Merge branch 'master' into upstream-merge-9307

This commit is contained in:
cadyn
2020-11-15 00:48:22 -08:00
committed by GitHub
149 changed files with 17211 additions and 466 deletions

View File

@@ -155,6 +155,8 @@
#define MAT_METALHYDROGEN "mhydrogen"
#define MAT_OSMIUM "osmium"
#define MAT_GRAPHITE "graphite"
#define MAT_LEATHER "leather"
#define MAT_CHITIN "chitin"
#define SHARD_SHARD "shard"
#define SHARD_SHRAPNEL "shrapnel"

View File

@@ -114,11 +114,12 @@
trigger_aiming(TARGET_CAN_CLICK)
return 1
// VOREStation Addition Start: inbelly interaction
// VOREStation Addition Start: inbelly item interaction
if(isbelly(loc) && (loc == A.loc))
if(W)
to_chat(src, "The firm confines prevent that kind of dexterity!") //Only hand-based interactions in bellies
return
var/resolved = W.resolve_attackby(A,src)
if(!resolved && A && W)
W.afterattack(A, src, 1, params) // 1: clicking something Adjacent
else
if(ismob(A)) // No instant mob attacking
setClickCooldown(get_attack_speed())

View File

@@ -7,7 +7,7 @@ datum/controller/transfer_controller
var/shift_last_vote = 0 //VOREStation Edit
datum/controller/transfer_controller/New()
timerbuffer = config.vote_autotransfer_initial
shift_hard_end = config.vote_autotransfer_initial + (config.vote_autotransfer_interval * 3) //CHOMPStation Edit //Change this "1" to how many extend votes you want there to be.
shift_hard_end = config.vote_autotransfer_initial + (config.vote_autotransfer_interval * 2) //CHOMPStation Edit //Change this "1" to how many extend votes you want there to be. //Note: Fuck you whoever just slapped a number here instead of using the FUCKING CONFIG LIKE ALL THE OTHER NUMBERS HERE
shift_last_vote = shift_hard_end - config.vote_autotransfer_interval //VOREStation Edit
START_PROCESSING(SSprocessing, src)

View File

@@ -0,0 +1,43 @@
#define FIRE_PRIORITY_REFLECTOR 20
SUBSYSTEM_DEF(reflector)
name = "Reflectors"
priority = FIRE_PRIORITY_REFLECTOR
flags = SS_BACKGROUND|SS_NO_INIT
wait = 5
var/stat_tag = "R" //Used for logging
var/list/processing = list()
var/list/currentrun = list()
var/process_proc = /datum/proc/process
var/obj/structure/reflector/current_thing
/datum/controller/subsystem/reflector/Recover()
log_debug("[name] subsystem Recover().")
if(SSreflector.current_thing)
log_debug("current_thing was: (\ref[SSreflector.current_thing])[SSreflector.current_thing]([SSreflector.current_thing.type]) - currentrun: [SSreflector.currentrun.len] vs total: [SSreflector.processing.len]")
var/list/old_processing = SSreflector.processing.Copy()
for(var/datum/D in old_processing)
if(CHECK_BITFIELD(D.datum_flags, DF_ISPROCESSING))
processing |= D
/datum/controller/subsystem/reflector/stat_entry()
..("[stat_tag]:[processing.len]")
/datum/controller/subsystem/reflector/fire(resumed = 0)
if (!resumed)
currentrun = processing.Copy()
//cache for sanic speed (lists are references anyways)
var/list/current_run = currentrun
while(current_run.len)
current_thing = current_run[current_run.len]
current_run.len--
if(QDELETED(current_thing))
processing -= current_thing
current_thing.Fire()
if (MC_TICK_CHECK)
current_thing = null
return
current_thing = null

View File

@@ -72,13 +72,24 @@ SUBSYSTEM_DEF(vote)
/datum/controller/subsystem/vote/proc/get_result() // Get the highest number of votes
var/greatest_votes = 0
var/total_votes = 0
//CHOMPEdit Begin
if(mode == VOTE_CREW_TRANSFER)
var/transfer_votes = choices["Initiate Crew Transfer"]
var/extend_votes = choices["Extend the Shift"]
total_votes = extend_votes + transfer_votes
if(transfer_votes / total_votes > 0.7)
greatest_votes = transfer_votes
. = list("Initiate Crew Transfer")
else
greatest_votes = extend_votes
. = list("Extend the Shift")
else
for(var/option in choices)
var/votes = choices[option]
total_votes += votes
if(votes > greatest_votes)
greatest_votes = votes
//CHOMPEdit End
if(!config.vote_no_default && choices.len) // Default-vote for everyone who didn't vote
var/non_voters = (GLOB.clients.len - total_votes)
if(non_voters > 0)
@@ -107,12 +118,14 @@ SUBSYSTEM_DEF(vote)
choices["Initiate Crew Transfer"] = round(choices["Initiate Crew Transfer"] * factor)
to_world("<font color='purple'>Crew Transfer Factor: [factor]</font>")
greatest_votes = max(choices["Initiate Crew Transfer"], choices["Extend the Shift"]) //VOREStation Edit
//CHOMPEdit Begin
if(!(mode == VOTE_CREW_TRANSFER))
. = list() // Get all options with that many votes and return them in a list
if(greatest_votes)
for(var/option in choices)
if(choices[option] == greatest_votes)
. += option
//CHOMPEdit End
/datum/controller/subsystem/vote/proc/announce_result()
var/list/winners = get_result()

View File

@@ -12,6 +12,7 @@
var/signal_enabled = FALSE
var/weakref/weakref // Holder of weakref instance pointing to this datum
var/datum_flags = NONE
var/trigger_uid //CHOMPEdit
#ifdef TESTING
var/tmp/running_find_references

View File

@@ -19,10 +19,13 @@
alt_titles = list("Intern" = /datum/alt_title/intern,
"Apprentice Engineer" = /datum/alt_title/intern_eng,
"Medical Intern" = /datum/alt_title/intern_med,
"Lab Assistant" = /datum/alt_title/intern_sci,
"Lab Assistant" = /datum/alt_title/intern_sci, //CHOMPEdit
"Security Cadet" = /datum/alt_title/intern_sec,
"Jr. Cargo Tech" = /datum/alt_title/intern_crg,
"Server" = /datum/alt_title/server)
"Server" = /datum/alt_title/server,
//CHOMPSTATION edit start.
"Belly Filler" = /datum/alt_title/prey)
//CHOMPSTATION edit end.
job_description = "An Intern does whatever is requested of them, often doing so in process of learning \
another job. Though they are part of the crew, they have no real authority."
timeoff_factor = 0 // Interns, noh
@@ -33,7 +36,7 @@
/datum/alt_title/intern_eng
title = "Apprentice Engineer"
title_blurb = "An Apprentice Engineer attempts to provide whatever the Engineering department needs. They are not proper Engineers, and are \
often in training to become an Engineer. A Technical Assistant has no real authority."
often in training to become an Engineer. An Apprentice Engineer has no real authority."
title_outfit = /decl/hierarchy/outfit/job/assistant/engineer
/datum/alt_title/intern_med
@@ -43,9 +46,9 @@
title_outfit = /decl/hierarchy/outfit/job/assistant/medic
/datum/alt_title/intern_sci
title = "Lab Assistant"
title = "Lab Assistant" //CHOMPEdit
title_blurb = "A Lab Assistant attempts to provide whatever the Research department needs. They are not proper Scientists, and are \
often in training to become a Scientist. A Lab Assistant has no real authority."
often in training to become a Scientist. A Lab Assistant has no real authority." //CHOMPEdit
title_outfit = /decl/hierarchy/outfit/job/assistant/scientist
/datum/alt_title/intern_sec
@@ -65,10 +68,13 @@
title_blurb = "A Server helps out kitchen and diner staff with various tasks, primarily food delivery. A Server has no real authority."
title_outfit = /decl/hierarchy/outfit/job/service/server
//////////////////////////////////
// Visitor
//////////////////////////////////
//CHOMPSTATION edit start: Thought it would be funny for people to wear their reason for being on station on their shoulder.
/datum/alt_title/prey
title = "Belly Filler"
title_blurb = "Considering the needs of this particular region of space, a Belly Filler is a crewmember who has willingly consigned themselves to \
serving the voracious appetites of their fellow crewmembers. A Belly Filler has no authority."
title_outfit = /decl/hierarchy/outfit/job/assistant/intern
//CHOMPSTATION edit end.
/datum/job/intern/New()
..()
@@ -82,11 +88,17 @@
else
return list()
//////////////////////////////////
// Visitor
//////////////////////////////////
/datum/job/assistant // Visitor
title = USELESS_JOB
supervisors = "nobody! You don't work here"
job_description = "A Visitor is just there to visit the place. They have no real authority or responsibility."
timeoff_factor = 0
alt_titles = list("Guest" = /datum/alt_title/guest, "Traveler" = /datum/alt_title/traveler)
/datum/job/assistant/New()
..()
@@ -96,3 +108,9 @@
/datum/job/assistant/get_access()
return list()
/datum/alt_title/guest
title = "Guest"
/datum/alt_title/traveler
title = "Traveler"

View File

@@ -2,6 +2,14 @@
disallow_jobhop = TRUE
pto_type = PTO_CIVILIAN
dept_time_required = 80 //Pending something more complicated
alt_titles = list("Overseer"= /datum/alt_title/overseer, "Facility Director" = /datum/alt_title/facility_director, "Chief Supervisor" = /datum/alt_title/chief_supervisor)
/datum/alt_title/facility_director
title = "Facility Director"
/datum/alt_title/chief_supervisor
title = "Chief Supervisor"
/datum/job/hop
disallow_jobhop = TRUE
@@ -10,8 +18,8 @@
departments_managed = list(DEPARTMENT_CIVILIAN, DEPARTMENT_CARGO, DEPARTMENT_PLANET)
dept_time_required = 60
alt_titles = list("Crew Resources Officer" = /datum/alt_title/cro,
"Deputy Director" = /datum/alt_title/deputy_director)
alt_titles = list("Crew Resources Officer" = /datum/alt_title/cro, "Deputy Director" = /datum/alt_title/deputy_director, "Staff Manager" = /datum/alt_title/staff_manager,
"Facility Steward" = /datum/alt_title/facility_steward) //CHOMPEdit
access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers,
access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,
@@ -29,6 +37,27 @@
/datum/alt_title/deputy_director
title = "Deputy Director"
/datum/alt_title/staff_manager
title = "Staff Manager"
/datum/alt_title/facility_steward
title = "Facility Steward"
/datum/job/secretary
disallow_jobhop = TRUE
pto_type = PTO_CIVILIAN
alt_titles = list("Command Liaison" = /datum/alt_title/command_liaison, "Bridge Secretary" = /datum/alt_title/bridge_secretary,
"Command Assistant" = /datum/alt_title/command_assistant, "Command Intern" = /datum/alt_title/command_intern)
/datum/alt_title/command_liaison
title = "Command Liaison"
/datum/alt_title/bridge_secretary
title = "Bridge Secretary"
/datum/alt_title/command_assistant
title = "Command Assistant"
/datum/alt_title/command_intern
title = "Command Intern"

View File

@@ -1,34 +1,104 @@
/datum/job/bartender
pto_type = PTO_CIVILIAN
alt_titles = list("Barkeeper" = /datum/alt_title/barkeeper, "Barmaid" = /datum/alt_title/barmaid, "Barista" = /datum/alt_title/barista, "Mixologist" = /datum/alt_title/mixologist)
/datum/alt_title/barkeeper
title = "Barkeeper"
/datum/alt_title/barmaid
title = "Barmaid"
/datum/alt_title/mixologist
title = "Mixologist"
/datum/job/chef
total_positions = 2 //IT TAKES A LOT TO MAKE A STEW
spawn_positions = 2 //A PINCH OF SALT AND LAUGHTER, TOO
pto_type = PTO_CIVILIAN
alt_titles = list("Sous-chef" = /datum/alt_title/souschef,"Cook" = /datum/alt_title/cook, "Kitchen Worker" = /datum/alt_title/kitchen_worker)
/datum/alt_title/souschef
title = "Sous-chef"
/datum/alt_title/kitchen_worker
title = "Kitchen Worker"
title_blurb = "A Kitchen Worker has the same duties, though they may be less experienced."
/datum/job/hydro
spawn_positions = 2
pto_type = PTO_CIVILIAN
alt_titles = list("Hydroponicist" = /datum/alt_title/hydroponicist, "Cultivator" = /datum/alt_title/cultivator, "Farmer" = /datum/alt_title/farmer,
"Gardener" = /datum/alt_title/gardener, "Florist" = /datum/alt_title/florsit)
/datum/alt_title/hydroponicist
title = "Hydroponicist"
/datum/alt_title/cultivator
title = "Cultivator"
/datum/alt_title/farmer
title = "Farmer"
/datum/alt_title/florsit
title = "Florist"
title_blurb = "A Florist may be less professional than their counterparts, and are more likely to tend to the public gardens if they aren't needed elsewhere."
/datum/job/qm
pto_type = PTO_CARGO
dept_time_required = 20
alt_titles = list("Supply Chief" = /datum/alt_title/supply_chief, "Logistics Manager" = /datum/alt_title/logistics_manager)
/datum/alt_title/logistics_manager
title = "Logistics Manager"
/datum/job/cargo_tech
total_positions = 3
spawn_positions = 3
pto_type = PTO_CARGO
alt_titles = list("Cargo Loader" = /datum/alt_title/cargo_loader, "Cargo Handler" = /datum/alt_title/cargo_handler, "Supply Courier" = /datum/alt_title/supply_courier,
"Disposals Sorter" = /datum/alt_title/disposal_sorter)
/datum/alt_title/supply_courier
title = "Supply Courier"
title_blurb = "A Supply Courier is usually tasked with devlivering packages or cargo directly to whoever requires it."
/datum/alt_title/cargo_loader
title = "Cargo Loader"
title_blurb = "A Cargo Loader is usually tasked with more menial labor within Supply department, such as loading and unloading supply shuttle."
/datum/alt_title/cargo_handler
title = "Cargo Handler"
title_blurb = "A Cargo Loader is usually tasked with more menial labor within Supply department, such as loading and unloading supply shuttle."
/datum/alt_title/disposal_sorter
title = "Disposals Sorter"
title_blurb = "A Disposals Sorter is usually tasked with operating disposals delivery system, sorting the trash and tagging parcels for delivery."
/datum/job/mining
total_positions = 4
spawn_positions = 4
pto_type = PTO_CARGO
alt_titles = list(/*CHOMPEdit Removal "Deep Space Miner" = /datum/alt_title/deep_space_miner*/, "Drill Technician" = /datum/alt_title/drill_tech, "Prospector" = /datum/alt_title/prospector)
/datum/alt_title/deep_space_miner
title = "Deep Space Miner"
title_blurb = "A Deep Space Miner specializes primarily in mining operations in zero-g environments, mostly in asteroid and debris fields."
/datum/alt_title/prospector
title = "Prospector"
/datum/job/janitor //Lots of janitor substations on station.
total_positions = 3
spawn_positions = 3
alt_titles = list("Custodian" = /datum/alt_title/custodian, "Sanitation Technician" = /datum/alt_title/sanitation_tech, "Maid" = /datum/alt_title/maid)
pto_type = PTO_CIVILIAN
alt_titles = list("Custodian" = /datum/alt_title/custodian, "Sanitation Technician" = /datum/alt_title/sanitation_tech,
"Maid" = /datum/alt_title/maid, "Garbage Collector" = /datum/alt_title/garbage_collector)
/datum/alt_title/sanitation_tech
title = "Sanitation Technician"
@@ -36,26 +106,73 @@
/datum/alt_title/maid
title = "Maid"
/datum/alt_title/garbage_collector
title = "Garbage Collector"
title_blurb = "A Garbage Collector keeps the station clean, though focuses moreso on collecting larger trash, with wet cleaning being secondary task."
/datum/job/librarian
total_positions = 2
spawn_positions = 2
alt_titles = list("Journalist" = /datum/alt_title/journalist, "Writer" = /datum/alt_title/writer, "Historian" = /datum/alt_title/historian, "Professor" = /datum/alt_title/professor)
alt_titles = list("Journalist" = /datum/alt_title/journalist, "Reporter" = /datum/alt_title/reporter, "Writer" = /datum/alt_title/writer,
"Historian" = /datum/alt_title/historian, "Archivist" = /datum/alt_title/archivist, "Professor" = /datum/alt_title/professor,
"Academic" = /datum/alt_title/academic, "Philosopher" = /datum/alt_title/philosopher)
pto_type = PTO_CIVILIAN
/datum/alt_title/reporter
title = "Reporter"
title_blurb = "The Reporter uses the Library as a base of operations, from which they can report the news and goings-on on the station with their camera."
/datum/alt_title/historian
title = "Historian"
title_blurb = "The Historian uses the Library as a base of operation to record any important events occuring on station."
/datum/alt_title/archivist
title = "Archivist"
title_blurb = "The Archivist uses the Library as a base of operation to record any important events occuring on station."
/datum/alt_title/professor
title = "Professor"
title_blurb = "The Professor uses the Library as a base of operations to share their vast knowledge with the crew."
/datum/alt_title/academic
title = "Academic"
title_blurb = "The Academic uses the Library as a base of operations to share their vast knowledge with the crew."
/datum/alt_title/philosopher
title = "Philosopher"
title_blurb = "The Philosopher uses the Library as a base of operation to ruminate on nature of life and other great questions, and share their opinions with the crew."
/datum/job/lawyer
disallow_jobhop = TRUE
pto_type = PTO_CIVILIAN
alt_titles = list("Internal Affairs Liaison" = /datum/alt_title/ia_liaison, "Internal Affairs Delegate" = /datum/alt_title/ia_delegate,
"Internal Affairs Investigator" = /datum/alt_title/ia_investigator)
/datum/alt_title/ia_liaison
title = "Internal Affairs Liaison"
/datum/alt_title/ia_delegate
title = "Internal Affairs Delegate"
/datum/alt_title/ia_investigator
title = "Internal Affairs Investigator"
/datum/job/chaplain
pto_type = PTO_CIVILIAN
alt_titles = list("Missionary" = /datum/alt_title/missionary, "Preacher" = /datum/alt_title/preacher, "Counselor" = /datum/alt_title/counselor, "Guru" = /datum/alt_title/guru)
/datum/alt_title/guru
title = "Guru"
title_blurb = "The Guru primarily tries to offer spiritual guidance to those who come seeking it."
/datum/alt_title/missionary
title = "Missionary"
/datum/alt_title/preacher
title = "Preacher"
@@ -79,17 +196,43 @@
outfit_type = /decl/hierarchy/outfit/job/assistant
job_description = "An entertainer does just that, entertains! Put on plays, play music, sing songs, tell stories, or read your favorite fanfic."
alt_titles = list("Performer" = /datum/alt_title/performer, "Musician" = /datum/alt_title/musician, "Stagehand" = /datum/alt_title/stagehand)
alt_titles = list("Performer" = /datum/alt_title/performer, "Musician" = /datum/alt_title/musician, "Stagehand" = /datum/alt_title/stagehand,
"Actor" = /datum/alt_title/actor, "Dancer" = /datum/alt_title/dancer, "Singer" = /datum/alt_title/singer,
"Magician" = /datum/alt_title/magician, "Comedian" = /datum/alt_title/comedian, "Tragedian" = /datum/alt_title/tragedian)
// Entertainer Alt Titles
/datum/alt_title/actor
title = "Actor"
title_blurb = "An Actor is someone who acts out a role! Whatever sort of character it is, get into it and impress people with power of comedy and tragedy!"
/datum/alt_title/performer
title = "Performer"
title_blurb = "A Performer is someone who performs! Acting, dancing, wrestling, etc!"
title_blurb = "A Performer is someone who performs! Whatever sort of performance will come to your mind, the world's a stage!"
/datum/alt_title/musician
title = "Musician"
title_blurb = "A Musician is someone who makes music! Singing, playing instruments, slam poetry, it's your call!"
title_blurb = "A Musician is someone who makes music with a wide variety of musical instruments!"
/datum/alt_title/stagehand
title = "Stagehand"
title_blurb = "A Stagehand typically performs everything the rest of the entertainers don't. Operate lights, shutters, windows, or narrate through your voicebox!"
/datum/alt_title/dancer
title = "Dancer"
title_blurb = "A Dancer is someone who impresses people through power of their own body! From waltz to breakdance, as long as crowd as cheering!"
/datum/alt_title/singer
title = "Singer"
title_blurb = "A Singer is someone with gift of melodious voice! Impress people with your vocal range!"
/datum/alt_title/magician
title = "Magician"
title_blurb = "A Magician is someone who awes those around them with impossible! Show off your repertoire of magic tricks, while keeping the secret hidden!"
/datum/alt_title/comedian
title = "Comedian"
title_blurb = "A Comedian will focus on making people laugh with the power of wit! Telling jokes, stand-up comedy, you are here to make others smile!"
/datum/alt_title/tragedian
title = "Tragedian"
title_blurb = "A Tragedian will focus on making people think about life and world around them! Life is a tragedy, and who's better to convey its emotions than you?"

View File

@@ -12,10 +12,38 @@
access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva,
access_heads, access_construction,
access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload)
alt_titles = list("Head Engineer" = /datum/alt_title/head_engineer, "Foreman" = /datum/alt_title/foreman, "Maintenance Manager" = /datum/alt_title/maintenance_manager)
/datum/alt_title/head_engineer
title = "Head Engineer"
/datum/alt_title/foreman
title = "Foreman"
/datum/alt_title/maintenance_manager
title = "Maintenance Manager"
/datum/job/engineer
pto_type = PTO_ENGINEERING
alt_titles = list("Maintenance Technician" = /datum/alt_title/maint_tech, "Engine Technician" = /datum/alt_title/engine_tech,
"Electrician" = /datum/alt_title/electrician, "Construction Engineer" = /datum/alt_title/construction_engi)
/datum/alt_title/construction_engi
title = "Construction Engineer"
title_blurb = "A Construction Engineer fulfills similar duties to other engineers, but usually occupies spare time with construction of extra facilities in dedicated areas or \
as additions to station layout."
/datum/job/atmos
spawn_positions = 3
pto_type = PTO_ENGINEERING
alt_titles = list("Atmospherics Maintainer" = /datum/alt_title/atmos_maint, /*CHOMPEdit "Disposals Technician" = /datum/alt_title/disposals_tech*/)
/datum/alt_title/atmos_maint
title = "Atmospherics Maintainer"
/datum/alt_title/disposals_tech
title = "Disposals Technician"
title_blurb = "A Disposals Technician is an Atmospheric Technician still and can fulfill all the same duties, although specializes more in disposals delivery system's operations and configurations."

