diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 6ae5692a..4080c325 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -157,6 +157,8 @@
var/list/contact_levels = list(1, 5) // Defines which Z-levels which, for example, a Code Red announcement may affect
var/list/player_levels = list(1, 3, 4, 5, 6) // Defines all Z-levels a character can typically reach
+ var/list/age_restrictions = list() // Holds all of the age restrictions for jobs and antag roles in a single associated list
+
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L)
@@ -576,6 +578,11 @@
else
log_misc("Unknown setting in configuration: '[name]'")
+ else if (type == "age_restrictions")
+ name = replacetext(name, "_", " ")
+ age_restrictions += name
+ age_restrictions[name] = text2num(value)
+
/datum/configuration/proc/loadsql(filename) // -- TLE
var/list/Lines = file2list(filename)
for(var/t in Lines)
diff --git a/code/datums/spells/horsemask.dm b/code/datums/spells/horsemask.dm
index 1319f620..066a6317 100644
--- a/code/datums/spells/horsemask.dm
+++ b/code/datums/spells/horsemask.dm
@@ -35,6 +35,51 @@
flick("e_flash", target.flash)
+//A spell for reversing the curse.
+/obj/effect/proc_holder/spell/targeted/remove_horsemask
+ name = "Free the Horseman"
+ desc = "This spell lifts the Curse of the Horseman from the target. This spell does not require robes."
+ school = "transmutation"
+ charge_type = "recharge"
+ charge_max = 150
+ charge_counter = 0
+ clothes_req = 0
+ stat_allowed = 0
+ invocation = "KN'A EUTH, PUCK 'BTHIK!"
+ invocation_type = "shout"
+ range = 7
+ selection_type = "range"
+ var/list/compatible_mobs = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
+
+/obj/effect/proc_holder/spell/targeted/remove_horsemask/cast(list/targets, mob/user = usr)
+ if (!targets.len)
+ user << "No target found in range."
+ return
+
+ var/mob/living/carbon/target = targets[1]
+
+ if (!(target.type in compatible_mobs))
+ user << "It'd be stupid to curse [target] with a horse's head!"
+ return
+
+ if (!(target in oview(range)))//If they are not in overview after selection.
+ user << "They are too far away!"
+ return
+
+ if (istype(target.wear_mask, /obj/item/clothing/mask/horsehead/magic))
+ var/obj/item/clothing/mask/horsehead/magic/to_be_removed = target.wear_mask
+ target.visible_message( "The [to_be_removed] on [target]'s face lights up and burns away, revealing \his face.", \
+ "Your face burns up once more, but you suddenly realize that you are no longer wearing a silly horsemask!")
+ target.u_equip(to_be_removed)
+
+ if (prob(40))
+ del(to_be_removed)
+ else
+ user << "They aren't cursed, as such, there is nothing to reverse!"
+ return
+
+ flick("e_flash", target.flash)
+
//item used by the horsehead spell
/obj/item/clothing/mask/horsehead/magic
//flags_inv = null //so you can still see their face... no. How can you recognize someone when their face is completely different?
@@ -43,7 +88,7 @@
dropped(mob/user as mob)
canremove = 1
..()
-
+
equipped(var/mob/user, var/slot)
if (slot == slot_wear_mask)
canremove = 0 //curses!
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index ef201cd0..9a12fed6 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -139,7 +139,7 @@
/area/proc/firealert()
- if(name == "Space") //no fire alarms in space
+ if(name == "\improper Space") //no fire alarms in space
return
if( !fire )
fire = 1
@@ -370,4 +370,4 @@
else
if(T && gravity_field_generators["[T.z]"] && length(gravity_field_generators["[T.z]"]))
return 1
- return 0
\ No newline at end of file
+ return 0
diff --git a/code/game/gamemodes/events/power_failure.dm b/code/game/gamemodes/events/power_failure.dm
index 3f0ae3c0..a388ce4c 100644
--- a/code/game/gamemodes/events/power_failure.dm
+++ b/code/game/gamemodes/events/power_failure.dm
@@ -69,7 +69,7 @@
S.updateicon()
S.power_change()
for(var/area/A in world)
- if(A.name != "Space" && A.name != "Engine Walls" && A.name != "Chemical Lab Test Chamber" && A.name != "space" && A.name != "Escape Shuttle" && A.name != "Arrival Area" && A.name != "Arrival Shuttle" && A.name != "start area" && A.name != "Engine Combustion Chamber")
+ if(A.name != "\improper Space" && A.name != "Engine Walls" && A.name != "Chemical Lab Test Chamber" && A.name != "space" && A.name != "Escape Shuttle" && A.name != "Arrival Area" && A.name != "Arrival Shuttle" && A.name != "start area" && A.name != "Engine Combustion Chamber")
A.power_light = 1
A.power_equip = 1
A.power_environ = 1
diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm
index f4d98d1d..60fb8187 100644
--- a/code/game/gamemodes/wizard/spellbook.dm
+++ b/code/game/gamemodes/wizard/spellbook.dm
@@ -38,6 +38,20 @@
dat += "Ethereal Jaunt (60)
"
dat += "Knock (10)
"
dat += "Curse of the Horseman (15)
"
+ dat += "A reversal spell offered for free, upon purchase.
"
+
+ var/need_remove_horse = 0
+ for (var/obj/effect/proc_holder/spell/targeted/horsemask/Add in user.spell_list)
+ if (need_remove_horse == 1)
+ break
+ need_remove_horse++
+ for (var/obj/effect/proc_holder/spell/targeted/remove_horsemask/Remove in user.spell_list)
+ if (need_remove_horse == 2)
+ break
+ need_remove_horse++
+ if (need_remove_horse == 1)
+ dat += "Free the Horseman (15)
"
+
// if(op)
// dat += "Summon Guns (One time use, global spell)
"
dat += "
"
@@ -153,7 +167,15 @@
if("horseman")
feedback_add_details("wizard_spell_learned","HH") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.spell_list += new /obj/effect/proc_holder/spell/targeted/horsemask(H)
+ if (alert("Do you want a spell that can lift this curse, too? (Does not cost a spellpoint.)",,"Yes","No") == "Yes")
+ feedback_add_details("wizard_spell_learned","RH")
+ H.spell_list += new /obj/effect/proc_holder/spell/targeted/remove_horsemask(H)
temp = "This spell will curse a person to wear an unremovable horse mask (it has glue on the inside) and speak like a horse. It does not require a wizard garb. Do note the curse will disintegrate the target's current mask if they are wearing one."
+ if ("remove_horseman")
+ feedback_add_details("wizard_spell_learned","RH") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
+ H.spell_list += new /obj/effect/proc_holder/spell/targeted/remove_horsemask(H)
+ temp = "This spell lifts the Curse of the Horseman from the target. This spell does not require robes."
+ uses++ //since it's a really trivial spell, purchasing it won't deduct points
if("summonguns")
feedback_add_details("wizard_spell_learned","SG") //please do not change the abbreviation to keep data processing consistent. Add a unique id to any new spells
H.rightandwrong()
diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm
index b0de91e9..7ed5b7d0 100644
--- a/code/game/jobs/job/job.dm
+++ b/code/game/jobs/job/job.dm
@@ -70,4 +70,8 @@
if(!isnum(minimal_player_age))
return 0
- return max(0, minimal_player_age - C.player_age)
\ No newline at end of file
+ return max(0, minimal_player_age - C.player_age)
+
+/datum/job/proc/fetch_age_restriction()
+ if (config.age_restrictions[lowertext(title)])
+ minimal_player_age = config.age_restrictions[lowertext(title)]
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index f4acb6bd..c7da1724 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -24,6 +24,8 @@ var/global/datum/controller/occupations/job_master
if(!job) continue
if(job.faction != faction) continue
occupations += job
+ if (config && config.use_age_restriction_for_jobs)
+ job.fetch_age_restriction()
return 1
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index b5e92042..0e10c5dc 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -1224,7 +1224,7 @@ Code shamelessly copied from apc_frame
if (!istype(loc, /turf/simulated/floor))
usr << "\red Air Alarm cannot be placed on this spot."
return
- if (A.requires_power == 0 || A.name == "Space")
+ if (A.requires_power == 0 || A.name == "\improper Space")
usr << "\red Air Alarm cannot be placed in this area."
return
@@ -1547,7 +1547,7 @@ Code shamelessly copied from apc_frame
if (!istype(loc, /turf/simulated/floor))
usr << "\red Fire Alarm cannot be placed on this spot."
return
- if (A.requires_power == 0 || A.name == "Space")
+ if (A.requires_power == 0 || A.name == "\improper Space")
usr << "\red Fire Alarm cannot be placed in this area."
return
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index a1199642..bb3641de 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -52,7 +52,9 @@
/obj/item/robot_parts/robot_component/diagnosis_unit,
/obj/item/robot_parts/robot_component/camera,
/obj/item/robot_parts/robot_component/law_computer,
- /obj/item/robot_parts/robot_component/armour
+ /obj/item/robot_parts/robot_component/armour,
+ /obj/item/robot_parts/robot_component/radiator,
+ /obj/item/robot_parts/robot_component/bladder
),
"Ripley"=list(
/obj/item/mecha_parts/chassis/ripley,
@@ -127,7 +129,9 @@
/obj/item/borg/upgrade/tasercooler,
/obj/item/borg/upgrade/jetpack),
- "Synthetic Coverings" = list( /obj/item/weapon/synth_skin_spray,
+ "Synthetic Shell Components" = list(
+ /obj/item/organ/eyes/robot,
+ /obj/item/weapon/synth_skin_spray,
/obj/item/weapon/synth_skin_cartridge/paint,
/obj/item/weapon/synth_skin_cartridge/skin,
/obj/item/weapon/synth_skin_cartridge/fur,
@@ -887,4 +891,4 @@
target.apply_damage(10, HALLOSS)
target.say("*scream")
spawn(10)
- user.visible_message("\red [user] stops the [src] and leaves [target] resting as they are.", "\red You turn the [src] off and let go of [target].")
\ No newline at end of file
+ user.visible_message("\red [user] stops the [src] and leaves [target] resting as they are.", "\red You turn the [src] off and let go of [target].")
diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm
index ff1a1fb1..7919762a 100644
--- a/code/game/objects/items/blueprints.dm
+++ b/code/game/objects/items/blueprints.dm
@@ -80,7 +80,7 @@ move an amendment to the drawing.
return A
/obj/item/blueprints/proc/get_area_type(var/area/A = get_area())
- if (A.name == "Space")
+ if (A.name == "\improper Space")
return AREA_SPACE
var/list/SPECIALS = list(
/area/shuttle,
@@ -247,4 +247,4 @@ move an amendment to the drawing.
if(BORDER_SPACE)
return ROOM_ERR_SPACE
found+=T
- return found
\ No newline at end of file
+ return found
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 8af5727d..ef95abdb 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -916,6 +916,21 @@ var/global/list/obj/item/device/pda/PDAs = list()
message = "\red" + message
M.show_message(message, 1)
+/obj/item/device/pda/verb/verb_reset_pda()
+ set category = "Object"
+ set name = "Reset PDA"
+ set src in usr
+
+ if(issilicon(usr))
+ return
+
+ if(can_use(usr))
+ mode = 0
+ nanomanager.update_uis(src)
+ usr << "You press the reset button on \the [src]."
+ else
+ usr << "You cannot do this while restrained."
+
/obj/item/device/pda/proc/remove_id()
if (id)
if (ismob(loc))
diff --git a/code/modules/admin/banjob.dm b/code/modules/admin/banjob.dm
index df251ef6..0c5f8e90 100644
--- a/code/modules/admin/banjob.dm
+++ b/code/modules/admin/banjob.dm
@@ -26,6 +26,10 @@ var/jobban_keylist[0] //to store the keys & ranks
if(config.usewhitelist && !check_whitelist(M))
return "Whitelisted Job"
+ if (config.use_age_restriction_for_jobs)
+ if (config.age_restrictions[rank] && M.client.player_age < config.age_restrictions[rank])
+ return "Age Restricted"
+
for (var/s in jobban_keylist)
if( findtext(s,"[M.ckey] - [rank]") == 1 )
var/startpos = findtext(s, "## ")+3
diff --git a/code/modules/admin/player_notes_sql.dm b/code/modules/admin/player_notes_sql.dm
index b80d2b83..0eac3ee8 100644
--- a/code/modules/admin/player_notes_sql.dm
+++ b/code/modules/admin/player_notes_sql.dm
@@ -8,6 +8,8 @@
var/ckey = sanitizeSQL(key)
var/content = sanitizeSQL(note)
+ note = sql_sanitize_text(note)
+
var/a_ckey
if(usr)
a_ckey = sanitizeSQL(usr.key)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index dfb14c9e..d985f847 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1366,6 +1366,7 @@
var/special_role_description = ""
var/health_description = ""
var/gender_description = ""
+ var/species_description = ""
var/turf/T = get_turf(M)
//Location
@@ -1399,8 +1400,18 @@
if(MALE,FEMALE) gender_description = "[M.gender]"
else gender_description = "[M.gender]"
+ //Species
+ if(ishuman(M))
+ var/mob/living/carbon/human/K = M
+ if(K.species)
+ species_description = "[K.species.name]"
+ else
+ species_description = "Unknown"
+ else
+ species_description = "N/A"
+
src.owner << "Info about [M.name]: "
- src.owner << "Mob type = [M.type]; Gender = [gender_description] Damage = [health_description]"
+ src.owner << "Mob type = [M.type]; Species = [species_description]; Gender = [gender_description]; Damage = [health_description]"
src.owner << "Name = [M.name]; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = [M.key];"
src.owner << "Location = [location_description];"
src.owner << "[special_role_description]"
diff --git a/code/modules/admin/verbs/warning.dm b/code/modules/admin/verbs/warning.dm
index a9288213..d222bb5e 100644
--- a/code/modules/admin/verbs/warning.dm
+++ b/code/modules/admin/verbs/warning.dm
@@ -88,8 +88,12 @@
if(!reason)
return
+ reason = sql_sanitize_text(reason)
+
var/notes = input("Add Additional Information. This is visible to staff only.") as null|text
+ notes = sql_sanitize_text(notes)
+
var/severity
switch(alert("Set Warning Severity",,"Standard","Severe"))
if("Standard")
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 2f7ec095..cea406ad 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -429,13 +429,18 @@ datum/preferences
src.be_special = 0
else
var/n = 0
+ var/banned = null
for (var/i in special_roles)
if(special_roles[i]) //if mode is available on the server
- if(jobban_isbanned(user, i))
- dat += "Be [i]: \[BANNED]
"
- else if(i == "pai candidate")
- if(jobban_isbanned(user, "pAI"))
- dat += "Be [i]: \[BANNED]
"
+ banned = jobban_isbanned(user, i)
+ if (i == "pai candidate")
+ banned = jobban_isbanned(user, "pAI")
+
+ if (banned == "Age Restricted")
+ var/time = config.age_restrictions[i] - user.client.player_age
+ dat += "Be [i]: \[IN [time] DAYS]
"
+ else if (banned)
+ dat += "Be [i]: \[BANNED]
"
else
dat += "Be [i]: [src.be_special&(1<
"
n++
@@ -1680,4 +1685,4 @@ var/list/limb_connection_data
/datum/preferences/proc/make_sure_we_have_a_brain_type_for_machines()
if (species=="Machine")
if(!machine_brain_type)
- machine_brain_type="Posibrain"
\ No newline at end of file
+ machine_brain_type="Posibrain"
diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm
index 8044f6a0..79f2863b 100644
--- a/code/modules/customitems/item_defines.dm
+++ b/code/modules/customitems/item_defines.dm
@@ -25,7 +25,8 @@
"/obj/item/weapon/airlock_electronics",
"/obj/item/weapon/module/power_control",
"/obj/item/weapon/cell",
- "/obj/item/weapon/hand_tele")
+ "/obj/item/weapon/hand_tele",
+ "/obj/item/weapon/soap/fluff/jace_toothbrush")
storage_slots = 14
max_combined_w_class = 42
max_w_class = 3
@@ -1323,4 +1324,38 @@ END R I P HAZERI
slot_flags = SLOT_MASK
/obj/item/clothing/tie/fluff/fortune_shieldpendant/New()
- inv_overlay = image("icon" = 'icons/obj/custom_items/fortune_shieldpendant.dmi', "icon_state" = "fortune_shieldpendant_w")
\ No newline at end of file
+ inv_overlay = image("icon" = 'icons/obj/custom_items/fortune_shieldpendant.dmi', "icon_state" = "fortune_shieldpendant_w")
+
+
+// Jace Evan's toothbrush - Wittly
+/obj/item/weapon/soap/fluff/jace_toothbrush
+ name = "toothbrush"
+ desc = "An old toothbrush. It looks well used."
+ icon = 'icons/obj/custom_items/jace_toothbrush.dmi'
+ icon_state = "jace_toothbrush"
+ var/cleanspeed = 20
+
+/obj/item/weapon/soap/fluff/jace_toothbrush/Crossed(AM as mob|obj)
+ return
+
+/obj/item/weapon/soap/fluff/jace_toothbrush/afterattack(atom/target, mob/user as mob, proximity)
+ if(!proximity) return
+
+ if(user.client && (target in user.client.screen))
+ return
+ if (istype(target,/obj/effect/decal/cleanable))
+ user.visible_message("[user] begins to scrub \the [target.name] out with [src].")
+ if(do_after(user, src.cleanspeed) && target)
+ user << "You scrub \the [target.name] out."
+ del(target)
+ else
+ user.visible_message("[user] begins to clean \the [target.name] with [src].")
+ if(do_after(user, src.cleanspeed))
+ user << "You clean \the [target.name]."
+ var/obj/effect/decal/cleanable/C = locate() in target
+ del(C)
+ target.clean_blood()
+ return
+
+/obj/item/weapon/soap/fluff/jace_toothbrush/attack(mob/target as mob, mob/user as mob)
+ return
\ No newline at end of file
diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm
index 618dba58..82e0175c 100644
--- a/code/modules/hydroponics/seeds.dm
+++ b/code/modules/hydroponics/seeds.dm
@@ -116,9 +116,6 @@
/obj/item/seeds/cornseed
seed_type = "corn"
-/obj/item/seeds/poppyseed
- seed_type = "poppies"
-
/obj/item/seeds/potatoseed
seed_type = "potato"
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 1a0399fa..5e14402c 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -801,7 +801,19 @@
proc/stabilize_body_temperature()
if (species.flags & IS_SYNTHETIC)
- bodytemperature += species.synth_temp_gain //just keep putting out heat.
+ var/temperatureModifier = 0
+ if(species.has_organ["radiator"])
+ if(internal_organs_by_name["radiator"])
+ var/datum/organ/internal/Radiator = internal_organs_by_name["radiator"]
+ if(Radiator.is_broken())
+ temperatureModifier = 25
+ if(bodytemperature > 450 && prob(10))
+ apply_damage(rand(1, 5), BURN)
+ else if(Radiator.is_bruised())
+ temperatureModifier = 18
+ else
+ temperatureModifier = 25
+ bodytemperature += species.synth_temp_gain + temperatureModifier //just keep putting out heat.
return
var/body_temperature_difference = species.body_temperature - bodytemperature
@@ -1432,15 +1444,29 @@
if(1) healths.icon_state = "health6"
if(2) healths.icon_state = "health7"
else
- //switch(health - halloss)
- switch(100 - ((species && species.flags & NO_PAIN & !IS_SYNTHETIC) ? 0 : traumatic_shock))
- if(100 to INFINITY) healths.icon_state = "health0"
- if(80 to 100) healths.icon_state = "health1"
- if(60 to 80) healths.icon_state = "health2"
- if(40 to 60) healths.icon_state = "health3"
- if(20 to 40) healths.icon_state = "health4"
- if(0 to 20) healths.icon_state = "health5"
- else healths.icon_state = "health6"
+ var/numb = 0
+ if (species.has_organ["diagnosis unit"])
+ if (internal_organs_by_name["diagnosis unit"])
+ var/datum/organ/internal/machine/Diagnosis_unit = internal_organs_by_name["diagnosis unit"]
+ if (Diagnosis_unit.is_broken())
+ numb = 1
+ else if (Diagnosis_unit.is_bruised() && prob(35))
+ numb = 1
+ else
+ numb = 1
+
+ if (numb)
+ healths.icon_state = "health_numb"
+ else
+ //switch(health - halloss)
+ switch(100 - ((species && species.flags & NO_PAIN & !IS_SYNTHETIC) ? 0 : traumatic_shock))
+ if(100 to INFINITY) healths.icon_state = "health0"
+ if(80 to 100) healths.icon_state = "health1"
+ if(60 to 80) healths.icon_state = "health2"
+ if(40 to 60) healths.icon_state = "health3"
+ if(20 to 40) healths.icon_state = "health4"
+ if(0 to 20) healths.icon_state = "health5"
+ else healths.icon_state = "health6"
if(nutrition_icon)
switch(nutrition)
@@ -1483,7 +1509,20 @@
else bodytemp.icon_state = "temp-4"
else
var/temp_step
- if (bodytemperature >= species.body_temperature)
+ var/numb = 0
+ if (species.has_organ["diagnosis unit"])
+ if(internal_organs_by_name["diagnosis unit"])
+ var/datum/organ/internal/machine/Diagnosis_unit = internal_organs_by_name["diagnosis unit"]
+ if (Diagnosis_unit.is_broken())
+ numb = 1
+ else if (Diagnosis_unit.is_bruised() && prob(35))
+ numb = 1
+ else numb = 1
+
+ if (numb)
+ bodytemp.icon_state = "temp_numb"
+
+ else if (bodytemperature >= species.body_temperature)
temp_step = (species.heat_level_1 - species.body_temperature)/4
if (bodytemperature >= species.heat_level_1)
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index ddfb8577..6fc004aa 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -201,17 +201,17 @@
// Grabs the window recieved when you click-drag someone onto you.
/datum/species/proc/get_inventory_dialogue(var/mob/living/carbon/human/H)
return
-
+
//Used by xenos understanding larvae and dionaea understanding nymphs.
/datum/species/proc/can_understand(var/mob/other)
return
-
-
+
+
/datum/species/proc/blend_preview_icon(var/icon/main_icon,var/datum/preferences/preferences,var/paint_colour)
if(paint_colour)
main_icon.Blend(paint_colour, ICON_ADD)
- return
+ return
if(flags & HAS_SKIN_COLOR)
main_icon.Blend(rgb(preferences.r_skin, preferences.g_skin, preferences.b_skin), ICON_ADD)
return
@@ -220,8 +220,8 @@
main_icon.Blend(rgb(preferences.s_tone, preferences.s_tone, preferences.s_tone), ICON_ADD)
else
main_icon.Blend(rgb(-preferences.s_tone, -preferences.s_tone, -preferences.s_tone), ICON_SUBTRACT)
-
-
+
+
/datum/species/proc/get_organ_preview_icon(var/name, var/robot, var/gendered, var/gender_string, var/datum/preferences/preferences, var/datum/synthetic_limb_cover/covering, var/paint_colour)
var/icon_name = icobase
if (robot)
@@ -236,7 +236,7 @@
var/icon/result = new /icon(icon_name,state_name)
blend_preview_icon(result,preferences,paint_colour)
return result
-
+
/datum/species/proc/get_is_preview_organ_robotic(var/name,var/datum/preferences/preferences)
if (flags & IS_SYNTHETIC)
@@ -245,7 +245,7 @@
var/list/organ_robotic_info=preferences.organ_data[name]
if (istype(organ_robotic_info))
return TRUE
-
+
/datum/species/proc/get_preview_organ_covering(var/name,var/datum/preferences/preferences)
if (name in preferences.organ_data)
var/list/organ_robotic_info=preferences.organ_data[name]
@@ -254,8 +254,8 @@
if (preferences.species=="Machine")
if (preferences.covering_type)
return list(preferences.covering_type,rgb(preferences.r_skin,preferences.g_skin,preferences.b_skin))
-
-
+
+
/datum/species/proc/get_tail_preview_icon(var/list/preview_coverings,var/datum/preferences/preferences)
var/tail_state=null
if (!(isnull(preview_coverings["groin"])))
@@ -268,8 +268,8 @@
var/icon/result = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = tail_state)
result.Blend(rgb(preferences.r_hair,preferences.g_hair,preferences.b_hair),ICON_ADD)
return result
-
-
+
+
/datum/species/proc/get_eyes_preview_icon(var/list/preview_coverings,var/datum/preferences/preferences)
var/eye_state=null
if (!(isnull(preview_coverings["head"])))
@@ -280,13 +280,13 @@
var/icon/result = new/icon('icons/mob/human_face.dmi',eye_state)
result.Blend(rgb(preferences.r_eyes,preferences.g_eyes,preferences.b_eyes),ICON_ADD)
return result
-
+
/* This function takes a preferences object and generates a complete body and hair icon for that set of preferences. It's needlessly complicated
and duplicates a lot of what's going on in update_icons. The two systems should be combined somehow, possibly by using a 'visual identity' object
-that could be created from either a living human or a preferences object and then passing that to a single render function, but I'll leave that
+that could be created from either a living human or a preferences object and then passing that to a single render function, but I'll leave that
exercise for another day.
-See code\modules\mob\new_player\preferences_setup.dm for where it's used.
+See code\modules\mob\new_player\preferences_setup.dm for where it's used.
- jack_fractal*/
/datum/species/proc/create_body_preview_icon(var/datum/preferences/preferences)
var/gender_string = (preferences.gender==FEMALE) ? "f" : "m"
@@ -578,7 +578,7 @@ See code\modules\mob\new_player\preferences_setup.dm for where it's used.
rarity_value = 2
eyes = "blank_eyes"
- brute_mod = 0.5
+ brute_mod = 1 //Fuck yo brute mod.
burn_mod = 1
warning_low_pressure = 50
@@ -602,6 +602,10 @@ See code\modules\mob\new_player\preferences_setup.dm for where it's used.
has_organ = list(
"heart" = /datum/organ/internal/heart,
"brain" = /datum/organ/internal/brain/robot,
+ "eyes" = /datum/organ/internal/eyes/robot,
+ "radiator" = /datum/organ/internal/machine/radiator,
+ "chemical containment" = /datum/organ/internal/machine/bladder,
+ "diagnosis unit" = /datum/organ/internal/machine/diagnosis_unit,
)
/datum/species/machine/create_organs(var/mob/living/carbon/human/H)
..()
@@ -609,8 +613,8 @@ See code\modules\mob\new_player\preferences_setup.dm for where it's used.
if (istype(brain_datum))
if (isnull(brain_datum.machine_brain_type))
brain_datum.machine_brain_type="Posibrain"
-
-
+
+
/datum/species/bug
name = "Vaurca"
name_plural = "varucae"
@@ -778,4 +782,4 @@ See code\modules\mob\new_player\preferences_setup.dm for where it's used.
if(slot_back in equip_slots)
equip_slots |= slot_in_backpack
- equip_slots |= slot_legcuffed
\ No newline at end of file
+ equip_slots |= slot_legcuffed
diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm
deleted file mode 100644
index b5043fd2..00000000
--- a/code/modules/mob/living/carbon/species.dm
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- Datum-based species. Should make for much cleaner and easier to maintain mutantrace code.
-*/
-
-/datum/species
- var/name // Species name.
-
- var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set.
- var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set.
- var/eyes = "eyes_s" // Icon for eyes.
-
- var/primitive // Lesser form, if any (ie. monkey for humans)
- var/tail // Name of tail image in species effects icon file.
- var/language // Default racial language, if any.
- var/unarmed //For empty hand harm-intent attack
- var/unarmed_type = /datum/unarmed_attack
- var/secondary_langs = list() // The names of secondary languages that are available to this species.
- var/mutantrace // Safeguard due to old code.
-
- var/breath_type = "oxygen" // Non-oxygen gas breathed, if any.
- var/poison_type = "phoron" // Poisonous air.
- var/exhale_type = "carbon_dioxide" // Exhaled gas type.
-
- var/cold_level_1 = 260 // Cold damage level 1 below this point.
- var/cold_level_2 = 200 // Cold damage level 2 below this point.
- var/cold_level_3 = 120 // Cold damage level 3 below this point.
-
- var/heat_level_1 = 360 // Heat damage level 1 above this point.
- var/heat_level_2 = 400 // Heat damage level 2 above this point.
- var/heat_level_3 = 1000 // Heat damage level 2 above this point.
-
- var/body_temperature = 310.15 //non-IS_SYNTHETIC species will try to stabilize at this temperature. (also affects temperature processing)
- var/synth_temp_gain = 0 //IS_SYNTHETIC species will gain this much temperature every second
- var/reagent_tag //Used for metabolizing reagents.
-
- var/darksight = 2
- var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure.
- var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning.
- var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning.
- var/hazard_low_pressure = HAZARD_LOW_PRESSURE // Dangerously low pressure.
-
- var/brute_mod = null // Physical damage reduction/malus.
- var/burn_mod = null // Burn damage reduction/malus.
-
- var/flags = 0 // Various specific features.
-
- var/list/abilities = list() // For species-derived or admin-given powers
-
- var/blood_color = "#A10808" //Red.
- var/flesh_color = "#FFC896" //Pink.
- var/base_color //Used when setting species.
-
- //Used in icon caching.
- var/race_key = 0
- var/icon/icon_template
-
-/datum/species/New()
- unarmed = new unarmed_type()
-
-/datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs.
- //This is a basic humanoid limb setup.
- H.organs = list()
- H.organs_by_name["chest"] = new/datum/organ/external/chest()
- H.organs_by_name["groin"] = new/datum/organ/external/groin(H.organs_by_name["chest"])
- H.organs_by_name["head"] = new/datum/organ/external/head(H.organs_by_name["chest"])
- H.organs_by_name["l_arm"] = new/datum/organ/external/l_arm(H.organs_by_name["chest"])
- H.organs_by_name["r_arm"] = new/datum/organ/external/r_arm(H.organs_by_name["chest"])
- H.organs_by_name["r_leg"] = new/datum/organ/external/r_leg(H.organs_by_name["groin"])
- H.organs_by_name["l_leg"] = new/datum/organ/external/l_leg(H.organs_by_name["groin"])
- H.organs_by_name["l_hand"] = new/datum/organ/external/l_hand(H.organs_by_name["l_arm"])
- H.organs_by_name["r_hand"] = new/datum/organ/external/r_hand(H.organs_by_name["r_arm"])
- H.organs_by_name["l_foot"] = new/datum/organ/external/l_foot(H.organs_by_name["l_leg"])
- H.organs_by_name["r_foot"] = new/datum/organ/external/r_foot(H.organs_by_name["r_leg"])
-
- H.internal_organs = list()
- H.internal_organs_by_name["heart"] = new/datum/organ/internal/heart(H)
- H.internal_organs_by_name["lungs"] = new/datum/organ/internal/lungs(H)
- H.internal_organs_by_name["liver"] = new/datum/organ/internal/liver(H)
- H.internal_organs_by_name["kidney"] = new/datum/organ/internal/kidney(H)
- H.internal_organs_by_name["brain"] = new/datum/organ/internal/brain(H)
- H.internal_organs_by_name["eyes"] = new/datum/organ/internal/eyes(H)
-
- for(var/name in H.organs_by_name)
- H.organs += H.organs_by_name[name]
-
- for(var/datum/organ/external/O in H.organs)
- O.owner = H
-
- if(flags & IS_SYNTHETIC)
- for(var/datum/organ/external/E in H.organs)
- if(E.status & ORGAN_CUT_AWAY || E.status & ORGAN_DESTROYED) continue
- E.status |= ORGAN_ROBOT
- for(var/datum/organ/internal/I in H.internal_organs)
- I.mechanize()
-
-/datum/species/proc/handle_post_spawn(var/mob/living/carbon/human/H) //Handles anything not already covered by basic species assignment.
- return
-
-/datum/species/proc/handle_death(var/mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns).
- if(flags & IS_SYNTHETIC)
- //H.make_jittery(200) //S-s-s-s-sytem f-f-ai-i-i-i-i-lure-ure-ure-ure
- H.h_style = ""
- spawn(100)
- //H.is_jittery = 0
- //H.jitteriness = 0
- H.update_hair()
- return
-
-
-/datum/species/proc/get_eye_icon()
- return eyes
-
-
-/datum/species/human
- name = "Human"
- language = "Sol Common"
- primitive = /mob/living/carbon/monkey
- unarmed_type = /datum/unarmed_attack/punch
-
- flags = HAS_SKIN_TONE | HAS_LIPS | HAS_UNDERWEAR
-
- //If you wanted to add a species-level ability:
- /*abilities = list(/client/proc/test_ability)*/
-
-/datum/species/unathi
- name = "Unathi"
- icobase = 'icons/mob/human_races/r_lizard.dmi'
- deform = 'icons/mob/human_races/r_def_lizard.dmi'
- language = "Sinta'unathi"
- tail = "sogtail"
- unarmed_type = /datum/unarmed_attack/claws
- primitive = /mob/living/carbon/monkey/unathi
- darksight = 3
-
- cold_level_1 = 280 //Default 260 - Lower is better
- cold_level_2 = 220 //Default 200
- cold_level_3 = 130 //Default 120
-
- heat_level_1 = 420 //Default 360 - Higher is better
- heat_level_2 = 480 //Default 400
- heat_level_3 = 1100 //Default 1000
-
- flags = IS_WHITELISTED | HAS_LIPS | HAS_UNDERWEAR | HAS_TAIL | HAS_SKIN_COLOR
-
- flesh_color = "#34AF10"
-
- reagent_tag = IS_UNATHI
- base_color = "#066000"
-
-/datum/species/tajaran
- name = "Tajaran"
- icobase = 'icons/mob/human_races/r_tajaran.dmi'
- deform = 'icons/mob/human_races/r_def_tajaran.dmi'
- language = "Siik'Maas"
- tail = "tajtail"
- unarmed_type = /datum/unarmed_attack/claws
- darksight = 8
-
- cold_level_1 = 200 //Default 260
- cold_level_2 = 140 //Default 200
- cold_level_3 = 80 //Default 120
-
- heat_level_1 = 330 //Default 360
- heat_level_2 = 380 //Default 400
- heat_level_3 = 800 //Default 1000
-
- primitive = /mob/living/carbon/monkey/tajara
-
- flags = IS_WHITELISTED | HAS_LIPS | HAS_UNDERWEAR | HAS_TAIL | HAS_SKIN_COLOR
-
- flesh_color = "#AFA59E"
- base_color = "#333333"
-
-/datum/species/skrell
- name = "Skrell"
- icobase = 'icons/mob/human_races/r_skrell.dmi'
- deform = 'icons/mob/human_races/r_def_skrell.dmi'
- language = "Skrellian"
- primitive = /mob/living/carbon/monkey/skrell
- unarmed_type = /datum/unarmed_attack/punch
-
- flags = IS_WHITELISTED | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR
-
- flesh_color = "#8CD7A3"
-
- reagent_tag = IS_SKRELL
-
-/datum/species/vox
- name = "Vox"
- icobase = 'icons/mob/human_races/r_vox.dmi'
- deform = 'icons/mob/human_races/r_def_vox.dmi'
- language = "Vox-pidgin"
- unarmed_type = /datum/unarmed_attack/claws //I dont think it will hurt to give vox claws too.
-
- warning_low_pressure = 50
- hazard_low_pressure = 0
-
- cold_level_1 = 80
- cold_level_2 = 50
- cold_level_3 = 0
-
- eyes = "vox_eyes_s"
-
- breath_type = "nitrogen"
- poison_type = "oxygen"
-
- flags = NO_SCAN
-
- blood_color = "#2299FC"
- flesh_color = "#808D11"
-
- reagent_tag = IS_VOX
-
-/datum/species/vox/handle_post_spawn(var/mob/living/carbon/human/H)
-
- H.verbs += /mob/living/carbon/human/proc/leap
- ..()
-
-/datum/species/vox/armalis/handle_post_spawn(var/mob/living/carbon/human/H)
-
- H.verbs += /mob/living/carbon/human/proc/gut
- H.verbs += /mob/living/carbon/human/proc/commune
- ..()
-
-/datum/species/vox/armalis
- name = "Vox Armalis"
- icobase = 'icons/mob/human_races/r_armalis.dmi'
- deform = 'icons/mob/human_races/r_armalis.dmi'
- language = "Vox-pidgin"
- unarmed_type = /datum/unarmed_attack/claws/armalis
-
- warning_low_pressure = 50
- hazard_low_pressure = 0
-
- cold_level_1 = 80
- cold_level_2 = 50
- cold_level_3 = 0
-
- heat_level_1 = 2000
- heat_level_2 = 3000
- heat_level_3 = 4000
-
- brute_mod = 0.2
- burn_mod = 0.2
-
- eyes = "blank_eyes"
- breath_type = "nitrogen"
- poison_type = "oxygen"
-
- flags = NO_SCAN | NO_BLOOD | HAS_TAIL | NO_PAIN | IS_WHITELISTED
-
- blood_color = "#2299FC"
- flesh_color = "#808D11"
-
- tail = "armalis_tail"
- icon_template = 'icons/mob/human_races/r_armalis.dmi'
-
- reagent_tag = IS_VOX
-
-/datum/species/diona
- name = "Diona"
- icobase = 'icons/mob/human_races/r_diona.dmi'
- deform = 'icons/mob/human_races/r_def_plant.dmi'
- language = "Rootspeak"
- unarmed_type = /datum/unarmed_attack/diona
- primitive = /mob/living/carbon/monkey/diona
-
- warning_low_pressure = 50
- hazard_low_pressure = -1
-
- cold_level_1 = 50
- cold_level_2 = -1
- cold_level_3 = -1
-
- heat_level_1 = 2000
- heat_level_2 = 3000
- heat_level_3 = 4000
-
- body_temperature = T0C + 15 //make the plant people have a bit lower body temperature, why not
-
- flags = IS_WHITELISTED | NO_BREATHE | REQUIRE_LIGHT | NO_SCAN | IS_PLANT | RAD_ABSORB | NO_BLOOD | IS_SLOW | NO_PAIN
-
- blood_color = "#004400"
- flesh_color = "#907E4A"
-
- reagent_tag = IS_DIONA
-
-/datum/species/diona/handle_post_spawn(var/mob/living/carbon/human/H)
- H.gender = NEUTER
-
- return ..()
-
-/datum/species/diona/handle_death(var/mob/living/carbon/human/H)
-
- var/mob/living/carbon/monkey/diona/S = new(get_turf(H))
-
- if(H.mind)
- H.mind.transfer_to(S)
-
- for(var/mob/living/carbon/monkey/diona/D in H.contents)
- if(D.client)
- D.loc = H.loc
- else
- del(D)
-
- H.visible_message("\red[H] splits apart with a wet slithering noise!")
-
-/datum/species/machine
- name = "Machine"
- icobase = 'icons/mob/human_races/r_machine.dmi'
- deform = 'icons/mob/human_races/r_machine.dmi'
- language = "Tradeband"
- unarmed_type = /datum/unarmed_attack/punch
-
- eyes = "blank_eyes"
- brute_mod = 0.5
- burn_mod = 1
-
- warning_low_pressure = 50
- hazard_low_pressure = 0
-
- cold_level_1 = 50
- cold_level_2 = -1
- cold_level_3 = -1
-
- heat_level_1 = 500 //gives them about 25 seconds in space before taking damage
- heat_level_2 = 1000
- heat_level_3 = 2000
-
- synth_temp_gain = 10 //this should cause IPCs to stabilize at ~80 C in a 20 C environment.
-
- flags = IS_WHITELISTED | NO_BREATHE | NO_SCAN | NO_BLOOD | NO_PAIN | IS_SYNTHETIC | NO_POISON
-
- blood_color = "#1F181F"
- flesh_color = "#575757"
-
- var/brain_type = 'posibrain' // default is robots
-
-
-//Species unarmed attacks
-
-/datum/unarmed_attack
- var/attack_verb = list("attack") // Empty hand hurt intent verb.
- var/damage = 0 // Extra empty hand attack damage.
- var/attack_sound = "punch"
- var/miss_sound = 'sound/weapons/punchmiss.ogg'
- var/sharp = 0
- var/edge = 0
-
-/datum/unarmed_attack/punch
- attack_verb = list("punch")
-
-/datum/unarmed_attack/diona
- attack_verb = list("lash", "bludgeon")
- damage = 5
-
-/datum/unarmed_attack/claws
- attack_verb = list("scratch", "claw")
- attack_sound = 'sound/weapons/slice.ogg'
- miss_sound = 'sound/weapons/slashmiss.ogg'
- damage = 5
- sharp = 1
- edge = 1
-
-/datum/unarmed_attack/claws/armalis
- attack_verb = list("slash", "claw")
- damage = 10 //they're huge! they should do a little more damage, i'd even go for 15-20 maybe...
-
-/datum/species/kocasslani
- name = "Kocasslani"
- icobase = 'icons/mob/human_races/r_kocasslani.dmi'
- deform = 'icons/mob/human_races/r_def_kocasslani.dmi'
- language = "Sini"
- darksight = 8
-
- cold_level_1 = 160 //Default 260
- cold_level_2 = 100 //Default 200
- cold_level_3 = 60 //Default 120
-
- heat_level_1 = 300 //Default 360
- heat_level_2 = 360 //Default 400
- heat_level_3 = 800 //Default 1000
-
- flags = IS_WHITELISTED | HAS_LIPS | HAS_UNDERWEAR
-
-/* blood_color = "#659CEF"
- flesh_color = "#D3AA8E"
-*/
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm
index bb03edb4..8f836208 100644
--- a/code/modules/mob/living/silicon/robot/component.dm
+++ b/code/modules/mob/living/silicon/robot/component.dm
@@ -147,6 +147,14 @@
var/brute = 0
var/burn = 0
var/icon_state_broken = "broken"
+ var/obj/item/organ/organ_type = null // for shells. Only define if this can be placed inside an IPC during organ replacement surgery.
+
+// In case the robot_component has a child organ, it is updated to have the proper datums and so on.
+/obj/item/robot_parts/robot_component/New()
+ ..()
+ spawn(5)
+ if(organ_type)
+ organ_type.update()
// TODO: actual icons ;)
/obj/item/robot_parts/robot_component/binary_communication_device
@@ -168,7 +176,8 @@
name = "camera"
icon_state = "camera"
icon_state_broken = "camera_broken"
-
+ organ_type = new /obj/item/organ/eyes/robot()
+
/obj/item/robot_parts/robot_component/law_computer
name = "law computer"
icon_state = "radio"
@@ -178,12 +187,25 @@
name = "diagnosis unit"
icon_state = "analyser"
icon_state_broken = "analyser_broken"
+ organ_type = new /obj/item/organ/machine/diagnosis_unit()
/obj/item/robot_parts/robot_component/radio
name = "radio"
icon_state = "radio"
icon_state_broken = "radio_broken"
+/obj/item/robot_parts/robot_component/radiator
+ name = "radiator"
+ icon_state = "radiator"
+ icon_state_broken = "radiator_broken"
+ organ_type = new /obj/item/organ/machine/radiator()
+
+/obj/item/robot_parts/robot_component/bladder
+ name = "chemical containment"
+ icon_state = "bladder"
+ icon_state_broken = "bladder_broken"
+ organ_type = new /obj/item/organ/machine/bladder()
+
//
//Robotic Component Analyser, basically a health analyser for robots
//
@@ -227,7 +249,7 @@
user.show_message("\t Damage Specifics: [BU] - [BR]")
if(M.tod && M.stat == DEAD)
user.show_message("\blue Time of Disable: [M.tod]")
-
+
if (istype(M, /mob/living/silicon/robot))
var/mob/living/silicon/robot/H = M
var/list/damaged = H.get_damaged_components(1,1,1)
@@ -245,7 +267,7 @@
user.show_message("\blue \t Components are OK.",1)
if(H.emagged && prob(5))
user.show_message("\red \t ERROR: INTERNAL SYSTEMS COMPROMISED",1)
-
+
if (ishuman(M) && (M:species.flags & IS_SYNTHETIC))
var/mob/living/carbon/human/H = M
var/list/damaged = H.get_damaged_organs(1,1)
@@ -258,8 +280,8 @@
(org.burn_dam > 0) ? "[org.burn_dam]" :0),1)
else
user.show_message("\blue \t Components are OK.",1)
-
+
user.show_message("\blue Operating Temperature: [M.bodytemperature-T0C]°C ([M.bodytemperature*1.8-459.67]°F)", 1)
-
+
src.add_fingerprint(user)
return
diff --git a/code/modules/organs/organ_alien.dm b/code/modules/organs/organ_alien.dm
index 9d4bfa0b..c473d377 100644
--- a/code/modules/organs/organ_alien.dm
+++ b/code/modules/organs/organ_alien.dm
@@ -224,4 +224,117 @@
robotic = 2
/obj/item/organ/stack/vox
- name = "vox cortical stack"
\ No newline at end of file
+ name = "vox cortical stack"
+
+//IPC/SHELL ORGANS.
+//TODO: Make the robot_components required for these
+//TODO: Make said components printable
+//TODO: sprites
+/datum/organ/internal/machine
+ removed_type = /obj/item/organ/machine
+
+/datum/organ/internal/machine/process()
+ return
+
+/datum/organ/internal/machine/radiator
+ name = "internal cooling unit"
+ parent_organ = "chest"
+ robotic = 2
+ min_bruised_damage = 15
+ min_broken_damage = 40
+ removed_type = /obj/item/organ/machine/radiator
+
+/obj/item/organ/machine/radiator
+ name = "internal cooling unit"
+ icon_state = "radiator"
+ organ_tag = "radiator"
+ organ_type = /datum/organ/internal/machine/radiator
+ robotic = 2
+
+/obj/item/organ/machine/radiator/exposed_to_the_world()
+ var/obj/item/robot_parts/robot_component/radiator/Radiator = new(src.loc)
+ if(organ_data.damage)
+ Radiator.brute = organ_data.damage
+ del(src)
+ return Radiator
+
+/datum/organ/internal/machine/bladder
+ name = "chemical containment"
+ parent_organ = "groin"
+ robotic = 2
+ removed_type = /obj/item/organ/machine/bladder
+
+/datum/organ/internal/machine/bladder/process()
+ if(status & ORGAN_CUT_AWAY)
+ return
+
+ if(is_bruised())
+ var/leakSmall = rand(1,5)
+ if(owner.reagents.total_volume > 0)
+ owner.reagents.remove_any(leakSmall)
+ if(owner.reagents.maximum_volume > 500)
+ owner.reagents.maximum_volume -= leakSmall
+
+ if(is_broken())
+ var/leakLarge = rand(25,50)
+ if(owner.reagents.total_volume > 0)
+ owner.reagents.remove_any(leakLarge)
+ if(owner.reagents.maximum_volume > 0)
+ if(owner.reagents.maximum_volume < leakLarge)
+ owner.reagents.maximum_volume = 0
+ else
+ owner.reagents.maximum_volume -= leakLarge
+
+ if(owner.reagents.reagent_list.len)
+ if(owner.reagents.has_reagent("sacid") || owner.reagents.has_reagent("pacid"))
+ take_damage(rand(0,2.5), 1)
+
+/obj/item/organ/machine/bladder
+ name = "chemical containment"
+ icon_state = "bladder"
+ organ_tag = "chemical containment"
+ organ_type = /datum/organ/internal/machine/bladder
+ robotic = 2
+
+/obj/item/organ/machine/bladder/replaced(var/mob/living/carbon/human/target)
+ if(istype(target) && (target.species.flags & IS_SYNTHETIC))
+ if(target.reagents.maximum_volume < 1000)
+ target.reagents.maximum_volume = 1000
+
+ ..()
+
+/obj/item/organ/machine/bladder/removed(var/mob/living/target, var/mob/living/user)
+ ..()
+
+ if(istype(target, /mob/living/carbon/human))
+ var/mob/living/carbon/human/Machine = target
+ if(Machine.species.flags & IS_SYNTHETIC)
+ Machine.reagents.clear_reagents()
+ Machine.reagents.maximum_volume = 0
+
+/obj/item/organ/machine/bladder/exposed_to_the_world()
+ var/obj/item/robot_parts/robot_component/bladder/Bladder = new(src.loc)
+ if(organ_data.damage)
+ Bladder.brute = organ_data.damage
+ del(src)
+ return Bladder
+
+/datum/organ/internal/machine/diagnosis_unit
+ name = "diagnosis unit"
+ parent_organ = "head"
+ robotic = 2
+ removed_type = /obj/item/organ/machine/diagnosis_unit
+
+/obj/item/organ/machine/diagnosis_unit
+ name = "diagnosis unit"
+ icon_state = "diagnosis_unit"
+ organ_tag = "diagnosis unit"
+ organ_type = /datum/organ/internal/machine/diagnosis_unit
+ robotic = 2
+
+/obj/item/organ/machine/diagnosis_unit/exposed_to_the_world()
+ var/obj/item/robot_parts/robot_component/diagnosis_unit/Diagnosis_unit = new(src.loc)
+ if(organ_data.damage)
+ Diagnosis_unit.brute = organ_data.damage
+ del(src)
+ return Diagnosis_unit
diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm
index 3ee262b7..53f28e83 100644
--- a/code/modules/organs/organ_internal.dm
+++ b/code/modules/organs/organ_internal.dm
@@ -249,12 +249,12 @@
parent_organ = "head"
removed_type = /obj/item/organ/brain
vital = 1
-
-
+
+
/datum/organ/internal/brain/robot // brains for shells
- var/machine_brain_type=null
-
-
+ var/machine_brain_type=null
+
+
/datum/organ/internal/brain/robot/proc/create_robot_brain_replacement(var/target,var/new_location)
var/obj/item/device/mmi/new_mmi
if (machine_brain_type=="Posibrain")
@@ -267,7 +267,7 @@
new_mmi.transfer_identity(target)
new_mmi.loc = new_location
return new_mmi
-
+
/datum/organ/internal/brain/xeno
removed_type = /obj/item/organ/brain/xeno
@@ -284,6 +284,11 @@
if(is_broken())
owner.eye_blind = 20
+/datum/organ/internal/eyes/robot // eyes for shells
+ name = "charge-coupled device"
+ parent_organ = "head"
+ removed_type = /obj/item/organ/eyes/robot
+
/datum/organ/internal/appendix
name = "appendix"
parent_organ = "groin"
@@ -306,4 +311,4 @@
removed_organ.update()
organ_holder = removed_organ
- return removed_organ
\ No newline at end of file
+ return removed_organ
diff --git a/code/modules/organs/organ_objects.dm b/code/modules/organs/organ_objects.dm
index c375cbb4..2340a34e 100644
--- a/code/modules/organs/organ_objects.dm
+++ b/code/modules/organs/organ_objects.dm
@@ -150,6 +150,19 @@
/obj/item/organ/eyes/prosthetic
robotic = 2
+/obj/item/organ/eyes/robot
+ name = "charge-coupled device"
+ icon_state = ""
+ organ_type = /datum/organ/internal/eyes/robot
+ robotic = 2
+
+ exposed_to_the_world()
+ var/obj/item/robot_parts/robot_component/camera/Camera = new()
+ if(organ_data.damage)
+ Camera.brute = organ_data.damage
+ del(src)
+ return Camera
+
/obj/item/organ/liver/prosthetic
robotic = 2
@@ -180,11 +193,11 @@
msg_admin_attack("[user.name] ([user.ckey]) removed a vital organ ([src]) from [target.name] ([target.ckey]) (INTENT: [uppertext(user.a_intent)]) (JMP)")
target.death()
-
+
/obj/item/organ/proc/exposed_to_the_world() // this is only useful for organs that change when actually removed from the body
- return
-
-
+ return
+
+
/obj/item/organ/appendix/removed(var/mob/living/target,var/mob/living/user)
..()
@@ -277,4 +290,4 @@
if(fingerprintslast) O.fingerprintslast = fingerprintslast
user.put_in_active_hand(O)
- del(src)
\ No newline at end of file
+ del(src)
diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm
index 0cf7dfef..b9a234aa 100644
--- a/code/modules/surgery/generic.dm
+++ b/code/modules/surgery/generic.dm
@@ -17,10 +17,11 @@
return 0
if (affected.status & ORGAN_DESTROYED)
return 0
- if (target_zone == "head" && target.species && (target.species.flags & IS_SYNTHETIC))
- return 1
if (affected.status & ORGAN_ROBOT)
- return 0
+ if (target.species && (target.species.flags & IS_SYNTHETIC) && affected.internal_organs.len)
+ return 1
+ else
+ return 0
return 1
/datum/surgery_step/generic/cut_with_laser
diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm
index 3ea958bb..71189a51 100644
--- a/code/modules/surgery/organs_internal.dm
+++ b/code/modules/surgery/organs_internal.dm
@@ -320,7 +320,8 @@
/datum/surgery_step/internal/replace_organ
allowed_tools = list(
- /obj/item/organ = 100
+ /obj/item/organ = 100,
+ /obj/item/robot_parts/robot_component = 100
)
min_duration = 60
@@ -334,7 +335,13 @@
var/organ_compatible
var/organ_missing
- if(!istype(O))
+ if(!istype(O) && istype(O, /obj/item/robot_parts/robot_component))
+ var/obj/item/robot_parts/robot_component/A = tool
+ if(A.organ_type)
+ O = A.organ_type
+ else
+ return 0
+ else
return 0
if(!target.species)
@@ -383,6 +390,11 @@
var/obj/item/organ/O = tool
if(istype(O))
O.replaced(target,affected)
+ else if(istype(tool, /obj/item/robot_parts/robot_component))
+ var/obj/item/robot_parts/robot_component/A = tool
+ if(A.organ_type)
+ O = A.organ_type
+ O.replaced(target,affected)
fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
user.visible_message("\red [user]'s hand slips, damaging \the [tool]!", \
@@ -455,4 +467,4 @@
// max_duration = 40
// can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
-// return ..() && target.op_stage.ribcage == 2
\ No newline at end of file
+// return ..() && target.op_stage.ribcage == 2
diff --git a/code/world.dm b/code/world.dm
index f5b526c3..790f6774 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -285,6 +285,8 @@ var/master_server_password
// apply some settings from config..
abandon_allowed = config.respawn
+ if (config.use_age_restriction_for_jobs)
+ config.load("config/age_restrictions.txt","age_restrictions")
/hook/startup/proc/loadMods()
world.load_mods()
diff --git a/config/example/age_restrictions.txt b/config/example/age_restrictions.txt
new file mode 100644
index 00000000..a0d3d3cf
--- /dev/null
+++ b/config/example/age_restrictions.txt
@@ -0,0 +1,71 @@
+#Try to keep up to date.
+#Replace all spaces in the job titles with underscores, otherwise the config will not load properly
+
+#These are all the titles (var/title) of the different job datums
+#Station jobs
+#Command
+Captain 0
+Head_of_Personnel 0
+Head_of_Security 0
+Chief_Engineer 0
+Research_Director 0
+Chief_Medical_Officer 0
+
+#Engineering
+Station_Engineer 0
+Atmospheric_Technician 0
+Engineering_Apprentice 0
+
+#Medical
+Medical_Doctor 0
+Psychiatrist 0
+Chemist 0
+Emergency_Medical_Tech 0
+Nursing_Intern 0
+
+#Science
+Scientist 0
+Geneticist 0
+Roboticist 0
+Xenobiologist 0
+Lab_Assistant 0
+
+#Security
+Warden 0
+Detective 0
+Forensic_Technician 0
+Security_Officer 0
+Security_Cadet 0
+
+#Civilian
+Bartender 0
+Botanist 0
+Chef 0
+Janitor 0
+Librarian 0
+Quartermaster 0
+Cargo_Technician 0
+Shaft_Miner 0
+Lawyer 0
+Chaplain 0
+Assistant 0
+Internal_Affairs_Agent 0
+
+#Synth
+AI 0
+Cyborg 0
+pAI 0
+
+#This is fetched from the special_roles global list.
+#Antags
+traitor 0
+operative 0
+changeling 0
+wizard 0
+malf_AI 0
+revolutionary 0
+cultist 0
+ninja 0
+vox_raider 0
+vampire 0
+mutineer 0
diff --git a/icons/obj/custom_items/jace_toothbrush.dmi b/icons/obj/custom_items/jace_toothbrush.dmi
new file mode 100644
index 00000000..63359516
Binary files /dev/null and b/icons/obj/custom_items/jace_toothbrush.dmi differ
diff --git a/icons/obj/robot_component.dmi b/icons/obj/robot_component.dmi
index 1129f25a..bb53a0ab 100644
Binary files a/icons/obj/robot_component.dmi and b/icons/obj/robot_component.dmi differ
diff --git a/icons/obj/seeds.dmi b/icons/obj/seeds.dmi
index 9f61275f..069f770c 100644
Binary files a/icons/obj/seeds.dmi and b/icons/obj/seeds.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index 202ec39b..694752e1 100644
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