mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2026-08-30 00:35:45 +01:00
Merge master and build TGUI
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
for(var/option in choices)
|
||||
var/votes = choices[option]
|
||||
total_votes += votes
|
||||
if(votes > greatest_votes)
|
||||
greatest_votes = votes
|
||||
|
||||
//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
|
||||
|
||||
. = 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 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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,6 +6,12 @@
|
||||
|
||||
//Rouguelike Mining
|
||||
/area/asteroid/rogue
|
||||
has_gravity = 0
|
||||
requires_power = 1
|
||||
always_unpowered = 1
|
||||
power_light = 0
|
||||
power_equip = 0
|
||||
power_environ = 0
|
||||
var/asteroid_spawns = list()
|
||||
var/mob_spawns = list()
|
||||
var/shuttle_area //It would be neat if this were more dynamic, but eh.
|
||||
|
||||
@@ -331,7 +331,7 @@
|
||||
connected = locate(/obj/machinery/dna_scannernew, get_step(src, dir))
|
||||
if(connected)
|
||||
break
|
||||
VARSET_IN(src, injector_ready, TRUE, 25 SECONDS)
|
||||
VARSET_IN(src, injector_ready, TRUE, 25 SECONDS)
|
||||
|
||||
/obj/machinery/computer/scan_consolenew/proc/all_dna_blocks(var/list/buffer)
|
||||
var/list/arr = list()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
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"
|
||||
|
||||
@@ -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!"
|
||||
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?"
|
||||
|
||||
@@ -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
|
||||
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."
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -147,4 +147,4 @@ VR edit end*/
|
||||
/datum/alt_title/mech_tech
|
||||
title = "Mechatronic Engineer"
|
||||
title_blurb = "A Mechatronic Engineer focuses on the construction and maintenance of Exosuits, and should be well versed in their use. \
|
||||
They may also be called upon to work on synthetics and prosthetics, if needed."
|
||||
They may also be called upon to work on synthetics and prosthetics, if needed."
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
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"
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -32,7 +32,7 @@
|
||||
/obj/machinery/washing_machine/Initialize()
|
||||
. = ..()
|
||||
default_apply_parts()
|
||||
|
||||
|
||||
/obj/machinery/washing_machine/AltClick()
|
||||
start()
|
||||
|
||||
@@ -67,9 +67,14 @@
|
||||
|
||||
//Tanning!
|
||||
for(var/obj/item/stack/hairlesshide/HH in washing)
|
||||
var/obj/item/stack/wetleather/WL = new(src)
|
||||
WL.amount = HH.amount
|
||||
qdel(HH)
|
||||
var/obj/item/stack/WL = new HH.wet_type(src)
|
||||
if(istype(WL))
|
||||
WL.amount = HH.amount
|
||||
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()
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
icon_state = ""
|
||||
initial_icon = ""
|
||||
|
||||
dir_in = null //Don't reset direction when empty
|
||||
|
||||
step_in = 2 //Fast
|
||||
|
||||
health = 400
|
||||
|
||||
@@ -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()
|
||||
*/
|
||||
@@ -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,29 +114,28 @@
|
||||
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)
|
||||
HS.amount = 1
|
||||
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)
|
||||
//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
|
||||
//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)
|
||||
HS.amount = 1
|
||||
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++
|
||||
wetness = initial(wetness)
|
||||
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/HS = new dry_type(src.loc)
|
||||
|
||||
if(istype(HS))
|
||||
HS.amount = 1
|
||||
wetness = initial(wetness)
|
||||
src.use(1)
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
/obj/item/stack/examine(mob/user)
|
||||
. = ..()
|
||||
|
||||
|
||||
if(Adjacent(user))
|
||||
if(!uses_charge)
|
||||
. += "There are [src.amount] [src.singular_name]\s in the stack."
|
||||
@@ -380,17 +380,17 @@
|
||||
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)
|
||||
src.title = title
|
||||
src.result_type = result_type
|
||||
src.req_amount = req_amount
|
||||
src.res_amount = res_amount
|
||||
src.max_res_amount = max_res_amount
|
||||
src.time = time
|
||||
src.one_per_turf = one_per_turf
|
||||
src.on_floor = on_floor
|
||||
src.use_material = supplied_material
|
||||
src.pass_color = 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
|
||||
src.res_amount = res_amount
|
||||
src.max_res_amount = max_res_amount
|
||||
src.time = time
|
||||
src.one_per_turf = one_per_turf
|
||||
src.on_floor = on_floor
|
||||
src.use_material = supplied_material
|
||||
src.pass_color = pass_stack_color
|
||||
|
||||
/*
|
||||
* Recipe list datum
|
||||
|
||||
@@ -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,59 +53,82 @@
|
||||
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))
|
||||
var/egg = rimplant.eggtype
|
||||
new egg(get_turf(src))
|
||||
src.SetStunned(3)
|
||||
playsound(src,'sound/vore/insert.ogg',50,1)
|
||||
var/index = rand(1,3)
|
||||
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)
|
||||
playsound(src,'sound/vore/insert.ogg',50,1)
|
||||
var/index = rand(1,3)
|
||||
|
||||
if (usr != src)
|
||||
var/emote = rimplant.emote_descriptor[index]
|
||||
var/verb_desc = rimplant.verb_descriptor[index]
|
||||
var/self_verb_desc = rimplant.self_verb_descriptor[index]
|
||||
visible_message("<span class='notice'>[usr] [verb_desc] [emote]</span>",
|
||||
"<span class='notice'>You [self_verb_desc] [emote]</span>")
|
||||
if (usr != src)
|
||||
var/emote = rimplant.emote_descriptor[index]
|
||||
var/verb_desc = rimplant.verb_descriptor[index]
|
||||
var/self_verb_desc = rimplant.self_verb_descriptor[index]
|
||||
visible_message("<span class='notice'>[usr] [verb_desc] [emote]</span>",
|
||||
"<span class='notice'>You [self_verb_desc] [emote]</span>")
|
||||
else
|
||||
visible_message("<span class='notice'>[src] [pick(rimplant.short_emote_descriptor)] an egg.</span>",
|
||||
"<span class='notice'>You [pick(rimplant.self_emote_descriptor)] an egg.</span>")
|
||||
|
||||
if(prob(15))
|
||||
visible_message("<span class='notice'>[src] [pick(rimplant.random_emote)].</span>")
|
||||
rimplant.reagents.remove_any(rimplant.transfer_amount)
|
||||
|
||||
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(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
|
||||
visible_message("<span class='notice'>[src] [pick(rimplant.short_emote_descriptor)] an egg.</span>",
|
||||
"<span class='notice'>You [pick(rimplant.self_emote_descriptor)] an egg.</span>")
|
||||
return
|
||||
/mob/living/carbon/human/proc/toggle_cascade()
|
||||
|
||||
if(prob(15))
|
||||
visible_message("<span class='notice'>[src] [pick(rimplant.random_emote)].</span>")
|
||||
rimplant.reagents.remove_any(rimplant.transfer_amount)
|
||||
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>")
|
||||
|
||||
if(prob(70*rimplant.reagents.total_volume/rimplant.usable_volume))
|
||||
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)
|
||||
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>")
|
||||
|
||||
/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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -349,9 +349,11 @@
|
||||
to_chat(user, "<span class='danger'>You go blind!</span>")
|
||||
user.Blind(5)
|
||||
user.eye_blurry = 5
|
||||
user.disabilities |= NEARSIGHTED
|
||||
spawn(100)
|
||||
user.disabilities &= ~NEARSIGHTED
|
||||
// Don't cure being nearsighted
|
||||
if(!(H.disabilities & NEARSIGHTED))
|
||||
user.disabilities |= NEARSIGHTED
|
||||
spawn(100)
|
||||
user.disabilities &= ~NEARSIGHTED
|
||||
return
|
||||
|
||||
/obj/item/weapon/weldingtool/is_hot()
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -235,7 +235,7 @@
|
||||
/obj/structure/flora/pottedplant/attackby(obj/item/I, mob/user)
|
||||
if(issilicon(user))
|
||||
return // Don't try to put modules in here, you're a borg. TODO: Inventory refactor to not be ass.
|
||||
|
||||
|
||||
if(stored_item)
|
||||
to_chat(user, "<span class='notice'>[I] won't fit in. There already appears to be something in here...</span>")
|
||||
return
|
||||
@@ -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>"
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
/obj/structure/lattice/Initialize()
|
||||
. = ..()
|
||||
|
||||
if(!(istype(src.loc, /turf/space) || istype(src.loc, /turf/simulated/open) || istype(src.loc, /turf/simulated/mineral)))
|
||||
if(!(istype(src.loc, /turf/space) || istype(src.loc, /turf/simulated/open) || istype(src.loc, /turf/simulated/mineral) || istype(src.loc, /turf/simulated/shuttle/plating/airless/carry)))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
for(var/obj/structure/lattice/LAT in src.loc)
|
||||
if(LAT != src)
|
||||
crash_with("Found multiple lattices at '[log_info_line(loc)]'")
|
||||
log_debug("Found multiple lattices at '[log_info_line(loc)]'") //VOREStation Edit, why was this a runtime, it's harmless
|
||||
return INITIALIZE_HINT_QDEL
|
||||
icon = 'icons/obj/smoothlattice.dmi'
|
||||
icon_state = "latticeblank"
|
||||
|
||||
@@ -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
|
||||
..()
|
||||
@@ -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
|
||||
|
||||
@@ -93,7 +93,12 @@
|
||||
|
||||
if(istype(M, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
dirtslip = H.species.dirtslip //CHOMPEdit
|
||||
//CHOMPEdit Begin
|
||||
dirtslip = H.species.dirtslip
|
||||
if(H.species.mudking)
|
||||
dirt = min(dirt+2, 101)
|
||||
update_dirt()
|
||||
//CHOMPEdit End
|
||||
// Tracking blood
|
||||
var/list/bloodDNA = null
|
||||
var/bloodcolor=""
|
||||
@@ -147,6 +152,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
|
||||
|
||||
@@ -43,6 +43,35 @@
|
||||
icon_state = "floor"
|
||||
set_light(0,0,"#ffffff")
|
||||
|
||||
/turf/simulated/shuttle/plating/airless/carry/attackby(obj/item/C, mob/user) //this is gross
|
||||
if (istype(C, /obj/item/stack/rods))
|
||||
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
|
||||
if(L)
|
||||
return
|
||||
var/obj/item/stack/rods/R = C
|
||||
if (R.use(1))
|
||||
to_chat(user, "<span class='notice'>Constructing support lattice ...</span>")
|
||||
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
|
||||
new/obj/structure/lattice(src)
|
||||
return
|
||||
|
||||
if (istype(C, /obj/item/stack/tile/floor))
|
||||
var/obj/structure/lattice/L = locate(/obj/structure/lattice, src)
|
||||
if(L)
|
||||
var/obj/item/stack/tile/floor/S = C
|
||||
if (S.get_amount() < 1)
|
||||
return
|
||||
qdel(L)
|
||||
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
|
||||
S.use(1)
|
||||
ChangeTurf(/turf/simulated/floor/airless)
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The plating is going to need some support.</span>")
|
||||
|
||||
/turf/simulated/shuttle/plating/airless/carry/is_solid_structure()
|
||||
return locate(/obj/structure/lattice, src)
|
||||
|
||||
/turf/simulated/floor/gorefloor
|
||||
name = "infected tile"
|
||||
desc = "Slick, sickly-squirming meat has grown in and out of cracks once empty. It pulsates intermittently, and with every beat, blood seeps out of pores."
|
||||
@@ -53,4 +82,4 @@
|
||||
name = "putrid mass"
|
||||
desc = "It is entirely made of sick, gurgling flesh. It is releasing a sickly odour."
|
||||
icon_state = "bloodfloor_2"
|
||||
icon = 'icons/goonstation/turf/meatland.dmi'
|
||||
icon = 'icons/goonstation/turf/meatland.dmi'
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -143,8 +143,14 @@
|
||||
if(reagents) //Handle ingestion of the reagent.
|
||||
playsound(M,'sound/items/eatfood.ogg', rand(10,50), 1)
|
||||
if(reagents.total_volume)
|
||||
if(reagents.total_volume > bitesize)
|
||||
reagents.trans_to_mob(M, bitesize, CHEM_INGEST)
|
||||
//CHOMPStation Edit Begin
|
||||
var/bite_mod = 1
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H))
|
||||
bite_mod = H.species.bite_mod
|
||||
if(reagents.total_volume > bitesize*bite_mod)
|
||||
reagents.trans_to_mob(M, bitesize*bite_mod, CHEM_INGEST)
|
||||
//CHOMPStation Edit End
|
||||
else
|
||||
reagents.trans_to_mob(M, reagents.total_volume, CHEM_INGEST)
|
||||
bitecount++
|
||||
@@ -4039,6 +4045,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!"
|
||||
|
||||
@@ -191,4 +191,61 @@
|
||||
/obj/item/weapon/reagent_containers/food/snacks/greentealeaf/Initialize()
|
||||
..()
|
||||
reagents.add_reagent("tealeavesgreen", 6)
|
||||
bitesize = 1
|
||||
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?
|
||||
@@ -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,17 +218,26 @@
|
||||
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))
|
||||
qdel(thing)
|
||||
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.
|
||||
thing.throw_at(get_edge_target_turf(src,gib_throw_dir),rand(0,3),emagged ? 100 : 50) // Being pelted with bits of meat and bone would hurt.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
//====================
|
||||
@@ -93,7 +98,7 @@
|
||||
)
|
||||
result = /obj/item/weapon/reagent_containers/food/snacks/donut/jelly
|
||||
result_quantity = 2
|
||||
|
||||
|
||||
/datum/recipe/jellydonut/poisonberry
|
||||
reagents = list("poisonberryjuice" = 5, "sugar" = 5)
|
||||
items = list(
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -200,4 +200,23 @@
|
||||
set_trait(TRAIT_PLANT_ICON,"alien4") //spooky pods
|
||||
set_trait(TRAIT_IDEAL_HEAT, 283)
|
||||
set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0)
|
||||
set_trait(TRAIT_WATER_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")
|
||||
@@ -1,6 +1,10 @@
|
||||
|
||||
/obj/item/seeds/teaseed
|
||||
seed_type = "tea"
|
||||
|
||||
/obj/item/seeds/pitcherseed
|
||||
seed_type = "pitcher plant"
|
||||
|
||||
/obj/item/seeds/teaseed
|
||||
seed_type = "tea"
|
||||
|
||||
|
||||
/obj/item/seeds/cinnamon
|
||||
seed_type = "cinnamon"
|
||||
|
||||
/obj/item/seeds/pitcherseed
|
||||
seed_type = "pitcher plant"
|
||||
|
||||
@@ -77,12 +77,16 @@
|
||||
update_lighting()
|
||||
|
||||
/obj/item/integrated_circuit/output/light/proc/update_lighting()
|
||||
if(light_toggled)
|
||||
if(assembly)
|
||||
assembly.set_light(l_range = light_brightness, l_power = light_brightness, l_color = light_rgb)
|
||||
else
|
||||
if(assembly)
|
||||
assembly.set_light(0)
|
||||
//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)
|
||||
light_source.set_light(l_range = light_brightness, l_power = light_brightness, l_color = light_rgb)
|
||||
else
|
||||
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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
/*
|
||||
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
message = "makes a weird noise!"
|
||||
playsound(src.loc, 'sound/misc/ough.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
|
||||
m_type = 2 //End of Yawn Addtion
|
||||
*/
|
||||
*/
|
||||
if ("howl") // YW add begins
|
||||
m_type = 2
|
||||
message = "lets out a howl."
|
||||
@@ -269,7 +269,7 @@
|
||||
set desc = "Switch tail layer on top."
|
||||
tail_alt = !tail_alt
|
||||
update_tail_showing()
|
||||
|
||||
|
||||
/mob/living/carbon/human/verb/hide_wings_vr()
|
||||
set name = "Show/Hide wings"
|
||||
set category = "IC"
|
||||
@@ -282,4 +282,12 @@
|
||||
else
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -288,7 +288,7 @@
|
||||
oxyloss = 0
|
||||
else
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/carbon/human/adjustHalLoss(var/amount)
|
||||
if(species.flags & NO_PAIN)
|
||||
halloss = 0
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -144,12 +146,12 @@
|
||||
// Check again...
|
||||
if(!l_hand && !r_hand)
|
||||
return
|
||||
|
||||
var/adrenaline = has_modifier_of_type(/datum/modifier/adrenaline) //CHOMPEdit
|
||||
for (var/obj/item/organ/external/E in organs)
|
||||
if(!E || !E.can_grasp)
|
||||
continue
|
||||
|
||||
if((E.is_broken() || E.is_dislocated()) && !E.splinted)
|
||||
if((E.is_broken() || E.is_dislocated()) && !E.splinted && !adrenaline) //CHOMPEdit
|
||||
switch(E.body_part)
|
||||
if(HAND_LEFT, ARM_LEFT)
|
||||
if(!l_hand)
|
||||
|
||||
@@ -969,6 +969,9 @@
|
||||
if(nutrition > 1000 && species.grows && size_multiplier < RESIZE_HUGE)
|
||||
nutrition_reduction *= 5
|
||||
resize(min(size_multiplier+0.004,RESIZE_HUGE))
|
||||
if(nutrition < 200 && species.shrinks && size_multiplier > RESIZE_TINY)
|
||||
nutrition_reduction *= 0.3
|
||||
resize(max(size_multiplier-0.004,RESIZE_TINY))
|
||||
//CHOMPEdit End
|
||||
adjust_nutrition(-nutrition_reduction)
|
||||
|
||||
@@ -1053,7 +1056,7 @@
|
||||
if (mind)
|
||||
//Are they SSD? If so we'll keep them asleep but work off some of that sleep var in case of stoxin or similar.
|
||||
if(client || sleeping > 3)
|
||||
AdjustSleeping(-1)
|
||||
AdjustSleeping(-1 * species.waking_speed) //CHOMPEdit
|
||||
throw_alert("asleep", /obj/screen/alert/asleep)
|
||||
if( prob(2) && health && !hal_crit )
|
||||
spawn(0)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/mob/living/carbon/human/handle_mutations_and_radiation()
|
||||
if(inStasisNow())
|
||||
return
|
||||
|
||||
if(getFireLoss())
|
||||
if((COLD_RESISTANCE in mutations) || (prob(1)))
|
||||
heal_organ_damage(0,1)
|
||||
|
||||
// DNA2 - Gene processing.
|
||||
// The HULK stuff that was here is now in the hulk gene.
|
||||
if(!isSynthetic())
|
||||
for(var/datum/dna/gene/gene in dna_genes)
|
||||
if(!gene.block)
|
||||
continue
|
||||
if(gene.is_active(src))
|
||||
gene.OnMobLife(src)
|
||||
|
||||
radiation = CLAMP(radiation,0,250)
|
||||
|
||||
if(!radiation)
|
||||
if(species.appearance_flags & RADIATION_GLOWS)
|
||||
set_light(0)
|
||||
else
|
||||
if(species.appearance_flags & RADIATION_GLOWS)
|
||||
set_light(max(1,min(5,radiation/15)), max(1,min(10,radiation/25)), species.get_flesh_colour(src))
|
||||
// END DOGSHIT SNOWFLAKE
|
||||
|
||||
var/obj/item/organ/internal/diona/nutrients/rad_organ = locate() in internal_organs
|
||||
if(rad_organ && !rad_organ.is_broken())
|
||||
var/rads = radiation/25
|
||||
radiation -= rads
|
||||
adjust_nutrition(rads)
|
||||
adjustBruteLoss(-(rads))
|
||||
adjustFireLoss(-(rads))
|
||||
adjustOxyLoss(-(rads))
|
||||
adjustToxLoss(-(rads))
|
||||
updatehealth()
|
||||
return
|
||||
|
||||
var/obj/item/organ/internal/brain/slime/core = locate() in internal_organs
|
||||
if(core)
|
||||
return
|
||||
|
||||
//VOREStation Addition start: shadekin
|
||||
var/obj/item/organ/internal/brain/shadekin/s_brain = locate() in internal_organs
|
||||
if(s_brain)
|
||||
return
|
||||
//VOREStation Addition end: shadekin
|
||||
var/rad_mult = RADIATION_SPEED_COEFFICIENT * species.rad_removal_mod
|
||||
var/damage = 0
|
||||
radiation -= 1 * rad_mult
|
||||
if(radiation > species.rad_levels["safe"] && prob(25)) // Safe for a little over 2m at the recommended maximum safe dosage of 0.05Bq
|
||||
damage = 1
|
||||
|
||||
if (radiation > species.rad_levels["danger_1"])
|
||||
damage = 1
|
||||
radiation -= 1 * rad_mult
|
||||
if(!isSynthetic())
|
||||
if(prob(5) && prob(100 * RADIATION_SPEED_COEFFICIENT))
|
||||
radiation -= 5 * rad_mult
|
||||
to_chat(src, "<span class='warning'>You feel weak.</span>")
|
||||
Weaken(3)
|
||||
if(!lying)
|
||||
emote("collapse")
|
||||
if(prob(5) && prob(100 * RADIATION_SPEED_COEFFICIENT) && species.get_bodytype() == SPECIES_HUMAN) //apes go bald
|
||||
if((h_style != "Bald" || f_style != "Shaved" ))
|
||||
to_chat(src, "<span class='warning'>Your hair falls out.</span>")
|
||||
h_style = "Bald"
|
||||
f_style = "Shaved"
|
||||
update_hair()
|
||||
|
||||
if (radiation > species.rad_levels["danger_2"])
|
||||
damage = 3
|
||||
radiation -= 1 * rad_mult
|
||||
if(!isSynthetic())
|
||||
if(prob(5))
|
||||
take_overall_damage(0, 5 * RADIATION_SPEED_COEFFICIENT, used_weapon = "Radiation Burns")
|
||||
if(prob(1))
|
||||
to_chat(src, "<span class='warning'>You feel strange!</span>")
|
||||
adjustCloneLoss(5 * RADIATION_SPEED_COEFFICIENT)
|
||||
emote("gasp")
|
||||
|
||||
if (radiation > species.rad_levels["danger_3"])
|
||||
damage = 6
|
||||
radiation -= 4 * rad_mult
|
||||
|
||||
if(damage)
|
||||
damage *= species.radiation_mod
|
||||
adjustToxLoss(damage * RADIATION_SPEED_COEFFICIENT)
|
||||
updatehealth()
|
||||
if(!isSynthetic() && organs.len)
|
||||
var/obj/item/organ/external/O = pick(organs)
|
||||
if(istype(O)) O.add_autopsy_data("Radiation Poisoning", damage)
|
||||
@@ -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()
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
var/dirtslip = FALSE
|
||||
var/photosynthesizing = FALSE
|
||||
var/grows = FALSE
|
||||
var/shrinks = FALSE
|
||||
var/rad_levels = list("safe" = 2.5, "danger_1" = 50, "danger_2" = 75, "danger_3" = 150)
|
||||
var/rad_removal_mod = 1
|
||||
var/bite_mod = 1
|
||||
var/grab_resist_divisor_victims = 1
|
||||
var/grab_resist_divisor_self = 1
|
||||
var/grab_power_victims = 0
|
||||
var/grab_power_self = 0
|
||||
var/waking_speed = 1
|
||||
var/mudking = FALSE
|
||||
|
||||
/datum/species/handle_environment_special(var/mob/living/carbon/human/H)
|
||||
for(var/datum/trait/env_trait in env_traits)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#ifndef GAUSSIAN_RANDOM
|
||||
#define GAUSSIAN_RANDOM(vars...) ((-2*log(rand()))**0.5 * cos(6.28318530718*rand()))
|
||||
#endif
|
||||
|
||||
/datum/trait/hollow
|
||||
excludes = list(/datum/trait/densebones)
|
||||
|
||||
@@ -6,44 +10,288 @@
|
||||
desc = "Even the tiniest particles of dirt give you uneasy footing, even through several layers of footwear."
|
||||
cost = -5
|
||||
var_changes = list("dirtslip" = TRUE)
|
||||
excludes = list(/datum/trait/absorbent)
|
||||
|
||||
/datum/trait/less_blood
|
||||
name = "Low blood volume"
|
||||
desc = "You have 33.3% less blood volume compared to most species, making you more prone to blood loss issues."
|
||||
cost = -3
|
||||
var_changes = list("blood_volume" = 375)
|
||||
excludes = list(/datum/trait/less_blood_extreme,/datum/trait/more_blood,/datum/trait/more_blood_extreme)
|
||||
not_for_synths = TRUE
|
||||
|
||||
/datum/trait/less_blood_extreme
|
||||
name = "Extremely low blood volume"
|
||||
desc = "You have 60% less blood volume compared to most species, making you much more prone to blood loss issues."
|
||||
cost = -5
|
||||
var_changes = list("blood_volume" = 224)
|
||||
excludes = list(/datum/trait/less_blood,/datum/trait/more_blood,/datum/trait/more_blood_extreme)
|
||||
not_for_synths = TRUE
|
||||
|
||||
/datum/trait/scrawny
|
||||
name = "Scrawny"
|
||||
desc = "You have a much harder time breaking free of grabs as well as creating and holding onto grabs on other people."
|
||||
cost = -2
|
||||
var_changes = list("grab_resist_divisor_victims" = 0.5, "grab_resist_divisor_self" = 3, "grab_power_victims" = 1, "grab_power_self" = -1)
|
||||
|
||||
/datum/trait/extreme_slowdown
|
||||
name = "Extreme slowdown"
|
||||
desc = "You move EXTREMELY slower than baseline"
|
||||
cost = -8
|
||||
var_changes = list("slowdown" = 4.0)
|
||||
|
||||
/datum/trait/deep_sleeper
|
||||
name = "Deep Sleeper"
|
||||
desc = "When you fall asleep, it takes you twice as long to wake up."
|
||||
cost = -1
|
||||
var_changes = list("waking_speed" = 0.5)
|
||||
|
||||
/datum/trait/low_blood_sugar
|
||||
name = "Low blood sugar"
|
||||
desc = "If you let your nutrition get too low, you will start to experience adverse affects including hallucinations, unconsciousness, and weakness"
|
||||
cost = -2
|
||||
special_env = TRUE
|
||||
|
||||
/datum/trait/low_blood_sugar/handle_environment_special(var/mob/living/carbon/human/H)
|
||||
if(H.nutrition < 200 && prob(5))
|
||||
if(H.nutrition > 150)
|
||||
to_chat(H,"<span class='warning'>You start to feel noticeably weak as your stomach rumbles, begging for more food. Maybe you should eat something to keep your blood sugar up</span>")
|
||||
else if(H.nutrition > 100)
|
||||
to_chat(H,"<span class='warning'>You begin to feel rather weak, and your stomach rumbles loudly. You feel lightheaded and it's getting harder to think. You really need to eat something.</span>")
|
||||
else if(H.nutrition > 50)
|
||||
to_chat(H,"<span class='danger'>You're feeling very weak and lightheaded, and your stomach continously rumbles at you. You really need to eat something!</span>")
|
||||
else
|
||||
to_chat(H,"<span class='critical'>You're feeling extremely weak and lightheaded. You feel as though you might pass out any moment and your stomach is screaming for food by now! You should really find something to eat!</span>")
|
||||
if(H.nutrition < 150 && prob(15))
|
||||
H.Confuse(20)
|
||||
if(H.nutrition < 100 && prob(30))
|
||||
H.hallucination = max(50,H.hallucination+10)
|
||||
if(H.nutrition < 50 && prob(10))
|
||||
H.drowsyness = max(100,H.drowsyness+30)
|
||||
|
||||
/datum/trait/blindness
|
||||
name = "Permanently blind"
|
||||
desc = "You are blind. For whatever reason, nothing is able to change this fact, not even surgery. WARNING: YOU WILL NOT BE ABLE TO SEE ANY POSTS USING THE ME VERB, ONLY SUBTLE AND DIALOGUE ARE VIEWABLE TO YOU, YOU HAVE BEEN WARNED."
|
||||
cost = -8
|
||||
special_env = TRUE
|
||||
|
||||
/datum/trait/blindness/handle_environment_special(var/mob/living/carbon/human/H)
|
||||
H.sdisabilities |= BLIND //no matter what you do, the blindess still comes for you
|
||||
|
||||
/datum/trait/schizophrenia
|
||||
name = "Episodic hallucinations."
|
||||
desc = "You have a condition which causes you to spontaneously have hallucinations! Luckily for you, in the modern space age, our doctors have solutions for you, just make sure you don't forget to take your pills."
|
||||
cost = -3
|
||||
special_env = TRUE
|
||||
not_for_synths = TRUE
|
||||
var/hallucination_max = 60
|
||||
var/hallucination_increase = 3
|
||||
var/episode_length_nomeds_avg = 4000
|
||||
var/episode_length_nomeds_dev = 100
|
||||
var/episode_length_meds_avg = 2000
|
||||
var/episode_length_meds_dev = 500
|
||||
var/break_length_nomeds_avg = 3000
|
||||
var/break_length_nomeds_dev = 600
|
||||
var/break_length_meds_avg = 30000
|
||||
var/break_length_meds_dev = 7000
|
||||
var/list/episode = list("in_episode" = FALSE)
|
||||
|
||||
/datum/trait/schizophrenia/apply(var/datum/species/S,var/mob/living/carbon/human/H)
|
||||
..()
|
||||
episode["next_episode_begin"] = world.time + 6000
|
||||
episode["next_episode_end"] = world.time + 9000
|
||||
|
||||
/datum/trait/schizophrenia/handle_environment_special(var/mob/living/carbon/human/H)
|
||||
var/med_vol = get_med_volume(H)
|
||||
if(!episode["in_episode"])
|
||||
if(world.time > episode["next_episode_begin"])
|
||||
episode["meds_at_beginning"] = med_vol
|
||||
episode["in_episode"] = TRUE
|
||||
else if(episode["meds_at_end"] && !med_vol) //Meds ran out
|
||||
var/new_episode_begin = world.time + (episode["next_episode_begin"] - world.time)/10
|
||||
episode["next_episode_end"] = new_episode_begin + (episode["next_episode_end"] - episode["next_episode_begin"])
|
||||
episode["next_episode_begin"] = new_episode_begin
|
||||
episode["meds_at_end"] = FALSE
|
||||
else if(!episode["meds_at_end"] && med_vol) //Meds were taken between episodes
|
||||
var/new_episode_begin = world.time + (episode["next_episode_begin"] - world.time)*10
|
||||
episode["next_episode_end"] = new_episode_begin + (episode["next_episode_end"] - episode["next_episode_begin"])
|
||||
episode["next_episode_begin"] = new_episode_begin
|
||||
episode["meds_at_end"] = TRUE
|
||||
else
|
||||
if(world.time > episode["next_episode_end"])
|
||||
episode["meds_at_end"] = med_vol
|
||||
episode["in_episode"] = FALSE
|
||||
var/break_length_dev = med_vol ? break_length_meds_dev : break_length_nomeds_dev
|
||||
var/break_length_avg = med_vol ? break_length_meds_avg : break_length_nomeds_avg
|
||||
var/episode_length_dev = med_vol ? episode_length_meds_dev : episode_length_nomeds_dev
|
||||
var/episode_length_avg = med_vol ? episode_length_meds_avg : episode_length_nomeds_avg
|
||||
episode["next_episode_begin"] = world.time + max(120,GAUSSIAN_RANDOM() * break_length_dev + break_length_avg)
|
||||
episode["next_episode_end"] = episode["next_episode_begin"] + max(120,GAUSSIAN_RANDOM() * episode_length_dev + episode_length_avg)
|
||||
else
|
||||
if(!episode["meds_at_beginning"] && med_vol)
|
||||
episode["next_episode_end"] = world.time + (episode["next_episode_end"] - world.time)/8
|
||||
H.hallucination = min(hallucination_max,H.hallucination + hallucination_increase)
|
||||
|
||||
/datum/trait/schizophrenia/proc/get_med_volume(var/mob/living/carbon/human/H)
|
||||
var/total_vol = 0
|
||||
for(var/datum/reagent/reagent in H.bloodstr.reagent_list)
|
||||
if(istype(reagent,/datum/reagent/tercozolam))
|
||||
total_vol += reagent.volume
|
||||
for(var/datum/reagent/reagent in H.ingested.reagent_list)
|
||||
if(istype(reagent,/datum/reagent/tercozolam))
|
||||
total_vol += reagent.volume
|
||||
return total_vol
|
||||
/datum/trait/agoraphobia
|
||||
name = "Agoraphobia"
|
||||
desc = "You very much dislike being in crowded places. When in the company of more than two other people, you start to panic and experience adverse effects."
|
||||
cost = -3
|
||||
var/warning_cap = 400
|
||||
var/hallucination_cap = 25
|
||||
var/escalation_speed = 0.8
|
||||
special_env = TRUE
|
||||
excludes = list(/datum/trait/lonely,/datum/trait/lonely/major)
|
||||
|
||||
/datum/trait/agoraphobia/handle_environment_special(var/mob/living/carbon/human/H)
|
||||
spawn(0)
|
||||
var/list/in_range = list()
|
||||
// If they're dead or unconcious they're a bit beyond this kind of thing.
|
||||
if(H.stat)
|
||||
return
|
||||
// No point processing if we're already stressing the hell out.
|
||||
if(H.hallucination >= hallucination_cap && H.loneliness_stage >= warning_cap)
|
||||
return
|
||||
in_range |= check_mob_company(H,H) //Checks our item slots and bellies for any people.
|
||||
in_range |= belly_check(H,H.loc) //Recursive check if we're in anyones bellies, are they in anyone's belly, etc.
|
||||
in_range |= holder_check(H,H.loc) //Recursive check if someone's holding us, is anyone holding them, etc.
|
||||
|
||||
// Check for company.
|
||||
for(var/mob/living/M in viewers(get_turf(H)))
|
||||
in_range |= check_mob_company(H,M)
|
||||
|
||||
for(var/obj/effect/overlay/aiholo/A in range(5, H))
|
||||
in_range |= A
|
||||
|
||||
if(in_range.len > 2)
|
||||
if(H.loneliness_stage < warning_cap)
|
||||
H.loneliness_stage = min(warning_cap,H.loneliness_stage+escalation_speed)
|
||||
handle_loneliness(H)
|
||||
if(H.loneliness_stage >= warning_cap && H.hallucination < hallucination_cap)
|
||||
H.hallucination = min(hallucination_cap,H.hallucination+2.5*escalation_speed)
|
||||
else
|
||||
H.loneliness_stage = max(H.loneliness_stage-4,0)
|
||||
|
||||
|
||||
/datum/trait/agoraphobia/proc/handle_loneliness(var/mob/living/carbon/human/H)
|
||||
var/ms = ""
|
||||
if(H.loneliness_stage == escalation_speed)
|
||||
ms = "You notice there's more people than you feel comfortable with around you..."
|
||||
if(H.loneliness_stage >= 50)
|
||||
ms = "You start to feel anxious from the number of people around you."
|
||||
if(H.loneliness_stage >= 250)
|
||||
ms = "[pick("You don't think you can last much longer with this much company!", "You should go find some space!")]"
|
||||
if(H.stuttering < hallucination_cap)
|
||||
H.stuttering += 5
|
||||
if(H.loneliness_stage >= warning_cap)
|
||||
ms = "<span class='danger'><b>[pick("Why am I still here? I have to leave and get some space!", "Please, just let me be alone!", "I need to be alone!")]</b></span>"
|
||||
if(world.time < H.next_loneliness_time)
|
||||
return
|
||||
if(ms != "")
|
||||
to_chat(H, ms)
|
||||
H.next_loneliness_time = world.time+500
|
||||
|
||||
/datum/trait/agoraphobia/proc/find_held_by(var/atom/item)
|
||||
if(!item || !istype(item))
|
||||
return null
|
||||
else if(istype(item,/mob/living))
|
||||
return item
|
||||
else
|
||||
return find_held_by(item.loc)
|
||||
|
||||
/datum/trait/agoraphobia/proc/holder_check(var/mob/living/carbon/human/H,var/obj/item/weapon/holder/H_holder)
|
||||
var/list/in_range = list()
|
||||
if(istype(H_holder))
|
||||
var/mob/living/held_by = find_held_by(H_holder)
|
||||
if(held_by)
|
||||
in_range |= check_mob_company(H,held_by,FALSE)
|
||||
in_range |= holder_check(H,held_by)
|
||||
return in_range
|
||||
|
||||
/datum/trait/agoraphobia/proc/belly_check(var/mob/living/carbon/human/H,var/obj/belly/B)
|
||||
var/list/in_range = list()
|
||||
if(istype(B))
|
||||
in_range |= check_mob_company(H,B.owner,FALSE)
|
||||
if(isbelly(B.owner.loc))
|
||||
in_range |= belly_check(H,B.owner.loc)
|
||||
return in_range
|
||||
|
||||
/datum/trait/agoraphobia/proc/check_mob_company(var/mob/living/carbon/human/H,var/mob/living/M,var/invis_matters = TRUE)
|
||||
var/list/in_range = list()
|
||||
var/social_check = !istype(M, /mob/living/carbon) && !istype(M, /mob/living/silicon/robot)
|
||||
var/ckey_check = !M.ckey
|
||||
var/overall_checks = M == H || M.stat == DEAD || social_check || ckey_check
|
||||
if(!istype(M))
|
||||
return in_range
|
||||
if(invis_matters && M.invisibility > H.see_invisible)
|
||||
return in_range
|
||||
if(!overall_checks)
|
||||
in_range |= M
|
||||
if(M.vore_organs)
|
||||
for(var/obj/belly/B in M.vore_organs)
|
||||
for(var/mob/living/content in B.contents)
|
||||
if(istype(content))
|
||||
in_range |= check_mob_company(H,content)
|
||||
in_range |= check_contents(M,H)
|
||||
return in_range
|
||||
|
||||
/datum/trait/agoraphobia/proc/check_contents(var/atom/item,var/mob/living/carbon/human/H,var/max_layer = 3,var/current_layer = 1)
|
||||
var/list/in_range = list()
|
||||
if(!item || !istype(item) || current_layer > max_layer)
|
||||
return in_range
|
||||
for(var/datum/content in item.contents)
|
||||
if(istype(content,/obj/item/weapon/holder))
|
||||
var/obj/item/weapon/holder/contentholder = content
|
||||
in_range |= check_mob_company(H,contentholder.held_mob)
|
||||
else
|
||||
in_range |= check_contents(content,H,max_layer,current_layer+1)
|
||||
return in_range
|
||||
|
||||
/datum/trait/lonely
|
||||
name = "Minor loneliness vulnerability"
|
||||
desc = "You're very prone to loneliness! Being alone for extended periods of time causes adverse effects. Most mobs will cure this loneliness as long as they aren't hostile."
|
||||
cost = -2
|
||||
var/warning_cap = 400
|
||||
var/only_people = FALSE
|
||||
var/hallucination_cap = 25
|
||||
var/escalation_speed = 0.8
|
||||
cost = -2
|
||||
special_env = TRUE
|
||||
excludes = list(/datum/trait/lonely/major)
|
||||
excludes = list(/datum/trait/lonely/major,/datum/trait/agoraphobia)
|
||||
|
||||
/datum/trait/lonely/major
|
||||
name = "Major loneliness vulnerability"
|
||||
desc = "You're extremely prone to loneliness! Being alone for extended periods of time causes adverse effects. Most mobs won't be enough to cure this loneliness, you need other social beings."
|
||||
cost = -5
|
||||
warning_cap = 300
|
||||
hallucination_cap = 50
|
||||
escalation_speed = 1.3
|
||||
only_people = TRUE
|
||||
cost = -5
|
||||
special_env = TRUE
|
||||
excludes = list(/datum/trait/lonely)
|
||||
excludes = list(/datum/trait/lonely,/datum/trait/agoraphobia)
|
||||
|
||||
/datum/trait/lonely/proc/sub_loneliness(var/mob/living/carbon/human/H,var/amount = 4)
|
||||
H.loneliness_stage = max(H.loneliness_stage - 4, 0)
|
||||
if(world.time >= H.next_loneliness_time && H.loneliness_stage > 0)
|
||||
to_chat(H, "The nearby company calms you down...")
|
||||
H.next_loneliness_time = world.time+500
|
||||
|
||||
/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))
|
||||
var/social_check = only_people && !istype(M, /mob/living/carbon) && !istype(M, /mob/living/silicon/robot)
|
||||
var/self_invisible_check = M == H || M.invisibility > H.see_invisible
|
||||
var/ckey_check = only_people && !M.ckey
|
||||
var/overall_checks = M.stat == DEAD || social_check || ckey_check
|
||||
if(self_invisible_check)
|
||||
return 0
|
||||
if(M == H || M.stat == DEAD || M.invisibility > H.see_invisible)
|
||||
return 0
|
||||
if(only_people && !M.ckey)
|
||||
return 0
|
||||
if(M.faction == "neutral" || M.faction == H.faction)
|
||||
if(H.loneliness_stage > 0)
|
||||
H.loneliness_stage -= 4
|
||||
if(H.loneliness_stage < 0)
|
||||
H.loneliness_stage = 0
|
||||
if(world.time >= H.next_loneliness_time)
|
||||
to_chat(H, "The nearby company calms you down...")
|
||||
H.next_loneliness_time = world.time+500
|
||||
if((M.faction == "neutral" || M.faction == H.faction) && !overall_checks)
|
||||
sub_loneliness(H)
|
||||
return 1
|
||||
else
|
||||
if(M.vore_organs)
|
||||
@@ -53,6 +301,19 @@
|
||||
check_mob_company(H,content)
|
||||
return 0
|
||||
|
||||
/datum/trait/lonely/proc/check_contents(var/atom/item,var/mob/living/carbon/human/H,var/max_layer = 3,var/current_layer = 1)
|
||||
if(!item || !istype(item) || current_layer > max_layer)
|
||||
return 0
|
||||
for(var/datum/content in item.contents)
|
||||
if(istype(content,/obj/item/weapon/holder))
|
||||
var/obj/item/weapon/holder/contentholder = content
|
||||
if(check_mob_company(H,contentholder.held_mob))
|
||||
return 1
|
||||
else
|
||||
if(check_contents(content,H,max_layer,current_layer+1))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/trait/lonely/handle_environment_special(var/mob/living/carbon/human/H)
|
||||
spawn(0)
|
||||
// If they're dead or unconcious they're a bit beyond this kind of thing.
|
||||
@@ -63,17 +324,19 @@
|
||||
return
|
||||
// Vored? Not gonna get frightened.
|
||||
if(isbelly(H.loc))
|
||||
if(H.loneliness_stage > 0)
|
||||
H.loneliness_stage -= 4
|
||||
sub_loneliness(H)
|
||||
return
|
||||
if(istype(H.loc, /obj/item/weapon/holder))
|
||||
if(H.loneliness_stage > 0)
|
||||
H.loneliness_stage -= 4
|
||||
sub_loneliness(H)
|
||||
return
|
||||
// Check for company.
|
||||
for(var/mob/living/M in viewers(H))
|
||||
if(check_contents(H,H)) //Check our item slots and storage for any micros.
|
||||
sub_loneliness(H)
|
||||
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)
|
||||
@@ -81,21 +344,9 @@
|
||||
if(check_mob_company(H,content))
|
||||
return
|
||||
for(var/obj/item/weapon/holder/micro/M in range(1, H))
|
||||
if(H.loneliness_stage > 0)
|
||||
H.loneliness_stage -= 4
|
||||
if(H.loneliness_stage < 0)
|
||||
H.loneliness_stage = 0
|
||||
if(world.time >= H.next_loneliness_time)
|
||||
to_chat(H, "[M] calms you down...")
|
||||
H.next_loneliness_time = world.time+500
|
||||
sub_loneliness(H)
|
||||
for(var/obj/effect/overlay/aiholo/A in range(5, H))
|
||||
if(H.loneliness_stage > 0)
|
||||
H.loneliness_stage -= 4
|
||||
if(H.loneliness_stage < 0)
|
||||
H.loneliness_stage = 0
|
||||
if(world.time >= H.next_loneliness_time)
|
||||
to_chat(H, "[A] calms you down...")
|
||||
H.next_loneliness_time = world.time+500
|
||||
sub_loneliness(H)
|
||||
|
||||
// No company? Suffer :(
|
||||
if(H.loneliness_stage < warning_cap)
|
||||
|
||||
@@ -20,4 +20,22 @@
|
||||
name = "Growing"
|
||||
desc = "After you consume enough nutrition, you start to slowly grow while metabolizing nutrition faster."
|
||||
cost = 0
|
||||
var_changes = list("grows" = TRUE)
|
||||
var_changes = list("grows" = TRUE)
|
||||
|
||||
/datum/trait/nutritionshrink
|
||||
name = "Shrinking"
|
||||
desc = "If you don't eat enough, your body starts shrinking to make up the difference!"
|
||||
cost = 0
|
||||
var_changes = list("shrinks" = TRUE)
|
||||
|
||||
/datum/trait/mudking
|
||||
name = "Mudking"
|
||||
desc = "Somehow you are so filthy that tiles get dirty four times as quick from you walking on them."
|
||||
cost = 0
|
||||
var_changes = list("mudking" = TRUE)
|
||||
|
||||
/datum/trait/singularity_metabolism
|
||||
name = "Singularity Metabolism"
|
||||
desc = "You are insanely hungry. You can seemingly never get enough to eat. Perhaps you had a singularity as an ancestor, or maybe one is currently living inside of your gut."
|
||||
cost = 0
|
||||
var_changes = list("metabolism_rate" = 2, "hunger_factor" = 1.6, "metabolism" = 0.012) //2x metabolism speed, 32x hunger speed
|
||||
@@ -34,4 +34,192 @@
|
||||
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.
|
||||
|
||||
/datum/trait/rad_resistance
|
||||
name = "Radiation Resistance"
|
||||
desc = "You are generally more resistant to radiation, and it dissipates faster from your body."
|
||||
cost = 2
|
||||
var_changes = list("radiation_mod" = 0.65, "rad_removal_mod" = 3.5, "rad_levels" = list("safe" = 20, "danger_1" = 75, "danger_2" = 100, "danger_3" = 200))
|
||||
|
||||
/datum/trait/rad_resistance_extreme
|
||||
name = "Extreme Radiation Resistance"
|
||||
desc = "You are much more resistant to radiation, and it dissipates much faster from your body."
|
||||
cost = 4
|
||||
var_changes = list("radiation_mod" = 0.5, "rad_removal_mod" = 5, "rad_levels" = list("safe" = 40, "danger_1" = 100, "danger_2" = 150, "danger_3" = 250))
|
||||
|
||||
/datum/trait/more_blood
|
||||
name = "High blood volume"
|
||||
desc = "You have much 50% more blood than most other people"
|
||||
cost = 3
|
||||
var_changes = list("blood_volume" = 840)
|
||||
excludes = list(/datum/trait/more_blood_extreme,/datum/trait/less_blood,/datum/trait/less_blood_extreme)
|
||||
not_for_synths = TRUE
|
||||
|
||||
/datum/trait/more_blood_extreme
|
||||
name = "Very high blood volume"
|
||||
desc = "You have much 150% more blood than most other people"
|
||||
cost = 6
|
||||
var_changes = list("blood_volume" = 1400)
|
||||
excludes = list(/datum/trait/more_blood,/datum/trait/less_blood,/datum/trait/less_blood_extreme)
|
||||
not_for_synths = TRUE
|
||||
|
||||
/datum/trait/heavyweight
|
||||
name = "Heavyweight"
|
||||
desc = "You are more heavyweight or otherwise more sturdy than most species, and as such, it's much more difficult to move you."
|
||||
cost = 2
|
||||
|
||||
/datum/trait/heavyweight/apply(var/datum/species/S,var/mob/living/carbon/human/H)
|
||||
..()
|
||||
H.mob_bump_flag = HEAVY
|
||||
|
||||
/datum/trait/table_passer
|
||||
name = "Table passer"
|
||||
desc = "You move over or under tables with ease of a Teshari."
|
||||
cost = 2
|
||||
|
||||
/datum/trait/table_passer/apply(var/datum/species/S,var/mob/living/carbon/human/H)
|
||||
..()
|
||||
H.pass_flags = PASSTABLE
|
||||
|
||||
|
||||
/datum/trait/big_mouth
|
||||
name = "Big mouth"
|
||||
desc = "It takes half as many bites to finish food as it does for most people."
|
||||
cost = 1
|
||||
var_changes = list("bite_mod" = 2)
|
||||
|
||||
/datum/trait/grappling_expert
|
||||
name = "Grappling expert"
|
||||
desc = "Your grabs are much harder to escape from, and you are better at escaping from other's grabs!"
|
||||
cost = 3
|
||||
var_changes = list("grab_resist_divisor_victims" = 3, "grab_resist_divisor_self" = 0.5, "grab_power_victims" = -1, "grab_power_self" = 1)
|
||||
|
||||
/datum/trait/big_mouth_extreme
|
||||
name = "Giant mouth"
|
||||
desc = "It takes a quarter as many bites to finish food as it does for most people."
|
||||
cost = 3
|
||||
var_changes = list("bite_mod" = 4)
|
||||
|
||||
/datum/trait/absorbent
|
||||
name = "Absorbent"
|
||||
desc = "You are able to clean messes just by walking over them, and gain nutrition from doing so!"
|
||||
cost = 2
|
||||
special_env = TRUE
|
||||
excludes = list(/datum/trait/slipperydirt)
|
||||
|
||||
/datum/trait/absorbent/handle_environment_special(var/mob/living/carbon/human/H)
|
||||
var/turf/T = get_turf(H)
|
||||
if(istype(T))
|
||||
if(!(H.shoes || (H.wear_suit && (H.wear_suit.body_parts_covered & FEET))))
|
||||
for(var/obj/O in T)
|
||||
if(O.clean_blood())
|
||||
H.adjust_nutrition(rand(5, 15))
|
||||
if (istype(T, /turf/simulated))
|
||||
var/turf/simulated/S = T
|
||||
if(T.clean_blood())
|
||||
H.adjust_nutrition(rand(10, 20))
|
||||
if(S.dirt > 50)
|
||||
S.dirt = 0
|
||||
H.adjust_nutrition(rand(10, 20))
|
||||
if(H.clean_blood(1))
|
||||
H.adjust_nutrition(rand(5, 15))
|
||||
if(H.r_hand)
|
||||
if(H.r_hand.clean_blood())
|
||||
H.adjust_nutrition(rand(5, 15))
|
||||
if(H.l_hand)
|
||||
if(H.l_hand.clean_blood())
|
||||
H.adjust_nutrition(rand(5, 15))
|
||||
if(H.head)
|
||||
if(H.head.clean_blood())
|
||||
H.update_inv_head(0)
|
||||
H.adjust_nutrition(rand(5, 15))
|
||||
if(H.wear_suit)
|
||||
if(H.wear_suit.clean_blood())
|
||||
H.update_inv_wear_suit(0)
|
||||
H.adjust_nutrition(rand(5, 15))
|
||||
if(H.w_uniform)
|
||||
if(H.w_uniform.clean_blood())
|
||||
H.update_inv_w_uniform(0)
|
||||
H.adjust_nutrition(rand(5, 15))
|
||||
|
||||
/datum/trait/adrenaline_rush
|
||||
name = "Adrenaline Rush"
|
||||
desc = "When you get critically damaged, you'll have an adrenaline rush before going down, giving you another chance to finish the fight, or get to safety."
|
||||
cost = 6
|
||||
special_env = TRUE
|
||||
not_for_synths = TRUE
|
||||
var/last_adrenaline_rush
|
||||
|
||||
/datum/trait/adrenaline_rush/handle_environment_special(var/mob/living/carbon/human/H)
|
||||
if(!(H.health<0))
|
||||
return
|
||||
if(last_adrenaline_rush && last_adrenaline_rush + 18000 > world.time)
|
||||
return
|
||||
last_adrenaline_rush = world.time
|
||||
log_and_message_admins("[H]'s adrenaline rush trait just activated!")
|
||||
H.add_modifier(/datum/modifier/adrenaline,300)
|
||||
|
||||
/datum/modifier/adrenaline
|
||||
name = "Adrenaline Rush"
|
||||
desc = "A rush of adrenaline, usually caused by near death in situations."
|
||||
on_created_text = "<span class='danger'>You suddenly feel adrenaline pumping through your veins as your body refuses to give up! You feel stronger, and faster, and the pain fades away quickly.</span>"
|
||||
on_expired_text = "<span class='danger'>You feel your body finally give in once more as the adrenaline subsides. The pain returns in full blast, along with your strength fading once more.</span>"
|
||||
|
||||
disable_duration_percent = 0 //Immune to being disabled.
|
||||
pain_immunity = TRUE //Immune to pain
|
||||
max_health_flat = 25 //Temporary health boost.
|
||||
incoming_damage_percent = 0.8 //Slight damage immunity
|
||||
incoming_oxy_damage_percent = 0.1 //Temporary oxyloss slowdown
|
||||
|
||||
outgoing_melee_damage_percent = 2 //Muscles are in overdrive
|
||||
attack_speed_percent = 0.5 //Muscles are in overdrive
|
||||
slowdown = -11 //Muscles are in overdrive
|
||||
evasion = 20 //Increased focus
|
||||
accuracy = 25 //Increased focus
|
||||
accuracy_dispersion = -25 //Increased focus
|
||||
pulse_modifier = 2 //Heart is in overdrive
|
||||
bleeding_rate_percent = 1.25 //Bleed more with higher blood pressure.
|
||||
metabolism_percent = 2.5 //Metabolism in overdrive
|
||||
|
||||
var/original_length
|
||||
var/list/original_values
|
||||
|
||||
/datum/modifier/adrenaline/on_applied()
|
||||
original_length = expire_at - world.time
|
||||
original_values = list("stun" = holder.halloss*1.5, "weaken" = holder.weakened*1.5, "paralyze" = holder.paralysis*1.5, "stutter" = holder.stuttering*1.5, "eye_blur" = holder.eye_blurry*1.5, "drowsy" = holder.drowsyness*1.5, "agony" = holder.halloss*1.5, "confuse" = holder.confused*1.5)
|
||||
|
||||
/datum/modifier/adrenaline/tick()
|
||||
holder.halloss = 0
|
||||
holder.weakened = 0
|
||||
holder.paralysis = 0
|
||||
holder.stuttering = 0
|
||||
holder.eye_blurry = 0
|
||||
holder.drowsyness = 0
|
||||
holder.halloss = 0
|
||||
holder.confused = 0
|
||||
holder.stunned = 0
|
||||
|
||||
/datum/modifier/adrenaline/on_expire() //Your time is up, time to suffer the consequences.
|
||||
holder.apply_effects(original_values["stun"] + 30,original_values["weaken"] + 20,original_values["paralyze"] + 15,0,original_values["stutter"] + 40,original_values["eye_blur"] + 20,original_values["drowsy"] + 75,original_values["agony"])
|
||||
holder.Confuse(original_values["confused"])
|
||||
holder.add_modifier(/datum/modifier/adrenaline_recovery,original_length*17.5)
|
||||
|
||||
/datum/modifier/adrenaline_recovery
|
||||
name = "Adrenaline detox"
|
||||
desc = "After an adrenaline rush, one will find themselves suffering from adrenaline detox, which is their body recovering from an intense adrenaline rush."
|
||||
on_created_text = "<span class='danger'>Your body aches and groans, forcing you into a period of rest as it recovers from the intense adrenaline rush.</span>"
|
||||
on_expired_text = "<span class='notice'>You finally recover from your adrenaline rush, your body returning to it's normal state.</span>"
|
||||
|
||||
disable_duration_percent = 1.35
|
||||
outgoing_melee_damage_percent = 0.75
|
||||
attack_speed_percent = 2
|
||||
slowdown = 2
|
||||
evasion = -20
|
||||
bleeding_rate_percent = 0.8
|
||||
pulse_modifier = 0.5
|
||||
metabolism_percent = 0.5
|
||||
accuracy = -25
|
||||
accuracy_dispersion = 25
|
||||
incoming_hal_damage_percent = 1.75
|
||||
incoming_oxy_damage_percent = 1.25
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -1462,4 +1484,4 @@ default behaviour is:
|
||||
// Tries to turn off things that let you see through walls, like mesons.
|
||||
// Each mob does vision a bit differently so this is just for inheritence and also so overrided procs can make the vision apply instantly if they call `..()`.
|
||||
/mob/living/proc/disable_spoiler_vision()
|
||||
handle_vision()
|
||||
handle_vision()
|
||||
|
||||
@@ -74,4 +74,4 @@
|
||||
var/image/selected_image = null // Used for buildmode AI control stuff.
|
||||
|
||||
var/inventory_panel_type = /datum/inventory_panel
|
||||
var/datum/inventory_panel/inventory_panel
|
||||
var/datum/inventory_panel/inventory_panel
|
||||
|
||||
@@ -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)
|
||||
|
||||
..()
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
@@ -726,4 +728,4 @@
|
||||
recycles = FALSE
|
||||
max_item_count = 25
|
||||
|
||||
#undef SLEEPER_INJECT_COST
|
||||
#undef SLEEPER_INJECT_COST
|
||||
|
||||
@@ -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
|
||||
..(icon_gib,1,icon) // we need to specify where the gib animation is stored
|
||||
|
||||
@@ -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
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
handle_special()
|
||||
|
||||
handle_guts()
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -94,7 +96,7 @@
|
||||
throw_alert("oxy", /obj/screen/alert/too_much_oxy)
|
||||
else
|
||||
clear_alert("oxy")
|
||||
|
||||
|
||||
if(min_tox && Environment.gas["phoron"] < min_tox)
|
||||
atmos_unsuitable = 2
|
||||
throw_alert("tox_in_air", /obj/screen/alert/not_enough_tox)
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -6,4 +6,17 @@
|
||||
response_disarm = "shoos"
|
||||
response_harm = "hits"
|
||||
|
||||
ai_holder_type = /datum/ai_holder/simple_mob/melee
|
||||
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\
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) )
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -385,8 +385,19 @@
|
||||
|
||||
//It's easier to break out of a grab by a smaller mob
|
||||
break_strength += max(size_difference(affecting, assailant), 0)
|
||||
//CHOMPEdit Begin
|
||||
var/prob_mult = 1
|
||||
var/mob/living/carbon/human/grabbee = affecting
|
||||
var/mob/living/carbon/human/grabber = assailant
|
||||
if(istype(grabbee))
|
||||
prob_mult /= grabbee.species.grab_resist_divisor_self
|
||||
break_strength += grabbee.species.grab_power_self
|
||||
if(istype(grabber))
|
||||
prob_mult /= grabber.species.grab_resist_divisor_victims
|
||||
break_strength += grabber.species.grab_power_victims
|
||||
|
||||
var/break_chance = break_chance_table[CLAMP(break_strength, 1, break_chance_table.len)]
|
||||
var/break_chance = CLAMP(prob_mult*break_chance_table[CLAMP(break_strength, 1, break_chance_table.len)],0,100)
|
||||
//CHOMPEdit End
|
||||
if(prob(break_chance))
|
||||
if(state == GRAB_KILL)
|
||||
reset_kill_state()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user