View File

@@ -29,6 +29,8 @@ var/const/SAR =(1<<14)
color = "#bab421"
sorting_order = 2 // Same as cargo in importance.
/datum/job/pathfinder
title = "Pathfinder"
flag = PATHFINDER
@@ -50,9 +52,14 @@ var/const/SAR =(1<<14)
minimal_access = list(access_eva, access_maint_tunnels, access_external_airlocks, access_pilot, access_explorer, access_gateway)
outfit_type = /decl/hierarchy/outfit/job/pathfinder
job_description = "The Pathfinder's job is to lead and manage expeditions, and is the primary authority on all off-station expeditions."
alt_titles = list("Expedition Lead" = /datum/alt_title/expedition_lead, "Exploration Manager" = /datum/alt_title/exploration_manager)
/datum/alt_title/expedition_lead
title = "Expedition Lead"
/datum/alt_title/exploration_manager
title = "Exploration Manager"
/datum/alt_title/pathfinder
title = "Pathfinder"
/datum/job/pilot
title = "Pilot"
@@ -71,9 +78,15 @@ var/const/SAR =(1<<14)
minimal_access = list(access_pilot)
outfit_type = /decl/hierarchy/outfit/job/pilot
job_description = "A Pilot flies the various shuttles in the Virgo-Erigone System."
alt_titles = list("Co-Pilot" = /datum/alt_title/co_pilot, "Navigator" = /datum/alt_title/navigator)
/datum/alt_title/co_pilot
title = "Co-Pilot"
title_blurb = "A Co-Pilot is there primarily to assist main pilot as well as learn from them"
/datum/alt_title/navigator
title = "Navigator"
/datum/alt_title/pilot
title = "Pilot"
/datum/job/explorer
title = "Explorer"
@@ -91,9 +104,14 @@ var/const/SAR =(1<<14)
minimal_access = list(access_explorer, access_external_airlocks, access_eva)
outfit_type = /decl/hierarchy/outfit/job/explorer2
job_description = "An Explorer searches for interesting things, and returns them to the station."
alt_titles = list("Surveyor" = /datum/alt_title/surveyor, "Offsite Scout" = /datum/alt_title/offsite_scout)
/datum/alt_title/surveyor
title = "Surveyor"
/datum/alt_title/offsite_scout
title = "Offsite Scout"
/datum/alt_title/explorer
title = "Explorer"
/datum/job/sar
title = "Field Medic"
@@ -112,25 +130,7 @@ var/const/SAR =(1<<14)
minimal_access = list(access_medical, access_medical_equip, access_morgue, access_pilot)
outfit_type = /decl/hierarchy/outfit/job/medical/sar
job_description = "A Field medic works as the field doctor of expedition teams."
alt_titles = list("Expedition Medic" = /datum/alt_title/expedition_medic)
/datum/alt_title/field_medic
title = "Field Medic"
/datum/job/offduty_exploration
title = "Off-duty Explorer"
latejoin_only = TRUE
timeoff_factor = -1
total_positions = -1
faction = "Station"
departments = list(DEPARTMENT_OFFDUTY)
supervisors = "nobody! Enjoy your time off"
selection_color = "#999440"
access = list(access_maint_tunnels, access_external_airlocks)
minimal_access = list(access_maint_tunnels, access_external_airlocks)
outfit_type = /decl/hierarchy/outfit/job/assistant/explorer
job_description = "Off-duty crew has no responsibilities or authority and is just there to spend their well-deserved time off."
pto_type = PTO_EXPLORATION
economic_modifier = 5
/datum/alt_title/offduty_exp
title = "Off-duty Explorer"
/datum/alt_title/expedition_medic
title = "Expedition Medic"

View File

@@ -16,10 +16,10 @@
req_admin_notify = 1
economic_modifier = 10
access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, access_teleporter,
access_keycard_auth, access_sec_doors, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels)
minimal_access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, access_teleporter,
access_keycard_auth, access_sec_doors, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels)
minimum_character_age = 25

View File

@@ -4,22 +4,77 @@
dept_time_required = 60
access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, access_teleporter, //CHOMPEdit
access_keycard_auth, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels)
minimal_access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce, access_teleporter,//CHOMPEdit
access_keycard_auth, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels)
alt_titles = list("Chief Physician" = /datum/alt_title/chief_physician, "Medical Director" = /datum/alt_title/medical_director, /*CHOMPEdit Removal"Healthcare Manager" = /datum/alt_title/healthcare_manager*/)
/datum/alt_title/chief_physician
title = "Chief Physician"
/datum/alt_title/medical_director
title = "Medical Director"
/datum/alt_title/healthcare_manager
title = "Healthcare Manager"
/datum/job/doctor
spawn_positions = 5
pto_type = PTO_MEDICAL
alt_titles = list("Physician" = /datum/alt_title/physician, "Medical Practitioner" = /datum/alt_title/medical_practitioner, "Surgeon" = /datum/alt_title/surgeon,
"Emergency Physician" = /datum/alt_title/emergency_physician, "Nurse" = /datum/alt_title/nurse, "Orderly" = /datum/alt_title/orderly,
"Virologist" = /datum/alt_title/virologist)
/datum/alt_title/physician
title = "Physician"
/datum/alt_title/medical_practitioner
title = "Medical Practitioner"
/datum/alt_title/orderly
title = "Orderly"
title_blurb = "An Orderly acts as Medbay's general helping hand, assisting any doctor that might need some form of help, as well as handling manual \
and dirty labor around the department."
title_outfit = /decl/hierarchy/outfit/job/medical/doctor/nurse
/datum/job/chemist
pto_type = PTO_MEDICAL
alt_titles = list("Pharmacist" = /datum/alt_title/pharmacist, "Pharmacologist" = /datum/alt_title/pharmacologist)
/datum/alt_title/pharmacologist
title = "Pharmacologist"
title_blurb = "A Pharmacologist focuses on the chemical needs of the Medical Department, primarily specializing in producing more advanced forms of medicine."
/datum/job/psychiatrist
pto_type = PTO_MEDICAL
alt_titles = list("Psychologist" = /datum/alt_title/psychologist, "Psychoanalyst" = /datum/alt_title/psychoanalyst, "Psychotherapist" = /datum/alt_title/psychotherapist)
/datum/alt_title/psychoanalyst
title = "Psychoanalyst"
title_blurb = "A Psychoanalyst provides mental health services to crew members in need, focusing more on therapy than medication. They may also be \
called upon to determine whatever ails the mentally unwell, frequently under Security supervision."
title_outfit = /decl/hierarchy/outfit/job/medical/psychiatrist/psychologist
/datum/alt_title/psychotherapist
title = "Psychotherapist"
title_blurb = "A Psychotherapist provides mental health services to crew members in need, focusing more on therapy than medication. They may also be \
called upon to determine whatever ails the mentally unwell, frequently under Security supervision."
title_outfit = /decl/hierarchy/outfit/job/medical/psychiatrist/psychologist
/datum/job/paramedic
pto_type = PTO_MEDICAL
alt_titles = list("Emergency Medical Technician" = /datum/alt_title/emt, "Medical Responder" = /datum/alt_title/medical_responder)
/datum/alt_title/medical_responder
title = "Medical Responder"
title_blurb = "A Medical Responder is primarily concerned with the recovery of patients who are unable to make it to the Medical Department on their \
own. They are capable of keeping a patient stabilized until they reach the hands of someone with more training."
title_outfit = /decl/hierarchy/outfit/job/medical/paramedic/emt

View File

@@ -18,9 +18,6 @@
pto_type = PTO_CIVILIAN
economic_modifier = 2
/datum/alt_title/offduty_civ
title = "Off-duty Worker"
/datum/job/offduty_cargo
title = "Off-duty Cargo"
latejoin_only = TRUE
@@ -37,9 +34,6 @@
pto_type = PTO_CARGO
economic_modifier = 2
/datum/alt_title/offduty_crg
title = "Off-duty Cargo"
/datum/job/offduty_engineering
title = "Off-duty Engineer"
latejoin_only = TRUE
@@ -56,9 +50,6 @@
pto_type = PTO_ENGINEERING
economic_modifier = 5
/datum/alt_title/offduty_eng
title = "Off-duty Engineer"
/datum/job/offduty_medical
title = "Off-duty Medic"
latejoin_only = TRUE
@@ -75,9 +66,6 @@
pto_type = PTO_MEDICAL
economic_modifier = 5
/datum/alt_title/offduty_med
title = "Off-duty Medic"
/datum/job/offduty_science
title = "Off-duty Scientist"
latejoin_only = TRUE
@@ -94,9 +82,6 @@
pto_type = PTO_SCIENCE
economic_modifier = 5
/datum/alt_title/offduty_sci
title = "Off-duty Scientist"
/datum/job/offduty_security
title = "Off-duty Officer"
latejoin_only = TRUE
@@ -113,5 +98,18 @@
pto_type = PTO_SECURITY
economic_modifier = 5
/datum/alt_title/offduty_sec
title = "Off-duty Officer"
/datum/job/offduty_exploration
title = "Off-duty Explorer"
latejoin_only = TRUE
timeoff_factor = -1
total_positions = -1
faction = "Station"
departments = list(DEPARTMENT_OFFDUTY)
supervisors = "nobody! Enjoy your time off"
selection_color = "#999440"
access = list(access_maint_tunnels, access_external_airlocks)
minimal_access = list(access_maint_tunnels, access_external_airlocks)
outfit_type = /decl/hierarchy/outfit/job/assistant/explorer
job_description = "Off-duty crew has no responsibilities or authority and is just there to spend their well-deserved time off."
pto_type = PTO_EXPLORATION
economic_modifier = 5

View File

@@ -13,30 +13,73 @@
access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage,
access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_eva, access_network,
access_explorer, access_pathfinder, access_xenobotany) //YW Edit access_gateway, _explorer, _pathfinder, and _xenobotany
/datum/alt_title/research_manager
title = "Research Manager"
/datum/alt_title/head_of_development
title = "Head of Development"
/datum/alt_title/head_scientist
title = "Head Scientist"
/datum/job/scientist
spawn_positions = 5
pto_type = PTO_SCIENCE
alt_titles = list("Xenoarchaeologist" = /datum/alt_title/xenoarch, "Anomalist" = /datum/alt_title/anomalist, \
"Phoron Researcher" = /datum/alt_title/phoron_research, "Circuit Designer" = /datum/alt_title/circuit_designer)
alt_titles = list("Lab Assistant" = /datum/alt_title/lab_assistant, "Xenoarchaeologist" = /datum/alt_title/xenoarch, "Xenopaleontologist" = /datum/alt_title/xenopaleontologist, \
"Anomalist" = /datum/alt_title/anomalist, "Phoron Researcher" = /datum/alt_title/phoron_research, "Gas Physicist" = /datum/alt_title/gas_physicist, \
"Circuit Designer" = /datum/alt_title/circuit_designer, "Circuit Programmer" = /datum/alt_title/circuit_programmer)
access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology, access_xenoarch, access_xenobotany)
minimal_access = list(access_tox, access_tox_storage, access_research, access_xenoarch) // Unchanged (for now?), mostly here for reference
/datum/alt_title/lab_assistant
title = "Lab Assistant"
title_blurb = "A Lab Assistant is a lower-level member of research staff, whose main purpose is to help scientists with their specialized work in more menial fashion, while also \
learning the specializations in process."
/datum/alt_title/xenopaleontologist
title = "Xenopaleontologist"
title_blurb = "A Xenopaleontologist enters digsites in search of fossils and other ancient remants of alien life. These digsites are frequently in vacuum or other inhospitable \
locations, and as such a Xenopaleontologist should be prepared to handle hostile evironmental conditions."
/datum/alt_title/gas_physicist
title = "Gas Physicist"
title_blurb = "A Gas Physicist is a specialist in various practical applications of gasses, but currently focuses their attention on phoron, and has knowledge of its practical uses and dangers. \
Many Gas Physicists are interested in the combustability and explosive properties of gaseous phoron, as well as the specific hazards \
of working with the substance in that state."
/datum/alt_title/circuit_designer
title = "Circuit Designer"
title_blurb = "A Circuit Designer is a Scientist whose expertise is working with integrated circuits. They are familar with the workings and programming of those devices. \
They work to create various useful devices using the capabilities of integrated circuitry."
/datum/alt_title/circuit_programmer
title = "Circuit Programmer"
title_blurb = "A Circuit Programmer is a Scientist whose expertise is working with integrated circuits. They are familar with the workings and programming of those devices. \
They work to create various useful devices using the capabilities of integrated circuitry."
/datum/job/xenobiologist
spawn_positions = 3
pto_type = PTO_SCIENCE
alt_titles = list("Xenozoologist" = /datum/alt_title/xenozoologist, "Xenoanthropologist" = /datum/alt_title/xenoanthropologist)
/datum/alt_title/xenozoologist
title = "Xenozoologist"
/datum/alt_title/xenoanthropologist
title = "Xenoanthropologist"
title_blurb = "Xenoanthropologist still heavily focuses their study on alien lifeforms, but their specialty leans more towards fellow sapient beings than simple animals."
/datum/job/roboticist
total_positions = 3
pto_type = PTO_SCIENCE
alt_titles = list("Assembly Technician" = /datum/alt_title/assembly_tech, "Biomechanical Engineer" = /datum/alt_title/biomech, "Mechatronic Engineer" = /datum/alt_title/mech_tech)
/datum/alt_title/assembly_tech
title = "Assembly Technician"
//////////////////////////////////
// Xenobotanist
@@ -61,3 +104,7 @@
outfit_type = /decl/hierarchy/outfit/job/science/xenobiologist
job_description = "A Xenobotanist grows and cares for a variety of abnormal, custom made, and frequently dangerous plant life. When the products of these plants \
are both safe and beneficial to the station, they may choose to introduce it to the rest of the crew."
alt_titles = list("Xenoflorist" = /datum/alt_title/xenoflorist)
/datum/alt_title/xenoflorist
title = "Xenoflorist"

View File

@@ -3,23 +3,55 @@
pto_type = PTO_SECURITY
dept_time_required = 60
access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory,
access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_teleporter,
access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
access_construction,
access_heads, access_hos, access_RC_announce, access_keycard_auth, access_external_airlocks)
minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory,
minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory, access_teleporter,
access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
access_construction,
access_heads, access_hos, access_RC_announce, access_keycard_auth, access_external_airlocks)
alt_titles = list("Security Commander" = /datum/alt_title/sec_commander, "Chief of Security" = /datum/alt_title/sec_chief, "Security Manager" = /datum/alt_title/security_manager)
/datum/alt_title/security_manager
title = "Security Manager"
/datum/job/warden
pto_type = PTO_SECURITY
dept_time_required = 20
alt_titles = list("Brig Sentry" = /datum/alt_title/brig_sentry, "Armory Superintendent" = /datum/alt_title/armory_superintendent)
/datum/alt_title/brig_sentry
title = "Brig Sentry"
/datum/alt_title/armory_superintendent
title = "Armory Superintendent"
/datum/job/detective
pto_type = PTO_SECURITY
alt_titles = list("Investigator" = /datum/alt_title/investigator, "Security Inspector" = /datum/alt_title/security_inspector, "Forensic Technician" = /datum/alt_title/forensic_tech)
/datum/alt_title/investigator
title = "Investigator"
/datum/alt_title/security_inspector
title = "Security Inspector"
/datum/job/officer
total_positions = 5
spawn_positions = 5
pto_type = PTO_SECURITY
alt_titles = list("Patrol Officer" = /datum/alt_title/patrol_officer, "Security Guard" = /datum/alt_title/security_guard,
"Security Deputy" = /datum/alt_title/security_guard, "Junior Officer" = /datum/alt_title/junior_officer)
/datum/alt_title/patrol_officer
title = "Patrol Officer"
/datum/alt_title/security_guard
title = "Security Guard"
/datum/alt_title/security_deputy
title = "Security Deputy"

View File

@@ -85,18 +85,18 @@
selection_color = "#515151"
economic_modifier = 1
job_description = "A Clown is there to entertain the crew and keep high morale using various harmless pranks and ridiculous jokes!"
alt_titles = list("Clown" = /datum/alt_title/clown, "Jester" = /datum/alt_title/jester)
whitelist_only = 1
latejoin_only = 1
outfit_type = /decl/hierarchy/outfit/job/clown
pto_type = PTO_CIVILIAN
/datum/alt_title/clown
title = "Clown"
alt_titles = list("Jester" = /datum/alt_title/jester, "Fool" = /datum/alt_title/fool)
/datum/alt_title/jester
title = "Jester"
/datum/alt_title/fool
title = "Fool"
/datum/job/clown/get_access()
if(config.assistant_maint)
return list(access_maint_tunnels, access_entertainment)
@@ -115,17 +115,14 @@
selection_color = "#515151"
economic_modifier = 1
job_description = "A Mime is there to entertain the crew and keep high morale using unbelievable performances and acting skills!"
alt_titles = list("Mime" = /datum/alt_title/mime, "Interpretive Dancer" = /datum/alt_title/interpretive_dancer)
alt_titles = list("Poseur" = /datum/alt_title/poseur)
whitelist_only = 1
latejoin_only = 1
outfit_type = /decl/hierarchy/outfit/job/mime
pto_type = PTO_CIVILIAN
/datum/alt_title/mime
title = "Mime"
/datum/alt_title/interpretive_dancer
title = "Interpretive Dancer"
/datum/alt_title/poseur
title = "Poseur"
/datum/job/mime/get_access()
if(config.assistant_maint)

View File

@@ -85,7 +85,7 @@
if(do_after(user,30 SECONDS,src)) //CHOMPedit . Increased time to force open welded door for alien
visible_message("<span class='danger'>\The [user] tears \the [src] open, sparks flying from its electronics!</span>") //CHOMPedit
src.do_animate("spark")
playsound(src, 'sound/machines/door/airlock_creaking.ogg', 100, 1, volume_channel = VOLUME_CHANNEL_DOORS)
playsound(src, 'sound/machines/door/airlock_creaking_xeno.ogg', 100, 1, volume_channel = VOLUME_CHANNEL_DOORS) //CHOMPedit gave xeno airlock breaking its own sound effect
src.locked = 0
src.welded = 0
update_icon()

View File

@@ -0,0 +1,122 @@
/obj/machinery/feeder
name = "\improper Feeder"
icon = 'icons/obj/feeder.dmi'
desc = "This is a feeder. Put in a reagent container, then click and drag the feeder to someone!"
anchored = FALSE
density = FALSE
var/mob/living/carbon/human/attached = null
var/obj/item/weapon/reagent_containers/beaker = null
/obj/machinery/feeder/update_icon()
if(attached)
icon_state = "feeding"
else
icon_state = ""
overlays.Cut()
if(beaker)
var/datum/reagents/reagents = beaker.reagents
if(reagents.total_volume)
var/image/filling = image('icons/obj/feeder.dmi', src, "reagent")
var/percent = round((reagents.total_volume / beaker.volume) * 100)
switch(percent)
if(0 to 9) filling.icon_state = "reagent0"
if(10 to 19) filling.icon_state = "reagent10"
if(20 to 44) filling.icon_state = "reagent20"
if(45 to 59) filling.icon_state = "reagent45"
if(60 to 74) filling.icon_state = "reagent60"
if(75 to 89) filling.icon_state = "reagent75"
if(90 to 94) filling.icon_state = "reagent90"
if(95 to INFINITY) filling.icon_state = "reagent100"
filling.icon += reagents.get_color()
overlays += filling
/obj/machinery/feeder/MouseDrop(over_object, src_location, over_location)
..()
if(!isliving(usr))
return
if(attached)
visible_message("The feeding tube is pulled out of [attached].")
attached = null
update_icon()
return
if(in_range(src, usr) && ishuman(over_object) && get_dist(over_object, src) <= 1)
visible_message("[usr] inserts the feeding tube into \the [over_object].")
attached = over_object
update_icon()
/obj/machinery/feeder/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/reagent_containers))
if(!isnull(beaker))
. += "There is already a reagent container inserted!"
return
user.drop_item()
W.loc = src
beaker = W
. += "You insert \the [W] into \the [src]."
update_icon()
return
if(default_deconstruction_screwdriver(user, W))
if(do_after(user, 15))
to_chat(user, "You deconstruct the feeder.")
var/obj/item/stack/material/plastic/A = new /obj/item/stack/material/plastic(src.loc)
A.amount = 4
if(beaker)
beaker.loc = get_turf(src)
beaker = null
qdel(src)
return
/obj/machinery/feeder/process()
set background = 1
if(attached)
if(!(get_dist(src, attached) <= 1 && isturf(attached.loc)))
visible_message("The tube is pulled out of [attached].")
attached = null
update_icon()
return
if(attached && beaker)
// Give food
if(beaker.volume > 0)
var/transfer_amount = 2
beaker.reagents.trans_to_mob(attached, transfer_amount, CHEM_INGEST)
update_icon()
/obj/machinery/feeder/attack_hand(mob/user as mob)
if(beaker)
beaker.loc = get_turf(src)
beaker = null
update_icon()
else
return ..()
/obj/machinery/feeder/examine(mob/user)
.=..()
if(!(user in view(2)) && user != src.loc) return
if(beaker)
if(beaker.reagents && beaker.reagents.reagent_list.len)
. += "<span class='notice'>Inserted is \a [beaker] with [beaker.reagents.total_volume] units of liquid.</span>"
else
. += "<span class='notice'>Inserted is an empty [beaker].</span>"
else
. += "<span class='notice'>No container is inserted.</span>"
. += "<span class='notice'>[attached ? attached : "No one"] is being fed by it.</span>"
/obj/machinery/feeder/CanPass(atom/movable/mover, turf/target, height = 0, air_group = 0)
if(height && istype(mover) && mover.checkpass(PASSTABLE)) //allow bullets, beams, thrown objects, mice, drones, and the like through.
return 1
return ..()

File diff suppressed because it is too large Load Diff

View File

@@ -67,9 +67,14 @@
//Tanning!
for(var/obj/item/stack/hairlesshide/HH in washing)
var/obj/item/stack/wetleather/WL = new(src)
var/obj/item/stack/WL = new HH.wet_type(src)
if(istype(WL))
WL.amount = HH.amount
qdel(HH)
washing -= HH
HH.forceMove(get_turf(src))
HH.use(HH.amount)
washing += WL
if(locate(/mob,washing))
state = 7
@@ -130,7 +135,7 @@
to_chat(user, "<span class='warning'>You can't fit \the [W] inside.</span>")
return
else if(istype(W, /obj/item/clothing) || istype(W, /obj/item/weapon/bedsheet))
else if(istype(W, /obj/item/clothing) || istype(W, /obj/item/weapon/bedsheet) || istype(W, /obj/item/stack/hairlesshide))
if(washing.len < 5)
if(state in list(1, 3))
user.drop_item()

