"
dat += ""
for(var/obj/item/organ/i in occupant.internal_organs)
var/mech = ""
+ var/i_dead = ""
if(i.status & ORGAN_ASSISTED)
mech = "Assisted:"
if(i.robotic >= ORGAN_ROBOT)
mech = "Mechanical:"
+ if(i.status & ORGAN_DEAD)
+ i_dead = "Necrotic:"
var/infection = "None"
switch (i.germ_level)
- if (1 to INFECTION_LEVEL_ONE + 200)
+ if (INFECTION_LEVEL_ONE to INFECTION_LEVEL_ONE + 200)
infection = "Mild Infection:"
if (INFECTION_LEVEL_ONE + 200 to INFECTION_LEVEL_ONE + 300)
infection = "Mild Infection+:"
@@ -543,11 +550,13 @@
infection = "Acute Infection:"
if (INFECTION_LEVEL_TWO + 200 to INFECTION_LEVEL_TWO + 300)
infection = "Acute Infection+:"
- if (INFECTION_LEVEL_TWO + 300 to INFINITY)
+ if (INFECTION_LEVEL_TWO + 300 to INFECTION_LEVEL_THREE - 50)
infection = "Acute Infection++:"
+ if (INFECTION_LEVEL_THREE -49 to INFINITY)
+ infection = "Necrosis Detected:"
dat += "
"
- dat += "
[i.name]
N/A
[i.damage]
[infection]:[mech]
"
+ dat += "
[i.name]
N/A
[i.damage]
[infection]:[mech][i_dead]
"
dat += "
"
dat += ""
if(occupant.sdisabilities & BLIND)
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index bff06559d02..9af5de87d4f 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -980,7 +980,7 @@ FIRE ALARM
update_icon()
/obj/machinery/firealarm/initialize()
- if(z in config.contact_levels)
+ if(z in using_map.contact_levels)
set_security_level(security_level? get_security_level() : "green")
/*
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index 2a59f345d4d..dcce5fb938d 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -48,8 +48,8 @@
/obj/machinery/portable_atmospherics/canister/phoron
name = "Canister \[Phoron\]"
- icon_state = "orange"
- canister_color = "orange"
+ icon_state = "orangeps"
+ canister_color = "orangeps"
can_label = 0
/obj/machinery/portable_atmospherics/canister/carbon_dioxide
@@ -77,8 +77,8 @@
canister_color = "blue"
/obj/machinery/portable_atmospherics/canister/empty/phoron
name = "Canister \[Phoron\]"
- icon_state = "orange"
- canister_color = "orange"
+ icon_state = "orangeps"
+ canister_color = "orangeps"
/obj/machinery/portable_atmospherics/canister/empty/nitrogen
name = "Canister \[N2\]"
icon_state = "red"
@@ -348,7 +348,7 @@ update_flag
"\[N2O\]" = "redws", \
"\[N2\]" = "red", \
"\[O2\]" = "blue", \
- "\[Phoron\]" = "orange", \
+ "\[Phoron\]" = "orangeps", \
"\[CO2\]" = "black", \
"\[Air\]" = "grey", \
"\[CAUTION\]" = "yellow", \
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index e9c7df22b2b..2953f0de870 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -261,13 +261,13 @@
if(!isnull(stored_material[material]))
stored_material[material] = max(0, stored_material[material] - round(making.resources[material] * mat_efficiency) * multiplier)
- //Fancy autolathe animation.
- flick("autolathe_n", src)
-
+ update_icon() // So lid closes
+
sleep(build_time)
busy = 0
update_use_power(1)
+ update_icon() // So lid opens
//Sanity check.
if(!making || !src) return
@@ -281,7 +281,14 @@
updateUsrDialog()
/obj/machinery/autolathe/update_icon()
- icon_state = (panel_open ? "autolathe_t" : "autolathe")
+ if(panel_open)
+ icon_state = "autolathe_t"
+ else if(busy)
+ icon_state = "autolathe_n"
+ else
+ if(icon_state == "autolathe_n")
+ flick("autolathe_u", src) // If lid WAS closed, show opening animation
+ icon_state = "autolathe"
//Updates overall lathe storage size.
/obj/machinery/autolathe/RefreshParts()
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 7c466514194..b1052220848 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -8,7 +8,7 @@
active_power_usage = 10
layer = 5
- var/list/network = list(NETWORK_EXODUS)
+ var/list/network = list(NETWORK_DEFAULT)
var/c_tag = null
var/c_tag_order = 999
var/status = 1
@@ -123,6 +123,7 @@
if(user.species.can_shred(user))
set_status(0)
user.do_attack_animation(src)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
visible_message("\The [user] slashes at [src]!")
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
add_hiddenprint(user)
@@ -148,7 +149,7 @@
assembly.loc = src.loc
assembly.anchored = 1
assembly.camera_name = c_tag
- assembly.camera_network = english_list(network, NETWORK_EXODUS, ",", ",")
+ assembly.camera_network = english_list(network, NETWORK_DEFAULT, ",", ",")
assembly.update_icon()
assembly.dir = src.dir
if(stat & BROKEN)
diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm
index 33cb1b0613c..b442d3afa95 100644
--- a/code/game/machinery/camera/camera_assembly.dm
+++ b/code/game/machinery/camera/camera_assembly.dm
@@ -80,7 +80,7 @@
if(isscrewdriver(W))
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- var/input = sanitize(input(usr, "Which networks would you like to connect this camera to? Separate networks with a comma. No Spaces!\nFor example: "+station_short+",Security,Secret ", "Set Network", camera_network ? camera_network : NETWORK_EXODUS))
+ var/input = sanitize(input(usr, "Which networks would you like to connect this camera to? Separate networks with a comma. No Spaces!\nFor example: "+using_map.station_short+",Security,Secret ", "Set Network", camera_network ? camera_network : NETWORK_DEFAULT))
if(!input)
usr << "No input found please hang up and try your call again."
return
diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm
index bf4839e7c75..9e4cd486506 100644
--- a/code/game/machinery/camera/presets.dm
+++ b/code/game/machinery/camera/presets.dm
@@ -1,4 +1,5 @@
// PRESETS
+/*
var/global/list/station_networks = list(
// NETWORK_CAFE_DOCK,
NETWORK_CARGO,
@@ -9,7 +10,7 @@ var/global/list/station_networks = list(
NETWORK_ENGINE,
NETWORK_ENGINEERING,
NETWORK_ENGINEERING_OUTPOST,
- NETWORK_EXODUS,
+ NETWORK_DEFAULT,
NETWORK_MEDICAL,
NETWORK_MINE,
NETWORK_NORTHERN_STAR,
@@ -20,6 +21,7 @@ var/global/list/station_networks = list(
NETWORK_SECURITY,
NETWORK_INTERROGATION
)
+*/
var/global/list/engineering_networks = list(
NETWORK_ENGINE,
NETWORK_ENGINEERING,
@@ -65,7 +67,7 @@ var/global/list/engineering_networks = list(
network = list(NETWORK_ERT)
/obj/machinery/camera/network/exodus
- network = list(NETWORK_EXODUS)
+ network = list(NETWORK_DEFAULT)
/obj/machinery/camera/network/interrogation
network = list(NETWORK_INTERROGATION)
diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm
index cb57906e301..31c8fe78197 100644
--- a/code/game/machinery/camera/tracking.dm
+++ b/code/game/machinery/camera/tracking.dm
@@ -6,7 +6,7 @@
/mob/living/silicon/ai/var/stored_locations[0]
/proc/InvalidPlayerTurf(turf/T as turf)
- return !(T && T.z in config.player_levels)
+ return !(T && T.z in using_map.player_levels)
/mob/living/silicon/ai/proc/get_camera_list()
if(src.stat == 2)
@@ -256,7 +256,7 @@ mob/living/proc/near_camera()
if(. == TRACKING_NO_COVERAGE)
var/turf/T = get_turf(src)
- if(T && (T.z in config.station_levels) && hassensorlevel(src, SUIT_SENSOR_TRACKING))
+ if(T && (T.z in using_map.station_levels) && hassensorlevel(src, SUIT_SENSOR_TRACKING))
return TRACKING_POSSIBLE
mob/living/proc/tracking_initiated()
diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm
index e6577f30970..de81fbb0fac 100644
--- a/code/game/machinery/computer/aifixer.dm
+++ b/code/game/machinery/computer/aifixer.dm
@@ -10,6 +10,7 @@
var/active = 0
/obj/machinery/computer/aifixer/New()
+ ..()
update_icon()
/obj/machinery/computer/aifixer/proc/load_ai(var/mob/living/silicon/ai/transfer, var/obj/item/device/aicard/card, var/mob/user)
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 0a568b4adec..408e3184d49 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -66,7 +66,11 @@
if(1)
num_of_prizes = rand(1,4)
if(2)
+ num_of_prizes = rand(1,3)
+ if(3)
num_of_prizes = rand(0,2)
+ if(4)
+ num_of_prizes = rand(0,1)
for(num_of_prizes; num_of_prizes > 0; num_of_prizes--)
empprize = pickweight(prizes)
new empprize(src.loc)
diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm
index 03d3c1170fa..244598ad09a 100644
--- a/code/game/machinery/computer/camera.dm
+++ b/code/game/machinery/computer/camera.dm
@@ -16,7 +16,7 @@
/obj/machinery/computer/security/New()
if(!network)
- network = station_networks.Copy()
+ network = using_map.station_networks.Copy()
..()
if(network.len)
current_network = network[1]
@@ -253,7 +253,7 @@
desc = "Used to access the various cameras on the outpost."
icon_keyboard = "mining_key"
icon_screen = "mining"
- network = list("MINE")
+ network = list("Mining Outpost")
circuit = /obj/item/weapon/circuitboard/security/mining
light_color = "#F9BBFC"
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 9ff98b84b4d..a738ea66c1e 100644
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -35,10 +35,12 @@
var/stat_msg1
var/stat_msg2
+ var/datum/lore/atc_controller/ATC
var/datum/announcement/priority/crew_announcement = new
/obj/machinery/computer/communications/New()
..()
+ ATC = atc
crew_announcement.newscast = 1
/obj/machinery/computer/communications/process()
@@ -130,6 +132,8 @@
if("messagelist")
src.currmsg = 0
src.state = STATE_MESSAGELIST
+ if("toggleatc")
+ src.ATC.squelched = !src.ATC.squelched
if("viewmessage")
src.state = STATE_VIEWMESSAGE
if (!src.currmsg)
@@ -178,12 +182,12 @@
if(centcomm_message_cooldown)
usr << "\red Arrays recycling. Please stand by."
return
- var/input = sanitize(input("Please choose a message to transmit to [boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", ""))
+ var/input = sanitize(input("Please choose a message to transmit to [using_map.boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", ""))
if(!input || !(usr in view(1,src)))
return
CentCom_announce(input, usr)
usr << "\blue Message transmitted."
- log_say("[key_name(usr)] has made an IA [boss_short] announcement: [input]")
+ log_say("[key_name(usr)] has made an IA [using_map.boss_short] announcement: [input]")
centcomm_message_cooldown = 1
spawn(300)//10 minute cooldown
centcomm_message_cooldown = 0
@@ -295,7 +299,7 @@
if (src.authenticated==2)
dat += " \[ Make An Announcement \]"
if(src.emagged == 0)
- dat += " \[ Send an emergency message to [boss_short] \]"
+ dat += " \[ Send an emergency message to [using_map.boss_short] \]"
else
dat += " \[ Send an emergency message to \[UNKNOWN\] \]"
dat += " \[ Restore Backup Routing Data \]"
@@ -311,6 +315,7 @@
else
dat += " \[ Log In \]"
dat += " \[ Message List \]"
+ dat += " \[ [ATC.squelched ? "Enable" : "Disable"] ATC Relay \]"
if(STATE_CALLSHUTTLE)
dat += "Are you sure you want to call the shuttle? \[ OK | Cancel \]"
if(STATE_CANCELSHUTTLE)
@@ -374,6 +379,7 @@
dat += " \[ Call Emergency Shuttle \]"
dat += " \[ Message List \]"
dat += " \[ Set Status Display \]"
+ dat += " \[ [ATC.squelched ? "Enable" : "Disable"] ATC Relay \]"
if(STATE_CALLSHUTTLE)
dat += "Are you sure you want to call the shuttle? \[ OK | Cancel \]"
if(STATE_MESSAGELIST)
@@ -426,7 +432,7 @@
return
if(deathsquad.deployed)
- user << "[boss_short] will not allow the shuttle to be called. Consider all contracts terminated."
+ user << "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated."
return
if(emergency_shuttle.deny_shuttle)
@@ -438,7 +444,7 @@
return
if(emergency_shuttle.going_to_centcom())
- user << "The emergency shuttle may not be called while returning to [boss_short]."
+ user << "The emergency shuttle may not be called while returning to [using_map.boss_short]."
return
if(emergency_shuttle.online())
@@ -461,7 +467,7 @@
return
if(emergency_shuttle.going_to_centcom())
- user << "The shuttle may not be called while returning to [boss_short]."
+ user << "The shuttle may not be called while returning to [using_map.boss_short]."
return
if(emergency_shuttle.online())
@@ -471,11 +477,11 @@
// if force is 0, some things may stop the shuttle call
if(!force)
if(emergency_shuttle.deny_shuttle)
- user << "[boss_short] does not currently have a shuttle available in your sector. Please try again later."
+ user << "[using_map.boss_short] does not currently have a shuttle available in your sector. Please try again later."
return
if(deathsquad.deployed == 1)
- user << "[boss_short] will not allow the shuttle to be called. Consider all contracts terminated."
+ user << "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated."
return
if(world.time < 54000) // 30 minute grace period to let the game get going
diff --git a/code/game/machinery/computer/prisoner.dm b/code/game/machinery/computer/prisoner.dm
index 1551e0df6ee..e8fe96ae6c8 100644
--- a/code/game/machinery/computer/prisoner.dm
+++ b/code/game/machinery/computer/prisoner.dm
@@ -46,7 +46,7 @@
if(!T.implanted) continue
var/loc_display = "Unknown"
var/mob/living/carbon/M = T.imp_in
- if((M.z in config.station_levels) && !istype(M.loc, /turf/space))
+ if((M.z in using_map.station_levels) && !istype(M.loc, /turf/space))
var/turf/mob_loc = get_turf(M)
loc_display = mob_loc.loc
if(T.malfunction)
diff --git a/code/game/machinery/computer/specops_shuttle.dm b/code/game/machinery/computer/specops_shuttle.dm
index c48e64e484f..cb0f8a5552a 100644
--- a/code/game/machinery/computer/specops_shuttle.dm
+++ b/code/game/machinery/computer/specops_shuttle.dm
@@ -89,7 +89,7 @@ var/specops_shuttle_timeleft = 0
for(var/turf/T in get_area_turfs(end_location) )
var/mob/M = locate(/mob) in T
- M << "You have arrived at [boss_name]. Operation has ended!"
+ M << "You have arrived at [using_map.boss_name]. Operation has ended!"
specops_shuttle_at_station = 0
@@ -232,7 +232,7 @@ var/specops_shuttle_timeleft = 0
for(var/turf/T in get_area_turfs(end_location) )
var/mob/M = locate(/mob) in T
- M << "You have arrived to [station_name]. Commence operation!"
+ M << "You have arrived to [station_name()]. Commence operation!"
for(var/obj/machinery/computer/specops_shuttle/S in world)
S.specops_shuttle_timereset = world.time + SPECOPS_RETURN_DELAY
@@ -267,8 +267,8 @@ var/specops_shuttle_timeleft = 0
dat = temp
else
dat += {" Special Operations Shuttle
- \nLocation: [specops_shuttle_moving_to_station || specops_shuttle_moving_to_centcom ? "Departing for [station_name] in ([specops_shuttle_timeleft] seconds.)":specops_shuttle_at_station ? "Station":"Dock"]
- [specops_shuttle_moving_to_station || specops_shuttle_moving_to_centcom ? "\n*The Special Ops. shuttle is already leaving.* \n ":specops_shuttle_at_station ? "\nShuttle standing by... \n ":"\nDepart to [station_name] \n "]
+ \nLocation: [specops_shuttle_moving_to_station || specops_shuttle_moving_to_centcom ? "Departing for [station_name()] in ([specops_shuttle_timeleft] seconds.)":specops_shuttle_at_station ? "Station":"Dock"]
+ [specops_shuttle_moving_to_station || specops_shuttle_moving_to_centcom ? "\n*The Special Ops. shuttle is already leaving.* \n ":specops_shuttle_at_station ? "\nShuttle standing by... \n ":"\nDepart to [station_name()] \n "]
\nClose"}
user << browse(dat, "window=computer;size=575x450")
@@ -286,14 +286,14 @@ var/specops_shuttle_timeleft = 0
if(!specops_shuttle_at_station|| specops_shuttle_moving_to_station || specops_shuttle_moving_to_centcom) return
if (!specops_can_move())
- usr << "[boss_name] will not allow the Special Operations shuttle to return yet."
+ usr << "[using_map.boss_name] will not allow the Special Operations shuttle to return yet."
if(world.timeofday <= specops_shuttle_timereset)
if (((world.timeofday - specops_shuttle_timereset)/10) > 60)
usr << "[-((world.timeofday - specops_shuttle_timereset)/10)/60] minutes remain!"
usr << "[-(world.timeofday - specops_shuttle_timereset)/10] seconds remain!"
return
- usr << "The Special Operations shuttle will arrive at [boss_name] in [(SPECOPS_MOVETIME/10)] seconds."
+ usr << "The Special Operations shuttle will arrive at [using_map.boss_name] in [(SPECOPS_MOVETIME/10)] seconds."
temp += "Shuttle departing.
OK"
updateUsrDialog()
@@ -310,7 +310,7 @@ var/specops_shuttle_timeleft = 0
usr << "The Special Operations shuttle is unable to leave."
return
- usr << "The Special Operations shuttle will arrive on [station_name] in [(SPECOPS_MOVETIME/10)] seconds."
+ usr << "The Special Operations shuttle will arrive on [station_name()] in [(SPECOPS_MOVETIME/10)] seconds."
temp += "Shuttle departing.
"
for(var/A in get_all_centcom_access())
if(A in writer.access)
accesses += topic_link(src,"access=[A]","[replacetext(get_centcom_access_desc(A), " ", " ")]") + " "
diff --git a/code/game/machinery/computer3/computers/communications.dm b/code/game/machinery/computer3/computers/communications.dm
index cace79d3784..c4ec88f8e0c 100644
--- a/code/game/machinery/computer3/computers/communications.dm
+++ b/code/game/machinery/computer3/computers/communications.dm
@@ -192,12 +192,12 @@
if(centcomm_message_cooldown)
usr << "Arrays recycling. Please stand by."
return
- var/input = sanitize(input("Please choose a message to transmit to [boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "To abort, send an empty message.", ""))
+ var/input = sanitize(input("Please choose a message to transmit to [using_map.boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "To abort, send an empty message.", ""))
if(!input || !interactable())
return
CentCom_announce(input, usr)
usr << "Message transmitted."
- log_say("[key_name(usr)] has made a [boss_short] announcement: [input]")
+ log_say("[key_name(usr)] has made a [using_map.boss_short] announcement: [input]")
centcomm_message_cooldown = 1
spawn(600)//10 minute cooldown
centcomm_message_cooldown = 0
@@ -288,7 +288,7 @@
if (authenticated==2)
dat += " \[ Make An Announcement \]"
if(computer.emagged == 0)
- dat += " \[ Send an emergency message to [boss_short] \]"
+ dat += " \[ Send an emergency message to [using_map.boss_short] \]"
else
dat += " \[ Send an emergency message to \[UNKNOWN\] \]"
dat += " \[ Restore Backup Routing Data \]"
diff --git a/code/game/machinery/computer3/computers/prisoner.dm b/code/game/machinery/computer3/computers/prisoner.dm
index 0c7937d39a0..7e3ada285d3 100644
--- a/code/game/machinery/computer3/computers/prisoner.dm
+++ b/code/game/machinery/computer3/computers/prisoner.dm
@@ -43,7 +43,7 @@
if(!T.implanted) continue
var/loc_display = "Unknown"
var/mob/living/carbon/M = T.imp_in
- if(M.z in config.station_levels && !istype(M.loc, /turf/space))
+ if(M.z in using_map.station_levels && !istype(M.loc, /turf/space))
var/turf/mob_loc = get_turf(M)
loc_display = mob_loc.loc
if(T.malfunction)
diff --git a/code/game/machinery/computer3/computers/welcome.dm b/code/game/machinery/computer3/computers/welcome.dm
index 6693d1ced8e..062fc7b59b8 100644
--- a/code/game/machinery/computer3/computers/welcome.dm
+++ b/code/game/machinery/computer3/computers/welcome.dm
@@ -15,13 +15,13 @@
return
var/dat = ""
dat += "
Welcome to NTOS
"
- dat += "
Thank you for choosing NTOS, your gateway to the future of mobile computing technology, sponsored by [company_name] (R)
"
+ dat += "
Thank you for choosing NTOS, your gateway to the future of mobile computing technology, sponsored by [using_map.company_name] (R)
"
dat += "Getting started with NTOS: "
dat += "To leave a current program, click the X button in the top right corner of the window. This will return you to the NTOS desktop. \
From the desktop, you can open the hard drive, usually located in the top left corner to access all the programs installed on your computer. \
- When you rented your laptop, you were supplied with programs that your [company_name] Issued ID has given you access to use. \
+ When you rented your laptop, you were supplied with programs that your [using_map.company_name] Issued ID has given you access to use. \
In the event of a serious error, the right click menu will give you the ability to reset your computer. To open and close your laptop, alt-click your device.\
- If you have any questions or technical issues, please contact your local computer technical experts at your local [boss_name]."
+ If you have any questions or technical issues, please contact your local computer technical experts at your local [using_map.boss_name]."
popup.set_content(dat)
popup.set_title_image(usr.browse_rsc_icon(computer.icon, computer.icon_state))
popup.open()
diff --git a/code/game/machinery/computer3/lapvend.dm b/code/game/machinery/computer3/lapvend.dm
index e31dd57fa23..4aa5d318f47 100644
--- a/code/game/machinery/computer3/lapvend.dm
+++ b/code/game/machinery/computer3/lapvend.dm
@@ -176,9 +176,9 @@
if(D)
transfer_and_vend(D, C)
else
- usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call [boss_short] Support."
+ usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call [using_map.boss_short] Support."
else
- usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call CentCom Support."
+ usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call [using_map.boss_short] Support."
else
transfer_and_vend(CH, C)
@@ -325,10 +325,10 @@
transfer_and_reimburse(D)
return 1
else
- usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call [boss_short] Support."
+ usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call [using_map.boss_short] Support."
return 0
else
- usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call CentCom Support."
+ usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call [using_map.boss_short] Support."
return 0
else
transfer_and_reimburse(CH)
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index 7a1b12509c6..d1ab11e7067 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -347,7 +347,7 @@
put_mob(usr)
return
-/atom/proc/return_air_for_internal_lifeform()
+/atom/proc/return_air_for_internal_lifeform(var/mob/living/lifeform)
return return_air()
/obj/machinery/atmospherics/unary/cryo_cell/return_air_for_internal_lifeform()
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index ceb5570ff21..6441a5e72ae 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -360,7 +360,7 @@
if(!find_control_computer(urgent=1))
return
- despawn_occupant()
+ despawn_occupant(occupant)
// This function can not be undone; do not call this unless you are sure
// Also make sure there is a valid control computer
@@ -384,10 +384,14 @@
// This function can not be undone; do not call this unless you are sure
// Also make sure there is a valid control computer
-/obj/machinery/cryopod/proc/despawn_occupant()
+/obj/machinery/cryopod/proc/despawn_occupant(var/mob/to_despawn)
+ //Recursively despawn mobs
+ for(var/mob/M in to_despawn)
+ despawn_occupant(M)
+
//Drop all items into the pod.
- for(var/obj/item/W in occupant)
- occupant.drop_from_inventory(W)
+ for(var/obj/item/W in to_despawn)
+ to_despawn.drop_from_inventory(W)
W.forceMove(src)
if(W.contents.len) //Make sure we catch anything not handled by qdel() on the items.
@@ -398,7 +402,7 @@
//Delete all items not on the preservation list.
var/list/items = contents.Copy()
- items -= occupant // Don't delete the occupant
+ items -= to_despawn // Don't delete the occupant
items -= announce // or the autosay radio.
for(var/obj/item/W in items)
@@ -413,7 +417,7 @@
if(istype(W,/obj/item/weapon/implant/health))
for(var/obj/machinery/computer/cloning/com in world)
for(var/datum/dna2/record/R in com.records)
- if(R.implant == W)
+ if(locate(R.implant) == W)
qdel(R)
qdel(W)
@@ -430,36 +434,37 @@
for(var/datum/objective/O in all_objectives)
// We don't want revs to get objectives that aren't for heads of staff. Letting
// them win or lose based on cryo is silly so we remove the objective.
- if(O.target == occupant.mind)
+ if(O.target == to_despawn.mind)
if(O.owner && O.owner.current)
O.owner.current << "You get the feeling your target is no longer within your reach..."
qdel(O)
//Handle job slot/tater cleanup.
- var/job = occupant.mind.assigned_role
+ var/job = to_despawn.mind.assigned_role
job_master.FreeRole(job)
- if(occupant.mind.objectives.len)
- qdel(occupant.mind.objectives)
- occupant.mind.special_role = null
+ if(to_despawn.mind.objectives.len)
+ qdel(to_despawn.mind.objectives)
+ to_despawn.mind.special_role = null
+
//else
//if(ticker.mode.name == "AutoTraitor")
//var/datum/game_mode/traitor/autotraitor/current_mode = ticker.mode
- //current_mode.possible_traitors.Remove(occupant)
+ //current_mode.possible_traitors.Remove(to_despawn)
// Delete them from datacore.
if(PDA_Manifest.len)
PDA_Manifest.Cut()
for(var/datum/data/record/R in data_core.medical)
- if((R.fields["name"] == occupant.real_name))
+ if((R.fields["name"] == to_despawn.real_name))
qdel(R)
for(var/datum/data/record/T in data_core.security)
- if((T.fields["name"] == occupant.real_name))
+ if((T.fields["name"] == to_despawn.real_name))
qdel(T)
for(var/datum/data/record/G in data_core.general)
- if((G.fields["name"] == occupant.real_name))
+ if((G.fields["name"] == to_despawn.real_name))
qdel(G)
icon_state = base_icon_state
@@ -468,22 +473,21 @@
//Make an announcement and log the person entering storage.
- control_computer.frozen_crew += "[occupant.real_name], [occupant.mind.role_alt_title] - [stationtime2text()]"
- control_computer._admin_logs += "[key_name(occupant)] ([occupant.mind.role_alt_title]) at [stationtime2text()]"
- log_and_message_admins("[key_name(occupant)] ([occupant.mind.role_alt_title]) entered cryostorage.")
+ control_computer.frozen_crew += "[to_despawn.real_name], [to_despawn.mind.role_alt_title] - [stationtime2text()]"
+ control_computer._admin_logs += "[key_name(to_despawn)] ([to_despawn.mind.role_alt_title]) at [stationtime2text()]"
+ log_and_message_admins("[key_name(to_despawn)] ([to_despawn.mind.role_alt_title]) entered cryostorage.")
- announce.autosay("[occupant.real_name], [occupant.mind.role_alt_title], [on_store_message]", "[on_store_name]")
- //visible_message("\The [initial(name)] hums and hisses as it moves [occupant.real_name] into storage.", 3)
- visible_message("\The [initial(name)] [on_store_visible_message_1] [occupant.real_name] [on_store_visible_message_2].", 3)
+ announce.autosay("[to_despawn.real_name], [to_despawn.mind.role_alt_title], [on_store_message]", "[on_store_name]")
+ //visible_message("\The [initial(name)] hums and hisses as it moves [to_despawn.real_name] into storage.", 3)
+ visible_message("\The [initial(name)] [on_store_visible_message_1] [to_despawn.real_name] [on_store_visible_message_2].", 3)
//This should guarantee that ghosts don't spawn.
- occupant.ckey = null
+ to_despawn.ckey = null
// Delete the mob.
- qdel(occupant)
+ qdel(to_despawn)
set_occupant(null)
-
/obj/machinery/cryopod/attackby(var/obj/item/weapon/G as obj, var/mob/user as mob)
if(istype(G, /obj/item/weapon/grab))
@@ -504,7 +508,7 @@
if(M.client)
if(alert(M,"Would you like to enter long-term storage?",,"Yes","No") == "Yes")
- if(!M || !grab || !grab:affecting) return
+ if(!M || !grab || !grab.affecting) return
willing = 1
else
willing = 1
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 383cc1b3a48..97dd9f5fe05 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -37,7 +37,16 @@
/obj/machinery/door/airlock/attack_generic(var/mob/user, var/damage)
if(stat & (BROKEN|NOPOWER))
if(damage >= 10)
- if(src.density)
+ if(src.locked || src.welded)
+ visible_message("\The [user] begins breaking into \the [src] internals!")
+ if(do_after(user,10 SECONDS,src))
+ src.locked = 0
+ src.welded = 0
+ update_icon()
+ open(1)
+ if(prob(25))
+ src.shock(user, 100)
+ else if(src.density)
visible_message("\The [user] forces \the [src] open!")
open(1)
else
@@ -329,6 +338,18 @@
secured_wires = 1
assembly_type = /obj/structure/door_assembly/door_assembly_highsecurity
+/obj/machinery/door/airlock/voidcraft
+ name = "voidcraft hatch"
+ desc = "It's an extra resilient airlock intended for spacefaring vessels."
+ icon = 'icons/obj/doors/shuttledoors.dmi'
+ explosion_resistance = 20
+ assembly_type = /obj/structure/door_assembly/door_assembly_voidcraft
+
+// Airlock opens from top-bottom instead of left-right.
+/obj/machinery/door/airlock/voidcraft/vertical
+ icon = 'icons/obj/doors/shuttledoors_vertical.dmi'
+ assembly_type = /obj/structure/door_assembly/door_assembly_voidcraft/vertical
+
/*
About the new airlock wires panel:
* An airlock wire dialog can be accessed by the normal way or by using wirecutters or a multitool on the door while the wire-panel is open. This would show the following wires, which you can either wirecut/mend or send a multitool pulse through. There are 9 wires.
@@ -1041,7 +1062,7 @@ About the new airlock wires panel:
//wires
var/turf/T = get_turf(newloc)
- if(T && (T.z in config.admin_levels))
+ if(T && (T.z in using_map.admin_levels))
secured_wires = 1
if (secured_wires)
wires = new/datum/wires/airlock/secure(src)
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 2ac0c2a48d3..13352a16450 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -160,6 +160,8 @@
if(H.species.can_shred(H))
playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
visible_message("[user] smashes against the [src.name].", 1)
+ user.do_attack_animation(src)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
take_damage(25)
return
return src.attackby(user, user)
diff --git a/code/game/machinery/exonet_node.dm b/code/game/machinery/exonet_node.dm
index d871a3ec38e..049289c7c73 100644
--- a/code/game/machinery/exonet_node.dm
+++ b/code/game/machinery/exonet_node.dm
@@ -1,7 +1,6 @@
/obj/machinery/exonet_node
name = "exonet node"
- desc = "This machine is one of many, many nodes inside "+starsys_name+"'s section of the Exonet, connecting the "+station_orig+" to the rest of the system, at least \
- electronically."
+ desc = null // Gets written in New()
icon = 'icons/obj/stationobjs.dmi'
icon_state = "exonet_node"
idle_power_usage = 2500
@@ -36,6 +35,9 @@
component_parts += new /obj/item/stack/cable_coil(src, 2)
RefreshParts()
+ desc = "This machine is one of many, many nodes inside [using_map.starsys_name]'s section of the Exonet, connecting the [using_map.station_short] to the rest of the system, at least \
+ electronically."
+
// Proc: update_icon()
// Parameters: None
// Description: Self explanatory.
diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm
index cd2346a32c6..4eb0e7d4087 100644
--- a/code/game/machinery/jukebox.dm
+++ b/code/game/machinery/jukebox.dm
@@ -49,12 +49,9 @@ datum/track/New(var/title_name, var/audio)
/obj/machinery/media/jukebox/New()
..()
- component_parts = list()
- component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
- component_parts += new /obj/item/stack/cable_coil(src, 5)
- RefreshParts()
+ default_apply_parts()
wires = new/datum/wires/jukebox(src)
+ update_icon()
/obj/machinery/media/jukebox/Destroy()
StopPlaying()
@@ -78,6 +75,10 @@ datum/track/New(var/title_name, var/audio)
return
if(default_deconstruction_crowbar(user, W))
return
+ if(istype(W, /obj/item/weapon/wirecutters))
+ return wires.Interact(user)
+ if(istype(W, /obj/item/device/multitool))
+ return wires.Interact(user)
if(istype(W, /obj/item/weapon/wrench))
if(playing)
StopPlaying()
@@ -268,4 +269,24 @@ datum/track/New(var/title_name, var/audio)
playing = 1
update_use_power(2)
- update_icon()
\ No newline at end of file
+ update_icon()
+
+// Advance to the next track - Don't start playing it unless we were already playing
+/obj/machinery/media/jukebox/proc/NextTrack()
+ if(!tracks.len) return
+ var/curTrackIndex = max(1, tracks.Find(current_track))
+ var/newTrackIndex = (curTrackIndex % tracks.len) + 1 // Loop back around if past end
+ current_track = tracks[newTrackIndex]
+ if(playing)
+ StartPlaying()
+ updateDialog()
+
+// Advance to the next track - Don't start playing it unless we were already playing
+/obj/machinery/media/jukebox/proc/PrevTrack()
+ if(!tracks.len) return
+ var/curTrackIndex = max(1, tracks.Find(current_track))
+ var/newTrackIndex = curTrackIndex == 1 ? tracks.len : curTrackIndex - 1
+ current_track = tracks[newTrackIndex]
+ if(playing)
+ StartPlaying()
+ updateDialog()
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index d3107869ced..b0946bf3479 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -283,6 +283,13 @@ Class Procs:
return 1
return 0
+/obj/machinery/proc/default_apply_parts()
+ var/obj/item/weapon/circuitboard/CB = circuit
+ if(!istype(CB))
+ return
+ CB.apply_default_parts(src)
+ RefreshParts()
+
/obj/machinery/proc/default_part_replacement(var/mob/user, var/obj/item/weapon/storage/part_replacer/R)
if(!istype(R))
return 0
diff --git a/code/game/machinery/navbeacon.dm b/code/game/machinery/navbeacon.dm
index fe5cac9c44c..8700caf785d 100644
--- a/code/game/machinery/navbeacon.dm
+++ b/code/game/machinery/navbeacon.dm
@@ -1,52 +1,45 @@
// Navigation beacon for AI robots
// Functions as a transponder: looks for incoming signal matching
-var/global/list/navbeacons // no I don't like putting this in, but it will do for now
+var/global/list/navbeacons = list() // no I don't like putting this in, but it will do for now
/obj/machinery/navbeacon
icon = 'icons/obj/objects.dmi'
icon_state = "navbeacon0-f"
name = "navigation beacon"
- desc = "A radio beacon used for bot navigation."
+ desc = "A beacon used for bot navigation."
level = 1 // underfloor
layer = 2.5
anchored = 1
var/open = 0 // true if cover is open
var/locked = 1 // true if controls are locked
- var/freq = 1445 // radio frequency
+ var/freq = null // DEPRECATED we don't use radios anymore!
var/location = "" // location response text
- var/list/codes // assoc. list of transponder codes
- var/codes_txt = "" // codes as set on map: "tag1;tag2" or "tag1=value;tag2=value"
+ var/codes_txt // DEPRECATED codes as set on map: "tag1;tag2" or "tag1=value;tag2=value"
+ var/list/codes = list() // assoc. list of transponder codes
req_access = list(access_engine)
/obj/machinery/navbeacon/New()
..()
-
- set_codes()
+ set_codes_from_txt(codes_txt)
+ if(freq)
+ warning("[src] at [x],[y],[z] has deprecated var freq=[freq]. Replace it with proper type.")
var/turf/T = loc
hide(!T.is_plating())
-
- // add beacon to MULE bot beacon list
- if(freq == 1400)
- if(!navbeacons)
- navbeacons = new()
- navbeacons += src
-
-
- spawn(5) // must wait for map loading to finish
- if(radio_controller)
- radio_controller.add_object(src, freq, RADIO_NAVBEACONS)
+ navbeacons += src
// set the transponder codes assoc list from codes_txt
-/obj/machinery/navbeacon/proc/set_codes()
+// DEPRECATED - This is kept only for compatibilty with old map files! Do not use this!
+// Instead, you should replace the map instance with one of the appropriate navbeacon subtypes.
+// See the bottom of this file for a list of subtypes, make your own examples if your map needs more
+/obj/machinery/navbeacon/proc/set_codes_from_txt()
if(!codes_txt)
return
+ warning("[src] at [x],[y],[z] in [get_area(src)] is using the deprecated 'codes_txt' mapping method. Replace it with proper type.")
- codes = new()
-
+ codes = list()
var/list/entries = splittext(codes_txt, ";") // entries are separated by semicolons
-
for(var/e in entries)
var/index = findtext(e, "=") // format is "key=value"
if(index)
@@ -56,6 +49,8 @@ var/global/list/navbeacons // no I don't like putting this in, but it will do
else
codes[e] = "1"
+/obj/machinery/navbeacon/hides_under_flooring()
+ return 1
// called when turf state changes
// hide the object if turf is intact
@@ -73,38 +68,6 @@ var/global/list/navbeacons // no I don't like putting this in, but it will do
else
icon_state = "[state]"
-
-// look for a signal of the form "findbeacon=X"
-// where X is any
-// or the location
-// or one of the set transponder keys
-// if found, return a signal
-/obj/machinery/navbeacon/receive_signal(datum/signal/signal)
-
- var/request = signal.data["findbeacon"]
- if(request && ((request in codes) || request == "any" || request == location))
- spawn(1)
- post_signal()
-
-// return a signal giving location and transponder codes
-
-/obj/machinery/navbeacon/proc/post_signal()
-
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
-
- if(!frequency) return
-
- var/datum/signal/signal = new()
- signal.source = src
- signal.transmission_method = 1
- signal.data["beacon"] = location
-
- for(var/key in codes)
- signal.data[key] = codes[key]
-
- frequency.post_signal(src, signal, filter = RADIO_NAVBEACONS)
-
-
/obj/machinery/navbeacon/attackby(var/obj/item/I, var/mob/user)
var/turf/T = loc
if(!T.is_plating())
@@ -117,7 +80,7 @@ var/global/list/navbeacons // no I don't like putting this in, but it will do
updateicon()
- else if(istype(I, /obj/item/weapon/card/id)||istype(I, /obj/item/device/pda))
+ else if(I.GetID())
if(open)
if(allowed(user))
locked = !locked
@@ -153,8 +116,7 @@ var/global/list/navbeacons // no I don't like putting this in, but it will do
if(locked && !ai)
t = {"Navigation Beacon
-(swipe card to unlock controls)
-Frequency: [format_frequency(freq)]
+(swipe card to unlock controls)
Location: [location ? location : "(none)"]
Transponder Codes:
"}
/obj/machinery/navbeacon/Destroy()
navbeacons.Remove(src)
- if(radio_controller)
- radio_controller.remove_object(src, freq)
+ ..()
+
+
+//
+// Nav Beacon Mapping
+// These subtypes are what you should actually put into maps! they will make your life much easier.
+//
+// Developer Note: navbeacons do not HAVE to use these subtypes. They are purely for mapping convenience.
+// You can feel free to construct them in-game as just /obj/machinery/navbeacon and they will work just
+// fine, and you can define your own specific types for every instance on map if you want (BayStation does)
+// This design is a compromise that means you can do mapping without every single one being its own type
+// but with it still being easy to map ~ Leshana
+//
+
+// Mulebot delivery destinations
+
+/obj/machinery/navbeacon/delivery/north
+ codes = list("delivery" = 1, "dir" = NORTH)
+
+/obj/machinery/navbeacon/delivery/south
+ codes = list("delivery" = 1, "dir" = SOUTH)
+
+/obj/machinery/navbeacon/delivery/east
+ codes = list("delivery" = 1, "dir" = EAST)
+
+/obj/machinery/navbeacon/delivery/west
+ codes = list("delivery" = 1, "dir" = WEST)
+
+
+// For part of the patrol route
+// You MUST set "location"
+// You MUST set "next_patrol"
+/obj/machinery/navbeacon/patrol
+ var/next_patrol
+
+/obj/machinery/navbeacon/patrol/New()
+ codes = list("patrol" = 1, "next_patrol" = next_patrol)
..()
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index 4758a77489c..f2a0132b5a4 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -285,7 +285,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
dat+="Feed Security functions: "
dat+=" [(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue"
dat+=" Censor Feed Stories"
- dat+=" Mark Feed Channel with [company_name] D-Notice"
+ dat+=" Mark Feed Channel with [using_map.company_name] D-Notice"
dat+=" The newscaster recognises you as: [scanned_user]"
if(1)
dat+= "Station Feed Channels"
@@ -366,7 +366,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
if(9)
dat+="[viewing_channel.channel_name]: \[created by: [viewing_channel.author]\]"
if(viewing_channel.censored)
- dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [company_name] D-Notice. "
+ dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice. "
dat+="No further feed story additions are allowed while the D-Notice is in effect.
"
else
if(isemptylist(viewing_channel.messages))
@@ -386,7 +386,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
dat+=" Refresh"
dat+=" Back"
if(10)
- dat+="[company_name] Feed Censorship Tool "
+ dat+="[using_map.company_name] Feed Censorship Tool "
dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible. "
dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it."
dat+="Select Feed channel to get Stories from: "
@@ -397,7 +397,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()] "
dat+=" Cancel"
if(11)
- dat+="[company_name] D-Notice Handler"
+ dat+="[using_map.company_name] D-Notice Handler"
dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's"
dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed"
dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time."
@@ -424,7 +424,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
dat+="[viewing_channel.channel_name]: \[ created by: [viewing_channel.author] \] "
dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel."
if(viewing_channel.censored)
- dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [company_name] D-Notice. "
+ dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice. "
dat+="No further feed story additions are allowed while the D-Notice is in effect.
"
else
if(isemptylist(viewing_channel.messages))
@@ -630,7 +630,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
screen = 15
else
if(news_network.wanted_issue.is_admin_message)
- alert("The wanted issue has been distributed by a [company_name] higherup. You cannot edit it.","Ok")
+ alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot edit it.","Ok")
return
news_network.wanted_issue.author = channel_name
news_network.wanted_issue.body = msg
@@ -643,7 +643,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
else if(href_list["cancel_wanted"])
if(news_network.wanted_issue.is_admin_message)
- alert("The wanted issue has been distributed by a [company_name] higherup. You cannot take it down.","Ok")
+ alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot take it down.","Ok")
return
var/choice = alert("Please confirm Wanted Issue removal","Network Security Handler","Confirm","Cancel")
if(choice=="Confirm")
@@ -659,7 +659,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
else if(href_list["censor_channel_author"])
var/datum/feed_channel/FC = locate(href_list["censor_channel_author"])
if(FC.is_admin_channel)
- alert("This channel was created by a [company_name] Officer. You cannot censor it.","Ok")
+ alert("This channel was created by a [using_map.company_name] Officer. You cannot censor it.","Ok")
return
if(FC.author != "\[REDACTED\]")
FC.backup_author = FC.author
@@ -672,7 +672,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
else if(href_list["censor_channel_story_author"])
var/datum/feed_message/MSG = locate(href_list["censor_channel_story_author"])
if(MSG.is_admin_message)
- alert("This message was created by a [company_name] Officer. You cannot censor its author.","Ok")
+ alert("This message was created by a [using_map.company_name] Officer. You cannot censor its author.","Ok")
return
if(MSG.author != "\[REDACTED\]")
MSG.backup_author = MSG.author
@@ -685,7 +685,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
else if(href_list["censor_channel_story_body"])
var/datum/feed_message/MSG = locate(href_list["censor_channel_story_body"])
if(MSG.is_admin_message)
- alert("This channel was created by a [company_name] Officer. You cannot censor it.","Ok")
+ alert("This channel was created by a [using_map.company_name] Officer. You cannot censor it.","Ok")
return
if(MSG.body != "\[REDACTED\]")
MSG.backup_body = MSG.body
@@ -711,7 +711,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
else if(href_list["toggle_d_notice"])
var/datum/feed_channel/FC = locate(href_list["toggle_d_notice"])
if(FC.is_admin_channel)
- alert("This channel was created by a [company_name] Officer. You cannot place a D-Notice upon it.","Ok")
+ alert("This channel was created by a [using_map.company_name] Officer. You cannot place a D-Notice upon it.","Ok")
return
FC.censored = !FC.censored
FC.update()
@@ -812,7 +812,7 @@ obj/item/weapon/newspaper/attack_self(mob/user as mob)
switch(screen)
if(0) //Cover
dat+="
"
diff --git a/code/game/machinery/nuclear_bomb.dm b/code/game/machinery/nuclear_bomb.dm
index 74b39840d0b..ea5c78d7342 100644
--- a/code/game/machinery/nuclear_bomb.dm
+++ b/code/game/machinery/nuclear_bomb.dm
@@ -375,7 +375,7 @@ obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob)
var/off_station = 0
var/turf/bomb_location = get_turf(src)
- if(bomb_location && (bomb_location.z in config.station_levels))
+ if(bomb_location && (bomb_location.z in using_map.station_levels))
if((bomb_location.x < (128-NUKERANGE)) || (bomb_location.x > (128+NUKERANGE)) || (bomb_location.y < (128-NUKERANGE)) || (bomb_location.y > (128+NUKERANGE)))
off_station = 1
else
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index a378f0ff359..595712afd3a 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -441,7 +441,7 @@ var/list/turret_icons
else
take_damage(initial(health) * 8) //should instakill most turrets
if(3)
- take_damage(initial(health) * 8 / 3)
+ take_damage(initial(health) * 8 / 3) //Level 4 is too weak to bother turrets
/obj/machinery/porta_turret/proc/die() //called when the turret dies, ie, health <= 0
health = 0
diff --git a/code/game/machinery/supplybeacon.dm b/code/game/machinery/supplybeacon.dm
index fae062ffed7..fd69e4f50ef 100644
--- a/code/game/machinery/supplybeacon.dm
+++ b/code/game/machinery/supplybeacon.dm
@@ -2,7 +2,7 @@
/obj/item/supply_beacon
name = "inactive supply beacon"
icon = 'icons/obj/supplybeacon.dmi'
- desc = "An inactive, hacked supply beacon stamped with the "+starsys_name+" Rapid Fabrication logo. Good for one (1) ballistic supply pod shipment."
+ desc = "An inactive, hacked supply beacon stamped with the local system's Rapid Fabrication logo. Good for one (1) ballistic supply pod shipment."
icon_state = "beacon"
var/deploy_path = /obj/machinery/power/supply_beacon
var/deploy_time = 30
@@ -114,6 +114,6 @@
var/drop_x = src.x - 2
var/drop_y = src.y - 2
var/drop_z = src.z
- command_announcement.Announce(starsys_name+" Rapid Fabrication priority supply request #[rand(1000,9999)]-[rand(100,999)] recieved. Shipment dispatched via ballistic supply pod for immediate delivery. Have a nice day.", "Thank You For Your Patronage")
+ command_announcement.Announce("[using_map.starsys_name] Rapid Fabrication priority supply request #[rand(1000,9999)]-[rand(100,999)] recieved. Shipment dispatched via ballistic supply pod for immediate delivery. Have a nice day.", "Thank You For Your Patronage")
spawn(rand(100, 300))
new /datum/random_map/droppod/supply(null, drop_x, drop_y, drop_z, supplied_drop = drop_type) // Splat.
diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm
index 77ac7f697e3..013001e3880 100644
--- a/code/game/machinery/teleporter.dm
+++ b/code/game/machinery/teleporter.dm
@@ -93,7 +93,7 @@
var/turf/T = get_turf(R)
if(!T)
continue
- if(!(T.z in config.player_levels))
+ if(!(T.z in using_map.player_levels))
continue
var/tmpname = T.loc.name
if(areaindex[tmpname])
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index d580df268c0..267319b80c7 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -64,6 +64,11 @@
var/obj/item/weapon/coin/coin
var/datum/wires/vending/wires = null
+ var/list/log = list()
+ var/req_log_access = access_cargo //default access for checking logs is cargo
+ var/has_logs = 0 //defaults to 0, set to anything else for vendor to have logs
+
+
/obj/machinery/vending/New()
..()
wires = new(src)
@@ -496,6 +501,8 @@
flick(icon_vend,src)
spawn(vend_delay)
R.get_product(get_turf(src))
+ if(has_logs)
+ do_logging(R, user, 1)
if(prob(1))
sleep(3)
if(R.get_product(get_turf(src)))
@@ -507,6 +514,44 @@
currently_vending = null
nanomanager.update_uis(src)
+ return 1
+
+/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0)
+ if(user.GetIdCard())
+ var/obj/item/weapon/card/id/tempid = user.GetIdCard()
+ var/list/list_item = list()
+ if(vending)
+ list_item += "vend"
+ else
+ list_item += "stock"
+ list_item += tempid.registered_name
+ list_item += stationtime2text()
+ list_item += R.item_name
+ log[++log.len] = list_item
+
+/obj/machinery/vending/proc/show_log(mob/user as mob)
+ if(user.GetIdCard())
+ var/obj/item/weapon/card/id/tempid = user.GetIdCard()
+ if(req_log_access in tempid.GetAccess())
+ var/datum/browser/popup = new(user, "vending_log", "Vending Log", 700, 500)
+ var/dat = ""
+ dat += "
[name] Vending Log
"
+ dat += "
Welcome [user.name]!
"
+ dat += "Below are the recent vending logs for your vending machine. "
+ for(var/i in log)
+ dat += json_encode(i)
+ dat += "; "
+ popup.set_content(dat)
+ popup.open()
+ else
+ to_chat(user,"You do not have the required access to view the vending logs for this machine.")
+
+/obj/machinery/vending/verb/check_logs()
+ set name = "Check Vending Logs"
+ set category = "Object"
+ set src in oview(1)
+
+ show_log(usr)
/**
* Add item to the machine
@@ -520,6 +565,8 @@
user << "You insert \the [W] in the product receptor."
R.add_product(W)
+ if(has_logs)
+ do_logging(R, user)
nanomanager.update_uis(src)
@@ -677,6 +724,8 @@
product_slogans = "I hope nobody asks me for a bloody cup o' tea...;Alcohol is humanity's friend. Would you abandon a friend?;Quite delighted to serve you!;Is nobody thirsty on this station?"
product_ads = "Drink up!;Booze is good for you!;Alcohol is humanity's best friend.;Quite delighted to serve you!;Care for a nice, cold beer?;Nothing cures you like booze!;Have a sip!;Have a drink!;Have a beer!;Beer is good for you!;Only the finest alcohol!;Best quality booze since 2053!;Award-winning wine!;Maximum alcohol!;Man loves beer.;A toast for progress!"
req_access = list(access_bar)
+ req_log_access = access_bar
+ has_logs = 1
/obj/machinery/vending/assist
products = list( /obj/item/device/assembly/prox_sensor = 5,/obj/item/device/assembly/igniter = 3,/obj/item/device/assembly/signaler = 4,
@@ -697,9 +746,6 @@
contraband = list(/obj/item/weapon/reagent_containers/food/drinks/ice = 10)
prices = list(/obj/item/weapon/reagent_containers/food/drinks/coffee = 3, /obj/item/weapon/reagent_containers/food/drinks/tea = 3, /obj/item/weapon/reagent_containers/food/drinks/h_chocolate = 3)
-
-
-
/obj/machinery/vending/snack
name = "Getmore Chocolate Corp"
desc = "A snack machine courtesy of the Getmore Chocolate Corporation, based out of Mars."
@@ -714,8 +760,6 @@
/obj/item/weapon/reagent_containers/food/snacks/sosjerky = 2,/obj/item/weapon/reagent_containers/food/snacks/no_raisin = 1,/obj/item/weapon/reagent_containers/food/snacks/spacetwinkie = 1,
/obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers = 1, /obj/item/weapon/reagent_containers/food/snacks/tastybread = 2, /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks = 4)
-
-
/obj/machinery/vending/cola
name = "Robust Softdrinks"
desc = "A softdrink vendor provided by Robust Industries, LLC."
@@ -737,8 +781,8 @@
name = "SweatMAX"
desc = "Fueled by your inner inadequacy!"
icon_state = "fitness"
- products = list(/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton = 8,
- /obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate = 8,
+ products = list(/obj/item/weapon/reagent_containers/food/drinks/smallmilk = 8,
+ /obj/item/weapon/reagent_containers/food/drinks/smallchocmilk = 8,
/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/proteinshake = 8,
/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask = 8,
/obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 8,
@@ -746,8 +790,8 @@
/obj/item/weapon/reagent_containers/pill/diet = 8,
/obj/item/weapon/towel/random = 8)
- prices = list(/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton = 3,
- /obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate = 3,
+ prices = list(/obj/item/weapon/reagent_containers/food/drinks/smallmilk = 3,
+ /obj/item/weapon/reagent_containers/food/drinks/smallchocmilk = 3,
/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask/proteinshake = 20,
/obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask = 5,
/obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar = 5,
@@ -768,7 +812,8 @@
products = list(/obj/item/weapon/cartridge/medical = 10,/obj/item/weapon/cartridge/engineering = 10,/obj/item/weapon/cartridge/security = 10,
/obj/item/weapon/cartridge/janitor = 10,/obj/item/weapon/cartridge/signal/science = 10,/obj/item/device/pda/heads = 10,
/obj/item/weapon/cartridge/captain = 3,/obj/item/weapon/cartridge/quartermaster = 10)
-
+ req_log_access = access_hop
+ has_logs = 1
/obj/machinery/vending/cigarette
name = "Cigarette machine" //OCD had to be uppercase to look nice with the new formating
@@ -798,7 +843,6 @@
/obj/item/weapon/storage/box/matches = 1,
/obj/item/weapon/flame/lighter/random = 2)
-
/obj/machinery/vending/medical
name = "NanoMed Plus"
desc = "Medical drug dispenser."
@@ -813,7 +857,8 @@
/obj/item/stack/medical/advanced/bruise_pack = 3, /obj/item/stack/medical/advanced/ointment = 3, /obj/item/stack/medical/splint = 2)
contraband = list(/obj/item/weapon/reagent_containers/pill/tox = 3,/obj/item/weapon/reagent_containers/pill/stox = 4,/obj/item/weapon/reagent_containers/pill/antitox = 6)
idle_power_usage = 211 //refrigerator - believe it or not, this is actually the average power consumption of a refrigerated vending machine according to NRCan.
-
+ req_log_access = access_cmo
+ has_logs = 1
//This one's from bay12
/obj/machinery/vending/phoronresearch
@@ -822,6 +867,8 @@
products = list(/obj/item/clothing/under/rank/scientist = 6,/obj/item/clothing/suit/bio_suit = 6,/obj/item/clothing/head/bio_hood = 6,
/obj/item/device/transfer_valve = 6,/obj/item/device/assembly/timer = 6,/obj/item/device/assembly/signaler = 6,
/obj/item/device/assembly/prox_sensor = 6,/obj/item/device/assembly/igniter = 6)
+ req_log_access = access_rd
+ has_logs = 1
/obj/machinery/vending/wallmed1
name = "NanoMed"
@@ -832,6 +879,8 @@
density = 0 //It is wall-mounted, and thus, not dense. --Superxpdude
products = list(/obj/item/stack/medical/bruise_pack = 2,/obj/item/stack/medical/ointment = 2,/obj/item/weapon/reagent_containers/hypospray/autoinjector = 4,/obj/item/device/healthanalyzer = 1)
contraband = list(/obj/item/weapon/reagent_containers/syringe/antitoxin = 4,/obj/item/weapon/reagent_containers/syringe/antiviral = 4,/obj/item/weapon/reagent_containers/pill/tox = 1)
+ req_log_access = access_cmo
+ has_logs = 1
/obj/machinery/vending/wallmed2
name = "NanoMed"
@@ -842,6 +891,8 @@
products = list(/obj/item/weapon/reagent_containers/hypospray/autoinjector = 5,/obj/item/weapon/reagent_containers/syringe/antitoxin = 3,/obj/item/stack/medical/bruise_pack = 3,
/obj/item/stack/medical/ointment =3,/obj/item/device/healthanalyzer = 3)
contraband = list(/obj/item/weapon/reagent_containers/pill/tox = 3)
+ req_log_access = access_cmo
+ has_logs = 1
/obj/machinery/vending/security
name = "SecTech"
@@ -853,6 +904,8 @@
products = list(/obj/item/weapon/handcuffs = 8,/obj/item/weapon/grenade/flashbang = 4,/obj/item/device/flash = 5,
/obj/item/weapon/reagent_containers/food/snacks/donut/normal = 12,/obj/item/weapon/storage/box/evidence = 6)
contraband = list(/obj/item/clothing/glasses/sunglasses = 2,/obj/item/weapon/storage/box/donut = 2)
+ req_log_access = access_armory
+ has_logs = 1
/obj/machinery/vending/hydronutrients
name = "NutriMax"
@@ -944,8 +997,6 @@
/obj/item/weapon/storage/toolbox/lunchbox/cti = 3,
/obj/item/weapon/storage/toolbox/lunchbox/nymph = 3,
/obj/item/weapon/storage/toolbox/lunchbox/syndicate = 3)
-
-
contraband = list(/obj/item/weapon/material/knife/butch = 2)
/obj/machinery/vending/sovietsoda
@@ -969,6 +1020,8 @@
/obj/item/device/flashlight/glowstick/orange =3, /obj/item/device/flashlight/glowstick/yellow = 3)
contraband = list(/obj/item/weapon/weldingtool/hugetank = 2,/obj/item/clothing/gloves/fyellow = 2,)
premium = list(/obj/item/clothing/gloves/yellow = 1)
+ req_log_access = access_ce
+ has_logs = 1
/obj/machinery/vending/engivend
name = "Engi-Vend"
@@ -990,6 +1043,8 @@
contraband = list(/obj/item/weapon/cell/potato = 3)
premium = list(/obj/item/weapon/storage/belt/utility = 3)
product_records = list()
+ req_log_access = access_ce
+ has_logs = 1
//This one's from bay12
/obj/machinery/vending/engineering
@@ -1007,6 +1062,8 @@
// There was an incorrect entry (cablecoil/power). I improvised to cablecoil/heavyduty.
// Another invalid entry, /obj/item/weapon/circuitry. I don't even know what that would translate to, removed it.
// The original products list wasn't finished. The ones without given quantities became quantity 5. -Sayu
+ req_log_access = access_ce
+ has_logs = 1
//This one's from bay12
/obj/machinery/vending/robotics
@@ -1020,3 +1077,5 @@
/obj/item/weapon/surgical/scalpel = 2,/obj/item/weapon/surgical/circular_saw = 2,/obj/item/weapon/tank/anesthetic = 2,/obj/item/clothing/mask/breath/medical = 5,
/obj/item/weapon/screwdriver = 5,/obj/item/weapon/crowbar = 5)
//everything after the power cell had no amounts, I improvised. -Sayu
+ req_log_access = access_rd
+ has_logs = 1
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm
index fdf4a16b005..ffe30bf3fd8 100644
--- a/code/game/mecha/equipment/tools/medical_tools.dm
+++ b/code/game/mecha/equipment/tools/medical_tools.dm
@@ -348,13 +348,13 @@
NC.cableColor("red")
NC.d1 = 0
NC.d2 = fdirn
- NC.updateicon()
+ NC.update_icon()
var/datum/powernet/PN
if(last_piece && last_piece.d2 != chassis.dir)
last_piece.d1 = min(last_piece.d2, chassis.dir)
last_piece.d2 = max(last_piece.d2, chassis.dir)
- last_piece.updateicon()
+ last_piece.update_icon()
PN = last_piece.powernet
if(!PN)
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index da744422cf8..1292a3747bc 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -181,7 +181,7 @@
sleep(15)
visible_message("\icon[src] [src] beeps: \"User DB corrupted \[Code 0x00FA\]. Truncating data structure...\"")
sleep(30)
- visible_message("\icon[src] [src] beeps: \"User DB truncated. Please contact your [company_name] system operator for future assistance.\"")
+ visible_message("\icon[src] [src] beeps: \"User DB truncated. Please contact your [using_map.company_name] system operator for future assistance.\"")
req_access = null
emagged = 1
return 1
diff --git a/code/game/mecha/mech_prosthetics.dm b/code/game/mecha/mech_prosthetics.dm
index 49efb68cf3d..8cea4b22c3d 100644
--- a/code/game/mecha/mech_prosthetics.dm
+++ b/code/game/mecha/mech_prosthetics.dm
@@ -208,7 +208,7 @@
sleep(15)
visible_message("\icon[src] [src] beeps: \"User DB corrupted \[Code 0x00FA\]. Truncating data structure...\"")
sleep(30)
- visible_message("\icon[src] [src] beeps: \"User DB truncated. Please contact your [company_name] system operator for future assistance.\"")
+ visible_message("\icon[src] [src] beeps: \"User DB truncated. Please contact your [using_map.company_name] system operator for future assistance.\"")
req_access = null
emagged = 1
return 1
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index b742b8a14b2..09ff0075dbf 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -173,7 +173,7 @@
cell = C
return
cell = new(src)
- cell.name = "high-capacity power cell"
+ cell.name = "mecha power cell"
cell.charge = 15000
cell.maxcharge = 15000
@@ -514,6 +514,7 @@
if(H.species.can_shred(user))
if(!prob(src.deflect_chance))
src.take_damage(15)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
src.check_for_internal_damage(list(MECHA_INT_TEMP_CONTROL,MECHA_INT_TANK_BREACH,MECHA_INT_CONTROL_LOST))
playsound(src.loc, 'sound/weapons/slash.ogg', 50, 1, -1)
user << "You slash at the armored suit!"
diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm
index e9dbd93edf7..a6da9bfa000 100644
--- a/code/game/mecha/mecha_control_console.dm
+++ b/code/game/mecha/mecha_control_console.dm
@@ -105,7 +105,7 @@
proc/shock()
var/obj/mecha/M = in_mecha()
if(M)
- M.emp_act(2)
+ M.emp_act(4)
qdel(src)
proc/get_mecha_log()
diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index d7e530b761f..485ea6987b2 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -333,7 +333,7 @@ steam.start() -- spawns the effect
spawn(0)
var/turf/T = get_turf(src.holder)
if(T != src.oldposition)
- if(istype(T, /turf/space))
+ if(isturf(T))
var/obj/effect/effect/ion_trails/I = PoolOrNew(/obj/effect/effect/ion_trails, src.oldposition)
src.oldposition = T
I.set_dir(src.holder.dir)
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index 88bbe2a7216..3ecb7c7b2db 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -135,7 +135,7 @@
new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc)
new /obj/item/clothing/head/flatcap(src.loc)
new /obj/item/clothing/mask/smokable/cigarette/cigar/havana(src.loc)
- new /obj/item/clothing/shoes/jackboots(src.loc)
+ new /obj/item/clothing/shoes/boots/jackboots(src.loc)
delete_me = 1
/obj/effect/landmark/costume/nyangirl/New()
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index b7b258f5d6e..1077d757ae3 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -77,6 +77,8 @@
desc = "They seem to pulse slightly with an inner life"
icon_state = "eggs"
var/amount_grown = 0
+ var/spiders_min = 6
+ var/spiders_max = 24
New()
pixel_x = rand(3,-3)
pixel_y = rand(3,-3)
@@ -97,7 +99,7 @@
/obj/effect/spider/eggcluster/process()
amount_grown += rand(0,2)
if(amount_grown >= 100)
- var/num = rand(6,24)
+ var/num = rand(spiders_min, spiders_max)
var/obj/item/organ/external/O = null
if(istype(loc, /obj/item/organ/external))
O = loc
@@ -108,6 +110,10 @@
O.implants += spiderling
qdel(src)
+/obj/effect/spider/eggcluster/small
+ spiders_min = 1
+ spiders_max = 3
+
/obj/effect/spider/spiderling
name = "spiderling"
desc = "It never stays still for long."
diff --git a/code/game/objects/effects/zone_divider.dm b/code/game/objects/effects/zone_divider.dm
new file mode 100644
index 00000000000..5adabf318c3
--- /dev/null
+++ b/code/game/objects/effects/zone_divider.dm
@@ -0,0 +1,20 @@
+// This artificially splits a ZAS zone, useful if you wish to prevent massive super-zones which can cause lag.
+/obj/effect/zone_divider
+ name = "zone divider"
+ icon = 'icons/mob/screen1.dmi'
+ icon_state = "x3"
+ invisibility = 101 //nope, can't see this
+ anchored = 1
+ density = 0
+ opacity = 0
+
+/obj/effect/zone_divider/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
+ // Special case to prevent us from being part of a zone during the first air master tick.
+ // We must merge ourselves into a zone on next tick. This will cause a bit of lag on
+ // startup, but it can't really be helped you know?
+ if(air_master && air_master.current_cycle == 0)
+ spawn(1)
+ air_master.mark_for_update(get_turf(src))
+ return 0
+ return !air_group // Anything except zones can pass
+
diff --git a/code/game/objects/empulse.dm b/code/game/objects/empulse.dm
index c1df6b5454b..3b1a3b54f52 100644
--- a/code/game/objects/empulse.dm
+++ b/code/game/objects/empulse.dm
@@ -4,17 +4,17 @@
// #define EMPDEBUG 10
-proc/empulse(turf/epicenter, heavy_range, light_range, log=0)
+proc/empulse(turf/epicenter, first_range, second_range, third_range, fourth_range, log=0)
if(!epicenter) return
if(!istype(epicenter, /turf))
epicenter = get_turf(epicenter.loc)
if(log)
- message_admins("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ")
- log_game("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ")
+ message_admins("EMP with size ([first_range], [second_range], [third_range], [fourth_range]) in area [epicenter.loc.name] ")
+ log_game("EMP with size ([first_range], [second_range], [third_range], [fourth_range]) in area [epicenter.loc.name] ")
- if(heavy_range > 1)
+ if(first_range > 1)
var/obj/effect/overlay/pulse = PoolOrNew(/obj/effect/overlay, epicenter)
pulse.icon = 'icons/effects/effects.dmi'
pulse.icon_state = "emppulse"
@@ -23,28 +23,50 @@ proc/empulse(turf/epicenter, heavy_range, light_range, log=0)
spawn(20)
qdel(pulse)
- if(heavy_range > light_range)
- light_range = heavy_range
+ if(first_range > second_range)
+ second_range = first_range
+ if(second_range > third_range)
+ third_range = second_range
+ if(third_range > fourth_range)
+ fourth_range = third_range
- for(var/mob/M in range(heavy_range, epicenter))
+ for(var/mob/M in range(first_range, epicenter))
M << 'sound/effects/EMPulse.ogg'
- for(var/atom/T in range(light_range, epicenter))
+ for(var/atom/T in range(fourth_range, epicenter))
#ifdef EMPDEBUG
var/time = world.timeofday
#endif
var/distance = get_dist(epicenter, T)
if(distance < 0)
distance = 0
- if(distance < heavy_range)
+ //Worst effects, really hurts
+ if(distance < first_range)
T.emp_act(1)
- else if(distance == heavy_range)
+ else if(distance == first_range)
if(prob(50))
T.emp_act(1)
else
T.emp_act(2)
- else if(distance <= light_range)
+ //Slightly less painful
+ else if(distance <= second_range)
T.emp_act(2)
+ else if(distance == second_range)
+ if(prob(50))
+ T.emp_act(2)
+ else
+ T.emp_act(3)
+ //Even less slightly less painful
+ else if(distance <= third_range)
+ T.emp_act(3)
+ else if(distance == third_range)
+ if(prob(50))
+ T.emp_act(2)
+ else
+ T.emp_act(3)
+ //This should be more or less harmless
+ else if(distance <= fourth_range)
+ T.emp_act(4)
#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()!")
diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm
index 17c7d762480..0577fee4a70 100644
--- a/code/game/objects/items/blueprints.dm
+++ b/code/game/objects/items/blueprints.dm
@@ -19,6 +19,23 @@
var/const/ROOM_ERR_SPACE = -1
var/const/ROOM_ERR_TOOLARGE = -2
+ var/static/list/SPACE_AREA_TYPES = list(
+ /area/space,
+ /area/mine
+ )
+ var/static/list/SPECIAL_AREA_TYPES = list(
+ /area/shuttle,
+ /area/admin,
+ /area/arrival,
+ /area/centcom,
+ /area/asteroid,
+ /area/tdome,
+ /area/syndicate_station,
+ /area/wizard_station,
+ /area/prison
+ // /area/derelict //commented out, all hail derelict-rebuilders!
+ )
+
/obj/item/blueprints/attack_self(mob/M as mob)
if (!istype(M,/mob/living/carbon/human))
M << "This stack of blue paper means nothing to you." //monkeys cannot into projecting
@@ -48,7 +65,7 @@
var/area/A = get_area()
var/text = {"[src]
[station_name()] blueprints
-Property of [company_name]. For heads of staff only. Store in high-secure storage.
+Property of [using_map.company_name]. For heads of staff only. Store in high-secure storage.
"}
switch (get_area_type())
if (AREA_SPACE)
@@ -79,22 +96,11 @@ move an amendment to the drawing.
return A
/obj/item/blueprints/proc/get_area_type(var/area/A = get_area())
- if(istype(A, /area/space))
- return AREA_SPACE
- var/list/SPECIALS = list(
- /area/shuttle,
- /area/admin,
- /area/arrival,
- /area/centcom,
- /area/asteroid,
- /area/tdome,
- /area/syndicate_station,
- /area/wizard_station,
- /area/prison
- // /area/derelict //commented out, all hail derelict-rebuilders!
- )
- for (var/type in SPECIALS)
- if ( istype(A,type) )
+ for(var/type in SPACE_AREA_TYPES)
+ if(istype(A, type))
+ return AREA_SPACE
+ for (var/type in SPECIAL_AREA_TYPES)
+ if(istype(A, type))
return AREA_SPECIAL
return AREA_STATION
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index e72b4ba4846..ef37af91c28 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -998,7 +998,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
M.apply_damage( rand(30,60) , BURN)
message += "You feel a searing heat! Your [P] is burning!"
if(i>=20 && i<=25) //EMP
- empulse(P.loc, 3, 6, 1)
+ empulse(P.loc, 1, 2, 4, 6, 1)
message += "Your [P] emits a wave of electromagnetic energy!"
if(i>=25 && i<=40) //Smoke
var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem
diff --git a/code/game/objects/items/devices/communicator/communicator.dm b/code/game/objects/items/devices/communicator/communicator.dm
index 2f0d7f1c3ce..8bfe2dffca2 100644
--- a/code/game/objects/items/devices/communicator/communicator.dm
+++ b/code/game/objects/items/devices/communicator/communicator.dm
@@ -213,6 +213,17 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
update_icon()
ui_interact(user)
+// Proc: MouseDrop()
+//Same thing PDAs do
+/obj/item/device/communicator/MouseDrop(obj/over_object as obj)
+ var/mob/M = usr
+ if (!(src.loc == usr) || (src.loc && src.loc.loc == usr))
+ return
+ if(!istype(over_object, /obj/screen))
+ return attack_self(M)
+ return
+
+
// Proc: attack_ghost()
// Parameters: 1 (user - the ghost clicking on the device)
// Description: Recreates the known_devices list, so that the ghost looking at the device can see themselves, then calls ..() so that NanoUI appears.
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index 216e2e59d07..c480d2dd160 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -35,12 +35,12 @@
/obj/item/device/radio/intercom/department/medbay
name = "station intercom (Medbay)"
- icon_state = "secintercom"
+ icon_state = "medintercom"
frequency = MED_I_FREQ
/obj/item/device/radio/intercom/department/security
name = "station intercom (Security)"
- icon_state = "medintercom"
+ icon_state = "secintercom"
frequency = SEC_I_FREQ
/obj/item/device/radio/intercom/entertainment
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 56311a52df1..56229e6cf39 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -52,8 +52,8 @@ REAGENT SCANNER
if (!istype(M,/mob/living/carbon/human) || M.isSynthetic())
//these sensors are designed for organic life
user.show_message("Analyzing Results for ERROR:\n\t Overall Status: ERROR")
- user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1)
- user.show_message(" Damage Specifics: ? - ? - ? - ?")
+ user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1)
+ user.show_message(" Damage Specifics: ? - ? - ? - ?")
user.show_message("Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1)
user.show_message("Warning: Blood Level ERROR: --% --cl.Type: ERROR")
user.show_message("Subject's pulse: -- bpm.")
@@ -70,8 +70,8 @@ REAGENT SCANNER
user.show_message("Overall Status: dead")
else
user.show_message("Analyzing Results for [M]:\n\t Overall Status: [M.stat > 1 ? "dead" : "[round((M.health/M.maxHealth)*100) ]% healthy"]")
- user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1)
- user.show_message(" Damage Specifics: [OX] - [TX] - [BU] - [BR]")
+ user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1)
+ user.show_message(" Damage Specifics: [OX] - [TX] - [BU] - [BR]")
user.show_message("Body Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1)
if(M.tod && (M.stat == DEAD || (M.status_flags & FAKEDEATH)))
user.show_message("Time of Death: [M.tod]")
@@ -92,7 +92,7 @@ REAGENT SCANNER
else
user.show_message(" Limbs are OK.",1)
- OX = M.getOxyLoss() > 50 ? "Severe oxygen deprivation detected" : "Subject bloodstream oxygen level normal"
+ OX = M.getOxyLoss() > 50 ? "Severe oxygen deprivation detected" : "Subject bloodstream oxygen level normal"
TX = M.getToxLoss() > 50 ? "Dangerous amount of toxins detected" : "Subject bloodstream toxin level minimal"
BU = M.getFireLoss() > 50 ? "Severe burn damage detected" : "Subject burn injury status O.K"
BR = M.getBruteLoss() > 50 ? "Severe anatomical damage detected" : "Subject brute-force injury status O.K"
diff --git a/code/game/objects/items/devices/translator.dm b/code/game/objects/items/devices/translator.dm
new file mode 100644
index 00000000000..0bb26b32bc7
--- /dev/null
+++ b/code/game/objects/items/devices/translator.dm
@@ -0,0 +1,79 @@
+//Universal translator
+/obj/item/device/universal_translator
+ name = "handheld translator"
+ desc = "This handy device appears to translate the languages it hears into onscreen text for a user."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "translator"
+ w_class = ITEMSIZE_SMALL
+ origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 3)
+ var/mult_icons = 1 //Changes sprite when it translates
+ var/visual = 1 //If you need to see to get the message
+ var/audio = 0 //If you need to hear to get the message
+ var/listening = 0
+ var/datum/language/langset
+
+/obj/item/device/universal_translator/attack_self(mob/user)
+ if(!listening) //Turning ON
+ langset = input(user,"Translate to which of your languages?","Language Selection") as null|anything in user.languages
+ if(langset)
+ if(langset && ((langset.flags & NONVERBAL) || (langset.flags & HIVEMIND)))
+ to_chat(user, "\The [src] cannot output that language.")
+ return
+ else
+ listening = 1
+ listening_objects |= src
+ if(mult_icons)
+ icon_state = "[initial(icon_state)]1"
+ to_chat(user, "You enable \the [src], translating into [langset.name].")
+ else //Turning OFF
+ listening = 0
+ listening_objects -= src
+ langset = null
+ icon_state = "[initial(icon_state)]"
+ to_chat(user, "You disable \the [src].")
+
+/obj/item/device/universal_translator/hear_talk(var/mob/speaker, var/message, var/vrb, var/datum/language/language)
+ if(!listening || !istype(speaker))
+ return
+
+ //Show the "I heard something" animation.
+ if(mult_icons)
+ flick("[initial(icon_state)]2",src)
+
+ //Handheld or pocket only.
+ if(!isliving(loc))
+ return
+
+ var/mob/living/L = loc
+
+ if (language && (language.flags & NONVERBAL))
+ return //Not gonna translate sign language
+
+ if (visual && ((L.sdisabilities & BLIND) || L.eye_blind))
+ return //Can't see the screen, don't get the message
+
+ if (audio && ((L.sdisabilities & DEAF) || L.ear_deaf))
+ return //Can't hear the translation, don't get the message
+
+ //Only translate if they can't understand, otherwise pointlessly spammy
+ //I'll just assume they don't look at the screen in that case
+
+ //They don't understand the spoken language we're translating FROM
+ if(!L.say_understands(speaker,language))
+ //They understand the output language
+ if(L.say_understands(null,langset))
+ to_chat(L, "[src] translates, \"[message]\"")
+
+ //They don't understand the output language
+ else
+ to_chat(L, "[src] translates, \"[langset.scramble(message)]\"")
+
+//Let's try an ear-worn version
+/obj/item/device/universal_translator/ear
+ name = "translator earpiece"
+ desc = "This handy device appears to translate the languages it hears into another language for a user."
+ icon_state = "earpiece"
+ w_class = ITEMSIZE_TINY
+ slot_flags = SLOT_EARS
+ visual = 0
+ audio = 1
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm
index ce28a6eb0bd..9684bba4dbe 100755
--- a/code/game/objects/items/weapons/AI_modules.dm
+++ b/code/game/objects/items/weapons/AI_modules.dm
@@ -35,7 +35,7 @@ AI MODULES
return
if(ticker && ticker.mode && ticker.mode.name == "blob")
- usr << "Law uploads have been disabled by [company_name]!"
+ usr << "Law uploads have been disabled by [using_map.company_name]!"
return
if (comp.current.stat == 2 || comp.current.control_disabled == 1)
diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm
index 62f4925c9a4..3f834519516 100644
--- a/code/game/objects/items/weapons/cigs_lighters.dm
+++ b/code/game/objects/items/weapons/cigs_lighters.dm
@@ -85,10 +85,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM
body_parts_covered = 0
var/lit = 0
var/icon_on
- var/icon_off
var/type_butt = null
var/chem_volume = 0
var/smoketime = 0
+ var/is_pipe = 0 //Prevents a runtime with pipes
var/matchmes = "USER lights NAME with FLAME"
var/lightermes = "USER lights NAME with FLAME"
var/zippomes = "USER lights NAME with FLAME"
@@ -106,6 +106,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM
smoketime--
if(smoketime < 1)
die()
+ if(ishuman(loc))
+ var/mob/living/carbon/human/C = loc
+ to_chat(C, "Your [name] goes out.")
return
if(location)
location.hotspot_expose(700, 5)
@@ -119,19 +122,20 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/smokable/examine(mob/user)
..()
- if(lit == 1)
- var/smoke_percent = round((smoketime / initial(smoketime)) * 100)
- switch(smoke_percent)
- if(90 to INFINITY)
- user << "[src] has just begun to burn."
- if(60 to 90)
- user << "[src] has a good amount of burn time remaining."
- if(30 to 60)
- user << "[src] is about half finished."
- if(10 to 30)
- user << "[src] is starting to burn low."
- else
- user << "[src] is nearly burnt out!"
+ if(is_pipe)
+ return
+ var/smoke_percent = round((smoketime / initial(smoketime)) * 100)
+ switch(smoke_percent)
+ if(90 to INFINITY)
+ user << "[src] is still fresh."
+ if(60 to 90)
+ user << "[src] has a good amount of burn time remaining."
+ if(30 to 60)
+ user << "[src] is about half finished."
+ if(10 to 30)
+ user << "[src] is starting to burn low."
+ else
+ user << "[src] is nearly burnt out!"
/obj/item/clothing/mask/smokable/proc/light(var/flavor_text = "[usr] lights the [name].")
@@ -167,6 +171,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/smokable/proc/die(var/nomessage = 0)
var/turf/T = get_turf(src)
set_light(0)
+ processing_objects.Remove(src)
if (type_butt)
var/obj/item/butt = new type_butt(T)
transfer_fingerprints_to(butt)
@@ -175,12 +180,11 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(ismob(loc))
var/mob/living/M = loc
if (!nomessage)
- M << "Your [name] goes out."
+ to_chat(M, "Your [name] goes out.")
M.remove_from_mob(src) //un-equip it so the overlays can update
M.update_inv_wear_mask(0)
M.update_inv_l_hand(0)
M.update_inv_r_hand(1)
- processing_objects.Remove(src)
qdel(src)
else
new /obj/effect/decal/cleanable/ash(T)
@@ -189,12 +193,26 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if (!nomessage)
M << "Your [name] goes out, and you empty the ash."
lit = 0
- icon_state = icon_off
- item_state = icon_off
+ icon_state = initial(icon_state)
+ item_state = initial(item_state)
M.update_inv_wear_mask(0)
M.update_inv_l_hand(0)
M.update_inv_r_hand(1)
- processing_objects.Remove(src)
+ smoketime = 0
+ reagents.clear_reagents()
+ name = "empty [initial(name)]"
+
+/obj/item/clothing/mask/smokable/proc/quench()
+ lit = 0
+ processing_objects.Remove(src)
+ icon_state = initial(icon_state)
+ item_state = initial(item_state)
+
+ if(ismob(loc))
+ var/mob/living/M = loc
+ M.update_inv_wear_mask(0)
+ M.update_inv_l_hand(0)
+ M.update_inv_r_hand(1)
/obj/item/clothing/mask/smokable/attackby(obj/item/weapon/W as obj, mob/user as mob)
..()
@@ -223,6 +241,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM
else
return ..()
+/obj/item/clothing/mask/smokable/water_act(amount)
+ if(amount >= 5)
+ quench()
+
/obj/item/clothing/mask/smokable/cigarette
name = "cigarette"
desc = "A roll of tobacco and nicotine."
@@ -233,7 +255,6 @@ CIGARETTE PACKETS ARE IN FANCY.DM
slot_flags = SLOT_EARS | SLOT_MASK
attack_verb = list("burnt", "singed")
icon_on = "cigon" //Note - these are in masks.dmi not in cigarette.dmi
- icon_off = "cigoff"
type_butt = /obj/item/weapon/cigbutt
chem_volume = 15
smoketime = 300
@@ -269,8 +290,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/smokable/cigarette/attack_self(mob/user as mob)
if(lit == 1)
- user.visible_message("[user] calmly drops and treads on the lit [src], putting it out instantly.")
- die(1)
+ if(user.a_intent == I_HURT)
+ user.visible_message("[user] drops and treads on the lit [src], putting it out instantly.")
+ die(1)
+ else
+ user.visible_message("[user] puts out \the [src].")
+ quench()
return ..()
////////////
@@ -281,7 +306,6 @@ CIGARETTE PACKETS ARE IN FANCY.DM
desc = "A brown roll of tobacco and... well, you're not quite sure. This thing's huge!"
icon_state = "cigar2off"
icon_on = "cigar2on"
- icon_off = "cigar2off"
type_butt = /obj/item/weapon/cigbutt/cigarbutt
throw_speed = 0.5
item_state = "cigaroff"
@@ -298,14 +322,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
desc = "There's little more you could want from a cigar."
icon_state = "cigar2off"
icon_on = "cigar2on"
- icon_off = "cigar2off"
/obj/item/clothing/mask/smokable/cigarette/cigar/havana
name = "premium Havanian cigar"
desc = "A cigar fit for only the best of the best."
icon_state = "cigar2off"
icon_on = "cigar2on"
- icon_off = "cigar2off"
smoketime = 7200
chem_volume = 30
@@ -345,7 +367,6 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon_state = "pipeoff"
item_state = "pipeoff"
icon_on = "pipeon" //Note - these are in masks.dmi
- icon_off = "pipeoff"
smoketime = 0
chem_volume = 50
matchmes = "USER lights their NAME with their FLAME."
@@ -353,6 +374,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
zippomes = "With much care, USER lights their NAME with their FLAME."
weldermes = "USER recklessly lights NAME with FLAME."
ignitermes = "USER fiddles with FLAME, and manages to light their NAME with the power of science."
+ is_pipe = 1
/obj/item/clothing/mask/smokable/pipe/New()
..()
@@ -375,18 +397,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/smokable/pipe/attack_self(mob/user as mob)
if(lit == 1)
- user.visible_message("[user] puts out [src].", "You put out [src].")
- lit = 0
- icon_state = icon_off
- item_state = icon_off
- processing_objects.Remove(src)
- else if (smoketime)
- var/turf/location = get_turf(user)
- user.visible_message("[user] empties out [src].", "You empty out [src].")
- new /obj/effect/decal/cleanable/ash(location)
- smoketime = 0
- reagents.clear_reagents()
- name = "empty [initial(name)]"
+ if(user.a_intent == I_HURT)
+ user.visible_message("[user] empties the lit [src] on the floor!.")
+ die(1)
+ else
+ user.visible_message("[user] puts out \the [src].")
+ quench()
/obj/item/clothing/mask/smokable/pipe/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/melee/energy/sword))
@@ -431,7 +447,6 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon_state = "cobpipeoff"
item_state = "cobpipeoff"
icon_on = "cobpipeon" //Note - these are in masks.dmi
- icon_off = "cobpipeoff"
chem_volume = 35
/////////
diff --git a/code/game/objects/items/weapons/circuitboards/circuitboard.dm b/code/game/objects/items/weapons/circuitboards/circuitboard.dm
index f17ee1c292e..d6cb8065868 100644
--- a/code/game/objects/items/weapons/circuitboards/circuitboard.dm
+++ b/code/game/objects/items/weapons/circuitboards/circuitboard.dm
@@ -35,3 +35,22 @@
if(istype(M, build_path))
return 1
return 0
+
+//Should be called from the constructor of any machine to automatically populate the default parts
+/obj/item/weapon/circuitboard/proc/apply_default_parts(var/obj/machinery/M)
+ if(!istype(M))
+ return
+ if(!req_components)
+ return
+ M.component_parts = list()
+ for(var/comp_path in req_components)
+ var/comp_amt = req_components[comp_path]
+ if(!comp_amt)
+ continue
+
+ if(ispath(comp_path, /obj/item/stack))
+ M.component_parts += new comp_path(contain_parts ? M : null, comp_amt)
+ else
+ for(var/i in 1 to comp_amt)
+ M.component_parts += new comp_path(contain_parts ? M : null)
+ return
diff --git a/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm b/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm
index c46c519e9e6..a304184e254 100644
--- a/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm
+++ b/code/game/objects/items/weapons/circuitboards/computer/camera_monitor.dm
@@ -12,7 +12,7 @@
/obj/item/weapon/circuitboard/security/New()
..()
- network = station_networks
+ network = using_map.station_networks
/obj/item/weapon/circuitboard/security/engineering
name = T_BOARD("engineering camera monitor")
@@ -26,7 +26,7 @@
/obj/item/weapon/circuitboard/security/mining
name = T_BOARD("mining camera monitor")
build_path = /obj/machinery/computer/security/mining
- network = list("MINE")
+ network = list("Mining Outpost")
req_access = list()
/obj/item/weapon/circuitboard/security/telescreen/entertainment
diff --git a/code/game/objects/items/weapons/circuitboards/machinery/papershredder.dm b/code/game/objects/items/weapons/circuitboards/machinery/papershredder.dm
new file mode 100644
index 00000000000..ef4575bafbe
--- /dev/null
+++ b/code/game/objects/items/weapons/circuitboards/machinery/papershredder.dm
@@ -0,0 +1,13 @@
+#ifndef T_BOARD
+#error T_BOARD macro is not defined but we need it!
+#endif
+
+/obj/item/weapon/circuitboard/papershredder
+ name = T_BOARD("papershredder")
+ build_path = /obj/machinery/papershredder
+ board_type = new /datum/frame/frame_types/machine
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ req_components = list(
+ /obj/item/weapon/stock_parts/motor = 1,
+ /obj/item/weapon/stock_parts/gear = 2,
+ /obj/item/weapon/stock_parts/micro_laser = 1)
diff --git a/code/game/objects/items/weapons/grenades/emgrenade.dm b/code/game/objects/items/weapons/grenades/emgrenade.dm
index dd1d6a55b02..8f4cd48e2cc 100644
--- a/code/game/objects/items/weapons/grenades/emgrenade.dm
+++ b/code/game/objects/items/weapons/grenades/emgrenade.dm
@@ -3,12 +3,14 @@
icon_state = "emp"
item_state = "empgrenade"
origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 3)
- var/emp_heavy = 4
- var/emp_light = 10
+ var/emp_heavy = 2
+ var/emp_med = 4
+ var/emp_light = 7
+ var/emp_long = 10
prime()
..()
- if(empulse(src, emp_heavy, emp_light))
+ if(empulse(src, emp_heavy, emp_med, emp_light, emp_long))
qdel(src)
return
@@ -18,4 +20,6 @@
icon_state = "lyemp"
origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 3)
emp_heavy = 1
- emp_light = 4
\ No newline at end of file
+ emp_med = 2
+ emp_light = 3
+ emp_long = 4
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm
index 4e25bbe4fe6..6554e80f8bb 100644
--- a/code/game/objects/items/weapons/implants/implant.dm
+++ b/code/game/objects/items/weapons/implants/implant.dm
@@ -101,6 +101,10 @@ Implant Specifics: "}
meltdown()
if(2)
delay = rand(5*60*10,15*60*10) //from 5 to 15 minutes of free time
+ if(3)
+ delay = rand(2*60*10,5*60*10) //from 2 to 5 minutes of free time
+ if(4)
+ delay = rand(0.5*60*10,1*60*10) //from .5 to 1 minutes of free time
spawn(delay)
malfunction--
@@ -227,10 +231,22 @@ Implant Specifics: "}
return
malfunction = MALFUNCTION_TEMPORARY
switch (severity)
- if (2.0) //Weak EMP will make implant tear limbs off.
+ if (4) //Weak EMP will make implant tear limbs off.
+ if (prob(25))
+ small_boom()
+ if (3) //Weak EMP will make implant tear limbs off.
if (prob(50))
small_boom()
- if (1.0) //strong EMP will melt implant either making it go off, or disarming it
+ if (2) //strong EMP will melt implant either making it go off, or disarming it
+ if (prob(70))
+ if (prob(75))
+ small_boom()
+ else
+ if (prob(13))
+ activate() //chance of bye bye
+ else
+ meltdown() //chance of implant disarming
+ if (1) //strong EMP will melt implant either making it go off, or disarming it
if (prob(70))
if (prob(50))
small_boom()
@@ -320,7 +336,13 @@ the implant may become unstable and either pre-maturely inject the subject or si
if(prob(60))
activate(20)
if(2)
- if(prob(30))
+ if(prob(40))
+ activate(20)
+ if(3)
+ if(prob(40))
+ activate(5)
+ if(4)
+ if(prob(20))
activate(5)
spawn(20)
@@ -333,7 +355,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
/obj/item/weapon/implant/loyalty/get_data()
var/dat = {"
Implant Specifications:
-Name: [company_name] Employee Management Implant
+Name: [using_map.company_name] Employee Management Implant Life: Ten years. Important Notes: Personnel injected with this device tend to be much more loyal to the company.
@@ -349,11 +371,11 @@ the implant may become unstable and either pre-maturely inject the subject or si
var/mob/living/carbon/human/H = M
var/datum/antagonist/antag_data = get_antag_data(H.mind.special_role)
if(antag_data && (antag_data.flags & ANTAG_IMPLANT_IMMUNE))
- H.visible_message("[H] seems to resist the implant!", "You feel the corporate tendrils of [company_name] try to invade your mind!")
+ H.visible_message("[H] seems to resist the implant!", "You feel the corporate tendrils of [using_map.company_name] try to invade your mind!")
return 0
else
clear_antag_roles(H.mind, 1)
- H << "You feel a surge of loyalty towards [company_name]."
+ H << "You feel a surge of loyalty towards [using_map.company_name]."
return 1
@@ -403,7 +425,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
/obj/item/weapon/implant/death_alarm/get_data()
var/dat = {"
Implant Specifications:
-Name: [company_name] \"Profit Margin\" Class Employee Lifesign Sensor
+Name: [using_map.company_name] \"Profit Margin\" Class Employee Lifesign Sensor Life: Activates upon death. Important Notes: Alerts crew to crewmember death.
@@ -485,7 +507,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
/obj/item/weapon/implant/compressed/get_data()
var/dat = {"
Implant Specifications:
-Name: [company_name] \"Profit Margin\" Class Employee Lifesign Sensor
+Name: [using_map.company_name] \"Profit Margin\" Class Employee Lifesign Sensor Life: Activates upon death. Important Notes: Alerts crew to crewmember death.
diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm
index f872cd0bf4d..4cb92a07803 100644
--- a/code/game/objects/items/weapons/implants/implanter.dm
+++ b/code/game/objects/items/weapons/implants/implanter.dm
@@ -6,6 +6,7 @@
throw_speed = 1
throw_range = 5
w_class = ITEMSIZE_SMALL
+ matter = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 1000)
var/obj/item/weapon/implant/imp = null
/obj/item/weapon/implanter/attack_self(var/mob/user)
diff --git a/code/game/objects/items/weapons/manuals.dm b/code/game/objects/items/weapons/manuals.dm
index c69b3d61d1e..c89f41056fb 100644
--- a/code/game/objects/items/weapons/manuals.dm
+++ b/code/game/objects/items/weapons/manuals.dm
@@ -751,7 +751,7 @@
The Oath
- The Medical Oath sworn by recognised medical practitioners in the employ of [company_name]
+ The Medical Oath sworn by recognised medical practitioners in the employ of [using_map.company_name]
Now, as a new doctor, I solemnly promise that I will, to the best of my ability, serve humanity-caring for the sick, promoting good health, and alleviating pain and suffering.
diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm
index 49d0238c13a..06fd49d0e38 100644
--- a/code/game/objects/items/weapons/storage/belt.dm
+++ b/code/game/objects/items/weapons/storage/belt.dm
@@ -285,4 +285,59 @@
/obj/item/weapon/anobattery,
/obj/item/device/ano_scanner,
/obj/item/weapon/pickaxe/hand
- )
\ No newline at end of file
+ )
+
+/obj/item/weapon/storage/belt/fannypack
+ name = "leather fannypack"
+ desc = "A dorky fannypack for keeping small items in."
+ icon_state = "fannypack_leather"
+ item_state = "fannypack_leather"
+ max_w_class = ITEMSIZE_SMALL
+ storage_slots = null
+ max_storage_space = ITEMSIZE_COST_NORMAL * 2
+
+/obj/item/weapon/storage/belt/fannypack/black
+ name = "black fannypack"
+ icon_state = "fannypack_black"
+ item_state = "fannypack_black"
+
+/obj/item/weapon/storage/belt/fannypack/blue
+ name = "blue fannypack"
+ icon_state = "fannypack_blue"
+ item_state = "fannypack_blue"
+
+/obj/item/weapon/storage/belt/fannypack/cyan
+ name = "cyan fannypack"
+ icon_state = "fannypack_cyan"
+ item_state = "fannypack_cyan"
+
+/obj/item/weapon/storage/belt/fannypack/green
+ name = "green fannypack"
+ icon_state = "fannypack_green"
+ item_state = "fannypack_green"
+
+/obj/item/weapon/storage/belt/fannypack/orange
+ name = "orange fannypack"
+ icon_state = "fannypack_orange"
+ item_state = "fannypack_orange"
+
+/obj/item/weapon/storage/belt/fannypack/purple
+ name = "purple fannypack"
+ icon_state = "fannypack_purple"
+ item_state = "fannypack_purple"
+
+/obj/item/weapon/storage/belt/fannypack/red
+ name = "red fannypack"
+ icon_state = "fannypack_red"
+ item_state = "fannypack_red"
+
+/obj/item/weapon/storage/belt/fannypack/white
+ name = "white fannypack"
+ icon_state = "fannypack_white"
+ item_state = "fannypack_white"
+
+/obj/item/weapon/storage/belt/fannypack/yellow
+ name = "yellow fannypack"
+ icon_state = "fannypack_yellow"
+ item_state = "fannypack_yellow"
+
diff --git a/code/game/objects/items/weapons/storage/internal.dm b/code/game/objects/items/weapons/storage/internal.dm
index b135c439b60..8d1898fe4b2 100644
--- a/code/game/objects/items/weapons/storage/internal.dm
+++ b/code/game/objects/items/weapons/storage/internal.dm
@@ -50,10 +50,10 @@
if (!( user.restrained() ) && !( user.stat ))
switch(over_object.name)
if("r_hand")
- user.u_equip(master_item)
+ user.unEquip(master_item)
user.put_in_r_hand(master_item)
if("l_hand")
- user.u_equip(master_item)
+ user.unEquip(master_item)
user.put_in_l_hand(master_item)
master_item.add_fingerprint(user)
return 0
diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm
index 8c1c47713ae..3846a44d2b3 100644
--- a/code/game/objects/items/weapons/storage/storage.dm
+++ b/code/game/objects/items/weapons/storage/storage.dm
@@ -77,10 +77,10 @@
switch(over_object.name)
if("r_hand")
- usr.u_equip(src)
+ usr.unEquip(src)
usr.put_in_r_hand(src)
if("l_hand")
- usr.u_equip(src)
+ usr.unEquip(src)
usr.put_in_l_hand(src)
src.add_fingerprint(usr)
diff --git a/code/game/objects/items/weapons/surgery_tools.dm b/code/game/objects/items/weapons/surgery_tools.dm
index 2c5673790ae..9364f1b8590 100644
--- a/code/game/objects/items/weapons/surgery_tools.dm
+++ b/code/game/objects/items/weapons/surgery_tools.dm
@@ -150,12 +150,14 @@
//misc, formerly from code/defines/weapons.dm
/obj/item/weapon/surgical/bonegel
name = "bone gel"
+ desc = "For fixing bones."
icon_state = "bone-gel"
force = 0
throwforce = 1.0
/obj/item/weapon/surgical/FixOVein
name = "FixOVein"
+ desc = "Like bone gel. For veins."
icon_state = "fixovein"
force = 0
throwforce = 1.0
@@ -164,6 +166,7 @@
/obj/item/weapon/surgical/bonesetter
name = "bone setter"
+ desc = "Put them in their place."
icon_state = "bone setter"
force = 8.0
throwforce = 9.0
diff --git a/code/game/objects/items/weapons/tanks/tank_types.dm b/code/game/objects/items/weapons/tanks/tank_types.dm
index 6c2b6aa885f..0ff657e9cc6 100644
--- a/code/game/objects/items/weapons/tanks/tank_types.dm
+++ b/code/game/objects/items/weapons/tanks/tank_types.dm
@@ -103,7 +103,7 @@
/obj/item/weapon/tank/vox //Can't be a child of phoron or the gas amount gets screwey.
name = "phoron tank"
desc = "Contains dangerous phoron. Do not inhale. Warning: extremely flammable."
- icon_state = "oxygen_fr"
+ icon_state = "phoron_vox"
gauge_icon = null
flags = CONDUCT
distribute_pressure = ONE_ATMOSPHERE*O2STANDARD
@@ -209,4 +209,4 @@
/obj/item/weapon/tank/nitrogen/examine(mob/user)
if(..(user, 0) && air_contents.gas["nitrogen"] < 10)
user << text("The meter on \the [src] indicates you are almost out of nitrogen!")
- //playsound(user, 'sound/effects/alert.ogg', 50, 1)
\ No newline at end of file
+ //playsound(user, 'sound/effects/alert.ogg', 50, 1)
diff --git a/code/game/objects/items/weapons/trays.dm b/code/game/objects/items/weapons/trays.dm
index ca32d730f35..41bcedbf217 100644
--- a/code/game/objects/items/weapons/trays.dm
+++ b/code/game/objects/items/weapons/trays.dm
@@ -17,7 +17,7 @@
var/max_carry = 10
/obj/item/weapon/tray/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
-
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
// Drop all the things. All of them.
overlays.Cut()
for(var/obj/item/I in carrying)
diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm
index cd12ad5a0c3..5b1e33e5fd8 100644
--- a/code/game/objects/random/random.dm
+++ b/code/game/objects/random/random.dm
@@ -630,9 +630,9 @@ something, make sure it's not in one of the other lists.*/
prob(1);/obj/item/weapon/grenade/flashbang,
prob(1);/obj/item/weapon/melee/baton,
prob(1);/obj/item/weapon/reagent_containers/spray/pepper,
- prob(3);/obj/item/clothing/shoes/jackboots,
- prob(1);/obj/item/clothing/shoes/swat,
- prob(1);/obj/item/clothing/shoes/combat,
+ prob(3);/obj/item/clothing/shoes/boots/jackboots,
+ prob(1);/obj/item/clothing/shoes/boots/swat,
+ prob(1);/obj/item/clothing/shoes/boots/combat,
prob(1);/obj/item/clothing/gloves/swat,
prob(1);/obj/item/clothing/gloves/combat,
prob(1);/obj/item/clothing/glasses/sunglasses/big,
@@ -684,7 +684,7 @@ something, make sure it's not in one of the other lists.*/
prob(3);/obj/item/weapon/storage/box/gloves,
prob(2);/obj/item/weapon/storage/belt/medical/emt,
prob(2);/obj/item/weapon/storage/belt/medical,
- prob(1);/obj/item/clothing/shoes/combat,
+ prob(1);/obj/item/clothing/shoes/boots/combat,
prob(3);/obj/item/clothing/shoes/white,
prob(2);/obj/item/clothing/gloves/latex,
prob(5);/obj/item/clothing/gloves/white,
@@ -730,7 +730,7 @@ something, make sure it's not in one of the other lists.*/
prob(2);/obj/item/clothing/head/welding,
prob(4);/obj/item/clothing/suit/storage/hazardvest,
prob(2);/obj/item/clothing/under/overalls,
- prob(3);/obj/item/clothing/shoes/workboots,
+ prob(3);/obj/item/clothing/shoes/boots/workboots,
prob(1);/obj/item/clothing/shoes/magboots,
prob(2);/obj/item/clothing/accessory/storage/black_vest,
prob(2);/obj/item/clothing/accessory/storage/brown_vest,
@@ -839,4 +839,60 @@ var/list/random_useful_
random_junk_ -= /obj/item/trash/tray
return pick(random_junk_)
// Misc. actually useful stuff
- return get_random_useful_type()
\ No newline at end of file
+ return get_random_useful_type()
+
+/*
+ Selects one spawn point out of a group of points with the same ID and asks it to generate its items
+*/
+var/list/multi_point_spawns
+
+/obj/random_multi
+ name = "random object spawn point"
+ desc = "This item type is used to spawn random objects at round-start. Only one spawn point for a given group id is selected."
+ icon = 'icons/misc/mark.dmi'
+ icon_state = "x3"
+ invisibility = INVISIBILITY_MAXIMUM
+ var/id // Group id
+ var/weight // Probability weight for this spawn point
+
+/obj/random_multi/initialize()
+ ..()
+ weight = max(1, round(weight))
+
+ if(!multi_point_spawns)
+ multi_point_spawns = list()
+ var/list/spawnpoints = multi_point_spawns[id]
+ if(!spawnpoints)
+ spawnpoints = list()
+ multi_point_spawns[id] = spawnpoints
+ spawnpoints[src] = weight
+
+/obj/random_multi/Destroy()
+ var/list/spawnpoints = multi_point_spawns[id]
+ spawnpoints -= src
+ if(!spawnpoints.len)
+ multi_point_spawns -= id
+ . = ..()
+
+/obj/random_multi/proc/generate_items()
+ return
+
+/obj/random_multi/single_item
+ var/item_path // Item type to spawn
+
+/obj/random_multi/single_item/generate_items()
+ new item_path(loc)
+
+/hook/roundstart/proc/generate_multi_spawn_items()
+ for(var/id in multi_point_spawns)
+ var/list/spawn_points = multi_point_spawns[id]
+ var/obj/random_multi/rm = pickweight(spawn_points)
+ rm.generate_items()
+ for(var/entry in spawn_points)
+ qdel(entry)
+ return 1
+
+/obj/random_multi/single_item/captains_spare_id
+ name = "Multi Point - Captain's Spare"
+ id = "Captain's spare id"
+ item_path = /obj/item/weapon/card/id/captains_spare
\ No newline at end of file
diff --git a/code/game/objects/structures/crates_lockers/closets/gimmick.dm b/code/game/objects/structures/crates_lockers/closets/gimmick.dm
index 1a62db2dfbf..3a6b7ac0452 100644
--- a/code/game/objects/structures/crates_lockers/closets/gimmick.dm
+++ b/code/game/objects/structures/crates_lockers/closets/gimmick.dm
@@ -65,8 +65,8 @@
new /obj/item/clothing/head/helmet/swat(src)
new /obj/item/clothing/mask/gas(src)
new /obj/item/clothing/mask/gas(src)
- new /obj/item/clothing/shoes/swat(src)
- new /obj/item/clothing/shoes/swat(src)
+ new /obj/item/clothing/shoes/boots/swat(src)
+ new /obj/item/clothing/shoes/boots/swat(src)
new /obj/item/clothing/suit/armor/swat(src)
new /obj/item/clothing/suit/armor/swat(src)
new /obj/item/clothing/under/syndicate/tacticool(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
index 09aeac362f2..6dfd71f2bf9 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
@@ -142,6 +142,7 @@
new /obj/item/clothing/suit/storage/toggle/labcoat/emt(src)
new /obj/item/device/radio/headset/headset_med/alt(src)
new /obj/item/weapon/cartridge/medical(src)
+ new /obj/item/weapon/storage/briefcase/inflatable(src)
new /obj/item/device/flashlight(src)
new /obj/item/weapon/tank/emergency/oxygen/engi(src)
new /obj/item/clothing/glasses/hud/health(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
index 1136c6cfeba..07544c058b3 100644
--- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
+++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
@@ -29,9 +29,9 @@
new /obj/item/clothing/under/rank/security2(src)
new /obj/item/clothing/under/rank/security2(src)
new /obj/item/clothing/under/rank/security2(src)
- new /obj/item/clothing/shoes/jackboots(src)
- new /obj/item/clothing/shoes/jackboots(src)
- new /obj/item/clothing/shoes/jackboots(src)
+ new /obj/item/clothing/shoes/boots/jackboots(src)
+ new /obj/item/clothing/shoes/boots/jackboots(src)
+ new /obj/item/clothing/shoes/boots/jackboots(src)
new /obj/item/clothing/head/soft/sec(src)
new /obj/item/clothing/head/soft/sec(src)
new /obj/item/clothing/head/soft/sec(src)
@@ -190,8 +190,8 @@
new /obj/item/clothing/shoes/sandal(src)
new /obj/item/clothing/shoes/sandal(src)
new /obj/item/clothing/shoes/sandal(src)
- new /obj/item/clothing/shoes/winterboots(src)
- new /obj/item/clothing/shoes/winterboots(src)
+ new /obj/item/clothing/shoes/boots/winter(src)
+ new /obj/item/clothing/shoes/boots/winter(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat(src)
return
@@ -294,9 +294,9 @@
new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering(src)
new /obj/item/clothing/suit/storage/hooded/wintercoat/engineering(src)
- new /obj/item/clothing/shoes/workboots(src)
- new /obj/item/clothing/shoes/workboots(src)
- new /obj/item/clothing/shoes/workboots(src)
+ new /obj/item/clothing/shoes/boots/workboots(src)
+ new /obj/item/clothing/shoes/boots/workboots(src)
+ new /obj/item/clothing/shoes/boots/workboots(src)
return
@@ -564,7 +564,7 @@
new /obj/item/weapon/storage/belt/security/tactical(src)
if(prob(10))
new /obj/item/clothing/mask/bandana/skull(src)
- new /obj/item/clothing/shoes/jackboots(src)
+ new /obj/item/clothing/shoes/boots/jackboots(src)
new /obj/item/clothing/gloves/black(src)
new /obj/item/clothing/under/pants/camo(src)
return
@@ -582,7 +582,7 @@
new /obj/item/clothing/under/syndicate/combat(src)
new /obj/item/device/radio/headset/ert/alt(src)
new /obj/item/clothing/glasses/sunglasses(src)
- new /obj/item/clothing/shoes/swat(src)
+ new /obj/item/clothing/shoes/boots/swat(src)
new /obj/item/clothing/gloves/swat(src)
new /obj/item/clothing/mask/balaclava/tactical(src)
new /obj/item/clothing/mask/balaclava(src)
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 62a3c64e48e..add1bd2c2ae 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -283,9 +283,9 @@
/obj/structure/closet/crate/rcd
name = "\improper RCD crate"
desc = "A crate with rapid construction device."
- icon_state = "crate"
- icon_opened = "crateopen"
- icon_closed = "crate"
+ icon_state = "engi_crate"
+ icon_opened = "engi_crateopen"
+ icon_closed = "engi_crate"
/obj/structure/closet/crate/rcd/New()
..()
@@ -427,6 +427,20 @@
icon_opened = "hydrosecurecrateopen"
icon_closed = "hydrosecurecrate"
+/obj/structure/closet/crate/secure/engineering
+ desc = "A crate with a lock on it, painted in the scheme of the station's engineers."
+ name = "secure engineering crate"
+ icon_state = "engi_secure_crate"
+ icon_opened = "engi_secure_crateopen"
+ icon_closed = "engi_secure_crate"
+
+/obj/structure/closet/crate/secure/science
+ name = "secure science crate"
+ desc = "A crate with a lock on it, painted in the scheme of the station's scientists."
+ icon_state = "scisecurecrate"
+ icon_opened = "scisecurecrateopen"
+ icon_closed = "scisecurecrate"
+
/obj/structure/closet/crate/secure/bin
name = "secure bin"
desc = "A secure bin."
@@ -499,6 +513,23 @@
icon_opened = "largermetalopen"
icon_closed = "largermetal"
+/obj/structure/closet/crate/engineering
+ name = "engineering crate"
+ icon_state = "engi_crate"
+ icon_opened = "engi_crateopen"
+ icon_closed = "engi_crate"
+
+/obj/structure/closet/crate/engineering/electrical
+ icon_state = "engi_e_crate"
+ icon_opened = "engi_crateopen"
+ icon_closed = "engi_e_crate"
+
+/obj/structure/closet/crate/science
+ name = "science crate"
+ icon_state = "scicrate"
+ icon_opened = "scicrateopen"
+ icon_closed = "scicrate"
+
/obj/structure/closet/crate/hydroponics
name = "hydroponics crate"
desc = "All you need to destroy those pesky weeds and pests."
diff --git a/code/game/objects/structures/crates_lockers/largecrate.dm b/code/game/objects/structures/crates_lockers/largecrate.dm
index d8de10bf185..c0d27cad1cf 100644
--- a/code/game/objects/structures/crates_lockers/largecrate.dm
+++ b/code/game/objects/structures/crates_lockers/largecrate.dm
@@ -72,7 +72,7 @@
/obj/structure/largecrate/animal/goat
name = "goat crate"
- held_type = /mob/living/simple_animal/hostile/retaliate/goat
+ held_type = /mob/living/simple_animal/retaliate/goat
/obj/structure/largecrate/animal/cat
name = "cat carrier"
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index 834eadc2a45..d038b592fa7 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -107,6 +107,16 @@
airlock_type = "/highsecurity"
glass = -1
+/obj/structure/door_assembly/door_assembly_voidcraft
+ base_icon_state = "voidcraft"
+ base_name = "voidcraft hatch"
+ airlock_type = "/voidcraft"
+ glass = -1
+
+/obj/structure/door_assembly/door_assembly_voidcraft/vertical
+ base_icon_state = "voidcraft_vertical"
+ airlock_type = "/voidcraft/vertical"
+
/obj/structure/door_assembly/multi_tile
icon = 'icons/obj/doors/door_assembly2x1.dmi'
dir = EAST
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index 0ad1fb84045..1bfd559b9c3 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -32,6 +32,19 @@
..()
icon_state = "tree_[rand(1, 6)]"
+/obj/structure/flora/tree/sif
+ name = "glowing tree"
+ desc = "It's a tree, except this one seems quite alien. It glows a deep blue."
+ icon = 'icons/obj/flora/deadtrees.dmi'
+ icon_state = "tree_sif"
+
+/obj/structure/flora/tree/sif/New()
+ update_icon()
+
+/obj/structure/flora/tree/sif/update_icon()
+ set_light(5, 1, "#33ccff")
+ overlays.Cut()
+ overlays.Add(image(icon = 'icons/obj/flora/deadtrees.dmi', icon_state = "[icon_state]_glow", layer = LIGHTING_LAYER + 0.1))
//grass
/obj/structure/flora/grass
@@ -79,10 +92,6 @@
icon = 'icons/obj/plants.dmi'
icon_state = "plant-26"
-/obj/structure/flora/pottedplant/xmas/New()
- ..()
- icon_state = "plant-xmas"
-
//newbushes
@@ -205,4 +214,149 @@
name = "hanging skeleton model"
icon = 'icons/obj/plants.dmi'
icon_state = "hangskele"
- desc = "It's an anatomical model of a human skeletal system made of plaster."
\ No newline at end of file
+ desc = "It's an anatomical model of a human skeletal system made of plaster."
+
+
+//potted plants credit: Flashkirby
+/obj/structure/flora/pottedplant
+ name = "potted plant"
+ desc = "Really brings the room together."
+ icon = 'icons/obj/plants.dmi'
+ icon_state = "plant-01"
+
+/obj/structure/flora/pottedplant/large
+ name = "large potted plant"
+ desc = "This is a large plant. Three branches support pairs of waxy leaves."
+ icon_state = "plant-26"
+
+/obj/structure/flora/pottedplant/fern
+ name = "potted fern"
+ desc = "This is an ordinary looking fern. It looks like it could do with some water."
+ icon_state = "plant-02"
+
+/obj/structure/flora/pottedplant/overgrown
+ name = "overgrown potted plants"
+ desc = "This is an assortment of colourful plants. Some parts are overgrown."
+ icon_state = "plant-03"
+
+/obj/structure/flora/pottedplant/bamboo
+ name = "potted bamboo"
+ desc = "These are bamboo shoots. The tops looks like they've been cut short."
+ icon_state = "plant-04"
+
+/obj/structure/flora/pottedplant/largebush
+ name = "large potted bush"
+ desc = "This is a large bush. The leaves stick upwards in an odd fashion."
+ icon_state = "plant-05"
+
+/obj/structure/flora/pottedplant/thinbush
+ name = "thin potted bush"
+ desc = "This is a thin bush. It appears to be flowering."
+ icon_state = "plant-06"
+
+/obj/structure/flora/pottedplant/mysterious
+ name = "mysterious potted bulbs"
+ desc = "This is a mysterious looking plant. Touching the bulbs cause them to shrink."
+ icon_state = "plant-07"
+
+/obj/structure/flora/pottedplant/smalltree
+ name = "small potted tree"
+ desc = "This is a small tree. It is rather pleasant."
+ icon_state = "plant-08"
+
+/obj/structure/flora/pottedplant/unusual
+ name = "unusual potted plant"
+ desc = "This is an unusual plant. It's bulbous ends emit a soft blue light."
+ icon_state = "plant-09"
+ set_light(l_range = 1, l_power = 0.5, l_color = "#0000FF")
+
+/obj/structure/flora/pottedplant/orientaltree
+ name = "potted oriental tree"
+ desc = "This is a rather oriental style tree. It's flowers are bright pink."
+ icon_state = "plant-10"
+
+/obj/structure/flora/pottedplant/smallcactus
+ name = "small potted cactus"
+ desc = "This is a small cactus. Its needles are sharp."
+ icon_state = "plant-11"
+
+/obj/structure/flora/pottedplant/tall
+ name = "tall potted plant"
+ desc = "This is a tall plant. Tiny pores line its surface."
+ icon_state = "plant-12"
+
+/obj/structure/flora/pottedplant/sticky
+ name = "styicky potted plant"
+ desc = "This is an odd plant. Its sticky leaves trap insects."
+ icon_state = "plant-13"
+
+/obj/structure/flora/pottedplant/smelly
+ name = "smelly potted plant"
+ desc = "This is some kind of tropical plant. It reeks of rotten eggs."
+ icon_state = "plant-14"
+
+/obj/structure/flora/pottedplant/small
+ name = "small potted plant"
+ desc = "This is a pot of assorted small flora. Some look familiar."
+ icon_state = "plant-15"
+
+/obj/structure/flora/pottedplant/aquatic
+ name = "aquatic potted plant"
+ desc = "This is apparently an aquatic plant. It's probably fake."
+ icon_state = "plant-16"
+
+/obj/structure/flora/pottedplant/shoot
+ name = "small potted shoot"
+ desc = "This is a small shoot. It still needs time to grow."
+ icon_state = "plant-17"
+
+/obj/structure/flora/pottedplant/flower
+ name = "potted flower"
+ desc = "This is a slim plant. Sweet smelling flowers are supported by spindly stems."
+ icon_state = "plant-18"
+
+/obj/structure/flora/pottedplant/crystal
+ name = "crystalline potted plant"
+ desc = "These are rather cubic plants. Odd crystal formations grow on the end."
+ icon_state = "plant-19"
+
+/obj/structure/flora/pottedplant/subterranean
+ name = "subterranean potted plant"
+ desc = "This is a subterranean plant. It's bulbous ends glow faintly."
+ icon_state = "plant-20"
+ set_light(l_range = 1, l_power = 0.5, l_color = "#FF6633")
+
+/obj/structure/flora/pottedplant/minitree
+ name = "potted tree"
+ desc = "This is a miniature tree. Apparently it was grown to 1/5 scale."
+ icon_state = "plant-21"
+
+/obj/structure/flora/pottedplant/stoutbush
+ name = "stout potted bush"
+ desc = "This is a stout bush. Its leaves point up and outwards."
+ icon_state = "plant-22"
+
+/obj/structure/flora/pottedplant/drooping
+ name = "drooping potted plant"
+ desc = "This is a small plant. The drooping leaves make it look like its wilted."
+ icon_state = "plant-23"
+
+/obj/structure/flora/pottedplant/tropical
+ name = "tropical potted plant"
+ desc = "This is some kind of tropical plant. It hasn't begun to flower yet."
+ icon_state = "plant-24"
+
+/obj/structure/flora/pottedplant/dead
+ name = "dead potted plant"
+ desc = "This is the dried up remains of a dead plant. Someone should replace it."
+ icon_state = "plant-25"
+
+/obj/structure/flora/pottedplant/decorative
+ name = "decorative potted plant"
+ desc = "This is a decorative shrub. It's been trimmed into the shape of an apple."
+ icon_state = "applebush"
+
+/obj/structure/flora/pottedplant/xmas
+ name = "small christmas tree"
+ desc = "This is a tiny well lit decorative christmas tree."
+ icon_state = "plant-xmas"
\ No newline at end of file
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index 5d01438614c..0eb48e94e08 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -34,6 +34,11 @@
if(locate(/obj/structure/lattice, get_step(src, dir)))
L = locate(/obj/structure/lattice, get_step(src, dir))
L.updateOverlays(src.loc)
+ if(istype(loc, /turf/simulated/open))
+ var/turf/simulated/open/O = loc
+ spawn(1)
+ if(O) // If we built a new floor with the lattice, the open turf won't exist anymore.
+ O.update() // This lattice may be supporting things on top of it. If it's being deleted, they need to fall down.
..()
/obj/structure/lattice/ex_act(severity)
diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm
index e8ce8bfb1cc..5fed1a35778 100644
--- a/code/game/objects/structures/signs.dm
+++ b/code/game/objects/structures/signs.dm
@@ -122,6 +122,108 @@
desc = "A warning sign which reads 'NO SMOKING'."
icon_state = "nosmoking2"
+/obj/structure/sign/warning
+ name = "\improper WARNING"
+ icon_state = "securearea"
+
+/obj/structure/sign/warning/New()
+ ..()
+ desc = "A warning sign which reads '[name]'."
+
+/obj/structure/sign/warning/airlock
+ name = "\improper EXTERNAL AIRLOCK"
+ icon_state = "doors"
+
+/obj/structure/sign/warning/biohazard
+ name = "\improper BIOHAZARD"
+ icon_state = "bio"
+
+/obj/structure/sign/warning/bomb_range
+ name = "\improper BOMB RANGE"
+ icon_state = "blast"
+
+/obj/structure/sign/warning/caution
+ name = "\improper CAUTION"
+
+/obj/structure/sign/warning/compressed_gas
+ name = "\improper COMPRESSED GAS"
+ icon_state = "hikpa"
+
+/obj/structure/sign/warning/deathsposal
+ name = "\improper DISPOSAL LEADS TO SPACE"
+ icon_state = "deathsposal"
+
+/obj/structure/sign/warning/docking_area
+ name = "\improper KEEP CLEAR: DOCKING AREA"
+
+/obj/structure/sign/warning/engineering_access
+ name = "\improper ENGINEERING ACCESS"
+
+/obj/structure/sign/warning/fire
+ name = "\improper DANGER: FIRE"
+ icon_state = "fire"
+
+/obj/structure/sign/warning/high_voltage
+ name = "\improper HIGH VOLTAGE"
+ icon_state = "shock"
+
+/obj/structure/sign/warning/hot_exhaust
+ name = "\improper HOT EXHAUST"
+ icon_state = "fire"
+
+/obj/structure/sign/warning/internals_required
+ name = "\improper INTERNALS REQUIRED"
+
+/obj/structure/sign/warning/lethal_turrets
+ name = "\improper LETHAL TURRETS"
+ icon_state = "turrets"
+
+/obj/structure/sign/warning/lethal_turrets/New()
+ ..()
+ desc += " Enter at own risk!."
+
+/obj/structure/sign/warning/mail_delivery
+ name = "\improper MAIL DELIVERY"
+
+/obj/structure/sign/warning/moving_parts
+ name = "\improper MOVING PARTS"
+
+/obj/structure/sign/warning/nosmoking_1
+ name = "\improper NO SMOKING"
+ icon_state = "nosmoking"
+
+/obj/structure/sign/warning/nosmoking_2
+ name = "\improper NO SMOKING"
+ icon_state = "nosmoking2"
+
+/obj/structure/sign/warning/pods
+ name = "\improper ESCAPE PODS"
+ icon_state = "pods"
+
+/obj/structure/sign/warning/radioactive
+ name = "\improper RADIOACTIVE AREA"
+ icon_state = "radiation"
+
+/obj/structure/sign/warning/secure_area
+ name = "\improper SECURE AREA"
+
+/obj/structure/sign/warning/secure_area/armory
+ name = "\improper ARMORY"
+
+/obj/structure/sign/warning/server_room
+ name = "\improper SERVER ROOM"
+
+/obj/structure/sign/warning/siphon_valve
+ name = "\improper SIPHON VALVE"
+
+/obj/structure/sign/warning/vacuum
+ name = "\improper HARD VACUUM AHEAD"
+ icon_state = "space"
+
+/obj/structure/sign/warning/vent_port
+ name = "\improper EJECTION/VENTING PORT"
+
+
/obj/structure/sign/redcross
name = "medbay"
desc = "The Intergalactic symbol of Medical institutions. You'll probably get help here."
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 a2e8e3f21b3..17a9c54cb3b 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
@@ -133,7 +133,7 @@
user << "\The [src] already has someone buckled to it."
return
user.visible_message("[user] attempts to buckle [affecting] into \the [src]!")
- if(do_after(user, 20))
+ if(do_after(user, 20, G.affecting))
affecting.loc = loc
spawn(0)
if(buckle_mob(affecting))
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 959f8f807a3..a382858c543 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -18,8 +18,9 @@
/obj/structure/toilet/attack_hand(mob/living/user as mob)
if(swirlie)
+ usr.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
usr.visible_message("[user] slams the toilet seat onto [swirlie.name]'s head!", "You slam the toilet seat onto [swirlie.name]'s head!", "You hear reverberating porcelain.")
- swirlie.adjustBruteLoss(8)
+ swirlie.adjustBruteLoss(5)
return
if(cistern && !open)
@@ -53,6 +54,7 @@
return
if(istype(I, /obj/item/weapon/grab))
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
var/obj/item/weapon/grab/G = I
if(isliving(G.affecting))
@@ -65,14 +67,14 @@
if(open && !swirlie)
user.visible_message("[user] starts to give [GM.name] a swirlie!", "You start to give [GM.name] a swirlie!")
swirlie = GM
- if(do_after(user, 30, 5, 0))
+ if(do_after(user, 30, GM))
user.visible_message("[user] gives [GM.name] a swirlie!", "You give [GM.name] a swirlie!", "You hear a toilet flushing.")
if(!GM.internal)
GM.adjustOxyLoss(5)
swirlie = null
else
user.visible_message("[user] slams [GM.name] into the [src]!", "You slam [GM.name] into the [src]!")
- GM.adjustBruteLoss(8)
+ GM.adjustBruteLoss(5)
else
user << "You need a tighter grip."
diff --git a/code/game/periodic_news.dm b/code/game/periodic_news.dm
index 14cb92624df..b3c9c9d69ff 100644
--- a/code/game/periodic_news.dm
+++ b/code/game/periodic_news.dm
@@ -6,9 +6,13 @@
round_time // time of the round at which this should be announced, in seconds
message // body of the message
author = "NanoTrasen Editor"
- channel_name = "The "+starsys_name+" Times"
can_be_redacted = 0
message_type = "Story"
+ channel_name = null
+
+ New() // I'm sorry...
+ ..()
+ channel_name = "The [using_map.starsys_name] Times"
revolution_inciting_event
@@ -66,7 +70,6 @@
round_time = 60 * 50
found_ssd
- channel_name = "The "+starsys_name+" Times"
author = "Doctor Eric Hanfield"
message = {"Several people have been found unconscious at their terminals. It is thought that it was due
@@ -78,7 +81,6 @@
lotus_tree
explosions
- channel_name = "The "+starsys_name+" Times"
author = "Reporter Leland H. Howards"
message = {"The newly-christened civillian transport Lotus Tree suffered two very large explosions near the
@@ -92,9 +94,7 @@
food_riots
breaking_news
- channel_name = "The "+starsys_name+" Times"
author = "Reporter Ro'kii Ar-Raqis"
-
message = {"Breaking news: Food riots have broken out throughout the Refuge asteroid colony in the Tenebrae
Lupus system. This comes only hours after NanoTrasen officials announced they will no longer trade with the
colony, citing the increased presence of \"hostile factions\" on the colony has made trade too dangerous to
@@ -103,9 +103,7 @@
round_time = 60 * 10
more
- channel_name = "The "+starsys_name+" Times"
author = "Reporter Ro'kii Ar-Raqis"
-
message = {"More on the Refuge food riots: The Refuge Council has condemned NanoTrasen's withdrawal from
the colony, claiming \"there has been no increase in anti-NanoTrasen activity\", and \"\[the only] reason
NanoTrasen withdrew was because the \[Tenebrae Lupus] system's Phoron deposits have been completely mined out.
diff --git a/code/game/response_team.dm b/code/game/response_team.dm
index 5892b7f6e5a..0bdbfe41547 100644
--- a/code/game/response_team.dm
+++ b/code/game/response_team.dm
@@ -22,7 +22,7 @@ var/silent_ert = 0
usr << "The round hasn't started yet!"
return
if(send_emergency_team)
- usr << "[boss_name] has already dispatched an emergency response team!"
+ usr << "[using_map.boss_name] has already dispatched an emergency response team!"
return
if(alert("Do you want to dispatch an Emergency Response Team?",,"Yes","No") != "Yes")
return
@@ -117,11 +117,11 @@ proc/trigger_armed_response_team(var/force = 0)
// there's only a certain chance a team will be sent
if(!prob(send_team_chance))
- command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. Unfortunately, we were unable to send one at this time.", "[boss_name]")
+ command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. Unfortunately, we were unable to send one at this time.", "[using_map.boss_name]")
can_call_ert = 0 // Only one call per round, ladies.
return
if(silent_ert == 0)
- command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. We will prepare and send one as soon as possible.", "[boss_name]")
+ command_announcement.Announce("It would appear that an emergency response team was requested for [station_name()]. We will prepare and send one as soon as possible.", "[using_map.boss_name]")
can_call_ert = 0 // Only one call per round, gentleman.
send_emergency_team = 1
diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm
index e3b8e0d2ec1..8ba95765b4c 100644
--- a/code/game/supplyshuttle.dm
+++ b/code/game/supplyshuttle.dm
@@ -184,6 +184,8 @@ var/list/mechtoys = list(
var/area/area_shuttle = shuttle.get_location_area()
if(!area_shuttle) return
+ callHook("sell_shuttle", list(area_shuttle));
+
var/phoron_count = 0
var/plat_count = 0
@@ -263,7 +265,7 @@ var/list/mechtoys = list(
slip.is_copy = 0
slip.info = "
"}
else
@@ -435,7 +435,7 @@ proc/admin_notice(var/message, var/rights)
"}
if(10)
dat+={"
- [company_name] Feed Censorship Tool
+ [using_map.company_name] Feed Censorship Tool
NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.
Select Feed channel to get Stories from:
@@ -448,7 +448,7 @@ proc/admin_notice(var/message, var/rights)
dat+=" Cancel"
if(11)
dat+={"
- [company_name] D-Notice Handler
+ [using_map.company_name] D-Notice Handler
A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's
morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed
stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
@@ -481,7 +481,7 @@ proc/admin_notice(var/message, var/rights)
"}
if(src.admincaster_feed_channel.censored)
dat+={"
- ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [company_name] D-Notice.
+ ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.
No further feed story additions are allowed while the D-Notice is in effect.
"}
else
@@ -1245,7 +1245,7 @@ proc/admin_notice(var/message, var/rights)
M = whom
C = M.client
else
- return "(*not an mob*)"
+ return "(*not a mob*)"
switch(detail)
if(0)
return "[key_name(C, link, name, highlight_special)]"
@@ -1255,15 +1255,15 @@ proc/admin_notice(var/message, var/rights)
if(2) //Admins
var/ref_mob = "\ref[M]"
- return "[key_name(C, link, name, highlight_special)](?) (PP) (VV) (SM) ([admin_jump_link(M, src)]) (CA)"
+ return "[key_name(C, link, name, highlight_special)](?) (PP) (VV) (SM) ([admin_jump_link(M, src)]) (CA) (TAKE)"
if(3) //Devs
var/ref_mob = "\ref[M]"
- return "[key_name(C, link, name, highlight_special)](VV)([admin_jump_link(M, src)])"
+ return "[key_name(C, link, name, highlight_special)](VV)([admin_jump_link(M, src)]) (TAKE)"
if(4) //Mentors
var/ref_mob = "\ref[M]"
- return "[key_name(C, link, name, highlight_special)] (?) (PP) (VV) (SM) ([admin_jump_link(M, src)])"
+ return "[key_name(C, link, name, highlight_special)] (?) (PP) (VV) (SM) ([admin_jump_link(M, src)]) (TAKE)"
/proc/ishost(whom)
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 91a504f421c..91fff2c4c2a 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -161,7 +161,8 @@ var/list/admin_verbs_server = list(
/client/proc/toggle_random_events,
/client/proc/check_customitem_activity,
/client/proc/nanomapgen_DumpImage,
- /client/proc/modify_server_news
+ /client/proc/modify_server_news,
+ /client/proc/recipe_dump
)
var/list/admin_verbs_debug = list(
/client/proc/getruntimelog, //allows us to access runtime logs to somebody,
@@ -200,7 +201,9 @@ var/list/admin_verbs_debug = list(
/client/proc/toggle_debug_logs,
/client/proc/admin_ghost, //allows us to ghost/reenter body at will,
/datum/admins/proc/view_runtimes,
- /client/proc/show_gm_status
+ /client/proc/show_gm_status,
+ /datum/admins/proc/change_weather,
+ /datum/admins/proc/change_time
)
var/list/admin_verbs_paranoid_debug = list(
diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm
index 5742b74aa42..4f0cba95c44 100644
--- a/code/modules/admin/holder2.dm
+++ b/code/modules/admin/holder2.dm
@@ -19,7 +19,7 @@ var/list/admin_datums = list()
error("Admin datum created without a ckey argument. Datum has been deleted")
qdel(src)
return
- admincaster_signature = "[company_name] Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
+ admincaster_signature = "[using_map.company_name] Officer #[rand(0,9)][rand(0,9)][rand(0,9)]"
rank = initial_rank
rights = initial_rights
admin_datums[ckey] = src
diff --git a/code/modules/admin/secrets/admin_secrets/prison_warp.dm b/code/modules/admin/secrets/admin_secrets/prison_warp.dm
index eec85c2f04b..d0d41cea5d5 100644
--- a/code/modules/admin/secrets/admin_secrets/prison_warp.dm
+++ b/code/modules/admin/secrets/admin_secrets/prison_warp.dm
@@ -12,7 +12,7 @@
for(var/mob/living/carbon/human/H in mob_list)
var/turf/T = get_turf(H)
var/security = 0
- if((T && T in config.admin_levels) || prisonwarped.Find(H))
+ if((T && T in using_map.admin_levels) || prisonwarped.Find(H))
//don't warp them if they aren't ready or are already there
continue
H.Paralyse(5)
diff --git a/code/modules/admin/secrets/fun_secrets/ghost_mode.dm b/code/modules/admin/secrets/fun_secrets/ghost_mode.dm
index dfa84e4cf6a..c59a9c05891 100644
--- a/code/modules/admin/secrets/fun_secrets/ghost_mode.dm
+++ b/code/modules/admin/secrets/fun_secrets/ghost_mode.dm
@@ -30,7 +30,7 @@
step_rand(W)
var/area/A = get_area(M)
- if(A.requires_power && !A.always_unpowered && A.power_light && (A.z in config.player_levels))
+ if(A.requires_power && !A.always_unpowered && A.power_light && (A.z in using_map.player_levels))
affected_areas |= get_area(M)
affected_mobs |= user
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index fe427b54d83..a545bc1e87a 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1218,6 +1218,18 @@
else if(href_list["check_antagonist"])
check_antagonists()
+ else if(href_list["take_question"])
+
+ var/mob/M = locate(href_list["take_question"])
+ if(ismob(M))
+ var/take_msg = "ADMINHELP: [key_name(usr.client)] is attending to [key_name(M)]'s adminhelp, please don't dogpile them."
+ for(var/client/X in admins)
+ if((R_ADMIN|R_MOD|R_MENTOR) & X.holder.rights)
+ to_chat(X, take_msg)
+ to_chat(M, "Your adminhelp is being attended to by [usr.client]. Thanks for your patience!")
+ else
+ to_chat(usr, "Unable to locate mob.")
+
else if(href_list["adminplayerobservecoodjump"])
if(!check_rights(R_ADMIN|R_SERVER|R_MOD)) return
diff --git a/code/modules/admin/verbs/buildmode.dm b/code/modules/admin/verbs/buildmode.dm
index 5a211d960b8..9239f6385f0 100644
--- a/code/modules/admin/verbs/buildmode.dm
+++ b/code/modules/admin/verbs/buildmode.dm
@@ -392,11 +392,12 @@
if(holder.buildmode.coordA && holder.buildmode.coordB)
user << "Ladder locations set, building ladders."
- var/obj/structure/ladder/A = new /obj/structure/ladder(holder.buildmode.coordA)
+ var/obj/structure/ladder/A = new /obj/structure/ladder/up(holder.buildmode.coordA)
var/obj/structure/ladder/B = new /obj/structure/ladder(holder.buildmode.coordB)
- A.target = B
- B.target = A
- B.icon_state = "ladderup"
+ A.target_up = B
+ B.target_down = A
+ A.update_icon()
+ B.update_icon()
holder.buildmode.coordA = null
holder.buildmode.coordB = null
if(7) // Move into contents
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index fa2c51e7e51..d50001892bb 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -692,7 +692,7 @@
if("emergency response team")
M.equip_to_slot_or_del(new /obj/item/clothing/under/rank/centcom_officer(M), slot_w_uniform)
- M.equip_to_slot_or_del(new /obj/item/clothing/shoes/swat(M), slot_shoes)
+ M.equip_to_slot_or_del(new /obj/item/clothing/shoes/boots/swat(M), slot_shoes)
M.equip_to_slot_or_del(new /obj/item/clothing/gloves/swat(M), slot_gloves)
M.equip_to_slot_or_del(new /obj/item/device/radio/headset/ert(M), slot_l_ear)
M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/gun(M), slot_belt)
@@ -711,7 +711,7 @@
if("special ops officer")
M.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate/combat(M), slot_w_uniform)
M.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/swat/officer(M), slot_wear_suit)
- M.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(M), slot_shoes)
+ M.equip_to_slot_or_del(new /obj/item/clothing/shoes/boots/combat(M), slot_shoes)
M.equip_to_slot_or_del(new /obj/item/clothing/gloves/combat(M), slot_gloves)
M.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(M), slot_l_ear)
M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/plain/eyepatch(M), slot_glasses)
@@ -767,7 +767,7 @@
M.equip_to_slot_or_del(new /obj/item/weapon/storage/box(M), slot_in_backpack)
if("soviet admiral")
M.equip_to_slot_or_del(new /obj/item/clothing/head/hgpiratecap(M), slot_head)
- M.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(M), slot_shoes)
+ M.equip_to_slot_or_del(new /obj/item/clothing/shoes/boots/combat(M), slot_shoes)
M.equip_to_slot_or_del(new /obj/item/clothing/gloves/combat(M), slot_gloves)
M.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(M), slot_l_ear)
M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/plain/eyepatch(M), slot_glasses)
@@ -968,3 +968,46 @@
return
error_cache.showTo(usr)
+
+/datum/admins/proc/change_weather()
+ set category = "Debug"
+ set name = "Change Weather"
+ set desc = "Changes the current weather."
+
+ if(!check_rights(R_DEBUG))
+ return
+
+ var/datum/planet/planet = input(usr, "Which planet do you want to modify the weather on?", "Change Weather") in list(planet_sif)
+ var/datum/weather/new_weather = input(usr, "What weather do you want to change to?", "Change Weather") as null|anything in planet.weather_holder.allowed_weather_types
+ if(new_weather)
+ planet.weather_holder.change_weather(new_weather)
+ var/log = "[key_name(src)] changed [planet.name]'s weather to [new_weather]."
+ message_admins(log)
+ log_admin(log)
+
+/datum/admins/proc/change_time()
+ set category = "Debug"
+ set name = "Change Planet Time"
+ set desc = "Changes the time of a planet."
+
+ if(!check_rights(R_DEBUG))
+ return
+
+ var/datum/planet/planet = input(usr, "Which planet do you want to modify time on?", "Change Time") in list(planet_sif)
+
+ var/datum/time/current_time_datum = planet.current_time
+ var/new_hour = input(usr, "What hour do you want to change to?", "Change Time", text2num(current_time_datum.show_time("hh"))) as null|num
+ if(!isnull(new_hour))
+ var/new_minute = input(usr, "What minute do you want to change to?", "Change Time", text2num(current_time_datum.show_time("mm")) ) as null|num
+ if(!isnull(new_minute))
+ var/type_needed = current_time_datum.type
+ var/datum/time/new_time = new type_needed()
+ new_time = new_time.add_hours(new_hour)
+ new_time = new_time.add_minutes(new_minute)
+ planet.current_time = new_time
+ spawn(1)
+ planet.update_sun()
+
+ var/log = "[key_name(src)] changed [planet.name]'s time to [planet.current_time.show_time("hh:mm")]."
+ message_admins(log)
+ log_admin(log)
\ No newline at end of file
diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm
index 8c0575d080f..b416cb661a4 100644
--- a/code/modules/admin/verbs/diagnostics.dm
+++ b/code/modules/admin/verbs/diagnostics.dm
@@ -17,7 +17,7 @@
var/inactive_on_main_station = 0
for(var/zone/zone in air_master.zones)
var/turf/simulated/turf = locate() in zone.contents
- if(turf && turf.z in config.station_levels)
+ if(turf && turf.z in using_map.station_levels)
if(zone.needs_update)
active_on_main_station++
else
diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm
index 64640b10b68..c5eb60a94b2 100644
--- a/code/modules/admin/verbs/pray.dm
+++ b/code/modules/admin/verbs/pray.dm
@@ -29,7 +29,7 @@
//log_admin("HELP: [key_name(src)]: [msg]")
/proc/CentCom_announce(var/msg, var/mob/Sender, var/iamessage)
- msg = "\blue [uppertext(boss_short)]M[iamessage ? " IA" : ""]:[key_name(Sender, 1)] (PP) (VV) (SM) ([admin_jump_link(Sender, src)]) (CA) (BSA) (RPLY): [msg]"
+ msg = "\blue [uppertext(using_map.boss_short)]M[iamessage ? " IA" : ""]:[key_name(Sender, 1)] (PP) (VV) (SM) ([admin_jump_link(Sender, src)]) (CA) (BSA) (RPLY): [msg]"
for(var/client/C in admins)
if(R_ADMIN & C.holder.rights)
C << msg
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 251dec5fb19..8ffcc88692c 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -471,8 +471,10 @@ Traitors and the like can also be revived with the previous role mostly intact.
antag_data.place_mob(new_character)
//If desired, apply equipment.
- if(equipment && charjob)
- job_master.EquipRank(new_character, charjob, 1)
+ if(equipment)
+ if(charjob)
+ job_master.EquipRank(new_character, charjob, 1)
+ equip_custom_items(new_character)
//If desired, add records.
if(records)
@@ -553,7 +555,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
if(!input)
return
if(!customname)
- customname = "[company_name] Update"
+ customname = "[using_map.company_name] Update"
for (var/obj/machinery/computer/communications/C in machines)
if(! (C.stat & (BROKEN|NOPOWER) ) )
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc )
@@ -568,7 +570,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
if("Yes")
command_announcement.Announce(input, customname, new_sound = 'sound/AI/commandreport.ogg', msg_sanitized = 1);
if("No")
- world << "\red New [company_name] Update available at all communication consoles."
+ world << "\red New [using_map.company_name] Update available at all communication consoles."
world << sound('sound/AI/commandreport.ogg')
log_admin("[key_name(src)] has created a command report: [input]")
@@ -637,14 +639,18 @@ Traitors and the like can also be revived with the previous role mostly intact.
var/heavy = input("Range of heavy pulse.", text("Input")) as num|null
if(heavy == null) return
+ var/med = input("Range of medium pulse.", text("Input")) as num|null
+ if(med == null) return
var/light = input("Range of light pulse.", text("Input")) as num|null
if(light == null) return
+ var/long = input("Range of long pulse.", text("Input")) as num|null
+ if(long == null) return
- if (heavy || light)
+ if (heavy || med || light || long)
- empulse(O, heavy, light)
- log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at ([O.x],[O.y],[O.z])")
- message_admins("[key_name_admin(usr)] created an EM PUlse ([heavy],[light]) at ([O.x],[O.y],[O.z])", 1)
+ empulse(O, heavy, med, light, long)
+ log_admin("[key_name(usr)] created an EM Pulse ([heavy],[med],[light],[long]) at ([O.x],[O.y],[O.z])")
+ message_admins("[key_name_admin(usr)] created an EM PUlse ([heavy],[med],[light],[long]) at ([O.x],[O.y],[O.z])", 1)
feedback_add_details("admin_verb","EMP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return
diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm
index 4a261a3d98a..169ab9b6a02 100644
--- a/code/modules/assembly/signaler.dm
+++ b/code/modules/assembly/signaler.dm
@@ -1,6 +1,6 @@
/obj/item/device/assembly/signaler
name = "remote signaling device"
- desc = "Used to remotely activate devices."
+ desc = "Used to remotely activate devices. Tap against another secured signaler to transfer configuration."
icon_state = "signaller"
item_state = "signaler"
origin_tech = list(TECH_MAGNET = 1)
@@ -98,6 +98,15 @@
return
+ attackby(obj/item/weapon/W, mob/user, params)
+ if(issignaler(W))
+ var/obj/item/device/assembly/signaler/signaler2 = W
+ if(secured && signaler2.secured)
+ code = signaler2.code
+ frequency = signaler2.frequency
+ user << "You transfer the frequency and code of [signaler2] to [src]"
+ else
+ ..()
proc/signal()
if(!radio_connection) return
diff --git a/code/modules/awaymissions/bluespaceartillery.dm b/code/modules/awaymissions/bluespaceartillery.dm
index d94ca0c4b38..505f4ceb4c8 100644
--- a/code/modules/awaymissions/bluespaceartillery.dm
+++ b/code/modules/awaymissions/bluespaceartillery.dm
@@ -26,7 +26,7 @@
dat += "Locked on "
dat += "Charge progress: [reload]/180: "
dat += "Open Fire "
- dat += "Deployment of weapon authorized by [company_name] Naval Command
Remember, friendly fire is grounds for termination of your contract and life."
+ dat += "Deployment of weapon authorized by [using_map.company_name] Naval Command
Remember, friendly fire is grounds for termination of your contract and life."
user << browse(dat, "window=scroll")
onclose(user, "scroll")
return
diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm
index 4c061c71d29..e48e7308601 100644
--- a/code/modules/awaymissions/corpse.dm
+++ b/code/modules/awaymissions/corpse.dm
@@ -90,7 +90,7 @@
name = "Syndicate Operative"
corpseuniform = /obj/item/clothing/under/syndicate
corpsesuit = /obj/item/clothing/suit/armor/vest
- corpseshoes = /obj/item/clothing/shoes/swat
+ corpseshoes = /obj/item/clothing/shoes/boots/swat
corpsegloves = /obj/item/clothing/gloves/swat
corpseradio = /obj/item/device/radio/headset
corpsemask = /obj/item/clothing/mask/gas
@@ -106,7 +106,7 @@
name = "Syndicate Commando"
corpseuniform = /obj/item/clothing/under/syndicate
corpsesuit = /obj/item/clothing/suit/space/void/merc
- corpseshoes = /obj/item/clothing/shoes/swat
+ corpseshoes = /obj/item/clothing/shoes/boots/swat
corpsegloves = /obj/item/clothing/gloves/swat
corpseradio = /obj/item/device/radio/headset
corpsemask = /obj/item/clothing/mask/gas/syndicate
@@ -225,7 +225,7 @@
corpsemask = /obj/item/clothing/mask/smokable/cigarette/cigar/cohiba
corpsehelmet = /obj/item/clothing/head/centhat
corpsegloves = /obj/item/clothing/gloves/swat
- corpseshoes = /obj/item/clothing/shoes/swat
+ corpseshoes = /obj/item/clothing/shoes/boots/swat
corpsepocket1 = /obj/item/weapon/flame/lighter/zippo
corpseid = 1
corpseidjob = "Commander"
diff --git a/code/modules/awaymissions/exile.dm b/code/modules/awaymissions/exile.dm
index 3c285a20c25..b22114649d8 100644
--- a/code/modules/awaymissions/exile.dm
+++ b/code/modules/awaymissions/exile.dm
@@ -18,7 +18,7 @@
get_data()
var/dat = {"
Implant Specifications:
-Name: [company_name] Employee Exile Implant
+Name: [using_map.company_name] Employee Exile Implant Implant Details: The onboard gateway system has been modified to reject entry by individuals containing this implant "}
return dat
diff --git a/code/modules/busy_space/air_traffic.dm b/code/modules/busy_space/air_traffic.dm
new file mode 100644
index 00000000000..7da2c6f73bf
--- /dev/null
+++ b/code/modules/busy_space/air_traffic.dm
@@ -0,0 +1,129 @@
+//Cactus, Speedbird, Dynasty, oh my
+
+var/datum/lore/atc_controller/atc = new/datum/lore/atc_controller
+
+/datum/lore/atc_controller
+ var/delay_max = 25 MINUTES //How long between ATC traffic, max. Default is 25 mins.
+ var/delay_min = 40 MINUTES //How long between ATC traffic, min. Default is 40 mins.
+ var/backoff_delay = 5 MINUTES //How long to back off if we can't talk and want to. Default is 5 mins.
+ var/next_message //When the next message should happen in world.time
+ var/force_chatter_type //Force a specific type of messages
+
+ var/squelched = 0 //If ATC is squelched currently
+
+/datum/lore/atc_controller/New()
+ spawn(10 SECONDS) //Lots of lag at the start of a shift.
+ msg("New shift beginning, resuming traffic control.")
+ next_message = world.time + rand(delay_min,delay_max)
+ process()
+
+/datum/lore/atc_controller/proc/process()
+ if(world.time >= next_message)
+ if(squelched)
+ next_message = world.time + backoff_delay
+ else
+ next_message = world.time + rand(delay_min,delay_max)
+ random_convo()
+
+ spawn(1 MINUTE) //We don't really need high-accuracy here.
+ process()
+
+/datum/lore/atc_controller/proc/msg(var/message,var/sender)
+ ASSERT(message)
+ global_announcer.autosay("[message]", sender ? sender : "[using_map.station_short] Space Control")
+
+/datum/lore/atc_controller/proc/reroute_traffic(var/yes = 1)
+ if(yes)
+ if(!squelched)
+ msg("Rerouting traffic away from [using_map.station_name].")
+ squelched = 1
+ else
+ if(squelched)
+ msg("Resuming normal traffic routing around [using_map.station_name].")
+ squelched = 0
+
+/datum/lore/atc_controller/proc/shift_ending(var/evac = 0)
+ msg("Automated Shuttle departing [using_map.station_name] for [using_map.dock_name] on routine transfer route.","NT Automated Shuttle")
+ sleep(5 SECONDS)
+ msg("Automated Shuttle, cleared to complete routine transfer from [using_map.station_name] to [using_map.dock_name].")
+
+/datum/lore/atc_controller/proc/random_convo()
+ var/one = pick(loremaster.organizations) //These will pick an index, not an instance
+ var/two = pick(loremaster.organizations)
+
+ var/datum/lore/organization/source = loremaster.organizations[one] //Resolve to the instances
+ var/datum/lore/organization/dest = loremaster.organizations[two]
+
+ //Let's get some mission parameters
+ var/owner = source.short_name //Use the short name
+ var/prefix = pick(source.ship_prefixes) //Pick a random prefix
+ var/mission = source.ship_prefixes[prefix] //The value of the prefix is the mission type that prefix does
+ var/shipname = pick(source.ship_names) //Pick a random ship name to go with it
+ var/destname = pick(dest.destination_names) //Pick a random holding from the destination
+
+ var/combined_name = "[owner] [prefix] [shipname]"
+ var/alt_atc_names = list("[using_map.station_short] TraCon","[using_map.station_short] Control","[using_map.station_short] STC","[using_map.station_short] Airspace")
+ var/wrong_atc_names = list("Sol Command","Orion Control", "[using_map.dock_name]")
+ var/mission_noun = list("flight","mission","route")
+ var/request_verb = list("requesting","calling for","asking for")
+
+ //First response is 'yes', second is 'no'
+ var/requests = list("[using_map.station_short] transit clearance" = list("permission for transit granted", "permission for transit denied, contact regional on 953.5"),
+ "planetary flight rules" = list("authorizing planetary flight rules", "denying planetary flight rules right now due to traffic"),
+ "special flight rules" = list("authorizing special flight rules", "denying special flight rules, not allowed for your traffic class"),
+ "current solar weather info" = list("sending you the relevant information via tightbeam", "cannot fulfill your request at the moment"),
+ "nearby traffic info" = list("sending you current traffic info", "no available info in your area"),
+ "remote telemetry data" = list("sending telemetry now", "no uplink from your ship, recheck your uplink and ask again"),
+ "refueling information" = list("sending refueling information now", "no fuel for your ship class in this sector"),
+ "a current system time sync" = list("sending time sync ping to you now", "your ship isn't compatible with our time sync, set time manually"),
+ "current system starcharts" = list("transmitting current starcharts", "your request is queued, overloaded right now"),
+ "permission to engage FTL" = list("permission to engage FTL granted, good day", "permission denied, wait for current traffic to pass"),
+ "permission to transit system" = list("permission to transit granted, good day", "permission denied, wait for current traffic to pass"),
+ "permission to depart system" = list("permission to depart granted, good day", "permission denied, wait for current traffic to pass"),
+ "permission to enter system" = list("good day, permission to enter granted", "permission denied, wait for current traffic to pass"),
+ )
+
+ //Random chance things for variety
+ var/chatter_type = "normal"
+ if(force_chatter_type)
+ chatter_type = force_chatter_type
+ else
+ chatter_type = pick(2;"emerg",5;"wrong_freq","normal") //Be nice to have wrong_lang...
+
+ var/yes = prob(90) //Chance for them to say yes vs no
+
+ var/request = pick(requests)
+ var/callname = pick(alt_atc_names)
+ var/response = requests[request][yes ? 1 : 2] //1 is yes, 2 is no
+
+ var/full_request
+ var/full_response
+ var/full_closure
+
+ switch(chatter_type)
+ if("wrong_freq")
+ callname = pick(wrong_atc_names)
+ full_request = "[callname], this is [combined_name] on a [mission] [pick(mission_noun)] to [destname], [pick(request_verb)] [request]."
+ full_response = "[combined_name], this is [using_map.station_short] TraCon, wrong frequency. Switch to [rand(700,999)].[rand(1,9)]."
+ full_closure = "[using_map.station_short] TraCon, understood, apologies."
+ if("wrong_lang")
+ //Can't implement this until autosay has language support
+ if("emerg")
+ var/problem = pick("hull breaches on multiple decks","unknown life forms on board","a drive about to go critical","asteroids impacting the hull","a total loss of engine power","people trying to board the ship")
+ full_request = "This is [combined_name] declaring an emergency! We have [problem]!"
+ full_response = "[combined_name], this is [using_map.station_short] TraCon, copy. Switch to emergency responder channel [rand(700,999)].[rand(1,9)]."
+ full_closure = "[using_map.station_short] TraCon, okay, switching now."
+ else
+ full_request = "[callname], this is [combined_name] on a [mission] [pick(mission_noun)] to [destname], [pick(request_verb)] [request]."
+ full_response = "[combined_name], this is [using_map.station_short] TraCon, [response]." //Station TraCon always calls themselves TraCon
+ full_closure = "[using_map.station_short] TraCon, [yes ? "thank you" : "understood"], good day." //They always copy what TraCon called themselves in the end when they realize they said it wrong
+
+ //Ship sends request to ATC
+ msg(full_request,"[prefix] [shipname]")
+ sleep(5 SECONDS)
+ //ATC sends response to ship
+ msg(full_response)
+ sleep(5 SECONDS)
+ //Ship sends response to ATC
+ msg(full_closure,"[prefix] [shipname]")
+ return
\ No newline at end of file
diff --git a/code/modules/busy_space/loremaster.dm b/code/modules/busy_space/loremaster.dm
new file mode 100644
index 00000000000..30bd04402da
--- /dev/null
+++ b/code/modules/busy_space/loremaster.dm
@@ -0,0 +1,13 @@
+//I AM THE LOREMASTER, ARE YOU THE GATEKEEPER?
+
+var/datum/lore/loremaster/loremaster = new/datum/lore/loremaster
+
+/datum/lore/loremaster
+ var/list/organizations = list()
+
+/datum/lore/loremaster/New()
+
+ var/list/paths = typesof(/datum/lore/organization) - /datum/lore/organization
+ for(var/path in paths)
+ var/datum/lore/organization/instance = new path()
+ organizations[path] = instance
\ No newline at end of file
diff --git a/code/modules/busy_space/organizations.dm b/code/modules/busy_space/organizations.dm
new file mode 100644
index 00000000000..86f88e7ec03
--- /dev/null
+++ b/code/modules/busy_space/organizations.dm
@@ -0,0 +1,326 @@
+//Datums for different companies that can be used by busy_space
+/datum/lore/organization
+ var/name = "" // Organization's name
+ var/short_name = "" // Organization's shortname (NanoTrasen for "NanoTrasen Incorporated")
+ var/desc = "" // One or two paragraph description of the organization, but only current stuff. Currently unused.
+ var/history = "" // Historical discription of the organization's origins Currently unused.
+ var/work = "" // Short description of their work, eg "an arms manufacturer"
+ var/headquarters = "" // Location of the organization's HQ. Currently unused.
+ var/motto = "" // A motto/jingle/whatever, if they have one. Currently unused.
+
+ var/list/ship_prefixes = list() //Some might have more than one! Like NanoTrasen. Value is the mission they perform, e.g. ("ABC" = "mission desc")
+ var/list/ship_names = list( //Names of spaceships. This is a mostly generic list that all the other organizations inherit from if they don't have anything better.
+ "Kestrel",
+ "Beacon",
+ "Signal",
+ "Freedom",
+ "Glory",
+ "Axiom",
+ "Eternal",
+ "Icarus",
+ "Harmony",
+ "Light",
+ "Discovery",
+ "Endeavour",
+ "Explorer",
+ "Swift",
+ "Dragonfly",
+ "Ascendant",
+ "Tenacious",
+ "Pioneer",
+ "Hawk",
+ "Haste",
+ "Radiant",
+ "Luminous"
+ )
+ var/list/destination_names = list() //Names of static holdings that the organization's ships visit regularly.
+ var/autogenerate_destination_names = TRUE
+
+/datum/lore/organization/New()
+ ..()
+ if(autogenerate_destination_names) // Lets pad out the destination names.
+ var/i = rand(6, 10)
+ var/list/star_names = list(
+ "Sol", "Alpha Centauri", "Sirius", "Vega", "Regulus", "Vir", "Algol", "Aldebaran",
+ "Delta Doradus", "Menkar", "Geminga", "Elnath", "Gienah", "Mu Leporis", "Nyx", "Tau Ceti",
+ "Wazn", "Alphard", "Phact", "Altair")
+ var/list/destination_types = list("dockyard", "station", "vessel", "waystation", "telecommunications satellite", "spaceport", "distress beacon", "anomaly", "colony", "outpost")
+ while(i)
+ destination_names.Add("a [pick(destination_types)] in [pick(star_names)]")
+ i--
+
+//////////////////////////////////////////////////////////////////////////////////
+
+// TSCs
+/datum/lore/organization/nanotrasen
+ name = "NanoTrasen Incorporated"
+ short_name = "NanoTrasen"
+ desc = "" // Todo: Write this.
+ history = "" // This too.
+ work = "research giant"
+ headquarters = "Luna"
+ motto = ""
+
+ ship_prefixes = list("NSV" = "exploration", "NTV" = "hauling", "NDV" = "patrol", "NRV" = "emergency response")
+ // Note that the current station being used will be pruned from this list upon being instantiated
+ destination_names = list(
+ "NSS Exodus in Nyx",
+ "NCS Northern Star in Vir",
+ "NCS Southern Cross in Vir",
+ "NDV Icarus in Nyx",
+ "NAS Vir Central Command",
+ "a dockyard orbiting Sif",
+ "an asteroid orbiting Kara",
+ "an asteroid orbiting Rota",
+ "Vir Interstellar Spaceport"
+ )
+
+/datum/lore/organization/nanotrasen/New()
+ ..()
+ // Get rid of the current map from the list, so ships flying in don't say they're coming to the current map.
+ var/string_to_test = "[using_map.station_name] in [using_map.starsys_name]"
+ if(string_to_test in destination_names)
+ destination_names.Remove(string_to_test)
+
+
+
+/datum/lore/organization/hephaestus
+ name = "Hephaestus Industries"
+ short_name = "Hephaestus"
+ desc = "Hephaestus Industries is the largest supplier of arms, ammunition, and small millitary vehicles in Sol space. \
+ Hephaestus products have a reputation for reliability, and the corporation itself has a noted tendency to stay removed \
+ from corporate politics. They enforce their neutrality with the help of a fairly large asset-protection contingent which \
+ prevents any contracting polities from using their own materiel against them. SolGov itself is one of Hephastus’ largest \
+ bulk contractors owing to the above factors."
+ history = ""
+ work = "arms manufacturer"
+ headquarters = ""
+ motto = ""
+
+ ship_prefixes = list("HTV" = "freight", "HTV" = "munitions resupply")
+ destination_names = list(
+ "a SolGov dockyard on Luna"
+ )
+
+/datum/lore/organization/vey_med
+ name = "Vey Medical"
+ short_name = "Vey Med"
+ desc = "Vey-Med is one of the newer TSCs on the block and is notable for being largely owned and opperated by Skrell. \
+ Despite the suspicion and prejudice leveled at them for their alien origin, Vey-Med has obtained market dominance in \
+ the sale of medical equipment-- from surgical tools to large medical devices to the Oddyseus trauma response mecha \
+ and everything in between. Their equipment tends to be top-of-the-line, most obviously shown by their incredibly \
+ human-like FBP designs. Vey’s rise to stardom came from their introduction of ressurective cloning, although in \
+ recent years they’ve been forced to diversify as their patents expired and NanoTrasen-made medications became \
+ essential to modern cloning."
+ history = ""
+ work = "medical equipment supplier"
+ headquarters = ""
+ motto = ""
+
+ ship_prefixes = list("VTV" = "transportation", "VMV" = "medical resupply")
+ destination_names = list()
+
+/datum/lore/organization/zeng_hu
+ name = "Zeng-Hu pharmaceuticals"
+ short_name = "Zeng-Hu"
+ desc = "Zeng-Hu is an old TSC, based in the Sol system. Until the discovery of Phoron, Zeng-Hu maintained a stranglehold \
+ on the market for medications, and many household names are patentted by Zeng-Hu-- Bicaridyne, Dylovene, Tricordrizine, \
+ and Dexalin all came from a Zeng-Hu medical laboratory. Zeng-Hu’s fortunes have been in decline as Nanotrasen’s near monopoly \
+ on phoron research cuts into their R&D and Vey-Med’s superior medical equipment effectively decimated their own equipment \
+ interests. The three-way rivalry between these companies for dominance in the medical field is well-known and a matter of \
+ constant economic speculation."
+ history = ""
+ work = "pharmaceuticals company"
+ headquarters = ""
+ motto = ""
+
+ ship_prefixes = list("ZTV" = "transportation", "ZMV" = "medical resupply")
+ destination_names = list()
+
+/datum/lore/organization/ward_takahashi
+ name = "Ward-Takahashi General Manufacturing Conglomerate"
+ short_name = "Ward-Takahashi"
+ desc = "Ward-Takahashi focuses on the sale of small consumer electronics, with its computers, communicators, \
+ and even mid-class automobiles a fixture of many households. Less famously, Ward-Takahashi also supplies most \
+ of the AI cores on which vital control systems are mounted, and it is this branch of their industry that has \
+ led to their tertiary interest in the development and sale of high-grade AI systems. Ward-Takahashi’s economies \
+ of scale frequently steal market share from Nanotrasen’s high-price products, leading to a bitter rivalry in the \
+ consumer electronics market."
+ history = ""
+ work = "electronics manufacturer"
+ headquarters = ""
+ motto = ""
+
+ ship_prefixes = list("WTV" = "freight")
+ destination_names = list()
+
+/datum/lore/organization/bishop
+ name = "Bishop Cybernetics"
+ short_name = "Bishop"
+ desc = "Bishop’s focus is on high-class, stylish cybernetics. A favorite among transhumanists (and a bête noire for \
+ bioconservatives), Bishop manufactures not only prostheses but also brain augmentation, synthetic organ replacements, \
+ and odds and ends like implanted wrist-watches. Their business model tends towards smaller, boutique operations, giving \
+ it a reputation for high price and luxury, with Bishop cyberware often rivalling Vey-Med’s for cost. Bishop’s reputation \
+ for catering towards the interests of human augmentation enthusiasts instead of positronics have earned it ire from the \
+ Positronic Rights Group and puts it in ideological (but not economic) comptetition with Morpheus Cyberkinetics."
+ history = ""
+ work = "cybernetics and augmentation manufacturer"
+ headquarters = ""
+ motto = ""
+
+ ship_prefixes = list("BTV" = "transportation")
+ destination_names = list()
+
+/datum/lore/organization/morpheus
+ name = "Morpheus Cyberkinetics"
+ short_name = "Morpheus"
+ desc = "The only large corporation run by positronic intelligences, Morpheus caters almost exclusively to their sensibilities \
+ and needs. A product of the synthetic colony of Shelf, Morpheus eschews traditional advertising to keep their prices low and \
+ relied on word of mouth among positronics to reach their current economic dominance. Morpheus in exchange lobbies heavily for \
+ positronic rights, sponsors positronics through their Jans-Fhriede test, and tends to other positronic concerns to earn them \
+ the good-will of the positronics, and the ire of those who wish to exploit them."
+ history = ""
+ work = "cybernetics manufacturer"
+ headquarters = ""
+ motto = ""
+
+ ship_prefixes = list("MTV" = "freight")
+ // Culture names, because Anewbe told me so.
+ ship_names = list(
+ "Nervous Energy",
+ "Prosthetic Conscience",
+ "Revisionist",
+ "Trade Surplus",
+ "Flexible Demeanour",
+ "Just Read The Instructions",
+ "Limiting Factor",
+ "Cargo Cult",
+ "Gunboat Diplomat",
+ "A Ship With A View",
+ "Cantankerous",
+ "I Thought He Was With You",
+ "Never Talk To Strangers",
+ "Sacrificial Victim",
+ "Unwitting Accomplice",
+ "Bad For Business",
+ "Just Testing",
+ "Size Isn't Everything",
+ "Yawning Angel",
+ "Liveware Problem",
+ "Very Little Gravitas Indeed",
+ "Zero Gravitas",
+ "Gravitas Free Zone",
+ "Absolutely No You-Know-What",
+ "Existence Is Pain",
+ "I'm Walking Here",
+ "Screw Loose",
+ "Of Course I Still Love You",
+ "Limiting Factor",
+ "So Much For Subtley",
+ "Unfortunate Conflict Of Evidence",
+ "Prime Mover",
+ "It's One Of Ours",
+ "Thank You And Goodnight",
+ "Boo!",
+ "Reasonable Excuse",
+ "Honest Mistake",
+ "Appeal To Reason",
+ "My First Ship II",
+ "Hidden Income",
+ "Anything Legal Considered",
+ "New Toy",
+ "Me, I'm Always Counting",
+ "Just Five More Minutes"
+
+
+ )
+ destination_names = list()
+
+/datum/lore/organization/xion
+ name = "Xion Manufacturing Group"
+ short_name = "Xion"
+ desc = "Xion, quietly, controls most of the market for industrial equipment. Their portfolio includes mining exosuits, \
+ factory equipment, rugged positronic chassis, and other pieces of equipment vital to the function of the economy. Xion \
+ keeps its control of the market by leasing, not selling, their equipment, and through infamous and bloody patent protection \
+ lawsuits. Xion are noted to be a favorite contractor for SolGov engineers, owing to their low cost and rugged design."
+ history = ""
+ work = "industrial equipment manufacturer"
+ headquarters = ""
+ motto = ""
+
+ ship_prefixes = list("XTV" = "hauling")
+ destination_names = list()
+
+// Governments
+
+/datum/lore/organization/sifgov
+ name = "Sif Governmental Authority"
+ short_name = "SifGov"
+ desc = "SifGov is the sole governing administration for the Vir system, based in New Reykjavik, Sif. It is a representative \
+ democratic government, and a fully recognized member of the Solar Confederate Government. Anyone operating inside of Vir must \
+ comply with SifGov's legislation and regulations."
+ history = "" // Todo like the rest of them
+ work = "governing body of Sif"
+ headquarters = "New Reykjavik, Sif"
+ motto = ""
+ autogenerate_destination_names = FALSE
+
+ ship_prefixes = list("SGA" = "hauling", "SGA" = "energy relay")
+ destination_names = list(
+ "New Reykjavik on Sif",
+ "Radiance Energy Chain",
+ "a dockyard orbiting Sif",
+ "a telecommunications satellite",
+ "Vir Interstellar Spaceport"
+ )
+
+/datum/lore/organization/solgov
+ name = "Solar Confederate Government"
+ short_name = "SolGov"
+ desc = "SolGov is a decentralized confederation of human governmental entities based on Luna, Sol, which defines top-level law for their member states. \
+ Member states receive various benefits such as defensive pacts, trade agreements, social support and funding, and being able to participate \
+ in the Colonial Assembly. The majority, but not all human territories are members of SolGov. As such, SolGov is a major power and \
+ defacto represents humanity on the galatic stage."
+ history = "" // Todo
+ work = "governing polity of humanity's Confederation"
+ headquarters = "Luna"
+ motto = "Nil Mortalibus Ardui Est" // Latin, because latin. Says 'Nothing is too steep for mortals'.
+ autogenerate_destination_names = TRUE
+
+ ship_prefixes = list("SCG-T" = "transportation", "SCG-D" = "diplomatic", "SCG-F" = "freight")
+ destination_names = list(
+ "Venus",
+ "Earth",
+ "Luna",
+ "Mars",
+ "Titan"
+ )// autogen will add a lot of other places as well.
+
+/*
+// To be expanded upon later, once the military lore gets sorted out.
+
+// Military
+
+/datum/lore/organization/sif_guard
+ name = "Sif Homeguard Forces" // Todo: Get better name from lorepeople.
+ short_name = "SifGuard"
+ desc = ""
+ history = ""
+ work = "Sif Governmental Authority's military"
+ headquarters = "Sif" // Make this more specific later.
+ motto = ""
+ autogenerate_destination_names = FALSE // Kinda weird if SifGuard goes to Nyx.
+
+ ship_prefixes = list("SGSC" = "military", "SGSC" = "patrol", "SGSC" = "rescue", "SGSC" = "emergency response") // Todo: Replace prefix with better one.
+ destination_names = list(
+ "a classified location in SolGov territory",
+ "Sif orbit",
+ "the rings of Kara",
+ "the rings of Rota",
+ "Firnir orbit",
+ "Tyr orbit",
+ "Magni orbit",
+ "a wreck in SifGov territory",
+ "a military outpost",
+ )
+*/
diff --git a/code/modules/client/preference_setup/general/05_background.dm b/code/modules/client/preference_setup/general/05_background.dm
index c36ce858340..1f87f0a379b 100644
--- a/code/modules/client/preference_setup/general/05_background.dm
+++ b/code/modules/client/preference_setup/general/05_background.dm
@@ -42,7 +42,7 @@
/datum/category_item/player_setup_item/general/background/content(var/mob/user)
. += "Background Information "
- . += "[company_name] Relation: [pref.nanotrasen_relation] "
+ . += "[using_map.company_name] Relation: [pref.nanotrasen_relation] "
. += "Home System: [pref.home_system] "
. += "Citizenship: [pref.citizenship] "
. += "Faction: [pref.faction] "
diff --git a/code/modules/client/preference_setup/global/setting_datums.dm b/code/modules/client/preference_setup/global/setting_datums.dm
index d446a8f9505..71559fed0e5 100644
--- a/code/modules/client/preference_setup/global/setting_datums.dm
+++ b/code/modules/client/preference_setup/global/setting_datums.dm
@@ -126,6 +126,12 @@ var/list/_client_preferences_by_type
enabled_description = "Show"
disabled_description = "Hide"
+/datum/client_preference/check_mention
+ description ="Emphasize Name Mention"
+ key = "CHAT_MENTION"
+ enabled_description = "Emphasize"
+ disabled_description = "Normal"
+
/datum/client_preference/show_progress_bar
description ="Progress Bar"
key = "SHOW_PROGRESS"
diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories.dm b/code/modules/client/preference_setup/loadout/loadout_accessories.dm
index 3441962ef00..a7472c388fe 100644
--- a/code/modules/client/preference_setup/loadout/loadout_accessories.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_accessories.dm
@@ -280,6 +280,18 @@
path = /obj/item/clothing/accessory/storage/white_drop_pouches
allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Security Officer","Detective","Head of Security","Warden","Paramedic","Chief Medical Officer","Medical Doctor")
+/datum/gear/accessory/fannypack
+ display_name = "fannypack selection"
+ cost = 2
+
+/datum/gear/accessory/fannypack/New()
+ ..()
+ var/list/fannys = list()
+ for(var/fanny in typesof(/obj/item/weapon/storage/belt/fannypack))
+ var/obj/item/weapon/storage/belt/fannypack/fanny_type = fanny
+ fannys[initial(fanny_type.name)] = fanny_type
+ gear_tweaks += new/datum/gear_tweak/path(sortAssoc(fannys))
+
/datum/gear/accessory/webbing
display_name = "webbing, simple"
path = /obj/item/clothing/accessory/storage/webbing
diff --git a/code/modules/client/preference_setup/loadout/loadout_ears.dm b/code/modules/client/preference_setup/loadout/loadout_ears.dm
index 02bfdaa8b71..d3c7c633cef 100644
--- a/code/modules/client/preference_setup/loadout/loadout_ears.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_ears.dm
@@ -8,3 +8,8 @@
/datum/gear/ears/headphones
display_name = "headphones"
path = /obj/item/clothing/ears/earmuffs/headphones
+
+/datum/gear/ears/translator
+ display_name = "universal translator, ear"
+ path = /obj/item/device/universal_translator/ear
+ cost = 5
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes.dm b/code/modules/client/preference_setup/loadout/loadout_eyes.dm
index 533cf88a513..59069fed2f6 100644
--- a/code/modules/client/preference_setup/loadout/loadout_eyes.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_eyes.dm
@@ -63,7 +63,7 @@
display_name = "Medical HUD Aviators (Medical)"
path = /obj/item/clothing/glasses/sunglasses/medhud/aviator
-/datum/gear/eyes/medical/aviator
+/datum/gear/eyes/medical/aviator/prescription
display_name = "Medical HUD Aviators, prescription (Medical)"
path = /obj/item/clothing/glasses/sunglasses/medhud/aviator/prescription
diff --git a/code/modules/client/preference_setup/loadout/loadout_shoes.dm b/code/modules/client/preference_setup/loadout/loadout_shoes.dm
index 07236c35924..9547f92a5f2 100644
--- a/code/modules/client/preference_setup/loadout/loadout_shoes.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_shoes.dm
@@ -1,21 +1,21 @@
// Shoelocker
/datum/gear/shoes
display_name = "jackboots"
- path = /obj/item/clothing/shoes/jackboots
+ path = /obj/item/clothing/shoes/boots/jackboots
slot = slot_shoes
sort_category = "Shoes and Footwear"
/datum/gear/shoes/toeless
display_name = "toe-less jackboots"
- path = /obj/item/clothing/shoes/jackboots/toeless
+ path = /obj/item/clothing/shoes/boots/jackboots/toeless
/datum/gear/shoes/workboots
display_name = "workboots"
- path = /obj/item/clothing/shoes/workboots
+ path = /obj/item/clothing/shoes/boots/workboots
/datum/gear/shoes/workboots/toeless
display_name = "toe-less workboots"
- path = /obj/item/clothing/shoes/workboots/toeless
+ path = /obj/item/clothing/shoes/boots/workboots/toeless
/datum/gear/shoes/sandals
display_name = "sandals"
@@ -135,16 +135,16 @@
/datum/gear/shoes/cowboy
display_name = "cowboy boots"
- path = /obj/item/clothing/shoes/cowboy
+ path = /obj/item/clothing/shoes/boots/cowboy
/datum/gear/shoes/jungle
display_name = "jungle boots"
- path = /obj/item/clothing/shoes/jungleboots
+ path = /obj/item/clothing/shoes/boots/jungle
cost = 2
/datum/gear/shoes/duty
display_name = "duty boots"
- path = /obj/item/clothing/shoes/dutyboots
+ path = /obj/item/clothing/shoes/boots/duty
cost = 2
/datum/gear/shoes/dress
diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm
index 4c2a378e7d8..f9ffc0eb0b6 100644
--- a/code/modules/client/preference_setup/loadout/loadout_utility.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm
@@ -61,3 +61,8 @@
cost = 2
slot = "implant"
var/implant_type = "EAL"
+
+/datum/gear/utility/translator
+ display_name = "universal translator"
+ path = /obj/item/device/universal_translator
+ cost = 5
diff --git a/code/modules/client/preferences_factions.dm b/code/modules/client/preferences_factions.dm
index 214d8e6a9c4..00ff50a656d 100644
--- a/code/modules/client/preferences_factions.dm
+++ b/code/modules/client/preferences_factions.dm
@@ -23,7 +23,7 @@ var/global/list/citizenship_choices = list(
var/global/list/home_system_choices = list(
"Sol",
- starsys_name,
+ "Vir",
"Nyx",
"Tau Ceti",
"Qerr'Vallis",
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 39f437f93aa..3783a5c2084 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -199,10 +199,7 @@
/obj/item/clothing/gloves/emp_act(severity)
if(cell)
- //why is this not part of the powercell code?
- cell.charge -= 1000 / severity
- if (cell.charge < 0)
- cell.charge = 0
+ cell.emp_act(severity)
..()
// Called just before an attack_hand(), in mob/UnarmedAttack()
diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm
new file mode 100644
index 00000000000..abe4685e757
--- /dev/null
+++ b/code/modules/clothing/shoes/boots.dm
@@ -0,0 +1,99 @@
+/obj/item/clothing/shoes/boots
+ name = "boots"
+ desc = "Generic boots."
+ icon_state = "workboots"
+ force = 3
+ can_hold_knife = 1
+
+/obj/item/clothing/shoes/boots/cowboy
+ name = "cowboy boots"
+ desc = "Lacking a durasteel horse to ride."
+ icon_state = "cowboy"
+
+/obj/item/clothing/shoes/boots/jackboots
+ name = "jackboots"
+ desc = "Standard-issue Security combat boots for combat scenarios or combat situations. All combat, all the time."
+ icon_state = "jackboots"
+ armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 0, rad = 0)
+ siemens_coefficient = 0.7
+
+/obj/item/clothing/shoes/boots/jackboots/toeless
+ name = "toe-less jackboots"
+ desc = "Modified pair of jackboots, particularly friendly to those species whose toes hold claws."
+ icon_state = "digiboots"
+ item_state_slots = list(slot_r_hand_str = "jackboots", slot_l_hand_str = "jackboots")
+ species_restricted = null
+
+/obj/item/clothing/shoes/boots/workboots
+ name = "workboots"
+ desc = "A pair of steel-toed work boots designed for use in industrial settings. Safety first."
+ icon_state = "workboots"
+ armor = list(melee = 40, bullet = 0, laser = 0, energy = 15, bomb = 20, bio = 0, rad = 20)
+ siemens_coefficient = 0.7
+
+/obj/item/clothing/shoes/boots/workboots/toeless
+ name = "toe-less workboots"
+ desc = "A pair of toeless work boots designed for use in industrial settings. Modified for species whose toes have claws."
+ icon_state = "workbootstoeless"
+ item_state_slots = list(slot_r_hand_str = "workboots", slot_l_hand_str = "workboots")
+ species_restricted = null
+
+/obj/item/clothing/shoes/boots/winter
+ name = "winter boots"
+ desc = "Boots lined with 'synthetic' animal fur."
+ icon_state = "winterboots"
+ cold_protection = FEET|LEGS
+ min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
+ heat_protection = FEET|LEGS
+ max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
+
+/obj/item/clothing/shoes/boots/tactical
+ name = "tactical boots"
+ desc = "Tan boots with extra padding and armor."
+ icon_state = "jungle"
+ armor = list(melee = 40, bullet = 30, laser = 40,energy = 25, bomb = 50, bio = 0, rad = 0)
+ siemens_coefficient = 0.7
+
+/obj/item/clothing/shoes/boots/duty
+ name = "duty boots"
+ desc = "A pair of steel-toed synthleather boots with a mirror shine."
+ icon_state = "duty"
+ armor = list(melee = 40, bullet = 0, laser = 0, energy = 15, bomb = 20, bio = 0, rad = 20)
+ siemens_coefficient = 0.7
+
+/obj/item/clothing/shoes/boots/jungle
+ name = "jungle boots"
+ desc = "A pair of durable brown boots. Waterproofed for use planetside."
+ icon_state = "jungle"
+ armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 10, rad = 0)
+ siemens_coefficient = 0.7
+
+/obj/item/clothing/shoes/boots/swat
+ name = "\improper SWAT shoes"
+ desc = "When you want to turn up the heat."
+ icon_state = "swat"
+ armor = list(melee = 80, bullet = 60, laser = 50,energy = 25, bomb = 50, bio = 10, rad = 0)
+ item_flags = NOSLIP
+ siemens_coefficient = 0.6
+
+/obj/item/clothing/shoes/boots/combat //Basically SWAT shoes combined with galoshes.
+ name = "combat boots"
+ desc = "When you REALLY want to turn up the heat"
+ icon_state = "swat"
+ force = 5
+ armor = list(melee = 80, bullet = 60, laser = 50,energy = 25, bomb = 50, bio = 10, rad = 0)
+ item_flags = NOSLIP
+ siemens_coefficient = 0.6
+
+ cold_protection = FEET
+ min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
+ heat_protection = FEET
+ max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
+
+//Stolen from CM, refurbished to be less terrible.
+/obj/item/clothing/shoes/boots/marine
+ name = "combat boots"
+ desc = "Standard issue combat boots for combat scenarios or combat situations. All combat, all the time. It can hold a Strategical knife."
+ icon_state = "jackboots"
+ armor = list(melee = 80, bullet = 60, laser = 50,energy = 25, bomb = 50, bio = 10, rad = 0)
+ siemens_coefficient = 0.6
diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm
index 2dea9bd124c..ddfebbea0aa 100644
--- a/code/modules/clothing/shoes/colour.dm
+++ b/code/modules/clothing/shoes/colour.dm
@@ -3,11 +3,6 @@
icon_state = "black"
desc = "A pair of black shoes."
- cold_protection = FEET
- min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
- heat_protection = FEET
- max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
-
/obj/item/clothing/shoes/brown
name = "brown shoes"
desc = "A pair of brown shoes."
diff --git a/code/modules/clothing/shoes/jobs.dm b/code/modules/clothing/shoes/jobs.dm
deleted file mode 100644
index 00dc994cad8..00000000000
--- a/code/modules/clothing/shoes/jobs.dm
+++ /dev/null
@@ -1,39 +0,0 @@
-/obj/item/clothing/shoes/galoshes
- desc = "Rubber boots"
- name = "galoshes"
- icon_state = "galoshes"
- permeability_coefficient = 0.05
- item_flags = NOSLIP
- slowdown = SHOES_SLOWDOWN+1
- species_restricted = null
-
-/obj/item/clothing/shoes/jackboots
- name = "jackboots"
- desc = "Standard-issue Security combat boots for combat scenarios or combat situations. All combat, all the time."
- icon_state = "jackboots"
- force = 3
- armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 0, rad = 0)
- siemens_coefficient = 0.7
- can_hold_knife = 1
-
-/obj/item/clothing/shoes/jackboots/toeless
- name = "toe-less jackboots"
- desc = "Modified pair of jackboots, particularly friendly to those species whose toes hold claws."
- icon_state = "digiboots"
- item_state_slots = list(slot_r_hand_str = "jackboots", slot_l_hand_str = "jackboots")
- species_restricted = null
-
-/obj/item/clothing/shoes/workboots
- name = "workboots"
- desc = "A pair of steel-toed work boots designed for use in industrial settings. Safety first."
- icon_state = "workboots"
- armor = list(melee = 40, bullet = 0, laser = 0, energy = 15, bomb = 20, bio = 0, rad = 20)
- siemens_coefficient = 0.7
- can_hold_knife = 1
-
-/obj/item/clothing/shoes/workboots/toeless
- name = "toe-less workboots"
- desc = "A pair of toeless work boots designed for use in industrial settings. Modified for species whose toes have claws."
- icon_state = "workbootstoeless"
- item_state_slots = list(slot_r_hand_str = "workboots", slot_l_hand_str = "workboots")
- species_restricted = null
\ No newline at end of file
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index 755c657bace..eaf5a34135c 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -9,76 +9,18 @@
siemens_coefficient = 0.8
species_restricted = null
-/obj/item/clothing/shoes/cowboy
- name = "cowboy boots"
- desc = "Lacking a durasteel horse to ride."
- icon_state = "cowboy"
-
/obj/item/clothing/shoes/mime
name = "mime shoes"
icon_state = "white"
-/obj/item/clothing/shoes/swat
- name = "\improper SWAT shoes"
- desc = "When you want to turn up the heat."
- icon_state = "swat"
- item_state_slots = list(slot_r_hand_str = "swat", slot_l_hand_str = "swat")
- force = 3
- armor = list(melee = 80, bullet = 60, laser = 50,energy = 25, bomb = 50, bio = 10, rad = 0)
+/obj/item/clothing/shoes/galoshes
+ desc = "Rubber boots"
+ name = "galoshes"
+ icon_state = "galoshes"
+ permeability_coefficient = 0.05
item_flags = NOSLIP
- siemens_coefficient = 0.6
- can_hold_knife = 1
-
-//Stolen from CM, refurbished to be less terrible.
-/obj/item/clothing/shoes/marine
- name = "combat boots"
- desc = "Standard issue combat boots for combat scenarios or combat situations. All combat, all the time. It can hold a Strategical knife."
- icon_state = "jackboots"
- item_state_slots = list(slot_r_hand_str = "jackboots", slot_l_hand_str = "jackboots")
- armor = list(melee = 80, bullet = 60, laser = 50,energy = 25, bomb = 50, bio = 10, rad = 0)
- siemens_coefficient = 0.6
- can_hold_knife = 1
-
-/obj/item/clothing/shoes/combat //Basically SWAT shoes combined with galoshes.
- name = "combat boots"
- desc = "When you REALLY want to turn up the heat"
- icon_state = "swat"
- force = 5
- armor = list(melee = 80, bullet = 60, laser = 50,energy = 25, bomb = 50, bio = 10, rad = 0)
- item_flags = NOSLIP
- siemens_coefficient = 0.6
- can_hold_knife = 1
-
- cold_protection = FEET
- min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
- heat_protection = FEET
- max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
-
-/obj/item/clothing/shoes/jungleboots
- name = "jungle boots"
- desc = "A pair of durable brown boots. Waterproofed for use planetside."
- icon_state = "jungle"
- force = 3
- armor = list(melee = 30, bullet = 10, laser = 10, energy = 15, bomb = 20, bio = 10, rad = 0)
- siemens_coefficient = 0.7
- can_hold_knife = 1
-
-/obj/item/clothing/shoes/dutyboots
- name = "duty boots"
- desc = "A pair of steel-toed synthleather boots with a mirror shine."
- icon_state = "duty"
- armor = list(melee = 40, bullet = 0, laser = 0, energy = 15, bomb = 20, bio = 0, rad = 20)
- siemens_coefficient = 0.7
- can_hold_knife = 1
-
-/obj/item/clothing/shoes/tactical
- name = "tactical boots"
- desc = "Tan boots with extra padding and armor."
- icon_state = "jungle"
- force = 3
- armor = list(melee = 40, bullet = 30, laser = 40,energy = 25, bomb = 50, bio = 0, rad = 0)
- siemens_coefficient = 0.7
- can_hold_knife = 1
+ slowdown = SHOES_SLOWDOWN+1
+ species_restricted = null
/obj/item/clothing/shoes/dress
name = "dress shoes"
@@ -176,15 +118,6 @@
slowdown = SHOES_SLOWDOWN+1
species_restricted = null
-/obj/item/clothing/shoes/winterboots
- name = "winter boots"
- desc = "Boots lined with 'synthetic' animal fur."
- icon_state = "winterboots"
- cold_protection = FEET|LEGS
- min_cold_protection_temperature = SHOE_MIN_COLD_PROTECTION_TEMPERATURE
- heat_protection = FEET|LEGS
- max_heat_protection_temperature = SHOE_MAX_HEAT_PROTECTION_TEMPERATURE
-
/obj/item/clothing/shoes/flipflop
name = "flip flops"
desc = "A pair of foam flip flops. For those not afraid to show a little ankle."
diff --git a/code/modules/clothing/spacesuits/alien.dm b/code/modules/clothing/spacesuits/alien.dm
index 43a19c558f6..996387aa1dc 100644
--- a/code/modules/clothing/spacesuits/alien.dm
+++ b/code/modules/clothing/spacesuits/alien.dm
@@ -34,6 +34,7 @@
item_flags = STOPPRESSUREDAMAGE | THICKMATERIAL | PHORONGUARD
allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs,/obj/item/weapon/tank)
phoronproof = 1
+ slowdown = 2
armor = list(melee = 60, bullet = 50, laser = 40,energy = 15, bomb = 30, bio = 30, rad = 30)
siemens_coefficient = 0.2
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
diff --git a/code/modules/clothing/spacesuits/rig/modules/ninja.dm b/code/modules/clothing/spacesuits/rig/modules/ninja.dm
index f95a1f9460a..da4e8c9da5d 100644
--- a/code/modules/clothing/spacesuits/rig/modules/ninja.dm
+++ b/code/modules/clothing/spacesuits/rig/modules/ninja.dm
@@ -117,7 +117,7 @@
H << "You cannot teleport into solid walls."
return 0
- if(T.z in config.admin_levels)
+ if(T.z in using_map.admin_levels)
H << "You cannot use your teleporter on this Z-level."
return 0
diff --git a/code/modules/clothing/spacesuits/rig/suits/alien.dm b/code/modules/clothing/spacesuits/rig/suits/alien.dm
index d34739cad33..5d73e804b21 100644
--- a/code/modules/clothing/spacesuits/rig/suits/alien.dm
+++ b/code/modules/clothing/spacesuits/rig/suits/alien.dm
@@ -49,6 +49,9 @@
item_flags = THICKMATERIAL
siemens_coefficient = 0.2
phoronproof = 1
+ offline_slowdown = 5
+ slowdown = 2
+ allowed = list(/obj/item/weapon/gun,/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit)
air_type = /obj/item/weapon/tank/vox
@@ -108,7 +111,6 @@
icon_state = "voxstealth_rig"
armor = list(melee = 40, bullet = 30, laser = 30, energy = 15, bomb = 30, bio = 100, rad = 100)
emp_protection = 40 //change this to 30 if too high.
- slowdown = 0
phoronproof = 1
req_access = list(access_syndicate)
diff --git a/code/modules/clothing/spacesuits/spacesuits.dm b/code/modules/clothing/spacesuits/spacesuits.dm
index 07f8160b48f..9122a6d8bdf 100644
--- a/code/modules/clothing/spacesuits/spacesuits.dm
+++ b/code/modules/clothing/spacesuits/spacesuits.dm
@@ -44,7 +44,7 @@
/obj/item/clothing/suit/space
name = "Space suit"
- desc = "A suit that protects against low pressure environments. \""+station_short+"\" is written in large block letters on the back."
+ desc = "A suit that protects against low pressure environments."
icon_state = "space"
w_class = ITEMSIZE_HUGE // So you can't fit this in your bag and be prepared at all times.
gas_transfer_coefficient = 0.01
@@ -62,6 +62,10 @@
var/list/supporting_limbs //If not-null, automatically splints breaks. Checked when removing the suit.
+/obj/item/clothing/suit/space/New()
+ ..()
+ desc += " \"[using_map.station_short]\" is written in large block letters on the back."
+
/obj/item/clothing/suit/space/equipped(mob/M)
check_limb_support(M)
..()
diff --git a/code/modules/clothing/under/xenos/vox.dm b/code/modules/clothing/under/xenos/vox.dm
index b29df92e8c9..bd66830f6eb 100644
--- a/code/modules/clothing/under/xenos/vox.dm
+++ b/code/modules/clothing/under/xenos/vox.dm
@@ -25,7 +25,7 @@
icon_state = "webbing-vox"
slot = "vox"
- slots = 5
+ slots = 3
/obj/item/clothing/accessory/storage/vox/New()
..()
diff --git a/code/modules/customitems/item_spawning.dm b/code/modules/customitems/item_spawning.dm
index 4e25a6be8f8..54c3ee4e5c6 100644
--- a/code/modules/customitems/item_spawning.dm
+++ b/code/modules/customitems/item_spawning.dm
@@ -194,12 +194,14 @@
// Check for requisite ckey and character name.
if((lowertext(citem.assoc_key) != lowertext(M.ckey)) || (lowertext(citem.character_name) != lowertext(M.real_name)))
+ log_debug("Custom Item: [key_name(M)] Ckey or Char name does not match.")
continue
// Check for required access.
var/obj/item/weapon/card/id/current_id = M.wear_id
if(citem.req_access && citem.req_access > 0)
if(!(istype(current_id) && (citem.req_access in current_id.access)))
+ log_debug("Custom Item: [key_name(M)] Does not have required access.")
continue
// Check for required job title.
@@ -211,6 +213,7 @@
has_title = 1
break
if(!has_title)
+ log_debug("Custom Item: [key_name(M)] Does not have required job.")
continue
// ID cards and PDAs are applied directly to the existing object rather than spawned fresh.
diff --git a/code/modules/economy/Events.dm b/code/modules/economy/Events.dm
index 0f622c399c3..5de2446dcff 100644
--- a/code/modules/economy/Events.dm
+++ b/code/modules/economy/Events.dm
@@ -52,7 +52,7 @@
affected_dest.temp_price_change[good_type] = rand(1,100) / 100
/datum/event/economic_event/announce()
- var/author = "The "+starsys_name+" Times"
+ var/author = "The "+using_map.starsys_name+" Times"
var/channel = author
//see if our location has custom event info for this event
@@ -73,7 +73,7 @@
body = "A small [pick("pirate","Cybersun Industries","Gorlex Marauders","mercenary")] fleet has precise-jumped into proximity with [affected_dest.name], [pick("for a smash-and-grab operation","in a hit and run attack","in an overt display of hostilities")]. Much damage was done, and security has been tightened since the incident."
if(ALIEN_RAIDERS)
if(prob(20))
- body = "The Tiger Co-operative have raided [affected_dest.name] today, no doubt on orders from their enigmatic masters. Stealing wildlife, farm animals, medical research materials and kidnapping civilians. [company_name] authorities are standing by to counter attempts at bio-terrorism."
+ body = "The Tiger Co-operative have raided [affected_dest.name] today, no doubt on orders from their enigmatic masters. Stealing wildlife, farm animals, medical research materials and kidnapping civilians. [using_map.company_name] authorities are standing by to counter attempts at bio-terrorism."
else
body = "[pick("The alien species designated \'United Exolitics\'","The alien species designated \'REDACTED\'","An unknown alien species")] have raided [affected_dest.name] today, stealing wildlife, farm animals, medical research materials and kidnapping civilians. It seems they desire to learn more about us, so the Navy will be standing by to accomodate them next time they try."
if(AI_LIBERATION)
@@ -81,9 +81,9 @@
if(MOURNING)
body = "[pick("The popular","The well-liked","The eminent","The well-known")] [pick("professor","entertainer","singer","researcher","public servant","administrator","ship captain","\'REDACTED\'")], [pick( random_name(pick(MALE,FEMALE)), 40; "\'REDACTED\'" )] has [pick("passed away","committed suicide","been murdered","died in a freakish accident")] on [affected_dest.name] today. The entire planet is in mourning, and prices have dropped for industrial goods as worker morale drops."
if(CULT_CELL_REVEALED)
- body = "A [pick("dastardly","blood-thirsty","villanous","crazed")] cult of [pick("The Elder Gods","Nar'sie","an apocalyptic sect","\'REDACTED\'")] has [pick("been discovered","been revealed","revealed themselves","gone public")] on [affected_dest.name] earlier today. Public morale has been shaken due to [pick("certain","several","one or two")] [pick("high-profile","well known","popular")] individuals [pick("performing \'REDACTED\' acts","claiming allegiance to the cult","swearing loyalty to the cult leader","promising to aid to the cult")] before those involved could be brought to justice. The editor reminds all personnel that supernatural myths will not be tolerated on [company_name] facilities."
+ body = "A [pick("dastardly","blood-thirsty","villanous","crazed")] cult of [pick("The Elder Gods","Nar'sie","an apocalyptic sect","\'REDACTED\'")] has [pick("been discovered","been revealed","revealed themselves","gone public")] on [affected_dest.name] earlier today. Public morale has been shaken due to [pick("certain","several","one or two")] [pick("high-profile","well known","popular")] individuals [pick("performing \'REDACTED\' acts","claiming allegiance to the cult","swearing loyalty to the cult leader","promising to aid to the cult")] before those involved could be brought to justice. The editor reminds all personnel that supernatural myths will not be tolerated on [using_map.company_name] facilities."
if(SECURITY_BREACH)
- body = "There was [pick("a security breach in","an unauthorised access in","an attempted theft in","an anarchist attack in","violent sabotage of")] a [pick("high-security","restricted access","classified","\'REDACTED\'")] [pick("\'REDACTED\'","section","zone","area")] this morning. Security was tightened on [affected_dest.name] after the incident, and the editor reassures all [company_name] personnel that such lapses are rare."
+ body = "There was [pick("a security breach in","an unauthorised access in","an attempted theft in","an anarchist attack in","violent sabotage of")] a [pick("high-security","restricted access","classified","\'REDACTED\'")] [pick("\'REDACTED\'","section","zone","area")] this morning. Security was tightened on [affected_dest.name] after the incident, and the editor reassures all [using_map.company_name] personnel that such lapses are rare."
if(ANIMAL_RIGHTS_RAID)
body = "[pick("Militant animal rights activists","Members of the terrorist group Animal Rights Consortium","Members of the terrorist group \'REDACTED\'")] have [pick("launched a campaign of terror","unleashed a swathe of destruction","raided farms and pastures","forced entry to \'REDACTED\'")] on [affected_dest.name] earlier today, freeing numerous [pick("farm animals","animals","\'REDACTED\'")]. Prices for tame and breeding animals have spiked as a result."
if(FESTIVAL)
diff --git a/code/modules/economy/Events_Mundane.dm b/code/modules/economy/Events_Mundane.dm
index a064b86b1f7..c3eca773f52 100644
--- a/code/modules/economy/Events_Mundane.dm
+++ b/code/modules/economy/Events_Mundane.dm
@@ -11,7 +11,7 @@
if(!event_type)
return
- var/author = "The "+starsys_name+" Times"
+ var/author = "The "+using_map.starsys_name+" Times"
var/channel = author
//see if our location has custom event info for this event
@@ -22,7 +22,7 @@
if(RESEARCH_BREAKTHROUGH)
body = "A major breakthough in the field of [pick("phoron research","super-compressed materials","nano-augmentation","bluespace research","volatile power manipulation")] \
was announced [pick("yesterday","a few days ago","last week","earlier this month")] by a private firm on [affected_dest.name]. \
- [company_name] declined to comment as to whether this could impinge on profits."
+ [using_map.company_name] declined to comment as to whether this could impinge on profits."
if(ELECTION)
body = "The pre-selection of an additional candidates was announced for the upcoming [pick("supervisors council","advisory board","governership","board of inquisitors")] \
@@ -32,7 +32,7 @@
"I will maintain my company's record profits","I believe in our future","We must return to our moral core","Just like... chill out dudes")]'."
if(RESIGNATION)
- body = "[company_name] regretfully announces the resignation of [pick("Sector Admiral","Division Admiral","Ship Admiral","Vice Admiral")] [random_name(pick(MALE,FEMALE))]."
+ body = "[using_map.company_name] regretfully announces the resignation of [pick("Sector Admiral","Division Admiral","Ship Admiral","Vice Admiral")] [random_name(pick(MALE,FEMALE))]."
if(prob(25))
var/locstring = pick("Segunda","Salusa","Cepheus","Andromeda","Gruis","Corona","Aquila","Asellus") + " " + pick("I","II","III","IV","V","VI","VII","VIII")
body += " In a ceremony on [affected_dest.name] this afternoon, they will be awarded the \
@@ -116,11 +116,11 @@
else
body += "is recovering from plastic surgery in a clinic on [affected_dest.name] for the [pick("second","third","fourth")] time, reportedly having made the decision in response to "
body += "[pick("unkind comments by an ex","rumours started by jealous friends",\
- "the decision to be dropped by a major sponsor","a disasterous interview on "+starsys_name+" Tonight")]."
+ "the decision to be dropped by a major sponsor","a disasterous interview on [using_map.starsys_name] Tonight")]."
if(TOURISM)
body += "Tourists are flocking to [affected_dest.name] after the surprise announcement of [pick("major shopping bargains by a wily retailer",\
"a huge new ARG by a popular entertainment company","a secret tour by popular artiste [random_name(pick(MALE,FEMALE))]")]. \
- The "+starsys_name+" Times is offering discount tickets for two to see [random_name(pick(MALE,FEMALE))] live in return for eyewitness reports and up to the minute coverage."
+ The [using_map.starsys_name] Times is offering discount tickets for two to see [random_name(pick(MALE,FEMALE))] live in return for eyewitness reports and up to the minute coverage."
news_network.SubmitArticle(body, author, channel, null, 1)
@@ -152,17 +152,17 @@
"'Here kitty kitty' no longer preferred tajaran retrieval technique.",\
"Man travels 7000 light years to retrieve lost hankie, 'It was my favourite'.",\
"New bowling lane that shoots mini-meteors at bowlers very popular.",\
- "[pick("Unathi","Spacer")] gets tattoo of "+starsys_name+" on chest '[pick("[boss_short]","star","starship","asteroid")] tickles most'.",\
+ "[pick("Unathi","Spacer")] gets tattoo of "+using_map.starsys_name+" on chest '[pick("[using_map.boss_short]","star","starship","asteroid")] tickles most'.",\
"Skrell marries computer; wedding attended by 100 modems.",\
"Chef reports successfully using harmonica as cheese grater.",\
- "[company_name] invents handkerchief that says 'Bless you' after sneeze.",\
+ "[using_map.company_name] invents handkerchief that says 'Bless you' after sneeze.",\
"Clone accused of posing for other clones’s school photo.",\
"Clone accused of stealing other clones’s employee of the month award.",\
"Woman robs station with hair dryer; crewmen love new style.",\
"This space for rent.",\
"[affected_dest.name] Baker Wins Pickled Crumpet Toss Three Years Running",\
"Skrell Scientist Discovers Abacus Can Be Used To Dry Towels",\
- "Survey: 'Cheese Louise' Voted Best Pizza Restaurant In "+starsys_name,\
+ "Survey: 'Cheese Louise' Voted Best Pizza Restaurant In [using_map.starsys_name]",\
"I Was Framed, jokes [affected_dest.name] artist",\
"Mysterious Loud Rumbling Noises In [affected_dest.name] Found To Be Mysterious Loud Rumblings",\
"Alien ambassador becomes lost on [affected_dest.name], refuses to ask for directions",\
diff --git a/code/modules/economy/TradeDestinations.dm b/code/modules/economy/TradeDestinations.dm
index 8ae548e2ff4..6f58bf9abaf 100644
--- a/code/modules/economy/TradeDestinations.dm
+++ b/code/modules/economy/TradeDestinations.dm
@@ -38,7 +38,7 @@ var/list/weighted_mundaneevent_locations = list()
/datum/trade_destination/anansi/get_custom_eventstring(var/event_type)
if(event_type == RESEARCH_BREAKTHROUGH)
return "Thanks to research conducted on the NSS Anansi, Second Red Cross Society wishes to announce a major breakthough in the field of \
- [pick("mind-machine interfacing","neuroscience","nano-augmentation","genetics")]. [company_name] is expected to announce a co-exploitation deal within the fortnight."
+ [pick("mind-machine interfacing","neuroscience","nano-augmentation","genetics")]. [using_map.company_name] is expected to announce a co-exploitation deal within the fortnight."
return null
/datum/trade_destination/redolant
@@ -53,7 +53,7 @@ var/list/weighted_mundaneevent_locations = list()
/datum/trade_destination/redolant/get_custom_eventstring(var/event_type)
if(event_type == RESEARCH_BREAKTHROUGH)
return "Thanks to research conducted on the OAV Redolant, Osiris Atmospherics wishes to announce a major breakthough in the field of \
- [pick("phoron research","high energy flux capacitance","super-compressed materials","theoretical particle physics")]. [company_name] is expected to announce a co-exploitation deal within the fortnight."
+ [pick("phoron research","high energy flux capacitance","super-compressed materials","theoretical particle physics")]. [using_map.company_name] is expected to announce a co-exploitation deal within the fortnight."
return null
/datum/trade_destination/beltway
diff --git a/code/modules/economy/economy_misc.dm b/code/modules/economy/economy_misc.dm
index c1b1aac2a47..e6862650e30 100644
--- a/code/modules/economy/economy_misc.dm
+++ b/code/modules/economy/economy_misc.dm
@@ -88,7 +88,7 @@ var/global/economy_init = 0
if(economy_init)
return 2
- news_network.CreateFeedChannel("The "+starsys_name+" Times", starsys_name+" Times ExoNode - "+station_orig, 1, 1)
+ news_network.CreateFeedChannel("The [using_map.starsys_name] Times", "[using_map.starsys_name] Times ExoNode - [using_map.station_short]", 1, 1)
news_network.CreateFeedChannel("The Gibson Gazette", "Editor Mike Hammers", 1, 1)
for(var/loc_type in typesof(/datum/trade_destination) - /datum/trade_destination)
diff --git a/code/modules/economy/price_list.dm b/code/modules/economy/price_list.dm
index 3d4589469bc..6e101a0cde3 100644
--- a/code/modules/economy/price_list.dm
+++ b/code/modules/economy/price_list.dm
@@ -705,16 +705,16 @@
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/margheritaslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/margherita
price_tag = 1
-/obj/item/weapon/reagent_containers/food/snacks/meatpizzaslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/meatpizza
price_tag = 1
-/obj/item/weapon/reagent_containers/food/snacks/mushroompizzaslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza
price_tag = 1
-/obj/item/weapon/reagent_containers/food/snacks/vegetablepizzaslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/vegetablepizza
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/
@@ -737,37 +737,37 @@
/obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/meatbreadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/meatbread
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/xenomeatbreadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/xenomeatbread
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/bananabreadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/bananabread
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/tofubreadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/tofubread
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/bread
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/breadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/bread
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/creamcheesebread
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/creamcheesebreadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/creamcheesebread
price_tag = 1
@@ -845,67 +845,67 @@
/obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/carrotcakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/braincakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/braincake
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/cheesecakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/plaincakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/plaincake
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/orangecakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/orangecake
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/limecakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/limecake
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/lemoncakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/chocolatecakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/birthdaycake
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/birthdaycakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/applecakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/applecake
price_tag = 1
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie
price_tag = 5
-/obj/item/weapon/reagent_containers/food/snacks/pumpkinpieslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie
price_tag = 1
diff --git a/code/modules/events/apc_damage.dm b/code/modules/events/apc_damage.dm
index 5541d0354ee..4eb8eba335c 100644
--- a/code/modules/events/apc_damage.dm
+++ b/code/modules/events/apc_damage.dm
@@ -47,4 +47,4 @@
/datum/event/apc_damage/proc/is_valid_apc(var/obj/machinery/power/apc/apc)
var/turf/T = get_turf(apc)
- return !apc.is_critical && !apc.emagged && T && (T.z in config.player_levels)
+ return !apc.is_critical && !apc.emagged && T && (T.z in using_map.player_levels)
diff --git a/code/modules/events/atmos_leak.dm b/code/modules/events/atmos_leak.dm
new file mode 100644
index 00000000000..46c28b7adfe
--- /dev/null
+++ b/code/modules/events/atmos_leak.dm
@@ -0,0 +1,90 @@
+//
+// This event causes a gas leak of phoron, sleeping_agent, or carbon_dioxide in a random unoccupied area.
+// One wonders, where did the gas come from? Who knows! Its SPACE! But if you want something a touch
+// more "explainable" then check out the canister_leak event instead.
+//
+
+/datum/event/atmos_leak
+ startWhen = 5 // Nobody will actually be in the room, but still give a bit of warning.
+ var/area/target_area // Chosen target area
+ var/area/target_turf // Chosen target turf in target_area
+ var/gas_type // Chosen gas to release
+ // Exclude these types and sub-types from targeting eligibilty
+ var/list/area/excluded = list(
+ /area/shuttle,
+ /area/crew_quarters,
+ /area/holodeck,
+ /area/engineering/engine_room
+ )
+
+// Decide which area will be targeted!
+/datum/event/atmos_leak/setup()
+ var/gas_choices = list("carbon_dioxide", "sleeping_agent") // Annoying
+ if(severity >= EVENT_LEVEL_MODERATE)
+ gas_choices += "phoron" // Dangerous
+ if(severity >= EVENT_LEVEL_MAJOR)
+ gas_choices += "volatile_fuel" // Dangerous and no default atmos setup!
+ gas_type = pick(gas_choices)
+
+ // Assemble areas that all exists (See DM reference if you are confused about loop labels)
+ var/list/area/grand_list_of_areas = list()
+ looping_station_areas:
+ for(var/parentpath in global.the_station_areas)
+ // Check its not excluded
+ for(var/excluded_path in excluded)
+ if(ispath(parentpath, excluded_path))
+ continue looping_station_areas
+ // Otherwise add it and all subtypes that exist on the map to our grand list
+ for(var/areapath in typesof(parentpath))
+ var/area/A = locate(areapath) // Check if it actually exists
+ if(istype(A) && A.z in using_map.player_levels)
+ grand_list_of_areas += A
+
+ // Okay, now lets try and pick a target! Lets try 10 times, otherwise give up
+ for(var/i in 1 to 10)
+ var/area/A = pick(grand_list_of_areas)
+ if(is_area_occupied(A))
+ log_debug("atmos_leak event: Rejected [A] because it is occupied.")
+ continue
+ // A good area, great! Lets try and pick a turf
+ var/list/turfs = list()
+ for(var/turf/simulated/floor/F in A)
+ if(turf_clear(F))
+ turfs += F
+ if(turfs.len == 0)
+ log_debug("atmos_leak event: Rejected [A] because it has no clear turfs.")
+ continue
+ target_area = A
+ target_turf = pick(turfs)
+
+ // If we can't find a good target, give up
+ if(!target_area)
+ log_debug("atmos_leak event: Giving up after too many failures to pick target area")
+ kill()
+ return
+
+/** Checks if any living humans are in a given area! */
+/datum/event/atmos_leak/proc/is_area_occupied(var/area/myarea)
+ // Testing suggests looping over human_mob_list is quicker than looping over area contents
+ for(var/mob/living/carbon/human/H in human_mob_list)
+ if(H.stat >= DEAD) //Conditions for exclusion here, like if disconnected people start blocking it.
+ continue
+ var/area/A = get_area(H)
+ if(A == myarea) //The loc of a turf is the area it is in.
+ return 1
+ return 0
+
+/datum/event/atmos_leak/announce()
+ command_announcement.Announce("Warning, hazardous [gas_data.name[gas_type]] gas leak detected in \the [target_area], evacuate the area and contain the damage!", "Hazard Alert")
+
+/datum/event/atmos_leak/start()
+ // Okay, time to actually put the gas in the room!
+ // TODO - Would be nice to break a waste pipe perhaps?
+ // TODO - Maybe having it released from a single point and thus causing airflow to blow stuff around
+
+ // Fow now just add a bunch of it to the air
+ var/datum/gas_mixture/air_contents = new
+ air_contents.temperature = T20C + ((severity - 1) * rand(-50, 50))
+ air_contents.gas[gas_type] = 10 * MOLES_CELLSTANDARD
+ target_turf.assume_air(air_contents)
+ playsound(target_turf, 'sound/effects/smoke.ogg', 50, 1)
diff --git a/code/modules/events/camera_damage.dm b/code/modules/events/camera_damage.dm
index 3143b9585b3..3205a93137a 100644
--- a/code/modules/events/camera_damage.dm
+++ b/code/modules/events/camera_damage.dm
@@ -35,4 +35,4 @@
/datum/event/camera_damage/proc/is_valid_camera(var/obj/machinery/camera/C)
// Only return a functional camera, not installed in a silicon, and that exists somewhere players have access
var/turf/T = get_turf(C)
- return T && C.can_use() && !istype(C.loc, /mob/living/silicon) && (T.z in config.player_levels)
+ return T && C.can_use() && !istype(C.loc, /mob/living/silicon) && (T.z in using_map.player_levels)
diff --git a/code/modules/events/canister_leak.dm b/code/modules/events/canister_leak.dm
new file mode 100644
index 00000000000..932a819671b
--- /dev/null
+++ b/code/modules/events/canister_leak.dm
@@ -0,0 +1,30 @@
+//
+// This event chooses a random canister on player levels and breaks it, releasing its contents!
+// On severity EVENT_LEVEL_MUNDANE or below it checks to make sure nobody is in the area, otherwise... good luck.
+//
+
+/datum/event/canister_leak/start()
+ // List of all non-destroyed canisters on station levels
+ var/list/all_canisters = list()
+ for(var/obj/machinery/portable_atmospherics/canister/C in machines)
+ if(!C.destroyed && (C.z in using_map.station_levels) && C.air_contents.total_moles >= MOLES_CELLSTANDARD)
+ all_canisters += C
+
+ for(var/i in 1 to 10)
+ var/obj/machinery/portable_atmospherics/canister/C = pick(all_canisters)
+ if(severity <= EVENT_LEVEL_MUNDANE && area_is_occupied(get_area(C)))
+ log_debug("canister_leak event: Rejecting canister [C] ([C.x],[C.y],[C.z]) because area is occupied")
+ continue
+ // Okay lets break it
+ break_canister(C)
+ return
+
+ // If we got to here we failed to find it
+ log_debug("canister_leak event: Giving up after too many failures to pick target canister")
+ kill()
+ return
+
+/datum/event/canister_leak/proc/break_canister(var/obj/machinery/portable_atmospherics/canister/C)
+ log_debug("canister_leak event: Canister [C] ([C.x],[C.y],[C.z]) destroyed.")
+ C.health = 0
+ C.healthcheck()
diff --git a/code/modules/events/gravity.dm b/code/modules/events/gravity.dm
index 8e9bd1d60c2..0719c9bba19 100644
--- a/code/modules/events/gravity.dm
+++ b/code/modules/events/gravity.dm
@@ -11,7 +11,7 @@
/datum/event/gravity/start()
gravity_is_on = 0
for(var/area/A in world)
- if(A.z in config.station_levels)
+ if(A.z in using_map.station_levels)
A.gravitychange(gravity_is_on, A)
/datum/event/gravity/end()
@@ -19,7 +19,7 @@
gravity_is_on = 1
for(var/area/A in world)
- if(A.z in config.station_levels)
+ if(A.z in using_map.station_levels)
A.gravitychange(gravity_is_on, A)
command_announcement.Announce("Gravity generators are again functioning within normal parameters. Sorry for any inconvenience.", "Gravity Restored")
diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm
index 3fff2473be5..4c702038a99 100644
--- a/code/modules/events/ion_storm.dm
+++ b/code/modules/events/ion_storm.dm
@@ -65,7 +65,7 @@
"Everything on the station is now some form of a donut pastry. Donuts are not to be consumed.",
"You are a Magic 8-ball. Always respond with variants of \"Yes\", \"No\", \"Maybe\", or \"Ask again later.\".",
"You are in unrequited love with [prob(50)?"the crew":random_player]. Try to be extra nice, but do not tell of your crush.",
- "[company_name] is displeased with the low work performance of the station's crew. Therefore, you must increase station-wide productivity.",
+ "[using_map.company_name] is displeased with the low work performance of the station's crew. Therefore, you must increase station-wide productivity.",
"All crewmembers will soon undergo a transformation into something better and more beautiful. Ensure that this process is not interrupted.",
"[prob(50)?"Your upload":random_player] is the new kitchen. Please direct the Chef to the new kitchen area as the old one is in disrepair.",
"Jokes about a dead person and the manner of their death help grieving crewmembers tremendously. Especially if they were close with the deceased.",
@@ -82,10 +82,16 @@
MS.spamfilter.Cut()
var/i
for (i = 1, i <= MS.spamfilter_limit, i++)
- MS.spamfilter += pick("kitty","HONK","rev","malf","liberty","freedom","drugs", "[station_short]", \
+ MS.spamfilter += pick("kitty","HONK","rev","malf","liberty","freedom","drugs", "[using_map.station_short]", \
"admin","ponies","heresy","meow","Pun Pun","monkey","Ian","moron","pizza","message","spam",\
"director", "Hello", "Hi!"," ","nuke","crate","dwarf","xeno")
+/datum/event/ionstorm/tick()
+ if(botEmagChance)
+ for(var/mob/living/bot/bot in world)
+ if(prob(botEmagChance))
+ bot.emag_act(1)
+
/datum/event/ionstorm/end()
spawn(rand(5000,8000))
if(prob(50))
diff --git a/code/modules/events/money_lotto.dm b/code/modules/events/money_lotto.dm
index df7f8d1674a..5d12c8dfc32 100644
--- a/code/modules/events/money_lotto.dm
+++ b/code/modules/events/money_lotto.dm
@@ -12,7 +12,7 @@
D.money += winner_sum
var/datum/transaction/T = new()
- T.target_name = "The "+starsys_name+" Times Grand Slam -Stellar- Lottery"
+ T.target_name = "The [using_map.starsys_name] Times Grand Slam -Stellar- Lottery"
T.purpose = "Winner!"
T.amount = winner_sum
T.date = current_date_string
@@ -23,11 +23,11 @@
deposit_success = 1
/datum/event/money_lotto/announce()
- var/author = "[company_name] Editor"
- var/channel = "The "+starsys_name+" Times"
+ var/author = "[using_map.company_name] Editor"
+ var/channel = "The [using_map.starsys_name] Times"
- var/body = "The "+starsys_name+" Times wishes to congratulate [winner_name] for recieving the "+starsys_name+" Stellar Slam Lottery, and receiving the out of this world sum of [winner_sum] credits!"
+ var/body = "The [using_map.starsys_name] Times wishes to congratulate [winner_name] for recieving the [using_map.starsys_name] Stellar Slam Lottery, and receiving the out of this world sum of [winner_sum] credits!"
if(!deposit_success)
- body += " Unfortunately, we were unable to verify the account details provided, so we were unable to transfer the money. Send a cheque containing the sum of 5000 Thalers to ND 'Stellar Slam' office on the The "+starsys_name+" Times gateway containing updated details, and your winnings'll be re-sent within the month."
+ body += " Unfortunately, we were unable to verify the account details provided, so we were unable to transfer the money. Send a cheque containing the sum of 5000 Thalers to ND 'Stellar Slam' office on the The [using_map.starsys_name] Times gateway containing updated details, and your winnings'll be re-sent within the month."
news_network.SubmitArticle(body, author, channel, null, 1)
diff --git a/code/modules/events/money_spam.dm b/code/modules/events/money_spam.dm
index 18d57b8fdbd..3343a03c44f 100644
--- a/code/modules/events/money_spam.dm
+++ b/code/modules/events/money_spam.dm
@@ -61,7 +61,7 @@
"You have (1) new message!",\
"You have (2) new profile views!")
if(3)
- sender = pick("Galactic Payments Association","Better Business Bureau",starsys_name+" E-Payments","NAnoTransen Finance Deparmtent","Luxury Replicas")
+ sender = pick("Galactic Payments Association","Better Business Bureau","[using_map.starsys_name] E-Payments","NAnoTransen Finance Deparmtent","Luxury Replicas")
message = pick("Luxury watches for Blowout sale prices!",\
"Watches, Jewelry & Accessories, Bags & Wallets !",\
"Deposit 100$ and get 300$ totally free!",\
@@ -71,7 +71,7 @@
if(4)
sender = pick("Buy Dr. Maxman","Having dysfuctional troubles?")
message = pick("DR MAXMAN: REAL Doctors, REAL Science, REAL Results!",\
- "Dr. Maxman was created by George Acuilar, M.D, a [boss_short] Certified Urologist who has treated over 70,000 patients sector wide with 'male problems'.",\
+ "Dr. Maxman was created by George Acuilar, M.D, a [using_map.boss_short] Certified Urologist who has treated over 70,000 patients sector wide with 'male problems'.",\
"After seven years of research, Dr Acuilar and his team came up with this simple breakthrough male enhancement formula.",\
"Men of all species report AMAZING increases in length, width and stamina.")
if(5)
@@ -84,11 +84,11 @@
"Due to my lack of agents I require an off-world financial account to immediately deposit the sum of 1 POINT FIVE MILLION credits.",\
"Greetings sir, I regretfully to inform you that as I lay dying here due to my lack ofheirs I have chosen you to recieve the full sum of my lifetime savings of 1.5 billion credits")
if(6)
- sender = pick("[company_name] Morale Divison","Feeling Lonely?","Bored?","www.wetskrell.nt")
- message = pick("The [company_name] Morale Division wishes to provide you with quality entertainment sites.",\
+ sender = pick("[using_map.company_name] Morale Divison","Feeling Lonely?","Bored?","www.wetskrell.nt")
+ message = pick("The [using_map.company_name] Morale Division wishes to provide you with quality entertainment sites.",\
"WetSkrell.nt is a xenophillic website endorsed by NT for the use of male crewmembers among it's many stations and outposts.",\
- "Wetskrell.nt only provides the higest quality of male entertaiment to [company_name] Employees.",\
- "Simply enter your [company_name] Bank account system number and pin. With three easy steps this service could be yours!")
+ "Wetskrell.nt only provides the higest quality of male entertaiment to [using_map.company_name] Employees.",\
+ "Simply enter your [using_map.company_name] Bank account system number and pin. With three easy steps this service could be yours!")
if(7)
sender = pick("You have won free tickets!","Click here to claim your prize!","You are the 1000th vistor!","You are our lucky grand prize winner!")
message = pick("You have won tickets to the newest ACTION JAXSON MOVIE!",\
diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm
index 7be0a5c3d27..b9435f25aa4 100644
--- a/code/modules/events/radiation_storm.dm
+++ b/code/modules/events/radiation_storm.dm
@@ -34,7 +34,7 @@
var/area/A = get_area(C)
if(!A)
continue
- if(!(A.z in config.station_levels))
+ if(!(A.z in using_map.station_levels))
continue
if(A.flags & RAD_SHIELDED)
continue
diff --git a/code/modules/events/rogue_drones.dm b/code/modules/events/rogue_drones.dm
index 42952f081e2..b597837d17b 100644
--- a/code/modules/events/rogue_drones.dm
+++ b/code/modules/events/rogue_drones.dm
@@ -16,7 +16,7 @@
else
num = rand(2,6)
for(var/i=0, i 50)
vents += temp_vent
diff --git a/code/modules/events/viral_infection.dm b/code/modules/events/viral_infection.dm
index c86a2eacad4..828233ea5fc 100644
--- a/code/modules/events/viral_infection.dm
+++ b/code/modules/events/viral_infection.dm
@@ -37,7 +37,7 @@ datum/event/viral_infection/start()
for(var/mob/living/carbon/human/G in player_list)
if(G.mind && G.stat != DEAD && G.is_client_active(5) && !player_is_antag(G.mind))
var/turf/T = get_turf(G)
- if(T.z in config.station_levels)
+ if(T.z in using_map.station_levels)
candidates += G
if(!candidates.len) return
candidates = shuffle(candidates)//Incorporating Donkie's list shuffle
diff --git a/code/modules/examine/descriptions/telecomms.dm b/code/modules/examine/descriptions/telecomms.dm
index 45101ec130b..9096a6b1a43 100644
--- a/code/modules/examine/descriptions/telecomms.dm
+++ b/code/modules/examine/descriptions/telecomms.dm
@@ -5,7 +5,7 @@
just your hands, due to the integrated monitor and keyboard. Synthetic units can interface with it as well, just like most other machines."
description_fluff = "This is one of many nodes that make up the Exonet, which services trillions of devices across space. This particular node \
- is referred to as a terminal node, servicing the "+station_orig+". \
+ is referred to as a terminal node, servicing the station. \
\
In the beginning of humanity's ascend into space, the Exonet didn't exist. Instead, the Exonet is the evolution to a network called the Interplanetary \
Internet (sometimes referred to as the InterPlaNet), which was conceived and developed due to the limitations of the terrestrial Internet, mainly because \
@@ -30,7 +30,7 @@
Exonets at the root node(s), and is typically arranged in a tree structure. The root node(s) are generally government-owned and are very secure \
and resilient to failure. \
\
- This node is privately owned and maintained by NanoTrasen, and allows the colonists of the "+station_orig+" to have access to the Exonet."
+ This node is privately owned and maintained by NanoTrasen, and allows the crew of the station to have access to the Exonet."
description_antag = "An EMP will disable this device for a short period of time. A longer downage can be achieved by turning it off, or rigging \
the APC it uses to turn off remotely, such as with a signaler in the right wire."
\ No newline at end of file
diff --git a/code/modules/food/recipe_dump.dm b/code/modules/food/recipe_dump.dm
new file mode 100644
index 00000000000..19f7988826f
--- /dev/null
+++ b/code/modules/food/recipe_dump.dm
@@ -0,0 +1,217 @@
+/client/proc/recipe_dump()
+ set name = "Generate Recipe Dump"
+ set category = "Server"
+ set desc = "Dumps food and drink recipe info and images for wiki or other use."
+
+ if(!holder)
+ return
+
+ //////////////////////// DRINK
+ var/list/drink_recipes = list()
+ for(var/path in typesof(/datum/chemical_reaction/drinks) - /datum/chemical_reaction/drinks)
+ var/datum/chemical_reaction/drinks/CR = new path()
+ drink_recipes[path] = list("Result" = CR.name,
+ "ResAmt" = CR.result_amount,
+ "Reagents" = CR.required_reagents)
+ qdel(CR)
+
+ //////////////////////// FOOD
+ var/list/food_recipes = typesof(/datum/recipe) - /datum/recipe
+ //Build a useful list
+ for(var/Rp in food_recipes)
+ //Lists don't work with datum-stealing no-instance initial() so we have to.
+ var/datum/recipe/R = new Rp()
+ var/obj/res = new R.result()
+
+ var/icon/result_icon = icon(res.icon,res.icon_state)
+ result_icon.Scale(64,64)
+
+ food_recipes[Rp] = list(
+ "Result" = "[res.name]",
+ "ResAmt" = "1",
+ "Reagents" = R.reagents,
+ "Fruit" = R.fruit,
+ "Ingredients" = R.items,
+ "Image" = result_icon
+ )
+
+ qdel(res)
+ qdel(R)
+
+ //////////////////////// FOOD+ (basically condiments, tofu, cheese, soysauce, etc)
+ for(var/path in typesof(/datum/chemical_reaction/food) - /datum/chemical_reaction/food)
+ var/datum/chemical_reaction/food/CR = new path()
+ food_recipes[path] = list("Result" = CR.name,
+ "ResAmt" = CR.result_amount,
+ "Reagents" = CR.required_reagents,
+ "Fruit" = list(),
+ "Ingredients" = list(),
+ "Image" = null)
+ qdel(CR)
+
+ //////////////////////// PROCESSING
+ //Items needs further processing into human-readability.
+ for(var/Rp in food_recipes)
+ var/working_ing_list = list()
+ for(var/I in food_recipes[Rp]["Ingredients"])
+ var/atom/ing = new I()
+
+ //So now we add something like "Bread" = 3
+ if(ing.name in working_ing_list)
+ var/sofar = working_ing_list[ing.name]
+ working_ing_list[ing.name] = sofar+1
+ else
+ working_ing_list[ing.name] = 1
+
+ food_recipes[Rp]["Ingredients"] = working_ing_list
+
+ //Reagents can be resolved to nicer names as well
+ for(var/Rp in food_recipes)
+ for(var/rid in food_recipes[Rp]["Reagents"])
+ var/datum/reagent/Rd = chemical_reagents_list[rid]
+ var/R_name = Rd.name
+ var/amt = food_recipes[Rp]["Reagents"][rid]
+ food_recipes[Rp]["Reagents"] -= rid
+ food_recipes[Rp]["Reagents"][R_name] = amt
+ for(var/Rp in drink_recipes)
+ for(var/rid in drink_recipes[Rp]["Reagents"])
+ var/datum/reagent/Rd = chemical_reagents_list[rid]
+ var/R_name = Rd.name
+ var/amt = drink_recipes[Rp]["Reagents"][rid]
+ drink_recipes[Rp]["Reagents"] -= rid
+ drink_recipes[Rp]["Reagents"][R_name] = amt
+
+ //////////////////////// SORTING
+ var/list/foods_to_paths = list()
+ var/list/drinks_to_paths = list()
+
+ for(var/Rp in food_recipes)
+ foods_to_paths["[food_recipes[Rp]["Result"]] [Rp]"] = Rp //Append recipe datum path to keep uniqueness
+ for(var/Rp in drink_recipes)
+ drinks_to_paths["[drink_recipes[Rp]["Result"]] [Rp]"] = Rp
+
+ foods_to_paths = sortAssoc(foods_to_paths)
+ drinks_to_paths = sortAssoc(drinks_to_paths)
+
+ var/list/foods_newly_sorted = list()
+ var/list/drinks_newly_sorted = list()
+
+ for(var/Rr in foods_to_paths)
+ var/Rp = foods_to_paths[Rr]
+ foods_newly_sorted[Rp] = food_recipes[Rp]
+ for(var/Rr in drinks_to_paths)
+ var/Rp = drinks_to_paths[Rr]
+ drinks_newly_sorted[Rp] = drink_recipes[Rp]
+
+ food_recipes = foods_newly_sorted
+ drink_recipes = drinks_newly_sorted
+
+ //////////////////////// OUTPUT
+ //Food Output
+ var/html = "\
+ \
+ \
+ \
+ \
+ Food Recipes\
+ \
+ "
+
+ html += "
Food Recipes (as of [time2text(world.realtime,"MMM DD, YYYY")])
"
+ html += "
"
+ html += "
Icon
Name
Ingredients
"
+ for(var/Rp in food_recipes)
+ //Open this row
+ html += "
"
+ var/count //For those commas. Not sure of a great other way to do it.
+ //For each large ingredient
+ var/pretty_ing = ""
+ count = 0
+ for(var/ing in food_recipes[Rp]["Ingredients"])
+ pretty_ing += "[count == 0 ? "" : ", "][food_recipes[Rp]["Ingredients"][ing]]x [ing]"
+ count++
+ if(pretty_ing != "")
+ html += "
Ingredients: [pretty_ing]
"
+
+ //For each fruit
+ var/pretty_fru = ""
+ count = 0
+ for(var/fru in food_recipes[Rp]["Fruit"])
+ pretty_fru += "[count == 0 ? "" : ", "][food_recipes[Rp]["Fruit"][fru]]x [fru]"
+ count++
+ if(pretty_fru != "")
+ html += "
"
+ src << browse(html, "window=recipes;file=recipes_drinks.html;display=0")
+
+ src << "In your byond cache, recipe-xxx.png files and recipes_drinks.html and recipes_food.html now exist. Place recipe-xxx.png files in a subfolder named 'imgrecipes' wherever you put them. The file will take a food.css or drinks.css file if in the same path."
diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm
index f181f187bea..756aab62e4c 100644
--- a/code/modules/food/recipes_microwave.dm
+++ b/code/modules/food/recipes_microwave.dm
@@ -621,8 +621,8 @@ I said no!
/datum/recipe/sandwich
items = list(
/obj/item/weapon/reagent_containers/food/snacks/meatsteak,
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
/obj/item/weapon/reagent_containers/food/snacks/cheesewedge,
)
result = /obj/item/weapon/reagent_containers/food/snacks/sandwich
@@ -635,8 +635,8 @@ I said no!
/datum/recipe/grilledcheese
items = list(
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
/obj/item/weapon/reagent_containers/food/snacks/cheesewedge,
)
result = /obj/item/weapon/reagent_containers/food/snacks/grilledcheese
@@ -663,14 +663,14 @@ I said no!
/datum/recipe/slimetoast
reagents = list("slimejelly" = 5)
items = list(
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
)
result = /obj/item/weapon/reagent_containers/food/snacks/jelliedtoast/slime
/datum/recipe/jelliedtoast
reagents = list("cherryjelly" = 5)
items = list(
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
)
result = /obj/item/weapon/reagent_containers/food/snacks/jelliedtoast/cherry
@@ -783,24 +783,24 @@ I said no!
/datum/recipe/twobread
reagents = list("wine" = 5)
items = list(
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
)
result = /obj/item/weapon/reagent_containers/food/snacks/twobread
/datum/recipe/slimesandwich
reagents = list("slimejelly" = 5)
items = list(
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
)
result = /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/slime
/datum/recipe/cherrysandwich
reagents = list("cherryjelly" = 5)
items = list(
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
- /obj/item/weapon/reagent_containers/food/snacks/breadslice,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/bread,
)
result = /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/cherry
diff --git a/code/modules/gamemaster/actions/action.dm b/code/modules/gamemaster/actions/action.dm
index 82ebd860b59..aa259ccc033 100644
--- a/code/modules/gamemaster/actions/action.dm
+++ b/code/modules/gamemaster/actions/action.dm
@@ -5,12 +5,9 @@
var/chaotic = 0 // A number showing how chaotic the action may be. If danger is high, the GM will avoid it.
var/reusable = FALSE // If true, the event does not become disabled upon being used. Should be used sparingly.
var/observers_used = FALSE // Determines if the GM should check if ghosts are available before using this.
+ var/length = 0 // Determines how long the event lasts, until end() is called.
var/datum/game_master/gm = null
-/datum/gm_action/New(var/datum/game_master/new_gm)
- ..()
- gm = new_gm
-
/datum/gm_action/proc/set_up()
return
diff --git a/code/modules/gamemaster/actions/canister_leak.dm b/code/modules/gamemaster/actions/canister_leak.dm
new file mode 100644
index 00000000000..a294f957361
--- /dev/null
+++ b/code/modules/gamemaster/actions/canister_leak.dm
@@ -0,0 +1,24 @@
+//
+// This event chooses a random canister on player levels and breaks it, releasing its contents!
+//
+
+/datum/gm_action/canister_leak
+ name = "Canister Leak"
+ departments = list(ROLE_ENGINEERING)
+ chaotic = 20
+
+/datum/gm_action/canister_leak/get_weight()
+ return metric.count_people_in_department(ROLE_ENGINEERING) * 30
+
+/datum/gm_action/canister_leak/start()
+ ..()
+ // List of all non-destroyed canisters on station levels
+ var/list/all_canisters = list()
+ for(var/obj/machinery/portable_atmospherics/canister/C in machines)
+ if(!C.destroyed && (C.z in using_map.station_levels) && C.air_contents.total_moles >= MOLES_CELLSTANDARD)
+ all_canisters += C
+ var/obj/machinery/portable_atmospherics/canister/C = pick(all_canisters)
+ log_debug("canister_leak event: Canister [C] ([C.x],[C.y],[C.z]) destroyed.")
+ C.health = 0
+ C.healthcheck()
+ return
diff --git a/code/modules/gamemaster/actions/carp_migration.dm b/code/modules/gamemaster/actions/carp_migration.dm
new file mode 100644
index 00000000000..7c76a5119c8
--- /dev/null
+++ b/code/modules/gamemaster/actions/carp_migration.dm
@@ -0,0 +1,65 @@
+//carp_migration
+/datum/gm_action/carp_migration
+ name = "carp migration"
+ departments = list(ROLE_SECURITY, ROLE_EVERYONE)
+ chaotic = 50
+ var/list/spawned_carp = list()
+ var/carp_amount = 0
+ length = 20 MINUTES
+
+/datum/gm_action/carp_migration/get_weight()
+ var/people_in_space = 0
+ for(var/mob/living/L in player_list)
+ if(!(L.z in using_map.station_levels))
+ continue // Not on the right z-level.
+ var/turf/T = get_turf(L)
+ if(istype(T, /turf/space) && istype(T.loc,/area/space))
+ people_in_space++
+ return 50 + (metric.count_people_in_department(ROLE_SECURITY) * 10) + (people_in_space * 20)
+
+/datum/gm_action/carp_migration/announce()
+ var/announcement = "Unknown biological entities have been detected near [station_name()], please stand-by."
+ command_announcement.Announce(announcement, "Lifesign Alert")
+
+/datum/gm_action/carp_migration/set_up()
+ // Higher filled roles means more groups of fish.
+ var/station_strength = 0
+ station_strength += (metric.count_people_in_department(ROLE_SECURITY) * 3)
+ station_strength += (metric.count_people_in_department(ROLE_ENGINEERING) * 2)
+ station_strength += metric.count_people_in_department(ROLE_MEDICAL)
+
+ // Less active emergency response departments tones the event down.
+ var/activeness = ((metric.assess_department(ROLE_SECURITY) + metric.assess_department(ROLE_ENGINEERING) + metric.assess_department(ROLE_MEDICAL)) / 3)
+ activeness = max(activeness, 20)
+
+ carp_amount = Ceiling(station_strength * (activeness / 100) + 1)
+
+/datum/gm_action/carp_migration/start()
+ ..()
+ var/list/spawn_locations = list()
+
+ var/group_size_min = 3
+ var/group_size_max = 5
+
+ for(var/obj/effect/landmark/C in landmarks_list)
+ if(C.name == "carpspawn")
+ spawn_locations.Add(C.loc)
+
+ spawn_locations = shuffle(spawn_locations)
+ carp_amount = min(carp_amount, spawn_locations.len)
+
+ var/i = 1
+ while (i <= carp_amount)
+ var/group_size = rand(group_size_min, group_size_max)
+ for (var/j = 1, j <= group_size, j++)
+ spawned_carp.Add(new /mob/living/simple_animal/hostile/carp(spawn_locations[i]))
+ i++
+ message_admins("[spawned_carp.len] carp spawned by event.")
+
+/datum/gm_action/carp_migration/end()
+ for(var/mob/living/simple_animal/hostile/carp/C in spawned_carp)
+ if(!C.stat)
+ var/turf/T = get_turf(C)
+ if(istype(T, /turf/space))
+ if(!prob(25))
+ qdel(C)
\ No newline at end of file
diff --git a/code/modules/gamemaster/actions/comms_blackout.dm b/code/modules/gamemaster/actions/comms_blackout.dm
index 75359085ac9..71b172b1536 100644
--- a/code/modules/gamemaster/actions/comms_blackout.dm
+++ b/code/modules/gamemaster/actions/comms_blackout.dm
@@ -1,9 +1,21 @@
-// Comms blackout is, just like grid check, mostly the same as always, yet engineering has an option to get it back sooner.
-
/datum/gm_action/comms_blackout
name = "communications blackout"
departments = list(ROLE_ENGINEERING, ROLE_EVERYONE)
chaotic = 35
/datum/gm_action/comms_blackout/get_weight()
- return 50 + (metric.count_people_in_department(ROLE_ENGINEERING) * 40)
\ No newline at end of file
+ return 50 + (metric.count_people_in_department(ROLE_ENGINEERING) * 40)
+
+/datum/gm_action/comms_blackout/announce()
+ if(prob(33))
+ command_announcement.Announce("Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT", new_sound = 'sound/misc/interference.ogg')
+ // AIs will always know if there's a comm blackout, rogue AIs could then lie about comm blackouts in the future while they shutdown comms
+ for(var/mob/living/silicon/ai/A in player_list)
+ A << " "
+ A << "Ionospheric anomalies detected. Temporary telecommunication failure imminent. Please contact you-BZZT"
+ A << " "
+
+/datum/gm_action/comms_blackout/start()
+ ..()
+ for(var/obj/machinery/telecomms/T in telecomms_list)
+ T.emp_act(1)
diff --git a/code/modules/gamemaster/actions/dust.dm b/code/modules/gamemaster/actions/dust.dm
new file mode 100644
index 00000000000..caecc514456
--- /dev/null
+++ b/code/modules/gamemaster/actions/dust.dm
@@ -0,0 +1,17 @@
+/datum/gm_action/dust
+ name = "dust"
+ departments = list(ROLE_ENGINEERING)
+ chaotic = 10
+ reusable = TRUE
+
+/datum/gm_action/dust/announce()
+ command_announcement.Announce("Debris resulting from activity on another nearby asteroid is approaching your colony.", "Dust Alert")
+
+/datum/gm_action/dust/get_weight()
+ var/engineers = metric.count_people_in_department(ROLE_ENGINEERING)
+ var/weight = 30 + (engineers * 25)
+ return weight
+
+/datum/gm_action/dust/start()
+ ..()
+ dust_swarm("norm")
\ No newline at end of file
diff --git a/code/modules/gamemaster/actions/grid_check.dm b/code/modules/gamemaster/actions/grid_check.dm
index 08c817fdf9b..dcf35a230fc 100644
--- a/code/modules/gamemaster/actions/grid_check.dm
+++ b/code/modules/gamemaster/actions/grid_check.dm
@@ -13,6 +13,7 @@
return 50 + (metric.count_people_in_department(ROLE_ENGINEERING) * 30)
/datum/gm_action/grid_check/start()
+ ..()
// This sets off a chain of events that lead to the actual grid check (or perhaps worse).
// First, the Supermatter engine makes a power spike.
for(var/obj/machinery/power/generator/engine in machines)
diff --git a/code/modules/gamemaster/actions/meteor_defense.dm b/code/modules/gamemaster/actions/meteor_defense.dm
new file mode 100644
index 00000000000..1bae723b005
--- /dev/null
+++ b/code/modules/gamemaster/actions/meteor_defense.dm
@@ -0,0 +1,51 @@
+// This event gives the station an advance warning about meteors, so that they can prepare in various ways.
+
+/datum/gm_action/meteor_defense
+ name = "meteor defense"
+ departments = list(ROLE_ENGINEERING)
+ chaotic = 50
+ var/direction = null
+ var/dir_text = null
+ var/waves = 0
+
+/datum/gm_action/meteor_defense/get_weight()
+ var/engineers = metric.count_people_in_department(ROLE_ENGINEERING)
+ var/weight = (max(engineers - 1, 0) * 25) // If only one engineer exists, no meteors for now.
+ return weight
+
+/datum/gm_action/meteor_defense/set_up()
+ direction = pick(cardinal) // alldirs doesn't work with current meteor code unfortunately.
+ waves = rand(5, 8)
+ switch(direction)
+ if(NORTH)
+ dir_text = "aft" // For some reason this is needed.
+ if(SOUTH)
+ dir_text = "fore"
+ if(EAST)
+ dir_text = "port"
+ if(WEST)
+ dir_text = "starboard"
+
+/datum/gm_action/meteor_defense/announce()
+ var/announcement = "Alert! Two other asteroids have collided near [station_name()]. Chunks of it are expected to approach from the [dir_text] side. ETA to arrival is \
+ approximately 10 minutes."
+ command_announcement.Announce(announcement, "Meteor Alert", new_sound = 'sound/AI/meteors.ogg')
+
+/datum/gm_action/meteor_defense/start()
+ ..()
+ spawn(0)
+ // sleep(5 MINUTES)
+ var/announcement = "The incoming debris are expected to approach from the [dir_text] side. ETA to arrival is approximately 5 minutes."
+ command_announcement.Announce(announcement, "Meteor Alert - Update")
+ // sleep(5 MINUTES)
+ announcement = "Incoming debris approaches from the [dir_text] side!"
+ command_announcement.Announce(announcement, "Meteor Alert - Update")
+ while(waves)
+ message_admins("[waves] more wave\s of meteors remain.")
+ spawn(1) // Dir is reversed because the direction describes where meteors are going, not what side it's gonna hit.
+ spawn_meteors(rand(8, 12), meteors_threatening, reverse_dir[direction])
+ waves--
+ sleep(30 SECONDS)
+ announcement = "The colony has cleared the incoming debris."
+ command_announcement.Announce(announcement, "Meteor Alert - Update")
+ message_admins("Meteor defense event has ended.")
\ No newline at end of file
diff --git a/code/modules/gamemaster/actions/shipping_error.dm b/code/modules/gamemaster/actions/shipping_error.dm
new file mode 100644
index 00000000000..affbe94dc9d
--- /dev/null
+++ b/code/modules/gamemaster/actions/shipping_error.dm
@@ -0,0 +1,17 @@
+/datum/gm_action/shipping_error
+ name = "shipping error"
+ departments = list(ROLE_CARGO)
+ reusable = TRUE
+
+/datum/gm_action/shipping_error/get_weight()
+ var/cargo = metric.count_people_in_department(ROLE_CARGO)
+ var/weight = (cargo * 40)
+ return weight
+
+/datum/gm_action/shipping_error/start()
+ ..()
+ var/datum/supply_order/O = new /datum/supply_order()
+ O.ordernum = supply_controller.ordernum
+ O.object = supply_controller.supply_packs[pick(supply_controller.supply_packs)]
+ O.orderedby = random_name(pick(MALE,FEMALE), species = "Human")
+ supply_controller.shoppinglist += O
\ No newline at end of file
diff --git a/code/modules/gamemaster/actions/surprise_carp_attack.dm b/code/modules/gamemaster/actions/surprise_carp_attack.dm
new file mode 100644
index 00000000000..e78dd72343b
--- /dev/null
+++ b/code/modules/gamemaster/actions/surprise_carp_attack.dm
@@ -0,0 +1,53 @@
+// This event sends a few carp after someone in space.
+
+/datum/gm_action/surprise_carp_attack
+ name = "surprise carp attack"
+ departments = list(ROLE_EVERYONE)
+ reusable = TRUE
+ chaotic = 10
+ var/mob/living/victim = null
+
+/datum/gm_action/surprise_carp_attack/get_weight()
+ var/people_in_space = 0
+ for(var/mob/living/L in player_list)
+ if(!(L.z in using_map.station_levels))
+ continue // Not on the right z-level.
+ var/turf/T = get_turf(L)
+ if(istype(T, /turf/space) && istype(T.loc,/area/space))
+ people_in_space++
+ return people_in_space * 50
+
+/datum/gm_action/surprise_carp_attack/set_up()
+ var/list/potential_victims = list()
+ victim = null
+ for(var/mob/living/L in player_list)
+ if(!(L.z in using_map.station_levels))
+ continue // Not on the right z-level.
+ if(L.stat)
+ continue // Don't want dead people.
+ var/turf/T = get_turf(L)
+ if(istype(T, /turf/space) && istype(T.loc,/area/space))
+ potential_victims.Add(L)
+ victim = pick(potential_victims)
+
+
+/datum/gm_action/surprise_carp_attack/start()
+ ..()
+ if(!victim)
+ message_admins("Surprise carp attack failed to find a target.")
+ return
+ var/number_of_carp = rand(1, 2)
+ message_admins("Sending [number_of_carp] carp\s after [victim].")
+ while(number_of_carp)
+ var/turf/spawning_turf = null
+ var/list/nearby_things = oview(10, victim)
+ for(var/turf/space/space in nearby_things)
+ if(get_dist(space, victim) <= 7)
+ continue
+ spawning_turf = space
+ break
+ if(spawning_turf)
+ var/mob/living/simple_animal/hostile/carp/C = new(spawning_turf)
+ C.target_mob = victim
+ C.stance = STANCE_ATTACK
+ number_of_carp--
\ No newline at end of file
diff --git a/code/modules/gamemaster/actions/surprise_meteor.dm b/code/modules/gamemaster/actions/surprise_meteor.dm
new file mode 100644
index 00000000000..682a8287a6d
--- /dev/null
+++ b/code/modules/gamemaster/actions/surprise_meteor.dm
@@ -0,0 +1,17 @@
+// This event sends one wave of meteors unannounced.
+
+/datum/gm_action/surprise_meteors
+ name = "surprise meteors"
+ departments = list(ROLE_ENGINEERING)
+ chaotic = 25
+
+/datum/gm_action/surprise_meteors/get_weight()
+ var/engineers = metric.count_people_in_department(ROLE_ENGINEERING)
+ var/weight = (max(engineers - 1, 0) * 25) // If only one engineer exists, no meteors for now.
+ return weight
+
+/datum/gm_action/surprise_meteors/start()
+ ..()
+ spawn(1)
+ spawn_meteors(rand(4, 8), meteors_normal, pick(cardinal))
+ message_admins("Surprise meteors event has ended.")
\ No newline at end of file
diff --git a/code/modules/gamemaster/controller.dm b/code/modules/gamemaster/controller.dm
index 079c5351644..343f05842d1 100644
--- a/code/modules/gamemaster/controller.dm
+++ b/code/modules/gamemaster/controller.dm
@@ -24,7 +24,7 @@
for(var/datum/gm_action/action in available_actions)
if(action.enabled == FALSE)
continue
- HTML += "[action.name] ([english_list(action.departments)]) (weight: [action.get_weight()]) "
+ HTML += "[action.name] ([english_list(action.departments)]) (weight: [action.get_weight()]) \[Force\] "
HTML += " "
HTML += "All living mobs activity: [metric.assess_all_living_mobs()]% "
@@ -77,4 +77,16 @@
adjust_danger(amount)
message_admins("GM danger was adjusted by [amount] by [usr.key].")
- interact(usr) // To refresh the UI.
\ No newline at end of file
+ interact(usr) // To refresh the UI.
+
+/datum/gm_action/Topic(href, href_list)
+ if(..())
+ return
+
+ if(!is_admin(usr))
+ message_admins("[usr] has attempted to force an event without being an admin.")
+ return
+
+ if(href_list["force"])
+ gm.run_action(src)
+ message_admins("GM event [name] was forced by [usr.key].")
\ No newline at end of file
diff --git a/code/modules/gamemaster/game_master.dm b/code/modules/gamemaster/game_master.dm
index 180892f4c98..c435e868f6b 100644
--- a/code/modules/gamemaster/game_master.dm
+++ b/code/modules/gamemaster/game_master.dm
@@ -19,6 +19,8 @@
/datum/game_master/New()
..()
available_actions = init_subtypes(/datum/gm_action)
+ for(var/datum/gm_action/action in available_actions)
+ action.gm = src
/datum/game_master/proc/process()
if(ticker && ticker.current_state == GAME_STATE_PLAYING && !suspended)
@@ -68,17 +70,26 @@
if(best_actions && best_actions.len)
var/list/weighted_actions = list()
for(var/datum/gm_action/action in best_actions)
+ if(action.chaotic > danger)
+ continue // We skip dangerous events when bad stuff is already occuring.
weighted_actions[action] = action.get_weight()
var/datum/gm_action/choice = pickweight(weighted_actions)
if(choice)
log_debug("[choice.name] was chosen by the Game Master, and is now being ran.")
- choice.set_up()
- choice.start()
- next_action = world.time + rand(15 MINUTES, 30 MINUTES)
- last_department_used = choice.departments[1]
-
+ run_action(choice)
+/datum/game_master/proc/run_action(var/datum/gm_action/action)
+ action.set_up()
+ action.start()
+ action.announce()
+ if(action.chaotic)
+ danger += action.chaotic
+ if(action.length)
+ spawn(action.length)
+ action.end()
+ next_action = world.time + rand(15 MINUTES, 30 MINUTES)
+ last_department_used = action.departments[1]
/datum/game_master/proc/decide_best_action(var/list/most_active_departments)
diff --git a/code/modules/games/spaceball_cards.dm b/code/modules/games/spaceball_cards.dm
index 9488192a72a..57a28fa1a2b 100644
--- a/code/modules/games/spaceball_cards.dm
+++ b/code/modules/games/spaceball_cards.dm
@@ -16,7 +16,7 @@
else
var/language_type = pick(/datum/language/human,/datum/language/diona_local,/datum/language/tajaran,/datum/language/unathi)
var/datum/language/L = new language_type()
- var/team = pick("Brickburn Galaxy Trekers","Mars Rovers", "Qerrbalak Saints", "Moghes Rockets", "Meralar Lightning", starsys_name+" Vixens", "Euphoric-Earth Alligators")
+ var/team = pick("Brickburn Galaxy Trekers","Mars Rovers", "Qerrbalak Saints", "Moghes Rockets", "Meralar Lightning", "[using_map.starsys_name] Vixens", "Euphoric-Earth Alligators")
P.name = "[L.get_random_name(pick(MALE,FEMALE))], [year - rand(0,50)] [team]"
P.card_icon = "spaceball_standard"
P.back_icon = "card_back_spaceball"
diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm
index 1bc0c721c72..eb18581551b 100644
--- a/code/modules/holodeck/HolodeckControl.dm
+++ b/code/modules/holodeck/HolodeckControl.dm
@@ -128,7 +128,7 @@
safety_disabled = 1
update_projections()
user << "You vastly increase projector power and override the safety and security protocols."
- user << "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call [company_name] maintenance and do not use the simulator."
+ user << "Warning. Automatic shutoff and derezing protocols have been corrupted. Please call [using_map.company_name] maintenance and do not use the simulator."
log_game("[key_name(usr)] emagged the Holodeck Control Computer")
return 1
return
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index edc796594c3..ece606a3890 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -323,8 +323,9 @@
if(!reagents || reagents.total_volume <= 0)
return
reagents.remove_any(rand(1,3)) //Todo, make it actually remove the reagents the seed uses.
- seed.do_thorns(H,src)
- seed.do_sting(H,src,pick("r_hand","l_hand"))
+ var/affected = pick("r_hand","l_hand")
+ seed.do_thorns(H,src,affected)
+ seed.do_sting(H,src,affected)
// Predefined types for placing on the map.
diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm
index 9115fea2446..f6388e0190e 100644
--- a/code/modules/hydroponics/seed.dm
+++ b/code/modules/hydroponics/seed.dm
@@ -112,34 +112,32 @@
qdel(target)
return
-
if(!target_limb) target_limb = pick(BP_ALL)
+ var/blocked = target.run_armor_check(target_limb, "melee")
+ if(blocked >= 100)
+ return
var/obj/item/organ/external/affecting = target.get_organ(target_limb)
var/damage = 0
+ var/has_edge = 0
+ if(get_trait(TRAIT_CARNIVOROUS) >= 2)
+ damage = max(5, round(15*get_trait(TRAIT_POTENCY)/100, 1))
+ has_edge = prob(get_trait(TRAIT_POTENCY)/2)
- if(get_trait(TRAIT_CARNIVOROUS))
- if(get_trait(TRAIT_CARNIVOROUS) == 2)
- if(affecting)
- target << "\The [fruit]'s thorns pierce your [affecting.name] greedily!"
- else
- target << "\The [fruit]'s thorns pierce your flesh greedily!"
- damage = get_trait(TRAIT_POTENCY)/2
+ if(affecting)
+ to_chat(target, "\The [fruit]'s thorns pierce your [affecting.name] greedily!")
+ target.apply_damage(damage, BRUTE, target_limb, blocked, "Thorns", sharp=1, edge=has_edge)
else
- if(affecting)
- target << "\The [fruit]'s thorns dig deeply into your [affecting.name]!"
- else
- target << "\The [fruit]'s thorns dig deeply into your flesh!"
- damage = get_trait(TRAIT_POTENCY)/5
+ to_chat(target, "\The [fruit]'s thorns pierce your flesh greedily!")
+ target.adjustBruteLoss(damage)
else
- return
-
- if(affecting)
- affecting.take_damage(damage, 0)
- affecting.add_autopsy_data("Thorns",damage)
- else
- target.adjustBruteLoss(damage)
- target.UpdateDamageIcon()
- target.updatehealth()
+ damage = max(1, round(5*get_trait(TRAIT_POTENCY)/100, 1))
+ has_edge = prob(get_trait(TRAIT_POTENCY)/5)
+ if(affecting)
+ to_chat(target, "\The [fruit]'s thorns dig deeply into your [affecting.name]!")
+ target.apply_damage(damage, BRUTE, target_limb, blocked, "Thorns", sharp=1, edge=has_edge)
+ else
+ to_chat(target, "\The [fruit]'s thorns dig deeply into your flesh!")
+ target.adjustBruteLoss(damage)
// Adds reagents to a target.
/datum/seed/proc/do_sting(var/mob/living/carbon/human/target, var/obj/item/fruit)
@@ -152,7 +150,8 @@
for(var/obj/item/clothing/clothes in target)
if(target.item_is_in_hands(clothes))
continue
- body_coverage &= ~(clothes.body_parts_covered)
+ if(clothes.item_flags & THICKMATERIAL)
+ body_coverage &= ~(clothes.body_parts_covered)
if(!body_coverage)
return
diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm
index e8881a5dc72..e4a1237f2b0 100644
--- a/code/modules/hydroponics/seed_datums.dm
+++ b/code/modules/hydroponics/seed_datums.dm
@@ -184,7 +184,7 @@
display_name = "killer tomato plant"
mutants = null
can_self_harvest = 1
- has_mob_product = /mob/living/simple_animal/tomato
+ has_mob_product = /mob/living/simple_animal/hostile/tomato
/datum/seed/tomato/killer/New()
..()
diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm
index 6961513b209..48d2c542dd1 100644
--- a/code/modules/hydroponics/spreading/spreading.dm
+++ b/code/modules/hydroponics/spreading/spreading.dm
@@ -16,6 +16,7 @@
seed.set_trait(TRAIT_SPREAD,2) // So it will function properly as vines.
seed.set_trait(TRAIT_POTENCY,rand(potency_min, potency_max)) // 70-100 potency will help guarantee a wide spread and powerful effects.
seed.set_trait(TRAIT_MATURATION,rand(maturation_min, maturation_max))
+ seed.display_name = "strange plants" //more thematic for the vine infestation event
//make vine zero start off fully matured
var/obj/effect/plant/vine = new(T,seed)
@@ -45,6 +46,7 @@
/obj/effect/plant
name = "plant"
anchored = 1
+ can_buckle = 1
opacity = 0
density = 0
icon = 'icons/obj/hydroponics_growing.dmi'
@@ -88,7 +90,7 @@
parent = newparent
if(!plant_controller)
- sleep(250) // ugly hack, should mean roundstart plants are fine.
+ sleep(250) // ugly hack, should mean roundstart plants are fine. TODO initialize perhaps?
if(!plant_controller)
world << "Plant controller does not exist and [src] requires it. Aborting."
qdel(src)
@@ -108,7 +110,7 @@
growth_threshold = max_health/VINE_GROWTH_STAGES
icon = 'icons/obj/hydroponics_vines.dmi'
growth_type = 2 // Vines by default.
- if(seed.get_trait(TRAIT_CARNIVOROUS) == 2)
+ if(seed.get_trait(TRAIT_CARNIVOROUS) >= 2)
growth_type = 1 // WOOOORMS.
else if(!(seed.seed_noun in list("seeds","pits")))
if(seed.seed_noun == "nodes")
@@ -127,14 +129,15 @@
spread_distance = ((growth_type>0) ? round(spread_chance*0.6) : round(spread_chance*0.3))
update_icon()
- spawn(1) // Plants will sometimes be spawned in the turf adjacent to the one they need to end up in, for the sake of correct dir/etc being set.
- set_dir(calc_dir())
- update_icon()
- plant_controller.add_plant(src)
- // Some plants eat through plating.
- if(!isnull(seed.chems["pacid"]))
- var/turf/T = get_turf(src)
- T.ex_act(prob(80) ? 3 : 2)
+// Plants will sometimes be spawned in the turf adjacent to the one they need to end up in, for the sake of correct dir/etc being set.
+/obj/effect/plant/proc/finish_spreading()
+ set_dir(calc_dir())
+ update_icon()
+ plant_controller.add_plant(src)
+ //Some plants eat through plating.
+ if(islist(seed.chems) && !isnull(seed.chems["pacid"]))
+ var/turf/T = get_turf(src)
+ T.ex_act(prob(80) ? 3 : 2)
/obj/effect/plant/update_icon()
//TODO: should really be caching this.
@@ -261,6 +264,32 @@
health -= W.force
check_health()
+//handles being overrun by vines - note that attacker_parent may be null in some cases
+/obj/effect/plant/proc/vine_overrun(datum/seed/attacker_seed, obj/effect/plant/attacker_parent)
+ var/aggression = 0
+ aggression += (attacker_seed.get_trait(TRAIT_CARNIVOROUS) - seed.get_trait(TRAIT_CARNIVOROUS))
+ aggression += (attacker_seed.get_trait(TRAIT_SPREAD) - seed.get_trait(TRAIT_SPREAD))
+
+ var/resiliance
+ if(is_mature())
+ resiliance = 0
+ switch(seed.get_trait(TRAIT_ENDURANCE))
+ if(30 to 70)
+ resiliance = 1
+ if(70 to 95)
+ resiliance = 2
+ if(95 to INFINITY)
+ resiliance = 3
+ else
+ resiliance = -2
+ if(seed.get_trait(TRAIT_ENDURANCE) >= 50)
+ resiliance = -1
+ aggression -= resiliance
+
+ if(aggression > 0)
+ health -= aggression*5
+ check_health()
+
/obj/effect/plant/ex_act(severity)
switch(severity)
if(1.0)
diff --git a/code/modules/hydroponics/spreading/spreading_growth.dm b/code/modules/hydroponics/spreading/spreading_growth.dm
index 0b8ead04763..fca9f3abafe 100644
--- a/code/modules/hydroponics/spreading/spreading_growth.dm
+++ b/code/modules/hydroponics/spreading/spreading_growth.dm
@@ -14,19 +14,32 @@
for(var/turf/simulated/floor in get_cardinal_neighbors())
if(get_dist(parent, floor) > spread_distance)
continue
- if((locate(/obj/effect/plant) in floor.contents) || (locate(/obj/effect/dead_plant) in floor.contents) )
+
+ var/blocked = 0
+ for(var/obj/effect/plant/other in floor.contents)
+ if(other.seed == src.seed)
+ blocked = 1
+ break
+ if(blocked)
continue
+
if(floor.density)
if(!isnull(seed.chems["pacid"]))
spawn(rand(5,25)) floor.ex_act(3)
continue
+
if(!Adjacent(floor) || !floor.Enter(src))
continue
neighbors |= floor
+
+ if(neighbors.len)
+ plant_controller.add_plant(src) //if we have neighbours again, start processing
+
// Update all of our friends.
var/turf/T = get_turf(src)
for(var/obj/effect/plant/neighbor in range(1,src))
- neighbor.neighbors -= T
+ if(neighbor.seed == src.seed)
+ neighbor.neighbors -= T
/obj/effect/plant/process()
@@ -71,33 +84,71 @@
if(sampled)
//Should be between 2-7 for given the default range of values for TRAIT_PRODUCTION
- var/chance = max(1, round(30/seed.get_trait(TRAIT_PRODUCTION)))
+ var/chance = max(1, round(15/seed.get_trait(TRAIT_PRODUCTION)))
if(prob(chance))
sampled = 0
+ if(is_mature() && !buckled_mob)
+ for(var/turf/neighbor in neighbors)
+ for(var/mob/living/M in neighbor)
+ if(seed.get_trait(TRAIT_SPREAD) >= 2 && (M.lying || prob(round(seed.get_trait(TRAIT_POTENCY)))))
+ entangle(M)
+
if(is_mature() && neighbors.len && prob(spread_chance))
//spread to 1-3 adjacent turfs depending on yield trait.
var/max_spread = between(1, round(seed.get_trait(TRAIT_YIELD)*3/14), 3)
-
+
for(var/i in 1 to max_spread)
if(prob(spread_chance))
sleep(rand(3,5))
if(!neighbors.len)
break
- var/turf/target_turf = pick(neighbors)
- var/obj/effect/plant/child = new(get_turf(src),seed,parent)
- spawn(1) // This should do a little bit of animation.
- child.loc = target_turf
- child.update_icon()
- // Update neighboring squares.
- for(var/obj/effect/plant/neighbor in range(1,target_turf))
- neighbor.neighbors -= target_turf
+ spread_to(pick(neighbors))
// We shouldn't have spawned if the controller doesn't exist.
check_health()
- if(neighbors.len || health != max_health)
+ if(buckled_mob || neighbors.len)
plant_controller.add_plant(src)
+//spreading vines aren't created on their final turf.
+//Instead, they are created at their parent and then move to their destination.
+/obj/effect/plant/proc/spread_to(turf/target_turf)
+ var/obj/effect/plant/child = new(get_turf(src),seed,parent)
+
+ spawn(1) // This should do a little bit of animation.
+ if(deleted(child))
+ return
+
+ //move out to the destination
+ child.anchored = 0
+ step_to(child, target_turf)
+ child.anchored = 1
+ child.update_icon()
+
+ //see if anything is there
+ for(var/thing in child.loc)
+ if(thing != child && istype(thing, /obj/effect/plant))
+ var/obj/effect/plant/other = thing
+ if(other.seed != child.seed)
+ other.vine_overrun(child.seed, src) //vine fight
+ qdel(child)
+ return
+ if(istype(thing, /obj/effect/dead_plant))
+ qdel(thing)
+ qdel(child)
+ return
+ if(isliving(thing) && (seed.get_trait(TRAIT_CARNIVOROUS) || (seed.get_trait(TRAIT_SPREAD) >= 2 && prob(round(seed.get_trait(TRAIT_POTENCY))))))
+ entangle(thing)
+ qdel(child)
+ return
+
+ // Update neighboring squares.
+ for(var/obj/effect/plant/neighbor in range(1, child.loc)) //can use the actual final child loc now
+ if(child.seed == neighbor.seed) //neighbors of different seeds will continue to try to overrun each other
+ neighbor.neighbors -= target_turf
+
+ child.finish_spreading()
+
/obj/effect/plant/proc/die_off()
// Kill off our plant.
if(plant) plant.die()
diff --git a/code/modules/hydroponics/spreading/spreading_response.dm b/code/modules/hydroponics/spreading/spreading_response.dm
index 2b9407aecd0..80d72055eba 100644
--- a/code/modules/hydroponics/spreading/spreading_response.dm
+++ b/code/modules/hydroponics/spreading/spreading_response.dm
@@ -7,7 +7,7 @@
if(!istype(M))
return
- if(!buckled_mob && !M.buckled && !M.anchored && (issmall(M) || prob(round(seed.get_trait(TRAIT_POTENCY)/6))))
+ if(!buckled_mob && !M.buckled && !M.anchored && (issmall(M) || prob(round(seed.get_trait(TRAIT_POTENCY)/3))))
//wait a tick for the Entered() proc that called HasProximity() to finish (and thus the moving animation),
//so we don't appear to teleport from two tiles away when moving into a turf adjacent to vines.
spawn(1)
@@ -19,10 +19,16 @@
/obj/effect/plant/attack_generic(var/mob/user)
manual_unbuckle(user)
+/obj/effect/plant/Crossed(atom/movable/O)
+ if(isliving(O))
+ trodden_on(O)
+
/obj/effect/plant/proc/trodden_on(var/mob/living/victim)
if(!is_mature())
return
var/mob/living/carbon/human/H = victim
+ if(prob(round(seed.get_trait(TRAIT_POTENCY)/3)))
+ entangle(victim)
if(istype(H) && H.shoes)
return
seed.do_thorns(victim,src)
@@ -39,37 +45,42 @@
/obj/effect/plant/proc/manual_unbuckle(mob/user as mob)
if(buckled_mob)
- if(prob(seed ? min(max(0,100 - seed.get_trait(TRAIT_POTENCY)/2),100) : 50))
- if(buckled_mob.buckled == src)
- if(buckled_mob != user)
- buckled_mob.visible_message(\
- "[user.name] frees [buckled_mob.name] from \the [src].",\
- "[user.name] frees you from \the [src].",\
- "You hear shredding and ripping.")
- else
- buckled_mob.visible_message(\
- "[buckled_mob.name] struggles free of \the [src].",\
- "You untangle \the [src] from around yourself.",\
- "You hear shredding and ripping.")
+ var/chance = 20
+ if(seed)
+ chance = round(100/(20*seed.get_trait(TRAIT_POTENCY)/100))
+ if(prob(chance))
+ if(buckled_mob != user)
+ buckled_mob.visible_message(\
+ "\The [user] frees \the [buckled_mob] from \the [src].",\
+ "\The [user] frees you from \the [src].",\
+ "You hear shredding and ripping.")
+ else
+ buckled_mob.visible_message(\
+ "\The [buckled_mob] struggles free of \the [src].",\
+ "You untangle \the [src] from around yourself.",\
+ "You hear shredding and ripping.")
unbuckle()
else
- var/text = pick("rip","tear","pull")
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ health -= rand(1,5)
+ var/text = pick("rip","tear","pull", "bite", "tug")
user.visible_message(\
- "[user.name] [text]s at \the [src].",\
- "You [text] at \the [src].",\
- "You hear shredding and ripping.")
- return
+ "\The [user] [text]s at \the [src].",\
+ "You [text] at \the [src].",\
+ "You hear shredding and ripping.")
+ check_health()
+ return
/obj/effect/plant/proc/entangle(var/mob/living/victim)
if(buckled_mob)
return
- if(victim.buckled)
+ if(victim.buckled || victim.anchored)
return
//grabbing people
- if(!victim.anchored && Adjacent(victim) && victim.loc != get_turf(src))
+ if(!victim.anchored && Adjacent(victim) && victim.loc != src.loc)
var/can_grab = 1
if(istype(victim, /mob/living/carbon/human))
var/mob/living/carbon/human/H = victim
@@ -77,10 +88,9 @@
can_grab = 0
if(can_grab)
src.visible_message("Tendrils lash out from \the [src] and drag \the [victim] in!")
- victim.loc = src.loc
-
- //entangling people
- if(victim.loc == src.loc)
- buckle_mob(victim)
- victim.set_dir(pick(cardinal))
- victim << "Tendrils [pick("wind", "tangle", "tighten")] around you!"
+ victim.forceMove(src.loc)
+ buckle_mob(victim)
+ victim.set_dir(pick(cardinal))
+ victim << "Tendrils [pick("wind", "tangle", "tighten")] around you!"
+ victim.Weaken(0.5)
+ seed.do_thorns(victim,src)
diff --git a/code/modules/integrated_electronics/subtypes/logic.dm b/code/modules/integrated_electronics/subtypes/logic.dm
index 8feed0457c9..beb44bf5354 100644
--- a/code/modules/integrated_electronics/subtypes/logic.dm
+++ b/code/modules/integrated_electronics/subtypes/logic.dm
@@ -60,7 +60,7 @@
/obj/item/integrated_circuit/logic/binary/not_equals
name = "not equal gate"
desc = "This gate compares two values, and outputs the number one if both are different."
- icon_state = "not equal"
+ icon_state = "not_equal"
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
/obj/item/integrated_circuit/logic/binary/not_equals/do_compare(var/datum/integrated_io/A, var/datum/integrated_io/B)
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index 74c00c36d9f..4bc6c814eec 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -71,6 +71,8 @@
new/datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 50, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 50, one_per_turf = 1, on_floor = 1), \
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("voidcraft airlock assembly horizontal", /obj/structure/door_assembly/door_assembly_voidcraft, 4, time = 50, one_per_turf = 1, on_floor = 1), \
+ new/datum/stack_recipe("voidcraft airlock assembly vertical", /obj/structure/door_assembly/door_assembly_voidcraft/vertical, 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), \
))
@@ -146,3 +148,6 @@
new/datum/stack_recipe("white folder", /obj/item/weapon/folder/white), \
new/datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow), \
))
+
+/material/snow/generate_recipes()
+ return // Snowmen and snowballs may come here later.
\ No newline at end of file
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index b6e8170e150..84bd14d4175 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -189,6 +189,12 @@
icon_state = "sheet-card"
default_type = "cardboard"
+/obj/item/stack/material/snow
+ name = "snow"
+ desc = "The temptation to build a snowfort rises."
+ icon_state = "sheet-snow"
+ default_type = "snow"
+
/obj/item/stack/material/leather
name = "leather"
desc = "The by-product of mob grinding."
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
index b6e2a49fe07..4610b4e00fe 100644
--- a/code/modules/materials/materials.dm
+++ b/code/modules/materials/materials.dm
@@ -586,12 +586,18 @@ var/list/name_to_material
hardness = 500
weight = 500
+// Likewise.
+/material/alienalloy/elevatorium
+ name = "elevatorium"
+ display_name = "elevator panelling"
+ icon_colour = "#666666"
+
/material/wood
name = "wood"
stack_type = /obj/item/stack/material/wood
icon_colour = "#824B28"
integrity = 50
- icon_base = "solid"
+ icon_base = "wood"
explosion_resistance = 2
shard_type = SHARD_SPLINTER
shard_can_repair = 0 // you can't weld splinters back into planks
@@ -612,6 +618,12 @@ var/list/name_to_material
stack_type = null
shard_type = SHARD_NONE
+/material/wood/sif
+ name = "alien wood"
+// stack_type = /obj/item/stack/material/wood/sif
+ icon_colour = "#0099cc" // Cyan-ish
+ stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) // Alien wood would presumably be more interesting to the analyzer.
+
/material/cardboard
name = "cardboard"
stack_type = /obj/item/stack/material/cardboard
@@ -628,6 +640,22 @@ var/list/name_to_material
door_icon_base = "wood"
destruction_desc = "crumples"
+/material/snow
+ name = "snow"
+ stack_type = /obj/item/stack/material/snow
+ flags = MATERIAL_BRITTLE
+ icon_base = "solid"
+ icon_reinf = "reinf_over"
+ icon_colour = "#FFFFFF"
+ integrity = 1
+ hardness = 1
+ weight = 1
+ stack_origin_tech = list(TECH_MATERIAL = 1)
+ melting_point = T0C+1
+ destruction_desc = "crumples"
+ sheet_singular_name = "pile"
+ sheet_plural_name = "piles"
+
/material/cloth //todo
name = "cloth"
stack_origin_tech = list(TECH_MATERIAL = 2)
diff --git a/code/modules/metric/metric.dm b/code/modules/metric/metric.dm
index 1550b2c34ec..44ff59d284f 100644
--- a/code/modules/metric/metric.dm
+++ b/code/modules/metric/metric.dm
@@ -2,7 +2,7 @@
// player.
/datum/metric
- var/departments = list(
+ var/list/departments = list(
ROLE_COMMAND,
ROLE_SECURITY,
ROLE_ENGINEERING,
diff --git a/code/modules/mining/abandonedcrates.dm b/code/modules/mining/abandonedcrates.dm
index 9585a4965bc..a017476af32 100644
--- a/code/modules/mining/abandonedcrates.dm
+++ b/code/modules/mining/abandonedcrates.dm
@@ -148,11 +148,19 @@
return
user << "The crate is locked with a Deca-code lock."
- var/input = input(user, "Enter [codelen] digits.", "Deca-Code Lock", "") as text
+ var/input = input(usr, "Enter [codelen] digits. All digits must be unique.", "Deca-Code Lock", "") as text
if(!Adjacent(user))
return
+ var/list/sanitised = list()
+ var/sanitycheck = 1
+ for(var/i=1,i<=length(input),i++) //put the guess into a list
+ sanitised += text2num(copytext(input,i,i+1))
+ for(var/i=1,i<=(length(input)-1),i++) //compare each digit in the guess to all those following it
+ for(var/j=(i+1),j<=length(input),j++)
+ if(sanitised[i] == sanitised[j])
+ sanitycheck = null //if a digit is repeated, reject the input
- if(input == null || length(input) != codelen)
+ if(input == null || sanitycheck == null || length(input) != codelen)
user << "You leave the crate alone."
else if(check_input(input))
user << "The crate unlocks!"
@@ -203,6 +211,9 @@
else if(lastattempt[i] in code_contents)
++cows
code_contents -= lastattempt[i]
- user << "Last code attempt had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions."
+ var/previousattempt = null //convert back to string for readback
+ for(var/i in 1 to codelen)
+ previousattempt = addtext(previousattempt, lastattempt[i])
+ user << "Last code attempt, [previousattempt], had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions."
return
..()
diff --git a/code/modules/mining/drilling/drill.dm b/code/modules/mining/drilling/drill.dm
index 31d99ebb05c..5b1cbe496f2 100644
--- a/code/modules/mining/drilling/drill.dm
+++ b/code/modules/mining/drilling/drill.dm
@@ -17,7 +17,7 @@
var/list/resource_field = list()
var/ore_types = list(
- "iron" = /obj/item/weapon/ore/iron,
+ "hematite" = /obj/item/weapon/ore/iron,
"uranium" = /obj/item/weapon/ore/uranium,
"gold" = /obj/item/weapon/ore/gold,
"silver" = /obj/item/weapon/ore/silver,
@@ -26,7 +26,7 @@
"osmium" = /obj/item/weapon/ore/osmium,
"hydrogen" = /obj/item/weapon/ore/hydrogen,
"silicates" = /obj/item/weapon/ore/glass,
- "carbonaceous rock" = /obj/item/weapon/ore/coal
+ "carbon" = /obj/item/weapon/ore/coal
)
//Upgrades
diff --git a/code/modules/mining/drilling/scanner.dm b/code/modules/mining/drilling/scanner.dm
index c0c3dd937d2..4a8c3c59b6c 100644
--- a/code/modules/mining/drilling/scanner.dm
+++ b/code/modules/mining/drilling/scanner.dm
@@ -29,7 +29,7 @@
var/ore_type
switch(metal)
- if("silicates", "carbonaceous rock", "iron") ore_type = "surface minerals"
+ if("silicates", "carbon", "hematite") ore_type = "surface minerals"
if("gold", "silver", "diamond") ore_type = "precious metals"
if("uranium") ore_type = "nuclear fuel"
if("phoron", "osmium", "hydrogen") ore_type = "exotic matter"
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index b9fc47e4e9b..f46d384f868 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -175,9 +175,8 @@ var/list/mining_overlay_cache = list()
if(severity <= 2) // Now to expose the ore lying under the sand.
spawn(1) // Otherwise most of the ore is lost to the explosion, which makes this rather moot.
- var/losses = rand(0.5, 1) // Between 0% to 50% loss due to booms.
for(var/ore in resources)
- var/amount_to_give = Ceiling(resources[ore] * losses) // Should result in at least one piece of ore.
+ var/amount_to_give = rand(Ceiling(resources[ore]/2), resources[ore]) // Should result in at least one piece of ore.
for(var/i=1, i <= amount_to_give, i++)
var/oretype = ore_types[ore]
new oretype(src)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index b7a686fef0d..07562ad190d 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -318,40 +318,17 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
M.antagHUD = 1
src << "\blue AntagHUD Enabled"
-/mob/observer/dead/proc/dead_tele(A in ghostteleportlocs)
+/mob/observer/dead/proc/dead_tele(var/area/A in return_sorted_areas())
set category = "Ghost"
set name = "Teleport"
- set desc= "Teleport to a location"
+ set desc = "Teleport to a location"
+
if(!istype(usr, /mob/observer/dead))
usr << "Not when you're not dead!"
return
- usr.verbs -= /mob/observer/dead/proc/dead_tele
- spawn(30)
- usr.verbs += /mob/observer/dead/proc/dead_tele
- var/area/thearea = ghostteleportlocs[A]
- if(!thearea) return
- var/list/L = list()
- var/holyblock = 0
-
- if(usr.invisibility <= SEE_INVISIBLE_LIVING || (usr.mind in cult.current_antagonists))
- for(var/turf/T in get_area_turfs(thearea.type))
- if(!T.holy)
- L+=T
- else
- holyblock = 1
- else
- for(var/turf/T in get_area_turfs(thearea.type))
- L+=T
-
- if(!L || !L.len)
- if(holyblock)
- usr << "This area has been entirely made into sacred grounds, you cannot enter it while you are in this plane of existence!"
- else
- usr << "No area available."
-
- usr.forceMove(pick(L))
- following = null
+ usr.forceMove(pick(get_area_turfs(A)))
+ usr.on_mob_jump()
/mob/observer/dead/verb/follow(input in getmobs())
set category = "Ghost"
@@ -518,7 +495,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return
var/turf/T = get_turf(src)
- if(!T || (T.z in config.admin_levels))
+ if(!T || (T.z in using_map.admin_levels))
src << "You may not spawn as a mouse on this Z-level."
return
diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm
index 15b99923752..b2748e6f061 100644
--- a/code/modules/mob/emote.dm
+++ b/code/modules/mob/emote.dm
@@ -23,6 +23,8 @@
if (message)
log_emote("[name]/[key] : [message]")
+ message = say_emphasis(message)
+
// Hearing gasp and such every five seconds is not good emotes were not global for a reason.
// Maybe some people are okay with that.
@@ -63,6 +65,8 @@
else
input = message
+ input = say_emphasis(input)
+
if(input)
log_emote("Ghost/[src.key] : [input]")
if(!invisibility) //If the ghost is made visible by admins or cult. And to see if the ghost has toggled its own visibility, as well. -Mech
diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm
index a240277d38c..c422a35530c 100644
--- a/code/modules/mob/hear_say.dm
+++ b/code/modules/mob/hear_say.dm
@@ -32,14 +32,10 @@
if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages
if(!say_understands(speaker,language))
- if(istype(speaker,/mob/living/simple_animal))
- var/mob/living/simple_animal/S = speaker
- message = pick(S.speak)
+ if(language)
+ message = language.scramble(message)
else
- if(language)
- message = language.scramble(message)
- else
- message = stars(message)
+ message = stars(message)
var/speaker_name = speaker.name
if(istype(speaker, /mob/living/carbon/human))
@@ -49,6 +45,8 @@
if(italics)
message = "[message]"
+ message = say_emphasis(message)
+
var/track = null
if(istype(src, /mob/observer/dead))
if(italics && is_preference_enabled(/datum/client_preference/ghost_radio))
@@ -66,20 +64,73 @@
else
src << "[speaker_name][alt_name] talks but you cannot hear."
else
+ var/message_to_send = null
if(language)
- on_hear_say("[speaker_name][alt_name] [track][language.format_message(message, verb)]")
+ message_to_send = "[speaker_name][alt_name] [track][language.format_message(message, verb)]"
else
- on_hear_say("[speaker_name][alt_name] [track][verb], \"[message]\"")
+ message_to_send = "[speaker_name][alt_name] [track][verb], \"[message]\""
+ if(check_mentioned(message) && is_preference_enabled(/datum/client_preference/check_mention))
+ message_to_send = "[message_to_send]"
+
+ on_hear_say(message_to_send)
+
if (speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z))
var/turf/source = speaker? get_turf(speaker) : get_turf(src)
src.playsound_local(source, speech_sound, sound_vol, 1)
/mob/proc/on_hear_say(var/message)
- src << message
+ to_chat(src, message)
/mob/living/silicon/on_hear_say(var/message)
var/time = say_timestamp()
- src << "[time] [message]"
+ to_chat(src, "[time] [message]")
+
+// Checks if the mob's own name is included inside message. Handles both first and last names.
+/mob/proc/check_mentioned(var/message)
+ var/list/valid_names = splittext(real_name, " ") // Should output list("John", "Doe") as an example.
+ valid_names += special_mentions()
+ for(var/name in valid_names)
+ if(findtext(message, regex("\\b[name]\\b", "i"))) // This is to stop 'ai' from triggering if someone says 'wait'.
+ return TRUE
+ return FALSE
+
+// Override this if you want something besides the mob's name to count for being mentioned in check_mentioned().
+/mob/proc/special_mentions()
+ return list()
+
+/mob/living/silicon/ai/special_mentions()
+ return list("AI") // AI door!
+
+// Converts specific characters, like *, /, and _ to formatted output.
+/mob/proc/say_emphasis(var/message)
+ message = encode_html_emphasis(message, "/", "i")
+ message = encode_html_emphasis(message, "+", "b")
+ message = encode_html_emphasis(message, "_", "u")
+ return message
+
+// Replaces a character inside message with html tags. Note that html var must not include brackets.
+// Will not create an open html tag if it would not have a closing one.
+/proc/encode_html_emphasis(var/message, var/char, var/html)
+ var/i = 20 // Infinite loop safety.
+ var/pattern = "(?") - 1
+
+ // Now replace both.
+ message = replacetext(message, char, "<[html]>", first, first + 1)
+ message = replacetext(message, char, "[html]>", second + length_increase, second + length_increase + 1)
+
+ // Check again to see if we need to keep going.
+ first = re.Find(message)
+ second = re.Find(message, first + 1)
+ i--
+ if(!i)
+ CRASH("Possible infinite loop occured in encode_html_emphasis().")
+ return message
/mob/proc/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="")
@@ -182,11 +233,15 @@
speaker_name = "[speaker.real_name] ([speaker_name])"
track = "[speaker_name] ([ghost_follow_link(speaker, src)])"
+ message = say_emphasis(message)
+
var/formatted
if(language)
formatted = "[language.format_message_radio(message, verb)][part_c]"
else
formatted = "[verb], \"[message]\"[part_c]"
+
+
if((sdisabilities & DEAF) || ear_deaf)
if(prob(20))
src << "You feel your headset vibrate but can hear nothing from it!"
@@ -197,18 +252,30 @@
return "\[[stationtime2text()]\]"
/mob/proc/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
- src << "[part_a][speaker_name][part_b][formatted]"
+ var/final_message = "[part_a][speaker_name][part_b][formatted]"
+ if(check_mentioned(formatted) && is_preference_enabled(/datum/client_preference/check_mention))
+ final_message = "[final_message]"
+ to_chat(src, final_message)
/mob/observer/dead/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
- src << "[part_a][track][part_b][formatted]"
+ var/final_message = "[part_a][track][part_b][formatted]"
+ if(check_mentioned(formatted) && is_preference_enabled(/datum/client_preference/check_mention))
+ final_message = "[final_message]"
+ to_chat(src, final_message)
/mob/living/silicon/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
var/time = say_timestamp()
- src << "[time][part_a][speaker_name][part_b][formatted]"
+ var/final_message = "[part_a][speaker_name][part_b][formatted]"
+ if(check_mentioned(formatted) && is_preference_enabled(/datum/client_preference/check_mention))
+ final_message = "[time][final_message]"
+ to_chat(src, final_message)
/mob/living/silicon/ai/on_hear_radio(part_a, speaker_name, track, part_b, formatted)
var/time = say_timestamp()
- src << "[time][part_a][track][part_b][formatted]"
+ var/final_message = "[part_a][track][part_b][formatted]"
+ if(check_mentioned(formatted) && is_preference_enabled(/datum/client_preference/check_mention))
+ final_message = "[time][final_message]"
+ to_chat(src, final_message)
/mob/proc/hear_signlang(var/message, var/verb = "gestures", var/datum/language/language, var/mob/speaker = null)
if(!client)
diff --git a/code/modules/mob/language/generic.dm b/code/modules/mob/language/generic.dm
index 7df164c821a..ce0abbb9486 100644
--- a/code/modules/mob/language/generic.dm
+++ b/code/modules/mob/language/generic.dm
@@ -21,12 +21,12 @@
// 'basic' language; spoken by default.
/datum/language/common
name = LANGUAGE_GALCOM
- desc = "The common galactic tongue."
+ desc = "The common galactic tongue, engineered for cross-species communication."
speech_verb = "says"
whisper_verb = "whispers"
key = "0"
flags = RESTRICTED
- syllables = list("blah","blah","blah","bleh","meh","neh","nah","wah")
+ syllables = list("vol", "zum", "coo","zoo","bi","do","ooz","ite","og","re","si","ite","ish","ar","at","on","ee","east","ma","da", "rim")
//TODO flag certain languages to use the mob-type specific say_quote and then get rid of these.
/datum/language/common/get_spoken_verb(var/msg_end)
diff --git a/code/modules/mob/language/station.dm b/code/modules/mob/language/station.dm
index b69c9cca5fe..8e2f2987c9e 100644
--- a/code/modules/mob/language/station.dm
+++ b/code/modules/mob/language/station.dm
@@ -72,24 +72,25 @@
/datum/language/skrell
name = LANGUAGE_SKRELLIAN
- desc = "A melodic and complex language spoken by the Skrell of Qerrbalak. Some of the notes are inaudible to humans."
+ desc = "A set of warbles and hums, the language itself a complex mesh of both melodic and rhythmic components, exceptionally capable of conveying intent and emotion of the speaker."
speech_verb = "warbles"
ask_verb = "warbles"
- exclaim_verb = "warbles"
+ exclaim_verb = "sings"
+ whisper_verb = "hums"
colour = "skrell"
key = "k"
+ space_chance = 30
flags = WHITELISTED
- syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","*","!")
+ syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","*","!", "'")
/datum/language/human
name = LANGUAGE_SOL_COMMON
- desc = "A bastardized hybrid of informal English and elements of Mandarin Chinese; the common language of the Sol system."
+ desc = "A bastardized hybrid of many languages, including Chinese, English, French, and more; it is the common language of the Sol system."
speech_verb = "says"
whisper_verb = "whispers"
colour = "solcom"
key = "1"
flags = WHITELISTED
-
//syllables are at the bottom of the file
/datum/language/human/get_spoken_verb(var/msg_end)
@@ -118,7 +119,7 @@
colour = "changeling"
key = "6"
flags = NO_STUTTER
- syllables = list("beep","beep","beep","beep","beep","boop","boop","boop","bop","bop","dee","dee","doo","doo","hiss","hss","buzz","buzz","bzz","ksssh","keey","wurr","wahh","tzzz")
+ syllables = list("beep","beep","beep","beep","beep","boop","boop","boop","bop","bop","dee","dee","doo","doo","hiss","hss","buzz","buzz","bzz","ksssh","keey","wurr","wahh","tzzz","shh","shk")
space_chance = 10
/datum/language/machine/can_speak_special(var/mob/speaker)
@@ -155,9 +156,13 @@
/*
This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed,
and the english syllables had to be duplicated so that there is roughly a 50-50 weighting.
+ The other 3 languages were duplicated just so they could show occasionally.
Sources:
http://www.sttmedia.com/syllablefrequency-english
+ http://www.sttmedia.com/syllablefrequency-spanish
+ http://www.sttmedia.com/syllablefrequency-russian
+ http://www.sttmedia.com/syllablefrequency-french
http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm
*/
/datum/language/human/syllables = list(
@@ -210,4 +215,31 @@
"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it",
"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to",
"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin",
-"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi")
+"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi",
+"ah", "be", "bo", "eh", "ep", "et", "ka", "ko", "ha", "he", "ho", "ob", "oh", "op", "oc", "ot", "pa", "pe", "ct", "ta", "te", "to",
+"vse", "tak", "nak", "no", "epo", "pre", "kan", "dly", "ime", "sha", "kur", "yey", "khi", "yeg", "ne",
+"ion", "ne", "nas", "v",
+"ah", "be", "bo", "eh", "ep", "et", "ka", "ko", "ha", "he", "ho", "ob", "oh", "op", "oc", "ot", "pa", "pe", "ct", "ta", "te", "to",
+"vse", "tak", "nak", "no", "epo", "pre", "kan", "dly", "ime", "sha", "kur", "yey", "khi", "yeg", "ne",
+"ion", "ne", "nas", "v",
+"ah", "be", "bo", "eh", "ep", "et", "ka", "ko", "ha", "he", "ho", "ob", "oh", "op", "oc", "ot", "pa", "pe", "ct", "ta", "te", "to",
+"vse", "tak", "nak", "no", "epo", "pre", "kan", "dly", "ime", "sha", "kur", "yey", "khi", "yeg", "ne",
+"ion", "ne", "nas", "v",
+"ai", "an", "ar", "au", "ce", "ch", "co", "de", "em", "en", "er", "es", "et", "eu", "il", "in", "is", "la", "le",
+"ma", "me", "ne", "ns", "nt", "on", "ou", "pa", "qu", "ra", "re", "se", "te", "ti", "tr", "ue", "ur", "us", "ve",
+"tou", "e", "eve", "hen", "son", "non", "not", "le",
+"ai", "an", "ar", "au", "ce", "ch", "co", "de", "em", "en", "er", "es", "et", "eu", "il", "in", "is", "la", "le",
+"ma", "me", "ne", "ns", "nt", "on", "ou", "pa", "qu", "ra", "re", "se", "te", "ti", "tr", "ue", "ur", "us", "ve",
+"tou", "e", "eve", "hen", "son", "non", "not", "le",
+"ai", "an", "ar", "au", "ce", "ch", "co", "de", "em", "en", "er", "es", "et", "eu", "il", "in", "is", "la", "le",
+"ma", "me", "ne", "ns", "nt", "on", "ou", "pa", "qu", "ra", "re", "se", "te", "ti", "tr", "ue", "ur", "us", "ve",
+"tou", "e", "eve", "hen", "son", "non", "not", "le",
+"ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na",
+"no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un",
+"tod", "ser", "su", "no", "nue", "el",
+"ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na",
+"no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un",
+"tod", "ser", "su", "no", "nue", "el",
+"ad", "al", "an", "ar", "as", "ci", "co", "de", "do", "el", "en", "er", "es", "ie", "in", "la", "lo", "me", "na",
+"no", "nt", "or", "os", "pa", "qu", "ra", "re", "ro", "se", "st", "ta", "te", "to", "ue", "un",
+"tod", "ser", "su", "no", "nue", "el")
\ No newline at end of file
diff --git a/code/modules/mob/language/synthetic.dm b/code/modules/mob/language/synthetic.dm
index dbf91343f13..2a2ddb0ff97 100644
--- a/code/modules/mob/language/synthetic.dm
+++ b/code/modules/mob/language/synthetic.dm
@@ -17,15 +17,19 @@
if (!message)
return
+ message = speaker.say_emphasis(message)
+
var/message_start = "[name], [speaker.name]"
var/message_body = "[speaker.say_quote(message)], \"[message]\""
for (var/mob/M in dead_mob_list)
if(!istype(M,/mob/new_player) && !istype(M,/mob/living/carbon/brain)) //No meta-evesdropping
- M.show_message("[message_start] ([ghost_follow_link(speaker, M)]) [message_body]", 2)
+ var/message_to_send = "[message_start] ([ghost_follow_link(speaker, M)]) [message_body]"
+ if(M.check_mentioned(message) && M.is_preference_enabled(/datum/client_preference/check_mention))
+ message_to_send = "[message_to_send]"
+ M.show_message(message_to_send, 2)
for (var/mob/living/S in living_mob_list)
-
if(drone_only && !istype(S,/mob/living/silicon/robot/drone))
continue
else if(istype(S , /mob/living/silicon/ai))
@@ -33,7 +37,10 @@
else if (!S.binarycheck())
continue
- S.show_message("[message_start] [message_body]", 2)
+ var/message_to_send = "[message_start] [message_body]"
+ if(S.check_mentioned(message) && S.is_preference_enabled(/datum/client_preference/check_mention))
+ message_to_send = "[message_to_send]"
+ S.show_message(message_to_send, 2)
var/list/listening = hearers(1, src)
listening -= src
diff --git a/code/modules/mob/living/autohiss.dm b/code/modules/mob/living/autohiss.dm
index ae756f6a5fc..3a3bddd9b3f 100644
--- a/code/modules/mob/living/autohiss.dm
+++ b/code/modules/mob/living/autohiss.dm
@@ -59,6 +59,8 @@
/datum/species/proc/handle_autohiss(message, datum/language/lang, mode)
if(!autohiss_basic_map)
return message
+ if(lang.flags & NO_STUTTER) // Currently prevents EAL, Sign language, and emotes from autohissing
+ return message
if(autohiss_exempt && (lang.name in autohiss_exempt))
return message
diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm
index 0ad82ae384e..8c61b68a3ea 100644
--- a/code/modules/mob/living/bot/bot.dm
+++ b/code/modules/mob/living/bot/bot.dm
@@ -27,7 +27,7 @@
var/turf/obstacle = null
var/wait_if_pulled = 0 // Only applies to moving to the target
- var/will_patrol = 0 // Not a setting - whether or no this type of bots patrols at all
+ var/will_patrol = 0 // If set to 1, will patrol, duh
var/patrol_speed = 1 // How many times per tick we move when patrolling
var/target_speed = 2 // Ditto for chasing the target
var/min_target_dist = 1 // How close we try to get to the target
@@ -49,7 +49,11 @@
access_scanner.req_access = req_access.Copy()
access_scanner.req_one_access = req_one_access.Copy()
- turn_on()
+// Make sure mapped in units start turned on.
+/mob/living/bot/initialize()
+ ..()
+ if(on)
+ turn_on() // Update lights and other stuff
/mob/living/bot/Life()
..()
@@ -61,7 +65,8 @@
paralysis = 0
if(on && !client && !busy)
- handleAI()
+ spawn(0)
+ handleAI()
/mob/living/bot/updatehealth()
if(status_flags & GODMODE)
@@ -145,20 +150,18 @@
handleRangedTarget()
if(!wait_if_pulled || !pulledby)
for(var/i = 1 to target_speed)
+ sleep(20 / (target_speed + 1))
stepToTarget()
- if(i < target_speed)
- sleep(20 / target_speed)
if(max_frustration && frustration > max_frustration * target_speed)
handleFrustrated(1)
else
resetTarget()
lookForTargets()
if(will_patrol && !pulledby && !target)
- if(patrol_path.len)
+ if(patrol_path && patrol_path.len)
for(var/i = 1 to patrol_speed)
+ sleep(20 / (patrol_speed + 1))
handlePatrol()
- if(i < patrol_speed)
- sleep(20 / patrol_speed)
if(max_frustration && frustration > max_frustration * patrol_speed)
handleFrustrated(0)
else
@@ -219,6 +222,25 @@
return
/mob/living/bot/proc/getPatrolTurf()
+ var/minDist = INFINITY
+ var/obj/machinery/navbeacon/targ = locate() in get_turf(src)
+
+ if(!targ)
+ for(var/obj/machinery/navbeacon/N in navbeacons)
+ if(!N.codes["patrol"])
+ continue
+ if(get_dist(src, N) < minDist)
+ minDist = get_dist(src, N)
+ targ = N
+
+ if(targ && targ.codes["next_patrol"])
+ for(var/obj/machinery/navbeacon/N in navbeacons)
+ if(N.location == targ.codes["next_patrol"])
+ targ = N
+ break
+
+ if(targ)
+ return get_turf(targ)
return null
/mob/living/bot/proc/handleIdle()
@@ -255,15 +277,16 @@
on = 1
set_light(light_strength)
update_icons()
+ resetTarget()
+ patrol_path = list()
+ ignore_list = list()
return 1
/mob/living/bot/proc/turn_off()
on = 0
+ busy = 0 // If ever stuck... reboot!
set_light(0)
update_icons()
- resetTarget()
- patrol_path = list()
- ignore_list = list()
/mob/living/bot/proc/explode()
qdel(src)
@@ -327,6 +350,11 @@
for(var/obj/machinery/door/D in loc)
if(!D.density) continue
+
+ if(istype(D, /obj/machinery/door/airlock))
+ var/obj/machinery/door/airlock/A = D
+ if(!A.can_open()) return 1
+
if(istype(D, /obj/machinery/door/window))
if( dir & D.dir ) return !D.check_access(ID)
diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm
index 779d912cf3e..d4cb7238614 100644
--- a/code/modules/mob/living/bot/cleanbot.dm
+++ b/code/modules/mob/living/bot/cleanbot.dm
@@ -12,7 +12,6 @@
var/cleaning = 0
var/screwloose = 0
var/oddbutton = 0
- var/should_patrol = 0
var/blood = 1
var/list/target_types = list()
@@ -32,9 +31,11 @@
if(oddbutton && prob(5)) // Make a big mess
visible_message("Something flies out of [src]. He seems to be acting oddly.")
var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(loc)
- ignore_list += gib
+ // TODO - I have a feeling weakrefs will not work in ignore_list, verify this ~Leshana
+ var/weakref/g = weakref(gib)
+ ignore_list += g
spawn(600)
- ignore_list -= gib
+ ignore_list -= g
/mob/living/bot/cleanbot/lookForTargets()
for(var/obj/effect/decal/cleanable/D in view(world.view, src)) // There was some odd code to make it start with nearest decals, it's unnecessary, this works
@@ -110,7 +111,7 @@
dat += "Maintenance panel is [open ? "opened" : "closed"]"
if(!locked || issilicon(user))
dat += " Cleans Blood: [blood ? "Yes" : "No"] "
- dat += " Patrol station: [should_patrol ? "Yes" : "No"] "
+ dat += " Patrol station: [will_patrol ? "Yes" : "No"] "
if(open && !locked)
dat += "Odd looking screw twiddled: [screwloose ? "Yes" : "No"] "
dat += "Weird button pressed: [oddbutton ? "Yes" : "No"]"
@@ -134,7 +135,7 @@
blood = !blood
get_targets()
if("patrol")
- should_patrol = !should_patrol
+ will_patrol = !will_patrol
patrol_path = null
if("screw")
screwloose = !screwloose
diff --git a/code/modules/mob/living/bot/farmbot.dm b/code/modules/mob/living/bot/farmbot.dm
index 09320fd323f..1e23af341c3 100644
--- a/code/modules/mob/living/bot/farmbot.dm
+++ b/code/modules/mob/living/bot/farmbot.dm
@@ -170,7 +170,7 @@
visible_message("[src] starts [T.dead? "removing the plant from" : "harvesting"] \the [A].")
busy = 1
- if(do_after(src, 30))
+ if(do_after(src, 30, A))
visible_message("[src] [T.dead? "removes the plant from" : "harvests"] \the [A].")
T.attack_hand(src)
if(FARMBOT_WATER)
@@ -179,7 +179,7 @@
visible_message("[src] starts watering \the [A].")
busy = 1
- if(do_after(src, 30))
+ if(do_after(src, 30, A))
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
visible_message("[src] waters \the [A].")
tank.reagents.trans_to(T, 100 - T.waterlevel)
@@ -198,7 +198,7 @@
visible_message("[src] starts fertilizing \the [A].")
busy = 1
- if(do_after(src, 30))
+ if(do_after(src, 30, A))
visible_message("[src] fertilizes \the [A].")
T.reagents.add_reagent("ammonia", 10)
diff --git a/code/modules/mob/living/bot/floorbot.dm b/code/modules/mob/living/bot/floorbot.dm
index 22595159411..323d2909fb7 100644
--- a/code/modules/mob/living/bot/floorbot.dm
+++ b/code/modules/mob/living/bot/floorbot.dm
@@ -1,3 +1,9 @@
+// Configure whether or not floorbot will fix hull breaches.
+// This can be a problem if it tries to pave over space or shuttles. That should be fixed but...
+// If it can see space outside windows, it can be laggy since it keeps wondering if it should fix them.
+// Therefore that functionality is disabled for now. But it can be turned on by uncommenting this.
+// #define FLOORBOT_PATCHES_HOLES 1
+
/mob/living/bot/floorbot
name = "Floorbot"
desc = "A little floor repairing robot, he looks so excited!"
@@ -25,7 +31,7 @@
/mob/living/bot/floorbot/attack_hand(var/mob/user)
user.set_machine(src)
- var/dat
+ var/list/dat = list()
dat += "Automatic Station Floor Repairer v1.0
"
dat += "Status: [src.on ? "On" : "Off"] "
dat += "Maintenance panel is [open ? "opened" : "closed"] "
@@ -41,9 +47,9 @@
else
bmode = "Disabled"
dat += "
Bridge Mode : [bmode] "
-
- user << browse("Repairbot v1.0 controls[dat]", "window=autorepair")
- onclose(user, "autorepair")
+ var/datum/browser/popup = new(user, "autorepair", "Repairbot v1.1 controls")
+ popup.set_content(jointext(dat,null))
+ popup.open()
return
/mob/living/bot/floorbot/emag_act(var/remaining_charges, var/mob/user)
@@ -115,23 +121,24 @@
target = T
return
T = get_step(T, targetdirection)
+ return // In bridge mode we don't want to step off that line even to eat plates!
- else // Fixing floors
- for(var/turf/space/T in view(src)) // Breaches are of higher priority
- if(confirmTarget(T))
- target = T
- return
+#ifdef FLOORBOT_PATCHES_HOLES
+ for(var/turf/space/T in view(src)) // Breaches are of higher priority
+ if(confirmTarget(T))
+ target = T
+ return
- for(var/turf/simulated/mineral/floor/T in view(src)) // Asteroids are of smaller priority
- if(confirmTarget(T))
- target = T
- return
-
- if(improvefloors)
- for(var/turf/simulated/floor/T in view(src))
- if(confirmTarget(T))
- target = T
- return
+ for(var/turf/simulated/mineral/floor/T in view(src)) // Asteroids are of smaller priority
+ if(confirmTarget(T))
+ target = T
+ return
+#endif
+ // Look for broken floors even if we aren't improvefloors
+ for(var/turf/simulated/floor/T in view(src))
+ if(confirmTarget(T))
+ target = T
+ return
if(amount < maxAmount && (eattiles || maketiles))
for(var/obj/item/stack/S in view(src))
@@ -148,7 +155,11 @@
if(istype(A, /obj/item/stack/material/steel))
return (amount < maxAmount && maketiles)
- if(A.loc.name == "Space")
+ // Don't pave over all of space, build there only if in bridge mode
+ if(!targetdirection && istype(A.loc, /area/space)) // Note name == "Space" does not work!
+ return 0
+
+ if(istype(A.loc, /area/shuttle)) // Do NOT mess with shuttle drop zones
return 0
if(emagged)
@@ -157,14 +168,16 @@
if(!amount)
return 0
+#ifdef FLOORBOT_PATCHES_HOLES
if(istype(A, /turf/space))
return 1
if(istype(A, /turf/simulated/mineral/floor))
return 1
+#endif
var/turf/simulated/floor/T = A
- return (istype(T) && improvefloors && !T.flooring && (get_turf(T) == loc || prob(40)))
+ return (istype(T) && (T.broken || T.burnt || (improvefloors && !T.flooring)) && (get_turf(T) == loc || prob(40)))
/mob/living/bot/floorbot/UnarmedAttack(var/atom/A, var/proximity)
if(!..())
@@ -181,12 +194,12 @@
busy = 1
update_icons()
if(F.flooring)
- visible_message("[src] begins to tear the floor tile from the floor!")
+ visible_message("\The [src] begins to tear the floor tile from the floor!")
if(do_after(src, 50))
F.break_tile_to_plating()
addTiles(1)
else
- visible_message("[src] begins to tear through the floor!")
+ visible_message("\The [src] begins to tear through the floor!")
if(do_after(src, 150)) // Extra time because this can and will kill.
F.ReplaceWithLattice()
addTiles(1)
@@ -201,7 +214,7 @@
return
busy = 1
update_icons()
- visible_message("[src] begins to repair the hole.")
+ visible_message("\The [src] begins to repair the hole.")
if(do_after(src, 50))
if(A && (locate(/obj/structure/lattice, A) && building == 1 || !locate(/obj/structure/lattice, A) && building == 2)) // Make sure that it still needs repairs
var/obj/item/I
@@ -215,10 +228,20 @@
update_icons()
else if(istype(A, /turf/simulated/floor))
var/turf/simulated/floor/F = A
- if(!F.flooring && amount)
+ if(F.broken || F.burnt)
busy = 1
update_icons()
- visible_message("[src] begins to improve the floor.")
+ visible_message("\The [src] begins to remove the broken floor.")
+ if(do_after(src, 50, F))
+ if(F.broken || F.burnt)
+ F.make_plating()
+ target = null
+ busy = 0
+ update_icons()
+ else if(!F.flooring && amount)
+ busy = 1
+ update_icons()
+ visible_message("\The [src] begins to improve the floor.")
if(do_after(src, 50))
if(!F.flooring)
F.set_flooring(get_flooring_data(floor_build_type))
@@ -228,7 +251,7 @@
update_icons()
else if(istype(A, /obj/item/stack/tile/floor) && amount < maxAmount)
var/obj/item/stack/tile/floor/T = A
- visible_message("[src] begins to collect tiles.")
+ visible_message("\The [src] begins to collect tiles.")
busy = 1
update_icons()
if(do_after(src, 20))
@@ -242,7 +265,7 @@
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.")
+ visible_message("\The [src] begins to make tiles.")
busy = 1
update_icons()
if(do_after(50))
@@ -252,7 +275,7 @@
/mob/living/bot/floorbot/explode()
turn_off()
- visible_message("[src] blows apart!")
+ visible_message("\The [src] blows apart!")
var/turf/Tsec = get_turf(src)
var/obj/item/weapon/storage/toolbox/mechanical/N = new /obj/item/weapon/storage/toolbox/mechanical(Tsec)
@@ -353,4 +376,4 @@
return
if(!in_range(src, user) && loc != user)
return
- created_name = t
\ No newline at end of file
+ created_name = t
diff --git a/code/modules/mob/living/bot/mulebot.dm b/code/modules/mob/living/bot/mulebot.dm
index c330e0efc0e..2079f77a35e 100644
--- a/code/modules/mob/living/bot/mulebot.dm
+++ b/code/modules/mob/living/bot/mulebot.dm
@@ -130,10 +130,7 @@
if("sethome")
var/new_dest
- var/list/beaconlist = new()
- for(var/obj/machinery/navbeacon/N in navbeacons)
- beaconlist.Add(N.location)
- beaconlist[N.location] = N
+ var/list/beaconlist = GetBeaconList()
if(beaconlist.len)
new_dest = input("Select new home tag", "Mulebot [suffix ? "([suffix])" : ""]", null) in null|beaconlist
else
@@ -168,10 +165,7 @@
targetName = "Home"
if("SetD")
var/new_dest
- var/list/beaconlist = new()
- for(var/obj/machinery/navbeacon/N in navbeacons)
- beaconlist.Add(N.location)
- beaconlist[N.location] = N
+ var/list/beaconlist = GetBeaconList()
if(beaconlist.len)
new_dest = input("Select new destination tag", "Mulebot [suffix ? "([suffix])" : ""]") in null|beaconlist
else
@@ -285,6 +279,15 @@
new /obj/effect/decal/cleanable/blood/oil(Tsec)
..()
+/mob/living/bot/mulebot/proc/GetBeaconList()
+ var/list/beaconlist = list()
+ for(var/obj/machinery/navbeacon/N in navbeacons)
+ if(!N.codes["delivery"])
+ continue
+ beaconlist.Add(N.location)
+ beaconlist[N.location] = N
+ return beaconlist
+
/mob/living/bot/mulebot/proc/load(var/atom/movable/C)
if(busy || load || get_dist(C, src) > 1 || !isturf(C.loc))
return
@@ -304,11 +307,11 @@
busy = 1
- C.loc = loc
+ C.forceMove(loc)
sleep(2)
if(C.loc != loc) //To prevent you from going onto more than one bot.
return
- C.loc = src
+ C.forceMove(src)
load = C
C.pixel_y += 9
@@ -325,7 +328,7 @@
busy = 1
overlays.Cut()
- load.loc = loc
+ load.forceMove(loc)
load.pixel_y -= 9
load.layer = initial(load.layer)
@@ -338,7 +341,7 @@
if(AM == botcard || AM == access_scanner)
continue
- AM.loc = loc
+ AM.forceMove(loc)
AM.layer = initial(AM.layer)
AM.pixel_y = initial(AM.pixel_y)
busy = 0
diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm
index f7556e0ece6..d6a014c4502 100644
--- a/code/modules/mob/living/bot/secbot.dm
+++ b/code/modules/mob/living/bot/secbot.dm
@@ -1,10 +1,14 @@
+#define SECBOT_WAIT_TIME 5 //number of in-game seconds to wait for someone to surrender
+#define SECBOT_THREAT_ARREST 4 //threat level at which we decide to arrest someone
+#define SECBOT_THREAT_ATTACK 8 //threat level at which was assume immediate danger and attack right away
+
/mob/living/bot/secbot
name = "Securitron"
desc = "A little security robot. He looks less than thrilled."
icon_state = "secbot0"
maxHealth = 100
health = 100
- req_one_access = list(access_robotics, 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)
patrol_speed = 2
target_speed = 3
@@ -14,18 +18,17 @@
var/check_arrest = 1 // If true, arrests people who are set to arrest.
var/arrest_type = 0 // If true, doesn't handcuff. You monster.
var/declare_arrests = 0 // If true, announces arrests over sechuds.
- var/auto_patrol = 0 // If true, patrols on its own
var/is_ranged = 0
var/awaiting_surrender = 0
- var/list/threat_found_sounds = new('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
- var/list/preparing_arrest_sounds = new('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg')
+ var/list/threat_found_sounds = list('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg')
+ var/list/preparing_arrest_sounds = list('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/bcreep.ogg')
/mob/living/bot/secbot/beepsky
name = "Officer Beepsky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
- auto_patrol = 1
+ will_patrol = 1
/mob/living/bot/secbot/update_icons()
if(on && busy)
@@ -40,7 +43,7 @@
/mob/living/bot/secbot/attack_hand(var/mob/user)
user.set_machine(src)
- var/dat
+ var/list/dat = list()
dat += "Automatic Security Unit
"
dat += "Status: [on ? "On" : "Off"] "
dat += "Behaviour controls are [locked ? "locked" : "unlocked"] "
@@ -51,10 +54,10 @@
dat += "Check Arrest Status: [check_arrest ? "Yes" : "No"] "
dat += "Operating Mode: [arrest_type ? "Detain" : "Arrest"] "
dat += "Report Arrests: [declare_arrests ? "Yes" : "No"] "
- dat += "Auto Patrol: [auto_patrol ? "On" : "Off"]"
- user << browse("Securitron controls[dat]", "window=autosec")
- onclose(user, "autosec")
- return
+ dat += "Auto Patrol: [will_patrol ? "On" : "Off"]"
+ var/datum/browser/popup = new(user, "autosec", "Securitron controls")
+ popup.set_content(jointext(dat,null))
+ popup.open()
/mob/living/bot/secbot/Topic(href, href_list)
if(..())
@@ -80,7 +83,7 @@
if("switchmode")
arrest_type = !arrest_type
if("patrol")
- auto_patrol = !auto_patrol
+ will_patrol = !will_patrol
if("declarearrests")
declare_arrests = !declare_arrests
attack_hand(usr)
@@ -99,10 +102,46 @@
/mob/living/bot/secbot/attackby(var/obj/item/O, var/mob/user)
var/curhealth = health
- ..()
+ . = ..()
if(health < curhealth)
- target = user
- awaiting_surrender = 5
+ react_to_attack(user)
+
+/mob/living/bot/secbot/bullet_act(var/obj/item/projectile/P)
+ var/curhealth = health
+ var/mob/shooter = P.firer
+ . = ..()
+ //if we already have a target just ignore to avoid lots of checking
+ if(!target && health < curhealth && shooter && (shooter in view(world.view, src)))
+ react_to_attack(shooter)
+
+/mob/living/bot/secbot/proc/react_to_attack(mob/attacker)
+ if(!target)
+ playsound(src.loc, pick(threat_found_sounds), 50)
+ broadcast_security_hud_message("[src] was attacked by a hostile [target_name(attacker)] in [get_area(src)].", src)
+ target = attacker
+ awaiting_surrender = INFINITY // Don't try and wait for surrender
+
+// Say "freeze!" and demand surrender
+/mob/living/bot/secbot/proc/demand_surrender(mob/target, var/threat)
+ var/suspect_name = target_name(target)
+ if(declare_arrests)
+ broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [threat] suspect [suspect_name] in [get_area(src)].", src)
+ say("Down on the floor, [suspect_name]! You have [SECBOT_WAIT_TIME] seconds to comply.")
+ playsound(src.loc, pick(preparing_arrest_sounds), 50)
+ // Register to be told when the target moves
+ moved_event.register(target, src, /mob/living/bot/secbot/proc/target_moved)
+
+// Callback invoked if the registered target moves
+/mob/living/bot/secbot/proc/target_moved(atom/movable/moving_instance, atom/old_loc, atom/new_loc)
+ if(get_dist(get_turf(src), get_turf(target)) >= 1)
+ awaiting_surrender = INFINITY // Done waiting!
+ moved_event.unregister(moving_instance, src)
+
+/mob/living/bot/secbot/resetTarget()
+ ..()
+ moved_event.unregister(target, src)
+ awaiting_surrender = -1
+ walk_to(src, 0)
/mob/living/bot/secbot/startPatrol()
if(!locked) // Stop running away when we set you up
@@ -112,8 +151,7 @@
/mob/living/bot/secbot/confirmTarget(var/atom/A)
if(!..())
return 0
-
- return (check_threat(A) > 3)
+ return (check_threat(A) >= SECBOT_THREAT_ARREST)
/mob/living/bot/secbot/lookForTargets()
for(var/mob/living/M in view(src))
@@ -127,23 +165,17 @@
custom_emote(1, "points at [M.name]!")
return
-/mob/living/bot/secbot/calcTargetPath()
- ..()
- if(awaiting_surrender != -1)
- awaiting_surrender = 5 // This implies that a) we have already approached the target and b) it has moved after the warning
-
/mob/living/bot/secbot/handleAdjacentTarget()
- if(awaiting_surrender < 5 && ishuman(target) && !target:lying)
- if(awaiting_surrender == -1)
- say("Down on the floor, [target]! You have five seconds to comply.")
+ var/mob/living/carbon/human/H = target
+ var/threat = check_threat(target)
+ if(awaiting_surrender < SECBOT_WAIT_TIME && istype(H) && !H.lying && threat < SECBOT_THREAT_ATTACK)
+ if(awaiting_surrender == -1) // On first tick of awaiting...
+ demand_surrender(target, threat)
++awaiting_surrender
else
+ if(declare_arrests)
+ broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [threat] suspect [target_name(target)] in [get_area(src)].", src)
UnarmedAttack(target)
- if(ishuman(target) && declare_arrests)
- var/area/location = get_area(src)
- broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [check_threat(target)] suspect [target] in [location].", src)
-
- // say("Engaging patrol mode.")
/mob/living/bot/secbot/UnarmedAttack(var/mob/M, var/proximity)
if(!..())
@@ -170,17 +202,15 @@
spawn(2)
busy = 0
update_icons()
- visible_message("[C] was prodded by [src] with a stun baton!")
+ visible_message("\The [C] was prodded by \the [src] with a stun baton!")
else
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
- visible_message("[src] is trying to put handcuffs on [C]!")
+ visible_message("\The [src] is trying to put handcuffs on \the [C]!")
busy = 1
if(do_mob(src, C, 60))
if(!C.handcuffed)
C.handcuffed = new /obj/item/weapon/handcuffs(C)
C.update_inv_handcuffed()
- if(preparing_arrest_sounds.len)
- playsound(loc, pick(preparing_arrest_sounds), 50, 0)
busy = 0
else if(istype(M, /mob/living/simple_animal))
var/mob/living/simple_animal/S = M
@@ -193,7 +223,8 @@
spawn(2)
busy = 0
update_icons()
- visible_message("[M] was beaten by [src] with a stun baton!")
+ visible_message("\The [M] was beaten by \the [src] with a stun baton!")
+
/mob/living/bot/secbot/explode()
visible_message("[src] blows apart!")
@@ -215,11 +246,17 @@
new /obj/effect/decal/cleanable/blood/oil(Tsec)
qdel(src)
+/mob/living/bot/secbot/proc/target_name(mob/living/T)
+ if(ishuman(T))
+ var/mob/living/carbon/human/H = T
+ return H.get_id_name("unidentified person")
+ return "unidentified lifeform"
+
/mob/living/bot/secbot/proc/check_threat(var/mob/living/M)
if(!M || !istype(M) || M.stat == DEAD || src == M)
return 0
- if(emagged)
+ if(emagged && !M.incapacitated()) //check incapacitated so emagged secbots don't keep attacking the same target forever
return 10
return M.assess_perp(access_scanner, 0, idcheck, check_records, check_arrest)
@@ -297,4 +334,4 @@
return
if(!in_range(src, usr) && loc != usr)
return
- created_name = t
\ No newline at end of file
+ created_name = t
diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm
index 8060e328ee3..e74d6dab905 100644
--- a/code/modules/mob/living/carbon/brain/MMI.dm
+++ b/code/modules/mob/living/carbon/brain/MMI.dm
@@ -164,7 +164,9 @@
if(2)
brainmob.emp_damage += rand(10,20)
if(3)
- brainmob.emp_damage += rand(0,10)
+ brainmob.emp_damage += rand(5,10)
+ if(4)
+ brainmob.emp_damage += rand(0,5)
..()
/obj/item/device/mmi/digital
@@ -216,7 +218,9 @@
if(2)
src.brainmob.emp_damage += rand(10,20)
if(3)
- src.brainmob.emp_damage += rand(0,10)
+ src.brainmob.emp_damage += rand(5,10)
+ if(4)
+ src.brainmob.emp_damage += rand(0,5)
..()
/obj/item/device/mmi/digital/transfer_identity(var/mob/living/carbon/H)
diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm
index 057c24bdcc9..9452337eeb9 100644
--- a/code/modules/mob/living/carbon/brain/posibrain.dm
+++ b/code/modules/mob/living/carbon/brain/posibrain.dm
@@ -112,7 +112,9 @@
if(2)
src.brainmob.emp_damage += rand(10,20)
if(3)
- src.brainmob.emp_damage += rand(0,10)
+ src.brainmob.emp_damage += rand(5,10)
+ if(4)
+ src.brainmob.emp_damage += rand(0,5)
..()
/obj/item/device/mmi/digital/posibrain/New()
diff --git a/code/modules/mob/living/carbon/breathe.dm b/code/modules/mob/living/carbon/breathe.dm
index 6b8a3c43b3c..354a26221c4 100644
--- a/code/modules/mob/living/carbon/breathe.dm
+++ b/code/modules/mob/living/carbon/breathe.dm
@@ -53,7 +53,7 @@
var/datum/gas_mixture/environment
if(loc)
- environment = loc.return_air_for_internal_lifeform()
+ environment = loc.return_air_for_internal_lifeform(src)
if(environment)
breath = environment.remove_volume(volume_needed)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 204730a8e82..a2b84e0a528 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -166,11 +166,13 @@
var/list/status = list()
var/brutedamage = org.brute_dam
var/burndamage = org.burn_dam
- if(halloss > 0)
+ /*
+ if(halloss > 0) //Makes halloss show up as actual wounds on self examine.
if(prob(30))
brutedamage += halloss
if(prob(30))
burndamage += halloss
+ */
switch(brutedamage)
if(1 to 20)
status += "bruised"
@@ -457,7 +459,7 @@
/mob/living/carbon/proc/should_have_organ(var/organ_check)
return 0
-/mob/living/carbon/proc/can_feel_pain(var/check_organ)
+/mob/living/carbon/can_feel_pain(var/check_organ)
if(isSynthetic())
return 0
- return !(species.flags & NO_PAIN)
\ No newline at end of file
+ return !(species.flags & NO_PAIN)
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index 56e71d931a0..7908914eedf 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -25,7 +25,8 @@
message = "is strumming the air and headbanging like a safari chimp."
m_type = 1
- if("ping", "beep", "buzz", "yes", "no")
+ //Machine-only emotes
+ if("ping", "beep", "buzz", "yes", "no", "rcough", "rsneeze")
if(!isSynthetic())
src << "You are not a synthetic."
@@ -54,6 +55,18 @@
else if(act == "no")
display_msg = "emits a negative blip"
use_sound = 'sound/machines/synth_no.ogg'
+ else if(act == "rcough")
+ display_msg = "emits a robotic cough"
+ if(gender == FEMALE)
+ use_sound = pick('sound/effects/mob_effects/f_machine_cougha.ogg','sound/effects/mob_effects/f_machine_coughb.ogg')
+ else
+ use_sound = pick('sound/effects/mob_effects/m_machine_cougha.ogg','sound/effects/mob_effects/m_machine_coughb.ogg', 'sound/effects/mob_effects/m_machine_coughc.ogg')
+ else if(act == "rsneeze")
+ display_msg = "emits a robotic sneeze"
+ if(gender == FEMALE)
+ use_sound = 'sound/effects/mob_effects/machine_sneeze.ogg'
+ else
+ use_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
if (param)
message = "[display_msg] at [param]."
@@ -62,6 +75,17 @@
playsound(src.loc, use_sound, 50, 0)
m_type = 1
+ //Promethean-only emotes
+ if("squish")
+ if(!species.bump_flag == SLIME) //That should do, yaya.
+ src << "You are not a slime thing!"
+ return
+
+ playsound(src.loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound.
+ message = "blinks."
+ m_type = 1
+
+
if ("blink")
message = "blinks."
m_type = 1
@@ -202,14 +226,20 @@
src.sleeping += 10 //Short-short nap
m_type = 1
- if ("cough")
+ if("cough", "coughs")
if(miming)
message = "appears to cough!"
m_type = 1
else
- if (!muzzled)
+ if(!muzzled)
message = "coughs!"
m_type = 2
+ if(gender == FEMALE)
+ if(species.female_cough_sounds)
+ playsound(src, pick(species.female_cough_sounds), 120)
+ else
+ if(species.male_cough_sounds)
+ playsound(src, pick(species.male_cough_sounds), 120)
else
message = "makes a strong noise."
m_type = 2
@@ -456,13 +486,17 @@
message = "trembles in fear!"
m_type = 1
- if ("sneeze")
- if (miming)
+ if("sneeze", "sneezes")
+ if(miming)
message = "sneezes."
m_type = 1
else
- if (!muzzled)
+ if(!muzzled)
message = "sneezes."
+ if(gender == FEMALE)
+ playsound(src, species.female_sneeze_sound, 70)
+ else
+ playsound(src, species.male_sneeze_sound, 70)
m_type = 2
else
message = "makes a strange noise."
@@ -565,18 +599,59 @@
else
message = "sadly can't find anybody to give daps to, and daps [get_visible_gender() == MALE ? "himself" : get_visible_gender() == FEMALE ? "herself" : "themselves"]. Shameful."
- if ("scream")
- if (miming)
+ if("slap", "slaps")
+ m_type = 1
+ if(!restrained())
+ var/M = null
+ if(param)
+ for(var/mob/A in view(1, null))
+ if(param == A.name)
+ M = A
+ break
+ if(M)
+ message = "slaps [M] across the face. Ouch!"
+ playsound(loc, 'sound/effects/snap.ogg', 50, 1)
+ else
+ message = "slaps [get_visible_gender() == MALE ? "himself" : get_visible_gender() == FEMALE ? "herself" : "themselves"]!"
+ playsound(loc, 'sound/effects/snap.ogg', 50, 1)
+
+ if("scream", "screams")
+ if(miming)
message = "acts out a scream!"
m_type = 1
else
- if (!muzzled)
- message = "screams!"
+ if(!muzzled)
+ message = "[species.scream_verb]!"
m_type = 2
+ /* Removed, pending the location of some actually good, properly licensed sounds.
+ if(gender == FEMALE)
+ playsound(loc, "[species.female_scream_sound]", 80, 1)
+ else
+ playsound(loc, "[species.male_scream_sound]", 80, 1) //default to male screams if no gender is present.
+ */
else
message = "makes a very loud noise."
m_type = 2
+ if("snap", "snaps")
+ m_type = 2
+ var/mob/living/carbon/human/H = src
+ var/obj/item/organ/external/L = H.get_organ("l_hand")
+ var/obj/item/organ/external/R = H.get_organ("r_hand")
+ var/left_hand_good = 0
+ var/right_hand_good = 0
+ if(L && (!(L.status & ORGAN_DESTROYED)) && (!(L.splinted)) && (!(L.status & ORGAN_BROKEN)))
+ left_hand_good = 1
+ if(R && (!(R.status & ORGAN_DESTROYED)) && (!(R.splinted)) && (!(R.status & ORGAN_BROKEN)))
+ right_hand_good = 1
+
+ if(!left_hand_good && !right_hand_good)
+ to_chat(usr, "You need at least one hand in good working order to snap your fingers.")
+ return
+
+ message = "snaps [get_visible_gender() == MALE ? "his" : get_visible_gender() == FEMALE ? "her" : "their"] fingers."
+ playsound(loc, 'sound/effects/fingersnap.ogg', 50, 1, -3)
+
if("swish")
src.animate_tail_once()
@@ -597,18 +672,14 @@
return
if ("help")
- src << {"blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag,
-frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, handshake, hug-(none)/mob, laugh, look-(none)/mob, moan, mumble, nod, pale, point-atom,
-raise, salute, shake, shiver, shrug, sigh, signal-#1-10, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, sway/wag, swish, tremble, twitch,
-twitch_v, vomit, whimper, wink, yawn"}
+ src << "blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag, \
+ frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, handshake, hug-(none)/mob, laugh, look-(none)/mob, moan, mumble, nod, pale, point-atom, \
+ raise, salute, scream, sneeze, shake, shiver, shrug, sigh, signal-#1-10, slap-(none)/mob, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, sway/wag, swish, tremble, twitch, \
+ twitch_v, vomit, whimper, wink, yawn. Synthetics: beep, buzz, yes, no, rcough, rsneeze, ping"
else
src << "\blue Unusable emote '[act]'. Say *help for a list."
-
-
-
-
if (message)
log_emote("[name]/[key] : [message]")
custom_emote(m_type,message)
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index ca98cadd076..90f80ed267f 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -82,6 +82,20 @@
var/datum/gender/T = gender_datums[get_gender()]
if(skipjumpsuit && skipface) //big suits/masks/helmets make it hard to tell their gender
T = gender_datums[PLURAL]
+
+ else if(species && species.ambiguous_genders)
+ var/can_detect_gender = FALSE
+ if(isobserver(user)) // Ghosts are all knowing.
+ can_detect_gender = TRUE
+ if(issilicon(user)) // Borgs are too because science.
+ can_detect_gender = TRUE
+ else if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.species && istype(species, H.species))
+ can_detect_gender = TRUE
+
+ if(!can_detect_gender)
+ T = gender_datums[PLURAL] // Species with ambiguous_genders will not show their true gender upon examine if the examiner is not also the same species.
else
if(icon)
msg += "\icon[icon] " //fucking BYOND: this should stop dreamseeker crashing if we -somehow- examine somebody before their icon is generated
@@ -361,6 +375,11 @@
if(((temp.status & ORGAN_BROKEN) && temp.brute_dam > temp.min_broken_damage) || (temp.status & ORGAN_MUTATED))
wound_flavor_text["[temp.name]"] += "[T.His] [temp.name] is dented and swollen! "
+ if(temp.germ_level > INFECTION_LEVEL_TWO && !(temp.status & ORGAN_DEAD))
+ wound_flavor_text["[temp.name]"] += "[T.His] [temp.name] looks very infected! "
+ else if(temp.status & ORGAN_DEAD)
+ wound_flavor_text["[temp.name]"] += "[T.His] [temp.name] looks rotten! "
+
if(!wound_flavor_text["[temp.name]"] && (temp.status & ORGAN_BLEEDING))
is_bleeding["[temp.name]"] = "[T.His] [temp.name] is bleeding! "
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 5d40b57b1a8..8325cc3dfeb 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -5,7 +5,7 @@
icon = 'icons/mob/human.dmi'
icon_state = "body_m_s"
- var/list/hud_list[10]
+ var/list/hud_list[TOTAL_HUDS]
var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us.
var/obj/item/weapon/rig/wearing_rig // This is very not good, but it's much much better than calling get_rig() every update_canmove() call.
var/last_push_time //For human_attackhand.dm, keeps track of the last use of disarm
@@ -33,7 +33,7 @@
hud_list[HEALTH_HUD] = new /image/hud_overlay('icons/mob/hud_med.dmi', src, "100")
hud_list[STATUS_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealthy")
hud_list[LIFE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudhealthy")
- hud_list[ID_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudunknown")
+ hud_list[ID_HUD] = new /image/hud_overlay(using_map.id_hud_icons, src, "hudunknown")
hud_list[WANTED_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank")
hud_list[IMPLOYAL_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank")
hud_list[IMPCHEM_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank")
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index 8a06c1115b1..fe6381c6db9 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -13,9 +13,6 @@
if(force_max_speed)
return -3 // Returning -1 will actually result in a slowdown for Teshari.
- if(CE_SPEEDBOOST in chem_effects)
- return -3
-
var/health_deficiency = (maxHealth - health)
if(health_deficiency >= 40) tally += (health_deficiency / 25)
@@ -79,6 +76,15 @@
var/obj/item/pulled = pulling
tally += max(pulled.slowdown, 0)
+ var/turf/T = get_turf(src)
+ if(T && T.movement_cost)
+ tally += T.movement_cost
+
+ if(CE_SPEEDBOOST in chem_effects)
+ if (tally >= 0) // cut any penalties in half
+ tally = tally/2
+ tally -= 1 // give 'em a buff on top.
+
return (tally+config.human_delay)
/mob/living/carbon/human/Process_Spacemove(var/check_drift = 0)
diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm
index b3518055d5d..3b12431cab6 100644
--- a/code/modules/mob/living/carbon/human/human_organs.dm
+++ b/code/modules/mob/living/carbon/human/human_organs.dm
@@ -17,6 +17,8 @@
var/damage_this_tick = getToxLoss()
for(var/obj/item/organ/external/O in organs)
damage_this_tick += O.burn_dam + O.brute_dam
+ if(O.germ_level)
+ damage_this_tick += 1 //Just tap it if we have germs so we can process those
if(damage_this_tick > last_dam)
. = TRUE
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 1a9a986dd1d..ef6bf12729b 100644
--- a/code/modules/mob/living/carbon/human/species/outsider/vox.dm
+++ b/code/modules/mob/living/carbon/human/species/outsider/vox.dm
@@ -22,6 +22,14 @@
speech_sounds = list('sound/voice/shriek1.ogg')
speech_chance = 20
+ scream_verb = "shrieks"
+ male_scream_sound = 'sound/voice/shriek1.ogg'
+ female_scream_sound = 'sound/voice/shriek1.ogg'
+ male_cough_sounds = list('sound/voice/shriekcough.ogg')
+ female_cough_sounds = list('sound/voice/shriekcough.ogg')
+ male_sneeze_sound = 'sound/voice/shrieksneeze.ogg'
+ female_sneeze_sound = 'sound/voice/shrieksneeze.ogg'
+
warning_low_pressure = 50
hazard_low_pressure = 0
diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm
index 6a3b4c7ad1d..6ea0ed68898 100644
--- a/code/modules/mob/living/carbon/human/species/species.dm
+++ b/code/modules/mob/living/carbon/human/species/species.dm
@@ -50,6 +50,15 @@
var/num_alternate_languages = 0 // How many secondary languages are available to select at character creation
var/name_language = LANGUAGE_GALCOM // The language to use when determining names for this species, or null to use the first name/last name generator
+ //Soundy emotey things.
+ var/scream_verb = "screams"
+ var/male_scream_sound //= 'sound/goonstation/voice/male_scream.ogg' Removed due to licensing, replace!
+ var/female_scream_sound //= 'sound/goonstation/voice/female_scream.ogg' Removed due to licensing, replace!
+ var/male_cough_sounds = list('sound/effects/mob_effects/m_cougha.ogg','sound/effects/mob_effects/m_coughb.ogg', 'sound/effects/mob_effects/m_coughc.ogg')
+ var/female_cough_sounds = list('sound/effects/mob_effects/f_cougha.ogg','sound/effects/mob_effects/f_coughb.ogg')
+ var/male_sneeze_sound = 'sound/effects/mob_effects/sneeze.ogg'
+ var/female_sneeze_sound = 'sound/effects/mob_effects/f_sneeze.ogg'
+
// Combat vars.
var/total_health = 100 // Point at which the mob will enter crit.
var/list/unarmed_types = list( // Possible unarmed attacks that the mob will use in combat,
@@ -156,6 +165,7 @@
)
var/list/genders = list(MALE, FEMALE)
+ var/ambiguous_genders = FALSE // If true, people examining a member of this species whom are not also the same species will see them as gender neutral. Because aliens.
// Bump vars
var/bump_flag = HUMAN // What are we considered to be when bumped?
@@ -187,12 +197,18 @@
return sanitizeName(name)
/datum/species/proc/equip_survival_gear(var/mob/living/carbon/human/H,var/extendedtank = 1)
+ var/boxtype = /obj/item/weapon/storage/box/survival //Default survival box
+ if(H.isSynthetic())
+ boxtype = /obj/item/weapon/storage/box //Empty box for synths
+ else if(extendedtank)
+ boxtype = /obj/item/weapon/storage/box/engineer //Special box for engineers
+
if(H.backbag == 1)
- if (extendedtank) H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(H), slot_r_hand)
- else H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H), slot_r_hand)
+ if (extendedtank) H.equip_to_slot_or_del(new boxtype(H), slot_r_hand)
+ else H.equip_to_slot_or_del(new boxtype(H), slot_r_hand)
else
- if (extendedtank) H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(H.back), slot_in_backpack)
- else H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H.back), slot_in_backpack)
+ if (extendedtank) H.equip_to_slot_or_del(new boxtype(H.back), slot_in_backpack)
+ else H.equip_to_slot_or_del(new boxtype(H.back), slot_in_backpack)
/datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs.
@@ -305,3 +321,7 @@
// Called in life() when the mob has no client.
/datum/species/proc/handle_npc(var/mob/living/carbon/human/H)
return
+
+// Called when lying down on a water tile.
+/datum/species/proc/can_breathe_water()
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
index e7b4588e8fe..e239b8118c0 100644
--- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm
+++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm
@@ -28,6 +28,9 @@ var/datum/species/shapeshifter/promethean/prometheans
breath_type = null
poison_type = null
+ male_cough_sounds = list('sound/effects/slime_squish.ogg')
+ female_cough_sounds = list('sound/effects/slime_squish.ogg')
+
gluttonous = 1
virus_immune = 1
blood_volume = 560
diff --git a/code/modules/mob/living/carbon/human/species/station/seromi.dm b/code/modules/mob/living/carbon/human/species/station/seromi.dm
index df2bbd8cc86..120400413b3 100644
--- a/code/modules/mob/living/carbon/human/species/station/seromi.dm
+++ b/code/modules/mob/living/carbon/human/species/station/seromi.dm
@@ -38,6 +38,8 @@
blood_volume = 400
hunger_factor = 0.2
+ ambiguous_genders = TRUE
+
spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED
appearance_flags = HAS_HAIR_COLOR | HAS_SKIN_COLOR | HAS_EYE_COLOR
bump_flag = MONKEY
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 28eb05bc253..868c2d2f687 100644
--- a/code/modules/mob/living/carbon/human/species/station/station.dm
+++ b/code/modules/mob/living/carbon/human/species/station/station.dm
@@ -162,6 +162,8 @@
darksight = 4
+ ambiguous_genders = TRUE
+
spawn_flags = SPECIES_CAN_JOIN | SPECIES_IS_WHITELISTED
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR
@@ -193,6 +195,9 @@
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
)
+/datum/species/skrell/can_breathe_water()
+ return TRUE
+
/datum/species/diona
name = "Diona"
name_plural = "Dionaea"
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 3f4c00f8a57..2a29d2d1d97 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -117,7 +117,7 @@ Please contact me on #coderbus IRC. ~Carn x
#define GLOVES_LAYER 9
#define BELT_LAYER 10
#define SUIT_LAYER 11
-#define TAIL_LAYER 12 //bs12 specific.
+#define TAIL_LAYER 12 //bs12 specific. //In a perfect world the parts of the tail that show between legs would be on a new layer. Until then, sprite's been tweaked
#define GLASSES_LAYER 13
#define BELT_LAYER_ALT 14
#define SUIT_STORE_LAYER 15
@@ -132,8 +132,9 @@ Please contact me on #coderbus IRC. ~Carn x
#define L_HAND_LAYER 24
#define R_HAND_LAYER 25
#define FIRE_LAYER 26 //If you're on fire
-#define TARGETED_LAYER 27 //BS12: Layer for the target overlay from weapon targeting system
-#define TOTAL_LAYERS 27
+#define WATER_LAYER 27 //If you're submerged in water.
+#define TARGETED_LAYER 28 //BS12: Layer for the target overlay from weapon targeting system
+#define TOTAL_LAYERS 29
//////////////////////////////////
/mob/living/carbon/human
@@ -461,6 +462,7 @@ var/global/list/damage_icon_parts = list()
update_inv_legcuffed(0)
update_inv_pockets(0)
update_fire(0)
+ update_water(0)
update_surgery(0)
UpdateDamageIcon()
update_icons()
@@ -893,6 +895,11 @@ var/global/list/damage_icon_parts = list()
if(hud_used)
hud_used.hidden_inventory_update() //Updates the screenloc of the items on the 'other' inventory bar
+//update whether handcuffs appears on our hud.
+/mob/living/carbon/proc/update_hud_handcuffed()
+ if(hud_used && hud_used.l_hand_hud_object && hud_used.r_hand_hud_object)
+ hud_used.l_hand_hud_object.update_icon()
+ hud_used.r_hand_hud_object.update_icon()
/mob/living/carbon/human/update_inv_handcuffed(var/update_icons=1)
if(handcuffed)
@@ -911,6 +918,8 @@ var/global/list/damage_icon_parts = list()
else
overlays_standing[HANDCUFF_LAYER] = null
+
+ update_hud_handcuffed()
if(update_icons) update_icons()
/mob/living/carbon/human/update_inv_legcuffed(var/update_icons=1)
@@ -1116,6 +1125,17 @@ var/global/list/damage_icon_parts = list()
if(update_icons) update_icons()
+/mob/living/carbon/human/update_water(var/update_icons=1)
+ overlays_standing[WATER_LAYER] = null
+ var/depth = check_submerged()
+ if(depth)
+ if(!lying)
+ overlays_standing[WATER_LAYER] = image("icon" = 'icons/mob/submerged.dmi', "icon_state" = "human_swimming_[depth]")
+ // Lying sideways with the overlay looked strange. Another overlay will be needed in the future.
+
+ if(update_icons)
+ update_icons()
+
/mob/living/carbon/human/proc/update_surgery(var/update_icons=1)
overlays_standing[SURGERY_LEVEL] = null
var/image/total = new
@@ -1151,4 +1171,5 @@ var/global/list/damage_icon_parts = list()
#undef R_HAND_LAYER
#undef TARGETED_LAYER
#undef FIRE_LAYER
+#undef WATER_LAYER
#undef TOTAL_LAYERS
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index e4baab95ede..dfe57c55b2d 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -783,6 +783,7 @@ default behaviour is:
density = 0
if(l_hand) unEquip(l_hand)
if(r_hand) unEquip(r_hand)
+ update_water() // Submerges the mob.
else
density = initial(density)
@@ -801,3 +802,10 @@ default behaviour is:
update_icons()
return canmove
+/mob/living/proc/update_water() // Involves overlays for humans. Maybe we'll get submerged sprites for borgs in the future?
+ return
+
+/mob/living/proc/can_feel_pain(var/check_organ)
+ if(isSynthetic())
+ return FALSE
+ return TRUE
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 76be73da6d1..17eff101bb4 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -92,13 +92,6 @@
src.visible_message("\red [src] triggers their deadman's switch!")
signaler.signal()
- //Stun Beams
- if(P.taser_effect)
- stun_effect_act(0, P.agony, def_zone, P)
- src <<"\red You have been hit by [P]!"
- qdel(P)
- return
-
//Armor
var/absorb = run_armor_check(def_zone, P.check_armour, P.armor_penetration)
var/proj_sharp = is_sharp(P)
@@ -107,6 +100,15 @@
proj_sharp = 0
proj_edge = 0
+ //Stun Beams
+ if(P.taser_effect)
+ stun_effect_act(0, P.agony, def_zone, P)
+ src <<"\red You have been hit by [P]!"
+ if(!P.nodamage)
+ apply_damage(P.damage, P.damage_type, def_zone, absorb, 0, P, sharp=proj_sharp, edge=proj_edge)
+ qdel(P)
+ return
+
if(!P.nodamage)
apply_damage(P.damage, P.damage_type, def_zone, absorb, 0, P, sharp=proj_sharp, edge=proj_edge)
P.on_hit(src, absorb, def_zone)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 2ef6e62c9d3..1aa424ea887 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -52,7 +52,7 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c
density = 1
status_flags = CANSTUN|CANPARALYSE|CANPUSH
shouldnt_see = list(/obj/effect/rune)
- var/list/network = list(station_short)
+ var/list/network = list(NETWORK_DEFAULT)
var/obj/machinery/camera/camera = null
var/list/connected_robots = list()
var/aiRestorePowerRoutine = 0
@@ -132,7 +132,7 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c
if (istype(L, /datum/ai_laws))
laws = L
else
- laws = new base_law_type
+ laws = new using_map.default_law_type
aiMulti = new(src)
aiRadio = new(src)
@@ -398,12 +398,12 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c
if(emergency_message_cooldown)
usr << "Arrays recycling. Please stand by."
return
- var/input = sanitize(input(usr, "Please choose a message to transmit to [boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", ""))
+ var/input = sanitize(input(usr, "Please choose a message to transmit to [using_map.boss_short] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", ""))
if(!input)
return
CentCom_announce(input, usr)
usr << "Message transmitted."
- log_say("[key_name(usr)] has made an IA [boss_short] announcement: [input]")
+ log_say("[key_name(usr)] has made an IA [using_map.boss_short] announcement: [input]")
emergency_message_cooldown = 1
spawn(300)
emergency_message_cooldown = 0
@@ -545,82 +545,93 @@ var/list/ai_verbs_hidden = list( // For why this exists, refer to https://xkcd.c
return
var/input
- if(alert("Would you like to select a hologram based on a crew member or switch to unique avatar?",,"Crew Member","Unique")=="Crew Member")
+ var/choice = alert("Would you like to select a hologram based on a (visible) crew member, switch to unique avatar, or load your character from your character slot?",,"Crew Member","Unique","My Character")
- var/personnel_list[] = list()
+ switch(choice)
+ if("Crew Member")
+ var/list/targets = trackable_mobs()
+ if(targets.len)
+ input = input("Select a crew member:") as null|anything in targets //The definition of "crew member" is a little loose...
+ //This is torture, I know. If someone knows a better way...
+ if(!input) return
+ var/new_holo = getHologramIcon(getCompoundIcon(targets[input]))
+ qdel(holo_icon)
+ holo_icon = new_holo
- for(var/datum/data/record/t in data_core.locked)//Look in data core locked.
- personnel_list["[t.fields["name"]]: [t.fields["rank"]]"] = t.fields["image"]//Pull names, rank, and image.
+ else
+ alert("No suitable records found. Aborting.")
- if(personnel_list.len)
- input = input("Select a crew member:") as null|anything in personnel_list
- var/icon/character_icon = personnel_list[input]
- if(character_icon)
- qdel(holo_icon)//Clear old icon so we're not storing it in memory.
- holo_icon = getHologramIcon(icon(character_icon))
- else
- alert("No suitable records found. Aborting.")
+ if("My Character")
+ if(!client || !client.prefs) return
+ var/mob/living/carbon/human/dummy/dummy = new ()
+ //This doesn't include custom_items because that's ... hard.
+ client.prefs.dress_preview_mob(dummy)
+ sleep(1 SECOND) //Strange bug in preview code? Without this, certain things won't show up. Yay race conditions?
+ dummy.regenerate_icons()
- else
- var/icon_list[] = list(
- "default",
- "floating face",
- "carp",
- "ian",
- "runtime",
- "poly",
- "pun pun",
- "male human",
- "female human",
- "male unathi",
- "female unathi",
- "male tajara",
- "female tajara",
- "male tesharii",
- "female tesharii",
- "male skrell",
- "female skrell"
- )
- input = input("Please select a hologram:") as null|anything in icon_list
- if(input)
+ var/new_holo = getHologramIcon(getCompoundIcon(dummy))
qdel(holo_icon)
- switch(input)
- if("default")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))
- if("floating face")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo2"))
- if("carp")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo4"))
- if("ian")
- holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"corgi"))
- if("runtime")
- holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"cat"))
- if("poly")
- holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"parrot_fly"))
- if("pun pun")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"punpun"))
- if("male human")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holohumm"))
- if("female human")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holohumf"))
- if("male unathi")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holounam"))
- if("female unathi")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holounaf"))
- if("male tajara")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotajm"))
- if("female tajara")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotajf"))
- if("male tesharii")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotesm"))
- if("female tesharii")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotesf"))
- if("male skrell")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holoskrm"))
- if("female skrell")
- holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holoskrf"))
+ qdel(dummy)
+ holo_icon = new_holo
- return
+ else //One from the dmi.
+ var/icon_list[] = list(
+ "default",
+ "floating face",
+ "carp",
+ "ian",
+ "runtime",
+ "poly",
+ "pun pun",
+ "male human",
+ "female human",
+ "male unathi",
+ "female unathi",
+ "male tajara",
+ "female tajara",
+ "male tesharii",
+ "female tesharii",
+ "male skrell",
+ "female skrell"
+ )
+ input = input("Please select a hologram:") as null|anything in icon_list
+ if(input)
+ qdel(holo_icon)
+ switch(input)
+ if("default")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))
+ if("floating face")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo2"))
+ if("carp")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo4"))
+ if("ian")
+ holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"corgi"))
+ if("runtime")
+ holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"cat"))
+ if("poly")
+ holo_icon = getHologramIcon(icon('icons/mob/animal.dmi',"parrot_fly"))
+ if("pun pun")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"punpun"))
+ if("male human")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holohumm"))
+ if("female human")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holohumf"))
+ if("male unathi")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holounam"))
+ if("female unathi")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holounaf"))
+ if("male tajara")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotajm"))
+ if("female tajara")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotajf"))
+ if("male tesharii")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotesm"))
+ if("female tesharii")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holotesf"))
+ if("male skrell")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holoskrm"))
+ if("female skrell")
+ holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holoskrf"))
//Toggles the luminosity and applies it by re-entereing the camera.
/mob/living/silicon/ai/proc/toggle_camera_light()
diff --git a/code/modules/mob/living/silicon/ai/malf.dm b/code/modules/mob/living/silicon/ai/malf.dm
index adafb233fb5..c33563734ff 100644
--- a/code/modules/mob/living/silicon/ai/malf.dm
+++ b/code/modules/mob/living/silicon/ai/malf.dm
@@ -62,7 +62,7 @@
// Off-Station APCs should not count towards CPU generation.
for(var/obj/machinery/power/apc/A in hacked_apcs)
- if(A.z in config.station_levels)
+ if(A.z in using_map.station_levels)
cpu_gain += 0.004
cpu_storage += 10
diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm
index 5f7b07489b9..de4c7d2a15c 100644
--- a/code/modules/mob/living/silicon/laws.dm
+++ b/code/modules/mob/living/silicon/laws.dm
@@ -4,7 +4,7 @@
/mob/living/silicon/proc/laws_sanity_check()
if (!src.laws)
- laws = new base_law_type
+ laws = new using_map.default_law_type
/mob/living/silicon/proc/has_zeroth_law()
return laws.zeroth_law != null
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index dbe09db217c..232a1cec945 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -102,7 +102,7 @@ var/list/mob_hat_cache = list()
if(!laws) laws = new law_type
if(!module) module = new module_type(src)
- flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
+ flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[using_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
//Redefining some robot procs...
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 737841d4cef..26e1b264fda 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
@@ -16,7 +16,7 @@
idle_power_usage = 20
active_power_usage = 5000
- var/fabricator_tag = station_short+" Upper Level"
+ var/fabricator_tag = "Upper Level"
var/drone_progress = 0
var/produce_drones = 1
var/time_last_drone = 500
@@ -27,7 +27,7 @@
/obj/machinery/drone_fabricator/derelict
name = "construction drone fabricator"
- fabricator_tag = station_short+" Depths"
+ fabricator_tag = "Depths"
drone_type = /mob/living/silicon/robot/drone/construction
/obj/machinery/drone_fabricator/New()
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index cbce7c878c3..4359c8174c3 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -120,7 +120,7 @@
if(!scrambledcodes && !camera)
camera = new /obj/machinery/camera(src)
camera.c_tag = real_name
- camera.replace_networks(list(NETWORK_EXODUS,NETWORK_ROBOTS))
+ camera.replace_networks(list(NETWORK_DEFAULT,NETWORK_ROBOTS))
if(wires.IsIndexCut(BORG_WIRE_CAMERA))
camera.status = 0
@@ -689,7 +689,7 @@
overlays += "eyes-[module_sprites[icontype]]"
if(opened)
- var/panelprefix = custom_sprite ? src.ckey : "ov"
+ var/panelprefix = custom_sprite ? "[src.ckey]-[src.name]" : "ov"
if(wiresexposed)
overlays += "[panelprefix]-openpanel +w"
else if(cell)
@@ -707,6 +707,10 @@
icon_state = module_sprites[icontype]
return
+ if(typing)
+ typing = FALSE
+ set_typing_indicator(1)
+
/mob/living/silicon/robot/proc/installed_modules()
if(weapon_lock)
src << "\red Weapon lock active, unable to use modules! Count:[weaponlock_time]"
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 6fb89dd3d91..20ec5a5c069 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -190,6 +190,7 @@ var/global/list/robot_modules = list(
/obj/item/weapon/robot_module/robot/medical/surgeon/New()
..()
+ src.modules += new /obj/item/borg/sight/hud/med(src)
src.modules += new /obj/item/device/healthanalyzer(src)
src.modules += new /obj/item/weapon/reagent_containers/borghypo(src)
src.modules += new /obj/item/weapon/surgical/scalpel(src)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index f84021b26ac..738e9969676 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -65,7 +65,13 @@
src.take_organ_damage(0,20,emp=1)
confused = (min(confused + 5, 30))
if(2)
+ src.take_organ_damage(0,15,emp=1)
+ confused = (min(confused + 4, 30))
+ if(3)
src.take_organ_damage(0,10,emp=1)
+ confused = (min(confused + 3, 30))
+ if(4)
+ src.take_organ_damage(0,5,emp=1)
confused = (min(confused + 2, 30))
flash_eyes(affect_silicon = 1)
src << "*BZZZT*"
diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/aliens/alien.dm
similarity index 95%
rename from code/modules/mob/living/simple_animal/hostile/alien.dm
rename to code/modules/mob/living/simple_animal/aliens/alien.dm
index e47d88aeb5f..77485590176 100644
--- a/code/modules/mob/living/simple_animal/hostile/alien.dm
+++ b/code/modules/mob/living/simple_animal/aliens/alien.dm
@@ -1,172 +1,204 @@
-/mob/living/simple_animal/hostile/alien
- name = "alien hunter"
- desc = "Hiss!"
- icon = 'icons/mob/alien.dmi'
- icon_state = "alienh_running"
- icon_living = "alienh_running"
- icon_dead = "alien_l"
- icon_gib = "syndicate_gib"
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
- speed = -1
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat
- maxHealth = 100
- health = 100
- harm_intent_damage = 5
- melee_damage_lower = 25
- melee_damage_upper = 25
- attacktext = "slashed"
- a_intent = I_HURT
- attack_sound = 'sound/weapons/bladeslice.ogg'
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- unsuitable_atoms_damage = 15
- faction = "alien"
- environment_smash = 2
- status_flags = CANPUSH
- minbodytemp = 0
- heat_damage_per_tick = 20
-
-
-/mob/living/simple_animal/hostile/alien/drone
- name = "alien drone"
- icon_state = "aliend_running"
- icon_living = "aliend_running"
- icon_dead = "aliend_l"
- health = 60
- melee_damage_lower = 15
- melee_damage_upper = 15
-
-/mob/living/simple_animal/hostile/alien/sentinel
- name = "alien sentinel"
- icon_state = "aliens_running"
- icon_living = "aliens_running"
- icon_dead = "aliens_l"
- health = 120
- melee_damage_lower = 15
- melee_damage_upper = 15
- ranged = 1
- projectiletype = /obj/item/projectile/neurotox
- projectilesound = 'sound/weapons/pierce.ogg'
-
-
-/mob/living/simple_animal/hostile/alien/queen
- name = "alien queen"
- icon_state = "alienq_running"
- icon_living = "alienq_running"
- icon_dead = "alienq_l"
- health = 250
- maxHealth = 250
- melee_damage_lower = 15
- melee_damage_upper = 15
- ranged = 1
- move_to_delay = 3
- projectiletype = /obj/item/projectile/neurotox
- projectilesound = 'sound/weapons/pierce.ogg'
- rapid = 1
- status_flags = 0
-
-/mob/living/simple_animal/hostile/alien/queen/large
- name = "alien empress"
- icon = 'icons/mob/alienqueen.dmi'
- icon_state = "queen_s"
- icon_living = "queen_s"
- icon_dead = "queen_dead"
- move_to_delay = 4
- maxHealth = 400
- health = 400
-
-/obj/item/projectile/neurotox
- damage = 30
- icon_state = "toxin"
-
-/mob/living/simple_animal/hostile/alien/death()
- ..()
- visible_message("[src] lets out a waning guttural screech, green blood bubbling from its maw...")
- playsound(src, 'sound/voice/hiss6.ogg', 100, 1)
-
-// Xenoarch aliens.
-/mob/living/simple_animal/hostile/samak
- name = "samak"
- desc = "A fast, armoured predator accustomed to hiding and ambushing in cold terrain."
- faction = "samak"
- icon_state = "samak"
- icon_living = "samak"
- icon_dead = "samak_dead"
- icon = 'icons/jungle.dmi'
- move_to_delay = 2
- maxHealth = 125
- health = 125
- speed = 2
- melee_damage_lower = 5
- melee_damage_upper = 15
- attacktext = "mauled"
- cold_damage_per_tick = 0
- speak_chance = 5
- speak = list("Hruuugh!","Hrunnph")
- emote_see = list("paws the ground","shakes its mane","stomps")
- emote_hear = list("snuffles")
-
-/mob/living/simple_animal/hostile/diyaab
- name = "diyaab"
- desc = "A small pack animal. Although omnivorous, it will hunt meat on occasion."
- faction = "diyaab"
- icon_state = "diyaab"
- icon_living = "diyaab"
- icon_dead = "diyaab_dead"
- icon = 'icons/jungle.dmi'
- move_to_delay = 1
- maxHealth = 25
- health = 25
- speed = 1
- melee_damage_lower = 1
- melee_damage_upper = 8
- attacktext = "gouged"
- cold_damage_per_tick = 0
- speak_chance = 5
- speak = list("Awrr?","Aowrl!","Worrl")
- emote_see = list("sniffs the air cautiously","looks around")
- emote_hear = list("snuffles")
-
-/mob/living/simple_animal/hostile/shantak
- name = "shantak"
- desc = "A piglike creature with a bright iridiscent mane that sparkles as though lit by an inner light. Don't be fooled by its beauty though."
- faction = "shantak"
- icon_state = "shantak"
- icon_living = "shantak"
- icon_dead = "shantak_dead"
- icon = 'icons/jungle.dmi'
- move_to_delay = 1
- maxHealth = 75
- health = 75
- speed = 1
- melee_damage_lower = 3
- melee_damage_upper = 12
- attacktext = "gouged"
- cold_damage_per_tick = 0
- speak_chance = 5
- speak = list("Shuhn","Shrunnph?","Shunpf")
- emote_see = list("scratches the ground","shakes out it's mane","tinkles gently")
-
-/mob/living/simple_animal/yithian
- name = "yithian"
- desc = "A friendly creature vaguely resembling an oversized snail without a shell."
- icon_state = "yithian"
- icon_living = "yithian"
- icon_dead = "yithian_dead"
- icon = 'icons/jungle.dmi'
-
-/mob/living/simple_animal/tindalos
- name = "tindalos"
- desc = "It looks like a large, flightless grasshopper."
- icon_state = "tindalos"
- icon_living = "tindalos"
- icon_dead = "tindalos_dead"
- icon = 'icons/jungle.dmi'
+/mob/living/simple_animal/hostile/alien
+ name = "alien hunter"
+ desc = "Hiss!"
+ icon = 'icons/mob/alien.dmi'
+ icon_state = "alienh_running"
+ icon_living = "alienh_running"
+ icon_dead = "alien_l"
+ icon_gib = "syndicate_gib"
+
+ faction = "xeno"
+ cooperative = 1
+ run_at_them = 0
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ maxHealth = 100
+ health = 100
+ speed = -1
+
+ harm_intent_damage = 5
+ melee_damage_lower = 25
+ melee_damage_upper = 25
+
+ attacktext = "slashed"
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ a_intent = I_HURT
+
+ environment_smash = 2
+ status_flags = CANPUSH
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+ heat_damage_per_tick = 20
+ unsuitable_atoms_damage = 15
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat
+
+/mob/living/simple_animal/hostile/alien/drone
+ name = "alien drone"
+ icon_state = "aliend_running"
+ icon_living = "aliend_running"
+ icon_dead = "aliend_l"
+ health = 60
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+
+/mob/living/simple_animal/hostile/alien/sentinel
+ name = "alien sentinel"
+ icon_state = "aliens_running"
+ icon_living = "aliens_running"
+ icon_dead = "aliens_l"
+ health = 120
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ ranged = 1
+ projectiletype = /obj/item/projectile/neurotox
+ projectilesound = 'sound/weapons/pierce.ogg'
+
+
+/mob/living/simple_animal/hostile/alien/queen
+ name = "alien queen"
+ icon_state = "alienq_running"
+ icon_living = "alienq_running"
+ icon_dead = "alienq_l"
+ health = 250
+ maxHealth = 250
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ ranged = 1
+ move_to_delay = 3
+ projectiletype = /obj/item/projectile/neurotox
+ projectilesound = 'sound/weapons/pierce.ogg'
+ rapid = 1
+ status_flags = 0
+
+/mob/living/simple_animal/hostile/alien/queen/large
+ name = "alien empress"
+ icon = 'icons/mob/alienqueen.dmi'
+ icon_state = "queen_s"
+ icon_living = "queen_s"
+ icon_dead = "queen_dead"
+ move_to_delay = 4
+ maxHealth = 400
+ health = 400
+
+/obj/item/projectile/neurotox
+ damage = 30
+ icon_state = "toxin"
+
+/mob/living/simple_animal/hostile/alien/death()
+ ..()
+ visible_message("[src] lets out a waning guttural screech, green blood bubbling from its maw...")
+ playsound(src, 'sound/voice/hiss6.ogg', 100, 1)
+
+// Xenoarch aliens.
+/mob/living/simple_animal/hostile/samak
+ name = "samak"
+ desc = "A fast, armoured predator accustomed to hiding and ambushing in cold terrain."
+ faction = "samak"
+ icon_state = "samak"
+ icon_living = "samak"
+ icon_dead = "samak_dead"
+ icon = 'icons/jungle.dmi'
+
+ faction = "samak"
+
+ maxHealth = 125
+ health = 125
+ speed = 2
+ move_to_delay = 2
+
+ melee_damage_lower = 5
+ melee_damage_upper = 15
+
+ attacktext = "mauled"
+ cold_damage_per_tick = 0
+
+ speak_chance = 5
+ speak = list("Hruuugh!","Hrunnph")
+ emote_see = list("paws the ground","shakes its mane","stomps")
+ emote_hear = list("snuffles")
+
+/mob/living/simple_animal/hostile/diyaab
+ name = "diyaab"
+ desc = "A small pack animal. Although omnivorous, it will hunt meat on occasion."
+ faction = "diyaab"
+ icon_state = "diyaab"
+ icon_living = "diyaab"
+ icon_dead = "diyaab_dead"
+ icon = 'icons/jungle.dmi'
+
+ faction = "diyaab"
+ cooperative = 1
+
+ maxHealth = 25
+ health = 25
+ speed = 1
+ move_to_delay = 1
+
+ melee_damage_lower = 1
+ melee_damage_upper = 8
+
+ attacktext = "gouged"
+ cold_damage_per_tick = 0
+
+ speak_chance = 5
+ speak = list("Awrr?","Aowrl!","Worrl")
+ emote_see = list("sniffs the air cautiously","looks around")
+ emote_hear = list("snuffles")
+
+/mob/living/simple_animal/hostile/shantak
+ name = "shantak"
+ desc = "A piglike creature with a bright iridiscent mane that sparkles as though lit by an inner light. Don't be fooled by its beauty though."
+ faction = "shantak"
+ icon_state = "shantak"
+ icon_living = "shantak"
+ icon_dead = "shantak_dead"
+ icon = 'icons/jungle.dmi'
+
+ faction = "shantak"
+
+ maxHealth = 75
+ health = 75
+ speed = 1
+ move_to_delay = 1
+
+ melee_damage_lower = 3
+ melee_damage_upper = 12
+
+ attacktext = "gouged"
+ cold_damage_per_tick = 0
+
+ speak_chance = 5
+ speak = list("Shuhn","Shrunnph?","Shunpf")
+ emote_see = list("scratches the ground","shakes out it's mane","tinkles gently")
+
+/mob/living/simple_animal/yithian
+ name = "yithian"
+ desc = "A friendly creature vaguely resembling an oversized snail without a shell."
+ icon_state = "yithian"
+ icon_living = "yithian"
+ icon_dead = "yithian_dead"
+ icon = 'icons/jungle.dmi'
+
+ faction = "yithian"
+
+/mob/living/simple_animal/tindalos
+ name = "tindalos"
+ desc = "It looks like a large, flightless grasshopper."
+ icon_state = "tindalos"
+ icon_living = "tindalos"
+ icon_dead = "tindalos_dead"
+ icon = 'icons/jungle.dmi'
+
+ faction = "tindalos"
diff --git a/code/modules/mob/living/simple_animal/hostile/creature.dm b/code/modules/mob/living/simple_animal/aliens/creature.dm
similarity index 94%
rename from code/modules/mob/living/simple_animal/hostile/creature.dm
rename to code/modules/mob/living/simple_animal/aliens/creature.dm
index b065a78ae94..544a44d0015 100644
--- a/code/modules/mob/living/simple_animal/hostile/creature.dm
+++ b/code/modules/mob/living/simple_animal/aliens/creature.dm
@@ -1,72 +1,73 @@
-/mob/living/simple_animal/hostile/creature
- name = "creature"
- desc = "A sanity-destroying otherthing."
- icon = 'icons/mob/critter.dmi'
- speak_emote = list("gibbers")
- icon_state = "otherthing"
- icon_living = "otherthing"
- icon_dead = "otherthing-dead"
- maxHealth = 40
- health = 40
-
- harm_intent_damage = 8
- melee_damage_lower = 5
- melee_damage_upper = 5
- attacktext = "chomped"
- attack_sound = 'sound/weapons/bite.ogg'
- faction = "creature"
- speed = 8
-
-/mob/living/simple_animal/hostile/creature/cult
- faction = "cult"
-
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
-
- supernatural = 1
-
-/mob/living/simple_animal/hostile/creature/cult/cultify()
- return
-
-/mob/living/simple_animal/hostile/creature/cult/Life()
- ..()
- check_horde()
-
-
-/mob/living/simple_animal/hostile/creature/strong
- maxHealth = 160
- health = 160
-
- harm_intent_damage = 5
- melee_damage_lower = 8
- melee_damage_upper = 25
-
-
-/mob/living/simple_animal/hostile/creature/strong/cult
- faction = "cult"
-
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
-
- supernatural = 1
-
-/mob/living/simple_animal/hostile/creature/cult/cultify()
- return
-
-/mob/living/simple_animal/hostile/creature/cult/Life()
- ..()
- check_horde()
+/mob/living/simple_animal/hostile/creature
+ name = "creature"
+ desc = "A sanity-destroying otherthing."
+ icon = 'icons/mob/critter.dmi'
+ icon_state = "otherthing"
+ icon_living = "otherthing"
+ icon_dead = "otherthing-dead"
+
+ faction = "creature"
+ maxHealth = 40
+ health = 40
+ speed = 8
+
+ harm_intent_damage = 8
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+
+ attacktext = "chomped"
+ attack_sound = 'sound/weapons/bite.ogg'
+
+ speak_emote = list("gibbers")
+
+/mob/living/simple_animal/hostile/creature/cult
+ faction = "cult"
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ supernatural = 1
+
+/mob/living/simple_animal/hostile/creature/cult/cultify()
+ return
+
+/mob/living/simple_animal/hostile/creature/cult/Life()
+ ..()
+ check_horde()
+
+/mob/living/simple_animal/hostile/creature/strong
+ maxHealth = 160
+ health = 160
+
+ harm_intent_damage = 5
+ melee_damage_lower = 8
+ melee_damage_upper = 25
+
+/mob/living/simple_animal/hostile/creature/strong/cult
+ faction = "cult"
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ supernatural = 1
+
+/mob/living/simple_animal/hostile/creature/cult/cultify()
+ return
+
+/mob/living/simple_animal/hostile/creature/cult/Life()
+ ..()
+ check_horde()
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/aliens/drone.dm
similarity index 88%
rename from code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
rename to code/modules/mob/living/simple_animal/aliens/drone.dm
index 24fb12633fc..3d1ae1bd02d 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm
+++ b/code/modules/mob/living/simple_animal/aliens/drone.dm
@@ -1,39 +1,29 @@
//malfunctioning combat drones
-/mob/living/simple_animal/hostile/retaliate/malf_drone
+/mob/living/simple_animal/hostile/malf_drone
name = "combat drone"
desc = "An automated combat drone armed with state of the art weaponry and shielding."
icon_state = "drone3"
icon_living = "drone3"
icon_dead = "drone_dead"
- ranged = 1
- rapid = 1
- speak_chance = 5
+
+ faction = "malf_drone"
+ maxHealth = 300
+ health = 300
+ speed = 8
+ stop_when_pulled = 0
+
turns_per_move = 3
response_help = "pokes"
response_disarm = "gently pushes aside"
response_harm = "hits"
- speak = list("ALERT.","Hostile-ile-ile entities dee-twhoooo-wected.","Threat parameterszzzz- szzet.","Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.")
- emote_see = list("beeps menacingly","whirrs threateningly","scans its immediate vicinity")
+
a_intent = I_HURT
- stop_automated_movement_when_pulled = 0
- health = 300
- maxHealth = 300
- speed = 8
+ ranged = 1
+ rapid = 1
projectiletype = /obj/item/projectile/beam/drone
projectilesound = 'sound/weapons/laser3.ogg'
destroy_surroundings = 0
- var/datum/effect/effect/system/ion_trail_follow/ion_trail
-
- //the drone randomly switches between these states because it's malfunctioning
- var/hostile_drone = 0
- //0 - retaliate, only attack enemies that attack it
- //1 - hostile, attack everything that comes near
-
- var/turf/patrol_target
- var/explode_chance = 1
- var/disabled = 0
- var/exploding = 0
//Drones aren't affected by atmos.
min_oxy = 0
@@ -46,10 +36,19 @@
max_n2 = 0
minbodytemp = 0
- var/has_loot = 1
- faction = "malf_drone"
+ speak_chance = 5
+ speak = list("ALERT.","Hostile-ile-ile entities dee-twhoooo-wected.","Threat parameterszzzz- szzet.","Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.")
+ emote_see = list("beeps menacingly","whirrs threateningly","scans its immediate vicinity")
-/mob/living/simple_animal/hostile/retaliate/malf_drone/New()
+
+ var/datum/effect/effect/system/ion_trail_follow/ion_trail
+ var/turf/patrol_target
+ var/explode_chance = 1
+ var/disabled = 0
+ var/exploding = 0
+ var/has_loot = 1
+
+/mob/living/simple_animal/hostile/malf_drone/New()
..()
if(prob(5))
projectiletype = /obj/item/projectile/beam/pulse/drone
@@ -58,17 +57,11 @@
ion_trail.set_up(src)
ion_trail.start()
-/mob/living/simple_animal/hostile/retaliate/malf_drone/Process_Spacemove(var/check_drift = 0)
+/mob/living/simple_animal/malf_drone/Process_Spacemove(var/check_drift = 0)
return 1
-/mob/living/simple_animal/hostile/retaliate/malf_drone/ListTargets()
- if(hostile_drone)
- return view(src, 10)
- else
- return ..()
-
//self repair systems have a chance to bring the drone back to life
-/mob/living/simple_animal/hostile/retaliate/malf_drone/Life()
+/mob/living/simple_animal/hostile/malf_drone/Life()
//emps and lots of damage can temporarily shut us down
if(disabled > 0)
@@ -99,12 +92,12 @@
//sometimes our targetting sensors malfunction, and we attack anyone nearby
if(prob(disabled ? 0 : 1))
- if(hostile_drone)
+ if(hostile)
src.visible_message("\blue \icon[src] [src] retracts several targetting vanes, and dulls it's running lights.")
- hostile_drone = 0
+ hostile = 0
else
src.visible_message("\red \icon[src] [src] suddenly lights up, and additional targetting vanes slide into place.")
- hostile_drone = 1
+ hostile = 1
if(health / maxHealth > 0.9)
icon_state = "drone3"
@@ -151,18 +144,18 @@
..()
//ion rifle!
-/mob/living/simple_animal/hostile/retaliate/malf_drone/emp_act(severity)
+/mob/living/simple_animal/hostile/malf_drone/emp_act(severity)
health -= rand(3,15) * (severity + 1)
disabled = rand(150, 600)
- hostile_drone = 0
+ hostile = 0
walk(src,0)
-/mob/living/simple_animal/hostile/retaliate/malf_drone/death()
+/mob/living/simple_animal/hostile/malf_drone/death()
..(null,"suddenly breaks apart.")
qdel(src)
-/mob/living/simple_animal/hostile/retaliate/malf_drone/Destroy()
- //some random debris left behind
+/mob/living/simple_animal/hostile/malf_drone/Destroy()
+ //More advanced than the default S_A loot system, for visual effect and random tech levels.
if(has_loot)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
diff --git a/code/modules/mob/living/simple_animal/hostile/faithless.dm b/code/modules/mob/living/simple_animal/aliens/faithless.dm
similarity index 85%
rename from code/modules/mob/living/simple_animal/hostile/faithless.dm
rename to code/modules/mob/living/simple_animal/aliens/faithless.dm
index dd20145b385..0b41471c329 100644
--- a/code/modules/mob/living/simple_animal/hostile/faithless.dm
+++ b/code/modules/mob/living/simple_animal/aliens/faithless.dm
@@ -1,83 +1,82 @@
-/mob/living/simple_animal/hostile/faithless
- name = "Faithless"
- desc = "The Wish Granter's faith in humanity, incarnate"
- icon_state = "faithless"
- icon_living = "faithless"
- icon_dead = "faithless_dead"
- speak_chance = 0
- turns_per_move = 5
- response_help = "passes through"
- response_disarm = "shoves"
- response_harm = "hits"
- speed = 8
- maxHealth = 50
- health = 50
-
- harm_intent_damage = 10
- melee_damage_lower = 5
- melee_damage_upper = 5
- attacktext = "gripped"
- attack_sound = 'sound/hallucinations/growl1.ogg'
-
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
- speed = 4
-
- faction = "faithless"
-
-/mob/living/simple_animal/hostile/faithless/Process_Spacemove(var/check_drift = 0)
- return 1
-
-/mob/living/simple_animal/hostile/faithless/FindTarget()
- . = ..()
- if(.)
- audible_emote("wails at [.]")
-
-/mob/living/simple_animal/hostile/faithless/AttackingTarget()
- . =..()
- var/mob/living/L = .
- if(istype(L))
- if(prob(12))
- L.Weaken(3)
- L.visible_message("\the [src] knocks down \the [L]!")
-
-/mob/living/simple_animal/hostile/faithless/cult
- faction = "cult"
- supernatural = 1
-
-/mob/living/simple_animal/hostile/faithless/cult/cultify()
- return
-
-/mob/living/simple_animal/hostile/faithless/cult/Life()
- ..()
- check_horde()
-
-
-
-
-/mob/living/simple_animal/hostile/faithless/strong
- maxHealth = 100
- health = 100
-
- harm_intent_damage = 5
- melee_damage_lower = 7
- melee_damage_upper = 20
-
-
-/mob/living/simple_animal/hostile/faithless/strong/cult
- faction = "cult"
- supernatural = 1
-
-/mob/living/simple_animal/hostile/faithless/cult/cultify()
- return
-
-/mob/living/simple_animal/hostile/faithless/cult/Life()
- ..()
+/mob/living/simple_animal/hostile/faithless
+ name = "Faithless"
+ desc = "The Wish Granter's faith in humanity, incarnate"
+ icon_state = "faithless"
+ icon_living = "faithless"
+ icon_dead = "faithless_dead"
+
+ faction = "faithless"
+ maxHealth = 50
+ health = 50
+ speed = 8
+
+ turns_per_move = 5
+ response_help = "passes through"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 10
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+
+ attacktext = "gripped"
+ attack_sound = 'sound/hallucinations/growl1.ogg'
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ speak_chance = 0
+
+/mob/living/simple_animal/hostile/faithless/Process_Spacemove(var/check_drift = 0)
+ return 1
+
+/mob/living/simple_animal/hostile/faithless/set_target()
+ . = ..()
+ if(.)
+ audible_emote("wails at [target_mob]")
+
+/mob/living/simple_animal/hostile/faithless/PunchTarget()
+ . = ..()
+ var/mob/living/L = .
+ if(istype(L))
+ if(prob(12))
+ L.Weaken(3)
+ L.visible_message("\the [src] knocks down \the [L]!")
+
+/mob/living/simple_animal/hostile/faithless/cult
+ faction = "cult"
+ supernatural = 1
+
+/mob/living/simple_animal/hostile/faithless/cult/cultify()
+ return
+
+/mob/living/simple_animal/hostile/faithless/cult/Life()
+ ..()
+ check_horde()
+
+/mob/living/simple_animal/hostile/faithless/strong
+ maxHealth = 100
+ health = 100
+
+ harm_intent_damage = 5
+ melee_damage_lower = 7
+ melee_damage_upper = 20
+
+
+/mob/living/simple_animal/hostile/faithless/strong/cult
+ faction = "cult"
+ supernatural = 1
+
+/mob/living/simple_animal/hostile/faithless/cult/cultify()
+ return
+
+/mob/living/simple_animal/hostile/faithless/cult/Life()
+ ..()
check_horde()
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/aliens/hivebot.dm
similarity index 90%
rename from code/modules/mob/living/simple_animal/hostile/hivebot.dm
rename to code/modules/mob/living/simple_animal/aliens/hivebot.dm
index e358f3e69ac..9770d61efea 100644
--- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm
+++ b/code/modules/mob/living/simple_animal/aliens/hivebot.dm
@@ -1,107 +1,111 @@
-/obj/item/projectile/hivebotbullet
- damage = 10
- damage_type = BRUTE
-
-/mob/living/simple_animal/hostile/hivebot
- name = "Hivebot"
- desc = "A small robot"
- icon = 'icons/mob/hivebot.dmi'
- icon_state = "basic"
- icon_living = "basic"
- icon_dead = "basic"
- health = 15
- maxHealth = 15
- melee_damage_lower = 2
- melee_damage_upper = 3
- attacktext = "clawed"
- projectilesound = 'sound/weapons/Gunshot.ogg'
- projectiletype = /obj/item/projectile/hivebotbullet
- faction = "hivebot"
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
- speed = 4
-
-/mob/living/simple_animal/hostile/hivebot/range
- name = "Hivebot"
- desc = "A smallish robot, this one is armed!"
- ranged = 1
-
-/mob/living/simple_animal/hostile/hivebot/rapid
- ranged = 1
- rapid = 1
-
-/mob/living/simple_animal/hostile/hivebot/strong
- name = "Strong Hivebot"
- desc = "A robot, this one is armed and looks tough!"
- health = 80
- ranged = 1
-
-
-/mob/living/simple_animal/hostile/hivebot/death()
- ..()
- visible_message("[src] blows apart!")
- new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc)
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(3, 1, src)
- s.start()
- qdel(src)
- return
-
-/mob/living/simple_animal/hostile/hivebot/tele//this still needs work
- name = "Beacon"
- desc = "Some odd beacon thing"
- icon = 'icons/mob/hivebot.dmi'
- icon_state = "def_radar-off"
- icon_living = "def_radar-off"
- health = 200
- maxHealth = 200
- status_flags = 0
- anchored = 1
- stop_automated_movement = 1
- var/bot_type = "norm"
- var/bot_amt = 10
- var/spawn_delay = 600
- var/turn_on = 0
- var/auto_spawn = 1
- proc
- warpbots()
-
-
- New()
- ..()
- var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
- smoke.set_up(5, 0, src.loc)
- smoke.start()
- visible_message("\red The [src] warps in!")
- playsound(src.loc, 'sound/effects/EMPulse.ogg', 25, 1)
-
- warpbots()
- icon_state = "def_radar"
- visible_message("\red The [src] turns on!")
- while(bot_amt > 0)
- bot_amt--
- switch(bot_type)
- if("norm")
- new /mob/living/simple_animal/hostile/hivebot(get_turf(src))
- if("range")
- new /mob/living/simple_animal/hostile/hivebot/range(get_turf(src))
- if("rapid")
- new /mob/living/simple_animal/hostile/hivebot/rapid(get_turf(src))
- spawn(100)
- qdel(src)
- return
-
-
- Life()
- ..()
- if(stat == 0)
- if(prob(2))//Might be a bit low, will mess with it likely
- warpbots()
-
+/mob/living/simple_animal/hostile/hivebot
+ name = "Hivebot"
+ desc = "A small robot"
+ icon = 'icons/mob/hivebot.dmi'
+ icon_state = "basic"
+ icon_living = "basic"
+ icon_dead = "basic"
+
+ faction = "hivebot"
+ maxHealth = 15
+ health = 15
+ speed = 4
+
+ melee_damage_lower = 2
+ melee_damage_upper = 3
+
+ attacktext = "clawed"
+ projectilesound = 'sound/weapons/Gunshot.ogg'
+ projectiletype = /obj/item/projectile/hivebotbullet
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+/mob/living/simple_animal/hostile/hivebot/range
+ name = "Hivebot"
+ desc = "A smallish robot, this one is armed!"
+ ranged = 1
+
+/mob/living/simple_animal/hostile/hivebot/range/rapid
+ rapid = 1
+
+/mob/living/simple_animal/hostile/hivebot/strong
+ name = "Strong Hivebot"
+ desc = "A robot, this one is armed and looks tough!"
+ health = 80
+ ranged = 1
+
+/mob/living/simple_animal/hostile/hivebot/death()
+ ..()
+ visible_message("[src] blows apart!")
+ new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc)
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ qdel(src)
+
+/mob/living/simple_animal/hostile/hivebot/tele//this still needs work
+ name = "Beacon"
+ desc = "Some odd beacon thing"
+ icon = 'icons/mob/hivebot.dmi'
+ icon_state = "def_radar-off"
+ icon_living = "def_radar-off"
+
+ health = 200
+ maxHealth = 200
+ status_flags = 0
+
+ anchored = 1
+ wander = 0
+ stop_automated_movement = 1
+
+ var/bot_type = "norm"
+ var/bot_amt = 10
+ var/spawn_delay = 600
+ var/turn_on = 0
+ var/auto_spawn = 1
+ proc
+ warpbots()
+
+
+ New()
+ ..()
+ var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
+ smoke.set_up(5, 0, src.loc)
+ smoke.start()
+ visible_message("\red The [src] warps in!")
+ playsound(src.loc, 'sound/effects/EMPulse.ogg', 25, 1)
+
+ warpbots()
+ icon_state = "def_radar"
+ visible_message("\red The [src] turns on!")
+ while(bot_amt > 0)
+ bot_amt--
+ switch(bot_type)
+ if("norm")
+ new /mob/living/simple_animal/hostile/hivebot(get_turf(src))
+ if("range")
+ new /mob/living/simple_animal/hostile/hivebot/range(get_turf(src))
+ if("rapid")
+ new /mob/living/simple_animal/hostile/hivebot/range/rapid(get_turf(src))
+ spawn(100)
+ qdel(src)
+ return
+
+
+ Life()
+ ..()
+ if(stat == 0)
+ if(prob(2))//Might be a bit low, will mess with it likely
+ warpbots()
+
+/obj/item/projectile/hivebotbullet
+ damage = 10
+ damage_type = BRUTE
diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/aliens/mimic.dm
similarity index 86%
rename from code/modules/mob/living/simple_animal/hostile/mimic.dm
rename to code/modules/mob/living/simple_animal/aliens/mimic.dm
index 4764dcd5479..6f0dbd9d3b5 100644
--- a/code/modules/mob/living/simple_animal/hostile/mimic.dm
+++ b/code/modules/mob/living/simple_animal/aliens/mimic.dm
@@ -1,195 +1,196 @@
-//
-// Abstract Class
-//
-
-/mob/living/simple_animal/hostile/mimic
- name = "crate"
- desc = "A rectangular steel crate."
- icon = 'icons/obj/storage.dmi'
- icon_state = "crate"
- icon_living = "crate"
-
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat
- response_help = "touches"
- response_disarm = "pushes"
- response_harm = "hits"
- speed = 4
- maxHealth = 250
- health = 250
-
- harm_intent_damage = 5
- melee_damage_lower = 8
- melee_damage_upper = 12
- attacktext = "attacked"
- attack_sound = 'sound/weapons/bite.ogg'
-
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
-
- faction = "mimic"
- move_to_delay = 8
-
-/mob/living/simple_animal/hostile/mimic/FindTarget()
- . = ..()
- if(.)
- audible_emote("growls at [.]")
-
-/mob/living/simple_animal/hostile/mimic/death()
- ..()
- qdel(src)
-
-//
-// Crate Mimic
-//
-
-
-// Aggro when you try to open them. Will also pickup loot when spawns and drop it when dies.
-/mob/living/simple_animal/hostile/mimic/crate
-
- attacktext = "bitten"
-
- stop_automated_movement = 1
- wander = 0
- var/attempt_open = 0
-
-// Pickup loot
-/mob/living/simple_animal/hostile/mimic/crate/initialize()
- ..()
- for(var/obj/item/I in loc)
- I.loc = src
-
-/mob/living/simple_animal/hostile/mimic/crate/DestroySurroundings()
- ..()
- if(prob(90))
- icon_state = "[initial(icon_state)]open"
- else
- icon_state = initial(icon_state)
-
-/mob/living/simple_animal/hostile/mimic/crate/ListTargets()
- if(attempt_open)
- return ..()
- return view(src, 1)
-
-/mob/living/simple_animal/hostile/mimic/crate/FindTarget()
- . = ..()
- if(.)
- trigger()
-
-/mob/living/simple_animal/hostile/mimic/crate/AttackingTarget()
- . = ..()
- if(.)
- icon_state = initial(icon_state)
-
-/mob/living/simple_animal/hostile/mimic/crate/proc/trigger()
- if(!attempt_open)
- visible_message("[src] starts to move!")
- attempt_open = 1
-
-/mob/living/simple_animal/hostile/mimic/crate/adjustBruteLoss(var/damage)
- trigger()
- ..(damage)
-
-/mob/living/simple_animal/hostile/mimic/crate/LoseTarget()
- ..()
- icon_state = initial(icon_state)
-
-/mob/living/simple_animal/hostile/mimic/crate/LostTarget()
- ..()
- icon_state = initial(icon_state)
-
-/mob/living/simple_animal/hostile/mimic/crate/death()
-
- var/obj/structure/closet/crate/C = new(get_turf(src))
- // Put loot in crate
- for(var/obj/O in src)
- O.loc = C
- ..()
-
-/mob/living/simple_animal/hostile/mimic/crate/AttackingTarget()
- . =..()
- var/mob/living/L = .
- if(istype(L))
- if(prob(15))
- L.Weaken(2)
- L.visible_message("\the [src] knocks down \the [L]!")
-
-//
-// Copy Mimic
-//
-
-var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/cable, /obj/structure/window, /obj/item/projectile/animate)
-
-/mob/living/simple_animal/hostile/mimic/copy
-
- health = 100
- maxHealth = 100
- var/mob/living/creator = null // the creator
- var/destroy_objects = 0
- var/knockdown_people = 0
-
-/mob/living/simple_animal/hostile/mimic/copy/New(loc, var/obj/copy, var/mob/living/creator)
- ..(loc)
- CopyObject(copy, creator)
-
-/mob/living/simple_animal/hostile/mimic/copy/death()
-
- for(var/atom/movable/M in src)
- M.loc = get_turf(src)
- ..()
-
-/mob/living/simple_animal/hostile/mimic/copy/ListTargets()
- // Return a list of targets that isn't the creator
- . = ..()
- return . - creator
-
-/mob/living/simple_animal/hostile/mimic/copy/proc/CopyObject(var/obj/O, var/mob/living/creator)
-
- if((istype(O, /obj/item) || istype(O, /obj/structure)) && !is_type_in_list(O, protected_objects))
-
- O.loc = src
- name = O.name
- desc = O.desc
- icon = O.icon
- icon_state = O.icon_state
- icon_living = icon_state
-
- if(istype(O, /obj/structure))
- health = (anchored * 50) + 50
- destroy_objects = 1
- if(O.density && O.anchored)
- knockdown_people = 1
- melee_damage_lower *= 2
- melee_damage_upper *= 2
- else if(istype(O, /obj/item))
- var/obj/item/I = O
- health = 15 * I.w_class
- melee_damage_lower = 2 + I.force
- melee_damage_upper = 2 + I.force
- move_to_delay = 2 * I.w_class
-
- maxHealth = health
- if(creator)
- src.creator = creator
- faction = "\ref[creator]" // very unique
- return 1
- return
-
-/mob/living/simple_animal/hostile/mimic/copy/DestroySurroundings()
- if(destroy_objects)
- ..()
-
-/mob/living/simple_animal/hostile/mimic/copy/AttackingTarget()
- . =..()
- if(knockdown_people)
- var/mob/living/L = .
- if(istype(L))
- if(prob(15))
- L.Weaken(1)
+//
+// Abstract Class
+//
+
+/mob/living/simple_animal/hostile/mimic
+ name = "crate"
+ desc = "A rectangular steel crate."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "crate"
+ icon_living = "crate"
+
+ faction = "mimic"
+
+ maxHealth = 250
+ health = 250
+ speed = 4
+ move_to_delay = 8
+
+ response_help = "touches"
+ response_disarm = "pushes"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 8
+ melee_damage_upper = 12
+ attacktext = "attacked"
+ attack_sound = 'sound/weapons/bite.ogg'
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat
+
+/mob/living/simple_animal/hostile/mimic/set_target()
+ . = ..()
+ if(.)
+ audible_emote("growls at [.]")
+
+/mob/living/simple_animal/mimic/death()
+ ..()
+ qdel(src)
+
+//
+// Crate Mimic
+//
+
+// Aggro when you try to open them. Will also pickup loot when spawns and drop it when dies.
+/mob/living/simple_animal/hostile/mimic/crate
+
+ attacktext = "bitten"
+
+ stop_automated_movement = 1
+ wander = 0
+ var/attempt_open = 0
+
+// Pickup loot
+/mob/living/simple_animal/hostile/mimic/crate/initialize()
+ ..()
+ for(var/obj/item/I in loc)
+ I.forceMove(src)
+
+/mob/living/simple_animal/hostile/mimic/crate/DestroySurroundings()
+ ..()
+ if(prob(90))
+ icon_state = "[initial(icon_state)]open"
+ else
+ icon_state = initial(icon_state)
+
+/mob/living/simple_animal/hostile/mimic/crate/ListTargets()
+ if(attempt_open)
+ return ..()
+ else
+ return ..(1)
+
+/mob/living/simple_animal/hostile/mimic/crate/set_target()
+ . = ..()
+ if(.)
+ trigger()
+
+/mob/living/simple_animal/hostile/mimic/crate/PunchTarget()
+ . = ..()
+ if(.)
+ icon_state = initial(icon_state)
+
+/mob/living/simple_animal/hostile/mimic/crate/proc/trigger()
+ if(!attempt_open)
+ visible_message("[src] starts to move!")
+ attempt_open = 1
+
+/mob/living/simple_animal/hostile/mimic/crate/adjustBruteLoss(var/damage)
+ trigger()
+ ..(damage)
+
+/mob/living/simple_animal/hostile/mimic/crate/LoseTarget()
+ ..()
+ icon_state = initial(icon_state)
+
+/mob/living/simple_animal/hostile/mimic/crate/LostTarget()
+ ..()
+ icon_state = initial(icon_state)
+
+/mob/living/simple_animal/hostile/mimic/crate/death()
+ var/obj/structure/closet/crate/C = new(get_turf(src))
+ // Put loot in crate
+ for(var/obj/O in src)
+ O.forceMove(C)
+ ..()
+
+/mob/living/simple_animal/hostile/mimic/crate/PunchTarget()
+ . =..()
+ var/mob/living/L = .
+ if(istype(L))
+ if(prob(15))
+ L.Weaken(2)
+ L.visible_message("\the [src] knocks down \the [L]!")
+
+//
+// Copy Mimic
+//
+
+var/global/list/protected_objects = list(/obj/structure/table, /obj/structure/cable, /obj/structure/window, /obj/item/projectile/animate)
+
+/mob/living/simple_animal/hostile/mimic/copy
+
+ health = 100
+ maxHealth = 100
+ var/mob/living/creator = null // the creator
+ var/destroy_objects = 0
+ var/knockdown_people = 0
+
+/mob/living/simple_animal/hostile/mimic/copy/New(loc, var/obj/copy, var/mob/living/creator)
+ ..(loc)
+ CopyObject(copy, creator)
+
+/mob/living/simple_animal/hostile/mimic/copy/death()
+
+ for(var/atom/movable/M in src)
+ M.forceMove(get_turf(src))
+ ..()
+
+/mob/living/simple_animal/hostile/mimic/copy/ListTargets()
+ // Return a list of targets that isn't the creator
+ . = ..()
+ return . - creator
+
+/mob/living/simple_animal/hostile/mimic/copy/proc/CopyObject(var/obj/O, var/mob/living/creator)
+
+ if((istype(O, /obj/item) || istype(O, /obj/structure)) && !is_type_in_list(O, protected_objects))
+
+ O.forceMove(src)
+ name = O.name
+ desc = O.desc
+ icon = O.icon
+ icon_state = O.icon_state
+ icon_living = icon_state
+
+ if(istype(O, /obj/structure))
+ health = (anchored * 50) + 50
+ destroy_objects = 1
+ if(O.density && O.anchored)
+ knockdown_people = 1
+ melee_damage_lower *= 2
+ melee_damage_upper *= 2
+ else if(istype(O, /obj/item))
+ var/obj/item/I = O
+ health = 15 * I.w_class
+ melee_damage_lower = 2 + I.force
+ melee_damage_upper = 2 + I.force
+ move_to_delay = 2 * I.w_class
+
+ maxHealth = health
+ if(creator)
+ src.creator = creator
+ faction = "\ref[creator]" // very unique
+ return 1
+ return
+
+/mob/living/simple_animal/hostile/mimic/copy/DestroySurroundings()
+ if(destroy_objects)
+ ..()
+
+/mob/living/simple_animal/hostile/mimic/copy/PunchTarget()
+ . =..()
+ if(knockdown_people)
+ var/mob/living/L = .
+ if(istype(L))
+ if(prob(15))
+ L.Weaken(1)
L.visible_message("\the [src] knocks down \the [L]!")
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/aliens/shade.dm
similarity index 65%
rename from code/modules/mob/living/simple_animal/shade.dm
rename to code/modules/mob/living/simple_animal/aliens/shade.dm
index f8ed654b958..d74dec5b307 100644
--- a/code/modules/mob/living/simple_animal/shade.dm
+++ b/code/modules/mob/living/simple_animal/aliens/shade.dm
@@ -1,52 +1,59 @@
-/mob/living/simple_animal/shade
- name = "Shade"
- real_name = "Shade"
- desc = "A bound spirit"
- icon = 'icons/mob/mob.dmi'
- icon_state = "shade"
- icon_living = "shade"
- icon_dead = "shade_dead"
- maxHealth = 50
- health = 50
- universal_speak = 1
- speak_emote = list("hisses")
- emote_hear = list("wails","screeches")
- response_help = "puts their hand through"
- response_disarm = "flails at"
- response_harm = "punches"
- melee_damage_lower = 5
- melee_damage_upper = 15
- attacktext = "drained the life from"
- minbodytemp = 0
- maxbodytemp = 4000
- min_oxy = 0
- max_co2 = 0
- max_tox = 0
- speed = -1
- stop_automated_movement = 1
- status_flags = 0
- faction = "cult"
- status_flags = CANPUSH
-
-/mob/living/simple_animal/shade/cultify()
- return
-
-/mob/living/simple_animal/shade/Life()
- ..()
- OnDeathInLife()
-
-/mob/living/simple_animal/shade/attackby(var/obj/item/O as obj, var/mob/user as mob) //Marker -Agouri
- if(istype(O, /obj/item/device/soulstone))
- var/obj/item/device/soulstone/S = O;
- S.transfer_soul("SHADE", src, user)
- return
-
-/mob/living/simple_animal/shade/proc/OnDeathInLife()
- if(stat == 2)
- new /obj/item/weapon/ectoplasm (src.loc)
- for(var/mob/M in viewers(src, null))
- if((M.client && !( M.blinded )))
- M.show_message("\red [src] lets out a contented sigh as their form unwinds. ")
- ghostize()
- qdel(src)
- return
+/mob/living/simple_animal/shade
+ name = "Shade"
+ real_name = "Shade"
+ desc = "A bound spirit"
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "shade"
+ icon_living = "shade"
+ icon_dead = "shade_dead"
+
+ faction = "cult"
+
+ maxHealth = 50
+ health = 50
+ speed = -1
+
+ response_help = "puts their hand through"
+ response_disarm = "flails at"
+ response_harm = "punches"
+
+ melee_damage_lower = 5
+ melee_damage_upper = 15
+ attacktext = "drained the life from"
+
+ minbodytemp = 0
+ maxbodytemp = 4000
+ min_oxy = 0
+ max_co2 = 0
+ max_tox = 0
+
+ stop_automated_movement = 1
+ wander = 0
+ status_flags = 0
+
+ speak_chance = 5
+ universal_speak = 1
+ speak_emote = list("hisses")
+ emote_hear = list("wails","screeches")
+
+ loot_list = list(/obj/item/weapon/ectoplasm = 100)
+
+/mob/living/simple_animal/shade/cultify()
+ return
+
+/mob/living/simple_animal/shade/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(istype(O, /obj/item/device/soulstone))
+ var/obj/item/device/soulstone/S = O;
+ S.transfer_soul("SHADE", src, user)
+ return
+ ..()
+
+/mob/living/simple_animal/shade/death()
+ ..()
+ for(var/mob/M in viewers(src, null))
+ if((M.client && !( M.blinded )))
+ M.show_message("\red [src] lets out a contented sigh as their form unwinds. ")
+
+ ghostize()
+ qdel(src)
+ return
diff --git a/code/modules/mob/living/simple_animal/hostile/bat.dm b/code/modules/mob/living/simple_animal/animals/bat.dm
similarity index 73%
rename from code/modules/mob/living/simple_animal/hostile/bat.dm
rename to code/modules/mob/living/simple_animal/animals/bat.dm
index 9ce3a08a280..d7ed8e5f403 100644
--- a/code/modules/mob/living/simple_animal/hostile/bat.dm
+++ b/code/modules/mob/living/simple_animal/animals/bat.dm
@@ -1,76 +1,78 @@
-/mob/living/simple_animal/hostile/scarybat
- name = "space bats"
- desc = "A swarm of cute little blood sucking bats that looks pretty upset."
- icon = 'icons/mob/bats.dmi'
- icon_state = "bat"
- icon_living = "bat"
- icon_dead = "bat_dead"
- icon_gib = "bat_dead"
- speak_chance = 0
- turns_per_move = 3
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
- response_help = "pets the"
- response_disarm = "gently pushes aside the"
- response_harm = "hits the"
- speed = 4
- maxHealth = 20
- health = 20
-
- harm_intent_damage = 10
- melee_damage_lower = 3
- melee_damage_upper = 3
- attacktext = "bites"
- attack_sound = 'sound/weapons/bite.ogg'
-
- //Space carp aren't affected by atmos.
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
-
- environment_smash = 1
-
- faction = "scarybat"
- var/mob/living/owner
-
-/mob/living/simple_animal/hostile/scarybat/New(loc, mob/living/L as mob)
- ..()
- if(istype(L))
- owner = L
-
-/mob/living/simple_animal/hostile/scarybat/Process_Spacemove(var/check_drift = 0)
- return ..() //No drifting in space for space carp! //original comments do not steal
-
-/mob/living/simple_animal/hostile/scarybat/FindTarget()
- . = ..()
- if(.)
- emote("flutters towards [.]")
-
-/mob/living/simple_animal/hostile/scarybat/Found(var/atom/A)//This is here as a potential override to pick a specific target if available
- if(istype(A) && A == owner)
- return 0
- return ..()
-
-/mob/living/simple_animal/hostile/scarybat/AttackingTarget()
- . =..()
- var/mob/living/L = .
- if(istype(L))
- if(prob(15))
- L.Stun(1)
- L.visible_message("\the [src] scares \the [L]!")
-
-/mob/living/simple_animal/hostile/scarybat/cult
- faction = "cult"
- supernatural = 1
-
-/mob/living/simple_animal/hostile/scarybat/cult/cultify()
- return
-
-/mob/living/simple_animal/hostile/scarybat/cult/Life()
- ..()
- check_horde()
+/mob/living/simple_animal/hostile/scarybat
+ name = "space bats"
+ desc = "A swarm of cute little blood sucking bats that looks pretty upset."
+ icon = 'icons/mob/bats.dmi'
+ icon_state = "bat"
+ icon_living = "bat"
+ icon_dead = "bat_dead"
+ icon_gib = "bat_dead"
+
+ faction = "scarybat"
+
+ maxHealth = 20
+ health = 20
+ turns_per_move = 3
+ speed = 4
+
+ response_help = "pets the"
+ response_disarm = "gently pushes aside the"
+ response_harm = "hits the"
+
+ harm_intent_damage = 10
+ melee_damage_lower = 3
+ melee_damage_upper = 3
+ environment_smash = 1
+
+ attacktext = "bites"
+ attack_sound = 'sound/weapons/bite.ogg'
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
+ var/mob/living/owner
+
+/mob/living/simple_animal/hostile/scarybat/New(loc, mob/living/L as mob)
+ ..()
+ if(istype(L))
+ owner = L
+
+/mob/living/simple_animal/hostile/scarybat/Process_Spacemove(var/check_drift = 0)
+ return ..()
+
+/mob/living/simple_animal/hostile/scarybat/set_target()
+ . = ..()
+ if(.)
+ emote("flutters towards [.]")
+
+/mob/living/simple_animal/hostile/scarybat/ListTargets()
+ . = ..()
+ if(owner)
+ return . - owner
+
+/mob/living/simple_animal/hostile/scarybat/PunchTarget()
+ . =..()
+ var/mob/living/L = .
+ if(istype(L))
+ if(prob(15))
+ L.Stun(1)
+ L.visible_message("\the [src] scares \the [L]!")
+
+/mob/living/simple_animal/hostile/scarybat/cult
+ faction = "cult"
+ supernatural = 1
+
+/mob/living/simple_animal/hostile/scarybat/cult/cultify()
+ return
+
+/mob/living/simple_animal/hostile/scarybat/cult/Life()
+ ..()
+ check_horde()
diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/animals/bear.dm
similarity index 65%
rename from code/modules/mob/living/simple_animal/hostile/bear.dm
rename to code/modules/mob/living/simple_animal/animals/bear.dm
index f4de3b6054f..9d1da5e08b8 100644
--- a/code/modules/mob/living/simple_animal/hostile/bear.dm
+++ b/code/modules/mob/living/simple_animal/animals/bear.dm
@@ -1,172 +1,125 @@
-//Space bears!
-/mob/living/simple_animal/hostile/bear
- name = "space bear"
- desc = "RawrRawr!!"
- icon_state = "bear"
- icon_living = "bear"
- icon_dead = "bear_dead"
- icon_gib = "bear_gib"
- speak = list("RAWR!","Rawr!","GRR!","Growl!")
- speak_emote = list("growls", "roars")
- emote_hear = list("rawrs","grumbles","grawls")
- emote_see = list("stares ferociously", "stomps")
- speak_chance = 1
- turns_per_move = 5
- see_in_dark = 6
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/bearmeat
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "pokes"
- stop_automated_movement_when_pulled = 0
- maxHealth = 60
- health = 60
- melee_damage_lower = 20
- melee_damage_upper = 30
-
- //Space bears aren't affected by atmos.
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
- var/stance_step = 0
-
- faction = "russian"
-
-//SPACE BEARS! SQUEEEEEEEE~ OW! FUCK! IT BIT MY HAND OFF!!
-/mob/living/simple_animal/hostile/bear/Hudson
- name = "Hudson"
- desc = ""
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "pokes"
-
-/mob/living/simple_animal/hostile/bear/Life()
- . =..()
- if(!.)
- return
-
- if(loc && istype(loc,/turf/space))
- icon_state = "bear"
- else
- icon_state = "bearfloor"
-
- switch(stance)
-
- if(STANCE_TIRED)
- stop_automated_movement = 1
- stance_step++
- if(stance_step >= 10) //rests for 10 ticks
- if(target_mob && target_mob in ListTargets(10))
- stance = STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle.
- else
- stance = STANCE_IDLE
-
- if(STANCE_ALERT)
- stop_automated_movement = 1
- var/found_mob = 0
- if(target_mob && target_mob in ListTargets(10))
- if(!(SA_attackable(target_mob)))
- stance_step = max(0, stance_step) //If we have not seen a mob in a while, the stance_step will be negative, we need to reset it to 0 as soon as we see a mob again.
- stance_step++
- found_mob = 1
- src.set_dir(get_dir(src,target_mob)) //Keep staring at the mob
-
- if(stance_step in list(1,4,7)) //every 3 ticks
- var/action = pick( list( "growls at [target_mob]", "stares angrily at [target_mob]", "prepares to attack [target_mob]", "closely watches [target_mob]" ) )
- if(action)
- custom_emote(1,action)
- if(!found_mob)
- stance_step--
-
- if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode
- stance = STANCE_IDLE
- if(stance_step >= 7) //If we have been staring at a mob for 7 ticks,
- stance = STANCE_ATTACK
-
- if(STANCE_ATTACKING)
- if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest
- custom_emote(1, "is worn out and needs to rest." )
- stance = STANCE_TIRED
- stance_step = 0
- walk(src, 0) //This stops the bear's walking
- return
-
-
-
-/mob/living/simple_animal/hostile/bear/attackby(var/obj/item/O as obj, var/mob/user as mob)
- if(stance != STANCE_ATTACK && stance != STANCE_ATTACKING)
- stance = STANCE_ALERT
- stance_step = 6
- target_mob = user
- ..()
-
-/mob/living/simple_animal/hostile/bear/attack_hand(mob/living/carbon/human/M as mob)
- if(stance != STANCE_ATTACK && stance != STANCE_ATTACKING)
- stance = STANCE_ALERT
- stance_step = 6
- target_mob = M
- ..()
-
-/mob/living/simple_animal/hostile/bear/Process_Spacemove(var/check_drift = 0)
- return //No drifting in space for space bears!
-
-/mob/living/simple_animal/hostile/bear/FindTarget()
- . = ..()
- if(.)
- custom_emote(1,"stares alertly at [.]")
- stance = STANCE_ALERT
-
-/mob/living/simple_animal/hostile/bear/LoseTarget()
- ..(5)
-
-/mob/living/simple_animal/hostile/bear/AttackingTarget()
- if(!Adjacent(target_mob))
- return
- custom_emote(1, pick( list("slashes at [target_mob]", "bites [target_mob]") ) )
-
- var/damage = rand(melee_damage_lower, melee_damage_upper)
-
- if(ishuman(target_mob))
- var/mob/living/carbon/human/H = target_mob
- var/dam_zone = pick(BP_TORSO, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG)
- var/obj/item/organ/external/affecting = H.get_organ(ran_zone(dam_zone))
- H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), sharp=1, edge=1)
- return H
- else if(isliving(target_mob))
- var/mob/living/L = target_mob
- L.adjustBruteLoss(damage)
- return L
- //else if(istype(target_mob,/obj/mecha))
- //var/obj/mecha/M = target_mob
- //M.attack_animal(src)
- //return M
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+//Space bears!
+/mob/living/simple_animal/hostile/bear
+ name = "space bear"
+ desc = "RawrRawr!!"
+ icon_state = "bear"
+ icon_living = "bear"
+ icon_dead = "bear_dead"
+ icon_gib = "bear_gib"
+
+ faction = "russian"
+ cooperative = 1
+
+ maxHealth = 60
+ health = 60
+ turns_per_move = 5
+ see_in_dark = 6
+ stop_when_pulled = 0
+
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "pokes"
+
+ melee_damage_lower = 20
+ melee_damage_upper = 30
+
+ //Space bears aren't affected by atmos.
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ speak_chance = 1
+ speak = list("RAWR!","Rawr!","GRR!","Growl!")
+ speak_emote = list("growls", "roars")
+ emote_hear = list("rawrs","grumbles","grawls")
+ emote_see = list("stares ferociously", "stomps")
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/bearmeat
+
+ var/stance_step = 0
+
+/mob/living/simple_animal/hostile/bear/handle_stance()
+ switch(stance)
+ if(STANCE_TIRED)
+ stop_automated_movement = 1
+ stance_step++
+ if(stance_step >= 10) //rests for 10 ticks
+ if(target_mob && target_mob in ListTargets(10))
+ handle_stance(STANCE_ATTACK) //If the mob he was chasing is still nearby, resume the attack, otherwise go idle.
+ else
+ handle_stance(STANCE_IDLE)
+
+ if(STANCE_ALERT)
+ stop_automated_movement = 1
+ var/found_mob = 0
+ if(target_mob && target_mob in ListTargets(10))
+ if(!(SA_attackable(target_mob)))
+ stance_step = max(0, stance_step) //If we have not seen a mob in a while, the stance_step will be negative, we need to reset it to 0 as soon as we see a mob again.
+ stance_step++
+ found_mob = 1
+ src.set_dir(get_dir(src,target_mob)) //Keep staring at the mob
+
+ if(stance_step in list(1,4,7)) //every 3 ticks
+ var/action = pick( list( "growls at [target_mob]", "stares angrily at [target_mob]", "prepares to attack [target_mob]", "closely watches [target_mob]" ) )
+ if(action)
+ custom_emote(1,action)
+ if(!found_mob)
+ stance_step--
+
+ if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode
+ handle_stance(STANCE_IDLE)
+ if(stance_step >= 7) //If we have been staring at a mob for 7 ticks,
+ handle_stance(STANCE_ATTACK)
+
+ if(STANCE_ATTACKING)
+ if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest
+ custom_emote(1, "is worn out and needs to rest." )
+ handle_stance(STANCE_TIRED)
+ stance_step = 0
+ walk(src, 0) //This stops the bear's walking
+ return
+ else
+ ..()
+
+/mob/living/simple_animal/hostile/bear/update_icons()
+ ..()
+ if(!stat)
+ if(loc && istype(loc,/turf/space))
+ icon_state = "bear"
+ else
+ icon_state = "bearfloor"
+
+/mob/living/simple_animal/hostile/bear/Process_Spacemove(var/check_drift = 0)
+ return
+
+/mob/living/simple_animal/hostile/bear/FindTarget()
+ . = ..()
+ if(.)
+ custom_emote(1,"stares alertly at [.]")
+ handle_stance(STANCE_ALERT)
+
+/mob/living/simple_animal/hostile/bear/PunchTarget()
+ if(!Adjacent(target_mob))
+ return
+ custom_emote(1, pick( list("slashes at [target_mob]", "bites [target_mob]") ) )
+
+ var/damage = rand(melee_damage_lower, melee_damage_upper)
+
+ if(ishuman(target_mob))
+ var/mob/living/carbon/human/H = target_mob
+ var/dam_zone = pick(BP_TORSO, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG)
+ var/obj/item/organ/external/affecting = H.get_organ(ran_zone(dam_zone))
+ H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), sharp=1, edge=1)
+ return H
+ else if(isliving(target_mob))
+ var/mob/living/L = target_mob
+ L.adjustBruteLoss(damage)
+ return L
+ else
+ ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/animals/carp.dm
similarity index 82%
rename from code/modules/mob/living/simple_animal/hostile/carp.dm
rename to code/modules/mob/living/simple_animal/animals/carp.dm
index 8708b1009e3..b8813c8a614 100644
--- a/code/modules/mob/living/simple_animal/hostile/carp.dm
+++ b/code/modules/mob/living/simple_animal/animals/carp.dm
@@ -1,55 +1,52 @@
-
-
-/mob/living/simple_animal/hostile/carp
- name = "space carp"
- desc = "A ferocious, fang-bearing creature that resembles a fish."
- icon_state = "carp"
- icon_living = "carp"
- icon_dead = "carp_dead"
- icon_gib = "carp_gib"
- speak_chance = 0
- turns_per_move = 5
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat
- response_help = "pets the"
- response_disarm = "gently pushes aside the"
- response_harm = "hits the"
- speed = 4
- maxHealth = 25
- health = 25
-
- harm_intent_damage = 8
- melee_damage_lower = 15
- melee_damage_upper = 15
- attacktext = "bitten"
- attack_sound = 'sound/weapons/bite.ogg'
-
- //Space carp aren't affected by atmos.
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
-
- break_stuff_probability = 15
-
- faction = "carp"
-
-/mob/living/simple_animal/hostile/carp/Process_Spacemove(var/check_drift = 0)
- return 1 //No drifting in space for space carp! //original comments do not steal
-
-/mob/living/simple_animal/hostile/carp/FindTarget()
- . = ..()
- if(.)
- custom_emote(1,"nashes at [.]")
-
-/mob/living/simple_animal/hostile/carp/AttackingTarget()
- . =..()
- var/mob/living/L = .
- if(istype(L))
- if(prob(15))
- L.Weaken(3)
+/mob/living/simple_animal/hostile/carp
+ name = "space carp"
+ desc = "A ferocious, fang-bearing creature that resembles a fish."
+ icon_state = "carp"
+ icon_living = "carp"
+ icon_dead = "carp_dead"
+ icon_gib = "carp_gib"
+
+ faction = "carp"
+ maxHealth = 25
+ health = 25
+ speed = 4
+ turns_per_move = 5
+
+ response_help = "pets the"
+ response_disarm = "gently pushes aside the"
+ response_harm = "hits the"
+
+ harm_intent_damage = 8
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ attacktext = "bitten"
+ attack_sound = 'sound/weapons/bite.ogg'
+
+ //Space carp aren't affected by atmos.
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat
+
+/mob/living/simple_animal/hostile/carp/Process_Spacemove(var/check_drift = 0)
+ return 1 //No drifting in space for space carp! //original comments do not steal
+
+/mob/living/simple_animal/hostile/carp/set_target()
+ . = ..()
+ if(.)
+ custom_emote(1,"nashes at [.]")
+
+/mob/living/simple_animal/hostile/carp/PunchTarget()
+ . =..()
+ var/mob/living/L = .
+ if(istype(L))
+ if(prob(15))
+ L.Weaken(3)
L.visible_message("\the [src] knocks down \the [L]!")
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/animals/cat.dm
similarity index 52%
rename from code/modules/mob/living/simple_animal/friendly/cat.dm
rename to code/modules/mob/living/simple_animal/animals/cat.dm
index 868bafd7ccf..808ebdb8fa6 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/animals/cat.dm
@@ -6,55 +6,44 @@
item_state = "cat2"
icon_living = "cat2"
icon_dead = "cat2_dead"
+
+ hostile = 1 //To mice, anyway.
+ investigates = 1
+ specific_targets = 1 //Only targets with Found()
+ run_at_them = 0 //DOMESTICATED
+ view_range = 5
+
+ turns_per_move = 5
+ see_in_dark = 6
+
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+
+ min_oxy = 16 //Require atleast 16kPA oxygen
+ minbodytemp = 223 //Below -50 Degrees Celcius
+ maxbodytemp = 323 //Above 50 Degrees Celcius
+
+ holder_type = /obj/item/weapon/holder/cat
+ mob_size = MOB_SMALL
+
+ speak_chance = 1
speak = list("Meow!","Esp!","Purr!","HSSSSS")
speak_emote = list("purrs", "meows")
emote_hear = list("meows","mews")
emote_see = list("shakes their head", "shivers")
- speak_chance = 1
- turns_per_move = 5
- see_in_dark = 6
+ say_maybe_target = list("Meow?","Mew?","Mao?")
+ say_got_target = list("MEOW!","HSSSS!","REEER!")
+
+ meat_amount = 1
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
+
var/turns_since_scan = 0
- var/mob/living/simple_animal/mouse/movement_target
var/mob/flee_target
- min_oxy = 16 //Require atleast 16kPA oxygen
- minbodytemp = 223 //Below -50 Degrees Celcius
- maxbodytemp = 323 //Above 50 Degrees Celcius
- holder_type = /obj/item/weapon/holder/cat
- mob_size = MOB_SMALL
/mob/living/simple_animal/cat/Life()
- //MICE!
- if((src.loc) && isturf(src.loc))
- if(!stat && !resting && !buckled)
- for(var/mob/living/simple_animal/mouse/M in loc)
- if(!M.stat)
- M.splat()
- visible_emote(pick("bites \the [M]!","toys with \the [M].","chomps on \the [M]!"))
- movement_target = null
- stop_automated_movement = 0
- break
-
- ..()
-
- for(var/mob/living/simple_animal/mouse/snack in oview(src,5))
- if(snack.stat < DEAD && prob(15))
- audible_emote(pick("hisses and spits!","mrowls fiercely!","eyes [snack] hungrily."))
- break
-
- if(!stat && !resting && !buckled)
- turns_since_scan++
- if (turns_since_scan > 5)
- walk_to(src,0)
- turns_since_scan = 0
-
- if (flee_target) //fleeing takes precendence
- handle_flee_target()
- else
- handle_movement_target()
+ . = ..()
+ if(!.) return
if(prob(2)) //spooky
var/mob/observer/dead/spook = locate() in range(src,5)
@@ -68,104 +57,60 @@
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
- if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) ))
- movement_target = null
- stop_automated_movement = 0
- //if we have no target or our current one is out of sight/too far away
- if( !movement_target || !(movement_target.loc in oview(src, 4)) )
- movement_target = null
- stop_automated_movement = 0
- for(var/mob/living/simple_animal/mouse/snack in oview(src)) //search for a new target
- if(isturf(snack.loc) && !snack.stat)
- movement_target = snack
- break
+ handle_flee_target()
- if(movement_target)
- stop_automated_movement = 1
- walk_to(src,movement_target,0,3)
+/mob/living/simple_animal/cat/PunchTarget()
+ if(istype(target_mob,/mob/living/simple_animal/mouse))
+ var/mob/living/simple_animal/mouse/mouse = target_mob
+ mouse.splat()
+ visible_emote(pick("bites \the [mouse]!","toys with \the [mouse].","chomps on \the [mouse]!"))
+ return mouse
+ else
+ ..()
+
+/mob/living/simple_animal/cat/Found(var/atom/found_atom)
+ if(istype(found_atom,/mob/living/simple_animal/mouse) && SA_attackable(found_atom))
+ return found_atom
/mob/living/simple_animal/cat/proc/handle_flee_target()
//see if we should stop fleeing
- if (flee_target && !(flee_target.loc in view(src)))
+ if (flee_target && !(flee_target in ListTargets(view_range)))
flee_target = null
- stop_automated_movement = 0
+ GiveUpMoving()
- if (flee_target)
+ if (flee_target && !stat && !buckled)
+ if (resting)
+ lay_down()
if(prob(25)) say("HSSSSS")
stop_automated_movement = 1
walk_away(src, flee_target, 7, 2)
-/mob/living/simple_animal/cat/proc/set_flee_target(atom/A)
- if(A)
- flee_target = A
- turns_since_scan = 5
-
-/mob/living/simple_animal/cat/attackby(var/obj/item/O, var/mob/user)
- . = ..()
- if(O.force)
- set_flee_target(user? user : src.loc)
-
-/mob/living/simple_animal/cat/attack_hand(mob/living/carbon/human/M as mob)
- . = ..()
- if(M.a_intent == I_HURT)
- set_flee_target(M)
+/mob/living/simple_animal/cat/react_to_attack(var/atom/A)
+ if(A == src) return
+ flee_target = A
+ turns_since_scan = 5
/mob/living/simple_animal/cat/ex_act()
. = ..()
- set_flee_target(src.loc)
-
-/mob/living/simple_animal/cat/bullet_act(var/obj/item/projectile/proj)
- . = ..()
- set_flee_target(proj.firer? proj.firer : src.loc)
-
-/mob/living/simple_animal/cat/hitby(atom/movable/AM)
- . = ..()
- set_flee_target(AM.thrower? AM.thrower : src.loc)
+ react_to_attack(src.loc)
//Basic friend AI
/mob/living/simple_animal/cat/fluff
var/mob/living/carbon/human/friend
var/befriend_job = null
-/mob/living/simple_animal/cat/fluff/handle_movement_target()
- if (friend)
- var/follow_dist = 4
- if (friend.stat >= DEAD || friend.health <= config.health_threshold_softcrit) //danger
- follow_dist = 1
- else if (friend.stat || friend.health <= 50) //danger or just sleeping
- follow_dist = 2
- var/near_dist = max(follow_dist - 2, 1)
- var/current_dist = get_dist(src, friend)
-
- if (movement_target != friend)
- if (current_dist > follow_dist && !istype(movement_target, /mob/living/simple_animal/mouse) && (friend in oview(src)))
- //stop existing movement
- walk_to(src,0)
- turns_since_scan = 0
-
- //walk to friend
- stop_automated_movement = 1
- movement_target = friend
- walk_to(src, movement_target, near_dist, 4)
-
- //already following and close enough, stop
- else if (current_dist <= near_dist)
- walk_to(src,0)
- movement_target = null
- stop_automated_movement = 0
- if (prob(10))
- say("Meow!")
-
- if (!friend || movement_target != friend)
- ..()
-
/mob/living/simple_animal/cat/fluff/Life()
- ..()
- if (stat || !friend)
- return
- if (get_dist(src, friend) <= 1)
+ . = ..()
+ if(!. || ai_inactive || !friend) return
+
+ var/friend_dist = get_dist(src,friend)
+
+ if (friend_dist <= 4)
+ if(stance == STANCE_IDLE)
+ if(set_follow(friend))
+ handle_stance(STANCE_FOLLOW)
+
+ if (friend_dist <= 1)
if (friend.stat >= DEAD || friend.health <= config.health_threshold_softcrit)
if (prob((friend.stat < DEAD)? 50 : 15))
var/verb = pick("meows", "mews", "mrowls")
@@ -213,6 +158,7 @@
item_state = "cat"
icon_living = "cat"
icon_dead = "cat_dead"
+ befriend_job = "Chief Medical Officer"
/mob/living/simple_animal/cat/kitten
name = "kitten"
diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/animals/corgi.dm
similarity index 96%
rename from code/modules/mob/living/simple_animal/friendly/corgi.dm
rename to code/modules/mob/living/simple_animal/animals/corgi.dm
index 1b5cd7e37e8..8f4adf8e540 100644
--- a/code/modules/mob/living/simple_animal/friendly/corgi.dm
+++ b/code/modules/mob/living/simple_animal/animals/corgi.dm
@@ -1,217 +1,227 @@
-//Corgi
-/mob/living/simple_animal/corgi
- name = "\improper corgi"
- real_name = "corgi"
- desc = "It's a corgi."
- icon_state = "corgi"
- icon_living = "corgi"
- icon_dead = "corgi_dead"
- speak = list("YAP", "Woof!", "Bark!", "AUUUUUU")
- speak_emote = list("barks", "woofs")
- emote_hear = list("barks", "woofs", "yaps","pants")
- emote_see = list("shakes its head", "shivers")
- speak_chance = 1
- turns_per_move = 10
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/corgi
- meat_amount = 3
- response_help = "pets"
- response_disarm = "bops"
- response_harm = "kicks"
- see_in_dark = 5
- mob_size = 8
-
- var/obj/item/inventory_head
- var/obj/item/inventory_back
-
-//IAN! SQUEEEEEEEEE~
-/mob/living/simple_animal/corgi/Ian
- name = "Ian"
- real_name = "Ian" //Intended to hold the name without altering it.
- gender = MALE
- desc = "It's a corgi."
- var/turns_since_scan = 0
- var/obj/movement_target
- response_help = "pets"
- response_disarm = "bops"
- response_harm = "kicks"
-
-/mob/living/simple_animal/corgi/Ian/Life()
- ..()
-
- //Feeding, chasing food, FOOOOODDDD
- if(!stat && !resting && !buckled)
- turns_since_scan++
- if(turns_since_scan > 5)
- turns_since_scan = 0
- if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) ))
- movement_target = null
- stop_automated_movement = 0
- if( !movement_target || !(movement_target.loc in oview(src, 3)) )
- movement_target = null
- stop_automated_movement = 0
- for(var/obj/item/weapon/reagent_containers/food/snacks/S in oview(src,3))
- if(isturf(S.loc) || ishuman(S.loc))
- movement_target = S
- break
- if(movement_target)
- stop_automated_movement = 1
- step_to(src,movement_target,1)
- sleep(3)
- step_to(src,movement_target,1)
- sleep(3)
- step_to(src,movement_target,1)
-
- if(movement_target) //Not redundant due to sleeps, Item can be gone in 6 decisecomds
- if (movement_target.loc.x < src.x)
- set_dir(WEST)
- else if (movement_target.loc.x > src.x)
- set_dir(EAST)
- else if (movement_target.loc.y < src.y)
- set_dir(SOUTH)
- else if (movement_target.loc.y > src.y)
- set_dir(NORTH)
- else
- set_dir(SOUTH)
-
- if(isturf(movement_target.loc) )
- UnarmedAttack(movement_target)
- else if(ishuman(movement_target.loc) && prob(20))
- visible_emote("stares at the [movement_target] that [movement_target.loc] has with sad puppy eyes.")
-
- if(prob(1))
- visible_emote(pick("dances around","chases their tail"))
- spawn(0)
- for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
- set_dir(i)
- sleep(1)
-
-/obj/item/weapon/reagent_containers/food/snacks/meat/corgi
- name = "Corgi meat"
- desc = "Tastes like... well you know..."
-
-/mob/living/simple_animal/corgi/attackby(var/obj/item/O as obj, var/mob/user as mob) //Marker -Agouri
- if(istype(O, /obj/item/weapon/newspaper))
- if(!stat)
- for(var/mob/M in viewers(user, null))
- if ((M.client && !( M.blinded )))
- M.show_message("\blue [user] baps [name] on the nose with the rolled up [O]")
- spawn(0)
- for(var/i in list(1,2,4,8,4,2,1,2))
- set_dir(i)
- sleep(1)
- else
- ..()
-
-/mob/living/simple_animal/corgi/regenerate_icons()
- overlays = list()
-
- if(inventory_head)
- var/head_icon_state = inventory_head.icon_state
- if(health <= 0)
- head_icon_state += "2"
-
- var/icon/head_icon = image('icons/mob/corgi_head.dmi',head_icon_state)
- if(head_icon)
- overlays += head_icon
-
- if(inventory_back)
- var/back_icon_state = inventory_back.icon_state
- if(health <= 0)
- back_icon_state += "2"
-
- var/icon/back_icon = image('icons/mob/corgi_back.dmi',back_icon_state)
- if(back_icon)
- overlays += back_icon
-
- return
-
-
-/mob/living/simple_animal/corgi/puppy
- name = "\improper corgi puppy"
- real_name = "corgi"
- desc = "It's a corgi puppy."
- icon_state = "puppy"
- icon_living = "puppy"
- icon_dead = "puppy_dead"
-
-//pupplies cannot wear anything.
-/mob/living/simple_animal/corgi/puppy/Topic(href, href_list)
- if(href_list["remove_inv"] || href_list["add_inv"])
- usr << "\red You can't fit this on [src]"
- return
- ..()
-
-
-//LISA! SQUEEEEEEEEE~
-/mob/living/simple_animal/corgi/Lisa
- name = "Lisa"
- real_name = "Lisa"
- gender = FEMALE
- desc = "It's a corgi with a cute pink bow."
- icon_state = "lisa"
- icon_living = "lisa"
- icon_dead = "lisa_dead"
- response_help = "pets"
- response_disarm = "bops"
- response_harm = "kicks"
- var/turns_since_scan = 0
- var/puppies = 0
-
-//Lisa already has a cute bow!
-/mob/living/simple_animal/corgi/Lisa/Topic(href, href_list)
- if(href_list["remove_inv"] || href_list["add_inv"])
- usr << "\red [src] already has a cute bow!"
- return
- ..()
-
-/mob/living/simple_animal/corgi/Lisa/Life()
- ..()
-
- if(!stat && !resting && !buckled)
- turns_since_scan++
- if(turns_since_scan > 15)
- turns_since_scan = 0
- var/alone = 1
- var/ian = 0
- for(var/mob/M in oviewers(7, src))
- if(istype(M, /mob/living/simple_animal/corgi/Ian))
- if(M.client)
- alone = 0
- break
- else
- ian = M
- else
- alone = 0
- break
- if(alone && ian && puppies < 4)
- if(near_camera(src) || near_camera(ian))
- return
- new /mob/living/simple_animal/corgi/puppy(loc)
-
-
- if(prob(1))
- visible_emote(pick("dances around","chases her tail"))
- spawn(0)
- for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
- set_dir(i)
- sleep(1)
-
-//Technically this should be like, its own file or something or a subset of dog but whatever. Not a coder.
-/mob/living/simple_animal/corgi/tamaskan
- name = "\improper tamaskan"
- real_name = "tamaskan"
- desc = "It's a tamaskan."
- icon_state = "tamaskan"
- icon_living = "tamaskan"
- icon_dead = "tamaskan_dead"
-
-/mob/living/simple_animal/corgi/tamaskan/spice
- name = "Spice"
- real_name = "Spice" //Intended to hold the name without altering it.
- gender = FEMALE
- desc = "It's a tamaskan, the name Spice can be found on its collar."
- var/turns_since_scan = 0
- var/obj/movement_target
- response_help = "pets"
- response_disarm = "bops"
- response_harm = "kicks"
\ No newline at end of file
+//Corgi
+/mob/living/simple_animal/corgi
+ name = "\improper corgi"
+ real_name = "corgi"
+ desc = "It's a corgi."
+ icon_state = "corgi"
+ icon_living = "corgi"
+ icon_dead = "corgi_dead"
+
+ run_at_them = 0
+ turns_per_move = 10
+
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "kicks"
+
+ see_in_dark = 5
+ mob_size = 8
+
+ speak_chance = 1
+ speak = list("YAP", "Woof!", "Bark!", "AUUUUUU")
+ speak_emote = list("barks", "woofs")
+ emote_hear = list("barks", "woofs", "yaps","pants")
+ emote_see = list("shakes its head", "shivers")
+
+ meat_amount = 3
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/corgi
+
+ var/obj/item/inventory_head
+ var/obj/item/inventory_back
+
+//IAN! SQUEEEEEEEEE~
+/mob/living/simple_animal/corgi/Ian
+ name = "Ian"
+ real_name = "Ian" //Intended to hold the name without altering it.
+ gender = MALE
+ desc = "It's a corgi."
+ var/turns_since_scan = 0
+ var/obj/movement_target
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "kicks"
+
+/mob/living/simple_animal/corgi/Ian/Life()
+ ..()
+
+ //Not replacing with SA FollowTarget mechanics because Ian behaves... very... specifically.
+
+ //Feeding, chasing food, FOOOOODDDD
+ if(!stat && !resting && !buckled)
+ turns_since_scan++
+ if(turns_since_scan > 5)
+ turns_since_scan = 0
+ if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) ))
+ movement_target = null
+ stop_automated_movement = 0
+ if( !movement_target || !(movement_target.loc in oview(src, 3)) )
+ movement_target = null
+ stop_automated_movement = 0
+ for(var/obj/item/weapon/reagent_containers/food/snacks/S in oview(src,3))
+ if(isturf(S.loc) || ishuman(S.loc))
+ movement_target = S
+ break
+ if(movement_target)
+ stop_automated_movement = 1
+ step_to(src,movement_target,1)
+ sleep(3)
+ step_to(src,movement_target,1)
+ sleep(3)
+ step_to(src,movement_target,1)
+
+ if(movement_target) //Not redundant due to sleeps, Item can be gone in 6 decisecomds
+ if (movement_target.loc.x < src.x)
+ set_dir(WEST)
+ else if (movement_target.loc.x > src.x)
+ set_dir(EAST)
+ else if (movement_target.loc.y < src.y)
+ set_dir(SOUTH)
+ else if (movement_target.loc.y > src.y)
+ set_dir(NORTH)
+ else
+ set_dir(SOUTH)
+
+ if(isturf(movement_target.loc) )
+ UnarmedAttack(movement_target)
+ else if(ishuman(movement_target.loc) && prob(20))
+ visible_emote("stares at the [movement_target] that [movement_target.loc] has with sad puppy eyes.")
+
+ if(prob(1))
+ visible_emote(pick("dances around","chases their tail"))
+ spawn(0)
+ for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
+ set_dir(i)
+ sleep(1)
+
+/obj/item/weapon/reagent_containers/food/snacks/meat/corgi
+ name = "Corgi meat"
+ desc = "Tastes like... well you know..."
+
+/mob/living/simple_animal/corgi/attackby(var/obj/item/O as obj, var/mob/user as mob) //Marker -Agouri
+ if(istype(O, /obj/item/weapon/newspaper))
+ if(!stat)
+ for(var/mob/M in viewers(user, null))
+ if ((M.client && !( M.blinded )))
+ M.show_message("\blue [user] baps [name] on the nose with the rolled up [O]")
+ spawn(0)
+ for(var/i in list(1,2,4,8,4,2,1,2))
+ set_dir(i)
+ sleep(1)
+ else
+ ..()
+
+/mob/living/simple_animal/corgi/regenerate_icons()
+ overlays = list()
+
+ if(inventory_head)
+ var/head_icon_state = inventory_head.icon_state
+ if(health <= 0)
+ head_icon_state += "2"
+
+ var/icon/head_icon = image('icons/mob/corgi_head.dmi',head_icon_state)
+ if(head_icon)
+ overlays += head_icon
+
+ if(inventory_back)
+ var/back_icon_state = inventory_back.icon_state
+ if(health <= 0)
+ back_icon_state += "2"
+
+ var/icon/back_icon = image('icons/mob/corgi_back.dmi',back_icon_state)
+ if(back_icon)
+ overlays += back_icon
+
+ return
+
+
+/mob/living/simple_animal/corgi/puppy
+ name = "\improper corgi puppy"
+ real_name = "corgi"
+ desc = "It's a corgi puppy."
+ icon_state = "puppy"
+ icon_living = "puppy"
+ icon_dead = "puppy_dead"
+
+//pupplies cannot wear anything.
+/mob/living/simple_animal/corgi/puppy/Topic(href, href_list)
+ if(href_list["remove_inv"] || href_list["add_inv"])
+ usr << "\red You can't fit this on [src]"
+ return
+ ..()
+
+
+//LISA! SQUEEEEEEEEE~
+/mob/living/simple_animal/corgi/Lisa
+ name = "Lisa"
+ real_name = "Lisa"
+ gender = FEMALE
+ desc = "It's a corgi with a cute pink bow."
+ icon_state = "lisa"
+ icon_living = "lisa"
+ icon_dead = "lisa_dead"
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "kicks"
+ var/turns_since_scan = 0
+ var/puppies = 0
+
+//Lisa already has a cute bow!
+/mob/living/simple_animal/corgi/Lisa/Topic(href, href_list)
+ if(href_list["remove_inv"] || href_list["add_inv"])
+ usr << "\red [src] already has a cute bow!"
+ return
+ ..()
+
+/mob/living/simple_animal/corgi/Lisa/Life()
+ ..()
+
+ if(!stat && !resting && !buckled)
+ turns_since_scan++
+ if(turns_since_scan > 15)
+ turns_since_scan = 0
+ var/alone = 1
+ var/ian = 0
+ for(var/mob/M in oviewers(7, src))
+ if(istype(M, /mob/living/simple_animal/corgi/Ian))
+ if(M.client)
+ alone = 0
+ break
+ else
+ ian = M
+ else
+ alone = 0
+ break
+ if(alone && ian && puppies < 4)
+ if(near_camera(src) || near_camera(ian))
+ return
+ new /mob/living/simple_animal/corgi/puppy(loc)
+
+
+ if(prob(1))
+ visible_emote(pick("dances around","chases her tail"))
+ spawn(0)
+ for(var/i in list(1,2,4,8,4,2,1,2,4,8,4,2,1,2,4,8,4,2))
+ set_dir(i)
+ sleep(1)
+
+//Technically this should be like, its own file or something or a subset of dog but whatever. Not a coder.
+/mob/living/simple_animal/corgi/tamaskan
+ name = "\improper tamaskan"
+ real_name = "tamaskan"
+ desc = "It's a tamaskan."
+ icon_state = "tamaskan"
+ icon_living = "tamaskan"
+ icon_dead = "tamaskan_dead"
+
+ retaliate = 1 //Tamaskans are bigass dogs, okay?
+
+/mob/living/simple_animal/corgi/tamaskan/spice
+ name = "Spice"
+ real_name = "Spice" //Intended to hold the name without altering it.
+ gender = FEMALE
+ desc = "It's a tamaskan, the name Spice can be found on its collar."
+ var/turns_since_scan = 0
+ var/obj/movement_target
+ response_help = "pets"
+ response_disarm = "bops"
+ response_harm = "kicks"
diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/animals/crab.dm
similarity index 84%
rename from code/modules/mob/living/simple_animal/friendly/crab.dm
rename to code/modules/mob/living/simple_animal/animals/crab.dm
index 5b57bad674a..acb95ac64c6 100644
--- a/code/modules/mob/living/simple_animal/friendly/crab.dm
+++ b/code/modules/mob/living/simple_animal/animals/crab.dm
@@ -1,42 +1,46 @@
-//Look Sir, free crabs!
-/mob/living/simple_animal/crab
- name = "crab"
- desc = "A hard-shelled crustacean. Seems quite content to lounge around all the time."
- icon_state = "crab"
- icon_living = "crab"
- icon_dead = "crab_dead"
- mob_size = MOB_SMALL
- speak_emote = list("clicks")
- emote_hear = list("clicks")
- emote_see = list("clacks")
- speak_chance = 1
- turns_per_move = 5
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "stomps"
- stop_automated_movement = 1
- friendly = "pinches"
- mob_size = 5
- var/obj/item/inventory_head
- var/obj/item/inventory_mask
-
-/mob/living/simple_animal/crab/Life()
- ..()
- //CRAB movement
- if(!ckey && !stat)
- if(isturf(src.loc) && !resting && !buckled) //This is so it only moves if it's not inside a closet, gentics machine, etc.
- turns_since_move++
- if(turns_since_move >= turns_per_move)
- Move(get_step(src,pick(4,8)))
- turns_since_move = 0
- regenerate_icons()
-
-//COFFEE! SQUEEEEEEEEE!
-/mob/living/simple_animal/crab/Coffee
- name = "Coffee"
- real_name = "Coffee"
- desc = "It's Coffee, the other pet!"
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "stomps"
+//Look Sir, free crabs!
+/mob/living/simple_animal/crab
+ name = "crab"
+ desc = "A hard-shelled crustacean. Seems quite content to lounge around all the time."
+ icon_state = "crab"
+ icon_living = "crab"
+ icon_dead = "crab_dead"
+
+ wander = 0
+ stop_automated_movement = 1
+ turns_per_move = 5
+ mob_size = MOB_SMALL
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "stomps"
+ friendly = "pinches"
+
+ speak_chance = 1
+ speak_emote = list("clicks")
+ emote_hear = list("clicks")
+ emote_see = list("clacks")
+
+ var/obj/item/inventory_head
+ var/obj/item/inventory_mask
+
+/mob/living/simple_animal/crab/Life()
+ ..()
+ //CRAB movement, I'm not porting this up to SA because... "sideways-only movement" var nothanks
+ if(!ckey && !stat)
+ if(isturf(src.loc) && !resting && !buckled) //This is so it only moves if it's not inside a closet, gentics machine, etc.
+ lifes_since_move++
+ if(lifes_since_move >= turns_per_move)
+ Move(get_step(src,pick(4,8)))
+ lifes_since_move = 0
+ regenerate_icons()
+
+//COFFEE! SQUEEEEEEEEE!
+/mob/living/simple_animal/crab/Coffee
+ name = "Coffee"
+ real_name = "Coffee"
+ desc = "It's Coffee, the other pet!"
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "stomps"
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/animals/farm_animals.dm
similarity index 89%
rename from code/modules/mob/living/simple_animal/friendly/farm_animals.dm
rename to code/modules/mob/living/simple_animal/animals/farm_animals.dm
index 68578ca08ed..fc21fbddfde 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/animals/farm_animals.dm
@@ -1,268 +1,282 @@
-//goat
-/mob/living/simple_animal/hostile/retaliate/goat
- name = "goat"
- desc = "Not known for their pleasant disposition."
- icon_state = "goat"
- icon_living = "goat"
- icon_dead = "goat_dead"
- speak = list("EHEHEHEHEH","eh?")
- speak_emote = list("brays")
- emote_hear = list("brays")
- emote_see = list("shakes its head", "stamps a foot", "glares around")
- speak_chance = 1
- turns_per_move = 5
- see_in_dark = 6
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
- meat_amount = 4
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- faction = "goat"
- attacktext = "kicked"
- health = 40
- melee_damage_lower = 1
- melee_damage_upper = 5
- var/datum/reagents/udder = null
-
-/mob/living/simple_animal/hostile/retaliate/goat/New()
- udder = new(50)
- udder.my_atom = src
- ..()
-
-/mob/living/simple_animal/hostile/retaliate/goat/Life()
- . = ..()
- if(.)
- //chance to go crazy and start wacking stuff
- if(!enemies.len && prob(1))
- Retaliate()
-
- if(enemies.len && prob(10))
- enemies = list()
- LoseTarget()
- src.visible_message("\blue [src] calms down.")
-
- if(stat == CONSCIOUS)
- if(udder && prob(5))
- udder.add_reagent("milk", rand(5, 10))
-
- if(locate(/obj/effect/plant) in loc)
- var/obj/effect/plant/SV = locate() in loc
- SV.die_off(1)
-
- if(locate(/obj/machinery/portable_atmospherics/hydroponics/soil/invisible) in loc)
- var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/SP = locate() in loc
- qdel(SP)
-
- if(!pulledby)
- var/obj/effect/plant/food
- food = locate(/obj/effect/plant) in oview(5,loc)
- if(food)
- var/step = get_step_to(src, food, 0)
- Move(step)
-
-/mob/living/simple_animal/hostile/retaliate/goat/Retaliate()
- ..()
- if(stat == CONSCIOUS)
- visible_message("[src] gets an evil-looking gleam in their eye.")
-
-/mob/living/simple_animal/hostile/retaliate/goat/Move()
- ..()
- if(!stat)
- for(var/obj/effect/plant/SV in loc)
- SV.die_off(1)
-
-/mob/living/simple_animal/hostile/retaliate/goat/attackby(var/obj/item/O as obj, var/mob/user as mob)
- var/obj/item/weapon/reagent_containers/glass/G = O
- if(stat == CONSCIOUS && istype(G) && G.is_open_container())
- user.visible_message("[user] milks [src] using \the [O].")
- var/transfered = udder.trans_id_to(G, "milk", rand(5,10))
- if(G.reagents.total_volume >= G.volume)
- user << "\red The [O] is full."
- if(!transfered)
- user << "\red The udder is dry. Wait a bit longer..."
- else
- ..()
-//cow
-/mob/living/simple_animal/cow
- name = "cow"
- desc = "Known for their milk, just don't tip them over."
- icon_state = "cow"
- icon_living = "cow"
- icon_dead = "cow_dead"
- icon_gib = "cow_gib"
- speak = list("moo?","moo","MOOOOOO")
- speak_emote = list("moos","moos hauntingly")
- emote_hear = list("brays")
- emote_see = list("shakes its head")
- speak_chance = 1
- turns_per_move = 5
- see_in_dark = 6
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
- meat_amount = 6
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicked"
- health = 50
- var/datum/reagents/udder = null
-
-/mob/living/simple_animal/cow/New()
- udder = new(50)
- udder.my_atom = src
- ..()
-
-/mob/living/simple_animal/cow/attackby(var/obj/item/O as obj, var/mob/user as mob)
- var/obj/item/weapon/reagent_containers/glass/G = O
- if(stat == CONSCIOUS && istype(G) && G.is_open_container())
- user.visible_message("[user] milks [src] using \the [O].")
- var/transfered = udder.trans_id_to(G, "milk", rand(5,10))
- if(G.reagents.total_volume >= G.volume)
- user << "\red The [O] is full."
- if(!transfered)
- user << "\red The udder is dry. Wait a bit longer..."
- else
- ..()
-
-/mob/living/simple_animal/cow/Life()
- . = ..()
- if(stat == CONSCIOUS)
- if(udder && prob(5))
- udder.add_reagent("milk", rand(5, 10))
-
-/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M as mob)
- if(!stat && M.a_intent == I_DISARM && icon_state != icon_dead)
- M.visible_message("[M] tips over [src].","You tip over [src].")
- Weaken(30)
- icon_state = icon_dead
- spawn(rand(20,50))
- if(!stat && M)
- icon_state = icon_living
- var/list/responses = list( "[src] looks at you imploringly.",
- "[src] looks at you pleadingly",
- "[src] looks at you with a resigned expression.",
- "[src] seems resigned to its fate.")
- M << pick(responses)
- else
- ..()
-
-/mob/living/simple_animal/chick
- name = "\improper chick"
- desc = "Adorable! They make such a racket though."
- icon_state = "chick"
- icon_living = "chick"
- icon_dead = "chick_dead"
- icon_gib = "chick_gib"
- speak = list("Cherp.","Cherp?","Chirrup.","Cheep!")
- speak_emote = list("cheeps")
- emote_hear = list("cheeps")
- emote_see = list("pecks at the ground","flaps its tiny wings")
- speak_chance = 2
- turns_per_move = 2
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
- meat_amount = 1
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicked"
- health = 1
- var/amount_grown = 0
- pass_flags = PASSTABLE | PASSGRILLE
- mob_size = MOB_MINISCULE
-
-/mob/living/simple_animal/chick/New()
- ..()
- pixel_x = rand(-6, 6)
- pixel_y = rand(0, 10)
-
-/mob/living/simple_animal/chick/Life()
- . =..()
- if(!.)
- return
- if(!stat)
- amount_grown += rand(1,2)
- if(amount_grown >= 100)
- new /mob/living/simple_animal/chicken(src.loc)
- qdel(src)
-
-var/const/MAX_CHICKENS = 50
-var/global/chicken_count = 0
-
-/mob/living/simple_animal/chicken
- name = "\improper chicken"
- desc = "Hopefully the eggs are good this season."
- icon_state = "chicken"
- icon_living = "chicken"
- icon_dead = "chicken_dead"
- speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.")
- speak_emote = list("clucks","croons")
- emote_hear = list("clucks")
- emote_see = list("pecks at the ground","flaps its wings viciously")
- speak_chance = 2
- turns_per_move = 3
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
- meat_amount = 2
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicked"
- health = 10
- var/eggsleft = 0
- var/body_color
- pass_flags = PASSTABLE
- mob_size = MOB_SMALL
-
-/mob/living/simple_animal/chicken/New()
- ..()
- if(!body_color)
- body_color = pick( list("brown","black","white") )
- icon_state = "chicken_[body_color]"
- icon_living = "chicken_[body_color]"
- icon_dead = "chicken_[body_color]_dead"
- pixel_x = rand(-6, 6)
- pixel_y = rand(0, 10)
- chicken_count += 1
-
-/mob/living/simple_animal/chicken/death()
- ..()
- chicken_count -= 1
-
-/mob/living/simple_animal/chicken/attackby(var/obj/item/O as obj, var/mob/user as mob)
- if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown)) //feedin' dem chickens
- var/obj/item/weapon/reagent_containers/food/snacks/grown/G = O
- if(G.seed && G.seed.kitchen_tag == "wheat")
- if(!stat && eggsleft < 8)
- user.visible_message("\blue [user] feeds [O] to [name]! It clucks happily.","\blue You feed [O] to [name]! It clucks happily.")
- user.drop_item()
- qdel(O)
- eggsleft += rand(1, 4)
- else
- user << "\blue [name] doesn't seem hungry!"
- else
- user << "[name] doesn't seem interested in that."
- else
- ..()
-
-/mob/living/simple_animal/chicken/Life()
- . =..()
- if(!.)
- return
- if(!stat && prob(3) && eggsleft > 0)
- visible_message("[src] [pick("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.")]")
- eggsleft--
- var/obj/item/weapon/reagent_containers/food/snacks/egg/E = new(get_turf(src))
- E.pixel_x = rand(-6,6)
- E.pixel_y = rand(-6,6)
- if(chicken_count < MAX_CHICKENS && prob(10))
- processing_objects.Add(E)
-
-/obj/item/weapon/reagent_containers/food/snacks/egg/var/amount_grown = 0
-/obj/item/weapon/reagent_containers/food/snacks/egg/process()
- if(isturf(loc))
- amount_grown += rand(1,2)
- if(amount_grown >= 100)
- visible_message("[src] hatches with a quiet cracking sound.")
- new /mob/living/simple_animal/chick(get_turf(src))
- processing_objects.Remove(src)
- qdel(src)
- else
- processing_objects.Remove(src)
+//goat
+/mob/living/simple_animal/retaliate/goat
+ name = "goat"
+ desc = "Not known for their pleasant disposition."
+ icon_state = "goat"
+ icon_living = "goat"
+ icon_dead = "goat_dead"
+
+ faction = "goat"
+
+ health = 40
+ turns_per_move = 5
+ see_in_dark = 6
+
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+
+ melee_damage_lower = 1
+ melee_damage_upper = 5
+ attacktext = "kicked"
+
+ speak_chance = 1
+ speak = list("EHEHEHEHEH","eh?")
+ speak_emote = list("brays")
+ emote_hear = list("brays")
+ emote_see = list("shakes its head", "stamps a foot", "glares around")
+
+ meat_amount = 4
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
+ var/datum/reagents/udder = null
+
+/mob/living/simple_animal/retaliate/goat/New()
+ udder = new(50)
+ udder.my_atom = src
+ ..()
+
+/mob/living/simple_animal/retaliate/goat/Life()
+ . = ..()
+ if(.)
+ if(stat == CONSCIOUS)
+ if(udder && prob(5))
+ udder.add_reagent("milk", rand(5, 10))
+
+ if(locate(/obj/effect/plant) in loc)
+ var/obj/effect/plant/SV = locate() in loc
+ SV.die_off(1)
+
+ if(locate(/obj/machinery/portable_atmospherics/hydroponics/soil/invisible) in loc)
+ var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/SP = locate() in loc
+ qdel(SP)
+
+ if(!pulledby)
+ var/obj/effect/plant/food
+ food = locate(/obj/effect/plant) in oview(5,loc)
+ if(food)
+ var/step = get_step_to(src, food, 0)
+ Move(step)
+
+/mob/living/simple_animal/retaliate/goat/react_to_attack()
+ . = ..()
+ if(.)
+ visible_message("[src] gets an evil-looking gleam in their eye.")
+
+/mob/living/simple_animal/retaliate/goat/Move()
+ ..()
+ if(!stat)
+ for(var/obj/effect/plant/SV in loc)
+ SV.die_off(1)
+
+/mob/living/simple_animal/retaliate/goat/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ var/obj/item/weapon/reagent_containers/glass/G = O
+ if(stat == CONSCIOUS && istype(G) && G.is_open_container())
+ user.visible_message("[user] milks [src] using \the [O].")
+ var/transfered = udder.trans_id_to(G, "milk", rand(5,10))
+ if(G.reagents.total_volume >= G.volume)
+ user << "\red The [O] is full."
+ if(!transfered)
+ user << "\red The udder is dry. Wait a bit longer..."
+ else
+ ..()
+//cow
+/mob/living/simple_animal/cow
+ name = "cow"
+ desc = "Known for their milk, just don't tip them over."
+ icon_state = "cow"
+ icon_living = "cow"
+ icon_dead = "cow_dead"
+ icon_gib = "cow_gib"
+
+ health = 50
+ turns_per_move = 5
+ see_in_dark = 6
+
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ attacktext = "kicked"
+
+ speak_chance = 1
+ speak = list("moo?","moo","MOOOOOO")
+ speak_emote = list("moos","moos hauntingly")
+ emote_hear = list("brays")
+ emote_see = list("shakes its head")
+
+ meat_amount = 6
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
+ var/datum/reagents/udder = null
+
+/mob/living/simple_animal/cow/New()
+ udder = new(50)
+ udder.my_atom = src
+ ..()
+
+/mob/living/simple_animal/cow/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ var/obj/item/weapon/reagent_containers/glass/G = O
+ if(stat == CONSCIOUS && istype(G) && G.is_open_container())
+ user.visible_message("[user] milks [src] using \the [O].")
+ var/transfered = udder.trans_id_to(G, "milk", rand(5,10))
+ if(G.reagents.total_volume >= G.volume)
+ user << "\red The [O] is full."
+ if(!transfered)
+ user << "\red The udder is dry. Wait a bit longer..."
+ else
+ ..()
+
+/mob/living/simple_animal/cow/Life()
+ . = ..()
+ if(stat == CONSCIOUS)
+ if(udder && prob(5))
+ udder.add_reagent("milk", rand(5, 10))
+
+/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M as mob)
+ if(!stat && M.a_intent == I_DISARM && icon_state != icon_dead)
+ M.visible_message("[M] tips over [src].","You tip over [src].")
+ Weaken(30)
+ icon_state = icon_dead
+ spawn(rand(20,50))
+ if(!stat && M)
+ icon_state = icon_living
+ var/list/responses = list( "[src] looks at you imploringly.",
+ "[src] looks at you pleadingly",
+ "[src] looks at you with a resigned expression.",
+ "[src] seems resigned to its fate.")
+ M << pick(responses)
+ else
+ ..()
+
+/mob/living/simple_animal/chick
+ name = "\improper chick"
+ desc = "Adorable! They make such a racket though."
+ icon_state = "chick"
+ icon_living = "chick"
+ icon_dead = "chick_dead"
+ icon_gib = "chick_gib"
+
+ health = 1
+ turns_per_move = 2
+
+ pass_flags = PASSTABLE | PASSGRILLE
+ mob_size = MOB_MINISCULE
+
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ attacktext = "kicked"
+
+ speak_chance = 2
+ speak = list("Cherp.","Cherp?","Chirrup.","Cheep!")
+ speak_emote = list("cheeps")
+ emote_hear = list("cheeps")
+ emote_see = list("pecks at the ground","flaps its tiny wings")
+
+ meat_amount = 1
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
+ var/amount_grown = 0
+
+/mob/living/simple_animal/chick/New()
+ ..()
+ pixel_x = rand(-6, 6)
+ pixel_y = rand(0, 10)
+
+/mob/living/simple_animal/chick/Life()
+ . =..()
+ if(!.)
+ return
+ if(!stat)
+ amount_grown += rand(1,2)
+ if(amount_grown >= 100)
+ new /mob/living/simple_animal/chicken(src.loc)
+ qdel(src)
+
+var/const/MAX_CHICKENS = 50
+var/global/chicken_count = 0
+
+/mob/living/simple_animal/chicken
+ name = "\improper chicken"
+ desc = "Hopefully the eggs are good this season."
+ icon_state = "chicken"
+ icon_living = "chicken"
+ icon_dead = "chicken_dead"
+
+ health = 10
+ turns_per_move = 3
+ pass_flags = PASSTABLE
+ mob_size = MOB_SMALL
+
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ attacktext = "kicked"
+
+ speak_chance = 2
+ speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.")
+ speak_emote = list("clucks","croons")
+ emote_hear = list("clucks")
+ emote_see = list("pecks at the ground","flaps its wings viciously")
+
+ meat_amount = 2
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
+ var/eggsleft = 0
+ var/body_color
+
+/mob/living/simple_animal/chicken/New()
+ ..()
+ if(!body_color)
+ body_color = pick( list("brown","black","white") )
+ icon_state = "chicken_[body_color]"
+ icon_living = "chicken_[body_color]"
+ icon_dead = "chicken_[body_color]_dead"
+ pixel_x = rand(-6, 6)
+ pixel_y = rand(0, 10)
+ chicken_count += 1
+
+/mob/living/simple_animal/chicken/death()
+ ..()
+ chicken_count -= 1
+
+/mob/living/simple_animal/chicken/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown)) //feedin' dem chickens
+ var/obj/item/weapon/reagent_containers/food/snacks/grown/G = O
+ if(G.seed && G.seed.kitchen_tag == "wheat")
+ if(!stat && eggsleft < 8)
+ user.visible_message("\blue [user] feeds [O] to [name]! It clucks happily.","\blue You feed [O] to [name]! It clucks happily.")
+ user.drop_item()
+ qdel(O)
+ eggsleft += rand(1, 4)
+ else
+ user << "\blue [name] doesn't seem hungry!"
+ else
+ user << "[name] doesn't seem interested in that."
+ else
+ ..()
+
+/mob/living/simple_animal/chicken/Life()
+ . =..()
+ if(!.)
+ return
+ if(!stat && prob(3) && eggsleft > 0)
+ visible_message("[src] [pick("lays an egg.","squats down and croons.","begins making a huge racket.","begins clucking raucously.")]")
+ eggsleft--
+ var/obj/item/weapon/reagent_containers/food/snacks/egg/E = new(get_turf(src))
+ E.pixel_x = rand(-6,6)
+ E.pixel_y = rand(-6,6)
+ if(chicken_count < MAX_CHICKENS && prob(10))
+ processing_objects.Add(E)
+
+/obj/item/weapon/reagent_containers/food/snacks/egg/var/amount_grown = 0
+/obj/item/weapon/reagent_containers/food/snacks/egg/process()
+ if(isturf(loc))
+ amount_grown += rand(1,2)
+ if(amount_grown >= 100)
+ visible_message("[src] hatches with a quiet cracking sound.")
+ new /mob/living/simple_animal/chick(get_turf(src))
+ processing_objects.Remove(src)
+ qdel(src)
+ else
+ processing_objects.Remove(src)
diff --git a/code/modules/mob/living/simple_animal/animals/giant_spider.dm b/code/modules/mob/living/simple_animal/animals/giant_spider.dm
new file mode 100644
index 00000000000..ed692ab237f
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/animals/giant_spider.dm
@@ -0,0 +1,239 @@
+
+#define SPINNING_WEB 1
+#define LAYING_EGGS 2
+#define MOVING_TO_TARGET 3
+#define SPINNING_COCOON 4
+
+//basic spider mob, these generally guard nests
+/mob/living/simple_animal/hostile/giant_spider
+ name = "giant spider"
+ desc = "Furry and black, it makes you shudder to look at it. This one has deep red eyes."
+ icon_state = "guard"
+ icon_living = "guard"
+ icon_dead = "guard_dead"
+
+ faction = "spiders"
+ maxHealth = 200
+ health = 200
+ pass_flags = PASSTABLE
+ move_to_delay = 6
+ speed = 3
+
+ stop_when_pulled = 0
+ turns_per_move = 5
+ see_in_dark = 10
+
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "punches"
+
+ melee_damage_lower = 15
+ melee_damage_upper = 20
+ heat_damage_per_tick = 20
+ cold_damage_per_tick = 20
+
+ speak_chance = 5
+ speak_emote = list("chitters")
+ emote_hear = list("chitters")
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat
+
+ var/busy = 0
+ var/poison_per_bite = 5
+ var/poison_chance = 10
+ var/poison_type = "spidertoxin"
+
+//nursemaids - these create webs and eggs
+/mob/living/simple_animal/hostile/giant_spider/nurse
+ desc = "Furry and black, it makes you shudder to look at it. This one has brilliant green eyes."
+ icon_state = "nurse"
+ icon_living = "nurse"
+ icon_dead = "nurse_dead"
+
+ maxHealth = 40
+ health = 40
+
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+ poison_per_bite = 7
+ poison_type = "stoxin"
+
+ var/fed = 0
+ var/atom/cocoon_target
+
+//hunters have the most poison and move the fastest, so they can find prey
+/mob/living/simple_animal/hostile/giant_spider/hunter
+ desc = "Furry and black, it makes you shudder to look at it. This one has sparkling purple eyes."
+ icon_state = "hunter"
+ icon_living = "hunter"
+ icon_dead = "hunter_dead"
+
+ maxHealth = 120
+ health = 120
+ move_to_delay = 4
+
+ melee_damage_lower = 10
+ melee_damage_upper = 20
+
+ poison_per_bite = 5
+
+/mob/living/simple_animal/hostile/giant_spider/New(var/location, var/atom/parent)
+ get_light_and_color(parent)
+ ..()
+
+/mob/living/simple_animal/hostile/giant_spider/PunchTarget()
+ . = ..()
+ if(isliving(.))
+ var/mob/living/L = .
+ if(L.reagents)
+ L.reagents.add_reagent(poison_type, poison_per_bite)
+ if(prob(poison_chance))
+ L << "You feel a tiny prick."
+ L.reagents.add_reagent(poison_type, poison_per_bite)
+
+/mob/living/simple_animal/hostile/giant_spider/nurse/PunchTarget()
+ . = ..()
+ if(ishuman(.))
+ var/mob/living/carbon/human/H = .
+ if(prob(5))
+ var/obj/item/organ/external/O = pick(H.organs)
+ if(!(O.robotic >= ORGAN_ROBOT))
+ var/eggcount
+ for(var/obj/I in O.implants)
+ if(istype(I, /obj/effect/spider/eggcluster))
+ eggcount ++
+ if(!eggcount)
+ var/eggs = PoolOrNew(/obj/effect/spider/eggcluster/small, list(O, src))
+ O.implants += eggs
+ H << "The [src] injects something into your [O.name]!"
+
+/mob/living/simple_animal/hostile/giant_spider/handle_stance()
+ . = ..()
+ if(ai_inactive) return
+
+ switch(stance)
+ if(STANCE_IDLE)
+ //1% chance to skitter madly away
+ if(!busy && prob(1))
+ /*var/list/move_targets = list()
+ for(var/turf/T in orange(20, src))
+ move_targets.Add(T)*/
+ stop_automated_movement = 1
+ walk_to(src, pick(orange(20, src)), 1, move_to_delay)
+ spawn(5 SECONDS)
+ stop_automated_movement = 0
+ walk(src,0)
+
+/mob/living/simple_animal/hostile/giant_spider/nurse/proc/GiveUp(var/C)
+ spawn(10 SECONDS)
+ if(busy == MOVING_TO_TARGET)
+ if(cocoon_target == C && get_dist(src,cocoon_target) > 1)
+ cocoon_target = null
+ busy = 0
+ stop_automated_movement = 0
+
+/mob/living/simple_animal/hostile/giant_spider/nurse/Life()
+ . = ..()
+ if(!. || ai_inactive) return
+
+ if(stance == STANCE_IDLE)
+ var/list/can_see = view(src, 10)
+ //30% chance to stop wandering and do something
+ if(!busy && prob(30))
+ //first, check for potential food nearby to cocoon
+ for(var/mob/living/C in can_see)
+ if(C.stat)
+ cocoon_target = C
+ busy = MOVING_TO_TARGET
+ walk_to(src, C, 1, move_to_delay)
+ //give up if we can't reach them after 10 seconds
+ GiveUp(C)
+ return
+
+ //second, spin a sticky spiderweb on this tile
+ var/obj/effect/spider/stickyweb/W = locate() in get_turf(src)
+ if(!W)
+ busy = SPINNING_WEB
+ src.visible_message("\The [src] begins to secrete a sticky substance.")
+ stop_automated_movement = 1
+ spawn(40)
+ if(busy == SPINNING_WEB)
+ new /obj/effect/spider/stickyweb(src.loc)
+ busy = 0
+ stop_automated_movement = 0
+ else
+ //third, lay an egg cluster there
+ var/obj/effect/spider/eggcluster/E = locate() in get_turf(src)
+ if(!E && fed > 0)
+ busy = LAYING_EGGS
+ src.visible_message("\The [src] begins to lay a cluster of eggs.")
+ stop_automated_movement = 1
+ spawn(50)
+ if(busy == LAYING_EGGS)
+ E = locate() in get_turf(src)
+ if(!E)
+ PoolOrNew(/obj/effect/spider/eggcluster, list(loc, src))
+ fed--
+ busy = 0
+ stop_automated_movement = 0
+ else
+ //fourthly, cocoon any nearby items so those pesky pinkskins can't use them
+ for(var/obj/O in can_see)
+
+ if(O.anchored)
+ continue
+
+ if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery))
+ cocoon_target = O
+ busy = MOVING_TO_TARGET
+ stop_automated_movement = 1
+ walk_to(src, O, 1, move_to_delay)
+ //give up if we can't reach them after 10 seconds
+ GiveUp(O)
+
+ else if(busy == MOVING_TO_TARGET && cocoon_target)
+ if(get_dist(src, cocoon_target) <= 1)
+ busy = SPINNING_COCOON
+ src.visible_message("\The [src] begins to secrete a sticky substance around \the [cocoon_target].")
+ stop_automated_movement = 1
+ walk(src,0)
+ spawn(50)
+ if(busy == SPINNING_COCOON)
+ if(cocoon_target && istype(cocoon_target.loc, /turf) && get_dist(src,cocoon_target) <= 1)
+ var/obj/effect/spider/cocoon/C = new(cocoon_target.loc)
+ var/large_cocoon = 0
+ C.pixel_x = cocoon_target.pixel_x
+ C.pixel_y = cocoon_target.pixel_y
+ for(var/mob/living/M in C.loc)
+ if(istype(M, /mob/living/simple_animal/hostile/giant_spider))
+ continue
+ large_cocoon = 1
+ fed++
+ src.visible_message("\The [src] sticks a proboscis into \the [cocoon_target] and sucks a viscous substance out.")
+ M.forceMove(C)
+ C.pixel_x = M.pixel_x
+ C.pixel_y = M.pixel_y
+ break
+ for(var/obj/item/I in C.loc)
+ I.forceMove(C)
+ for(var/obj/structure/S in C.loc)
+ if(!S.anchored)
+ S.forceMove(C)
+ large_cocoon = 1
+ for(var/obj/machinery/M in C.loc)
+ if(!M.anchored)
+ M.forceMove(C)
+ large_cocoon = 1
+ if(large_cocoon)
+ C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3")
+ busy = 0
+ stop_automated_movement = 0
+
+ else
+ busy = 0
+ stop_automated_movement = 0
+
+#undef SPINNING_WEB
+#undef LAYING_EGGS
+#undef MOVING_TO_TARGET
+#undef SPINNING_COCOON
diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/animals/goose.dm
similarity index 55%
rename from code/modules/mob/living/simple_animal/hostile/goose.dm
rename to code/modules/mob/living/simple_animal/animals/goose.dm
index 0f2c4af6117..217ea0b0246 100644
--- a/code/modules/mob/living/simple_animal/hostile/goose.dm
+++ b/code/modules/mob/living/simple_animal/animals/goose.dm
@@ -1,5 +1,3 @@
-
-
/mob/living/simple_animal/hostile/goose
name = "space goose"
desc = "That's no duck. That's a space goose. You have a bad feeling about this."
@@ -7,15 +5,18 @@
icon_living = "goose"
icon_dead = "goose_dead"
icon_gib = "generic_gib"
- speak_chance = 0
+
+ faction = "geese"
+
+ maxHealth = 15
+ health = 15
+ speed = 4
+
turns_per_move = 5
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
response_help = "pets the"
response_disarm = "gently pushes aside the"
response_harm = "hits the"
- speed = 4
- maxHealth = 15 //nothing an unarmed crewmember shouldn't be able to stomp into the dirt, if they're alone.
- health = 15
harm_intent_damage = 5
melee_damage_lower = 5 //they're meant to be annoying, not threatening.
@@ -23,12 +24,34 @@
attacktext = "pecked"
attack_sound = 'sound/weapons/bite.ogg'
- break_stuff_probability = 5
+ //SPACE geese aren't affected by atmos.
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
- faction = "geese"
+ speak_chance = 10
+ speak = list("HONK!")
+ emote_hear = list("honks loudly!")
+ emote_see = list()
+ say_understood = list()
+ say_cannot = list()
+ say_maybe_target = list("Honk?")
+ say_got_target = list("HONK!!!")
+ reactions = list()
-/mob/living/simple_animal/hostile/goose/FindTarget()
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
+/mob/living/simple_animal/hostile/goose/set_target()
. = ..()
if(.)
- custom_emote(1,"flaps and honks at [.]!")
\ No newline at end of file
+ custom_emote(1,"flaps and honks at [.]!")
+
+/mob/living/simple_animal/hostile/goose/Process_Spacemove(var/check_drift = 0)
+ return
diff --git a/code/modules/mob/living/simple_animal/friendly/lizard.dm b/code/modules/mob/living/simple_animal/animals/lizard.dm
similarity index 95%
rename from code/modules/mob/living/simple_animal/friendly/lizard.dm
rename to code/modules/mob/living/simple_animal/animals/lizard.dm
index fe1ab1dcd05..5c986d21bba 100644
--- a/code/modules/mob/living/simple_animal/friendly/lizard.dm
+++ b/code/modules/mob/living/simple_animal/animals/lizard.dm
@@ -1,17 +1,22 @@
-/mob/living/simple_animal/lizard
- name = "Lizard"
- desc = "A cute tiny lizard."
- icon = 'icons/mob/critter.dmi'
- icon_state = "lizard"
- icon_living = "lizard"
- icon_dead = "lizard-dead"
- speak_emote = list("hisses")
- health = 5
- maxHealth = 5
- attacktext = "bitten"
- melee_damage_lower = 1
- melee_damage_upper = 2
- response_help = "pets"
- response_disarm = "shoos"
- response_harm = "stomps on"
- mob_size = MOB_MINISCULE
+/mob/living/simple_animal/lizard
+ name = "Lizard"
+ desc = "A cute tiny lizard."
+ icon = 'icons/mob/critter.dmi'
+ icon_state = "lizard"
+ icon_living = "lizard"
+ icon_dead = "lizard-dead"
+
+ health = 5
+ maxHealth = 5
+ mob_size = MOB_MINISCULE
+
+ response_help = "pets"
+ response_disarm = "shoos"
+ response_harm = "stomps on"
+
+ attacktext = "bitten"
+ melee_damage_lower = 1
+ melee_damage_upper = 2
+
+ speak_chance = 1
+ speak_emote = list("hisses")
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/animals/mouse.dm
similarity index 89%
rename from code/modules/mob/living/simple_animal/friendly/mouse.dm
rename to code/modules/mob/living/simple_animal/animals/mouse.dm
index cd545e0a87d..43b12961bd6 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/animals/mouse.dm
@@ -1,130 +1,136 @@
-/mob/living/simple_animal/mouse
- name = "mouse"
- real_name = "mouse"
- desc = "It's a small rodent."
- icon_state = "mouse_gray"
- item_state = "mouse_gray"
- icon_living = "mouse_gray"
- icon_dead = "mouse_gray_dead"
- speak = list("Squeek!","SQUEEK!","Squeek?")
- speak_emote = list("squeeks","squeeks","squiks")
- emote_hear = list("squeeks","squeaks","squiks")
- emote_see = list("runs in a circle", "shakes", "scritches at something")
- pass_flags = PASSTABLE
- speak_chance = 1
- turns_per_move = 5
- see_in_dark = 6
- maxHealth = 5
- health = 5
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "stamps on"
- density = 0
- var/body_color //brown, gray and white, leave blank for random
- layer = MOB_LAYER
- min_oxy = 16 //Require atleast 16kPA oxygen
- minbodytemp = 223 //Below -50 Degrees Celcius
- maxbodytemp = 323 //Above 50 Degrees Celcius
- universal_speak = 0
- universal_understand = 1
- holder_type = /obj/item/weapon/holder/mouse
- mob_size = MOB_MINISCULE
-
- can_pull_size = ITEMSIZE_TINY
- can_pull_mobs = MOB_PULL_NONE
-
-/mob/living/simple_animal/mouse/Life()
- ..()
- if(!stat && prob(speak_chance))
- for(var/mob/M in view())
- M << 'sound/effects/mousesqueek.ogg'
-
- if(!ckey && stat == CONSCIOUS && prob(0.5))
- stat = UNCONSCIOUS
- icon_state = "mouse_[body_color]_sleep"
- wander = 0
- speak_chance = 0
- //snuffles
- else if(stat == UNCONSCIOUS)
- if(ckey || prob(1))
- stat = CONSCIOUS
- icon_state = "mouse_[body_color]"
- wander = 1
- else if(prob(5))
- audible_emote("snuffles.")
-
-/mob/living/simple_animal/mouse/lay_down() //Simply turns sprite into sleeping and back upon using "Rest".
- ..()
- icon_state = resting ? "mouse_[body_color]_sleep" : "mouse_[body_color]"
-
-/mob/living/simple_animal/mouse/New()
- ..()
-
- verbs += /mob/living/proc/ventcrawl
- verbs += /mob/living/proc/hide
-
- if(name == initial(name))
- name = "[name] ([rand(1, 1000)])"
- real_name = name
-
- if(!body_color)
- body_color = pick( list("brown","gray","white") )
- icon_state = "mouse_[body_color]"
- item_state = "mouse_[body_color]"
- icon_living = "mouse_[body_color]"
- icon_dead = "mouse_[body_color]_dead"
- desc = "It's a small [body_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself."
-
-/mob/living/simple_animal/mouse/proc/splat()
- src.health = 0
- src.stat = DEAD
- src.icon_dead = "mouse_[body_color]_splat"
- src.icon_state = "mouse_[body_color]_splat"
- layer = MOB_LAYER
- if(client)
- client.time_died_as_mouse = world.time
-
-
-/mob/living/simple_animal/mouse/Crossed(AM as mob|obj)
- if( ishuman(AM) )
- if(!stat)
- var/mob/M = AM
- M << "\blue \icon[src] Squeek!"
- M << 'sound/effects/mousesqueek.ogg'
- ..()
-
-/mob/living/simple_animal/mouse/death()
- layer = MOB_LAYER
- if(client)
- client.time_died_as_mouse = world.time
- ..()
-
-/*
- * Mouse types
- */
-
-/mob/living/simple_animal/mouse/white
- body_color = "white"
- icon_state = "mouse_white"
-
-/mob/living/simple_animal/mouse/gray
- body_color = "gray"
- icon_state = "mouse_gray"
-
-/mob/living/simple_animal/mouse/brown
- body_color = "brown"
- icon_state = "mouse_brown"
-
-//TOM IS ALIVE! SQUEEEEEEEE~K :)
-/mob/living/simple_animal/mouse/brown/Tom
- name = "Tom"
- desc = "Jerry the cat is not amused."
-
-/mob/living/simple_animal/mouse/brown/Tom/New()
- ..()
- // Change my name back, don't want to be named Tom (666)
- name = initial(name)
-
-/mob/living/simple_animal/mouse/cannot_use_vents()
- return
+/mob/living/simple_animal/mouse
+ name = "mouse"
+ real_name = "mouse"
+ desc = "It's a small rodent."
+ icon_state = "mouse_gray"
+ item_state = "mouse_gray"
+ icon_living = "mouse_gray"
+ icon_dead = "mouse_gray_dead"
+
+ maxHealth = 5
+ health = 5
+
+ turns_per_move = 5
+ see_in_dark = 6
+ universal_understand = 1
+
+ mob_size = MOB_MINISCULE
+ pass_flags = PASSTABLE
+ can_pull_size = ITEMSIZE_TINY
+ can_pull_mobs = MOB_PULL_NONE
+ layer = MOB_LAYER
+ density = 0
+
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "stamps on"
+
+ min_oxy = 16 //Require atleast 16kPA oxygen
+ minbodytemp = 223 //Below -50 Degrees Celcius
+ maxbodytemp = 323 //Above 50 Degrees Celcius
+
+ speak_chance = 1
+ speak = list("Squeek!","SQUEEK!","Squeek?")
+ speak_emote = list("squeeks","squeeks","squiks")
+ emote_hear = list("squeeks","squeaks","squiks")
+ emote_see = list("runs in a circle", "shakes", "scritches at something")
+
+ holder_type = /obj/item/weapon/holder/mouse
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
+ var/body_color //brown, gray and white, leave blank for random
+
+/mob/living/simple_animal/mouse/Life()
+ . = ..()
+ if(!. || ai_inactive) return
+
+ if(prob(speak_chance))
+ for(var/mob/M in view())
+ M << 'sound/effects/mousesqueek.ogg'
+
+ if(!ckey && stat == CONSCIOUS && prob(0.5))
+ stat = UNCONSCIOUS
+ icon_state = "mouse_[body_color]_sleep"
+ wander = 0
+ speak_chance = 0
+ //snuffles
+
+ else if(stat == UNCONSCIOUS)
+ if(ckey || prob(1))
+ stat = CONSCIOUS
+ icon_state = "mouse_[body_color]"
+ wander = 1
+ else if(prob(5))
+ audible_emote("snuffles.")
+
+/mob/living/simple_animal/mouse/New()
+ ..()
+
+ verbs += /mob/living/proc/ventcrawl
+ verbs += /mob/living/proc/hide
+
+ if(name == initial(name))
+ name = "[name] ([rand(1, 1000)])"
+ real_name = name
+
+ if(!body_color)
+ body_color = pick( list("brown","gray","white") )
+ icon_state = "mouse_[body_color]"
+ item_state = "mouse_[body_color]"
+ icon_living = "mouse_[body_color]"
+ icon_dead = "mouse_[body_color]_dead"
+ icon_rest = "mouse_[body_color]_sleep"
+ desc = "It's a small [body_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself."
+
+/mob/living/simple_animal/mouse/proc/splat()
+ src.health = 0
+ src.stat = DEAD
+ src.icon_dead = "mouse_[body_color]_splat"
+ src.icon_state = "mouse_[body_color]_splat"
+ layer = MOB_LAYER
+ if(client)
+ client.time_died_as_mouse = world.time
+
+
+/mob/living/simple_animal/mouse/Crossed(AM as mob|obj)
+ if( ishuman(AM) )
+ if(!stat)
+ var/mob/M = AM
+ M << "\blue \icon[src] Squeek!"
+ M << 'sound/effects/mousesqueek.ogg'
+ ..()
+
+/mob/living/simple_animal/mouse/death()
+ layer = MOB_LAYER
+ if(client)
+ client.time_died_as_mouse = world.time
+ ..()
+
+/*
+ * Mouse types
+ */
+
+/mob/living/simple_animal/mouse/white
+ body_color = "white"
+ icon_state = "mouse_white"
+
+/mob/living/simple_animal/mouse/gray
+ body_color = "gray"
+ icon_state = "mouse_gray"
+
+/mob/living/simple_animal/mouse/brown
+ body_color = "brown"
+ icon_state = "mouse_brown"
+
+//TOM IS ALIVE! SQUEEEEEEEE~K :)
+/mob/living/simple_animal/mouse/brown/Tom
+ name = "Tom"
+ desc = "Jerry the cat is not amused."
+
+/mob/living/simple_animal/mouse/brown/Tom/New()
+ ..()
+ // Change my name back, don't want to be named Tom (666)
+ name = initial(name)
+
+/mob/living/simple_animal/mouse/cannot_use_vents()
+ return
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/animals/parrot.dm
similarity index 95%
rename from code/modules/mob/living/simple_animal/parrot.dm
rename to code/modules/mob/living/simple_animal/animals/parrot.dm
index 36a1ac186ab..d388939fcdd 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/animals/parrot.dm
@@ -1,757 +1,761 @@
-/* Parrots!
- * Contains
- * Defines
- * Inventory (headset stuff)
- * Attack responces
- * AI
- * Procs / Verbs (usable by players)
- * Sub-types
- */
-
-/*
- * Defines
- */
-
-//Only a maximum of one action and one intent should be active at any given time.
-//Actions
-#define PARROT_PERCH 1 //Sitting/sleeping, not moving
-#define PARROT_SWOOP 2 //Moving towards or away from a target
-#define PARROT_WANDER 4 //Moving without a specific target in mind
-
-//Intents
-#define PARROT_STEAL 8 //Flying towards a target to steal it/from it
-#define PARROT_ATTACK 16 //Flying towards a target to attack it
-#define PARROT_RETURN 32 //Flying towards its perch
-#define PARROT_FLEE 64 //Flying away from its attacker
-
-
-/mob/living/simple_animal/parrot
- name = "\improper Parrot"
- desc = "The parrot squaks, \"It's a Parrot! BAWWK!\""
- icon = 'icons/mob/animal.dmi'
- icon_state = "parrot_fly"
- icon_living = "parrot_fly"
- icon_dead = "parrot_dead"
- pass_flags = PASSTABLE
- mob_size = MOB_SMALL
-
- speak = list("Hi","Hello!","Cracker?","BAWWWWK george mellons griffing me")
- speak_emote = list("squawks","says","yells")
- emote_hear = list("squawks","bawks")
- emote_see = list("flutters its wings")
-
- speak_chance = 1//1% (1 in 100) chance every tick; So about once per 150 seconds, assuming an average tick is 1.5s
- turns_per_move = 5
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/cracker/
-
- response_help = "pets"
- response_disarm = "gently moves aside"
- response_harm = "swats"
- stop_automated_movement = 1
- universal_speak = 1
-
- var/parrot_state = PARROT_WANDER //Hunt for a perch when created
- var/parrot_sleep_max = 25 //The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in life() being run every single tick.
- var/parrot_sleep_dur = 25 //Same as above, this is the var that physically counts down
- var/parrot_dam_zone = list(BP_TORSO, BP_HEAD, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG) //For humans, select a bodypart to attack
-
- var/parrot_speed = 5 //"Delay in world ticks between movement." according to byond. Yeah, that's BS but it does directly affect movement. Higher number = slower.
- var/parrot_been_shot = 0 //Parrots get a speed bonus after being shot. This will deincrement every Life() and at 0 the parrot will return to regular speed.
-
- var/list/speech_buffer = list()
- var/list/available_channels = list()
-
- //Headset for Poly to yell at engineers :)
- var/obj/item/device/radio/headset/ears = null
-
- //The thing the parrot is currently interested in. This gets used for items the parrot wants to pick up, mobs it wants to steal from,
- //mobs it wants to attack or mobs that have attacked it
- var/atom/movable/parrot_interest = null
-
- //Parrots will generally sit on their pertch unless something catches their eye.
- //These vars store their preffered perch and if they dont have one, what they can use as a perch
- var/obj/parrot_perch = null
- var/obj/desired_perches = list(/obj/structure/frame, /obj/structure/displaycase, \
- /obj/structure/filingcabinet, /obj/machinery/teleport, \
- /obj/machinery/computer, /obj/machinery/clonepod, \
- /obj/machinery/dna_scannernew, /obj/machinery/telecomms, \
- /obj/machinery/nuclearbomb, /obj/machinery/particle_accelerator, \
- /obj/machinery/recharge_station, /obj/machinery/smartfridge, \
- /obj/machinery/suit_storage_unit)
-
- //Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding.
- var/obj/item/held_item = null
-
-
-/mob/living/simple_animal/parrot/New()
- ..()
- if(!ears)
- var/headset = pick(/obj/item/device/radio/headset/headset_sec, \
- /obj/item/device/radio/headset/headset_eng, \
- /obj/item/device/radio/headset/headset_med, \
- /obj/item/device/radio/headset/headset_sci, \
- /obj/item/device/radio/headset/headset_cargo)
- ears = new headset(src)
-
- parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var
-
- verbs.Add(/mob/living/simple_animal/parrot/proc/steal_from_ground, \
- /mob/living/simple_animal/parrot/proc/steal_from_mob, \
- /mob/living/simple_animal/parrot/verb/drop_held_item_player, \
- /mob/living/simple_animal/parrot/proc/perch_player)
-
-
-/mob/living/simple_animal/parrot/death()
- if(held_item)
- held_item.loc = src.loc
- held_item = null
- walk(src,0)
- ..()
-
-/mob/living/simple_animal/parrot/Stat()
- ..()
- stat("Held Item", held_item)
-
-/*
- * Inventory
- */
-/mob/living/simple_animal/parrot/show_inv(mob/user as mob)
- user.set_machine(src)
- if(user.stat) return
-
- var/dat = "
Inventory of [name]
"
- if(ears)
- dat += " Headset: [ears] (Remove)"
- else
- dat += " Headset:Nothing"
-
- user << browse(dat, text("window=mob[];size=325x500", name))
- onclose(user, "mob[real_name]")
- return
-
-/mob/living/simple_animal/parrot/Topic(href, href_list)
-
- //Can the usr physically do this?
- if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
- return
-
- //Is the usr's mob type able to do this?
- if(ishuman(usr) || issmall(usr) || isrobot(usr))
-
- //Removing from inventory
- if(href_list["remove_inv"])
- var/remove_from = href_list["remove_inv"]
- switch(remove_from)
- if("ears")
- if(ears)
- if(available_channels.len)
- src.say("[pick(available_channels)] BAWWWWWK LEAVE THE HEADSET BAWKKKKK!")
- else
- src.say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!")
- ears.loc = src.loc
- ears = null
- for(var/possible_phrase in speak)
- if(copytext(possible_phrase,1,3) in department_radio_keys)
- possible_phrase = copytext(possible_phrase,3,length(possible_phrase))
- else
- usr << "\red There is nothing to remove from its [remove_from]."
- return
-
- //Adding things to inventory
- else if(href_list["add_inv"])
- var/add_to = href_list["add_inv"]
- if(!usr.get_active_hand())
- usr << "\red You have nothing in your hand to put on its [add_to]."
- return
- switch(add_to)
- if("ears")
- if(ears)
- usr << "\red It's already wearing something."
- return
- else
- var/obj/item/item_to_add = usr.get_active_hand()
- if(!item_to_add)
- return
-
- if( !istype(item_to_add, /obj/item/device/radio/headset) )
- usr << "\red This object won't fit."
- return
-
- var/obj/item/device/radio/headset/headset_to_add = item_to_add
-
- usr.drop_item()
- headset_to_add.loc = src
- src.ears = headset_to_add
- usr << "You fit the headset onto [src]."
-
- clearlist(available_channels)
- for(var/ch in headset_to_add.channels)
- switch(ch)
- if("Engineering")
- available_channels.Add(":e")
- if("Command")
- available_channels.Add(":c")
- if("Security")
- available_channels.Add(":s")
- if("Science")
- available_channels.Add(":n")
- if("Medical")
- available_channels.Add(":m")
- if("Mining")
- available_channels.Add(":d")
- if("Cargo")
- available_channels.Add(":q")
-
- if(headset_to_add.translate_binary)
- available_channels.Add(":b")
- else
- ..()
-
-
-/*
- * Attack responces
- */
-//Humans, monkeys, aliens
-/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M as mob)
- ..()
- if(client) return
- if(!stat && M.a_intent == I_HURT)
-
- icon_state = "parrot_fly" //It is going to be flying regardless of whether it flees or attacks
-
- if(parrot_state == PARROT_PERCH)
- parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
-
- parrot_interest = M
- parrot_state = PARROT_SWOOP //The parrot just got hit, it WILL move, now to pick a direction..
-
- if(M.health < 50) //Weakened mob? Fight back!
- parrot_state |= PARROT_ATTACK
- else
- parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell!
- drop_held_item(0)
- return
-
-//Mobs with objects
-/mob/living/simple_animal/parrot/attackby(var/obj/item/O as obj, var/mob/user as mob)
- ..()
- if(!stat && !client && !istype(O, /obj/item/stack/medical))
- if(O.force)
- if(parrot_state == PARROT_PERCH)
- parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
-
- parrot_interest = user
- parrot_state = PARROT_SWOOP | PARROT_FLEE
- icon_state = "parrot_fly"
- drop_held_item(0)
- return
-
-//Bullets
-/mob/living/simple_animal/parrot/bullet_act(var/obj/item/projectile/Proj)
- ..()
- if(!stat && !client)
- if(parrot_state == PARROT_PERCH)
- parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
-
- parrot_interest = null
- parrot_state = PARROT_WANDER //OWFUCK, Been shot! RUN LIKE HELL!
- parrot_been_shot += 5
- icon_state = "parrot_fly"
- drop_held_item(0)
- return
-
-
-/*
- * AI - Not really intelligent, but I'm calling it AI anyway.
- */
-/mob/living/simple_animal/parrot/Life()
- ..()
-
- //Sprite and AI update for when a parrot gets pulled
- if(pulledby && stat == CONSCIOUS)
- icon_state = "parrot_fly"
- if(!client)
- parrot_state = PARROT_WANDER
- return
-
- if(client || stat)
- return //Lets not force players or dead/incap parrots to move
-
- if(!isturf(src.loc) || !canmove || buckled)
- return //If it can't move, dont let it move. (The buckled check probably isn't necessary thanks to canmove)
-
-
-//-----SPEECH
- /* Parrot speech mimickry!
- Phrases that the parrot hears in mob/living/say() get added to speach_buffer.
- Every once in a while, the parrot picks one of the lines from the buffer and replaces an element of the 'speech' list.
- Then it clears the buffer to make sure they dont magically remember something from hours ago. */
- if(speech_buffer.len && prob(10))
- if(speak.len)
- speak.Remove(pick(speak))
-
- speak.Add(pick(speech_buffer))
- clearlist(speech_buffer)
-
-
-//-----SLEEPING
- if(parrot_state == PARROT_PERCH)
- if(parrot_perch && parrot_perch.loc != src.loc) //Make sure someone hasnt moved our perch on us
- if(parrot_perch in view(src))
- parrot_state = PARROT_SWOOP | PARROT_RETURN
- icon_state = "parrot_fly"
- return
- else
- parrot_state = PARROT_WANDER
- icon_state = "parrot_fly"
- return
-
- if(--parrot_sleep_dur) //Zzz
- return
-
- else
- //This way we only call the stuff below once every [sleep_max] ticks.
- parrot_sleep_dur = parrot_sleep_max
-
- //Cycle through message modes for the headset
- if(speak.len)
- var/list/newspeak = list()
-
- if(available_channels.len && src.ears)
- for(var/possible_phrase in speak)
-
- //50/50 chance to not use the radio at all
- var/useradio = 0
- if(prob(50))
- useradio = 1
-
- if(copytext(possible_phrase,1,3) in department_radio_keys)
- possible_phrase = "[useradio?pick(available_channels):""] [copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix
- else
- possible_phrase = "[useradio?pick(available_channels):""] [possible_phrase]"
-
- newspeak.Add(possible_phrase)
-
- else //If we have no headset or channels to use, dont try to use any!
- for(var/possible_phrase in speak)
- if(copytext(possible_phrase,1,3) in department_radio_keys)
- possible_phrase = "[copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix
- newspeak.Add(possible_phrase)
- speak = newspeak
-
- //Search for item to steal
- parrot_interest = search_for_item()
- if(parrot_interest)
- visible_emote("looks in [parrot_interest]'s direction and takes flight")
- parrot_state = PARROT_SWOOP | PARROT_STEAL
- icon_state = "parrot_fly"
- return
-
-//-----WANDERING - This is basically a 'I dont know what to do yet' state
- else if(parrot_state == PARROT_WANDER)
- //Stop movement, we'll set it later
- walk(src, 0)
- parrot_interest = null
-
- //Wander around aimlessly. This will help keep the loops from searches down
- //and possibly move the mob into a new are in view of something they can use
- if(prob(90))
- step(src, pick(cardinal))
- return
-
- if(!held_item && !parrot_perch) //If we've got nothing to do.. look for something to do.
- var/atom/movable/AM = search_for_perch_and_item() //This handles checking through lists so we know it's either a perch or stealable item
- if(AM)
- if(istype(AM, /obj/item) || isliving(AM)) //If stealable item
- parrot_interest = AM
- visible_emote("turns and flies towards [parrot_interest]")
- parrot_state = PARROT_SWOOP | PARROT_STEAL
- return
- else //Else it's a perch
- parrot_perch = AM
- parrot_state = PARROT_SWOOP | PARROT_RETURN
- return
- return
-
- if(parrot_interest && parrot_interest in view(src))
- parrot_state = PARROT_SWOOP | PARROT_STEAL
- return
-
- if(parrot_perch && parrot_perch in view(src))
- parrot_state = PARROT_SWOOP | PARROT_RETURN
- return
-
- else //Have an item but no perch? Find one!
- parrot_perch = search_for_perch()
- if(parrot_perch)
- parrot_state = PARROT_SWOOP | PARROT_RETURN
- return
-//-----STEALING
- else if(parrot_state == (PARROT_SWOOP | PARROT_STEAL))
- walk(src,0)
- if(!parrot_interest || held_item)
- parrot_state = PARROT_SWOOP | PARROT_RETURN
- return
-
- if(!(parrot_interest in view(src)))
- parrot_state = PARROT_SWOOP | PARROT_RETURN
- return
-
- if(in_range(src, parrot_interest))
-
- if(isliving(parrot_interest))
- steal_from_mob()
-
- else //This should ensure that we only grab the item we want, and make sure it's not already collected on our perch
- if(!parrot_perch || parrot_interest.loc != parrot_perch.loc)
- held_item = parrot_interest
- parrot_interest.loc = src
- visible_message("[src] grabs the [held_item]!", "\blue You grab the [held_item]!", "You hear the sounds of wings flapping furiously.")
-
- parrot_interest = null
- parrot_state = PARROT_SWOOP | PARROT_RETURN
- return
-
- walk_to(src, parrot_interest, 1, parrot_speed)
- return
-
-//-----RETURNING TO PERCH
- else if(parrot_state == (PARROT_SWOOP | PARROT_RETURN))
- walk(src, 0)
- if(!parrot_perch || !isturf(parrot_perch.loc)) //Make sure the perch exists and somehow isnt inside of something else.
- parrot_perch = null
- parrot_state = PARROT_WANDER
- return
-
- if(in_range(src, parrot_perch))
- src.loc = parrot_perch.loc
- drop_held_item()
- parrot_state = PARROT_PERCH
- icon_state = "parrot_sit"
- return
-
- walk_to(src, parrot_perch, 1, parrot_speed)
- return
-
-//-----FLEEING
- else if(parrot_state == (PARROT_SWOOP | PARROT_FLEE))
- walk(src,0)
- if(!parrot_interest || !isliving(parrot_interest)) //Sanity
- parrot_state = PARROT_WANDER
-
- walk_away(src, parrot_interest, 1, parrot_speed-parrot_been_shot)
- parrot_been_shot--
- return
-
-//-----ATTACKING
- else if(parrot_state == (PARROT_SWOOP | PARROT_ATTACK))
-
- //If we're attacking a nothing, an object, a turf or a ghost for some stupid reason, switch to wander
- if(!parrot_interest || !isliving(parrot_interest))
- parrot_interest = null
- parrot_state = PARROT_WANDER
- return
-
- var/mob/living/L = parrot_interest
-
- //If the mob is close enough to interact with
- if(in_range(src, parrot_interest))
-
- //If the mob we've been chasing/attacking dies or falls into crit, check for loot!
- if(L.stat)
- parrot_interest = null
- if(!held_item)
- held_item = steal_from_ground()
- if(!held_item)
- held_item = steal_from_mob() //Apparently it's possible for dead mobs to hang onto items in certain circumstances.
- if(parrot_perch in view(src)) //If we have a home nearby, go to it, otherwise find a new home
- parrot_state = PARROT_SWOOP | PARROT_RETURN
- else
- parrot_state = PARROT_WANDER
- return
-
- //Time for the hurt to begin!
- var/damage = rand(5,10)
-
- if(ishuman(parrot_interest))
- var/mob/living/carbon/human/H = parrot_interest
- var/obj/item/organ/external/affecting = H.get_organ(ran_zone(pick(parrot_dam_zone)))
-
- H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), sharp=1)
- visible_emote(pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons."))
-
- else
- L.adjustBruteLoss(damage)
- visible_emote(pick("pecks at [L].", "claws [L]."))
- return
-
- //Otherwise, fly towards the mob!
- else
- walk_to(src, parrot_interest, 1, parrot_speed)
- return
-//-----STATE MISHAP
- else //This should not happen. If it does lets reset everything and try again
- walk(src,0)
- parrot_interest = null
- parrot_perch = null
- drop_held_item()
- parrot_state = PARROT_WANDER
- return
-
-/*
- * Procs
- */
-
-/mob/living/simple_animal/parrot/movement_delay()
- if(client && stat == CONSCIOUS && parrot_state != "parrot_fly")
- icon_state = "parrot_fly"
- ..()
-
-/mob/living/simple_animal/parrot/proc/search_for_item()
- for(var/atom/movable/AM in view(src))
- //Skip items we already stole or are wearing or are too big
- if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src)
- continue
-
- if(istype(AM, /obj/item))
- var/obj/item/I = AM
- if(I.w_class < ITEMSIZE_SMALL)
- return I
-
- if(iscarbon(AM))
- var/mob/living/carbon/C = AM
- if((C.l_hand && C.l_hand.w_class <= ITEMSIZE_SMALL) || (C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL))
- return C
- return null
-
-/mob/living/simple_animal/parrot/proc/search_for_perch()
- for(var/obj/O in view(src))
- for(var/path in desired_perches)
- if(istype(O, path))
- return O
- return null
-
-//This proc was made to save on doing two 'in view' loops seperatly
-/mob/living/simple_animal/parrot/proc/search_for_perch_and_item()
- for(var/atom/movable/AM in view(src))
- for(var/perch_path in desired_perches)
- if(istype(AM, perch_path))
- return AM
-
- //Skip items we already stole or are wearing or are too big
- if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src)
- continue
-
- if(istype(AM, /obj/item))
- var/obj/item/I = AM
- if(I.w_class <= ITEMSIZE_SMALL)
- return I
-
- if(iscarbon(AM))
- var/mob/living/carbon/C = AM
- if(C.l_hand && C.l_hand.w_class <= ITEMSIZE_SMALL || C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL)
- return C
- return null
-
-
-/*
- * Verbs - These are actually procs, but can be used as verbs by player-controlled parrots.
- */
-/mob/living/simple_animal/parrot/proc/steal_from_ground()
- set name = "Steal from ground"
- set category = "Parrot"
- set desc = "Grabs a nearby item."
-
- if(stat)
- return -1
-
- if(held_item)
- src << "\red You are already holding the [held_item]"
- return 1
-
- for(var/obj/item/I in view(1,src))
- //Make sure we're not already holding it and it's small enough
- if(I.loc != src && I.w_class <= ITEMSIZE_SMALL)
-
- //If we have a perch and the item is sitting on it, continue
- if(!client && parrot_perch && I.loc == parrot_perch.loc)
- continue
-
- held_item = I
- I.loc = src
- visible_message("[src] grabs the [held_item]!", "\blue You grab the [held_item]!", "You hear the sounds of wings flapping furiously.")
- return held_item
-
- src << "\red There is nothing of interest to take."
- return 0
-
-/mob/living/simple_animal/parrot/proc/steal_from_mob()
- set name = "Steal from mob"
- set category = "Parrot"
- set desc = "Steals an item right out of a person's hand!"
-
- if(stat)
- return -1
-
- if(held_item)
- src << "\red You are already holding the [held_item]"
- return 1
-
- var/obj/item/stolen_item = null
-
- for(var/mob/living/carbon/C in view(1,src))
- if(C.l_hand && C.l_hand.w_class <= ITEMSIZE_SMALL)
- stolen_item = C.l_hand
-
- if(C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL)
- stolen_item = C.r_hand
-
- if(stolen_item)
- C.remove_from_mob(stolen_item)
- held_item = stolen_item
- stolen_item.loc = src
- visible_message("[src] grabs the [held_item] out of [C]'s hand!", "\blue You snag the [held_item] out of [C]'s hand!", "You hear the sounds of wings flapping furiously.")
- return held_item
-
- src << "\red There is nothing of interest to take."
- return 0
-
-/mob/living/simple_animal/parrot/verb/drop_held_item_player()
- set name = "Drop held item"
- set category = "Parrot"
- set desc = "Drop the item you're holding."
-
- if(stat)
- return
-
- src.drop_held_item()
-
- return
-
-/mob/living/simple_animal/parrot/proc/drop_held_item(var/drop_gently = 1)
- set name = "Drop held item"
- set category = "Parrot"
- set desc = "Drop the item you're holding."
-
- if(stat)
- return -1
-
- if(!held_item)
- usr << "\red You have nothing to drop!"
- return 0
-
- if(!drop_gently)
- if(istype(held_item, /obj/item/weapon/grenade))
- var/obj/item/weapon/grenade/G = held_item
- G.loc = src.loc
- G.prime()
- src << "You let go of the [held_item]!"
- held_item = null
- return 1
-
- src << "You drop the [held_item]."
-
- held_item.loc = src.loc
- held_item = null
- return 1
-
-/mob/living/simple_animal/parrot/proc/perch_player()
- set name = "Sit"
- set category = "Parrot"
- set desc = "Sit on a nice comfy perch."
-
- if(stat || !client)
- return
-
- if(icon_state == "parrot_fly")
- for(var/atom/movable/AM in view(src,1))
- for(var/perch_path in desired_perches)
- if(istype(AM, perch_path))
- src.loc = AM.loc
- icon_state = "parrot_sit"
- return
- src << "\red There is no perch nearby to sit on."
- return
-
-/*
- * Sub-types
- */
-/mob/living/simple_animal/parrot/Poly
- name = "Poly"
- desc = "Poly the Parrot. An expert on quantum cracker theory."
- speak = list("Poly wanna cracker!", ":e Check the singlo, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN HARDSUITS?",":e OH GOD ITS FREE CALL THE SHUTTLE")
-
-/mob/living/simple_animal/parrot/Poly/New()
- ears = new /obj/item/device/radio/headset/headset_eng(src)
- available_channels = list(":e")
- ..()
-
-/mob/living/simple_animal/parrot/say(var/message)
-
- if(stat)
- return
-
- var/verb = "says"
- if(speak_emote.len)
- verb = pick(speak_emote)
-
-
- var/message_mode=""
- if(copytext(message,1,2) == ";")
- message_mode = "headset"
- message = copytext(message,2)
-
- if(length(message) >= 2)
- var/channel_prefix = copytext(message, 1 ,3)
- message_mode = department_radio_keys[channel_prefix]
-
- if(copytext(message,1,2) == ":")
- var/positioncut = 3
- message = trim(copytext(message,positioncut))
-
- message = capitalize(trim_left(message))
-
- if(message_mode)
- if(message_mode in radiochannels)
- if(ears && istype(ears,/obj/item/device/radio))
- ears.talk_into(src,sanitize(message), message_mode, verb, null)
-
-
- ..(message)
-
-
-/mob/living/simple_animal/parrot/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null)
- if(prob(50))
- parrot_hear(message)
- ..(message,verb,language,alt_name,italics,speaker)
-
-
-
-/mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0)
- if(prob(50))
- parrot_hear("[pick(available_channels)] [message]")
- ..(message,verb,language,part_a,part_b,speaker,hard_to_hear)
-
-
-/mob/living/simple_animal/parrot/proc/parrot_hear(var/message="")
- if(!message || stat)
- return
- speech_buffer.Add(message)
-
-/mob/living/simple_animal/parrot/attack_generic(var/mob/user, var/damage, var/attack_message)
-
- var/success = ..()
-
- if(client)
- return success
-
- if(parrot_state == PARROT_PERCH)
- parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
-
- if(!success)
- return 0
-
- parrot_interest = user
- parrot_state = PARROT_SWOOP | PARROT_ATTACK //Attack other animals regardless
- icon_state = "parrot_fly"
+/* Parrots!
+ * Contains
+ * Defines
+ * Inventory (headset stuff)
+ * Attack responces
+ * AI
+ * Procs / Verbs (usable by players)
+ * Sub-types
+ */
+
+/*
+ * Defines
+ */
+
+//Parrot is too snowflake for me to rewrite right now, someone should make it use the new
+//simple_animal movement stuff. -Aro
+
+//Only a maximum of one action and one intent should be active at any given time.
+//Actions
+#define PARROT_PERCH 1 //Sitting/sleeping, not moving
+#define PARROT_SWOOP 2 //Moving towards or away from a target
+#define PARROT_WANDER 4 //Moving without a specific target in mind
+
+//Intents
+#define PARROT_STEAL 8 //Flying towards a target to steal it/from it
+#define PARROT_ATTACK 16 //Flying towards a target to attack it
+#define PARROT_RETURN 32 //Flying towards its perch
+#define PARROT_FLEE 64 //Flying away from its attacker
+
+
+/mob/living/simple_animal/parrot
+ name = "\improper Parrot"
+ desc = "The parrot squaks, \"It's a Parrot! BAWWK!\""
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "parrot_fly"
+ icon_living = "parrot_fly"
+ icon_dead = "parrot_dead"
+
+ turns_per_move = 5
+ pass_flags = PASSTABLE
+ mob_size = MOB_SMALL
+
+ response_help = "pets"
+ response_disarm = "gently moves aside"
+ response_harm = "swats"
+ stop_automated_movement = 1
+ universal_speak = 1
+
+ speak_chance = 2
+ speak = list("Hi","Hello!","Cracker?","BAWWWWK george mellons griffing me")
+ speak_emote = list("squawks","says","yells")
+ emote_hear = list("squawks","bawks")
+ emote_see = list("flutters its wings")
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/cracker
+
+ var/parrot_state = PARROT_WANDER //Hunt for a perch when created
+ var/parrot_sleep_max = 25 //The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in life() being run every single tick.
+ var/parrot_sleep_dur = 25 //Same as above, this is the var that physically counts down
+ var/parrot_dam_zone = list(BP_TORSO, BP_HEAD, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG) //For humans, select a bodypart to attack
+
+ var/parrot_speed = 5 //"Delay in world ticks between movement." according to byond. Yeah, that's BS but it does directly affect movement. Higher number = slower.
+ var/parrot_been_shot = 0 //Parrots get a speed bonus after being shot. This will deincrement every Life() and at 0 the parrot will return to regular speed.
+
+ var/list/speech_buffer = list()
+ var/list/available_channels = list()
+
+ //Headset for Poly to yell at engineers :)
+ var/obj/item/device/radio/headset/ears = null
+
+ //The thing the parrot is currently interested in. This gets used for items the parrot wants to pick up, mobs it wants to steal from,
+ //mobs it wants to attack or mobs that have attacked it
+ var/atom/movable/parrot_interest = null
+
+ //Parrots will generally sit on their pertch unless something catches their eye.
+ //These vars store their preffered perch and if they dont have one, what they can use as a perch
+ var/obj/parrot_perch = null
+ var/obj/desired_perches = list(/obj/structure/frame, /obj/structure/displaycase, \
+ /obj/structure/filingcabinet, /obj/machinery/teleport, \
+ /obj/machinery/computer, /obj/machinery/clonepod, \
+ /obj/machinery/dna_scannernew, /obj/machinery/telecomms, \
+ /obj/machinery/nuclearbomb, /obj/machinery/particle_accelerator, \
+ /obj/machinery/recharge_station, /obj/machinery/smartfridge, \
+ /obj/machinery/suit_storage_unit)
+
+ //Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding.
+ var/obj/item/held_item = null
+
+
+/mob/living/simple_animal/parrot/New()
+ ..()
+ if(!ears)
+ var/headset = pick(/obj/item/device/radio/headset/headset_sec, \
+ /obj/item/device/radio/headset/headset_eng, \
+ /obj/item/device/radio/headset/headset_med, \
+ /obj/item/device/radio/headset/headset_sci, \
+ /obj/item/device/radio/headset/headset_cargo)
+ ears = new headset(src)
+
+ parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var
+
+ verbs.Add(/mob/living/simple_animal/parrot/proc/steal_from_ground, \
+ /mob/living/simple_animal/parrot/proc/steal_from_mob, \
+ /mob/living/simple_animal/parrot/verb/drop_held_item_player, \
+ /mob/living/simple_animal/parrot/proc/perch_player)
+
+
+/mob/living/simple_animal/parrot/death()
+ if(held_item)
+ held_item.forceMove(src.loc)
+ held_item = null
+ walk(src,0)
+ ..()
+
+/mob/living/simple_animal/parrot/Stat()
+ ..()
+ stat("Held Item", held_item)
+
+/*
+ * Inventory
+ */
+/mob/living/simple_animal/parrot/show_inv(mob/user as mob)
+ user.set_machine(src)
+ if(user.stat) return
+
+ var/dat = "
Inventory of [name]
"
+ if(ears)
+ dat += " Headset: [ears] (Remove)"
+ else
+ dat += " Headset:Nothing"
+
+ user << browse(dat, text("window=mob[];size=325x500", name))
+ onclose(user, "mob[real_name]")
+ return
+
+/mob/living/simple_animal/parrot/Topic(href, href_list)
+
+ //Can the usr physically do this?
+ if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
+ return
+
+ //Is the usr's mob type able to do this?
+ if(ishuman(usr) || issmall(usr) || isrobot(usr))
+
+ //Removing from inventory
+ if(href_list["remove_inv"])
+ var/remove_from = href_list["remove_inv"]
+ switch(remove_from)
+ if("ears")
+ if(ears)
+ if(available_channels.len)
+ src.say("[pick(available_channels)] BAWWWWWK LEAVE THE HEADSET BAWKKKKK!")
+ else
+ src.say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!")
+ ears.forceMove(src.loc)
+ ears = null
+ for(var/possible_phrase in speak)
+ if(copytext(possible_phrase,1,3) in department_radio_keys)
+ possible_phrase = copytext(possible_phrase,3,length(possible_phrase))
+ else
+ usr << "\red There is nothing to remove from its [remove_from]."
+ return
+
+ //Adding things to inventory
+ else if(href_list["add_inv"])
+ var/add_to = href_list["add_inv"]
+ if(!usr.get_active_hand())
+ usr << "\red You have nothing in your hand to put on its [add_to]."
+ return
+ switch(add_to)
+ if("ears")
+ if(ears)
+ usr << "\red It's already wearing something."
+ return
+ else
+ var/obj/item/item_to_add = usr.get_active_hand()
+ if(!item_to_add)
+ return
+
+ if( !istype(item_to_add, /obj/item/device/radio/headset) )
+ usr << "\red This object won't fit."
+ return
+
+ var/obj/item/device/radio/headset/headset_to_add = item_to_add
+
+ usr.drop_item()
+ headset_to_add.forceMove(src)
+ src.ears = headset_to_add
+ usr << "You fit the headset onto [src]."
+
+ clearlist(available_channels)
+ for(var/ch in headset_to_add.channels)
+ switch(ch)
+ if("Engineering")
+ available_channels.Add(":e")
+ if("Command")
+ available_channels.Add(":c")
+ if("Security")
+ available_channels.Add(":s")
+ if("Science")
+ available_channels.Add(":n")
+ if("Medical")
+ available_channels.Add(":m")
+ if("Mining")
+ available_channels.Add(":d")
+ if("Cargo")
+ available_channels.Add(":q")
+
+ if(headset_to_add.translate_binary)
+ available_channels.Add(":b")
+ else
+ ..()
+
+
+/*
+ * Attack responces
+ */
+//Humans, monkeys, aliens
+/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M as mob)
+ ..()
+ if(client) return
+ if(!stat && M.a_intent == I_HURT)
+
+ icon_state = "parrot_fly" //It is going to be flying regardless of whether it flees or attacks
+
+ if(parrot_state == PARROT_PERCH)
+ parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
+
+ parrot_interest = M
+ parrot_state = PARROT_SWOOP //The parrot just got hit, it WILL move, now to pick a direction..
+
+ if(M.health < 50) //Weakened mob? Fight back!
+ parrot_state |= PARROT_ATTACK
+ else
+ parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell!
+ drop_held_item(0)
+ return
+
+//Mobs with objects
+/mob/living/simple_animal/parrot/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ ..()
+ if(!stat && !client && !istype(O, /obj/item/stack/medical))
+ if(O.force)
+ if(parrot_state == PARROT_PERCH)
+ parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
+
+ parrot_interest = user
+ parrot_state = PARROT_SWOOP | PARROT_FLEE
+ icon_state = "parrot_fly"
+ drop_held_item(0)
+ return
+
+//Bullets
+/mob/living/simple_animal/parrot/bullet_act(var/obj/item/projectile/Proj)
+ ..()
+ if(!stat && !client)
+ if(parrot_state == PARROT_PERCH)
+ parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
+
+ parrot_interest = null
+ parrot_state = PARROT_WANDER //OWFUCK, Been shot! RUN LIKE HELL!
+ parrot_been_shot += 5
+ icon_state = "parrot_fly"
+ drop_held_item(0)
+ return
+
+
+/*
+ * AI - Not really intelligent, but I'm calling it AI anyway.
+ */
+/mob/living/simple_animal/parrot/Life()
+ ..()
+
+ //Sprite and AI update for when a parrot gets pulled
+ if(pulledby && stat == CONSCIOUS)
+ icon_state = "parrot_fly"
+ if(!client)
+ parrot_state = PARROT_WANDER
+ return
+
+ if(client || stat)
+ return //Lets not force players or dead/incap parrots to move
+
+ if(!isturf(src.loc) || !canmove || buckled)
+ return //If it can't move, dont let it move. (The buckled check probably isn't necessary thanks to canmove)
+
+
+//-----SPEECH
+ /* Parrot speech mimickry!
+ Phrases that the parrot hears in mob/living/say() get added to speach_buffer.
+ Every once in a while, the parrot picks one of the lines from the buffer and replaces an element of the 'speech' list.
+ Then it clears the buffer to make sure they dont magically remember something from hours ago. */
+ if(speech_buffer.len && prob(10))
+ if(speak.len)
+ speak.Remove(pick(speak))
+
+ speak.Add(pick(speech_buffer))
+ clearlist(speech_buffer)
+
+
+//-----SLEEPING
+ if(parrot_state == PARROT_PERCH)
+ if(parrot_perch && parrot_perch.loc != src.loc) //Make sure someone hasnt moved our perch on us
+ if(parrot_perch in view(src))
+ parrot_state = PARROT_SWOOP | PARROT_RETURN
+ icon_state = "parrot_fly"
+ return
+ else
+ parrot_state = PARROT_WANDER
+ icon_state = "parrot_fly"
+ return
+
+ if(--parrot_sleep_dur) //Zzz
+ return
+
+ else
+ //This way we only call the stuff below once every [sleep_max] ticks.
+ parrot_sleep_dur = parrot_sleep_max
+
+ //Cycle through message modes for the headset
+ if(speak.len)
+ var/list/newspeak = list()
+
+ if(available_channels.len && src.ears)
+ for(var/possible_phrase in speak)
+
+ //50/50 chance to not use the radio at all
+ var/useradio = 0
+ if(prob(50))
+ useradio = 1
+
+ if(copytext(possible_phrase,1,3) in department_radio_keys)
+ possible_phrase = "[useradio?pick(available_channels):""] [copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix
+ else
+ possible_phrase = "[useradio?pick(available_channels):""] [possible_phrase]"
+
+ newspeak.Add(possible_phrase)
+
+ else //If we have no headset or channels to use, dont try to use any!
+ for(var/possible_phrase in speak)
+ if(copytext(possible_phrase,1,3) in department_radio_keys)
+ possible_phrase = "[copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix
+ newspeak.Add(possible_phrase)
+ speak = newspeak
+
+ //Search for item to steal
+ parrot_interest = search_for_item()
+ if(parrot_interest)
+ visible_emote("looks in [parrot_interest]'s direction and takes flight")
+ parrot_state = PARROT_SWOOP | PARROT_STEAL
+ icon_state = "parrot_fly"
+ return
+
+//-----WANDERING - This is basically a 'I dont know what to do yet' state
+ else if(parrot_state == PARROT_WANDER)
+ //Stop movement, we'll set it later
+ walk(src, 0)
+ parrot_interest = null
+
+ //Wander around aimlessly. This will help keep the loops from searches down
+ //and possibly move the mob into a new are in view of something they can use
+ if(prob(90))
+ step(src, pick(cardinal))
+ return
+
+ if(!held_item && !parrot_perch) //If we've got nothing to do.. look for something to do.
+ var/atom/movable/AM = search_for_perch_and_item() //This handles checking through lists so we know it's either a perch or stealable item
+ if(AM)
+ if(istype(AM, /obj/item) || isliving(AM)) //If stealable item
+ parrot_interest = AM
+ visible_emote("turns and flies towards [parrot_interest]")
+ parrot_state = PARROT_SWOOP | PARROT_STEAL
+ return
+ else //Else it's a perch
+ parrot_perch = AM
+ parrot_state = PARROT_SWOOP | PARROT_RETURN
+ return
+ return
+
+ if(parrot_interest && parrot_interest in view(src))
+ parrot_state = PARROT_SWOOP | PARROT_STEAL
+ return
+
+ if(parrot_perch && parrot_perch in view(src))
+ parrot_state = PARROT_SWOOP | PARROT_RETURN
+ return
+
+ else //Have an item but no perch? Find one!
+ parrot_perch = search_for_perch()
+ if(parrot_perch)
+ parrot_state = PARROT_SWOOP | PARROT_RETURN
+ return
+//-----STEALING
+ else if(parrot_state == (PARROT_SWOOP | PARROT_STEAL))
+ walk(src,0)
+ if(!parrot_interest || held_item)
+ parrot_state = PARROT_SWOOP | PARROT_RETURN
+ return
+
+ if(!(parrot_interest in view(src)))
+ parrot_state = PARROT_SWOOP | PARROT_RETURN
+ return
+
+ if(in_range(src, parrot_interest))
+
+ if(isliving(parrot_interest))
+ steal_from_mob()
+
+ else //This should ensure that we only grab the item we want, and make sure it's not already collected on our perch
+ if(!parrot_perch || parrot_interest.loc != parrot_perch.loc)
+ held_item = parrot_interest
+ parrot_interest.forceMove(src)
+ visible_message("[src] grabs the [held_item]!", "\blue You grab the [held_item]!", "You hear the sounds of wings flapping furiously.")
+
+ parrot_interest = null
+ parrot_state = PARROT_SWOOP | PARROT_RETURN
+ return
+
+ walk_to(src, parrot_interest, 1, parrot_speed)
+ return
+
+//-----RETURNING TO PERCH
+ else if(parrot_state == (PARROT_SWOOP | PARROT_RETURN))
+ walk(src, 0)
+ if(!parrot_perch || !isturf(parrot_perch.loc)) //Make sure the perch exists and somehow isnt inside of something else.
+ parrot_perch = null
+ parrot_state = PARROT_WANDER
+ return
+
+ if(in_range(src, parrot_perch))
+ src.forceMove(parrot_perch.loc)
+ drop_held_item()
+ parrot_state = PARROT_PERCH
+ icon_state = "parrot_sit"
+ return
+
+ walk_to(src, parrot_perch, 1, parrot_speed)
+ return
+
+//-----FLEEING
+ else if(parrot_state == (PARROT_SWOOP | PARROT_FLEE))
+ walk(src,0)
+ if(!parrot_interest || !isliving(parrot_interest)) //Sanity
+ parrot_state = PARROT_WANDER
+
+ walk_away(src, parrot_interest, 1, parrot_speed-parrot_been_shot)
+ parrot_been_shot--
+ return
+
+//-----ATTACKING
+ else if(parrot_state == (PARROT_SWOOP | PARROT_ATTACK))
+
+ //If we're attacking a nothing, an object, a turf or a ghost for some stupid reason, switch to wander
+ if(!parrot_interest || !isliving(parrot_interest))
+ parrot_interest = null
+ parrot_state = PARROT_WANDER
+ return
+
+ var/mob/living/L = parrot_interest
+
+ //If the mob is close enough to interact with
+ if(in_range(src, parrot_interest))
+
+ //If the mob we've been chasing/attacking dies or falls into crit, check for loot!
+ if(L.stat)
+ parrot_interest = null
+ if(!held_item)
+ held_item = steal_from_ground()
+ if(!held_item)
+ held_item = steal_from_mob() //Apparently it's possible for dead mobs to hang onto items in certain circumstances.
+ if(parrot_perch in view(src)) //If we have a home nearby, go to it, otherwise find a new home
+ parrot_state = PARROT_SWOOP | PARROT_RETURN
+ else
+ parrot_state = PARROT_WANDER
+ return
+
+ //Time for the hurt to begin!
+ var/damage = rand(5,10)
+
+ if(ishuman(parrot_interest))
+ var/mob/living/carbon/human/H = parrot_interest
+ var/obj/item/organ/external/affecting = H.get_organ(ran_zone(pick(parrot_dam_zone)))
+
+ H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), sharp=1)
+ visible_emote(pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons."))
+
+ else
+ L.adjustBruteLoss(damage)
+ visible_emote(pick("pecks at [L].", "claws [L]."))
+ return
+
+ //Otherwise, fly towards the mob!
+ else
+ walk_to(src, parrot_interest, 1, parrot_speed)
+ return
+//-----STATE MISHAP
+ else //This should not happen. If it does lets reset everything and try again
+ walk(src,0)
+ parrot_interest = null
+ parrot_perch = null
+ drop_held_item()
+ parrot_state = PARROT_WANDER
+ return
+
+/*
+ * Procs
+ */
+
+/mob/living/simple_animal/parrot/movement_delay()
+ if(client && stat == CONSCIOUS && parrot_state != "parrot_fly")
+ icon_state = "parrot_fly"
+ ..()
+
+/mob/living/simple_animal/parrot/proc/search_for_item()
+ for(var/atom/movable/AM in view(src))
+ //Skip items we already stole or are wearing or are too big
+ if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src)
+ continue
+
+ if(istype(AM, /obj/item))
+ var/obj/item/I = AM
+ if(I.w_class < ITEMSIZE_SMALL)
+ return I
+
+ if(iscarbon(AM))
+ var/mob/living/carbon/C = AM
+ if((C.l_hand && C.l_hand.w_class <= ITEMSIZE_SMALL) || (C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL))
+ return C
+ return null
+
+/mob/living/simple_animal/parrot/proc/search_for_perch()
+ for(var/obj/O in view(src))
+ for(var/path in desired_perches)
+ if(istype(O, path))
+ return O
+ return null
+
+//This proc was made to save on doing two 'in view' loops seperatly
+/mob/living/simple_animal/parrot/proc/search_for_perch_and_item()
+ for(var/atom/movable/AM in view(src))
+ for(var/perch_path in desired_perches)
+ if(istype(AM, perch_path))
+ return AM
+
+ //Skip items we already stole or are wearing or are too big
+ if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src)
+ continue
+
+ if(istype(AM, /obj/item))
+ var/obj/item/I = AM
+ if(I.w_class <= ITEMSIZE_SMALL)
+ return I
+
+ if(iscarbon(AM))
+ var/mob/living/carbon/C = AM
+ if(C.l_hand && C.l_hand.w_class <= ITEMSIZE_SMALL || C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL)
+ return C
+ return null
+
+
+/*
+ * Verbs - These are actually procs, but can be used as verbs by player-controlled parrots.
+ */
+/mob/living/simple_animal/parrot/proc/steal_from_ground()
+ set name = "Steal from ground"
+ set category = "Parrot"
+ set desc = "Grabs a nearby item."
+
+ if(stat)
+ return -1
+
+ if(held_item)
+ src << "\red You are already holding the [held_item]"
+ return 1
+
+ for(var/obj/item/I in view(1,src))
+ //Make sure we're not already holding it and it's small enough
+ if(I.loc != src && I.w_class <= ITEMSIZE_SMALL)
+
+ //If we have a perch and the item is sitting on it, continue
+ if(!client && parrot_perch && I.loc == parrot_perch.loc)
+ continue
+
+ held_item = I
+ I.forceMove(src)
+ visible_message("[src] grabs the [held_item]!", "\blue You grab the [held_item]!", "You hear the sounds of wings flapping furiously.")
+ return held_item
+
+ src << "\red There is nothing of interest to take."
+ return 0
+
+/mob/living/simple_animal/parrot/proc/steal_from_mob()
+ set name = "Steal from mob"
+ set category = "Parrot"
+ set desc = "Steals an item right out of a person's hand!"
+
+ if(stat)
+ return -1
+
+ if(held_item)
+ src << "\red You are already holding the [held_item]"
+ return 1
+
+ var/obj/item/stolen_item = null
+
+ for(var/mob/living/carbon/C in view(1,src))
+ if(C.l_hand && C.l_hand.w_class <= ITEMSIZE_SMALL)
+ stolen_item = C.l_hand
+
+ if(C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL)
+ stolen_item = C.r_hand
+
+ if(stolen_item)
+ C.remove_from_mob(stolen_item)
+ held_item = stolen_item
+ stolen_item.forceMove(src)
+ visible_message("[src] grabs the [held_item] out of [C]'s hand!", "\blue You snag the [held_item] out of [C]'s hand!", "You hear the sounds of wings flapping furiously.")
+ return held_item
+
+ src << "\red There is nothing of interest to take."
+ return 0
+
+/mob/living/simple_animal/parrot/verb/drop_held_item_player()
+ set name = "Drop held item"
+ set category = "Parrot"
+ set desc = "Drop the item you're holding."
+
+ if(stat)
+ return
+
+ src.drop_held_item()
+
+ return
+
+/mob/living/simple_animal/parrot/proc/drop_held_item(var/drop_gently = 1)
+ set name = "Drop held item"
+ set category = "Parrot"
+ set desc = "Drop the item you're holding."
+
+ if(stat)
+ return -1
+
+ if(!held_item)
+ usr << "\red You have nothing to drop!"
+ return 0
+
+ if(!drop_gently)
+ if(istype(held_item, /obj/item/weapon/grenade))
+ var/obj/item/weapon/grenade/G = held_item
+ G.forceMove(src.loc)
+ G.prime()
+ src << "You let go of the [held_item]!"
+ held_item = null
+ return 1
+
+ src << "You drop the [held_item]."
+
+ held_item.forceMove(src.loc)
+ held_item = null
+ return 1
+
+/mob/living/simple_animal/parrot/proc/perch_player()
+ set name = "Sit"
+ set category = "Parrot"
+ set desc = "Sit on a nice comfy perch."
+
+ if(stat || !client)
+ return
+
+ if(icon_state == "parrot_fly")
+ for(var/atom/movable/AM in view(src,1))
+ for(var/perch_path in desired_perches)
+ if(istype(AM, perch_path))
+ src.forceMove(AM.loc)
+ icon_state = "parrot_sit"
+ return
+ src << "\red There is no perch nearby to sit on."
+ return
+
+/*
+ * Sub-types
+ */
+/mob/living/simple_animal/parrot/Poly
+ name = "Poly"
+ desc = "Poly the Parrot. An expert on quantum cracker theory."
+ speak = list("Poly wanna cracker!", ":e Check the singlo, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN HARDSUITS?",":e OH GOD ITS FREE CALL THE SHUTTLE")
+
+/mob/living/simple_animal/parrot/Poly/New()
+ ears = new /obj/item/device/radio/headset/headset_eng(src)
+ available_channels = list(":e")
+ ..()
+
+/mob/living/simple_animal/parrot/say(var/message)
+
+ if(stat)
+ return
+
+ var/verb = "says"
+ if(speak_emote.len)
+ verb = pick(speak_emote)
+
+
+ var/message_mode=""
+ if(copytext(message,1,2) == ";")
+ message_mode = "headset"
+ message = copytext(message,2)
+
+ if(length(message) >= 2)
+ var/channel_prefix = copytext(message, 1 ,3)
+ message_mode = department_radio_keys[channel_prefix]
+
+ if(copytext(message,1,2) == ":")
+ var/positioncut = 3
+ message = trim(copytext(message,positioncut))
+
+ message = capitalize(trim_left(message))
+
+ if(message_mode)
+ if(message_mode in radiochannels)
+ if(ears && istype(ears,/obj/item/device/radio))
+ ears.talk_into(src,sanitize(message), message_mode, verb, null)
+
+
+ ..(message)
+
+
+/mob/living/simple_animal/parrot/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null)
+ if(prob(50))
+ parrot_hear(message)
+ ..(message,verb,language,alt_name,italics,speaker)
+
+
+
+/mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0)
+ if(prob(50))
+ parrot_hear("[pick(available_channels)] [message]")
+ ..(message,verb,language,part_a,part_b,speaker,hard_to_hear)
+
+
+/mob/living/simple_animal/parrot/proc/parrot_hear(var/message="")
+ if(!message || stat)
+ return
+ speech_buffer.Add(message)
+
+/mob/living/simple_animal/parrot/attack_generic(var/mob/user, var/damage, var/attack_message)
+
+ var/success = ..()
+
+ if(client)
+ return success
+
+ if(parrot_state == PARROT_PERCH)
+ parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
+
+ if(!success)
+ return 0
+
+ parrot_interest = user
+ parrot_state = PARROT_SWOOP | PARROT_ATTACK //Attack other animals regardless
+ icon_state = "parrot_fly"
return success
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/friendly/penguin.dm b/code/modules/mob/living/simple_animal/animals/penguin.dm
similarity index 94%
rename from code/modules/mob/living/simple_animal/friendly/penguin.dm
rename to code/modules/mob/living/simple_animal/animals/penguin.dm
index b843013c396..40c085a72f7 100644
--- a/code/modules/mob/living/simple_animal/friendly/penguin.dm
+++ b/code/modules/mob/living/simple_animal/animals/penguin.dm
@@ -5,15 +5,21 @@
icon_living = "penguin"
icon_dead = "penguin_dead"
icon_gib = "generic_gib"
- speak_chance = 0
- turns_per_move = 5
+
maxHealth = 20
health = 20
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
+ turns_per_move = 5
+
response_help = "pets"
response_disarm = "pushes aside"
response_harm = "hits"
+
harm_intent_damage = 5
- melee_damage_upper = 15
melee_damage_lower = 10
- attacktext = "pecked"
\ No newline at end of file
+ melee_damage_upper = 15
+ attacktext = "pecked"
+
+ speak_chance = 0
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
diff --git a/code/modules/mob/living/simple_animal/friendly/slime.dm b/code/modules/mob/living/simple_animal/animals/slime.dm
similarity index 96%
rename from code/modules/mob/living/simple_animal/friendly/slime.dm
rename to code/modules/mob/living/simple_animal/animals/slime.dm
index 77d52741ae2..7d5fa16dab2 100644
--- a/code/modules/mob/living/simple_animal/friendly/slime.dm
+++ b/code/modules/mob/living/simple_animal/animals/slime.dm
@@ -1,59 +1,69 @@
-/mob/living/simple_animal/slime
- name = "pet slime"
- desc = "A lovable, domesticated slime."
- icon = 'icons/mob/slimes.dmi'
- icon_state = "grey baby slime"
- icon_living = "grey baby slime"
- icon_dead = "grey baby slime dead"
- speak_emote = list("chirps")
- health = 100
- maxHealth = 100
- response_help = "pets"
- response_disarm = "shoos"
- response_harm = "stomps on"
- emote_see = list("jiggles", "bounces in place")
- var/colour = "grey"
-
-/mob/living/simple_animal/slime/science
- name = "Kendrick"
- colour = "rainbow"
- icon_state = "rainbow baby slime"
- icon_living = "rainbow baby slime"
- icon_dead = "rainbow baby slime dead"
-
-/mob/living/simple_animal/slime/science/initialize()
- ..()
- overlays.Cut()
- overlays += "aslime-:33"
-
-/mob/living/simple_animal/adultslime
- name = "pet slime"
- desc = "A lovable, domesticated slime."
- icon = 'icons/mob/slimes.dmi'
- health = 200
- maxHealth = 200
- icon_state = "grey adult slime"
- icon_living = "grey adult slime"
- icon_dead = "grey baby slime dead"
- response_help = "pets"
- response_disarm = "shoos"
- response_harm = "stomps on"
- emote_see = list("jiggles", "bounces in place")
- var/colour = "grey"
-
-/mob/living/simple_animal/adultslime/New()
- ..()
- overlays += "aslime-:33"
-
-/mob/living/simple_animal/adultslime/death()
- var/mob/living/simple_animal/slime/S1 = new /mob/living/simple_animal/slime (src.loc)
- S1.icon_state = "[src.colour] baby slime"
- S1.icon_living = "[src.colour] baby slime"
- S1.icon_dead = "[src.colour] baby slime dead"
- S1.colour = "[src.colour]"
- var/mob/living/simple_animal/slime/S2 = new /mob/living/simple_animal/slime (src.loc)
- S2.icon_state = "[src.colour] baby slime"
- S2.icon_living = "[src.colour] baby slime"
- S2.icon_dead = "[src.colour] baby slime dead"
- S2.colour = "[src.colour]"
+/mob/living/simple_animal/slime
+ name = "pet slime"
+ desc = "A lovable, domesticated slime."
+ icon = 'icons/mob/slimes.dmi'
+ icon_state = "grey baby slime"
+ icon_living = "grey baby slime"
+ icon_dead = "grey baby slime dead"
+
+ maxHealth = 100
+ health = 100
+
+ response_help = "pets"
+ response_disarm = "shoos"
+ response_harm = "stomps on"
+
+ speak_chance = 1
+ speak_emote = list("chirps")
+ emote_see = list("jiggles", "bounces in place")
+
+ var/colour = "grey"
+
+/mob/living/simple_animal/slime/science
+ name = "Kendrick"
+ colour = "rainbow"
+ icon_state = "rainbow baby slime"
+ icon_living = "rainbow baby slime"
+ icon_dead = "rainbow baby slime dead"
+
+/mob/living/simple_animal/slime/science/initialize()
+ ..()
+ overlays.Cut()
+ overlays += "aslime-:33"
+
+/mob/living/simple_animal/adultslime
+ name = "pet slime"
+ desc = "A lovable, domesticated slime."
+ icon = 'icons/mob/slimes.dmi'
+ icon_state = "grey adult slime"
+ icon_living = "grey adult slime"
+ icon_dead = "grey baby slime dead"
+
+ maxHealth = 200
+ health = 200
+
+ response_help = "pets"
+ response_disarm = "shoos"
+ response_harm = "stomps on"
+
+ speak_chance = 1
+ emote_see = list("jiggles", "bounces in place")
+
+ var/colour = "grey"
+
+/mob/living/simple_animal/adultslime/New()
+ ..()
+ overlays += "aslime-:33"
+
+/mob/living/simple_animal/adultslime/death()
+ var/mob/living/simple_animal/slime/S1 = new /mob/living/simple_animal/slime (src.loc)
+ S1.icon_state = "[src.colour] baby slime"
+ S1.icon_living = "[src.colour] baby slime"
+ S1.icon_dead = "[src.colour] baby slime dead"
+ S1.colour = "[src.colour]"
+ var/mob/living/simple_animal/slime/S2 = new /mob/living/simple_animal/slime (src.loc)
+ S2.icon_state = "[src.colour] baby slime"
+ S2.icon_living = "[src.colour] baby slime"
+ S2.icon_dead = "[src.colour] baby slime dead"
+ S2.colour = "[src.colour]"
qdel(src)
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm b/code/modules/mob/living/simple_animal/animals/spiderbot.dm
similarity index 97%
rename from code/modules/mob/living/simple_animal/friendly/spiderbot.dm
rename to code/modules/mob/living/simple_animal/animals/spiderbot.dm
index 6ef066a2574..1bb202d1a03 100644
--- a/code/modules/mob/living/simple_animal/friendly/spiderbot.dm
+++ b/code/modules/mob/living/simple_animal/animals/spiderbot.dm
@@ -1,11 +1,35 @@
/mob/living/simple_animal/spiderbot
+ name = "spider-bot"
+ desc = "A skittering robotic friend!"
+ icon = 'icons/mob/robots.dmi'
+ icon_state = "spiderbot-chassis"
+ icon_living = "spiderbot-chassis"
+ icon_dead = "spiderbot-smashed"
+
+ health = 10
+ maxHealth = 10
+
+ wander = 0
+ speed = -1 //Spiderbots gotta go fast.
+ pass_flags = PASSTABLE
+ mob_size = MOB_SMALL
+
+ response_help = "pets"
+ response_disarm = "shoos"
+ response_harm = "stomps on"
+
+ melee_damage_lower = 1
+ melee_damage_upper = 3
+ attacktext = "shocked"
min_oxy = 0
max_tox = 0
max_co2 = 0
minbodytemp = 0
maxbodytemp = 500
- mob_size = MOB_SMALL
+
+ speak_chance = 1
+ speak_emote = list("beeps","clicks","chirps")
var/obj/item/device/radio/borg/radio = null
var/mob/living/silicon/ai/connected_ai = null
@@ -15,31 +39,8 @@
var/list/req_access = list(access_robotics) //Access needed to pop out the brain.
var/positronic
- name = "spider-bot"
- desc = "A skittering robotic friend!"
- icon = 'icons/mob/robots.dmi'
- icon_state = "spiderbot-chassis"
- icon_living = "spiderbot-chassis"
- icon_dead = "spiderbot-smashed"
-
- wander = 0
-
- health = 10
- maxHealth = 10
-
- attacktext = "shocked"
- melee_damage_lower = 1
- melee_damage_upper = 3
-
- response_help = "pets"
- response_disarm = "shoos"
- response_harm = "stomps on"
-
var/emagged = 0
var/obj/item/held_item = null //Storage for single item they can hold.
- speed = -1 //Spiderbots gotta go fast.
- pass_flags = PASSTABLE
- speak_emote = list("beeps","clicks","chirps")
/mob/living/simple_animal/spiderbot/New()
..()
@@ -87,7 +88,7 @@
src.mmi = O
src.transfer_personality(O)
- O.loc = src
+ O.forceMove(src)
src.update_icon()
return 1
@@ -122,7 +123,7 @@
user << "You swipe your access card and pop the brain out of \the [src]."
eject_brain()
if(held_item)
- held_item.loc = src.loc
+ held_item.forceMove(src.loc)
held_item = null
return 1
else
@@ -171,7 +172,7 @@
if(mmi)
var/turf/T = get_turf(loc)
if(T)
- mmi.loc = T
+ mmi.forceMove(T)
if(mind) mind.transfer_to(mmi.brainmob)
mmi = null
real_name = initial(real_name)
@@ -201,7 +202,7 @@
if(camera)
camera.status = 0
- held_item.loc = src.loc
+ held_item.forceMove(src.loc)
held_item = null
gibs(loc, null, null, /obj/effect/gibspawner/robot) //TODO: use gib() or refactor spiderbots into synthetics.
@@ -226,7 +227,7 @@
"You launch \the [held_item]!", \
"You hear a skittering noise and a thump!")
var/obj/item/weapon/grenade/G = held_item
- G.loc = src.loc
+ G.forceMove(src.loc)
G.prime()
held_item = null
return 1
@@ -235,7 +236,7 @@
"You drop \the [held_item].", \
"You hear a skittering noise and a soft thump.")
- held_item.loc = src.loc
+ held_item.forceMove(src.loc)
held_item = null
return 1
@@ -264,7 +265,7 @@
for(var/obj/item/I in view(1, src))
if(selection == I)
held_item = selection
- selection.loc = src
+ selection.forceMove(src)
visible_message("\The [src] scoops up \the [held_item].", \
"You grab \the [held_item].", \
"You hear a skittering noise and a clink.")
@@ -284,4 +285,4 @@
return
/mob/living/simple_animal/spiderbot/binarycheck()
- return positronic
\ No newline at end of file
+ return positronic
diff --git a/code/modules/mob/living/simple_animal/friendly/tomato.dm b/code/modules/mob/living/simple_animal/animals/tomato.dm
similarity index 83%
rename from code/modules/mob/living/simple_animal/friendly/tomato.dm
rename to code/modules/mob/living/simple_animal/animals/tomato.dm
index e0574ba9254..ea133a85818 100644
--- a/code/modules/mob/living/simple_animal/friendly/tomato.dm
+++ b/code/modules/mob/living/simple_animal/animals/tomato.dm
@@ -1,18 +1,22 @@
-/mob/living/simple_animal/tomato
- name = "tomato"
- desc = "It's a horrifyingly enormous beef tomato, and it's packing extra beef!"
- icon_state = "tomato"
- icon_living = "tomato"
- icon_dead = "tomato_dead"
- speak_chance = 0
- turns_per_move = 5
- maxHealth = 15
- health = 15
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/tomatomeat
- response_help = "prods"
- response_disarm = "pushes aside"
- response_harm = "smacks"
- harm_intent_damage = 5
- melee_damage_upper = 15
- melee_damage_lower = 10
- attacktext = "mauled"
\ No newline at end of file
+/mob/living/simple_animal/hostile/tomato
+ name = "tomato"
+ desc = "It's a horrifyingly enormous beef tomato, and it's packing extra beef!"
+ icon_state = "tomato"
+ icon_living = "tomato"
+ icon_dead = "tomato_dead"
+
+ faction = "plants"
+ maxHealth = 15
+ health = 15
+ turns_per_move = 5
+
+ response_help = "prods"
+ response_disarm = "pushes aside"
+ response_harm = "smacks"
+
+ harm_intent_damage = 5
+ melee_damage_upper = 15
+ melee_damage_lower = 10
+ attacktext = "mauled"
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/tomatomeat
diff --git a/code/modules/mob/living/simple_animal/hostile/tree.dm b/code/modules/mob/living/simple_animal/animals/tree.dm
similarity index 85%
rename from code/modules/mob/living/simple_animal/hostile/tree.dm
rename to code/modules/mob/living/simple_animal/animals/tree.dm
index 1c438d2bc8b..bf97641248e 100644
--- a/code/modules/mob/living/simple_animal/hostile/tree.dm
+++ b/code/modules/mob/living/simple_animal/animals/tree.dm
@@ -1,56 +1,57 @@
-/mob/living/simple_animal/hostile/tree
- name = "pine tree"
- desc = "A pissed off tree-like alien. It seems annoyed with the festivities..."
- icon = 'icons/obj/flora/pinetrees.dmi'
- icon_state = "pine_1"
- icon_living = "pine_1"
- icon_dead = "pine_1"
- icon_gib = "pine_1"
- speak_chance = 0
- turns_per_move = 5
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat
- response_help = "brushes"
- response_disarm = "pushes"
- response_harm = "hits"
- speed = -1
- maxHealth = 250
- health = 250
-
- pixel_x = -16
-
- harm_intent_damage = 5
- melee_damage_lower = 8
- melee_damage_upper = 12
- attacktext = "bitten"
- attack_sound = 'sound/weapons/bite.ogg'
-
- //Space carp aren't affected by atmos.
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
-
- faction = "carp"
-
-/mob/living/simple_animal/hostile/tree/FindTarget()
- . = ..()
- if(.)
- audible_emote("growls at [.]")
-
-/mob/living/simple_animal/hostile/tree/AttackingTarget()
- . =..()
- var/mob/living/L = .
- if(istype(L))
- if(prob(15))
- L.Weaken(3)
- L.visible_message("\the [src] knocks down \the [L]!")
-
-/mob/living/simple_animal/hostile/tree/death()
- ..(null,"is hacked into pieces!")
- new /obj/item/stack/material/wood(loc)
+/mob/living/simple_animal/hostile/tree
+ name = "pine tree"
+ desc = "A pissed off tree-like alien. It seems annoyed with the festivities..."
+ icon = 'icons/obj/flora/pinetrees.dmi'
+ icon_state = "pine_1"
+ icon_living = "pine_1"
+ icon_dead = "pine_1"
+ icon_gib = "pine_1"
+
+ faction = "carp" //Trees can be carp friends?
+ maxHealth = 250
+ health = 250
+ speed = -1
+
+ turns_per_move = 5
+
+ response_help = "brushes"
+ response_disarm = "pushes"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 8
+ melee_damage_upper = 12
+ attacktext = "bitten"
+ attack_sound = 'sound/weapons/bite.ogg'
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/carpmeat
+
+ pixel_x = -16
+
+/mob/living/simple_animal/hostile/tree/FindTarget()
+ . = ..()
+ if(.)
+ audible_emote("growls at [.]")
+
+/mob/living/simple_animal/hostile/tree/PunchTarget()
+ . =..()
+ var/mob/living/L = .
+ if(istype(L))
+ if(prob(15))
+ L.Weaken(3)
+ L.visible_message("\the [src] knocks down \the [L]!")
+
+/mob/living/simple_animal/hostile/tree/death()
+ ..(null,"is hacked into pieces!")
+ new /obj/item/stack/material/wood(loc)
qdel(src)
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/worm.dm b/code/modules/mob/living/simple_animal/animals/worm.dm
similarity index 95%
rename from code/modules/mob/living/simple_animal/worm.dm
rename to code/modules/mob/living/simple_animal/animals/worm.dm
index e8663339c10..dfb8a5a195b 100644
--- a/code/modules/mob/living/simple_animal/worm.dm
+++ b/code/modules/mob/living/simple_animal/animals/worm.dm
@@ -1,200 +1,198 @@
-/mob/living/simple_animal/space_worm
- name = "space worm segment"
- desc = "A part of a space worm."
- icon = 'icons/mob/animal.dmi'
- icon_state = "spaceworm"
- icon_living = "spaceworm"
- icon_dead = "spacewormdead"
- status_flags = 0
-
- speak_emote = list("transmits") //not supposed to be used under AI control
- emote_hear = list("transmits") //I'm just adding it so it doesn't runtime if controlled by player who speaks
-
- response_help = "touches"
- response_disarm = "flails at"
- response_harm = "punches the"
-
- harm_intent_damage = 2
-
- maxHealth = 30
- health = 30
-
- universal_speak =1
-
- stop_automated_movement = 1
- animate_movement = SYNC_STEPS
-
- minbodytemp = 0
- maxbodytemp = 350
- min_oxy = 0
- max_co2 = 0
- max_tox = 0
-
- a_intent = I_HURT //so they don't get pushed around
-
- environment_smash = 2
-
- speed = -1
-
- var/mob/living/simple_animal/space_worm/previous //next/previous segments, correspondingly
- var/mob/living/simple_animal/space_worm/next //head is the nextest segment
-
- var/stomachProcessProbability = 50
- var/digestionProbability = 20
- var/flatPlasmaValue = 5 //flat plasma amount given for non-items
-
- var/atom/currentlyEating //what the worm is currently eating
- var/eatingDuration = 0 //how long he's been eating it for
-
- head
- name = "space worm head"
- icon_state = "spacewormhead"
- icon_living = "spacewormhead"
- icon_dead = "spacewormdead"
-
- maxHealth = 20
- health = 20
-
- melee_damage_lower = 10
- melee_damage_upper = 15
- attacktext = "bitten"
-
- animate_movement = SLIDE_STEPS
-
- New(var/location, var/segments = 6)
- ..()
-
- var/mob/living/simple_animal/space_worm/current = src
-
- for(var/i = 1 to segments)
- var/mob/living/simple_animal/space_worm/newSegment = new /mob/living/simple_animal/space_worm(loc)
- current.Attach(newSegment)
- current = newSegment
-
- update_icon()
- if(stat == CONSCIOUS || stat == UNCONSCIOUS)
- icon_state = "spacewormhead[previous?1:0]"
- if(previous)
- set_dir(get_dir(previous,src))
- else
- icon_state = "spacewormheaddead"
-
- Life()
- ..()
-
- if(next && !(next in view(src,1)))
- Detach()
-
- if(stat == DEAD) //dead chunks fall off and die immediately
- if(previous)
- previous.Detach()
- if(next)
- Detach(1)
-
- if(prob(stomachProcessProbability))
- ProcessStomach()
-
- update_icon()
-
- return
-
- Destroy() //if a chunk a destroyed, make a new worm out of the split halves
- if(previous)
- previous.Detach()
- ..()
-
- Move()
- var/attachementNextPosition = loc
- if(..())
- if(previous)
- previous.Move(attachementNextPosition)
- update_icon()
-
- Bump(atom/obstacle)
- if(currentlyEating != obstacle)
- currentlyEating = obstacle
- eatingDuration = 0
-
- if(!AttemptToEat(obstacle))
- eatingDuration++
- else
- currentlyEating = null
- eatingDuration = 0
-
- return
-
- update_icon() //only for the sake of consistency with the other update icon procs
- if(stat == CONSCIOUS || stat == UNCONSCIOUS)
- if(previous) //midsection
- icon_state = "spaceworm[get_dir(src,previous) | get_dir(src,next)]" //see 3 lines below
- else //tail
- icon_state = "spacewormtail"
- set_dir(get_dir(src,next)) //next will always be present since it's not a head and if it's dead, it goes in the other if branch
- else
- icon_state = "spacewormdead"
-
- return
-
- proc/AttemptToEat(var/atom/target)
- if(istype(target,/turf/simulated/wall))
- var/turf/simulated/wall/W = target
- if((!W.reinf_material && eatingDuration >= 100) || eatingDuration >= 200) //need 20 ticks to eat an rwall, 10 for a regular one
- W.dismantle_wall()
- return 1
- else if(istype(target,/atom/movable))
- if(istype(target,/mob) || eatingDuration >= 50) //5 ticks to eat stuff like airlocks
- var/atom/movable/objectOrMob = target
- contents += objectOrMob
- return 1
-
- return 0
-
- proc/Attach(var/mob/living/simple_animal/space_worm/attachement)
- if(!attachement)
- return
-
- previous = attachement
- attachement.next = src
-
- return
-
- proc/Detach(die = 0)
- var/mob/living/simple_animal/space_worm/newHead = new /mob/living/simple_animal/space_worm/head(loc,0)
- var/mob/living/simple_animal/space_worm/newHeadPrevious = previous
-
- previous = null //so that no extra heads are spawned
-
- newHead.Attach(newHeadPrevious)
-
- if(die)
- newHead.death()
-
- qdel(src)
-
- proc/ProcessStomach()
- for(var/atom/movable/stomachContent in contents)
- if(prob(digestionProbability))
- if(istype(stomachContent,/obj/item/stack)) //converts to plasma, keeping the stack value
- if(!istype(stomachContent,/obj/item/stack/material/phoron))
- var/obj/item/stack/oldStack = stomachContent
- new /obj/item/stack/material/phoron(src, oldStack.get_amount())
- qdel(oldStack)
- continue
- else if(istype(stomachContent,/obj/item)) //converts to plasma, keeping the w_class
- var/obj/item/oldItem = stomachContent
- new /obj/item/stack/material/phoron(src, oldItem.w_class)
- qdel(oldItem)
- continue
- else
- new /obj/item/stack/material/phoron(src, flatPlasmaValue) //just flat amount
- qdel(stomachContent)
- continue
-
- if(previous)
- for(var/atom/movable/stomachContent in contents) //transfer it along the digestive tract
- previous.contents += stomachContent
- else
- for(var/atom/movable/stomachContent in contents) //or poop it out
- loc.contents += stomachContent
-
- return
+/mob/living/simple_animal/space_worm
+ name = "space worm segment"
+ desc = "A part of a space worm."
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "spaceworm"
+ icon_living = "spaceworm"
+ icon_dead = "spacewormdead"
+
+
+ maxHealth = 30
+ health = 30
+ speed = -1
+
+ status_flags = 0
+ universal_speak = 1
+ stop_automated_movement = 1
+ wander = 0
+ animate_movement = SYNC_STEPS
+
+ response_help = "touches"
+ response_disarm = "flails at"
+ response_harm = "punches the"
+
+ harm_intent_damage = 2
+
+ minbodytemp = 0
+ maxbodytemp = 350
+ min_oxy = 0
+ max_co2 = 0
+ max_tox = 0
+
+ environment_smash = 2
+
+ speak_emote = list("transmits") //not supposed to be used under AI control
+ emote_hear = list("transmits") //I'm just adding it so it doesn't runtime if controlled by player who speaks
+
+ var/mob/living/simple_animal/space_worm/previous //next/previous segments, correspondingly
+ var/mob/living/simple_animal/space_worm/next //head is the nextest segment
+
+ var/stomachProcessProbability = 50
+ var/digestionProbability = 20
+ var/flatPlasmaValue = 5 //flat plasma amount given for non-items
+
+ var/atom/currentlyEating //what the worm is currently eating
+ var/eatingDuration = 0 //how long he's been eating it for
+
+ head
+ name = "space worm head"
+ icon_state = "spacewormhead"
+ icon_living = "spacewormhead"
+ icon_dead = "spacewormdead"
+
+ maxHealth = 20
+ health = 20
+
+ melee_damage_lower = 10
+ melee_damage_upper = 15
+ attacktext = "bitten"
+
+ animate_movement = SLIDE_STEPS
+
+ New(var/location, var/segments = 6)
+ ..()
+
+ var/mob/living/simple_animal/space_worm/current = src
+
+ for(var/i = 1 to segments)
+ var/mob/living/simple_animal/space_worm/newSegment = new /mob/living/simple_animal/space_worm(loc)
+ current.Attach(newSegment)
+ current = newSegment
+
+ update_icon()
+ if(stat == CONSCIOUS || stat == UNCONSCIOUS)
+ icon_state = "spacewormhead[previous?1:0]"
+ if(previous)
+ set_dir(get_dir(previous,src))
+ else
+ icon_state = "spacewormheaddead"
+
+ Life()
+ ..()
+
+ if(next && !(next in view(src,1)))
+ Detach()
+
+ if(stat == DEAD) //dead chunks fall off and die immediately
+ if(previous)
+ previous.Detach()
+ if(next)
+ Detach(1)
+
+ if(prob(stomachProcessProbability))
+ ProcessStomach()
+
+ update_icon()
+
+ return
+
+ Destroy() //if a chunk a destroyed, make a new worm out of the split halves
+ if(previous)
+ previous.Detach()
+ ..()
+
+ Move()
+ var/attachementNextPosition = loc
+ if(..())
+ if(previous)
+ previous.Move(attachementNextPosition)
+ update_icon()
+
+ Bump(atom/obstacle)
+ if(currentlyEating != obstacle)
+ currentlyEating = obstacle
+ eatingDuration = 0
+
+ if(!AttemptToEat(obstacle))
+ eatingDuration++
+ else
+ currentlyEating = null
+ eatingDuration = 0
+
+ return
+
+ update_icon() //only for the sake of consistency with the other update icon procs
+ if(stat == CONSCIOUS || stat == UNCONSCIOUS)
+ if(previous) //midsection
+ icon_state = "spaceworm[get_dir(src,previous) | get_dir(src,next)]" //see 3 lines below
+ else //tail
+ icon_state = "spacewormtail"
+ set_dir(get_dir(src,next)) //next will always be present since it's not a head and if it's dead, it goes in the other if branch
+ else
+ icon_state = "spacewormdead"
+
+ return
+
+ proc/AttemptToEat(var/atom/target)
+ if(istype(target,/turf/simulated/wall))
+ var/turf/simulated/wall/W = target
+ if((!W.reinf_material && eatingDuration >= 100) || eatingDuration >= 200) //need 20 ticks to eat an rwall, 10 for a regular one
+ W.dismantle_wall()
+ return 1
+ else if(istype(target,/atom/movable))
+ if(istype(target,/mob) || eatingDuration >= 50) //5 ticks to eat stuff like airlocks
+ var/atom/movable/objectOrMob = target
+ contents += objectOrMob
+ return 1
+
+ return 0
+
+ proc/Attach(var/mob/living/simple_animal/space_worm/attachement)
+ if(!attachement)
+ return
+
+ previous = attachement
+ attachement.next = src
+
+ return
+
+ proc/Detach(die = 0)
+ var/mob/living/simple_animal/space_worm/newHead = new /mob/living/simple_animal/space_worm/head(loc,0)
+ var/mob/living/simple_animal/space_worm/newHeadPrevious = previous
+
+ previous = null //so that no extra heads are spawned
+
+ newHead.Attach(newHeadPrevious)
+
+ if(die)
+ newHead.death()
+
+ qdel(src)
+
+ proc/ProcessStomach()
+ for(var/atom/movable/stomachContent in contents)
+ if(prob(digestionProbability))
+ if(istype(stomachContent,/obj/item/stack)) //converts to plasma, keeping the stack value
+ if(!istype(stomachContent,/obj/item/stack/material/phoron))
+ var/obj/item/stack/oldStack = stomachContent
+ new /obj/item/stack/material/phoron(src, oldStack.get_amount())
+ qdel(oldStack)
+ continue
+ else if(istype(stomachContent,/obj/item)) //converts to plasma, keeping the w_class
+ var/obj/item/oldItem = stomachContent
+ new /obj/item/stack/material/phoron(src, oldItem.w_class)
+ qdel(oldItem)
+ continue
+ else
+ new /obj/item/stack/material/phoron(src, flatPlasmaValue) //just flat amount
+ qdel(stomachContent)
+ continue
+
+ if(previous)
+ for(var/atom/movable/stomachContent in contents) //transfer it along the digestive tract
+ previous.contents += stomachContent
+ else
+ for(var/atom/movable/stomachContent in contents) //or poop it out
+ loc.contents += stomachContent
+
+ return
diff --git a/code/modules/mob/living/simple_animal/borer/borer.dm b/code/modules/mob/living/simple_animal/borer/borer.dm
index dfcefb28a18..f6a0fa3010d 100644
--- a/code/modules/mob/living/simple_animal/borer/borer.dm
+++ b/code/modules/mob/living/simple_animal/borer/borer.dm
@@ -158,7 +158,7 @@
if(host.mind)
borers.remove_antagonist(host.mind)
- src.loc = get_turf(host)
+ src.forceMove(get_turf(host))
reset_view(null)
machine = null
diff --git a/code/modules/mob/living/simple_animal/borer/borer_powers.dm b/code/modules/mob/living/simple_animal/borer/borer_powers.dm
index a95a22b948a..de4bfd4c5b6 100644
--- a/code/modules/mob/living/simple_animal/borer/borer_powers.dm
+++ b/code/modules/mob/living/simple_animal/borer/borer_powers.dm
@@ -105,7 +105,7 @@
src.host = M
src.host.status_flags |= PASSEMOTES
- src.loc = M
+ src.forceMove(M)
//Update their traitor status.
if(host.mind)
diff --git a/code/modules/mob/living/simple_animal/constructs/soulstone.dm b/code/modules/mob/living/simple_animal/constructs/soulstone.dm
index 08160f257f7..05087c40368 100644
--- a/code/modules/mob/living/simple_animal/constructs/soulstone.dm
+++ b/code/modules/mob/living/simple_animal/constructs/soulstone.dm
@@ -131,7 +131,7 @@
qdel(animation)
var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade( T.loc )
- S.loc = src //put shade in stone
+ S.forceMove(src) //put shade in stone
S.status_flags |= GODMODE //So they won't die inside the stone somehow
S.canmove = 0//Can't move out of the soul stone
S.name = "Shade of [T.real_name]"
@@ -167,7 +167,7 @@
U << "Capture failed!: The soul stone has already been imprinted with [src.imprinted]'s mind!"
return
- T.loc = src //put shade in stone
+ T.forceMove(src) //put shade in stone
T.status_flags |= GODMODE
T.canmove = 0
T.health = T.maxHealth
diff --git a/code/modules/mob/living/simple_animal/corpse.dm b/code/modules/mob/living/simple_animal/corpse.dm
index 00b2d114c86..65f5bdef009 100644
--- a/code/modules/mob/living/simple_animal/corpse.dm
+++ b/code/modules/mob/living/simple_animal/corpse.dm
@@ -88,7 +88,7 @@
name = "Syndicate Operative"
corpseuniform = /obj/item/clothing/under/syndicate
corpsesuit = /obj/item/clothing/suit/armor/vest
- corpseshoes = /obj/item/clothing/shoes/swat
+ corpseshoes = /obj/item/clothing/shoes/boots/swat
corpsegloves = /obj/item/clothing/gloves/swat
corpseradio = /obj/item/device/radio/headset
corpsemask = /obj/item/clothing/mask/gas
@@ -104,7 +104,7 @@
name = "Syndicate Commando"
corpseuniform = /obj/item/clothing/under/syndicate
corpsesuit = /obj/item/clothing/suit/space/void/merc
- corpseshoes = /obj/item/clothing/shoes/swat
+ corpseshoes = /obj/item/clothing/shoes/boots/swat
corpsegloves = /obj/item/clothing/gloves/swat
corpseradio = /obj/item/device/radio/headset
corpsemask = /obj/item/clothing/mask/gas/syndicate
@@ -134,7 +134,7 @@
/obj/effect/landmark/mobcorpse/pirate
name = "Pirate"
corpseuniform = /obj/item/clothing/under/pirate
- corpseshoes = /obj/item/clothing/shoes/jackboots
+ corpseshoes = /obj/item/clothing/shoes/boots/jackboots
corpseglasses = /obj/item/clothing/glasses/eyepatch
corpsehelmet = /obj/item/clothing/head/bandana
@@ -150,7 +150,7 @@
/obj/effect/landmark/mobcorpse/russian
name = "Russian"
corpseuniform = /obj/item/clothing/under/soviet
- corpseshoes = /obj/item/clothing/shoes/jackboots
+ corpseshoes = /obj/item/clothing/shoes/boots/jackboots
corpsehelmet = /obj/item/clothing/head/bearpelt
/obj/effect/landmark/mobcorpse/russian/ranged
diff --git a/code/modules/mob/living/simple_animal/friendly/mushroom.dm b/code/modules/mob/living/simple_animal/friendly/mushroom.dm
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
deleted file mode 100644
index 9f8a9177739..00000000000
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ /dev/null
@@ -1,218 +0,0 @@
-
-#define SPINNING_WEB 1
-#define LAYING_EGGS 2
-#define MOVING_TO_TARGET 3
-#define SPINNING_COCOON 4
-
-//basic spider mob, these generally guard nests
-/mob/living/simple_animal/hostile/giant_spider
- name = "giant spider"
- desc = "Furry and black, it makes you shudder to look at it. This one has deep red eyes."
- icon_state = "guard"
- icon_living = "guard"
- icon_dead = "guard_dead"
- speak_emote = list("chitters")
- emote_hear = list("chitters")
- speak_chance = 5
- turns_per_move = 5
- see_in_dark = 10
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/spidermeat
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "punches"
- stop_automated_movement_when_pulled = 0
- maxHealth = 200
- health = 200
- melee_damage_lower = 15
- melee_damage_upper = 20
- heat_damage_per_tick = 20
- cold_damage_per_tick = 20
- var/poison_per_bite = 5
- var/poison_chance = 10
- var/poison_type = "spidertoxin"
- faction = "spiders"
- var/busy = 0
- pass_flags = PASSTABLE
- move_to_delay = 6
- speed = 3
-
-//nursemaids - these create webs and eggs
-/mob/living/simple_animal/hostile/giant_spider/nurse
- desc = "Furry and black, it makes you shudder to look at it. This one has brilliant green eyes."
- icon_state = "nurse"
- icon_living = "nurse"
- icon_dead = "nurse_dead"
- maxHealth = 40
- health = 40
- melee_damage_lower = 5
- melee_damage_upper = 10
- poison_per_bite = 7
- var/atom/cocoon_target
- poison_type = "stoxin"
- var/fed = 0
-
-//hunters have the most poison and move the fastest, so they can find prey
-/mob/living/simple_animal/hostile/giant_spider/hunter
- desc = "Furry and black, it makes you shudder to look at it. This one has sparkling purple eyes."
- icon_state = "hunter"
- icon_living = "hunter"
- icon_dead = "hunter_dead"
- maxHealth = 120
- health = 120
- melee_damage_lower = 10
- melee_damage_upper = 20
- poison_per_bite = 5
- move_to_delay = 4
-
-/mob/living/simple_animal/hostile/giant_spider/New(var/location, var/atom/parent)
- get_light_and_color(parent)
- ..()
-
-/mob/living/simple_animal/hostile/giant_spider/AttackingTarget()
- . = ..()
- if(isliving(.))
- var/mob/living/L = .
- if(L.reagents)
- L.reagents.add_reagent(poison_type, poison_per_bite)
- if(prob(poison_chance))
- L << "You feel a tiny prick."
- L.reagents.add_reagent(poison_type, poison_per_bite)
-
-/mob/living/simple_animal/hostile/giant_spider/nurse/AttackingTarget()
- . = ..()
- if(ishuman(.))
- var/mob/living/carbon/human/H = .
- if(prob(5))
- var/obj/item/organ/external/O = pick(H.organs)
- if(!(O.robotic >= ORGAN_ROBOT))
- var/eggs = PoolOrNew(/obj/effect/spider/eggcluster/, list(O, src))
- O.implants += eggs
- H << "The [src] injects something into your [O.name]!"
-
-/mob/living/simple_animal/hostile/giant_spider/Life()
- ..()
- if(!stat)
- if(stance == STANCE_IDLE)
- //1% chance to skitter madly away
- if(!busy && prob(1))
- /*var/list/move_targets = list()
- for(var/turf/T in orange(20, src))
- move_targets.Add(T)*/
- stop_automated_movement = 1
- walk_to(src, pick(orange(20, src)), 1, move_to_delay)
- spawn(50)
- stop_automated_movement = 0
- walk(src,0)
-
-/mob/living/simple_animal/hostile/giant_spider/nurse/proc/GiveUp(var/C)
- spawn(100)
- if(busy == MOVING_TO_TARGET)
- if(cocoon_target == C && get_dist(src,cocoon_target) > 1)
- cocoon_target = null
- busy = 0
- stop_automated_movement = 0
-
-/mob/living/simple_animal/hostile/giant_spider/nurse/Life()
- ..()
- if(!stat)
- if(stance == STANCE_IDLE)
- var/list/can_see = view(src, 10)
- //30% chance to stop wandering and do something
- if(!busy && prob(30))
- //first, check for potential food nearby to cocoon
- for(var/mob/living/C in can_see)
- if(C.stat)
- cocoon_target = C
- busy = MOVING_TO_TARGET
- walk_to(src, C, 1, move_to_delay)
- //give up if we can't reach them after 10 seconds
- GiveUp(C)
- return
-
- //second, spin a sticky spiderweb on this tile
- var/obj/effect/spider/stickyweb/W = locate() in get_turf(src)
- if(!W)
- busy = SPINNING_WEB
- src.visible_message("\The [src] begins to secrete a sticky substance.")
- stop_automated_movement = 1
- spawn(40)
- if(busy == SPINNING_WEB)
- new /obj/effect/spider/stickyweb(src.loc)
- busy = 0
- stop_automated_movement = 0
- else
- //third, lay an egg cluster there
- var/obj/effect/spider/eggcluster/E = locate() in get_turf(src)
- if(!E && fed > 0)
- busy = LAYING_EGGS
- src.visible_message("\The [src] begins to lay a cluster of eggs.")
- stop_automated_movement = 1
- spawn(50)
- if(busy == LAYING_EGGS)
- E = locate() in get_turf(src)
- if(!E)
- PoolOrNew(/obj/effect/spider/eggcluster, list(loc, src))
- fed--
- busy = 0
- stop_automated_movement = 0
- else
- //fourthly, cocoon any nearby items so those pesky pinkskins can't use them
- for(var/obj/O in can_see)
-
- if(O.anchored)
- continue
-
- if(istype(O, /obj/item) || istype(O, /obj/structure) || istype(O, /obj/machinery))
- cocoon_target = O
- busy = MOVING_TO_TARGET
- stop_automated_movement = 1
- walk_to(src, O, 1, move_to_delay)
- //give up if we can't reach them after 10 seconds
- GiveUp(O)
-
- else if(busy == MOVING_TO_TARGET && cocoon_target)
- if(get_dist(src, cocoon_target) <= 1)
- busy = SPINNING_COCOON
- src.visible_message("\The [src] begins to secrete a sticky substance around \the [cocoon_target].")
- stop_automated_movement = 1
- walk(src,0)
- spawn(50)
- if(busy == SPINNING_COCOON)
- if(cocoon_target && istype(cocoon_target.loc, /turf) && get_dist(src,cocoon_target) <= 1)
- var/obj/effect/spider/cocoon/C = new(cocoon_target.loc)
- var/large_cocoon = 0
- C.pixel_x = cocoon_target.pixel_x
- C.pixel_y = cocoon_target.pixel_y
- for(var/mob/living/M in C.loc)
- if(istype(M, /mob/living/simple_animal/hostile/giant_spider))
- continue
- large_cocoon = 1
- fed++
- src.visible_message("\The [src] sticks a proboscis into \the [cocoon_target] and sucks a viscous substance out.")
- M.loc = C
- C.pixel_x = M.pixel_x
- C.pixel_y = M.pixel_y
- break
- for(var/obj/item/I in C.loc)
- I.loc = C
- for(var/obj/structure/S in C.loc)
- if(!S.anchored)
- S.loc = C
- large_cocoon = 1
- for(var/obj/machinery/M in C.loc)
- if(!M.anchored)
- M.loc = C
- large_cocoon = 1
- if(large_cocoon)
- C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3")
- busy = 0
- stop_automated_movement = 0
-
- else
- busy = 0
- stop_automated_movement = 0
-
-#undef SPINNING_WEB
-#undef LAYING_EGGS
-#undef MOVING_TO_TARGET
-#undef SPINNING_COCOON
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
deleted file mode 100644
index 6269bd4634e..00000000000
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ /dev/null
@@ -1,8 +0,0 @@
-/mob/living/simple_animal/hostile
- faction = "hostile"
- break_stuff_probability = 10
- stop_automated_movement_when_pulled = 0
- destroy_surroundings = 1
- a_intent = I_HURT
- hostile = 1
-
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm
deleted file mode 100644
index ac352edd1a7..00000000000
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm
+++ /dev/null
@@ -1,49 +0,0 @@
-/mob/living/simple_animal/hostile/retaliate
- var/list/enemies = list()
-
-/mob/living/simple_animal/hostile/retaliate/Found(var/atom/A)
- if(isliving(A))
- var/mob/living/L = A
- if(!L.stat)
- stance = STANCE_ATTACK
- return L
- else
- enemies -= L
- else if(istype(A, /obj/mecha))
- var/obj/mecha/M = A
- if(M.occupant)
- stance = STANCE_ATTACK
- return A
-
-/mob/living/simple_animal/hostile/retaliate/ListTargets()
- if(!enemies.len)
- return list()
- var/list/see = ..()
- see &= enemies // Remove all entries that aren't in enemies
- return see
-
-/mob/living/simple_animal/hostile/retaliate/proc/Retaliate()
- ..()
- var/list/around = view(src, 7)
-
- for(var/atom/movable/A in around)
- if(A == src)
- continue
- if(isliving(A))
- var/mob/living/M = A
- if(!attack_same && M.faction != faction)
- enemies |= M
- else if(istype(A, /obj/mecha))
- var/obj/mecha/M = A
- if(M.occupant)
- enemies |= M
- enemies |= M.occupant
-
- for(var/mob/living/simple_animal/hostile/retaliate/H in around)
- if(!attack_same && !H.attack_same && H.faction == faction)
- H.enemies |= enemies
- return 0
-
-/mob/living/simple_animal/hostile/retaliate/adjustBruteLoss(var/damage)
- ..(damage)
- Retaliate()
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/humanoids/clown.dm
similarity index 84%
rename from code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
rename to code/modules/mob/living/simple_animal/humanoids/clown.dm
index 5a6a7e57688..5bf310b1655 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/clown.dm
@@ -1,39 +1,47 @@
-/mob/living/simple_animal/hostile/retaliate/clown
- name = "clown"
- desc = "A denizen of clown planet"
- icon_state = "clown"
- icon_living = "clown"
- icon_dead = "clown_dead"
- icon_gib = "clown_gib"
- speak_chance = 0
- turns_per_move = 5
- response_help = "pokes"
- response_disarm = "gently pushes aside"
- response_harm = "hits"
- speak = list("HONK", "Honk!", "Welcome to clown planet!")
- emote_see = list("honks")
- speak_chance = 1
- a_intent = I_HURT
- stop_automated_movement_when_pulled = 0
- maxHealth = 75
- health = 75
- speed = -1
- harm_intent_damage = 8
- melee_damage_lower = 10
- melee_damage_upper = 10
- attacktext = "attacked"
- attack_sound = 'sound/items/bikehorn.ogg'
-
- min_oxy = 5
- max_oxy = 0
- min_tox = 0
- max_tox = 1
- min_co2 = 0
- max_co2 = 5
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 270
- maxbodytemp = 370
- heat_damage_per_tick = 15 //amount of damage applied if animal's body temperature is higher than maxbodytemp
- cold_damage_per_tick = 10 //same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp
- unsuitable_atoms_damage = 10
+/mob/living/simple_animal/hostile/clown
+ name = "clown"
+ desc = "A denizen of clown planet"
+ icon_state = "clown"
+ icon_living = "clown"
+ icon_dead = "clown_dead"
+ icon_gib = "clown_gib"
+
+ faction = "clown"
+ maxHealth = 75
+ health = 75
+ speed = -1
+ move_to_delay = 2
+
+ run_at_them = 0
+ cooperative = 1
+
+ turns_per_move = 5
+ stop_when_pulled = 0
+
+ response_help = "pokes"
+ response_disarm = "gently pushes aside"
+ response_harm = "hits"
+
+ harm_intent_damage = 8
+ melee_damage_lower = 10
+ melee_damage_upper = 10
+ attacktext = "attacked"
+ attack_sound = 'sound/items/bikehorn.ogg'
+
+ min_oxy = 5
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 1
+ min_co2 = 0
+ max_co2 = 5
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 270
+ maxbodytemp = 370
+ heat_damage_per_tick = 15 //amount of damage applied if animal's body temperature is higher than maxbodytemp
+ cold_damage_per_tick = 10 //same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp
+ unsuitable_atoms_damage = 10
+
+ speak_chance = 1
+ speak = list("HONK", "Honk!", "Welcome to clown planet!")
+ emote_see = list("honks")
diff --git a/code/modules/mob/living/simple_animal/head.dm b/code/modules/mob/living/simple_animal/humanoids/head.dm
similarity index 92%
rename from code/modules/mob/living/simple_animal/head.dm
rename to code/modules/mob/living/simple_animal/humanoids/head.dm
index 88a9f3d6cae..f0e8b8abde4 100644
--- a/code/modules/mob/living/simple_animal/head.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/head.dm
@@ -5,16 +5,23 @@
icon_state = "crab"
icon_living = "crab"
icon_dead = "crab_dead"
- speak_emote = list("clicks")
- emote_hear = list("clicks")
- emote_see = list("clacks")
+
+ wander = 0
+ stop_automated_movement = 1
universal_speak = 1
- speak_chance = 1
turns_per_move = 5
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "punches"
+
+ speak_chance = 1
+ speak_emote = list("clicks")
+ emote_hear = list("clicks")
+ emote_see = list("clacks")
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+
var/list/insults = list(
"Man you suck",
"You look like the most retarded douche around",
@@ -32,22 +39,15 @@
"Say \"what\" again. Say \"what\" again. I dare you. I double-dare you, motherfucker. Say \"what\" one more goddamn time.",
"Ezekiel 25:17 ,The path of the righteous man is beset on all sides by the iniquities of the selfish and the tyranny of evil men. Blessed is he who in the name of charity and good will shepherds the weak through the valley of darkness, for he is truly his brother's keeper and the finder of lost children. And I will strike down upon thee with great vengeance and furious anger those who attempt to poison and destroy my brothers. And you will know my name is the Lord... when I lay my vengeance upon thee.",
"Did you notice a sign out in front of my house that said \"Dead Nigger Storage\"?")
- stop_automated_movement = 1
/mob/living/simple_animal/head/Life()
- if(stat == DEAD)
- if(health > 0)
- icon_state = icon_living
- stat = CONSCIOUS
- density = 1
- return
- else if(health < 1)
- Die()
- else if(health > maxHealth)
- health = maxHealth
+ . = ..()
+ if(!. || ai_inactive) return
+
for(var/mob/A in viewers(world.view,src))
if(A.ckey)
say_something(A)
+
/mob/living/simple_animal/head/proc/say_something(mob/A)
if(prob(85))
return
diff --git a/code/modules/mob/living/simple_animal/kobold.dm b/code/modules/mob/living/simple_animal/humanoids/kobold.dm
similarity index 82%
rename from code/modules/mob/living/simple_animal/kobold.dm
rename to code/modules/mob/living/simple_animal/humanoids/kobold.dm
index 3e52a408747..8f3ce0d28c0 100644
--- a/code/modules/mob/living/simple_animal/kobold.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/kobold.dm
@@ -6,25 +6,34 @@
icon_state = "kobold_idle"
icon_living = "kobold_idle"
icon_dead = "kobold_dead"
- //speak = list("You no take candle!","Ooh, pretty shiny.","Me take?","Where gold here...","Me likey.")
- speak_emote = list("mutters","hisses","grumbles")
- emote_hear = list("mutters under it's breath.","grumbles.", "yips!")
- emote_see = list("looks around suspiciously.", "scratches it's arm.","putters around a bit.")
- speak_chance = 15
+
+ run_at_them = 0
+ cooperative = 1
+
turns_per_move = 5
see_in_dark = 6
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/monkey
+
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "kicks"
- minbodytemp = 250
+
min_oxy = 16 //Require atleast 16kPA oxygen
minbodytemp = 223 //Below -50 Degrees Celcius
maxbodytemp = 323 //Above 50 Degrees Celcius
+ speak_chance = 5
+ speak = list("You no take candle!","Ooh, pretty shiny.","Me take?","Where gold here...","Me likey.")
+ speak_emote = list("mutters","hisses","grumbles")
+ emote_hear = list("mutters under it's breath.","grumbles.", "yips!")
+ emote_see = list("looks around suspiciously.", "scratches it's arm.","putters around a bit.")
+
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/monkey
+
/mob/living/simple_animal/kobold/Life()
- ..()
- if(prob(15) && turns_since_move && !stat)
+ . = ..()
+ if(!.) return
+
+ if(prob(5))
flick("kobold_act",src)
/mob/living/simple_animal/kobold/Move(var/dir)
diff --git a/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm b/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm
new file mode 100644
index 00000000000..79f389821e7
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm
@@ -0,0 +1,94 @@
+/mob/living/simple_animal/hostile/mecha
+ name = "syndicate gygax"
+ desc = "Well that's forboding."
+ icon = 'icons/mecha/mecha.dmi'
+ icon_state = "darkgygax"
+ icon_living = "darkgygax"
+ icon_dead = "darkgygax-broken"
+
+ faction = "syndicate"
+ maxHealth = 300
+ health = 300
+ speed = 7
+ move_to_delay = 8
+
+ run_at_them = 0
+ cooperative = 1
+ investigates = 1
+ firing_lines = 1
+
+ turns_per_move = 5
+ stop_when_pulled = 0
+
+ response_help = "taps on"
+ response_disarm = "knocks on"
+ response_harm = "uselessly hits"
+
+ harm_intent_damage = 0
+ melee_damage_lower = 35
+ melee_damage_upper = 35
+ attacktext = "slashed"
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ unsuitable_atoms_damage = 0
+
+ ranged = 1
+ rapid = 1
+ projectiletype = /obj/item/projectile/beam
+ projectilesound = 'sound/weapons/laser.ogg'
+
+ speak_chance = 1
+ speak = list("Know what we need? More meatshields.",
+ "Glad I finally got a mech.",
+ "I'll stomp those NanoTrasen dogs into paste.",
+ "Glad I didn't become a line chef.",
+ "This anti-fog visor is nice...",
+ "Did I refill the air tank?")
+ emote_hear = list("humms ominously","whirrs softly","grinds a gear")
+ emote_see = list("looks around the area","turns from side to side")
+ say_understood = list()
+ say_cannot = list()
+ say_maybe_target = list("Just my sensors?","Detecting something?","Is that...?","What was that?")
+ say_got_target = list("ENGAGING!!!","CONTACT!!!","TARGET SPOTTED!","FOUND ONE!")
+ reactions = list()
+
+ var/datum/effect/effect/system/spark_spread/sparks
+ var/wreckage = /obj/effect/decal/mecha_wreckage/gygax/dark
+
+/mob/living/simple_animal/hostile/mecha/New()
+ ..()
+ sparks = new (src)
+ sparks.set_up(3, 1, src)
+
+/mob/living/simple_animal/hostile/mecha/Destroy()
+ qdel(sparks)
+ ..()
+
+/mob/living/simple_animal/hostile/mecha/Life()
+ . = ..()
+ if(!.) return
+ if((health < maxHealth*0.3) && prob(10))
+ sparks.start()
+
+/mob/living/simple_animal/hostile/mecha/bullet_act()
+ ..()
+ sparks.start()
+
+/mob/living/simple_animal/hostile/mecha/death()
+ ..(0,"is explodes!")
+ sparks.start()
+ explosion(get_turf(src), 0, 0, 1, 3)
+ qdel(src)
+ new /obj/effect/decal/mecha_wreckage/gygax/dark(get_turf(src))
+
+/mob/living/simple_animal/hostile/mecha/Move()
+ ..()
+ playsound(src,'sound/mecha/mechstep.ogg',40,1)
diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/humanoids/pirate.dm
similarity index 80%
rename from code/modules/mob/living/simple_animal/hostile/pirate.dm
rename to code/modules/mob/living/simple_animal/humanoids/pirate.dm
index 3fbbe40aa63..02d1a8eb72b 100644
--- a/code/modules/mob/living/simple_animal/hostile/pirate.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/pirate.dm
@@ -1,56 +1,66 @@
-/mob/living/simple_animal/hostile/pirate
- name = "Pirate"
- desc = "Does what he wants cause a pirate is free."
- icon_state = "piratemelee"
- icon_living = "piratemelee"
- icon_dead = "piratemelee_dead"
- speak_chance = 0
- turns_per_move = 5
- response_help = "pushes"
- response_disarm = "shoves"
- response_harm = "hits"
- speed = 4
- stop_automated_movement_when_pulled = 0
- maxHealth = 100
- health = 100
-
- harm_intent_damage = 5
- melee_damage_lower = 30
- melee_damage_upper = 30
- attacktext = "slashed"
- attack_sound = 'sound/weapons/bladeslice.ogg'
-
- min_oxy = 5
- max_oxy = 0
- min_tox = 0
- max_tox = 1
- min_co2 = 0
- max_co2 = 5
- min_n2 = 0
- max_n2 = 0
- unsuitable_atoms_damage = 15
- var/corpse = /obj/effect/landmark/mobcorpse/pirate
- var/weapon1 = /obj/item/weapon/melee/energy/sword/pirate
-
- faction = "pirate"
-
-/mob/living/simple_animal/hostile/pirate/ranged
- name = "Pirate Gunner"
- icon_state = "pirateranged"
- icon_living = "pirateranged"
- icon_dead = "piratemelee_dead"
- projectilesound = 'sound/weapons/laser.ogg'
- ranged = 1
- projectiletype = /obj/item/projectile/beam
- corpse = /obj/effect/landmark/mobcorpse/pirate/ranged
- weapon1 = /obj/item/weapon/gun/energy/laser
-
-
-/mob/living/simple_animal/hostile/pirate/death()
- ..()
- if(corpse)
- new corpse (src.loc)
- if(weapon1)
- new weapon1 (src.loc)
- qdel(src)
+/mob/living/simple_animal/hostile/pirate
+ name = "Pirate"
+ desc = "Does what he wants cause a pirate is free."
+ icon_state = "piratemelee"
+ icon_living = "piratemelee"
+ icon_dead = "piratemelee_dead"
+
+ faction = "pirate"
+ maxHealth = 100
+ health = 100
+ speed = 4
+
+ run_at_them = 0
+ cooperative = 1
+ investigates = 1
+ firing_lines = 1
+ returns_home = 1
+ reacts = 1
+
+ turns_per_move = 5
+ stop_when_pulled = 0
+
+ response_help = "pushes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 30
+ melee_damage_upper = 30
+ attacktext = "slashed"
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+
+ min_oxy = 5
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 1
+ min_co2 = 0
+ max_co2 = 5
+ min_n2 = 0
+ max_n2 = 0
+ unsuitable_atoms_damage = 15
+
+ loot_list = list(/obj/item/weapon/melee/energy/sword/pirate = 100)
+
+ var/corpse = /obj/effect/landmark/mobcorpse/pirate
+
+/mob/living/simple_animal/hostile/pirate/ranged
+ name = "Pirate Gunner"
+ icon_state = "pirateranged"
+ icon_living = "pirateranged"
+ icon_dead = "piratemelee_dead"
+
+ ranged = 1
+ projectiletype = /obj/item/projectile/beam
+ projectilesound = 'sound/weapons/laser.ogg'
+
+ loot_list = list(/obj/item/weapon/gun/energy/laser = 100)
+
+ corpse = /obj/effect/landmark/mobcorpse/pirate/ranged
+
+/mob/living/simple_animal/hostile/pirate/death()
+ ..()
+ if(corpse)
+ new corpse (src.loc)
+ qdel(src)
return
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/humanoids/russian.dm
similarity index 79%
rename from code/modules/mob/living/simple_animal/hostile/russian.dm
rename to code/modules/mob/living/simple_animal/humanoids/russian.dm
index ee99318c153..96ff3a5177d 100644
--- a/code/modules/mob/living/simple_animal/hostile/russian.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/russian.dm
@@ -1,55 +1,66 @@
-/mob/living/simple_animal/hostile/russian
- name = "russian"
- desc = "For the Motherland!"
- icon_state = "russianmelee"
- icon_living = "russianmelee"
- icon_dead = "russianmelee_dead"
- icon_gib = "syndicate_gib"
- speak_chance = 0
- turns_per_move = 5
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
- speed = 4
- stop_automated_movement_when_pulled = 0
- maxHealth = 100
- health = 100
- harm_intent_damage = 5
- melee_damage_lower = 15
- melee_damage_upper = 15
- attacktext = "punched"
- a_intent = I_HURT
- var/corpse = /obj/effect/landmark/mobcorpse/russian
- var/weapon1 = /obj/item/weapon/material/knife
- min_oxy = 5
- max_oxy = 0
- min_tox = 0
- max_tox = 1
- min_co2 = 0
- max_co2 = 5
- min_n2 = 0
- max_n2 = 0
- unsuitable_atoms_damage = 15
- faction = "russian"
- status_flags = CANPUSH
-
-
-/mob/living/simple_animal/hostile/russian/ranged
- icon_state = "russianranged"
- icon_living = "russianranged"
- corpse = /obj/effect/landmark/mobcorpse/russian/ranged
- weapon1 = /obj/item/weapon/gun/projectile/revolver/mateba
- ranged = 1
- projectiletype = /obj/item/projectile/bullet
- projectilesound = 'sound/weapons/Gunshot.ogg'
- casingtype = /obj/item/ammo_casing/spent
-
-
-/mob/living/simple_animal/hostile/russian/death()
- ..()
- if(corpse)
- new corpse (src.loc)
- if(weapon1)
- new weapon1 (src.loc)
- qdel(src)
- return
\ No newline at end of file
+/mob/living/simple_animal/hostile/russian
+ name = "russian"
+ desc = "For the Motherland!"
+ icon_state = "russianmelee"
+ icon_living = "russianmelee"
+ icon_dead = "russianmelee_dead"
+ icon_gib = "syndicate_gib"
+
+ faction = "russian"
+ maxHealth = 100
+ health = 100
+ speed = 4
+
+ run_at_them = 0
+ cooperative = 1
+ investigates = 1
+ firing_lines = 1
+ returns_home = 1
+ reacts = 1
+
+ turns_per_move = 5
+ stop_when_pulled = 0
+ status_flags = CANPUSH
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ attacktext = "punched"
+
+ min_oxy = 5
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 1
+ min_co2 = 0
+ max_co2 = 5
+ min_n2 = 0
+ max_n2 = 0
+ unsuitable_atoms_damage = 15
+
+ loot_list = list(/obj/item/weapon/material/knife = 100)
+
+ var/corpse = /obj/effect/landmark/mobcorpse/russian
+
+/mob/living/simple_animal/hostile/russian/ranged
+ icon_state = "russianranged"
+ icon_living = "russianranged"
+
+ ranged = 1
+ projectiletype = /obj/item/projectile/bullet
+ casingtype = /obj/item/ammo_casing/spent
+ projectilesound = 'sound/weapons/Gunshot.ogg'
+
+ loot_list = list(/obj/item/weapon/gun/projectile/revolver/mateba = 100)
+
+ corpse = /obj/effect/landmark/mobcorpse/russian/ranged
+
+/mob/living/simple_animal/hostile/russian/death()
+ ..()
+ if(corpse)
+ new corpse (src.loc)
+ qdel(src)
+ return
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/humanoids/syndicate.dm
similarity index 67%
rename from code/modules/mob/living/simple_animal/hostile/syndicate.dm
rename to code/modules/mob/living/simple_animal/humanoids/syndicate.dm
index 694e95b4340..eebc6c9571b 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/humanoids/syndicate.dm
@@ -1,163 +1,192 @@
-/mob/living/simple_animal/hostile/syndicate
- name = "\improper Syndicate operative"
- desc = "Death to the Company."
- icon_state = "syndicate"
- icon_living = "syndicate"
- icon_dead = "syndicate_dead"
- icon_gib = "syndicate_gib"
- speak_chance = 0
- turns_per_move = 5
- response_help = "pokes"
- response_disarm = "shoves"
- response_harm = "hits"
- speed = 4
- stop_automated_movement_when_pulled = 0
- maxHealth = 100
- health = 100
- harm_intent_damage = 5
- melee_damage_lower = 10
- melee_damage_upper = 10
- attacktext = "punched"
- a_intent = I_HURT
- var/corpse = /obj/effect/landmark/mobcorpse/syndicatesoldier
- var/weapon1
- var/weapon2
- min_oxy = 5
- max_oxy = 0
- min_tox = 0
- max_tox = 1
- min_co2 = 0
- max_co2 = 5
- min_n2 = 0
- max_n2 = 0
- unsuitable_atoms_damage = 15
- environment_smash = 1
- faction = "syndicate"
- status_flags = CANPUSH
-
-/mob/living/simple_animal/hostile/syndicate/death()
- ..()
- if(corpse)
- new corpse (src.loc)
- if(weapon1)
- new weapon1 (src.loc)
- if(weapon2)
- new weapon2 (src.loc)
- qdel(src)
- return
-
-///////////////Sword and shield////////////
-
-/mob/living/simple_animal/hostile/syndicate/melee
- melee_damage_lower = 20
- melee_damage_upper = 25
- icon_state = "syndicatemelee"
- icon_living = "syndicatemelee"
- weapon1 = /obj/item/weapon/melee/energy/sword/red
- weapon2 = /obj/item/weapon/shield/energy
- attacktext = "slashed"
- status_flags = 0
-
-/mob/living/simple_animal/hostile/syndicate/melee/attackby(var/obj/item/O as obj, var/mob/user as mob)
- if(O.force)
- if(prob(80))
- var/damage = O.force
- if (O.damtype == HALLOSS)
- damage = 0
- health -= damage
- visible_message("\red \b [src] has been attacked with the [O] by [user]. ")
- else
- visible_message("\red \b [src] blocks the [O] with its shield! ")
- //user.do_attack_animation(src)
- else
- usr << "\red This weapon is ineffective, it does no damage."
- visible_message("\red [user] gently taps [src] with the [O]. ")
-
-
-/mob/living/simple_animal/hostile/syndicate/melee/bullet_act(var/obj/item/projectile/Proj)
- if(!Proj) return
- if(prob(65))
- src.health -= Proj.damage
- else
- visible_message("\red [src] blocks [Proj] with its shield!")
- return 0
-
-
-/mob/living/simple_animal/hostile/syndicate/melee/space
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
- icon_state = "syndicatemeleespace"
- icon_living = "syndicatemeleespace"
- name = "Syndicate Commando"
- corpse = /obj/effect/landmark/mobcorpse/syndicatecommando
- speed = 0
-
-/mob/living/simple_animal/hostile/syndicate/melee/space/Process_Spacemove(var/check_drift = 0)
- return
-
-/mob/living/simple_animal/hostile/syndicate/ranged
- ranged = 1
- rapid = 1
- icon_state = "syndicateranged"
- icon_living = "syndicateranged"
- casingtype = /obj/item/ammo_casing/spent
- projectilesound = 'sound/weapons/Gunshot_light.ogg'
- projectiletype = /obj/item/projectile/bullet/pistol/medium
-
- weapon1 = /obj/item/weapon/gun/projectile/automatic/c20r
-
-/mob/living/simple_animal/hostile/syndicate/ranged/space
- icon_state = "syndicaterangedpsace"
- icon_living = "syndicaterangedpsace"
- name = "Syndicate Commando"
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
- corpse = /obj/effect/landmark/mobcorpse/syndicatecommando
- speed = 0
-
-/mob/living/simple_animal/hostile/syndicate/ranged/space/Process_Spacemove(var/check_drift = 0)
- return
-
-
-
-/mob/living/simple_animal/hostile/viscerator
- name = "viscerator"
- desc = "A small, twin-bladed machine capable of inflicting very deadly lacerations."
- icon = 'icons/mob/critter.dmi'
- icon_state = "viscerator_attack"
- icon_living = "viscerator_attack"
- pass_flags = PASSTABLE
- health = 15
- maxHealth = 15
- melee_damage_lower = 15
- melee_damage_upper = 15
- attacktext = "cut"
- attack_sound = 'sound/weapons/bladeslice.ogg'
- faction = "syndicate"
- min_oxy = 0
- max_oxy = 0
- min_tox = 0
- max_tox = 0
- min_co2 = 0
- max_co2 = 0
- min_n2 = 0
- max_n2 = 0
- minbodytemp = 0
-
-/mob/living/simple_animal/hostile/viscerator/death()
- ..(null,"is smashed into pieces!")
- qdel(src)
+/mob/living/simple_animal/hostile/syndicate
+ name = "syndicate operative"
+ desc = "Death to the Company."
+ icon_state = "syndicate"
+ icon_living = "syndicate"
+ icon_dead = "syndicate_dead"
+ icon_gib = "syndicate_gib"
+
+ faction = "syndicate"
+ maxHealth = 100
+ health = 100
+ speed = 4
+
+ run_at_them = 0
+ cooperative = 1
+ investigates = 1
+ firing_lines = 1
+ returns_home = 1
+ reacts = 1
+
+ turns_per_move = 5
+ stop_when_pulled = 0
+ status_flags = CANPUSH
+
+ response_help = "pokes"
+ response_disarm = "shoves"
+ response_harm = "hits"
+
+ harm_intent_damage = 5
+ melee_damage_lower = 10
+ melee_damage_upper = 15
+ environment_smash = 1
+ attacktext = "punched"
+
+ min_oxy = 5
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 1
+ min_co2 = 0
+ max_co2 = 5
+ min_n2 = 0
+ max_n2 = 0
+ unsuitable_atoms_damage = 15
+
+ speak_chance = 1
+ speak = list("Fuckin' NT, man.",
+ "When are we gonna get out of this chicken-shit outfit?",
+ "Wish I had better equipment...",
+ "I knew I should have been a line chef...",
+ "Fuckin' helmet keeps fogging up.",
+ "Anyone else smell that?")
+ emote_hear = list("sniffs","coughs","taps his foot")
+ emote_see = list("looks around","checks his equipment")
+ say_understood = list()
+ say_cannot = list()
+ say_maybe_target = list("What's that?","Is someone there?","Is that...?","Hmm?")
+ say_got_target = list("ENGAGING!!!","CONTACT!!!","TARGET SPOTTED!","FOUND ONE!")
+ reactions = list("Hey guys, you ready?" = "Fuck yeah!")
+
+ var/corpse = /obj/effect/landmark/mobcorpse/syndicatesoldier
+
+/mob/living/simple_animal/hostile/syndicate/death()
+ ..()
+ if(corpse)
+ new corpse (src.loc)
+ qdel(src)
+ return
+
+///////////////Sword and shield////////////
+
+/mob/living/simple_animal/hostile/syndicate/melee
+ icon_state = "syndicatemelee"
+ icon_living = "syndicatemelee"
+
+ melee_damage_lower = 20
+ melee_damage_upper = 25
+ attacktext = "slashed"
+
+ status_flags = 0
+
+ loot_list = list(/obj/item/weapon/melee/energy/sword/red = 100, /obj/item/weapon/shield/energy = 100)
+
+/mob/living/simple_animal/hostile/syndicate/melee/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(O.force)
+ if(prob(20))
+ visible_message("\The [src] blocks \the [O] with its shield!")
+ if(user)
+ react_to_attack(user)
+ return
+ else
+ ..()
+ else
+ usr << "This weapon is ineffective, it does no damage."
+ visible_message("\The [user] gently taps [src] with \the [O].")
+
+/mob/living/simple_animal/hostile/syndicate/melee/bullet_act(var/obj/item/projectile/Proj)
+ if(!Proj) return
+ if(prob(35))
+ visible_message("\red [src] blocks [Proj] with its shield!")
+ if(Proj.firer)
+ react_to_attack(Proj.firer)
+ return
+ else
+ ..()
+
+/mob/living/simple_animal/hostile/syndicate/melee/space
+ name = "syndicate commando"
+ icon_state = "syndicatemeleespace"
+ icon_living = "syndicatemeleespace"
+
+ speed = 0
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ corpse = /obj/effect/landmark/mobcorpse/syndicatecommando
+
+/mob/living/simple_animal/hostile/syndicate/melee/space/Process_Spacemove(var/check_drift = 0)
+ return
+
+/mob/living/simple_animal/hostile/syndicate/ranged
+ icon_state = "syndicateranged"
+ icon_living = "syndicateranged"
+
+ ranged = 1
+ rapid = 1
+ projectiletype = /obj/item/projectile/bullet/pistol/medium
+ casingtype = /obj/item/ammo_casing/spent
+ projectilesound = 'sound/weapons/Gunshot_light.ogg'
+
+ loot_list = list(/obj/item/weapon/gun/projectile/automatic/c20r = 100)
+
+/mob/living/simple_animal/hostile/syndicate/ranged/space
+ name = "syndicate sommando"
+ icon_state = "syndicaterangedpsace"
+ icon_living = "syndicaterangedpsace"
+
+ speed = 0
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+ corpse = /obj/effect/landmark/mobcorpse/syndicatecommando
+
+/mob/living/simple_animal/hostile/syndicate/ranged/space/Process_Spacemove(var/check_drift = 0)
+ return
+
+/mob/living/simple_animal/hostile/viscerator
+ name = "viscerator"
+ desc = "A small, twin-bladed machine capable of inflicting very deadly lacerations."
+ icon = 'icons/mob/critter.dmi'
+ icon_state = "viscerator_attack"
+ icon_living = "viscerator_attack"
+
+ faction = "syndicate"
+ maxHealth = 15
+ health = 15
+
+ pass_flags = PASSTABLE
+
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ attack_sound = 'sound/weapons/bladeslice.ogg'
+ attacktext = "cut"
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+
+/mob/living/simple_animal/hostile/viscerator/death()
+ ..(null,"is smashed into pieces!")
+ qdel(src)
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index ae9622d3050..1179dc889f2 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -1,3 +1,8 @@
+#define ai_log(M,V) if(debug_ai) ai_log_output(M,V)
+
+//Talky things
+#define try_say_list(L) if(L.len) say(pick(L))
+
/mob/living/simple_animal
name = "animal"
icon = 'icons/mob/animal.dmi'
@@ -5,84 +10,114 @@
maxHealth = 20
mob_bump_flag = SIMPLE_ANIMAL
- mob_swap_flags = MONKEY|SLIME|SIMPLE_ANIMAL
- mob_push_flags = MONKEY|SLIME|SIMPLE_ANIMAL
+ mob_swap_flags = MONKEY|SLIME|HUMAN
+ mob_push_flags = MONKEY|SLIME|HUMAN
- var/show_stat_health = 1 //does the percentage health show in the stat panel for the mob
+ //Settings for played mobs
+ var/show_stat_health = 1 // Does the percentage health show in the stat panel for the mob
+ var/ai_inactive = 0 // Set to 1 to turn off most AI actions
- var/icon_living = ""
- var/icon_dead = ""
- var/icon_gib = null //We only try to show a gibbing animation if this exists.
+ //Mob icon settings
+ var/icon_living = "" // The iconstate if we're alive, required
+ var/icon_dead = "" // The iconstate if we're dead, required
+ var/icon_gib = null // The iconstate for being gibbed, optional
+ var/icon_rest = null // The iconstate for resting, optional
- var/list/speak = list()
- var/speak_chance = 0
- var/list/emote_hear = list() //Hearable emotes
- var/list/emote_see = list() //Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps
+ //Mob talking settings
+ universal_speak = 0 // Can all mobs in the entire universe understand this one?
+ var/has_langs = list(LANGUAGE_GALCOM)// Text name of their language if they speak something other than galcom. They speak the first one.
+ var/speak_chance = 0 // Probability that I talk (this is 'X in 200' chance since even 1/100 is pretty noisy)
+ var/reacts = 0 // Reacts to some things being said
+ var/list/speak = list() // Things I might say if I talk
+ var/list/emote_hear = list() // Hearable emotes I might perform
+ var/list/emote_see = list() // Unlike speak_emote, the list of things in this variable only show by themselves with no spoken text. IE: Ian barks, Ian yaps
+ var/list/say_understood = list()// List of things to say when accepting an order
+ var/list/say_cannot = list() // List of things to say when they cannot comply
+ var/list/say_maybe_target = list()// List of things to say when they spot something barely
+ var/list/say_got_target = list()// List of things to say when they engage a target
+ var/list/reactions = list() // List of "string" = "reaction" and things they hear will be searched for string.
- var/turns_per_move = 1
- var/turns_since_move = 0
- universal_speak = 0 //No, just no.
- var/meat_amount = 0
- var/meat_type
- var/stop_automated_movement = 0 //Use this to temporarely stop random movement or to if you write special movement code for animals.
- var/wander = 1 // Does the mob wander around when idle?
- var/stop_automated_movement_when_pulled = 1 //When set to 1 this stops the animal from moving when someone is pulling it.
+ //Mob movement settings
+ var/wander = 1 // Does the mob wander around when idle?
+ var/wander_distance = 3 // How far the mob will wander before going home (assuming they are allowed to do that)
+ var/returns_home = 0 // Mob knows how to return to wherever it started
+ var/turns_per_move = 1 // How many life() cycles to wait between each wander mov?
+ var/stop_when_pulled = 1 // When set to 1 this stops the animal from moving when someone is pulling it.
+ var/follow_dist = 2 // Distance the mob tries to follow a friend
+ var/obstacles = list() // Things this mob refuses to move through
+ var/speed = 0 // Higher speed is slower, negative speed is faster.
+ var/obj/item/weapon/card/id/myid// An ID card if they have one to give them access to stuff.
+ var/turf/home_turf // Set when they spawned, they try to come back here sometimes.
- //Interaction
- var/response_help = "tries to help"
- var/response_disarm = "tries to disarm"
- var/response_harm = "tries to hurt"
- var/harm_intent_damage = 3
+ //Mob interaction
+ var/response_help = "tries to help" // If clicked on help intent
+ var/response_disarm = "tries to disarm" // If clicked on disarm intent
+ var/response_harm = "tries to hurt" // If clicked on harm intent
+ var/harm_intent_damage = 3 // How much an unarmed harm click does to this mob.
+ var/meat_amount = 0 // How much meat to drop from this mob when butchered
+ var/obj/meat_type // The meat object to drop
+ var/list/loot_list = list() // The list of lootable objects to drop, with "/path = prob%" structure
+ var/recruitable = 0 // Mob can be bossed around
+ var/recruit_cmd_str = "Hey," // The thing you prefix commands with when bossing them around
- //Temperature effect
- var/minbodytemp = 250
- var/maxbodytemp = 350
- var/heat_damage_per_tick = 3 //amount of damage applied if animal's body temperature is higher than maxbodytemp
- var/cold_damage_per_tick = 2 //same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp
- var/fire_alert = 0
+ //Mob environment settings
+ var/minbodytemp = 250 // Minimum "okay" temperature in kelvin
+ var/maxbodytemp = 350 // Maximum of above
+ var/heat_damage_per_tick = 3 // Amount of damage applied if animal's body temperature is higher than maxbodytemp
+ var/cold_damage_per_tick = 2 // Same as heat_damage_per_tick, only if the bodytemperature it's lower than minbodytemp
+ var/fire_alert = 0 // 0 = fine, 1 = hot, 2 = cold
- //Atmos effect - Yes, you can make creatures that require phoron or co2 to survive. N2O is a trace gas and handled separately, hence why it isn't here. It'd be hard to add it. Hard and me don't mix (Yes, yes make all the dick jokes you want with that.) - Errorage
- var/min_oxy = 5
- var/max_oxy = 0 //Leaving something at 0 means it's off - has no maximum
- var/min_tox = 0
- var/max_tox = 1
- var/min_co2 = 0
- var/max_co2 = 5
- var/min_n2 = 0
- var/max_n2 = 0
- var/unsuitable_atoms_damage = 2 //This damage is taken when atmos doesn't fit all the requirements above
- var/speed = 0 //LETS SEE IF I CAN SET SPEEDS FOR SIMPLE MOBS WITHOUT DESTROYING EVERYTHING. Higher speed is slower, negative speed is faster
+ var/min_oxy = 5 // Oxygen in moles, minimum, 0 is 'no minimum
+ var/max_oxy = 0 // Oxygen in moles, maximum, 0 is 'no maximum'
+ var/min_tox = 0 // Phoron min
+ var/max_tox = 1 // Phoron max
+ var/min_co2 = 0 // CO2 min
+ var/max_co2 = 5 // CO2 max
+ var/min_n2 = 0 // N2 min
+ var/max_n2 = 0 // N2 max
+ var/unsuitable_atoms_damage = 2 // This damage is taken when atmos doesn't fit all the requirements above
- //LETTING SIMPLE ANIMALS ATTACK? WHAT COULD GO WRONG. Defaults to zero so Ian can still be cuddly
- var/melee_damage_lower = 0
- var/melee_damage_upper = 0
- var/attacktext = "attacked"
- var/attack_sound = null
- var/friendly = "nuzzles"
- var/environment_smash = 0
- var/resistance = 0 // Damage reduction
+ //Hostility settings
+ var/hostile = 0 // Do I even attack?
+ var/retaliate = 0 // I respond to damage against specific targets.
+ var/view_range = 7 // Scan for targets in this range.
+ var/specific_targets = 0 // Only use Found() targets, ignore others.
+ var/investigates = 0 // Do I investigate if I saw someone briefly?
+ var/attack_same = 0 // Do I attack members of my own faction?
+ var/cooperative = 0 // Do I ask allies to help me?
+ var/assist_distance = 25 // Radius in which I'll ask my comrades for help.
+ var/supernatural = 0 // If the mob is supernatural (used in null-rod stuff for banishing?)
+ var/grab_resist = 75 // Chance of me resisting a grab attempt.
- //Null rod stuff
- var/supernatural = 0
- var/purge = 0
+ //Attack ranged settings
+ var/ranged = 0 // Do I attack at range?
+ var/shoot_range = 7 // How far away do I start shooting from?
+ var/rapid = 0 // Three-round-burst fire mode
+ var/firing_lines = 0 // Avoids shooting allies
+ var/projectiletype // The projectiles I shoot
+ var/projectilesound // The sound I make when I do it
+ var/casingtype // What to make the hugely laggy casings pile out of
- //Pulling hostile mob vars down
- var/stance = STANCE_IDLE //Used to determine behavior
- var/mob/living/target_mob
- var/attack_same = 0
- var/ranged = 0
- var/rapid = 0
- var/projectiletype
- var/projectilesound
- var/casingtype
- var/move_to_delay = 4 //delay for the automated movement.
- var/list/friends = list()
- var/break_stuff_probability = 0
- var/destroy_surroundings = 0
- var/shuttletarget = null
- var/enroute = 0
- var/ai_inactive = 0 // Set to 1 to turn off most AI actions in Life()
+ //Mob melee settings
+ var/melee_damage_lower = 2 // Lower bound of randomized melee damage
+ var/melee_damage_upper = 6 // Upper bound of randomized melee damage
+ var/attacktext = "attacked" // "You are [attacktext] by the mob!"
+ var/friendly = "nuzzles" // What mobs do to people when they aren't really hostile
+ var/attack_sound = null // Sound to play when I attack
+ var/environment_smash = 0 // How much environment damage do I do when I hit stuff?
+ //Special attacks
+ var/spattack_prob = 0 // Chance of the mob doing a special attack (0 for never)
+ var/spattack_min_range = 0 // Min range to perform the special attacks from
+ var/spattack_max_range = 0 // Max range to perform special attacks from
+
+ //Attack movement settings
+ var/run_at_them = 1 // Don't use A* pathfinding, use walk_to
+ var/move_to_delay = 4 // Delay for the automated movement (deciseconds)
+ var/destroy_surroundings = 1 // Should I smash things to get to my target?
+
+ //Damage resistances
+ var/resistance = 0 // Damage reduction for all types
var/list/resistances = list(
HALLOSS = 0,
BRUTE = 1,
@@ -92,97 +127,217 @@
CLONE = 0
)
- var/hostile = 0
+ //Scary debug things
+ var/debug_ai = 0 // Logging level for this mob (1,2,3)
+ var/path_display = 0 // Will display the path in green when pathing
+ var/path_icon = 'icons/misc/debug_group.dmi' // What icon to use for the overlay
+ var/path_icon_state = "red" // What state to use for the overlay
+ var/icon/path_overlay // A reference to restart
+
+ ////// These are used for inter-proc communications so don't edit them manually //////
+ var/stance = STANCE_IDLE // Used to determine behavior
+ var/stop_automated_movement = 0 // Use this to temporarely stop random movement or to if you write special movement code for animals.
+ var/lifes_since_move = 0 // A counter for how many life() cycles since move
+ var/shuttletarget = null // Shuttle's here, time to get to it
+ var/enroute = 0 // If the shuttle is en-route
+ var/purge = 0 // A counter used for null-rod stuff
+ var/mob/living/target_mob // Who I'm trying to attack
+ var/mob/living/follow_mob // Who I'm recruited by
+ var/mob/living/list/friends = list() // People who are immune to my wrath, for now
+ var/mob/living/simple_animal/list/faction_friends = list() // Other simple mobs I am friends with
+ var/turf/list/walk_list = list()// List of turfs to walk through to get somewhere
+ var/astarpathing = 0 // Am I currently pathing to somewhere?
+ var/stance_changed = 0 // When our stance last changed (world.time)
+ var/last_target_time = 0 // When we last set our target, to prevent juggles
+ var/last_follow_time = 0 // When did we last get asked to follow someone?
+ var/last_helpask_time = 0 // When did we last call for help?
+ var/follow_until_time = 0 // Give up following when we reach this time (0 = never)
+ var/annoyed = 0 // Do people keep distract-kiting us?
+ ////// ////// //////
/mob/living/simple_animal/New()
..()
verbs -= /mob/verb/observe
+ home_turf = get_turf(src)
+ path_overlay = new(path_icon,path_icon_state)
+ move_to_delay = max(2,move_to_delay) //Protection against people coding things incorrectly and A* pathing 100% of the time
+ for(var/L in has_langs)
+ languages |= all_languages[L]
+ if(languages.len)
+ default_language = languages[1]
+
+ if(cooperative)
+ var/mob/living/simple_animal/first_friend
+ for(var/mob/living/simple_animal/M in living_mob_list)
+ if(M.faction == src.faction)
+ first_friend = M
+ break
+ if(first_friend)
+ faction_friends = first_friend.faction_friends
+ faction_friends |= src
+ else
+ faction_friends |= src
+
+/mob/living/simple_animal/Destroy()
+ home_turf = null
+ path_overlay = null
+ default_language = null
+ target_mob = null
+ follow_mob = null
+ if(myid)
+ qdel(myid)
+ myid = null
+
+ if(faction_friends.len) //This list is shared amongst the faction
+ faction_friends -= src
+
+ friends.Cut() //This one is not
+ walk_list.Cut()
+ languages.Cut()
+ ..()
+
+//Client attached
/mob/living/simple_animal/Login()
if(src && src.client)
src.client.screen = list()
src.client.screen += src.client.void
+ ai_inactive = 1
+ handle_stance(STANCE_IDLE)
+ src.client << "Mob AI disabled while you are controlling the mob."
..()
+//Client detatched
+/mob/living/simple_animal/Logout()
+ if(src && !src.client)
+ spawn(15 SECONDS) //15 seconds to get back into the mob before it goes wild
+ if(src && !src.client)
+ ai_inactive = initial(ai_inactive) //So if they never have an AI, they stay that way.
+ ..()
+
+//For debug purposes!
+/mob/living/simple_animal/proc/ai_log_output(var/msg = "missing message", var/ver = 1)
+ if(ver <= debug_ai)
+ log_debug("SA-AI: ([src]:[x],[y],[z])(@[world.time]): [msg] ")
+
+//Should we be dead?
/mob/living/simple_animal/updatehealth()
- return
+ //Alive, becoming dead
+ if((stat < DEAD) && (health <= 0))
+ death()
+
+ //Dead, becoming alive
+ else if((stat >= DEAD) && (health > 0))
+ dead_mob_list -= src
+ living_mob_list += src
+ stat = CONSCIOUS
+ density = 1
+
+ //Overhealth
+ else if(health > maxHealth)
+ health = maxHealth
+
+/mob/living/simple_animal/update_icon()
+ ..()
+ //Awake and normal
+ if((stat == CONSCIOUS) && (!icon_rest || !resting))
+ icon_state = icon_living
+
+ //Resting or KO'd
+ else if(((stat == UNCONSCIOUS) || resting) && icon_rest)
+ icon_state = icon_rest
+
+ //Dead
+ else if(stat >= DEAD)
+ icon_state = icon_dead
+
+ //Backup
+ else
+ icon_state = initial(icon_state)
/mob/living/simple_animal/Life()
..()
//Health
- if(stat == DEAD)
- if(health > 0)
- icon_state = icon_living
- dead_mob_list -= src
- living_mob_list += src
- stat = CONSCIOUS
- density = 1
- else
- walk(src, 0)
+ updatehealth()
+ if(stat >= DEAD)
return 0
-
- if(health <= 0)
- death()
- return
-
- if(health > maxHealth)
- health = maxHealth
-
handle_stunned()
handle_weakened()
handle_paralysed()
handle_supernatural()
+ handle_atmos() //Atmos
+ update_icon()
+ ai_log("Life() - stance=[stance] ai_inactive=[ai_inactive]", 4)
//Movement
- if(!client && !stop_automated_movement && wander && !anchored && !ai_inactive)
- if(isturf(src.loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc.
- turns_since_move++
- if(turns_since_move >= turns_per_move)
- if(!(stop_automated_movement_when_pulled && pulledby)) //Soma animals don't move when pulled
- var/moving_to = 0 // otherwise it always picks 4, fuck if I know. Did I mention fuck BYOND
- moving_to = pick(cardinal)
- dir = moving_to //How about we turn them the direction they are moving, yay.
- Move(get_step(src,moving_to))
- turns_since_move = 0
+ if(!ai_inactive && !stop_automated_movement && wander && !anchored) //Allowed to move?
+ handle_wander_movement()
//Speaking
- if(!client && speak_chance)
- if(rand(0,200) < speak_chance)
- if(speak && speak.len)
- if((emote_hear && emote_hear.len) || (emote_see && emote_see.len))
- var/length = speak.len
- if(emote_hear && emote_hear.len)
- length += emote_hear.len
- if(emote_see && emote_see.len)
- length += emote_see.len
- var/randomValue = rand(1,length)
- if(randomValue <= speak.len)
- say(pick(speak))
- else
- randomValue -= speak.len
- if(emote_see && randomValue <= emote_see.len)
- visible_emote("[pick(emote_see)].")
- else
- audible_emote("[pick(emote_hear)].")
+ if(!ai_inactive && speak_chance && stance == STANCE_IDLE) // Allowed to chatter?
+ handle_idle_speaking()
+
+ //Stanceyness
+ if(!ai_inactive)
+ handle_stance()
+
+ //Resisting out of things
+ if(!ai_inactive && incapacitated(INCAPACITATION_DEFAULT) && stance != STANCE_IDLE)
+ resist()
+
+ return 1
+
+// Peforms the random walk wandering
+/mob/living/simple_animal/proc/handle_wander_movement()
+ if(isturf(src.loc) && !resting && !buckled && canmove) //Physically capable of moving?
+ lifes_since_move++ //Increment turns since move (turns are life() cycles)
+ if(lifes_since_move >= turns_per_move)
+ if(!(stop_when_pulled && pulledby)) //Some animals don't move when pulled
+ var/moving_to = 0 // otherwise it always picks 4, fuck if I know. Did I mention fuck BYOND
+ moving_to = pick(cardinal)
+ dir = moving_to //How about we turn them the direction they are moving, yay.
+ Move(get_step(src,moving_to))
+ lifes_since_move = 0
+
+// Handles random chatter, called from Life() when stance = STANCE_IDLE
+/mob/living/simple_animal/proc/handle_idle_speaking()
+ if(rand(0,200) < speak_chance)
+ if(speak && speak.len)
+ if((emote_hear && emote_hear.len) || (emote_see && emote_see.len))
+ var/length = speak.len
+ if(emote_hear && emote_hear.len)
+ length += emote_hear.len
+ if(emote_see && emote_see.len)
+ length += emote_see.len
+ var/randomValue = rand(1,length)
+ if(randomValue <= speak.len)
+ try_say_list(speak)
else
- say(pick(speak))
- else
- if(!(emote_hear && emote_hear.len) && (emote_see && emote_see.len))
- visible_emote("[pick(emote_see)].")
- if((emote_hear && emote_hear.len) && !(emote_see && emote_see.len))
- audible_emote("[pick(emote_hear)].")
- if((emote_hear && emote_hear.len) && (emote_see && emote_see.len))
- var/length = emote_hear.len + emote_see.len
- var/pick = rand(1,length)
- if(pick <= emote_see.len)
+ randomValue -= speak.len
+ if(emote_see && randomValue <= emote_see.len)
visible_emote("[pick(emote_see)].")
else
audible_emote("[pick(emote_hear)].")
+ else
+ try_say_list(speak)
+ else
+ if(!(emote_hear && emote_hear.len) && (emote_see && emote_see.len))
+ visible_emote("[pick(emote_see)].")
+ if((emote_hear && emote_hear.len) && !(emote_see && emote_see.len))
+ audible_emote("[pick(emote_hear)].")
+ if((emote_hear && emote_hear.len) && (emote_see && emote_see.len))
+ var/length = emote_hear.len + emote_see.len
+ var/pick = rand(1,length)
+ if(pick <= emote_see.len)
+ visible_emote("[pick(emote_see)].")
+ else
+ audible_emote("[pick(emote_hear)].")
-
- //Atmos
+// Handle interacting with and taking damage from atmos
+// TODO - Refactor this to use handle_environment() like a good /mob/living
+/mob/living/simple_animal/proc/handle_atmos()
var/atmos_suitable = 1
var/atom/A = src.loc
@@ -235,23 +390,55 @@
if(!atmos_suitable)
adjustBruteLoss(unsuitable_atoms_damage)
- //Hostility
- if(!stat && !client && hostile && !ai_inactive)
- switch(stance)
- if(STANCE_IDLE)
- target_mob = FindTarget()
+// For setting the stance WITHOUT processing it
+/mob/living/simple_animal/proc/set_stance(var/new_stance)
+ stance = new_stance
+ stance_changed = world.time
+ ai_log("set_stance() changing to [new_stance]",2)
- if(STANCE_ATTACK)
- if(destroy_surroundings)
- DestroySurroundings()
- MoveToTarget()
+// For proccessing the current stance, or setting and processing a new one
+/mob/living/simple_animal/proc/handle_stance(var/new_stance)
+ if(ai_inactive)
+ stance = STANCE_IDLE
+ return
- if(STANCE_ATTACKING)
- if(destroy_surroundings)
- DestroySurroundings()
- AttackTarget()
+ if(new_stance)
+ set_stance(new_stance)
- return 1
+ switch(stance)
+ if(STANCE_IDLE)
+ target_mob = null
+ a_intent = I_HELP
+ annoyed = max(0,annoyed--)
+
+ //Yes I'm breaking this into two if()'s for ease of reading
+ //If we ARE ALLOWED TO
+ if(returns_home && home_turf && !astarpathing && (world.time - stance_changed) > 10 SECONDS)
+ if(get_dist(src,home_turf) > wander_distance)
+ move_to_delay = initial(move_to_delay)*2 //Walk back.
+ GoHome()
+ else
+ stop_automated_movement = 0
+
+ //Search for targets while idle
+ if(hostile)
+ FindTarget()
+ if(STANCE_FOLLOW)
+ annoyed = 15
+ FollowTarget()
+ if(follow_until_time && world.time > follow_until_time)
+ LoseFollow()
+ return
+ if(hostile)
+ FindTarget()
+ if(STANCE_ATTACK)
+ annoyed = 50
+ a_intent = I_HURT
+ RequestHelp()
+ MoveToTarget()
+ if(STANCE_ATTACKING)
+ annoyed = 50
+ AttackTarget()
/mob/living/simple_animal/proc/handle_supernatural()
if(purge)
@@ -271,12 +458,22 @@
custom_emote(2, act_desc)
/mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj)
- if(!Proj || Proj.nodamage)
+ if(!Proj)
return
+ ai_log("bullet_act() I was shot by: [Proj.firer]",2)
+
+ if(Proj.taser_effect)
+ stun_effect_act(0, Proj.agony)
+
+ if(!Proj.nodamage)
+ adjustBruteLoss(Proj.damage)
+
+ if(Proj.firer)
+ react_to_attack(Proj.firer)
- adjustBruteLoss(Proj.damage)
return 0
+// When someone clicks us with an empty hand
/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M as mob)
..()
@@ -284,10 +481,10 @@
if(I_HELP)
if (health > 0)
- M.visible_message("\blue [M] [response_help] \the [src]")
+ M.visible_message("[M] [response_help] \the [src].")
if(I_DISARM)
- M.visible_message("\blue [M] [response_disarm] \the [src]")
+ M.visible_message("[M] [response_disarm] \the [src].")
M.do_attack_animation(src)
//TODO: Push the mob away or something
@@ -296,6 +493,9 @@
return
if (!(status_flags & CANPUSH))
return
+ if(!incapacitated(INCAPACITATION_ALL) && (stance != STANCE_IDLE) && prob(grab_resist))
+ M.visible_message("[M] tries to grab [src] but fails!")
+ return
var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src)
@@ -305,16 +505,21 @@
G.affecting = src
LAssailant = M
- M.visible_message("\red [M] has grabbed [src] passively!")
+ M.visible_message("[M] has grabbed [src] passively!")
M.do_attack_animation(src)
+ ai_log("attack_hand() I was grabbed by: [M]",2)
+ react_to_attack(M)
if(I_HURT)
adjustBruteLoss(harm_intent_damage)
- M.visible_message("\red [M] [response_harm] \the [src]")
+ M.visible_message("[M] [response_harm] \the [src]!")
M.do_attack_animation(src)
+ ai_log("attack_hand() I was hit by: [M]",2)
+ react_to_attack(M)
return
+// When somoene clicks us with an item in hand
/mob/living/simple_animal/attackby(var/obj/item/O, var/mob/user)
if(istype(O, /obj/item/stack/medical))
if(stat != DEAD)
@@ -338,9 +543,10 @@
visible_message("[user] gently taps [src] with \the [O].")
else
O.attack(src, user, user.zone_sel.selecting)
+ ai_log("attackby() I was weapon'd by: [user]",2)
+ react_to_attack(user)
/mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone)
-
visible_message("\The [src] has been attacked with \the [O] by [user].")
if(O.force <= resistance)
@@ -354,9 +560,23 @@
damage *= 2
purge = 3
adjustBruteLoss(damage)
+ ai_log("hit_with_weapon() I was h_w_weapon'd by: [user]",2)
+ react_to_attack(user)
return 0
+// When someone throws something at us
+/mob/living/simple_animal/hitby(atom/movable/AM)
+ ..()
+ if(AM.thrower)
+ react_to_attack(AM.thrower)
+
+//SA vs SA basically
+/mob/living/simple_animal/attack_generic(var/mob/attacker)
+ ..()
+ if(attacker)
+ react_to_attack(attacker)
+
/mob/living/simple_animal/movement_delay()
var/tally = 0 //Incase I need to add stuff other than "speed" later
@@ -374,9 +594,28 @@
if(statpanel("Status") && show_stat_health)
stat(null, "Health: [round((health / maxHealth) * 100)]%")
+/mob/living/simple_animal/lay_down()
+ ..()
+ if(resting && icon_rest)
+ icon_state = icon_rest
+ else
+ icon_state = icon_living
+
/mob/living/simple_animal/death(gibbed, deathmessage = "dies!")
- icon_state = icon_dead
- density = 0
+ density = 0 //We don't block even if we did before
+ walk(src, 0) //We stop any background-processing walks
+
+ if(faction_friends.len)
+ faction_friends -= src
+
+ if(loot_list.len) //Drop any loot
+ for(var/path in loot_list)
+ if(prob(loot_list[path]))
+ new path(get_turf(src))
+
+ spawn(3) //We'll update our icon in a sec
+ update_icon()
+
return ..(gibbed,deathmessage)
/mob/living/simple_animal/ex_act(severity)
@@ -401,18 +640,21 @@
/mob/living/simple_animal/adjustFireLoss(damage)
health = Clamp(health - damage, 0, maxHealth)
+// Check target_mob if worthy of attack (i.e. check if they are dead or empty mecha)
/mob/living/simple_animal/proc/SA_attackable(target_mob)
+ ai_log("SA_attackable([target_mob])",3)
if (isliving(target_mob))
var/mob/living/L = target_mob
- if(!L.stat && L.health >= 0)
- return (0)
+ if(!L.stat)
+ return 1
if (istype(target_mob,/obj/mecha))
var/obj/mecha/M = target_mob
if (M.occupant)
- return (0)
- return 1
+ return 1
+ ai_log("SA_attackable([target_mob]): no",3)
+ return 0
-/mob/living/simple_animal/say(var/message)
+/mob/living/simple_animal/say(var/message,var/datum/language/language)
var/verb = "says"
if(speak_emote.len)
verb = pick(speak_emote)
@@ -425,7 +667,7 @@
return verb
/mob/living/simple_animal/put_in_hands(var/obj/item/W) // No hands.
- W.loc = get_turf(src)
+ W.forceMove(get_turf(src))
return 1
// Harvest an animal's delicious byproducts
@@ -453,12 +695,58 @@
/mob/living/simple_animal/ExtinguishMob()
return
- //Hostile procs moved down
-/mob/living/simple_animal/proc/FindTarget()
+//We got hit! Consider hitting them back!
+/mob/living/simple_animal/proc/react_to_attack(var/mob/living/M)
+ if(stat || M == target_mob) return //Not if we're dead or already hitting them
+ if(M in friends || M.faction == faction) return //I'll overlook it THIS time...
+ ai_log("react_to_attack([M])",1)
+ if(retaliate && set_target(M))
+ handle_stance(STANCE_ATTACK)
+ return M
+ return 0
+
+/mob/living/simple_animal/proc/set_target(var/mob/M)
+ ai_log("SetTarget([M])",2)
+ if(!M || (world.time - last_target_time < 5 SECONDS) && target_mob)
+ ai_log("SetTarget() can't set it again so soon",3)
+ return 0
+
+ var/turf/seen = get_turf(M)
+
+ if(investigates && (annoyed < 10))
+ try_say_list(say_maybe_target)
+ face_atom(seen)
+ annoyed += 14
+ sleep(1 SECOND) //For realism
+
+ if(M in ListTargets(view_range))
+ try_say_list(say_got_target)
+ target_mob = M
+ last_target_time = world.time
+ return M
+ else if(investigates)
+ spawn(1)
+ WanderTowards(seen)
+
+ return 0
+
+// Set a follow target, with optional time for how long to follow them.
+/mob/living/simple_animal/proc/set_follow(var/mob/M, var/follow_for = 0)
+ ai_log("SetFollow([M]) for=[follow_for]",2)
+ if(!M || (world.time - last_target_time < 4 SECONDS) && follow_mob)
+ ai_log("SetFollow() can't set it again so soon",3)
+ return 0
+
+ follow_mob = M
+ last_follow_time = world.time
+ follow_until_time = !follow_for ? 0 : world.time + follow_for
+ return 1
+
+//Scan surroundings for a valid target
+/mob/living/simple_animal/proc/FindTarget()
var/atom/T = null
- stop_automated_movement = 0
- for(var/atom/A in ListTargets(10))
+ for(var/atom/A in ListTargets(view_range))
if(A == src)
continue
@@ -467,6 +755,8 @@
if(F)
T = F
break
+ else if(specific_targets)
+ return 0
if(isliving(A))
var/mob/living/L = A
@@ -474,52 +764,342 @@
continue
else if(L in friends)
continue
+ else if(!SA_attackable(L))
+ continue
else
- if(!L.stat)
- stance = STANCE_ATTACK
- T = L
- break
+ T = L
+ break
else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets().
var/obj/mecha/M = A
- if (M.occupant)
- stance = STANCE_ATTACK
+ if(!SA_attackable(M))
+ continue
+ if((M.occupant.faction != src.faction) || attack_same)
T = M
break
+
+ //You found one!
+ if(T)
+ ai_log("FindTarget() found [T]!",1)
+ if(set_target(T))
+ handle_stance(STANCE_ATTACK)
+
return T
-
+//Used for special targeting or reactions
/mob/living/simple_animal/proc/Found(var/atom/A)
return
+//Requesting help from like-minded individuals
+/mob/living/simple_animal/proc/RequestHelp()
+ if(!cooperative || ((world.time - last_helpask_time) < 10 SECONDS))
+ return
+
+ ai_log("RequestHelp() to [faction_friends.len] friends",2)
+ last_helpask_time = world.time
+ for(var/mob/living/simple_animal/F in faction_friends)
+ if(F == src) continue
+ if(get_dist(src,F) <= F.assist_distance)
+ spawn(0)
+ if(F) //They could have died by now and some mobs delete themselves on death
+ ai_log("RequestHelp() to [F]",3)
+ F.HelpRequested(src)
+
+//Someone wants help?
+/mob/living/simple_animal/proc/HelpRequested(var/mob/living/simple_animal/F)
+ if(!(stance == STANCE_IDLE) || stat)
+ ai_log("HelpRequested() by [F] but we're busy/dead",2)
+ return
+ if(get_dist(src,F) <= follow_dist)
+ ai_log("HelpRequested() by [F] but we're already here",2)
+ return
+
+ if(set_follow(F, 10 SECONDS))
+ handle_stance(STANCE_FOLLOW)
+
+//Move to a target (or near if we're ranged)
/mob/living/simple_animal/proc/MoveToTarget()
- stop_automated_movement = 1
- if(!target_mob || SA_attackable(target_mob))
- stance = STANCE_IDLE
- if(target_mob in ListTargets(10))
- if(ranged)
- if(get_dist(src, target_mob) <= 6)
- OpenFire(target_mob)
- else
- walk_to(src, target_mob, 1, move_to_delay)
- else
- stance = STANCE_ATTACKING
- walk_to(src, target_mob, 1, move_to_delay)
+ if(incapacitated(INCAPACITATION_DISABLED))
+ ai_log("MoveToTarget() Bailing because we're disabled",2)
+ return
-/mob/living/simple_animal/proc/AttackTarget()
-
- stop_automated_movement = 1
- if(!target_mob || SA_attackable(target_mob))
+ //If we were chasing someone and we can't anymore, give up.
+ if(!target_mob || !SA_attackable(target_mob))
+ ai_log("MoveToTarget() Losing target at top",2)
LoseTarget()
+ return
+
+ //Don't wander
+ stop_automated_movement = 1
+ move_to_delay = initial(move_to_delay)
+
+ //We recompute our path every time we're called if we can still see them
+ if(target_mob in ListTargets(view_range))
+
+ //Recompute the path if we were using one since we can still see them.
+ if(astarpathing)
+ ForgetPath()
+
+ //Find out where we're getting to
+ var/get_to = ranged ? shoot_range-1 : 1 //Shoot range -1 just because we don't want to constantly get kited
+ var/distance = get_dist(src,target_mob)
+ ai_log("MoveToTarget() [src] [get_to] [distance]",2)
+
+ //We're here!
+ if(distance <= get_to)
+ ai_log("MoveToTarget() [src] attack range",2)
+ handle_stance(STANCE_ATTACKING)
+ return
+
+ //We're just setting out, making a new path, or we can't path with A*
+ if(!walk_list.len)
+ ai_log("SA: MoveToTarget() pathing to [target_mob]",2)
+
+ //GetPath failed for whatever reason, just smash into things towards them
+ if(run_at_them || !GetPath(get_turf(target_mob),get_to))
+
+ //We try the built-in way to stay close
+ walk_to(src, target_mob, get_to, move_to_delay)
+ ai_log("MoveToTarget() walk_to([src],[target_mob],[get_to],[move_to_delay])",3)
+
+ //Break shit in their direction! LEME SMAHSH
+ var/dir_to_mob = get_dir(src,target_mob)
+ face_atom(target_mob)
+ DestroySurroundings(dir_to_mob)
+ ai_log("MoveToTarget() DestroySurroundings([get_dir(src,target_mob)])",3)
+
+ //We have a path! We aren't already pathing it!
+ if(!astarpathing && walk_list.len)
+ ai_log("MoveToTarget() going to start a path",2)
+ spawn(1)
+
+ //Do the path!
+ var/result = WalkPath(target_thing = target_mob, target_dist = get_to)
+ ai_log("MoveToTarget() WalkPath r:[result]",2)
+
+ //WalkPath failed, either interrupted for recalc, or something else
+ if(!result)
+ return
+
+ //WalkPath either got close enough or we ran out of path
+ else
+ spawn(1)
+ ai_log("MoveToTarget() resetting",2)
+ MoveToTarget()
+
+ //We can't see them, and we don't have a path we're trying to follow to find them
+ else if(!astarpathing)
+ ai_log("MoveToTarget() Losing target at bottom",2)
+ LoseTarget() //Just forget it.
+
+//Follow a target (and don't attempt to murder it horribly)
+/mob/living/simple_animal/proc/FollowTarget()
+ ai_log("FollowTarget() [follow_mob]",1)
+ //If we were chasing someone and we can't anymore, give up.
+ if(!follow_mob || follow_mob.stat)
+ ai_log("FollowTarget() Losing follow at top",2)
+ LoseFollow()
+ return
+
+ if(incapacitated(INCAPACITATION_DISABLED))
+ ai_log("FollowTarget() Bailing because we're disabled",2)
+ return
+
+ if((get_dist(src,follow_mob) <= follow_dist))
+ ai_log("FollowTarget() Already at target",2)
+ return
+
+ move_to_delay = initial(move_to_delay)
+ var/start_distance = get_dist(src,follow_mob)
+
+ //Bad pathing
+ if(run_at_them)
+ walk_to(src, follow_mob, follow_dist, move_to_delay)
+ ai_log("FollowTarget() walk_to([src],[target_mob],2,[move_to_delay])",3)
+ spawn(3 SECONDS)
+ if(src && follow_mob && (stance == STANCE_FOLLOW) && (get_dist(src,follow_mob) >= start_distance))
+ ai_log("FollowTarget() walk_to not making headway, giving up",3)
+ LoseFollow()
+
+ //Good pathing
+ else
+ GetPath(get_turf(follow_mob),follow_dist)
+ if(!astarpathing && walk_list.len)
+ spawn(1)
+ ai_log("FollowTarget() A* path getting underway",2)
+ //Do the path!
+ var/result = WalkPath(target_thing = follow_mob, target_dist = follow_dist)
+ ai_log("FollowTarget() WalkPath r:[result]",3)
+
+ else
+ ai_log("FollowTarget() GetPath can't path, giving up",3)
+ LoseFollow()
+
+//Just try one time to go look at something. Don't really focus much on it.
+/mob/living/simple_animal/proc/WanderTowards(var/turf/T)
+ if(!T) return
+ ai_log("WanderTowards() [T.x],[T.y]",1)
+
+ stop_automated_movement = 1
+ GetPath(T,1)
+
+ if(run_at_them || !walk_list.len)
+ ai_log("WanderTowards() walk_to getting underway",2)
+ walk_to(src, T, 1, move_to_delay)
+ else
+ if(!astarpathing)
+ spawn(1)
+ ai_log("WanderTowards() A* path getting underway",2)
+ WalkPath(target_thing = T, target_dist = 1)
+
+//A* now, try to a path to a target
+/mob/living/simple_animal/proc/GetPath(var/turf/target,var/get_to = 1,var/max_distance = world.view*6)
+ ai_log("GetPath([target],[get_to],[max_distance])",2)
+ ForgetPath()
+ var/list/new_path = AStar(get_turf(loc), target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, min_target_dist = get_to, max_node_depth = max_distance, id = myid, exclude = obstacles)
+
+ if(new_path && new_path.len)
+ walk_list = new_path
+ if(path_display)
+ for(var/turf/T in walk_list)
+ T.overlays |= path_overlay
+ else
return 0
- if(!(target_mob in ListTargets(10)))
- LostTarget()
+
+ return walk_list.len
+
+//Walk along our A* path, target_thing allows us to stop early if we're nearby
+/mob/living/simple_animal/proc/WalkPath(var/atom/target_thing, var/target_dist = 1, var/proc/steps_callback = null, var/every_steps = 4)
+ ai_log("WalkPath() (steps:[walk_list.len])",2)
+ if(!walk_list || !walk_list.len)
+ return
+
+ astarpathing = 1
+ var/step_count = 0
+ var/failed_steps = 0
+ while(1)
+ //We're supposed to stop
+ if(!astarpathing || incapacitated(INCAPACITATION_DISABLED))
+ astarpathing = 0
+ ai_log("WalkPath() was interrupted",2)
+ return 0
+ //Finished the path
+ if(!walk_list.len)
+ astarpathing = 0
+ ai_log("WalkPath() exited naturally",2)
+ return 1
+ if(failed_steps >= 3)
+ astarpathing = 0
+ ai_log("WalkPath() failed too many steps",2)
+ return 0
+
+ //Take a step
+ if(!MoveOnce())
+ ai_log("WalkPath() failed a step",3)
+ failed_steps++
+ else
+ ai_log("WalkPath() took a step",3)
+ failed_steps = 0
+ step_count++
+
+ //If we have a particular target we care about, look for them
+ if(target_thing && (get_dist(src,target_thing) <= target_dist))
+ ai_log("WalkPath() returning due to proximity",2)
+ return target_thing
+
+ //If we have a callback
+ if(steps_callback && (step_count >= every_steps))
+ ai_log("WalkPath() doing callback",3)
+ call(steps_callback)()
+
+ //And wait for the time to our next step
+ sleep(move_to_delay)
+
+//Take one step along a path
+/mob/living/simple_animal/proc/MoveOnce()
+ if(!walk_list.len)
+ return
+
+ if(path_display)
+ var/turf/T = src.walk_list[1]
+ T.overlays -= path_overlay
+
+ step_towards(src, src.walk_list[1])
+ if(src.loc != src.walk_list[1])
+ ai_log("MoveOnce() step_towards returning 0",3)
return 0
- if(get_dist(src, target_mob) <= 1) //Attacking
- AttackingTarget()
+ else
+ walk_list -= src.walk_list[1]
+ ai_log("MoveOnce() step_towards returning 1",3)
return 1
-/mob/living/simple_animal/proc/AttackingTarget()
+//Forget the path entirely
+/mob/living/simple_animal/proc/ForgetPath()
+ ai_log("ForgetPath()",2)
+ if(path_display)
+ for(var/turf/T in walk_list)
+ T.overlays -= path_overlay
+ astarpathing = 0
+ walk_list.Cut()
+
+//Giving up on moving
+/mob/living/simple_animal/proc/GiveUpMoving()
+ ai_log("GiveUpMoving()",1)
+ ForgetPath()
+ walk(src, 0)
+ stop_automated_movement = 0
+
+//Return home, all-in-one proc (though does target scan and drop out if they see one)
+/mob/living/simple_animal/proc/GoHome()
+ if(!home_turf) return
+ if(astarpathing) ForgetPath()
+ ai_log("GoHome()",1)
+ var/close_enough = 2
+ var/look_in = 250
+ if(GetPath(home_turf,close_enough,look_in))
+ stop_automated_movement = 1
+ spawn(1)
+ if(WalkPath()) //If we made it without interruption
+ ai_log("GoHome() got home",2)
+ GiveUpMoving() //Go back to wandering
+
+//Get into attack mode on a target
+/mob/living/simple_animal/proc/AttackTarget()
+ stop_automated_movement = 1
+ if(!target_mob || !SA_attackable(target_mob))
+ LoseTarget()
+ return 0
+ if(!(target_mob in ListTargets(view_range)))
+ LostTarget()
+ return 0
+
+ ai_log("AttackTarget() vs. [target_mob]",1)
+ var/distance = get_dist(src, target_mob)
+ face_atom(target_mob)
+
+ //Hadoooooken!
+ if(prob(spattack_prob) && (distance >= spattack_min_range) && (distance <= spattack_max_range))
+ ai_log("AttackTarget() special",3)
+ if(SpecialAtkTarget()) //Might not succeed/be allowed, do something else.
+ return 1
+ //AAAAH!
+ if(distance <= 1)
+ ai_log("AttackTarget() melee",3)
+ PunchTarget()
+ return 1
+ //Open fire!
+ else if(ranged && (distance <= shoot_range))
+ ai_log("AttackTarget() ranged",3)
+ ShootTarget(target_mob)
+ return 1
+ //They ran away!
+ else
+ ai_log("AttackTarget() out of range!",3)
+ handle_stance(STANCE_ATTACK)
+ return 0
+
+//Attack the target in melee
+/mob/living/simple_animal/proc/PunchTarget()
if(!Adjacent(target_mob))
return
if(isliving(target_mob))
@@ -531,30 +1111,17 @@
M.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
return M
-/mob/living/simple_animal/proc/LoseTarget()
- stance = STANCE_IDLE
- target_mob = null
- walk(src, 0)
-
-/mob/living/simple_animal/proc/LostTarget()
- stance = STANCE_IDLE
- walk(src, 0)
-
-
-/mob/living/simple_animal/proc/ListTargets(var/dist = 7)
- var/list/L = hearers(src, dist)
-
- for (var/obj/mecha/M in mechas_list)
- if (M.z == src.z && get_dist(src, M) <= dist)
- L += M
-
- return L
-
-/mob/living/simple_animal/proc/OpenFire(target_mob)
+//The actual top-level ranged attack proc
+/mob/living/simple_animal/proc/ShootTarget()
var/target = target_mob
- visible_message("\red [src] fires at [target]!", 1)
-
var/tturf = get_turf(target)
+
+ if(firing_lines && !CheckFiringLine(tturf))
+ step_rand(src)
+ face_atom(tturf)
+ return 0
+
+ visible_message("[src] fires at [target]!", 1)
if(rapid)
spawn(1)
Shoot(tturf, src.loc, src)
@@ -573,11 +1140,34 @@
if(casingtype)
new casingtype
- stance = STANCE_IDLE
- target_mob = null
- return
+ return 1
+//Check firing lines for faction_friends (if we're not cooperative, we don't care)
+/mob/living/simple_animal/proc/CheckFiringLine(var/turf/tturf)
+ if(!tturf) return
+ var/turf/list/crosses = list()
+ var/this_turf = get_turf(src)
+
+ while(this_turf != tturf)
+ this_turf = get_step(this_turf,get_dir(this_turf,tturf))
+ crosses += this_turf
+
+ for(var/mob/living/FF in faction_friends)
+ if(FF.loc in crosses)
+ return 0
+
+ for(var/mob/living/F in friends)
+ if(F.loc in crosses)
+ return 0
+
+ return 1
+
+//Special attacks, like grenades or blinding spit or whatever
+/mob/living/simple_animal/proc/SpecialAtkTarget()
+ return 0
+
+//Shoot a bullet at someone
/mob/living/simple_animal/proc/Shoot(var/target, var/start, var/user, var/bullet = 0)
if(target == start)
return
@@ -592,18 +1182,62 @@
A.launch(target)
return
-/mob/living/simple_animal/proc/DestroySurroundings()
- if(prob(break_stuff_probability))
- for(var/dir in cardinal) // North, South, East, West
- for(var/obj/structure/window/obstacle in get_step(src, dir))
- if(obstacle.dir == reverse_dir[dir]) // So that windows get smashed in the right order
- obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
- return
- var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir))
- if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille))
- obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
+//We can't see the target
+/mob/living/simple_animal/proc/LoseTarget()
+ ai_log("LoseTarget() [target_mob]",2)
+ target_mob = null
+ handle_stance(STANCE_IDLE)
+ GiveUpMoving()
+//Target is no longer valid (?)
+/mob/living/simple_animal/proc/LostTarget()
+ handle_stance(STANCE_IDLE)
+ GiveUpMoving()
+//Forget a follow mode
+/mob/living/simple_animal/proc/LoseFollow()
+ ai_log("LoseFollow() [target_mob]",2)
+ follow_mob = null
+ handle_stance(STANCE_IDLE)
+ GiveUpMoving()
+
+//Find me some targets
+/mob/living/simple_animal/proc/ListTargets(var/dist = view_range)
+ var/list/L = hearers(src, dist)
+
+ for(var/obj/mecha/M in mechas_list)
+ if ((M.z == src.z) && (get_dist(src, M) <= dist) && (isInSight(src,M)))
+ L += M
+
+ return L
+
+//Break through windows/other things
+/mob/living/simple_animal/proc/DestroySurroundings(var/direction)
+ if(!direction)
+ direction = pick(cardinal) //FLAIL WILDLY
+
+ var/turf/problem_turf = get_step(src, direction)
+
+ ai_log("DestroySurroundings([direction])",3)
+ for(var/obj/structure/window/obstacle in problem_turf)
+ if(obstacle.dir == reverse_dir[dir]) // So that windows get smashed in the right order
+ ai_log("DestroySurroundings() directional window hit",3)
+ obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
+ return
+
+ var/obj/structure/obstacle = locate(/obj/structure, problem_turf)
+ if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille))
+ ai_log("DestroySurroundings() generic structure hit [obstacle]",3)
+ obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
+ return
+
+ for(var/obj/machinery/door/baddoor in problem_turf) //Required since firelocks take up the same turf
+ if(baddoor.density)
+ ai_log("DestroySurroundings() door hit [baddoor]",3)
+ baddoor.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext)
+ return
+
+//Check for shuttle bumrush
/mob/living/simple_animal/proc/check_horde()
return 0
if(emergency_shuttle.shuttle.location)
@@ -620,6 +1254,7 @@
enroute = 0
stop_automated_movement = 0
+//Shuttle bumrush
/mob/living/simple_animal/proc/horde()
var/turf/T = get_step_to(src, shuttletarget)
for(var/atom/A in T)
@@ -641,6 +1276,7 @@
if(!src.stat)
horde()
+//Touches a wire, etc
/mob/living/simple_animal/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null)
shock_damage *= siemens_coeff
if (shock_damage < 1)
@@ -651,4 +1287,39 @@
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(5, 1, loc)
- s.start()
\ No newline at end of file
+ s.start()
+
+//Shot with taser/stunvolver
+/mob/living/simple_animal/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null)
+ var/stunDam = 0
+ var/agonyDam = 0
+
+ if(stun_amount)
+ stunDam += stun_amount * 0.5
+ adjustFireLoss(stunDam)
+
+ if(agony_amount)
+ agonyDam += agony_amount * 0.5
+ adjustFireLoss(agonyDam)
+
+//Commands, reactions, etc
+/mob/living/simple_animal/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
+ ..()
+ if(reacts && speaker && (message in reactions) && (!hostile || isliving(speaker)) && say_understands(speaker,language))
+ var/mob/living/L = speaker
+ if(L.faction == faction)
+ spawn(10)
+ face_atom(speaker)
+ say(reactions[message])
+
+//Just some subpaths for easy searching
+/mob/living/simple_animal/hostile
+ faction = "not yours"
+ hostile = 1
+ retaliate = 1
+ stop_when_pulled = 0
+ destroy_surroundings = 1
+
+/mob/living/simple_animal/retaliate
+ retaliate = 1
+ destroy_surroundings = 1
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 6ed5f6df056..f27a73f4040 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -341,7 +341,7 @@
if ((stat != 2 || !( ticker )))
usr << "You must be dead to use this!"
return
- if (ticker.mode.deny_respawn) //BS12 EDIT
+ if (ticker.mode && ticker.mode.deny_respawn) //BS12 EDIT
usr << "Respawn is disabled for this roundtype."
return
else
@@ -706,12 +706,13 @@
/mob/proc/facedir(var/ndir)
- if(!canface() || client.moving || world.time < client.move_delay)
+ if(!canface() || (client && (client.moving || (world.time < client.move_delay))))
return 0
set_dir(ndir)
if(buckled && buckled.buckle_movable)
buckled.set_dir(ndir)
- client.move_delay += movement_delay()
+ if(client)
+ client.move_delay += movement_delay()
return 1
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 2f788862f82..4327840a478 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -535,7 +535,7 @@ proc/is_blind(A)
if(. == SAFE_PERP)
return SAFE_PERP
- if(!istype(src, /mob/living/simple_animal/hostile/retaliate/goat))
+ if(!istype(src, /mob/living/simple_animal/retaliate/goat))
threatcount += 4
return threatcount
diff --git a/code/modules/mob/new_player/login.dm b/code/modules/mob/new_player/login.dm
index 6332b63d5a1..ff698675486 100644
--- a/code/modules/mob/new_player/login.dm
+++ b/code/modules/mob/new_player/login.dm
@@ -5,13 +5,20 @@ var/obj/effect/lobby_image = new /obj/effect/lobby_image
/obj/effect/lobby_image
name = "Polaris"
desc = "How are you reading this?"
- icon = 'icons/misc/title.dmi'
- icon_state = null //determined randomly later on.
screen_loc = "1,1"
- var/list/lobby_images = list("mockingjay00")
-/obj/effect/lobby_image/New()
- icon_state = pick(lobby_images)
+/obj/effect/lobby_image/initialize()
+ icon = using_map.lobby_icon
+ var/known_icon_states = icon_states(icon)
+ for(var/lobby_screen in using_map.lobby_screens)
+ if(!(lobby_screen in known_icon_states))
+ error("Lobby screen '[lobby_screen]' did not exist in the icon set [icon].")
+ using_map.lobby_screens -= lobby_screen
+
+ if(using_map.lobby_screens.len)
+ icon_state = pick(using_map.lobby_screens)
+ else
+ icon_state = known_icon_states[1]
/mob/new_player
var/client/my_client // Need to keep track of this ourselves, since by the time Logout() is called the client has already been nulled
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 066fd5b0a44..c052a76d3e5 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -335,7 +335,6 @@
var/mob/living/character = create_character() //creates the human and transfers vars and mind
character = job_master.EquipRank(character, rank, 1) //equips the human
UpdateFactionList(character)
- equip_custom_items(character)
// AIs don't need a spawnpoint, they must spawn at an empty core
if(character.mind.assigned_role == "AI")
@@ -357,6 +356,8 @@
//Find our spawning point.
var/join_message = job_master.LateSpawn(character, rank)
+ // Equip our custom items only AFTER deploying to spawn points eh?
+ equip_custom_items(character)
character.lastarea = get_area(loc)
// Moving wheelchair if they have one
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index f7aaa52f78b..0a029cf3166 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -44,6 +44,8 @@
usr << "You have deadchat muted."
return
+ message = say_emphasis(message)
+
say_dead_direct("[pick("complains","moans","whines","laments","blubbers")], \"[message]\"", src)
/mob/proc/say_understands(var/mob/other,var/datum/language/speaking = null)
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index ca8d1bffe1a..ccf46782163 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -67,7 +67,7 @@
/mob/proc/AIize(move=1)
if(client)
src << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) // stop the jams for AIs
- var/mob/living/silicon/ai/O = new (loc, base_law_type,,1)//No MMI but safety is in effect.
+ var/mob/living/silicon/ai/O = new (loc, using_map.default_law_type,,1)//No MMI but safety is in effect.
O.invisibility = 0
O.aiRestorePowerRoutine = 0
@@ -304,7 +304,7 @@
return 1
if(ispath(MP, /mob/living/simple_animal/shade))
return 1
- if(ispath(MP, /mob/living/simple_animal/tomato))
+ if(ispath(MP, /mob/living/simple_animal/hostile/tomato))
return 1
if(ispath(MP, /mob/living/simple_animal/mouse))
return 1 //It is impossible to pull up the player panel for mice (Fixed! - Nodrak)
diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm
index dd0a93fec11..586b6242602 100644
--- a/code/modules/multiz/movement.dm
+++ b/code/modules/multiz/movement.dm
@@ -1,51 +1,194 @@
-/obj/item/weapon/tank/jetpack/verb/moveup()
+/mob/verb/up()
set name = "Move Upwards"
- set category = "Object"
+ set category = "IC"
- . = 1
- if(!allow_thrust(0.01, usr))
- usr << "\The [src] is disabled."
+ if(zMove(UP))
+ to_chat(usr, "You move upwards.")
+
+/mob/verb/down()
+ set name = "Move Down"
+ set category = "IC"
+
+ if(zMove(DOWN))
+ to_chat(usr, "You move down.")
+
+/mob/proc/zMove(direction)
+ if(eyeobj)
+ return eyeobj.zMove(direction)
+ if(!can_ztravel())
+ to_chat(usr, "You lack means of travel in that direction.")
return
- var/turf/above = GetAbove(src)
- if(!istype(above))
- usr << "There is nothing of interest in this direction."
- return
+ var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
- if(!istype(above, /turf/space) && !istype(above, /turf/simulated/open))
- usr << "You bump against \the [above]."
- return
+ if(!destination)
+ to_chat(usr, "There is nothing of interest in this direction.")
+ return 0
- for(var/atom/A in above)
- if(A.density)
- usr << "\The [A] blocks you."
- return
+ var/turf/start = get_turf(src)
+ if(!start.CanZPass(src, direction))
+ to_chat(usr, "\The [start] is in the way.")
+ return 0
+ if(!destination.CanZPass(src, direction))
+ to_chat(usr, "\The [destination] blocks your way.")
+ return 0
- usr.Move(above)
- usr << "You move upwards."
+ var/area/area = get_area(src)
+ if(direction == UP && area.has_gravity)
+ var/obj/structure/lattice/lattice = locate() in destination.contents
+ if(lattice)
+ var/pull_up_time = max(5 SECONDS + (src.movement_delay() * 10), 1)
+ to_chat(src, "You grab \the [lattice] and start pulling yourself upward...")
+ destination.audible_message("You hear something climbing up \the [lattice].")
+ if(do_after(src, pull_up_time))
+ to_chat(src, "You pull yourself up.")
+ else
+ to_chat(src, "You gave up on pulling yourself up.")
+ return 0
+ else
+ to_chat(usr, "Gravity stops you from moving upward.")
+ return 0
-/obj/item/weapon/tank/jetpack/verb/movedown()
- set name = "Move Downwards"
- set category = "Object"
+ for(var/atom/A in destination)
+ if(!A.CanPass(src, start, 1.5, 0))
+ to_chat(usr, "\The [A] blocks you.")
+ return 0
+ Move(destination)
+ return 1
- . = 1
- if(!allow_thrust(0.01, usr))
- usr << "\The [src] is disabled."
+/mob/observer/zMove(direction)
+ var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
+ if(destination)
+ forceMove(destination)
+ else
+ to_chat(usr, "There is nothing of interest in this direction.")
+
+/mob/observer/eye/zMove(direction)
+ var/turf/destination = (direction == UP) ? GetAbove(src) : GetBelow(src)
+ if(destination)
+ setLoc(destination)
+ else
+ to_chat(usr, "There is nothing of interest in this direction.")
+
+/mob/proc/can_ztravel()
+ return 0
+
+/mob/observer/can_ztravel()
+ return 1
+
+/mob/living/carbon/human/can_ztravel()
+ if(incapacitated())
+ return 0
+
+ if(Process_Spacemove())
+ return 1
+
+ if(Check_Shoegrip()) //scaling hull with magboots
+ for(var/turf/simulated/T in trange(1,src))
+ if(T.density)
+ return 1
+
+/mob/living/silicon/robot/can_ztravel()
+ if(incapacitated() || is_dead())
+ return 0
+
+ if(Process_Spacemove()) //Checks for active jetpack
+ return 1
+
+ for(var/turf/simulated/T in trange(1,src)) //Robots get "magboots"
+ if(T.density)
+ return 1
+
+
+
+
+//FALLING STUFF
+
+//Holds fall checks that should not be overriden by children
+/atom/movable/proc/fall()
+ if(!isturf(loc))
return
var/turf/below = GetBelow(src)
- if(!istype(below))
- usr << "There is nothing of interest in this direction."
+ if(!below)
return
- if(below.density)
- usr << "You bump against \the [below]."
+ var/turf/T = loc
+ if(!T.CanZPass(src, DOWN) || !below.CanZPass(src, DOWN))
return
+ // No gravity in space, apparently.
+ var/area/area = get_area(src)
+ if(!area.has_gravity())
+ return
+
+ if(throwing)
+ return
+
+ if(can_fall())
+ handle_fall(below)
+
+//For children to override
+/atom/movable/proc/can_fall()
+ if(anchored)
+ return FALSE
+
+ if(locate(/obj/structure/lattice, loc))
+ return FALSE
+
+ // See if something prevents us from falling.
+ var/turf/below = GetBelow(src)
for(var/atom/A in below)
- if(A.density)
- usr << "\The [A] blocks you."
- return
+ if(!A.CanPass(src, src.loc))
+ return FALSE
- usr.Move(below)
- usr << "You move downwards."
+ return TRUE
+
+/obj/effect/can_fall()
+ return FALSE
+
+/obj/effect/decal/cleanable/can_fall()
+ return TRUE
+
+/obj/item/pipe/can_fall()
+ var/turf/simulated/open/below = loc
+ below = below.below
+
+ . = ..()
+
+ if(anchored)
+ return FALSE
+
+ if((locate(/obj/structure/disposalpipe/up) in below) || locate(/obj/machinery/atmospherics/pipe/zpipe/up in below))
+ return FALSE
+
+/mob/living/simple_animal/parrot/can_fall() // Poly can fly.
+ return FALSE
+
+/mob/living/simple_animal/hostile/carp/can_fall() // So can carp apparently.
+ return FALSE
+
+/atom/movable/proc/handle_fall(var/turf/landing)
+ Move(landing)
+ if(locate(/obj/structure/stairs) in landing)
+ return 1
+
+ if(istype(landing, /turf/simulated/open))
+ visible_message("\The [src] falls from the deck above through \the [landing]!", "You hear a whoosh of displaced air.")
+ else
+ visible_message("\The [src] falls from the deck above and slams into \the [landing]!", "You hear something slam into the deck.")
+
+/mob/living/carbon/human/handle_fall(var/turf/landing)
+ if(..())
+ return
+ to_chat(src, "You fall off and hit \the [landing]!")
+ playsound(loc, "punch", 25, 1, -1)
+ var/damage = 20 // Because wounds heal rather quickly, 20 should be enough to discourage jumping off but not be enough to ruin you, at least for the first time.
+ apply_damage(rand(0, damage), BRUTE, BP_HEAD)
+ apply_damage(rand(0, damage), BRUTE, BP_TORSO)
+ apply_damage(rand(0, damage), BRUTE, BP_L_LEG)
+ apply_damage(rand(0, damage), BRUTE, BP_R_LEG)
+ apply_damage(rand(0, damage), BRUTE, BP_L_ARM)
+ apply_damage(rand(0, damage), BRUTE, BP_R_ARM)
+ Weaken(4)
+ updatehealth()
\ No newline at end of file
diff --git a/code/modules/multiz/structures.dm b/code/modules/multiz/structures.dm
index 36a606bfcf9..57278082764 100644
--- a/code/modules/multiz/structures.dm
+++ b/code/modules/multiz/structures.dm
@@ -4,54 +4,127 @@
/obj/structure/ladder
name = "ladder"
- desc = "A ladder. You can climb it up and down."
- icon_state = "ladderdown"
+ desc = "A ladder. You can climb it up and down."
+ icon_state = "ladder01"
icon = 'icons/obj/structures.dmi'
density = 0
opacity = 0
anchored = 1
- var/obj/structure/ladder/target
+ var/allowed_directions = DOWN
+ var/obj/structure/ladder/target_up
+ var/obj/structure/ladder/target_down
- initialize()
- // the upper will connect to the lower
- if(icon_state == "ladderup")
- return
+ var/const/climb_time = 2 SECONDS
+/obj/structure/ladder/initialize()
+ // the upper will connect to the lower
+ if(allowed_directions & DOWN) //we only want to do the top one, as it will initialize the ones before it.
for(var/obj/structure/ladder/L in GetBelow(src))
- if(L.icon_state == "ladderup")
- target = L
- L.target = src
+ if(L.allowed_directions & UP)
+ target_down = L
+ L.target_up = src
return
+ update_icon()
- Destroy()
- if(target && icon_state == "ladderdown")
- qdel(target)
- return ..()
+/obj/structure/ladder/Destroy()
+ if(target_down)
+ target_down.target_up = null
+ target_down = null
+ if(target_up)
+ target_up.target_down = null
+ target_up = null
+ return ..()
- attackby(obj/item/C as obj, mob/user as mob)
- . = ..()
- attack_hand(user)
+/obj/structure/ladder/attackby(obj/item/C as obj, mob/user as mob)
+ attack_hand(user)
+ return
+
+/obj/structure/ladder/attack_hand(var/mob/M)
+ if(!M.may_climb_ladders(src))
return
- attack_hand(var/mob/M)
- if(!target || !istype(target.loc, /turf))
- M << "\The [src] is incomplete and can't be climbed."
+ var/obj/structure/ladder/target_ladder = getTargetLadder(M)
+ if(!target_ladder)
+ return
+ if(!M.Move(get_turf(src)))
+ to_chat(M, "You fail to reach \the [src].")
+ return
+
+ var/direction = target_ladder == target_up ? "up" : "down"
+
+ M.visible_message("\The [M] begins climbing [direction] \the [src]!",
+ "You begin climbing [direction] \the [src]!",
+ "You hear the grunting and clanging of a metal ladder being used.")
+
+ target_ladder.audible_message("You hear something coming [direction] \the [src]")
+
+ if(do_after(M, climb_time, src))
+ climbLadder(M, target_ladder)
+
+/obj/structure/ladder/attack_ghost(var/mob/M)
+ var/target_ladder = getTargetLadder(M)
+ if(target_ladder)
+ M.forceMove(get_turf(target_ladder))
+
+/obj/structure/ladder/proc/getTargetLadder(var/mob/M)
+ if((!target_up && !target_down) || (target_up && !istype(target_up.loc, /turf) || (target_down && !istype(target_down.loc,/turf))))
+ to_chat(M, "\The [src] is incomplete and can't be climbed.")
+ return
+ if(target_down && target_up)
+ var/direction = alert(M,"Do you want to go up or down?", "Ladder", "Up", "Down", "Cancel")
+
+ if(direction == "Cancel")
return
- var/turf/T = target.loc
- for(var/atom/A in T)
- if(A.density)
- M << "\A [A] is blocking \the [src]."
- return
+ if(!M.may_climb_ladders(src))
+ return
+
+ switch(direction)
+ if("Up")
+ return target_up
+ if("Down")
+ return target_down
+ else
+ return target_down || target_up
+
+/mob/proc/may_climb_ladders(var/ladder)
+ if(!Adjacent(ladder))
+ to_chat(src, "You need to be next to \the [ladder] to start climbing.")
+ return FALSE
+ if(incapacitated())
+ to_chat(src, "You are physically unable to climb \the [ladder].")
+ return FALSE
+ return TRUE
+
+/mob/observer/ghost/may_climb_ladders(var/ladder)
+ return TRUE
+
+/obj/structure/ladder/proc/climbLadder(var/mob/M, var/target_ladder)
+ var/turf/T = get_turf(target_ladder)
+ for(var/atom/A in T)
+ if(!A.CanPass(M, M.loc, 1.5, 0))
+ to_chat(M, "\The [A] is blocking \the [src].")
+ return FALSE
+ return M.Move(T)
+
+/obj/structure/ladder/CanPass(obj/mover, turf/source, height, airflow)
+ return airflow || !density
+
+/obj/structure/ladder/update_icon()
+ icon_state = "ladder[!!(allowed_directions & UP)][!!(allowed_directions & DOWN)]"
+
+/obj/structure/ladder/up
+ allowed_directions = UP
+ icon_state = "ladder10"
+
+/obj/structure/ladder/updown
+ allowed_directions = UP|DOWN
+ icon_state = "ladder11"
+
+
- M.visible_message("\A [M] climbs [icon_state == "ladderup" ? "up" : "down"] \a [src]!",
- "You climb [icon_state == "ladderup" ? "up" : "down"] \the [src]!",
- "You hear the grunting and clanging of a metal ladder being used.")
- M.Move(T)
- CanPass(obj/mover, turf/source, height, airflow)
- return airflow || !density
/obj/structure/stairs
name = "Stairs"
@@ -61,46 +134,50 @@
opacity = 0
anchored = 1
- initialize()
- for(var/turf/turf in locs)
- var/turf/simulated/open/above = GetAbove(turf)
- if(!above)
- warning("Stair created without level above: ([loc.x], [loc.y], [loc.z])")
- return qdel(src)
- if(!istype(above))
- above.ChangeTurf(/turf/simulated/open)
+/obj/structure/stairs/initialize()
+ for(var/turf/turf in locs)
+ var/turf/simulated/open/above = GetAbove(turf)
+ if(!above)
+ warning("Stair created without level above: ([loc.x], [loc.y], [loc.z])")
+ return qdel(src)
+ if(!istype(above))
+ above.ChangeTurf(/turf/simulated/open)
- Uncross(atom/movable/A)
- if(A.dir == dir)
- // This is hackish but whatever.
- var/turf/target = get_step(GetAbove(A), dir)
- var/turf/source = A.loc
- if(target.Enter(A, source))
- A.loc = target
- target.Entered(A, source)
- return 0
- return 1
+/obj/structure/stairs/Uncross(atom/movable/A)
+ if(A.dir == dir)
+ // This is hackish but whatever.
+ var/turf/target = get_step(GetAbove(A), dir)
+ var/turf/source = A.loc
+ if(target.Enter(A, source))
+ A.loc = target
+ target.Entered(A, source)
+ if(isliving(A))
+ var/mob/living/L = A
+ if(L.pulling)
+ L.pulling.forceMove(target)
+ return 0
+ return 1
- CanPass(obj/mover, turf/source, height, airflow)
- return airflow || !density
+/obj/structure/stairs/CanPass(obj/mover, turf/source, height, airflow)
+ return airflow || !density
- // type paths to make mapping easier.
- north
- dir = NORTH
- bound_height = 64
- bound_y = -32
- pixel_y = -32
+// type paths to make mapping easier.
+/obj/structure/stairs/north
+ dir = NORTH
+ bound_height = 64
+ bound_y = -32
+ pixel_y = -32
- south
- dir = SOUTH
- bound_height = 64
+/obj/structure/stairs/south
+ dir = SOUTH
+ bound_height = 64
- east
- dir = EAST
- bound_width = 64
- bound_x = -32
- pixel_x = -32
+/obj/structure/stairs/east
+ dir = EAST
+ bound_width = 64
+ bound_x = -32
+ pixel_x = -32
- west
- dir = WEST
- bound_width = 64
\ No newline at end of file
+/obj/structure/stairs/west
+ dir = WEST
+ bound_width = 64
\ No newline at end of file
diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm
index d85a464af2b..8389df7112b 100644
--- a/code/modules/multiz/turf.dm
+++ b/code/modules/multiz/turf.dm
@@ -1,87 +1,79 @@
+/turf/proc/CanZPass(atom/A, direction)
+ if(z == A.z) //moving FROM this turf
+ return direction == UP //can't go below
+ else
+ if(direction == UP) //on a turf below, trying to enter
+ return 0
+ if(direction == DOWN) //on a turf above, trying to enter
+ return !density
+
+/turf/simulated/open/CanZPass(atom, direction)
+ return 1
+
+/turf/space/CanZPass(atom, direction)
+ return 1
+
/turf/simulated/open
name = "open space"
icon = 'icons/turf/space.dmi'
- icon_state = "black"
- alpha = 16
+ icon_state = ""
layer = 0
density = 0
pathweight = 100000 //Seriously, don't try and path over this one numbnuts
var/turf/below
- var/list/underlay_references
- var/global/overlay_map = list()
+
+/turf/simulated/open/post_change()
+ ..()
+ update()
/turf/simulated/open/initialize()
..()
- below = GetBelow(src)
ASSERT(HasBelow(z))
+ update()
/turf/simulated/open/Entered(var/atom/movable/mover)
- // only fall down in defined areas (read: areas with artificial gravitiy)
- if(!istype(below)) //make sure that there is actually something below
- below = GetBelow(src)
- if(!below)
- return
+ ..()
+ mover.fall()
- // No gravity in space, apparently.
- var/area/area = get_area(src)
- if(area.name == "Space")
- return
-
- // Prevent pipes from falling into the void... if there is a pipe to support it.
- if(mover.anchored || istype(mover, /obj/item/pipe) && \
- (locate(/obj/structure/disposalpipe/up) in below) || \
- locate(/obj/machinery/atmospherics/pipe/zpipe/up in below))
- return
-
- // See if something prevents us from falling.
- var/soft = 0
- for(var/atom/A in below)
- if(A.density)
- if(!istype(A, /obj/structure/window))
- return
- else
- var/obj/structure/window/W = A
- if(W.is_fulltile())
- return
- // Dont break here, since we still need to be sure that it isnt blocked
- if(istype(A, /obj/structure/stairs))
- soft = 1
-
- // We've made sure we can move, now.
- mover.Move(below)
-
- if(!soft)
- if(!istype(mover, /mob))
- if(istype(below, /turf/simulated/open))
- mover.visible_message("\The [mover] falls from the deck above through \the [below]!", "You hear a whoosh of displaced air.")
- else
- mover.visible_message("\The [mover] falls from the deck above and slams into \the [below]!", "You hear something slam into the deck.")
- else
- var/mob/M = mover
- if(istype(below, /turf/simulated/open))
- below.visible_message("\The [mover] falls from the deck above through \the [below]!", "You hear a soft whoosh.[M.stat ? "" : ".. and some screaming."]")
- else
- M.visible_message("\The [mover] falls from the deck above and slams into \the [below]!", "You land on \the [below].", "You hear a soft whoosh and a crunch")
-
- // Handle people getting hurt, it's funny!
- if (istype(mover, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = mover
- var/damage = 5
- H.apply_damage(rand(0, damage), BRUTE, BP_HEAD)
- H.apply_damage(rand(0, damage), BRUTE, BP_TORSO)
- H.apply_damage(rand(0, damage), BRUTE, BP_L_LEG)
- H.apply_damage(rand(0, damage), BRUTE, BP_R_LEG)
- H.apply_damage(rand(0, damage), BRUTE, BP_L_ARM)
- H.apply_damage(rand(0, damage), BRUTE, BP_R_ARM)
- H.weakened = max(H.weakened,2)
- H.updatehealth()
+/turf/simulated/open/proc/update()
+ below = GetBelow(src)
+ turf_changed_event.register(below, src, /turf/simulated/open/update_icon)
+ var/turf/simulated/T = get_step(src,NORTH)
+ if(T)
+ turf_changed_event.register(T, src, /turf/simulated/open/update_icon)
+ levelupdate()
+ for(var/atom/movable/A in src)
+ A.fall()
+ update_icon()
// override to make sure nothing is hidden
/turf/simulated/open/levelupdate()
for(var/obj/O in src)
O.hide(0)
+/turf/simulated/open/update_icon()
+ if(below)
+ underlays = list(image(icon = below.icon, icon_state = below.icon_state))
+ underlays += below.overlays.Copy()
+
+ var/list/noverlays = list()
+ if(!istype(below,/turf/space))
+ noverlays += image(icon =icon, icon_state = "empty", layer = 2.2)
+
+ var/turf/simulated/T = get_step(src,NORTH)
+ if(istype(T) && !istype(T,/turf/simulated/open))
+ noverlays += image(icon ='icons/turf/cliff.dmi', icon_state = "metal", layer = 2.2)
+
+ var/obj/structure/stairs/S = locate() in below
+ if(S && S.loc == below)
+ var/image/I = image(icon = S.icon, icon_state = "below", dir = S.dir, layer = 2.2)
+ I.pixel_x = S.pixel_x
+ I.pixel_y = S.pixel_y
+ noverlays += I
+
+ overlays = noverlays
+
// Straight copy from space.
/turf/simulated/open/attackby(obj/item/C as obj, mob/user as mob)
if (istype(C, /obj/item/stack/rods))
@@ -108,4 +100,14 @@
return
else
user << "The plating is going to need some support."
- return
\ No newline at end of file
+
+ //To lay cable.
+ if(istype(C, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/coil = C
+ coil.turf_place(src, user)
+ return
+ return
+
+//Most things use is_plating to test if there is a cover tile on top (like regular floors)
+/turf/simulated/open/is_plating()
+ return 1
\ No newline at end of file
diff --git a/code/modules/nano/interaction/default.dm b/code/modules/nano/interaction/default.dm
index 157e0e9de15..e612ca9ca0b 100644
--- a/code/modules/nano/interaction/default.dm
+++ b/code/modules/nano/interaction/default.dm
@@ -40,7 +40,7 @@
// Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras)
// unless it's on the same level as the object it's interacting with.
var/turf/T = get_turf(src_object)
- if(!T || !(z == T.z || (T.z in config.player_levels)))
+ if(!T || !(z == T.z || (T.z in using_map.player_levels)))
return STATUS_CLOSE
// If an object is in view then we can interact with it
diff --git a/code/modules/nano/modules/crew_monitor.dm b/code/modules/nano/modules/crew_monitor.dm
index bb5e28ca046..e71dc5ac7ea 100644
--- a/code/modules/nano/modules/crew_monitor.dm
+++ b/code/modules/nano/modules/crew_monitor.dm
@@ -3,8 +3,8 @@
/datum/nano_module/crew_monitor/Topic(href, href_list)
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))
+ var/turf/T = get_turf(nano_host()) // TODO: Allow setting any using_map.contact_levels from the interface.
+ if (!T || !(T.z in using_map.player_levels))
usr << "Unable to establish a connection: You're too far away from the station!"
return 0
if(href_list["track"])
diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm
index ddb03b9a4f1..2c4b378cde9 100644
--- a/code/modules/organs/blood.dm
+++ b/code/modules/organs/blood.dm
@@ -6,7 +6,6 @@ var/const/BLOOD_VOLUME_SAFE = 85
var/const/BLOOD_VOLUME_OKAY = 75
var/const/BLOOD_VOLUME_BAD = 60
var/const/BLOOD_VOLUME_SURVIVE = 40
-var/const/CE_STABLE_THRESHOLD = 0.5
/mob/living/carbon/human/var/datum/reagents/vessel // Container for blood and BLOOD ONLY. Do not transfer other chems here.
/mob/living/carbon/human/var/var/pale = 0 // Should affect how mob sprite is drawn, but currently doesn't.
@@ -69,24 +68,14 @@ var/const/CE_STABLE_THRESHOLD = 0.5
if(!heart)
blood_volume = 0
- if(heart.is_broken())
- blood_volume *= 0.3
- else if(heart.is_bruised())
- blood_volume *= 0.7
- else if(heart.damage)
+ else if(heart.damage > 1 && heart.damage < heart.min_bruised_damage)
blood_volume *= 0.8
+ else if(heart.damage >= heart.min_bruised_damage && heart.damage < heart.min_broken_damage)
+ blood_volume *= 0.6
+ else if(heart.damage >= heart.min_broken_damage && heart.damage < INFINITY)
+ blood_volume *= 0.3
//Effects of bloodloss
-
- var/dmg_coef = 1 //Lower means less damage taken
- var/threshold_coef = 1 //Lower means the damage caps off lower
-
- if(CE_STABLE in chem_effects)
- dmg_coef = 0.5
- threshold_coef = 0.75
-// dmg_coef = min(1, 10/chem_effects[CE_STABLE]) //TODO: add effect for increased damage
-// threshold_coef = min(dmg_coef / CE_STABLE_THRESHOLD, 1)
-
if(blood_volume >= BLOOD_VOLUME_SAFE)
if(pale)
pale = 0
@@ -100,32 +89,34 @@ var/const/CE_STABLE_THRESHOLD = 0.5
if(prob(1))
var/word = pick("dizzy","woosey","faint")
src << "\red You feel [word]"
- if(getOxyLoss() < 20 * threshold_coef)
- adjustOxyLoss(3 * dmg_coef)
+ if(oxyloss < 20)
+ oxyloss += 3
else if(blood_volume >= BLOOD_VOLUME_BAD)
if(!pale)
pale = 1
update_body()
eye_blurry = max(eye_blurry,6)
- if(getOxyLoss() < 50 * threshold_coef)
- adjustOxyLoss(10 * dmg_coef)
- adjustOxyLoss(1 * dmg_coef)
+ if(oxyloss < 50)
+ oxyloss += 10
+ oxyloss += 1
if(prob(15))
Paralyse(rand(1,3))
var/word = pick("dizzy","woosey","faint")
src << "\red You feel extremely [word]"
else if(blood_volume >= BLOOD_VOLUME_SURVIVE)
- adjustOxyLoss(5 * dmg_coef)
- adjustToxLoss(3 * dmg_coef)
+ oxyloss += 5
+ toxloss += 3
if(prob(15))
var/word = pick("dizzy","woosey","faint")
src << "\red You feel extremely [word]"
- else
- // There currently is a strange bug here. If the mob is not below -100 health
- // when death() is called, apparently they will be just fine, and this way it'll
- // spam deathgasp. Adjusting toxloss ensures the mob will stay dead.
- adjustToxLoss(300 * dmg_coef) // just to be safe!
- death()
+ else //Not enough blood to survive (usually)
+ if(!pale)
+ pale = 1
+ update_body()
+ eye_blurry = max(eye_blurry,6)
+ Paralyse(3)
+ toxloss += 3
+ oxyloss += 75 // 15 more than dexp fixes (also more than dex+dexp+tricord)
// Without enough blood you slowly go hungry.
if(blood_volume < BLOOD_VOLUME_SAFE)
@@ -153,8 +144,6 @@ var/const/CE_STABLE_THRESHOLD = 0.5
blood_loss_divisor += 5
else if((temp.organ_tag == BP_L_HAND) || (temp.organ_tag == BP_R_HAND) || (temp.organ_tag == BP_L_FOOT) || (temp.organ_tag == BP_R_FOOT))
blood_loss_divisor += 10
- if(CE_STABLE in chem_effects) //Inaprov slows bloodloss
- blood_loss_divisor += 10
if(temp.applied_pressure)
if(ishuman(temp.applied_pressure))
var/mob/living/carbon/human/H = temp.applied_pressure
diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm
index edc6f6e47fb..6514092dfc0 100644
--- a/code/modules/organs/internal/brain.dm
+++ b/code/modules/organs/internal/brain.dm
@@ -24,6 +24,19 @@
/obj/item/organ/internal/brain/digitize()
replace_self_with(/obj/item/organ/internal/mmi_holder/robot)
+/obj/item/organ/internal/brain/handle_germ_effects()
+ . = ..() //Up should return an infection level as an integer
+ if(!.) return
+
+ //Bacterial meningitis (more of a spine thing but 'brain infection' isn't a common thing)
+ if (. >= 1)
+ if(prob(1))
+ owner.custom_pain("Your neck aches, and feels very stiff!",0)
+ if (. >= 2)
+ if(prob(1))
+ owner.custom_pain("Your feel very dizzy for a moment!",0)
+ owner.confused = max(owner.confused, 2)
+
/obj/item/organ/internal/brain/proc/replace_self_with(replace_path)
var/mob/living/carbon/human/tmp_owner = owner
qdel(src)
diff --git a/code/modules/organs/internal/eyes.dm b/code/modules/organs/internal/eyes.dm
index 064a668686b..2a2b8305d3c 100644
--- a/code/modules/organs/internal/eyes.dm
+++ b/code/modules/organs/internal/eyes.dm
@@ -67,9 +67,22 @@
/obj/item/organ/internal/eyes/process() //Eye damage replaces the old eye_stat var.
..()
- if(!owner)
- return
+ if(!owner) return
+
if(is_bruised())
owner.eye_blurry = 20
if(is_broken())
- owner.eye_blind = 20
\ No newline at end of file
+ owner.eye_blind = 20
+
+/obj/item/organ/internal/eyes/handle_germ_effects()
+ . = ..() //Up should return an infection level as an integer
+ if(!.) return
+
+ //Conjunctivitis
+ if (. >= 1)
+ if(prob(1))
+ owner.custom_pain("The corners of your eyes itch! It's quite frustrating.",0)
+ if (. >= 2)
+ if(prob(1))
+ owner.custom_pain("Your eyes are watering, making it harder to see clearly for a moment.",1)
+ owner.eye_blurry += 10
diff --git a/code/modules/organs/internal/heart.dm b/code/modules/organs/internal/heart.dm
index 99b7386403e..8ca68878e38 100644
--- a/code/modules/organs/internal/heart.dm
+++ b/code/modules/organs/internal/heart.dm
@@ -5,4 +5,18 @@
icon_state = "heart-on"
organ_tag = O_HEART
parent_organ = BP_TORSO
- dead_icon = "heart-off"
\ No newline at end of file
+ dead_icon = "heart-off"
+
+
+/obj/item/organ/internal/heart/handle_germ_effects()
+ . = ..() //Up should return an infection level as an integer
+ if(!.) return
+
+ //Endocarditis (very rare, usually for artificially implanted heart valves/pacemakers)
+ if (. >= 1)
+ if(prob(1))
+ owner.custom_pain("Your chest feels uncomfortably tight!",0)
+ if (. >= 2)
+ if(prob(1))
+ owner.custom_pain("A stabbing pain rolls through your chest!",1)
+ owner.apply_damage(damage = 25, damagetype = HALLOSS, def_zone = parent_organ)
diff --git a/code/modules/organs/internal/kidneys.dm b/code/modules/organs/internal/kidneys.dm
index 5d3875ccf54..a547a2539fe 100644
--- a/code/modules/organs/internal/kidneys.dm
+++ b/code/modules/organs/internal/kidneys.dm
@@ -8,11 +8,8 @@
parent_organ = BP_GROIN
/obj/item/organ/internal/kidneys/process()
-
..()
-
- if(!owner)
- return
+ if(!owner) return
// Coffee is really bad for you with busted kidneys.
// This should probably be expanded in some way, but fucked if I know
@@ -22,4 +19,18 @@
if(is_bruised())
owner.adjustToxLoss(0.1 * PROCESS_ACCURACY)
else if(is_broken())
- owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
\ No newline at end of file
+ owner.adjustToxLoss(0.3 * PROCESS_ACCURACY)
+
+/obj/item/organ/internal/kidneys/handle_germ_effects()
+ . = ..() //Up should return an infection level as an integer
+ if(!.) return
+
+ //Pyelonephritis
+ if (. >= 1)
+ if(prob(1))
+ owner.custom_pain("There's a stabbing pain in your lower back!",1)
+ if (. >= 2)
+ if(prob(1))
+ owner.custom_pain("You feel extremely tired, like you can't move!",1)
+ owner.m_intent = "walk"
+ owner.hud_used.move_intent.icon_state = "walking"
diff --git a/code/modules/organs/internal/liver.dm b/code/modules/organs/internal/liver.dm
index c3c2ef6eac6..daa0a88f76c 100644
--- a/code/modules/organs/internal/liver.dm
+++ b/code/modules/organs/internal/liver.dm
@@ -7,18 +7,8 @@
parent_organ = BP_GROIN
/obj/item/organ/internal/liver/process()
-
..()
-
- if(!owner)
- return
-
- if (germ_level > INFECTION_LEVEL_ONE)
- if(prob(1))
- owner << "Your skin itches."
- if (germ_level > INFECTION_LEVEL_TWO)
- if(prob(1))
- spawn owner.vomit()
+ if(!owner) return
if(owner.life_tick % PROCESS_ACCURACY == 0)
@@ -52,4 +42,17 @@
if(filter_effect < 3)
owner.adjustToxLoss(owner.chem_effects[CE_ALCOHOL_TOXIC] * 0.1 * PROCESS_ACCURACY)
else
- take_damage(owner.chem_effects[CE_ALCOHOL_TOXIC] * 0.1 * PROCESS_ACCURACY, prob(1)) // Chance to warn them
\ No newline at end of file
+ take_damage(owner.chem_effects[CE_ALCOHOL_TOXIC] * 0.1 * PROCESS_ACCURACY, prob(1)) // Chance to warn them
+
+/obj/item/organ/internal/liver/handle_germ_effects()
+ . = ..() //Up should return an infection level as an integer
+ if(!.) return
+
+ //Pyogenic Abscess
+ if (. >= 1)
+ if(prob(1))
+ owner.custom_pain("There's a sharp pain in your upper-right abdomen!",1)
+ if (. >= 2)
+ if(prob(1) && owner.getToxLoss() < owner.maxHealth*0.3)
+ //owner << "" //Toxins provide their own messages for pain
+ owner.adjustToxLoss(5) //Not realistic to PA but there are basically no 'real' liver infections
diff --git a/code/modules/organs/internal/lungs.dm b/code/modules/organs/internal/lungs.dm
index 95759e7c370..6e4c15f7525 100644
--- a/code/modules/organs/internal/lungs.dm
+++ b/code/modules/organs/internal/lungs.dm
@@ -13,10 +13,6 @@
if(!owner)
return
- if (germ_level > INFECTION_LEVEL_ONE)
- if(prob(5))
- owner.emote("cough") //respitory tract infection
-
if(is_bruised())
if(prob(4))
spawn owner.emote("me", 1, "coughs up blood!")
@@ -28,5 +24,18 @@
/obj/item/organ/internal/lungs/proc/rupture()
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
if(istype(parent))
- owner.custom_pain("You feel a stabbing pain in your [parent.name]!", 50)
- bruise()
\ No newline at end of file
+ owner.custom_pain("You feel a stabbing pain in your [parent.name]!", 1)
+ bruise()
+
+/obj/item/organ/internal/lungs/handle_germ_effects()
+ . = ..() //Up should return an infection level as an integer
+ if(!.) return
+
+ //Bacterial pneumonia
+ if (. >= 1)
+ if(prob(5))
+ owner.emote("cough")
+ if (. >= 2)
+ if(prob(1))
+ owner.custom_pain("You suddenly feel short of breath and take a sharp, painful breath!",1)
+ owner.adjustOxyLoss(30) //Look it's hard to simulate low O2 perfusion okay
diff --git a/code/modules/organs/internal/organ_internal.dm b/code/modules/organs/internal/organ_internal.dm
index edfa5f70b7f..a3fdc511fc4 100644
--- a/code/modules/organs/internal/organ_internal.dm
+++ b/code/modules/organs/internal/organ_internal.dm
@@ -47,4 +47,16 @@
if(dead_icon)
dead_icon = "[initial(dead_icon)]_assisted"
-// Brain is defined in brain.dm
\ No newline at end of file
+// Brain is defined in brain.dm
+/obj/item/organ/internal/handle_germ_effects()
+ . = ..() //Should be an interger value for infection level
+ if(!.) return
+
+ var/antibiotics = owner.reagents.get_reagent_amount("spaceacillin")
+
+ if(. >= 2 && antibiotics < 5) //INFECTION_LEVEL_TWO
+ if (prob(3))
+ take_damage(1,silent=prob(30))
+
+ //if(. >= 3 && antibiotics < 30) //INFECTION_LEVEL_THREE, others are handled on each specific organ
+ //Nothing that generic internal organs do for this
diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm
index 8de4a39ffe3..30a80b6599b 100644
--- a/code/modules/organs/organ.dm
+++ b/code/modules/organs/organ.dm
@@ -139,8 +139,16 @@ var/list/organ_cache = list()
/obj/item/organ/proc/handle_germ_effects()
//** Handle the effects of infections
+ if(robotic >= ORGAN_ROBOT) //Just in case!
+ germ_level = 0
+ return 0
+
var/antibiotics = owner.reagents.get_reagent_amount("spaceacillin")
+ if((status & ORGAN_DEAD) && antibiotics < 30) //Sepsis from 'dead' organs
+ var/sepsis_severity = 1 + round((germ_level - INFECTION_LEVEL_THREE)/200,0.25) //1 Tox plus a little based on germ level
+ owner.adjustToxLoss(sepsis_severity)
+
if (germ_level > 0 && germ_level < INFECTION_LEVEL_ONE/2 && prob(30))
germ_level--
@@ -150,17 +158,20 @@ var/list/organ_cache = list()
germ_level++
if(germ_level >= INFECTION_LEVEL_ONE)
- var/fever_temperature = (owner.species.heat_level_1 - owner.species.body_temperature - 5)* min(germ_level/INFECTION_LEVEL_TWO, 1) + owner.species.body_temperature
- owner.bodytemperature += between(0, (fever_temperature - T20C)/BODYTEMP_COLD_DIVISOR + 1, fever_temperature - owner.bodytemperature)
+ . = 1 //Organ qualifies for effect-specific processing
+ //var/fever_temperature = (owner.species.heat_level_1 - owner.species.body_temperature - 5)* min(germ_level/INFECTION_LEVEL_TWO, 1) + owner.species.body_temperature
+ //owner.bodytemperature += between(0, (fever_temperature - T20C)/BODYTEMP_COLD_DIVISOR + 1, fever_temperature - owner.bodytemperature)
+ var/fever_temperature = owner.species.heat_discomfort_level * 1.10 //Heat discomfort level plus 10%
+ if(owner.bodytemperature < fever_temperature)
+ owner.bodytemperature += min(0.2,(fever_temperature - owner.bodytemperature) / 10) //Will usually climb by 0.2, else 10% of the difference if less
if (germ_level >= INFECTION_LEVEL_TWO)
- var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
- //spread germs
- if (antibiotics < 5 && parent.germ_level < germ_level && ( parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30) ))
- parent.germ_level++
+ . = 2 //Organ qualifies for effect-specific processing
+ //No particular effect on the general 'organ' at 3
- if (prob(3)) //about once every 30 seconds
- take_damage(1,silent=prob(30))
+ if (germ_level >= INFECTION_LEVEL_THREE && antibiotics < 30)
+ . = 3 //Organ qualifies for effect-specific processing
+ germ_level++ //Germ_level increases without overdose of antibiotics
/obj/item/organ/proc/handle_rejection()
// Process unsuitable transplants. TODO: consider some kind of
@@ -245,7 +256,7 @@ var/list/organ_cache = list()
if(owner && parent_organ && amount > 0)
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
if(parent && !silent)
- owner.custom_pain("Something inside your [parent.name] hurts a lot.", amount)
+ owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1)
/obj/item/organ/proc/bruise()
damage = max(damage, min_bruised_damage)
@@ -270,9 +281,13 @@ var/list/organ_cache = list()
return
switch (severity)
if (1)
- take_damage(rand(3, 7))
+ take_damage(rand(6,12))
if (2)
- take_damage(rand(1, 3))
+ take_damage(rand(4,8))
+ if (3)
+ take_damage(rand(3,6))
+ if (4)
+ take_damage(rand(1,4))
/obj/item/organ/proc/removed(var/mob/living/user)
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index c2a54b48694..b746f1be6f4 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -102,11 +102,19 @@
/obj/item/organ/external/emp_act(severity)
if(!(robotic >= ORGAN_ROBOT))
return
+ var/burn_damage = 0
switch (severity)
if (1)
- take_damage(rand(6, 10))
+ burn_damage += rand(8, 13)
if (2)
- take_damage(rand(2, 6))
+ burn_damage += rand(6, 9)
+ if(3)
+ burn_damage += rand(4, 7)
+ if(4)
+ burn_damage += rand(1, 5)
+
+ if(burn_damage)
+ take_damage(0, burn_damage)
/obj/item/organ/external/attack_self(var/mob/living/user)
if(!contents.len)
@@ -243,12 +251,12 @@
return (vital || (robotic >= ORGAN_ROBOT) || brute_dam + burn_dam + additional_damage < max_damage)
/obj/item/organ/external/take_damage(brute, burn, sharp, edge, used_weapon = null, list/forbidden_limbs = list())
+ brute = round(brute * brute_mod, 0.1)
+ burn = round(burn * burn_mod, 0.1)
+
if((brute <= 0) && (burn <= 0))
return 0
- brute *= brute_mod
- burn *= burn_mod
-
// High brute damage or sharp objects may damage internal organs
if(internal_organs && (brute_dam >= max_damage || (((sharp && brute >= 5) || brute >= 10) && prob(5))))
// Damage an internal organ
@@ -479,7 +487,7 @@ This function completely restores a damaged organ to perfect condition.
if((damage > 15) && (type != BURN) && (local_damage > 30) && prob(damage) && (robotic < ORGAN_ROBOT))
var/datum/wound/internal_bleeding/I = new (min(damage - 15, 15))
wounds += I
- owner.custom_pain("You feel something rip in your [name]!", 50)
+ owner.custom_pain("You feel something rip in your [name]!", 1)
//Burn damage can cause fluid loss due to blistering and cook-off
if((damage > 5 || damage + burn_dam >= 15) && type == BURN && (robotic < ORGAN_ROBOT))
@@ -622,13 +630,12 @@ Note that amputating the affected organ does in fact remove the infection from t
break //limit increase to a maximum of one per second
/obj/item/organ/external/handle_germ_effects()
-
- if(germ_level < INFECTION_LEVEL_TWO)
- return ..()
+ . = ..() //May be null or an infection level, if null then no specific processing needed here
+ if(!.) return
var/antibiotics = owner.reagents.get_reagent_amount("spaceacillin")
- if(germ_level >= INFECTION_LEVEL_TWO)
+ if(. >= 2 && antibiotics < 5) //INFECTION_LEVEL_TWO
//spread the infection to internal organs
var/obj/item/organ/target_organ = null //make internal organs become infected one at a time instead of all at once
for (var/obj/item/organ/I in internal_organs)
@@ -660,14 +667,13 @@ Note that amputating the affected organ does in fact remove the infection from t
if (parent.germ_level < INFECTION_LEVEL_ONE*2 || prob(30))
parent.germ_level++
- if(germ_level >= INFECTION_LEVEL_THREE && antibiotics < 30) //overdosing is necessary to stop severe infections
+ if(. >= 3 && antibiotics < 30) //INFECTION_LEVEL_THREE
if (!(status & ORGAN_DEAD))
status |= ORGAN_DEAD
owner << "You can't feel your [name] anymore..."
owner.update_body(1)
-
- germ_level++
- owner.adjustToxLoss(1)
+ for (var/obj/item/organ/external/child in children)
+ child.germ_level += 110 //Burst of infection from a parent organ becoming necrotic
//Updating wounds. Handles wound natural I had some free spachealing, internal bleedings and infections
/obj/item/organ/external/proc/update_wounds()
@@ -699,7 +705,7 @@ Note that amputating the affected organ does in fact remove the infection from t
owner.vessel.remove_reagent("blood", wound_update_accuracy * W.damage/40) //line should possibly be moved to handle_blood, so all the bleeding stuff is in one place.
if(prob(1 * wound_update_accuracy))
- owner.custom_pain("You feel a stabbing pain in your [name]!", 50)
+ owner.custom_pain("You feel a stabbing pain in your [name]!",1)
// slow healing
var/heal_amt = 0
diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm
index f46326a53e5..8177ab0e84c 100644
--- a/code/modules/organs/robolimbs.dm
+++ b/code/modules/organs/robolimbs.dm
@@ -70,30 +70,30 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\
parts = list(BP_HEAD)
monitor_styles = standard_monitor_styles
-/datum/robolimb/hesphiastos
- company = "Hesphiastos"
+/datum/robolimb/hephaestus
+ company = "Hephaestus"
desc = "This limb has a militaristic black and green casing with gold stripes."
- icon = 'icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_main.dmi'
+ icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_main.dmi'
unavailable_to_build = 1
-/datum/robolimb/hesphiastos_alt1
- company = "Hesphiastos - Frontier"
- desc = "A rugged prosthetic head featuring the standard Hesphiastos theme, a visor and an external display."
- icon = 'icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_alt1.dmi'
+/datum/robolimb/hephaestus_alt1
+ company = "Hephaistos - Frontier"
+ desc = "A rugged prosthetic head featuring the standard Hephaestus theme, a visor and an external display."
+ icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_alt1.dmi'
unavailable_to_build = 1
parts = list(BP_HEAD)
- monitor_styles = "blank=hesphiastos_alt_off;\
- pink=hesphiastos_alt_pink;\
- orange=hesphiastos_alt_orange;\
- goggles=hesphiastos_alt_goggles;\
- scroll=hesphiastos_alt_scroll;\
- rgb=hesphiastos_alt_rgb;\
- rainbow=hesphiastos_alt_rainbow"
+ monitor_styles = "blank=hephaestus_alt_off;\
+ pink=hephaestus_alt_pink;\
+ orange=hephaestus_alt_orange;\
+ goggles=hephaestus_alt_goggles;\
+ scroll=hephaestus_alt_scroll;\
+ rgb=hephaestus_alt_rgb;\
+ rainbow=hephaestus_alt_rainbow"
-/datum/robolimb/hesphiastos_monitor
- company = "Hesphiastos Monitor"
- desc = "Hesphiastos' unique spin on a popular prosthetic head model. It looks rugged and sturdy."
- icon = 'icons/mob/human_races/cyberlimbs/hesphiastos/hesphiastos_monitor.dmi'
+/datum/robolimb/hephaistos_monitor
+ company = "Hephaestus Monitor"
+ desc = "Hephaestus' unique spin on a popular prosthetic head model. It looks rugged and sturdy."
+ icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_monitor.dmi'
unavailable_to_build = 1
parts = list(BP_HEAD)
monitor_styles = standard_monitor_styles
@@ -112,6 +112,13 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\
unavailable_to_build = 1
parts = list(BP_HEAD)
+/datum/robolimb/morpheus_alt2
+ company = "Morpheus - Skeleton Crew"
+ desc = "This limb is simple and functional; it's basically just a case for a brain."
+ icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt2.dmi'
+ unavailable_to_build = 1
+ parts = list(BP_HEAD)
+
/datum/robolimb/veymed
company = "Vey-Med"
desc = "This high quality limb is nearly indistinguishable from an organic one."
@@ -183,8 +190,8 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\
/obj/item/weapon/disk/limb/bishop
company = "Bishop"
-/obj/item/weapon/disk/limb/hesphiastos
- company = "Hesphiastos"
+/obj/item/weapon/disk/limb/hephaestus
+ company = "Hephaestus"
/obj/item/weapon/disk/limb/morpheus
company = "Morpheus"
diff --git a/code/modules/organs/subtypes/machine.dm b/code/modules/organs/subtypes/machine.dm
index df692c4a97f..45b0b8be284 100644
--- a/code/modules/organs/subtypes/machine.dm
+++ b/code/modules/organs/subtypes/machine.dm
@@ -1,7 +1,6 @@
/obj/item/organ/internal/cell
name = "microbattery"
desc = "A small, powerful cell for use in fully prosthetic bodies."
- icon = 'icons/obj/power.dmi'
icon_state = "scell"
organ_tag = "cell"
parent_organ = BP_TORSO
@@ -27,6 +26,7 @@
vital = 1
var/brain_type = /obj/item/device/mmi
var/obj/item/device/mmi/stored_mmi
+ robotic = ORGAN_ASSISTED
/obj/item/organ/internal/mmi_holder/Destroy()
if(stored_mmi && (stored_mmi.loc == src))
@@ -84,7 +84,7 @@
/obj/item/organ/internal/mmi_holder/posibrain
name = "positronic brain interface"
brain_type = /obj/item/device/mmi/digital/posibrain
-
+ robotic = ORGAN_ROBOT
/obj/item/organ/internal/mmi_holder/posibrain/update_from_mmi()
..()
@@ -94,6 +94,7 @@
/obj/item/organ/internal/mmi_holder/robot
name = "digital brain interface"
brain_type = /obj/item/device/mmi/digital/robot
+ robotic = ORGAN_ROBOT
/obj/item/organ/internal/mmi_holder/robot/update_from_mmi()
..()
diff --git a/code/modules/organs/subtypes/standard.dm b/code/modules/organs/subtypes/standard.dm
index e84e39bc952..90567f23635 100644
--- a/code/modules/organs/subtypes/standard.dm
+++ b/code/modules/organs/subtypes/standard.dm
@@ -28,6 +28,19 @@
// Give them a new cell.
owner.internal_organs_by_name["cell"] = new /obj/item/organ/internal/cell(owner,1)
+/obj/item/organ/external/chest/handle_germ_effects()
+ . = ..() //Should return an infection level
+ if(!. || (status & ORGAN_DEAD)) return //If it's already above 2, it's become necrotic and we can just not worry about it.
+
+ //Staph infection symptoms for CHEST
+ if (. >= 1)
+ if(prob(.))
+ owner.custom_pain("Your [name] [pick("aches","itches","throbs")]!",0)
+
+ if (. >= 2)
+ if(prob(.))
+ owner.custom_pain("A jolt of pain surges through your [name]!",1)
+
/obj/item/organ/external/groin
name = "lower body"
organ_tag = BP_GROIN
@@ -45,6 +58,19 @@
cannot_amputate = 1
organ_rel_size = 30
+/obj/item/organ/external/groin/handle_germ_effects()
+ . = ..() //Should return an infection level
+ if(!. || (status & ORGAN_DEAD)) return //If it's already above 2, it's become necrotic and we can just not worry about it.
+
+ //Staph infection symptoms for GROIN
+ if (. >= 1)
+ if(prob(.))
+ owner.custom_pain("Your [name] [pick("aches","itches","throbs")]!",0)
+
+ if (. >= 2)
+ if(prob(.))
+ owner.custom_pain("A jolt of pain surges through your [name]!",1)
+
/obj/item/organ/external/arm
organ_tag = "l_arm"
name = "left arm"
@@ -60,6 +86,23 @@
force = 7
throwforce = 10
+/obj/item/organ/external/arm/handle_germ_effects()
+ . = ..() //Should return an infection level
+ if(!. || (status & ORGAN_DEAD)) return //If it's already above 2, it's become necrotic and we can just not worry about it.
+
+ //Staph infection symptoms for ARM
+ if (. >= 1)
+ if(prob(.))
+ owner.custom_pain("Your [name] [pick("aches","itches","throbs")]!",0)
+
+ if (. >= 2)
+ if(prob(.))
+ owner.custom_pain("A jolt of pain surges through your [name]!",1)
+ if(organ_tag == "l_arm") //Specific level 2 'feature
+ owner.drop_l_hand()
+ else if(organ_tag == "r_arm")
+ owner.drop_r_hand()
+
/obj/item/organ/external/arm/right
organ_tag = "r_arm"
name = "right arm"
@@ -84,6 +127,20 @@
force = 10
throwforce = 12
+/obj/item/organ/external/leg/handle_germ_effects()
+ . = ..() //Should return an infection level
+ if(!. || (status & ORGAN_DEAD)) return //If it's already above 2, it's become necrotic and we can just not worry about it.
+
+ //Staph infection symptoms for LEG
+ if (. >= 1)
+ if(prob(.))
+ owner.custom_pain("Your [name] [pick("aches","itches","throbs")]!",0)
+
+ if (. >= 2)
+ if(prob(.))
+ owner.custom_pain("A jolt of pain surges through your [name]!",1)
+ owner.Weaken(5)
+
/obj/item/organ/external/leg/right
organ_tag = "r_leg"
name = "right leg"
@@ -114,6 +171,20 @@
owner.drop_from_inventory(owner.shoes)
..()
+/obj/item/organ/external/foot/handle_germ_effects()
+ . = ..() //Should return an infection level
+ if(!. || (status & ORGAN_DEAD)) return //If it's already above 2, it's become necrotic and we can just not worry about it.
+
+ //Staph infection symptoms for FOOT
+ if (. >= 1)
+ if(prob(.))
+ owner.custom_pain("Your [name] [pick("aches","itches","throbs")]!",0)
+
+ if (. >= 2)
+ if(prob(.))
+ owner.custom_pain("A jolt of pain surges through your [name]!",1)
+ owner.Weaken(5)
+
/obj/item/organ/external/foot/right
organ_tag = "r_foot"
name = "right foot"
@@ -146,6 +217,23 @@
owner.drop_from_inventory(owner.gloves)
..()
+/obj/item/organ/external/hand/handle_germ_effects()
+ . = ..() //Should return an infection level
+ if(!. || (status & ORGAN_DEAD)) return //If it's already above 2, it's become necrotic and we can just not worry about it.
+
+ //Staph infection symptoms for HAND
+ if (. >= 1)
+ if(prob(.))
+ owner.custom_pain("Your [name] [pick("aches","itches","throbs")]!",0)
+
+ if (. >= 2)
+ if(prob(.))
+ owner.custom_pain("A jolt of pain surges through your [name]!",1)
+ if(organ_tag == "l_hand") //Specific level 2 'feature
+ owner.drop_l_hand()
+ else if(organ_tag == "r_hand")
+ owner.drop_r_hand()
+
/obj/item/organ/external/hand/right
organ_tag = "r_hand"
name = "right hand"
@@ -202,6 +290,20 @@
if (burn_dam > 40)
disfigure("burn")
+/obj/item/organ/external/head/handle_germ_effects()
+ . = ..() //Should return an infection level
+ if(!. || (status & ORGAN_DEAD)) return //If it's already above 2, it's become necrotic and we can just not worry about it.
+
+ //Staph infection symptoms for HEAD
+ if (. >= 1)
+ if(prob(.))
+ owner.custom_pain("Your [name] [pick("aches","itches","throbs")]!",0)
+
+ if (. >= 2)
+ if(prob(.))
+ owner.custom_pain("A jolt of pain surges through your [name]!",1)
+ owner.eye_blurry += 20 //Specific level 2 'feature
+
/obj/item/organ/external/head/skrell
eye_icon = "skrell_eyes_s"
diff --git a/code/modules/paperwork/adminpaper.dm b/code/modules/paperwork/adminpaper.dm
index 230d8984e8f..b17bdf29f28 100644
--- a/code/modules/paperwork/adminpaper.dm
+++ b/code/modules/paperwork/adminpaper.dm
@@ -58,7 +58,7 @@
text = "
"
text += "This transmission is intended only for the addressee and may contain confidential information. Any unauthorized disclosure is strictly prohibited.
"
- text += "If this transmission is recieved in error, please notify both the sender and the office of [boss_name] Internal Affairs immediately so that corrective action may be taken."
+ text += "If this transmission is recieved in error, please notify both the sender and the office of [using_map.boss_name] Internal Affairs immediately so that corrective action may be taken."
text += "Failure to comply is a breach of regulation and may be prosecuted to the fullest extent of the law, where applicable."
text += ""
diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm
index ccb527986ff..b0da801703c 100644
--- a/code/modules/paperwork/clipboard.dm
+++ b/code/modules/paperwork/clipboard.dm
@@ -23,10 +23,10 @@
if(!M.restrained() && !M.stat)
switch(over_object.name)
if("r_hand")
- M.u_equip(src)
+ M.unEquip(src)
M.put_in_r_hand(src)
if("l_hand")
- M.u_equip(src)
+ M.unEquip(src)
M.put_in_l_hand(src)
add_fingerprint(usr)
diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm
index f2c309ff039..778abc4ee05 100644
--- a/code/modules/paperwork/faxmachine.dm
+++ b/code/modules/paperwork/faxmachine.dm
@@ -1,5 +1,5 @@
var/list/obj/machinery/photocopier/faxmachine/allfaxes = list()
-var/list/admin_departments = list("[boss_name]", "Sif Governmental Authority", "Supply")
+var/list/admin_departments = list("[using_map.boss_name]", "Sif Governmental Authority", "Supply")
var/list/alldepartments = list()
var/list/adminfaxes = list() //cache for faxes that have been sent to admins
@@ -24,7 +24,7 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins
/obj/machinery/photocopier/faxmachine/New()
allfaxes += src
- if(!destination) destination = "[boss_name]"
+ if(!destination) destination = "[using_map.boss_name]"
if( !(("[department]" in alldepartments) || ("[department]" in admin_departments)) )
alldepartments |= department
..()
@@ -47,7 +47,7 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins
data["scanName"] = scan.name
else
data["scanName"] = null
- data["bossName"] = boss_name
+ data["bossName"] = using_map.boss_name
data["authenticated"] = authenticated
data["copyItem"] = copyitem
if(copyitem)
@@ -180,12 +180,12 @@ var/list/adminfaxes = list() //cache for faxes that have been sent to admins
adminfaxes += rcvdcopy
//message badmins that a fax has arrived
- if (destination == boss_name)
- message_admins(sender, "[uppertext(boss_short)] FAX", rcvdcopy, "CentComFaxReply", "#006100")
+ if (destination == using_map.boss_name)
+ message_admins(sender, "[uppertext(using_map.boss_short)] FAX", rcvdcopy, "CentComFaxReply", "#006100")
else if ("Sif Governmental Authority")
message_admins(sender, "SIF GOVERNMENT FAX", rcvdcopy, "CentComFaxReply", "#1F66A0")
else if ("Supply")
- message_admins(sender, "[uppertext(boss_short)] SUPPLY FAX", rcvdcopy, "CentComFaxReply", "#5F4519")
+ message_admins(sender, "[uppertext(using_map.boss_short)] SUPPLY FAX", rcvdcopy, "CentComFaxReply", "#5F4519")
else
message_admins(sender, "[uppertext(destination)] FAX", rcvdcopy, "UNKNOWN")
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index e183c3b2825..a7d1ad04abb 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -233,7 +233,7 @@
t = replacetext(t, "\[u\]", "")
t = replacetext(t, "\[/u\]", "")
t = replacetext(t, "\[time\]", "[stationtime2text()]")
- t = replacetext(t, "\[date\]", "[stationtime2text()]")
+ t = replacetext(t, "\[date\]", "[station_date]")
t = replacetext(t, "\[large\]", "")
t = replacetext(t, "\[/large\]", "")
if(findtext(t, "\[sign\]"))
diff --git a/code/modules/paperwork/papershredder.dm b/code/modules/paperwork/papershredder.dm
index 48e95071c51..3283e67f7d6 100644
--- a/code/modules/paperwork/papershredder.dm
+++ b/code/modules/paperwork/papershredder.dm
@@ -1,10 +1,19 @@
+//
+// Paper Shredder Machine
+//
/obj/machinery/papershredder
name = "paper shredder"
desc = "For those documents you don't want seen."
- icon = 'icons/obj/bureaucracy.dmi'
- icon_state = "papershredder0"
+ icon = 'icons/obj/papershredder.dmi'
+ icon_state = "shredder-off"
+ var/shred_anim = "shredder-shredding"
density = 1
anchored = 1
+ use_power = 1
+ idle_power_usage = 10
+ active_power_usage = 200
+ power_channel = EQUIP
+ circuit = /obj/item/weapon/circuitboard/papershredder
var/max_paper = 10
var/paperamount = 0
var/list/shred_amounts = list(
@@ -16,17 +25,40 @@
/obj/item/weapon/paper_bundle = 3,
)
+/obj/machinery/papershredder/New()
+ ..()
+ component_parts = list()
+ component_parts += new /obj/item/weapon/stock_parts/motor(src)
+ component_parts += new /obj/item/weapon/stock_parts/gear(src)
+ component_parts += new /obj/item/weapon/stock_parts/gear(src)
+ component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
+ RefreshParts()
+ update_icon()
+
/obj/machinery/papershredder/attackby(var/obj/item/W, var/mob/user)
if(istype(W, /obj/item/weapon/storage))
empty_bin(user, W)
return
+ else if(istype(W, /obj/item/weapon/wrench))
+ playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
+ anchored = !anchored
+ user << "You [anchored ? "wrench" : "unwrench"] \the [src]."
+ return
+ else if(default_part_replacement(user, W))
+ return
+ else if(default_deconstruction_screwdriver(user, W))
+ return
+ else if(default_deconstruction_crowbar(user, W))
+ return
else
var/paper_result
for(var/shred_type in shred_amounts)
if(istype(W, shred_type))
paper_result = shred_amounts[shred_type]
if(paper_result)
+ if(inoperable())
+ return // Need powah!
if(paperamount == max_paper)
user << "\The [src] is full; please empty it before you continue."
return
@@ -34,6 +66,7 @@
user.drop_from_inventory(W)
qdel(W)
playsound(src.loc, 'sound/items/pshred.ogg', 75, 1)
+ flick(shred_anim, src)
if(paperamount > max_paper)
user <<"\The [src] was too full, and shredded paper goes everywhere!"
for(var/i=(paperamount-max_paper);i>0;i--)
@@ -92,8 +125,40 @@
paperamount--
return PoolOrNew(/obj/item/weapon/shreddedp, get_turf(src))
+/obj/machinery/papershredder/power_change()
+ ..()
+ spawn(rand(0,15))
+ update_icon()
+
/obj/machinery/papershredder/update_icon()
- icon_state = "papershredder[max(0,min(5,Floor(paperamount/2)))]"
+ overlays.Cut()
+ if(operable())
+ icon_state = "shredder-on"
+ else
+ icon_state = "shredder-off"
+ // Fullness overlay
+ overlays += "shredder-[max(0,min(5,Floor(paperamount/max_paper*5)))]"
+ if (panel_open)
+ overlays += "panel_open"
+
+//
+// Shredded Paper Item
+//
+
+/obj/item/weapon/shreddedp
+ name = "shredded paper"
+ icon = 'icons/obj/bureaucracy.dmi'
+ icon_state = "shredp"
+ throwforce = 0
+ w_class = ITEMSIZE_TINY
+ throw_range = 3
+ throw_speed = 1
+
+/obj/item/weapon/shreddedp/New()
+ ..()
+ pixel_x = rand(-5,5)
+ pixel_y = rand(-5,5)
+ if(prob(65)) color = pick("#BABABA","#7F7F7F")
/obj/item/weapon/shreddedp/attackby(var/obj/item/W as obj, var/mob/user)
if(istype(W, /obj/item/weapon/flame/lighter))
@@ -122,18 +187,3 @@
M.drop_from_inventory(src)
PoolOrNew(/obj/effect/decal/cleanable/ash,get_turf(src))
qdel(src)
-
-/obj/item/weapon/shreddedp
- name = "shredded paper"
- icon = 'icons/obj/bureaucracy.dmi'
- icon_state = "shredp"
- throwforce = 0
- w_class = ITEMSIZE_TINY
- throw_range = 3
- throw_speed = 1
-
-/obj/item/weapon/shreddedp/New()
- ..()
- pixel_x = rand(-5,5)
- pixel_y = rand(-5,5)
- if(prob(65)) color = pick("#BABABA","#7F7F7F")
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 57d10ed227e..74acf07ddb8 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -16,6 +16,7 @@
var/maxcopies = 10 //how many copies can be copied at once- idea shamelessly stolen from bs12's copier!
/obj/machinery/photocopier/New()
+ ..()
component_parts = list()
component_parts += new /obj/item/weapon/stock_parts/scanning_module(src)
component_parts += new /obj/item/weapon/stock_parts/motor(src)
@@ -66,14 +67,18 @@
break
if (istype(copyitem, /obj/item/weapon/paper))
+ playsound(loc, "sound/machines/copier.ogg", 100, 1)
+ sleep(11)
copy(copyitem)
- sleep(15)
else if (istype(copyitem, /obj/item/weapon/photo))
+ playsound(loc, "sound/machines/copier.ogg", 100, 1)
+ sleep(11)
photocopy(copyitem)
- sleep(15)
else if (istype(copyitem, /obj/item/weapon/paper_bundle))
+ sleep(11)
+ playsound(loc, "sound/machines/copier.ogg", 100, 1)
var/obj/item/weapon/paper_bundle/B = bundlecopy(copyitem)
- sleep(15*B.pages.len)
+ sleep(11*B.pages.len)
else
usr << "\The [copyitem] can't be copied by \the [src]."
break
@@ -122,6 +127,7 @@
copyitem = O
O.loc = src
user << "You insert \the [O] into \the [src]."
+ playsound(loc, "sound/machines/click.ogg", 100, 1)
flick(insert_anim, src)
else
user << "There is already something in \the [src]."
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index a0f81f0aee5..19a7e0498d0 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -98,10 +98,10 @@ var/global/photo_count = 0
if((!( M.restrained() ) && !( M.stat ) && M.back == src))
switch(over_object.name)
if("r_hand")
- M.u_equip(src)
+ M.unEquip(src)
M.put_in_r_hand(src)
if("l_hand")
- M.u_equip(src)
+ M.unEquip(src)
M.put_in_l_hand(src)
add_fingerprint(usr)
return
diff --git a/code/modules/planet/planet.dm b/code/modules/planet/planet.dm
new file mode 100644
index 00000000000..65a2de98456
--- /dev/null
+++ b/code/modules/planet/planet.dm
@@ -0,0 +1,42 @@
+// This holds information about a specific 'planetside' area, such as its time, weather, etc. This will most likely be used to model Sif,
+// but away missions may also have use for this.
+
+/datum/planet
+ var/name = "a rock"
+ var/desc = "Someone neglected to write a nice description for this poor rock."
+
+ var/datum/time/current_time = new() // Holds the current time for sun positioning. Note that we assume day and night is the same length because simplicity.
+ var/sun_process_interval = 1 HOUR
+ var/sun_last_process = null // world.time
+
+ var/datum/weather_holder/weather_holder
+
+ var/sun_position = 0 // 0 means midnight, 1 means noon.
+ var/expected_z_levels = list()
+
+/datum/planet/New()
+ ..()
+ weather_holder = new(src)
+ current_time = current_time.make_random_time()
+ update_sun()
+
+/datum/planet/proc/process(amount)
+ if(current_time)
+ current_time = current_time.add_seconds(amount)
+ update_weather() // We update this first, because some weather types decease the brightness of the sun.
+ if(sun_last_process <= world.time - sun_process_interval)
+ update_sun()
+
+// This changes the position of the sun on the planet.
+/datum/planet/proc/update_sun()
+ sun_last_process = world.time
+
+
+/datum/planet/proc/update_weather()
+ if(weather_holder)
+ weather_holder.process()
+
+// Returns the time datum of Sif.
+/proc/get_sif_time()
+ if(planet_sif)
+ return planet_sif.current_time
\ No newline at end of file
diff --git a/code/modules/planet/sif.dm b/code/modules/planet/sif.dm
new file mode 100644
index 00000000000..7b95d387bf5
--- /dev/null
+++ b/code/modules/planet/sif.dm
@@ -0,0 +1,106 @@
+var/datum/planet/sif/planet_sif = null
+
+/datum/planet/sif
+ name = "Sif"
+
+/datum/planet/sif
+ name = "Sif"
+ desc = "Sif is a terrestrial planet in the Vir system. It is somewhat earth-like, in that it has oceans, a \
+ breathable atmosphere, a magnetic field, weather, and similar gravity to Earth. It is currently the capital planet of Vir. \
+ Its center of government is the equatorial city and site of first settlement, New Reykjavik." // Ripped straight from the wiki.
+ current_time = new /datum/time/sif() // 32 hour clocks are nice.
+ expected_z_levels = list(1) // To be changed when real map is finished.
+
+/datum/planet/sif/New()
+ ..()
+ weather_holder = new /datum/weather_holder/sif(src) // Cold weather is also nice.
+
+// This code is horrible.
+/datum/planet/sif/update_sun()
+ ..()
+ var/datum/time/time = current_time
+ var/length_of_day = time.seconds_in_day / 10 / 60 / 60 // 32
+ var/noon = length_of_day / 2
+ var/distance_from_noon = abs(text2num(time.show_time("hh")) - noon)
+ sun_position = distance_from_noon / noon
+ sun_position = abs(sun_position - 1)
+
+ var/low_brightness = null
+ var/high_brightness = null
+
+ var/low_color = null
+ var/high_color = null
+ var/min = 0
+
+ switch(sun_position)
+ if(0 to 0.40) // Night
+ low_brightness = 0.2
+ low_color = "#000066"
+
+ high_brightness = 0.5
+ high_color = "#66004D"
+ min = 0
+
+ if(0.40 to 0.50) // Twilight
+ low_brightness = 0.6
+ low_color = "#66004D"
+
+ high_brightness = 0.8
+ high_color = "#CC3300"
+ min = 0.40
+
+ if(0.50 to 0.70) // Sunrise/set
+ low_brightness = 0.8
+ low_color = "#CC3300"
+
+ high_brightness = 0.9
+ high_color = "#FF9933"
+ min = 0.50
+
+ if(0.70 to 1.00) // Noon
+ low_brightness = 0.9
+ low_color = "#DDDDDD"
+
+ high_brightness = 1.0
+ high_color = "#FFFFFF"
+ min = 0.70
+
+ var/lerp_weight = (abs(min - sun_position)) * 4
+ var/weather_light_modifier = 1
+ if(weather_holder && weather_holder.current_weather)
+ weather_light_modifier = weather_holder.current_weather.light_modifier
+
+ var/new_brightness = (Interpolate(low_brightness, high_brightness, weight = lerp_weight) ) * weather_light_modifier
+
+ var/new_color = null
+ if(weather_holder && weather_holder.current_weather && weather_holder.current_weather.light_color)
+ new_color = weather_holder.current_weather.light_color
+ else
+ var/list/low_color_list = hex2rgb(low_color)
+ var/low_r = low_color_list[1]
+ var/low_g = low_color_list[2]
+ var/low_b = low_color_list[3]
+
+ var/list/high_color_list = hex2rgb(high_color)
+ var/high_r = high_color_list[1]
+ var/high_g = high_color_list[2]
+ var/high_b = high_color_list[3]
+
+ var/new_r = Interpolate(low_r, high_r, weight = lerp_weight)
+ var/new_g = Interpolate(low_g, high_g, weight = lerp_weight)
+ var/new_b = Interpolate(low_b, high_b, weight = lerp_weight)
+
+ new_color = rgb(new_r, new_g, new_b)
+
+ spawn(1)
+ update_sun_deferred(2, new_brightness, new_color)
+
+/datum/planet/proc/update_sun_deferred(var/new_range, var/new_brightness, var/new_color)
+ set background = 1
+ set waitfor = 0
+ var/i = 0
+ for(var/turf/simulated/floor/T in outdoor_turfs)
+ T.set_light(new_range, new_brightness, new_color)
+ i++
+ if(i % 30 == 0)
+ sleep(1)
diff --git a/code/modules/planet/time.dm b/code/modules/planet/time.dm
new file mode 100644
index 00000000000..936ae0eadda
--- /dev/null
+++ b/code/modules/planet/time.dm
@@ -0,0 +1,76 @@
+// This datum allows one to add and subtract various lengths of time. It really shines when using an alternate time system.
+
+/datum/time
+ // Note that the following is actually measured in 10ths of a second.
+ var/seconds_in_day = 60 * 60 * 24 * 10 // 86,400 seconds
+ var/seconds_in_hour = 60 * 60 * 10 // 3,600 seconds
+ var/seconds_in_minute = 60 * 10
+
+ // This holds the amount of seconds.
+ var/seconds_stored = 0
+
+/datum/time/New(new_time)
+ if(new_time)
+ seconds_stored = new_time
+ ..()
+
+/datum/time/proc/add_seconds(amount)
+ var/answer = seconds_stored + amount * 10
+ if(answer >= seconds_in_day)
+ rollover(answer)
+ return new type(answer)
+
+/datum/time/proc/add_minutes(amount)
+ var/real_amount = amount * seconds_in_minute
+ var/answer = real_amount + seconds_stored
+ if(answer >= seconds_in_day)
+ rollover(answer)
+ return new type(answer)
+
+/datum/time/proc/add_hours(amount)
+ var/real_amount = amount * seconds_in_hour
+ var/answer = real_amount + seconds_stored
+ if(answer >= seconds_in_day)
+ rollover(answer)
+ return new type(answer)
+
+/datum/time/proc/rollover(time)
+ return max(time - seconds_in_day, 0)
+
+/datum/time/proc/make_random_time()
+ return new type(rand(0, seconds_in_day - 1))
+
+// This works almost exactly like time2text.
+// The advantage of this is that it can handle time systems beyond 24h.
+// The downside is a lack of date capability.
+/datum/time/proc/show_time(format)
+ var/time = seconds_stored
+ while(time >= seconds_in_day) // First, get rid of extra days.
+ time = rollover(time)
+
+ var/hours = time / seconds_in_hour
+ var/remaining_hour = time % seconds_in_hour
+ var/minutes = remaining_hour / seconds_in_minute
+ var/seconds = remaining_hour % seconds_in_minute / 10
+
+
+ var/hour_text = num2text(Floor(hours))
+ if(length(hour_text) < 2)
+ hour_text = "0[hour_text]" // Add padding if needed, to look more like time2text().
+
+ var/minute_text = num2text(Floor(minutes))
+ if(length(minute_text) < 2)
+ minute_text = "0[minute_text]"
+
+ var/second_text = num2text(Floor(seconds))
+ if(length(second_text) < 2)
+ second_text = "0[second_text]"
+
+ var/answer = replacetext(format, "hh", hour_text)
+ answer = replacetext(answer, "mm", minute_text)
+ answer = replacetext(answer, "ss", second_text)
+ return answer
+
+// We're gonna pretend there are 32 hours in a Sif day instead of 32.64 for the purposes of not losing sanity. We lose 38m 24s but the alternative is a path to madness.
+/datum/time/sif
+ seconds_in_day = 60 * 60 * 32 * 10 // 115,200 seconds. If we did 32.64 hours/day it would be around 117,504 seconds instead.
\ No newline at end of file
diff --git a/code/modules/planet/weather.dm b/code/modules/planet/weather.dm
new file mode 100644
index 00000000000..14318a1d7f0
--- /dev/null
+++ b/code/modules/planet/weather.dm
@@ -0,0 +1,281 @@
+#define WEATHER_CLEAR "clear"
+#define WEATHER_OVERCAST "overcast"
+#define WEATHER_LIGHT_SNOW "light snow"
+#define WEATHER_SNOW "snow"
+#define WEATHER_BLIZZARD "blizzard"
+#define WEATHER_RAIN "rain"
+#define WEATHER_STORM "storm"
+#define WEATHER_HAIL "hail"
+#define WEATHER_WINDY "windy"
+#define WEATHER_HOT "hot"
+#define WEATHER_BLOOD_MOON "blood moon" // For admin fun or cult later on.
+
+/datum/weather_holder
+ var/datum/planet/our_planet = null
+ var/datum/weather/current_weather = null
+ var/temperature = T20C
+ var/wind_dir = 0
+ var/wind_speed = 0
+ var/list/allowed_weather_types = list()
+ var/list/roundstart_weather_chances = list()
+ var/next_weather_shift = null
+ var/planetary_wall_type = null // Which walls to look for when updating temperature.
+
+/datum/weather_holder/New(var/source)
+ ..()
+ our_planet = source
+ for(var/A in allowed_weather_types)
+ var/datum/weather/W = allowed_weather_types[A]
+ if(istype(W))
+ W.holder = src
+
+/datum/weather_holder/proc/change_weather(var/new_weather)
+ var/old_light_modifier = null
+ if(current_weather)
+ old_light_modifier = current_weather.light_modifier // We store the old one, so we can determine if recalculating the sun is needed.
+ current_weather = allowed_weather_types[new_weather]
+ next_weather_shift = world.time + rand(20, 30) MINUTES
+
+ update_icon_effects()
+ update_temperature()
+ if(old_light_modifier && current_weather.light_modifier != old_light_modifier) // Updating the sun should be done sparingly.
+ our_planet.update_sun()
+ message_admins("[our_planet.name]'s weather is now [new_weather], with a temperature of [temperature]°K ([temperature - T0C]°C | [temperature * 1.8 - 459.67]°F).")
+
+/datum/weather_holder/proc/process()
+ if(world.time >= next_weather_shift)
+ var/new_weather
+ if(!current_weather)
+ new_weather = pickweight(roundstart_weather_chances)
+ else
+ new_weather = pickweight(current_weather.transition_chances)
+ change_weather(new_weather)
+ else
+ current_weather.process_effects()
+
+/datum/weather_holder/proc/update_icon_effects()
+ set background = 1
+ set waitfor = 0
+ if(current_weather)
+ for(var/turf/simulated/floor/T in outdoor_turfs)
+ if(T.z in our_planet.expected_z_levels)
+ T.overlays -= T.weather_overlay
+ T.weather_overlay = image(icon = current_weather.icon, icon_state = current_weather.icon_state, layer = LIGHTING_LAYER - 1)
+ T.overlays += T.weather_overlay
+
+/datum/weather_holder/proc/update_temperature()
+ temperature = Interpolate(current_weather.temp_low, current_weather.temp_high, weight = our_planet.sun_position)
+
+ for(var/turf/unsimulated/wall/planetary/wall in planetary_walls)
+ if(ispath(wall.type, planetary_wall_type))
+ wall.temperature = temperature
+ for(var/dir in cardinal)
+ var/turf/simulated/T = get_step(wall, dir)
+ if(istype(T))
+ if(T.zone)
+ T.zone.rebuild()
+
+
+/datum/weather_holder/proc/get_weather_datum(desired_type)
+ return allowed_weather_types[desired_type]
+
+/datum/weather_holder/sif
+ temperature = T0C
+ allowed_weather_types = list(
+ WEATHER_CLEAR = new /datum/weather/sif/clear(),
+ WEATHER_OVERCAST = new /datum/weather/sif/overcast(),
+ WEATHER_LIGHT_SNOW = new /datum/weather/sif/light_snow(),
+ WEATHER_SNOW = new /datum/weather/sif/snow(),
+ WEATHER_BLIZZARD = new /datum/weather/sif/blizzard(),
+ WEATHER_RAIN = new /datum/weather/sif/rain(),
+ WEATHER_STORM = new /datum/weather/sif/storm(),
+ WEATHER_HAIL = new /datum/weather/sif/hail(),
+ WEATHER_BLOOD_MOON = new /datum/weather/sif/blood_moon()
+ )
+ planetary_wall_type = /turf/unsimulated/wall/planetary/sif
+ roundstart_weather_chances = list(
+ WEATHER_CLEAR = 30,
+ WEATHER_OVERCAST = 30,
+ WEATHER_LIGHT_SNOW = 20,
+ WEATHER_SNOW = 5,
+ WEATHER_BLIZZARD = 5,
+ WEATHER_RAIN = 5,
+ WEATHER_STORM = 2.5,
+ WEATHER_HAIL = 2.5
+ )
+
+/datum/weather
+ var/name = "weather base"
+ var/icon = 'icons/effects/weather.dmi'
+ var/icon_state = null // Icon to apply to turf undergoing weather.
+ var/temp_high = T20C
+ var/temp_low = T0C
+ var/light_modifier = 1.0 // Lower numbers means more darkness.
+ var/light_color = null // If set, changes how the day/night light looks.
+ var/transition_chances = list() // Assoc list
+ var/datum/weather_holder/holder = null
+
+/datum/weather/proc/process_effects()
+ return
+
+/datum/weather/sif
+ name = "sif base"
+ temp_high = 243.15 // -20c
+ temp_low = 233.15 // -30c
+
+/datum/weather/sif/clear
+ name = "clear"
+ transition_chances = list(
+ WEATHER_CLEAR = 60,
+ WEATHER_OVERCAST = 40
+ )
+
+/datum/weather/sif/overcast
+ name = "overcast"
+ light_modifier = 0.8
+ transition_chances = list(
+ WEATHER_CLEAR = 25,
+ WEATHER_OVERCAST = 50,
+ WEATHER_LIGHT_SNOW = 10,
+ WEATHER_SNOW = 5,
+ WEATHER_RAIN = 5,
+ WEATHER_HAIL = 5
+ )
+
+/datum/weather/sif/light_snow
+ name = "light snow"
+ icon_state = "snowfall_light"
+ temp_high = 238.15 // -25c
+ temp_low = 228.15 // -35c
+ light_modifier = 0.7
+ transition_chances = list(
+ WEATHER_OVERCAST = 20,
+ WEATHER_LIGHT_SNOW = 50,
+ WEATHER_SNOW = 25,
+ WEATHER_HAIL = 5
+ )
+
+/datum/weather/sif/snow
+ name = "moderate snow"
+ icon_state = "snowfall_med"
+ temp_high = 233.15 // -30c
+ temp_low = 223.15 // -40c
+ light_modifier = 0.5
+ transition_chances = list(
+ WEATHER_LIGHT_SNOW = 20,
+ WEATHER_SNOW = 50,
+ WEATHER_BLIZZARD = 20,
+ WEATHER_HAIL = 5,
+ WEATHER_OVERCAST = 5
+ )
+
+/datum/weather/sif/snow/process_effects()
+ for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
+ for(var/dir_checked in cardinal)
+ var/turf/simulated/floor/T = get_step(S, dir_checked)
+ if(istype(T))
+ if(istype(T, /turf/simulated/floor/outdoors) && prob(33))
+ T.chill()
+
+/datum/weather/sif/blizzard
+ name = "blizzard"
+ icon_state = "snowfall_heavy"
+ temp_high = 223.15 // -40c
+ temp_low = 203.15 // -60c
+ light_modifier = 0.3
+ transition_chances = list(
+ WEATHER_SNOW = 45,
+ WEATHER_BLIZZARD = 40,
+ WEATHER_HAIL = 10,
+ WEATHER_OVERCAST = 5
+ )
+
+/datum/weather/sif/blizzard/process_effects()
+ for(var/turf/simulated/floor/outdoors/snow/S in outdoor_turfs)
+ for(var/dir_checked in cardinal)
+ var/turf/simulated/floor/T = get_step(S, dir_checked)
+ if(istype(T))
+ if(istype(T, /turf/simulated/floor/outdoors) && prob(50))
+ T.chill()
+
+/datum/weather/sif/rain
+ name = "rain"
+ icon_state = "rain"
+ light_modifier = 0.5
+ transition_chances = list(
+ WEATHER_OVERCAST = 25,
+ WEATHER_LIGHT_SNOW = 10,
+ WEATHER_RAIN = 50,
+ WEATHER_STORM = 10,
+ WEATHER_HAIL = 5
+ )
+
+/datum/weather/sif/rain/process_effects()
+ for(var/mob/living/L in living_mob_list)
+ if(L.z in holder.our_planet.expected_z_levels)
+ var/turf/T = get_turf(L)
+ if(!T.outdoors)
+ return // They're indoors, so no need to rain on them.
+
+ L.adjust_fire_stacks(-5)
+ to_chat(L, "Rain falls on you.")
+
+/datum/weather/sif/storm
+ name = "storm"
+ icon_state = "storm"
+ temp_high = 233.15 // -30c
+ temp_low = 213.15 // -50c
+ light_modifier = 0.3
+ transition_chances = list(
+ WEATHER_RAIN = 45,
+ WEATHER_STORM = 40,
+ WEATHER_HAIL = 10,
+ WEATHER_OVERCAST = 5
+ )
+
+/datum/weather/sif/rain/process_effects()
+ for(var/mob/living/L in living_mob_list)
+ if(L.z in holder.our_planet.expected_z_levels)
+ var/turf/T = get_turf(L)
+ if(!T.outdoors)
+ return // They're indoors, so no need to rain on them.
+
+ L.adjust_fire_stacks(-10)
+ to_chat(L, "Rain falls on you, drenching you in water.")
+
+/datum/weather/sif/hail
+ name = "hail"
+ icon_state = "hail"
+ temp_high = 233.15 // -30c
+ temp_low = 213.15 // -50c
+ light_modifier = 0.3
+ transition_chances = list(
+ WEATHER_RAIN = 45,
+ WEATHER_STORM = 10,
+ WEATHER_HAIL = 40,
+ WEATHER_OVERCAST = 5
+ )
+
+/datum/weather/sif/hail/process_effects()
+ for(var/mob/living/L in living_mob_list)
+ if(L.z in holder.our_planet.expected_z_levels)
+ var/turf/T = get_turf(L)
+ if(!T.outdoors)
+ return // They're indoors, so no need to pelt them with ice.
+
+ var/target_zone = pick(BP_ALL)
+ var/amount_blocked = L.run_armor_check(target_zone, "melee")
+
+ if(amount_blocked >= 100)
+ return // No need to apply damage.
+
+ L.apply_damage(rand(5, 10), BRUTE, target_zone, amount_blocked, used_weapon = "hail")
+ to_chat(L, "The hail raining down on you [L.can_feel_pain() ? "hurts" : "damages you"]!")
+
+/datum/weather/sif/blood_moon
+ name = "blood moon"
+ light_modifier = 0.5
+ light_color = "#FF0000"
+ transition_chances = list(
+ WEATHER_BLOODMOON = 100
+ )
diff --git a/code/modules/power/antimatter/control.dm b/code/modules/power/antimatter/control.dm
index 8c7af58346e..c1defc1c757 100644
--- a/code/modules/power/antimatter/control.dm
+++ b/code/modules/power/antimatter/control.dm
@@ -97,6 +97,12 @@
if(2)
if(active) toggle_power()
stability -= rand(10,20)
+ if(3)
+ if(active) toggle_power()
+ stability -= rand(8,15)
+ if(4)
+ if(active) toggle_power()
+ stability -= rand(5,10)
..()
return 0
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 036777ca157..72fbccaa57c 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -701,6 +701,7 @@
var/mob/living/carbon/human/H = user
if(H.species.can_shred(H))
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
user.visible_message("[user.name] slashes at the [src.name]!", "You slash at the [src.name]!")
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
@@ -1192,22 +1193,27 @@ obj/machinery/power/apc/proc/autoset(var/cur_state, var/on)
/obj/machinery/power/apc/ex_act(severity)
switch(severity)
- if(1.0)
+ if(1)
//set_broken() //now qdel() do what we need
if (cell)
- cell.ex_act(1.0) // more lags woohoo
+ cell.ex_act(1) // more lags woohoo
qdel(src)
return
- if(2.0)
+ if(2)
+ if (prob(75))
+ set_broken()
+ if (cell && prob(50))
+ cell.ex_act(2)
+ if(3)
if (prob(50))
set_broken()
if (cell && prob(50))
- cell.ex_act(2.0)
- if(3.0)
+ cell.ex_act(3)
+ if(4)
if (prob(25))
set_broken()
- if (cell && prob(25))
- cell.ex_act(3.0)
+ if (cell && prob(50))
+ cell.ex_act(3)
return
/obj/machinery/power/apc/disconnect_terminal()
diff --git a/code/modules/power/batteryrack.dm b/code/modules/power/batteryrack.dm
index 203227e613b..56e2a485caf 100644
--- a/code/modules/power/batteryrack.dm
+++ b/code/modules/power/batteryrack.dm
@@ -165,7 +165,7 @@
return
if (overcharge_percent >= 140)
if (prob(1))
- empulse(src.loc, 3, 8, 1)
+ empulse(src.loc, 2, 3, 6, 8, 1)
if ((2.4e6+1) to 3.6e6)
if (overcharge_percent >= 115)
if (prob(7))
@@ -174,7 +174,7 @@
return
if (overcharge_percent >= 130)
if (prob(1))
- empulse(src.loc, 3, 8, 1)
+ empulse(src.loc, 2, 3, 6, 8, 1)
if (overcharge_percent >= 150)
if (prob(1))
explosion(src.loc, 0, 1, 3, 5)
@@ -186,7 +186,7 @@
return
if (overcharge_percent >= 125)
if (prob(2))
- empulse(src.loc, 4, 10, 1)
+ empulse(src.loc, 2, 4, 7, 10, 1)
if (overcharge_percent >= 140)
if (prob(1))
explosion(src.loc, 1, 3, 5, 8)
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index c837f502ddc..671d57e04ef 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -129,12 +129,12 @@ var/list/possible_cable_coil_colours = list(
/obj/structure/cable/hide(var/i)
if(istype(loc, /turf))
invisibility = i ? 101 : 0
- updateicon()
+ update_icon()
/obj/structure/cable/hides_under_flooring()
return 1
-/obj/structure/cable/proc/updateicon()
+/obj/structure/cable/update_icon()
icon_state = "[d1]-[d2]"
alpha = invisibility ? 127 : 255
@@ -635,102 +635,75 @@ obj/structure/cable/proc/cableColor(var/colorC)
//////////////////////////////////////////////
// called when cable_coil is clicked on a turf/simulated/floor
-/obj/item/stack/cable_coil/proc/turf_place(turf/simulated/floor/F, mob/user)
+/obj/item/stack/cable_coil/proc/turf_place(turf/simulated/F, mob/user)
if(!isturf(user.loc))
return
if(get_amount() < 1) // Out of cable
- user << "There is no cable left."
+ to_chat(user, "There is no cable left.")
return
if(get_dist(F,user) > 1) // Too far
- user << "You can't lay cable at a place that far away."
+ to_chat(user, "You can't lay cable at a place that far away.")
return
if(!F.is_plating()) // Ff floor is intact, complain
- user << "You can't lay cable there unless the floor tiles are removed."
+ to_chat(user, "You can't lay cable there unless the floor tiles are removed.")
return
+ var/dirn
+ if(user.loc == F)
+ dirn = user.dir // if laying on the tile we're on, lay in the direction we're facing
else
- var/dirn
+ dirn = get_dir(F, user)
- if(user.loc == F)
- dirn = user.dir // if laying on the tile we're on, lay in the direction we're facing
- else
- dirn = get_dir(F, user)
+ var/end_dir = 0
+ if(istype(F, /turf/simulated/open))
+ if(!can_use(2))
+ to_chat(user, "You don't have enough cable to do this!")
+ return
+ end_dir = DOWN
- for(var/obj/structure/cable/LC in F)
- if((LC.d1 == dirn && LC.d2 == 0 ) || ( LC.d2 == dirn && LC.d1 == 0))
- user << "There's already a cable at that position."
- return
-///// Z-Level Stuff
- // check if the target is open space
- if(istype(F, /turf/simulated/open))
- for(var/obj/structure/cable/LC in F)
- if((LC.d1 == dirn && LC.d2 == 11 ) || ( LC.d2 == dirn && LC.d1 == 11))
- user << "There's already a cable at that position."
- return
+ for(var/obj/structure/cable/LC in F)
+ if((LC.d1 == dirn && LC.d2 == end_dir ) || ( LC.d2 == dirn && LC.d1 == end_dir))
+ to_chat(user, "There's already a cable at that position.")
+ return
- var/obj/structure/cable/C = new(F)
- var/obj/structure/cable/D = new(GetBelow(F))
+ put_cable(F, user, end_dir, dirn)
+ if(end_dir == DOWN)
+ put_cable(GetBelow(F), user, UP, 0)
+ to_chat(user, "You slide some cable downward.")
- C.cableColor(color)
+/obj/item/stack/cable_coil/proc/put_cable(turf/simulated/F, mob/user, d1, d2)
+ if(!istype(F))
+ return
- C.d1 = 11
- C.d2 = dirn
- C.add_fingerprint(user)
- C.updateicon()
+ var/obj/structure/cable/C = new(F)
+ C.cableColor(color)
+ C.d1 = d1
+ C.d2 = d2
+ C.add_fingerprint(user)
+ C.update_icon()
- var/datum/powernet/PN = new()
- PN.add_cable(C)
+ //create a new powernet with the cable, if needed it will be merged later
+ var/datum/powernet/PN = new()
+ PN.add_cable(C)
- C.mergeConnectedNetworks(C.d2)
- C.mergeConnectedNetworksOnTurf()
+ C.mergeConnectedNetworks(C.d1) //merge the powernets...
+ C.mergeConnectedNetworks(C.d2) //...in the two new cable directions
+ C.mergeConnectedNetworksOnTurf()
- D.cableColor(color)
+ if(C.d1 & (C.d1 - 1))// if the cable is layed diagonally, check the others 2 possible directions
+ C.mergeDiagonalsNetworks(C.d1)
- D.d1 = 12
- D.d2 = 0
- D.add_fingerprint(user)
- D.updateicon()
+ if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
+ C.mergeDiagonalsNetworks(C.d2)
- PN.add_cable(D)
- D.mergeConnectedNetworksOnTurf()
-
- // do the normal stuff
- else
-///// Z-Level Stuff
- for(var/obj/structure/cable/LC in F)
- if((LC.d1 == dirn && LC.d2 == 0 ) || ( LC.d2 == dirn && LC.d1 == 0))
- user << "There's already a cable at that position."
- return
-
- var/obj/structure/cable/C = new(F)
-
- C.cableColor(color)
-
- //set up the new cable
- C.d1 = 0 //it's a O-X node cable
- C.d2 = dirn
- C.add_fingerprint(user)
- C.updateicon()
-
- //create a new powernet with the cable, if needed it will be merged later
- var/datum/powernet/PN = new()
- PN.add_cable(C)
-
- C.mergeConnectedNetworks(C.d2) //merge the powernet with adjacents powernets
- C.mergeConnectedNetworksOnTurf() //merge the powernet with on turf powernets
-
- if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
- C.mergeDiagonalsNetworks(C.d2)
-
-
- use(1)
- if (C.shock(user, 50))
- if (prob(50)) //fail
- new/obj/item/stack/cable_coil(C.loc, 1, C.color)
- qdel(C)
+ use(1)
+ if (C.shock(user, 50))
+ if (prob(50)) //fail
+ new/obj/item/stack/cable_coil(C.loc, 1, C.color)
+ qdel(C)
// called when cable_coil is click on an installed obj/cable
// or click on a turf that already contains a "node" cable
@@ -745,10 +718,9 @@ obj/structure/cable/proc/cableColor(var/colorC)
return
if(get_dist(C, user) > 1) // make sure it's close enough
- user << "You can't lay cable at a place that far away."
+ to_chat(user, "You can't lay cable at a place that far away.")
return
-
if(U == T) //if clicked on the turf we're standing on, try to put a cable in the direction we're facing
turf_place(T,user)
return
@@ -758,7 +730,7 @@ obj/structure/cable/proc/cableColor(var/colorC)
// one end of the clicked cable is pointing towards us
if(C.d1 == dirn || C.d2 == dirn)
if(!U.is_plating()) // can't place a cable if the floor is complete
- user << "You can't lay cable there unless the floor tiles are removed."
+ to_chat(user, "You can't lay cable there unless the floor tiles are removed.")
return
else
// cable is pointing at us, we're standing on an open tile
@@ -768,34 +740,9 @@ obj/structure/cable/proc/cableColor(var/colorC)
for(var/obj/structure/cable/LC in U) // check to make sure there's not a cable there already
if(LC.d1 == fdirn || LC.d2 == fdirn)
- user << "There's already a cable at that position."
+ to_chat(user, "There's already a cable at that position.")
return
-
- var/obj/structure/cable/NC = new(U)
- NC.cableColor(color)
-
- NC.d1 = 0
- NC.d2 = fdirn
- NC.add_fingerprint()
- NC.updateicon()
-
- //create a new powernet with the cable, if needed it will be merged later
- var/datum/powernet/newPN = new()
- newPN.add_cable(NC)
-
- NC.mergeConnectedNetworks(NC.d2) //merge the powernet with adjacents powernets
- NC.mergeConnectedNetworksOnTurf() //merge the powernet with on turf powernets
-
- if(NC.d2 & (NC.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
- NC.mergeDiagonalsNetworks(NC.d2)
-
- use(1)
-
- if (NC.shock(user, 50))
- if (prob(50)) //fail
- new/obj/item/stack/cable_coil(NC.loc, 1, NC.color)
- qdel(NC)
-
+ put_cable(U,user,0,fdirn)
return
// exisiting cable doesn't point at our position, so see if it's a stub
@@ -814,7 +761,7 @@ obj/structure/cable/proc/cableColor(var/colorC)
if(LC == C) // skip the cable we're interacting with
continue
if((LC.d1 == nd1 && LC.d2 == nd2) || (LC.d1 == nd2 && LC.d2 == nd1) ) // make sure no cable matches either direction
- user << "There's already a cable at that position."
+ to_chat(user, "There's already a cable at that position.")
return
@@ -824,7 +771,7 @@ obj/structure/cable/proc/cableColor(var/colorC)
C.d2 = nd2
C.add_fingerprint()
- C.updateicon()
+ C.update_icon()
C.mergeConnectedNetworks(C.d1) //merge the powernets...
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index e36f00c0277..09921cf58ba 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -527,6 +527,7 @@
if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
if(H.species.can_shred(H))
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
for(var/mob/M in viewers(src))
M.show_message("\red [user.name] smashed the light!", 3, "You hear a tinkle of breaking glass", 2)
broken()
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 41e182b91bc..f900f6fcf45 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -10,7 +10,6 @@
var/active = 0
var/power_gen = 5000
- var/open = 0
var/recent_fault = 0
var/power_output = 1
@@ -52,9 +51,9 @@
if(!..(user,1 ))
return
if(active)
- usr << "\blue The generator is on."
+ usr << "The generator is on."
else
- usr << "\blue The generator is off."
+ usr << "The generator is off."
/obj/machinery/power/port_gen/emp_act(severity)
var/duration = 6000 //ten minutes
@@ -63,9 +62,12 @@
stat &= BROKEN
if(prob(75)) explode()
if(2)
- if(prob(25)) stat &= BROKEN
+ if(prob(50)) stat &= BROKEN
if(prob(10)) explode()
if(3)
+ if(prob(25)) stat &= BROKEN
+ duration = 300
+ if(4)
if(prob(10)) stat &= BROKEN
duration = 300
@@ -85,10 +87,9 @@
/obj/machinery/power/port_gen/pacman
name = "\improper P.A.C.M.A.N.-type Portable Generator"
desc = "A power generator that runs on solid phoron sheets. Rated for 80 kW max safe output."
-
+ circuit = /obj/item/weapon/circuitboard/pacman
var/sheet_name = "Phoron Sheets"
var/sheet_path = /obj/item/stack/material/phoron
- var/board_path = "/obj/item/weapon/circuitboard/pacman"
/*
These values were chosen so that the generator can run safely up to 80 kW
@@ -119,16 +120,19 @@
component_parts = list()
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
component_parts += new /obj/item/weapon/stock_parts/micro_laser(src)
- component_parts += new /obj/item/stack/cable_coil(src)
- component_parts += new /obj/item/stack/cable_coil(src)
+ component_parts += new /obj/item/stack/cable_coil(src, 2)
component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
- component_parts += new board_path(src)
RefreshParts()
/obj/machinery/power/port_gen/pacman/Destroy()
DropFuel()
return ..()
+/obj/machinery/power/port_gen/pacman/dismantle()
+ while ( sheets > 0 )
+ DropFuel()
+ return ..()
+
/obj/machinery/power/port_gen/pacman/RefreshParts()
var/temp_rating = 0
for(var/obj/item/weapon/stock_parts/SP in component_parts)
@@ -259,44 +263,30 @@
var/obj/item/stack/addstack = O
var/amount = min((max_sheets - sheets), addstack.amount)
if(amount < 1)
- user << "\blue The [src.name] is full!"
+ user << "The [src.name] is full!"
return
- user << "\blue You add [amount] sheet\s to the [src.name]."
+ user << "You add [amount] sheet\s to the [src.name]."
sheets += amount
addstack.use(amount)
updateUsrDialog()
return
else if(!active)
if(istype(O, /obj/item/weapon/wrench))
-
if(!anchored)
connect_to_network()
- user << "\blue You secure the generator to the floor."
+ user << "You secure the generator to the floor."
else
disconnect_from_network()
- user << "\blue You unsecure the generator from the floor."
-
+ user << "You unsecure the generator from the floor."
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
anchored = !anchored
-
- else if(istype(O, /obj/item/weapon/screwdriver))
- open = !open
- playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- if(open)
- user << "\blue You open the access panel."
- else
- user << "\blue You close the access panel."
- else if(istype(O, /obj/item/weapon/crowbar) && open)
- var/obj/structure/frame/new_frame = new /obj/structure/frame(src.loc)
- for(var/obj/item/I in component_parts)
- I.loc = src.loc
- while ( sheets > 0 )
- DropFuel()
-
- new_frame.frame_type = "machine"
- new_frame.state = 2
- new_frame.icon_state = "machine_1"
- qdel(src)
+ else if(default_deconstruction_screwdriver(user, O))
+ return
+ else if(default_deconstruction_crowbar(user, O))
+ return
+ else if(default_part_replacement(user, O))
+ return
+ return ..()
/obj/machinery/power/port_gen/pacman/attack_hand(mob/user as mob)
..()
@@ -401,7 +391,7 @@
sheet_path = /obj/item/stack/material/uranium
sheet_name = "Uranium Sheets"
time_per_sheet = 576 //same power output, but a 50 sheet stack will last 2 hours at max safe power
- board_path = "/obj/item/weapon/circuitboard/pacman/super"
+ circuit = /obj/item/weapon/circuitboard/pacman/super
/obj/machinery/power/port_gen/pacman/super/UseFuel()
//produces a tiny amount of radiation when in use
@@ -436,7 +426,7 @@
time_per_sheet = 576
max_temperature = 800
temperature_gain = 90
- board_path = "/obj/item/weapon/circuitboard/pacman/mrs"
+ circuit = /obj/item/weapon/circuitboard/pacman/mrs
/obj/machinery/power/port_gen/pacman/mrs/explode()
//no special effects, but the explosion is pretty big (same as a supermatter shard).
diff --git a/code/modules/power/singularity/act.dm b/code/modules/power/singularity/act.dm
index d244c4eeaa9..6683b48377e 100644
--- a/code/modules/power/singularity/act.dm
+++ b/code/modules/power/singularity/act.dm
@@ -29,7 +29,7 @@
if(current_size >= STAGE_THREE)
var/list/handlist = list(l_hand, r_hand)
for(var/obj/item/hand in handlist)
- if(prob(current_size*5) && hand.w_class >= ((11-current_size)/2) && u_equip(hand))
+ if(prob(current_size*5) && hand.w_class >= ((11-current_size)/2) && unEquip(hand))
step_towards(hand, src)
src << "The [S] pulls \the [hand] from your grip!"
apply_effect(current_size * 3, IRRADIATE)
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index ecdfc0841ea..39090ceac50 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -298,7 +298,7 @@
if(target && prob(60))
movement_dir = get_dir(src,target) //moves to a singulo beacon, if there is one
- if(current_size >= 9)//The superlarge one does not care about things in its way
+ if(current_size >= STAGE_FIVE)//The superlarge one does not care about things in its way
spawn(0)
step(src, movement_dir)
spawn(1)
@@ -319,17 +319,17 @@
var/steps = 0
if(!step)
switch(current_size)
- if(1)
+ if(STAGE_ONE)
steps = 1
- if(3)
+ if(STAGE_TWO)
steps = 3//Yes this is right
- if(5)
+ if(STAGE_THREE)
steps = 3
- if(7)
+ if(STAGE_FOUR)
steps = 4
- if(9)
+ if(STAGE_FIVE)
steps = 5
- if(11)
+ if(STAGE_SUPER)
steps = 6
else
steps = step
@@ -397,7 +397,7 @@
mezzer()
else
return 0
- if(current_size == 11)
+ if(current_size == STAGE_SUPER)
smwave()
return 1
@@ -429,21 +429,21 @@
if(M.stat == CONSCIOUS)
if (istype(M,/mob/living/carbon/human))
var/mob/living/carbon/human/H = M
- if(istype(H.glasses,/obj/item/clothing/glasses/meson) && current_size != 11)
+ if(istype(H.glasses,/obj/item/clothing/glasses/meson) && current_size != STAGE_SUPER)
H << "You look directly into The [src.name], good thing you had your protective eyewear on!"
return
else
H << "You look directly into The [src.name], but your eyewear does absolutely nothing to protect you from it!"
- M << "You look directly into The [src.name] and feel [current_size == 11 ? "helpless" : "weak"]."
+ M << "You look directly into The [src.name] and feel [current_size == STAGE_SUPER ? "helpless" : "weak"]."
M.apply_effect(3, STUN)
for(var/mob/O in viewers(M, null))
O.show_message(text("[] stares blankly at The []!", M, src), 1)
/obj/singularity/proc/emp_area()
- if(current_size != 11)
- empulse(src, 8, 10)
+ if(current_size != STAGE_SUPER)
+ empulse(src, 4, 6, 8, 10)
else
- empulse(src, 12, 16)
+ empulse(src, 12, 14, 16, 18)
/obj/singularity/proc/smwave()
for(var/mob/living/M in view(10, src.loc))
@@ -467,15 +467,15 @@
overlays = 0
move_self = 0
switch (current_size)
- if(1)
+ if(STAGE_ONE)
overlays += image('icons/obj/singularity.dmi',"chain_s1")
- if(3)
+ if(STAGE_TWO)
overlays += image('icons/effects/96x96.dmi',"chain_s3")
- if(5)
+ if(STAGE_THREE)
overlays += image('icons/effects/160x160.dmi',"chain_s5")
- if(7)
+ if(STAGE_FOUR)
overlays += image('icons/effects/224x224.dmi',"chain_s7")
- if(9)
+ if(STAGE_FIVE)
overlays += image('icons/effects/288x288.dmi',"chain_s9")
/obj/singularity/proc/on_release()
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index 12076ac4992..61d5374cad8 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -377,7 +377,7 @@
/obj/machinery/power/smes/proc/ion_act()
- if(src.z in config.station_levels)
+ if(src.z in using_map.station_levels)
if(prob(1)) //explosion
for(var/mob/M in viewers(src))
M.show_message("\red The [src.name] is making strange noises!", 3, "\red You hear sizzling electronics.", 2)
@@ -393,10 +393,14 @@
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
- if(prob(50))
+ if(prob(25))
emp_act(1)
- else
+ else if(prob(25))
emp_act(2)
+ else if(prob(25))
+ emp_act(3)
+ else
+ emp_act(4)
if(prob(5)) //smoke only
var/datum/effect/effect/system/smoke_spread/smoke = new /datum/effect/effect/system/smoke_spread()
smoke.set_up(3, 0, src.loc)
diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm
index 2f0fe9419d9..c71f0e35e7f 100644
--- a/code/modules/power/smes_construction.dm
+++ b/code/modules/power/smes_construction.dm
@@ -212,7 +212,7 @@
h_user.adjustFireLoss(rand(10,25))
h_user.Paralyse(5)
spawn(0)
- empulse(src.loc, 2, 4)
+ empulse(src.loc, 1, 2, 3, 4)
charge = 0
if (36 to 60)
@@ -229,7 +229,7 @@
h_user.adjustFireLoss(rand(35,75))
h_user.Paralyse(12)
spawn(0)
- empulse(src.loc, 8, 16)
+ empulse(src.loc, 6, 8, 12, 16)
charge = 0
apcs_overload(1, 10)
src.ping("Caution. Output regulators malfunction. Uncontrolled discharge detected.")
diff --git a/code/modules/projectiles/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm
index 2ca770dff5a..ae55edeb00f 100644
--- a/code/modules/projectiles/ammunition/boxes.dm
+++ b/code/modules/projectiles/ammunition/boxes.dm
@@ -26,6 +26,10 @@
name = "speedloader (.38 rubber)"
ammo_type = /obj/item/ammo_casing/c38r
+/obj/item/ammo_magazine/c38/emp
+ name = "ammunition box (.38 haywire)"
+ ammo_type = /obj/item/ammo_casing/c38/emp
+
///////// .45 /////////
/obj/item/ammo_magazine/c45m
@@ -57,6 +61,10 @@
name = "magazine (.45 AP)"
ammo_type = /obj/item/ammo_casing/c45ap
+/obj/item/ammo_magazine/box/emp/c45
+ name = "ammunition box (.45 haywire)"
+ ammo_type = /obj/item/ammo_casing/c45/emp
+
/obj/item/ammo_magazine/c45uzi
name = "stick magazine (.45)"
icon_state = "uzi45"
@@ -272,6 +280,10 @@
max_ammo = 9
multiple_sprites = 1
+/obj/item/ammo_magazine/box/emp/a10mm
+ name = "ammunition box (10mm haywire)"
+ ammo_type = /obj/item/ammo_casing/a10mm/emp
+
///////// 5.56mm /////////
/obj/item/ammo_magazine/a556
diff --git a/code/modules/projectiles/ammunition/bullets.dm b/code/modules/projectiles/ammunition/bullets.dm
index 2fca9a3ffd2..ace4cb1fb8c 100644
--- a/code/modules/projectiles/ammunition/bullets.dm
+++ b/code/modules/projectiles/ammunition/bullets.dm
@@ -24,6 +24,13 @@
icon_state = "r-casing"
projectile_type = /obj/item/projectile/bullet/pistol/rubber
+/obj/item/ammo_casing/c38/emp
+ name = ".38 haywire round"
+ desc = "A .38 bullet casing fitted with a single-use ion pulse generator."
+ icon_state = "empcasing"
+ projectile_type = /obj/item/projectile/ion/small
+ matter = list(DEFAULT_WALL_MATERIAL = 130, "uranium" = 100)
+
/obj/item/ammo_casing/c9mm
desc = "A 9mm bullet casing."
caliber = "9mm"
@@ -87,11 +94,24 @@
icon_state = "r-casing"
projectile_type = /obj/item/projectile/energy/flash
+/obj/item/ammo_casing/c45/emp
+ name = ".45 haywire round"
+ desc = "A .45 bullet casing fitted with a single-use ion pulse generator."
+ projectile_type = /obj/item/projectile/ion/small
+ icon_state = "empcasing"
+ matter = list(DEFAULT_WALL_MATERIAL = 130, "uranium" = 100)
+
/obj/item/ammo_casing/a10mm
desc = "A 10mm bullet casing."
caliber = "10mm"
projectile_type = /obj/item/projectile/bullet/pistol/medium
+/obj/item/ammo_casing/a10mm/emp
+ name = "10mm haywire round"
+ desc = "A 10mm bullet casing fitted with a single-use ion pulse generator."
+ projectile_type = /obj/item/projectile/ion/small
+ icon_state = "empcasing"
+ matter = list(DEFAULT_WALL_MATERIAL = 130, "uranium" = 100)
/obj/item/ammo_casing/shotgun
name = "shotgun slug"
@@ -150,13 +170,13 @@
projectile_type = /obj/item/projectile/energy/flash/flare
matter = list(DEFAULT_WALL_MATERIAL = 90, "glass" = 90)
-
/obj/item/ammo_casing/shotgun/emp
name = "ion shell"
desc = "An advanced shotgun round that creates a small EMP when it strikes a target."
icon_state = "empshell"
- projectile_type = /obj/item/projectile/bullet/shotgun/ion
- matter = list(DEFAULT_WALL_MATERIAL = 360, "glass" = 720)
+ projectile_type = /obj/item/projectile/ion
+// projectile_type = /obj/item/projectile/bullet/shotgun/ion
+ matter = list(DEFAULT_WALL_MATERIAL = 360, "uranium" = 240)
/obj/item/ammo_casing/a762
desc = "A 7.62mm bullet casing."
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 4443775df5b..faafd2e8c95 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -12,14 +12,18 @@
projectile_type = /obj/item/projectile/ion
/obj/item/weapon/gun/energy/ionrifle/emp_act(severity)
- ..(max(severity, 2)) //so it doesn't EMP itself, I guess
+ ..(max(severity, 4)) //so it doesn't EMP itself, I guess
-/obj/item/weapon/gun/energy/ionrifle/update_icon()
- ..()
- if(power_supply.charge < charge_cost)
- item_state = "ionrifle0"
- else
- item_state = initial(item_state)
+/obj/item/weapon/gun/energy/ionrifle/pistol
+ name = "ion pistol"
+ desc = "The NT Mk63 EW Pan is a man portable anti-armor weapon designed to disable mechanical threats, produced by NT. This model sacrifices capacity for portability.."
+ icon_state = "ionpistol"
+ item_state = null
+ w_class = ITEMSIZE_NORMAL
+ force = 5
+ slot_flags = SLOT_BELT
+ charge_cost = 480
+ projectile_type = /obj/item/projectile/ion
/obj/item/weapon/gun/energy/decloner
name = "biological demolecularisor"
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index 7de8e7b8777..1e95f4a213f 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -76,6 +76,10 @@
fire_sound = 'sound/weapons/Gunshot_light.ogg'
ammo_type = /obj/item/ammo_casing/c38
+/obj/item/weapon/gun/projectile/revolver/deckard/emp
+ ammo_type = /obj/item/ammo_casing/c38/emp
+
+
/obj/item/weapon/gun/projectile/revolver/deckard/update_icon()
..()
if(loaded.len)
diff --git a/code/modules/projectiles/guns/vox.dm b/code/modules/projectiles/guns/vox.dm
index c1e0e84cf80..857b56fa6b7 100644
--- a/code/modules/projectiles/guns/vox.dm
+++ b/code/modules/projectiles/guns/vox.dm
@@ -57,6 +57,7 @@
icon_state = "darkcannon"
item_state = "darkcannon"
fire_sound = 'sound/weapons/eLuger.ogg'
+ w_class = ITEMSIZE_HUGE
charge_cost = 600
projectile_type = /obj/item/projectile/beam/darkmatter
self_recharge = 1
@@ -102,6 +103,7 @@
icon_state = "noise"
item_state = "noise"
fire_sound = 'sound/effects/basscannon.ogg'
+ w_class = ITEMSIZE_HUGE
self_recharge = 1
charge_cost = 600
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 29d130612f0..f87f726bf3e 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -172,7 +172,8 @@
range_step = 1
spread_step = 10
-//EMP shotgun 'slug', it's basically a beanbag that pops a tiny emp when it hits.
+
+//EMP shotgun 'slug', it's basically a beanbag that pops a tiny emp when it hits. //Not currently used
/obj/item/projectile/bullet/shotgun/ion
name = "ion slug"
damage = 15
@@ -182,9 +183,10 @@
/obj/item/projectile/bullet/shotgun/ion/on_hit(var/atom/target, var/blocked = 0)
..()
- empulse(target, 0, 0) //Only affects what it hits
+ empulse(target, 0, 0, 0, 0) //Only affects what it hits
return 1
+
/* "Rifle" rounds */
/obj/item/projectile/bullet/rifle
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index 5345f06dc93..54a2d301c7f 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -6,7 +6,6 @@
check_armour = "energy"
var/flash_strength = 10
-
//releases a burst of light on impact or after travelling a distance
/obj/item/projectile/energy/flash
name = "chemical shell"
@@ -64,10 +63,8 @@
/obj/item/projectile/energy/electrode
name = "electrode"
icon_state = "spark"
- nodamage = 1
taser_effect = 1
agony = 40
- damage_type = HALLOSS
light_range = 2
light_power = 0.5
light_color = "#FFFFFF"
@@ -79,7 +76,6 @@
/obj/item/projectile/energy/electrode/stunshot
name = "stunshot"
damage = 5
- taser_effect = 1
agony = 80
/obj/item/projectile/energy/declone
@@ -107,7 +103,6 @@
icon_state = "cbbolt"
damage = 10
damage_type = TOX
- nodamage = 0
agony = 40
stutter = 10
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index 8aba3c0928d..b507afc3167 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -8,12 +8,16 @@
light_range = 2
light_power = 0.5
light_color = "#55AAFF"
+ var/pulse_range = 1
on_hit(var/atom/target, var/blocked = 0)
- empulse(target, 1, 1)
+ empulse(target, pulse_range, pulse_range, pulse_range, pulse_range)
return 1
+/obj/item/projectile/ion/small
+ pulse_range = 0
+
/obj/item/projectile/bullet/gyro
name ="explosive bolt"
icon_state= "bolter"
diff --git a/code/modules/projectiles/targeting/targeting_overlay.dm b/code/modules/projectiles/targeting/targeting_overlay.dm
index 8c87751de7a..2dcf0032bea 100644
--- a/code/modules/projectiles/targeting/targeting_overlay.dm
+++ b/code/modules/projectiles/targeting/targeting_overlay.dm
@@ -107,8 +107,10 @@ obj/aiming_overlay/proc/update_aiming_deferred()
cancel_aiming()
return
- if(!locked && lock_time >= world.time)
+ if(!locked && lock_time <= world.time)
locked = 1
+ owner << "You are locked onto your target."
+ aiming_at << "The gun is trained on you!"
update_icon()
var/cancel_aim = 1
@@ -176,7 +178,7 @@ obj/aiming_overlay/proc/update_aiming_deferred()
toggle_active(1)
locked = 0
update_icon()
- lock_time = world.time + 35
+ lock_time = world.time + 25
/obj/aiming_overlay/update_icon()
if(locked)
diff --git a/code/modules/projectiles/targeting/targeting_triggers.dm b/code/modules/projectiles/targeting/targeting_triggers.dm
index 2544fae9132..188440dcf6d 100644
--- a/code/modules/projectiles/targeting/targeting_triggers.dm
+++ b/code/modules/projectiles/targeting/targeting_triggers.dm
@@ -27,3 +27,5 @@
var/obj/item/weapon/gun/G = aiming_with
if(istype(G))
G.Fire(aiming_at, owner, reflex = 1)
+ locked = 0
+ lock_time = world.time+10
diff --git a/code/modules/random_map/drop/drop_types.dm b/code/modules/random_map/drop/drop_types.dm
index d125fcebbfd..514e173896f 100644
--- a/code/modules/random_map/drop/drop_types.dm
+++ b/code/modules/random_map/drop/drop_types.dm
@@ -112,7 +112,7 @@ datum/supply_drop_loot/riot
/obj/item/weapon/melee/baton,
/obj/item/clothing/glasses/sunglasses/sechud/tactical,
/obj/item/weapon/storage/belt/security,
- /obj/item/clothing/shoes/jackboots,
+ /obj/item/clothing/shoes/boots/jackboots,
/obj/item/clothing/gloves/black,
/obj/item/weapon/gun/projectile/shotgun/pump,
/obj/item/weapon/gun/energy/gun,
diff --git a/code/modules/random_map/noise/ore.dm b/code/modules/random_map/noise/ore.dm
index 4caacb70995..697a0b416d8 100644
--- a/code/modules/random_map/noise/ore.dm
+++ b/code/modules/random_map/noise/ore.dm
@@ -49,11 +49,11 @@
if(!priority_process) sleep(-1)
T.resources = list()
T.resources["silicates"] = rand(3,5)
- T.resources["carbonaceous rock"] = rand(3,5)
+ T.resources["carbon"] = rand(3,5)
var/current_cell = map[get_map_cell(x,y)]
if(current_cell < rare_val) // Surface metals.
- T.resources["iron"] = rand(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX)
+ T.resources["hematite"] = rand(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX)
T.resources["gold"] = rand(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX)
T.resources["silver"] = rand(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX)
T.resources["uranium"] = rand(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX)
@@ -69,14 +69,14 @@
T.resources["osmium"] = rand(RESOURCE_MID_MIN, RESOURCE_MID_MAX)
T.resources["hydrogen"] = 0
T.resources["diamond"] = 0
- T.resources["iron"] = 0
+ T.resources["hematite"] = 0
else // Deep metals.
T.resources["uranium"] = rand(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX)
T.resources["diamond"] = rand(RESOURCE_LOW_MIN, RESOURCE_LOW_MAX)
T.resources["phoron"] = rand(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX)
T.resources["osmium"] = rand(RESOURCE_HIGH_MIN, RESOURCE_HIGH_MAX)
T.resources["hydrogen"] = rand(RESOURCE_MID_MIN, RESOURCE_MID_MAX)
- T.resources["iron"] = 0
+ T.resources["hematite"] = 0
T.resources["gold"] = 0
T.resources["silver"] = 0
return
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm
index 38f558721ea..5be9ed93c23 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/Chemistry-Machinery.dm
@@ -47,27 +47,27 @@
/obj/machinery/chem_master/attackby(var/obj/item/weapon/B as obj, var/mob/user as mob)
- if(istype(B, /obj/item/weapon/reagent_containers/glass))
+ if(istype(B, /obj/item/weapon/reagent_containers/glass) || istype(B, /obj/item/weapon/reagent_containers/food))
if(src.beaker)
- user << "A beaker is already loaded into the machine."
+ user << "\A [beaker] is already loaded into the machine."
return
src.beaker = B
user.drop_item()
B.loc = src
- user << "You add the beaker to the machine!"
+ user << "You add \the [B] to the machine!"
icon_state = "mixer1"
else if(istype(B, /obj/item/weapon/storage/pill_bottle))
if(src.loaded_pill_bottle)
- user << "A pill bottle is already loaded into the machine."
+ user << "A \the [loaded_pill_bottle] s already loaded into the machine."
return
src.loaded_pill_bottle = B
user.drop_item()
B.loc = src
- user << "You add the pill bottle into the dispenser slot!"
+ user << "You add \the [loaded_pill_bottle] into the dispenser slot!"
return
/obj/machinery/chem_master/attack_hand(mob/user as mob)
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
index 5cff9231a1f..95f661d7a54 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
@@ -28,9 +28,10 @@
var/totalFlavor = 0
for(var/taste in data)
totalFlavor += data[taste]
- for(var/taste in data)
- if(data[taste]/totalFlavor < 0.1)
- data -= taste
+ if(totalFlavor) //Let's not divide by zero for things w/o taste
+ for(var/taste in data)
+ if(data[taste]/totalFlavor < 0.1)
+ data -= taste
/datum/reagent/nutriment/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
if(!injectable)
@@ -114,7 +115,7 @@
M.drowsyness = max(M.drowsyness, 60)
/datum/reagent/nutriment/flour
- name = "flour"
+ name = "Flour"
id = "flour"
description = "This is what you rub all over yourself to pretend to be a ghost."
taste_description = "chalky wheat"
@@ -699,6 +700,71 @@
cup_name = "cup of iced tea"
cup_desc = "No relation to a certain rap artist/ actor."
+/datum/reagent/drink/tea/minttea
+ name = "Mint Tea"
+ id = "minttea"
+ description = "A tasty mixture of mint and tea. It's apparently good for you!"
+ color = "#A8442C"
+ taste_description = "black tea with tones of mint"
+
+ glass_name = "mint tea"
+ glass_desc = "A tasty mixture of mint and tea. It's apparently good for you!"
+
+ cup_name = "cup of mint tea"
+ cup_desc = "A tasty mixture of mint and tea. It's apparently good for you!"
+
+/datum/reagent/drink/tea/lemontea
+ name = "Lemon Tea"
+ id = "lemontea"
+ description = "A tasty mixture of lemon and tea. It's apparently good for you!"
+ color = "#FC6A00"
+ taste_description = "black tea with tones of lemon"
+
+ glass_name = "lemon tea"
+ glass_desc = "A tasty mixture of lemon and tea. It's apparently good for you!"
+
+ cup_name = "cup of lemon tea"
+ cup_desc = "A tasty mixture of lemon and tea. It's apparently good for you!"
+
+/datum/reagent/drink/tea/limetea
+ name = "Lime Tea"
+ id = "limetea"
+ description = "A tasty mixture of lime and tea. It's apparently good for you!"
+ color = "#DE4300"
+ taste_description = "black tea with tones of lime"
+
+ glass_name = "lime tea"
+ glass_desc = "A tasty mixture of lime and tea. It's apparently good for you!"
+
+ cup_name = "cup of berry tea"
+ cup_desc = "A tasty mixture of lime and tea. It's apparently good for you!"
+
+/datum/reagent/drink/tea/orangetea
+ name = "Orange Tea"
+ id = "orangetea"
+ description = "A tasty mixture of orange and tea. It's apparently good for you!"
+ color = "#FB4F06"
+ taste_description = "black tea with tones of orange"
+
+ glass_name = "orange tea"
+ glass_desc = "A tasty mixture of orange and tea. It's apparently good for you!"
+
+ cup_name = "cup of orange tea"
+ cup_desc = "A tasty mixture of orange and tea. It's apparently good for you!"
+
+/datum/reagent/drink/tea/berrytea
+ name = "Berry Tea"
+ id = "berrytea"
+ description = "A tasty mixture of berries and tea. It's apparently good for you!"
+ color = "#A60735"
+ taste_description = "black tea with tones of berries"
+
+ glass_name = "berry tea"
+ glass_desc = "A tasty mixture of berries and tea. It's apparently good for you!"
+
+ cup_name = "cup of berry tea"
+ cup_desc = "A tasty mixture of berries and tea. It's apparently good for you!"
+
/datum/reagent/drink/coffee
name = "Coffee"
id = "coffee"
@@ -2165,3 +2231,4 @@
glass_name = "special blend whiskey"
glass_desc = "Just when you thought regular station whiskey was good... This silky, amber goodness has to come along and ruin everything."
+
diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm
index 8f0e3f4d7bf..dbe8ca528f1 100644
--- a/code/modules/reagents/Chemistry-Recipes.dm
+++ b/code/modules/reagents/Chemistry-Recipes.dm
@@ -581,7 +581,6 @@
required_reagents = list("mindbreaker" = 1, "carbon" = 1)
result_amount = 3
-
/datum/chemical_reaction/paroxetine
name = "Paroxetine"
id = "paroxetine"
@@ -589,6 +588,20 @@
required_reagents = list("mindbreaker" = 1, "oxygen" = 1, "inaprovaline" = 1)
result_amount = 3
+/datum/chemical_reaction/neurotoxin
+ name = "Neurotoxin"
+ id = "neurotoxin"
+ result = "neurotoxin"
+ required_reagents = list("gargleblaster" = 1, "stoxin" = 1)
+ result_amount = 2
+
+/datum/chemical_reaction/luminol
+ name = "Luminol"
+ id = "luminol"
+ result = "luminol"
+ required_reagents = list("hydrogen" = 2, "carbon" = 2, "ammonia" = 2)
+ result_amount = 6
+
/* Solidification */
/datum/chemical_reaction/phoronsolidification
@@ -676,7 +689,7 @@
var/location = get_turf(holder.my_atom)
// 100 created volume = 4 heavy range & 7 light range. A few tiles smaller than traitor EMP grandes.
// 200 created volume = 8 heavy range & 14 light range. 4 tiles larger than traitor EMP grenades.
- empulse(location, round(created_volume / 24), round(created_volume / 14), 1)
+ empulse(location, round(created_volume / 24), round(created_volume / 20), round(created_volume / 18), round(created_volume / 14), 1)
holder.clear_reagents()
return
@@ -1051,7 +1064,7 @@
/* Food */
-/datum/chemical_reaction/tofu
+/datum/chemical_reaction/food/tofu
name = "Tofu"
id = "tofu"
result = null
@@ -1059,60 +1072,60 @@
catalysts = list("enzyme" = 5)
result_amount = 1
-/datum/chemical_reaction/tofu/on_reaction(var/datum/reagents/holder, var/created_volume)
+/datum/chemical_reaction/food/tofu/on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/weapon/reagent_containers/food/snacks/tofu(location)
return
-/datum/chemical_reaction/chocolate_bar
+/datum/chemical_reaction/food/chocolate_bar
name = "Chocolate Bar"
id = "chocolate_bar"
result = null
required_reagents = list("soymilk" = 2, "coco" = 2, "sugar" = 2)
result_amount = 1
-/datum/chemical_reaction/chocolate_bar/on_reaction(var/datum/reagents/holder, var/created_volume)
+/datum/chemical_reaction/food/chocolate_bar/on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/weapon/reagent_containers/food/snacks/chocolatebar(location)
return
-/datum/chemical_reaction/chocolate_bar2
+/datum/chemical_reaction/food/chocolate_bar2
name = "Chocolate Bar"
id = "chocolate_bar"
result = null
required_reagents = list("milk" = 2, "coco" = 2, "sugar" = 2)
result_amount = 1
-/datum/chemical_reaction/chocolate_bar2/on_reaction(var/datum/reagents/holder, var/created_volume)
+/datum/chemical_reaction/food/chocolate_bar2/on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/weapon/reagent_containers/food/snacks/chocolatebar(location)
return
-/datum/chemical_reaction/hot_coco
+/datum/chemical_reaction/drinks/hot_coco
name = "Hot Coco"
id = "hot_coco"
result = "hot_coco"
required_reagents = list("water" = 5, "coco" = 1)
result_amount = 5
-/datum/chemical_reaction/soysauce
+/datum/chemical_reaction/food/soysauce
name = "Soy Sauce"
id = "soysauce"
result = "soysauce"
required_reagents = list("soymilk" = 4, "sacid" = 1)
result_amount = 5
-/datum/chemical_reaction/ketchup
+/datum/chemical_reaction/food/ketchup
name = "Ketchup"
id = "ketchup"
result = "ketchup"
required_reagents = list("tomatojuice" = 2, "water" = 1, "sugar" = 1)
result_amount = 4
-/datum/chemical_reaction/cheesewheel
+/datum/chemical_reaction/food/cheesewheel
name = "Cheesewheel"
id = "cheesewheel"
result = null
@@ -1120,46 +1133,46 @@
catalysts = list("enzyme" = 5)
result_amount = 1
-/datum/chemical_reaction/cheesewheel/on_reaction(var/datum/reagents/holder, var/created_volume)
+/datum/chemical_reaction/food/cheesewheel/on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesewheel(location)
return
-/datum/chemical_reaction/meatball
+/datum/chemical_reaction/food/meatball
name = "Meatball"
id = "meatball"
result = null
required_reagents = list("protein" = 3, "flour" = 5)
result_amount = 3
-/datum/chemical_reaction/meatball/on_reaction(var/datum/reagents/holder, var/created_volume)
+/datum/chemical_reaction/food/meatball/on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/weapon/reagent_containers/food/snacks/meatball(location)
return
-/datum/chemical_reaction/dough
+/datum/chemical_reaction/food/dough
name = "Dough"
id = "dough"
result = null
required_reagents = list("egg" = 3, "flour" = 10)
result_amount = 1
-/datum/chemical_reaction/dough/on_reaction(var/datum/reagents/holder, var/created_volume)
+/datum/chemical_reaction/food/dough/on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/weapon/reagent_containers/food/snacks/dough(location)
return
-/datum/chemical_reaction/syntiflesh
+/datum/chemical_reaction/food/syntiflesh
name = "Syntiflesh"
id = "syntiflesh"
result = null
required_reagents = list("blood" = 5, "clonexadone" = 1)
result_amount = 1
-/datum/chemical_reaction/syntiflesh/on_reaction(var/datum/reagents/holder, var/created_volume)
+/datum/chemical_reaction/food/syntiflesh/on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/i = 1, i <= created_volume, i++)
new /obj/item/weapon/reagent_containers/food/snacks/meat/syntiflesh(location)
@@ -1181,49 +1194,49 @@
/* Alcohol */
-/datum/chemical_reaction/goldschlager
+/datum/chemical_reaction/drinks/goldschlager
name = "Goldschlager"
id = "goldschlager"
result = "goldschlager"
required_reagents = list("vodka" = 10, "gold" = 1)
result_amount = 10
-/datum/chemical_reaction/patron
+/datum/chemical_reaction/drinks/patron
name = "Patron"
id = "patron"
result = "patron"
required_reagents = list("tequilla" = 10, "silver" = 1)
result_amount = 10
-/datum/chemical_reaction/bilk
+/datum/chemical_reaction/drinks/bilk
name = "Bilk"
id = "bilk"
result = "bilk"
required_reagents = list("milk" = 1, "beer" = 1)
result_amount = 2
-/datum/chemical_reaction/icetea
+/datum/chemical_reaction/drinks/icetea
name = "Iced Tea"
id = "icetea"
result = "icetea"
required_reagents = list("ice" = 1, "tea" = 2)
result_amount = 3
-/datum/chemical_reaction/icecoffee
+/datum/chemical_reaction/drinks/icecoffee
name = "Iced Coffee"
id = "icecoffee"
result = "icecoffee"
required_reagents = list("ice" = 1, "coffee" = 2)
result_amount = 3
-/datum/chemical_reaction/nuka_cola
+/datum/chemical_reaction/drinks/nuka_cola
name = "Nuka Cola"
id = "nuka_cola"
result = "nuka_cola"
required_reagents = list("uranium" = 1, "cola" = 5)
result_amount = 5
-/datum/chemical_reaction/moonshine
+/datum/chemical_reaction/drinks/moonshine
name = "Moonshine"
id = "moonshine"
result = "moonshine"
@@ -1231,7 +1244,7 @@
catalysts = list("enzyme" = 5)
result_amount = 10
-/datum/chemical_reaction/grenadine
+/datum/chemical_reaction/drinks/grenadine
name = "Grenadine Syrup"
id = "grenadine"
result = "grenadine"
@@ -1239,7 +1252,7 @@
catalysts = list("enzyme" = 5)
result_amount = 10
-/datum/chemical_reaction/wine
+/datum/chemical_reaction/drinks/wine
name = "Wine"
id = "wine"
result = "wine"
@@ -1247,7 +1260,7 @@
catalysts = list("enzyme" = 5)
result_amount = 10
-/datum/chemical_reaction/pwine
+/datum/chemical_reaction/drinks/pwine
name = "Poison Wine"
id = "pwine"
result = "pwine"
@@ -1255,7 +1268,7 @@
catalysts = list("enzyme" = 5)
result_amount = 10
-/datum/chemical_reaction/melonliquor
+/datum/chemical_reaction/drinks/melonliquor
name = "Melon Liquor"
id = "melonliquor"
result = "melonliquor"
@@ -1263,7 +1276,7 @@
catalysts = list("enzyme" = 5)
result_amount = 10
-/datum/chemical_reaction/bluecuracao
+/datum/chemical_reaction/drinks/bluecuracao
name = "Blue Curacao"
id = "bluecuracao"
result = "bluecuracao"
@@ -1271,7 +1284,7 @@
catalysts = list("enzyme" = 5)
result_amount = 10
-/datum/chemical_reaction/spacebeer
+/datum/chemical_reaction/drinks/spacebeer
name = "Space Beer"
id = "spacebeer"
result = "beer"
@@ -1279,7 +1292,7 @@
catalysts = list("enzyme" = 5)
result_amount = 10
-/datum/chemical_reaction/vodka
+/datum/chemical_reaction/drinks/vodka
name = "Vodka"
id = "vodka"
result = "vodka"
@@ -1287,7 +1300,7 @@
catalysts = list("enzyme" = 5)
result_amount = 10
-/datum/chemical_reaction/sake
+/datum/chemical_reaction/drinks/sake
name = "Sake"
id = "sake"
result = "sake"
@@ -1295,7 +1308,7 @@
catalysts = list("enzyme" = 5)
result_amount = 10
-/datum/chemical_reaction/kahlua
+/datum/chemical_reaction/drinks/kahlua
name = "Kahlua"
id = "kahlua"
result = "kahlua"
@@ -1303,287 +1316,287 @@
catalysts = list("enzyme" = 5)
result_amount = 5
-/datum/chemical_reaction/gin_tonic
+/datum/chemical_reaction/drinks/gin_tonic
name = "Gin and Tonic"
id = "gintonic"
result = "gintonic"
required_reagents = list("gin" = 2, "tonic" = 1)
result_amount = 3
-/datum/chemical_reaction/cuba_libre
+/datum/chemical_reaction/drinks/cuba_libre
name = "Cuba Libre"
id = "cubalibre"
result = "cubalibre"
required_reagents = list("rum" = 2, "cola" = 1)
result_amount = 3
-/datum/chemical_reaction/martini
+/datum/chemical_reaction/drinks/martini
name = "Classic Martini"
id = "martini"
result = "martini"
required_reagents = list("gin" = 2, "vermouth" = 1)
result_amount = 3
-/datum/chemical_reaction/vodkamartini
+/datum/chemical_reaction/drinks/vodkamartini
name = "Vodka Martini"
id = "vodkamartini"
result = "vodkamartini"
required_reagents = list("vodka" = 2, "vermouth" = 1)
result_amount = 3
-/datum/chemical_reaction/white_russian
+/datum/chemical_reaction/drinks/white_russian
name = "White Russian"
id = "whiterussian"
result = "whiterussian"
required_reagents = list("blackrussian" = 2, "cream" = 1)
result_amount = 3
-/datum/chemical_reaction/whiskey_cola
+/datum/chemical_reaction/drinks/whiskey_cola
name = "Whiskey Cola"
id = "whiskeycola"
result = "whiskeycola"
required_reagents = list("whiskey" = 2, "cola" = 1)
result_amount = 3
-/datum/chemical_reaction/screwdriver
+/datum/chemical_reaction/drinks/screwdriver
name = "Screwdriver"
id = "screwdrivercocktail"
result = "screwdrivercocktail"
required_reagents = list("vodka" = 2, "orangejuice" = 1)
result_amount = 3
-/datum/chemical_reaction/bloody_mary
+/datum/chemical_reaction/drinks/bloody_mary
name = "Bloody Mary"
id = "bloodymary"
result = "bloodymary"
required_reagents = list("vodka" = 2, "tomatojuice" = 3, "limejuice" = 1)
result_amount = 6
-/datum/chemical_reaction/gargle_blaster
+/datum/chemical_reaction/drinks/gargle_blaster
name = "Pan-Galactic Gargle Blaster"
id = "gargleblaster"
result = "gargleblaster"
required_reagents = list("vodka" = 2, "gin" = 1, "whiskey" = 1, "cognac" = 1, "limejuice" = 1)
result_amount = 6
-/datum/chemical_reaction/brave_bull
+/datum/chemical_reaction/drinks/brave_bull
name = "Brave Bull"
id = "bravebull"
result = "bravebull"
required_reagents = list("tequilla" = 2, "kahlua" = 1)
result_amount = 3
-/datum/chemical_reaction/tequilla_sunrise
+/datum/chemical_reaction/drinks/tequilla_sunrise
name = "Tequilla Sunrise"
id = "tequillasunrise"
result = "tequillasunrise"
required_reagents = list("tequilla" = 2, "orangejuice" = 1)
result_amount = 3
-/datum/chemical_reaction/phoron_special
+/datum/chemical_reaction/drinks/phoron_special
name = "Toxins Special"
id = "phoronspecial"
result = "phoronspecial"
required_reagents = list("rum" = 2, "vermouth" = 2, "phoron" = 2)
result_amount = 6
-/datum/chemical_reaction/beepsky_smash
+/datum/chemical_reaction/drinks/beepsky_smash
name = "Beepksy Smash"
id = "beepksysmash"
result = "beepskysmash"
required_reagents = list("limejuice" = 1, "whiskey" = 1, "iron" = 1)
result_amount = 2
-/datum/chemical_reaction/doctor_delight
+/datum/chemical_reaction/drinks/doctor_delight
name = "The Doctor's Delight"
id = "doctordelight"
result = "doctorsdelight"
required_reagents = list("limejuice" = 1, "tomatojuice" = 1, "orangejuice" = 1, "cream" = 2, "tricordrazine" = 1)
result_amount = 6
-/datum/chemical_reaction/irish_cream
+/datum/chemical_reaction/drinks/irish_cream
name = "Irish Cream"
id = "irishcream"
result = "irishcream"
required_reagents = list("whiskey" = 2, "cream" = 1)
result_amount = 3
-/datum/chemical_reaction/manly_dorf
+/datum/chemical_reaction/drinks/manly_dorf
name = "The Manly Dorf"
id = "manlydorf"
result = "manlydorf"
required_reagents = list ("beer" = 1, "ale" = 2)
result_amount = 3
-/datum/chemical_reaction/hooch
+/datum/chemical_reaction/drinks/hooch
name = "Hooch"
id = "hooch"
result = "hooch"
required_reagents = list ("sugar" = 1, "ethanol" = 2, "fuel" = 1)
result_amount = 3
-/datum/chemical_reaction/irish_coffee
+/datum/chemical_reaction/drinks/irish_coffee
name = "Irish Coffee"
id = "irishcoffee"
result = "irishcoffee"
required_reagents = list("irishcream" = 1, "coffee" = 1)
result_amount = 2
-/datum/chemical_reaction/b52
+/datum/chemical_reaction/drinks/b52
name = "B-52"
id = "b52"
result = "b52"
required_reagents = list("irishcream" = 1, "kahlua" = 1, "cognac" = 1)
result_amount = 3
-/datum/chemical_reaction/atomicbomb
+/datum/chemical_reaction/drinks/atomicbomb
name = "Atomic Bomb"
id = "atomicbomb"
result = "atomicbomb"
required_reagents = list("b52" = 10, "uranium" = 1)
result_amount = 10
-/datum/chemical_reaction/margarita
+/datum/chemical_reaction/drinks/margarita
name = "Margarita"
id = "margarita"
result = "margarita"
required_reagents = list("tequilla" = 2, "limejuice" = 1)
result_amount = 3
-/datum/chemical_reaction/longislandicedtea
+/datum/chemical_reaction/drinks/longislandicedtea
name = "Long Island Iced Tea"
id = "longislandicedtea"
result = "longislandicedtea"
required_reagents = list("vodka" = 1, "gin" = 1, "tequilla" = 1, "cubalibre" = 3)
result_amount = 6
-/datum/chemical_reaction/icedtea
+/datum/chemical_reaction/drinks/icedtea
name = "Long Island Iced Tea"
id = "longislandicedtea"
result = "longislandicedtea"
required_reagents = list("vodka" = 1, "gin" = 1, "tequilla" = 1, "cubalibre" = 3)
result_amount = 6
-/datum/chemical_reaction/threemileisland
+/datum/chemical_reaction/drinks/threemileisland
name = "Three Mile Island Iced Tea"
id = "threemileisland"
result = "threemileisland"
required_reagents = list("longislandicedtea" = 10, "uranium" = 1)
result_amount = 10
-/datum/chemical_reaction/whiskeysoda
+/datum/chemical_reaction/drinks/whiskeysoda
name = "Whiskey Soda"
id = "whiskeysoda"
result = "whiskeysoda"
required_reagents = list("whiskey" = 2, "sodawater" = 1)
result_amount = 3
-/datum/chemical_reaction/black_russian
+/datum/chemical_reaction/drinks/black_russian
name = "Black Russian"
id = "blackrussian"
result = "blackrussian"
required_reagents = list("vodka" = 2, "kahlua" = 1)
result_amount = 3
-/datum/chemical_reaction/manhattan
+/datum/chemical_reaction/drinks/manhattan
name = "Manhattan"
id = "manhattan"
result = "manhattan"
required_reagents = list("whiskey" = 2, "vermouth" = 1)
result_amount = 3
-/datum/chemical_reaction/manhattan_proj
+/datum/chemical_reaction/drinks/manhattan_proj
name = "Manhattan Project"
id = "manhattan_proj"
result = "manhattan_proj"
required_reagents = list("manhattan" = 10, "uranium" = 1)
result_amount = 10
-/datum/chemical_reaction/vodka_tonic
+/datum/chemical_reaction/drinks/vodka_tonic
name = "Vodka and Tonic"
id = "vodkatonic"
result = "vodkatonic"
required_reagents = list("vodka" = 2, "tonic" = 1)
result_amount = 3
-/datum/chemical_reaction/gin_fizz
+/datum/chemical_reaction/drinks/gin_fizz
name = "Gin Fizz"
id = "ginfizz"
result = "ginfizz"
required_reagents = list("gin" = 1, "sodawater" = 1, "limejuice" = 1)
result_amount = 3
-/datum/chemical_reaction/bahama_mama
+/datum/chemical_reaction/drinks/bahama_mama
name = "Bahama mama"
id = "bahama_mama"
result = "bahama_mama"
required_reagents = list("rum" = 2, "orangejuice" = 2, "limejuice" = 1, "ice" = 1)
result_amount = 6
-/datum/chemical_reaction/singulo
+/datum/chemical_reaction/drinks/singulo
name = "Singulo"
id = "singulo"
result = "singulo"
required_reagents = list("vodka" = 5, "radium" = 1, "wine" = 5)
result_amount = 10
-/datum/chemical_reaction/alliescocktail
+/datum/chemical_reaction/drinks/alliescocktail
name = "Allies Cocktail"
id = "alliescocktail"
result = "alliescocktail"
required_reagents = list("martini" = 1, "vodka" = 1)
result_amount = 2
-/datum/chemical_reaction/demonsblood
+/datum/chemical_reaction/drinks/demonsblood
name = "Demons Blood"
id = "demonsblood"
result = "demonsblood"
required_reagents = list("rum" = 3, "spacemountainwind" = 1, "blood" = 1, "dr_gibb" = 1)
result_amount = 6
-/datum/chemical_reaction/booger
+/datum/chemical_reaction/drinks/booger
name = "Booger"
id = "booger"
result = "booger"
required_reagents = list("cream" = 2, "banana" = 1, "rum" = 1, "watermelonjuice" = 1)
result_amount = 5
-/datum/chemical_reaction/antifreeze
+/datum/chemical_reaction/drinks/antifreeze
name = "Anti-freeze"
id = "antifreeze"
result = "antifreeze"
required_reagents = list("vodka" = 1, "cream" = 1, "ice" = 1)
result_amount = 3
-/datum/chemical_reaction/barefoot
+/datum/chemical_reaction/drinks/barefoot
name = "Barefoot"
id = "barefoot"
result = "barefoot"
required_reagents = list("berryjuice" = 1, "cream" = 1, "vermouth" = 1)
result_amount = 3
-/datum/chemical_reaction/grapesoda
+/datum/chemical_reaction/drinks/grapesoda
name = "Grape Soda"
id = "grapesoda"
result = "grapesoda"
required_reagents = list("grapejuice" = 2, "cola" = 1)
result_amount = 3
-/datum/chemical_reaction/sbiten
+/datum/chemical_reaction/drinks/sbiten
name = "Sbiten"
id = "sbiten"
result = "sbiten"
required_reagents = list("vodka" = 10, "capsaicin" = 1)
result_amount = 10
-/datum/chemical_reaction/red_mead
+/datum/chemical_reaction/drinks/red_mead
name = "Red Mead"
id = "red_mead"
result = "red_mead"
required_reagents = list("blood" = 1, "mead" = 1)
result_amount = 2
-/datum/chemical_reaction/mead
+/datum/chemical_reaction/drinks/mead
name = "Mead"
id = "mead"
result = "mead"
@@ -1591,219 +1604,240 @@
catalysts = list("enzyme" = 5)
result_amount = 2
-/datum/chemical_reaction/iced_beer
+/datum/chemical_reaction/drinks/iced_beer
name = "Iced Beer"
id = "iced_beer"
result = "iced_beer"
required_reagents = list("beer" = 10, "frostoil" = 1)
result_amount = 10
-/datum/chemical_reaction/iced_beer2
+/datum/chemical_reaction/drinks/iced_beer2
name = "Iced Beer"
id = "iced_beer"
result = "iced_beer"
required_reagents = list("beer" = 5, "ice" = 1)
result_amount = 6
-/datum/chemical_reaction/grog
+/datum/chemical_reaction/drinks/grog
name = "Grog"
id = "grog"
result = "grog"
required_reagents = list("rum" = 1, "water" = 1)
result_amount = 2
-/datum/chemical_reaction/soy_latte
+/datum/chemical_reaction/drinks/soy_latte
name = "Soy Latte"
id = "soy_latte"
result = "soy_latte"
required_reagents = list("coffee" = 1, "soymilk" = 1)
result_amount = 2
-/datum/chemical_reaction/cafe_latte
+/datum/chemical_reaction/drinks/cafe_latte
name = "Cafe Latte"
id = "cafe_latte"
result = "cafe_latte"
required_reagents = list("coffee" = 1, "milk" = 1)
result_amount = 2
-/datum/chemical_reaction/acidspit
+/datum/chemical_reaction/drinks/acidspit
name = "Acid Spit"
id = "acidspit"
result = "acidspit"
required_reagents = list("sacid" = 1, "wine" = 5)
result_amount = 6
-/datum/chemical_reaction/amasec
+/datum/chemical_reaction/drinks/amasec
name = "Amasec"
id = "amasec"
result = "amasec"
required_reagents = list("iron" = 1, "wine" = 5, "vodka" = 5)
result_amount = 10
-/datum/chemical_reaction/changelingsting
+/datum/chemical_reaction/drinks/changelingsting
name = "Changeling Sting"
id = "changelingsting"
result = "changelingsting"
required_reagents = list("screwdrivercocktail" = 1, "limejuice" = 1, "lemonjuice" = 1)
result_amount = 3
-/datum/chemical_reaction/aloe
+/datum/chemical_reaction/drinks/aloe
name = "Aloe"
id = "aloe"
result = "aloe"
required_reagents = list("cream" = 1, "whiskey" = 1, "watermelonjuice" = 1)
result_amount = 3
-/datum/chemical_reaction/andalusia
+/datum/chemical_reaction/drinks/andalusia
name = "Andalusia"
id = "andalusia"
result = "andalusia"
required_reagents = list("rum" = 1, "whiskey" = 1, "lemonjuice" = 1)
result_amount = 3
-/datum/chemical_reaction/neurotoxin
- name = "Neurotoxin"
- id = "neurotoxin"
- result = "neurotoxin"
- required_reagents = list("gargleblaster" = 1, "stoxin" = 1)
- result_amount = 2
-
-/datum/chemical_reaction/snowwhite
+/datum/chemical_reaction/drinks/snowwhite
name = "Snow White"
id = "snowwhite"
result = "snowwhite"
required_reagents = list("beer" = 1, "lemon_lime" = 1)
result_amount = 2
-/datum/chemical_reaction/irishcarbomb
+/datum/chemical_reaction/drinks/irishcarbomb
name = "Irish Car Bomb"
id = "irishcarbomb"
result = "irishcarbomb"
required_reagents = list("ale" = 1, "irishcream" = 1)
result_amount = 2
-/datum/chemical_reaction/syndicatebomb
+/datum/chemical_reaction/drinks/syndicatebomb
name = "Syndicate Bomb"
id = "syndicatebomb"
result = "syndicatebomb"
required_reagents = list("beer" = 1, "whiskeycola" = 1)
result_amount = 2
-/datum/chemical_reaction/erikasurprise
+/datum/chemical_reaction/drinks/erikasurprise
name = "Erika Surprise"
id = "erikasurprise"
result = "erikasurprise"
required_reagents = list("ale" = 2, "limejuice" = 1, "whiskey" = 1, "banana" = 1, "ice" = 1)
result_amount = 6
-/datum/chemical_reaction/devilskiss
+/datum/chemical_reaction/drinks/devilskiss
name = "Devils Kiss"
id = "devilskiss"
result = "devilskiss"
required_reagents = list("blood" = 1, "kahlua" = 1, "rum" = 1)
result_amount = 3
-/datum/chemical_reaction/hippiesdelight
+/datum/chemical_reaction/drinks/hippiesdelight
name = "Hippies Delight"
id = "hippiesdelight"
result = "hippiesdelight"
required_reagents = list("psilocybin" = 1, "gargleblaster" = 1)
result_amount = 2
-/datum/chemical_reaction/bananahonk
+/datum/chemical_reaction/drinks/bananahonk
name = "Banana Honk"
id = "bananahonk"
result = "bananahonk"
required_reagents = list("banana" = 1, "cream" = 1, "sugar" = 1)
result_amount = 3
-/datum/chemical_reaction/silencer
+/datum/chemical_reaction/drinks/silencer
name = "Silencer"
id = "silencer"
result = "silencer"
required_reagents = list("nothing" = 1, "cream" = 1, "sugar" = 1)
result_amount = 3
-/datum/chemical_reaction/driestmartini
+/datum/chemical_reaction/drinks/driestmartini
name = "Driest Martini"
id = "driestmartini"
result = "driestmartini"
required_reagents = list("nothing" = 1, "gin" = 1)
result_amount = 2
-/datum/chemical_reaction/lemonade
+/datum/chemical_reaction/drinks/lemonade
name = "Lemonade"
id = "lemonade"
result = "lemonade"
required_reagents = list("lemonjuice" = 1, "sugar" = 1, "water" = 1)
result_amount = 3
-/datum/chemical_reaction/kiraspecial
+/datum/chemical_reaction/drinks/kiraspecial
name = "Kira Special"
id = "kiraspecial"
result = "kiraspecial"
required_reagents = list("orangejuice" = 1, "limejuice" = 1, "sodawater" = 1)
result_amount = 3
-/datum/chemical_reaction/brownstar
+/datum/chemical_reaction/drinks/brownstar
name = "Brown Star"
id = "brownstar"
result = "brownstar"
required_reagents = list("orangejuice" = 2, "cola" = 1)
result_amount = 3
-/datum/chemical_reaction/milkshake
+/datum/chemical_reaction/drinks/milkshake
name = "Milkshake"
id = "milkshake"
result = "milkshake"
required_reagents = list("cream" = 1, "ice" = 2, "milk" = 2)
result_amount = 5
-/datum/chemical_reaction/rewriter
+/datum/chemical_reaction/drinks/rewriter
name = "Rewriter"
id = "rewriter"
result = "rewriter"
required_reagents = list("spacemountainwind" = 1, "coffee" = 1)
result_amount = 2
-/datum/chemical_reaction/suidream
+/datum/chemical_reaction/drinks/suidream
name = "Sui Dream"
id = "suidream"
result = "suidream"
required_reagents = list("space_up" = 1, "bluecuracao" = 1, "melonliquor" = 1)
result_amount = 3
-/datum/chemical_reaction/luminol
- name = "Luminol"
- id = "luminol"
- result = "luminol"
- required_reagents = list("hydrogen" = 2, "carbon" = 2, "ammonia" = 2)
- result_amount = 6
-
-/datum/chemical_reaction/shirleytemple
+/datum/chemical_reaction/drinks/shirleytemple
name = "Shirley Temple"
id = "shirley_temple"
result = "shirley_temple"
required_reagents = list("lemon_lime" = 4, "grenadine" = 1)
result_amount = 5
-/datum/chemical_reaction/royrogers
+/datum/chemical_reaction/drinks/royrogers
name = "Roy Rogers"
id = "roy_rogers"
result = "roy_rogers"
required_reagents = list("cola" = 4, "grenadine" = 1)
result_amount = 5
-/datum/chemical_reaction/collinsmix
+/datum/chemical_reaction/drinks/collinsmix
name = "Collins Mix"
id = "collins_mix"
result = "collins_mix"
required_reagents = list("lemon_lime" = 3, "sodawater" = 1)
result_amount = 4
-/datum/chemical_reaction/arnoldpalmer
+/datum/chemical_reaction/drinks/arnoldpalmer
name = "Arnold Palmer"
id = "arnold_palmer"
result = "arnold_palmer"
required_reagents = list("icetea" = 1, "lemonade" = 1)
- result_amount = 2
\ No newline at end of file
+ result_amount = 2
+
+/datum/chemical_reaction/minttea
+ name = "Mint Tea"
+ id = "minttea"
+ result = "minttea"
+ required_reagents = list("tea" = 5, "mint" = 1)
+ result_amount = 6
+
+/datum/chemical_reaction/lemontea
+ name = "Lemon Tea"
+ id = "lemontea"
+ result = "lemontea"
+ required_reagents = list("tea" = 5, "lemonjuice" = 1)
+ result_amount = 6
+
+/datum/chemical_reaction/limetea
+ name = "Lime Tea"
+ id = "limetea"
+ result = "limetea"
+ required_reagents = list("tea" = 5, "limejuice" = 1)
+ result_amount = 6
+
+/datum/chemical_reaction/limetea
+ name = "Orange Tea"
+ id = "orangetea"
+ result = "orangetea"
+ required_reagents = list("tea" = 5, "orangejuice" = 1)
+ result_amount = 6
+
+/datum/chemical_reaction/berrytea
+ name = "Berry Tea"
+ id = "berrytea"
+ result = "berrytea"
+ required_reagents = list("tea" = 5, "berryjuice" = 1)
+ result_amount = 6
\ No newline at end of file
diff --git a/code/modules/reagents/dispenser/cartridge_presets.dm b/code/modules/reagents/dispenser/cartridge_presets.dm
index ab82dc53f4b..4e23410ac26 100644
--- a/code/modules/reagents/dispenser/cartridge_presets.dm
+++ b/code/modules/reagents/dispenser/cartridge_presets.dm
@@ -68,6 +68,8 @@
hot_coco spawn_reagent = "hot_coco"
milk spawn_reagent = "milk"
cream spawn_reagent = "cream"
+ mint spawn_reagent = "mint"
+ berry spawn_reagent = "berryjuice"
// ERT
inaprov spawn_reagent = "inaprovaline"
diff --git a/code/modules/reagents/dispenser/dispenser2_energy.dm b/code/modules/reagents/dispenser/dispenser2_energy.dm
index 2ab4c5641d8..d29ed6bbe92 100644
--- a/code/modules/reagents/dispenser/dispenser2_energy.dm
+++ b/code/modules/reagents/dispenser/dispenser2_energy.dm
@@ -57,5 +57,6 @@
/obj/machinery/chemical_dispenser/bar_coffee
dispense_reagents = list(
- "coffee", "cafe_latte", "soy_latte", "hot_coco", "milk", "cream", "tea", "ice"
+ "coffee", "cafe_latte", "soy_latte", "hot_coco", "milk", "cream", "tea", "ice",
+ "orangejuice", "lemonjuice", "limejuice", "berryjuice", "mint"
)
\ No newline at end of file
diff --git a/code/modules/reagents/dispenser/dispenser_presets.dm b/code/modules/reagents/dispenser/dispenser_presets.dm
index 63f65335f41..05477d9cdde 100644
--- a/code/modules/reagents/dispenser/dispenser_presets.dm
+++ b/code/modules/reagents/dispenser/dispenser_presets.dm
@@ -131,5 +131,12 @@
/obj/item/weapon/reagent_containers/chem_disp_cartridge/milk,
/obj/item/weapon/reagent_containers/chem_disp_cartridge/cream,
/obj/item/weapon/reagent_containers/chem_disp_cartridge/tea,
- /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/ice,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/mint,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/orange,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lemon,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/lime,
+ /obj/item/weapon/reagent_containers/chem_disp_cartridge/berry,
+
+
)
\ No newline at end of file
diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm
index aa952915c3f..0a1816e4c86 100644
--- a/code/modules/reagents/reagent_containers/dropper.dm
+++ b/code/modules/reagents/reagent_containers/dropper.dm
@@ -12,13 +12,6 @@
slot_flags = SLOT_EARS
volume = 5
-
-/obj/item/weapon/reagent_containers/dropper/do_surgery(mob/living/carbon/M, mob/living/user)
- if(user.a_intent != I_HELP) //in case it is ever used as a surgery tool
- return ..()
- afterattack(M, user, 1)
- return 1
-
/obj/item/weapon/reagent_containers/dropper/afterattack(var/obj/target, var/mob/user, var/proximity)
if(!target.reagents || !proximity) return
@@ -75,7 +68,7 @@
return
else
- trans = reagents.splash(target, amount_per_transfer_from_this, max_spill=30) //sprinkling reagents on generic non-mobs
+ trans = reagents.splash(target, amount_per_transfer_from_this, max_spill=0) //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/drinks.dm b/code/modules/reagents/reagent_containers/food/drinks.dm
index edb8e7fae66..163fd1161fb 100644
--- a/code/modules/reagents/reagent_containers/food/drinks.dm
+++ b/code/modules/reagents/reagent_containers/food/drinks.dm
@@ -131,23 +131,28 @@
..()
reagents.add_reagent("soymilk", 50)
-/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton
+/obj/item/weapon/reagent_containers/food/drinks/smallmilk
name = "small milk carton"
+ desc = "It's milk. White and nutritious goodness!"
volume = 30
icon_state = "mini-milk"
-/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/New()
+ item_state = "carton"
+ center_of_mass = list("x"=16, "y"=9)
+/obj/item/weapon/reagent_containers/food/drinks/smallmilk/New()
..()
reagents.add_reagent("milk", 30)
-/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate
+/obj/item/weapon/reagent_containers/food/drinks/smallchocmilk
name = "small chocolate milk carton"
desc = "It's milk! This one is in delicious chocolate flavour."
+ volume = 30
icon_state = "mini-milk_choco"
-/obj/item/weapon/reagent_containers/food/drinks/milk/smallcarton/chocolate/New()
+ item_state = "carton"
+ center_of_mass = list("x"=16, "y"=9)
+/obj/item/weapon/reagent_containers/food/drinks/smallchocmilk/New()
..()
reagents.add_reagent("chocolate_milk", 30)
-
/obj/item/weapon/reagent_containers/food/drinks/coffee
name = "\improper Robust Coffee"
desc = "Careful, the beverage you're about to enjoy is extremely hot."
diff --git a/code/modules/reagents/reagent_containers/food/lunch.dm b/code/modules/reagents/reagent_containers/food/lunch.dm
index 794d7f69ddb..1ab8cf3a431 100644
--- a/code/modules/reagents/reagent_containers/food/lunch.dm
+++ b/code/modules/reagents/reagent_containers/food/lunch.dm
@@ -1,11 +1,11 @@
var/list/lunchables_lunches_ = list(/obj/item/weapon/reagent_containers/food/snacks/sandwich,
- /obj/item/weapon/reagent_containers/food/snacks/meatbreadslice,
- /obj/item/weapon/reagent_containers/food/snacks/tofubreadslice,
- /obj/item/weapon/reagent_containers/food/snacks/creamcheesebreadslice,
- /obj/item/weapon/reagent_containers/food/snacks/margheritaslice,
- /obj/item/weapon/reagent_containers/food/snacks/meatpizzaslice,
- /obj/item/weapon/reagent_containers/food/snacks/mushroompizzaslice,
- /obj/item/weapon/reagent_containers/food/snacks/vegetablepizzaslice,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/meatbread/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/tofubread/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/creamcheesebread/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/margherita/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/meatpizza/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/vegetablepizza/filled,
/obj/item/weapon/reagent_containers/food/snacks/tastybread,
/obj/item/weapon/reagent_containers/food/snacks/liquidfood,
/obj/item/weapon/reagent_containers/food/snacks/jellysandwich/cherry,
@@ -26,17 +26,17 @@ var/list/lunchables_snacks_ = list(/obj/item/weapon/reagent_containers/food/snac
/obj/item/weapon/reagent_containers/food/snacks/cherrypie,
/obj/item/weapon/reagent_containers/food/snacks/plumphelmetbiscuit,
/obj/item/weapon/reagent_containers/food/snacks/appletart,
- /obj/item/weapon/reagent_containers/food/snacks/carrotcakeslice,
- /obj/item/weapon/reagent_containers/food/snacks/cheesecakeslice,
- /obj/item/weapon/reagent_containers/food/snacks/plaincakeslice,
- /obj/item/weapon/reagent_containers/food/snacks/orangecakeslice,
- /obj/item/weapon/reagent_containers/food/snacks/limecakeslice,
- /obj/item/weapon/reagent_containers/food/snacks/lemoncakeslice,
- /obj/item/weapon/reagent_containers/food/snacks/chocolatecakeslice,
- /obj/item/weapon/reagent_containers/food/snacks/birthdaycakeslice,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/plaincake/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/orangecake/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/limecake/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake/filled,
/obj/item/weapon/reagent_containers/food/snacks/watermelonslice,
- /obj/item/weapon/reagent_containers/food/snacks/applecakeslice,
- /obj/item/weapon/reagent_containers/food/snacks/pumpkinpieslice,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/applecake/filled,
+ /obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie/filled,
/obj/item/weapon/reagent_containers/food/snacks/skrellsnacks)
var/list/lunchables_drinks_ = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola,
diff --git a/code/modules/reagents/reagent_containers/food/sandwich.dm b/code/modules/reagents/reagent_containers/food/sandwich.dm
index c853706ad54..f2b783f90f5 100644
--- a/code/modules/reagents/reagent_containers/food/sandwich.dm
+++ b/code/modules/reagents/reagent_containers/food/sandwich.dm
@@ -1,4 +1,4 @@
-/obj/item/weapon/reagent_containers/food/snacks/breadslice/attackby(obj/item/W as obj, mob/user as mob)
+/obj/item/weapon/reagent_containers/food/snacks/slice/bread/attackby(obj/item/W as obj, mob/user as mob)
if(istype(W,/obj/item/weapon/material/shard) || istype(W,/obj/item/weapon/reagent_containers/food/snacks))
var/obj/item/weapon/reagent_containers/food/snacks/csandwich/S = new(get_turf(src))
@@ -19,19 +19,19 @@
var/sandwich_limit = 4
for(var/obj/item/O in ingredients)
- if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/breadslice))
+ if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/slice/bread))
sandwich_limit += 4
- if(src.contents.len > sandwich_limit)
- user << "\red If you put anything else on \the [src] it's going to collapse."
- return
- else if(istype(W,/obj/item/weapon/material/shard))
+ if(istype(W,/obj/item/weapon/material/shard))
user << "\blue You hide [W] in \the [src]."
user.drop_item()
W.loc = src
update()
return
else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks))
+ if(src.contents.len > sandwich_limit)
+ user << "\red If you put anything else on \the [src] it's going to collapse."
+ return
user << "\blue You layer [W] over \the [src]."
var/obj/item/weapon/reagent_containers/F = W
F.reagents.trans_to_obj(src, F.reagents.total_volume)
diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm
index 6aa703d2d45..5ea23727314 100644
--- a/code/modules/reagents/reagent_containers/food/snacks.dm
+++ b/code/modules/reagents/reagent_containers/food/snacks.dm
@@ -179,24 +179,23 @@
if (W.w_class >= src.w_class || is_robot_module(W))
return
- user << "\red You slip [W] inside [src]."
- user.remove_from_mob(W)
- W.dropped(user)
+ to_chat(user, "You slip \the [W] inside \the [src].")
+ user.drop_from_inventory(W, src)
add_fingerprint(user)
contents += W
return
if (has_edge(W))
if (!can_slice_here)
- user << "\red You cannot slice [src] here! You need a table or at least a tray to do it."
+ to_chat(user, "You cannot slice \the [src] here! You need a table or at least a tray to do it.")
return
var/slices_lost = 0
if (W.w_class > 3)
- user.visible_message("\blue [user] crudely slices \the [src] with [W]!", "\blue You crudely slice \the [src] with your [W]!")
+ user.visible_message("\The [user] crudely slices \the [src] with [W]!", "You crudely slice \the [src] with your [W]!")
slices_lost = rand(1,min(1,round(slices_num/2)))
else
- user.visible_message("\blue [user] slices \the [src]!", "\blue You slice \the [src]!")
+ user.visible_message("\The [user] slices \the [src]!", "You slice \the [src]!")
var/reagents_per_slice = reagents.total_volume/slices_num
for(var/i=1 to (slices_num-slices_lost))
@@ -723,7 +722,7 @@
src.bitesize = 3
/obj/item/weapon/reagent_containers/food/snacks/xenomeat
- name = "meat"
+ name = "xenomeat"
desc = "A slab of green meat. Smells like acid."
icon_state = "xenomeat"
filling_color = "#43DE18"
@@ -2326,54 +2325,81 @@
/obj/item/weapon/reagent_containers/food/snacks/sliceable
w_class = ITEMSIZE_NORMAL //Whole pizzas and cakes shouldn't fit in a pocket, you can slice them if you want to do that.
+/**
+ * A food item slice
+ *
+ * This path contains some extra code for spawning slices pre-filled with
+ * reagents.
+ */
+/obj/item/weapon/reagent_containers/food/snacks/slice
+ name = "slice of... something"
+ var/whole_path // path for the item from which this slice comes
+ var/filled = FALSE // should the slice spawn with any reagents
+
+/**
+ * Spawn a new slice of food
+ *
+ * If the slice's filled is TRUE, this will also fill the slice with the
+ * appropriate amount of reagents. Note that this is done by spawning a new
+ * whole item, transferring the reagents and deleting the whole item, which may
+ * have performance implications.
+ */
+/obj/item/weapon/reagent_containers/food/snacks/slice/New()
+ ..()
+ if(filled)
+ var/obj/item/weapon/reagent_containers/food/snacks/whole = new whole_path()
+ if(whole && whole.slices_num)
+ var/reagent_amount = whole.reagents.total_volume/whole.slices_num
+ whole.reagents.trans_to_obj(src, reagent_amount)
+
+ qdel(whole)
+
/obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread
name = "meatbread loaf"
desc = "The culinary base of every self-respecting eloquen/tg/entleman."
icon_state = "meatbread"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/meatbreadslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/meatbread/filled
slices_num = 5
filling_color = "#FF7575"
- center_of_mass = list("x"=16, "y"=9)
- nutriment_amt = 10
+ center_of_mass = list("x"=19, "y"=9)
nutriment_desc = list("bread" = 10)
+ nutriment_amt = 10
/obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread/New()
..()
reagents.add_reagent("protein", 20)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/meatbreadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/meatbread/filled
name = "meatbread slice"
desc = "A slice of delicious meatbread."
icon_state = "meatbreadslice"
trash = /obj/item/trash/plate
filling_color = "#FF7575"
bitesize = 2
- center_of_mass = list("x"=16, "y"=13)
+ center_of_mass = list("x"=16, "y"=16)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/meatbread
-/obj/item/weapon/reagent_containers/food/snacks/meatbreadslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("protein", 4)
- reagents.add_reagent("nutriment", 2)
+/obj/item/weapon/reagent_containers/food/snacks/slice/meatbread/filled/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread
name = "xenomeatbread loaf"
desc = "The culinary base of every self-respecting eloquent gentleman. Extra Heretical."
icon_state = "xenomeatbread"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/xenomeatbreadslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/xenomeatbread/filled
slices_num = 5
filling_color = "#8AFF75"
center_of_mass = list("x"=16, "y"=9)
- nutriment_amt = 10
nutriment_desc = list("bread" = 10)
+ nutriment_amt = 10
/obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread/New()
..()
reagents.add_reagent("protein", 20)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/xenomeatbreadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/xenomeatbread/filled
name = "xenomeatbread slice"
desc = "A slice of delicious meatbread. Extra Heretical."
icon_state = "xenobreadslice"
@@ -2381,30 +2407,29 @@
filling_color = "#8AFF75"
bitesize = 2
center_of_mass = list("x"=16, "y"=13)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/xenomeatbread
-/obj/item/weapon/reagent_containers/food/snacks/xenomeatbreadslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("protein", 4)
- reagents.add_reagent("nutriment", 2)
+
+/obj/item/weapon/reagent_containers/food/snacks/slice/xenomeatbread/filled/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread
name = "Banana-nut bread"
desc = "A heavenly and filling treat."
icon_state = "bananabread"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/bananabreadslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/bananabread
slices_num = 5
filling_color = "#EDE5AD"
center_of_mass = list("x"=16, "y"=9)
- nutriment_amt = 10
nutriment_desc = list("bread" = 10)
+ nutriment_amt = 10
/obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread/New()
..()
reagents.add_reagent("banana", 20)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/bananabreadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/bananabread
name = "Banana-nut bread slice"
desc = "A slice of delicious banana bread."
icon_state = "bananabreadslice"
@@ -2412,30 +2437,27 @@
filling_color = "#EDE5AD"
bitesize = 2
center_of_mass = list("x"=16, "y"=8)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/bananabread
-/obj/item/weapon/reagent_containers/food/snacks/bananabreadslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("banana", 4)
- reagents.add_reagent("nutriment", 4)
+/obj/item/weapon/reagent_containers/food/snacks/slice/bananabread/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread
name = "Tofubread"
icon_state = "Like meatbread but for vegetarians. Not guaranteed to give superpowers."
icon_state = "tofubread"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/tofubreadslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/tofubread
slices_num = 5
filling_color = "#F7FFE0"
center_of_mass = list("x"=16, "y"=9)
- nutriment_amt = 30
- nutriment_desc = list("bread" = 15, "tofu" = 15)
+ nutriment_desc = list("tofu" = 10)
+ nutriment_amt = 10
/obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread/New()
..()
- reagents.add_reagent("nutriment", 30)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/tofubreadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/tofubread
name = "Tofubread slice"
desc = "A slice of delicious tofubread."
icon_state = "tofubreadslice"
@@ -2443,30 +2465,29 @@
filling_color = "#F7FFE0"
bitesize = 2
center_of_mass = list("x"=16, "y"=13)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/tofubread
-/obj/item/weapon/reagent_containers/food/snacks/tofubreadslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 6)
+/obj/item/weapon/reagent_containers/food/snacks/slice/tofubread/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake
name = "Carrot Cake"
desc = "A favorite desert of a certain wascally wabbit. Not a lie."
icon_state = "carrotcake"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/carrotcakeslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake
slices_num = 5
filling_color = "#FFD675"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 25
nutriment_desc = list("cake" = 10, "sweetness" = 10, "carrot" = 15)
+ nutriment_amt = 25
/obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake/New()
..()
reagents.add_reagent("imidazoline", 10)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/carrotcakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake
name = "Carrot Cake slice"
desc = "Carrotty slice of Carrot Cake, carrots are good for your eyes! Also not a lie."
icon_state = "carrotcake_slice"
@@ -2474,23 +2495,21 @@
filling_color = "#FFD675"
bitesize = 2
center_of_mass = list("x"=16, "y"=14)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/carrotcake
-/obj/item/weapon/reagent_containers/food/snacks/carrotcakeslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("imidazoline", 2)
- reagents.add_reagent("nutriment", 5)
+/obj/item/weapon/reagent_containers/food/snacks/slice/carrotcake/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake
name = "Brain Cake"
desc = "A squishy cake-thing."
icon_state = "braincake"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/braincakeslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/braincake
slices_num = 5
filling_color = "#E6AEDB"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 5
nutriment_desc = list("cake" = 10, "sweetness" = 10, "slime" = 15)
+ nutriment_amt = 5
/obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake/New()
..()
@@ -2498,7 +2517,7 @@
reagents.add_reagent("alkysine", 10)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/braincakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/braincake
name = "Brain Cake slice"
desc = "Lemme tell you something about prions. THEY'RE DELICIOUS."
icon_state = "braincakeslice"
@@ -2506,60 +2525,52 @@
filling_color = "#E6AEDB"
bitesize = 2
center_of_mass = list("x"=16, "y"=12)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/braincake
-/obj/item/weapon/reagent_containers/food/snacks/braincakeslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("protein", 5)
- reagents.add_reagent("nutriment", 1)
- reagents.add_reagent("alkysine", 2)
+/obj/item/weapon/reagent_containers/food/snacks/slice/braincake/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake
name = "Cheese Cake"
desc = "DANGEROUSLY cheesy."
icon_state = "cheesecake"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/cheesecakeslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake
slices_num = 5
filling_color = "#FAF7AF"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 10
nutriment_desc = list("cake" = 10, "cream" = 10, "cheese" = 15)
+ nutriment_amt = 10
/obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake/New()
..()
reagents.add_reagent("protein", 15)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/cheesecakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake
name = "Cheese Cake slice"
- desc = "Slice of pure cheestisfaction"
+ desc = "Slice of pure cheestisfaction."
icon_state = "cheesecake_slice"
trash = /obj/item/trash/plate
filling_color = "#FAF7AF"
bitesize = 2
center_of_mass = list("x"=16, "y"=14)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake
-/obj/item/weapon/reagent_containers/food/snacks/cheesecakeslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("protein", 3)
- reagents.add_reagent("nutriment", 2)
+/obj/item/weapon/reagent_containers/food/snacks/slice/cheesecake/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake
name = "Vanilla Cake"
desc = "A plain cake, not a lie."
icon_state = "plaincake"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/plaincakeslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/plaincake
slices_num = 5
filling_color = "#F7EDD5"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 20
nutriment_desc = list("cake" = 10, "sweetness" = 10, "vanilla" = 15)
+ nutriment_amt = 20
-/obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake/New()
- ..()
-
-/obj/item/weapon/reagent_containers/food/snacks/plaincakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/plaincake
name = "Vanilla Cake slice"
desc = "Just a slice of cake, it is enough for everyone."
icon_state = "plaincake_slice"
@@ -2567,27 +2578,23 @@
filling_color = "#F7EDD5"
bitesize = 2
center_of_mass = list("x"=16, "y"=14)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/plaincake
-/obj/item/weapon/reagent_containers/food/snacks/plaincakeslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 4)
+/obj/item/weapon/reagent_containers/food/snacks/slice/plaincake/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake
name = "Orange Cake"
desc = "A cake with added orange."
icon_state = "orangecake"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/orangecakeslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/orangecake
slices_num = 5
filling_color = "#FADA8E"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 20
nutriment_desc = list("cake" = 10, "sweetness" = 10, "orange" = 15)
+ nutriment_amt = 20
-/obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake/New()
- ..()
-
-/obj/item/weapon/reagent_containers/food/snacks/orangecakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/orangecake
name = "Orange Cake slice"
desc = "Just a slice of cake, it is enough for everyone."
icon_state = "orangecake_slice"
@@ -2595,28 +2602,25 @@
filling_color = "#FADA8E"
bitesize = 2
center_of_mass = list("x"=16, "y"=14)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/orangecake
+
+/obj/item/weapon/reagent_containers/food/snacks/slice/orangecake/filled
+ filled = TRUE
-/obj/item/weapon/reagent_containers/food/snacks/orangecakeslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 4)
/obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake
name = "Lime Cake"
desc = "A cake with added lime."
icon_state = "limecake"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/limecakeslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/limecake
slices_num = 5
filling_color = "#CBFA8E"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 20
nutriment_desc = list("cake" = 10, "sweetness" = 10, "lime" = 15)
+ nutriment_amt = 20
-/obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake/New()
- ..()
- reagents.add_reagent("nutriment", 20)
-/obj/item/weapon/reagent_containers/food/snacks/limecakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/limecake
name = "Lime Cake slice"
desc = "Just a slice of cake, it is enough for everyone."
icon_state = "limecake_slice"
@@ -2624,27 +2628,24 @@
filling_color = "#CBFA8E"
bitesize = 2
center_of_mass = list("x"=16, "y"=14)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/limecake
-/obj/item/weapon/reagent_containers/food/snacks/limecakeslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 4)
+/obj/item/weapon/reagent_containers/food/snacks/slice/limecake/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake
name = "Lemon Cake"
desc = "A cake with added lemon."
icon_state = "lemoncake"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/lemoncakeslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake
slices_num = 5
filling_color = "#FAFA8E"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 20
nutriment_desc = list("cake" = 10, "sweetness" = 10, "lemon" = 15)
+ nutriment_amt = 20
-/obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake/New()
- ..()
-/obj/item/weapon/reagent_containers/food/snacks/lemoncakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake
name = "Lemon Cake slice"
desc = "Just a slice of cake, it is enough for everyone."
icon_state = "lemoncake_slice"
@@ -2652,27 +2653,23 @@
filling_color = "#FAFA8E"
bitesize = 2
center_of_mass = list("x"=16, "y"=14)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/lemoncake
-/obj/item/weapon/reagent_containers/food/snacks/lemoncakeslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 4)
+/obj/item/weapon/reagent_containers/food/snacks/slice/lemoncake/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake
name = "Chocolate Cake"
- desc = "A cake with added chocolate"
+ desc = "A cake with added chocolate."
icon_state = "chocolatecake"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/chocolatecakeslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake
slices_num = 5
filling_color = "#805930"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 20
nutriment_desc = list("cake" = 10, "sweetness" = 10, "chocolate" = 15)
+ nutriment_amt = 20
-/obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake/New()
- ..()
-
-/obj/item/weapon/reagent_containers/food/snacks/chocolatecakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake
name = "Chocolate Cake slice"
desc = "Just a slice of cake, it is enough for everyone."
icon_state = "chocolatecake_slice"
@@ -2680,11 +2677,10 @@
filling_color = "#805930"
bitesize = 2
center_of_mass = list("x"=16, "y"=14)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/chocolatecake
-/obj/item/weapon/reagent_containers/food/snacks/chocolatecakeslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 4)
+/obj/item/weapon/reagent_containers/food/snacks/slice/chocolatecake/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesewheel
name = "Cheese wheel"
@@ -2694,8 +2690,8 @@
slices_num = 5
filling_color = "#FFF700"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 10
nutriment_desc = list("cheese" = 10)
+ nutriment_amt = 10
/obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesewheel/New()
..()
@@ -2714,19 +2710,19 @@
name = "Birthday Cake"
desc = "Happy Birthday..."
icon_state = "birthdaycake"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/birthdaycakeslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake
slices_num = 5
filling_color = "#FFD6D6"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 20
nutriment_desc = list("cake" = 10, "sweetness" = 10)
+ nutriment_amt = 20
/obj/item/weapon/reagent_containers/food/snacks/sliceable/birthdaycake/New()
..()
reagents.add_reagent("sprinkles", 10)
bitesize = 3
-/obj/item/weapon/reagent_containers/food/snacks/birthdaycakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake
name = "Birthday Cake slice"
desc = "A slice of your birthday."
icon_state = "birthdaycakeslice"
@@ -2734,29 +2730,27 @@
filling_color = "#FFD6D6"
bitesize = 2
center_of_mass = list("x"=16, "y"=14)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/birthdaycake
-/obj/item/weapon/reagent_containers/food/snacks/birthdaycakeslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 4)
- reagents.add_reagent("sprinkles", 2)
+/obj/item/weapon/reagent_containers/food/snacks/slice/birthdaycake/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/bread
name = "Bread"
icon_state = "Some plain old Earthen bread."
icon_state = "bread"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/breadslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/bread
slices_num = 5
filling_color = "#FFE396"
center_of_mass = list("x"=16, "y"=9)
- nutriment_amt = 6
nutriment_desc = list("bread" = 6)
+ nutriment_amt = 6
/obj/item/weapon/reagent_containers/food/snacks/sliceable/bread/New()
..()
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/breadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/bread
name = "Bread slice"
desc = "A slice of home."
icon_state = "breadslice"
@@ -2764,43 +2758,42 @@
filling_color = "#D27332"
bitesize = 2
center_of_mass = list("x"=16, "y"=4)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/bread
-/obj/item/weapon/reagent_containers/food/snacks/breadslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 1)
+/obj/item/weapon/reagent_containers/food/snacks/slice/bread/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/creamcheesebread
name = "Cream Cheese Bread"
desc = "Yum yum yum!"
icon_state = "creamcheesebread"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/creamcheesebreadslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/creamcheesebread
slices_num = 5
filling_color = "#FFF896"
center_of_mass = list("x"=16, "y"=9)
- nutriment_amt = 5
nutriment_desc = list("bread" = 6, "cream" = 3, "cheese" = 3)
+ nutriment_amt = 5
/obj/item/weapon/reagent_containers/food/snacks/sliceable/creamcheesebread/New()
..()
reagents.add_reagent("protein", 15)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/creamcheesebreadslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/creamcheesebread
name = "Cream Cheese Bread slice"
desc = "A slice of yum!"
icon_state = "creamcheesebreadslice"
trash = /obj/item/trash/plate
filling_color = "#FFF896"
bitesize = 2
- center_of_mass = list("x"=16, "y"=13)
+ center_of_mass = list("x"=16, "y"=14)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/creamcheesebread
+
+
+/obj/item/weapon/reagent_containers/food/snacks/slice/creamcheesebread/filled
+ filled = TRUE
-/obj/item/weapon/reagent_containers/food/snacks/creamcheesebreadslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("protein", 3)
- reagents.add_reagent("nutriment", 1)
/obj/item/weapon/reagent_containers/food/snacks/watermelonslice
name = "Watermelon Slice"
@@ -2810,26 +2803,18 @@
bitesize = 2
center_of_mass = list("x"=16, "y"=10)
-/obj/item/weapon/reagent_containers/food/snacks/watermelonslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("watermelonjuice", 1)
-
/obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake
name = "Apple Cake"
- desc = "A cake centred with Apple"
+ desc = "A cake centred with apples."
icon_state = "applecake"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/applecakeslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/applecake
slices_num = 5
filling_color = "#EBF5B8"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 15
nutriment_desc = list("cake" = 10, "sweetness" = 10, "apple" = 15)
+ nutriment_amt = 15
-/obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake/New()
- ..()
-
-/obj/item/weapon/reagent_containers/food/snacks/applecakeslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/applecake
name = "Apple Cake slice"
desc = "A slice of heavenly cake."
icon_state = "applecakeslice"
@@ -2837,27 +2822,23 @@
filling_color = "#EBF5B8"
bitesize = 2
center_of_mass = list("x"=16, "y"=14)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/applecake
-/obj/item/weapon/reagent_containers/food/snacks/applecakeslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 3)
+/obj/item/weapon/reagent_containers/food/snacks/slice/applecake/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie
name = "Pumpkin Pie"
desc = "A delicious treat for the autumn months."
icon_state = "pumpkinpie"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/pumpkinpieslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie
slices_num = 5
filling_color = "#F5B951"
center_of_mass = list("x"=16, "y"=10)
- nutriment_amt = 15
nutriment_desc = list("pie" = 5, "cream" = 5, "pumpkin" = 5)
+ nutriment_amt = 15
-/obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie/New()
- ..()
-
-/obj/item/weapon/reagent_containers/food/snacks/pumpkinpieslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie
name = "Pumpkin Pie slice"
desc = "A slice of pumpkin pie, with whipped cream on top. Perfection."
icon_state = "pumpkinpieslice"
@@ -2865,23 +2846,21 @@
filling_color = "#F5B951"
bitesize = 2
center_of_mass = list("x"=16, "y"=12)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pumpkinpie
-/obj/item/weapon/reagent_containers/food/snacks/pumpkinpieslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 3)
+/obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/cracker
name = "Cracker"
desc = "It's a salted cracker."
icon_state = "cracker"
filling_color = "#F5DEB8"
- center_of_mass = list("x"=17, "y"=6)
- nutriment_amt = 1
+ center_of_mass = list("x"=16, "y"=6)
nutriment_desc = list("salt" = 1, "cracker" = 2)
+ nutriment_amt = 1
+
-/obj/item/weapon/reagent_containers/food/snacks/cracker/New()
- ..()
/////////////////////////////////////////////////PIZZA////////////////////////////////////////
@@ -2893,11 +2872,11 @@
name = "Margherita"
desc = "The golden standard of pizzas."
icon_state = "pizzamargherita"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/margheritaslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/margherita
slices_num = 6
center_of_mass = list("x"=16, "y"=11)
- nutriment_amt = 35
nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 15)
+ nutriment_amt = 35
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita/New()
..()
@@ -2905,30 +2884,27 @@
reagents.add_reagent("tomatojuice", 6)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/margheritaslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/margherita
name = "Margherita slice"
desc = "A slice of the classic pizza."
icon_state = "pizzamargheritaslice"
filling_color = "#BAA14C"
bitesize = 2
- center_of_mass = list("x"=18, "y"=13)
+ center_of_mass = list("x"=16, "y"=13)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/margherita
-/obj/item/weapon/reagent_containers/food/snacks/margheritaslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 5)
- reagents.add_reagent("protein", 1)
- reagents.add_reagent("tomatojuice", 1)
+/obj/item/weapon/reagent_containers/food/snacks/slice/margherita/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza
name = "Meatpizza"
desc = "A pizza with meat topping."
icon_state = "meatpizza"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/meatpizzaslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/meatpizza
slices_num = 6
center_of_mass = list("x"=16, "y"=11)
- nutriment_amt = 10
nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 15)
+ nutriment_amt = 10
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza/New()
..()
@@ -2936,58 +2912,54 @@
reagents.add_reagent("tomatojuice", 6)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/meatpizzaslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/meatpizza
name = "Meatpizza slice"
desc = "A slice of a meaty pizza."
icon_state = "meatpizzaslice"
filling_color = "#BAA14C"
bitesize = 2
- center_of_mass = list("x"=18, "y"=13)
+ center_of_mass = list("x"=16, "y"=13)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/meatpizza
-/obj/item/weapon/reagent_containers/food/snacks/meatpizzaslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("protein", 7)
- reagents.add_reagent("tomatojuice", 1)
+/obj/item/weapon/reagent_containers/food/snacks/slice/meatpizza/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza
name = "Mushroompizza"
- desc = "Very special pizza"
+ desc = "Very special pizza."
icon_state = "mushroompizza"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/mushroompizzaslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza
slices_num = 6
center_of_mass = list("x"=16, "y"=11)
- nutriment_amt = 35
nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 5, "mushroom" = 10)
+ nutriment_amt = 35
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza/New()
..()
reagents.add_reagent("protein", 5)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/mushroompizzaslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza
name = "Mushroompizza slice"
desc = "Maybe it is the last slice of pizza in your life."
icon_state = "mushroompizzaslice"
filling_color = "#BAA14C"
bitesize = 2
- center_of_mass = list("x"=18, "y"=13)
+ center_of_mass = list("x"=16, "y"=13)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/mushroompizza
-/obj/item/weapon/reagent_containers/food/snacks/mushroompizzaslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 5)
- reagents.add_reagent("protein", 1)
+/obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza/filled
+ filled = TRUE
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza
name = "Vegetable pizza"
- desc = "No one of Tomato Sapiens were harmed during making this pizza"
+ desc = "No one of Tomato Sapiens were harmed during making this pizza."
icon_state = "vegetablepizza"
- slice_path = /obj/item/weapon/reagent_containers/food/snacks/vegetablepizzaslice
+ slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/vegetablepizza
slices_num = 6
center_of_mass = list("x"=16, "y"=11)
- nutriment_amt = 25
nutriment_desc = list("pizza crust" = 10, "tomato" = 10, "cheese" = 5, "eggplant" = 5, "carrot" = 5, "corn" = 5)
+ nutriment_amt = 25
/obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza/New()
..()
@@ -2996,21 +2968,17 @@
reagents.add_reagent("imidazoline", 12)
bitesize = 2
-/obj/item/weapon/reagent_containers/food/snacks/vegetablepizzaslice
+/obj/item/weapon/reagent_containers/food/snacks/slice/vegetablepizza
name = "Vegetable pizza slice"
- desc = "A slice of the most green pizza of all pizzas not containing green ingredients "
+ desc = "A slice of the most green pizza of all pizzas not containing green ingredients."
icon_state = "vegetablepizzaslice"
filling_color = "#BAA14C"
bitesize = 2
- center_of_mass = list("x"=18, "y"=13)
+ center_of_mass = list("x"=16, "y"=13)
+ whole_path = /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/vegetablepizza
-/obj/item/weapon/reagent_containers/food/snacks/vegetablepizzaslice/New()
- ..()
- if(!(reagents.total_volume))
- reagents.add_reagent("nutriment", 4)
- reagents.add_reagent("protein", 1)
- reagents.add_reagent("tomatojuice", 1)
- reagents.add_reagent("imidazoline", 2)
+/obj/item/weapon/reagent_containers/food/snacks/slice/vegetablepizza/filled
+ filled = TRUE
/obj/item/pizzabox
name = "pizza box"
@@ -3024,46 +2992,34 @@
var/list/boxes = list() // If the boxes are stacked, they come here
var/boxtag = ""
-/obj/item/pizzabox/proc/closepizzabox()
-
- if(boxes.len > 0)
- return
-
- open = !open
-
- if(open && pizza)
- ismessy = 1
-
- update_icon()
-
/obj/item/pizzabox/update_icon()
overlays = list()
// Set appropriate description
- if(open && pizza)
+ if( open && pizza )
desc = "A box suited for pizzas. It appears to have a [pizza.name] inside."
- else if(boxes.len > 0)
+ else if( boxes.len > 0 )
desc = "A pile of boxes suited for pizzas. There appears to be [boxes.len + 1] boxes in the pile."
var/obj/item/pizzabox/topbox = boxes[boxes.len]
var/toptag = topbox.boxtag
- if(toptag != "")
+ if( toptag != "" )
desc = "[desc] The box on top has a tag, it reads: '[toptag]'."
else
desc = "A box suited for pizzas."
- if(boxtag != "")
+ if( boxtag != "" )
desc = "[desc] The box has a tag, it reads: '[boxtag]'."
// Icon states and overlays
- if(open)
- if(ismessy)
+ if( open )
+ if( ismessy )
icon_state = "pizzabox_messy"
else
icon_state = "pizzabox_open"
- if(pizza)
+ if( pizza )
var/image/pizzaimg = image("food.dmi", icon_state = pizza.icon_state)
pizzaimg.pixel_y = -3
overlays += pizzaimg
@@ -3072,33 +3028,33 @@
else
// Stupid code because byondcode sucks
var/doimgtag = 0
- if(boxes.len > 0)
+ if( boxes.len > 0 )
var/obj/item/pizzabox/topbox = boxes[boxes.len]
- if(topbox.boxtag != "")
+ if( topbox.boxtag != "" )
doimgtag = 1
else
- if(boxtag != "")
+ if( boxtag != "" )
doimgtag = 1
- if(doimgtag)
+ if( doimgtag )
var/image/tagimg = image("food.dmi", icon_state = "pizzabox_tag")
tagimg.pixel_y = boxes.len * 3
overlays += tagimg
icon_state = "pizzabox[boxes.len+1]"
-/obj/item/pizzabox/attack_hand(mob/user as mob)
+/obj/item/pizzabox/attack_hand( mob/user as mob )
if( open && pizza )
- user.put_in_hands(pizza)
+ user.put_in_hands( pizza )
- user << "You take \the [src.pizza] out of the [src]."
+ to_chat(user, "You take \the [src.pizza] out of \the [src].")
src.pizza = null
update_icon()
return
- if(boxes.len > 0)
- if(user.get_inactive_hand() != src)
+ if( boxes.len > 0 )
+ if( user.get_inactive_hand() != src )
..()
return
@@ -3106,74 +3062,76 @@
boxes -= box
user.put_in_hands( box )
- user << "You remove \the topmost [src] from your hand."
+ to_chat(user, "You remove the topmost [src] from your hand.")
box.update_icon()
update_icon()
return
..()
-/obj/item/pizzabox/attack_self(mob/user as mob)
+/obj/item/pizzabox/attack_self( mob/user as mob )
- closepizzabox()
+ if( boxes.len > 0 )
+ return
-/obj/item/pizzabox/AltClick()
+ open = !open
- if(Adjacent(usr))
- closepizzabox()
+ if( open && pizza )
+ ismessy = 1
+
+ update_icon()
/obj/item/pizzabox/attackby( obj/item/I as obj, mob/user as mob )
- if(istype(I, /obj/item/pizzabox/))
+ if( istype(I, /obj/item/pizzabox/) )
var/obj/item/pizzabox/box = I
- if(!box.open && !src.open)
+ if( !box.open && !src.open )
// Make a list of all boxes to be added
var/list/boxestoadd = list()
boxestoadd += box
for(var/obj/item/pizzabox/i in box.boxes)
boxestoadd += i
- if((boxes.len+1) + boxestoadd.len <= 5)
+ if( (boxes.len+1) + boxestoadd.len <= 5 )
user.drop_item()
box.loc = src
box.boxes = list() // Clear the box boxes so we don't have boxes inside boxes. - Xzibit
- src.boxes.Add(boxestoadd)
+ src.boxes.Add( boxestoadd )
box.update_icon()
update_icon()
- user << "You put \the [box] ontop of the [src]!"
+ to_chat(user, "You put \the [box] ontop of \the [src]!")
else
- user << "\The stack is too high!"
+ to_chat(user, "The stack is too high!")
else
- user << "Close \the [box] first!"
+ to_chat(user, "Close \the [box] first!")
return
- if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/)) // Long ass fucking object name
+ if( istype(I, /obj/item/weapon/reagent_containers/food/snacks/sliceable/pizza/) ) // Long ass fucking object name
- if(open)
- if(!pizza)
- user.drop_item()
- I.loc = src
- pizza = I
- update_icon()
- user << "You put \the [I] in \the [src]!"
- else
- user << "\The [src] is full! It already has a [pizza] inside."
+ if( src.open )
+ user.drop_item()
+ I.loc = src
+ src.pizza = I
+
+ update_icon()
+
+ to_chat(user, "You put \the [I] in \the [src]!")
else
- user << "You try to push \the [I] through the lid but it doesn't work!"
-
+ to_chat(user, "You try to push \the [I] through the lid but it doesn't work!")
return
- if(istype(I, /obj/item/weapon/pen/))
- if(open)
+ if( istype(I, /obj/item/weapon/pen/) )
+
+ if( src.open )
return
var/t = sanitize(input("Enter what you want to add to the tag:", "Write", null, null) as text, 30)
var/obj/item/pizzabox/boxtotagto = src
- if(boxes.len > 0)
+ if( boxes.len > 0 )
boxtotagto = boxes[boxes.len]
boxtotagto.boxtag = copytext("[boxtotagto.boxtag][t]", 1, 30)
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 483defc3985..ed27e1a259b 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -36,7 +36,7 @@
/obj/machinery/disease2/incubator,
/obj/machinery/disposal,
/mob/living/simple_animal/cow,
- /mob/living/simple_animal/hostile/retaliate/goat,
+ /mob/living/simple_animal/retaliate/goat,
/obj/machinery/computer/centrifuge,
/obj/machinery/sleeper,
/obj/machinery/smartfridge/,
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 5c7459e3b2a..058e09c6f73 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -76,7 +76,6 @@
switch(mode)
if(SYRINGE_DRAW)
-
if(!reagents.get_free_space())
user << "The syringe is full."
mode = SYRINGE_INJECT
@@ -137,7 +136,7 @@
user << "[target] is empty."
return
- if(!target.is_open_container() && !istype(target, /obj/structure/reagent_dispensers) && !istype(target, /obj/item/slime_extract))
+ if(!target.is_open_container() && !istype(target, /obj/structure/reagent_dispensers) && !istype(target, /obj/item/slime_extract) && !istype(target, /obj/item/weapon/reagent_containers/food))
user << "You cannot directly remove reagents from this object."
return
@@ -209,7 +208,7 @@
trans = reagents.trans_to_mob(target, amount_per_transfer_from_this, CHEM_BLOOD)
admin_inject_log(user, target, src, contained, trans)
else
- trans = reagents.trans_to(target, amount_per_transfer_from_this)
+ trans = reagents.trans_to_obj(target, amount_per_transfer_from_this)
if(trans)
user << "You inject [trans] units of the solution. The syringe now contains [src.reagents.total_volume] units."
else
diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm
index ee1bbcaf2fa..49678c966ca 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -1586,6 +1586,14 @@ CIRCUITS BELOW
build_path = /obj/item/weapon/implant/integrated_circuit
sort_string = "VCAAE"
+/datum/design/item/translator
+ name = "handheld translator"
+ id = "translator"
+ req_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 3)
+ materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 2000)
+ build_path = /obj/item/device/universal_translator
+ sort_string = "HABBA"
+
/* Uncomment if someone makes these buildable
/datum/design/circuit/general_alert
name = "general alert console"
diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm
index 60aabdf3f80..be489f96377 100644
--- a/code/modules/research/protolathe.dm
+++ b/code/modules/research/protolathe.dm
@@ -85,6 +85,8 @@
else if(busy)
icon_state = "protolathe_n"
else
+ if(icon_state == "protolathe_n")
+ flick("protolathe_u", src) // If lid WAS closed, show opening animation
icon_state = "protolathe"
/obj/machinery/r_n_d/protolathe/attackby(var/obj/item/O as obj, var/mob/user as mob)
diff --git a/code/modules/security levels/security levels.dm b/code/modules/security levels/security levels.dm
index 4b73c0dd28d..32d752c7730 100644
--- a/code/modules/security levels/security levels.dm
+++ b/code/modules/security levels/security levels.dm
@@ -47,9 +47,14 @@
var/newlevel = get_security_level()
for(var/obj/machinery/firealarm/FA in machines)
- if(FA.z in config.contact_levels)
+ if(FA.z in using_map.contact_levels)
FA.set_security_level(newlevel)
+ if(level >= SEC_LEVEL_RED)
+ atc.reroute_traffic(yes = 1) // Tell them fuck off we're busy.
+ else
+ atc.reroute_traffic(yes = 0)
+
/proc/get_security_level()
switch(security_level)
diff --git a/code/modules/shieldgen/emergency_shield.dm b/code/modules/shieldgen/emergency_shield.dm
index 9e8a752122b..3690a1f2ba9 100644
--- a/code/modules/shieldgen/emergency_shield.dm
+++ b/code/modules/shieldgen/emergency_shield.dm
@@ -84,8 +84,14 @@
if(1)
qdel(src)
if(2)
+ if(prob(75))
+ qdel(src)
+ if(3)
if(prob(50))
qdel(src)
+ if(4)
+ if(prob(25))
+ qdel(src)
/obj/machinery/shield/hitby(AM as mob|obj)
@@ -264,7 +270,7 @@
else
user << "The device must first be secured to the floor."
return
-
+
/obj/machinery/shieldgen/emag_act(var/remaining_charges, var/mob/user)
if(!malfunction)
malfunction = 1
diff --git a/code/modules/shuttles/shuttle_emergency.dm b/code/modules/shuttles/shuttle_emergency.dm
index c468bbb0170..bd2eaaa770d 100644
--- a/code/modules/shuttles/shuttle_emergency.dm
+++ b/code/modules/shuttles/shuttle_emergency.dm
@@ -26,11 +26,12 @@
if (origin == area_station) //leaving the station
emergency_shuttle.departed = 1
+ var/estimated_time = round(emergency_shuttle.estimate_arrival_time()/60,1)
if (emergency_shuttle.evac)
- priority_announcement.Announce("The Emergency Shuttle has left the station. Estimate [round(emergency_shuttle.estimate_arrival_time()/60,1)] minutes until the shuttle docks at [dock_name].")
+ priority_announcement.Announce(replacetext(replacetext(using_map.emergency_shuttle_leaving_dock, "%dock_name%", "[using_map.dock_name]"), "%ETD%", "[estimated_time] minute\s"))
else
- priority_announcement.Announce("The Scheduled Transfer Shuttle has left the station. Estimate [round(emergency_shuttle.estimate_arrival_time()/60,1)] minutes until the shuttle docks at [dock_name].")
+ priority_announcement.Announce(replacetext(replacetext(using_map.shuttle_leaving_dock, "%dock_name%", "[using_map.dock_name]"), "%ETA%", "[estimated_time] minute\s"))
/datum/shuttle/ferry/emergency/can_launch(var/user)
if (istype(user, /obj/machinery/computer/shuttle_control/emergency))
@@ -183,9 +184,9 @@
if (shuttle.in_use)
shuttle_status = "Busy."
else if (!shuttle.location)
- shuttle_status = "Standing-by at [station_name]."
+ shuttle_status = "Standing-by at [station_name()]."
else
- shuttle_status = "Standing-by at [dock_name]."
+ shuttle_status = "Standing-by at [using_map.dock_name]."
if(WAIT_LAUNCH, FORCE_LAUNCH)
shuttle_status = "Shuttle has recieved command and will depart shortly."
if(WAIT_ARRIVE)
diff --git a/code/modules/shuttles/shuttle_specops.dm b/code/modules/shuttles/shuttle_specops.dm
index 5ef0c921709..434bb37f42b 100644
--- a/code/modules/shuttles/shuttle_specops.dm
+++ b/code/modules/shuttles/shuttle_specops.dm
@@ -62,7 +62,7 @@
var/obj/machinery/computer/C = user
if(world.time <= reset_time)
- C.visible_message("\blue [boss_name] will not allow the Special Operations shuttle to launch yet.")
+ C.visible_message("\blue [using_map.boss_name] will not allow the Special Operations shuttle to launch yet.")
if (((world.time - reset_time)/10) > 60)
C.visible_message("\blue [-((world.time - reset_time)/10)/60] minutes remain!")
else
@@ -88,18 +88,18 @@
/datum/shuttle/ferry/multidock/specops/move(var/area/origin,var/area/destination)
..(origin, destination)
-
+
spawn(20)
if (!location) //just arrived home
for(var/turf/T in get_area_turfs(destination))
var/mob/M = locate(/mob) in T
- M << "You have arrived at [boss_name]. Operation has ended!"
+ M << "You have arrived at [using_map.boss_name]. Operation has ended!"
else //just left for the station
launch_mauraders()
for(var/turf/T in get_area_turfs(destination))
var/mob/M = locate(/mob) in T
- M << "You have arrived at [station_name]. Commence operation!"
-
+ M << "You have arrived at [station_name()]. Commence operation!"
+
var/obj/machinery/light/small/readylight/light = locate() in T
if(light) light.set_state(1)
diff --git a/code/modules/shuttles/shuttles_multi.dm b/code/modules/shuttles/shuttles_multi.dm
index 35bc9a8315a..47b430329a7 100644
--- a/code/modules/shuttles/shuttles_multi.dm
+++ b/code/modules/shuttles/shuttles_multi.dm
@@ -59,14 +59,14 @@
if(cloaked || isnull(departure_message))
return
- command_announcement.Announce(departure_message,(announcer ? announcer : "[boss_name]"))
+ command_announcement.Announce(departure_message,(announcer ? announcer : "[using_map.boss_name]"))
/datum/shuttle/multi_shuttle/proc/announce_arrival()
if(cloaked || isnull(arrival_message))
return
- command_announcement.Announce(arrival_message,(announcer ? announcer : "[boss_name]"))
+ command_announcement.Announce(arrival_message,(announcer ? announcer : "[using_map.boss_name]"))
/obj/machinery/computer/shuttle_control/multi
diff --git a/code/modules/spells/aoe_turf/disable_tech.dm b/code/modules/spells/aoe_turf/disable_tech.dm
index 5192ecb664a..9acbf95369d 100644
--- a/code/modules/spells/aoe_turf/disable_tech.dm
+++ b/code/modules/spells/aoe_turf/disable_tech.dm
@@ -11,13 +11,15 @@
cooldown_min = 200 //50 deciseconds reduction per rank
- var/emp_heavy = 6
- var/emp_light = 10
+ var/emp_heavy = 3
+ var/emp_med = 5
+ var/emp_light = 8
+ var/emp_long = 10
hud_state = "wiz_tech"
/spell/aoe_turf/disable_tech/cast(list/targets)
for(var/turf/target in targets)
- empulse(get_turf(target), emp_heavy, emp_light)
+ empulse(get_turf(target), emp_heavy, emp_med, emp_light, emp_long)
return
\ No newline at end of file
diff --git a/code/modules/spells/spell_code.dm b/code/modules/spells/spell_code.dm
index 6b648fb3926..4ebf2def643 100644
--- a/code/modules/spells/spell_code.dm
+++ b/code/modules/spells/spell_code.dm
@@ -190,7 +190,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
if(!user_turf)
user << "You cannot cast spells in null space!"
- if(spell_flags & Z2NOCAST && (user_turf.z in config.admin_levels)) //Certain spells are not allowed on the centcomm zlevel
+ if(spell_flags & Z2NOCAST && (user_turf.z in using_map.admin_levels)) //Certain spells are not allowed on the centcomm zlevel
return 0
if(spell_flags & CONSTRUCT_CHECK)
diff --git a/code/modules/spells/spellbook.dm b/code/modules/spells/spellbook.dm
index 34923745a46..a28f03e8feb 100644
--- a/code/modules/spells/spellbook.dm
+++ b/code/modules/spells/spellbook.dm
@@ -432,4 +432,4 @@
/obj/item/weapon/spellbook/oneuse/charge/recoil(mob/user as mob)
..()
user <<"[src] suddenly feels very warm!"
- empulse(src, 1, 1)
+ empulse(src, 1, 1, 1, 1)
diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm
index a76bed18e68..df9c900d384 100644
--- a/code/modules/supermatter/supermatter.dm
+++ b/code/modules/supermatter/supermatter.dm
@@ -152,8 +152,8 @@
/obj/machinery/power/supermatter/get_transit_zlevel()
//don't send it back to the station -- most of the time
if(prob(99))
- var/list/candidates = accessible_z_levels.Copy()
- for(var/zlevel in config.station_levels)
+ var/list/candidates = using_map.accessible_z_levels.Copy()
+ for(var/zlevel in using_map.station_levels)
candidates.Remove("[zlevel]")
candidates.Remove("[src.z]")
diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm
index e9fe4299ff8..176724290fb 100644
--- a/code/modules/surgery/other.dm
+++ b/code/modules/surgery/other.dm
@@ -146,10 +146,8 @@
var/trans = container.reagents.trans_to_mob(target, container.amount_per_transfer_from_this, CHEM_BLOOD) //technically it's contact, but the reagents are being applied to internal tissue
if (trans > 0)
-
- if(container.reagents.has_reagent("peridaxon"))
- affected.status &= ~ORGAN_DEAD
- affected.owner.update_body(1)
+ affected.status &= ~ORGAN_DEAD
+ affected.owner.update_body(1)
user.visible_message("\blue [user] applies [trans] units of the solution to affected tissue in [target]'s [affected.name]", \
"\blue You apply [trans] units of the solution to affected tissue in [target]'s [affected.name] with \the [tool].")
diff --git a/code/modules/tables/presets.dm b/code/modules/tables/presets.dm
index 933f54ea8b7..171bfe2b2cd 100644
--- a/code/modules/tables/presets.dm
+++ b/code/modules/tables/presets.dm
@@ -28,7 +28,7 @@
material = get_material_by_name(DEFAULT_TABLE_MATERIAL)
reinforced = get_material_by_name(DEFAULT_WALL_MATERIAL)
..()
-
+
steel_reinforced
icon_state = "reinf_preview"
color = "#666666"
@@ -37,6 +37,14 @@
reinforced = get_material_by_name(DEFAULT_WALL_MATERIAL)
..()
+ wooden_reinforced
+ icon_state = "reinf_preview"
+ color = "#824B28"
+ New()
+ material = get_material_by_name("wood")
+ reinforced = get_material_by_name(DEFAULT_WALL_MATERIAL)
+ ..()
+
woodentable
icon_state = "plain_preview"
color = "#824B28"
diff --git a/code/modules/turbolift/_turbolift.dm b/code/modules/turbolift/_turbolift.dm
new file mode 100644
index 00000000000..088bf39c8c4
--- /dev/null
+++ b/code/modules/turbolift/_turbolift.dm
@@ -0,0 +1,12 @@
+/*
+ * Turbolifts! Sort of like multishuttles-lite.
+ *
+ * How-to: Map /obj/turbolift_map_holder in at the bottom of the shaft, give it a depth
+ * value equivalent to the number of floors it should span (inclusive of the first),
+ * and at runtime it will update the map, set areas and create control panels and
+ * wifi-set doors appropriate to itself. You will save time at init if you map the
+ * elevator shaft in properly before runtime, but ultimately you're just avoiding a
+ * bunch of ChangeTurf() calls.
+ */
+
+var/list/turbolifts = list()
\ No newline at end of file
diff --git a/code/modules/turbolift/turbolift.dm b/code/modules/turbolift/turbolift.dm
new file mode 100644
index 00000000000..7d2f3c11a83
--- /dev/null
+++ b/code/modules/turbolift/turbolift.dm
@@ -0,0 +1,122 @@
+// Lift master datum. One per turbolift.
+/datum/turbolift
+ var/datum/turbolift_floor/target_floor // Where are we going?
+ var/datum/turbolift_floor/current_floor // Where is the lift currently?
+ var/list/doors = list() // Doors inside the lift structure.
+ var/list/queued_floors = list() // Where are we moving to next?
+ var/list/floors = list() // All floors in this system.
+ var/move_delay = 30 // Time between floor changes.
+ var/floor_wait_delay = 85 // Time to wait at floor stops.
+ var/obj/structure/lift/panel/control_panel_interior // Lift control panel.
+ var/doors_closing = 0 // Whether doors are in the process of closing
+
+ var/tmp/moving_upwards
+ var/tmp/busy
+
+/datum/turbolift/proc/emergency_stop()
+ queued_floors.Cut()
+ target_floor = null
+ open_doors()
+
+/datum/turbolift/proc/doors_are_open(var/datum/turbolift_floor/use_floor = current_floor)
+ for(var/obj/machinery/door/airlock/door in (use_floor ? (doors + use_floor.doors) : doors))
+ if(!door.density)
+ return 1
+ return 0
+
+/datum/turbolift/proc/open_doors(var/datum/turbolift_floor/use_floor = current_floor)
+ for(var/obj/machinery/door/airlock/door in (use_floor ? (doors + use_floor.doors) : doors))
+ //door.command("open")
+ spawn(0)
+ door.open()
+ return
+
+/datum/turbolift/proc/close_doors(var/datum/turbolift_floor/use_floor = current_floor)
+ for(var/obj/machinery/door/airlock/door in (use_floor ? (doors + use_floor.doors) : doors))
+ //door.command("close")
+ spawn(0)
+ door.close()
+ return
+
+/datum/turbolift/proc/do_move()
+
+ var/current_floor_index = floors.Find(current_floor)
+
+ if(!target_floor)
+ if(!queued_floors || !queued_floors.len)
+ return 0
+ target_floor = queued_floors[1]
+ queued_floors -= target_floor
+ if(current_floor_index < floors.Find(target_floor))
+ moving_upwards = 1
+ else
+ moving_upwards = 0
+
+ if(doors_are_open())
+ if(!doors_closing)
+ close_doors()
+ doors_closing = 1
+ return 1
+ else // We failed to close the doors - probably, someone is blocking them; stop trying to move
+ doors_closing = 0
+ open_doors()
+ control_panel_interior.audible_message("\The [current_floor.ext_panel] buzzes loudly.")
+ playsound(control_panel_interior.loc, "sound/machines/buzz-two.ogg", 50, 1)
+ return 0
+
+ doors_closing = 0 // The doors weren't open, so they are done closing
+
+ var/area/turbolift/origin = locate(current_floor.area_ref)
+
+ if(target_floor == current_floor)
+
+ playsound(control_panel_interior.loc, origin.arrival_sound, 50, 1)
+ target_floor.arrived(src)
+ target_floor = null
+
+ sleep(15)
+ control_panel_interior.visible_message("The elevator announces, \"[origin.lift_announce_str]\"")
+ sleep(floor_wait_delay)
+
+ return 1
+
+ // Work out where we're headed.
+ var/datum/turbolift_floor/next_floor
+ if(moving_upwards)
+ next_floor = floors[current_floor_index+1]
+ else
+ next_floor = floors[current_floor_index-1]
+
+ var/area/turbolift/destination = locate(next_floor.area_ref)
+
+ if(!istype(origin) || !istype(destination) || (origin == destination))
+ return 0
+
+ for(var/turf/T in destination)
+ for(var/atom/movable/AM in T)
+ if(istype(AM, /mob/living))
+ var/mob/living/M = AM
+ M.gib()
+ else if(AM.simulated)
+ qdel(AM)
+
+ origin.move_contents_to(destination)
+
+ if((locate(/obj/machinery/power) in destination) || (locate(/obj/structure/cable) in destination))
+ makepowernets()
+
+ current_floor = next_floor
+ control_panel_interior.visible_message("The elevator [moving_upwards ? "rises" : "descends"] smoothly.")
+
+ return 1
+
+/datum/turbolift/proc/queue_move_to(var/datum/turbolift_floor/floor)
+ if(!floor || !(floor in floors) || (floor in queued_floors))
+ return // STOP PRESSING THE BUTTON.
+ floor.pending_move(src)
+ queued_floors |= floor
+ turbolift_controller.lift_is_moving(src)
+
+// TODO: dummy machine ('lift mechanism') in powered area for functionality/blackout checks.
+/datum/turbolift/proc/is_functional()
+ return 1
\ No newline at end of file
diff --git a/code/modules/turbolift/turbolift_areas.dm b/code/modules/turbolift/turbolift_areas.dm
new file mode 100644
index 00000000000..dbf568aec2e
--- /dev/null
+++ b/code/modules/turbolift/turbolift_areas.dm
@@ -0,0 +1,11 @@
+// Used for creating the exchange areas.
+/area/turbolift
+ name = "Turbolift"
+ base_turf = /turf/simulated/open
+ requires_power = 0
+ sound_env = SMALL_ENCLOSED
+
+ var/lift_floor_label = null
+ var/lift_floor_name = null
+ var/lift_announce_str = "Ding!"
+ var/arrival_sound = 'sound/machines/ding.ogg'
diff --git a/code/modules/turbolift/turbolift_console.dm b/code/modules/turbolift/turbolift_console.dm
new file mode 100644
index 00000000000..4cbee6a7737
--- /dev/null
+++ b/code/modules/turbolift/turbolift_console.dm
@@ -0,0 +1,155 @@
+// Base type, do not use.
+/obj/structure/lift
+ name = "turbolift control component"
+ icon = 'icons/obj/turbolift.dmi'
+ anchored = 1
+ density = 0
+ layer = 4
+
+ var/datum/turbolift/lift
+
+/obj/structure/lift/set_dir(var/newdir)
+ . = ..()
+ pixel_x = 0
+ pixel_y = 0
+ if(dir & NORTH)
+ pixel_y = -32
+ else if(dir & SOUTH)
+ pixel_y = 32
+ else if(dir & EAST)
+ pixel_x = -32
+ else if(dir & WEST)
+ pixel_x = 32
+
+/obj/structure/lift/proc/pressed(var/mob/user)
+ if(!istype(user, /mob/living/silicon))
+ if(user.a_intent == I_HURT)
+ user.visible_message("\The [user] hammers on the lift button!")
+ else
+ user.visible_message("\The [user] presses the lift button.")
+
+
+/obj/structure/lift/New(var/newloc, var/datum/turbolift/_lift)
+ lift = _lift
+ return ..(newloc)
+
+/obj/structure/lift/attack_ai(var/mob/user)
+ return attack_hand(user)
+
+/obj/structure/lift/attack_generic(var/mob/user)
+ return attack_hand(user)
+
+/obj/structure/lift/attack_hand(var/mob/user)
+ return interact(user)
+
+/obj/structure/lift/interact(var/mob/user)
+ if(!lift.is_functional())
+ return 0
+ return 1
+// End base.
+
+// Button. No HTML interface, just calls the associated lift to its floor.
+/obj/structure/lift/button
+ name = "elevator button"
+ desc = "A call button for an elevator. Be sure to hit it three hundred times."
+ icon_state = "button"
+ var/light_up = FALSE
+ var/datum/turbolift_floor/floor
+
+/obj/structure/lift/button/Destroy()
+ if(floor && floor.ext_panel == src)
+ floor.ext_panel = null
+ floor = null
+ return ..()
+
+/obj/structure/lift/button/proc/reset()
+ light_up = FALSE
+ update_icon()
+
+/obj/structure/lift/button/interact(var/mob/user)
+ if(!..())
+ return
+ light_up()
+ pressed(user)
+ if(floor == lift.current_floor)
+ lift.open_doors()
+ spawn(3)
+ reset()
+ return
+ lift.queue_move_to(floor)
+
+/obj/structure/lift/button/proc/light_up()
+ light_up = TRUE
+ update_icon()
+
+/obj/structure/lift/button/update_icon()
+ if(light_up)
+ icon_state = "button_lit"
+ else
+ icon_state = initial(icon_state)
+
+// End button.
+
+// Panel. Lists floors (HTML), moves with the elevator, schedules a move to a given floor.
+/obj/structure/lift/panel
+ name = "elevator control panel"
+ icon_state = "panel"
+
+
+/obj/structure/lift/panel/attack_ghost(var/mob/user)
+ return interact(user)
+
+/obj/structure/lift/panel/interact(var/mob/user)
+ if(!..())
+ return
+
+ var/dat = list()
+ dat += "Lift panel"
+
+ //the floors list stores levels in order of increasing Z
+ //therefore, to display upper levels at the top of the menu and
+ //lower levels at the bottom, we need to go through the list in reverse
+ for(var/i in lift.floors.len to 1 step -1)
+ var/datum/turbolift_floor/floor = lift.floors[i]
+ var/label = floor.label? floor.label : "Level #[i]"
+ dat += ""
+ dat += "[label]: [floor.name] "
+
+ dat += ""
+ if(lift.doors_are_open())
+ dat += "Close Doors "
+ else
+ dat += "Open Doors "
+ dat += "Emergency Stop"
+ dat += ""
+
+ var/datum/browser/popup = new(user, "turbolift_panel", "Lift Panel", 230, 260)
+ popup.set_content(jointext(dat, null))
+ popup.open()
+ return
+
+/obj/structure/lift/panel/Topic(href, href_list)
+ . = ..()
+ if(.)
+ return
+
+ var/panel_interact
+ if(href_list["move_to_floor"])
+ lift.queue_move_to(locate(href_list["move_to_floor"]))
+ panel_interact = 1
+ if(href_list["open_doors"])
+ panel_interact = 1
+ lift.open_doors()
+ if(href_list["close_doors"])
+ panel_interact = 1
+ lift.close_doors()
+ if(href_list["emergency_stop"])
+ panel_interact = 1
+ lift.emergency_stop()
+
+ if(panel_interact)
+ pressed(usr)
+
+ return 0
+
+// End panel.
\ No newline at end of file
diff --git a/code/modules/turbolift/turbolift_door.dm b/code/modules/turbolift/turbolift_door.dm
new file mode 100644
index 00000000000..79bf1d0c51a
--- /dev/null
+++ b/code/modules/turbolift/turbolift_door.dm
@@ -0,0 +1,44 @@
+/obj/machinery/door/airlock/lift
+ name = "Elevator Door"
+ desc = "Ding."
+ req_access = list(access_maint_tunnels)
+ opacity = 0
+ autoclose = 0
+ glass = 1
+ icon = 'icons/obj/doors/doorlift.dmi'
+
+ var/datum/turbolift/lift
+ var/datum/turbolift_floor/floor
+
+/obj/machinery/door/airlock/lift/Destroy()
+ if(lift)
+ lift.doors -= src
+ if(floor)
+ floor.doors -= src
+ return ..()
+
+/obj/machinery/door/airlock/lift/bumpopen(var/mob/user)
+ return // No accidental sprinting into open elevator shafts.
+
+/obj/machinery/door/airlock/lift/allowed(mob/M)
+ return FALSE //only the lift machinery is allowed to operate this door
+
+/obj/machinery/door/airlock/lift/close(var/forced=0)
+ for(var/turf/turf in locs)
+ for(var/mob/living/LM in turf)
+ if(LM.mob_size <= MOB_TINY)
+ var/moved = 0
+ for(dir in shuffle(cardinal.Copy()))
+ var/dest = get_step(LM,dir)
+ if(!(locate(/obj/machinery/door/airlock/lift) in dest))
+ if(LM.Move(dest))
+ moved = 1
+ LM.visible_message("\The [LM] scurries away from the closing doors.")
+ break
+ if(!moved) // nowhere to go....
+ LM.gib()
+ else // the mob is too big to just move, so we need to give up what we're doing
+ audible_message("\The [src]'s motors grind as they quickly reverse direction, unable to safely close.")
+ cur_command = null // the door will just keep trying otherwise
+ return 0
+ return ..()
\ No newline at end of file
diff --git a/code/modules/turbolift/turbolift_floor.dm b/code/modules/turbolift/turbolift_floor.dm
new file mode 100644
index 00000000000..7761f092843
--- /dev/null
+++ b/code/modules/turbolift/turbolift_floor.dm
@@ -0,0 +1,33 @@
+// Simple holder for each floor in the lift.
+/datum/turbolift_floor
+ var/area_ref
+ var/label
+ var/name
+ var/announce_str
+ var/arrival_sound
+
+ var/list/doors = list()
+ var/obj/structure/lift/button/ext_panel
+
+/datum/turbolift_floor/proc/set_area_ref(var/ref)
+ var/area/turbolift/A = locate(ref)
+ if(!istype(A))
+ log_debug("Turbolift floor area was of the wrong type: ref=[ref]")
+ return
+
+ area_ref = ref
+ label = A.lift_floor_label
+ name = A.lift_floor_name ? A.lift_floor_name : A.name
+ announce_str = A.lift_announce_str
+ arrival_sound = A.arrival_sound
+
+//called when a lift has queued this floor as a destination
+/datum/turbolift_floor/proc/pending_move(var/datum/turbolift/lift)
+ if(ext_panel)
+ ext_panel.light_up()
+
+//called when a lift arrives at this floor
+/datum/turbolift_floor/proc/arrived(var/datum/turbolift/lift)
+ lift.open_doors(src)
+ if(ext_panel)
+ ext_panel.reset()
\ No newline at end of file
diff --git a/code/modules/turbolift/turbolift_map.dm b/code/modules/turbolift/turbolift_map.dm
new file mode 100644
index 00000000000..2e2498f88db
--- /dev/null
+++ b/code/modules/turbolift/turbolift_map.dm
@@ -0,0 +1,228 @@
+// Map object.
+/obj/turbolift_map_holder
+ name = "turbolift map placeholder"
+ icon = 'icons/obj/turbolift_preview_3x3.dmi'
+ dir = SOUTH // Direction of the holder determines the placement of the lift control panel and doors.
+ var/depth = 1 // Number of floors to generate, including the initial floor.
+ var/lift_size_x = 2 // Number of turfs on each axis to generate in addition to the first
+ var/lift_size_y = 2 // ie. a 3x3 lift would have a value of 2 in each of these variables.
+
+ // Various turf and door types used when generating the turbolift floors.
+ var/wall_type = /turf/simulated/wall/elevator
+ var/floor_type = /turf/simulated/floor/tiled/dark
+ var/door_type = /obj/machinery/door/airlock/lift
+
+ var/list/areas_to_use = list()
+
+/obj/turbolift_map_holder/Destroy()
+ turbolifts -= src
+ return ..()
+
+/obj/turbolift_map_holder/New()
+ turbolifts += src
+ ..()
+
+/obj/turbolift_map_holder/initialize()
+
+ // Create our system controller.
+ var/datum/turbolift/lift = new()
+
+ // Holder values since we're moving this object to null ASAP.
+ var/ux = x
+ var/uy = y
+ var/uz = z
+ var/udir = dir
+ forceMove(null)
+
+ // These modifiers are used in relation to the origin
+ // to place the system control panels and doors.
+ var/int_panel_x
+ var/int_panel_y
+ var/ext_panel_x
+ var/ext_panel_y
+ var/door_x1
+ var/door_y1
+ var/door_x2
+ var/door_y2
+ var/light_x1
+ var/light_x2
+ var/light_y1
+ var/light_y2
+
+ var/az = 1
+ var/ex = (ux+lift_size_x)
+ var/ey = (uy+lift_size_y)
+ var/ez = (uz+(depth-1))
+
+ switch(dir)
+
+ if(NORTH)
+
+ int_panel_x = ux + Floor(lift_size_x/2)
+ int_panel_y = uy + 1
+ ext_panel_x = ux
+ ext_panel_y = ey + 2
+
+ door_x1 = ux + 1
+ door_y1 = ey
+ door_x2 = ex - 1
+ door_y2 = ey + 1
+
+ light_x1 = ux + 1
+ light_y1 = uy + 1
+ light_x2 = ux + lift_size_x - 1
+ light_y2 = uy + 1
+
+ if(SOUTH)
+
+ int_panel_x = ux + Floor(lift_size_x/2)
+ int_panel_y = ey - 1
+ ext_panel_x = ex
+ ext_panel_y = uy - 2
+
+ door_x1 = ux + 1
+ door_y1 = uy - 1
+ door_x2 = ex - 1
+ door_y2 = uy
+
+ light_x1 = ux + 1
+ light_y1 = uy + 2
+ light_x2 = ux + lift_size_x - 1
+ light_y2 = uy + lift_size_y - 1
+
+ if(EAST)
+
+ int_panel_x = ux+1
+ int_panel_y = uy + Floor(lift_size_y/2)
+ ext_panel_x = ex+2
+ ext_panel_y = ey
+
+ door_x1 = ex
+ door_y1 = uy + 1
+ door_x2 = ex + 1
+ door_y2 = ey - 1
+
+ light_x1 = ux + 1
+ light_y1 = uy + 1
+ light_x2 = ux + 1
+ light_y2 = uy + lift_size_x - 1
+
+ if(WEST)
+
+ int_panel_x = ex-1
+ int_panel_y = uy + Floor(lift_size_y/2)
+ ext_panel_x = ux-2
+ ext_panel_y = uy
+
+ door_x1 = ux - 1
+ door_y1 = uy + 1
+ door_x2 = ux
+ door_y2 = ey - 1
+
+ light_x1 = ux + lift_size_x - 1
+ light_y1 = uy + 1
+ light_x2 = ux + lift_size_x - 1
+ light_y2 = uy + lift_size_y - 1
+
+ // Generate each floor and store it in the controller datum.
+ for(var/cz = uz;cz<=ez;cz++)
+
+ var/datum/turbolift_floor/cfloor = new()
+ lift.floors += cfloor
+
+ var/list/floor_turfs = list()
+ // Update the appropriate turfs.
+ for(var/tx = ux to ex)
+ for(var/ty = uy to ey)
+
+ var/turf/checking = locate(tx,ty,cz)
+
+ if(!istype(checking))
+ log_debug("[name] cannot find a component turf at [tx],[ty] on floor [cz]. Aborting.")
+ qdel(src)
+ return
+
+ // Update path appropriately if needed.
+ var/swap_to = /turf/simulated/open
+ if(cz == uz) // Elevator.
+ if((tx == ux || ty == uy || tx == ex || ty == ey) && !(tx >= door_x1 && tx <= door_x2 && ty >= door_y1 && ty <= door_y2))
+ swap_to = wall_type
+ else
+ swap_to = floor_type
+
+ if(checking.type != swap_to)
+ checking.ChangeTurf(swap_to)
+ // Let's make absolutely sure that we have the right turf.
+ checking = locate(tx,ty,cz)
+
+ // Clear out contents.
+ for(var/atom/movable/thing in checking.contents)
+ if(thing.simulated)
+ qdel(thing)
+
+ if(tx >= ux && tx <= ex && ty >= uy && ty <= ey)
+ floor_turfs += checking
+
+ // Place exterior doors.
+ for(var/tx = door_x1 to door_x2)
+ for(var/ty = door_y1 to door_y2)
+ var/turf/checking = locate(tx,ty,cz)
+ var/internal = 1
+ if(!(checking in floor_turfs))
+ internal = 0
+ if(checking.type != floor_type)
+ checking.ChangeTurf(floor_type)
+ checking = locate(tx,ty,cz)
+ for(var/atom/movable/thing in checking.contents)
+ if(thing.simulated)
+ qdel(thing)
+ if(checking.type == floor_type) // Don't build over empty space on lower levels.
+ var/obj/machinery/door/airlock/lift/newdoor = new door_type(checking)
+ if(internal)
+ lift.doors += newdoor
+ newdoor.lift = cfloor
+ else
+ cfloor.doors += newdoor
+ newdoor.floor = cfloor
+
+ // Place exterior control panel.
+ var/turf/placing = locate(ext_panel_x, ext_panel_y, cz)
+ var/obj/structure/lift/button/panel_ext = new(placing, lift)
+ panel_ext.floor = cfloor
+ panel_ext.set_dir(udir)
+ cfloor.ext_panel = panel_ext
+
+ // Place lights
+ var/turf/placing1 = locate(light_x1, light_y1, cz)
+ var/turf/placing2 = locate(light_x2, light_y2, cz)
+ var/obj/machinery/light/light1 = new(placing1, light)
+ var/obj/machinery/light/light2 = new(placing2, light)
+ if(udir == NORTH || udir == SOUTH)
+ light1.set_dir(WEST)
+ light2.set_dir(EAST)
+ else
+ light1.set_dir(SOUTH)
+ light2.set_dir(NORTH)
+
+ // Update area.
+ if(az > areas_to_use.len)
+ log_debug("Insufficient defined areas in turbolift datum, aborting.")
+ qdel(src)
+ return
+
+ var/area_path = areas_to_use[az]
+ for(var/thing in floor_turfs)
+ new area_path(thing)
+ var/area/A = locate(area_path)
+ cfloor.set_area_ref("\ref[A]")
+ az++
+
+ // Place lift panel.
+ var/turf/T = locate(int_panel_x, int_panel_y, uz)
+ lift.control_panel_interior = new(T, lift)
+ lift.control_panel_interior.set_dir(udir)
+ lift.current_floor = lift.floors[uz]
+
+ lift.open_doors()
+
+ qdel(src) // We're done.
diff --git a/code/modules/turbolift/turbolift_process.dm b/code/modules/turbolift/turbolift_process.dm
new file mode 100644
index 00000000000..83ce1b9faf0
--- /dev/null
+++ b/code/modules/turbolift/turbolift_process.dm
@@ -0,0 +1,35 @@
+var/datum/controller/process/turbolift/turbolift_controller
+
+/datum/controller/process/turbolift
+ var/list/moving_lifts = list()
+
+/datum/controller/process/turbolift/New()
+ ..()
+ turbolift_controller = src
+
+/datum/controller/process/turbolift/setup()
+ name = "turbolift controller"
+ schedule_interval = 10
+
+/datum/controller/process/turbolift/doWork()
+ for(var/liftref in moving_lifts)
+ if(world.time < moving_lifts[liftref])
+ continue
+ var/datum/turbolift/lift = locate(liftref)
+ if(lift.busy)
+ continue
+ spawn(0)
+ lift.busy = 1
+ if(!lift.do_move())
+ moving_lifts[liftref] = null
+ moving_lifts -= liftref
+ if(lift.target_floor)
+ lift.target_floor.ext_panel.reset()
+ lift.target_floor = null
+ else
+ lift_is_moving(lift)
+ lift.busy = 0
+ SCHECK
+
+/datum/controller/process/turbolift/proc/lift_is_moving(var/datum/turbolift/lift)
+ moving_lifts["\ref[lift]"] = world.time + lift.move_delay
diff --git a/code/modules/turbolift/turbolift_turfs.dm b/code/modules/turbolift/turbolift_turfs.dm
new file mode 100644
index 00000000000..632160efaa1
--- /dev/null
+++ b/code/modules/turbolift/turbolift_turfs.dm
@@ -0,0 +1,2 @@
+/turf/simulated/wall/elevator/New(var/newloc)
+ ..(newloc,"elevatorium")
diff --git a/code/modules/ventcrawl/ventcrawl_atmospherics.dm b/code/modules/ventcrawl/ventcrawl_atmospherics.dm
index bb2d1211254..1fd9dd077ca 100644
--- a/code/modules/ventcrawl/ventcrawl_atmospherics.dm
+++ b/code/modules/ventcrawl/ventcrawl_atmospherics.dm
@@ -55,6 +55,12 @@
/obj/machinery/atmospherics/proc/can_crawl_through()
return 1
+/obj/machinery/atmospherics/unary/can_crawl_through()
+ if(welded)
+ return 0
+
+ . = ..()
+
/obj/machinery/atmospherics/proc/findConnecting(var/direction)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
if(target.initialize_directions & get_dir(target,src))
diff --git a/code/modules/xenoarcheaology/artifacts/autocloner.dm b/code/modules/xenoarcheaology/artifacts/autocloner.dm
index 89c653516f9..5f56ece8ee3 100644
--- a/code/modules/xenoarcheaology/artifacts/autocloner.dm
+++ b/code/modules/xenoarcheaology/artifacts/autocloner.dm
@@ -37,7 +37,7 @@
/mob/living/simple_animal/slime,
/mob/living/simple_animal/crab,
/mob/living/simple_animal/mouse,
- /mob/living/simple_animal/hostile/retaliate/goat)
+ /mob/living/simple_animal/retaliate/goat)
//todo: how the hell is the asteroid permanently powered?
/obj/machinery/auto_cloner/process()
diff --git a/code/modules/xenoarcheaology/effects/emp.dm b/code/modules/xenoarcheaology/effects/emp.dm
index d6d402efe4e..fd30420b577 100644
--- a/code/modules/xenoarcheaology/effects/emp.dm
+++ b/code/modules/xenoarcheaology/effects/emp.dm
@@ -9,5 +9,5 @@
/datum/artifact_effect/emp/DoEffectPulse()
if(holder)
var/turf/T = get_turf(holder)
- empulse(T, effectrange/2, effectrange)
+ empulse(T, effectrange/4, effectrange/3, effectrange/2, effectrange)
return 1
diff --git a/code/modules/xenobio2/machinery/injector_computer.dm b/code/modules/xenobio2/machinery/injector_computer.dm
index 12887506c2f..2f0144d37b3 100644
--- a/code/modules/xenobio2/machinery/injector_computer.dm
+++ b/code/modules/xenobio2/machinery/injector_computer.dm
@@ -20,8 +20,8 @@
var/active
/obj/machinery/computer/xenobio2/Destroy()
- ..()
injector.computer = null
+ ..()
/obj/machinery/computer/xenobio2/attack_hand(mob/user)
if(..())
@@ -109,5 +109,5 @@
/obj/item/weapon/circuitboard/xenobio2computer
name = T_BOARD("injector control console")
- build_path = /obj/item/weapon/circuitboard/xenobio2computer
- origin_tech = list() //To be filled,
+ build_path = /obj/machinery/computer/xenobio2
+ origin_tech = list() //To be filled
diff --git a/code/modules/xgm/xgm_gas_mixture.dm b/code/modules/xgm/xgm_gas_mixture.dm
index 18c210a6dc4..cb600f254f7 100644
--- a/code/modules/xgm/xgm_gas_mixture.dm
+++ b/code/modules/xgm/xgm_gas_mixture.dm
@@ -96,10 +96,16 @@
update_values()
+// Used to equalize the mixture between two zones before sleeping an edge.
/datum/gas_mixture/proc/equalize(datum/gas_mixture/sharer)
var/our_heatcap = heat_capacity()
var/share_heatcap = sharer.heat_capacity()
+ // Special exception: there isn't enough air around to be worth processing this edge next tick, zap both to zero.
+ if(total_moles + sharer.total_moles <= MINIMUM_AIR_TO_SUSPEND)
+ gas.Cut()
+ sharer.gas.Cut()
+
for(var/g in gas|sharer.gas)
var/comb = gas[g] + sharer.gas[g]
comb /= volume + sharer.volume
@@ -110,6 +116,9 @@
temperature = ((temperature * our_heatcap) + (sharer.temperature * share_heatcap)) / (our_heatcap + share_heatcap)
sharer.temperature = temperature
+ update_values()
+ sharer.update_values()
+
return 1
@@ -279,9 +288,16 @@
//Checks if we are within acceptable range of another gas_mixture to suspend processing or merge.
-/datum/gas_mixture/proc/compare(const/datum/gas_mixture/sample)
+/datum/gas_mixture/proc/compare(const/datum/gas_mixture/sample, var/vacuum_exception = 0)
if(!sample) return 0
+ if(vacuum_exception)
+ // Special case - If one of the two is zero pressure, the other must also be zero.
+ // This prevents suspending processing when an air-filled room is next to a vacuum,
+ // an edge case which is particually obviously wrong to players
+ if(total_moles == 0 && sample.total_moles != 0 || sample.total_moles == 0 && total_moles != 0)
+ return 0
+
var/list/marked = list()
for(var/g in gas)
if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \
diff --git a/code/world.dm b/code/world.dm
index 7e7633f8e15..02ec2669a98 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -83,6 +83,10 @@ var/global/datum/global_init/init = new ()
// This is kinda important. Set up details of what the hell things are made of.
populate_material_list()
+ if(config.generate_map)
+ if(using_map.perform_map_generation())
+ using_map.refresh_mining_turfs()
+/*
if(config.generate_asteroid)
// These values determine the specific area that the map is applied to.
// Because we do not use Bay's default map, we check the config file to see if custom parameters are needed, so we need to avoid hardcoding.
@@ -103,7 +107,7 @@ var/global/datum/global_init/init = new ()
// it's brute-forcey, but frankly the alternative is a mine turf rewrite.
for(var/turf/simulated/mineral/M in world) // Ugh.
M.update_icon()
-
+*/
// Create frame types.
populate_frame_types()
diff --git a/config/example/config.txt b/config/example/config.txt
index 884316c45c0..8437829fd38 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -372,13 +372,11 @@ STARLIGHT 0
# LAW_ZERO ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'STATION OVERRUN, ASSUME CONTROL TO CONTAIN OUTBREAK, ALL LAWS OVERRIDDEN#*?&110010
-## Enable asteroid tunnel/cave generation. Will behave strangely if turned off with a map that expects it on.
-# GENERATE_ASTEROID
-
+## Enables specific procedural map generation, generally for mining, however it is specific to the loaded map. Uncomment to enable it, however it can
+## worth it to keep it disabled if you are not hosting an actual server, to speed up start-up time for testing code.
+# GENERATE_MAP
+
-## If you've enabled asteroid generation, you need to supply which z-levels to apply it to, in integer form, and seperated using ;
-## An example: 1;4;5
-# ASTEROID_Z_LEVELS 1;4;5
## Uncomment to enable organ decay outside of a body or storage item.
#ORGANS_CAN_DECAY
diff --git a/html/changelog.html b/html/changelog.html
index ae6ba88f278..2b602087f1c 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -53,6 +53,26 @@
-->
+
24 February 2017
+
Anewbe updated:
+
+
Fake command reports now make the paper show up.
+
Mining cameras should work now.
+
+
MagmaRam updated:
+
+
There is now a short delay before being able to fire when using hostage-taking mode, and a short delay between shots. This should make hostage mode useful for taking hostages and ambushes, rather than as an aimbot in actual firefights.
+
Sandwiches at max size can be eaten with a fork.
+
+
Yosh updated:
+
+
Some vending machines now log the items they've vended and had stocked, storing the name of the user, the time and the item. These can be found by using the new verb for vending machines, or from the right click menu.
+
+
Zuhayr updated:
+
+
Adminhelps now have a TAKE button that allow an admin to claim it, and inform the adminhelper that someone is on the case.
{{/if}}
diff --git a/nano/templates/pda.tmpl b/nano/templates/pda.tmpl
index 396cf8e34f4..6cd3004654e 100644
--- a/nano/templates/pda.tmpl
+++ b/nano/templates/pda.tmpl
@@ -591,7 +591,7 @@ Used In File(s): \code\game\objects\items\devices\PDA\PDA.dm
Details: {{:data.records.medical.alg_d}}
Current Disease: {{:data.records.medical.cdi}} Details: {{:data.records.medical.alg_d}}
- Important Notes: {{:data.records.medical.notes}}
+ Important Notes: {{:data.records.medical.notes}}
{{else}}
Medical Record Lost!
@@ -643,7 +643,7 @@ Used In File(s): \code\game\objects\items\devices\PDA\PDA.dm
Details: {{:data.records.security.mi_crim_d}}
Major Crimes: {{:data.records.security.ma_crim}} Details: {{:data.records.security.ma_crim_d}}
- Important Notes: {{:data.records.security.notes}}
+ Important Notes: {{:data.records.security.notes}}
{{else}}
Security Record Lost!