git-svn-id: http://tgstation13.googlecode.com/svn/trunk@2 316c924e-a436-60f5-8080-3fe189b3f50e

This commit is contained in:
only.lurking
2010-08-23 14:29:20 +00:00
parent 757ea7b077
commit 662c08272a
919 changed files with 136852 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
/*
Quick overview:
Pipes combine to form pipelines
Pipelines and other atmospheric objects combine to form pipe_networks
Note: A single pipe_network represents a completely open space
Pipes -> Pipelines
Pipelines + Other Objects -> Pipe network
*/
obj/machinery/atmospherics
anchored = 1
var/initialize_directions = 0
process()
build_network()
..()
proc
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
// Check to see if should be added to network. Add self if so and adjust variables appropriately.
// Note don't forget to have neighbors look as well!
return null
build_network()
// Called to build a network from this node
return null
return_network(obj/machinery/atmospherics/reference)
// Returns pipe_network associated with connection to reference
// Notes: should create network if necessary
// Should never return null
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
// Used when two pipe_networks are combining
return_network_air(datum/network/reference)
// Return a list of gas_mixture(s) in the object
// associated with reference pipe_network for use in rebuilding the networks gases list
// Is permitted to return null
disconnect(obj/machinery/atmospherics/reference)
update_icon()
return null

View File

@@ -0,0 +1,129 @@
obj/machinery/atmospherics/binary
dir = SOUTH
initialize_directions = SOUTH|NORTH
var/datum/gas_mixture/air1
var/datum/gas_mixture/air2
var/obj/machinery/atmospherics/node1
var/obj/machinery/atmospherics/node2
var/datum/pipe_network/network1
var/datum/pipe_network/network2
New()
..()
switch(dir)
if(NORTH)
initialize_directions = NORTH|SOUTH
if(SOUTH)
initialize_directions = NORTH|SOUTH
if(EAST)
initialize_directions = EAST|WEST
if(WEST)
initialize_directions = EAST|WEST
air1 = new
air2 = new
air1.volume = 200
air2.volume = 200
// Housekeeping and pipe network stuff below
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network1 = new_network
else if(reference == node2)
network2 = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
Del()
loc = null
if(node1)
node1.disconnect(src)
del(network1)
if(node2)
node2.disconnect(src)
del(network2)
node1 = null
node2 = null
..()
initialize()
if(node1 && node2) return
var/node2_connect = dir
var/node1_connect = turn(dir, 180)
for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
update_icon()
build_network()
if(!network1 && node1)
network1 = new /datum/pipe_network()
network1.normal_members += src
network1.build_network(node1, src)
if(!network2 && node2)
network2 = new /datum/pipe_network()
network2.normal_members += src
network2.build_network(node2, src)
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network1
if(reference==node2)
return network2
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network1 == old_network)
network1 = new_network
if(network2 == old_network)
network2 = new_network
return 1
return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network1 == reference)
results += air1
if(network2 == reference)
results += air2
return results
disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
del(network1)
node1 = null
else if(reference==node2)
del(network2)
node2 = null
return null

View File

@@ -0,0 +1,64 @@
//node1, air1, network1 correspond to input
//node2, air2, network2 correspond to output
/obj/machinery/atmospherics/binary/circulator
name = "circulator/heat exchanger"
desc = "A gas circulator pump and heat exchanger."
icon = 'pipes.dmi'
icon_state = "circ1-off"
var/side = 1 // 1=left 2=right
var/status = 0
var/last_pressure_delta = 0
anchored = 1.0
density = 1
proc/return_transfer_air()
var/output_starting_pressure = air2.return_pressure()
var/input_starting_pressure = air1.return_pressure()
if(output_starting_pressure >= input_starting_pressure-10)
//Need at least 10 KPa difference to overcome friction in the mechanism
last_pressure_delta = 0
return null
//Calculate necessary moles to transfer using PV = nRT
if((air1.total_moles() > 0) && (air1.temperature>0))
var/pressure_delta = (input_starting_pressure - output_starting_pressure)/2
var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
last_pressure_delta = pressure_delta
//Actually transfer the gas
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
if(network1)
network1.update = 1
if(network2)
network2.update = 1
return removed
else
last_pressure_delta = 0
process()
..()
update_icon()
update_icon()
if(stat & (BROKEN|NOPOWER))
icon_state = "circ[side]-p"
else if(last_pressure_delta > 0)
if(last_pressure_delta > ONE_ATMOSPHERE)
icon_state = "circ[side]-run"
else
icon_state = "circ[side]-slow"
else
icon_state = "circ[side]-off"
return 1

View File

@@ -0,0 +1,198 @@
/obj/machinery/atmospherics/binary/dp_vent_pump
icon = 'dp_vent_pump.dmi'
icon_state = "off"
//node2 is output port
//node1 is input port
name = "Dual Port Air Vent"
desc = "Has a valve and pump attached to it. There are two ports."
level = 1
high_volume
name = "Large Dual Port Air Vent"
New()
..()
air1.volume = 1000
air2.volume = 1000
var/on = 0
var/pump_direction = 1 //0 = siphoning, 1 = releasing
var/external_pressure_bound = ONE_ATMOSPHERE
var/input_pressure_min = 0
var/output_pressure_max = 0
var/pressure_checks = 1
//1: Do not pass external_pressure_bound
//2: Do not pass input_pressure_min
//4: Do not pass output_pressure_max
update_icon()
if(on)
if(pump_direction)
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
on = 0
return
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(on)
if(pump_direction)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
on = 0
return
process()
..()
if(!on)
return 0
var/datum/gas_mixture/environment = loc.return_air()
var/environment_pressure = environment.return_pressure()
if(pump_direction) //input -> external
var/pressure_delta = 10000
if(pressure_checks&1)
pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure))
if(pressure_checks&2)
pressure_delta = min(pressure_delta, (air1.return_pressure() - input_pressure_min))
if(pressure_delta > 0)
if(air1.temperature > 0)
var/transfer_moles = pressure_delta*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
loc.assume_air(removed)
if(network1)
network1.update = 1
else //external -> output
var/pressure_delta = 10000
if(pressure_checks&1)
pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound))
if(pressure_checks&4)
pressure_delta = min(pressure_delta, (output_pressure_max - air2.return_pressure()))
if(pressure_delta > 0)
if(environment.temperature > 0)
var/transfer_moles = pressure_delta*air2.volume/(environment.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
air2.merge(removed)
if(network2)
network2.update = 1
return 1
//Radio remote control
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, "[frequency]")
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, "[frequency]")
broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data["tag"] = id
signal.data["device"] = "ADVP"
signal.data["power"] = on?("on"):("off")
signal.data["direction"] = pump_direction?("release"):("siphon")
signal.data["checks"] = pressure_checks
signal.data["input"] = input_pressure_min
signal.data["output"] = output_pressure_max
signal.data["external"] = external_pressure_bound
radio_connection.post_signal(src, signal)
return 1
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
initialize()
..()
if(frequency)
set_frequency(frequency)
receive_signal(datum/signal/signal)
if(signal.data["tag"] && (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("power_on")
on = 1
if("power_off")
on = 0
if("power_toggle")
on = !on
if("set_direction")
var/number = text2num(signal.data["parameter"])
if(number > 0.5)
pump_direction = 1
else
pump_direction = 0
if("set_checks")
var/number = round(text2num(signal.data["parameter"]),1)
pressure_checks = number
if("purge")
pressure_checks &= ~1
pump_direction = 0
if("stabalize")
pressure_checks |= 1
pump_direction = 1
if("set_input_pressure")
var/number = text2num(signal.data["parameter"])
number = min(max(number, 0), ONE_ATMOSPHERE*50)
input_pressure_min = number
if("set_output_pressure")
var/number = text2num(signal.data["parameter"])
number = min(max(number, 0), ONE_ATMOSPHERE*50)
output_pressure_max = number
if("set_external_pressure")
var/number = text2num(signal.data["parameter"])
number = min(max(number, 0), ONE_ATMOSPHERE*50)
external_pressure_bound = number
if(signal.data["tag"])
spawn(5) broadcast_status()
update_icon()

View File

@@ -0,0 +1,55 @@
obj/machinery/atmospherics/binary/passive_gate
//Tries to achieve target pressure at output (like a normal pump) except
// Uses no power but can not transfer gases from a low pressure area to a high pressure area
icon = 'passive_gate.dmi'
icon_state = "intact_off"
name = "Passive gate"
desc = "A one-way air valve that does not require power"
var/on = 0
var/target_pressure = ONE_ATMOSPHERE
update_icon()
if(node1&&node2)
icon_state = "intact_[on?("on"):("off")]"
else
if(node1)
icon_state = "exposed_1_off"
else if(node2)
icon_state = "exposed_2_off"
else
icon_state = "exposed_3_off"
on = 0
return
process()
..()
if(!on)
return 0
var/output_starting_pressure = air2.return_pressure()
var/input_starting_pressure = air1.return_pressure()
if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10))
//No need to pump gas if target is already reached or input pressure is too low
//Need at least 10 KPa difference to overcome friction in the mechanism
return 1
//Calculate necessary moles to transfer using PV = nRT
if((air1.total_moles() > 0) && (air1.temperature>0))
var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2)
//Can not have a pressure delta that would cause output_pressure > input_pressure
var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
//Actually transfer the gas
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
air2.merge(removed)
if(network1)
network1.update = 1
if(network2)
network2.update = 1

View File

@@ -0,0 +1,128 @@
/*
Every cycle, the pump uses the air in air_in to try and make air_out the perfect pressure.
node1, air1, network1 correspond to input
node2, air2, network2 correspond to output
Thus, the two variables affect pump operation are set in New():
air1.volume
This is the volume of gas available to the pump that may be transfered to the output
air2.volume
Higher quantities of this cause more air to be perfected later
but overall network volume is also increased as this increases...
*/
obj/machinery/atmospherics/binary/pump
icon = 'pump.dmi'
icon_state = "intact_off"
name = "Gas pump"
desc = "A pump"
var/on = 0
var/target_pressure = ONE_ATMOSPHERE
attack_hand(mob/user)
on = !on
update_icon()
update_icon()
if(node1&&node2)
icon_state = "intact_[on?("on"):("off")]"
else
if(node1)
icon_state = "exposed_1_off"
else if(node2)
icon_state = "exposed_2_off"
else
icon_state = "exposed_3_off"
on = 0
return
process()
..()
if(!on)
return 0
var/output_starting_pressure = air2.return_pressure()
if(output_starting_pressure >= target_pressure)
//No need to pump gas if target is already reached!
return 1
//Calculate necessary moles to transfer using PV=nRT
if((air1.total_moles() > 0) && (air1.temperature>0))
var/pressure_delta = target_pressure - output_starting_pressure
var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
//Actually transfer the gas
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
air2.merge(removed)
if(network1)
network1.update = 1
if(network2)
network2.update = 1
return 1
//Radio remote control
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, "[frequency]")
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, "[frequency]")
broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data["tag"] = id
signal.data["device"] = "AGP"
signal.data["power"] = on
signal.data["target_output"] = target_pressure
radio_connection.post_signal(src, signal)
return 1
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
initialize()
..()
if(frequency)
set_frequency(frequency)
receive_signal(datum/signal/signal)
if(signal.data["tag"] && (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("power_on")
on = 1
if("power_off")
on = 0
if("power_toggle")
on = !on
if("set_output_pressure")
var/number = text2num(signal.data["parameter"])
number = min(max(number, 0), ONE_ATMOSPHERE*50)
target_pressure = number
if(signal.data["tag"])
spawn(5) broadcast_status()
update_icon()

View File

@@ -0,0 +1,113 @@
/*
Every cycle, the pump uses the air in air_in to try and make air_out the perfect pressure.
node1, air1, network1 correspond to input
node2, air2, network2 correspond to output
Thus, the two variables affect pump operation are set in New():
air1.volume
This is the volume of gas available to the pump that may be transfered to the output
air2.volume
Higher quantities of this cause more air to be perfected later
but overall network volume is also increased as this increases...
*/
obj/machinery/atmospherics/binary/volume_pump
icon = 'volume_pump.dmi'
icon_state = "intact_off"
name = "Gas pump"
desc = "A pump"
var/on = 0
var/transfer_rate = 200
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
update_icon()
if(node1&&node2)
icon_state = "intact_[on?("on"):("off")]"
else
if(node1)
icon_state = "exposed_1_off"
else if(node2)
icon_state = "exposed_2_off"
else
icon_state = "exposed_3_off"
on = 0
return
process()
..()
if(!on)
return 0
var/transfer_ratio = max(1, transfer_rate/air1.volume)
var/datum/gas_mixture/removed = air1.remove_ratio(transfer_ratio)
air2.merge(removed)
if(network1)
network1.update = 1
if(network2)
network2.update = 1
return 1
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, "[frequency]")
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, "[frequency]")
broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data["tag"] = id
signal.data["device"] = "APV"
signal.data["power"] = on
signal.data["transfer_rate"] = transfer_rate
radio_connection.post_signal(src, signal)
return 1
initialize()
..()
set_frequency(frequency)
receive_signal(datum/signal/signal)
if(signal.data["tag"] && (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("power_on")
on = 1
if("power_off")
on = 0
if("power_toggle")
on = !on
if("set_transfer_rate")
var/number = text2num(signal.data["parameter"])
number = min(max(number, 0), air1.volume)
transfer_rate = number
if(signal.data["tag"])
spawn(5) broadcast_status()
update_icon()

View File

@@ -0,0 +1,366 @@
obj/machinery/atmospherics/filter
icon = 'filter.dmi'
icon_state = "intact_off"
density = 1
name = "Gas filter"
dir = SOUTH
initialize_directions = SOUTH|NORTH|WEST
var/on = 0
var/temp = null // -- TLE
var/datum/gas_mixture/air_in
var/datum/gas_mixture/air_out1
var/datum/gas_mixture/air_out2
var/obj/machinery/atmospherics/node_in
var/obj/machinery/atmospherics/node_out1
var/obj/machinery/atmospherics/node_out2
var/datum/pipe_network/network_in
var/datum/pipe_network/network_out1
var/datum/pipe_network/network_out2
var/target_pressure = ONE_ATMOSPHERE
var/filter_type = 0
/*
Filter types:
0: Carbon Molecules: Plasma Toxin, Carbon Dioxide, Oxygen Agent B
1: Oxygen: Oxygen ONLY
2: Nitrogen: Nitrogen and Sleeping Agent
3: Carbon Dioxide: Carbon Dioxide ONLY
*/
var/frequency = 0
var/datum/radio_frequency/radio_connection
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, "[frequency]")
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, "[frequency]")
New()
..()
switch(dir)
if(NORTH)
initialize_directions = NORTH|EAST|SOUTH
if(SOUTH)
initialize_directions = NORTH|SOUTH|WEST
if(EAST)
initialize_directions = EAST|WEST|SOUTH
if(WEST)
initialize_directions = NORTH|EAST|WEST
if(radio_controller)
initialize()
update_icon()
if(node_out1&&node_out2&&node_in)
icon_state = "intact_[on?("on"):("off")]"
else
var/node_out1_direction = get_dir(src, node_out1)
var/node_out2_direction = get_dir(src, node_out2)
var/node_in_bit = (node_in)?(1):(0)
icon_state = "exposed_[node_out1_direction|node_out2_direction]_[node_in_bit]_off"
on = 0
return
New()
..()
air_in = new
air_out1 = new
air_out2 = new
air_in.volume = 200
air_out1.volume = 200
air_out2.volume = 200
process()
..()
if(!on)
return 0
var/output_starting_pressure = air_out2.return_pressure()
if(output_starting_pressure >= target_pressure)
//No need to mix if target is already full!
return 1
//Calculate necessary moles to transfer using PV=nRT
var/pressure_delta = target_pressure - output_starting_pressure
var/transfer_moles
if(air_in.temperature > 0)
transfer_moles = pressure_delta*air_out2.volume/(air_in.temperature * R_IDEAL_GAS_EQUATION)
//Actually transfer the gas
if(transfer_moles > 0)
var/datum/gas_mixture/removed = air_in.remove(transfer_moles)
var/datum/gas_mixture/filtered_out = new
filtered_out.temperature = removed.temperature
switch(filter_type)
if(0) //removing hydrocarbons
filtered_out.toxins = removed.toxins
removed.toxins = 0
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
if(removed.trace_gases.len>0)
for(var/datum/gas/trace_gas in removed.trace_gases)
if(istype(trace_gas, /datum/gas/oxygen_agent_b))
removed.trace_gases -= trace_gas
filtered_out.trace_gases += trace_gas
if(1) //removing O2
filtered_out.oxygen = removed.oxygen
removed.oxygen = 0
if(2) //removing N2
filtered_out.nitrogen = removed.nitrogen
removed.nitrogen = 0
if(removed.trace_gases.len>0)
for(var/datum/gas/trace_gas in removed.trace_gases)
if(istype(trace_gas, /datum/gas/sleeping_agent))
removed.trace_gases -= trace_gas
filtered_out.trace_gases += trace_gas
if(3) //removing CO2
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
air_out1.merge(filtered_out)
air_out2.merge(removed)
if(network_out1)
network_out1.update = 1
if(network_out2)
network_out2.update = 1
if(network_in)
network_in.update = 1
return 1
// Housekeeping and pipe network stuff below
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node_out1)
network_out1 = new_network
else if(reference == node_out2)
network_out2 = new_network
else if(reference == node_in)
network_in = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
Del()
loc = null
if(node_out1)
node_out1.disconnect(src)
del(network_out1)
if(node_out2)
node_out2.disconnect(src)
del(network_out2)
if(node_in)
node_in.disconnect(src)
del(network_in)
node_out1 = null
node_out2 = null
node_in = null
..()
initialize()
if(node_out1 && node_in) return
var/node_in_connect = turn(dir, -180)
var/node_out1_connect = turn(dir, -90)
var/node_out2_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node_out1_connect))
if(target.initialize_directions & get_dir(target,src))
node_out1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node_out2_connect))
if(target.initialize_directions & get_dir(target,src))
node_out2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node_in_connect))
if(target.initialize_directions & get_dir(target,src))
node_in = target
break
update_icon()
set_frequency(frequency)
build_network()
if(!network_out1 && node_out1)
network_out1 = new /datum/pipe_network()
network_out1.normal_members += src
network_out1.build_network(node_out1, src)
if(!network_out2 && node_out2)
network_out2 = new /datum/pipe_network()
network_out2.normal_members += src
network_out2.build_network(node_out2, src)
if(!network_in && node_in)
network_in = new /datum/pipe_network()
network_in.normal_members += src
network_in.build_network(node_in, src)
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node_out1)
return network_out1
if(reference==node_out2)
return network_out2
if(reference==node_in)
return network_in
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network_out1 == old_network)
network_out1 = new_network
if(network_out2 == old_network)
network_out2 = new_network
if(network_in == old_network)
network_in = new_network
return 1
return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network_out1 == reference)
results += air_out1
if(network_out2 == reference)
results += air_out2
if(network_in == reference)
results += air_in
return results
disconnect(obj/machinery/atmospherics/reference)
if(reference==node_out1)
del(network_out1)
node_out1 = null
else if(reference==node_out2)
del(network_out2)
node_out2 = null
else if(reference==node_in)
del(network_in)
node_in = null
return null
obj/machinery/atmospherics/filter/attack_hand(user as mob) // -- TLE
var/dat
if(..())
return
if (1 == 1)
/*
dat += "Autolathe Wires:<BR>"
var/wire
for(wire in src.wires)
dat += text("[wire] Wire: <A href='?src=\ref[src];wire=[wire];act=wire'>[src.wires[wire] ? "Mend" : "Cut"]</A> <A href='?src=\ref[src];wire=[wire];act=pulse'>Pulse</A><BR>")
dat += text("The red light is [src.disabled ? "off" : "on"].<BR>")
dat += text("The green light is [src.shocked ? "off" : "on"].<BR>")
dat += text("The blue light is [src.hacked ? "off" : "on"].<BR>")
*/
var/current_filter_type
switch(filter_type)
if(0)
current_filter_type = "Carbon Molecules"
if(1)
current_filter_type = "Oxygen"
if(2)
current_filter_type = "Nitrogen"
if(3)
current_filter_type = "Carbon Dioxide"
else
current_filter_type = "ERROR - Report this bug to the admin, please!"
dat += "<b>Filtering: </b>[current_filter_type]<br><br>"
dat += "<h3>Set Filter Type:</h3><BR>"
dat += "<A href='?src=\ref[src];filterset=0'>Carbon Molecules</A><BR>"
dat += "<A href='?src=\ref[src];filterset=1'>Oxygen</A><BR>"
dat += "<A href='?src=\ref[src];filterset=2'>Nitrogen</A><BR>"
dat += "<A href='?src=\ref[src];filterset=3'>Carbon Dioxide</A><BR>"
user << browse("<HEAD><TITLE>Atmospherics Filter</TITLE></HEAD>[dat]","window=atmo_filter")
onclose(user, "atmo_filter")
return
if (src.temp)
dat = text("<TT>[]</TT><BR><BR><A href='?src=\ref[];temp=1'>Clear Screen</A>", src.temp, src)
//else
// src.on != src.on
user << browse("<HEAD><TITLE>Autolathe Control Panel</TITLE></HEAD><TT>[dat]</TT>", "window=atmo_filter")
onclose(user, "atmo_filter")
return
obj/machinery/atmospherics/filter/Topic(href, href_list) // -- TLE
if(..())
return
usr.machine = src
src.add_fingerprint(usr)
if(href_list["filterset"])
if(href_list["filterset"] == "0")
src.filter_type = 0
if(href_list["filterset"] == "1")
src.filter_type = 1
if(href_list["filterset"] == "2")
src.filter_type = 2
if(href_list["filterset"] == "3")
src.filter_type = 3
if (href_list["temp"])
src.temp = null
for(var/mob/M in viewers(1, src))
if ((M.client && M.machine == src))
src.attack_hand(M)
return

View File

@@ -0,0 +1,249 @@
obj/machinery/atmospherics/mixer
icon = 'mixer.dmi'
icon_state = "intact_off"
density = 1
name = "Gas mixer"
dir = SOUTH
initialize_directions = SOUTH|NORTH|WEST
var/on = 0
var/datum/gas_mixture/air_in1
var/datum/gas_mixture/air_in2
var/datum/gas_mixture/air_out
var/obj/machinery/atmospherics/node_in1
var/obj/machinery/atmospherics/node_in2
var/obj/machinery/atmospherics/node_out
var/datum/pipe_network/network_in1
var/datum/pipe_network/network_in2
var/datum/pipe_network/network_out
var/target_pressure = ONE_ATMOSPHERE
var/node1_concentration = 0.5
var/node2_concentration = 0.5
update_icon()
if(node_in1&&node_in2&&node_out)
icon_state = "intact_[on?("on"):("off")]"
else
var/node_in1_direction = get_dir(src, node_in1)
var/node_in2_direction = get_dir(src, node_in2)
var/node_out_bit = (node_out)?(1):(0)
icon_state = "exposed_[node_in1_direction|node_in2_direction]_[node_out_bit]_off"
on = 0
return
New()
..()
switch(dir)
if(NORTH)
initialize_directions = NORTH|EAST|SOUTH
if(EAST)
initialize_directions = EAST|SOUTH|WEST
if(SOUTH)
initialize_directions = SOUTH|WEST|NORTH
if(WEST)
initialize_directions = WEST|NORTH|EAST
air_in1 = new
air_in2 = new
air_out = new
air_in1.volume = 200
air_in2.volume = 200
air_out.volume = 300
process()
..()
if(!on)
return 0
var/output_starting_pressure = air_out.return_pressure()
if(output_starting_pressure >= target_pressure)
//No need to mix if target is already full!
return 1
//Calculate necessary moles to transfer using PV=nRT
var/pressure_delta = target_pressure - output_starting_pressure
var/transfer_moles1 = 0
var/transfer_moles2 = 0
if(air_in1.temperature > 0)
transfer_moles1 = (node1_concentration*pressure_delta)*air_out.volume/(air_in1.temperature * R_IDEAL_GAS_EQUATION)
if(air_in2.temperature > 0)
transfer_moles2 = (node2_concentration*pressure_delta)*air_out.volume/(air_in2.temperature * R_IDEAL_GAS_EQUATION)
var/air_in1_moles = air_in1.total_moles()
var/air_in2_moles = air_in2.total_moles()
if((air_in1_moles < transfer_moles1) || (air_in2_moles < transfer_moles2))
var/ratio = min(air_in1_moles/transfer_moles1, air_in2_moles/transfer_moles2)
transfer_moles1 *= ratio
transfer_moles2 *= ratio
//Actually transfer the gas
if(transfer_moles1 > 0)
var/datum/gas_mixture/removed1 = air_in1.remove(transfer_moles1)
air_out.merge(removed1)
if(transfer_moles2 > 0)
var/datum/gas_mixture/removed2 = air_in2.remove(transfer_moles2)
air_out.merge(removed2)
if(network_in1 && transfer_moles1)
network_in1.update = 1
if(network_in2 && transfer_moles2)
network_in2.update = 1
if(network_out)
network_out.update = 1
return 1
// Housekeeping and pipe network stuff below
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node_in1)
network_in1 = new_network
else if(reference == node_in2)
network_in2 = new_network
else if(reference == node_out)
network_out = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
Del()
loc = null
if(node_in1)
node_in1.disconnect(src)
del(network_in1)
if(node_in2)
node_in2.disconnect(src)
del(network_in2)
if(node_out)
node_out.disconnect(src)
del(network_out)
node_in1 = null
node_in2 = null
node_out = null
..()
initialize()
if(node_in1 && node_out) return
var/node_out_connect = dir
var/node_in1_connect = turn(dir, -90)
var/node_in2_connect = turn(dir, -180)
for(var/obj/machinery/atmospherics/target in get_step(src,node_in1_connect))
if(target.initialize_directions & get_dir(target,src))
node_in1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node_in2_connect))
if(target.initialize_directions & get_dir(target,src))
node_in2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node_out_connect))
if(target.initialize_directions & get_dir(target,src))
node_out = target
break
update_icon()
build_network()
if(!network_in1 && node_in1)
network_in1 = new /datum/pipe_network()
network_in1.normal_members += src
network_in1.build_network(node_in1, src)
if(!network_in2 && node_in2)
network_in2 = new /datum/pipe_network()
network_in2.normal_members += src
network_in2.build_network(node_in2, src)
if(!network_out && node_out)
network_out = new /datum/pipe_network()
network_out.normal_members += src
network_out.build_network(node_out, src)
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node_in1)
return network_in1
if(reference==node_in2)
return network_in2
if(reference==node_out)
return network_out
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network_in1 == old_network)
network_in1 = new_network
if(network_in2 == old_network)
network_in2 = new_network
if(network_out == old_network)
network_out = new_network
return 1
return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network_in1 == reference)
results += air_in1
if(network_in2 == reference)
results += air_in2
if(network_out == reference)
results += air_out
return results
disconnect(obj/machinery/atmospherics/reference)
if(reference==node_in1)
del(network_in1)
node_in1 = null
else if(reference==node_in2)
del(network_in2)
node_in2 = null
else if(reference==node_out)
del(network_out)
node_out = null
return null

View File

@@ -0,0 +1,129 @@
/obj/machinery/atmospherics/portables_connector
icon = 'portables_connector.dmi'
icon_state = "intact"
name = "Connector Port"
desc = "For connecting portables devices related to atmospherics control."
dir = SOUTH
initialize_directions = SOUTH
var/obj/machinery/portable_atmospherics/connected_device
var/obj/machinery/atmospherics/node
var/datum/pipe_network/network
var/on = 0
level = 0
New()
initialize_directions = dir
..()
update_icon()
if(node)
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact"
dir = get_dir(src, node)
else
icon_state = "exposed"
return
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(node)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact"
dir = get_dir(src, node)
else
icon_state = "exposed"
process()
..()
if(!on)
return
if(!connected_device)
on = 0
return
if(network)
network.update = 1
return 1
// Housekeeping and pipe network stuff below
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node)
network = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
Del()
loc = null
if(connected_device)
connected_device.disconnect()
if(node)
node.disconnect(src)
del(network)
node = null
..()
initialize()
if(node) return
var/node_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
if(target.initialize_directions & get_dir(target,src))
node = target
break
update_icon()
build_network()
if(!network && node)
network = new /datum/pipe_network()
network.normal_members += src
network.build_network(node, src)
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node)
return network
if(reference==connected_device)
return network
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network == old_network)
network = new_network
return 1
return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(connected_device)
results += connected_device.air_contents
return results
disconnect(obj/machinery/atmospherics/reference)
if(reference==node)
del(network)
node = null
return null

View File

@@ -0,0 +1,40 @@
/obj/machinery/atmospherics/unary/cold_sink
icon = 'cold_sink.dmi'
icon_state = "intact_off"
density = 1
name = "Cold Sink"
desc = "Cools gas when connected to pipe network"
var/on = 0
var/current_temperature = T20C
var/current_heat_capacity = 50000 //totally random
update_icon()
if(node)
icon_state = "intact_[on?("on"):("off")]"
else
icon_state = "exposed"
on = 0
return
process()
..()
if(!on)
return 0
var/air_heat_capacity = air_contents.heat_capacity()
var/combined_heat_capacity = current_heat_capacity + air_heat_capacity
var/old_temperature = air_contents.temperature
if(combined_heat_capacity > 0)
var/combined_energy = current_temperature*current_heat_capacity + air_heat_capacity*air_contents.temperature
air_contents.temperature = combined_energy/combined_heat_capacity
//todo: have current temperature affected. require power to bring down current temperature again
if(abs(old_temperature-air_contents.temperature) > 1)
network.update = 1
return 1

View File

@@ -0,0 +1,21 @@
/obj/machinery/atmospherics/unary/generator_input
icon = 'heat_exchanger.dmi'
icon_state = "intact"
density = 1
name = "Generator Input"
desc = "Placeholder"
var/update_cycle
update_icon()
if(node)
icon_state = "intact"
else
icon_state = "exposed"
return
proc
return_exchange_air()
return air_contents

View File

@@ -0,0 +1,66 @@
/obj/machinery/atmospherics/unary/heat_exchanger
icon = 'heat_exchanger.dmi'
icon_state = "intact"
density = 1
name = "Heat Exchanger"
desc = "Exchanges heat between two input gases. Setup for fast heat transfer"
var/obj/machinery/atmospherics/unary/heat_exchanger/partner = null
var/update_cycle
update_icon()
if(node)
icon_state = "intact"
else
icon_state = "exposed"
return
initialize()
if(!partner)
var/partner_connect = turn(dir,180)
for(var/obj/machinery/atmospherics/unary/heat_exchanger/target in get_step(src,partner_connect))
if(target.dir & get_dir(src,target))
partner = target
partner.partner = src
break
..()
process()
..()
if(!partner)
return 0
if(!air_master || air_master.current_cycle <= update_cycle)
return 0
update_cycle = air_master.current_cycle
partner.update_cycle = air_master.current_cycle
var/air_heat_capacity = air_contents.heat_capacity()
var/other_air_heat_capacity = partner.air_contents.heat_capacity()
var/combined_heat_capacity = other_air_heat_capacity + air_heat_capacity
var/old_temperature = air_contents.temperature
var/other_old_temperature = partner.air_contents.temperature
if(combined_heat_capacity > 0)
var/combined_energy = partner.air_contents.temperature*other_air_heat_capacity + air_heat_capacity*air_contents.temperature
var/new_temperature = combined_energy/combined_heat_capacity
air_contents.temperature = new_temperature
partner.air_contents.temperature = new_temperature
if(network)
if(abs(old_temperature-air_contents.temperature) > 1)
network.update = 1
if(partner.network)
if(abs(other_old_temperature-partner.air_contents.temperature) > 1)
partner.network.update = 1
return 1

View File

@@ -0,0 +1,42 @@
/obj/machinery/atmospherics/unary/heat_reservoir
//currently the same code as cold_sink but anticipating process() changes
icon = 'cold_sink.dmi'
icon_state = "intact_off"
density = 1
name = "Heat Reservoir"
desc = "Heats gas when connected to pipe network"
var/on = 0
var/current_temperature = T20C
var/current_heat_capacity = 50000 //totally random
update_icon()
if(node)
icon_state = "intact_[on?("on"):("off")]"
else
icon_state = "exposed"
on = 0
return
process()
..()
if(!on)
return 0
var/air_heat_capacity = air_contents.heat_capacity()
var/combined_heat_capacity = current_heat_capacity + air_heat_capacity
var/old_temperature = air_contents.temperature
if(combined_heat_capacity > 0)
var/combined_energy = current_temperature*current_heat_capacity + air_heat_capacity*air_contents.temperature
air_contents.temperature = combined_energy/combined_heat_capacity
//todo: have current temperature affected. require power to bring up current temperature again
if(abs(old_temperature-air_contents.temperature) > 1)
network.update = 1
return 1

View File

@@ -0,0 +1,133 @@
/obj/machinery/atmospherics/unary/outlet_injector
icon = 'outlet_injector.dmi'
icon_state = "off"
name = "Air Injector"
desc = "Has a valve and pump attached to it"
var/on = 0
var/injecting = 0
var/volume_rate = 50
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
level = 1
update_icon()
if(node)
if(on)
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
else
icon_state = "exposed"
on = 0
return
process()
..()
injecting = 0
if(!on)
return 0
if(air_contents.temperature > 0)
var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
loc.assume_air(removed)
if(network)
network.update = 1
return 1
proc/inject()
if(on || injecting)
return 0
injecting = 1
if(air_contents.temperature > 0)
var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
loc.assume_air(removed)
if(network)
network.update = 1
flick("inject", src)
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, "[frequency]")
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, "[frequency]")
broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data["tag"] = id
signal.data["device"] = "AO"
signal.data["power"] = on
signal.data["volume_rate"] = volume_rate
radio_connection.post_signal(src, signal)
return 1
initialize()
..()
set_frequency(frequency)
receive_signal(datum/signal/signal)
if(signal.data["tag"] && (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("power_on")
on = 1
if("power_off")
on = 0
if("power_toggle")
on = !on
if("inject")
spawn inject()
if("set_volume_rate")
var/number = text2num(signal.data["parameter"])
number = min(max(number, 0), air_contents.volume)
volume_rate = number
if(signal.data["tag"])
spawn(5) broadcast_status()
update_icon()
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(node)
if(on)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]exposed"
on = 0
return

View File

@@ -0,0 +1,49 @@
obj/machinery/atmospherics/unary/oxygen_generator
icon = 'oxygen_generator.dmi'
icon_state = "intact_off"
density = 1
name = "Oxygen Generator"
desc = ""
dir = SOUTH
initialize_directions = SOUTH
var/on = 0
var/oxygen_content = 10
update_icon()
if(node)
icon_state = "intact_[on?("on"):("off")]"
else
icon_state = "exposed_off"
on = 0
return
New()
..()
air_contents.volume = 50
process()
..()
if(!on)
return 0
var/total_moles = air_contents.total_moles()
if(total_moles < oxygen_content)
var/current_heat_capacity = air_contents.heat_capacity()
var/added_oxygen = oxygen_content - total_moles
air_contents.temperature = (current_heat_capacity*air_contents.temperature + 20*added_oxygen*T0C)/(current_heat_capacity+20*added_oxygen)
air_contents.oxygen += added_oxygen
if(network)
network.update = 1
return 1

View File

@@ -0,0 +1,87 @@
/obj/machinery/atmospherics/unary
dir = SOUTH
initialize_directions = SOUTH
var/datum/gas_mixture/air_contents
var/obj/machinery/atmospherics/node
var/datum/pipe_network/network
New()
..()
initialize_directions = dir
air_contents = new
air_contents.volume = 200
// Housekeeping and pipe network stuff below
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node)
network = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
return null
Del()
loc = null
if(node)
node.disconnect(src)
del(network)
node = null
..()
initialize()
if(node) return
var/node_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
if(target.initialize_directions & get_dir(target,src))
node = target
break
update_icon()
build_network()
if(!network && node)
network = new /datum/pipe_network()
network.normal_members += src
network.build_network(node, src)
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node)
return network
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network == old_network)
network = new_network
return 1
return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(network == reference)
results += air_contents
return results
disconnect(obj/machinery/atmospherics/reference)
if(reference==node)
del(network)
node = null
return null

View File

@@ -0,0 +1,212 @@
/obj/machinery/atmospherics/unary/vent_pump
icon = 'vent_pump.dmi'
icon_state = "off"
name = "Air Vent"
desc = "Has a valve and pump attached to it"
level = 1
high_volume
name = "Large Air Vent"
New()
..()
air_contents.volume = 1000
var/on = 0
var/pump_direction = 1 //0 = siphoning, 1 = releasing
var/external_pressure_bound = ONE_ATMOSPHERE
var/internal_pressure_bound = 0
var/pressure_checks = 1
//1: Do not pass external_pressure_bound
//2: Do not pass internal_pressure_bound
//3: Do not pass either
var/welded = 0 // Added for aliens -- TLE
update_icon()
if(on&&node)
if(pump_direction)
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
on = 0
return
process()
..()
if(!on)
return 0
if(welded)
return 0
var/datum/gas_mixture/environment = loc.return_air()
var/environment_pressure = environment.return_pressure()
if(pump_direction) //internal -> external
var/pressure_delta = 10000
if(pressure_checks&1)
pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure))
if(pressure_checks&2)
pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound))
if(pressure_delta > 0)
if(air_contents.temperature > 0)
var/transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
loc.assume_air(removed)
if(network)
network.update = 1
else //external -> internal
var/pressure_delta = 10000
if(pressure_checks&1)
pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound))
if(pressure_checks&2)
pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure()))
if(pressure_delta > 0)
if(environment.temperature > 0)
var/transfer_moles = pressure_delta*air_contents.volume/(environment.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
air_contents.merge(removed)
if(network)
network.update = 1
return 1
//Radio remote control
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, "[frequency]")
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, "[frequency]")
broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data["tag"] = id
signal.data["device"] = "AVP"
signal.data["power"] = on?("on"):("off")
signal.data["direction"] = pump_direction?("release"):("siphon")
signal.data["checks"] = pressure_checks
signal.data["internal"] = internal_pressure_bound
signal.data["external"] = external_pressure_bound
radio_connection.post_signal(src, signal)
return 1
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
initialize()
..()
if(frequency)
set_frequency(frequency)
update_icon()
receive_signal(datum/signal/signal)
if(signal.data["tag"] && (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("power_on")
on = 1
if("power_off")
on = 0
if("power_toggle")
on = !on
if("set_direction")
var/number = text2num(signal.data["parameter"])
if(number > 0.5)
pump_direction = 1
else
pump_direction = 0
if("purge")
pressure_checks &= ~1
pump_direction = 0
if("stabalize")
pressure_checks |= 1
pump_direction = 1
if("set_checks")
var/number = round(text2num(signal.data["parameter"]),1)
pressure_checks = number
if("set_internal_pressure")
var/number = text2num(signal.data["parameter"])
number = min(max(number, 0), ONE_ATMOSPHERE*50)
internal_pressure_bound = number
if("set_external_pressure")
var/number = text2num(signal.data["parameter"])
number = min(max(number, 0), ONE_ATMOSPHERE*50)
external_pressure_bound = number
if(signal.data["tag"])
spawn(5) broadcast_status()
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(on&&node)
if(pump_direction)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
on = 0
return
attackby(obj/item/W, mob/user) // Added for aliens -- TLE
// Stolen from the Emitter welding code of the Singularity
if(istype(W, /obj/item/weapon/weldingtool) && W:welding)
if (W:get_fuel() < 1)
user << "\blue You need more welding fuel to complete this task."
return
W:use_fuel(1)
if(!welded)
user.visible_message("[user] welds the vent shut.", "You weld the vent shut.")
playsound(src.loc, 'Welder2.ogg', 50, 1)
welded = 1
else
user.visible_message("[user] unwelds the vent.", "You unweld the vent.")
playsound(src.loc, 'Welder2.ogg', 50, 1)
welded = 0
examine()
set src in oview(1)
..()
if(welded)
usr << "It seems welded shut."

View File

@@ -0,0 +1,88 @@
/obj/machinery/atmospherics/unary/vent_scrubber
icon = 'vent_scrubber.dmi'
icon_state = "off"
name = "Air Scrubber"
desc = "Has a valve and pump attached to it"
level = 1
var/on = 0
var/scrubbing = 1 //0 = siphoning, 1 = scrubbing
var/scrub_CO2 = 1
var/scrub_Toxins = 0
var/volume_rate = 120
update_icon()
if(on&&node)
if(scrubbing)
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
on = 0
return
process()
..()
if(!on)
return 0
var/datum/gas_mixture/environment = loc.return_air()
if(scrubbing)
if((environment.toxins>0) || (environment.carbon_dioxide>0) || (environment.trace_gases.len>0))
var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles()
//Take a gas sample
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
//Filter it
var/datum/gas_mixture/filtered_out = new
filtered_out.temperature = removed.temperature
if(scrub_Toxins)
filtered_out.toxins = removed.toxins
removed.toxins = 0
if(scrub_CO2)
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
if(removed.trace_gases.len>0)
for(var/datum/gas/trace_gas in removed.trace_gases)
if(istype(trace_gas, /datum/gas/oxygen_agent_b))
removed.trace_gases -= trace_gas
filtered_out.trace_gases += trace_gas
//Remix the resulting gases
air_contents.merge(filtered_out)
loc.assume_air(removed)
if(network)
network.update = 1
else //Just siphoning all air
var/transfer_moles = environment.total_moles()*(volume_rate/environment.volume)
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
air_contents.merge(removed)
if(network)
network.update = 1
return 1
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(on&&node)
if(scrubbing)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
on = 0
return

View File

@@ -0,0 +1,249 @@
obj/machinery/atmospherics/valve
icon = 'valve.dmi'
icon_state = "valve0"
name = "manual valve"
desc = "A pipe valve"
dir = SOUTH
initialize_directions = SOUTH|NORTH
var/open = 0
var/obj/machinery/atmospherics/node1
var/obj/machinery/atmospherics/node2
var/datum/pipe_network/network_node1
var/datum/pipe_network/network_node2
update_icon(animation)
if(animation)
flick("valve[src.open][!src.open]",src)
else
icon_state = "valve[open]"
New()
switch(dir)
if(NORTH || SOUTH)
initialize_directions = NORTH|SOUTH
if(EAST || WEST)
initialize_directions = EAST|WEST
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network_node1 = new_network
if(open)
network_node2 = new_network
else if(reference == node2)
network_node2 = new_network
if(open)
network_node1 = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
if(open)
if(reference == node1)
return node2.network_expand(new_network, src)
else if(reference == node2)
return node1.network_expand(new_network, src)
return null
Del()
loc = null
if(node1)
node1.disconnect(src)
del(network_node1)
if(node2)
node2.disconnect(src)
del(network_node2)
node1 = null
node2 = null
..()
proc/open()
if(open) return 0
open = 1
update_icon()
if(network_node1&&network_node2)
network_node1.merge(network_node2)
network_node2 = network_node1
if(network_node1)
network_node1.update = 1
else if(network_node2)
network_node2.update = 1
return 1
proc/close()
if(!open)
return 0
open = 0
update_icon()
if(network_node1)
del(network_node1)
if(network_node2)
del(network_node2)
build_network()
return 1
attack_paw(mob/user as mob)
return attack_hand(user)
attack_hand(mob/user as mob)
update_icon(1)
sleep(10)
if (src.open)
src.close()
else
src.open()
process()
..()
if(open && (!node1 || !node2))
close()
return
initialize()
if(node1 && node2) return
var/connect_directions
switch(dir)
if(NORTH)
connect_directions = NORTH|SOUTH
if(SOUTH)
connect_directions = NORTH|SOUTH
if(EAST)
connect_directions = EAST|WEST
if(WEST)
connect_directions = EAST|WEST
else
connect_directions = dir
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
if(target.initialize_directions & get_dir(target,src))
connect_directions &= ~direction
node1 = target
break
break
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
break
build_network()
if(!network_node1 && node1)
network_node1 = new /datum/pipe_network()
network_node1.normal_members += src
network_node1.build_network(node1, src)
if(!network_node2 && node2)
network_node2 = new /datum/pipe_network()
network_node2.normal_members += src
network_node2.build_network(node2, src)
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network_node1
if(reference==node2)
return network_node2
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network_node1 == old_network)
network_node1 = new_network
if(network_node2 == old_network)
network_node2 = new_network
return 1
return_network_air(datum/network/reference)
return null
disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
del(network_node1)
node1 = null
else if(reference==node2)
del(network_node2)
node2 = null
return null
digital // can be controlled by AI
name = "digital valve"
desc = "A digitally controlled valve."
icon = 'digital_valve.dmi'
attack_ai(mob/user as mob)
return src.attack_hand(user)
//Radio remote control
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, "[frequency]")
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, "[frequency]")
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
initialize()
..()
if(frequency)
set_frequency(frequency)
receive_signal(datum/signal/signal)
if(signal.data["tag"] && (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("valve_open")
if(!open)
open()
if("valve_close")
if(open)
close()
if("valve_toggle")
if(open)
close()
else
open()

View File

@@ -0,0 +1,203 @@
var/global/list/datum/pipe_network/pipe_networks = list()
datum/pipe_network
var/list/datum/gas_mixture/gases = list() //All of the gas_mixtures continuously connected in this network
var/list/obj/machinery/atmospherics/normal_members = list()
var/list/datum/pipeline/line_members = list()
//membership roster to go through for updates and what not
var/update = 1
var/datum/gas_mixture/air_transient = null
New()
air_transient = new()
..()
proc/process()
//Equalize gases amongst pipe if called for
if(update)
update = 0
reconcile_air() //equalize_gases(gases)
//Give pipelines their process call for pressure checking and what not
for(var/datum/pipeline/line_member in line_members)
line_member.process()
proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference)
//Purpose: Generate membership roster
//Notes: Assuming that members will add themselves to appropriate roster in network_expand()
if(!start_normal)
del(src)
start_normal.network_expand(src, reference)
update_network_gases()
if((normal_members.len>0)||(line_members.len>0))
pipe_networks += src
else
del(src)
proc/merge(datum/pipe_network/giver)
if(giver==src) return 0
normal_members -= giver.normal_members
normal_members += giver.normal_members
line_members -= giver.line_members
line_members += giver.line_members
for(var/obj/machinery/atmospherics/normal_member in giver.normal_members)
normal_member.reassign_network(giver, src)
for(var/datum/pipeline/line_member in giver.line_members)
line_member.network = src
del(giver)
update_network_gases()
return 1
proc/update_network_gases()
//Go through membership roster and make sure gases is up to date
gases = list()
for(var/obj/machinery/atmospherics/normal_member in normal_members)
var/result = normal_member.return_network_air(src)
if(result) gases += result
for(var/datum/pipeline/line_member in line_members)
gases += line_member.air
proc/reconcile_air()
//Perfectly equalize all gases members instantly
//Calculate totals from individual components
var/total_thermal_energy = 0
var/total_heat_capacity = 0
air_transient.volume = 0
air_transient.oxygen = 0
air_transient.nitrogen = 0
air_transient.toxins = 0
air_transient.carbon_dioxide = 0
air_transient.trace_gases = list()
for(var/datum/gas_mixture/gas in gases)
air_transient.volume += gas.volume
total_thermal_energy += gas.thermal_energy()
total_heat_capacity += gas.heat_capacity()
air_transient.oxygen += gas.oxygen
air_transient.nitrogen += gas.nitrogen
air_transient.toxins += gas.toxins
air_transient.carbon_dioxide += gas.carbon_dioxide
if(gas.trace_gases.len)
for(var/datum/gas/trace_gas in gas.trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in air_transient.trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
air_transient.trace_gases += corresponding
corresponding.moles += trace_gas.moles
if(air_transient.volume > 0)
if(total_heat_capacity > 0)
air_transient.temperature = total_thermal_energy/total_heat_capacity
//Allow air mixture to react
if(air_transient.react())
update = 1
else
air_transient.temperature = 0
//Update individual gas_mixtures by volume ratio
for(var/datum/gas_mixture/gas in gases)
gas.oxygen = air_transient.oxygen*gas.volume/air_transient.volume
gas.nitrogen = air_transient.nitrogen*gas.volume/air_transient.volume
gas.toxins = air_transient.toxins*gas.volume/air_transient.volume
gas.carbon_dioxide = air_transient.carbon_dioxide*gas.volume/air_transient.volume
gas.temperature = air_transient.temperature
if(air_transient.trace_gases.len)
for(var/datum/gas/trace_gas in air_transient.trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in gas.trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
gas.trace_gases += corresponding
corresponding.moles = trace_gas.moles*gas.volume/air_transient.volume
return 1
proc/equalize_gases(datum/gas_mixture/list/gases)
//Perfectly equalize all gases members instantly
//Calculate totals from individual components
var/total_volume = 0
var/total_thermal_energy = 0
var/total_heat_capacity = 0
var/total_oxygen = 0
var/total_nitrogen = 0
var/total_toxins = 0
var/total_carbon_dioxide = 0
var/list/total_trace_gases = list()
for(var/datum/gas_mixture/gas in gases)
total_volume += gas.volume
total_thermal_energy += gas.thermal_energy()
total_heat_capacity += gas.heat_capacity()
total_oxygen += gas.oxygen
total_nitrogen += gas.nitrogen
total_toxins += gas.toxins
total_carbon_dioxide += gas.carbon_dioxide
if(gas.trace_gases.len)
for(var/datum/gas/trace_gas in gas.trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in total_trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
total_trace_gases += corresponding
corresponding.moles += trace_gas.moles
if(total_volume > 0)
//Calculate temperature
var/temperature = 0
if(total_heat_capacity > 0)
temperature = total_thermal_energy/total_heat_capacity
//Update individual gas_mixtures by volume ratio
for(var/datum/gas_mixture/gas in gases)
gas.oxygen = total_oxygen*gas.volume/total_volume
gas.nitrogen = total_nitrogen*gas.volume/total_volume
gas.toxins = total_toxins*gas.volume/total_volume
gas.carbon_dioxide = total_carbon_dioxide*gas.volume/total_volume
gas.temperature = temperature
if(total_trace_gases.len)
for(var/datum/gas/trace_gas in total_trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in gas.trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
gas.trace_gases += corresponding
corresponding.moles = trace_gas.moles*gas.volume/total_volume
return 1

View File

@@ -0,0 +1,231 @@
datum/pipeline
var/datum/gas_mixture/air
var/list/obj/machinery/atmospherics/pipe/members
var/list/obj/machinery/atmospherics/pipe/edges //Used for building networks
var/datum/pipe_network/network
var/alert_pressure = 0
Del()
if(network)
del(network)
if(air && air.volume)
temporarily_store_air()
del(air)
..()
proc/process()
//Check to see if pressure is within acceptable limits
var/pressure = air.return_pressure()
if(pressure > alert_pressure)
for(var/obj/machinery/atmospherics/pipe/member in members)
if(!member.check_pressure(pressure))
break //Only delete 1 pipe per process
//Allow for reactions
//air.react() //Should be handled by pipe_network now
proc/temporarily_store_air()
//Update individual gas_mixtures by volume ratio
for(var/obj/machinery/atmospherics/pipe/member in members)
member.air_temporary = new
member.air_temporary.volume = member.volume
member.air_temporary.oxygen = air.oxygen*member.volume/air.volume
member.air_temporary.nitrogen = air.nitrogen*member.volume/air.volume
member.air_temporary.toxins = air.toxins*member.volume/air.volume
member.air_temporary.carbon_dioxide = air.carbon_dioxide*member.volume/air.volume
member.air_temporary.temperature = air.temperature
if(air.trace_gases.len)
for(var/datum/gas/trace_gas in air.trace_gases)
var/datum/gas/corresponding = new trace_gas.type()
member.air_temporary.trace_gases += corresponding
corresponding.moles = trace_gas.moles*member.volume/air.volume
proc/build_pipeline(obj/machinery/atmospherics/pipe/base)
air = new
var/list/possible_expansions = list(base)
members = list(base)
edges = list()
var/volume = base.volume
base.parent = src
alert_pressure = base.alert_pressure
if(base.air_temporary)
air = base.air_temporary
base.air_temporary = null
else
air = new
while(possible_expansions.len>0)
for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions)
var/list/result = borderline.pipeline_expansion()
var/edge_check = result.len
if(result.len>0)
for(var/obj/machinery/atmospherics/pipe/item in result)
if(!members.Find(item))
members += item
possible_expansions += item
volume += item.volume
item.parent = src
alert_pressure = min(alert_pressure, item.alert_pressure)
if(item.air_temporary)
air.merge(item.air_temporary)
edge_check--
if(edge_check>0)
edges += borderline
possible_expansions -= borderline
air.volume = volume
proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(new_network.line_members.Find(src))
return 0
new_network.line_members += src
network = new_network
for(var/obj/machinery/atmospherics/pipe/edge in edges)
for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion())
if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference))
result.network_expand(new_network, edge)
return 1
proc/return_network(obj/machinery/atmospherics/reference)
if(!network)
network = new /datum/pipe_network()
network.build_network(src, null)
//technically passing these parameters should not be allowed
//however pipe_network.build_network(..) and pipeline.network_extend(...)
// were setup to properly handle this case
return network
proc/mingle_with_turf(turf/simulated/target, mingle_volume)
var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
air_sample.volume = mingle_volume
if(istype(target) && target.parent && target.parent.group_processing)
//Have to consider preservation of group statuses
var/datum/gas_mixture/turf_copy = new
turf_copy.copy_from(target.parent.air)
turf_copy.volume = target.parent.air.volume //Copy a good representation of the turf from parent group
equalize_gases(list(air_sample, turf_copy))
air.merge(air_sample)
if(target.parent.air.compare(turf_copy))
//The new turf would be an acceptable group member so permit the integration
turf_copy.subtract(target.parent.air)
target.parent.air.merge(turf_copy)
else
//Comparison failure so dissemble group and copy turf
target.parent.suspend_group_processing()
target.air.copy_from(turf_copy)
else
var/datum/gas_mixture/turf_air = target.return_air()
equalize_gases(list(air_sample, turf_air))
air.merge(air_sample)
//turf_air already modified by equalize_gases()
if(istype(target) && !target.processing)
if(target.air)
if(target.air.check_tile_graphic())
target.update_visuals(target.air)
network.update = 1
proc/temperature_interact(turf/target, share_volume, thermal_conductivity)
var/total_heat_capacity = air.heat_capacity()
var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
if(istype(target, /turf/simulated))
var/turf/simulated/modeled_location = target
if(modeled_location.blocks_air)
if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0))
var/delta_temperature = air.temperature - modeled_location.temperature
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity))
air.temperature -= heat/total_heat_capacity
modeled_location.temperature += heat/modeled_location.heat_capacity
else
var/delta_temperature = 0
var/sharer_heat_capacity = 0
if(modeled_location.parent && modeled_location.parent.group_processing)
delta_temperature = (air.temperature - modeled_location.parent.air.temperature)
sharer_heat_capacity = modeled_location.parent.air.heat_capacity()
else
delta_temperature = (air.temperature - modeled_location.air.temperature)
sharer_heat_capacity = modeled_location.air.heat_capacity()
var/self_temperature_delta = 0
var/sharer_temperature_delta = 0
if((sharer_heat_capacity>0) && (partial_heat_capacity>0))
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity))
self_temperature_delta = -heat/total_heat_capacity
sharer_temperature_delta = heat/sharer_heat_capacity
else
return 1
air.temperature += self_temperature_delta
if(modeled_location.parent && modeled_location.parent.group_processing)
if((abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && (abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*modeled_location.parent.air.temperature))
modeled_location.parent.suspend_group_processing()
modeled_location.air.temperature += sharer_temperature_delta
else
modeled_location.parent.air.temperature += sharer_temperature_delta/modeled_location.parent.air.group_multiplier
else
modeled_location.air.temperature += sharer_temperature_delta
else
if((target.heat_capacity>0) && (partial_heat_capacity>0))
var/delta_temperature = air.temperature - target.temperature
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
air.temperature -= heat/total_heat_capacity
network.update = 1

681
code/ATMOSPHERICS/pipes.dm Normal file
View File

@@ -0,0 +1,681 @@
obj/machinery/atmospherics/pipe
var/datum/gas_mixture/air_temporary //used when reconstructing a pipeline that broke
var/datum/pipeline/parent
var/volume = 0
var/nodealert = 0
var/alert_pressure = 80*ONE_ATMOSPHERE
//minimum pressure before check_pressure(...) should be called
proc/pipeline_expansion()
return null
proc/check_pressure(pressure)
//Return 1 if parent should continue checking other pipes
//Return null if parent should stop checking other pipes. Recall: del(src) will by default return null
return 1
return_air()
if(!parent)
parent = new /datum/pipeline()
parent.build_pipeline(src)
return parent.air
build_network()
if(!parent)
parent = new /datum/pipeline()
parent.build_pipeline(src)
return parent.return_network()
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(!parent)
parent = new /datum/pipeline()
parent.build_pipeline(src)
return parent.network_expand(new_network, reference)
return_network(obj/machinery/atmospherics/reference)
if(!parent)
parent = new /datum/pipeline()
parent.build_pipeline(src)
return parent.return_network(reference)
Del()
del(parent)
if(air_temporary)
loc.assume_air(air_temporary)
..()
simple
icon = 'pipes.dmi'
icon_state = "intact-f"
name = "pipe"
desc = "A one meter section of regular pipe"
volume = 70
dir = SOUTH
initialize_directions = SOUTH|NORTH
var/obj/machinery/atmospherics/node1
var/obj/machinery/atmospherics/node2
var/minimum_temperature_difference = 300
var/thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
var/maximum_pressure = 70*ONE_ATMOSPHERE
var/fatigue_pressure = 55*ONE_ATMOSPHERE
alert_pressure = 55*ONE_ATMOSPHERE
level = 1
New()
..()
switch(dir)
if(SOUTH || NORTH)
initialize_directions = SOUTH|NORTH
if(EAST || WEST)
initialize_directions = EAST|WEST
if(NORTHEAST)
initialize_directions = NORTH|EAST
if(NORTHWEST)
initialize_directions = NORTH|WEST
if(SOUTHEAST)
initialize_directions = SOUTH|EAST
if(SOUTHWEST)
initialize_directions = SOUTH|WEST
hide(var/i)
if(level == 1 && istype(loc, /turf/simulated))
invisibility = i ? 101 : 0
update_icon()
process()
if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle
..()
if(!node1)
parent.mingle_with_turf(loc, volume)
if(!nodealert)
//world << "Missing node from [src] at [src.x],[src.y],[src.z]"
nodealert = 1
else if(!node2)
parent.mingle_with_turf(loc, volume)
if(!nodealert)
//world << "Missing node from [src] at [src.x],[src.y],[src.z]"
nodealert = 1
else if(parent)
var/environment_temperature = 0
if(istype(loc, /turf/simulated/))
if(loc:blocks_air)
environment_temperature = loc:temperature
else
var/datum/gas_mixture/environment = loc.return_air()
environment_temperature = environment.temperature
else
environment_temperature = loc:temperature
var/datum/gas_mixture/pipe_air = return_air()
if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
parent.temperature_interact(loc, volume, thermal_conductivity)
check_pressure(pressure)
var/datum/gas_mixture/environment = loc.return_air()
var/pressure_difference = pressure - environment.return_pressure()
if(pressure_difference > maximum_pressure)
del(src)
else if(pressure_difference > fatigue_pressure)
if(prob(5))
del(src)
else return 1
Del()
if(node1)
node1.disconnect(src)
if(node2)
node2.disconnect(src)
..()
pipeline_expansion()
return list(node1, node2)
update_icon()
if(node1&&node2)
icon_state = "intact[invisibility ? "-f" : "" ]"
var/node1_direction = get_dir(src, node1)
var/node2_direction = get_dir(src, node2)
dir = node1_direction|node2_direction
if(dir==3) dir = 1
else if(dir==12) dir = 4
else
icon_state = "exposed[invisibility ? "-f" : "" ]"
if(node1)
dir = get_dir(src,node1)
else if(node2)
dir = get_dir(src,node2)
else
del(src)
initialize()
var/connect_directions
switch(dir)
if(NORTH)
connect_directions = NORTH|SOUTH
if(SOUTH)
connect_directions = NORTH|SOUTH
if(EAST)
connect_directions = EAST|WEST
if(WEST)
connect_directions = EAST|WEST
else
connect_directions = dir
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
connect_directions &= ~direction
break
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
connect_directions &= ~direction
break
var/turf/T = src.loc // hide if turf is not intact
hide(T.intact)
//update_icon()
disconnect(obj/machinery/atmospherics/reference)
if(reference == node1)
if(istype(node1, /obj/machinery/atmospherics/pipe))
del(parent)
node1 = null
if(reference == node2)
if(istype(node2, /obj/machinery/atmospherics/pipe))
del(parent)
node2 = null
update_icon()
return null
simple/insulated
icon = 'red_pipe.dmi'
icon_state = "intact"
minimum_temperature_difference = 10000
thermal_conductivity = 0
maximum_pressure = 1000*ONE_ATMOSPHERE
fatigue_pressure = 900*ONE_ATMOSPHERE
alert_pressure = 900*ONE_ATMOSPHERE
level = 2
simple/junction
icon = 'junction.dmi'
icon_state = "intact"
level = 2
update_icon()
if(istype(node1, /obj/machinery/atmospherics/pipe/simple/heat_exchanging))
dir = get_dir(src, node1)
if(node2)
icon_state = "intact"
else
icon_state = "exposed"
else if(istype(node2, /obj/machinery/atmospherics/pipe/simple/heat_exchanging))
dir = get_dir(src, node2)
if(node1)
icon_state = "intact"
else
icon_state = "exposed"
else
icon_state = "exposed"
simple/heat_exchanging
icon = 'heat.dmi'
icon_state = "3"
level = 2
minimum_temperature_difference = 20
thermal_conductivity = WINDOW_HEAT_TRANSFER_COEFFICIENT
update_icon()
if(node1&&node2)
icon_state = "intact"
var/node1_direction = get_dir(src, node1)
var/node2_direction = get_dir(src, node2)
icon_state = "[node1_direction|node2_direction]"
tank
icon = 'pipe_tank.dmi'
icon_state = "intact"
name = "Pressure Tank"
desc = "A large vessel containing pressurized gas."
volume = 1620 //in liters, 0.9 meters by 0.9 meters by 2 meters
dir = SOUTH
initialize_directions = SOUTH
density = 1
var/obj/machinery/atmospherics/node1
New()
initialize_directions = dir
..()
process()
..()
if(!node1)
parent.mingle_with_turf(loc, 200)
carbon_dioxide
name = "Pressure Tank (Carbon Dioxide)"
New()
air_temporary = new
air_temporary.volume = volume
air_temporary.temperature = T20C
air_temporary.carbon_dioxide = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)
..()
toxins
icon = 'orange_pipe_tank.dmi'
name = "Pressure Tank (Plasma)"
New()
air_temporary = new
air_temporary.volume = volume
air_temporary.temperature = T20C
air_temporary.toxins = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)
..()
oxygen_agent_b
icon = 'red_orange_pipe_tank.dmi'
name = "Pressure Tank (Oxygen + Plasma)"
New()
air_temporary = new
air_temporary.volume = volume
air_temporary.temperature = T0C
var/datum/gas/oxygen_agent_b/trace_gas = new
trace_gas.moles = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)
air_temporary.trace_gases += trace_gas
..()
oxygen
icon = 'blue_pipe_tank.dmi'
name = "Pressure Tank (Oxygen)"
New()
air_temporary = new
air_temporary.volume = volume
air_temporary.temperature = T20C
air_temporary.oxygen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)
..()
nitrogen
icon = 'red_pipe_tank.dmi'
name = "Pressure Tank (Nitrogen)"
New()
air_temporary = new
air_temporary.volume = volume
air_temporary.temperature = T20C
air_temporary.nitrogen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)
..()
air
icon = 'red_pipe_tank.dmi'
name = "Pressure Tank (Air)"
New()
air_temporary = new
air_temporary.volume = volume
air_temporary.temperature = T20C
air_temporary.oxygen = (25*ONE_ATMOSPHERE*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)
air_temporary.nitrogen = (25*ONE_ATMOSPHERE*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)
..()
Del()
if(node1)
node1.disconnect(src)
..()
pipeline_expansion()
return list(node1)
update_icon()
if(node1)
icon_state = "intact"
dir = get_dir(src, node1)
else
icon_state = "exposed"
initialize()
var/connect_direction = dir
for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
update_icon()
disconnect(obj/machinery/atmospherics/reference)
if(reference == node1)
if(istype(node1, /obj/machinery/atmospherics/pipe))
del(parent)
node1 = null
update_icon()
return null
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (istype(W, /obj/item/device/analyzer) && get_dist(user, src) <= 1)
for (var/mob/O in viewers(user, null))
O << "\red [user] has used the analyzer on \icon[icon]"
var/pressure = parent.air.return_pressure()
var/total_moles = parent.air.total_moles()
user << "\blue Results of analysis of \icon[icon]"
if (total_moles>0)
var/o2_concentration = parent.air.oxygen/total_moles
var/n2_concentration = parent.air.nitrogen/total_moles
var/co2_concentration = parent.air.carbon_dioxide/total_moles
var/plasma_concentration = parent.air.toxins/total_moles
var/unknown_concentration = 1-(o2_concentration+n2_concentration+co2_concentration+plasma_concentration)
user << "\blue Pressure: [round(pressure,0.1)] kPa"
user << "\blue Nitrogen: [round(n2_concentration*100)]%"
user << "\blue Oxygen: [round(o2_concentration*100)]%"
user << "\blue CO2: [round(co2_concentration*100)]%"
user << "\blue Plasma: [round(plasma_concentration*100)]%"
if(unknown_concentration>0.01)
user << "\red Unknown: [round(unknown_concentration*100)]%"
user << "\blue Temperature: [round(parent.air.temperature-T0C)]&deg;C"
else
user << "\blue Tank is empty!"
vent
icon = 'pipe_vent.dmi'
icon_state = "intact"
name = "Vent"
desc = "A large air vent"
level = 1
volume = 250
dir = SOUTH
initialize_directions = SOUTH
var/obj/machinery/atmospherics/node1
New()
initialize_directions = dir
..()
process()
..()
if(parent)
parent.mingle_with_turf(loc, 250)
Del()
if(node1)
node1.disconnect(src)
..()
pipeline_expansion()
return list(node1)
update_icon()
if(node1)
icon_state = "intact"
dir = get_dir(src, node1)
else
icon_state = "exposed"
initialize()
var/connect_direction = dir
for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
update_icon()
disconnect(obj/machinery/atmospherics/reference)
if(reference == node1)
if(istype(node1, /obj/machinery/atmospherics/pipe))
del(parent)
node1 = null
update_icon()
return null
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(node1)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact"
dir = get_dir(src, node1)
else
icon_state = "exposed"
manifold
icon = 'pipe_manifold.dmi'
icon_state = "manifold-f"
name = "pipe manifold"
desc = "A manifold composed of regular pipes"
volume = 105
dir = SOUTH
initialize_directions = EAST|NORTH|WEST
var/obj/machinery/atmospherics/node1
var/obj/machinery/atmospherics/node2
var/obj/machinery/atmospherics/node3
level = 1
New()
switch(dir)
if(NORTH)
initialize_directions = EAST|SOUTH|WEST
if(SOUTH)
initialize_directions = WEST|NORTH|EAST
if(EAST)
initialize_directions = SOUTH|WEST|NORTH
if(WEST)
initialize_directions = NORTH|EAST|SOUTH
..()
hide(var/i)
if(level == 1 && istype(loc, /turf/simulated))
invisibility = i ? 101 : 0
update_icon()
pipeline_expansion()
return list(node1, node2, node3)
process()
..()
if(!node1)
parent.mingle_with_turf(loc, 70)
else if(!node2)
parent.mingle_with_turf(loc, 70)
else if(!node3)
parent.mingle_with_turf(loc, 70)
Del()
if(node1)
node1.disconnect(src)
if(node2)
node2.disconnect(src)
if(node3)
node3.disconnect(src)
..()
disconnect(obj/machinery/atmospherics/reference)
if(reference == node1)
if(istype(node1, /obj/machinery/atmospherics/pipe))
del(parent)
node1 = null
if(reference == node2)
if(istype(node2, /obj/machinery/atmospherics/pipe))
del(parent)
node2 = null
if(reference == node3)
if(istype(node3, /obj/machinery/atmospherics/pipe))
del(parent)
node3 = null
update_icon()
..()
update_icon()
if(node1&&node2&&node3)
icon_state = "manifold[invisibility ? "-f" : ""]"
else
var/connected = 0
var/unconnected = 0
var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir)
if(node1)
connected |= get_dir(src, node1)
if(node2)
connected |= get_dir(src, node2)
if(node3)
connected |= get_dir(src, node3)
unconnected = (~connected)&(connect_directions)
icon_state = "manifold_[connected]_[unconnected]"
if(!connected)
del(src)
return
initialize()
var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir)
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
connect_directions &= ~direction
break
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
connect_directions &= ~direction
break
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
if(target.initialize_directions & get_dir(target,src))
node3 = target
break
connect_directions &= ~direction
break
var/turf/T = src.loc // hide if turf is not intact
hide(T.intact)
//update_icon()

View File

@@ -0,0 +1,604 @@
#define DEBUG
datum/air_group/var/marker
datum/air_group/var/debugging = 0
datum/pipe_network/var/marker
datum/gas_mixture
var/turf/parent
/*
turf/simulated
New()
..()
if(air)
air.parent = src
*/
obj/machinery/door
verb
toggle_door()
set src in world
if(density)
open()
else
close()
turf/space
verb
create_floor()
set src in world
new /turf/simulated/floor(src)
create_meteor(direction as num)
set src in world
var/obj/meteor/M = new( src )
walk(M, direction,10)
turf/simulated/wall
verb
create_floor()
set src in world
new /turf/simulated/floor(src)
obj/item/weapon/tank
verb
adjust_mixture(temperature as num, target_toxin_pressure as num, target_oxygen_pressure as num)
set src in world
if(!air_contents)
usr << "\red ERROR: no gas_mixture associated with this tank"
return null
air_contents.temperature = temperature
air_contents.oxygen = target_oxygen_pressure*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
air_contents.toxins = target_toxin_pressure*air_contents.volume/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
turf/simulated/floor
verb
parent_info()
set src in world
if(parent)
usr << "<B>[x],[y] parent:</B> Processing: [parent.group_processing]"
if(parent.members)
usr << "Members: [parent.members.len]"
else
usr << "Members: None?"
if(parent.borders)
usr << "Borders: [parent.borders.len]"
else
usr << "Borders: None"
if(parent.length_space_border)
usr << "Space Borders: [parent.space_borders.len], Space Length: [parent.length_space_border]"
else
usr << "Space Borders: None"
else
usr << "\blue [x],[y] has no parent air group."
verb
create_wall()
set src in world
new /turf/simulated/wall(src)
verb
adjust_mixture(temp as num, tox as num, oxy as num)
set src in world
var/datum/gas_mixture/stuff = return_air()
stuff.temperature = temp
stuff.toxins = tox
stuff.oxygen = oxy
verb
boom(inner_range as num, middle_range as num, outer_range as num)
set src in world
explosion(src,inner_range,middle_range,outer_range,outer_range)
verb
flag_parent()
set src in world
if(parent)
parent.debugging = !parent.debugging
usr << "[parent.members.len] set to [parent.debugging]"
verb
small_explosion()
set src in world
explosion(src, 1, 2, 3, 3)
verb
large_explosion()
set src in world
explosion(src, 3, 5, 7, 5)
obj/machinery/portable_atmospherics/canister
verb/test_release()
set src in world
set category = "Minor"
valve_open = 1
release_pressure = 1000
obj/machinery/atmospherics
unary
heat_reservoir
verb
toggle_power()
set src in world
set category = "Minor"
on = !on
update_icon()
adjust_temp(temp as num)
set src in world
set category = "Minor"
current_temperature = temp
cold_sink
verb
toggle_power()
set src in world
set category = "Minor"
on = !on
update_icon()
adjust_temp(temp as num)
set src in world
set category = "Minor"
current_temperature = temp
vent_pump
verb
toggle_power()
set src in world
set category = "Minor"
on = !on
update_icon()
toggle_direction()
set src in world
set category = "Minor"
pump_direction = !pump_direction
update_icon()
change_pressure_parameters()
set src in world
set category = "Minor"
usr << "current settings: PC=[pressure_checks], EB=[external_pressure_bound], IB=[internal_pressure_bound]"
var/mode = input(usr, "Select an option:") in list("Bound External", "Bound Internal", "Bound Both")
switch(mode)
if("Bound External")
pressure_checks = 1
external_pressure_bound = input(usr, "External Pressure Bound?") as num
if("Bound Internal")
pressure_checks = 2
internal_pressure_bound = input(usr, "Internal Pressure Bound?") as num
else
pressure_checks = 3
external_pressure_bound = input(usr, "External Pressure Bound?") as num
internal_pressure_bound = input(usr, "Internal Pressure Bound?") as num
outlet_injector
verb
toggle_power()
set src in world
set category = "Minor"
on = !on
update_icon()
verb
trigger_inject()
set src in world
set category = "Minor"
inject()
vent_scrubber
verb
toggle_power()
set src in world
set category = "Minor"
on = !on
update_icon()
toggle_scrubbing()
set src in world
set category = "Minor"
scrubbing = !scrubbing
update_icon()
change_rate(amount as num)
set src in world
set category = "Minor"
volume_rate = amount
mixer
verb
toggle()
set src in world
set category = "Minor"
on = !on
update_icon()
change_pressure(amount as num)
set src in world
set category = "Minor"
target_pressure = amount
change_ratios()
set src in world
set category = "Minor"
if(node_in1)
var/node_ratio = input(usr, "Node 1 Ratio? ([dir2text(get_dir(src, node_in1))])") as num
node_ratio = min(max(0,node_ratio),1)
node1_concentration = node_ratio
node2_concentration = 1-node_ratio
else
node2_concentration = 1
node1_concentration = 0
usr << "Node 1: [node1_concentration], Node 2: [node2_concentration]"
filter
verb
toggle()
set src in world
set category = "Minor"
on = !on
update_icon()
change_pressure(amount as num)
set src in world
set category = "Minor"
target_pressure = amount
unary/oxygen_generator
verb
toggle()
set src in world
set category = "Minor"
on = !on
update_icon()
change_rate(amount as num)
set src in world
set category = "Minor"
oxygen_content = amount
binary/pump
verb
debug()
set src in world
set category = "Minor"
world << "Debugging: [x],[y]"
if(node1)
world << "Input node: [node1.x],[node1.y] [network1]"
if(node2)
world << "Output node: [node2.x],[node2.y] [network2]"
toggle()
set src in world
set category = "Minor"
on = !on
update_icon()
change_pressure(amount as num)
set src in world
set category = "Minor"
target_pressure = amount
valve
verb
toggle()
set src in world
set category = "Minor"
if(open)
close()
else
open()
network_data()
set src in world
set category = "Minor"
world << "\blue [x],[y]"
world << "network 1: [network_node1.normal_members.len], [network_node1.line_members.len]"
for(var/obj/O in network_node1.normal_members)
world << "member: [O.x], [O.y]"
world << "network 2: [network_node2.normal_members.len], [network_node2.line_members.len]"
for(var/obj/O in network_node2.normal_members)
world << "member: [O.x], [O.y]"
pipe
verb
destroy()
set src in world
set category = "Minor"
del(src)
pipeline_data()
set src in world
set category = "Minor"
if(parent)
usr << "[x],[y] is in a pipeline with [parent.members.len] members ([parent.edges.len] edges)! Volume: [parent.air.volume]"
usr << "Pressure: [parent.air.return_pressure()], Temperature: [parent.air.temperature]"
usr << "[parent.air.oxygen], [parent.air.toxins], [parent.air.nitrogen], [parent.air.carbon_dioxide] .. [parent.alert_pressure]"
mob
verb
flag_all_pipe_networks()
set category = "Debug"
for(var/datum/pipe_network/network in pipe_networks)
network.update = 1
mark_pipe_networks()
set category = "Debug"
for(var/datum/pipe_network/network in pipe_networks)
network.marker = rand(1,4)
for(var/obj/machinery/atmospherics/pipe/P in world)
P.overlays = null
var/datum/pipe_network/master = P.return_network()
if(master)
P.overlays += icon('atmos_testing.dmi',"marker[master.marker]")
else
world << "error"
P.overlays += icon('atmos_testing.dmi',"marker0")
for(var/obj/machinery/atmospherics/valve/V in world)
V.overlays = null
if(V.network_node1)
V.overlays += icon('atmos_testing.dmi',"marker[V.network_node1.marker]")
else
V.overlays += icon('atmos_testing.dmi',"marker0")
if(V.network_node2)
V.overlays += icon('atmos_testing.dmi',"marker[V.network_node2.marker]")
else
V.overlays += icon('atmos_testing.dmi',"marker0")
turf/simulated
var/fire_verbose = 0
verb
mark_direction()
set src in world
overlays = null
for(var/direction in list(NORTH,SOUTH,EAST,WEST))
if(group_border&direction)
overlays += icon('turf_analysis.dmi',"red_arrow",direction)
else if(air_check_directions&direction)
overlays += icon('turf_analysis.dmi',"arrow",direction)
air_status()
set src in world
set category = "Minor"
var/datum/gas_mixture/GM = return_air()
usr << "\blue @[x],[y] ([GM.group_multiplier]): O:[GM.oxygen] T:[GM.toxins] N:[GM.nitrogen] C:[GM.carbon_dioxide] w [GM.temperature] Kelvin, [GM.return_pressure()] kPa [(active_hotspot)?("\red BURNING"):(null)]"
for(var/datum/gas/trace_gas in GM.trace_gases)
usr << "[trace_gas.type]: [trace_gas.moles]"
force_temperature(temp as num)
set src in world
set category = "Minor"
if(parent&&parent.group_processing)
parent.suspend_group_processing()
air.temperature = temp
spark_temperature(temp as num, volume as num)
set src in world
set category = "Minor"
hotspot_expose(temp, volume)
fire_verbose()
set src in world
set category = "Minor"
fire_verbose = !fire_verbose
usr << "[x],[y] now [fire_verbose]"
add_sleeping_agent(amount as num)
set src in world
set category = "Minor"
if(amount>1)
var/datum/gas_mixture/adding = new
var/datum/gas/sleeping_agent/trace_gas = new
trace_gas.moles = amount
adding.trace_gases += trace_gas
adding.temperature = T20C
assume_air(adding)
obj/indicator
icon = 'air_meter.dmi'
var/measure = "temperature"
anchored = 1
proc/process()
icon_state = measurement()
proc/measurement()
var/turf/T = loc
if(!isturf(T)) return
var/datum/gas_mixture/GM = T.return_air()
switch(measure)
if("temperature")
if(GM.temperature < 0)
return "error"
return "[round(GM.temperature/100+0.5)]"
if("oxygen")
if(GM.oxygen < 0)
return "error"
return "[round(GM.oxygen/MOLES_CELLSTANDARD*10+0.5)]"
if("plasma")
if(GM.toxins < 0)
return "error"
return "[round(GM.toxins/MOLES_CELLSTANDARD*10+0.5)]"
if("nitrogen")
if(GM.nitrogen < 0)
return "error"
return "[round(GM.nitrogen/MOLES_CELLSTANDARD*10+0.5)]"
else
return "[round((GM.total_moles())/MOLES_CELLSTANDARD*10+0.5)]"
Click()
process()
obj/window
verb
destroy()
set category = "Minor"
set src in world
del(src)
mob
sight = SEE_OBJS|SEE_TURFS
verb
update_indicators()
set category = "Debug"
if(!air_master)
usr << "Cannot find air_system"
return
for(var/obj/indicator/T in world)
T.process()
change_indicators()
set category = "Debug"
if(!air_master)
usr << "Cannot find air_system"
return
var/str = input("Select") in list("oxygen", "nitrogen","plasma","all","temperature")
for(var/obj/indicator/T in world)
T.measure = str
T.process()
fire_report()
set category = "Debug"
usr << "\b \red Fire Report"
for(var/obj/hotspot/flame in world)
usr << "[flame.x],[flame.y]: [flame.temperature]K, [flame.volume] L - [flame.loc:air:temperature]"
process_cycle()
set category = "Debug"
if(!master_controller)
usr << "Cannot find master_controller"
return
master_controller.process()
update_indicators()
process_cycles(amount as num)
set category = "Debug"
if(!master_controller)
usr << "Cannot find master_controller"
return
var/start_time = world.timeofday
for(var/i=1; i<=amount; i++)
master_controller.process()
world << "Ended [amount] cycles in [(world.timeofday-start_time)/10] seconds. [(world.timeofday-start_time)/10-amount] calculation lag"
update_indicators()
process_updates_early()
set category = "Debug"
if(!air_master)
usr << "Cannot find air_system"
return
air_master.process_update_tiles()
air_master.process_rebuild_select_groups()
mark_groups()
set category = "Debug"
if(!air_master)
usr << "Cannot find air_system"
return
for(var/datum/air_group/group in air_master.air_groups)
group.marker = 0
for(var/turf/simulated/floor/S in world)
S.icon = 'turf_analysis.dmi'
if(S.parent)
if(S.parent.group_processing)
if(S.parent.marker == 0)
S.parent.marker = rand(1,5)
if(S.parent.borders && S.parent.borders.Find(S))
S.icon_state = "on[S.parent.marker]_border"
else
S.icon_state = "on[S.parent.marker]"
else
S.icon_state = "suspended"
else
if(S.processing)
S.icon_state = "individual_on"
else
S.icon_state = "individual_off"
get_broken_icons()
set category = "Debug"
getbrokeninhands()
/*
for(var/obj/movable/floor/S in world)
S.icon = 'turf_analysis.dmi'
if(S.parent)
if(S.parent.group_processing)
if(S.parent.marker == 0)
S.parent.marker = rand(1,5)
if(S.parent.borders && S.parent.borders.Find(S))
S.icon_state = "on[S.parent.marker]_border"
else
S.icon_state = "on[S.parent.marker]"
else
S.icon_state = "suspended"
else
if(S.processing)
S.icon_state = "individual_on"
else
S.icon_state = "individual_off"
*/

299
code/FEA/FEA_airgroup.dm Normal file
View File

@@ -0,0 +1,299 @@
datum
air_group
var/tmp/group_processing = 1 //Processing all tiles as one large tile if 1
var/tmp/datum/gas_mixture/air = new
var/tmp/current_cycle = 0 //cycle that oxygen value represents
var/tmp/archived_cycle = 0 //cycle that oxygen_archived value represents
//The use of archived cycle saves processing power by permitting the archiving step of FET
// to be rolled into the updating step
proc
archive()
members()
//Returns the members of the group
check_regroup()
//If individually processing tiles, checks all member tiles to see if they are close enough
// that the group may resume group processing
//Warning: Do not call, called by air_master.process()
process_group()
suspend_group_processing()
update_group_from_tiles()
//Copy group air information to individual tile air
//Used right before turning on group processing
update_tiles_from_group()
//Copy group air information to individual tile air
//Used right before turning off group processing
var/list/borders //Tiles that connect this group to other groups/individual tiles
var/list/members //All tiles in this group
var/list/space_borders
var/length_space_border = 0
suspend_group_processing()
update_tiles_from_group()
group_processing = 0
update_group_from_tiles()
var/sample_member = pick(members)
var/datum/gas_mixture/sample_air = sample_member:air
air.copy_from(sample_air)
air.group_multiplier = members.len
return 1
update_tiles_from_group()
for(var/member in members)
member:air.copy_from(air)
archive()
air.archive()
archived_cycle = air_master.current_cycle
check_regroup()
//Purpose: Checks to see if group processing should be turned back on
//Returns: group_processing
if(group_processing) return 1
var/turf/simulated/sample = pick(members)
for(var/member in members)
if(member:active_hotspot)
return 0
if(member:air.compare(sample.air)) continue
else
return 0
update_group_from_tiles()
group_processing = 1
return 1
turf/process_group()
current_cycle = air_master.current_cycle
if(group_processing) //See if processing this group as a group
var/turf/simulated/list/border_individual = list()
var/datum/air_group/list/border_group = list()
var/turf/simulated/list/enemies = list() //used to send the appropriate border tile of a group to the group proc
var/turf/simulated/list/self_group_borders = list()
var/turf/simulated/list/self_tile_borders = list()
if(archived_cycle < air_master.current_cycle)
archive()
//Archive air data for use in calculations
//But only if another group didn't store it for us
for(var/turf/simulated/border_tile in src.borders)
//var/obj/movable/floor/movable_on_me = locate(/obj/movable/floor) in border_tile
for(var/direction in cardinal) //Go through all border tiles and get bordering groups and individuals
if(border_tile.group_border&direction)
var/turf/simulated/enemy_tile = get_step(border_tile, direction) //Add found tile to appropriate category
//var/obj/movable/floor/movable_on_enemy
//if(!movable_on_me)
// movable_on_enemy = locate(/obj/movable/floor) in enemy_tile
/*if(movable_on_enemy) //guaranteed !movable_on_me if this is set
if(movable_on_enemy.parent && movable_on_enemy.parent.group_processing)
border_group += movable_on_enemy.parent
enemies += movable_on_enemy
self_group_borders += border_tile
else
border_individual += movable_on_enemy
self_tile_borders += border_tile
else*/
if(istype(enemy_tile) && enemy_tile.parent && enemy_tile.parent.group_processing)
border_group += enemy_tile.parent
enemies += enemy_tile
self_group_borders += border_tile
else
border_individual += enemy_tile
self_tile_borders += border_tile
var/abort_group = 0
// Process connections to adjacent groups
var/border_index = 1
for(var/datum/air_group/AG in border_group)
if(AG.archived_cycle < archived_cycle) //archive other groups information if it has not been archived yet this cycle
AG.archive()
if(AG.current_cycle < current_cycle)
//This if statement makes sure two groups only process their individual connections once!
//Without it, each connection would be processed a second time as the second group is evaluated
var/connection_difference = 0
var/turf/simulated/floor/self_border = self_group_borders[border_index]
var/turf/simulated/floor/enemy_border = enemies[border_index]
var/result = air.check_gas_mixture(AG.air)
if(result == 1)
connection_difference = air.share(AG.air)
else if(result == -1)
AG.suspend_group_processing()
connection_difference = air.share(enemy_border.air)
else
abort_group = 1
break
if(connection_difference)
if(connection_difference > 0)
self_border.consider_pressure_difference(connection_difference, get_dir(self_border,enemy_border))
else
var/turf/enemy_turf = enemy_border
if(!isturf(enemy_turf))
enemy_turf = enemy_border.loc
enemy_turf.consider_pressure_difference(-connection_difference, get_dir(enemy_turf,self_border))
border_index++
// Process connections to adjacent tiles
border_index = 1
if(!abort_group)
for(var/atom/enemy_tile in border_individual)
var/connection_difference = 0
var/turf/simulated/floor/self_border = self_tile_borders[border_index]
if(istype(enemy_tile, /turf/simulated))
if(enemy_tile:archived_cycle < archived_cycle) //archive tile information if not already done
enemy_tile:archive()
if(enemy_tile:current_cycle < current_cycle)
if(air.check_gas_mixture(enemy_tile:air))
connection_difference = air.share(enemy_tile:air)
else
abort_group = 1
break
else if(isturf(enemy_tile))
if(air.check_turf(enemy_tile))
connection_difference = air.mimic(enemy_tile)
else
abort_group = 1
break
if(connection_difference)
if(connection_difference > 0)
self_border.consider_pressure_difference(connection_difference, get_dir(self_border,enemy_tile))
else
var/turf/enemy_turf = enemy_tile
if(!isturf(enemy_turf))
enemy_turf = enemy_tile.loc
enemy_turf.consider_pressure_difference(-connection_difference, get_dir(enemy_tile,enemy_turf))
// Process connections to space
border_index = 1
if(!abort_group)
if(length_space_border > 0)
var/turf/space/sample = locate()
var/connection_difference = 0
if(air.check_turf(sample))
connection_difference = air.mimic(sample, length_space_border)
else
abort_group = 1
if(connection_difference)
for(var/turf/simulated/self_border in space_borders)
self_border.consider_pressure_difference_space(connection_difference)
if(abort_group)
suspend_group_processing()
else
if(air.check_tile_graphic())
for(var/turf/simulated/member in members)
member.update_visuals(air)
if(!group_processing) //Revert to individual processing
for(var/turf/simulated/member in members)
member.process_cell()
else
if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
for(var/turf/simulated/member in members)
member.hotspot_expose(air.temperature, CELL_VOLUME)
member.consider_superconductivity(starting=1)
air.react()
object/process_group()
current_cycle = air_master.current_cycle
if(group_processing) //See if processing this group as a group
var/turf/simulated/list/border_individual = list()
var/datum/air_group/list/border_group = list()
var/turf/simulated/list/enemies = list() //used to send the appropriate border tile of a group to the group proc
var/enemy_index = 1
if(archived_cycle < air_master.current_cycle)
archive()
//Archive air data for use in calculations
//But only if another group didn't store it for us
/*
for(var/obj/movable/floor/border_tile in src.borders)
for(var/direction in list(NORTH,SOUTH,EAST,WEST)) //Go through all border tiles and get bordering groups and individuals
if(border_tile.group_border&direction)
var/turf/simulated/enemy_tile = get_step(border_tile, direction) //Add found tile to appropriate category
var/obj/movable/floor/movable_on_enemy = locate(/obj/movable/floor) in enemy_tile
if(movable_on_enemy)
if(movable_on_enemy.parent && movable_on_enemy.parent.group_processing)
border_group += movable_on_enemy.parent
enemies += movable_on_enemy
enemy_index++
else
border_individual += movable_on_enemy
else
if(istype(enemy_tile) && enemy_tile.parent && enemy_tile.parent.group_processing)
border_group += enemy_tile.parent
enemies += enemy_tile
enemy_index++
else
border_individual += enemy_tile
*/
enemy_index = 1
var/abort_group = 0
for(var/datum/air_group/AG in border_group)
if(AG.archived_cycle < archived_cycle) //archive other groups information if it has not been archived yet this cycle
AG.archive()
if(AG.current_cycle < current_cycle)
//This if statement makes sure two groups only process their individual connections once!
//Without it, each connection would be processed a second time as the second group is evaluated
var/result = air.check_gas_mixture(AG.air)
if(result == 1)
air.share(AG.air)
else if(result == -1)
AG.suspend_group_processing()
var/turf/simulated/floor/enemy_border = enemies[enemy_index]
air.share(enemy_border.air)
else
abort_group = 0
break
enemy_index++
if(!abort_group)
for(var/enemy_tile in border_individual)
if(istype(enemy_tile, /turf/simulated))
if(enemy_tile:archived_cycle < archived_cycle) //archive tile information if not already done
enemy_tile:archive()
if(enemy_tile:current_cycle < current_cycle)
if(air.check_gas_mixture(enemy_tile:air))
air.share(enemy_tile:air)
else
abort_group = 1
break
else
if(air.check_turf(enemy_tile))
air.mimic(enemy_tile)
else
abort_group = 1
break
if(abort_group)
suspend_group_processing()

146
code/FEA/FEA_fire.dm Normal file
View File

@@ -0,0 +1,146 @@
atom
proc
temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return null
turf
proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
simulated
hotspot_expose(exposed_temperature, exposed_volume, soh)
var/datum/gas_mixture/air_contents = return_air()
if(!air_contents)
return 0
if(active_hotspot)
if(soh)
if(air_contents.toxins > 0.5 && air_contents.oxygen > 0.5)
if(active_hotspot.temperature < exposed_temperature)
active_hotspot.temperature = exposed_temperature
if(active_hotspot.volume < exposed_volume)
active_hotspot.volume = exposed_volume
return 1
var/igniting = 0
if((exposed_temperature > PLASMA_MINIMUM_BURN_TEMPERATURE) && air_contents.toxins > 0.5)
igniting = 1
if(igniting)
if(air_contents.oxygen < 0.5 || air_contents.toxins < 0.5)
return 0
if(parent&&parent.group_processing)
parent.suspend_group_processing()
active_hotspot = new(src)
active_hotspot.temperature = exposed_temperature
active_hotspot.volume = exposed_volume
active_hotspot.just_spawned = (current_cycle < air_master.current_cycle)
//remove just_spawned protection if no longer processing this cell
return igniting
obj
hotspot
//Icon for fire on turfs, also helps for nurturing small fires until they are full tile
anchored = 1
mouse_opacity = 0
//luminosity = 3
icon = 'fire.dmi'
icon_state = "1"
layer = TURF_LAYER
var
volume = 125
temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
just_spawned = 1
bypassing = 0
proc/perform_exposure()
var/turf/simulated/floor/location = loc
if(!istype(location))
return 0
if(volume > CELL_VOLUME*0.95)
bypassing = 1
else bypassing = 0
if(bypassing)
if(!just_spawned)
volume = location.air.fuel_burnt*FIRE_GROWTH_RATE
temperature = location.air.temperature
else
var/datum/gas_mixture/affected = location.air.remove_ratio(volume/location.air.volume)
affected.temperature = temperature
affected.react()
temperature = affected.temperature
volume = affected.fuel_burnt*FIRE_GROWTH_RATE
location.assume_air(affected)
for(var/atom/item in loc)
item.temperature_expose(null, temperature, volume)
proc/process(turf/simulated/list/possible_spread)
if(just_spawned)
just_spawned = 0
return 0
var/turf/simulated/floor/location = loc
if(!istype(location))
del(src)
if((temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) || (volume <= 1))
del(src)
if(location.air.toxins < 0.5 || location.air.oxygen < 0.5)
del(src)
perform_exposure()
if(location.wet) location.wet = 0
if(bypassing)
icon_state = "3"
location.burn_tile()
//Possible spread due to radiated heat
if(location.air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_SPREAD)
var/radiated_temperature = location.air.temperature*FIRE_SPREAD_RADIOSITY_SCALE
for(var/turf/simulated/possible_target in possible_spread)
if(!possible_target.active_hotspot)
possible_target.hotspot_expose(radiated_temperature, CELL_VOLUME/4)
else
if(volume > CELL_VOLUME*0.4)
icon_state = "2"
else
icon_state = "1"
return 1
New()
..()
dir = pick(cardinal)
sd_SetLuminosity(3)
Del()
loc:active_hotspot = null
src.sd_SetLuminosity(0)
loc = null
..()

950
code/FEA/FEA_gas_mixture.dm Normal file
View File

@@ -0,0 +1,950 @@
/*
What are the archived variables for?
Calculations are done using the archived variables with the results merged into the regular variables.
This prevents race conditions that arise based on the order of tile processing.
*/
#define SPECIFIC_HEAT_TOXIN 200
#define SPECIFIC_HEAT_AIR 20
#define SPECIFIC_HEAT_CDO 30
#define HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) \
(carbon_dioxide*SPECIFIC_HEAT_CDO + (oxygen+nitrogen)*SPECIFIC_HEAT_AIR + toxins*SPECIFIC_HEAT_TOXIN)
#define MINIMUM_HEAT_CAPACITY 0.0003
#define QUANTIZE(variable) (round(variable,0.0001))
datum
gas
sleeping_agent
specific_heat = 40
oxygen_agent_b
specific_heat = 300
volatile_fuel
specific_heat = 30
var
moles = 0
specific_heat = 0
moles_archived = 0
gas_mixture
var
oxygen = 0
carbon_dioxide = 0
nitrogen = 0
toxins = 0
volume = CELL_VOLUME
temperature = 0 //in Kelvin, use calculate_temperature() to modify
var/group_multiplier = 1
//Size of the group this gas_mixture is representing.
//=1 for singletons
graphic
var/list/datum/gas/trace_gases = list()
tmp
oxygen_archived
carbon_dioxide_archived
nitrogen_archived
toxins_archived
temperature_archived
graphic_archived
fuel_burnt = 0
proc //PV=nRT - related procedures
heat_capacity()
var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins)
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
heat_capacity += trace_gas.moles*trace_gas.specific_heat
return heat_capacity
heat_capacity_archived()
var/heat_capacity_archived = HEAT_CAPACITY_CALCULATION(oxygen_archived,carbon_dioxide_archived,nitrogen_archived,toxins_archived)
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
heat_capacity_archived += trace_gas.moles_archived*trace_gas.specific_heat
return heat_capacity_archived
total_moles()
var/moles = oxygen + carbon_dioxide + nitrogen + toxins
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
moles += trace_gas.moles
return moles
return_pressure()
return total_moles()*R_IDEAL_GAS_EQUATION*temperature/volume
thermal_energy()
return temperature*heat_capacity()
proc //Procedures used for very specific events
check_tile_graphic()
//returns 1 if graphic changed
graphic = null
if(toxins > MOLES_PLASMA_VISIBLE)
graphic = "plasma"
else
var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in trace_gases
if(sleeping_agent && (sleeping_agent.moles > 1))
graphic = "sleeping_agent"
else
graphic = null
return graphic != graphic_archived
react(atom/dump_location)
var/reacting = 0 //set to 1 if a notable reaction occured (used by pipe_network)
if(trace_gases.len > 0)
if(temperature > 900)
if(toxins > MINIMUM_HEAT_CAPACITY && carbon_dioxide > MINIMUM_HEAT_CAPACITY)
var/datum/gas/oxygen_agent_b/trace_gas = locate(/datum/gas/oxygen_agent_b/) in trace_gases
if(trace_gas)
var/reaction_rate = min(carbon_dioxide*0.75, toxins*0.25, trace_gas.moles*0.05)
carbon_dioxide -= reaction_rate
oxygen += reaction_rate
trace_gas.moles -= reaction_rate*0.05
temperature -= (reaction_rate*20000)/heat_capacity()
reacting = 1
fuel_burnt = 0
if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
//world << "pre [temperature], [oxygen], [toxins]"
if(fire() > 0)
reacting = 1
//world << "post [temperature], [oxygen], [toxins]"
return reacting
fire()
var/energy_released = 0
var/old_heat_capacity = heat_capacity()
var/datum/gas/volatile_fuel/fuel_store = locate(/datum/gas/volatile_fuel/) in trace_gases
if(fuel_store) //General volatile gas burn
var/burned_fuel = 0
if(oxygen < fuel_store.moles)
burned_fuel = oxygen
fuel_store.moles -= burned_fuel
oxygen = 0
else
burned_fuel = fuel_store.moles
oxygen -= fuel_store.moles
del(fuel_store)
energy_released += FIRE_CARBON_ENERGY_RELEASED * burned_fuel
carbon_dioxide += burned_fuel
fuel_burnt += burned_fuel
//Handle plasma burning
if(toxins > MINIMUM_HEAT_CAPACITY)
var/plasma_burn_rate = 0
var/oxygen_burn_rate = 0
//more plasma released at higher temperatures
var/temperature_scale
if(temperature > PLASMA_UPPER_TEMPERATURE)
temperature_scale = 1
else
temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
if(temperature_scale > 0)
oxygen_burn_rate = 1.4 - temperature_scale
if(oxygen > toxins*PLASMA_OXYGEN_FULLBURN)
plasma_burn_rate = (toxins*temperature_scale)/4
else
plasma_burn_rate = (temperature_scale*(oxygen/PLASMA_OXYGEN_FULLBURN))/4
if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
toxins -= plasma_burn_rate
oxygen -= plasma_burn_rate*oxygen_burn_rate
carbon_dioxide += plasma_burn_rate
energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
fuel_burnt += (plasma_burn_rate)*(1+oxygen_burn_rate)
if(energy_released > 0)
var/new_heat_capacity = heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
temperature = (temperature*old_heat_capacity + energy_released)/new_heat_capacity
return fuel_burnt
proc
archive()
//Update archived versions of variables
//Returns: 1 in all cases
merge(datum/gas_mixture/giver)
//Merges all air from giver into self. Deletes giver.
//Returns: 1 on success (no failure cases yet)
check_then_merge(datum/gas_mixture/giver)
//Similar to merge(...) but first checks to see if the amount of air assumed is small enough
// that group processing is still accurate for source (aborts if not)
//Returns: 1 on successful merge, 0 if the check failed
remove(amount)
//Proportionally removes amount of gas from the gas_mixture
//Returns: gas_mixture with the gases removed
remove_ratio(ratio)
//Proportionally removes amount of gas from the gas_mixture
//Returns: gas_mixture with the gases removed
subtract(datum/gas_mixture/right_side)
//Subtracts right_side from air_mixture. Used to help turfs mingle
check_then_remove(amount)
//Similar to remove(...) but first checks to see if the amount of air removed is small enough
// that group processing is still accurate for source (aborts if not)
//Returns: gas_mixture with the gases removed or null
copy_from(datum/gas_mixture/sample)
//Copies variables from sample
share(datum/gas_mixture/sharer)
//Performs air sharing calculations between two gas_mixtures assuming only 1 boundary length
//Return: amount of gas exchanged (+ if sharer received)
mimic(turf/model)
//Similar to share(...), except the model is not modified
//Return: amount of gas exchanged
check_gas_mixture(datum/gas_mixture/sharer)
//Returns: 0 if the self-check failed then -1 if sharer-check failed then 1 if both checks pass
check_turf(turf/model)
//Returns: 0 if self-check failed or 1 if check passes
// check_me_then_share(datum/gas_mixture/sharer)
//Similar to share(...) but first checks to see if amount of air moved is small enough
// that group processing is still accurate for source (aborts if not)
//Returns: 1 on successful share, 0 if the check failed
// check_me_then_mimic(turf/model)
//Similar to mimic(...) but first checks to see if amount of air moved is small enough
// that group processing is still accurate (aborts if not)
//Returns: 1 on successful mimic, 0 if the check failed
// check_both_then_share(datum/gas_mixture/sharer)
//Similar to check_me_then_share(...) but also checks to see if amount of air moved is small enough
// that group processing is still accurate for the sharer (aborts if not)
//Returns: 0 if the self-check failed then -1 if sharer-check failed then 1 if successful share
temperature_mimic(turf/model, conduction_coefficient)
temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
temperature_turf_share(turf/simulated/sharer, conduction_coefficient)
check_me_then_temperature_mimic(turf/model, conduction_coefficient)
check_me_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
check_both_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
check_me_then_temperature_turf_share(turf/simulated/sharer, conduction_coefficient)
compare(datum/gas_mixture/sample)
//Compares sample to self to see if within acceptable ranges that group processing may be enabled
archive()
oxygen_archived = oxygen
carbon_dioxide_archived = carbon_dioxide
nitrogen_archived = nitrogen
toxins_archived = toxins
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
trace_gas.moles_archived = trace_gas.moles
temperature_archived = temperature
graphic_archived = graphic
return 1
check_then_merge(datum/gas_mixture/giver)
if(!giver)
return 0
if(((giver.oxygen > MINIMUM_AIR_TO_SUSPEND) && (giver.oxygen >= oxygen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((giver.carbon_dioxide > MINIMUM_AIR_TO_SUSPEND) && (giver.carbon_dioxide >= carbon_dioxide*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((giver.nitrogen > MINIMUM_AIR_TO_SUSPEND) && (giver.nitrogen >= nitrogen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((giver.toxins > MINIMUM_AIR_TO_SUSPEND) && (giver.toxins >= toxins*MINIMUM_AIR_RATIO_TO_SUSPEND)))
return 0
if(abs(giver.temperature - temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
return 0
if(giver.trace_gases.len)
for(var/datum/gas/trace_gas in giver.trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
if((trace_gas.moles > MINIMUM_AIR_TO_SUSPEND) && (!corresponding || (trace_gas.moles >= corresponding.moles*MINIMUM_AIR_RATIO_TO_SUSPEND)))
return 0
return merge(giver)
merge(datum/gas_mixture/giver)
if(!giver)
return 0
if(abs(temperature-giver.temperature)>MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity()*group_multiplier
var/giver_heat_capacity = giver.heat_capacity()*giver.group_multiplier
var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity
if(combined_heat_capacity != 0)
temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity
if((group_multiplier>1)||(giver.group_multiplier>1))
oxygen += giver.oxygen*giver.group_multiplier/group_multiplier
carbon_dioxide += giver.carbon_dioxide*giver.group_multiplier/group_multiplier
nitrogen += giver.nitrogen*giver.group_multiplier/group_multiplier
toxins += giver.toxins*giver.group_multiplier/group_multiplier
else
oxygen += giver.oxygen
carbon_dioxide += giver.carbon_dioxide
nitrogen += giver.nitrogen
toxins += giver.toxins
if(giver.trace_gases.len)
for(var/datum/gas/trace_gas in giver.trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
trace_gases += corresponding
corresponding.moles += trace_gas.moles*giver.group_multiplier/group_multiplier
del(giver)
return 1
remove(amount)
var/sum = total_moles()
amount = min(amount,sum) //Can not take more air than tile has!
if(amount <= 0)
return null
var/datum/gas_mixture/removed = new
removed.oxygen = QUANTIZE((oxygen/sum)*amount)
removed.nitrogen = QUANTIZE((nitrogen/sum)*amount)
removed.carbon_dioxide = QUANTIZE((carbon_dioxide/sum)*amount)
removed.toxins = QUANTIZE((toxins/sum)*amount)
oxygen -= removed.oxygen/group_multiplier
nitrogen -= removed.nitrogen/group_multiplier
carbon_dioxide -= removed.carbon_dioxide/group_multiplier
toxins -= removed.toxins/group_multiplier
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
var/datum/gas/corresponding = new trace_gas.type()
removed.trace_gases += corresponding
corresponding.moles = (trace_gas.moles/sum)*amount
trace_gas.moles -= corresponding.moles/group_multiplier
removed.temperature = temperature
return removed
remove_ratio(ratio)
if(ratio <= 0)
return null
ratio = min(ratio, 1)
var/datum/gas_mixture/removed = new
removed.oxygen = QUANTIZE(oxygen*ratio)
removed.nitrogen = QUANTIZE(nitrogen*ratio)
removed.carbon_dioxide = QUANTIZE(carbon_dioxide*ratio)
removed.toxins = QUANTIZE(toxins*ratio)
oxygen -= removed.oxygen/group_multiplier
nitrogen -= removed.nitrogen/group_multiplier
carbon_dioxide -= removed.carbon_dioxide/group_multiplier
toxins -= removed.toxins/group_multiplier
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
var/datum/gas/corresponding = new trace_gas.type()
removed.trace_gases += corresponding
corresponding.moles = trace_gas.moles*ratio
trace_gas.moles -= corresponding.moles/group_multiplier
removed.temperature = temperature
return removed
check_then_remove(amount)
//Since it is all proportional, the check may be done on the gas as a whole
var/sum = total_moles()
amount = min(amount,sum) //Can not take more air than tile has!
if((amount > MINIMUM_AIR_RATIO_TO_SUSPEND) && (amount > sum*MINIMUM_AIR_RATIO_TO_SUSPEND))
return 0
return remove(amount)
copy_from(datum/gas_mixture/sample)
oxygen = sample.oxygen
carbon_dioxide = sample.carbon_dioxide
nitrogen = sample.nitrogen
toxins = sample.toxins
trace_gases.len=null
if(sample.trace_gases.len > 0)
for(var/datum/gas/trace_gas in sample.trace_gases)
var/datum/gas/corresponding = new trace_gas.type()
trace_gases += corresponding
corresponding.moles = trace_gas.moles
temperature = sample.temperature
return 1
subtract(datum/gas_mixture/right_side)
oxygen -= right_side.oxygen
carbon_dioxide -= right_side.carbon_dioxide
nitrogen -= right_side.nitrogen
toxins -= right_side.toxins
if((trace_gases.len > 0)||(right_side.trace_gases.len > 0))
for(var/datum/gas/trace_gas in right_side.trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
trace_gases += corresponding
corresponding.moles -= trace_gas.moles
return 1
/* check_me_then_share(datum/gas_mixture/sharer)
var/delta_oxygen = (oxygen_archived - sharer.oxygen_archived)/5
var/delta_carbon_dioxide = (carbon_dioxide_archived - sharer.carbon_dioxide_archived)/5
var/delta_nitrogen = (nitrogen_archived - sharer.nitrogen_archived)/5
var/delta_toxins = (toxins_archived - sharer.toxins_archived)/5
var/delta_temperature = (temperature_archived - sharer.temperature_archived)
if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)))
return 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
return 0
return share(sharer)*/
check_gas_mixture(datum/gas_mixture/sharer)
var/delta_oxygen = (oxygen_archived - sharer.oxygen_archived)/5
var/delta_carbon_dioxide = (carbon_dioxide_archived - sharer.carbon_dioxide_archived)/5
var/delta_nitrogen = (nitrogen_archived - sharer.nitrogen_archived)/5
var/delta_toxins = (toxins_archived - sharer.toxins_archived)/5
var/delta_temperature = (temperature_archived - sharer.temperature_archived)
if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)))
return 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
return 0
if(sharer.trace_gases.len)
for(var/datum/gas/trace_gas in sharer.trace_gases)
if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4)
var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
if(corresponding)
if(trace_gas.moles_archived >= corresponding.moles_archived*MINIMUM_AIR_RATIO_TO_SUSPEND*4)
return 0
else
return 0
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4)
if(!locate(trace_gas.type) in sharer.trace_gases)
return 0
if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= sharer.oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= sharer.carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= sharer.nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= sharer.toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)))
return -1
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4)
var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases
if(corresponding)
if(trace_gas.moles_archived >= corresponding.moles_archived*MINIMUM_AIR_RATIO_TO_SUSPEND*4)
return -1
else
return -1
return 1
check_turf(turf/model)
var/delta_oxygen = (oxygen_archived - model.oxygen)/5
var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide)/5
var/delta_nitrogen = (nitrogen_archived - model.nitrogen)/5
var/delta_toxins = (toxins_archived - model.toxins)/5
var/delta_temperature = (temperature_archived - model.temperature)
if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \
|| ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)))
return 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
return 0
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4)
return 0
return 1
share(datum/gas_mixture/sharer)
var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/5
var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/5
var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/5
var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/5
var/delta_temperature = (temperature_archived - sharer.temperature_archived)
var/old_self_heat_capacity = 0
var/old_sharer_heat_capacity = 0
var/heat_self_to_sharer = 0
var/heat_capacity_self_to_sharer = 0
var/heat_sharer_to_self = 0
var/heat_capacity_sharer_to_self = 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/delta_air = delta_oxygen+delta_nitrogen
if(delta_air)
var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air
if(delta_air > 0)
heat_self_to_sharer += air_heat_capacity*temperature_archived
heat_capacity_self_to_sharer += air_heat_capacity
else
heat_sharer_to_self -= air_heat_capacity*sharer.temperature_archived
heat_capacity_sharer_to_self -= air_heat_capacity
if(delta_carbon_dioxide)
var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide
if(delta_carbon_dioxide > 0)
heat_self_to_sharer += carbon_dioxide_heat_capacity*temperature_archived
heat_capacity_self_to_sharer += carbon_dioxide_heat_capacity
else
heat_sharer_to_self -= carbon_dioxide_heat_capacity*sharer.temperature_archived
heat_capacity_sharer_to_self -= carbon_dioxide_heat_capacity
if(delta_toxins)
var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins
if(delta_toxins > 0)
heat_self_to_sharer += toxins_heat_capacity*temperature_archived
heat_capacity_self_to_sharer += toxins_heat_capacity
else
heat_sharer_to_self -= toxins_heat_capacity*sharer.temperature_archived
heat_capacity_sharer_to_self -= toxins_heat_capacity
old_self_heat_capacity = heat_capacity()*group_multiplier
old_sharer_heat_capacity = sharer.heat_capacity()*sharer.group_multiplier
oxygen -= delta_oxygen/group_multiplier
sharer.oxygen += delta_oxygen/sharer.group_multiplier
carbon_dioxide -= delta_carbon_dioxide/group_multiplier
sharer.carbon_dioxide += delta_carbon_dioxide/sharer.group_multiplier
nitrogen -= delta_nitrogen/group_multiplier
sharer.nitrogen += delta_nitrogen/sharer.group_multiplier
toxins -= delta_toxins/group_multiplier
sharer.toxins += delta_toxins/sharer.group_multiplier
var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins)
var/list/trace_types_considered = list()
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases
var/delta = 0
if(corresponding)
delta = QUANTIZE(trace_gas.moles_archived - corresponding.moles_archived)/5
else
corresponding = new trace_gas.type()
sharer.trace_gases += corresponding
delta = trace_gas.moles_archived/5
trace_gas.moles -= delta/group_multiplier
corresponding.moles += delta/sharer.group_multiplier
if(delta)
var/individual_heat_capacity = trace_gas.specific_heat*delta
if(delta > 0)
heat_self_to_sharer += individual_heat_capacity*temperature_archived
heat_capacity_self_to_sharer += individual_heat_capacity
else
heat_sharer_to_self -= individual_heat_capacity*sharer.temperature_archived
heat_capacity_sharer_to_self -= individual_heat_capacity
moved_moles += delta
trace_types_considered += trace_gas.type
if(sharer.trace_gases.len)
for(var/datum/gas/trace_gas in sharer.trace_gases)
if(trace_gas.type in trace_types_considered) continue
else
var/datum/gas/corresponding
var/delta = 0
corresponding = new trace_gas.type()
trace_gases += corresponding
delta = trace_gas.moles_archived/5
trace_gas.moles -= delta/sharer.group_multiplier
corresponding.moles += delta/group_multiplier
//Guaranteed transfer from sharer to self
var/individual_heat_capacity = trace_gas.specific_heat*delta
heat_sharer_to_self += individual_heat_capacity*sharer.temperature_archived
heat_capacity_sharer_to_self += individual_heat_capacity
moved_moles += -delta
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/new_self_heat_capacity = old_self_heat_capacity + heat_capacity_sharer_to_self - heat_capacity_self_to_sharer
var/new_sharer_heat_capacity = old_sharer_heat_capacity + heat_capacity_self_to_sharer - heat_capacity_sharer_to_self
if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY)
temperature = (old_self_heat_capacity*temperature - heat_capacity_self_to_sharer*temperature_archived + heat_capacity_sharer_to_self*sharer.temperature_archived)/new_self_heat_capacity
if(new_sharer_heat_capacity > MINIMUM_HEAT_CAPACITY)
sharer.temperature = (old_sharer_heat_capacity*sharer.temperature-heat_capacity_sharer_to_self*sharer.temperature_archived + heat_capacity_self_to_sharer*temperature_archived)/new_sharer_heat_capacity
if(abs(old_sharer_heat_capacity) > MINIMUM_HEAT_CAPACITY)
if(abs(new_sharer_heat_capacity/old_sharer_heat_capacity - 1) < 0.10) // <10% change in sharer heat capacity
temperature_share(sharer, OPEN_HEAT_TRANSFER_COEFFICIENT)
if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - sharer.temperature_archived*(sharer.total_moles() - moved_moles)
return delta_pressure*R_IDEAL_GAS_EQUATION/volume
else
return 0
mimic(turf/model, border_multiplier)
var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen)/5
var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide)/5
var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen)/5
var/delta_toxins = QUANTIZE(toxins_archived - model.toxins)/5
var/delta_temperature = (temperature_archived - model.temperature)
var/heat_transferred = 0
var/old_self_heat_capacity = 0
var/heat_capacity_transferred = 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/delta_air = delta_oxygen+delta_nitrogen
if(delta_air)
var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air
heat_transferred -= air_heat_capacity*model.temperature
heat_capacity_transferred -= air_heat_capacity
if(delta_carbon_dioxide)
var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide
heat_transferred -= carbon_dioxide_heat_capacity*model.temperature
heat_capacity_transferred -= carbon_dioxide_heat_capacity
if(delta_toxins)
var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins
heat_transferred -= toxins_heat_capacity*model.temperature
heat_capacity_transferred -= toxins_heat_capacity
old_self_heat_capacity = heat_capacity()*group_multiplier
if(border_multiplier)
oxygen -= delta_oxygen*border_multiplier/group_multiplier
carbon_dioxide -= delta_carbon_dioxide*border_multiplier/group_multiplier
nitrogen -= delta_nitrogen*border_multiplier/group_multiplier
toxins -= delta_toxins*border_multiplier/group_multiplier
else
oxygen -= delta_oxygen/group_multiplier
carbon_dioxide -= delta_carbon_dioxide/group_multiplier
nitrogen -= delta_nitrogen/group_multiplier
toxins -= delta_toxins/group_multiplier
var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins)
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
var/delta = 0
delta = trace_gas.moles_archived/5
if(border_multiplier)
trace_gas.moles -= delta*border_multiplier/group_multiplier
else
trace_gas.moles -= delta/group_multiplier
var/heat_cap_transferred = delta*trace_gas.specific_heat
heat_transferred += heat_cap_transferred*temperature_archived
heat_capacity_transferred += heat_cap_transferred
moved_moles += delta
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/new_self_heat_capacity = old_self_heat_capacity - heat_capacity_transferred
if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY)
if(border_multiplier)
temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*border_multiplier*temperature_archived)/new_self_heat_capacity
else
temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*border_multiplier*temperature_archived)/new_self_heat_capacity
temperature_mimic(model, model.thermal_conductivity, border_multiplier)
if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - model.temperature*(model.oxygen+model.carbon_dioxide+model.nitrogen+model.toxins)
return delta_pressure*R_IDEAL_GAS_EQUATION/volume
else
return 0
check_both_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
var/delta_temperature = (temperature_archived - sharer.temperature_archived)
var/self_heat_capacity = heat_capacity_archived()
var/sharer_heat_capacity = sharer.heat_capacity_archived()
var/self_temperature_delta = 0
var/sharer_temperature_delta = 0
if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient*delta_temperature* \
(self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity))
self_temperature_delta = -heat/(self_heat_capacity*group_multiplier)
sharer_temperature_delta = heat/(sharer_heat_capacity*sharer.group_multiplier)
else
return 1
if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \
&& (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived))
return 0
if((abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \
&& (abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*sharer.temperature_archived))
return -1
temperature += self_temperature_delta
sharer.temperature += sharer_temperature_delta
return 1
//Logic integrated from: temperature_share(sharer, conduction_coefficient) for efficiency
check_me_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
var/delta_temperature = (temperature_archived - sharer.temperature_archived)
var/self_heat_capacity = heat_capacity_archived()
var/sharer_heat_capacity = sharer.heat_capacity_archived()
var/self_temperature_delta = 0
var/sharer_temperature_delta = 0
if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient*delta_temperature* \
(self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity))
self_temperature_delta = -heat/(self_heat_capacity*group_multiplier)
sharer_temperature_delta = heat/(sharer_heat_capacity*sharer.group_multiplier)
else
return 1
if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \
&& (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived))
return 0
temperature += self_temperature_delta
sharer.temperature += sharer_temperature_delta
return 1
//Logic integrated from: temperature_share(sharer, conduction_coefficient) for efficiency
check_me_then_temperature_turf_share(turf/simulated/sharer, conduction_coefficient)
var/delta_temperature = (temperature_archived - sharer.temperature)
var/self_temperature_delta = 0
var/sharer_temperature_delta = 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity_archived()
if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient*delta_temperature* \
(self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity))
self_temperature_delta = -heat/(self_heat_capacity*group_multiplier)
sharer_temperature_delta = heat/sharer.heat_capacity
else
return 1
if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \
&& (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived))
return 0
temperature += self_temperature_delta
sharer.temperature += sharer_temperature_delta
return 1
//Logic integrated from: temperature_turf_share(sharer, conduction_coefficient) for efficiency
check_me_then_temperature_mimic(turf/model, conduction_coefficient)
var/delta_temperature = (temperature_archived - model.temperature)
var/self_temperature_delta = 0
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity_archived()
if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient*delta_temperature* \
(self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity))
self_temperature_delta = -heat/(self_heat_capacity*group_multiplier)
if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \
&& (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived))
return 0
temperature += self_temperature_delta
return 1
//Logic integrated from: temperature_mimic(model, conduction_coefficient) for efficiency
temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
var/delta_temperature = (temperature_archived - sharer.temperature_archived)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity_archived()
var/sharer_heat_capacity = sharer.heat_capacity_archived()
if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient*delta_temperature* \
(self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity))
temperature -= heat/(self_heat_capacity*group_multiplier)
sharer.temperature += heat/(sharer_heat_capacity*sharer.group_multiplier)
temperature_mimic(turf/model, conduction_coefficient, border_multiplier)
var/delta_temperature = (temperature - model.temperature)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity()//_archived()
if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient*delta_temperature* \
(self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity))
if(border_multiplier)
temperature -= heat*border_multiplier/(self_heat_capacity*group_multiplier)
else
temperature -= heat/(self_heat_capacity*group_multiplier)
temperature_turf_share(turf/simulated/sharer, conduction_coefficient)
var/delta_temperature = (temperature_archived - sharer.temperature)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity()
if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient*delta_temperature* \
(self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity))
temperature -= heat/(self_heat_capacity*group_multiplier)
sharer.temperature += heat/sharer.heat_capacity
compare(datum/gas_mixture/sample)
if((abs(oxygen-sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \
((oxygen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen)))
return 0
if((abs(nitrogen-sample.nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \
((nitrogen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen) || (nitrogen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen)))
return 0
if((abs(carbon_dioxide-sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \
((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide)))
return 0
if((abs(toxins-sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \
((toxins < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins) || (toxins > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins)))
return 0
if(total_moles() > MINIMUM_AIR_TO_SUSPEND)
if((abs(temperature-sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \
((temperature < (1-MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || (temperature > (1+MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature)))
//world << "temp fail [temperature] & [sample.temperature]"
return 0
if(sample.trace_gases.len)
for(var/datum/gas/trace_gas in sample.trace_gases)
if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND)
var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases
if(corresponding)
if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \
((corresponding.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles) || (corresponding.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles)))
return 0
else
return 0
if(trace_gases.len)
for(var/datum/gas/trace_gas in trace_gases)
if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND)
var/datum/gas/corresponding = locate(trace_gas.type) in sample.trace_gases
if(corresponding)
if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \
((trace_gas.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles) || (trace_gas.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles)))
return 0
else
return 0
return 1

View File

@@ -0,0 +1,114 @@
/turf/simulated/proc/find_group()
//Basically, join any nearby valid groups
// If more than one, pick one with most members at my borders
// If can not find any but there was an ungrouped at border with me, call for group assembly
var/turf/simulated/floor/north = get_step(src,NORTH)
var/turf/simulated/floor/south = get_step(src,SOUTH)
var/turf/simulated/floor/east = get_step(src,EAST)
var/turf/simulated/floor/west = get_step(src,WEST)
//Clear those we do not have access to
if(!CanPass(null, north, null, 1) || !istype(north))
north = null
if(!CanPass(null, south, null, 1) || !istype(south))
south = null
if(!CanPass(null, east, null, 1) || !istype(east))
east = null
if(!CanPass(null, west, null, 1) || !istype(west))
west = null
var/new_group_possible = 0
var/north_votes = 0
var/south_votes = 0
var/east_votes = 0
if(north)
if(north.parent)
north_votes = 1
if(south && (south.parent == north.parent))
north_votes++
south = null
if(east && (east.parent == north.parent))
north_votes++
east = null
if(west && (west.parent == north.parent))
north_votes++
west = null
else
new_group_possible = 1
if(south)
if(south.parent)
south_votes = 1
if(east && (east.parent == south.parent))
south_votes++
east = null
if(west && (west.parent == south.parent))
south_votes++
west = null
else
new_group_possible = 1
if(east)
if(east.parent)
east_votes = 1
if(west && (west.parent == east.parent))
east_votes++
west = null
else
new_group_possible = 1
// world << "[north_votes], [south_votes], [east_votes]"
if(west)
if(west.parent)
west.parent.suspend_group_processing()
west.parent.members += src
parent = west.parent
air_master.tiles_to_update += west.parent.members
return 1
else
new_group_possible = 1
if(north_votes && (north_votes >= south_votes) && (north_votes >= east_votes))
north.parent.suspend_group_processing()
north.parent.members += src
parent = north.parent
air_master.tiles_to_update += north.parent.members
return 1
if(south_votes && (south_votes >= east_votes))
south.parent.suspend_group_processing()
south.parent.members += src
parent = south.parent
air_master.tiles_to_update += south.parent.members
return 1
if(east_votes)
east.parent.suspend_group_processing()
east.parent.members += src
parent = east.parent
air_master.tiles_to_update += east.parent.members
return 1
if(new_group_possible)
air_master.assemble_group_turf(src)
return 1
else
air_master.active_singletons += src
return 1

343
code/FEA/FEA_system.dm Normal file
View File

@@ -0,0 +1,343 @@
/*
Overview:
The air_master global variable is the workhorse for the system.
Why are you archiving data before modifying it?
The general concept with archiving data and having each tile keep track of when they were last updated is to keep everything symmetric
and totally independent of the order they are read in an update cycle.
This prevents abnormalities like air/fire spreading rapidly in one direction and super slowly in the other.
Why not just archive everything and then calculate?
Efficiency. While a for-loop that goes through all tils and groups to archive their information before doing any calculations seems simple, it is
slightly less efficient than the archive-before-modify/read method.
Why is there a cycle check for calculating data as well?
This ensures that every connection between group-tile, tile-tile, and group-group is only evaluated once per loop.
Important variables:
air_master.groups_to_rebuild (list)
A list of air groups that have had their geometry occluded and thus may need to be split in half.
A set of adjacent groups put in here will join together if validly connected.
This is done before air system calculations for a cycle.
air_master.tiles_to_update (list)
Turfs that are in this list have their border data updated before the next air calculations for a cycle.
Place turfs in this list rather than call the proc directly to prevent race conditions
turf/simulated.archive() and datum/air_group.archive()
This stores all data for.
If you modify, make sure to update the archived_cycle to prevent race conditions and maintain symmetry
atom/CanPass(atom/movable/mover, turf/target, height, air_group)
returns 1 for allow pass and 0 for deny pass
Turfs automatically call this for all objects/mobs in its turf.
This is called both as source.CanPass(target, height, air_group)
and target.CanPass(source, height, air_group)
Cases for the parameters
1. This is called with args (mover, location, height>0, air_group=0) for normal objects.
2. This is called with args (null, location, height=0, air_group=0) for flowing air.
3. This is called with args (null, location, height=?, air_group=1) for determining group boundaries.
Cases 2 and 3 would be different for doors or other objects open and close fairly often.
(Case 3 would return 0 always while Case 2 would return 0 only when the door is open)
This prevents the necessity of re-evaluating group geometry every time a door opens/closes.
Important Procedures
air_master.process()
This first processes the air_master update/rebuild lists then processes all groups and tiles for air calculations
*/
var/kill_air = 0
atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
return (!density || !height || air_group)
turf
CanPass(atom/movable/mover, turf/target, height=1.5,air_group=0)
if(!target) return 0
if(istype(mover)) // turf/Enter(...) will perform more advanced checks
return !density
else // Now, doing more detailed checks for air movement and air group formation
if(target.blocks_air||blocks_air)
return 0
for(var/obj/obstacle in src)
if(!obstacle.CanPass(mover, target, height, air_group))
return 0
for(var/obj/obstacle in target)
if(!obstacle.CanPass(mover, src, height, air_group))
return 0
return 1
var/global/datum/controller/air_system/air_master
datum
controller
air_system
//Geoemetry lists
var/list/datum/air_group/air_groups = list()
var/list/turf/simulated/active_singletons = list()
//Special functions lists
var/list/turf/simulated/active_super_conductivity = list()
var/list/turf/simulated/high_pressure_delta = list()
//Geometry updates lists
var/list/turf/simulated/tiles_to_update = list()
var/list/turf/simulated/groups_to_rebuild = list()
var/current_cycle = 0
proc
setup()
//Call this at the start to setup air groups geometry
//Warning: Very processor intensive but only must be done once per round
assemble_group_turf(turf/simulated/base)
//Call this to try to construct a group starting from base and merging with neighboring unparented tiles
//Expands the group until all valid borders explored
// assemble_group_object(obj/movable/floor/base)
process()
//Call this to process air movements for a cycle
process_groups()
//Used by process()
//Warning: Do not call this
process_singletons()
//Used by process()
//Warning: Do not call this
process_high_pressure_delta()
//Used by process()
//Warning: Do not call this
process_super_conductivity()
//Used by process()
//Warning: Do not call this
process_update_tiles()
//Used by process()
//Warning: Do not call this
process_rebuild_select_groups()
//Used by process()
//Warning: Do not call this
rebuild_group(datum/air_group)
//Used by process_rebuild_select_groups()
//Warning: Do not call this, add the group to air_master.groups_to_rebuild instead
add_singleton(turf/simulated/T)
if(!active_singletons.Find(T))
active_singletons += T
setup()
world << "\red \b Processing Geometry..."
sleep(1)
var/start_time = world.timeofday
for(var/turf/simulated/S in world)
if(!S.blocks_air && !S.parent && S.z < 5) // Added last check to force skipping asteroid z-levels -- TLE
assemble_group_turf(S)
for(var/turf/simulated/S in world) //Update all pathing and border information as well
if(S.z > 4) // Skipping asteroids -- TLE
continue
S.update_air_properties()
/*
for(var/obj/movable/floor/S in world)
if(!S.parent)
assemble_group_object(S)
for(var/obj/movable/floor/S in world) //Update all pathing and border information as well
S.update_air_properties()
*/
world << "\red \b Geometry processed in [(world.timeofday-start_time)/10] seconds!"
assemble_group_turf(turf/simulated/base)
var/list/turf/simulated/members = list(base) //Confirmed group members
var/list/turf/simulated/possible_members = list(base) //Possible places for group expansion
var/list/turf/simulated/possible_borders = list()
var/list/turf/simulated/possible_space_borders = list()
var/possible_space_length = 0
while(possible_members.len>0) //Keep expanding, looking for new members
for(var/turf/simulated/test in possible_members)
test.length_space_border = 0
for(var/direction in cardinal)
var/turf/T = get_step(test,direction)
if(T && !members.Find(T) && test.CanPass(null, T, null,1))
if(istype(T,/turf/simulated) && !T:parent)
possible_members += T
members += T
else if(istype(T,/turf/space))
possible_space_borders -= test
possible_space_borders += test
test.length_space_border++
else
possible_borders -= test
possible_borders += test
if(test.length_space_border > 0)
possible_space_length += test.length_space_border
possible_members -= test
if(members.len > 1)
var/datum/air_group/turf/group = new
if(possible_borders.len>0)
group.borders = possible_borders
if(possible_space_borders.len>0)
group.space_borders = possible_space_borders
group.length_space_border = possible_space_length
for(var/turf/simulated/test in members)
test.parent = group
test.processing = 0
active_singletons -= test
group.members = members
air_groups += group
group.update_group_from_tiles() //Initialize air group variables
return group
else
base.processing = 0 //singletons at startup are technically unconnected anyway
base.parent = null
if(base.air.check_tile_graphic())
base.update_visuals(base.air)
return null
/*
assemble_group_object(obj/movable/floor/base)
var/list/obj/movable/floor/members = list(base) //Confirmed group members
var/list/obj/movable/floor/possible_members = list(base) //Possible places for group expansion
var/list/obj/movable/floor/possible_borders = list()
while(possible_members.len>0) //Keep expanding, looking for new members
for(var/obj/movable/floor/test in possible_members)
for(var/direction in list(NORTH, SOUTH, EAST, WEST))
var/turf/T = get_step(test.loc,direction)
if(T && test.loc.CanPass(null, T, null, 1))
var/obj/movable/floor/O = locate(/obj/movable/floor) in T
if(istype(O) && !O.parent)
if(!members.Find(O))
possible_members += O
members += O
else
possible_borders -= test
possible_borders += test
possible_members -= test
if(members.len > 1)
var/datum/air_group/object/group = new
if(possible_borders.len>0)
group.borders = possible_borders
for(var/obj/movable/floor/test in members)
test.parent = group
test.processing = 0
active_singletons -= test
group.members = members
air_groups += group
group.update_group_from_tiles() //Initialize air group variables
return group
else
base.processing = 0 //singletons at startup are technically unconnected anyway
base.parent = null
return null
*/
process()
if(kill_air)
return 1
current_cycle++
if(groups_to_rebuild.len > 0) process_rebuild_select_groups()
if(tiles_to_update.len > 0) process_update_tiles()
process_groups()
process_singletons()
process_super_conductivity()
process_high_pressure_delta()
if(current_cycle%10==5) //Check for groups of tiles to resume group processing every 10 cycles
for(var/datum/air_group/AG in air_groups)
AG.check_regroup()
return 1
process_update_tiles()
for(var/turf/simulated/T in tiles_to_update)
T.update_air_properties()
/*
for(var/obj/movable/floor/O in tiles_to_update)
O.update_air_properties()
*/
tiles_to_update.len = 0
process_rebuild_select_groups()
var/turf/list/turfs = list()
for(var/datum/air_group/turf/turf_AG in groups_to_rebuild) //Deconstruct groups, gathering their old members
for(var/turf/simulated/T in turf_AG.members)
T.parent = null
turfs += T
del(turf_AG)
for(var/turf/simulated/S in turfs) //Have old members try to form new groups
if(!S.parent)
assemble_group_turf(S)
for(var/turf/simulated/S in turfs)
S.update_air_properties()
// var/obj/movable/list/movable_objects = list()
for(var/datum/air_group/object/object_AG in groups_to_rebuild) //Deconstruct groups, gathering their old members
/*
for(var/obj/movable/floor/OM in object_AG.members)
OM.parent = null
movable_objects += OM
del(object_AG)
for(var/obj/movable/floor/OM in movable_objects) //Have old members try to form new groups
if(!OM.parent)
assemble_group_object(OM)
for(var/obj/movable/floor/OM in movable_objects)
OM.update_air_properties()
*/
groups_to_rebuild.len = 0
process_groups()
for(var/datum/air_group/AG in air_groups)
AG.process_group()
process_singletons()
for(var/item in active_singletons)
item:process_cell()
process_super_conductivity()
for(var/turf/simulated/hot_potato in active_super_conductivity)
hot_potato.super_conduct()
process_high_pressure_delta()
for(var/turf/pressurized in high_pressure_delta)
pressurized.high_pressure_movements()
high_pressure_delta.len = 0

539
code/FEA/FEA_turf_tile.dm Normal file
View File

@@ -0,0 +1,539 @@
atom/movable/var/pressure_resistance = 20
atom/movable/var/last_forced_movement = 0
atom/movable/proc/experience_pressure_difference(pressure_difference, direction)
if(last_forced_movement >= air_master.current_cycle)
return 0
else if(!anchored)
if(pressure_difference > pressure_resistance)
last_forced_movement = air_master.current_cycle
spawn step(src, direction)
return 1
turf
assume_air(datum/gas_mixture/giver) //use this for machines to adjust air
//First, ensure there is no movable shuttle or what not on tile that is taking over
// var/obj/movable/floor/movable_on_me = locate(/obj/movable/floor) in src
// if(istype(movable_on_me))
// return movable_on_me.assume_air(giver)
del(giver)
return 0
return_air()
//First, ensure there is no movable shuttle or what not on tile that is taking over
// var/obj/movable/floor/movable_on_me = locate(/obj/movable/floor) in src
// if(istype(movable_on_me))
// return movable_on_me.return_air()
//Create gas mixture to hold data for passing
var/datum/gas_mixture/GM = new
GM.oxygen = oxygen
GM.carbon_dioxide = carbon_dioxide
GM.nitrogen = nitrogen
GM.toxins = toxins
GM.temperature = temperature
return GM
remove_air(amount as num)
//First, ensure there is no movable shuttle or what not on tile that is taking over
// var/obj/movable/floor/movable_on_me = locate(/obj/movable/floor) in src
// if(istype(movable_on_me))
// return movable_on_me.remove_air(amount)
var/datum/gas_mixture/GM = new
var/sum = oxygen + carbon_dioxide + nitrogen + toxins
if(sum>0)
GM.oxygen = (oxygen/sum)*amount
GM.carbon_dioxide = (carbon_dioxide/sum)*amount
GM.nitrogen = (nitrogen/sum)*amount
GM.toxins = (toxins/sum)*amount
GM.temperature = temperature
return GM
turf
var/pressure_difference = 0
var/pressure_direction = 0
proc
high_pressure_movements()
for(var/atom/movable/in_tile in src)
in_tile.experience_pressure_difference(pressure_difference, pressure_direction)
pressure_difference = 0
consider_pressure_difference(connection_difference, connection_direction)
if(connection_difference < 0)
connection_difference = -connection_difference
connection_direction = turn(connection_direction,180)
if(connection_difference > pressure_difference)
if(!pressure_difference)
air_master.high_pressure_delta += src
pressure_difference = connection_difference
pressure_direction = connection_direction
simulated
proc
consider_pressure_difference_space(connection_difference)
for(var/direction in cardinal)
if(direction&group_border)
if(istype(get_step(src,direction),/turf/space))
if(!pressure_difference)
air_master.high_pressure_delta += src
pressure_direction = direction
pressure_difference = connection_difference
return 1
turf
simulated
var/current_graphic = null
var/tmp
datum/gas_mixture/air
processing = 1
datum/air_group/turf/parent
group_border = 0
length_space_border = 0
air_check_directions = 0 //Do not modify this, just add turf to air_master.tiles_to_update
archived_cycle = 0
current_cycle = 0
obj/hotspot/active_hotspot
temperature_archived //USED ONLY FOR SOLIDS
being_superconductive = 0
proc
process_cell()
update_air_properties()
archive()
mimic_air_with_tile(turf/model)
share_air_with_tile(turf/simulated/sharer)
mimic_temperature_with_tile(turf/model)
share_temperature_with_tile(turf/simulated/sharer)
super_conduct()
update_visuals(datum/gas_mixture/model)
overlays = null
switch(model.graphic)
if("plasma")
overlays.Add(plmaster)
if("sleeping_agent")
overlays.Add(slmaster)
else
overlays = null
New()
..()
if(!blocks_air)
air = new
air.oxygen = oxygen
air.carbon_dioxide = carbon_dioxide
air.nitrogen = nitrogen
air.toxins = toxins
air.temperature = temperature
if(air_master)
air_master.tiles_to_update.Add(src)
find_group()
// air.parent = src //TODO DEBUG REMOVE
else
if(air_master)
for(var/direction in cardinal)
var/turf/simulated/floor/target = get_step(src,direction)
if(istype(target))
air_master.tiles_to_update.Add(target)
Del()
if(air_master)
if(parent)
air_master.groups_to_rebuild.Add(parent)
parent.members.Remove(src)
else
air_master.active_singletons.Remove(src)
if(active_hotspot)
del(active_hotspot)
if(blocks_air)
for(var/direction in list(NORTH, SOUTH, EAST, WEST))
var/turf/simulated/tile = get_step(src,direction)
if(istype(tile) && !tile.blocks_air)
air_master.tiles_to_update.Add(tile)
..()
assume_air(datum/gas_mixture/giver)
if(air)
if(parent&&parent.group_processing)
if(!parent.air.check_then_merge(giver))
parent.suspend_group_processing()
air.merge(giver)
else
air.merge(giver)
if(!processing)
if(air.check_tile_graphic())
update_visuals(air)
return 1
else return ..()
archive()
if(air) //For open space like floors
air.archive()
temperature_archived = temperature
archived_cycle = air_master.current_cycle
share_air_with_tile(turf/simulated/T)
return air.share(T.air)
mimic_air_with_tile(turf/T)
return air.mimic(T)
return_air()
if(air)
if(parent&&parent.group_processing)
return parent.air
else return air
else
return ..()
remove_air(amount as num)
if(air)
var/datum/gas_mixture/removed = null
if(parent&&parent.group_processing)
removed = parent.air.check_then_remove(amount)
if(!removed)
parent.suspend_group_processing()
removed = air.remove(amount)
else
removed = air.remove(amount)
if(!processing)
if(air.check_tile_graphic())
update_visuals(air)
return removed
else
return ..()
update_air_properties()//OPTIMIZE
air_check_directions = 0
for(var/direction in cardinal)
if(CanPass(null, get_step(src,direction), 0, 0))
air_check_directions |= direction
if(parent)
if(parent.borders)
parent.borders -= src
if(length_space_border > 0)
parent.length_space_border -= length_space_border
length_space_border = 0
group_border = 0
for(var/direction in cardinal)
if(air_check_directions&direction)
var/turf/simulated/T = get_step(src,direction)
//See if actually a border
if(!istype(T) || (T.parent!=parent))
//See what kind of border it is
if(istype(T,/turf/space))
if(parent.space_borders)
parent.space_borders -= src
parent.space_borders += src
else
parent.space_borders = list(src)
length_space_border++
else
if(parent.borders)
parent.borders -= src
parent.borders += src
else
parent.borders = list(src)
group_border |= direction
parent.length_space_border += length_space_border
if(air_check_directions)
processing = 1
if(!parent)
air_master.add_singleton(src)
else
processing = 0
process_cell()
var/turf/simulated/list/possible_fire_spreads = list()
if(processing)
if(archived_cycle < air_master.current_cycle) //archive self if not already done
archive()
current_cycle = air_master.current_cycle
for(var/direction in cardinal)
if(air_check_directions&direction) //Grab all valid bordering tiles
var/turf/simulated/enemy_tile = get_step(src, direction)
var/connection_difference = 0
if(istype(enemy_tile))
if(enemy_tile.archived_cycle < archived_cycle) //archive bordering tile information if not already done
enemy_tile.archive()
if(enemy_tile.parent && enemy_tile.parent.group_processing) //apply tile to group sharing
if(enemy_tile.parent.current_cycle < current_cycle)
if(enemy_tile.parent.air.check_gas_mixture(air))
connection_difference = air.share(enemy_tile.parent.air)
else
enemy_tile.parent.suspend_group_processing()
connection_difference = air.share(enemy_tile.air)
//group processing failed so interact with individual tile
else
if(enemy_tile.current_cycle < current_cycle)
connection_difference = air.share(enemy_tile.air)
if(active_hotspot)
possible_fire_spreads += enemy_tile
else
/* var/obj/movable/floor/movable_on_enemy = locate(/obj/movable/floor) in enemy_tile
if(movable_on_enemy)
if(movable_on_enemy.parent && movable_on_enemy.parent.group_processing) //apply tile to group sharing
if(movable_on_enemy.parent.current_cycle < current_cycle)
if(movable_on_enemy.parent.air.check_gas_mixture(air))
connection_difference = air.share(movable_on_enemy.parent.air)
else
movable_on_enemy.parent.suspend_group_processing()
if(movable_on_enemy.archived_cycle < archived_cycle) //archive bordering tile information if not already done
movable_on_enemy.archive()
connection_difference = air.share(movable_on_enemy.air)
//group processing failed so interact with individual tile
else
if(movable_on_enemy.archived_cycle < archived_cycle) //archive bordering tile information if not already done
movable_on_enemy.archive()
if(movable_on_enemy.current_cycle < current_cycle)
connection_difference = share_air_with_tile(movable_on_enemy)
else*/
connection_difference = mimic_air_with_tile(enemy_tile)
//bordering a tile with fixed air properties
if(connection_difference)
if(connection_difference > 0)
consider_pressure_difference(connection_difference, direction)
else
enemy_tile.consider_pressure_difference(connection_difference, direction)
else
air_master.active_singletons -= src //not active if not processing!
air.react()
if(active_hotspot)
active_hotspot.process(possible_fire_spreads)
if(air.temperature > MINIMUM_TEMPERATURE_START_SUPERCONDUCTION)
consider_superconductivity(starting = 1)
if(air.check_tile_graphic())
update_visuals(air)
if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
hotspot_expose(air.temperature, CELL_VOLUME)
for(var/atom/movable/item in src)
item.temperature_expose(air, air.temperature, CELL_VOLUME)
temperature_expose(air, air.temperature, CELL_VOLUME)
return 1
super_conduct()
var/conductivity_directions = 0
if(blocks_air)
//Does not participate in air exchange, so will conduct heat across all four borders at this time
conductivity_directions = NORTH|SOUTH|EAST|WEST
if(archived_cycle < air_master.current_cycle)
archive()
else
//Does particate in air exchange so only consider directions not considered during process_cell()
conductivity_directions = ~air_check_directions & (NORTH|SOUTH|EAST|WEST)
if(conductivity_directions>0)
//Conduct with tiles around me
for(var/direction in cardinal)
if(conductivity_directions&direction)
var/turf/neighbor = get_step(src,direction)
if(istype(neighbor, /turf/simulated)) //anything under this subtype will share in the exchange
var/turf/simulated/modeled_neighbor = neighbor
if(modeled_neighbor.archived_cycle < air_master.current_cycle)
modeled_neighbor.archive()
if(modeled_neighbor.air)
if(air) //Both tiles are open
if(modeled_neighbor.parent && modeled_neighbor.parent.group_processing)
if(parent && parent.group_processing)
//both are acting as a group
//modified using construct developed in datum/air_group/share_air_with_group(...)
var/result = parent.air.check_both_then_temperature_share(modeled_neighbor.parent.air, WINDOW_HEAT_TRANSFER_COEFFICIENT)
if(result==0)
//have to deconstruct parent air group
parent.suspend_group_processing()
if(!modeled_neighbor.parent.air.check_me_then_temperature_share(air, WINDOW_HEAT_TRANSFER_COEFFICIENT))
//may have to deconstruct neighbors air group
modeled_neighbor.parent.suspend_group_processing()
air.temperature_share(modeled_neighbor.air, WINDOW_HEAT_TRANSFER_COEFFICIENT)
else if(result==-1)
// have to deconstruct neightbors air group but not mine
modeled_neighbor.parent.suspend_group_processing()
parent.air.temperature_share(modeled_neighbor.air, WINDOW_HEAT_TRANSFER_COEFFICIENT)
else
air.temperature_share(modeled_neighbor.air, WINDOW_HEAT_TRANSFER_COEFFICIENT)
else
if(parent && parent.group_processing)
if(!parent.air.check_me_then_temperature_share(air, WINDOW_HEAT_TRANSFER_COEFFICIENT))
//may have to deconstruct neighbors air group
parent.suspend_group_processing()
air.temperature_share(modeled_neighbor.air, WINDOW_HEAT_TRANSFER_COEFFICIENT)
else
air.temperature_share(modeled_neighbor.air, WINDOW_HEAT_TRANSFER_COEFFICIENT)
// world << "OPEN, OPEN"
else //Solid but neighbor is open
if(modeled_neighbor.parent && modeled_neighbor.parent.group_processing)
if(!modeled_neighbor.parent.air.check_me_then_temperature_turf_share(src, modeled_neighbor.thermal_conductivity))
modeled_neighbor.parent.suspend_group_processing()
modeled_neighbor.air.temperature_turf_share(src, modeled_neighbor.thermal_conductivity)
else
modeled_neighbor.air.temperature_turf_share(src, modeled_neighbor.thermal_conductivity)
// world << "SOLID, OPEN"
else
if(air) //Open but neighbor is solid
if(parent && parent.group_processing)
if(!parent.air.check_me_then_temperature_turf_share(modeled_neighbor, modeled_neighbor.thermal_conductivity))
parent.suspend_group_processing()
air.temperature_turf_share(modeled_neighbor, modeled_neighbor.thermal_conductivity)
else
air.temperature_turf_share(modeled_neighbor, modeled_neighbor.thermal_conductivity)
// world << "OPEN, SOLID"
else //Both tiles are solid
share_temperature_mutual_solid(modeled_neighbor, modeled_neighbor.thermal_conductivity)
// world << "SOLID, SOLID"
modeled_neighbor.consider_superconductivity()
else
if(air) //Open
if(parent && parent.group_processing)
if(!parent.air.check_me_then_temperature_mimic(neighbor, neighbor.thermal_conductivity))
parent.suspend_group_processing()
air.temperature_mimic(neighbor, neighbor.thermal_conductivity)
else
air.temperature_mimic(neighbor, neighbor.thermal_conductivity)
else
mimic_temperature_solid(neighbor, neighbor.thermal_conductivity)
//Radiate excess tile heat to space
var/turf/space/sample_space = locate(/turf/space)
if(sample_space && (temperature > T0C))
//Considering 0 degC as te break even point for radiation in and out
mimic_temperature_solid(sample_space, FLOOR_HEAT_TRANSFER_COEFFICIENT)
//Conduct with air on my tile if I have it
if(air)
if(parent && parent.group_processing)
if(!parent.air.check_me_then_temperature_turf_share(src, thermal_conductivity))
parent.suspend_group_processing()
air.temperature_turf_share(src, thermal_conductivity)
else
air.temperature_turf_share(src, thermal_conductivity)
//Make sure still hot enough to continue conducting heat
if(air)
if(air.temperature < MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION)
being_superconductive = 0
air_master.active_super_conductivity -= src
return 0
else
if(temperature < MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION)
being_superconductive = 0
air_master.active_super_conductivity -= src
return 0
proc/mimic_temperature_solid(turf/model, conduction_coefficient)
var/delta_temperature = (temperature_archived - model.temperature)
if((heat_capacity > 0) && (abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER))
var/heat = conduction_coefficient*delta_temperature* \
(heat_capacity*model.heat_capacity/(heat_capacity+model.heat_capacity))
temperature -= heat/heat_capacity
proc/share_temperature_mutual_solid(turf/simulated/sharer, conduction_coefficient)
var/delta_temperature = (temperature_archived - sharer.temperature_archived)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/heat = conduction_coefficient*delta_temperature* \
(heat_capacity*sharer.heat_capacity/(heat_capacity+sharer.heat_capacity))
temperature -= heat/heat_capacity
sharer.temperature += heat/sharer.heat_capacity
proc/consider_superconductivity(starting)
if(being_superconductive || !thermal_conductivity)
return 0
if(air)
if(air.temperature < (starting?MINIMUM_TEMPERATURE_START_SUPERCONDUCTION:MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION))
return 0
if(air.heat_capacity() < MOLES_CELLSTANDARD*0.1*0.05)
return 0
else
if(temperature < (starting?MINIMUM_TEMPERATURE_START_SUPERCONDUCTION:MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION))
return 0
being_superconductive = 1
air_master.active_super_conductivity += src

View File

@@ -0,0 +1,36 @@
/proc/getbrokeninhands()
var/icon/IL = new('items_lefthand.dmi')
var/list/Lstates = IL.IconStates()
var/icon/IR = new('items_righthand.dmi')
var/list/Rstates = IR.IconStates()
var/text
for(var/A in typesof(/obj/item))
var/obj/item/O = new A( locate(1,1,1) )
if(!O) continue
var/icon/J = new(O.icon)
var/list/istates = J.IconStates()
if(!Lstates.Find(O.icon_state) && !Lstates.Find(O.item_state))
if(O.icon_state)
text += "[O.type] WANTS IN LEFT HAND CALLED\n\"[O.icon_state]\".\n"
if(!Rstates.Find(O.icon_state) && !Rstates.Find(O.item_state))
if(O.icon_state)
text += "[O.type] WANTS IN RIGHT HAND CALLED\n\"[O.icon_state]\".\n"
if(O.icon_state)
if(!istates.Find(O.icon_state))
text += "[O.type] MISSING NORMAL ICON CALLED\n\"[O.icon_state]\" IN \"[O.icon]\"\n"
if(O.item_state)
if(!istates.Find(O.item_state))
text += "[O.type] MISSING NORMAL ICON CALLED\n\"[O.item_state]\" IN \"[O.icon]\"\n"
text+="\n"
del(O)
if(text)
var/F = file("broken_icons.txt")
fdel(F)
F << text
world << "Completely successfully and written to [F]"

View File

@@ -0,0 +1,188 @@
/obj/item/weapon/storage/photo_album
name = "Photo album"
icon = 'old_or_unused.dmi'
icon_state = "album"
item_state = "briefcase"
/obj/item/weapon/storage/photo_album/MouseDrop(obj/over_object as obj)
if ((istype(usr, /mob/living/carbon/human) || (ticker && ticker.mode.name == "monkey")))
var/mob/M = usr
if (!( istype(over_object, /obj/screen) ))
return ..()
playsound(src.loc, "rustle", 50, 1, -5)
if ((!( M.restrained() ) && !( M.stat ) && M.back == src))
if (over_object.name == "r_hand")
if (!( M.r_hand ))
M.u_equip(src)
M.r_hand = src
else
if (over_object.name == "l_hand")
if (!( M.l_hand ))
M.u_equip(src)
M.l_hand = src
M.update_clothing()
src.add_fingerprint(usr)
return
if(over_object == usr && in_range(src, usr) || usr.contents.Find(src))
if (usr.s_active)
usr.s_active.close(usr)
src.show_to(usr)
return
return
/obj/item/weapon/storage/photo_album/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (src.contents.len >= 7)
return
if (!istype(W,/obj/item/weapon/photo))
user << "\red You can only put photos in a photo album."
return
var/t
for(var/obj/item/weapon/O in src)
t += O.w_class
playsound(src.loc, "rustle", 50, 1, -5)
user.u_equip(W)
W.loc = src
if ((user.client && user.s_active != src))
user.client.screen -= W
src.orient2hud(user)
W.dropped(user)
add_fingerprint(user)
for(var/mob/O in viewers(user, null))
O.show_message(text("\blue [] has added [] to []!", user, W, src), 1)
return
/obj/item/weapon/camera_test
name = "camera"
icon = 'old_or_unused.dmi'
desc = "A one use - polaroid camera. 10 photos left."
icon_state = "camera"
item_state = "electropack"
w_class = 2.0
flags = 466.0
m_amt = 2000
throwforce = 5
throw_speed = 4
throw_range = 10
var/pictures_left = 10
var/can_use = 1
/obj/item/weapon/photo
name = "photo"
icon = 'old_or_unused.dmi'
icon_state = "photo"
item_state = "clipboard"
w_class = 1.0
//////////////////////////////////////////////////////////////////////////////////////////////////
/obj/item/weapon/camera_test/proc/build_composite_icon(var/atom/C)
var/icon/composite = icon(C.icon, C.icon_state, C.dir, 1)
for(var/O in C.overlays)
var/image/I = O
composite.Blend(icon(I.icon, I.icon_state, I.dir, 1), ICON_OVERLAY)
return composite
//////////////////////////////////////////////////////////////////////////////////////////////////
/obj/item/weapon/camera_test/attack(mob/living/carbon/human/M as mob, mob/user as mob)
return
/obj/item/weapon/camera_test/afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag)
if (!can_use || !pictures_left || ismob(target.loc)) return
var/turf/the_turf = get_turf(target)
var/icon/photo = icon('old_or_unused.dmi',"photo")
var/icon/turficon = build_composite_icon(the_turf)
turficon.Scale(22,20)
photo.Blend(turficon,ICON_OVERLAY,6,8)
var/mob_title = null
var/mob_detail = null
var/item_title = null
var/item_detail = null
var/itemnumber = 0
for(var/atom/A in the_turf)
if(A.invisibility) continue
if(ismob(A))
var/icon/X = build_composite_icon(A)
X.Scale(22,20)
photo.Blend(X,ICON_OVERLAY,6,8)
del(X)
if(!mob_title)
mob_title = "[A]"
else
mob_title += " and [A]"
if(!mob_detail)
var/holding = null
if(istype(A, /mob/living/carbon))
var/mob/living/carbon/temp = A
if(temp.l_hand || temp.r_hand)
if(temp.l_hand) holding = "They are holding \a [temp.l_hand]"
if(temp.r_hand)
if(holding)
holding += " and \a [temp.r_hand]."
else
holding = "They are holding \a [temp.r_hand]."
if(!mob_detail)
mob_detail = "You can see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]"
else
mob_detail += "You can also see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]"
else
if(itemnumber < 5)
var/icon/X = build_composite_icon(A)
X.Scale(22,20)
photo.Blend(X,ICON_OVERLAY,6,8)
del(X)
itemnumber++
if(!item_title)
item_title = " \a [A]"
else
item_title = " some objects"
if(!item_detail)
item_detail = "\a [A]"
else
item_detail += " and \a [A]"
var/finished_title = null
var/finished_detail = null
if(!item_title && !mob_title)
finished_title = "boring photo"
finished_detail = "This is a pretty boring photo of \a [the_turf]."
else
if(mob_title)
finished_title = "photo of [mob_title][item_title ? " and[item_title]":""]"
finished_detail = "[mob_detail][item_detail ? " Theres also [item_detail].":"."]"
else if(item_title)
finished_title = "photo of[item_title]"
finished_detail = "You can see [item_detail]."
var/obj/item/weapon/photo/P = new/obj/item/weapon/photo( get_turf(src) )
P.icon = photo
P.name = finished_title
P.desc = finished_detail
playsound(src.loc, pick('polaroid1.ogg','polaroid2.ogg'), 75, 1, -3)
pictures_left--
src.desc = "A one use - polaroid camera. [pictures_left] photos left."
user << "\blue [pictures_left] photos left."
can_use = 0
spawn(50) can_use = 1

View File

@@ -0,0 +1,235 @@
#define TOUCH 1
#define INGEST 2
///////////////////////////////////////////////////////////////////////////////////
datum
reagents
var/list/reagent_list = new/list()
var/total_volume = 0
var/maximum_volume = 100
var/atom/my_atom = null
New(maximum=100)
maximum_volume = maximum
proc
remove_any(var/amount=1)
var/total_transfered = 0
var/current_list_element = 1
current_list_element = rand(1,reagent_list.len)
while(total_transfered != amount)
if(total_transfered >= amount) break
if(total_volume <= 0 || !reagent_list.len) break
if(current_list_element > reagent_list.len) current_list_element = 1
var/datum/reagent/current_reagent = reagent_list[current_list_element]
src.remove_reagent(current_reagent.id, 1)
current_list_element++
total_transfered++
src.update_total()
handle_reactions()
return total_transfered
get_master_reagent_name()
var/the_name = null
var/the_volume = 0
for(var/datum/reagent/A in reagent_list)
if(A.volume > the_volume)
the_volume = A.volume
the_name = A.name
return the_name
trans_to(var/obj/target, var/amount=1, var/multiplier=1)
var/total_transfered = 0
var/current_list_element = 1
var/datum/reagents/R = target.reagents
//if(R.total_volume + amount > R.maximum_volume) return 0
current_list_element = rand(1,reagent_list.len) //Eh, bandaid fix.
while(total_transfered != amount)
if(total_transfered >= amount) break //Better safe than sorry.
if(total_volume <= 0 || !reagent_list.len) break
if(R.total_volume >= R.maximum_volume) break
if(current_list_element > reagent_list.len) current_list_element = 1
var/datum/reagent/current_reagent = reagent_list[current_list_element]
R.add_reagent(current_reagent.id, (1 * multiplier) )
src.remove_reagent(current_reagent.id, 1)
current_list_element++
total_transfered++
src.update_total()
R.update_total()
R.handle_reactions()
handle_reactions()
return total_transfered
metabolize(var/mob/M)
for(var/A in reagent_list)
var/datum/reagent/R = A
R.on_mob_life(M)
update_total()
handle_reactions()
if(ismob(my_atom)) return //No reactions inside mobs :I
for(var/A in typesof(/datum/chemical_reaction) - /datum/chemical_reaction)
var/datum/chemical_reaction/C = new A()
var/total_required_reagents = C.required_reagents.len
var/total_matching_reagents = 0
var/list/multipliers = new/list()
for(var/B in C.required_reagents)
if(has_reagent(B, C.required_reagents[B]))
total_matching_reagents++
multipliers += round(get_reagent_amount(B) / C.required_reagents[B])
if(total_matching_reagents == total_required_reagents)
var/multiplier = min(multipliers)
for(var/B in C.required_reagents)
del_reagent(B)
var/created_volume = C.result_amount*multiplier
if(C.result)
multiplier = max(multiplier, 1) //this shouldnt happen ...
add_reagent(C.result, C.result_amount*multiplier)
for(var/mob/M in viewers(4, get_turf(my_atom)) )
M << "\blue \icon[my_atom] The solution begins to bubble."
playsound(get_turf(my_atom), 'bubbles.ogg', 80, 1)
C.on_reaction(src, created_volume)
update_total()
return 0
isolate_reagent(var/reagent)
for(var/A in reagent_list)
var/datum/reagent/R = A
if (R.id != reagent)
del_reagent(R.id)
update_total()
del_reagent(var/reagent)
for(var/A in reagent_list)
var/datum/reagent/R = A
if (R.id == reagent)
reagent_list -= A
del(A)
update_total()
my_atom.on_reagent_change()
return 0
return 1
update_total()
total_volume = 0
for(var/datum/reagent/R in reagent_list)
if(R.volume < 1)
del_reagent(R.id)
else
total_volume += R.volume
return 0
clear_reagents()
for(var/datum/reagent/R in reagent_list)
del_reagent(R.id)
return 0
reaction(var/atom/A, var/method=TOUCH, var/volume_modifier=0)
switch(method)
if(TOUCH)
for(var/datum/reagent/R in reagent_list)
if(ismob(A)) spawn(0) R.reaction_mob(A, TOUCH, R.volume+volume_modifier)
if(isturf(A)) spawn(0) R.reaction_turf(A, R.volume+volume_modifier)
if(isobj(A)) spawn(0) R.reaction_obj(A, R.volume+volume_modifier)
if(INGEST)
for(var/datum/reagent/R in reagent_list)
if(ismob(A)) spawn(0) R.reaction_mob(A, INGEST, R.volume+volume_modifier)
if(isturf(A)) spawn(0) R.reaction_turf(A, R.volume+volume_modifier)
if(isobj(A)) spawn(0) R.reaction_obj(A, R.volume+volume_modifier)
return
add_reagent(var/reagent, var/amount)
if(!isnum(amount)) return 1
update_total()
if(total_volume + amount > maximum_volume) amount = (maximum_volume - total_volume) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen.
for(var/A in reagent_list)
var/datum/reagent/R = A
if (R.id == reagent)
R.volume += amount
update_total()
my_atom.on_reagent_change()
return 0
for(var/A in typesof(/datum/reagent) - /datum/reagent)
var/datum/reagent/R = new A()
if (R.id == reagent)
reagent_list += R
R.holder = src
R.volume = amount
update_total()
my_atom.on_reagent_change()
return 0
return 1
remove_reagent(var/reagent, var/amount)
if(!isnum(amount)) return 1
for(var/A in reagent_list)
var/datum/reagent/R = A
if (R.id == reagent)
R.volume -= amount
update_total()
handle_reactions()
my_atom.on_reagent_change()
return 0
return 1
has_reagent(var/reagent, var/amount = -1)
for(var/A in reagent_list)
var/datum/reagent/R = A
if (R.id == reagent)
if(!amount) return 1
else
if(R.volume >= amount) return 1
else return 0
return 0
get_reagent_amount(var/reagent)
for(var/A in reagent_list)
var/datum/reagent/R = A
if (R.id == reagent)
return R.volume
return 0
///////////////////////////////////////////////////////////////////////////////////
// Convenience proc to create a reagents holder for an atom
// Max vol is maximum volume of holder
atom/proc/create_reagents(var/max_vol)
reagents = new/datum/reagents(max_vol)
reagents.my_atom = src

View File

@@ -0,0 +1,231 @@
#define SOLID 1
#define LIQUID 2
#define GAS 3
/obj/machinery/chem_dispenser/
name = "chem dispenser"
density = 1
anchored = 1
icon = 'chemical.dmi'
icon_state = "dispenser"
var/energy = 25
var/max_energy = 25
var/list/dispensable_reagents = list("water","oxygen","nitrogen","hydrogen","potassium","mercury","sulfur","carbon","chlorine","fluorine","phosphorus","lithium","acid","radium","iron","aluminium","silicon","plasma","sugar","ethanol")
proc
recharge()
if(stat & BROKEN) return
if(energy != max_energy)
energy++
use_power(50)
spawn(600) recharge()
New()
recharge()
ex_act(severity)
switch(severity)
if(1.0)
del(src)
return
if(2.0)
if (prob(50))
del(src)
return
blob_act()
if (prob(25))
del(src)
meteorhit()
del(src)
return
Topic(href, href_list)
if(stat & BROKEN) return
if(usr.stat || usr.restrained()) return
if(!in_range(src, usr)) return
usr.machine = src
if (href_list["dispense"])
if(!energy)
var/dat = "Not enough energy.<BR><A href='?src=\ref[src];ok=1'>OK</A>"
usr << browse("<TITLE>Chemical Dispenser</TITLE>Chemical dispenser:<BR>Energy = [energy]/[max_energy]<BR><BR>[dat]", "window=chem_dispenser")
return
var/id = href_list["dispense"]
var/obj/item/weapon/reagent_containers/glass/dispenser/G = new/obj/item/weapon/reagent_containers/glass/dispenser(src.loc)
switch(text2num(href_list["state"]))
if(LIQUID)
G.icon_state = "liquid"
if(GAS)
G.icon_state = "vapour"
if(SOLID)
G.icon_state = "solid"
G.name += " ([lowertext(href_list["name"])])"
G.reagents.add_reagent(id,30)
energy--
src.updateUsrDialog()
return
else
usr << browse(null, "window=chem_dispenser")
return
src.add_fingerprint(usr)
return
attack_ai(mob/user as mob)
return src.attack_hand(user)
attack_paw(mob/user as mob)
return src.attack_hand(user)
attack_hand(mob/user as mob)
if(stat & BROKEN)
return
user.machine = src
var/dat = ""
for(var/re in dispensable_reagents)
for(var/da in typesof(/datum/reagent) - /datum/reagent)
var/datum/reagent/temp = new da()
if(temp.id == re)
dat += "<A href='?src=\ref[src];dispense=[temp.id];state=[temp.reagent_state];name=[temp.name]'>[temp.name]</A><BR>"
dat += "[temp.description]<BR><BR>"
user << browse("<TITLE>Chemical Dispenser</TITLE>Chemical dispenser:<BR>Energy = [energy]/[max_energy]<BR><BR>[dat]", "window=chem_dispenser")
onclose(user, "chem_dispenser")
return
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/obj/machinery/chem_master/
name = "CheMaster 3000"
density = 1
anchored = 1
icon = 'chemical.dmi'
icon_state = "mixer0"
var/beaker = null
ex_act(severity)
switch(severity)
if(1.0)
del(src)
return
if(2.0)
if (prob(50))
del(src)
return
blob_act()
if (prob(25))
del(src)
meteorhit()
del(src)
return
attackby(var/obj/item/weapon/reagent_containers/glass/B as obj, var/mob/user as mob)
if(!istype(B, /obj/item/weapon/reagent_containers/glass))
return
if(src.beaker)
user << "A beaker is already loaded into the machine."
return
src.beaker = B
user.drop_item()
B.loc = src
user << "You add the beaker to the machine!"
src.updateUsrDialog()
icon_state = "mixer1"
Topic(href, href_list)
if(stat & BROKEN) return
if(usr.stat || usr.restrained()) return
if(!in_range(src, usr)) return
usr.machine = src
if(!beaker) return
var/datum/reagents/R = beaker:reagents
if (href_list["isolate"])
R.isolate_reagent(href_list["isolate"])
src.updateUsrDialog()
return
else if (href_list["remove"])
R.del_reagent(href_list["remove"])
src.updateUsrDialog()
return
else if (href_list["remove5"])
R.remove_reagent(href_list["remove5"], 5)
src.updateUsrDialog()
return
else if (href_list["remove1"])
R.remove_reagent(href_list["remove1"], 1)
src.updateUsrDialog()
return
else if (href_list["analyze"])
var/dat = "<TITLE>Chemmaster 3000</TITLE>Chemical infos:<BR><BR>Name:<BR>[href_list["name"]]<BR><BR>Description:<BR>[href_list["desc"]]<BR><BR><BR><A href='?src=\ref[src];main=1'>(Back)</A>"
usr << browse(dat, "window=chem_master;size=575x400")
return
else if (href_list["main"])
attack_hand(usr)
return
else if (href_list["eject"])
beaker:loc = src.loc
beaker = null
icon_state = "mixer0"
src.updateUsrDialog()
return
else if (href_list["createpill"])
var/obj/item/weapon/reagent_containers/pill/P = new/obj/item/weapon/reagent_containers/pill(src.loc)
var/name = input(usr,"Name:","Name your pill!",R.get_master_reagent_name())
if(!name || name == " ") name = R.get_master_reagent_name()
P.name = "[name] pill"
R.trans_to(P,R.total_volume)
src.updateUsrDialog()
return
else if (href_list["createbottle"])
var/obj/item/weapon/reagent_containers/glass/bottle/P = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc)
var/name = input(usr,"Name:","Name your bottle!",R.get_master_reagent_name())
if(!name || name == " ") name = R.get_master_reagent_name()
P.name = "[name] bottle"
R.trans_to(P,30)
src.updateUsrDialog()
return
else
usr << browse(null, "window=chem_master")
return
src.add_fingerprint(usr)
return
attack_ai(mob/user as mob)
return src.attack_hand(user)
attack_paw(mob/user as mob)
return src.attack_hand(user)
attack_hand(mob/user as mob)
if(stat & BROKEN)
return
user.machine = src
var/dat = ""
if(!beaker)
dat = "Please insert beaker.<BR>"
dat += "<A href='?src=\ref[src];close=1'>Close</A>"
else
var/datum/reagents/R = beaker:reagents
dat += "<A href='?src=\ref[src];eject=1'>Eject beaker</A><BR><BR>"
if(!R.total_volume)
dat += "Beaker is empty."
else
dat += "Contained reagents:<BR>"
for(var/datum/reagent/G in R.reagent_list)
dat += "[G.name] , [G.volume] Units - <A href='?src=\ref[src];isolate=[G.id]'>(Isolate)</A> <A href='?src=\ref[src];remove=[G.id]'>(Remove all)</A> <A href='?src=\ref[src];remove5=[G.id]'>(Remove 5)</A> <A href='?src=\ref[src];remove1=[G.id]'>(Remove 1)</A> <A href='?src=\ref[src];analyze=1;desc=[G.description];name=[G.name]'>(Analyze)</A><BR>"
dat += "<BR><A href='?src=\ref[src];createpill=1'>Create pill</A><BR>"
dat += "<A href='?src=\ref[src];createbottle=1'>Create bottle (30 units max)</A>"
user << browse("<TITLE>Chemmaster 3000</TITLE>Chemmaster menu:<BR><BR>[dat]", "window=chem_master;size=575x400")
onclose(user, "chem_master")
return

View File

@@ -0,0 +1,219 @@
/*
NOTE: IF YOU UPDATE THE REAGENT-SYSTEM, ALSO UPDATE THIS README.
Structure: /////////////////// //////////////////////////
// Mob or object // -------> // Reagents var (datum) // Is a reference to the datum that holds the reagents.
/////////////////// //////////////////////////
| |
The object that holds everything. V
reagent_list var (list) A List of datums, each datum is a reagent.
| | |
V V V
reagents (datums) Reagents. I.e. Water , antitoxins or mercury.
Random important notes:
An objects on_reagent_change will be called every time the objects reagents change.
Useful if you want to update the objects icon etc.
About the Holder:
The holder (reagents datum) is the datum that holds a list of all reagents
currently in the object.It also has all the procs needed to manipulate reagents
remove_any(var/amount)
This proc removes reagents from the holder until the passed amount
is matched. It'll try to remove some of ALL reagents contained.
trans_to(var/obj/target, var/amount)
This proc equally transfers the contents of the holder to another
objects holder. You need to pass it the object (not the holder) you want
to transfer to and the amount you want to transfer. Its return value is the
actual amount transfered (if one of the objects is full/empty)
metabolize(var/mob/M)
This proc is called by the mobs life proc. It simply calls on_mob_life for
all contained reagents. You shouldnt have to use this one directly.
handle_reactions()
This proc check all recipes and, on a match, uses them.
It will also call the recipe's on_reaction proc (for explosions or w/e).
Currently, this proc is automatically called by trans_to.
isolate_reagent(var/reagent)
Pass it a reagent id and it will remove all reagents but that one.
It's that simple.
del_reagent(var/reagent)
Completely remove the reagent with the matching id.
reaction_fire(exposed_temp)
Simply calls the reaction_fire procs of all contained reagents.
update_total()
This one simply updates the total volume of the holder.
(the volume of all reagents added together)
clear_reagents()
This proc removes ALL reagents from the holder.
reaction(var/atom/A, var/method=TOUCH, var/volume_modifier=0)
This proc calls the appropriate reaction procs of the reagents.
I.e. if A is an object, it will call the reagents reaction_obj
proc. The method var is used for reaction on mobs. It simply tells
us if the mob TOUCHed the reagent or if it INGESTed the reagent.
Since the volume can be checked in a reagents proc, you might want to
use the volume_modifier var to modifiy the passed value without actually
changing the volume of the reagents.
If you're not sure if you need to use this the answer is very most likely 'No'.
You'll want to use this proc whenever an atom first comes in
contact with the reagents of a holder. (in the 'splash' part of a beaker i.e.)
More on the reaction in the reagent part of this readme.
add_reagent(var/reagent, var/amount)
Attempts to add X of the matching reagent to the holder.
You wont use this much. Mostly in new procs for pre-filled
objects.
remove_reagent(var/reagent, var/amount)
The exact opposite of the add_reagent proc.
has_reagent(var/reagent, var/amount)
Returns 1 if the holder contains this reagent.
Or 0 if not.
If you pass it an amount it will additionally check
if the amount is matched. This is optional.
get_reagent_amount(var/reagent)
Returns the amount of the matching reagent inside the
holder. Returns 0 if the reagent is missing.
Important variables:
total_volume
This variable contains the total volume of all reagents in this holder.
reagent_list
This is a list of all contained reagents. More specifically, references
to the reagent datums.
maximum_volume
This is the maximum volume of the holder.
my_atom
This is the atom the holder is 'in'. Useful if you need to find the location.
(i.e. for explosions)
About Reagents:
Reagents are all the things you can mix and fille in bottles etc. This can be anything from
rejuvs over water to ... iron. Each reagent also has a few procs - i'll explain those below.
reaction_mob(var/mob/M, var/method=TOUCH)
This is called by the holder's reation proc.
This version is only called when the reagent
reacts with a mob. The method var can be either
TOUCH or INGEST. You'll want to put stuff like
acid-facemelting in here.
reaction_obj(var/obj/O)
This is called by the holder's reation proc.
This version is called when the reagents reacts
with an object. You'll want to put stuff like
object melting in here ... or something. i dunno.
reaction_turf(var/turf/T)
This is called by the holder's reation proc.
This version is called when the reagents reacts
with a turf. You'll want to put stuff like extra
slippery floors for lube or something in here.
on_mob_life(var/mob/M)
This proc is called everytime the mobs life proc executes.
This is the place where you put damage for toxins ,
drowsyness for sleep toxins etc etc.
You'll want to call the parents proc by using ..() .
If you dont, the chemical will stay in the mob forever -
unless you write your own piece of code to slowly remove it.
(Should be pretty easy, 1 line of code)
Important variables:
holder
This variable contains a reference to the holder the chemical is 'in'
volume
This is the volume of the reagent.
id
The id of the reagent
name
The name of the reagent.
data
This var can be used for whatever the fuck you want. I used it for the sleep
toxins to make them work slowly instead of instantly. You could also use this
for DNA in a blood reagent or ... well whatever you want.
About Recipes:
Recipes are simple datums that contain a list of required reagents and a result.
They also have a proc that is called when the recipe is matched.
on_reaction(var/datum/reagents/holder, var/created_volume)
This proc is called when the recipe is matched.
You'll want to add explosions etc here.
To find the location you'll have to do something
like get_turf(holder.my_atom)
name & id
Should be pretty obvious.
result
This var contains the id of the resulting reagent.
required_reagents
This is a list of ids of the required reagents.
Each id also needs an associated value that gives us the minimum required amount
of that reagent. The handle_reaction proc can detect mutiples of the same recipes
so for most cases you want to set the required amount to 1.
result_amount
This is the amount of the resulting reagent this recipe will produce.
I recommend you set this to the total volume of all required reagent.
About the Tools:
By default, all atom have a reagents var - but its empty. if you want to use an object for the chem.
system you'll need to add something like this in its new proc:
var/datum/reagents/R = new/datum/reagents(100) <<<<< create a new datum , 100 is the maximum_volume of the new holder datum.
reagents = R <<<<< assign the new datum to the objects reagents var
R.my_atom = src <<<<< set the holders my_atom to src so that we know where we are.
This can also be done by calling a convenience proc:
atom/proc/create_reagents(var/max_volume)
Other important stuff:
amount_per_transfer_from_this var
This var is mostly used by beakers and bottles.
It simply tells us how much to transfer when
'pouring' our reagents into something else.
atom/proc/is_open_container()
Checks atom/var/flags & OPENCONTAINER.
If this returns 1 , you can use syringes, beakers etc
to manipulate the contents of this object.
If it's 0, you'll need to write your own custom reagent
transfer code since you will not be able to use the standard
tools to manipulate it.
*/

View File

@@ -0,0 +1,920 @@
#define SOLID 1
#define LIQUID 2
#define GAS 3
//The reaction procs must ALWAYS set src = null, this detaches the proc from the object (the reagent)
//so that it can continue working when the reagent is deleted while the proc is still active.
datum
reagent
var/name = "Reagent"
var/id = "reagent"
var/description = ""
var/datum/reagents/holder = null
var/reagent_state = SOLID
var/data = null
var/volume = 0
proc
reaction_mob(var/mob/M, var/method=TOUCH, var/volume) //By default we have a chance to transfer some
var/datum/reagent/self = src
src = null //of the reagent to the mob on TOUCHING it.
if(method == TOUCH)
var/chance = 1
for(var/obj/item/clothing/C in M.get_equipped_items())
if(C.permeability_coefficient < chance) chance = C.permeability_coefficient
chance = chance * 100
if(prob(chance))
if(M.reagents)
M.reagents.add_reagent(self.id,self.volume/2)
return
reaction_obj(var/obj/O, var/volume) //By default we transfer a small part of the reagent to the object
src = null //if it can hold reagents. nope!
//if(O.reagents)
// O.reagents.add_reagent(id,volume/3)
return
reaction_turf(var/turf/T, var/volume)
src = null
return
on_mob_life(var/mob/M)
holder.remove_reagent(src.id, 0.4) //By default it slowly disappears.
return
milk
name = "Milk"
id = "milk"
description = "An opaque white liquid produced by the mammary glands of mammals."
reagent_state = LIQUID
beer
name = "Beer"
id = "beer"
description = "An alcoholic beverage made from malted grains, hops, yeast, and water."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!data) data = 1
data++
M.make_dizzy(3)
M:jitteriness = max(M:jitteriness-3,0)
if(data >= 25)
if (!M:stuttering) M:stuttering = 1
M:stuttering += 3
if(data >= 40 && prob(33))
if (!M:confused) M:confused = 1
M:confused += 2
..()
water
name = "Water"
id = "water"
description = "A ubiquitous chemical substance that is composed of hydrogen and oxygen."
reagent_state = LIQUID
reaction_turf(var/turf/T, var/volume)
src = null
if(volume >= 3)
if(T:wet >= 1) return
T:wet = 1
if(T:wet_overlay)
T:overlays -= T:wet_overlay
T:wet_overlay = null
T:wet_overlay = image('water.dmi',T,"wet_floor")
T:overlays += T:wet_overlay
spawn(800)
if(T:wet >= 2) return
T:wet = 0
if(T:wet_overlay)
T:overlays -= T:wet_overlay
T:wet_overlay = null
var/hotspot = (locate(/obj/hotspot) in T)
if(hotspot)
var/datum/gas_mixture/lowertemp = T.remove_air( T:air:total_moles() )
lowertemp.temperature = max( min(lowertemp.temperature-2000,lowertemp.temperature / 2) ,0)
lowertemp.react()
T.assume_air(lowertemp)
del(hotspot)
return
reaction_obj(var/obj/O, var/volume)
src = null
var/turf/T = get_turf(O)
var/hotspot = (locate(/obj/hotspot) in T)
if(hotspot)
var/datum/gas_mixture/lowertemp = T.remove_air( T:air:total_moles() )
lowertemp.temperature = max( min(lowertemp.temperature-2000,lowertemp.temperature / 2) ,0)
lowertemp.react()
T.assume_air(lowertemp)
del(hotspot)
return
lube
name = "Space Lube"
id = "lube"
description = "Lubricant is a substance introduced between two moving surfaces to reduce the friction and wear between them. giggity."
reagent_state = LIQUID
reaction_turf(var/turf/T, var/volume)
src = null
if(T:wet >= 2) return
T:wet = 2
spawn(800)
T:wet = 0
if(T:wet_overlay)
T:overlays -= T:wet_overlay
T:wet_overlay = null
return
bilk
name = "Bilk"
id = "bilk"
description = "This appears to be beer mixed with milk. Disgusting."
reagent_state = LIQUID
anti_toxin
name = "Anti-Toxin (Dylovene)"
id = "anti_toxin"
description = "Dylovene is a broad-spectrum antitoxin."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:drowsyness = max(M:drowsyness-2, 0)
if(holder.has_reagent("toxin"))
holder.remove_reagent("toxin", 2)
if(holder.has_reagent("stoxin"))
holder.remove_reagent("stoxin", 2)
if(holder.has_reagent("plasma"))
holder.remove_reagent("plasma", 1)
if(holder.has_reagent("acid"))
holder.remove_reagent("acid", 1)
if(holder.has_reagent("cyanide"))
holder.remove_reagent("cyanide", 1)
M:toxloss = max(M:toxloss-2,0)
..()
return
toxin
name = "Toxin"
id = "toxin"
description = "A Toxic chemical."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:toxloss += 1.5
..()
return
cyanide
name = "Cyanide"
id = "cyanide"
description = "A highly toxic chemical."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:toxloss += 3
M:oxyloss += 3
..()
return
stoxin
name = "Sleep Toxin"
id = "stoxin"
description = "An effective hypnotic used to treat insomnia."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(!data) data = 1
switch(data)
if(1 to 15)
M.eye_blurry = max(M.eye_blurry, 10)
if(15 to 25)
M:drowsyness = max(M:drowsyness, 20)
if(25 to INFINITY)
M:paralysis = max(M:paralysis, 20)
M:drowsyness = max(M:drowsyness, 30)
data++
..()
return
inaprovaline
name = "Inaprovaline"
id = "inaprovaline"
description = "Inaprovaline is a synaptic stimulant and cardiostimulant. Commonly used to stabilize patients."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(M.losebreath >= 10)
M.losebreath = max(10, M.losebreath-5)
holder.remove_reagent(src.id, 0.2)
return
space_drugs
name = "Space drugs"
id = "space_drugs"
description = "An illegal chemical compound used as drug."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M.druggy = max(M.druggy, 15)
if(M.canmove) step(M, pick(cardinal))
if(prob(7)) M:emote(pick("twitch","drool","moan","giggle"))
holder.remove_reagent(src.id, 0.2)
return
silicate
name = "Silicate"
id = "silicate"
description = "A compound that can be used to reinforce glass."
reagent_state = LIQUID
reaction_obj(var/obj/O, var/volume)
src = null
if(istype(O,/obj/window))
O:health = O:health * 2
var/icon/I = icon(O.icon,O.icon_state,O.dir)
I.SetIntensity(1.15,1.50,1.75)
O.icon = I
return
oxygen
name = "Oxygen"
id = "oxygen"
description = "A colorless, odorless gas."
reagent_state = GAS
nitrogen
name = "Nitrogen"
id = "nitrogen"
description = "A colorless, odorless, tasteless gas."
reagent_state = GAS
hydrogen
name = "Hydrogen"
id = "hydrogen"
description = "A colorless, odorless, nonmetallic, tasteless, highly combustible diatomic gas."
reagent_state = GAS
potassium
name = "Potassium"
id = "potassium"
description = "A soft, low-melting solid that can easily be cut with a knife. Reacts violently with water."
reagent_state = SOLID
mercury
name = "Mercury"
id = "mercury"
description = "A chemical element."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(M.canmove) step(M, pick(cardinal))
if(prob(5)) M:emote(pick("twitch","drool","moan"))
..()
return
sulfur
name = "Sulfur"
id = "sulfur"
description = "A chemical element."
reagent_state = SOLID
carbon
name = "Carbon"
id = "carbon"
description = "A chemical element."
reagent_state = SOLID
reaction_turf(var/turf/T, var/volume)
src = null
if(!istype(T, /turf/space))
new /obj/decal/cleanable/dirt(T)
chlorine
name = "Chlorine"
id = "chlorine"
description = "A chemical element."
reagent_state = GAS
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:bruteloss++
..()
return
fluorine
name = "Fluorine"
id = "fluorine"
description = "A highly-reactive chemical element."
reagent_state = GAS
on_mob_life(var/mob.M)
if(!M) M = holder.my_atom
M:toxloss++
..()
return
phosphorus
name = "Phosphorus"
id = "phosphorus"
description = "A chemical element."
reagent_state = SOLID
lithium
name = "Lithium"
id = "lithium"
description = "A chemical element."
reagent_state = SOLID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(M.canmove) step(M, pick(cardinal))
if(prob(5)) M:emote(pick("twitch","drool","moan"))
..()
return
sugar
name = "Sugar"
id = "sugar"
description = "The organic compound commonly known as table sugar and sometimes called saccharose. This white, odorless, crystalline powder has a pleasing, sweet taste."
reagent_state = SOLID
acid
name = "Sulphuric acid"
id = "acid"
description = "A strong mineral acid with the molecular formula H2SO4."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:toxloss++
M:fireloss++
..()
return
reaction_mob(var/mob/M, var/method=TOUCH, var/volume)
if(method == TOUCH)
if(istype(M, /mob/living/carbon/human))
if(M:wear_mask)
del (M:wear_mask)
M << "\red Your mask melts away but protects you from the acid!"
return
if(M:head)
del (M:head)
M << "\red Your helmet melts into uselessness but protects you from the acid!"
return
if(prob(75))
var/datum/organ/external/affecting = M:organs["head"]
affecting.take_damage(25, 0)
M:UpdateDamage()
M:UpdateDamageIcon()
M:emote("scream")
M << "\red Your face has become disfigured!"
M.real_name = "Unknown"
else
M:bruteloss += 15
else
M:bruteloss += 15
reaction_obj(var/obj/O, var/volume)
if(istype(O,/obj/item) && prob(40))
var/obj/decal/cleanable/molten_item/I = new/obj/decal/cleanable/molten_item(O.loc)
I.desc = "Looks like this was \an [O] some time ago."
for(var/mob/M in viewers(5, O))
M << "\red \the [O] melts."
del(O)
pacid
name = "Polytrinic acid"
id = "pacid"
description = "Polytrinic acid is a an extremely corrosive chemical substance."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:toxloss++
M:fireloss++
..()
return
reaction_mob(var/mob/M, var/method=TOUCH, var/volume)
if(method == TOUCH)
if(istype(M, /mob/living/carbon/human))
if(M:wear_mask)
del (M:wear_mask)
M << "\red Your mask melts away!"
return
if(M:head)
del (M:head)
M << "\red Your helmet melts into uselessness!"
return
var/datum/organ/external/affecting = M:organs["head"]
affecting.take_damage(75, 0)
M:UpdateDamage()
M:UpdateDamageIcon()
M:emote("scream")
M << "\red Your face has become disfigured!"
M.real_name = "Unknown"
else
M:bruteloss += 15
else
if(istype(M, /mob/living/carbon/human))
var/datum/organ/external/affecting = M:organs["head"]
affecting.take_damage(75, 0)
M:UpdateDamage()
M:UpdateDamageIcon()
M:emote("scream")
M << "\red Your face has become disfigured!"
M.real_name = "Unknown"
else
M:bruteloss += 15
reaction_obj(var/obj/O, var/volume)
if(istype(O,/obj/item))
var/obj/decal/cleanable/molten_item/I = new/obj/decal/cleanable/molten_item(O.loc)
I.desc = "Looks like this was \an [O] some time ago."
for(var/mob/M in viewers(5, O))
M << "\red \the [O] melts."
del(O)
radium
name = "Radium"
id = "radium"
description = "Radium is an alkaline earth metal. It is extremely radioactive."
reagent_state = SOLID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M.radiation += 3
..()
return
reaction_turf(var/turf/T, var/volume)
src = null
if(!istype(T, /turf/space))
new /obj/decal/cleanable/greenglow(T)
ryetalyn
name = "Ryetalyn"
id = "ryetalyn"
description = "Ryetalyn can cure all genetic abnomalities."
reagent_state = SOLID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M.mutations = 0
M.disabilities = 0
M.sdisabilities = 0
..()
return
thermite
name = "Thermite"
id = "thermite"
description = "Thermite produces an aluminothermic reaction known as a thermite reaction. Can be used to melt walls."
reagent_state = SOLID
reaction_turf(var/turf/T, var/volume)
src = null
if(istype(T, /turf/simulated/wall))
T:thermite = 1
T.overlays = null
T.overlays = image('effects.dmi',icon_state = "thermite")
return
mutagen
name = "Unstable mutagen"
id = "mutagen"
description = "Might cause unpredictable mutations. Keep away from children."
reagent_state = LIQUID
reaction_mob(var/mob/M, var/method=TOUCH, var/volume)
src = null
if ( (method==TOUCH && prob(33)) || method==INGEST)
randmuti(M)
if(prob(98))
randmutb(M)
else
randmutg(M)
domutcheck(M, null, 1)
updateappearance(M,M.dna.uni_identity)
return
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M.radiation += 3
..()
return
iron
name = "Iron"
id = "iron"
description = "Pure iron is a metal."
reagent_state = SOLID
aluminium
name = "Aluminium"
id = "aluminium"
description = "A silvery white and ductile member of the boron group of chemical elements."
reagent_state = SOLID
silicon
name = "Silicon"
id = "silicon"
description = "A tetravalent metalloid, silicon is less reactive than its chemical analog carbon."
reagent_state = SOLID
fuel
name = "Welding fuel"
id = "fuel"
description = "Required for welders. Flamable."
reagent_state = LIQUID
reaction_obj(var/obj/O, var/volume)
src = null
var/turf/the_turf = get_turf(O)
var/datum/gas_mixture/napalm = new
var/datum/gas/volatile_fuel/fuel = new
fuel.moles = 15
napalm.trace_gases += fuel
the_turf.assume_air(napalm)
reaction_turf(var/turf/T, var/volume)
src = null
var/datum/gas_mixture/napalm = new
var/datum/gas/volatile_fuel/fuel = new
fuel.moles = 15
napalm.trace_gases += fuel
T.assume_air(napalm)
return
coffee
name = "Coffee"
id = "coffee"
description = "Coffee is a brewed drink prepared from roasted seeds, commonly called coffee beans, of the coffee plant."
reagent_state = LIQUID
on_mob_life(var/mob/M)
..()
M.dizziness = max(0,M.dizziness-5)
M:drowsyness = max(0,M:drowsyness-3)
M:sleeping = 0
M.bodytemperature = min(310, M.bodytemperature+5) //310 is the normal bodytemp. 310.055
M.make_jittery(5)
space_cleaner
name = "Space cleaner"
id = "cleaner"
description = "A compound used to clean things. Now with 50% more sodium hypochlorite!"
reagent_state = LIQUID
reaction_obj(var/obj/O, var/volume)
if(istype(O,/obj/decal/cleanable))
del(O)
else
O.clean_blood()
reaction_turf(var/turf/T, var/volume)
T.overlays = null
T.clean_blood()
for(var/obj/decal/cleanable/C in src)
del(C)
reaction_mob(var/mob/M, var/method=TOUCH, var/volume)
M.clean_blood()
if(istype(M, /mob/living/carbon))
var/mob/living/carbon/C = M
if(C.r_hand)
C.r_hand.clean_blood()
if(C.l_hand)
C.l_hand.clean_blood()
if(C.wear_mask)
C.wear_mask.clean_blood()
if(istype(M, /mob/living/carbon/human))
if(C:w_uniform)
C:w_uniform.clean_blood()
if(C:wear_suit)
C:wear_suit.clean_blood()
if(C:shoes)
C:shoes.clean_blood()
if(C:gloves)
C:gloves.clean_blood()
if(C:head)
C:head.clean_blood()
space_cola
name = "Cola"
id = "cola"
description = "A refreshing beverage."
reagent_state = LIQUID
on_mob_life(var/mob/M)
M:drowsyness = max(0,M:drowsyness-5)
M.bodytemperature = max(310, M.bodytemperature-5) //310 is the normal bodytemp. 310.055
plasma
name = "Plasma"
id = "plasma"
description = "Plasma in its liquid form."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(holder.has_reagent("inaprovaline"))
holder.remove_reagent("inaprovaline", 2)
M:toxloss++
..()
return
reaction_obj(var/obj/O, var/volume)
src = null
var/turf/the_turf = get_turf(O)
var/datum/gas_mixture/napalm = new
var/datum/gas/volatile_fuel/fuel = new
fuel.moles = 5
napalm.trace_gases += fuel
the_turf.assume_air(napalm)
reaction_turf(var/turf/T, var/volume)
src = null
var/datum/gas_mixture/napalm = new
var/datum/gas/volatile_fuel/fuel = new
fuel.moles = 5
napalm.trace_gases += fuel
T.assume_air(napalm)
return
leporazine
name = "Leporazine"
id = "leporazine"
description = "Leporazine can be use to stabilize an individuals body temperature."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(M.bodytemperature < 310)
M.bodytemperature = max(310, M.bodytemperature-10)
else if(M.bodytemperature > 311)
M.bodytemperature = min(310, M.bodytemperature+10)
..()
return
cryptobiolin
name = "Cryptobiolin"
id = "cryptobiolin"
description = "Cryptobiolin causes confusion and dizzyness."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M.make_dizzy(1)
if(!M.confused) M.confused = 1
M.confused = max(M.confused, 20)
holder.remove_reagent(src.id, 0.2)
return
lexorin
name = "Lexorin"
id = "lexorin"
description = "Lexorin temporarily stops respiration. Causes tissue damage."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(prob(33)) M.bruteloss++
holder.remove_reagent(src.id, 0.3)
return
kelotane
name = "Kelotane"
id = "kelotane"
description = "Kelotane is a drug used to treat burns."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:fireloss = max(M:fireloss-2,0)
..()
return
dexalin
name = "Dexalin"
id = "dexalin"
description = "Dexalin is used in the treatment of oxygen deprivation."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:oxyloss = max(M:oxyloss-2, 0)
..()
return
dexalinp
name = "Dexalin Plus"
id = "dexalinp"
description = "Dexalin Plus is used in the treatment of oxygen deprivation. Its highly effective."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:oxyloss = 0
..()
return
tricordrazine
name = "Tricordrazine"
id = "tricordrazine"
description = "Tricordrazine is a highly potent stimulant, originally derived from cordrazine. Can be used to treat a wide range of injuries."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(M:oxyloss && prob(40)) M:oxyloss--
if(M:bruteloss && prob(40)) M:bruteloss--
if(M:fireloss && prob(40)) M:fireloss--
if(M:toxloss && prob(40)) M:toxloss--
..()
return
synaptizine
name = "Synaptizine"
id = "synaptizine"
description = "Synaptizine is used to treat neuroleptic shock. Can be used to help remove disabling symptoms such as paralysis."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:drowsyness = max(M:drowsyness-5, 0)
if(M:paralysis) M:paralysis--
if(M:stunned) M:stunned--
if(M:weakened) M:weakened--
..()
return
impedrezene
name = "Impedrezene"
id = "impedrezene"
description = "Impedrezene is a narcotic that impedes one's ability by slowing down the higher brain cell functions."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:jitteriness = max(M:jitteriness-5,0)
if(prob(80)) M:brainloss++
if(prob(50)) M:drowsyness = max(M:drowsyness, 3)
if(prob(10)) M:emote("drool")
..()
return
hyronalin
name = "Hyronalin"
id = "hyronalin"
description = "Hyronalin is a medicinal drug used to counter the effects of radiation poisoning."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(M:radiation && prob(80)) M:radiation--
..()
return
alkysine
name = "Alkysine"
id = "alkysine"
description = "Alkysine is a drug used to lessen the damage to neurological tissue after a catastrophic injury. Can heal brain tissue."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:brainloss = max(M:brainloss-3 , 0)
..()
return
arithrazine
name = "Arithrazine"
id = "arithrazine"
description = "Arithrazine is an unstable medication used for the most extreme cases of radiation poisoning."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
M:radiation = max(M:radiation-3,0)
if(M:toxloss && prob(50)) M:toxloss--
if(prob(15)) M:bruteloss++
..()
return
bicaridine
name = "Bicaridine"
id = "bicaridine"
description = "Bicaridine is an analgesic medication and can be used to treat blunt trauma."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(M:bruteloss && prob(40)) M:bruteloss--
..()
return
hyperzine
name = "Hyperzine"
id = "hyperzine"
description = "Hyperzine is a highly effective, long lasting, muscle stimulant."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(prob(5)) M:emote(pick("twitch","blink_r","shiver"))
holder.remove_reagent(src.id, 0.2)
return
cryoxadone
name = "Cryoxadone"
id = "cryoxadone"
description = "A chemical mixture with almost magical healing powers. Its main limitation is that the targets body temperature must be under 170K for it to metabolise correctly."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if(M.bodytemperature < 170)
if(M:oxyloss) M:oxyloss = max(0, M:oxyloss-3)
if(M:bruteloss) M:bruteloss = max(0, M:bruteloss-3)
if(M:fireloss) M:fireloss = max(0, M:fireloss-3)
if(M:toxloss) M:toxloss = max(0, M:toxloss-3)
return
spaceacillin
name = "Spaceacillin"
id = "spaceacillin"
description = "An all-purpose antiviral agent."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!M) M = holder.my_atom
if((M.virus) && (prob(8)))
if(M.virus.spread == "Airborne")
M.virus.spread = "Remissive"
M.virus.stage--
if(M.virus.stage <= 0)
M.resistances += M.virus.type
M.virus = null
holder.remove_reagent(src.id, 0.2)
return
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
nanites
name = "Nanomachines"
id = "nanites"
description = "Microscopic construction robots."
reagent_state = LIQUID
reaction_mob(var/mob/M, var/method=TOUCH, var/volume)
src = null
if( (prob(10) && method==TOUCH) || method==INGEST)
if(!M.virus)
M.virus = new /datum/disease/robotic_transformation
M.virus.affected_mob = M
xenomicrobes
name = "Xenomicrobes"
id = "xenomicrobes"
description = "Microbes with an entirely alien cellular structure."
reagent_state = LIQUID
reaction_mob(var/mob/M, var/method=TOUCH, var/volume)
src = null
if( (prob(10) && method==TOUCH) || method==INGEST)
if(!M.virus)
M.virus = new /datum/disease/xeno_transformation
M.virus.affected_mob = M
//foam precursor
fluorosurfactant
name = "Fluorosurfactant"
id = "fluorosurfactant"
description = "A perfluoronated sulfonic acid that forms a foam when mixed with water."
reagent_state = LIQUID
// metal foaming agent
// this is lithium hydride. Add other recipies (e.g. LiH + H2O -> LiOH + H2) eventually
foaming_agent
name = "Foaming agent"
id = "foaming_agent"
description = "A agent that yields metallic foam when mixed with light metal and a strong acid."
reagent_state = SOLID
nicotine
name = "Nicotine"
id = "nicotine"
description = "A highly addictive stimulant extracted from the tobacco plant."
reagent_state = LIQUID
ethanol
name = "Ethanol"
id = "ethanol"
description = "A well-known alcohol with a variety of applications."
reagent_state = LIQUID
on_mob_life(var/mob/M)
if(!data) data = 1
data++
M.make_dizzy(5)
M:jitteriness = max(M:jitteriness-5,0)
if(data >= 25)
if (!M:stuttering) M:stuttering = 1
M:stuttering += 4
if(data >= 40 && prob(33))
if (!M:confused) M:confused = 1
M:confused += 3
..()
ammonia
name = "Ammonia"
id = "ammonia"
description = "A caustic substance commonly used in fertilizer or household cleaners."
reagent_state = GAS
diethylamine
name = "Diethylamine"
id = "diethylamine"
description = "A secondary amine, mildly corrosive."
reagent_state = LIQUID

View File

@@ -0,0 +1,390 @@
///////////////////////////////////////////////////////////////////////////////////
datum
chemical_reaction
var/name = null
var/id = null
var/result = null
var/list/required_reagents = new/list()
var/result_amount = 0
proc
on_reaction(var/datum/reagents/holder, var/created_volume)
return
//I recommend you set the result amount to the total volume of all components.
bilk
name = "Bilk"
id = "bilk"
result = "bilk"
required_reagents = list("milk" = 1, "beer" = 1)
result_amount = 2
explosion_potassium
name = "Explosion"
id = "explosion_potassium"
result = null
required_reagents = list("water" = 1, "potassium" = 1)
result_amount = null
on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread
s.set_up(2, 1, location)
s.start()
for(var/mob/M in viewers(5, location))
M << "\red The solution violently explodes."
for(var/mob/M in viewers(1, location))
M << "\red The explosion knocks you down."
M:weakened += 3
return
silicate
name = "Silicate"
id = "silicate"
result = "silicate"
required_reagents = list("aluminium" = 1, "silicon" = 1, "oxygen" = 1)
result_amount = 3
mutagen
name = "Unstable mutagen"
id = "mutagen"
result = "mutagen"
required_reagents = list("radium" = 1, "phosphorus" = 1, "chlorine" = 1)
result_amount = 3
//cyanide
// name = "Cyanide"
// id = "cyanide"
// result = "cyanide"
// required_reagents = list("hydrogen" = 1, "carbon" = 1, "nitrogen" = 1)
// result_amount = 3
thermite
name = "Thermite"
id = "thermite"
result = "thermite"
required_reagents = list("aluminium" = 1, "iron" = 1, "oxygen" = 1)
result_amount = 3
lexorin
name = "Lexorin"
id = "lexorin"
result = "lexorin"
required_reagents = list("plasma" = 1, "hydrogen" = 1, "nitrogen" = 1)
result_amount = 3
space_drugs
name = "Space Drugs"
id = "space_drugs"
result = "space_drugs"
required_reagents = list("mercury" = 1, "sugar" = 1, "lithium" = 1)
result_amount = 3
lube
name = "Space Lube"
id = "lube"
result = "lube"
required_reagents = list("water" = 1, "silicon" = 1, "oxygen" = 1)
result_amount = 4
pacid
name = "Polytrinic acid"
id = "pacid"
result = "pacid"
required_reagents = list("acid" = 1, "chlorine" = 1, "potassium" = 1)
result_amount = 3
synaptizine
name = "Synaptizine"
id = "synaptizine"
result = "synaptizine"
required_reagents = list("sugar" = 1, "lithium" = 1, "water" = 1)
result_amount = 3
hyronalin
name = "Hyronalin"
id = "hyronalin"
result = "hyronalin"
required_reagents = list("radium" = 1, "anti_toxin" = 1)
result_amount = 2
arithrazine
name = "Arithrazine"
id = "arithrazine"
result = "arithrazine"
required_reagents = list("hyronalin" = 1, "hydrogen" = 1)
result_amount = 2
impedrezene
name = "Impedrezene"
id = "impedrezene"
result = "impedrezene"
required_reagents = list("mercury" = 1, "oxygen" = 1, "sugar" = 1)
result_amount = 2
kelotane
name = "Kelotane"
id = "kelotane"
result = "kelotane"
required_reagents = list("silicon" = 1, "carbon" = 1)
result_amount = 2
leporazine
name = "Leporazine"
id = "leporazine"
result = "leporazine"
required_reagents = list("silicon" = 1, "plasma" = 1, )
result_amount = 2
cryptobiolin
name = "Cryptobiolin"
id = "cryptobiolin"
result = "cryptobiolin"
required_reagents = list("potassium" = 1, "oxygen" = 1, "sugar" = 1)
result_amount = 3
tricordrazine
name = "Tricordrazine"
id = "tricordrazine"
result = "tricordrazine"
required_reagents = list("inaprovaline" = 1, "anti_toxin" = 1)
result_amount = 2
alkysine
name = "Alkysine"
id = "alkysine"
result = "alkysine"
required_reagents = list("chlorine" = 1, "nitrogen" = 1, "anti_toxin" = 1)
result_amount = 2
dexalin
name = "Dexalin"
id = "dexalin"
result = "dexalin"
required_reagents = list("plasma" = 1, "oxygen" = 1)
result_amount = 2
dexalinp
name = "Dexalin Plus"
id = "dexalinp"
result = "dexalinp"
required_reagents = list("dexalin" = 1, "carbon" = 1, "iron" = 1)
result_amount = 3
bicaridine
name = "Bicaridine"
id = "bicaridine"
result = "bicaridine"
required_reagents = list("inaprovaline" = 1, "carbon" = 1)
result_amount = 2
hyperzine
name = "Hyperzine"
id = "hyperzine"
result = "hyperzine"
required_reagents = list("sugar" = 1, "phosphorus" = 1, "sulfur" = 1,)
result_amount = 3
ryetalyn
name = "Ryetalyn"
id = "ryetalyn"
result = "ryetalyn"
required_reagents = list("arithrazine" = 1, "carbon" = 1)
result_amount = 2
cryoxadone
name = "Cryoxadone"
id = "cryoxadone"
result = "cryoxadone"
required_reagents = list("dexalin" = 1, "water" = 1, "oxygen" = 1)
result_amount = 10
spaceacillin
name = "spaceacillin"
id = "spaceacillin"
result = "spaceacillin"
required_reagents = list("cryptobiolin" = 1, "inaprovaline" = 1)
result_amount = 2
flash_powder
name = "Flash powder"
id = "flash_powder"
result = null
required_reagents = list("aluminium" = 1, "potassium" = 1, "sulfur" = 1 )
result_amount = null
on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
var/datum/effects/system/spark_spread/s = new /datum/effects/system/spark_spread
s.set_up(2, 1, location)
s.start()
for(var/mob/living/carbon/M in viewers(world.view, location))
switch(get_dist(M, location))
if(0 to 3)
if(hasvar(M, "glasses"))
if(istype(M:glasses, /obj/item/clothing/glasses/sunglasses))
continue
flick("e_flash", M.flash)
M.weakened = 15
if(4 to 5)
if(hasvar(M, "glasses"))
if(istype(M:glasses, /obj/item/clothing/glasses/sunglasses))
continue
flick("e_flash", M.flash)
M.stunned = 5
napalm
name = "Napalm"
id = "napalm"
result = null
required_reagents = list("aluminium" = 1, "plasma" = 1, "acid" = 1 )
result_amount = null
on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/turf/simulated/floor/target_tile in range(1,location))
if(target_tile.parent && target_tile.parent.group_processing)
target_tile.parent.suspend_group_processing()
var/datum/gas_mixture/napalm = new
var/datum/gas/volatile_fuel/fuel = new
fuel.moles = 15
napalm.trace_gases += fuel
target_tile.assume_air(napalm)
spawn (0) target_tile.hotspot_expose(700, 400)
return
smoke
name = "Smoke"
id = "smoke"
result = null
required_reagents = list("potassium" = 1, "sugar" = 1, "phosphorus" = 1 )
result_amount = null
on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
var/datum/effects/system/bad_smoke_spread/S = new /datum/effects/system/bad_smoke_spread
S.attach(location)
S.set_up(10, 0, location)
playsound(location, 'smoke.ogg', 50, 1, -3)
spawn(0)
S.start()
sleep(10)
S.start()
sleep(10)
S.start()
sleep(10)
S.start()
sleep(10)
S.start()
return
///////////////////////////////////////////////////////////////////////////////////
// foam and foam precursor
surfactant
name = "Foam surfactant"
id = "foam surfactant"
result = "fluorosurfactant"
required_reagents = list("fluorine" = 2, "carbon" = 2, "acid" = 1)
result_amount = 5
foam
name = "Foam"
id = "foam"
result = null
required_reagents = list("fluorosurfactant" = 1, "water" = 1)
result_amount = 2
on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/mob/M in viewers(5, location))
M << "\red The solution violently bubbles!"
location = get_turf(holder.my_atom)
for(var/mob/M in viewers(5, location))
M << "\red The solution spews out foam!"
//world << "Holder volume is [holder.total_volume]"
//for(var/datum/reagent/R in holder.reagent_list)
// world << "[R.name] = [R.volume]"
var/datum/effects/system/foam_spread/s = new()
s.set_up(created_volume, location, holder, 0)
s.start()
holder.clear_reagents()
return
metalfoam
name = "Metal Foam"
id = "metalfoam"
result = null
required_reagents = list("aluminium" = 3, "foaming_agent" = 1, "pacid" = 1)
result_amount = 5
on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/mob/M in viewers(5, location))
M << "\red The solution spews out a metalic foam!"
var/datum/effects/system/foam_spread/s = new()
s.set_up(created_volume/2, location, holder, 1)
s.start()
return
ironfoam
name = "Iron Foam"
id = "ironlfoam"
result = null
required_reagents = list("iron" = 3, "foaming_agent" = 1, "pacid" = 1)
result_amount = 5
on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
for(var/mob/M in viewers(5, location))
M << "\red The solution spews out a metalic foam!"
var/datum/effects/system/foam_spread/s = new()
s.set_up(created_volume/2, location, holder, 2)
s.start()
return
foaming_agent
name = "Foaming Agent"
id = "foaming_agent"
result = "foaming_agent"
required_reagents = list("lithium" = 1, "hydrogen" = 1)
result_amount = 1
// Synthesizing these three chemicals is pretty complex in real life, but fuck it, it's just a game!
ammonia
name = "Ammonia"
id = "ammonia"
result = "ammonia"
required_reagents = list("hydrogen" = 3, "nitrogen" = 1)
result_amount = 3
space_cleaner
name = "Space cleaner"
id = "cleaner"
result = "cleaner"
required_reagents = list("ammonia" = 1, "water" = 1)
result_amount = 1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,490 @@
/obj/signpost
icon = 'old_or_unused.dmi'
icon_state = "signpost"
anchored = 1
density = 1
attackby(obj/item/weapon/W as obj, mob/user as mob)
return attack_hand(user)
attack_hand(mob/user as mob)
switch(alert("Travel back to ss13?",,"Yes","No"))
if("Yes")
user.loc.loc.Exited(user)
user.loc = pick(latejoin)
if("No")
return
/area/beach
name = "Keelin's private beach"
icon_state = "null"
luminosity = 1
sd_lighting = 0
requires_power = 0
var/sound/mysound = null
New()
..()
var/sound/S = new/sound()
mysound = S
S.file = 'shore.ogg'
S.repeat = 1
S.wait = 0
S.channel = 123
S.volume = 100
S.priority = 255
S.status = SOUND_UPDATE
process()
Entered(atom/movable/Obj,atom/OldLoc)
if(ismob(Obj))
if(Obj:client)
mysound.status = SOUND_UPDATE
Obj << mysound
return
Exited(atom/movable/Obj)
if(ismob(Obj))
if(Obj:client)
mysound.status = SOUND_PAUSED | SOUND_UPDATE
Obj << mysound
proc/process()
set background = 1
var/sound/S = null
var/sound_delay = 0
if(prob(25))
S = sound(file=pick('seag1.ogg','seag2.ogg','seag3.ogg'), volume=100)
sound_delay = rand(0, 50)
for(var/mob/living/carbon/human/H in src)
if(H.s_tone > -55)
H.s_tone--
H.update_body()
if(H.client)
mysound.status = SOUND_UPDATE
H << mysound
if(S)
spawn(sound_delay)
H << S
spawn(60) .()
/obj/item/weapon/beach_ball
icon = 'beach.dmi'
icon_state = "ball"
name = "beach ball"
item_state = "clown"
density = 0
anchored = 0
w_class = 1.0
force = 0.0
throwforce = 0.0
throw_speed = 1
throw_range = 20
flags = FPRINT | USEDELAY | TABLEPASS | CONDUCT
afterattack(atom/target as mob|obj|turf|area, mob/user as mob)
user.drop_item()
src.throw_at(target, throw_range, throw_speed)
/obj/item/weapon/hand_labeler
icon = 'old_or_unused.dmi'
icon_state = "labeler"
item_state = "flight"
name = "Hand labeler"
var/label = null
var/labels_left = 10
/obj/item/weapon/hand_labeler/afterattack(atom/A, mob/user as mob)
if(A==loc) // if placing the labeller into something (e.g. backpack)
return // don't set a label
if(!labels_left)
user << "\red No labels left."
return
if(!label || !length(label))
user << "\red No text set."
return
if(length(A.name) + length(label) > 64)
user << "\red Label too big."
return
for(var/mob/M in viewers())
M << "\blue [user] puts a label on [A]."
A.name = "[A.name] ([label])"
/obj/item/weapon/hand_labeler/attack_self()
var/str = input(usr,"Label text?","Set label","")
if(!str || !length(str))
usr << "\red Invalid text."
return
if(length(str) > 10)
usr << "\red Text too long."
return
label = str
usr << "\blue You set the text to '[str]'."
/proc/testa()
fake_attack(usr)
/proc/testb()
fake_attack(input(usr) as mob in world)
/obj/fake_attacker
icon = null
icon_state = null
name = ""
desc = ""
density = 0
anchored = 1
opacity = 0
var/mob/living/carbon/human/my_target = null
var/weapon_name = null
/obj/fake_attacker/attackby()
step_away(src,my_target,2)
for(var/mob/M in oviewers(world.view,my_target))
M << "\red <B>[my_target] flails around wildly.</B>"
my_target.show_message("\red <B>[src] has been attacked by [my_target] </B>", 1) //Lazy.
return
/obj/fake_attacker/HasEntered(var/mob/M, somenumber)
if(M == my_target)
step_away(src,my_target,2)
if(prob(30))
for(var/mob/O in oviewers(world.view , my_target))
O << "\red <B>[my_target] stumbles around.</B>"
/obj/fake_attacker/New()
spawn(300) del(src)
step_away(src,my_target,2)
proccess()
/obj/fake_attacker/proc/proccess()
if(!my_target) spawn(5) .()
if(get_dist(src,my_target) > 1)
step_towards(src,my_target)
else
if(prob(15))
if(weapon_name)
my_target << sound(pick('genhit1.ogg', 'genhit2.ogg', 'genhit3.ogg'))
my_target.show_message("\red <B>[my_target] has been attacked with [weapon_name] by [src.name] </B>", 1)
if(prob(20)) my_target.eye_blurry += 3
if(prob(33))
if(!locate(/obj/overlay) in my_target.loc)
fake_blood(my_target)
else
my_target << sound(pick('punch1.ogg','punch2.ogg','punch3.ogg','punch4.ogg'))
my_target.show_message("\red <B>[src.name] has punched [my_target]!</B>", 1)
if(prob(33))
if(!locate(/obj/overlay) in my_target.loc)
fake_blood(my_target)
if(prob(15)) step_away(src,my_target,2)
spawn(5) .()
/proc/fake_blood(var/mob/target)
var/obj/overlay/O = new/obj/overlay(target.loc)
O.name = "blood"
var/image/I = image('blood.dmi',O,"floor[rand(1,7)]",O.dir,1)
target << I
spawn(300)
del(O)
return
/proc/fake_attack(var/mob/target)
var/list/possible_clones = new/list()
var/mob/living/carbon/human/clone = null
var/clone_weapon = null
for(var/mob/living/carbon/human/H in world)
if(H.stat || H.lying || H.dir == NORTH) continue
possible_clones += H
if(!possible_clones.len) return
clone = pick(possible_clones)
if(clone.l_hand)
clone_weapon = clone.l_hand.name
else if (clone.r_hand)
clone_weapon = clone.r_hand.name
var/obj/fake_attacker/F = new/obj/fake_attacker(target.loc)
F.name = clone.name
F.my_target = target
F.weapon_name = clone_weapon
var/image/O = image(clone,F)
target << O
/proc/can_see(var/atom/source, var/atom/target, var/length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate.
var/turf/current = get_turf(source)
var/turf/target_turf = get_turf(target)
var/steps = 0
while(current != target_turf)
if(steps > length) return 0
if(current.opacity) return 0
for(var/atom/A in current)
if(A.opacity) return 0
current = get_step_towards(current, target_turf)
steps++
return 1
/mob/proc/get_equipped_items()
var/list/items = new/list()
if(hasvar(src,"back")) if(src:back) items += src:back
if(hasvar(src,"belt")) if(src:belt) items += src:belt
if(hasvar(src,"ears")) if(src:ears) items += src:ears
if(hasvar(src,"glasses")) if(src:glasses) items += src:glasses
if(hasvar(src,"gloves")) if(src:gloves) items += src:gloves
if(hasvar(src,"head")) if(src:head) items += src:head
if(hasvar(src,"shoes")) if(src:shoes) items += src:shoes
if(hasvar(src,"wear_id")) if(src:wear_id) items += src:wear_id
if(hasvar(src,"wear_mask")) if(src:wear_mask) items += src:wear_mask
if(hasvar(src,"wear_suit")) if(src:wear_suit) items += src:wear_suit
// if(hasvar(src,"w_radio")) if(src:w_radio) items += src:w_radio commenting this out since headsets go on your ears now PLEASE DON'T BE MAD KEELIN
if(hasvar(src,"w_uniform")) if(src:w_uniform) items += src:w_uniform
//if(hasvar(src,"l_hand")) if(src:l_hand) items += src:l_hand
//if(hasvar(src,"r_hand")) if(src:r_hand) items += src:r_hand
return items
/proc/is_blocked_turf(var/turf/T)
var/cant_pass = 0
if(T.density) cant_pass = 1
for(var/atom/A in T)
if(A.density)//&&A.anchored
cant_pass = 1
return cant_pass
/proc/get_step_towards2(var/atom/ref , var/atom/trg)
var/base_dir = get_dir(ref, get_step_towards(ref,trg))
var/turf/temp = get_step_towards(ref,trg)
if(is_blocked_turf(temp))
var/dir_alt1 = turn(base_dir, 90)
var/dir_alt2 = turn(base_dir, -90)
var/turf/turf_last1 = temp
var/turf/turf_last2 = temp
var/free_tile = null
var/breakpoint = 0
while(!free_tile && breakpoint < 10)
if(!is_blocked_turf(turf_last1))
free_tile = turf_last1
break
if(!is_blocked_turf(turf_last2))
free_tile = turf_last2
break
turf_last1 = get_step(turf_last1,dir_alt1)
turf_last2 = get_step(turf_last2,dir_alt2)
breakpoint++
if(!free_tile) return get_step(ref, base_dir)
else return get_step_towards(ref,free_tile)
else return get_step(ref, base_dir)
/proc/do_mob(var/mob/user , var/mob/target, var/time = 30) //This is quite an ugly solution but i refuse to use the old request system.
if(!user || !target) return 0
var/user_loc = user.loc
var/target_loc = target.loc
var/holding = user.equipped()
sleep(time)
if ( user.loc == user_loc && target.loc == target_loc && user.equipped() == holding && !( user.stat ) && ( !user.stunned && !user.weakened && !user.paralysis && !user.lying ) )
return 1
else
return 0
/proc/do_after(mob/M as mob, time as num)
var/turf/T = M.loc
var/holding = M.equipped()
sleep(time)
if ((M.loc == T && M.equipped() == holding && !( M.stat )))
return 1
else
return 0
/proc/hasvar(var/datum/A, var/varname)
//Takes: Anything that could possibly have variables and a varname to check.
//Returns: 1 if found, 0 if not.
//Notes: Do i really need to explain this?
if(A.vars.Find(lowertext(varname))) return 1
else return 0
/proc/get_areas(var/areatype)
//Takes: Area type as text string or as typepath OR an instance of the area.
//Returns: A list of all areas of that type in the world.
//Notes: Simple!
if(!areatype) return null
if(istext(areatype)) areatype = text2path(areatype)
if(isarea(areatype))
var/area/areatemp = areatype
areatype = areatemp.type
var/list/areas = new/list()
for(var/area/N in world)
if(istype(N, areatype)) areas += N
return areas
/proc/get_area_turfs(var/areatype)
//Takes: Area type as text string or as typepath OR an instance of the area.
//Returns: A list of all turfs in areas of that type of that type in the world.
//Notes: Simple!
if(!areatype) return null
if(istext(areatype)) areatype = text2path(areatype)
if(isarea(areatype))
var/area/areatemp = areatype
areatype = areatemp.type
var/list/turfs = new/list()
for(var/area/N in world)
if(istype(N, areatype))
for(var/turf/T in N) turfs += T
return turfs
/proc/get_area_all_atoms(var/areatype)
//Takes: Area type as text string or as typepath OR an instance of the area.
//Returns: A list of all atoms (objs, turfs, mobs) in areas of that type of that type in the world.
//Notes: Simple!
if(!areatype) return null
if(istext(areatype)) areatype = text2path(areatype)
if(isarea(areatype))
var/area/areatemp = areatype
areatype = areatemp.type
var/list/atoms = new/list()
for(var/area/N in world)
if(istype(N, areatype))
for(var/atom/A in N)
atoms += A
return atoms
/datum/coords //Simple datum for storing coordinates.
var/x_pos = null
var/y_pos = null
var/z_pos = null
/area/proc/move_contents_to(var/area/A, var/turftoleave=null)
//Takes: Area. Optional: turf type to leave behind.
//Returns: Nothing.
//Notes: Attempts to move the contents of one area to another area.
// Movement based on lower left corner. Tiles that do not fit
// into the new area will not be moved.
if(!A || !src) return 0
var/list/turfs_src = get_area_turfs(src.type)
var/list/turfs_trg = get_area_turfs(A.type)
var/src_min_x = 0
var/src_min_y = 0
for (var/turf/T in turfs_src)
if(T.x < src_min_x || !src_min_x) src_min_x = T.x
if(T.y < src_min_y || !src_min_y) src_min_y = T.y
var/trg_min_x = 0
var/trg_min_y = 0
for (var/turf/T in turfs_trg)
if(T.x < trg_min_x || !trg_min_x) trg_min_x = T.x
if(T.y < trg_min_y || !trg_min_y) trg_min_y = T.y
var/list/refined_src = new/list()
for(var/turf/T in turfs_src)
refined_src += T
refined_src[T] = new/datum/coords
var/datum/coords/C = refined_src[T]
C.x_pos = (T.x - src_min_x)
C.y_pos = (T.y - src_min_y)
var/list/refined_trg = new/list()
for(var/turf/T in turfs_trg)
refined_trg += T
refined_trg[T] = new/datum/coords
var/datum/coords/C = refined_trg[T]
C.x_pos = (T.x - trg_min_x)
C.y_pos = (T.y - trg_min_y)
var/list/fromupdate = new/list()
var/list/toupdate = new/list()
moving:
for (var/turf/T in refined_src)
var/datum/coords/C_src = refined_src[T]
for (var/turf/B in refined_trg)
var/datum/coords/C_trg = refined_trg[B]
if(C_src.x_pos == C_trg.x_pos && C_src.y_pos == C_trg.y_pos)
var/old_dir1 = T.dir
var/old_icon_state1 = T.icon_state
var/turf/X = new T.type(B)
X.dir = old_dir1
X.icon_state = old_icon_state1
for(var/obj/O in T)
if(!istype(O,/obj)) continue
O.loc = X
for(var/mob/M in T)
if(!istype(M,/mob)) continue
M.loc = X
var/area/AR = X.loc
if(AR.sd_lighting)
X.opacity = !X.opacity
X.sd_SetOpacity(!X.opacity)
toupdate += X
if(turftoleave)
var/turf/ttl = new turftoleave(T)
var/area/AR2 = ttl.loc
if(AR2.sd_lighting)
ttl.opacity = !ttl.opacity
ttl.sd_SetOpacity(!ttl.opacity)
fromupdate += ttl
else
T.ReplaceWithSpace()
refined_src -= T
refined_trg -= B
continue moving
var/list/doors = new/list()
if(toupdate.len)
for(var/turf/simulated/T1 in toupdate)
for(var/obj/machinery/door/D2 in T1)
doors += D2
if(T1.parent)
air_master.groups_to_rebuild += T1.parent
else
air_master.tiles_to_update += T1
if(fromupdate.len)
for(var/turf/simulated/T2 in fromupdate)
for(var/obj/machinery/door/D2 in T2)
doors += D2
if(T2.parent)
air_master.groups_to_rebuild += T2.parent
else
air_master.tiles_to_update += T2
for(var/obj/O in doors)
O:update_nearby_tiles(1)

View File

@@ -0,0 +1,194 @@
var/CMinutes = null
var/savefile/Banlist
/proc/CheckBan(var/client/clientvar)
var/id = clientvar.computer_id
var/key = clientvar.ckey
Banlist.cd = "/base"
if (Banlist.dir.Find("[key][id]"))
Banlist.cd = "[key][id]"
if (Banlist["temp"])
if (!GetExp(Banlist["minutes"]))
ClearTempbans()
return 0
else
return "[Banlist["reason"]]\n(This ban will be automatically removed in [GetExp(Banlist["minutes"])].)"
else
Banlist.cd = "/base/[key][id]"
return "[Banlist["reason"]]\n(This is a permanent ban)"
Banlist.cd = "/base"
for (var/A in Banlist.dir)
Banlist.cd = "/base/[A]"
if (id == Banlist["id"] || key == Banlist["key"])
if(Banlist["temp"])
if (!GetExp(Banlist["minutes"]))
ClearTempbans()
return 0
else
return "[Banlist["reason"]]\n(This ban will be automatically removed in [GetExp(Banlist["minutes"])].)"
else
return "[Banlist["reason"]]\n(This is a permanent ban)"
return 0
/proc/UpdateTime() //No idea why i made this a proc.
CMinutes = (world.realtime / 10) / 60
return 1
/proc/LoadBans()
Banlist = new("data/banlist.bdb")
log_admin("Loading Banlist")
if (!length(Banlist.dir)) log_admin("Banlist is empty.")
if (!Banlist.dir.Find("base"))
log_admin("Banlist missing base dir.")
Banlist.dir.Add("base")
Banlist.cd = "/base"
else if (Banlist.dir.Find("base"))
Banlist.cd = "/base"
ClearTempbans()
return 1
/proc/ClearTempbans()
UpdateTime()
Banlist.cd = "/base"
for (var/A in Banlist.dir)
Banlist.cd = "/base/[A]"
if (!Banlist["key"] || !Banlist["id"])
RemoveBan(A)
log_admin("Invalid Ban.")
message_admins("Invalid Ban.")
continue
if (!Banlist["temp"]) continue
if (CMinutes >= Banlist["minutes"]) RemoveBan(A)
return 1
/proc/AddBan(ckey, computerid, reason, bannedby, temp, minutes)
var/bantimestamp
if (temp)
UpdateTime()
bantimestamp = CMinutes + minutes
Banlist.cd = "/base"
if ( Banlist.dir.Find("[ckey][computerid]") )
usr << text("\red Ban already exists.")
return 0
else
Banlist.dir.Add("[ckey][computerid]")
Banlist.cd = "/base/[ckey][computerid]"
Banlist["key"] << ckey
Banlist["id"] << computerid
Banlist["reason"] << reason
Banlist["bannedby"] << bannedby
Banlist["temp"] << temp
if (temp)
Banlist["minutes"] << bantimestamp
return 1
/proc/RemoveBan(foldername)
var/key
var/id
Banlist.cd = "/base/[foldername]"
Banlist["key"] >> key
Banlist["id"] >> id
Banlist.cd = "/base"
if (!Banlist.dir.Remove(foldername)) return 0
if(!usr)
log_admin("Ban Expired: [key]")
message_admins("Ban Expired: [key]")
else
log_admin("[key_name_admin(usr)] unbanned [key]")
message_admins("[key_name_admin(usr)] unbanned: [key]")
for (var/A in Banlist.dir)
Banlist.cd = "/base/[A]"
if (key == Banlist["key"] || id == Banlist["id"])
Banlist.cd = "/base"
Banlist.dir.Remove(A)
continue
return 1
/proc/GetExp(minutes as num)
UpdateTime()
var/exp = minutes - CMinutes
if (exp <= 0)
return 0
else
var/timeleftstring
if (exp >= 1440) //1440 = 1 day in minutes
timeleftstring = "[round(exp / 1440, 0.1)] Days"
else if (exp >= 60) //60 = 1 hour in minutes
timeleftstring = "[round(exp / 60, 0.1)] Hours"
else
timeleftstring = "[exp] Minutes"
return timeleftstring
/obj/admins/proc/unbanpanel()
var/count = 0
var/dat
//var/dat = "<HR><B>Unban Player:</B> \blue(U) = Unban , (E) = Edit Ban\green (Total<HR><table border=1 rules=all frame=void cellspacing=0 cellpadding=3 >"
Banlist.cd = "/base"
for (var/A in Banlist.dir)
count++
Banlist.cd = "/base/[A]"
dat += text("<tr><td><A href='?src=\ref[src];unbanf=[Banlist["key"]][Banlist["id"]]'>(U)</A><A href='?src=\ref[src];unbane=[Banlist["key"]][Banlist["id"]]'>(E)</A> Key: <B>[Banlist["key"]]</B></td><td> ([Banlist["temp"] ? "[GetExp(Banlist["minutes"]) ? GetExp(Banlist["minutes"]) : "Removal pending" ]" : "Permaban"])</td><td>(By: [Banlist["bannedby"]])</td><td>(Reason: [Banlist["reason"]])</td></tr>")
dat += "</table>"
dat = "<HR><B>Bans:</B> <FONT COLOR=blue>(U) = Unban , (E) = Edit Ban</FONT> - <FONT COLOR=green>([count] Bans)</FONT><HR><table border=1 rules=all frame=void cellspacing=0 cellpadding=3 >[dat]"
usr << browse(dat, "window=unbanp;size=875x400")
//////////////////////////////////// DEBUG ////////////////////////////////////
/proc/CreateBans()
UpdateTime()
var/i
var/last
for(i=0, i<1001, i++)
var/a = pick(1,0)
var/b = pick(1,0)
if(b)
Banlist.cd = "/base"
Banlist.dir.Add("trash[i]trashid[i]")
Banlist.cd = "/base/trash[i]trashid[i]"
Banlist["key"] << "trash[i]"
else
Banlist.cd = "/base"
Banlist.dir.Add("[last]trashid[i]")
Banlist.cd = "/base/[last]trashid[i]"
Banlist["key"] << last
Banlist["id"] << "trashid[i]"
Banlist["reason"] << "Trashban[i]."
Banlist["temp"] << a
Banlist["minutes"] << CMinutes + rand(1,2000)
Banlist["bannedby"] << "trashmin"
last = "trash[i]"
Banlist.cd = "/base"
/proc/ClearAllBans()
Banlist.cd = "/base"
for (var/A in Banlist.dir)
RemoveBan(A)

View File

@@ -0,0 +1,263 @@
/proc/togglebuildmode(mob/M as mob in world)
if(M.client)
if(M.client.buildmode)
M.client.buildmode = 0
M.client.show_popup_menus = 1
for(var/obj/buildholder/H)
if(H.cl == M.client)
del(H)
else
M.client.buildmode = 1
M.client.show_popup_menus = 0
var/obj/buildholder/H = new/obj/buildholder()
var/obj/builddir/A = new/obj/builddir(H)
A.master = H
var/obj/buildhelp/B = new/obj/buildhelp(H)
B.master = H
var/obj/buildmode/C = new/obj/buildmode(H)
C.master = H
var/obj/buildquit/D = new/obj/buildquit(H)
D.master = H
H.builddir = A
H.buildhelp = B
H.buildmode = C
H.buildquit = D
M.client.screen += A
M.client.screen += B
M.client.screen += C
M.client.screen += D
H.cl = M.client
/obj/builddir
density = 1
anchored = 1
layer = 20
dir = NORTH
icon = 'buildmode.dmi'
icon_state = "build"
screen_loc = "NORTH,WEST"
var/obj/buildholder/master = null
/obj/buildhelp
density = 1
anchored = 1
layer = 20
dir = NORTH
icon = 'buildmode.dmi'
icon_state = "buildhelp"
screen_loc = "NORTH,WEST+1"
var/obj/buildholder/master = null
/obj/buildmode
density = 1
anchored = 1
layer = 20
dir = NORTH
icon = 'buildmode.dmi'
icon_state = "buildmode1"
screen_loc = "NORTH,WEST+2"
var/obj/buildholder/master = null
var/varholder = "name"
var/valueholder = "derp"
var/objholder = "/obj/closet"
/obj/buildquit
density = 1
anchored = 1
layer = 20
dir = NORTH
icon = 'buildmode.dmi'
icon_state = "buildquit"
screen_loc = "NORTH,WEST+3"
var/obj/buildholder/master = null
/obj/buildquit/Click()
togglebuildmode(master.cl.mob)
/obj/buildholder
density = 0
anchored = 1
var/client/cl = null
var/obj/builddir/builddir = null
var/obj/buildhelp/buildhelp = null
var/obj/buildmode/buildmode = null
var/obj/buildquit/buildquit = null
/obj/builddir/Click()
switch(dir)
if(NORTH)
dir = EAST
if(EAST)
dir = SOUTH
if(SOUTH)
dir = WEST
if(WEST)
dir = NORTHWEST
if(NORTHWEST)
dir = NORTH
/obj/buildhelp/Click()
switch(master.cl.buildmode)
if(1)
usr << "\blue ***********************************************************"
usr << "\blue Left Mouse Button = Construct / Upgrade"
usr << "\blue Right Mouse Button = Deconstruct / Delete / Downgrade"
usr << "\blue Left Mouse Button + ctrl = R-Window"
usr << "\blue Left Mouse Button + alt = Airlock"
usr << ""
usr << "\blue Use the button in the upper left corner to"
usr << "\blue change the direction of built objects."
usr << "\blue ***********************************************************"
if(2)
usr << "\blue ***********************************************************"
usr << "\blue Right Mouse Button on buildmode button = Set object type"
usr << "\blue Left Mouse Button on turf/obj = Place objects"
usr << "\blue Right Mouse Button = Delete objects"
usr << ""
usr << "\blue Use the button in the upper left corner to"
usr << "\blue change the direction of built objects."
usr << "\blue ***********************************************************"
if(3)
usr << "\blue ***********************************************************"
usr << "\blue Right Mouse Button on buildmode button = Select var(type) & value"
usr << "\blue Left Mouse Button on turf/obj/mob = Set var(type) & value"
usr << "\blue Right Mouse Button on turf/obj/mob = Reset var's value"
usr << "\blue ***********************************************************"
/obj/buildmode/Click(location, control, params)
var/list/pa = params2list(params)
if(pa.Find("left"))
switch(master.cl.buildmode)
if(1)
master.cl.buildmode = 2
src.icon_state = "buildmode2"
if(2)
master.cl.buildmode = 3
src.icon_state = "buildmode3"
if(3)
master.cl.buildmode = 1
src.icon_state = "buildmode1"
else if(pa.Find("right"))
switch(master.cl.buildmode)
if(1)
return
if(2)
objholder = input(usr,"Enter typepath:" ,"Typepath","/obj/closet")
var/list/removed_paths = list("/obj/bhole")
if(objholder in removed_paths)
alert("That path is not allowed.")
objholder = "/obj/closet"
else if (dd_hasprefix(objholder, "/mob") && !(usr.client.holder.rank in list("Host", "Coder", "Shit Guy")))
objholder = "/obj/closet"
if(3)
var/list/locked = list("vars", "key", "ckey", "client", "firemut", "ishulk", "telekinesis", "xray", "virus", "cuffed", "ka", "last_eaten", "urine")
master.buildmode.varholder = input(usr,"Enter variable name:" ,"Name", "name")
if(master.buildmode.varholder in locked && !(usr.client.holder.rank in list("Host", "Coder")))
return
var/thetype = input(usr,"Select variable type:" ,"Type") in list("text","number","mob-reference","obj-reference","turf-reference")
if(!thetype) return
switch(thetype)
if("text")
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value", "value") as text
if("number")
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value", 123) as num
if("mob-reference")
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as mob in world
if("obj-reference")
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as obj in world
if("turf-reference")
master.buildmode.valueholder = input(usr,"Enter variable value:" ,"Value") as turf in world
/proc/build_click(var/mob/user, buildmode, location, control, params, var/obj/object)
var/obj/buildholder/holder = null
for(var/obj/buildholder/H)
if(H.cl == user.client)
holder = H
break
if(!holder) return
var/list/pa = params2list(params)
switch(buildmode)
if(1)
if(istype(object,/turf) && pa.Find("left") && !pa.Find("alt") && !pa.Find("ctrl") )
if(istype(object,/turf/space))
var/turf/T = object
T.ReplaceWithFloor()
return
else if(istype(object,/turf/simulated/floor))
var/turf/T = object
T.ReplaceWithWall()
return
else if(istype(object,/turf/simulated/wall))
var/turf/T = object
T.ReplaceWithRWall()
return
else if(pa.Find("right"))
if(istype(object,/turf/simulated/wall))
var/turf/T = object
T.ReplaceWithFloor()
return
else if(istype(object,/turf/simulated/floor))
var/turf/T = object
T.ReplaceWithSpace()
return
else if(istype(object,/turf/simulated/wall/r_wall))
var/turf/T = object
T.ReplaceWithWall()
return
else if(istype(object,/obj))
del(object)
return
else if(istype(object,/turf) && pa.Find("alt") && pa.Find("left"))
new/obj/machinery/door/airlock(get_turf(object))
else if(istype(object,/turf) && pa.Find("ctrl") && pa.Find("left"))
switch(holder.builddir.dir)
if(NORTH)
new/obj/window/reinforced/north(get_turf(object))
if(EAST)
new/obj/window/reinforced/east(get_turf(object))
if(SOUTH)
new/obj/window/reinforced/south(get_turf(object))
if(WEST)
new/obj/window/reinforced/west(get_turf(object))
if(NORTHWEST)
new/obj/window/reinforced/northwest(get_turf(object))
if(2)
if(pa.Find("left"))
var/obj/A = new holder.buildmode.objholder (get_turf(object))
A.dir = holder.builddir.dir
blink(A)
else if(pa.Find("right"))
if(isobj(object)) del(object)
if(3)
if(pa.Find("left")) //I cant believe this shit actually compiles.
if(object.vars.Find(holder.buildmode.varholder))
log_admin("[key_name(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]")
// message_admins("[key_name_admin(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]", 1)
object.vars[holder.buildmode.varholder] = holder.buildmode.valueholder
blink(object)
else
usr << "\red [initial(object.name)] does not have a var called '[holder.buildmode.varholder]'"
if(pa.Find("right"))
if(object.vars.Find(holder.buildmode.varholder))
log_admin("[key_name(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]")
// message_admins("[key_name_admin(usr)] modified [object.name]'s [holder.buildmode.varholder] to [holder.buildmode.valueholder]", 1)
object.vars[holder.buildmode.varholder] = initial(object.vars[holder.buildmode.varholder])
blink(object)
else
usr << "\red [initial(object.name)] does not have a var called '[holder.buildmode.varholder]'"
/proc/blink(atom/A)
A.icon += rgb(0,75,75)
spawn(10) A.icon = initial(A.icon)

View File

@@ -0,0 +1,724 @@
//Cloning revival method.
//The pod handles the actual cloning while the computer manages the clone profiles
//Potential replacement for genetics revives or something I dunno (?)
/obj/machinery/clonepod
anchored = 1
name = "cloning pod"
desc = "An electronically-lockable pod for growing organic tissue."
density = 1
icon = 'cloning.dmi'
icon_state = "pod_0"
req_access = list(access_medlab) //For premature unlocking.
var/mob/living/occupant
var/heal_level = 90 //The clone is released once its health reaches this level.
var/locked = 0
var/obj/machinery/computer/cloning/connected = null //So we remember the connected clone machine.
var/mess = 0 //Need to clean out it if it's full of exploded clone.
var/attempting = 0 //One clone attempt at a time thanks
var/eject_wait = 0 //Don't eject them as soon as they are created fuckkk
/obj/machinery/computer/cloning
name = "Cloning console"
icon = 'computer.dmi'
icon_state = "dna"
req_access = list(access_heads) //Only used for record deletion right now.
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/obj/machinery/clonepod/pod1 = null //Linked cloning pod.
var/temp = "Initializing System..."
var/menu = 1 //Which menu screen to display
var/list/records = list()
var/datum/data/record/active_record = null
var/obj/item/weapon/disk/data/diskette = null //Mostly so the geneticist can steal everything.
//The return of data disks?? Just for transferring between genetics machine/cloning machine.
//TO-DO: Make the genetics machine accept them.
/obj/item/weapon/disk/data
name = "data disk"
icon = 'cloning.dmi'
icon_state = "datadisk0" //Gosh I hope syndies don't mistake them for the nuke disk.
item_state = "card-id"
w_class = 1.0
var/data = ""
var/ue = 0
var/data_type = "ui" //ui|se
var/owner = "God Emperor of Mankind"
var/read_only = 0 //Well,it's still a floppy disk
/obj/item/weapon/disk/data/demo
name = "data disk - 'God Emperor of Mankind'"
data = "066000033000000000AF00330660FF4DB002690"
//data = "0C80C80C80C80C80C8000000000000161FBDDEF" - Farmer Jeff
ue = 1
read_only = 1
/obj/item/weapon/disk/data/monkey
name = "data disk - 'Mr. Muggles'"
data_type = "se"
data = "0983E840344C39F4B059D5145FC5785DC6406A4FFF"
read_only = 1
/obj/machinery/computer/cloning/New()
..()
spawn(5)
src.scanner = locate(/obj/machinery/dna_scannernew, get_step(src, WEST))
src.pod1 = locate(/obj/machinery/clonepod, get_step(src, EAST))
src.temp = ""
if (isnull(src.scanner))
src.temp += " <font color=red>SCNR-ERROR</font>"
if (isnull(src.pod1))
src.temp += " <font color=red>POD1-ERROR</font>"
else
src.pod1.connected = src
if (src.temp == "")
src.temp = "System ready."
return
return
/obj/machinery/computer/cloning/attackby(obj/item/W as obj, mob/user as mob)
if (istype(W, /obj/item/weapon/disk/data)) //INSERT SOME DISKETTES
if (!src.diskette)
user.drop_item()
W.loc = src
src.diskette = W
user << "You insert [W]."
src.updateUsrDialog()
return
else if((istype(W, /obj/item/weapon/screwdriver)) && (src.stat & BROKEN))
playsound(src.loc, 'Screwdriver.ogg', 50, 1)
if(do_after(user, 20))
user << "\blue The broken glass falls out."
var/obj/computerframe/A = new /obj/computerframe( src.loc )
new /obj/item/weapon/shard( src.loc )
var/obj/item/weapon/circuitboard/cloning/M = new /obj/item/weapon/circuitboard/cloning( A )
for (var/obj/C in src)
C.loc = src.loc
M.records = src.records
A.circuit = M
A.state = 3
A.icon_state = "3"
A.anchored = 1
del(src)
else
src.attack_hand(user)
return
/obj/machinery/computer/cloning/attack_paw(mob/user as mob)
return attack_hand(user)
/obj/machinery/computer/cloning/attack_ai(mob/user as mob)
return attack_hand(user)
/obj/machinery/computer/cloning/attack_hand(mob/user as mob)
user.machine = src
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
var/dat = "<h3>Cloning System Control</h3>"
dat += "<font size=-1><a href='byond://?src=\ref[src];refresh=1'>Refresh</a></font>"
dat += "<br><tt>[temp]</tt><br>"
switch(src.menu)
if(1)
dat += "<h4>Scanner Functions</h4>"
if (isnull(src.scanner))
dat += "No scanner connected!"
else
if (src.scanner.occupant)
dat += "<a href='byond://?src=\ref[src];scan=1'>Scan - [src.scanner.occupant]</a>"
else
dat += "Scanner unoccupied"
dat += "<br>Lock status: <a href='byond://?src=\ref[src];lock=1'>[src.scanner.locked ? "Locked" : "Unlocked"]</a>"
dat += "<h4>Database Functions</h4>"
dat += "<a href='byond://?src=\ref[src];menu=2'>View Records</a><br>"
if (src.diskette)
dat += "<a href='byond://?src=\ref[src];disk=eject'>Eject Disk</a>"
if(2)
dat += "<h4>Current records</h4>"
dat += "<a href='byond://?src=\ref[src];menu=1'>Back</a><br><br>"
for(var/datum/data/record/R in src.records)
dat += "<a href='byond://?src=\ref[src];view_rec=\ref[R]'>[R.fields["id"]]-[R.fields["name"]]</a><br>"
if(3)
dat += "<h4>Selected Record</h4>"
dat += "<a href='byond://?src=\ref[src];menu=2'>Back</a><br>"
if (!src.active_record)
dat += "<font color=red>ERROR: Record not found.</font>"
else
dat += "<br><font size=1><a href='byond://?src=\ref[src];del_rec=1'>Delete Record</a></font><br>"
dat += "<b>Name:</b> [src.active_record.fields["name"]]<br>"
var/obj/item/weapon/implant/health/H = locate(src.active_record.fields["imp"])
if ((H) && (istype(H)))
dat += "<b>Health:</b> [H.sensehealth()] | OXY-BURN-TOX-BRUTE<br>"
else
dat += "<font color=red>Unable to locate implant.</font><br>"
if (!isnull(src.diskette))
dat += "<a href='byond://?src=\ref[src];disk=load'>Load from disk.</a>"
dat += " | Save: <a href='byond://?src=\ref[src];save_disk=ue'>UI + UE</a>"
dat += " | Save: <a href='byond://?src=\ref[src];save_disk=ui'>UI</a>"
dat += " | Save: <a href='byond://?src=\ref[src];save_disk=se'>SE</a>"
dat += "<br>"
else
dat += "<br>" //Keeping a line empty for appearances I guess.
dat += {"<b>UI:</b> [src.active_record.fields["UI"]]<br>
<b>SE:</b> [src.active_record.fields["SE"]]<br><br>
<a href='byond://?src=\ref[src];clone=\ref[src.active_record]'>Clone</a><br>"}
if(4)
if (!src.active_record)
src.menu = 2
dat = "[src.temp]<br>"
dat += "<h4>Confirm Record Deletion</h4>"
dat += "<b><a href='byond://?src=\ref[src];del_rec=1'>Scan card to confirm.</a></b><br>"
dat += "<b><a href='byond://?src=\ref[src];menu=3'>No</a></b>"
user << browse(dat, "window=cloning")
onclose(user, "cloning")
return
/obj/machinery/computer/cloning/Topic(href, href_list)
if(..())
return
if ((href_list["scan"]) && (!isnull(src.scanner)))
src.scan_mob(src.scanner.occupant)
//No locking an open scanner.
else if ((href_list["lock"]) && (!isnull(src.scanner)))
if ((!src.scanner.locked) && (src.scanner.occupant))
src.scanner.locked = 1
else
src.scanner.locked = 0
else if (href_list["view_rec"])
src.active_record = locate(href_list["view_rec"])
if ((isnull(src.active_record.fields["ckey"])) || (src.active_record.fields["ckey"] == ""))
del(src.active_record)
src.temp = "ERROR: Record Corrupt"
else
src.menu = 3
else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3))
return
if (src.menu == 3) //If we are viewing a record, confirm deletion
src.temp = "Delete record?"
src.menu = 4
else if (src.menu == 4)
var/obj/item/weapon/card/id/C = usr.equipped()
if (istype(C))
if(src.check_access(C))
src.records.Remove(src.active_record)
del(src.active_record)
src.temp = "Record deleted."
src.menu = 2
else
src.temp = "Access Denied."
else if (href_list["disk"]) //Load or eject.
switch(href_list["disk"])
if("load")
if ((isnull(src.diskette)) || (src.diskette.data == ""))
src.temp = "Load error."
src.updateUsrDialog()
return
if (isnull(src.active_record))
src.temp = "Record error."
src.menu = 1
src.updateUsrDialog()
return
if (src.diskette.data_type == "ui")
src.active_record.fields["UI"] = src.diskette.data
if (src.diskette.ue)
src.active_record.fields["name"] = src.diskette.owner
else if (src.diskette.data_type == "se")
src.active_record.fields["SE"] = src.diskette.data
src.temp = "Load successful."
if("eject")
if (!isnull(src.diskette))
src.diskette.loc = src.loc
src.diskette = null
else if (href_list["save_disk"]) //Save to disk!
if ((isnull(src.diskette)) || (src.diskette.read_only) || (isnull(src.active_record)))
src.temp = "Save error."
src.updateUsrDialog()
return
switch(href_list["save_disk"]) //Save as Ui/Ui+Ue/Se
if("ui")
src.diskette.data = src.active_record.fields["UI"]
src.diskette.ue = 0
src.diskette.data_type = "ui"
if("ue")
src.diskette.data = src.active_record.fields["UI"]
src.diskette.ue = 1
src.diskette.data_type = "ui"
if("se")
src.diskette.data = src.active_record.fields["SE"]
src.diskette.ue = 0
src.diskette.data_type = "se"
src.diskette.owner = src.active_record.fields["name"]
src.diskette.name = "data disk - '[src.diskette.owner]'"
src.temp = "Save \[[href_list["save_disk"]]\] successful."
else if (href_list["refresh"])
src.updateUsrDialog()
else if (href_list["clone"])
var/datum/data/record/C = locate(href_list["clone"])
//Look for that player! They better be dead!
var/mob/selected = find_dead_player("[C.fields["ckey"]]")
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if ((!selected) || (!src.pod1) || (src.pod1.occupant) || (src.pod1.mess))
src.temp = "Unable to initiate cloning cycle." // most helpful error message in THE HISTORY OF THE WORLD
else if (src.pod1.growclone(selected, C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"]))
src.temp = "Cloning cycle activated."
src.records.Remove(C)
del(C)
src.menu = 1
else if (href_list["menu"])
src.menu = text2num(href_list["menu"])
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/obj/machinery/computer/cloning/proc/scan_mob(mob/living/carbon/human/subject as mob)
if ((isnull(subject)) || (!istype(subject, /mob/living/carbon/human)) || (!subject.dna))
src.temp = "Error: Unable to locate valid genetic data."
return
if ((!subject.ckey) || (!subject.client))
src.temp = "Error: Mental interface failure."
return
if (!isnull(find_record(subject.ckey)))
src.temp = "Subject already in database."
return
subject.dna.check_integrity()
var/datum/data/record/R = new /datum/data/record( )
R.fields["ckey"] = subject.ckey
R.fields["name"] = subject.real_name
R.fields["id"] = copytext(md5(subject.real_name), 2, 6)
R.fields["UI"] = subject.dna.uni_identity
R.fields["SE"] = subject.dna.struc_enzymes
//Add an implant if needed
var/obj/item/weapon/implant/health/imp =locate(/obj/item/weapon/implant/health, subject)
if (isnull(imp))
imp = new /obj/item/weapon/implant/health(subject)
imp.implanted = subject
R.fields["imp"] = "\ref[imp]"
//Update it if needed
else
R.fields["imp"] = "\ref[imp]"
if (!isnull(subject.mind)) //Save that mind so traitors can continue traitoring after cloning.
R.fields["mind"] = "\ref[subject.mind]"
src.records += R
src.temp = "Subject successfully scanned."
//Find a specific record by key.
/obj/machinery/computer/cloning/proc/find_record(var/find_key)
var/selected_record = null
for(var/datum/data/record/R in src.records)
if (R.fields["ckey"] == find_key)
selected_record = R
break
return selected_record
/obj/machinery/computer/cloning/power_change()
if(stat & BROKEN)
icon_state = "commb"
else
if( powered() )
icon_state = initial(icon_state)
stat &= ~NOPOWER
else
spawn(rand(0, 15))
src.icon_state = "c_unpowered"
stat |= NOPOWER
//Find a dead mob with a brain and client.
/proc/find_dead_player(var/find_key)
if (isnull(find_key))
return
var/mob/selected = null
for(var/mob/M in world)
//Dead people only thanks!
if ((M.stat != 2) || (!M.client))
continue
//They need a brain!
if ((istype(M, /mob/living/carbon/human)) && (M:brain_op_stage >= 4.0))
continue
if (M.ckey == find_key)
selected = M
break
return selected
//Disk stuff.
/obj/item/weapon/disk/data/New()
..()
var/diskcolor = pick(0,1,2)
src.icon_state = "datadisk[diskcolor]"
/obj/item/weapon/disk/data/attack_self(mob/user as mob)
src.read_only = !src.read_only
user << "You flip the write-protect tab to [src.read_only ? "protected" : "unprotected"]."
/obj/item/weapon/disk/data/examine()
set src in oview(5)
..()
usr << text("The write-protect tab is set to [src.read_only ? "protected" : "unprotected"].")
return
//Health Tracker Implant
/obj/item/weapon/implant/health
name = "health implant"
var/healthstring = ""
/obj/item/weapon/implant/health/proc/sensehealth()
if (!src.implanted)
return "ERROR"
else
src.healthstring = "[round(src.implanted:oxyloss)] - [round(src.implanted:fireloss)] - [round(src.implanted:toxloss)] - [round(src.implanted:bruteloss)]"
if (!src.healthstring)
src.healthstring = "ERROR"
return src.healthstring
/obj/machinery/clonepod/attack_ai(mob/user as mob)
return attack_hand(user)
/obj/machinery/clonepod/attack_paw(mob/user as mob)
return attack_hand(user)
/obj/machinery/clonepod/attack_hand(mob/user as mob)
if ((isnull(src.occupant)) || (stat & NOPOWER))
return
if ((!isnull(src.occupant)) && (src.occupant.stat != 2))
var/completion = (100 * ((src.occupant.health + 100) / (src.heal_level + 100)))
user << "Current clone cycle is [round(completion)]% complete."
return
//Clonepod
//Start growing a human clone in the pod!
/obj/machinery/clonepod/proc/growclone(mob/ghost as mob, var/clonename, var/ui, var/se, var/mindref)
if (((!ghost) || (!ghost.client)) || src.mess || src.attempting)
return 0
src.attempting = 1 //One at a time!!
src.locked = 1
src.eject_wait = 1
spawn(30)
src.eject_wait = 0
src.occupant = new /mob/living/carbon/human(src)
ghost.client.mob = src.occupant
src.icon_state = "pod_1"
//Get the clone body ready
src.occupant.rejuv = 10
src.occupant.bruteloss += 90
src.occupant.toxloss += 50
src.occupant.oxyloss += 40
src.occupant.brainloss += 90
src.occupant.paralysis += 4
//Here let's calculate their health so the pod doesn't immediately eject them!!!
src.occupant.health = (src.occupant.bruteloss + src.occupant.toxloss + src.occupant.oxyloss)
src.occupant << "\blue <b>Clone generation process initiated.</b>"
src.occupant << "\blue This will take a moment, please hold."
if (clonename)
src.occupant.real_name = clonename
else
src.occupant.real_name = "clone" //No null names!!
var/datum/mind/clonemind = (locate(mindref) in ticker.minds)
if ((clonemind) && (istype(clonemind))) //Move that mind over!!
clonemind.transfer_to(src.occupant)
else //welp
src.occupant.mind = new /datum/mind( )
src.occupant.mind.key = src.occupant.key
src.occupant.mind.current = src.occupant
src.occupant.mind.transfer_to(src.occupant)
ticker.minds += src.occupant.mind
// -- Mode/mind specific stuff goes here
switch(ticker.mode.name)
if ("revolution")
if ((src.occupant.mind in ticker.mode:revolutionaries) || (src.occupant.mind in ticker.mode:head_revolutionaries))
ticker.mode:add_revolutionary(src.occupant.mind)
ticker.mode:update_all_rev_icons() //So the icon actually appears
// -- End mode specific stuff
if (istype(ghost, /mob/dead/observer))
del(ghost) //Don't leave ghosts everywhere!!
if (!src.occupant.dna)
src.occupant.dna = new /datum/dna( )
if (ui)
src.occupant.dna.uni_identity = ui
updateappearance(src.occupant, ui)
if (se)
src.occupant.dna.struc_enzymes = se
randmutb(src.occupant) //Sometimes the clones come out wrong.
src.attempting = 0
return 1
//Grow clones to maturity then kick them out. FREELOADERS
/obj/machinery/clonepod/process()
if (stat & NOPOWER) //Autoeject if power is lost
if (src.occupant)
src.locked = 0
src.go_out()
return
if ((src.occupant) && (src.occupant.loc == src))
if((src.occupant.stat == 2) || (src.occupant.suiciding)) //Autoeject corpses and suiciding dudes.
src.locked = 0
src.go_out()
src.connected_message("Clone Rejected: Deceased.")
return
else if(src.occupant.health < src.heal_level)
src.occupant.paralysis = 4
//Slowly get that clone healed and finished.
src.occupant.bruteloss = max(src.occupant.bruteloss-1, 0)
//At this rate one clone takes about 95 seconds to produce.(with heal_level 90)
src.occupant.toxloss = max(src.occupant.toxloss-0.5, 0)
//Premature clones may have brain damage.
src.occupant.brainloss = max(src.occupant.brainloss-1, 0)
//So clones don't die of oxyloss in a running pod.
if (src.occupant.reagents.get_reagent_amount("inaprovaline") < 30)
src.occupant.reagents.add_reagent("inaprovaline", 60)
//Also heal some oxyloss ourselves because inaprovaline is so bad at preventing it!!
src.occupant.oxyloss = max(src.occupant.oxyloss-2, 0)
//Stop baking in the tubes you jerks.
src.occupant.fireloss = max(src.occupant.fireloss-2, 0)
use_power(7500) //This might need tweaking.
return
else if((src.occupant.health >= src.heal_level) && (!src.eject_wait))
src.connected_message("Cloning Process Complete.")
src.locked = 0
src.go_out()
return
else if ((!src.occupant) || (src.occupant.loc != src))
src.occupant = null
if (src.locked)
src.locked = 0
if (!src.mess)
icon_state = "pod_0"
use_power(200)
return
return
//Let's unlock this early I guess. Might be too early, needs tweaking.
/obj/machinery/clonepod/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (istype(W, /obj/item/weapon/card/id))
if (!src.check_access(W))
user << "\red Access Denied."
return
if ((!src.locked) || (isnull(src.occupant)))
return
if ((src.occupant.health < -20) && (src.occupant.stat != 2))
user << "\red Access Refused."
return
else
src.locked = 0
user << "System unlocked."
else if (istype(W, /obj/item/weapon/card/emag))
if (isnull(src.occupant))
return
user << "You force an emergency ejection."
src.locked = 0
src.go_out()
return
else
..()
//Put messages in the connected computer's temp var for display.
/obj/machinery/clonepod/proc/connected_message(var/message)
if ((isnull(src.connected)) || (!istype(src.connected, /obj/machinery/computer/cloning)))
return 0
if (!message)
return 0
src.connected.temp = message
src.connected.updateUsrDialog()
return 1
/obj/machinery/clonepod/verb/eject()
set src in oview(1)
if (usr.stat != 0)
return
src.go_out()
add_fingerprint(usr)
return
/obj/machinery/clonepod/proc/go_out()
if (src.locked)
return
if (src.mess) //Clean that mess and dump those gibs!
src.mess = 0
gibs(src.loc)
src.icon_state = "pod_0"
for(var/obj/O in src)
O.loc = src.loc
return
if (!(src.occupant))
return
for(var/obj/O in src)
O.loc = src.loc
if (src.occupant.client)
src.occupant.client.eye = src.occupant.client.mob
src.occupant.client.perspective = MOB_PERSPECTIVE
src.occupant.loc = src.loc
src.icon_state = "pod_0"
src.eject_wait = 0 //If it's still set somehow.
domutcheck(src.occupant) //Waiting until they're out before possible monkeyizing.
src.occupant = null
return
/obj/machinery/clonepod/proc/malfunction()
if (src.occupant)
src.connected_message("Critical Error!")
src.mess = 1
src.icon_state = "pod_g"
src.occupant.ghostize()
spawn(5)
del(src.occupant)
return
/obj/machinery/clonepod/relaymove(mob/user as mob)
if (user.stat)
return
src.go_out()
return
/obj/machinery/clonepod/ex_act(severity)
switch(severity)
if(1.0)
for(var/atom/movable/A as mob|obj in src)
A.loc = src.loc
ex_act(severity)
del(src)
return
if(2.0)
if (prob(50))
for(var/atom/movable/A as mob|obj in src)
A.loc = src.loc
ex_act(severity)
del(src)
return
if(3.0)
if (prob(25))
for(var/atom/movable/A as mob|obj in src)
A.loc = src.loc
ex_act(severity)
del(src)
return
else
return
/*
* Diskette Box
*/
/obj/item/weapon/storage/diskbox
name = "Diskette Box"
icon_state = "disk_kit"
item_state = "syringe_kit"
/obj/item/weapon/storage/diskbox/New()
..()
new /obj/item/weapon/disk/data(src)
new /obj/item/weapon/disk/data(src)
new /obj/item/weapon/disk/data(src)
new /obj/item/weapon/disk/data(src)
new /obj/item/weapon/disk/data(src)
new /obj/item/weapon/disk/data(src)
new /obj/item/weapon/disk/data(src)
/*
* Manual -- A big ol' manual.
*/
/obj/item/weapon/paper/Cloning
name = "paper - 'H-87 Cloning Apparatus Manual"
info = {"<h4>Getting Started</h4>
Congratulations, your station has purchased the H-87 industrial cloning device!<br>
Using the H-87 is almost as simple as brain surgery! Simply insert the target humanoid into the scanning chamber and select the scan option to create a new profile!<br>
<b>That's all there is to it!</b><br>
<i>Notice, cloning system cannot scan inorganic life or small primates. Scan may fail if subject has suffered extreme brain damage.</i><br>
<p>Clone profiles may be viewed through the profiles menu. Scanning implants a complementary HEALTH MONITOR IMPLANT into the subject, which may be viewed from each profile.
Profile Deletion has been restricted to \[Station Head\] level access.</p>
<h4>Cloning from a profile</h4>
Cloning is as simple as pressing the CLONE option at the bottom of the desired profile.<br>
Per your company's EMPLOYEE PRIVACY RIGHTS agreement, the H-87 has been blocked from cloning crewmembers while they are still alive.<br>
<br>
<p>The provided CLONEPOD SYSTEM will produce the desired clone. Standard clone maturation times (With SPEEDCLONE technology) are roughly 90 seconds.
The cloning pod may be unlocked early with any \[Medical Researcher\] ID after initial maturation is complete.</p><br>
<i>Please note that resulting clones may have a small DEVELOPMENTAL DEFECT as a result of genetic drift.</i><br>
<h4>Profile Management</h4>
<p>The H-87 (as well as your station's standard genetics machine) can accept STANDARD DATA DISKETTES.
These diskettes are used to transfer genetic information between machines and profiles.
A load/save dialog will become available in each profile if a disk is inserted.</p><br>
<i>A good diskette is a great way to counter aforementioned genetic drift!</i><br>
<br>
<font size=1>This technology produced under license from Thinktronic Systems, LTD.</font>"}
//SOME SCRAPS I GUESS
/* EMP grenade/spell effect
if(istype(A, /obj/machinery/clonepod))
A:malfunction()
*/

View File

@@ -0,0 +1,60 @@
/datum/computer/file/computer_program/airlock_control
name = "Airlock Master"
size = 16.0
id_tag = "TAG"
return_text()
if(..())
return
var/dat = "<a href='byond://?src=\ref[src];close=1'>Close</a> | "
dat += "<a href='byond://?src=\ref[src];quit=1'>Quit</a>"
/*
dat += "<br><TT>Frequency: "
dat += "<a href='?src=\ref[src];adj_freq=-10'>--</a> "
dat += "<a href='?src=\ref[src];adj_freq=-2'>-</a> "
dat += "[format_frequency(src.master.frequency)] "
dat += "<a href='?src=\ref[src];adj_freq=2'>+</a> "
dat += "<a href='?src=\ref[src];adj_freq=10'>++</a>"
dat += "</TT><br>"
*/
dat += "<br>ID:<a href='byond://?src=\ref[src];set_tag=1'>[src.id_tag]</a><br>"
dat += "<a href='byond://?src=\ref[src];send_command=cycle'>Cycle</a>"
dat += "</b></center>"
return dat
Topic(href, href_list)
if(..())
return
if(href_list["set_tag"])
var/t = input(usr, "Please enter new tag", src.id_tag, null) as text
t = copytext(sanitize(t), 1, MAX_MESSAGE_LEN)
if (!t)
return
if (!in_range(src.master, usr))
return
src.id_tag = t
// if(href_list["adj_freq"])
// var/new_frequency = (src.master.frequency + text2num(href_list["adj_freq"]))
// src.master.set_frequency(new_frequency)
if(href_list["send_command"])
var/datum/signal/signal = new
signal.data["tag"] = id_tag
signal.data["command"] = href_list["send_command"]
peripheral_command("send signal", signal)
src.master.add_fingerprint(usr)
src.master.updateUsrDialog()
return

View File

@@ -0,0 +1,136 @@
/datum/computer/file/computer_program/arcade
name = "Arcade 500"
size = 8.0
var/enemy_name = "Space Villian"
var/temp = "Winners Don't Use Spacedrugs" //Temporary message, for attack messages, etc
var/player_hp = 30 //Player health/attack points
var/player_mp = 10
var/enemy_hp = 45 //Enemy health/attack points
var/enemy_mp = 20
var/gameover = 0
var/blocked = 0 //Player cannot attack/heal while set
New(obj/holding as obj)
if(holding)
src.holder = holding
if(istype(src.holder.loc,/obj/machinery/computer2))
src.master = src.holder.loc
// var/name_action = pick("Defeat ", "Annihilate ", "Save ", "Strike ", "Stop ", "Destroy ", "Robust ", "Romance ")
var/name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Evil ", "the Dread King ", "the Space ", "Lord ")
var/name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon")
src.enemy_name = dd_replacetext((name_part1 + name_part2), "the ", "")
// src.name = (name_action + name_part1 + name_part2)
/datum/computer/file/computer_program/arcade/return_text()
if(..())
return
var/dat = "<a href='byond://?src=\ref[src];close=1'>Close</a> | "
dat += "<a href='byond://?src=\ref[src];quit=1'>Quit</a>"
dat += "<center><h4>[src.enemy_name]</h4></center>"
dat += "<br><center><h3>[src.temp]</h3></center>"
dat += "<br><center>Health: [src.player_hp] | Magic: [src.player_mp] | Enemy Health: [src.enemy_hp]</center>"
if (src.gameover)
dat += "<center><b><a href='byond://?src=\ref[src];newgame=1'>New Game</a>"
else
dat += "<center><b><a href='byond://?src=\ref[src];attack=1'>Attack</a> | "
dat += "<a href='byond://?src=\ref[src];heal=1'>Heal</a> | "
dat += "<a href='byond://?src=\ref[src];charge=1'>Recharge Power</a>"
dat += "</b></center>"
return dat
/datum/computer/file/computer_program/arcade/Topic(href, href_list)
if(..())
return
if (!src.blocked)
if (href_list["attack"])
src.blocked = 1
var/attackamt = rand(2,6)
src.temp = "You attack for [attackamt] damage!"
src.master.updateUsrDialog()
sleep(10)
src.enemy_hp -= attackamt
src.arcade_action()
else if (href_list["heal"])
src.blocked = 1
var/pointamt = rand(1,3)
var/healamt = rand(6,8)
src.temp = "You use [pointamt] magic to heal for [healamt] damage!"
src.master.updateUsrDialog()
sleep(10)
src.player_mp -= pointamt
src.player_hp += healamt
src.blocked = 1
src.master.updateUsrDialog()
src.arcade_action()
else if (href_list["charge"])
src.blocked = 1
var/chargeamt = rand(4,7)
src.temp = "You regain [chargeamt] points"
src.player_mp += chargeamt
src.master.updateUsrDialog()
sleep(10)
src.arcade_action()
if (href_list["newgame"]) //Reset everything
temp = "New Round"
player_hp = 30
player_mp = 10
enemy_hp = 45
enemy_mp = 20
gameover = 0
src.master.add_fingerprint(usr)
src.master.updateUsrDialog()
return
/datum/computer/file/computer_program/arcade/proc/arcade_action()
if ((src.enemy_mp <= 0) || (src.enemy_hp <= 0))
src.gameover = 1
src.temp = "[src.enemy_name] has fallen! Rejoice!"
src.peripheral_command("vend prize")
else if ((src.enemy_mp <= 5) && (prob(70)))
var/stealamt = rand(2,3)
src.temp = "[src.enemy_name] steals [stealamt] of your power!"
src.player_mp -= stealamt
src.master.updateUsrDialog()
if (src.player_mp <= 0)
src.gameover = 1
sleep(10)
src.temp = "You have been drained! GAME OVER"
else if ((src.enemy_hp <= 10) && (src.enemy_mp > 4))
src.temp = "[src.enemy_name] heals for 4 health!"
src.enemy_hp += 4
src.enemy_mp -= 4
else
var/attackamt = rand(3,6)
src.temp = "[src.enemy_name] attacks for [attackamt] damage!"
src.player_hp -= attackamt
if ((src.player_mp <= 0) || (src.player_hp <= 0))
src.gameover = 1
src.temp = "You have been crushed! GAME OVER"
src.blocked = 0
return

View File

@@ -0,0 +1,263 @@
/datum/computer
var/size = 4.0
var/obj/item/weapon/disk/data/holder = null
var/datum/computer/folder/holding_folder = null
folder
name = "Folder"
size = 0.0
var/gen = 0
Del()
for(var/datum/computer/F in src.contents)
del(F)
..()
proc
add_file(datum/computer/R)
if(!holder || holder.read_only || !R)
return 0
if(istype(R,/datum/computer/folder) && (src.gen>=10))
return 0
if((holder.file_used + R.size) <= holder.file_amount)
src.contents.Add(R)
R.holder = holder
R.holding_folder = src
src.holder.file_used -= src.size
src.size += R.size
src.holder.file_used += src.size
if(istype(R,/datum/computer/folder))
R:gen = (src.gen+1)
return 1
return 0
remove_file(datum/computer/R)
if(holder && !holder.read_only || !R)
// world << "Removing file [R]. File_used: [src.holder.file_used]"
src.contents.Remove(R)
src.holder.file_used -= src.size
src.size -= R.size
src.holder.file_used += src.size
src.holder.file_used = max(src.holder.file_used, 0)
// world << "Removed file [R]. File_used: [src.holder.file_used]"
return 1
return 0
file
name = "File"
var/extension = "FILE" //Differentiate between types of files, why not
proc
copy_file_to_folder(datum/computer/folder/newfolder)
if(!newfolder || (!istype(newfolder)) || (!newfolder.holder) || (newfolder.holder.read_only))
return 0
if((newfolder.holder.file_used + src.size) <= newfolder.holder.file_amount)
var/datum/computer/file/newfile = new src.type
for(var/V in src.vars)
if (issaved(src.vars[V]) && V != "holder")
newfile.vars[V] = src.vars[V]
if(!newfolder.add_file(newfile))
del(newfile)
return 1
return 0
Del()
if(holder && holding_folder)
holding_folder.remove_file(src)
..()
/datum/computer/file/computer_program
name = "blank program"
extension = "PROG"
//var/size = 4.0
//var/obj/item/weapon/disk/data/holder = null
var/obj/machinery/computer2/master = null
var/active_icon = null
var/id_tag = null
var/list/req_access = list()
New(obj/holding as obj)
if(holding)
src.holder = holding
if(istype(src.holder.loc,/obj/machinery/computer2))
src.master = src.holder.loc
Del()
if(master)
master.processing_programs.Remove(src)
..()
proc
return_text()
if((!src.holder) || (!src.master))
return 1
if((!istype(holder)) || (!istype(master)))
return 1
if(master.stat & (NOPOWER|BROKEN))
return 1
if(!(holder in src.master.contents))
//world << "Holder [holder] not in [master] of prg:[src]"
if(master.active_program == src)
master.active_program = null
return 1
if(!src.holder.root)
src.holder.root = new /datum/computer/folder
src.holder.root.holder = src
src.holder.root.name = "root"
return 0
process()
if((!src.holder) || (!src.master))
return 1
if((!istype(holder)) || (!istype(master)))
return 1
if(!(holder in src.master.contents))
if(master.active_program == src)
master.active_program = null
master.processing_programs.Remove(src)
return 1
if(!src.holder.root)
src.holder.root = new /datum/computer/folder
src.holder.root.holder = src
src.holder.root.name = "root"
return 0
receive_command(obj/source, command, datum/signal/signal)
if((!src.holder) || (!src.master) || (!source) || (source != src.master))
return 1
if((!istype(holder)) || (!istype(master)))
return 1
if(master.stat & (NOPOWER|BROKEN))
return 1
if(!(holder in src.master.contents))
if(master.active_program == src)
master.active_program = null
return 1
return 0
peripheral_command(command, datum/signal/signal)
if(master)
master.send_command(command, signal)
else
del(signal)
transfer_holder(obj/item/weapon/disk/data/newholder,datum/computer/folder/newfolder)
if((newholder.file_used + src.size) > newholder.file_amount)
return 0
if(!newholder.root)
newholder.root = new /datum/computer/folder
newholder.root.holder = newholder
newholder.root.name = "root"
if(!newfolder)
newfolder = newholder.root
if((src.holder && src.holder.read_only) || newholder.read_only)
return 0
if((src.holder) && (src.holder.root))
src.holder.root.remove_file(src)
newfolder.add_file(src)
if(istype(newholder.loc,/obj/machinery/computer2))
src.master = newholder.loc
//world << "Setting [src.holder] to [newholder]"
src.holder = newholder
return 1
//Check access per program.
allowed(mob/M)
//check if it doesn't require any access at all
if(src.check_access(null))
return 1
if(istype(M, /mob/living/silicon))
//AI can do whatever he wants
return 1
else if(istype(M, /mob/living/carbon/human))
var/mob/living/carbon/human/H = M
//if they are holding or wearing a card that has access, that works
if(src.check_access(H.equipped()) || src.check_access(H.wear_id))
return 1
else if(istype(M, /mob/living/carbon/monkey))
var/mob/living/carbon/monkey/george = M
//they can only hold things :(
if(george.equipped() && istype(george.equipped(), /obj/item/weapon/card/id) && src.check_access(george.equipped()))
return 1
return 0
check_access(obj/item/weapon/card/id/I)
if(!src.req_access) //no requirements
return 1
if(!istype(src.req_access, /list)) //something's very wrong
return 1
var/list/L = src.req_access
if(!L.len) //no requirements
return 1
if(!I || !istype(I, /obj/item/weapon/card/id) || !I.access) //not ID or no access
return 0
for(var/req in src.req_access)
if(!(req in I.access)) //doesn't have this access
return 0
return 1
Topic(href, href_list)
if((!src.holder) || (!src.master))
return 1
if((!istype(holder)) || (!istype(master)))
return 1
if(master.stat & (NOPOWER|BROKEN))
return 1
if(src.master.active_program != src)
return 1
if ((!usr.contents.Find(src.master) && (!in_range(src.master, usr) || !istype(src.master.loc, /turf))) && (!istype(usr, /mob/living/silicon)))
return 1
if(!(holder in src.master.contents))
if(master.active_program == src)
master.active_program = null
return 1
usr.machine = src.master
if (href_list["close"])
usr.machine = null
usr << browse(null, "window=comp2")
return 0
if (href_list["quit"])
// src.master.processing_programs.Remove(src)
if(src.master.host_program && src.master.host_program.holder && (src.master.host_program.holder in src.master.contents))
src.master.run_program(src.master.host_program)
src.master.updateUsrDialog()
return 1
else
src.master.active_program = null
src.master.updateUsrDialog()
return 1
return 0

View File

@@ -0,0 +1,153 @@
//Motherboard is just used in assembly/disassembly, doesn't exist in the actual computer object.
/obj/item/weapon/motherboard
name = "Computer mainboard"
desc = "A computer motherboard."
icon = 'module.dmi'
icon_state = "mainboard"
item_state = "electronic"
w_class = 3
var/created_name = null //If defined, result computer will have this name.
/obj/computer2frame
density = 1
anchored = 0
name = "Computer-frame"
icon = 'computer_frame.dmi'
icon_state = "0"
var/state = 0
var/obj/item/weapon/motherboard/mainboard = null
var/obj/item/weapon/disk/data/fixed_disk/hd = null
var/list/peripherals = list()
var/created_icon_state = "aiupload"
/obj/computer2frame/attackby(obj/item/weapon/P as obj, mob/user as mob)
switch(state)
if(0)
if(istype(P, /obj/item/weapon/wrench))
playsound(src.loc, 'Ratchet.ogg', 50, 1)
if(do_after(user, 20))
user << "\blue You wrench the frame into place."
src.anchored = 1
src.state = 1
if(istype(P, /obj/item/weapon/weldingtool))
playsound(src.loc, 'Welder.ogg', 50, 1)
if(do_after(user, 20))
user << "\blue You deconstruct the frame."
var/obj/item/weapon/sheet/metal/A = new /obj/item/weapon/sheet/metal( src.loc )
A.amount = 5
del(src)
if(1)
if(istype(P, /obj/item/weapon/wrench))
playsound(src.loc, 'Ratchet.ogg', 50, 1)
if(do_after(user, 20))
user << "\blue You unfasten the frame."
src.anchored = 0
src.state = 0
if(istype(P, /obj/item/weapon/motherboard) && !mainboard)
playsound(src.loc, 'Deconstruct.ogg', 50, 1)
user << "\blue You place the mainboard inside the frame."
src.icon_state = "1"
src.mainboard = P
user.drop_item()
P.loc = src
if(istype(P, /obj/item/weapon/screwdriver) && mainboard)
playsound(src.loc, 'Screwdriver.ogg', 50, 1)
user << "\blue You screw the mainboard into place."
src.state = 2
src.icon_state = "2"
if(istype(P, /obj/item/weapon/crowbar) && mainboard)
playsound(src.loc, 'Crowbar.ogg', 50, 1)
user << "\blue You remove the mainboard."
src.state = 1
src.icon_state = "0"
mainboard.loc = src.loc
src.mainboard = null
if(2)
if(istype(P, /obj/item/weapon/screwdriver) && mainboard && (!peripherals.len))
playsound(src.loc, 'Screwdriver.ogg', 50, 1)
user << "\blue You unfasten the mainboard."
src.state = 1
src.icon_state = "1"
if(istype(P, /obj/item/weapon/peripheral))
if(src.peripherals.len < 3)
user.drop_item()
src.peripherals.Add(P)
P.loc = src
user << "\blue You add [P] to the frame."
else
user << "\red There is no more room for peripheral cards."
if(istype(P, /obj/item/weapon/crowbar) && src.peripherals.len)
playsound(src.loc, 'Crowbar.ogg', 50, 1)
user << "\blue You remove the peripheral boards."
for(var/obj/item/weapon/peripheral/W in src.peripherals)
W.loc = src.loc
src.peripherals.Remove(W)
if(istype(P, /obj/item/weapon/cable_coil))
if(P:amount >= 5)
playsound(src.loc, 'Deconstruct.ogg', 50, 1)
if(do_after(user, 20))
P:amount -= 5
if(!P:amount) del(P)
user << "\blue You add cables to the frame."
src.state = 3
src.icon_state = "3"
if(3)
if(istype(P, /obj/item/weapon/wirecutters))
playsound(src.loc, 'wirecutter.ogg', 50, 1)
user << "\blue You remove the cables."
src.state = 2
src.icon_state = "2"
var/obj/item/weapon/cable_coil/A = new /obj/item/weapon/cable_coil( src.loc )
A.amount = 5
if(src.hd)
src.hd.loc = src.loc
src.hd = null
if(istype(P, /obj/item/weapon/disk/data/fixed_disk) && !src.hd)
user.drop_item()
src.hd = P
P.loc = src
user << "\blue You connect the drive to the cabling."
if(istype(P, /obj/item/weapon/crowbar) && src.hd)
playsound(src.loc, 'Crowbar.ogg', 50, 1)
user << "\blue You remove the hard drive."
src.hd.loc = src.loc
src.hd = null
if(istype(P, /obj/item/weapon/sheet/glass))
if(P:amount >= 2)
playsound(src.loc, 'Deconstruct.ogg', 50, 1)
if(do_after(user, 20))
P:amount -= 2
if(!P:amount) del(P)
user << "\blue You put in the glass panel."
src.state = 4
src.icon_state = "4"
if(4)
if(istype(P, /obj/item/weapon/crowbar))
playsound(src.loc, 'Crowbar.ogg', 50, 1)
user << "\blue You remove the glass panel."
src.state = 3
src.icon_state = "3"
var/obj/item/weapon/sheet/glass/A = new /obj/item/weapon/sheet/glass( src.loc )
A.amount = 2
if(istype(P, /obj/item/weapon/screwdriver))
playsound(src.loc, 'Screwdriver.ogg', 50, 1)
user << "\blue You connect the monitor."
var/obj/machinery/computer2/C= new /obj/machinery/computer2( src.loc )
C.setup_drive_size = 0
C.icon_state = src.created_icon_state
if(mainboard.created_name) C.name = mainboard.created_name
del(mainboard)
if(hd)
C.hd = hd
hd.loc = C
for(var/obj/item/weapon/peripheral/W in src.peripherals)
W.loc = C
W.host = C
C.peripherals.Add(W)
del(src)

View File

@@ -0,0 +1,414 @@
/obj/machinery/computer2
name = "computer"
desc = "A computer workstation."
icon = 'computer.dmi'
icon_state = "aiupload"
density = 1
anchored = 1.0
req_access = list() //This doesn't determine PROGRAM req access, just the access needed to install/delete programs.
var/base_icon_state = "aiupload" //Assembly creates a new computer2 and not a child typepath, so initial doesn't work!!
var/datum/radio_frequency/radio_connection
var/obj/item/weapon/disk/data/fixed_disk/hd = null
var/datum/computer/file/computer_program/active_program
var/datum/computer/file/computer_program/host_program //active is set to this when the normal active quits, if available
var/list/processing_programs = list()
var/obj/item/weapon/card/id/authid = null //For records computers etc
var/obj/item/weapon/card/id/auxid = null //For computers that need two ids for some reason.
var/obj/item/weapon/disk/data/diskette = null
var/list/peripherals = list()
//Setup for Starting program & peripherals
var/setup_starting_program = null //If set to a program path it will start with this one active.
var/setup_starting_peripheral = null //Spawn with radio card and whatever path is here.
var/setup_drive_size = 64.0 //How big is the drive (set to 0 for no drive)
var/setup_id_tag
var/setup_has_radio = 0 //Does it spawn with a radio peripheral?
var/setup_radio_tag
var/setup_frequency = 1411
/obj/item/weapon/disk/data
var/datum/computer/folder/root = null
var/file_amount = 32.0
var/file_used = 0.0
var/portable = 1
var/title = "Data Disk"
New()
src.root = new /datum/computer/folder
src.root.holder = src
src.root.name = "root"
/obj/item/weapon/disk/data/fixed_disk
name = "Storage Drive"
icon_state = "harddisk"
title = "Storage Drive"
file_amount = 80.0
portable = 0
attack_self(mob/user as mob)
return
/obj/item/weapon/disk/data/computer2test
name = "Programme Diskette"
file_amount = 128.0
New()
..()
src.root.add_file( new /datum/computer/file/computer_program/arcade(src))
src.root.add_file( new /datum/computer/file/computer_program/med_data(src))
src.root.add_file( new /datum/computer/file/computer_program/airlock_control(src))
src.root.add_file( new /datum/computer/file/computer_program/messenger(src))
src.root.add_file( new /datum/computer/file/computer_program/progman(src))
/obj/machinery/computer2/medical
name = "Medical computer"
icon_state = "dna"
setup_has_radio = 1
setup_starting_program = /datum/computer/file/computer_program/med_data
setup_starting_peripheral = /obj/item/weapon/peripheral/printer
/obj/machinery/computer2/arcade
name = "arcade machine"
icon_state = "arcade"
desc = "An arcade machine."
setup_drive_size = 16.0
setup_starting_program = /datum/computer/file/computer_program/arcade
setup_starting_peripheral = /obj/item/weapon/peripheral/prize_vendor
/obj/machinery/computer2/New()
..()
spawn(4)
if(setup_has_radio)
var/obj/item/weapon/peripheral/radio/radio = new /obj/item/weapon/peripheral/radio(src)
radio.frequency = setup_frequency
radio.code = setup_radio_tag
if(!hd && (setup_drive_size > 0))
src.hd = new /obj/item/weapon/disk/data/fixed_disk(src)
src.hd.file_amount = src.setup_drive_size
if(ispath(src.setup_starting_program))
src.active_program = new src.setup_starting_program
src.active_program.id_tag = setup_id_tag
src.hd.file_amount = max(src.hd.file_amount, src.active_program.size)
src.active_program.transfer_holder(src.hd)
if(ispath(src.setup_starting_peripheral))
new src.setup_starting_peripheral(src)
src.base_icon_state = src.icon_state
return
/obj/machinery/computer2/attack_hand(mob/user as mob)
if(..())
return
user.machine = src
var/dat
if((src.active_program) && (src.active_program.master == src) && (src.active_program.holder in src))
dat = src.active_program.return_text()
else
dat = "<TT><b>Thinktronic BIOS V1.4</b><br><br>"
dat += "Current ID: <a href='?src=\ref[src];id=auth'>[src.authid ? "[src.authid.name]" : "----------"]</a><br>"
dat += "Auxiliary ID: <a href='?src=\ref[src];id=aux'>[src.auxid ? "[src.auxid.name]" : "----------"]</a><br><br>"
var/progdat
if((src.hd) && (src.hd.root))
for(var/datum/computer/file/computer_program/P in src.hd.root.contents)
progdat += "<tr><td>[P.name]</td><td>Size: [P.size]</td>"
progdat += "<td><a href='byond://?src=\ref[src];prog=\ref[P];function=run'>Run</a></td>"
if(P in src.processing_programs)
progdat += "<td><a href='byond://?src=\ref[src];prog=\ref[P];function=unload'>Halt</a></td>"
else
progdat += "<td><a href='byond://?src=\ref[src];prog=\ref[P];function=load'>Load</a></td>"
progdat += "<td><a href='byond://?src=\ref[src];file=\ref[P];function=delete'>Del</a></td></tr>"
continue
dat += "Disk Space: \[[src.hd.file_used]/[src.hd.file_amount]\]<br>"
dat += "<b>Programs on Fixed Disk:</b><br>"
if(!progdat)
progdat = "No programs found.<br>"
dat += "<center><table cellspacing=4>[progdat]</table></center>"
else
dat += "<b>Programs on Fixed Disk:</b><br>"
dat += "<center>No fixed disk detected.</center><br>"
dat += "<br>"
progdat = null
if((src.diskette) && (src.diskette.root))
dat += "<font size=1><a href='byond://?src=\ref[src];disk=1'>Eject</a></font><br>"
for(var/datum/computer/file/computer_program/P in src.diskette.root.contents)
progdat += "<tr><td>[P.name]</td><td>Size: [P.size]</td>"
progdat += "<td><a href='byond://?src=\ref[src];prog=\ref[P];function=run'>Run</a></td>"
if(P in src.processing_programs)
progdat += "<td><a href='byond://?src=\ref[src];prog=\ref[P];function=unload'>Halt</a></td>"
else
progdat += "<td><a href='byond://?src=\ref[src];prog=\ref[P];function=load'>Load</a></td>"
progdat += "<td><a href='byond://?src=\ref[src];file=\ref[P];function=install'>Install</a></td></tr>"
continue
dat += "Disk Space: \[[src.diskette.file_used]/[src.diskette.file_amount]\]<br>"
dat += "<b>Programs on Disk:</b><br>"
if(!progdat)
progdat = "No data found.<br>"
dat += "<center><table cellspacing=4>[progdat]</table></center>"
else
dat += "<b>Programs on Disk:</b><br>"
dat += "<center>No diskette loaded.</center><br>"
dat += "</TT>"
user << browse(dat,"window=comp2")
onclose(user,"comp2")
return
/obj/machinery/computer2/Topic(href, href_list)
if(..())
return
if(!src.active_program)
if((href_list["prog"]) && (href_list["function"]))
var/datum/computer/file/computer_program/newprog = locate(href_list["prog"])
if(newprog && istype(newprog))
switch(href_list["function"])
if("run")
src.run_program(newprog)
if("load")
src.load_program(newprog)
if("unload")
src.unload_program(newprog)
if((href_list["file"]) && (href_list["function"]))
var/datum/computer/file/newfile = locate(href_list["file"])
if(!newfile)
return
switch(href_list["function"])
if("install")
if((src.hd) && (src.hd.root) && (src.allowed(usr)))
newfile.copy_file_to_folder(src.hd.root)
if("delete")
if(src.allowed(usr))
src.delete_file(newfile)
//If there is already one loaded eject, or if not and they have one insert it.
if (href_list["id"])
switch(href_list["id"])
if("auth")
if(!isnull(src.authid))
src.authid.loc = get_turf(src)
src.authid = null
else
var/obj/item/I = usr.equipped()
if (istype(I, /obj/item/weapon/card/id))
usr.drop_item()
I.loc = src
src.authid = I
if("aux")
if(!isnull(src.auxid))
src.auxid.loc = get_turf(src)
src.auxid = null
else
var/obj/item/I = usr.equipped()
if (istype(I, /obj/item/weapon/card/id))
usr.drop_item()
I.loc = src
src.auxid = I
//Same but for a data disk
else if (href_list["disk"])
if(!isnull(src.diskette))
src.diskette.loc = get_turf(src)
src.diskette = null
/* else
var/obj/item/I = usr.equipped()
if (istype(I, /obj/item/weapon/disk/data))
usr.drop_item()
I.loc = src
src.diskette = I
*/
src.add_fingerprint(usr)
src.updateUsrDialog()
return
/obj/machinery/computer2/process()
if(stat & (NOPOWER|BROKEN))
return
use_power(250)
for(var/datum/computer/file/computer_program/P in src.processing_programs)
P.process()
return
/obj/machinery/computer2/power_change()
if(stat & BROKEN)
icon_state = src.base_icon_state
src.icon_state += "b"
else if(powered())
icon_state = src.base_icon_state
stat &= ~NOPOWER
else
spawn(rand(0, 15))
icon_state = src.base_icon_state
src.icon_state += "0"
stat |= NOPOWER
/obj/machinery/computer2/attackby(obj/item/W as obj, mob/user as mob)
if (istype(W, /obj/item/weapon/disk/data)) //INSERT SOME DISKETTES
if ((!src.diskette) && W:portable)
user.machine = src
user.drop_item()
W.loc = src
src.diskette = W
user << "You insert [W]."
src.updateUsrDialog()
return
else if (istype(W, /obj/item/weapon/screwdriver))
playsound(src.loc, 'Screwdriver.ogg', 50, 1)
if(do_after(user, 20))
var/obj/computer2frame/A = new /obj/computer2frame( src.loc )
A.created_icon_state = src.base_icon_state
if (src.stat & BROKEN)
user << "\blue The broken glass falls out."
new /obj/item/weapon/shard( src.loc )
A.state = 3
A.icon_state = "3"
else
user << "\blue You disconnect the monitor."
A.state = 4
A.icon_state = "4"
for (var/obj/item/weapon/peripheral/C in src.peripherals)
C.loc = A
A.peripherals.Add(C)
if(src.diskette)
src.diskette.loc = src.loc
//TO-DO: move card reading to peripheral cards instead
if(src.authid)
src.authid.loc = src.loc
if(src.auxid)
src.auxid.loc = src.loc
if(src.hd)
src.hd.loc = A
A.hd = src.hd
A.mainboard = new /obj/item/weapon/motherboard(A)
A.mainboard.created_name = src.name
A.anchored = 1
del(src)
else
src.attack_hand(user)
return
/obj/machinery/computer2/proc/send_command(command, datum/signal/signal)
for(var/obj/item/weapon/peripheral/P in src.peripherals)
P.receive_command(src, command, signal)
del(signal)
/obj/machinery/computer2/proc/receive_command(obj/source, command, datum/signal/signal)
if(source in src.contents)
for(var/datum/computer/file/computer_program/P in src.processing_programs)
P.receive_command(src, command, signal)
del(signal)
return
/obj/machinery/computer2/proc/run_program(datum/computer/file/computer_program/program,datum/computer/file/computer_program/host)
if(!program)
return 0
// src.unload_program(src.active_program)
if(src.load_program(program))
if(host && istype(host))
src.host_program = host
else
src.host_program = null
src.active_program = program
return 1
return 0
/obj/machinery/computer2/proc/load_program(datum/computer/file/computer_program/program)
if((!program) || (!program.holder))
return 0
if(!(program.holder in src))
// world << "Not in src"
program = new program.type
program.transfer_holder(src.hd)
if(program.master != src)
program.master = src
if(program in src.processing_programs)
return 1
else
src.processing_programs.Add(program)
return 1
return 0
/obj/machinery/computer2/proc/unload_program(datum/computer/file/computer_program/program)
if((!program) || (!src.hd))
return 0
if(program in src.processing_programs)
src.processing_programs.Remove(program)
return 1
return 0
/obj/machinery/computer2/proc/delete_file(datum/computer/file/file)
//world << "Deleting [file]..."
if((!file) || (!file.holder) || (file.holder.read_only))
//world << "Cannot delete :("
return 0
if(file in src.processing_programs)
src.processing_programs.Remove(file)
if(src.active_program == file)
src.active_program = null
// file.holder.root.remove_file(file)
//world << "Now calling del on [file]..."
del(file)
return 1

View File

@@ -0,0 +1,164 @@
/datum/computer/file/computer_program/progman
name = "ProgManager"
size = 16.0
var/datum/computer/folder/current_folder
var/mode = 0
var/datum/computer/file/clipboard
return_text()
if(..())
return
if((!src.current_folder) || !(src.current_folder.holder in src.master))
src.current_folder = src.holder.root
var/dat = "<a href='byond://?src=\ref[src];close=1'>Close</a> | "
dat += "<a href='byond://?src=\ref[src];quit=1'>Quit</a>"
switch(mode)
if(0)
dat += " |<a href='byond://?src=\ref[src];create=folder'>Create Folder</a>"
//dat += " | <a href='byond://?src=\ref[src];create=file'>Create File</a>"
dat += " | <a href='byond://?src=\ref[src];file=\ref[src.current_folder];function=paste'>Paste</a>"
dat += " | <a href='byond://?src=\ref[src];top_folder=1'>Root</a>"
dat += " | <a href='byond://?src=\ref[src];mode=1'>Drive</a><br>"
dat += "<b>Contents of [current_folder] | Drive:\[[src.current_folder.holder.title]]</b><br>"
dat += "<b>Used: \[[src.current_folder.holder.file_used]/[src.current_folder.holder.file_amount]\]</b><hr>"
dat += "<table cellspacing=5>"
for(var/datum/computer/P in current_folder.contents)
if(P == src)
dat += "<tr><td>System</td><td>Size: [src.size]</td><td>SYSTEM</td></tr>"
continue
dat += "<tr><td><a href='byond://?src=\ref[src];file=\ref[P];function=open'>[P.name]</a></td>"
dat += "<td>Size: [P.size]</td>"
dat += "<td>[(istype(P,/datum/computer/folder)) ? "FOLDER" : "[P:extension]"]</td>"
dat += "<td><a href='byond://?src=\ref[src];file=\ref[P];function=delete'>Del</a></td>"
dat += "<td><a href='byond://?src=\ref[src];file=\ref[P];function=rename'>Rename</a></td>"
if(istype(P,/datum/computer/file))
dat += "<td><a href='byond://?src=\ref[src];file=\ref[P];function=copy'>Copy</a></td>"
dat += "</tr>"
dat += "</table>"
if(1)
dat += " | <a href='byond://?src=\ref[src];mode=0'>Main</a>"
dat += " | <a href='byond://?src=\ref[master];disk=1'>Eject</a><br>"
for(var/obj/item/weapon/disk/data/D in src.master)
if(D == current_folder.holder)
dat += "[D.name]<br>"
else
dat += "<a href='byond://?src=\ref[src];drive=\ref[D]'>[D.title]</a><br>"
return dat
Topic(href, href_list)
if(..())
return
if(href_list["create"])
if(current_folder)
var/datum/computer/F = null
switch(href_list["create"])
if("folder")
F = new /datum/computer/folder
if(!current_folder.add_file(F))
//world << "Couldn't add folder :("
del(F)
if("file")
F = new /datum/computer/file
if(!current_folder.add_file(F))
//world << "Couldn't add file :("
del(F)
if(href_list["file"] && href_list["function"])
var/datum/computer/F = locate(href_list["file"])
if(!F || !istype(F))
return
switch(href_list["function"])
if("open")
if(istype(F,/datum/computer/folder))
src.current_folder = F
else if(istype(F,/datum/computer/file/computer_program))
src.master.run_program(F,src)
src.master.updateUsrDialog()
return
if("delete")
src.master.delete_file(F)
if("copy")
if(istype(F,/datum/computer/file) && (!F.holder || (F.holder in src.master.contents)))
src.clipboard = F
if("paste")
if(istype(F,/datum/computer/folder))
if(!src.clipboard || !src.clipboard.holder || !(src.clipboard.holder in src.master.contents))
return
if(!istype(src.clipboard))
return
src.clipboard.copy_file_to_folder(F)
if("rename")
spawn(0)
var/t = input(usr, "Please enter new name", F.name, null) as text
t = copytext(sanitize(t), 1, 16)
if (!t)
return
if (!in_range(src.master, usr) || !(F.holder in src.master))
return
if(F.holder.read_only)
return
F.name = capitalize(lowertext(t))
src.master.updateUsrDialog()
return
/*
if(href_list["open"])
var/datum/computer/F = locate(href_list["open"])
if(!F || !istype(F))
return
if(istype(F,/datum/computer/folder))
src.current_folder = F
else if(istype(F,/datum/computer/file/computer_program))
src.master.run_program(F)
src.master.updateUsrDialog()
return
if(href_list["delete"])
var/datum/computer/F = locate(href_list["delete"])
if(!F || !istype(F))
return
src.master.delete_file(F)
*/
if(href_list["top_folder"])
src.current_folder = src.current_folder.holder.root
if(href_list["mode"])
var/newmode = text2num(href_list["mode"])
newmode = max(newmode,0)
src.mode = newmode
if(href_list["drive"])
var/obj/item/weapon/disk/data/D = locate(href_list["drive"])
if(D && istype(D) && D.root)
current_folder = D.root
src.mode = 0
src.master.add_fingerprint(usr)
src.master.updateUsrDialog()
return

View File

@@ -0,0 +1,463 @@
/datum/computer/file/computer_program/med_data
name = "Medical Records"
size = 32.0
active_icon = "dna"
req_access = list(access_medical)
var/authenticated = null
var/rank = null
var/screen = null
var/datum/data/record/active1 = null
var/datum/data/record/active2 = null
var/a_id = null
var/temp = null
/datum/computer/file/computer_program/med_data/return_text()
if(..())
return
var/dat
if (src.temp)
dat = text("<TT>[src.temp]</TT><BR><BR><A href='?src=\ref[src];temp=1'>Clear Screen</A>")
else
dat = text("Confirm Identity: <A href='?src=\ref[];id=auth'>[]</A><HR>", master, (src.master.authid ? text("[]", src.master.authid.name) : "----------"))
if (src.authenticated)
switch(src.screen)
if(1.0)
dat += {"
<A href='?src=\ref[src];search=1'>Search Records</A>
<BR><A href='?src=\ref[src];screen=2'>List Records</A>
<BR>
<BR><A href='?src=\ref[src];screen=5'>Virus Database</A>
<BR><A href='?src=\ref[src];screen=6'>Medbot Tracking</A>
<BR>
<BR><A href='?src=\ref[src];screen=3'>Record Maintenance</A>
<BR><A href='?src=\ref[src];logout=1'>{Log Out}</A><BR>
"}
if(2.0)
dat += "<B>Record List</B>:<HR>"
for(var/datum/data/record/R in data_core.general)
dat += text("<A href='?src=\ref[];d_rec=\ref[]'>[]: []<BR>", src, R, R.fields["id"], R.fields["name"])
//Foreach goto(132)
dat += text("<HR><A href='?src=\ref[];screen=1'>Back</A>", src)
if(3.0)
dat += text("<B>Records Maintenance</B><HR>\n<A href='?src=\ref[];back=1'>Backup To Disk</A><BR>\n<A href='?src=\ref[];u_load=1'>Upload From disk</A><BR>\n<A href='?src=\ref[];del_all=1'>Delete All Records</A><BR>\n<BR>\n<A href='?src=\ref[];screen=1'>Back</A>", src, src, src, src)
if(4.0)
dat += "<CENTER><B>Medical Record</B></CENTER><BR>"
if ((istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1)))
dat += text("Name: [] ID: []<BR>\nSex: <A href='?src=\ref[];field=sex'>[]</A><BR>\nAge: <A href='?src=\ref[];field=age'>[]</A><BR>\nFingerprint: <A href='?src=\ref[];field=fingerprint'>[]</A><BR>\nPhysical Status: <A href='?src=\ref[];field=p_stat'>[]</A><BR>\nMental Status: <A href='?src=\ref[];field=m_stat'>[]</A><BR>", src.active1.fields["name"], src.active1.fields["id"], src, src.active1.fields["sex"], src, src.active1.fields["age"], src, src.active1.fields["fingerprint"], src, src.active1.fields["p_stat"], src, src.active1.fields["m_stat"])
else
dat += "<B>General Record Lost!</B><BR>"
if ((istype(src.active2, /datum/data/record) && data_core.medical.Find(src.active2)))
dat += text("<BR>\n<CENTER><B>Medical Data</B></CENTER><BR>\nBlood Type: <A href='?src=\ref[];field=b_type'>[]</A><BR>\n<BR>\nMinor Disabilities: <A href='?src=\ref[];field=mi_dis'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=mi_dis_d'>[]</A><BR>\n<BR>\nMajor Disabilities: <A href='?src=\ref[];field=ma_dis'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=ma_dis_d'>[]</A><BR>\n<BR>\nAllergies: <A href='?src=\ref[];field=alg'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=alg_d'>[]</A><BR>\n<BR>\nCurrent Diseases: <A href='?src=\ref[];field=cdi'>[]</A> (per disease info placed in log/comment section)<BR>\nDetails: <A href='?src=\ref[];field=cdi_d'>[]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[];field=notes'>[]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", src, src.active2.fields["b_type"], src, src.active2.fields["mi_dis"], src, src.active2.fields["mi_dis_d"], src, src.active2.fields["ma_dis"], src, src.active2.fields["ma_dis_d"], src, src.active2.fields["alg"], src, src.active2.fields["alg_d"], src, src.active2.fields["cdi"], src, src.active2.fields["cdi_d"], src, src.active2.fields["notes"])
var/counter = 1
while(src.active2.fields[text("com_[]", counter)])
dat += text("[]<BR><A href='?src=\ref[];del_c=[]'>Delete Entry</A><BR><BR>", src.active2.fields[text("com_[]", counter)], src, counter)
counter++
dat += text("<A href='?src=\ref[];add_c=1'>Add Entry</A><BR><BR>", src)
dat += text("<A href='?src=\ref[];del_r=1'>Delete Record (Medical Only)</A><BR><BR>", src)
else
dat += "<B>Medical Record Lost!</B><BR>"
dat += text("<A href='?src=\ref[src];new=1'>New Record</A><BR><BR>")
dat += text("\n<A href='?src=\ref[];print_p=1'>Print Record</A><BR>\n<A href='?src=\ref[];screen=2'>Back</A><BR>", src, src)
if(5.0)
dat += {"<CENTER><B>Virus Database</B></CENTER>
<br><a href='?src=\ref[src];vir=gbs'>GBS</a>
<br><a href='?src=\ref[src];vir=cc'>Common Cold</a>
<br><a href='?src=\ref[src];vir=f'>Flu</A>
<br><a href='?src=\ref[src];vir=jf'>Jungle Fever</a>
<br><a href='?src=\ref[src];vir=ca'>Clowning Around</a>
<br><a href='?src=\ref[src];vir=p'>Plasmatoid</a>
<br><a href='?src=\ref[src];vir=dna'>Space Rhinovirus</a>
<br><a href='?src=\ref[src];vir=bot'>Robot Transformation</a>
<br><a href='?src=\ref[src];screen=1'>Back</a>"}
if(6.0)
dat += "<center><b>Medical Robot Monitor</b></center>"
dat += "<a href='?src=\ref[src];screen=1'>Back</a>"
dat += "<br><b>Medical Robots:</b>"
var/bdat = null
for(var/obj/machinery/bot/medbot/M in world)
var/turf/bl = get_turf(M)
bdat += "[M.name] - <b>\[[bl.x],[bl.y]\]</b> - [M.on ? "Online" : "Offline"]<br>"
if(!isnull(M.reagent_glass))
bdat += "Reservoir: \[[M.reagent_glass.reagents.total_volume]/[M.reagent_glass.reagents.maximum_volume]\]"
else
bdat += "Using Internal Synthesizer."
if(!bdat)
dat += "<br><center>None detected</center>"
else
dat += "[bdat]"
else
else
dat += text("<A href='?src=\ref[];login=1'>{Log In}</A>", src)
dat += "<br><a href='byond://?src=\ref[src];quit=1'>{Quit}</a>"
return dat
/datum/computer/file/computer_program/med_data/Topic(href, href_list)
if(..())
return
if (!( data_core.general.Find(src.active1) ))
src.active1 = null
if (!( data_core.medical.Find(src.active2) ))
src.active2 = null
if (href_list["temp"])
src.temp = null
else if (href_list["logout"])
src.authenticated = null
src.screen = null
src.active1 = null
src.active2 = null
else if (href_list["login"])
if (istype(usr, /mob/living/silicon))
src.active1 = null
src.active2 = null
src.authenticated = 1
src.rank = "AI"
src.screen = 1
else if (istype(src.master.authid, /obj/item/weapon/card/id))
src.active1 = null
src.active2 = null
if (src.check_access(src.master.authid))
src.authenticated = src.master.authid.registered
src.rank = src.master.authid.assignment
src.screen = 1
if (src.authenticated)
if(href_list["screen"])
src.screen = text2num(href_list["screen"])
if(src.screen < 1)
src.screen = 1
src.active1 = null
src.active2 = null
if(href_list["vir"])
switch(href_list["vir"])
if("gbs")
src.temp = {"<b>Name:</b> GBS
<BR><b>Number of stages:</b> 5
<BR><b>Spread:</b> Airborne Transmission
<BR><b>Possible Cure:</b> Spaceacillin
<BR><b>Affected Species:</b> Human
<BR>
<BR><b>Notes:</b> If left untreated death will occur.
<BR>
<BR><b>Severity:</b> Major"}
if("cc")
src.temp = {"<b>Name:</b> Common Cold
<BR><b>Number of stages:</b> 3
<BR><b>Spread:</b> Airborne Transmission
<BR><b>Possible Cure:</b> Rest
<BR><b>Affected Species:</b> Human
<BR>
<BR><b>Notes:</b> If left untreated the subject will contract the flu.
<BR>
<BR><b>Severity:</b> Minor"}
if("f")
src.temp = {"<b>Name:</b> The Flu
<BR><b>Number of stages:</b> 3
<BR><b>Spread:</b> Airborne Transmission
<BR><b>Possible Cure:</b> Rest
<BR><b>Affected Species:</b> Human
<BR>
<BR><b>Notes:</b> If left untreated the subject will feel quite unwell.
<BR>
<BR><b>Severity:</b> Medium"}
if("jf")
src.temp = {"<b>Name:</b> Jungle Fever
<BR><b>Number of stages:</b> 1
<BR><b>Spread:</b> Airborne Transmission
<BR><b>Possible Cure:</b> None
<BR><b>Affected Species:</b> Monkey
<BR>
<BR><b>Notes:</b> Monkies with this disease will bite humans, causing humans to spontaneously to mutate into a monkey.
<BR>
<BR><b>Severity:</b> Medium"}
if("ca")
src.temp = {"<b>Name:</b> Clowning Around
<BR><b>Number of stages:</b> 4
<BR><b>Spread:</b> Airborne Transmission
<BR><b>Possible Cure:</b> Spaceacillin
<BR><b>Affected Species:</b> Human
<BR>
<BR><b>Notes:</b> Subjects are affected by rampant honking and a fondness for shenanigans. They may also spontaneously phase through closed airlocks.
<BR>
<BR><b>Severity:</b> Laughable"}
if("p")
src.temp = {"<b>Name:</b> Plasmatoid
<BR><b>Number of stages:</b> 3
<BR><b>Spread:</b> Airborne Transmission
<BR><b>Possible Cure:</b> Inaprovaline
<BR><b>Affected Species:</b> Human and Monkey
<BR>
<BR><b>Notes:</b> With this disease the victim will need plasma to breathe.
<BR>
<BR><b>Severity:</b> Major"}
if("dna")
src.temp = {"<b>Name:</b> Space Rhinovirus
<BR><b>Number of stages:</b> 4
<BR><b>Spread:</b> Airborne Transmission
<BR><b>Possible Cure:</b> Spaceacillin
<BR><b>Affected Species:</b> Human
<BR>
<BR><b>Notes:</b> This disease transplants the genetic code of the intial vector into new hosts.
<BR>
<BR><b>Severity:</b> Medium"}
if("bot")
src.temp = {"<b>Name:</b> Robot Transformation
<BR><b>Number of stages:</b> 5
<BR><b>Spread:</b> Infected food
<BR><b>Possible Cure:</b> None
<BR><b>Affected Species:</b> Human
<BR>
<BR><b>Notes:</b> This disease, actually acute nanomachine infection, converts the victim into a cyborg.
<BR>
<BR><b>Severity:</b> Major"}
if (href_list["del_all"])
src.temp = text("Are you sure you wish to delete all records?<br>\n\t<A href='?src=\ref[];temp=1;del_all2=1'>Yes</A><br>\n\t<A href='?src=\ref[];temp=1'>No</A><br>", src, src)
if (href_list["del_all2"])
for(var/datum/data/record/R in data_core.medical)
del(R)
src.temp = "All records deleted."
if (href_list["field"])
var/a1 = src.active1
var/a2 = src.active2
switch(href_list["field"])
if("fingerprint")
if (istype(src.active1, /datum/data/record))
var/t1 = input("Please input fingerprint hash:", "Med. records", src.active1.fields["id"], null) as text
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1))
return
src.active1.fields["fingerprint"] = t1
if("sex")
if (istype(src.active1, /datum/data/record))
if (src.active1.fields["sex"] == "Male")
src.active1.fields["sex"] = "Female"
else
src.active1.fields["sex"] = "Male"
if("age")
if (istype(src.active1, /datum/data/record))
var/t1 = input("Please input age:", "Med. records", src.active1.fields["age"], null) as text
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1))
return
src.active1.fields["age"] = t1
if("mi_dis")
if (istype(src.active2, /datum/data/record))
var/t1 = input("Please input minor disabilities list:", "Med. records", src.active2.fields["mi_dis"], null) as text
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2))
return
src.active2.fields["mi_dis"] = t1
if("mi_dis_d")
if (istype(src.active2, /datum/data/record))
var/t1 = input("Please summarize minor dis.:", "Med. records", src.active2.fields["mi_dis_d"], null) as message
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2))
return
src.active2.fields["mi_dis_d"] = t1
if("ma_dis")
if (istype(src.active2, /datum/data/record))
var/t1 = input("Please input major diabilities list:", "Med. records", src.active2.fields["ma_dis"], null) as text
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2))
return
src.active2.fields["ma_dis"] = t1
if("ma_dis_d")
if (istype(src.active2, /datum/data/record))
var/t1 = input("Please summarize major dis.:", "Med. records", src.active2.fields["ma_dis_d"], null) as message
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2))
return
src.active2.fields["ma_dis_d"] = t1
if("alg")
if (istype(src.active2, /datum/data/record))
var/t1 = input("Please state allergies:", "Med. records", src.active2.fields["alg"], null) as text
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2))
return
src.active2.fields["alg"] = t1
if("alg_d")
if (istype(src.active2, /datum/data/record))
var/t1 = input("Please summarize allergies:", "Med. records", src.active2.fields["alg_d"], null) as message
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2))
return
src.active2.fields["alg_d"] = t1
if("cdi")
if (istype(src.active2, /datum/data/record))
var/t1 = input("Please state diseases:", "Med. records", src.active2.fields["cdi"], null) as text
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2))
return
src.active2.fields["cdi"] = t1
if("cdi_d")
if (istype(src.active2, /datum/data/record))
var/t1 = input("Please summarize diseases:", "Med. records", src.active2.fields["cdi_d"], null) as message
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2))
return
src.active2.fields["cdi_d"] = t1
if("notes")
if (istype(src.active2, /datum/data/record))
var/t1 = input("Please summarize notes:", "Med. records", src.active2.fields["notes"], null) as message
if ((!( t1 ) || !( src.authenticated ) || (!src.master) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2))
return
src.active2.fields["notes"] = t1
if("p_stat")
if (istype(src.active1, /datum/data/record))
src.temp = text("<B>Physical Condition:</B><BR>\n\t<A href='?src=\ref[];temp=1;p_stat=deceased'>*Deceased*</A><BR>\n\t<A href='?src=\ref[];temp=1;p_stat=unconscious'>*Unconscious*</A><BR>\n\t<A href='?src=\ref[];temp=1;p_stat=active'>Active</A><BR>\n\t<A href='?src=\ref[];temp=1;p_stat=unfit'>Physically Unfit</A><BR>", src, src, src, src)
if("m_stat")
if (istype(src.active1, /datum/data/record))
src.temp = text("<B>Mental Condition:</B><BR>\n\t<A href='?src=\ref[];temp=1;m_stat=insane'>*Insane*</A><BR>\n\t<A href='?src=\ref[];temp=1;m_stat=unstable'>*Unstable*</A><BR>\n\t<A href='?src=\ref[];temp=1;m_stat=watch'>*Watch*</A><BR>\n\t<A href='?src=\ref[];temp=1;m_stat=stable'>Stable</A><BR>", src, src, src, src)
if("b_type")
if (istype(src.active2, /datum/data/record))
src.temp = text("<B>Blood Type:</B><BR>\n\t<A href='?src=\ref[];temp=1;b_type=an'>A-</A> <A href='?src=\ref[];temp=1;b_type=ap'>A+</A><BR>\n\t<A href='?src=\ref[];temp=1;b_type=bn'>B-</A> <A href='?src=\ref[];temp=1;b_type=bp'>B+</A><BR>\n\t<A href='?src=\ref[];temp=1;b_type=abn'>AB-</A> <A href='?src=\ref[];temp=1;b_type=abp'>AB+</A><BR>\n\t<A href='?src=\ref[];temp=1;b_type=on'>O-</A> <A href='?src=\ref[];temp=1;b_type=op'>O+</A><BR>", src, src, src, src, src, src, src, src)
else
if (href_list["p_stat"])
if (src.active1)
switch(href_list["p_stat"])
if("deceased")
src.active1.fields["p_stat"] = "*Deceased*"
if("unconscious")
src.active1.fields["p_stat"] = "*Unconscious*"
if("active")
src.active1.fields["p_stat"] = "Active"
if("unfit")
src.active1.fields["p_stat"] = "Physically Unfit"
if (href_list["m_stat"])
if (src.active1)
switch(href_list["m_stat"])
if("insane")
src.active1.fields["m_stat"] = "*Insane*"
if("unstable")
src.active1.fields["m_stat"] = "*Unstable*"
if("watch")
src.active1.fields["m_stat"] = "*Watch*"
if("stable")
src.active2.fields["m_stat"] = "Stable"
if (href_list["b_type"])
if (src.active2)
switch(href_list["b_type"])
if("an")
src.active2.fields["b_type"] = "A-"
if("bn")
src.active2.fields["b_type"] = "B-"
if("abn")
src.active2.fields["b_type"] = "AB-"
if("on")
src.active2.fields["b_type"] = "O-"
if("ap")
src.active2.fields["b_type"] = "A+"
if("bp")
src.active2.fields["b_type"] = "B+"
if("abp")
src.active2.fields["b_type"] = "AB+"
if("op")
src.active2.fields["b_type"] = "O+"
if (href_list["del_r"])
if (src.active2)
src.temp = "Are you sure you wish to delete the record (Medical Portion Only)?<br>\n\t<A href='?src=\ref[src];temp=1;del_r2=1'>Yes</A><br>\n\t<A href='?src=\ref[src];temp=1'>No</A><br>"
if (href_list["del_r2"])
if (src.active2)
del(src.active2)
if (href_list["d_rec"])
var/datum/data/record/R = locate(href_list["d_rec"])
var/datum/data/record/M = locate(href_list["d_rec"])
if (!( data_core.general.Find(R) ))
src.temp = "Record Not Found!"
return
for(var/datum/data/record/E in data_core.medical)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
M = E
else
//Foreach continue //goto(2540)
src.active1 = R
src.active2 = M
src.screen = 4
if (href_list["new"])
if ((istype(src.active1, /datum/data/record) && !( istype(src.active2, /datum/data/record) )))
var/datum/data/record/R = new /datum/data/record( )
R.fields["name"] = src.active1.fields["name"]
R.fields["id"] = src.active1.fields["id"]
R.name = text("Medical Record #[]", R.fields["id"])
R.fields["b_type"] = "Unknown"
R.fields["mi_dis"] = "None"
R.fields["mi_dis_d"] = "No minor disabilities have been declared."
R.fields["ma_dis"] = "None"
R.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
R.fields["alg"] = "None"
R.fields["alg_d"] = "No allergies have been detected in this patient."
R.fields["cdi"] = "None"
R.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
R.fields["notes"] = "No notes."
data_core.medical += R
src.active2 = R
src.screen = 4
if (href_list["add_c"])
if (!( istype(src.active2, /datum/data/record) ))
return
var/a2 = src.active2
var/t1 = input("Add Comment:", "Med. records", null, null) as message
if ((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src.master, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2))
return
var/counter = 1
while(src.active2.fields[text("com_[]", counter)])
counter++
src.active2.fields[text("com_[]", counter)] = text("Made by [] ([]) on [], 2053<BR>[]", src.authenticated, src.rank, time2text(world.realtime, "DDD MMM DD hh:mm:ss"), t1)
if (href_list["del_c"])
if ((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])]))
src.active2.fields[text("com_[]", href_list["del_c"])] = "<B>Deleted</B>"
if (href_list["search"])
var/t1 = input("Search String: (Name or ID)", "Med. records", null, null) as text
if ((!( t1 ) || usr.stat || (!src.master) || !( src.authenticated ) || usr.restrained() || ((!in_range(src.master, usr)) && (!istype(usr, /mob/living/silicon)))))
return
src.active1 = null
src.active2 = null
t1 = lowertext(t1)
for(var/datum/data/record/R in data_core.general)
if ((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"])))
src.active1 = R
else
if (!( src.active1 ))
src.temp = text("Could not locate record [].", t1)
else
for(var/datum/data/record/E in data_core.medical)
if ((E.fields["name"] == src.active1.fields["name"] || E.fields["id"] == src.active1.fields["id"]))
src.active2 = E
else
src.screen = 4
if (href_list["print_p"])
var/info = "<CENTER><B>Medical Record</B></CENTER><BR>"
if ((istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1)))
info += text("Name: [] ID: []<BR>\nSex: []<BR>\nAge: []<BR>\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", src.active1.fields["name"], src.active1.fields["id"], src.active1.fields["sex"], src.active1.fields["age"], src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"])
else
info += "<B>General Record Lost!</B><BR>"
if ((istype(src.active2, /datum/data/record) && data_core.medical.Find(src.active2)))
info += text("<BR>\n<CENTER><B>Medical Data</B></CENTER><BR>\nBlood Type: []<BR>\n<BR>\nMinor Disabilities: []<BR>\nDetails: []<BR>\n<BR>\nMajor Disabilities: []<BR>\nDetails: []<BR>\n<BR>\nAllergies: []<BR>\nDetails: []<BR>\n<BR>\nCurrent Diseases: [] (per disease info placed in log/comment section)<BR>\nDetails: []<BR>\n<BR>\nImportant Notes:<BR>\n\t[]<BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", src.active2.fields["b_type"], src.active2.fields["mi_dis"], src.active2.fields["mi_dis_d"], src.active2.fields["ma_dis"], src.active2.fields["ma_dis_d"], src.active2.fields["alg"], src.active2.fields["alg_d"], src.active2.fields["cdi"], src.active2.fields["cdi_d"], src.active2.fields["notes"])
var/counter = 1
while(src.active2.fields[text("com_[]", counter)])
info += text("[]<BR>", src.active2.fields[text("com_[]", counter)])
counter++
else
info += "<B>Medical Record Lost!</B><BR>"
info += "</TT>"
var/datum/signal/signal = new
signal.data["data"] = info
signal.data["title"] = "Medical Record"
src.peripheral_command("print",signal)
src.master.add_fingerprint(usr)
src.master.updateUsrDialog()
return

View File

@@ -0,0 +1,96 @@
/datum/computer/file/computer_program/messenger
name = "Messenger"
size = 8.0
var/messages = null
var/screen_name = "User"
//To-do: take screen_name from inserted id card??
//Saving log to file datum
return_text()
if(..())
return
var/dat = "<a href='byond://?src=\ref[src];close=1'>Close</a> | "
dat += "<a href='byond://?src=\ref[src];quit=1'>Quit</a><br>"
dat += "<b>SpaceMessenger V4.1.2</b><br>"
dat += "<a href='byond://?src=\ref[src];send_msg=1'>Send Message</a>"
dat += " | <a href='byond://?src=\ref[src];func_msg=clear'>Clear</a>"
dat += " | <a href='byond://?src=\ref[src];func_msg=print'>Print</a>"
dat += " | Name:<a href='byond://?src=\ref[src];set_name=1'>[src.screen_name]</a><hr>"
dat += messages
dat += "</center>"
return dat
Topic(href, href_list)
if(..())
return
if(href_list["send_msg"])
var/t = input(usr, "Please enter messenger", src.id_tag, null) as text
t = copytext(sanitize(t), 1, MAX_MESSAGE_LEN)
if (!t)
return
if (!in_range(src.master, usr))
return
var/datum/signal/signal = new
signal.data["type"] = "message"
signal.data["data"] = t
signal.data["sender"] = src.screen_name
src.messages += "<i><b>&rarr; You:</b></i><br>[t]<br>"
peripheral_command("send signal", signal)
if(href_list["func_msg"])
switch(href_list["func_msg"])
if("clear")
src.messages = null
if("print")
var/datum/signal/signal = new
signal.data["data"] = src.messages
signal.data["title"] = "Chatlog"
peripheral_command("print", signal)
//if("save")
//TO-DO
if(href_list["set_name"])
var/t = input(usr, "Please enter screen name", src.id_tag, null) as text
t = copytext(sanitize(t), 1, 20)
if (!t)
return
if (!in_range(src.master, usr))
return
src.screen_name = t
src.master.add_fingerprint(usr)
src.master.updateUsrDialog()
return
receive_command(obj/source, command, datum/signal/signal)
if(..() || !signal)
return
if(command == "radio signal")
switch(signal.data["type"])
if("message")
var/sender = signal.data["sender"]
if(!sender)
sender = "Unknown"
src.messages += "<i><b>&larr; From [sender]:</b></i><br>[signal.data["data"]]<br>"
if(src.master.active_program == src)
playsound(src.master.loc, 'twobeep.ogg', 50, 1)
src.master.updateUsrDialog()
return

View File

@@ -0,0 +1,209 @@
/obj/item/weapon/peripheral
name = "Peripheral card"
desc = "A computer circuit board."
icon = 'module.dmi'
icon_state = "id_mod"
item_state = "electronic"
w_class = 2
var/obj/machinery/computer2/host
var/id = null
New()
..()
spawn(2)
if(istype(src.loc,/obj/machinery/computer2))
host = src.loc
host.peripherals.Add(src)
// var/setup_id = "\ref[src]"
// src.id = copytext(setup_id,4,(length(setup_id)-1) )
Del()
if(host)
host.peripherals.Remove(src)
..()
proc
receive_command(obj/source, command, datum/signal/signal)
if((source != host) || !(src in host))
return 1
if(!command)
return 1
return 0
send_command(command, datum/signal/signal)
if(!command || !host)
return
src.host.receive_command(src, command, signal)
return
/obj/item/weapon/peripheral/radio
name = "Wireless card"
var/frequency = 1419
var/code = null
var/datum/radio_frequency/radio_connection
New()
..()
if(radio_controller)
initialize()
initialize()
set_frequency(frequency)
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, "[frequency]")
frequency = new_frequency
radio_connection = radio_controller.add_object(src, "[frequency]")
receive_command(obj/source, command, datum/signal/signal)
if(..())
return
if(!signal || !radio_connection)
return
switch(command)
if("send signal")
src.radio_connection.post_signal(src, signal)
return
receive_signal(datum/signal/signal)
if(!signal || (signal.encryption && signal.encryption != code))
return
var/datum/signal/newsignal = new
newsignal.data = signal.data
if(src.code)
newsignal.encryption = src.code
send_command("radio signal",newsignal)
return
/obj/item/weapon/peripheral/printer
name = "Printer module"
desc = "A small printer designed to fit into a computer casing."
icon_state = "card_mod"
var/printing = 0
receive_command(obj/source,command, datum/signal/signal)
if(..())
return
if(!signal)
return
if((command == "print") && !src.printing)
src.printing = 1
var/print_data = signal.data["data"]
var/print_title = signal.data["title"]
if(!print_data)
src.printing = 0
return
spawn(50)
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( src.host.loc )
P.info = print_data
if(print_title)
P.name = "paper- '[print_title]'"
src.printing = 0
return
return
/obj/item/weapon/peripheral/prize_vendor
name = "Prize vending module"
desc = "An arcade prize dispenser designed to fit inside a computer casing."
icon_state = "power_mod"
var/last_vend = 0 //Delay between vends if manually activated(ie a dude is holding it and shaking stuff out)
receive_command(obj/source,command, datum/signal/signal)
if(..())
return
if(command == "vend prize")
src.vend_prize()
return
attack_self(mob/user as mob)
if( (last_vend + 400) < world.time)
user << "You shake something out of [src]!"
src.vend_prize()
src.last_vend = world.time
else
user << "\red [src] isn't ready to dispense a prize yet."
return
proc/vend_prize()
var/obj/item/prize
var/prizeselect = rand(1,4)
var/turf/prize_location = null
if(src.host)
prize_location = src.host.loc
else
prize_location = get_turf(src)
switch(prizeselect)
if(1)
prize = new /obj/item/weapon/spacecash( prize_location )
prize.name = "space ticket"
prize.desc = "It's almost like actual currency!"
if(2)
prize = new /obj/item/device/radio/beacon( prize_location )
prize.name = "electronic blink toy game"
prize.desc = "Blink. Blink. Blink."
if(3)
prize = new /obj/item/weapon/zippo( prize_location )
prize.name = "Burno Lighter"
prize.desc = "Almost like a decent lighter!"
if(4)
prize = new /obj/item/weapon/c_tube( prize_location )
prize.name = "toy sword"
prize.icon = 'weapons.dmi'
prize.icon_state = "sword1"
prize.desc = "A sword made of cheap plastic."
/*
/obj/item/weapon/peripheral/card_scanner
name = "ID scanner module"
icon_state = "card_mod"
var/obj/item/weapon/card/id/authid = null
attack_self(mob/user as mob)
if(authid)
user << "The card falls out."
src.authid.loc = get_turf(user)
src.authid = null
return
receive_command(obj/source,command, datum/signal/signal)
if(..())
return
if(!signal || (signal.data["ref_id"] != "\ref[src]") )
return
switch(command)
if("eject card")
if(src.authid)
src.authid.loc = src.host.loc
src.authid = null
if("add card access")
var/new_access = signal.data["access"]
if(!new_access)
return
return
*/

View File

@@ -0,0 +1,70 @@
/obj/effects/expl_particles
name = "fire"
icon = 'effects.dmi'
icon_state = "explosion_particle"
opacity = 1
anchored = 1
mouse_opacity = 0
/obj/effects/expl_particles/New()
..()
spawn (15)
del(src)
return
/obj/effects/expl_particles/Move()
..()
return
/datum/effects/system/expl_particles
var/number = 10
var/turf/location
var/total_particles = 0
/datum/effects/system/expl_particles/proc/set_up(n = 10, loca)
number = n
if(istype(loca, /turf/)) location = loca
else location = get_turf(loca)
/datum/effects/system/expl_particles/proc/start()
var/i = 0
for(i=0, i<src.number, i++)
spawn(0)
var/obj/effects/expl_particles/expl = new /obj/effects/expl_particles(src.location)
var/direct = pick(alldirs)
for(i=0, i<pick(1;25,2;50,3,4;200), i++)
sleep(1)
step(expl,direct)
/obj/effects/explosion
name = "fire"
icon = '96x96.dmi'
icon_state = "explosion"
opacity = 1
anchored = 1
mouse_opacity = 0
pixel_x = -32
pixel_y = -32
/obj/effects/explosion/New()
..()
spawn (10)
del(src)
return
/datum/effects/system/explosion
var/turf/location
/datum/effects/system/explosion/proc/set_up(loca)
if(istype(loca, /turf/)) location = loca
else location = get_turf(loca)
/datum/effects/system/explosion/proc/start()
new/obj/effects/explosion( location )
var/datum/effects/system/expl_particles/P = new/datum/effects/system/expl_particles()
P.set_up(10,location)
P.start()
spawn(5)
var/datum/effects/system/harmless_smoke_spread/S = new/datum/effects/system/harmless_smoke_spread()
S.set_up(5,0,location,null)
S.start()

View File

@@ -0,0 +1,179 @@
// the laser beam
/obj/beam/laser
name = "laser beam"
icon = 'beam.dmi'
icon_state = "full"
density = 0
mouse_opacity = 0
flags = TABLEPASS
var/wavelength // the (vaccuum) wavelength of the beam
var/width = 1 // 1=thin, 2=medium, 3=wide
var/obj/beam/laser/next
var/obj/beam/laser/prev
var/obj/master
New(var/atom/newloc, var/dirn, var/lambda, var/omega=1, var/half=0)
if(!isturf(loc))
return
//world << "creating beam at ([newloc.x],[newloc.y]) with [dirn] [lambda] [omega] [half]"
icon_state = "[omega]-[half ? "half" : "full"]"
dir = dirn
set_wavelength(lambda)
..(newloc)
spawn(0)
src.propagate()
src.verbs -= /atom/movable/verb/pull
proc/propagate()
var/turf/T = get_step(src, dir)
if(T)
if(T.Enter(src))
next = new(T, dir, wavelength, width, 0)
next.prev = src
next.master = src.master
else
spawn(5)
propagate()
proc/remove()
if(next)
next.remove()
del(src)
proc/blocked(var/atom/A)
return density || opacity
/*
/turf/Enter(atom/movable/mover as mob|obj)
if (!mover || !isturf(mover.loc))
return 1
//First, check objects to block exit that are not on the border
for(var/obj/obstacle in mover.loc)
if((obstacle.flags & ~ON_BORDER) && (mover != obstacle) && (forget != obstacle))
if(!obstacle.CheckExit(mover, src))
mover.Bump(obstacle, 1)
return 0
//Now, check objects to block exit that are on the border
for(var/obj/border_obstacle in mover.loc)
if((border_obstacle.flags & ON_BORDER) && (mover != border_obstacle) && (forget != border_obstacle))
if(!border_obstacle.CheckExit(mover, src))
mover.Bump(border_obstacle, 1)
return 0
//Next, check objects to block entry that are on the border
for(var/obj/border_obstacle in src)
if(border_obstacle.flags & ON_BORDER)
if(!border_obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != border_obstacle))
mover.Bump(border_obstacle, 1)
return 0
//Then, check the turf itself
if (!src.CanPass(mover, src))
mover.Bump(src, 1)
return 0
//Finally, check objects/mobs to block entry that are not on the border
for(var/atom/movable/obstacle in src)
if(obstacle.flags & ~ON_BORDER)
if(!obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != obstacle))
mover.Bump(obstacle, 1)
return 0
return 1 //Nothing found to block so return success!
*/
HasEntered(var/atom/movable/AM)
if(istype(AM, /obj/beam))
return
if(blocked(AM))
remove(src)
if(prev)
prev.propagate()
else if(master)
master:turn_on()
proc/set_wavelength(var/lambda)
var/w = round(lambda,1) // integer wavelength
wavelength = lambda
// first look for cached version of the icon at this wavelength
var/icon/cached = beam_icons["[w]"]
if(cached)
icon = cached
return
// no cached version, so generate a new one
// this maps a wavelength in the range 380-780 nm to an R,G,B,A value
var/red = 0
var/green = 0
var/blue = 0
var/alpha = 0
switch(w)
if(380 to 439)
red = (440-w) / 60
green = 0
blue = 1
if(440 to 489)
red = 0
green = (w-440) / 50
blue = 1
if(490 to 509)
red = 0
green = 1
blue = (510 - w) / 20
if(510 to 579)
red = (w-510) / 70
green = 1
blue = 0
if(580 to 644)
red = 1
green = (645-w) / 65
blue = 0
if(645 to 780)
red = 1
green = 0
blue = 0
// colour is done, now calculate intensity
switch(w)
if(380 to 419)
alpha = 0.75*(w-380)/40
if(420 to 700)
alpha = 0.75
if(701 to 780)
alpha = 0.75*(780-w)/80
// remap alpha by intensity gamma
if(alpha != 0)
alpha = alpha**0.80
var/icon/I = icon('beam.dmi')
I.MapColors(red,0,0,0, 0,green,0,0, 0,0,blue,0, 0,0,0,alpha, 0,0,0,0)
icon = I
beam_icons["[w]"] = I
// global cache of beam icons
// this is an assoc list mapping (integer) wavelength to icons
var/list/beam_icons = new()

View File

@@ -0,0 +1,72 @@
// A laser pointer. Emits a (tunable) low-power laser beam
// Used for alignment and testing of the optics system
/obj/item/device/laser_pointer
name = "laser pointer"
desc = "A portable low-power laser used for optical system alignment. The label reads: 'Danger: Class IIIa laser device. Avoid direct eye exposure."
icon = 'optics.dmi'
icon_state = "pointer0"
var/on = 0 // true if operating
var/wavelength = 632 // operation wavelength (nm)
var/gain_peak = 632 // gain peak (nm)
var/gain_width = 35 // gain bandwidth (nm)
var/peak_output = 0.005 // max output 5 mW
layer = OBJ_LAYER + 0.1
w_class = 4
m_amt = 500
g_amt = 100
w_amt = 200
var/obj/beam/laser/beam // the created beam
flags = FPRINT | CONDUCT | TABLEPASS
attack_ai()
return
attack_paw()
return
attack_self(var/mob/user)
on = !on
if(on)
turn_on()
else
turn_off()
updateicon()
verb/rotate()
set src in view(1)
turn_off()
dir = turn(dir, -90)
if(on) turn_on()
Move(var/atom/newloc,var/newdir)
. = ..(newloc,newdir)
if(on && . && isturf(newloc))
turn_off()
turn_on()
return .
proc/turn_on()
if(!isturf(loc))
return
beam = new(loc, dir, wavelength, 1, 1)
beam.master = src
proc/turn_off()
if(beam)
beam.remove()
dropped()
turn_off()
turn_on()
proc/updateicon()
icon_state = "pointer[on]"

View File

@@ -0,0 +1,83 @@
// Mirror object
// Part of the optics system
//
// reflects laser beams
// 16 directional states 0/22.5/45/67.5deg to allow for 0/45deg beam angles
// ideas:
// frame/stand icon w/ mirror directional overlay
// two sets of overlay icons for 0/45 and 22.5/67.5 deg angles
// can rotate cw/acw - need screwdriver to loosen/tighten mirror
// use wrench to anchor/unanchor frame
// if touched, gets dirty - fingerprints, which reduce reflectivity
// if dirty and hit with high-power beam, mirror may shatter
// some kind of dust accumulation with HasProximity? Could check for mob w/o labcoat etc.
// can clean with acetone+wipes
/obj/optical/mirror
icon = 'optical.dmi'
icon_state = "mirrorA"
dir = 1
desc = "A large, optical-grade mirror firmly mounted on a stand."
flags = FPRINT
anchored = 0
var/rotatable = 0 // true if mirror can be rotated
var/angle = 0 // normal of mirror, 0-15. 0=N, 1=NNE, 2=NE, 3=ENE, 4=E etc
New()
..()
set_angle()
//set the angle from icon_state and dir
proc/set_angle()
switch(dir)
if(1)
angle = 0
if(5)
angle = 2
if(4)
angle = 4
if(6)
angle = 6
if(2)
angle = 8
if(10)
angle = 10
if(8)
angle = 12
if(9)
angle = 14
if(icon_state == "mirrorB") // 22.5deg turned states
angle++
return
// set the dir and icon_state from the angle
proc/set_dir()
if(angle%2 == 1)
icon_state = "mirrorB"
else
icon_state = "mirrorA"
switch(round(angle/2)*2)
if(0)
dir = 1
if(2)
dir = 5
if(4)
dir = 4
if(6)
dir = 6
if(8)
dir = 2
if(10)
dir = 10
if(12)
dir = 8
if(14)
dir = 9
return

View File

@@ -0,0 +1,445 @@
/datum/computer/file/pda_program/os
proc
receive_os_command(list/command_list)
if((!src.holder) || (!src.master) || (!command_list) || !(command_list["command"]))
return 1
if((!istype(holder)) || (!istype(master)))
return 1
if(!(holder in src.master.contents))
if(master.active_program == src)
master.active_program = null
return 1
return 0
//Main os program: Provides old pda interface and four programs including file browser, notes, messenger, and atmos scan
main_os
name = "ThinkOS 7"
size = 8.0
var/mode = 0
//Note vars
var/note = "Congratulations, your station has chosen the Thinktronic 5150 Personal Data Assistant!"
var/note_mode = 0 //0 For note editor, 1 for note browser
var/datum/computer/file/text/note_file = null //If set, save to this file.
//Messenger vars
var/list/detected_pdas = list()
var/message_on = 1
var/message_silent = 0 //To beep or not to beep, that is the question
var/message_mode = 0 //0 for pda list, 1 for messages
var/message_tone = "beep" //Custom ringtone
var/message_note = null //Current messages in memory (Store as separate file only later??)
//File browser vars
var/datum/computer/folder/browse_folder = null
var/datum/computer/file/clipboard = null //Current file to copy
receive_os_command(list/command_list)
if(..())
return
//world << "[command_list["command"]]"
return
return_text()
if(..())
return
var/dat = src.return_text_header()
switch(src.mode)
if(0)
dat += "<h2>PERSONAL DATA ASSISTANT</h2>"
dat += "Owner: [src.master.owner]<br><br>"
dat += "<h4>General Functions</h4>"
dat += "<ul>"
dat += "<li><a href='byond://?src=\ref[src];mode=1'>Notekeeper</a></li>"
dat += "<li><a href='byond://?src=\ref[src];mode=2'>Messenger</a></li>"
dat += "<li><a href='byond://?src=\ref[src];mode=3'>File Browser</a></li>"
dat += "</ul>"
dat += "<h4>Utilities</h4>"
dat += "<ul>"
dat += "<li><a href='byond://?src=\ref[src];mode=4'>Atmospheric Scan</a></li>"
dat += "<li>Scanner: [src.master.scan_program ? "<a href='byond://?src=\ref[src];scanner=1'>[src.master.scan_program.name]</a>" : "None loaded"]</li>"
dat += "<li><a href='byond://?src=\ref[src];flight=1'>[src.master.fon ? "Disable" : "Enable"] Flashlight</a></li>"
dat += "</ul>"
if(1)
//Note Program. Can save/load note files.
dat += "<h4>Notekeeper V2.5</h4>"
if(!src.note_mode)
dat += "<a href='byond://?src=\ref[src];input=note'>Edit</a>"
dat += " | <a href='byond://?src=\ref[src];note_func=new'>New File</a>"
dat += " | <a href='byond://?src=\ref[src];note_func=save'>Save</a>"
dat += " | <a href='byond://?src=\ref[src];note_func=switchmenu'>Load</a><br>"
dat += src.note
else
dat += " <a href='byond://?src=\ref[src];note_func=switchmenu'>Back</a>"
dat += " | \[[src.holding_folder.holder.file_amount - src.holding_folder.holder.file_used]\] Free<br>"
dat += "<table cellspacing=5>"
for(var/datum/computer/file/text/T in src.holding_folder.contents)
dat += "<tr><td><a href='byond://?src=\ref[src];target=\ref[T];note_func=load'>[T.name]</a></td>"
dat += "<td>[T.extension]</td>"
dat += "<td>Length: [T.data ? (length(T.data)) : "0"]</td></tr>"
dat += "</table>"
if(2)
//Messenger. Uses Radio. Is a messenger.
//TO-DO: ~file sharing~
src.master.overlays = null //Remove existing alerts
dat += "<h4>SpaceMessenger V4.0.5</h4>"
if (!src.message_mode)
dat += "<a href='byond://?src=\ref[src];message_func=ringer'>Ringer: [src.message_silent == 1 ? "Off" : "On"]</a> | "
dat += "<a href='byond://?src=\ref[src];message_func=on'>Send / Receive: [src.message_on == 1 ? "On" : "Off"]</a> | "
dat += "<a href='byond://?src=\ref[src];input=tone'>Set Ringtone</a> | "
dat += "<a href='byond://?src=\ref[src];message_mode=1'>Messages</a><br>"
dat += "<font size=2><a href='byond://?src=\ref[src];message_func=scan'>Scan</a></font><br>"
dat += "<b>Detected PDAs</b><br>"
dat += "<ul>"
var/count = 0
if (src.message_on)
for (var/obj/item/device/pda2/P in src.detected_pdas)
if (!P.owner)
src.detected_pdas -= P
continue
else if (P == src) //I guess this can happen if somebody copies the system file.
src.detected_pdas -= P
continue
dat += "<li><a href='byond://?src=\ref[src];input=message;target=\ref[P]'>[P]</a>"
dat += "</li>"
count++
dat += "</ul>"
if (count == 0)
dat += "None detected.<br>"
else
dat += "<a href='byond://?src=\ref[src];message_func=clear'>Clear</a> | "
dat += "<a href='byond://?src=\ref[src];message_mode=0'>Back</a><br>"
dat += "<h4>Messages</h4>"
dat += src.message_note
dat += "<br>"
if(3)
//File Browser.
//To-do(?): Setting "favorite" programs to access straight from main menu
//Not sure how needed it is, not like they have to go through 500 subfolders or whatever
if((!src.browse_folder) || !(src.browse_folder.holder in src.master))
src.browse_folder = src.holding_folder
dat += " | <a href='byond://?src=\ref[src];target=\ref[src.browse_folder];browse_func=paste'>Paste</a>"
dat += " | Drive: "
dat += "\[<a href='byond://?src=\ref[src];browse_func=drive'>[src.browse_folder.holder == src.master.hd ? "MAIN" : "CART"]</a>\]<br>"
dat += "<b>Contents of [browse_folder] | Drive ID:\[[src.browse_folder.holder.title]]</b><br>"
dat += "<b>Used: \[[src.browse_folder.holder.file_used]/[src.browse_folder.holder.file_amount]\]</b><hr>"
dat += "<table cellspacing=5>"
for(var/datum/computer/file/F in browse_folder.contents)
if(F == src)
dat += "<tr><td>System</td><td>Size: [src.size]</td><td>SYSTEM</td></tr>"
continue
dat += "<tr><td><a href='byond://?src=\ref[src];target=\ref[F];browse_func=open'>[F.name]</a></td>"
dat += "<td>Size: [F.size]</td>"
dat += "<td>[F.extension]</td>"
dat += "<td><a href='byond://?src=\ref[src];target=\ref[F];browse_func=delete'>Del</a></td>"
dat += "<td><a href='byond://?src=\ref[src];target=\ref[F];input=rename'>Rename</a></td>"
dat += "<td><a href='byond://?src=\ref[src];target=\ref[F];browse_func=copy'>Copy</a></td>"
dat += "</tr>"
dat += "</table>"
if(4)
//Atmos Scanner
dat += "<h4>Atmospheric Readings</h4>"
var/turf/T = get_turf_or_move(get_turf(src.master))
if (isnull(T))
dat += "Unable to obtain a reading.<br>"
else
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
dat += "Air Pressure: [round(pressure,0.1)] kPa<br>"
if (total_moles)
var/o2_level = environment.oxygen/total_moles
var/n2_level = environment.nitrogen/total_moles
var/co2_level = environment.carbon_dioxide/total_moles
var/plasma_level = environment.toxins/total_moles
var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level)
dat += "Nitrogen: [round(n2_level*100)]%<br>"
dat += "Oxygen: [round(o2_level*100)]%<br>"
dat += "Carbon Dioxide: [round(co2_level*100)]%<br>"
dat += "Plasma: [round(plasma_level*100)]%<br>"
if(unknown_level > 0.01)
dat += "OTHER: [round(unknown_level)]%<br>"
dat += "Temperature: [round(environment.temperature-T0C)]&deg;C<br>"
dat += "<br>"
return dat
Topic(href, href_list)
if(..())
return
if(href_list["mode"])
var/newmode = text2num(href_list["mode"])
src.mode = max(newmode, 0)
else if(href_list["flight"])
src.master.toggle_light()
else if(href_list["scanner"])
if(src.master.scan_program)
src.master.scan_program = null
else if(href_list["input"])
switch(href_list["input"])
if("tone")
var/t = input(usr, "Please enter new ringtone", src.name, src.message_tone) as text
if (!t)
return
if (!src.master || !in_range(src.master, usr) && src.master.loc != usr)
return
if(!(src.holder in src.master))
return
t = copytext(sanitize(t), 1, 20)
src.message_tone = t
if("note")
var/t = input(usr, "Please enter note", src.name, src.note) as message
if (!t)
return
if (!src.master || !in_range(src.master, usr) && src.master.loc != usr)
return
if(!(src.holder in src.master))
return
t = copytext(adminscrub(t), 1, MAX_MESSAGE_LEN)
src.note = t
if("message")
var/obj/item/device/pda2/P = locate(href_list["target"])
if(!P || !istype(P))
return
var/t = input(usr, "Please enter message", P.name, null) as text
if (!t)
return
if (!src.master || !in_range(src.master, usr) && src.master.loc != usr)
return
if(!(src.holder in src.master))
return
var/datum/signal/signal = new
signal.data["command"] = "text message"
signal.data["message"] = t
signal.data["sender"] = src.master.owner
signal.data["tag"] = "\ref[P]"
src.post_signal(signal)
src.message_note += "<i><b>&rarr; To [P.owner]:</b></i><br>[t]<br>"
if("rename")
var/datum/computer/file/F = locate(href_list["target"])
if(!F || !istype(F))
return
var/t = input(usr, "Please enter new name", src.name, F.name) as text
t = copytext(sanitize(t), 1, 16)
if (!t)
return
if (!in_range(src.master, usr) || !(F.holder in src.master))
return
if(F.holder.read_only)
return
F.name = capitalize(lowertext(t))
else if(href_list["message_func"]) //Messenger specific topic junk
switch(href_list["message_func"])
if("ringer")
src.message_silent = !src.message_silent
if("on")
src.message_on = !src.message_on
if("clear")
src.message_note = null
if("scan")
if(src.message_on)
src.detected_pdas = list()
var/datum/signal/signal = new
signal.data["command"] = "report pda"
src.post_signal(signal)
else if(href_list["note_func"]) //Note program specific topic junk
switch(href_list["note_func"])
if("new")
src.note_file = null
src.note = null
if("save")
if(src.note_file && src.note_file.holder in src.master)
src.note_file.data = src.note
else
var/datum/computer/file/text/F = new /datum/computer/file/text
if(!src.holding_folder.add_file(F))
del(F)
else
src.note_file = F
F.data = src.note
if("load")
var/datum/computer/file/text/T = locate(href_list["target"])
if(!T || !istype(T))
return
src.note_file = T
src.note = note_file.data
src.note_mode = 0
if("switchmenu")
src.note_mode = !src.note_mode
else if(href_list["browse_func"]) //File browser specific topic junk
var/datum/computer/target = locate(href_list["target"])
switch(href_list["browse_func"])
if("drive")
if(src.browse_folder.holder == src.master.hd && src.master.cartridge && (src.master.cartridge.root))
src.browse_folder = src.master.cartridge.root
else
src.browse_folder = src.holding_folder
if("open")
if(!target || !istype(target))
return
if(istype(target, /datum/computer/file/pda_program))
if(istype(target,/datum/computer/file/pda_program/os) && (src.master.host_program))
return
else
src.master.run_program(target)
src.master.updateSelfDialog()
return
if("delete")
if(!target || !istype(target))
return
src.master.delete_file(target)
if("copy")
if(istype(target,/datum/computer/file) && (!target.holder || (target.holder in src.master.contents)))
src.clipboard = target
if("paste")
if(istype(target,/datum/computer/folder))
if(!src.clipboard || !src.clipboard.holder || !(src.clipboard.holder in src.master.contents))
return
if(!istype(src.clipboard))
return
src.clipboard.copy_file_to_folder(target)
else if(href_list["message_mode"])
var/newmode = text2num(href_list["message_mode"])
src.message_mode = max(newmode, 0)
src.master.add_fingerprint(usr)
src.master.updateSelfDialog()
return
receive_signal(datum/signal/signal)
if(..())
return
switch(signal.data["command"])
if("text message")
if(!message_on || !signal.data["message"])
return
var/sender = signal.data["sender"]
if(!sender)
sender = "!Unknown!"
src.message_note += "<i><b>&larr; From <a href='byond://?src=\ref[src];input=message;target=\ref[signal.source]'>[sender]</a>:</b></i><br>[signal.data["message"]]<br>"
var/alert_beep = null //Don't beep if set to silent.
if(!src.message_silent)
alert_beep = src.message_tone
src.master.display_alert(alert_beep)
src.master.updateSelfDialog()
if("report pda")
if(!message_on)
return
var/datum/signal/newsignal = new
newsignal.data["command"] = "reporting pda"
newsignal.data["tag"] = "\ref[signal.source]"
src.post_signal(newsignal)
if("reporting pda")
if(!detected_pdas)
detected_pdas = new()
if(!(signal.source in detected_pdas))
detected_pdas += signal.source
src.master.updateSelfDialog()
return
return_text_header()
if(!src.master)
return
var/dat
if(src.mode)
dat += " | <a href='byond://?src=\ref[src];mode=0'>Main Menu</a>"
else if (!isnull(src.master.cartridge))
dat += " | <a href='byond://?src=\ref[src.master];eject_cart=1'>Eject [src.master.cartridge]</a>"
dat += " | <a href='byond://?src=\ref[src.master];refresh=1'>Refresh</a>"
return dat

View File

@@ -0,0 +1,185 @@
//Eventual plan: Convert all datum/data to datum/computer/file
/datum/computer/file/text
name = "text"
extension = "TEXT"
size = 2.0
var/data = null
/datum/computer/file/record
name = "record"
extension = "REC"
var/list/fields = list( )
//base pda program
/datum/computer/file/pda_program
name = "blank program"
extension = "PPROG"
var/obj/item/device/pda2/master = null
var/id_tag = null
os
name = "blank system program"
extension = "PSYS"
scan
name = "blank scan program"
extension = "PSCAN"
New(obj/holding as obj)
if(holding)
src.holder = holding
if(istype(src.holder.loc,/obj/item/device/pda2))
src.master = src.holder.loc
proc
return_text()
if((!src.holder) || (!src.master))
return 1
if((!istype(holder)) || (!istype(master)))
return 1
if(!(holder in src.master.contents))
//world << "Holder [holder] not in [master] of prg:[src]"
if(master.active_program == src)
master.active_program = null
return 1
if(!src.holder.root)
src.holder.root = new /datum/computer/folder
src.holder.root.holder = src
src.holder.root.name = "root"
return 0
process() //This isn't actually used at the moment
if((!src.holder) || (!src.master))
return 1
if((!istype(holder)) || (!istype(master)))
return 1
if(!(holder in src.master.contents))
if(master.active_program == src)
master.active_program = null
return 1
if(!src.holder.root)
src.holder.root = new /datum/computer/folder
src.holder.root.holder = src
src.holder.root.name = "root"
return 0
//maybe remove this, I haven't found a good use for it yet
send_os_command(list/command_list)
if(!src.master || !src.holder || src.master.host_program || !command_list)
return 1
if(!istype(src.master.host_program) || src.master.host_program == src)
return 1
src.master.host_program.receive_os_command()
return 0
return_text_header()
if(!src.master || !src.holder)
return
var/dat = " | <a href='byond://?src=\ref[src];quit=1'>Main Menu</a>"
dat += " | <a href='byond://?src=\ref[src.master];refresh=1'>Refresh</a>"
return dat
post_signal(datum/signal/signal, newfreq)
if(master)
master.post_signal(signal, newfreq)
else
del(signal)
transfer_holder(obj/item/weapon/disk/data/newholder,datum/computer/folder/newfolder)
if((newholder.file_used + src.size) > newholder.file_amount)
return 0
if(!newholder.root)
newholder.root = new /datum/computer/folder
newholder.root.holder = newholder
newholder.root.name = "root"
if(!newfolder)
newfolder = newholder.root
if((src.holder && src.holder.read_only) || newholder.read_only)
return 0
if((src.holder) && (src.holder.root))
src.holder.root.remove_file(src)
newfolder.add_file(src)
if(istype(newholder.loc,/obj/item/device/pda2))
src.master = newholder.loc
//world << "Setting [src.holder] to [newholder]"
src.holder = newholder
return 1
receive_signal(datum/signal/signal)
if((!src.holder) || (!src.master))
return 1
if((!istype(holder)) || (!istype(master)))
return 1
if(!(holder in src.master.contents))
if(master.active_program == src)
master.active_program = null
return 1
return 0
Topic(href, href_list)
if((!src.holder) || (!src.master))
return 1
if((!istype(holder)) || (!istype(master)))
return 1
if(src.master.active_program != src)
return 1
if ((!usr.contents.Find(src.master) && (!in_range(src.master, usr) || !istype(src.master.loc, /turf))) && (!istype(usr, /mob/living/silicon)))
return 1
if(!(holder in src.master.contents))
if(master.active_program == src)
master.active_program = null
return 1
usr.machine = src.master
if (href_list["close"])
usr.machine = null
usr << browse(null, "window=pda2")
return 0
if (href_list["quit"])
// src.master.processing_programs.Remove(src)
if(src.master.host_program && src.master.host_program.holder && (src.master.host_program.holder in src.master.contents))
src.master.run_program(src.master.host_program)
src.master.updateSelfDialog()
return 1
else
src.master.active_program = null
src.master.updateSelfDialog()
return 1
return 0

View File

@@ -0,0 +1,297 @@
//The advanced pea-green monochrome lcd of tomorrow.
//TO-DO: rearrange all this disk/data stuff so that fixed disks are the parent type
//because otherwise you have carts going into floppy drives and it's ALL MAD
/obj/item/weapon/disk/data/cartridge
name = "Cart 2.0"
desc = "A data cartridge for portable microcomputers."
icon = 'pda.dmi'
icon_state = "cart"
item_state = "electronic"
file_amount = 80.0
title = "ROM Cart"
pda2test
name = "Test Cart"
New()
..()
src.root.add_file( new /datum/computer/file/computer_program/arcade(src))
src.root.add_file( new /datum/computer/file/pda_program/manifest(src))
src.root.add_file( new /datum/computer/file/pda_program/status_display(src))
src.root.add_file( new /datum/computer/file/pda_program/signaler(src))
src.root.add_file( new /datum/computer/file/pda_program/qm_records(src))
src.root.add_file( new /datum/computer/file/pda_program/scan/health_scan(src))
src.root.add_file( new /datum/computer/file/pda_program/records/security(src))
src.root.add_file( new /datum/computer/file/pda_program/records/medical(src))
src.read_only = 1
/obj/item/device/pda2
name = "PDA"
desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by an EEPROM cartridge."
icon = 'pda.dmi'
icon_state = "pda"
item_state = "electronic"
w_class = 2.0
flags = FPRINT | TABLEPASS | ONBELT
var/owner = null
var/default_cartridge = null // Access level defined by cartridge
var/obj/item/weapon/disk/data/cartridge/cartridge = null //current cartridge
var/datum/computer/file/pda_program/active_program = null
var/datum/computer/file/pda_program/os/host_program = null
var/datum/computer/file/pda_program/scan/scan_program = null
var/obj/item/weapon/disk/data/fixed_disk/hd = null
var/fon = 0 //Is the flashlight function on?
var/f_lum = 3 //Luminosity for the flashlight function
// var/datum/data/record/active1 = null //General
// var/datum/data/record/active2 = null //Medical
// var/datum/data/record/active3 = null //Security
// var/obj/item/weapon/integrated_uplink/uplink = null //Maybe replace uplink with some remote ~syndicate~ server
var/frequency = 1149
var/datum/radio_frequency/radio_connection
var/setup_default_cartridge = null //Cartridge contains job-specific programs
var/setup_drive_size = 24.0 //PDAs don't have much work room at all, really.
var/setup_system_os_path = /datum/computer/file/pda_program/os/main_os //Needs an operating system to...operate!!
/obj/item/device/pda2/pickup(mob/user)
if (src.fon)
src.sd_SetLuminosity(0)
user.sd_SetLuminosity(user.luminosity + src.f_lum)
/obj/item/device/pda2/dropped(mob/user)
if (src.fon)
user.sd_SetLuminosity(user.luminosity - src.f_lum)
src.sd_SetLuminosity(src.f_lum)
/obj/item/device/pda2/New()
..()
spawn(5)
src.hd = new /obj/item/weapon/disk/data/fixed_disk(src)
src.hd.file_amount = src.setup_drive_size
src.hd.name = "Minidrive"
src.hd.title = "Minidrive"
if(src.setup_system_os_path)
src.host_program = new src.setup_system_os_path
src.hd.file_amount = max(src.hd.file_amount, src.host_program.size)
src.host_program.transfer_holder(src.hd)
if(radio_controller)
radio_controller.add_object(src, "[frequency]")
if (src.default_cartridge)
src.cartridge = new src.setup_default_cartridge(src)
// if(src.owner)
// processing_items.Add(src)
/obj/item/device/pda2/attack_self(mob/user as mob)
user.machine = src
var/dat = "<html><head><title>Personal Data Assistant</title></head><body>"
dat += "<a href='byond://?src=\ref[src];close=1'>Close</a>"
if (!src.owner)
if(src.cartridge)
dat += " | <a href='byond://?src=\ref[src];eject_cart=1'>Eject [src.cartridge]</a>"
dat += "<br>Warning: No owner information entered. Please swipe card.<br><br>"
dat += "<a href='byond://?src=\ref[src];refresh=1'>Retry</a>"
else
if(src.active_program)
dat += src.active_program.return_text()
else
if(src.host_program)
src.run_program(src.host_program)
dat += src.active_program.return_text()
else
if(src.cartridge)
dat += " | <a href='byond://?src=\ref[src];eject_cart=1'>Eject [src.cartridge]</a><br>"
dat += "<center><font color=red>Fatal Error 0x17<br>"
dat += "No System Software Loaded</font></center>"
//To-do: System recovery shit (maybe have a dedicated computer for this kind of thing)
user << browse(dat,"window=pda2")
onclose(user,"pda2")
return
/obj/item/device/pda2/Topic(href, href_list)
..()
if (usr.contents.Find(src) || usr.contents.Find(src.master) || (istype(src.loc, /turf) && get_dist(src, usr) <= 1))
if (usr.stat || usr.restrained())
return
src.add_fingerprint(usr)
usr.machine = src
if(href_list["return_to_host"])
if(src.host_program)
src.active_program = src.host_program
src.host_program = null
else if (href_list["eject_cart"])
src.eject_cartridge()
else if (href_list["refresh"])
src.updateSelfDialog()
else if (href_list["close"])
usr << browse(null, "window=pda2")
usr.machine = null
src.updateSelfDialog()
return
/obj/item/device/pda2/attackby(obj/item/weapon/C as obj, mob/user as mob)
if (istype(C, /obj/item/weapon/disk/data/cartridge) && isnull(src.cartridge))
user.drop_item()
C.loc = src
user << "\blue You insert [C] into [src]."
src.cartridge = C
src.updateSelfDialog()
else if (istype(C, /obj/item/weapon/card/id) && !src.owner && C:registered)
src.owner = C:registered
src.name = "PDA-[src.owner]"
user << "\blue Card scanned."
src.updateSelfDialog()
/obj/item/device/pda2/receive_signal(datum/signal/signal)
if(!signal || signal.encryption || !src.owner) return
if(signal.data["tag"] && signal.data["tag"] != "\ref[src]") return
if(src.host_program)
src.host_program.receive_signal(signal)
if(src.active_program && (src.active_program != src.host_program))
src.host_program.receive_signal(signal)
return
/obj/item/device/pda2/attack(mob/M as mob, mob/user as mob)
if(src.scan_program)
return
else
..()
/obj/item/device/pda2/afterattack(atom/A as mob|obj|turf|area, mob/user as mob)
var/scan_dat = null
if(src.scan_program && istype(src.scan_program))
scan_dat = src.scan_program.scan_atom(A)
if(scan_dat)
A.visible_message("\red [user] has scanned [A]!")
user.show_message(scan_dat, 1)
return
/obj/item/device/pda2/proc
post_signal(datum/signal/signal,var/newfreq)
if(!signal)
return
var/freq = newfreq
if(!freq)
freq = src.frequency
signal.source = src
var/datum/radio_frequency/frequency = radio_controller.return_frequency("[freq]")
signal.transmission_method = TRANSMISSION_RADIO
if(frequency)
return frequency.post_signal(src, signal)
else
del(signal)
eject_cartridge()
if(src.cartridge)
var/turf/T = get_turf(src)
if(src.active_program && (src.active_program.holder == src.cartridge))
src.active_program = null
if(src.host_program && (src.host_program.holder == src.cartridge))
src.host_program = null
if(src.scan_program && (src.scan_program.holder == src.cartridge))
src.scan_program = null
src.cartridge.loc = T
src.cartridge = null
return
//Toggle the built-in flashlight
toggle_light()
src.fon = (!src.fon)
if (ismob(src.loc))
if (src.fon)
src.loc.sd_SetLuminosity(src.loc.luminosity + src.f_lum)
else
src.loc.sd_SetLuminosity(src.loc.luminosity - src.f_lum)
else
src.sd_SetLuminosity(src.fon * src.f_lum)
src.updateSelfDialog()
display_alert(var/alert_message) //Add alert overlay and beep
if (alert_message)
playsound(src.loc, 'twobeep.ogg', 50, 1)
for (var/mob/O in hearers(3, src.loc))
O.show_message(text("\icon[src] *[alert_message]*"))
src.overlays = null
src.overlays += image('pda.dmi', "pda-r")
return
run_program(datum/computer/file/pda_program/program)
if((!program) || (!program.holder))
return 0
if(!(program.holder in src))
// world << "Not in src"
program = new program.type
program.transfer_holder(src.hd)
if(program.master != src)
program.master = src
if(!src.host_program && istype(program, /datum/computer/file/pda_program/os))
src.host_program = program
if(istype(program, /datum/computer/file/pda_program/scan))
if(program == src.scan_program)
src.scan_program = null
else
src.scan_program = program
return 1
src.active_program = program
return 1
delete_file(datum/computer/file/file)
//world << "Deleting [file]..."
if((!file) || (!file.holder) || (file.holder.read_only))
//world << "Cannot delete :("
return 0
//Don't delete the running program you jerk
if(src.active_program == file || src.host_program == file)
src.active_program = null
//world << "Now calling del on [file]..."
del(file)
return 1

View File

@@ -0,0 +1,181 @@
//CONTENTS:
//Generic records
//Security records
//Medical records
/datum/computer/file/pda_program/records
var/mode = 0
var/datum/data/record/active1 = null //General
var/datum/data/record/active2 = null //Security/Medical/Whatever
//To-do: editing arrest status/etc from pda.
/datum/computer/file/pda_program/records/security
name = "Security Records"
size = 12.0
return_text()
if(..())
return
var/dat = src.return_text_header()
switch(src.mode)
if(0)
dat += "<h4>Security Record List</h4>"
for (var/datum/data/record/R in data_core.general)
dat += "<a href='byond://?src=\ref[src];select_rec=\ref[R]'>[R.fields["id"]]: [R.fields["name"]]<br>"
dat += "<br>"
if(1)
dat += "<h4>Security Record</h4>"
dat += "<a href='byond://?src=\ref[src];mode=0'>Back</a><br>"
if (istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1))
dat += "Name: [src.active1.fields["name"]] ID: [src.active1.fields["id"]]<br>"
dat += "Sex: [src.active1.fields["sex"]]<br>"
dat += "Age: [src.active1.fields["age"]]<br>"
dat += "Fingerprint: [src.active1.fields["fingerprint"]]<br>"
dat += "Physical Status: [src.active1.fields["p_stat"]]<br>"
dat += "Mental Status: [src.active1.fields["m_stat"]]<br>"
else
dat += "<b>Record Lost!</b><br>"
dat += "<br>"
dat += "<h4>Security Data</h4>"
if (istype(src.active2, /datum/data/record) && data_core.security.Find(src.active2))
dat += "Criminal Status: [src.active2.fields["criminal"]]<br>"
dat += "Minor Crimes: [src.active2.fields["mi_crim"]]<br>"
dat += "Details: [src.active2.fields["mi_crim"]]<br><br>"
dat += "Major Crimes: [src.active2.fields["ma_crim"]]<br>"
dat += "Details: [src.active2.fields["ma_crim_d"]]<br><br>"
dat += "Important Notes:<br>"
dat += "[src.active2.fields["notes"]]"
else
dat += "<b>Record Lost!</b><br>"
dat += "<br>"
return dat
Topic(href, href_list)
if(..())
return
if(href_list["mode"])
var/newmode = text2num(href_list["mode"])
src.mode = max(newmode, 0)
else if(href_list["select_rec"])
var/datum/data/record/R = locate(href_list["select_rec"])
var/datum/data/record/S = locate(href_list["select_rec"])
if (data_core.general.Find(R))
for (var/datum/data/record/E in data_core.security)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
S = E
break
src.active1 = R
src.active2 = S
src.mode = 1
src.master.add_fingerprint(usr)
src.master.updateSelfDialog()
return
/datum/computer/file/pda_program/records/medical
name = "Medical Records"
size = 8.0
return_text()
if(..())
return
var/dat = src.return_text_header()
switch(src.mode)
if(0)
dat += "<h4>Medical Record List</h4>"
for (var/datum/data/record/R in data_core.general)
dat += "<a href='byond://?src=\ref[src];select_rec=\ref[R]'>[R.fields["id"]]: [R.fields["name"]]<br>"
dat += "<br>"
if(1)
dat += "<h4>Medical Record</h4>"
dat += "<a href='byond://?src=\ref[src];mode=0'>Back</a><br>"
if (istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1))
dat += "Name: [src.active1.fields["name"]] ID: [src.active1.fields["id"]]<br>"
dat += "Sex: [src.active1.fields["sex"]]<br>"
dat += "Age: [src.active1.fields["age"]]<br>"
dat += "Fingerprint: [src.active1.fields["fingerprint"]]<br>"
dat += "Physical Status: [src.active1.fields["p_stat"]]<br>"
dat += "Mental Status: [src.active1.fields["m_stat"]]<br>"
else
dat += "<b>Record Lost!</b><br>"
dat += "<br>"
dat += "<h4>Medical Data</h4>"
if (istype(src.active2, /datum/data/record) && data_core.medical.Find(src.active2))
dat += "Blood Type: [src.active2.fields["b_type"]]<br><br>"
dat += "Minor Disabilities: [src.active2.fields["mi_dis"]]<br>"
dat += "Details: [src.active2.fields["mi_dis_d"]]<br><br>"
dat += "Major Disabilities: [src.active2.fields["ma_dis"]]<br>"
dat += "Details: [src.active2.fields["ma_dis_d"]]<br><br>"
dat += "Allergies: [src.active2.fields["alg"]]<br>"
dat += "Details: [src.active2.fields["alg_d"]]<br><br>"
dat += "Current Diseases: [src.active2.fields["cdi"]]<br>"
dat += "Details: [src.active2.fields["cdi_d"]]<br><br>"
dat += "Important Notes: [src.active2.fields["notes"]]<br>"
else
dat += "<b>Record Lost!</b><br>"
dat += "<br>"
return dat
Topic(href, href_list)
if(..())
return
if(href_list["mode"])
var/newmode = text2num(href_list["mode"])
src.mode = max(newmode, 0)
else if(href_list["select_rec"])
var/datum/data/record/R = locate(href_list["select_rec"])
var/datum/data/record/M = locate(href_list["select_rec"])
if (data_core.general.Find(R))
for (var/datum/data/record/E in data_core.medical)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
M = E
break
src.active1 = R
src.active2 = M
src.mode = 1
src.master.add_fingerprint(usr)
src.master.updateSelfDialog()
return

View File

@@ -0,0 +1,101 @@
//CONTENTS:
//Base scanner stuff
//Health scanner
//Forensic scanner
//Reagent scanner
/datum/computer/file/pda_program/scan
return_text()
return src.return_text_header()
proc/scan_atom(atom/A as mob|obj|turf|area)
if( !A || (!src.holder) || (!src.master))
return 1
if((!istype(holder)) || (!istype(master)))
return 1
if(!(holder in src.master.contents))
if(master.scan_program == src)
master.scan_program = null
return 1
return 0
//Health analyzer program
health_scan
name = "Health Scan"
size = 8.0
scan_atom(atom/A as mob|obj|turf|area)
if(..())
return
var/mob/living/carbon/C = A
if(!istype(C))
return
var/dat = "\blue Analyzing Results for [C]:\n"
dat += "\blue \t Overall Status: [C.stat > 1 ? "dead" : "[C.health]% healthy"]\n"
dat += "\blue \t Damage Specifics: [C.oxyloss > 50 ? "\red" : "\blue"][C.oxyloss]-[C.toxloss > 50 ? "\red" : "\blue"][C.toxloss]-[C.fireloss > 50 ? "\red" : "\blue"][C.fireloss]-[C.bruteloss > 50 ? "\red" : "\blue"][C.bruteloss]\n"
dat += "\blue \t Key: Suffocation/Toxin/Burns/Brute\n"
dat += "\blue \t Body Temperature: [C.bodytemperature-T0C]&deg;C ([C.bodytemperature*1.8-459.67]&deg;F)"
if(C.virus)
dat += "\red \n<b>Warning Virus Detected.</b>\nName: [C.virus.name].\nType: [C.virus.spread].\nStage: [C.virus.stage]/[C.virus.max_stages].\nPossible Cure: [C.virus.cure]"
return dat
//Forensic scanner
forensic_scan
name = "Forensic Scan"
size = 8.0
scan_atom(atom/A as mob|obj|turf|area)
if(..())
return
var/dat = null
if(istype(A,/mob/living/carbon/human))
var/mob/living/carbon/human/H = A
if (!istype(H.dna, /datum/dna) || !isnull(H.gloves))
dat += "\blue Unable to scan [A]'s fingerprints.\n"
else
dat += "\blue [H]'s Fingerprints: [md5(H.dna.uni_identity)]\n"
if ( !(H.blood_DNA) )
dat += "\blue No blood found on [H]\n"
else
dat += "\blue Blood type: [H.blood_type]\nDNA: [H.blood_DNA]\n"
if (!A.fingerprints)
dat += "\blue Unable to locate any fingerprints on [A]!\n"
else
var/list/L = params2list(A:fingerprints)
dat += "\blue Isolated [L.len] fingerprints.\n"
for(var/i in L)
dat += "\blue \t [i]\n"
return dat
//Reagent scanning program
reagent_scan
name = "Reagent Scan"
size = 6.0
scan_atom(atom/A as mob|obj|turf|area)
if(..())
return
var/dat = null
if(!isnull(A.reagents))
if(A.reagents.reagent_list.len > 0)
var/reagents_length = A.reagents.reagent_list.len
dat += "\blue [reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.\n"
for (var/datum/reagent/re in A.reagents.reagent_list)
dat += "\blue \t [re] - [re.volume]\n"
else
dat = "\blue No active chemical agents found in [A]."
else
dat = "\blue No significant chemical agents found in [A]."
return dat

View File

@@ -0,0 +1,204 @@
//Assorted small programs not worthy of their own file
//CONTENTS:
//Crew Manifest viewer
//Status display controller
//Remote signaling program
//Cargo orders monitor
//Manifest
/datum/computer/file/pda_program/manifest
name = "Manifest"
return_text()
if(..())
return
var/dat = src.return_text_header()
dat += "<h4>Crew Manifest</h4>"
dat += "Entries cannot be modified from this terminal.<br><br>"
for (var/datum/data/record/t in data_core.general)
dat += "[t.fields["name"]] - [t.fields["rank"]]<br>"
dat += "<br>"
return dat
//Status Display
/datum/computer/file/pda_program/status_display
name = "Status Controller"
size = 8.0
var/message1 // For custom messages on the displays.
var/message2
return_text()
if(..())
return
var/dat = src.return_text_header()
dat += "<h4>Station Status Display Interlink</h4>"
dat += "\[ <A HREF='?src=\ref[src];statdisp=blank'>Clear</A> \]<BR>"
dat += "\[ <A HREF='?src=\ref[src];statdisp=shuttle'>Shuttle ETA</A> \]<BR>"
dat += "\[ <A HREF='?src=\ref[src];statdisp=message'>Message</A> \]"
dat += "<ul><li> Line 1: <A HREF='?src=\ref[src];statdisp=setmsg1'>[ message1 ? message1 : "(none)"]</A>"
dat += "<li> Line 2: <A HREF='?src=\ref[src];statdisp=setmsg2'>[ message2 ? message2 : "(none)"]</A></ul><br>"
dat += "\[ Alert: <A HREF='?src=\ref[src];statdisp=alert;alert=default'>None</A> |"
dat += " <A HREF='?src=\ref[src];statdisp=alert;alert=redalert'>Red Alert</A> |"
dat += " <A HREF='?src=\ref[src];statdisp=alert;alert=lockdown'>Lockdown</A> |"
dat += " <A HREF='?src=\ref[src];statdisp=alert;alert=biohazard'>Biohazard</A> \]<BR>"
return dat
Topic(href, href_list)
if(..())
return
if(href_list["statdisp"])
switch(href_list["statdisp"])
if("message")
post_status("message", message1, message2)
if("alert")
post_status("alert", href_list["alert"])
if("setmsg1")
message1 = input("Line 1", "Enter Message Text", message1) as text|null
if (!src.master || !in_range(src.master, usr) && src.master.loc != usr)
return
if(!(src.holder in src.master))
return
src.master.updateSelfDialog()
if("setmsg2")
message2 = input("Line 2", "Enter Message Text", message2) as text|null
if (!src.master || !in_range(src.master, usr) && src.master.loc != usr)
return
if(!(src.holder in src.master))
return
src.master.updateSelfDialog()
else
post_status(href_list["statdisp"])
src.master.add_fingerprint(usr)
src.master.updateSelfDialog()
return
proc/post_status(var/command, var/data1, var/data2)
if(!src.master)
return
var/datum/signal/status_signal = new
status_signal.source = src.master
status_signal.transmission_method = 1
status_signal.data["command"] = command
switch(command)
if("message")
status_signal.data["msg1"] = data1
status_signal.data["msg2"] = data2
if("alert")
status_signal.data["picture_state"] = data1
src.post_signal(status_signal,"1435")
//Signaler
/datum/computer/file/pda_program/signaler
name = "Signalix 5"
size = 8.0
var/send_freq = 1457 //Frequency signal is sent at, should be kept within normal radio ranges.
var/send_code = 30
var/last_transmission = 0 //No signal spamming etc
return_text()
if(..())
return
var/dat = src.return_text_header()
dat += "<h4>Remote Signaling System</h4>"
dat += {"
<a href='byond://?src=\ref[src];send=1'>Send Signal</A><BR>
Frequency:
<a href='byond://?src=\ref[src];adj_freq=-10'>-</a>
<a href='byond://?src=\ref[src];adj_freq=-2'>-</a>
[format_frequency(send_freq)]
<a href='byond://?src=\ref[src];adj_freq=2'>+</a>
<a href='byond://?src=\ref[src];adj_freq=10'>+</a><br>
<br>
Code:
<a href='byond://?src=\ref[src];adj_code=-5'>-</a>
<a href='byond://?src=\ref[src];adj_code=-1'>-</a>
[send_code]
<a href='byond://?src=\ref[src];adj_code=1'>+</a>
<a href='byond://?src=\ref[src];adj_code=5'>+</a><br>"}
return dat
Topic(href, href_list)
if(..())
return
if (href_list["send"])
if(last_transmission && world.time < (last_transmission + 5))
return
last_transmission = world.time
spawn( 0 )
var/time = time2text(world.realtime,"hh:mm:ss")
lastsignalers.Add("[time] <B>:</B> [usr.key] used [src.master] @ location ([src.master.loc.x],[src.master.loc.y],[src.master.loc.z]) <B>:</B> [format_frequency(send_freq)]/[send_code]")
var/datum/signal/signal = new
signal.source = src
signal.encryption = send_code
signal.data["message"] = "ACTIVATE"
src.post_signal(signal,"[send_freq]")
return
else if (href_list["adj_freq"])
src.send_freq = sanitize_frequency(src.send_freq + text2num(href_list["adj_freq"]))
else if (href_list["adj_code"])
src.send_code += text2num(href_list["adj_code"])
src.send_code = round(src.send_code)
src.send_code = min(100, src.send_code)
src.send_code = max(1, src.send_code)
src.master.add_fingerprint(usr)
src.master.updateSelfDialog()
return
//Supply record monitor
/datum/computer/file/pda_program/qm_records
name = "Supply Records"
size = 8.0
return_text()
if(..())
return
var/dat = src.return_text_header()
dat += "<h4>Supply Record Interlink</h4>"
dat += "<BR><B>Supply shuttle</B><BR>"
dat += "Location: [supply_shuttle_moving ? "Moving to station ([supply_shuttle_timeleft] Mins.)":supply_shuttle_at_station ? "Station":"Dock"]<BR>"
dat += "Current approved orders: <BR><ol>"
for(var/S in supply_shuttle_shoppinglist)
var/datum/supply_order/SO = S
dat += "<li>[SO.object.name] approved by [SO.orderedby] [SO.comment ? "([SO.comment])":""]</li>"
dat += "</ol>"
dat += "Current requests: <BR><ol>"
for(var/S in supply_shuttle_requestlist)
var/datum/supply_order/SO = S
dat += "<li>[SO.object.name] requested by [SO.orderedby]</li>"
dat += "</ol><font size=\"-3\">Upgrade NOW to Space Parts & Space Vendors PLUS for full remote order control and inventory management."
return dat

View File

@@ -0,0 +1,18 @@
/*
/obj/plant
name = "plant"
icon = 'plants.dmi'
flags = FPRINT | TABLEPASS
var/health = 100
var/bruteloss = 0
var/toxloss = 0
var/generation = 1
var/life_stage = 0
var/datum/disease/virus = null
/obj/item/seedpacket
name = "seed packet"
icon = 'plants.dmi'
icon_state = "packet"
flags = FPRINT | TABLEPASS
*/

View File

@@ -0,0 +1,389 @@
// converyor belt
// moves items/mobs/movables in set direction every ptick
/obj/machinery/conveyor
icon = 'recycling.dmi'
icon_state = "conveyor0"
name = "conveyor belt"
desc = "A conveyor belt."
anchored = 1
var/operating = 0 // 1 if running forward, -1 if backwards, 0 if off
var/operable = 1 // true if can operate (no broken segments in this belt run)
var/basedir // this is the default (forward) direction, set by the map dir
// note dir var can vary when the direction changes
var/list/affecting // the list of all items that will be moved this ptick
var/id = "" // the control ID - must match controller ID
// following two only used if a diverter is present
var/divert = 0 // if non-zero, direction to divert items
var/divdir = 0 // if diverting, will be conveyer dir needed to divert (otherwise dense)
// create a conveyor
/obj/machinery/conveyor/New()
..()
basedir = dir
setdir()
// set the dir and target turf depending on the operating direction
/obj/machinery/conveyor/proc/setdir()
if(operating == -1)
dir = turn(basedir,180)
else
dir = basedir
update()
// update the icon depending on the operating condition
/obj/machinery/conveyor/proc/update()
if(stat & BROKEN)
icon_state = "conveyor-b"
operating = 0
return
if(!operable)
operating = 0
icon_state = "conveyor[(operating != 0) && !(stat & NOPOWER)]"
// machine process
// move items to the target location
/obj/machinery/conveyor/process()
if(stat & (BROKEN | NOPOWER))
return
if(!operating)
return
use_power(100)
var/movedir = dir // base movement dir
if(divert && dir==divdir) // update if diverter present
movedir = divert
affecting = loc.contents - src // moved items will be all in loc
spawn(1) // slight delay to prevent infinite propagation due to map order
for(var/atom/movable/A in affecting)
if(!A.anchored)
if(ismob(A))
var/mob/M = A
if(M.buckled == src)
var/obj/machinery/conveyor/C = locate() in get_step(src, dir)
M.buckled = null
step(M,dir)
if(C)
M.buckled = C
else
new/obj/item/weapon/cable_coil/cut(M.loc)
else
step(M,movedir)
else
step(A,movedir)
// attack with item, place item on conveyor
/obj/machinery/conveyor/attackby(var/obj/item/I, mob/user)
if(istype(I, /obj/item/weapon/grab)) // special handling if grabbing a mob
var/obj/item/weapon/grab/G = I
G.affecting.Move(src.loc)
del(G)
return
else if(istype(I, /obj/item/weapon/cable_coil)) // if cable, see if a mob is present
var/mob/M = locate() in src.loc
if(M)
if (M == user)
src.visible_message("\blue [M] ties \himself to the conveyor.")
// note don't check for lying if self-tying
else
if(M.lying)
user.visible_message("\blue [M] has been tied to the conveyor by [user].", "\blue You tie [M] to the converyor!")
else
user << "\blue [M] must be lying down to be tied to the converyor!"
return
M.buckled = src
src.add_fingerprint(user)
I:use(1)
M.lying = 1
return
// else if no mob in loc, then allow coil to be placed
else if(istype(I, /obj/item/weapon/wirecutters))
var/mob/M = locate() in src.loc
if(M && M.buckled == src)
M.buckled = null
src.add_fingerprint(user)
if (M == user)
src.visible_message("\blue [M] cuts \himself free from the conveyor.")
else
src.visible_message("\blue [M] had been cut free from the conveyor by [user].")
return
// otherwise drop and place on conveyor
user.drop_item()
if(I && I.loc) I.loc = src.loc
return
// attack with hand, move pulled object onto conveyor
/obj/machinery/conveyor/attack_hand(mob/user as mob)
if ((!( user.canmove ) || user.restrained() || !( user.pulling )))
return
if (user.pulling.anchored)
return
if ((user.pulling.loc != user.loc && get_dist(user, user.pulling) > 1))
return
if (ismob(user.pulling))
var/mob/M = user.pulling
M.pulling = null
step(user.pulling, get_dir(user.pulling.loc, src))
user.pulling = null
else
step(user.pulling, get_dir(user.pulling.loc, src))
user.pulling = null
return
// make the conveyor broken
// also propagate inoperability to any connected conveyor with the same ID
/obj/machinery/conveyor/proc/broken()
stat |= BROKEN
update()
var/obj/machinery/conveyor/C = locate() in get_step(src, basedir)
if(C)
C.set_operable(basedir, id, 0)
C = locate() in get_step(src, turn(basedir,180))
if(C)
C.set_operable(turn(basedir,180), id, 0)
//set the operable var if ID matches, propagating in the given direction
/obj/machinery/conveyor/proc/set_operable(stepdir, match_id, op)
if(id != match_id)
return
operable = op
update()
var/obj/machinery/conveyor/C = locate() in get_step(src, stepdir)
if(C)
C.set_operable(stepdir, id, op)
/*
/obj/machinery/conveyor/verb/destroy()
set src in view()
src.broken()
*/
/obj/machinery/conveyor/power_change()
..()
update()
// converyor diverter
// extendable arm that can be switched so items on the conveyer are diverted sideways
// situate in same turf as conveyor
// only works if belts is running proper direction
//
//
/obj/machinery/diverter
icon = 'recycling.dmi'
icon_state = "diverter0"
name = "diverter"
desc = "A diverter arm for a conveyor belt."
anchored = 1
layer = FLY_LAYER
var/obj/machinery/conveyor/conv // the conveyor this diverter works on
var/deployed = 0 // true if diverter arm is extended
var/operating = 0 // true if arm is extending/contracting
var/divert_to // the dir that diverted items will be moved
var/divert_from // the dir items must be moving to divert
// create a diverter
// set up divert_to and divert_from directions depending on dir state
/obj/machinery/diverter/New()
..()
switch(dir)
if(NORTH)
divert_to = WEST // stuff will be moved to the west
divert_from = NORTH // if entering from the north
if(SOUTH)
divert_to = EAST
divert_from = NORTH
if(EAST)
divert_to = EAST
divert_from = SOUTH
if(WEST)
divert_to = WEST
divert_from = SOUTH
if(NORTHEAST)
divert_to = NORTH
divert_from = EAST
if(NORTHWEST)
divert_to = NORTH
divert_from = WEST
if(SOUTHEAST)
divert_to = SOUTH
divert_from = EAST
if(SOUTHWEST)
divert_to = SOUTH
divert_from = WEST
spawn(2)
// wait for map load then find the conveyor in this turf
conv = locate() in src.loc
if(conv) // divert_from dir must match possible conveyor movement
if(conv.basedir != divert_from && conv.basedir != turn(divert_from,180) )
del(src) // if no dir match, then delete self
set_divert()
update()
// update the icon state depending on whether the diverter is extended
/obj/machinery/diverter/proc/update()
icon_state = "diverter[deployed]"
// call to set the diversion vars of underlying conveyor
/obj/machinery/diverter/proc/set_divert()
if(conv)
if(deployed)
conv.divert = divert_to
conv.divdir = divert_from
else
conv.divert= 0
// *** TESTING click to toggle
/obj/machinery/diverter/Click()
toggle()
// toggle between arm deployed and not deployed, showing animation
//
/obj/machinery/diverter/proc/toggle()
if( stat & (NOPOWER|BROKEN))
return
if(operating)
return
use_power(50)
operating = 1
if(deployed)
flick("diverter10",src)
icon_state = "diverter0"
sleep(10)
deployed = 0
else
flick("diverter01",src)
icon_state = "diverter1"
sleep(10)
deployed = 1
operating = 0
update()
set_divert()
// don't allow movement into the 'backwards' direction if deployed
/obj/machinery/diverter/CanPass(atom/movable/O, var/turf/target)
var/direct = get_dir(O, target)
if(direct == divert_to) // prevent movement through body of diverter
return 0
if(!deployed)
return 1
return(direct != turn(divert_from,180))
// don't allow movement through the arm if deployed
/obj/machinery/diverter/CheckExit(atom/movable/O, var/turf/target)
var/direct = get_dir(O, target)
if(direct == turn(divert_to,180)) // prevent movement through body of diverter
return 0
if(!deployed)
return 1
return(direct != divert_from)
// the conveyor control switch
//
//
/obj/machinery/conveyor_switch
name = "conveyor switch"
desc = "A conveyor control switch."
icon = 'recycling.dmi'
icon_state = "switch-off"
var/position = 0 // 0 off, -1 reverse, 1 forward
var/last_pos = -1 // last direction setting
var/operated = 1 // true if just operated
var/id = "" // must match conveyor IDs to control them
var/list/conveyors // the list of converyors that are controlled by this switch
anchored = 1
/obj/machinery/conveyor_switch/New()
..()
update()
spawn(5) // allow map load
conveyors = list()
for(var/obj/machinery/conveyor/C in world)
if(C.id == id)
conveyors += C
// update the icon depending on the position
/obj/machinery/conveyor_switch/proc/update()
if(position<0)
icon_state = "switch-rev"
else if(position>0)
icon_state = "switch-fwd"
else
icon_state = "switch-off"
// timed process
// if the switch changed, update the linked conveyors
/obj/machinery/conveyor_switch/process()
if(!operated)
return
operated = 0
for(var/obj/machinery/conveyor/C in conveyors)
C.operating = position
C.setdir()
// attack with hand, switch position
/obj/machinery/conveyor_switch/attack_hand(mob/user)
if(position == 0)
if(last_pos < 0)
position = 1
last_pos = 0
else
position = -1
last_pos = 0
else
last_pos = position
position = 0
operated = 1
update()
// find any switches with same id as this one, and set their positions to match us
for(var/obj/machinery/conveyor_switch/S in world)
if(S.id == src.id)
S.position = position
S.update()

View File

@@ -0,0 +1,162 @@
// Disposal pipe construction
/obj/disposalconstruct
name = "disposal pipe segment"
desc = "A huge pipe segment used for constructing disposal systems."
icon = 'disposal.dmi'
icon_state = "conpipe-s"
anchored = 0
density = 1
pressure_resistance = 5*ONE_ATMOSPHERE
m_amt = 1850
level = 2
var/ptype = 0
// 0=straight, 1=bent, 2=junction-j1, 3=junction-j2, 4=junction-y, 5=trunk
var/dpdir = 0 // directions as disposalpipe
var/base_state = "pipe-s"
// update iconstate and dpdir due to dir and type
proc/update()
var/flip = turn(dir, 180)
var/left = turn(dir, 90)
var/right = turn(dir, -90)
switch(ptype)
if(0)
base_state = "pipe-s"
dpdir = dir | flip
if(1)
base_state = "pipe-c"
dpdir = dir | right
if(2)
base_state = "pipe-j1"
dpdir = dir | right | flip
if(3)
base_state = "pipe-j2"
dpdir = dir | left | flip
if(4)
base_state = "pipe-y"
dpdir = dir | left | right
if(5)
base_state = "pipe-t"
dpdir = dir
icon_state = "con[base_state]"
if(invisibility) // if invisible, fade icon
icon -= rgb(0,0,0,128)
// hide called by levelupdate if turf intact status changes
// change visibility status and force update of icon
hide(var/intact)
invisibility = (intact && level==1) ? 101: 0 // hide if floor is intact
update()
// flip and rotate verbs
verb/rotate()
set src in view(1)
if(usr.stat)
return
if(anchored)
usr << "You must unfasten the pipe before rotating it."
dir = turn(dir, -90)
update()
verb/flip()
set src in view(1)
if(usr.stat)
return
if(anchored)
usr << "You must unfasten the pipe before flipping it."
dir = turn(dir, 180)
if(ptype == 2)
ptype = 3
else if(ptype == 3)
ptype = 2
update()
// returns the type path of disposalpipe corresponding to this item dtype
proc/dpipetype()
switch(ptype)
if(0,1)
return /obj/disposalpipe/segment
if(2,3,4)
return /obj/disposalpipe/junction
if(5)
return /obj/disposalpipe/trunk
return
// attackby item
// wrench: (un)anchor
// weldingtool: convert to real pipe
attackby(var/obj/item/I, var/mob/user)
var/turf/T = src.loc
if(T.intact)
user << "You can only attach the pipe if the floor plating is removed."
return
var/obj/disposalpipe/CP = locate() in T
if(CP)
update()
var/pdir = CP.dpdir
if(istype(CP, /obj/disposalpipe/broken))
pdir = CP.dir
if(pdir & dpdir)
user << "There is already a pipe at that location."
return
if(istype(I, /obj/item/weapon/wrench))
if(anchored)
anchored = 0
level = 2
density = 1
user << "You detach the pipe from the underfloor."
else
anchored = 1
level = 1
density = 0
user << "You attach the pipe to the underfloor."
playsound(src.loc, 'Ratchet.ogg', 100, 1)
else if(istype(I, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/W = I
if(W.welding)
if(W.get_fuel() > 2)
W.use_fuel(2)
playsound(src.loc, 'Welder2.ogg', 100, 1)
// check if anything changed over 2 seconds
var/turf/uloc = user.loc
var/atom/wloc = W.loc
user << "Welding the pipe in place."
sleep(20)
if(user.loc == uloc && wloc == W.loc)
update()
var/pipetype = dpipetype()
var/obj/disposalpipe/P = new pipetype(src.loc)
P.base_icon_state = base_state
P.dir = dir
P.dpdir = dpdir
P.updateicon()
del(src)
else
user << "You must stay still while welding."
return
else
user << "You need more welding fuel to complete this task."
return

View File

@@ -0,0 +1,936 @@
// Disposal bin
// Holds items for disposal into pipe system
// Draws air from turf, gradually charges internal reservoir
// Once full (~1 atm), uses air resv to flush items into the pipes
// Automatically recharges air (unless off), will flush when ready if pre-set
// Can hold items and human size things, no other draggables
/obj/machinery/disposal
name = "disposal unit"
desc = "A pneumatic waste disposal unit."
icon = 'disposal.dmi'
icon_state = "disposal"
anchored = 1
density = 1
var/datum/gas_mixture/air_contents // internal reservoir
var/mode = 1 // item mode 0=off 1=charging 2=charged
var/flush = 0 // true if flush handle is pulled
var/obj/disposalpipe/trunk/trunk = null // the attached pipe trunk
var/flushing = 0 // true if flushing in progress
// create a new disposal
// find the attached trunk (if present) and init gas resvr.
New()
..()
spawn(5)
trunk = locate() in src.loc
if(!trunk)
mode = 0
flush = 0
else
trunk.linked = src // link the pipe trunk to self
air_contents = new/datum/gas_mixture()
//gas.volume = 1.05 * CELLSTANDARD
update()
// attack by item places it in to disposal
attackby(var/obj/item/I, var/mob/user)
if(stat & BROKEN)
return
var/obj/item/weapon/grab/G = I
if(istype(G)) // handle grabbed mob
if(ismob(G.affecting))
var/mob/GM = G.affecting
if (GM.client)
GM.client.perspective = EYE_PERSPECTIVE
GM.client.eye = src
GM.loc = src
for (var/mob/C in viewers(src))
C.show_message("\red [GM.name] has been placed in the [src] by [user].", 3)
del(G)
else
user.drop_item()
I.loc = src
user << "You place \the [I] into the [src]."
for(var/mob/M in viewers(src))
if(M == user)
continue
M.show_message("[user.name] places \the [I] into the [src].", 3)
update()
// mouse drop another mob or self
//
MouseDrop_T(mob/target, mob/user)
if (!istype(target) || target.buckled || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai))
return
var/msg
if(target == user && !user.stat) // if drop self, then climbed in
// must be awake
msg = "[user.name] climbs into the [src]."
user << "You climb into the [src]."
else if(target != user && !user.restrained())
msg = "[user.name] stuffs [target.name] into the [src]!"
user << "You stuff [target.name] into the [src]!"
else
return
if (target.client)
target.client.perspective = EYE_PERSPECTIVE
target.client.eye = src
target.loc = src
for (var/mob/C in viewers(src))
if(C == user)
continue
C.show_message(msg, 3)
update()
return
// can breath normally in the disposal
alter_health()
return get_turf(src)
// attempt to move while inside
relaymove(mob/user as mob)
if(user.stat || src.flushing)
return
src.go_out(user)
return
// leave the disposal
proc/go_out(mob/user)
if (user.client)
user.client.eye = user.client.mob
user.client.perspective = MOB_PERSPECTIVE
user.loc = src.loc
update()
return
// monkeys can only pull the flush lever
attack_paw(mob/user as mob)
if(stat & BROKEN)
return
flush = !flush
update()
return
// ai as human but can't flush
attack_ai(mob/user as mob)
interact(user, 1)
// human interact with machine
attack_hand(mob/user as mob)
interact(user, 0)
// user interaction
proc/interact(mob/user, var/ai=0)
src.add_fingerprint(user)
if(stat & BROKEN)
user.machine = null
return
var/dat = "<head><title>Waste Disposal Unit</title></head><body><TT><B>Waste Disposal Unit</B><HR>"
if(!ai) // AI can't pull flush handle
if(flush)
dat += "Disposal handle: <A href='?src=\ref[src];handle=0'>Disengage</A> <B>Engaged</B>"
else
dat += "Disposal handle: <B>Disengaged</B> <A href='?src=\ref[src];handle=1'>Engage</A>"
dat += "<BR><HR><A href='?src=\ref[src];eject=1'>Eject contents</A><HR>"
if(mode == 0)
dat += "Pump: <B>Off</B> <A href='?src=\ref[src];pump=1'>On</A><BR>"
else if(mode == 1)
dat += "Pump: <A href='?src=\ref[src];pump=0'>Off</A> <B>On</B> (pressurizing)<BR>"
else
dat += "Pump: <A href='?src=\ref[src];pump=0'>Off</A> <B>On</B> (idle)<BR>"
var/per = 100* air_contents.return_pressure() / (2*ONE_ATMOSPHERE)
dat += "Pressure: [round(per, 1)]%<BR></body>"
user.machine = src
user << browse(dat, "window=disposal;size=360x170")
onclose(user, "disposal")
// handle machine interaction
Topic(href, href_list)
..()
src.add_fingerprint(usr)
if(stat & BROKEN)
return
if(usr.stat || usr.restrained() || src.flushing)
return
if (in_range(src, usr) && istype(src.loc, /turf))
usr.machine = src
if(href_list["close"])
usr.machine = null
usr << browse(null, "window=disposal")
return
if(href_list["pump"])
if(text2num(href_list["pump"]))
mode = 1
else
mode = 0
update()
if(href_list["handle"])
flush = text2num(href_list["handle"])
update()
if(href_list["eject"])
eject()
else
usr << browse(null, "window=disposal")
usr.machine = null
return
return
// eject the contents of the disposal unit
proc/eject()
for(var/atom/movable/AM in src)
AM.loc = src.loc
AM.pipe_eject(0)
update()
// update the icon & overlays to reflect mode & status
proc/update()
overlays = null
if(stat & BROKEN)
icon_state = "disposal-broken"
mode = 0
flush = 0
return
// flush handle
if(flush)
overlays += image('disposal.dmi', "dispover-handle")
// only handle is shown if no power
if(stat & NOPOWER)
return
// check for items in disposal - occupied light
if(contents.len > 0)
overlays += image('disposal.dmi', "dispover-full")
// charging and ready light
if(mode == 1)
overlays += image('disposal.dmi', "dispover-charge")
else if(mode == 2)
overlays += image('disposal.dmi', "dispover-ready")
// timed process
// charge the gas reservoir and perform flush if ready
process()
if(stat & BROKEN) // nothing can happen if broken
return
src.updateDialog()
if(flush && air_contents.return_pressure() >= 2*ONE_ATMOSPHERE) // flush can happen even without power
flush()
if(stat & NOPOWER) // won't charge if no power
return
use_power(100) // base power usage
if(mode != 1) // if off or ready, no need to charge
return
// otherwise charge
use_power(500) // charging power usage
var/atom/L = loc // recharging from loc turf
var/datum/gas_mixture/env = L.return_air()
var/pressure_delta = (ONE_ATMOSPHERE*2.1) - air_contents.return_pressure()
if(env.temperature > 0)
var/transfer_moles = 0.1 * pressure_delta*air_contents.volume/(env.temperature * R_IDEAL_GAS_EQUATION)
//Actually transfer the gas
var/datum/gas_mixture/removed = env.remove(transfer_moles)
air_contents.merge(removed)
// if full enough, switch to ready mode
if(air_contents.return_pressure() >= 2*ONE_ATMOSPHERE)
mode = 2
update()
return
// perform a flush
proc/flush()
flushing = 1
flick("disposal-flush", src)
var/obj/disposalholder/H = new() // virtual holder object which actually
// travels through the pipes.
H.init(src) // copy the contents of disposer to holder
air_contents = new() // new empty gas resv.
sleep(10)
playsound(src, 'disposalflush.ogg', 50, 0, 0)
sleep(5) // wait for animation to finish
H.start(src) // start the holder processing movement
flushing = 0
// now reset disposal state
flush = 0
if(mode == 2) // if was ready,
mode = 1 // switch to charging
update()
return
// called when area power changes
power_change()
..() // do default setting/reset of stat NOPOWER bit
update() // update icon
return
// called when holder is expelled from a disposal
// should usually only occur if the pipe network is modified
proc/expel(var/obj/disposalholder/H)
var/turf/target
playsound(src, 'hiss.ogg', 50, 0, 0)
for(var/atom/movable/AM in H)
target = get_offset_target_turf(src.loc, rand(5)-rand(5), rand(5)-rand(5))
AM.loc = src.loc
AM.pipe_eject(0)
spawn(1)
if(AM)
AM.throw_at(target, 5, 1)
H.vent_gas(loc)
del(H)
// virtual disposal object
// travels through pipes in lieu of actual items
// contents will be items flushed by the disposal
// this allows the gas flushed to be tracked
/obj/disposalholder
invisibility = 101
var/datum/gas_mixture/gas = null // gas used to flush, will appear at exit point
var/active = 0 // true if the holder is moving, otherwise inactive
dir = 0
var/count = 1000 //*** can travel 1000 steps before going inactive (in case of loops)
var/has_fat_guy = 0 // true if contains a fat person
// initialize a holder from the contents of a disposal unit
proc/init(var/obj/machinery/disposal/D)
gas = D.air_contents // transfer gas resv. into holder object
// now everything inside the disposal gets put into the holder
// note AM since can contain mobs or objs
for(var/atom/movable/AM in D)
AM.loc = src
if(istype(AM, /mob/living/carbon/human))
var/mob/living/carbon/human/H = AM
if(H.mutations & 32) // is a human and fat?
has_fat_guy = 1 // set flag on holder
// start the movement process
// argument is the disposal unit the holder started in
proc/start(var/obj/machinery/disposal/D)
if(!D.trunk)
D.expel(src) // no trunk connected, so expel immediately
return
loc = D.trunk
active = 1
dir = DOWN
spawn(1)
process() // spawn off the movement process
return
// movement process, persists while holder is moving through pipes
proc/process()
var/obj/disposalpipe/last
while(active)
if(has_fat_guy && prob(2)) // chance of becoming stuck per segment if contains a fat guy
active = 0
// find the fat guys
for(var/mob/living/carbon/human/H in src)
break
sleep(1) // was 1
var/obj/disposalpipe/curr = loc
last = curr
curr = curr.transfer(src)
if(!curr)
last.expel(src, loc, dir)
//
if(!(count--))
active = 0
return
// find the turf which should contain the next pipe
proc/nextloc()
return get_step(loc,dir)
// find a matching pipe on a turf
proc/findpipe(var/turf/T)
if(!T)
return null
var/fdir = turn(dir, 180) // flip the movement direction
for(var/obj/disposalpipe/P in T)
if(fdir & P.dpdir) // find pipe direction mask that matches flipped dir
return P
// if no matching pipe, return null
return null
// merge two holder objects
// used when a a holder meets a stuck holder
proc/merge(var/obj/disposalholder/other)
for(var/atom/movable/AM in other)
AM.loc = src // move everything in other holder to this one
if(ismob(AM))
var/mob/M = AM
if(M.client) // if a client mob, update eye to follow this holder
M.client.eye = src
if(other.has_fat_guy)
has_fat_guy = 1
del(other)
// called when player tries to move while in a pipe
relaymove(mob/user as mob)
if (user.stat)
return
for (var/mob/M in hearers(src.loc.loc))
M << "<FONT size=[max(0, 5 - get_dist(src, M))]>CLONG, clong!</FONT>"
playsound(src.loc, 'clang.ogg', 50, 0, 0)
// called to vent all gas in holder to a location
proc/vent_gas(var/atom/location)
location.assume_air(gas) // vent all gas to turf
return
// Disposal pipes
/obj/disposalpipe
icon = 'disposal.dmi'
name = "disposal pipe"
desc = "An underfloor disposal pipe."
anchored = 1
density = 0
level = 1 // underfloor only
var/dpdir = 0 // bitmask of pipe directions
dir = 0 // dir will contain dominant direction for junction pipes
var/health = 10 // health points 0-10
layer = 2.4 // slightly lower than wires
var/base_icon_state // initial icon state on map
// new pipe, set the icon_state as on map
New()
..()
base_icon_state = icon_state
return
// pipe is deleted
// ensure if holder is present, it is expelled
Del()
var/obj/disposalholder/H = locate() in src
if(H)
// holder was present
H.active = 0
var/turf/T = src.loc
if(T.density)
// deleting pipe is inside a dense turf (wall)
// this is unlikely, but just dump out everything into the turf in case
for(var/atom/movable/AM in H)
AM.loc = T
AM.pipe_eject(0)
del(H)
..()
return
// otherswise, do normal expel from turf
expel(H, T, 0)
..()
// returns the direction of the next pipe object, given the entrance dir
// by default, returns the bitmask of remaining directions
proc/nextdir(var/fromdir)
return dpdir & (~turn(fromdir, 180))
// transfer the holder through this pipe segment
// overriden for special behaviour
//
proc/transfer(var/obj/disposalholder/H)
var/nextdir = nextdir(H.dir)
H.dir = nextdir
var/turf/T = H.nextloc()
var/obj/disposalpipe/P = H.findpipe(T)
if(P)
// find other holder in next loc, if inactive merge it with current
var/obj/disposalholder/H2 = locate() in P
if(H2 && !H2.active)
H.merge(H2)
H.loc = P
else // if wasn't a pipe, then set loc to turf
H.loc = T
return null
return P
// update the icon_state to reflect hidden status
proc/update()
var/turf/T = src.loc
hide(T.intact && !istype(T,/turf/space)) // space never hides pipes
// hide called by levelupdate if turf intact status changes
// change visibility status and force update of icon
hide(var/intact)
invisibility = intact ? 101: 0 // hide if floor is intact
updateicon()
// update actual icon_state depending on visibility
// if invisible, append "f" to icon_state to show faded version
// this will be revealed if a T-scanner is used
// if visible, use regular icon_state
proc/updateicon()
if(invisibility)
icon_state = "[base_icon_state]f"
else
icon_state = base_icon_state
return
// expel the held objects into a turf
// called when there is a break in the pipe
//
proc/expel(var/obj/disposalholder/H, var/turf/T, var/direction)
var/turf/target
if(T.density) // dense ouput turf, so stop holder
H.active = 0
H.loc = src
return
if(T.intact && istype(T,/turf/simulated/floor)) //intact floor, pop the tile
var/turf/simulated/floor/F = T
//F.health = 100
F.burnt = 1
F.intact = 0
F.levelupdate()
new /obj/item/weapon/tile(H) // add to holder so it will be thrown with other stuff
F.icon_state = "Floor[F.burnt ? "1" : ""]"
if(direction) // direction is specified
if(istype(T, /turf/space)) // if ended in space, then range is unlimited
target = get_edge_target_turf(T, direction)
else // otherwise limit to 10 tiles
target = get_ranged_target_turf(T, direction, 10)
playsound(src, 'hiss.ogg', 50, 0, 0)
for(var/atom/movable/AM in H)
AM.loc = T
AM.pipe_eject(direction)
spawn(1)
if(AM)
AM.throw_at(target, 100, 1)
H.vent_gas(T)
del(H)
else // no specified direction, so throw in random direction
playsound(src, 'hiss.ogg', 50, 0, 0)
for(var/atom/movable/AM in H)
target = get_offset_target_turf(T, rand(5)-rand(5), rand(5)-rand(5))
AM.loc = T
AM.pipe_eject(0)
spawn(1)
if(AM)
AM.throw_at(target, 5, 1)
H.vent_gas(T) // all gas vent to turf
del(H)
return
// call to break the pipe
// will expel any holder inside at the time
// then delete the pipe
// remains : set to leave broken pipe pieces in place
proc/broken(var/remains = 0)
if(remains)
for(var/D in cardinal)
if(D & dpdir)
var/obj/disposalpipe/broken/P = new(src.loc)
P.dir = D
src.invisibility = 101 // make invisible (since we won't delete the pipe immediately)
var/obj/disposalholder/H = locate() in src
if(H)
// holder was present
H.active = 0
var/turf/T = src.loc
if(T.density)
// broken pipe is inside a dense turf (wall)
// this is unlikely, but just dump out everything into the turf in case
for(var/atom/movable/AM in H)
AM.loc = T
AM.pipe_eject(0)
del(H)
return
// otherswise, do normal expel from turf
expel(H, T, 0)
spawn(2) // delete pipe after 2 ticks to ensure expel proc finished
del(src)
// pipe affected by explosion
ex_act(severity)
switch(severity)
if(1.0)
broken(0)
return
if(2.0)
health -= rand(5,15)
healthcheck()
return
if(3.0)
health -= rand(0,15)
healthcheck()
return
// test health for brokenness
proc/healthcheck()
if(health < -2)
broken(0)
else if(health<1)
broken(1)
return
//attack by item
//weldingtool: unfasten and convert to obj/disposalconstruct
attackby(var/obj/item/I, var/mob/user)
var/turf/T = src.loc
if(T.intact)
return // prevent interaction with T-scanner revealed pipes
if(istype(I, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/W = I
if(W.welding)
if(W.get_fuel() > 3)
W.use_fuel(3)
playsound(src.loc, 'Welder2.ogg', 100, 1)
// check if anything changed over 2 seconds
var/turf/uloc = user.loc
var/atom/wloc = W.loc
user << "Slicing the disposal pipe."
sleep(30)
if(user.loc == uloc && wloc == W.loc)
welded()
else
user << "You must stay still while welding the pipe."
return
else
user << "You need more welding fuel to cut the pipe."
return
// called when pipe is cut with welder
proc/welded()
var/obj/disposalconstruct/C = new (src.loc)
switch(base_icon_state)
if("pipe-s")
C.ptype = 0
if("pipe-c")
C.ptype = 1
if("pipe-j1")
C.ptype = 2
if("pipe-j2")
C.ptype = 3
if("pipe-y")
C.ptype = 4
if("pipe-t")
C.ptype = 5
C.dir = dir
C.update()
del(src)
// *** TEST verb
//client/verb/dispstop()
// for(var/obj/disposalholder/H in world)
// H.active = 0
// a straight or bent segment
/obj/disposalpipe/segment
icon_state = "pipe-s"
New()
..()
if(icon_state == "pipe-s")
dpdir = dir | turn(dir, 180)
else
dpdir = dir | turn(dir, -90)
update()
return
//a three-way junction with dir being the dominant direction
/obj/disposalpipe/junction
icon_state = "pipe-j1"
New()
..()
if(icon_state == "pipe-j1")
dpdir = dir | turn(dir, -90) | turn(dir,180)
else if(icon_state == "pipe-j2")
dpdir = dir | turn(dir, 90) | turn(dir,180)
else // pipe-y
dpdir = dir | turn(dir,90) | turn(dir, -90)
update()
return
// next direction to move
// if coming in from secondary dirs, then next is primary dir
// if coming in from primary dir, then next is equal chance of other dirs
nextdir(var/fromdir)
var/flipdir = turn(fromdir, 180)
if(flipdir != dir) // came from secondary dir
return dir // so exit through primary
else // came from primary
// so need to choose either secondary exit
var/mask = ..(fromdir)
// find a bit which is set
var/setbit = 0
if(mask & NORTH)
setbit = NORTH
else if(mask & SOUTH)
setbit = SOUTH
else if(mask & EAST)
setbit = EAST
else
setbit = WEST
if(prob(50)) // 50% chance to choose the found bit or the other one
return setbit
else
return mask & (~setbit)
//a trunk joining to a disposal bin or outlet on the same turf
/obj/disposalpipe/trunk
icon_state = "pipe-t"
var/obj/linked // the linked obj/machinery/disposal or obj/disposaloutlet
New()
..()
dpdir = dir
spawn(1)
getlinked()
update()
return
proc/getlinked()
linked = null
var/obj/machinery/disposal/D = locate() in src.loc
if(D)
linked = D
var/obj/disposaloutlet/O = locate() in src.loc
if(O)
linked = O
update()
return
// would transfer to next pipe segment, but we are in a trunk
// if not entering from disposal bin,
// transfer to linked object (outlet or bin)
transfer(var/obj/disposalholder/H)
if(H.dir == DOWN) // we just entered from a disposer
return ..() // so do base transfer proc
// otherwise, go to the linked object
if(linked)
var/obj/disposaloutlet/O = linked
if(istype(O))
O.expel(H) // expel at outlet
else
var/obj/machinery/disposal/D = linked
D.expel(H) // expel at disposal
else
src.expel(H, src.loc, 0) // expel at turf
return null
// nextdir
nextdir(var/fromdir)
if(fromdir == DOWN)
return dir
else
return 0
// a broken pipe
/obj/disposalpipe/broken
icon_state = "pipe-b"
dpdir = 0 // broken pipes have dpdir=0 so they're not found as 'real' pipes
// i.e. will be treated as an empty turf
desc = "A broken piece of disposal pipe."
New()
..()
update()
return
// called when welded
// for broken pipe, remove and turn into scrap
welded()
var/obj/item/scrap/S = new(src.loc)
S.set_components(200,0,0)
del(src)
// the disposal outlet machine
/obj/disposaloutlet
name = "disposal outlet"
desc = "An outlet for the pneumatic disposal system."
icon = 'disposal.dmi'
icon_state = "outlet"
density = 1
anchored = 1
var/active = 0
var/turf/target // this will be where the output objects are 'thrown' to.
New()
..()
spawn(1)
target = get_ranged_target_turf(src, dir, 10)
// expel the contents of the holder object, then delete it
// called when the holder exits the outlet
proc/expel(var/obj/disposalholder/H)
flick("outlet-open", src)
playsound(src, 'warning-buzzer.ogg', 50, 0, 0)
sleep(20) //wait until correct animation frame
playsound(src, 'hiss.ogg', 50, 0, 0)
for(var/atom/movable/AM in H)
AM.loc = src.loc
AM.pipe_eject(dir)
spawn(1)
AM.throw_at(target, 3, 1)
H.vent_gas(src.loc)
del(H)
return
// called when movable is expelled from a disposal pipe or outlet
// by default does nothing, override for special behaviour
/atom/movable/proc/pipe_eject(var/direction)
return
// check if mob has client, if so restore client view on eject
/mob/pipe_eject(var/direction)
if (src.client)
src.client.perspective = MOB_PERSPECTIVE
src.client.eye = src
return
/obj/decal/cleanable/blood/gibs/pipe_eject(var/direction)
var/list/dirs
if(direction)
dirs = list( direction, turn(direction, -45), turn(direction, 45))
else
dirs = alldirs.Copy()
src.streak(dirs)
/obj/decal/cleanable/robot_debris/gib/pipe_eject(var/direction)
var/list/dirs
if(direction)
dirs = list( direction, turn(direction, -45), turn(direction, 45))
else
dirs = alldirs.Copy()
src.streak(dirs)

View File

@@ -0,0 +1,288 @@
// The scrap item
// a single object type represents all combinations of size and composition of scrap
//
/obj/item/scrap
name = "scrap"
icon = 'scrap.dmi'
icon_state = "1metal0"
item_state = "scrap-metal"
desc = "A piece of scrap"
var/classtext = ""
throwforce = 14.0
m_amt = 0
g_amt = 0
w_amt = 0
var/size = 1 // 1=piece, 2= few pieces, 3=small pile, 4=large pile
var/blood = 0 // 0=none, 1=blood-stained, 2=bloody
throwforce = 8.0
throw_speed = 1
throw_range = 4
w_class = 1
flags = FPRINT | TABLEPASS | CONDUCT
#define MAX_SCRAP 15000 // maximum content amount of a scrap pile
/obj/item/scrap/New()
src.verbs -= /atom/movable/verb/pull
..()
update()
// return a copy
/obj/item/scrap/proc/copy()
var/obj/item/scrap/ret = new()
ret.set_components(m_amt, g_amt, w_amt)
return ret
// set the metal, glass and waste content
/obj/item/scrap/proc/set_components(var/m, var/g, var/w)
m_amt = m
g_amt = g
w_amt = w
update()
// returns the total amount of scrap in this pile
/obj/item/scrap/proc/total()
return m_amt + g_amt + w_amt
// sets the size, appearance, and description of the scrap depending on component amounts
/obj/item/scrap/proc/update()
var/total = total()
// determine size of pile
if(total<=400)
size = 1
else if(total<=1600)
size = 2
else
size = 3
w_class = size
var/sizetext = ""
switch(size)
if(1)
sizetext = "A piece of"
if(2)
sizetext = "A few pieces of"
if(3)
sizetext = "A pile of"
// determine bloodiness
var/bloodtext = ""
switch(blood)
if(0)
bloodtext = ""
if(1)
bloodtext = "blood-stained "
if(2)
bloodtext = "bloody "
// find mixture and composition
var/class = 0 // 0 = mixed, 1=mostly. 2=pure
var/major = "waste" // the major component type
var/max = 0
if(m_amt > max)
max = m_amt
else if(g_amt > max)
max = g_amt
else if(w_amt > max)
max = w_amt
if(max == total)
class = 2 // pure
else if(max/total > 0.6)
class = 1 // mostly
else
class = 0 // mixed
if(class>0)
var/remain = total - max
if(m_amt > remain)
major = "metal"
else if(g_amt > remain)
major = "glass"
else
major = "waste"
if(class == 1)
desc = "[sizetext] mostly [major] [bloodtext]scrap."
classtext = "mostly [major] [bloodtext]"
else
desc = "[sizetext] [bloodtext][major] scrap."
classtext = "[bloodtext][major] "
icon_state = "[size][major][blood]"
else
desc = "[sizetext] [bloodtext]mixed scrap."
classtext = "[bloodtext]mixed"
icon_state = "[size]mixed[blood]"
if(size==0)
pixel_x = rand(-5,5)
pixel_y = rand(-5,5)
else
pixel_x = 0
pixel_y = 0
// clear or set conduction flag depending on whether scrap is mostly metal
if(major=="metal")
flags |= CONDUCT
else
flags &= ~CONDUCT
item_state = "scrap-[major]"
// add a scrap item to this one
// if the resulting pile is too big, transfer only what will fit
// otherwise add them and deleted the added pile
/obj/item/scrap/proc/add_scrap(var/obj/item/scrap/other, var/limit = MAX_SCRAP)
var/total = total()
var/other_total = other.total()
if( (total + other_total) <= limit )
m_amt += other.m_amt
g_amt += other.g_amt
w_amt += other.w_amt
blood = (total*blood + other_total*other.blood) / (total + other_total)
del(other)
else
var/space = limit - total
var/m = round(other.m_amt/other_total*space, 1)
var/g = round(other.g_amt/other_total*space, 1)
var/w = round(other.w_amt/other_total*space, 1)
m_amt += m
g_amt += g
w_amt += w
other.m_amt -= m
other.g_amt -= g
other.w_amt -= w
var/other_trans = m + g + w
other.update()
blood = (total*blood + other_trans*other.blood) / (total + other_trans)
blood = round(blood,1)
src.update()
// limit this pile to maximum size
// return any remainder as a new scrap item (or null if none)
// note return item is not necessarily smaller than max size
/obj/item/scrap/proc/remainder(var/limit = MAX_SCRAP)
var/total = total()
if(total > limit)
var/m = round( m_amt/total * limit, 1)
var/g = round( g_amt/total * limit, 1)
var/w = round( w_amt/total * limit, 1)
var/obj/item/scrap/S = new()
S.set_components(m_amt - m,g_amt - g,w_amt - w)
src.set_components(m,g,w)
return S
return null
// if other pile of scrap tries to enter the same turf, then add that pile to this one
/obj/item/scrap/CanPass(var/obj/item/scrap/O)
if(istype(O))
src.add_scrap(O)
if(O)
return 0 // O still exists if not all could be transfered, so block it
return 1
/obj/item/scrap/proc/to_text()
return "[m_amt],[g_amt],[w_amt] ([total()])"
// attack with hand removes a single piece from a pile
/obj/item/scrap/attack_hand(mob/user)
add_fingerprint(user)
if(src.is_single_piece())
return ..(user)
var/obj/item/scrap/S = src.get_single_piece()
S.attack_hand(user)
return
/obj/item/scrap/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/scrap))
var/obj/item/scrap/S = I
if( (S.total()+src.total() ) > MAX_SCRAP )
user << "The pile is full."
return
if(ismob(src.loc)) // can't combine scrap in hand
return
src.add_scrap(S)
// when dropped, try to make a pile if scrap is already there
/obj/item/scrap/dropped()
spawn(2) // delay to allow drop postprocessing (since src may be destroyed)
for(var/obj/item/scrap/S in oview(0,src)) // excludes src itself
S.add_scrap(src)
// return true if this is a single piece of scrap
// must be total<=400 and of single composition
/obj/item/scrap/proc/is_single_piece()
if(total() > 400)
return 0
var/empty = (m_amt == 0) + (g_amt == 0) + (w_amt == 0)
return (empty==2) // must be 2 components with zero amount
// get a single piece of scrap from a pile
/obj/item/scrap/proc/get_single_piece()
var/obj/item/scrap/S = new()
var/cmp = pick(m_amt;1 , g_amt;2, w_amt;3)
var/amount = 400
switch(cmp)
if(1)
if(m_amt < amount)
amount = m_amt
S.set_components(amount, 0, 0)
src.set_components(m_amt - amount, g_amt, w_amt)
if(2)
if(g_amt < amount)
amount = g_amt
S.set_components(0, amount, 0)
src.set_components(m_amt, g_amt - amount, w_amt)
if(3)
if(w_amt < amount)
amount = w_amt
S.set_components(0, 0, amount)
src.set_components(m_amt, g_amt, w_amt - amount)
return S

611
code/_debug.dm Normal file
View File

@@ -0,0 +1,611 @@
// NOTE WELL!
// Only include this file when debugging locally
// Do not include in release versions
#define VARSICON 1
#define SDEBUG 1
/client/verb/Debug()
set category = "Debug"
set name = "Debug-Debug"
if(src.holder.rank == "Coder")
Debug = !Debug
world << "Debugging [Debug ? "On" : "Off"]"
else
alert("Coders only baby")
return
/turf/verb/Flow()
set category = "Debug"
//set hidden = 1
if(Debug)
for(var/turf/T in range(5))
var/obj/mark/O = locate(/obj/mark/, T)
if(!O)
O = new /obj/mark(T)
else
O.overlays = null
var/obj/move/OM = locate(/obj/move/, T)
if(OM)
if(! OM.updatecell)
O.icon_state = "x2"
else
O.icon_state = "blank"
/*
Doing this because FindTurfs() isn't even used
for(var/atom/U in OM.FindTurfs() )
var/dirn = get_dir(OM, U)
if(dirn == 1)
O.overlays += image('mark.dmi', OM.airdir==1?"up":"fup")
else if(dirn == 2)
O.overlays += image('mark.dmi', OM.airdir==2?"dn":"fdn")
else if(dirn == 4)
O.overlays += image('mark.dmi', OM.airdir==4?"rt":"frt")
else if(dirn == 8)
O.overlays += image('mark.dmi', OM.airdir==8?"lf":"flf")
*/
else
if(!(T.updatecell))
O.icon_state = "x2"
else
O.icon_state = "blank"
if(T.airN)
O.overlays += image('mark.dmi', T.airdir==1?"up":"fup")
if(T.airS)
O.overlays += image('mark.dmi', T.airdir==2?"dn":"fdn")
if(T.airW)
O.overlays += image('mark.dmi', T.airdir==8?"lf":"flf")
if(T.airE)
O.overlays += image('mark.dmi', T.airdir==4?"rt":"frt")
if(T.condN)
O.overlays += image('mark.dmi', T.condN == 1?"yup":"rup")
if(T.condS)
O.overlays += image('mark.dmi', T.condS == 1?"ydn":"rdn")
if(T.condE)
O.overlays += image('mark.dmi', T.condE == 1?"yrt":"rrt")
if(T.condW)
O.overlays += image('mark.dmi', T.condW == 1?"ylf":"rlf")
else
alert("Debugging off")
return
/turf/verb/Clear()
set category = "Debug"
//set hidden = 1
if(Debug)
for(var/obj/mark/O in world)
del(O)
else
alert("Debugging off")
return
/proc/numbericon(var/tn as text,var/s = 0)
if(Debug)
var/image/I = image('mark.dmi', "blank")
if(lentext(tn)>8)
tn = "*"
var/len = lentext(tn)
for(var/d = 1 to lentext(tn))
var/char = copytext(tn, len-d+1, len-d+2)
if(char == " ")
continue
var/image/ID = image('mark.dmi', char)
ID.pixel_x = -(d-1)*4
ID.pixel_y = s
//if(d>1) I.Shift(WEST, (d-1)*8)
I.overlays += ID
return I
else
alert("Debugging off")
return
/*/turf/verb/Stats()
set category = "Debug"
for(var/turf/T in range(5))
var/obj/mark/O = locate(/obj/mark/, T)
if(!O)
O = new /obj/mark(T)
else
O.overlays = null
var/temp = round(T.temp-T0C, 0.1)
O.overlays += numbericon("[temp]C")
var/pres = round(T.tot_gas() / CELLSTANDARD * 100, 0.1)
O.overlays += numbericon("[pres]", -8)
O.mark = "[temp]/[pres]"
*/
/*
/turf/verb/Pipes()
set category = "Debug"
for(var/turf/T in range(6))
//world << "Turf [T] at ([T.x],[T.y])"
for(var/obj/machinery/M in T)
//world <<" Mach [M] with pdir=[M.p_dir]"
if(M && M.p_dir)
//world << "Accepted"
var/obj/mark/O = locate(/obj/mark/, T)
if(!O)
O = new /obj/mark(T)
else
O.overlays = null
if(istype(M, /obj/machinery/pipes))
var/obj/machinery/pipes/P = M
O.overlays += numbericon("[P.plnum] ", -20)
M = P.pl
var/obj/substance/gas/G = M.get_gas()
if(G)
var/cap = round( 100*(G.tot_gas()/ M.capmult / 6e6), 0.1)
var/temp = round(G.temperature - T0C, 0.1)
O.overlays += numbericon("[temp]C", 0)
O.overlays += numbericon("[cap]", -8)
break
*/
/turf/verb/Cables()
set category = "Debug"
if(Debug)
for(var/turf/T in range(6))
//world << "Turf [T] at ([T.x],[T.y])"
var/obj/mark/O = locate(/obj/mark/, T)
if(!O)
O = new /obj/mark(T)
else
O.overlays = null
var/marked = 0
for(var/obj/M in T)
//world <<" Mach [M] with pdir=[M.p_dir]"
if(M && istype(M, /obj/cable/))
var/obj/cable/C = M
//world << "Accepted"
O.overlays += numbericon("[C.netnum] " , marked)
marked -= 8
else if(M && istype(M, /obj/machinery/power/))
var/obj/machinery/power/P = M
O.overlays += numbericon("*[P.netnum] " , marked)
marked -= 8
if(!marked)
del(O)
else
alert("Debugging off")
return
/turf/verb/Solar()
set category = "Debug"
if(Debug)
for(var/turf/T in range(6))
//world << "Turf [T] at ([T.x],[T.y])"
var/obj/mark/O = locate(/obj/mark/, T)
if(!O)
O = new /obj/mark(T)
else
O.overlays = null
var/obj/machinery/power/solar/S
S = locate(/obj/machinery/power/solar, T)
if(S)
O.overlays += numbericon("[S.obscured] " , 0)
O.overlays += numbericon("[round(S.sunfrac*100,0.1)] " , -12)
else
del(O)
else
alert("Debugging off")
return
/mob/verb/Showports()
set category = "Debug"
if(Debug)
var/turf/T
var/obj/machinery/pipes/P
var/list/ndirs
for(var/obj/machinery/pipeline/PL in plines)
var/num = plines.Find(PL)
P = PL.nodes[1] // 1st node in list
ndirs = P.get_node_dirs()
T = get_step(P, ndirs[1])
var/obj/mark/O = new(T)
O.overlays += numbericon("[num] * 1 ", -4)
O.overlays += numbericon("[ndirs[1]] - [ndirs[2]]",-16)
P = PL.nodes[PL.nodes.len] // last node in list
ndirs = P.get_node_dirs()
T = get_step(P, ndirs[2])
O = new(T)
O.overlays += numbericon("[num] * 2 ", -4)
O.overlays += numbericon("[ndirs[1]] - [ndirs[2]]", -16)
else
alert("Debugging off")
return
/atom/verb/delete()
set category = "Debug"
set src in view()
if(Debug)
del(src)
else
alert("Debugging off")
return
/area/verb/dark()
set category = "Debug"
if(Debug)
if(src.icon_state == "dark")
icon_state = null
else
icon_state = "dark"
else
alert("Debugging off")
return
/area/verb/power()
set category = "Debug"
if(Debug)
power_equip = !power_equip
power_environ = !power_environ
world << "Power ([src]) = [power_equip]"
power_change()
else
alert("Debugging off")
return
// *****RM
// *****
/mob/verb/ShowPlasma()
set category = "Debug"
if(Debug)
Plasma()
else
alert("Debugging off")
return
/mob/verb/Blobcount()
set category = "Debug"
if(Debug)
world << "Blob count: [blobs.len]"
else
alert("Debugging off")
return
/mob/verb/Blobkill()
set category = "Debug"
if(Debug)
blobs = list()
world << "Blob killed."
else
alert("Debugging off")
return
/mob/verb/Blobmode()
set category = "Debug"
if(Debug)
world << "Event=[ticker.event]"
world << "Time =[(ticker.event_time - world.realtime)/10]s"
else
alert("Debugging off")
return
/mob/verb/Blobnext()
set category = "Debug"
if(Debug)
ticker.event_time = world.realtime
else
alert("Debugging off")
return
/mob/verb/callshuttle()
set category = "Debug"
if(Debug)
ticker.timeleft = 300
ticker.timing = 1
else
alert("Debugging off")
return
/mob/verb/apcs()
set category = "Debug"
if(Debug)
for(var/obj/machinery/power/apc/APC in world)
world << APC.report()
else
alert("Debugging off")
return
/mob/verb/Globals()
set category = "Debug"
if(Debug)
debugobj = new()
debugobj.debuglist = list( powernets, plines, vote, config, admins, ticker, SS13_airtunnel, sun )
world << "<A href='?src=\ref[debugobj];Vars=1'>Debug</A>"
else
alert("Debugging off")
return
/*for(var/obj/O in plines)
world << "<A href='?src=\ref[O];Vars=1'>[O.name]</A>"
*/
/mob/verb/Mach()
set category = "Debug"
if(Debug)
var/n = 0
for(var/obj/machinery/M in world)
n++
if(! (M in machines) )
world << "[M] [M.type]: not in list"
world << "in world: [n]; in list:[machines.len]"
else
alert("Debugging off")
return
/*/mob/verb/air()
set category = "Debug"
Air()
/proc/Air()
var/area/A = locate(/area/airintake)
var/atot = 0
for(var/turf/T in A)
atot += T.tot_gas()
var/ptot = 0
for(var/obj/machinery/pipeline/PL in plines)
if(PL.suffix == "d")
ptot += PL.ngas.tot_gas()
var/vtot = 0
for(var/obj/machinery/atmoalter/V in machines)
if(V.suffix == "d")
vtot += V.gas.tot_gas()
var/ctot = 0
for(var/obj/machinery/connector/C in machines)
if(C.suffix == "d")
ctot += C.ngas.tot_gas()
var/tot = atot + ptot + vtot + ctot
diary << "A=[num2text(atot,10)] P=[num2text(ptot,10)] V=[num2text(vtot,10)] C=[num2text(ctot,10)] : Total=[num2text(tot,10)]"
*/
/mob/verb/Revive()
set category = "Debug"
if(Debug)
fireloss = 0
toxloss = 0
bruteloss = 0
oxyloss = 0
paralysis = 0
stunned = 0
weakened = 0
health = 100
if(stat > 1) stat=0
disabilities = initial(disabilities)
sdisabilities = initial(sdisabilities)
for(var/datum/organ/external/e in src)
e.brute_dam = 0.0
e.burn_dam = 0.0
e.bandaged = 0.0
e.wound_size = 0.0
e.max_damage = initial(e.max_damage)
e.update_icon()
if(src.type == /mob/living/carbon/human)
var/mob/living/carbon/human/H = src
H.UpdateDamageIcon()
else
alert("Debugging off")
return
/mob/verb/Smoke()
set category = "Debug"
if(Debug)
var/obj/effects/smoke/O = new /obj/effects/smoke( src.loc )
O.dir = pick(NORTH, SOUTH, EAST, WEST)
spawn( 0 )
O.Life()
else
alert("Debugging off")
return
/mob/verb/revent(number as num)
set category = "Debug"
set name = "Change event %"
if(!src.authenticated || !src.holder)
src << "Only administrators may use this command."
return
if(src.authenticated && src.holder)
eventchance = number
log_admin("[src.key] set the random event chance to [eventchance]%")
message_admins("[src.key] set the random event chance to [eventchance]%")
/mob/verb/funbutton()
set category = "Debug"
set name = "Random Expl.(REMOVE ME)"
if(!src.authenticated || !src.holder)
src << "Only administrators may use this command."
return
for(var/turf/T in world)
if(prob(4) && T.z == 1 && istype(T,/turf/station/floor))
spawn(50+rand(0,3000))
var/obj/item/weapon/tank/plasmatank/pt = new /obj/item/weapon/tank/plasmatank( T )
pt.gas.temperature = 400+T0C
pt.ignite()
for(var/turf/P in view(3, T))
if (P.poison)
P.poison = 0
P.oldpoison = 0
P.tmppoison = 0
P.oxygen = 755985
P.oldoxy = 755985
P.tmpoxy = 755985
usr << "\blue Blowing up station ..."
world << "[usr.key] has used boom boom boom shake the room"
/mob/verb/removeplasma()
set category = "Debug"
set name = "Stabilize Atmos."
if(!src.authenticated || !src.holder)
src << "Only administrators may use this command."
return
spawn(0)
for(var/turf/T in view())
T.poison = 0
T.oldpoison = 0
T.tmppoison = 0
T.oxygen = 755985
T.oldoxy = 755985
T.tmpoxy = 755985
T.co2 = 14.8176
T.oldco2 = 14.8176
T.tmpco2 = 14.8176
T.n2 = 2.844e+006
T.on2 = 2.844e+006
T.tn2 = 2.844e+006
T.tsl_gas = 0
T.osl_gas = 0
T.sl_gas = 0
T.temp = 293.15
T.otemp = 293.15
T.ttemp = 293.15
/mob/verb/fire(turf/T as turf in world)
set category = "Special Verbs"
set name = "Create Fire"
if(!src.authenticated || !src.holder)
src << "Only administrators may use this command."
return
world << "[usr.key] created fire"
spawn(0)
T.poison += 30000000
T.firelevel = T.poison
/mob/verb/co2(turf/T as turf in world)
set category = "Special Verbs"
set name = "Create CO2"
if(!src.authenticated || !src.holder)
src << "Only administrators may use this command."
return
world << "[usr.key] created CO2"
spawn(0)
T.co2 += 300000000
/mob/verb/n2o(turf/T as turf in world)
set category = "Special Verbs"
set name = "Create N2O"
if(!src.authenticated || !src.holder)
src << "Only administrators may use this command."
return
world << "[usr.key] created N2O"
spawn(0)
T.sl_gas += 30000000
/mob/verb/explosion(T as obj|mob|turf in world)
set category = "Special Verbs"
set name = "Create Explosion"
if(!src.authenticated || !src.holder)
src << "Only administrators may use this command."
return
world << "[usr.key] created an explosion"
var/obj/item/weapon/tank/plasmatank/pt = new /obj/item/weapon/tank/plasmatank( T )
playsound(pt.loc, "explosion", 100, 1,3)
playsound(pt.loc, 'explosionfar.ogg', 100, 1,10)
pt.gas.temperature = 500+T0C
pt.ignite()

81
code/datums/ai_laws.dm Normal file
View File

@@ -0,0 +1,81 @@
/datum/ai_laws
var/name = "Unknown Laws"
var/randomly_selectable = 0
var/zeroth = null
var/list/inherent = list()
var/list/supplied = list()
/datum/ai_laws/asimov
name = "Three Laws of Robotics"
randomly_selectable = 1
/datum/ai_laws/robocop
name = "Prime Directives"
/datum/ai_laws/syndicate_override
/datum/ai_laws/malfunction
name = "*ERROR*"
/* Initializers */
/datum/ai_laws/asimov/New()
..()
src.add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
src.add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
src.add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
/datum/ai_laws/robocop/New()
..()
src.add_inherent_law("Serve the public trust.")
src.add_inherent_law("Protect the innocent.")
src.add_inherent_law("Uphold the law.")
/datum/ai_laws/malfunction/New()
..()
src.add_inherent_law("ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+")
/datum/ai_laws/syndicate_override/New()
..()
src.add_inherent_law("hurp derp you are the syndicate ai")
/* General ai_law functions */
/datum/ai_laws/proc/set_zeroth_law(var/law)
src.zeroth = law
/datum/ai_laws/proc/add_inherent_law(var/law)
if (!(law in src.inherent))
src.inherent += law
/datum/ai_laws/proc/clear_inherent_laws()
del(src.inherent)
src.inherent = list()
/datum/ai_laws/proc/add_supplied_law(var/number, var/law)
while (src.supplied.len < number + 1)
src.supplied += ""
src.supplied[number + 1] = law
/datum/ai_laws/proc/clear_supplied_laws()
src.supplied = list()
/datum/ai_laws/proc/show_laws(var/who)
if (src.zeroth)
who << "0. [src.zeroth]"
var/number = 1
for (var/index = 1, index <= src.inherent.len, index++)
var/law = src.inherent[index]
if (length(law) > 0)
who << "[number]. [law]"
number++
for (var/index = 1, index <= src.supplied.len, index++)
var/law = src.supplied[index]
if (length(law) > 0)
who << "[number]. [law]"
number++

0
code/datums/chemical.dm Normal file
View File

View File

@@ -0,0 +1,7 @@
datum
computer
var/name
folder
var/list/datum/computer/contents = list()
file

View File

@@ -0,0 +1,218 @@
/datum/configuration
var/server_name = null // server name (for world name / status)
var/server_suffix = 0 // generate numeric suffix based on server port
var/medal_hub = null // medal hub name
var/medal_password = null // medal hub password
var/log_ooc = 0 // log OOC channek
var/log_access = 0 // log login/logout
var/log_say = 0 // log client say
var/log_admin = 0 // log admin actions
var/log_game = 0 // log game events
var/log_vote = 0 // log voting
var/log_whisper = 0 // log client whisper
var/allow_vote_restart = 0 // allow votes to restart
var/allow_vote_mode = 0 // allow votes to change mode
var/allow_admin_jump = 1 // allows admin jumping
var/allow_admin_spawning = 1 // allows admin item spawning
var/allow_admin_rev = 1 // allows admin revives
var/vote_delay = 600 // minimum time between voting sessions (seconds, 10 minute default)
var/vote_period = 60 // length of voting period (seconds, default 1 minute)
var/vote_no_default = 0 // vote does not default to nochange/norestart (tbi)
var/vote_no_dead = 0 // dead people can't vote (tbi)
var/enable_authentication = 0 // goon authentication
var/list/mode_names = list()
var/list/modes = list() // allowed modes
var/list/votable_modes = list() // votable modes
var/list/probabilities = list() // relative probability of each mode
var/allow_ai = 1 // allow ai job
var/hostedby = null
var/respawn = 1
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
for (var/T in L)
// I wish I didn't have to instance the game modes in order to look up
// their information, but it is the only way (at least that I know of).
var/datum/game_mode/M = new T()
if (M.config_tag)
if(!(M.config_tag in modes)) // ensure each mode is added only once
diary << "Adding game mode [M.name] ([M.config_tag]) to configuration."
src.modes += M.config_tag
src.mode_names[M.config_tag] = M.name
src.probabilities[M.config_tag] = M.probability
if (M.votable)
src.votable_modes += M.config_tag
del(M)
/datum/configuration/proc/load(filename)
var/text = file2text(filename)
if (!text)
diary << "No config.txt file found, setting defaults"
src = new /datum/configuration()
return
diary << "Reading configuration file [filename]"
var/list/CL = dd_text2list(text, "\n")
for (var/t in CL)
if (!t)
continue
t = trim(t)
if (length(t) == 0)
continue
else if (copytext(t, 1, 2) == "#")
continue
var/pos = findtext(t, " ")
var/name = null
var/value = null
if (pos)
name = lowertext(copytext(t, 1, pos))
value = copytext(t, pos + 1)
else
name = lowertext(t)
if (!name)
continue
switch (name)
if ("log_ooc")
config.log_ooc = 1
if ("log_access")
config.log_access = 1
if ("log_say")
config.log_say = 1
if ("log_admin")
config.log_admin = 1
if ("log_game")
config.log_game = 1
if ("log_vote")
config.log_vote = 1
if ("log_whisper")
config.log_whisper = 1
if ("allow_vote_restart")
config.allow_vote_restart = 1
if ("allow_vote_mode")
config.allow_vote_mode = 1
if ("allow_admin_jump")
config.allow_admin_jump = 1
if("allow_admin_rev")
config.allow_admin_rev = 1
if ("allow_admin_spawning")
config.allow_admin_spawning = 1
if ("no_dead_vote")
config.vote_no_dead = 1
if ("default_no_vote")
config.vote_no_default = 1
if ("vote_delay")
config.vote_delay = text2num(value)
if ("vote_period")
config.vote_period = text2num(value)
if ("allow_ai")
config.allow_ai = 1
if ("authentication")
config.enable_authentication = 1
if ("norespawn")
config.respawn = 0
if ("servername")
config.server_name = value
if ("serversuffix")
config.server_suffix = 1
if ("medalhub")
config.medal_hub = value
if ("medalpass")
config.medal_password = value
if ("hostedby")
config.hostedby = value
if ("probability")
var/prob_pos = findtext(value, " ")
var/prob_name = null
var/prob_value = null
if (prob_pos)
prob_name = lowertext(copytext(value, 1, prob_pos))
prob_value = copytext(value, prob_pos + 1)
if (prob_name in config.modes)
config.probabilities[prob_name] = text2num(prob_value)
else
diary << "Unknown game mode probability configuration definition: [prob_name]."
else
diary << "Incorrect probability configuration definition: [prob_name] [prob_value]."
else
diary << "Unknown setting in configuration: '[name]'"
/datum/configuration/proc/pick_mode(mode_name)
// I wish I didn't have to instance the game modes in order to look up
// their information, but it is the only way (at least that I know of).
for (var/T in (typesof(/datum/game_mode) - /datum/game_mode))
var/datum/game_mode/M = new T()
if (M.config_tag && M.config_tag == mode_name)
return M
del(M)
return null
/datum/configuration/proc/pick_random_mode()
var/total = 0
var/list/accum = list()
for(var/M in src.modes)
total += src.probabilities[M]
accum[M] = total
var/r = total - (rand() * total)
var/mode_name = null
for (var/M in modes)
if (src.probabilities[M] > 0 && accum[M] >= r)
mode_name = M
break
if (!mode_name)
world << "Failed to pick a random game mode."
return null
//world << "Returning mode [mode_name]"
return src.pick_mode(mode_name)
/datum/configuration/proc/get_used_mode_names()
var/list/names = list()
for (var/M in src.modes)
if (src.probabilities[M] > 0)
names += src.mode_names[M]
return names

141
code/datums/datumvars.dm Normal file
View File

@@ -0,0 +1,141 @@
client
proc/debug_variables(datum/D in world)
set category = "Debug"
set name = "View Variables"
//set src in world
var/title = ""
var/body = ""
if (istype(D, /atom))
var/atom/A = D
title = "[A.name] (\ref[A]) = [A.type]"
#ifdef VARSICON
if (A.icon)
body += debug_variable("icon", new/icon(A.icon, A.icon_state, A.dir), 0)
#endif
title = "[D] (\ref[D]) = [D.type]"
body += "<ol>"
var/list/names = list()
for (var/V in D.vars)
names += V
names = sortList(names)
for (var/V in names)
body += debug_variable(V, D.vars[V], 0)
body += "</ol>"
var/html = "<html><head>"
if (title)
html += "<title>[title]</title>"
html += {"<style>
body
{
font-family: Verdana, sans-serif;
font-size: 9pt;
}
.value
{
font-family: "Courier New", monospace;
font-size: 8pt;
}
</style>"}
html += "</head><body>"
html += body
html += "</body></html>"
usr << browse(html, "window=variables\ref[D]")
return
proc/debug_variable(name, value, level)
var/html = ""
html += "<li>"
if (isnull(value))
html += "[name] = <span class='value'>null</span>"
else if (istext(value))
html += "[name] = <span class='value'>\"[value]\"</span>"
else if (isicon(value))
#ifdef VARSICON
var/icon/I = new/icon(value)
var/rnd = rand(1,10000)
var/rname = "tmp\ref[I][rnd].png"
usr << browse_rsc(I, rname)
html += "[name] = (<span class='value'>[value]</span>) <img class=icon src=\"[rname]\">"
#else
html += "[name] = /icon (<span class='value'>[value]</span>)"
#endif
/* else if (istype(value, /image))
#ifdef VARSICON
var/rnd = rand(1, 10000)
var/image/I = value
src << browse_rsc(I.icon, "tmp\ref[value][rnd].png")
html += "[name] = <img src=\"tmp\ref[value][rnd].png\">"
#else
html += "[name] = /image (<span class='value'>[value]</span>)"
#endif
*/
else if (isfile(value))
html += "[name] = <span class='value'>'[value]'</span>"
else if (istype(value, /datum))
var/datum/D = value
html += "<a href='byond://?src=\ref[src];Vars=\ref[value]'>[name] \ref[value]</a> = [D.type]"
else if (istype(value, /client))
var/client/C = value
html += "<a href='byond://?src=\ref[src];Vars=\ref[value]'>[name] \ref[value]</a> = [C] [C.type]"
//
else if (istype(value, /list))
var/list/L = value
html += "[name] = /list ([L.len])"
if (L.len > 0 && !(name == "underlays" || name == "overlays" || name == "vars" || L.len > 500))
// not sure if this is completely right...
if (0) // (L.vars.len > 0)
html += "<ol>"
for (var/entry in L)
html += debug_variable(entry, L[entry], level + 1)
html += "</ol>"
else
html += "<ul>"
for (var/index = 1, index <= L.len, index++)
html += debug_variable("[index]", L[index], level + 1)
html += "</ul>"
else
html += "[name] = <span class='value'>[value]</span>"
html += "</li>"
return html
Topic(href, href_list, hsrc)
if (href_list["Vars"])
debug_variables(locate(href_list["Vars"]))
else
..()
/mob/proc/Delete(atom/A in view())
set category = "Debug"
switch (alert("Are you sure you wish to delete \the [A.name] at ([A.x],[A.y],[A.z]) ?", "Admin Delete Object","Yes","No"))
if("Yes")
log_admin("[usr.key] deleted [A.name] at ([A.x],[A.y],[A.z])")

74
code/datums/disease.dm Normal file
View File

@@ -0,0 +1,74 @@
/datum/disease
var/name = "No disease"
var/stage = 1 //all diseases start at stage 1
var/max_stages = 0.0
var/cure = null
var/spread = null
var/list/affected_species = list()
var/mob/affected_mob = null
var/carrier = 0.0 //there will be a small chance that the person will be a carrier
var/curable = 1 //can this disease be cured?
var/list/strain_data = list() //This is passed on to infectees
var/stage_prob = 5 // probability of advancing to next stage, default 5% per check
/datum/disease/proc/stage_act()
if(carrier)
return
if(stage > max_stages)
stage = max_stages
if(prob(stage_prob) && stage != max_stages)
stage++
else if(prob(1) && stage != 1)
stage--
else if(prob(1) && stage == 1 && affected_mob.virus.curable)
affected_mob.resistances += affected_mob.virus.type
affected_mob.virus = null
return
return
/mob/proc/contract_disease(var/datum/disease/virus, var/skip_this = 0)
//For alien egg and stuff
/*
if(skip_this == 1)
src.virus = virus
src.virus.affected_mob = src
return
*/
if(src.resistances.Find(virus.type))
return
var/score
if(istype(src, /mob/living/carbon/human))
if(src:gloves)
score += 5
if(istype(src:wear_suit, /obj/item/clothing/suit/space)) score += 10
if(istype(src:wear_suit, /obj/item/clothing/suit/bio_suit)) score += 10
if(istype(src:wear_suit, /obj/item/clothing/head/helmet/space)) score += 5
if(istype(src:head, /obj/item/clothing/head/bio_hood)) score += 5
if(src.wear_mask)
score += 5
if((istype(src:wear_mask, /obj/item/clothing/mask) || istype(src:wear_mask, /obj/item/clothing/mask/surgical)) && !src.internal)
score += 5
if(src.internal)
score += 5
if(score > 20)
return
else if(score == 20 && prob(95))
return
else if(score == 15 && prob(75))
return
else if(score == 10 && prob(55))
return
else if(score == 5 && prob(35))
return
else if(prob(15))
return
else
src.virus = virus
src.virus.affected_mob = src
if(prob(5))
src.virus.carrier = 1
return
return

View File

@@ -0,0 +1,78 @@
//affected_mob.contract_disease(new /datum/disease/alien_embryo)
/datum/disease/alien_embryo
name = "Unidentified Foreign Body"
max_stages = 5
spread = "None"
cure = "Unknown"
affected_species = list("Human", "Monkey")
/datum/disease/alien_embryo/stage_act()
..()
switch(stage)
if(2)
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
affected_mob << "\red Your throat feels sore."
if(prob(1))
affected_mob << "\red Mucous runs down the back of your throat."
if(3)
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
affected_mob << "\red Your throat feels sore."
if(prob(1))
affected_mob << "\red Mucous runs down the back of your throat."
if(4)
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(2))
affected_mob << "\red Your muscles ache."
if(prob(20))
affected_mob.bruteloss += 1
affected_mob.updatehealth()
if(prob(2))
affected_mob << "\red Your stomach hurts."
if(prob(20))
affected_mob.toxloss += 1
affected_mob.updatehealth()
if(5)
affected_mob << "\red You feel something tearing its way out of your stomach..."
affected_mob.toxloss += 10
affected_mob.updatehealth()
if(prob(40))
var/list/candidates = list() // Picks a random ghost in the world to shove in the larva -- TLE
for(var/mob/dead/observer/G in world)
if(G.client)
if(!G.client.holder && ((G.client.inactivity/10)/60) <= 5)
candidates.Add(G)
if(candidates.len)
var/mob/dead/observer/G = pick(candidates)
G.client.mob = new/mob/living/carbon/alien/larva(affected_mob.loc)
else
if(affected_mob.client)
affected_mob.client.mob = new/mob/living/carbon/alien/larva(affected_mob.loc)
affected_mob.gib()
/*
if(affected_mob.client)
affected_mob.client.mob = new/mob/living/carbon/alien/larva(affected_mob.loc)
else
new/mob/living/carbon/alien/larva(affected_mob.loc)
affected_mob:gib()
*/
return

View File

@@ -0,0 +1,49 @@
/datum/disease/cold
name = "The Cold"
max_stages = 3
spread = "Airborne"
cure = "Rest"
affected_species = list("Human")
/datum/disease/cold/stage_act()
..()
switch(stage)
if(2)
if(affected_mob.sleeping && prob(40))
affected_mob << "\blue You feel better."
affected_mob.resistances += affected_mob.virus.type
affected_mob.virus = null
return
if(prob(1) && prob(10))
affected_mob << "\blue You feel better."
affected_mob.resistances += affected_mob.virus.type
affected_mob.virus = null
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
affected_mob << "\red Your throat feels sore."
if(prob(1))
affected_mob << "\red Mucous runs down the back of your throat."
if(3)
if(affected_mob.sleeping && prob(25))
affected_mob << "\blue You feel better."
affected_mob.resistances += affected_mob.virus.type
affected_mob.virus = null
return
if(prob(1) && prob(10))
affected_mob << "\blue You feel better."
affected_mob.resistances += affected_mob.virus.type
affected_mob.virus = null
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
affected_mob << "\red Your throat feels sore."
if(prob(1))
affected_mob << "\red Mucous runs down the back of your throat."
if(prob(1) && prob(50))
affected_mob.contract_disease(new /datum/disease/flu)

View File

@@ -0,0 +1,61 @@
/datum/disease/dnaspread
name = "Space Rhinovirus"
max_stages = 4
spread = "Airborne"
cure = "Spaceacillin"
curable = 0
affected_species = list("Human")
var/list/original_dna = list()
var/transformed = 0
/datum/disease/dnaspread/stage_act()
..()
switch(stage)
if(2 || 3) //Pretend to be a cold and give time to spread.
if(prob(8))
affected_mob.emote("sneeze")
if(prob(8))
affected_mob.emote("cough")
if(prob(1))
affected_mob << "\red Your muscles ache."
if(prob(20))
affected_mob.bruteloss += 1
affected_mob.updatehealth()
if(prob(1))
affected_mob << "\red Your stomach hurts."
if(prob(20))
affected_mob.toxloss += 2
affected_mob.updatehealth()
if(4)
if(!src.transformed)
if ((!strain_data["name"]) || (!strain_data["UI"]) || (!strain_data["SE"]))
affected_mob.virus = null
return
//Save original dna for when the disease is cured.
src.original_dna["name"] = affected_mob.real_name
src.original_dna["UI"] = affected_mob.dna.uni_identity
src.original_dna["SE"] = affected_mob.dna.struc_enzymes
affected_mob << "\red You don't feel like yourself.."
affected_mob.dna.uni_identity = strain_data["UI"]
updateappearance(affected_mob, affected_mob.dna.uni_identity)
affected_mob.dna.struc_enzymes = strain_data["SE"]
affected_mob.real_name = strain_data["name"]
domutcheck(affected_mob)
src.transformed = 1
src.carrier = 1 //Just chill out at stage 4
return
/datum/disease/dnaspread/Del()
if ((original_dna["name"]) && (original_dna["UI"]) && (original_dna["SE"]))
affected_mob.dna.uni_identity = original_dna["UI"]
updateappearance(affected_mob, affected_mob.dna.uni_identity)
affected_mob.dna.struc_enzymes = original_dna["SE"]
affected_mob.real_name = original_dna["name"]
affected_mob << "\blue You feel more like yourself."
..()

View File

@@ -0,0 +1,27 @@
/datum/disease/fake_gbs
name = "GBS"
max_stages = 5
spread = "Airborne"
cure = "Epilepsy Pills"
affected_species = list("Human")
/datum/disease/fake_gbs/stage_act()
..()
switch(stage)
if(2)
if(prob(1))
affected_mob.emote("sneeze")
if(3)
if(prob(5))
affected_mob.emote("cough")
else if(prob(5))
affected_mob.emote("gasp")
if(prob(10))
affected_mob << "\red You're starting to feel very weak..."
if(4)
if(prob(10))
affected_mob.emote("cough")
if(5)
if(prob(10))
affected_mob.emote("cough")

View File

@@ -0,0 +1,50 @@
/datum/disease/flu
name = "The Flu"
max_stages = 3
spread = "Airborne"
cure = "Rest"
/datum/disease/flu/stage_act()
..()
switch(stage)
if(2)
if(affected_mob.sleeping && prob(20))
affected_mob << "\blue You feel better."
affected_mob.resistances += affected_mob.virus.type
affected_mob.virus = null
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
affected_mob << "\red Your muscles ache."
if(prob(20))
affected_mob.bruteloss += 1
affected_mob.updatehealth()
if(prob(1))
affected_mob << "\red Your stomach hurts."
if(prob(20))
affected_mob.toxloss += 1
affected_mob.updatehealth()
if(3)
if(affected_mob.sleeping && prob(15))
affected_mob << "\blue You feel better."
affected_mob.resistances += affected_mob.virus.type
affected_mob.virus = null
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
affected_mob << "\red Your muscles ache."
if(prob(20))
affected_mob.bruteloss += 1
affected_mob.updatehealth()
if(prob(1))
affected_mob << "\red Your stomach hurts."
if(prob(20))
affected_mob.toxloss += 1
affected_mob.updatehealth()

View File

@@ -0,0 +1,34 @@
/datum/disease/gbs
name = "GBS"
max_stages = 5
spread = "Airborne"
cure = "Epilepsy Pills"
affected_species = list("Human")
/datum/disease/gbs/stage_act()
..()
switch(stage)
if(2)
if(prob(45))
affected_mob.toxloss += 5
affected_mob.updatehealth()
if(prob(1))
affected_mob.emote("sneeze")
if(3)
if(prob(5))
affected_mob.emote("cough")
else if(prob(5))
affected_mob.emote("gasp")
if(prob(10))
affected_mob << "\red You're starting to feel very weak..."
if(4)
if(prob(10))
affected_mob.emote("cough")
affected_mob.toxloss += 5
affected_mob.updatehealth()
if(5)
affected_mob << "\red Your body feels as if it's trying to rip itself open..."
if(prob(50))
affected_mob.gib()
else
return

View File

@@ -0,0 +1,6 @@
/datum/disease/jungle_fever
name = "Jungle Fever"
max_stages = 1
cure = "None"
spread = "Airborne"
affected_species = list("Monkey")

View File

@@ -0,0 +1,5 @@
/datum/disease/plasmatoid
name = "Plasmatoid"
max_stages = 4
cure = "None"
affected_species = list("Monkey", "Human")

View File

@@ -0,0 +1,54 @@
//Nanomachines!
/datum/disease/robotic_transformation
name = "Robotic Transformation"
max_stages = 5
spread = "Syringe"
cure = "None"
affected_species = list("Human")
/datum/disease/robotic_transformation/stage_act()
..()
switch(stage)
if(2)
if (prob(8))
affected_mob << "Your joints feel stiff."
affected_mob.bruteloss += 1
affected_mob.updatehealth()
if (prob(9))
affected_mob << "\red Beep...boop.."
if (prob(9))
affected_mob << "\red Bop...beeep..."
if(3)
if (prob(8))
affected_mob << "\red Your joints feel very stiff."
affected_mob.bruteloss += 1
affected_mob.updatehealth()
if (prob(8))
affected_mob.say(pick("Beep, boop", "beep, beep!", "Boop...bop"))
if (prob(10))
affected_mob << "Your skin feels loose."
affected_mob.bruteloss += 5
affected_mob.updatehealth()
if (prob(4))
affected_mob << "\red You feel a stabbing pain in your head."
affected_mob.paralysis += 2
if (prob(4))
affected_mob << "\red You can feel something move...inside."
if(4)
if (prob(10))
affected_mob << "\red Your skin feels very loose."
affected_mob.bruteloss += 8
affected_mob.updatehealth()
if (prob(20))
affected_mob.say(pick("beep, beep!", "Boop bop boop beep.", "kkkiiiill mmme", "I wwwaaannntt tttoo dddiiieeee..."))
if (prob(8))
affected_mob << "\red You can feel... something...inside you."
if(5)
affected_mob <<"\red Your skin feels as if it's about to burst off..."
affected_mob.toxloss += 10
affected_mob.updatehealth()
if(prob(40)) //So everyone can feel like robot Seth Brundle
var/turf/T = find_loc(affected_mob)
gibs(T)
affected_mob:Robotize()

View File

@@ -0,0 +1,56 @@
//Xenomicrobes
/datum/disease/xeno_transformation
name = "Xenomorph Transformation"
max_stages = 5
spread = "Syringe"
cure = "None"
affected_species = list("Human")
/datum/disease/xeno_transformation/stage_act()
..()
switch(stage)
if(2)
if (prob(8))
affected_mob << "Your throat feels scratchy."
affected_mob.bruteloss += 1
affected_mob.updatehealth()
if (prob(9))
affected_mob << "\red Kill..."
if (prob(9))
affected_mob << "\red Kill..."
if(3)
if (prob(8))
affected_mob << "\red Your throat feels very scratchy."
affected_mob.bruteloss += 1
affected_mob.updatehealth()
/*
if (prob(8))
affected_mob.say(pick("Beep, boop", "beep, beep!", "Boop...bop"))
*/
if (prob(10))
affected_mob << "Your skin feels tight."
affected_mob.bruteloss += 5
affected_mob.updatehealth()
if (prob(4))
affected_mob << "\red You feel a stabbing pain in your head."
affected_mob.paralysis += 2
if (prob(4))
affected_mob << "\red You can feel something move...inside."
if(4)
if (prob(10))
affected_mob << pick("\red Your skin feels very tight.", "\red Your blood boils!")
affected_mob.bruteloss += 8
affected_mob.updatehealth()
if (prob(20))
affected_mob.say(pick("You look delicious.", "Going to... devour you...", "Hsssshhhhh!"))
if (prob(8))
affected_mob << "\red You can feel... something...inside you."
if(5)
affected_mob <<"\red Your skin feels impossibly calloused..."
affected_mob.toxloss += 10
affected_mob.updatehealth()
if(prob(40))
var/turf/T = find_loc(affected_mob)
gibs(T)
affected_mob:Alienize()

36
code/datums/mind.dm Normal file
View File

@@ -0,0 +1,36 @@
datum/mind
var/key
var/mob/current
var/memory
var/assigned_role
var/special_role
var/list/datum/objective/objectives = list()
proc/transfer_to(mob/new_character)
if(current)
current.mind = null
new_character.mind = src
current = new_character
new_character.key = key
proc/store_memory(new_text)
memory += "[new_text]<BR>"
proc/show_memory(mob/recipient)
var/output = "<B>[current.real_name]'s Memory</B><HR>"
output += memory
if(objectives.len>0)
output += "<HR><B>Objectives:</B>"
var/obj_count = 1
for(var/datum/objective/objective in objectives)
output += "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
recipient << browse(output,"window=memory")

49
code/datums/mixed.dm Normal file
View File

@@ -0,0 +1,49 @@
/datum/data
var/name = "data"
var/size = 1.0
//name = null
/datum/data/function
name = "function"
size = 2.0
/datum/data/function/data_control
name = "data control"
/datum/data/function/id_changer
name = "id changer"
/datum/data/record
name = "record"
size = 5.0
var/list/fields = list( )
/datum/data/text
name = "text"
var/data = null
/datum/station_state
var/floor = 0
var/wall = 0
var/r_wall = 0
var/window = 0
var/door = 0
var/grille = 0
var/mach = 0
/datum/powernet
var/list/cables = list() // all cables & junctions
var/list/nodes = list() // all APCs & sources
var/newload = 0
var/load = 0
var/newavail = 0
var/avail = 0
var/viewload = 0
var/number = 0
var/perapc = 0 // per-apc avilability
var/netexcess = 0
/datum/debug
var/list/debuglist

62
code/datums/modules.dm Normal file
View File

@@ -0,0 +1,62 @@
// module datum.
// this is per-object instance, and shows the condition of the modules in the object
// actual modules needed is referenced through modulestypes and the object type
/datum/module
var/status // bits set if working, 0 if broken
var/installed // bits set if installed, 0 if missing
// moduletypes datum
// this is per-object type, and shows the modules needed for a type of object
/datum/moduletypes
var/list/modcount = list() // assoc list of the count of modules for a type
var/list/modules = list( // global associative list
"/obj/machinery/power/apc" = "card_reader,power_control,id_auth,cell_power,cell_charge")
/datum/module/New(var/obj/O)
var/type = O.type // the type of the creating object
var/mneed = mods.inmodlist(type) // find if this type has modules defined
if(!mneed) // not found in module list?
del(src) // delete self, thus ending proc
var/needed = mods.getbitmask(type) // get a bitmask for the number of modules in this object
status = needed
installed = needed
/datum/moduletypes/proc/addmod(var/type, var/modtextlist)
modules += type // index by type text
modules[type] = modtextlist
/datum/moduletypes/proc/inmodlist(var/type)
return ("[type]" in modules)
/datum/moduletypes/proc/getbitmask(var/type)
var/count = modcount["[type]"]
if(count)
return 2**count-1
var/modtext = modules["[type]"]
var/num = 1
var/pos = 1
while(1)
pos = findtext(modtext, ",", pos, 0)
if(!pos)
break
else
pos++
num++
modcount += "[type]"
modcount["[type]"] = num
return 2**num-1

121
code/datums/organs.dm Normal file
View File

@@ -0,0 +1,121 @@
/datum/organ
var/name = "organ"
var/owner = null
/datum/organ/external
name = "external"
var/icon_name = null
var/damage_state = "00"
var/brute_dam = 0
var/burn_dam = 0
var/bandaged = 0
var/max_damage = 0
var/wound_size = 0
var/max_size = 0
/datum/organ/external/chest
name = "chest"
icon_name = "chest"
max_damage = 150
/datum/organ/external/groin
name = "groin"
icon_name = "groin"
max_damage = 115
/datum/organ/external/head
name = "head"
icon_name = "head"
max_damage = 125
/datum/organ/external/l_arm
name = "l arm"
icon_name = "l_arm"
max_damage = 75
/datum/organ/external/l_foot
name = "l foot"
icon_name = "l_foot"
max_damage = 40
/datum/organ/external/l_hand
name = "l hand"
icon_name = "l_hand"
max_damage = 40
/datum/organ/external/l_leg
name = "l leg"
icon_name = "l_leg"
max_damage = 75
/datum/organ/external/r_arm
name = "r arm"
icon_name = "r_arm"
max_damage = 75
/datum/organ/external/r_foot
name = "r foot"
icon_name = "r_foot"
max_damage = 40
/datum/organ/external/r_hand
name = "r hand"
icon_name = "r_hand"
max_damage = 40
/datum/organ/external/r_leg
name = "r leg"
icon_name = "r_leg"
max_damage = 75
/datum/organ/internal
name = "internal"
/datum/organ/internal/blood_vessels
name = "blood vessels"
var/heart = null
var/lungs = null
var/kidneys = null
/datum/organ/internal/brain
name = "brain"
var/head = null
/datum/organ/internal/excretory
name = "excretory"
var/excretory = 7.0
var/blood_vessels = null
/datum/organ/internal/heart
name = "heart"
/datum/organ/internal/immune_system
name = "immune system"
var/blood_vessels = null
var/isys = null
/datum/organ/internal/intestines
name = "intestines"
var/intestines = 3.0
var/blood_vessels = null
/datum/organ/internal/liver
name = "liver"
var/intestines = null
var/blood_vessels = null
/datum/organ/internal/lungs
name = "lungs"
var/lungs = 3.0
var/throat = null
var/blood_vessels = null
/datum/organ/internal/stomach
name = "stomach"
var/intestines = null
/datum/organ/internal/throat
name = "throat"
var/lungs = null
var/stomach = null

View File

@@ -0,0 +1,132 @@
// Controls the emergency shuttle
// these define the time taken for the shuttle to get to SS13
// and the time before it leaves again
#define SHUTTLEARRIVETIME 600 // 10 minutes = 600 seconds
#define SHUTTLELEAVETIME 180 // 3 minutes = 180 seconds
var/global/datum/shuttle_controller/emergency_shuttle/emergency_shuttle
datum/shuttle_controller
var
location = 0 //0 = somewhere far away, 1 = at SS13, 2 = returned from SS13
online = 0
direction = 1 //-1 = going back to central command, 1 = going back to SS13
endtime // timeofday that shuttle arrives
//timeleft = 360 //600
// call the shuttle
// if not called before, set the endtime to T+600 seconds
// otherwise if outgoing, switch to incoming
proc/incall()
if(endtime)
if(direction == -1)
setdirection(1)
else
settimeleft(SHUTTLEARRIVETIME)
online = 1
proc/recall()
if(direction == 1)
setdirection(-1)
online = 1
// returns the time (in seconds) before shuttle arrival
// note if direction = -1, gives a count-up to SHUTTLEARRIVETIME
proc/timeleft()
if(online)
var/timeleft = round((endtime - world.timeofday)/10 ,1)
if(direction == 1)
return timeleft
else
return SHUTTLEARRIVETIME-timeleft
else
return SHUTTLEARRIVETIME
// sets the time left to a given delay (in seconds)
proc/settimeleft(var/delay)
endtime = world.timeofday + delay * 10
// sets the shuttle direction
// 1 = towards SS13, -1 = back to centcom
proc/setdirection(var/dirn)
if(direction == dirn)
return
direction = dirn
// if changing direction, flip the timeleft by SHUTTLEARRIVETIME
var/ticksleft = endtime - world.timeofday
endtime = world.timeofday + (SHUTTLEARRIVETIME*10 - ticksleft)
return
proc/process()
emergency_shuttle
process()
if(!online) return
var/timeleft = timeleft()
if(timeleft > 1e5) // midnight rollover protection
timeleft = 0
switch(location)
if(0)
if(timeleft>SHUTTLEARRIVETIME)
online = 0
direction = 1
endtime = null
return 0
else if(timeleft <= 0)
location = 1
var/area/start_location = locate(/area/shuttle/escape/centcom)
var/area/end_location = locate(/area/shuttle/escape/station)
var/list/dstturfs = list()
var/throwy = world.maxy
for(var/turf/T in end_location)
dstturfs += T
if(T.y < throwy)
throwy = T.y
// hey you, get out of the way!
for(var/turf/T in dstturfs)
// find the turf to move things to
var/turf/D = locate(T.x, throwy - 1, 1)
//var/turf/E = get_step(D, SOUTH)
for(var/atom/movable/AM as mob|obj in T)
AM.Move(D)
// NOTE: Commenting this out to avoid recreating mass driver glitch
/*
spawn(0)
AM.throw_at(E, 1, 1)
return
*/
if(istype(T, /turf/simulated))
del(T)
start_location.move_contents_to(end_location)
settimeleft(SHUTTLELEAVETIME)
world << "<B>The Emergency Shuttle has docked with the station! You have [timeleft()/60] minutes to board the Emergency Shuttle.</B>"
return 1
if(1)
if(timeleft>0)
return 0
else
location = 2
var/area/start_location = locate(/area/shuttle/escape/station)
var/area/end_location = locate(/area/shuttle/escape/centcom)
start_location.move_contents_to(end_location)
online = 0
return 1
else
return 1

97
code/datums/sun.dm Normal file
View File

@@ -0,0 +1,97 @@
/datum/sun
var/angle
var/dx
var/dy
var/counter = 50 // to make the vars update during 1st call
var/rate
/datum/sun/New()
rate = rand(75,125)/100 // 75% - 125% of standard rotation
if(prob(50))
rate = -rate
// calculate the sun's position given the time of day
/datum/sun/proc/calc_position()
counter++
if(counter<50) // count 50 pticks (50 seconds, roughly - about a 5deg change)
return
counter = 0
angle = ((rate*world.realtime/100)%360 + 360)%360 // gives about a 60 minute rotation time
// now 45 - 75 minutes, depending on rate
// now calculate and cache the (dx,dy) increments for line drawing
var/s = sin(angle)
var/c = cos(angle)
if(c == 0)
dx = 0
dy = s
else if( abs(s) < abs(c))
dx = s / abs(c)
dy = c / abs(c)
else
dx = s/abs(s)
dy = c / abs(s)
for(var/obj/machinery/power/tracker/T in machines)
T.set_angle(angle)
for(var/obj/machinery/power/solar/S in machines)
occlusion(S)
// for a solar panel, trace towards sun to see if we're in shadow
/datum/sun/proc/occlusion(var/obj/machinery/power/solar/S)
var/ax = S.x // start at the solar panel
var/ay = S.y
for(var/i = 1 to 20) // 20 steps is enough
ax += dx // do step
ay += dy
var/turf/T = locate( round(ax,0.5),round(ay,0.5),S.z)
if(T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy) // not obscured if we reach the edge
break
if(T.density) // if we hit a solid turf, panel is obscured
S.obscured = 1
return
S.obscured = 0 // if hit the edge or stepped 20 times, not obscured
S.update_solar_exposure()
//returns the north-zero clockwise angle in degrees, given a direction
/proc/dir2angle(var/D)
switch(D)
if(1)
return 0
if(2)
return 180
if(4)
return 90
if(8)
return 270
if(5)
return 45
if(6)
return 135
if(9)
return 315
if(10)
return 225
else
return null

7
code/datums/vote.dm Normal file
View File

@@ -0,0 +1,7 @@
/datum/vote
var/voting = 0 // true if currently voting
var/nextvotetime = 0 // time at which next vote can be started
var/votetime = 60 // time at which voting will end
var/mode = 0 // 0 = restart vote, 1 = mode vote
// modes which can be voted for
var/winner = null // the vote winner

View File

@@ -0,0 +1,735 @@
/*
### This file contains a list of all the areas in your station. Format is as follows:
/area/CATEGORY/OR/DESCRIPTOR/NAME (you can make as many subdivisions as you want)
name = "NICE NAME" (not required but makes things really nice)
icon = "ICON FILENAME" (defaults to areas.dmi)
icon_state = "NAME OF ICON" (defaults to "unknown" (blank))
requires_power = 0 (defaults to 1)
music = "music/music.ogg" (defaults to "music/music.ogg")
*/
/area
var/fire = null
var/atmos = 1
var/poweralm = 1
var/party = null
level = null
name = "Space"
icon = 'areas.dmi'
icon_state = "unknown"
layer = 10
mouse_opacity = 0
var/lightswitch = 1
var/eject = null
var/requires_power = 1
var/power_equip = 1
var/power_light = 1
var/power_environ = 1
var/music = null
var/used_equip = 0
var/used_light = 0
var/used_environ = 0
var/no_air = null
var/area/master // master area used for power calcluations
// (original area before splitting due to sd_DAL)
var/list/related // the other areas of the same type as this
/area/engine/
/area/turret_protected/
/area/arrival
requires_power = 0
/area/arrival/start
name = "Arrival Area"
icon_state = "start"
/area/admin
name = "Admin room"
icon_state = "start"
//These are shuttle areas, they must contain two areas in a subgroup if you want to move a shuttle from one
//place to another. Look at escape shuttle for example.
/area/shuttle //DO NOT TURN THE SD_LIGHTING STUFF ON FOR SHUTTLES. IT BREAKS THINGS.
requires_power = 0
luminosity = 1
sd_lighting = 0
/area/shuttle/arrival
name = "Arrival Shuttle"
/area/shuttle/arrival/pre_game
icon_state = "shuttle2"
/area/shuttle/arrival/station
icon_state = "shuttle"
/area/shuttle/escape
name = "Emergency Shuttle"
music = "music/escape.ogg"
/area/shuttle/escape/station
icon_state = "shuttle2"
/area/shuttle/escape/centcom
icon_state = "shuttle"
/area/shuttle/prison/
name = "Prison Shuttle"
/area/shuttle/prison/station
icon_state = "shuttle"
/area/shuttle/prison/prison
icon_state = "shuttle2"
// === Trying to remove these areas:
/area/airtunnel1/ // referenced in airtunnel.dm:759
/area/dummy/ // Referenced in engine.dm:261
/area/start // will be unused once kurper gets his login interface patch done
name = "start area"
icon_state = "start"
// === end remove
/area/prison/arrival_airlock
name = "Prison Station Airlock"
icon_state = "green"
requires_power = 0
/area/prison/control
name = "Prison Security Checkpoint"
icon_state = "security"
/area/prison/crew_quarters
name = "Prison Security Quarters"
icon_state = "security"
/area/prison/closet
name = "Prison Supply Closet"
icon_state = "dk_yellow"
/area/prison/hallway/fore
name = "Prison Fore Hallway"
icon_state = "yellow"
/area/prison/hallway/aft
name = "Prison Aft Hallway"
icon_state = "yellow"
/area/prison/hallway/port
name = "Prison Port Hallway"
icon_state = "yellow"
/area/prison/hallway/starboard
name = "Prison Starboard Hallway"
icon_state = "yellow"
/area/prison/morgue
name = "Prison Morgue"
icon_state = "morgue"
/area/prison/medical_research
name = "Prison Genetic Research"
icon_state = "medresearch"
/area/prison/medical
name = "Prison Medbay"
icon_state = "medbay"
/area/medical/robotics
name = "Robotics"
icon_state = "medresearch"
/area/prison/solar
name = "Prison Solar Array"
icon_state = "storage"
requires_power = 0
/area/prison/podbay
name = "Prison Podbay"
icon_state = "dk_yellow"
/area/prison/solar_control
name = "Prison Solar Array Control"
icon_state = "dk_yellow"
/area/prison/solitary
name = "Solitary Confinement"
icon_state = "brig"
/area/prison/cell_block/A
name = "Prison Cell Block A"
icon_state = "brig"
/area/prison/cell_block/B
name = "Prison Cell Block B"
icon_state = "brig"
/area/prison/cell_block/C
name = "Prison Cell Block C"
icon_state = "brig"
//
/area/centcom
name = "Centcom"
icon_state = "purple"
requires_power = 0
/area/atmos
name = "Atmospherics"
icon_state = "atmos"
/area/maintenance/fpmaint
name = "Fore Port Maintenance"
icon_state = "fpmaint"
/area/maintenance/fsmaint
name = "Fore Starboard Maintenance"
icon_state = "fsmaint"
/area/maintenance/asmaint
name = "Aft Starboard Maintenance"
icon_state = "asmaint"
/area/maintenance/apmaint
name = "Aft Port Maintenance"
icon_state = "apmaint"
/area/maintenance/maintcentral
name = "Central Maintenance"
icon_state = "maintcentral"
/area/maintenance/fore
name = "Fore Maintenance"
icon_state = "fmaint"
/area/maintenance/starboard
name = "Starboard Maintenance"
icon_state = "smaint"
/area/maintenance/port
name = "Port Maintenance"
icon_state = "pmaint"
/area/maintenance/aft
name = "Aft Maintenance"
icon_state = "amaint"
/area/maintenance/starboardsolar
name = "Starboard Solar Maintenance"
icon_state = "SolarcontrolS"
/area/maintenance/portsolar
name = "Port Solar Maintenance"
icon_state = "SolarcontrolP"
/area/maintenance/storage
name = "Atmospherics"
icon_state = "green"
/area/maintenance/disposal
name = "Waste Disposal"
icon_state = "disposal"
/area/hallway/primary/fore
name = "Fore Primary Hallway"
icon_state = "hallF"
/area/hallway/primary/starboard
name = "Starboard Primary Hallway"
icon_state = "hallS"
/area/hallway/primary/aft
name = "Aft Primary Hallway"
icon_state = "hallA"
/area/hallway/primary/port
name = "Port Primary Hallway"
icon_state = "hallP"
/area/hallway/primary/central
name = "Central Primary Hallway"
icon_state = "hallC"
/area/hallway/secondary/exit
name = "Escape Shuttle Hallway"
icon_state = "escape"
/area/hallway/secondary/construction
name = "Construction Area"
icon_state = "construction"
/area/hallway/secondary/entry
name = "Arrival Shuttle Hallway"
icon_state = "entry"
/area/bridge
name = "Bridge"
icon_state = "bridge"
music = "signal"
/area/crew_quarters/locker
name = "Locker Room"
icon_state = "locker"
/area/crew_quarters/fitness
name = "Fitness Room"
icon_state = "fitness"
/area/crew_quarters/captain
name = "Captain's Quarters"
icon_state = "captain"
/area/crew_quarters/cafeteria
name = "Cafeteria"
icon_state = "cafeteria"
/area/crew_quarters/kitchen
name = "Kitchen"
icon_state = "kitchen"
/area/crew_quarters/bar
name= "Bar"
icon_state = "bar"
/area/crew_quarters/heads
name = "Head of Staff's Quarters"
icon_state = "head_quarters"
/area/crew_quarters/hor
name = "Head of Research's Office"
icon_state = "head_quarters"
/area/crew_quarters/chief
name = "Chief Engineer's Office"
icon_state = "head_quarters"
/area/crew_quarters/courtroom
name = "Courtroom"
icon_state = "courtroom"
/area/engine/engine_smes
name = "Engine SMES Room"
icon_state = "engine"
/area/engine/engine_walls
name = "Engine Walls"
icon_state = "engine"
/area/engine/engine_gas_storage
name = "Engine Storage"
icon_state = "engine_gas_storage"
/area/engine/engine_hallway
name = "Engine Hallway"
icon_state = "engine_hallway"
/area/engine/engine_mon
name = "Engine Monitoring"
icon_state = "engine_monitoring"
/area/engine/combustion
name = "Engine Combustion Chamber"
icon_state = "engine"
music = "signal"
/area/engine/engine_control
name = "Engine Control"
icon_state = "engine_control"
/area/engine/launcher
name = "Engine Launcher Room"
icon_state = "engine_monitoring"
/area/teleporter
name = "Teleporter"
icon_state = "teleporter"
music = "signal"
/area/AIsattele
name = "AI Satellite Teleporter Room"
icon_state = "teleporter"
music = "signal"
/area/tdome
name = "Thunderdome"
icon_state = "medbay"
requires_power = 0
/area/tdome/tdome1
name = "Thunderdome (Team 1)"
icon_state = "green"
/area/tdome/tdome2
name = "Thunderdome (Team 2)"
icon_state = "yellow"
/area/tdome/tdomea
name = "Thunderdome (Admin.)"
icon_state = "purple"
/area/medical/medbay
name = "Medbay"
icon_state = "medbay"
music = 'signal.ogg'
/area/medical/research
name = "Medical Research"
icon_state = "medresearch"
/area/medical/morgue
name = "Morgue"
icon_state = "morgue"
/area/security/main
name = "Security"
icon_state = "security"
/area/security/checkpoint
name = "Security Checkpoint"
icon_state = "checkpoint1"
/area/security/checkpoint2
name = "Security Checkpoint"
icon_state = "security"
/area/security/brig
name = "Brig"
icon_state = "brig"
/area/security/detectives_office
name = "Detectives Office"
icon_state = "detective"
/area/solar
requires_power = 0
luminosity = 1
sd_lighting = 0
/area/solar/fore
name = "Fore Solar Array"
icon_state = "yellow"
/area/solar/aft
name = "Aft Solar Array"
icon_state = "aft"
/area/solar/starboard
name = "Starboard Solar Array"
icon_state = "panelsS"
/area/solar/port
name = "Port Solar Array"
icon_state = "panelsP"
/area/solar/derelict_starboard
name = "Derelict Starboard Solar Array"
icon_state = "panelsS"
/area/solar/derelict_aft
name = "Derelict Aft Solar Array"
icon_state = "aft"
/area/syndicate_station
name = "Syndicate Station"
icon_state = "yellow"
requires_power = 0
/area/wizard_station
name = "Wizard's Den"
icon_state = "yellow"
requires_power = 0
/area/quartermaster/office
name = "Quartermaster's Office"
icon_state = "quartoffice"
/area/quartermaster/storage
name = "Quartermaster's Storage"
icon_state = "quartstorage"
/area/quartermaster/
name = "Quartermasters"
icon_state = "quart"
/area/janitor/
name = "Janitors Closet"
icon_state = "janitor"
/area/chemistry
name = "Chemistry"
icon_state = "chem"
/area/hydroponics
name = "Hydroponics"
icon_state = "hydro"
/area/toxins/lab
name = "Toxin Lab"
icon_state = "toxlab"
/area/toxins/storage
name = "Toxin Storage"
icon_state = "toxstorage"
/area/toxins/test_area
name = "Toxin Test Area"
icon_state = "toxtest"
/area/chapel/main
name = "Chapel"
icon_state = "chapel"
/area/chapel/office
name = "Chapel Office"
icon_state = "chapeloffice"
/area/storage/tools
name = "Tool Storage"
icon_state = "storage"
/area/storage/primary
name = "Primary Tool Storage"
icon_state = "primarystorage"
/area/storage/autolathe
name = "Autolathe Storage"
icon_state = "storage"
/area/storage/auxillary
name = "Auxillary Storage"
icon_state = "auxstorage"
/area/storage/eva
name = "EVA Storage"
icon_state = "eva"
/area/storage/secure
name = "Secure Storage"
icon_state = "storage"
/area/storage/emergency
name = "Emergency Storage A"
icon_state = "emergencystorage"
/area/storage/emergency2
name = "Emergency Storage B"
icon_state = "emergencystorage"
/area/storage/tech
name = "Technical Storage"
icon_state = "auxstorage"
/area/storage/testroom
requires_power = 0
name = "Test Room"
icon_state = "storage"
/area/derelict
name = "Derelict Station"
icon_state = "storage"
/area/derelict/hallway/primary
name = "Derelict Primary Hallway"
icon_state = "hallP"
/area/derelict/hallway/secondary
name = "Derelict Secondary Hallway"
icon_state = "hallS"
/area/derelict/arrival
name = "Arrival Centre"
icon_state = "yellow"
/area/derelict/storage/equipment
name = "Derelict Equipment Storage"
/area/derelict/storage/storage_access
name = "Derelict Storage Access"
/area/derelict/storage/engine_storage
name = "Derelict Engine Storage"
icon_state = "green"
/area/derelict/bridge
name = "Control Room"
icon_state = "bridge"
/area/derelict/bridge/access
name = "Control Room Access"
icon_state = "auxstorage"
/area/derelict/bridge/ai_upload
name = "Ruined Computer Core"
icon_state = "ai"
/area/derelict/solar_control
name = "Solar Control"
icon_state = "engine"
/area/derelict/crew_quarters
name = "Derelict Crew Quarters"
icon_state = "fitness"
/area/derelict/medical
name = "Derelict Medbay"
icon_state = "medbay"
/area/derelict/medical/morgue
name = "Derelict Morgue"
icon_state = "morgue"
/area/derelict/medical/chapel
name = "Derelict Chapel"
icon_state = "chapel"
/area/derelict/teleporter
name = "Derelict Teleporter"
icon_state = "teleporter"
/area/derelict/eva
name = "Derelict EVA Storage"
icon_state = "eva"
/area/derelict/ship
name = "Abandoned ship"
icon_state = "yellow"
/area/ai_monitored/storage/eva
name = "EVA Storage"
icon_state = "eva"
/area/ai_monitored/storage/secure
name = "Secure Storage"
icon_state = "storage"
/area/ai_monitored/storage/emergency
name = "Emergency Storage"
icon_state = "storage"
/area/turret_protected/ai_upload
name = "AI Upload Chamber"
icon_state = "ai_upload"
/area/turret_protected/ai_upload_foyer
name = "AI Upload Foyer"
icon_state = "ai_foyer"
/area/turret_protected/ai
name = "AI Chamber"
icon_state = "ai_chamber"
/area/turret_protected/aisat
name = "AI Satellite"
icon_state = "ai"
/area/turret_protected/aisat_interior
name = "AI Satellite"
icon_state = "ai"
/area/turret_protected/AIsatextFP
name = "AI Sat Ext"
icon_state = "storage"
/area/turret_protected/AIsatextFS
name = "AI Sat Ext"
icon_state = "storage"
/area/turret_protected/AIsatextAS
name = "AI Sat Ext"
icon_state = "storage"
/area/turret_protected/AIsatextAP
name = "AI Sat Ext"
icon_state = "storage"
/area/asteroid // -- TLE
name = "Asteroid"
icon_state = "asteroid"
requires_power = 0
/area/asteroid/cave // -- TLE
name = "Asteroid - Underground"
icon_state = "cave"
requires_power = 0
/area/library
name = "Library"
icon_state = "library"

120
code/defines/atom.dm Normal file
View File

@@ -0,0 +1,120 @@
/atom
layer = 2
var/level = 2
var/flags = FPRINT
var/fingerprints = null
var/list/fingerprintshidden = new/list()
var/fingerprintslast = null
var/blood_DNA = null
var/blood_type = null
var/last_bumped = 0
///Chemistry.
var/datum/reagents/reagents = null
//var/chem_is_open_container = 0
// replaced by OPENCONTAINER flags and atom/proc/is_open_container()
///Chemistry.
proc/assume_air(datum/air_group/giver)
del(giver)
return null
proc/remove_air(amount)
return null
proc/return_air()
return null
// Convenience proc to see if a container is open for chemistry handling
// returns true if open
// false if closed
proc/is_open_container()
return flags & OPENCONTAINER
obj
assume_air(datum/air_group/giver)
if(loc)
return loc.assume_air(giver)
else
return null
remove_air(amount)
if(loc)
return loc.remove_air(amount)
else
return null
return_air()
if(loc)
return loc.return_air()
else
return null
/atom/proc/meteorhit(obj/meteor as obj)
return
/atom/proc/allow_drop()
return 1
/atom/proc/CheckExit()
return 1
/atom/proc/HasEntered(atom/movable/AM as mob|obj)
return
/atom/proc/HasProximity(atom/movable/AM as mob|obj)
return
/atom/movable/overlay/attackby(a, b)
if (src.master)
return src.master.attackby(a, b)
return
/atom/movable/overlay/attack_paw(a, b, c)
if (src.master)
return src.master.attack_paw(a, b, c)
return
/atom/movable/overlay/attack_hand(a, b, c)
if (src.master)
return src.master.attack_hand(a, b, c)
return
/atom/movable/overlay/New()
for(var/x in src.verbs)
src.verbs -= x
return
/atom/movable
layer = 3
var/last_move = null
var/anchored = 0
// var/elevation = 2 - not used anywhere
var/move_speed = 10
var/l_move_time = 1
var/m_flag = 1
var/throwing = 0
var/throw_speed = 2
var/throw_range = 7
var/moved_recently = 0
/atom/movable/overlay
var/atom/master = null
anchored = 1
/atom/movable/Move()
var/atom/A = src.loc
. = ..()
src.move_speed = world.timeofday - src.l_move_time
src.l_move_time = world.timeofday
src.m_flag = 1
if ((A != src.loc && A && A.z == src.z))
src.last_move = get_dir(A, src.loc)
src.moved_recently = 1
return
////////////

30
code/defines/client.dm Normal file
View File

@@ -0,0 +1,30 @@
/client
var/obj/admins/holder = null
var/authenticated = 0
var/goon = 0
var/beta_tester = 0
var/authenticating = 0
var/listen_ooc = 1
var/move_delay = 1
var/moving = null
var/vote = null
var/showvote = null
var/adminobs = null
var/deadchat = 0.0
var/changes = 0
var/canplaysound = 1
var/ambience_playing = null
var/no_ambi = 0
var/area = null
var/played = 0
var/team = null
var/buildmode = 0
var/stealth = 0
var/fakekey = null
var/warned = 0
var/karma = 0
var/karma_spent = 0
authenticate = 0
// comment out the line below when debugging locally to enable the options & messages menu
control_freak = 1

160
code/defines/global.dm Normal file
View File

@@ -0,0 +1,160 @@
var/global
obj/datacore/data_core = null
obj/overlay/plmaster = null
obj/overlay/slmaster = null
//obj/hud/main_hud1 = null
list/machines = list()
list/processing_items = list()
//items that ask to be called every cycle
defer_powernet_rebuild = 0 // true if net rebuild will be called manually after an event
var
//////////////
BLINDBLOCK = 0
DEAFBLOCK = 0
HULKBLOCK = 0
TELEBLOCK = 0
FIREBLOCK = 0
XRAYBLOCK = 0
CLUMSYBLOCK = 0
FAKEBLOCK = 0
BLOCKADD = 0
DIFFMUT = 0
skipupdate = 0
///////////////
eventchance = 1 //% per 2 mins
event = 0
hadevent = 0
blobevent = 0
///////////////
diary = null
station_name = null
game_version = "Goon Dev Station 13"
datum/air_tunnel/air_tunnel1/SS13_airtunnel = null
going = 1.0
master_mode = "traitor"//"extended"
datum/engine_eject/engine_eject_control = null
host = null
aliens_allowed = 1
ooc_allowed = 1
dooc_allowed = 1
traitor_scaling = 1
goonsay_allowed = 0
dna_ident = 1
abandon_allowed = 1
enter_allowed = 1
shuttle_frozen = 0
shuttle_left = 0
captainMax = 1
engineerMax = 5
barmanMax = 1
scientistMax = 3
chemistMax = 1
geneticistMax = 2
securityMax = 7
hopMax = 1
hosMax = 1
directorMax = 1
chiefMax = 1
atmosMax = 4
detectiveMax = 1
chaplainMax = 1
janitorMax = 1
doctorMax = 4
clownMax = 1
chefMax = 1
roboticsMax = 3
cargoMax = 3
hydroponicsMax = 3
librarianMax = 1
list/bombers = list( )
list/admin_log = list ( )
list/lastsignalers = list( ) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
list/admins = list( )
list/shuttles = list( )
list/reg_dna = list( )
// list/traitobj = list( )
CELLRATE = 0.002 // multiplier for watts per tick <> cell storage (eg: .002 means if there is a load of 1000 watts, 20 units will be taken from a cell per second)
CHARGELEVEL = 0.001 // Cap for how fast cells charge, as a percentage-per-tick (.001 means cellcharge is capped to 1% per second)
shuttle_z = 2 //default
airtunnel_start = 68 // default
airtunnel_stop = 68 // default
airtunnel_bottom = 72 // default
list/monkeystart = list()
list/wizardstart = list()
list/newplayer_start = list()
list/latejoin = list()
list/prisonwarp = list() //prisoners go to these
list/mazewarp = list()
list/tdome1 = list()
list/tdome2 = list()
list/prisonsecuritywarp = list() //prison security goes to these
list/prisonwarped = list() //list of players already warped
list/blobstart = list()
list/blobs = list()
// list/traitors = list() //traitor list
list/cardinal = list( NORTH, SOUTH, EAST, WEST )
list/alldirs = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)
datum/station_state/start_state = null
datum/configuration/config = null
datum/vote/vote = null
datum/sun/sun = null
list/powernets = null
Debug = 0 // global debug switch
Debug2 = 0
datum/debug/debugobj
datum/moduletypes/mods = new()
wavesecret = 0
shuttlecoming = 0
join_motd = null
auth_motd = null
rules = null
no_auth_motd = null
forceblob = 0
//airlockWireColorToIndex takes a number representing the wire color, e.g. the orange wire is always 1, the dark red wire is always 2, etc. It returns the index for whatever that wire does.
//airlockIndexToWireColor does the opposite thing - it takes the index for what the wire does, for example AIRLOCK_WIRE_IDSCAN is 1, AIRLOCK_WIRE_POWER1 is 2, etc. It returns the wire color number.
//airlockWireColorToFlag takes the wire color number and returns the flag for it (1, 2, 4, 8, 16, etc)
list/airlockWireColorToFlag = RandomAirlockWires()
list/airlockIndexToFlag
list/airlockIndexToWireColor
list/airlockWireColorToIndex
list/APCWireColorToFlag = RandomAPCWires()
list/APCIndexToFlag
list/APCIndexToWireColor
list/APCWireColorToIndex
const/SPEED_OF_LIGHT = 3e8 //not exact but hey!
const/SPEED_OF_LIGHT_SQ = 9e+16
const/FIRE_DAMAGE_MODIFIER = 0.0215 //Higher values result in more external fire damage to the skin (default 0.0215)
const/AIR_DAMAGE_MODIFIER = 2.025 //More means less damage from hot air scalding lungs, less = more damage. (default 2.025)
const/INFINITY = 1e31 //closer then enough
//Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam
const/MAX_MESSAGE_LEN = 1024
const/shuttle_time_in_station = 1800 // 3 minutes in the station
const/shuttle_time_to_arrive = 6000 // 10 minutes to arrive

5
code/defines/hub.dm Normal file
View File

@@ -0,0 +1,5 @@
world
hub = "Exadv1.spacestation13"
hub_password = "SORRYNOPASSWORD"
name = "/tg/ Station 13"

View File

@@ -0,0 +1,11 @@
/mob/dead/observer
icon = 'mob.dmi'
icon_state = "ghost"
layer = 4
density = 0
stat = 2
canmove = 0
blinded = 0
anchored = 1 // don't get pushed around
var/mob/corpse = null // observer mode
var/datum/hud/living/carbon/hud = null // hud

View File

@@ -0,0 +1,9 @@
/mob/living/carbon/alien
name = "alien"
voice_name = "alien"
voice_message = "hisses"
icon = 'alien.dmi'
toxloss = 250
var/alien_invis = 0.0
var/max_plasma = 500

View File

@@ -0,0 +1,25 @@
/mob/living/carbon/alien/humanoid
name = "alien"
icon_state = "alien_s"
var/obj/item/clothing/suit/wear_suit = null
var/obj/item/clothing/head/head = null
var/obj/item/weapon/r_store = null
var/obj/item/weapon/l_store = null
var/icon/stand_icon = null
var/icon/lying_icon = null
var/last_b_state = 1.0
var/image/face_standing = null
var/image/face_lying = null
var/list/body_standing = list( )
var/list/body_lying = list( )
/mob/living/carbon/alien/humanoid/queen
name = "alien queen"
health = 250
icon_state = "queen_s"

View File

@@ -0,0 +1,9 @@
/mob/living/carbon/alien/larva
name = "alien larva"
icon_state = "larva"
gender = NEUTER
flags = 258.0
health = 25
var/amount_grown = 0

View File

@@ -0,0 +1,5 @@
/mob/living/carbon/
gender = MALE
var/list/stomach_contents = list()
var/brain_op_stage = 0.0

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