View File

@@ -21,9 +21,61 @@
/obj/item/device/starcaster_news/attack_self(mob/user as mob)
user.set_machine(src)
ui_interact(user) //Activates nanoUI. Fuck nanoUI.
tgui_interact(user) //Activates tgui. Bless tgui.
return
/obj/item/device/starcaster_news/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "StarcasterCh", name)
ui.open()
/obj/item/device/starcaster_news/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) //Mostly ripped off from news_browser.dm
var/list/data = list()
var/list/all_articles = list()
data["showing_archived"] = show_archived
data["article"] = null
if(loaded_article) // Viewing an article.
data["article"] = list(
"title" = loaded_article.filename,
"cover" = loaded_article.cover,
"content" = loaded_article.stored_data,
)
else // Viewing list of articles
for(var/datum/computer_file/data/news_article/F in ntnet_global.available_news)
if(!show_archived && F.archived)
continue
all_articles.Add(list(list(
"name" = F.filename,
"uid" = F.uid,
"archived" = F.archived
)))
data["all_articles"] = all_articles
return data
/obj/item/device/starcaster_news/tgui_act(action, list/params, datum/tgui/ui) //Also ripped from news_browser.dm. Bless tgui
if(..())
return TRUE
switch(action)
if("PRG_openarticle")
. = TRUE
if(loaded_article)
return TRUE
for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news)
if(N.uid == text2num(params["uid"]))
loaded_article = N.clone()
break
if("PRG_reset")
. = TRUE
loaded_article = null
if("PRG_toggle_archived")
. = TRUE
show_archived = !show_archived
/* Deprecated nanoUI code. Keeping mostly for reference.
/obj/item/device/starcaster_news/Topic(href, href_list) //Mostly ripped off from news_browser.dm
if(..())
return 1
@@ -73,3 +125,4 @@
ui.auto_update_layout = 1
ui.set_initial_data(data)
ui.open()
*/

View File

@@ -1,70 +1,75 @@
/obj/item/stack/animalhide
name = "hide"
desc = "The hide of some creature."
icon_state = "sheet-hide"
drop_sound = 'sound/items/drop/cloth.ogg'
pickup_sound = 'sound/items/pickup/cloth.ogg'
amount = 1
stacktype = "hide"
no_variants = TRUE
var/process_type = /obj/item/stack/hairlesshide
/obj/item/stack/animalhide/human
name = "human skin"
desc = "The by-product of human farming."
singular_name = "human skin piece"
name = "skin"
desc = "The by-product of sapient farming."
singular_name = "skin piece"
icon_state = "sheet-hide"
no_variants = FALSE
drop_sound = 'sound/items/drop/leather.ogg'
pickup_sound = 'sound/items/pickup/leather.ogg'
/obj/item/stack/animalhide/human
amount = 50
amount = 1
stacktype = "hide-human"
/obj/item/stack/animalhide/corgi
name = "corgi hide"
desc = "The by-product of corgi farming."
singular_name = "corgi hide piece"
icon_state = "sheet-corgi"
/obj/item/stack/animalhide/corgi
amount = 50
amount = 1
stacktype = "hide-corgi"
/obj/item/stack/animalhide/cat
name = "cat hide"
desc = "The by-product of cat farming."
singular_name = "cat hide piece"
icon_state = "sheet-cat"
/obj/item/stack/animalhide/cat
amount = 50
amount = 1
stacktype = "hide-cat"
/obj/item/stack/animalhide/monkey
name = "monkey hide"
desc = "The by-product of monkey farming."
singular_name = "monkey hide piece"
icon_state = "sheet-monkey"
/obj/item/stack/animalhide/monkey
amount = 50
amount = 1
stacktype = "hide-monkey"
/obj/item/stack/animalhide/lizard
name = "lizard skin"
desc = "Sssssss..."
singular_name = "lizard skin piece"
icon_state = "sheet-lizard"
/obj/item/stack/animalhide/lizard
amount = 50
amount = 1
stacktype = "hide-lizard"
/obj/item/stack/animalhide/xeno
name = "alien hide"
desc = "The skin of a terrible creature."
singular_name = "alien hide piece"
icon_state = "sheet-xeno"
/obj/item/stack/animalhide/xeno
amount = 50
amount = 1
stacktype = "hide-xeno"
//don't see anywhere else to put these, maybe together they could be used to make the xenos suit?
/obj/item/stack/xenochitin
name = "alien chitin"
desc = "A piece of the hide of a terrible creature."
singular_name = "alien hide piece"
singular_name = "alien chitin piece"
icon = 'icons/mob/alien.dmi'
icon_state = "chitin"
/obj/item/stack/xenochitin
amount = 50
amount = 1
stacktype = "hide-chitin"
/obj/item/xenos_claw
name = "alien claw"
@@ -84,9 +89,22 @@
singular_name = "hairless hide piece"
icon_state = "sheet-hairlesshide"
no_variants = FALSE
amount = 1
stacktype = "hairlesshide"
var/cleaning = FALSE // Can we be water_acted, or are we busy? To prevent accidental hide duplication and the collapse of causality.
/obj/item/stack/hairlesshide
amount = 50
var/wet_type = /obj/item/stack/wetleather
/obj/item/stack/hairlesshide/water_act(var/wateramount)
..()
cleaning = TRUE
while(amount > 0 && wateramount > 0)
use(1)
wateramount--
new wet_type(get_turf(src))
cleaning = FALSE
return
/obj/item/stack/wetleather
name = "wet leather"
@@ -96,28 +114,27 @@
var/wetness = 30 //Reduced when exposed to high temperautres
var/drying_threshold_temperature = 500 //Kelvin to start drying
no_variants = FALSE
amount = 1
stacktype = "wetleather"
/obj/item/stack/wetleather
amount = 50
var/dry_type = /obj/item/stack/material/leather
//Step one - dehairing.
/obj/item/stack/animalhide/attackby(obj/item/weapon/W as obj, mob/user as mob)
if( istype(W, /obj/item/weapon/material/knife) || \
istype(W, /obj/item/weapon/material/twohanded/fireaxe) || \
istype(W, /obj/item/weapon/material/knife/machete/hatchet) )
if(has_edge(W) || is_sharp(W))
//visible message on mobs is defined as visible_message(var/message, var/self_message, var/blind_message)
usr.visible_message("<span class='notice'>\The [usr] starts cutting hair off \the [src]</span>", "<span class='notice'>You start cutting the hair off \the [src]</span>", "You hear the sound of a knife rubbing against flesh")
if(do_after(user,50))
to_chat(usr, "<span class='notice'>You cut the hair from this [src.singular_name]</span>")
//Try locating an exisitng stack on the tile and add to there if possible
for(var/obj/item/stack/hairlesshide/HS in usr.loc)
if(HS.amount < 50)
if(HS.amount < 50 && istype(HS, process_type))
HS.amount++
src.use(1)
break
return
//If it gets to here it means it did not find a suitable stack on the tile.
var/obj/item/stack/hairlesshide/HS = new(usr.loc)
var/obj/item/stack/HS = new process_type(usr.loc)
if(istype(HS))
HS.amount = 1
src.use(1)
else
@@ -132,15 +149,20 @@
if(exposed_temperature >= drying_threshold_temperature)
wetness--
if(wetness == 0)
dry()
/obj/item/stack/wetleather/proc/dry()
//Try locating an exisitng stack on the tile and add to there if possible
for(var/obj/item/stack/material/leather/HS in src.loc)
if(HS.amount < 50)
HS.amount++
src.use(1)
wetness = initial(wetness)
break
src.use(1)
return
//If it gets to here it means it did not find a suitable stack on the tile.
var/obj/item/stack/material/leather/HS = new(src.loc)
var/obj/item/stack/HS = new dry_type(src.loc)
if(istype(HS))
HS.amount = 1
wetness = initial(wetness)
src.use(1)

View File

@@ -380,7 +380,7 @@
var/use_material
var/pass_color
New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1, time = 0, one_per_turf = 0, on_floor = 0, supplied_material = null, pass_stack_color)
/datum/stack_recipe/New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1, time = 0, one_per_turf = 0, on_floor = 0, supplied_material = null, pass_stack_color)
src.title = title
src.result_type = result_type
src.req_amount = req_amount

View File

@@ -1,9 +1,9 @@
/obj/item/weapon/implant/reagent_generator/egg
name = "egg laying implant"
name = "regular egg laying implant"
desc = "This is an implant that allows the user to lay eggs."
generated_reagents = list("egg" = 2)
usable_volume = 500
transfer_amount = 50
usable_volume = 1500
transfer_amount = 300
var/verb_descriptor = list("squeezes", "pushes", "hugs")
var/self_verb_descriptor = list("squeeze", "push", "hug")
var/short_emote_descriptor = list("lays", "forces out", "pushes out")
@@ -11,11 +11,13 @@
random_emote = list("lets out an embarrassed moan", "yelps in embarrassment", "quietly groans in a mixture of discomfort and pleasure")
assigned_proc = /mob/living/carbon/human/proc/use_reagent_implant_egg
var/eggtype = /obj/item/weapon/reagent_containers/food/snacks/egg
var/cascade
/obj/item/weapon/implant/reagent_generator/egg/post_implant(mob/living/carbon/source)
START_PROCESSING(SSobj, src)
to_chat(source, "<span class='notice'>You implant [source] with \the [src].</span>")
source.verbs |= assigned_proc
source.verbs |= /mob/living/carbon/human/proc/toggle_cascade
return 1
/mob/living/carbon/human/proc/use_reagent_implant_egg()
@@ -51,8 +53,9 @@
to_chat(usr, "<span class='notice'>It seems that [src] is out of eggs!</span>")
to_chat(src, "<span class='notice'>[pick(rimplant.empty_message)]</span>")
return
visible_message("<span class='notice'>[usr] starts squeezing [src]'s lower body firmly...</span>")
if (rimplant && do_after(usr,60))
visible_message("<span class='danger'>[usr] starts squeezing [src]'s lower body firmly...</span>")
if (rimplant && do_after(usr,120,src))
if(src.Adjacent(usr))
var/egg = rimplant.eggtype
new egg(get_turf(src))
src.SetStunned(3)
@@ -73,37 +76,59 @@
visible_message("<span class='notice'>[src] [pick(rimplant.random_emote)].</span>")
rimplant.reagents.remove_any(rimplant.transfer_amount)
if(prob(70*rimplant.reagents.total_volume/rimplant.usable_volume))
if(rimplant.cascade)
to_chat(src, "<span class='notice'>You feel your legs quake as your muscles fail to stand strong!</span>")
while(rimplant.reagents.total_volume >= rimplant.transfer_amount)
if(do_after(src,30))
src.SetStunned(5)
src.SetStunned(3)
playsound(src,'sound/vore/insert.ogg',50,1)
src.apply_effect(10,STUTTER,0)
new egg(get_turf(src))
rimplant.reagents.remove_any(rimplant.transfer_amount)
if(prob(25))
visible_message("<span class='notice'>[src] [pick(rimplant.random_emote)].</span>")
else
return
/mob/living/carbon/human/proc/toggle_cascade()
set name = "Toggle cascading"
set desc = "Toggle whether or not being forced to lay an egg will cause you to lay all others as well, in rapid succession"
set category = "Local"
var/obj/item/weapon/implant/reagent_generator/egg/rimplant
for(var/obj/item/organ/external/E in organs)
for(var/obj/item/weapon/implant/I in E.implants)
if(istype(I, /obj/item/weapon/implant/reagent_generator))
rimplant = I
break
if(rimplant.cascade)
rimplant.cascade = 0
to_chat(src, "<span class='notice'>You toggle cascading off</span>")
else
rimplant.cascade = 1
to_chat(src, "<span class='notice'>You toggle cascading on</span>")
/obj/item/weapon/implant/reagent_generator/egg/slow
name = "slow egg laying implant"
usable_volume = 3000
transfer_amount = 300
transfer_amount = 600
/obj/item/weapon/implant/reagent_generator/egg/veryslow
name = "very slow egg laying implant"
usable_volume = 6000
transfer_amount = 600
transfer_amount = 1200
/obj/item/weapon/implant/reagent_generator/egg/hicap
name = "high capacity egg laying implant" // Note that the capacity does not affect the regeneration rate, rather, the transfer amount does
usable_volume = 1000 // Effectively, the transfer_amount is the cost/time of making an egg. Usable volume is simply the max number of eggs.
transfer_amount = 50
usable_volume = 3000 // Effectively, the transfer_amount is the cost/time of making an egg. Usable volume is simply the max number of eggs.
transfer_amount = 300
/obj/item/weapon/implant/reagent_generator/egg/doublehicap
name = "extreme capacity egg laying implant"
usable_volume = 2000
transfer_amount = 50
usable_volume = 6000
transfer_amount = 300
/obj/item/weapon/implant/reagent_generator/egg/slowlowcap
name = "slow, low capacity egg laying implant"

View File

@@ -68,7 +68,7 @@
item_state = "candlebox5"
throwforce = 2
slot_flags = SLOT_BELT
max_storage_space = ITEMSIZE_COST_SMALL * 5
max_storage_space = ITEMSIZE_COST_TINY * 5 //CHOMPEdit
starts_with = list(/obj/item/weapon/flame/candle = 5)
/obj/item/weapon/storage/fancy/whitecandle_box
@@ -80,7 +80,7 @@
item_state = "whitecandlebox5"
throwforce = 2
slot_flags = SLOT_BELT
max_storage_space = ITEMSIZE_COST_SMALL * 5
max_storage_space = ITEMSIZE_COST_TINY * 5 //CHOMPEdit
starts_with = list(/obj/item/weapon/flame/candle/white = 5)
/obj/item/weapon/storage/fancy/blackcandle_box
@@ -92,7 +92,7 @@
item_state = "blackcandlebox5"
throwforce = 2
slot_flags = SLOT_BELT
max_storage_space = ITEMSIZE_COST_SMALL * 5
max_storage_space = ITEMSIZE_COST_TINY * 5 //CHOMPEdit
starts_with = list(/obj/item/weapon/flame/candle/black = 5)

View File

@@ -0,0 +1,7 @@
/obj/item/weapon/storage/fancy/cigar/cohiba
name = "cohiban cigar case"
starts_with = list(/obj/item/clothing/mask/smokable/cigarette/cigar/cohiba = 7)
/obj/item/weapon/storage/fancy/cigar/havana
name = "havanian cigar case"
starts_with = list(/obj/item/clothing/mask/smokable/cigarette/cigar/havana = 7)

View File

@@ -349,6 +349,8 @@
to_chat(user, "<span class='danger'>You go blind!</span>")
user.Blind(5)
user.eye_blurry = 5
// Don't cure being nearsighted
if(!(H.disabilities & NEARSIGHTED))
user.disabilities |= NEARSIGHTED
spawn(100)
user.disabilities &= ~NEARSIGHTED

View File

@@ -0,0 +1,96 @@
//Try not to question it too hard. These are the spicy tools.
/obj/item/weapon/tool/crowbar/heavysniper
name = "anti-materiel sniper crowbar"
desc = "This abomination or piece of art, depending on how you view it, seems to use a 14.5mm anti-materiel sniper rifle to the same effect of a crowbar."
icon = 'icons/obj/gun.dmi'
icon_state = "heavysniper"
item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_guns.dmi',slot_r_hand_str = 'icons/mob/items/righthand_guns.dmi')
item_state = "heavysniper"
toolspeed = 0.1
force = 30
usesound = 'sound/weapons/Gunshot_cannon.ogg'
/obj/item/weapon/weldingtool/lasercannon
name = "laser cannon welding tool"
desc = "This abomination or piece of art, depending on how you view it, seems to be a laser cannon converted into a welding tool."
icon = 'icons/obj/gun.dmi'
icon_state = "lasercannon"
item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_guns.dmi',slot_r_hand_str = 'icons/mob/items/righthand_guns.dmi')
item_state = "mhdhowitzer-wielded"
toolspeed = 0.1
usesound = 'sound/weapons/lasercannonfire.ogg'
acti_sound = 'sound/weapons/kenetic_reload.ogg'
always_process = TRUE
/obj/item/weapon/weldingtool/lasercannon/process()
if(get_fuel() <= get_max_fuel())
reagents.add_reagent("fuel", 1)
..()
/obj/item/weapon/weldingtool/lasercannon/update_icon()
// Lights
if(welding && flame_intensity)
set_light(flame_intensity, flame_intensity, flame_color)
else
set_light(0)
// icon_state = welding ? "[icon_state]1" : "[initial(icon_state)]"
var/mob/M = loc
if(istype(M))
M.update_inv_l_hand()
M.update_inv_r_hand()
/obj/item/weapon/tool/wrench/fuelrod
name = "fuel-rod cannon wrench"
desc = "This abomination or piece of art, depending on how you view it, seems to by some means use a fuel rod cannon as a wrench... how this is possible, one can only theorize."
icon = 'icons/obj/railgun.dmi'
icon_state = "fuelrodgun"
item_icons = list(slot_l_hand_str = 'icons/mob/items/lefthand_guns.dmi',slot_r_hand_str = 'icons/mob/items/righthand_guns.dmi')
item_state = "coilgun"
usesound = 'sound/weapons/railgun.ogg'
toolspeed = 0.1
force = 30
/obj/item/weapon/tool/wirecutters/chainsaw
name = "chainsaw wirecutters"
desc = "This abomination or piece of art, depending on how you view it, seems to be a chainsaw that is by some means converted into wirecutters."
icon = 'icons/obj/weapons.dmi'
icon_state = "chainsaw0"
item_state = "chainsaw0"
usesound = 'sound/weapons/chainsaw_attack.ogg'
random_color = FALSE
toolspeed = 0.1
force = 30
/obj/item/weapon/tool/screwdriver/diamonddrill
name = "diamond drill power screwdriver"
desc = "This abomination or piece of art, depending on how you view it, seems to be a diamond drill that was converted into a power screwdriver."
icon = 'icons/obj/items.dmi'
icon_state = "diamonddrill"
item_state = "jackhammer"
hitsound = 'sound/items/drill_hit.ogg'
usesound = 'sound/items/drill_use.ogg'
random_color = FALSE
toolspeed = 0.1
force = 30
/obj/item/stack/cable_coil/alien/blood
name = "Blood cable coil"
desc = "This seems to be a blood red cable coil which magically replenishes itself, and if you look closely at the insulation you can read the words \"forged from the blood of our enemies\""
icon = 'icons/obj/power.dmi'
icon_state = "coil"
item_state = "coil"
color = "#8A0303"
catalogue_data = null
toolspeed = 0.1
/obj/item/weapon/storage/belt/utility/spicyfull
starts_with = list(
/obj/item/weapon/tool/crowbar/heavysniper,
/obj/item/weapon/weldingtool/lasercannon,
/obj/item/weapon/tool/wrench/fuelrod,
/obj/item/weapon/tool/wirecutters/chainsaw,
/obj/item/weapon/tool/screwdriver/diamonddrill,
/obj/item/stack/cable_coil/alien/blood
)

View File

@@ -0,0 +1,230 @@
/obj/kbutton
name = "button"
icon = 'icons/obj/objects.dmi'
icon_state = "launcherbtt"
desc = "A remote control switch for something."
anchored = 1.0
var/nothing_sound_file //Sound to play when button fails to be pressed
var/nothing_sound_volume //Volume of sound when button fails to be pressed
var/pressed_sound_file = 'sound/machines/button.ogg'//Sound to play when button is successfully pressed
var/pressed_sound_volume = 100 //Volume of sound when button is successfully pressed
var/list/trig_target_paths = list() //What are the paths of whatever we want to call our proc on?
var/trig_target_trigger_uid //What is the trigger_uid of whatever we want to call our proc on?
var/trig_proc //What proc do we want to call?
var/list/trig_args = list() //What are the arguments for said proc?
var/trig_message = "You press the button" //Should we send a message to the person who pressed the button?
var/trig_message_span_class = "notice" //Span class used for pressed message, normal ones include notice, warning, and danger.
var/nothing_message = "Nothing happens." //Should we send a message if nothing happens when the button is pressed?
var/nothing_message_span_class = "warning" //Span class used for nothing message, normal ones include notice, warning, and danger.
var/list/trig_targets = list()
var/trig_target_is_trigerrer = FALSE //Should we use the button presser as the target?
/obj/kbutton/attackby(obj/item/weapon/W, mob/user as mob)
return attack_hand(user)
/obj/kbutton/attack_hand(mob/user as mob)
. = ..()
if(can_press(user))
if(trig_target_is_trigerrer)
trig_targets = list(user)
button_trigger()
if(pressed_sound_file)
playsound(src, pressed_sound_file, pressed_sound_volume, 1)
if(trig_message)
to_chat(user,"<span class='[trig_message_span_class]'>"+trig_message+"</span>")
else
if(nothing_sound_file)
playsound(src, nothing_sound_file, nothing_sound_volume, 1)
if(nothing_message)
to_chat(user,"<span class='[nothing_message_span_class]'>"+nothing_message+"</span>")
return
/obj/kbutton/proc/button_trigger()
if(trig_proc)
if(trig_targets.len)
var/testname = trig_proc
//Find one of the 3 possible ways they could have written /proc/PROCNAME
if(findtext(trig_proc, "/proc/"))
testname = replacetext(trig_proc, "/proc/", "")
else if(findtext(trig_proc, "/proc"))
testname = replacetext(trig_proc, "/proc", "")
else if(findtext(trig_proc, "proc/"))
testname = replacetext(trig_proc, "proc/", "")
//Clear out any parenthesis if they're a dummy
testname = replacetext(testname, "()", "")
for(var/trig_target in trig_targets)
if(trig_target && !hascall(trig_target,testname))
message_admins("TRIGGER ERROR: ONE OR MORE TRIGGER TARGETS LACKS THE MENTIONED PROC")
return
for(var/trig_target in trig_targets)
call(trig_target,testname)(arglist(trig_args))
else
var/procpath = text2path(trig_proc)
if(!procpath)
message_admins("TRIGGER ERROR: INVALID PROC")
return
call(procpath)(arglist(trig_args))
/obj/kbutton/proc/can_press(mob/user)
return TRUE
/obj/kbutton/proc/update_trig_targets()
trig_targets = list()
for(var/path in trig_target_paths)
var/trig_target_path = text2path(path)
if(trig_target_path && trig_target_trigger_uid)
var/list/candidates = get_all_of_type(trig_target_path)
for(var/candidate in candidates)
var/datum/cand_datum = candidate
if(istype(cand_datum))
if(cand_datum.trigger_uid == trig_target_trigger_uid)
trig_targets += candidate
continue
continue
if(!trig_targets.len)
message_admins("TRIGGER ERROR: trig_targets STILL EMPTY AFTER CALLED update_trig_targets()")
/obj/kbutton/Initialize(mapload)
. = ..()
update_trig_targets()
return
/obj/kbutton/single_use
name = "single use button"
var/has_been_pressed = FALSE
/obj/kbutton/single_use/button_trigger()
has_been_pressed = TRUE
..()
/obj/kbutton/single_use/can_press(mob/user)
return !has_been_pressed
/obj/kbutton/single_use_per_mob
name = "button"
var/list/been_triggered_by = list()
/obj/kbutton/single_use_per_mob/can_press(mob/user)
if(user in been_triggered_by)
return FALSE
else
been_triggered_by |= user
return TRUE
/obj/kbutton/toggle
name = "toggle button"
var/toggled = FALSE
//For each of the following, each of the following variables will be used when switching to that state,
//and if it's set to null, it will use def(short for default)
var/trig_message_types = list(\
"def" = "You toggle the button.", \
"on" = null, \
"off" = null)
var/nothing_message_types = list(\
"def" = "Nothing happens.", \
"on" = null, \
"off" = null)
var/pressed_sound_file_types = list(\
"def" = 'sound/machines/button.ogg', \
"on" = null, \
"off" = null)
var/pressed_sound_volume_types = list(\
"def" = 100, \
"on" = null, \
"off" = null)
var/nothing_sound_file_types = list(\
"def" = null, \
"on" = null, \
"off" = null)
var/nothing_sound_volume_types = list(\
"def" = null, \
"on" = null, \
"off" = null)
var/icon_types = list(\
"def" = 'icons/obj/objects.dmi', \
"on" = null, \
"off" = null)
var/icon_state_types = list(\
"def" = "launcherbtt", \
"on" = null, \
"off" = null)
var/trig_proc_types = list(\
"def" = null, \
"on" = null, \
"off" = null)
var/trig_args_types = list(\
"def" = list(), \
"on" = list(), \
"off" = list())
/obj/kbutton/toggle/Initialize(mapload)
. = ..()
update_variables()
/obj/kbutton/toggle/proc/update_variables()
var/index = toggled ? "on" : "off"
trig_message = trig_message_types[index] ? trig_message_types[index] : trig_message_types["def"]
nothing_message = nothing_message_types[index] ? nothing_message_types[index] : nothing_message_types["def"]
pressed_sound_file = pressed_sound_file_types[index] ? pressed_sound_file_types[index] : pressed_sound_file_types["def"]
pressed_sound_volume = pressed_sound_volume_types[index] ? pressed_sound_volume_types[index] : pressed_sound_volume_types["def"]
nothing_sound_file = nothing_sound_file_types[index] ? nothing_sound_file_types[index] : nothing_sound_file_types["def"]
nothing_sound_volume = nothing_sound_volume_types[index] ? nothing_sound_volume_types[index] : nothing_sound_volume_types["def"]
icon = icon_types[index] ? icon_types[index] : icon_types["def"]
icon_state = icon_state_types[index] ? icon_state_types[index] : icon_state_types["def"]
trig_proc = trig_proc_types[index] ? trig_proc_types[index] : trig_proc_types["def"]
trig_args = trig_args_types[index].len ? trig_args_types[index] : trig_args_types["def"]
/obj/kbutton/toggle/button_trigger()
toggled = !toggled
update_variables()
..()
//An example button which opens and closes a closet.
/obj/kbutton/toggle/example
var/press_wait_time = 25
var/last_pressed = 0
trig_target_paths = list("/obj/structure/closet")
trig_target_trigger_uid = 97482
trig_message_types = list(\
"def" = "You toggle the button.", \
"on" = "You switch the button on.", \
"off" = "You switch the button off.")
nothing_message_types = list(\
"def" = "Nothing happens.", \
"on" = "You fail to switch the button off.", \
"off" = "You fail to switch the button on.")
pressed_sound_file_types = list(\
"def" = 'sound/machines/button.ogg', \
"on" = 'sound/machines/chime.ogg', \
"off" = 'sound/machines/buttonbeep.ogg')
pressed_sound_volume_types = list(\
"def" = 80, \
"on" = 80, \
"off" = 80)
nothing_sound_file_types = list(\
"def" = 'sound/machines/buzz-sigh.ogg', \
"on" = 'sound/machines/buzz-sigh.ogg', \
"off" = 'sound/machines/buzz-two.ogg')
nothing_sound_volume_types = list(\
"def" = 100, \
"on" = 100, \
"off" = 100)
icon_state_types = list(\
"def" = "launcherbtt", \
"on" = "launcheract", \
"off" = "launcherbtt")
trig_proc_types = list(\
"def" = "close", \
"on" = "open", \
"off" = "close")
/obj/kbutton/toggle/example/can_press(mob/user)
if(world.time > last_pressed + press_wait_time)
last_pressed = world.time
return TRUE
else
return FALSE
//Corresponding closet for example button
/obj/structure/closet/button_example
trigger_uid = 97482

View File

@@ -250,6 +250,16 @@
removed.add_thermal_energy(heat_transfer)
for(var/mob/living/L in view(3, src))
L.add_modifier(/datum/modifier/endothermic, 10 SECONDS, null, TRUE)
for(var/obj/item/stack/wetleather/WL in view(2, src))
if(WL.wetness >= 0)
WL.dry()
continue
WL.wetness = max(0, WL.wetness - rand(1, 4))
env.merge(removed)
/obj/structure/bonfire/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)

View File

@@ -494,3 +494,47 @@
/obj/structure/flora/sif/tendrils/get_harvestable_desc()
return "<span class='notice'>\The [src] seems to be growing over something.</span>"
/datum/category_item/catalogue/flora/frostbelle
name = "Sivian Flora - Frostbelle"
desc = "A rare plant native to Sif, with very peculiar growing requirements. Rarely seen outside of their original habitat,\
or the homes of the wealthy, the plant's unique vein structure is actually used to carry the plant's reproductive material \
to forming buds, the petals of which secrete the luminescent sap containing the pollen at the time of blooming. Certain \
horticulturists have found ways of halting this process prior to the secretion of the sap, leaving the flower's petals \
bright, at the cost of making that bud sterile."
value = CATALOGUER_REWARD_HARD
/obj/structure/flora/sif/frostbelle
name = "gnarly shrub"
desc = "A stocky plant with fins bearing luminescent veins along its branches."
icon_state = "grass"
randomize_size = TRUE
catalogue_data = list(/datum/category_item/catalogue/flora/frostbelle)
harvest_tool = /obj/item/weapon/material/knife
max_harvests = 2
min_harvests = -4
harvest_loot = list(
/obj/item/weapon/reagent_containers/food/snacks/frostbelle = 1
)
var/variantnum = null
/obj/structure/flora/sif/frostbelle/Initialize()
. = ..()
variantnum = rand(1,3)
update_icon()
/obj/structure/flora/sif/frostbelle/update_icon()
..()
if(max_harvests > 0 && harvest_count < max_harvests)
icon_state = "[initial(icon_state)][variantnum]"
else
icon_state = initial(icon_state)
/obj/structure/flora/sif/frostbelle/get_harvestable_desc()
return "<span class='notice'>\The [src] seems to be budding.</span>"

View File

@@ -0,0 +1,313 @@
/obj/structure/reflector
name = "reflector base"
icon = 'icons/obj/tgs_structures_ch.dmi'
icon_state = "reflector_map"
desc = "A base for reflector assemblies."
anchored = FALSE
density = FALSE
var/deflector_icon_state
var/image/deflector_overlay
var/finished = FALSE
var/admin = FALSE //Can't be rotated or deconstructed
var/can_rotate = TRUE
var/framebuildstacktype = /obj/item/stack/material//metal
var/framebuildstackamount = 5
var/buildstacktype = /obj/item/stack/material//metal
var/buildstackamount = 0
var/fires_projectile = /obj/item/projectile/beam/emitter
var/fires_accuracy = 10000
var/fires_dispersion = 0
var/list/allowed_projectile_typecache = list(/obj/item/projectile/beam)
var/rotation_angle = -1
var/can_decon = TRUE
var/list/has_projectiles = list()
var/bullet_act_in_progress = FALSE
/obj/structure/reflector/Initialize()
. = ..()
icon_state = "reflector_base"
allowed_projectile_typecache = typecacheof(allowed_projectile_typecache)
if(deflector_icon_state)
deflector_overlay = image(icon, deflector_icon_state)
add_overlay(deflector_overlay)
if(rotation_angle == -1)
setAngle(dir2angle(dir))
else
setAngle(rotation_angle)
if(admin)
can_rotate = FALSE
SSreflector.processing += src
/obj/structure/reflector/examine(mob/user)
. = ..()
if(finished)
. += "It is set to [rotation_angle] degrees, and the rotation is [can_rotate ? "unlocked" : "locked"]."
if(!admin)
if(can_rotate)
. += "<span class='notice'>Alt-click to adjust its direction.</span>"
else
. += "<span class='notice'>Use screwdriver to unlock the rotation.</span>"
/obj/structure/reflector/proc/Fire()
UNTIL(!bullet_act_in_progress)
var/list/angles = list()
for(var/obj/item/projectile/P in has_projectiles)
angles[num2text(has_projectiles[P])] += P.damage
for(var/angle in angles)
var/obj/item/projectile/P = new fires_projectile(src)
P.firer = src
P.damage = angles[angle]
P.accuracy = 350
P.dispersion = 0
P.fire(text2num(angle))
has_projectiles = list()
/obj/structure/reflector/proc/setAngle(new_angle)
if(can_rotate)
rotation_angle = new_angle
if(deflector_overlay)
cut_overlay(deflector_overlay)
deflector_overlay.transform = turn(matrix(), new_angle)
add_overlay(deflector_overlay)
/obj/structure/reflector/proc/redirect_projectile(obj/item/projectile/P,pangle)
has_projectiles[P] = pangle
qdel(P)
/obj/structure/reflector/set_dir(new_dir)
return ..(NORTH)
/obj/structure/reflector/Crossed(atom/movable/AM) //Ok so this is my solution to garbage projectile code. Please god let this work.
if(istype(AM,/obj/item/projectile))
AM.Bump(src)
/obj/structure/reflector/bullet_act(obj/item/projectile/P)
bullet_act_in_progress = TRUE
var/pdir = P.dir
var/pangle = P.Angle
var/ploc = get_turf(P)
if(!finished || !allowed_projectile_typecache[P.type] || !(P.dir in cardinal))
return ..()
if(auto_reflect(P, pdir, ploc, pangle) != 2)
return ..()
bullet_act_in_progress = FALSE
/obj/structure/reflector/proc/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
P.ignore_source_check = TRUE
return 2
/obj/structure/reflector/attackby(obj/item/W, mob/user, params)
if(admin)
return
if(W.is_screwdriver())
can_rotate = !can_rotate
to_chat(user, "<span class='notice'>You [can_rotate ? "unlock" : "lock"] [src]'s rotation.</span>")
playsound(W, W.usesound, 50, 1)
return
if(W.is_wrench() && can_decon)
if(anchored)
to_chat(user, "<span class='warning'>Unweld [src] from the floor first!</span>")
return
user.visible_message("<span class='notice'>[user] starts to dismantle [src].</span>", "<span class='notice'>You start to dismantle [src]...</span>")
to_chat(user, "<span class='notice'>You dismantle [src].</span>")
new framebuildstacktype(drop_location(), framebuildstackamount)
if(buildstackamount)
new buildstacktype(drop_location(), buildstackamount)
qdel(src)
else if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/I = W
if(!anchored)
if(!I.remove_fuel(1,user))
return
user.visible_message("<span class='notice'>[user] starts to weld [src] to the floor.</span>",
"<span class='notice'>You start to weld [src] to the floor...</span>",
"<span class='hear'>You hear welding.</span>")
anchored = TRUE
to_chat(user, "<span class='notice'>You weld [src] to the floor.</span>")
else
if(!I.remove_fuel(1,user))
return
user.visible_message("<span class='notice'>[user] starts to cut [src] free from the floor.</span>",
"<span class='notice'>You start to cut [src] free from the floor...</span>",
"<span class='hear'>You hear welding.</span>")
anchored = FALSE
to_chat(user, "<span class='notice'>You cut [src] free from the floor.</span>")
//Finishing the frame
else if(istype(W, /obj/item/stack/material))
if(finished)
return
var/obj/item/stack/material/S = W
if(istype(S, /obj/item/stack/material/glass))
if(S.use(5))
new /obj/structure/reflector/single(drop_location())
qdel(src)
else
to_chat(user, "<span class='warning'>You need five sheets of glass to create a reflector!</span>")
return
if(istype(S, /obj/item/stack/material/glass/reinforced))
if(S.use(10))
new /obj/structure/reflector/double(drop_location())
qdel(src)
else
to_chat(user, "<span class='warning'>You need ten sheets of reinforced glass to create a double reflector!</span>")
return
if(istype(S, /obj/item/stack/material/diamond))
if(S.use(1))
new /obj/structure/reflector/box(drop_location())
qdel(src)
else
return ..()
/obj/structure/reflector/proc/rotate(mob/user)
if (!can_rotate || admin)
to_chat(user, "<span class='warning'>The rotation is locked!</span>")
return FALSE
var/new_angle = input(user, "Input a new angle for primary reflection face.", "Reflector Angle", rotation_angle) as null|num
if(!CanUseTopic(user))
return
if(!isnull(new_angle))
setAngle(SIMPLIFY_DEGREES(new_angle))
return TRUE
/obj/structure/reflector/AltClick(mob/user)
if(!CanUseTopic(user))
return
else if(finished)
rotate(user)
//TYPES OF REFLECTORS, SINGLE, DOUBLE, BOX
//SINGLE
/obj/structure/reflector/single
name = "reflector"
deflector_icon_state = "reflector"
desc = "An angled mirror for reflecting laser beams."
density = TRUE
finished = TRUE
buildstacktype = /obj/item/stack/material//glass
buildstackamount = 5
/obj/structure/reflector/single/anchored
anchored = TRUE
/obj/structure/reflector/single/mapping
admin = TRUE
anchored = TRUE
/obj/structure/reflector/single/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
var/incidence = GET_ANGLE_OF_INCIDENCE(rotation_angle, (P.Angle + 180))
if(abs(incidence) > 90 && abs(incidence) < 270)
return FALSE
var/new_angle = SIMPLIFY_DEGREES(rotation_angle + incidence)
redirect_projectile(P,new_angle)
return ..()
//DOUBLE
/obj/structure/reflector/double
name = "double sided reflector"
deflector_icon_state = "reflector_double"
desc = "A double sided angled mirror for reflecting laser beams."
density = TRUE
finished = TRUE
buildstacktype = /obj/item/stack/material/glass/reinforced
buildstackamount = 10
/obj/structure/reflector/double/anchored
anchored = TRUE
/obj/structure/reflector/double/mapping
admin = TRUE
anchored = TRUE
/obj/structure/reflector/double/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
var/incidence = GET_ANGLE_OF_INCIDENCE(rotation_angle, (P.Angle + 180))
var/new_angle = SIMPLIFY_DEGREES(rotation_angle + incidence)
redirect_projectile(P,new_angle)
return ..()
//BOX
/obj/structure/reflector/box
name = "reflector box"
deflector_icon_state = "reflector_box"
desc = "A box with an internal set of mirrors that reflects all laser beams in a single direction."
density = TRUE
finished = TRUE
buildstacktype = /obj/item/stack/material/diamond
buildstackamount = 1
/obj/structure/reflector/box/Fire() //Since they all end up at the same angle, this should save a tad bit of processing power and memory <3
UNTIL(!bullet_act_in_progress)
var/total_damage = 0
for(var/obj/item/projectile/P in has_projectiles)
total_damage += P.damage
if(total_damage)
var/obj/item/projectile/P = new fires_projectile(src)
P.firer = src
P.damage = total_damage
P.accuracy = 350
P.dispersion = 0
P.fire(rotation_angle)
has_projectiles = list()
/obj/structure/reflector/box/anchored
anchored = TRUE
/obj/structure/reflector/box/mapping
admin = TRUE
anchored = TRUE
/obj/structure/reflector/box/auto_reflect(obj/item/projectile/P)
redirect_projectile(P,rotation_angle)
return ..()
/obj/structure/reflector/ex_act()
if(admin)
return
else
return ..()
/obj/structure/reflector/singularity_act()
if(admin)
return
else
return ..()
/obj/structure/reflector/box/orderable
name = "NanoTrasen reflector box"
desc = "A box with an internal set of mirrors that reflects all laser beams in a single direction. This one is marked with NanoTrasen's logo."
can_decon = FALSE
/datum/material/steel/generate_recipes()
..()
recipes += new/datum/stack_recipe("reflector frame", /obj/structure/reflector, 5, time = 25, one_per_turf = TRUE, on_floor = TRUE)
/datum/supply_pack/eng/reflector
name = "Reflector crate"
cost = 35
containername = "Reflector crate"
containertype = /obj/structure/closet/crate/secure/einstein
contains = list(/obj/structure/reflector/box/orderable = 3)
//Below is mostly mapping stuff for the spicy storage I added to house these new reflectors ;p
/area/engineering/secret_storage
name = "Engineering Secret Storage"
/obj/machinery/portable_atmospherics/canister
var/dont_burst = FALSE
/obj/machinery/portable_atmospherics/canister/phoron/cold/New()
src.air_contents.temperature = 2.72
..()

View File

@@ -3,7 +3,7 @@ GLOBAL_VAR(trader_loaded)
/proc/consider_trader_load()
if(!GLOB.trader_loaded)
GLOB.trader_loaded = TRUE
var/datum/map_template/MT = SSmapping.map_templates["Special Area - Trader"]
var/datum/map_template/MT = SSmapping.map_templates["Special Area - Salamander Trader"] //was: "Special Area - Trader"
if(!istype(MT))
error("Trader is not a valid map template!")
else

View File

@@ -147,6 +147,8 @@
if(M.slip("the [floor_type] floor", slip_stun))
for(var/i = 1 to slip_dist)
if(M.slip_vore_in_progress) //CHOMPEdit
break //CHOMPEdit
step(M, M.dir)
sleep(1)
else

View File

@@ -90,5 +90,10 @@ var/list/grass_types = list(
icon_state = "grass_sif_dark0"
edge_blending_priority = 5
tree_chance = 4
grass_chance = 0
grass_chance = 1
grass_types = list(
/obj/structure/flora/sif/frostbelle = 1,
/obj/structure/flora/sif/eyes = 5,
/obj/structure/flora/sif/tendrils = 30
)

View File

@@ -0,0 +1,88 @@
/turf/simulated
var/triggers = FALSE
var/list/potential_triggerers = list() //What can set off our trigger?
var/list/trig_target_paths = list() //What are the paths of whatever we want to call our proc on?
var/trig_target_trigger_uid //What is the trigger_uid of whatever we want to call our proc on?
var/trig_proc //What proc do we want to call?
var/list/trig_args = list() //What are the arguments for said proc?
var/trig_message //Should we send a message to the person who stepped here?
var/message_span_class = "notice" //If we're gonna send them a message, what span class to use?
var/trig_single_use = FALSE //Is this only a single use trigger, or can it be used multiple times?
var/has_been_used = FALSE //Has this trigger been set off yet?
var/list/trig_targets = list() //This is set automatically if the other target vars are set.
var/list/been_triggered_by = list() //Who has set this off so far?
var/trig_single_use_per_triggerer = FALSE //Do we want to make so each atom can only trigger this once?
var/trig_target_is_trigerrer = FALSE //Do we want to use the atom that trigerred us as the target?
/turf/simulated/proc/can_use_trigger(atom/movable/mover)
if(trig_single_use && has_been_used)
return FALSE
if(trig_single_use_per_triggerer && (mover in been_triggered_by))
return FALSE
if(!potential_triggerers.len)
return TRUE
else
for(var/path in potential_triggerers)
if(istype(mover,text2path(trim(path))))
return TRUE
else
continue
return FALSE
/turf/simulated/Entered(atom/movable/mover, atom/oldloc)
. = ..()
if(triggers && can_use_trigger(mover))
if(trig_proc)
if(trig_target_is_trigerrer)
trig_targets = list(mover)
if(trig_targets.len)
var/testname = trig_proc
//Find one of the 3 possible ways they could have written /proc/PROCNAME
if(findtext(trig_proc, "/proc/"))
testname = replacetext(trig_proc, "/proc/", "")
else if(findtext(trig_proc, "/proc"))
testname = replacetext(trig_proc, "/proc", "")
else if(findtext(trig_proc, "proc/"))
testname = replacetext(trig_proc, "proc/", "")
//Clear out any parenthesis if they're a dummy
testname = replacetext(testname, "()", "")
for(var/trig_target in trig_targets)
if(trig_target && !hascall(trig_target,testname))
message_admins("TRIGGER ERROR: ONE OR MORE TRIGGER TARGETS LACKS THE MENTIONED PROC")
return
for(var/trig_target in trig_targets)
call(trig_target,testname)(arglist(trig_args))
else
var/procpath = text2path(trig_proc)
if(!procpath)
message_admins("TRIGGER ERROR: INVALID PROC")
return
call(procpath)(arglist(trig_args))
if(trig_message)
to_chat(mover,"<span class='[message_span_class]'>"+trig_message+"</span>")
has_been_used = TRUE
been_triggered_by |= mover
else
return
/turf/simulated/proc/update_trig_targets()
trig_targets = list()
for(var/path in trig_target_paths)
var/trig_target_path = text2path(path)
if(trig_target_path && trig_target_trigger_uid)
var/list/candidates = get_all_of_type(trig_target_path)
for(var/candidate in candidates)
var/datum/cand_datum = candidate
if(istype(cand_datum))
if(cand_datum.trigger_uid == trig_target_trigger_uid)
trig_targets += candidate
continue
continue
if(!trig_targets.len)
message_admins("TRIGGER ERROR: trig_targets STILL EMPTY AFTER CALLED update_trig_targets()")
/turf/simulated/Initialize(mapload)
. = ..()
if(triggers)
update_trig_targets()

View File

@@ -5,7 +5,7 @@
var/input_NIF
if(!check_rights(R_ADMIN|R_EVENT|R_DEBUG)) //CHOMPStation Edit TFF 24/4/19: Allow Devs to use Quick-NIF verb.
if(!check_rights(R_ADMIN|R_EVENT|R_DEBUG|R_MOD)) //CHOMPStation Edit TFF 24/4/19: Allow Devs to use Quick-NIF verb. 11/9/20: Also allow mods :3
return
var/mob/living/carbon/human/H = input("Pick a mob with a player","Quick NIF") as null|anything in player_list

View File

@@ -0,0 +1,11 @@
/datum/gear/cigar_case
display_name = "cigar case"
path = /obj/item/weapon/storage/fancy/cigar
/datum/gear/cigar_case/New()
..()
var/list/cigars = list()
for(var/cigar in (typesof(/obj/item/weapon/storage/fancy/cigar)))
var/obj/item/weapon/storage/fancy/cigar/cigar_brand = cigar
cigars[initial(cigar_brand.name)] = cigar_brand
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(cigars))

View File

@@ -614,3 +614,34 @@
display_name = "disheveled suit"
path = /obj/item/clothing/under/disheveled
/datum/gear/uniform/orangedress
display_name = "orange dress"
path = /obj/item/clothing/under/dress/dress_orange
/datum/gear/uniform/sundress_pink
display_name = "pink sundress"
path = /obj/item/clothing/under/dress/sundress_pink
/datum/gear/uniform/sundress_white
display_name = "white sundress"
path = /obj/item/clothing/under/dress/sundress_white
/datum/gear/uniform/sundress_pinkbow
display_name = "bowed pink sundress"
path = /obj/item/clothing/under/dress/sundress_pinkbow
/datum/gear/uniform/sundress_blue
display_name = "long blue sundress"
path = /obj/item/clothing/under/dress/sundress_blue
/datum/gear/uniform/sundress_pinkshort
display_name = "short pink sundress"
path = /obj/item/clothing/under/dress/sundress_pinkshort
/datum/gear/uniform/twopiece
display_name = "two-piece dress"
path = /obj/item/clothing/under/dress/twopiece
/datum/gear/uniform/gothic2
display_name = "lacey gothic dress"
path = /obj/item/clothing/under/dress/gothic2

View File

@@ -184,9 +184,12 @@
return TOPIC_REFRESH
else if(href_list["clicked_pos_trait"])
var/traitpath = text2path(href_list["clicked_pos_trait"]) //CHOMPEdit
var/datum/trait/trait = text2path(href_list["clicked_pos_trait"])
var/choice = alert("Remove [initial(trait.name)] and regain [initial(trait.cost)] points?","Remove Trait","Remove","Cancel")
if(choice == "Remove")
if(traitpath == /datum/trait/linguist) //CHOMPEdit
pref.num_languages = 0 //CHOMPEdit
pref.pos_traits -= trait
return TOPIC_REFRESH
@@ -287,7 +290,8 @@
alert("You cannot take this trait and [conflict] at the same time. \
Please remove that trait, or pick another trait to add.","Error")
return TOPIC_REFRESH
if(path==/datum/trait/linguist) //CHOMPEdit
pref.num_languages = 12 //CHOMPEdit
mylist += path
return TOPIC_REFRESH

View File

@@ -159,6 +159,12 @@
icon_state = "scrubsnavyblue"
item_state_slots = list(slot_r_hand_str = "blue", slot_l_hand_str = "blue")
/obj/item/clothing/under/rank/medical/scrubs/white
name = "scrubs"
desc = "It's made of a special fiber that provides minor protection against biohazards"
icon_state = "scrubs"
item_state_slots = list(slot_r_hand_str = "white", slot_l_hand_str = "white")
/obj/item/clothing/under/rank/psych
desc = "A basic white jumpsuit. It has turqouise markings that denote the wearer as a psychiatrist."
name = "psychiatrist's jumpsuit"

View File

@@ -621,7 +621,7 @@ Uniforms and such
*/
/obj/item/clothing/under/sundress
name = "sundress"
name = "flowery white sundress"
desc = "Makes you want to frolic in a field of daisies."
icon_state = "sundress"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
@@ -632,6 +632,47 @@ Uniforms and such
icon_state = "sundress_white"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/sundress_pink
name = "pink stripied sundress"
desc = "A cute pink sundress."
icon_state = "pinksun"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/sundress_white
name = "white sundress"
desc = "A white sundress, it's short."
icon_state = "whitesun"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/sundress_pinkbow
name = "bowed pink sundress"
desc = "A cute pink sundress with a bow."
icon_state = "bowsun"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/sundress_blue
name = "long blue sundress"
desc = "A long blue sun dress with white frills towards the bottom."
icon_state = "bluesun"
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS
/obj/item/clothing/under/dress/sundress_pinkshort
name = "short pink sundress"
desc = "A very short pink sundress, it's more like a chemise."
icon_state = "shortpink"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/twopiece
name = "two-piece dress"
desc = "A fancy two-piece dress, the pieces are sewn together."
icon_state = "twopiece"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/gothic2
name = "lacey gothic dress"
desc = "An elegant gothic dress with lace decorations."
icon_state = "gothic2"
/obj/item/clothing/under/captainformal
name = "site manager's formal uniform"
desc = "A Site Manager's formal-wear, for special occasions."

View File

@@ -7,7 +7,7 @@
// 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)
if(!C.destroyed && (C.z in using_map.station_levels) && C.air_contents.total_moles >= MOLES_CELLSTANDARD && !C.dont_burst) //CHOMPEdit
all_canisters += C
for(var/i in 1 to 10)

View File

@@ -73,7 +73,7 @@
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Carp School", /datum/event/carp_migration, -20, list(ASSIGNMENT_ENGINEER = 10, ASSIGNMENT_SECURITY = 30, ASSIGNMENT_HOS = 10, ASSIGNMENT_WARDEN = 5), 1),
// Just disables comms for a short while.
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Communication Blackout", /datum/event/communications_blackout, 500, list(ASSIGNMENT_AI = 150, ASSIGNMENT_SECURITY = 120), 1),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Drone Pod Drop", /datum/event/drone_pod_drop, 10, list(ASSIGNMENT_SCIENTIST = 40), 1),
// Just blows out a few lights
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Electrical Storm", /datum/event/electrical_storm, 250, list(ASSIGNMENT_ENGINEER = 20, ASSIGNMENT_JANITOR = 150), 1),
//Escaped slime event itself needs to be rejiggered because of the mob refactor.
@@ -102,6 +102,8 @@
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Meteor Shower", /datum/event/meteor_wave, 30, list(ASSIGNMENT_ENGINEER = 20)),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Random Antagonist", /datum/event/random_antag, 2.5, list(ASSIGNMENT_SECURITY = 1), 1, 0, 5),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Carp School", /datum/event/carp_migration, 0, list(ASSIGNMENT_SECURITY = 30), 1),
//Commenting this event out, the pod is not mapped in.
//new /datum/event_meta(EVENT_LEVEL_MODERATE, "Drone Pod Drop", /datum/event/drone_pod_drop, 10, list(ASSIGNMENT_SCIENTIST = 40), 1),
//Spacedust doesn't work, commenting this out.
//new /datum/event_meta(EVENT_LEVEL_MODERATE, "Space Dust", /datum/event/dust, 0, list(ASSIGNMENT_ENGINEER = 20), 1, 0, 50),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Maintenance Predator", /datum/event/maintenance_predator, 75, list(ASSIGNMENT_SECURITY = 25, ASSIGNMENT_SCIENTIST = 10), 1),
@@ -120,6 +122,7 @@
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, -100, list(ASSIGNMENT_SECURITY = 40, ASSIGNMENT_HOS = 10, ASSIGNMENT_WARDEN = 10, ASSIGNMENT_ENGINEER = 5), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Carp Migration", /datum/event/carp_migration, -110, list(ASSIGNMENT_SECURITY = 50, ASSIGNMENT_HOS = 10, ASSIGNMENT_WARDEN = 10), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Containment Breach", /datum/event/prison_break/station,0, list(ASSIGNMENT_ANY = 5), 0),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Drone Pod Drop", /datum/event/drone_pod_drop, 10, list(ASSIGNMENT_SCIENTIST = 40), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Meteor Wave", /datum/event/meteor_wave, -110, list(ASSIGNMENT_ENGINEER = 50), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Space Vines", /datum/event/spacevine, 20, list(ASSIGNMENT_ENGINEER = 15), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Viral Infection", /datum/event/viral_infection, -50, list(ASSIGNMENT_MEDICAL = 25), 1),

View File

@@ -4039,6 +4039,40 @@
/obj/item/weapon/reagent_containers/food/snacks/rawsunflower/Initialize()
. = ..()
/obj/item/weapon/reagent_containers/food/snacks/frostbelle
name = "frostbelle bud"
desc = "A frostbelle flower from Sif. Its petals shimmer with an inner light."
icon = 'icons/obj/food_ingredients.dmi'
icon_state = "frostbelle"
bitesize = 1
nutriment_amt = 1
nutriment_desc = list("another world" = 2)
catalogue_data = list(/datum/category_item/catalogue/flora/frostbelle)
filling_color = "#5dadcf"
/obj/item/weapon/reagent_containers/food/snacks/frostbelle/Initialize()
. = ..()
set_light(1, 1, "#5dadcf")
reagents.add_reagent("oxycodone", 1)
reagents.add_reagent("sifsap", 5)
reagents.add_reagent("space_drugs", 5)
/obj/item/weapon/reagent_containers/food/snacks/bellefritter
name = "frostbelle fritters"
desc = "Frostbelles, prepared traditionally."
icon = 'icons/obj/food_syn.dmi'
icon_state = "bellefritter"
filling_color = "#5dadcf"
center_of_mass = list("x"=16, "y"=12)
do_coating_prefix = 0
/obj/item/weapon/reagent_containers/food/snacks/bellefritter/Initialize()
. = ..()
reagents.add_reagent("batter", 10)
reagents.add_reagent("sugar", 5)
bitesize = 2
/obj/item/weapon/reagent_containers/food/snacks/roastedsunflower
name = "sunflower seeds"
desc = "Sunflower seeds!"

View File

@@ -192,3 +192,60 @@
..()
reagents.add_reagent("tealeavesgreen", 6)
bitesize = 1
/obj/item/weapon/reagent_containers/food/snacks/butterscotch
name = "Butterscotch"
desc = "A sweet, golden-brown liquid, usually used as part of confectionary. Just a spoonful wouldn't hurt, right?"
icon = 'icons/obj/food_ch.dmi'
icon_state = "butterscotch" //Sprite by Dinnel
nutriment_amt = 1
nutriment_desc = list("sickly sweet deliciousness" = 1)
/obj/item/weapon/reagent_containers/food/snacks/butterscotch/Initialize()
..()
bitesize = 1
/obj/item/weapon/reagent_containers/food/snacks/slicable/buttspie
name = "Butterscotch-Cinnamon Pie"
desc = "A delightfully caramel-coloured filling in a crispy pie base, dotted with sprays of cream."
icon = 'icons/obj/food_ch.dmi'
icon_state = "butts_pie" //Sprite by Dinnel
slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/buttspie
slices_num = 6
nutriment_amt = 12
nutriment_desc = list("a warm, buttery sweetness that reminds you of home" = 5)
center_of_mass = list("x"=16, "y"=9)
/obj/item/weapon/reagent_containers/food/snacks/slicable/buttspie/Initialize()
..()
bitesize = 4
/obj/item/weapon/reagent_containers/food/snacks/slice/buttspie //TODO: Fix the numbers.
name = "Slice of Butterscotch-Cinnamon Pie"
desc = "A slice of pie, filled with delightfully caramel-coloured filling. There a spray of cream on top."
icon = 'icons/obj/food_ch.dmi'
icon_state = "butts_pie_slice" //Sprite by Dinnel
trash = /obj/item/trash/plate
whole_path = /obj/item/weapon/reagent_containers/food/snacks/slicable/buttspie
/obj/item/weapon/reagent_containers/food/snacks/slice/buttspie/Initialize()
..()
bitesize = 2
/obj/item/weapon/reagent_containers/food/snacks/spicy_boys //These are off-brand red hots/atomic fireballs
name = "Spicy Boys"
desc = "Spicy little candy rounds for very naughty individuals."
icon = 'icons/obj/food_ch.dmi'
icon_state = "spicy_boys" //Sprite by Dinnel
nutriment_amt = 1 //todo - change numbers
nutriment_desc = list("a sweet, candy-like spiciness." = 2) //WIP flavour??
/obj/item/weapon/reagent_containers/food/snacks/cinnamonroll
name = "cinnamon roll"
desc = "A precious little cinnamon roll, just begging to be eaten."
icon = 'icons/obj/food_ch.dmi'
icon_state = "cinnamon_roll" //Sprite by Dinnel
nutriment_amt = 1 //Todo - Change numbers.
nutriment_desc = list("a precious sweetness that needs protecting" = 2) //This is a WIP flavour, Could keep it if you don't mind the "gotta protect the precious cinnamon roll" joke
//TODO: Maybe butterscotch candies?

View File

@@ -188,18 +188,13 @@
update_icon()
var/slab_name = occupant.name
var/slab_count = 3
var/slab_type = /obj/item/weapon/reagent_containers/food/snacks/meat
var/slab_count = 2 + occupant.meat_amount
var/slab_type = occupant.meat_type ? occupant.meat_type : /obj/item/weapon/reagent_containers/food/snacks/meat
var/slab_nutrition = src.occupant.nutrition / 15
// Some mobs have specific meat item types.
if(istype(src.occupant,/mob/living/simple_mob))
var/mob/living/simple_mob/critter = src.occupant
if(critter.meat_amount)
slab_count = critter.meat_amount
if(critter.meat_type)
slab_type = critter.meat_type
else if(istype(src.occupant,/mob/living/carbon/human))
var/list/byproducts = occupant?.butchery_loot?.Copy()
if(istype(src.occupant,/mob/living/carbon/human))
var/mob/living/carbon/human/H = occupant
slab_name = src.occupant.real_name
slab_type = H.isSynthetic() ? /obj/item/stack/material/steel : H.species.meat_type
@@ -209,7 +204,8 @@
slab_nutrition *= 0.5
slab_nutrition /= slab_count
for(var/i=1 to slab_count)
while(slab_count)
slab_count--
var/obj/item/weapon/reagent_containers/food/snacks/meat/new_meat = new slab_type(src, rand(3,8))
if(istype(new_meat))
new_meat.name = "[slab_name] [new_meat.name]"
@@ -222,16 +218,25 @@
src.occupant.ghostize()
spawn(gib_time)
operating = 0
occupant.gib()
occupant = null
playsound(src, 'sound/effects/splat.ogg', 50, 1)
operating = 0
if(LAZYLEN(byproducts))
for(var/path in byproducts)
while(byproducts[path])
if(prob(min(90,30 * byproducts[path])))
new path(src)
byproducts[path] -= 1
for (var/obj/thing in contents)
// There's a chance that the gibber will fail to destroy some evidence.
// There's a chance that the gibber will fail to destroy or butcher some evidence.
if(istype(thing,/obj/item/organ) && prob(80))
var/obj/item/organ/OR = thing
if(OR.can_butcher(src))
OR.butcher(src, null, src) // Butcher it, and add it to our list of things to launch.
else
qdel(thing)
continue
thing.forceMove(get_turf(thing)) // Drop it onto the turf for throwing.

View File

@@ -137,6 +137,10 @@
var/obj/item/weapon/reagent_containers/food/snacks/S = O
if (S.dried_type)
return 1
if(istype(O, /obj/item/stack/wetleather))
return 1
return 0
/obj/machinery/smartfridge/drying_rack/process()
@@ -180,6 +184,17 @@
new D(get_turf(src))
qdel(S)
return
for(var/obj/item/stack/wetleather/WL in I.instances)
if(!WL.wetness)
if(WL.amount == 1)
WL.forceMove(get_turf(src))
I.instances -= WL
WL.dry()
break
WL.wetness = max(0, WL.wetness - rand(1, 3))
return
/obj/machinery/smartfridge/process()

View File

@@ -27,6 +27,11 @@
reagent_mix = RECIPE_REAGENT_REPLACE //Simplify end product
result = /obj/item/weapon/reagent_containers/food/snacks/risottoballs
/datum/recipe/bellefritter
appliance = FRYER
reagents = list("sugar" = 5, "batter" = 10)
items = list(/obj/item/weapon/reagent_containers/food/snacks/frostbelle)
result = /obj/item/weapon/reagent_containers/food/snacks/bellefritter
//Meaty Recipes
//====================

View File

@@ -97,3 +97,12 @@
/obj/item/weapon/reagent_containers/food/snacks/steamrolltealeaf
)
result = /obj/item/weapon/reagent_containers/food/snacks/greentealeaf
/datum/recipe/butterscotch
reagents = list("sugar" = 10, "cream" = 5)
reagent_mix = RECIPE_REAGENT_REPLACE //No actual reagents since it's meant to be a cooking item
items = list(
/obj/item/weapon/reagent_containers/food/snacks/spreads/butter
)
result = /obj/item/weapon/reagent_containers/food/snacks/butterscotch
result_quantity = 2

View File

@@ -0,0 +1,23 @@
/datum/recipe/buttspie
appliance = OVEN
reagents = list("cinnamonpowder" = 10)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/butterscotch,
/obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough
)
result = /obj/item/weapon/reagent_containers/food/snacks/slicable/buttspie
/datum/recipe/cinnamon_roll
appliance = OVEN
reagents = list("cinnamonpowder" = 5, "sugar" = 10)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/spreads/butter
)
result = /obj/item/weapon/reagent_containers/food/snacks/cinnamonroll
/datum/recipe/spicy_boys
appliance = OVEN
reagents = list("cinnamonpowder" = 5, "sugar" = 10, "cornoil" = 10)
result = /obj/item/weapon/reagent_containers/food/snacks/spicy_boys
result_quantity = 6

View File

@@ -201,3 +201,22 @@
set_trait(TRAIT_IDEAL_HEAT, 283)
set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0)
set_trait(TRAIT_WATER_CONSUMPTION, 0)
/datum/seed/cinnamon //WIP - I have no idea what I'm doing with growables in code right now.
name = "cinnamon"
seed_name = "cinnamon"
display_name = "cinnamon tree"
chems = list("cinnamonpowder" = list(5,25))
mutants = null
kitchen_tag = "cinnamon"
/datum/seed/cinnamon/New()
..()
set_trait(TRAIT_HARVEST_REPEAT,1)
set_trait(TRAIT_MATURATION,6)
set_trait(TRAIT_PRODUCTION,6)
set_trait(TRAIT_YIELD,5)
set_trait(TRAIT_POTENCY,10)
set_trait(TRAIT_PRODUCT_ICON, "stalk")
set_trait(TRAIT_PRODUCT_COLOUR, "#FF9A85")
set_trait(TRAIT_PLANT_ICON,"tree2")

View File

@@ -2,5 +2,9 @@
/obj/item/seeds/teaseed
seed_type = "tea"
/obj/item/seeds/cinnamon
seed_type = "cinnamon"
/obj/item/seeds/pitcherseed
seed_type = "pitcher plant"

View File

@@ -77,12 +77,16 @@
update_lighting()
/obj/item/integrated_circuit/output/light/proc/update_lighting()
//CHOMPEdit Begin
if(assembly)
var/atom/light_source = assembly
if(istype(assembly,/obj/item/device/electronic_assembly/clothing))
light_source = assembly.loc
if(light_toggled)
if(assembly)
assembly.set_light(l_range = light_brightness, l_power = light_brightness, l_color = light_rgb)
light_source.set_light(l_range = light_brightness, l_power = light_brightness, l_color = light_rgb)
else
if(assembly)
assembly.set_light(0)
light_source.set_light(0)
//CHOMPEdit End
power_draw_idle = light_toggled ? light_brightness * light_brightness : 0 // Should be the same draw as regular lights.
/obj/item/integrated_circuit/output/light/power_fail() // Turns off the flashlight if there's no power left.

View File

@@ -140,6 +140,7 @@
recipes += new/datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS)
recipes += new/datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("Feeder", /obj/machinery/feeder, 4, time = 20, one_per_turf = 1, on_floor = 1) //CHOMP Addition
/datum/material/wood/generate_recipes()
..()
@@ -248,3 +249,24 @@
recipes += new/datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] membrane", /obj/effect/alien/resin/membrane, 1, time = 2 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] node", /obj/effect/alien/weeds/node, 1, time = 4 SECONDS)
/datum/material/leather/generate_recipes()
recipes = list()
recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)

View File

@@ -444,7 +444,18 @@
name = "leather"
desc = "The by-product of mob grinding."
icon_state = "sheet-leather"
default_type = "leather"
default_type = MAT_LEATHER
no_variants = FALSE
pass_color = TRUE
strict_color_stacking = TRUE
drop_sound = 'sound/items/drop/leather.ogg'
pickup_sound = 'sound/items/pickup/leather.ogg'
/obj/item/stack/material/chitin
name = "chitin"
desc = "The by-product of mob grinding."
icon_state = "chitin"
default_type = MAT_CHITIN
no_variants = FALSE
pass_color = TRUE
strict_color_stacking = TRUE

View File

@@ -922,7 +922,7 @@ var/list/name_to_material
sheet_singular_name = null
sheet_plural_name = "pile"
pass_stack_colors = TRUE
supply_conversion_value = 3 //YW Adds: logs worth points
supply_conversion_value = 1
/datum/material/wood/log/sif
name = MAT_SIFLOG
@@ -1008,6 +1008,7 @@ var/list/name_to_material
flags = MATERIAL_PADDING
conductive = 0
pass_stack_colors = TRUE
supply_conversion_value = 2
/datum/material/cult
name = "cult"
@@ -1033,16 +1034,32 @@ var/list/name_to_material
/datum/material/cult/reinf/place_dismantled_product(var/turf/target)
new /obj/effect/decal/remains/human(target)
/datum/material/chitin
name = MAT_CHITIN
icon_colour = "#8d6653"
stack_type = /obj/item/stack/material/chitin
stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4)
icon_base = "solid"
icon_reinf = "reinf_mesh"
integrity = 60
ignition_point = T0C+400
melting_point = T0C+500
protectiveness = 25
conductive = 0
supply_conversion_value = 4
//TODO PLACEHOLDERS:
/datum/material/leather
name = "leather"
name = MAT_LEATHER
icon_colour = "#5C4831"
stack_origin_tech = list(TECH_MATERIAL = 2)
stack_type = /obj/item/stack/material/leather
stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
flags = MATERIAL_PADDING
ignition_point = T0C+300
melting_point = T0C+300
protectiveness = 3 // 13%
conductive = 0
supply_conversion_value = 3
//CHOMPstation Removal Start: Moved to materials_ch and changed to allow for material var
/*

View File

@@ -0,0 +1,66 @@
/mob/living
var/meat_amount = 0 // How much meat to drop from this mob when butchered
var/obj/meat_type // The meat object to drop
var/gib_on_butchery = FALSE
var/list/butchery_loot // Associated list, path = number.
// Harvest an animal's delicious byproducts
/mob/living/proc/harvest(var/mob/user, var/obj/item/I)
if(meat_type && meat_amount>0 && (stat == DEAD))
while(meat_amount > 0 && do_after(user, 0.5 SECONDS * (mob_size / 10), src))
var/obj/item/meat = new meat_type(get_turf(src))
meat.name = "[src.name] [meat.name]"
new /obj/effect/decal/cleanable/blood/splatter(get_turf(src))
meat_amount--
if(!meat_amount)
handle_butcher(user, I)
/mob/living/proc/can_butcher(var/mob/user, var/obj/item/I) // Override for special butchering checks.
if(((meat_type && meat_amount) || LAZYLEN(butchery_loot)) && stat == DEAD)
return TRUE
return FALSE
/mob/living/proc/handle_butcher(var/mob/user, var/obj/item/I)
if(!user || do_after(user, 2 SECONDS * mob_size / 10, src))
if(LAZYLEN(butchery_loot))
if(LAZYLEN(butchery_loot))
for(var/path in butchery_loot)
while(butchery_loot[path])
butchery_loot[path] -= 1
var/obj/item/loot = new path(get_turf(src))
loot.pixel_x = rand(-12, 12)
loot.pixel_y = rand(-12, 12)
butchery_loot.Cut()
butchery_loot = null
if(LAZYLEN(organs))
organs_by_name.Cut()
for(var/obj/item/organ/OR in organs)
OR.removed()
organs -= OR
if(LAZYLEN(internal_organs))
internal_organs_by_name.Cut()
for(var/obj/item/organ/OR in internal_organs)
OR.removed()
internal_organs -= OR
if(!ckey)
if(issmall(src))
user?.visible_message("<span class='danger'>[user] chops up \the [src]!</span>")
new /obj/effect/decal/cleanable/blood/splatter(get_turf(src))
if(gib_on_butchery)
qdel(src)
else
user?.visible_message("<span class='danger'>[user] butchers \the [src] messily!</span>")
if(gib_on_butchery)
gib()

View File

@@ -1,4 +1,4 @@
/mob/living/carbon/
/mob/living/carbon
gender = MALE
var/datum/species/species //Contains icon generation and language information, set during New().
var/list/stomach_contents = list()

View File

@@ -283,3 +283,11 @@
message = "hides their wings."
visible_message("[src] [message]")
// Chomp Edit Start
/mob/living/carbon/human/verb/hide_nutrition_vr()
set name = "Show/Hide Nutrition Levels"
set category = "IC"
set desc = "Allow other player to see your current nutrition level or not."
nutrition_hidden = !nutrition_hidden
to_chat(src, "Players will [nutrition_hidden ? "no longer" : "now"] see your nutrition levels.")
// Chomp Edit End

View File

@@ -68,6 +68,8 @@
/mob/living/carbon/human/proc/examine_nutrition()
if(!show_pudge()) //Some clothing or equipment can hide this.
return ""
if(nutrition_hidden) // Chomp Edit
return ""
var/message = ""
var/nutrition_examine = round(nutrition)
var/t_He = "It" //capitalised for use at the start of each line.

View File

@@ -1,3 +1,6 @@
/mob/living/carbon/human
var/datum/unarmed_attack/default_attack
/mob/living/carbon/human/proc/get_unarmed_attack(var/mob/living/carbon/human/target, var/hit_zone)
// VOREStation Edit - Begin
if(nif && nif.flag_check(NIF_C_HARDCLAWS,NIF_FLAGS_COMBAT)){return unarmed_hardclaws}
@@ -16,6 +19,12 @@
if(soft_type)
return soft_type
return G.special_attack
if(src.default_attack && src.default_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
var/datum/unarmed_attack/soft_type = src.default_attack.get_sparring_variant()
if(soft_type)
return soft_type
return src.default_attack
for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks)
if(u_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
@@ -434,3 +443,37 @@
user.visible_message("\The [user] stops applying pressure to [src]'s [organ.name]!", "You stop applying pressure to [src]'s [organ.name]!")
return TRUE
/mob/living/carbon/human/verb/check_attacks()
set name = "Check Attacks"
set category = "IC"
set src = usr
var/dat = "<b><font size = 5>Known Attacks</font></b><br/><br/>"
if(default_attack)
dat += "Current default attack: [default_attack.attack_name] - <a href='byond://?src=\ref[src];default_attk=reset_attk'>reset</a><br/><br/>"
for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks)
if(u_attack == default_attack)
dat += "<b>Primarily [u_attack.attack_name]</b> - default - <a href='byond://?src=\ref[src];default_attk=reset_attk'>reset</a><br/><br/><br/>"
else
dat += "<b>Primarily [u_attack.attack_name]</b> - <a href='byond://?src=\ref[src];default_attk=\ref[u_attack]'>set default</a><br/><br/><br/>"
src << browse(dat, "window=checkattack")
/mob/living/carbon/human/Topic(href, href_list)
if(href_list["default_attk"])
if(href_list["default_attk"] == "reset_attk")
set_default_attack(null)
else
var/datum/unarmed_attack/u_attack = locate(href_list["default_attk"])
if(u_attack && (u_attack in species.unarmed_attacks))
set_default_attack(u_attack)
check_attacks()
return 1
else
return ..()
/mob/living/carbon/human/proc/set_default_attack(var/datum/unarmed_attack/u_attack)
default_attack = u_attack

View File

@@ -439,13 +439,14 @@ This function restores all organs.
return 0
return
/*
/mob/living/carbon/human/proc/get_organ(var/zone)
if(!zone)
zone = BP_TORSO
else if (zone in list( O_EYES, O_MOUTH ))
zone = BP_HEAD
return organs_by_name[zone]
*/
/mob/living/carbon/human/apply_damage(var/damage = 0, var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/soaked = 0, var/sharp = 0, var/edge = 0, var/obj/used_weapon = null)
if(Debug2)

View File

@@ -44,7 +44,7 @@
var/age = 30 //Player's age (pure fluff)
var/b_type = "A+" //Player's bloodtype
var/datum/robolimb/synthetic //If they are a synthetic (aka synthetic torso)
var/datum/robolimb/synthetic //If they are a synthetic (aka synthetic torso). Also holds the datum for the type of robolimb.
var/list/all_underwear = list()
var/list/all_underwear_metadata = list()
@@ -85,7 +85,6 @@
var/special_voice = "" // For changing our voice. Used by a symptom.
var/last_dam = -1 //Used for determining if we need to process all organs or just some or even none.
var/list/bad_external_organs = list()// organs we check until they are good.
var/xylophone = 0 //For the spoooooooky xylophone cooldown
@@ -118,3 +117,4 @@
var/obj/machinery/machine_visual //machine that is currently applying visual effects to this mob. Only used for camera monitors currently.
inventory_panel_type = /datum/inventory_panel/human
butchery_loot = list(/obj/item/stack/animalhide/human = 1)

View File

@@ -10,6 +10,7 @@
var/ability_flags = 0 //Shadekin abilities/potentially other species-based?
var/sensorpref = 5 //Suit sensor loadout pref
var/wings_hidden = FALSE
var/nutrition_hidden = FALSE // Chomp Edit
/mob/living/carbon/human/proc/shadekin_get_energy()
var/datum/species/shadekin/SK = species

View File

@@ -5,6 +5,7 @@
update_icons_body() //Body handles eyes
update_eyes() //For floating eyes only
/*
/mob/living/carbon/var/list/internal_organs = list()
/mob/living/carbon/human/var/list/organs = list()
/mob/living/carbon/human/var/list/organs_by_name = list() // map organ names to organs
@@ -13,6 +14,7 @@
/mob/living/carbon/human/proc/get_bodypart_name(var/zone)
var/obj/item/organ/external/E = get_organ(zone)
if(E) . = E.name
*/
/mob/living/carbon/human/proc/recheck_bad_external_organs()
var/damage_this_tick = getToxLoss()

View File

@@ -1,4 +1,5 @@
/datum/unarmed_attack/bite/sharp //eye teeth
attack_name = "sharp bite"
attack_verb = list("bit", "chomped on")
attack_sound = 'sound/weapons/bite.ogg'
shredding = 0
@@ -6,12 +7,14 @@
edge = 1
/datum/unarmed_attack/diona
attack_name = "tendrils"
attack_verb = list("lashed", "bludgeoned")
attack_noun = list("tendril")
eye_attack_text = "a tendril"
eye_attack_text_victim = "a tendril"
/datum/unarmed_attack/claws
attack_name = "claws"
attack_verb = list("scratched", "clawed", "slashed")
attack_noun = list("claws")
eye_attack_text = "claws"
@@ -54,6 +57,7 @@
if(5) user.visible_message("<span class='danger'>[user] tears [T.his] [pick(attack_noun)] [pick("deep into", "into", "across")] [target]'s [affecting.name]!</span>")
/datum/unarmed_attack/claws/strong
attack_name = "strong claws"
attack_verb = list("slashed")
damage = 5
shredding = 1
@@ -67,6 +71,7 @@
damage = 15
/datum/unarmed_attack/bite/strong
attack_name = "strong bite"
attack_verb = list("mauled")
damage = 8
shredding = 1
@@ -75,6 +80,7 @@
damage = 10
/datum/unarmed_attack/slime_glomp
attack_name = "glomp"
attack_verb = list("glomped")
attack_noun = list("body")
damage = 2
@@ -84,6 +90,7 @@
user.apply_stored_shock_to(target)
/datum/unarmed_attack/stomp/weak
attack_name = "weak stomp"
attack_verb = list("jumped on")
/datum/unarmed_attack/stomp/weak/get_unarmed_damage()

View File

@@ -142,8 +142,8 @@
)
unarmed_types = list(
/datum/unarmed_attack/bite/sharp,
/datum/unarmed_attack/claws,
/datum/unarmed_attack/bite/sharp,
/datum/unarmed_attack/stomp/weak
)

View File

@@ -30,11 +30,10 @@
excludes = list(/datum/trait/lonely)
/datum/trait/lonely/proc/check_mob_company(var/mob/living/carbon/human/H,var/mob/living/M)
if(only_people && !istype(M, /mob/living/carbon) && !istype(M, /mob/living/silicon/robot))
return 0
if(M == H || M.stat == DEAD || M.invisibility > H.see_invisible)
return 0
if(only_people && !M.ckey)
var/social_check = only_people && !istype(M, /mob/living/carbon) && !istype(M, /mob/living/silicon/robot)
var/self_dead_invisible_check = M == H || M.stat == DEAD || M.invisibility > H.see_invisible
var/ckey_check = only_people && !M.ckey
if(social_check || self_dead_invisible_check || ckey_check)
return 0
if(M.faction == "neutral" || M.faction == H.faction)
if(H.loneliness_stage > 0)
@@ -71,9 +70,13 @@
H.loneliness_stage -= 4
return
// Check for company.
for(var/mob/living/M in viewers(H))
for(var/mob/living/M in H.contents)
if(istype(M) && check_mob_company(H,M))
return
for(var/mob/living/M in viewers(get_turf(H)))
if(check_mob_company(H,M))
return
//Check to see if there's anyone in our belly
if(H.vore_organs)
for(var/obj/belly/B in H.vore_organs)
for(var/mob/living/content in B.contents)

View File

@@ -34,4 +34,4 @@
desc = "Your body is able to produce nutrition from being in light."
cost = 3
var_changes = list("photosynthesizing" = TRUE)
not_for_synths = 1 //Synths don't use nutrition.
not_for_synths = 0 //Synths actually use nutrition, just with a fancy covering.

View File

@@ -2,6 +2,7 @@ var/global/list/sparring_attack_cache = list()
//Species unarmed attacks
/datum/unarmed_attack
var/attack_name = "fist"
var/attack_verb = list("attack") // Empty hand hurt intent verb.
var/attack_noun = list("fist")
var/damage = 0 // Extra empty hand attack damage.
@@ -109,6 +110,7 @@ var/global/list/sparring_attack_cache = list()
return FALSE //return true if the unarmed override prevents further attacks
/datum/unarmed_attack/bite
attack_name = "bite"
attack_verb = list("bit")
attack_sound = 'sound/weapons/bite.ogg'
shredding = 0
@@ -127,6 +129,7 @@ var/global/list/sparring_attack_cache = list()
return TRUE
/datum/unarmed_attack/punch
attack_name = "punch"
attack_verb = list("punched")
attack_noun = list("fist")
eye_attack_text = "fingers"
@@ -181,6 +184,7 @@ var/global/list/sparring_attack_cache = list()
user.visible_message("<span class='danger'>[user] [pick("punched", "threw a punch against", "struck", "slammed [TU.his] [pick(attack_noun)] into")] [target]'s [organ]!</span>") //why do we have a separate set of verbs for lying targets?
/datum/unarmed_attack/kick
attack_name = "kick"
attack_verb = list("kicked", "kicked", "kicked", "kneed")
attack_noun = list("kick", "kick", "kick", "knee strike")
attack_sound = "swing_hit"
@@ -224,6 +228,7 @@ var/global/list/sparring_attack_cache = list()
if(5) user.visible_message("<span class='danger'>[user] landed a strong [pick(attack_noun)] against [target]'s [organ]!</span>")
/datum/unarmed_attack/stomp
attack_name = "stomp"
attack_verb = null
attack_noun = list("stomp")
attack_sound = "swing_hit"
@@ -269,6 +274,7 @@ var/global/list/sparring_attack_cache = list()
if(5) user.visible_message("<span class='danger'>[pick("[user] landed a powerful stomp on", "[user] stomped down hard on", "[user] slammed [TU.his] [shoes ? copytext(shoes.name, 1, -1) : "foot"] down hard onto")] [target]'s [organ]!</span>") //Devastated lol. No. We want to say that the stomp was powerful or forceful, not that it /wrought devastation/
/datum/unarmed_attack/light_strike
attack_name = "light hit"
attack_noun = list("tap","light strike")
attack_verb = list("tapped", "lightly struck")
damage = 3

View File

@@ -31,9 +31,25 @@
nest = null
if(buckled)
buckled.unbuckle_mob(src, TRUE)
qdel(selected_image)
QDEL_NULL(vorePanel) //VOREStation Add
QDEL_LIST_NULL(vore_organs) //VOREStation Add
if(LAZYLEN(organs))
organs_by_name.Cut()
while(organs.len)
var/obj/item/OR = organs[1]
organs -= OR
qdel(OR)
if(LAZYLEN(internal_organs))
internal_organs_by_name.Cut()
while(internal_organs.len)
var/obj/item/OR = internal_organs[1]
internal_organs -= OR
qdel(OR)
return ..()
//mob verbs are faster than object verbs. See mob/verb/examine.
@@ -924,6 +940,12 @@ default behaviour is:
/mob/living/Moved(var/atom/oldloc, direct, forced, movetime)
. = ..()
handle_footstep(loc)
// Begin VOREstation edit
if(is_shifted)
is_shifted = FALSE
pixel_x = 0
pixel_y = 0
// End VOREstation edit
if(pulling) // we were pulling a thing and didn't lose it during our move.
var/pull_dir = get_dir(src, pulling)

View File

@@ -0,0 +1,28 @@
/mob/living
var/list/internal_organs = list()
var/list/organs = list()
var/list/organs_by_name = list() // map organ names to organs
var/list/internal_organs_by_name = list() // so internal organs have less ickiness too
var/list/bad_external_organs = list()// organs we check until they are good.
/mob/living/proc/get_bodypart_name(var/zone)
var/obj/item/organ/external/E = get_organ(zone)
if(E) . = E.name
/mob/living/proc/get_organ(var/zone)
if(!zone)
zone = BP_TORSO
else if (zone in list( O_EYES, O_MOUTH ))
zone = BP_HEAD
return organs_by_name[zone]
/mob/living/gib()
for(var/obj/item/organ/I in internal_organs)
I.removed()
if(isturf(I?.loc)) // Some organs qdel themselves or other things when removed
I.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),30)
for(var/obj/item/organ/external/E in src.organs)
E.droplimb(0,DROPLIMB_EDGE,1)
..()

View File

@@ -145,6 +145,7 @@
name = "MediHound hypospray"
desc = "An advanced chemical synthesizer and injection system utilizing carrier's reserves, designed for heavy-duty medical equipment."
charge_cost = 10
reagent_ids = list("inaprovaline", "dexalin", "bicaridine", "kelotane", "anti_toxin", "spaceacillin", "paracetamol")
var/datum/matter_synth/water = null
/obj/item/weapon/reagent_containers/borghypo/hound/process() //Recharges in smaller steps and uses the water reserves as well.

View File

@@ -39,6 +39,7 @@
var/datum/matter_synth/water = null
var/digest_brute = 2
var/digest_burn = 3
var/digest_multiplier = 1
var/recycles = FALSE
var/medsensor = TRUE //Does belly sprite come with patient ok/dead light?
@@ -541,8 +542,8 @@
else
var/old_brute = T.getBruteLoss()
var/old_burn = T.getFireLoss()
T.adjustBruteLoss(digest_brute)
T.adjustFireLoss(digest_burn)
T.adjustBruteLoss(digest_brute * digest_multiplier)
T.adjustFireLoss(digest_burn * digest_multiplier)
var/actual_brute = T.getBruteLoss() - old_brute
var/actual_burn = T.getFireLoss() - old_burn
var/damage_gain = actual_brute + actual_burn
@@ -717,6 +718,7 @@
icon_state = "sleeperc"
injection_chems = list("glucose","inaprovaline","tricordrazine")
max_item_count = 1
/obj/item/device/dogborg/sleeper/command //Command borg belly // CH addition
name = "Bluespace Filing Belly"
desc = "A mounted bluespace storage unit for carrying paperwork"

View File

@@ -71,6 +71,5 @@
/mob/living/simple_mob/proc/remove_eyes()
cut_overlay(eye_layer)
/mob/living/simple_mob/gib()
..(icon_gib,1,icon) // we need to specify where the gib animation is stored

View File

@@ -0,0 +1,8 @@
/mob/living/simple_mob
gib_on_butchery = TRUE
/mob/living/simple_mob/can_butcher(var/mob/user, var/obj/item/I) // Override for special butchering checks.
. = ..()
if(. && (!is_sharp(I) || !has_edge(I)))
return FALSE

View File

@@ -68,9 +68,9 @@
else
var/datum/gender/T = gender_datums[src.get_visible_gender()]
to_chat(user, "<span class='notice'>\The [src] is dead, medical items won't bring [T.him] back to life.</span>") // the gender lookup is somewhat overkill, but it functions identically to the obsolete gender macros and future-proofs this code
if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead.
if(istype(O, /obj/item/weapon/material/knife))
harvest(user)
if(can_butcher(user, O)) //if the animal can be butchered, do so and return. It's likely to be gibbed.
harvest(user, O)
return
if(user.a_intent == I_HELP && harvest_tool && istype(O, harvest_tool) && stat != DEAD)
if(world.time > (harvest_recent + harvest_cooldown))

View File

@@ -17,7 +17,7 @@
/mob/living/simple_mob/examine(mob/user)
. = ..()
if(user && harvest_tool && (get_dist(user, src) <= 3))
if(stat != DEAD && user && harvest_tool && (get_dist(user, src) <= 3))
. += "<span class='notice'>\The [src] can be [harvest_verb] with a [initial(harvest_tool.name)] every [round(harvest_cooldown, 0.1)] minutes.</span>"
var/time_to_harvest = (harvest_recent + harvest_cooldown) - world.time
if(time_to_harvest > 0)

View File

@@ -14,6 +14,8 @@
handle_special()
handle_guts()
return TRUE
@@ -137,6 +139,12 @@
else
adjustOxyLoss(-unsuitable_atoms_damage)
/mob/living/simple_mob/proc/handle_guts()
for(var/obj/item/organ/OR in internal_organs)
OR.process()
for(var/obj/item/organ/OR in organs)
OR.process()
/mob/living/simple_mob/proc/handle_supernatural()
if(purge)

View File

@@ -57,8 +57,6 @@
var/response_harm = "tries to hurt" // If clicked on harm intent
var/list/friends = list() // Mobs on this list wont get attacked regardless of faction status.
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/obj/item/weapon/card/id/myid// An ID card if they have one to give them access to stuff.
@@ -158,6 +156,10 @@
// don't process me if there's nobody around to see it
low_priority = TRUE
// Used for if the mob can drop limbs. Overrides species dmi.
var/limb_icon
// Used for if the mob can drop limbs. Overrides the icon cache key, so it doesn't keep remaking the icon needlessly.
var/limb_icon_key
/mob/living/simple_mob/Initialize()
verbs -= /mob/verb/observe
@@ -170,8 +172,31 @@
if(has_eye_glow)
add_eyes()
return ..()
if(LAZYLEN(organs))
for(var/path in organs)
if(ispath(path))
var/obj/item/organ/external/neworg = new path(src)
neworg.name = "[name] [neworg.name]"
neworg.meat_type = meat_type
if(limb_icon)
neworg.force_icon = limb_icon
neworg.force_icon_key = limb_icon_key
organs |= neworg
organs -= path
if(LAZYLEN(internal_organs))
for(var/path in internal_organs)
if(ispath(path))
var/obj/item/organ/neworg = new path(src)
neworg.name = "[name] [neworg.name]"
neworg.meat_type = meat_type
internal_organs |= neworg
internal_organs -= path
return ..()
/mob/living/simple_mob/Destroy()
default_language = null
@@ -190,7 +215,6 @@
update_icon()
..()
//Client attached
/mob/living/simple_mob/Login()
. = ..()
@@ -269,27 +293,6 @@
/mob/living/simple_mob/get_speech_ending(verb, var/ending)
return verb
// Harvest an animal's delicious byproducts
/mob/living/simple_mob/proc/harvest(var/mob/user, var/invisible)
var/actual_meat_amount = max(1,(meat_amount/2))
var/attacker_name = user.name
if(invisible)
attacker_name = "someone"
if(meat_type && actual_meat_amount>0 && (stat == DEAD))
for(var/i=0;i<actual_meat_amount;i++)
var/obj/item/meat = new meat_type(get_turf(src))
meat.name = "[src.name] [meat.name]"
if(issmall(src))
user.visible_message("<span class='danger'>[attacker_name] chops up \the [src]!</span>")
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
qdel(src)
else
user.visible_message("<span class='danger'>[attacker_name] butchers \the [src] messily!</span>")
gib()
/mob/living/simple_mob/is_sentient()
return mob_class & MOB_CLASS_HUMANOID|MOB_CLASS_ANIMAL|MOB_CLASS_SLIME // Update this if needed.

View File

@@ -7,3 +7,16 @@
response_harm = "hits"
ai_holder_type = /datum/ai_holder/simple_mob/melee
internal_organs = list(\
/obj/item/organ/internal/brain,\
/obj/item/organ/internal/heart,\
/obj/item/organ/internal/liver,\
/obj/item/organ/internal/stomach,\
/obj/item/organ/internal/intestine,\
/obj/item/organ/internal/lungs\
)
butchery_loot = list(\
/obj/item/stack/animalhide = 3\
)

View File

@@ -110,6 +110,10 @@
var/poison_chance = 10 // Chance for injection to occur.
var/poison_per_bite = 5 // Amount added per injection.
butchery_loot = list(\
/obj/item/stack/material/chitin = 1\
)
/mob/living/simple_mob/animal/giant_spider/apply_melee_effects(var/atom/A)
if(isliving(A))
var/mob/living/L = A

View File

@@ -0,0 +1,301 @@
#define BULLET_AP_DIVISOR 200
#define AP_DIVISOR 4152
#define ARMOR_Y_INTERCEPT 0.2
#define ARMOR_SLOPE 0.017
#define PENETRATION_PROBABILITY_EXP_BASE 2
#define PENETRATION_PROBABILITY_EXP_MULT 30
#define BULLET_DEFLECTED_PAIN_DIVISOR 5000
#define BULLET_DEFLECTED_BULLET_DIVISOR 70
#define BULLET_DEFLECTED_MELEE_DIVISOR 280
#define BULLET_DEFLECTED_PAIN_EXPONENT 1.5
#define BULLET_DEFLECTED_BRUISE_SUBTRACT 5
GLOBAL_VAR_INIT(SKIN_LOSS_COEFFICIENT,16)
GLOBAL_VAR_INIT(ARMOR_LOSS_COEFFICIENT,150)
GLOBAL_VAR_INIT(ARMOR_LOSS_MIN_MULT,0.5)
GLOBAL_VAR_INIT(ARMOR_LOSS_MIN_ARMOR,20)
GLOBAL_VAR_INIT(INTERNAL_LOSS_COEFFICIENT,195)
#define ORGAN_LOSS_COEFFICIENT 350
#define HIT_VITAL_ORGAN_CHANCE 35
#define BONE_HIT_CHANCE_UNENCASED 45
#define BONE_HIT_CHANCE_ENCASED 80
GLOBAL_VAR_INIT(BONE_JOULES_PERHP_AVG,2)
GLOBAL_VAR_INIT(BONE_JOULES_PERHP_DEV,1)
GLOBAL_VAR_INIT(BONE_JOULES_MIN,100)
#define BONE_HP_AVG 25
GLOBAL_VAR_INIT(HOLLOW_POINT_VELLOSS_BONUS,2.35)
GLOBAL_VAR_INIT(HOLLOW_POINT_CONVERSION_EFF,1.15)
#define PROB_LEAVE_EARLY_FIRST 20
#define PROB_LEAVE_EARLY_SECOND 40
GLOBAL_VAR_INIT(ENERGY_DAMAGE_FLESH_FACTOR,0.03)
GLOBAL_VAR_INIT(ENERGY_DAMAGE_ORGAN_FACTOR,0.035)
#ifndef GAUSSIAN_RANDOM
#define GAUSSIAN_RANDOM(vars...) ((-2*log(rand()))**0.5 * cos(6.28318530718*rand()))
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// CADYN'S BALLISTICS ////////////////////////////////////////////////////////////////////////// ORIGINAL FROM CHOMPSTATION ////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/mob/living/proc/handle_ballistics(var/obj/item/projectile/bullet/P, var/def_zone)
var/list/updated_organ_weight = list()
var/ballistic_armor = getarmor(def_zone, "bullet")
var/melee_armor = getarmor(def_zone, "melee")
var/obj/item/organ/external/hit_organ
var/mob/living/carbon/human/H = src
if(istype(H))
hit_organ = H.get_organ(def_zone)
for(var/ext_organ in ballistic_variables["organ_hit_weight"])
var/list/input = list()
var/obj/item/organ/external/ref_ext_organ = H.get_organ(ext_organ)
for(var/int_organ in ballistic_variables["organ_hit_weight"][ext_organ])
var/ref_int_organ = H.internal_organs_by_name[int_organ]
if(ref_ext_organ && ref_int_organ && (ref_int_organ in ref_ext_organ.internal_organs))
input[ref_int_organ] = ballistic_variables["organ_hit_weight"][ext_organ][int_organ]
if(input.len)
updated_organ_weight[ref_ext_organ] = input
//log_and_message_admins("Beginning handle_ballistics")
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(!prob(penetration_chance)) //Boo-hoo we got deflected. Do boring agony/bruises stuff.
//log_and_message_admins("Bullet deflected")
var/pain_hit = hit_organ ? "into your [hit_organ]" : "into you"
var/hurt_value = P.velocity * P.grains / (BULLET_DEFLECTED_PAIN_DIVISOR * (1 + ballistic_armor/BULLET_DEFLECTED_BULLET_DIVISOR + melee_armor/BULLET_DEFLECTED_MELEE_DIVISOR)) //Better armor spreads out the energy better.
var/hurt_value_pain = hurt_value ** BULLET_DEFLECTED_PAIN_EXPONENT
var/hurt_value_bruise = max(0,hurt_value-BULLET_DEFLECTED_BRUISE_SUBTRACT)
var/absorber = ballistic_armor ? "armor" : "body" //There is a super tiny chance that small rounds can get deflected without armor, so this is just incase.
to_chat(src,"<span class='warning'>You feel the energy of the bullet painfully transfered [pain_hit] as your [absorber] deflects it!</span>")
apply_damage(hurt_value_pain,HALLOSS,def_zone)
if(hurt_value_bruise)
apply_damage(hurt_value_bruise,BRUTE,def_zone)
P.sub_velocity(P.velocity)
return 2
else //Now the FUN begins
//log_and_message_admins("Bullet penetrated")
var/area_over_mass = P.diam * P.diam / P.grains
//Most of these calculations don't involve energies because I'm treating flesh and organic tissue as a fluid since it's squishy and stuff.
//Since drag is proportional to velocity, we can do things on an m*v basis instead of an mv^2 basis.
//Obviously bones are more solid, so we do actual energy calculations for that.
var/conversion_efficiency = P.hollow_point ? GLOB.HOLLOW_POINT_CONVERSION_EFF : 1
var/vel_loss_multiplier = P.hollow_point ? GLOB.HOLLOW_POINT_VELLOSS_BONUS : 1
var/energy_dumped_organic = 0
var/vel_lost_armor = ballistic_armor >= GLOB.ARMOR_LOSS_MIN_ARMOR ? GLOB.ARMOR_LOSS_COEFFICIENT * area_over_mass * ((1 + GLOB.ARMOR_LOSS_MIN_MULT) - penetration_chance/100) : 0
P.sub_velocity(vel_lost_armor)
var/energy_past = P.energy
var/internal_loss = vel_loss_multiplier * GLOB.INTERNAL_LOSS_COEFFICIENT * area_over_mass
var/vel_lost_skin = vel_loss_multiplier * GLOB.SKIN_LOSS_COEFFICIENT * area_over_mass
P.sub_velocity(vel_lost_skin + internal_loss)
energy_dumped_organic += (energy_past - P.energy)
if(prob(PROB_LEAVE_EARLY_FIRST) || !P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 1
if(hit_organ)
//log_and_message_admins("organ_handle_ballistics called. hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor,updated_organ_weight)
else
//log_and_message_admins("general_handle_ballistics called.")
return general_handle_ballistics(P,def_zone,energy_dumped_organic,internal_loss,ballistic_armor)
/mob/living/proc/organ_handle_ballistics(var/obj/item/projectile/bullet/P,var/obj/item/organ/external/hit_organ,var/energy_dumped_organic,var/internal_loss,var/ballistic_armor,var/list/updated_organ_weight)
var/conversion_efficiency = P.hollow_point ? GLOB.HOLLOW_POINT_CONVERSION_EFF : 1
var/energy_past
var/area_over_mass = P.diam * P.diam / P.grains
var/bone_chance = BONE_HIT_CHANCE_UNENCASED
if(hit_organ.encased)
bone_chance = BONE_HIT_CHANCE_ENCASED
else
bone_chance = ballistic_variables["bone_chance_unencased"][hit_organ.organ_tag]
//log_and_message_admins("Bone hit chance is [bone_chance], organ is [hit_organ]")
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
//log_and_message_admins("Bone hit, bone_chance1. energy_to_fracture = [energy_to_fracture]")
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
//log_and_message_admins("Insufficient projectile energy. Stopping projectile.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
else
//log_and_message_admins("Sufficient projectile energy to pass through bone.")
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
if(!(hit_organ.status & ORGAN_BROKEN))
//log_and_message_admins("Fracturing [hit_organ]")
hit_organ.fracture()
//log_and_message_admins("Bone checking done. hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
if(hit_organ.internal_organs.len && P.velocity > area_over_mass*ORGAN_LOSS_COEFFICIENT && prob(ballistic_variables["organ_hit_chance"][hit_organ.organ_tag]) && updated_organ_weight[hit_organ] && updated_organ_weight[hit_organ].len)
//log_and_message_admins("Organ was hit by bullet.")
energy_past = P.energy
P.sub_velocity(internal_loss)
damage_organ_energy((energy_past - P.energy) * conversion_efficiency, pickweight(updated_organ_weight[hit_organ]))
if(!P.velocity)
//log_and_message_admins("Organ stopped bullet.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
//log_and_message_admins("Organ check done, hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity || (hit_organ.organ_tag in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND))
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return P.velocity ? -1 : 2
//log_and_message_admins("Internal_loss 2 stopped bullet")
//log_and_message_admins("Internal_loss 2 completed, hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
//log_and_message_admins("Bone hit, bone_chance1. energy_to_fracture = [energy_to_fracture]")
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
//log_and_message_admins("Insufficient projectile energy. Stopping projectile.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
else
//log_and_message_admins("Sufficient projectile energy to pass through bone.")
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
if(!(hit_organ.status & ORGAN_BROKEN))
//log_and_message_admins("Fracturing [hit_organ]")
hit_organ.fracture()
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity)
//log_and_message_admins("Internal_loss 3 stopped bullet")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
//log_and_message_admins("Internal_loss 3 completed. hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
//log_and_message_admins("Projectile exiting.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return -1
else
//log_and_message_admins("Projectile continuing inside body")
energy_dumped_organic += P.energy / 3
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
/mob/living/proc/general_handle_ballistics(var/obj/item/projectile/bullet/P,var/def_zone,var/energy_dumped_organic,var/internal_loss,var/ballistic_armor)
var/conversion_efficiency = P.hollow_point ? GLOB.HOLLOW_POINT_CONVERSION_EFF : 1
var/energy_past
var/area_over_mass = P.diam * P.diam / P.grains
var/bone_chance = BONE_HIT_CHANCE_UNENCASED
//if(def_zone in ballistic_variables["bone_chance_unencased"])
//bone_chance = ballistic_variables["bone_chance_unencased"][def_zone]
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, BONE_HP_AVG * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
if(P.velocity > area_over_mass * ORGAN_LOSS_COEFFICIENT && prob(HIT_VITAL_ORGAN_CHANCE))
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += (energy_past - P.energy) * 1.5
if(!P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity || (def_zone in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND))
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return P.velocity ? -1 : 2
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, BONE_HP_AVG * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return -1
else
energy_dumped_organic += P.energy / 3
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
/mob/living/proc/damage_organ_energy(var/energy,var/obj/item/organ/internal/target)
var/damage = round(energy*GLOB.ENERGY_DAMAGE_ORGAN_FACTOR)
//log_and_message_admins("damage_organ_energy([energy]) : [target].take_damage([damage])")
target.take_damage(damage)
return
/mob/living/proc/energy_to_damage(var/energy,var/def_zone)
var/damage = round(energy*GLOB.ENERGY_DAMAGE_FLESH_FACTOR)
//log_and_message_admins("energy_to_damage([energy]) : apply_damage([damage], BRUTE, [def_zone])")
apply_damage(damage, BRUTE, def_zone)
return
/mob/living/proc/armor_penetration_probability(var/armor, var/obj/item/projectile/bullet/P)
var/bullet_ap_value = (1+((P.armor_penetration)/BULLET_AP_DIVISOR))
var/ap_value = P.velocity * bullet_ap_value * (P.grains / P.diam)**(2/3) / AP_DIVISOR
var/armor_value = ARMOR_Y_INTERCEPT + ARMOR_SLOPE * armor
var/penetration_chance = 100 / (1 + PENETRATION_PROBABILITY_EXP_BASE**(-PENETRATION_PROBABILITY_EXP_MULT*(ap_value - armor_value)))
return penetration_chance
/mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone)
//log_and_message_admins("bullet_act_ch")
var/obj/item/projectile/bullet/B = P
if(P.check_armour == "bullet" && istype(B) && !B.old_bullet_act)
//log_and_message_admins("is bullet")
return handle_ballistics(P,def_zone)
else
//log_and_message_admins("is not bullet")
return ..()
/mob/living
var/list/ballistic_variables = list(\
"bone_chance_unencased" = list(BP_HEAD = 5, BP_TORSO = 20, BP_GROIN = 20, BP_L_FOOT = 80, BP_R_FOOT = 80, BP_L_LEG = 35, BP_R_LEG = 35, BP_L_ARM = 65, BP_R_ARM = 65, BP_L_HAND = 80, BP_R_HAND = 80), \
"organ_leave_early" = list("l_arm", "r_arm", "l_hand", "r_hand", "l_foot", "r_foot"), \
"organ_hit_weight" = list(\
BP_HEAD = list(\
/*Standard organs*/O_BRAIN = 90, O_EYES = 5, \
/*Diona organs*/O_RESPONSE = 10, O_RESPONSE = 15, O_GBLADDER = 15, \
/*Replicant organs*/O_VRLINK = 20, \
/*Xeno organs*/O_ACID = 10, O_RESIN = 10), \
BP_TORSO = list(\
/*Standard organs*/O_HEART = 5, O_LUNGS = 50, O_SPLEEN = 15, O_VOICE = 10, \
/*Synth organs*/O_CELL = 5, O_PUMP = 15, O_HEATSINK = 35, O_CYCLER = 15, O_DIAGNOSTIC = 10, \
/*Promethean organs*/O_REGBRUTE = 20, O_REGBURN = 20, O_REGOXY = 20, O_REGTOX = 20, \
/*Diona organs*/O_STRATA = 35, O_BRAIN = 20, O_NUTRIENT = 10, \
/*Replicant organs*/O_AREJECT = 35, \
/*Xeno organs*/O_PLASMA = 10, O_HIVE = 10), \
BP_GROIN = list(\
/*Standard organs*/O_INTESTINES = 50, O_STOMACH = 20, O_LIVER = 20, O_KIDNEYS = 15, O_APPENDIX = 5, \
/*Diona organs*/O_POLYP = 10, O_ANCHOR = 15, \
/*Replicant organs*/O_VENTC = 20, \
/*Xeno organs*/ O_EGG = 25) ), \
"organ_hit_chance" = list(BP_HEAD = 95, BP_TORSO = 90, BP_GROIN = 90) )

View File

@@ -0,0 +1,236 @@
#define BULLET_PENETRATED 1<<0
#define BULLET_BONECHECK1_TRUE 1<<1
#define BULLET_ORGANCHECK_TRUE 1<<2
#define BULLET_BONECHECK2_TRUE 1<<3
#define BULLET_PASSED_LEAVE_EARLY 1<<4
#define BULLET_PASSED_BONECHECK1 1<<5
#define BULLET_PASSED_ORGANCHECK 1<<6
#define BULLET_PASSED_INTERNALCHECK2 1<<7
#define BULLET_PASSED_BONECHECK2 1<<8
#define BULLET_PASSED_INTERNALCHECK3 1<<9
#define BULLET_TESTS 150
/mob/living/carbon/human/monkey/testerboyo
name = "testerboyo"
var/the_big_armor = 0
/mob/living/carbon/human/monkey/testerboyo/getarmor(var/def_zone,var/type)
return the_big_armor
/proc/test_all_ballistics()
var/mob/living/carbon/human/monkey/testerboyo/tester = new()
var/obj/item/projectile/bullet/pistol/test1 = new()
var/obj/item/projectile/bullet/pistol/ap/test2 = new()
var/obj/item/projectile/bullet/pistol/hp/test3 = new()
var/obj/item/projectile/bullet/pistol/medium/test4 = new()
var/obj/item/projectile/bullet/pistol/medium/ap/test5 = new()
var/obj/item/projectile/bullet/pistol/medium/hp/test6 = new()
var/obj/item/projectile/bullet/pistol/strong/test7 = new()
var/obj/item/projectile/bullet/shotgun/test8 = new()
var/obj/item/projectile/bullet/shotgun/buckshot/test9 = new()
var/obj/item/projectile/bullet/rifle/a762/test10 = new()
var/obj/item/projectile/bullet/rifle/a762/ap/test11 = new()
var/obj/item/projectile/bullet/rifle/a762/hp/test12 = new()
var/obj/item/projectile/bullet/rifle/a545/test13 = new()
var/obj/item/projectile/bullet/rifle/a545/ap/test14 = new()
var/obj/item/projectile/bullet/rifle/a545/hp/test15 = new()
var/obj/item/projectile/bullet/rifle/a145/test16 = new()
var/obj/item/projectile/bullet/rifle/a145/highvel/test17 = new()
var/obj/item/projectile/bullet/rifle/a44rifle/test18 = new()
var/obj/item/projectile/bullet/rifle/a95/test19 = new()
var/obj/item/projectile/bullet/rifle/a762/lmg/test20 = new()
test_ballistics(test1,tester)
test_ballistics(test2,tester)
test_ballistics(test3,tester)
test_ballistics(test4,tester)
test_ballistics(test5,tester)
test_ballistics(test6,tester)
test_ballistics(test7,tester)
test_ballistics(test8,tester)
test_ballistics(test9,tester)
test_ballistics(test10,tester)
test_ballistics(test11,tester)
test_ballistics(test12,tester)
test_ballistics(test13,tester)
test_ballistics(test14,tester)
test_ballistics(test15,tester)
test_ballistics(test16,tester)
test_ballistics(test17,tester)
test_ballistics(test18,tester)
test_ballistics(test19,tester)
test_ballistics(test20,tester)
qdel(tester)
qdel(test1)
qdel(test2)
qdel(test3)
qdel(test4)
qdel(test5)
qdel(test6)
qdel(test7)
qdel(test8)
qdel(test9)
qdel(test10)
qdel(test11)
qdel(test12)
qdel(test13)
qdel(test14)
qdel(test15)
qdel(test16)
qdel(test17)
qdel(test18)
qdel(test19)
qdel(test20)
/proc/test_ballistics(var/obj/item/projectile/bullet/P,var/mob/living/carbon/human/monkey/testerboyo/tester)
var/list/data = list()
for(var/armor_level in list(0,5,10,20,50,80))
data["[armor_level]"] = list()
data["[armor_level]"]["average"] = list()
tester.the_big_armor = armor_level
var/bp_num = 0
for(var/body_part in list(BP_TORSO,BP_HEAD,BP_R_LEG,BP_R_ARM,BP_R_HAND))
bp_num++
data["[armor_level]"][body_part] = list()
for(var/i = 0,i<BULLET_TESTS,i++)
P.velocity = initial(P.velocity)
P.sub_velocity(0)
var/out = tester.handle_ballistics(P,body_part)
for(var/x = 0,x<10,x++)
var/input = (out["chex"] & (1<<x)) ? 1 : 0
data["[armor_level]"][body_part]["[x]"] += input
data["[armor_level]"]["average"]["[x]"] += input
data["[armor_level]"][body_part]["10"] += out["energy"]
data["[armor_level]"][body_part]["10"] /= BULLET_TESTS
data["[armor_level]"]["average"]["10"] += data["[armor_level]"][body_part]["10"]
for(var/x = 0,x<11,x++)
data["[armor_level]"]["average"]["[x]"] /= bp_num
for(var/entry in data["[armor_level]"])
var/string_to_send = "[P.type]: Armor level [armor_level]: [entry]:"
for(var/x = 0,x<11,x++)
string_to_send += " [x]:[data["[armor_level]"][entry]["[x]"]]"
log_and_message_admins(string_to_send)
/proc/lazy_return_testing(var/chex,var/energy)
return list("chex" = chex, "energy" = energy)
/mob/living/carbon/human/monkey/testerboyo/handle_ballistics(var/obj/item/projectile/bullet/P, var/def_zone)
var/chex = 0
var/list/updated_organ_weight = list()
var/ballistic_armor = getarmor(def_zone, "bullet")
var/melee_armor = getarmor(def_zone, "melee")
var/obj/item/organ/external/hit_organ
var/mob/living/carbon/human/H = src
if(istype(H))
hit_organ = H.get_organ(def_zone)
for(var/ext_organ in ballistic_variables["organ_hit_weight"])
var/list/input = list()
var/obj/item/organ/external/ref_ext_organ = H.get_organ(ext_organ)
for(var/int_organ in ballistic_variables["organ_hit_weight"][ext_organ])
var/ref_int_organ = H.internal_organs_by_name[int_organ]
if(ref_ext_organ && ref_int_organ && (ref_int_organ in ref_ext_organ.internal_organs))
input[ref_int_organ] = ballistic_variables["organ_hit_weight"][ext_organ][int_organ]
if(input.len)
updated_organ_weight[ref_ext_organ] = input
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(!prob(penetration_chance)) //Boo-hoo we got deflected. Do boring agony/bruises stuff.
var/pain_hit = hit_organ ? "into your [hit_organ]" : "into you"
var/hurt_value = P.velocity * P.grains / (BULLET_DEFLECTED_PAIN_DIVISOR * (1 + ballistic_armor/BULLET_DEFLECTED_BULLET_DIVISOR + melee_armor/BULLET_DEFLECTED_MELEE_DIVISOR)) //Better armor spreads out the energy better.
var/hurt_value_pain = hurt_value ** BULLET_DEFLECTED_PAIN_EXPONENT
var/hurt_value_bruise = max(0,hurt_value-BULLET_DEFLECTED_BRUISE_SUBTRACT)
var/absorber = ballistic_armor ? "armor" : "body" //There is a super tiny chance that small rounds can get deflected without armor, so this is just incase.
to_chat(src,"<span class='warning'>You feel the energy of the bullet painfully transfered [pain_hit] as your [absorber] deflects it!</span>")
apply_damage(hurt_value_pain,HALLOSS,def_zone)
if(hurt_value_bruise)
apply_damage(hurt_value_bruise,BRUTE,def_zone)
P.sub_velocity(P.velocity)
return lazy_return_testing(chex,0)
else //Now the FUN begins
chex |= BULLET_PENETRATED
var/area_over_mass = P.diam * P.diam / P.grains
//Most of these calculations don't involve energies because I'm treating flesh and organic tissue as a fluid since it's squishy and stuff.
//Since drag is proportional to velocity, we can do things on an m*v basis instead of an mv^2 basis.
//Obviously bones are more solid, so we do actual energy calculations for that.
//var/conversion_efficiency = P.hollow_point ? 0.925 : 1
var/vel_loss_multiplier = P.hollow_point ? GLOB.HOLLOW_POINT_VELLOSS_BONUS : 1
var/energy_dumped_organic = 0
var/vel_lost_armor = ballistic_armor >= GLOB.ARMOR_LOSS_MIN_ARMOR ? GLOB.ARMOR_LOSS_COEFFICIENT * area_over_mass * ((1 + GLOB.ARMOR_LOSS_MIN_MULT) - penetration_chance/100) : 0
P.sub_velocity(vel_lost_armor)
var/energy_past = P.energy
var/internal_loss = vel_loss_multiplier * GLOB.INTERNAL_LOSS_COEFFICIENT * area_over_mass
var/vel_lost_skin = vel_loss_multiplier * GLOB.SKIN_LOSS_COEFFICIENT * area_over_mass
P.sub_velocity(vel_lost_skin + internal_loss)
energy_dumped_organic += (energy_past - P.energy)
if(prob(PROB_LEAVE_EARLY_FIRST) || !P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
if(hit_organ)
chex |= BULLET_PASSED_LEAVE_EARLY
return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor,updated_organ_weight,chex)
else
return general_handle_ballistics(P,def_zone,energy_dumped_organic,internal_loss,ballistic_armor)
/mob/living/carbon/human/monkey/testerboyo/organ_handle_ballistics(var/obj/item/projectile/bullet/P,var/obj/item/organ/external/hit_organ,var/energy_dumped_organic,var/internal_loss,var/ballistic_armor,var/list/updated_organ_weight,var/chex)
//var/conversion_efficiency = P.hollow_point ? 0.8 : 1
var/energy_past
var/area_over_mass = P.diam * P.diam / P.grains
var/bone_chance = BONE_HIT_CHANCE_UNENCASED
if(hit_organ.encased)
bone_chance = BONE_HIT_CHANCE_ENCASED
else
bone_chance = ballistic_variables["bone_chance_unencased"][hit_organ.organ_tag]
if(prob(bone_chance))
chex |= BULLET_BONECHECK1_TRUE
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += energy_to_fracture / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
chex |= BULLET_PASSED_BONECHECK1
if(hit_organ.internal_organs.len && P.velocity > area_over_mass*ORGAN_LOSS_COEFFICIENT && prob(ballistic_variables["organ_hit_chance"][hit_organ.organ_tag]) && updated_organ_weight[hit_organ] && updated_organ_weight[hit_organ].len)
chex |= BULLET_ORGANCHECK_TRUE
energy_past = P.energy
P.sub_velocity(internal_loss)
if(!P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
chex |= BULLET_PASSED_ORGANCHECK
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity || (hit_organ.organ_tag in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND))
return lazy_return_testing(chex,energy_dumped_organic)
chex |= BULLET_PASSED_INTERNALCHECK2
if(prob(bone_chance))
chex |= BULLET_BONECHECK2_TRUE
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += energy_to_fracture / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
chex |= BULLET_PASSED_BONECHECK2
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
chex |= BULLET_PASSED_INTERNALCHECK3
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
return lazy_return_testing(chex,energy_dumped_organic)
else
energy_dumped_organic += P.energy / 3
P.sub_velocity(P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)

View File

@@ -1022,6 +1022,40 @@ mob/proc/yank_out_object()
set hidden = 1
set_face_dir(client.client_dir(WEST))
// Begin VOREstation edit
/mob/verb/shiftnorth()
set hidden = TRUE
if(!canface())
return FALSE
if(pixel_y <= 16)
pixel_y++
is_shifted = TRUE
/mob/verb/shiftsouth()
set hidden = TRUE
if(!canface())
return FALSE
if(pixel_y >= -16)
pixel_y--
is_shifted = TRUE
/mob/verb/shiftwest()
set hidden = TRUE
if(!canface())
return FALSE
if(pixel_x >= -16)
pixel_x--
is_shifted = TRUE
mob/verb/shifteast()
set hidden = TRUE
if(!canface())
return FALSE
if(pixel_x <= 16)
pixel_x++
is_shifted = TRUE
// End VOREstation edit
/mob/proc/adjustEarDamage()
return

View File

@@ -83,6 +83,7 @@
var/resting = 0 //Carbon
var/lying = 0
var/lying_prev = 0
var/is_shifted = FALSE // VoreStation Edit; pixel shifting
var/canmove = 1
//Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects.
var/incorporeal_move = 0 //0 is off, 1 is normal, 2 is for ninjas.

View File

@@ -1184,17 +1184,6 @@
bee_stripes
name = "bee stripes"
icon_state = "beestripes"
<<<<<<< HEAD
body_parts = list(BP_TORSO,BP_GROIN)
||||||| parent of bbd7600f00... Merge pull request #9307 from KasparoVy/port-some-citrp-stuff
body_parts = list(BP_TORSO,BP_GROIN)
vas_toes
name = "Bug Paws (Vasilissan)"
icon_state = "vas_toes"
color_blend_mode = ICON_MULTIPLY
body_parts = list(BP_L_FOOT,BP_R_FOOT)
=======
body_parts = list(BP_TORSO,BP_GROIN)
vas_toes
@@ -1269,4 +1258,4 @@
color_blend_mode = ICON_MULTIPLY
body_parts = list(BP_L_LEG,BP_R_LEG,BP_L_HAND,BP_R_HAND,BP_TORSO,BP_GROIN,BP_HEAD)
species_allowed = list(SPECIES_TESHARI)
>>>>>>> bbd7600f00... Merge pull request #9307 from KasparoVy/port-some-citrp-stuff
body_parts = list(BP_L_FOOT,BP_R_FOOT)

View File

@@ -100,6 +100,8 @@
/datum/nifsoft/medichines_syn/life()
if((. = ..()))
var/mob/living/carbon/human/H = nif.human // Chomp Edit
var/HP_percent = H.health/H.getMaxHealth() // Chomp Edit
//We're good!
if(!nif.human.bad_external_organs.len)
if(mode || active)
@@ -117,7 +119,7 @@
var/obj/item/organ/external/EO = eo
for(var/w in EO.wounds)
var/datum/wound/W = w
if(W.damage <= 5)
if(W.damage <= 30) // Chomp Edit // The current limb break threshold.
W.heal_damage(0.1)
EO.update_damages()
if(EO.update_icon())
@@ -127,6 +129,17 @@
else if(mode == 1)
mode = 2
nif.notify("Medichines unable to repair all damage. Perform manual repairs.",TRUE)
// Chomp Edit Start //
else if(mode == 2 && HP_percent < -0.4)
nif.notify("User Status: CRITICAL. Notifying medical!",TRUE)
H << 'sound/voice/nifmed_critical.ogg' //CHOMP Add
mode = 0
if(!isbelly(H.loc)) //Not notified in case of vore, for gameplay purposes.
var/turf/T = get_turf(H)
var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null)
a.autosay("[H.real_name] is in critical condition, located at ([T.x],[T.y],[T.z])!", "[H.real_name]'s NIF", "Medical")
qdel(a)
// Chomp Edit End //
return TRUE

View File

@@ -14,6 +14,8 @@
target_parent_classes = list() // Is the parent supposed to be organic, robotic, assisted?
forgiving_class = TRUE // Will the organ give its verbs when it isn't a perfect match? I.E., assisted in organic, synthetic in organic.
butcherable = FALSE
var/obj/item/integrated_object // Objects held by the organ, used for re-usable, deployable things.
var/integrated_object_type // Object type the organ will spawn.
var/target_slot = null

View File

@@ -83,7 +83,10 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
health = config.default_brain_health
defib_timer = (config.defib_timer MINUTES) / 2
spawn(5)
if(brainmob && brainmob.client)
if(brainmob)
butcherable = FALSE
if(brainmob.client)
brainmob.client.screen.len = null //clear the hud
/obj/item/organ/internal/brain/Destroy()
@@ -96,6 +99,8 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
brainmob = new(src)
brainmob.name = H.real_name
brainmob.real_name = H.real_name
if(istype(H))
brainmob.dna = H.dna.Clone()
brainmob.timeofhostdeath = H.timeofdeath
brainmob.ooc_notes = H.ooc_notes //VOREStation Edit
@@ -125,13 +130,13 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
if(name == initial(name))
name = "\the [owner.real_name]'s [initial(name)]"
var/mob/living/simple_mob/animal/borer/borer = owner.has_brain_worms()
var/mob/living/simple_mob/animal/borer/borer = owner?.has_brain_worms()
if(borer)
borer.detatch() //Should remove borer if the brain is removed - RR
var/obj/item/organ/internal/brain/B = src
if(istype(B) && istype(owner))
if(istype(B) && owner)
B.transfer_identity(owner)
..()

View File

@@ -8,7 +8,7 @@
/obj/item/organ/internal/liver/process()
..()
if(!owner) return
if(!iscarbon(owner)) return
if(owner.life_tick % PROCESS_ACCURACY == 0)

View File

@@ -9,3 +9,4 @@
decays = FALSE // Ditto. Rust takes a while.
robotic = ORGAN_ROBOT
butcherable = FALSE

View File

@@ -44,6 +44,9 @@ var/list/organ_cache = list()
var/list/target_parent_classes = list() // Is the parent supposed to be organic, robotic, assisted?
var/forgiving_class = TRUE // Will the organ give its verbs when it isn't a perfect match? I.E., assisted in organic, synthetic in organic.
var/butcherable = TRUE
var/meat_type // What does butchering, if possible, make?
/obj/item/organ/Destroy()
handle_organ_mod_special(TRUE)
@@ -59,21 +62,42 @@ var/list/organ_cache = list()
/obj/item/organ/proc/update_health()
return
/obj/item/organ/New(var/mob/living/carbon/holder, var/internal)
/obj/item/organ/New(var/mob/living/holder, var/internal)
..(holder)
create_reagents(5)
if(!max_damage)
max_damage = min_broken_damage * 2
if(istype(holder))
if(isliving(holder))
src.owner = holder
src.w_class = max(src.w_class + mob_size_difference(holder.mob_size, MOB_MEDIUM), 1) //smaller mobs have smaller organs.
if(internal)
if(!LAZYLEN(holder.internal_organs))
holder.internal_organs = list()
if(!LAZYLEN(holder.internal_organs_by_name))
holder.internal_organs_by_name = list()
holder.internal_organs |= src
holder.internal_organs_by_name[organ_tag] = src
else
if(!LAZYLEN(holder.organs))
holder.organs = list()
if(!LAZYLEN(holder.organs_by_name))
holder.organs_by_name = list()
holder.internal_organs |= src
holder.internal_organs_by_name[organ_tag] = src
if(!max_damage)
max_damage = min_broken_damage * 2
if(iscarbon(holder))
var/mob/living/carbon/C = holder
species = GLOB.all_species[SPECIES_HUMAN]
if(holder.dna)
dna = holder.dna.Clone()
species = holder.species //VOREStation Edit - For custom species
dna = C.dna.Clone()
species = C.species //VOREStation Edit - For custom species
else
log_debug("[src] at [loc] spawned without a proper DNA.")
var/mob/living/carbon/human/H = holder
var/mob/living/carbon/human/H = C
if(istype(H))
if(internal)
var/obj/item/organ/external/E = H.get_organ(parent_organ)
@@ -81,18 +105,32 @@ var/list/organ_cache = list()
if(E.internal_organs == null)
E.internal_organs = list()
E.internal_organs |= src
H.internal_organs_by_name[organ_tag] = src
if(dna)
if(!blood_DNA)
blood_DNA = list()
blood_DNA[dna.unique_enzymes] = dna.b_type
if(internal)
holder.internal_organs |= src
else
species = GLOB.all_species["Human"]
handle_organ_mod_special()
/obj/item/organ/Initialize()
..()
if(owner)
if(!meat_type)
if(owner.isSynthetic())
meat_type = /obj/item/stack/material/steel
else if(ishuman(owner))
var/mob/living/carbon/human/H = owner
meat_type = H?.species?.meat_type
if(!meat_type)
if(owner.meat_type)
meat_type = owner.meat_type
else
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
/obj/item/organ/proc/set_dna(var/datum/dna/new_dna)
if(new_dna)
dna = new_dna.Clone()
@@ -134,7 +172,7 @@ var/list/organ_cache = list()
handle_organ_proc_special()
//Process infections
if(robotic >= ORGAN_ROBOT || (owner && owner.species && (owner.species.flags & IS_PLANT || (owner.species.flags & NO_INFECT))))
if(robotic >= ORGAN_ROBOT || (istype(owner) && (owner.species && (owner.species.flags & (IS_PLANT | NO_INFECT)))))
germ_level = 0
return
@@ -152,7 +190,7 @@ var/list/organ_cache = list()
if(germ_level >= INFECTION_LEVEL_THREE)
die()
else if(owner && owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs
else if(owner && owner?.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs
//** Handle antibiotics and curing infections
handle_antibiotics()
handle_rejection()
@@ -170,7 +208,7 @@ var/list/organ_cache = list()
germ_level = 0
return 0
var/antibiotics = owner.chem_effects[CE_ANTIBIOTIC] || 0
var/antibiotics = iscarbon(owner) ? owner.chem_effects[CE_ANTIBIOTIC] || 0 : 0
var/infection_damage = 0
@@ -203,10 +241,12 @@ var/list/organ_cache = list()
//Level 1 qualifies for specific organ processing effects
if(germ_level >= INFECTION_LEVEL_ONE)
. = 1
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
. = 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
//Level two qualifies for further processing effects
if (germ_level >= INFECTION_LEVEL_TWO)
@@ -269,6 +309,7 @@ var/list/organ_cache = list()
//Germs
/obj/item/organ/proc/handle_antibiotics()
if(istype(owner))
var/antibiotics = owner.chem_effects[CE_ANTIBIOTIC] || 0
if (!germ_level || antibiotics < ANTIBIO_NORM)
@@ -304,7 +345,7 @@ var/list/organ_cache = list()
//only show this if the organ is not robotic
if(owner && parent_organ && amount > 0)
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
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)
@@ -322,6 +363,7 @@ var/list/organ_cache = list()
robotic = ORGAN_ASSISTED
min_bruised_damage = 15
min_broken_damage = 35
butcherable = FALSE
/obj/item/organ/proc/digitize() //Used to make the circuit-brain. On this level in the event more circuit-organs are added/tweaks are wanted.
robotize()
@@ -341,10 +383,7 @@ var/list/organ_cache = list()
take_damage(rand(1,3))
/obj/item/organ/proc/removed(var/mob/living/user)
if(!istype(owner))
return
if(owner)
owner.internal_organs_by_name[organ_tag] = null
owner.internal_organs_by_name -= organ_tag
owner.internal_organs_by_name -= null
@@ -356,6 +395,8 @@ var/list/organ_cache = list()
forceMove(owner.drop_location())
START_PROCESSING(SSobj, src)
rejecting = null
if(istype(owner))
var/datum/reagent/blood/organ_blood = locate(/datum/reagent/blood) in reagents.reagent_list
if(!organ_blood || !organ_blood.data["blood_DNA"])
owner.vessel.trans_to(src, 5, 1, 1)
@@ -379,13 +420,13 @@ var/list/organ_cache = list()
var/datum/reagent/blood/transplant_blood = locate(/datum/reagent/blood) in reagents.reagent_list
transplant_data = list()
if(!transplant_blood)
transplant_data["species"] = target.species.name
transplant_data["blood_type"] = target.dna.b_type
transplant_data["blood_DNA"] = target.dna.unique_enzymes
transplant_data["species"] = target?.species.name
transplant_data["blood_type"] = target?.dna.b_type
transplant_data["blood_DNA"] = target?.dna.unique_enzymes
else
transplant_data["species"] = transplant_blood.data["species"]
transplant_data["blood_type"] = transplant_blood.data["blood_type"]
transplant_data["blood_DNA"] = transplant_blood.data["blood_DNA"]
transplant_data["species"] = transplant_blood?.data["species"]
transplant_data["blood_type"] = transplant_blood?.data["blood_type"]
transplant_data["blood_DNA"] = transplant_blood?.data["blood_DNA"]
owner = target
loc = owner
@@ -428,6 +469,46 @@ var/list/organ_cache = list()
bitten(user)
return
/obj/item/organ/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(can_butcher(W, user))
butcher(W, user)
return
return ..()
/obj/item/organ/proc/can_butcher(var/obj/item/O, var/mob/living/user)
if(butcherable && meat_type)
if(istype(O, /obj/machinery/gibber)) // The great equalizer.
return TRUE
if(robotic >= ORGAN_ROBOT)
if(O.is_screwdriver())
return TRUE
else
if(is_sharp(O) && has_edge(O))
return TRUE
return FALSE
/obj/item/organ/proc/butcher(var/obj/item/O, var/mob/living/user, var/atom/newtarget)
if(robotic >= ORGAN_ROBOT)
user?.visible_message("<span class='notice'>[user] disassembles \the [src].</span>")
else
user?.visible_message("<span class='notice'>[user] butchers \the [src].</span>")
if(!newtarget)
newtarget = get_turf(src)
var/obj/item/newmeat = new meat_type(newtarget)
if(istype(newmeat, /obj/item/weapon/reagent_containers/food/snacks/meat))
newmeat.name = "[src.name] [newmeat.name]" // "liver meat" "heart meat", etc.
qdel(src)
/obj/item/organ/proc/organ_can_feel_pain()
if(species.flags & NO_PAIN)
return 0

View File

@@ -34,7 +34,8 @@
var/body_part = null // Part flag
var/icon_position = 0 // Used in mob overlay layering calculations.
var/model // Used when caching robolimb icons.
var/force_icon // Used to force override of species-specific limb icons (for prosthetics).
var/force_icon // Used to force override of species-specific limb icons (for prosthetics). Also used for any limbs chopped from a simple mob, and then attached to humans.
var/force_icon_key // Used to force the override of the icon-key generated using the species. Must be used in tandem with the above.
var/icon/mob_icon // Cached icon for use in mob overlays.
var/gendered_icon = 0 // Whether or not the icon state appends a gender.
var/s_tone // Skin tone.
@@ -97,7 +98,7 @@
qdel(splinted)
splinted = null
if(owner)
if(istype(owner))
owner.organs -= src
owner.organs_by_name[organ_tag] = null
owner.organs_by_name -= organ_tag
@@ -199,7 +200,7 @@
return
dislocated = 1
if(owner)
if(istype(owner))
owner.verbs |= /mob/living/carbon/human/proc/relocate
/obj/item/organ/external/proc/relocate()
@@ -207,7 +208,7 @@
return
dislocated = 0
if(owner)
if(istype(owner))
owner.shock_stage += 20
//check to see if we still need the verb
@@ -221,7 +222,7 @@
/obj/item/organ/external/New(var/mob/living/carbon/holder)
..(holder, 0)
if(owner)
if(istype(owner))
replaced(owner)
sync_colour_to_human(owner)
spawn(1)
@@ -887,11 +888,11 @@ Note that amputating the affected organ does in fact remove the infection from t
var/mob/living/carbon/human/victim = owner //Keep a reference for post-removed().
var/obj/item/organ/external/parent_organ = parent
var/use_flesh_colour = species.get_flesh_colour(owner)
var/use_blood_colour = species.get_blood_colour(owner)
var/use_flesh_colour = species?.get_flesh_colour(owner) ? species.get_flesh_colour(owner) : "#C80000"
var/use_blood_colour = species?.get_blood_colour(owner) ? species.get_blood_colour(owner) : "#C80000"
removed(null, ignore_children)
victim.traumatic_shock += 60
victim?.traumatic_shock += 60
if(parent_organ)
var/datum/wound/lost_limb/W = new (src, disintegrate, clean)
@@ -907,9 +908,12 @@ Note that amputating the affected organ does in fact remove the infection from t
stump.update_damages()
spawn(1)
if(istype(victim))
victim.updatehealth()
victim.UpdateDamageIcon()
victim.update_icons_body()
else
victim.update_icons()
dir = 2
var/atom/droploc = victim.drop_location()
@@ -1236,7 +1240,7 @@ Note that amputating the affected organ does in fact remove the infection from t
organ.loc = src
// Remove parent references
parent.children -= src
parent?.children -= src
parent = null
release_restraints(victim)

View File

@@ -58,7 +58,7 @@ var/global/list/limb_icon_cache = list()
cut_overlays()
//Every 'addon' below requires information from species
if(!owner || !owner.species)
if(!iscarbon(owner) || !owner.species)
return
//Eye color/icon
@@ -135,7 +135,10 @@ var/global/list/limb_icon_cache = list()
if(owner && owner.gender == FEMALE)
gender = "f"
if(!force_icon_key)
icon_cache_key = "[icon_name]_[species ? species.get_bodytype() : SPECIES_HUMAN]" //VOREStation Edit
else
icon_cache_key = "[icon_name]_[force_icon_key]"
if(force_icon)
mob_icon = new /icon(force_icon, "[icon_name][gendered_icon ? "_[gender]" : ""]")

View File

@@ -38,6 +38,7 @@
var/brain_type = /obj/item/device/mmi
var/obj/item/device/mmi/stored_mmi
robotic = ORGAN_ASSISTED
butcherable = FALSE
/obj/item/organ/internal/mmi_holder/Destroy()
if(stored_mmi && (stored_mmi.loc == src))

View File

@@ -282,6 +282,7 @@
/obj/item/organ/external/head/removed()
if(owner)
if(iscarbon(owner))
name = "[owner.real_name]'s head"
owner.drop_from_inventory(owner.glasses)
owner.drop_from_inventory(owner.head)

View File

@@ -112,7 +112,7 @@
var/can_hold_val = 0
loading = TRUE
while(mat_storage + SHEET_MATERIAL_AMOUNT <= max_mat_storage && do_after(user,1.5 SECONDS))
while(can_hold_val < M.amount && mat_storage + SHEET_MATERIAL_AMOUNT <= max_mat_storage && do_after(user,1.5 SECONDS)) //CHOMPEdit
can_hold_val ++
mat_storage += SHEET_MATERIAL_AMOUNT
playsound(src, 'sound/effects/phasein.ogg', 15, 1)

Some files were not shown because too many files have changed in this diff Show More