mirror of
https://github.com/goonstation/goonstation-2016.git
synced 2026-08-27 07:56:12 +01:00
Initial Commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
This work is licensed under the Creative Commons
|
||||
Attribution-NonCommercial-ShareAlike 3.0 United States License. To view a copy
|
||||
of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/us/ or
|
||||
send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
@@ -0,0 +1 @@
|
||||
Official release of goonstation from 2016-03-04, based on revision 35cd644.
|
||||
@@ -0,0 +1,8 @@
|
||||
$oggFiles = Get-ChildItem -Recurse -Filter "*.ogg" -Name
|
||||
$oggVariables = $oggFiles | %{$_ -replace "\\", "/"} | %{$_ -replace "'", "\'"} | %{$_ -replace "((?:[a-zA-Z0-9_/\\'-]|\s)*.ogg)`$", ' "$1" = ''$1'''}
|
||||
$oggVariables = $oggVariables | %{$_ + ",\
|
||||
"}
|
||||
$output = "var/global/list/soundCache = list(
|
||||
$oggVariables
|
||||
`"NONE`" = null)"
|
||||
$output | Out-File -encoding ascii code\soundCache.dm
|
||||
@@ -0,0 +1,601 @@
|
||||
//#define DEBUG
|
||||
|
||||
datum/air_group/var/marker
|
||||
datum/air_group/var/debugging = 0
|
||||
datum/pipe_network/var/marker
|
||||
|
||||
datum/gas_mixture
|
||||
var/turf/parent
|
||||
var/debugging
|
||||
|
||||
/*
|
||||
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/newmeteor/M = new( src )
|
||||
walk(M, direction,10)
|
||||
|
||||
|
||||
turf/simulated/wall
|
||||
verb
|
||||
create_floor()
|
||||
set src in world
|
||||
new /turf/simulated/floor(src)
|
||||
|
||||
obj/item/tank
|
||||
verb
|
||||
adjust_mixture(temperature as num, target_toxin_pressure as num, target_oxygen_pressure as num)
|
||||
set src in world
|
||||
if(!air_contents)
|
||||
boutput(usr, "<span style=\"color:red\">ERROR: no gas_mixture associated with this tank</span>")
|
||||
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)
|
||||
boutput(usr, "<B>[x],[y] parent:</B> Processing: [parent.group_processing]")
|
||||
if(parent.members)
|
||||
boutput(usr, "Members: [parent.members.len]")
|
||||
else
|
||||
boutput(usr, "Members: None?")
|
||||
if(parent.borders)
|
||||
boutput(usr, "Borders: [parent.borders.len]")
|
||||
else
|
||||
boutput(usr, "Borders: None")
|
||||
if(parent.length_space_border)
|
||||
boutput(usr, "Space Borders: [parent.space_borders.len], Space Length: [parent.length_space_border]")
|
||||
else
|
||||
boutput(usr, "Space Borders: None")
|
||||
else
|
||||
boutput(usr, "<span style=\"color:blue\">[x],[y] has no parent air group.</span>")
|
||||
|
||||
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,src,inner_range,middle_range,outer_range,outer_range)
|
||||
|
||||
verb
|
||||
flag_parent()
|
||||
set src in world
|
||||
if(parent)
|
||||
parent.debugging = !parent.debugging
|
||||
parent.air.debugging = parent.debugging
|
||||
boutput(usr, "[parent.members.len] set to [parent.debugging]")
|
||||
verb
|
||||
small_explosion()
|
||||
set src in world
|
||||
explosion(src, src, 1, 2, 3, 3)
|
||||
|
||||
verb
|
||||
large_explosion()
|
||||
set src in world
|
||||
explosion(src, 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"
|
||||
|
||||
boutput(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
|
||||
|
||||
boutput(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"
|
||||
|
||||
boutput(world, "Debugging: [x],[y]")
|
||||
|
||||
if(node1)
|
||||
boutput(world, "Input node: [node1.x],[node1.y] [network1]")
|
||||
if(node2)
|
||||
boutput(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"
|
||||
|
||||
boutput(world, "<span style=\"color:blue\">[x],[y]</span>")
|
||||
boutput(world, "network 1: [network_node1.normal_members.len], [network_node1.line_members.len]")
|
||||
for(var/obj/O in network_node1.normal_members)
|
||||
boutput(world, "member: [O.x], [O.y]")
|
||||
boutput(world, "network 2: [network_node2.normal_members.len], [network_node2.line_members.len]")
|
||||
for(var/obj/O in network_node2.normal_members)
|
||||
boutput(world, "member: [O.x], [O.y]")
|
||||
pipe
|
||||
verb
|
||||
destroy()
|
||||
set src in world
|
||||
set category = "Minor"
|
||||
|
||||
qdel(src)
|
||||
|
||||
pipeline_data()
|
||||
set src in world
|
||||
set category = "Minor"
|
||||
|
||||
if(parent)
|
||||
boutput(usr, "[x],[y] is in a pipeline with [parent.members.len] members ([parent.edges.len] edges)! Volume: [parent.air.volume]")
|
||||
boutput(usr, "Pressure: [parent.air.return_pressure()], Temperature: [parent.air.temperature]")
|
||||
boutput(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 atmos_machines)
|
||||
P.overlays = null
|
||||
|
||||
var/datum/pipe_network/master = P.return_network()
|
||||
if(master)
|
||||
P.overlays += icon('icons/Testing/atmos_testing.dmi',"marker[master.marker]")
|
||||
else
|
||||
boutput(world, "error")
|
||||
P.overlays += icon('icons/Testing/atmos_testing.dmi',"marker0")
|
||||
|
||||
for(var/obj/machinery/atmospherics/valve/V in atmos_machines)
|
||||
V.overlays = null
|
||||
|
||||
if(V.network_node1)
|
||||
V.overlays += icon('icons/Testing/atmos_testing.dmi',"marker[V.network_node1.marker]")
|
||||
else
|
||||
V.overlays += icon('icons/Testing/atmos_testing.dmi',"marker0")
|
||||
|
||||
if(V.network_node2)
|
||||
V.overlays += icon('icons/Testing/atmos_testing.dmi',"marker[V.network_node2.marker]")
|
||||
else
|
||||
V.overlays += icon('icons/Testing/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('icons/turf_analysis.dmi',"red_arrow",direction)
|
||||
else if(air_check_directions&direction)
|
||||
overlays += icon('icons/turf_analysis.dmi',"arrow",direction)
|
||||
air_status()
|
||||
set src in world
|
||||
set category = "Minor"
|
||||
var/datum/gas_mixture/GM = return_air()
|
||||
boutput(usr, "<span style=\"color: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)?("<span style=\"color:red\">BURNING</span>"):(null)]")
|
||||
if(GM.trace_gases && GM.trace_gases.len)
|
||||
for(var/datum/gas/trace_gas in GM.trace_gases)
|
||||
boutput(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
|
||||
boutput(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 = unpool(/datum/gas_mixture)
|
||||
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 = 'icons/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
|
||||
qdel(src)
|
||||
|
||||
mob
|
||||
sight = SEE_OBJS|SEE_TURFS
|
||||
|
||||
verb
|
||||
update_indicators()
|
||||
set category = "Debug"
|
||||
if(!air_master)
|
||||
boutput(usr, "Cannot find air_system")
|
||||
return
|
||||
|
||||
for(var/obj/indicator/T in world)
|
||||
T.process()
|
||||
change_indicators()
|
||||
set category = "Debug"
|
||||
if(!air_master)
|
||||
boutput(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"
|
||||
boutput(usr, "<span style=\"color:red\"><b>Fire Report</b></span>")
|
||||
for(var/obj/hotspot/flame in world)
|
||||
boutput(usr, "[flame.x],[flame.y]: [flame.temperature]K, [flame.volume] L - [flame.loc:air:temperature]")
|
||||
|
||||
process_cycle()
|
||||
set category = "Debug"
|
||||
if(!processScheduler)
|
||||
boutput(usr, "Cannot find processScheduler")
|
||||
return
|
||||
|
||||
boutput(usr, "Sorry, this needs to be rebuilt! Yell at Dr. Singh.")
|
||||
|
||||
|
||||
process_cycles(amount as num)
|
||||
set category = "Debug"
|
||||
if(!processScheduler)
|
||||
boutput(usr, "Cannot find processScheduler")
|
||||
return
|
||||
|
||||
boutput(usr, "Sorry, this needs to be rebuilt! Yell at Dr. Singh.")
|
||||
|
||||
|
||||
process_updates_early()
|
||||
set category = "Debug"
|
||||
if(!air_master)
|
||||
boutput(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)
|
||||
boutput(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 = 'icons/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 = 'icons/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"
|
||||
*/
|
||||
@@ -0,0 +1,353 @@
|
||||
/datum/air_group
|
||||
//Processing all tiles as one large tile if 1
|
||||
var/tmp/group_processing = 1
|
||||
|
||||
var/tmp/datum/gas_mixture/air = null
|
||||
|
||||
//cycle that oxygen value represents
|
||||
var/tmp/current_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
|
||||
var/tmp/archived_cycle = 0
|
||||
|
||||
//Tiles that connect this group to other groups/individual tiles
|
||||
var/list/borders
|
||||
|
||||
//All tiles in this group
|
||||
var/list/members
|
||||
|
||||
// Space tiles that border this group
|
||||
var/list/space_borders
|
||||
|
||||
// Length of space border
|
||||
var/length_space_border = 0
|
||||
|
||||
// drsingh - lets try caching these lists from process_group, see if we can't reduce the garbage collection
|
||||
var/turf/simulated/list/border_individual
|
||||
var/datum/air_group/list/border_group
|
||||
|
||||
//used to send the appropriate border tile of a group to the group proc
|
||||
var/turf/simulated/list/enemies
|
||||
var/turf/simulated/list/self_group_borders
|
||||
var/turf/simulated/list/self_tile_borders
|
||||
|
||||
var/spaced = 0
|
||||
var/spaced_via_group = 0
|
||||
|
||||
// overrides
|
||||
/datum/air_group/disposing()
|
||||
pool(air)
|
||||
air = null
|
||||
..()
|
||||
|
||||
/datum/air_group/New()
|
||||
..()
|
||||
air = unpool(/datum/gas_mixture)
|
||||
|
||||
// Group procs
|
||||
/datum/air_group/proc/suspend_group_processing()
|
||||
// Distribute air from the group out to members
|
||||
update_tiles_from_group()
|
||||
group_processing = 0
|
||||
|
||||
/datum/air_group/proc/resume_group_processing()
|
||||
update_group_from_tiles()
|
||||
group_processing = 1
|
||||
|
||||
//Copy group air information to individual tile air
|
||||
//Used right before turning on group processing
|
||||
/datum/air_group/proc/update_group_from_tiles()
|
||||
// Single sample? Seems like not very many...
|
||||
// Local var, direct access to gas_mixture, no need to pool
|
||||
var/sample_member
|
||||
for (var/turf/S in members)
|
||||
if (istype(S, /turf/space))
|
||||
members -= S
|
||||
if(!members || !members.len ) //I guess all the areas were BADSPACE!!! OH NO! (Spyguy fix for pick() from empty list)
|
||||
qdel(src)
|
||||
return 0
|
||||
sample_member = pick(members)
|
||||
if (sample_member:air)
|
||||
var/datum/gas_mixture/sample_air = sample_member:air
|
||||
|
||||
air.copy_from(sample_air)
|
||||
air.group_multiplier = members.len
|
||||
|
||||
return 1
|
||||
|
||||
//Copy group air information to individual tile air
|
||||
//Used right before turning off group processing
|
||||
/datum/air_group/proc/update_tiles_from_group()
|
||||
for(var/turf/simulated/member in members)
|
||||
if (member.air) member.air.copy_from(air)
|
||||
|
||||
/datum/air_group/proc/archive()
|
||||
air.archive()
|
||||
archived_cycle = air_master.current_cycle
|
||||
|
||||
//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()
|
||||
/datum/air_group/proc/check_regroup()
|
||||
//Purpose: Checks to see if group processing should be turned back on
|
||||
//Returns: group_processing
|
||||
if(group_processing) return 1
|
||||
|
||||
// I don't know why the fuck space tiles are even getting into
|
||||
// airgroups, but this should sort of fix it. This is a bad
|
||||
// hack and I'm sorry. This should eliminate the runtime
|
||||
// "undefined variable: /turf/space/var/air"
|
||||
for(var/turf/space/BADSPACE in members)
|
||||
if(istype(BADSPACE))
|
||||
members -= BADSPACE
|
||||
|
||||
if(!members || !members.len ) //I guess all the areas were BADSPACE!!! OH NO! (Spyguy fix for pick() from empty list)
|
||||
qdel(src)
|
||||
return 0
|
||||
|
||||
var/turf/simulated/sample = pick(members)
|
||||
for(var/turf/simulated/member in members)
|
||||
if (!istype(member)) // Marq fix for undefined variable /turf/space/var/air
|
||||
continue
|
||||
if(member.active_hotspot)
|
||||
return 0
|
||||
if(member.air && member.air.compare(sample.air)) continue
|
||||
else
|
||||
return 0
|
||||
|
||||
resume_group_processing()
|
||||
return 1
|
||||
|
||||
/datum/air_group/proc/process_group(var/datum/controller/process/parent_controller)
|
||||
current_cycle = air_master.current_cycle
|
||||
|
||||
if (spaced)
|
||||
if (!length_space_border)
|
||||
unspace_group()
|
||||
check_regroup()
|
||||
else if(!group_processing)
|
||||
check_regroup()
|
||||
|
||||
if(group_processing) //See if processing this group as a group
|
||||
border_individual = null
|
||||
border_group = null
|
||||
|
||||
enemies = null //used to send the appropriate border tile of a group to the group proc
|
||||
self_group_borders = null
|
||||
self_tile_borders = null
|
||||
|
||||
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
|
||||
|
||||
// Tiles can get added to these lists more than once, but that is OK,
|
||||
// because groups sharing more than one edge should transfer more air.
|
||||
if(istype(enemy_tile) && enemy_tile.parent && enemy_tile.parent.group_processing)
|
||||
// Tile is a border with another group, and the other group is in group processing mode.
|
||||
// Build border groups list
|
||||
if(!border_group)
|
||||
border_group = list()
|
||||
border_group += enemy_tile.parent
|
||||
|
||||
// Build enemies list
|
||||
if(!enemies)
|
||||
enemies = list()
|
||||
enemies += enemy_tile
|
||||
|
||||
// Build self-group border list
|
||||
if(!self_group_borders)
|
||||
self_group_borders = list()
|
||||
self_group_borders += border_tile
|
||||
else
|
||||
// Tile is a border with a singleton, not a group in group processing mode.
|
||||
// Build individual border list
|
||||
if(!border_individual)
|
||||
border_individual = list()
|
||||
border_individual += enemy_tile
|
||||
|
||||
// Build self-tile-border list
|
||||
if(!self_tile_borders)
|
||||
self_tile_borders = list()
|
||||
self_tile_borders += border_tile
|
||||
|
||||
var/abort_group = 0
|
||||
|
||||
// Process connections to adjacent groups
|
||||
var/border_index = 1
|
||||
if(border_group)
|
||||
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
|
||||
var/turf/simulated/floor/enemy_border
|
||||
if(self_group_borders && self_group_borders.len)
|
||||
self_border = self_group_borders[border_index]
|
||||
if(enemy_border)
|
||||
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 && !isnull(enemy_border) && !isnull(self_border))
|
||||
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 && border_individual)
|
||||
for(var/atom/enemy_tile in border_individual)
|
||||
var/connection_difference = 0
|
||||
var/turf/simulated/floor/self_border
|
||||
if(self_tile_borders)
|
||||
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 && !isnull(self_border))
|
||||
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)
|
||||
|
||||
|
||||
// This logic is not inverted because group processing may have been
|
||||
// suspended in the above block.
|
||||
if(!group_processing) //Revert to individual processing
|
||||
var/c = 0
|
||||
|
||||
// space fastpath
|
||||
if (members.len && length_space_border) {
|
||||
if (space_fastpath(parent_controller))
|
||||
// If the fastpath resulted in the group being zeroed, return early.
|
||||
return
|
||||
}
|
||||
for(var/turf/simulated/member in members)
|
||||
member.process_cell()
|
||||
if (!(c++ % 10) && parent_controller)
|
||||
parent_controller.scheck()
|
||||
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()
|
||||
|
||||
// If group processing is off, and the air group is bordered by a space tile,
|
||||
// execute a fast evacuation of the air in the group.
|
||||
// If the average pressure in the group is < 5kpa, the group will be zeroed
|
||||
// returns: 1 if the group is zeroed, 0 if not
|
||||
/datum/air_group/proc/space_fastpath(var/datum/controller/process/parent_controller)
|
||||
var/minDist
|
||||
var/dist
|
||||
var/turf/space/sample = locate()
|
||||
var/totalPressure = 0
|
||||
var/c
|
||||
|
||||
for(var/turf/simulated/member in members)
|
||||
minDist = null
|
||||
// find nearest space border tile
|
||||
for(var/turf/simulated/b in space_borders)
|
||||
if (b == member)
|
||||
continue
|
||||
|
||||
dist = get_dist(b, member)
|
||||
if (minDist == null || dist < minDist)
|
||||
minDist = dist
|
||||
|
||||
if (member.air && !isnull(minDist))
|
||||
// Todo - retain nearest space tile border and apply force proportional to amount
|
||||
// of air leaving through it
|
||||
member.air.mimic(sample, CLAMP(length_space_border / (2 * max(1, minDist)), 0.1, 1))
|
||||
if (member && member.air)
|
||||
totalPressure += member.air.return_pressure()
|
||||
|
||||
if (!(c++ % 20))
|
||||
parent_controller.scheck()
|
||||
|
||||
if (totalPressure / members.len < 5)
|
||||
space_group()
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/datum/air_group/proc/space_group()
|
||||
for(var/turf/simulated/member in members)
|
||||
if (member.air)
|
||||
member.air.zero()
|
||||
if (length_space_border)
|
||||
spaced = 1
|
||||
resume_group_processing()
|
||||
|
||||
/datum/air_group/proc/unspace_group()
|
||||
suspend_group_processing()
|
||||
spaced = 0
|
||||
@@ -0,0 +1,241 @@
|
||||
atom
|
||||
proc
|
||||
temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
if(reagents) reagents.temperature_reagents(exposed_temperature, exposed_volume)
|
||||
if(src.material) src.material.triggerTemp(src, exposed_temperature)
|
||||
return null
|
||||
|
||||
turf
|
||||
proc/hotspot_expose(exposed_temperature, exposed_volume, soh)
|
||||
if(src.material)
|
||||
src.material.triggerTemp(src, exposed_temperature)
|
||||
|
||||
simulated
|
||||
hotspot_expose(exposed_temperature, exposed_volume, soh)
|
||||
if (src == ff_debug_turf && ff_debugger)
|
||||
boutput(ff_debugger, "<span style='color:#ff8800'>Fireflash affecting tile at [showCoords(x, y, z)]</span>")
|
||||
|
||||
var/datum/gas_mixture/air_contents = return_air()
|
||||
if(src.material)
|
||||
src.material.triggerTemp(src, exposed_temperature)
|
||||
|
||||
if(reagents)
|
||||
reagents.temperature_reagents(exposed_temperature, 10, 10, 300)
|
||||
|
||||
for(var/atom/item in src) //I hate having to add this here too but too many things use hotspot_expose. This might cause lag on large fires.
|
||||
item.temperature_expose(null, exposed_temperature, exposed_volume)
|
||||
|
||||
if(!air_contents)
|
||||
return 0
|
||||
|
||||
if(active_hotspot)
|
||||
|
||||
if(locate(/obj/fire_foam) in src)
|
||||
active_hotspot.disposing() // have to call this now to force the lighting cleanup
|
||||
pool(active_hotspot)
|
||||
active_hotspot = null
|
||||
|
||||
if(soh)
|
||||
if(air_contents.toxins > 0.5 && air_contents.oxygen > 0.5)
|
||||
if(active_hotspot.temperature < exposed_temperature)
|
||||
active_hotspot.temperature = exposed_temperature
|
||||
active_hotspot.set_real_color()
|
||||
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(locate(/obj/fire_foam) in src) return 0
|
||||
|
||||
if(air_contents.oxygen < 0.5 || air_contents.toxins < 0.5)
|
||||
return 0
|
||||
|
||||
if(parent&&parent.group_processing)
|
||||
parent.suspend_group_processing()
|
||||
|
||||
active_hotspot = unpool(/obj/hotspot)
|
||||
active_hotspot.temperature = exposed_temperature
|
||||
active_hotspot.volume = exposed_volume
|
||||
active_hotspot.set_real_color()
|
||||
active_hotspot.set_loc(src)
|
||||
|
||||
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
|
||||
layer = NOLIGHT_EFFECTS_LAYER_BASE
|
||||
|
||||
mouse_opacity = 0
|
||||
|
||||
icon = 'icons/effects/fire.dmi'
|
||||
icon_state = "1"
|
||||
|
||||
//layer = TURF_LAYER
|
||||
alpha = 250
|
||||
blend_mode = BLEND_ADD
|
||||
var/datum/light/light
|
||||
|
||||
animate_movement = NO_STEPS // fix for weird unpool sliding
|
||||
|
||||
var
|
||||
volume = 125
|
||||
temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
|
||||
|
||||
just_spawned = 1
|
||||
|
||||
bypassing = 0
|
||||
|
||||
// now this is ss13 level code
|
||||
proc/set_real_color()
|
||||
var/input = temperature / 100
|
||||
|
||||
var/red
|
||||
if (input <= 66)
|
||||
red = 255
|
||||
else
|
||||
red = input - 60
|
||||
red = 329.698727446 * (red ** -0.1332047592)
|
||||
red = max(0, min(red, 255))
|
||||
|
||||
var/green
|
||||
if (input <= 66)
|
||||
green = max(0.001, input)
|
||||
green = 99.4708025861 * log(green) - 161.1195681661
|
||||
else
|
||||
green = input - 60
|
||||
green = 288.1221695283 * (green ** -0.0755148492)
|
||||
green = max(0, min(green, 255))
|
||||
|
||||
var/blue
|
||||
if (input >= 66)
|
||||
blue = 255
|
||||
else
|
||||
if (input <= 19)
|
||||
blue = 0
|
||||
else
|
||||
blue = input - 10
|
||||
blue = 138.5177312231 * log(blue) - 305.0447927307
|
||||
blue = max(0, min(blue, 255))
|
||||
|
||||
color = rgb(red, green, blue)
|
||||
|
||||
red /= 255
|
||||
green /= 255
|
||||
blue /= 255
|
||||
|
||||
// dear lord i apologuize for this conditional which i am about to write and commit. please be with the starving pygmies down in new guinea amen
|
||||
var/max_color_diff = max( abs(red - light.r), max ( abs (blue - light.b), abs (green - light.g) ) )
|
||||
// debug_log += "[src.x],[src.y]:[temperature] max diff was [max_color_diff], [red] [green] [blue] vs [sd_ColorRed] [sd_ColorGreen] [sd_ColorBlue]"
|
||||
if ( 0.05 < max_color_diff )
|
||||
light.set_color(red, green, blue)
|
||||
light.enable()
|
||||
|
||||
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/max((location.air.volume/5),1))
|
||||
|
||||
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)
|
||||
|
||||
set_real_color()
|
||||
|
||||
Crossed(var/atom/A)
|
||||
A.temperature_expose(null, temperature, volume)
|
||||
if (istype(A, /mob/living))
|
||||
var/mob/living/H = A
|
||||
var/B = min(55, max(0, temperature - 100 / 550))
|
||||
H.update_burning(B)
|
||||
|
||||
proc/process(turf/simulated/list/possible_spread)
|
||||
if(just_spawned)
|
||||
just_spawned = 0
|
||||
return 0
|
||||
|
||||
var/turf/simulated/floor/location = loc
|
||||
if(!istype(location) || (locate(/obj/fire_foam) in location))
|
||||
pool(src)
|
||||
return 0
|
||||
|
||||
if((temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) || (volume <= 1))
|
||||
pool(src)
|
||||
return 0
|
||||
|
||||
if(!location.air || location.air.toxins < 0.5 || location.air.oxygen < 0.5)
|
||||
pool(src)
|
||||
return 0
|
||||
|
||||
for(var/mob/living/L in loc)
|
||||
L.update_burning(min(max(temperature / 60, 5),33))
|
||||
|
||||
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)
|
||||
light = new /datum/light/point
|
||||
light.set_brightness(0.5)
|
||||
light.attach(src)
|
||||
// note: light is left disabled until the color is set
|
||||
|
||||
disposing()
|
||||
if (loc)
|
||||
loc:active_hotspot = null
|
||||
..()
|
||||
|
||||
ex_act()
|
||||
return
|
||||
@@ -0,0 +1,943 @@
|
||||
/*
|
||||
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
|
||||
var/moles = 0
|
||||
var/moles_archived = 0
|
||||
var/specific_heat = 0
|
||||
|
||||
/datum/gas/sleeping_agent
|
||||
specific_heat = 40
|
||||
/datum/gas/oxygen_agent_b
|
||||
specific_heat = 300
|
||||
/datum/gas/volatile_fuel
|
||||
specific_heat = 30
|
||||
/datum/gas/rad_particles
|
||||
specific_heat = 20
|
||||
|
||||
/datum/gas_mixture
|
||||
var/oxygen = 0
|
||||
var/tmp/oxygen_archived
|
||||
var/carbon_dioxide = 0
|
||||
var/tmp/carbon_dioxide_archived
|
||||
var/nitrogen = 0
|
||||
var/tmp/nitrogen_archived
|
||||
var/toxins = 0
|
||||
var/tmp/toxins_archived
|
||||
|
||||
var/temperature = 0
|
||||
var/tmp/temperature_archived
|
||||
|
||||
var/volume = CELL_VOLUME
|
||||
var/group_multiplier = 1
|
||||
var/graphic
|
||||
var/tmp/graphic_archived
|
||||
var/list/datum/gas/trace_gases
|
||||
var/tmp/fuel_burnt = 0
|
||||
|
||||
|
||||
// Overrides
|
||||
/datum/gas_mixture/disposing()
|
||||
if (trace_gases)
|
||||
trace_gases = null
|
||||
..()
|
||||
|
||||
/datum/gas_mixture/New()
|
||||
..()
|
||||
total_gas_mixtures++
|
||||
|
||||
|
||||
/datum/gas_mixture/unpooled()
|
||||
trace_gases = initial(trace_gases)
|
||||
volume = initial(volume)
|
||||
temperature = initial(temperature)
|
||||
group_multiplier = initial(group_multiplier)
|
||||
graphic = initial(graphic)
|
||||
oxygen_archived = initial(oxygen_archived)
|
||||
carbon_dioxide_archived = initial(carbon_dioxide_archived)
|
||||
nitrogen_archived = initial(nitrogen_archived)
|
||||
toxins_archived = initial(toxins_archived)
|
||||
temperature_archived = initial(temperature_archived)
|
||||
graphic_archived = initial(graphic_archived)
|
||||
fuel_burnt = initial(fuel_burnt)
|
||||
trace_gases = initial(trace_gases)
|
||||
oxygen = initial(oxygen)
|
||||
carbon_dioxide = initial(carbon_dioxide)
|
||||
nitrogen = initial(nitrogen)
|
||||
toxins = initial(toxins)
|
||||
..()
|
||||
|
||||
// Gas equation procs
|
||||
/datum/gas_mixture/proc/heat_capacity()
|
||||
var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins)
|
||||
|
||||
if(trace_gases && trace_gases.len)
|
||||
for(var/datum/gas/trace_gas in trace_gases)
|
||||
heat_capacity += trace_gas.moles*trace_gas.specific_heat
|
||||
|
||||
|
||||
return heat_capacity
|
||||
|
||||
/datum/gas_mixture/proc/heat_capacity_archived()
|
||||
var/heat_capacity_archived = HEAT_CAPACITY_CALCULATION(oxygen_archived,carbon_dioxide_archived,nitrogen_archived,toxins_archived)
|
||||
|
||||
if(trace_gases && 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
|
||||
|
||||
/datum/gas_mixture/proc/total_moles()
|
||||
var/moles = oxygen + carbon_dioxide + nitrogen + toxins
|
||||
|
||||
if(trace_gases && trace_gases.len)
|
||||
for(var/datum/gas/trace_gas in trace_gases)
|
||||
moles += trace_gas.moles
|
||||
|
||||
return moles
|
||||
|
||||
/datum/gas_mixture/proc/return_pressure()
|
||||
return (total_moles()*R_IDEAL_GAS_EQUATION*temperature/volume)
|
||||
|
||||
/datum/gas_mixture/proc/thermal_energy()
|
||||
return temperature*heat_capacity()
|
||||
|
||||
// Mutator procs
|
||||
// For specific events
|
||||
/datum/gas_mixture/proc/zero()
|
||||
trace_gases = null
|
||||
oxygen = 0
|
||||
carbon_dioxide = 0
|
||||
nitrogen = 0
|
||||
toxins = 0
|
||||
|
||||
/datum/gas_mixture/proc/check_tile_graphic()
|
||||
//returns 1 if graphic changed
|
||||
graphic = ""
|
||||
|
||||
if(toxins > MOLES_PLASMA_VISIBLE)
|
||||
graphic += "plasma;"
|
||||
else if(trace_gases && trace_gases.len)
|
||||
var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in trace_gases
|
||||
if(sleeping_agent && (sleeping_agent.moles > 1))
|
||||
graphic += "n2o;"
|
||||
var/datum/gas/rad_particles = locate(/datum/gas/rad_particles) in trace_gases
|
||||
if(rad_particles && (rad_particles.moles > 1))
|
||||
graphic += "n2o;"
|
||||
|
||||
return graphic != graphic_archived
|
||||
|
||||
/datum/gas_mixture/proc/react(atom/dump_location)
|
||||
var/reacting = 0 //set to 1 if a notable reaction occured (used by pipe_network)
|
||||
|
||||
if(trace_gases && 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)
|
||||
if(fire() > 0)
|
||||
reacting = 1
|
||||
|
||||
return reacting
|
||||
|
||||
/datum/gas_mixture/proc/fire()
|
||||
var/energy_released = 0
|
||||
var/old_heat_capacity = heat_capacity()
|
||||
|
||||
if(trace_gases && trace_gases.len)
|
||||
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
|
||||
//qdel(fuel_store)
|
||||
trace_gases -= fuel_store
|
||||
if(!trace_gases.len)
|
||||
trace_gases = null
|
||||
fuel_store = null
|
||||
|
||||
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/3
|
||||
oxygen -= plasma_burn_rate*oxygen_burn_rate
|
||||
carbon_dioxide += plasma_burn_rate/3
|
||||
|
||||
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
|
||||
|
||||
//Update archived versions of variables
|
||||
//Returns: 1 in all cases
|
||||
/datum/gas_mixture/proc/archive()
|
||||
oxygen_archived = oxygen
|
||||
carbon_dioxide_archived = carbon_dioxide
|
||||
nitrogen_archived = nitrogen
|
||||
toxins_archived = toxins
|
||||
|
||||
if(trace_gases && 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
|
||||
|
||||
//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
|
||||
/datum/gas_mixture/proc/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 && giver.trace_gases.len)
|
||||
for(var/datum/gas/trace_gas in giver.trace_gases)
|
||||
var/datum/gas/corresponding
|
||||
if(trace_gases && trace_gases.len)
|
||||
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)
|
||||
|
||||
//Merges all air from giver into self. Deletes giver.
|
||||
//Returns: 1 on success (no failure cases yet)
|
||||
/datum/gas_mixture/proc/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 && giver.trace_gases.len)
|
||||
for(var/datum/gas/trace_gas in giver.trace_gases)
|
||||
var/datum/gas/corresponding
|
||||
if(trace_gases && trace_gases.len)
|
||||
corresponding = locate(trace_gas.type) in trace_gases
|
||||
if(!corresponding)
|
||||
corresponding = new trace_gas.type()
|
||||
if(!trace_gases)
|
||||
trace_gases = list()
|
||||
trace_gases += corresponding
|
||||
corresponding.moles += trace_gas.moles*giver.group_multiplier/group_multiplier
|
||||
|
||||
pool(giver)
|
||||
return 1
|
||||
|
||||
//Proportionally removes amount of gas from the gas_mixture
|
||||
//Returns: gas_mixture with the gases removed
|
||||
/datum/gas_mixture/proc/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 = unpool(/datum/gas_mixture)
|
||||
|
||||
|
||||
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 && trace_gases.len)
|
||||
for(var/datum/gas/trace_gas in trace_gases)
|
||||
var/datum/gas/corresponding = new trace_gas.type()
|
||||
if(!removed.trace_gases)
|
||||
removed.trace_gases = list()
|
||||
removed.trace_gases += corresponding
|
||||
|
||||
corresponding.moles = (trace_gas.moles/sum)*amount
|
||||
trace_gas.moles -= corresponding.moles/group_multiplier
|
||||
|
||||
removed.temperature = temperature
|
||||
|
||||
return removed
|
||||
|
||||
//Proportionally removes amount of gas from the gas_mixture
|
||||
//Returns: gas_mixture with the gases removed
|
||||
/datum/gas_mixture/proc/remove_ratio(ratio)
|
||||
if(ratio <= 0)
|
||||
return null
|
||||
|
||||
ratio = min(ratio, 1)
|
||||
|
||||
var/datum/gas_mixture/removed = unpool(/datum/gas_mixture)
|
||||
|
||||
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 && trace_gases.len)
|
||||
for(var/datum/gas/trace_gas in trace_gases)
|
||||
var/datum/gas/corresponding = new trace_gas.type()
|
||||
if(!removed.trace_gases)
|
||||
removed.trace_gases = list()
|
||||
removed.trace_gases += corresponding
|
||||
|
||||
corresponding.moles = trace_gas.moles*ratio
|
||||
trace_gas.moles -= corresponding.moles/group_multiplier
|
||||
|
||||
removed.temperature = temperature
|
||||
|
||||
return removed
|
||||
|
||||
//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
|
||||
/datum/gas_mixture/proc/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)
|
||||
|
||||
//Copies variables from sample
|
||||
/datum/gas_mixture/proc/copy_from(datum/gas_mixture/sample)
|
||||
if (sample == null)
|
||||
return
|
||||
|
||||
oxygen = sample.oxygen
|
||||
carbon_dioxide = sample.carbon_dioxide
|
||||
nitrogen = sample.nitrogen
|
||||
toxins = sample.toxins
|
||||
|
||||
trace_gases = null
|
||||
if(sample.trace_gases && sample.trace_gases.len > 0)
|
||||
trace_gases = list()
|
||||
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
|
||||
|
||||
//Subtracts right_side from air_mixture. Used to help turfs mingle
|
||||
/datum/gas_mixture/proc/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(right_side.trace_gases && right_side.trace_gases.len > 0)
|
||||
trace_gases = list()
|
||||
|
||||
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
|
||||
|
||||
//Returns: 0 if the self-check failed then -1 if sharer-check failed then 1 if both checks pass
|
||||
/datum/gas_mixture/proc/check_gas_mixture(datum/gas_mixture/sharer)
|
||||
if (!sharer)
|
||||
return 0
|
||||
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 && sharer.trace_gases.len)
|
||||
if(!trace_gases || !trace_gases.len)
|
||||
return 0
|
||||
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 && trace_gases.len)
|
||||
if(!sharer.trace_gases || !sharer.trace_gases.len)
|
||||
return 0
|
||||
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 && 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
|
||||
if(sharer.trace_gases && sharer.trace_gases.len)
|
||||
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
|
||||
|
||||
//Returns: 0 if self-check failed or 1 if check passes
|
||||
/datum/gas_mixture/proc/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 && 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
|
||||
|
||||
//Performs air sharing calculations between two gas_mixtures assuming only 1 boundary length
|
||||
//Return: amount of gas exchanged (+ if sharer received)
|
||||
/datum/gas_mixture/proc/share(datum/gas_mixture/sharer)
|
||||
if(!sharer)
|
||||
return
|
||||
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_capacity_self_to_sharer = 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_capacity_self_to_sharer += air_heat_capacity
|
||||
else
|
||||
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_capacity_self_to_sharer += carbon_dioxide_heat_capacity
|
||||
else
|
||||
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_capacity_self_to_sharer += toxins_heat_capacity
|
||||
else
|
||||
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
|
||||
|
||||
if(trace_gases && trace_gases.len)
|
||||
trace_types_considered = list()
|
||||
|
||||
for(var/datum/gas/trace_gas in trace_gases)
|
||||
|
||||
var/datum/gas/corresponding
|
||||
if(sharer.trace_gases && sharer.trace_gases.len)
|
||||
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()
|
||||
if(!sharer.trace_gases)
|
||||
sharer.trace_gases = list()
|
||||
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_capacity_self_to_sharer += individual_heat_capacity
|
||||
else
|
||||
heat_capacity_sharer_to_self -= individual_heat_capacity
|
||||
|
||||
moved_moles += delta
|
||||
|
||||
trace_types_considered += trace_gas.type
|
||||
|
||||
|
||||
if(sharer.trace_gases && sharer.trace_gases.len)
|
||||
for(var/datum/gas/trace_gas in sharer.trace_gases)
|
||||
if(trace_types_considered && trace_gas.type in trace_types_considered) continue
|
||||
else
|
||||
var/datum/gas/corresponding
|
||||
var/delta = 0
|
||||
|
||||
corresponding = new trace_gas.type()
|
||||
if(!trace_gases)
|
||||
trace_gases = list()
|
||||
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
|
||||
|
||||
//Similar to share(...), except the model is not modified
|
||||
//Return: amount of gas exchanged
|
||||
/datum/gas_mixture/proc/mimic(turf/model, border_multiplier = 1)
|
||||
var/delta_oxygen = QUANTIZE(((oxygen_archived - model.oxygen)/5)*border_multiplier/group_multiplier)
|
||||
var/delta_carbon_dioxide = QUANTIZE(((carbon_dioxide_archived - model.carbon_dioxide)/5)*border_multiplier/group_multiplier)
|
||||
var/delta_nitrogen = QUANTIZE(((nitrogen_archived - model.nitrogen)/5)*border_multiplier/group_multiplier)
|
||||
var/delta_toxins = QUANTIZE(((toxins_archived - model.toxins)/5)*border_multiplier/group_multiplier)
|
||||
|
||||
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
|
||||
|
||||
|
||||
oxygen -= delta_oxygen
|
||||
carbon_dioxide -= delta_carbon_dioxide
|
||||
nitrogen -= delta_nitrogen
|
||||
toxins -= delta_toxins
|
||||
|
||||
var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins)
|
||||
|
||||
if(trace_gases && trace_gases.len)
|
||||
for(var/datum/gas/trace_gas in trace_gases)
|
||||
var/delta = 0
|
||||
|
||||
delta = QUANTIZE((trace_gas.moles_archived/5)*border_multiplier/group_multiplier)
|
||||
|
||||
trace_gas.moles -= delta
|
||||
|
||||
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))
|
||||
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
|
||||
|
||||
/datum/gas_mixture/proc/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
|
||||
|
||||
/datum/gas_mixture/proc/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
|
||||
|
||||
/datum/gas_mixture/proc/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
|
||||
|
||||
/datum/gas_mixture/proc/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
|
||||
|
||||
/datum/gas_mixture/proc/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)
|
||||
|
||||
/datum/gas_mixture/proc/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)
|
||||
|
||||
/datum/gas_mixture/proc/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
|
||||
|
||||
//Compares sample to self to see if within acceptable ranges that group processing may be enabled
|
||||
/datum/gas_mixture/proc/compare(datum/gas_mixture/sample)
|
||||
if (!sample)
|
||||
return 0
|
||||
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)))
|
||||
return 0
|
||||
|
||||
if(sample.trace_gases && 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
|
||||
if(trace_gases && trace_gases.len)
|
||||
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 && trace_gases.len)
|
||||
for(var/datum/gas/trace_gas in trace_gases)
|
||||
if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND)
|
||||
var/datum/gas/corresponding
|
||||
if(sample.trace_gases)
|
||||
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
|
||||
|
||||
// Dead prototypes (or never implemented?)
|
||||
// /datum/gas_mixture/proc/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
|
||||
|
||||
// /datum/gas_mixture/proc/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
|
||||
|
||||
// /datum/gas_mixture/proc/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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
// boutput(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
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
Should mirror stuff done in FEA_turf_tile
|
||||
*/
|
||||
|
||||
obj
|
||||
movable/floor
|
||||
|
||||
New()
|
||||
..()
|
||||
|
||||
air.oxygen = oxygen
|
||||
air.carbon_dioxide = carbon_dioxide
|
||||
air.nitrogen = nitrogen
|
||||
air.toxins = toxins
|
||||
|
||||
air.temperature = temperature
|
||||
|
||||
assume_air(datum/gas_mixture/giver)
|
||||
if(parent&&parent.group_processing)
|
||||
if(!parent.air.check_then_merge(giver))
|
||||
parent.suspend_group_processing()
|
||||
air.merge(giver)
|
||||
else
|
||||
air.merge(giver)
|
||||
|
||||
return 1
|
||||
|
||||
archive()
|
||||
air.archive()
|
||||
|
||||
archived_cycle = air_master.current_cycle
|
||||
|
||||
share_air_with_tile(turf/simulated/sharer)
|
||||
air.share(sharer.air)
|
||||
|
||||
mimic_air_with_tile(turf/model)
|
||||
air.mimic(model)
|
||||
|
||||
return_air()
|
||||
if(parent&&parent.group_processing)
|
||||
return parent.air
|
||||
else return air
|
||||
|
||||
remove_air(amount as num)
|
||||
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)
|
||||
|
||||
return removed
|
||||
|
||||
update_air_properties()//OPTIMIZE
|
||||
air_check_directions = 0
|
||||
|
||||
for(var/direction in list(NORTH, SOUTH, EAST, WEST))
|
||||
if(loc.CanPass(null, get_step(loc,direction), 0, 0))
|
||||
air_check_directions |= direction
|
||||
|
||||
if(parent)
|
||||
if(parent.borders)
|
||||
parent.borders -= src
|
||||
|
||||
group_border = 0
|
||||
for(var/direction in list(NORTH, SOUTH, EAST, WEST))
|
||||
if(air_check_directions&direction)
|
||||
var/turf/T = get_step(src,direction)
|
||||
var/obj/movable/floor/O = locate(/obj/movable/floor) in T
|
||||
if(!istype(O) || (O.parent!=parent))
|
||||
if(parent.borders)
|
||||
parent.borders -= src
|
||||
parent.borders += src
|
||||
else
|
||||
parent.borders = list(src)
|
||||
group_border |= direction
|
||||
|
||||
if(air_check_directions)
|
||||
processing = 1
|
||||
if(!parent)
|
||||
air_master.add_singleton(src)
|
||||
else
|
||||
processing = 0
|
||||
|
||||
process_cell()
|
||||
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 list(NORTH,SOUTH,EAST,WEST))
|
||||
if(air_check_directions&direction) //Grab all valid bordering tiles
|
||||
var/turf/simulated/enemy_tile = get_step(src, direction)
|
||||
var/obj/movable/floor/movable_on_enemy = locate(/obj/movable/floor) in enemy_tile
|
||||
if(movable_on_enemy)
|
||||
if(movable_on_enemy.archived_cycle < archived_cycle) //archive bordering tile information if not already done
|
||||
movable_on_enemy.archive()
|
||||
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))
|
||||
air.share(movable_on_enemy.parent.air)
|
||||
else
|
||||
movable_on_enemy.parent.suspend_group_processing()
|
||||
air.share(movable_on_enemy.air)
|
||||
//group processing failed so interact with individual tile
|
||||
else
|
||||
if(movable_on_enemy.current_cycle < current_cycle)
|
||||
share_air_with_tile(movable_on_enemy)
|
||||
else
|
||||
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))
|
||||
air.share(enemy_tile.parent.air)
|
||||
else
|
||||
enemy_tile.parent.suspend_group_processing()
|
||||
air.share(enemy_tile.air)
|
||||
//group processing failed so interact with individual tile
|
||||
else
|
||||
if(enemy_tile.current_cycle < current_cycle)
|
||||
share_air_with_tile(enemy_tile)
|
||||
else
|
||||
mimic_air_with_tile(enemy_tile) //bordering a tile with fixed air properties
|
||||
|
||||
return 1
|
||||
else
|
||||
air_master.active_singletons -= src //not active if not processing!
|
||||
return 0
|
||||
@@ -0,0 +1,399 @@
|
||||
var/atmos_suspend = 0
|
||||
/*
|
||||
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
|
||||
|
||||
|
||||
*/
|
||||
|
||||
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
|
||||
var/global/total_gas_mixtures = 0
|
||||
|
||||
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
|
||||
var/datum/controller/process/air_system/parent_controller = null
|
||||
|
||||
|
||||
proc
|
||||
setup(datum/controller/process/air_system/controller)
|
||||
//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
|
||||
|
||||
set_controller(datum/controller/process/air_system/controller)
|
||||
parent_controller = controller
|
||||
|
||||
queue_update_tile(turf/simulated/T)
|
||||
if (!(T in tiles_to_update))
|
||||
tiles_to_update += T
|
||||
|
||||
queue_update_group(datum/air_group)
|
||||
if (!(air_group in groups_to_rebuild))
|
||||
groups_to_rebuild += air_group
|
||||
|
||||
setup(datum/controller/process/air_system/controller)
|
||||
set_controller(controller)
|
||||
|
||||
boutput(world, "<span style=\"color:red\">Processing Geometry...</span>")
|
||||
sleep(1)
|
||||
|
||||
var/start_time = world.timeofday
|
||||
|
||||
for(var/turf/simulated/S in world)
|
||||
if(!S.blocks_air && !S.parent)
|
||||
assemble_group_turf(S)
|
||||
//for(var/turf/simulated/S in world) //Update all pathing and border information as well
|
||||
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()
|
||||
*/
|
||||
boutput(world, "<span style=\"color:red\">Geometry processed in [(world.timeofday-start_time)/10] seconds!</span>")
|
||||
|
||||
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
|
||||
var/list/turf/simulated/possible_space_borders
|
||||
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))
|
||||
if(!possible_space_borders)
|
||||
possible_space_borders = list()
|
||||
if(!possible_space_borders.Find(test))
|
||||
possible_space_borders += test
|
||||
test.length_space_border++
|
||||
else
|
||||
if(!possible_borders)
|
||||
possible_borders = list()
|
||||
if(!possible_borders.Find(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/group = new
|
||||
if(possible_borders && possible_borders.len>0)
|
||||
group.borders = possible_borders
|
||||
if(possible_space_borders && 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 && 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()
|
||||
set background = 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
|
||||
|
||||
var/c
|
||||
for(var/datum/air_group/AG in air_groups)
|
||||
AG.check_regroup()
|
||||
// There's about 700 airgroups, so this should be enough...
|
||||
if (!(c++ % 50))
|
||||
parent_controller.scheck()
|
||||
|
||||
return 1
|
||||
|
||||
process_update_tiles()
|
||||
set background = 1
|
||||
var/c
|
||||
for(var/turf/simulated/T in tiles_to_update)
|
||||
T.update_air_properties()
|
||||
// This list can be quite large, so lets not scheck like a madperson.
|
||||
if(!(c++ % 50))
|
||||
parent_controller.scheck()
|
||||
|
||||
/*
|
||||
for(var/obj/movable/floor/O in tiles_to_update)
|
||||
O.update_air_properties()
|
||||
*/
|
||||
tiles_to_update.len = 0
|
||||
|
||||
process_rebuild_select_groups()
|
||||
set background = 1
|
||||
var/turf/list/turfs = list()
|
||||
|
||||
for(var/datum/air_group/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
|
||||
air_master.air_groups -= turf_AG
|
||||
turf_AG.members.len = 0
|
||||
|
||||
// This can be some expensive shit, so lets scheck every time.
|
||||
parent_controller.scheck()
|
||||
|
||||
var/c
|
||||
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()
|
||||
|
||||
if (!(c++ % 10))
|
||||
parent_controller.scheck()
|
||||
|
||||
// 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
|
||||
qdel(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()
|
||||
set background = 1
|
||||
var/c
|
||||
for(var/datum/air_group/AG in air_groups)
|
||||
AG.process_group(parent_controller)
|
||||
if (!(c++ % 50) && parent_controller)
|
||||
parent_controller.scheck()
|
||||
|
||||
process_singletons()
|
||||
set background = 1
|
||||
var/c
|
||||
for(var/item in active_singletons)
|
||||
item:process_cell()
|
||||
|
||||
if (!(c++ % 20) && parent_controller)
|
||||
parent_controller.scheck()
|
||||
|
||||
process_super_conductivity()
|
||||
set background = 1
|
||||
|
||||
for(var/turf/simulated/hot_potato in active_super_conductivity)
|
||||
hot_potato.super_conduct()
|
||||
if (parent_controller)
|
||||
parent_controller.scheck()
|
||||
|
||||
process_high_pressure_delta()
|
||||
set background = 1
|
||||
for(var/turf/pressurized in high_pressure_delta)
|
||||
pressurized.high_pressure_movements()
|
||||
if (parent_controller)
|
||||
parent_controller.scheck()
|
||||
|
||||
high_pressure_delta.len = 0
|
||||
@@ -0,0 +1,637 @@
|
||||
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)
|
||||
|
||||
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
|
||||
// TODO this is returning a new air object, but object_tile returns the existing air
|
||||
// This is used in a lot of places and thrown away, so it should be pooled,
|
||||
// But there is no way to tell here if it will be retained or discarded, so
|
||||
// we can't pool the object returned by return_air. Bad news, man.
|
||||
var/datum/gas_mixture/GM = unpool(/datum/gas_mixture)
|
||||
|
||||
GM.oxygen = oxygen
|
||||
GM.carbon_dioxide = carbon_dioxide
|
||||
GM.nitrogen = nitrogen
|
||||
GM.toxins = toxins
|
||||
|
||||
GM.temperature = temperature
|
||||
|
||||
return GM
|
||||
|
||||
remove_air(amount as num)//, remove_water = 0)
|
||||
//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 = unpool(/datum/gas_mixture)
|
||||
var/sum = oxygen + carbon_dioxide + nitrogen + toxins
|
||||
//if(remove_water)
|
||||
// sum += water
|
||||
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
|
||||
//if(remove_water)
|
||||
// GM.water += (water/sum)*amount
|
||||
|
||||
GM.temperature = temperature
|
||||
|
||||
return GM
|
||||
|
||||
turf
|
||||
var/pressure_difference = 0
|
||||
var/pressure_direction = 0
|
||||
var/tmp/obj/hotspot/active_hotspot
|
||||
|
||||
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/parent
|
||||
group_border = 0
|
||||
length_space_border = 0
|
||||
|
||||
air_check_directions = 0 //Do not modify this, just call air_master.queue_update_tile on this
|
||||
|
||||
archived_cycle = 0
|
||||
current_cycle = 0
|
||||
|
||||
temperature_archived //USED ONLY FOR SOLIDS
|
||||
being_superconductive = 0
|
||||
obj/overlay/tile_gas_effect/gas_icon_overlay
|
||||
visuals_state
|
||||
|
||||
|
||||
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)
|
||||
if (disposed)
|
||||
return
|
||||
|
||||
//overlays.len = 0
|
||||
|
||||
var/list/graphics = params2list(model.graphic)//dd_text2list(model.graphic, ";")
|
||||
|
||||
if(!graphics || !graphics.len)
|
||||
if (gas_icon_overlay)
|
||||
pool(gas_icon_overlay)
|
||||
gas_icon_overlay = null
|
||||
return
|
||||
|
||||
var/new_visuals_state = 0
|
||||
|
||||
for(var/str in graphics)
|
||||
switch(str)
|
||||
/*
|
||||
if("water3")
|
||||
effect_overlay.overlays.Add(w3master)
|
||||
if("water2")
|
||||
effect_overlay.overlays.Add(w2master)
|
||||
if("water1")
|
||||
effect_overlay.overlays.Add(w1master)
|
||||
*/
|
||||
if("plasma")
|
||||
new_visuals_state |= 1
|
||||
if("n2o")
|
||||
new_visuals_state |= 2
|
||||
else
|
||||
continue
|
||||
|
||||
if (new_visuals_state)
|
||||
if (new_visuals_state != visuals_state)
|
||||
if(!gas_icon_overlay)
|
||||
gas_icon_overlay = unpool(/obj/overlay/tile_gas_effect)
|
||||
gas_icon_overlay.set_loc(src)
|
||||
else
|
||||
gas_icon_overlay.overlays.len = 0
|
||||
|
||||
visuals_state = new_visuals_state
|
||||
if (visuals_state & 1)
|
||||
gas_icon_overlay.overlays.Add(plmaster)
|
||||
if (visuals_state & 2)
|
||||
gas_icon_overlay.overlays.Add(slmaster)
|
||||
else
|
||||
if (gas_icon_overlay)
|
||||
pool(gas_icon_overlay)
|
||||
gas_icon_overlay = null
|
||||
New()
|
||||
..()
|
||||
|
||||
if(!blocks_air)
|
||||
air = unpool(/datum/gas_mixture)
|
||||
|
||||
air.oxygen = oxygen
|
||||
air.carbon_dioxide = carbon_dioxide
|
||||
air.nitrogen = nitrogen
|
||||
air.toxins = toxins
|
||||
|
||||
air.temperature = temperature
|
||||
|
||||
if(air_master)
|
||||
air_master.queue_update_tile(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.queue_update_tile(target)
|
||||
|
||||
disposing()
|
||||
if(air_master)
|
||||
if(parent)
|
||||
air_master.queue_update_group(parent)
|
||||
parent.members.Remove(src)
|
||||
else
|
||||
air_master.active_singletons.Remove(src)
|
||||
if(active_hotspot)
|
||||
active_hotspot.disposing() // have to call this now to force the lighting cleanup
|
||||
if (active_hotspot)
|
||||
pool(active_hotspot)
|
||||
active_hotspot = null
|
||||
if(blocks_air)
|
||||
for(var/direction in list(NORTH, SOUTH, EAST, WEST))
|
||||
var/turf/simulated/tile = get_step(src,direction)
|
||||
if(air_master && istype(tile) && !tile.blocks_air)
|
||||
air_master.queue_update_tile(tile)
|
||||
pool(air)
|
||||
air = null
|
||||
parent = null
|
||||
..()
|
||||
|
||||
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)//, remove_water = 0)
|
||||
if(air)
|
||||
var/datum/gas_mixture/removed = null
|
||||
|
||||
if(parent&&parent.group_processing)
|
||||
removed = parent.air.check_then_remove(amount)//, remove_water)
|
||||
if(!removed)
|
||||
parent.suspend_group_processing()
|
||||
removed = air.remove(amount)//, remove_water)
|
||||
else
|
||||
removed = air.remove(amount)//, remove_water)
|
||||
|
||||
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
|
||||
if(processing && air)
|
||||
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)
|
||||
if(!possible_fire_spreads)
|
||||
possible_fire_spreads = list()
|
||||
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!
|
||||
return
|
||||
|
||||
air.react()
|
||||
|
||||
if(active_hotspot && possible_fire_spreads)
|
||||
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 (!neighbor) continue
|
||||
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)
|
||||
// boutput(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)
|
||||
// boutput(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)
|
||||
// boutput(world, "OPEN, SOLID")
|
||||
|
||||
else //Both tiles are solid
|
||||
share_temperature_mutual_solid(modeled_neighbor, modeled_neighbor.thermal_conductivity)
|
||||
// boutput(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, src.thermal_conductivity))
|
||||
parent.suspend_group_processing()
|
||||
air.temperature_turf_share(src, src.thermal_conductivity)
|
||||
else
|
||||
air.temperature_turf_share(src, 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((src.heat_capacity > 0) && (model.heat_capacity > 0) && (abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER))
|
||||
|
||||
var/heat = conduction_coefficient*delta_temperature* \
|
||||
(src.heat_capacity*model.heat_capacity/(src.heat_capacity+model.heat_capacity))
|
||||
temperature -= heat/src.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* \
|
||||
(src.heat_capacity*sharer.heat_capacity/(src.heat_capacity+sharer.heat_capacity))
|
||||
|
||||
temperature -= heat/src.heat_capacity
|
||||
sharer.temperature += sharer.heat_capacity != 0 ? heat/sharer.heat_capacity : 0
|
||||
|
||||
proc/consider_superconductivity(starting)
|
||||
|
||||
if(being_superconductive || !src.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
|
||||
|
||||
proc/update_nearby_tiles(need_rebuild)
|
||||
if(!air_master) return 0
|
||||
|
||||
var/turf/simulated/north = get_step(src,NORTH)
|
||||
var/turf/simulated/south = get_step(src,SOUTH)
|
||||
var/turf/simulated/east = get_step(src,EAST)
|
||||
var/turf/simulated/west = get_step(src,WEST)
|
||||
|
||||
if(need_rebuild)
|
||||
if(istype(src)) //Rebuild/update nearby group geometry
|
||||
if(src.parent)
|
||||
air_master.queue_update_group(src.parent)
|
||||
else
|
||||
air_master.queue_update_tile(src)
|
||||
if(istype(north))
|
||||
if(north.parent)
|
||||
air_master.queue_update_group(north.parent)
|
||||
else
|
||||
air_master.queue_update_tile(north)
|
||||
if(istype(south))
|
||||
if(south.parent)
|
||||
air_master.queue_update_group(south.parent)
|
||||
else
|
||||
air_master.queue_update_tile(south)
|
||||
if(istype(east))
|
||||
if(east.parent)
|
||||
air_master.queue_update_group(east.parent)
|
||||
else
|
||||
air_master.queue_update_tile(east)
|
||||
if(istype(west))
|
||||
if(west.parent)
|
||||
air_master.queue_update_group(west.parent)
|
||||
else
|
||||
air_master.queue_update_tile(west)
|
||||
else
|
||||
if(istype(src)) air_master.queue_update_tile(src)
|
||||
if(istype(north)) air_master.queue_update_tile(north)
|
||||
if(istype(south)) air_master.queue_update_tile(south)
|
||||
if(istype(east)) air_master.queue_update_tile(east)
|
||||
if(istype(west)) air_master.queue_update_tile(west)
|
||||
|
||||
return 1
|
||||
@@ -0,0 +1,425 @@
|
||||
#define FTCS_Background "#999999"
|
||||
#define FTCS_Button "#bbbbbb"
|
||||
#define FTCS_Cancel "#FFFFFF"
|
||||
#define FTCS_Cancel_Background "#FF0000"
|
||||
#define FTCS_Layer 1000
|
||||
#define FTCS_Help_Background "#0000dd"
|
||||
#define FTCS_Help_Color "#FFFFFF"
|
||||
|
||||
f_color_selector_handler
|
||||
var
|
||||
current_clients[0]
|
||||
current_selectors[0]
|
||||
|
||||
|
||||
|
||||
proc
|
||||
Get_Color(mob/M, default_color = null)
|
||||
if(ismob(M))
|
||||
if(!M.client)
|
||||
world.log << "<b>ERROR:</b> Call to f_color_selector_handler passed mob with no client."
|
||||
return
|
||||
var/client/C
|
||||
if(ismob(M))
|
||||
C = M.client
|
||||
else if(istype(M, /client))
|
||||
C = M
|
||||
else
|
||||
world.log << "<b>ERROR:</b> Call to f_color_selector_handler passed invalid value. (Not a client or mob with client.)"
|
||||
return
|
||||
if(C in current_clients)
|
||||
return
|
||||
current_clients += C
|
||||
var/customization_second_color_selector/F = new(C, default_color, src)
|
||||
current_selectors += F
|
||||
var/color = F.Get_Color(C)
|
||||
del F
|
||||
current_clients -= C
|
||||
return color
|
||||
|
||||
customization_second_color_selector
|
||||
var
|
||||
f_color_selector_handler/owner
|
||||
list/pieces = new
|
||||
R = 0
|
||||
G = 0
|
||||
B = 0
|
||||
current_color
|
||||
background[0]
|
||||
obj/FTCS_Object/current_color/Current_Color
|
||||
obj/FTCS_Object/current_rgb_text/RGB_Text = new
|
||||
ok_buttons[0]
|
||||
waiting = TRUE
|
||||
list/backgroundPieces = new
|
||||
|
||||
|
||||
New(client/C, default_color, f_color_selector_handler/F)
|
||||
..()
|
||||
owner = F
|
||||
Setup(C)
|
||||
if(default_color)
|
||||
Current_Color.Update_Color(default_color)
|
||||
UpdateColorText(default_color, C)
|
||||
Del()
|
||||
for(var/V in (ok_buttons + pieces + background + Current_Color + backgroundPieces + RGB_Text))
|
||||
del V
|
||||
..()
|
||||
proc
|
||||
UpdateColorText(color, client/C)
|
||||
var/r
|
||||
var/g
|
||||
var/b
|
||||
r = Hex2Num(copytext(color, 2,4))
|
||||
g = Hex2Num(copytext(color, 4,6))
|
||||
b = Hex2Num(copytext(color, 6))
|
||||
R = r
|
||||
G = g
|
||||
B = b
|
||||
RGB_Text.Update("RED", r)
|
||||
RGB_Text.Update("GREEN", g)
|
||||
RGB_Text.Update("BLUE", b)
|
||||
for(var/obj/FTCS_Object/color_slider/O in pieces)
|
||||
if(O.base_color == "RED" && r >= O.base_value && r <= O.base_value+63)
|
||||
O.SetMark(round((r-O.base_value)/2), C)
|
||||
if(O.base_color == "GREEN" && g >= O.base_value && g <= O.base_value+63)
|
||||
O.SetMark(round((g-O.base_value)/2), C)
|
||||
if(O.base_color == "BLUE" && b >= O.base_value && b <= O.base_value+63)
|
||||
O.SetMark(round((b-O.base_value)/2), C)
|
||||
|
||||
|
||||
|
||||
Hex2Num(value)
|
||||
var/list/nums = list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
|
||||
return (16*(nums.Find(uppertext(copytext(value, 1,2)))-1)+nums.Find(uppertext(copytext(value,2)))-1)
|
||||
|
||||
Cancel()
|
||||
current_color = null
|
||||
waiting = FALSE
|
||||
|
||||
Setup(client/C)
|
||||
var/i
|
||||
var/xval = Get_X(C)
|
||||
var/yval = Get_Y(C)
|
||||
ShowBackground(xval, yval, C)
|
||||
Show_Text(xval,yval, C)
|
||||
Show_Buttons(xval,yval,C)
|
||||
// Set_Background(xval,yval,C)
|
||||
Current_Color = new(null,"[xval+1],[yval-2]", C)
|
||||
Current_Color.Update_Color(current_color)
|
||||
for(i=0, i<=3, i++)
|
||||
pieces += new /obj/FTCS_Object/color_slider/red(null,i,"[xval+i+1],[yval-1]", src)
|
||||
pieces += new /obj/FTCS_Object/color_slider/green(null,i,"[xval+i+1],[yval-1]", src)
|
||||
pieces += new /obj/FTCS_Object/color_slider/blue(null,i,"[xval+i+1],[yval-1]", src)
|
||||
|
||||
Done()
|
||||
waiting = FALSE
|
||||
|
||||
Set_Background(xval,yval,client/C)
|
||||
background += new /obj/FTCS_Object/background(null,"[xval+4],[yval-1]",C)
|
||||
|
||||
Show_Buttons(xval,yval,client/C)
|
||||
ok_buttons += new /obj/FTCS_Object/ok_buttons(null,"[xval+4]:8,[yval-2]","O",C, src)
|
||||
background += new /obj/FTCS_Object/cancel_button(null, "[xval+3]:16,[yval-2]", C, src)
|
||||
background += new /obj/FTCS_Object/help_button(null, "[xval+2]:22,[yval-2]", C, src)
|
||||
|
||||
ShowBackground(xval, yval, client/C)
|
||||
for(var/i in 1 to 6)
|
||||
for(var/j in 1 to 4)
|
||||
var/obj/O = new()
|
||||
O.layer = FTCS_Layer-1
|
||||
O.icon = 'icons/colselection/F_Select_Background.dmi'
|
||||
O.icon_state = "[i],[j]"
|
||||
O.screen_loc = "[xval+i-1],[yval+j-4]"
|
||||
backgroundPieces += O
|
||||
for(var/obj/P in backgroundPieces)
|
||||
C.screen += P
|
||||
|
||||
Show_Text(xval,yval,client/C)
|
||||
var/i
|
||||
for(i=1, i<=6, i++)
|
||||
var/obj/O = new(null)
|
||||
O.text = "<font bgcolor=[FTCS_Background] color=#000055>[copytext("Select",i,i+1)]"
|
||||
O.screen_loc = "[xval-1+i],[yval+1]"
|
||||
O.layer = FTCS_Layer
|
||||
O.name = "Select Color"
|
||||
C.screen += O
|
||||
background += O
|
||||
for(i=1, i<=6, i++)
|
||||
var/obj/O = new(null)
|
||||
O.text = "<font bgcolor=[FTCS_Background] color=#000055>[copytext("Color ",i,i+1)]"
|
||||
O.screen_loc = "[xval-1+i],[yval]"
|
||||
O.layer = FTCS_Layer
|
||||
O.name = "Select Color"
|
||||
C.screen += O
|
||||
background += O
|
||||
RGB_Text.screen_loc = "[xval+1]:26,[yval-2]"
|
||||
C.screen += RGB_Text
|
||||
|
||||
|
||||
|
||||
Update_Color(base_color, value)
|
||||
switch(base_color)
|
||||
if("RED")
|
||||
R = value
|
||||
if("GREEN")
|
||||
G = value
|
||||
if("BLUE")
|
||||
B = value
|
||||
current_color = rgb(R,G,B)
|
||||
Current_Color.Update_Color(current_color)
|
||||
RGB_Text.Update(base_color, value)
|
||||
|
||||
Get_Color(client/C)
|
||||
for(var/V in pieces)
|
||||
C.screen += V
|
||||
while(waiting)
|
||||
sleep(10)
|
||||
return current_color
|
||||
|
||||
Get_X(client/C)
|
||||
if(isnum(C.view)) //If view is already a number, set xval and yval
|
||||
if(C.view >=4)
|
||||
return C.view-3
|
||||
else
|
||||
return 1
|
||||
else //If not, it is a text var. Parse the xval and yval values
|
||||
var/divider = findtext(lowertext(C.view), "x")
|
||||
var/xval = text2num(copytext(C.view, 1, divider))
|
||||
if(xval >= 6)
|
||||
return round(xval/2 - 3)
|
||||
else
|
||||
return 0
|
||||
Get_Y(client/C)
|
||||
if(isnum(C.view)) //If view is already a number, set xval and yval
|
||||
if(C.view >=2)
|
||||
return C.view+3
|
||||
else
|
||||
return 5
|
||||
else //If not, it is a text var. Parse the xval and yval values
|
||||
var/divider = findtext(lowertext(C.view), "x")
|
||||
var/yval = text2num(copytext(C.view, divider+1))
|
||||
if(yval >= 6)
|
||||
return round(yval/2 + 3)
|
||||
else
|
||||
return 5
|
||||
|
||||
|
||||
|
||||
|
||||
// yval = text2num(copytext(C.view, divider+1))
|
||||
|
||||
|
||||
obj/FTCS_Object
|
||||
color_slider
|
||||
icon = 'icons/colselection/sliders.dmi'
|
||||
layer = FTCS_Layer
|
||||
var
|
||||
obj/marker
|
||||
base_color
|
||||
base_value
|
||||
Yval
|
||||
Xval
|
||||
customization_second_color_selector/Owner
|
||||
New(loc,position, s_loc, customization_second_color_selector/F)
|
||||
..()
|
||||
icon_state = "[base_color]_[position+1]"
|
||||
Owner = F
|
||||
base_value = 2*position*32
|
||||
screen_loc = s_loc
|
||||
|
||||
|
||||
MouseUp(location, control, params)
|
||||
var/list/L = params2list(params)
|
||||
var/icon_x = text2num(L["icon-x"])
|
||||
// drsingh for Cannot execute null.Update Color()
|
||||
if (!isnull(Owner)) Owner.Update_Color(base_color, base_value+2*icon_x)
|
||||
SetMark(icon_x, usr.client)
|
||||
|
||||
proc
|
||||
SetMark(icon_x, client/C)
|
||||
for(var/obj/FTCS_Object/color_slider/O in C.screen)
|
||||
if(O.base_color == src.base_color)
|
||||
O.overlays.Cut()
|
||||
var/icon/I = new('icons/colselection/selected_slider.dmi')
|
||||
I.Shift(EAST, min(icon_x,31))
|
||||
switch(base_color)
|
||||
if("GREEN")
|
||||
I.Shift(NORTH, 10)
|
||||
if("RED")
|
||||
I.Shift(NORTH, 20)
|
||||
var/obj/T = new()
|
||||
T.icon=I
|
||||
T.layer = FTCS_Layer+10
|
||||
overlays += I
|
||||
|
||||
|
||||
red
|
||||
base_color = "RED"
|
||||
name = "Red"
|
||||
New()
|
||||
..()
|
||||
text = "<font bgcolor=[rgb(base_value+32,0,0)]> "
|
||||
|
||||
green
|
||||
base_color = "GREEN"
|
||||
name = "Green"
|
||||
New()
|
||||
..()
|
||||
text = "<font bgcolor=[rgb(0,base_value+32,0)]> "
|
||||
|
||||
blue
|
||||
base_color = "BLUE"
|
||||
name = "Blue"
|
||||
New()
|
||||
..()
|
||||
text = "<font bgcolor=[rgb(0,0,base_value+32)]> "
|
||||
|
||||
obj/FTCS_Object
|
||||
layer = FTCS_Layer
|
||||
current_rgb_text
|
||||
icon = 'icons/colselection/numbers_ones.dmi'
|
||||
icon_state = "CODES_BACKGROUND"
|
||||
layer = 1118
|
||||
var
|
||||
icon/red_overlay
|
||||
icon/green_overlay
|
||||
icon/blue_overlay
|
||||
|
||||
proc
|
||||
num2alpha(var/N as num)
|
||||
switch(N)
|
||||
if(1)
|
||||
return "ONE"
|
||||
if(2)
|
||||
return "TWO"
|
||||
if(3)
|
||||
return "THREE"
|
||||
if(4)
|
||||
return "FOUR"
|
||||
if(5)
|
||||
return "FIVE"
|
||||
if(6)
|
||||
return "SIX"
|
||||
if(7)
|
||||
return "SEVEN"
|
||||
if(8)
|
||||
return "EIGHT"
|
||||
if(9)
|
||||
return "NINE"
|
||||
if(0)
|
||||
return "ZERO"
|
||||
|
||||
Update(color, value)
|
||||
switch(color)
|
||||
if("RED")
|
||||
overlays -= red_overlay
|
||||
red_overlay = Get_Number_Overlay(value)
|
||||
red_overlay.Shift(NORTH, 20)
|
||||
overlays += red_overlay
|
||||
if("GREEN")
|
||||
overlays -= green_overlay
|
||||
green_overlay = Get_Number_Overlay(value)
|
||||
green_overlay.Shift(NORTH, 10)
|
||||
overlays += green_overlay
|
||||
if("BLUE")
|
||||
overlays -= blue_overlay
|
||||
blue_overlay = Get_Number_Overlay(value)
|
||||
overlays += blue_overlay
|
||||
|
||||
Get_Number_Overlay(value)
|
||||
var/icon/total_overlay = new /icon('icons/colselection/numbers_ones.dmi', "BLANK")
|
||||
if(value >= 100)
|
||||
var/icon/temp_icon = new('icons/colselection/numbers_ones.dmi', num2alpha((value-(value%100))/100))
|
||||
temp_icon.Shift(WEST, 12)
|
||||
total_overlay.Blend(temp_icon, ICON_OVERLAY)
|
||||
if(value >= 10)
|
||||
var/icon/temp_icon = new('icons/colselection/numbers_ones.dmi', num2alpha((value -(value-value%100) - value%10)/10))
|
||||
temp_icon.Shift(WEST, 6)
|
||||
total_overlay.Blend(temp_icon, ICON_OVERLAY)
|
||||
var/icon/I = new('icons/colselection/numbers_ones.dmi', num2alpha((value - (value-value%10))))
|
||||
total_overlay.Blend(I, ICON_OVERLAY)
|
||||
return total_overlay
|
||||
|
||||
current_color
|
||||
name = "Current Color"
|
||||
layer = FTCS_Layer
|
||||
text = "<font bgcolor=#000001> "
|
||||
icon = 'icons/colselection/blank.dmi'
|
||||
New(loc,s_loc,client/C)
|
||||
..()
|
||||
screen_loc = s_loc
|
||||
C.screen += src
|
||||
proc
|
||||
Update_Color(value = "#000000")
|
||||
var/icon/I = new('icons/colselection/blank.dmi')
|
||||
if(value)
|
||||
I.Blend(value, ICON_ADD)
|
||||
icon = I
|
||||
|
||||
ok_buttons
|
||||
layer = FTCS_Layer
|
||||
name = "OK"
|
||||
icon = 'icons/colselection/button.dmi'
|
||||
var
|
||||
customization_second_color_selector/Owner
|
||||
New(loc,s_loc,letter, client/C, customization_second_color_selector/F)
|
||||
..()
|
||||
Owner = F
|
||||
screen_loc = s_loc
|
||||
text = "<font bgcolor=[FTCS_Button] color=#000055>[letter]"
|
||||
C.screen += src
|
||||
Click()
|
||||
..()
|
||||
Owner.Done()
|
||||
|
||||
cancel_button
|
||||
layer = FTCS_Layer
|
||||
name = "Cancel"
|
||||
icon = 'icons/colselection/cancel.dmi'
|
||||
var
|
||||
customization_second_color_selector/Owner
|
||||
New(loc,s_loc, client/C, customization_second_color_selector/F)
|
||||
..()
|
||||
Owner = F
|
||||
screen_loc = s_loc
|
||||
text = "<font bgcolor=[FTCS_Cancel_Background] color=[FTCS_Cancel]>X"
|
||||
C.screen += src
|
||||
Click()
|
||||
..()
|
||||
Owner.Cancel()
|
||||
|
||||
background
|
||||
name = ""
|
||||
layer = FTCS_Layer-1
|
||||
New(loc,s_loc,client/C)
|
||||
..()
|
||||
text = "<font bgcolor=[FTCS_Background]> "
|
||||
screen_loc = s_loc
|
||||
C.screen += src
|
||||
|
||||
help_button
|
||||
name = "Help"
|
||||
layer = FTCS_Layer
|
||||
icon = 'icons/colselection/help.dmi'
|
||||
invisibility = 100
|
||||
var
|
||||
customization_second_color_selector/Owner
|
||||
New(loc,s_loc, client/C, customization_second_color_selector/F)
|
||||
..()
|
||||
Owner = F
|
||||
text = "<font bgcolor=[FTCS_Help_Background] color=[FTCS_Help_Color]>?"
|
||||
screen_loc = s_loc
|
||||
C.screen += src
|
||||
Click()
|
||||
..()
|
||||
var/rendered = {"
|
||||
<b>Basic Help</b>
|
||||
To select a color, simply click on the red, green and blue selection
|
||||
bars until you get the color you want. Once you have the color you
|
||||
want, click the 'OK' button. Click the red slashed circle button to cancel.
|
||||
"}
|
||||
boutput(usr, rendered)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,499 @@
|
||||
var
|
||||
RL_Generation = 0
|
||||
|
||||
#define RL_Atten_Quadratic 2.2 // basically just brightness scaling atm
|
||||
#define RL_Atten_Constant -0.1 // constant subtracted at every point to make sure it goes <0 after some distance
|
||||
#define RL_MaxRadius 7 // maximum allowed light.radius value. if any light ends up needing more than this it'll cap and look screwy
|
||||
|
||||
datum/light
|
||||
var
|
||||
x
|
||||
y
|
||||
z
|
||||
|
||||
r = 1
|
||||
g = 1
|
||||
b = 1
|
||||
brightness = 1
|
||||
height = 1
|
||||
enabled = 0
|
||||
|
||||
radius = 1
|
||||
premul_r = 1
|
||||
premul_g = 1
|
||||
premul_b = 1
|
||||
|
||||
atom/attached_to = null
|
||||
attach_x = 0.5
|
||||
attach_y = 0.5
|
||||
|
||||
New(x=0, y=0, z=0)
|
||||
src.x = x
|
||||
src.y = y
|
||||
src.z = z
|
||||
var/turf/T = locate(x, y, z)
|
||||
if (T)
|
||||
if (!T.RL_Lights)
|
||||
T.RL_Lights = list()
|
||||
T.RL_Lights |= src
|
||||
|
||||
proc
|
||||
set_brightness(brightness)
|
||||
if (src.brightness == brightness)
|
||||
return
|
||||
|
||||
if (src.enabled)
|
||||
var/strip_gen = ++RL_Generation
|
||||
var/list/affected = src.strip(strip_gen)
|
||||
|
||||
src.brightness = brightness
|
||||
src.precalc()
|
||||
|
||||
for (var/turf/T in src.apply())
|
||||
T.RL_UpdateLight()
|
||||
for (var/turf/T in affected)
|
||||
if (T.RL_UpdateGeneration <= strip_gen)
|
||||
T.RL_UpdateLight()
|
||||
else
|
||||
src.brightness = brightness
|
||||
src.precalc()
|
||||
|
||||
set_color(r, g, b)
|
||||
if (src.r == r && src.g == g && src.b == b)
|
||||
return
|
||||
|
||||
if (src.enabled)
|
||||
var/strip_gen = ++RL_Generation
|
||||
var/list/affected = src.strip(strip_gen)
|
||||
|
||||
src.r = r
|
||||
src.g = g
|
||||
src.b = b
|
||||
src.precalc()
|
||||
|
||||
for (var/turf/T in src.apply())
|
||||
T.RL_UpdateLight()
|
||||
for (var/turf/T in affected)
|
||||
if (T.RL_UpdateGeneration <= strip_gen)
|
||||
T.RL_UpdateLight()
|
||||
else
|
||||
src.r = r
|
||||
src.g = g
|
||||
src.b = b
|
||||
src.precalc()
|
||||
|
||||
set_height(height)
|
||||
if (src.height == height)
|
||||
return
|
||||
|
||||
if (src.enabled)
|
||||
var/strip_gen = ++RL_Generation
|
||||
var/list/affected = src.strip(strip_gen)
|
||||
|
||||
src.height = height
|
||||
src.precalc()
|
||||
|
||||
for (var/turf/T in src.apply())
|
||||
T.RL_UpdateLight()
|
||||
for (var/turf/T in affected)
|
||||
if (T.RL_UpdateGeneration <= strip_gen)
|
||||
T.RL_UpdateLight()
|
||||
else
|
||||
src.height = height
|
||||
src.precalc()
|
||||
|
||||
enable()
|
||||
if (enabled)
|
||||
return
|
||||
enabled = 1
|
||||
for (var/turf/T in src.apply())
|
||||
T.RL_UpdateLight()
|
||||
|
||||
disable()
|
||||
if (!enabled)
|
||||
return
|
||||
enabled = 0
|
||||
for (var/turf/T in src.strip(++RL_Generation))
|
||||
T.RL_UpdateLight()
|
||||
|
||||
detach()
|
||||
if (src.attached_to)
|
||||
src.attached_to.RL_Attached -= src
|
||||
src.attached_to = null
|
||||
|
||||
attach(atom/A, offset_x=0.5, offset_y=0.5)
|
||||
if (src.attached_to)
|
||||
var/atom/old = src.attached_to
|
||||
old.RL_Attached -= src
|
||||
|
||||
src.move(A.x + offset_x, A.y + offset_x, A.z)
|
||||
src.attached_to = A
|
||||
src.attach_x = offset_x
|
||||
src.attach_y = offset_y
|
||||
if (!A.RL_Attached)
|
||||
A.RL_Attached = list(src)
|
||||
else
|
||||
A.RL_Attached += src
|
||||
|
||||
// internals
|
||||
precalc()
|
||||
src.premul_r = src.r * src.brightness
|
||||
src.premul_g = src.g * src.brightness
|
||||
src.premul_b = src.b * src.brightness
|
||||
src.radius = min(ceil(sqrt(max((brightness * RL_Atten_Quadratic) / -RL_Atten_Constant - src.height**2, 0)) + 1), RL_MaxRadius)
|
||||
|
||||
apply()
|
||||
if (!RL_Started)
|
||||
return list()
|
||||
|
||||
return apply_internal(++RL_Generation, src.premul_r, src.premul_g, src.premul_b)
|
||||
|
||||
strip(generation)
|
||||
if (!RL_Started)
|
||||
return list()
|
||||
|
||||
return apply_internal(generation, -src.premul_r, -src.premul_g, -src.premul_b)
|
||||
|
||||
move(x, y, z)
|
||||
var/turf/old_turf = locate(src.x, src.y, src.z)
|
||||
if (old_turf)
|
||||
if (old_turf.RL_Lights.len)
|
||||
old_turf.RL_Lights -= src
|
||||
if (!old_turf.RL_Lights.len)
|
||||
old_turf.RL_Lights = null
|
||||
else
|
||||
old_turf.RL_Lights = null
|
||||
|
||||
var/strip_gen = ++RL_Generation
|
||||
var/list/affected
|
||||
if (src.enabled)
|
||||
affected = src.strip(strip_gen)
|
||||
|
||||
src.x = x
|
||||
src.y = y
|
||||
src.z = z
|
||||
|
||||
var/turf/new_turf = locate(x, y, z)
|
||||
if (new_turf)
|
||||
if (!new_turf.RL_Lights)
|
||||
new_turf.RL_Lights = list()
|
||||
new_turf.RL_Lights |= src
|
||||
|
||||
if (src.enabled)
|
||||
for (var/turf/T in src.apply())
|
||||
T.RL_UpdateLight()
|
||||
for (var/turf/T in affected)
|
||||
if (T.RL_UpdateGeneration <= strip_gen)
|
||||
T.RL_UpdateLight()
|
||||
|
||||
move_defer(x, y, z)
|
||||
. = src.strip(++RL_Generation)
|
||||
src.x = x
|
||||
src.y = y
|
||||
src.z = z
|
||||
|
||||
. |= src.apply()
|
||||
|
||||
apply_to(turf/T)
|
||||
CRASH("Default apply_to called, did you mean to create a /datum/light/point and not a /datum/light?")
|
||||
return
|
||||
|
||||
apply_internal(generation, r, g, b) // per light type
|
||||
CRASH("Default apply_internal called, did you mean to create a /datum/light/point and not a /datum/light?")
|
||||
return
|
||||
|
||||
point
|
||||
apply_to(turf/T)
|
||||
T.RL_ApplyLight(src.x, src.y, src.brightness, src.height**2, r, g, b)
|
||||
|
||||
#define ADDUPDATE(var) if (var.RL_UpdateGeneration < generation) { var.RL_UpdateGeneration = generation; . += var; }
|
||||
apply_internal(generation, r, g, b)
|
||||
. = list()
|
||||
var/height2 = src.height**2
|
||||
var/turf/middle = locate(src.x, src.y, src.z)
|
||||
outer:
|
||||
for (var/turf/T in view(src.radius, middle))
|
||||
if (T.opacity)
|
||||
continue
|
||||
for (var/atom/A in T)
|
||||
if (A.opacity)
|
||||
continue outer
|
||||
|
||||
T.RL_ApplyLight(src.x, src.y, src.brightness, height2, r, g, b)
|
||||
T.RL_ApplyGeneration = generation
|
||||
T.RL_UpdateGeneration = generation
|
||||
. += T
|
||||
|
||||
for (var/turf/T in .)
|
||||
var/turf/E = get_step(T, EAST)
|
||||
var/turf/N = get_step(T, NORTH)
|
||||
var/turf/NE = get_step(T, NORTHEAST)
|
||||
var/turf/W = get_step(T, WEST)
|
||||
var/turf/S = get_step(T, SOUTH)
|
||||
var/turf/SW = get_step(T, SOUTHWEST)
|
||||
|
||||
if (E && E.RL_ApplyGeneration < generation)
|
||||
E.RL_ApplyGeneration = generation
|
||||
E.RL_ApplyLight(src.x, src.y, src.brightness, height2, r, g, b)
|
||||
ADDUPDATE(E)
|
||||
|
||||
var/turf/SE = get_step(T, SOUTHEAST)
|
||||
ADDUPDATE(SE)
|
||||
|
||||
if (N && N.RL_ApplyGeneration < generation)
|
||||
N.RL_ApplyGeneration = generation
|
||||
N.RL_ApplyLight(src.x, src.y, src.brightness, height2, r, g, b)
|
||||
ADDUPDATE(N)
|
||||
|
||||
var/turf/NW = get_step(T, NORTHWEST)
|
||||
ADDUPDATE(NW)
|
||||
|
||||
if (NE && NE.RL_ApplyGeneration < generation)
|
||||
NE.RL_ApplyLight(src.x, src.y, src.brightness, height2, r, g, b)
|
||||
NE.RL_ApplyGeneration = generation
|
||||
ADDUPDATE(NE)
|
||||
|
||||
ADDUPDATE(W)
|
||||
ADDUPDATE(S)
|
||||
ADDUPDATE(SW)
|
||||
|
||||
var
|
||||
RL_Started = 0
|
||||
|
||||
proc
|
||||
RL_Start()
|
||||
RL_Started = 1
|
||||
for (var/datum/light/light)
|
||||
if (light.enabled)
|
||||
light.apply()
|
||||
for (var/turf/T in world)
|
||||
T.RL_UpdateLight()
|
||||
|
||||
RL_Suspend()
|
||||
// TODO
|
||||
|
||||
RL_Resume()
|
||||
// TODO
|
||||
|
||||
turf
|
||||
var
|
||||
RL_ApplyGeneration = 0
|
||||
RL_UpdateGeneration = 0
|
||||
obj/overlay/tile_effect/RL_MulOverlay = null
|
||||
obj/overlay/tile_effect/RL_AddOverlay = null
|
||||
RL_LumR = 0
|
||||
RL_LumG = 0
|
||||
RL_LumB = 0
|
||||
RL_AddLumR = 0
|
||||
RL_AddLumG = 0
|
||||
RL_AddLumB = 0
|
||||
RL_NeedsAdditive = 0
|
||||
RL_OverlayState = ""
|
||||
list/datum/light/RL_Lights = null
|
||||
|
||||
RL_Ignore = 0
|
||||
|
||||
luminosity = 1 // TODO
|
||||
|
||||
New()
|
||||
..()
|
||||
var/area/A = src.loc
|
||||
if (!RL_Started)
|
||||
RL_LumR += A.RL_AmbientRed
|
||||
RL_LumG += A.RL_AmbientGreen
|
||||
RL_LumB += A.RL_AmbientBlue
|
||||
|
||||
disposing()
|
||||
..()
|
||||
RL_Cleanup()
|
||||
|
||||
var/old_lights = src.RL_Lights
|
||||
var/old_opacity = src.opacity
|
||||
spawn(0) // ugghhh fuuck
|
||||
var/area/A = src.loc
|
||||
RL_LumR = A.RL_AmbientRed
|
||||
RL_LumG = A.RL_AmbientGreen
|
||||
RL_LumB = A.RL_AmbientBlue
|
||||
if (old_lights)
|
||||
if (!RL_Lights)
|
||||
RL_Lights = old_lights
|
||||
else
|
||||
RL_Lights |= old_lights
|
||||
var/new_opacity = src.opacity
|
||||
src.opacity = old_opacity
|
||||
RL_SetOpacity(new_opacity)
|
||||
|
||||
for (var/turf/T in view(RL_MaxRadius, src))
|
||||
for (var/datum/light/light in T.RL_Lights)
|
||||
if (light.enabled)
|
||||
light.apply_to(src)
|
||||
RL_UpdateLight()
|
||||
|
||||
proc
|
||||
RL_ApplyLight(lx, ly, brightness, height2, r, g, b)
|
||||
var/area/A = loc
|
||||
if (RL_Ignore || !A.RL_Lighting)
|
||||
return
|
||||
|
||||
var/atten = (brightness*RL_Atten_Quadratic) / ((src.x - lx)**2 + (src.y - ly)**2 + height2) + RL_Atten_Constant
|
||||
if (atten < 0)
|
||||
return
|
||||
RL_LumR += r*atten
|
||||
RL_LumG += g*atten
|
||||
RL_LumB += b*atten
|
||||
RL_AddLumR = min(max((RL_LumR - 1) * 0.5, 0), 0.3)
|
||||
RL_AddLumG = min(max((RL_LumG - 1) * 0.5, 0), 0.3)
|
||||
RL_AddLumB = min(max((RL_LumB - 1) * 0.5, 0), 0.3)
|
||||
RL_NeedsAdditive = (RL_AddLumR > 0) || (RL_AddLumG > 0) || (RL_AddLumB > 0)
|
||||
|
||||
RL_UpdateLight()
|
||||
if (!RL_Started)
|
||||
return
|
||||
|
||||
var/area/A = loc
|
||||
if (RL_Ignore || !A.RL_Lighting)
|
||||
if (src.RL_MulOverlay)
|
||||
pool(src.RL_MulOverlay)
|
||||
src.RL_MulOverlay.set_loc(null)
|
||||
src.RL_MulOverlay = null
|
||||
if (src.RL_AddOverlay)
|
||||
pool(src.RL_AddOverlay)
|
||||
src.RL_AddOverlay.set_loc(null)
|
||||
src.RL_AddOverlay = null
|
||||
return
|
||||
|
||||
var/turf/E = get_step(src, EAST) || src
|
||||
var/turf/N = get_step(src, NORTH) || src
|
||||
var/turf/NE = get_step(src, NORTHEAST) || src
|
||||
|
||||
if (!src.RL_MulOverlay)
|
||||
var/obj/overlay/tile_effect/overlay = unpool(/obj/overlay/tile_effect)
|
||||
overlay.set_loc(src)
|
||||
overlay.blend_mode = BLEND_MULTIPLY
|
||||
overlay.icon = 'icons/effects/light_overlay.dmi'
|
||||
overlay.icon_state = src.RL_OverlayState
|
||||
src.RL_MulOverlay = overlay
|
||||
src.RL_MulOverlay.color = list(
|
||||
src.RL_LumR, src.RL_LumG, src.RL_LumB, 0,
|
||||
E.RL_LumR, E.RL_LumG, E.RL_LumB, 0,
|
||||
N.RL_LumR, N.RL_LumG, N.RL_LumB, 0,
|
||||
NE.RL_LumR, NE.RL_LumG, NE.RL_LumB, 0,
|
||||
0, 0, 0, 1)
|
||||
|
||||
if (src.RL_NeedsAdditive || E.RL_NeedsAdditive || N.RL_NeedsAdditive || NE.RL_NeedsAdditive)
|
||||
if (!src.RL_AddOverlay)
|
||||
var/obj/overlay/tile_effect/overlay = unpool(/obj/overlay/tile_effect)
|
||||
overlay.set_loc(src)
|
||||
overlay.blend_mode = BLEND_ADD
|
||||
overlay.icon = 'icons/effects/light_overlay.dmi'
|
||||
overlay.icon_state = src.RL_OverlayState
|
||||
src.RL_AddOverlay = overlay
|
||||
src.RL_AddOverlay.color = list(
|
||||
src.RL_AddLumR, src.RL_AddLumG, src.RL_AddLumB, 0,
|
||||
E.RL_AddLumR, E.RL_AddLumG, E.RL_AddLumB, 0,
|
||||
N.RL_AddLumR, N.RL_AddLumG, N.RL_AddLumB, 0,
|
||||
NE.RL_AddLumR, NE.RL_AddLumG, NE.RL_AddLumB, 0,
|
||||
0, 0, 0, 1)
|
||||
else if (src.RL_AddOverlay)
|
||||
src.RL_AddOverlay.set_loc(null)
|
||||
pool(src.RL_AddOverlay)
|
||||
src.RL_AddOverlay = null
|
||||
|
||||
RL_SetSprite(state)
|
||||
if (src.RL_MulOverlay)
|
||||
src.RL_MulOverlay.icon_state = state
|
||||
if (src.RL_AddOverlay)
|
||||
src.RL_AddOverlay.icon_state = state
|
||||
src.RL_OverlayState = state
|
||||
|
||||
// Approximate RGB -> Luma conversion formula.
|
||||
RL_GetBrightness()
|
||||
var/BN = max(0, ((src.RL_LumR * 0.33) + (src.RL_LumG * 0.5) + (src.RL_LumB * 0.16)))
|
||||
return BN
|
||||
|
||||
RL_Cleanup()
|
||||
if (src.RL_MulOverlay)
|
||||
src.RL_MulOverlay.set_loc(null)
|
||||
pool(src.RL_MulOverlay)
|
||||
src.RL_MulOverlay = null
|
||||
if (src.RL_AddOverlay)
|
||||
src.RL_AddOverlay.set_loc(null)
|
||||
pool(src.RL_AddOverlay)
|
||||
src.RL_AddOverlay = null
|
||||
|
||||
RL_Reset()
|
||||
// TODO
|
||||
|
||||
area
|
||||
var
|
||||
RL_Lighting = 1
|
||||
RL_AmbientRed = 0.1
|
||||
RL_AmbientGreen = 0.1
|
||||
RL_AmbientBlue = 0.1
|
||||
|
||||
atom
|
||||
var
|
||||
RL_Attached = null
|
||||
|
||||
movable
|
||||
Move(atom/target)
|
||||
var/old_loc = src.loc
|
||||
. = ..()
|
||||
if (src.loc != old_loc && src.RL_Attached)
|
||||
for (var/datum/light/light in src.RL_Attached)
|
||||
light.move(src.x + light.attach_x, src.y + light.attach_y, src.z)
|
||||
|
||||
set_loc(atom/target)
|
||||
if (opacity)
|
||||
var/list/datum/light/lights = list()
|
||||
for (var/turf/T in view(RL_MaxRadius, src))
|
||||
if (T.RL_Lights)
|
||||
lights |= T.RL_Lights
|
||||
|
||||
var/list/affected = list()
|
||||
for (var/datum/light/light in lights)
|
||||
if (light.enabled)
|
||||
affected |= light.strip(++RL_Generation)
|
||||
|
||||
. = ..()
|
||||
|
||||
for (var/datum/light/light in lights)
|
||||
if (light.enabled)
|
||||
affected |= light.apply()
|
||||
for (var/turf/T in affected)
|
||||
T.RL_UpdateLight()
|
||||
else
|
||||
. = ..()
|
||||
|
||||
if (src.RL_Attached) // TODO: defer updates and update all affected tiles at once?
|
||||
for (var/datum/light/light in src.RL_Attached)
|
||||
light.move(src.x+0.5, src.y+0.5, src.z)
|
||||
|
||||
disposing()
|
||||
..()
|
||||
if (src.RL_Attached)
|
||||
for (var/datum/light/attached in src.RL_Attached)
|
||||
attached.disable()
|
||||
if (opacity)
|
||||
RL_SetOpacity(0)
|
||||
|
||||
proc
|
||||
RL_SetOpacity(new_opacity)
|
||||
if (src.opacity == new_opacity)
|
||||
return
|
||||
|
||||
var/list/datum/light/lights = list()
|
||||
for (var/turf/T in view(RL_MaxRadius, src))
|
||||
if (T.RL_Lights)
|
||||
lights |= T.RL_Lights
|
||||
|
||||
var/list/affected = list()
|
||||
for (var/datum/light/light in lights)
|
||||
if (light.enabled)
|
||||
affected |= light.strip(++RL_Generation)
|
||||
src.opacity = new_opacity
|
||||
for (var/datum/light/light in lights)
|
||||
if (light.enabled)
|
||||
affected |= light.apply()
|
||||
for (var/turf/T in affected)
|
||||
T.RL_UpdateLight()
|
||||
@@ -0,0 +1,399 @@
|
||||
#define ITEM_ABILITIES_WRAP_AT 15
|
||||
|
||||
//There is no stunned etc. check when clicking the buttons.
|
||||
//If you want one, code it. (the_mob var on the buttons).
|
||||
|
||||
//oh my god what the fuck is going on in this file jesus wow
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/obj/item/extinguisher/abilities = list(/obj/ability_button/extinguisher_ab)
|
||||
|
||||
/obj/ability_button/extinguisher_ab
|
||||
name = "Extinguish"
|
||||
icon_state = "extab"
|
||||
|
||||
execute_ability()
|
||||
var/obj/item/extinguisher/E = the_item
|
||||
if(!E.reagents || !E.reagents.total_volume || E.special) return
|
||||
|
||||
if (E.reagents.has_reagent("vomit") || E.reagents.has_reagent("blackpowder") || E.reagents.has_reagent("blood") || E.reagents.has_reagent("gvomit") || E.reagents.has_reagent("carbon") || E.reagents.has_reagent("cryostylane") || E.reagents.has_reagent("chickensoup") || E.reagents.has_reagent("salt"))
|
||||
boutput(the_mob, "<span style=\"color:red\">The nozzle is clogged!</span>")
|
||||
return
|
||||
|
||||
if (E.reagents.has_reagent("acid") || E.reagents.has_reagent("pacid") || E.reagents.has_reagent("napalm"))
|
||||
for(var/mob/O in AIviewers(the_mob, null)) O.show_message(text("<span style=\"color:red\">[] melts!</span>", E), 1)
|
||||
new/obj/decal/cleanable/molten_item(get_turf(the_mob))
|
||||
qdel(E)
|
||||
return
|
||||
|
||||
for(var/mob/M in view(the_mob))
|
||||
boutput(M, "<span style=\"color:red\">[the_mob] prepares to spray the contents of the extinguisher all around \himself!</span>")
|
||||
|
||||
E.special = 1
|
||||
the_mob.transforming = 1
|
||||
spawn(30) if (the_mob) the_mob.transforming = 0
|
||||
sleep(30)
|
||||
|
||||
var/theturf
|
||||
var/list/spraybits = new/list()
|
||||
var/direction = NORTH
|
||||
if (the_mob)
|
||||
theturf = get_turf(the_mob)
|
||||
else
|
||||
theturf = get_turf(E)
|
||||
|
||||
for(var/i=0, i<8, i++)
|
||||
var/obj/effects/spray/S = new/obj/effects/spray(theturf)
|
||||
spawn(150) qdel(S)
|
||||
S.dir = direction
|
||||
S.original_dir = direction
|
||||
direction = turn(direction,45)
|
||||
S.create_reagents(1000)
|
||||
E.reagents.copy_to(S.reagents)
|
||||
//var/icon/IC = icon(S.icon,S.icon_state)
|
||||
//IC.Blend(S.reagents.get_master_color(),ICON_MULTIPLY)
|
||||
//S.icon = IC
|
||||
spraybits += S
|
||||
spawn(0)
|
||||
S.reagents.reaction(theturf, TOUCH)
|
||||
for(var/atom/A in theturf)
|
||||
S.reagents.reaction(A, TOUCH)
|
||||
|
||||
if (the_mob) playsound(the_mob, 'sound/effects/spray.ogg', 75, 1, 0)
|
||||
E.reagents.clear_reagents()
|
||||
|
||||
sleep(5)
|
||||
E.special = 0
|
||||
|
||||
spawn(0)
|
||||
for(var/i=0, i<3, i++)
|
||||
for(var/obj/effects/spray/SP in spraybits)
|
||||
SP.set_loc(get_step(SP.loc, SP.original_dir))
|
||||
SP.reagents.reaction(SP.loc, TOUCH)
|
||||
for(var/atom/A in SP.loc)
|
||||
SP.reagents.reaction(A, TOUCH)
|
||||
if(is_blocked_turf(SP.loc))
|
||||
spraybits -= SP
|
||||
qdel(SP)
|
||||
sleep(5)
|
||||
|
||||
OnDrop()
|
||||
if (the_mob) the_mob.transforming = 0
|
||||
////////////////////////////////////////////////////////////
|
||||
/obj/item/clothing/head/helmet/welding/abilities = list(/obj/ability_button/mask_toggle)
|
||||
|
||||
|
||||
/obj/ability_button/mask_toggle
|
||||
name = "Toggle Welding Mask"
|
||||
icon_state = "weldup"
|
||||
|
||||
execute_ability()
|
||||
var/obj/item/clothing/head/helmet/welding/W = the_item
|
||||
if(W.up)
|
||||
W.up = !W.up
|
||||
W.see_face = !W.see_face
|
||||
W.icon_state = "welding"
|
||||
boutput(the_mob, "You flip the mask down.")
|
||||
the_mob.set_clothing_icon_dirty()
|
||||
icon_state = "weldup"
|
||||
else
|
||||
W.up = !W.up
|
||||
W.see_face = !W.see_face
|
||||
W.icon_state = "welding-up"
|
||||
boutput(the_mob, "You flip the mask up.")
|
||||
the_mob.set_clothing_icon_dirty()
|
||||
icon_state = "welddown"
|
||||
|
||||
/obj/item/tank/air/abilities = list(/obj/ability_button/tank_valve_toggle)
|
||||
/obj/item/tank/oxygen/abilities = list(/obj/ability_button/tank_valve_toggle)
|
||||
/obj/item/tank/emergency_oxygen/abilities = list(/obj/ability_button/tank_valve_toggle)
|
||||
|
||||
/obj/ability_button/tank_valve_toggle
|
||||
name = "Toggle Tank Valve"
|
||||
icon_state = "airoff"
|
||||
|
||||
OnDrop() // since tanks close when dropped this should always start off
|
||||
icon_state = "airoff"
|
||||
..()
|
||||
|
||||
execute_ability()
|
||||
var/obj/item/tank/T = the_item
|
||||
if (!T) return
|
||||
T.toggle_valve() // the tank valve toggle handles the icon updates since its also used by tank/Topic
|
||||
|
||||
/obj/item/clothing/shoes/rocket/abilities = list(/obj/ability_button/shoerocket)
|
||||
|
||||
/obj/ability_button/shoerocket
|
||||
name = "Activate Shoes"
|
||||
icon_state = "rocketshoes"
|
||||
var/explosion_chance = 3
|
||||
|
||||
Click()
|
||||
if(!the_item || !the_mob || !the_mob.canmove) return
|
||||
var/obj/item/clothing/shoes/rocket/R = the_item
|
||||
|
||||
if(the_mob:shoes != the_item)
|
||||
boutput(the_mob, "<span style=\"color:red\">You must be wearing the shoes to use them.</span>")
|
||||
return
|
||||
|
||||
R.uses--
|
||||
|
||||
if(R.uses < 0)
|
||||
the_item.name = "Empty Rocket Shoes"
|
||||
boutput(the_mob, "<span style=\"color:red\">Your Rocket Shoes are empty.</span>")
|
||||
R.abilities.Cut()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
playsound(get_turf(the_mob), 'sound/effects/bamf.ogg', 100, 1)
|
||||
|
||||
if(prob(explosion_chance))
|
||||
boutput(the_mob, "<span style=\"color:red\">The Rocket Shoes blow up</span>")
|
||||
explosion(src, get_turf(the_mob), -1, -1, 1, 1)
|
||||
qdel(the_item)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
spawn(0)
|
||||
var/turf/curr = get_turf(the_mob)
|
||||
|
||||
for(var/i=0, i<15, i++)
|
||||
curr = get_step(curr, the_mob.dir)
|
||||
|
||||
the_mob.throw_unlimited = 1
|
||||
|
||||
spawn(0)
|
||||
for(var/i=0, i<15, i++)
|
||||
var/obj/O = new/obj(get_turf(the_mob))
|
||||
O.density = 0
|
||||
O.name = "Smoke"
|
||||
O.anchored = 0
|
||||
O.opacity = 0
|
||||
O.icon = 'icons/effects/effects.dmi'
|
||||
O.icon_state = "smoke"
|
||||
O.dir = pick(alldirs)
|
||||
spawn(10) qdel(O)
|
||||
sleep(1)
|
||||
|
||||
the_mob.throw_at(curr, 16, 3)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/obj/item/device/flashlight/abilities = list(/obj/ability_button/flashlight_toggle)
|
||||
|
||||
/obj/ability_button/flashlight_toggle
|
||||
name = "Toggle Flashlight"
|
||||
icon_state = "on"
|
||||
|
||||
execute_ability()
|
||||
var/obj/item/device/flashlight/J = the_item
|
||||
J.attack_self(the_mob)
|
||||
if(J.on) icon_state = "off"
|
||||
else icon_state = "on"
|
||||
////////////////////////////////////////////////////////////
|
||||
/obj/item/clothing/head/helmet/space/engineer/abilities = list(/obj/ability_button/flashlight_engiehelm)
|
||||
|
||||
/obj/ability_button/flashlight_engiehelm
|
||||
name = "Toggle Flashlight"
|
||||
icon_state = "on"
|
||||
|
||||
execute_ability()
|
||||
var/obj/item/clothing/head/helmet/space/engineer/J = the_item
|
||||
J.flashlight_toggle(the_mob)
|
||||
if (J.on) src.icon_state = "off"
|
||||
else src.icon_state = "on"
|
||||
////////////////////////////////////////////////////////////
|
||||
/obj/item/clothing/head/helmet/hardhat/abilities = list(/obj/ability_button/flashlight_hardhat)
|
||||
/obj/ability_button/flashlight_hardhat
|
||||
name = "Toggle Flashlight"
|
||||
icon_state = "on"
|
||||
|
||||
execute_ability()
|
||||
var/obj/item/clothing/head/helmet/hardhat/J = the_item
|
||||
J.flashlight_toggle(the_mob)
|
||||
if (J.on) src.icon_state = "off"
|
||||
else src.icon_state = "on"
|
||||
////////////////////////////////////////////////////////////
|
||||
/obj/item/device/t_scanner/abilities = list(/obj/ability_button/tscanner_toggle)
|
||||
|
||||
/obj/ability_button/tscanner_toggle
|
||||
name = "Toggle T-Scanner"
|
||||
icon_state = "on"
|
||||
|
||||
execute_ability()
|
||||
var/obj/item/device/t_scanner/J = the_item
|
||||
J.attack_self(the_mob)
|
||||
if(J.on) icon_state = "off"
|
||||
else icon_state = "on"
|
||||
////////////////////////////////////////////////////////////
|
||||
/obj/item/tank/jetpack/abilities = list(/obj/ability_button/jetpack_toggle, /obj/ability_button/tank_valve_toggle)
|
||||
|
||||
/obj/ability_button/jetpack_toggle
|
||||
name = "Toggle jetpack"
|
||||
icon_state = "jeton"
|
||||
|
||||
execute_ability()
|
||||
var/obj/item/tank/jetpack/J = the_item
|
||||
J.toggle()
|
||||
if(J.on) icon_state = "jetoff"
|
||||
else icon_state = "jeton"
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/mob/var/list/item_abilities = new/list()
|
||||
/mob/var/need_update_item_abilities = 0
|
||||
|
||||
/mob/proc/update_item_abilities()
|
||||
if(!src.client || !need_update_item_abilities) return
|
||||
|
||||
need_update_item_abilities = 0
|
||||
//src.client.screen -= src.item_abilities
|
||||
for(var/obj/ability_button/B in src.client.screen)
|
||||
src.client.screen -= B
|
||||
|
||||
if(src.stat) return
|
||||
|
||||
if (istype(src,/mob/living/carbon/human/))
|
||||
var/mob/living/carbon/human/H = src
|
||||
H.hud.update_ability_hotbar()
|
||||
|
||||
// shifted all the stuff down there over to the hud file human.dm
|
||||
|
||||
//var/pos_x = 1
|
||||
//var/pos_y = 0
|
||||
|
||||
//for(var/obj/ability_button/B2 in src.item_abilities)
|
||||
// B2.screen_loc = "NORTH-[pos_y],[pos_x]"
|
||||
// src.client.screen += B2
|
||||
// pos_x++
|
||||
// if(pos_x > ITEM_ABILITIES_WRAP_AT)
|
||||
// pos_x = 1
|
||||
// pos_y++
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////// Base vars & procs /////////////////////////////////
|
||||
|
||||
//If you want an item to have abilities, you need to make sure
|
||||
//you add the stuff in the new proc here to its new proc, should it have one.
|
||||
//You also need to add the pickup / dropped stuff if the item has custom ones.
|
||||
//In some cases you might be able to use ..() instead.
|
||||
|
||||
/obj/item/
|
||||
|
||||
var/list/abilities = list("")
|
||||
var/list/ability_buttons = new/list()
|
||||
|
||||
var/mob/the_mob = null
|
||||
|
||||
New()
|
||||
for(var/A in abilities)
|
||||
if(!ispath(A,/obj/ability_button))
|
||||
abilities -= A
|
||||
continue
|
||||
var/obj/ability_button/NB = new A(src)
|
||||
ability_buttons += NB
|
||||
|
||||
for(var/obj/ability_button/B in ability_buttons) B.the_item = src
|
||||
// if(ability_buttons.len > 0)
|
||||
// spawn(0) check_abilities()
|
||||
..()
|
||||
|
||||
proc/clear_mob()
|
||||
for(var/obj/ability_button/B in ability_buttons)
|
||||
B.the_mob = null
|
||||
the_mob = null
|
||||
|
||||
proc/set_mob(var/mob/M)
|
||||
if(!M) return
|
||||
for(var/obj/ability_button/B in ability_buttons)
|
||||
B.the_mob = M
|
||||
the_mob = M
|
||||
|
||||
proc/show_buttons()
|
||||
if(!the_mob || !ability_buttons.len) return
|
||||
if(!the_mob.item_abilities.Find(ability_buttons[1]))
|
||||
the_mob.item_abilities.Add(ability_buttons)
|
||||
the_mob.need_update_item_abilities = 1
|
||||
the_mob.update_item_abilities()
|
||||
|
||||
proc/hide_buttons()
|
||||
if(!the_mob) return
|
||||
the_mob.item_abilities.Remove(ability_buttons)
|
||||
the_mob.need_update_item_abilities = 1
|
||||
the_mob.update_item_abilities()
|
||||
/*
|
||||
proc/check_abilities()
|
||||
if (!(src in heh))
|
||||
heh += src
|
||||
boutput(world, "heh len = [heh.len]")
|
||||
if(!the_mob)
|
||||
spawn(30) check_abilities()
|
||||
return
|
||||
|
||||
if(!(src in the_mob.get_equipped_items()))
|
||||
hide_buttons()
|
||||
else
|
||||
if(istype(src,/obj/item/clothing/suit/wizrobe))
|
||||
clear_buttons()
|
||||
show_buttons()
|
||||
|
||||
spawn(10) check_abilities()
|
||||
*/
|
||||
proc/dropped(mob/user as mob)
|
||||
if(src.material) src.material.triggerDrop(user)
|
||||
for(var/obj/ability_button/B in ability_buttons)
|
||||
B.OnDrop()
|
||||
hide_buttons()
|
||||
clear_mob()
|
||||
return
|
||||
|
||||
proc/pickup(mob/user)
|
||||
if(src.material) src.material.triggerPickup(user)
|
||||
set_mob(user)
|
||||
show_buttons()
|
||||
return
|
||||
|
||||
proc/clear_buttons()
|
||||
if(!the_mob) return
|
||||
the_mob.item_abilities = list()
|
||||
|
||||
/obj/ability_button
|
||||
name = "baseButton"
|
||||
desc = ""
|
||||
icon = 'icons/misc/abilities.dmi'
|
||||
icon_state = "test"
|
||||
layer = HUD_LAYER
|
||||
|
||||
var/obj/item/the_item = null
|
||||
var/mob/the_mob = null
|
||||
|
||||
Click()
|
||||
if(ability_allowed())
|
||||
execute_ability()
|
||||
|
||||
attackby()
|
||||
return
|
||||
|
||||
attack_hand()
|
||||
return
|
||||
|
||||
//WIRE TOOLTIPS
|
||||
MouseEntered(location, control, params)
|
||||
usr.client.tooltip.show(src, params, title = src.name, content = (src.desc ? src.desc : null))
|
||||
|
||||
MouseExited()
|
||||
usr.client.tooltip.hide()
|
||||
|
||||
proc/ability_allowed()
|
||||
if (!the_item)
|
||||
return 0
|
||||
if (!the_mob || !the_mob.canmove)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
proc/execute_ability()
|
||||
return
|
||||
|
||||
proc/OnDrop()
|
||||
return
|
||||
@@ -0,0 +1,391 @@
|
||||
//Collection of animations we can reuse for stuff.
|
||||
//Try to isolate animations you create an put them in here.
|
||||
|
||||
/proc/animate_fade_grayscale(var/atom/A, var/time=5)
|
||||
if (!istype(A) && !istype(A, /client))
|
||||
return
|
||||
A.color = list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1)
|
||||
animate(A, color=list(0.33, 0.33, 0.33, 0, 0.33, 0.33, 0.33, 0, 0.33, 0.33, 0.33, 0, 0, 0, 0, 1), time=time, easing=SINE_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_melt_pixel(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
//A.alpha = 200
|
||||
animate(A, pixel_y = 0, time = 50 - A.pixel_y, alpha = 175, easing = BOUNCE_EASING)
|
||||
animate(alpha = 0, easing = LINEAR_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_explode_pixel(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/floatdegrees = rand(5, 20)
|
||||
var/side = 1
|
||||
side = pick(-1, 1)
|
||||
animate(A, pixel_x = rand(-64, 64), pixel_y = rand(-64, 64), transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = 10, alpha = 0, easing = SINE_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_float(var/atom/A, var/loopnum = -1, floatspeed = 20, random_side = 1)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/floatdegrees = rand(5, 20)
|
||||
var/side = 1
|
||||
if(random_side) side = pick(-1, 1)
|
||||
|
||||
spawn(rand(1,10))
|
||||
animate(A, pixel_y = 32, transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING)
|
||||
animate(pixel_y = 0, transform = matrix(floatdegrees * (side == 1 ? -1:1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_levitate(var/atom/A, var/loopnum = -1, floatspeed = 20, random_side = 1)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/floatdegrees = rand(5, 20)
|
||||
var/side = 1
|
||||
if(random_side) side = pick(-1, 1)
|
||||
|
||||
spawn(rand(1,10))
|
||||
animate(A, pixel_y = 8, transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING)
|
||||
animate(pixel_y = 0, transform = null, time = floatspeed, loop = loopnum, easing = SINE_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_revenant_shockwave(var/atom/A, var/loopnum = -1, floatspeed = 20, random_side = 1)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/floatdegrees = rand(5, 20)
|
||||
var/side = 1
|
||||
if(random_side) side = pick(-1, 1)
|
||||
|
||||
spawn(rand(1,10))
|
||||
animate(A, pixel_y = 8, transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING)
|
||||
animate(pixel_y = 0, transform = matrix(floatdegrees * (side == 1 ? -1:1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_glitchy_freakout(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/matrix/M = matrix()
|
||||
var/looper = rand(3,5)
|
||||
while(looper > 0)
|
||||
looper--
|
||||
M.Scale(rand(1,4),rand(1,4))
|
||||
animate(A, transform = M, pixel_x = A.pixel_x + rand(-12,12), pixel_z = A.pixel_z + rand(-12,12), time = 3, loop = 1, easing = LINEAR_EASING)
|
||||
animate(transform = matrix(rand(-360,360), MATRIX_ROTATE), time = 3, loop = 1, easing = LINEAR_EASING)
|
||||
M.Scale(1,1)
|
||||
animate(transform = M, pixel_x = 0, pixel_z = 0, time = 1, loop = 1, easing = LINEAR_EASING)
|
||||
animate(transform = null, time = 1, loop = 1, easing = LINEAR_EASING)
|
||||
|
||||
/proc/animate_fading_leap_up(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/matrix/M = matrix()
|
||||
var/do_loops = 15
|
||||
while (do_loops > 0)
|
||||
do_loops--
|
||||
animate(A, transform = M, pixel_z = A.pixel_z + 12, alpha = A.alpha - 17, time = 1, loop = 1, easing = LINEAR_EASING)
|
||||
M.Scale(1.2,1.2)
|
||||
sleep(1)
|
||||
A.alpha = 0
|
||||
|
||||
/proc/animate_fading_leap_down(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/matrix/M = matrix()
|
||||
var/do_loops = 15
|
||||
M.Scale(18,18)
|
||||
while (do_loops > 0)
|
||||
do_loops--
|
||||
animate(A, transform = M, pixel_z = A.pixel_z - 12, alpha = A.alpha + 17, time = 1, loop = 1, easing = LINEAR_EASING)
|
||||
M.Scale(0.8,0.8)
|
||||
sleep(1)
|
||||
animate(A, transform = M, pixel_z = 0, alpha = 255, time = 1, loop = 1, easing = LINEAR_EASING)
|
||||
|
||||
/proc/animate_shake(var/atom/A,var/amount = 5,var/x_severity = 2,var/y_severity = 2)
|
||||
// Wiggles the sprite around on its tile then returns it to normal
|
||||
if (!istype(A))
|
||||
return
|
||||
if (!isnum(amount) || !isnum(x_severity) || !isnum(y_severity))
|
||||
return
|
||||
amount = max(1,min(amount,50))
|
||||
x_severity = max(-32,min(x_severity,32))
|
||||
y_severity = max(-32,min(y_severity,32))
|
||||
|
||||
var/x_severity_inverse = 0 - x_severity
|
||||
var/y_severity_inverse = 0 - y_severity
|
||||
|
||||
animate(A, transform = null, pixel_y = rand(y_severity_inverse,y_severity), pixel_x = rand(x_severity_inverse,x_severity),time = 1,loop = amount, easing = ELASTIC_EASING)
|
||||
spawn(amount)
|
||||
animate(A, transform = null, pixel_y = 0, pixel_x = 0,time = 1,loop = 1, easing = LINEAR_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_teleport(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/matrix/M = matrix(1, 3, MATRIX_SCALE)
|
||||
animate(A, transform = M, pixel_y = 32, time = 10, alpha = 50, easing = CIRCULAR_EASING)
|
||||
M.Scale(0,4)
|
||||
animate(transform = M, time = 5, color = "#1111ff", alpha = 0, easing = CIRCULAR_EASING)
|
||||
animate(transform = null, time = 5, color = "#ffffff", alpha = 255, pixel_y = 0, easing = ELASTIC_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_teleport_wiz(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/matrix/M = matrix(0, 4, MATRIX_SCALE)
|
||||
animate(A, color = "#ddddff", time = 20, alpha = 70, easing = LINEAR_EASING)
|
||||
animate(transform = M, pixel_y = 32, time = 20, color = "#2222ff", alpha = 0, easing = CIRCULAR_EASING)
|
||||
animate(time = 8, transform = M, alpha = 5) //Do nothing, essentially
|
||||
animate(transform = null, time = 5, color = "#ffffff", alpha = 255, pixel_y = 0, easing = ELASTIC_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_rainbow_glow_old(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
animate(A, color = "#FF0000", time = rand(5,10), loop = -1, easing = LINEAR_EASING)
|
||||
animate(color = "#00FF00", time = rand(5,10), loop = -1, easing = LINEAR_EASING)
|
||||
animate(color = "#0000FF", time = rand(5,10), loop = -1, easing = LINEAR_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_rainbow_glow(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
animate(A, color = "#FF0000", time = rand(5,10), loop = -1, easing = LINEAR_EASING)
|
||||
animate(color = "#FFFF00", time = rand(5,10), loop = -1, easing = LINEAR_EASING)
|
||||
animate(color = "#00FF00", time = rand(5,10), loop = -1, easing = LINEAR_EASING)
|
||||
animate(color = "#00FFFF", time = rand(5,10), loop = -1, easing = LINEAR_EASING)
|
||||
animate(color = "#0000FF", time = rand(5,10), loop = -1, easing = LINEAR_EASING)
|
||||
animate(color = "#FF00FF", time = rand(5,10), loop = -1, easing = LINEAR_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_fade_to_color_fill(var/atom/A,var/the_color,var/time)
|
||||
if (!istype(A) || !the_color || !time)
|
||||
return
|
||||
animate(A, color = the_color, time = time, easing = LINEAR_EASING)
|
||||
|
||||
/proc/animate_flash_color_fill(var/atom/A,var/the_color,var/loops,var/time)
|
||||
if (!istype(A) || !the_color || !time || !loops)
|
||||
return
|
||||
animate(A, color = the_color, time = time, easing = LINEAR_EASING)
|
||||
animate(color = "#FFFFFF", time = 5, loop = loops, easing = LINEAR_EASING)
|
||||
|
||||
/proc/animate_flash_color_fill_inherit(var/atom/A,var/the_color,var/loops,var/time)
|
||||
if (!istype(A) || !the_color || !time || !loops)
|
||||
return
|
||||
var/color_old = A.color
|
||||
animate(A, color = the_color, time = time, loop = loops, easing = LINEAR_EASING)
|
||||
animate(A, color = color_old, time = time, loop = loops, easing = LINEAR_EASING)
|
||||
|
||||
/proc/animate_clownspell(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
animate(A, transform = matrix(1.3, MATRIX_SCALE), time = 5, color = "#00ff00", easing = BACK_EASING)
|
||||
animate(transform = null, time = 5, color = "#ffffff", easing = ELASTIC_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_wiggle_then_reset(var/atom/A, var/loops = 5, var/speed = 5, var/x_var = 3, var/y_var = 3)
|
||||
if (!istype(A) || !loops || !speed)
|
||||
return
|
||||
animate(A, pixel_x = rand(-x_var, x_var), pixel_y = rand(-y_var, y_var), time = speed * 2,loop = loops, easing = rand(2,7))
|
||||
animate(pixel_x = 0, pixel_y = 0, time = speed, easing = rand(2,7))
|
||||
|
||||
/proc/animate_blink(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/matrix/Orig = A.transform
|
||||
A.Scale(0.2,0.2)
|
||||
A.alpha = 50
|
||||
animate(A,transform = Orig, time = 3, alpha = 255, easing = CIRCULAR_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_bullspellground(var/atom/A, var/spell_color = "#cccccc")
|
||||
if (!istype(A))
|
||||
return
|
||||
animate(A, time = 5, color = spell_color)
|
||||
animate(time = 5, color = "#ffffff")
|
||||
return
|
||||
|
||||
/proc/animate_spin(var/atom/A, var/dir = "L", var/T = 1, var/looping = -1)
|
||||
if (!istype(A))
|
||||
return
|
||||
|
||||
var/matrix/M = A.transform
|
||||
var/turn = -90
|
||||
if (dir == "R")
|
||||
turn = 90
|
||||
|
||||
animate(A, transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping)
|
||||
animate(transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping)
|
||||
animate(transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping)
|
||||
animate(transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping)
|
||||
return
|
||||
|
||||
/proc/animate_bumble(var/atom/A, var/loopnum = -1, floatspeed = 10, Y1 = 3, Y2 = -3, var/slightly_random = 1)
|
||||
if (!istype(A))
|
||||
return
|
||||
|
||||
if (slightly_random)
|
||||
floatspeed = floatspeed * rand_deci(1, 0, 1, 4)
|
||||
animate(A, pixel_y = Y1, time = floatspeed, loop = loopnum, easing = LINEAR_EASING)
|
||||
animate(pixel_y = Y2, time = floatspeed, loop = loopnum, easing = LINEAR_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_beespin(var/atom/A, var/dir = "L", var/T = 1.5, var/looping = 1)
|
||||
if (!istype(A))
|
||||
return
|
||||
|
||||
var/matrix/turned
|
||||
|
||||
if (dir == "R")
|
||||
A.dir = WEST
|
||||
turned = matrix(A.transform, 90, MATRIX_ROTATE)
|
||||
|
||||
if (dir == "L")
|
||||
A.dir = EAST
|
||||
turned = matrix(A.transform, -90, MATRIX_ROTATE)
|
||||
|
||||
animate(A, pixel_y = (A.pixel_y + 4), pixel_x = (A.pixel_x + 4), transform = turned, time = T, loop = looping, dir = EAST)
|
||||
animate(pixel_y = (A.pixel_y + 6), transform = turned.Turn(dir == "R" ? 90 : -90), time = T, loop = looping, dir = EAST)
|
||||
animate(pixel_y = (A.pixel_y - 4), transform = turned.Turn(dir == "R" ? 90 : -90), time = T, loop = looping, dir = EAST)
|
||||
animate(pixel_y = (A.pixel_y - 6), pixel_x = (A.pixel_x - 4), transform = turned.Turn(dir == "R" ? 90 : -90), time = T, loop = looping, dir = EAST)
|
||||
|
||||
animate(pixel_y = (A.pixel_y - 4), pixel_x = (A.pixel_x + 4), transform = turned.Turn(dir == "R" ? 90 : -90), time = T, loop = looping, dir = EAST)
|
||||
animate(pixel_y = (A.pixel_y - 4), transform = turned.Turn(dir == "R" ? 90 : -90), time = T, loop = looping, dir = EAST)
|
||||
animate(pixel_y = (A.pixel_y + 4), transform = turned.Turn(dir == "R" ? 90 : -90), time = T, loop = looping, dir = EAST)
|
||||
animate(pixel_y = (A.pixel_y + 4), pixel_x = (A.pixel_x - 4), transform = turned.Turn(dir == "R" ? 90 : -90), time = T, loop = looping, dir = EAST)
|
||||
return
|
||||
|
||||
/proc/animate_smug(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/obj/effect/smug/S = new(A.loc)
|
||||
S.Scale(0.05, 0.05)
|
||||
S.alpha = 0
|
||||
animate(S,transform = matrix(0.5, MATRIX_SCALE), time = 20, alpha = 255, pixel_y = 27, easing = ELASTIC_EASING)
|
||||
animate(time = 5, alpha = 0, pixel_y = -16, easing = CIRCULAR_EASING)
|
||||
spawn(30) qdel(S)
|
||||
return
|
||||
|
||||
/proc/animate_horizontal_wiggle(var/atom/A, var/loopnum = 5, speed = 10, X1 = 3, X2 = -3, var/slightly_random = 1)
|
||||
if (!istype(A))
|
||||
return
|
||||
|
||||
if (slightly_random)
|
||||
var/rand_var = (rand(10, 14) / 10)
|
||||
DEBUG("rand_var [rand_var]")
|
||||
speed = speed * rand_var
|
||||
animate(A, pixel_x = X1, time = speed, loop = loopnum, easing = LINEAR_EASING)
|
||||
animate(pixel_x = X2, time = speed, loop = loopnum, easing = LINEAR_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_slide(var/atom/A, var/px, var/py, var/T = 10, var/ease = SINE_EASING)
|
||||
if(!istype(A))
|
||||
return
|
||||
|
||||
animate(A, pixel_x = px, pixel_y = py, time = T, easing = ease)
|
||||
|
||||
/proc/animate_rest(var/atom/A, var/stand)
|
||||
if(!istype(A))
|
||||
return
|
||||
|
||||
if(stand)
|
||||
animate(A, pixel_x = 0, pixel_y = 0, transform = null, time = 3, easing = LINEAR_EASING)
|
||||
else
|
||||
animate(A, pixel_x = 0, pixel_y = -4, transform = matrix(90, MATRIX_ROTATE), time = 2, easing = LINEAR_EASING)
|
||||
|
||||
/proc/animate_flip(var/atom/A, var/T)
|
||||
animate(A, transform = matrix(A.transform, 90, MATRIX_ROTATE), time = T)
|
||||
animate(transform = matrix(A.transform, 180, MATRIX_ROTATE), time = T)
|
||||
|
||||
|
||||
/proc/animate_offset_spin(var/atom/A, var/radius, var/laps, var/lap_start_t, var/lap_end_t)
|
||||
if(!laps || !radius || lap_start_t < 1 || lap_end_t < 1)
|
||||
return
|
||||
|
||||
animate(A, transform = null, time = 1)
|
||||
var/time_diff = (lap_end_t - lap_start_t) //How much should the lap time change overall ?
|
||||
var/T = lap_start_t //Lap time starts at the set start time
|
||||
var/res = 8 //The resolution - how many points on the circle do we want to calculate?
|
||||
var/deg = 360 / res //How much difference in degrees is there per point?
|
||||
for(var/J = 0 to res*laps) //Step through the points
|
||||
animate(transform = matrix(A.transform, (J!=0)*deg, MATRIX_ROTATE), \
|
||||
pixel_x = (radius * sin(deg*J)), \
|
||||
pixel_y = (radius * cos(deg*J)), \
|
||||
time = (T + (time_diff*J/(laps*res))) / res )
|
||||
DEBUG("Animating D: [deg], res: [res], px: [A.pixel_x], py: [A.pixel_y], T: [T], ActualTime:[(T + (time_diff*J/(laps*res)))], J/laps:[J/(laps*res)] TD:[(time_diff*J/(laps*res))]")
|
||||
//T += time_diff //Modify the time with the calculated difference.
|
||||
animate(pixel_x = 0, pixel_y = 0, time = 2)
|
||||
|
||||
/*
|
||||
/mob/verb/offset_spin(var/radius as num, var/laps as num, var/s_time as num, var/e_time as num)
|
||||
set category = "Debug"
|
||||
set name = "Test Offset Spin"
|
||||
set desc = "(radius,laps,s_time,e_time)Holy balls!"
|
||||
set usr = src
|
||||
animate_offset_spin(src, radius, laps, s_time, e_time)
|
||||
*/
|
||||
|
||||
/proc/animate_shockwave(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/punchstr = rand(10, 20)
|
||||
var/original_y = A.pixel_y
|
||||
animate(A, transform = matrix(punchstr, MATRIX_ROTATE), pixel_y = 16, time = 2, color = "#eeeeee", easing = BOUNCE_EASING)
|
||||
animate(transform = matrix(-punchstr, MATRIX_ROTATE), pixel_y = original_y, time = 2, color = "#ffffff", easing = BOUNCE_EASING)
|
||||
animate(transform = null, time = 3, easing = BOUNCE_EASING)
|
||||
return
|
||||
|
||||
/proc/animate_glitchy_fuckup1(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
|
||||
animate(A, pixel_z = A.pixel_z + -128, time = 3, loop = -1, easing = LINEAR_EASING)
|
||||
animate(pixel_z = A.pixel_z + 128, time = 0, loop = -1, easing = LINEAR_EASING)
|
||||
|
||||
/proc/animate_glitchy_fuckup2(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
|
||||
animate(A, pixel_x = A.pixel_x + rand(-128,128), pixel_z = A.pixel_z + rand(-128,128), time = 2, loop = -1, easing = LINEAR_EASING)
|
||||
animate(pixel_x = 0, pixel_z = 0, time = 0, loop = -1, easing = LINEAR_EASING)
|
||||
|
||||
/proc/animate_glitchy_fuckup3(var/atom/A)
|
||||
if (!istype(A))
|
||||
return
|
||||
var/matrix/M = matrix()
|
||||
var/matrix/MD = matrix()
|
||||
var/list/scaley_numbers = list(0.25,0.5,1,1.5,2)
|
||||
M.Scale(pick(scaley_numbers),pick(scaley_numbers))
|
||||
animate(A, transform = M, time = 1, loop = -1, easing = LINEAR_EASING)
|
||||
animate(transform = MD, time = 1, loop = -1, easing = LINEAR_EASING)
|
||||
|
||||
// these don't use animate but they're close enough, idk
|
||||
/proc/showswirl(var/atom/target)
|
||||
if (!target)
|
||||
return
|
||||
var/turf/target_turf = get_turf(target)
|
||||
if (!target_turf)
|
||||
return
|
||||
var/obj/decal/teleport_swirl/swirl = unpool(/obj/decal/teleport_swirl)
|
||||
swirl.set_loc(target_turf)
|
||||
swirl.pixel_y = 10
|
||||
playsound(target_turf, "sound/effects/teleport.ogg", 50, 1)
|
||||
spawn(15)
|
||||
if (swirl)
|
||||
swirl.pixel_y = 0
|
||||
pool(swirl)
|
||||
return
|
||||
|
||||
/proc/leaveresidual(var/atom/target)
|
||||
if (!target)
|
||||
return
|
||||
var/turf/target_turf = get_turf(target)
|
||||
if (!target_turf)
|
||||
return
|
||||
if (locate(/obj/decal/residual_energy) in target_turf)
|
||||
return
|
||||
var/obj/decal/residual_energy/e = unpool(/obj/decal/residual_energy)
|
||||
e.set_loc(target_turf)
|
||||
spawn(100)
|
||||
if (e)
|
||||
pool(e)
|
||||
return
|
||||
@@ -0,0 +1,674 @@
|
||||
|
||||
//Somewhere out in the vast nothingness of space, a chef (and an admin) is crying.
|
||||
|
||||
/obj/machinery/vending/pizza
|
||||
name = "Pizza Vending Machine"
|
||||
icon_state = "pizza"
|
||||
desc = "A vending machine that serves.. pizza?"
|
||||
var/pizcooking = 0
|
||||
var/piztopping = "plain"
|
||||
anchored = 0
|
||||
acceptcard = 0
|
||||
pay = 1
|
||||
credit = 100
|
||||
|
||||
New()
|
||||
..()
|
||||
slogan_list += "A revolution in the pizza industry!"
|
||||
slogan_list += "Prepared in moments!"
|
||||
slogan_list += "I'm a chef who works 24 hours a day!"
|
||||
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if (stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
var/dat
|
||||
if(pizcooking)
|
||||
dat += "<TT><B>Cooking your pizza, please wait!</B></TT><BR>"
|
||||
else
|
||||
dat += "<TT><B>PizzaVend 0.5b</B></TT><BR>"
|
||||
if(emagged)
|
||||
dat += "<BR><B>Available Credits:</B> CREDIT CALCULATION ERROR<BR>"
|
||||
else
|
||||
dat += "<BR><B>Available Credits:</B> $[src.credit]<BR>"
|
||||
dat += "Topping - <A href='?src=\ref[src];picktopping=1'>[piztopping]</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];cook=1'>Cook!</A><BR>"
|
||||
user << browse("<HEAD><TITLE>Pizza Vendor</TITLE></HEAD>[dat]", "window=pizzavend")
|
||||
onclose(user, "pizzavend")
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if (stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if (usr.contents.Find(src) || in_range(src, usr) && istype(src.loc, /turf))
|
||||
usr.machine = src
|
||||
if (href_list["cook"])
|
||||
if(!pizcooking)
|
||||
if((credit < 50)&&(!emagged))
|
||||
boutput(usr, "<span style=\"color:red\">Insufficient funds!</span>") // no money? get out
|
||||
return
|
||||
if(!emagged)
|
||||
credit -= 50
|
||||
pizcooking = 1
|
||||
icon_state = "pizza-vend"
|
||||
updateUsrDialog()
|
||||
sleep(200)
|
||||
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1, -1)
|
||||
var/obj/item/reagent_containers/food/snacks/pizza/P = new /obj/item/reagent_containers/food/snacks/pizza(src.loc)
|
||||
P.quality = 0.6
|
||||
P.heal_amt = 2
|
||||
P.desc = "A typical [piztopping] pizza."
|
||||
P.name = "[piztopping] pizza"
|
||||
sleep(0.2)
|
||||
if(piztopping != "plain")
|
||||
switch(piztopping)
|
||||
if("meatball") P.topping_color ="#663300"
|
||||
if("mushroom") P.topping_color ="#CFCFCF"
|
||||
if("pepperoni") P.topping_color ="#C90E0E"
|
||||
P.topping = 1
|
||||
P.add_topping(0)
|
||||
|
||||
if (!(stat & (NOPOWER|BROKEN)))
|
||||
icon_state = "pizza"
|
||||
|
||||
pizcooking = 0
|
||||
if(href_list["picktopping"])
|
||||
switch(piztopping)
|
||||
if("plain") piztopping = "meatball"
|
||||
if("meatball") piztopping = "mushroom"
|
||||
if("mushroom") piztopping = "pepperoni"
|
||||
if("pepperoni") piztopping = "plain"
|
||||
add_fingerprint(usr)
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/monkeyplant
|
||||
name = "monkeyplant"
|
||||
icon = 'icons/obj/decoration.dmi'
|
||||
icon_state = "monkeyplant"
|
||||
desc = "Jane Goodall is crying."
|
||||
density = 1
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
src.visible_message("<B>[src]</B> screams!",1)
|
||||
if (narrator_mode)
|
||||
playsound(get_turf(src), 'sound/vox/scream.ogg', 10, 1, -1)
|
||||
else
|
||||
playsound(get_turf(src), 'sound/voice/monkey_scream.ogg', 10, 1, -1)
|
||||
..()
|
||||
return
|
||||
|
||||
//abandoned mars outpost stuff/
|
||||
|
||||
/obj/item/clothing/suit/armor/mars
|
||||
name = "ME-3 Suit"
|
||||
desc = "A suit designed to withstand intense dust storms."
|
||||
icon_state = "mars_blue"
|
||||
icon = 'icons/obj/clothing/overcoats/item_suit_hazard.dmi'
|
||||
wear_image_icon = 'icons/mob/overcoats/worn_suit_hazard.dmi'
|
||||
item_state = "mars_blue"
|
||||
c_flags = SPACEWEAR
|
||||
permeability_coefficient = 0.02
|
||||
protective_temperature = 700
|
||||
heat_transfer_coefficient = 0.02
|
||||
|
||||
/obj/item/clothing/head/helmet/mars
|
||||
name = "ME-3 Helmet "
|
||||
desc = "A suit designed to preserve the user's visibility during intense dust storms."
|
||||
icon_state = "mars"
|
||||
item_state = "mars"
|
||||
c_flags = SPACEWEAR | COVERSEYES | COVERSMOUTH
|
||||
see_face = 0.0
|
||||
|
||||
|
||||
/obj/critter/marsrobot
|
||||
name = "Inactive Robot"
|
||||
desc = "It looks like it hasn't been in service for decades."
|
||||
icon_state = "mars_bot"
|
||||
density = 1
|
||||
health = 55
|
||||
aggressive = 1
|
||||
defensive = 1
|
||||
wanderer = 0
|
||||
opensdoors = 1
|
||||
atkcarbon = 1
|
||||
atksilicon = 1
|
||||
firevuln = 1
|
||||
brutevuln = 1
|
||||
var/active = 0
|
||||
var/startup = 1
|
||||
|
||||
New()
|
||||
..()
|
||||
icon_state = "mars_bot-0"
|
||||
|
||||
seek_target()
|
||||
if(active)
|
||||
src.anchored = 0
|
||||
for (var/mob/living/C in hearers(src.seekrange,src))
|
||||
if ((C.name == src.oldtarget_name) && (world.time < src.last_found + 100)) continue
|
||||
if (iscarbon(C) && !src.atkcarbon) continue
|
||||
if (istype(C, /mob/living/silicon/) && !src.atksilicon) continue
|
||||
if (C.health < 0) continue
|
||||
if (C in src.friends) continue
|
||||
if (C.name == src.attacker) src.attack = 1
|
||||
if (iscarbon(C) && src.atkcarbon) src.attack = 1
|
||||
if (istype(C, /mob/living/silicon/) && src.atksilicon) src.attack = 1
|
||||
|
||||
if (src.attack)
|
||||
src.target = C
|
||||
src.oldtarget_name = C.name
|
||||
if(startup)
|
||||
src.visible_message("<span class='combat'>The <b>[src]</b> suddenly turns on!</span>")
|
||||
name = "malfunctioning robot"
|
||||
src.speak("Lev##LLl 7 SEV-s-E infraAAAAAaction @leRT??!")
|
||||
src.visible_message("The <b>[src]</b> points at [C.name]!")
|
||||
playsound(src.loc, 'sound/voice/robot_scream.ogg', 50, 1)
|
||||
startup = 0
|
||||
wanderer = 1
|
||||
src.visible_message("<span style=\"color:red\">The <b>[src]</b> charges at [C:name]!</span>")
|
||||
src.speak(pick("DooN'T Wor##y I'M hERE!!!","LawwSS UpdAA&$.A.!!.!","CANIHELPYO&£%SIR","REsREACH!!!!!","NATAS&$%LIAHLLA ERROR CODE #736"))
|
||||
playsound(src.loc, 'sound/machines/glitch3.ogg', 50, 1)
|
||||
icon_state = "mars_bot"
|
||||
src.task = "chasing"
|
||||
break
|
||||
else
|
||||
continue
|
||||
|
||||
ChaseAttack(mob/M)
|
||||
src.visible_message("<span class='combat'>The <B>[src]</B> launches itself towards [M]!</span>")
|
||||
if (prob(20)) M.stunned += rand(1,3)
|
||||
random_brute_damage(M, rand(2,5))
|
||||
|
||||
CritterAttack(mob/M)
|
||||
src.attacking = 1
|
||||
src.visible_message("<span class='combat'>The <B>[src]</B> slams itself against [src.target]!</span>")
|
||||
random_brute_damage(src.target, rand(7,17))
|
||||
spawn(10)
|
||||
src.attacking = 0
|
||||
|
||||
|
||||
Move()
|
||||
..()
|
||||
playsound(src.loc, 'sound/effects/airbridge_dpl.ogg', 30, 10, -2)
|
||||
|
||||
|
||||
proc/speak(var/message)
|
||||
for(var/mob/O in hearers(src, null))
|
||||
boutput(O, "<span class='game say'><span class='name'>[src]</span> beeps, \"[message]\"")
|
||||
return
|
||||
|
||||
attackby(obj/item/W as obj, mob/living/user as mob)
|
||||
if(active) ..()
|
||||
|
||||
attack_hand(var/mob/user as mob)
|
||||
if(active) ..()
|
||||
|
||||
CritterDeath()
|
||||
if (!src.alive) return
|
||||
src.icon_state += "-dead"
|
||||
src.alive = 0
|
||||
src.anchored = 0
|
||||
src.density = 0
|
||||
walk_to(src,0)
|
||||
src.visible_message("<b>[src]</b> collapses!")
|
||||
playsound(src.loc, 'sound/voice/robot_scream.ogg', 50, 1)
|
||||
speak("aaaaaaalkaAAAA##AAAAAAAAAAAAAAAAA'ERRAAAAAAAA!!!")
|
||||
|
||||
/obj/mars_roverpuzzle
|
||||
name = "rover frame"
|
||||
icon = 'icons/misc/worlds.dmi'
|
||||
icon_state = "rover_puzzle_base"
|
||||
desc = "It looks like this rover was never finished."
|
||||
density = 1
|
||||
anchored = 1
|
||||
var/wheel = 0
|
||||
var/oxy = 0
|
||||
var/battery = 0
|
||||
var/glass = 0
|
||||
var/motherboard = 0
|
||||
|
||||
attackby(obj/item/P as obj, mob/user as mob)
|
||||
if (istype(P, /obj/item/mars_roverpart))
|
||||
if ((istype(P, /obj/item/mars_roverpart/wheel))&&(!wheel))
|
||||
boutput(user, "<span style=\"color:blue\">You attach the wheel to the rover's chassis.</span>")
|
||||
overlays += icon('icons/misc/worlds.dmi', "rover_puzzle_wheel")
|
||||
wheel = 1
|
||||
if ((istype(P, /obj/item/mars_roverpart/oxy))&&(!oxy))
|
||||
boutput(user, "<span style=\"color:blue\">You connect the life support module to the rover.</span>")
|
||||
overlays += icon('icons/misc/worlds.dmi', "rover_puzzle_oxy")
|
||||
oxy = 1
|
||||
if ((istype(P, /obj/item/mars_roverpart/glass))&&(!glass))
|
||||
boutput(user, "<span style=\"color:blue\">You attach the glass to the rover.</span>")
|
||||
overlays += icon('icons/misc/worlds.dmi', "rover_puzzle_window")
|
||||
glass = 1
|
||||
if ((istype(P, /obj/item/mars_roverpart/battery))&&(!battery))
|
||||
boutput(user, "<span style=\"color:blue\">You wire the battery to the rover.</span>")
|
||||
overlays += icon('icons/misc/worlds.dmi', "rover_puzzle_cell")
|
||||
battery = 1
|
||||
if ((istype(P, /obj/item/mars_roverpart/motherboard))&&(!motherboard))
|
||||
boutput(user, "<span style=\"color:blue\">You wire the motherboard to the rover.</span>")
|
||||
motherboard = 1
|
||||
playsound(user, 'sound/items/Deconstruct.ogg', 65, 1)
|
||||
qdel(P)
|
||||
if((wheel)&&(oxy)&&(battery)&&(glass)&&(motherboard))
|
||||
var/obj/vehicle/marsrover/R = new /obj/vehicle/marsrover(loc)
|
||||
R.dir = WEST
|
||||
playsound(src.loc, 'sound/machines/rev_engine.ogg', 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">The rover has been completed!</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/mars_roverpart
|
||||
icon = 'icons/misc/worlds.dmi'
|
||||
|
||||
wheel
|
||||
name = "wheel"
|
||||
icon_state = "rover_puzzle_wheelitem"
|
||||
desc = "A wheel for some kind of vehicle."
|
||||
oxy
|
||||
name = "filter"
|
||||
icon_state = "rover_puzzle_oxyitem"
|
||||
desc = "Some kind of filter designed to keep dust from getting into a chamber."
|
||||
glass
|
||||
name = "glass"
|
||||
icon_state = "rover_puzzle_glassitem"
|
||||
desc = "It looks pretty strong."
|
||||
battery
|
||||
name = "rover battery"
|
||||
icon_state = "rover_puzzle_batteryitem"
|
||||
desc = "A battery designed for rovers. I don't think it's safe to poke around with this thing."
|
||||
|
||||
motherboard
|
||||
name = "rover motherboard"
|
||||
icon_state = "rover_puzzle_motherboarditem"
|
||||
desc = "The motherboard of a rover, it looks pretty fancy!"
|
||||
var/pickedup = 0
|
||||
|
||||
pickup(mob/user)
|
||||
..()
|
||||
if(!pickedup)
|
||||
boutput(user, "<span style=\"color:red\">Uh oh.</span>")
|
||||
for(var/obj/critter/marsrobot/M in oview(4,src))
|
||||
M.active = 1
|
||||
M.seek_target()
|
||||
pickedup = 1
|
||||
|
||||
|
||||
/obj/vehicle/marsrover
|
||||
name = "Rover"
|
||||
desc = "A rover designed to let researchers explore hazardous planets safely and efficiently. It looks pretty old."
|
||||
icon_state = "marsrover"
|
||||
rider_visible = 0
|
||||
layer = MOB_LAYER + 1
|
||||
sealed_cabin = 1
|
||||
mats = 8
|
||||
|
||||
/obj/vehicle/marsrover/proc/update()
|
||||
if(rider)
|
||||
icon_state = "marsrover2"
|
||||
else
|
||||
icon_state = "marsrover"
|
||||
|
||||
/obj/vehicle/marsrover/eject_rider(var/crashed, var/selfdismount)
|
||||
rider.set_loc(src.loc)
|
||||
rider.pixel_y = 0
|
||||
walk(src, 0)
|
||||
|
||||
for (var/obj/item/I in src)
|
||||
I.set_loc(get_turf(src))
|
||||
|
||||
if(crashed)
|
||||
if(crashed == 2)
|
||||
playsound(src.loc, 'sound/misc/meteorimpact.ogg', 40, 1)
|
||||
boutput(rider, "<span class='combat'><B>You are flung over the [src]'s handlebars!</B></span>")
|
||||
rider.stunned = 8
|
||||
rider.weakened = 5
|
||||
for (var/mob/C in AIviewers(src))
|
||||
if(C == rider)
|
||||
continue
|
||||
C.show_message("<span class='combat'><B>[rider] is flung over the [src]'s handlebars!</B></span>", 1)
|
||||
var/turf/target = get_edge_target_turf(src, src.dir)
|
||||
rider.throw_at(target, 5, 1)
|
||||
rider.buckled = null
|
||||
rider = null
|
||||
|
||||
update()
|
||||
return
|
||||
if(selfdismount)
|
||||
boutput(rider, "<span style=\"color:blue\">You dismount from the [src].</span>")
|
||||
for (var/mob/C in AIviewers(src))
|
||||
if(C == rider)
|
||||
continue
|
||||
C.show_message("<B>[rider]</B> dismounts from the [src].", 1)
|
||||
rider.buckled = null
|
||||
rider = null
|
||||
update()
|
||||
return
|
||||
|
||||
/obj/vehicle/marsrover/relaymove(mob/user as mob, dir)
|
||||
if(rider)
|
||||
if(istype(src.loc, /turf/space))
|
||||
return
|
||||
icon_state = "marsrover2"
|
||||
walk(src, dir, 2)
|
||||
else
|
||||
for(var/mob/M in src.contents)
|
||||
M.set_loc(src.loc)
|
||||
|
||||
/obj/vehicle/marsrover/MouseDrop_T(mob/living/carbon/human/target, mob/user)
|
||||
if (rider || !istype(target) || target.buckled || LinkBlocked(target.loc,src.loc) || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.paralysis || user.stunned || user.weakened || user.stat || istype(user, /mob/living/silicon/ai))
|
||||
return
|
||||
|
||||
var/msg
|
||||
|
||||
if(target == user && !user.stat) // if drop self, then climbed in
|
||||
msg = "[user.name] climbs onto the [src]."
|
||||
boutput(user, "<span style=\"color:blue\">You climb onto the [src].</span>")
|
||||
else if(target != user && !user.restrained())
|
||||
msg = "[user.name] helps [target.name] onto the [src]!"
|
||||
boutput(user, "<span style=\"color:blue\">You help [target.name] onto the [src]!</span>")
|
||||
else
|
||||
return
|
||||
|
||||
for (var/obj/item/I in src)
|
||||
I.set_loc(get_turf(src))
|
||||
|
||||
target.set_loc(src)
|
||||
rider = target
|
||||
rider.pixel_x = 0
|
||||
rider.pixel_y = 5
|
||||
if(rider.restrained() || rider.stat)
|
||||
rider.buckled = src
|
||||
|
||||
for (var/mob/C in AIviewers(src))
|
||||
if(C == user)
|
||||
continue
|
||||
C.show_message(msg, 3)
|
||||
|
||||
update()
|
||||
return
|
||||
|
||||
/obj/vehicle/marsrover/Click()
|
||||
if(usr != rider)
|
||||
..()
|
||||
return
|
||||
if(!(usr.paralysis || usr.stunned || usr.weakened || usr.stat))
|
||||
eject_rider(0, 1)
|
||||
return
|
||||
|
||||
/obj/vehicle/marsrover/attack_hand(mob/living/carbon/human/M as mob)
|
||||
if(!M || !rider)
|
||||
..()
|
||||
return
|
||||
switch(M.a_intent)
|
||||
if("harm", "disarm")
|
||||
if(prob(60))
|
||||
playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
src.visible_message("<span class='combat'><B>[M] has shoved [rider] off of the [src]!</B></span>")
|
||||
rider.weakened = 2
|
||||
eject_rider()
|
||||
else
|
||||
playsound(src.loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
|
||||
src.visible_message("<span class='combat'><B>[M] has attempted to shove [rider] off of the [src]!</B></span>")
|
||||
return
|
||||
|
||||
/obj/vehicle/marsrover/bullet_act(flag, A as obj)
|
||||
if(rider)
|
||||
eject_rider()
|
||||
rider.bullet_act(flag, A)
|
||||
return
|
||||
|
||||
/obj/vehicle/marsrover/meteorhit()
|
||||
if(rider)
|
||||
eject_rider()
|
||||
rider.meteorhit()
|
||||
return
|
||||
|
||||
/obj/vehicle/marsrover/disposing()
|
||||
if(rider)
|
||||
boutput(rider, "<span class='combat'><B>Your rover is destroyed!</B></span>")
|
||||
eject_rider()
|
||||
..()
|
||||
return
|
||||
|
||||
/area/marsoutpost
|
||||
name = "Abandoned Outpost"
|
||||
var/sound/mysound = null
|
||||
|
||||
New()
|
||||
..()
|
||||
var/sound/S = new/sound()
|
||||
mysound = S
|
||||
S.file = 'sound/ambience/mars_interiorambi.ogg'
|
||||
S.repeat = 1
|
||||
S.wait = 0
|
||||
S.channel = 123
|
||||
S.volume = 60
|
||||
S.priority = 255
|
||||
S.status = SOUND_UPDATE
|
||||
spawn(10) 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()
|
||||
var/sound/S = null
|
||||
var/sound_delay = 0
|
||||
while(ticker && ticker.current_state < GAME_STATE_FINISHED)
|
||||
sleep(60)
|
||||
if (ticker.current_state == GAME_STATE_PLAYING)
|
||||
if(prob(10))
|
||||
S = sound(file=pick('sound/ambience/marsfx1.ogg','sound/ambience/marsfx2.ogg','sound/ambience/marsfx3.ogg','sound/ambience/marsfx4.ogg'), volume=100)
|
||||
sound_delay = rand(0, 50)
|
||||
else
|
||||
S = null
|
||||
continue
|
||||
|
||||
for(var/mob/living/carbon/human/H in src)
|
||||
if(H.client)
|
||||
mysound.status = SOUND_UPDATE
|
||||
H << mysound
|
||||
if(S)
|
||||
spawn(sound_delay)
|
||||
H << S
|
||||
|
||||
/area/marsoutpost/duststorm
|
||||
name = "Barren Planet"
|
||||
icon_state = "yellow"
|
||||
|
||||
New()
|
||||
..()
|
||||
overlays += image(icon = 'icons/turf/areas.dmi', icon_state = "dustverlay", layer = EFFECTS_LAYER_BASE)
|
||||
|
||||
Entered(atom/movable/O)
|
||||
..()
|
||||
if (istype(O, /mob/living/carbon/human))
|
||||
var/mob/living/jerk = O
|
||||
if (jerk.stat != 2)
|
||||
if((istype(jerk:wear_suit, /obj/item/clothing/suit/armor/mars))&&(istype(jerk:head, /obj/item/clothing/head/helmet/mars))) return
|
||||
random_brute_damage(jerk, 100)
|
||||
jerk.weakened = 40
|
||||
step(jerk,EAST)
|
||||
if(prob(50))
|
||||
playsound(src.loc, 'sound/effects/bloody_stabOLD.ogg', 50, 1)
|
||||
boutput(jerk, pick("Dust gets caught in your eyes!","The wind blows you off course!","Debris pierces through your skin!"))
|
||||
|
||||
|
||||
|
||||
/area/marsoutpost/vault
|
||||
icon_state = "red"
|
||||
|
||||
/obj/critter/gunbot/heavy
|
||||
name = "security robot"
|
||||
desc = "A 2030's-era security robot. Uh oh."
|
||||
icon = 'icons/misc/critter.dmi'
|
||||
icon_state = "mars_sec_bot"
|
||||
opensdoors = 0
|
||||
atksilicon = 1
|
||||
var/overheat = 0
|
||||
var/datum/projectile/my_bullet = new/datum/projectile/bullet/revolver_38
|
||||
|
||||
Shoot()
|
||||
if(overheat < 10)
|
||||
overheat ++
|
||||
..()
|
||||
|
||||
proc/speak(var/message)
|
||||
if((!alive) || (!message))
|
||||
return
|
||||
|
||||
var/fontSize = 2
|
||||
var/fontIncreasing = 1
|
||||
var/fontSizeMax = 2
|
||||
var/fontSizeMin = -2
|
||||
var/messageLen = length(message)
|
||||
var/processedMessage = ""
|
||||
|
||||
for (var/i = 1, i <= messageLen, i++)
|
||||
processedMessage += "<font size=[fontSize]>[copytext(message, i, i+1)]</font>"
|
||||
if (fontIncreasing)
|
||||
fontSize = min(fontSize+1, fontSizeMax)
|
||||
if (fontSize >= fontSizeMax)
|
||||
fontIncreasing = 0
|
||||
else
|
||||
fontSize = max(fontSize-1, fontSizeMin)
|
||||
if (fontSize <= fontSizeMin)
|
||||
fontIncreasing = 1
|
||||
if(prob(10))
|
||||
processedMessage += pick("%","##A","-","- - -","ERROR")
|
||||
|
||||
for(var/mob/O in hearers(src, null))
|
||||
O.show_message("<span class='game say'><span class='name'>[src]</span> blares, \"<B>[processedMessage]</B>\"",2)
|
||||
|
||||
return
|
||||
|
||||
|
||||
seek_target()
|
||||
src.anchored = 0
|
||||
if(overheat == 10)
|
||||
speak("WARNING : OVERHEATING")
|
||||
sleep(50)
|
||||
overheat = 0
|
||||
else
|
||||
for (var/mob/living/C in hearers(src.seekrange,src))
|
||||
if (!src.alive) break
|
||||
if (C.health < 0) continue
|
||||
if (C.name == src.attacker) src.attack = 1
|
||||
if (iscarbon(C) && src.atkcarbon) src.attack = 1
|
||||
if (istype(C, /mob/living/silicon/) && src.atksilicon) src.attack = 1
|
||||
|
||||
if (src.attack)
|
||||
|
||||
src.target = C
|
||||
src.oldtarget_name = C.name
|
||||
src.visible_message("<span class='combat'><b>[src]</b> rapidly fires at [src.target]!</span>")
|
||||
|
||||
|
||||
playsound(src.loc, 'sound/weapons/ak47shot.ogg', 50, 1)
|
||||
var/tturf = get_turf(target)
|
||||
spawn(2)
|
||||
Shoot(tturf, src.loc, src)
|
||||
src.pixel_x += rand(-3,3)
|
||||
src.pixel_y += rand(-3,3)
|
||||
if(prob(55))
|
||||
speak(pick("SECURITY OPERATION IN PROGRESS.","WARNING - YOU ARE IN A SECURITY ZONE.","ALERT - ALL OUTPOST PERSONNEL ARE TO MOVE TO A SAFE ZONE.","WARNING: THREAT RECOGNIZED AS NANOTRASEN, ESPONIAGE DETECTED","THIS IS FOR THE FREE MARKET","NANOTRASEN BETRAYED YOU."))
|
||||
var/glitchsound = pick('sound/machines/romhack1.ogg', 'sound/machines/romhack2.ogg', 'sound/machines/romhack3.ogg','sound/machines/glitch1.ogg','sound/machines/glitch2.ogg','sound/machines/glitch3.ogg','sound/machines/glitch4.ogg','sound/machines/glitch5.ogg')
|
||||
playsound(src.loc, glitchsound, 50, 1)
|
||||
if(prob(75))
|
||||
spawn(0) step_to(src,target)
|
||||
src.attack = 0
|
||||
return
|
||||
else continue
|
||||
task = "thinking"
|
||||
|
||||
Shoot(var/target, var/start, var/user, var/bullet = 0)
|
||||
if(target == start)
|
||||
return
|
||||
if (!start) //Wire: fix for Cannot read null.y (start was null somehow)
|
||||
return
|
||||
|
||||
shoot_projectile_ST(src, my_bullet, target)
|
||||
|
||||
/obj/machinery/computer/mars_vault
|
||||
name = "Vault Console"
|
||||
desc = "A very old computer that controls the vault."
|
||||
icon_state = "old"
|
||||
pixel_y = 8
|
||||
var/triggered = 0
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if (..() || (stat & (NOPOWER|BROKEN)))
|
||||
return
|
||||
|
||||
user.machine = src
|
||||
add_fingerprint(user)
|
||||
|
||||
var/dat = "<center><h4>Vault Computer</h4></center>"
|
||||
if(triggered)
|
||||
dat += "<center><font size = 20>VAULT UNLOCKED</font></center><br>"
|
||||
|
||||
else
|
||||
dat += "<center><a href='?src=\ref[src];unlock=1'>Unlock Vault</a></center>"
|
||||
user << browse("<head><title>Vault Computer</title></head>[dat]", "window=tourconsole;size=302x245")
|
||||
onclose(user, "vaultcomputer")
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.machine = src
|
||||
src.add_fingerprint(usr)
|
||||
|
||||
if (href_list["unlock"])
|
||||
if(!triggered)
|
||||
triggered = 1
|
||||
for(var/area/marsoutpost/vault/V in world)
|
||||
V.overlays += image(icon = 'icons/effects/alert.dmi', icon_state = "blue", layer = EFFECTS_LAYER_1)
|
||||
for(var/obj/machinery/door/poddoor/P)
|
||||
if (P.id == "mars_vault")
|
||||
spawn( 0 )
|
||||
P.open()
|
||||
for(var/obj/item/storage/secure/ssafe/marsvault/M in world)
|
||||
M.disabled = 0
|
||||
|
||||
for(var/obj/machinery/door/poddoor/P)
|
||||
playsound(src.loc, 'sound/machines/engine_alert1.ogg', 50, 1)
|
||||
|
||||
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/item/device/audio_log/mars
|
||||
continuous = 0
|
||||
audiolog_messages = list("*Heavy breathing*",
|
||||
"ALERT: THE EMERGENCY ROCKET WILL ARRIVE IN FIVE MINUTES.",
|
||||
"Come on, wh-have to get out of here!",
|
||||
"I can't.. *cough*",
|
||||
"Please! We can't just stay here, we are the only ones left who-",
|
||||
"It's too late for me, you sti-*cough*-have a chance to escape with it.",
|
||||
"Take the r-ro-rover, it's yo-u-*cough* *cough* ... . . .",
|
||||
"*Psshhh*")
|
||||
audiolog_speakers = list("Male Scientist",
|
||||
"Computerized Voice",
|
||||
"Female Scientist",
|
||||
"Male Scientist",
|
||||
"Female Scientist",
|
||||
"Male Scientist",
|
||||
"Male Scientist",
|
||||
"Airlock")
|
||||
@@ -0,0 +1,34 @@
|
||||
/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/icon/I = new('icons/mob/inhand/hand_general.dmi')
|
||||
var/list/states = I.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(!states.Find(O.icon_state) && !states.Find(O.item_state))
|
||||
if(O.icon_state)
|
||||
text += "[O.type] WANTS SPRITE CALLED<br>\"[O.icon_state]\".<br>"
|
||||
|
||||
|
||||
if(O.icon_state)
|
||||
if(!istates.Find(O.icon_state))
|
||||
text += "[O.type] MISSING NORMAL ICON CALLED<br>\"[O.icon_state]\" IN \"[O.icon]\"<br>"
|
||||
if(O.item_state)
|
||||
if(!istates.Find(O.item_state))
|
||||
text += "[O.type] MISSING NORMAL ICON CALLED<br>\"[O.item_state]\" IN \"[O.icon]\"<br>"
|
||||
text+="<br>"
|
||||
qdel(O)
|
||||
if(text)
|
||||
var/F = file("broken_icons.txt")
|
||||
fdel(F)
|
||||
boutput(F, text)
|
||||
boutput(world, "Completely successfully and written to [F]")
|
||||
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
/obj/item/storage/photo_album
|
||||
name = "Photo album"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "album"
|
||||
item_state = "briefcase"
|
||||
|
||||
/obj/item/storage/photo_album/attackby(obj/item/W as obj, mob/user as mob)
|
||||
if (!istype(W,/obj/item/photo))
|
||||
boutput(user, "<span style=\"color:red\">You can only put photos in a photo album.</span>")
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/camera_test
|
||||
name = "camera"
|
||||
icon = 'icons/obj/device.dmi'
|
||||
desc = "A reusable polaroid camera."
|
||||
icon_state = "camera"
|
||||
item_state = "electropack"
|
||||
w_class = 2.0
|
||||
flags = FPRINT | TABLEPASS | EXTRADELAY | CONDUCT | ONBELT
|
||||
m_amt = 2000
|
||||
throwforce = 5
|
||||
throw_speed = 4
|
||||
throw_range = 10
|
||||
var/pictures_left = 10
|
||||
var/pictures_max = 30
|
||||
var/can_use = 1
|
||||
|
||||
large
|
||||
pictures_left = 30
|
||||
|
||||
examine()
|
||||
..()
|
||||
boutput(usr, "There are [src.pictures_left] pictures left!")
|
||||
return
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if (istype(W, /obj/item/camera_film))
|
||||
var/obj/item/camera_film/C = W
|
||||
|
||||
if (C.pictures <= 0)
|
||||
user.show_text("The [C.name] is used up.", "red")
|
||||
return
|
||||
if (src.pictures_left < 0)
|
||||
src.pictures_left = 0
|
||||
if (src.pictures_left != 0)
|
||||
user.show_text("You have to use up the current film cartridge before you can replace it.", "red")
|
||||
return
|
||||
|
||||
src.pictures_left = min(src.pictures_left + C.pictures, src.pictures_max)
|
||||
user.u_equip(C)
|
||||
qdel(C)
|
||||
user.show_text("You replace the film cartridge. The camera can now take [src.pictures_left] pictures.", "blue")
|
||||
|
||||
else
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/item/camera_film
|
||||
name = "film cartridge"
|
||||
desc = "A replacement film cartridge for an instant camera."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "camera_film"
|
||||
item_state = "box"
|
||||
w_class = 2.0
|
||||
mats = 10
|
||||
var/pictures = 10
|
||||
|
||||
large
|
||||
name = "film cartridge (large)"
|
||||
pictures = 30
|
||||
mats = 15
|
||||
|
||||
examine()
|
||||
..()
|
||||
boutput(usr, "It is good for [src.pictures] pictures.")
|
||||
return
|
||||
|
||||
/obj/item/photo
|
||||
name = "photo"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "photo"
|
||||
item_state = "clipboard"
|
||||
w_class = 1.0
|
||||
var/image/fullImage
|
||||
var/icon/fullIcon
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*/obj/item/camera_test*/
|
||||
/proc/build_composite_icon(var/atom/C)
|
||||
if (!C)
|
||||
return
|
||||
var/image/composite = image(C.icon, null, C.icon_state, null /*max(OBJ_LAYER, C.layer)*/, C.dir)
|
||||
if (!composite)
|
||||
return
|
||||
|
||||
composite.overlays = C.overlays
|
||||
composite.underlays = C.underlays
|
||||
return composite
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/obj/item/camera_test/attack(mob/living/carbon/human/M as mob, mob/user as mob)
|
||||
return
|
||||
|
||||
/obj/item/camera_test/afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag)
|
||||
if (!can_use || ismob(target.loc)) return
|
||||
if (src.pictures_left <= 0)
|
||||
if (src.pictures_left < 0)
|
||||
src.pictures_left = 0
|
||||
user.show_text("The film cartridge is used up. You have to replace it first.", "red")
|
||||
return
|
||||
|
||||
var/turf/the_turf = get_turf(target)
|
||||
|
||||
var/image/photo = image(the_turf.icon, null, the_turf.icon_state, OBJ_LAYER, the_turf.dir)
|
||||
var/icon/photo_icon = getFlatIcon(the_turf)
|
||||
if (!photo)
|
||||
return
|
||||
|
||||
//photo.overlays += the_turf
|
||||
|
||||
//turficon.Scale(22,20)
|
||||
|
||||
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 || istype(A, /obj/overlay/tile_effect))
|
||||
continue
|
||||
if(ismob(A))
|
||||
var/image/X = build_composite_icon(A)
|
||||
var/icon/Y = A:build_flat_icon()
|
||||
//X.Scale(22,20)
|
||||
photo.overlays += X
|
||||
photo_icon.Blend(Y, ICON_OVERLAY)
|
||||
qdel(X)
|
||||
qdel(Y)
|
||||
|
||||
if(!mob_title)
|
||||
mob_title = "[A]"
|
||||
else
|
||||
mob_title += " and [A]"
|
||||
|
||||
if(!mob_detail)
|
||||
|
||||
var/holding = null
|
||||
if(iscarbon(A))
|
||||
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/image/X = build_composite_icon(A)
|
||||
var/icon/Y = getFlatIcon(A)
|
||||
if (X)
|
||||
//X.Scale(22,20)
|
||||
photo.overlays += X
|
||||
if (Y)
|
||||
photo_icon.Blend(Y, ICON_OVERLAY)
|
||||
itemnumber++
|
||||
qdel(X)
|
||||
qdel(Y)
|
||||
|
||||
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/photo/P = new/obj/item/photo( get_turf(src) )
|
||||
|
||||
P.fullImage = photo//image(photo, "")
|
||||
P.fullIcon = photo_icon
|
||||
|
||||
var/oldtransform = P.fullImage.transform
|
||||
P.fullImage.transform = matrix(0.6875, 0.625, MATRIX_SCALE)
|
||||
P.fullImage.pixel_y = 1
|
||||
P.overlays += P.fullImage
|
||||
P.fullImage.transform = oldtransform
|
||||
P.fullImage.pixel_y = 0
|
||||
//boutput(world, "[bicon(P.fullImage)]")
|
||||
|
||||
P.name = finished_title
|
||||
P.desc = finished_detail
|
||||
|
||||
playsound(src.loc, pick('sound/items/polaroid1.ogg','sound/items/polaroid2.ogg'), 75, 1, -3)
|
||||
|
||||
src.pictures_left = max(0, src.pictures_left - 1)
|
||||
boutput(user, "<span style=\"color:blue\">[pictures_left] photos left.</span>")
|
||||
can_use = 0
|
||||
spawn (50)
|
||||
if (src) src.can_use = 1
|
||||
@@ -0,0 +1,532 @@
|
||||
/turf/unsimulated/floor/cave
|
||||
name = "cave floor"
|
||||
icon_state = "cave-medium"
|
||||
RL_Ignore = 0
|
||||
|
||||
/turf/unsimulated/wall/cave
|
||||
name = "cave wall"
|
||||
icon_state = "cave-dark"
|
||||
RL_Ignore = 0
|
||||
|
||||
////// cogwerks - lava turf
|
||||
|
||||
/turf/unsimulated/floor/lava
|
||||
name = "Lava"
|
||||
desc = "The floor is lava. Oh no."
|
||||
icon_state = "lava"
|
||||
var/deadly = 1
|
||||
RL_Ignore = 0
|
||||
pathable = 0
|
||||
can_replace_with_stuff = 1
|
||||
|
||||
Entered(atom/movable/O)
|
||||
..()
|
||||
if(src.deadly)
|
||||
if (istype(O, /obj/critter) && O:flying)
|
||||
return
|
||||
|
||||
if (istype(O, /obj/projectile))
|
||||
return
|
||||
|
||||
if (istype(O, /obj/overlay/tile_effect))
|
||||
return
|
||||
|
||||
if (O.throwing && !istype(O, /mob/living))
|
||||
spawn(8)
|
||||
if (O && O.loc == src)
|
||||
melt_away(O)
|
||||
return
|
||||
|
||||
melt_away(O)
|
||||
|
||||
|
||||
proc/melt_away(atom/movable/O)
|
||||
if (istype(O, /mob))
|
||||
if (istype(O, /mob/living))
|
||||
var/mob/living/M = O
|
||||
var/mob/living/carbon/human/H = M
|
||||
if (istype(H))
|
||||
H.unkillable = 0
|
||||
if(!M.stat) M.emote("scream")
|
||||
src.visible_message("<span style=\"color:red\"><B>[M]</B> falls into the [src] and melts away!</span>")
|
||||
M.firegib() // thanks ISN!
|
||||
else
|
||||
src.visible_message("<span style=\"color:red\"><B>[O]</B> falls into the [src] and melts away!</span>")
|
||||
qdel(O)
|
||||
|
||||
ex_act(severity)
|
||||
return
|
||||
|
||||
/obj/decal/lightshaft
|
||||
name = "light"
|
||||
desc = "There's light coming through a hole in the ceiling."
|
||||
density = 0
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
layer = NOLIGHT_EFFECTS_LAYER_BASE
|
||||
icon = 'icons/effects/64x64.dmi'
|
||||
icon_state = "lightshaft"
|
||||
luminosity = 2
|
||||
|
||||
/obj/decal/stalagtite
|
||||
name = "stalactite" // c, not g! c as in ceiling, g as in ground. dang!
|
||||
desc = "It's a stalactite."
|
||||
density = 0
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
layer = EFFECTS_LAYER_BASE
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "stal1"
|
||||
|
||||
/obj/decal/stalagmite
|
||||
name = "stalagmite"
|
||||
desc = "It's a stalagmite."
|
||||
density = 1
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
layer = EFFECTS_LAYER_BASE
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "stal2"
|
||||
|
||||
/obj/decal/snowbits
|
||||
name = "snow"
|
||||
desc = "A bit of snow."
|
||||
density = 0
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
layer = OBJ_LAYER
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "snowbits"
|
||||
|
||||
/obj/decal/runemarks
|
||||
name = "runes"
|
||||
desc = "A set of dimly glowing runes is carved into the rock here."
|
||||
density = 0
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
layer = OBJ_LAYER
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "runemarks"
|
||||
|
||||
/obj/decal/cliff
|
||||
name = "cliff"
|
||||
desc = "The edge of a cliff."
|
||||
density = 0
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
layer = OBJ_LAYER
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "cliff"
|
||||
|
||||
/obj/decal/statue
|
||||
name = "statue"
|
||||
desc = "A statue of some humanoid being."
|
||||
density = 1
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
layer = OBJ_LAYER
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "stat1"
|
||||
|
||||
/obj/decal/statue/monkey1
|
||||
desc = "A statue of a monkey of some sort."
|
||||
icon_state = "stat2"
|
||||
|
||||
/obj/decal/statue/monkey2
|
||||
desc = "A statue of a monkey of some sort."
|
||||
icon_state = "stat3"
|
||||
|
||||
/obj/decal/statue/monkey3
|
||||
desc = "A statue of a monkey of some sort."
|
||||
icon_state = "stat4"
|
||||
|
||||
/obj/decal/woodclutter
|
||||
name = "pieces of wood"
|
||||
desc = "Theres bits and pieces of wood all over the place."
|
||||
density = 0
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
layer = OBJ_LAYER
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "woodclutter4"
|
||||
|
||||
/obj/decal/mushrooms
|
||||
name = "mushroom"
|
||||
desc = "Some sort of mushroom."
|
||||
density = 0
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
layer = OBJ_LAYER
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "mushroom7"
|
||||
|
||||
/obj/decal/mushrooms/type1
|
||||
icon_state = "mushroom1"
|
||||
|
||||
/obj/decal/mushrooms/type2
|
||||
icon_state = "mushroom2"
|
||||
|
||||
/obj/decal/mushrooms/type3
|
||||
icon_state = "mushroom3"
|
||||
|
||||
/obj/decal/mushrooms/type4
|
||||
icon_state = "mushroom4"
|
||||
|
||||
/obj/decal/mushrooms/type5
|
||||
icon_state = "mushroom5"
|
||||
|
||||
/obj/decal/mushrooms/type6
|
||||
icon_state = "mushroom6"
|
||||
|
||||
/obj/decal/mushrooms/type7
|
||||
icon_state = "mushroom7"
|
||||
|
||||
/obj/shifting_wall/sneaky/cave
|
||||
name = "strange wall"
|
||||
desc = "This wall seems strangely out-of-place."
|
||||
icon_state = "cave-dark"
|
||||
icon = 'icons/turf/walls.dmi'
|
||||
|
||||
var/active = 0
|
||||
|
||||
proc/do_move(var/direction)
|
||||
if(active) return
|
||||
var/turf/tile = get_step(src,direction)
|
||||
if(tile.density) return
|
||||
if(is_blocked_turf(tile)) return
|
||||
if(locate(/obj/decal/runemarks) in tile) return
|
||||
|
||||
active = 1
|
||||
|
||||
if(src.loc.invisibility) src.loc.invisibility = 0
|
||||
if(src.loc.opacity) src.loc.opacity = 0
|
||||
|
||||
src.set_loc(tile)
|
||||
|
||||
spawn(5)
|
||||
tile.invisibility = 100
|
||||
tile.opacity = 1
|
||||
active = 0
|
||||
|
||||
find_suitable_tiles()
|
||||
var/list/possible = new/list()
|
||||
|
||||
for(var/A in cardinal)
|
||||
var/turf/current = get_step(src,A)
|
||||
if(current.density) continue
|
||||
if(is_blocked_turf(current)) continue
|
||||
if(someone_can_see(current)) continue
|
||||
if(locate(/obj/decal/runemarks) in current) continue
|
||||
possible += current
|
||||
|
||||
return possible
|
||||
|
||||
update()
|
||||
if(active) return
|
||||
if(someone_can_see_me())
|
||||
spawn(rand(50,80)) update()
|
||||
return
|
||||
|
||||
var/list/possible = find_suitable_tiles()
|
||||
|
||||
if(!possible.len)
|
||||
spawn(30) update()
|
||||
return
|
||||
|
||||
active = 1
|
||||
if(prob(25)) // don't let all of them spam the noise at once
|
||||
spawn(rand(1,10))
|
||||
playsound(src.loc, 'sound/effects/rockscrape.ogg', 40, 1)
|
||||
|
||||
var/turf/picked = pick(possible)
|
||||
if(src.loc.invisibility) src.loc.invisibility = 0
|
||||
if(src.loc.opacity) src.loc.opacity = 0
|
||||
|
||||
src.set_loc(picked)
|
||||
|
||||
spawn(5)
|
||||
picked.invisibility = 100
|
||||
picked.opacity = 1
|
||||
active = 0
|
||||
|
||||
//spawn(rand(100,200)) update() // raised delay
|
||||
|
||||
/obj/line_obj/whip
|
||||
name = "Whip"
|
||||
desc = ""
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
|
||||
/obj/whip_trg_dummy
|
||||
name = ""
|
||||
desc = ""
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
invisibility = 99
|
||||
|
||||
/obj/item/whip
|
||||
name = "whip"
|
||||
desc = "a sturdy whip."
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
inhand_image_icon = 'icons/mob/inhand/hand_weapons.dmi'
|
||||
icon_state = "whip"
|
||||
item_state = "c_tube"
|
||||
flags = FPRINT | EXTRADELAY | TABLEPASS | CONDUCT
|
||||
w_class = 2.0
|
||||
|
||||
afterattack(atom/target as mob|obj|turf, mob/user as mob)
|
||||
if(target == usr) return
|
||||
|
||||
if(get_dist(usr, target) > 5)
|
||||
boutput(usr, "<span style=\"color:red\">That is too far away!</span>")
|
||||
return
|
||||
|
||||
var/atom/target_r = target
|
||||
|
||||
if(isturf(target))
|
||||
target_r = new/obj/whip_trg_dummy(target)
|
||||
|
||||
playsound(src, 'sound/effects/snap.ogg', 40, 1)
|
||||
|
||||
var/list/affected = DrawLine(src.loc, target_r, /obj/line_obj/whip ,'icons/obj/projectiles.dmi',"WholeWhip",1,1,"HalfStartWhip","HalfEndWhip",OBJ_LAYER,1)
|
||||
|
||||
for(var/obj/O in affected)
|
||||
O.anchored = 1 //Proc wont spawn the right object type so lets do that here.
|
||||
O.name = "Whip"
|
||||
|
||||
var/turf/T = O.loc
|
||||
|
||||
if(locate(/obj/decal/stalagmite) in T)
|
||||
boutput(usr, "<span style=\"color:red\">You pull yourself to the stalagmite using the whip.</span>")
|
||||
usr.set_loc(T)
|
||||
else if(locate(/obj/decal/stalagtite) in T)
|
||||
boutput(usr, "<span style=\"color:red\">You pull yourself to the stalagtite using the whip.</span>")
|
||||
usr.set_loc(T)
|
||||
|
||||
spawn(2) pool(O)
|
||||
|
||||
if(istype(target_r, /obj/whip_trg_dummy)) qdel(target_r)
|
||||
|
||||
return
|
||||
|
||||
/obj/boulder_trap_boulder
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "boulder"
|
||||
density = 1
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
|
||||
New(var/atom/sloc)
|
||||
src.set_loc(sloc)
|
||||
spawn(0) go()
|
||||
|
||||
proc/go()
|
||||
while(!disposed)
|
||||
sleep(2)
|
||||
var/turf/next = get_step(src, SOUTH)
|
||||
if(prob(30))
|
||||
playsound(src.loc, 'sound/effects/rockscrape.ogg', 60, 1) // having some noise might be rad
|
||||
|
||||
if(!next || next.density)
|
||||
playsound(src.loc, 'sound/effects/Explosion2.ogg', 40, 1)
|
||||
new/obj/item/raw_material/rock(src.loc)
|
||||
new/obj/item/raw_material/rock(src.loc)
|
||||
new/obj/item/raw_material/rock(src.loc)
|
||||
new/obj/item/raw_material/rock(src.loc)
|
||||
spawn(0)
|
||||
dispose()
|
||||
return
|
||||
else
|
||||
src.set_loc(next)
|
||||
for(var/mob/living/carbon/C in next)
|
||||
C.TakeDamage("chest", 33, 0)
|
||||
if(hasvar(C, "weakened"))
|
||||
C:weakened += 5
|
||||
|
||||
|
||||
/obj/boulder_trap/respawning
|
||||
resets = 10
|
||||
|
||||
/obj/boulder_trap
|
||||
icon = 'icons/misc/mark.dmi'
|
||||
icon_state = "x4"
|
||||
invisibility = 101
|
||||
anchored = 1
|
||||
density = 0
|
||||
var/ready = 1
|
||||
var/resets = 0
|
||||
|
||||
HasEntered(atom/movable/AM as mob|obj)
|
||||
if(!ready) return
|
||||
if(ismob(AM))
|
||||
if(AM:client)
|
||||
ready = 0
|
||||
playsound(src, 'sound/effects/exlow.ogg', 40, 0)
|
||||
var/turf/spawnloc = get_step(get_step(get_step(src, NORTH), NORTH), NORTH)
|
||||
new/obj/boulder_trap_boulder(spawnloc)
|
||||
playsound(src.loc, 'sound/effects/rockscrape.ogg', 40, 1)
|
||||
|
||||
if(resets)
|
||||
spawn(resets) ready = 1
|
||||
|
||||
/obj/item/runetablet
|
||||
name = "Runic Tablet"
|
||||
desc = "A Tablet with several runes engraved upon its surface."
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "runetablet"
|
||||
|
||||
attack_self()
|
||||
|
||||
var/dat = ""
|
||||
dat += "<b>There's several runes inscribed here ...</b><BR><BR>"
|
||||
dat += "<A href='?src=\ref[src];north=1'>Touch the first rune</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];east=1'>Touch the second rune</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];south=1'>Touch the third rune</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];west=1'>Touch the fourth rune</A><BR>"
|
||||
|
||||
usr.machine = src
|
||||
usr << browse("[dat]", "window=rtab;size=400x300")
|
||||
onclose(usr, "rtab")
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
if (..(href, href_list))
|
||||
return
|
||||
|
||||
var/movedir = null
|
||||
|
||||
if (href_list["north"])
|
||||
boutput(usr, "<span style=\"color:blue\">The rune glows softly...</span>")
|
||||
movedir = NORTH
|
||||
playsound(src.loc, 'sound/machines/ArtifactEld1.ogg', 30, 1)
|
||||
playsound(src.loc, 'sound/effects/rockscrape.ogg', 40, 1)
|
||||
else if (href_list["east"])
|
||||
boutput(usr, "<span style=\"color:blue\">The rune glows softly...</span>")
|
||||
movedir = EAST
|
||||
playsound(src.loc, 'sound/machines/ArtifactEld1.ogg', 30, 1)
|
||||
playsound(src.loc, 'sound/effects/rockscrape.ogg', 40, 1)
|
||||
else if (href_list["south"])
|
||||
boutput(usr, "<span style=\"color:blue\">The rune glows softly...</span>")
|
||||
movedir = SOUTH
|
||||
playsound(src.loc, 'sound/machines/ArtifactEld1.ogg', 30, 1)
|
||||
playsound(src.loc, 'sound/effects/rockscrape.ogg', 40, 1)
|
||||
else if (href_list["west"])
|
||||
boutput(usr, "<span style=\"color:blue\">The rune glows softly...</span>")
|
||||
movedir = WEST
|
||||
playsound(src.loc, 'sound/machines/ArtifactEld1.ogg', 30, 1)
|
||||
playsound(src.loc, 'sound/effects/rockscrape.ogg', 40, 1)
|
||||
|
||||
if(movedir != null)
|
||||
for(var/obj/shifting_wall/sneaky/cave/C in orange(3, usr))
|
||||
C.do_move(movedir)
|
||||
|
||||
usr << browse(null, "window=rtab")
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
|
||||
// cogwerks - wall shift trigger
|
||||
|
||||
/obj/sneaky_wall_trigger
|
||||
icon = 'icons/misc/mark.dmi'
|
||||
icon_state = "ydn"
|
||||
invisibility = 101
|
||||
anchored = 1
|
||||
density = 0
|
||||
var/active = 0
|
||||
HasEntered(atom/movable/AM as mob|obj)
|
||||
if(active) return
|
||||
if(ismob(AM))
|
||||
if(AM:client)
|
||||
if(prob(75))
|
||||
active = 1
|
||||
for(var/obj/shifting_wall/sneaky/cave/C in orange(7, usr))
|
||||
C.update()
|
||||
spawn(100) active = 0
|
||||
|
||||
//////// cogwerks - reward item, based on the old cyborg suit
|
||||
|
||||
/obj/item/clothing/suit/armor/ancient
|
||||
name = "ancient armor"
|
||||
desc = "It belongs in a museum. Or maybe a laboratory. What the hell is this?"
|
||||
icon_state = "death"
|
||||
item_state = "death"
|
||||
// stole some shit from the welder's apron
|
||||
flags = FPRINT | TABLEPASS | SPACEWEAR
|
||||
body_parts_covered = TORSO|LEGS|ARMS
|
||||
fire_resist = T0C+5200
|
||||
permeability_coefficient = 0.02
|
||||
protective_temperature = 1000
|
||||
heat_transfer_coefficient = 0.02
|
||||
cant_self_remove = 1
|
||||
cant_other_remove = 1
|
||||
w_class = 3.0
|
||||
var/processing = 0
|
||||
|
||||
|
||||
// scare the everliving fuck out of the player when they equip it
|
||||
// what else should this thing do? idk yet. maybe some crazy hallucinations with an ancient blood reagent or something? something like the obsidian crown?
|
||||
// spookycoders are welcome to contribute to this thing
|
||||
|
||||
/obj/item/clothing/suit/armor/ancient/equipped(var/mob/user, var/slot)
|
||||
boutput(user, "<span style=\"color:blue\">The armor plates creak oddly as you put on [src].</span>")
|
||||
playsound(src.loc, 'sound/machines/ArtifactEld2.ogg', 30, 1)
|
||||
user.reagents.add_reagent("itching", 10)
|
||||
take_bleeding_damage(user, null, 0, DAMAGE_STAB, 0)
|
||||
bleed(user, 5, 5)
|
||||
src.desc = "This isn't coming off... oh god..."
|
||||
if (!src.processing)
|
||||
src.processing++
|
||||
if (!(src in processing_items))
|
||||
processing_items.Add(src)
|
||||
spawn(50)
|
||||
boutput(user, "<span style=\"color:blue\">The [src] feels like it's getting tighter. Ouch! Seems to have a lot of sharp edges inside.</span>")
|
||||
random_brute_damage(user, 5)
|
||||
take_bleeding_damage(user, null, 0, DAMAGE_STAB, 0)
|
||||
bleed(user, 5, 5)
|
||||
spawn(90)
|
||||
user.visible_message("<span style=\"color:red\"><b>[src] violently contracts around [user]!</B></span>")
|
||||
playsound(user.loc, 'sound/effects/bloody_stab.ogg', 50, 1, -1)
|
||||
random_brute_damage(user, 15)
|
||||
user.emote("scream")
|
||||
take_bleeding_damage(user, null, 0, DAMAGE_STAB, 0)
|
||||
bleed(user, 5, 1)
|
||||
spawn(50)
|
||||
user.visible_message("<span style=\"color:red\"><b>[src] digs into [user]!</B></span>")
|
||||
playsound(user.loc, 'sound/effects/bloody_stab.ogg', 50, 1, -1)
|
||||
random_brute_damage(user, 15)
|
||||
user.emote("scream")
|
||||
take_bleeding_damage(user, null, 0, DAMAGE_STAB, 0)
|
||||
bleed(user, 5, 5)
|
||||
spawn(50)
|
||||
var/mob/living/carbon/human/H = user
|
||||
playsound(user.loc, 'sound/effects/blobattack.ogg', 50, 1, -1)
|
||||
H.visible_message("<span style=\"color:red\"><b>[src] absorbs some of [user]'s skin!</b></span>")
|
||||
random_brute_damage(user, 30)
|
||||
H.emote("scream")
|
||||
if (!H.decomp_stage)
|
||||
H.bioHolder.AddEffect("eaten") //gross
|
||||
take_bleeding_damage(user, null, 0, DAMAGE_CUT, 0)
|
||||
bleed(user, 15, 5)
|
||||
user.emote("faint")
|
||||
user.reagents.add_reagent("ectoplasm", 50)
|
||||
return
|
||||
|
||||
|
||||
/obj/item/clothing/suit/armor/ancient/process()
|
||||
var/mob/living/host = src.loc
|
||||
if (!istype(host))
|
||||
processing_items.Remove(src)
|
||||
processing = 0
|
||||
return
|
||||
|
||||
if(prob(30) && istype(host,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/M = host
|
||||
M.bioHolder.age++
|
||||
if(prob(10)) boutput(M, "<span style=\"color:red\">You feel [pick("old", "strange", "frail", "peculiar", "odd")].</span>")
|
||||
if(prob(4)) M.emote("scream")
|
||||
return
|
||||
|
||||
///////////////////////////////
|
||||
@@ -0,0 +1,331 @@
|
||||
/obj/screen/ability/chaplain
|
||||
clicked(params)
|
||||
var/datum/targetable/chaplain/spell = owner
|
||||
if (!istype(spell))
|
||||
return
|
||||
if (!spell.holder)
|
||||
return
|
||||
if (!isturf(usr.loc))
|
||||
return
|
||||
if (spell.targeted)
|
||||
if (world.time < spell.last_cast)
|
||||
return
|
||||
usr:targeting_spell = owner
|
||||
usr.update_cursor()
|
||||
else
|
||||
spawn
|
||||
spell.handleCast()
|
||||
|
||||
/datum/abilityHolder/religious
|
||||
usesPoints = 0
|
||||
regenRate = 0
|
||||
tabName = "Miracles"
|
||||
var/god_fullname = null
|
||||
var/god_name = null
|
||||
var/god_epithet = null
|
||||
var/god_domain = null
|
||||
var/atheist = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
src.addAbility(/datum/targetable/chaplain/chooseReligion)
|
||||
|
||||
|
||||
/datum/targetable/chaplain
|
||||
name = "OOPS SOMETHING BROKE"
|
||||
desc = "for real if you can see this tell a coder"
|
||||
icon = 'icons/mob/wraith_ui.dmi'
|
||||
icon_state = "template"
|
||||
cooldown = 0
|
||||
last_cast = 0
|
||||
targeted = 1
|
||||
target_anything = 1
|
||||
var/disabled = 0
|
||||
|
||||
New()
|
||||
var/obj/screen/ability/chaplain/B = new /obj/screen/ability/chaplain(null)
|
||||
B.icon = src.icon
|
||||
B.icon_state = src.icon_state
|
||||
B.owner = src
|
||||
B.name = src.name
|
||||
B.desc = src.desc
|
||||
src.object = B
|
||||
|
||||
proc/incapacitationCheck()
|
||||
var/mob/living/M = holder.owner
|
||||
return M.restrained() || M.stat || M.paralysis || M.stunned || M.weakened
|
||||
|
||||
castcheck()
|
||||
if (incapacitationCheck())
|
||||
boutput(holder.owner, "<span style=\"color:red\">You can't do that while you're incapacitated.</span>")
|
||||
return 0
|
||||
if (disabled)
|
||||
boutput(holder.owner, "<span style=\"color:red\">You cannot use that ability at this time.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
cast(atom/target)
|
||||
. = ..()
|
||||
actions.interrupt(holder.owner, INTERRUPT_ACT)
|
||||
|
||||
doCooldown()
|
||||
if (!holder)
|
||||
return
|
||||
last_cast = world.time + cooldown
|
||||
holder.updateButtons()
|
||||
spawn(cooldown + 5)
|
||||
holder.updateButtons()
|
||||
|
||||
/proc/assemble_name(var/datum/abilityHolder/religious/religiousHolder)
|
||||
var/list/god_adjective = strings("gods.txt", "adjective")
|
||||
var/list/god_noun = strings("gods.txt", "noun")
|
||||
var/list/namebegin = strings("gods.txt", "namebegin")
|
||||
var/list/nameend = strings("gods.txt", "nameend")
|
||||
religiousHolder.god_fullname = ""
|
||||
if (religiousHolder.atheist == 1) // dweeb detected
|
||||
religiousHolder.god_name = religiousHolder.owner.real_name
|
||||
religiousHolder.god_epithet = "Smug Bastard"
|
||||
else
|
||||
religiousHolder.god_name = "[pick(namebegin)][pick(nameend)]"
|
||||
religiousHolder.god_epithet = ""
|
||||
religiousHolder.god_epithet += "[capitalize(pick(god_adjective))] "
|
||||
religiousHolder.god_epithet += "[capitalize(pick(god_noun))]"
|
||||
religiousHolder.god_fullname += "[religiousHolder.god_name] the [religiousHolder.god_epithet], "
|
||||
if (religiousHolder.atheist == 1)
|
||||
if (religiousHolder.owner.gender == MALE)
|
||||
religiousHolder.god_fullname += "'God'"
|
||||
else
|
||||
religiousHolder.god_fullname += "'Goddess'"
|
||||
else
|
||||
religiousHolder.god_fullname += pick("God", "Goddess")
|
||||
religiousHolder.god_fullname += " of [religiousHolder.god_domain]"
|
||||
|
||||
boutput(religiousHolder.owner, "<span style=\"color:blue\">You are now a priest of [religiousHolder.god_fullname]!</span>")
|
||||
return
|
||||
|
||||
/datum/targetable/chaplain/chooseReligion
|
||||
name = "Choose Religion"
|
||||
desc = "What flavor of crazy street preacher do you feel like being today?"
|
||||
cooldown = 0
|
||||
targeted = 0
|
||||
target_anything = 0
|
||||
icon_state = "absorbcorpse"
|
||||
var/static/list/domains = list("Atheism" = 1, "Order" = 2, "Chaos" = 3, "Light" = 4, "Darkness" = 5, "Life" = 6, "Death" = 7, "Machinery" = 8, "Nature" = 9, "Surprise me!" = 10)
|
||||
//var/static/list/domainsForNerds = list("Atheism" = 1, "Order" = 2, "Chaos" = 3, "Light" = 4, "Darkness" = 5, "Life" = 6, "Death" = 7, "Machinery" = 8, "Nature" = 9, "Sol Invictus" = 10, "the Void" = 11, "Surprise me!" = 12)
|
||||
|
||||
cast()
|
||||
var/datum/abilityHolder/religious/religiousHolder = src.holder
|
||||
if (..())
|
||||
return 1
|
||||
var/domainChoice = input("Which domain?", "Domain", "Surprise me!") in domains
|
||||
|
||||
if (domainChoice == "Surprise me!")
|
||||
domainChoice = rand(1, 9)
|
||||
else
|
||||
domainChoice = domains[domainChoice]
|
||||
switch (domainChoice)
|
||||
if (1)
|
||||
religiousHolder.atheist = 1
|
||||
religiousHolder.god_domain = "Atheism"
|
||||
assemble_name(religiousHolder)
|
||||
if (2)
|
||||
religiousHolder.god_domain = "Order"
|
||||
assemble_name(religiousHolder)
|
||||
if (3)
|
||||
religiousHolder.god_domain = "Chaos"
|
||||
assemble_name(religiousHolder)
|
||||
if (4)
|
||||
religiousHolder.god_domain = "Light"
|
||||
assemble_name(religiousHolder)
|
||||
if (5)
|
||||
religiousHolder.god_domain = "Darkness"
|
||||
assemble_name(religiousHolder)
|
||||
if (6)
|
||||
religiousHolder.god_domain = "Life"
|
||||
assemble_name(religiousHolder)
|
||||
if (7)
|
||||
religiousHolder.god_domain = "Death"
|
||||
assemble_name(religiousHolder)
|
||||
if (8)
|
||||
religiousHolder.god_domain = "Machinery"
|
||||
usr.robot_talk_understand = 1
|
||||
religiousHolder.addAbility(/datum/targetable/chaplain/chaplainDemag)
|
||||
religiousHolder.addAbility(/datum/targetable/chaplain/sootheMachineSpirits)
|
||||
assemble_name(religiousHolder)
|
||||
if (9)
|
||||
religiousHolder.god_domain = "Nature"
|
||||
religiousHolder.addAbility(/datum/targetable/chaplain/blessWeed)
|
||||
religiousHolder.addAbility(/datum/targetable/chaplain/fortifySeed)
|
||||
assemble_name(religiousHolder)
|
||||
|
||||
religiousHolder.removeAbility(/datum/targetable/chaplain/chooseReligion)
|
||||
return
|
||||
|
||||
//*************** ATHEISM *****************
|
||||
|
||||
//100% worthless gimmick shit, free fedora, supersmug emote, immunity to fedora gib?
|
||||
|
||||
//*************** ORDER *****************
|
||||
|
||||
//Clean everything in an aoe
|
||||
//??? move demag here, give machinery a repair power???
|
||||
|
||||
//*************** CHAOS *****************
|
||||
|
||||
//Xom bullshit, Pandemonium, etc
|
||||
|
||||
//*************** LIGHT *****************
|
||||
|
||||
//Flash immunity
|
||||
//Photokinesis
|
||||
//Glowy
|
||||
|
||||
//*************** DARKNESS *****************
|
||||
|
||||
//Erebokinesis
|
||||
//Ignore all darkness
|
||||
|
||||
//*************** LIFE *****************
|
||||
|
||||
//stabilize someone in shock/heart attack, long cd
|
||||
//self-regen/heal
|
||||
|
||||
//*************** DEATH *****************
|
||||
|
||||
//passively sense when deaths occur
|
||||
//????
|
||||
//Animate meatcubes maybe???
|
||||
|
||||
//*************** NATURE *****************
|
||||
|
||||
|
||||
/datum/targetable/chaplain/blessWeed
|
||||
name = "Bless Weed"
|
||||
desc = "Make some herb into sacred herbs."
|
||||
cooldown = 150
|
||||
targeted = 1
|
||||
target_anything = 1
|
||||
icon_state = "absorbcorpse"
|
||||
|
||||
cast(atom/T)
|
||||
var/datum/abilityHolder/religious/religiousHolder = src.holder
|
||||
if (..())
|
||||
return 1
|
||||
|
||||
if (!istype(T, /obj/item/plant/herb/cannabis))
|
||||
boutput(holder.owner, "<span style=\"color:red\">That ain't weed, you dingus!</span>")
|
||||
return 1
|
||||
|
||||
if (istype(T,/obj/item/plant/herb/cannabis/black))
|
||||
boutput(holder.owner, "<span style=\"color:blue\">You purify the toxins in [T]!</span>")
|
||||
new/obj/item/plant/herb/cannabis/spawnable(T.loc)
|
||||
qdel(T)
|
||||
return 0
|
||||
if (istype(T, /obj/item/plant/herb/cannabis/mega))
|
||||
boutput(holder.owner, "<span style=\"color:blue\">You bestow [religiousHolder.god_name]'s blessing upon [T]!</span>")
|
||||
new/obj/item/plant/herb/cannabis/omega/spawnable(T.loc)
|
||||
qdel(T)
|
||||
return 0
|
||||
if (istype(T, /obj/item/plant/herb/cannabis/white))
|
||||
boutput(holder.owner, "<span style=\"color:red\">No need to bless what's already blessed.</span>")
|
||||
return 1
|
||||
if (istype(T, /obj/item/plant/herb/cannabis/omega))
|
||||
boutput(holder.owner, "<span style=\"color:red\">Look, this shit could glue [religiousHolder.god_name] to the couch already. Making it any more dank might cause some sort of weedularity.</span>")
|
||||
return 1
|
||||
else
|
||||
boutput(holder.owner, "<span style=\"color:blue\">You bestow [religiousHolder.god_name]'s blessing upon [T]!</span>")
|
||||
new/obj/item/plant/herb/cannabis/white/spawnable(T.loc)
|
||||
qdel(T)
|
||||
return 0
|
||||
|
||||
/datum/targetable/chaplain/fortifySeed
|
||||
name = "Fortify Seed"
|
||||
desc = "Blesses a seed, giving small, random improvements to all of its traits."
|
||||
cooldown = 450
|
||||
targeted = 1
|
||||
target_anything = 1
|
||||
icon_state = "absorbcorpse"
|
||||
|
||||
proc/fortify(var/obj/item/seed/S)
|
||||
var/datum/plantgenes/DNA = S.plantgenes
|
||||
DNA.growtime -= rand(0,8)
|
||||
DNA.harvtime -= rand(0,5)
|
||||
DNA.cropsize += rand(0,4)
|
||||
DNA.harvests += rand(0,1)
|
||||
DNA.potency += rand(0,6)
|
||||
DNA.endurance += rand(0,3)
|
||||
|
||||
cast(atom/T)
|
||||
if (..())
|
||||
return 1
|
||||
|
||||
if (istype(T, /obj/item/seed))
|
||||
fortify(T)
|
||||
return 0
|
||||
else
|
||||
boutput(holder.owner, "<span style=\"color:red\">This only works on seeds!</span>")
|
||||
return 1
|
||||
|
||||
|
||||
//*************** MACHINES *****************
|
||||
|
||||
/datum/targetable/chaplain/chaplainDemag
|
||||
name = "Demag"
|
||||
desc = "Repairs damage to sensitive electronics due to electromagnetic scrambling. Note: cyborg circuitry is too complex for this to work."
|
||||
cooldown = 1800
|
||||
targeted = 1
|
||||
target_anything = 1
|
||||
icon_state = "absorbcorpse"
|
||||
|
||||
cast(atom/T)
|
||||
if (..())
|
||||
return 1
|
||||
|
||||
if (!istype(T, /obj))
|
||||
boutput(holder.owner, "<span style=\"color:red\">You cannot try to repair this!</span>")
|
||||
return 1
|
||||
|
||||
var/obj/O = T
|
||||
// go to jail, do not pass src, do not collect pushed messages
|
||||
if (O.demag())
|
||||
boutput(usr, "<span style=\"color:blue\">You repair the damage to [O].</span>")
|
||||
return 0
|
||||
else
|
||||
boutput(usr, "<span style=\"color:red\">It doesn't seem like this needs fixing.</span>")
|
||||
return 1
|
||||
|
||||
/datum/targetable/chaplain/sootheMachineSpirits
|
||||
name = "Soothe Machine Spirits"
|
||||
desc = "NT-model thermoelectric engines tend to be...tempermental. You're able to calm them down better than most."
|
||||
cooldown = 900
|
||||
targeted = 1
|
||||
target_anything = 1
|
||||
max_range = 1
|
||||
icon_state = "absorbcorpse"
|
||||
|
||||
cast(atom/T)
|
||||
if (..())
|
||||
return 1
|
||||
|
||||
if (get_dist(usr, T) > src.max_range)
|
||||
boutput(usr, __red("[T] is too far away."))
|
||||
return 1
|
||||
|
||||
if (!istype(T, /obj/machinery/power/generatorTemp))
|
||||
boutput(usr, "<span style=\"color:red\">You can only use this on the engine's core!</span>")
|
||||
return 1
|
||||
|
||||
var/obj/machinery/power/generatorTemp/E = T
|
||||
usr.visible_message("<span style=\"color:blue\">[usr] places a hand on the [E] and mumbles something.</span>")
|
||||
playsound(usr.loc, "sound/effects/heavenly.ogg", 50, 1)
|
||||
spawn(30)
|
||||
E.grump = 0
|
||||
E.visible_message("<span style=\"color:blue\"><b>The [E] suddenly seems very chill!</b></span>")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
//*************** SOL INVICTUS? *****************
|
||||
|
||||
|
||||
//*************** THE VOID? *****************
|
||||
@@ -0,0 +1,250 @@
|
||||
/obj/machinery/fogmachine
|
||||
name = "FogMachine-3000"
|
||||
desc = "The FogMachine-3000 is guaranteed to suit all of your fog-filled needs. Just put the FogMaster FogFluid into the FogMachine-3000 Chemical Funnel Duct and then turn the FogMachine-3000. The FogMachine-3000 will cease to pump fog when the fluid resevoir is empty."
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "fogmachine0"
|
||||
|
||||
|
||||
var/on = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
var/datum/reagents/R = new/datum/reagents(1000)
|
||||
reagents = R
|
||||
R.my_atom = src
|
||||
return
|
||||
|
||||
process()
|
||||
if(reagents.has_reagent("radium"))
|
||||
src.reagents.clear_reagents()
|
||||
src.visible_message("<span style=\"color:red\">The <B>[src]</B> makes an odd sound, and releases a puff of green steam.</span>")
|
||||
|
||||
if(on == 1)
|
||||
if(reagents.reagent_list.len < 1 || reagents.total_volume < 1)
|
||||
on = 0
|
||||
icon_state = "fogmachine0"
|
||||
|
||||
src.visible_message("<span style=\"color:red\">The <B>[src]</B> splutters to a halt.</span>")
|
||||
playsound(src, 'sound/machines/ding.ogg', 50, 1)
|
||||
else
|
||||
spawn(50)
|
||||
var/datum/chemical_reaction/smoke/S = new
|
||||
S.on_reaction(reagents)
|
||||
reagents.total_volume -= 5
|
||||
if (reagents.total_volume < 5)
|
||||
reagents.total_volume = 0
|
||||
reagents.clear_reagents()
|
||||
return
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
|
||||
attackby(var/obj/item/reagent_containers/C as obj, var/mob/user as mob)
|
||||
if(!istype(C, /obj/item/reagent_containers))
|
||||
return
|
||||
if(istype(C, /obj/item/reagent_containers/glass))
|
||||
if(C.reagents.reagent_list.len < 1)
|
||||
boutput(user, "[C] is empty.")
|
||||
return
|
||||
else
|
||||
boutput(user, "You pour the contents of [C] into the funnel.")
|
||||
|
||||
|
||||
for(var/current_id in C.reagents.reagent_list)
|
||||
var/datum/reagent/current_reagent = C.reagents.reagent_list[current_id]
|
||||
|
||||
if(current_reagent.id == "radium")
|
||||
C.reagents.del_reagent("radium")
|
||||
boutput(user, "The [src] vapourizes the radium.")
|
||||
else
|
||||
reagents.add_reagent(current_id, 10, null, null, 1)
|
||||
|
||||
C.reagents.clear_reagents()
|
||||
playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
|
||||
return
|
||||
else
|
||||
boutput(user, "You put [C] into the funnel.")
|
||||
|
||||
for(var/current_id in C.reagents.reagent_list)
|
||||
var/datum/reagent/current_reagent = C.reagents.reagent_list[current_id]
|
||||
|
||||
if(current_reagent.id == "radium")
|
||||
C.reagents.del_reagent("radium")
|
||||
boutput(user, "The [src] vapourizes the radium.")
|
||||
else
|
||||
reagents.add_reagent(current_id, 10, null, null, 1)
|
||||
|
||||
qdel(C)
|
||||
playsound(src, 'sound/effects/pop.ogg', 50, 1)
|
||||
return
|
||||
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if(on == 0)
|
||||
on = 1
|
||||
boutput(user, "<span style=\"color:blue\">You flip the switch on the FogMachine-3000 to the On position.</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
return
|
||||
if(on == 1)
|
||||
on = 0
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">You flip the switch on the FogMachine-3000 to the Off position.</span>")
|
||||
return
|
||||
|
||||
|
||||
|
||||
/proc/honk(var/string)
|
||||
var/modded = ""
|
||||
var/list/text_tokens = dd_text2list(string, " ")
|
||||
for(var/token in text_tokens)
|
||||
modded += "HONK "
|
||||
modded += "HONK!"
|
||||
if(prob(15))
|
||||
modded += " - HOOOOOONNNKKK!!!"
|
||||
|
||||
return modded
|
||||
|
||||
/obj/machinery/bathtub
|
||||
name = "bathtub"
|
||||
desc = "Now, that looks cosy!"
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "bathtub"
|
||||
flags = OPENCONTAINER
|
||||
var/static/image/fluid_icon = image("icon" = 'icons/obj/stationobjs.dmi', "icon_state" = "fluid_bathtub")
|
||||
var/static/image/fluid_icon_feet = image("icon" = 'icons/obj/stationobjs.dmi', "icon_state" = "fluid_bathtub_feet")
|
||||
var/static/image/bath_edge = image("icon" = 'icons/obj/stationobjs.dmi', "icon_state" = "bath_edge", "layer" = FLOAT_LAYER)
|
||||
var/mob/living/carbon/human/myuser = null
|
||||
|
||||
New()
|
||||
..()
|
||||
var/datum/reagents/R = new/datum/reagents(500)
|
||||
reagents = R
|
||||
R.my_atom = src
|
||||
return
|
||||
|
||||
|
||||
get_desc(dist, mob/user)
|
||||
if (dist > 2)
|
||||
return
|
||||
if (!reagents)
|
||||
return
|
||||
. += "<br><span style=\"color:blue\">[reagents.get_description(user,RC_FULLNESS|RC_VISIBLE|RC_SPECTRO)]</span>"
|
||||
return
|
||||
|
||||
on_reagent_change()
|
||||
src.overlays = null
|
||||
|
||||
if(reagents.total_volume)
|
||||
icon_state = "bathtub"
|
||||
|
||||
src.overlays += fluid_icon
|
||||
|
||||
if(src.myuser)
|
||||
src.overlays += src.myuser
|
||||
if(reagents.total_volume)
|
||||
src.overlays += fluid_icon_feet
|
||||
|
||||
src.overlays += bath_edge
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if (src.myuser)
|
||||
boutput(user, "<span style=\"color:red\">You pull [src.myuser] out of the bath!</span>")
|
||||
src.eject_user()
|
||||
else
|
||||
boutput(user, "<span style=\"color:blue\">You pull the plug.</span>")
|
||||
src.reagents.clear_reagents()
|
||||
src.on_reagent_change()
|
||||
var/count = 0
|
||||
for (var/obj/O in src)
|
||||
count++
|
||||
qdel(O)
|
||||
if (count > 0)
|
||||
boutput(user, "<span style=\"color:red\">...and flush something down the drain. Damn!</span>")
|
||||
return
|
||||
|
||||
proc/eject_user()
|
||||
if (src.myuser)
|
||||
src.myuser.pixel_y = 0
|
||||
src.myuser.set_loc(get_turf(src))
|
||||
src.myuser = null
|
||||
src.on_reagent_change()
|
||||
|
||||
for (var/obj/O in src)
|
||||
O.set_loc(get_turf(src))
|
||||
return
|
||||
|
||||
relaymove(mob/user as mob, dir)
|
||||
src.eject_user()
|
||||
boutput(user, "<span style=\"color:blue\">You get out of the bath.</span>")
|
||||
|
||||
|
||||
process()
|
||||
if (src.myuser)
|
||||
if(src.myuser.loc != src)
|
||||
src.myuser.pixel_y = 0
|
||||
src.myuser = null
|
||||
src.overlays = null
|
||||
on_reagent_change()
|
||||
|
||||
return
|
||||
if(src.reagents.total_volume > 5)
|
||||
reagents.reaction(src.myuser, TOUCH)
|
||||
src.reagents.trans_to(src.myuser,5,1)
|
||||
else
|
||||
src.reagents.clear_reagents()
|
||||
on_reagent_change()
|
||||
|
||||
return
|
||||
|
||||
MouseDrop_T(mob/living/carbon/human/target, mob/user)
|
||||
if (src.myuser || !istype(target) || target.buckled || LinkBlocked(target.loc,src.loc) || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.paralysis || user.stunned || user.weakened || user.stat || istype(user, /mob/living/silicon/ai))
|
||||
return
|
||||
|
||||
var/msg
|
||||
|
||||
if(target == user && !user.stat) // if drop self, then climbed in
|
||||
msg = "[user.name] climbs into [src]."
|
||||
boutput(user, "<span style=\"color:blue\">You climb into [src].</span>")
|
||||
|
||||
else if(target != user && !user.restrained())
|
||||
msg = "[user.name] push [target.name] into the [src]!"
|
||||
boutput(user, "<span style=\"color:blue\">You push [target.name] into the [src]!</span>")
|
||||
|
||||
else
|
||||
return
|
||||
|
||||
target.set_loc(src)
|
||||
src.myuser = target
|
||||
src.myuser.pixel_y += 5
|
||||
src.on_reagent_change()
|
||||
|
||||
for (var/mob/C in viewers(src))
|
||||
if(C == user)
|
||||
continue
|
||||
C.show_message(msg, 3)
|
||||
|
||||
|
||||
return
|
||||
|
||||
is_open_container()
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/head/apprentice
|
||||
proc/fantasia()
|
||||
if(ticker && ticker.mode && istype(ticker.mode, /datum/game_mode/wizard))
|
||||
for (var/obj/item/mop/M in orange(5,src))
|
||||
src.visible_message("<span style=\"color:red\">[src] begins to twitch and move!</span>")
|
||||
var/moveto = locate(M.x + rand(-1,1),M.y + rand(-1, 1),src.z)
|
||||
//make the mops move
|
||||
if (istype(moveto, /turf/simulated/floor) || istype(moveto, /turf/simulated/shuttle/floor) || istype(moveto, /turf/simulated/aprilfools/floor) || istype(moveto, /turf/unsimulated/floor) || istype(moveto, /turf/unsimulated/aprilfools)) step_towards(M, moveto)
|
||||
spawn(50)
|
||||
src.visible_message("<span style=\"color:blue\">Thankfully, [src] settles down.</span>")
|
||||
else
|
||||
for (var/obj/item/mop/M in orange(5,src))
|
||||
src.visible_message("<span style=\"color:red\">[src] begins to twitch and mov- oh. No. No it doesn't.</span>")
|
||||
|
||||
/obj/item/clothing/head/apprentice/equipped(var/mob/user, var/slot)
|
||||
boutput(user, "<span style=\"color:blue\">Your head tingles with magic! Or asbestos. Probably asbestos.</span>")
|
||||
src.fantasia()
|
||||
..()
|
||||
@@ -0,0 +1,629 @@
|
||||
|
||||
/obj/item/electronics/
|
||||
name = "electronic thing"
|
||||
icon = 'icons/obj/electronics.dmi'
|
||||
inhand_image_icon = 'icons/mob/inhand/hand_tools.dmi'
|
||||
force = 5
|
||||
damtype = "brute"
|
||||
throwforce = 5
|
||||
w_class = 1.0
|
||||
pressure_resistance = 10
|
||||
item_state = "electronic"
|
||||
flags = FPRINT | TABLEPASS | CONDUCT
|
||||
|
||||
/obj/item/electronics/New()
|
||||
desc = "A [src.name] used in electronic projects."
|
||||
return
|
||||
|
||||
/obj/item/electronics/proc/randompix()
|
||||
src.pixel_x = rand(8, 12)
|
||||
src.pixel_y = rand(8, 12)
|
||||
return
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
/obj/item/electronics/battery
|
||||
name = "battery"
|
||||
icon_state = "batt1"
|
||||
module_research = list("electronics" = 2)
|
||||
|
||||
/obj/item/electronics/battery/New()
|
||||
src.icon_state = pick("batt1", "batt2", "batt3")
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////up
|
||||
/obj/item/electronics/board
|
||||
name = "board"
|
||||
icon_state = "board1"
|
||||
module_research = list("electronics" = 2)
|
||||
|
||||
/obj/item/electronics/board/New()
|
||||
src.icon_state = pick("board1", "board2", "board3")
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////
|
||||
/obj/item/electronics/fuse
|
||||
name = "fuse"
|
||||
icon_state = "fuse1"
|
||||
module_research = list("electronics" = 2)
|
||||
|
||||
/obj/item/electronics/fuse/New()
|
||||
src.icon_state = pick("fuse1", "fuse2", "fuse3")
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////
|
||||
/obj/item/electronics/switc
|
||||
name = "switch"
|
||||
icon_state = "switch1"
|
||||
module_research = list("electronics" = 2)
|
||||
|
||||
/obj/item/electronics/switc/New()
|
||||
src.icon_state = pick("switch1", "switch2", "switch3")
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////up
|
||||
/obj/item/electronics/keypad
|
||||
name = "keypad"
|
||||
icon_state = "keypad1"
|
||||
module_research = list("electronics" = 2)
|
||||
/obj/item/electronics/keypad/New()
|
||||
src.icon_state = pick("keypad1", "keypad2", "keypad3")
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////up
|
||||
/obj/item/electronics/screen
|
||||
name = "screen"
|
||||
icon_state = "screen1"
|
||||
module_research = list("electronics" = 2)
|
||||
/obj/item/electronics/screen/New()
|
||||
src.icon_state = pick("screen1", "screen2", "screen3")
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////
|
||||
/obj/item/electronics/capacitor
|
||||
name = "capacitor"
|
||||
icon_state = "capacitor1"
|
||||
module_research = list("electronics" = 2)
|
||||
/obj/item/electronics/capacitor/New()
|
||||
src.icon_state = pick("capacitor1", "capacitor2", "capacitor3")
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////up
|
||||
/obj/item/electronics/buzzer
|
||||
name = "buzzer"
|
||||
icon_state = "buzzer"
|
||||
module_research = list("electronics" = 2)
|
||||
/obj/item/electronics/buzzer/New()
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////
|
||||
/obj/item/electronics/resistor
|
||||
name = "resistor"
|
||||
icon_state = "resistor1"
|
||||
module_research = list("electronics" = 2)
|
||||
/obj/item/electronics/resistor/New()
|
||||
src.icon_state = pick("resistor1", "resistor2")
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////
|
||||
/obj/item/electronics/bulb
|
||||
name = "bulb"
|
||||
icon_state = "bulb1"
|
||||
module_research = list("electronics" = 2)
|
||||
/obj/item/electronics/bulb/New()
|
||||
src.icon_state = pick("bulb1", "bulb2")
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////
|
||||
/obj/item/electronics/relay
|
||||
name = "relay"
|
||||
icon_state = "relay1"
|
||||
module_research = list("electronics" = 2)
|
||||
/obj/item/electronics/bulb/New()
|
||||
src.icon_state = pick("relay1", "relay2")
|
||||
randompix()
|
||||
..()
|
||||
////////////////////////////////////////////////////////////////no
|
||||
/obj/item/electronics/frame
|
||||
name = "frame"
|
||||
icon_state = "frame"
|
||||
var/store_type = null
|
||||
var/secured = 0
|
||||
var/viewstat = 0
|
||||
var/dir_needed = 0
|
||||
//var/list/parts = new/list()
|
||||
var/list/needed_parts = new/list()
|
||||
module_research = list("electronics" = 3, "engineering" = 1)
|
||||
|
||||
/obj/item/electronics/frame/verb/rotate()
|
||||
set src in view(1)
|
||||
if (!istype(usr, /mob/living))
|
||||
return
|
||||
src.dir = turn(src.dir, 90)
|
||||
|
||||
/obj/item/electronics/frame/attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(istype(W,/obj/item/electronics/))
|
||||
var/obj/item/electronics/E = W
|
||||
if(!(istype(E,/obj/item/electronics/disk)||istype(E,/obj/item/electronics/scanner)||istype(E,/obj/item/electronics/soldering)||istype(E,/obj/item/electronics/frame)))
|
||||
E.set_loc(src)
|
||||
user.u_equip(E)
|
||||
//parts.Add(E)
|
||||
boutput(user, "<span style=\"color:blue\">You add the [E.name] to the [src].</span>")
|
||||
return
|
||||
else if(istype(E,/obj/item/electronics/soldering))
|
||||
if(!secured)
|
||||
secured = 1
|
||||
viewstat = 1
|
||||
boutput(user, "<span style=\"color:blue\">You secure the [src].</span>")
|
||||
else if(secured == 1)
|
||||
secured = 0
|
||||
viewstat = 0
|
||||
boutput(user, "<span style=\"color:blue\">You unsecure the [src].</span>")
|
||||
else if(secured == 2)
|
||||
secured = 0
|
||||
boutput(user, "<span style=\"color:red\">You deploy the [src]!</span>")
|
||||
logTheThing("station", user, null, "deploys a [src.name] in [user.loc.loc] ([showCoords(src.x, src.y, src.z)])")
|
||||
deploy()
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/electronics/frame/MouseDrop_T(atom/movable/O as obj, mob/user as mob)
|
||||
if(!iscarbon(user) || user.stat || user.weakened || user.paralysis)
|
||||
return
|
||||
|
||||
if(get_dist(user, src) > 1)
|
||||
return
|
||||
|
||||
var/list/bad_types = list(/obj/item/electronics/disk, /obj/item/electronics/scanner, /obj/item/electronics/soldering, /obj/item/electronics/frame)
|
||||
if(!istype(O, /obj/item/electronics) || (O.type in bad_types))
|
||||
boutput(user, "<span style=\"color:red\">That is not a valid component!</span>")
|
||||
return
|
||||
|
||||
if (!src.secured)
|
||||
var/turf/source_turf = get_turf(O)
|
||||
if(!source_turf) return
|
||||
user.visible_message("<span style=\"color:blue\">[user] begins quickly adding components to [src]!</span>", "<span style=\"color:blue\">You begin to quickly add components to [src]!</span>")
|
||||
var/staystill = user.loc
|
||||
|
||||
for(var/obj/item/electronics/I in source_turf)
|
||||
if(I.type in bad_types) continue
|
||||
I.set_loc(src)
|
||||
//parts.Add(I)
|
||||
sleep(3)
|
||||
if (user.loc != staystill) break
|
||||
|
||||
boutput(user, "<span style=\"color:blue\">You finish adding components to [src]!</span>")
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">The board is already secured!</span>")
|
||||
return
|
||||
|
||||
/obj/item/electronics/frame/attack_self(mob/user as mob)
|
||||
src.add_fingerprint(user)
|
||||
var/dat
|
||||
dat = "Parts:<BR>"
|
||||
|
||||
switch(viewstat)
|
||||
|
||||
if(0)
|
||||
for(var/obj/item/electronics/P in src.contents)
|
||||
dat += "[P.name]: <A href='?src=\ref[src];op=\ref[P];tp=move'>Remove</A><BR>"
|
||||
|
||||
user.machine = src
|
||||
user << browse("<HEAD><TITLE>Frame</TITLE></HEAD><TT>[dat]</TT>", "window=fkit")
|
||||
onclose(user, "fkit")
|
||||
|
||||
if(1)
|
||||
var/check = parts_check()
|
||||
if(!check)
|
||||
boutput(user, "<span style=\"color:red\">Incomplete Object, unable to finish!</span>")
|
||||
return
|
||||
if(dir_needed)
|
||||
var/dirr = input("Select A Direction!", "UDLR", null, null) in list("Up","Down","Left","Right")
|
||||
switch(dirr)
|
||||
if("Up")
|
||||
src.dir = 1
|
||||
if("Down")
|
||||
src.dir = 2
|
||||
if("Left")
|
||||
src.dir = 8
|
||||
if("Right")
|
||||
src.dir = 4
|
||||
boutput(user, "Ready to deploy!")
|
||||
switch(alert("Ready to deploy?",,"Yes","No"))
|
||||
if("Yes")
|
||||
boutput(user, "<span style=\"color:red\">Place box and solder to deploy!</span>")
|
||||
viewstat = 2
|
||||
secured = 2
|
||||
icon_state = "dbox"
|
||||
if("No")
|
||||
return
|
||||
else
|
||||
return
|
||||
|
||||
/obj/item/electronics/frame/Topic(href, href_list)
|
||||
if (usr.stat)
|
||||
return
|
||||
if ((usr.contents.Find(src) || usr.contents.Find(src.master) || in_range(src, usr) && istype(src.loc, /turf)))
|
||||
usr.machine = src
|
||||
|
||||
switch(href_list["tp"])
|
||||
if("move")
|
||||
if(href_list["op"])
|
||||
var/obj/Z = locate(href_list["op"])
|
||||
var/turf/T = src.loc
|
||||
if (ismob(T))
|
||||
T = T.loc
|
||||
Z.set_loc(T)
|
||||
//parts.Remove(Z)
|
||||
|
||||
|
||||
updateDialog()
|
||||
else
|
||||
usr << browse(null, "window=fkit")
|
||||
usr.machine = null
|
||||
return
|
||||
|
||||
/obj/item/electronics/frame/proc/deploy()
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/O = new store_type(T)
|
||||
O.dir = src.dir
|
||||
O.mats = "Built"
|
||||
qdel(src)
|
||||
|
||||
return
|
||||
|
||||
/obj/item/electronics/frame/proc/parts_check()
|
||||
// if(src.contents.len != needed_parts.len)
|
||||
// return 0
|
||||
|
||||
//for(var/tracker = 1, tracker <= parts:len, tracker ++)
|
||||
var/list/checkList = needed_parts.Copy()
|
||||
for(var/tracker = 1, tracker <= src.contents:len, tracker ++)
|
||||
var/partID
|
||||
//var/obj/T = parts[tracker]
|
||||
var/obj/T = src.contents[tracker]
|
||||
if(istype(T,/obj/item/electronics/battery))
|
||||
partID = "battery"
|
||||
else if(istype(T,/obj/item/electronics/fuse))
|
||||
partID = "fuse"
|
||||
else if(istype(T,/obj/item/electronics/switc))
|
||||
partID = "switch"
|
||||
else if(istype(T,/obj/item/electronics/capacitor))
|
||||
partID = "capacitor"
|
||||
else if(istype(T,/obj/item/electronics/resistor))
|
||||
partID = "resistor"
|
||||
else if(istype(T,/obj/item/electronics/bulb))
|
||||
partID = "bulb"
|
||||
else if(istype(T,/obj/item/electronics/relay))
|
||||
partID = "relay"
|
||||
else if(istype(T,/obj/item/electronics/board))
|
||||
partID = "board"
|
||||
else if(istype(T,/obj/item/electronics/keypad))
|
||||
partID = "keypad"
|
||||
else if(istype(T,/obj/item/electronics/screen))
|
||||
partID = "screen"
|
||||
else if(istype(T,/obj/item/electronics/buzzer))
|
||||
partID = "buzzer"
|
||||
|
||||
if (!isnum(checkList[partID]) || (checkList[partID] < 1))
|
||||
continue
|
||||
|
||||
checkList[partID] = checkList[partID] - 1
|
||||
|
||||
for (var/i in checkList)
|
||||
if (checkList[i] > 0)
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
////////////////////////////////////////////////////////////////?
|
||||
/obj/item/electronics/soldering
|
||||
name = "soldering iron"
|
||||
icon = 'icons/obj/electronics.dmi'
|
||||
icon_state = "solderingiron"
|
||||
force = 10
|
||||
damtype = "fire"
|
||||
throwforce = 5
|
||||
w_class = 2.0
|
||||
pressure_resistance = 40
|
||||
module_research = list("electronics" = 3, "engineering" = 1)
|
||||
|
||||
////////////////////////////////////////////////////////////////no
|
||||
/obj/item/electronics/disk
|
||||
name = "data module"
|
||||
icon_state = "disk"
|
||||
var/list/parts = new/list()
|
||||
var/item_name = "Error"
|
||||
|
||||
////////////////////////////////////////////////////////////////up
|
||||
/obj/item/electronics/scanner
|
||||
name = "device analyzer"
|
||||
icon_state = "deviceana"
|
||||
desc = "Used for scanning certain items for use with the ruckingenur kit."
|
||||
force = 2
|
||||
damtype = "brute"
|
||||
throwforce = 5
|
||||
w_class = 2.0
|
||||
pressure_resistance = 50
|
||||
var/list/scanned = list()
|
||||
var/viewstat = 0
|
||||
module_research = list("electronics" = 3, "engineering" = 3, "analysis" = 2)
|
||||
|
||||
syndicate
|
||||
is_syndicate = 1
|
||||
|
||||
/obj/item/electronics/scanner/afterattack(var/obj/O, mob/user as mob)
|
||||
if(istype(O,/obj/machinery/rkit))
|
||||
return
|
||||
if(istype(O,/obj/))
|
||||
if(O.mats == 0 || (O.is_syndicate != 0 && src.is_syndicate == 0))
|
||||
// if this item doesn't have mats defined or was constructed or
|
||||
// attempting to scan a syndicate item and this is a normal scanner
|
||||
boutput(user, "<span style=\"color:red\">The structure of this object is not compatible with the scanner.</span>")
|
||||
return
|
||||
|
||||
if (O.mats == "Built" && (ticker && ticker.mode && !istype(ticker.mode, /datum/game_mode/construction)))
|
||||
boutput(user, "<span style=\"color:red\">You cannot scan an object that was already deployed by a mechanic.</span>")
|
||||
return
|
||||
|
||||
user.visible_message("<B>[user.name]</B> scans [O].")
|
||||
|
||||
var/final_type = O.mechanics_type_override ? O.mechanics_type_override : O.type
|
||||
|
||||
for (var/X in src.scanned)
|
||||
if (final_type == X)
|
||||
boutput(user, "<span style=\"color:red\">You have already scanned that object.</span>")
|
||||
return
|
||||
|
||||
for(var/datum/electronics/scanned_item/I in mechanic_controls.scanned_items)
|
||||
if(final_type == I.item_type)
|
||||
boutput(user, "<span style=\"color:red\">That object already exists in the scanned database.</span>")
|
||||
return
|
||||
src.scanned += final_type
|
||||
boutput(user, "<span style=\"color:blue\">Item scan successful.</span>")
|
||||
|
||||
////////////////////////////////////////////////////////////////no
|
||||
/obj/machinery/rkit
|
||||
name = "ruckingenur kit"
|
||||
desc = "Used for reverse engineering certain items."
|
||||
icon = 'icons/obj/electronics.dmi'
|
||||
icon_state = "rkit"
|
||||
anchored = 1
|
||||
density = 1
|
||||
//var/datum/electronics/electronics_items/link = null
|
||||
|
||||
var/processing = 0
|
||||
var/net_id = null
|
||||
var/frequency = 1149
|
||||
var/datum/radio_frequency/radio_connection
|
||||
var/no_print_spam = 1 // In relation to world.time.
|
||||
|
||||
/obj/machinery/rkit/New()
|
||||
..()
|
||||
//link = mechanic_controls
|
||||
spawn(8)
|
||||
if(radio_controller)
|
||||
radio_connection = radio_controller.add_object(src, "[frequency]")
|
||||
if(!src.net_id)
|
||||
src.net_id = generate_net_id(src)
|
||||
mechanic_controls.rkit_addresses += src.net_id
|
||||
|
||||
/obj/machinery/rkit/disposing()
|
||||
if(radio_controller)
|
||||
radio_controller.remove_object(src, "[frequency]")
|
||||
radio_connection = null
|
||||
|
||||
if (src.net_id)
|
||||
mechanic_controls.rkit_addresses -= src.net_id
|
||||
|
||||
//link = null
|
||||
|
||||
..()
|
||||
|
||||
/obj/machinery/rkit/receive_signal(datum/signal/signal)
|
||||
if(stat & NOPOWER)
|
||||
return
|
||||
|
||||
if(!signal || signal.encryption || !signal.data["sender"])
|
||||
return
|
||||
|
||||
var/target = signal.data["sender"]
|
||||
if((signal.data["address_1"] == "ping") && target)
|
||||
spawn(5) //Send a reply for those curious jerks
|
||||
|
||||
var/datum/signal/newsignal = get_free_signal()
|
||||
newsignal.source = src
|
||||
newsignal.transmission_method = TRANSMISSION_RADIO
|
||||
newsignal.data["command"] = "ping_reply"
|
||||
newsignal.data["device"] = "NET_RKANALZYER"
|
||||
newsignal.data["netid"] = src.net_id
|
||||
|
||||
newsignal.data["address_1"] = target
|
||||
newsignal.data["sender"] = src.net_id
|
||||
|
||||
radio_connection.post_signal(src, newsignal)
|
||||
|
||||
return
|
||||
|
||||
if(signal.data["address_1"] != src.net_id || !target || signal.data["command"] != "add" || !istype(signal.data_file, /datum/computer/file/electronics_scan))
|
||||
return
|
||||
|
||||
var/datum/computer/file/electronics_scan/scanFile = signal.data_file
|
||||
for(var/datum/electronics/scanned_item/O in mechanic_controls.scanned_items)
|
||||
if(scanFile.scannedPath == O.item_type)
|
||||
spawn(5)
|
||||
|
||||
var/datum/signal/newsignal = get_free_signal()
|
||||
newsignal.source = src
|
||||
newsignal.transmission_method = TRANSMISSION_RADIO
|
||||
newsignal.data["command"] = "text_message"
|
||||
newsignal.data["sender_name"] = "RKIT-MAILBOT"
|
||||
newsignal.data["message"] = "Notice: Item already in database."
|
||||
|
||||
newsignal.data["address_1"] = target
|
||||
newsignal.data["sender"] = src.net_id
|
||||
|
||||
radio_connection.post_signal(src, newsignal)
|
||||
return
|
||||
|
||||
mechanic_controls.scan_in(scanFile.scannedName, scanFile.scannedPath, scanFile.scannedMats)
|
||||
spawn(5)
|
||||
|
||||
var/datum/signal/newsignal = get_free_signal()
|
||||
newsignal.source = src
|
||||
newsignal.transmission_method = TRANSMISSION_RADIO
|
||||
newsignal.data["command"] = "text_message"
|
||||
newsignal.data["sender_name"] = "RKIT-MAILBOT"
|
||||
newsignal.data["message"] = "Notice: Item entered into database."
|
||||
|
||||
newsignal.data["address_1"] = target
|
||||
newsignal.data["sender"] = src.net_id
|
||||
|
||||
radio_connection.post_signal(src, newsignal)
|
||||
|
||||
/obj/machinery/rkit/attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
if(istype(W,/obj/item/electronics/scanner))
|
||||
var/obj/item/electronics/scanner/S = W
|
||||
var/add_count = 0
|
||||
var/match_check = 1
|
||||
for(var/X in S.scanned)
|
||||
match_check = 0
|
||||
for(var/datum/electronics/scanned_item/O in mechanic_controls.scanned_items)
|
||||
if(S.scanned == O.item_type)
|
||||
S.scanned -= X
|
||||
match_check = 1
|
||||
break
|
||||
if (!match_check)
|
||||
var/obj/tempobj = new X (src)
|
||||
mechanic_controls.scan_in(tempobj.name,tempobj.type,tempobj.mats)
|
||||
spawn(40)
|
||||
qdel(tempobj)
|
||||
S.scanned -= X
|
||||
add_count++
|
||||
|
||||
if (add_count > 0)
|
||||
boutput(user, "<span style=\"color:blue\">[add_count] new items entered into kit.</span>")
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">No new items entered into kit.</span>")
|
||||
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/rkit/attack_hand(mob/user as mob)
|
||||
src.add_fingerprint(user)
|
||||
var/dat
|
||||
dat = "<b>Ruckingenur Kit</b><HR>"
|
||||
|
||||
dat += "<b>Scanned Items:</b><br>"
|
||||
for(var/datum/electronics/scanned_item/S in mechanic_controls.scanned_items)
|
||||
dat += "<u>[S.name]</u><small> "
|
||||
//dat += "<A href='?src=\ref[src];op=\ref[S];tp=done'>Frame</A>"
|
||||
if (S.blueprint)
|
||||
dat += " * <A href='?src=\ref[src];op=\ref[S];tp=blueprint'>Blueprint</A>"
|
||||
dat += "</small><br>"
|
||||
dat += "<br>"
|
||||
|
||||
dat += "<HR>"
|
||||
|
||||
user.machine = src
|
||||
user << browse("<HEAD><TITLE>Ruckingenur Kit Control Panel</TITLE></HEAD><TT>[dat]</TT>", "window=rkit")
|
||||
onclose(user, "rkit")
|
||||
|
||||
/obj/machinery/rkit/Topic(href, href_list)
|
||||
if (usr.stat)
|
||||
return
|
||||
if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon)))
|
||||
usr.machine = src
|
||||
|
||||
switch(href_list["tp"])
|
||||
|
||||
if("done")
|
||||
if(href_list["op"])
|
||||
var/datum/electronics/scanned_item/O = locate(href_list["op"])
|
||||
if(istype(O,/datum/electronics/scanned_item/))
|
||||
var/obj/item/electronics/frame/F = new/obj/item/electronics/frame(src.loc)
|
||||
F.name = "[O.name]-frame"
|
||||
F.store_type = O.item_type
|
||||
F.needed_parts = O.item_mats
|
||||
|
||||
if("blueprint")
|
||||
if(href_list["op"])
|
||||
if (src.no_print_spam && world.time < src.no_print_spam + 50)
|
||||
usr.show_text("[src] isn't done with the previous print job.", "red")
|
||||
else
|
||||
var/datum/electronics/scanned_item/O = locate(href_list["op"])
|
||||
if (istype(O.blueprint, /datum/manufacture/mechanics/))
|
||||
usr.show_text("Print job started...", "blue")
|
||||
var/datum/manufacture/mechanics/M = O.blueprint
|
||||
playsound(src.loc, 'sound/machines/printer_thermal.ogg', 50, 1)
|
||||
src.no_print_spam = world.time
|
||||
spawn (50)
|
||||
if (src)
|
||||
new /obj/item/paper/manufacturer_blueprint(src.loc, M.name)
|
||||
|
||||
updateDialog()
|
||||
else
|
||||
usr << browse(null, "window=rkit")
|
||||
usr.machine = null
|
||||
return
|
||||
|
||||
/obj/item/deconstructor
|
||||
name = "deconstruction device"
|
||||
desc = "A device able to break copied objects down into their base materials."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "forensic0"
|
||||
w_class = 3.0
|
||||
var/datum/effects/system/spark_spread/spark_system
|
||||
module_research = list("electronics" = 3, "engineering" = 1)
|
||||
|
||||
New()
|
||||
..()
|
||||
src.spark_system = unpool(/datum/effects/system/spark_spread)
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
return
|
||||
|
||||
afterattack(atom/target as mob|obj|turf|area, mob/user as mob)
|
||||
if (!istype(target,/obj/))
|
||||
return
|
||||
var/obj/O = target
|
||||
if (O.mats != "Built")
|
||||
boutput(user, "<span style=\"color:red\">This fixture cannot be deconstructed.</span>")
|
||||
return
|
||||
boutput(user, "Deconstructing [O], please remain still...")
|
||||
playsound(user.loc, 'sound/effects/pop.ogg', 50, 1)
|
||||
if(do_after(user, 20))
|
||||
logTheThing("station", user, null, "deconstructs [O] in [user.loc.loc] ([showCoords(user.x, user.y, user.z)])")
|
||||
playsound(user.loc, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
user.visible_message("<B>[user.name]</B> deconstructs [O].")
|
||||
|
||||
var/datum/manufacture/mechanics/R = null
|
||||
for (var/datum/manufacture/mechanics/M in manuf_controls.custom_schematics)
|
||||
if (M.frame_path == O.type)
|
||||
R = M
|
||||
break
|
||||
|
||||
if (istype(R))
|
||||
var/looper = round(R.item_amounts[1] / 10, 1)
|
||||
while (looper > 0)
|
||||
new /obj/item/material_piece/mauxite(O.loc)
|
||||
looper--
|
||||
looper = round(R.item_amounts[2] / 10, 1)
|
||||
while (looper > 0)
|
||||
new /obj/item/material_piece/pharosium(O.loc)
|
||||
looper--
|
||||
looper = round(R.item_amounts[3] / 10, 1)
|
||||
while (looper > 0)
|
||||
new /obj/item/material_piece/molitz(O.loc)
|
||||
looper--
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">Could not reclaim resources.</span>")
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.start()
|
||||
qdel(O)
|
||||
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">Deconstruction of [O] interrupted!</span>")
|
||||
return
|
||||
@@ -0,0 +1,196 @@
|
||||
/obj/fitness/speedbag
|
||||
name = "punching bag"
|
||||
desc = "A punching bag. Can you get to speed level 4???"
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "punchingbag"
|
||||
anchored = 1
|
||||
layer = MOB_LAYER_BASE+1 // TODO LAYER
|
||||
var/list/hit_sounds = list('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg',\
|
||||
'sound/weapons/punch1.ogg', 'sound/weapons/punch2.ogg', 'sound/weapons/punch3.ogg', 'sound/weapons/punch4.ogg')
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
flick("[icon_state]2", src)
|
||||
playsound(src.loc, pick(src.hit_sounds), 25, 1, -1)
|
||||
if (ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if (H.sims)
|
||||
H.sims.affectMotive("fun", 2)
|
||||
if(hascall(user, "add_stam_mod_regen"))
|
||||
if(user:add_stam_mod_regen("fitness_bag", 1) )
|
||||
spawn(9000)
|
||||
if (user) //Wire: Fix for Cannot execute null.remove stam mod regen().
|
||||
user:remove_stam_mod_regen("fitness_bag")
|
||||
|
||||
wizard
|
||||
icon_state = "punchingbagwizard"
|
||||
desc = "It has a picture of a weird wizard on it."
|
||||
|
||||
syndie
|
||||
icon_state = "punchingbagsyndie"
|
||||
desc = "It has a picture of a mean ol' syndicate on it."
|
||||
|
||||
captain
|
||||
icon_state = "punchingbagcaptain"
|
||||
desc = "It has a picture of a dumb looking station captain on it."
|
||||
|
||||
clown
|
||||
name = "clown bop bag"
|
||||
desc = "A bop bag in the shape of a goofy clown."
|
||||
icon_state = "bopbag"
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
flick("[icon_state]2", src)
|
||||
if (narrator_mode)
|
||||
playsound(src.loc, 'sound/vox/hit.ogg', 25, 1, -1)
|
||||
playsound(src.loc, 'sound/vox/honk.ogg', 50, 1, -1)
|
||||
else
|
||||
playsound(src.loc, pick(src.hit_sounds), 25, 1, -1)
|
||||
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1, -1)
|
||||
|
||||
/obj/fitness/stacklifter
|
||||
name = "Weight Machine"
|
||||
desc = "Just looking at this thing makes you feel tired."
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "fitnesslifter"
|
||||
density = 1
|
||||
anchored = 1
|
||||
var/in_use = 0
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if(in_use)
|
||||
boutput(user, "<span style=\"color:red\">Its already in use - wait a bit.</span>")
|
||||
return
|
||||
else
|
||||
in_use = 1
|
||||
icon_state = "fitnesslifter2"
|
||||
user.transforming = 1
|
||||
user.dir = SOUTH
|
||||
user.set_loc(src.loc)
|
||||
var/bragmessage = pick("pushing it to the limit","going into overdrive","burning with determination","rising up to the challenge", "getting strong now","getting ripped")
|
||||
usr.visible_message(text("<span style=\"color:red\"><B>[usr] is [bragmessage]!</B></span>"))
|
||||
var/lifts = 0
|
||||
while (lifts++ < 6)
|
||||
if (user.loc != src.loc)
|
||||
break
|
||||
sleep(3)
|
||||
user.pixel_y = -2
|
||||
sleep(3)
|
||||
user.pixel_y = -4
|
||||
sleep(3)
|
||||
playsound(user, 'sound/effects/spring.ogg', 60, 1)
|
||||
|
||||
playsound(user, 'sound/machines/click.ogg', 60, 1)
|
||||
in_use = 0
|
||||
user.transforming = 0
|
||||
user.pixel_y = 0
|
||||
if (ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if (H.sims)
|
||||
H.sims.affectMotive("fun", 4)
|
||||
var/finishmessage = pick("You feel stronger!","You feel like you can take on the world!","You feel robust!","You feel indestructible!")
|
||||
icon_state = "fitnesslifter"
|
||||
boutput(user, "<span style=\"color:blue\">[finishmessage]</span>")
|
||||
if(hascall(user, "add_stam_mod_regen"))
|
||||
if(user:add_stam_mod_regen("fitness_stack", 1) )
|
||||
spawn(9000)
|
||||
if (user) //Wire: Fix for Cannot execute null.remove stam mod regen().
|
||||
user:remove_stam_mod_regen("fitness_stack")
|
||||
|
||||
/obj/fitness/weightlifter
|
||||
name = "Weight Machine"
|
||||
desc = "Just looking at this thing makes you feel tired."
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "fitnessweight"
|
||||
density = 1
|
||||
anchored = 1
|
||||
var/in_use = 0
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if(in_use)
|
||||
boutput(user, "<span style=\"color:red\">Its already in use - wait a bit.</span>")
|
||||
return
|
||||
else
|
||||
in_use = 1
|
||||
icon_state = "fitnessweight-c"
|
||||
user.transforming = 1
|
||||
user.dir = SOUTH
|
||||
user.set_loc(src.loc)
|
||||
var/obj/decal/W = new /obj/decal/
|
||||
W.icon = 'icons/obj/stationobjs.dmi'
|
||||
W.icon_state = "fitnessweight-w"
|
||||
W.loc = loc
|
||||
W.anchored = 1
|
||||
W.layer = MOB_LAYER_BASE+1
|
||||
var/bragmessage = pick("pushing it to the limit","going into overdrive","burning with determination","rising up to the challenge", "getting strong now","getting ripped")
|
||||
usr.visible_message(text("<span style=\"color:red\"><B>[usr] is [bragmessage]!</B></span>"))
|
||||
var/reps = 0
|
||||
user.pixel_y = 5
|
||||
while (reps++ < 6)
|
||||
if (user.loc != src.loc)
|
||||
break
|
||||
|
||||
for (var/innerReps = max(reps, 1), innerReps > 0, innerReps--)
|
||||
sleep(3)
|
||||
user.pixel_y = (user.pixel_y == 3) ? 5 : 3
|
||||
|
||||
playsound(user, 'sound/effects/spring.ogg', 60, 1)
|
||||
|
||||
sleep(3)
|
||||
user.pixel_y = 2
|
||||
sleep(3)
|
||||
playsound(user, 'sound/machines/click.ogg', 60, 1)
|
||||
in_use = 0
|
||||
user.transforming = 0
|
||||
user.pixel_y = 0
|
||||
if (ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if (H.sims)
|
||||
H.sims.affectMotive("fun", 4)
|
||||
var/finishmessage = pick("You feel stronger!","You feel like you can take on the world!","You feel robust!","You feel indestructible!")
|
||||
icon_state = "fitnessweight"
|
||||
qdel(W)
|
||||
boutput(user, "<span style=\"color:blue\">[finishmessage]</span>")
|
||||
if(hascall(user, "add_stam_mod_max"))
|
||||
if(user:add_stam_mod_max("fitness_weight", 10) )
|
||||
spawn(9000)
|
||||
if (user) //Wire: Fix for Cannot execute null.remove stam mod regen().
|
||||
user:remove_stam_mod_max("fitness_weight")
|
||||
|
||||
/obj/item/rubberduck
|
||||
name = "Rubber Duck"
|
||||
desc = "Awww, it squeaks!"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "rubber_duck"
|
||||
item_state = "sponge"
|
||||
throwforce = 1
|
||||
w_class = 1.0
|
||||
throw_speed = 3
|
||||
throw_range = 15
|
||||
var/spam_flag = 0
|
||||
|
||||
/obj/item/rubberduck/attack_self(mob/user as mob)
|
||||
if (spam_flag == 0)
|
||||
if (ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if (H.sims)
|
||||
H.sims.affectMotive("fun", 1)
|
||||
spam_flag = 1
|
||||
if (narrator_mode)
|
||||
playsound(src.loc, 'sound/vox/duct.ogg', 50, 1)
|
||||
else
|
||||
playsound(src.loc, 'sound/items/rubberduck.ogg', 50, 1)
|
||||
if(prob(1))
|
||||
user.drop_item()
|
||||
playsound(src.loc, 'sound/ambience/lavamoon_strange_fx1.ogg', 50, 1) // this is gonna spook some people!!
|
||||
var/wacka = 0
|
||||
while (wacka++ < 50)
|
||||
sleep(2)
|
||||
pixel_x = rand(-6,6)
|
||||
pixel_y = rand(-6,6)
|
||||
sleep(1)
|
||||
pixel_y = 0
|
||||
pixel_x = 0
|
||||
src.add_fingerprint(user)
|
||||
spawn(20)
|
||||
spam_flag = 0
|
||||
return
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,164 @@
|
||||
////////////////// MISC BULLSHIT //////////////////
|
||||
|
||||
/mob/proc/fake_damage(var/amount,var/seconds)
|
||||
if (!amount || !seconds)
|
||||
return
|
||||
|
||||
src.fakeloss += amount
|
||||
|
||||
spawn(seconds * 10)
|
||||
src.fakeloss -= amount
|
||||
|
||||
/mob/proc/false_death(var/seconds)
|
||||
if (!seconds)
|
||||
return
|
||||
|
||||
src.fakedead = 1
|
||||
boutput(src, "<B>[src]</B> seizes up and falls limp, [his_or_her(src)] eyes dead and lifeless...")
|
||||
src.weakened = 5
|
||||
|
||||
spawn(seconds * 10)
|
||||
src.fakedead = 0
|
||||
src.weakened = 0
|
||||
|
||||
/proc/get_mobs_of_type_at_point_blank(var/atom/object,var/mob_path)
|
||||
var/list/returning_list = list()
|
||||
if (!object || !mob_path)
|
||||
return returning_list
|
||||
|
||||
if (istype(object,/area/))
|
||||
return returning_list
|
||||
|
||||
for (var/mob/L in range(1,object))
|
||||
if (istype(L,mob_path))
|
||||
returning_list += L
|
||||
|
||||
return returning_list
|
||||
|
||||
/proc/get_mobs_of_type_in_view(var/atom/object,var/mob_path)
|
||||
var/list/returning_list = list()
|
||||
if (!object || !mob_path)
|
||||
return returning_list
|
||||
|
||||
if (istype(object,/area/))
|
||||
return returning_list
|
||||
|
||||
for (var/mob/L in view(7,object))
|
||||
if (istype(L,mob_path))
|
||||
returning_list += L
|
||||
|
||||
return returning_list
|
||||
|
||||
/mob/proc/get_current_active_item()
|
||||
return null
|
||||
|
||||
/mob/living/carbon/human/get_current_active_item()
|
||||
if (src.hand)
|
||||
return src.r_hand
|
||||
else
|
||||
return src.l_hand
|
||||
|
||||
/mob/living/silicon/robot/get_current_active_item()
|
||||
return src.module_active
|
||||
|
||||
/mob/proc/get_temp_deviation()
|
||||
var/tempdiff = src.bodytemperature - src.base_body_temp
|
||||
var/tol = src.temp_tolerance
|
||||
var/ntl = 0 - src.temp_tolerance // these are just to make the switch a bit easier to look at
|
||||
|
||||
if (tempdiff > tol*4)
|
||||
return 4 // some like to be on fire
|
||||
else if (tempdiff < ntl*4)
|
||||
return -4 // i think my ears just froze off oh god
|
||||
else if (tempdiff > tol*3)
|
||||
return 3 // some like it too hot
|
||||
else if (tempdiff < ntl*3)
|
||||
return -3 // too chill
|
||||
else if (tempdiff > tol*2)
|
||||
return 2 // some like it hot
|
||||
else if (tempdiff < ntl*2)
|
||||
return -2 // pretty chill
|
||||
else if (tempdiff > tol*1)
|
||||
return 1 // some like it warm
|
||||
else if (tempdiff < ntl*1)
|
||||
return -1 // a little bit chill
|
||||
else
|
||||
return 0 // I'M APOLLO JUSTICE AND I'M FINE
|
||||
|
||||
/mob/proc/is_cold_resistant()
|
||||
if (!src)
|
||||
return 0
|
||||
if(src.bioHolder && src.bioHolder.HasOneOfTheseEffects("cold_resist","thermal_resist"))
|
||||
return 1
|
||||
if(src.get_ability_holder(/datum/abilityHolder/changeling))
|
||||
return 1
|
||||
if(src.nodamage)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/mob/proc/is_heat_resistant()
|
||||
if (!src)
|
||||
return 0
|
||||
if(src.bioHolder && src.bioHolder.HasOneOfTheseEffects("fire_resist","thermal_resist"))
|
||||
return 1
|
||||
if(src.nodamage)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
// Hallucinations
|
||||
|
||||
/mob/living/proc/hallucinate_fake_melee_attack()
|
||||
var/list/PB_mobs = get_mobs_of_type_at_point_blank(src,/mob/living/)
|
||||
var/mob/living/H = pick(PB_mobs)
|
||||
if (H.stat)
|
||||
return
|
||||
var/obj/item/I = H.get_current_active_item()
|
||||
|
||||
if (istype(I))
|
||||
boutput(src, "<span style=\"color:red\"><b>[H.name] attacks [src.name] with [I]!</b></span>")
|
||||
if (I.hitsound)
|
||||
src.playsound_local(src.loc, I.hitsound, 50, 1)
|
||||
src.fake_damage(I.force,100)
|
||||
else
|
||||
if (!istype(H,/mob/living/carbon/human/))
|
||||
return
|
||||
if (!src.canmove)
|
||||
src.playsound_local(src.loc, 'sound/weapons/genhit1.ogg', 25, 1, -1)
|
||||
boutput(src, "<span style=\"color:red\"><B>[H.name] kicks [src.name]!</B></span>")
|
||||
else
|
||||
var/list/punches = list('sound/weapons/punch1.ogg','sound/weapons/punch2.ogg','sound/weapons/punch3.ogg','sound/weapons/punch4.ogg')
|
||||
src.playsound_local(src.loc, pick(punches), 25, 1, -1)
|
||||
boutput(src, "<span style=\"color:red\"><B>[H.name] punches [src.name]!</B></span>")
|
||||
src.fake_damage(rand(2,9),100)
|
||||
src.hit_twitch()
|
||||
|
||||
///////////////
|
||||
// Anomalies //
|
||||
///////////////
|
||||
|
||||
/obj/anomaly
|
||||
name = "anomaly"
|
||||
desc = "swirly thing alert!!!!"
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "anom"
|
||||
density = 1
|
||||
opacity = 0
|
||||
anchored = 1
|
||||
var/has_processing_loop = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
if (has_processing_loop)
|
||||
global.processing_items.Add(src)
|
||||
return 0
|
||||
|
||||
proc/process()
|
||||
return 0
|
||||
|
||||
/obj/anomaly/test
|
||||
name = "boing anomaly"
|
||||
desc = "it goes boing and does stuff"
|
||||
has_processing_loop = 1
|
||||
|
||||
process()
|
||||
playsound(src.loc, 'sound/effects/chanting.ogg', 100, 0, 5, 0.5)
|
||||
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
IconProcs
|
||||
by Lummox JR
|
||||
version 1.0
|
||||
|
||||
A library for manipulating icons and colors in BYOND
|
||||
|
||||
See documentation in IconProcs.html
|
||||
*/
|
||||
|
||||
#define TO_HEX_DIGIT(n) ascii2text((n&15) + ((n&15)<10 ? 48 : 87))
|
||||
|
||||
icon
|
||||
// Multiply all alpha values by this float
|
||||
proc/ChangeOpacity(opacity = 1.0)
|
||||
MapColors(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,opacity, 0,0,0,0)
|
||||
|
||||
// Convert to grayscale
|
||||
proc/GrayScale()
|
||||
MapColors(0.3,0.3,0.3, 0.59,0.59,0.59, 0.11,0.11,0.11, 0,0,0)
|
||||
|
||||
proc/ColorTone(tone)
|
||||
GrayScale()
|
||||
|
||||
var/list/TONE = ReadRGB(tone)
|
||||
var/gray = round(TONE[1]*0.3 + TONE[2]*0.59 + TONE[3]*0.11, 1)
|
||||
|
||||
var/icon/upper = (255-gray) ? new(src) : null
|
||||
|
||||
if(gray)
|
||||
MapColors(255/gray,0,0, 0,255/gray,0, 0,0,255/gray, 0,0,0)
|
||||
Blend(tone, ICON_MULTIPLY)
|
||||
else SetIntensity(0)
|
||||
if(255-gray)
|
||||
upper.Blend(rgb(gray,gray,gray), ICON_SUBTRACT)
|
||||
upper.MapColors((255-TONE[1])/(255-gray),0,0,0, 0,(255-TONE[2])/(255-gray),0,0, 0,0,(255-TONE[3])/(255-gray),0, 0,0,0,0, 0,0,0,1)
|
||||
Blend(upper, ICON_ADD)
|
||||
|
||||
// Take the minimum color of two icons; combine transparency as if blending with ICON_ADD
|
||||
proc/MinColors(icon)
|
||||
var/icon/I = new(src)
|
||||
I.Opaque()
|
||||
I.Blend(icon, ICON_SUBTRACT)
|
||||
Blend(I, ICON_SUBTRACT)
|
||||
|
||||
// Take the maximum color of two icons; combine opacity as if blending with ICON_OR
|
||||
proc/MaxColors(icon)
|
||||
var/icon/I
|
||||
if(isicon(icon))
|
||||
I = new(icon)
|
||||
else
|
||||
// solid color
|
||||
I = new(src)
|
||||
I.Blend("#000000", ICON_OVERLAY)
|
||||
I.SwapColor("#000000", null)
|
||||
I.Blend(icon, ICON_OVERLAY)
|
||||
var/icon/J = new(src)
|
||||
J.Opaque()
|
||||
I.Blend(J, ICON_SUBTRACT)
|
||||
Blend(I, ICON_OR)
|
||||
|
||||
// make this icon fully opaque--transparent pixels become black
|
||||
proc/Opaque(background = "#000000")
|
||||
SwapColor(null, background)
|
||||
MapColors(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,0, 0,0,0,1)
|
||||
|
||||
// Change a grayscale icon into a white icon where the original color becomes the alpha
|
||||
// I.e., black -> transparent, gray -> translucent white, white -> solid white
|
||||
proc/BecomeAlphaMask()
|
||||
SwapColor(null, "#000000ff") // don't let transparent become gray
|
||||
MapColors(0,0,0,0.3, 0,0,0,0.59, 0,0,0,0.11, 0,0,0,0, 1,1,1,0)
|
||||
|
||||
proc/UseAlphaMask(mask)
|
||||
Opaque()
|
||||
AddAlphaMask(mask)
|
||||
|
||||
proc/AddAlphaMask(mask)
|
||||
var/icon/M = new(mask)
|
||||
M.Blend("#ffffff", ICON_SUBTRACT)
|
||||
// apply mask
|
||||
Blend(M, ICON_ADD)
|
||||
|
||||
/*
|
||||
HSV format is represented as "#hhhssvv" or "#hhhssvvaa"
|
||||
|
||||
Hue ranges from 0 to 0x5ff (1535)
|
||||
|
||||
0x000 = red
|
||||
0x100 = yellow
|
||||
0x200 = green
|
||||
0x300 = cyan
|
||||
0x400 = blue
|
||||
0x500 = magenta
|
||||
|
||||
Saturation is from 0 to 0xff (255)
|
||||
|
||||
More saturation = more color
|
||||
Less saturation = more gray
|
||||
|
||||
Value ranges from 0 to 0xff (255)
|
||||
|
||||
Higher value means brighter color
|
||||
*/
|
||||
|
||||
proc/ReadRGB(rgb)
|
||||
if(!rgb) return
|
||||
|
||||
// interpret the HSV or HSVA value
|
||||
var/i=1,start=1
|
||||
if(text2ascii(rgb) == 35) ++start // skip opening #
|
||||
var/ch,which=0,r=0,g=0,b=0,alpha=0,usealpha
|
||||
var/digits=0
|
||||
for(i=start, i<=length(rgb), ++i)
|
||||
ch = text2ascii(rgb, i)
|
||||
if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102) break
|
||||
++digits
|
||||
if(digits == 8) break
|
||||
|
||||
var/single = digits < 6
|
||||
if(digits != 3 && digits != 4 && digits != 6 && digits != 8) return
|
||||
if(digits == 4 || digits == 8) usealpha = 1
|
||||
for(i=start, digits>0, ++i)
|
||||
ch = text2ascii(rgb, i)
|
||||
if(ch >= 48 && ch <= 57) ch -= 48
|
||||
else if(ch >= 65 && ch <= 70) ch -= 55
|
||||
else if(ch >= 97 && ch <= 102) ch -= 87
|
||||
else break
|
||||
--digits
|
||||
switch(which)
|
||||
if(0)
|
||||
r = (r << 4) | ch
|
||||
if(single)
|
||||
r |= r << 4
|
||||
++which
|
||||
else if(!(digits & 1)) ++which
|
||||
if(1)
|
||||
g = (g << 4) | ch
|
||||
if(single)
|
||||
g |= g << 4
|
||||
++which
|
||||
else if(!(digits & 1)) ++which
|
||||
if(2)
|
||||
b = (b << 4) | ch
|
||||
if(single)
|
||||
b |= b << 4
|
||||
++which
|
||||
else if(!(digits & 1)) ++which
|
||||
if(3)
|
||||
alpha = (alpha << 4) | ch
|
||||
if(single) alpha |= alpha << 4
|
||||
|
||||
. = list(r, g, b)
|
||||
if(usealpha) . += alpha
|
||||
|
||||
proc/ReadHSV(hsv)
|
||||
if(!hsv) return
|
||||
|
||||
// interpret the HSV or HSVA value
|
||||
var/i=1,start=1
|
||||
if(text2ascii(hsv) == 35) ++start // skip opening #
|
||||
var/ch,which=0,hue=0,sat=0,val=0,alpha=0,usealpha
|
||||
var/digits=0
|
||||
for(i=start, i<=length(hsv), ++i)
|
||||
ch = text2ascii(hsv, i)
|
||||
if(ch < 48 || (ch > 57 && ch < 65) || (ch > 70 && ch < 97) || ch > 102) break
|
||||
++digits
|
||||
if(digits == 9) break
|
||||
if(digits > 7) usealpha = 1
|
||||
if(digits <= 4) ++which
|
||||
if(digits <= 2) ++which
|
||||
for(i=start, digits>0, ++i)
|
||||
ch = text2ascii(hsv, i)
|
||||
if(ch >= 48 && ch <= 57) ch -= 48
|
||||
else if(ch >= 65 && ch <= 70) ch -= 55
|
||||
else if(ch >= 97 && ch <= 102) ch -= 87
|
||||
else break
|
||||
--digits
|
||||
switch(which)
|
||||
if(0)
|
||||
hue = (hue << 4) | ch
|
||||
if(digits == (usealpha ? 6 : 4)) ++which
|
||||
if(1)
|
||||
sat = (sat << 4) | ch
|
||||
if(digits == (usealpha ? 4 : 2)) ++which
|
||||
if(2)
|
||||
val = (val << 4) | ch
|
||||
if(digits == (usealpha ? 2 : 0)) ++which
|
||||
if(3)
|
||||
alpha = (alpha << 4) | ch
|
||||
|
||||
. = list(hue, sat, val)
|
||||
if(usealpha) . += alpha
|
||||
|
||||
proc/HSVtoRGB(hsv)
|
||||
if(!hsv) return "#000000"
|
||||
var/list/HSV = ReadHSV(hsv)
|
||||
if(!HSV) return "#000000"
|
||||
|
||||
var/hue = HSV[1]
|
||||
var/sat = HSV[2]
|
||||
var/val = HSV[3]
|
||||
|
||||
// Compress hue into easier-to-manage range
|
||||
hue -= hue >> 8
|
||||
if(hue >= 0x5fa) hue -= 0x5fa
|
||||
|
||||
var/hi,mid,lo,r,g,b
|
||||
hi = val
|
||||
lo = round((255 - sat) * val / 255, 1)
|
||||
mid = lo + round(abs(round(hue, 510) - hue) * (hi - lo) / 255, 1)
|
||||
if(hue >= 765)
|
||||
if(hue >= 1275) {r=hi; g=lo; b=mid}
|
||||
else if(hue >= 1020) {r=mid; g=lo; b=hi }
|
||||
else {r=lo; g=mid; b=hi }
|
||||
else
|
||||
if(hue >= 510) {r=lo; g=hi; b=mid}
|
||||
else if(hue >= 255) {r=mid; g=hi; b=lo }
|
||||
else {r=hi; g=mid; b=lo }
|
||||
|
||||
return (HSV.len > 3) ? rgb(r,g,b,HSV[4]) : rgb(r,g,b)
|
||||
|
||||
proc/RGBtoHSV(rgb)
|
||||
if(!rgb) return "#0000000"
|
||||
var/list/RGB = ReadRGB(rgb)
|
||||
if(!RGB) return "#0000000"
|
||||
|
||||
var/r = RGB[1]
|
||||
var/g = RGB[2]
|
||||
var/b = RGB[3]
|
||||
var/hi = max(r,g,b)
|
||||
var/lo = min(r,g,b)
|
||||
|
||||
var/val = hi
|
||||
var/sat = hi ? round((hi-lo) * 255 / hi, 1) : 0
|
||||
var/hue = 0
|
||||
|
||||
if(sat)
|
||||
var/dir
|
||||
var/mid
|
||||
if(hi == r)
|
||||
if(lo == b) {hue=0; dir=1; mid=g}
|
||||
else {hue=1535; dir=-1; mid=b}
|
||||
else if(hi == g)
|
||||
if(lo == r) {hue=512; dir=1; mid=b}
|
||||
else {hue=511; dir=-1; mid=r}
|
||||
else if(hi == b)
|
||||
if(lo == g) {hue=1024; dir=1; mid=r}
|
||||
else {hue=1023; dir=-1; mid=g}
|
||||
hue += dir * round((mid-lo) * 255 / (hi-lo), 1)
|
||||
|
||||
return hsv(hue, sat, val, (RGB.len>3 ? RGB[4] : null))
|
||||
|
||||
proc/hsv(hue, sat, val, alpha)
|
||||
if(hue < 0 || hue >= 1536) hue %= 1536
|
||||
if(hue < 0) hue += 1536
|
||||
if((hue & 0xFF) == 0xFF)
|
||||
++hue
|
||||
if(hue >= 1536) hue = 0
|
||||
if(sat < 0) sat = 0
|
||||
if(sat > 255) sat = 255
|
||||
if(val < 0) val = 0
|
||||
if(val > 255) val = 255
|
||||
. = "#"
|
||||
. += TO_HEX_DIGIT(hue >> 8)
|
||||
. += TO_HEX_DIGIT(hue >> 4)
|
||||
. += TO_HEX_DIGIT(hue)
|
||||
. += TO_HEX_DIGIT(sat >> 4)
|
||||
. += TO_HEX_DIGIT(sat)
|
||||
. += TO_HEX_DIGIT(val >> 4)
|
||||
. += TO_HEX_DIGIT(val)
|
||||
if(!isnull(alpha))
|
||||
if(alpha < 0) alpha = 0
|
||||
if(alpha > 255) alpha = 255
|
||||
. += TO_HEX_DIGIT(alpha >> 4)
|
||||
. += TO_HEX_DIGIT(alpha)
|
||||
|
||||
/*
|
||||
Smooth blend between HSV colors
|
||||
|
||||
amount=0 is the first color
|
||||
amount=1 is the second color
|
||||
amount=0.5 is directly between the two colors
|
||||
|
||||
amount<0 or amount>1 are allowed
|
||||
*/
|
||||
proc/BlendHSV(hsv1, hsv2, amount)
|
||||
var/list/HSV1 = ReadHSV(hsv1)
|
||||
var/list/HSV2 = ReadHSV(hsv2)
|
||||
|
||||
// add missing alpha if needed
|
||||
if(HSV1.len < HSV2.len) HSV1 += 255
|
||||
else if(HSV2.len < HSV1.len) HSV2 += 255
|
||||
var/usealpha = HSV1.len > 3
|
||||
|
||||
// normalize hsv values in case anything is screwy
|
||||
if(HSV1[1] > 1536) HSV1[1] %= 1536
|
||||
if(HSV2[1] > 1536) HSV2[1] %= 1536
|
||||
if(HSV1[1] < 0) HSV1[1] += 1536
|
||||
if(HSV2[1] < 0) HSV2[1] += 1536
|
||||
if(!HSV1[3]) {HSV1[1] = 0; HSV1[2] = 0}
|
||||
if(!HSV2[3]) {HSV2[1] = 0; HSV2[2] = 0}
|
||||
|
||||
// no value for one color means don't change saturation
|
||||
if(!HSV1[3]) HSV1[2] = HSV2[2]
|
||||
if(!HSV2[3]) HSV2[2] = HSV1[2]
|
||||
// no saturation for one color means don't change hues
|
||||
if(!HSV1[2]) HSV1[1] = HSV2[1]
|
||||
if(!HSV2[2]) HSV2[1] = HSV1[1]
|
||||
|
||||
// Compress hues into easier-to-manage range
|
||||
HSV1[1] -= HSV1[1] >> 8
|
||||
HSV2[1] -= HSV2[1] >> 8
|
||||
|
||||
var/hue_diff = HSV2[1] - HSV1[1]
|
||||
if(hue_diff > 765) hue_diff -= 1530
|
||||
else if(hue_diff <= -765) hue_diff += 1530
|
||||
|
||||
var/hue = round(HSV1[1] + hue_diff * amount, 1)
|
||||
var/sat = round(HSV1[2] + (HSV2[2] - HSV1[2]) * amount, 1)
|
||||
var/val = round(HSV1[3] + (HSV2[3] - HSV1[3]) * amount, 1)
|
||||
var/alpha = usealpha ? round(HSV1[4] + (HSV2[4] - HSV1[4]) * amount, 1) : null
|
||||
|
||||
// normalize hue
|
||||
if(hue < 0 || hue >= 1530) hue %= 1530
|
||||
if(hue < 0) hue += 1530
|
||||
// decompress hue
|
||||
hue += round(hue / 255)
|
||||
|
||||
return hsv(hue, sat, val, alpha)
|
||||
|
||||
/*
|
||||
Smooth blend between RGB colors
|
||||
|
||||
amount=0 is the first color
|
||||
amount=1 is the second color
|
||||
amount=0.5 is directly between the two colors
|
||||
|
||||
amount<0 or amount>1 are allowed
|
||||
*/
|
||||
proc/BlendRGB(rgb1, rgb2, amount)
|
||||
var/list/RGB1 = ReadRGB(rgb1)
|
||||
var/list/RGB2 = ReadRGB(rgb2)
|
||||
|
||||
// add missing alpha if needed
|
||||
if(RGB1.len < RGB2.len) RGB1 += 255
|
||||
else if(RGB2.len < RGB1.len) RGB2 += 255
|
||||
var/usealpha = RGB1.len > 3
|
||||
|
||||
var/r = round(RGB1[1] + (RGB2[1] - RGB1[1]) * amount, 1)
|
||||
var/g = round(RGB1[2] + (RGB2[2] - RGB1[2]) * amount, 1)
|
||||
var/b = round(RGB1[3] + (RGB2[3] - RGB1[3]) * amount, 1)
|
||||
var/alpha = usealpha ? round(RGB1[4] + (RGB2[4] - RGB1[4]) * amount, 1) : null
|
||||
|
||||
return isnull(alpha) ? rgb(r, g, b) : rgb(r, g, b, alpha)
|
||||
|
||||
proc/BlendRGBasHSV(rgb1, rgb2, amount)
|
||||
return HSVtoRGB(RGBtoHSV(rgb1), RGBtoHSV(rgb2), amount)
|
||||
|
||||
proc/HueToAngle(hue)
|
||||
// normalize hsv in case anything is screwy
|
||||
if(hue < 0 || hue >= 1536) hue %= 1536
|
||||
if(hue < 0) hue += 1536
|
||||
// Compress hue into easier-to-manage range
|
||||
hue -= hue >> 8
|
||||
return hue / (1530/360)
|
||||
|
||||
proc/AngleToHue(angle)
|
||||
// normalize hsv in case anything is screwy
|
||||
if(angle < 0 || angle >= 360) angle -= 360 * round(angle / 360)
|
||||
var/hue = angle * (1530/360)
|
||||
// Decompress hue
|
||||
hue += round(hue / 255)
|
||||
return hue
|
||||
|
||||
|
||||
// positive angle rotates forward through red->green->blue
|
||||
proc/RotateHue(hsv, angle)
|
||||
var/list/HSV = ReadHSV(hsv)
|
||||
|
||||
// normalize hsv in case anything is screwy
|
||||
if(HSV[1] >= 1536) HSV[1] %= 1536
|
||||
if(HSV[1] < 0) HSV[1] += 1536
|
||||
|
||||
// Compress hue into easier-to-manage range
|
||||
HSV[1] -= HSV[1] >> 8
|
||||
|
||||
if(angle < 0 || angle >= 360) angle -= 360 * round(angle / 360)
|
||||
HSV[1] = round(HSV[1] + angle * (1530/360), 1)
|
||||
|
||||
// normalize hue
|
||||
if(HSV[1] < 0 || HSV[1] >= 1530) HSV[1] %= 1530
|
||||
if(HSV[1] < 0) HSV[1] += 1530
|
||||
// decompress hue
|
||||
HSV[1] += round(HSV[1] / 255)
|
||||
|
||||
return hsv(HSV[1], HSV[2], HSV[3], (HSV.len > 3 ? HSV[4] : null))
|
||||
|
||||
// Convert an rgb color to grayscale
|
||||
proc/GrayScale(rgb)
|
||||
var/list/RGB = ReadRGB(rgb)
|
||||
var/gray = RGB[1]*0.3 + RGB[2]*0.59 + RGB[3]*0.11
|
||||
return (RGB.len > 3) ? rgb(gray, gray, gray, RGB[4]) : rgb(gray, gray, gray)
|
||||
|
||||
// Change grayscale color to black->tone->white range
|
||||
proc/ColorTone(rgb, tone)
|
||||
var/list/RGB = ReadRGB(rgb)
|
||||
var/list/TONE = ReadRGB(tone)
|
||||
|
||||
var/gray = RGB[1]*0.3 + RGB[2]*0.59 + RGB[3]*0.11
|
||||
var/tone_gray = TONE[1]*0.3 + TONE[2]*0.59 + TONE[3]*0.11
|
||||
|
||||
if(gray <= tone_gray) return BlendRGB("#000000", tone, gray/(tone_gray || 1))
|
||||
else return BlendRGB(tone, "#ffffff", (gray-tone_gray)/((255-tone_gray) || 1))
|
||||
@@ -0,0 +1,152 @@
|
||||
|
||||
/obj/item/clothing/mask/pallid
|
||||
name = "The Pallid Mask"
|
||||
desc = "..."
|
||||
icon_state = "pallid_mask"
|
||||
|
||||
/proc/get_oov_tile(var/atom) //Get a tile that is *just* outside the view of a given atom.
|
||||
var/list/viewl = oview(7, atom)
|
||||
for(var/atom/A in viewl) //List of visible turfs.
|
||||
if(!isturf(A)) viewl -= A
|
||||
|
||||
var/list/rangel = orange(7, atom)
|
||||
for(var/atom/A2 in rangel) //List of all turfs.
|
||||
if(!isturf(A2)) rangel -= A2
|
||||
|
||||
var/list/not_vis = viewl ^ rangel //List of all turfs that are NOT visible.
|
||||
var/list/valid = new/list() //List of all turfs that are NOT visible that border a VISIBLE turf.
|
||||
|
||||
for(var/turf/T in not_vis)
|
||||
for(var/dir in cardinal)
|
||||
if(get_step(T, dir) in viewl)
|
||||
if(is_free(T))
|
||||
var/atom/between = get_step(T, get_dir(T, atom))
|
||||
if(!between.opacity || 1) //this might limit it too much. check later
|
||||
valid += T
|
||||
break
|
||||
|
||||
if(!valid.len) return null
|
||||
else return pick(valid)
|
||||
|
||||
/obj/kingyellow_vanish
|
||||
name = "Distortion"
|
||||
desc = ""
|
||||
density = 0
|
||||
anchored = 1
|
||||
layer = EFFECTS_LAYER_BASE
|
||||
var/image/effect = null
|
||||
|
||||
New(var/atom/location, var/atom/trg)
|
||||
if(trg != null)
|
||||
loc = location
|
||||
effect = image('icons/effects/effects.dmi', src, "ykingvanish", 4)
|
||||
trg << effect
|
||||
spawn(3) qdel(src)
|
||||
else qdel(src)
|
||||
|
||||
|
||||
/obj/kingyellow_phantom
|
||||
name = "Strange Person"
|
||||
desc = "Who is that? They look extremely out-of-place."
|
||||
density = 0
|
||||
anchored = 1
|
||||
var/atom/target = null
|
||||
var/image/showimg = null
|
||||
var/created = null
|
||||
|
||||
New(var/atom/location, var/atom/trg)
|
||||
loc = location
|
||||
target = trg
|
||||
created = world.time
|
||||
showimg = image('icons/misc/critter.dmi', src, "kingyellow", 3)
|
||||
target << showimg
|
||||
src.dir = get_dir(src, target)
|
||||
spawn(5) update()
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
vanish()
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
vanish()
|
||||
|
||||
proc/update()
|
||||
if(!target) vanish()
|
||||
if(!(src in view(7, target)) && (world.time - created) > 40) vanish()
|
||||
if(get_dist(src,target) <= 2) vanish()
|
||||
src.dir = get_dir(src, target)
|
||||
spawn(5) update()
|
||||
|
||||
proc/vanish()
|
||||
new/obj/kingyellow_vanish(src.loc, target)
|
||||
spawn(3) qdel(src)
|
||||
|
||||
/obj/item/book_kinginyellow
|
||||
name = "\"The King In Yellow\""
|
||||
desc = "This appears to be an ancient Book containing a Play."
|
||||
icon = 'icons/obj/writing.dmi'
|
||||
icon_state = "bookkiy"
|
||||
item_state = "paper"
|
||||
layer = OBJ_LAYER
|
||||
|
||||
var/list/readers = new/list()
|
||||
var/atom/curr_phantom = null
|
||||
|
||||
New()
|
||||
work()
|
||||
return
|
||||
|
||||
proc/work()
|
||||
if(readers.len)
|
||||
var/mob/living/L = pick(readers)
|
||||
var/turf/oovTile = get_oov_tile(L)
|
||||
if(oovTile != null && curr_phantom == null)
|
||||
curr_phantom = new/obj/kingyellow_phantom(oovTile, L)
|
||||
|
||||
spawn(30) work()
|
||||
return
|
||||
|
||||
examine()
|
||||
set src in view()
|
||||
if (!issilicon(usr))
|
||||
var/mob/living/carbon/reader = usr
|
||||
if(!istype(reader)) return
|
||||
|
||||
if(usr in readers)
|
||||
var/message = "This appears to be an ancient Book containing a Play.<br><br>"
|
||||
message += "You frantically read the play again ...<br>"
|
||||
message += "You feel as if you're about to faint."
|
||||
boutput(usr, message)
|
||||
|
||||
reader.drowsyness += 3
|
||||
else
|
||||
var/message = "This appears to be an ancient Book containing a Play.<br><br>"
|
||||
message += "The first act tells of a city named Carcosa, and a mysterious \"King in Yellow\"<br>"
|
||||
message += "The second act seems incomplete but ... It is horrifying.<br>"
|
||||
boutput(usr, message)
|
||||
|
||||
for(var/mob/M in readers)
|
||||
boutput(M, "<span style=\"color:red\">You feel the irresistible urge to read the \"The King In Yellow\" again.</span>")
|
||||
readers -= M
|
||||
|
||||
readers += reader
|
||||
return
|
||||
else
|
||||
boutput(usr, "This ancient data storage medium appears to contain data used for entertainment purposes.")
|
||||
|
||||
suicide(var/mob/user as mob)
|
||||
if (ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if (!farting_allowed)
|
||||
return 0
|
||||
user.visible_message("<span style=\"color:red\">[user] farts on [src].<br><b>A mysterious force sucks [user] into the Book!!</b></span>")
|
||||
user.u_equip(src)
|
||||
src.layer = initial(src.layer)
|
||||
src.set_loc(user.loc)
|
||||
if (user.gender == MALE)
|
||||
playsound(get_turf(user), "sound/voice/male_fallscream.ogg", 100, 0, 0, H.get_age_pitch())
|
||||
else
|
||||
playsound(get_turf(user), "sound/voice/female_fallscream.ogg", 100, 0, 0, H.get_age_pitch())
|
||||
user.implode()
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
@@ -0,0 +1,650 @@
|
||||
// The day has come when this warps into existence.
|
||||
// Dear god, imagine the horrors that will soon lurk in here.
|
||||
|
||||
/proc/chs(var/str, var/i)
|
||||
return ascii2text(text2ascii(str,i))
|
||||
|
||||
/**
|
||||
* BASH explode:
|
||||
* Splits a string into string pieces the same way BASH handles this.
|
||||
* - Process quoted strings LTR: Apostrophized strings are unparsed. Quoted strings are parsed.
|
||||
* - Insert parsed strings back into the string by using a placeholder for spaces.
|
||||
* - Split the string with the usual space separation method.
|
||||
* - Return list.
|
||||
*/
|
||||
|
||||
// TODO: Variable processing.
|
||||
|
||||
#define NONE 0
|
||||
#define APOS 1
|
||||
#define QUOT 2
|
||||
|
||||
#define ESCAPE "\\"
|
||||
|
||||
/proc/bash_explode(var/str)
|
||||
var/fin = 0
|
||||
var/state = NONE
|
||||
var/pos = 1
|
||||
var/qpos = 1
|
||||
var/buf = ""
|
||||
while (!fin)
|
||||
switch(state)
|
||||
if (NONE)
|
||||
var/NA = findtext(str, "'", pos)
|
||||
var/NQ = findtext(str, "\"", pos)
|
||||
if (!NA && !NQ)
|
||||
buf += copytext(str, pos)
|
||||
fin = 1
|
||||
else if (NA && !NQ || (NA && NQ && NA < NQ))
|
||||
if (chs(str, NA - 1) == ESCAPE)
|
||||
buf += copytext(str, pos, NA - 1) + "'"
|
||||
pos = NA + 1
|
||||
continue
|
||||
else
|
||||
buf += copytext(str, pos, NA)
|
||||
pos = NA + 1
|
||||
state = APOS
|
||||
else if (NQ && !NA || (NA && NQ && NQ < NA))
|
||||
if (chs(str, NQ - 1) == ESCAPE)
|
||||
buf += copytext(str, pos, NQ - 1) + "\""
|
||||
pos = NQ + 1
|
||||
continue
|
||||
else
|
||||
buf += copytext(str, pos, NQ)
|
||||
pos = NQ + 1
|
||||
qpos = NQ + 1
|
||||
state = QUOT
|
||||
else if (NA == NQ)
|
||||
//??????
|
||||
return null
|
||||
|
||||
if (APOS)
|
||||
var/NA = findtext(str, "'", pos)
|
||||
if (!NA)
|
||||
return null
|
||||
var/temp = copytext(str, pos, NA)
|
||||
buf += dd_replacetext(temp, " ", " ")
|
||||
pos = NA + 1
|
||||
state = NONE
|
||||
|
||||
if (QUOT)
|
||||
var/NQ = findtext(str, "\"", pos)
|
||||
if (!NQ)
|
||||
return null
|
||||
if (copytext(str, NQ - 1, NQ) == ESCAPE)
|
||||
pos = NQ + 1
|
||||
continue
|
||||
var/temp = copytext(str, qpos, NQ)
|
||||
buf += dd_replacetext(dd_replacetext(temp, " ", " "), "\\\"", "\"")
|
||||
pos = NQ + 1
|
||||
state = NONE
|
||||
|
||||
var/list/el = dd_text2list(buf, " ")
|
||||
var/list/ret = list()
|
||||
for (var/s in el)
|
||||
ret += dd_replacetext(s, " ", " ")
|
||||
return ret
|
||||
|
||||
#undef ESCAPE
|
||||
#undef QUOT
|
||||
#undef APOS
|
||||
#undef NONE
|
||||
|
||||
/proc/bash_sanitize(var/data)
|
||||
var/list/allowed_chars = list(" ")
|
||||
var/ret = ""
|
||||
var/lgp = 0
|
||||
for (var/i = 1, i <= length(data), i++)
|
||||
var/char = text2ascii(data, i)
|
||||
var/ord = ascii2text(char)
|
||||
if ((65 <= char && char <= 90) || (97 <= char && char <= 122) || (ord in allowed_chars))
|
||||
if (lgp == 0)
|
||||
lgp = i
|
||||
continue
|
||||
if (lgp == 0)
|
||||
continue
|
||||
ret += copytext(data, lgp, i)
|
||||
lgp = 0
|
||||
if (lgp)
|
||||
ret += copytext(data, lgp)
|
||||
return ret
|
||||
|
||||
|
||||
/obj/nerd_trap_door
|
||||
name = "Heavily locked door"
|
||||
desc = "Man, whatever is in here must be pretty valuable. This door seems to be indestructible and features an unrealistic amount of keyholes."
|
||||
var/list/expected = list("silver key", "skeleton key", "literal skeleton key", "hot iron key", "cold steel key", "onyx key", "key lime pie", "futuristic key", "virtual key", "golden key", "bee key", "iron key", "iridium key", "lunar key")
|
||||
var/list/unlocked = list()
|
||||
var/list/ol = list()
|
||||
icon = 'icons/misc/aprilfools.dmi'
|
||||
icon_state = "hld0"
|
||||
opacity = 1
|
||||
density = 1
|
||||
anchored = 1
|
||||
|
||||
examine()
|
||||
..()
|
||||
boutput(usr, "Your keen skills of observation tell you that [expected.len - unlocked.len] out of the [expected.len] locks are locked.")
|
||||
|
||||
attackby(var/obj/item/I, var/mob/user)
|
||||
if (istype(I, /obj/item/device/key))
|
||||
var/kname = null
|
||||
if (I.name in expected)
|
||||
kname = I.name
|
||||
//for (var/N in expected)
|
||||
// if (dd_hasprefix(I.name, N))
|
||||
// break
|
||||
if (kname)
|
||||
boutput(user, "<span style='color:blue'>You insert the [I.name] into the [kname]hole and turn it. The door emits a loud click.</span>")
|
||||
playsound(src.loc, "sound/effects/thunk.ogg", 60, 1)
|
||||
if (kname in unlocked)
|
||||
unlocked -= kname
|
||||
overlays -= ol[kname]
|
||||
ol -= kname
|
||||
else
|
||||
unlocked += kname
|
||||
var/image/IM = image('icons/misc/aprilfools.dmi', "[kname]hole")
|
||||
ol[kname] = IM
|
||||
overlays += IM
|
||||
else
|
||||
boutput(user, "<span style='color:red'>You cannot find a matching keyhole for that key!</span>")
|
||||
else if (istype(I, /obj/item/reagent_containers/food/snacks/pie/lime))
|
||||
if ("key lime pie" in expected)
|
||||
boutput(user, "<span style='color:blue'>You insert the [I.name] into the key lime piehole and turn it. The door emits a loud click.</span>")
|
||||
playsound(src.loc, "sound/effects/thunk.ogg", 60, 1)
|
||||
if ("key lime pie" in unlocked)
|
||||
unlocked -= "key lime pie"
|
||||
overlays -= ol["key lime pie"]
|
||||
ol -= "key lime pie"
|
||||
else
|
||||
unlocked += "key lime pie"
|
||||
var/image/IM = image('icons/misc/aprilfools.dmi', "key lime piehole")
|
||||
ol["key lime pie"] = IM
|
||||
overlays += IM
|
||||
else
|
||||
boutput(user, "<span style='color:red'>You cannot find a matching keyhole for that key!</span>")
|
||||
|
||||
Bumped(var/mob/M)
|
||||
if (!istype(M))
|
||||
return
|
||||
attack_hand(M)
|
||||
|
||||
attack_hand(var/mob/user)
|
||||
if (!density)
|
||||
return
|
||||
if (unlocked.len == expected.len)
|
||||
open()
|
||||
else
|
||||
boutput(user, "<span style='color:red'>The door won't budge!</span>")
|
||||
|
||||
proc/open()
|
||||
if (unlocked.len != expected.len)
|
||||
return
|
||||
playsound(src.loc, "sound/machines/door_open.ogg", 50, 1)
|
||||
icon_state = "hld1"
|
||||
density = 0
|
||||
opacity = 0
|
||||
overlays.len = 0
|
||||
|
||||
meteorhit()
|
||||
return
|
||||
|
||||
ex_act()
|
||||
return
|
||||
|
||||
blob_act()
|
||||
return
|
||||
|
||||
bullet_act()
|
||||
return
|
||||
|
||||
/obj/steel_beams
|
||||
name = "steel beams"
|
||||
desc = "A bunch of unfortunately placed, tightly packed steel beams. You cannot get a meaningful glimpse of what's on the other side."
|
||||
anchored = 1
|
||||
density = 1
|
||||
opacity = 1
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "beams"
|
||||
|
||||
meteorhit()
|
||||
return
|
||||
|
||||
ex_act()
|
||||
return
|
||||
|
||||
blob_act()
|
||||
return
|
||||
|
||||
bullet_act()
|
||||
return
|
||||
|
||||
/obj/faint_shimmer
|
||||
name = "faint shimmer"
|
||||
desc = "Huh."
|
||||
anchored = 1
|
||||
density = 0
|
||||
invisibility = 2
|
||||
blend_mode = 4
|
||||
icon = 'icons/misc/old_or_unused.dmi'
|
||||
icon_state = "noise5"
|
||||
var/decloaked_type = /obj/item/storage/toilet
|
||||
|
||||
dense
|
||||
density = 1
|
||||
|
||||
// Aiming bow action.
|
||||
/datum/action/bar/aim
|
||||
duration = -1
|
||||
var/obj/item/gun/bow/bow = null
|
||||
var/progress = 0
|
||||
var/direction = 1
|
||||
var/progression = 0.18
|
||||
var/linger = 15
|
||||
var/moved = 0
|
||||
|
||||
New(var/mob/M, var/obj/item/gun/bow/B)
|
||||
owner = M
|
||||
bow = B
|
||||
..()
|
||||
|
||||
onStart()
|
||||
..()
|
||||
playsound(get_turf(owner), 'sound/effects/bow_aim.ogg', 75, 1)
|
||||
owner.visible_message("<span style='color:red'>[owner] pulls the string on [bow]!</span>", "<span style='color:blue'>You pull the string on [bow]!</span>")
|
||||
|
||||
onDelete()
|
||||
if (bow)
|
||||
bow.aim = null
|
||||
..()
|
||||
|
||||
onEnd()
|
||||
boutput(owner, "<span style='color:red'>You couldn't hold the string any longer.</span>")
|
||||
if (bow)
|
||||
bow.aim = null
|
||||
..()
|
||||
|
||||
interrupt(var/flag)
|
||||
var/mob/mowner = owner
|
||||
if(flag == INTERRUPT_MOVE && mowner.m_intent == "walk")
|
||||
bar.color = "#FF0000"
|
||||
switch (direction)
|
||||
if (-1)
|
||||
progress = max(0, progress - 4 * progression)
|
||||
progression += 0.035
|
||||
if (!progress)
|
||||
state = ACTIONSTATE_FINISH
|
||||
if (0)
|
||||
linger = max(linger - 4, 0)
|
||||
if (linger)
|
||||
direction = 1
|
||||
progress = max(0, progress - 4 * progression)
|
||||
moved = 1
|
||||
else
|
||||
direction = -1
|
||||
moved = 0
|
||||
if (1)
|
||||
moved = 2
|
||||
linger = max(0, linger - 2)
|
||||
progress = max(0, progress - 3 * progression)
|
||||
if (!linger)
|
||||
direction = -1
|
||||
moved = 0
|
||||
return
|
||||
..()
|
||||
|
||||
onUpdate()
|
||||
if (!progress && direction == -1)
|
||||
state = ACTIONSTATE_FINISH
|
||||
return
|
||||
if (moved)
|
||||
moved--
|
||||
linger = max(0, linger - 1)
|
||||
if (linger <= 0)
|
||||
direction = -1
|
||||
moved = 0
|
||||
return
|
||||
switch (direction)
|
||||
if (-1)
|
||||
progress = max(0, progress - progression)
|
||||
if (!progress)
|
||||
state = ACTIONSTATE_FINISH
|
||||
if (0)
|
||||
linger--
|
||||
if (linger <= 0)
|
||||
direction = -1
|
||||
if (1)
|
||||
progress = min(1, progress + progression)
|
||||
if (progress == 1)
|
||||
direction = 0
|
||||
var/complete = progress
|
||||
bar.color = "#0000FF"
|
||||
bar.transform = matrix(complete, 1, MATRIX_SCALE)
|
||||
bar.pixel_x = -nround( ((30 - (30 * complete)) / 2) )
|
||||
|
||||
/obj/item/arrow
|
||||
name = "steel-headed arrow"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = null
|
||||
flags = FPRINT | TABLEPASS | SUPPRESSATTACK
|
||||
// placeholder
|
||||
var/datum/material/head_material
|
||||
var/datum/material/shaft_material
|
||||
var/image/shaft
|
||||
var/image/head
|
||||
amount = 1
|
||||
|
||||
New()
|
||||
..()
|
||||
shaft = image(icon, "arrow_base")
|
||||
head = image(icon, "arrow_head")
|
||||
reagents = new /datum/reagents(3)
|
||||
reagents.my_atom = src
|
||||
overlays += shaft
|
||||
overlays += head
|
||||
|
||||
examine()
|
||||
..()
|
||||
if (amount > 1)
|
||||
boutput(usr, "<span style='color:blue'>This is a stack of [amount] arrows. Picking it up will take a single arrow from the stack.")
|
||||
if (reagents.total_volume)
|
||||
boutput(usr, "<span style='color:blue'>The tip of the arrow is coated with reagents.</span>")
|
||||
|
||||
clone(var/newloc = null)
|
||||
var/obj/item/arrow/O = new(loc)
|
||||
if (newloc)
|
||||
O.set_loc(newloc)
|
||||
O.setHeadMaterial(head_material)
|
||||
O.setShaftMaterial(shaft_material)
|
||||
|
||||
attack_hand(var/mob/user)
|
||||
if (amount > 1)
|
||||
amount--
|
||||
var/obj/item/arrow/O = clone(loc)
|
||||
user.put_in_hand_or_drop(O, user.hand)
|
||||
boutput(usr, "<span style='color:blue'>You take \a [src] from the stack of [src]s. [amount] remaining on the stack.")
|
||||
else
|
||||
..()
|
||||
|
||||
set_loc()
|
||||
..()
|
||||
if (isturf(loc))
|
||||
overlays.len = 0
|
||||
head.layer = initial(head.layer)
|
||||
shaft.layer = initial(shaft.layer)
|
||||
overlays += shaft
|
||||
overlays += head
|
||||
else
|
||||
overlays.len = 0
|
||||
head.layer = HUD_LAYER+3
|
||||
shaft.layer = HUD_LAYER+3
|
||||
overlays += shaft
|
||||
overlays += head
|
||||
|
||||
proc/setName()
|
||||
if (head_material && shaft_material)
|
||||
name = "[head_material]-headed [shaft_material] arrow"
|
||||
else if (head_material)
|
||||
name = "[head_material]-headed arrow"
|
||||
else if (shaft_material)
|
||||
name = "steel-headed [shaft_material] arrow"
|
||||
else
|
||||
name = "steel-headed arrow"
|
||||
|
||||
proc/setHeadMaterial(var/datum/material/M)
|
||||
head_material = copyMaterial(M)
|
||||
overlays -= head
|
||||
if (M)
|
||||
head.color = M.color
|
||||
head.alpha = M.alpha
|
||||
else
|
||||
head.color = null
|
||||
head.alpha = 255
|
||||
overlays += head
|
||||
setName()
|
||||
|
||||
proc/setShaftMaterial(var/datum/material/M)
|
||||
shaft_material = copyMaterial(M)
|
||||
material = shaft_material
|
||||
overlays -= shaft
|
||||
if (M)
|
||||
shaft.color = M.color
|
||||
shaft.alpha = M.alpha
|
||||
else
|
||||
shaft.color = null
|
||||
shaft.alpha = 255
|
||||
overlays += head
|
||||
setName()
|
||||
|
||||
afterattack(var/atom/target, var/mob/user, reach)
|
||||
if (!reach)
|
||||
return
|
||||
if (istype(target, /mob/living))
|
||||
if (prob(50))
|
||||
user.visible_message("<span style='color:red'><b>[user] tries to stab [target] with [src] but misses!</b></span>")
|
||||
playsound(get_turf(user), 'sound/weapons/punchmiss.ogg', 25, 1, 1)
|
||||
return
|
||||
user.visible_message("<span style='color:red'><b>[user] stabs [target] with [src]!</b></span>")
|
||||
user.u_equip(src)
|
||||
playsound(get_turf(user), 'sound/effects/bloody_stab.ogg', 75, 1)
|
||||
if (ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/obj/item/implant/projectile/arrow/A = new
|
||||
A.material = head_material
|
||||
A.arrow = src
|
||||
A.name = name
|
||||
set_loc(A)
|
||||
A.set_loc(target)
|
||||
A.owner = target
|
||||
H.implant += A
|
||||
A.implanted(H, null, 100)
|
||||
reagents.reaction(target, 2)
|
||||
reagents.trans_to(target, reagents.total_volume)
|
||||
take_bleeding_damage(target, null, 8, DAMAGE_STAB)
|
||||
if (head_material)
|
||||
head_material.triggerOnAttack(src, user, target)
|
||||
else
|
||||
var/obj/item/I = target
|
||||
if (istype(I) && I.is_open_container() == 1 && I.reagents)
|
||||
if (reagents.total_volume == reagents.maximum_volume)
|
||||
boutput(user, "<span style='color:red'>[src] is already coated in the maximum amount of reagents it can hold.</span>")
|
||||
else if (!I.reagents.total_volume)
|
||||
boutput(user, "<span style='color:red'>[I] is empty.</span>")
|
||||
else
|
||||
var/amt = min(reagents.maximum_volume - reagents.total_volume, I.reagents.total_volume)
|
||||
logTheThing("combat", user, null, "poisoned [src] [log_reagents(I)] at [log_loc(user)].") // Logs would be nice (Convair880).
|
||||
I.reagents.trans_to(src, amt)
|
||||
boutput(user, "<span style='color:blue'>You dip [src] into [I], coating it with [amt] units of reagents.</span>")
|
||||
|
||||
/obj/item/arrowhead
|
||||
name = "arrowhead"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "arrowhead"
|
||||
|
||||
examine()
|
||||
..()
|
||||
boutput(usr, "There [amount == 1 ? "is" : "are"] [amount] arrowhead[amount != 1 ? "s" : null] in the stack.")
|
||||
|
||||
/obj/item/implant/projectile/arrow
|
||||
name = "arrow"
|
||||
icon = null
|
||||
icon_state = null
|
||||
desc = "An arrow."
|
||||
var/obj/item/arrow/arrow = null
|
||||
|
||||
New()
|
||||
..()
|
||||
implant_overlay = image(icon='icons/mob/human.dmi', icon_state="arrow_stick_[rand(0,4)]", layer=MOB_EFFECT_LAYER)
|
||||
|
||||
// Hack.
|
||||
set_loc()
|
||||
..()
|
||||
if (isturf(loc))
|
||||
if (arrow)
|
||||
arrow.set_loc(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/quiver
|
||||
name = "quiver"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "quiver-0"
|
||||
wear_image_icon = 'icons/mob/back.dmi'
|
||||
item_state = "quiver"
|
||||
flags = FPRINT | TABLEPASS | ONBACK
|
||||
|
||||
attackby(var/obj/item/arrow/I, var/mob/user)
|
||||
if (!istype(I))
|
||||
boutput(user, "<span style='color:red'>That cannot be placed in [src]!</span>")
|
||||
return
|
||||
user.u_equip(I)
|
||||
I.loc = src
|
||||
maptext = "[contents.len]"
|
||||
icon_state = "quiver-[min(contents.len, 4)]"
|
||||
|
||||
attack_hand(var/mob/user)
|
||||
if (src in user)
|
||||
if (contents.len)
|
||||
boutput(user, "<span style='color:blue'>You take [contents[1]] from [src].</span>")
|
||||
user.put_in_hand(contents[1], user.hand)
|
||||
if (contents.len)
|
||||
maptext = "[contents.len]"
|
||||
else
|
||||
maptext = null
|
||||
icon_state = "quiver-[min(contents.len, 4)]"
|
||||
return
|
||||
..()
|
||||
|
||||
MouseDrop(atom/over_object, src_location, over_location)
|
||||
..()
|
||||
var/obj/screen/hud/S = over_object
|
||||
if (istype(S))
|
||||
playsound(src.loc, "rustle", 50, 1, -5)
|
||||
if (!usr.restrained() && !usr.stat && src.loc == usr)
|
||||
if (S.id == "rhand")
|
||||
if (!usr.r_hand)
|
||||
usr.u_equip(src)
|
||||
usr.put_in_hand(src, 0)
|
||||
else
|
||||
if (S.id == "lhand")
|
||||
if (!usr.l_hand)
|
||||
usr.u_equip(src)
|
||||
usr.put_in_hand(src, 1)
|
||||
return
|
||||
if (usr.is_in_hands(src))
|
||||
var/turf/T = over_object
|
||||
if (istype(T, /obj/table))
|
||||
T = get_turf(T)
|
||||
if (!(usr in range(1, T)))
|
||||
return
|
||||
if (istype(T))
|
||||
for (var/obj/O in T)
|
||||
if (O.density && !istype(O, /obj/table) && !istype(O, /obj/rack))
|
||||
return
|
||||
if (!T.density)
|
||||
usr.visible_message("<span style=\"color:red\">[usr] dumps the contents of [src] onto [T]!</span>")
|
||||
for (var/obj/item/I in src)
|
||||
I.set_loc(T)
|
||||
I.layer = initial(I.layer)
|
||||
|
||||
/datum/projectile/arrow
|
||||
name = "arrow"
|
||||
power = 25
|
||||
dissipation_delay = 4
|
||||
dissipation_rate = 5
|
||||
shot_sound = 'sound/effects/bow_fire.ogg'
|
||||
damage_type = D_KINETIC
|
||||
hit_type = DAMAGE_STAB
|
||||
implanted = null
|
||||
ks_ratio = 1.0
|
||||
icon_turf_hit = "bhole"
|
||||
icon_state = "arrow"
|
||||
|
||||
on_hit(var/atom/A, angle, var/obj/projectile/P)
|
||||
if (ismob(A))
|
||||
playsound(get_turf(A), 'sound/effects/bloody_stab.ogg', 75, 1)
|
||||
var/obj/item/implant/projectile/arrow/B = P.implanted
|
||||
if (istype(B))
|
||||
if (B.material)
|
||||
B.material.triggerOnAttack(B, null, A)
|
||||
B.arrow.reagents.reaction(A, 2)
|
||||
B.arrow.reagents.trans_to(A, B.arrow.reagents.total_volume)
|
||||
take_bleeding_damage(A, null, round(src.power / 3), src.hit_type)
|
||||
|
||||
|
||||
/obj/item/gun/bow
|
||||
name = "bow"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "bow"
|
||||
var/obj/item/arrow/loaded = null
|
||||
var/datum/action/bar/aim/aim = null
|
||||
current_projectile = new/datum/projectile/arrow
|
||||
spread_angle = 30
|
||||
force = 5
|
||||
|
||||
attack_hand(var/mob/user)
|
||||
if (loaded && user.is_in_hands(src))
|
||||
user.put_in_hand_or_drop(loaded)
|
||||
boutput(user, "<span style='color:blue'>You unload the arrow from the bow.</span>")
|
||||
overlays.len = 0
|
||||
loaded = null
|
||||
else
|
||||
..()
|
||||
|
||||
attack(var/mob/target, var/mob/user)
|
||||
user.lastattacked = target
|
||||
target.lastattacker = user
|
||||
target.lastattackertime = world.time
|
||||
|
||||
if(isliving(target) && aim)
|
||||
src.shoot_point_blank(target, user)
|
||||
else
|
||||
..()
|
||||
|
||||
#ifdef DATALOGGER
|
||||
game_stats.Increment("violence")
|
||||
#endif
|
||||
return
|
||||
|
||||
|
||||
attack_self(var/mob/user)
|
||||
if (!aim && loaded)
|
||||
aim = new(user, src)
|
||||
actions.start(aim, user)
|
||||
|
||||
process_ammo(var/mob/user)
|
||||
if (!loaded)
|
||||
boutput(user, "<span style='color:red'>Nothing is loaded in the bow!</span>")
|
||||
return 0
|
||||
overlays.len = 0
|
||||
var/obj/item/implant/projectile/arrow/A = new
|
||||
A.material = loaded.head_material
|
||||
A.arrow = loaded
|
||||
A.name = loaded.name
|
||||
current_projectile.name = loaded.name
|
||||
loaded.set_loc(A)
|
||||
current_projectile.implanted = A
|
||||
loaded = null
|
||||
return 1
|
||||
|
||||
canshoot()
|
||||
return loaded != null
|
||||
|
||||
pixelaction(atom/target, params, mob/user, reach)
|
||||
if (!loaded)
|
||||
boutput(user, "<span style='color:red'>Nothing is loaded in the bow!</span>")
|
||||
return 1
|
||||
spread_angle = 30
|
||||
if (aim)
|
||||
spread_angle = (1 - aim.progress) * 30
|
||||
aim.state = ACTIONSTATE_FINISH
|
||||
..()
|
||||
|
||||
attackby(var/obj/item/arrow/I, var/mob/user)
|
||||
if (!istype(I))
|
||||
return
|
||||
if (loaded)
|
||||
boutput(user, "<span style='color:red'>An arrow is already loaded onto the bow.</span>")
|
||||
overlays += I
|
||||
user.u_equip(I)
|
||||
loaded = I
|
||||
I.loc = src
|
||||
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
triggerOnAttacked(var/obj/item/owner, var/mob/attacker, var/mob/attacked, var/atom/weapon)
|
||||
triggerOnAttack(var/obj/item/owner, var/mob/attacker, var/mob/attacked)
|
||||
triggerOnLife(var/mob/M, var/obj/item/I)
|
||||
triggerOnAdd(var/owner)
|
||||
triggerChem(var/location, var/chem, var/amount)
|
||||
triggerPickup(var/mob/M)
|
||||
triggerDrop(var/mob/M)
|
||||
triggerTemp(var/owner, var/temp)
|
||||
triggerExp(var/owner, var/severity)/
|
||||
triggerOnEntered(var/atom/owner, var/atom/entering)
|
||||
*/
|
||||
|
||||
|
||||
//!!!!!!!!!!!!!!!!!!!! THINGS LIKE GOLD SPARKLES ARE NOT REMOVED WHEN MATERIAL CHANGES!. MOVE THESE TO NEW APPEARANCE SYSTEM.
|
||||
|
||||
/datum/materialProc
|
||||
var/id = null
|
||||
var/max_generations = 2 //After how many material "generations" this trait disappears. -1 = does not disappear.
|
||||
var/desc = "" //Optional simple sentence that describes how the traits appears on the material. i.e. "It is shiny."
|
||||
|
||||
proc/execute()
|
||||
return
|
||||
|
||||
/datum/materialProc/ethereal_add
|
||||
id = "ethereal_add"
|
||||
desc = "It is almost impossible to grasp."
|
||||
|
||||
execute(var/atom/owner)
|
||||
owner.density = 0
|
||||
return
|
||||
|
||||
/datum/materialProc/wendigo_temp_onlife
|
||||
id = "wendigo_temp"
|
||||
desc = "It feels furry."
|
||||
|
||||
execute(var/mob/M, var/obj/item/I)
|
||||
if(M)
|
||||
M.bodytemperature = 310
|
||||
return
|
||||
|
||||
/datum/materialProc/fail_explosive
|
||||
id = "fail_explosive"
|
||||
var/lastTrigger = 0
|
||||
var/trigger_chance = 100
|
||||
|
||||
New(var/chance = 100)
|
||||
trigger_chance = chance
|
||||
..()
|
||||
|
||||
execute(var/atom/location)
|
||||
if(world.time - lastTrigger < 100) return
|
||||
lastTrigger = world.time
|
||||
var/turf/tloc = get_turf(location)
|
||||
explosion(location, location, tloc, 1, 2, 3, 4, 1)
|
||||
location.visible_message("<span style=\"color:red\">[location] explodes!</span>")
|
||||
return
|
||||
|
||||
/datum/materialProc/generic_radiation_onenter
|
||||
id = "generic_radiation_onenter"
|
||||
desc = "It glows faintly."
|
||||
|
||||
execute(var/atom/owner, var/atom/entering)
|
||||
if(ismob(entering))
|
||||
var/mob/M = entering
|
||||
M.irradiate(1)
|
||||
return
|
||||
|
||||
/datum/materialProc/generic_reagent_onattacked
|
||||
id = "generic_reagent_onattacked"
|
||||
var/trigger_chance = 100
|
||||
var/limit = 0
|
||||
var/limit_count = 0
|
||||
var/lastTrigger = 0
|
||||
var/trigger_delay = 0
|
||||
var/reagent_id = ""
|
||||
var/reagent_amount = 0
|
||||
|
||||
New(var/reagid = "carbon", var/amt = 2, var/chance = 100, var/limit_t = 0, var/tdelay = 50)
|
||||
trigger_chance = chance
|
||||
limit = limit_t
|
||||
trigger_delay = tdelay
|
||||
reagent_id = reagid
|
||||
reagent_amount = amt
|
||||
..()
|
||||
|
||||
execute(var/obj/item/owner, var/mob/attacker, var/mob/attacked, var/atom/weapon)
|
||||
if(limit && limit_count >= limit) return
|
||||
if(world.time - lastTrigger < trigger_delay) return
|
||||
lastTrigger = world.time
|
||||
if(prob(trigger_chance))
|
||||
if(attacked.reagents)
|
||||
attacked.reagents.add_reagent(reagent_id, reagent_amount, null, T0C)
|
||||
return
|
||||
|
||||
/datum/materialProc/generic_explode_attack
|
||||
id = "generic_explode_attack"
|
||||
var/trigger_chance = 100
|
||||
var/explode_limit = 0
|
||||
var/explode_count = 0
|
||||
var/lastTrigger = 0
|
||||
|
||||
desc = "It looks dangerously unstable."
|
||||
|
||||
New(var/chance = 100, var/limit = 0)
|
||||
trigger_chance = chance
|
||||
explode_limit = limit
|
||||
..()
|
||||
|
||||
execute(var/obj/item/owner, var/mob/attacker, var/mob/attacked)
|
||||
if(explode_limit && explode_count >= explode_limit) return
|
||||
if(world.time - lastTrigger < 50) return
|
||||
lastTrigger = world.time
|
||||
if(prob(trigger_chance))
|
||||
explode_count++
|
||||
var/turf/tloc = get_turf(attacked)
|
||||
explosion(owner, tloc, 0, 1, 2, 3, 1)
|
||||
tloc.visible_message("<span style=\"color:red\">[owner] explodes!</span>")
|
||||
qdel(owner)
|
||||
return
|
||||
|
||||
/datum/materialProc/generic_fireflash
|
||||
id = "generic_fireflash"
|
||||
var/lastTrigger = 0
|
||||
|
||||
execute(var/atom/location, var/temp)
|
||||
if(temp < T0C + 200)
|
||||
return
|
||||
if(world.time - lastTrigger < 1200) return
|
||||
lastTrigger = world.time
|
||||
fireflash(get_turf(location), 1)
|
||||
return
|
||||
|
||||
/datum/materialProc/generic_itchy_onlife
|
||||
id = "generic_itchy_onlife"
|
||||
desc = "It makes your hands itch."
|
||||
|
||||
execute(var/mob/M, var/obj/item/I)
|
||||
if(prob(20)) M.emote(pick("twitch", "laugh", "sneeze", "cry"))
|
||||
if(prob(10))
|
||||
boutput(M, "<span style=\"color:blue\"><b>Something tickles!</b></span>")
|
||||
M.emote(pick("laugh", "giggle"))
|
||||
if(prob(8))
|
||||
M.visible_message("<span style=\"color:red\"><b>[M.name]</b> scratches at an itch.</span>")
|
||||
random_brute_damage(M, 1)
|
||||
M.stunned += rand(0,1)
|
||||
M.emote("grumble")
|
||||
if(prob(8))
|
||||
boutput(M, "<span style=\"color:red\"><b>So itchy!</b></span>")
|
||||
random_brute_damage(M, 2)
|
||||
if(prob(1))
|
||||
boutput(M, "<span style=\"color:red\"><b><font size='[rand(2,5)]'>AHHHHHH!</font></b></span>")
|
||||
random_brute_damage(M,5)
|
||||
M.weakened +=5
|
||||
M.make_jittery(6)
|
||||
M.visible_message("<span style=\"color:red\"><b>[M.name]</b> falls to the floor, scratching themselves violently!</span>")
|
||||
M.emote("scream")
|
||||
return
|
||||
|
||||
/datum/materialProc/generic_reagent_onattack_depleting
|
||||
id = "generic_reagent_onattack_depleting"
|
||||
var/reag_id = "carbon"
|
||||
var/reag_amt = 1
|
||||
var/reag_chance = 10
|
||||
var/charges_left = 10
|
||||
|
||||
New(var/reagent_id = "carbon", var/amount = 1, var/chance = 10, var/charges = 10)
|
||||
reag_id = reagent_id
|
||||
reag_amt = amount
|
||||
reag_chance = chance
|
||||
charges_left = charges
|
||||
..()
|
||||
|
||||
execute(var/obj/item/owner, var/mob/attacker, var/mob/attacked)
|
||||
if(prob(reag_chance) && attacked && attacked.reagents)
|
||||
charges_left--
|
||||
attacked.reagents.add_reagent(reag_id, reag_amt, null, T0C)
|
||||
if(!charges_left)
|
||||
if(owner.material)
|
||||
owner.material.triggersOnAttack.Remove(src)
|
||||
return
|
||||
|
||||
/datum/materialProc/generic_reagent_onattack
|
||||
id = "generic_reagent_onattack"
|
||||
var/reag_id = "carbon"
|
||||
var/reag_amt = 1
|
||||
var/reag_chance = 10
|
||||
|
||||
New(var/reagent_id = "carbon", var/amount = 1, var/chance = 10)
|
||||
reag_id = reagent_id
|
||||
reag_amt = amount
|
||||
reag_chance = chance
|
||||
..()
|
||||
|
||||
execute(var/obj/item/owner, var/mob/attacker, var/mob/attacked)
|
||||
if(prob(reag_chance) && attacked && attacked.reagents)
|
||||
attacked.reagents.add_reagent(reag_id, reag_amt, null, T0C)
|
||||
return
|
||||
|
||||
/datum/materialProc/generic_reagent_onlife
|
||||
id = "generic_reagent_onlife"
|
||||
var/reag_id = "carbon"
|
||||
var/reag_amt = 1
|
||||
|
||||
New(var/reagent_id = "carbon", var/amount = 1)
|
||||
reag_id = reagent_id
|
||||
reag_amt = amount
|
||||
..()
|
||||
|
||||
execute(var/mob/M, var/obj/item/I)
|
||||
if(M && M.reagents)
|
||||
M.reagents.add_reagent(reag_id, reag_amt, null, T0C)
|
||||
return
|
||||
|
||||
/datum/materialProc/generic_reagent_onlife_depleting
|
||||
id = "generic_reagent_onlife_depleting"
|
||||
var/reag_id = "carbon"
|
||||
var/reag_amt = 1
|
||||
var/max_volume = 0
|
||||
var/added = 0
|
||||
|
||||
New(var/reagent_id = "carbon", var/amount = 1, var/maxadd = 50)
|
||||
reag_id = reagent_id
|
||||
reag_amt = amount
|
||||
max_volume = maxadd
|
||||
..()
|
||||
|
||||
execute(var/mob/M, var/obj/item/I)
|
||||
if(M && M.reagents)
|
||||
M.reagents.add_reagent(reag_id, reag_amt, null, T0C)
|
||||
added += reag_amt
|
||||
if(added >= max_volume)
|
||||
if(I.material)
|
||||
I.material.triggersOnLife.Remove(src)
|
||||
return
|
||||
|
||||
/datum/materialProc/generic_explosive
|
||||
id = "generic_explosive"
|
||||
var/lastTrigger = 0
|
||||
|
||||
execute(var/atom/location, var/temp)
|
||||
if(temp < T0C + 100)
|
||||
return
|
||||
if(world.time - lastTrigger < 100) return
|
||||
lastTrigger = world.time
|
||||
var/turf/tloc = get_turf(location)
|
||||
explosion(location, tloc, 1, 2, 3, 4, 1)
|
||||
location.visible_message("<span style=\"color:red\">[location] explodes!</span>")
|
||||
return
|
||||
|
||||
/datum/materialProc/flash_hit
|
||||
id = "flash_hit"
|
||||
var/last_trigger = 0
|
||||
desc = "Every now and then it produces some bright sparks."
|
||||
|
||||
execute(var/obj/item/owner, var/mob/attacker, var/mob/attacked, var/atom/weapon)
|
||||
if((world.time - last_trigger) >= 600)
|
||||
last_trigger = world.time
|
||||
attacked.visible_message("<span style=\"color:red\">[owner] emits a flash of light!</span>")
|
||||
for (var/mob/living/carbon/M in all_viewers(5, attacked))
|
||||
M.apply_flash(8, 0, 0, 0, 3)
|
||||
return
|
||||
|
||||
/datum/materialProc/smoke_hit
|
||||
id = "smoke_hit"
|
||||
desc = "Faint wisps of smoke rise from it."
|
||||
var/last_trigger = 0
|
||||
|
||||
execute(var/obj/item/owner, var/mob/attacker, var/mob/attacked, var/atom/weapon)
|
||||
if((world.time - last_trigger) >= 200)
|
||||
last_trigger = world.time
|
||||
attacked.visible_message("<span style=\"color:red\">[owner] emits a puff of smoke!</span>")
|
||||
for(var/turf/T in view(1, attacked))
|
||||
harmless_smoke_puff(get_turf(T))
|
||||
return
|
||||
|
||||
/datum/materialProc/gold_add
|
||||
id = "gold_add"
|
||||
desc = "It's very shiny."
|
||||
|
||||
execute(var/location)
|
||||
if(!particleMaster.CheckSystemExists(/datum/particleSystem/sparkles, location))
|
||||
particleMaster.SpawnSystem(new /datum/particleSystem/sparkles(location))
|
||||
return
|
||||
|
||||
/datum/materialProc/telecrystal_entered
|
||||
id = "telecrystal_entered"
|
||||
|
||||
execute(var/atom/owner, var/atom/movable/entering)
|
||||
if(prob(50) && owner && !isrestrictedz(owner.z))
|
||||
. = get_turf(pick(orange(2, owner)))
|
||||
if (isturf(.))
|
||||
entering.visible_message("<span style=\"color:red\">[entering] is warped away!</span>")
|
||||
boutput(entering, "<span style=\"color:red\">You suddenly teleport ...</span>")
|
||||
entering.set_loc(.)
|
||||
return
|
||||
|
||||
/datum/materialProc/telecrystal_life
|
||||
id = "telecrystal_life"
|
||||
|
||||
execute(var/mob/M, var/obj/item/I)
|
||||
if(prob(5) && M && !isrestrictedz(M.z))
|
||||
. = get_turf(pick(orange(8, M)))
|
||||
if (isturf(.))
|
||||
M.visible_message("<span style=\"color:red\">[M] is warped away!</span>")
|
||||
boutput(M, "<span style=\"color:red\">You suddenly teleport ...</span>")
|
||||
M.set_loc(.)
|
||||
return
|
||||
|
||||
/datum/materialProc/plasmastone
|
||||
id = "plasmastone"
|
||||
|
||||
execute(var/location) //exp and temp both have the location as first argument so i can use this for both.
|
||||
for (var/turf/simulated/floor/target in range(1,location))
|
||||
if(!target.blocks_air && target.air)
|
||||
if(target.parent)
|
||||
target.parent.suspend_group_processing()
|
||||
|
||||
var/datum/gas_mixture/payload = unpool(/datum/gas_mixture)
|
||||
payload.toxins = 100
|
||||
target.air.merge(payload)
|
||||
return
|
||||
|
||||
/datum/materialProc/miracle_add
|
||||
id = "miracle_add"
|
||||
|
||||
execute(var/location)
|
||||
animate_rainbow_glow(location)
|
||||
return
|
||||
|
||||
/datum/materialProc/cerenkite_add
|
||||
id = "cerenkite_add"
|
||||
|
||||
execute(var/location)
|
||||
animate_flash_color_fill_inherit(location,"#1122EE",-1,40)
|
||||
return
|
||||
|
||||
/datum/materialProc/cerenkite_life
|
||||
id = "cerenkite_life"
|
||||
|
||||
execute(var/mob/M, var/obj/item/I)
|
||||
M.irradiate(1)
|
||||
return
|
||||
|
||||
/datum/materialProc/cerenkite_pickup
|
||||
id = "cerenkite_pickup"
|
||||
|
||||
execute(var/mob/M)
|
||||
M.irradiate(10)
|
||||
return
|
||||
|
||||
/datum/materialProc/erebite_flash
|
||||
id = "erebite_flash"
|
||||
|
||||
execute(var/location)
|
||||
animate_flash_color_fill_inherit(location,"#FF7711",-1,10)
|
||||
return
|
||||
|
||||
/datum/materialProc/erebite_temp
|
||||
id = "erebite_temp"
|
||||
var/lastTrigger = 0
|
||||
|
||||
execute(var/atom/location, var/temp)
|
||||
if(temp < T0C + 10) return
|
||||
if(world.time - lastTrigger < 100) return
|
||||
lastTrigger = world.time
|
||||
var/turf/tloc = get_turf(location)
|
||||
explosion(location, tloc, 0, 1, 2, 3, 1)
|
||||
location.visible_message("<span style=\"color:red\">[location] explodes!</span>")
|
||||
return
|
||||
|
||||
/datum/materialProc/erebite_exp
|
||||
id = "erebite_exp"
|
||||
var/lastTrigger = 0
|
||||
|
||||
execute(var/atom/location, var/sev)
|
||||
if(world.time - lastTrigger < 100) return
|
||||
lastTrigger = world.time
|
||||
var/turf/tloc = get_turf(location)
|
||||
if(sev > 0 && sev < 4)
|
||||
location.visible_message("<span style=\"color:red\">[location] explodes!</span>")
|
||||
switch(sev)
|
||||
if(1)
|
||||
explosion(location, tloc, 0, 1, 2, 3, 1)
|
||||
if(2)
|
||||
explosion(location, tloc, -1, 0, 1, 2, 1)
|
||||
if(3)
|
||||
explosion(location, tloc, -1, -1, 0, 1, 1)
|
||||
qdel(location)
|
||||
return
|
||||
|
||||
//triggerOnAttack(var/obj/item/owner, var/mob/attacker, var/mob/attacked)
|
||||
/datum/materialProc/slippery_attack
|
||||
id = "slippery_attack"
|
||||
|
||||
execute(var/obj/item/owner, var/mob/attacker, var/mob/attacked)
|
||||
if (prob(20))
|
||||
boutput(attacker, "<span style=\"color:red\">[owner] slips right out of your hand!</span>")
|
||||
owner.loc = attacker.loc
|
||||
owner.dropped()
|
||||
return
|
||||
|
||||
/datum/materialProc/slippery_entered
|
||||
id = "slippery_entered"
|
||||
|
||||
execute(var/atom/owner, var/atom/movable/entering)
|
||||
if (iscarbon(entering) && prob(75))
|
||||
var/mob/living/carbon/C = entering
|
||||
boutput(C, "You slip on the icy floor!")
|
||||
playsound(get_turf(owner), "sound/misc/slip.ogg", 30, 1)
|
||||
C.weakened += 2
|
||||
return
|
||||
|
||||
/datum/materialProc/ice_life
|
||||
id = "ice_life"
|
||||
desc = "It is slowly melting."
|
||||
|
||||
execute(var/mob/M, var/obj/item/I)
|
||||
if (istype(M,/mob/living/carbon/))
|
||||
var/mob/living/carbon/C = M
|
||||
if (C.bodytemperature > 0)
|
||||
C.bodytemperature -= 2
|
||||
if (C.bodytemperature > 100 && prob(4))
|
||||
boutput(C, "Your [I] melts from your body heat!")
|
||||
qdel(I)
|
||||
return
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,335 @@
|
||||
//processing_items.Add(src)
|
||||
//process()
|
||||
|
||||
//And the sloppiest code award 2014 goes to this file. FUCK. ME.
|
||||
//This will need some major refactoring once im done.
|
||||
|
||||
/obj/workbench_ui/maptext_dummy
|
||||
name = ""
|
||||
desc = ""
|
||||
|
||||
/obj/workbench_ui
|
||||
layer = HUD_LAYER_UNDER_1
|
||||
|
||||
/obj/workbench_ui/menubutton
|
||||
name = "button"
|
||||
desc = ""
|
||||
icon = 'icons/misc/ManuUI.dmi'
|
||||
var/datum/modular_recipe/recipe = null
|
||||
New(var/datum/modular_recipe/C)
|
||||
recipe = C
|
||||
return
|
||||
|
||||
Click(location,control,params)
|
||||
switch(src.name)
|
||||
if("okay")
|
||||
recipe.bench.build_recipe()
|
||||
if("hide")
|
||||
recipe.bench.hide_from(usr)
|
||||
recipe.bench.users.Remove(usr)
|
||||
if("unload")
|
||||
recipe.bench.unload_recipe()
|
||||
return
|
||||
|
||||
/obj/workbench_ui/menubutton/okay
|
||||
name = "okay"
|
||||
icon_state = "ok"
|
||||
|
||||
/obj/workbench_ui/menubutton/cancel
|
||||
name = "hide"
|
||||
icon_state = "cancel"
|
||||
|
||||
/obj/workbench_ui/menubutton/unload
|
||||
name = "unload"
|
||||
icon_state = "unload"
|
||||
|
||||
/obj/workbench_ui/slotbutton
|
||||
name = "slotbutton"
|
||||
desc = "flerpderp"
|
||||
icon = 'icons/misc/ManuUI.dmi'
|
||||
var/datum/modular_component/component = null
|
||||
|
||||
New(var/datum/modular_component/C)
|
||||
component = C
|
||||
return
|
||||
|
||||
Click(location,control,params)
|
||||
if(get_dist(component.recipe.bench, usr) > 1)
|
||||
component.recipe.bench.process() //This is dumb and im sorry.
|
||||
boutput(usr, "<span style=\"color:red\">You are too far away.</span>")
|
||||
return
|
||||
if(istype(usr, /mob/living/carbon/human))
|
||||
|
||||
if(component.slot_object)
|
||||
boutput(usr, "<span style=\"color:red\">You remove the [component.slot_object].</span>")
|
||||
component.remove_object()
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = usr
|
||||
|
||||
if(!H.equipped())
|
||||
src.examine()
|
||||
return
|
||||
|
||||
if(component.check_match(H.equipped()))
|
||||
var/atom/movable/M = H.equipped()
|
||||
H.drop_item()
|
||||
component.assign_object(M)
|
||||
boutput(usr, "<span style=\"color:green\">You put the [M] into the slot.</span>")
|
||||
else
|
||||
boutput(usr, "<span style=\"color:red\">Not enough items or wrong type.</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/datum/modular_component
|
||||
var/component_name = "component"
|
||||
var/component_desc = "a COMPONENT is required for this slot. What kind of component? WHO KNOWS!"
|
||||
var/icon_state = "pocket"
|
||||
var/datum/modular_recipe/recipe = null
|
||||
|
||||
var/obj/workbench_ui/slotbutton/component_button = null
|
||||
var/obj/item/slot_object = null
|
||||
|
||||
var/required_amount = 1
|
||||
|
||||
New(var/datum/modular_recipe/p)
|
||||
recipe = p
|
||||
component_button = new (src)
|
||||
component_button.icon_state = icon_state
|
||||
component_button.name = component_name
|
||||
component_button.desc = component_desc
|
||||
return ..()
|
||||
|
||||
proc/assign_object(var/atom/movable/A)
|
||||
if(!A) return
|
||||
A.x = 0
|
||||
A.y = 0
|
||||
A.z = 0
|
||||
A.layer = HUD_LAYER
|
||||
component_button.overlays.Cut()
|
||||
component_button.overlays.Add(A)
|
||||
src.slot_object = A
|
||||
component_button.name = A.name
|
||||
component_button.desc = A.desc
|
||||
return
|
||||
|
||||
proc/remove_object(var/manual = 0)
|
||||
var/atom/movable/A = slot_object
|
||||
if(A)
|
||||
A.layer = initial(A.layer)
|
||||
slot_object = null
|
||||
component_button.name = component_name
|
||||
component_button.desc = component_desc
|
||||
component_button.overlays.Cut()
|
||||
if(!manual) A.set_loc(get_turf(recipe.bench))
|
||||
return
|
||||
|
||||
proc/check_match(var/obj/item/A)
|
||||
if(A.amount < required_amount)
|
||||
boutput(usr, "<span style=\"color:red\">You do not have enough of that item for use in the recipe.</span>")
|
||||
return 0
|
||||
if(A.amount > required_amount)
|
||||
var/left = (A.amount - required_amount)
|
||||
A.amount = required_amount
|
||||
var/obj/item/X = new A.type(get_turf(recipe.bench))
|
||||
X.amount = left
|
||||
if(A.material) X.setMaterial(copyMaterial(A.material))
|
||||
boutput(usr, "<span style=\"color:blue\">You put the remaining [left] [A] on the workbench.</span>")
|
||||
return 1
|
||||
|
||||
/datum/modular_recipe
|
||||
var/recipe_name = "recipe"
|
||||
var/recipe_desc = "a recipe"
|
||||
var/list/recipe_parts = list()
|
||||
var/obj/workbench/bench = null
|
||||
|
||||
var/obj/workbench_ui/menubutton/okay/okay
|
||||
var/obj/workbench_ui/menubutton/cancel/cancel
|
||||
var/obj/workbench_ui/menubutton/unload/unload
|
||||
var/obj/workbench_ui/maptext_dummy/maptext
|
||||
|
||||
var/manual_component_handling = 0 //If 1 then the used materials will not be deleted.
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
bench = w
|
||||
var/loc_x = 0
|
||||
var/loc_y = 0
|
||||
|
||||
maptext = new()
|
||||
okay = new (src)
|
||||
cancel = new (src)
|
||||
unload = new (src)
|
||||
|
||||
okay.screen_loc = "CENTER-1, CENTER-1"
|
||||
cancel.screen_loc = "CENTER, CENTER-1"
|
||||
unload.screen_loc = "CENTER+1, CENTER-1"
|
||||
maptext.screen_loc = "CENTER-1, CENTER"
|
||||
maptext.maptext_width = 128
|
||||
maptext.maptext = "<span style=\"color:white\">[capitalize(recipe_name)]</span>"
|
||||
|
||||
for(var/datum/modular_component/C in recipe_parts)
|
||||
C.component_button.screen_loc = "CENTER [loc_x - 1 > 0 ? "+" : ""][loc_x - 1 == 0 ? "" : loc_x - 1] , CENTER[-2+loc_y]"
|
||||
if(loc_x >= 2)
|
||||
loc_x = 0
|
||||
loc_y--
|
||||
else
|
||||
loc_x++
|
||||
|
||||
return ..()
|
||||
|
||||
proc/unload() //Dumps all the objects loaded into the recipe onto the floor.
|
||||
for(var/datum/modular_component/C in recipe_parts)
|
||||
C.remove_object()
|
||||
return
|
||||
|
||||
proc/create()
|
||||
var/obj/storage/closet/newObj = new()
|
||||
return newObj
|
||||
|
||||
/obj/workbench
|
||||
icon = 'icons/obj/crafting.dmi'
|
||||
icon_state = "workbench"
|
||||
density = 1
|
||||
anchored = 1
|
||||
var/list/recipe_list = list()
|
||||
var/list/users = list()
|
||||
|
||||
var/datum/modular_recipe/active_recipe = null
|
||||
var/list/active_buttons = list()
|
||||
|
||||
var/building = 0
|
||||
|
||||
ProximityLeave(atom/movable/AM as mob|obj)
|
||||
if(get_dist(src, AM) > 1 && users.Find(AM))
|
||||
users.Remove(AM)
|
||||
hide_from(AM)
|
||||
return
|
||||
|
||||
Del()
|
||||
active_recipe = null
|
||||
for(var/datum/modular_recipe/R in recipe_list)
|
||||
R.unload()
|
||||
for(var/datum/modular_component/C in R.recipe_parts)
|
||||
if(C.component_button) qdel(C.component_button)
|
||||
R.recipe_parts.Cut()
|
||||
recipe_list.Cut()
|
||||
..()
|
||||
|
||||
New()
|
||||
if (!(src in processing_items))
|
||||
processing_items.Add(src)
|
||||
var/list/types = typesof(/datum/modular_recipe) - /datum/modular_recipe
|
||||
for(var/r in types)
|
||||
recipe_list.Add(new r(src))
|
||||
return
|
||||
|
||||
proc/process()
|
||||
for(var/mob/M in users)
|
||||
if(get_dist(src, M) > 1)
|
||||
users.Remove(M)
|
||||
hide_from(M)
|
||||
return
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if(active_recipe)
|
||||
if(!users.Find(user)) users.Add(user)
|
||||
show_to(user)
|
||||
else
|
||||
var/html = {"<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Workbench</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<link rel="stylesheet" type="text/css" href="[resource("css/style.css")]">
|
||||
</head>
|
||||
<body id="manubody">"}
|
||||
html += {"<div id="manudiv">"}
|
||||
for(var/datum/modular_recipe/x in recipe_list)
|
||||
html += {"<div class="manuborder"><a class="manulink" href='?src=\ref[src];loadrecipe=\ref[x]'>[capitalize(x.recipe_name)]</a></div><br>"}
|
||||
html += {"</div>
|
||||
</body>
|
||||
</html>"}
|
||||
user << browse(html, "window=modmanu2;size=610x458;can_resize=0;can_minimize=0")
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
|
||||
if(href_list["loadrecipe"])
|
||||
|
||||
if(active_recipe)
|
||||
if(!users.Find(usr)) users.Add(usr)
|
||||
show_to(usr)
|
||||
usr << browse(null, "window=modmanu2")
|
||||
return
|
||||
|
||||
var/datum/modular_recipe/sel = locate(href_list["loadrecipe"])
|
||||
if(sel && istype(sel, /datum/modular_recipe))
|
||||
load_recipe(sel)
|
||||
if(!users.Find(usr)) users.Add(usr)
|
||||
show_to(usr)
|
||||
usr << browse(null, "window=modmanu2")
|
||||
|
||||
proc/unload_recipe()
|
||||
if(active_recipe)
|
||||
hide_from_all()
|
||||
users.Cut()
|
||||
for(var/datum/modular_component/C in active_recipe.recipe_parts)
|
||||
var/atom/movable/A = C.remove_object()
|
||||
if(A) A.set_loc(get_turf(src))
|
||||
active_recipe = null
|
||||
return
|
||||
|
||||
proc/show_to(var/mob/M)
|
||||
if(active_recipe)
|
||||
if(M.client)
|
||||
M.client.screen += active_recipe.okay
|
||||
M.client.screen += active_recipe.cancel
|
||||
M.client.screen += active_recipe.unload
|
||||
M.client.screen += active_recipe.maptext
|
||||
for(var/datum/modular_component/C in active_recipe.recipe_parts)
|
||||
M.client.screen += C.component_button
|
||||
return
|
||||
|
||||
proc/hide_from(var/mob/M)
|
||||
if(active_recipe)
|
||||
if(M.client)
|
||||
M.client.screen -= active_recipe.okay
|
||||
M.client.screen -= active_recipe.cancel
|
||||
M.client.screen -= active_recipe.unload
|
||||
M.client.screen -= active_recipe.maptext
|
||||
for(var/datum/modular_component/C in active_recipe.recipe_parts)
|
||||
M.client.screen -= C.component_button
|
||||
return
|
||||
|
||||
proc/load_recipe(var/datum/modular_recipe/R)
|
||||
active_recipe = R
|
||||
return
|
||||
|
||||
proc/hide_from_all()
|
||||
for(var/mob/M in users)
|
||||
hide_from(M)
|
||||
return
|
||||
|
||||
proc/build_recipe()
|
||||
if(active_recipe)
|
||||
var/fail = 0
|
||||
for(var/datum/modular_component/C in active_recipe.recipe_parts)
|
||||
if(!C.slot_object)
|
||||
fail = 1
|
||||
break
|
||||
if(fail)
|
||||
boutput(usr, "<span style=\"color:red\">The recipe is not complete.</span>")
|
||||
return
|
||||
else
|
||||
playsound(src.loc, "sound/items/Ratchet.ogg", 100, 1)
|
||||
var/atom/movable/M = active_recipe.create()
|
||||
M.set_loc(src.loc)
|
||||
for(var/datum/modular_component/CB in active_recipe.recipe_parts)
|
||||
if(CB.slot_object)
|
||||
if(CB.slot_object == M) continue //To allow us to pass modified items through the recipe.
|
||||
var/atom/movable/AM = CB.slot_object
|
||||
CB.remove_object(active_recipe.manual_component_handling)
|
||||
if(!active_recipe.manual_component_handling) del(AM) //THIS NEEDS TO BE DEL NOT QDEL. DONT FUCK AROUND WITH IT.
|
||||
else CB.slot_object = null
|
||||
unload_recipe()
|
||||
return
|
||||
@@ -0,0 +1,763 @@
|
||||
/*///////RECIPE DATUMS
|
||||
/datum/manufacturer_blueprint/sunglasses
|
||||
name = "Sunglasses"
|
||||
desc = "Some fancy sunglasses."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Glass")
|
||||
part_list["Glass"] = new/datum/manufacturer_part(MATERIAL_CRYSTAL, "Glass")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/clothing/glasses/sunglasses/G = new/obj/item/clothing/glasses/sunglasses(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Glass"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
|
||||
/datum/manufacturer_blueprint/mop
|
||||
name = "Mop"
|
||||
desc = "A mop."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/mop/G = new/obj/item/mop(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/basketball
|
||||
name = "Basketball"
|
||||
desc = "A basketball."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Rubber")
|
||||
part_list["Rubber"] = new/datum/manufacturer_part(MATERIAL_RUBBER, "Rubber")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/basketball/G = new/obj/item/basketball(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Rubber"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/baton
|
||||
name = "Baton"
|
||||
desc = "A security baton."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/baton/G = new/obj/item/baton(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/bulletstwentytwo
|
||||
name = "Custom .22 bullets"
|
||||
desc = "8 custom .22 caliber bullets."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/ammo/bullets/custom/G = new/obj/item/ammo/bullets/custom(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/wateringcan
|
||||
name = "Watering can"
|
||||
desc = "A watering can."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/reagent_containers/glass/wateringcan/G = new/obj/item/reagent_containers/glass/wateringcan(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/chainsaw
|
||||
name = "Chainsaw"
|
||||
desc = "A chainsaw."
|
||||
assembly_time = 80
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
|
||||
part_list.Add("Energy")
|
||||
part_list["Energy"] = new/datum/manufacturer_part(MATERIAL_ENERGY, "Energy source")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/saw/G = new/obj/item/saw(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/shoes
|
||||
name = "Shoes"
|
||||
desc = "Shoes! Not very protective."
|
||||
assembly_time = 20
|
||||
|
||||
setParts()
|
||||
part_list.Add("Fabric")
|
||||
part_list["Fabric"] = new/datum/manufacturer_part(MATERIAL_CLOTH, "Fabric")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/clothing/shoes/white/G = new/obj/item/clothing/shoes/white(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Fabric"]
|
||||
|
||||
var/datum/material/M = part1.assigned.material
|
||||
|
||||
G.setMaterial(M)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/rollingpin
|
||||
name = "Rolling pin"
|
||||
desc = "A rolling pin."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/kitchen/rollingpin/G = new/obj/item/kitchen/rollingpin(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
///MAKE ESCAPE TIME DEPEDANT ON MATERIAL!!!!!!!!!!! Exploding erebite handcuffs?
|
||||
/datum/manufacturer_blueprint/handcuffs
|
||||
name = "Handcuffs"
|
||||
desc = "Some handcuffs."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/handcuffs/G = new/obj/item/handcuffs(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/spaceset
|
||||
name = "Space suit set"
|
||||
desc = "A space suit, helmet and jetpack."
|
||||
assembly_time = 200
|
||||
|
||||
setParts()
|
||||
part_list.Add("Fabric")
|
||||
part_list["Fabric"] = new/datum/manufacturer_part(MATERIAL_CLOTH, "Fabric")
|
||||
|
||||
part_list.Add("Padding")
|
||||
part_list["Padding"] = new/datum/manufacturer_part(MATERIAL_CLOTH, "Padding")
|
||||
|
||||
part_list.Add("Reinforment")
|
||||
part_list["Reinforment"] = new/datum/manufacturer_part(MATERIAL_METAL, "Reinforment")
|
||||
|
||||
part_list.Add("Jetpack")
|
||||
part_list["Jetpack"] = new/datum/manufacturer_part(MATERIAL_METAL, "Jetpack metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/clothing/suit/space/G = new/obj/item/clothing/suit/space(get_turf(owner))
|
||||
var/obj/item/clothing/head/helmet/space/G1 = new/obj/item/clothing/head/helmet/space(get_turf(owner))
|
||||
var/obj/item/tank/jetpack/G2 = new/obj/item/tank/jetpack(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Fabric"]
|
||||
var/datum/manufacturer_part/part2 = part_list["Jetpack"]
|
||||
|
||||
var/datum/material/M = part1.assigned.material
|
||||
|
||||
G.setMaterial(M)
|
||||
G1.setMaterial(M)
|
||||
G2.setMaterial(part2.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/gasmask
|
||||
name = "Gas mask"
|
||||
desc = "A gas mask. Doesn't protect much from physical attacks."
|
||||
assembly_time = 50
|
||||
|
||||
setParts()
|
||||
part_list.Add("Fabric")
|
||||
part_list["Fabric"] = new/datum/manufacturer_part(MATERIAL_CLOTH, "Fabric")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/clothing/mask/gas/emergency/G = new/obj/item/clothing/mask/gas/emergency(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Fabric"]
|
||||
|
||||
var/datum/material/M = part1.assigned.material
|
||||
|
||||
G.setMaterial(M)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/gastank
|
||||
name = "Gas tank"
|
||||
desc = "A portable gas tank."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/tank/air/G = new/obj/item/tank/air(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/beakers
|
||||
name = "Beaker box"
|
||||
desc = "A box of simple beakers."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Material")
|
||||
part_list["Material"] = new/datum/manufacturer_part(MATERIAL_CRYSTAL, "Material")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/storage/box/beakerbox/G = new/obj/item/storage/box/beakerbox(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Material"]
|
||||
|
||||
G.name = "Box of [part1.assigned.material.name] beakers"
|
||||
|
||||
for(var/atom/A in G)
|
||||
A.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/labcoat
|
||||
name = "Labcoat"
|
||||
desc = "A labcoat. Not very good against physical hazards but very good against diseases."
|
||||
assembly_time = 50
|
||||
|
||||
setParts()
|
||||
part_list.Add("Fabric")
|
||||
part_list["Fabric"] = new/datum/manufacturer_part(MATERIAL_CLOTH, "Fabric")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/clothing/suit/labcoat/G = new/obj/item/clothing/suit/labcoat(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Fabric"]
|
||||
|
||||
var/datum/material/M = part1.assigned.material
|
||||
|
||||
G.setMaterial(M)
|
||||
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/firesuit
|
||||
name = "Firesuit"
|
||||
desc = "A firesuit. Doesn't help much against physical attacks but can have superb temperature stats."
|
||||
assembly_time = 50
|
||||
|
||||
setParts()
|
||||
part_list.Add("Fabric")
|
||||
part_list["Fabric"] = new/datum/manufacturer_part(MATERIAL_CLOTH, "Fabric")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/clothing/suit/fire/G = new/obj/item/clothing/suit/fire(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Fabric"]
|
||||
|
||||
var/datum/material/M = part1.assigned.material
|
||||
|
||||
G.setMaterial(M)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/cutlery
|
||||
name = "Cutlery set"
|
||||
desc = "A fork, spoon and knife."
|
||||
assembly_time = 30
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/kitchen/utensil/fork/G = new/obj/item/kitchen/utensil/fork(get_turf(owner))
|
||||
var/obj/item/kitchen/utensil/spoon/G1 = new/obj/item/kitchen/utensil/spoon(get_turf(owner))
|
||||
var/obj/item/kitchen/utensil/knife/G2 = new/obj/item/kitchen/utensil/knife(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
|
||||
G.setMaterial(part1.assigned.material)
|
||||
G1.setMaterial(part1.assigned.material)
|
||||
G2.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/glass
|
||||
name = "Drinking glass"
|
||||
desc = "A drinking glass."
|
||||
assembly_time = 20
|
||||
|
||||
setParts()
|
||||
part_list.Add("Material")
|
||||
part_list["Material"] = new/datum/manufacturer_part(MATERIAL_CRYSTAL, "Material")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/reagent_containers/food/drinks/drinkingglass/G = new/obj/item/reagent_containers/food/drinks/drinkingglass(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Material"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/plate
|
||||
name = "Plate"
|
||||
desc = "A simple plate for food."
|
||||
assembly_time = 20
|
||||
|
||||
setParts()
|
||||
part_list.Add("Material")
|
||||
part_list["Material"] = new/datum/manufacturer_part(MATERIAL_CRYSTAL, "Material")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/plate/G = new/obj/item/plate(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Material"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/extinguisher
|
||||
name = "Extinguisher"
|
||||
desc = "A fire extinguisher."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/extinguisher/G = new/obj/item/extinguisher(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/toolbox_emergency
|
||||
name = "Emergency toolbox"
|
||||
desc = "A complete emergency toolbox."
|
||||
assembly_time = 80
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/storage/toolbox/emergency/G = new/obj/item/storage/toolbox/emergency(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
|
||||
G.setMaterial(part1.assigned.material)
|
||||
|
||||
for(var/atom/A in G)
|
||||
A.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/toolbox_electrical
|
||||
name = "Electrical toolbox"
|
||||
desc = "A complete electrical toolbox."
|
||||
assembly_time = 80
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/storage/toolbox/electrical/G = new/obj/item/storage/toolbox/electrical(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
|
||||
for(var/atom/A in G)
|
||||
A.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/toolbox_mechanical
|
||||
name = "Mechanical toolbox"
|
||||
desc = "A complete mechanical toolbox."
|
||||
assembly_time = 80
|
||||
|
||||
setParts()
|
||||
part_list.Add("Metal")
|
||||
part_list["Metal"] = new/datum/manufacturer_part(MATERIAL_METAL, "Metal")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/storage/toolbox/mechanical/G = new/obj/item/storage/toolbox/mechanical(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Metal"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
|
||||
for(var/atom/A in G)
|
||||
A.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/glasssheet10
|
||||
name = "Glass sheet x10"
|
||||
desc = "Sheets of glass-like material."
|
||||
assembly_time = 20
|
||||
|
||||
setParts()
|
||||
part_list.Add("Panel")
|
||||
part_list["Panel"] = new/datum/manufacturer_part(MATERIAL_CRYSTAL, "Panel")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/sheet/G = new/obj/item/sheet(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Panel"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
G.amount = 10
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/metalsheet10
|
||||
name = "Metal sheet x10"
|
||||
desc = "Sheets of metal-like material."
|
||||
assembly_time = 20
|
||||
|
||||
setParts()
|
||||
part_list.Add("Panel")
|
||||
part_list["Panel"] = new/datum/manufacturer_part(MATERIAL_METAL, "Panel")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/sheet/G = new/obj/item/sheet(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Panel"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
G.amount = 10
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/slagshovel
|
||||
name = "Slag shovel"
|
||||
desc = "A shovel used to remove slag from the arc smelter."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Shovel")
|
||||
part_list["Shovel"] = new/datum/manufacturer_part(MATERIAL_METAL, "Shovel")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/slag_shovel/G = new/obj/item/slag_shovel(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Shovel"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/gloves
|
||||
name = "Gloves"
|
||||
desc = "Simple gloves."
|
||||
assembly_time = 30
|
||||
|
||||
setParts()
|
||||
part_list.Add("Fabric")
|
||||
part_list["Fabric"] = new/datum/manufacturer_part(MATERIAL_CLOTH, "Fabric")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/clothing/gloves/latex/G = new/obj/item/clothing/gloves/latex(get_turf(owner))
|
||||
G.name = "gloves"
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Fabric"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/jumpsuit
|
||||
name = "Jumpsuit"
|
||||
desc = "A very basic jumpsuit. Has capped stats due to thin fabric."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Fabric")
|
||||
part_list["Fabric"] = new/datum/manufacturer_part(MATERIAL_CLOTH, "Fabric")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/clothing/under/color/whitetemp/G = new/obj/item/clothing/under/color/whitetemp(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Fabric"]
|
||||
|
||||
var/datum/material/M = part1.assigned.material
|
||||
|
||||
G.setMaterial(M)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/podarmor
|
||||
name = "Pod Armor"
|
||||
desc = "A custom-built set of pod armor."
|
||||
assembly_time = 300
|
||||
|
||||
setParts()
|
||||
part_list.Add("Armor plating")
|
||||
part_list["Armor plating"] = new/datum/manufacturer_part(MATERIAL_METAL, "Armor plating")
|
||||
|
||||
part_list.Add("Coating")
|
||||
part_list["Coating"] = new/datum/manufacturer_part(MATERIAL_CRYSTAL, "Coating")
|
||||
|
||||
part_list.Add("Bolts")
|
||||
part_list["Bolts"] = new/datum/manufacturer_part(MATERIAL_METAL, "Bolts")
|
||||
|
||||
part_list.Add("Struts")
|
||||
part_list["Struts"] = new/datum/manufacturer_part(MATERIAL_METAL, "Struts")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/pod/armor_custom/G = new/obj/item/pod/armor_custom(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Armor plating"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/harmor
|
||||
name = "Heavy Armor"
|
||||
desc = "A full set of heavy armor. Offers good protection against attacks but not much else."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Plating")
|
||||
part_list["Plating"] = new/datum/manufacturer_part(MATERIAL_METAL, "Plating")
|
||||
|
||||
part_list.Add("Coating")
|
||||
part_list["Coating"] = new/datum/manufacturer_part(MATERIAL_CRYSTAL, "Coating")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/clothing/suit/armor/heavy/G = new/obj/item/clothing/suit/armor/heavy(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Plating"]
|
||||
|
||||
var/datum/material/M = part1.assigned.material
|
||||
|
||||
G.setMaterial(M)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/horse
|
||||
name = "Horse mask"
|
||||
desc = "A stupid looking horse mask."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Mask")
|
||||
part_list["Mask"] = new/datum/manufacturer_part(MATERIAL_METAL, "Mask")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/item/clothing/mask/horse_mask/G = new/obj/item/clothing/mask/horse_mask(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Mask"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint/gtank
|
||||
name = "Atmos Canister"
|
||||
desc = "A large gas tank."
|
||||
assembly_time = 40
|
||||
|
||||
setParts()
|
||||
part_list.Add("Hull")
|
||||
part_list["Hull"] = new/datum/manufacturer_part(MATERIAL_METAL, "Hull")
|
||||
return
|
||||
|
||||
assemble(var/atom/owner)
|
||||
for(var/datum/manufacturer_part/P in part_list)
|
||||
if(!P.assigned) return 0
|
||||
|
||||
var/obj/machinery/portable_atmospherics/canister/G = new/obj/machinery/portable_atmospherics/canister(get_turf(owner))
|
||||
|
||||
var/datum/manufacturer_part/part1 = part_list["Hull"]
|
||||
G.setMaterial(part1.assigned.material)
|
||||
return 1
|
||||
|
||||
/datum/manufacturer_blueprint
|
||||
var/name = "blueprint" //Please make sure names are unique. They are also used as ID
|
||||
var/desc = "desc"
|
||||
var/list/part_list = list()
|
||||
var/assembly_time = 10 //ticks.
|
||||
|
||||
New()
|
||||
setParts()
|
||||
return ..()
|
||||
|
||||
proc/assemble(var/atom/owner)
|
||||
return
|
||||
|
||||
proc/setParts() //This is responsible for setting the required materials.
|
||||
return
|
||||
|
||||
proc/reset() //Resets the blueprint after assembly.
|
||||
part_list.Cut()
|
||||
setParts()
|
||||
return
|
||||
///////RECIPE DATUMS
|
||||
|
||||
///////RECIPE OBJECTS
|
||||
/obj/item/man_blueprint
|
||||
icon = 'icons/obj/manufacturer.dmi'
|
||||
icon_state = "blueprint"
|
||||
name = "manufacturer blueprint"
|
||||
desc = "A blueprint that will allow a manufacturer to produce new objects."
|
||||
var/bpType = null
|
||||
|
||||
/obj/item/man_blueprint/horsemask
|
||||
name = "horse mask blueprint"
|
||||
bpType = /datum/manufacturer_blueprint/horse
|
||||
|
||||
/obj/item/man_blueprint/sunglasses
|
||||
name = "sunglasses blueprint"
|
||||
bpType = /datum/manufacturer_blueprint/sunglasses
|
||||
|
||||
/obj/item/man_blueprint/mop
|
||||
name = "mop blueprint"
|
||||
bpType = /datum/manufacturer_blueprint/mop
|
||||
|
||||
/obj/item/man_blueprint/basketball
|
||||
name = "basketball blueprint"
|
||||
bpType = /datum/manufacturer_blueprint/basketball
|
||||
///////RECIPE OBJECTS
|
||||
*/
|
||||
@@ -0,0 +1,696 @@
|
||||
//RECIPES START//
|
||||
|
||||
/datum/modular_recipe/flash
|
||||
recipe_name = "flash"
|
||||
recipe_desc = "A flash."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/energy_cell_small(src))
|
||||
recipe_parts.Add(new/datum/modular_component/material_metal(src))
|
||||
recipe_parts.Add(new/datum/modular_component/lens(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/device/flash/newObj = new()
|
||||
var/datum/modular_component/cell = recipe_parts[1] //This should be the energy cell if order is preserved.
|
||||
var/datum/modular_component/metal = recipe_parts[2] //This should be the metal if order is preserved.
|
||||
var/datum/modular_component/lens = recipe_parts[3] //This should be the lens if order is preserved.
|
||||
|
||||
if(cell.slot_object && cell.slot_object.material && metal.slot_object && metal.slot_object.material)
|
||||
newObj.setMaterial(metal.slot_object.material)
|
||||
newObj.name = "[cell.slot_object.name] fitted [newObj.name]"
|
||||
newObj.desc = newObj.desc + " It has a [cell.slot_object.name] and a [lens.slot_object.name]."
|
||||
newObj.use = round(cell.slot_object:max_charge / 10) * (-1)
|
||||
newObj.eye_damage_mod = round(lens.slot_object:focal_strength / 30)
|
||||
newObj.range_mod = round(lens.slot_object:clarity / 55)
|
||||
newObj.burn_mod = round(metal.slot_object.material.getProperty(PROP_THERMAL) / 9) * (-1)
|
||||
newObj.stun_mod = round(metal.slot_object.material.quality / 40)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/flashlight
|
||||
recipe_name = "flashlight"
|
||||
recipe_desc = "A flashlight."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/energy_cell_large(src))
|
||||
recipe_parts.Add(new/datum/modular_component/material_metal(src))
|
||||
recipe_parts.Add(new/datum/modular_component/lens(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/device/flashlight/newObj = new()
|
||||
var/datum/modular_component/cell = recipe_parts[1] //This should be the energy cell if order is preserved.
|
||||
var/datum/modular_component/metal = recipe_parts[2] //This should be the metal if order is preserved.
|
||||
var/datum/modular_component/lens = recipe_parts[3] //This should be the lens if order is preserved.
|
||||
|
||||
if(cell.slot_object && cell.slot_object.material && metal.slot_object && metal.slot_object.material)
|
||||
newObj.setMaterial(metal.slot_object.material)
|
||||
newObj.name = "[lens.slot_object.name] [newObj.name]"
|
||||
newObj.desc = newObj.desc + " It has a [lens.slot_object.name]."
|
||||
newObj.col_r = GetRedPart(lens.slot_object.material.color) / 255
|
||||
newObj.col_g = GetGreenPart(lens.slot_object.material.color) / 255
|
||||
newObj.col_b = GetBluePart(lens.slot_object.material.color) / 255
|
||||
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/cell_small
|
||||
recipe_name = "small energy cell"
|
||||
recipe_desc = "A small energy cell used in guns and small portable devices."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_energy(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/ammo/power_cell/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/cell_large
|
||||
recipe_name = "large energy cell"
|
||||
recipe_desc = "A large enery cell, often used in APCs or cyborgs."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_energy(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/cell/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/arrowhead
|
||||
recipe_name = "arrowhead"
|
||||
recipe_desc = "A few arrowheads."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_metal_or_crystal(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/arrowhead/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
newObj.amount = 4
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/lens
|
||||
recipe_name = "lens"
|
||||
recipe_desc = "A small lens."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_crystal(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/lens/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/gears
|
||||
recipe_name = "gears"
|
||||
recipe_desc = "Some gears."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_metal(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/gears/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/small_coil
|
||||
recipe_name = "small coil"
|
||||
recipe_desc = "A small coil."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_metal(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/coil/small/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/large_coil
|
||||
recipe_name = "large coil"
|
||||
recipe_desc = "A large coil."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_metal(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/coil/large/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/sheets_ten
|
||||
recipe_name = "10 sheets"
|
||||
recipe_desc = "10 sheets of a given material."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_any(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/sheet/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
newObj.amount = 10
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/jumpsuit
|
||||
recipe_name = "jumpsuit"
|
||||
recipe_desc = "A simple jumpsuit."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_fabric(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/clothing/under/color/whitetemp/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/atmoscanister
|
||||
recipe_name = "atmos canister"
|
||||
recipe_desc = "A large gas canister."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_metal(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/machinery/portable_atmospherics/canister/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/horsemask
|
||||
recipe_name = "horse mask"
|
||||
recipe_desc = "A horse mask."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_any(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/clothing/mask/horse_mask/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/armorplates
|
||||
recipe_name = "armor plates"
|
||||
recipe_desc = "Some armor plates."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/tile/three(src))
|
||||
recipe_parts.Add(new/datum/modular_component/rods_5(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/aplate/newObj = new()
|
||||
var/datum/modular_component/tiles = recipe_parts[1]
|
||||
var/datum/modular_component/rods = recipe_parts[2]
|
||||
|
||||
if(tiles.slot_object && tiles.slot_object.material && rods.slot_object && rods.slot_object.material)
|
||||
newObj.setMaterial(tiles.slot_object.material)
|
||||
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/harmor
|
||||
recipe_name = "heavy armor"
|
||||
recipe_desc = "heavy armor."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/aplate(src))
|
||||
recipe_parts.Add(new/datum/modular_component/rods_5(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/clothing/suit/armor/heavy/newObj = new()
|
||||
var/datum/modular_component/plates = recipe_parts[1]
|
||||
var/datum/modular_component/rods = recipe_parts[2]
|
||||
|
||||
if(plates.slot_object && plates.slot_object.material && rods.slot_object && rods.slot_object.material)
|
||||
newObj.setMaterial(plates.slot_object.material)
|
||||
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/podarmor
|
||||
recipe_name = "pod armor"
|
||||
recipe_desc = "pod armor."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/aplate(src))
|
||||
recipe_parts.Add(new/datum/modular_component/rods_5(src))
|
||||
recipe_parts.Add(new/datum/modular_component/material_crystal(src))
|
||||
recipe_parts.Add(new/datum/modular_component/gears(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/pod/armor_custom/newObj = new()
|
||||
var/datum/modular_component/plates = recipe_parts[1]
|
||||
|
||||
if(plates.slot_object && plates.slot_object.material)
|
||||
newObj.setMaterial(plates.slot_object.material)
|
||||
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/fuelpellet
|
||||
recipe_name = "fuel pellet"
|
||||
recipe_desc = "A small fueled pellet used in RTGs."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_metal(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/fuel_pellet/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/cablecoil
|
||||
recipe_name = "cable coil"
|
||||
recipe_desc = "A coil of cable."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/material_any(src))
|
||||
recipe_parts.Add(new/datum/modular_component/material_metal(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/cable_coil/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1] //Insulator
|
||||
var/datum/modular_component/C2 = recipe_parts[2] //Conductor
|
||||
if(C.slot_object && C.slot_object.material && C2.slot_object && C2.slot_object.material)
|
||||
applyCableMaterials(newObj, C.slot_object.material, C2.slot_object.material)
|
||||
newObj.amount = MAXCOIL
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/tripod
|
||||
recipe_name = "tripod"
|
||||
recipe_desc = "A 3-legged stand for supporting various devices."
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/rods_3(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/obj/item/tripod/newObj = new()
|
||||
var/datum/modular_component/C = recipe_parts[1]
|
||||
if(C.slot_object && C.slot_object.material)
|
||||
newObj.setMaterial(C.slot_object.material)
|
||||
return newObj
|
||||
|
||||
/datum/modular_recipe/eguncellswap
|
||||
recipe_name = "Swap energy gun cell"
|
||||
recipe_desc = "Allows you to switch out the energy cell used by a gun."
|
||||
manual_component_handling = 1
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/egun(src))
|
||||
recipe_parts.Add(new/datum/modular_component/energy_cell_small(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/datum/modular_component/gun = recipe_parts[1]
|
||||
var/datum/modular_component/cell = recipe_parts[2]
|
||||
|
||||
var/obj/item/gun/energy/gunobj = gun.slot_object
|
||||
var/obj/item/ammo/power_cell/cellobj = cell.slot_object
|
||||
|
||||
// Those self-charging ten-shot radbows were a bit overpowered (Convair880).
|
||||
if (gunobj.custom_cell_max_capacity && (cellobj.max_charge > gunobj.custom_cell_max_capacity))
|
||||
usr.show_text("This power cell won't fit!", "red")
|
||||
cellobj.set_loc(bench.loc)
|
||||
return gunobj
|
||||
|
||||
if(gunobj.cell)
|
||||
gunobj.cell.set_loc(bench.loc)
|
||||
gunobj.cell = null
|
||||
|
||||
gunobj.cell = cellobj
|
||||
cellobj.set_loc(gunobj)
|
||||
|
||||
gunobj.logme_temp(usr, gunobj, gunobj.cell) // Added a pair of proc calls here (Convair880).
|
||||
gunobj.update_icon()
|
||||
|
||||
if(!processing_items.Find(gunobj))
|
||||
processing_items.Add(gunobj)
|
||||
|
||||
return gunobj
|
||||
|
||||
// Made batons use energy cells, and it make sense that you can swap them too (Convair880).
|
||||
/datum/modular_recipe/batoncellswap
|
||||
recipe_name = "Swap stun baton cell"
|
||||
recipe_desc = "Allows you to switch out the energy cell used by a stun baton."
|
||||
manual_component_handling = 1
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/baton(src))
|
||||
recipe_parts.Add(new/datum/modular_component/energy_cell_small(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/datum/modular_component/baton = recipe_parts[1]
|
||||
var/datum/modular_component/cell = recipe_parts[2]
|
||||
|
||||
var/obj/item/baton/batonobj = baton.slot_object
|
||||
var/obj/item/ammo/power_cell/cellobj = cell.slot_object
|
||||
|
||||
if (batonobj.uses_electricity == 0 || batonobj.uses_charges == 0)
|
||||
usr.show_text("This baton doesn't require a power cell.", "red")
|
||||
cellobj.set_loc(bench.loc)
|
||||
return batonobj
|
||||
|
||||
if (batonobj.cell)
|
||||
batonobj.cell.set_loc(bench.loc)
|
||||
batonobj.cell = null
|
||||
|
||||
batonobj.cell = cellobj
|
||||
cellobj.set_loc(batonobj)
|
||||
|
||||
batonobj.log_cellswap(usr, batonobj.cell)
|
||||
batonobj.update_icon()
|
||||
|
||||
if (!processing_items.Find(batonobj))
|
||||
processing_items.Add(batonobj)
|
||||
|
||||
return batonobj
|
||||
|
||||
/datum/modular_recipe/meleeweapon
|
||||
recipe_name = "Improvised weapon"
|
||||
recipe_desc = "Allows you to improvise a weapon of some sort. Results may vary depending on items used."
|
||||
manual_component_handling = 1
|
||||
|
||||
New(var/obj/workbench/w)
|
||||
recipe_parts.Add(new/datum/modular_component/item_any/core(src))
|
||||
recipe_parts.Add(new/datum/modular_component/item_any/head(src))
|
||||
return ..(w)
|
||||
|
||||
create()
|
||||
var/datum/modular_component/core = recipe_parts[1]
|
||||
var/datum/modular_component/head = recipe_parts[2]
|
||||
|
||||
var/obj/item/coreobj = core.slot_object
|
||||
var/obj/item/headobj = head.slot_object
|
||||
|
||||
var/list/long_stuff = list(/obj/item/rods, /obj/item/rods/steel, /obj/item/baton, /obj/item/crowbar, /obj/item/slag_shovel, /obj/item/clothing/head/plunger)
|
||||
var/list/sharp_stuff = list(/obj/item/raw_material/shard, /obj/item/raw_material/shard/plasmacrystal, /obj/item/raw_material/shard/glass, /obj/item/scalpel, /obj/item/wirecutters, /obj/item/screwdriver, /obj/item/scissors, /obj/item/razor_blade, /obj/item/kitchen/utensil/knife, /obj/item/kitchen/utensil/fork)
|
||||
|
||||
if(long_stuff.Find(coreobj.type) && sharp_stuff.Find(headobj.type)) //I guess this makes a spear.
|
||||
var/obj/item/craftedmelee/spear/spear = new/obj/item/craftedmelee/spear(bench.loc)
|
||||
|
||||
coreobj.set_loc(spear)
|
||||
headobj.set_loc(spear)
|
||||
|
||||
spear.core = coreobj
|
||||
spear.head = headobj
|
||||
|
||||
spear.rebuild()
|
||||
return spear
|
||||
else if (long_stuff.Find(coreobj.type) && istype(headobj, /obj/item/arrowhead))
|
||||
if (headobj.amount < 1)
|
||||
headobj.amount = 1
|
||||
if (coreobj.amount < 1)
|
||||
coreobj.amount = 1
|
||||
var/obj/item/arrow/A = new(bench.loc)
|
||||
A.setHeadMaterial(headobj.material)
|
||||
A.setShaftMaterial(coreobj.material)
|
||||
A.amount = min(headobj.amount, coreobj.amount)
|
||||
headobj.amount -= A.amount
|
||||
coreobj.amount -= A.amount
|
||||
if (headobj.amount <= 0)
|
||||
qdel(headobj)
|
||||
if (coreobj.amount <= 0)
|
||||
qdel(coreobj)
|
||||
return A
|
||||
else
|
||||
//var/obj/item/craftedcrap/crap = new/obj/item/craftedcrap(bench.loc)
|
||||
|
||||
//coreobj.set_loc(crap)
|
||||
//headobj.set_loc(crap)
|
||||
|
||||
coreobj.set_loc(bench.loc)
|
||||
headobj.set_loc(bench.loc)
|
||||
|
||||
//crap.item1 = coreobj
|
||||
//crap.item2 = headobj
|
||||
|
||||
//crap.rebuild()
|
||||
|
||||
return coreobj //crap
|
||||
|
||||
//RECIPES END//
|
||||
|
||||
|
||||
|
||||
//COMPONENTS START//
|
||||
/datum/modular_component/item_any/core
|
||||
component_name = "any item (core)"
|
||||
|
||||
/datum/modular_component/item_any/head
|
||||
component_name = "any item (head)"
|
||||
|
||||
/datum/modular_component/item_any
|
||||
component_name = "any item"
|
||||
component_desc = "This slot requires an item of any type."
|
||||
icon_state = "pocket"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(istype(A,/obj/item)) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/material_any
|
||||
component_name = "any material"
|
||||
component_desc = "This slot requires a material of any type."
|
||||
icon_state = "any"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(!istype(A,/obj/item/raw_material) && !istype(A,/obj/item/material_piece)) return 0
|
||||
if(A.material)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/material_metal
|
||||
component_name = "metal"
|
||||
component_desc = "This slot requires some form of metal."
|
||||
icon_state = "metal"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(!istype(A,/obj/item/raw_material) && !istype(A,/obj/item/material_piece)) return 0
|
||||
if(A.material)
|
||||
if(A.material.material_flags & MATERIAL_METAL) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/material_crystal
|
||||
component_name = "crystal"
|
||||
component_desc = "This slot requires some form of crystal."
|
||||
icon_state = "crystal"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(!istype(A,/obj/item/raw_material) && !istype(A,/obj/item/material_piece)) return 0
|
||||
if(A.material)
|
||||
if(A.material.material_flags & MATERIAL_CRYSTAL) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/material_metal_or_crystal
|
||||
component_name = "metal or crystal"
|
||||
component_desc = "This slot requires some form of metal or crystal."
|
||||
icon_state = "metal_or_crystal"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(!istype(A,/obj/item/raw_material) && !istype(A,/obj/item/material_piece)) return 0
|
||||
if(A.material)
|
||||
if(A.material.material_flags & MATERIAL_CRYSTAL || A.material.material_flags & MATERIAL_METAL) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/material_fabric
|
||||
component_name = "fabric"
|
||||
component_desc = "This slot requires some form of fabric."
|
||||
icon_state = "fabric"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(!istype(A,/obj/item/raw_material) && !istype(A,/obj/item/material_piece)) return 0
|
||||
if(A.material)
|
||||
if(A.material.material_flags & MATERIAL_CLOTH) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/material_rubber
|
||||
component_name = "rubber"
|
||||
component_desc = "This slot requires some form of rubber."
|
||||
icon_state = "rubber"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(!istype(A,/obj/item/raw_material) && !istype(A,/obj/item/material_piece)) return 0
|
||||
if(A.material)
|
||||
if(A.material.material_flags & MATERIAL_RUBBER) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/material_organic
|
||||
component_name = "organic material"
|
||||
component_desc = "This slot requires some form of organic material."
|
||||
icon_state = "organic"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(!istype(A,/obj/item/raw_material) && !istype(A,/obj/item/material_piece)) return 0
|
||||
if(A.material)
|
||||
if(A.material.material_flags & MATERIAL_ORGANIC) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/material_energy
|
||||
component_name = "energy source"
|
||||
component_desc = "This slot requires some form of raw energy source."
|
||||
icon_state = "energy"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(!istype(A,/obj/item/raw_material) && !istype(A,/obj/item/material_piece)) return 0
|
||||
if(A.material)
|
||||
if(A.material.material_flags & MATERIAL_ENERGY) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/energy_cell_small
|
||||
component_name = "small energy cell"
|
||||
component_desc = "This slot requires some form of small enery cell, often used in energy guns."
|
||||
icon_state = "sbattery"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(istype(A,/obj/item/ammo/power_cell)) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/energy_cell_large
|
||||
component_name = "large energy cell"
|
||||
component_desc = "This slot requires some form of large enery cell."
|
||||
icon_state = "lbattery"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(istype(A,/obj/item/cell)) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/lens
|
||||
component_name = "lens"
|
||||
component_desc = "This slot requires a lens."
|
||||
icon_state = "lens"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(istype(A,/obj/item/lens)) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/gears
|
||||
component_name = "gears"
|
||||
component_desc = "This slot requires some gears."
|
||||
icon_state = "gears"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(istype(A,/obj/item/gears)) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/rods_3
|
||||
component_name = "3+ rods"
|
||||
component_desc = "This slot requires at least 3 rods."
|
||||
icon_state = "3rods"
|
||||
required_amount = 3
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(istype(A,/obj/item/rods)) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/rods_5
|
||||
component_name = "5+ rods"
|
||||
component_desc = "This slot requires at least 5 rods."
|
||||
icon_state = "5rods"
|
||||
required_amount = 5
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(istype(A,/obj/item/rods)) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/aplate
|
||||
component_name = "armor plate"
|
||||
component_desc = "This slot requires armor plates."
|
||||
icon_state = "armor"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(istype(A,/obj/item/aplate)) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/tile
|
||||
component_name = "floor tiles"
|
||||
component_desc = "This slot requires floor tiles."
|
||||
icon_state = "tile"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(istype(A,/obj/item/tile)) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/tile/three
|
||||
component_name = "3 floor tiles"
|
||||
component_desc = "This slot requires 3 floor tiles."
|
||||
icon_state = "tile"
|
||||
required_amount = 3
|
||||
|
||||
/datum/modular_component/egun
|
||||
component_name = "energy gun"
|
||||
component_desc = "This slot requires an energy cell-based gun."
|
||||
icon_state = "egun"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if(!..(A)) return 0 //This checks for the amount.
|
||||
if(istype(A,/obj/item/gun/energy)) return 1
|
||||
return 0
|
||||
|
||||
/datum/modular_component/baton
|
||||
component_name = "stun baton"
|
||||
component_desc = "This slot requires an energy cell-based stun baton."
|
||||
icon_state = "baton"
|
||||
|
||||
check_match(var/obj/item/A)
|
||||
if (!..(A)) return 0 //This checks for the amount.
|
||||
if (istype(A, /obj/item/baton))
|
||||
var/obj/item/baton/B = A
|
||||
if (B.uses_electricity != 0 && B.uses_charges != 0)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//COMPONENTS END//
|
||||
@@ -0,0 +1,30 @@
|
||||
//The stuff below is very rough and will be refined once im done writing the actual systems.
|
||||
|
||||
/*
|
||||
The system has gotten a bit convoluted so im gonna write down some notes here to help people.
|
||||
|
||||
How do i add new Material trigger procs?
|
||||
-Add a new datum for it in the Mat_MaterialProcs.dm file
|
||||
-Make sure the signature for the execute proc matches what will be passed in. See the Mat_Materials.dm file and the calling procs therein - for example "triggerOnLife" - to find the signatures.
|
||||
-In the New proc of the material datum, do something like addDelegate(triggersOnAdd, new /datum/materialProc/erebite_flash())
|
||||
|
||||
How do i add a new Trigger?
|
||||
-Add a list and a calling proc for it in the base material definition
|
||||
-Add the name of the list to triggerVars in Mat_ProcsDefines.dm
|
||||
-Add the required handling for the new trigger in the getFusedMaterial proc in Mat_ProcsDefines.dm - See the existing ones for an example.
|
||||
-Make sure the calling proc you created in step one is called from somewhere in the game.
|
||||
-If possible, make sure that the call for your new trigger has the object owning the material or a relevant entity as its first argument.
|
||||
|
||||
How do i add a new material flag?
|
||||
-Add it in _setup.dm
|
||||
-Add the handling for it in the getFusedMaterial proc in Mat_ProcsDefines.dm
|
||||
-Give it a name in getMatFlagString in Mat_ProcsDefines.dm
|
||||
|
||||
MATERIAL PROPERTIES:
|
||||
Tensile Strength: How much a material can be stretched before it snaps
|
||||
Compressive Strength: How much a material can resist being crushed
|
||||
Shear Strength: Essentially resistance to being cut or abrased
|
||||
Ductility: How much it can be fucked with until it is permanently deformed
|
||||
Toughness: How much force it can absorb without fracturing
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,702 @@
|
||||
/obj/machinery/computer/material
|
||||
name = "material recombobulator"
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
icon_state = "computer_generic"
|
||||
|
||||
var/mob/using = null
|
||||
var/datum/material/editing = null
|
||||
var/obj/editing_obj = null
|
||||
|
||||
New()
|
||||
..()
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(W.material != null)
|
||||
if(!W.material.canMix || (!istype(W,/obj/item/raw_material) && !istype(W,/obj/item/material_piece)))
|
||||
boutput(user, "<span style=\"color:red\">This material can not be used in [src].</span>")
|
||||
return
|
||||
|
||||
if(!editing)
|
||||
src.visible_message("<span style=\"color:blue\">[user] puts [W] into [src]</span>")
|
||||
user.drop_item()
|
||||
editing = W.material
|
||||
editing_obj = W
|
||||
W.loc = src
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">There's already a material inside [src]</span>")
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">This object has no material.</span>")
|
||||
return
|
||||
|
||||
attack_ai(mob/user as mob)
|
||||
return attack_hand(user)
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
|
||||
if(using && (!using.client || using.client.inactivity >= 1200 || get_dist(src, using) > 1))
|
||||
using << browse(null, "window=materials")
|
||||
using = null
|
||||
|
||||
if(using && using != user)
|
||||
boutput(user, "<span style=\"color:red\">Somebody is already using that machine.</span>")
|
||||
return.
|
||||
|
||||
using = user
|
||||
|
||||
//<a href='?src=\ref[src];fart=1'><small>(fart)</small></a>
|
||||
user.machine = src
|
||||
add_fingerprint(user)
|
||||
user << browse(grabResource("html/materialRecombobulator.html"), "window=materials;size=730x415;can_resize=0;can_minimize=0;can_close=0")
|
||||
onclose(user, "materials", src)
|
||||
|
||||
spawn(10) callJsFunc(usr, "setRef", list("\ref[src]")) //This is shit but without it, it calls the JS before the window is open and doesn't work.
|
||||
return
|
||||
|
||||
proc/handleRecipes()
|
||||
if(!editing || !editing_obj) return
|
||||
var/datum/material_recipe/RE = matchesMaterialRecipe(editing)
|
||||
if(RE)
|
||||
if(RE.result_item)
|
||||
var/atom/movable/A = new RE.result_item(src.loc)
|
||||
A.set_loc(src)
|
||||
editing = null
|
||||
del(editing_obj)
|
||||
editing_obj = A
|
||||
editing = A.material
|
||||
else if(length(RE.result_id))
|
||||
editing = null
|
||||
editing_obj.removeMaterial()
|
||||
editing_obj.setMaterial(getCachedMaterial(RE.result_id))
|
||||
else
|
||||
RE.apply_to(editing)
|
||||
editing_obj.setMaterial(editing_obj.material)
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
//boutput(world, href)
|
||||
if(!using || get_dist(using, src) > 1)
|
||||
using << browse(null, "window=materials")
|
||||
using = null
|
||||
return
|
||||
|
||||
if(href_list["close"])
|
||||
using = null
|
||||
else if(href_list["jscall"])
|
||||
switch(href_list["jscall"])
|
||||
if("refResearch")
|
||||
loadContent("Research")
|
||||
if("selMod")
|
||||
if(!editing)
|
||||
callJsFunc(usr, "showDialog", list("No material to edit. Please insert material into computer."))
|
||||
return
|
||||
|
||||
var/newhtml = ""
|
||||
|
||||
switch(href_list["name"])
|
||||
if("Wendigo thermal insulation")
|
||||
newhtml += "<table><tr>"
|
||||
newhtml += "<th>BEFORE<br>[generateMaterialInfo()]</th>" //Before
|
||||
editing.setProperty(PROP_THERMAL, max(editing.getProperty(PROP_THERMAL) - 10, 18))
|
||||
editing.setProperty(PROP_INSTABILITY, editing.getProperty(PROP_INSTABILITY) + 10)
|
||||
editing_obj.setMaterial(editing_obj.material)
|
||||
handleRecipes()
|
||||
newhtml += "<th>AFTER<br>[generateMaterialInfo()]</th>" //After
|
||||
newhtml += "</tr></table>"
|
||||
callJsFunc(usr, "setHtmlId", list("#tabs-3", newhtml))
|
||||
if("Wendigo King thermal protection")
|
||||
newhtml += "<table><tr>"
|
||||
newhtml += "<th>BEFORE<br>[generateMaterialInfo()]</th>" //Before
|
||||
editing.setProperty(PROP_THERMAL, max(editing.getProperty(PROP_THERMAL) - 20, 10))
|
||||
editing.setProperty(PROP_INSTABILITY, editing.getProperty(PROP_INSTABILITY) + 25)
|
||||
editing.addDelegate(editing.triggersOnLife, new /datum/materialProc/wendigo_temp_onlife())
|
||||
editing_obj.setMaterial(editing_obj.material)
|
||||
handleRecipes()
|
||||
newhtml += "<th>AFTER<br>[generateMaterialInfo()]</th>" //After
|
||||
newhtml += "</tr></table>"
|
||||
callJsFunc(usr, "setHtmlId", list("#tabs-3", newhtml))
|
||||
if("Supernatural enhancement")
|
||||
newhtml += "<table><tr>"
|
||||
newhtml += "<th>BEFORE<br>[generateMaterialInfo()]</th>" //Before
|
||||
editing.color = "#FFFFFF"
|
||||
editing.setProperty(PROP_ENERGY, min(editing.getProperty(PROP_ENERGY) + 20, 95))
|
||||
editing.addDelegate(editing.triggersOnAdd, new /datum/materialProc/ethereal_add())
|
||||
editing.setProperty(PROP_INSTABILITY, editing.getProperty(PROP_INSTABILITY) + 33)
|
||||
editing_obj.setMaterial(editing_obj.material)
|
||||
handleRecipes()
|
||||
newhtml += "<th>AFTER<br>[generateMaterialInfo()]</th>" //After
|
||||
newhtml += "</tr></table>"
|
||||
callJsFunc(usr, "setHtmlId", list("#tabs-3", newhtml))
|
||||
if("closeWindow")
|
||||
usr << browse(null, "window=materials")
|
||||
using = null
|
||||
if("ejectMaterial")
|
||||
if(editing_obj)
|
||||
editing_obj.set_loc(src.loc)
|
||||
editing = null
|
||||
editing_obj = null
|
||||
if("loadTab")
|
||||
if(href_list["newTab"])
|
||||
loadContent(href_list["newTab"])
|
||||
if("research")
|
||||
if(href_list["id"] && materialsResearch.research.Find(href_list["id"]))
|
||||
var/datum/materialResearch/R = materialsResearch.research[href_list["id"]]
|
||||
var/error = R.canStart()
|
||||
if(!error)
|
||||
R.beginResearch()
|
||||
loadContent("Research")
|
||||
else
|
||||
callJsFunc(usr, "showDialog", list(error))
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
callJsFunc(usr, "setRef", list("\ref[src]"))
|
||||
return
|
||||
|
||||
proc/loadContent(var/content, var/divId)
|
||||
switch(content)
|
||||
if("View Material")
|
||||
if(src.editing)
|
||||
callJsFunc(usr, "setHtmlId", list(divId ? divId : "#tabs-2", "[generateMaterialInfo()]"))
|
||||
else
|
||||
callJsFunc(usr, "setHtmlId", list(divId ? divId : "#tabs-2", "No material loaded."))
|
||||
|
||||
if("Modify Material")
|
||||
var/scripts = ""
|
||||
var/newhtml = ""
|
||||
newhtml += {"<ul id="modmenu">"}
|
||||
newhtml += {"<li class="ui-widget-header">Standard methods</li>"}
|
||||
newhtml += {"<li class="ui-widget-header">Researched methods</li>"}
|
||||
if(materialsResearch.completed.Find("wendigo")) newhtml += {"<li>Wendigo thermal insulation</li>"}
|
||||
if(materialsResearch.completed.Find("wendigoking")) newhtml += {"<li>Wendigo King thermal protection</li>"}
|
||||
if(materialsResearch.completed.Find("supernatural2")) newhtml += {"<li>Supernatural enhancement</li>"}
|
||||
if(materialsResearch.completed.Find("recondition1") && !materialsResearch.completed.Find("recondition2")) newhtml += {"<li>Reconditioning</li>"}
|
||||
if(materialsResearch.completed.Find("recondition2")) newhtml += {"<li>Advanced reconditioning</li>"}
|
||||
newhtml += {"</ul">"}
|
||||
scripts += {"<script>$(function() {$( "#modmenu" ).menu({items: "> :not(.ui-widget-header)" });});</script>"}
|
||||
scripts += {"<script>$(function() {$( "#modmenu" ).on( "menuselect", function( event, ui ) {callByond("selMod", \["name=" + ui.item.text()\]);});});</script>"}
|
||||
newhtml += scripts
|
||||
callJsFunc(usr, "setHtmlId", list(divId ? divId : "#tabs-3", newhtml))
|
||||
|
||||
if("Research")
|
||||
var/scripts = {"<script>$(function() {$( "#researchfold" ).accordion({heightStyle: "content" });});</script>"}
|
||||
var/newhtml = {"<div style="height:365px; padding:0px; margin:0px; border:0px;overflow:auto">"}
|
||||
newhtml += {"<button id="bttrefreshres" style="top:39px;z-index: 200;font-size:10px;position:absolute;left:675px;">Refresh</button>"}
|
||||
newhtml += {"<div id="researchfold" style="width:670px;overflow:visible;max-width: 670px;">"}
|
||||
scripts += {"<script>$(function(){$( "#bttrefreshres" ).button({icons: {primary: "ui-icon-refresh" },text: false});$( "#bttrefreshres" ).click(function() {callByond("refResearch", \[\]);});});</script>"}
|
||||
|
||||
for(var/x in materialsResearch.research)
|
||||
var/datum/materialResearch/R = materialsResearch.research[x]
|
||||
if(!R.canShow()) continue
|
||||
newhtml += "<h3>[R.name] <div id=\"prog[R.id]\" style=\"float: right;\"><span id=\"proglabel[R.id]\" style=\"position:absolute;width: 300px;text-align: center; margin-top:2px; font-size: 9px;\">[R.statusString]</span></div></h3>"
|
||||
newhtml += "<div><div style=\"width:625px;max-width:625px;\">[R.completed ? (length(R.r_desc) ? R.r_desc : R.desc) : R.desc]</div>"
|
||||
newhtml += "<br>Research cost: [R.researchCost] ([wagesystem.research_budget]) | Research duration: [round(R.researchTime / 10)]s<br>"
|
||||
if(istype(R, /datum/materialResearch/scanner))
|
||||
newhtml += "<br>Required Scans:<br>"
|
||||
var/linkcount = 0
|
||||
for(var/datum/materialResearchScan/S in R:requiredScans)
|
||||
newhtml += {"<div id="sc[R.id][linkcount]" style="width:150px;background-color: [S.completed?"#5FD269":"#D2655F"];cursor: pointer; cursor: hand;">[S.name]</div><br>"} //I could use jquery for this but fuck it
|
||||
if(!R.completed) scripts += {"<script>$('#sc[R.id][linkcount]').click(function(){ showDialog("[S.name]<br><br>[S.desc]"); return false; });</script>"}
|
||||
linkcount++
|
||||
|
||||
if(!R.completed) newhtml += "<br><button id=\"btt[R.id]\">Research</button>"
|
||||
newhtml += "</div>"
|
||||
|
||||
scripts += {"<script>$(function(){$( "#prog[R.id]" ).progressbar({value:[R.prcComplete],max:100});$( "#prog[R.id]" ).height(15);$( "#prog[R.id]" ).width(300);});</script>"}
|
||||
scripts += {"<script>$(function(){$( "#btt[R.id]" ).button();});</script>"}
|
||||
scripts += {"<script>$(function(){$( "#btt[R.id]" ).click(function() {callByond("research", \["id=[R.id]"\]);});});</script>"}
|
||||
|
||||
newhtml += "</div>"
|
||||
newhtml += "</div>"
|
||||
newhtml += scripts
|
||||
callJsFunc(usr, "setHtmlId", list(divId ? divId : "#tabs-4", newhtml))
|
||||
return
|
||||
|
||||
proc/callJsFunc(var/client, var/funcName, var/list/params)
|
||||
var/paramsJS = list2params(params)
|
||||
client << output(paramsJS,"materials.browser:[funcName]")
|
||||
return
|
||||
|
||||
proc/generateMaterialInfo()
|
||||
var/matInfo = ""
|
||||
if(!editing) return "No material"
|
||||
matInfo += "<div class=\"matcomptext\">[editing.name]</div>"
|
||||
matInfo += "<div class=\"matcomptext\">[editing.material_flags & MATERIAL_CRYSTAL ? "(Crystal)":""][editing.material_flags & MATERIAL_METAL ? "(Metal)":""][editing.material_flags & MATERIAL_CLOTH ? "(Fabric)":""][editing.material_flags & MATERIAL_ORGANIC ? "(Organic)":""][editing.material_flags & MATERIAL_ENERGY ? "(Energy)":""][editing.material_flags & MATERIAL_RUBBER ? "(Rubber)":""]</div><br>"
|
||||
matInfo += "<div class=\"matcomptext\">Color: <div style=\"width:35px; height:8px; display:inline-block; background-color: [editing.color];margin:0px;border-style: solid;border-width: 1px;\"></div></div>"
|
||||
matInfo += "<div class=\"matcomptext\">Quality: [editing.quality]%</div>"
|
||||
|
||||
for(var/X in editing.properties)
|
||||
matInfo += "<div class=\"matcomptext\">[X]: [editing.getProperty(X)] / [editing.getProperty(X, VALUE_MAX)]</div>"
|
||||
|
||||
matInfo += "<div class=\"matcomptext\">Unique Effects: [editing.triggersTemp.len + editing.triggersChem.len + editing.triggersPickup.len + editing.triggersDrop.len + editing.triggersExp.len + editing.triggersOnAdd.len + editing.triggersOnLife.len + editing.triggersOnAttack.len + editing.triggersOnAttacked.len + editing.triggersOnEntered.len]</div>" //AAAAHHH
|
||||
return matInfo
|
||||
|
||||
/obj/machinery/smelter_portable
|
||||
name = "Portable Smelter"
|
||||
desc = "A small furnace-like machine used to melt and combine metals or minerals."
|
||||
icon = 'icons/obj/crafting.dmi'
|
||||
icon_state = "portsmelter0"
|
||||
anchored = 0
|
||||
density = 1
|
||||
layer = FLOOR_EQUIP_LAYER1
|
||||
var/list/components = list()
|
||||
var/sound/sound_bubble = sound('sound/effects/bubbles.ogg')
|
||||
var/datum/material/output = null
|
||||
var/datum/light/light
|
||||
|
||||
New()
|
||||
..()
|
||||
light = new /datum/light/point
|
||||
light.attach(src)
|
||||
light.set_brightness(0.5)
|
||||
light.set_color(1, 0.6, 0.2)
|
||||
|
||||
proc/resetMats()
|
||||
icon_state = "portsmelter0"
|
||||
output = null
|
||||
for(var/atom/A in components)
|
||||
qdel(A)
|
||||
components.Cut()
|
||||
return
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if(output)
|
||||
var/datum/material_recipe/R = matchesMaterialRecipe(output)
|
||||
if(R)
|
||||
if(R.result_item)
|
||||
var/atom/A = new R.result_item(src.loc)
|
||||
boutput(user, "<span style=\"color:blue\">You remove [A.name] from the [src].</span>")
|
||||
resetMats()
|
||||
return
|
||||
else if(length(R.result_id))
|
||||
output = getCachedMaterial(R.result_id)
|
||||
else
|
||||
R.apply_to(output)
|
||||
|
||||
boutput(user, "<span style=\"color:blue\">You remove [output.name] from the [src].</span>")
|
||||
icon_state = "portsmelter0"
|
||||
|
||||
var/bar_type = getProcessedMaterialForm(output)
|
||||
var/obj/item/material_piece/M = new bar_type(src.loc)
|
||||
|
||||
M.add_fingerprint(user) // May not be the same person who smelted the materials (Convair880).
|
||||
src.add_fingerprint(user) // Add some prints to the smelter too.
|
||||
|
||||
M.setMaterial(output)
|
||||
resetMats()
|
||||
|
||||
if(M.material && prob(M.material.getProperty(PROP_INSTABILITY)))
|
||||
M.visible_message("<span style=\"color:red\">[M] [getMatFailString(M.material.material_flags)]!</span>")
|
||||
M.material.triggerOnFail(M)
|
||||
return
|
||||
|
||||
if(components.len > 0)
|
||||
|
||||
if(!src.powered())
|
||||
boutput(usr, "<span style=\"color:red\">The smelter is not powered.</span>")
|
||||
return
|
||||
else
|
||||
src.use_power(1000)
|
||||
|
||||
light.enable()
|
||||
playsound(src.loc, sound_bubble, 40, 1)
|
||||
if(components.len == 1)
|
||||
boutput(user, "<span style=\"color:red\">You activate the [src].</span>")
|
||||
icon_state = "portsmelter2"
|
||||
sleep(10)
|
||||
var/atom/obj1 = components[1]
|
||||
output = copyMaterial(obj1.material)
|
||||
else
|
||||
icon_state = "portsmelter2"
|
||||
sleep(10)
|
||||
var/atom/obj1 = components[1]
|
||||
var/atom/obj2 = components[2]
|
||||
|
||||
var/datum/material/mat1 = obj1.material
|
||||
var/datum/material/mat2 = obj2.material
|
||||
|
||||
if(!mat1 || !mat2)
|
||||
icon_state = "portsmelter0"
|
||||
return
|
||||
|
||||
output = getFusedMaterial(mat1, mat2)
|
||||
output.generation++
|
||||
logTheThing("station", user, null, "creates a [output] bar (<b>Material:</b> <i>[output.mat_id]</i>) with the [src] at [log_loc(src)].") // Re-added/fixed because of erebite, plasmastone etc. alloys (Convair880).
|
||||
spawn(8)
|
||||
light.disable()
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">There is nothing in the [src].</span>")
|
||||
return
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(W.material != null)
|
||||
if(!W.material.canMix || (!istype(W,/obj/item/raw_material) && !istype(W,/obj/item/material_piece)))
|
||||
boutput(user, "<span style=\"color:red\">This material can not be used in the [src].</span>")
|
||||
return
|
||||
if(W.material.material_flags & MATERIAL_METAL || W.material.material_flags & MATERIAL_CRYSTAL)
|
||||
if(components.len < 2)
|
||||
src.visible_message("<span style=\"color:blue\">[user] puts [W] into [src]</span>")
|
||||
user.drop_item()
|
||||
components.Add(W)
|
||||
W.loc = src
|
||||
icon_state = "portsmelter1"
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">The smelter is already filled to capacity!</span>")
|
||||
return
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">The smelter can only use metals or minerals.</span>")
|
||||
return
|
||||
return
|
||||
|
||||
ex_act(severity)
|
||||
return
|
||||
|
||||
/obj/machinery/loom
|
||||
name = "Auto-loom"
|
||||
desc = "A piece of machinery used to process fabrics."
|
||||
icon = 'icons/obj/crafting.dmi'
|
||||
icon_state = "loom-off"
|
||||
anchored = 1
|
||||
density = 1
|
||||
layer = FLOOR_EQUIP_LAYER1
|
||||
|
||||
var/list/components = list()
|
||||
var/active = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
|
||||
proc/resetMats()
|
||||
icon_state = "loom-off"
|
||||
for(var/atom/A in components)
|
||||
qdel(A)
|
||||
components.Cut()
|
||||
return
|
||||
|
||||
proc/produceMaterial(var/datum/material/O)
|
||||
if(!O) return
|
||||
|
||||
var/datum/material_recipe/R = matchesMaterialRecipe(O)
|
||||
if(R)
|
||||
if(R.result_item)
|
||||
new R.result_item(src.loc)
|
||||
resetMats()
|
||||
return
|
||||
else if(length(R.result_id))
|
||||
O = getCachedMaterial(R.result_id)
|
||||
|
||||
var/obj/item/material_piece/cloth/M = new/obj/item/material_piece/cloth(src.loc)
|
||||
M.setMaterial(O)
|
||||
resetMats()
|
||||
if(M.material && prob(M.material.getProperty(PROP_INSTABILITY)))
|
||||
M.visible_message("<span style=\"color:red\">[M] [getMatFailString(M.material.material_flags)]!</span>")
|
||||
M.material.triggerOnFail(M)
|
||||
return
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if(active) return
|
||||
if(components.len > 0)
|
||||
if(components.len == 1)
|
||||
boutput(user, "<span style=\"color:red\">You activate the [src].</span>")
|
||||
icon_state = "loom-work"
|
||||
playsound(src.loc, "sound/machines/loom.ogg", 35, 0)
|
||||
active = 1
|
||||
sleep(25)
|
||||
active = 0
|
||||
var/atom/obj1 = components[1]
|
||||
produceMaterial(copyMaterial(obj1.material))
|
||||
else
|
||||
icon_state = "loom-work"
|
||||
playsound(src.loc, "sound/machines/loom.ogg", 35, 0)
|
||||
active = 1
|
||||
sleep(25)
|
||||
active = 0
|
||||
var/atom/obj1 = components[1]
|
||||
var/atom/obj2 = components[2]
|
||||
|
||||
var/datum/material/mat1 = obj1.material
|
||||
var/datum/material/mat2 = obj2.material
|
||||
|
||||
if(!mat1 || !mat2)
|
||||
icon_state = "loom-off"
|
||||
return
|
||||
|
||||
var/datum/material/output = getFusedMaterial(mat1, mat2)
|
||||
output.generation++
|
||||
produceMaterial(output)
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">There is nothing in the [src].</span>")
|
||||
return
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(active) return
|
||||
|
||||
if (istype(W,/obj/item/clothing/under/))
|
||||
src.visible_message("<span style=\"color:blue\">[user] puts [W] into [src]</span>")
|
||||
var/datum/material/M
|
||||
if (W.material)
|
||||
M = W.material
|
||||
else
|
||||
M = getCachedMaterial("cotton")
|
||||
qdel(W)
|
||||
icon_state = "loom-work"
|
||||
playsound(src.loc, "sound/machines/loom.ogg", 35, 0)
|
||||
active = 1
|
||||
sleep(10)
|
||||
active = 0
|
||||
produceMaterial(M)
|
||||
return
|
||||
|
||||
if (istype(W,/obj/item/clothing/shoes/))
|
||||
src.visible_message("<span style=\"color:blue\">[user] puts [W] into [src]</span>")
|
||||
var/datum/material/M
|
||||
if (W.material)
|
||||
M = W.material
|
||||
else
|
||||
M = getCachedMaterial("leather")
|
||||
qdel(W)
|
||||
icon_state = "loom-work"
|
||||
playsound(src.loc, "sound/machines/loom.ogg", 35, 0)
|
||||
active = 1
|
||||
sleep(10)
|
||||
active = 0
|
||||
produceMaterial(M)
|
||||
return
|
||||
|
||||
if(W.material != null)
|
||||
if(!W.material.canMix)
|
||||
boutput(user, "<span style=\"color:red\">This material can not be used in the [src].</span>")
|
||||
return
|
||||
|
||||
if(W.material.material_flags & MATERIAL_CLOTH || W.material.material_flags & MATERIAL_RUBBER)
|
||||
if(components.len < 2)
|
||||
icon_state = "loom-on"
|
||||
src.visible_message("<span style=\"color:blue\">[user] puts [W] into [src]</span>")
|
||||
user.drop_item()
|
||||
components.Add(W)
|
||||
W.loc = src
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">The loom can not hold any more materials!</span>")
|
||||
return
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">The loom can only use cloth or rubber.</span>")
|
||||
return
|
||||
return
|
||||
|
||||
ex_act(severity)
|
||||
return
|
||||
|
||||
/obj/machinery/smelter
|
||||
name = "Arc Smelter"
|
||||
desc = "A huge furnace-like machine used to melt and combine metals or minerals."
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "smelter0"
|
||||
anchored = 1
|
||||
bound_height = 96
|
||||
bound_width = 96
|
||||
density = 1
|
||||
layer = FLOOR_EQUIP_LAYER1
|
||||
|
||||
var/list/components = list()
|
||||
var/slag_level = 0
|
||||
|
||||
var/sound/sound_thunk = sound('sound/items/Deconstruct.ogg')
|
||||
var/sound/sound_zap = sound('sound/effects/elec_bzzz.ogg')
|
||||
var/sound/sound_hiss = sound('sound/machines/hiss.ogg')
|
||||
var/sound/sound_bubble = sound('sound/effects/bubbles.ogg')
|
||||
|
||||
var/datum/material/output = null
|
||||
var/datum/light/light
|
||||
|
||||
New()
|
||||
..()
|
||||
light = new /datum/light/point
|
||||
light.attach(src, 1.5, 1.5)
|
||||
light.set_brightness(0.5)
|
||||
light.set_color(0.4, 0.8, 1)
|
||||
|
||||
proc/resetMats()
|
||||
icon_state = "smelter0"
|
||||
output = null
|
||||
for(var/atom/A in components)
|
||||
qdel(A)
|
||||
components.Cut()
|
||||
return
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if(output)
|
||||
var/datum/material_recipe/R = matchesMaterialRecipe(output)
|
||||
if(R)
|
||||
if(R.result_item)
|
||||
var/atom/A = new R.result_item(locate(src.x + 1, src.y, src.z))
|
||||
boutput(user, "<span style=\"color:blue\">You remove [A.name] from the [src].</span>")
|
||||
playsound(src.loc, sound_thunk, 40, 1)
|
||||
resetMats()
|
||||
return
|
||||
else if(length(R.result_id))
|
||||
output = getCachedMaterial(R.result_id)
|
||||
else
|
||||
R.apply_to(output)
|
||||
|
||||
boutput(user, "<span style=\"color:blue\">You remove [output.name] from the [src].</span>")
|
||||
|
||||
var/bar_type = getProcessedMaterialForm(output)
|
||||
var/obj/item/material_piece/M = new bar_type(locate(src.x + 1, src.y, src.z))
|
||||
|
||||
M.add_fingerprint(user) // May not be the same person who smelted the materials (Convair880).
|
||||
src.add_fingerprint(user) // Add some prints to the smelter too.
|
||||
|
||||
M.setMaterial(output)
|
||||
resetMats()
|
||||
playsound(src.loc, sound_thunk, 40, 1)
|
||||
|
||||
if(M.material && prob(M.material.getProperty(PROP_INSTABILITY)))
|
||||
M.visible_message("<span style=\"color:red\">[M] [getMatFailString(M.material.material_flags)]!</span>")
|
||||
M.material.triggerOnFail(M)
|
||||
return
|
||||
|
||||
if(components.len > 0)
|
||||
light.enable()
|
||||
playsound(src.loc, sound_zap, 40, 1)
|
||||
spawn(5)
|
||||
playsound(src.loc, sound_bubble, 40, 1)
|
||||
if(components.len == 1)
|
||||
boutput(user, "<span style=\"color:red\">You activate the [src].</span>")
|
||||
icon_state = "smelter1"
|
||||
sleep(10)
|
||||
var/atom/obj1 = components[1]
|
||||
output = copyMaterial(obj1.material)
|
||||
logTheThing("station", user, null, "creates a [output] bar (<b>Material:</b> <i>[output.mat_id]</i>) with the [src] at [log_loc(src)].") // Re-added/fixed because of erebite, plasmastone etc. alloys (Convair880).
|
||||
handleSlag()
|
||||
else
|
||||
icon_state = "smelter1"
|
||||
sleep(10)
|
||||
var/atom/obj1 = components[1]
|
||||
var/atom/obj2 = components[2]
|
||||
|
||||
var/datum/material/mat1 = obj1.material
|
||||
var/datum/material/mat2 = obj2.material
|
||||
|
||||
if(!mat1 || !mat2)
|
||||
icon_state = "smelter0"
|
||||
return
|
||||
|
||||
output = getFusedMaterial(mat1, mat2)
|
||||
output.generation++
|
||||
logTheThing("station", user, null, "creates a [output] bar (<b>Material:</b> <i>[output.mat_id]</i>) with the [src] at [log_loc(src)].") // Sorry for code duplication, but I'm regularly seeing runtime errors for some reason if this proc is called after handleSlag (Convair880).
|
||||
handleSlag()
|
||||
spawn(8)
|
||||
playsound(src.loc, sound_hiss, 45, 1)
|
||||
light.disable()
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">There is nothing in the [src].</span>")
|
||||
return
|
||||
|
||||
proc/handleSlag()
|
||||
switch(slag_level)
|
||||
if(500 to 1000)
|
||||
particleMaster.SpawnSystem(new /datum/particleSystem/localSmoke("#967360", 10, locate(src.x +1, src.y, src.z)))
|
||||
//output.adjustProperty(PROP_INSTABILITY , 5)
|
||||
output.quality += rand(5, -15)
|
||||
if(1000 to INFINITY)
|
||||
particleMaster.SpawnSystem(new /datum/particleSystem/localSmoke("#221511", 10, locate(src.x +1, src.y, src.z)))
|
||||
output.quality += rand(-15, -30)
|
||||
//output.adjustProperty(PROP_INSTABILITY , 15)
|
||||
slag_level += (100 - output.quality)
|
||||
return
|
||||
|
||||
suicide(var/mob/user)
|
||||
if (!user)
|
||||
return
|
||||
|
||||
user.visible_message("<span style=\"color:red\"><b>[user] hops right into [src]! Jesus!</b></span>")
|
||||
user.unequip_all()
|
||||
user.set_loc(src)
|
||||
|
||||
|
||||
var/datum/material/M = new /datum/material/organic/flesh {desc="A disgusting wad of flesh."; color="#881111";} ()
|
||||
M.name = "[user.real_name] flesh"
|
||||
|
||||
var/obj/item/dummyItem = new (src)
|
||||
dummyItem.material = M
|
||||
components += dummyItem
|
||||
user.ghostize()
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if (istype(W, /obj/item/slag_shovel))
|
||||
if(slag_level)
|
||||
src.visible_message("<span style=\"color:blue\">[user] removes slag from the [src]</span>")
|
||||
slag_level = 0
|
||||
new/obj/item/material_piece/slag(src.loc)
|
||||
return
|
||||
else
|
||||
boutput(user, "<span style=\"color:blue\">There is no slag in [src].</span>")
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/wizard_crystal) && components.len < 2 && !W.material)
|
||||
W.material = new W:assoc_material()
|
||||
|
||||
if(W.material != null)
|
||||
if(!W.material.canMix)
|
||||
boutput(user, "<span style=\"color:red\">This material can not be used in the [src].</span>")
|
||||
return
|
||||
|
||||
if((W.material.material_flags & MATERIAL_METAL || W.material.material_flags & MATERIAL_CRYSTAL) && (istype(W, /obj/item/material_piece) || istype(W, /obj/item/raw_material)) )
|
||||
if(components.len < 2)
|
||||
src.visible_message("<span style=\"color:blue\">[user] puts [W] into [src]</span>")
|
||||
user.drop_item()
|
||||
components.Add(W)
|
||||
W.loc = src
|
||||
playsound(src.loc, sound_thunk, 40, 1)
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">The smelter is already filled to capacity!</span>")
|
||||
return
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">The smelter can only use metals or minerals in raw form.</span>")
|
||||
return
|
||||
return
|
||||
|
||||
ex_act(severity) // bloo bloo we blew it up and nobody gets to have fun
|
||||
return
|
||||
|
||||
//
|
||||
/obj/item/device/matanalyzer
|
||||
icon_state = "matanalyzer"
|
||||
name = "Material analyzer"
|
||||
flags = FPRINT | EXTRADELAY | TABLEPASS | CONDUCT
|
||||
w_class = 2
|
||||
|
||||
afterattack(atom/target as mob|obj|turf|area, mob/user as mob)
|
||||
if(get_dist(src, target) <= 2)
|
||||
var/atom/W = target
|
||||
if(!W.material)
|
||||
boutput(user, "<span style=\"color:red\">No material found.</span>")
|
||||
else
|
||||
boutput(user, "<span style=\"color:blue\">[W.material.name]</span>")
|
||||
boutput(user, "<span style=\"color:blue\">[W.material.desc]</span>")
|
||||
boutput(user, "<span style=\"color:blue\">Quality: [W.material.quality]%</span>")
|
||||
boutput(user, "<br>")
|
||||
|
||||
if(W.material.properties.len)
|
||||
boutput(user, "Noteworthy properties:")
|
||||
for(var/X in W.material.properties)
|
||||
boutput(user, "<span style=\"color:blue\">[X]: [W.material.getProperty(X)] / [W.material.getProperty(X, VALUE_MAX)]</span>")
|
||||
|
||||
if(W.material.triggersTemp.len || W.material.triggersChem.len || W.material.triggersPickup.len || W.material.triggersDrop.len || W.material.triggersExp.len || W.material.triggersOnAdd.len || W.material.triggersOnLife.len || W.material.triggersOnAttack.len || W.material.triggersOnAttacked.len)
|
||||
boutput(user, "<span style=\"color:blue\">Material has unique properties.</span>")
|
||||
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">[target] is too far away.</span>")
|
||||
return
|
||||
|
||||
/obj/item/slag_shovel
|
||||
name = "slag shovel"
|
||||
desc = "Used to remove slag from the arc smelter."
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "shovel"
|
||||
inhand_image_icon = 'icons/mob/inhand/hand_tools.dmi'
|
||||
item_state = "pick"
|
||||
w_class = 3
|
||||
flags = ONBELT
|
||||
force = 7 // 15 puts it significantly above most other weapons
|
||||
hitsound = 'sound/weapons/smash.ogg'
|
||||
@@ -0,0 +1,438 @@
|
||||
var/global/list/material_cache = list()
|
||||
/atom/var/datum/material/material = null
|
||||
|
||||
//This contains the names of the trigger lists on materials. Required for copying materials. Remember to keep this updated if you add new triggers.
|
||||
var/global/list/triggerVars = list("triggersFail", "triggersTemp", "triggersChem", "triggersPickup", "triggersDrop", "triggersExp", "triggersOnAdd", "triggersOnLife", "triggersOnAttack", "triggersOnAttacked", "triggersOnEntered")
|
||||
|
||||
//Returns one of the base materials by id.
|
||||
/proc/getCachedMaterial(var/mat)
|
||||
if(!istext(mat) || !length(mat)) return null
|
||||
if(!material_cache.len) buildMaterialCache()
|
||||
if(material_cache.Find(mat)) return copyMaterial(material_cache[mat])
|
||||
return null
|
||||
|
||||
/proc/mergeProperties(var/list/l1, var/list/l2, var/bias=0.5)
|
||||
if(!l1) CRASH("SOME IDIOT TRIED TO MERGE LISTS WITHOUT PASSING LISTS TO MERGEPROPERTIES")
|
||||
var/oBias = 1 - bias
|
||||
|
||||
var/list/merged = list()
|
||||
|
||||
for(var/o in l1)
|
||||
merged.Add(o)
|
||||
var/datum/material_property/Base = l1[o]
|
||||
var/datum/material_property/newProp = new/datum/material_property()
|
||||
merged[o] = newProp
|
||||
newProp.name = o
|
||||
newProp.value_max = Base.value_max
|
||||
newProp.value_min = Base.value_min
|
||||
newProp.value = Base.value
|
||||
|
||||
if(l2)
|
||||
for(var/x in l2)
|
||||
if(merged.Find(x))
|
||||
var/datum/material_property/Base = l2[x]
|
||||
var/datum/material_property/Modded = merged[x]
|
||||
Modded.value_min = round(Modded.value_min * oBias + Base.value_min * bias)
|
||||
Modded.value_max = round(Modded.value_max * oBias + Base.value_max * bias)
|
||||
Modded.value = round(Modded.value * oBias + Base.value * bias)
|
||||
else
|
||||
var/datum/material_property/Base = l2[x]
|
||||
var/datum/material_property/newProp = new/datum/material_property()
|
||||
merged[x] = newProp
|
||||
newProp.name = x
|
||||
newProp.value_max = Base.value_max
|
||||
newProp.value_min = Base.value_min
|
||||
newProp.value = Base.value
|
||||
return merged
|
||||
|
||||
//Returns a copy of a given material.
|
||||
/proc/copyMaterial(var/datum/material/base)
|
||||
if(!base || !istype(base, /datum/material))
|
||||
var/datum/material/M = new/datum/material()
|
||||
return M
|
||||
else
|
||||
var/datum/material/M = new base.type ()
|
||||
|
||||
var/list/copyProps = mergeProperties(base.properties)
|
||||
M.properties = copyProps
|
||||
|
||||
for(var/X in base.vars)
|
||||
if(X == "type" || X == "parent_type" || X == "tag" || X == "vars" || X == "properties") continue
|
||||
|
||||
if(X in triggerVars)
|
||||
M.vars[X] = getFusedTriggers(base.vars[X], list()) //Pass in an empty list to basically copy the first one.
|
||||
else
|
||||
if(M.vars.Find(X))
|
||||
if(istype(base.vars[X],/list))
|
||||
var/list/oldList = base.vars[X]
|
||||
M.vars[X] = oldList.Copy()
|
||||
else
|
||||
M.vars[X] = base.vars[X]
|
||||
return M
|
||||
return null
|
||||
|
||||
//Simply removes a material from an object.
|
||||
/atom/proc/removeMaterial()
|
||||
if(src.mat_changename)
|
||||
src.remove_prefixes(99)
|
||||
src.remove_suffixes(99)
|
||||
src.UpdateName()
|
||||
//src.name = initial(src.name)
|
||||
|
||||
if(src.mat_changedesc)
|
||||
src.desc = initial(src.desc)
|
||||
|
||||
src.alpha = initial(src.alpha)
|
||||
src.color = initial(src.color)
|
||||
|
||||
src.UpdateOverlays(null, "material")
|
||||
|
||||
src.material = null
|
||||
return
|
||||
|
||||
//Time for some super verbose proc names.
|
||||
/proc/get_material_trait_desc(var/datum/material/mat1)
|
||||
var/string = ""
|
||||
var/list/allTriggers = (mat1.triggersFail + mat1.triggersTemp + mat1.triggersChem + mat1.triggersPickup + mat1.triggersDrop + mat1.triggersExp + mat1.triggersOnAdd + mat1.triggersOnLife + mat1.triggersOnAttack + mat1.triggersOnAttacked + mat1.triggersOnEntered)
|
||||
for(var/datum/materialProc/P in allTriggers)
|
||||
if(length(P.desc))
|
||||
if(length(string))
|
||||
if(!findtext(string,P.desc))
|
||||
string += " " + P.desc
|
||||
else
|
||||
string = P.desc
|
||||
return string
|
||||
|
||||
//Sets the material of an object. PLEASE USE THIS TO SET MATERIALS UNLESS YOU KNOW WHAT YOU'RE DOING.
|
||||
/atom/proc/setMaterial(var/datum/material/mat1)
|
||||
if(!mat1 ||!istype(mat1, /datum/material)) return
|
||||
var/traitDesc = get_material_trait_desc(mat1)
|
||||
var/strPrefix = dd_list2text(mat1.prefixes, " ")
|
||||
var/strSuffix = dd_list2text(mat1.suffixes, " ")
|
||||
// Setting mat_changename/desc == 0 is almost as conspicuous as having "good gold chameleon bombs".
|
||||
// Real_desc/name is a substandard implementation, but it will prevent some midas touch exploits (Convair880).
|
||||
if (src.mat_changename) // now that I've cleaned up the name prefix/suffix stuff, let's try this, in the hopes that eveything that SHOULD override UpdateName() actually DOES - Haine
|
||||
src.remove_prefixes(99) // janky but better than ending up with uhh
|
||||
src.remove_suffixes(99) // "This is a good gold good gold good gold good gold good gold good gold good gold good gold good gold good gold bedsheet."
|
||||
src.name_prefix(strPrefix ? strPrefix : "")
|
||||
src.name_prefix(length(getQualityName(mat1.quality)) ? getQualityName(mat1.quality) : "")
|
||||
src.name_prefix(mat1.name ? mat1.name : "")
|
||||
src.name_suffix(strSuffix ? "of [strSuffix]" : "")
|
||||
src.UpdateName()
|
||||
/* if (istype(src, /obj))
|
||||
var/obj/O = src
|
||||
O.name = "[strPrefix ? strPrefix + " ":""][length(getQualityName(mat1.quality)) ? getQualityName(mat1.quality) + " ":""][mat1.name ? mat1.name + " ":""][!isnull(O.real_name) ? "[O.real_name]" : "[initial(O.name)]"][strSuffix ? (" of " + strSuffix) : ""]"
|
||||
else
|
||||
src.name = "[strPrefix ? strPrefix + " ":""][length(getQualityName(mat1.quality)) ? getQualityName(mat1.quality) + " ":""][mat1.name ? mat1.name + " ":""][initial(src.name)][strSuffix ? (" of " + strSuffix) : ""]"
|
||||
*/
|
||||
if (src.mat_changedesc)
|
||||
if (istype(src, /obj))
|
||||
var/obj/O2 = src
|
||||
O2.desc = "[!isnull(O2.real_desc) ? "[O2.real_desc]" : "[initial(O2.desc)]"] It is made of [mat1.name].[length(traitDesc) ? " " + traitDesc : ""]"
|
||||
else
|
||||
src.desc = "[initial(src.desc)] It is made of [mat1.name].[length(traitDesc) ? " " + traitDesc : ""]"
|
||||
if(mat1.texture)
|
||||
src.setTexture(mat1.texture, mat1.texture_blend, "material")
|
||||
src.alpha = mat1.alpha
|
||||
src.color = mat1.color
|
||||
src.material = mat1
|
||||
mat1.owner = src
|
||||
mat1.triggerOnAdd(src)
|
||||
src.onMaterialChanged()
|
||||
return
|
||||
|
||||
/proc/getProcessedMaterialForm(var/datum/material/MAT)
|
||||
if (!istype(MAT))
|
||||
return /obj/item/material_piece // just in case
|
||||
|
||||
// higher on this list means higher priority, be careful with it!
|
||||
if (MAT.material_flags & MATERIAL_CRYSTAL)
|
||||
return /obj/item/material_piece/block
|
||||
if (MAT.material_flags & MATERIAL_METAL)
|
||||
return /obj/item/material_piece
|
||||
if (MAT.material_flags & MATERIAL_ORGANIC)
|
||||
return /obj/item/material_piece/wad
|
||||
if (MAT.material_flags & MATERIAL_CLOTH)
|
||||
return /obj/item/material_piece/cloth
|
||||
if (MAT.material_flags & MATERIAL_RUBBER)
|
||||
return /obj/item/material_piece/block
|
||||
if (MAT.material_flags & MATERIAL_ENERGY)
|
||||
return /obj/item/material_piece/sphere
|
||||
|
||||
return /obj/item/material_piece
|
||||
|
||||
//Increases generations on material triggers and handles removal if over the generation cap.
|
||||
/proc/handleTriggerGenerations(var/list/toDo)
|
||||
for(var/datum/materialProc/current in toDo)
|
||||
if(current.max_generations != -1 && (toDo[current] + 1) > current.max_generations) toDo.Remove(current)
|
||||
else toDo[current] = (toDo[current] + 1)
|
||||
return toDo
|
||||
|
||||
//Fuses two material trigger lists.
|
||||
/proc/getFusedTriggers(var/list/L1 , var/list/L2)
|
||||
var/list/newList = list()
|
||||
for(var/datum/materialProc/toCopy in L1) //Copy list 1 with new instances of trigger datum.
|
||||
var/datum/materialProc/P = new toCopy.type()
|
||||
newList.Add(P) //Add new instance of datum
|
||||
newList[P] = L1[toCopy] //Set generation
|
||||
for(var/varCopy in toCopy.vars)
|
||||
if(varCopy == "type" || varCopy == "id" || varCopy == "parent_type" || varCopy == "tag" || varCopy == "vars") continue
|
||||
if(!issaved(toCopy.vars[varCopy])) continue
|
||||
P.vars[varCopy] = toCopy.vars[varCopy]
|
||||
|
||||
for(var/datum/materialProc/A in L2) //Go through second list
|
||||
if((locate(A.type) in newList)) //We already have that trigger type from the other list
|
||||
var/datum/materialProc/existing = (locate(A.type) in newList) //Get the trigger datum from the other list
|
||||
if(newList[existing] <= L2[A]) continue //If the generation of the datum that already exists is lower or equal to the new one, leave it alone.
|
||||
else newList[existing] = L2[A] //Otherwise set the generation to the generation of the second copy because it is lower.
|
||||
else //Trigger type isnt in the list yet.
|
||||
var/datum/materialProc/newProc = new A.type() //Create a new instance
|
||||
newList.Add(newProc) //Add to list
|
||||
newList[newProc] = L2[A] //Set generation
|
||||
for(var/varCopy in A.vars)
|
||||
if(varCopy == "type" || varCopy == "id" || varCopy == "parent_type" || varCopy == "tag" || varCopy == "vars") continue
|
||||
if(!issaved(A.vars[varCopy])) continue
|
||||
newProc.vars[varCopy] = A.vars[varCopy]
|
||||
return newList
|
||||
|
||||
/proc/getFusedMaterial(var/datum/material/mat1,var/datum/material/mat2)
|
||||
//Merges two materials and returns result as new material.
|
||||
return getInterpolatedMaterial(mat1, mat2, 0.5)
|
||||
|
||||
/proc/getInterpolatedMaterial(var/datum/material/mat1,var/datum/material/mat2,var/t)
|
||||
var/ot = 1 - t
|
||||
var/datum/material/newMat = new()
|
||||
|
||||
newMat.quality = round(mat1.quality * ot + mat2.quality * t)
|
||||
|
||||
newMat.prefixes = (mat1.prefixes | mat2.prefixes)
|
||||
newMat.suffixes = (mat1.suffixes | mat2.suffixes)
|
||||
|
||||
//newMat.name = getInterpolatedName(mat1.name, mat2.name, t)
|
||||
newMat.name = getInterpolatedName(mat1.name, mat2.name, 0.5)
|
||||
newMat.mat_id = "([mat1.mat_id]+[mat2.mat_id])"
|
||||
newMat.alpha = round(mat1.alpha * ot + mat2.alpha * t)
|
||||
newMat.color = rgb(round(GetRedPart(mat1.color) * ot + GetRedPart(mat2.color) * t), round(GetGreenPart(mat1.color) * ot + GetGreenPart(mat2.color) * t), round(GetBluePart(mat1.color) * ot + GetBluePart(mat2.color) * t))
|
||||
newMat.properties = mergeProperties(mat1.properties, mat2.properties, t)
|
||||
//--
|
||||
newMat.triggersFail = getFusedTriggers(mat1.triggersFail, mat2.triggersFail)
|
||||
newMat.triggersTemp = getFusedTriggers(mat1.triggersTemp, mat2.triggersTemp)
|
||||
newMat.triggersChem = getFusedTriggers(mat1.triggersChem, mat2.triggersChem)
|
||||
newMat.triggersPickup = getFusedTriggers(mat1.triggersPickup, mat2.triggersPickup)
|
||||
newMat.triggersDrop = getFusedTriggers(mat1.triggersDrop, mat2.triggersDrop)
|
||||
newMat.triggersExp = getFusedTriggers(mat1.triggersExp, mat2.triggersExp)
|
||||
newMat.triggersOnAdd = getFusedTriggers(mat1.triggersOnAdd, mat2.triggersOnAdd)
|
||||
newMat.triggersOnLife = getFusedTriggers(mat1.triggersOnLife, mat2.triggersOnLife)
|
||||
newMat.triggersOnAttack = getFusedTriggers(mat1.triggersOnAttack, mat2.triggersOnAttack)
|
||||
newMat.triggersOnAttacked = getFusedTriggers(mat1.triggersOnAttacked, mat2.triggersOnAttacked)
|
||||
newMat.triggersOnEntered = getFusedTriggers(mat1.triggersOnEntered, mat2.triggersOnEntered)
|
||||
|
||||
handleTriggerGenerations(newMat.triggersFail)
|
||||
handleTriggerGenerations(newMat.triggersTemp)
|
||||
handleTriggerGenerations(newMat.triggersChem)
|
||||
handleTriggerGenerations(newMat.triggersPickup)
|
||||
handleTriggerGenerations(newMat.triggersDrop)
|
||||
handleTriggerGenerations(newMat.triggersExp)
|
||||
handleTriggerGenerations(newMat.triggersOnAdd)
|
||||
handleTriggerGenerations(newMat.triggersOnLife)
|
||||
handleTriggerGenerations(newMat.triggersOnAttack)
|
||||
handleTriggerGenerations(newMat.triggersOnAttacked)
|
||||
handleTriggerGenerations(newMat.triggersOnEntered)
|
||||
//--
|
||||
|
||||
//Texture merging. SUPER DUPER UGLY AAAAH
|
||||
if(mat2.texture && !mat1.texture)
|
||||
newMat.texture = mat2.texture
|
||||
newMat.texture_blend = mat2.texture_blend
|
||||
else if (mat1.texture && !mat2.texture)
|
||||
newMat.texture = mat2.texture
|
||||
newMat.texture_blend = mat1.texture_blend
|
||||
else if (mat1.texture && mat2.texture)
|
||||
if(mat1.generation == mat2.generation)
|
||||
//Mat1 has higher priority in this case. Optional: implement some shitty blended texture thing. probably a bad idea.
|
||||
newMat.texture = mat1.texture
|
||||
newMat.texture_blend = mat1.texture_blend
|
||||
else
|
||||
if(mat1.generation < mat2.generation)
|
||||
newMat.texture = mat1.texture
|
||||
newMat.texture_blend = mat1.texture_blend
|
||||
else
|
||||
newMat.texture = mat2.texture
|
||||
newMat.texture_blend = mat2.texture_blend
|
||||
//
|
||||
|
||||
//This is sub-optimal and only used because im dumb
|
||||
if(mat1.material_flags & MATERIAL_CRYSTAL || mat2.material_flags & MATERIAL_CRYSTAL) newMat.material_flags |= MATERIAL_CRYSTAL
|
||||
if(mat1.material_flags & MATERIAL_METAL || mat2.material_flags & MATERIAL_METAL) newMat.material_flags |= MATERIAL_METAL
|
||||
if(mat1.material_flags & MATERIAL_CLOTH || mat2.material_flags & MATERIAL_CLOTH) newMat.material_flags |= MATERIAL_CLOTH
|
||||
if(mat1.material_flags & MATERIAL_ORGANIC || mat2.material_flags & MATERIAL_ORGANIC) newMat.material_flags |= MATERIAL_ORGANIC
|
||||
if(mat1.material_flags & MATERIAL_ENERGY || mat2.material_flags & MATERIAL_ENERGY) newMat.material_flags |= MATERIAL_ENERGY
|
||||
if(mat1.material_flags & MATERIAL_RUBBER || mat2.material_flags & MATERIAL_RUBBER) newMat.material_flags |= MATERIAL_RUBBER
|
||||
|
||||
newMat.parent_materials.Add(mat1)
|
||||
newMat.parent_materials.Add(mat2)
|
||||
|
||||
return newMat
|
||||
|
||||
//Merges two material names into one.
|
||||
/proc/getInterpolatedName(var/mat1, var/mat2, var/t)
|
||||
var/ot = 1 - t
|
||||
var/part1 = copytext(mat1, 1, round((length(mat1) * ot) + 0.5))
|
||||
var/part2 = copytext(mat2, round((length(mat2) * ot) + 0.5), 0)
|
||||
return capitalize(ckey("[part1][part2]"))
|
||||
|
||||
//Returns a string for when a material fail or breaks depending on its material flags.
|
||||
/proc/getMatFailString(var/flag)
|
||||
if(flag & MATERIAL_METAL && flag & MATERIAL_CRYSTAL && flag & MATERIAL_CLOTH)
|
||||
return "frays apart into worthless dusty fibers"
|
||||
if(flag & MATERIAL_METAL && flag & MATERIAL_CRYSTAL)
|
||||
return "cracks and shatters into unworkable dust"
|
||||
if(flag & MATERIAL_CLOTH && flag & MATERIAL_CRYSTAL)
|
||||
return "shatters into useless brittle fibers"
|
||||
if(flag & MATERIAL_ENERGY && flag & MATERIAL_CRYSTAL)
|
||||
return "violently disintegrates into vapor"
|
||||
if(flag & MATERIAL_ENERGY && flag & MATERIAL_METAL)
|
||||
return "shines brightly before self-vaporizing"
|
||||
if(flag & MATERIAL_ENERGY && flag & MATERIAL_CLOTH)
|
||||
return "bursts into flames and is gone almost instantly"
|
||||
if(flag & MATERIAL_ENERGY && flag & MATERIAL_ORGANIC)
|
||||
return "catches on fire and rapidly burns to ash"
|
||||
if(flag & MATERIAL_ORGANIC)
|
||||
return "crumbles into worthless slime"
|
||||
if(flag & MATERIAL_CRYSTAL)
|
||||
return "shatters to dust and blows away"
|
||||
if(flag & MATERIAL_METAL)
|
||||
return "disintegrates into useless flakes"
|
||||
if(flag & MATERIAL_CLOTH)
|
||||
return "frays apart into useless strands"
|
||||
if(flag & MATERIAL_ENERGY)
|
||||
return "suddenly vanishes into nothingness"
|
||||
if(flag & MATERIAL_RUBBER)
|
||||
return "melts into an unworkable pile of slop"
|
||||
return "comes apart"
|
||||
|
||||
//Translates a material flag into a string.
|
||||
/proc/getMatFlagString(var/flag)
|
||||
switch(flag)
|
||||
if(MATERIAL_CRYSTAL)
|
||||
return "Crystal"
|
||||
if(MATERIAL_METAL)
|
||||
return "Metal"
|
||||
if(MATERIAL_CLOTH)
|
||||
return "Fabric"
|
||||
if(MATERIAL_ORGANIC)
|
||||
return "Organic Matter"
|
||||
if(MATERIAL_ENERGY)
|
||||
return "Energy Source"
|
||||
if(MATERIAL_RUBBER)
|
||||
return "Rubber"
|
||||
else
|
||||
return "Unknown"
|
||||
return
|
||||
|
||||
//Simply returns a string for a given quality. Used as prefix for objects.
|
||||
/proc/getQualityName(var/quality)
|
||||
switch(quality)
|
||||
if(-INFINITY to -101)
|
||||
return "useless"
|
||||
if(-100 to -91)
|
||||
return "atrocious"
|
||||
if(-90 to -81)
|
||||
return "wretched"
|
||||
if(-80 to -71)
|
||||
return "crap"
|
||||
if(-70 to -61)
|
||||
return "awful"
|
||||
if(-60 to -51)
|
||||
return "terrible"
|
||||
if(-50 to -41)
|
||||
return "bad"
|
||||
if(-40 to -31)
|
||||
return "shabby"
|
||||
if(-30 to -21)
|
||||
return "mediocre"
|
||||
if(-20 to -11)
|
||||
return "low-quality"
|
||||
if(-10 to -1)
|
||||
return "poor"
|
||||
if(0)
|
||||
return ""
|
||||
if(1 to 10)
|
||||
return "decent"
|
||||
if(11 to 20)
|
||||
return "fine"
|
||||
if(21 to 30)
|
||||
return "good"
|
||||
if(31 to 40)
|
||||
return "great"
|
||||
if(41 to 50)
|
||||
return "high-quality"
|
||||
if(51 to 60)
|
||||
return "excellent"
|
||||
if(61 to 70)
|
||||
return "superb"
|
||||
if(71 to 80)
|
||||
return "incredible"
|
||||
if(81 to 90)
|
||||
return "amazing"
|
||||
if(91 to 100)
|
||||
return "supreme"
|
||||
if(101 to INFINITY)
|
||||
return "perfect"
|
||||
else
|
||||
return "odd"
|
||||
return
|
||||
|
||||
//Checks if a material matches a recipe and returns the recipe if a match is found. returns null if nothing matches it.
|
||||
/proc/matchesMaterialRecipe(var/datum/material/M)
|
||||
for(var/datum/material_recipe/R in materialRecipes)
|
||||
if(R.validate(M)) return R
|
||||
return null
|
||||
|
||||
//Searches the parent materials of the given material, up to a given generation, for an id.
|
||||
//Useful if you want to figure out if a given material was used in the making of another material.
|
||||
//Keep in mind that this can be expensive so use it only when you have to.
|
||||
/proc/hasParentMaterial(var/datum/material/M, var/search_id, var/max_generations = 3)
|
||||
return searchMatTree(M, search_id, 0, max_generations)
|
||||
|
||||
/proc/searchMatTree(var/datum/material/M, var/id, var/current_depth, var/max_depth = 3)
|
||||
if(!M || !id) return null
|
||||
if(!M.parent_materials.len) return null
|
||||
for(var/datum/material/CM in M.parent_materials)
|
||||
if(CM.mat_id == id) return CM
|
||||
if(current_depth + 1 <= max_depth)
|
||||
var/temp = searchMatTree(CM, id, current_depth + 1, max_depth)
|
||||
if(temp) return temp
|
||||
return null
|
||||
|
||||
//Yes hello apparently we need a proc for this because theres a million types of different wires and cables.
|
||||
/proc/applyCableMaterials(var/atom/C, var/datum/material/insulator, var/datum/material/conductor)
|
||||
if(!conductor) return // silly
|
||||
|
||||
if(istype(C, /obj/cable))
|
||||
var/obj/cable/cable = C
|
||||
cable.insulator = insulator
|
||||
cable.conductor = conductor
|
||||
|
||||
if (cable.insulator)
|
||||
cable.setMaterial(copyMaterial(cable.insulator))
|
||||
cable.name = "[cable.insulator.name]-insulated [cable.conductor.name]-cable"
|
||||
cable.color = cable.insulator.color
|
||||
else
|
||||
cable.setMaterial(copyMaterial(cable.conductor))
|
||||
cable.name = "uninsulated [cable.conductor.name]-cable"
|
||||
cable.color = cable.conductor.color
|
||||
|
||||
if(istype(C, /obj/item/cable_coil))
|
||||
var/obj/item/cable_coil/coil = C
|
||||
|
||||
coil.insulator = insulator
|
||||
coil.conductor = conductor
|
||||
|
||||
if (coil.insulator)
|
||||
coil.setMaterial(copyMaterial(coil.insulator))
|
||||
coil.color = coil.insulator.color
|
||||
else
|
||||
coil.setMaterial(copyMaterial(coil.conductor))
|
||||
coil.color = coil.conductor.color
|
||||
coil.updateName()
|
||||
@@ -0,0 +1,172 @@
|
||||
/obj/item/material_piece
|
||||
name = "bar"
|
||||
desc = "Some sort of processed material bar."
|
||||
icon = 'icons/obj/materials.dmi'
|
||||
icon_state = "bar"
|
||||
var/default_material = null // used for prefab bars
|
||||
|
||||
New()
|
||||
..()
|
||||
if (istext(default_material))
|
||||
var/datum/material/M = getCachedMaterial(default_material)
|
||||
src.setMaterial(M)
|
||||
|
||||
block
|
||||
// crystal, rubber
|
||||
name = "block"
|
||||
icon_state = "block"
|
||||
desc = "A nicely cut square brick."
|
||||
|
||||
cloth
|
||||
// fabric
|
||||
icon_state = "fabric"
|
||||
name = "fabric"
|
||||
desc = "A weave of some kind."
|
||||
|
||||
wad
|
||||
// organic
|
||||
icon_state = "wad"
|
||||
name = "clump"
|
||||
desc = "A clump of some kind of material."
|
||||
|
||||
sphere
|
||||
// energy
|
||||
icon_state = "sphere"
|
||||
name = "sphere"
|
||||
desc = "A weird sphere of some kind."
|
||||
|
||||
MouseDrop(over_object, src_location, over_location)
|
||||
if (istype(usr,/mob/dead/))
|
||||
boutput(usr, "<span style=\"color:red\">Quit that! You're dead!</span>")
|
||||
return
|
||||
|
||||
if (get_dist(usr,src) > 1)
|
||||
boutput(usr, "<span style=\"color:red\">You're too far away from it to do that.</span>")
|
||||
return
|
||||
|
||||
if (get_dist(usr,over_object) > 1)
|
||||
boutput(usr, "<span style=\"color:red\">You're too far away from it to do that.</span>")
|
||||
return
|
||||
|
||||
if (isturf(over_object))
|
||||
var/turf/T = over_object
|
||||
usr.visible_message("<span style=\"color:blue\">[usr.name] begins sorting [src] into a pile!</span>")
|
||||
var/staystill = usr.loc
|
||||
for(var/obj/item/I in view(1,usr))
|
||||
if (!I)
|
||||
continue
|
||||
if (src.name != I.name)
|
||||
continue
|
||||
if (I.loc == usr)
|
||||
continue
|
||||
I.set_loc(T)
|
||||
sleep(0.5)
|
||||
if (usr.loc != staystill) break
|
||||
boutput(usr, "<span style=\"color:blue\">You finish sorting [src]!</span>")
|
||||
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/iridiumalloy
|
||||
icon_state = "iridium"
|
||||
name = "iridium-alloy plate"
|
||||
desc = "A chunk of some sort of iridium-alloy plating."
|
||||
New()
|
||||
src.material = getCachedMaterial("iridiumalloy")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/spacelag
|
||||
icon_state = "spacelag"
|
||||
name = "spacelag bar"
|
||||
desc = "Yep. There it is. You've done it. I hope you're happy now."
|
||||
New()
|
||||
src.material = getCachedMaterial("spacelag")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/slag
|
||||
icon_state = "slag"
|
||||
name = "slag"
|
||||
desc = "By-product of smelting"
|
||||
New()
|
||||
src.material = getCachedMaterial("slag")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/cloth/spidersilk
|
||||
name = "space spider silk"
|
||||
desc = "space silk produced by space dwelling space spiders. space."
|
||||
icon_state = "spidersilk"
|
||||
New()
|
||||
src.material = getCachedMaterial("spidersilk")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/cloth/leather
|
||||
name = "leather"
|
||||
desc = "leather made from the skin of some sort of space critter."
|
||||
icon_state = "leather"
|
||||
New()
|
||||
src.material = getCachedMaterial("leather")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/cloth/synthleather
|
||||
name = "synthleather"
|
||||
desc = "A type of artificial leather."
|
||||
icon_state = "synthleather"
|
||||
New()
|
||||
src.material = getCachedMaterial("synthleather")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/cloth/cottonfabric
|
||||
name = "cotton fabric"
|
||||
desc = "A type of natural fabric."
|
||||
icon_state = "fabric"
|
||||
New()
|
||||
src.material = getCachedMaterial("cotton")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/cloth/wendigohide
|
||||
name = "wendigo hide"
|
||||
desc = "The hide of a wendigo."
|
||||
icon_state = "wendigohide"
|
||||
New()
|
||||
src.material = getCachedMaterial("wendigohide")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/cloth/kingwendigohide
|
||||
name = "king wendigo hide"
|
||||
desc = "The hide of a king wendigo."
|
||||
icon_state = "wendigohide"
|
||||
New()
|
||||
src.material = getCachedMaterial("kingwendigohide")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/cloth/carbon
|
||||
name = "carbon nano fibre fabric"
|
||||
desc = "carbon based hi-tech material."
|
||||
icon_state = "carbonfibre"
|
||||
New()
|
||||
src.material = getCachedMaterial("carbonfibre")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/cloth/dyneema
|
||||
name = "dyneema fabric"
|
||||
desc = "carbon nanofibres and space spider silk!"
|
||||
icon_state = "dyneema"
|
||||
New()
|
||||
src.material = getCachedMaterial("dyneema")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/soulsteel
|
||||
name = "soulsteel bar"
|
||||
desc = "A bar of soulsteel. Metal made from souls."
|
||||
icon_state = "soulsteel"
|
||||
New()
|
||||
src.material = getCachedMaterial("soulsteel")
|
||||
..()
|
||||
|
||||
/obj/item/material_piece/bone
|
||||
name = "bits of bone"
|
||||
desc = "some bits and pieces of bones."
|
||||
icon_state = "scrap3"
|
||||
New()
|
||||
src.material = getCachedMaterial("bone")
|
||||
..()
|
||||
@@ -0,0 +1,43 @@
|
||||
/datum/material_recipe
|
||||
var/name = ""
|
||||
var/result_id = "" //Id of the result material. used as fallback or when you do not want to use a result item.
|
||||
var/result_item = null //Path of the resulting material item.
|
||||
|
||||
//This checks if the recipe applies to the given result material.
|
||||
//This is a proc so you can do practically anything for recipes.
|
||||
//Want a recipe that only applies to wool + erebite composites and only if they have a high temperature resistance? You can.
|
||||
//Try to keep these cheap if you can.
|
||||
proc/validate(var/datum/material/M)
|
||||
return null
|
||||
|
||||
//If no result id or result items are defined, this proc will be executed on the material. Do this if you want a recipe to just modifiy a material.
|
||||
proc/apply_to(var/datum/material/M)
|
||||
return M
|
||||
|
||||
/datum/material_recipe/spacelag
|
||||
name = "spacelag"
|
||||
result_id = "spacelag"
|
||||
result_item = /obj/item/material_piece/spacelag
|
||||
|
||||
validate(var/datum/material/M)
|
||||
if(M.name == "spacelag") return 1
|
||||
else return 0
|
||||
|
||||
/datum/material_recipe/dyneema
|
||||
name = "dyneema"
|
||||
result_id = "dyneema"
|
||||
result_item = /obj/item/material_piece/cloth/dyneema
|
||||
|
||||
validate(var/datum/material/M)
|
||||
var/hasCarbon = 0
|
||||
var/hasSilk = 0
|
||||
|
||||
for(var/datum/material/CM in M.parent_materials)
|
||||
if(CM.mat_id == "carbonfibre") hasCarbon = 1
|
||||
if(CM.mat_id == "spidersilk") hasSilk = 1
|
||||
|
||||
if(M.mat_id == "carbonfibre") hasCarbon = 1
|
||||
if(M.mat_id == "spidersilk") hasSilk = 1
|
||||
|
||||
if(hasCarbon && hasSilk) return 1
|
||||
else return 0
|
||||
@@ -0,0 +1,286 @@
|
||||
var/datum/materialResearchHolder/materialsResearch
|
||||
|
||||
/datum/materialResearchHolder
|
||||
var/list/research = list()
|
||||
var/list/completed = list()
|
||||
var/running = 0 //Amount of currently running research projects.
|
||||
var/max_running = 1//Max amount of running research allowed.
|
||||
|
||||
proc/isComplete(var/researchId)
|
||||
return completed.Find(researchId)
|
||||
|
||||
proc/setup()
|
||||
var/types = (typesof(/datum/materialResearch) - /datum/materialResearch) - /datum/materialResearch/scanner
|
||||
for(var/x in types)
|
||||
var/datum/materialResearch/R = new x(src)
|
||||
research.Add(R.id)
|
||||
research[R.id] = R
|
||||
return
|
||||
|
||||
/obj/machinery/matscanner
|
||||
name = "Scanner"
|
||||
desc = "A piece of machinery used to scan various materials and objects for research purposes."
|
||||
icon = 'icons/obj/crafting.dmi'
|
||||
icon_state = "matscanner0"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/active = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(active)
|
||||
boutput(usr, "<span style=\"color:red\">The scanner is busy.</span>")
|
||||
return
|
||||
|
||||
active = 1
|
||||
flick("matscanner1", src)
|
||||
playsound(src.loc, "sound/machines/ArtifactPre1.ogg", 50, 0)
|
||||
|
||||
for(var/x in materialsResearch.research)
|
||||
var/datum/materialResearch/R = materialsResearch.research[x]
|
||||
R.onScan(W)
|
||||
if(istype(R, /datum/materialResearch/scanner))
|
||||
var/datum/materialResearch/scanner/R2 = R
|
||||
for(var/datum/materialResearchScan/S in R2.requiredScans)
|
||||
if(S.completed) continue
|
||||
S.checkCompletion(W)
|
||||
|
||||
spawn(10) active = 0
|
||||
|
||||
ex_act(severity)
|
||||
return
|
||||
|
||||
/datum/materialResearchScan
|
||||
var/name = ""
|
||||
var/desc = "" //Quick description of whats needed for this scan.
|
||||
var/completed = 0
|
||||
|
||||
proc/checkCompletion(var/atom/scanned) //This proc checks if a scanned object fits this scan. Simply do you check and set completed to 1 if the scan fits this profile.
|
||||
completed = 0
|
||||
return
|
||||
|
||||
/datum/materialResearch
|
||||
var/name = ""
|
||||
var/desc = "" //Shown when not researched.
|
||||
var/r_desc = ""//Shown when researched. If not set, normal desc will be shown.
|
||||
var/id = "" //Unique id
|
||||
var/researchCost = 0
|
||||
var/researchTime = 0 //in 1/10 of a second in BYOND TIME
|
||||
var/hidden = 0 //1 = research is hidden and can not be researched.
|
||||
|
||||
var/startTime = 0
|
||||
var/completed = 0
|
||||
var/prcComplete = 0
|
||||
var/statusString = "error"
|
||||
|
||||
proc/canShow() //Use this to check for certain conditions like only showing this research when another one has been completed.
|
||||
if(hidden) return 0
|
||||
return 1
|
||||
|
||||
proc/beginResearch()
|
||||
if(canStart()) return canStart()
|
||||
if(materialsResearch.running >= materialsResearch.max_running) return "Maximum amount of concurrently running research reached."
|
||||
if(!canShow()) return "Internal error: Attempting to start hidden research. Report this please."
|
||||
if(researchCost) wagesystem.research_budget -= researchCost
|
||||
startTime = world.time
|
||||
materialsResearch.running++
|
||||
return 0 //Again, 0 means everything is good.
|
||||
|
||||
proc/canStart()
|
||||
if(researchCost && wagesystem.research_budget < researchCost)
|
||||
return "Not enough research budget."
|
||||
|
||||
if(completed) return "Research already completed."
|
||||
return 0 //0 means "yes, we can start this". This is so we can return a string when we CAN'T.
|
||||
|
||||
proc/onComplete()
|
||||
return
|
||||
|
||||
proc/onScan(var/atom/scanned) //Called when something is scanned. In case you want to make hidden research that shows up after scanning something.
|
||||
return
|
||||
|
||||
proc/process()
|
||||
if(!startTime) statusString = "Not researched"
|
||||
if(completed || !startTime) return
|
||||
|
||||
var/finishTime = (startTime + researchTime)
|
||||
var/remaining = finishTime - world.time
|
||||
|
||||
if(remaining <= 0)
|
||||
completed = 1
|
||||
statusString = "Complete"
|
||||
prcComplete = 100
|
||||
materialsResearch.running--
|
||||
onComplete()
|
||||
else
|
||||
var/done = world.time - startTime
|
||||
prcComplete = round((done / researchTime) * 100)
|
||||
statusString = "[prcComplete]% ([round(remaining / 10)]s)"
|
||||
return
|
||||
|
||||
/datum/materialResearchScan/wendigoHide
|
||||
name = "Wendigo Hide"
|
||||
desc = "We need to scan the fur of a wendigo."
|
||||
|
||||
checkCompletion(var/atom/scanned)
|
||||
if(completed) return
|
||||
if(scanned.material && scanned.material.mat_id == "wendigohide")
|
||||
completed = 1
|
||||
return
|
||||
|
||||
/datum/materialResearchScan/wendigoKingHide
|
||||
name = "Wendigo King Hide"
|
||||
desc = "We need to scan the fur of a wendigo King."
|
||||
|
||||
checkCompletion(var/atom/scanned)
|
||||
if(completed) return
|
||||
if(scanned.material && scanned.material.mat_id == "kingwendigohide")
|
||||
completed = 1
|
||||
return
|
||||
|
||||
/datum/materialResearchScan/iridiumAlloy
|
||||
name = "Iridium alloy"
|
||||
desc = "We need to scan the iridium alloy rumored to be used in certain high-end battle drones."
|
||||
|
||||
checkCompletion(var/atom/scanned)
|
||||
if(completed) return
|
||||
if(scanned.material && scanned.material.mat_id == "iridiumalloy")
|
||||
completed = 1
|
||||
return
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/materialResearch/supernatural1
|
||||
name = "Supernatural materials"
|
||||
desc = "Our scans of supernatural materials have shown strange properties that could be useful. We could focus on researching this."
|
||||
r_desc = "<span style=\"color:#078C00;\">Our first round of research has shown that cobryl appears to be an excellent conductor for spiritual energy, we should try infusing it with ectoplasm.</span>"
|
||||
id = "supernatural1"
|
||||
researchTime = 1200
|
||||
researchCost = 1000
|
||||
hidden = 1
|
||||
|
||||
onScan(var/atom/scanned)
|
||||
if(scanned.reagents)
|
||||
if(scanned.reagents.has_reagent("ectoplasm")) hidden = 0
|
||||
else if(istype(scanned, /obj/item/reagent_containers/food/snacks/ectoplasm)) hidden = 0
|
||||
return
|
||||
|
||||
/datum/materialResearch/supernatural2
|
||||
name = "Supernatural enhancement"
|
||||
desc = "We believe that it could be possible to imbue materials with certain properties exhibited by apparitions and spirits but more research is needed."
|
||||
r_desc = "<span style=\"color:#078C00;\">Through our research we have discovered a process to make materials ethereal, allowing matter to pass through them.</span>"
|
||||
id = "supernatural2"
|
||||
researchTime = 3000
|
||||
researchCost = 6000
|
||||
|
||||
canShow()
|
||||
if(!..()) return 0
|
||||
if(materialsResearch.completed.Find("supernatural1")) return 1
|
||||
return 0
|
||||
|
||||
/datum/materialResearch/efficientresearch
|
||||
name = "Efficient research methods"
|
||||
desc = "Researching this would allow us to more efficiently research future projects, leading to a reduction in cost."
|
||||
r_desc = "<span style=\"color:#078C00;\">Our improved research methods have resulted in a 1000c research cost reduction.</span>"
|
||||
id = "effresearch"
|
||||
researchTime = 1200
|
||||
researchCost = 1000
|
||||
|
||||
onComplete()
|
||||
for(var/x in materialsResearch.research)
|
||||
var/datum/materialResearch/R = materialsResearch.research[x]
|
||||
R.researchCost = max(R.researchCost - 1000, 0)
|
||||
return
|
||||
|
||||
/datum/materialResearch/fastresearch
|
||||
name = "Fast research"
|
||||
desc = "Streamlining of our research methods will allow us to complete future research faster."
|
||||
r_desc = "<span style=\"color:#078C00;\">Our improved research methods have resulted in a 15% reduction in research time.</span>"
|
||||
id = "fstresearch"
|
||||
researchTime = 1800
|
||||
researchCost = 3000
|
||||
|
||||
canShow()
|
||||
if(!..()) return 0
|
||||
if(materialsResearch.completed.Find("effresearch")) return 1
|
||||
return 0
|
||||
|
||||
onComplete()
|
||||
for(var/x in materialsResearch.research)
|
||||
var/datum/materialResearch/R = materialsResearch.research[x]
|
||||
R.researchTime = round(R.researchTime - (R.researchTime * 0.15))
|
||||
return
|
||||
/*
|
||||
/datum/materialResearch/reconditioning1
|
||||
name = "Material reconditioning"
|
||||
desc = "It may be possible to customize materials beyond their normal limits - this will require some research, however."
|
||||
r_desc = "<span style=\"color:#078C00;\">We have discovered a process that allows us to recondition materials. However, this greatly strains and damages the materials.</span>"
|
||||
id = "recondition1"
|
||||
researchTime = 1200
|
||||
researchCost = 4000
|
||||
|
||||
canShow()
|
||||
if(!..()) return 0
|
||||
if(materialsResearch.completed.Find("fstresearch")) return 1
|
||||
return 0
|
||||
|
||||
/datum/materialResearch/scanner/reconditioning2
|
||||
name = "Advanced material reconditioning"
|
||||
desc = "Analysis of certain iridium alloys might help us find new ways to re-condition materials far beyond their normal limits."
|
||||
r_desc = "<span style=\"color:#078C00;\">We were able to develop a new method of material re-conditioning that no longer damages the materials used.</span>"
|
||||
id = "recondition2"
|
||||
researchTime = 1200
|
||||
researchCost = 2000
|
||||
|
||||
New()
|
||||
requiredScans.Add(new/datum/materialResearchScan/iridiumAlloy(src))
|
||||
|
||||
canShow()
|
||||
if(!..()) return 0
|
||||
if(materialsResearch.completed.Find("recondition1")) return 1
|
||||
return 0
|
||||
*/
|
||||
|
||||
/datum/materialResearch/scanner/wendigo
|
||||
name = "Wendigo research"
|
||||
desc = "We need to closely analyze a sample of wendigo fur so that we can replicate their remarkable resistance to cold climates."
|
||||
r_desc = "<span style=\"color:#078C00;\">Our research into wendigo fur has resulted in a process that increases thermal insulation of materials.</span>"
|
||||
id = "wendigo"
|
||||
researchTime = 800
|
||||
researchCost = 1500
|
||||
|
||||
New()
|
||||
requiredScans.Add(new/datum/materialResearchScan/wendigoHide(src))
|
||||
|
||||
/datum/materialResearch/scanner/wendigoking
|
||||
name = "Wendigo King research"
|
||||
desc = "We should closely analyze the fur of a wendigo King to discover what exactly makes it different from a normal wendigo."
|
||||
r_desc = "<span style=\"color:#078C00;\">Our research shows that in addition to the remarkable resistance to cold, the wendigo King can also keep it's body's temperature constant. We should be able to replicate this.</span>"
|
||||
id = "wendigoking"
|
||||
researchTime = 1000
|
||||
researchCost = 5500
|
||||
|
||||
canShow()
|
||||
if(!..()) return 0
|
||||
if(materialsResearch.completed.Find("wendigo")) return 1
|
||||
return 0
|
||||
|
||||
New()
|
||||
requiredScans.Add(new/datum/materialResearchScan/wendigoKingHide(src))
|
||||
|
||||
/datum/materialResearch/scanner //This subtype of research required certain scanned things to allow research.
|
||||
var/list/requiredScans = list()
|
||||
|
||||
canStart()
|
||||
if(!..())
|
||||
var/completeCount = 0
|
||||
for(var/datum/materialResearchScan/x in requiredScans)
|
||||
if(x.completed == 1) completeCount++
|
||||
|
||||
if(completeCount < requiredScans.len)
|
||||
return "Can not start research - [requiredScans.len - completeCount] Scan(s) missing."
|
||||
else
|
||||
return 0
|
||||
else return ..()
|
||||
@@ -0,0 +1,13 @@
|
||||
var/list/matrixPool = list()
|
||||
var/matrixPoolHitCount = 0
|
||||
var/matrixPoolMissCount = 0
|
||||
|
||||
/matrix
|
||||
proc/Reset()
|
||||
src.a = 1
|
||||
src.b = 0
|
||||
src.c = 0
|
||||
src.d = 0
|
||||
src.e = 1
|
||||
src.f = 0
|
||||
src.disposed = 0
|
||||
@@ -0,0 +1,435 @@
|
||||
|
||||
var/list/hex_digit_mask = list("0"=1,"1"=2,"2"=4,"3"=8,"4"=16,"5"=32,"6"=64,"7"=128,"8"=256,"9"=512,"A"=1024,"B"=2048,"C"=4096,"D"=8192,"E"=16384,"F"=32768)
|
||||
var/list/hex_digit_values = list("0" = 0, "1" = 1, "2" = 2, "3" = 3, "4" = 4, "5" = 5, "6" = 6, "7" = 7, "8" = 8, "9" = 9, "A" = 10, "B" = 11, "C" = 12, "D" = 13, "E" = 14, "F" = 15)
|
||||
|
||||
/*
|
||||
* Toy implementation of MC14500b industrial control unit, a 1970s 1-bit CMOS processor used to replace ladder logic. It's a little baby PLC.
|
||||
*
|
||||
* Instructions: Word size in this setup is one byte, one nibble is the instruction and the other is the operand. In that order. A0 is opcode A operand 0.
|
||||
* 0 and F are NOPs
|
||||
* 1 (LD) loads an input value into the accumulator, RR
|
||||
* 2 (LDC) acts like 1, but with the complement of the input
|
||||
* 3 (AND) sets RR to the logical AND of RR and the input.
|
||||
* 4 (ANDC) sets RR to the logical AND of RR and the complement of the input
|
||||
* 5 (OR) sets RR to the logical OR of RR and the input
|
||||
* 6 (ORC) sets RR to the logical OR of RR and the complement of the input
|
||||
* 7 (XNOR) essentially equates RR and the input, with RR set to the result of the test.
|
||||
* 8 (STO) store RR in either a RAM addess (High 8 bits) or one of 8 outputs (Low 8 bits).
|
||||
* 9 (STOC) store complement of RR in the same was as STO.
|
||||
* A (IEN) sets IEN to the input
|
||||
* B (OEN) sets OEN to the input
|
||||
* C (JMP) will adjust the program counter by up to 32 addresses, forward or backward from the current instruction. Arguments 8+ will subtract 7 and then jump 4x that value forward, less than that will jump back 4x (that value + 1)
|
||||
* D (RTN) skip next instruction. For some reason.
|
||||
* E (SKZ) skip next instruction if RR is zero.
|
||||
*/
|
||||
|
||||
#define INSTRUCTIONS_PER_PROCESS 32
|
||||
#define MAX_ROM_SIZE 128
|
||||
|
||||
/obj/item/mechanics/mc14500
|
||||
name = "Control Unit"
|
||||
icon = 'icons/obj/networked.dmi'
|
||||
icon_state = "genericsmall0"
|
||||
var/ROM = ""
|
||||
var/ioPins = 1 //Bitfield. Low byte is IO, high byte is internal memory flags, lowest bit is read as complement of RR
|
||||
var/RR = 0 //Result register. It's the accumulator. Look, motorola picked these names.
|
||||
var/IEN = 0 //Input ENable flag
|
||||
var/OEN = 0 //Output ENable flag
|
||||
var/running = 0
|
||||
var/program_counter = 0
|
||||
var/tmp/datum/mechanicsMessage/lastSignal = null
|
||||
|
||||
//var/tmp/list/sourceCode = list()
|
||||
|
||||
var/dbgmode = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
mechanics.addInput("input 1", "fire1")
|
||||
mechanics.addInput("input 2", "fire2")
|
||||
mechanics.addInput("input 3", "fire3")
|
||||
mechanics.addInput("input 4", "fire4")
|
||||
mechanics.addInput("input 5", "fire5")
|
||||
mechanics.addInput("input 6", "fire6")
|
||||
mechanics.addInput("input 7", "fire7")
|
||||
//mechanics.addInput("input 8", "fire8")
|
||||
|
||||
|
||||
process()
|
||||
if (..() || !running || !level)
|
||||
return
|
||||
|
||||
. = length(ROM)
|
||||
if (. < 2 || . % 2) //Too short or an odd length and we're out of here.
|
||||
running = 0
|
||||
src.icon_state = "genericsmall0"
|
||||
return
|
||||
|
||||
updateUsrDialog()
|
||||
|
||||
spawn (0)
|
||||
for (var/i = INSTRUCTIONS_PER_PROCESS, i > 0, i--)
|
||||
if (!running || !level)
|
||||
break
|
||||
|
||||
program_counter %= .
|
||||
|
||||
switch (interpret_instruction(copytext(ROM, program_counter+1, program_counter+2), copytext(ROM, program_counter+2, program_counter+3)))
|
||||
if (-1)
|
||||
running = 0
|
||||
src.icon_state = "genericsmall0"
|
||||
break
|
||||
|
||||
if (1)
|
||||
i -= 5
|
||||
|
||||
program_counter += 2
|
||||
sleep(1)
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if (!src.level)
|
||||
return ..()
|
||||
|
||||
if (user.machine == src)
|
||||
user << output("[src.running]&[RR ? 1 : 0]&[IEN]&[OEN]", "mcu14500b.browser:update_indicators")
|
||||
user << output("[ioPins]", "mcu14500b.browser:update_mem_lights")
|
||||
return
|
||||
|
||||
. = user_interface(user)
|
||||
if (.)
|
||||
user << browse(., "window=mcu14500b")
|
||||
onclose(user, "mcu14500b")
|
||||
|
||||
proc/user_interface(mob/user as mob)
|
||||
if (!user || user.stat || (iscarbon(user) && get_dist(user, src) > 1))
|
||||
return
|
||||
|
||||
user.machine = src
|
||||
|
||||
. = {"<html><head><title>Industrial Control Unit</title></head><body>
|
||||
<center><table border='1'><tr><td id='active_indicator'><font color=white style='background-color:[running ? "#33FF00" : "#F80000"]'>[running ? " ACTIVE " : "INACTIVE"]</font></td></tr></table><br>
|
||||
<table border='1' style='color:#FFFFFF'><tr'><td id='ind_rr'> <font style='background-color:[RR ? "#33FF00" : "#F80000"]'>RR</font></td><td id='ind_ien'><font style='background-color:[IEN ? "#33FF00" : "#F80000"]'>Input ENable</font></td><td id='ind_oen'><font style='background-color:[OEN ? "#33FF00" : "#F80000"]'>Output ENable</font></td></tr></table>
|
||||
<br><br>
|
||||
<b>INPUT STATUS</b>
|
||||
<table border='1' style='color:#FFFFFF'>
|
||||
<tr>"}
|
||||
|
||||
for (var/bit = 7, bit >= 0, bit--)
|
||||
. += "<td id='bit[bit]'> <div align=left style='background-color=[ioPins & (1<<bit) ? "#33FF00" : "#F80000"]'>[bit]</div></td>"
|
||||
|
||||
. += "</tr></table><b>RAM STATUS</b><table border='1' style ='color:#FFFFFF'><tr>"
|
||||
|
||||
for (var/bit = 15, bit >= 8, bit--)
|
||||
. += "<td id='bit[bit]'> <div align=left style='background-color=[ioPins & (1<<bit) ? "#33FF00" : "#F80000"]'>[bit-8]</div></td>"
|
||||
|
||||
. += {"</tr></table></center>
|
||||
<script type="text/javascript">
|
||||
|
||||
function update_indicators(active, rr, ien, oen)
|
||||
{
|
||||
if (active == 1)
|
||||
{
|
||||
document.getElementById("active_indicator").innerHTML = "<font style='background-color:#33FF00' color=white> ACTIVE </font>";
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById("active_indicator").innerHTML = "<font style='background-color:#F80000' color=white>INACTIVE</font>";
|
||||
}
|
||||
document.getElementById("ind_rr").innerHTML = "<font style='background-color:" + (rr == 1 ? "#33FF00" : "#F80000") + "'>RR</font>"
|
||||
document.getElementById("ind_ien").innerHTML = "<font style='background-color:" + (ien == 1 ? "#33FF00" : "#F80000") + "'>Input ENable</font>"
|
||||
document.getElementById("ind_oen").innerHTML = "<font style='background-color:" + (oen == 1 ? "#33FF00" : "#F80000") + "'>Output ENable</font>"
|
||||
|
||||
}
|
||||
|
||||
function update_mem_lights(mem)
|
||||
{
|
||||
var ind = 1;
|
||||
for (var i = 0; i < 16; i++)
|
||||
{
|
||||
document.getElementById("bit" + i).innerHTML = "<div align=left style='background-color:#" + ((mem & ind) ? "33FF00" : "F80000") + "'>" + i%8 + "</div>";
|
||||
ind = ind << 1;
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
"}
|
||||
|
||||
|
||||
//WIP
|
||||
|
||||
verb/goofy_rom_debug()
|
||||
set src in view(1)
|
||||
set name = "\[Set ROM\]"
|
||||
set desc = "Configure the ROM by thinking really hard at the floating-gate transistors inside. Really, really hard."
|
||||
if (!istype(usr, /mob/living))
|
||||
return
|
||||
if (usr.stat)
|
||||
return
|
||||
if (!mechanics.allowChange(usr))
|
||||
boutput(usr, "<span style=\"color:red\">[MECHFAILSTRING]</span>")
|
||||
return
|
||||
|
||||
. = adminscrub(strip_html(input(usr, "What should the ROM be set to? This better be hexadecimal and an even number of characters!!", "Terrible debug ROM panel", src.ROM) as text))
|
||||
if (usr.stat || get_dist(usr, src) > 2)
|
||||
return
|
||||
if (!mechanics.allowChange(usr))
|
||||
boutput(usr, "<span style=\"color:red\">[MECHFAILSTRING]</span>")
|
||||
return
|
||||
|
||||
. = uppertext(copytext(ckey(.), 1, 65))
|
||||
if (length(.)%2 || !ishex(.))
|
||||
boutput(usr, "<span style=\"color:red\">Invalid ROM values. Great job, knucklehead!!</span>")
|
||||
|
||||
ROM = .
|
||||
|
||||
verb/goofy_power_debug()
|
||||
set src in view(1)
|
||||
set name = "\[Toggle Active\]"
|
||||
set desc = "Toggle whether this is on or not. Doing stuff."
|
||||
|
||||
if (!istype(usr, /mob/living))
|
||||
return
|
||||
if (usr.stat)
|
||||
return
|
||||
if (!mechanics.allowChange(usr))
|
||||
boutput(usr, "<span style=\"color:red\">[MECHFAILSTRING]</span>")
|
||||
return
|
||||
|
||||
src.running = !src.running && src.level
|
||||
IEN = 0
|
||||
OEN = 0
|
||||
RR = 0
|
||||
src.ioPins = 1 //All zero except the !RR section.
|
||||
src.icon_state = "genericsmall[src.running ? 1 : 0]"
|
||||
|
||||
desc = {"* Instructions: Word size in this setup is one byte, one nibble is the instruction and the other is the operand. In that order. A0 is opcode A operand 0.<br>
|
||||
* 0 and F are NOPs<br>
|
||||
* 1 (LD) loads an input value into the accumulator, RR. Input 0 is !RR.<br>
|
||||
* 2 (LDC) acts like 1, but with the complement of the input<br>
|
||||
* 3 (AND) sets RR to the logical AND of RR and the input.<br>
|
||||
* 4 (ANDC) sets RR to the logical AND of RR and the complement of the input<br>
|
||||
* 5 (OR) sets RR to the logical OR of RR and the input<br>
|
||||
* 6 (ORC) sets RR to the logical OR of RR and the complement of the input<br>
|
||||
* 7 (XNOR) essentially equates RR and the input, with RR set to the result of the test.<br>
|
||||
* 8 (STO) store RR in either a RAM addess (High 8 bits) or one of 8 outputs (Low 8 bits).<br>
|
||||
* 9 (STOC) store complement of RR in the same was as STO.<br>
|
||||
* A (IEN) sets IEN to the input. IEN is Input ENable.<br>
|
||||
* B (OEN) sets OEN to the input. OEN is Output ENable.<br>
|
||||
* C (JMP) will adjust the program counter by up to 32 addresses, forward or backward from the current instruction. Arguments 8+ will subtract 7 and then jump 4x that value forward, less than that will jump back 4x (that value + 1)<br>
|
||||
* D (RTN) skip next instruction. For some reason.<br>
|
||||
* E (SKZ) skip next instruction if RR is zero.<br>
|
||||
Output signals have the value \"PIN:VALUE\" i.e \"2:1\" to output true on pin 2. You can filter this with OR gate triggers, ok.<br>
|
||||
Example program: \"30A0B01181\" Will AND RR with 0 on the first iteration (As IEN is zero) and AND it with !RR on subsequent loops (Both set it to zero), load !RR (1) into IEN and OEN, then load input 1 and send it to output 1. This will repeat without end."}
|
||||
|
||||
|
||||
proc/interpret_instruction(instruction, argument)
|
||||
if (src.dbgmode)
|
||||
boutput(world, "\[[instruction], [argument]] RR=[RR] IEN=[IEN] OEN=[OEN]")
|
||||
|
||||
. = argument
|
||||
argument = hex_digit_mask["[argument]"]
|
||||
if (!argument)
|
||||
return -1
|
||||
|
||||
switch (instruction)
|
||||
if ("0","F")//NOP
|
||||
return 0
|
||||
|
||||
if ("1") //LD, RR = (DATA & IEN)
|
||||
RR = (IEN && (ioPins & argument))
|
||||
ioPins = (ioPins & 65534 & (~argument | 65280)) | !RR
|
||||
|
||||
if ("2") //LDC, RR = !(DATA & IEN)
|
||||
RR = !(IEN && (ioPins & argument))
|
||||
ioPins = (ioPins & 65534 & (~argument | 65280)) | !RR
|
||||
|
||||
if ("3") //AND, RR = RR & (DATA & IEN)
|
||||
RR = RR && (IEN && (ioPins & argument))
|
||||
ioPins = (ioPins & 65534 & (~argument | 65280)) | !RR
|
||||
|
||||
if ("4") //ANDC, RR = RR & !(DATA & IEN)
|
||||
RR = RR && !(IEN && (ioPins & argument))
|
||||
ioPins = (ioPins & 65534 & (~argument | 65280)) | !RR
|
||||
|
||||
if ("5") //OR, RR = RR | (DATA & IEN)
|
||||
RR = RR || (IEN && (ioPins & argument))
|
||||
ioPins = (ioPins & 65534 & (~argument | 65280)) | !RR
|
||||
|
||||
if ("6") //ORC, RR = RR | !(DATA & IEN). Waugh.
|
||||
RR = RR || !(IEN && (ioPins & argument))
|
||||
ioPins = (ioPins & 65534 & (~argument | 65280)) | !RR
|
||||
|
||||
if ("7") //XNOR, RR = RR == (DATA & IEN)
|
||||
RR = (RR && 1) == ((IEN && (ioPins & argument)) && 1) //The &&1 is so we can compare them both as booleans instead of tripping over two bitfields with ones in different places
|
||||
ioPins = (ioPins & 65534 & (~argument | 65280)) | !RR
|
||||
|
||||
if ("8") //STO, DATA = RR
|
||||
|
||||
if (argument > 128)
|
||||
if (OEN)
|
||||
ioPins = RR ? (ioPins | argument) : (ioPins & ~argument)
|
||||
|
||||
return 0
|
||||
|
||||
else if (OEN)
|
||||
if (lastSignal)
|
||||
lastSignal.signal = "[.]:[RR ? 1 : 0]"
|
||||
mechanics.fireOutgoing(lastSignal)
|
||||
lastSignal = null
|
||||
if (src.dbgmode)
|
||||
boutput(world, "OUTe: [.]:[RR ? 1 : 0]")
|
||||
|
||||
else
|
||||
mechanics.fireOutgoing(mechanics.newSignal("[.]:[RR ? 1 : 0]"))
|
||||
if (src.dbgmode)
|
||||
boutput(world, "OUT: [.]:[RR ? 1 : 0]")
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
if ("9") //STOC, DATA = !RR
|
||||
if (argument > 128)
|
||||
if (OEN)
|
||||
ioPins = RR ? (ioPins & ~argument) : (ioPins | argument)
|
||||
|
||||
return 0
|
||||
|
||||
else if (OEN)
|
||||
if (lastSignal)
|
||||
lastSignal.signal = "[.]:[RR ? 0 : 1]"
|
||||
mechanics.fireOutgoing(lastSignal)
|
||||
lastSignal = null
|
||||
if (src.dbgmode)
|
||||
boutput(world, "OUTe: [.]:[RR ? 0 : 1]")
|
||||
|
||||
else
|
||||
mechanics.fireOutgoing(mechanics.newSignal("[.]:[RR ? 0 : 1]"))
|
||||
if (src.dbgmode)
|
||||
boutput(world, "OUT: [.]:[RR ? 0 : 1]")
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
if ("A") //IEN, IEN = DATA
|
||||
IEN = (ioPins & argument)
|
||||
|
||||
if ("B") //OEN, OEN = DATA
|
||||
OEN = (ioPins & argument)
|
||||
|
||||
if ("C") //JMP
|
||||
. = hex_digit_values[.]
|
||||
if (!isnum(.))
|
||||
return -1
|
||||
|
||||
if (. > 7)
|
||||
program_counter += (4 * (. - 7)) - 2
|
||||
|
||||
else
|
||||
program_counter -= (4 * (. + 1)) - 2
|
||||
|
||||
. = length(ROM)
|
||||
if (program_counter < 0)
|
||||
program_counter = . + (program_counter % .)
|
||||
|
||||
return 0
|
||||
|
||||
if ("D") //RTN, skip next instruction
|
||||
program_counter += 2
|
||||
|
||||
if ("E") //SKZ, skip next instruction if !RR
|
||||
if (!RR)
|
||||
program_counter += 2
|
||||
|
||||
else
|
||||
return -1
|
||||
|
||||
return 0
|
||||
|
||||
proc
|
||||
fire1(var/datum/mechanicsMessage/anInput)
|
||||
if(level == 2)
|
||||
return
|
||||
|
||||
if (anInput && anInput.isTrue())
|
||||
ioPins |= 2
|
||||
|
||||
else
|
||||
ioPins &= ~2
|
||||
|
||||
lastSignal = anInput
|
||||
|
||||
fire2(var/datum/mechanicsMessage/anInput)
|
||||
if(level == 2)
|
||||
return
|
||||
|
||||
if (anInput && anInput.isTrue())
|
||||
ioPins |= 4
|
||||
|
||||
else
|
||||
ioPins &= ~4
|
||||
|
||||
lastSignal = anInput
|
||||
|
||||
fire3(var/datum/mechanicsMessage/anInput)
|
||||
if(level == 2)
|
||||
return
|
||||
|
||||
if (anInput && anInput.isTrue())
|
||||
ioPins |= 8
|
||||
|
||||
else
|
||||
ioPins &= ~8
|
||||
|
||||
lastSignal = anInput
|
||||
|
||||
fire4(var/datum/mechanicsMessage/anInput)
|
||||
if(level == 2)
|
||||
return
|
||||
|
||||
if (anInput && anInput.isTrue())
|
||||
ioPins |= 16
|
||||
|
||||
else
|
||||
ioPins &= ~16
|
||||
|
||||
lastSignal = anInput
|
||||
|
||||
fire5(var/datum/mechanicsMessage/anInput)
|
||||
if(level == 2)
|
||||
return
|
||||
|
||||
if (anInput && anInput.isTrue())
|
||||
ioPins |= 32
|
||||
|
||||
else
|
||||
ioPins &= ~32
|
||||
|
||||
lastSignal = anInput
|
||||
|
||||
fire6(var/datum/mechanicsMessage/anInput)
|
||||
if(level == 2)
|
||||
return
|
||||
|
||||
if (anInput && anInput.isTrue())
|
||||
ioPins |= 64
|
||||
|
||||
else
|
||||
ioPins &= ~64
|
||||
|
||||
lastSignal = anInput
|
||||
|
||||
fire7(var/datum/mechanicsMessage/anInput)
|
||||
if(level == 2)
|
||||
return
|
||||
|
||||
if (anInput && anInput.isTrue())
|
||||
ioPins |= 128
|
||||
|
||||
else
|
||||
ioPins &= ~128
|
||||
|
||||
lastSignal = anInput
|
||||
|
||||
|
||||
#undef INSTRUCTIONS_PER_PROCESS
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,212 @@
|
||||
//This is a big messy copy & paste job of several things and thus has been banished to its own file.
|
||||
//Shouldve probably done it like ibm and have based it on a networked thing instead of duplicating it all here.
|
||||
//im coder
|
||||
|
||||
/obj/item/mechanics/networkcomp
|
||||
name = "Powernet-networking component"
|
||||
desc = ""
|
||||
icon = 'icons/obj/networked.dmi'
|
||||
icon_state = "generic-p"
|
||||
|
||||
var/net_id = null
|
||||
var/host_id = null //Who are we connected to? (If we have a single host)
|
||||
var/old_host_id = null //Were we previously connected to someone? Do we care?
|
||||
var/obj/machinery/power/data_terminal/link = null
|
||||
var/device_tag = "PNET_MECHNET"
|
||||
|
||||
var/last_reset = 0 //Last world.time we were manually reset.
|
||||
var/net_number = 0 //A cute little bitfield (0-3 exposed) to allow multiple networks on one wirenet. Differentiate between intended hosts, if they care
|
||||
|
||||
var/self_only = 1
|
||||
|
||||
var/ready = 1
|
||||
|
||||
New()
|
||||
. = ..()
|
||||
src.net_id = generate_net_id(src)
|
||||
verbs -= /obj/item/mechanics/verb/setvalue
|
||||
mechanics.addInput("send packet", "spacket")
|
||||
|
||||
verb/togglenwcomps()
|
||||
set src in view(1)
|
||||
set name = "\[Toggle Self-only messages\]"
|
||||
set desc = "Sets whether the component only listens to messages adressed to it."
|
||||
|
||||
if (!istype(usr, /mob/living))
|
||||
return
|
||||
if (usr.stat)
|
||||
return
|
||||
if (!mechanics.allowChange(usr))
|
||||
boutput(usr, "<span style=\"color:red\">[MECHFAILSTRING]</span>")
|
||||
return
|
||||
|
||||
self_only = !self_only
|
||||
boutput(usr, "[self_only ? "Now only processing messages adressed at us.":"Now processing all messages recieved."]")
|
||||
return
|
||||
|
||||
proc/spacket(var/datum/mechanicsMessage/input)
|
||||
if(!ready) return
|
||||
ready = 0
|
||||
spawn(20) ready = 1
|
||||
post_raw(input.signal)
|
||||
return
|
||||
|
||||
proc/post_raw(var/rawstring)
|
||||
if(!src.link)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
signal.source = src
|
||||
signal.transmission_method = TRANSMISSION_WIRE
|
||||
|
||||
var/list/inputlist = params2list(rawstring)
|
||||
|
||||
for(var/x in inputlist)
|
||||
signal.data[x] = inputlist[x]
|
||||
|
||||
src.link.post_signal(src, signal)
|
||||
|
||||
proc/post_status(var/target_id, var/key, var/value, var/key2, var/value2, var/key3, var/value3, var/key4, var/value4)
|
||||
if(!src.link || !target_id)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
signal.source = src
|
||||
signal.transmission_method = TRANSMISSION_WIRE
|
||||
signal.data[key] = value
|
||||
if(key2)
|
||||
signal.data[key2] = value2
|
||||
if(key3)
|
||||
signal.data[key3] = value3
|
||||
if(key4)
|
||||
signal.data[key4] = value4
|
||||
|
||||
signal.data["address_1"] = target_id
|
||||
signal.data["sender"] = src.net_id
|
||||
|
||||
src.link.post_signal(src, signal)
|
||||
|
||||
//command=term_message&data=command=trigger&data=yoursignal&adress_1=targetId&sender=senderId
|
||||
|
||||
proc/sendRaw(var/datum/signal/S)
|
||||
var/dataStr = ""//list2params(S.data) Using list2params() will result in weird glitches if the data already contains a set of params, like in terminal comms
|
||||
for (var/i in S.data)
|
||||
dataStr += "[i][isnull(S.data[i]) ? ";" : "=[S.data[i]];"]"
|
||||
var/datum/mechanicsMessage/msg = mechanics.newSignal(dataStr)
|
||||
mechanics.fireOutgoing(msg)
|
||||
animate_flash_color_fill(src,"#00AA00",1, 1)
|
||||
return
|
||||
|
||||
proc/post_file(var/target_id, var/key, var/value, var/file)
|
||||
if(!src.link || !target_id)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
signal.source = src
|
||||
signal.transmission_method = TRANSMISSION_WIRE
|
||||
signal.data[key] = value
|
||||
if(file)
|
||||
var/datum/computer/file/F = file
|
||||
signal.data_file = F.copy_file()
|
||||
|
||||
signal.data["address_1"] = target_id
|
||||
signal.data["command"] = "term_file"
|
||||
signal.data["sender"] = src.net_id
|
||||
|
||||
src.link.post_signal(src, signal)
|
||||
|
||||
disposing()
|
||||
if (src.link)
|
||||
src.link.master = null
|
||||
src.link = null
|
||||
|
||||
..()
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(..(W, user))
|
||||
if(src.level == 1) //wrenched down
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/machinery/power/data_terminal/test_link = locate() in T
|
||||
src.icon_state = "generic0"
|
||||
if(test_link && !test_link.is_valid_master(test_link.master))
|
||||
src.link = test_link
|
||||
src.link.master = src
|
||||
src.icon_state = "generic1"
|
||||
else if (src.level == 2) //loose
|
||||
resetConnection()
|
||||
src.icon_state = "generic-p"
|
||||
if(src.link)
|
||||
src.link.master = null
|
||||
src.link = null
|
||||
return
|
||||
|
||||
proc/resetConnection()
|
||||
if(!host_id)
|
||||
return
|
||||
|
||||
var/rem_host = src.host_id ? src.host_id : src.old_host_id
|
||||
src.host_id = null
|
||||
src.old_host_id = null
|
||||
src.post_status(rem_host, "command","term_disconnect")
|
||||
spawn(5)
|
||||
src.post_status(rem_host, "command","term_connect","device",src.device_tag)
|
||||
return
|
||||
|
||||
receive_signal(datum/signal/signal)
|
||||
if(!src.link)
|
||||
return
|
||||
|
||||
if(!signal || !src.net_id || signal.encryption || (signal.source == src))
|
||||
return
|
||||
|
||||
if(signal.transmission_method != TRANSMISSION_WIRE) //No radio for us thanks
|
||||
return
|
||||
|
||||
var/target = signal.data["sender"]
|
||||
|
||||
if((signal.data["address_1"] != src.net_id))
|
||||
if((signal.data["address_1"] == "ping") && ((signal.data["net"] == null) || ("[signal.data["net"]]" == "[src.net_number]")) && signal.data["sender"])
|
||||
spawn(5)
|
||||
src.post_status(target, "command", "ping_reply", "device", src.device_tag, "netid", src.net_id, "net", "[net_number]")
|
||||
|
||||
if(self_only) return
|
||||
|
||||
sendRaw(signal)
|
||||
|
||||
var/sigcommand = lowertext(signal.data["command"])
|
||||
if(sigcommand && signal.data["sender"])
|
||||
switch(sigcommand)
|
||||
if("term_connect") //Terminal interface stuff.
|
||||
if(target == src.host_id)
|
||||
//WHAT IS THIS, HOW COULD THIS HAPPEN??
|
||||
src.host_id = null
|
||||
src.updateUsrDialog()
|
||||
spawn(3)
|
||||
src.post_status(target, "command","term_disconnect")
|
||||
return
|
||||
|
||||
if(src.host_id)
|
||||
return
|
||||
|
||||
src.host_id = target
|
||||
src.old_host_id = target
|
||||
if(signal.data["data"] != "noreply")
|
||||
src.post_status(target, "command","term_connect","data","noreply","device",src.device_tag)
|
||||
src.updateUsrDialog()
|
||||
spawn(2) //Sign up with the driver (if a mainframe contacted us)
|
||||
src.post_status(target,"command","term_message","data","command=register&data=MECHNET")
|
||||
return
|
||||
|
||||
if("term_ping")
|
||||
if(target != src.host_id)
|
||||
return
|
||||
if(signal.data["data"] == "reply")
|
||||
src.post_status(target, "command","term_ping")
|
||||
return
|
||||
|
||||
if("term_disconnect")
|
||||
if(target == src.host_id)
|
||||
src.host_id = null
|
||||
return
|
||||
|
||||
return
|
||||
@@ -0,0 +1,91 @@
|
||||
/obj/infared_icon//Mostly copy/paste from paper
|
||||
name = "Infared Writing"
|
||||
icon = 'icons/obj/infared_writing.dmi'
|
||||
icon_state = "norm"
|
||||
var/info = "There is nothing here."
|
||||
infra_luminosity = 4
|
||||
anchored = 1
|
||||
invisibility = 1
|
||||
|
||||
/obj/infared_icon/examine()
|
||||
set src in view()
|
||||
if(usr.see_infrared)
|
||||
usr << browse(text("<HTML><HEAD><TITLE>[]</TITLE></HEAD><BODY><TT>[]</TT></BODY></HTML>", src.name, src.info), text("window=[]", src.name))
|
||||
onclose(usr, "[src.name]")
|
||||
return
|
||||
|
||||
/obj/infared_icon/attack_ai(var/mob/living/silicon/user as mob)
|
||||
//I still need a way for the AI to actually make these
|
||||
var/select = input("Select an action!", "Icon", null, null) in list("Add","Clear","Remove","View")
|
||||
switch(select)
|
||||
if("Add")
|
||||
var/t = input(user, "What text do you wish to add?", text("[]", src.name), null) as message
|
||||
t = copytext(html_encode(t), 1, MAX_MESSAGE_LEN)
|
||||
t = dd_replacetext(t, "\n", "<BR>")
|
||||
t = dd_replacetext(t, "\[b\]", "<B>")
|
||||
t = dd_replacetext(t, "\[/b\]", "</B>")
|
||||
t = dd_replacetext(t, "\[i\]", "<I>")
|
||||
t = dd_replacetext(t, "\[/i\]", "</I>")
|
||||
t = dd_replacetext(t, "\[u\]", "<U>")
|
||||
t = dd_replacetext(t, "\[/u\]", "</U>")
|
||||
t = dd_replacetext(t, "\[sign\]", text("<font face=vivaldi>[]</font>", user.real_name))
|
||||
t = text("<font face=calligrapher>[]</font>", t)
|
||||
src.info += t
|
||||
|
||||
if("Clear")
|
||||
src.info = ""
|
||||
|
||||
if("Remove")
|
||||
spawn(5)
|
||||
qdel(src)
|
||||
|
||||
if("Change Icon")
|
||||
var/iconchange = input("Select an action!", "Icon", null, null) in list("Standard","Arrow Up","Arrow Left","Arrow Right","Arrow Down")
|
||||
switch(iconchange)
|
||||
if("Standard")
|
||||
icon_state = "norm"
|
||||
if("Arrow Up")
|
||||
icon_state = "up"
|
||||
if("Arrow Down")
|
||||
icon_state = "down"
|
||||
if("Arrow Left")
|
||||
icon_state = "left"
|
||||
if("Arrow Right")
|
||||
icon_state = "right"
|
||||
|
||||
if("View")
|
||||
if(usr.see_infrared)
|
||||
user << browse(text("<HTML><HEAD><TITLE>[]</TITLE></HEAD><BODY><TT>[]</TT></BODY></HTML>", src.name, src.info), text("window=[]", src.name))
|
||||
onclose(usr, "[src.name]")
|
||||
return
|
||||
|
||||
/obj/infared_icon/attackby(obj/item/P as obj, mob/user as mob)
|
||||
|
||||
if (istype(P, /obj/item/pen/infared))
|
||||
|
||||
var/select = input("Select an action!", "Icon", null, null) in list("Add","Clear","Remove")
|
||||
switch(select)
|
||||
if("Add")
|
||||
var/t = input(user, "What text do you wish to add?", text("[]", src.name), null) as message
|
||||
if ((!in_range(src, usr) && src.loc != user && !( istype(src.loc, /obj/item/clipboard) ) && src.loc.loc != user && user.equipped() != P))
|
||||
return
|
||||
t = copytext(html_encode(t), 1, MAX_MESSAGE_LEN)
|
||||
t = dd_replacetext(t, "\n", "<BR>")
|
||||
t = dd_replacetext(t, "\[b\]", "<B>")
|
||||
t = dd_replacetext(t, "\[/b\]", "</B>")
|
||||
t = dd_replacetext(t, "\[i\]", "<I>")
|
||||
t = dd_replacetext(t, "\[/i\]", "</I>")
|
||||
t = dd_replacetext(t, "\[u\]", "<U>")
|
||||
t = dd_replacetext(t, "\[/u\]", "</U>")
|
||||
t = dd_replacetext(t, "\[sign\]", text("<font face=vivaldi>[]</font>", user.real_name))
|
||||
t = text("<font face=calligrapher>[]</font>", t)
|
||||
src.info += t
|
||||
|
||||
if("Clear")
|
||||
src.info = ""
|
||||
|
||||
if("Remove")
|
||||
spawn(5)
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
/area/projection
|
||||
|
||||
name = "projection"
|
||||
|
||||
icon_state = "proj"
|
||||
requires_power = 0
|
||||
|
||||
var/id = 0
|
||||
var/obj/point_to_projection/pointer = null
|
||||
|
||||
/area/point_to_projection
|
||||
|
||||
name = "pointer"
|
||||
|
||||
icon_state = "pointer"
|
||||
requires_power = 0
|
||||
|
||||
var/id = 0
|
||||
var/obj/projection/proj = null
|
||||
|
||||
var/projection_enabled = 1
|
||||
|
||||
|
||||
New()
|
||||
..()
|
||||
for(var/area/projection/P in world)
|
||||
if(P.id == src.id)
|
||||
src.proj = P
|
||||
P.pointer = src
|
||||
|
||||
src.setup_lists(P)
|
||||
break
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
proc/make_icon_with_turf(var/turf/the_turf as turf)
|
||||
|
||||
var/icon/I = icon('icons/misc/old_or_unused.dmi',"blank")
|
||||
|
||||
var/icon/turficon = build_composite_icon(the_turf)
|
||||
|
||||
I.Blend(turficon,ICON_OVERLAY)
|
||||
|
||||
var/itemnumber = 0
|
||||
for(var/atom/A in the_turf)
|
||||
if(A.invisibility) continue
|
||||
if(ismob(A))
|
||||
var/icon/X = build_composite_icon(A)
|
||||
I.Blend(X,ICON_OVERLAY)
|
||||
qdel(X)
|
||||
|
||||
else
|
||||
if(itemnumber < 5)
|
||||
var/icon/X = build_composite_icon(A)
|
||||
I.Blend(X,ICON_OVERLAY)
|
||||
qdel(X)
|
||||
|
||||
return I
|
||||
|
||||
proc/setup_lists(var/area/projection/A)
|
||||
//Takes: Area of projection
|
||||
//Returns: Nothing.
|
||||
//Notes: Attempts to project the contents of one area to another.
|
||||
// Movement based on lower left corner. Tiles that do not fit
|
||||
// into the new area will not be projected.
|
||||
|
||||
if(!A || !src) return 0
|
||||
|
||||
//This first part here is to do with making sure the areas are the same size
|
||||
|
||||
var/list/turfs_pointer = get_area_turfs(src.type)
|
||||
var/list/turfs_proj = get_area_turfs(A.type)
|
||||
|
||||
var/src_min_x = 0
|
||||
var/src_min_y = 0
|
||||
|
||||
for (var/turf/T in turfs_pointer)
|
||||
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_proj)
|
||||
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
|
||||
|
||||
//Now we make refined lists (i.e. if the areas are not the same size these will be smaller than either
|
||||
//of the lists above)
|
||||
|
||||
var/list/refined_pointer = new/list()
|
||||
for(var/turf/T in turfs_pointer)
|
||||
refined_pointer += T
|
||||
refined_pointer[T] = new/datum/coords
|
||||
var/datum/coords/C = refined_pointer[T]
|
||||
C.x_pos = (T.x - src_min_x)
|
||||
C.y_pos = (T.y - src_min_y)
|
||||
|
||||
var/list/refined_proj = new/list()
|
||||
for(var/turf/T in turfs_proj)
|
||||
refined_proj += T
|
||||
refined_proj[T] = new/datum/coords
|
||||
var/datum/coords/C = refined_proj[T]
|
||||
C.x_pos = (T.x - trg_min_x)
|
||||
C.y_pos = (T.y - trg_min_y)
|
||||
|
||||
project(refined_pointer, refined_proj)
|
||||
|
||||
proc/project(var/list/refined_pointer, var/list/refined_proj)
|
||||
|
||||
while(src.projection_enabled)
|
||||
|
||||
for (var/turf/T in refined_pointer)
|
||||
var/datum/coords/C_pointer = refined_pointer[T]
|
||||
|
||||
for (var/turf/B in refined_proj)
|
||||
var/datum/coords/C_proj = refined_proj[B]
|
||||
|
||||
if(C_pointer.x_pos == C_proj.x_pos && C_pointer.y_pos == C_proj.y_pos)
|
||||
|
||||
B.icon = make_icon_with_turf(T)
|
||||
|
||||
sleep(5)
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
This works
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/projection
|
||||
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
|
||||
name = "projection"
|
||||
|
||||
icon = 'icons/misc/old_or_unused.dmi'
|
||||
icon_state = "blank"
|
||||
|
||||
var/id = 0
|
||||
var/obj/point_to_projection/pointer = null
|
||||
|
||||
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
|
||||
|
||||
proc/make_icon_with_turf(var/turf/the_turf as turf)
|
||||
|
||||
var/icon/I = icon('icons/misc/old_or_unused.dmi',"blank")
|
||||
|
||||
var/icon/turficon = build_composite_icon(the_turf)
|
||||
|
||||
I.Blend(turficon,ICON_OVERLAY)
|
||||
|
||||
var/itemnumber = 0
|
||||
for(var/atom/A in the_turf)
|
||||
if(A.invisibility) continue
|
||||
if(ismob(A))
|
||||
var/icon/X = build_composite_icon(A)
|
||||
I.Blend(X,ICON_OVERLAY)
|
||||
qdel(X)
|
||||
|
||||
else
|
||||
if(itemnumber < 5)
|
||||
var/icon/X = build_composite_icon(A)
|
||||
I.Blend(X,ICON_OVERLAY)
|
||||
qdel(X)
|
||||
|
||||
return I
|
||||
|
||||
|
||||
proc/Life()
|
||||
if(src.pointer)
|
||||
|
||||
var/turf/the_turf = get_turf(src.pointer)
|
||||
|
||||
src.icon = make_icon_with_turf(the_turf)
|
||||
|
||||
spawn(5) src.Life()
|
||||
|
||||
else
|
||||
logTheThing("admin", null, null, "[src]/(%coords([src.x], [src.y], [src.z])%) not defined properly with ID = [src.id] and PTP = [src.pointer]")
|
||||
logTheThing("diary", null, null, "[src]/(%coords([src.x], [src.y], [src.z])%) not defined properly with ID = [src.id] and PTP = [src.pointer]", "admin")
|
||||
|
||||
|
||||
/obj/point_to_projection
|
||||
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
|
||||
name = "pointer"
|
||||
|
||||
icon = 'icons/misc/old_or_unused.dmi'
|
||||
icon_state = "blank"
|
||||
|
||||
var/id = 0
|
||||
var/obj/projection/proj = null
|
||||
|
||||
New()
|
||||
for(var/obj/projection/P in world)
|
||||
if(P.id == src.id)
|
||||
src.proj = P
|
||||
P.pointer = src
|
||||
P.Life()
|
||||
break
|
||||
@@ -0,0 +1,330 @@
|
||||
var/list/recently_dead = new/list()
|
||||
var/datum/vote_manager/vote_manager = new/datum/vote_manager()
|
||||
var/list/vote_log = new/list()
|
||||
var/const/max_votes_per_round = 2
|
||||
var/const/recently_time = 6000 // 10 mins
|
||||
|
||||
/mob/verb/vote_new()
|
||||
set name = "Vote"
|
||||
//if(!config.allow_vote_restart && !config.allow_vote_mode && !src.client.holder)
|
||||
// boutput(src, "<span style=\"color:red\">Player voting disabled.</span>")
|
||||
// return
|
||||
if(!ticker)
|
||||
boutput(src, "<span style=\"color:red\">Can not start votes before the game starts.</span>")
|
||||
return
|
||||
if(!vote_manager) return //shits hitting the fan at ludicrous speeds
|
||||
if(vote_manager.active_vote) vote_manager.show_vote(src.client)
|
||||
else
|
||||
if(src.ckey in vote_log)
|
||||
if(vote_log[src.ckey] < max_votes_per_round)
|
||||
if(vote_manager.show_vote_selection(src.client)) vote_log[src.ckey]++
|
||||
else
|
||||
boutput(src, "<span style=\"color:red\">You may not start any more votes this round. (Maximum reached : [max_votes_per_round])</span>")
|
||||
else
|
||||
if(vote_manager.show_vote_selection(src.client)) vote_log[src.ckey] = 1
|
||||
|
||||
/datum/vote_manager
|
||||
var/datum/vote_new/active_vote = null
|
||||
|
||||
proc/show_vote_selection(var/client/C)
|
||||
if(active_vote) return 0
|
||||
var/choice
|
||||
/*
|
||||
if(NT.Find(C.ckey) || NTC.Find(C.ckey) || C.holder) //Trusted player.
|
||||
choice = input(C,"Please choose the type of vote you would like to start:","Vote",null) in list("Restart", "Gamemode", "Player Ban", "Player Mute", "***CANCEL***")
|
||||
else
|
||||
choice = input(C,"Please choose the type of vote you would like to start:","Vote",null) in list("Restart", "Gamemode", "Player Mute", "***CANCEL***")
|
||||
*/
|
||||
choice = input(C,"Please choose the type of vote you would like to start:","Vote",null) in list("Restart", "Gamemode"/*, "Player Mute"*/, "***CANCEL***")
|
||||
if(!choice) return 0
|
||||
|
||||
switch(choice)
|
||||
if("***CANCEL***")
|
||||
return 0
|
||||
if("Restart")
|
||||
//if(!config.allow_vote_restart && !C.holder)
|
||||
// boutput(C, "<span style=\"color:red\">Restart votes disabled.</span>")
|
||||
// return
|
||||
if(C.ckey in recently_dead && !C.holder)
|
||||
boutput(C, "<span style=\"color:red\">You may not start this type of vote because you recently died.</span>")
|
||||
return
|
||||
if(C.mob.stat && !C.holder)
|
||||
boutput(C, "<span style=\"color:red\">You may not start this type of vote while dying/unconcious.</span>")
|
||||
return
|
||||
if(active_vote) return 0
|
||||
active_vote = new/datum/vote_new/restart()
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Vote restart initiated by [C.ckey]</B></BIG></span>")
|
||||
show_vote(C)
|
||||
return 1
|
||||
if("Gamemode")
|
||||
//if(!config.allow_vote_mode && !C.holder)
|
||||
// boutput(C, "<span style=\"color:red\">Gamemode votes disabled.</span>")
|
||||
// return
|
||||
var/list/modes = new/list()
|
||||
for(var/mode_list in config.votable_modes)
|
||||
var/the_mode = capitalize(mode_list)
|
||||
if(the_mode == "default") continue
|
||||
modes += the_mode
|
||||
modes += "Secret"
|
||||
var/mode = input(C,"Please choose gamemode:","Vote",null) in modes
|
||||
if(!mode) return 0 //Magic?!
|
||||
if(active_vote) return 0
|
||||
active_vote = new/datum/vote_new/mode(mode)
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Vote gamemode ([mode]) initiated by [C.ckey]</B></BIG></span>")
|
||||
show_vote(C)
|
||||
return 1
|
||||
if("Player Ban")
|
||||
if(world.time < 6000)
|
||||
boutput(C, "<span style=\"color:red\">You may not start this type of vote yet.</span>")
|
||||
return
|
||||
var/list/bannable = new/list()
|
||||
for(var/mob/M in mobs)
|
||||
if(!M.client) continue
|
||||
if(istype(M,/mob/new_player)) continue
|
||||
if(M.client.holder) continue
|
||||
bannable += M.name
|
||||
bannable[M.name] = M
|
||||
bannable += "***CANCEL***"
|
||||
var/player = input(C,"Please choose player:","Vote",null) in bannable
|
||||
if(!player || player == "***CANCEL***") return 0
|
||||
var/mob/picked = bannable[player]
|
||||
if(!picked) return 0
|
||||
if(active_vote) return 0
|
||||
active_vote = new/datum/vote_new/ban(picked.client)
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Vote Ban ([player]) initiated by [C.ckey]</B></BIG></span>")
|
||||
show_vote(C)
|
||||
return 1
|
||||
/*if("Player Mute")
|
||||
if(world.time < 6000)
|
||||
boutput(C, "<span style=\"color:red\">You may not start this type of vote yet.</span>")
|
||||
return
|
||||
var/list/muteable = new/list()
|
||||
for(var/mob/M in mobs)
|
||||
if(!M.client) continue
|
||||
if(istype(M,/mob/new_player)) continue
|
||||
if(M.client.holder) continue
|
||||
muteable += M.name
|
||||
muteable[M.name] = M
|
||||
muteable += "***CANCEL***"
|
||||
var/player = input(C,"Please choose player:","Vote",null) in muteable
|
||||
if(!player || player == "***CANCEL***") return 0
|
||||
var/mob/picked = muteable[player]
|
||||
if(!picked) return 0
|
||||
if(active_vote) return 0
|
||||
active_vote = new/datum/vote_new/mute(picked.client)
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Vote Mute ([player]) initiated by [C.ckey]</B></BIG></span>")
|
||||
show_vote(C)
|
||||
return 1*/
|
||||
return 0
|
||||
|
||||
proc/show_vote(var/client/C)
|
||||
if(!active_vote) return
|
||||
active_vote.show_to(C)
|
||||
return
|
||||
|
||||
proc/cancel_vote()
|
||||
if(active_vote)
|
||||
active_vote.kill = 1
|
||||
qdel(active_vote)
|
||||
active_vote = null
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Voting aborted.</B></BIG></span>")
|
||||
|
||||
/datum/vote_new
|
||||
var/list/options = new/list()
|
||||
var/list/open_votes = new/list()
|
||||
var/list/voted_ckey = new/list()
|
||||
var/list/voted_id = new/list()
|
||||
var/list/may_vote = new/list()
|
||||
var/details = ""
|
||||
var/vote_name = ""
|
||||
var/vote_length = 1200 //2 Minutes
|
||||
var/vote_started = 0
|
||||
var/data = null
|
||||
var/vote_flags = 0
|
||||
var/curr_win = ""
|
||||
var/kill = 0 //just making sure ...
|
||||
|
||||
New(var/A)
|
||||
for(var/mob/M in mobs)
|
||||
if(!M.client) continue
|
||||
may_vote += M.ckey
|
||||
vote_started = world.time
|
||||
data = A
|
||||
process()
|
||||
..()
|
||||
|
||||
proc/process()
|
||||
if(kill)
|
||||
return
|
||||
if(world.time - vote_started >= vote_length)
|
||||
end_vote()
|
||||
return
|
||||
curr_win = get_winner()
|
||||
spawn(20) process()
|
||||
|
||||
proc/show_to(var/client/C)
|
||||
if(C in open_votes) return
|
||||
if(!(C.ckey in may_vote))
|
||||
boutput(C, "<span style=\"color:red\"><BIG>You may not vote as you were not present when the vote was started.</BIG></span>")
|
||||
return
|
||||
if(C.ckey in voted_ckey || C.computer_id in voted_id)
|
||||
boutput(C, "<span style=\"color:red\"><BIG>You have already voted. Current winner : [curr_win]</BIG></span>")
|
||||
return
|
||||
open_votes += C
|
||||
var/choice = input(C,details,vote_name,null) in options
|
||||
if(!src) return //I suppose this could happen ...
|
||||
if(!choice)
|
||||
open_votes -= C
|
||||
return
|
||||
if(!options[choice]) options[choice] = 1
|
||||
else options[choice]++
|
||||
open_votes -= C
|
||||
voted_ckey += C.ckey
|
||||
voted_id += C.computer_id
|
||||
|
||||
proc/get_winner()
|
||||
var/winner = null
|
||||
var/winner_num = 0
|
||||
for(var/A in options)
|
||||
if(options[A])
|
||||
if(options[A] > winner_num)
|
||||
winner_num = options[A]
|
||||
winner = A
|
||||
if(!winner) winner = "none"
|
||||
return(winner)
|
||||
|
||||
proc/get_winner_num()
|
||||
var/winner_num = 0
|
||||
for(var/A in options)
|
||||
if(options[A])
|
||||
if(options[A] > winner_num)
|
||||
winner_num = options[A]
|
||||
return(winner_num)
|
||||
|
||||
proc/end_vote()
|
||||
vote_manager.active_vote = null
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/datum/vote_new/mode
|
||||
options = list("Yes","No")
|
||||
details = ""
|
||||
vote_name = "Vote gamemode"
|
||||
vote_length = 1200 //2 Minutes
|
||||
|
||||
New(var/A)
|
||||
for(var/mob/M in mobs)
|
||||
if(!M.client) continue
|
||||
may_vote += M.ckey
|
||||
vote_started = world.time
|
||||
data = A
|
||||
details = "Change gamemode to '[A]' ?"
|
||||
process()
|
||||
|
||||
end_vote()
|
||||
vote_manager.active_vote = null
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Vote gamemode result: [get_winner()]</B></BIG></span>")
|
||||
if(get_winner() == "Yes")
|
||||
if(get_winner_num() < 3)
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Minimum mode votes not reached (3)</B></BIG></span>")
|
||||
qdel(src)
|
||||
return
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Gamemode will be changed to [data] after the next reboot.</B></BIG></span>")
|
||||
world.save_mode(lowertext(data))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/datum/vote_new/restart
|
||||
options = list("Yes","No")
|
||||
details = "Restart the server?"
|
||||
vote_name = "Vote restart"
|
||||
vote_length = 1200 //2 Minutes
|
||||
|
||||
end_vote()
|
||||
vote_manager.active_vote = null
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Vote restart result: [get_winner()]</B></BIG></span>")
|
||||
if(get_winner() == "Yes")
|
||||
if(get_winner_num() < 5)
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Minimum restart votes not reached (5).</B></BIG></span>")
|
||||
qdel(src)
|
||||
return
|
||||
Reboot_server()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/datum/vote_new/ban
|
||||
options = list("Yes","No")
|
||||
details = ""
|
||||
vote_name = "Vote Ban"
|
||||
vote_length = 1200 //2 Minutes
|
||||
var/backup_ckey = ""
|
||||
var/backup_computerid = ""
|
||||
var/backup_ip = " "
|
||||
|
||||
New(var/A)
|
||||
for(var/mob/M in mobs)
|
||||
if(!M.client) continue
|
||||
may_vote += M.ckey
|
||||
vote_started = world.time
|
||||
data = A
|
||||
details = "Ban player '[A:mob:name]' for 1 day?"
|
||||
backup_ckey = A:ckey
|
||||
backup_computerid = A:computer_id
|
||||
backup_ip = A:client.address
|
||||
process()
|
||||
|
||||
end_vote()
|
||||
vote_manager.active_vote = null
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Vote ban result: [get_winner()]</B></BIG></span>")
|
||||
if(get_winner() == "Yes")
|
||||
if(get_winner_num() < 5)
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Minimum ban votes not reached (5) - Player not banned.</B></BIG></span>")
|
||||
qdel(src)
|
||||
return
|
||||
if(data)
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>[data:mob:name] / [data:ckey] has been banned for 3 hours.</B></BIG></span>")
|
||||
AddBan(data:ckey, data:computer_id, data:client.address, "VOTE BAN - 1 day", "VOTEBAN", 1, 180)
|
||||
qdel(data)
|
||||
else //Logged out while vote was in progress. Longer ban!
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>[data:backup_ckey] has been banned for 1 week for logging out while vote was in progress.</B></BIG></span>")
|
||||
AddBan(backup_ckey, backup_computerid, backup_ip, "VOTE BAN - Logged out while vote was in progress - 1 day", "VOTEBAN", 1, 1440)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/datum/vote_new/mute
|
||||
options = list("Yes","No")
|
||||
details = ""
|
||||
vote_name = "Vote Mute"
|
||||
vote_length = 1200 //2 Minutes
|
||||
var/backup_ckey = ""
|
||||
var/backup_computerid = ""
|
||||
var/backup_ip = " "
|
||||
|
||||
New(var/A)
|
||||
for(var/mob/M in mobs)
|
||||
if(!M.client) continue
|
||||
may_vote += M.ckey
|
||||
vote_started = world.time
|
||||
data = A
|
||||
details = "Mute player '[A:mob:name]'?"
|
||||
backup_ckey = A:ckey
|
||||
backup_computerid = A:computer_id
|
||||
backup_ip = A:client.address
|
||||
process()
|
||||
|
||||
end_vote()
|
||||
vote_manager.active_vote = null
|
||||
boutput(world, "<span style=\"color:green\">Vote mute result: [get_winner()]</span>")
|
||||
if(get_winner() == "Yes")
|
||||
if(get_winner_num() < 3)
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>Minimum mute votes not reached (3) - Player not muted.</B></BIG></span>")
|
||||
qdel(src)
|
||||
return
|
||||
if(data)
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>[data:mob:name] has been muted.</B></BIG></span>")
|
||||
//data:mob:muted = 1
|
||||
else //Logged out while vote was in progress.
|
||||
boutput(world, "<span style=\"color:green\"><BIG><B>[data:backup_ckey] has been banned for 15 minutes for logging out while vote was in progress.</B></BIG></span>")
|
||||
AddBan(backup_ckey, backup_computerid, backup_ip, "VOTE MUTE - Logged out while vote was in progress - 15 minutes", "VOTEMUTE", 1, 15)
|
||||
qdel(src)
|
||||
return
|
||||
@@ -0,0 +1,342 @@
|
||||
/var/list/screenOverlayLibrary = list()
|
||||
|
||||
/mob/var/list/screenoverlays = list()
|
||||
//Please note that overlays are saved on a per mob basis.
|
||||
//You need to make sure that they are updated (added to the client screen) in the life proc and on mob login. Or in other ways if not applicable.
|
||||
//You also need to make sure they are removed in those proc and on logout and on ghosting
|
||||
//For convenience i have tagged all related additions in other files with "ov1"
|
||||
|
||||
/mob/proc/addOverlayComposition(var/compType) //Adds composition type to active compositions on mob
|
||||
if(!ispath(compType))return
|
||||
if(!screenOverlayLibrary.Find(compType))return
|
||||
var/instance = screenOverlayLibrary[compType]
|
||||
if(screenoverlays.Find(instance))return //Only one instance per overlay Type. Keep this. Im serious. Else mobs will end up with 324598762 blind overlays
|
||||
screenoverlays.Add(instance)
|
||||
return
|
||||
|
||||
/mob/proc/removeOverlayComposition(var/compType) //Removes composition type from active compositions on mob
|
||||
if(!ispath(compType)) return
|
||||
if(!screenOverlayLibrary.Find(compType)) return
|
||||
var/instance = screenOverlayLibrary[compType]
|
||||
if(screenoverlays.Find(instance))
|
||||
screenoverlays.Remove(instance)
|
||||
return
|
||||
|
||||
/mob/proc/hasOverlayComposition(var/compType) //Does that mob have the overlay active?
|
||||
if(!ispath(compType)) return
|
||||
if(!screenOverlayLibrary.Find(compType)) return
|
||||
var/instance = screenOverlayLibrary[compType]
|
||||
return screenoverlays.Find(instance)
|
||||
|
||||
/mob/proc/updateOverlaysClient(var/client/CL) //Updates the overlays of current mob to given client
|
||||
removeOverlaysClient(CL)
|
||||
addOverlaysClient(CL)
|
||||
return
|
||||
|
||||
/mob/proc/addOverlaysClient(var/client/CL) //Adds the overlays of current mob to given client
|
||||
if(!CL) return
|
||||
for(var/datum/overlayComposition/C in screenoverlays)
|
||||
for(var/obj/screen/screenoverlay/S in C.instances)
|
||||
CL.screen += S
|
||||
|
||||
/mob/proc/removeOverlaysClient(var/client/CL) //Removes all overlays of given client
|
||||
if(!CL) return
|
||||
for(var/obj/screen/screenoverlay/S in CL.screen)
|
||||
CL.screen -= S
|
||||
|
||||
//Because dead mobs don't have a life loop
|
||||
/mob/dead/addOverlayComposition()
|
||||
..()
|
||||
updateOverlaysClient(src.client)
|
||||
|
||||
/mob/dead/removeOverlayComposition()
|
||||
..()
|
||||
updateOverlaysClient(src.client)
|
||||
|
||||
/obj/screen/screenoverlay
|
||||
name = ""
|
||||
icon = 'icons/effects/overlays/cloudy.dmi'
|
||||
layer = HUD_LAYER_UNDER_2
|
||||
screen_loc = "1,1"
|
||||
|
||||
/datum/overlayDefinition
|
||||
var/d_icon = 'icons/effects/overlays/cloudy.dmi'
|
||||
var/d_icon_state = "cloudy"
|
||||
var/d_alpha = 255
|
||||
var/customization_third_color = "#ffffff"
|
||||
var/d_blend_mode = 1
|
||||
var/d_layer = HUD_LAYER_UNDER_2 //18 is just below the ui but above everything else.
|
||||
var/d_mouse_opacity = 0 //In case you want it to block clicks. For blindness and such.
|
||||
|
||||
//list of overlay composition stored on mob
|
||||
//list is applied in life proc?! and login
|
||||
|
||||
/datum/overlayComposition
|
||||
var/list/definitions = list()
|
||||
var/list/instances = list()
|
||||
|
||||
New()
|
||||
for(var/datum/overlayDefinition/D in definitions)
|
||||
var/obj/screen/screenoverlay/S = new()
|
||||
S.icon = D.d_icon
|
||||
S.icon_state = D.d_icon_state
|
||||
S.alpha = D.d_alpha
|
||||
S.color = D.customization_third_color
|
||||
S.blend_mode = D.d_blend_mode
|
||||
S.layer = D.d_layer
|
||||
S.mouse_opacity = D.d_mouse_opacity
|
||||
instances.Add(S)
|
||||
return ..()
|
||||
|
||||
proc/removeFromMob(var/mob/M)
|
||||
return
|
||||
|
||||
proc/addToMob(var/mob/M) //Do not allow more than once instance of any given type. There is a reason for this,
|
||||
return
|
||||
|
||||
// Debug stuff
|
||||
|
||||
/proc/removerlays()
|
||||
for(var/obj/screen/screenoverlay/F in world)
|
||||
del(F)
|
||||
|
||||
return
|
||||
|
||||
/proc/overlaytest()
|
||||
var/numover = input(usr, "How many overlays?") as null|num
|
||||
if (!numover)
|
||||
return
|
||||
var/list/overlist = list()
|
||||
for(var/i=0, i<numover, i++)
|
||||
var/obj/screen/screenoverlay/O = createover(i)
|
||||
if(O) overlist.Add(O)
|
||||
|
||||
boutput(usr, "<b><font color=\"gold\"> [overlist.len] overlays defined.</font></b>")
|
||||
|
||||
if(overlist.len)
|
||||
for(var/obj/screen/screenoverlay/F in overlist)
|
||||
F.add_to_client(usr.client)
|
||||
|
||||
switch(alert("Would you like to add these overlays to everyone?",,"Yes","No"))
|
||||
if("Yes")
|
||||
for(var/client/C)
|
||||
if(C == usr.client) continue
|
||||
for(var/obj/screen/screenoverlay/F in overlist)
|
||||
F.add_to_client(C)
|
||||
if("No")
|
||||
for(var/obj/screen/screenoverlay/F in overlist)
|
||||
usr.client.screen -= F
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
/proc/createover(var/i)
|
||||
/*
|
||||
var/obj/screen/screenoverlay/F = new()
|
||||
|
||||
var/state = input(usr, "Icon state?","Overlay #[i]", "wiggle") in icon_states(icon('icons/effects/480x480.dmi'))
|
||||
var/blendm = input(usr, "Blend mode?","Overlay #[i] (1=normal,2=add,3=sub,4=mult)", 1) in list(1, 2, 3, 4)
|
||||
var/ialpha = input(usr, "Alpha?","Overlay #[i] (1-255 opaque)", 255) as num
|
||||
var/icolor = input(usr, "Color?","Overlay #[i] (hex)", "#ffffff")
|
||||
var/ilayer = input(usr, "Layer?","Overlay #[i]", HUD_LAYER_UNDER_2) as num
|
||||
|
||||
if(length(state) && blendm && ialpha && length(icolor))
|
||||
F.icon_state = state
|
||||
F.blend_mode = blendm
|
||||
F.alpha = max(0, min(255, ialpha))
|
||||
F.color = icolor
|
||||
F.layer = ilayer
|
||||
|
||||
return F
|
||||
*/
|
||||
return null
|
||||
|
||||
// END Debug stuff
|
||||
|
||||
// Compositions below ...
|
||||
|
||||
/datum/overlayComposition/blinded
|
||||
New()
|
||||
var/datum/overlayDefinition/spot = new()
|
||||
spot.d_icon = 'icons/effects/overlays/knockout2.dmi'
|
||||
spot.d_icon_state = "knockout2"
|
||||
spot.d_blend_mode = 3 //sub
|
||||
spot.d_mouse_opacity = 1 //its gonna be use for blindness. Dont let them click stuff.
|
||||
definitions.Add(spot)
|
||||
|
||||
var/datum/overlayDefinition/fluff = new()
|
||||
fluff.d_icon = 'icons/effects/overlays/meatysmall.dmi'
|
||||
fluff.d_icon_state = "meatysmall"
|
||||
fluff.d_blend_mode = 3 //sub
|
||||
fluff.customization_third_color = "#eeeeee"
|
||||
definitions.Add(fluff)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/overlayComposition/flashed
|
||||
New()
|
||||
var/datum/overlayDefinition/beam = new()
|
||||
beam.d_icon = 'icons/effects/overlays/beamout.dmi'
|
||||
beam.d_icon_state = "beamout"
|
||||
beam.d_blend_mode = 2 //add
|
||||
beam.customization_third_color = "#eeeeee"
|
||||
definitions.Add(beam)
|
||||
|
||||
var/datum/overlayDefinition/spot = new()
|
||||
spot.d_icon = 'icons/effects/overlays/meatysmall.dmi'
|
||||
spot.d_icon_state = "meatysmall"
|
||||
spot.d_blend_mode = 2 //add
|
||||
spot.customization_third_color = "#eeeeee"
|
||||
definitions.Add(spot)
|
||||
return ..()
|
||||
|
||||
/datum/overlayComposition/smoke
|
||||
New()
|
||||
var/datum/overlayDefinition/spot = new()
|
||||
spot.d_icon = 'icons/effects/overlays/knockout.dmi'
|
||||
spot.d_icon_state = "knockout"
|
||||
spot.d_blend_mode = 3 //sub
|
||||
spot.customization_third_color = "#eeeeee"
|
||||
definitions.Add(spot)
|
||||
|
||||
var/datum/overlayDefinition/one = new()
|
||||
one.d_icon = 'icons/effects/overlays/cloudy.dmi'
|
||||
one.d_icon_state = "cloudy"
|
||||
one.d_blend_mode = 3 //sub
|
||||
one.customization_third_color = "#aaaaaa"
|
||||
definitions.Add(one)
|
||||
|
||||
var/datum/overlayDefinition/two = new()
|
||||
two.d_icon = 'icons/effects/overlays/cloudy.dmi'
|
||||
two.d_icon_state = "cloudy"
|
||||
two.d_blend_mode = 2 //add
|
||||
two.customization_third_color = "#bbbbbb"
|
||||
definitions.Add(two)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/overlayComposition/heat
|
||||
New()
|
||||
var/datum/overlayDefinition/part1 = new()
|
||||
part1.d_icon = 'icons/effects/overlays/meatysmall.dmi'
|
||||
part1.d_icon_state = "meatysmall"
|
||||
part1.d_blend_mode = 2
|
||||
part1.customization_third_color = "#ff0000"
|
||||
part1.d_alpha = 100
|
||||
definitions.Add(part1)
|
||||
|
||||
var/datum/overlayDefinition/part2 = new()
|
||||
part2.d_icon = 'icons/effects/overlays/cloudy.dmi'
|
||||
part2.d_icon_state = "cloudy"
|
||||
part2.d_blend_mode = 2
|
||||
part2.customization_third_color = "#ffff00"
|
||||
part1.d_alpha = 100
|
||||
definitions.Add(part2)
|
||||
return ..()
|
||||
|
||||
/datum/overlayComposition/anima
|
||||
New()
|
||||
var/datum/overlayDefinition/zero = new()
|
||||
zero.d_icon = 'icons/effects/overlays/beamout.dmi'
|
||||
zero.d_icon_state = "beamout"
|
||||
zero.d_blend_mode = 4
|
||||
zero.customization_third_color = "#5C0E80"
|
||||
zero.d_alpha = 255
|
||||
definitions.Add(zero)
|
||||
return ..()
|
||||
|
||||
/datum/overlayComposition/triplemeth
|
||||
New()
|
||||
var/datum/overlayDefinition/zero = new()
|
||||
zero.d_icon = 'icons/effects/overlays/meatysmall.dmi'
|
||||
zero.d_icon_state = "meatysmall"
|
||||
zero.d_blend_mode = 2
|
||||
zero.customization_third_color = "#ff0000"
|
||||
zero.d_alpha = 75
|
||||
definitions.Add(zero)
|
||||
|
||||
var/datum/overlayDefinition/one = new()
|
||||
one.d_icon = 'icons/effects/overlays/cloudy.dmi'
|
||||
one.d_icon_state = "cloudy"
|
||||
one.d_blend_mode = 2
|
||||
one.customization_third_color = "#00ff00"
|
||||
one.d_alpha = 75
|
||||
definitions.Add(one)
|
||||
|
||||
var/datum/overlayDefinition/two = new()
|
||||
two.d_icon = 'icons/effects/overlays/beamout.dmi'
|
||||
two.d_icon_state = "beamout"
|
||||
two.d_blend_mode = 2
|
||||
two.customization_third_color = "#0000ff"
|
||||
two.d_alpha = 75
|
||||
definitions.Add(two)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/overlayComposition/static_noise
|
||||
var/special_blend = BLEND_DEFAULT
|
||||
New()
|
||||
var/datum/overlayDefinition/zero = new()
|
||||
zero.d_icon = 'icons/effects/overlays/noise.dmi'
|
||||
zero.d_icon_state = "noise"
|
||||
zero.d_blend_mode = BLEND_DEFAULT
|
||||
zero.customization_third_color = "#bbbbbb"
|
||||
zero.d_mouse_opacity = 1
|
||||
definitions.Add(zero)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/overlayComposition/static_noise/sub
|
||||
special_blend = BLEND_SUBTRACT
|
||||
|
||||
/datum/overlayComposition/blinded_r_eye
|
||||
New()
|
||||
var/datum/overlayDefinition/dither = new()
|
||||
dither.d_icon = 'icons/effects/overlays/Rtrans.dmi'
|
||||
dither.d_icon_state = "Rtrans"
|
||||
dither.d_blend_mode = 1
|
||||
//dither.d_mouse_opacity = 1
|
||||
definitions.Add(dither)
|
||||
|
||||
var/datum/overlayDefinition/meaty = new()
|
||||
meaty.d_icon = 'icons/effects/overlays/meatyR.dmi'
|
||||
meaty.d_icon_state = "meatyR"
|
||||
meaty.d_blend_mode = 2
|
||||
meaty.d_alpha = 140
|
||||
meaty.customization_third_color = "#610306"
|
||||
definitions.Add(meaty)
|
||||
return ..()
|
||||
|
||||
/datum/overlayComposition/blinded_l_eye
|
||||
New()
|
||||
var/datum/overlayDefinition/dither = new()
|
||||
dither.d_icon = 'icons/effects/overlays/Ltrans.dmi'
|
||||
dither.d_icon_state = "Ltrans"
|
||||
dither.d_blend_mode = 1
|
||||
//dither.d_mouse_opacity = 1
|
||||
definitions.Add(dither)
|
||||
|
||||
var/datum/overlayDefinition/meaty = new()
|
||||
meaty.d_icon = 'icons/effects/overlays/meatyL.dmi'
|
||||
meaty.d_icon_state = "meatyL"
|
||||
meaty.d_blend_mode = 2
|
||||
meaty.d_alpha = 140
|
||||
meaty.customization_third_color = "#610306"
|
||||
definitions.Add(meaty)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/overlayComposition/shuttle_warp
|
||||
var/warp_dir = "warp"
|
||||
New()
|
||||
var/datum/overlayDefinition/warp = new()
|
||||
warp.d_icon = 'icons/effects/overlays/warp.dmi'
|
||||
warp.d_icon_state = src.warp_dir
|
||||
warp.d_blend_mode = 1
|
||||
warp.d_layer = TURF_LAYER-1
|
||||
definitions.Add(warp)
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/overlayComposition/shuttle_warp/ew
|
||||
warp_dir = "warp_ew"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,588 @@
|
||||
/*var/const/PHASER_EMP = 1
|
||||
var/const/PHASER_FLASH = 2
|
||||
var/const/PHASER_TOXINS = 4
|
||||
var/const/PHASER_BURN = 8
|
||||
var/const/PHASER_SING = 16
|
||||
var/const/PHASER_CONC = 512
|
||||
|
||||
var/const/PHASER_ENERGY = 32
|
||||
var/const/PHASER_RADIUS = 64
|
||||
var/const/PHASER_HOMING = 128
|
||||
var/const/PHASER_SNIPER = 256
|
||||
|
||||
/obj/phaser_projectile
|
||||
name = "Energy"
|
||||
desc = "Looks dangerous."
|
||||
density = 0
|
||||
opacity = 0
|
||||
anchored = 1
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
var/mob/origin = null
|
||||
var/list/impactsounds = new/list()
|
||||
var/power = 0
|
||||
var/damage = 0
|
||||
var/range = 0
|
||||
var/stun = 0
|
||||
var/upgrades = 0
|
||||
var/turf/dest = null
|
||||
flags = TABLEPASS
|
||||
|
||||
/obj/mod_spawner
|
||||
icon = 'icons/misc/mark.dmi'
|
||||
icon_state = "rup"
|
||||
New()
|
||||
var/A = pick(typesof(/obj/item/gun_ext)-/obj/item/gun_ext)
|
||||
new A (src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/gun_ext
|
||||
var/overlay_name = ""
|
||||
var/upgrade = null
|
||||
var/location = null
|
||||
name = "Phaser extension"
|
||||
desc = "For use with phasers"
|
||||
item_state = "table_parts"
|
||||
inhand_image_icon = 'icons/mob/inhand/hand_tools.dmi'
|
||||
icon = 'icons/obj/gun.dmi'
|
||||
var/proj_mod = null
|
||||
var/proj_sound = null
|
||||
var/proj_sound_impact = null
|
||||
mats = 8
|
||||
|
||||
/obj/item/gun_ext/sniper
|
||||
name = "Phaser extension (sniper)"
|
||||
desc = "Massively increases energy usage and damage. Also disables the radius setting."
|
||||
overlay_name = "ext_sniper"
|
||||
upgrade = PHASER_SNIPER
|
||||
location = "ext"
|
||||
icon_state = "add_sniper"
|
||||
proj_sound = 'sound/weapons/snipershot.ogg'
|
||||
|
||||
/obj/item/gun_ext/battery
|
||||
name = "Phaser extension (battery)"
|
||||
desc = "Increases battery maximum but slightly reduces damage."
|
||||
overlay_name = "ext_battery"
|
||||
upgrade = PHASER_ENERGY
|
||||
location = "ext"
|
||||
icon_state = "add_battery"
|
||||
|
||||
/obj/item/gun_ext/homing
|
||||
name = "Phaser extension (homing)"
|
||||
desc = "Decreases battery maximum and increases energy usage but gives shots a slight homing ability."
|
||||
overlay_name = "ext_focus"
|
||||
upgrade = PHASER_HOMING
|
||||
location = "ext"
|
||||
icon_state = "add_homing"
|
||||
|
||||
/obj/item/gun_ext/thermal
|
||||
name = "Phaser energy-converter mod (thermal)"
|
||||
desc = "Decreases energy usage but causes burn damage instead of brute damage."
|
||||
overlay_name = "conv_thermal"
|
||||
upgrade = PHASER_BURN
|
||||
location = "conv"
|
||||
icon_state = "add_thermal"
|
||||
proj_mod = "proj_thermal"
|
||||
|
||||
/obj/item/gun_ext/sing
|
||||
name = "Phaser energy-converter mod (micro-singularity)"
|
||||
desc = "Increases energy usage and decreases damage but pulls nearby targets in."
|
||||
overlay_name = "conv_sing"
|
||||
upgrade = PHASER_SING
|
||||
location = "conv"
|
||||
icon_state = "add_sing"
|
||||
proj_mod = "proj_sing"
|
||||
proj_sound_impact = 'sound/effects/singsuck.ogg'
|
||||
|
||||
/obj/item/gun_ext/toxin
|
||||
name = "Phaser energy-converter mod (toxin)"
|
||||
desc = "Increases energy usage but causes toxin damage instead of brute damage and adds additional damage over time."
|
||||
overlay_name = "conv_tox"
|
||||
upgrade = PHASER_TOXINS
|
||||
location = "conv"
|
||||
icon_state = "add_tox"
|
||||
proj_mod = "proj_tox"
|
||||
|
||||
/obj/item/gun_ext/flash
|
||||
name = "Phaser energy-converter mod (flash)"
|
||||
desc = "Greatly reduces damage and stun time but causes each hit to blind the target temporarily."
|
||||
overlay_name = "conv_flash"
|
||||
upgrade = PHASER_FLASH
|
||||
location = "conv"
|
||||
icon_state = "add_flash"
|
||||
proj_mod = "proj_flash"
|
||||
|
||||
/obj/item/gun_ext/emp
|
||||
name = "Phaser energy-converter mod (EMP)"
|
||||
desc = "Increases damage against synthetic lifeforms but slightly increases energy usage."
|
||||
overlay_name = "conv_emp"
|
||||
upgrade = PHASER_EMP
|
||||
location = "conv"
|
||||
icon_state = "add_emp"
|
||||
proj_mod = "proj_emp"
|
||||
|
||||
/obj/item/gun_ext/conc
|
||||
name = "Phaser energy-converter mod (concussion)"
|
||||
desc = "Disables stuns and reduces damage but knocks target back on hit."
|
||||
overlay_name = "conv_conc"
|
||||
upgrade = PHASER_CONC
|
||||
location = "conv"
|
||||
icon_state = "add_conc"
|
||||
proj_mod = "proj_conc"
|
||||
|
||||
/obj/item/oldgun
|
||||
name = "gun"
|
||||
icon = 'icons/obj/gun.dmi'
|
||||
inhand_image_icon = 'icons/mob/inhand/hand_weapons.dmi'
|
||||
flags = FPRINT | TABLEPASS | CONDUCT | ONBELT | EXTRADELAY
|
||||
item_state = "gun"
|
||||
m_amt = 2000
|
||||
throwforce = 5
|
||||
w_class = 2.0
|
||||
throw_speed = 4
|
||||
throw_range = 10
|
||||
|
||||
/obj/item/oldgun/energy
|
||||
name = "energy"
|
||||
var/charges = 10.0
|
||||
var/maximum_charges = 10.0
|
||||
var/unscrewed = 0
|
||||
mats = 15
|
||||
|
||||
/obj/item/oldgun/energy/phaser/secure
|
||||
safeties = 1
|
||||
name = "locked phaser"
|
||||
|
||||
/obj/item/oldgun/energy/phaser
|
||||
name = "phaser"
|
||||
icon_state = "phaser"
|
||||
desc = "Set phasers to 'Robust'"
|
||||
w_class = 3.0
|
||||
item_state = "gun"
|
||||
force = 10.0
|
||||
throw_speed = 2
|
||||
throw_range = 10
|
||||
|
||||
var/obj/item/gun_ext/extension_mod = null
|
||||
var/obj/item/gun_ext/converter_mod = null
|
||||
var/list/shot_overlays = new/list()
|
||||
var/list/shot_firesounds = new/list()
|
||||
var/list/shot_impactsounds = new/list()
|
||||
|
||||
var/upgrades = 0
|
||||
|
||||
charges = 125
|
||||
maximum_charges = 125
|
||||
|
||||
var/charges_per_shot = 0
|
||||
var/safeties = 0
|
||||
|
||||
var/prop_dmg = 0
|
||||
var/prop_stun = 0
|
||||
var/prop_range = 0
|
||||
var/prop_maxrange = 1
|
||||
var/prop_power = 10
|
||||
var/prop_iconstate = ""
|
||||
var/prop_sound = 'sound/weapons/Taser.ogg'
|
||||
|
||||
var/overloading = 0
|
||||
|
||||
verb/remove_mods()
|
||||
set src in usr
|
||||
set name = "Remove Mods"
|
||||
if(!src.contents.len)
|
||||
boutput(usr, "<span style=\"color:red\">No mods to remove.</span>")
|
||||
return
|
||||
boutput(usr, "<span style=\"color:blue\">You remove all mods.</span>")
|
||||
for(var/obj/O in src)
|
||||
O.set_loc(get_turf(src))
|
||||
var/obj/item/oldgun/energy/phaser/P = new/obj/item/oldgun/energy/phaser(get_turf(src))
|
||||
var/energy_old = min(125,src.charges)
|
||||
P.safeties = src.safeties
|
||||
P.charges = energy_old
|
||||
P.update_icon()
|
||||
qdel(src)
|
||||
|
||||
examine()
|
||||
set src in view()
|
||||
if(src.contents.len)
|
||||
boutput(usr, "<span style=\"color:blue\">Installed mods:</span>")
|
||||
boutput(usr, "")
|
||||
for(var/obj/O in src)
|
||||
boutput(usr, "<span style=\"color:blue\">[O.name]</span>")
|
||||
boutput(usr, "<span style=\"color:blue\">[O.desc]</span>")
|
||||
boutput(usr, "")
|
||||
..()
|
||||
|
||||
New()
|
||||
update_settings()
|
||||
..()
|
||||
|
||||
proc/generate_overlays()
|
||||
src.overlays = null
|
||||
if(extension_mod)
|
||||
src.overlays += icon('icons/obj/gun.dmi',extension_mod.overlay_name)
|
||||
if(converter_mod)
|
||||
src.overlays += icon('icons/obj/gun.dmi',converter_mod.overlay_name)
|
||||
|
||||
attackby(obj/O as obj, mob/user as mob)
|
||||
if (istype(O,/obj/item/gun_ext))
|
||||
var/obj/item/gun_ext/G = O
|
||||
switch(G.location)
|
||||
if("ext")
|
||||
if(extension_mod)
|
||||
boutput(user, "<span style=\"color:red\">There is already a gun extension installed.</span>")
|
||||
else
|
||||
user.drop_item()
|
||||
boutput(user, "<span style=\"color:blue\">You install the gun extension.</span>")
|
||||
playsound(user, "sound/items/Screwdriver2.ogg", 65, 1)
|
||||
G.set_loc(src)
|
||||
extension_mod = G
|
||||
generate_overlays()
|
||||
upgrades |= G.upgrade
|
||||
if(G.proj_mod) shot_overlays += G.proj_mod
|
||||
if(G.proj_sound) shot_firesounds += G.proj_sound
|
||||
if(G.proj_sound_impact) shot_impactsounds += G.proj_sound_impact
|
||||
update_settings()
|
||||
if("conv")
|
||||
if(converter_mod)
|
||||
boutput(user, "<span style=\"color:red\">There is already an energy-converter mod installed.</span>")
|
||||
else
|
||||
user.drop_item()
|
||||
boutput(user, "<span style=\"color:blue\">You install the energy-converter mod.</span>")
|
||||
playsound(user, "sound/items/Screwdriver2.ogg", 65, 1)
|
||||
G.set_loc(src)
|
||||
converter_mod = G
|
||||
generate_overlays()
|
||||
upgrades |= G.upgrade
|
||||
if(G.proj_mod) shot_overlays += G.proj_mod
|
||||
if(G.proj_sound) shot_firesounds += G.proj_sound
|
||||
if(G.proj_sound_impact) shot_impactsounds += G.proj_sound_impact
|
||||
update_settings()
|
||||
|
||||
proc/update_settings()
|
||||
var/dmg_mod = 0
|
||||
var/stun_mod = 0
|
||||
var/cost_mod = 0
|
||||
if(overloading) return
|
||||
|
||||
if(upgrades & PHASER_ENERGY)
|
||||
maximum_charges = 175
|
||||
else if((upgrades & PHASER_RADIUS) || (upgrades & PHASER_HOMING))
|
||||
maximum_charges = 100
|
||||
charges = min(100,charges)
|
||||
else
|
||||
maximum_charges = 125
|
||||
|
||||
if(upgrades & PHASER_RADIUS)
|
||||
prop_maxrange = 2
|
||||
else
|
||||
prop_maxrange = 1
|
||||
|
||||
switch(prop_power)
|
||||
if(1 to 33)
|
||||
prop_iconstate = "phaser_light"
|
||||
dmg_mod = -round(prop_power/6)
|
||||
stun_mod = min(round(prop_power/4),4)
|
||||
prop_sound = 'sound/weapons/laserlight.ogg'
|
||||
if(34 to 66)
|
||||
prop_iconstate = "phaser_med"
|
||||
dmg_mod = 1
|
||||
stun_mod = -round(prop_power/6)
|
||||
prop_sound = 'sound/weapons/lasermed.ogg'
|
||||
if(67 to 100)
|
||||
prop_iconstate = "phaser_heavy"
|
||||
dmg_mod = max(0,round(prop_power / 10)-2)
|
||||
stun_mod = -prop_power
|
||||
prop_sound = 'sound/weapons/laserheavy.ogg'
|
||||
if(101 to 150)
|
||||
prop_iconstate = "phaser_ultra"
|
||||
dmg_mod = max(0,round(prop_power / 10)-2) + 10
|
||||
stun_mod = -20
|
||||
cost_mod = max(0,round(prop_power / 10)-2)
|
||||
prop_sound = 'sound/weapons/laserultra.ogg'
|
||||
|
||||
if(upgrades & PHASER_SNIPER)
|
||||
prop_range = 0
|
||||
prop_dmg = max(0, round(prop_power / 4)-(prop_range*5) + dmg_mod)
|
||||
prop_stun = max(0,round( ((prop_power/4)+stun_mod-prop_range*2)) )
|
||||
if(upgrades & PHASER_SNIPER)
|
||||
cost_mod += 50
|
||||
prop_dmg += 45
|
||||
if(upgrades & PHASER_ENERGY)
|
||||
prop_dmg = max(0,prop_dmg-8)
|
||||
if(upgrades & PHASER_HOMING)
|
||||
cost_mod += 5
|
||||
if(upgrades & PHASER_BURN)
|
||||
cost_mod -= 5
|
||||
if(upgrades & PHASER_TOXINS)
|
||||
cost_mod += 8
|
||||
if(upgrades & PHASER_EMP)
|
||||
cost_mod += 5
|
||||
if(upgrades & PHASER_SING)
|
||||
cost_mod += 8
|
||||
prop_dmg = max(0,prop_dmg-((prop_dmg/3)+3))
|
||||
if(upgrades & PHASER_FLASH)
|
||||
prop_dmg = max(0,round(prop_dmg-(prop_dmg/2)))
|
||||
prop_stun = max(0, prop_stun-5)
|
||||
if(upgrades & PHASER_CONC)
|
||||
prop_stun = 0
|
||||
prop_dmg = max(0,round(prop_dmg-(prop_dmg/2)))
|
||||
|
||||
charges_per_shot = round(max( 10,(prop_power/4)+(prop_range*14) ))+cost_mod
|
||||
|
||||
if(isrobot(loc))
|
||||
charges_per_shot = charges_per_shot*10
|
||||
|
||||
return
|
||||
|
||||
proc/update_icon()
|
||||
var/ratio = src.charges / maximum_charges
|
||||
ratio = round(ratio, 0.25) * 100
|
||||
src.icon_state = text("phaser[]", ratio)
|
||||
|
||||
afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag)
|
||||
if(overloading) return
|
||||
if (flag)
|
||||
return
|
||||
|
||||
src.add_fingerprint(user)
|
||||
|
||||
if(isrobot(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
if(R.cell.charge < charges_per_shot)
|
||||
boutput(user, "<span style=\"color:red\">*Warning* Not enough power.</span>");
|
||||
return
|
||||
else
|
||||
if(src.charges < charges_per_shot)
|
||||
boutput(user, "<span style=\"color:red\">*click* *click*</span>");
|
||||
return
|
||||
|
||||
if(shot_firesounds.len)
|
||||
for(var/S in shot_firesounds)
|
||||
playsound(user, S, 60, 1)
|
||||
else
|
||||
playsound(user, prop_sound, 60, 1)
|
||||
|
||||
if(isrobot(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
R.cell.charge -= charges_per_shot
|
||||
else
|
||||
src.charges -= charges_per_shot
|
||||
|
||||
update_icon()
|
||||
|
||||
spawn(0)
|
||||
|
||||
var/obj/phaser_projectile/O = new/obj/phaser_projectile(get_turf(src))
|
||||
O.damage = prop_dmg
|
||||
O.range = prop_range
|
||||
O.stun = prop_stun
|
||||
O.power = prop_power
|
||||
O.upgrades = upgrades
|
||||
O.icon_state = prop_iconstate
|
||||
O.dest = get_turf(target)
|
||||
O.origin = user
|
||||
O.impactsounds = shot_impactsounds.Copy()
|
||||
spawn(15) qdel(O)
|
||||
|
||||
if(shot_overlays.len)
|
||||
for(var/S in shot_overlays)
|
||||
O.overlays += icon("icons/obj/gun.dmi",S)
|
||||
|
||||
while(O.loc != O.dest)
|
||||
var/impact = 0
|
||||
var/turf/next = get_step_towards(O,O.dest)
|
||||
if(next.density) impact = 1
|
||||
else O.set_loc(next)
|
||||
|
||||
if(O.upgrades & PHASER_HOMING)
|
||||
for(var/mob/living/M in view(2,O.loc))
|
||||
if(M == O.origin) continue
|
||||
step_towards(O,M)
|
||||
break
|
||||
|
||||
for(var/mob/living/M in O.loc)
|
||||
if(M == O.origin || M.lying) continue
|
||||
impact = 1
|
||||
break
|
||||
|
||||
for(var/obj/machinery/bot/B in O.loc)
|
||||
impact = 1
|
||||
break
|
||||
|
||||
for(var/obj/critter/C in O.loc)
|
||||
impact = 1
|
||||
break
|
||||
|
||||
if(O.loc == O.dest) impact = 1
|
||||
|
||||
if(impact)
|
||||
if(O.impactsounds.len)
|
||||
for(var/S in O.impactsounds)
|
||||
playsound(user, S, 65, 1)
|
||||
|
||||
if(O.upgrades & PHASER_SING)
|
||||
var/turf/myloc = O.loc
|
||||
for(var/mob/living/M in view(2,O.loc))
|
||||
if(M == O.origin) continue
|
||||
spawn(0)
|
||||
step_towards(M,myloc)
|
||||
sleep(5)
|
||||
step_towards(M,myloc)
|
||||
|
||||
var/obj/projectile/PBul = unpool(/obj/projectile)
|
||||
var/obj/projectile/PLas = unpool(/obj/projectile)
|
||||
PBul.proj_data = new /datum/projectile/bullet/revolver_357( )
|
||||
PLas.proj_data = new /datum/projectile/laser( )
|
||||
for(var/obj/machinery/bot/B in view(O.range,O.loc))
|
||||
if(O.upgrades & PHASER_EMP)
|
||||
B.bullet_act(PBul)
|
||||
B.bullet_act(PLas)
|
||||
else
|
||||
B.bullet_act(PLas)
|
||||
if(O.upgrades & PHASER_CONC)
|
||||
var/dir_old = O.dir
|
||||
spawn(0)
|
||||
step(B,dir_old)
|
||||
sleep(3)
|
||||
step(B,dir_old)
|
||||
|
||||
for(var/obj/critter/C in view(O.range,O.loc))
|
||||
C.bullet_act(PLas)
|
||||
if(O.upgrades & PHASER_CONC)
|
||||
var/dir_old = O.dir
|
||||
spawn(0)
|
||||
step(C,dir_old)
|
||||
sleep(3)
|
||||
step(C,dir_old)
|
||||
|
||||
qdel(PBul)
|
||||
qdel(PLas)
|
||||
|
||||
for(var/mob/living/M in view(O.range,O.loc))
|
||||
if(M == O.origin) continue
|
||||
|
||||
user.lastattacked = M
|
||||
M.lastattacker = user
|
||||
M.lastattackertime = world.time
|
||||
|
||||
if(!isrobot(M) || (isrobot(M)&&!(O.upgrades & PHASER_EMP)))
|
||||
if(O.upgrades & PHASER_BURN)
|
||||
M.TakeDamage("chest", 0, O.damage)
|
||||
else if(O.upgrades & PHASER_TOXINS)
|
||||
M.take_toxin_damage(O.damage)
|
||||
if(M.reagents)
|
||||
M.reagents.add_reagent("toxin",7)
|
||||
else
|
||||
random_brute_damage(M, max(0,O.damage))
|
||||
M.weakened += max(0,O.stun)
|
||||
else if(isrobot(M) && (O.upgrades & PHASER_EMP))
|
||||
random_brute_damage(M, max(0,round(O.damage*1.5)))
|
||||
M.weakened += max(0,O.stun)
|
||||
if(O.upgrades & PHASER_FLASH)
|
||||
M.flash(60)
|
||||
|
||||
if(O.upgrades & PHASER_CONC)
|
||||
var/dir_old = O.dir
|
||||
spawn(0)
|
||||
M.weakened += 2
|
||||
step(M,dir_old)
|
||||
sleep(3)
|
||||
step(M,dir_old)
|
||||
|
||||
switch(O.power)
|
||||
if(1 to 33)
|
||||
for(var/turf/simulated/floor/T in view(O.range,O.loc))
|
||||
var/obj/OV = unpool(/obj/effects/sparks)
|
||||
OV.set_loc(T)
|
||||
OV.dir = pick(alldirs)
|
||||
spawn(20) if (OV) pool(OV)
|
||||
if(34 to 66)
|
||||
playsound(O.loc, "sound/effects/exlow.ogg", 65, 1)
|
||||
for(var/turf/simulated/floor/T in view(O.range,O.loc))
|
||||
var/obj/OV = new/obj/overlay(T)
|
||||
OV.icon = 'icons/effects/effects.dmi'
|
||||
OV.icon_state = "empdisable"
|
||||
OV.dir = pick(alldirs)
|
||||
spawn(3) qdel(OV)
|
||||
if(prob(O.power/2) || !O.range)
|
||||
T.burn_tile()
|
||||
if(67 to 100)
|
||||
playsound(O.loc, "sound/weapons/flashbang.ogg", 65, 1)
|
||||
for(var/turf/simulated/floor/T in view(O.range,O.loc))
|
||||
var/obj/OV = new/obj/effects/expl_particles(T)
|
||||
OV.dir=get_dir(O.loc,OV)
|
||||
if(prob(O.power/2) || !O.range)
|
||||
T.break_tile()
|
||||
if(101 to 150)
|
||||
playsound(O.loc, "sound/weapons/grenade.ogg", 65, 1)
|
||||
for(var/turf/simulated/floor/T in view(O.range,O.loc))
|
||||
var/obj/OV = new/obj/effects/expl_particles(T)
|
||||
OV.dir=get_dir(O.loc,OV)
|
||||
if(prob(85) || !O.range)
|
||||
T.break_tile_to_plating()
|
||||
|
||||
qdel(O)
|
||||
return
|
||||
sleep(1)
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
if(overloading) return
|
||||
if(usr.stat || usr.restrained()) return
|
||||
if(!in_range(src, usr)) return
|
||||
usr.machine = src
|
||||
if (href_list["power"])
|
||||
var/change = href_list["power"]
|
||||
prop_power += text2num(change)
|
||||
if(prop_power < 0) prop_power = 0
|
||||
if(prop_power > 50 && safeties) prop_power = 50
|
||||
if(prop_power > 100) prop_power = 100
|
||||
|
||||
update_settings()
|
||||
src.attack_self(usr)
|
||||
return
|
||||
else if (href_list["focus"])
|
||||
var/change = href_list["focus"]
|
||||
prop_range += text2num(change)
|
||||
if(prop_range < 0) prop_range = 0
|
||||
if(prop_range > prop_maxrange) prop_range = prop_maxrange
|
||||
update_settings()
|
||||
src.attack_self(usr)
|
||||
return
|
||||
else if (href_list["overload"])
|
||||
boutput(usr, "<span style=\"color:red\">Your phaser overloads.</span>");
|
||||
overloading = 1
|
||||
playsound(usr, "sound/weapons/phaseroverload.ogg", 65, 1)
|
||||
spawn(60)
|
||||
var/turf/curr = get_turf(src)
|
||||
curr.hotspot_expose(700,125)
|
||||
explosion(src, curr, 0, 0, 2, 4)
|
||||
qdel(src)
|
||||
src.attack_self(usr)
|
||||
src.add_fingerprint(usr)
|
||||
return
|
||||
|
||||
attack_self(mob/user as mob)
|
||||
if(overloading) return
|
||||
usr.machine = src
|
||||
var/dat = "Phaser settings:<BR><BR>"
|
||||
dat += "Power:<BR>"
|
||||
dat += "<A href='?src=\ref[src];power=-5'>(--)</A><A href='?src=\ref[src];power=-1'>(-)</A> [prop_power] <A href='?src=\ref[src];power=1'>(+)</A><A href='?src=\ref[src];power=5'>(++)</A><BR><BR>"
|
||||
dat += "Radius:<BR>"
|
||||
//dat += "<A href='?src=\ref[src];focus=-1'>(-)</A> [prop_range] <A href='?src=\ref[src];focus=1'>(+)</A><BR><BR>"
|
||||
dat += "Energy-cost per shot:[charges_per_shot]<BR>"
|
||||
|
||||
if(isrobot(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
dat += "Energy:[R.cell.charge]<BR><BR>"
|
||||
else
|
||||
dat += "Energy:[charges]/[maximum_charges]<BR><BR>"
|
||||
|
||||
if(safeties) dat += "Safeties active. Phaser locked to non-lethal power levels."
|
||||
//dat += "Damage:[prop_dmg]<BR>"
|
||||
//dat += "Stun:[prop_stun]<BR>"
|
||||
user << browse(dat, "window=phaser;can_minimize=0;can_resize=0;size=180x340")
|
||||
onclose(user, "window=phaser")
|
||||
return
|
||||
*/
|
||||
@@ -0,0 +1,416 @@
|
||||
/obj/line_obj/railgun
|
||||
name = "Energy"
|
||||
desc = ""
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
|
||||
unpooled(var/pool)
|
||||
name = initial(name)
|
||||
desc = initial(desc)
|
||||
anchored = initial(anchored)
|
||||
density = initial(density)
|
||||
opacity = initial(opacity)
|
||||
icon = initial(icon)
|
||||
icon_state = initial(icon_state)
|
||||
layer = initial(layer)
|
||||
pixel_x = initial(pixel_x)
|
||||
pixel_y = initial(pixel_y)
|
||||
..()
|
||||
|
||||
/obj/railgun_trg_dummy
|
||||
name = ""
|
||||
desc = ""
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
invisibility = 99
|
||||
|
||||
/obj/item/railgun
|
||||
name = "Railgun"
|
||||
desc = "Bzooom"
|
||||
icon = 'icons/obj/gun.dmi'
|
||||
inhand_image_icon = 'icons/mob/inhand/hand_weapons.dmi'
|
||||
icon_state = "railgun"
|
||||
item_state = "gun"
|
||||
flags = FPRINT | EXTRADELAY | TABLEPASS | CONDUCT
|
||||
w_class = 2.0
|
||||
|
||||
afterattack(atom/target as mob|obj|turf, mob/user as mob)
|
||||
if(target == usr) return
|
||||
|
||||
var/atom/target_r = target
|
||||
|
||||
if(isturf(target))
|
||||
target_r = new/obj/railgun_trg_dummy(target)
|
||||
|
||||
playsound(src, "sound/weapons/railgun.ogg", 40, 1)
|
||||
|
||||
var/list/affected = DrawLine(src.loc, target_r, /obj/line_obj/railgun ,'icons/obj/projectiles.dmi',"WholeRailG",1,1,"HalfStartRailG","HalfEndRailG",OBJ_LAYER,1)
|
||||
|
||||
for(var/obj/O in affected)
|
||||
O.anchored = 1 //Proc wont spawn the right object type so lets do that here.
|
||||
O.name = "Energy"
|
||||
var/turf/src_turf = O.loc
|
||||
for(var/atom/A in src_turf)
|
||||
if(A == O || A == user) continue
|
||||
A.meteorhit(O)
|
||||
// var/turf/T = O.loc
|
||||
// for(var/atom/A in T.contents)
|
||||
// boutput(src, "There is a [A.name] at this location.")
|
||||
spawn(5) pool(O)
|
||||
|
||||
if(istype(target_r, /obj/railgun_trg_dummy)) qdel(target_r)
|
||||
|
||||
return
|
||||
|
||||
/*
|
||||
proc/Preload360() //This is mainly for overhead pixel movement games but often works in the majority.
|
||||
var/icon/Total_Icon = new('icons/effects/LghtLine.dmi')
|
||||
var/IS = "WholeLghtn"
|
||||
for(var/i = 0,i < 360,i++)
|
||||
var/icon/I = new('full.dmi')
|
||||
I.Turn(i+45)
|
||||
Total_Icon.Insert(I,"[IS][i]")
|
||||
IS = "HalfStartLghtn"
|
||||
for(var/i = 0,i < 360,i++)
|
||||
var/icon/I = new('halfstart.dmi')
|
||||
I.Turn(i+45)
|
||||
Total_Icon.Insert(I,"[IS][i]")
|
||||
IS = "HalfEndLghtn"
|
||||
for(var/i = 0,i < 360,i++)
|
||||
var/icon/I = new('halfend.dmi')
|
||||
I.Turn(i+45)
|
||||
Total_Icon.Insert(I,"[IS][i]")
|
||||
usr << ftp(Total_Icon,"PreloadedLine.dmi")
|
||||
*/
|
||||
|
||||
//This is not my code. VVV
|
||||
|
||||
/*
|
||||
The DrawLine proc in detail:
|
||||
|
||||
|
||||
|
||||
|
||||
The Proc:
|
||||
|
||||
DrawLine(Start,End,LineType,Icon,Whole_Icon_State,CenterOfIconStart,CenterOfIconEnd,HalfStart_Icon_State,HalfEnd_Icon_State,Layer,ExtraDetection,StartPx,StartPy,EndPx,EndPy,SpecStartPx,SpecStartPy)
|
||||
|
||||
|
||||
|
||||
The Arguments:
|
||||
|
||||
Start
|
||||
-The /atom the line will start at. CANNOT BE TURF.
|
||||
End
|
||||
-The /atom the line will end at. CANNOT BE TURF.
|
||||
LineType
|
||||
-The object type path that the lines will be defined as.
|
||||
-Example value: /obj/Line
|
||||
Icon
|
||||
-The icon that the lines will get their images from.
|
||||
-Note that you must make your .dmi file according to what you want as the Whole, HalfEnd, and HalfStart icon states.
|
||||
Whole_Icon_State
|
||||
-The icon state of the body of the lines. Like in Line.dmi, this should be a 3x3 line that stretches diagonally (NW corner-SE corner) accross the icon.
|
||||
-Default value: "", Reccomended value: "Whole"
|
||||
CenterOfIconStart
|
||||
-1 if you want the line to be drawn into the center of it's starting position, 0 if you want it to start at the edge.
|
||||
-Default: 1
|
||||
CenterOfIconEnd
|
||||
-1 if you want the line to be drawn into the center of it's ending position, 0 if you want it to start at the edge.
|
||||
-Default: 1
|
||||
HalfStart_Icon_State
|
||||
-The icon_state of the line going into the center of the starting position. Like in Line.dmi, this should be a 3x3 line that stretches diagonally from the NW corner to the 17 pixel_y mark.
|
||||
-Default and Reccomended Value: "HalfStart"
|
||||
HalfEnd_Icon_State
|
||||
-The icon_state of the line going into the center of the ending position. Like in Line.dmi, this should be a 3x3 line that stretches diagonally from the SE corner to the 17 pixel_y mark.
|
||||
-Default and Reccomended Value: "HalfEnd"
|
||||
Layer
|
||||
-This is the layer you want the line objects to be created on.
|
||||
-Default: OBJ_LAYER
|
||||
ExtraDetection
|
||||
-1 if you want it to add extra lines to the line list to account for areas where one line segment crosses 2 tiles.
|
||||
-(The reason this is in effect is so it detects all tiles the line goes into, instead of just ones where the entire line segment is within bounds. Check scrnshot1.jpg and scrnshot2.jpg for examples.)
|
||||
-Reccomended: 1
|
||||
-Note that when you access the line list that is returned by the DrawLine proc, if you have Extra Detection on, if you are editing the images of lines, make sure to check if the line has an icon or not to determine if it is an extra detection line (which is invisible) or a regular line (which is visible).
|
||||
StartPx
|
||||
-Leave null unless you want pixel-based support.
|
||||
-If you want pixel-based support, set this to the object's Px loc var. (I refer to Px as a mob's x var multiplied by 32 and then having the lower-left corner of the object's bounding box's x added to it.)
|
||||
-Example: M.Px
|
||||
-Example (with math): M.x*32+M.BBLowerLeftx
|
||||
-Default value: null
|
||||
-You can instead set a specific location instead of using an object and using it's bounding box. This is shown in the demo. Remember, however, that this library always needs a start and end object.
|
||||
-Example (without objects): 37*32+45
|
||||
StartPy
|
||||
-Leave null unless you want pixel-based support.
|
||||
-If you want pixel-based support, set this to the object's Py loc var. (I refer to Py as a mob's x var multiplied by 32 and then having the lower-left corner of the object's bounding box's y added to it.)
|
||||
-Example: M.Py
|
||||
-Example (with math): M.y*32+M.BBLowerLefty
|
||||
-Default value: null
|
||||
-You can instead set a specific location instead of using an object and using it's bounding box. This is shown in the demo. Remember, however, that this library always needs a start and end object.
|
||||
-Example (without objects): 37*32+45
|
||||
EndPx
|
||||
-Leave null unless you want pixel-based support.
|
||||
-Like StartPx, but for the ending object instead of the starting object.
|
||||
EndPy
|
||||
-Leave null unless you want pixel-based support.
|
||||
-Like StartPy, but for the ending object instead of the starting object.
|
||||
SpecStartPx
|
||||
-In StartPx, you see 3 parts that are equated for the math. M.x*32+M.BBLowerLeftx. SpecStartPx is the third part that is added to StartPx; which is, in this case, M.BBLowerLeftx.
|
||||
-It is the Px equation without the tiles into the map counted in.
|
||||
-Can be anywhere from -16 to 16.
|
||||
SpecStartPy
|
||||
-In StartPy, you see 3 parts that are equated for the math. M.y*32+M.BBLowerLefty. SpecStartPy is the third part that is added to StartPy; which is, in this case, M.BBLowerLefty.
|
||||
-It is the Py equation without the tiles into the map counted in.
|
||||
-Can be anywhere from -16 to 16.
|
||||
|
||||
|
||||
This proc returns a list of the line objects for your detection purposes. As an example of how it's used, you can
|
||||
loop through the line segments (a line segment is a 32x32 tile containing a piece of line or if not visible it's an
|
||||
extra detection line), and check if any of the line segments' locs have say, a monster in their contents. If so,
|
||||
damage that monster.
|
||||
|
||||
|
||||
|
||||
Example of Proper Usage (Tile-based):
|
||||
|
||||
src.LineList.Add(DrawLine(StartingObject,EndingObject,/obj/Line,'Line.dmi',"Whole",1,1,"HalfStart","HalfEnd",OBJ_LAYER,1))
|
||||
|
||||
You could then access the list to see what turfs/mobs/objs/etc. the line crossed like this:
|
||||
|
||||
for(var/obj/Line/L in src.LineList)
|
||||
boutput(src, "The line crossed loc [L.x],[L.y]")
|
||||
var/turf/T = L.loc
|
||||
for(var/atom/A in T.contents)
|
||||
boutput(src, "There is a [A.name] at this location.")
|
||||
|
||||
|
||||
*/
|
||||
|
||||
proc/Get_Angle(atom/ref, atom/target,startpx,startpy,endpx,endpy)
|
||||
if(!ref || !target) return 0
|
||||
var/dy
|
||||
var/dx
|
||||
if(startpx)
|
||||
dy = endpy - startpy
|
||||
dx = endpx - startpx
|
||||
else
|
||||
dy = target.y - ref.y
|
||||
dx = target.x - ref.x
|
||||
if(!dy)
|
||||
return (dx>=0) ? 90 : 270
|
||||
. = arctan(dx/dy)
|
||||
if(dy<0)
|
||||
. += 180
|
||||
else if(dx<0)
|
||||
.+=360
|
||||
|
||||
proc/arctan(x)
|
||||
var/y=arcsin(x/sqrt(1+x*x))
|
||||
return y
|
||||
|
||||
proc/DrawLine(atom/Start,atom/End,LineType,Icon,Whole_Icon_State = "",CenterOfIconStart=1,CenterOfIconEnd=1,HalfStart_Icon_State = "HalfStart",HalfEnd_Icon_State = "HalfEnd",Layer=OBJ_LAYER,ExtraDetection=1,startpx,startpy,endpx,endpy,startpx2,startpy2,PreloadedIcon=null)
|
||||
if(isturf(Start)||isturf(End))
|
||||
world.log << "ERROR: Cannot draw line with turf for starting or ending point. Please use /obj points instead."
|
||||
return
|
||||
var/list/LineList = list()
|
||||
var/Angle = Get_Angle(Start,End,startpx,startpy,endpx,endpy)
|
||||
var/icon/I
|
||||
if(!PreloadedIcon)
|
||||
I = new(Icon)
|
||||
I.Turn(Angle+45)
|
||||
else
|
||||
I = PreloadedIcon
|
||||
var/turf/CurrentLoc = line_ReturnNextTile(Start,Angle)
|
||||
if(!CurrentLoc)
|
||||
CurrentLoc = Start
|
||||
var/Nullspace = round(tan(90-Angle)*32) //round(((sin(90-Angle)/cos(90-Angle))*16)*2)
|
||||
var/ReturnedDir = line_ReturnDir(Start,Angle,End,startpx,startpy,endpx,endpy)
|
||||
if(ReturnedDir == EAST||ReturnedDir == WEST)
|
||||
Nullspace = round(tanR(90-Angle)*32) //round(((cos(90-Angle)/sin(90-Angle))*16)*2)
|
||||
if(Angle == 180)
|
||||
Nullspace = 0 //Small bug workaround
|
||||
var/CoorCounter = Nullspace
|
||||
if(Start.loc != End.loc&&!(Start.loc in orange(1,End.loc)))
|
||||
while(CurrentLoc&&!(((ReturnedDir == NORTH||ReturnedDir == SOUTH)&&CurrentLoc.x == End.x)||((ReturnedDir == EAST||ReturnedDir == WEST)&&CurrentLoc.y == End.y)||(ReturnedDir == null&&CurrentLoc == End.loc)))
|
||||
var/obj/NewLine = unpool(LineType)
|
||||
if(!PreloadedIcon)
|
||||
NewLine.icon = I
|
||||
NewLine.icon_state = Whole_Icon_State
|
||||
else
|
||||
NewLine.icon = PreloadedIcon
|
||||
NewLine.icon_state = "[Whole_Icon_State][round(Angle)]"
|
||||
NewLine.layer = Layer
|
||||
if(CoorCounter >= 32)
|
||||
CoorCounter -= 32
|
||||
CurrentLoc = get_step(CurrentLoc,ReturnedDir)
|
||||
else if(CoorCounter <= -32)
|
||||
CoorCounter += 32
|
||||
CurrentLoc = get_step(CurrentLoc,ReturnedDir)
|
||||
if(!CurrentLoc)
|
||||
return
|
||||
line_PixelOffset(NewLine,ReturnedDir,Angle,CoorCounter,startpx2,startpy2)
|
||||
NewLine.set_loc(CurrentLoc)
|
||||
LineList.Add(NewLine)
|
||||
CoorCounter += Nullspace
|
||||
CurrentLoc = line_ReturnNextTile(CurrentLoc,Angle)
|
||||
if(CenterOfIconStart == 1)
|
||||
var/obj/NewLineStart = unpool(LineType)
|
||||
if(!PreloadedIcon)
|
||||
NewLineStart.icon = I
|
||||
NewLineStart.icon_state = HalfStart_Icon_State
|
||||
else
|
||||
NewLineStart.icon = PreloadedIcon
|
||||
NewLineStart.icon_state = "[HalfStart_Icon_State][round(Angle)]"
|
||||
NewLineStart.layer = Layer
|
||||
line_PixelOffset(NewLineStart,ReturnedDir,Angle,0,startpx2,startpy2)
|
||||
NewLineStart.set_loc(Start.loc)
|
||||
LineList.Add(NewLineStart)
|
||||
if(CenterOfIconEnd == 1)
|
||||
var/obj/NewLineEnd = unpool(LineType)
|
||||
if(!PreloadedIcon)
|
||||
NewLineEnd.icon = I
|
||||
NewLineEnd.icon_state = HalfEnd_Icon_State
|
||||
else
|
||||
NewLineEnd.icon = PreloadedIcon
|
||||
NewLineEnd.icon_state = "[HalfEnd_Icon_State][round(Angle)]"
|
||||
NewLineEnd.layer = Layer
|
||||
if(CoorCounter >= 32)
|
||||
CoorCounter -= 32
|
||||
CurrentLoc = get_step(CurrentLoc,ReturnedDir)
|
||||
else if(CoorCounter <= -32)
|
||||
CoorCounter += 32
|
||||
CurrentLoc = get_step(CurrentLoc,ReturnedDir)
|
||||
NewLineEnd.set_loc(CurrentLoc)
|
||||
line_PixelOffset(NewLineEnd,ReturnedDir,Angle,CoorCounter,startpx2,startpy2)
|
||||
LineList.Add(NewLineEnd)
|
||||
var/EndCount = LineList.len
|
||||
for(var/obj/L in LineList)
|
||||
if(LineList.Find(L) > EndCount)
|
||||
break
|
||||
else
|
||||
if(L.pixel_y >= 17)
|
||||
if(ExtraDetection == 1&&L.pixel_y <= 21)
|
||||
var/obj/ExtraLine = unpool(LineType)
|
||||
ExtraLine.set_loc(L.loc)
|
||||
LineList.Add(ExtraLine)
|
||||
L.pixel_y -= 32
|
||||
L.y++
|
||||
if(L.pixel_y <= -17)
|
||||
if(ExtraDetection == 1&&L.pixel_y >= -21)
|
||||
var/obj/ExtraLine = unpool(LineType)
|
||||
ExtraLine.set_loc(L.loc)
|
||||
LineList.Add(ExtraLine)
|
||||
L.pixel_y += 32
|
||||
L.y--
|
||||
if(L.pixel_x >= 17)
|
||||
if(ExtraDetection == 1&&L.pixel_x <= 21)
|
||||
var/obj/ExtraLine = unpool(LineType)
|
||||
ExtraLine.set_loc(L.loc)
|
||||
LineList.Add(ExtraLine)
|
||||
L.pixel_x -= 32
|
||||
L.x++
|
||||
if(L.pixel_x <= -17)
|
||||
if(ExtraDetection == 1&&L.pixel_x >= -21)
|
||||
var/obj/ExtraLine = unpool(LineType)
|
||||
ExtraLine.set_loc(L.loc)
|
||||
LineList.Add(ExtraLine)
|
||||
L.pixel_x += 32
|
||||
L.x--
|
||||
return LineList
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//This returns the next tile based on angle.
|
||||
proc/line_ReturnNextTile(turf/Start,Angle)
|
||||
var/turf/ReturnedLoc
|
||||
var/RetDir = line_ReturnEfficDir(Angle)
|
||||
ReturnedLoc = get_step(Start,RetDir)
|
||||
return ReturnedLoc
|
||||
|
||||
//This proc returns a straight dir based on starting and ending points
|
||||
//It is used in place of get_dir(), for get_dir() will return diagonals.
|
||||
proc/line_ReturnDir(turf/Start,Angle,turf/End,startpx,startpy,endpx,endpy)
|
||||
var/ReturnedDir = null
|
||||
var/RetDir = line_ReturnEfficDir(Angle)
|
||||
switch(RetDir)
|
||||
if(NORTH)
|
||||
if(End.x > Start.x||(startpx&&startpx <= endpx))
|
||||
ReturnedDir = EAST
|
||||
else if(End.x < Start.x||(startpx&&startpx >= endpx))
|
||||
ReturnedDir = WEST
|
||||
if(EAST)
|
||||
if(End.y > Start.y||(startpy&&startpy <= endpy))
|
||||
ReturnedDir = NORTH
|
||||
else if(End.y < Start.y||(startpy&&startpy >= endpy))
|
||||
ReturnedDir = SOUTH
|
||||
else
|
||||
ReturnedDir = null
|
||||
if(SOUTH)
|
||||
if(End.x > Start.x||(startpx&&startpx <= endpx))
|
||||
ReturnedDir = EAST
|
||||
else if(End.x <= Start.x||(startpx&&startpx >= endpx))
|
||||
ReturnedDir = WEST
|
||||
else
|
||||
ReturnedDir = null
|
||||
if(WEST)
|
||||
if(End.y > Start.y||(startpy&&startpy <= endpy))
|
||||
ReturnedDir = NORTH
|
||||
else if(End.y < Start.y||(startpy&&startpy >= endpy))
|
||||
ReturnedDir = SOUTH
|
||||
else
|
||||
ReturnedDir = null
|
||||
return ReturnedDir
|
||||
|
||||
//This offsets the image based on quadrent and direction.
|
||||
proc/line_PixelOffset(obj/NewLine,ReturnedDir,Angle,CoorCounter,startpx2=0,startpy2=0)
|
||||
if(ReturnedDir != null)
|
||||
switch(ReturnedDir)
|
||||
if(NORTH)
|
||||
if(Angle >= 225&&Angle < 315)
|
||||
NewLine.pixel_y = 0-CoorCounter+startpy2
|
||||
NewLine.pixel_x = startpx2
|
||||
else
|
||||
NewLine.pixel_y = CoorCounter+startpy2
|
||||
NewLine.pixel_x = startpx2
|
||||
if(SOUTH)
|
||||
if(Angle >= 225&&Angle < 315)
|
||||
NewLine.pixel_y = 0-CoorCounter+startpy2
|
||||
NewLine.pixel_x = startpx2
|
||||
else
|
||||
NewLine.pixel_y = CoorCounter+startpy2
|
||||
NewLine.pixel_x = startpx2
|
||||
if(EAST)
|
||||
NewLine.pixel_x = abs(CoorCounter)+startpx2
|
||||
NewLine.pixel_y = startpy2
|
||||
if(WEST)
|
||||
if(Angle >= 315)
|
||||
NewLine.pixel_x = CoorCounter+startpx2
|
||||
NewLine.pixel_y = startpy2
|
||||
else
|
||||
NewLine.pixel_x = 0-CoorCounter+startpx2
|
||||
NewLine.pixel_y = startpy2
|
||||
|
||||
//This returns a direction based on angle, to determine which straight should be used.
|
||||
proc/line_ReturnEfficDir(Angle)
|
||||
var/ReturnedDir
|
||||
if((Angle >= 0&&Angle < 45)||Angle >= 315)
|
||||
ReturnedDir = NORTH
|
||||
else if(Angle >= 45&&Angle < 135)
|
||||
ReturnedDir = EAST
|
||||
else if(Angle >= 135&&Angle < 225)
|
||||
ReturnedDir = SOUTH
|
||||
else if(Angle >= 225&&Angle < 315)
|
||||
ReturnedDir = WEST
|
||||
return ReturnedDir
|
||||
|
||||
//This returns the tangent of x, for use with North and South straights.
|
||||
proc/tan(x)
|
||||
return (sin(x)/cos(x))
|
||||
|
||||
//This returns the tangent reciprocal of x, for use with East and West straights.
|
||||
proc/tanR(x)
|
||||
return (cos(x)/sin(x))
|
||||
@@ -0,0 +1,298 @@
|
||||
#define RANDOM_Z_LEVEL_TARGET 7 //Z level that should recieve randomized station
|
||||
#define RANDOM_Z_LEVEL_SOURCE 6 //Z level that contains source rooms with room_props objects.
|
||||
#define RANDOM_Z_LEVEL_MAXROOMS 35 //How many rooms max should we use.
|
||||
|
||||
//Make sure that no duplicates can exist in unconnected list.
|
||||
//Write something that runs at the end and plugs up holes to space. either with walls or airlocks
|
||||
//Add something to room props that tells us if only one instance of that room is allowed.
|
||||
|
||||
/proc/jumptoseed()
|
||||
usr.x = 112
|
||||
usr.y = 112
|
||||
usr.z = 7
|
||||
|
||||
/area/random_source //Used to clean up after we're done.
|
||||
name = "Random station source tiles"
|
||||
icon_state = "yellow"
|
||||
|
||||
/area/random_station
|
||||
name = "Mysterious Station"
|
||||
icon_state = "yellow"
|
||||
requires_power = 0
|
||||
luminosity = 1
|
||||
RL_Lighting = 0
|
||||
|
||||
var/list/rnd_rooms = new/list()
|
||||
var/list/rnd_cons = new/list()
|
||||
|
||||
/datum/source_room
|
||||
var/list/tiles = new/list()
|
||||
var/area
|
||||
|
||||
/obj/room_monsterspawn //Used to mark spawns for monsters.
|
||||
name = "room monster spawn"
|
||||
anchored = 1
|
||||
invisibility = 100
|
||||
var/probability = 100 //probability that we actually spawn something here.
|
||||
icon = 'icons/misc/mark.dmi'
|
||||
icon_state = "rdn"
|
||||
|
||||
/obj/room_rewardspawn //Used to mark spawns for rewards.
|
||||
name = "room reward spawn"
|
||||
anchored = 1
|
||||
invisibility = 100
|
||||
var/probability = 100 //probability that we actually spawn something here.
|
||||
icon = 'icons/misc/mark.dmi'
|
||||
icon_state = "ydn"
|
||||
|
||||
/obj/room_props //These need to be placed in the center of the room
|
||||
name = "room props"
|
||||
anchored = 1
|
||||
invisibility = 100
|
||||
var/room_range = 1 //Range of the room (see range proc for how the numbers work)
|
||||
var/room_unique = 0 //Is this an unique room that should only be placed once? 0=no, 1=yes
|
||||
var/list/connections = new/list()
|
||||
icon = 'icons/misc/mark.dmi'
|
||||
icon_state = "props"
|
||||
|
||||
/obj/room_connection //These are placed north east south and west from the center at the edge of the room if that tile is not solid
|
||||
name = "room connection" //Or otherwise blocked. These are used to connect rooms to each other.
|
||||
anchored = 1
|
||||
invisibility = 100
|
||||
var/open_dir = -1 //These vars are automatically set. Dont need to mess with them.
|
||||
var/obj/room_props/room = null
|
||||
|
||||
proc/copy_vars(var/atom/from, var/atom/target)
|
||||
if (!target || !from) return
|
||||
for(var/V in from.vars)
|
||||
if (!issaved(from.vars[V]))
|
||||
continue
|
||||
|
||||
//The following are commented out because they are already tmp, so issaved() is false for them.
|
||||
//if(V == "x") continue
|
||||
//if(V == "y") continue
|
||||
//if(V == "z") continue
|
||||
//if(V == "loc") continue
|
||||
if(V == "locs") continue
|
||||
if(V == "contents") continue
|
||||
//if(V == "type") continue
|
||||
//if(V == "parent_type") continue
|
||||
//if(V == "vars") continue
|
||||
//if(V == "verbs") continue
|
||||
target.vars[V] = from.vars[V]
|
||||
|
||||
proc/should_copy_room(var/obj/room_props/source, var/turf/target)
|
||||
for(var/turf/T in range(source.room_range, target))
|
||||
var/diff_x = T.x - target.x
|
||||
var/diff_y = T.y - target.y
|
||||
var/turf/source_turf = locate(source.loc.x + diff_x, source.loc.y + diff_y, RANDOM_Z_LEVEL_SOURCE)
|
||||
if(istype(source_turf, /turf/space) && !source_turf.contents.len) continue
|
||||
if(!istype(T, /turf/space))
|
||||
return 0
|
||||
if(T.contents.len)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
proc/copy_room_to(var/obj/room_props/source, var/turf/target)
|
||||
for(var/turf/T in range(source.room_range, source.loc))
|
||||
if(istype(T, /turf/space) && !T.contents.len) continue //No need to copy this. This is the default state.
|
||||
var/diff_x = T.x - source.x
|
||||
var/diff_y = T.y - source.y
|
||||
var/turf/target_turf = locate(target.x + diff_x, target.y + diff_y, RANDOM_Z_LEVEL_TARGET)
|
||||
if(!target_turf) continue //Outside map.
|
||||
new T.type(target_turf)
|
||||
copy_vars(T, target_turf)
|
||||
new/area/random_station(target_turf)
|
||||
for(var/atom/A in T)
|
||||
var/atom/newAtom = new A.type(target_turf)
|
||||
copy_vars(A, newAtom)
|
||||
return
|
||||
|
||||
/proc/has_dense_objects(var/turf/T)
|
||||
for(var/atom/A in T)
|
||||
if(A.density) return 1
|
||||
return 0
|
||||
|
||||
/proc/cleanuprnd()
|
||||
for(var/obj/room_props/p in world)
|
||||
qdel(p)
|
||||
for(var/obj/room_connection/c in world)
|
||||
qdel(c)
|
||||
var/area/A = locate(/area/random_source)
|
||||
for(var/obj/toDel in A)
|
||||
qdel(toDel)
|
||||
|
||||
proc/spawnmonsters()
|
||||
var/theme = pick("undead", "plantsnanimals", "aliens", "demonsnmutants")
|
||||
for(var/obj/room_monsterspawn/S in world)
|
||||
if(S.z != RANDOM_Z_LEVEL_TARGET)
|
||||
continue
|
||||
if(prob(S.probability))
|
||||
switch(theme)
|
||||
if("undead")
|
||||
var/selected = pick(/obj/critter/spirit, /obj/critter/zombie, /obj/critter/zombie/scientist, /obj/critter/zombie/security)
|
||||
new selected(S.loc)
|
||||
qdel(S)
|
||||
if("plantsnanimals")
|
||||
var/selected = pick(/obj/critter/bear, /obj/critter/spacebee, /obj/critter/lion, /obj/critter/killertomato, /obj/critter/maneater)
|
||||
new selected(S.loc)
|
||||
qdel(S)
|
||||
if("aliens")
|
||||
var/selected = pick(/obj/critter/martian/soldier, /obj/critter/martian/warrior, /obj/critter/martian/psychic)
|
||||
new selected(S.loc)
|
||||
qdel(S)
|
||||
if("demonsnmutants")
|
||||
var/selected = pick(/obj/critter/bloodling, /obj/critter/blobman, /obj/critter/mimic)
|
||||
new selected(S.loc)
|
||||
qdel(S)
|
||||
|
||||
proc/spawnrewards()
|
||||
for(var/obj/room_rewardspawn/S in world)
|
||||
if(S.z != RANDOM_Z_LEVEL_TARGET)
|
||||
continue
|
||||
if(prob(S.probability))
|
||||
var/selected = pick(/obj/storage/crate/loot) //No idea what the rewards should be
|
||||
new selected(S.loc)
|
||||
qdel(S)
|
||||
|
||||
proc/spawndeco()
|
||||
var/theme = pick("bloody", "messy", "dirty", "clean")
|
||||
for(var/turf/T in locate(/area/random_station))
|
||||
if(T.z != RANDOM_Z_LEVEL_TARGET)
|
||||
continue
|
||||
switch(theme)
|
||||
if("bloody")
|
||||
if(T.density)
|
||||
if(prob(11) && prob(50))
|
||||
var/selected = pick(/obj/decal/cleanable/blood, /obj/decal/cleanable/blood/splatter)
|
||||
new selected(T)
|
||||
else
|
||||
if(prob(11) && prob(55))
|
||||
var/selected = pick(/obj/decal/cleanable/blood, /obj/decal/cleanable/blood/splatter, /obj/decal/cleanable/blood/gibs, /obj/decal/cleanable/blood/gibs/core, /obj/decal/cleanable/blood/gibs/body)
|
||||
new selected(T)
|
||||
if("messy")
|
||||
if(T.density)
|
||||
if(prob(11) && prob(50))
|
||||
var/selected = pick(/obj/decal/cleanable/eggsplat, /obj/decal/cleanable/tomatosplat)
|
||||
new selected(T)
|
||||
else
|
||||
if(prob(11) && prob(55))
|
||||
var/selected = pick(/obj/decal/cleanable/generic, /obj/deskclutter, /obj/decal/cleanable/robot_debris, /obj/decal/cleanable/robot_debris/limb, /obj/decal/cleanable/robot_debris/gib, /obj/decal/cleanable/molten_item)
|
||||
new selected(T)
|
||||
if("dirty")
|
||||
if(T.density)
|
||||
if(prob(11) && prob(50))
|
||||
var/selected = pick(/obj/decal/cleanable/eggsplat, /obj/decal/cleanable/tomatosplat, /obj/decal/cleanable/oil, /obj/decal/cleanable/oil/streak, /obj/decal/cleanable/fungus)
|
||||
new selected(T)
|
||||
else
|
||||
if(prob(11) && prob(55))
|
||||
var/selected = pick(/obj/decal/cleanable/dirt, /obj/decal/cleanable/oil, /obj/decal/cleanable/oil/streak, /obj/decal/cleanable/vomit, /obj/decal/cleanable/urine)
|
||||
new selected(T)
|
||||
if("clean")
|
||||
continue
|
||||
|
||||
proc/create_random_station()
|
||||
var/mid_x = round(world.maxx / 2)
|
||||
var/mid_y = round(world.maxy / 2)
|
||||
|
||||
var/turf/origin = locate(mid_x, mid_y, RANDOM_Z_LEVEL_TARGET)
|
||||
|
||||
for(var/obj/room_props/p in world)
|
||||
if(p.z != RANDOM_Z_LEVEL_SOURCE) continue
|
||||
rnd_rooms.Add(p)
|
||||
var/turf/north = locate(p.x, p.y + p.room_range, RANDOM_Z_LEVEL_SOURCE)
|
||||
var/turf/south = locate(p.x, p.y - p.room_range, RANDOM_Z_LEVEL_SOURCE)
|
||||
var/turf/east = locate(p.x + p.room_range, p.y, RANDOM_Z_LEVEL_SOURCE)
|
||||
var/turf/west = locate(p.x - p.room_range, p.y, RANDOM_Z_LEVEL_SOURCE)
|
||||
if(north)
|
||||
if(!north.density && !istype(north, /turf/space) && !has_dense_objects(north))
|
||||
var/obj/room_connection/c = new/obj/room_connection(north)
|
||||
c.open_dir = NORTH
|
||||
c.room = p
|
||||
rnd_cons.Add(c)
|
||||
p.connections.Add(c)
|
||||
if(south)
|
||||
if(!south.density && !istype(south, /turf/space) && !has_dense_objects(south))
|
||||
var/obj/room_connection/c = new/obj/room_connection(south)
|
||||
c.open_dir = SOUTH
|
||||
c.room = p
|
||||
rnd_cons.Add(c)
|
||||
p.connections.Add(c)
|
||||
if(east)
|
||||
if(!east.density && !istype(east, /turf/space) && !has_dense_objects(east))
|
||||
var/obj/room_connection/c = new/obj/room_connection(east)
|
||||
c.open_dir = EAST
|
||||
c.room = p
|
||||
rnd_cons.Add(c)
|
||||
p.connections.Add(c)
|
||||
if(west)
|
||||
if(!west.density && !istype(west, /turf/space) && !has_dense_objects(west))
|
||||
var/obj/room_connection/c = new/obj/room_connection(west)
|
||||
c.open_dir = WEST
|
||||
c.room = p
|
||||
rnd_cons.Add(c)
|
||||
p.connections.Add(c)
|
||||
|
||||
var/list/multi_rooms = new/list()
|
||||
for(var/obj/room_props/p_seed in rnd_rooms)
|
||||
if(p_seed.connections.len >= 2) multi_rooms.Add(p_seed)
|
||||
|
||||
var/obj/room_props/selected = pick(multi_rooms)
|
||||
copy_room_to(selected, origin)
|
||||
|
||||
var/list/unconnected = new/list()
|
||||
for(var/obj/room_connection/R in range(selected.room_range, origin))
|
||||
unconnected.Add(R)
|
||||
|
||||
var/rooms_left = RANDOM_Z_LEVEL_MAXROOMS
|
||||
|
||||
while(rooms_left > 0 && unconnected.len && multi_rooms.len)
|
||||
var/obj/room_connection/newcon = pick(unconnected)
|
||||
unconnected.Remove(newcon)
|
||||
var/list/valid_rooms = new/list()
|
||||
for(var/obj/room_props/valid in multi_rooms)
|
||||
for(var/obj/room_connection/chk_con in valid.connections)
|
||||
if(chk_con.open_dir == turn(newcon.open_dir, 180))
|
||||
valid_rooms.Add(valid)
|
||||
valid_rooms[valid] = chk_con
|
||||
var/obj/room_props/selected_new = pick(valid_rooms)
|
||||
var/turf/target_origin = newcon.loc
|
||||
for(var/i=0, i <= selected_new.room_range, i++)
|
||||
target_origin = get_step(target_origin, newcon.open_dir)
|
||||
if(target_origin)
|
||||
if(should_copy_room(selected_new, target_origin))
|
||||
if(selected_new.room_unique)
|
||||
multi_rooms.Remove(selected_new)
|
||||
copy_room_to(selected_new, target_origin)
|
||||
var/turf/conremturf = get_step(newcon.loc, newcon.open_dir)
|
||||
var/obj/room_connection/todel = locate(/obj/room_connection) in conremturf
|
||||
qdel(todel)
|
||||
for(var/obj/room_connection/R1 in range(selected_new.room_range, target_origin))
|
||||
if(!unconnected.Find(R1))
|
||||
unconnected.Add(R1)
|
||||
rooms_left--
|
||||
qdel(newcon)
|
||||
else
|
||||
unconnected.Add(newcon) //Didnt fit, readd to open connections.
|
||||
|
||||
filling_holes:
|
||||
for(var/obj/room_connection/C in unconnected)
|
||||
var/turf/con_next = get_step(C.loc, C.open_dir)
|
||||
if(istype(con_next, /turf/space))
|
||||
if(prob(50))
|
||||
for(var/turf/T in range(C, 1))
|
||||
if(T.density)
|
||||
new T.type(C.loc)
|
||||
continue filling_holes
|
||||
new/turf/simulated/wall(C.loc)
|
||||
else
|
||||
new/obj/machinery/door/airlock/external(C.loc)
|
||||
else
|
||||
if(prob(33))
|
||||
new/obj/machinery/door/airlock/glass(C.loc)
|
||||
|
||||
cleanuprnd()
|
||||
spawnmonsters()
|
||||
spawndeco()
|
||||
spawnrewards()
|
||||
return
|
||||
@@ -0,0 +1,309 @@
|
||||
/obj/item/shipcomponent/mainweapon
|
||||
name = "Class-A Light Phaser"
|
||||
desc = "A simple phaser designed for scout vehicles."
|
||||
var/r_gunner = 0
|
||||
var/mob/gunner = null
|
||||
var/datum/projectile/current_projectile = new/datum/projectile/laser/light
|
||||
var/firerate = 8
|
||||
var/isfiring = 0
|
||||
var/weapon_score = 0.1
|
||||
var/appearanceString
|
||||
|
||||
var/uses_ammunition = 0
|
||||
var/remaining_ammunition = 0
|
||||
|
||||
icon_state = "m_w_system"
|
||||
power_used = 65
|
||||
system = "Main Weapon"
|
||||
opencomputer(mob/user as mob)
|
||||
if(user.loc != src.ship)
|
||||
return
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>[src] Console</B><BR><HR><BR>"
|
||||
if(src.active)
|
||||
if(r_gunner)
|
||||
dat += {"<B>Gunner:</B>"}
|
||||
if(!gunner)
|
||||
dat += {"<A href='?src=\ref[src];gunner=1'>Enter Gunner Seat</A><BR>"}
|
||||
else
|
||||
dat += {"[src]<BR>"}
|
||||
else
|
||||
dat += {"<B><span style=\"color:red\">SYSTEM OFFLINE</span></B>"}
|
||||
user << browse(dat, "window=ship_main_weapon")
|
||||
onclose(user, "ship_main_weapon")
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
if(usr.stat || usr.restrained())
|
||||
return
|
||||
|
||||
if (usr.loc == ship)
|
||||
usr.machine = src
|
||||
|
||||
if (href_list["gunner"])
|
||||
MakeGunner(usr)
|
||||
src.updateDialog()
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
for(var/mob/M in ship)
|
||||
if ((M.client && M.machine == src))
|
||||
src.opencomputer(M)
|
||||
else
|
||||
usr << browse(null, "window=ship_main_weapon")
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/proc/Fire(var/mob/user)
|
||||
if(isfiring) return
|
||||
isfiring = 1
|
||||
if(uses_ammunition)
|
||||
if (remaining_ammunition < ship.AmmoPerShot())
|
||||
boutput(usr, "[ship.ship_message("You need [ship.AmmoPerShot()] to fire the weapon. You currently have [remaining_ammunition] loaded.")]")
|
||||
isfiring = 0
|
||||
return
|
||||
|
||||
var/rdir = ship.dir
|
||||
if ((rdir - 1) & rdir)
|
||||
rdir &= 12
|
||||
logTheThing("combat", usr, null, "driving [ship.name] fires [src.name] (<b>Dir:</b> <i>[dir2text(rdir)]</i>, <b>Projectile:</b> <i>[src.current_projectile]</i>) at [log_loc(ship)].") // Similar to handguns, but without target coordinates (Convair880).
|
||||
ship.ShootProjectiles(user, current_projectile, rdir)
|
||||
remaining_ammunition -= ship.AmmoPerShot()
|
||||
spawn (firerate)
|
||||
isfiring = 0
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/proc/MakeGunner(mob/M as mob)
|
||||
if(!gunner)
|
||||
gunner = M
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/light_longrange
|
||||
name = "Class-AX Light Long-range Phaser"
|
||||
desc = "A phaser designed for scout vehicles. Features a more focused energy discharge, leading to an increased range."
|
||||
current_projectile = new/datum/projectile/laser/light/longrange
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/mining
|
||||
name = "Plasma Cutter System"
|
||||
desc = "A high-temperature rock cutter for pods. Use with extreme caution."
|
||||
power_used = 130
|
||||
weapon_score = 0.7
|
||||
current_projectile = new/datum/projectile/laser/mining
|
||||
appearanceString = "pod_weapon_cutter_on"
|
||||
firerate = 12
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/taser
|
||||
name = "Mk.1 Combat Taser"
|
||||
power_used = 50
|
||||
appearanceString = "pod_weapon_taser"
|
||||
weapon_score = 0.2
|
||||
current_projectile = new/datum/projectile/energy_bolt
|
||||
firerate = 10
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/phaser
|
||||
name = "Mk 1.5 Light Phaser"
|
||||
weapon_score = 0.3
|
||||
appearanceString = "pod_weapon_ltlaser"
|
||||
current_projectile = new/datum/projectile/laser/light
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/laser
|
||||
name = "Mk.2 Scout Laser"
|
||||
weapon_score = 0.4
|
||||
appearanceString = "pod_weapon_laser"
|
||||
power_used = 100
|
||||
current_projectile = new/datum/projectile/laser
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/russian
|
||||
name = "Svet-Oruzhiye Mk.4"
|
||||
weapon_score = 0.6
|
||||
current_projectile = new/datum/projectile/laser/glitter
|
||||
firerate = 5
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/disruptor_light
|
||||
name = "Mk.3 Disruptor"
|
||||
weapon_score = 0.6
|
||||
current_projectile = new/datum/projectile/disruptor
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/precursor
|
||||
name = "IRIDIUM Spheroid Projector"
|
||||
desc = "****CLASSIFIED: THANOTECH APPLIED RESEARCH DIVISION, Y-LEVEL CLEARANCE REQUIRED****."
|
||||
weapon_score = 1.25
|
||||
current_projectile = new/datum/projectile/laser/precursor/sphere
|
||||
appearanceString = "pod_weapon_precursor"
|
||||
firerate = 25
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/gun
|
||||
name = "SPK-12 Ballistic System"
|
||||
weapon_score = 1.25
|
||||
current_projectile = new/datum/projectile/bullet/a12
|
||||
appearanceString = "pod_weapon_gun_off"
|
||||
firerate = 10
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/laser_ass // hehhh
|
||||
name = "Mk.4 Assault Laser"
|
||||
weapon_score = 1.25
|
||||
power_used = 350
|
||||
firerate = 35
|
||||
appearanceString = "pod_weapon_emitter"
|
||||
current_projectile = new/datum/projectile/laser/asslaser
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/rockdrills
|
||||
name = "Rock Drilling Rig"
|
||||
power_used = 100
|
||||
weapon_score = 1.0
|
||||
current_projectile = new/datum/projectile/laser/drill
|
||||
appearanceString = "pod_weapon_drills"
|
||||
firerate = 5
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/disruptor
|
||||
name = "Heavy Disruptor Array"
|
||||
desc = "Huh."
|
||||
power_used = 180
|
||||
weapon_score = 1.25
|
||||
current_projectile = new/datum/projectile/disruptor/high
|
||||
appearanceString = "pod_weapon_cbeam_off"
|
||||
firerate = 25
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/artillery
|
||||
name = "40mm Grenade Launcher Platform"
|
||||
desc = "A slow but extremely destructive weapon that fires explosive 40mm shells."
|
||||
current_projectile = new/datum/projectile/bullet/autocannon
|
||||
|
||||
uses_ammunition = 1
|
||||
remaining_ammunition = 14
|
||||
|
||||
weapon_score = 1.5
|
||||
appearanceString = "pod_weapon_bfg"
|
||||
firerate = 100
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/UFO
|
||||
name = "UFO Blaster"
|
||||
desc = "An extraterrestrial weapons system."
|
||||
weapon_score = 1.1
|
||||
var/datum/projectile/ufo = new/datum/projectile/bullet/flare/UFO
|
||||
var/datum/projectile/hlaser = new/datum/projectile/laser/heavy
|
||||
var/mode = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
current_projectile = ufo
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
if(user.loc != src.ship)
|
||||
return
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>Weapon Console</B><BR><HR>"
|
||||
if(src.active)
|
||||
dat +="<B>Weapon Mode:</B><BR>"
|
||||
if(mode == 0)
|
||||
dat+="Heat Beam<BR>"
|
||||
dat+="<A href='?src=\ref[src];death=1'>Death Ray</A><BR>"
|
||||
else
|
||||
dat+="<A href='?src=\ref[src];heat=1'>Heat Beam</A><BR>"
|
||||
dat+="Death Ray<BR>"
|
||||
|
||||
else
|
||||
dat += {"<B><span style=\"color:red\">SYSTEM OFFLINE</span></B>"}
|
||||
user << browse(dat, "window=ship_main_weapon")
|
||||
onclose(user, "ship_main_weapon")
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
|
||||
usr.machine = src
|
||||
|
||||
if (href_list["heat"])
|
||||
current_projectile = ufo
|
||||
mode = 0
|
||||
else if(href_list["death"])
|
||||
current_projectile = hlaser
|
||||
mode = 1
|
||||
opencomputer(usr)
|
||||
return
|
||||
|
||||
// engineer miniputt constructor utility
|
||||
|
||||
/obj/item/shipcomponent/mainweapon/foamer
|
||||
name = "Industrial Utility Arms"
|
||||
desc = "A pair of robotic arms equipped with metalfoam nozzles and cutter blades."
|
||||
current_projectile = new/datum/projectile/laser/drill/cutter
|
||||
firerate = 60
|
||||
var/mode = 0
|
||||
|
||||
|
||||
Fire(var/mob/user)
|
||||
switch(mode)
|
||||
if(0)
|
||||
if(isfiring) return
|
||||
isfiring = 1
|
||||
var/obj/decal/D = new/obj/decal(ship.loc)
|
||||
D.dir = ship.dir
|
||||
D.name = "metal foam spray"
|
||||
D.icon = 'icons/obj/chemical.dmi'
|
||||
D.icon_state = "chempuff"
|
||||
D.layer = EFFECTS_LAYER_BASE
|
||||
|
||||
playsound(src.loc, "sound/machines/mixer.ogg", 50, 1)
|
||||
|
||||
// Necessary, as the foamer doesn't use the global fire proc (Convair880).
|
||||
logTheThing("combat", usr, null, "driving [ship.name] fires [src.name], creating metal foam at [log_loc(ship)].")
|
||||
|
||||
spawn(0)
|
||||
step_towards(D, get_step(D, D.dir))
|
||||
var/location = get_turf(D)
|
||||
for(var/mob/M in AIviewers(5, location))
|
||||
boutput(M, "<span style=\"color:red\">[ship] spews out a metalic foam!</span>")
|
||||
var/list/bandaidfix = list("iron" = 3, "fluorosurfactant" = 1, "acid" = 1)
|
||||
var/datum/effects/system/foam_spread/s = new()
|
||||
s.set_up(5, location, bandaidfix, 1) // Aborts if reagent list is null (even for metal foam), but I'm not gonna touch foam_spread.dm (Convair880).
|
||||
s.start()
|
||||
sleep(3)
|
||||
D.dispose()
|
||||
|
||||
spawn(firerate)
|
||||
isfiring = 0
|
||||
if(1)
|
||||
..()
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
if(user.loc != src.ship)
|
||||
return
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>Weapon Console</B><BR><HR>"
|
||||
if(src.active)
|
||||
dat +="<B>Weapon Mode:</B><BR>"
|
||||
if(mode == 0)
|
||||
dat+="Metalfoam Constructor Nozzles<BR>"
|
||||
dat+="<A href='?src=\ref[src];cutter=1'>Switch to Cutter Blades</A><BR>"
|
||||
else
|
||||
dat+="<A href='?src=\ref[src];foam=1'>Switch to Foam Nozzles</A><BR>"
|
||||
dat+="Industrial Cutter Blades<BR>"
|
||||
|
||||
else
|
||||
dat += {"<B><span style=\"color:red\">SYSTEM OFFLINE</span></B>"}
|
||||
user << browse(dat, "window=ship_main_weapon")
|
||||
onclose(user, "ship_main_weapon")
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
|
||||
usr.machine = src
|
||||
|
||||
if (href_list["foam"])
|
||||
mode = 0
|
||||
firerate = 60
|
||||
|
||||
else if(href_list["cutter"])
|
||||
mode = 1
|
||||
firerate = 15
|
||||
|
||||
opencomputer(usr)
|
||||
return
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/obj/item/device/radio/intercom/ship
|
||||
name = "Communication Panel"
|
||||
anchored = 1.0
|
||||
|
||||
/obj/item/device/radio/intercom/ship/send_hear()
|
||||
if (src.listening)
|
||||
var/list/shiphears = list()
|
||||
for(var/mob/M in src.loc)
|
||||
shiphears += M
|
||||
return shiphears
|
||||
|
||||
/obj/item/shipcomponent/communications
|
||||
power_used = 10
|
||||
active = 0
|
||||
name = "Robustco Communication Array"
|
||||
desc = "Enables long-distance communications and interfacing with pod bay door controls."
|
||||
power_used = 10
|
||||
system = "Communications"
|
||||
icon_state = "com"
|
||||
color = "#16CC77"
|
||||
var/access_type = 1
|
||||
var/obj/item/device/ship_radio_control/rc_ship = null
|
||||
|
||||
mining
|
||||
name = "NT Magnet Link Array"
|
||||
desc = "Allows a pod to communicate with a Mining Magnet for more convenient mining."
|
||||
power_used = 30
|
||||
color = "#FABF0F"
|
||||
|
||||
External()
|
||||
for(var/obj/machinery/mining_magnet/MM in range(7,src.ship))
|
||||
MM.generate_interface(usr)
|
||||
return null
|
||||
boutput(usr, "<span style=\"color:red\">No magnet found in range of seven meters.</span>")
|
||||
return null
|
||||
|
||||
syndicate
|
||||
name = "Radioarbeiten Communication Array"
|
||||
desc = "A cheaper soviet-made shipboard communicator. Often used by those who oppose NanoTrasen."
|
||||
color = "#BA1313"
|
||||
access_type = -1
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
if(ship.intercom)
|
||||
ship.intercom.attack_self(user)
|
||||
return
|
||||
|
||||
deactivate()
|
||||
..()
|
||||
if(ship.intercom)
|
||||
ship.intercom.broadcasting = 0
|
||||
ship.intercom.listening = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
rc_ship = new /obj/item/device/ship_radio_control( src )
|
||||
rc_ship.com = src
|
||||
return
|
||||
|
||||
proc/External()
|
||||
var/broadcast = copytext(html_encode(input(usr, "Please enter what you want to say over the external speaker.", "[src.name]")), 1, MAX_MESSAGE_LEN)
|
||||
if(!broadcast)
|
||||
return
|
||||
logTheThing("diary", usr, null, "(POD) : [broadcast]", "say")
|
||||
if (ishuman(usr))//istype(usr:wear_mask, /obj/item/clothing/mask/gas/voice))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
if (H.wear_mask && H.wear_mask.vchange && H.wear_id)
|
||||
. = H.wear_id:registered
|
||||
else
|
||||
. = usr.name
|
||||
else
|
||||
. = usr.real_name
|
||||
|
||||
for(var/mob/M in ship)
|
||||
boutput(M, "<font color='green'><b>[bicon(ship)]\[[.]\]</b> says, \"[broadcast]\"</font>")
|
||||
for(var/mob/O in hearers(ship, null))
|
||||
boutput(O, "<font color='green'><b>[bicon(ship)]\[[.]\]</b> says, \"[broadcast]\"</font>")
|
||||
|
||||
return null
|
||||
|
||||
/obj/item/device/ship_radio_control
|
||||
name = "Ship Radio Control"
|
||||
var/frequency = 1142
|
||||
var/net_id = null
|
||||
var/obj/item/shipcomponent/communications/com = null
|
||||
|
||||
New()
|
||||
..()
|
||||
spawn(5)
|
||||
if(radio_controller)
|
||||
radio_controller.add_object(src, "[frequency]")
|
||||
|
||||
src.net_id = format_net_id("\ref[src]")
|
||||
|
||||
receive_signal(datum/signal/signal)
|
||||
if(..())
|
||||
return
|
||||
return
|
||||
|
||||
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
|
||||
// qdel(signal)
|
||||
|
||||
proc/open_hangar(mob/user as mob)
|
||||
var/pass = input(usr, "Please enter panel access number.", "Access Number") as text
|
||||
pass = copytext(html_encode(pass), 1, 32)
|
||||
if(!pass)
|
||||
return
|
||||
|
||||
var/datum/signal/newsignal = get_free_signal()
|
||||
newsignal.data["command"] = "open door"
|
||||
if (com)
|
||||
newsignal.data["access_type"] = com.access_type
|
||||
else
|
||||
newsignal.data["access_type"] = 0
|
||||
newsignal.data["doorpass"] = pass
|
||||
newsignal.data["sender"] = net_id
|
||||
src.post_signal(newsignal)
|
||||
|
||||
|
||||
proc/return_to_station(mob/user as mob)
|
||||
// todo
|
||||
return 1
|
||||
@@ -0,0 +1,91 @@
|
||||
//essential part of the ship,provides power to other components
|
||||
//enables travel to other Z-Spaces.
|
||||
/obj/item/shipcomponent/engine
|
||||
name = "Warp-1 Engine"
|
||||
desc = "A standard engine"
|
||||
var/powergenerated = 200 //how much power for components the engine generates
|
||||
var/currentgen = 200 //handles engine power debuffs
|
||||
var/warprecharge = 300 //Interval it takes for warp to be ready again
|
||||
var/status = "Normal"
|
||||
var/speedmod = 2 // how fast should the vehicle be, lower is faster
|
||||
var/wormholeQueued = 0 //so users cant open a million inputs and bypass all cooldowns
|
||||
power_used = 0
|
||||
system = "Engine"
|
||||
icon_state = "engine"
|
||||
|
||||
activate()
|
||||
..()
|
||||
ship.powercapacity = src.powergenerated
|
||||
return
|
||||
////Warp requires recharge time
|
||||
ready()
|
||||
spawn(warprecharge)
|
||||
ready = 1
|
||||
wormholeQueued = 0
|
||||
|
||||
deactivate()
|
||||
..()
|
||||
ship.powercapacity = 0
|
||||
for(var/obj/item/shipcomponent/S in ship.components)
|
||||
if(S.active)
|
||||
S.deactivate()
|
||||
return
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
if(user.loc != src.ship)
|
||||
return
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>[src] Console</B><BR><HR><BR>"
|
||||
if(src.active)
|
||||
dat+= {"<BR><B>Current Output:</B> [currentgen]"}
|
||||
dat+= {"<BR><B>Standard Ouput:</B> [powergenerated]"}
|
||||
dat+= {"<BR><B>Engine Status:</B> [status]"}
|
||||
dat+= {"<BR><B>Current Load:</B> [ship.powercurrent]"}
|
||||
if(ready)
|
||||
dat+= {"<BR><B>Warp Status:</B> Ready"}
|
||||
else
|
||||
dat+= {"<BR><B>Warp Status:</B> Recharging"}
|
||||
else
|
||||
dat += {"<B><span style=\"color:red\">SYSTEM OFFLINE</span></B>"}
|
||||
user << browse(dat, "window=ship_engine")
|
||||
onclose(user, "ship_engine")
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/engine/proc/Wormhole()
|
||||
if (wormholeQueued)
|
||||
return
|
||||
var/list/beacons = list()
|
||||
for(var/obj/warp_beacon/W)
|
||||
beacons += W
|
||||
for (var/obj/machinery/tripod/T)
|
||||
if (istype(T.bulb, /obj/item/tripod_bulb/beacon))
|
||||
beacons += T
|
||||
wormholeQueued = 1
|
||||
var/obj/target = input(usr, "Please select a location to warp to.", "Warp Computer") as null|obj in beacons
|
||||
if(!target)
|
||||
wormholeQueued = 0
|
||||
return
|
||||
var/obj/warp_portal/P = new /obj/warp_portal( ship.loc )
|
||||
P.target = target
|
||||
step(P, ship.dir)
|
||||
ready = 0
|
||||
ready()
|
||||
/obj/item/shipcomponent/engine/helios
|
||||
name = "Helios Mark-II Engine"
|
||||
desc = "A really fast engine"
|
||||
powergenerated = 300 //how much power for components the engine generates
|
||||
currentgen = 300 //handles engine power debuffs
|
||||
warprecharge = 150 //Interval it takes for warp to be ready again
|
||||
speedmod = 1
|
||||
|
||||
/obj/item/shipcomponent/engine/hermes
|
||||
name = "Hermes 3.0 Engine"
|
||||
desc = "An incredibly powerful but slow engine"
|
||||
powergenerated = 500
|
||||
currentgen = 500
|
||||
warprecharge =300
|
||||
speedmod = 3
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/////Handles oxygen and heating
|
||||
/obj/item/shipcomponent/life_support
|
||||
name = "Nanotrasen Life-Support System"
|
||||
desc = "An advanced life-support system"
|
||||
power_used=20
|
||||
var/tempreg = 310.0
|
||||
system = "Life Support"
|
||||
icon_state = "life_support"
|
||||
@@ -0,0 +1,842 @@
|
||||
/obj/item/shipcomponent/secondary_system
|
||||
name = "Secondary System"
|
||||
desc = "Add functionality to the ship"
|
||||
power_used = 0
|
||||
system = "Secondary System"
|
||||
var/f_active = 0 //1 if use proc activates/deactivates the systems.
|
||||
var/hud_state = "blank"
|
||||
icon_state= "sec_system"
|
||||
|
||||
proc/Use(mob/user as mob)
|
||||
boutput(usr, "[ship.ship_message("No special function for this ship!")]")
|
||||
return
|
||||
|
||||
proc/Clickdrag_PodToObject(var/mob/living/user,var/atom/A)
|
||||
return
|
||||
|
||||
proc/Clickdrag_ObjectToPod(var/mob/living/user,var/atom/A)
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/cloak
|
||||
name = "Medusa Stealth System 300"
|
||||
desc = "When activated cloaks the ship."
|
||||
power_used = 250
|
||||
hud_state = "cloak"
|
||||
f_active = 1
|
||||
var/image/shield = null
|
||||
|
||||
Use(mob/user as mob)
|
||||
if(!active)
|
||||
activate()
|
||||
else
|
||||
deactivate()
|
||||
return
|
||||
|
||||
activate()
|
||||
..()
|
||||
if(!active)
|
||||
return
|
||||
ship.invisibility = 2
|
||||
shield = image("icon" = 'icons/obj/ship.dmi', "icon_state" = "shield", "layer" = MOB_LAYER)
|
||||
ship.overlays += shield
|
||||
return
|
||||
|
||||
deactivate()
|
||||
..()
|
||||
ship.invisibility = 0
|
||||
ship.overlays -= shield
|
||||
return
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
if(user.loc != src.ship)
|
||||
return
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>[src] Console</B><BR><HR><BR>"
|
||||
if(src.active)
|
||||
dat+= {"<B>SYSTEM ONLINE</B>"}
|
||||
else
|
||||
dat += {"<B><span style=\"color:red\">SYSTEM OFFLINE</span></B>"}
|
||||
user << browse(dat, "window=ship_sec_system")
|
||||
onclose(user, "ship_sec_system")
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/orescoop
|
||||
name = "Alloyed Solutions Ore Scoop/Hold"
|
||||
desc = "Allows the ship to scoop up ore automatically."
|
||||
var/capacity = 300
|
||||
hud_state = "cargo"
|
||||
f_active = 1
|
||||
|
||||
Use(mob/user as mob)
|
||||
activate()
|
||||
return
|
||||
|
||||
activate()
|
||||
boutput(usr, "[ship.ship_message("To unload, click and drag the pod onto a nearby tile.")]")
|
||||
return
|
||||
|
||||
deactivate()
|
||||
return
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
if(user.loc != src.ship)
|
||||
return
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>[src] Console</B><BR><HR><BR>"
|
||||
dat += {"<BR><B>Capacity: [src.contents.len]/[src.capacity]</B><HR>"}
|
||||
user << browse(dat, "window=ship_sec_system")
|
||||
onclose(user, "ship_sec_system")
|
||||
return
|
||||
|
||||
Clickdrag_PodToObject(var/mob/living/user,var/atom/A)
|
||||
if (contents.len < 1)
|
||||
boutput(user, "<span style=\"color:red\">[src] has nothing to unload.</span>")
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(A)
|
||||
|
||||
var/inrange = 0
|
||||
for(var/turf/ST in src.ship.locs)
|
||||
if (get_dist(T,ST) <= 1)
|
||||
inrange = 1
|
||||
break
|
||||
if (!inrange)
|
||||
boutput(user, "<span style=\"color:red\">That tile too far away.</span>")
|
||||
return
|
||||
|
||||
for(var/obj/O in T.contents)
|
||||
if(O.density)
|
||||
boutput(user, "<span style=\"color:red\">That tile is blocked by [O].</span>")
|
||||
return
|
||||
|
||||
for(var/obj/item/I in src.contents)
|
||||
I.set_loc(T)
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/cargo
|
||||
name = "Cargo Hold"
|
||||
desc = "Allows the ship to load crates and transport them."
|
||||
var/list/load = list() //Current crates inside
|
||||
var/maxcap = 3 //how many crates it can hold
|
||||
var/list/acceptable = list(/obj/storage/crate,
|
||||
/obj/machinery/artifact,
|
||||
/obj/artifact,
|
||||
/obj/mopbucket,
|
||||
/obj/machinery/portable_atmospherics,
|
||||
/obj/machinery/space_heater,
|
||||
/obj/machinery/oreaccumulator,
|
||||
/obj/machinery/bot,
|
||||
/obj/machinery/nuclearbomb)
|
||||
|
||||
hud_state = "cargo"
|
||||
f_active = 1
|
||||
|
||||
small
|
||||
maxcap = 1
|
||||
name = "Small Cargo Hold"
|
||||
|
||||
Use(mob/user as mob)
|
||||
activate()
|
||||
return
|
||||
|
||||
deactivate()
|
||||
return
|
||||
|
||||
activate()
|
||||
var/loadmode = input(usr, "Unload/Load", "Unload/Load") as null|anything in list("Load", "Unload")
|
||||
switch(loadmode)
|
||||
if("Load")
|
||||
var/atom/movable/AM = null
|
||||
for(var/atom/movable/A in get_step(ship.loc, turn(ship.dir,180) ))
|
||||
if(!A.anchored)
|
||||
AM = A
|
||||
break
|
||||
if(AM)
|
||||
load(AM)
|
||||
return
|
||||
if("Unload")
|
||||
var/crate = input(usr, "Choose which cargo to unload..", "Choose cargo") as null|anything in load
|
||||
if(!crate)
|
||||
return
|
||||
unload(crate)
|
||||
else
|
||||
return
|
||||
return
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
if(user.loc != src.ship)
|
||||
return
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>[src] Console</B><BR><HR><BR>"
|
||||
dat+= {"<BR><B>Current Contents:</B><HR>"}
|
||||
for(var/cargoitem in load)
|
||||
dat += "<BR><B>[cargoitem]</B><HR>"
|
||||
dat += "<BR>"
|
||||
user << browse(dat, "window=ship_sec_system")
|
||||
onclose(user, "ship_sec_system")
|
||||
return
|
||||
|
||||
Clickdrag_PodToObject(var/mob/living/user,var/atom/A)
|
||||
if (load.len < 1)
|
||||
boutput(user, "<span style=\"color:red\">[src] has nothing to unload.</span>")
|
||||
return
|
||||
var/turf/T = get_turf(A)
|
||||
|
||||
var/inrange = 0
|
||||
for(var/turf/ST in src.ship.locs)
|
||||
if (get_dist(T,ST) <= 1)
|
||||
inrange = 1
|
||||
break
|
||||
if (!inrange)
|
||||
boutput(user, "<span style=\"color:red\">That tile too far away.</span>")
|
||||
return
|
||||
|
||||
for(var/obj/O in T.contents)
|
||||
if(O.density)
|
||||
boutput(user, "<span style=\"color:red\">That tile is blocked by [O].</span>")
|
||||
return
|
||||
|
||||
var/crate = input(usr, "Choose which cargo to unload..", "Choose cargo") as null|anything in load
|
||||
if(!crate)
|
||||
return
|
||||
unload(crate,T)
|
||||
return
|
||||
|
||||
Clickdrag_ObjectToPod(var/mob/living/user,var/atom/A)
|
||||
if (src.load.len > src.maxcap)
|
||||
boutput(user, "<span style=\"color:red\">[src] has no available cargo space.</span>")
|
||||
return
|
||||
|
||||
switch(src.load(A))
|
||||
if (1)
|
||||
// if cargo system is not emagged, only allow crates to be loaded
|
||||
boutput(user, "<span style=\"color:red\">The pod's cargo autoloader rejects [A].</span>")
|
||||
return
|
||||
if (2)
|
||||
// cargo system full (this should never happen)
|
||||
boutput(user, "<span style=\"color:red\">[src] has no available cargo space.</span>")
|
||||
return
|
||||
if (3)
|
||||
// out of range (this should never happen)
|
||||
boutput(user, "<span style=\"color:red\">[A] is too far away to do that.</span>")
|
||||
return
|
||||
if (0)
|
||||
// success
|
||||
src.visible_message("<span style=\"color:blue\">[user] loads the [A] into [src]'s cargo bay.</span>")
|
||||
return
|
||||
|
||||
boutput(user, "<span style=\"color:red\">[src] has no cargo system or no available cargo space.</span>")
|
||||
return
|
||||
|
||||
proc/load(var/atom/movable/C)
|
||||
if(load.len >= maxcap)
|
||||
playsound(src.loc, "sound/machines/buzz-sigh.ogg", 50, 0)
|
||||
boutput(usr, "[ship.ship_message("Cargo hold is full!")]")
|
||||
return 2
|
||||
|
||||
var/inrange = 0
|
||||
for (var/turf/T in src.ship.locs)
|
||||
if (get_dist(T,C) <= 1)
|
||||
inrange = 1
|
||||
break
|
||||
if (!inrange)
|
||||
return 3
|
||||
|
||||
// if a crate, close before loading
|
||||
var/obj/storage/crate/crate = C
|
||||
if(istype(crate))
|
||||
crate.close()
|
||||
|
||||
var/acceptable_cargo = 0
|
||||
for(var/X in src.acceptable)
|
||||
if (istype(C,X))
|
||||
acceptable_cargo = 1
|
||||
break
|
||||
if (!acceptable_cargo)
|
||||
playsound(src.loc, "sound/machines/buzz-sigh.ogg", 50, 0)
|
||||
return 1 // invalid cargo
|
||||
|
||||
C.set_loc(src.loc)
|
||||
sleep(2)
|
||||
C.set_loc(src)
|
||||
load += C
|
||||
C.anchored = 1 // fix for pulled items getting pulled back out of the cargo hold
|
||||
playsound(src.loc, "sound/machines/ping.ogg", 50, 0)
|
||||
return 0
|
||||
|
||||
proc/unload(var/atom/movable/C,var/turf/T)
|
||||
if(!C)
|
||||
return
|
||||
|
||||
if(T)
|
||||
C.set_loc(T)
|
||||
else
|
||||
C.set_loc(ship.loc)
|
||||
C.anchored = 0
|
||||
step(C, turn(ship.dir,180))
|
||||
|
||||
load -= C
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/tractor_beam
|
||||
name = "Tri-Corp Tractor Beam"
|
||||
desc = "Allows the ship to pull objects towards it"
|
||||
var/atom/movable/target = null //how many crates it can hold
|
||||
var/seekrange = 10
|
||||
var/settingup = 1
|
||||
var/image/tractor = null
|
||||
f_active = 1
|
||||
power_used = 80
|
||||
hud_state = "tractor_beam"
|
||||
|
||||
run_component()
|
||||
if(settingup)
|
||||
return
|
||||
if(target in view(src.seekrange,ship.loc))
|
||||
step_to(target, ship, 1)
|
||||
return
|
||||
deactivate()
|
||||
return
|
||||
|
||||
Use(mob/user as mob)
|
||||
if(!active)
|
||||
activate()
|
||||
else
|
||||
deactivate()
|
||||
activate()
|
||||
..()
|
||||
if(!active)
|
||||
return
|
||||
var/list/targets = list()
|
||||
for (var/atom/movable/a in view(src.seekrange,ship.loc))
|
||||
if(!a.anchored)
|
||||
targets += a
|
||||
|
||||
target = input(usr, "Choose what to use the tractor beam on", "Choose Target") as null|anything in targets
|
||||
|
||||
if(!target)
|
||||
deactivate()
|
||||
return
|
||||
tractor = image("icon" = 'icons/obj/ship.dmi', "icon_state" = "tractor", "layer" = FLOAT_LAYER)
|
||||
target.overlays += tractor
|
||||
settingup = 0
|
||||
deactivate()
|
||||
..()
|
||||
settingup = 1
|
||||
if(target)
|
||||
target.overlays -= tractor
|
||||
target = null
|
||||
return
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
if(user.loc != src.ship)
|
||||
return
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>[src] Console</B><BR><HR><BR>"
|
||||
if(src.active)
|
||||
dat+= {"<BR><B>Current Target</B>: [target]"}
|
||||
else
|
||||
dat += {"<B><span style=\"color:red\">SYSTEM OFFLINE</span></B>"}
|
||||
user << browse(dat, "window=ship_sec_system")
|
||||
onclose(user, "ship_sec_system")
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/repair
|
||||
name = "Duracorp Construction Device"
|
||||
desc = "Gives ships the ability to repair external damage to space stations."
|
||||
var/list/load = list() //Current crates inside
|
||||
var/ammo = 30 //current ammo
|
||||
var/maxammo = 30 //max RCD ammo
|
||||
f_active = 1
|
||||
hud_state = "repair"
|
||||
|
||||
Use(mob/user as mob)
|
||||
activate()
|
||||
return
|
||||
|
||||
deactivate()
|
||||
return
|
||||
|
||||
activate()
|
||||
var/repairmode = input(usr, "Please choose the function to use.", "Repair Mode") as null|anything in list("Construct", "Repair", "Deconstruct")
|
||||
switch(repairmode)
|
||||
if("Construct")
|
||||
if(!ammo)
|
||||
return
|
||||
var/turf/T = get_turf(get_step(ship.loc, ship.dir))
|
||||
if (istype(T, /turf/space) && ammo >= 1)
|
||||
playsound(src.loc, "sound/items/Deconstruct.ogg", 50, 1)
|
||||
T:ReplaceWithFloor()
|
||||
ammo--
|
||||
return
|
||||
if (istype(T, /turf/simulated/floor) && ammo >= 3)
|
||||
playsound(src.loc, "sound/machines/click.ogg", 50, 1)
|
||||
if(after_time(20))
|
||||
T:ReplaceWithWall()
|
||||
playsound(src.loc, "sound/items/Deconstruct.ogg", 50, 1)
|
||||
ammo -= 3
|
||||
return
|
||||
|
||||
if("Repair")
|
||||
for(var/obj/structure/girder/G in get_step(ship.loc, ship.dir))
|
||||
var/turf/T = get_turf(G.loc)
|
||||
qdel(G)
|
||||
T:ReplaceWithWall()
|
||||
playsound(src.loc, "sound/items/Deconstruct.ogg", 50, 1)
|
||||
break
|
||||
return
|
||||
|
||||
|
||||
if("Deconstruct")
|
||||
var/turf/T = get_turf(get_step(ship.loc, ship.dir))
|
||||
if (istype(T, /turf/simulated/wall) && ammo >= 5)
|
||||
playsound(src.loc, "sound/machines/click.ogg", 50, 1)
|
||||
if(after_time(50))
|
||||
ammo -= 5
|
||||
T:ReplaceWithFloor()
|
||||
playsound(src.loc, "sound/items/Deconstruct.ogg", 50, 1)
|
||||
return
|
||||
if ((istype(T, /turf/simulated/wall/r_wall) || istype(T, /turf/simulated/wall/auto/reinforced) ) && ammo >= 5)
|
||||
playsound(src.loc, "sound/machines/click.ogg", 50, 1)
|
||||
if(after_time(50))
|
||||
ammo -= 5
|
||||
T:ReplaceWithWall()
|
||||
playsound(src.loc, "sound/items/Deconstruct.ogg", 50, 1)
|
||||
|
||||
return
|
||||
if (istype(T, /turf/simulated/floor) && ammo >= 5)
|
||||
playsound(src.loc, "sound/machines/click.ogg", 50, 1)
|
||||
if(after_time(50))
|
||||
ammo -= 5
|
||||
T:ReplaceWithSpace()
|
||||
playsound(src.loc, "sound/items/Deconstruct.ogg", 50, 1)
|
||||
return
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
if(user.loc != src.ship)
|
||||
return
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>[src] Console</B><BR><HR><BR>"
|
||||
if(src.active)
|
||||
dat+= {"<B>Current Ammo</B>:[src.ammo]/[src.maxammo]"}
|
||||
else
|
||||
dat += {"<B><span style=\"color:red\">SYSTEM OFFLINE</span></B>"}
|
||||
user << browse(dat, "window=ship_sec_system")
|
||||
onclose(user, "ship_sec_system")
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/gps
|
||||
name = "Ship's Navigation GPS"
|
||||
desc = "A useful navigation device for those lost in space."
|
||||
f_active = 1
|
||||
power_used = 50
|
||||
|
||||
Use(mob/user as mob)
|
||||
opencomputer(user)
|
||||
return
|
||||
opencomputer(mob/user as mob)
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>[src] Console</B><BR><HR><BR>"
|
||||
dat+= {"<BR><B>Located at:</B><HR>
|
||||
<b>X</b>: [src.ship.x]<BR><b>Y</b>: [src.ship.y]"}
|
||||
user << browse(dat, "window=ship_sec_system")
|
||||
onclose(user, "ship_sec_system")
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/UFO
|
||||
name = "Abductor"
|
||||
desc = "Useful for abducting humans for experimentation"
|
||||
f_active = 1
|
||||
power_used = 50
|
||||
hud_state = "abductor"
|
||||
|
||||
Use(mob/user as mob)
|
||||
var/mob/target = input(usr, "Choose Who to Abduct", "Choose Target") as mob in view(ship.loc)
|
||||
if(target)
|
||||
boutput(target, "<span style=\"color:red\"><B>You have been abducted!</B></span>")
|
||||
showswirl(get_turf(target))
|
||||
target.set_loc(ship)
|
||||
return
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
var/dat = "<TT><B>[src] Console</B><BR><HR>"
|
||||
for(var/mob/M in ship)
|
||||
if(M == ship.pilot) continue
|
||||
dat +="<A href='?src=\ref[src];release=[M.name]'><B><U>[M.name]</U></B></A><BR>"
|
||||
user << browse(dat, "window=ship_sec_system")
|
||||
onclose(user, "ship_sec_system")
|
||||
|
||||
Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
|
||||
usr.machine = src
|
||||
if (href_list["release"])
|
||||
for(var/mob/M in ship)
|
||||
if(cmptext(href_list["release"], M.name))
|
||||
var/list/turfs = get_area_turfs(/area/shuttle/arrival, 1)
|
||||
if (turfs && turfs.len)
|
||||
M.set_loc(pick(turfs))
|
||||
showswirl(get_turf(M))
|
||||
opencomputer(usr)
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/lock
|
||||
name = "Hatch Locking Unit"
|
||||
desc = "A basic hatch locking mechanism with keypad entry."
|
||||
system = "Lock"
|
||||
f_active = 1
|
||||
power_used = 0
|
||||
icon_state = "lock"
|
||||
var/code = ""
|
||||
var/configure_mode = 0 //If true, entering a valid code sets that as the code.
|
||||
|
||||
disposing()
|
||||
if (ship)
|
||||
ship.locked = 0
|
||||
ship.lock = null
|
||||
|
||||
..()
|
||||
|
||||
deactivate()
|
||||
if (ship)
|
||||
ship.locked = 0
|
||||
|
||||
if (!src.active)
|
||||
src.active = 0
|
||||
ship.powercurrent -= power_used
|
||||
|
||||
Use(mob/user as mob)
|
||||
return show_lock_panel(user, 1)
|
||||
|
||||
proc/show_lock_panel(mob/user)
|
||||
var/dat = {"
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>Pod Locking Mechanism</title>
|
||||
<style type="text/css">
|
||||
table.keypad, td.key
|
||||
{
|
||||
text-align:center;
|
||||
color:#1F1F1F;
|
||||
background-color:#7F7F7F;
|
||||
border:2px solid #1F1F1F;
|
||||
padding:10px;
|
||||
font-size:24px;
|
||||
font-weight:bold;
|
||||
}
|
||||
a
|
||||
{
|
||||
text-align:center;
|
||||
color:#1F1F1F;
|
||||
background-color:#7F7F7F;
|
||||
font-size:24px;
|
||||
font-weight:bold;
|
||||
border:2px solid #1F1F1F;
|
||||
text-decoration:none;
|
||||
display:block;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
|
||||
|
||||
<body bgcolor=#2F2F2F>
|
||||
<table border = 2 bgcolor=#7F3030 width = 150px>
|
||||
<tr><td><font face='system' size = 6 color=#FF0000 id = "readout"> </font></td></tr>
|
||||
</table>
|
||||
<br>
|
||||
<table class = "keypad">
|
||||
<tr><td><a href='javascript:keypadIn(7);'>7</a></td><td><a href='javascript:keypadIn(8);'>8</a></td><td><a href='javascript:keypadIn(9);'>9</a></td></td><td><a href='javascript:keypadIn("A");'>A</a></td></tr>
|
||||
<tr><td><a href='javascript:keypadIn(4);'>4</a></td><td><a href='javascript:keypadIn(5);'>5</a></td><td><a href='javascript:keypadIn(6)'>6</a></td></td><td><a href='javascript:keypadIn("B");'>B</a></td></tr>
|
||||
<tr><td><a href='javascript:keypadIn(1);'>1</a></td><td><a href='javascript:keypadIn(2);'>2</a></td><td><a href='javascript:keypadIn(3)'>3</a></td></td><td><a href='javascript:keypadIn("C");'>C</a></td></tr>
|
||||
<tr><td><a href='javascript:keypadIn(0);'>0</a></td><td><a href='javascript:keypadIn("F");'>F</a></td><td><a href='javascript:keypadIn("E");'>E</a></td></td><td><a href='javascript:keypadIn("D");'>D</a></td></tr>
|
||||
|
||||
<tr><td colspan=2 width = 100px><a id = "enterkey" href='?src=\ref[src];enter=0;'>ENTER</a></td><td colspan = 2 width = 100px><a href='javascript:keypadIn("reset");'>RESET</a></td></tr>
|
||||
</table>
|
||||
|
||||
<script language="JavaScript">
|
||||
var currentVal = "";
|
||||
|
||||
function updateReadout(t, additive)
|
||||
{
|
||||
if ((additive != 1 && additive != "1") || currentVal == "")
|
||||
{
|
||||
document.getElementById("readout").innerHTML = " ";
|
||||
currentVal = "";
|
||||
}
|
||||
var i = 0
|
||||
while (i++ < 4 && currentVal.length < 4)
|
||||
{
|
||||
if (t.length)
|
||||
{
|
||||
document.getElementById("readout").innerHTML += t.substr(0,1) + " ";
|
||||
currentVal += t.substr(0,1);
|
||||
t = t.substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("enterkey").setAttribute("href","?src=\ref[src];enter=" + currentVal + ";");
|
||||
}
|
||||
|
||||
function keypadIn(num)
|
||||
{
|
||||
switch (num)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
updateReadout(num.toString(), 1);
|
||||
break;
|
||||
|
||||
case "A":
|
||||
case "B":
|
||||
case "C":
|
||||
case "D":
|
||||
case "E":
|
||||
case "F":
|
||||
updateReadout(num, 1);
|
||||
break;
|
||||
|
||||
case "reset":
|
||||
updateReadout("", 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>"}
|
||||
|
||||
user << browse(dat, "window=ship_lock;size=270x300;can_resize=0;can_minimize=0")
|
||||
onclose(user, "ship_lock")
|
||||
|
||||
Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if ((usr.contents.Find(src) || (in_range(ship, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
|
||||
usr.machine = src
|
||||
|
||||
if (href_list["enter"])
|
||||
if (configure_mode)
|
||||
var/new_code = uppertext(ckey(href_list["enter"]))
|
||||
if (!new_code || length(new_code) != 4 || !ishex(new_code))
|
||||
usr << output("ERR!&0", "ship_lock.browser:updateReadout")
|
||||
else
|
||||
code = new_code
|
||||
configure_mode = 0
|
||||
usr << output("SET!&0", "ship_lock.browser:updateReadout")
|
||||
//if (ship)
|
||||
// ship.access_computer(usr)
|
||||
|
||||
else
|
||||
if (uppertext(href_list["enter"]) == src.code)
|
||||
usr << output("!OK!&0", "ship_lock.browser:updateReadout")
|
||||
if (ship)
|
||||
ship.locked = 0
|
||||
boutput(usr, "<span style=\"color:red\">The lock mechanism clicks unlocked.</span>")
|
||||
// ship.access_computer(usr)
|
||||
else
|
||||
usr << output("ERR!&0", "ship_lock.browser:updateReadout")
|
||||
var/code_attempt = uppertext(ckey(href_list["enter"]))
|
||||
if (length(code_attempt) == 4)
|
||||
var/oldcode = code
|
||||
var/i = 0
|
||||
var/incode = 0
|
||||
var/rightplace = 0
|
||||
while (++i < 5)
|
||||
if (copytext(code_attempt, i,i+1) == copytext(oldcode, 1,2))
|
||||
rightplace++
|
||||
incode++
|
||||
oldcode = copytext(oldcode,2)
|
||||
continue
|
||||
|
||||
var/foundpoint = findtext(oldcode, copytext(code_attempt,i,i+1))
|
||||
if (foundpoint)
|
||||
incode++
|
||||
oldcode = copytext(oldcode, 1,foundpoint) + copytext(oldcode, foundpoint+1)
|
||||
|
||||
var/desctext = ""
|
||||
switch(rightplace)
|
||||
if (1)
|
||||
desctext += "a short beep"
|
||||
if (2)
|
||||
desctext += "a pair of short beeps"
|
||||
if (3)
|
||||
desctext += "a trio of short beeps"
|
||||
|
||||
if (desctext && (incode - rightplace) > 0)
|
||||
desctext += " and "
|
||||
|
||||
switch(incode - rightplace)
|
||||
if (1)
|
||||
desctext += "a short boop"
|
||||
if (2)
|
||||
desctext += "two warbly boops"
|
||||
if (3)
|
||||
desctext += "a quick three boops"
|
||||
if (4)
|
||||
desctext += "a rather long boop"
|
||||
|
||||
if (desctext)
|
||||
boutput(usr, "<span style=\"color:red\">The lock panel emits [desctext].</span>")
|
||||
|
||||
else if (href_list["lock"])
|
||||
if (usr.loc != src.ship)
|
||||
boutput(usr, "<span style=\"color:red\">You must be inside the ship to do that!</span>")
|
||||
return
|
||||
|
||||
if (ship && !ship.locked)
|
||||
ship.locked = 1
|
||||
boutput(usr, "<span style=\"color:red\">The lock mechanism clunks locked.</span>")
|
||||
//ship.access_computer(usr)
|
||||
|
||||
else if (href_list["unlock"])
|
||||
if (usr.loc != src.ship)
|
||||
boutput(usr, "<span style=\"color:red\">You must be inside the ship to do that!</span>")
|
||||
return
|
||||
|
||||
if (ship && ship.locked)
|
||||
ship.locked = 0
|
||||
boutput(usr, "<span style=\"color:red\">The ship mechanism clicks unlocked.</span>")
|
||||
//ship.access_computer(usr)
|
||||
|
||||
else if (href_list["setcode"])
|
||||
if (usr.loc != src.ship)
|
||||
boutput(usr, "<span style=\"color:red\">You must be inside the ship to do that!</span>")
|
||||
return
|
||||
|
||||
src.configure_mode = 1
|
||||
if (src.ship)
|
||||
src.ship.locked = 0
|
||||
src.code = ""
|
||||
|
||||
boutput(usr, "Code reset. Please type new code and press enter.")
|
||||
show_lock_panel(usr)
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/crash
|
||||
name = "Syndicate Explosive Entry Device"
|
||||
desc = "The SEED that when explosively planted in a space station, lets you grow into the best death blossom you can be."
|
||||
f_active = 1
|
||||
power_used = 0
|
||||
var/crashable = 0
|
||||
var/crashhits = 8
|
||||
var/in_bump = 0
|
||||
hud_state = "seed"
|
||||
|
||||
Use(mob/user as mob)
|
||||
activate()
|
||||
return
|
||||
|
||||
deactivate()
|
||||
crashable = 0
|
||||
return
|
||||
|
||||
activate()
|
||||
if (crashable == 0) // To avoid spam. SEEDs can't be deactivated (Convair880).
|
||||
logTheThing("vehicle", usr, null, "activates a SEED, turning [src.ship] into a flying bomb at [log_loc(src.ship)]. Direction: [dir2text(src.ship.dir)].")
|
||||
crashable = 1
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/crash/proc/dispense()
|
||||
for (var/mob/living/B in ship.contents)
|
||||
boutput(B, "<span style=\"color:red\">You eject!</span>")
|
||||
ship.visible_message("<span style=\"color:red\">[B] launches out of the [ship]!</span>")
|
||||
step(B,ship.dir,0)
|
||||
step(B,ship.dir,0)
|
||||
step(B,ship.dir,0)
|
||||
step_rand(B, 0)
|
||||
B.remove_shipcrewmember_powers(ship.weapon_class)
|
||||
qdel(ship)
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/crash/proc/crashtime(atom/A)
|
||||
var/tempstate = ship.icon_state
|
||||
ship.icon_state = "flaming"
|
||||
A.meteorhit(ship)
|
||||
playsound(ship.loc, "sound/misc/meteorimpact.ogg", 40, 1)
|
||||
ship.icon_state = tempstate
|
||||
crashhits --
|
||||
if (crashhits <= 0)
|
||||
explosion(ship, ship.loc, 1, 2, 2, 3)
|
||||
playsound(ship.loc, "explosion", 50, 1)
|
||||
dispense()
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/secondary_system/crash/proc/crashtime2(atom/A as mob|obj|turf)
|
||||
if (in_bump)
|
||||
return
|
||||
if (A == ship.pilot)
|
||||
return
|
||||
walk(src, 0)
|
||||
in_bump = 1
|
||||
crashhits--
|
||||
if(isturf(A))
|
||||
if((istype(A, /turf/simulated/wall/r_wall) || istype(A, /turf/simulated/wall/auto/reinforced)) && prob(40))
|
||||
in_bump = 0
|
||||
return
|
||||
if(istype(A, /turf/simulated/wall))
|
||||
var/turf/simulated/wall/T = A
|
||||
T.dismantle_wall(1)
|
||||
playsound(src.loc, "sound/misc/meteorimpact.ogg", 40, 1)
|
||||
playsound(src, "sound/misc/meteorimpact.ogg", 40, 1)
|
||||
boutput(ship.pilot, "<span style=\"color:red\"><B>You crash through the wall!</B></span>")
|
||||
in_bump = 0
|
||||
if(istype(A, /turf/simulated/floor))
|
||||
qdel(A)
|
||||
if(ismob(A))
|
||||
var/mob/M = A
|
||||
boutput(ship.pilot, "<span style=\"color:red\"><B>You crash into [M]!</B></span>")
|
||||
shake_camera(M, 8, 3)
|
||||
boutput(M, "<span style=\"color:red\"><B>The [src] crashes into [M]!</B></span>")
|
||||
M.stunned = 8
|
||||
M.weakened = 5
|
||||
var/turf/target = get_edge_target_turf(ship, ship.dir)
|
||||
spawn(0)
|
||||
M.throw_at(target, 4, 2)
|
||||
playsound(src.loc, "sound/misc/meteorimpact.ogg", 40, 1)
|
||||
playsound(src, "sound/misc/meteorimpact.ogg", 40, 1)
|
||||
in_bump = 0
|
||||
if(isobj(A))
|
||||
var/obj/O = A
|
||||
if(O.density)
|
||||
boutput(ship.pilot, "<span style=\"color:red\"><B>You crash into [O]!</B></span>")
|
||||
boutput(O, "<span style=\"color:red\"><B>[ship] crashes into you!</B></span>")
|
||||
var/turf/target = get_edge_target_turf(ship, ship.dir)
|
||||
playsound(src.loc, "sound/misc/meteorimpact.ogg", 40, 1)
|
||||
playsound(src, "sound/misc/meteorimpact.ogg", 40, 1)
|
||||
O.throw_at(target, 4, 2)
|
||||
O.anchored = 0
|
||||
if (istype(O, /obj/machinery/vehicle))
|
||||
A.meteorhit(src)
|
||||
crashhits -= 3
|
||||
if (istype(O, /obj/rack) || istype(O, /obj/table))
|
||||
A.meteorhit(src)
|
||||
if (istype(O, /obj/storage/closet) || istype(O, /obj/storage/secure/closet))
|
||||
O:dump_contents()
|
||||
qdel(O)
|
||||
if (istype(O, /obj/window) || istype(O, /obj/grille) || istype(O, /obj/machinery/door) || istype(O, /obj/structure/girder) || istype(O, /obj/foamedmetal))
|
||||
qdel(O)
|
||||
if (istype(O, /obj/critter))
|
||||
O:CritterDeath()
|
||||
in_bump = 0
|
||||
if (crashhits <= 0)
|
||||
explosion(ship, ship.loc, 1, 2, 2, 3)
|
||||
playsound(ship.loc, "explosion", 50, 1)
|
||||
dispense()
|
||||
in_bump = 0
|
||||
return
|
||||
@@ -0,0 +1,134 @@
|
||||
/obj/item/shipcomponent/sensor
|
||||
name = "Standard Sensor System"
|
||||
desc = "Advanced scanning system for ships."
|
||||
power_used = 20
|
||||
system = "Sensors"
|
||||
var/ships = 0
|
||||
var/list/shiplist = list()
|
||||
var/lifeforms = 0
|
||||
var/list/lifelist = list()
|
||||
var/seekrange = 30
|
||||
var/sight = SEE_SELF
|
||||
var/see_in_dark = SEE_DARK_HUMAN + 3
|
||||
var/see_invisible = 2
|
||||
var/scanning = 0
|
||||
icon_state = "sensor"
|
||||
|
||||
mob_deactivate(mob/M as mob)
|
||||
M.sight &= ~SEE_TURFS
|
||||
M.sight &= ~SEE_MOBS
|
||||
M.sight &= ~SEE_OBJS
|
||||
M.see_in_dark = initial(M.see_in_dark)
|
||||
M.see_invisible = 0
|
||||
|
||||
opencomputer(mob/user as mob)
|
||||
if(user.loc != src.ship)
|
||||
return
|
||||
user.machine = src
|
||||
|
||||
var/dat = "<TT><B>[src] Console</B><BR><HR><BR>"
|
||||
if(src.active)
|
||||
dat += {"<BR><A href='?src=\ref[src];scan=1'>Scan Area</A>"}
|
||||
dat += {"<HR><B>[ships] Ships Detected:</B><BR>"}
|
||||
if(shiplist.len)
|
||||
for(var/shipname in shiplist)
|
||||
dat += {"<HR>[shipname] | "}
|
||||
dat += {"<HR>[lifeforms] Lifeforms Detected:</B><BR>"}
|
||||
if(lifelist.len)
|
||||
for(var/lifename in lifelist)
|
||||
dat += {"[lifename] | "}
|
||||
else
|
||||
dat += {"<B><span style=\"color:red\">SYSTEM OFFLINE</span></B>"}
|
||||
user << browse(dat, "window=ship_sensor")
|
||||
onclose(user, "ship_sensor")
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
if(usr.stat || usr.restrained())
|
||||
return
|
||||
|
||||
if (usr.loc == ship)
|
||||
usr.machine = src
|
||||
|
||||
if (href_list["scan"] && !scanning)
|
||||
scan(usr)
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
for(var/mob/M in ship)
|
||||
if ((M.client && M.machine == src))
|
||||
src.opencomputer(M)
|
||||
else
|
||||
usr << browse(null, "window=ship_sensor")
|
||||
return
|
||||
return
|
||||
|
||||
proc/dir_name(var/direction)
|
||||
switch (direction)
|
||||
if (1)
|
||||
return "north"
|
||||
if (2)
|
||||
return "south"
|
||||
if (4)
|
||||
return "east"
|
||||
if (8)
|
||||
return "west"
|
||||
if (5)
|
||||
return "northeast"
|
||||
if (6)
|
||||
return "southeast"
|
||||
if (9)
|
||||
return "northwest"
|
||||
if (10)
|
||||
return "southwest"
|
||||
|
||||
proc/scan(mob/user as mob)
|
||||
scanning = 1
|
||||
lifeforms = 0
|
||||
ships = 0
|
||||
lifelist = list()
|
||||
shiplist = list()
|
||||
playsound(ship.loc, "sound/machines/signal.ogg", 50, 0)
|
||||
ship.visible_message("<b>[ship] begins a sensor sweep of the area.</b>")
|
||||
boutput(usr, "<span style=\"color:blue\">Scanning...</span>")
|
||||
sleep(30)
|
||||
boutput(usr, "<span style=\"color:blue\">Scan complete.</span>")
|
||||
for (var/mob/living/C in range(src.seekrange,ship.loc))
|
||||
if(C.stat != 2)
|
||||
lifeforms++
|
||||
lifelist += C.name
|
||||
for (var/obj/critter/C in range(src.seekrange,ship.loc))
|
||||
if(C.alive && !istype(C,/obj/critter/gunbot))
|
||||
lifeforms++
|
||||
lifelist += C.name
|
||||
for (var/obj/npc/C in range(src.seekrange,ship.loc))
|
||||
if(C.alive)
|
||||
lifeforms++
|
||||
lifelist += C.name
|
||||
for (var/obj/machinery/vehicle/V in range(src.seekrange,ship.loc))
|
||||
if(V != ship)
|
||||
ships++
|
||||
shiplist += "[V.name] [dir_name(get_dir(ship, V))]"
|
||||
for (var/obj/critter/gunbot/drone/V in range(src.seekrange,ship.loc))
|
||||
ships++
|
||||
shiplist += "[V.name] [dir_name(get_dir(ship, V))]"
|
||||
src.updateDialog()
|
||||
sleep(10)
|
||||
scanning = 0
|
||||
return
|
||||
|
||||
|
||||
/obj/item/shipcomponent/sensor/ecto
|
||||
name = "Ecto-Sensor 900"
|
||||
desc = "The number one choice for reasearchers of the supernatural."
|
||||
see_invisible = 15
|
||||
power_used = 40
|
||||
|
||||
/obj/item/shipcomponent/sensor/mining
|
||||
name = "Conclave A-1984 Sensor System"
|
||||
desc = "Advanced geological meson scanners for ships."
|
||||
sight = SEE_TURFS
|
||||
power_used = 35
|
||||
|
||||
scan(mob/user as mob)
|
||||
..()
|
||||
mining_scan(get_turf(user), user, 6)
|
||||
@@ -0,0 +1,79 @@
|
||||
///ship components have their work proc called in the vehicle's process
|
||||
/obj/item/shipcomponent
|
||||
name = "Ship Component"
|
||||
icon = 'icons/obj/ship.dmi'
|
||||
icon_state = "default"
|
||||
flags = FPRINT | TABLEPASS| CONDUCT
|
||||
var/power_used = 0 //How much of the engine's capacity the part takes up
|
||||
var/obj/machinery/vehicle/ship = null //The owner of the part
|
||||
var/active = 0 //If the part is working or not
|
||||
var/ready = 1 //Some parts need setup before full functionality
|
||||
var/component_class = 0 //determines if a part can be installed.
|
||||
var/system = "part" //what system it is, to avoid a bunch of istype checks
|
||||
|
||||
// Code to clean up a shipcomponent that is no longer in use
|
||||
/obj/item/shipcomponent/disposing()
|
||||
ship = null
|
||||
..()
|
||||
|
||||
//Code for when device needs recharging
|
||||
/obj/item/shipcomponent/proc/ready()
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/proc/toggle()
|
||||
if (active)
|
||||
deactivate()
|
||||
else
|
||||
activate()
|
||||
|
||||
//What the component does when activated
|
||||
/obj/item/shipcomponent/proc/activate()
|
||||
if(src.active == 1)
|
||||
return
|
||||
if(ship.powercapacity < (ship.powercurrent + power_used))
|
||||
for(var/mob/M in ship)
|
||||
boutput(M, "[ship.ship_message("Not enough power to activate [src]!")]")
|
||||
return
|
||||
else
|
||||
ship.powercurrent += power_used
|
||||
|
||||
src.active = 1
|
||||
for(var/mob/M in src.ship)
|
||||
boutput(M, "[ship.ship_message("[src] is coming online...")]")
|
||||
mob_activate(M)
|
||||
if (src.ship.myhud)
|
||||
src.ship.myhud.update_states()
|
||||
return
|
||||
|
||||
///Component does this constantly
|
||||
/obj/item/shipcomponent/proc/run_component()
|
||||
return
|
||||
|
||||
///What the component does when deactived
|
||||
/obj/item/shipcomponent/proc/deactivate()
|
||||
if(src.active == 0)
|
||||
return
|
||||
src.active = 0
|
||||
ship.powercurrent -= power_used
|
||||
for(var/mob/M in src.ship)
|
||||
boutput(M, "[ship.ship_message("[src] is shutting down...")]")
|
||||
mob_deactivate(M)
|
||||
src.ship.myhud.update_states()
|
||||
return
|
||||
///Handles mob entering ship
|
||||
/obj/item/shipcomponent/proc/mob_activate(mob/M as mob)
|
||||
return
|
||||
///Handles mob exiting from ship
|
||||
/obj/item/shipcomponent/proc/mob_deactivate(mob/M as mob)
|
||||
return
|
||||
//Opens the control panel for that component if it has one
|
||||
/obj/item/shipcomponent/proc/opencomputer()
|
||||
return
|
||||
|
||||
/obj/item/shipcomponent/proc/after_time(time as num)
|
||||
var/turf/T = ship.loc
|
||||
sleep(time)
|
||||
if (ship.loc == T )
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
///Warp Beacons and Wormholes
|
||||
///Used by spaceships to travel to other Z-planes
|
||||
/obj/warp_beacon
|
||||
name = "warp beacon"
|
||||
desc = "Part of an elaborate small-ship teleportation network recently deployed by Nanotrasen. Probably won't cause you to die."
|
||||
icon = 'icons/obj/ship.dmi'
|
||||
icon_state = "beacon"
|
||||
anchored = 1
|
||||
density = 1
|
||||
|
||||
// Please keep synchronizied with these lists for easy map changes:
|
||||
// /obj/machinery/door_control (door_control.dm)
|
||||
// /obj/machinery/r_door_control (door_control.dm)
|
||||
// /obj/machinery/door/poddoor/pyro (poddoor.dm)
|
||||
// /obj/machinery/door/poddoor/blast/pyro (poddoor.dm)
|
||||
// We don't need a complete copy of all hangars, though.
|
||||
// A limited-but-logical selection of beacon will suffice.
|
||||
catering
|
||||
name = "catering hangar beacon"
|
||||
arrivals
|
||||
name = "arrivals hangar beacon"
|
||||
escape
|
||||
name = "escape hangar beacon"
|
||||
mainpod1
|
||||
name = "main hangar beacon (#1)"
|
||||
mainpod2
|
||||
name = "main hangar beacon (#2)"
|
||||
engineering
|
||||
name = "engineering hangar beacon"
|
||||
security
|
||||
name = "security hangar beacon"
|
||||
medsci
|
||||
name = "medsci hangar beacon"
|
||||
research
|
||||
name = "research hangar beacon"
|
||||
medbay
|
||||
name = "medbay hangar beacon"
|
||||
qm
|
||||
name = "QM hangar beacon"
|
||||
mining
|
||||
name = "mining hangar beacon"
|
||||
miningoutpost
|
||||
name = "mining outpost beacon"
|
||||
diner
|
||||
name = "space diner beacon"
|
||||
faint
|
||||
name = "faint signal"
|
||||
|
||||
/obj/warp_portal
|
||||
name = "particularly buff portal"
|
||||
icon ='icons/obj/objects.dmi'
|
||||
icon_state = "fatportal"
|
||||
density = 0
|
||||
var/obj/target = null
|
||||
anchored = 1.0
|
||||
|
||||
|
||||
/obj/warp_portal/Bumped(mob/M as mob|obj)
|
||||
spawn(0)
|
||||
src.teleport(M)
|
||||
return
|
||||
return
|
||||
|
||||
/obj/warp_portal/HasEntered(AM as mob|obj)
|
||||
spawn(0)
|
||||
src.teleport(AM)
|
||||
return
|
||||
return
|
||||
|
||||
/obj/warp_portal/New()
|
||||
spawn(300)
|
||||
qdel(src)
|
||||
return
|
||||
return
|
||||
|
||||
/obj/warp_portal/proc/teleport(atom/movable/M as mob|obj)
|
||||
if(istype(M, /obj/effects)) //sparks don't teleport
|
||||
return
|
||||
if (M.anchored && (!istype(M,/obj/machinery/vehicle)))
|
||||
return
|
||||
if (!( src.target ))
|
||||
qdel(src)
|
||||
return
|
||||
if (istype(M, /mob))
|
||||
var/mob/T = M
|
||||
boutput(T, "<span style=\"color:red\">You are exposed to some pretty swole strange particles, this can't be good...</span>")
|
||||
if(prob(10))
|
||||
T.gib()
|
||||
T.unlock_medal("Where we're going, we won't need eyes to see", 1)
|
||||
return
|
||||
else
|
||||
T.irradiate(rand(5,25))
|
||||
if(istype(T, /mob/living/carbon/human/))
|
||||
var/mob/living/carbon/human/H = T
|
||||
if (prob(75))
|
||||
H:bioHolder:RandomEffect("bad")
|
||||
else
|
||||
H:bioHolder:RandomEffect("good")
|
||||
if (istype(M, /atom/movable))
|
||||
do_teleport(M, src.target, 1) ///You will appear adjacent to the beacon
|
||||
|
||||
|
||||
@@ -0,0 +1,580 @@
|
||||
/datum/beakerSpec
|
||||
var/list/chems = list()
|
||||
var/list/amounts = list()
|
||||
var/temp = T0C
|
||||
|
||||
proc/addChem(var/chem as text, var/amount=0)
|
||||
if(chems.Find(chem))
|
||||
removeChem(chem)
|
||||
|
||||
if(istext(amount))
|
||||
amount = text2num(amount)
|
||||
|
||||
chems.Add(chem)
|
||||
amounts[chem] = amount
|
||||
|
||||
proc/removeChem(var/chem as text)
|
||||
chems.Remove(chem)
|
||||
amounts[chem] = 0
|
||||
|
||||
proc/setTemp(var/ttemp as text)
|
||||
temp = text2num(ttemp)
|
||||
|
||||
proc/createBeaker(var/holder)
|
||||
var/obj/item/reagent_containers/glass/B = new(holder)
|
||||
|
||||
var/total = 0
|
||||
|
||||
for(var/chem in chems)
|
||||
total += amounts[chem]
|
||||
B.reagents.maximum_volume = total
|
||||
B.reagents.add_reagent(chem, amounts[chem], null, 0, 1)
|
||||
B.reagents.set_reagent_temp(temp)
|
||||
|
||||
return B
|
||||
|
||||
proc/createReagents()
|
||||
var/datum/reagents/R = new(1000)
|
||||
|
||||
var/total = 0
|
||||
for(var/chem in chems)
|
||||
total += amounts[chem]
|
||||
R.maximum_volume = total
|
||||
R.add_reagent(chem, amounts[chem], null, 0, 1)
|
||||
|
||||
return R
|
||||
|
||||
proc/toJson()
|
||||
var/first = 1
|
||||
var/json = "{\"chems\": \["
|
||||
|
||||
for(var/chem in chems)
|
||||
var amount = amounts[chem]
|
||||
|
||||
if(!first)
|
||||
json += ","
|
||||
else
|
||||
first = 0
|
||||
|
||||
json += "{\"chem\":\"[chem]\",\"amount\":[amount]}"
|
||||
|
||||
json += "],\"temp\":[temp]}"
|
||||
return json
|
||||
|
||||
/obj/machinery/chem_dispenser_admin/
|
||||
name = "chem dispenser"
|
||||
density = 1
|
||||
anchored = 1
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "dispenser"
|
||||
flags = NOSPLASH
|
||||
var/beaker = null
|
||||
|
||||
var/glass_path = /obj/item/reagent_containers/glass
|
||||
var/glass_name = "beaker"
|
||||
var/dispenser_name = "Chemical"
|
||||
var/obj/item/card/id/user_id = null
|
||||
var/datum/reagent_group_account/current_account = null
|
||||
var/list/accounts = list()
|
||||
var/list/chems1 = list()
|
||||
var/list/amounts1 = list()
|
||||
var/list/chems2 = list()
|
||||
var/list/amounts2 = list()
|
||||
var/list/chems3 = list()
|
||||
var/list/amounts3 = list()
|
||||
var/list/beakerSpecs = list()
|
||||
var/list/temps = list()
|
||||
|
||||
New()
|
||||
UnsubscribeProcess()
|
||||
|
||||
ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
qdel(src)
|
||||
return
|
||||
if(2.0)
|
||||
if (prob(50))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
blob_act(var/power)
|
||||
if (prob(power * 1.25))
|
||||
qdel(src)
|
||||
|
||||
meteorhit()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
proc/beakerSpecsToJson()
|
||||
var/first = 1
|
||||
var/json = "\["
|
||||
|
||||
for(var/datum/beakerSpec/S in beakerSpecs)
|
||||
if(!first)
|
||||
json += ","
|
||||
else
|
||||
first = 0
|
||||
|
||||
json += S.toJson()
|
||||
|
||||
json += "]"
|
||||
return json
|
||||
|
||||
Topic(href, href_list)
|
||||
switch(href_list["action"])
|
||||
if("add")
|
||||
addChem(href_list["chem"], text2num(href_list["amount"]), text2num(href_list["beaker"]))
|
||||
|
||||
usr << output(href_list["chem"] + ";" + href_list["amount"], "cheminterface.browser:addCallback")
|
||||
if("remove")
|
||||
removeChem(href_list["chem"], text2num(href_list["beaker"]))
|
||||
|
||||
if("temp")
|
||||
setTemp(href_list["temp"], text2num(href_list["beaker"]))
|
||||
|
||||
if("grenade")
|
||||
grenade(href_list["name"])
|
||||
|
||||
if("syringe")
|
||||
syringe(href_list["name"])
|
||||
|
||||
if("lbeaker")
|
||||
lbeaker(href_list["name"])
|
||||
|
||||
if("patch")
|
||||
patch(href_list["name"])
|
||||
|
||||
if("getBeakerSpecs")
|
||||
usr << output(beakerSpecsToJson(), "cheminterface.browser:loadBeakerSpecsCallback")
|
||||
|
||||
if("newBeaker")
|
||||
beakerSpecs.len++
|
||||
beakerSpecs[beakerSpecs.len] = new /datum/beakerSpec()
|
||||
|
||||
else
|
||||
usr << output("bar", "cheminterface.browser:out")
|
||||
|
||||
proc/removeChem(var/chem as text, var/beaker=1)
|
||||
if(istext(beaker))
|
||||
beaker = text2num(beaker)
|
||||
|
||||
if(beaker > beakerSpecs.len || isnull(beakerSpecs[beaker]))
|
||||
return
|
||||
|
||||
var/datum/beakerSpec/beakerSpec = beakerSpecs[beaker]
|
||||
beakerSpec.removeChem(chem)
|
||||
|
||||
proc/addChem(var/chem as text, var/amount=0, var/beaker=1)
|
||||
if(isnull(beakerSpecs[beaker]))
|
||||
beakerSpecs[beaker] = new /datum/beakerSpec()
|
||||
|
||||
var/datum/beakerSpec/beakerSpec = beakerSpecs[beaker]
|
||||
beakerSpec.addChem(chem, amount)
|
||||
|
||||
proc/setTemp(var/temp as text, var/beaker=1)
|
||||
if(isnull(beakerSpecs[beaker]))
|
||||
return
|
||||
|
||||
var/datum/beakerSpec/beakerSpec = beakerSpecs[beaker]
|
||||
beakerSpec.setTemp(temp)
|
||||
|
||||
|
||||
proc/grenade(var/name as text)
|
||||
var/obj/item/chem_grenade/adminGrenade = new /obj/item/chem_grenade(src.loc)
|
||||
|
||||
if(name == "" || isnull(name))
|
||||
adminGrenade.name = "grief grenade"
|
||||
else
|
||||
adminGrenade.name = name
|
||||
adminGrenade.desc = "This shit is dangerous."
|
||||
adminGrenade.stage = 2
|
||||
adminGrenade.icon_state = "chemg3"
|
||||
|
||||
var/total = 0
|
||||
|
||||
for(var/datum/beakerSpec/S in beakerSpecs)
|
||||
var/obj/item/reagent_containers/glass/B = S.createBeaker(adminGrenade)
|
||||
total += B.reagents.maximum_volume
|
||||
adminGrenade.beakers += B
|
||||
|
||||
adminGrenade.reagents.maximum_volume = total
|
||||
return
|
||||
|
||||
proc/syringe(var/name as text)
|
||||
var/obj/item/reagent_containers/syringe/adminSyringe = new(src.loc)
|
||||
|
||||
if(name == "" || isnull(name))
|
||||
adminSyringe.name = "An unlabeled syringe"
|
||||
else
|
||||
adminSyringe.name = name
|
||||
|
||||
var/datum/beakerSpec/S = beakerSpecs[1]
|
||||
var/datum/reagents/R = S.createReagents()
|
||||
|
||||
adminSyringe.reagents.my_atom = null
|
||||
adminSyringe.reagents.dispose()
|
||||
adminSyringe.reagents = R
|
||||
R.my_atom = adminSyringe
|
||||
return
|
||||
|
||||
proc/lbeaker(var/name as text)
|
||||
var/obj/item/reagent_containers/glass/beaker/large/adminBeaker = new(src.loc)
|
||||
|
||||
if(name == "" || isnull(name))
|
||||
adminBeaker.name = "mysterious large beaker"
|
||||
else
|
||||
adminBeaker.name = name
|
||||
|
||||
var/datum/beakerSpec/S = beakerSpecs[1]
|
||||
var/datum/reagents/R = S.createReagents()
|
||||
|
||||
adminBeaker.reagents.my_atom = null
|
||||
adminBeaker.reagents.dispose()
|
||||
adminBeaker.reagents = R
|
||||
R.my_atom = adminBeaker
|
||||
return
|
||||
|
||||
proc/patch(var/name as text)
|
||||
var/obj/item/reagent_containers/patch/adminPatch = new(src.loc)
|
||||
|
||||
if(name == "" || isnull(name))
|
||||
adminPatch.name = "An unmarked patch"
|
||||
else
|
||||
adminPatch.name = name
|
||||
|
||||
var/datum/beakerSpec/S = beakerSpecs[1]
|
||||
var/datum/reagents/R = S.createReagents()
|
||||
|
||||
adminPatch.reagents.my_atom = null
|
||||
adminPatch.reagents.dispose()
|
||||
adminPatch.reagents = R
|
||||
R.my_atom = adminPatch
|
||||
return
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
panel()
|
||||
|
||||
proc/panel()
|
||||
set background = 1
|
||||
|
||||
if(beakerSpecs.len == 0)
|
||||
beakerSpecs.len++
|
||||
beakerSpecs[beakerSpecs.len] = new /datum/beakerSpec()
|
||||
|
||||
//setup
|
||||
var/datum/tag/page/html = new
|
||||
var/datum/tag/heading/h = new (1)
|
||||
var/datum/tag/title/title = new
|
||||
html.addToBody(h)
|
||||
html.addToHead(title)
|
||||
//heading
|
||||
h.setText("Chemofabricator")
|
||||
|
||||
//container
|
||||
var/datum/tag/div/container = new
|
||||
container.addClass("container-fluid")
|
||||
html.addToBody(container)
|
||||
|
||||
//Top row with chem select and amount
|
||||
var/datum/tag/div/row = new
|
||||
row.addClass("row-fluid")
|
||||
container.addChildElement(row)
|
||||
var/datum/tag/div/span = new
|
||||
span.addClass("span8")
|
||||
row.addChildElement(span)
|
||||
var/datum/tag/select/chemSelect = new
|
||||
span.addChildElement(chemSelect)
|
||||
chemSelect.setId("chemselect")
|
||||
chemSelect.setName("chemselect")
|
||||
for(var/rtype in global.reagents_cache)
|
||||
chemSelect.addOption(rtype,rtype)
|
||||
|
||||
span = new
|
||||
var/datum/tag/input/chemAmount = new ("text")
|
||||
span.addChildElement(chemAmount)
|
||||
span.addClass("span4")
|
||||
row.addChildElement(span)
|
||||
chemAmount.setName("chemamount")
|
||||
chemAmount.setId("chemamount")
|
||||
chemAmount.setValue("10")
|
||||
|
||||
var/datum/tag/div/beakerContainer = new
|
||||
beakerContainer.addClass("container-fluid")
|
||||
html.addToBody(beakerContainer)
|
||||
beakerContainer.setId("beaker-container")
|
||||
|
||||
//Grenade button
|
||||
row = new
|
||||
row.addClass("row-fluid")
|
||||
container.addChildElement(row)
|
||||
span = new
|
||||
span.addClass("span3")
|
||||
row.addChildElement(span)
|
||||
span.innerHtml = "Name: "
|
||||
|
||||
span = new
|
||||
span.addClass("span6")
|
||||
row.addChildElement(span)
|
||||
var/datum/tag/input/name = new ("text")
|
||||
span.addChildElement(name)
|
||||
name.setId("grenadeName")
|
||||
name.setName("grenadeName")
|
||||
|
||||
row = new
|
||||
row.addClass("row-fluid")
|
||||
container.addChildElement(row)
|
||||
|
||||
span = new
|
||||
span.addClass("span3")
|
||||
row.addChildElement(span)
|
||||
var/datum/tag/button/grenade = new
|
||||
grenade.setText("Grenade")
|
||||
grenade.setId("grenadeButton")
|
||||
span.addChildElement(grenade)
|
||||
|
||||
span = new
|
||||
span.addClass("span3")
|
||||
row.addChildElement(span)
|
||||
var/datum/tag/button/syringe = new
|
||||
syringe.setText("Syringe")
|
||||
syringe.setId("syringeButton")
|
||||
span.addChildElement(syringe)
|
||||
|
||||
span = new
|
||||
span.addClass("span3")
|
||||
row.addChildElement(span)
|
||||
var/datum/tag/button/lbeaker = new
|
||||
lbeaker.setText("Large Beaker")
|
||||
lbeaker.setId("lbeakerButton")
|
||||
span.addChildElement(lbeaker)
|
||||
|
||||
span = new
|
||||
span.addClass("span3")
|
||||
row.addChildElement(span)
|
||||
var/datum/tag/button/patch = new
|
||||
patch.setText("Patch")
|
||||
patch.setId("patchButton")
|
||||
span.addChildElement(patch)
|
||||
|
||||
row = new
|
||||
row.addClass("row-fluid")
|
||||
container.addChildElement(row)
|
||||
span = new
|
||||
span.addClass("span3")
|
||||
row.addChildElement(span)
|
||||
|
||||
var/datum/tag/button/newBeaker = new
|
||||
newBeaker.setText("Add Beaker")
|
||||
newBeaker.setId("newBeaker")
|
||||
newBeaker.addClass("btn btn-default")
|
||||
span.addChildElement(newBeaker)
|
||||
|
||||
span = new
|
||||
span.addClass("span3")
|
||||
row.addChildElement(span)
|
||||
|
||||
var/datum/tag/button/refresh = new
|
||||
refresh.setText("Refresh")
|
||||
refresh.setId("refresh")
|
||||
refresh.addClass("btn btn-default")
|
||||
span.addChildElement(refresh)
|
||||
|
||||
var/datum/tag/script/controlscr = new
|
||||
|
||||
controlscr.setContent( {"
|
||||
var specs = {beakerSpecs: \[]};
|
||||
function loadBeakerSpecsCallback(spec) {
|
||||
var bspecs = $.parseJSON(spec);
|
||||
$.observable(specs).setProperty("beakerSpecs", bspecs);
|
||||
}
|
||||
|
||||
function loadBeakerSpecs() {
|
||||
window.location = '?src=\ref[src];action=getBeakerSpecs';
|
||||
}
|
||||
|
||||
function addReagentClick(event) {
|
||||
var chem = $('#chemselect').val();
|
||||
var amount = $('#chemamount').val();
|
||||
var beaker = $(event.target).data("beaker");
|
||||
window.location='?src=\ref[src];action=add;chem=' + chem + ';amount=' + amount + ';beaker=' + beaker;
|
||||
setTimeout(loadBeakerSpecs, 300);
|
||||
}
|
||||
|
||||
function removeReagentClick(event) {
|
||||
var beaker = $(event.target).data("beaker");
|
||||
var chem = $('#addedRegs' + beaker).val();
|
||||
window.location='?src=\ref[src];action=remove;chem=' + chem + ';beaker=' + beaker;
|
||||
setTimeout(loadBeakerSpecs, 300);
|
||||
}
|
||||
|
||||
function tempButtonClick(event) {
|
||||
var beaker = $(event.target).data("beaker");
|
||||
var temp = $('#temp' + beaker).val();
|
||||
window.location='?src=\ref[src];action=temp;temp=' + temp + ';beaker=' + beaker;
|
||||
setTimeout(loadBeakerSpecs, 300);
|
||||
}
|
||||
|
||||
$(function() {
|
||||
var beakerTemplate = $.templates("#beakerTemplate");
|
||||
beakerTemplate.link("#beaker-container", specs);
|
||||
|
||||
$(specs).on("propertyChange", function() {
|
||||
$('.addButton').on("click", addReagentClick);
|
||||
$('.removeButton').on("click", removeReagentClick);
|
||||
$('.tempButton').on("click", tempButtonClick);
|
||||
});
|
||||
loadBeakerSpecs();
|
||||
|
||||
$('#newBeaker').click(function() {
|
||||
window.location='?src=\ref[src];action=newBeaker';
|
||||
setTimeout(loadBeakerSpecs, 300);
|
||||
});
|
||||
|
||||
$('#refresh').click(function() {
|
||||
setTimeout(loadBeakerSpecs, 300);
|
||||
});
|
||||
|
||||
function removeReg(beaker, chem, send) {
|
||||
$('#addedRegs' + beaker).find('#reg' + beaker + '-' + chem).remove();
|
||||
if(typeof send !== 'undefined' && send)
|
||||
window.location='?src=\ref[src];action=remove;chem=' + chem + ';beaker=' + beaker;
|
||||
}
|
||||
|
||||
|
||||
$('#grenadeButton').click(function() {
|
||||
var name = $('#grenadeName').val();
|
||||
window.location='?src=\ref[src];action=grenade;name=' + name;
|
||||
});
|
||||
|
||||
|
||||
$('#syringeButton').click(function() {
|
||||
var name = $('#grenadeName').val();
|
||||
window.location='?src=\ref[src];action=syringe;name=' + name;
|
||||
});
|
||||
|
||||
|
||||
$('#lbeakerButton').click(function() {
|
||||
var name = $('#grenadeName').val();
|
||||
window.location='?src=\ref[src];action=lbeaker;name=' + name;
|
||||
});
|
||||
|
||||
|
||||
$('#patchButton').click(function() {
|
||||
var name = $('#grenadeName').val();
|
||||
window.location='?src=\ref[src];action=patch;name=' + name;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
"})
|
||||
html.addToBody(controlscr)
|
||||
|
||||
var/datum/tag/script/scr = new
|
||||
scr.setContent({"
|
||||
function out(txt) {
|
||||
//alert(txt);
|
||||
}
|
||||
function addCallback(chem, amount) {
|
||||
//alert("chem: " + chem + " amount: " + amount);
|
||||
}
|
||||
"})
|
||||
html.addToBody(scr)
|
||||
|
||||
var/datum/tag/cssinclude/bootstrap = new
|
||||
bootstrap.setHref(resource("css/bootstrap.min.css"))
|
||||
html.addToHead(bootstrap)
|
||||
|
||||
var/datum/tag/cssinclude/bootstrapResponsive = new
|
||||
bootstrapResponsive.setHref(resource("css/bootstrap-responsive.min.css"))
|
||||
html.addToHead(bootstrapResponsive)
|
||||
|
||||
var/datum/tag/scriptinclude/jquery = new
|
||||
jquery.setSrc(resource("js/jquery.min.js"))
|
||||
html.addToHead(jquery)
|
||||
|
||||
var/datum/tag/scriptinclude/jqueryMigrate = new
|
||||
jqueryMigrate.setSrc(resource("js/jquery.migrate.js"))
|
||||
html.addToHead(jqueryMigrate)
|
||||
|
||||
var/datum/tag/scriptinclude/bootstrapJs = new
|
||||
bootstrapJs.setSrc(resource("js/bootstrap.min.js"))
|
||||
html.addToBody(bootstrapJs)
|
||||
|
||||
var/datum/tag/scriptinclude/jsviews = new
|
||||
jsviews.setSrc(resource("js/jsviews.min.js"))
|
||||
html.addToBody(jsviews)
|
||||
|
||||
var/datum/tag/script/beakerTemplate = new
|
||||
beakerTemplate.setId("beakerTemplate")
|
||||
beakerTemplate.setAttribute("type", "text/x-jsrender")
|
||||
html.addToBody(beakerTemplate)
|
||||
|
||||
beakerTemplate.setContent({"
|
||||
{^{for beakerSpecs}}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<h4>Beaker {{:#index + 1}}</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span5">
|
||||
<button class="btn btn-primary addButton" id="addButton{{:#index + 1}}" data-beaker="{{:#index + 1}}">Add</button>
|
||||
<button class="btn btn-danger removeButton" id="removeButton{{:#index + 1}}" data-beaker="{{:#index + 1}}">Remove</button>
|
||||
<input type="text" name="temp{{:#index + 1}}" id="temp{{:#index + 1}}">
|
||||
<button class="btn btn-default tempButton" id="tempButton{{:#index + 1}}" data-beaker="{{:#index + 1}}">Temp</button>
|
||||
<span>{{:temp}}</span>
|
||||
</div>
|
||||
<div class="span7">
|
||||
<select multiple="multiple" id="addedRegs{{:#index + 1}}">
|
||||
{^{for chems}}
|
||||
<option value="{{:chem}}">{{:chem}}: {{:amount}}</option>
|
||||
{{/for}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/for}}
|
||||
"})
|
||||
|
||||
/*
|
||||
row = new
|
||||
row.addClass("row-fluid")
|
||||
beakerTemplate.addChildElement(row)
|
||||
span = new
|
||||
span.addClass("span12")
|
||||
row.addChildElement(span)
|
||||
h = new(4)
|
||||
h.setText("Beaker 3")
|
||||
span.addChildElement(h)
|
||||
|
||||
row = new
|
||||
row.addClass("row-fluid")
|
||||
beakerTemplate.addChildElement(row)
|
||||
|
||||
span = new
|
||||
span.addClass("span3")
|
||||
row.addChildElement(span)
|
||||
var/datum/tag/button/add3 = new
|
||||
add3.setText("Add #3")
|
||||
add3.setId("addButton3")
|
||||
span.addChildElement(add3)
|
||||
var/datum/tag/button/remove3 = new
|
||||
remove3.setText("Remove #3")
|
||||
remove3.setId("removeButton3")
|
||||
span.addChildElement(remove3)
|
||||
|
||||
span = new
|
||||
span.addClass("span9")
|
||||
row.addChildElement(span)
|
||||
var/datum/tag/select/multi/added3 = new
|
||||
added3.setId("addedRegs3")
|
||||
for(var/chem in chems3)
|
||||
var/amt = amounts3[chem]
|
||||
added3.addOption(chem, "[chem]: [amt]")
|
||||
span.addChildElement(added3)*/
|
||||
|
||||
/*var/datum/tag/firebug/fb = new
|
||||
html.addToHead(fb)*/
|
||||
|
||||
usr << browse(html.toHtml(), "window=cheminterface;size=600x600")
|
||||
@@ -0,0 +1,770 @@
|
||||
/*
|
||||
Contents:
|
||||
Skull of Souls
|
||||
Tommyize proc
|
||||
Donald Trumpet
|
||||
SpyGUI
|
||||
*/
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//The pretty darn mean skull
|
||||
//That's nice to ghosts
|
||||
// Yay
|
||||
////////////////////////////
|
||||
/obj/item/soulskull
|
||||
name = "ominous skull"
|
||||
desc = "This skull gives you the heebie-jeebies."
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "skull_ominous"
|
||||
var/being_mean = 0
|
||||
|
||||
attack_hand(mob/M)
|
||||
if(!being_mean)
|
||||
..()
|
||||
M.show_text("<B><I>It burns...!</I></B>", "red")
|
||||
if(ishuman(M)) evil_act(M)
|
||||
/* oops didn't quite think this through
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if (istype(W, /obj/item/parts/robot_parts/leg))
|
||||
var/obj/machinery/bot/skullbot/B = new /obj/machinery/bot/skullbot
|
||||
B.icon = icon('icons/obj/aibots.dmi', "skullbot-ominous")
|
||||
B.name = "ominous skullbot"
|
||||
boutput(user, "<span style=\"color:blue\">You add [W] to [src]. That's neat.</span>")
|
||||
B.set_loc(get_turf(user))
|
||||
qdel(W)
|
||||
qdel(src)
|
||||
return
|
||||
*/
|
||||
proc/evil_act(mob/living/carbon/human/H)
|
||||
|
||||
var/list/mob/dead/observer/possible_targets = list()
|
||||
var/list/mob/dead/observer/priority_targets = list()
|
||||
|
||||
|
||||
if(ticker && ticker.mode) //Yes, I'm sure my runtimes will matter if the goddamn TICKER is gone.
|
||||
for(var/datum/mind/M in (ticker.mode.Agimmicks | ticker.mode.traitors)) //We want an EVIL ghost
|
||||
if(!M.dnr && M.current && isobserver(M.current) && M.current.client && M.special_role != "vampthrall" && M.special_role != "mindslave")
|
||||
priority_targets.Add(M.current)
|
||||
|
||||
if(!priority_targets.len) //Okay, fine. Any ghost. *sigh
|
||||
for(var/mob/dead/observer/O in mobs)
|
||||
if(O && O.client && O.mind && !O.mind.dnr)
|
||||
possible_targets.Add(O)
|
||||
|
||||
|
||||
if(!priority_targets.len && !possible_targets.len) return //Gotta have a ghostie
|
||||
|
||||
being_mean = 1
|
||||
H.canmove = 0
|
||||
H.drop_item(src)
|
||||
src.set_loc(H.loc)
|
||||
src.layer = EFFECTS_LAYER_4
|
||||
playsound(src.loc, 'sound/ambience/voidfx4.ogg', 40, 1)
|
||||
spawn(0) animate_levitate(src, -1)
|
||||
H.emote("scream")
|
||||
|
||||
H.weakened = 10
|
||||
|
||||
spawn(70)
|
||||
if(!H)
|
||||
being_mean = 0
|
||||
return
|
||||
H.emote("faint")
|
||||
H.paralysis = 10
|
||||
H.show_text("<I><font size=5>You feel your mind drifting away from your body!</font></I>", "red")
|
||||
|
||||
playsound(src.loc, 'sound/effects/ghost.ogg', 50, 1)
|
||||
|
||||
if(!H.mind)
|
||||
H.ghostize()
|
||||
else
|
||||
if(priority_targets.len) //Do we have an evil ghost?
|
||||
H.mind.swap_with(pick(priority_targets))
|
||||
H.show_text("<I><B>You hear a sinister voice in your head... \"I have brought you back to do evil once more!\"</B></I>")
|
||||
else if(possible_targets.len) //Do we have a plain ol' ghost?
|
||||
H.mind.swap_with(pick(possible_targets))
|
||||
else //How the fuck did we even get here??
|
||||
H.ghostize()
|
||||
|
||||
spawn(15) playsound(src.loc, 'sound/effects/ghostlaugh.ogg', 70, 1)
|
||||
flick("skull_ominous_explode", src)
|
||||
sleep(30)
|
||||
qdel(src)
|
||||
|
||||
//////////////////////////////
|
||||
//Tommyize
|
||||
////////////////////////////
|
||||
proc/Create_Tommyname()
|
||||
return pick("Toh", "Tho", "To") + pick("mmh", "mh", "mm", "m") + pick("i", "eh", "yh", "ee", "u") + " " + pick("Wa", "Wi", "Wu", "Wee", "We") + pick("z", "zh", "se", "seh") + pick("oo", "oh", "eeh", "au", "ay", "uu", "uh")
|
||||
|
||||
/mob/proc/tommyize()
|
||||
src.transforming = 1
|
||||
src.canmove = 0
|
||||
src.invisibility = 101
|
||||
for(var/obj/item/clothing/O in src)
|
||||
src.u_equip(O)
|
||||
if (O)
|
||||
O.set_loc(src.loc)
|
||||
O.dropped(src)
|
||||
O.layer = initial(O.layer)
|
||||
|
||||
var/mob/living/carbon/human/tommy/T = new(src.loc)
|
||||
if(src.mind)
|
||||
src.mind.transfer_to(T)
|
||||
else
|
||||
T.key = src.key
|
||||
|
||||
spawn(10)
|
||||
qdel(src)
|
||||
|
||||
/mob/living/carbon/human/proc/tommyize_reshape()
|
||||
//Set up the new appearance
|
||||
var/datum/appearanceHolder/AH = new
|
||||
AH.gender = "male"
|
||||
AH.customization_first = "Dreadlocks"
|
||||
AH.gender = "male"
|
||||
AH.s_tone = -15
|
||||
AH.owner = src
|
||||
AH.parentHolder = src.bioHolder
|
||||
|
||||
src.gender = "male"
|
||||
src.real_name = Create_Tommyname()
|
||||
src.sound_list_laugh = list('sound/voice/tommy_hahahah.ogg', 'sound/voice/tommy_hahahaha.ogg')
|
||||
src.sound_list_scream = list('sound/voice/tommy_you-are-tearing-me-apart-lisauh.ogg', 'sound/voice/tommy_did-not-hit-hehr.ogg')
|
||||
src.sound_list_flap = list('sound/voice/tommy_weird-chicken-noise.ogg')
|
||||
|
||||
for(var/obj/item/clothing/O in src)
|
||||
src.u_equip(O)
|
||||
if (O)
|
||||
if(istype(O, /obj/item/clothing/shoes/black) || istype(O, /obj/item/clothing/under/suit))
|
||||
O.cant_drop = 1
|
||||
O.cant_other_remove = 1
|
||||
O.cant_self_remove = 1
|
||||
continue
|
||||
|
||||
O.set_loc(src.loc)
|
||||
O.dropped(src)
|
||||
O.layer = initial(O.layer)
|
||||
|
||||
src.equip_if_possible(new /obj/item/clothing/shoes/black {cant_drop = 1; cant_other_remove = 1; cant_self_remove = 1} (src), slot_shoes)
|
||||
src.equip_if_possible(new /obj/item/clothing/under/suit {cant_drop = 1; cant_other_remove = 1; cant_self_remove = 1} (src), slot_w_uniform)
|
||||
src.equip_if_possible(new /obj/item/football(src), slot_in_backpack)
|
||||
|
||||
src.sound_malescream = 'sound/voice/tommy_you-are-tearing-me-apart-lisauh.ogg'
|
||||
src.sound_fingersnap = 'sound/voice/tommy_did-not-hit-hehr.ogg'
|
||||
|
||||
if(src.bioHolder)
|
||||
src.bioHolder.mobAppearance = AH
|
||||
src.bioHolder.AddEffect("accent_tommy")
|
||||
spawn(10)
|
||||
src.bioHolder.mobAppearance.UpdateMob()
|
||||
|
||||
//////////////////////////////
|
||||
//Tommy gun
|
||||
////////////////////////////
|
||||
|
||||
/datum/projectile/tommy
|
||||
name = "space-tommy disruption"
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
icon_state = "random_thing"
|
||||
//How much of a punch this has, tends to be seconds/damage before any resist
|
||||
power = 10
|
||||
//How much ammo this costs
|
||||
cost = 10
|
||||
//How fast the power goes away
|
||||
dissipation_rate = 1
|
||||
//How many tiles till it starts to lose power
|
||||
dissipation_delay = 10
|
||||
//Kill/Stun ratio
|
||||
ks_ratio = 0.0
|
||||
//name of the projectile setting, used when you change a guns setting
|
||||
sname = "Tommify"
|
||||
//file location for the sound you want it to play
|
||||
shot_sound = 'sound/voice/tommy_hauh.ogg'
|
||||
//How many projectiles should be fired, each will cost the full cost
|
||||
shot_number = 1
|
||||
//What is our damage type
|
||||
damage_type = 0
|
||||
//With what % do we hit mobs laying down
|
||||
hit_ground_chance = 10
|
||||
//Can we pass windows
|
||||
window_pass = 0
|
||||
|
||||
on_hit(atom/hit)
|
||||
if(ishuman(hit))
|
||||
hit:tommyize_reshape()
|
||||
playsound(hit.loc, 'sound/voice/tommy_hey-everybody.ogg', 50, 1)
|
||||
else if(ismob(hit))
|
||||
hit:tommyize()
|
||||
playsound(hit.loc, 'sound/voice/tommy_hey-everybody.ogg', 50, 1)
|
||||
|
||||
///////////////////////////////////////Tommy Gun
|
||||
|
||||
/obj/item/gun/energy/tommy_gun
|
||||
name = "Tommy Gun"
|
||||
icon = 'icons/obj/gun.dmi'
|
||||
icon_state = "tommy1"
|
||||
m_amt = 4000
|
||||
rechargeable = 1
|
||||
force = 0.0
|
||||
desc = "It smells of cheap cologne and..."
|
||||
|
||||
New()
|
||||
cell = new/obj/item/ammo/power_cell/high_power
|
||||
current_projectile = new/datum/projectile/tommy
|
||||
projectiles = list(new/datum/projectile/tommy)
|
||||
..()
|
||||
|
||||
update_icon()
|
||||
return
|
||||
|
||||
shoot(var/target,var/start,var/mob/user,var/POX,var/POY)
|
||||
for(var/mob/O in AIviewers(user, null))
|
||||
O.show_message("<span style=\"color:red\"><B>[user] fires the [src] at [target]!</B></span>", 1, "<span style=\"color:red\">You hear a loud crackling noise.</span>", 2)
|
||||
sleep(1)
|
||||
return ..(target, start, user)
|
||||
|
||||
update_icon()
|
||||
if(cell)
|
||||
src.icon_state = "tommy[src.cell.charge > 0]"
|
||||
return
|
||||
|
||||
///////////////////////////////////////Analysis datum for the spectrometer
|
||||
|
||||
/datum/spectro_analysis
|
||||
|
||||
proc/analyze_reagents(var/datum/reagents/R, var/check_recipes = 0)
|
||||
if(R && R.reagent_list && R.reagent_list.len)
|
||||
if(check_recipes)
|
||||
. = analyze_reagent_components(R.reagent_list)
|
||||
else
|
||||
. = analyze_reagent_list(R.reagent_list)
|
||||
|
||||
|
||||
|
||||
//Analyze the recipe for each reagent id. If there's more than one id this will be a fucking mess.
|
||||
proc/analyze_reagent_components(var/list/reagent_ids)
|
||||
if(reagent_ids.len)
|
||||
var/output = list()
|
||||
for (var/id in reagent_ids)
|
||||
|
||||
var/datum/chemical_reaction/recipe = chem_reactions_by_id[id]
|
||||
if(recipe && recipe.required_reagents && recipe.required_reagents.len)
|
||||
analyze_reagent_list(recipe.required_reagents, output)
|
||||
else
|
||||
for(var/i=0, i<rand(2,7), i++) //If it doesn't have a recipe, just spit out some random data
|
||||
analyze_single(output, md5(rand(100,100000)))
|
||||
|
||||
return output
|
||||
|
||||
return null
|
||||
|
||||
//Calculates the result for every reagent ID in a list
|
||||
proc/analyze_reagent_list(var/list/reagent_ids, var/list/output)
|
||||
if(reagent_ids.len)
|
||||
if(!output) output = list()
|
||||
for(var/RID in reagent_ids)
|
||||
if(reagents_cache[RID])
|
||||
output = analyze_single(output, RID)
|
||||
else
|
||||
logTheThing("debug", null, null, "<B>SpyGuy/spectro:</B> attempted to analyze invalid reagent id: [RID]")
|
||||
|
||||
return output
|
||||
|
||||
//This is mainly a helper
|
||||
proc/analyze_single(var/list/base, var/id)
|
||||
var/hash = md5("AReally[id]ShittySalt")
|
||||
var/listPos = calc_start_point(hash)
|
||||
|
||||
for(var/i=1, i <= lentext(hash), i+=2)
|
||||
var/block = copytext(hash, i, i+2)
|
||||
if (isnull(base["[listPos]"]))
|
||||
base["[listPos]"] = hex2num(block)
|
||||
else
|
||||
base["[listPos]"] += hex2num(block)
|
||||
listPos += (hex2num(copytext(block,1,2)) + hex2num(copytext(block,2)))
|
||||
return base
|
||||
|
||||
//So is this
|
||||
proc/calc_start_point(var/hash)
|
||||
for(var/i = 1; i <= lentext(hash); i++)
|
||||
var/temp = copytext(hash, i, i+1)
|
||||
temp = hex2num(temp)
|
||||
. += temp
|
||||
|
||||
. = round(. * 1.5)
|
||||
|
||||
/////////////////////////////// Trigger
|
||||
|
||||
/obj/trigger
|
||||
name = "trigger"
|
||||
desc = "warning"
|
||||
icon = 'icons/mob/screen1.dmi'
|
||||
icon_state = "x2"
|
||||
anchored = 1
|
||||
invisibility = 101
|
||||
|
||||
HasEntered(atom/movable/AM)
|
||||
..()
|
||||
on_trigger(AM)
|
||||
|
||||
proc/on_trigger(var/atom/movable/triggerer)
|
||||
|
||||
|
||||
/obj/trigger/critter //Wakes up all critters in an area
|
||||
name = "critter trigger"
|
||||
var/area/assigned_area = null
|
||||
|
||||
on_trigger(atom/movable/triggerer)
|
||||
if(isliving(triggerer) || locate(/mob) in triggerer)
|
||||
if(!assigned_area) assigned_area = get_area(src)
|
||||
assigned_area.wake_critters()
|
||||
|
||||
/obj/trigger/throw
|
||||
name = "throw trigger"
|
||||
var/throw_dir = NORTH
|
||||
|
||||
on_trigger(var/atom/movable/triggerer)
|
||||
if(isobserver(triggerer)) return
|
||||
var/atom/target = get_edge_target_turf(src, src.throw_dir)
|
||||
spawn(0)
|
||||
if (target)
|
||||
triggerer.throw_at(target, 50, 1)
|
||||
|
||||
|
||||
////////////////////////////// Donald Trumpet
|
||||
/datum/projectile/energy_bolt_v/trumpet
|
||||
name = "trumpet bolt"
|
||||
shot_sound = 'sound/items/dootdoot.ogg'
|
||||
|
||||
on_hit(atom/hit)
|
||||
..()
|
||||
|
||||
if(ishuman(hit))
|
||||
var/mob/living/carbon/human/H = hit
|
||||
if(!istype(H.head, /obj/item/clothing/head/wig))
|
||||
var/obj/item/clothing/head/wig/W = H.create_wig()
|
||||
H.bioHolder.mobAppearance.customization_first = "None"
|
||||
H.cust_one_state = customization_styles["None"]
|
||||
H.drop_from_slot(H.head)
|
||||
H.force_equip(W, H.slot_head)
|
||||
H.set_clothing_icon_dirty()
|
||||
|
||||
/obj/item/gun/energy/dtrumpet
|
||||
name = "Donald Trumpet"
|
||||
desc = "You can tell this gun has been fired!"
|
||||
icon = 'icons/obj/instruments.dmi'
|
||||
icon_state = "trumpet"
|
||||
New()
|
||||
cell = new/obj/item/ammo/power_cell/high_power
|
||||
current_projectile = new/datum/projectile/energy_bolt_v/trumpet
|
||||
projectiles = list(new/datum/projectile/energy_bolt_v/trumpet)
|
||||
..()
|
||||
|
||||
////////////////////////////// Power machine
|
||||
/obj/machinery/power/debug_generator
|
||||
name = "mysterious petrol generator"
|
||||
desc = "Holds untold powers. Literally. Untold power. Get it? Power. Watts? Ok, fine. This thing spits out unlimited watt-volts!! There. I said it!"
|
||||
icon_state = "ggenoff"
|
||||
density = 1
|
||||
var/generating = 0
|
||||
New()
|
||||
..()
|
||||
//UnsubscribeProcess()
|
||||
attack_hand(mob/user)
|
||||
if(!user) return
|
||||
generating = (input("Select the amount of power this machine should generate (in MW))", "Playing with power") as num) * 1e6
|
||||
if(generating > 0)
|
||||
SubscribeToProcess()
|
||||
icon_state = "ggenoff"
|
||||
else
|
||||
UnsubscribeProcess()
|
||||
icon_state = "ggen"
|
||||
|
||||
process()
|
||||
..()
|
||||
if(!generating) UnsubscribeProcess()
|
||||
add_avail(generating)
|
||||
|
||||
////////////////////////////// Spy GUI (ha ha ha ha)
|
||||
/datum/spyGUI
|
||||
var/target_file = null
|
||||
var/desired_file = ""
|
||||
var/target_window = ""
|
||||
var/target_params = ""
|
||||
var/list/mob/subscribed_mobs = new
|
||||
var/list/mob/connecting = new
|
||||
var/datum/master = null
|
||||
|
||||
var/max_retries = 5
|
||||
var/time_per_try = 2
|
||||
|
||||
var/validate_user = 0
|
||||
|
||||
New(var/filename, var/windowname, var/parameters, var/datum/master)
|
||||
..()
|
||||
target_window = windowname
|
||||
target_params = parameters
|
||||
target_file = grabResource(filename)
|
||||
desired_file = filename
|
||||
src.master = master
|
||||
|
||||
proc/getFile()
|
||||
if(!target_file)
|
||||
target_file = grabResource(desired_file)
|
||||
return target_file
|
||||
|
||||
|
||||
proc/displayInterface(var/mob/target, var/initData)
|
||||
if((target in connecting))
|
||||
return
|
||||
connecting[target] = initData
|
||||
var/retries = max_retries
|
||||
var/extrasleep = 0
|
||||
target << browse(getFile(), "window=[target_window];[target_params]")
|
||||
onclose(target, target_window, src)
|
||||
|
||||
do
|
||||
if(winexists(target, "[target_window].browser")) //Fuck if I know
|
||||
target << output("\ref[src]", "[target_window].browser:setRef")
|
||||
sleep(time_per_try + extrasleep++)
|
||||
while(retries-- > 0 && target in connecting) //Keep trying to send the UI update until it times out or they get it.
|
||||
|
||||
if(target in connecting)
|
||||
connecting -= target
|
||||
target << browse(null, target_window)
|
||||
|
||||
proc/unsubscribeTarget(var/mob/target, close=1)
|
||||
if(close)
|
||||
target << browse(null, target_window)
|
||||
subscribed_mobs -= target
|
||||
|
||||
|
||||
Topic(href, href_list)
|
||||
..()
|
||||
DEBUG("Received: [href]")
|
||||
if (href_list["ackref"] )
|
||||
var/D = connecting[usr]
|
||||
if(D)
|
||||
connecting -= usr
|
||||
subscribed_mobs |= usr
|
||||
sendData(usr, D, "setUIState")
|
||||
return
|
||||
if (href_list["close"])
|
||||
subscribed_mobs -= usr
|
||||
|
||||
|
||||
if(master != src)
|
||||
master.Topic(href, href_list) //Pass the href on
|
||||
|
||||
proc/validateSubscriber(var/mob/sub)
|
||||
if(!sub.client) //If the subscriber lacks a client then rip they
|
||||
return 0
|
||||
|
||||
if(!validate_user)
|
||||
return 1
|
||||
|
||||
. = 1
|
||||
if(sub.stat) . = 0 //Not dead / unconscious
|
||||
if ( . && istype(master, /atom)) //Range check.
|
||||
. = (sub in range(1, master))
|
||||
|
||||
proc/sendToSubscribers(var/data, var/handler)
|
||||
DEBUG("Sending: [data] to [handler ? handler : "-nothing-"]")
|
||||
for(var/mob/M in subscribed_mobs)
|
||||
if(validateSubscriber(M))
|
||||
sendData(M, data, handler)
|
||||
else
|
||||
unsubscribeTarget(M)
|
||||
|
||||
proc/sendData(var/mob/target, var/data, var/handler)
|
||||
var/list/L = new
|
||||
L += handler
|
||||
L += data
|
||||
var/O = list2params(L)
|
||||
target << output(O, "[target_window].browser:receiveData")
|
||||
|
||||
|
||||
|
||||
#define STAT_STANDBY 0
|
||||
#define STAT_MOVING 1
|
||||
#define STAT_EXTENDED 2
|
||||
|
||||
#define DEFAULT_ANIMATION_TIME 10
|
||||
////////////////////////////// Solar Panel thingamajig
|
||||
/obj/solar_control
|
||||
name = "solar panel servo"
|
||||
desc = "This machine contains a neatly-folded solar panel, for use when the ship is at little risk of external impacts and low on power."
|
||||
//invisibility = 100
|
||||
icon = 'icons/obj/machines/nuclear.dmi'
|
||||
icon_state = "engineoff"
|
||||
var/extension_dir = WEST
|
||||
var/num_panels = 4
|
||||
var/panel_width = 2
|
||||
var/panel_length = 5
|
||||
var/panel_space = 1
|
||||
var/controller_padding = 1
|
||||
var/station_padding = 2
|
||||
|
||||
var/status = 0
|
||||
|
||||
var/list/atom/created_atoms = list()
|
||||
|
||||
//TODO:
|
||||
//Pooling and reuse of components
|
||||
|
||||
////Debug verbs
|
||||
/obj/solar_control/verb/extend()
|
||||
set src in range(1)
|
||||
set category = "Local"
|
||||
extend_panel()
|
||||
|
||||
/obj/solar_control/verb/retract()
|
||||
set src in range(1)
|
||||
set category = "Local"
|
||||
retract_panel()
|
||||
|
||||
/obj/solar_control/proc/extend_panel()
|
||||
if(status != STAT_STANDBY) return
|
||||
icon_state = "engineon"
|
||||
status = STAT_MOVING
|
||||
var/paneldir1 = turn(extension_dir, 90)
|
||||
var/paneldir2 = turn(extension_dir, -90)
|
||||
var/list/turf/panelturfs = list()
|
||||
var/turf/walker = get_turf(src)
|
||||
DEBUG("Extending panel at [showCoords(src.x, src.y, src.z)]. extension_dir: [extension_dir] ([dir2text(extension_dir)]), paneldir1: [paneldir1] ([dir2text(paneldir1)]), paneldir2: [paneldir2] ([dir2text(paneldir2)])")
|
||||
var/total_len = station_padding + controller_padding + (panel_space * (num_panels -1)) + num_panels * panel_width
|
||||
DEBUG("Determined total length of panel to be [total_len] tiles.")
|
||||
|
||||
//Create the initial padding
|
||||
DEBUG("Creating stationside padding.")
|
||||
var/list/catwalk = list(/turf/simulated/floor/plating/airless/catwalk, /obj/grille/catwalk)
|
||||
for(var/i = 0; i < station_padding;i++)
|
||||
move_create_obj(catwalk, walker, extension_dir, extension_dir) //Then we walk outwards, creating stuff as we go along
|
||||
walker = get_step(walker,extension_dir)
|
||||
/*
|
||||
if(i == 0)
|
||||
spawn(0)
|
||||
move_create_obj(list(new /obj/lattice{icon_state="lattice-dir-b"}), walker, paneldir1, paneldir2 | extension_dir)
|
||||
move_create_obj(list(new /obj/lattice{icon_state="lattice-dir-b"}), walker, paneldir2, paneldir1 | turn(extension_dir, 180))
|
||||
*/
|
||||
|
||||
DEBUG("Creating panel segments.")
|
||||
//Create the panels themselves
|
||||
for(var/i = 0; i < num_panels; i++)
|
||||
for(var/j = 0; j < (panel_space + panel_width);j++)
|
||||
move_create_obj(catwalk, walker, extension_dir, (j >= panel_space) ? paneldir1 : extension_dir)
|
||||
walker = get_step(walker, extension_dir)
|
||||
if(j >= panel_space) panelturfs += walker
|
||||
|
||||
DEBUG("Creating controller padding")
|
||||
for(var/i = 0; i < controller_padding; i++)
|
||||
move_create_obj(catwalk, walker, extension_dir, extension_dir) //Then we walk outwards, creating stuff as we go along
|
||||
walker = get_step(walker,extension_dir)
|
||||
|
||||
|
||||
DEBUG("Creating solar panels")
|
||||
var/list/solar_list = list(/turf/simulated/floor/airless/solar, /obj/machinery/power/solar)
|
||||
for(var/turf/T in panelturfs)
|
||||
spawn(0)
|
||||
var/turf/w1 = T
|
||||
var/turf/w2 = T
|
||||
for(var/i = 0; i < panel_length; i++)
|
||||
spawn(-1)
|
||||
move_create_obj(solar_list, w1, paneldir1, paneldir1)
|
||||
w1 = get_step(w1, paneldir1)
|
||||
move_create_obj(solar_list, w2, paneldir2, paneldir2)
|
||||
w2 = get_step(w2, paneldir2)
|
||||
|
||||
DEBUG("Creating solar controller")
|
||||
move_create_obj(list(/turf/simulated/floor/plating/airless, /obj/machinery/power/tracker), walker, extension_dir)
|
||||
walker = get_step(walker,extension_dir)
|
||||
spawn(0) move_create_obj(list(new /obj/lattice{icon_state="lattice-dir-b"}), walker, paneldir1, paneldir2)
|
||||
move_create_obj(list(new /obj/lattice{icon_state="lattice-dir-b"}), walker, paneldir2, paneldir1)
|
||||
|
||||
status = STAT_EXTENDED
|
||||
icon_state = "engineoff"
|
||||
|
||||
/obj/solar_control/proc/retract_panel()
|
||||
if(status != STAT_EXTENDED) return
|
||||
status = STAT_MOVING
|
||||
|
||||
var/list/atom/panels = get_panels()
|
||||
|
||||
for(var/i = panels.len; i > 0; i--)
|
||||
var/list/atom/L = panels[i]
|
||||
for(var/atom/A in L)
|
||||
spawn(0)
|
||||
move_and_delete_object(A)
|
||||
sleep(DEFAULT_ANIMATION_TIME)
|
||||
|
||||
while(created_atoms.len > 0)
|
||||
var/atom/A = created_atoms[created_atoms.len]
|
||||
created_atoms.len--
|
||||
if(istype(A, /turf))
|
||||
var/turf/T = A
|
||||
T.ReplaceWithSpace()
|
||||
else if(istype(A,/obj))
|
||||
move_and_delete_object(A)
|
||||
|
||||
|
||||
status = STAT_STANDBY
|
||||
|
||||
|
||||
/obj/solar_control/proc/get_panels()
|
||||
var/list/atom/out = list()
|
||||
var/list/atom/temp
|
||||
|
||||
out.len = panel_length //A list containing all the solar panels sorted on distance from centreline
|
||||
for(var/i = created_atoms.len; i > 0; i--)
|
||||
var/atom/A = created_atoms[i]
|
||||
if(istype(A, /obj/machinery/power/solar) || istype(A, /turf/simulated/floor/airless/solar))
|
||||
var/dist = get_dist_from_centreline(A)
|
||||
temp = out[dist]
|
||||
if(!temp)
|
||||
temp = list()
|
||||
out[dist] = temp
|
||||
temp += A
|
||||
|
||||
return out
|
||||
|
||||
/obj/solar_control/proc/move_and_delete_object(var/obj/O, var/animtime = DEFAULT_ANIMATION_TIME)
|
||||
//calculate new px / py
|
||||
if(istype(O, /turf))
|
||||
var/turf/T = O
|
||||
var/obj/movedummy/MD = unpool(/obj/movedummy)
|
||||
MD.mimic_turf(T.type, 0)
|
||||
MD.set_loc(T)
|
||||
T.ReplaceWithSpace()
|
||||
O = MD
|
||||
|
||||
var/tdir = get_reciprocal(O)
|
||||
var/npx = 0
|
||||
if(tdir & (EAST | WEST))
|
||||
if(tdir & WEST)
|
||||
npx = -32
|
||||
else if(tdir & EAST)
|
||||
npx = 32
|
||||
var/npy = 0
|
||||
if(tdir & (NORTH | SOUTH))
|
||||
if(tdir & NORTH)
|
||||
npy = 32
|
||||
else if (tdir & SOUTH)
|
||||
npy = -32
|
||||
|
||||
animate_slide(O, npx, npy, animtime)
|
||||
sleep(animtime)
|
||||
if(istype(O, /obj/movedummy))
|
||||
pool(O)
|
||||
else
|
||||
qdel(O)
|
||||
|
||||
|
||||
/obj/solar_control/proc/move_create_obj(var/list/atom/to_create, var/turf/startturf, var/movedir, var/setdir=null, var/animtime = DEFAULT_ANIMATION_TIME)
|
||||
//calculate initial px / py
|
||||
var/ipx = 0
|
||||
if(movedir & (EAST | WEST))
|
||||
if(movedir & WEST)
|
||||
ipx = 32
|
||||
else if(movedir & EAST)
|
||||
ipx = -32
|
||||
var/ipy = 0
|
||||
if(movedir & (NORTH | SOUTH))
|
||||
if(movedir & NORTH)
|
||||
ipy = -32
|
||||
else if (movedir & SOUTH)
|
||||
ipy = 32
|
||||
|
||||
|
||||
DEBUG("Initial offsets calculated based on movedir: [movedir] ([dir2text(movedir)]) as ipx: [ipx], ipy: [ipy]")
|
||||
var/is_turf = 0
|
||||
var/turf/T = get_step(startturf, movedir)
|
||||
var/turf_type = null
|
||||
for(var/t_type in to_create)
|
||||
if(ispath(t_type, /turf))
|
||||
turf_type = t_type
|
||||
break
|
||||
spawn(0)
|
||||
for(var/t_type in to_create)
|
||||
var/obj/O
|
||||
is_turf = ispath(t_type, /turf) //If it's a turf we need some special handling.
|
||||
|
||||
if(istype(t_type, /obj))
|
||||
O = t_type
|
||||
else if(ispath(t_type))
|
||||
if(!is_turf)
|
||||
O = new t_type(null)
|
||||
else
|
||||
var/obj/movedummy/MD = unpool(/obj/movedummy)
|
||||
MD.mimic_turf(t_type, animtime)
|
||||
O = MD
|
||||
|
||||
else if(!ispath(t_type))
|
||||
CRASH("move_create_obj not provided with type")
|
||||
if(!is_turf)
|
||||
created_atoms += O
|
||||
O.pixel_x = ipx
|
||||
O.pixel_y = ipy
|
||||
if(setdir)
|
||||
O.dir = setdir
|
||||
O.set_loc(T)
|
||||
animate_slide(O, 0, 0, animtime, LINEAR_EASING)
|
||||
|
||||
playsound(T, "sound/effects/airbridge_dpl.ogg", 50, 1)
|
||||
sleep(animtime)
|
||||
if(turf_type)
|
||||
DEBUG("Creating [turf_type] at [showCoords(T.x, T.y, T.z)]")
|
||||
var/turf/NT = new turf_type(T)
|
||||
if(setdir) NT.dir = setdir
|
||||
created_atoms += NT
|
||||
|
||||
|
||||
//Helpers
|
||||
/obj/solar_control/proc/get_reciprocal(var/atom/A)
|
||||
var/d = get_dir(A,src)
|
||||
d &= ~(extension_dir | turn(extension_dir, 180)) //Turn off the bits parallell to the extension_dir
|
||||
if(!d) d = turn(extension_dir, 180) //If this wound up turning off all the bits, the dir is on the extension line
|
||||
//Look, I'm Swedish, I don't know your goddamn mathwords
|
||||
return d
|
||||
|
||||
/obj/solar_control/proc/get_dist_from_centreline(var/atom/A) //Finds the distance from the closest point on the extension line
|
||||
if(extension_dir & (NORTH|SOUTH) )
|
||||
.= abs(A.x - src.x)
|
||||
else if ( extension_dir & (EAST|WEST) )
|
||||
.= abs(A.y - src.y)
|
||||
|
||||
DEBUG("get_dist from [showCoords(A.x, A.y, A.z)] returned: [.]")
|
||||
|
||||
|
||||
//The dummy object that imitates a turf
|
||||
/obj/movedummy
|
||||
name = "Dummy object."
|
||||
invisibility = 101
|
||||
|
||||
/obj/movedummy/pooled()
|
||||
..()
|
||||
invisibility = 101
|
||||
|
||||
/obj/movedummy/proc/mimic_turf(var/turf_type, var/TTL)
|
||||
ASSERT(ispath(turf_type, /turf))
|
||||
var/turf/T = turf_type
|
||||
src.name = initial(T.name)
|
||||
src.desc = initial(T.desc)
|
||||
src.icon = initial(T.icon)
|
||||
src.icon_state = initial(T.icon_state)
|
||||
src.density = initial(T.density)
|
||||
src.opacity = initial(T.opacity)
|
||||
src.dir = initial(T.dir)
|
||||
src.layer = initial(T.layer)
|
||||
src.invisibility = 0
|
||||
if(TTL)
|
||||
spawn(TTL)
|
||||
pool(src)
|
||||
|
||||
#undef STAT_STANDBY
|
||||
#undef STAT_MOVING
|
||||
#undef STAT_EXTENDED
|
||||
#undef DEFAULT_ANIMATION_TIME
|
||||
|
||||
//Aw heck
|
||||
@@ -0,0 +1,83 @@
|
||||
var/list/areaColorList = new/list()
|
||||
// meh
|
||||
var/list/stationMap_bannedAreas = list("Space", "Wizard's Den", "Abandoned ship")
|
||||
|
||||
proc/getAreaColor(var/area/A)
|
||||
if (areaColorList.Find(A.type))
|
||||
return areaColorList[A.type]
|
||||
else
|
||||
var/newCol = rgb(rand(30, 255),rand(30, 255),rand(30, 255))
|
||||
areaColorList.Add(A.type)
|
||||
areaColorList[A.type] = newCol
|
||||
return newCol
|
||||
|
||||
var/global/icon/station_map = null
|
||||
|
||||
// now that the map is cached, maybe we can have it black out turfs that get destroyed and replaced with space?
|
||||
/proc/generateStationMap(var/obj/source)
|
||||
if (!station_map)
|
||||
station_map = icon('icons/misc/mapEmpty.dmi', "template")
|
||||
for (var/y=world.maxy, y > 0, y--)
|
||||
for (var/x=1, x<=world.maxx, x++)
|
||||
var/turf/located = locate(x,y,1)
|
||||
if (located.loc.name in stationMap_bannedAreas) //This might look like i don't know how to code but there's a reason for this, trust me.
|
||||
station_map.DrawBox(rgb(15,15,15), x,y)
|
||||
else
|
||||
station_map.DrawBox(getAreaColor(located.loc), x,y)
|
||||
|
||||
var/icon/map = new(station_map)
|
||||
var/icon/marker = icon('icons/obj/stationobjs.dmi', "youmark")
|
||||
map.Blend(marker, ICON_OVERLAY, source.x - 2, source.y - 2)
|
||||
|
||||
var/icon/overlay = icon('icons/misc/mapEmpty.dmi', "overlay")
|
||||
map.Blend(overlay, ICON_OVERLAY, 1, 1)
|
||||
|
||||
return map
|
||||
|
||||
/obj/stationMapObj
|
||||
name = "Map (Click somewhere in space to close)"
|
||||
desc = "A map of the station. Click somewhere in space on the map to close it."
|
||||
|
||||
anchored = 1
|
||||
density = 0
|
||||
opacity = 0
|
||||
layer = HUD_LAYER
|
||||
screen_loc = "CENTER-3, CENTER-3"
|
||||
|
||||
MouseUp(var/location,var/control,var/params)
|
||||
var/list/paramList = params2list(params)
|
||||
if (paramList.Find("left"))
|
||||
var/turf/clicked = locate(text2num(paramList["icon-x"]),text2num(paramList["icon-y"]),1)
|
||||
|
||||
if (clicked.loc.name in stationMap_bannedAreas)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
boutput(usr, "<span style=\"color:blue\">That is <B>[clicked.loc.name]</B>.</span>")
|
||||
/* boutput(usr, "<span style=\"color:green\"><I>[clicked.loc.desc]</I></span>") // none of these fucking things have descriptions anyway
|
||||
boutput(usr, " ") // no fuck you too
|
||||
*/
|
||||
/obj/stationMapWall
|
||||
name = "Station Map"
|
||||
desc = "A map of the station."
|
||||
|
||||
layer = EFFECTS_LAYER_BASE
|
||||
anchored = 1
|
||||
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "stationmap"
|
||||
|
||||
Click()
|
||||
if (..(usr))
|
||||
return
|
||||
|
||||
if (locate(/obj/stationMapObj) in usr) return
|
||||
|
||||
var/icon/mapIcon = generateStationMap(usr)
|
||||
var/obj/stationMapObj/S = new/obj/stationMapObj(usr)
|
||||
|
||||
S.icon = mapIcon
|
||||
S.icon_state = "template"
|
||||
|
||||
usr.client.screen += S
|
||||
return
|
||||
@@ -0,0 +1,736 @@
|
||||
//node1, air1, network1 correspond to input
|
||||
//node2, air2, network2 correspond to output
|
||||
//
|
||||
/obj/machinery/atmospherics/binary/circulatorTemp
|
||||
name = "hot gas circulator"
|
||||
desc = "It's the gas circulator of a thermoeletric generator."
|
||||
icon = 'icons/obj/atmospherics/pipes.dmi'
|
||||
icon_state = "circ1-off"
|
||||
|
||||
var/side = 1 // 1=left 2=right
|
||||
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()
|
||||
|
||||
//Calculate necessary moles to transfer using PV = nRT
|
||||
var/pressure_delta = abs((input_starting_pressure - output_starting_pressure))/2
|
||||
|
||||
var/transfer_moles = pressure_delta*air2.volume/max((air1.temperature * R_IDEAL_GAS_EQUATION), 1) //Stop annoying runtime errors
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
/obj/machinery/atmospherics/binary/circulatorTemp/right
|
||||
side = 2
|
||||
icon_state = "circ2-off"
|
||||
name = "cold gas circulator"
|
||||
|
||||
/obj/machinery/power/monitor
|
||||
name = "Power Monitoring Computer"
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
icon_state = "power"
|
||||
density = 1
|
||||
anchored = 1
|
||||
|
||||
/obj/machinery/power/generatorTemp
|
||||
name = "generator"
|
||||
desc = "A high efficiency thermoelectric generator."
|
||||
icon_state = "teg"
|
||||
anchored = 1
|
||||
density = 1
|
||||
//var/lightsbusted = 0
|
||||
|
||||
var/obj/machinery/atmospherics/binary/circulatorTemp/circ1
|
||||
var/obj/machinery/atmospherics/binary/circulatorTemp/right/circ2
|
||||
|
||||
var/lastgen = 0
|
||||
var/lastgenlev = -1
|
||||
var/overloaded = 0
|
||||
var/running = 0
|
||||
var/spam_limiter = 0 // stop the lights and icon updates from spazzing out as much at the threshold between power tiers
|
||||
var/efficiency_controller = 52 // cogwerks - debugging/testing var
|
||||
var/datum/light/light
|
||||
|
||||
var/boost = 0
|
||||
|
||||
var/grump = 0 // best var 2013
|
||||
var/grumping = 0 // is the engine currently doing grumpy things
|
||||
|
||||
var/list/grump_prefix = list("an upsetting", "an unsettling",
|
||||
"a scary", "a loud", "a sassy", "a grouchy", "a grumpy",
|
||||
"an awful", "a horrible", "a despicable", "a pretty rad", "a godawful")
|
||||
|
||||
var/list/grump_suffix = list("noise", "racket", "ruckus", "sound", "clatter", "fracas", "hubbub")
|
||||
|
||||
var/sound_engine1 = 'sound/machines/tractor_running.ogg'
|
||||
var/sound_engine2 = 'sound/machines/engine_highpower.ogg'
|
||||
var/sound_tractorrev = 'sound/machines/tractorrev.ogg'
|
||||
var/sound_engine_alert1 = 'sound/machines/engine_alert1.ogg'
|
||||
var/sound_engine_alert2 = 'sound/machines/engine_alert2.ogg'
|
||||
var/sound_engine_alert3 = 'sound/machines/engine_alert3.ogg'
|
||||
var/sound_bigzap = 'sound/effects/elec_bigzap.ogg'
|
||||
var/sound_bellalert = 'sound/machines/bellalert.ogg'
|
||||
var/sound_warningbuzzer = 'sound/machines/warning-buzzer.ogg'
|
||||
|
||||
New()
|
||||
..()
|
||||
|
||||
light = new /datum/light/point
|
||||
light.attach(src)
|
||||
|
||||
spawn(5)
|
||||
circ1 = locate(/obj/machinery/atmospherics/binary/circulatorTemp) in get_step(src,WEST)
|
||||
circ2 = locate(/obj/machinery/atmospherics/binary/circulatorTemp/right) in get_step(src,EAST)
|
||||
if(!circ1 || !circ2)
|
||||
stat |= BROKEN
|
||||
|
||||
updateicon()
|
||||
|
||||
proc/updateicon()
|
||||
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
overlays = null
|
||||
else
|
||||
overlays = null
|
||||
|
||||
if(lastgenlev != 0)
|
||||
overlays += image('icons/obj/power.dmi', "teg-op[lastgenlev]")
|
||||
|
||||
switch (lastgenlev)
|
||||
if(0)
|
||||
light.disable()
|
||||
if(1 to 11)
|
||||
light.set_color(1, 1, 1)
|
||||
light.set_brightness(0.3)
|
||||
if(12 to 15)
|
||||
light.set_color(0.30,0.30,0.90)
|
||||
light.set_brightness(0.6)
|
||||
light.enable()
|
||||
if(16 to 17)
|
||||
light.set_color(0.90,0.90,0.10)
|
||||
light.set_brightness(0.6)
|
||||
light.enable()
|
||||
if(18 to 22)
|
||||
playsound(src.loc, "sound/effects/elec_bzzz.ogg", 50,0)
|
||||
light.set_color(0.90,0.10,0.10)
|
||||
light.set_brightness(0.6)
|
||||
light.enable()
|
||||
if(18 to 25)
|
||||
playsound(src.loc, "sound/effects/elec_bigzap.ogg", 50,0)
|
||||
light.set_color(0.90,0.10,0.10)
|
||||
light.set_brightness(1)
|
||||
light.enable()
|
||||
if(26 to INFINITY)
|
||||
playsound(src.loc, "sound/effects/electric_shock.ogg", 50,0)
|
||||
light.set_color(0.90,0.00,0.90)
|
||||
light.set_brightness(1.5)
|
||||
light.enable()
|
||||
// this needs a safer lightbust proc
|
||||
|
||||
process()
|
||||
if(!circ1 || !circ2)
|
||||
return
|
||||
|
||||
var/datum/gas_mixture/hot_air = circ1.return_transfer_air()
|
||||
var/datum/gas_mixture/cold_air = circ2.return_transfer_air()
|
||||
|
||||
lastgen = 0
|
||||
|
||||
if(cold_air && hot_air)
|
||||
var/cold_air_heat_capacity = cold_air.heat_capacity()
|
||||
var/hot_air_heat_capacity = hot_air.heat_capacity()
|
||||
|
||||
var/delta_temperature = hot_air.temperature - cold_air.temperature
|
||||
|
||||
// uncomment to debug
|
||||
// logTheThing("debug", null, null, "pre delta, cold temp = [cold_air.temperature], hot temp = [hot_air.temperature]")
|
||||
// logTheThing("debug", null, null, "pre prod, delta : [delta_temperature], cold cap [cold_air_heat_capacity], hot cap [hot_air_heat_capacity]")
|
||||
if(delta_temperature > 0 && cold_air_heat_capacity > 0 && hot_air_heat_capacity > 0)
|
||||
var/efficiency = (1 - cold_air.temperature/hot_air.temperature) * (efficiency_controller * 0.01) //controller expressed as a percentage
|
||||
|
||||
var/energy_transfer = delta_temperature*hot_air_heat_capacity*cold_air_heat_capacity/(hot_air_heat_capacity+cold_air_heat_capacity)
|
||||
|
||||
var/heat = energy_transfer*(1-efficiency)
|
||||
lastgen = energy_transfer*efficiency
|
||||
|
||||
hot_air.temperature = hot_air.temperature - energy_transfer/hot_air_heat_capacity
|
||||
cold_air.temperature = cold_air.temperature + heat/cold_air_heat_capacity
|
||||
|
||||
// uncomment to debug
|
||||
//logTheThing("debug", null, null, "POWER: [lastgen] W generated at [efficiency*100]% efficiency and sinks sizes [cold_air_heat_capacity], [hot_air_heat_capacity]")
|
||||
|
||||
add_avail(lastgen)
|
||||
// update icon overlays only if displayed level has changed
|
||||
|
||||
if(hot_air)
|
||||
circ1.air2.merge(hot_air)
|
||||
|
||||
if(cold_air)
|
||||
circ2.air2.merge(cold_air)
|
||||
desc = "Current Output: [engineering_notation(lastgen)]W"
|
||||
var/genlev = max(0, min(round(26*lastgen / 4000000), 26)) // raised 2MW toplevel to 3MW, dudes were hitting 2mw way too easily
|
||||
if((genlev != lastgenlev) && !spam_limiter)
|
||||
spam_limiter = 1
|
||||
lastgenlev = genlev
|
||||
updateicon()
|
||||
if(!genlev)
|
||||
running = 0
|
||||
else if (genlev && !running)
|
||||
playsound(src.loc, sound_tractorrev, 55, 0)
|
||||
running = 1
|
||||
spawn(5)
|
||||
spam_limiter = 0
|
||||
src.updateDialog()
|
||||
|
||||
// engine looping sounds and hazards
|
||||
if (lastgenlev > 0)
|
||||
if(grump < 0) // grumpcode
|
||||
grump = 0 // no negative grump plz
|
||||
grump++ // get grump'd
|
||||
if(grump >= 100 && prob(5))
|
||||
playsound(src.loc, pick(sounds_enginegrump), 70, 0)
|
||||
src.visible_message("<span style=\"color:red\">[src] makes [pick(grump_prefix)] [pick(grump_suffix)]!</span>")
|
||||
grump -= 5
|
||||
switch (lastgenlev)
|
||||
if(0)
|
||||
return
|
||||
if(1 to 2)
|
||||
playsound(src.loc, sound_engine1, 60, 0)
|
||||
if(prob(5))
|
||||
playsound(src.loc, pick(sounds_engine), 70, 0)
|
||||
if(3 to 11)
|
||||
playsound(src.loc, sound_engine1, 60, 0)
|
||||
if(12 to 15)
|
||||
playsound(src.loc, sound_engine2, 60, 0)
|
||||
if(16 to 18)
|
||||
playsound(src.loc, sound_bellalert, 60, 0)
|
||||
if (prob(5))
|
||||
var/datum/effects/system/spark_spread/s = unpool(/datum/effects/system/spark_spread)
|
||||
s.set_up(2, 1, (get_turf(src)))
|
||||
s.start()
|
||||
if(19 to 21)
|
||||
playsound(src.loc, sound_warningbuzzer, 50, 0)
|
||||
if (prob(5))
|
||||
var/datum/effects/system/bad_smoke_spread/smoke = new /datum/effects/system/bad_smoke_spread()
|
||||
smoke.set_up(1, 0, src.loc)
|
||||
smoke.attach(src)
|
||||
smoke.start()
|
||||
src.visible_message("<span style=\"color:red\">[src] starts smoking!</span>")
|
||||
if (!grumping && grump >= 100 && prob(5))
|
||||
grumping = 1
|
||||
playsound(src.loc, "sound/machines/engine_grump1.ogg", 50, 0)
|
||||
src.visible_message("<span style=\"color:red\">[src] erupts in flame!</span>")
|
||||
fireflash(src, 1)
|
||||
grumping = 0
|
||||
grump -= 10
|
||||
if(22 to 23)
|
||||
playsound(src.loc, sound_engine_alert1, 55, 0)
|
||||
if (prob(5)) zapStuff()
|
||||
if (prob(5))
|
||||
var/datum/effects/system/bad_smoke_spread/smoke = new /datum/effects/system/bad_smoke_spread()
|
||||
smoke.set_up(1, 0, src.loc)
|
||||
smoke.attach(src)
|
||||
smoke.start()
|
||||
src.visible_message("<span style=\"color:red\">[src] starts smoking!</span>")
|
||||
if (!grumping && grump >= 100 && prob(5))
|
||||
grumping = 1
|
||||
playsound(src.loc, "sound/machines/engine_grump1.ogg", 50, 0)
|
||||
src.visible_message("<span style=\"color:red\">[src] erupts in flame!</span>")
|
||||
fireflash(src, rand(1,3))
|
||||
grumping = 0
|
||||
grump -= 30
|
||||
|
||||
if(24 to 25)
|
||||
playsound(src.loc, sound_engine_alert1, 55, 0)
|
||||
if (prob(10)) // lowering a bit more
|
||||
zapStuff()
|
||||
if (prob(5))
|
||||
var/datum/effects/system/bad_smoke_spread/smoke = new /datum/effects/system/bad_smoke_spread()
|
||||
smoke.set_up(1, 0, src.loc)
|
||||
smoke.attach(src)
|
||||
smoke.start()
|
||||
src.visible_message("<span style=\"color:red\">[src] starts smoking!</span>")
|
||||
if (!grumping && grump >= 100 && prob(10)) // probably not good if this happens several times in a row
|
||||
grumping = 1
|
||||
playsound(src.loc, "sound/weapons/rocket.ogg", 50, 0)
|
||||
src.visible_message("<span style=\"color:red\">[src] explodes in flame!</span>")
|
||||
var/firesize = rand(1,4)
|
||||
fireflash(src, firesize)
|
||||
for(var/atom/movable/M in view(firesize, src.loc)) // fuck up those jerkbag engineers
|
||||
if(M.anchored) continue
|
||||
if(ismob(M)) if(hasvar(M,"weakened")) M:weakened += 8
|
||||
if(ismob(M)) random_brute_damage(M, 10)
|
||||
if(ismob(M))
|
||||
var/atom/targetTurf = get_edge_target_turf(M, get_dir(src, get_step_away(M, src)))
|
||||
M.throw_at(targetTurf, 200, 4)
|
||||
else if (prob(15)) // cut down the number of other junk things that get blown around
|
||||
var/atom/targetTurf = get_edge_target_turf(M, get_dir(src, get_step_away(M, src)))
|
||||
M.throw_at(targetTurf, 200, 4)
|
||||
grumping = 0
|
||||
grump -= 30
|
||||
|
||||
if(26 to INFINITY)
|
||||
playsound(src.loc, sound_engine_alert3, 55, 0)
|
||||
if(!grumping && grump >= 100 && prob(6))
|
||||
grumping = 1
|
||||
src.visible_message("<span style=\"color:red\"><b>[src] [pick("resonates", "shakes", "rumbles", "grumbles", "vibrates", "roars")] [pick("dangerously", "strangely", "ominously", "frighteningly", "grumpily")]!</b></span>")
|
||||
playsound(src.loc, "sound/effects/explosionfar.ogg", 65, 1)
|
||||
for (var/obj/window/W in range(6, src.loc)) // smash nearby windows
|
||||
if (W.health_max >= 80) // plasma glass or better, no break please and thank you
|
||||
continue
|
||||
if (prob(get_dist(W,src.loc)*6))
|
||||
continue
|
||||
W.health = 0
|
||||
W.smash()
|
||||
for (var/mob/living/M in range(6, src.loc))
|
||||
shake_camera(M, 3, 2)
|
||||
M.weakened++
|
||||
for (var/atom/A in range(rand(1,3), src.loc))
|
||||
if (istype(A, /turf/simulated))
|
||||
A.pixel_x = rand(-1,1)
|
||||
A.pixel_y = rand(-1,1)
|
||||
grumping = 0
|
||||
grump -= 30
|
||||
|
||||
if(src.lastgen >= 10000000)
|
||||
for (var/turf/T in range(6, src))
|
||||
var/T_dist = get_dist(T, src)
|
||||
var/T_effect_prob = 100 * (1 - (max(T_dist-1,1) / 5))
|
||||
|
||||
for (var/obj/item/I in T)
|
||||
if ( prob(T_effect_prob) )
|
||||
animate_float(I, 1, 3)
|
||||
|
||||
if (prob(33)) // lowered because all the DEL procs related to zap are stacking up in the profiler
|
||||
zapStuff()
|
||||
if(prob(5))
|
||||
src.visible_message("<span style=\"color:red\">[src] [pick("rumbles", "groans", "shudders", "grustles", "hums", "thrums")] [pick("ominously", "oddly", "strangely", "oddly", "worringly", "softly", "loudly")]!</span>")
|
||||
else if (prob(2))
|
||||
src.visible_message("<span style=\"color:red\"><b>[src] hungers!</b></span>")
|
||||
// todo: sorta run happily at this extreme level as long as it gets a steady influx of corpses OR WEED into the furnaces
|
||||
|
||||
proc/zapStuff()
|
||||
var/atom/target = null
|
||||
var/atom/last = src
|
||||
|
||||
var/list/starts = new/list()
|
||||
for(var/atom/movable/M in orange(3, src))
|
||||
if(istype(M, /obj/overlay/tile_effect) || M.invisibility) continue
|
||||
starts.Add(M)
|
||||
|
||||
if(!starts.len) return
|
||||
|
||||
if(prob(10))
|
||||
var/person = null
|
||||
person = (locate(/mob/living) in starts)
|
||||
if(person)
|
||||
target = person
|
||||
else
|
||||
target = pick(starts)
|
||||
else
|
||||
target = pick(starts)
|
||||
|
||||
if(isturf(target))
|
||||
return //This should not be possible. But byond.
|
||||
|
||||
playsound(target, sound_bigzap, 40, 1)
|
||||
|
||||
for(var/count=0, count<3, count++)
|
||||
|
||||
if(target == null) break
|
||||
|
||||
var/list/affected = DrawLine(last, target, /obj/line_obj/elec ,'icons/obj/projectiles.dmi',"WholeLghtn",1,1,"HalfStartLghtn","HalfEndLghtn",OBJ_LAYER,1,PreloadedIcon='icons/effects/LghtLine.dmi')
|
||||
|
||||
for(var/obj/O in affected)
|
||||
spawn(6) pool(O)
|
||||
|
||||
//var/turf/currTurf = get_turf(target)
|
||||
//currTurf.hotspot_expose(2000, 400)
|
||||
|
||||
if(istype(target, /mob/living)) //Probably unsafe.
|
||||
target:TakeDamage("chest", 0, 20)
|
||||
|
||||
var/list/next = new/list()
|
||||
for(var/atom/movable/M in orange(2, target))
|
||||
if(istype(M, /obj/overlay/tile_effect) || istype(M, /obj/line_obj/elec) || M.invisibility) continue
|
||||
next.Add(M)
|
||||
|
||||
last = target
|
||||
target = pick(next)
|
||||
|
||||
|
||||
attack_ai(mob/user)
|
||||
if(stat & (BROKEN|NOPOWER)) return
|
||||
|
||||
interact(user)
|
||||
|
||||
attack_hand(mob/user)
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
if(stat & (BROKEN|NOPOWER)) return
|
||||
|
||||
interact(user)
|
||||
|
||||
proc/interact(mob/user)
|
||||
if ( (get_dist(src, user) > 1 ) && (!istype(user, /mob/living/silicon/ai)))
|
||||
user.machine = null
|
||||
user << browse(null, "window=teg")
|
||||
return
|
||||
|
||||
user.machine = src
|
||||
|
||||
var/t = "<PRE><B>Thermo-Electric Generator</B><HR>"
|
||||
|
||||
t += "Output : [engineering_notation(lastgen)]W<BR><BR>"
|
||||
|
||||
t += "<B>Hot loop</B><BR>"
|
||||
t += "Temperature Inlet: [round(circ1.air1.temperature, 0.1)] K Outlet: [round(circ1.air2.temperature, 0.1)] K<BR>"
|
||||
t += "Pressure Inlet: [round(circ1.air1.return_pressure(), 0.1)] kPa Outlet: [round(circ1.air2.return_pressure(), 0.1)] kPa<BR>"
|
||||
|
||||
t += "<B>Cold loop</B><BR>"
|
||||
t += "Temperature Inlet: [round(circ2.air1.temperature, 0.1)] K Outlet: [round(circ2.air2.temperature, 0.1)] K<BR>"
|
||||
t += "Pressure Inlet: [round(circ2.air1.return_pressure(), 0.1)] kPa Outlet: [round(circ2.air2.return_pressure(), 0.1)] kPa<BR>"
|
||||
|
||||
t += "<BR><HR><A href='?src=\ref[src];close=1'>Close</A>"
|
||||
|
||||
t += "</PRE>"
|
||||
user << browse(t, "window=teg;size=460x300")
|
||||
onclose(user, "teg")
|
||||
return 1
|
||||
|
||||
Topic(href, href_list)
|
||||
..()
|
||||
|
||||
if( href_list["close"] )
|
||||
usr << browse(null, "window=teg")
|
||||
usr.machine = null
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
power_change()
|
||||
..()
|
||||
updateicon()
|
||||
|
||||
/obj/machinery/atmospherics/unary/furnace_connector
|
||||
|
||||
icon = 'icons/obj/atmospherics/heat_reservoir.dmi'
|
||||
icon_state = "intact_off"
|
||||
density = 1
|
||||
|
||||
name = "Furnace Connector"
|
||||
desc = "Used to connect a furnace to a pipe network."
|
||||
|
||||
var/current_temperature = T20C
|
||||
var/current_heat_capacity = 3000
|
||||
|
||||
update_icon()
|
||||
if(node)
|
||||
icon_state = "intact_on"
|
||||
else
|
||||
icon_state = "exposed"
|
||||
return
|
||||
|
||||
process()
|
||||
..()
|
||||
return
|
||||
|
||||
proc/heat()
|
||||
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
|
||||
|
||||
if(abs(old_temperature-air_contents.temperature) > 1)
|
||||
if(network)
|
||||
network.update = 1
|
||||
return 1
|
||||
|
||||
/obj/machinery/power/furnace/thermo
|
||||
name = "Furnace"
|
||||
desc = "Generates Heat for the thermoelectric generator."
|
||||
icon_state = "furnace"
|
||||
anchored = 1
|
||||
density = 1
|
||||
mats = 20
|
||||
|
||||
var/obj/machinery/atmospherics/unary/furnace_connector/f_connector = null
|
||||
|
||||
proc/get_connector()
|
||||
for(var/obj/machinery/atmospherics/unary/furnace_connector/C in src.loc)
|
||||
f_connector = C
|
||||
break
|
||||
return
|
||||
|
||||
New()
|
||||
..()
|
||||
get_connector()
|
||||
|
||||
process()
|
||||
if(!f_connector) get_connector()
|
||||
if(!f_connector) return
|
||||
..()
|
||||
/*
|
||||
if(src.active)
|
||||
if(src.fuel)
|
||||
var/additional_heat = src.fuel * 4
|
||||
f_connector.current_temperature = T20C + 200 + additional_heat
|
||||
f_connector.heat()
|
||||
fuel--
|
||||
|
||||
if(!src.fuel)
|
||||
src.visible_message("<span style=\"color:red\">[src] runs out of fuel and shuts down!</span>")
|
||||
src.overlays = null
|
||||
src.active = 0
|
||||
|
||||
update_icon()
|
||||
|
||||
/* //Holy lag batman!
|
||||
src.overlays = null
|
||||
if (src.active) src.overlays +=
|
||||
if (fuelperc >= 20) src.overlays += image('icons/obj/power.dmi', "furn-c1")
|
||||
if (fuelperc >= 40) src.overlays += image('icons/obj/power.dmi', "furn-c2")
|
||||
if (fuelperc >= 60) src.overlays += image('icons/obj/power.dmi', "furn-c3")
|
||||
if (fuelperc >= 80) src.overlays += image('icons/obj/power.dmi', "furn-c4")
|
||||
|
||||
*/
|
||||
*/
|
||||
on_burn()
|
||||
var/additional_heat = src.fuel * 4
|
||||
f_connector.current_temperature = T20C + 200 + additional_heat
|
||||
f_connector.heat()
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define PUMP_POWERLEVEL_1 100
|
||||
#define PUMP_POWERLEVEL_2 500
|
||||
#define PUMP_POWERLEVEL_3 1000
|
||||
#define PUMP_POWERLEVEL_4 2500
|
||||
#define PUMP_POWERLEVEL_5 5000
|
||||
|
||||
/datum/pump_infoset
|
||||
var/power_status = 0
|
||||
var/target_output = 0
|
||||
var/id = ""
|
||||
|
||||
/obj/machinery/computer/atmosphere/pumpcontrol
|
||||
req_access = list() //Change
|
||||
req_access_txt = ""
|
||||
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
icon_state = "computer_generic"
|
||||
|
||||
name = "Pump control computer"
|
||||
|
||||
var/list/pump_infos = new/list()
|
||||
|
||||
var/last_change = 0
|
||||
var/message_delay = 600
|
||||
|
||||
var/frequency = 1225
|
||||
var/datum/radio_frequency/radio_connection
|
||||
|
||||
attack_hand(mob/user)
|
||||
if(stat & (BROKEN | NOPOWER))
|
||||
return
|
||||
user << browse(return_text(),"window=computer")
|
||||
user.machine = src
|
||||
onclose(user, "computer")
|
||||
|
||||
process()
|
||||
..()
|
||||
if(stat & (BROKEN | NOPOWER))
|
||||
return
|
||||
//src.updateDialog()
|
||||
|
||||
attackby(I as obj, user as mob)
|
||||
//Readd construction code + boards
|
||||
src.attack_hand(user)
|
||||
return
|
||||
|
||||
receive_signal(datum/signal/signal)
|
||||
if(!signal || signal.encryption)
|
||||
return
|
||||
|
||||
if(signal.data["device"] == "AGP")
|
||||
if (!signal.data["tag"] || !signal.data["power"] || !signal.data["target_output"])
|
||||
return
|
||||
|
||||
var/datum/pump_infoset/I = new()
|
||||
I.id = signal.data["tag"]
|
||||
I.power_status = signal.data["power"]
|
||||
I.target_output = signal.data["target_output"]
|
||||
|
||||
if (!(signal.source in pump_infos))
|
||||
var/area/pump_area = get_area(signal.source)
|
||||
if (istype(pump_area))
|
||||
var/area_label_position = pump_infos.Find(pump_area.name)
|
||||
if (area_label_position)
|
||||
while (1)
|
||||
area_label_position++
|
||||
if (area_label_position > pump_infos.len)
|
||||
break
|
||||
var/datum/pump_infoset/infoset = pump_infos[ pump_infos[area_label_position] ]
|
||||
if (!istype(infoset))
|
||||
break
|
||||
|
||||
if (sorttext(I.id, infoset.id) == 1)
|
||||
break
|
||||
|
||||
pump_infos.Insert(area_label_position, signal.source)
|
||||
|
||||
else
|
||||
pump_infos += pump_area.name
|
||||
pump_infos += signal.source
|
||||
|
||||
pump_infos[signal.source] = I
|
||||
|
||||
src.updateDialog()
|
||||
|
||||
proc/return_text()
|
||||
var/pump_html = ""
|
||||
//var/count = 1
|
||||
for(var/A in pump_infos)
|
||||
if (istext(A))
|
||||
pump_html += "<center><b>[A]</b></center><br>"
|
||||
continue
|
||||
|
||||
var/datum/pump_infoset/I = pump_infos[A]
|
||||
if (!istype(I))
|
||||
continue
|
||||
pump_html += "<B>[I.id] Status</B>:<BR>"
|
||||
//pump_html += "<B>Pump [count] Status</B>: <BR>"
|
||||
//pump_html += " Pump Id: [I.id]<BR>"
|
||||
pump_html += " Pump Status: <U><A href='?src=\ref[src];toggle=[I.id]'>[I.power_status == "on" ? "On":"Off"]</A></U><BR>"
|
||||
var/current_pump_level = 0
|
||||
switch (I.target_output)
|
||||
if (1 to PUMP_POWERLEVEL_1)
|
||||
current_pump_level = 1
|
||||
if (PUMP_POWERLEVEL_1 + 1 to PUMP_POWERLEVEL_2)
|
||||
current_pump_level = 2
|
||||
if (PUMP_POWERLEVEL_2 + 1 to PUMP_POWERLEVEL_3)
|
||||
current_pump_level = 3
|
||||
if (PUMP_POWERLEVEL_3 + 1 to PUMP_POWERLEVEL_4)
|
||||
current_pump_level = 4
|
||||
if (PUMP_POWERLEVEL_4 + 1 to INFINITY)
|
||||
current_pump_level = 5
|
||||
pump_html += " Pump Pressure Level: "
|
||||
for (var/i =1, i < 6, i++)
|
||||
if (current_pump_level == i)
|
||||
pump_html += "<b>[i]</b> "
|
||||
else
|
||||
pump_html += "<A href='?src=\ref[src];setoutput=[i]&target=[I.id]'>[i]</A> "
|
||||
|
||||
pump_html += "<BR><BR>"
|
||||
//count++
|
||||
|
||||
var/output = "<B>[name]</B><BR><A href='?src=\ref[src];refresh=1'>Refresh</A><BR><HR><B>Pump Data: <BR><BR></B>[pump_html]<HR>"
|
||||
return output
|
||||
|
||||
Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(!allowed(usr))
|
||||
boutput(usr, "<span style=\"color:red\">Access Denied!</span>")
|
||||
return
|
||||
|
||||
if(href_list["toggle"])
|
||||
src.add_fingerprint(usr)
|
||||
if(!radio_connection)
|
||||
return 0
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
signal.transmission_method = 1 //radio
|
||||
signal.source = src
|
||||
signal.data["tag"] = href_list["toggle"]
|
||||
signal.data["command"] = "power_toggle"
|
||||
radio_connection.post_signal(src, signal)
|
||||
|
||||
if(href_list["setoutput"])
|
||||
src.add_fingerprint(usr)
|
||||
if(!radio_connection || !href_list["target"])
|
||||
return 0
|
||||
|
||||
var/new_target = 0
|
||||
switch (href_list["setoutput"])
|
||||
if ("1")
|
||||
new_target = PUMP_POWERLEVEL_1
|
||||
if ("2")
|
||||
new_target = PUMP_POWERLEVEL_2
|
||||
if ("3")
|
||||
new_target = PUMP_POWERLEVEL_3
|
||||
if ("4")
|
||||
new_target = PUMP_POWERLEVEL_4
|
||||
if ("5")
|
||||
new_target = PUMP_POWERLEVEL_5
|
||||
|
||||
if (!new_target)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
signal.transmission_method = 1 //radio
|
||||
signal.source = src
|
||||
signal.data["tag"] = href_list["target"]
|
||||
signal.data["command"] = "set_output_pressure"
|
||||
signal.data["parameter"] = new_target
|
||||
radio_connection.post_signal(src, signal)
|
||||
|
||||
if(href_list["refresh"])
|
||||
src.add_fingerprint(usr)
|
||||
if(!radio_connection)
|
||||
return 0
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
signal.transmission_method = 1 //radio
|
||||
signal.source = src
|
||||
signal.data["command"] = "broadcast_status"
|
||||
radio_connection.post_signal(src, signal)
|
||||
proc
|
||||
set_frequency(new_frequency)
|
||||
radio_controller.remove_object(src, "[frequency]")
|
||||
frequency = new_frequency
|
||||
radio_connection = radio_controller.add_object(src, "[frequency]")
|
||||
|
||||
initialize()
|
||||
set_frequency(frequency)
|
||||
|
||||
#undef PUMP_POWERLEVEL_1
|
||||
#undef PUMP_POWERLEVEL_2
|
||||
#undef PUMP_POWERLEVEL_3
|
||||
#undef PUMP_POWERLEVEL_4
|
||||
#undef PUMP_POWERLEVEL_5
|
||||
@@ -0,0 +1,171 @@
|
||||
|
||||
/client/proc/wireTest()
|
||||
set name = "WireTest"
|
||||
set hidden = 1
|
||||
admin_only
|
||||
|
||||
//src.chui.reload()
|
||||
src.Browse(grabResource("html/wireTest.html"), "window=wireTest;size=500x650;title=Wire Test;")
|
||||
//src.mob.deathConfetti()
|
||||
|
||||
|
||||
//Proc for parsing data returned by the bans API (as well as whatever else in the future)
|
||||
//Expects a base64 encoded url parameter query string. Yes I know how weird that sounds.
|
||||
/proc/parseCallbackData(data)
|
||||
if (copytext(data, 1, 2) == "{") //we got fed json instead (probably) whoops
|
||||
var/error[] = new()
|
||||
error["error"] = "Parsing error (JSON provided)"
|
||||
return error
|
||||
|
||||
data = base64str(data)
|
||||
var/list/ldata = params2list(url_decode(data))
|
||||
var/parsedList[] = new()
|
||||
var/regex/R = new("/(^\\d{1,2})/i")
|
||||
|
||||
for (var/e = 1, e <= ldata.len, e++) //each field in the format index[fieldkey]=field
|
||||
var/index = ldata[e]
|
||||
var/num
|
||||
|
||||
if (R.Find(index))
|
||||
do
|
||||
num = R.GroupText(1) //grab the index number e.g. the 1 from 1[ckey]=blah
|
||||
while(R.FindNext(index))
|
||||
|
||||
if (!num) //no num found, we're assuming this was an error message response (or any kind of message really)
|
||||
ldata[index] = base64str(ldata[index])
|
||||
return ldata
|
||||
|
||||
var/field = copytext(index, lentext(num)+1, 0) //grab the field name e.g. [ckey]
|
||||
field = copytext(field, 2, -1) //convert [ckey] to ckey
|
||||
var/val = base64str(ldata[index]) //the actual value e.g. blah
|
||||
|
||||
if (!parsedList[num]) //if a list of this num doesnt exist, create it e.g. parsedList(1 => list())
|
||||
parsedList[num] = new/list()
|
||||
parsedList[num][field] = val //shove data in appropriate list e.g. parsedList(1 => list("ckey" => "blah"))
|
||||
//boutput(world, "Index: [index]. Num: [num]. Field: [field]. Val: [val]") //DEBUG
|
||||
|
||||
return parsedList
|
||||
|
||||
|
||||
//Silly little thing that the bans panel calls on refresh
|
||||
/proc/getWorldMins()
|
||||
var/CMinutes = num2text((world.realtime / 10) / 60, 99) //fuck you byond scientific notation
|
||||
if (centralConn)
|
||||
var/list/returnData = new()
|
||||
returnData["cminutes"] = CMinutes
|
||||
return list2json(returnData)
|
||||
else
|
||||
return CMinutes
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a query to send to the goonhub web API
|
||||
*
|
||||
* @route (string) requested route e.g. bans/check
|
||||
* @query (list) query arguments to be passed along to route
|
||||
* @forceResponse (boolean) will force the API server to return the requested data from the route rather than hitting hubCallback later on
|
||||
* @return (list|boolean) list containing parsed data response from api, 1 if forceResponse is false, 0 if error
|
||||
*
|
||||
*/
|
||||
/proc/queryAPI(route, query, forceResponse = 0)
|
||||
set background = 1
|
||||
if (!route) return 0
|
||||
|
||||
var/list/data = new()
|
||||
|
||||
if (centralConn)
|
||||
|
||||
var/uri = "http://goonhub.com/ss13" //TODO: Config option
|
||||
var/req = "[uri]/[route]/?[query ? "[list2params(query)]&" : ""]" //Necessary
|
||||
req += "[forceResponse ? "bypass=1&" : ""]" //Force a response RIGHT NOW y/n
|
||||
req += "data_server=[(world.port % 1000) / 100]&" //Append server number
|
||||
req += "auth=[md5(config.extserver_token)]" //Append auth code
|
||||
|
||||
var/response[] = world.Export(req)
|
||||
if(!response)
|
||||
logTheThing("debug", null, null, "<b>API Error</b>: No response from server during query to <b>[req]</b>. Try count is: <b>[centralConnTries]</b>")
|
||||
logTheThing("diary", null, null, "API Error: No response from server during query to [req]. Try count is [centralConnTries]", "debug")
|
||||
//if (centralConnTries >= 5)
|
||||
// centralConn = 0
|
||||
// logTheThing("debug", null, null, "<b>Critical API Error</b>: <b>Max remote API tries exceeded, switching to local fallback system.</b>")
|
||||
// logTheThing("diary", null, null, "Critical API Error: Max remote API tries exceeded, switching to local fallback system.", "debug")
|
||||
//else
|
||||
// centralConnTries++
|
||||
return 0
|
||||
|
||||
if (forceResponse)
|
||||
var/key
|
||||
var/contentExists = 0
|
||||
for (key in response)
|
||||
if (key == "CONTENT")
|
||||
contentExists = 1
|
||||
|
||||
if (!contentExists)
|
||||
logTheThing("debug", null, null, "<b>API Error</b>: Malformed response from server during <b>[req]</b>")
|
||||
logTheThing("diary", null, null, "API Error: Malformed response from server during [req]", "debug")
|
||||
return 0
|
||||
|
||||
//Parse the response
|
||||
data = parseCallbackData(file2text(response["CONTENT"]))
|
||||
|
||||
|
||||
var/theProc = null
|
||||
if (findtext(route, "bans/"))
|
||||
route = copytext(route, 6)
|
||||
//Ban routes we don't run locally if centralConn is UP
|
||||
if (centralConn)
|
||||
if (route == "check")
|
||||
return data
|
||||
//Ban routes we don't run locally regardless of anything
|
||||
if (route == "parity" || route == "updateLocal" || route == "updateRemote")
|
||||
return (centralConn ? data : 0)
|
||||
theProc = "/proc/" + route + "BanApiFallback"
|
||||
|
||||
if (!theProc)
|
||||
/* Wire note: This gets a little spammy with procs we don't care about local fallbacks for e.g. numbers station
|
||||
logTheThing("debug", null, null, "<b>Local API Error</b> - No proc specified for route: <b>[route]</b>")
|
||||
logTheThing("diary", null, null, "<b>Local API Error</b> - No proc specified for route: [route]", "debug")
|
||||
*/
|
||||
return (centralConn ? data : 0)
|
||||
|
||||
var/localData = call(theProc)(query)
|
||||
if (!localData)
|
||||
logTheThing("debug", null, null, "<b>Local API Error</b> - Nothing returned from <b>[theProc]</b>")
|
||||
logTheThing("diary", null, null, "<b>Local API Error</b> - Nothing returned from [theProc]", "debug")
|
||||
return (centralConn ? data : 0)
|
||||
|
||||
if (istype(localData, /list))
|
||||
var/list/ldata = localData
|
||||
if (ldata["error"])
|
||||
logTheThing("debug", null, null, "<b>Local API Error</b> - Callback failed in <b>[theProc]</b> with message: <b>[ldata["error"]]</b>")
|
||||
logTheThing("diary", null, null, "<b>Local API Error</b> - Callback failed in [theProc] with message: [ldata["error"]]", "debug")
|
||||
if (ldata["showAdmins"])
|
||||
message_admins("<span style=\"color:blue\"><b>Failed for route [route]BanApiFallback</b>: [ldata["error"]]</span>")
|
||||
|
||||
return (centralConn ? data : localData)
|
||||
|
||||
|
||||
/* Death confetti yayyyyyyy */
|
||||
#ifdef XMAS
|
||||
var/global/deathConfettiActive = 1
|
||||
#else
|
||||
var/global/deathConfettiActive = 0
|
||||
#endif
|
||||
|
||||
/mob/proc/deathConfetti()
|
||||
particleMaster.SpawnSystem(new /datum/particleSystem/confetti(src.loc))
|
||||
spawn(10)
|
||||
playsound(src.loc, "sound/effects/yayyy.ogg", 50, 1)
|
||||
|
||||
/client/proc/toggle_death_confetti()
|
||||
set popup_menu = 0
|
||||
set category = "Toggles"
|
||||
set name = "Toggle Death Confetti"
|
||||
set desc = "Toggles the fun confetti effect and sound whenever a mob dies"
|
||||
admin_only
|
||||
|
||||
deathConfettiActive = !deathConfettiActive
|
||||
|
||||
logTheThing("admin", src, null, "toggled Death Confetti [deathConfettiActive ? "on" : "off"]")
|
||||
logTheThing("diary", src, null, "toggled Death Confetti [deathConfettiActive ? "on" : "off"]", "admin")
|
||||
message_admins("[key_name(src)] toggled Death Confetti [deathConfettiActive ? "on" : "off"]")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,90 @@
|
||||
/obj/machinery/computer/am_engine
|
||||
name = "Antimatter Engine Console"
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "comm_computer"
|
||||
req_access = list(access_engine)
|
||||
var/engine_id = 0
|
||||
var/authenticated = 0
|
||||
var/obj/machinery/power/am_engine/engine/connected_E = null
|
||||
var/obj/machinery/power/am_engine/injector/connected_I = null
|
||||
var/state = STATE_DEFAULT
|
||||
var/const
|
||||
STATE_DEFAULT = 1
|
||||
STATE_INJECTOR = 2
|
||||
STATE_ENGINE = 3
|
||||
|
||||
/obj/machinery/computer/am_engine/New()
|
||||
..()
|
||||
spawn( 24 )
|
||||
for(var/obj/machinery/power/am_engine/engine/E in machines)
|
||||
if(E.engine_id == src.engine_id)
|
||||
src.connected_E = E
|
||||
for(var/obj/machinery/power/am_engine/injector/I in machines)
|
||||
if(I.engine_id == src.engine_id)
|
||||
src.connected_I = I
|
||||
return
|
||||
|
||||
/obj/machinery/computer/am_engine/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.machine = src
|
||||
|
||||
if(!href_list["operation"])
|
||||
return
|
||||
switch(href_list["operation"])
|
||||
// main interface
|
||||
if("activate")
|
||||
src.connected_E.engine_process()
|
||||
if("engine")
|
||||
src.state = STATE_ENGINE
|
||||
if("injector")
|
||||
src.state = STATE_INJECTOR
|
||||
if("main")
|
||||
src.state = STATE_DEFAULT
|
||||
if("login")
|
||||
var/mob/M = usr
|
||||
var/obj/item/weapon/card/id/I = M.equipped()
|
||||
if (I && istype(I))
|
||||
if(src.check_access(I))
|
||||
authenticated = 1
|
||||
if("deactivate")
|
||||
src.connected_E.stopping = 1
|
||||
if("logout")
|
||||
authenticated = 0
|
||||
|
||||
src.updateUsrDialog()
|
||||
|
||||
/obj/machinery/computer/am_engine/attack_ai(var/mob/user as mob)
|
||||
return src.attack_hand(user)
|
||||
|
||||
/obj/machinery/computer/am_engine/attack_hand(var/mob/user as mob)
|
||||
if(..())
|
||||
return
|
||||
user.machine = src
|
||||
var/dat = "<head><title>Engine Computer</title></head><body>"
|
||||
switch(src.state)
|
||||
if(STATE_DEFAULT)
|
||||
if (src.authenticated)
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=logout'>Log Out</A> \]<br>"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=engine'>Engine Menu</A> \]"
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=injector'>Injector Menu</A> \]"
|
||||
else
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=login'>Log In</A> \]"
|
||||
if(STATE_INJECTOR)
|
||||
if(src.connected_I.injecting)
|
||||
dat += "<BR>\[ Injecting \]<br>"
|
||||
else
|
||||
dat += "<BR>\[ Injecting not in progress \]<br>"
|
||||
if(STATE_ENGINE)
|
||||
if(src.connected_E.stopping)
|
||||
dat += "<BR>\[ STOPPING \]"
|
||||
else if(src.connected_E.operating && !src.connected_E.stopping)
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=deactivate'>Emergency Stop</A> \]"
|
||||
else
|
||||
dat += "<BR>\[ <A HREF='?src=\ref[src];operation=activate'>Activate Engine</A> \]"
|
||||
dat += "<BR>Contents:<br>[src.connected_E.H_fuel]kg of Hydrogen<br>[src.connected_E.antiH_fuel]kg of Anti-Hydrogen<br>"
|
||||
|
||||
dat += "<BR>\[ [(src.state != STATE_DEFAULT) ? "<A HREF='?src=\ref[src];operation=main'>Main Menu</A> | " : ""]<A HREF='?action=mach_close&window=communications'>Close</A> \]"
|
||||
user << browse(dat, "window=communications;size=400x500")
|
||||
onclose(user, "communications")
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/obj/machinery/power/am_engine
|
||||
icon = 'AM_Engine.dmi'
|
||||
density = 1
|
||||
anchored = 1.0
|
||||
flags = ON_BORDER
|
||||
|
||||
/obj/machinery/power/am_engine/bits
|
||||
name = "Antimatter Engine"
|
||||
icon_state = "1"
|
||||
|
||||
/obj/machinery/power/am_engine/engine
|
||||
name = "Antimatter Engine"
|
||||
icon_state = "am_engine"
|
||||
var/engine_id = 0
|
||||
var/H_fuel = 0
|
||||
var/antiH_fuel = 0
|
||||
var/operating = 0
|
||||
var/stopping = 0
|
||||
var/obj/machinery/power/am_engine/injector/connected = null
|
||||
|
||||
/obj/machinery/power/am_engine/injector
|
||||
name = "Injector"
|
||||
icon_state = "injector"
|
||||
var/engine_id = 0
|
||||
var/injecting = 0
|
||||
var/fuel = 0
|
||||
var/obj/machinery/power/am_engine/engine/connected = null
|
||||
|
||||
//injector
|
||||
|
||||
/obj/machinery/power/am_engine/injector/New()
|
||||
..()
|
||||
spawn( 13 )
|
||||
var/loc = get_step(src, NORTH)
|
||||
src.connected = locate(/obj/machinery/power/am_engine/engine, get_step(loc, NORTH))
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_engine/injector/attackby(obj/item/weapon/fuel/F, mob/user)
|
||||
if( (stat & BROKEN) || !connected) return
|
||||
|
||||
if(istype(F, /obj/item/weapon/fuel/H))
|
||||
if(injecting)
|
||||
boutput(user, "Theres already a fuel rod in the injector!")
|
||||
return
|
||||
boutput(user, "You insert the rod into the injector")
|
||||
injecting = 1
|
||||
var/fuel = F.fuel
|
||||
qdel(F)
|
||||
spawn( 300 )
|
||||
injecting = 0
|
||||
new/obj/item/weapon/fuel(src.loc)
|
||||
connected.H_fuel += fuel
|
||||
|
||||
if(istype(F, /obj/item/weapon/fuel/antiH))
|
||||
if(injecting)
|
||||
boutput(user, "Theres already a fuel rod in the injector!")
|
||||
return
|
||||
boutput(user, "You insert the rod into the injector")
|
||||
injecting = 1
|
||||
var/fuel = F.fuel
|
||||
qdel(F)
|
||||
spawn( 300 )
|
||||
injecting = 0
|
||||
new /obj/item/weapon/fuel(src.loc)
|
||||
connected.antiH_fuel += fuel
|
||||
|
||||
return
|
||||
|
||||
|
||||
//engine
|
||||
|
||||
|
||||
/obj/machinery/power/am_engine/engine/New()
|
||||
..()
|
||||
spawn( 7 )
|
||||
var/loc = get_step(src, SOUTH)
|
||||
src.connected = locate(/obj/machinery/power/am_engine/injector, get_step(loc, SOUTH))
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_engine/engine/proc/engine_go()
|
||||
|
||||
if( (!src.connected) || (stat & BROKEN) )
|
||||
return
|
||||
|
||||
if(!antiH_fuel || !H_fuel)
|
||||
return
|
||||
|
||||
operating = 1
|
||||
var/energy = 0
|
||||
|
||||
if(antiH_fuel == H_fuel)
|
||||
var/mass = antiH_fuel + H_fuel
|
||||
energy = convert2energy(mass)
|
||||
H_fuel = 0
|
||||
antiH_fuel = 0
|
||||
else
|
||||
var/residual_matter = modulus(H_fuel - antiH_fuel)
|
||||
var/mass = antiH_fuel + H_fuel - residual_matter
|
||||
energy = convert2energy(mass)
|
||||
if( H_fuel > antiH_fuel )
|
||||
H_fuel = residual_matter
|
||||
antiH_fuel = 0
|
||||
else
|
||||
H_fuel = 0
|
||||
antiH_fuel = residual_matter
|
||||
|
||||
for(var/mob/M in hearers(src, null))
|
||||
M.show_message(text("<span style=\"color:red\">You hear a loud bang!</span>"))
|
||||
|
||||
//Q = k x (delta T)
|
||||
|
||||
energy = energy*0.75
|
||||
operating = 0
|
||||
|
||||
//TODO: DEFERRED Heat tile
|
||||
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_engine/engine/proc/engine_process()
|
||||
|
||||
do
|
||||
if( (!src.connected) || (stat & BROKEN) )
|
||||
return
|
||||
|
||||
if(!antiH_fuel || !H_fuel)
|
||||
return
|
||||
|
||||
if(operating)
|
||||
return
|
||||
|
||||
operating = 1
|
||||
|
||||
sleep(50)
|
||||
|
||||
var/energy //energy from the reaction
|
||||
var/H //residual matter if H
|
||||
var/antiH //residual matter if antiH
|
||||
var/mass //total mass
|
||||
|
||||
if(antiH_fuel == H_fuel) //if they're equal then convert the whole mass to energy
|
||||
mass = antiH_fuel + H_fuel
|
||||
energy = convert2energy(mass)
|
||||
|
||||
else //else if they're not equal determine which isn't equal
|
||||
//and set it equal to either H or antiH so we don't lose anything
|
||||
|
||||
var/residual_matter = modulus(H_fuel - antiH_fuel)
|
||||
mass = antiH_fuel + H_fuel - residual_matter
|
||||
energy = convert2energy(mass)
|
||||
|
||||
if( H_fuel > antiH_fuel )
|
||||
H = residual_matter
|
||||
else
|
||||
antiH = residual_matter
|
||||
|
||||
|
||||
if(energy > convert2energy(8e-12)) //TOO MUCH ENERGY
|
||||
for(var/mob/M in hearers(src, null))
|
||||
M.show_message(text("<span style=\"color:red\">You hear a loud whirring!</span>"))
|
||||
sleep(20)
|
||||
|
||||
//Q = k x (delta T)
|
||||
//Too much energy so machine panics and dissapates half of it as heat
|
||||
//The rest of the energetic photons then form into H and anti H particles again!
|
||||
|
||||
H_fuel -= H
|
||||
antiH_fuel -= antiH
|
||||
antiH_fuel = antiH_fuel/2
|
||||
H_fuel = H_fuel/2
|
||||
|
||||
energy = convert2energy(H_fuel + antiH_fuel)
|
||||
|
||||
H_fuel += H
|
||||
antiH_fuel += antiH
|
||||
|
||||
if(energy > convert2energy(8e-12)) //FAR TOO MUCH ENERGY STILL
|
||||
for(var/mob/M in hearers(src, null))
|
||||
M.show_message(text("<span style=\"color:red\"><big>BANG!</big></span>"))
|
||||
new /obj/bhole(src.loc)
|
||||
|
||||
else //this amount of energy is okay so it does the proper output thing
|
||||
|
||||
sleep(60)
|
||||
//E = Pt
|
||||
//Lets say its 86% efficient
|
||||
var/output = 0.86*energy/20
|
||||
add_avail(output)
|
||||
//yeah the machine realises that something isn't right and accounts for it if H or antiH
|
||||
H_fuel -= H
|
||||
antiH_fuel -= antiH
|
||||
antiH_fuel = antiH_fuel/4
|
||||
H_fuel = H_fuel/4
|
||||
H_fuel += H
|
||||
antiH_fuel += antiH
|
||||
operating = 0
|
||||
sleep(100)
|
||||
|
||||
while(!stopping)
|
||||
|
||||
stopping = 0
|
||||
|
||||
return
|
||||
@@ -0,0 +1,92 @@
|
||||
/obj/item/fuel
|
||||
name = "Magnetic Storage Ring"
|
||||
desc = "A magnetic storage ring."
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "rcdammo"
|
||||
opacity = 0
|
||||
density = 0
|
||||
anchored = 0.0
|
||||
var/fuel = 0
|
||||
var/s_time = 1.0
|
||||
var/content = null
|
||||
|
||||
/obj/item/fuel/H
|
||||
name = "Hydrogen storage ring"
|
||||
content = "Hydrogen"
|
||||
fuel = 1e-12 //pico-kilogram
|
||||
|
||||
/obj/item/fuel/antiH
|
||||
name = "Anti-Hydrogen storage ring"
|
||||
content = "Anti-Hydrogen"
|
||||
fuel = 1e-12 //pico-kilogram
|
||||
|
||||
/obj/item/fuel/attackby(obj/item/fuel/F, mob/user)
|
||||
if(istype(src, /obj/item/fuel/antiH))
|
||||
if(istype(F, /obj/item/fuel/antiH))
|
||||
src.fuel += F.fuel
|
||||
F.fuel = 0
|
||||
boutput(user, "You have added the anti-Hydorgen to the storage ring, it now contains [src.fuel]kg")
|
||||
if(istype(F, /obj/item/fuel/H))
|
||||
src.fuel += F.fuel
|
||||
qdel(F)
|
||||
src:annihilation(src.fuel)
|
||||
if(istype(src, /obj/item/fuel/H))
|
||||
if(istype(F, /obj/item/fuel/H))
|
||||
src.fuel += F.fuel
|
||||
F.fuel = 0
|
||||
boutput(user, "You have added the Hydorgen to the storage ring, it now contains [src.fuel]kg")
|
||||
if(istype(F, /obj/item/fuel/antiH))
|
||||
src.fuel += F.fuel
|
||||
qdel(src)
|
||||
F:annihilation(F.fuel)
|
||||
|
||||
/obj/item/fuel/antiH/proc/annihilation(var/mass)
|
||||
|
||||
var/strength = convert2energy(mass)
|
||||
|
||||
if (strength < 773.0)
|
||||
var/turf/T = get_turf(src.loc)
|
||||
|
||||
if (strength > (450+T0C))
|
||||
explosion(src, T, 0, 1, 2, 4)
|
||||
else
|
||||
if (strength > (300+T0C))
|
||||
explosion(src, T, 0, 0, 2, 3)
|
||||
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
var/turf/ground_zero = get_turf(loc)
|
||||
|
||||
var/ground_zero_range = round(strength / 387)
|
||||
explosion(src, ground_zero, ground_zero_range, ground_zero_range*2, ground_zero_range*3, ground_zero_range*4)
|
||||
|
||||
//SN src = null
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
/obj/item/fuel/examine()
|
||||
set src in view(1)
|
||||
if(usr && !usr.stat)
|
||||
boutput(usr, "A magnetic storage ring, it contains [fuel]kg of [content ? content : "nothing"].")
|
||||
|
||||
/obj/item/fuel/proc/injest(mob/M as mob)
|
||||
switch(content)
|
||||
if("Anti-Hydrogen")
|
||||
M.gib(1)
|
||||
if("Hydrogen")
|
||||
boutput(M, "<span style=\"color:blue\">You feel very light, as if you might just float away...</span>")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/item/fuel/attack(mob/M as mob, mob/user as mob)
|
||||
if (user != M)
|
||||
user.visible_message("<span style=\"color:red\">[user] is trying to force [M] to eat the [src.content]!</span>")
|
||||
if (do_mob(user, M, 40))
|
||||
user.visible_message("<span style=\"color:red\">[user] forced [M] to eat the [src.content]!</span>")
|
||||
src.injest(M)
|
||||
else
|
||||
for(var/mob/O in viewers(M, null))
|
||||
O.show_message(text("<span style=\"color:red\">[M] ate the [content ? content : "empty canister"]!</span>"), 1)
|
||||
src.injest(M)
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
These are fallback procs for all API functions that require it
|
||||
This means that if the central server dies, this can pick up and do it's thang
|
||||
Currently only bans exist here
|
||||
*/
|
||||
|
||||
/proc/checkBanApiFallback(data)
|
||||
var/database/db = new("data/localBans.db")
|
||||
|
||||
//Construct sql field search
|
||||
var/searchSql = ""
|
||||
var/list/prepared = new()
|
||||
for (var/key in data)
|
||||
if (key == "ckey" || key == "ip" || key == "compID")
|
||||
var/param = data[key]
|
||||
if (param)
|
||||
searchSql += "[key] = ? OR "
|
||||
prepared.Add(param)
|
||||
|
||||
searchSql = copytext(searchSql, 1, -4) //Remove the trailing ' OR '
|
||||
var/sql = "SELECT * FROM bans WHERE removed = 0 AND ([searchSql]) ORDER BY id DESC"
|
||||
|
||||
var/list/queryList = new()
|
||||
queryList.Add(sql)
|
||||
queryList += prepared
|
||||
var/database/query/q = new(queryList)
|
||||
|
||||
var/list/returnData = new()
|
||||
|
||||
if(!q.Execute(db))
|
||||
returnData["error"] = "Unable to query database: \[[q.Error()]\] [q.ErrorMsg()]"
|
||||
return returnData
|
||||
|
||||
var/count = 1
|
||||
while(q.NextRow())
|
||||
var/list/current = new()
|
||||
var/list/row = q.GetRowData()
|
||||
for (var/key in row)
|
||||
current[key] = row[key]
|
||||
returnData["[count]"] = current
|
||||
count++
|
||||
|
||||
if (count == 1) //None found, tell the bans proc thus. yes i know 1 is weird for none, shush
|
||||
returnData["none"] = "No results found"
|
||||
return returnData
|
||||
|
||||
return returnData
|
||||
|
||||
|
||||
/proc/clearTempBansApiFallback()
|
||||
var/database/db = new("data/localBans.db")
|
||||
|
||||
var/cminutes = (world.realtime / 10) / 60
|
||||
var/sql = "UPDATE bans SET removed = 1 WHERE (timestamp > 0 AND ? >= timestamp) AND removed = 0"
|
||||
|
||||
var/list/queryList = new()
|
||||
queryList.Add(sql)
|
||||
queryList.Add(cminutes)
|
||||
var/database/query/q = new(queryList)
|
||||
|
||||
var/list/returnData = new()
|
||||
|
||||
if(!q.Execute(db))
|
||||
returnData["error"] = "Unable to query database: \[[q.Error()]\] [q.ErrorMsg()]"
|
||||
return returnData
|
||||
|
||||
var/count = q.RowsAffected()
|
||||
|
||||
returnData["cleared"] = count
|
||||
return returnData
|
||||
|
||||
|
||||
/proc/addBanApiFallback(data)
|
||||
var/database/db = new("data/localBans.db")
|
||||
|
||||
//Check we dont already have this ban
|
||||
var/sql = "SELECT * FROM bans WHERE ckey = ? AND compID = ? AND ip = ? AND removed = 0"
|
||||
var/list/prepared = new()
|
||||
prepared.Add(data["ckey"])
|
||||
prepared.Add(data["compID"])
|
||||
prepared.Add(data["ip"])
|
||||
|
||||
var/list/queryList = new()
|
||||
queryList.Add(sql)
|
||||
queryList += prepared
|
||||
var/database/query/q = new(queryList)
|
||||
|
||||
var/list/returnData = new()
|
||||
|
||||
if(!q.Execute(db))
|
||||
returnData["error"] = "Unable to query database: \[[q.Error()]\] [q.ErrorMsg()]"
|
||||
return returnData
|
||||
|
||||
var/count = 0
|
||||
while(q.NextRow())
|
||||
count++
|
||||
break
|
||||
|
||||
if (count)
|
||||
returnData["showAdmins"] = 1
|
||||
returnData["error"] = "Ban already exists for: Ckey: [data["ckey"]], compID: [data["compID"]] and IP: [data["ip"]]"
|
||||
return returnData
|
||||
|
||||
//Add the ban
|
||||
var/sql2 = "INSERT INTO bans (ckey, compID, ip, reason, akey, timestamp, previous, chain) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
|
||||
var/list/prepared2 = new()
|
||||
prepared2.Add(data["ckey"])
|
||||
prepared2.Add(data["compID"])
|
||||
prepared2.Add(data["ip"])
|
||||
prepared2.Add(data["reason"])
|
||||
prepared2.Add(data["akey"])
|
||||
prepared2.Add(data["timestamp"])
|
||||
prepared2.Add(data["previous"])
|
||||
prepared2.Add(data["chain"])
|
||||
|
||||
var/list/queryList2 = new()
|
||||
queryList2.Add(sql2)
|
||||
queryList2 += prepared2
|
||||
var/database/query/q2 = new(queryList2)
|
||||
|
||||
if(!q2.Execute(db))
|
||||
returnData["error"] = "Unable to query database: \[[q.Error()]\] [q.ErrorMsg()]"
|
||||
return returnData
|
||||
|
||||
returnData["1"] = data
|
||||
data["type"] = "add"
|
||||
writeToBanLog(data)
|
||||
return returnData
|
||||
|
||||
|
||||
/proc/editBanApiFallback(data)
|
||||
var/database/db = new("data/localBans.db")
|
||||
|
||||
//Add the ban
|
||||
var/sql = "UPDATE bans SET ckey = ?, compID = ?, ip = ?, reason = ?, akey = ?, timestamp = ? WHERE id = ?"
|
||||
var/list/prepared = new()
|
||||
prepared.Add(data["ckey"])
|
||||
prepared.Add(data["compID"])
|
||||
prepared.Add(data["ip"])
|
||||
prepared.Add(data["reason"])
|
||||
prepared.Add(data["akey"])
|
||||
prepared.Add(data["timestamp"])
|
||||
prepared.Add(data["id"])
|
||||
|
||||
var/list/queryList = new()
|
||||
queryList.Add(sql)
|
||||
queryList += prepared
|
||||
var/database/query/q = new(queryList)
|
||||
|
||||
var/list/returnData = new()
|
||||
|
||||
if(!q.Execute(db))
|
||||
returnData["error"] = "Unable to query database: \[[q.Error()]\] [q.ErrorMsg()]"
|
||||
return returnData
|
||||
|
||||
if (q.RowsAffected() == 0) //Oh no nothing was changed that's PRETTY FUCKIN WEIRD
|
||||
returnData["error"] = "Edit ban changed nothing for: Ckey: [data["ckey"]], compID: [data["compID"]] and IP: [data["ip"]]"
|
||||
return returnData
|
||||
|
||||
returnData["1"] = data
|
||||
data["type"] = "edit"
|
||||
writeToBanLog(data)
|
||||
return returnData
|
||||
|
||||
|
||||
/proc/deleteBanApiFallback(data)
|
||||
var/database/db = new("data/localBans.db")
|
||||
|
||||
//Add the ban
|
||||
var/sql = "UPDATE bans SET removed = 1 WHERE id = ?"
|
||||
var/list/prepared = new()
|
||||
prepared.Add(data["id"])
|
||||
|
||||
var/list/queryList = new()
|
||||
queryList.Add(sql)
|
||||
queryList += prepared
|
||||
var/database/query/q = new(queryList)
|
||||
|
||||
var/list/returnData = new()
|
||||
|
||||
if(!q.Execute(db))
|
||||
returnData["error"] = "Unable to query database: \[[q.Error()]\] [q.ErrorMsg()]"
|
||||
return returnData
|
||||
|
||||
if (q.RowsAffected() == 0) //It wasn't removed that's also pretty fuckin weird
|
||||
returnData["error"] = "Delete ban removed nothing for ID: [data["id"]]"
|
||||
return returnData
|
||||
|
||||
returnData["1"] = data
|
||||
data["type"] = "delete"
|
||||
writeToBanLog(data)
|
||||
return returnData
|
||||
|
||||
|
||||
//Internal proc for the ban panel to search through bans
|
||||
/proc/getBanApiFallback(searchCol="all", search="", order="DESC", offset=0, limit=10, sort="id", removed=0)
|
||||
|
||||
var/database/db = new("data/localBans.db")
|
||||
|
||||
//I COULD do field validation here but I really cannot be fucked
|
||||
|
||||
//Get the matched rows
|
||||
var/list/prepArray = new()
|
||||
var/sql = "SELECT * FROM bans WHERE removed = [removed]"
|
||||
if (search && length(search) > 0)
|
||||
sql += " AND ("
|
||||
if (searchCol == "all")
|
||||
var/val = search
|
||||
sql += "ckey LIKE ? OR akey LIKE ? OR compID LIKE ? OR ip LIKE ? OR reason LIKE ?"
|
||||
var/pSearch = val+"%"
|
||||
prepArray.Add(pSearch, pSearch, pSearch, pSearch, pSearch) //this is so dumb
|
||||
else
|
||||
sql += searchCol + " LIKE ?"
|
||||
prepArray.Add(search+"%")
|
||||
sql += ")"
|
||||
|
||||
sql += " ORDER BY "+sort+" "+order+" LIMIT "+limit
|
||||
var/list/queryList = new()
|
||||
queryList.Add(sql)
|
||||
queryList += prepArray
|
||||
var/database/query/q = new(queryList)
|
||||
|
||||
if(!q.Execute(db))
|
||||
logTheThing("debug", null, null, "<b>Local Callback Error</b> - callback failed in <b>getBanApiFallback</b> with message: <b>Unable to query database</b>: \[[q.Error()]\] [q.ErrorMsg()]")
|
||||
logTheThing("diary", null, null, "Local Callback Error - callback failed in getBanApiFallback with message: Unable to query database: \[[q.Error()]\] [q.ErrorMsg()]", "debug")
|
||||
return 0
|
||||
|
||||
//We gotta put all our rows in a list so we can count them for pagination
|
||||
var/list/returnData = new()
|
||||
var/list/allRows = new()
|
||||
while(q.NextRow())
|
||||
var/list/row = q.GetRowData()
|
||||
allRows += list(row)
|
||||
|
||||
var/totalBans = allRows.len
|
||||
|
||||
//Now we get the subset of the returned rows and format them correctly
|
||||
var/list/requested = allRows.Copy(offset, limit)
|
||||
var/count = 1
|
||||
for (var/key1 in requested)
|
||||
var/list/current = new()
|
||||
var/list/row = requested[count]
|
||||
for (var/key2 in row)
|
||||
current[key2] = row[key2]
|
||||
returnData["[count]"] = current
|
||||
count++
|
||||
|
||||
returnData["total"] = totalBans
|
||||
returnData["cminutes"] = getWorldMins()
|
||||
returnData["callback"] = "updateBans"
|
||||
|
||||
return list2json(returnData)
|
||||
|
||||
|
||||
/proc/uploadLocalBans(F as file)
|
||||
fcopy(F, "data/localBans.db")
|
||||
@@ -0,0 +1,250 @@
|
||||
/client/proc/sharkban(mob/sharktarget as mob in world)
|
||||
set category = null
|
||||
set name = "Shark Ban"
|
||||
set popup_menu = 0
|
||||
var/startx = 1
|
||||
var/starty = 1
|
||||
// var/startside = pick(cardinal)
|
||||
// var/pickstarter = null
|
||||
if(!src.holder)
|
||||
boutput(src, "Only administrators may use this command.")
|
||||
return
|
||||
else
|
||||
switch(alert("Temporary Ban?",,"Yes","No"))
|
||||
if("Yes")
|
||||
var/sharkmins = input(usr,"How long (in minutes)?","Ban time",1440) as num
|
||||
if(!sharkmins)
|
||||
return
|
||||
if(sharkmins >= 2441) sharkmins = 2440
|
||||
var/reason = input(usr,"Reason?","reason","Griefer") as text
|
||||
if(!reason)
|
||||
return
|
||||
var/speed = input(usr,"How fast is the shark? Lower is faster.","speed","5") as num
|
||||
if(!speed)
|
||||
return
|
||||
var/time = input(usr,"How long until it gives up and cheats? No relation to real time.","time","4") as num
|
||||
if(!time)
|
||||
return
|
||||
// switch(startside)
|
||||
// if(NORTH)
|
||||
// starty = world.maxy-2
|
||||
// startx = rand(2, world.maxx-2)
|
||||
// if(EAST)
|
||||
// starty = rand(2,world.maxy-2)
|
||||
// startx = world.maxx-2
|
||||
// if(SOUTH)
|
||||
// starty = 2
|
||||
// startx = rand(2, world.maxx-2)
|
||||
// if(WEST)
|
||||
// starty = rand(2, world.maxy-2)
|
||||
// startx = 2
|
||||
boutput(sharktarget, "Uh oh.")
|
||||
sharktarget << sound('sound/misc/jaws.ogg')
|
||||
sleep(200)
|
||||
startx = sharktarget.x - rand(-11, 11)
|
||||
starty = sharktarget.y - rand(-11, 11)
|
||||
// pickedstarter = get_turf(pick(sharktarget:range(10)))
|
||||
var/turf/pickedstart = locate(startx, starty, sharktarget.z)
|
||||
var/obj/banshark/Q = new /obj/banshark(pickedstart)
|
||||
Q.sharkmins2 = sharkmins
|
||||
Q.sharktarget2 = sharktarget
|
||||
Q.caller = usr
|
||||
Q.sharkreason = reason
|
||||
Q.timelimit = time
|
||||
Q.sharkspeed = speed
|
||||
// boutput(sharktarget, "<span style=\"color:red\"><BIG><B>You have been banned by [usr.client.ckey].<br>Reason: [reason].</B></BIG></span>")
|
||||
// boutput(sharktarget, "<span style=\"color:red\">This is a temporary ban, it will be removed in [sharkmins] minutes.</span>")
|
||||
// logTheThing("admin", usr, sharktarget, "has sharked %target%. Reason: [reason]. This will be removed in [sharkmins] minutes.")
|
||||
logTheThing("diary", usr, sharktarget, "has sharked %target%. Reason: [reason]. This will be removed in [sharkmins] minutes.", "admin")
|
||||
// message_admins("<span style=\"color:blue\">[usr.client.ckey] has banned [sharktarget.ckey].<br>Reason: [reason]<br>This will be removed in [sharkmins] minutes.</span>")
|
||||
|
||||
/client/proc/sharkgib(mob/sharktarget as mob in world)
|
||||
set category = null
|
||||
set name = "Shark Gib"
|
||||
set popup_menu = 0
|
||||
var/startx = 1
|
||||
var/starty = 1
|
||||
// var/startside = pick(cardinal)
|
||||
// var/pickstarter = null
|
||||
if(!src.holder)
|
||||
boutput(src, "Only administrators may use this command.")
|
||||
return
|
||||
|
||||
var/speed = input(usr,"How fast is the shark? Lower is faster.","speed","5") as num
|
||||
if(!speed)
|
||||
return
|
||||
// switch(startside)
|
||||
// if(NORTH)
|
||||
// starty = world.maxy-2
|
||||
// startx = rand(2, world.maxx-2)
|
||||
// if(EAST)
|
||||
// starty = rand(2,world.maxy-2)
|
||||
// startx = world.maxx-2
|
||||
// if(SOUTH)
|
||||
// starty = 2
|
||||
// startx = rand(2, world.maxx-2)
|
||||
// if(WEST)
|
||||
// starty = rand(2, world.maxy-2)
|
||||
// startx = 2
|
||||
boutput(sharktarget, "Uh oh.")
|
||||
sharktarget << sound('sound/misc/jaws.ogg')
|
||||
sleep(200)
|
||||
startx = sharktarget.x - rand(-11, 11)
|
||||
starty = sharktarget.y - rand(-11, 11)
|
||||
// pickedstarter = get_turf(pick(sharktarget:range(10)))
|
||||
var/turf/pickedstart = locate(startx, starty, sharktarget.z)
|
||||
var/obj/gibshark/Q = new /obj/gibshark(pickedstart)
|
||||
Q.sharktarget2 = sharktarget
|
||||
Q.caller = usr
|
||||
Q.sharkspeed = speed
|
||||
// boutput(sharktarget, "<span style=\"color:red\"><BIG><B>You have been banned by [usr.client.ckey].<br>Reason: [reason].</B></BIG></span>")
|
||||
// boutput(sharktarget, "<span style=\"color:red\">This is a temporary ban, it will be removed in [sharkmins] minutes.</span>")
|
||||
// logTheThing("admin", usr, sharktarget, "has sharked %target%.<br>Reason: [reason]<br>This will be removed in [sharkmins] minutes.")
|
||||
// logTheThing("diary", usr, sharktarget, "has sharked %target%.<br>Reason: [reason]<br>This will be removed in [sharkmins] minutes.", "admin")
|
||||
// message_admins("<span style=\"color:blue\">[usr.client.ckey] has banned [sharktarget.ckey].<br>Reason: [reason]<br>This will be removed in [sharkmins] minutes.</span>")
|
||||
|
||||
|
||||
/obj/banshark/
|
||||
name = "banshark"
|
||||
desc = "This is the most terrifying thing you've ever laid eyes on."
|
||||
icon = 'icons/misc/banshark.dmi'
|
||||
icon_state = "banshark1"
|
||||
layer = EFFECTS_LAYER_2
|
||||
density = 1
|
||||
anchored = 0
|
||||
var/mob/sharktarget2 = null
|
||||
var/sharkmins2 = null
|
||||
var/caller = null
|
||||
var/sharkreason = null
|
||||
var/sharkcantreach = 0
|
||||
var/timelimit = 6
|
||||
var/sharkspeed = 1
|
||||
|
||||
New()
|
||||
spawn(0) process()
|
||||
..()
|
||||
|
||||
Bump(M as turf|obj|mob)
|
||||
M:density = 0
|
||||
spawn(4)
|
||||
M:density = 1
|
||||
sleep(1)
|
||||
var/turf/T = get_turf(M)
|
||||
src.x = T.x
|
||||
src.y = T.y
|
||||
|
||||
proc/process()
|
||||
while (!disposed)
|
||||
if (sharkcantreach >= timelimit)
|
||||
if (sharkcantreach >= 20)
|
||||
qdel(src)
|
||||
return
|
||||
src.x = sharktarget2.x
|
||||
src.y = sharktarget2.y
|
||||
src.z = sharktarget2.z
|
||||
banproc()
|
||||
return
|
||||
else if (get_dist(src, src.sharktarget2) <= 1)
|
||||
for(var/mob/O in AIviewers(src, null))
|
||||
O.show_message("<span style=\"color:red\"><B>[src]</B> bites [sharktarget2]!</span>", 1)
|
||||
sharktarget2.weakened += 10
|
||||
sharktarget2.stunned += 10
|
||||
playsound(src.loc, 'sound/effects/bang.ogg', 50, 1, -1)
|
||||
banproc()
|
||||
return
|
||||
else
|
||||
walk_towards(src, src.sharktarget2, sharkspeed)
|
||||
sleep(10)
|
||||
sharkcantreach++
|
||||
|
||||
proc/banproc()
|
||||
// drsingh for various cannot read null.
|
||||
for(var/mob/O in AIviewers(src, null))
|
||||
O.show_message("<span style=\"color:red\"><B>[src]</B> bans [sharktarget2] in one bite!</span>", 1)
|
||||
playsound(src.loc, 'sound/items/eatfood.ogg', 30, 1, -2)
|
||||
if(sharktarget2 && sharktarget2.client)
|
||||
if(sharktarget2.client.holder)
|
||||
boutput(sharktarget2, "Here is where you'd get banned.")
|
||||
qdel(src)
|
||||
return
|
||||
var/addData[] = new()
|
||||
addData["ckey"] = sharktarget2.ckey
|
||||
addData["compID"] = sharktarget2.computer_id
|
||||
addData["ip"] = sharktarget2.client.address
|
||||
addData["reason"] = sharkreason
|
||||
addData["akey"] = caller:ckey
|
||||
addData["mins"] = sharkmins2
|
||||
addBan(1, addData)
|
||||
boutput(sharktarget2, "<span style=\"color:red\"><BIG><B>You have been sharked by [usr.client.ckey].<br>Reason: [sharkreason] and he couldn't escape the shark.</B></BIG></span>")
|
||||
boutput(sharktarget2, "<span style=\"color:red\">This is a temporary sharkban, it will be removed in [sharkmins2] minutes.</span>")
|
||||
logTheThing("admin", caller:client, sharktarget2, "has sharkbanned %target%. Reason: [sharkreason] and he couldn't escape the shark. This will be removed in [sharkmins2] minutes.")
|
||||
logTheThing("diary", caller:client, sharktarget2, "has sharkbanned %target%. Reason: [sharkreason] and he couldn't escape the shark. This will be removed in [sharkmins2] minutes.", "admin")
|
||||
message_admins("<span style=\"color:blue\">[caller:client.ckey] has sharkbanned [sharktarget2.ckey].<br>Reason: [sharkreason] and he couldn't escape the shark.<br>This will be removed in [sharkmins2] minutes.</span>")
|
||||
del(sharktarget2.client)
|
||||
sharktarget2.gib()
|
||||
// if(ishuman(sharktarget2))
|
||||
// animation = new(src.loc)
|
||||
// animation.icon_state = "blank"
|
||||
// animation.icon = 'icons/mob/mob.dmi'
|
||||
// animation.master = src
|
||||
// if (sharktarget2:client)
|
||||
playsound(src.loc, pick('sound/misc/burp_alien.ogg'), 50, 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/gibshark/
|
||||
name = "gibshark"
|
||||
desc = "This is the second most terrifying thing you've ever laid eyes on."
|
||||
icon = 'icons/misc/banshark.dmi'
|
||||
icon_state = "banshark1"
|
||||
layer = EFFECTS_LAYER_2
|
||||
density = 1
|
||||
anchored = 0
|
||||
var/mob/sharktarget2 = null
|
||||
var/sharkspeed = 1
|
||||
var/caller = null
|
||||
|
||||
New()
|
||||
spawn(0) process()
|
||||
..()
|
||||
|
||||
Bump(M as turf|obj|mob)
|
||||
M:density = 0
|
||||
spawn(4)
|
||||
M:density = 1
|
||||
sleep(1)
|
||||
var/turf/T = get_turf(M)
|
||||
src.x = T.x
|
||||
src.y = T.y
|
||||
|
||||
proc/process()
|
||||
while (!disposed)
|
||||
if (get_dist(src, src.sharktarget2) <= 1)
|
||||
for(var/mob/O in AIviewers(src, null))
|
||||
O.show_message("<span style=\"color:red\"><B>[src]</B> bites [sharktarget2]!</span>", 1)
|
||||
sharktarget2.weakened += 10
|
||||
sharktarget2.stunned += 10
|
||||
playsound(src.loc, 'sound/effects/bang.ogg', 50, 1, -1)
|
||||
gibproc()
|
||||
return
|
||||
else
|
||||
walk_towards(src, src.sharktarget2, sharkspeed)
|
||||
sleep(10)
|
||||
|
||||
proc/gibproc()
|
||||
// drsingh for various cannot read null.
|
||||
sleep(15)
|
||||
if (get_dist(src, src.sharktarget2) <= 1)
|
||||
for(var/mob/O in AIviewers(src, null))
|
||||
O.show_message("<span style=\"color:red\"><B>[src]</B> gibs [sharktarget2] in one bite!</span>", 1)
|
||||
playsound(src.loc, 'sound/items/eatfood.ogg', 30, 1, -2)
|
||||
if(sharktarget2 && sharktarget2.client)
|
||||
logTheThing("admin", caller:client, sharktarget2, "sharkgibbed %target%")
|
||||
logTheThing("diary", caller:client, sharktarget2, "sharkgibbed %target%", "admin")
|
||||
message_admins("<span style=\"color:blue\">[caller:client.ckey] has sharkgibbed [sharktarget2.ckey].</span>")
|
||||
sharktarget2.gib()
|
||||
sleep(5)
|
||||
playsound(src.loc, pick('sound/misc/burp_alien.ogg'), 50, 0)
|
||||
sleep(5)
|
||||
qdel(src)
|
||||
else
|
||||
process()
|
||||
@@ -0,0 +1,275 @@
|
||||
|
||||
// 4 arfur
|
||||
// xoxo procitizen
|
||||
|
||||
|
||||
/obj/item/clothing/suit/armor/batman/equipped(var/mob/user)
|
||||
user.verbs += /client/proc/batsmoke
|
||||
user.verbs += /client/proc/batarang
|
||||
user.verbs += /mob/proc/batkick
|
||||
user.verbs += /mob/proc/batrevive
|
||||
user.verbs += /mob/proc/batattack
|
||||
user.verbs += /mob/proc/batspinkick
|
||||
user.verbs += /mob/proc/batspin
|
||||
user.verbs += /mob/proc/batdropkick
|
||||
|
||||
/obj/item/clothing/suit/armor/batman/unequipped(var/mob/user)
|
||||
user.verbs -= /client/proc/batsmoke
|
||||
user.verbs -= /client/proc/batarang
|
||||
user.verbs -= /mob/proc/batkick
|
||||
user.verbs -= /mob/proc/batrevive
|
||||
user.verbs -= /mob/proc/batattack
|
||||
user.verbs -= /mob/proc/batspinkick
|
||||
user.verbs -= /mob/proc/batspin
|
||||
user.verbs -= /mob/proc/batdropkick
|
||||
|
||||
/client/proc/batsmoke()
|
||||
set category = "Batman"
|
||||
set name = "Batsmoke \[Support]"
|
||||
|
||||
var/datum/effects/system/bad_smoke_spread/smoke = new /datum/effects/system/bad_smoke_spread()
|
||||
smoke.set_up(10, 0, usr.loc)
|
||||
smoke.start()
|
||||
|
||||
/client/proc/batarang(mob/T as mob in oview())
|
||||
set category = "Batman"
|
||||
set name = "Batarang \[Combat]"
|
||||
|
||||
for(var/mob/O in viewers(usr, null))
|
||||
O.show_message(text("<span style=\"color:red\">[] tosses a batarang at []!</span>", usr, T), 1)
|
||||
var/obj/overlay/A = new /obj/overlay( usr.loc )
|
||||
A.icon_state = "batarang"
|
||||
A.icon = 'icons/effects/effects.dmi'
|
||||
A.name = "a batarang"
|
||||
A.anchored = 0
|
||||
A.density = 0
|
||||
var/i
|
||||
for(i=0, i<100, i++)
|
||||
step_to(A,T,0)
|
||||
if (get_dist(A,T) <= 1)
|
||||
T.weakened += 5
|
||||
T.stunned += 5
|
||||
for(var/mob/O in viewers(T, null))
|
||||
O.show_message(text("<span style=\"color:red\">[] was struck by the batarang!</span>", T), 1)
|
||||
qdel(A)
|
||||
sleep(2)
|
||||
qdel(A)
|
||||
return
|
||||
|
||||
/mob/proc/batkick(mob/T as mob in oview(1))
|
||||
set category = "Batman"
|
||||
set name = "Bat Kick \[Combat]"
|
||||
set desc = "A powerful stunning kick, sending people flying across the room"
|
||||
|
||||
spawn(0)
|
||||
if(T)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] powerfully kicks []!</B></span>", usr, T), 1)
|
||||
T.weakened += 6
|
||||
step_away(T,usr,15)
|
||||
sleep(1)
|
||||
step_away(T,usr,15)
|
||||
sleep(1)
|
||||
step_away(T,usr,15)
|
||||
playsound(T.loc, "swing_hit", 25, 1, -1)
|
||||
|
||||
/mob/proc/batrevive()
|
||||
set category = "Batman"
|
||||
set name = "Recover \[Support]"
|
||||
set desc = "Unstuns you"
|
||||
|
||||
if(!usr.weakened)
|
||||
usr.stunned = 0
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] suddenly recovers!</B></span>", usr), 1)
|
||||
else
|
||||
usr.weakened = 0
|
||||
usr.stunned = 0
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] suddenly jumps up!</B></span>", usr), 1)
|
||||
|
||||
/mob/proc/batattack(mob/T as mob in oview(1))
|
||||
set category = "Batman"
|
||||
set name = "Bat Punch \[Combat]"
|
||||
set desc = "Attack, but Batman-like ok"
|
||||
|
||||
if(usr.stat)
|
||||
boutput(usr, "<span style=\"color:red\">Not when you're incapped!</span>")
|
||||
return
|
||||
spawn(0)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] punches []!</B></span>", usr, T), 1)
|
||||
var/zone = "chest"
|
||||
if(usr.zone_sel)
|
||||
zone = usr.zone_sel.selecting
|
||||
if ((zone in list( "eyes", "mouth" )))
|
||||
zone = "head"
|
||||
T.TakeDamage(zone, 4, 0)
|
||||
T.stunned += 1
|
||||
var/icon/I = icon('icons/effects/effects.dmi',prob(50) ? "batpow" : "batwham")
|
||||
T.overlays += I
|
||||
spawn(50) T.overlays -= I
|
||||
T.updatehealth()
|
||||
|
||||
/mob/proc/batspinkick(mob/T as mob in oview(1))
|
||||
set category = "Batman"
|
||||
set name = "Batkick \[Finisher]"
|
||||
set desc = "A spinning kick that drops motherfuckers to the CURB"
|
||||
|
||||
var/icon/I = icon('icons/effects/effects.dmi',"batpow")
|
||||
var/icon/R = icon('icons/effects/effects.dmi', "batwham")
|
||||
if(usr.stat)
|
||||
boutput(usr, "<span style=\"color:red\">Not when you're incapped!</span>")
|
||||
return
|
||||
spawn(0)
|
||||
T.transforming = 1
|
||||
src.transforming = 1
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] leaps in the air, shocking []!</B></span>", usr, T), 1)
|
||||
for(var/i = 0, i < 5, i++)
|
||||
usr.pixel_y += 4
|
||||
sleep(2)
|
||||
sleep(10)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] begins kicking [] in the face rapidly!</B></span>", usr, T), 1)
|
||||
for(var/i = 0, i < 5, i++)
|
||||
usr.dir = NORTH
|
||||
T.TakeDamage("head", 4, 0)
|
||||
T.updatehealth()
|
||||
T.overlays -= R
|
||||
T.overlays += I
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] kicks [] in the face!</B></span>", usr, T), 1)
|
||||
playsound(T.loc, "swing_hit", 25, 1, -1)
|
||||
sleep(1)
|
||||
usr.dir = EAST
|
||||
T.TakeDamage("head", 4, 0)
|
||||
T.updatehealth()
|
||||
T.overlays -= I
|
||||
T.overlays += R
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] kicks [] in the face!</B></span>", usr, T), 1)
|
||||
playsound(T.loc, "swing_hit", 25, 1, -1)
|
||||
sleep(1)
|
||||
usr.dir = SOUTH
|
||||
T.TakeDamage("head", 4, 0)
|
||||
T.updatehealth()
|
||||
T.overlays -= R
|
||||
T.overlays += I
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] kicks [] in the face!</B></span>", usr, T), 1)
|
||||
playsound(T.loc, "swing_hit", 25, 1, -1)
|
||||
sleep(1)
|
||||
usr.dir = WEST
|
||||
T.TakeDamage("head", 4, 0)
|
||||
T.updatehealth()
|
||||
T.overlays -= I
|
||||
T.overlays += R
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] kicks [] in the face!</B></span>", usr, T), 1)
|
||||
playsound(T.loc, "swing_hit", 25, 1, -1)
|
||||
usr.dir = get_dir(usr, T)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] stares deeply at []!</B></span>", usr, T), 1)
|
||||
sleep(50)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] unleashes a tremendous kick to the jaw towards []!</B></span>", usr, T), 1)
|
||||
playsound(T.loc, "swing_hit", 25, 1, -1)
|
||||
flick("e_flash", T.flash)
|
||||
T.transforming = 0
|
||||
T.weakened += 6
|
||||
step_away(T,usr,15)
|
||||
sleep(1)
|
||||
step_away(T,usr,15)
|
||||
sleep(1)
|
||||
step_away(T,usr,15)
|
||||
sleep(1)
|
||||
step_away(T,usr,15)
|
||||
sleep(1)
|
||||
step_away(T,usr,15)
|
||||
T.TakeDamage("head", 70, 0)
|
||||
T.updatehealth()
|
||||
for(var/i = 0, i < 5, i++)
|
||||
usr.pixel_y += 10
|
||||
sleep(1)
|
||||
usr.set_loc(T.loc)
|
||||
usr.weakened = 10
|
||||
usr.transforming = 0
|
||||
for(var/i = 0, i < 5, i++)
|
||||
usr.pixel_y -= 8
|
||||
sleep(1)
|
||||
usr.pixel_y = 0
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] elbow drops [] into oblivion!</B></span>", usr, T), 1)
|
||||
T.gib()
|
||||
|
||||
/mob/proc/batspin(mob/T as mob in oview(1))
|
||||
set category = "Batman"
|
||||
set name = "Bat Spin \[Finisher]"
|
||||
set desc = "Grab someone and spin them around until they explode"
|
||||
|
||||
spawn(0)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] grabs [] tightly!</B></span>", usr, T), 1)
|
||||
usr.transforming = 1
|
||||
T.transforming = 1
|
||||
T.u_equip(l_hand)
|
||||
T.u_equip(r_hand)
|
||||
sleep(30)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] starts spinning [] around!</B></span>", usr, T), 1)
|
||||
for(var/i = 0, i < 2, i++)
|
||||
T.dir = NORTH
|
||||
sleep(5)
|
||||
T.dir = EAST
|
||||
sleep(5)
|
||||
T.dir = SOUTH
|
||||
sleep(5)
|
||||
T.dir = WEST
|
||||
sleep(5)
|
||||
for(var/i = 0, i < 1, i++)
|
||||
T.dir = NORTH
|
||||
sleep(2)
|
||||
T.dir = EAST
|
||||
sleep(2)
|
||||
T.dir = SOUTH
|
||||
sleep(2)
|
||||
T.dir = WEST
|
||||
sleep(2)
|
||||
boutput(T, "<span style=\"color:red\">YOU'RE GOING TOO FAST!!!</span>")
|
||||
for(var/i = 0, i < 10, i++)
|
||||
T.dir = NORTH
|
||||
sleep(1)
|
||||
T.dir = EAST
|
||||
sleep(1)
|
||||
T.dir = SOUTH
|
||||
sleep(1)
|
||||
T.dir = WEST
|
||||
sleep(1)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] suddenly explodes</B>!</span>", T), 1)
|
||||
T.gib()
|
||||
|
||||
/mob/proc/batdropkick(mob/T as mob in oview())
|
||||
set category = "Batman"
|
||||
set name = "Drop Kick \[Disabler]"
|
||||
set desc = "Fall to the ground, leap up and knock a dude out"
|
||||
|
||||
spawn(0)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] falls to the ground</B>!</span>", usr), 1)
|
||||
usr.weakened += 760 // lol whatever
|
||||
sleep(20)
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] launches towards []</B>!</span>", usr, T), 1)
|
||||
for(var/i=0, i<100, i++)
|
||||
step_to(usr,T,0)
|
||||
if (get_dist(usr,T) <= 1)
|
||||
T.weakened += 10
|
||||
T.stunned += 10
|
||||
for(var/mob/O in viewers(src, null))
|
||||
O.show_message(text("<span style=\"color:red\"><B>[] flies at [], slamming \him in the head</B>!</span>", usr, T), 1)
|
||||
usr.weakened = 0
|
||||
i=100
|
||||
sleep(1)
|
||||
|
||||
@@ -0,0 +1,799 @@
|
||||
/* ._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._. */
|
||||
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-ISSUES=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
|
||||
/* '~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~' */
|
||||
/*
|
||||
- healing spells for lings/etc should stop bleeding
|
||||
- iron and sugar have effects on blood: sugar reduces low blood_volume effects, research it & iron
|
||||
- Bleeding rework: if you have open surgical wounds your bleeding shouldn't drop to 0
|
||||
- Processor still needs to be finished.
|
||||
- Blood donation is better now with IVs, but the processor still could be useful
|
||||
- With how cheap sutures are to make, they need more drawbacks/bandages need less, so people actually have a reason to use bandages.
|
||||
- Vampires?? ??????
|
||||
- Open wounds, limb loss, etc need to bleed more/be more obvious that they're bleeding.
|
||||
- Maybe a rewrite to the limb system so it doesn't SUCK re: bugs and interaction with other systems. (medborgs not being able to remove limbs and crap like that - ???)
|
||||
*/
|
||||
/* ._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._. */
|
||||
/*-=-=-=-=-=-=-=-=-=-=-=-=-BLOOD-STUFF-=-=-=-=-=-=-=-=-=-=-=-=-*/
|
||||
/* '~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~' */
|
||||
|
||||
var/global/haine_blood_debug = 0
|
||||
|
||||
/client/proc/haine_blood_debug()
|
||||
set desc = "Toggle blood debug messages."
|
||||
set name = "Haine Blood Debug"
|
||||
set hidden = 1
|
||||
haine_blood_debug = !( haine_blood_debug )
|
||||
logTheThing("admin", usr, null, "toggled blood debug messages [haine_blood_debug ? "on" : "off"].")
|
||||
logTheThing("diary", usr, null, "toggled blood debug messages [haine_blood_debug ? "on" : "off"].", "admin")
|
||||
message_admins("[key_name(usr)] toggled blood debug messages [haine_blood_debug ? "on" : "off"]")
|
||||
|
||||
// for logging purposes
|
||||
/proc/dam_num2name(var/damtype)
|
||||
if (isnull(damtype))
|
||||
return "error"
|
||||
switch (damtype)
|
||||
if (DAMAGE_STAB)
|
||||
return "damage_stab"
|
||||
if (DAMAGE_CUT)
|
||||
return "damage_cut"
|
||||
if (DAMAGE_BLUNT)
|
||||
return "damage_blunt"
|
||||
if (DAMAGE_BURN)
|
||||
return "damage_burn"
|
||||
if (DAMAGE_CRUSH)
|
||||
return "damage_crush"
|
||||
return "error"
|
||||
|
||||
/* ._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._. */
|
||||
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=PROCS=-=-=-=-=-=-=-=-==-=-=-=-=-=*/
|
||||
/* '~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~' */
|
||||
/*
|
||||
---------- WHAT'S HERE ----------
|
||||
|
||||
take_bleeding_damage(mob/some_idiot, mob/some_jerk, damage, damage_type, bloodsplatter = 1, turf/T)
|
||||
|
||||
some_idiot is your target who takes the damage, some_jerk is the guy what did it to some_idiot
|
||||
for things that would cause bloodsplatter and increase bleeding
|
||||
- damage determines how much blood is lost
|
||||
- damage_types: DAMAGE_STAB, DAMAGE_CUT, DAMAGE_BLUNT, DAMAGE_BURN - these will affect the chance of increasing bleeding
|
||||
- bloodsplatter var just in case that needs to be taken care of elsewhere???
|
||||
if it's 0 it'll just remove [damage] from some_idiot's blood_volume without the decal appearing
|
||||
- T will pass a turf to bleed() in case you need the blood to appear in more places than just where some_idiot is
|
||||
if you don't give it T it defaults to some_idiot's turf
|
||||
- if the damage_type is DAMAGE_BURN and a bleeding increase doesn't occur, there's a chance that repair_bleeding_damage() will be triggered
|
||||
|
||||
----------
|
||||
|
||||
repair_bleeding_damage(mob/some_idiot, repair_chance, repair_amount)
|
||||
|
||||
for things that'll fix bleeding: sutures, bandages, etc
|
||||
- repair_chance will be affected by how much some_idiot is bleeding already: higher levels of bleeding have a better chance of repair
|
||||
- repair_amount should be 1-10, and will be subtracted from some_idiot's bleeding
|
||||
|
||||
----------
|
||||
|
||||
bleed(mob/some_idiot, num_amount, vis_amount, turf/T)
|
||||
|
||||
creates bloodsplatter on T, or if it isn't passed T, some_idiot's turf
|
||||
- num_amount is how much blood to lose
|
||||
- vis_amount is how much blood to spawn visually, 1-5 (see the dynamic blood decal in decal.dm for more info)
|
||||
I keep having to make this same thing over and over so this is just a timesaver for me
|
||||
you should probably use take_bleeding_damage() instead of this unless you have some need to make someone bleed without making their bleeding increase
|
||||
|
||||
----------
|
||||
|
||||
transfer_blood(mob/living/carbon/human/some_idiot, atom/A, amount)
|
||||
|
||||
take [amount] total blood and reagents (combined) out of some_idiot and transfer it into A
|
||||
currently used by syringes and IVs
|
||||
it removes blood from some_idiot's blood_volume and reagents from their reagent holder
|
||||
|
||||
----------
|
||||
|
||||
blood_slash(mob/some_idiot, bleed_amount, atom/A, direction, splatters = 4)
|
||||
|
||||
creates a trail of blood in either the direction provided, or, failing that, some_idiot's direction
|
||||
- bleed_amount is how much blood to lose FOR EACH BLOODSPLATTER + THE INITIAL ONE, this defaults to bleed_amount * 5
|
||||
- direction and A are optional in case you want to create the slash in a place/direction other than some_idiot's (ie some_idiot is inside something)
|
||||
- splatters is how many decals to spawn
|
||||
made for suicides where you cut your throat, but maybe you can find some other use for it
|
||||
|
||||
----------
|
||||
|
||||
animate_blood_damage(mob/some_idiot, mob/some_jerk)
|
||||
|
||||
WIP, doesn't work yet. you can ignore this.
|
||||
|
||||
----------
|
||||
|
||||
staunch_bleeding(mob/some_idiot)
|
||||
|
||||
a proc under /mob/living/carbon/human for putting pressure on wounds to stop bleeding.
|
||||
this is already used where it needs to be used, you can probably ignore it.
|
||||
|
||||
---------- END ---------- */
|
||||
|
||||
/* ============================================ */
|
||||
/* ---------- take_bleeding_damage() ---------- */
|
||||
/* ============================================ */
|
||||
|
||||
/proc/take_bleeding_damage(var/mob/some_idiot as mob, var/mob/some_jerk as mob, var/damage as num, var/damage_type = DAMAGE_CUT, var/bloodsplatter = 1, var/turf/T as turf)
|
||||
if (!T) // I forget why I set T as a variable OH WELL
|
||||
T = get_turf(some_idiot)
|
||||
|
||||
if (!blood_system)
|
||||
if (bloodsplatter) // we at least wanna create the decal anyway
|
||||
bleed(some_idiot, 0, 5, T)
|
||||
//animate_blood_damage(some_idiot, some_jerk)
|
||||
return
|
||||
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [some_idiot] begins bleed damage proc</b>")
|
||||
|
||||
if (!ishuman(some_idiot)) // maybe later borgs will bleed. not now though.
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [some_idiot] is not human so bleed damage was canceled</b>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = some_idiot
|
||||
|
||||
if (H.stat == 2 || H.nodamage || !H.can_bleed)
|
||||
if (H.bleeding)
|
||||
H.bleeding = 0
|
||||
H.bleeding_internal = 0
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] is dead or immortal or otherwise not supposed to bleed, so their bleeding has been set to 0 and bleed damage was canceled</b>")
|
||||
return
|
||||
|
||||
if ((!isvampire(H) && H.blood_volume > 0) || (isvampire(H) && H.get_vampire_blood() > 0)) // make sure we have blood to bleed
|
||||
if (bloodsplatter) // make sure we want to make bloodsplatter
|
||||
bleed(H, damage, 5, T) // actually bleed
|
||||
//animate_blood_damage(some_idiot, some_jerk)
|
||||
if (isvampire(H)) // we can go now, we don't need to do anything else for vamps
|
||||
return
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s blood level is [H.blood_volume]")
|
||||
|
||||
else
|
||||
H.bleeding = 0 // if we don't have any blood to bleed, just stop okay, just stop.
|
||||
H.bleeding_internal = 0
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] has no blood and their bleeding has been set to 0 and bleed damage was canceled</b>")
|
||||
return
|
||||
|
||||
if (H.bleeding >= 10) // don't bleed more if you're already at bleeding 10 tia
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H]'s bleeding was [H.bleeding] and has been set to 10 and bleed damage was canceled</b>")
|
||||
H.bleeding = 10
|
||||
return
|
||||
|
||||
var/increase_chance = rand(30, 50)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s initial increase chance is [increase_chance]")
|
||||
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s initial bleeding is [H.bleeding]")
|
||||
switch (H.bleeding)
|
||||
if (-INFINITY to 0)
|
||||
increase_chance += rand(30, 50)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
if (1 to 3)
|
||||
increase_chance += rand(20, 30)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
if (4 to 6)
|
||||
increase_chance += rand(5, 20)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
if (7 to 8)
|
||||
increase_chance += rand(0, 5)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
if (9 to INFINITY)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s bleeding was already high and chance was not increased")
|
||||
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s damage type is [dam_num2name(damage_type)]")
|
||||
switch (damage_type)
|
||||
if (DAMAGE_STAB)
|
||||
increase_chance += rand(0, 10)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
if (DAMAGE_CUT)
|
||||
increase_chance += rand(5, 20)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
if (DAMAGE_BLUNT)
|
||||
increase_chance -= rand(10, 30)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance decreased to [increase_chance]")
|
||||
if (DAMAGE_BURN)
|
||||
if (!H.is_heat_resistant())
|
||||
increase_chance -= rand(30, 50)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance decreased to [increase_chance]")
|
||||
|
||||
if (ischangeling(H))
|
||||
increase_chance -= rand(10, 20)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H] is a changeling - [H]'s increase chance decreased to [increase_chance]")
|
||||
/*
|
||||
if (isvampire(H))
|
||||
increase_chance -= rand(10, 20)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H] is a vampire - [H]'s increase chance decreased to [increase_chance]")
|
||||
*/
|
||||
if(H.traitHolder && H.traitHolder.hasTrait("hemophilia"))
|
||||
increase_chance *= 3
|
||||
|
||||
var/final_increase_chance = min(increase_chance, 100)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s final increase chance is [final_increase_chance]")
|
||||
if (prob(final_increase_chance))
|
||||
H.bleeding ++
|
||||
switch (H.bleeding)
|
||||
if (-INFINITY to 1)
|
||||
H.show_text("<b>You start bleeding!</b>", "red")
|
||||
if (1 to 8)
|
||||
if (prob(33))
|
||||
H.show_text("<b>You[pick(" start bleeding even worse", " start bleeding even more", " start bleeding more", "r bleeding worsens", "r bleeding gets worse")]!</b>", "red")
|
||||
if (9 to INFINITY)
|
||||
H.show_text("<b>You can't go on very long with blood pouring out of you like this!</b>", "red")
|
||||
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] rolls bleeding increase, bleeding is now [H.bleeding]</b>")
|
||||
else
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H]'s bleeding does not increase</b>")
|
||||
if (damage_type == DAMAGE_BURN && !H.is_heat_resistant() && H.bleeding > 0)
|
||||
if (prob(rand(30,50)))
|
||||
repair_bleeding_damage(H, rand(30,50), rand(1,3))
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] rolls bleeding repair due to DAMAGE_BURN</b>")
|
||||
|
||||
/* ============================================== */
|
||||
/* ---------- repair_bleeding_damage() ---------- */
|
||||
/* ============================================== */
|
||||
|
||||
/proc/repair_bleeding_damage(var/mob/some_idiot as mob, var/repair_chance as num, var/repair_amount as num)
|
||||
if (!blood_system)
|
||||
return
|
||||
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [some_idiot] begins bleeding repair</b>")
|
||||
|
||||
if (!ishuman(some_idiot)) // if they aren't human they shouldn't be able to bleed!!
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [some_idiot] is not human so repair was canceled</b>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = some_idiot
|
||||
|
||||
if (H.stat == 2)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] is dead and their bleeding has been set to 0 and repair was canceled</b>")
|
||||
H.bleeding = 0 // no just stop bleeding entirely okay, you're dead, stop it
|
||||
H.bleeding_internal = 0
|
||||
return
|
||||
|
||||
if (isvampire(H))
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] is a vampire and their bleeding has been set to 0 and repair was canceled</b>")
|
||||
H.bleeding = 0 // bleh im a vampar
|
||||
H.bleeding_internal = 0
|
||||
return
|
||||
|
||||
if (H.blood_volume <= 0)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] has no blood and their bleeding has been set to 0 and repair was canceled</b>")
|
||||
H.bleeding = 0 // you have no blood so stop trying to bleed
|
||||
H.bleeding_internal = 0
|
||||
return
|
||||
|
||||
if (repair_amount <= 0)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H]'s repair_amount was set as [repair_amount] so repair was canceled</b>")
|
||||
return // you wouldn't have done anything anyway
|
||||
|
||||
if (repair_chance < 100) // if it's already 100 we don't need to go through all the crap down here
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s initial repair chance is [repair_chance]")
|
||||
switch (H.bleeding)
|
||||
if (-INFINITY to 0)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H] isn't bleeding and repair has been stopped")
|
||||
return // there's nothing to fix here, go home
|
||||
if (1 to 2)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s bleeding was already low and chance was not increased")
|
||||
if (3 to 4)
|
||||
repair_chance += rand(0, 5)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s repair chance increased to [repair_chance]")
|
||||
if (5 to 7)
|
||||
repair_chance += rand(5, 20)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s repair chance increased to [repair_chance]")
|
||||
if (8 to 9)
|
||||
repair_chance += rand(20, 30)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s repair chance increased to [repair_chance]")
|
||||
if (10 to INFINITY)
|
||||
repair_chance += rand(30, 50)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s repair chance increased to [repair_chance]")
|
||||
|
||||
var/final_repair_chance = min(repair_chance, 100)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s final repair chance is [final_repair_chance]")
|
||||
|
||||
if (prob(final_repair_chance))
|
||||
H.bleeding -= repair_amount
|
||||
if (!H.bleeding && H.get_surgery_status())
|
||||
H.bleeding ++
|
||||
switch (H.bleeding)
|
||||
if (-INFINITY to 0)
|
||||
H.show_text("<b>Your bleeding stops!</b>", "red")
|
||||
if (1 to 8)
|
||||
switch (repair_amount)
|
||||
if (1 to 3)
|
||||
H.show_text("<b>Your bleeding [pick("slows", "slows down", "slightly slows", "slows a little", "gets slightly slower", "barely slows")]!</b>", "red")
|
||||
if (4 to 6)
|
||||
H.show_text("<b>Your bleeding [pick("slows", "slows down", "slows a lot", "slows down a lot", "really slows down")]!</b>", "red")
|
||||
if (7 to 10)
|
||||
H.show_text("<b>Your bleeding [pick("slows", "slows down", "slows a lot", "slows down a lot", "really slows down", "slows way down", "nearly stops", "has almost stopped", "is barely a trickle now")]!</b>", "red")
|
||||
if (9 to INFINITY)
|
||||
H.show_text("<b>You can't go on very long with blood pouring out of you like this!</b>", "red")
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H]'s bleeding repaired by [repair_amount], now [H.bleeding]</b>")
|
||||
if (H.bleeding < 0)
|
||||
H.bleeding = 0
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s bleeding dropped below 0 and was reset to 0")
|
||||
|
||||
else if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] rolled no repair</b>")
|
||||
|
||||
/* ============================= */
|
||||
/* ---------- bleed() ---------- */
|
||||
/* ============================= */
|
||||
|
||||
/proc/bleed(var/mob/living/some_idiot as mob, var/num_amount as num, var/vis_amount as num, var/turf/T as turf)
|
||||
|
||||
if (!T)
|
||||
T = get_turf(some_idiot)
|
||||
|
||||
var/mob/living/carbon/human/H = some_idiot
|
||||
|
||||
if (!blood_system) // we're here because we want to create a decal, so create it anyway
|
||||
|
||||
var/obj/decal/cleanable/blood/dynamic/B = locate(/obj/decal/cleanable/blood/dynamic) in T
|
||||
var/blood_color_to_pass = DEFAULT_BLOOD_COLOR
|
||||
|
||||
if (istype(H))
|
||||
blood_color_to_pass = H.blood_color
|
||||
|
||||
if (!B) // look for an existing dynamic blood decal and add to it if you find one
|
||||
B = new /obj/decal/cleanable/blood/dynamic(T)
|
||||
B.add_volume(blood_color_to_pass, vis_amount)
|
||||
else
|
||||
B.add_volume(blood_color_to_pass, vis_amount)
|
||||
if (some_idiot.blood_id)
|
||||
B.reagents.add_reagent(some_idiot.blood_id, num_amount)
|
||||
|
||||
if (istype(H))
|
||||
if (H.is_changeling())
|
||||
B.ling_blood = 1
|
||||
|
||||
if (some_idiot.bioHolder)
|
||||
B.blood_DNA = some_idiot.bioHolder.Uid
|
||||
B.blood_type = some_idiot.bioHolder.bloodType
|
||||
else
|
||||
B.blood_DNA = "--unidentified substance--"
|
||||
B.blood_type = "--unidentified substance--"
|
||||
|
||||
return
|
||||
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [some_idiot] begins bleed</b>")
|
||||
|
||||
if (!istype(H)) // if they aren't human they shouldn't be able to bleed!!
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [some_idiot] is not human so bleed was canceled</b>")
|
||||
return
|
||||
|
||||
|
||||
if (H.stat == 2 || H.nodamage || !H.can_bleed)
|
||||
if (H.bleeding)
|
||||
H.bleeding = 0 // stop that
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [some_idiot] is either dead, immortal, or has can_bleed disabled, so bleed was canceled</b>")
|
||||
return
|
||||
|
||||
if (isvampire(H)) // vampires should be special
|
||||
if (H.bleeding)
|
||||
H.bleeding = 0 // we don't need this to be anything above 0 for vamps
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [some_idiot] is a vampire with a bleeding above 0, so it was reset to 0</b>")
|
||||
|
||||
if ((!isvampire(H) && H.blood_volume > 0) || (isvampire(H) && H.get_vampire_blood() > 0)) // you shouldn't bleed unless you have blood okay
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> [H] blood level [H.blood_volume]")
|
||||
var/obj/decal/cleanable/blood/dynamic/B = locate(/obj/decal/cleanable/blood/dynamic) in T
|
||||
|
||||
if (!B) // look for an existing dynamic blood decal and add to it if you find one
|
||||
B = new /obj/decal/cleanable/blood/dynamic(T)
|
||||
B.add_volume(H.blood_color, vis_amount)
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> [H] creates new blood decal")
|
||||
else
|
||||
B.add_volume(H.blood_color, vis_amount)
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> [H] adds volume to existing blood decal")
|
||||
|
||||
if (H.is_changeling())
|
||||
B.ling_blood = 1
|
||||
|
||||
if (H.bleeding > 4 && B.reagents && B.reagents.total_volume < 90 && H.reagents && H.reagents.total_volume)
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> [H] transfers reagents to blood decal [log_reagents(H)]")
|
||||
H.reagents.trans_to(B, min(round(H.bleeding / 2, 1), 5))
|
||||
|
||||
B.blood_DNA = some_idiot.bioHolder.Uid
|
||||
B.blood_type = some_idiot.bioHolder.bloodType
|
||||
|
||||
if (isvampire(H))
|
||||
H.change_vampire_blood(-5) //num_amount // gunna go with a set number as a test
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [H] bleeds -5 from vamp_blood_remaining and their vamp_blood_remaining becomes [H.get_vampire_blood()]</b>")
|
||||
|
||||
else
|
||||
H.blood_volume -= num_amount // time to bleed
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [H] bleeds [num_amount] and their blood level becomes [H.blood_volume]</b>")
|
||||
|
||||
if (H.blood_volume < 0) // you shouldn't have negative blood okay
|
||||
H.blood_volume = 0
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s blood volume dropped below 0 and was reset to 0")
|
||||
else
|
||||
return
|
||||
|
||||
/* ====================================== */
|
||||
/* ---------- transfer_blood() ---------- */
|
||||
/* ====================================== */
|
||||
|
||||
/proc/transfer_blood(var/mob/living/some_idiot as mob, var/atom/A as obj|mob, var/amount = 5)
|
||||
if (!some_idiot || !A || !istype(some_idiot))
|
||||
return 0
|
||||
|
||||
var/mob/living/carbon/human/some_human_idiot = some_idiot // this is shit, but thenagain for SOME REASON a global proc is handling specifics of blood
|
||||
|
||||
if (!A.reagents || (!istype(some_human_idiot) && !some_idiot.reagents))
|
||||
return 0
|
||||
if (istype(some_human_idiot))
|
||||
if (isvampire(some_human_idiot) && (some_human_idiot.get_vampire_blood() <= 0) || (!isvampire(some_human_idiot) && !some_human_idiot.reagents && !some_human_idiot.blood_volume))
|
||||
return 0
|
||||
|
||||
var/reagents_to_transfer = (amount / 5) * 2
|
||||
var/blood_to_transfer = (amount - min(reagents_to_transfer, some_idiot.reagents.total_volume))
|
||||
|
||||
var/datum/bioHolder/bloodHolder = null
|
||||
|
||||
if (istype(some_human_idiot))
|
||||
if (isvampire(some_human_idiot) && (some_human_idiot.get_vampire_blood() < blood_to_transfer))
|
||||
blood_to_transfer = some_human_idiot.get_vampire_blood()
|
||||
|
||||
// Ignore that second container of blood entirely if it's a vampire (Convair880).
|
||||
if (!isvampire(some_human_idiot) && (some_human_idiot.blood_volume < blood_to_transfer))
|
||||
blood_to_transfer = some_human_idiot.blood_volume
|
||||
|
||||
bloodHolder = new/datum/bioHolder(null)
|
||||
bloodHolder.CopyOther(some_idiot.bioHolder)
|
||||
bloodHolder.ownerName = some_idiot.real_name
|
||||
|
||||
var/datum/reagent/R = null
|
||||
|
||||
if (ischangeling(some_idiot))
|
||||
A.reagents.add_reagent("bloodc", blood_to_transfer, bloodHolder)
|
||||
R = A.reagents.get_reagent("bloodc")
|
||||
else
|
||||
A.reagents.add_reagent(some_idiot.blood_id, blood_to_transfer, bloodHolder)
|
||||
R = A.reagents.get_reagent(some_idiot.blood_id)
|
||||
|
||||
if (R && (R.id == "blood" || R.id == "bloodc") && istype(some_human_idiot))
|
||||
var/datum/reagent/blood/B = R
|
||||
var/list/SP = A.reagents.aggregate_pathogens()
|
||||
for (var/uid in some_human_idiot.pathogens)
|
||||
if (!(uid in SP))
|
||||
var/datum/pathogen/P = unpool(/datum/pathogen)
|
||||
P.setup(0, some_human_idiot.pathogens[uid], 0)
|
||||
B.pathogens[uid] = P
|
||||
|
||||
if (istype(some_human_idiot))
|
||||
// Vampires can't use this trick to inflate their blood count, because they can't get more than ~30% of it back (Convair880).
|
||||
if (blood_system && (isvampire(some_human_idiot) && (some_human_idiot.get_vampire_blood() >= blood_to_transfer)))
|
||||
some_human_idiot.change_vampire_blood(-blood_to_transfer)
|
||||
|
||||
// Ignore that second container of blood entirely if it's a vampire (Convair880).
|
||||
if (blood_system && !isvampire(some_idiot) && (some_human_idiot.blood_volume >= blood_to_transfer))
|
||||
some_human_idiot.blood_volume -= blood_to_transfer
|
||||
|
||||
if (blood_to_transfer < amount)
|
||||
some_idiot.reagents.trans_to(A, (amount - blood_to_transfer))
|
||||
return 1
|
||||
|
||||
/* =================================== */
|
||||
/* ---------- blood_slash() ---------- */
|
||||
/* =================================== */
|
||||
|
||||
/proc/blood_slash(var/mob/some_idiot as mob, var/bleed_amount as num, var/atom/A as mob|obj|turf, var/direction, var/splatters = 4)
|
||||
|
||||
var/turf/target
|
||||
var/turf/end_target
|
||||
|
||||
if (!some_idiot) // what do you want and also what are you doing here?!
|
||||
if (haine_blood_debug) logTheThing("debug", null, null, "<b>HAINE BLOOD DEBUG:</b> blood_slash: not passed a mob, exiting")
|
||||
return
|
||||
|
||||
if (!ishuman(some_idiot)) // no stop trying to bleed you aren't human
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> blood_slash: passed non-human mob [some_idiot], exiting")
|
||||
return
|
||||
|
||||
if (!A) // if we aren't provided with a separate target, use some_idiot
|
||||
target = some_idiot.loc
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> blood_slash: no origin point specified, using [some_idiot]'s location")
|
||||
else
|
||||
target = A.loc
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> blood_slash: origin point set to [A]")
|
||||
|
||||
take_bleeding_damage(some_idiot, null, bleed_amount, DAMAGE_CUT, 1, target)
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> [some_idiot] enters take_bleeding_damage from blood_slash")
|
||||
|
||||
if (!direction) // if we aren't provided with a direction, use some_idiot again
|
||||
direction = some_idiot.dir
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> blood_slash: no direction specified, using [some_idiot]'s dir")
|
||||
|
||||
for (var/i = 0, i < splatters, i++)
|
||||
switch (direction)
|
||||
if (NORTH)
|
||||
end_target = locate(target.x, target.y+i, target.z)
|
||||
if (SOUTH)
|
||||
end_target = locate(target.x, target.y-i, target.z)
|
||||
if (EAST)
|
||||
end_target = locate(target.x+i, target.y, target.z)
|
||||
if (WEST)
|
||||
end_target = locate(target.x-i, target.y, target.z)
|
||||
bleed(some_idiot, bleed_amount, 5, end_target)
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG:</b> [some_idiot] enters bleed from blood_slash")
|
||||
|
||||
/* ============================================ */
|
||||
/* ---------- animate_blood_damage() ---------- */
|
||||
/* ============================================ */
|
||||
|
||||
//proc/animate_blood_damage(var/mob/some_idiot as mob, var/mob/some_jerk as mob)
|
||||
/*
|
||||
DEBUG("made it into proc")
|
||||
if (!some_idiot || !ishuman(some_idiot)) // what're we gunna do here?
|
||||
return 0
|
||||
|
||||
var/blood_color = DEFAULT_BLOOD_COLOR // default is #990000 atm, a dark-ish red.
|
||||
|
||||
if (ishuman(some_idiot)) // only humans have the blood_color var
|
||||
DEBUG("some_idiot [some_idiot] is human")
|
||||
blood_color = some_idiot:blood_color // they might have ~extra-fab blood~ so we wanna use whatever color they have
|
||||
|
||||
var/anim_offset_y = 0 // vertical offset
|
||||
var/anim_offset_x = 0 // horizontal offset
|
||||
|
||||
if (some_idiot.lying) // are we laying around on the floor like some kinda bum?
|
||||
DEBUG("some_idiot [some_idiot] is lying down")
|
||||
if (some_jerk) // our attacker, if we've got one
|
||||
switch (some_jerk.zone_sel.selecting) // where're they aiming?
|
||||
if ("head")
|
||||
DEBUG("some_jerk [some_jerk] is aiming at the head")
|
||||
anim_offset_y = rand(-2,-10)
|
||||
anim_offset_x = rand(6,12)
|
||||
if ("chest" || "l_arm" || "r_arm")
|
||||
DEBUG("some_jerk [some_jerk] is aiming at the chest/arms")
|
||||
anim_offset_y = rand(-2,-12)
|
||||
anim_offset_x = rand(8,15)
|
||||
if ("l_leg" || "r_leg")
|
||||
DEBUG("some_jerk [some_jerk] is aiming at the legs")
|
||||
anim_offset_y = rand(0,-12)
|
||||
anim_offset_x = rand(-7,-15)
|
||||
else // otherwise...
|
||||
DEBUG("some_jerk not passed")
|
||||
anim_offset_y = rand(7,-12)
|
||||
anim_offset_x = rand(8,-15)
|
||||
else // if we aren't on the ground
|
||||
DEBUG("some_idiot [some_idiot] is standing")
|
||||
if (some_jerk)
|
||||
switch (some_jerk.zone_sel.selecting)
|
||||
if ("head")
|
||||
DEBUG("some_jerk [some_jerk] is aiming at the head")
|
||||
anim_offset_y = rand(8,14)
|
||||
anim_offset_x = rand(-5,3)
|
||||
if ("chest" || "l_arm" || "r_arm")
|
||||
DEBUG("some_jerk [some_jerk] is aiming at the chest/arms")
|
||||
anim_offset_y = rand(-5,6)
|
||||
anim_offset_x = rand(-9,7)
|
||||
if ("l_leg" || "r_leg")
|
||||
DEBUG("some_jerk [some_jerk] is aiming at the legs")
|
||||
anim_offset_y = rand(-5,-15)
|
||||
anim_offset_x = rand(-7,-5)
|
||||
else
|
||||
DEBUG("some_jerk not passed")
|
||||
anim_offset_y = rand(-15,14)
|
||||
anim_offset_x = rand(-9,-7)
|
||||
|
||||
|
||||
some_idiot:damage_animation:icon_state = "bloodhit"
|
||||
some_idiot:damage_animation:pixel_y = anim_offset_y
|
||||
some_idiot:damage_animation:pixel_x = anim_offset_x
|
||||
some_idiot:damage_animation:color = blood_color
|
||||
some_idiot:damage_animation:transform = turn(some_idiot:damage_animation:transform, rand(0, 359))
|
||||
DEBUG("anim y [some_idiot:damage_animation:pixel_y], anim x [some_idiot:damage_animation:pixel_x], blood color [some_idiot:damage_animation:color]")
|
||||
|
||||
DEBUG("adding overlay")
|
||||
some_idiot.overlays += some_idiot:damage_animation
|
||||
spawn(15)
|
||||
DEBUG("removing overlay")
|
||||
some_idiot:damage_animation:icon_state = "blank"
|
||||
some_idiot.overlays -= some_idiot:damage_animation
|
||||
*/
|
||||
|
||||
/* ======================================== */
|
||||
/* ---------- staunch_bleeding() ---------- */
|
||||
/* ======================================== */
|
||||
|
||||
/mob/proc/staunch_bleeding(var/mob/some_idiot) // stolen from ISN's shake_awake() proc
|
||||
if (!src || !some_idiot)
|
||||
return 0
|
||||
|
||||
if (istype(some_idiot,/mob/living/carbon/human/))
|
||||
var/mob/living/carbon/human/H = some_idiot
|
||||
var/his_her = "[H.gender == "male" ? "his" : "her"]"
|
||||
|
||||
if (H.being_staunched)
|
||||
src.show_text("[H == src ? "You're" : "Someone's"] already putting pressure on [H == src ? "your" : "[H]'s"] wounds!", "red")
|
||||
return
|
||||
|
||||
if (H)
|
||||
H.add_fingerprint(src) // Just put 'em on the mob itself, like pulling does. Simplifies forensic analysis a bit (Convair880).
|
||||
|
||||
// if (H.w_uniform)
|
||||
// H.w_uniform.add_fingerprint(src)
|
||||
|
||||
H.being_staunched = 1
|
||||
|
||||
src.tri_message("<span style=\"color:blue\"><b>[src]</b> puts pressure on [src == H ? "[his_her]" : "[H]'s"] wounds, trying to stop the bleeding!</span>",\
|
||||
src, "<span style=\"color:blue\">You put pressure on [src == H ? "your" : "[H]'s"] wounds, trying to stop the bleeding!</span>",\
|
||||
H, "<span style=\"color:blue\">[H == src ? "You put" : "<b>[src]</b> puts"] pressure on your wounds, trying to stop the bleeding!</span>")
|
||||
|
||||
if (do_mob(src, H, 100))
|
||||
var/original_bleed = H.bleeding
|
||||
repair_bleeding_damage(H, 20, rand(1,2))
|
||||
|
||||
if (original_bleed > H.bleeding)
|
||||
switch (H.bleeding)
|
||||
if (-INFINITY to 0)
|
||||
src.show_text("The bleeding stops!", "blue")
|
||||
if (1 to 8)
|
||||
src.show_text("The bleeding slows!", "blue")
|
||||
if (9 to INFINITY)
|
||||
src.show_text("It barely helps!", "red")
|
||||
|
||||
else if (original_bleed == H.bleeding)
|
||||
src.show_text("The bleeding doesn't slow at all!", "red")
|
||||
|
||||
else if (original_bleed < H.bleeding) // what
|
||||
src.show_text("Oh fuck somehow the bleeding got WORSE!", "red")
|
||||
|
||||
H.being_staunched = 0
|
||||
return 1
|
||||
|
||||
else
|
||||
src.show_text("You were interrupted!", "red")
|
||||
H.being_staunched = 0
|
||||
return 0
|
||||
else
|
||||
return 0
|
||||
|
||||
/* ._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._. */
|
||||
/*-=-=-=-=-=-=-=-=-=-=-=INTERNAL-BLEEDING=-=-=-=-=-=-=-=-=-=-=-*/
|
||||
/* '~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~' */
|
||||
|
||||
/proc/internal_bleeding_damage(var/mob/some_idiot as mob, var/mob/some_jerk as mob, var/damage as num)
|
||||
if (!blood_system)
|
||||
return
|
||||
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [some_idiot] begins internal bleed damage proc</b>")
|
||||
|
||||
if (!ishuman(some_idiot)) // maybe later borgs will bleed. not now though.
|
||||
if (haine_blood_debug) logTheThing("debug", some_idiot, null, "<b>HAINE BLOOD DEBUG: [some_idiot] is not human so internal bleed damage was canceled</b>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = some_idiot
|
||||
|
||||
if (H.stat == 2 || H.nodamage || !H.can_bleed || isvampire(H))
|
||||
if (H.bleeding)
|
||||
H.bleeding = 0
|
||||
H.bleeding_internal = 0
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] is dead/immortal/a vampire/otherwise not supposed to bleed, so their bleeding has been set to 0 and internal bleed damage was canceled</b>")
|
||||
return
|
||||
|
||||
if (!(H.blood_volume > 0)) // make sure we have blood to bleed
|
||||
H.bleeding = 0 // if we don't have any blood to bleed, just stop okay, just stop.
|
||||
H.bleeding_internal = 0
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] has no blood and their bleeding has been set to 0 and internal bleed damage was canceled</b>")
|
||||
return
|
||||
|
||||
if (H.bleeding_internal >= 10) // don't bleed more if you're already at bleeding 10 tia
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H]'s internal bleeding was [H.bleeding_internal] and has been set to 10 and internal bleed damage was canceled</b>")
|
||||
H.bleeding_internal = 10
|
||||
return
|
||||
|
||||
var/increase_chance = rand(30, 50)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s initial increase chance is [increase_chance]")
|
||||
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s initial internal bleeding is [H.bleeding_internal]")
|
||||
switch (H.bleeding_internal)
|
||||
if (-INFINITY to 1)
|
||||
increase_chance += rand(30, 50)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
if (2)
|
||||
increase_chance += rand(20, 30)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
if (3)
|
||||
increase_chance += rand(5, 20)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
if (4)
|
||||
increase_chance += rand(0, 5)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
if (5 to INFINITY)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s internal bleeding was already high and chance was not increased")
|
||||
|
||||
if (some_jerk && some_jerk.zone_sel && some_jerk.zone_sel.selecting)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [some_jerk]'s target zone is [some_jerk.zone_sel.selecting]")
|
||||
switch (some_jerk.zone_sel.selecting)
|
||||
if ("head")
|
||||
increase_chance += rand(0, 10)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s increase chance increased to [increase_chance]")
|
||||
|
||||
if (ischangeling(H))
|
||||
increase_chance -= rand(10, 20)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H] is a changeling - [H]'s increase chance decreased to [increase_chance]")
|
||||
|
||||
var/final_increase_chance = min(increase_chance, 100)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG:</b> [H]'s final increase chance is [final_increase_chance]")
|
||||
if (prob(final_increase_chance))
|
||||
H.bleeding_internal ++
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H] rolls internal bleeding increase, internal bleeding is now [H.bleeding_internal]</b>")
|
||||
else
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H]'s internal bleeding does not increase</b>")
|
||||
H.bleeding_internal = minmax(H.bleeding_internal, 0, 5)
|
||||
if (haine_blood_debug) logTheThing("debug", H, null, "<b>HAINE BLOOD DEBUG: [H]'s internal bleeding is [H.bleeding_internal] after minmax</b>")
|
||||
|
||||
/* ._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._. */
|
||||
/*-=-=-=-=-=-=-=-=-=-=-=MEDICAL-EQUIPMENT=-=-=-=-=-=-=-=-=-=-=-*/
|
||||
/* '~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~' */
|
||||
|
||||
/* ---------- BLOOD PROCESSOR ---------- */
|
||||
|
||||
/* ._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._. */
|
||||
/*-=-=-=-=-=-=-=-=-=-=-=-=-TEST=-ITEMS=-=-=-=-=-=-=-=-=-=-=-=-=*/
|
||||
/* '~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~'-._.-'~' */
|
||||
|
||||
/obj/item/test_toilet
|
||||
name = "test toilet"
|
||||
desc = "this is for testing bleeding stuff"
|
||||
w_class = 1.0
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "toilet"
|
||||
flags = FPRINT | CONDUCT | TABLEPASS
|
||||
var/damage_type = DAMAGE_CUT
|
||||
|
||||
attack_self(mob/user as mob)
|
||||
var/selection = input("Select damage type", "Damage Type", "CUT") as anything in list("STAB", "CUT", "BLUNT", "BURN")
|
||||
if (!selection)
|
||||
return
|
||||
switch (selection)
|
||||
if ("STAB")
|
||||
src.damage_type = DAMAGE_STAB
|
||||
if ("CUT")
|
||||
src.damage_type = DAMAGE_CUT
|
||||
if ("BLUNT")
|
||||
src.damage_type = DAMAGE_BLUNT
|
||||
if ("BURN")
|
||||
src.damage_type = DAMAGE_BURN
|
||||
|
||||
attack(mob/M as mob, mob/user as mob)
|
||||
user.visible_message("<span class='combat'><b>[user]</b> attacks [M] with [src], set to <b>[dam_num2name(src.damage_type)]</b>!</span>", "<span class='combat'>You attack [M] with [src], set to <b>[src.damage_type]</b>!</span>")
|
||||
switch(src.damage_type)
|
||||
if (DAMAGE_STAB)
|
||||
playsound(M, 'sound/effects/bloody_stab.ogg', 30, 1)
|
||||
if (DAMAGE_CUT)
|
||||
playsound(M, 'sound/weapons/slashcut.ogg', 30, 1)
|
||||
if (DAMAGE_BLUNT)
|
||||
playsound(M, 'sound/weapons/smash.ogg', 30, 1)
|
||||
if (DAMAGE_BURN)
|
||||
playsound(M, 'sound/effects/mag_fireballlaunch.ogg', 30, 1)
|
||||
take_bleeding_damage(M, user, 1, src.damage_type)
|
||||
|
||||
/obj/item/test_dagger
|
||||
name = "test dagger"
|
||||
desc = "this is for testing bleeding stuff"
|
||||
w_class = 1.0
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "dagger"
|
||||
inhand_image_icon = 'icons/mob/inhand/hand_food.dmi'
|
||||
item_state = "knife"
|
||||
force = 0.0
|
||||
throwforce = 0.0
|
||||
throw_range = 16
|
||||
flags = FPRINT | TABLEPASS | NOSHIELD
|
||||
burn_type = 1
|
||||
|
||||
throw_impact(atom/A)
|
||||
if(iscarbon(A))
|
||||
if (istype(usr, /mob))
|
||||
A:lastattacker = usr
|
||||
A:lastattackertime = world.time
|
||||
playsound(A, 'sound/effects/bloody_stab.ogg', 60, 1)
|
||||
take_bleeding_damage(A, null, rand(2,3), DAMAGE_STAB)
|
||||
|
||||
attack(target as mob, mob/user as mob)
|
||||
..()
|
||||
playsound(target, 'sound/effects/bloody_stab.ogg', 60, 1)
|
||||
take_bleeding_damage(target, user, rand(2,3), DAMAGE_STAB)
|
||||
@@ -0,0 +1,657 @@
|
||||
/obj/abcuMarker
|
||||
name = "ABCU Marker"
|
||||
desc = "Denotes a valid tile."
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
name = "Building marker (valid)"
|
||||
icon_state = "bmarker"
|
||||
anchored = 1
|
||||
density = 0
|
||||
layer = TURF_LAYER
|
||||
|
||||
/obj/abcuMarker/red
|
||||
name = "ABCU Marker"
|
||||
desc = "Denotes an invalid tile."
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
name = "Building marker (invalid)"
|
||||
icon_state = "bmarkerred"
|
||||
anchored = 1
|
||||
density = 0
|
||||
layer = TURF_LAYER
|
||||
|
||||
/obj/machinery/abcu
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "builder"
|
||||
name = "Automated Blueprint Construction Unit (ABC-U)"
|
||||
desc = "This fine piece of machinery can construct entire rooms from blueprints."
|
||||
density = 1
|
||||
opacity = 0
|
||||
anchored = 0
|
||||
|
||||
var/invalidCount = 0
|
||||
|
||||
var/obj/item/blueprint/currentBp = null
|
||||
var/locked = 0
|
||||
var/building = 0
|
||||
|
||||
var/off_x = 0
|
||||
var/off_y = 0
|
||||
|
||||
var/list/markers = new/list()
|
||||
|
||||
New()
|
||||
..()
|
||||
UnsubscribeProcess()
|
||||
|
||||
attack_ai(mob/user)
|
||||
boutput(user, "<span style=\"color:red\">This machine is not linked to your network.</span>")
|
||||
return
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(istype(W, /obj/item/blueprint))
|
||||
if(currentBp)
|
||||
boutput(user, "<span style=\"color:red\">Theres already a blueprint in the machine.</span>")
|
||||
return
|
||||
else
|
||||
boutput(user, "<span style=\"color:blue\">You insert the blueprint into the machine.</span>")
|
||||
user.drop_item()
|
||||
W.set_loc(src)
|
||||
currentBp = W
|
||||
return
|
||||
else if (istype(W, /obj/item/sheet))
|
||||
boutput(user, "<span style=\"color:blue\">You insert the sheet into the machine.</span>")
|
||||
user.drop_item()
|
||||
W.set_loc(src)
|
||||
return
|
||||
return
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if(building)
|
||||
boutput(user, "<span style=\"color:red\">The machine is currently constructing something. Best not touch it until it's done.</span>")
|
||||
return
|
||||
|
||||
var/list/options = list(locked ? "Unlock":"Lock", "Begin Building", "Dump Materials", "Check Materials" ,currentBp ? "Eject Blueprint":null)
|
||||
var/input = input(usr,"Select option:","Option") in options
|
||||
switch(input)
|
||||
if("Unlock")
|
||||
if(!locked || building) return
|
||||
boutput(user, "<span style=\"color:blue\">The machine unlocks and shuts down.</span>")
|
||||
deactivate()
|
||||
|
||||
if("Lock")
|
||||
if(locked || building) return
|
||||
if(!currentBp)
|
||||
boutput(user, "<span style=\"color:red\">The machine requires a blueprint before it can be locked</span>")
|
||||
return
|
||||
boutput(user, "<span style=\"color:blue\">The machine locks into place and begins humming softly.</span>")
|
||||
activate()
|
||||
|
||||
if("Begin Building")
|
||||
if(building) return
|
||||
if(!locked)
|
||||
boutput(user, "<span style=\"color:red\">The machine must be locked into place before activating it.</span>")
|
||||
return
|
||||
if(!currentBp)
|
||||
boutput(user, "<span style=\"color:red\">The machine requires a blueprint before it can build anything.</span>")
|
||||
return
|
||||
build()
|
||||
|
||||
if("Eject Blueprint")
|
||||
if(building) return
|
||||
if(locked)
|
||||
boutput(user, "<span style=\"color:red\">Can not eject blueprint while machine is locked.</span>")
|
||||
return
|
||||
currentBp.set_loc(src.loc)
|
||||
currentBp = null
|
||||
|
||||
if("Dump Materials")
|
||||
if(building) return
|
||||
for(var/obj/o in src)
|
||||
if(o == currentBp) continue
|
||||
o.set_loc(src.loc)
|
||||
|
||||
if("Check Materials")
|
||||
if(building) return
|
||||
var/metal_cnt = 0
|
||||
var/glass_cnt = 0
|
||||
|
||||
for(var/obj/O in src)
|
||||
if(O == currentBp) continue
|
||||
if(istype(O, /obj/item/sheet))
|
||||
var/obj/item/sheet/S = O
|
||||
if (S.material)
|
||||
if (S.material.material_flags & MATERIAL_METAL)
|
||||
metal_cnt += S.amount
|
||||
if (S.material.material_flags & MATERIAL_CRYSTAL)
|
||||
glass_cnt += S.amount
|
||||
|
||||
boutput(user, "<span style=\"color:blue\">Currently loaded :</span>")
|
||||
boutput(user, "<span style=\"color:blue\">[metal_cnt] of [currentBp ? currentBp.req_metal : "-"] required metal</span>")
|
||||
boutput(user, "<span style=\"color:blue\">[glass_cnt] of [currentBp ? currentBp.req_glass : "-"] required glass</span>")
|
||||
return
|
||||
|
||||
proc/deactivate()
|
||||
for(var/obj/O in markers)
|
||||
qdel(O)
|
||||
locked = 0
|
||||
anchored = 0
|
||||
return
|
||||
|
||||
proc/activate()
|
||||
locked = 1
|
||||
anchored = 1
|
||||
invalidCount = 0
|
||||
for(var/datum/tileinfo/T in currentBp.roominfo)
|
||||
var/turf/pos = locate(text2num(T.posx) + src.x,text2num(T.posy) + src.y, src.z)
|
||||
var/obj/abcuMarker/O = null
|
||||
|
||||
if(istype(pos, /turf/space))
|
||||
O = new/obj/abcuMarker(pos)
|
||||
else
|
||||
O = new/obj/abcuMarker/red(pos)
|
||||
invalidCount++
|
||||
|
||||
markers.Add(O)
|
||||
boutput(usr, "<span style=\"color:blue\">Building this will require [currentBp.req_metal] metal and [currentBp.req_glass] glass sheets.</span>")
|
||||
return
|
||||
|
||||
proc/build()
|
||||
var/metal_cnt = 0
|
||||
var/glass_cnt = 0
|
||||
|
||||
if(invalidCount)
|
||||
boutput(usr, "<span style=\"color:red\">The machine can not build on anything but empty space. Check for red markers.</span>")
|
||||
return
|
||||
|
||||
for(var/obj/O in src)
|
||||
if(O == currentBp) continue
|
||||
if(istype(O, /obj/item/sheet))
|
||||
var/obj/item/sheet/S = O
|
||||
if (S.material)
|
||||
if (S.material.material_flags & MATERIAL_METAL)
|
||||
metal_cnt += S.amount
|
||||
if (S.material.material_flags & MATERIAL_CRYSTAL)
|
||||
glass_cnt += S.amount
|
||||
|
||||
if(metal_cnt < currentBp.req_metal || glass_cnt < currentBp.req_glass)
|
||||
boutput(usr, "<span style=\"color:red\">The machine buzzes in protest. Seems like it doesn't have enough material to work with.</span>")
|
||||
return
|
||||
|
||||
boutput(usr, "<span style=\"color:blue\">The machine starts to buzz and vibrate.</span>")
|
||||
|
||||
building = 1
|
||||
icon_state = "builder1"
|
||||
|
||||
spawn(0)
|
||||
|
||||
for(var/datum/tileinfo/T in currentBp.roominfo)
|
||||
var/turf/pos = locate(text2num(T.posx) + src.x,text2num(T.posy) + src.y, src.z)
|
||||
|
||||
var/obj/overlay/V = new/obj/overlay(pos)
|
||||
V.icon = 'icons/obj/objects.dmi'
|
||||
V.icon_state = "buildeffect"
|
||||
V.name = "energy"
|
||||
V.anchored = 1
|
||||
V.density = 0
|
||||
V.layer = EFFECTS_LAYER_BASE
|
||||
|
||||
sleep(15)
|
||||
|
||||
qdel(V)
|
||||
|
||||
for(var/obj/O in markers)
|
||||
if(O.loc == pos)
|
||||
qdel(O)
|
||||
break
|
||||
|
||||
for(var/datum/objectinfo/O in T.objects)
|
||||
if(O.objecttype == null) continue
|
||||
var/atom/A = new O.objecttype(pos)
|
||||
A.dir = O.direction
|
||||
A.layer = O.layer
|
||||
A.pixel_x = O.px
|
||||
A.pixel_y = O.py
|
||||
|
||||
if(T.tiletype != null)
|
||||
var/turf/newTile = new T.tiletype(pos)
|
||||
newTile.icon_state = T.state
|
||||
newTile.dir = T.direction
|
||||
|
||||
for(var/obj/J in src)
|
||||
qdel(J)
|
||||
|
||||
building = 0
|
||||
icon_state = "builder"
|
||||
makepowernets()
|
||||
qdel(src) //Blah
|
||||
|
||||
return
|
||||
|
||||
proc/splittext(txt as text, sep as text)
|
||||
var
|
||||
list/accum
|
||||
start;end
|
||||
|
||||
accum = new/list()
|
||||
start = 1
|
||||
do
|
||||
end = findtext(txt,sep,start)
|
||||
accum += copytext(txt,start,end)
|
||||
start = end + lentext(sep)
|
||||
while(end)
|
||||
return accum
|
||||
|
||||
/datum/objectinfo
|
||||
var/objecttype = null
|
||||
var/direction = 0
|
||||
var/layer = 0
|
||||
var/px = 0
|
||||
var/py = 0
|
||||
|
||||
/datum/tileinfo
|
||||
var/list/objects = new/list()
|
||||
var/state = ""
|
||||
var/direction = 0
|
||||
var/tiletype = null
|
||||
var/posx = 0
|
||||
var/posy = 0
|
||||
|
||||
/verb/adminCreateBlueprint()
|
||||
set name = "Create Blueprint"
|
||||
set desc = "Allows creation of blueprints of any user."
|
||||
set category = "Special Verbs"
|
||||
|
||||
var/list/bps = new/list()
|
||||
var/savefile/save = new/savefile("data/blueprints.dat")
|
||||
save.cd = "/"
|
||||
|
||||
for(var/curr in save.dir)
|
||||
save.cd = "/[curr]"
|
||||
bps.Add("[curr];[save["roomname"]]")
|
||||
|
||||
save.cd = "/"
|
||||
|
||||
var/input = input(usr,"Select save:","Blueprints") in bps
|
||||
var/list/split = splittext(input, ";")
|
||||
var/key = split[1]
|
||||
|
||||
if(save.dir.Find("[key]"))
|
||||
var/obj/item/blueprint/bp = new/obj/item/blueprint(get_turf(usr))
|
||||
|
||||
save.cd = "/[key]"
|
||||
boutput(usr, "<span style=\"color:blue\">Printed Blueprint for '[save["roomname"]]'</span>")
|
||||
var/roomname = save["roomname"]
|
||||
bp.size_x = save["sizex"]
|
||||
bp.size_y = save["sizey"]
|
||||
|
||||
for (var/A in save.dir)
|
||||
if(A == "sizex" || A == "sizey" || A == "roomname") continue
|
||||
save.cd = "/[key]/[A]"
|
||||
var/list/coords = splittext(A, ",")
|
||||
var/datum/tileinfo/tf = new/datum/tileinfo()
|
||||
tf.posx = coords[1]
|
||||
tf.posy = coords[2]
|
||||
tf.tiletype = save["type"]
|
||||
tf.state = save["state"]
|
||||
tf.direction = save["dir"]
|
||||
for (var/B in save.dir)
|
||||
if(B == "type" || B == "state") continue
|
||||
save.cd = "/[key]/[A]/[B]"
|
||||
var/datum/objectinfo/O = new/datum/objectinfo()
|
||||
O.objecttype = save["type"]
|
||||
O.direction = save["dir"]
|
||||
O.layer = save["layer"]
|
||||
O.px = save["pixelx"]
|
||||
O.py = save["pixely"]
|
||||
tf.objects.Add(O)
|
||||
bp.roominfo.Add(tf)
|
||||
bp.name = "Blueprint '[roomname]'"
|
||||
|
||||
|
||||
/obj/item/blueprint
|
||||
name = "Blueprint"
|
||||
desc = "A blueprint used to quickly construct rooms."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
|
||||
icon_state = "blueprint"
|
||||
item_state = "sheet"
|
||||
|
||||
var/req_metal = 0
|
||||
var/req_glass = 0
|
||||
|
||||
var/size_x = 0
|
||||
var/size_y = 0
|
||||
|
||||
var/list/roominfo = new/list()
|
||||
/*
|
||||
attack_self(mob/user as mob)
|
||||
for(var/datum/tileinfo/T in roominfo)
|
||||
var/turf/pos = locate(text2num(T.posx) + user.x,text2num(T.posy) + user.y, user.z) //Change
|
||||
//boutput(world, "[pos.x]-[pos.y]-[pos.z] # [pos]")
|
||||
for(var/datum/objectinfo/O in T.objects)
|
||||
//boutput(world, newObjType + " - " + O.objecttype)
|
||||
if(O.objecttype == null) continue
|
||||
var/atom/A = new O.objecttype(pos)
|
||||
A.dir = O.direction
|
||||
A.layer = O.layer
|
||||
A.pixel_x = O.px
|
||||
A.pixel_y = O.py
|
||||
|
||||
//boutput(world, newTilePath + " - " + T.tiletype)
|
||||
if(T.tiletype != null)
|
||||
var/turf/newTile = new T.tiletype(pos)
|
||||
newTile.icon_state = T.state
|
||||
|
||||
//rebuild powernets etc.
|
||||
*/
|
||||
|
||||
/obj/item/blueprint_marker
|
||||
name = "Blueprint Marker"
|
||||
desc = "A tool used to map rooms for the creation of blueprints."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
|
||||
icon_state = "blueprintmarker"
|
||||
item_state = "gun"
|
||||
|
||||
flags = FPRINT | EXTRADELAY | TABLEPASS | CONDUCT
|
||||
w_class = 2.0
|
||||
|
||||
var/prints_left = 5
|
||||
|
||||
var/mob/using = null
|
||||
|
||||
var/roomname = "NewRoom"
|
||||
var/list/roomList = new/list()
|
||||
|
||||
var/list/permittedObjectTypes = list(\
|
||||
"/obj/closet", \
|
||||
"/obj/stool", \
|
||||
"/obj/grille", \
|
||||
"/obj/window", \
|
||||
"/obj/machinery/door", \
|
||||
"/obj/cable", \
|
||||
"/obj/table", \
|
||||
"/obj/rack", \
|
||||
"/obj/structure",
|
||||
"/obj/disposalpipe", \
|
||||
"/obj/machinery/vending", \
|
||||
"/obj/machinery/light", \
|
||||
"/obj/machinery/door_control", \
|
||||
"/obj/machinery/light_switch", \
|
||||
"/obj/machinery/camera", \
|
||||
"/obj/item/device/radio/intercom", \
|
||||
"/obj/machinery/firealarm", \
|
||||
"/obj/machinery/power/apc", \
|
||||
"/obj/machinery/alarm", \
|
||||
"/obj/machinery/power/terminal", \
|
||||
"/obj/machinery/disposal", \
|
||||
"/obj/machinery/gibber",
|
||||
"/obj/machinery/floorflusher",
|
||||
"/obj/machinery/driver_button", \
|
||||
"/obj/machinery/door_control",
|
||||
"/obj/machinery/disposal",
|
||||
"/obj/submachine/chef_oven",
|
||||
"/obj/submachine/chef_sink",
|
||||
"/obj/machinery/launcher_loader",
|
||||
"/obj/machinery/optable",
|
||||
"/obj/machinery/mass_driver", \
|
||||
"/obj/reagent_dispensers", \
|
||||
"/obj/machinery/manufacturer", \
|
||||
"/obj/machinery/sleeper", \
|
||||
"/obj/machinery/sleep_console", \
|
||||
"/obj/submachine/slot_machine", \
|
||||
"/obj/machinery/deep_fryer",
|
||||
"/obj/submachine/ATM", \
|
||||
"/obj/submachine/slot_machine",
|
||||
"/obj/submachine/ice_cream_dispenser",
|
||||
"/obj/machinery/portable_atmospherics", \
|
||||
"/obj/machinery/ai_status_display",
|
||||
"/obj/noticeboard",
|
||||
"/obj/securearea",
|
||||
"/obj/submachine/mixer",
|
||||
"/obj/submachine/foodprocessor"
|
||||
)
|
||||
|
||||
var/list/permittedTileTypes = list("/turf/simulated")
|
||||
|
||||
var/savefile/save = new/savefile("data/blueprints.dat")
|
||||
|
||||
afterattack(atom/target as mob|obj|turf, mob/user as mob)
|
||||
if(get_dist(src,target) > 2) return
|
||||
|
||||
if(!isturf(target)) target = get_turf(target)
|
||||
|
||||
var/maxSize = 20
|
||||
|
||||
var/minx = 100000000
|
||||
var/miny = 100000000
|
||||
|
||||
var/maxx = 0
|
||||
var/maxy = 0
|
||||
|
||||
var/permitted = 0
|
||||
for(var/p in permittedTileTypes)
|
||||
var/type = text2path(p)
|
||||
if(istype(target, type))
|
||||
permitted = 1
|
||||
break
|
||||
|
||||
if(!permitted)
|
||||
boutput(user, "<span style=\"color:red\">Unsupported Tile type detected.</span>")
|
||||
return
|
||||
|
||||
for(var/a in roomList)
|
||||
var/turf/t = a
|
||||
if(t.x < minx) minx = t.x
|
||||
if(t.y < miny) miny = t.y
|
||||
|
||||
if(t.x > maxx) maxx = t.x
|
||||
if(t.y > maxy) maxy = t.y
|
||||
|
||||
//Do stuff
|
||||
|
||||
if(target.x < minx) minx = target.x
|
||||
if(target.y < miny) miny = target.y
|
||||
|
||||
if(target.x > maxx) maxx = target.x
|
||||
if(target.y > maxy) maxy = target.y
|
||||
|
||||
if(abs(minx - maxx) >= maxSize || abs(miny - maxy) >= maxSize)
|
||||
boutput(user, "<span style=\"color:red\">Tile exceeds maximum size of blueprint.</span>")
|
||||
return
|
||||
|
||||
if(roomList.Find(target))
|
||||
if (using && using.client)
|
||||
using.client.images -= roomList[target]
|
||||
roomList.Remove(target)
|
||||
else
|
||||
roomList.Add(target)
|
||||
roomList[target] = image('icons/misc/old_or_unused.dmi',target,"tiletag", layer = EFFECTS_LAYER_BASE)
|
||||
updateOverlays()
|
||||
|
||||
return
|
||||
|
||||
New()
|
||||
|
||||
return
|
||||
|
||||
proc/removeOverlays()
|
||||
if (using && using.client)
|
||||
for(var/a in roomList)
|
||||
var/image/i = roomList[a]
|
||||
using.client.images -= i
|
||||
return
|
||||
|
||||
proc/updateOverlays()
|
||||
if (using && using.client)
|
||||
removeOverlays()
|
||||
for(var/a in roomList)
|
||||
var/image/i = roomList[a]
|
||||
using.client.images += i
|
||||
return
|
||||
|
||||
proc/saveMarked(var/name = "", var/applyWhitelist = 1)
|
||||
save.cd = "/"
|
||||
if(save.dir.Find("[usr.client.ckey]" + name))
|
||||
save.dir.Remove("[usr.client.ckey]" + name)
|
||||
save.dir.Add("[usr.client.ckey]" + name)
|
||||
save.cd = "/[usr.client.ckey]" + name
|
||||
else
|
||||
save.dir.Add("[usr.client.ckey]" + name)
|
||||
save.cd = "/[usr.client.ckey]" + name
|
||||
|
||||
var/minx = 100000000
|
||||
var/miny = 100000000
|
||||
|
||||
var/maxx = 0
|
||||
var/maxy = 0
|
||||
|
||||
for(var/a in roomList)
|
||||
var/turf/t = a
|
||||
if(t.x < minx) minx = t.x
|
||||
if(t.y < miny) miny = t.y
|
||||
|
||||
if(t.x > maxx) maxx = t.x
|
||||
if(t.y > maxy) maxy = t.y
|
||||
|
||||
var/sizex = (maxx - minx) + 1
|
||||
var/sizey = (maxy - miny) + 1
|
||||
|
||||
save["sizex"] << sizex
|
||||
save["sizey"] << sizey
|
||||
save["roomname"] << roomname
|
||||
|
||||
for(var/atom/curr in roomList)
|
||||
var/posx = (curr.x - minx)
|
||||
var/posy = (curr.y - miny)
|
||||
|
||||
save.cd = "/[usr.client.ckey]" + name
|
||||
save.dir.Add("[posx],[posy]")
|
||||
save.cd = "/[usr.client.ckey][name]/[posx],[posy]"
|
||||
save["type"] << curr.type
|
||||
save["dir"] << curr.dir
|
||||
save["state"] << curr.icon_state
|
||||
|
||||
for(var/obj/o in curr)
|
||||
if (istype(o, /obj/disposalpipe/loafer)) // Sorry.
|
||||
continue
|
||||
var/permitted = 0
|
||||
for(var/p in permittedObjectTypes)
|
||||
var/type = text2path(p)
|
||||
if(istype(o, type))
|
||||
permitted = 1
|
||||
break
|
||||
if(permitted || !applyWhitelist)
|
||||
var/id = "\ref[o]"
|
||||
save.cd = "/[usr.client.ckey][name]/[posx],[posy]"
|
||||
while(save.dir.Find(id))
|
||||
id = id + "I"
|
||||
save.dir.Add("[id]")
|
||||
save.cd = "/[usr.client.ckey][name]/[posx],[posy]/[id]"
|
||||
save["dir"] << o.dir
|
||||
save["type"] << o.type
|
||||
save["layer"] << o.layer
|
||||
save["pixelx"] << o.pixel_x
|
||||
save["pixely"] << o.pixel_y
|
||||
return
|
||||
|
||||
proc/printSaved(var/name = "")
|
||||
save.cd = "/"
|
||||
if(save.dir.Find("[usr.client.ckey]" + name))
|
||||
var/obj/item/blueprint/bp = new/obj/item/blueprint(get_turf(src))
|
||||
prints_left--
|
||||
|
||||
save.cd = "/[usr.client.ckey]" + name
|
||||
boutput(usr, "<span style=\"color:blue\">Printed Blueprint for '[save["roomname"]]'</span>")
|
||||
var/roomname = save["roomname"]
|
||||
bp.size_x = save["sizex"]
|
||||
bp.size_y = save["sizey"]
|
||||
|
||||
for (var/A in save.dir)
|
||||
if(A == "sizex" || A == "sizey" || A == "roomname") continue
|
||||
save.cd = "/[usr.client.ckey][name]/[A]"
|
||||
var/list/coords = splittext(A, ",")
|
||||
var/datum/tileinfo/tf = new/datum/tileinfo()
|
||||
tf.posx = coords[1]
|
||||
tf.posy = coords[2]
|
||||
tf.tiletype = save["type"]
|
||||
tf.state = save["state"]
|
||||
tf.direction = save["dir"]
|
||||
bp.req_metal += 1.0
|
||||
bp.req_glass += 0.5
|
||||
for (var/B in save.dir)
|
||||
if(B == "type" || B == "state") continue
|
||||
save.cd = "/[usr.client.ckey][name]/[A]/[B]"
|
||||
var/datum/objectinfo/O = new/datum/objectinfo()
|
||||
O.objecttype = save["type"]
|
||||
O.direction = save["dir"]
|
||||
O.layer = save["layer"]
|
||||
O.px = save["pixelx"]
|
||||
O.py = save["pixely"]
|
||||
bp.req_metal += 0.9
|
||||
bp.req_glass += 1.5
|
||||
tf.objects.Add(O)
|
||||
bp.roominfo.Add(tf)
|
||||
bp.name = "Blueprint '[roomname]'"
|
||||
bp.req_metal = round(bp.req_metal)
|
||||
bp.req_glass = round(bp.req_glass)
|
||||
return
|
||||
else
|
||||
boutput(usr, "<span style=\"color:red\">No blueprint found for user.</span>")
|
||||
return
|
||||
|
||||
attack_self(mob/user as mob)
|
||||
var/list/options = list("Reset", "Set Blueprint Name", "Print Saved Blueprint", "Save Blueprint", "Information")
|
||||
var/input = input(usr,"Select option:","Option") in options
|
||||
|
||||
switch(input)
|
||||
if("Reset")
|
||||
boutput(user, "<span style=\"color:blue\">Resetting ...</span>")
|
||||
removeOverlays()
|
||||
roomList.Cut()
|
||||
|
||||
if("Set Blueprint Name")
|
||||
roomname = copytext(strip_html(input(user,"Set Blueprint Name:","Setup",roomname) as text), 1, 257)
|
||||
boutput(user, "<span style=\"color:blue\">Name set to '[roomname]'</span>")
|
||||
|
||||
//if("Create Clone Blueprint")
|
||||
// saveMarked("_temp", 1)
|
||||
// printSaved("_temp")
|
||||
// return
|
||||
|
||||
if("Print Saved Blueprint")
|
||||
if(prints_left <= 0)
|
||||
boutput(user, "<span style=\"color:red\">Out of energy.</span>")
|
||||
return
|
||||
printSaved()
|
||||
return
|
||||
|
||||
if("Save Blueprint")
|
||||
saveMarked()
|
||||
return
|
||||
|
||||
if("Information")
|
||||
var/message = "<span style=\"color:blue\">Blueprint Marker Tool Usage Information:</span><br><br>"
|
||||
message += "<span style=\"color:blue\">Reset: Resets the tools and clears all marked areas.</span><br>"
|
||||
message += "<span style=\"color:blue\">Set Blueprint Name: Allows you to set the name that will appear on the blueprint.</span><br>"
|
||||
//message += "<span style=\"color:blue\">Create Clone Blueprint: Creates a blueprint for an exact copy of the marked area. This type of blueprint can not be saved and costs slightly more to build.</span><br>"
|
||||
message += "<span style=\"color:blue\">Print Saved Blueprint: Prints a previously saved blueprint.</span><br>"
|
||||
message += "<span style=\"color:blue\">Save Blueprint: Saves a blueprint of the marked area to the server. This type of blueprint can be saved but it can not save all types of objects.</span>"
|
||||
boutput(user, message)
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
dropped(mob/user as mob)
|
||||
removeOverlays()
|
||||
using = null
|
||||
return
|
||||
|
||||
pickup(mob/user)
|
||||
using = user
|
||||
updateOverlays()
|
||||
return
|
||||
|
||||
equipped(var/mob/user, var/slot)
|
||||
using = user
|
||||
updateOverlays()
|
||||
return
|
||||
@@ -0,0 +1,104 @@
|
||||
|
||||
#define BONE_HEALTHY 0
|
||||
#define BONE_BRUISED 1
|
||||
#define BONE_CRACKED 2
|
||||
#define BONE_FRACTURED 4
|
||||
#define BONE_SHATTERED 8
|
||||
|
||||
/* sticking these here just for reference
|
||||
#define DAMAGE_BLUNT 1
|
||||
#define DAMAGE_CUT 2
|
||||
#define DAMAGE_STAB 4
|
||||
#define DAMAGE_BURN 8
|
||||
#define DAMAGE_CRUSH 16
|
||||
*/
|
||||
/proc/bone_num2name(var/damtype)
|
||||
if (isnull(damtype))
|
||||
return "error"
|
||||
switch (damtype)
|
||||
if (BONE_HEALTHY)
|
||||
return "bone_healthy"
|
||||
if (BONE_BRUISED)
|
||||
return "bone_bruised"
|
||||
if (BONE_CRACKED)
|
||||
return "bone_cracked"
|
||||
if (BONE_FRACTURED)
|
||||
return "bone_fractured"
|
||||
if (BONE_SHATTERED)
|
||||
return "bone_shattered"
|
||||
return "error"
|
||||
|
||||
#define BONE_DEBUG(x) if (bone_system) message_coders(x)
|
||||
|
||||
/datum/bone
|
||||
var/name = "bone" // what we are
|
||||
var/mob/living/carbon/human/donor = null // our house
|
||||
var/parent_organ = null // where we are in our house
|
||||
var/damage = 0 // how many times we've stubbed our toe on that table we hate
|
||||
var/damage_status = 0 // puts us into groups of table hatred
|
||||
|
||||
proc/take_damage(var/damage_type, var/amt = 1)
|
||||
if (!bone_system)
|
||||
return 0
|
||||
|
||||
if (!donor || !src.parent_organ) // I can't see a reason we'd still need to damage this thing if it's just kinda floating in the void somewhere
|
||||
BONE_DEBUG("a bone datum lacks a donor or parent_organ so take_damage() was canceled, oops")
|
||||
return 0 // ghostbones
|
||||
|
||||
BONE_DEBUG("[donor]'s [parent_organ]'s bones.take_damage() entered")
|
||||
|
||||
var/damtype_modifier = 1
|
||||
if (damage_type == DAMAGE_BURN)
|
||||
damtype_modifier = 0.6
|
||||
else if (damage_type == DAMAGE_STAB)
|
||||
damtype_modifier = 0.6
|
||||
else if (damage_type == DAMAGE_BLUNT)
|
||||
damtype_modifier = 1.3
|
||||
else if (damage_type == DAMAGE_CRUSH)
|
||||
damtype_modifier = 1.5
|
||||
|
||||
if (!((amt * damtype_modifier) > 0))
|
||||
return 0
|
||||
|
||||
BONE_DEBUG("[donor]'s [parent_organ]'s bones.take_damage() amt: [amt], damage_type: [dam_num2name(damage_type)], damtype_modifier: [damtype_modifier], initial bone damage: [src.damage], damage changing to [src.damage + (amt * damtype_modifier)], initial damage_status: [bone_num2name(src.damage_status)]")
|
||||
src.damage += (amt * damtype_modifier)
|
||||
|
||||
if (prob((10 + src.damage) * damtype_modifier))
|
||||
src.damage_status = max(1, src.damage_status * 2) // a chance to bump up the current damage_status level
|
||||
BONE_DEBUG("[donor]'s [parent_organ]'s bones rolled increase in damage level at prob (20 + [src.damage]) * [damtype_modifier] = [(20 + src.damage) * damtype_modifier]")
|
||||
|
||||
switch (src.damage_status)
|
||||
if (BONE_HEALTHY)
|
||||
BONE_DEBUG("[donor]'s [parent_organ]'s bones bruised")
|
||||
src.damage_status = BONE_BRUISED
|
||||
src.donor.show_text("Your [src.parent_organ] hurts!", "red")
|
||||
|
||||
if (BONE_BRUISED)
|
||||
BONE_DEBUG("[donor]'s [parent_organ]'s bones cracked")
|
||||
src.damage_status = BONE_CRACKED
|
||||
src.donor.show_text("Your [src.parent_organ] hurts like hell!", "red")
|
||||
|
||||
if (BONE_CRACKED)
|
||||
BONE_DEBUG("[donor]'s [parent_organ]'s bones fractured")
|
||||
src.damage_status = BONE_FRACTURED
|
||||
src.donor.visible_message("<span style='color:red'>[src.donor]'s [src.parent_organ] emits a [pick("", "disturbing ", "unsettling ", "worrying ")][pick("crack", "crunch", "snap")]!</span>",\
|
||||
"<span style='color:red'><b>You feel something in your [src.parent_organ] break!</b></span>")
|
||||
|
||||
if (BONE_FRACTURED)
|
||||
BONE_DEBUG("[donor]'s [parent_organ]'s bones shattered")
|
||||
src.damage_status = BONE_SHATTERED
|
||||
src.donor.visible_message("<span style='color:red'>[src.donor]'s [src.parent_organ] emits a [pick("", "disturbing ", "unsettling ", "worrying ")][pick("crack", "crunch", "snap")]!</span>",\
|
||||
"<span style='color:red'><b>You feel something in your [src.parent_organ] shatter!</b></span>")
|
||||
|
||||
proc/repair_damage(var/amt)
|
||||
if (!amt)
|
||||
return 0
|
||||
if (istext(amt) && lowertext(amt) == "all")
|
||||
src.damage = 0
|
||||
src.damage_status = BONE_HEALTHY
|
||||
|
||||
#undef BONE_HEALTHY
|
||||
#undef BONE_BRUISED
|
||||
#undef BONE_CRACKED
|
||||
#undef BONE_FRACTURED
|
||||
#undef BONE_SHATTERED
|
||||
@@ -0,0 +1,120 @@
|
||||
/turf/simulated/bowling
|
||||
name = "floor"
|
||||
icon = 'bowling.dmi'
|
||||
icon_state = "bowling_floor"
|
||||
|
||||
wet = 2
|
||||
|
||||
Entered(atom/movable/entered as mob|obj)
|
||||
if (ismob(entered))
|
||||
var/mob/M = entered
|
||||
if (M.weakened<4 && !M.lying)
|
||||
M.pulling = null
|
||||
random_brute_damage(M, 5)
|
||||
M.weakened = max(8, M.weakened)
|
||||
|
||||
if (M.client)
|
||||
M.show_message("<span style=\"color:blue\">You slipped on the floor!</span>")
|
||||
|
||||
playsound(src.loc, "sound/misc/slip.ogg", 50, 1, -3)
|
||||
|
||||
spawn(0.1)
|
||||
step(M, M.dir)
|
||||
|
||||
else
|
||||
var/obj/O = entered
|
||||
spawn(0.1)
|
||||
step(O, O.dir)
|
||||
|
||||
/obj/machinery/gutter
|
||||
density = 1
|
||||
flags = NOSPLASH
|
||||
anchored = 1
|
||||
|
||||
name = "gutter"
|
||||
icon = 'bowling.dmi'
|
||||
icon_state = "bowling_gutter"
|
||||
|
||||
var/datum/gas_mixture/air_contents
|
||||
var/obj/disposalpipe/trunk/trunk = null
|
||||
|
||||
var/mode = 1
|
||||
|
||||
New()
|
||||
..()
|
||||
spawn(0)
|
||||
src.link_gutter()
|
||||
|
||||
proc/link_gutter()
|
||||
trunk = locate() in src.loc
|
||||
if(!trunk)
|
||||
mode = 0
|
||||
//icon_state = "" //broken, no trunk
|
||||
else
|
||||
trunk.linked = src // link the pipe trunk to self
|
||||
//icon_state = "bowling_gutter"
|
||||
|
||||
if(!air_contents)
|
||||
air_contents = unpool(/datum/gas_mixture)
|
||||
|
||||
disposing()
|
||||
if(air_contents)
|
||||
pool(air_contents)
|
||||
air_contents = null
|
||||
..()
|
||||
|
||||
Bumped(atom/movable/bumper as mob|obj)
|
||||
if (mode)
|
||||
if (ismob(bumper))
|
||||
var/mob/living/M = bumper
|
||||
M.set_loc(src)
|
||||
boutput(M, "You fall into the [src]!")
|
||||
for(var/mob/V in viewers(src))
|
||||
if (V.client)
|
||||
V.show_message("[M] falls into the [src]!", 3)
|
||||
|
||||
else
|
||||
var/obj/O = bumper
|
||||
O.set_loc(src)
|
||||
|
||||
flush()
|
||||
|
||||
relaymove(atom/movable/mover as mob|obj)
|
||||
return
|
||||
|
||||
proc/flush()
|
||||
var/obj/disposalholder/H = new() // virtual holder object which actually
|
||||
// travels through the pipes.
|
||||
|
||||
H.init(src) // copy the contents of disposer to holder
|
||||
H.start(src)
|
||||
|
||||
proc/expel(var/obj/disposalholder/H)
|
||||
|
||||
var/turf/target
|
||||
for(var/atom/movable/AM in H)
|
||||
target = get_offset_target_turf(src.loc, rand(5)-rand(5), rand(5)-rand(5))
|
||||
|
||||
AM.set_loc(src.loc)
|
||||
AM.pipe_eject(0)
|
||||
spawn(1)
|
||||
if(AM)
|
||||
AM.throw_at(target, 5, 1)
|
||||
|
||||
H.vent_gas(loc)
|
||||
qdel(H)
|
||||
|
||||
alter_health()
|
||||
return get_turf(src)
|
||||
|
||||
/turf/simulated/floor/pin
|
||||
name = "pin"
|
||||
icon = 'bowling.dmi'
|
||||
icon_state = "pin"
|
||||
|
||||
Enter(atom/movable/mover as mob|obj)
|
||||
if (ismob(mover))
|
||||
var/mob/M = mover
|
||||
if (M.client)
|
||||
M.show_message("You hit [src]!", 3) //You get stuck here, turf is solid for some reason. Had a headache and didn't want to try to figure it out.
|
||||
..(mover)
|
||||
@@ -0,0 +1,179 @@
|
||||
/obj/decal/fakeobjects/carcosa/statue
|
||||
name = "statue"
|
||||
desc = "A statue of some ominous looking, robed, figure. There's barely a scratch on it."
|
||||
icon = 'icons/obj/64x64.dmi'
|
||||
icon_state = "statue"
|
||||
anchored = 1
|
||||
density = 1
|
||||
layer = 4
|
||||
bound_height = 32
|
||||
bound_width = 64
|
||||
/obj/decal/fakeobjects/carcosa/statue/broken
|
||||
name = "broken statue"
|
||||
desc = "A statue of some ominous looking, robed, figure. It's badly damaged."
|
||||
icon_state = "statue_broken"
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/tree
|
||||
name = "tree"
|
||||
desc = "A dead tree."
|
||||
icon = 'icons/obj/64x64.dmi'
|
||||
icon_state = "tree1"
|
||||
anchored = 1
|
||||
density = 1
|
||||
layer = 4
|
||||
bound_height = 32
|
||||
bound_width = 64
|
||||
/obj/decal/fakeobjects/carcosa/tree/one
|
||||
icon_state = "tree1"
|
||||
/obj/decal/fakeobjects/carcosa/tree/two
|
||||
icon_state = "planthuge1"
|
||||
/obj/decal/fakeobjects/carcosa/tree/three
|
||||
icon_state = "planthuge2"
|
||||
/obj/decal/fakeobjects/carcosa/tree/four
|
||||
icon_state = "planthuge3"
|
||||
/obj/decal/fakeobjects/carcosa/tree/five
|
||||
icon_state = "planthuge4"
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/brokenwall
|
||||
name = "broken wall"
|
||||
desc = "A broken wall."
|
||||
icon = 'icons/obj/64x64.dmi'
|
||||
icon_state = "cwall1"
|
||||
anchored = 1
|
||||
density = 1
|
||||
bound_height = 32
|
||||
bound_width = 64
|
||||
/obj/decal/fakeobjects/carcosa/brokenwall/one
|
||||
icon_state = "cwall1"
|
||||
/obj/decal/fakeobjects/carcosa/brokenwall/two
|
||||
icon_state = "cwall2"
|
||||
/obj/decal/fakeobjects/carcosa/brokenwall/three
|
||||
icon_state = "cwall3"
|
||||
/obj/decal/fakeobjects/carcosa/brokenwall/four
|
||||
icon_state = "cwall4"
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/brokenwall/up_one
|
||||
icon_state = "wallcont1"
|
||||
bound_height = 64
|
||||
bound_width = 32
|
||||
bound_x = 32
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/brokenwall/up_two
|
||||
icon_state = "wallcont2"
|
||||
bound_height = 64
|
||||
bound_width = 32
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/brokenwall/ruined_one
|
||||
icon_state = "wallruin1"
|
||||
bound_height = 32
|
||||
bound_width = 32
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/brokenwall/ruined_two
|
||||
icon_state = "wallruin2"
|
||||
bound_height = 32
|
||||
bound_width = 32
|
||||
bound_x = 32
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/brokenwall/arch_one
|
||||
icon_state = "carch1"
|
||||
name = "crumbling arches"
|
||||
desc = "An archway, It's a bit crumbly."
|
||||
density = 0
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/grtrans
|
||||
name = ""
|
||||
desc = ""
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "empty"
|
||||
anchored = 1
|
||||
density = 0
|
||||
/obj/decal/fakeobjects/carcosa/grtrans/west
|
||||
icon_state = "grtransW"
|
||||
/obj/decal/fakeobjects/carcosa/grtrans/east
|
||||
icon_state = "grtransE"
|
||||
/obj/decal/fakeobjects/carcosa/grtrans/north
|
||||
icon_state = "grtransN"
|
||||
/obj/decal/fakeobjects/carcosa/grtrans/south
|
||||
icon_state = "grtransS"
|
||||
/obj/decal/fakeobjects/carcosa/grtrans/northeast
|
||||
icon_state = "grtransNE"
|
||||
/obj/decal/fakeobjects/carcosa/grtrans/southeast
|
||||
icon_state = "grtransSE"
|
||||
/obj/decal/fakeobjects/carcosa/grtrans/southwest
|
||||
icon_state = "grtransSW"
|
||||
/obj/decal/fakeobjects/carcosa/grtrans/northwest
|
||||
icon_state = "grtransNW"
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/rubble
|
||||
name = "rubble"
|
||||
desc = "Bits of stone and various other debris."
|
||||
icon = 'icons/obj/64x64.dmi'
|
||||
icon_state = "empty"
|
||||
anchored = 1
|
||||
density = 0
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/rubble/one
|
||||
icon_state = "crubble1"
|
||||
/obj/decal/fakeobjects/carcosa/rubble/two
|
||||
icon_state = "crubble2"
|
||||
/obj/decal/fakeobjects/carcosa/rubble/three
|
||||
icon_state = "crubble3"
|
||||
|
||||
/obj/decal/fakeobjects/carcosa/carcosa_plant
|
||||
name = "alien plant"
|
||||
desc = "A strange looking plant."
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "empty"
|
||||
anchored = 1
|
||||
density = 0
|
||||
/obj/decal/fakeobjects/carcosa/carcosa_plant/one
|
||||
icon_state = "aplant1"
|
||||
/obj/decal/fakeobjects/carcosa/carcosa_plant/two
|
||||
icon_state = "aplant2"
|
||||
/obj/decal/fakeobjects/carcosa/carcosa_plant/three
|
||||
icon_state = "aplant3"
|
||||
/obj/decal/fakeobjects/carcosa/carcosa_plant/four
|
||||
icon_state = "aplant4"
|
||||
/obj/decal/fakeobjects/carcosa/carcosa_plant/five
|
||||
icon_state = "aplant5"
|
||||
/obj/decal/fakeobjects/carcosa/carcosa_plant/six
|
||||
icon_state = "aplant6"
|
||||
|
||||
/turf/simulated/floor/carcosa/carcosa_dirt
|
||||
name = "dirt"
|
||||
desc = "It's just some odd looking dirt."
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "aground"
|
||||
|
||||
ex_act(severity)
|
||||
return
|
||||
|
||||
/turf/simulated/floor/carcosa/carcosa_dirt_inner
|
||||
name = "dirt"
|
||||
desc = "It's just some odd looking dirt."
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "aground_inner4"
|
||||
|
||||
ex_act(severity)
|
||||
return
|
||||
|
||||
|
||||
// cognote: large adventure areas should probably mostly use unsimulated turfs. i'll leave your simulated versions in for now so i don't break your local files
|
||||
|
||||
/turf/unsimulated/floor/setpieces/carcosa/carcosa_dirt
|
||||
name = "dirt"
|
||||
desc = "It's just some odd looking dirt."
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "aground"
|
||||
|
||||
ex_act(severity)
|
||||
return
|
||||
|
||||
/turf/unsimulated/floor/setpieces/carcosa/carcosa_dirt_inner
|
||||
name = "dirt"
|
||||
desc = "It's just some odd looking dirt."
|
||||
icon = 'icons/misc/exploration.dmi'
|
||||
icon_state = "aground_inner4"
|
||||
|
||||
ex_act(severity)
|
||||
return
|
||||
@@ -0,0 +1,782 @@
|
||||
/datum/computer/file/terminal_program/os/main_os/no_login
|
||||
setup_needs_authentication = 0
|
||||
|
||||
/datum/computer/file/terminal_program/os/main_os
|
||||
name = "ThinkDOS"
|
||||
size = 12
|
||||
var/tmp/datum/computer/folder/current_folder = null
|
||||
var/tmp/datum/computer/file/clipboard = null
|
||||
var/tmp/datum/computer/file/text/command_log = null
|
||||
var/tmp/datum/computer/file/record/help_lib = null
|
||||
var/tmp/datum/computer/file/user_data/active_account = null
|
||||
var/echo_input = 1
|
||||
var/log_errors = 1
|
||||
var/list/peripherals = list()
|
||||
var/authenticated = null //Is anyone logged in?
|
||||
|
||||
var/setup_version_name = "ThinkDOS 0.7.2"
|
||||
var/setup_needs_authentication = 1 //Do we need to present an ID to use this?
|
||||
//Setup for data logging
|
||||
#define SETUP_LOG_DIRECTORY "logs"
|
||||
#define SETUP_LOG_FILENAME "syslog"
|
||||
//Setup for help library
|
||||
#define SETUP_HELP_FILEPATH "/logs/helplib"
|
||||
//Where to put user account data.
|
||||
#define SETUP_ACC_DIRECTORY "logs"
|
||||
#define SETUP_ACC_FILENAME "sysusr"
|
||||
|
||||
disposing()
|
||||
peripherals = null
|
||||
current_folder = null
|
||||
clipboard = null
|
||||
command_log = null
|
||||
help_lib = null
|
||||
active_account = null
|
||||
|
||||
..()
|
||||
|
||||
input_text(text)
|
||||
if(..())
|
||||
return
|
||||
|
||||
var/list/command_list = parse_string(text)
|
||||
var/command = command_list[1]
|
||||
command_list -= command_list[1] //Remove the command we are now processing.
|
||||
|
||||
if(src.echo_input)
|
||||
src.print_text(strip_html(text))
|
||||
|
||||
print_to_log(text) //print to log strips html as it logs, no need to do it here!!
|
||||
|
||||
if(!current_folder)
|
||||
current_folder = src.holding_folder
|
||||
|
||||
if(!src.authenticated && src.setup_needs_authentication)
|
||||
switch(lowertext(command))
|
||||
if("login","logon")
|
||||
if (issilicon(usr) && !isghostdrone(usr))
|
||||
src.system_login("AIUSR","Station AI", null, 1)
|
||||
//src.print_text("Authorization Accepted.<br>Welcome, AIUSR!<br><b>Current Folder: [current_folder.name]</b>")
|
||||
//src.authenticated = "AI"
|
||||
//src.print_to_log("LOGIN: AIUSR | \[Station AI]")
|
||||
else
|
||||
var/obj/item/peripheral/scanner = find_peripheral("ID_SCANNER")
|
||||
if(!scanner)
|
||||
src.print_text("<b>Error:</b> No ID scanner detected.")
|
||||
return
|
||||
var/datum/signal/login_result = src.peripheral_command("scan_card", null, "\ref[scanner]")
|
||||
if(istype(login_result))
|
||||
system_login(login_result.data["registered"], login_result.data["assignment"], login_result.data["access"])
|
||||
else if(login_result == "nocard")
|
||||
src.print_text("<b>Error:</b> No ID card inserted.")
|
||||
|
||||
else
|
||||
src.print_text("Login required. Please use \"login\" command.")
|
||||
|
||||
else
|
||||
switch(lowertext(command))
|
||||
if("cls", "home") //Clear temp var of master computer3
|
||||
src.master.temp = null
|
||||
src.master.temp_add = "Screen cleared.<br>" //Okay perhaps not entirely clear.
|
||||
src.master.updateUsrDialog()
|
||||
|
||||
if("dir", "catalog", "ls") //Show contents of current folder
|
||||
|
||||
src.print_text("<b>Files on [current_folder.holder.title] - Used: \[[src.current_folder.holder.file_used]/[src.current_folder.holder.file_amount]\]</b>")
|
||||
src.print_text("<b>Current Folder: [current_folder.name]</b>")
|
||||
|
||||
var/dir_text = null
|
||||
for(var/datum/computer/P in current_folder.contents)
|
||||
if(P == src)
|
||||
dir_text += "[src.name] - SYSTEM - \[Size: [src.size]]<br>"
|
||||
continue
|
||||
|
||||
dir_text += "[P.name] - [(istype(P,/datum/computer/folder)) ? "FOLDER" : "[P:extension]"] - \[Size: [P.size]]<br>"
|
||||
|
||||
if(dir_text)
|
||||
src.print_text(dir_text)
|
||||
|
||||
if("cd", "chdir") //Attempts to set current folder to directory arg1
|
||||
var/dir_string = null
|
||||
if(command_list.len)
|
||||
dir_string = dd_list2text(command_list, " ")
|
||||
else
|
||||
src.print_text("<b>Syntax:</b> \"cd \[directory string]\" String is relative to current directory.")
|
||||
return
|
||||
|
||||
if(dir_string == "/") //If it is seriously just /, act like the root command
|
||||
src.current_folder = src.current_folder.holder.root
|
||||
src.print_text("<b>Current Directory is now [current_folder.name]</b>")
|
||||
return
|
||||
|
||||
var/datum/computer/folder/new_dir = parse_directory(dir_string, src.current_folder)
|
||||
if(!new_dir || !istype(new_dir))
|
||||
src.print_error_text("<b>Error:</b> Invalid directory or path.")
|
||||
return
|
||||
else
|
||||
src.current_folder = new_dir
|
||||
src.print_text("<b>Current Directory is now [new_dir.name]</b>")
|
||||
|
||||
if("root") //Sets current folder to root of current drive
|
||||
if(src.current_folder && src.current_folder.holder.root)
|
||||
src.current_folder = src.current_folder.holder.root
|
||||
src.print_text("<b>Current Directory is now [current_folder.name]</b>")
|
||||
|
||||
if("run") //Runs /datum/computer/file/terminal_program with name arg1
|
||||
var/prog_name = null
|
||||
if(command_list.len)
|
||||
prog_name = dd_list2text(command_list, " ")
|
||||
else
|
||||
src.print_text("<b>Syntax:</b> \"run \[program filepath].\" Path is relative to current directory.")
|
||||
return
|
||||
|
||||
var/datum/computer/file/terminal_program/to_run = src.parse_file_directory(prog_name, current_folder)
|
||||
|
||||
if(isnull(to_run) || !istype(to_run) || istype(to_run, /datum/computer/file/terminal_program/os))
|
||||
src.print_error_text("<b>Error:</b> Invalid file name or type.")
|
||||
else
|
||||
src.master.run_program(to_run)
|
||||
src.master.updateUsrDialog()
|
||||
return
|
||||
|
||||
if("makedir","mkdir") //Creates folder in current directory with name arg1
|
||||
var/new_folder_name = strip_html(dd_list2text(command_list, " "))
|
||||
new_folder_name = copytext(new_folder_name, 1, 16)
|
||||
|
||||
if(!new_folder_name)
|
||||
src.print_text("<b>Syntax:</b> \"makedir \[new directory name]\"")
|
||||
return
|
||||
|
||||
if(src.get_computer_datum(new_folder_name, current_folder))
|
||||
src.print_error_text("<b>Error:</b> Directory name in use.")
|
||||
return
|
||||
|
||||
if(is_name_invalid(new_folder_name))
|
||||
src.print_error_text("<b>Error:</b> Invalid character in name.")
|
||||
return
|
||||
|
||||
var/datum/computer/F = new /datum/computer/folder
|
||||
F.name = new_folder_name
|
||||
if(!current_folder.add_file(F))
|
||||
src.print_error_text("<b>Error:</b> Unable to create new directory.")
|
||||
//qdel(F)
|
||||
F.dispose()
|
||||
else
|
||||
src.print_text("New directory created.")
|
||||
|
||||
if("rename","ren") //Sets name of file arg1 to arg2
|
||||
var/to_rename = null
|
||||
var/new_name = null
|
||||
if(command_list.len >= 2)
|
||||
to_rename = command_list[1]
|
||||
new_name = command_list[2]
|
||||
new_name = copytext(strip_html(new_name), 1, 16)
|
||||
|
||||
if(!to_rename || !new_name)
|
||||
src.print_text("<b>Syntax:</b> \"rename \[name of target] \[new name]\"")
|
||||
return
|
||||
|
||||
if(is_name_invalid(new_name))
|
||||
src.print_error_text("<b>Error:</b> Invalid character in name.")
|
||||
return
|
||||
|
||||
var/datum/computer/target = get_computer_datum(to_rename, current_folder)
|
||||
|
||||
if(!target || !istype(target))
|
||||
src.print_error_text("<b>Error:</b> File not found.")
|
||||
return
|
||||
|
||||
var/datum/computer/check_existing = get_computer_datum(new_name, src.current_folder)
|
||||
if(check_existing && check_existing != target )
|
||||
src.print_error_text("<b>Error:</b> Name in use.")
|
||||
return
|
||||
|
||||
target.name = new_name
|
||||
src.print_text("Done.")
|
||||
|
||||
if("title") //Set the title var of the current drive.
|
||||
var/new_name = null
|
||||
if(command_list.len)
|
||||
new_name = strip_html(dd_list2text(command_list, " "))
|
||||
new_name = copytext(new_name, 1, 16)
|
||||
else
|
||||
src.print_text("<b>Syntax:</b> \"title \[title name]\" Set name of active drive to given title.")
|
||||
return
|
||||
|
||||
if(src.current_folder.holder && !src.current_folder.holder.read_only)
|
||||
src.current_folder.holder.title = new_name
|
||||
src.print_text("Drive title set to <b>[new_name]</b>.")
|
||||
else
|
||||
src.print_error_text("<b>Error:</b> Unable to set title string.")
|
||||
|
||||
if("delete", "del","era","erase","rm") //Deletes file arg1
|
||||
var/file_name = null
|
||||
if(command_list.len)
|
||||
file_name = ckey(dd_list2text(command_list, " "))
|
||||
else
|
||||
src.print_text("<b>Syntax:</b> \"del \[file name].\" File must be in current directory.")
|
||||
return
|
||||
|
||||
var/datum/computer/target = get_computer_datum(file_name, current_folder)
|
||||
if(!target || !istype(target))
|
||||
src.print_error_text("<b>Error:</b> File not found.")
|
||||
return
|
||||
|
||||
if(target == src)
|
||||
src.print_error_text("<b>Error:</b> Access denied.")
|
||||
return
|
||||
|
||||
if(src.master.delete_file(target))
|
||||
src.print_text("File deleted.")
|
||||
else
|
||||
src.print_error_text("<b>Error:</b> Unable to delete file.")
|
||||
|
||||
if("copy","cp") //Sets file arg1 to be copied
|
||||
var/file_name = null
|
||||
if(command_list.len)
|
||||
file_name = ckey(dd_list2text(command_list, " "))
|
||||
else
|
||||
src.print_text("<b>Syntax:</b> \"copy \[file name].\" File must be in current directory.")
|
||||
return
|
||||
|
||||
var/datum/computer/target = get_file_name(file_name, current_folder)
|
||||
if(!target || !istype(target))
|
||||
src.print_error_text("<b>Error:</b> File not found.")
|
||||
return
|
||||
|
||||
src.clipboard = target
|
||||
src.print_text("File marked.")
|
||||
|
||||
if("paste","ps") //Pastes clipboard file with name arg1
|
||||
var/pasted_name = strip_html(dd_list2text(command_list, " "))
|
||||
pasted_name = copytext(pasted_name, 1, 16)
|
||||
|
||||
if(!pasted_name)
|
||||
src.print_text("<b>Syntax:</b> \"paste \[new file name].\" File is placed in current directory.")
|
||||
return
|
||||
|
||||
if(!src.clipboard || !src.clipboard.holder || !(src.clipboard.holder in src.master.contents))
|
||||
src.print_error_text("<b>Error:</b> Unable to locate marked file.")
|
||||
return
|
||||
|
||||
if(!istype(src.clipboard))
|
||||
src.print_error_text("<b>Error:</b> Invalid or corrupt file type.")
|
||||
return
|
||||
|
||||
if(get_computer_datum(pasted_name, src.current_folder))
|
||||
src.print_error_text("<b>Error:</b> Name in use.")
|
||||
return
|
||||
|
||||
if(is_name_invalid(pasted_name))
|
||||
src.print_error_text("<b>Error:</b> Invalid character in name.")
|
||||
return
|
||||
|
||||
if(src.clipboard.copy_file_to_folder(current_folder, pasted_name))
|
||||
src.print_text("Done")
|
||||
else
|
||||
src.print_error_text("<b>Error:</b> Unable to paste file (Drive is full?)")
|
||||
|
||||
if("drive","drv") //Sets current folder to root of drive arg1
|
||||
var/argument1 = null
|
||||
if(command_list.len)
|
||||
argument1 = command_list[1]
|
||||
|
||||
var/list/drives = src.get_loaded_drives()
|
||||
|
||||
if(!ckey(argument1))
|
||||
var/valid_string = english_list(drives, "None", " ")
|
||||
src.print_text("<b>Syntax:</b> \"drive \[drive id].\"<br><b>Valid IDs:</b> ([valid_string]).")
|
||||
return
|
||||
|
||||
var/obj/item/disk/data/to_load = drives[argument1]
|
||||
if(to_load && istype(to_load) && to_load.root)
|
||||
src.current_folder = to_load.root
|
||||
src.print_text("<b>Current Drive is now [current_folder.holder.title]</b>")
|
||||
else
|
||||
src.print_text("<b>Error:</b> Drive invalid.")
|
||||
|
||||
if("initlogs") //Restart logging if log file is deleted or otherwise lost.
|
||||
if(src.command_log)
|
||||
src.print_error_text("<b>Error:</b> Logging is already active.")
|
||||
else
|
||||
if(initialize_logs())
|
||||
src.print_text("Logging re-initialized.")
|
||||
else
|
||||
src.print_error_text("<b>Error:</b> Unable to re-initialize logging.")
|
||||
|
||||
if("help") //Allow access to "helplib" record datum. Should be kept tup to date with system commands, etc
|
||||
if(!src.help_lib || !istype(src.help_lib) || help_lib.disposed)
|
||||
help_lib = null
|
||||
src.print_error_text("<b>Error:</b> Help file missing or corrupt.")
|
||||
return
|
||||
else
|
||||
var/argument1 = "help"
|
||||
if(command_list.len)
|
||||
argument1 = lowertext(command_list[1])
|
||||
|
||||
var/help_string = src.help_lib.fields[argument1]
|
||||
if(help_string)
|
||||
src.print_text("<b>[capitalize(argument1)]</b><br>[help_string]")
|
||||
else
|
||||
src.print_error_text("<b>Error:</b> Invalid field.")
|
||||
|
||||
if("periph","p") //Allow some user interactions with peripheral cards.
|
||||
var/argument1 = null
|
||||
if(command_list.len)
|
||||
argument1 = command_list[1]
|
||||
|
||||
switch(argument1)
|
||||
if("view","v") //View installed cards.
|
||||
src.print_text("<b>Current active peripheral cards:</b>")
|
||||
if(!src.peripherals.len)
|
||||
src.print_text("<center>None loaded.</center>")
|
||||
else
|
||||
for(var/x = 1, x <= src.peripherals.len, x++)
|
||||
var/obj/item/peripheral/P = src.peripherals[x]
|
||||
if(istype(P))
|
||||
var/statdat = P.return_status_text()
|
||||
src.print_text("<b>ID: \[[x]] [P.func_tag]</b><br>Status: [statdat]")
|
||||
else
|
||||
src.peripherals -= P
|
||||
continue
|
||||
|
||||
if("command","c")
|
||||
var/id = 0
|
||||
var/pcommand = null
|
||||
var/sig_filename = null
|
||||
|
||||
if(command_list.len >= 3) //These two args are needed for this mode
|
||||
id = round(text2num(command_list[2]))
|
||||
pcommand = strip_html(command_list[3])
|
||||
|
||||
if(command_list.len >= 4) //Having a signal file is optional, however
|
||||
sig_filename = ckey(command_list[4])
|
||||
|
||||
if(!pcommand) //Check for command first, if they skip it they also don't get the id and it complains about that and aaaa
|
||||
src.print_error_text("Error: Command argument required.")
|
||||
return
|
||||
|
||||
if((!id) || (id > src.peripherals.len) || (id <= 0))
|
||||
src.print_error_text("Error: ID invalid or out of bounds.")
|
||||
return
|
||||
|
||||
var/datum/computer/file/signal/sig = null
|
||||
if(sig_filename)
|
||||
sig = get_file_name(sig_filename, src.current_folder)
|
||||
if(!sig || (!istype(sig) && !istype(sig, /datum/computer/file/record)))
|
||||
src.print_error_text("Error: Signal file missing or invalid.")
|
||||
return
|
||||
|
||||
src.print_text("Command: <b>ID:</b> [id] <b>COM:</b> [pcommand]")
|
||||
var/datum/signal/signal = get_free_signal()//new
|
||||
//signal.encryption = "\ref[src.peripherals[id]]"
|
||||
if(sig)
|
||||
if (istype(sig,/datum/computer/file/record))
|
||||
var/datum/computer/file/record/sigrec = sig
|
||||
for (var/entry in sigrec.fields)
|
||||
var/equalpos = findtext("=", entry)
|
||||
if (equalpos)
|
||||
signal.data["[copytext(entry, 1, equalpos)]"] = "[copytext(entry, equalpos)]"
|
||||
else
|
||||
if (!isnull(sigrec.fields[entry]))
|
||||
signal.data["[entry]"] = sigrec.fields[entry]
|
||||
else
|
||||
signal.data += entry
|
||||
|
||||
if (command_list.len > 4)
|
||||
signal.data_file = get_file_name(ckey(command_list[5]), src.current_folder)
|
||||
if (istype(signal.data_file, /datum/computer/file))
|
||||
signal.data_file = signal.data_file.copy_file()
|
||||
else
|
||||
signal.data_file = null
|
||||
|
||||
else
|
||||
signal.data = sig.data.Copy()
|
||||
if(sig.data_file) //For file transfers!
|
||||
var/datum/computer/file/tempfile = sig.data_file.copy_file()
|
||||
if(tempfile && istype(tempfile))
|
||||
signal.data_file = tempfile
|
||||
var/result = peripheral_command(pcommand, signal, "\ref[src.peripherals[id]]")
|
||||
if (result != 0)
|
||||
if (result == 1)
|
||||
src.print_text("Error: Command unsuccessful.")
|
||||
else if (istext(result))
|
||||
src.print_text("Response: [result]")
|
||||
|
||||
else
|
||||
src.print_text("Syntax: \"periph \[mode] \[ID] \[command] \[signal file]\"<br><b>Valid modes:</b> (view, command)")
|
||||
|
||||
if("backprog", "bp") //Allow the user to manage programs chilling in the background
|
||||
var/argument1 = null
|
||||
if(command_list.len)
|
||||
argument1 = command_list[1]
|
||||
|
||||
switch(argument1)
|
||||
if("view", "v") //View processing programs (other than us)
|
||||
src.print_text("<b>Current programs in memory:</b>")
|
||||
if(!src.master.processing_programs.len) //This should never happen as we should be in it.
|
||||
src.print_text("<center>None detected.</center>")
|
||||
else
|
||||
for(var/x = 1, x <= src.master.processing_programs.len, x++)
|
||||
var/datum/computer/file/terminal_program/T = src.master.processing_programs[x]
|
||||
if(istype(T))
|
||||
src.print_text("<b>ID: \[[x]]</b> [(T == src) ? "SYSTEM" : T.name]")
|
||||
|
||||
if("kill", "k") //Okay now that we know them it is time to BE RID OF THEM
|
||||
var/target_id = 0
|
||||
if(command_list.len >= 2)
|
||||
target_id = round(text2num(command_list[2]))
|
||||
else
|
||||
src.print_error_text("Target ID Required.")
|
||||
return
|
||||
|
||||
if((!target_id) || (target_id > src.master.processing_programs.len) || (target_id <= 0))
|
||||
src.print_error_text("<b>Error:</b> ID invalid or out of bounds.")
|
||||
return
|
||||
|
||||
var/datum/computer/file/terminal_program/target = src.master.processing_programs[target_id]
|
||||
if(!target || !istype(target) || target == src) //No terminating ourselves!!
|
||||
src.print_error_text("<b>Error:</b> Invalid Target.")
|
||||
return
|
||||
|
||||
src.master.unload_program(target)
|
||||
src.print_text("Program killed.")
|
||||
|
||||
if("switch", "s")
|
||||
var/target_id = 0
|
||||
if(command_list.len >= 2)
|
||||
target_id = round(text2num(command_list[2]))
|
||||
else
|
||||
src.print_error_text("Target ID Required.")
|
||||
return
|
||||
|
||||
if((!target_id) || (target_id > src.master.processing_programs.len) || (target_id <= 0))
|
||||
src.print_error_text("<b>Error:</b> ID invalid or out of bounds.")
|
||||
return
|
||||
|
||||
var/datum/computer/file/terminal_program/target = src.master.processing_programs[target_id]
|
||||
if(!target || !istype(target) || target == src || istype(target, /datum/computer/file/terminal_program/os)) //No re-running ourselves!!
|
||||
src.print_error_text("<b>Error:</b> Invalid Target.")
|
||||
return
|
||||
|
||||
src.print_text("Switching to target...")
|
||||
src.master.run_program(target)
|
||||
src.master.updateUsrDialog()
|
||||
return
|
||||
|
||||
|
||||
else
|
||||
src.print_text("<b>Syntax:</b> \"backprog \[mode] \[ID]\"<br><b>Valid modes:</b> (view, kill, switch)")
|
||||
|
||||
|
||||
if("print") //Print text arg1 to screen.
|
||||
var/new_text = strip_html(dd_list2text(command_list, " "))
|
||||
if(new_text)
|
||||
src.print_text(new_text)
|
||||
else
|
||||
src.print_text("<b>Syntax:</b> \"print \[text to be printed]\"")
|
||||
|
||||
if("goonsay") //Display text arg1 along with goonsay ascii
|
||||
var/goon = {" __________<br>
|
||||
(--\[ .]-\[ .] /<br>
|
||||
(_______0__)<br>
|
||||
"}
|
||||
|
||||
var/anger_text = "A clown? On a space station? what"
|
||||
if(istype(command_list) && (command_list.len > 0))
|
||||
anger_text = strip_html(dd_list2text(command_list, " "))
|
||||
|
||||
src.print_text("<tt>[anger_text]<br>[goon]</tt>")
|
||||
|
||||
/*
|
||||
if("echo") //Determine if entered commands are printed to screen
|
||||
var/argument1 = null
|
||||
if(command_list.len)
|
||||
argument1 = command_list[1]
|
||||
|
||||
switch(argument1)
|
||||
if("on","ON")
|
||||
src.echo_input = 1
|
||||
|
||||
if("off","OFF")
|
||||
src.echo_input = 0
|
||||
|
||||
else
|
||||
src.echo_input = !src.echo_input
|
||||
|
||||
src.print_text("Input Echo is now <b>[src.echo_input ? "ON" : "OFF"]</b>")
|
||||
*/
|
||||
if("user") //Show current user identfication data
|
||||
if(!src.setup_needs_authentication)
|
||||
src.print_error_text("Account system inactive.")
|
||||
return
|
||||
|
||||
if(!src.active_account)
|
||||
src.print_error_text("<b>Error:</b> Unable to find account file.")
|
||||
return
|
||||
|
||||
src.print_text("Current User: [src.active_account.registered]<br>Rank: [src.active_account.assignment]")
|
||||
|
||||
if("logout","logoff") //Log out if we are currently logged in.
|
||||
if(!setup_needs_authentication || !src.authenticated)
|
||||
src.print_error_text("Account system inactive.")
|
||||
return
|
||||
else
|
||||
src.print_to_log("<b>LOGOUT:</b> [src.authenticated]",0)
|
||||
src.authenticated = null
|
||||
src.active_account = null
|
||||
src.master.temp = null
|
||||
src.echo_input = 1
|
||||
|
||||
//Kill off any background programs that may be running.
|
||||
for(var/datum/computer/file/terminal_program/T in src.master.processing_programs)
|
||||
if(T == src)
|
||||
continue
|
||||
|
||||
src.master.unload_program(T)
|
||||
|
||||
src.print_text("Logout complete. Have a secure day.<br><br>Authentication required.<br>Please insert card and \"Login.\"")
|
||||
|
||||
|
||||
if("read","type") //Display contents of text file arg1
|
||||
var/file_name = null
|
||||
if(command_list.len)
|
||||
file_name = ckey(dd_list2text(command_list, " "))
|
||||
else
|
||||
src.print_text("<b>Syntax:</b> \"read \[file name].\" Text file must be in current directory.")
|
||||
return
|
||||
|
||||
var/datum/computer/file/text/T = get_file_name(file_name, current_folder)
|
||||
|
||||
if(isnull(T) || !istype(T) || !T.data)
|
||||
if(istype(T, /datum/computer/file/record))
|
||||
var/print_buffer = null
|
||||
var/datum/computer/file/record/R = T
|
||||
for(var/i in R.fields)
|
||||
if (R.fields[i])
|
||||
print_buffer += "[i]: [R.fields[i]]<br>"
|
||||
else
|
||||
print_buffer += "[i]<br>"
|
||||
if(print_buffer)
|
||||
src.print_text(print_buffer)
|
||||
else
|
||||
src.print_error_text("<b>Error:</b> File is empty.")
|
||||
return
|
||||
|
||||
src.print_error_text("<b>Error:</b> Invalid or blank file.")
|
||||
else
|
||||
src.print_text(T.data)
|
||||
|
||||
if("version") //Show the version name. ~Flavortext~
|
||||
src.print_text("[src.setup_version_name]<br>Copyright 2047 Thinktronic Systems, LTD.")
|
||||
|
||||
if("time") //Hello my immersion needs to know the time
|
||||
src.print_text("System time: [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], 2053.")
|
||||
|
||||
else
|
||||
//Load the program if they just entered a path I guess
|
||||
var/prog_name = dd_list2text(command_list, " ")
|
||||
prog_name = command + prog_name
|
||||
|
||||
var/datum/computer/file/terminal_program/to_run = src.parse_file_directory(prog_name, current_folder)
|
||||
|
||||
if(isnull(to_run) || !istype(to_run) || istype(to_run, /datum/computer/file/terminal_program/os))
|
||||
src.print_text("Syntax Error.")
|
||||
else
|
||||
src.master.run_program(to_run)
|
||||
src.master.updateUsrDialog()
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
initialize()
|
||||
src.print_text("Loading [src.setup_version_name]<br>Scanning for peripheral cards...")
|
||||
|
||||
src.peripherals = new //Figure out what cards are there now so we can address them later all easy-like
|
||||
for(var/obj/item/peripheral/P in src.master.peripherals)
|
||||
if(!(P in src.peripherals))
|
||||
src.peripherals += P
|
||||
|
||||
src.print_text("Preparing filesystem...")
|
||||
|
||||
src.command_log = null
|
||||
src.help_lib = null
|
||||
src.authenticated = null
|
||||
|
||||
src.current_folder = src.holder.root
|
||||
|
||||
if(src.initialize_logs()) //Get the logging file ready.
|
||||
print_text("<font color=red>Log system failure.</font>")
|
||||
|
||||
if(src.initialize_help()) //Find the help file so it can help people.
|
||||
print_text("<font color=red>Help library not found.</font>")
|
||||
|
||||
if(setup_needs_authentication && initialize_accounts())
|
||||
print_text("<font color=red>Unable to start account system.</font>")
|
||||
|
||||
if(src.setup_needs_authentication)
|
||||
src.print_text("Authentication required.<br>Please insert card and \"Login.\"")
|
||||
|
||||
else
|
||||
src.print_text("Ready.")
|
||||
|
||||
return
|
||||
|
||||
disk_ejected(var/obj/item/disk/data/thedisk)
|
||||
if(!thedisk)
|
||||
return
|
||||
|
||||
if(current_folder && (current_folder.holder == thedisk))
|
||||
current_folder = src.holding_folder
|
||||
|
||||
if(src.holder == thedisk)
|
||||
src.print_text("<font color=red><b>System Error:</b> Unable to read system file.</font>")
|
||||
src.master.active_program = null
|
||||
src.master.host_program = null
|
||||
return
|
||||
|
||||
return
|
||||
/*
|
||||
receive_command(obj/source, command, datum/signal/signal)
|
||||
if((..()))
|
||||
return
|
||||
|
||||
if((command == "card_authed") && signal && (!src.authenticated) && src.setup_needs_authentication)
|
||||
|
||||
system_login(signal.data["registered"], signal.data["assignment"], signal.data["access"])
|
||||
return
|
||||
|
||||
return
|
||||
*/
|
||||
|
||||
proc
|
||||
//Log this text in the ~system log~ as well as printing it.
|
||||
print_error_text(text)
|
||||
if(src.log_errors)
|
||||
src.print_to_log(text, 0)
|
||||
|
||||
return src.print_text(text)
|
||||
|
||||
initialize_logs() //Man we sure love logging things. Let's set up a log for our logging.
|
||||
var/datum/computer/folder/logdir = parse_directory(SETUP_LOG_DIRECTORY, src.holder.root)
|
||||
if(!logdir || !istype(logdir))
|
||||
logdir = new /datum/computer/folder
|
||||
if(src.holder.root.add_file(logdir))
|
||||
logdir.name = SETUP_LOG_DIRECTORY
|
||||
else
|
||||
return -1 //Must be read-only or something if we can't add a folder. Give up.
|
||||
|
||||
var/datum/computer/file/text/the_log = get_file_name(SETUP_LOG_FILENAME, logdir)
|
||||
if(the_log && istype(the_log))
|
||||
src.command_log = the_log
|
||||
|
||||
else
|
||||
the_log = new /datum/computer/file/text()
|
||||
if(logdir.add_file(the_log))
|
||||
src.command_log = the_log
|
||||
the_log.name = SETUP_LOG_FILENAME
|
||||
|
||||
else
|
||||
return -2
|
||||
|
||||
the_log.data += "<br><b>STARTUP:</b> [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], 2053"
|
||||
return 0
|
||||
|
||||
print_to_log(text, strip_input=1)
|
||||
if(!text)
|
||||
return 0
|
||||
if(!command_log || !istype(command_log) || !command_log.holder)
|
||||
return 0
|
||||
|
||||
if(!(command_log.holder in src.master.contents))
|
||||
return 0
|
||||
|
||||
if(strip_input)
|
||||
command_log.data += "<br>[strip_html(text)]"
|
||||
else
|
||||
command_log.data += "<br>[text]"
|
||||
|
||||
return 1
|
||||
|
||||
initialize_help() //It's pretty similar to initialize_logs(), but unable to recreate the file if missing.
|
||||
|
||||
var/datum/computer/file/record/target_rec = parse_file_directory(SETUP_HELP_FILEPATH)
|
||||
if(target_rec && istype(target_rec))
|
||||
src.help_lib = target_rec
|
||||
print_to_log("Help System Initialized.")
|
||||
return 0
|
||||
|
||||
return -1
|
||||
|
||||
initialize_accounts()
|
||||
var/datum/computer/folder/accdir = parse_directory(SETUP_ACC_DIRECTORY, src.holder.root)
|
||||
if(!accdir || !istype(accdir))
|
||||
accdir = new /datum/computer/folder
|
||||
if(src.holder.root.add_file(accdir))
|
||||
accdir.name = SETUP_ACC_DIRECTORY
|
||||
else
|
||||
return -1 //Oh welp read only
|
||||
|
||||
var/datum/computer/file/user_data/the_acc = get_file_name(SETUP_ACC_FILENAME, accdir)
|
||||
if(the_acc && istype(the_acc))
|
||||
src.active_account = the_acc
|
||||
|
||||
else
|
||||
the_acc = new /datum/computer/file/user_data()
|
||||
if(accdir.add_file(the_acc))
|
||||
src.active_account = the_acc
|
||||
the_acc.name = SETUP_ACC_FILENAME
|
||||
|
||||
else
|
||||
return -1
|
||||
|
||||
return 0
|
||||
|
||||
system_login(var/acc_name, var/acc_job, var/access_string, all_access=0)
|
||||
if(!acc_name || !acc_job)
|
||||
return
|
||||
|
||||
if(!src.active_account && !src.initialize_accounts()) //Oh welp we can't write it to file
|
||||
src.print_text("<b>Error:</b> Unable to write account file.")
|
||||
return -1
|
||||
|
||||
src.authenticated = acc_name
|
||||
src.active_account.access = list()
|
||||
src.active_account.registered = acc_name
|
||||
src.active_account.assignment = acc_job
|
||||
src.current_folder = src.holder.root
|
||||
|
||||
if(access_string && !all_access)
|
||||
var/list/decoding = dd_text2list(access_string, ";")
|
||||
for(var/x in decoding)
|
||||
src.active_account.access += text2num(x)
|
||||
|
||||
else if(all_access)
|
||||
src.active_account.access = get_all_accesses()
|
||||
|
||||
src.print_to_log("<b>LOGIN:</b> [acc_name] | \[[acc_job]]", 0)
|
||||
|
||||
src.print_text("Welcome, [acc_name]!<br><b>Current Folder: [current_folder.name]</b>")
|
||||
return 0
|
||||
|
||||
get_loaded_drives() //Return a list of the drives in the master computer3.
|
||||
var/list/drives = list()
|
||||
var/drive_num = 0
|
||||
if(src.master.hd)
|
||||
drives["hd0"] = src.master.hd
|
||||
if(src.master.diskette)
|
||||
drives["fd0"] = src.master.diskette
|
||||
|
||||
for(var/obj/item/disk/data/drive in src.master.contents)
|
||||
if(drive == src.master.hd || drive == src.master.diskette)
|
||||
continue
|
||||
drives["sd[drive_num]"] = drive
|
||||
drive_num++
|
||||
|
||||
return drives
|
||||
|
||||
#undef SETUP_LOG_DIRECTORY
|
||||
#undef SETUP_LOG_FILENAME
|
||||
#undef SETUP_HELP_FILEPATH
|
||||
#undef SETUP_ACC_DIRECTORY
|
||||
#undef SETUP_ACC_FILENAME
|
||||
@@ -0,0 +1,468 @@
|
||||
|
||||
|
||||
|
||||
/datum/computer/file/terminal_program
|
||||
name = "blank program"
|
||||
extension = "TPROG"
|
||||
//var/size = 4.0
|
||||
//var/obj/item/disk/data/holder = null
|
||||
var/obj/machinery/computer3/master = null
|
||||
//var/active_icon = null
|
||||
var/list/req_access = list()
|
||||
//var/id_tag = null
|
||||
var/executable = 1
|
||||
|
||||
os
|
||||
name = "blank system program"
|
||||
extension = "TSYS"
|
||||
executable = 0
|
||||
var/tmp/setup_string = null
|
||||
|
||||
os_call(var/list/call_list, var/datum/computer/file/terminal_program/caller, var/datum/computer/file/file)
|
||||
return (!master || master.stat & (NOPOWER|BROKEN) || !caller || !call_list)
|
||||
|
||||
termapp //Small applications for the "termos" computer3s.
|
||||
name = "blank terminal app"
|
||||
extension = "TAPP"
|
||||
executable = 0
|
||||
|
||||
New(obj/holding as obj)
|
||||
..()
|
||||
if(holding)
|
||||
src.holder = holding
|
||||
|
||||
if(istype(src.holder.loc,/obj/machinery/computer3))
|
||||
src.master = src.holder.loc
|
||||
|
||||
/* new disposing() pattern should handle this. -singh
|
||||
Del()
|
||||
if(master)
|
||||
master.processing_programs.Remove(src)
|
||||
..()
|
||||
*/
|
||||
|
||||
disposing()
|
||||
if (master)
|
||||
if (master.processing_programs)
|
||||
master.processing_programs.Remove(src)
|
||||
master = null
|
||||
|
||||
src.req_access = null
|
||||
..()
|
||||
|
||||
proc
|
||||
os_call(var/list/call_list, var/datum/computer/file/file)
|
||||
if(!master || master.stat & (NOPOWER|BROKEN))
|
||||
return null
|
||||
|
||||
if(master.host_program)
|
||||
return master.host_program.os_call(call_list, src, file)
|
||||
return null
|
||||
|
||||
print_text(var/text)
|
||||
if((!src.holder) || (!src.master) || !text)
|
||||
return 1
|
||||
|
||||
if((!istype(holder)) || (!istype(master)))
|
||||
return 1
|
||||
|
||||
if(master.stat & (NOPOWER|BROKEN))
|
||||
return 1
|
||||
|
||||
if(src != src.master.active_program)
|
||||
return 1
|
||||
|
||||
if(!(holder in src.master.contents))
|
||||
//boutput(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"
|
||||
|
||||
src.master.temp_add += "[text]<br>"
|
||||
src.master.updateUsrDialog()
|
||||
|
||||
return 0
|
||||
|
||||
input_text(var/text)
|
||||
if((!src.holder) || (!src.master) || !text)
|
||||
return 1
|
||||
|
||||
if((!istype(holder)) || (!istype(master)))
|
||||
return 1
|
||||
|
||||
if(master.stat & (NOPOWER|BROKEN))
|
||||
return 1
|
||||
|
||||
if(!(holder in src.master.contents))
|
||||
//boutput(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
|
||||
|
||||
initialize() //Called when a program starts running.
|
||||
return
|
||||
|
||||
restart()
|
||||
return
|
||||
|
||||
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, target_ref)
|
||||
if(master)
|
||||
return master.send_command(command, signal, target_ref)
|
||||
//else
|
||||
// qdel(signal)
|
||||
|
||||
return null
|
||||
|
||||
//Find a peripheral by func_tag
|
||||
find_peripheral(desired_tag)
|
||||
if(!src.master || !desired_tag) return
|
||||
|
||||
var/found = null
|
||||
for(var/obj/item/peripheral/P in src.master.peripherals)
|
||||
if(P.func_tag == desired_tag)
|
||||
found = P
|
||||
|
||||
return found
|
||||
|
||||
transfer_holder(obj/item/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/computer3))
|
||||
src.master = newholder.loc
|
||||
|
||||
//boutput(world, "Setting [src.holder] to [newholder]")
|
||||
src.holder = newholder
|
||||
return 1
|
||||
|
||||
parse_string(string)
|
||||
var/list/sorted = command2list(string, " ")
|
||||
if (!sorted.len) sorted.len++
|
||||
return sorted
|
||||
|
||||
//Command2list is a modified version of dd_text2list() designed to eat empty list entries generated by superfluous whitespace.
|
||||
//It was born in mainframe2. Do not forget your history.
|
||||
command2list(text, separator)
|
||||
var/textlength = length(text)
|
||||
var/separatorlength = length(separator)
|
||||
var/list/textList = new()
|
||||
var/searchPosition = 1
|
||||
var/findPosition = 1
|
||||
while(1)
|
||||
findPosition = findtext(text, separator, searchPosition, 0)
|
||||
var/buggyText = copytext(text, searchPosition, findPosition)
|
||||
if(buggyText)
|
||||
textList += "[buggyText]"
|
||||
if(!findPosition)
|
||||
return textList
|
||||
searchPosition = findPosition + separatorlength
|
||||
if(searchPosition > textlength)
|
||||
return textList
|
||||
return
|
||||
|
||||
parse_directory(string, var/datum/computer/folder/origin)
|
||||
if(!string)
|
||||
return null
|
||||
|
||||
//boutput(world, "[string]")
|
||||
var/datum/computer/folder/current = origin
|
||||
|
||||
if(!origin)
|
||||
origin = src.holding_folder
|
||||
|
||||
if(dd_hasprefix(string , "/")) //if it starts with a /
|
||||
current = origin.holder.root //Begin the search at root.of current drive
|
||||
string = copytext(string,2)
|
||||
//boutput(world, "string is now: [string]")
|
||||
|
||||
var/list/sort1 = dd_text2list(string,"/")
|
||||
if (sort1.len && copytext(sort1[1], 4, 5) == ":")
|
||||
. = lowertext( copytext(sort1[1], 1, 4) )
|
||||
if (length(sort1[1]) > 4)
|
||||
sort1[1] = copytext(sort1[1], 5)
|
||||
else
|
||||
sort1.Cut(1,2)
|
||||
switch (.)
|
||||
if ("hd0")
|
||||
if (master.hd)
|
||||
current = master.hd.root
|
||||
else
|
||||
return null
|
||||
|
||||
if ("fd0")
|
||||
if (master.diskette)
|
||||
current = master.diskette.root
|
||||
else
|
||||
return null
|
||||
|
||||
else
|
||||
if (cmptext(copytext(., 1, 3), "sd"))
|
||||
. = text2num(copytext(., 3))
|
||||
if (!isnum(.))
|
||||
return null
|
||||
|
||||
.++
|
||||
for (var/obj/item/disk/data/drive in master.contents)
|
||||
if (drive == master.hd || drive == master.diskette)
|
||||
continue
|
||||
|
||||
if (--. < 1)
|
||||
current = drive.root
|
||||
break
|
||||
|
||||
if (. > 0)
|
||||
return null
|
||||
|
||||
while(current)
|
||||
|
||||
if(!sort1.len)
|
||||
//boutput(world, "finished with [current.name]")
|
||||
return current
|
||||
|
||||
var/new_current = 0
|
||||
for(var/datum/computer/folder/F in current.contents)
|
||||
//boutput(world, "testing: [F.name] -- [sort1[1]] in folder [current]")
|
||||
if(ckey(F.name) == ckey(sort1[1]))
|
||||
//boutput(world, "matches: [F.name] -- [sort1[1]]")
|
||||
sort1 -= sort1[1]
|
||||
current = F
|
||||
new_current = 1
|
||||
break
|
||||
|
||||
if(!new_current)
|
||||
//boutput(world, "no new current")
|
||||
return null
|
||||
|
||||
return null
|
||||
|
||||
//Find a file at the end of a given dirstring.
|
||||
parse_file_directory(string, var/datum/computer/folder/origin)
|
||||
if(!string)
|
||||
return null
|
||||
|
||||
//boutput(world, "[string]")
|
||||
var/datum/computer/folder/current = origin
|
||||
|
||||
if(!origin)
|
||||
origin = src.holding_folder
|
||||
|
||||
if(dd_hasprefix(string , "/")) //if it starts with a /
|
||||
current = origin.holder.root //Begin the search at root.of current drive
|
||||
string = copytext(string,2)
|
||||
//boutput(world, "string is now: [string]")
|
||||
|
||||
var/list/sort1 = dd_text2list(string,"/")
|
||||
if (sort1.len && copytext(sort1[1], 4, 5) == ":")
|
||||
. = lowertext( copytext(sort1[1], 1, 4) )
|
||||
if (length(sort1[1]) > 4)
|
||||
sort1[1] = copytext(sort1[1], 5)
|
||||
else
|
||||
sort1.Cut(1,2)
|
||||
switch (.)
|
||||
if ("hd0")
|
||||
if (master.hd)
|
||||
current = master.hd.root
|
||||
else
|
||||
return null
|
||||
|
||||
if ("fd0")
|
||||
if (master.diskette)
|
||||
current = master.diskette.root
|
||||
else
|
||||
return null
|
||||
|
||||
else
|
||||
if (cmptext(copytext(., 1, 3), "sd"))
|
||||
. = text2num(copytext(., 3))
|
||||
if (!isnum(.))
|
||||
return null
|
||||
|
||||
.++
|
||||
for (var/obj/item/disk/data/drive in master.contents)
|
||||
if (drive == master.hd || drive == master.diskette)
|
||||
continue
|
||||
|
||||
if (--. < 1)
|
||||
current = drive.root
|
||||
break
|
||||
|
||||
if (. > 0)
|
||||
return null
|
||||
|
||||
var/file_name = sort1[sort1.len]
|
||||
if(!file_name)
|
||||
return null
|
||||
|
||||
sort1 -= sort1[sort1.len]
|
||||
|
||||
while(current)
|
||||
|
||||
if(!sort1.len)
|
||||
var/datum/computer/file/check = get_file_name(file_name, current)
|
||||
if(check && istype(check))
|
||||
return check
|
||||
else
|
||||
return null
|
||||
|
||||
var/new_current = 0
|
||||
for(var/datum/computer/folder/F in current.contents)
|
||||
//boutput(world, "testing: [F.name] -- [sort1[1]] in folder [current]")
|
||||
if(ckey(F.name) == ckey(sort1[1]))
|
||||
//boutput(world, "matches: [F.name] -- [sort1[1]]")
|
||||
sort1 -= sort1[1]
|
||||
current = F
|
||||
new_current = 1
|
||||
break
|
||||
|
||||
if(!new_current)
|
||||
//boutput(world, "no new current")
|
||||
return null
|
||||
|
||||
return null
|
||||
|
||||
disk_ejected(var/obj/item/disk/data/thedisk) //So we can switch out of the floppy if it's ejected or whatever.
|
||||
if(!thedisk)
|
||||
return
|
||||
|
||||
if(src.holder == thedisk)
|
||||
src.print_text("<font color=red>Fatal Error. Returning to system...</font>")
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
//Find a folder with a given name
|
||||
get_folder_name(string, var/datum/computer/folder/check_folder)
|
||||
if(!string || (!check_folder || !istype(check_folder)))
|
||||
return null
|
||||
|
||||
var/datum/computer/taken = null
|
||||
for(var/datum/computer/folder/F in check_folder.contents)
|
||||
if(ckey(string) == ckey(F.name))
|
||||
taken = F
|
||||
break
|
||||
|
||||
return taken
|
||||
|
||||
//Find a file with a given name
|
||||
get_file_name(string, var/datum/computer/folder/check_folder)
|
||||
if(!string || (!check_folder || !istype(check_folder)))
|
||||
return null
|
||||
|
||||
var/datum/computer/taken = null
|
||||
for(var/datum/computer/file/F in check_folder.contents)
|
||||
if(ckey(string) == ckey(F.name))
|
||||
taken = F
|
||||
break
|
||||
|
||||
return taken
|
||||
|
||||
//Just find any computer datum with this name, gosh
|
||||
get_computer_datum(string, var/datum/computer/folder/check_folder)
|
||||
if(!string || (!check_folder || !istype(check_folder)))
|
||||
return null
|
||||
|
||||
var/datum/computer/taken = null
|
||||
for(var/datum/computer/C in check_folder.contents)
|
||||
if(ckey(string) == ckey(C.name))
|
||||
taken = C
|
||||
break
|
||||
|
||||
return taken
|
||||
|
||||
is_name_invalid(string) //Check if a filename is invalid somehow
|
||||
if(!string)
|
||||
return 1
|
||||
|
||||
if(ckey(string) != dd_replacetext(lowertext(string), " ", null))
|
||||
return 1
|
||||
|
||||
if(findtext(string, "/"))
|
||||
src.print_text("<b>Error:</b> Invalid character in name.")
|
||||
return 1
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
check_access(var/list/check_list)
|
||||
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) //still no requirements
|
||||
return 1
|
||||
if(!check_list || !istype(check_list, /list)) //invalid or no access
|
||||
return 0
|
||||
for(var/req in src.req_access)
|
||||
if(!(req in check_list)) //doesn't have this access
|
||||
return 0
|
||||
return 1
|
||||
@@ -0,0 +1,206 @@
|
||||
//Motherboard is just used in assembly/disassembly, doesn't exist in the actual computer object.
|
||||
/obj/item/motherboard
|
||||
name = "Computer mainboard"
|
||||
desc = "A computer motherboard."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
inhand_image_icon = 'icons/mob/inhand/hand_tools.dmi'
|
||||
icon_state = "mainboard"
|
||||
item_state = "electronic"
|
||||
w_class = 2.0
|
||||
var/created_name = null //If defined, result computer will have this name.
|
||||
var/integrated_floppy = 1 //Does the resulting computer have a built-in disk drive?
|
||||
mats = 8
|
||||
|
||||
/obj/computer3frame
|
||||
density = 1
|
||||
anchored = 0
|
||||
name = "Computer-frame"
|
||||
icon = 'icons/obj/computer_frame.dmi'
|
||||
icon_state = "0"
|
||||
var/state = 0
|
||||
var/obj/item/motherboard/mainboard = null
|
||||
var/obj/item/disk/data/fixed_disk/hd = null
|
||||
var/max_peripherals = 3
|
||||
var/list/peripherals = list()
|
||||
var/created_icon_state = "computer_generic"
|
||||
var/glass_needed = 2 //How much glass does this need for a screen?
|
||||
var/metal_given = 5 //How much metal does this give when destroyed?
|
||||
|
||||
terminal //Light frame
|
||||
name = "Terminal-frame"
|
||||
desc = "A light micro-computer frame used for terminal systems."
|
||||
icon = 'icons/obj/terminal_frame.dmi'
|
||||
created_icon_state = "dterm"
|
||||
max_peripherals = 2
|
||||
metal_given = 3
|
||||
glass_needed = 1
|
||||
|
||||
desktop //Those old desktop computers
|
||||
name = "Desktop Computer-frame"
|
||||
icon = 'icons/obj/computer_frame_desk.dmi'
|
||||
created_icon_state = "old"
|
||||
max_peripherals = 3
|
||||
metal_given = 3
|
||||
glass_needed = 1
|
||||
|
||||
blob_act(var/power)
|
||||
if (prob(power * 2.5))
|
||||
qdel(src)
|
||||
|
||||
/obj/computer3frame/meteorhit(obj/O as obj)
|
||||
qdel(src)
|
||||
|
||||
/obj/computer3frame/attackby(obj/item/P as obj, mob/user as mob)
|
||||
switch(state)
|
||||
if(0)
|
||||
if(istype(P, /obj/item/wrench))
|
||||
playsound(src.loc, "sound/items/Ratchet.ogg", 50, 1)
|
||||
if(do_after(user, 20))
|
||||
boutput(user, "<span style=\"color:blue\">You wrench the frame into place.</span>")
|
||||
src.anchored = 1
|
||||
src.state = 1
|
||||
if(istype(P, /obj/item/weldingtool))
|
||||
playsound(src.loc, "sound/items/Welder.ogg", 50, 1)
|
||||
if(do_after(user, 20))
|
||||
boutput(user, "<span style=\"color:blue\">You deconstruct the frame.</span>")
|
||||
var/obj/item/sheet/A = new /obj/item/sheet( src.loc )
|
||||
if(src.material)
|
||||
A.setMaterial(src.material)
|
||||
else
|
||||
var/datum/material/M = getCachedMaterial("steel")
|
||||
A.setMaterial(M)
|
||||
A.amount = src.metal_given
|
||||
qdel(src)
|
||||
if(1)
|
||||
if(istype(P, /obj/item/wrench))
|
||||
playsound(src.loc, "sound/items/Ratchet.ogg", 50, 1)
|
||||
if(do_after(user, 20))
|
||||
boutput(user, "<span style=\"color:blue\">You unfasten the frame.</span>")
|
||||
src.anchored = 0
|
||||
src.state = 0
|
||||
if(istype(P, /obj/item/motherboard) && !mainboard)
|
||||
playsound(src.loc, "sound/items/Deconstruct.ogg", 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">You place the mainboard inside the frame.</span>")
|
||||
src.icon_state = "1"
|
||||
src.mainboard = P
|
||||
user.drop_item()
|
||||
P.set_loc(src)
|
||||
if(istype(P, /obj/item/screwdriver) && mainboard)
|
||||
playsound(src.loc, "sound/items/Screwdriver.ogg", 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">You screw the mainboard into place.</span>")
|
||||
src.state = 2
|
||||
src.icon_state = "2"
|
||||
if(istype(P, /obj/item/crowbar) && mainboard)
|
||||
playsound(src.loc, "sound/items/Crowbar.ogg", 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">You remove the mainboard.</span>")
|
||||
src.state = 1
|
||||
src.icon_state = "0"
|
||||
mainboard.set_loc(src.loc)
|
||||
src.mainboard = null
|
||||
if(istype(P, /obj/item/circuitboard))
|
||||
boutput(user, "<span style=\"color:red\">This is the wrong type of frame, it won't fit!</span>")
|
||||
|
||||
if(2)
|
||||
if(istype(P, /obj/item/screwdriver) && mainboard && (!peripherals.len))
|
||||
playsound(src.loc, "sound/items/Screwdriver.ogg", 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">You unfasten the mainboard.</span>")
|
||||
src.state = 1
|
||||
src.icon_state = "1"
|
||||
|
||||
if(istype(P, /obj/item/peripheral))
|
||||
if(src.peripherals.len < src.max_peripherals)
|
||||
user.drop_item()
|
||||
src.peripherals.Add(P)
|
||||
P.set_loc(src)
|
||||
boutput(user, "<span style=\"color:blue\">You add [P] to the frame.</span>")
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">There is no more room for peripheral cards.</span>")
|
||||
|
||||
if(istype(P, /obj/item/crowbar) && src.peripherals.len)
|
||||
playsound(src.loc, "sound/items/Crowbar.ogg", 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">You remove the peripheral boards.</span>")
|
||||
for(var/obj/item/peripheral/W in src.peripherals)
|
||||
W.set_loc(src.loc)
|
||||
src.peripherals.Remove(W)
|
||||
W.uninstalled()
|
||||
|
||||
if(istype(P, /obj/item/cable_coil))
|
||||
if(P:amount >= 5)
|
||||
playsound(src.loc, "sound/items/Deconstruct.ogg", 50, 1)
|
||||
if(do_after(user, 20))
|
||||
if (!P) //Wire: Fix for Cannot read null.amount
|
||||
return
|
||||
P:amount -= 5
|
||||
if(!P:amount) qdel(P)
|
||||
boutput(user, "<span style=\"color:blue\">You add cables to the frame.</span>")
|
||||
src.state = 3
|
||||
src.icon_state = "3"
|
||||
if(3)
|
||||
if(istype(P, /obj/item/wirecutters))
|
||||
playsound(src.loc, "sound/items/Wirecutter.ogg", 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">You remove the cables.</span>")
|
||||
src.state = 2
|
||||
src.icon_state = "2"
|
||||
var/obj/item/cable_coil/A = new /obj/item/cable_coil( src.loc )
|
||||
A.amount = 5
|
||||
if(src.hd)
|
||||
src.hd.set_loc(src.loc)
|
||||
src.hd = null
|
||||
|
||||
if(istype(P, /obj/item/disk/data/fixed_disk) && !src.hd)
|
||||
user.drop_item()
|
||||
src.hd = P
|
||||
P.set_loc(src)
|
||||
boutput(user, "<span style=\"color:blue\">You connect the drive to the cabling.</span>")
|
||||
|
||||
if(istype(P, /obj/item/crowbar) && src.hd)
|
||||
playsound(src.loc, "sound/items/Crowbar.ogg", 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">You remove the hard drive.</span>")
|
||||
src.hd.set_loc(src.loc)
|
||||
src.hd = null
|
||||
|
||||
if(istype(P, /obj/item/sheet))
|
||||
var/obj/item/sheet/S = P
|
||||
if (S.material && S.material.material_flags & MATERIAL_CRYSTAL)
|
||||
if (S.amount >= src.glass_needed)
|
||||
playsound(src.loc, "sound/items/Deconstruct.ogg", 50, 1)
|
||||
if(do_after(user, 20) && S)
|
||||
S.amount -= src.glass_needed
|
||||
if(S.amount < 1)
|
||||
qdel(S)
|
||||
boutput(user, "<span style=\"color:blue\">You put in the glass panel.</span>")
|
||||
src.state = 4
|
||||
src.icon_state = "4"
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">There's not enough sheets on the stack.</span>")
|
||||
else
|
||||
boutput(user, "<span style=\"color:red\">You need sheets of some kind of crystal or glass for this.</span>")
|
||||
if(4)
|
||||
if(istype(P, /obj/item/crowbar))
|
||||
playsound(src.loc, "sound/items/Crowbar.ogg", 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">You remove the glass panel.</span>")
|
||||
src.state = 3
|
||||
src.icon_state = "3"
|
||||
var/obj/item/sheet/glass/A = new /obj/item/sheet/glass(src.loc)
|
||||
A.amount = src.glass_needed
|
||||
|
||||
if(istype(P, /obj/item/screwdriver))
|
||||
playsound(src.loc, "sound/items/Screwdriver.ogg", 50, 1)
|
||||
boutput(user, "<span style=\"color:blue\">You connect the monitor.</span>")
|
||||
var/obj/machinery/computer3/C= new /obj/machinery/computer3( src.loc )
|
||||
if(src.material) C.setMaterial(src.material)
|
||||
C.setup_drive_size = 0
|
||||
C.icon_state = src.created_icon_state
|
||||
C.setup_frame_type = src.type
|
||||
if(mainboard.created_name) C.name = mainboard.created_name
|
||||
if(mainboard.integrated_floppy) C.setup_has_internal_disk = 1
|
||||
//qdel(mainboard)
|
||||
mainboard.dispose()
|
||||
if(hd)
|
||||
C.hd = hd
|
||||
hd.set_loc(C)
|
||||
for(var/obj/item/peripheral/W in src.peripherals)
|
||||
W.set_loc(C)
|
||||
W.installed(C) //Set C as their host, etc
|
||||
//dispose()
|
||||
src.dispose()
|
||||
@@ -0,0 +1,291 @@
|
||||
/obj/machinery/communications_dish
|
||||
name = "Communications dish"
|
||||
icon = 'icons/mob/hivebot.dmi'
|
||||
icon_state = "def_radar"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/list/messagetitle = list()
|
||||
var/list/messagetext = list()
|
||||
var/list/terminals = list() //list of netIDs of connected terminals.
|
||||
var/net_id = null
|
||||
var/obj/machinery/power/data_terminal/link = null
|
||||
//Radio inter-dish communications
|
||||
var/frequency = "0000"
|
||||
var/datum/radio_frequency/radio_connection
|
||||
|
||||
mats = 25
|
||||
|
||||
New()
|
||||
..()
|
||||
spawn(6)
|
||||
if(!src.link)
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/machinery/power/data_terminal/test_link = locate() in T
|
||||
if(test_link && !test_link.is_valid_master(test_link.master))
|
||||
src.link = test_link
|
||||
src.link.master = src
|
||||
|
||||
if(radio_controller)
|
||||
initialize()
|
||||
src.net_id = generate_net_id(src)
|
||||
|
||||
initialize()
|
||||
radio_connection = radio_controller.add_object(src, "[frequency]")
|
||||
|
||||
proc
|
||||
add_centcom_report(var/title, var/message)
|
||||
if (!message)
|
||||
return
|
||||
|
||||
if (src.stat & (BROKEN|NOPOWER) )
|
||||
return
|
||||
|
||||
if (!title)
|
||||
title = "Cent. Com. Report"
|
||||
|
||||
messagetitle += title
|
||||
messagetext += message
|
||||
|
||||
if (!src.link)
|
||||
return
|
||||
|
||||
var/list/report_content = list(title) + dd_text2list(message, "<BR>")
|
||||
|
||||
for (var/listener_netid in src.terminals)
|
||||
var/datum/computer/file/record/report = new ()
|
||||
report.fields = report_content.Copy()
|
||||
report.name = "report[messagetext.len]"
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
signal.source = src
|
||||
signal.transmission_method = TRANSMISSION_WIRE
|
||||
signal.data["command"] = "term_file"
|
||||
signal.data["data"] = "command=add_report"
|
||||
signal.data_file = report
|
||||
|
||||
signal.data["address_1"] = listener_netid
|
||||
signal.data["sender"] = src.net_id
|
||||
|
||||
src.link.post_signal(src, signal)
|
||||
|
||||
|
||||
post_status(var/target_id, var/key, var/value, var/key2, var/value2, var/key3, var/value3)
|
||||
if(!src.link || !target_id)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
signal.source = src
|
||||
signal.transmission_method = TRANSMISSION_WIRE
|
||||
signal.data[key] = value
|
||||
if(key2)
|
||||
signal.data[key2] = value2
|
||||
if(key3)
|
||||
signal.data[key3] = value3
|
||||
|
||||
signal.data["address_1"] = target_id
|
||||
signal.data["sender"] = src.net_id
|
||||
|
||||
src.link.post_signal(src, signal)
|
||||
|
||||
post_reply(error_text, target_id)
|
||||
if(!error_text || !target_id)
|
||||
return
|
||||
spawn(3)
|
||||
src.post_status(target_id, "command", "device_reply", "status", error_text)
|
||||
return
|
||||
|
||||
parse_string(string) //Parse commands the same way a c3 does, for terminal control.
|
||||
var/list/sort1 = list()
|
||||
sort1 = dd_text2list(string,";")
|
||||
for(var/x in sort1)
|
||||
var/list/sorted = list()
|
||||
sorted = dd_text2list(x," ")
|
||||
return sorted
|
||||
|
||||
receive_signal(datum/signal/signal)
|
||||
if(stat & (NOPOWER|BROKEN) || !src.link)
|
||||
return
|
||||
if(!signal || !src.net_id || signal.encryption)
|
||||
return
|
||||
|
||||
if(signal.transmission_method != TRANSMISSION_WIRE) //No radio for us thanks
|
||||
return
|
||||
|
||||
var/target = signal.data["sender"]
|
||||
|
||||
//They don't need to target us specifically to ping us.
|
||||
//Otherwise, ff they aren't addressing us, ignore them
|
||||
if(signal.data["address_1"] != src.net_id)
|
||||
if((signal.data["address_1"] == "ping") && signal.data["sender"])
|
||||
spawn(5) //Send a reply for those curious jerks
|
||||
src.post_status(target, "command", "ping_reply", "device", "PNET_COM_ARRAY", "netid", src.net_id)
|
||||
|
||||
return
|
||||
|
||||
var/sigcommand = lowertext(signal.data["command"])
|
||||
if(!sigcommand || !signal.data["sender"])
|
||||
return
|
||||
|
||||
switch(sigcommand)
|
||||
if("call", "recall") //Time to call/cancel a shuttle!
|
||||
switch(signal.data["shuttle_id"])
|
||||
if("emergency")
|
||||
if(signal.data["acc_code"] != netpass_heads) //Cool dudes with head codes only thanks.
|
||||
return //Otherwise you have every jerk calling the shuttle from medbay or some shit.
|
||||
|
||||
if(emergency_shuttle.location!=0)
|
||||
src.post_reply("SHUTL_E_DIS", target)
|
||||
return
|
||||
|
||||
if(sigcommand == "call")
|
||||
//don't spam call it you buttes
|
||||
if(emergency_shuttle.online || call_shuttle_proc()) //Returns 1 on failure
|
||||
src.post_reply("SHUTL_E_DIS", target)
|
||||
return
|
||||
src.post_reply("SHUTL_E_SEN", target)
|
||||
else if(sigcommand == "recall")
|
||||
if(!emergency_shuttle.online || cancel_call_proc())
|
||||
src.post_reply("SHUTL_E_DIS", target)
|
||||
return
|
||||
src.post_reply("SHUTL_E_RET", target)
|
||||
else
|
||||
//to-do: error reply
|
||||
if("term_connect") //Terminal interface stuff.
|
||||
if(target in src.terminals)
|
||||
//something might be wrong here, disconnect them!
|
||||
src.terminals.Remove(target)
|
||||
spawn(3)
|
||||
src.post_status(target, "command","term_disconnect")
|
||||
return
|
||||
|
||||
src.terminals.Add(target) //Accept the connection!
|
||||
src.post_status(target, "command","term_connect","data","noreply","device","PNET_COM_ARRAY")
|
||||
src.updateUsrDialog()
|
||||
spawn(2) //Hello!
|
||||
src.post_status(target,"command","term_message","data","command=register")
|
||||
return
|
||||
|
||||
if("term_message")
|
||||
if(!(target in src.terminals)) //Ignore mystery jerks who aren't connected.
|
||||
return
|
||||
|
||||
var/list/commandList = params2list(signal.data["data"])
|
||||
if (!commandList || !commandList.len)
|
||||
return
|
||||
|
||||
switch (commandList["command"])
|
||||
if ("list")
|
||||
. = list()
|
||||
for(var/x, x <= src.messagetitle.len, x++)
|
||||
var/mtitle = src.messagetitle[x]
|
||||
if(isnull(mtitle)) continue
|
||||
|
||||
.["[add_zero("[x]",2)]"] = "[mtitle]"
|
||||
|
||||
spawn(3)
|
||||
src.post_status(target, "command","term_message","data",list2params(.),"render","multiline")
|
||||
return
|
||||
|
||||
if ("download")
|
||||
var/msg_id = round(text2num(commandList["message"]))
|
||||
|
||||
if(!msg_id || msg_id > src.messagetext.len)
|
||||
return
|
||||
|
||||
var/to_send = src.messagetext[msg_id]
|
||||
if(!to_send) return
|
||||
|
||||
//post status doesn't cover file attachments, so we do it here
|
||||
if(!src.link || !target)
|
||||
return
|
||||
|
||||
var/datum/computer/file/text/sendfile = new
|
||||
sendfile.name = "temp"
|
||||
sendfile.data = to_send
|
||||
|
||||
var/datum/signal/filesig = new()
|
||||
filesig.source = src
|
||||
filesig.transmission_method = TRANSMISSION_WIRE
|
||||
|
||||
filesig.data_file = sendfile
|
||||
filesig.data["command"] = "term_file"
|
||||
filesig.data["data"] = ""
|
||||
filesig.data["address_1"] = target
|
||||
filesig.data["sender"] = src.net_id
|
||||
|
||||
spawn(3)
|
||||
src.link.post_signal(src, filesig)
|
||||
|
||||
/*
|
||||
var/termcommand = lowertext(signal.data["data"])
|
||||
if(!termcommand) return
|
||||
var/list/termlist = parse_string(termcommand)
|
||||
termcommand = termlist[1]
|
||||
termlist -= termlist[1]
|
||||
|
||||
switch(termcommand)
|
||||
if("list")
|
||||
var/listdat = null
|
||||
for(var/x, x <= src.messagetitle.len, x++)
|
||||
var/mtitle = src.messagetitle[x]
|
||||
if(isnull(mtitle)) continue
|
||||
|
||||
listdat += "MSG:\[[add_zero("[x]",2)]] [mtitle]|n"
|
||||
|
||||
if(!listdat)
|
||||
listdat = "No messages available."
|
||||
|
||||
spawn(3)
|
||||
src.post_status(target, "command","term_message","data",listdat,"render","multiline")
|
||||
return
|
||||
|
||||
if("download")
|
||||
var/msg_id = 0
|
||||
if(termlist.len)
|
||||
msg_id = round(text2num(termlist[1]))
|
||||
|
||||
if(!msg_id || msg_id > src.messagetext.len)
|
||||
return
|
||||
|
||||
var/to_send = src.messagetext[msg_id]
|
||||
if(!to_send) return
|
||||
|
||||
//post status doesn't cover file attachments, so we do it here
|
||||
if(!src.link || !target)
|
||||
return
|
||||
|
||||
var/datum/computer/file/text/sendfile = new
|
||||
sendfile.name = "temp"
|
||||
sendfile.data = to_send
|
||||
|
||||
var/datum/signal/filesig = new()
|
||||
filesig.source = src
|
||||
filesig.transmission_method = TRANSMISSION_WIRE
|
||||
|
||||
filesig.data_file = sendfile
|
||||
filesig.data["command"] = "term_file"
|
||||
filesig.data["address_1"] = target
|
||||
filesig.data["sender"] = src.net_id
|
||||
|
||||
spawn(3)
|
||||
src.link.post_signal(src, filesig)
|
||||
*/
|
||||
return
|
||||
|
||||
if("term_ping")
|
||||
if(!(target in terminals))
|
||||
return
|
||||
if(signal.data["data"] == "reply")
|
||||
src.post_status(target, "command","term_ping")
|
||||
//src.timeout = initial(src.timeout)
|
||||
//src.timeout_alert = 0 //no really please stay zero
|
||||
return
|
||||
|
||||
if("term_disconnect")
|
||||
if(target in src.terminals)
|
||||
src.terminals -= target
|
||||
|
||||
return
|
||||
|
||||
|
||||
return
|
||||
@@ -0,0 +1,249 @@
|
||||
/datum/computer/file/terminal_program/communications
|
||||
name = "COMMaster"
|
||||
size = 16
|
||||
req_access = list(access_heads)
|
||||
var/tmp/authenticated = null //Are we currently logged in?
|
||||
var/datum/computer/file/user_data/account = null
|
||||
var/obj/item/peripheral/network/radio/radiocard = null
|
||||
var/obj/item/peripheral/network/powernet_card/pnet_card = null
|
||||
var/tmp/comm_net_id = null //The net id of our linked ~comm dish~
|
||||
var/tmp/reply_wait = -1 //How long do we wait for replies? -1 is not waiting.
|
||||
|
||||
var/setup_acc_filepath = "/logs/sysusr"//Where do we look for login data?
|
||||
|
||||
initialize()
|
||||
|
||||
src.authenticated = null
|
||||
src.master.temp = null
|
||||
if(!src.find_access_file()) //Find the account information, as it's essentially a ~digital ID card~
|
||||
src.print_text("<b>Error:</b> Cannot locate user file. Quitting...")
|
||||
src.master.unload_program(src) //Oh no, couldn't find the file.
|
||||
return
|
||||
|
||||
src.radiocard = locate() in src.master.peripherals
|
||||
if(!radiocard || !istype(src.radiocard))
|
||||
src.radiocard = null
|
||||
src.print_text("<b>Warning:</b> No radio module detected.")
|
||||
|
||||
src.pnet_card = locate() in src.master.peripherals
|
||||
if(!pnet_card || !istype(src.pnet_card))
|
||||
src.pnet_card = null
|
||||
src.print_text("<b>Warning:</b> No network adapter detected.")
|
||||
|
||||
if(!src.check_access(src.account.access))
|
||||
src.print_text("User [src.account.registered] does not have needed access credentials.<br>Quitting...")
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
|
||||
src.reply_wait = -1
|
||||
src.authenticated = src.account.registered
|
||||
|
||||
src.print_shuttle_status()
|
||||
var/intro_text = {"<br>Welcome to COMMaster!
|
||||
<br>InterStation Communication System.
|
||||
<br><b>Commands:</b>
|
||||
<br>(Status) to view current status.
|
||||
<br>(Link) to link with a comm array.
|
||||
<br>(Call) to call shuttle.
|
||||
<br>(Recall) to recall shuttle.
|
||||
<br>(Clear) to clear the screen.
|
||||
<br>(Quit) to exit COMMaster."}
|
||||
src.print_text(intro_text)
|
||||
|
||||
|
||||
input_text(text)
|
||||
if(..())
|
||||
return
|
||||
|
||||
var/list/command_list = parse_string(text)
|
||||
var/command = command_list[1]
|
||||
command_list -= command_list[1] //Remove the command we are now processing.
|
||||
|
||||
switch(lowertext(command))
|
||||
|
||||
if("status")
|
||||
src.print_shuttle_status()
|
||||
|
||||
if("link")
|
||||
if(!src.pnet_card) //can't do this ~fancy network stuff~ without a network card.
|
||||
src.print_text("<b>Error:</b> Network card required.")
|
||||
src.master.add_fingerprint(usr)
|
||||
return
|
||||
|
||||
src.print_text("Now scanning for communications array...")
|
||||
src.detect_comm_dish()
|
||||
|
||||
if("call")
|
||||
if(!src.pnet_card)
|
||||
src.print_text("<b>Error:</b> Network card required.")
|
||||
src.master.add_fingerprint(usr)
|
||||
return
|
||||
|
||||
if(!src.comm_net_id)
|
||||
src.detect_comm_dish()
|
||||
sleep(8)
|
||||
if (!src.comm_net_id)
|
||||
src.print_text("<b>Error:</b> Unable to detect comm dish. Please check network cabling.")
|
||||
return
|
||||
|
||||
if (solar_flare)
|
||||
src.print_text("Solar Flare activity is preventing contact with the Emergency Shuttle.")
|
||||
else
|
||||
src.print_text("Transmitting call request...")
|
||||
generate_signal(comm_net_id, "command", "call", "shuttle_id", "emergency", "acc_code", netpass_heads)
|
||||
|
||||
if("recall")
|
||||
if(!src.pnet_card)
|
||||
src.print_text("<b>Error:</b> Network card required.")
|
||||
src.master.add_fingerprint(usr)
|
||||
return
|
||||
|
||||
if(istype(usr, /mob/living/silicon/ai) || src.authenticated == "AIUSR")
|
||||
src.print_text("<b>Error:</b> Shuttle recall from AIUSR blocked by Central Command.")
|
||||
return
|
||||
|
||||
if(!src.comm_net_id)
|
||||
src.detect_comm_dish()
|
||||
sleep(8)
|
||||
if (!src.comm_net_id)
|
||||
src.print_text("<b>Error:</b> Unable to detect comm dish. Please check network cabling.")
|
||||
return
|
||||
|
||||
if (solar_flare)
|
||||
src.print_text("Solar Flare activity is preventing contact with the Emergency Shuttle.")
|
||||
else
|
||||
src.print_text("Transmitting recall request...")
|
||||
generate_signal(comm_net_id, "command", "recall", "shuttle_id", "emergency", "acc_code", netpass_heads)
|
||||
|
||||
if("help")
|
||||
var/help_text = {"<b>Commands:</b>
|
||||
<br>(Status) to view current status.
|
||||
<br>(Link) to link with a comm array.
|
||||
<br>(Call) to call shuttle.
|
||||
<br>(Recall) to recall shuttle.
|
||||
<br>(Clear) to clear the screen.
|
||||
<br>(Quit) to exit COMMaster."}
|
||||
src.print_text(help_text)
|
||||
|
||||
if("clear")
|
||||
src.master.temp = null
|
||||
src.master.temp_add = "Workspace cleared.<br>"
|
||||
|
||||
if("quit")
|
||||
src.master.temp = ""
|
||||
print_text("Now quitting...")
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
|
||||
else
|
||||
print_text("Unknown command : \"[copytext(strip_html(command), 1, 16)]\"")
|
||||
|
||||
|
||||
src.master.add_fingerprint(usr)
|
||||
src.master.updateUsrDialog()
|
||||
return
|
||||
|
||||
process()
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(src.reply_wait > 0)
|
||||
src.reply_wait--
|
||||
if(src.reply_wait == 0)
|
||||
src.print_text("Timed out on Dish. Please rescan and retry.")
|
||||
src.comm_net_id = null
|
||||
|
||||
receive_command(obj/source, command, datum/signal/signal)
|
||||
if((..()) || (!signal))
|
||||
return
|
||||
|
||||
//If we don't have a comm dish net_id to use, set one.
|
||||
switch(signal.data["command"])
|
||||
if("ping_reply")
|
||||
if(src.comm_net_id)
|
||||
return
|
||||
if((signal.data["device"] != "PNET_COM_ARRAY") || !signal.data["netid"])
|
||||
return
|
||||
|
||||
src.comm_net_id = signal.data["netid"]
|
||||
src.print_text("Communications array detected.")
|
||||
if("device_reply")
|
||||
if(!src.comm_net_id || signal.data["sender"] != src.comm_net_id)
|
||||
return
|
||||
|
||||
src.reply_wait = -1
|
||||
|
||||
switch(lowertext(signal.data["status"]))
|
||||
if("shutl_e_dis")
|
||||
src.print_text("<b>Alert:</b> Shuttle command request rejected!")
|
||||
|
||||
if("shutl_e_sen")
|
||||
src.print_text("<b>Alert:</b> The Emergency Shuttle has been called.")
|
||||
if(master && master.current_user)
|
||||
message_admins("<span style=\"color:blue\">[key_name(master.current_user)] called the Emergency Shuttle to the station</span>")
|
||||
logTheThing("station", null, null, "[key_name(master.current_user)] called the Emergency Shuttle to the station")
|
||||
|
||||
if("shutl_e_ret")
|
||||
src.print_text("<b>Alert:</b> The Emergency Shuttle has been recalled.")
|
||||
if(master && master.current_user)
|
||||
message_admins("<span style=\"color:blue\">[key_name(master.current_user)] recalled the Emergency Shuttle</span>")
|
||||
logTheThing("station", null, null, "[key_name(master.current_user)] recalled the Emergency Shuttle")
|
||||
|
||||
return
|
||||
|
||||
|
||||
return
|
||||
|
||||
proc
|
||||
find_access_file() //Look for the whimsical account_data file
|
||||
var/datum/computer/folder/accdir = src.holder.root
|
||||
if(src.master.host_program) //Check where the OS is, preferably.
|
||||
accdir = src.master.host_program.holder.root
|
||||
|
||||
var/datum/computer/file/user_data/target = parse_file_directory(setup_acc_filepath, accdir)
|
||||
if(target && istype(target))
|
||||
src.account = target
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
detect_comm_dish() //Send out a ping signal to find a comm dish.
|
||||
if(!src.pnet_card)
|
||||
return //The card is kinda crucial for this.
|
||||
|
||||
var/datum/signal/newsignal = get_free_signal()
|
||||
//newsignal.encryption = "\ref[src.pnet_card]"
|
||||
|
||||
src.comm_net_id = null
|
||||
src.reply_wait = -1
|
||||
src.peripheral_command("ping", newsignal, "\ref[src.pnet_card]")
|
||||
|
||||
generate_signal(var/target_id, var/key, var/value, var/key2, var/value2, var/key3, var/value3)
|
||||
if(!src.pnet_card || !comm_net_id)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
//signal.encryption = "\ref[src.pnet_card]"
|
||||
signal.data["address_1"] = target_id
|
||||
signal.data[key] = value
|
||||
if(key2)
|
||||
signal.data[key2] = value2
|
||||
if(key3)
|
||||
signal.data[key3] = value3
|
||||
|
||||
src.reply_wait = 5
|
||||
src.peripheral_command("transmit", signal, "\ref[src.pnet_card]")
|
||||
|
||||
|
||||
|
||||
print_shuttle_status()
|
||||
var/dat = "<b>Status</b>: "
|
||||
if (emergency_shuttle.online && emergency_shuttle.location==0)
|
||||
var/timeleft = emergency_shuttle.timeleft()
|
||||
dat += "<b>Emergency shuttle</b><br>ETA: [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]"
|
||||
else
|
||||
dat += "No shuttles currently en route."
|
||||
|
||||
src.print_text(dat)
|
||||
|
||||
return
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,317 @@
|
||||
//CONTENTS
|
||||
//Base disk
|
||||
//Base fixed disk
|
||||
//Base memcard
|
||||
//Base tape reel (HEH)
|
||||
//Base "read only" floppy.
|
||||
//Computer3 boot floppy
|
||||
//Network tools floppy
|
||||
//Medical program floppy
|
||||
//Security program floppy
|
||||
//Research programs floppy
|
||||
//Computer3-formatted fixed disk.
|
||||
//Box of tapes
|
||||
|
||||
|
||||
/obj/item/disk/data
|
||||
name = "data disk"
|
||||
icon = 'icons/obj/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
|
||||
//DNA machine vars
|
||||
var/data = ""
|
||||
var/ue = 0
|
||||
var/data_type = "ui" //ui|se
|
||||
var/owner = "Farmer Jeff"
|
||||
var/read_only = 0 //Well,it's still a floppy disk
|
||||
//Filesystem vars
|
||||
var/datum/computer/folder/root = null
|
||||
var/file_amount = 32
|
||||
var/file_used = 0
|
||||
var/portable = 1
|
||||
var/title = "Data Disk"
|
||||
New()
|
||||
src.root = new /datum/computer/folder
|
||||
src.root.holder = src
|
||||
src.root.name = "root"
|
||||
|
||||
disposing()
|
||||
if (root)
|
||||
root.dispose()
|
||||
root = null
|
||||
|
||||
data = null
|
||||
..()
|
||||
|
||||
clone()
|
||||
var/obj/item/disk/data/D = ..()
|
||||
if (!D)
|
||||
return
|
||||
|
||||
D.data = src.data
|
||||
D.ue = src.ue
|
||||
D.data_type = src.data_type
|
||||
D.owner = src.owner
|
||||
D.read_only = src.read_only
|
||||
|
||||
D.title = src.title
|
||||
D.file_amount = src.file_amount
|
||||
if (src.root)
|
||||
D.root = src.root.copy_folder()
|
||||
D.root.holder = D
|
||||
|
||||
return D
|
||||
|
||||
/obj/item/disk/data/floppy
|
||||
var/random_color = 1
|
||||
|
||||
/obj/item/disk/data/floppy/New()
|
||||
..()
|
||||
if(random_color)
|
||||
var/diskcolor = pick(0,1,2)
|
||||
src.icon_state = "datadisk[diskcolor]"
|
||||
|
||||
/obj/item/disk/data/floppy/attack_self(mob/user as mob)
|
||||
src.read_only = !src.read_only
|
||||
boutput(user, "You flip the write-protect tab to [src.read_only ? "protected" : "unprotected"].")
|
||||
|
||||
/obj/item/disk/data/floppy/examine()
|
||||
set src in oview(5)
|
||||
..()
|
||||
boutput(usr, text("The write-protect tab is set to [src.read_only ? "protected" : "unprotected"]."))
|
||||
return
|
||||
|
||||
/obj/item/disk/data/floppy/demo
|
||||
name = "data disk - 'Farmer Jeff'"
|
||||
data = "0C80C80C80C80C80C8000000000000161FBDDEF"
|
||||
ue = 1
|
||||
read_only = 1
|
||||
|
||||
/obj/item/disk/data/floppy/monkey
|
||||
name = "data disk - 'Mr. Muggles'"
|
||||
data_type = "se"
|
||||
data = "0983E840344C39F4B059D5145FC5785DC6406A4FFF"
|
||||
read_only = 1
|
||||
|
||||
/obj/item/disk/data/fixed_disk
|
||||
name = "Storage Drive"
|
||||
icon_state = "harddisk"
|
||||
title = "Storage Drive"
|
||||
file_amount = 80
|
||||
portable = 0
|
||||
|
||||
/obj/item/disk/data/memcard
|
||||
name = "Memory Board"
|
||||
icon_state = "memcard"
|
||||
desc = "A large board of non-volatile memory."
|
||||
title = "MEMCORE"
|
||||
file_amount = 640
|
||||
portable = 0
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if (istype(W, /obj/item/device/multitool))
|
||||
user.visible_message("<span style=\"color:red\"><b>[user] begins to clear the [src]!</b></span>","You begin to clear the [src].")
|
||||
if(do_after(user, 30))
|
||||
user.visible_message("<span style=\"color:red\"><b>[user] clears the [src]!</b></span>","You clear the [src].")
|
||||
//qdel(src.root)
|
||||
if (src.root)
|
||||
src.root.dispose()
|
||||
|
||||
src.root = new /datum/computer/folder
|
||||
src.root.holder = src
|
||||
src.root.name = "root"
|
||||
return
|
||||
|
||||
/obj/item/disk/data/tape
|
||||
name = "ThinkTape"
|
||||
desc = "A form of proprietary magnetic data tape used by Thinktronic Data Systems, LLC."
|
||||
title = "MAGTAPE"
|
||||
icon_state = "tape"
|
||||
item_state = "paper"
|
||||
file_amount = 128
|
||||
portable = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
src.root.gen = 99 //No subfolders!!
|
||||
return
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if (istype(W, /obj/item/pen))
|
||||
var/t = input(user, "Enter new tape label", src.name, null) as text
|
||||
t = copytext(strip_html(t), 1, 36)
|
||||
if (!in_range(src, usr) && src.loc != usr)
|
||||
return
|
||||
if (!t)
|
||||
src.name = "ThinkTape"
|
||||
return
|
||||
|
||||
src.name = "ThinkTape-'[t]'"
|
||||
else
|
||||
..()
|
||||
return
|
||||
|
||||
//Floppy disks that are read-only ONLY.
|
||||
//It's good to have a more permanent source of programs when somebody deletes everything (until they space all the disks)
|
||||
//Remember to actually set them as read only after adding files in New()
|
||||
/obj/item/disk/data/floppy/read_only
|
||||
name = "Permafloppy"
|
||||
|
||||
attack_self(mob/user as mob)
|
||||
boutput(user, "<span style=\"color:red\">You can't flip the write-protect tab, it's held in place with glue or something!</span>")
|
||||
return
|
||||
|
||||
/obj/item/disk/data/floppy/computer3boot
|
||||
name = "data disk-'ThinkDOS'"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/os/main_os(src))
|
||||
var/datum/computer/folder/newfolder = new /datum/computer/folder( )
|
||||
newfolder.name = "logs"
|
||||
src.root.add_file( newfolder )
|
||||
newfolder.add_file( new /datum/computer/file/record/c3help(src))
|
||||
newfolder = new /datum/computer/folder
|
||||
newfolder.name = "bin"
|
||||
src.root.add_file( newfolder )
|
||||
newfolder.add_file( new /datum/computer/file/terminal_program/writewizard(src))
|
||||
|
||||
/obj/item/disk/data/floppy/read_only/network_progs
|
||||
name = "data disk-'Network Tools'"
|
||||
desc = "A collection of network management tools."
|
||||
title = "Network Help"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/background/ping(src))
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/background/signal_catcher(src))
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/file_transfer(src))
|
||||
//src.root.add_file( new /datum/computer/file/terminal_program/sigcrafter(src))
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/sigpal(src))
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/email(src))
|
||||
src.read_only = 1
|
||||
|
||||
/obj/item/disk/data/floppy/read_only/medical_progs
|
||||
name = "data disk-'Med-Trak 4'"
|
||||
desc = "The future of professional medical record management"
|
||||
title = "Med-Trak 4"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/medical_records(src))
|
||||
src.read_only = 1
|
||||
|
||||
/obj/item/disk/data/floppy/read_only/security_progs
|
||||
name = "data disk-'SecMate 6'"
|
||||
desc = "It manages security records. It is the law."
|
||||
title = "SecMate 6"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/secure_records(src))
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/manifest(src))
|
||||
src.read_only = 1
|
||||
|
||||
/obj/item/disk/data/floppy/read_only/research_progs
|
||||
name = "data disk-'AutoMate'"
|
||||
desc = "A disk containing a popular robotics research application."
|
||||
title = "Research"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/robotics_research(src))
|
||||
src.read_only = 1
|
||||
|
||||
/obj/item/disk/data/floppy/read_only/ext_research_progs
|
||||
name = "data disk-'Research Suite'"
|
||||
desc = "A disk of research programs."
|
||||
title = "Research"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/artifact_research(src))
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/disease_research(src))
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/robotics_research(src))
|
||||
src.read_only = 1
|
||||
|
||||
/obj/item/disk/data/floppy/read_only/terminal_os
|
||||
name = "data disk-'TermOS B'"
|
||||
desc = "A boot-disk for terminal systems."
|
||||
title = "TermOS"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/os/terminal_os(src))
|
||||
src.read_only = 1
|
||||
|
||||
/obj/item/disk/data/floppy/read_only/communications
|
||||
name = "data disk-'COMMaster'"
|
||||
desc = "A disk for station communication programs."
|
||||
title = "COMMaster"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/communications(src))
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/manifest(src))
|
||||
src.read_only = 1
|
||||
#ifdef SINGULARITY_TIME
|
||||
/obj/item/disk/data/floppy/read_only/engine_prog
|
||||
name = "data disk-'EngineMaster'"
|
||||
desc = "A disk with an engine startup program."
|
||||
title = "EngineDisk"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/engine_control(src))
|
||||
src.read_only = 1
|
||||
#endif
|
||||
|
||||
/obj/item/disk/data/floppy/read_only/authentication
|
||||
name = "Authentication Disk"
|
||||
desc = "Capable of storing entire kilobytes of information, this disk carries activation codes for various secure things that aren't nuclear bombs."
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "nucleardisk"
|
||||
item_state = "card-id"
|
||||
w_class = 1.0
|
||||
mats = 15
|
||||
random_color = 0
|
||||
file_amount = 32.0
|
||||
|
||||
New()
|
||||
..()
|
||||
spawn (10) //Give time to actually generate network passes I guess.
|
||||
//src.root.add_file( new /datum/computer/file/nuclear_auth(src))
|
||||
var/datum/computer/file/record/authrec = new /datum/computer/file/record {name = "GENAUTH";} (src)
|
||||
authrec.fields = list("HEADS"="[netpass_heads]",
|
||||
"SEC"="[netpass_security]",
|
||||
"MED"="[netpass_medical]")
|
||||
|
||||
src.root.add_file( authrec )
|
||||
src.root.add_file( new /datum/computer/file/terminal_program/communications(src))
|
||||
src.read_only = 1
|
||||
|
||||
/obj/item/disk/data/floppy/devkit
|
||||
name = "data disk-'Development'"
|
||||
title = "T-DISK"
|
||||
|
||||
//A fixed disk with some structure already set up for the main os I guess
|
||||
/obj/item/disk/data/fixed_disk/computer3
|
||||
New()
|
||||
..()
|
||||
//First off, create the directory for logging stuff
|
||||
var/datum/computer/folder/newfolder = new /datum/computer/folder( )
|
||||
newfolder.name = "logs"
|
||||
src.root.add_file( newfolder )
|
||||
newfolder.add_file( new /datum/computer/file/record/c3help(src))
|
||||
//This is the bin folder. For various programs I guess sure why not.
|
||||
newfolder = new /datum/computer/folder
|
||||
newfolder.name = "bin"
|
||||
src.root.add_file( newfolder )
|
||||
//newfolder.add_file( new /datum/computer/file/terminal_program/sigcrafter(src))
|
||||
newfolder.add_file( new /datum/computer/file/terminal_program/sigpal(src))
|
||||
newfolder.add_file( new /datum/computer/file/terminal_program/background/signal_catcher(src))
|
||||
if (prob(75))
|
||||
newfolder.add_file( new /datum/computer/file/terminal_program/writewizard(src))
|
||||
else
|
||||
newfolder.add_file( new /datum/computer/file/terminal_program/file_transfer(src))
|
||||
@@ -0,0 +1,806 @@
|
||||
//CONTENTS
|
||||
//Email client!!
|
||||
|
||||
|
||||
#define MENU_MAIN 0 //Fun reminder that Byond does not have enums and probably never will.
|
||||
#define MENU_SETTINGS 1
|
||||
#define MENU_SETTING_INPUT 2
|
||||
#define MENU_MAIL_INDEX 3
|
||||
#define MENU_MAIL_SELECT 4
|
||||
#define MENU_MAIL_VIEW 5
|
||||
#define MENU_WAIT 6
|
||||
#define MENU_EDIT 7
|
||||
|
||||
#define MAIL_MODE_VIEW "V"
|
||||
#define MAIL_MODE_DELETE "D"
|
||||
#define MAIL_MODE_FORWARD "F"
|
||||
#define MAIL_MODE_REPLY "R"
|
||||
|
||||
#define EDIT_MODE_TARGET 1
|
||||
#define EDIT_MODE_SUBJ 2
|
||||
#define EDIT_MODE_BODY 3
|
||||
#define EDIT_MODE_REPLYBODY 4
|
||||
#define EDIT_MODE_FWD_TARGET 5
|
||||
|
||||
#define MAX_MAIL_TITLE_LEN 32
|
||||
|
||||
/datum/computer/file/terminal_program/email
|
||||
name = "ViewPoint"
|
||||
size = 4
|
||||
|
||||
var/tmp/obj/item/peripheral/network/netCard = null
|
||||
var/tmp/server_netid = null
|
||||
var/tmp/potential_server_netid = null
|
||||
var/tmp/connected = 0
|
||||
var/tmp/menu = MENU_MAIN
|
||||
var/tmp/list/mail_index = null
|
||||
var/tmp/list/mail_temp = null
|
||||
var/tmp/list/header_temp = null
|
||||
var/tmp/header_text = null
|
||||
var/tmp/setting_input = 0
|
||||
var/tmp/mail_mode = MAIL_MODE_VIEW
|
||||
var/tmp/edit_mode = EDIT_MODE_TARGET
|
||||
var/tmp/user_address = null
|
||||
|
||||
var/tmp/edit_mail_address = null
|
||||
var/tmp/edit_mail_subject = null
|
||||
var/tmp/edit_mail_group = null
|
||||
|
||||
var/max_lines = 16
|
||||
var/signature = null
|
||||
|
||||
var/setup_acc_filepath = "/logs/sysusr"//Where do we look for login data?
|
||||
var/defaultDomain = "NT13"
|
||||
|
||||
initialize()
|
||||
src.netCard = null
|
||||
src.menu = 0
|
||||
var/introdat = "ViewPoint Email Client V1.5<br>Copyright 2051 Thinktronic Systems, LTD.<br>"
|
||||
|
||||
src.netCard = find_peripheral("NET_ADAPTER")
|
||||
if (!src.netCard || !istype(src.netCard))
|
||||
src.netCard = null
|
||||
src.print_text("<b> Error:</b>No network card detected. Quitting...")
|
||||
|
||||
src.server_netid = null
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
|
||||
else
|
||||
introdat += mainmenu_text()
|
||||
|
||||
src.master.temp = null
|
||||
src.print_text(introdat)
|
||||
|
||||
return
|
||||
|
||||
input_text(text)
|
||||
if(..())
|
||||
return
|
||||
|
||||
var/list/command_list = parse_string(text)
|
||||
var/command = command_list[1]
|
||||
command_list -= command_list[1]
|
||||
|
||||
switch(menu)
|
||||
if (MENU_MAIN)
|
||||
switch (command)
|
||||
if ("0")
|
||||
src.print_text("Quitting...")
|
||||
if (connected)
|
||||
connected = 0
|
||||
disconnect_server()
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
if ("1") //(dis)connect
|
||||
if (connected)
|
||||
disconnect_server()
|
||||
src.connected = 0
|
||||
src.master.temp = null
|
||||
src.print_text(mainmenu_text(1))
|
||||
return
|
||||
else
|
||||
if (server_netid)
|
||||
//Attempt to connect to server
|
||||
src.menu = -1
|
||||
connect_server(server_netid, 1)
|
||||
if (connected)
|
||||
src.print_text("Connection established to \[[server_netid]]!<br>[mainmenu_text(0)]")
|
||||
src.menu = MENU_MAIN
|
||||
return
|
||||
|
||||
src.menu = MENU_MAIN
|
||||
src.print_text("Connection failed.")
|
||||
return
|
||||
else
|
||||
//Attempt to autodetect server & connect
|
||||
src.menu = -1
|
||||
src.print_text("Searching for mailserver...")
|
||||
if (ping_server(1))
|
||||
src.print_text("Unable to detect mailserver!")
|
||||
src.menu = MENU_MAIN
|
||||
return
|
||||
|
||||
src.print_text("Mailserver detected at \[[potential_server_netid]]<br>Connecting...")
|
||||
connect_server(potential_server_netid, 1)
|
||||
|
||||
src.menu = MENU_MAIN
|
||||
if (connected)
|
||||
src.print_text("Connection established to \[[server_netid]]!<br>[mainmenu_text(0)]")
|
||||
return
|
||||
|
||||
src.print_text("Connection failed.")
|
||||
return
|
||||
if ("2") //Settings
|
||||
//todo: List all settings
|
||||
src.master.temp = null
|
||||
var/menuText = "Options:<br><br> (1) Set Mailserver Address<br> (2) Set Max Printed Lines Before Prompt \[[max_lines]]<br> (3) Set signature<br> (0) Go Back."
|
||||
src.print_text(menuText)
|
||||
src.menu = MENU_SETTINGS
|
||||
return
|
||||
if ("3") //Receive mail
|
||||
message_server("command=mail&args=index")
|
||||
return
|
||||
|
||||
if ("4") //View mailbox
|
||||
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.master.temp = null
|
||||
src.print_text(mailbox_text())
|
||||
return
|
||||
|
||||
if ("5") //Compose new email
|
||||
|
||||
src.menu = MENU_EDIT
|
||||
src.edit_mode = EDIT_MODE_TARGET
|
||||
src.print_text("Please enter target address. \"AddressName--MailGroup\" or 0 to return.")
|
||||
|
||||
return
|
||||
|
||||
if (MENU_SETTINGS)
|
||||
switch (command)
|
||||
if ("1")
|
||||
if (src.connected)
|
||||
src.print_text("This cannot be changed while connected.")
|
||||
return
|
||||
|
||||
src.print_text("Current value: [server_netid ? server_netid : "AUTO"]<br>Please enter new value.")
|
||||
src.setting_input = 1
|
||||
src.menu = MENU_SETTING_INPUT
|
||||
|
||||
if ("2")
|
||||
src.print_text("Please enter new value (1-64).")
|
||||
src.setting_input = 2
|
||||
src.menu = MENU_SETTING_INPUT
|
||||
|
||||
if ("3")
|
||||
src.print_text("Current value: [signature ? signature : "OFF"]<br>Please enter new value, *NONE to clear, or 0 to return.")
|
||||
src.setting_input = 3
|
||||
src.menu = MENU_SETTING_INPUT
|
||||
|
||||
if ("0")
|
||||
src.menu = MENU_MAIN
|
||||
src.master.temp = null
|
||||
src.print_text(mainmenu_text())
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
if (MENU_SETTING_INPUT)
|
||||
switch (setting_input)
|
||||
if (1)
|
||||
var/new_netid = ckey(command)
|
||||
if (new_netid == "auto")
|
||||
src.print_text("Automatic mailserver location enabled.")
|
||||
server_netid = null
|
||||
else if (!new_netid || !ishex(new_netid) || length(new_netid) != 8)
|
||||
src.print_text("Invalid value.")
|
||||
else
|
||||
server_netid = new_netid
|
||||
src.print_text("New mailserver address set.")
|
||||
|
||||
if (2)
|
||||
var/new_max_lines = round(text2num(command))
|
||||
if (new_max_lines < 1 || new_max_lines > 64)
|
||||
src.print_text("Invalid value.")
|
||||
else
|
||||
max_lines = new_max_lines
|
||||
src.print_text("New line maximum set.")
|
||||
|
||||
if (3)
|
||||
var/new_signature = copytext( strip_html(text), 1, 129 )
|
||||
if (new_signature != "0")
|
||||
if (ckey(new_signature) && lowertext(new_signature) != "*none")
|
||||
src.signature = new_signature
|
||||
|
||||
else
|
||||
src.signature = null
|
||||
|
||||
src.print_text("New signature set.")
|
||||
|
||||
src.menu = MENU_SETTINGS
|
||||
src.setting_input = 0
|
||||
return
|
||||
|
||||
if (MENU_MAIL_INDEX)
|
||||
switch (lowertext(command))
|
||||
if ("v")
|
||||
src.mail_mode = MAIL_MODE_VIEW
|
||||
src.print_text("Mode set to: View Mail Entry.")
|
||||
if ("d")
|
||||
src.mail_mode = MAIL_MODE_DELETE
|
||||
src.print_text("Mode set to: Delete Mail Entry.")
|
||||
if ("f")
|
||||
src.mail_mode = MAIL_MODE_FORWARD
|
||||
src.print_text("Mode set to: Forward Mail Entry.")
|
||||
if ("r")
|
||||
src.mail_mode = MAIL_MODE_REPLY
|
||||
src.print_text("Mode set to: Reply to Mail Entry.")
|
||||
|
||||
else
|
||||
var/index_number = round( max( text2num(command), 0) )
|
||||
if (index_number == 0)
|
||||
src.menu = MENU_MAIN
|
||||
src.master.temp = null
|
||||
src.print_text(mainmenu_text())
|
||||
return
|
||||
|
||||
if (!istype(mail_index) || index_number > mail_index.len)
|
||||
src.print_text("Invalid mail entry.")
|
||||
return
|
||||
|
||||
if (!connected)
|
||||
src.print_text("Not connected to mailserver.")
|
||||
return
|
||||
|
||||
switch (mail_mode)
|
||||
if (MAIL_MODE_VIEW)
|
||||
//steps: request mail from server -> load mail -> display in sections
|
||||
src.mail_temp = null
|
||||
src.header_temp = null
|
||||
message_server("command=mail&args=get [index_number]") //Request mail
|
||||
src.menu = -1
|
||||
sleep(8)
|
||||
if (istype(mail_temp))
|
||||
var/dat = ""
|
||||
var/end_max = max( min(mail_temp.len, max_lines) - 8, 0)
|
||||
for (var/i = 1, i <= end_max, i++)
|
||||
dat += "<br>[mail_temp[i]]"
|
||||
|
||||
src.master.temp = null
|
||||
if (end_max < mail_temp.len)
|
||||
print_text("[header_text][dat]<br> ([mail_temp.len-end_max]) lines remaining. Any key to show more, 0 to return.")
|
||||
src.menu = MENU_MAIL_VIEW
|
||||
src.mail_temp.Cut(1,end_max+1)
|
||||
return
|
||||
|
||||
print_text("[header_text][dat]<br>|---------| Press 0 to Return |---------|")
|
||||
src.menu = MENU_WAIT
|
||||
return
|
||||
|
||||
src.print_text("Error retrieving mail.")
|
||||
sleep(10)
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.print_text(mainmenu_text())
|
||||
return
|
||||
if (MAIL_MODE_DELETE)
|
||||
src.menu = -1
|
||||
message_server("command=mail&args=delete [index_number]")
|
||||
|
||||
src.mail_index = null
|
||||
message_server("command=mail&args=index")
|
||||
sleep(8)
|
||||
if (istype(src.mail_index))
|
||||
src.master.temp = null
|
||||
src.print_text(mailbox_text())
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
return
|
||||
|
||||
src.print_text("Unable to refresh mailbox.")
|
||||
sleep(10)
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.print_text(mainmenu_text())
|
||||
return
|
||||
if (MAIL_MODE_FORWARD)
|
||||
//steps: request mail from server -> load mail -> request new target -> send to new target
|
||||
src.mail_temp = null
|
||||
message_server("command=mail&args=get [index_number]") //Request mail
|
||||
src.menu = -1
|
||||
sleep(8)
|
||||
if (istype(mail_temp))
|
||||
src.print_text("Please enter new target address. \"AddressName--MailGroup\"")
|
||||
src.menu = MENU_EDIT
|
||||
src.edit_mode = EDIT_MODE_FWD_TARGET
|
||||
return
|
||||
|
||||
src.print_text("Error retrieving mail.")
|
||||
sleep(10)
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.print_text(mainmenu_text())
|
||||
return
|
||||
if (MAIL_MODE_REPLY)
|
||||
src.mail_temp = null
|
||||
message_server("command=mail&args=get [index_number]")
|
||||
src.menu = -1
|
||||
sleep(8)
|
||||
if (istype(mail_temp))
|
||||
src.print_text("Please enter body text, \"!send\" to send,<br>\"!del\" to remove last line or JUST 0 to return.")
|
||||
if (src.mail_temp)
|
||||
src.mail_temp.len = 0
|
||||
src.menu = MENU_EDIT
|
||||
src.edit_mode = EDIT_MODE_REPLYBODY
|
||||
return
|
||||
|
||||
src.print_text("Error retrieving mail.")
|
||||
sleep(10)
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.print_text(mainmenu_text())
|
||||
return
|
||||
|
||||
if (MENU_MAIL_VIEW)
|
||||
if (command == "0" || (!src.mail_temp || !src.mail_temp.len))
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.master.temp = null
|
||||
src.print_text(mailbox_text())
|
||||
return
|
||||
|
||||
if (istype(mail_temp))
|
||||
var/dat = ""
|
||||
var/end_max = min(mail_temp.len, max_lines)
|
||||
for (var/i = 1, i <= end_max, i++)
|
||||
dat += "<br>[mail_temp[i]]"
|
||||
|
||||
if (end_max < mail_temp.len)
|
||||
print_text("[dat]<br> ([mail_temp.len-end_max]) lines remaining. Any key to show more, 0 to return.")
|
||||
src.mail_temp.Cut(1,end_max+1)
|
||||
return
|
||||
|
||||
print_text("[dat]<br>|---------| Press 0 to Return |---------|")
|
||||
src.menu = MENU_WAIT
|
||||
return
|
||||
|
||||
if (MENU_WAIT)
|
||||
if (command == "0")
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.master.temp = null
|
||||
src.print_text(mailbox_text())
|
||||
|
||||
return
|
||||
|
||||
if (MENU_EDIT)
|
||||
switch (edit_mode)
|
||||
if (EDIT_MODE_TARGET)
|
||||
if (command == "0")
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.master.temp = null
|
||||
src.print_text(mailbox_text())
|
||||
return
|
||||
|
||||
var/attemptAddress = copytext( ckeyEx(uppertext(text)), 1, 33)
|
||||
if (!attemptAddress)
|
||||
return
|
||||
|
||||
var/mailgroupName = null
|
||||
var/mailgroupPoint = findtext(attemptAddress, "--")
|
||||
if (mailgroupPoint)
|
||||
mailgroupName = copytext(attemptAddress, mailgroupPoint+2)
|
||||
attemptAddress = copytext(attemptAddress, 1, mailgroupPoint)
|
||||
if (!attemptAddress && ckey(mailgroupName))
|
||||
attemptAddress = "GENERIC@[defaultDomain]"
|
||||
else if (!ckey(mailgroupName) || findtext(attemptAddress, "--"))
|
||||
src.print_text("Invalid mailgroup specification. Try \"Address--mailGroupName\"")
|
||||
return
|
||||
|
||||
if (!findtext(attemptAddress, "@"))
|
||||
attemptAddress += "@[defaultDomain]"
|
||||
|
||||
src.edit_mode = EDIT_MODE_SUBJ
|
||||
src.edit_mail_address = attemptAddress
|
||||
src.edit_mail_group = mailgroupName
|
||||
src.print_text("Target Address set to \"[edit_mail_address]\"[mailgroupName ? "<br>Target Mailgroup set to \"[mailgroupName]\"" : null]<br>Please enter subject line, or 0 to go back to address entry.")
|
||||
return
|
||||
|
||||
if (EDIT_MODE_SUBJ)
|
||||
if (command == "0")
|
||||
src.edit_mode = EDIT_MODE_TARGET
|
||||
src.print_text("Please enter new target address. \"AddressName--MailGroup\" or 0 to return.")
|
||||
return
|
||||
|
||||
var/attemptSubj = copytext( strip_html(text), 1, 33 )
|
||||
if (!ckey(attemptSubj))
|
||||
return
|
||||
|
||||
src.edit_mode = EDIT_MODE_BODY
|
||||
if (src.mail_temp)
|
||||
src.mail_temp.len = 0
|
||||
else
|
||||
src.mail_temp = list()
|
||||
|
||||
src.edit_mail_subject = attemptSubj
|
||||
src.print_text("Subject Line set to \"[edit_mail_subject]\"<br>Please enter body text, \"!send\" to send,<br>\"!del\" to remove last line or JUST 0 to go back to subject entry.")
|
||||
return
|
||||
|
||||
if (EDIT_MODE_BODY, EDIT_MODE_REPLYBODY)
|
||||
if (command == "0")
|
||||
if (edit_mode == EDIT_MODE_BODY)
|
||||
src.edit_mode = EDIT_MODE_SUBJ
|
||||
src.print_text("Please enter subject line, or 0 to go back.")
|
||||
|
||||
else
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.master.temp = null
|
||||
src.print_text(mailbox_text())
|
||||
|
||||
return
|
||||
|
||||
else if (copytext(command,1,2) == "!")
|
||||
switch (lowertext(command))
|
||||
if ("!send")
|
||||
|
||||
src.menu = -1
|
||||
if (edit_mode == EDIT_MODE_REPLYBODY && header_temp)
|
||||
header_temp["subj"] = copytext("RE: [header_temp["subj"]]", 1, 33)
|
||||
src.edit_mail_group = "*NONE"
|
||||
else
|
||||
header_temp = list()
|
||||
header_temp["mailnet"] = "PUBLIC_NT"
|
||||
header_temp["priority"] = "STANDARD"
|
||||
header_temp["subj"] = src.edit_mail_subject
|
||||
header_temp["target"] =src.edit_mail_address
|
||||
header_temp["group"] = src.edit_mail_group ? uppertext(src.edit_mail_group) : "*NONE"
|
||||
header_temp["sender"] = user_address ? user_address : "???"
|
||||
mail_temp.Insert(1, list2params(header_temp))
|
||||
|
||||
if (src.signature)
|
||||
mail_temp += "-[src.signature]"
|
||||
|
||||
var/datum/computer/file/record/outgoingMail = new
|
||||
outgoingMail.name = "mail"
|
||||
outgoingMail.fields = mail_temp
|
||||
src.mail_temp = null
|
||||
header_temp = null
|
||||
message_server("command=mail&args=send", outgoingMail)
|
||||
src.print_text("Sending message...")
|
||||
|
||||
src.mail_index = null
|
||||
message_server("command=mail&args=index")
|
||||
sleep(8)
|
||||
if (istype(src.mail_index))
|
||||
src.master.temp = null
|
||||
src.print_text(mailbox_text())
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
return
|
||||
|
||||
src.print_text("Unable to refresh mailbox.")
|
||||
sleep(10)
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.print_text(mainmenu_text())
|
||||
return
|
||||
|
||||
if ("!del")
|
||||
if (!istype(src.mail_temp) || !src.mail_temp.len)
|
||||
return
|
||||
|
||||
src.mail_temp.len--
|
||||
src.print_text("Line removed.")
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
if (!src.mail_temp)
|
||||
src.mail_temp = list()
|
||||
|
||||
var/toAdd = copytext( strip_html(text), 1, MAX_MESSAGE_LEN)
|
||||
if (!ckeyEx(toAdd) || src.mail_temp.len >= 99)
|
||||
return
|
||||
|
||||
src.mail_temp += toAdd
|
||||
src.print_text("\[[add_zero("[src.mail_temp.len]", 2)]] [toAdd]")
|
||||
|
||||
return
|
||||
|
||||
if (EDIT_MODE_FWD_TARGET)
|
||||
if (command == "0" || !istype(mail_temp) || !mail_temp.len)
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.master.temp = null
|
||||
src.print_text(mailbox_text())
|
||||
return
|
||||
|
||||
var/attemptAddress = copytext( ckeyEx(uppertext(text)), 1, 33)
|
||||
if (!attemptAddress)
|
||||
return
|
||||
|
||||
var/mailgroupName = null
|
||||
var/mailgroupPoint = findtext(attemptAddress, "--")
|
||||
if (mailgroupPoint)
|
||||
mailgroupName = copytext(attemptAddress, mailgroupPoint+2)
|
||||
attemptAddress = copytext(attemptAddress, 1, mailgroupPoint)
|
||||
if (!attemptAddress && ckey(mailgroupName))
|
||||
attemptAddress = "GENERIC@[defaultDomain]"
|
||||
else if (!ckey(mailgroupName) || findtext(attemptAddress, "--"))
|
||||
src.print_text("Invalid mailgroup specification. Try \"address--mailGroupName\"")
|
||||
return
|
||||
|
||||
if (!findtext(attemptAddress, "@"))
|
||||
attemptAddress += "@[defaultDomain]"
|
||||
|
||||
if (header_temp && header_temp.len) //email from grandma, FWD: RE: FWD: FWD: Space-President Jordan WQIT'XFWQ' Wilkins actually syndicate martian infiltrator!!
|
||||
src.menu = -1
|
||||
header_temp["subj"] = "FWD: [header_temp["subj"]]"
|
||||
header_temp["target"] = attemptAddress
|
||||
header_temp["group"] = mailgroupName ? uppertext(mailgroupName) : "*NONE"
|
||||
header_temp["sender"] = user_address ? user_address : "???"
|
||||
mail_temp.Insert(1, list2params(header_temp))
|
||||
|
||||
var/datum/computer/file/record/outgoingMail = new
|
||||
outgoingMail.name = "mail"
|
||||
outgoingMail.fields = mail_temp
|
||||
src.mail_temp = null
|
||||
header_temp = null
|
||||
message_server("command=mail&args=send", outgoingMail)
|
||||
src.print_text("Forwarding message...")
|
||||
|
||||
src.mail_index = null
|
||||
message_server("command=mail&args=index")
|
||||
sleep(8)
|
||||
if (istype(src.mail_index))
|
||||
src.master.temp = null
|
||||
src.print_text(mailbox_text())
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
return
|
||||
|
||||
src.print_text("Unable to refresh mailbox.")
|
||||
sleep(10)
|
||||
src.menu = MENU_MAIL_INDEX
|
||||
src.print_text(mainmenu_text())
|
||||
return
|
||||
|
||||
receive_command(obj/source, command, datum/signal/signal)
|
||||
if ((..()) || (!signal))
|
||||
return
|
||||
|
||||
if (!connected)
|
||||
if (signal.data["command"] == "ping_reply" && !potential_server_netid)
|
||||
|
||||
if (signal.data["device"] == "PNET_MAINFRAME" && signal.data["sender"] && ishex(signal.data["sender"]))
|
||||
potential_server_netid = signal.data["sender"]
|
||||
return
|
||||
|
||||
else if (signal.data["command"] == "term_connect")
|
||||
server_netid = ckey(signal.data["sender"])
|
||||
connected = 1
|
||||
potential_server_netid = null
|
||||
if(signal.data["data"] != "noreply")
|
||||
var/datum/signal/termsignal = get_free_signal()
|
||||
|
||||
termsignal.data["address_1"] = signal.data["sender"]
|
||||
termsignal.data["command"] = "term_connect"
|
||||
termsignal.data["device"] = "SRV_TERMINAL"
|
||||
termsignal.data["data"] = "noreply"
|
||||
|
||||
src.peripheral_command("transmit", termsignal, "\ref[netCard]")
|
||||
|
||||
return
|
||||
else
|
||||
if (signal.data["sender"] != server_netid)
|
||||
return
|
||||
|
||||
if (!server_netid)
|
||||
connected = 0
|
||||
return
|
||||
|
||||
switch(lowertext(signal.data["command"]))
|
||||
if ("term_message")
|
||||
var/list/data = params2list(signal.data["data"])
|
||||
if(!data || !data["command"])
|
||||
return
|
||||
|
||||
switch (lowertext(data["command"]))
|
||||
if ("mail_index")
|
||||
src.mail_index = null
|
||||
return
|
||||
//todo
|
||||
return
|
||||
|
||||
if ("term_file")
|
||||
var/list/data = params2list(signal.data["data"])
|
||||
if(!data || !data["command"])
|
||||
return
|
||||
|
||||
switch (lowertext(data["command"]))
|
||||
if ("mail_index")
|
||||
var/datum/computer/file/record/indexRecord = signal.data_file
|
||||
if (!istype(indexRecord))
|
||||
return
|
||||
|
||||
src.mail_index = indexRecord.fields.Copy()
|
||||
|
||||
if ("mail_entry")
|
||||
var/datum/computer/file/record/entryRecord = signal.data_file
|
||||
if (!istype(entryRecord))
|
||||
return
|
||||
|
||||
if (src.mail_temp)
|
||||
src.mail_temp = null
|
||||
|
||||
var/list/headerList = params2list(entryRecord.fields[1])
|
||||
if (!headerList || !headerList.len)
|
||||
return
|
||||
|
||||
src.header_temp = headerList
|
||||
entryRecord.fields.Cut(1,2)
|
||||
src.mail_temp = entryRecord.fields.Copy()
|
||||
if (!mail_temp)
|
||||
mail_temp = list("--No Message Body--")
|
||||
|
||||
header_text = {"-----------------|HEAD|-----------------<br>
|
||||
MAILNET: [ckeyEx(headerList["mailnet"]) ? copytext(uppertext(ckeyEx(headerList["mailnet"])), 1, 33) : "???"]<br>
|
||||
WORKGROUP: [ckeyEx(headerList["group"]) ? copytext(uppertext(headerList["group"]), 1, 33) : "???"]<br>
|
||||
FROM: [ckeyEx(headerList["sender"]) ? copytext(uppertext(headerList["sender"]), 1, 33) : "???"]<br>
|
||||
TO: [ckeyEx(headerList["target"]) ? copytext(uppertext(headerList["target"]), 1, 33) : "???"]<br>
|
||||
PRIORITY: [ckeyEx(headerList["priority"]) ? copytext(uppertext(ckeyEx(headerList["priority"])), 1, 9) : "???"]<br>
|
||||
SUBJECT: [ckeyEx(headerList["subj"]) ? copytext(uppertext(headerList["subj"]), 1, 33) : "???"]<br>
|
||||
----------------------------------------"}
|
||||
|
||||
return
|
||||
|
||||
if ("term_disconnect")
|
||||
src.connected = 0
|
||||
src.user_address = null
|
||||
src.print_text("Connection closed by mailserver.")
|
||||
|
||||
if("term_ping")
|
||||
if(signal.data["data"] == "reply")
|
||||
var/datum/signal/termsignal = get_free_signal()
|
||||
|
||||
termsignal.data["address_1"] = signal.data["sender"]
|
||||
termsignal.data["command"] = "term_ping"
|
||||
|
||||
src.peripheral_command("transmit", termsignal, "\ref[netCard]")
|
||||
|
||||
|
||||
return
|
||||
|
||||
proc
|
||||
connect_server(var/attempted_netid, delayCaller=0)
|
||||
if (connected || !netCard)
|
||||
return 1
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
|
||||
signal.data["address_1"] = attempted_netid
|
||||
signal.data["command"] = "term_connect"
|
||||
signal.data["device"] = "SRV_TERMINAL"
|
||||
var/datum/computer/file/user_data/user_data = get_user_data()
|
||||
var/datum/computer/file/record/udat = null
|
||||
if (istype(user_data))
|
||||
udat = new
|
||||
|
||||
var/userid = format_username(user_data.registered)
|
||||
|
||||
udat.fields["userid"] = userid
|
||||
src.user_address = "[userid]@[defaultDomain]"
|
||||
//udat.fields["assignment"] = user_data.assignment
|
||||
udat.fields["access"] = list2params(user_data.access)
|
||||
if (!udat.fields["access"] || !udat.fields["userid"])
|
||||
//qdel(udat)
|
||||
udat.dispose()
|
||||
return 1
|
||||
|
||||
udat.fields["service"] = "mail"
|
||||
|
||||
if (udat)
|
||||
signal.data_file = udat
|
||||
|
||||
src.peripheral_command("transmit", signal, "\ref[netCard]")
|
||||
if (delayCaller)
|
||||
sleep(8)
|
||||
return 0
|
||||
|
||||
return 0
|
||||
|
||||
disconnect_server()
|
||||
if (!server_netid || !netCard)
|
||||
return 1
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
|
||||
signal.data["address_1"] = server_netid
|
||||
signal.data["command"] = "term_disconnect"
|
||||
|
||||
src.peripheral_command("transmit", signal, "\ref[netCard]")
|
||||
|
||||
return 0
|
||||
|
||||
message_server(var/message, var/datum/computer/file/toSend)
|
||||
if (!connected || !server_netid || !netCard || !message)
|
||||
return 1
|
||||
|
||||
var/datum/signal/termsignal = get_free_signal()
|
||||
|
||||
termsignal.data["address_1"] = server_netid
|
||||
termsignal.data["data"] = message
|
||||
termsignal.data["command"] = "term_message"
|
||||
if (toSend)
|
||||
termsignal.data_file = toSend
|
||||
|
||||
src.peripheral_command("transmit", termsignal, "\ref[netCard]")
|
||||
return 0
|
||||
|
||||
ping_server(delayCaller=0)
|
||||
if (connected || !netCard)
|
||||
return 1
|
||||
|
||||
potential_server_netid = null
|
||||
src.peripheral_command("ping", null, "\ref[netCard]")
|
||||
|
||||
if (delayCaller)
|
||||
sleep(8)
|
||||
return (potential_server_netid == null)
|
||||
|
||||
return 0
|
||||
|
||||
get_user_data()
|
||||
var/datum/computer/folder/accdir = src.holder.root
|
||||
if(src.master.host_program) //Check where the OS is, preferably.
|
||||
accdir = src.master.host_program.holder.root
|
||||
|
||||
var/datum/computer/file/user_data/target = parse_file_directory(setup_acc_filepath, accdir)
|
||||
if(target && istype(target))
|
||||
return target
|
||||
|
||||
return null
|
||||
|
||||
mainmenu_text(display_server=1)
|
||||
. = null
|
||||
if (display_server)
|
||||
. = "<b>Mail Server</b>: "
|
||||
if (server_netid)
|
||||
. += "\[[server_netid]] ([connected ? null : "Not "]Connected)<br>Your address is: \[[user_address ? user_address : "???"]]<br><br>"
|
||||
else
|
||||
. += "None Set<br><br>"
|
||||
|
||||
. += "Please Select an Option:<br> (1) [connected ? "Disconnect from" : "Connect to"] Mailserver.<br> (2) Mailserver Settings."
|
||||
if (connected)
|
||||
. += "<br> (3) Receive Mail<br> (4) View Mailbox.<br> (5) Compose Mail."
|
||||
|
||||
. += "<br> (0) Quit"
|
||||
|
||||
|
||||
mailbox_text()
|
||||
. = "Message List:"
|
||||
if (istype(mail_index) && mail_index.len)
|
||||
var/leadingZeroCount = length("[mail_index.len]")
|
||||
for (var/i = 1, i <= mail_index.len, i++)
|
||||
var/iTitle = mail_index[i]
|
||||
if (length(iTitle) > MAX_MAIL_TITLE_LEN)
|
||||
iTitle = "[copytext(iTitle, 1,MAX_MAIL_TITLE_LEN+1)]..."
|
||||
|
||||
. += "<br> \[[add_zero("[i]", leadingZeroCount)]] [iTitle]"
|
||||
else
|
||||
. += "<br> No Messages."
|
||||
|
||||
. += "<br><br>Modes: (V) View (R) Reply (F) Forward (D) Delete<br>Current Mode: ([src.mail_mode])<br>Enter mail number or 0 to return."
|
||||
|
||||
|
||||
#undef MENU_MAIN
|
||||
#undef MENU_SETTINGS
|
||||
#undef MENU_SETTING_INPUT
|
||||
#undef MENU_MAIL_INDEX
|
||||
#undef MENU_MAIL_SELECT
|
||||
#undef MENU_MAIL_VIEW
|
||||
#undef MENU_WAIT
|
||||
#undef MENU_EDIT
|
||||
|
||||
#undef MAIL_MODE_VIEW
|
||||
#undef MAIL_MODE_DELETE
|
||||
#undef MAIL_MODE_FORWARD
|
||||
#undef MAIL_MODE_REPLY
|
||||
|
||||
#undef EDIT_MODE_TARGET
|
||||
#undef EDIT_MODE_SUBJ
|
||||
#undef EDIT_MODE_BODY
|
||||
#undef EDIT_MODE_REPLYBODY
|
||||
#undef EDIT_MODE_FWD_TARGET
|
||||
|
||||
#undef MAX_MAIL_TITLE_LEN
|
||||
@@ -0,0 +1,291 @@
|
||||
//Singularity engine control program
|
||||
#ifdef SINGULARITY_TIME
|
||||
/datum/computer/file/terminal_program/engine_control
|
||||
name = "EngineMaster"
|
||||
size = 10
|
||||
req_access = list(access_engineering_engine)
|
||||
var/tmp/authenticated = null //Are we currently logged in?
|
||||
var/datum/computer/file/user_data/account = null
|
||||
var/log_string = null
|
||||
var/obj/item/peripheral/network/powernet_card/netcard = null
|
||||
var/obj/item/peripheral/network/radio/radiocard = null
|
||||
var/tmp/task = null //What are we doing at the moment?
|
||||
var/tmp/startup_line = 1
|
||||
var/tmp/starting_up = 0 //Are we currently starting up?
|
||||
var/list/emitter_ids = list() //Net ids of located emitters.
|
||||
var/list/fieldgen_ids = list() //Net ids of located field generators.
|
||||
var/tmp/last_event_report = 0 //When did we last report an event?
|
||||
|
||||
var/setup_acc_filepath = "/logs/sysusr"//Where do we look for login data?
|
||||
var/setup_logdump_name = "englog"
|
||||
var/setup_mail_freq = 1149 //Which freq do we report to?
|
||||
var/setup_mailgroup = "engineer" //The PDA mailgroup used when alerting engineer pdas.
|
||||
|
||||
|
||||
initialize()
|
||||
|
||||
src.authenticated = null
|
||||
src.task = null
|
||||
src.master.temp = null
|
||||
src.startup_line = 1
|
||||
|
||||
if(!src.find_access_file()) //Find the account information, as it's essentially a ~digital ID card~
|
||||
src.print_text("<b>Error:</b> Cannot locate user file. Quitting...")
|
||||
src.master.unload_program(src) //Oh no, couldn't find the file.
|
||||
return
|
||||
if(!src.check_access(src.account.access))
|
||||
src.print_text("User [src.account.registered] does not have needed access credentials.<br>Quitting...")
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
|
||||
src.netcard = locate() in src.master.peripherals
|
||||
if(!src.netcard || !istype(src.netcard))
|
||||
src.print_text("<b>Error:</b> No network card detected.<br>Quitting...")
|
||||
src.log_string += "<br>Startup Failure: No network card."
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
|
||||
src.radiocard = locate() in src.master.peripherals
|
||||
if(!radiocard || !istype(src.radiocard))
|
||||
src.radiocard = null
|
||||
src.print_text("<b>Warning:</b> No radio module detected.")
|
||||
src.log_string += "<br>Startup Error: No radio."
|
||||
|
||||
src.authenticated = src.account.registered
|
||||
src.log_string += "<br><b>LOGIN:</b> [src.authenticated]"
|
||||
|
||||
src.ping_devices()
|
||||
|
||||
var/intro_text = {"<br>EngineMaster
|
||||
<br>Automated Engine Control System
|
||||
<br><b>Commands:</b>
|
||||
<br>(Startup) to activate engine systems.
|
||||
<br>(Abort) to abort startup procedure.
|
||||
<br>(Rescan) to rescan for engine devices.
|
||||
<br>(Clear) to clear the screen.
|
||||
<br>(Quit) to exit."}
|
||||
src.print_text(intro_text)
|
||||
|
||||
return
|
||||
|
||||
input_text(text)
|
||||
if(..())
|
||||
return
|
||||
|
||||
var/list/command_list = parse_string(text)
|
||||
var/command = command_list[1]
|
||||
command_list -= command_list[1]
|
||||
|
||||
src.print_text(strip_html(text))
|
||||
|
||||
switch(lowertext(command))
|
||||
|
||||
if("startup")
|
||||
//We're already starting, jeez give it some time
|
||||
if(src.starting_up)
|
||||
src.print_text("Startup already in progress.")
|
||||
src.master.add_fingerprint(usr)
|
||||
return
|
||||
|
||||
if(!emitter_ids || emitter_ids.len <= 0)
|
||||
src.print_text("<b>Error:</b> Insufficient emitters detected.")
|
||||
src.master.add_fingerprint(usr)
|
||||
return
|
||||
|
||||
if(!fieldgen_ids || fieldgen_ids.len < 4)
|
||||
src.print_text("<b>Error:</b> Insufficient field generators detected.")
|
||||
src.master.add_fingerprint(usr)
|
||||
return
|
||||
|
||||
src.startup_line = 1
|
||||
src.starting_up = 1
|
||||
src.task = "startup-emit"
|
||||
src.log_string += "<br>Startup initiated."
|
||||
src.report_event("Engine starting up...")
|
||||
src.print_text("Startup procedure initiated.")
|
||||
|
||||
if("abort")
|
||||
if(!src.starting_up)
|
||||
src.print_text("No startup procedure in progress.")
|
||||
src.master.add_fingerprint(usr)
|
||||
return
|
||||
|
||||
src.startup_line = 1
|
||||
src.task = null
|
||||
src.starting_up = 0
|
||||
src.log_string += "<br>Startup aborted."
|
||||
src.print_text("Startup procedure aborted.")
|
||||
|
||||
if("rescan")
|
||||
if((src.task && src.task != "scan") || src.starting_up)
|
||||
src.print_text("Unable to scan, system is busy.")
|
||||
return
|
||||
|
||||
src.ping_devices()
|
||||
|
||||
if("logdump")
|
||||
if(!src.log_string) //Something is wrong.
|
||||
src.print_text("<b>Error:</b> No log data to dump.")
|
||||
return
|
||||
|
||||
if(src.holder.read_only)
|
||||
src.print_text("<b>Error:</b> Destination drive is read-only.")
|
||||
return
|
||||
|
||||
var/datum/computer/file/text/logdump = get_file_name(setup_logdump_name, src.holding_folder)
|
||||
if(logdump && !istype(logdump) || get_folder_name(setup_logdump_name, src.holding_folder))
|
||||
src.print_text("<b>Error:</b> Name in use.")
|
||||
return
|
||||
|
||||
if(logdump && istype(logdump))
|
||||
logdump.data = src.log_string
|
||||
else
|
||||
logdump = new /datum/computer/file/text
|
||||
logdump.name = setup_logdump_name
|
||||
logdump.data = src.log_string
|
||||
if(!src.holding_folder.add_file(logdump))
|
||||
//qdel(logdump)
|
||||
logdump.dispose()
|
||||
src.print_text("<b>Error:</b> Cannot save to disk.")
|
||||
return
|
||||
|
||||
src.print_text("Log dumped to holding directory.")
|
||||
|
||||
if("clear")
|
||||
src.master.temp = null
|
||||
src.master.temp_add = "Workspace cleared.<br>"
|
||||
|
||||
if("quit")
|
||||
src.log_string += "<br><b>LOGOUT:</b> [src.authenticated]"
|
||||
src.print_text("Now quitting...")
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
|
||||
else
|
||||
src.print_text("Unknown command.")
|
||||
|
||||
src.master.add_fingerprint(usr)
|
||||
src.master.updateUsrDialog()
|
||||
return
|
||||
|
||||
process()
|
||||
if(..() || !src.task)
|
||||
return
|
||||
|
||||
switch(src.task)
|
||||
if("startup-emit")
|
||||
if(startup_line > src.emitter_ids.len)
|
||||
src.task = "startup-field"
|
||||
src.startup_line = 1
|
||||
return
|
||||
|
||||
post_status(src.emitter_ids[src.startup_line], "command", "activate")
|
||||
src.startup_line++
|
||||
|
||||
if("startup-field")
|
||||
if(startup_line > src.fieldgen_ids.len)
|
||||
src.task = null
|
||||
src.startup_line = 1
|
||||
src.starting_up = 0
|
||||
src.print_text("Startup procedure complete.")
|
||||
return
|
||||
|
||||
post_status(src.fieldgen_ids[src.startup_line], "command", "activate")
|
||||
src.startup_line++
|
||||
|
||||
receive_command(obj/source, command, datum/signal/signal)
|
||||
if((..()) || !signal)
|
||||
return
|
||||
|
||||
//Time to populate our lists of components.
|
||||
if(signal.data["command"] == "ping_reply" && (src.task == "scan"))
|
||||
if(!signal.data["netid"])
|
||||
return
|
||||
|
||||
switch(signal.data["device"])
|
||||
if("PNET_ENG_EMITR") //Oh hey a new emitter.
|
||||
if(!(signal.data["netid"] in src.emitter_ids))
|
||||
src.emitter_ids += signal.data["netid"]
|
||||
if("PNET_ENG_FIELD")
|
||||
if(!(signal.data["netid"] in src.fieldgen_ids))
|
||||
src.fieldgen_ids += signal.data["netid"]
|
||||
else
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
proc
|
||||
ping_devices()
|
||||
if(!src.netcard)
|
||||
return
|
||||
src.task = "scan"
|
||||
src.emitter_ids = new
|
||||
src.fieldgen_ids = new
|
||||
|
||||
var/datum/signal/newsignal = get_free_signal()
|
||||
//newsignal.encryption = "\ref[src.netcard]"
|
||||
|
||||
src.log_string += "<br>Scanning for devices..."
|
||||
src.print_text("Scanning for devices...")
|
||||
src.peripheral_command("ping", newsignal, "\ref[src.netcard]")
|
||||
|
||||
return
|
||||
|
||||
post_status(var/target_id, var/key, var/value, var/key2, var/value2, var/key3, var/value3)
|
||||
if(!src.netcard)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
|
||||
//signal.encryption = "\ref[src.netcard]"
|
||||
signal.data[key] = value
|
||||
if(key2)
|
||||
signal.data[key2] = value2
|
||||
if(key3)
|
||||
signal.data[key3] = value3
|
||||
|
||||
signal.data["address_1"] = target_id
|
||||
src.peripheral_command("transmit", signal, "\ref[src.netcard]")
|
||||
|
||||
report_event(var/event_string)
|
||||
if(!event_string || !src.radiocard)
|
||||
return
|
||||
|
||||
//Unlikely that this would be a problem but OH WELL
|
||||
if(last_event_report && world.time < (last_event_report + 10))
|
||||
return
|
||||
|
||||
//Set card frequency if it isn't already.
|
||||
if(src.radiocard.frequency != src.setup_mail_freq && !src.radiocard.setup_freq_locked)
|
||||
var/datum/signal/freqsignal = get_free_signal()
|
||||
//freqsignal.encryption = "\ref[src.radiocard]"
|
||||
peripheral_command("[src.setup_mail_freq]", freqsignal,"\ref[src.radiocard]")
|
||||
src.log_string += "<br>Adjusting frequency... \[[src.setup_mail_freq]]."
|
||||
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
//signal.encryption = "\ref[src.radiocard]"
|
||||
|
||||
//Create a PDA mass-message string.
|
||||
signal.data["address_1"] = "00000000"
|
||||
signal.data["command"] = "text_message"
|
||||
signal.data["sender_name"] = "ENGINE-MAILBOT"
|
||||
signal.data["group"] = src.setup_mailgroup //Only engineer PDAs should be informed.
|
||||
signal.data["message"] = "Notice: [event_string]"
|
||||
|
||||
src.log_string += "<br>Event notification sent."
|
||||
last_event_report = world.time
|
||||
peripheral_command("transmit", signal, "\ref[src.radiocard]")
|
||||
return
|
||||
|
||||
find_access_file() //Look for the whimsical account_data file
|
||||
var/datum/computer/folder/accdir = src.holder.root
|
||||
if(src.master.host_program) //Check where the OS is, preferably.
|
||||
accdir = src.master.host_program.holder.root
|
||||
|
||||
var/datum/computer/file/user_data/target = parse_file_directory(setup_acc_filepath, accdir)
|
||||
if(target && istype(target))
|
||||
src.account = target
|
||||
return 1
|
||||
|
||||
return 0
|
||||
#endif
|
||||
@@ -0,0 +1,213 @@
|
||||
#define HANGAR_AREATYPE "/area/hangar"
|
||||
/datum/computer/file/terminal_program/hangar_control
|
||||
name = "HangarControl"
|
||||
size = 16
|
||||
req_access = list(access_hangar)
|
||||
var/tmp/authenticated = null //Are we currently logged in?
|
||||
var/datum/computer/file/user_data/account = null
|
||||
var/tmp/reply_wait = -1 //How long do we wait for replies? -1 is not waiting.
|
||||
var/setup_acc_filepath = "/logs/sysusr"//Where do we look for login data?
|
||||
|
||||
initialize()
|
||||
|
||||
src.authenticated = null
|
||||
src.master.temp = null
|
||||
if(!src.find_access_file()) //Find the account information, as it's essentially a ~digital ID card~
|
||||
src.print_text("<b>Error:</b> Cannot locate user file. Quitting...")
|
||||
src.master.unload_program(src) //Oh no, couldn't find the file.
|
||||
return
|
||||
|
||||
if(!src.check_access(src.account.access))
|
||||
src.print_text("User [src.account.registered] does not have needed access credentials.<br>Quitting...")
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
|
||||
src.reply_wait = -1
|
||||
src.authenticated = src.account.registered
|
||||
var/intro_text = {"<br>Welcome to HangarControl!
|
||||
<br>Hangar Management System.
|
||||
<br><b>Commands:</b>
|
||||
<br>(Status) to view current status.
|
||||
<br>(ResetPass) to reset a hangar door's password.
|
||||
<br>(CloseAll) to close all hangar doors.
|
||||
<br>(Toggle) to toggle a hangar door.
|
||||
<br>(Clear) to clear the screen.
|
||||
<br>(Quit) to exit HangarControl."}
|
||||
src.print_text(intro_text)
|
||||
|
||||
input_text(text)
|
||||
if(..())
|
||||
return
|
||||
|
||||
var/list/command_list = parse_string(text)
|
||||
var/command = command_list[1]
|
||||
command_list -= command_list[1] //Remove the command we are now processing.
|
||||
|
||||
switch(lowertext(command))
|
||||
if("status")
|
||||
print_status()
|
||||
if("clear")
|
||||
src.master.temp = null
|
||||
src.master.temp_add = "Workspace cleared.<br>"
|
||||
if("closeall")
|
||||
close_all()
|
||||
if("toggle")
|
||||
var/door_name = ckey(dd_list2text(command_list, " "))
|
||||
if(!door_name)
|
||||
var/dat = "<b>Available Hangar Doors:</b><br>"
|
||||
for(var/turf/T in get_area_turfs(HANGAR_AREATYPE))
|
||||
for(var/obj/machinery/r_door_control/R in T)
|
||||
if(R.open)
|
||||
dat+="[R.name]<BR>"
|
||||
else
|
||||
dat+="[R.name]<BR>"
|
||||
src.print_text(dat)
|
||||
else
|
||||
for(var/turf/T in get_area_turfs(HANGAR_AREATYPE))
|
||||
for(var/obj/machinery/r_door_control/R in T)
|
||||
if(cmptext(door_name,R.id))
|
||||
if(R.open)
|
||||
src.print_text("Closing Door...")
|
||||
else
|
||||
src.print_text("Opening Door...")
|
||||
R.open_door()
|
||||
src.print_text("Done.<BR>")
|
||||
src.master.add_fingerprint(usr)
|
||||
src.master.updateUsrDialog()
|
||||
return
|
||||
src.print_text("Invalid Hangar Door!<BR>")
|
||||
if("resetpass")
|
||||
var/door_name = ckey(dd_list2text(command_list, " "))
|
||||
if(!door_name)
|
||||
var/dat = "<b>Available Hangar Doors:</b><br>"
|
||||
for(var/turf/T in get_area_turfs(HANGAR_AREATYPE))
|
||||
for(var/obj/machinery/r_door_control/R in T)
|
||||
if(R.open)
|
||||
dat+="[R.name]<BR>"
|
||||
else
|
||||
dat+="[R.name]<BR>"
|
||||
src.print_text(dat)
|
||||
else
|
||||
for(var/turf/T in get_area_turfs(HANGAR_AREATYPE))
|
||||
for(var/obj/machinery/r_door_control/R in T)
|
||||
if(cmptext(door_name,R.id))
|
||||
R.pass = "[R.id]-[rand(100,999)]"
|
||||
src.print_text("[R.name] New Pass: [R.pass]")
|
||||
src.master.add_fingerprint(usr)
|
||||
src.master.updateUsrDialog()
|
||||
return
|
||||
src.print_text("Invalid Hangar Door!<BR>")
|
||||
|
||||
if("help")
|
||||
var/intro_text = {"<br>Welcome to HangarControl!
|
||||
<br>Hangar Management System.
|
||||
<br><b>Commands:</b>
|
||||
<br>(Status) to view current status.
|
||||
<br>(ResetPass) to reset a hangar door's password.
|
||||
<br>(CloseAll) to close all hangar doors.
|
||||
<br>(Toggle) to toggle a hangar door.
|
||||
<br>(Clear) to clear the screen.
|
||||
<br>(Quit) to exit HangarControl."}
|
||||
src.print_text(intro_text)
|
||||
if("quit")
|
||||
src.master.temp = ""
|
||||
print_text("Now quitting...")
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
else
|
||||
print_text("Unknown command : \"[copytext(strip_html(command), 1, 16)]\"")
|
||||
|
||||
|
||||
src.master.add_fingerprint(usr)
|
||||
src.master.updateUsrDialog()
|
||||
return
|
||||
|
||||
proc
|
||||
find_access_file() //Look for the whimsical account_data file
|
||||
var/datum/computer/folder/accdir = src.holder.root
|
||||
if(src.master.host_program) //Check where the OS is, preferably.
|
||||
accdir = src.master.host_program.holder.root
|
||||
|
||||
var/datum/computer/file/user_data/target = parse_file_directory(setup_acc_filepath, accdir)
|
||||
if(target && istype(target))
|
||||
src.account = target
|
||||
return 1
|
||||
|
||||
return 0
|
||||
print_status()
|
||||
var/dat="<b>Status</b>:<BR>"
|
||||
for(var/turf/T in get_area_turfs(HANGAR_AREATYPE))
|
||||
for(var/obj/machinery/r_door_control/R in T)
|
||||
if(R.open)
|
||||
dat+="[R.name] (Open): [R.pass]<BR>"
|
||||
else
|
||||
dat+="[R.name] (Closed): [R.pass]<BR>"
|
||||
src.print_text(dat)
|
||||
close_all()
|
||||
src.print_text("Closing All Doors...")
|
||||
for(var/turf/T in get_area_turfs(HANGAR_AREATYPE))
|
||||
for(var/obj/machinery/r_door_control/R in T)
|
||||
if(R.open)
|
||||
R.open_door()
|
||||
src.print_text("Done.<BR>")
|
||||
|
||||
/datum/computer/file/terminal_program/hangar_research
|
||||
name = "HangarHelper"
|
||||
size = 16
|
||||
req_access = list(access_hangar)
|
||||
var/tmp/authenticated = null //Are we currently logged in?
|
||||
var/datum/computer/file/user_data/account = null
|
||||
var/tmp/reply_wait = -1 //How long do we wait for replies? -1 is not waiting.
|
||||
var/setup_acc_filepath = "/logs/sysusr"//Where do we look for login data?
|
||||
|
||||
initialize()
|
||||
|
||||
src.authenticated = null
|
||||
src.master.temp = null
|
||||
if(!src.find_access_file()) //Find the account information, as it's essentially a ~digital ID card~
|
||||
src.print_text("<b>Error:</b> Cannot locate user file. Quitting...")
|
||||
src.master.unload_program(src) //Oh no, couldn't find the file.
|
||||
return
|
||||
|
||||
if(!src.check_access(src.account.access))
|
||||
src.print_text("User [src.account.registered] does not have needed access credentials.<br>Quitting...")
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
|
||||
src.reply_wait = -1
|
||||
src.authenticated = src.account.registered
|
||||
src.print_research_status()
|
||||
var/intro_text = {"<br>HangarHelper
|
||||
<br>Bringing You the Latest in Ship Technology!.
|
||||
<br><b>Commands:</b>
|
||||
<br>(Status) to view current progress.
|
||||
<br>(Research) to view research topics.
|
||||
<br>(Cancel) to halt current research.
|
||||
<br>(Complete) to view completed research.
|
||||
<br>(Clear) to clear the screen.
|
||||
<br>(Quit) to exit HangarHelper"}
|
||||
src.print_text(intro_text)
|
||||
|
||||
proc
|
||||
find_access_file() //Look for the whimsical account_data file
|
||||
var/datum/computer/folder/accdir = src.holder.root
|
||||
if(src.master.host_program) //Check where the OS is, preferably.
|
||||
accdir = src.master.host_program.holder.root
|
||||
|
||||
var/datum/computer/file/user_data/target = parse_file_directory(setup_acc_filepath, accdir)
|
||||
if(target && istype(target))
|
||||
src.account = target
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
print_research_status()
|
||||
var/dat = "<b>Tier [robotics_research.tier] Hangar Research</b><br>"
|
||||
if(robotics_research.is_researching)
|
||||
var/timeleft = robotics_research.get_research_timeleft()
|
||||
var/text = robotics_research.current_research
|
||||
dat += "Current Research: [text ? text : "None"]. ETA: [timeleft ? timeleft : "Completed"]."
|
||||
else
|
||||
dat += "Currently not researching."
|
||||
src.print_text(dat)
|
||||
return
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,655 @@
|
||||
//CONTENTS:
|
||||
//Mainframe program parent type
|
||||
//Mainframe user account datum
|
||||
|
||||
|
||||
/*
|
||||
* Mainframe Software
|
||||
*/
|
||||
|
||||
/datum/computer/file/mainframe_program
|
||||
name = "mainframe program"
|
||||
extension = "MPG"
|
||||
var/obj/machinery/networked/mainframe/master = null
|
||||
var/executable = 1
|
||||
var/needs_holder = 1
|
||||
var/tmp/datum/computer/file/mainframe_program/parent_task = null
|
||||
var/tmp/progid = 0
|
||||
var/tmp/initialized = 0
|
||||
var/tmp/datum/mainframe2_user_data/useracc = null
|
||||
|
||||
os
|
||||
name = "Base OS"
|
||||
size = 16
|
||||
extension = "SYS"
|
||||
executable = 0
|
||||
var/tmp/setup_string = null
|
||||
|
||||
proc
|
||||
//Called by the mainframe when a new terminal connection is made so as to alert the OS
|
||||
new_connection(datum/terminal_connection/conn)
|
||||
return
|
||||
|
||||
//Called by the mainframe upon termination of a connection, conn is deleted afterwards
|
||||
closed_connection(datum/terminal_connection/conn)
|
||||
return
|
||||
|
||||
//The data string (And, optionally, file) sent to us by a connected terminal (Identified by network ID in termid)
|
||||
//Note: The passed file will be completely temporary and is deleted after the function returns.
|
||||
term_input(var/data, var/termid, var/datum/computer/file/file)
|
||||
if(!src.master || !data || !termid)
|
||||
return 1
|
||||
|
||||
if(master.stat & (NOPOWER|BROKEN|MAINT))
|
||||
return 1
|
||||
|
||||
if(src.needs_holder)
|
||||
if(!(holder in src.master.contents))
|
||||
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
|
||||
|
||||
//Called by the mainframe upon receipt of a ping_reply network signal. This does not a terminal_connection because we are not necessarily connected to the responding device.
|
||||
ping_reply(var/senderid,var/sendertype)
|
||||
return (!master || !senderid || !sendertype)
|
||||
|
||||
|
||||
//Send a message to a connected terminal device (Using term_message)
|
||||
message_term(var/message, var/termid, var/render=null)
|
||||
|
||||
if(!istype(master) || !message || !termid)
|
||||
return 1
|
||||
|
||||
if(master.stat & (NOPOWER|BROKEN|MAINT))
|
||||
return 1
|
||||
|
||||
if(src.needs_holder)
|
||||
if (!holder || !(holder in src.master.contents))
|
||||
return 1
|
||||
|
||||
if(!src.holder.root)
|
||||
src.holder.root = new /datum/computer/folder
|
||||
src.holder.root.holder = src
|
||||
src.holder.root.name = "root"
|
||||
|
||||
spawn(1)
|
||||
src.master.post_status(termid, "command", "term_message", "data", message, "render", render)
|
||||
return 0
|
||||
|
||||
//Send a file and message to a connected terminal device (Using term_file)
|
||||
file_term(var/datum/computer/file/file, var/termid, var/exdata)
|
||||
|
||||
|
||||
if(!istype(master) || !istype(file) || !termid)
|
||||
return 1
|
||||
|
||||
if(master.stat & (NOPOWER|BROKEN|MAINT))
|
||||
return 1
|
||||
|
||||
if(src.needs_holder)
|
||||
if (!holder || !(holder in src.master.contents))
|
||||
return 1
|
||||
|
||||
if(!src.holder.root)
|
||||
src.holder.root = new /datum/computer/folder
|
||||
src.holder.root.holder = src
|
||||
src.holder.root.name = "root"
|
||||
|
||||
spawn(1)
|
||||
src.master.post_file(termid, "data", exdata, file)
|
||||
return 0
|
||||
|
||||
/*
|
||||
* The parse_* functions parse the filesystem to locate a computer datum of some sort (Be it directory, file, or either)
|
||||
* with a supplied filepath string, origin point, and user. Create_if_missing determines whether intermediary folders in the path should be created if not present.
|
||||
* Notes: A '/' prefixing the filepath will cause the search to start at the origin point
|
||||
* '.' refers to the current folder in the search, while '..' refers to its parent folder
|
||||
* Results will be filtered based on the supplied user's permissions -- If they do not have permission to read a file, they will not find said file.
|
||||
* If a user datum is not supplied, it is assumed that the system made the call desiring full access.
|
||||
*/
|
||||
|
||||
parse_directory(string, var/datum/computer/folder/origin, var/create_if_missing, var/datum/mainframe2_user_data/user)
|
||||
if(!string)
|
||||
return null
|
||||
|
||||
var/datum/computer/folder/current = origin
|
||||
|
||||
if(!origin)
|
||||
origin = src.holder.root
|
||||
|
||||
if(dd_hasprefix(string , "/")) //if it starts with a /
|
||||
if (string == "/")
|
||||
return origin
|
||||
current = origin
|
||||
string = copytext(string,2)
|
||||
|
||||
var/list/sort1 = list()
|
||||
sort1 = dd_text2list(string,"/")
|
||||
if (sort1.len && !sort1[sort1.len])
|
||||
sort1.len--
|
||||
|
||||
while(current)
|
||||
|
||||
if(!sort1.len)
|
||||
return current
|
||||
|
||||
if(sort1[1] == "..")
|
||||
if (current == origin)
|
||||
return null
|
||||
current = current.holding_folder
|
||||
sort1 -= sort1[1]
|
||||
continue
|
||||
else if (sort1[1] == ".")
|
||||
sort1 -= sort1[1]
|
||||
continue
|
||||
|
||||
else if (!sort1[1] && !create_if_missing)
|
||||
return current
|
||||
|
||||
var/new_current = 0
|
||||
for(var/datum/computer/folder/F in current.contents)
|
||||
if(ckey(F.name) == ckey(sort1[1]) && (!user || check_read_permission(F, user)))
|
||||
sort1 -= sort1[1]
|
||||
current = F
|
||||
new_current = 1
|
||||
break
|
||||
|
||||
if(!new_current)
|
||||
if (!create_if_missing)
|
||||
return null
|
||||
|
||||
var/datum/computer/folder/F = new /datum/computer/folder( )
|
||||
F.name = sort1[1]
|
||||
|
||||
if (is_name_invalid(F.name))
|
||||
//qdel(F)
|
||||
F.dispose()
|
||||
return null
|
||||
|
||||
. = current.add_file(F)
|
||||
if (!.)
|
||||
if (F)
|
||||
F.dispose()
|
||||
return null
|
||||
|
||||
else if (istype(., /datum/computer/folder))
|
||||
F = .
|
||||
|
||||
sort1 -= sort1[1]
|
||||
current = F
|
||||
new_current = 1
|
||||
|
||||
return null
|
||||
|
||||
//Find a file at the end of a given dirstring.
|
||||
parse_file_directory(string, var/datum/computer/folder/origin, var/create_if_missing, var/datum/mainframe2_user_data/user)
|
||||
if(!string)
|
||||
return null
|
||||
|
||||
var/datum/computer/folder/current = origin
|
||||
|
||||
if(!origin)
|
||||
origin = src.holder.root
|
||||
|
||||
if(dd_hasprefix(string , "/")) //if it starts with a /
|
||||
current = origin
|
||||
string = copytext(string,2)
|
||||
|
||||
var/list/sort1 = list()
|
||||
sort1 = dd_text2list(string,"/")
|
||||
|
||||
var/file_name = sort1[sort1.len]
|
||||
if(!file_name)
|
||||
return null
|
||||
|
||||
sort1 -= sort1[sort1.len]
|
||||
|
||||
while(current)
|
||||
|
||||
if(!sort1.len)
|
||||
var/datum/computer/file/check = get_file_name(file_name, current, user)
|
||||
if(check && istype(check))
|
||||
return check
|
||||
else
|
||||
return null
|
||||
|
||||
if(sort1[1] == "..")
|
||||
if (current == origin)
|
||||
return null
|
||||
current = current.holding_folder
|
||||
sort1 -= sort1[1]
|
||||
continue
|
||||
else if (sort1[1] == ".")
|
||||
sort1 -= sort1[1]
|
||||
continue
|
||||
|
||||
var/new_current = 0
|
||||
for(var/datum/computer/folder/F in current.contents)
|
||||
if(ckey(F.name) == ckey(sort1[1]) && (!user || check_read_permission(F, user)))
|
||||
sort1 -= sort1[1]
|
||||
current = F
|
||||
new_current = 1
|
||||
break
|
||||
|
||||
if(!new_current)
|
||||
if (!create_if_missing)
|
||||
return null
|
||||
|
||||
var/datum/computer/folder/F = new /datum/computer/folder
|
||||
F.name = sort1[1]
|
||||
|
||||
if (is_name_invalid(F.name) || !current.add_file(F))
|
||||
//qdel(F)
|
||||
F.dispose()
|
||||
return null
|
||||
|
||||
sort1 -= sort1[1]
|
||||
current = F
|
||||
new_current = 1
|
||||
|
||||
return null
|
||||
|
||||
//If we are willing to accept either a file or folder as the return value.
|
||||
parse_datum_directory(string, var/datum/computer/folder/origin, var/create_if_missing, var/datum/mainframe2_user_data/user)
|
||||
if(!string)
|
||||
return null
|
||||
|
||||
var/datum/computer/folder/current = origin
|
||||
|
||||
if(!origin)
|
||||
origin = src.holder.root
|
||||
|
||||
if(dd_hasprefix(string , "/")) //if it starts with a /
|
||||
if (string == "/")
|
||||
return origin
|
||||
current = origin
|
||||
string = copytext(string,2)
|
||||
|
||||
var/list/sort1 = list()
|
||||
sort1 = dd_text2list(string,"/")
|
||||
|
||||
var/datum_name = sort1[sort1.len]
|
||||
if(!datum_name)
|
||||
//return null
|
||||
sort1.len--
|
||||
while (sort1.len)
|
||||
datum_name = sort1[sort1.len]
|
||||
if (!datum_name)
|
||||
sort1.len--
|
||||
continue
|
||||
break
|
||||
|
||||
sort1.len = max(0, sort1.len-1)
|
||||
|
||||
while(current)
|
||||
|
||||
if(!sort1.len)
|
||||
switch(datum_name)
|
||||
if ("..")
|
||||
if (current == origin)
|
||||
return null
|
||||
return current.holding_folder
|
||||
if (".")
|
||||
return current
|
||||
var/datum/computer/check = get_computer_datum(datum_name, current, user)
|
||||
if(check && istype(check))
|
||||
return check
|
||||
else
|
||||
return null
|
||||
|
||||
if(sort1[1] == "..")
|
||||
current = current.holding_folder
|
||||
sort1 -= sort1[1]
|
||||
continue
|
||||
else if (sort1[1] == ".")
|
||||
sort1 -= sort1[1]
|
||||
continue
|
||||
|
||||
var/new_current = 0
|
||||
for(var/datum/computer/folder/F in current.contents)
|
||||
if(ckey(F.name) == ckey(sort1[1]) && (!user || check_read_permission(F, user)))
|
||||
sort1 -= sort1[1]
|
||||
current = F
|
||||
new_current = 1
|
||||
break
|
||||
|
||||
if(!new_current)
|
||||
if (!create_if_missing)
|
||||
return null
|
||||
|
||||
var/datum/computer/folder/F = new /datum/computer/folder
|
||||
F.name = sort1[1]
|
||||
|
||||
if (is_name_invalid(F.name) || !current.add_file(F))
|
||||
//qdel(F)
|
||||
F.dispose()
|
||||
return null
|
||||
|
||||
sort1 -= sort1[1]
|
||||
current = F
|
||||
new_current = 1
|
||||
|
||||
return null
|
||||
|
||||
New(obj/holding as obj)
|
||||
if(holding)
|
||||
src.holder = holding
|
||||
|
||||
if(istype(src.holder.loc,/obj/machinery/networked/mainframe))
|
||||
src.master = src.holder.loc
|
||||
|
||||
disposing()
|
||||
if(master && (src in master.processing))
|
||||
master.processing[src] = null
|
||||
master = null
|
||||
..()
|
||||
|
||||
asText()
|
||||
return initialized ? "[progid]" : ..()
|
||||
|
||||
proc
|
||||
input_text(var/text)
|
||||
if(!istype(src.master) || !text || !useracc)
|
||||
return 1
|
||||
|
||||
if(src.needs_holder)
|
||||
if(!istype(holder))
|
||||
return 1
|
||||
|
||||
if(!(holder in src.master.contents))
|
||||
return 1
|
||||
|
||||
if(master.stat & (NOPOWER|BROKEN|MAINT))
|
||||
return 1
|
||||
|
||||
if(src.needs_holder && !src.holder.root)
|
||||
src.holder.root = new /datum/computer/folder
|
||||
src.holder.root.holder = src
|
||||
src.holder.root.name = "root"
|
||||
|
||||
return 0
|
||||
|
||||
initialize(var/initparams) //Called when a program starts running.
|
||||
if(src.initialized || !master)
|
||||
return 1
|
||||
|
||||
src.initialized = 1
|
||||
return 0
|
||||
|
||||
//Note: If you want your application to end inteionally, send the OS an "exit" signal.
|
||||
//Use the mainframe_prog_exit macro. The program will not exit otherwise, even if nothing bothers to send it more input
|
||||
handle_quit()
|
||||
if(src.master)
|
||||
src.master.unload_program(src)
|
||||
return
|
||||
|
||||
process()
|
||||
if (!istype(master))
|
||||
return 1
|
||||
|
||||
if (src.needs_holder)
|
||||
if (!istype(holder))
|
||||
return 1
|
||||
|
||||
if(!(holder in src.master.contents))
|
||||
master.processing.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
|
||||
|
||||
parse_string(string, var/list/replaceList = null)
|
||||
var/list/sorted = list()
|
||||
sorted = command2list(string, " ", replaceList)
|
||||
if (!sorted.len) sorted.len++
|
||||
return sorted
|
||||
|
||||
//Find a folder with a given name
|
||||
get_folder_name(string, var/datum/computer/folder/check_folder, var/datum/mainframe2_user_data/user)
|
||||
if(!string || !istype(check_folder))
|
||||
return null
|
||||
|
||||
var/datum/computer/taken = null
|
||||
for(var/datum/computer/folder/F in check_folder.contents)
|
||||
if(ckey(string) == ckey(F.name) && (!user || check_read_permission(F, user)))
|
||||
taken = F
|
||||
break
|
||||
|
||||
return taken
|
||||
|
||||
//Find a file with a given name
|
||||
get_file_name(string, var/datum/computer/folder/check_folder, var/datum/mainframe2_user_data/user)
|
||||
if(!string || !istype(check_folder))
|
||||
return null
|
||||
|
||||
var/datum/computer/taken = null
|
||||
for(var/datum/computer/file/F in check_folder.contents)
|
||||
if(ckey(string) == ckey(F.name) && (!user || check_read_permission(F, user)))
|
||||
taken = F
|
||||
break
|
||||
|
||||
return taken
|
||||
|
||||
//Just find any computer datum with this name, gosh
|
||||
get_computer_datum(string, var/datum/computer/folder/check_folder, var/datum/mainframe2_user_data/user)
|
||||
if(!string || !istype(check_folder))
|
||||
return null
|
||||
|
||||
var/datum/computer/taken = null
|
||||
for(var/datum/computer/C in check_folder.contents)
|
||||
if(ckey(string) == ckey(C.name) && (!user || check_read_permission(C, user)))
|
||||
taken = C
|
||||
break
|
||||
|
||||
return taken
|
||||
|
||||
is_name_invalid(string) //Check if a filename is invalid somehow
|
||||
if(!string)
|
||||
return 1
|
||||
//ckeyEx because it allows for - and _ and we love those!!
|
||||
if(lowertext(ckeyEx(string)) != dd_replacetext(lowertext(string), " ", null))
|
||||
return 1
|
||||
|
||||
if(findtext(string, "/"))
|
||||
return 1
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
//Pass an output string to the user terminal, with optional render value.
|
||||
//Notes: The string is not immediately set to the user! It is instead passed by signal to the parent task of the program.
|
||||
//This allows for piping operations, etc. It is the duty of the OS to actually tranmit the information to the terminal.
|
||||
message_user(var/msg, var/render, var/file)
|
||||
if (!useracc)
|
||||
return ESIG_NOTARGET
|
||||
|
||||
if (parent_task)
|
||||
if (render)
|
||||
return signal_program(parent_task.progid, list("command"=DWAINE_COMMAND_MSG_TERM, "data" = msg, "term" = useracc.user_id, "render" = render), file )
|
||||
else
|
||||
return signal_program(parent_task.progid, list("command"=DWAINE_COMMAND_MSG_TERM, "data" = msg, "term" = useracc.user_id), file )
|
||||
|
||||
return ESIG_GENERIC
|
||||
|
||||
read_user_field(var/field)
|
||||
if (!useracc || (!istype(useracc.user_file) && !useracc.reload_user_file()))
|
||||
return null
|
||||
|
||||
return useracc.user_file.fields[field]
|
||||
|
||||
write_user_field(var/field, var/data)
|
||||
if (!useracc || !field || (!istype(useracc.user_file) && !useracc.reload_user_file()) || !useracc.user_file.fields)
|
||||
return 0
|
||||
|
||||
useracc.user_file.fields[field] = data
|
||||
return 1
|
||||
|
||||
signal_program(var/progid, var/list/data, var/datum/computer/file/file)
|
||||
if(!data || !master)
|
||||
return 1
|
||||
|
||||
if(useracc && useracc.user_file && ("id" in useracc.user_file.fields))
|
||||
data["user"] = useracc.user_file.fields["id"]
|
||||
|
||||
return master.relay_progsignal(src, progid, data, file)
|
||||
|
||||
receive_progsignal(var/sendid, var/list/data, var/datum/computer/file/file)
|
||||
return (!src.master || !(src in master.processing))
|
||||
|
||||
|
||||
unloaded()
|
||||
return
|
||||
|
||||
check_read_permission(var/datum/computer/cdatum, var/datum/mainframe2_user_data/usdat)
|
||||
if (!usdat)
|
||||
return 0
|
||||
|
||||
if (istype(cdatum, /datum/computer/folder/link) && cdatum:target)
|
||||
cdatum = cdatum:target
|
||||
|
||||
if (!istype(cdatum) || !cdatum.metadata)
|
||||
return 0
|
||||
|
||||
var/permissions = COMP_ALLACC
|
||||
if (isnum(cdatum.metadata["permission"]))
|
||||
permissions = cdatum.metadata["permission"]
|
||||
|
||||
if (istype(usdat.user_file) || usdat.reload_user_file())
|
||||
if (!usdat.user_file.fields)
|
||||
usdat.user_file.fields = list()
|
||||
|
||||
if (usdat.user_file.fields["group"] == 0) //Sysop usergroup
|
||||
return 1
|
||||
|
||||
if (cdatum.metadata["owner"] && (usdat.user_file.fields["name"] == cdatum.metadata["owner"]) && (permissions & COMP_ROWNER))
|
||||
return 1
|
||||
|
||||
if (cdatum.metadata["group"] && (usdat.user_file.fields["group"] == cdatum.metadata["group"]) && (permissions & COMP_RGROUP))
|
||||
return 1
|
||||
|
||||
return (permissions & COMP_ROTHER)
|
||||
|
||||
check_write_permission(var/datum/computer/cdatum, var/datum/mainframe2_user_data/usdat)
|
||||
if (!cdatum || !usdat)
|
||||
return 0
|
||||
|
||||
var/permissions = COMP_ALLACC
|
||||
|
||||
if (istype(cdatum, /datum/computer/folder/link) && cdatum:target)
|
||||
cdatum = cdatum:target
|
||||
|
||||
if (!istype(cdatum) || !cdatum.metadata)
|
||||
return 0
|
||||
|
||||
if (istype(cdatum.metadata, /list) && isnum(cdatum.metadata["permission"]))
|
||||
permissions = cdatum.metadata["permission"]
|
||||
|
||||
if (istype(usdat.user_file) || usdat.reload_user_file())
|
||||
|
||||
if (usdat.user_file.fields["group"] == 0) //Sysop usergroup can ~do anything~
|
||||
return 1
|
||||
|
||||
if (cdatum.metadata["owner"] && (usdat.user_file.fields["name"] == cdatum.metadata["owner"]) && (permissions & COMP_WOWNER))
|
||||
return 1
|
||||
|
||||
if (cdatum.metadata["group"] && (usdat.user_file.fields["group"] == cdatum.metadata["group"]) && (permissions & COMP_WGROUP))
|
||||
return 1
|
||||
|
||||
return (permissions & COMP_WOTHER)
|
||||
|
||||
return 0
|
||||
|
||||
check_mode_permission(var/datum/computer/cdatum, var/datum/mainframe2_user_data/usdat)
|
||||
if (!cdatum || !usdat)
|
||||
return 0
|
||||
|
||||
if (istype(cdatum, /datum/computer/folder/link) && cdatum:target)
|
||||
cdatum = cdatum:target
|
||||
|
||||
if (!istype(cdatum) || !cdatum.metadata)
|
||||
return 0
|
||||
|
||||
var/permissions = COMP_ALLACC
|
||||
if (istype(cdatum.metadata, /list) && isnum(cdatum.metadata["permission"]))
|
||||
permissions = cdatum.metadata["permission"]
|
||||
|
||||
if (istype(usdat.user_file) || usdat.reload_user_file())
|
||||
|
||||
if (usdat.user_file.fields["group"] == 0) //Sysop usergroup can ~do anything~
|
||||
return 1
|
||||
|
||||
if (cdatum.metadata["owner"] && (usdat.user_file.fields["name"] == cdatum.metadata["owner"]) && (permissions & COMP_DOWNER && permissions & COMP_WOWNER) )
|
||||
return 1
|
||||
|
||||
if (cdatum.metadata["group"] && (usdat.user_file.fields["group"] == cdatum.metadata["group"]) && (permissions & COMP_DGROUP && permissions & COMP_WGROUP) )
|
||||
return 1
|
||||
|
||||
return ((permissions & COMP_DOTHER) && (permissions & COMP_WOTHER))
|
||||
|
||||
return 0
|
||||
|
||||
//Command2list is a modified version of dd_text2list() designed to eat empty list entries generated by superfluous whitespace.
|
||||
//It also can insert shell alias/variables if provided with a replacement value list.
|
||||
#define QUOTE_SYMBOL "\""
|
||||
#define QUOTE_SYMBOL_LENGTH 1
|
||||
/proc/command2list(text, separator, list/replaceList, list/substitution_feedback_thing)
|
||||
var/textlength = length(text)
|
||||
var/separatorlength = length(separator)
|
||||
var/list/textList = new()
|
||||
var/searchPosition = 1
|
||||
var/findPosition = 1
|
||||
var/buggyText
|
||||
|
||||
|
||||
//substitution_feedback_thing = list() //debug
|
||||
while(1)
|
||||
findPosition = findtext(text, separator, searchPosition, 0)
|
||||
var/quotePoint = findtext(text, QUOTE_SYMBOL, searchPosition, findPosition)
|
||||
if (quotePoint)
|
||||
text = copytext(text, 1, quotePoint) + copytext(text, quotePoint + QUOTE_SYMBOL_LENGTH, 0)
|
||||
var/quotePointEnd = findtext(text, QUOTE_SYMBOL, quotePoint, 0)
|
||||
buggyText = copytext(text, searchPosition, quotePointEnd)
|
||||
findPosition = quotePointEnd+QUOTE_SYMBOL_LENGTH
|
||||
else
|
||||
var/subStartPoint = findtext(text, "$(", searchPosition, findPosition)
|
||||
if (substitution_feedback_thing && subStartPoint)
|
||||
var/subEndPoint = findtext(text, ")", subStartPoint)
|
||||
substitution_feedback_thing[++substitution_feedback_thing.len] = copytext(text, subStartPoint+2, subEndPoint)
|
||||
|
||||
text = copytext(text, 1, subStartPoint) + "_sub[substitution_feedback_thing.len]" + copytext(text, subEndPoint ? subEndPoint + 1 : 0)
|
||||
//boutput(world, "text changed to \"[text]\"")
|
||||
|
||||
//boutput(world, "added: \[[substitution_feedback_thing[substitution_feedback_thing.len]]]")
|
||||
|
||||
continue
|
||||
|
||||
else
|
||||
buggyText = trim(copytext(text, searchPosition, findPosition))
|
||||
|
||||
if(buggyText)
|
||||
|
||||
if (replaceList && dd_hasprefix(buggyText, "$") && (copytext(buggyText,2) in replaceList))
|
||||
textList += "[replaceList[copytext(buggyText, 2)]]"
|
||||
else
|
||||
textList += "[buggyText]"
|
||||
if(!findPosition)
|
||||
//boutput(world, english_list(textList))
|
||||
return textList
|
||||
searchPosition = findPosition + separatorlength
|
||||
if(searchPosition > textlength)
|
||||
//boutput(world, english_list(textList))
|
||||
return textList
|
||||
return
|
||||
|
||||
#undef QUOTE_SYMBOL
|
||||
#undef QUOTE_SYMBOL_LENGTH
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
//CONTENTS:
|
||||
//DWAINE system help file
|
||||
//Guardbot readme
|
||||
//Guardbot demo patrol script file
|
||||
//Guardbot demo bodyguard script file
|
||||
//Guardbot demo configuration file
|
||||
//Artifact research readme
|
||||
|
||||
|
||||
/*
|
||||
* Help record - Individual entries accessed by shell "help" command. "index" entry generated programmatically.
|
||||
*/
|
||||
/datum/computer/file/record/dwaine_help
|
||||
name = "help"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.fields["basics1"] = "DWAINE is a multi-user Unix-like operating system produced by Thinktronic Data Systems. The primary user interface is through a text-based terminal shell.|nApplications may be invoked simply by typing their filename, followed by a list of arguments if necessary. A set of primary commands, those covering basic system tasks (Such as ls and cd), are made available to all users regardless of location in the filesystem. Otherwise, applications must be in the user's current working directory to run."
|
||||
src.fields["basics2"] = "Directory navigation is accomplished primarily through the ls and cd commands.|nLS, an abbreviation of \"list\" will list the contents of the current directory. The argument -l will cause it to also display extended file information and hidden files.|nCD, or \"change directory\" will set the current directory to the provided path, if valid. A filepath takes a form such as \"/mnt/drive0\" Paths starting with / descend from the root directory \"..\" refers to the directory one level up from the current, while \".\" refers to the current directory.|nEx: \"cd ../hams\" would specify a directory named ham with the same parent as the current working one."
|
||||
src.fields["basics3"] = "DWAINE is, primarily, a networked system. All devices, from user terminals to lineprinters and tape drives, are connected remotely to the central mainframe. Devices that interact with files, such as drives or printers, may appear as part of the filesystem as a sub-directory of /mnt.|nFor example, the contents of tape databank \"Main\" would appear within /mnt/main and applications and other files could be accessed by setting it to your working directory with \"cd /mnt/main\""
|
||||
src.fields["basics4"] = "Application software is often bundled with a \"readme\" file of some sort, which can be viewed with the CAT command.|nEx: \"cat readme\" will view the contents of a readme file in the user's working directory."
|
||||
src.fields["ls"] = "View contents of a directory. If no filepath is supplied, the working directory will be listed.|nExpanded file information, as well as hidden files, may be viewed through use of the -l argument.|nUsage: ls \[-l] \[filepath]"
|
||||
src.fields["cd"] = "Change working directory to the filepath supplied as argument.|nUsage: cd \"filepath\""
|
||||
src.fields["cat"] = "Combine the contents of one or more data files and print result to current output (Default output would be the user terminal). Use with executable files is inadvisable.|nUsage: cat \"filepath\" \[filepath...]"
|
||||
src.fields["echo"] = "Print text to current stream. Stream defaults to standard output (User terminal screen) if not piping.|nIf piping, output is passed on. If the piping target is not an executable, an attempt will be made to write to that file.|nUsage: echo \"text\" OR echo \"text\" | pipe_file_name"
|
||||
src.fields["eval"] = "Evaluate an expression. Stack based with RPN input--the operation is expressed following the inputs, like \"1 2 +\" will result in 3.|nInput values are placed in order in a \"stack,\" with most recent input on top and first input on the bottom. Values are taken back off the stack from the top down. Operations act on the top 1 or 2 values on the stack, usually removing them and placing the result as the new top.|nValid operations are +, -, *, /, %, for arithmetic operations.|neq (equal), neq (not equal), gt (greater than), ge (greater or equal), lt (less than), le (less or equal) for comparison operations,|nAnd, Or, Not, and Xor for logical operations.|nThe operator DUP will copy the top value on the stack without removing anything from the stack.|nText surrounded by apostrophes will be interpreted as a string. Variables may be set by pushing the desired value to the stack and then using the TO operator and a variable name. For example, \"5 to HAMDAD\" would create a variable with the name HAMDAD and value 5.|nThere are also four file checking operators: d, e, f, and x. Each take a filepath string from the top of the stack and leave a boolean value in its place. d leaves a true if the path is to a folder, x is true if the path is to an executable, f is true if the path is to a file, and e is true if the path is to anything at all."
|
||||
src.fields["who"] = "Print list of current users to current output.|nUsage: who"
|
||||
src.fields["mesg"] = "Control acceptance of messages sent by other users.|nUsage mesg \"(y/n)\""
|
||||
src.fields["talk"] = "Send a message to another current user.|nUsage talk \"user name or user terminal ID\" \"message\""
|
||||
src.fields["cp"] = "Copy datafile to a new location. If new filepath specifies only a directory, the copy will retain original name.|nUsage: cp \"target filepath\" \"new filepath\""
|
||||
src.fields["mv"] = "Move datafile to a new location. If new filepath specifies only a directory, the file will retain original name.|nUsage: mv \"target filepath\" \"new filepath\""
|
||||
src.fields["rm"] = "Delete datafile or directory. Use of -r switch required for directory deletion. -i switch enables confirmation prompt, while -f suppresses this and error messages.|nUsage: rm \"target filepath\""
|
||||
src.fields["su"] = "Assume superuser status. An authorized ID must be provided.|nUsage: \"su\""
|
||||
src.fields["mkdir"] = "Create a directory or set of directories with the provided paths.|nUsage: mkdir \[filepath...]"
|
||||
src.fields["chmod"] = "Change the permissions of a file. File permissions take the form of three octal digits in the order of: owner, group, any user.|nBit one (The least significant bit) of each field controls modify access, bit two controls write access, and the third bit controls read access.|nUsage: chmod \"access value, i.e 777\" \"filename\""
|
||||
src.fields["chown"] = "Change the owner and/or group of a file. System operator status required to invoke.|nUsage: chown \[exact username]:\[group ID] \"filename\""
|
||||
src.fields["mount"] = "Mount device driver file space to filesystem. System operator status required to invoke.|nUsage: mount \"device net ID\" \"mountpoint name (Name for folder in /mnt)\""
|
||||
src.fields["scnt"] = "Scan network for unconnected peripheral devices, and then automatically connect to them. System operator status required to invoke.|nSpecific net IDs may be provided as arguments to connect to them directly. |nUsage: \"scnt\""
|
||||
src.fields["logoff"] = "Log out current user and ready system to accept new login.|nUsage: \"logoff\""
|
||||
|
||||
src.fields["index"] = "Usage: help \"topic\"|nValid Topics: [english_list(src.fields, "None")]"
|
||||
|
||||
/datum/computer/file/record/pr6_readme
|
||||
name = "readme"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.fields = list("Readme for PR-6 Control Interface",
|
||||
"Notice: Superuser access may be required to run prman application",
|
||||
"Please ready authorized heads ID and type \"su\"",
|
||||
"",
|
||||
"A series of demo files have been supplied, as well as PR-6 task packages.",
|
||||
"patrol_script takes one argument, the net id of the target bot. It may be invoked by \"patrol_script (bot id)\"",
|
||||
"guard_script takes two arguments, the net id of the target bot and the full name, with no spaces, of the person to protect.",
|
||||
"demo_conf is a demonstration configuration file to set bodyguard tasks to guard \"John Doe\"",
|
||||
"Valid PR-6 net ids may be listed via \"prman list\"",
|
||||
"PR-6 units may be recalled via \"prman recall (id)\" The id may either correspond to the actual PR-6 unit or its last used dock.",
|
||||
"If no arguments are supplied to prman, it will list valid commands.")
|
||||
|
||||
/datum/computer/file/record/patrol_script
|
||||
name = "patrol_script"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.fields = list("#!",
|
||||
"#demonstration patrol script",
|
||||
"#takes bot net id as argument",
|
||||
"if $argc 1 lt | echo Error: No Net ID specified! | break",
|
||||
"if $su 1 ne | echo Please authenticate (su) prior to invocation. | break",
|
||||
//FUN NOTE; Why do we use /conf instead of just the local directory?
|
||||
//"echo patrol=1|/conf/confpatrol",
|
||||
//Because this file is, by default, on a tape drive. The write time on secondary storage is such that
|
||||
//"prman upload $arg0 secure -f /conf/confpatrol",
|
||||
//by the time the file is visible, prman would've already looked and failed to find it.
|
||||
|
||||
"prman upload $arg0 secure patrol=1;",
|
||||
"prman wake $arg0")
|
||||
|
||||
/datum/computer/file/record/bodyguard_script
|
||||
name = "guard_script"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.fields = list("#!",
|
||||
"#simple bodyguard script",
|
||||
"#takes bot net id and spaceless target name as argument",
|
||||
"#ex: guard_script 02000050 johndoe",
|
||||
"if argc 2 lt | echo Error: No Net ID or target name specified! | break",
|
||||
"if su 1 ne | echo Please authenticate (su) prior to invocation. | break",
|
||||
//"echo name= | echo $arg1|/conf/confguard",
|
||||
//"prman upload $arg0 bodyguard -f /conf/confguard",
|
||||
"prman upload $arg0 bodyguard name= $arg1",
|
||||
"prman wake $arg0")
|
||||
|
||||
/datum/computer/file/record/roomguard_script
|
||||
name = "roomguard_script"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.fields = list("#!",
|
||||
"#Bot will only look for targets in the same area.",
|
||||
"#takes bot net id as argument",
|
||||
"if $argc 1 lt | echo Error: No Net ID specified! | break",
|
||||
"if $su 1 ne | echo Please authenticate (su) prior to invocation. | break",
|
||||
"prman upload $arg0 areaguard",
|
||||
"prman wake $arg0")
|
||||
|
||||
/datum/computer/file/record/bodyguard_conf
|
||||
name = "demo_conf"
|
||||
|
||||
New()
|
||||
..()
|
||||
src.fields = list("#demonstration of configuration file",
|
||||
"#for bodyguard and secure tasks",
|
||||
"name=john doe",
|
||||
"#this is the name of the protected individual",
|
||||
"",
|
||||
"#this is for use with the secure task",
|
||||
"patrol=1",
|
||||
"",
|
||||
"#prman upload bot_id bodyguard patrol=1",
|
||||
"or",
|
||||
"#prman upload bot_id bodyguard -f demo_conf")
|
||||
|
||||
/*
|
||||
* Emails!!
|
||||
*/
|
||||
|
||||
/proc/get_random_email_list()
|
||||
return strings("mainframe/documents/randomEmail.txt", "availableMail")
|
||||
|
||||
/datum/computer/file/record/random_email
|
||||
|
||||
New(mailName as text)
|
||||
..()
|
||||
src.name = "[copytext("\ref[src]", 4, 12)]GENERIC"
|
||||
if (mailName)
|
||||
src.fields = strings("mainframe/documents/randomEmail.txt", mailName)
|
||||
@@ -0,0 +1,250 @@
|
||||
//CONTENTS
|
||||
//Email daemon thing
|
||||
|
||||
/datum/computer/file/mainframe_program/srv/email
|
||||
name = "mail"
|
||||
size = 1
|
||||
|
||||
var/setup_email_folder = "/etc/mail"
|
||||
var/setup_mailgroup_table = "groups"
|
||||
var/defaultDomain = "NT13"
|
||||
|
||||
initialize(var/initparams)
|
||||
if (..() || !useracc)
|
||||
mainframe_prog_exit
|
||||
return
|
||||
//todo: all of this. All of this forever.
|
||||
|
||||
//boutput(world, "[initparams]")
|
||||
|
||||
var/command = null
|
||||
var/list/initlist = dd_text2list(initparams, " ")
|
||||
if (!initparams || !initlist.len)
|
||||
command = "index"
|
||||
else
|
||||
command = ckey(initlist[1])
|
||||
|
||||
var/user_name = dd_hasprefix(useracc.user_name, "SRV") ? copytext(useracc.user_name, 4, length(useracc.user_name)) : copytext(useracc.user_name, 1, length(useracc.user_name))
|
||||
|
||||
//boutput(world, "Username: \"[useracc.user_name]\" -> \"[user_name]\"")
|
||||
|
||||
switch (command)
|
||||
if ("index")
|
||||
var/group = null
|
||||
if (initlist.len > 1)
|
||||
group = initlist[2]
|
||||
var/list/mail_subjects = list_mail_subjects(user_name, group)
|
||||
var/message = "mail_index"
|
||||
if (mail_subjects.len)
|
||||
message += "|n" + dd_list2text(mail_subjects, "|n")
|
||||
message_user(message, "record")
|
||||
|
||||
if ("get")
|
||||
var/index = 0
|
||||
var/group = null
|
||||
if (initlist.len > 1)
|
||||
index = max( round(text2num(initlist[2])), 1)
|
||||
|
||||
if (initlist.len > 2)
|
||||
group = initlist[3]
|
||||
|
||||
var/list/mailList = list_mail_for(user_name, group)
|
||||
if (!istype(mailList) || mailList.len < index)
|
||||
mainframe_prog_exit
|
||||
return
|
||||
|
||||
var/datum/computer/file/record/targetMail = mailList[index]
|
||||
if (istype(targetMail) && parent_task)
|
||||
targetMail = format_outgoing_mail(targetMail)
|
||||
message_user("mail_entry",null,targetMail)
|
||||
|
||||
if ("send")
|
||||
if (initlist.len > 1)
|
||||
var/sentMailPath = initlist[2]
|
||||
if (!dd_hasprefix(sentMailPath, "/"))
|
||||
sentMailPath = "/[sentMailPath]"
|
||||
|
||||
var/datum/computer/file/record/sentMail = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[sentMailPath]"))
|
||||
if (istype(sentMail))
|
||||
sentMail = sentMail.copy_file()
|
||||
sentMail.fields = sentMail.fields.Copy()
|
||||
if (send_mail_to(sentMail) == 0)
|
||||
message_user("ack")
|
||||
else
|
||||
message_user("nack")
|
||||
|
||||
if ("delete")
|
||||
var/index = 0
|
||||
var/group = null
|
||||
if (initlist.len > 1)
|
||||
index = max( round(text2num(initlist[2])), 1)
|
||||
|
||||
if (initlist.len > 2)
|
||||
group = initlist[3]
|
||||
|
||||
var/list/mailList = list_mail_for(user_name, group)
|
||||
if (!istype(mailList) || mailList.len < index)
|
||||
mainframe_prog_exit
|
||||
return
|
||||
|
||||
var/datum/computer/file/record/targetMail = mailList[index]
|
||||
if (istype(targetMail) && dd_hassuffix(targetMail.name, user_name))
|
||||
if (signal_program(1, list("command"=DWAINE_COMMAND_FKILL, "path"="[setup_email_folder]/[targetMail.name]")) == ESIG_SUCCESS)
|
||||
message_user("ack")
|
||||
else
|
||||
message_user("nack")
|
||||
else
|
||||
message_user("nack")
|
||||
|
||||
mainframe_prog_exit
|
||||
return
|
||||
|
||||
proc
|
||||
format_outgoing_mail(var/datum/computer/file/record/mail)
|
||||
if (!istype(mail) || !mail.fields || (mail.fields.len < 6))
|
||||
return null
|
||||
|
||||
var/datum/computer/file/record/newMail = mail.copy_file()
|
||||
newMail.fields = newMail.fields.Copy()
|
||||
var/compactHeader = "mailnet=[mail.fields[1] ? mail.fields[1] : "???"]&group=[mail.fields[2] ? mail.fields[2] : "???"]"
|
||||
compactHeader += "&sender=[mail.fields[3] ? mail.fields[3] : "???"]&target=[mail.fields[4] ? mail.fields[4] : "???"]"
|
||||
compactHeader += "&priority=[mail.fields[5] ? mail.fields[5] : "LOW"]&subj=[mail.fields[6] ? mail.fields[6] : "???"]"
|
||||
|
||||
newMail.fields[1] = compactHeader
|
||||
newMail.fields.Cut(2, 7)
|
||||
|
||||
return newMail
|
||||
|
||||
send_mail_to(var/datum/computer/file/record/mail)
|
||||
if (!istype(mail) || !mail.fields.len)
|
||||
return 1
|
||||
|
||||
var/list/mailHeader = params2list(mail.fields[1])
|
||||
if (!mailHeader)
|
||||
return 2
|
||||
|
||||
var/target = mailHeader["target"]
|
||||
var/target_name = target
|
||||
var/atLocation = findtext(target, "@")
|
||||
if (atLocation)
|
||||
target_name = copytext(target,1, atLocation)
|
||||
|
||||
var/mailgroup = ckey(mailHeader["group"]) ? mailHeader["group"] : "*NONE"
|
||||
|
||||
if (!target && !mailgroup)
|
||||
return 3
|
||||
|
||||
var/datum/computer/folder/mailgroupTable = null
|
||||
if (mailgroup && lowertext(mailgroup) != "*all" && lowertext(mailgroup) != "*none")
|
||||
mailgroupTable = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[setup_email_folder]/[setup_mailgroup_table]"))
|
||||
if (!istype(mailgroupTable))
|
||||
return 4
|
||||
|
||||
mail.fields.Cut(1,2)
|
||||
mail.name = "[copytext("\ref[mail]", 4, 12)][target_name ? lowertext(target_name) : "all"]"
|
||||
mail.fields.Insert(1, "PUBLIC_NT", "[uppertext(mailgroup)]","[ckeyEx(mailHeader["sender"]) ? copytext(uppertext(ckeyEx(mailHeader["sender"])), 1, 33) : "???"][dd_hassuffix(mailHeader["sender"], "@[defaultDomain]") ? null : "@[defaultDomain]"]",\
|
||||
"[target ? target : "ALL"]",\
|
||||
"[ckeyEx(mailHeader["priority"]) ? copytext(uppertext(ckeyEx(mailHeader["priority"])), 1, 9) : "LOW"]",\
|
||||
"[ckeyEx(mailHeader["subj"]) ? copytext(uppertext(mailHeader["subj"]), 1, 33) : "???"]")
|
||||
|
||||
if (signal_program(1, list("command"=DWAINE_COMMAND_FWRITE, "path"="[setup_email_folder]", "mkdir"=1), mail) == ESIG_SUCCESS)
|
||||
return 0
|
||||
|
||||
return 5
|
||||
|
||||
list_mail_for(var/target, var/mailgroup=null)//"*all")
|
||||
if (!target && !mailgroup)
|
||||
return
|
||||
|
||||
var/list/mailList = list()
|
||||
var/datum/computer/folder/mailFolder = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[setup_email_folder]"))
|
||||
if (!istype(mailFolder))
|
||||
return mailList
|
||||
|
||||
var/datum/computer/file/record/mailgroupTable = null
|
||||
var/list/groupTargets = null
|
||||
if (!(mailgroup && lowertext(mailgroup) != "*all"))
|
||||
groupTargets = list()
|
||||
mailgroupTable = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[setup_email_folder]/[setup_mailgroup_table]"))
|
||||
if (istype(mailgroupTable))
|
||||
for (var/groupDef in mailgroupTable.fields)
|
||||
if (findtext(groupDef, "[target],"))
|
||||
groupTargets += "[copytext(groupDef, 1, findtext(groupDef, ":"))]"
|
||||
break
|
||||
|
||||
for(var/datum/computer/file/record/emailRec in mailFolder.contents)
|
||||
if (!check_read_permission(emailRec, useracc))
|
||||
continue
|
||||
|
||||
if ((emailRec.fields.len >= 2) && lowertext(emailRec.fields[2]) == "*all")
|
||||
mailList += emailRec
|
||||
continue
|
||||
|
||||
if (groupTargets && groupTargets.len)
|
||||
var/success = 0
|
||||
for (var/groupMember in groupTargets)
|
||||
if (emailRec.fields.len >= 2 && (lowertext(groupMember) == lowertext(emailRec.fields[2])))
|
||||
mailList += emailRec
|
||||
success = 1
|
||||
break
|
||||
|
||||
if (success)
|
||||
continue
|
||||
|
||||
if (target && dd_hassuffix(emailRec.name, target))
|
||||
mailList += emailRec
|
||||
continue
|
||||
|
||||
return mailList
|
||||
|
||||
|
||||
list_mail_subjects(var/target, var/mailgroup=null)//"*all")
|
||||
if (!target && !mailgroup)
|
||||
return
|
||||
|
||||
var/list/mailSubjs = list()
|
||||
var/datum/computer/folder/mailFolder = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[setup_email_folder]"))
|
||||
if (!istype(mailFolder))
|
||||
return mailSubjs
|
||||
|
||||
var/datum/computer/file/record/mailgroupTable = null
|
||||
var/list/groupTargets = null
|
||||
if (!(mailgroup && lowertext(mailgroup) != "*all"))
|
||||
groupTargets = list()
|
||||
mailgroupTable = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[setup_email_folder]/[setup_mailgroup_table]"))
|
||||
if (istype(mailgroupTable))
|
||||
for (var/groupDef in mailgroupTable.fields)
|
||||
if (findtext(groupDef, "[target],"))
|
||||
groupTargets += "[copytext(groupDef, 1, findtext(groupDef, ":"))]"
|
||||
break
|
||||
|
||||
for(var/datum/computer/file/record/emailRec in mailFolder.contents)
|
||||
if (!check_read_permission(emailRec, useracc))
|
||||
continue
|
||||
|
||||
if (!emailRec.fields || emailRec.fields.len < 6)
|
||||
continue
|
||||
|
||||
if (lowertext(emailRec.fields[2]) == "*all")
|
||||
mailSubjs.len++
|
||||
mailSubjs[mailSubjs.len] = copytext(emailRec.fields[6], 1, 33)
|
||||
continue
|
||||
|
||||
if (groupTargets && groupTargets.len)
|
||||
var/success = 0
|
||||
for (var/groupMember in groupTargets)
|
||||
if (lowertext(groupMember) == lowertext(emailRec.fields[2]))
|
||||
mailSubjs.len++
|
||||
mailSubjs[mailSubjs.len] = copytext(emailRec.fields[6], 1, 33)
|
||||
success = 1
|
||||
break
|
||||
|
||||
if (success)
|
||||
continue
|
||||
|
||||
if (target && dd_hassuffix(emailRec.name, target))
|
||||
mailSubjs.len++
|
||||
mailSubjs[mailSubjs.len] = copytext(emailRec.fields[6], 1, 33)
|
||||
continue
|
||||
|
||||
return mailSubjs
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
|
||||
//Filetype used to store information on current user
|
||||
/datum/computer/file/user_data
|
||||
name = "user account"
|
||||
extension = "USR"
|
||||
size = 1
|
||||
|
||||
//Store the data an ID card would.
|
||||
var/registered = null
|
||||
var/assignment = null
|
||||
var/list/access = list()
|
||||
//And some more
|
||||
var/net_id = null
|
||||
var/tmp/authlevel = 0
|
||||
var/tmp/datum/computer/file/mainframe_program/active_program = null
|
||||
var/tmp/datum/computer/folder/current_folder = null
|
||||
|
||||
disposing()
|
||||
active_program = null
|
||||
current_folder = null
|
||||
access = null
|
||||
|
||||
..()
|
||||
|
||||
/*
|
||||
* User Account Datum
|
||||
*/
|
||||
|
||||
/datum/mainframe2_user_data
|
||||
var/datum/computer/file/record/user_file = null
|
||||
var/datum/computer/folder/user_file_folder = null
|
||||
var/user_filename = null
|
||||
var/user_name = "GENERIC"
|
||||
var/user_id = null
|
||||
var/full_user = 0
|
||||
var/datum/computer/file/mainframe_program/current_prog = null
|
||||
|
||||
disposing()
|
||||
current_prog = null
|
||||
user_file = null
|
||||
user_file_folder = null
|
||||
|
||||
..()
|
||||
|
||||
proc/reload_user_file()
|
||||
if (!user_file_folder || !user_filename)
|
||||
return 0
|
||||
|
||||
for (var/datum/computer/file/record/potential in user_file_folder.contents)
|
||||
if (potential.name == user_filename)
|
||||
user_file = potential
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/datum/computer/file/document
|
||||
name = "Document"
|
||||
extension = "DOC"
|
||||
var/list/textlist = list() //Actual document text
|
||||
var/list/metalist = list() //Instructions on how to process each line.
|
||||
|
||||
disposing()
|
||||
textlist = null
|
||||
metalist = null
|
||||
|
||||
..()
|
||||
@@ -0,0 +1,754 @@
|
||||
#define ACCESSLOG_RECORDS_LIMIT 256
|
||||
#define DEFAULT_LOG_PATH "/var/log/door-access"
|
||||
#define MAINFRAME_ACCESSLOG_DRIVER_HACK
|
||||
|
||||
/datum/computer/file/record/accesslog_default_config
|
||||
name = "accesslog"
|
||||
New()
|
||||
..()
|
||||
fields = list("logdir" = DEFAULT_LOG_PATH)
|
||||
|
||||
/obj/machinery/networked/logreader
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
icon_state = "computer_generic"
|
||||
name = "door access logs"
|
||||
density = 1
|
||||
anchored = 1
|
||||
device_tag = "PNET_LOGREADER"
|
||||
timeout = 10
|
||||
mats = 14
|
||||
power_usage = 100
|
||||
var/static/list/required_fields = list("card_name", "door_name", "time_t", "timestamp", "door_id", "action")
|
||||
var/filter_name = null
|
||||
var/ftb_min = null
|
||||
var/ftb_sec = null
|
||||
var/fte_min = null
|
||||
var/fte_sec = null
|
||||
var/filter_door_id = null
|
||||
var/filter_action = null
|
||||
var/machine_screen = 1
|
||||
var/list/records = list()
|
||||
var/refreshing = 0
|
||||
var/refresh_id = 0
|
||||
var/timed_out = 0
|
||||
var/spoofed = 0
|
||||
|
||||
New()
|
||||
..()
|
||||
spawn(5)
|
||||
src.net_id = generate_net_id(src)
|
||||
|
||||
if(!src.link)
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/machinery/power/data_terminal/test_link = locate() in T
|
||||
if(test_link && !test_link.is_valid_master(test_link.master))
|
||||
src.link = test_link
|
||||
src.link.master = src
|
||||
|
||||
attack_hand(var/mob/user)
|
||||
if(..() || (stat & (NOPOWER|BROKEN)))
|
||||
return
|
||||
|
||||
user.machine = src
|
||||
|
||||
var/dat = {"<html><head><title>Access Log Reader</title><style>
|
||||
.conn-box {
|
||||
float: right;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
display: block;
|
||||
display: inline-block;
|
||||
border: 1px solid #888888;
|
||||
}
|
||||
|
||||
.conn-ok {
|
||||
background-color: #33FF00;
|
||||
}
|
||||
|
||||
.conn-no {
|
||||
background-color: #F80000;
|
||||
}
|
||||
|
||||
.conn-error {
|
||||
background-color: #888888;
|
||||
}
|
||||
|
||||
</style></head><body>"}
|
||||
|
||||
|
||||
var/readout_class = "conn-error"
|
||||
var/readout = "ERROR"
|
||||
if(src.host_id)
|
||||
readout_class = "conn-ok"
|
||||
readout = "OK CONNECTION"
|
||||
else
|
||||
readout_class = "conn-no"
|
||||
readout = "NO CONNECTION"
|
||||
|
||||
dat += "<div class='conn-box [readout_class]'></div>"
|
||||
if (!refreshing)
|
||||
if (machine_screen == 1)
|
||||
dat += "<b>Connection</b> | <a href='?src=\ref[src];screen=2'>Data</a>"
|
||||
else if (machine_screen == 2)
|
||||
dat += "<a href='?src=\ref[src];screen=1'>Connection</a> | <b>Data</b>"
|
||||
else if (!refreshing)
|
||||
dat += "<a href='?src=\ref[src];screen=1'>Connection</a> | <a href='?src=\ref[src];screen=2'>Data</a>"
|
||||
|
||||
|
||||
dat += "<hr><br>"
|
||||
|
||||
|
||||
if (machine_screen == 1)
|
||||
dat += "<b>Host Connection:</b>"
|
||||
dat += "<table border='1' class='[readout_class]'><tr><td><font color=white>[readout]</font></td></tr></table><br>"
|
||||
dat += "<a href='?src=\ref[src];reset=1'>Reset Connection</a><br>"
|
||||
|
||||
if (src.panel_open)
|
||||
dat += net_switch_html()
|
||||
|
||||
else if (machine_screen == 2)
|
||||
dat += "<h3>Door access logs</h3>"
|
||||
if (spoofed)
|
||||
dat += "<i>Warning: could not verify authenticity of displayed data.</i><br>"
|
||||
if (timed_out)
|
||||
dat += "<i>Warning: last request to refresh records timed out with no response.</i><br>"
|
||||
if (spoofed || timed_out)
|
||||
dat += "<br>"
|
||||
dat += "<b>Filters</b><br>"
|
||||
dat += "<b>Card name (partial):</b> <a href='?src=\ref[src];card_name=1'>[filter_name ? filter_name : "<not set>"]</a>[filter_name ? " <a href='?src=\ref[src];card_name_clear=1'>\[X\]</a>" : null]<br>"
|
||||
dat += "<b>Time interval:</b> "
|
||||
if (ftb_min != null && ftb_sec != null && fte_min != null && fte_sec != null)
|
||||
dat += "<a href='?src=\ref[src];time_begin_min=1'>[ftb_min]</a>:"
|
||||
dat += "<a href='?src=\ref[src];time_begin_sec=1'>[ftb_sec]</a> - "
|
||||
dat += "<a href='?src=\ref[src];time_end_min=1'>[fte_min]</a>:"
|
||||
dat += "<a href='?src=\ref[src];time_end_sec=1'>[fte_sec]</a> "
|
||||
dat += "<a href='?src=\ref[src];time_clear=1'>\[X\]</a>"
|
||||
else
|
||||
dat += "<a href='?src=\ref[src];time=1'><not set></a>"
|
||||
dat += "<br>"
|
||||
dat += "<b>Action:</b> <a href='?src=\ref[src];action=1'>[filter_action ? filter_action : "<not set>"]</a>[filter_action ? " <a href='?src=\ref[src];action_clear=1'>\[X\]</a>" : null]<br>"
|
||||
dat += "<b>Door net ID:</b> <a href='?src=\ref[src];door_id=1'>[filter_door_id ? filter_door_id : "<not set>"]</a>[filter_door_id ? " <a href='?src=\ref[src];door_id_clear=1'>\[X\]</a>" : null]<br>"
|
||||
dat += "<a href='?src=\ref[src];refresh=1'>Refresh records</a><br><br>"
|
||||
|
||||
dat += "<b>Record listing: </b><br>"
|
||||
if (!records.len)
|
||||
dat += "<i>No records currently loaded. Refresh the records to load data.</i><br>"
|
||||
else
|
||||
for (var/rec in records)
|
||||
dat += "[rec]<br>"
|
||||
else if (refreshing)
|
||||
dat += "<i>Refreshing data, please wait...</i>"
|
||||
|
||||
user << browse(dat,"window=net_logreader;size=545x302")
|
||||
onclose(user,"net_logreader")
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if (!(usr in range(1)))
|
||||
return
|
||||
|
||||
usr.machine = src
|
||||
src.add_fingerprint(usr)
|
||||
|
||||
if (href_list["reset"])
|
||||
if(last_reset && (last_reset + NETWORK_MACHINE_RESET_DELAY >= world.time))
|
||||
return
|
||||
|
||||
src.last_reset = world.time
|
||||
var/rem_host = src.host_id ? src.host_id : src.old_host_id
|
||||
src.host_id = null
|
||||
src.old_host_id = null
|
||||
src.post_status(rem_host, "command","term_disconnect")
|
||||
spawn(5)
|
||||
src.post_status(rem_host, "command","term_connect","device",src.device_tag)
|
||||
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
if (href_list["screen"])
|
||||
machine_screen = text2num(href_list["screen"])
|
||||
|
||||
if (href_list["card_name"])
|
||||
filter_name = input("Partial name of card holder", "Card holder name", filter_name) as text|null
|
||||
|
||||
if (href_list["card_name_clear"])
|
||||
filter_name = null
|
||||
|
||||
if (href_list["action"])
|
||||
filter_action = input("Door action", "Door action", filter_action) as null|anything in list("open","close","lock","unlock","reject")
|
||||
|
||||
if (href_list["action_clear"])
|
||||
filter_action = null
|
||||
|
||||
if (href_list["door_id"])
|
||||
filter_door_id = input("Net ID of door", "Door net ID", filter_door_id) as text|null
|
||||
|
||||
if (href_list["door_id_clear"])
|
||||
filter_door_id = null
|
||||
|
||||
if (href_list["time"])
|
||||
ftb_min = input("Filter start time: minutes", "Begin time minutes", 0) as num|null
|
||||
if (ftb_min == null)
|
||||
return
|
||||
ftb_sec = input("Filter start time: seconds", "Begin time seconds", 0) as num|null
|
||||
if (ftb_sec == null)
|
||||
ftb_min = null
|
||||
return
|
||||
fte_min = input("Filter end time: minutes", "End time minutes", 0) as num|null
|
||||
if (fte_min == null)
|
||||
ftb_min = null
|
||||
ftb_sec = null
|
||||
return
|
||||
fte_sec = input("Filter end time: seconds", "End time seconds", 0) as num|null
|
||||
if (fte_sec == null)
|
||||
ftb_min = null
|
||||
ftb_sec = null
|
||||
fte_min = null
|
||||
return
|
||||
|
||||
if (href_list["time_begin_min"])
|
||||
var/n_ftb_min = input("Filter start time: minutes", "Begin time minutes", ftb_min) as num|null
|
||||
if (n_ftb_min != null)
|
||||
ftb_min = n_ftb_min
|
||||
|
||||
if (href_list["time_begin_sec"])
|
||||
var/n_ftb_sec = input("Filter start time: seconds", "Begin time seconds", ftb_sec) as num|null
|
||||
if (n_ftb_sec != null)
|
||||
ftb_sec = n_ftb_sec
|
||||
|
||||
if (href_list["time_end_min"])
|
||||
var/n_fte_min = input("Filter end time: minutes", "End time minutes", fte_min) as num|null
|
||||
if (n_fte_min != null)
|
||||
fte_min = n_fte_min
|
||||
|
||||
if (href_list["time_end_sec"])
|
||||
var/n_fte_sec = input("Filter end time: seconds", "End time seconds", fte_sec) as num|null
|
||||
if (n_fte_sec != null)
|
||||
fte_sec = n_fte_sec
|
||||
|
||||
if (href_list["time_clear"])
|
||||
ftb_min = null
|
||||
ftb_sec = null
|
||||
fte_min = null
|
||||
fte_sec = null
|
||||
|
||||
if (href_list["refresh"])
|
||||
if (!src.host_id)
|
||||
return
|
||||
if (refreshing)
|
||||
return
|
||||
refreshing = 1
|
||||
refresh_id++
|
||||
var/my_refresh_id = refresh_id
|
||||
var/datum/signal/signal = get_free_signal()
|
||||
signal.source = src
|
||||
signal.transmission_method = TRANSMISSION_WIRE
|
||||
var/arguments = "-l 32 -f"
|
||||
if (ftb_min != null && ftb_sec != null && fte_min != null && fte_sec != null)
|
||||
var/st = ftb_min * 600 + ftb_sec * 10
|
||||
var/et = fte_min * 600 + fte_sec * 10
|
||||
arguments += " -t [st]:[et]"
|
||||
if (filter_action)
|
||||
arguments += " -m [filter_action]"
|
||||
if (filter_door_id)
|
||||
arguments += " -s [uppertext(ckey(filter_door_id))]"
|
||||
if (filter_name)
|
||||
arguments += " -- [bash_sanitize(filter_name)]"
|
||||
var/data = list2params(list("command"="record_query","query"="[arguments]"))
|
||||
src.post_status(src.host_id, "command", "term_message", "data", data, "netid", "[net_id]", "device", device_tag)
|
||||
spawn (300)
|
||||
if (refresh_id == my_refresh_id && refreshing)
|
||||
timed_out = 1
|
||||
refreshing = 0
|
||||
|
||||
attack_hand(usr)
|
||||
return
|
||||
|
||||
process()
|
||||
..()
|
||||
if(stat & NOPOWER)
|
||||
return
|
||||
use_power(100)
|
||||
|
||||
if(!host_id || !link)
|
||||
return
|
||||
|
||||
if(src.timeout == 0)
|
||||
src.post_status(host_id, "command","term_disconnect","data","timeout")
|
||||
src.host_id = null
|
||||
src.updateUsrDialog()
|
||||
src.timeout = initial(src.timeout)
|
||||
src.timeout_alert = 0
|
||||
else
|
||||
src.timeout--
|
||||
if(src.timeout <= 5 && !src.timeout_alert)
|
||||
src.timeout_alert = 1
|
||||
src.post_status(src.host_id, "command","term_ping","data","reply")
|
||||
|
||||
return
|
||||
|
||||
receive_signal(datum/signal/signal)
|
||||
if(stat & (NOPOWER) || !src.link)
|
||||
return
|
||||
if(!signal || !src.net_id || signal.encryption)
|
||||
return
|
||||
|
||||
var/target = signal.data["sender"] ? signal.data["sender"] : signal.data["netid"]
|
||||
if(!target)
|
||||
return
|
||||
|
||||
if(signal.data["target_device"] && signal.data["target_device"] != device_tag)
|
||||
return
|
||||
|
||||
//We care very deeply about address_1.
|
||||
if(lowertext(signal.data["address_1"]) != lowertext(src.net_id))
|
||||
if((signal.data["address_1"] == "ping") && ((signal.data["net"] == null) || ("[signal.data["net"]]" == "[src.net_number]")))
|
||||
spawn(5) //Send a reply for those curious jerks
|
||||
if (signal.transmission_method == TRANSMISSION_WIRE)
|
||||
src.post_status(target, "command", "ping_reply", "device", src.device_tag, "netid", src.net_id, "net", "[net_number]")
|
||||
// else ????
|
||||
return
|
||||
if (!signal.data["target_device"])
|
||||
return
|
||||
|
||||
var/sigcommand = lowertext(signal.data["command"])
|
||||
if(!sigcommand || !target)
|
||||
return
|
||||
|
||||
switch(sigcommand)
|
||||
if("term_connect") //Terminal interface stuff.
|
||||
if(target == src.host_id)
|
||||
src.host_id = null
|
||||
src.updateUsrDialog()
|
||||
spawn(3)
|
||||
src.post_status(target, "command","term_disconnect")
|
||||
return
|
||||
|
||||
if(src.host_id)
|
||||
return
|
||||
|
||||
src.timeout = initial(src.timeout)
|
||||
src.timeout_alert = 0
|
||||
src.host_id = target
|
||||
src.old_host_id = target
|
||||
if(signal.data["data"] != "noreply")
|
||||
src.post_status(target, "command","term_connect","data","noreply","device",src.device_tag)
|
||||
src.updateUsrDialog()
|
||||
spawn(2) //Sign up with the driver (if a mainframe contacted us)
|
||||
src.post_status(target,"command","term_message","data","command=register")
|
||||
return
|
||||
|
||||
if("term_message","term_file")
|
||||
if(target != src.host_id) //Huh, who is this?
|
||||
return
|
||||
var/data = signal.data["data"]
|
||||
if(!data || sigcommand == "term_message") // currently no action is taken without a file, so throw back term_message
|
||||
src.post_status(target,"command","term_message","data","command=status&status=failure")
|
||||
return
|
||||
|
||||
var/datum/computer/file/archive/archive = signal.data_file
|
||||
if (!istype(archive))
|
||||
src.post_status(target,"command","term_message","data","command=status&status=failure")
|
||||
return
|
||||
|
||||
records.len = 0
|
||||
for (var/datum/computer/file/record/R in archive.contained_files)
|
||||
var/bad = 0
|
||||
for (var/F in required_fields)
|
||||
if (!(F in R.fields))
|
||||
bad = 1
|
||||
break
|
||||
if (bad)
|
||||
continue
|
||||
records += accesslog_digest(R, 1)
|
||||
|
||||
if (data == "ack")
|
||||
spoofed = 0
|
||||
else
|
||||
spoofed = 1
|
||||
|
||||
timed_out = 0
|
||||
refreshing = 0
|
||||
|
||||
src.post_status(target,"command","term_message","data","command=status&status=success")
|
||||
for (var/mob/M in range(1))
|
||||
if (M.machine == src)
|
||||
attack_hand(M)
|
||||
return
|
||||
|
||||
if("term_ping")
|
||||
if(target != src.host_id)
|
||||
return
|
||||
if(signal.data["data"] == "reply")
|
||||
src.post_status(target, "command","term_ping")
|
||||
src.timeout = initial(src.timeout)
|
||||
src.timeout_alert = 0
|
||||
return
|
||||
|
||||
if("term_disconnect")
|
||||
if(target == src.host_id)
|
||||
src.host_id = null
|
||||
src.timeout = initial(src.timeout)
|
||||
src.timeout_alert = 0 //No need to be alerted about this anymore.
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
proc/accesslog_digest(var/datum/computer/file/record/R, formatted = 0)
|
||||
if (!istype(R))
|
||||
return "unknown type [R.name], possibly not a record"
|
||||
var/action = R.fields["action"]
|
||||
var/card_name = R.fields["card_name"]
|
||||
var/time_t = R.fields["time_t"]
|
||||
var/door_name = R.fields["door_name"]
|
||||
if (!action)
|
||||
return "corrupted record [R.name] missing action"
|
||||
if (!card_name)
|
||||
return "corrupted record [R.name] missing user ID"
|
||||
if (!time_t)
|
||||
return "corrupted record [R.name] missing human readable time"
|
||||
if (!door_name)
|
||||
return "corrupted record [R.name] missing door designated name"
|
||||
if (action != "reject")
|
||||
if (!formatted)
|
||||
return "[time_t] [card_name] [action]s [door_name]"
|
||||
else
|
||||
return "<b>[time_t]</b> [card_name] <b>[action]s</b> [door_name]"
|
||||
else
|
||||
if (!formatted)
|
||||
return "[time_t] [door_name] rejected entry for [card_name]"
|
||||
else
|
||||
return "<b>[time_t]</b> [door_name] <b>rejected entry for</b> [card_name]"
|
||||
|
||||
/datum/computer/file/mainframe_program/srv/accesslog
|
||||
name = "accesslog"
|
||||
size = 1
|
||||
var/static/nextlog = 1
|
||||
var/opt_data = null
|
||||
|
||||
receive_progsignal(var/sendid, var/list/data, var/datum/computer/file/file)
|
||||
. = ..()
|
||||
if (!.)
|
||||
if (data["command"] == DWAINE_COMMAND_REPLY)
|
||||
if (data["sender_tag"] == "getopt")
|
||||
opt_data = data["data"]
|
||||
return ESIG_USR4
|
||||
else
|
||||
return ESIG_GENERIC
|
||||
else if (data["command"] == DWAINE_COMMAND_MSG_TERM)
|
||||
message_user(data["data"])
|
||||
else
|
||||
return ESIG_GENERIC
|
||||
return ESIG_SUCCESS
|
||||
|
||||
proc/usage()
|
||||
message_user("Usage:")
|
||||
message_user("[name] -a -s DOOR_ID -m (open|close|lock|unlock|reject) -t TIME USER_ID")
|
||||
message_user("[name] -l COUNT \[-f\] \[-s DOOR_ID\] \[-m (open|close|lock|unlock|reject)\] \[-b TIME_START:TIME_END\] \[USER_ID_FRAGMENT \]")
|
||||
|
||||
proc/loglist(timestamp, action, door_id, card_name)
|
||||
var/list/ret = list()
|
||||
ret["action"] = action
|
||||
ret["door_id"] = door_id
|
||||
ret["card_name"] = card_name
|
||||
var/atom/door = locate("\[0x[door_id]\]")
|
||||
if (istype(door, /obj/machinery/door/airlock))
|
||||
ret["door_name"] = door.name
|
||||
else if (istype(door, /obj/machinery/networked))
|
||||
ret["door_name"] = "[door.name] (ALERT: network indicates this may not be door)"
|
||||
else
|
||||
ret["door_name"] = "Unknown device (0x[door_id])"
|
||||
var/time_n = istext(timestamp) ? text2num(timestamp) : timestamp
|
||||
ret["timestamp"] = time_n
|
||||
var/min = round(time_n / 600)
|
||||
var/sec = round(time_n / 10) - min * 60
|
||||
ret["time_t"] = "[min < 10 ? 0 : null][min]:[sec < 10 ? 0 : null][sec]"
|
||||
return ret
|
||||
|
||||
proc/message_reply_and_user(var/message)
|
||||
var/list/data = list("command"=DWAINE_COMMAND_REPLY, "data" = message, "sender_tag" = "accesslog")
|
||||
if (useracc)
|
||||
data["term"] = useracc.user_id
|
||||
var/sig = signal_program(parent_task.progid, data)
|
||||
if (sig != ESIG_USR4)
|
||||
message_user(message)
|
||||
|
||||
initialize(var/initparams)
|
||||
if (..())
|
||||
mainframe_prog_exit
|
||||
return
|
||||
|
||||
if (!initparams)
|
||||
usage()
|
||||
mainframe_prog_exit
|
||||
return
|
||||
|
||||
var/log_to = DEFAULT_LOG_PATH
|
||||
var/datum/computer/file/record/conf_file = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="/etc/accesslog"))
|
||||
if (istype(conf_file))
|
||||
if (conf_file.fields["logdir"])
|
||||
log_to = conf_file.fields["logdir"]
|
||||
if (chs(log_to, 1) != "/")
|
||||
log_to = "/log_to"
|
||||
|
||||
opt_data = null
|
||||
var/status = signal_program(1, list("command"=DWAINE_COMMAND_TSPAWN, "passusr" = 1, "path" = "/bin/getopt", "args" = "afl:m:s:t: [initparams]"))
|
||||
if (status == ESIG_NOTARGET)
|
||||
message_user("getopt: command not found")
|
||||
mainframe_prog_exit
|
||||
return
|
||||
if (!opt_data)
|
||||
message_user("accesslog: No response from getopt.")
|
||||
mainframe_prog_exit
|
||||
return
|
||||
if (copytext(opt_data, 1, 7) == "getopt")
|
||||
message_user(opt_data)
|
||||
mainframe_prog_exit
|
||||
return
|
||||
var/list/l = optparse(opt_data)
|
||||
if (!istype(l))
|
||||
message_user("accesslog: Error parsing options: [opt_data].")
|
||||
mainframe_prog_exit
|
||||
return
|
||||
var/list/opts = l[1]
|
||||
var/list/params = l[2]
|
||||
if (opts["a"] && opts["l"])
|
||||
usage()
|
||||
mainframe_prog_exit
|
||||
return
|
||||
|
||||
if (opts["a"])
|
||||
if (opts["s"] && opts["t"] && opts["m"] && params.len)
|
||||
if (!(opts["m"] in list("open","close","lock","unlock","reject")))
|
||||
message_user("")
|
||||
var/mylog = nextlog
|
||||
nextlog++
|
||||
|
||||
var/datum/computer/file/record/logfile = new()
|
||||
var/fname = "access[mylog]"
|
||||
logfile.name = fname
|
||||
if (useracc)
|
||||
logfile.metadata["owner"] = read_user_field("name")
|
||||
logfile.metadata["permissions"] = COMP_ROWNER | COMP_RGROUP
|
||||
logfile.fields = loglist(opts["t"], opts["m"], opts["s"], dd_list2text(params, " "))
|
||||
var/datum/computer/folder/logs_dir = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"=log_to))
|
||||
if (istype(logs_dir))
|
||||
var/idx = 0
|
||||
while (logs_dir.contents.len >= ACCESSLOG_RECORDS_LIMIT)
|
||||
idx++
|
||||
if (idx > logs_dir.contents.len)
|
||||
message_user("Could not make space for new entry.")
|
||||
mainframe_prog_exit
|
||||
return
|
||||
var/datum/computer/to_delete = logs_dir.contents[idx]
|
||||
if (istype(to_delete, /datum/computer/file/record))
|
||||
logs_dir.remove_file(to_delete)
|
||||
if (to_delete)
|
||||
qdel(to_delete)
|
||||
idx--
|
||||
var/result = signal_program(1, list("command"=DWAINE_COMMAND_FWRITE, "path"=log_to,"replace"=1,"mkdir"=1), logfile)
|
||||
if (result == ESIG_SUCCESS)
|
||||
message_user("Data recorded.")
|
||||
else
|
||||
message_user("File system error occurred while recording data.")
|
||||
else
|
||||
usage()
|
||||
mainframe_prog_exit
|
||||
return
|
||||
else if (opts["l"])
|
||||
var/time_begin = null
|
||||
var/time_end = null
|
||||
if (opts["t"])
|
||||
var/time_filter = opts["t"]
|
||||
var/list/tf_list = dd_text2list(time_filter, ":")
|
||||
if (tf_list.len != 2)
|
||||
message_user("Invalid timestamp filter format [time_filter], usage: TIMESTAMP_BEGIN:TIMESTAMP_END.")
|
||||
mainframe_prog_exit
|
||||
return
|
||||
time_begin = text2num(tf_list[1])
|
||||
time_end = text2num(tf_list[2])
|
||||
if (!isnum(time_begin) || !isnum(time_end))
|
||||
message_user("Invalid timestamp filter [time_filter].")
|
||||
mainframe_prog_exit
|
||||
return
|
||||
var/datum/computer/folder/logs_folder = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"=log_to))
|
||||
if (logs_folder == ESIG_NOFILE)
|
||||
message_user("No recorded data.")
|
||||
mainframe_prog_exit
|
||||
return
|
||||
if (!istype(logs_folder))
|
||||
message_user("Error: cannot access logs directory. Please check your permissions and try again.")
|
||||
mainframe_prog_exit
|
||||
return
|
||||
var/count = text2num(opts["l"])
|
||||
if (!count)
|
||||
message_user("Invalid count: [opts["l"]]")
|
||||
mainframe_prog_exit
|
||||
return
|
||||
if (count < 0)
|
||||
message_user("Listing the last [count] records (do you honestly expect this to break anything?).")
|
||||
mainframe_prog_exit
|
||||
return
|
||||
if (count > 32)
|
||||
count = 32
|
||||
message_user("Listing the last [count] records:")
|
||||
var/paramsearch = null
|
||||
if (params.len)
|
||||
paramsearch = dd_list2text(params, " ")
|
||||
var/list/records = logs_folder.contents.Copy()
|
||||
if (!records.len)
|
||||
message_user("No recorded data.")
|
||||
else
|
||||
var/printed = 0
|
||||
var/now = ticker.round_elapsed_ticks
|
||||
var/max = -1
|
||||
var/datum/computer/file/record/C = null
|
||||
for (var/Q in records)
|
||||
if (!istype(Q, /datum/computer/file/record))
|
||||
records -= Q
|
||||
continue
|
||||
var/datum/computer/file/record/R = Q
|
||||
if (!R.fields["door_id"] || !R.fields["timestamp"] || !R.fields["card_name"] || !R.fields["action"] || !R.fields["time_t"] || !R.fields["door_name"])
|
||||
records -= Q
|
||||
var/TS = R.fields["timestamp"]
|
||||
if (!TS)
|
||||
records -= Q
|
||||
continue
|
||||
if (!isnum(TS))
|
||||
TS = text2num(TS)
|
||||
R.fields["timestamp"] = TS
|
||||
if (TS < 0)
|
||||
records -= Q
|
||||
continue
|
||||
if (opts["t"])
|
||||
if (TS < time_begin || TS > time_end)
|
||||
records -= Q
|
||||
continue
|
||||
if (opts["s"])
|
||||
if (R.fields["door_id"] != opts["s"])
|
||||
records -= Q
|
||||
continue
|
||||
if (opts["m"])
|
||||
if (R.fields["action"] != opts["m"])
|
||||
records -= Q
|
||||
continue
|
||||
if (params.len)
|
||||
if (!findtext(R.fields["card_name"], paramsearch))
|
||||
records -= Q
|
||||
continue
|
||||
|
||||
var/list/printing = list()
|
||||
while (printed < count && records.len)
|
||||
max = -1
|
||||
for (var/datum/computer/file/record/R in records)
|
||||
var/TS = R.fields["timestamp"]
|
||||
if (!isnum(TS))
|
||||
TS = text2num(TS)
|
||||
R.fields["timestamp"] = TS
|
||||
if (R.fields["timestamp"] > max && R.fields["timestamp"] < now - 300)
|
||||
max = R.fields["timestamp"]
|
||||
C = R
|
||||
if (C)
|
||||
printing += C
|
||||
records -= C
|
||||
printed++
|
||||
else
|
||||
break
|
||||
|
||||
for (var/i = printing.len, i >= 1, i--)
|
||||
var/datum/computer/file/record/R = printing[i]
|
||||
if (opts["f"])
|
||||
message_reply_and_user("[log_to]/[R.name]")
|
||||
else
|
||||
message_reply_and_user(accesslog_digest(R))
|
||||
|
||||
mainframe_prog_exit
|
||||
return
|
||||
|
||||
/datum/computer/file/mainframe_program/driver/mountable/logreader
|
||||
name = "logreader"
|
||||
setup_processes = 1
|
||||
var/tmp/list/records = list()
|
||||
var/tmp/archive_path = null
|
||||
|
||||
initialize(var/initparams)
|
||||
if (..())
|
||||
return
|
||||
|
||||
signal_program(1, list("command"=DWAINE_COMMAND_MOUNT, "id"=src.name, "link"="logreader"))
|
||||
return
|
||||
|
||||
process()
|
||||
return
|
||||
|
||||
receive_progsignal(var/sendid, var/list/data, var/datum/computer/file/file)
|
||||
. = ..()
|
||||
if (!.)
|
||||
if (data["command"] == DWAINE_COMMAND_REPLY)
|
||||
if (data["sender_tag"] == "accesslog")
|
||||
records += data["data"]
|
||||
return ESIG_USR4
|
||||
else if (data["sender_tag"] == "tar")
|
||||
archive_path = data["data"]
|
||||
return ESIG_USR4
|
||||
else
|
||||
return ESIG_GENERIC
|
||||
else if (data["command"] == DWAINE_COMMAND_MSG_TERM)
|
||||
message_user(data["data"])
|
||||
else
|
||||
return ESIG_GENERIC
|
||||
return ESIG_SUCCESS
|
||||
|
||||
terminal_input(var/data, var/datum/computer/file/theFile)
|
||||
if (..() || !data)
|
||||
return 1
|
||||
|
||||
|
||||
var/list/dataList = params2list(data)
|
||||
if (!dataList || !dataList.len)
|
||||
return 1
|
||||
|
||||
|
||||
switch (lowertext(dataList["command"]))
|
||||
if ("record_query")
|
||||
records.len = 0
|
||||
var/datum/computer/file/mainframe_program/P = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="/sys/srv/accesslog"))
|
||||
if (istype(P))
|
||||
var/list/siglist = list("command"=DWAINE_COMMAND_TSPAWN, "passusr"=1, "path"="/sys/srv/accesslog", "args"=strip_html(dataList["query"]))
|
||||
signal_program(1, siglist)
|
||||
// see what i did here? heh? HEH?
|
||||
// doubly so, it almost sounds like tar gz
|
||||
var/targs = dd_list2text(records, " ")
|
||||
archive_path = null
|
||||
siglist = list("command"=DWAINE_COMMAND_TSPAWN, "passusr"=1, "path"="/bin/tar", "args"="-cqt -- [targs]")
|
||||
signal_program(1, siglist)
|
||||
if (!archive_path)
|
||||
return 1
|
||||
var/datum/computer/file/archive/archive = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[archive_path]"))
|
||||
if (!istype(archive))
|
||||
return 1
|
||||
message_device("ack", archive)
|
||||
//archive.dispose() // we don't need that tempfile anymore
|
||||
return 0
|
||||
|
||||
add_file(var/datum/computer/file/theFile)
|
||||
if (!initialized)
|
||||
return 0
|
||||
|
||||
if (istype(theFile, /datum/computer/file/archive))
|
||||
var/datum/computer/file/archive/R = theFile
|
||||
message_device("suppl", R)
|
||||
theFile.dispose()
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
change_metadata(var/datum/computer/file/file, var/field, var/newval)
|
||||
return 0
|
||||
|
||||
#undef DEFAULT_LOG_PATH
|
||||
#undef ACCESSLOG_RECORDS_LIMIT
|
||||
@@ -0,0 +1,949 @@
|
||||
|
||||
|
||||
/*
|
||||
* The Terminal Connection datum, used to keep track of, well, terminal connections.
|
||||
*/
|
||||
|
||||
/datum/terminal_connection
|
||||
var/obj/machinery/networked/master = null
|
||||
var/net_id = null //Network ID of connected device.
|
||||
var/term_type = null //Terminal type ID of connected device. i.e. PNET_MAINFRAME or HUI_TERMINAL
|
||||
|
||||
New(var/obj/machinery/networked/newmaster, var/new_id, var/newterm_type)
|
||||
..()
|
||||
if(istype(newmaster))
|
||||
src.master = newmaster
|
||||
|
||||
if(new_id)
|
||||
src.net_id = new_id
|
||||
|
||||
if(newterm_type)
|
||||
src.term_type = newterm_type
|
||||
return
|
||||
|
||||
disposing()
|
||||
master = null
|
||||
|
||||
..()
|
||||
|
||||
/*
|
||||
* The physical mainframe, communication through wired network.
|
||||
*/
|
||||
|
||||
/obj/machinery/networked/mainframe
|
||||
name = "Mainframe"
|
||||
desc = "A mainframe computer. It's pretty big!"
|
||||
density = 1
|
||||
anchored = 1
|
||||
icon_state = "dwaine"
|
||||
device_tag = "PNET_MAINFRAME"
|
||||
timeout = 30
|
||||
req_access = list(access_heads)
|
||||
var/list/terminals = list() //list of netIDs/terminal profiles of connected terminal devices.
|
||||
var/list/processing = list() //As the name implies, this is the list of programs that should be updated every process call on the mainframe object.
|
||||
var/list/timeout_list = list() //Terminals currently set to time out
|
||||
var/datum/computer/file/mainframe_program/os/os = null //Ref to current operating system program
|
||||
var/datum/computer/file/mainframe_program/os/bootstrap = null //Ref to bootloader program, instanciated when a main OS cannot be located on the memory card
|
||||
var/datum/computer/folder/runfolder = null //Storage folder for currently running programs.
|
||||
var/obj/item/disk/data/memcard/hd = null //Only internal storage for the mainframe--core memory, used as primary storage.
|
||||
|
||||
var/posted = 1 //Have we run through the POST sequence? Set to 1 initially so it doesn't freak out during map powernet generation.
|
||||
|
||||
var/setup_drive_size = 4096
|
||||
var/setup_drive_type = /obj/item/disk/data/memcard //Use this path for the hd
|
||||
var/setup_bootstrap_path = /datum/computer/file/mainframe_program/os/bootstrap //The bootstrapping system.
|
||||
var/setup_os_string = null
|
||||
power_usage = 500
|
||||
|
||||
zeta
|
||||
//setup_starting_os = /datum/computer/file/mainframe_program/os/main_os
|
||||
setup_drive_type = /obj/item/disk/data/memcard/main2
|
||||
|
||||
New()
|
||||
..()
|
||||
spawn(10)
|
||||
|
||||
src.net_id = generate_net_id(src)
|
||||
|
||||
if(!src.link)
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/machinery/power/data_terminal/test_link = locate() in T
|
||||
if(test_link && !test_link.is_valid_master(test_link.master))
|
||||
src.link = test_link
|
||||
src.link.master = src
|
||||
|
||||
if(!hd && (setup_drive_size > 0))
|
||||
if(src.setup_drive_type)
|
||||
src.hd = new src.setup_drive_type
|
||||
src.hd.set_loc(src)
|
||||
else
|
||||
src.hd = new /obj/item/disk/data/memcard(src)
|
||||
src.hd.file_amount = src.setup_drive_size
|
||||
|
||||
if(ispath(setup_bootstrap_path))
|
||||
src.bootstrap = new setup_bootstrap_path
|
||||
src.bootstrap.master = src
|
||||
|
||||
sleep(54)
|
||||
src.posted = 0
|
||||
src.post_system()
|
||||
|
||||
return
|
||||
|
||||
disposing()
|
||||
if (terminals)
|
||||
for (var/datum/conn in terminals)
|
||||
conn.dispose()
|
||||
|
||||
terminals.len = 0
|
||||
terminals = null
|
||||
|
||||
if (processing)
|
||||
processing.len = 0
|
||||
processing = null
|
||||
|
||||
if (timeout_list)
|
||||
timeout_list.len = 0
|
||||
timeout_list = null
|
||||
|
||||
if (os)
|
||||
os.dispose()
|
||||
os = null
|
||||
|
||||
if (bootstrap)
|
||||
bootstrap.dispose()
|
||||
bootstrap = null
|
||||
|
||||
if (runfolder)
|
||||
runfolder = null
|
||||
|
||||
if (hd)
|
||||
hd.dispose()
|
||||
hd = null
|
||||
|
||||
..()
|
||||
|
||||
attack_ai(mob/user as mob)
|
||||
return
|
||||
|
||||
attack_hand(mob/user as mob)
|
||||
if (user.stat || user.restrained())
|
||||
return
|
||||
|
||||
if(stat & BROKEN)
|
||||
if(!src.hd)
|
||||
return
|
||||
|
||||
boutput(user, "<span style=\"color:red\">The mainframe is trashed, but the memory core could probably salvaged.</span>")
|
||||
return
|
||||
|
||||
var/dat = "<html><head><title>Mainframe Access Panel</title></head><body><hr>"
|
||||
|
||||
dat += "<b>ACTIVE:</b> [src.os ? "YES" : "NO"]<br>"
|
||||
dat += "<b>BOOTING:</b> [(src.bootstrap && src.os && istype(src.os, src.bootstrap.type)) ? "YES" : "NO"]<br><br>"
|
||||
|
||||
if(stat & NOPOWER)
|
||||
|
||||
dat += "<b>Memory Core:</b> <a href='?src=\ref[src];core=1'>[src.hd ? "LOADED" : "---------"]</a><br>"
|
||||
dat += "Core Shield Maglock is <b>OFF</b><hr>[net_switch_html()]<hr>"
|
||||
else
|
||||
|
||||
dat += "<b>Memory Core:</b> [src.hd ? "LOADED" : "---------"]<br>"
|
||||
dat += "Core Shield Maglock is <b>ON</b><hr>"
|
||||
|
||||
|
||||
user << browse(dat, "window=mainframe;size=245x202")
|
||||
onclose(user, "mainframe")
|
||||
return
|
||||
|
||||
Topic(href, href_list)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
|
||||
if (istype(src.loc, /turf) && get_dist(src, usr) <= 1)
|
||||
if (usr.stat || usr.restrained())
|
||||
return
|
||||
|
||||
usr.machine = src
|
||||
|
||||
if(href_list["core"])
|
||||
|
||||
if(!(stat & NOPOWER))
|
||||
boutput(usr, "<span style=\"color:red\">The electromagnetic lock is still on!</span>")
|
||||
return
|
||||
|
||||
//Ai/cyborgs cannot physically remove a memory board from a room away.
|
||||
if(istype(usr,/mob/living/silicon) && get_dist(src, usr) > 1)
|
||||
boutput(usr, "<span style=\"color:red\">You cannot physically touch the board.</span>")
|
||||
return
|
||||
|
||||
if(src.hd)
|
||||
src.hd.set_loc(src.loc)
|
||||
boutput(usr, "You remove the memory core from the mainframe.")
|
||||
usr.unlock_medal("421", 1)
|
||||
stat |= MAINT
|
||||
src.unload_all()
|
||||
src.hd = null
|
||||
src.runfolder = null
|
||||
src.posted = 0
|
||||
|
||||
else
|
||||
var/obj/item/I = usr.equipped()
|
||||
if (istype(I, /obj/item/disk/data/memcard))
|
||||
usr.drop_item()
|
||||
I.set_loc(src)
|
||||
src.hd = I
|
||||
stat &= ~MAINT
|
||||
boutput(usr, "You insert [I].")
|
||||
|
||||
else if (href_list["dipsw"] && (stat & NOPOWER))
|
||||
var/switchNum = text2num(href_list["dipsw"])
|
||||
if (switchNum < 1 || switchNum > 8)
|
||||
return 1
|
||||
|
||||
switchNum = round(switchNum)
|
||||
if (net_number & switchNum)
|
||||
net_number &= ~switchNum
|
||||
else
|
||||
net_number |= switchNum
|
||||
|
||||
src.updateUsrDialog()
|
||||
src.add_fingerprint(usr)
|
||||
return
|
||||
|
||||
attackby(obj/item/W as obj, mob/user as mob)
|
||||
if (istype(W, /obj/item/crowbar))
|
||||
if (!(stat & BROKEN))
|
||||
return
|
||||
|
||||
if (!src.hd)
|
||||
boutput(usr, "<span style=\"color:red\">The memory core has already been removed.</span>")
|
||||
return
|
||||
|
||||
stat |= MAINT
|
||||
src.unload_all()
|
||||
src.hd.set_loc(src.loc)
|
||||
src.hd = null
|
||||
src.posted = 0
|
||||
|
||||
boutput(usr, "You pry out the memory core.")
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
else
|
||||
..()
|
||||
|
||||
return
|
||||
|
||||
|
||||
process()
|
||||
..()
|
||||
if(stat & (NOPOWER|BROKEN|MAINT) || !processing)
|
||||
return
|
||||
use_power(500)
|
||||
if(prob(3))
|
||||
spawn(1)
|
||||
playsound(src.loc, pick(ambience_computer), 50, 1)
|
||||
|
||||
for (var/progIndex = 1, progIndex <= src.processing.len, progIndex++)
|
||||
var/datum/computer/file/mainframe_program/prog = src.processing[progIndex]
|
||||
if (prog)
|
||||
if (prog.disposed)
|
||||
src.processing[progIndex] = null
|
||||
continue
|
||||
|
||||
prog.process()
|
||||
/*
|
||||
for(var/datum/computer/file/mainframe_program/P in src.processing)
|
||||
if (P)
|
||||
P.process()
|
||||
*/
|
||||
if(src.timeout == 0)
|
||||
src.timeout = initial(src.timeout)
|
||||
src.timeout_alert = 0
|
||||
for(var/timed in timeout_list)
|
||||
var/datum/terminal_connection/conn = src.terminals[timed]
|
||||
src.terminals -= timed
|
||||
if(src.os && conn)
|
||||
src.os.closed_connection(conn)
|
||||
//qdel(conn)
|
||||
if (conn)
|
||||
conn.dispose()
|
||||
else
|
||||
src.timeout--
|
||||
if(src.timeout <= 5 && !src.timeout_alert)
|
||||
src.timeout_alert = 1
|
||||
src.timeout_list = src.terminals.Copy()
|
||||
for(var/id in timeout_list)
|
||||
src.post_status(id, "command","term_ping","data","reply")
|
||||
|
||||
return
|
||||
|
||||
receive_signal(datum/signal/signal)
|
||||
if(stat & (NOPOWER|BROKEN|MAINT) || !src.link)
|
||||
return
|
||||
if(!signal || !src.net_id || signal.encryption)
|
||||
return
|
||||
|
||||
if(signal.transmission_method != TRANSMISSION_WIRE) //No radio for us thanks
|
||||
return
|
||||
|
||||
var/target = signal.data["sender"]
|
||||
|
||||
//They don't need to target us specifically to ping us.
|
||||
//Otherwise, if they aren't addressing us, ignore them
|
||||
if(signal.data["address_1"] != src.net_id)
|
||||
if((signal.data["address_1"] == "ping") && ((signal.data["net"] == null) || ("[signal.data["net"]]" == "[src.net_number]")) && signal.data["sender"])
|
||||
spawn(5) //Send a reply for those curious jerks
|
||||
src.post_status(target, "command", "ping_reply", "device", src.device_tag, "netid", src.net_id)
|
||||
|
||||
return
|
||||
|
||||
var/sigcommand = lowertext(signal.data["command"])
|
||||
if(!sigcommand || !signal.data["sender"])
|
||||
return
|
||||
|
||||
switch(sigcommand)
|
||||
if("term_connect") //Terminal interface stuff.
|
||||
if(target in src.terminals)
|
||||
//something might be wrong here, disconnect them!
|
||||
var/datum/terminal_connection/conn = src.terminals[target]
|
||||
src.terminals.Remove(target)
|
||||
if(src.os)
|
||||
src.os.closed_connection(conn)
|
||||
//qdel(conn)
|
||||
if (conn)
|
||||
conn.dispose()
|
||||
spawn(3)
|
||||
src.post_status(target, "command","term_disconnect")
|
||||
return
|
||||
|
||||
var/devtype = signal.data["device"]
|
||||
if(!devtype) return
|
||||
var/datum/terminal_connection/newconn = new /datum/terminal_connection(src, target, devtype)
|
||||
src.terminals[target] = newconn //Accept the connection!
|
||||
if(signal.data["data"] != "noreply")
|
||||
src.post_status(target, "command","term_connect","data","noreply")
|
||||
//also say hi.
|
||||
if(src.os)
|
||||
var/datum/computer/theFile = null
|
||||
if (signal.data_file)
|
||||
theFile = signal.data_file.copy_file()
|
||||
src.os.new_connection(newconn, theFile)
|
||||
//qdel(file)
|
||||
if (theFile)
|
||||
theFile.dispose()
|
||||
return
|
||||
|
||||
if("term_message","term_file")
|
||||
if(!(target in src.terminals)) //Huh, who is this?
|
||||
return
|
||||
|
||||
//src.visible_message("[src] beeps.")
|
||||
var/data = signal.data["data"]
|
||||
var/file = null
|
||||
if(signal.data_file)
|
||||
file = signal.data_file.copy_file()
|
||||
if(src.os && data)
|
||||
src.os.term_input(data, target, file)
|
||||
//qdel(file)
|
||||
|
||||
return
|
||||
|
||||
if ("term_break")
|
||||
if (!(target in src.terminals))
|
||||
return
|
||||
|
||||
if (src.os)
|
||||
src.os.term_input(1, target, null, 1)
|
||||
|
||||
if("term_ping")
|
||||
if(!(target in src.terminals))
|
||||
spawn(3) //Go away!!
|
||||
src.post_status(target, "command","term_disconnect")
|
||||
return
|
||||
if(target in src.timeout_list)
|
||||
src.timeout_list -= target
|
||||
if(signal.data["data"] == "reply")
|
||||
src.post_status(target, "command","term_ping")
|
||||
return
|
||||
|
||||
if("term_disconnect")
|
||||
if(target in src.terminals)
|
||||
var/datum/terminal_connection/conn = src.terminals[target]
|
||||
if(src.os)
|
||||
src.os.closed_connection(conn)
|
||||
src.terminals -= target
|
||||
//qdel(conn)
|
||||
if (conn)
|
||||
conn.dispose()
|
||||
|
||||
return
|
||||
|
||||
if("ping_reply")
|
||||
if(src.os)
|
||||
os.ping_reply(signal.data["netid"],signal.data["device"])
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
power_change()
|
||||
if(stat & BROKEN)
|
||||
icon_state = initial(src.icon_state)
|
||||
src.icon_state += "b"
|
||||
return
|
||||
|
||||
else if(powered())
|
||||
icon_state = initial(src.icon_state)
|
||||
stat &= ~NOPOWER
|
||||
src.post_system() //Will simply return if POSTed already.
|
||||
else
|
||||
spawn(rand(0, 15))
|
||||
icon_state = initial(src.icon_state)
|
||||
src.icon_state += "0"
|
||||
stat |= NOPOWER
|
||||
src.posted = 0
|
||||
src.os = null
|
||||
|
||||
clone()
|
||||
var/obj/machinery/networked/mainframe/cloneframe = ..()
|
||||
if (!cloneframe)
|
||||
return
|
||||
|
||||
cloneframe.setup_bootstrap_path = src.setup_bootstrap_path
|
||||
cloneframe.setup_os_string = src.setup_os_string
|
||||
if (src.hd)
|
||||
cloneframe.hd = src.hd.clone()
|
||||
|
||||
return cloneframe
|
||||
|
||||
meteorhit(var/obj/O as obj)
|
||||
if(stat & BROKEN)
|
||||
//dispose()
|
||||
src.dispose()
|
||||
set_broken()
|
||||
var/datum/effects/system/harmless_smoke_spread/smoke = new /datum/effects/system/harmless_smoke_spread()
|
||||
smoke.set_up(5, 0, src)
|
||||
smoke.start()
|
||||
return
|
||||
|
||||
ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
//dispose()
|
||||
src.dispose()
|
||||
return
|
||||
if(2.0)
|
||||
if (prob(50))
|
||||
set_broken()
|
||||
if(3.0)
|
||||
if (prob(25))
|
||||
set_broken()
|
||||
else
|
||||
return
|
||||
|
||||
blob_act(var/power)
|
||||
if (prob(power * 2.5))
|
||||
set_broken()
|
||||
src.density = 0
|
||||
|
||||
proc
|
||||
run_program(datum/computer/file/mainframe_program/program, var/datum/mainframe2_user_data/user, var/datum/computer/file/mainframe_program/caller, var/runparams)
|
||||
if(!hd || !program || (!program.holder && program.needs_holder))
|
||||
return 0
|
||||
|
||||
if(!runfolder)
|
||||
for (var/datum/computer/folder/F in src.hd.root.contents)
|
||||
if (F.name == "proc")
|
||||
runfolder = F
|
||||
runfolder.metadata["permission"] = COMP_HIDDEN
|
||||
break
|
||||
|
||||
if(!runfolder)
|
||||
runfolder = new /datum/computer/folder( )
|
||||
runfolder.name = "proc"
|
||||
runfolder.metadata["permission"] = COMP_HIDDEN
|
||||
if(!hd.root.add_file( runfolder ))
|
||||
//qdel(runfolder)
|
||||
runfolder.dispose()
|
||||
return 0
|
||||
if (!(program in src.processing))
|
||||
program = program.copy_file()
|
||||
if(!runfolder.add_file( program ))
|
||||
//qdel(program)
|
||||
program.dispose()
|
||||
return 0
|
||||
|
||||
if(program.master != src)
|
||||
program.master = src
|
||||
|
||||
if(istype(program, /datum/computer/file/mainframe_program/os))
|
||||
if (!src.os)
|
||||
src.os = program
|
||||
else
|
||||
//qdel(program)
|
||||
program.dispose()
|
||||
return 0
|
||||
|
||||
if(!(program in src.processing))
|
||||
if (src.os == program && src.processing.len)
|
||||
src.processing.len++
|
||||
for (var/x = src.processing.len, x > 0, x--)
|
||||
var/datum/computer/file/mainframe_program/P = src.processing[x]
|
||||
if (istype(P))
|
||||
P.progid = x+1
|
||||
if (src.processing.len == x)
|
||||
src.processing.len++
|
||||
src.processing[x+1] = P
|
||||
|
||||
src.processing[1] = src.os
|
||||
src.os.progid = 1
|
||||
|
||||
else
|
||||
var/success = 0
|
||||
for (var/x = 1, x <= src.processing.len, x++)
|
||||
if (!isnull(src.processing[x]))
|
||||
continue
|
||||
|
||||
src.processing[x] = program
|
||||
program.progid = x
|
||||
success = 1
|
||||
break
|
||||
|
||||
if (!success)
|
||||
src.processing += program
|
||||
program.progid = src.processing.len
|
||||
|
||||
if (user)
|
||||
program.useracc = user
|
||||
user.current_prog = program
|
||||
|
||||
if (caller)
|
||||
program.parent_task = caller
|
||||
|
||||
program.initialize(runparams)
|
||||
//program.initialized = 1
|
||||
return program
|
||||
|
||||
unload_program(datum/computer/file/mainframe_program/program)
|
||||
if(!program)
|
||||
return 0
|
||||
|
||||
if(program == src.os)
|
||||
return 0
|
||||
|
||||
if (src.processing[src.processing.len] == program)
|
||||
src.processing -= program
|
||||
else if (program.progid && program.progid <= src.processing.len)
|
||||
src.processing[program.progid] = null
|
||||
// if(src.active_program == program)
|
||||
// src.active_program = src.host_program
|
||||
program.initialized = 0
|
||||
program.unloaded()
|
||||
|
||||
if (program.holding_folder == src.runfolder)
|
||||
//qdel(program)
|
||||
program.dispose()
|
||||
|
||||
return 1
|
||||
|
||||
unload_all()
|
||||
src.os = null
|
||||
for(var/datum/computer/file/mainframe_program/M in src.processing)
|
||||
src.unload_program(M)
|
||||
|
||||
return
|
||||
|
||||
|
||||
delete_file(datum/computer/file/theFile)
|
||||
if((!theFile) || (!theFile.holder) || (theFile.holder.read_only))
|
||||
//boutput(world, "Cannot delete :(")
|
||||
return 0
|
||||
|
||||
//qdel(file)
|
||||
theFile.dispose()
|
||||
return 1
|
||||
|
||||
relay_progsignal(var/datum/computer/file/mainframe_program/caller, var/progid, var/list/data = null, var/datum/computer/file/file)
|
||||
if (progid < 1 || progid > src.processing.len || !caller)
|
||||
return ESIG_GENERIC
|
||||
|
||||
var/datum/computer/file/mainframe_program/P = src.processing[progid]
|
||||
if(!istype(P))
|
||||
return ESIG_GENERIC
|
||||
|
||||
var/callID = src.processing.Find(caller)
|
||||
return P.receive_progsignal(callID, data, file)
|
||||
|
||||
set_broken()
|
||||
icon_state = initial(src.icon_state)
|
||||
icon_state += "b"
|
||||
stat |= BROKEN
|
||||
|
||||
reconnect_all_devices()
|
||||
for (var/device_id in src.terminals)
|
||||
var/datum/terminal_connection/conn = src.terminals[device_id]
|
||||
if (istype(conn) && cmptext(conn.term_type, "hui_terminal"))
|
||||
continue
|
||||
|
||||
reconnect_device(device_id)
|
||||
|
||||
return ESIG_SUCCESS
|
||||
|
||||
reconnect_device(var/device_netid)
|
||||
if (!device_netid)
|
||||
return ESIG_GENERIC
|
||||
|
||||
device_netid = lowertext(device_netid)
|
||||
if (device_netid in src.terminals)
|
||||
var/datum/terminal_connection/conn = src.terminals[device_netid]
|
||||
if(src.os)
|
||||
src.os.closed_connection(conn)
|
||||
src.terminals -= device_netid
|
||||
//qdel(conn)
|
||||
if (conn)
|
||||
conn.dispose()
|
||||
|
||||
src.post_status(device_netid, "command", "term_connect", "device", src.device_tag)
|
||||
return ESIG_SUCCESS
|
||||
|
||||
/*
|
||||
* Overview of startup process:
|
||||
* If we already have an OS reference, initialize it and return.
|
||||
* If not, begin looking for an OS file in memory (Of type /datum/computer/file/mainframe_program/os)
|
||||
* Ideally, there is a folder named "sys" in the root directory to look in.
|
||||
* If we can't find the OS there, we pass control over the our bootstrapping program.
|
||||
*/
|
||||
|
||||
post_system()
|
||||
if(src.posted || !src.hd)
|
||||
return
|
||||
|
||||
src.posted = 1
|
||||
|
||||
if(src.os) //Let the starting programs set up vars or whatever
|
||||
src.os.initialize()
|
||||
|
||||
else
|
||||
|
||||
if (src.runfolder)
|
||||
//qdel(src.runfolder)
|
||||
src.runfolder.dispose()
|
||||
src.runfolder = null
|
||||
|
||||
if(src.hd && src.hd.root)
|
||||
var/datum/computer/folder/sysfolder = null
|
||||
for (var/datum/computer/folder/F in src.hd.root.contents)
|
||||
if (F.name == "sys")
|
||||
sysfolder = F
|
||||
break
|
||||
|
||||
if (sysfolder)
|
||||
var/datum/computer/file/mainframe_program/os/newos = locate(/datum/computer/file/mainframe_program/os) in sysfolder.contents
|
||||
if (istype(newos))
|
||||
src.visible_message("[src] beeps")
|
||||
newos.initialized = 0
|
||||
src.run_program(newos)
|
||||
return
|
||||
|
||||
if(!istype(src.bootstrap))
|
||||
src.bootstrap = new src.setup_bootstrap_path
|
||||
|
||||
//Run the bootstrapping code!
|
||||
if(bootstrap)
|
||||
src.run_program(bootstrap)
|
||||
|
||||
return
|
||||
|
||||
|
||||
/*
|
||||
* Bootstrapping System
|
||||
*/
|
||||
|
||||
/datum/computer/file/mainframe_program/os/bootstrap
|
||||
name = "NETBOOT"
|
||||
size = 4
|
||||
needs_holder = 0
|
||||
var/tmp/list/known_banks = list()
|
||||
var/tmp/current = null //Net ID of current bank.
|
||||
var/tmp/stage = 0
|
||||
var/tmp/ping_wait = 0
|
||||
var/tmp/stage_wait = 0
|
||||
var/tmp/rescan_wait = 0
|
||||
var/setup_system_directory = "/sys"
|
||||
var/setup_driver_directory = "/sys/drvr"
|
||||
var/setup_bin_directory = "/bin"
|
||||
|
||||
disposing()
|
||||
known_banks = null
|
||||
..()
|
||||
|
||||
initialize()
|
||||
if(..())
|
||||
return
|
||||
|
||||
src.known_banks.len = 0
|
||||
|
||||
src.clear_core()
|
||||
|
||||
src.find_existing_databanks()
|
||||
|
||||
src.stage_wait = 4
|
||||
src.stage = 1
|
||||
src.ping_wait = 4
|
||||
src.current = null
|
||||
spawn(1)
|
||||
src.master.post_status("ping","data","NETBOOT","net","[src.master.net_number]")
|
||||
return
|
||||
|
||||
process()
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(src.ping_wait)
|
||||
src.ping_wait--
|
||||
return
|
||||
|
||||
if(src.rescan_wait)
|
||||
if (--src.rescan_wait < 1)
|
||||
src.initialized = 0
|
||||
src.initialize()
|
||||
return
|
||||
|
||||
if(src.stage_wait)
|
||||
src.stage_wait--
|
||||
if(stage_wait <= 0)
|
||||
stage = 0
|
||||
|
||||
if(!stage)
|
||||
if(!known_banks.len)
|
||||
src.master.os = null
|
||||
src.handle_quit()
|
||||
//qdel (src)
|
||||
src.dispose()
|
||||
return
|
||||
|
||||
new_current()
|
||||
src.message_term("command=bootreq",current)
|
||||
return
|
||||
return
|
||||
|
||||
new_connection(datum/terminal_connection/conn)
|
||||
if(!istype(conn))
|
||||
return
|
||||
|
||||
if(conn.term_type == "PNET_DATA_BANK" && !(conn.net_id in known_banks) )
|
||||
known_banks += conn.net_id
|
||||
|
||||
return
|
||||
|
||||
closed_connection(datum/terminal_connection/conn)
|
||||
if(!istype(conn)) return
|
||||
var/del_netid = conn.net_id
|
||||
if(del_netid in src.known_banks)
|
||||
src.known_banks -= del_netid
|
||||
return
|
||||
|
||||
ping_reply(var/senderid,var/sendertype)
|
||||
if(..() || !ping_wait)
|
||||
return
|
||||
|
||||
if( !(senderid in master.terminals) && (sendertype == "PNET_DATA_BANK" || sendertype == "HUI_TERMINAL"))
|
||||
spawn(rand(1,4))
|
||||
src.master.post_status(senderid,"command","term_connect","device",master.device_tag)
|
||||
return
|
||||
|
||||
term_input(var/data, var/termid, var/datum/computer/file/the_file)
|
||||
if(..() || !stage)
|
||||
return
|
||||
|
||||
var/datum/terminal_connection/conn = master.terminals[termid]
|
||||
if(!conn || !conn.term_type)
|
||||
return
|
||||
var/device_type = conn.term_type
|
||||
if(device_type == "PNET_DATA_BANK")
|
||||
var/list/commandlist = params2list(data)
|
||||
if(!commandlist || !commandlist["command"])
|
||||
return
|
||||
var/command = lowertext(commandlist["command"])
|
||||
|
||||
//boutput(world, "\[[conn.net_id]]")
|
||||
|
||||
switch(command)
|
||||
if("register")
|
||||
return
|
||||
|
||||
if("file")
|
||||
//boutput(world, "FILE")
|
||||
if(!the_file)
|
||||
new_current()
|
||||
return
|
||||
|
||||
var/datum/computer/file/archive/arc = the_file.copy_file()
|
||||
if(!istype(arc))
|
||||
//qdel(arc)
|
||||
arc.dispose()
|
||||
new_current()
|
||||
return
|
||||
|
||||
var/datum/computer/file/mainframe_program/os/newos = locate() in arc.contained_files
|
||||
if(!istype(newos))
|
||||
//qdel(arc)
|
||||
arc.dispose()
|
||||
new_current()
|
||||
return
|
||||
|
||||
var/datum/computer/folder/sysdir = parse_directory(src.setup_system_directory, src.holder.root, 1)
|
||||
var/datum/computer/folder/drivedir = parse_directory(src.setup_driver_directory, src.holder.root, 1)
|
||||
var/datum/computer/folder/bindir = parse_directory(src.setup_bin_directory, src.holder.root, 1)
|
||||
var/datum/computer/folder/srvdir = parse_directory("srv", sysdir, 1)
|
||||
if(!sysdir || !drivedir || !bindir || !srvdir)
|
||||
master.visible_message("[master] boops")
|
||||
master.os = null
|
||||
src.handle_quit()
|
||||
//dispose()
|
||||
src.dispose()
|
||||
return
|
||||
|
||||
for(var/datum/computer/file/mainframe_program/MP in arc.contained_files)
|
||||
if (istype(MP, /datum/computer/file/mainframe_program/os))
|
||||
continue
|
||||
|
||||
var/datum/computer/file/mainframe_program/MP_copy = MP.copy_file()
|
||||
if (istype(MP_copy, /datum/computer/file/mainframe_program/driver))
|
||||
if(get_computer_datum(MP_copy.name, drivedir))
|
||||
continue
|
||||
if(!drivedir.add_file(MP_copy))
|
||||
//qdel(MP_copy)
|
||||
MP_copy.dispose()
|
||||
break
|
||||
|
||||
else if (istype(MP_copy, /datum/computer/file/mainframe_program/utility))
|
||||
if(get_computer_datum(MP_copy.name, bindir))
|
||||
continue
|
||||
if(!bindir.add_file(MP_copy))
|
||||
///qdel(MP_copy)
|
||||
MP_copy.dispose()
|
||||
break
|
||||
|
||||
else if (istype(MP_copy, /datum/computer/file/mainframe_program/srv))
|
||||
if(get_computer_datum(MP_copy.name, sysdir))
|
||||
continue
|
||||
|
||||
if(!srvdir.add_file(MP_copy))
|
||||
MP_copy.dispose()
|
||||
|
||||
else
|
||||
if(get_computer_datum(MP_copy.name, sysdir))
|
||||
continue
|
||||
if(!sysdir.add_file(MP_copy))
|
||||
//qdel(MP_copy)
|
||||
MP_copy.dispose()
|
||||
break
|
||||
|
||||
newos = newos.copy_file()
|
||||
if(sysdir.add_file(newos))
|
||||
master.os = null
|
||||
//qdel(arc)
|
||||
arc.dispose()
|
||||
master.visible_message("[master] beeps")
|
||||
master.run_program(newos)
|
||||
src.handle_quit()
|
||||
//dispose()
|
||||
src.dispose()
|
||||
return
|
||||
else
|
||||
//qdel(arc)
|
||||
//qdel(newos)
|
||||
if (arc)
|
||||
arc.dispose()
|
||||
if (newos)
|
||||
newos.dispose()
|
||||
/*
|
||||
src.quit()
|
||||
qdel(src)
|
||||
*/
|
||||
master.visible_message("[master] boops sadly.")
|
||||
src.rescan_wait = 20
|
||||
return
|
||||
|
||||
|
||||
if ("status")
|
||||
src.stage_wait = 1
|
||||
return
|
||||
|
||||
return
|
||||
|
||||
proc
|
||||
new_current() //Move on to a new current in the list.
|
||||
if(src.current)
|
||||
src.known_banks.Cut(1,2)
|
||||
src.current = null
|
||||
|
||||
if(!known_banks.len)
|
||||
/*
|
||||
src.master.os = null
|
||||
src.quit()
|
||||
qdel(src)
|
||||
*/
|
||||
src.rescan_wait = 20
|
||||
return
|
||||
|
||||
stage_wait = 4
|
||||
stage = 1
|
||||
src.current = known_banks[1]
|
||||
return
|
||||
|
||||
clear_core() //Clear the core memory board.
|
||||
if(!src.holder || !src.holder.root)
|
||||
return 0
|
||||
|
||||
for(var/datum/computer/C in src.holder.root)
|
||||
if(C == src || C == src.holding_folder)
|
||||
continue
|
||||
|
||||
//qdel(C)
|
||||
C.dispose()
|
||||
|
||||
return 1
|
||||
|
||||
find_existing_databanks() //Find databank connections already in master.terminals
|
||||
if(!src.master)
|
||||
return
|
||||
|
||||
for(var/x in master.terminals)
|
||||
var/datum/terminal_connection/conn = master.terminals[x]
|
||||
if(!istype(conn))
|
||||
continue
|
||||
|
||||
master.terminals -= x
|
||||
//qdel(conn)
|
||||
conn.dispose()
|
||||
|
||||
var/tempx = x
|
||||
spawn(rand(1,4))
|
||||
src.master.post_status(tempx, "command", "term_disconnect")
|
||||
|
||||
|
||||
return
|
||||
|
||||
|
||||
/*
|
||||
* A little mass message proc for some SPOOKY ANTICS
|
||||
*/
|
||||
|
||||
/proc/send_spooky_mainframe_message(var/the_message, var/a_spooky_custom_name)
|
||||
if (!the_message)
|
||||
return 1
|
||||
|
||||
for (var/obj/machinery/networked/mainframe/aMainframe in world)
|
||||
if (aMainframe.z != 1)
|
||||
continue
|
||||
|
||||
if (!aMainframe.os || !hascall(aMainframe.os, "message_all_users"))
|
||||
continue
|
||||
|
||||
aMainframe.os:message_all_users(the_message, a_spooky_custom_name, 1)
|
||||
return 0
|
||||
|
||||
return 2
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,969 @@
|
||||
//CONTENTS
|
||||
//User shell
|
||||
|
||||
|
||||
//User shell program
|
||||
//Allows execution of various mainframe programs, as well as some scripting and a set of built-in commands.
|
||||
/datum/computer/file/mainframe_program/shell
|
||||
name = "Msh"
|
||||
size = 8
|
||||
executable = 0
|
||||
var/tmp/piping = 0
|
||||
var/tmp/pipetemp = ""
|
||||
|
||||
var/tmp/scriptline = 0
|
||||
var/tmp/list/shscript
|
||||
var/tmp/list/scriptvars
|
||||
var/tmp/scriptstat = 0
|
||||
var/tmp/script_iteration = 1
|
||||
|
||||
var/tmp/list/stack = list()
|
||||
var/tmp/list/previous_shscripts
|
||||
var/tmp/list/previous_scriptline
|
||||
var/tmp/previous_pipeout
|
||||
var/tmp/suppress_out = 0
|
||||
|
||||
var/setup_helprec_name = "help"
|
||||
var/setup_max_piped_commands = 16
|
||||
|
||||
#define SCRIPT_IF_TRUE 1
|
||||
#define SCRIPT_IN_LOOP 2
|
||||
#define MAX_SCRIPT_ITERATIONS 2048
|
||||
#define MAX_STACK_DEPTH 128
|
||||
|
||||
#define EVAL_BOOL_TRUE 1
|
||||
#define EVAL_BOOL_FALSE 0
|
||||
#define ERR_STACK_OVER -1
|
||||
#define ERR_STACK_UNDER -2
|
||||
#define ERR_UNDEFINED -3
|
||||
|
||||
initialize()
|
||||
if(..() || !useracc)
|
||||
return
|
||||
|
||||
previous_pipeout = null
|
||||
|
||||
piping = 0
|
||||
suppress_out = 0
|
||||
pipetemp = ""
|
||||
scriptline = 0
|
||||
script_iteration = 1
|
||||
scriptstat = 0
|
||||
scriptvars = list()
|
||||
shscript = list()
|
||||
previous_shscripts = list()
|
||||
previous_scriptline = list()
|
||||
|
||||
if (useracc.user_file)
|
||||
if(!read_user_field("name"))
|
||||
write_user_field("name", useracc.user_name)
|
||||
useracc.user_file.fields["curpath"] = "/home/usr[read_user_field("name")]"
|
||||
|
||||
message_user("[read_user_field("name")]@DWAINE - [time2text(world.realtime, "hh:mm MM/DD/53")]|nType \"help\" for command listing.", "multiline")
|
||||
return
|
||||
|
||||
process()
|
||||
if (..() || !useracc)
|
||||
return
|
||||
|
||||
script_process()
|
||||
return
|
||||
|
||||
|
||||
input_text(var/text, var/scripting = 0)
|
||||
//boutput(world, "input_text([text], [scripting])")
|
||||
if(..() || !useracc || ((scripting != 0) != (scriptline != 0)))
|
||||
return 1
|
||||
|
||||
var/list/subcommands = list()
|
||||
var/list/piped_list = command2list(text, "^", scriptvars, subcommands)//scripting ? scriptvars : null)
|
||||
piped_list.len = min(piped_list.len, setup_max_piped_commands)
|
||||
piping = piped_list.len
|
||||
pipetemp = ""
|
||||
var/script_counter = 0
|
||||
|
||||
while(piped_list.len && (script_counter < MAX_SCRIPT_ITERATIONS))
|
||||
script_counter++
|
||||
text = piped_list[1]
|
||||
piped_list -= piped_list[1]
|
||||
piping--
|
||||
|
||||
var/subPlace = findtext(text, "_sub")
|
||||
|
||||
while (subPlace)
|
||||
|
||||
var/subIndex = text2num( copytext( text, subPlace+4, subPlace+5) )
|
||||
|
||||
if (isnum(subIndex) && subIndex > 0 && subIndex <= subcommands.len)
|
||||
|
||||
previous_pipeout = ""
|
||||
suppress_out = 1
|
||||
if (!input_text(subcommands[subIndex], 0))
|
||||
|
||||
if (dd_hassuffix(previous_pipeout, "|n"))
|
||||
previous_pipeout = copytext(previous_pipeout, 1, -2)
|
||||
|
||||
text = "[copytext(text, 1, subPlace)][previous_pipeout][copytext(text, subPlace+5)]"
|
||||
//boutput(world, " --> \"[text]\"")
|
||||
suppress_out = 0
|
||||
|
||||
|
||||
else
|
||||
suppress_out = 0
|
||||
return 1
|
||||
|
||||
subPlace = findtext(text, "_sub")
|
||||
|
||||
var/list/command_list = parse_string(text, (scripting ? src.scriptvars : null))
|
||||
var/command = lowertext(command_list[1])
|
||||
command_list.Cut(1,2) //Remove the command that we are now processing.
|
||||
while (!command && command_list.len)
|
||||
command = command_list[1]
|
||||
command_list.Cut(1,2)
|
||||
|
||||
var/current = read_user_field("curpath")
|
||||
|
||||
if (!dd_hassuffix(current, "/") && current != "/")
|
||||
current = "[current]/"
|
||||
|
||||
if (execpath("/bin/[command]", current, command, command_list, scripting ? script_iteration : 0))
|
||||
continue
|
||||
|
||||
else
|
||||
switch(execpath("[current][dd_hasprefix(command,"/") ? copytext(command, 1) : command]", current, command, command_list, scripting ? script_iteration : 0))
|
||||
if (1)
|
||||
continue
|
||||
if (2)
|
||||
if (script_iteration < 2)
|
||||
script_process()
|
||||
return 0
|
||||
if (3)
|
||||
message_user("Error: Stack overflow.")
|
||||
return 1
|
||||
|
||||
switch(lowertext(command))
|
||||
if ("eval")
|
||||
var/result = null
|
||||
var/pipe_result = (command_list.len == 1)
|
||||
|
||||
if (!command_list.len)
|
||||
continue
|
||||
|
||||
if (stack)
|
||||
stack.len = 0
|
||||
else
|
||||
stack = list()
|
||||
|
||||
switch (script_evaluate2(command_list, 0))
|
||||
if (0,1)
|
||||
if (stack.len)
|
||||
result = stack[stack.len]
|
||||
else
|
||||
result = 0
|
||||
|
||||
|
||||
if (ERR_STACK_OVER)
|
||||
message_user("Error: Stack overflow.")
|
||||
return 1
|
||||
|
||||
if (ERR_STACK_UNDER)
|
||||
message_user("Error: Stack underflow.")
|
||||
return 1
|
||||
|
||||
if (ERR_UNDEFINED)
|
||||
message_user("Error: Undefined result.")
|
||||
|
||||
return 1
|
||||
|
||||
if (piping && pipe_result)
|
||||
pipetemp = "[result]"
|
||||
|
||||
else if (!scripting && !isnull(result))
|
||||
message_user("[result]")
|
||||
|
||||
continue
|
||||
|
||||
if ("goonsay")
|
||||
var/anger_text = null
|
||||
if (pipetemp)
|
||||
anger_text = pipetemp
|
||||
|
||||
if(istype(command_list) && (command_list.len > 0))
|
||||
anger_text += dd_list2text(command_list, " ")
|
||||
|
||||
if (piping && piped_list.len && (ckey(piped_list[1]) != "break") )
|
||||
pipetemp = anger_text
|
||||
else
|
||||
if (!anger_text)
|
||||
anger_text = "A clown? On a space station? what|n"
|
||||
else if (!dd_hassuffix(anger_text, "|n"))
|
||||
anger_text += "|n"
|
||||
message_user("[anger_text] __________|n(--\[ .]-\[ .] /|n(_______0__)", "multiline")
|
||||
continue
|
||||
|
||||
|
||||
if ("echo")
|
||||
var/echo_text = null
|
||||
if (pipetemp)
|
||||
echo_text = pipetemp
|
||||
|
||||
if(istype(command_list) && (command_list.len > 0))
|
||||
echo_text += dd_list2text(command_list, " ")
|
||||
|
||||
if (piping && piped_list.len && (ckey(piped_list[1]) != "break") )
|
||||
pipetemp = echo_text
|
||||
else
|
||||
if (echo_text && !dd_hassuffix(echo_text, "|n"))
|
||||
echo_text += "|n"
|
||||
message_user(echo_text, "multiline")
|
||||
|
||||
continue
|
||||
|
||||
//User identification & communication commands
|
||||
|
||||
if ("who")
|
||||
var/whotext = null
|
||||
var/list/wholist = signal_program(1, list("command"=DWAINE_COMMAND_ULIST))
|
||||
|
||||
if (istype(wholist))
|
||||
for (var/uid in wholist)
|
||||
whotext += "[uid]-[wholist[uid]]|n"
|
||||
else
|
||||
whotext = "Error: Unable to determine current users."
|
||||
|
||||
if (piping)
|
||||
pipetemp = whotext
|
||||
else
|
||||
if (!whotext)
|
||||
whotext = "Error: Unable to determine current users."
|
||||
|
||||
message_user(whotext, "multiline")
|
||||
continue
|
||||
|
||||
if ("mesg")
|
||||
var/input = (command_list.len ? command_list[1] : null)
|
||||
if (pipetemp)
|
||||
input = pipetemp
|
||||
|
||||
if (piping)
|
||||
if (input)
|
||||
switch (lowertext(input))
|
||||
if ("y")
|
||||
if (write_user_field("accept_msg","1"))
|
||||
pipetemp = "Now allowing messages."
|
||||
else
|
||||
pipetemp = "Error: Unable to write user configuration."
|
||||
if ("n")
|
||||
if (write_user_field("accept_msg","0"))
|
||||
pipetemp = "Now disallowing messages."
|
||||
else
|
||||
pipetemp = "Error: Unable to write user configuration."
|
||||
else
|
||||
pipetemp = "Error: Invalid argument for mesg (Must be \"y\" or \"n\")"
|
||||
else
|
||||
pipetemp = "is [read_user_field("accept_msg") == "1" ? "y" : "n"]"
|
||||
else
|
||||
if (input)
|
||||
switch (lowertext(input))
|
||||
if ("y")
|
||||
if (write_user_field("accept_msg","1"))
|
||||
message_user("Now allowing messages.")
|
||||
else
|
||||
message_user("Error: Unable to write user configuration.")
|
||||
if ("n")
|
||||
if (write_user_field("accept_msg","0"))
|
||||
message_user("Now disallowing messages.")
|
||||
else
|
||||
message_user("Error: Unable to write user configuration.")
|
||||
else
|
||||
message_user("Error: Invalid argument for mesg (Must be \"y\" or \"n\")")
|
||||
else
|
||||
message_user("is [read_user_field("accept_msg") == "1" ? "y" : "n"]")
|
||||
|
||||
continue
|
||||
|
||||
if ("talk")
|
||||
if (pipetemp)
|
||||
|
||||
if(istype(command_list))
|
||||
command_list += dd_text2list(pipetemp, " ")
|
||||
|
||||
if (command_list.len < 2)
|
||||
message_user("Error: Insufficient arguments for Talk (Requires Target ID and Message).")
|
||||
return 1
|
||||
|
||||
var/targetUser = lowertext(command_list[1])
|
||||
command_list.Cut(1,2)
|
||||
|
||||
switch (signal_program(1, list("command"=DWAINE_COMMAND_UMSG, "term"=targetUser, data=dd_list2text(command_list, " "))))
|
||||
if (ESIG_SUCCESS)
|
||||
continue
|
||||
if (ESIG_NOTARGET)
|
||||
message_user("Error: Invalid Target ID")
|
||||
return 1
|
||||
if (ESIG_IOERR)
|
||||
if (piping)
|
||||
pipetemp = "Error: Message refused by Target."
|
||||
else
|
||||
message_user("Error: Message refused by Target.")
|
||||
continue
|
||||
else
|
||||
message_user("Error: Unexpected response from kernel.")
|
||||
return 1
|
||||
|
||||
continue
|
||||
|
||||
|
||||
//SCRIPTING COMMANDS FOLLOW:
|
||||
//If - Evaluate an expression. If true, set SCRIPT_IF_TRUE in scriptstat and continue piping
|
||||
//if false, unset SCRIPT_IF_TRUE and continue to the next line
|
||||
//if null (From an evaluation error or invalid input), halt the script
|
||||
if ("if")
|
||||
|
||||
if (!command_list.len)
|
||||
return 1
|
||||
|
||||
switch (script_evaluate2(command_list, 1))
|
||||
if (1)
|
||||
pipetemp = null
|
||||
scriptstat |= SCRIPT_IF_TRUE
|
||||
var/elsePosition = piped_list.Find("else")
|
||||
if (elsePosition)
|
||||
piped_list.Cut(elsePosition)
|
||||
piping = piped_list.len
|
||||
continue //Continue processing any piped commands following this.
|
||||
if (0)
|
||||
scriptstat &= ~SCRIPT_IF_TRUE
|
||||
|
||||
var/elsePosition = piped_list.Find("else")
|
||||
if (elsePosition)
|
||||
piped_list.Cut(1,elsePosition+1)
|
||||
piping = piped_list.len
|
||||
pipetemp = null
|
||||
continue
|
||||
|
||||
return 0 //Move to the next line of the script, dropping any following commands on this line.
|
||||
if (null)
|
||||
return 1
|
||||
|
||||
if ("else")
|
||||
|
||||
if (scriptstat & SCRIPT_IF_TRUE)
|
||||
return 0
|
||||
|
||||
continue
|
||||
|
||||
if ("while")
|
||||
if (!command_list.len || (scriptstat & SCRIPT_IN_LOOP))
|
||||
return 1
|
||||
|
||||
switch (script_evaluate2(command_list, 1))
|
||||
if (1)
|
||||
scriptstat |= SCRIPT_IN_LOOP
|
||||
continue
|
||||
if (0)
|
||||
scriptstat &= ~SCRIPT_IN_LOOP
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
|
||||
if ("break")
|
||||
return 1
|
||||
|
||||
if ("sleep")
|
||||
if (!command_list.len)
|
||||
continue
|
||||
|
||||
. = text2num(command_list[1])
|
||||
if (!isnum(.) || . < 0)
|
||||
continue
|
||||
|
||||
sleep ( max(0, min(., 30)) )
|
||||
continue
|
||||
|
||||
if ("help", "man")
|
||||
var/datum/computer/file/record/helpRec = signal_program(1, list("command"=DWAINE_COMMAND_CONFGET,"fname"=setup_helprec_name))
|
||||
if (istype(helpRec))
|
||||
var/target_entry = "index"
|
||||
if (command_list.len && ckey(command_list[1]))
|
||||
target_entry = lowertext(command_list[1])
|
||||
|
||||
if (target_entry in helpRec.fields)
|
||||
message_user("[capitalize(target_entry)]: [helpRec.fields[target_entry]]", "multiline")
|
||||
else
|
||||
message_user("Error: Unknown topic.")
|
||||
else
|
||||
message_user("Error: Help library missing or invalid.")
|
||||
|
||||
continue
|
||||
|
||||
if ("logout","logoff")
|
||||
message_user("Thank you for using DWAINE!", "clear")
|
||||
mainframe_prog_exit
|
||||
return 1
|
||||
|
||||
else
|
||||
if (pipetemp)
|
||||
var/prefixroot = dd_hasprefix(command, "/")
|
||||
if (!prefixroot)
|
||||
command = "[current]" + ((dd_hassuffix(current, "/") || current == "/") ? null : "/") + command
|
||||
|
||||
var/list/templist = dd_text2list(command, "/")
|
||||
if (!templist.len)
|
||||
message_user("Syntax error.")
|
||||
break
|
||||
|
||||
var/recname = null
|
||||
recname = copytext(templist[templist.len], 1, 16)
|
||||
while (dd_hasprefix(recname, " "))
|
||||
recname = copytext(recname, 2)
|
||||
templist.len--
|
||||
command = dd_list2text(templist, "/")
|
||||
if (!recname)
|
||||
recname = "out"
|
||||
|
||||
if ((prefixroot || !command) && !dd_hasprefix(command, "/"))
|
||||
command = "/[command]"
|
||||
|
||||
//boutput(world, "here is the path: \"[command]\" and the name \"[recname]\"")
|
||||
var/datum/computer/file/record/rec = new /datum/computer/file/record( )
|
||||
rec.fields = dd_text2list(pipetemp, "|n")
|
||||
rec.name = recname
|
||||
rec.metadata["owner"] = read_user_field("name")
|
||||
rec.metadata["permission"] = COMP_ALLACC
|
||||
|
||||
if (signal_program(1, list("command"=DWAINE_COMMAND_FWRITE,"path"=command, "append"=1), rec) != ESIG_SUCCESS)
|
||||
message_user("Unable to pipe stream to file.")
|
||||
//qdel(rec)
|
||||
rec.dispose()
|
||||
break
|
||||
|
||||
continue
|
||||
|
||||
|
||||
message_user("Syntax error.")
|
||||
return 1
|
||||
|
||||
//message_user("[dirpath]$ " + text)
|
||||
previous_pipeout += pipetemp
|
||||
return 0
|
||||
|
||||
proc
|
||||
execpath(var/fpath, var/current, var/command, var/list/command_list, var/scripting=0)
|
||||
//boutput(world, "execpath([fpath], [current], [command], ,[scripting])")
|
||||
var/datum/computer/file/record/exec = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"=fpath))
|
||||
if (istype(exec, /datum/computer/file/mainframe_program))
|
||||
var/list/siglist = list("command"=DWAINE_COMMAND_TSPAWN, "passusr"=1, "path"=fpath)//"[current][command]")
|
||||
if (command_list.len)
|
||||
siglist["args"] = strip_html(dd_list2text(command_list, " ")) + (pipetemp ? " [pipetemp]" : null)
|
||||
else if (pipetemp)
|
||||
siglist["args"] = pipetemp
|
||||
|
||||
pipetemp = ""
|
||||
signal_program(1, siglist)
|
||||
//qdel(siglist)
|
||||
return 1
|
||||
|
||||
else if (istype(exec) && (!pipetemp || scripting) && exec.fields && (exec.fields.len > 1) && dd_hasprefix(exec.fields[1], "#!")) //Maybe it's a shell script?
|
||||
if (previous_shscripts.len + 1 > MAX_SCRIPT_ITERATIONS)
|
||||
//script_iteration = 1
|
||||
previous_shscripts.len = 0
|
||||
return 3
|
||||
previous_scriptline.Insert(1, scriptline)
|
||||
scriptline = 1
|
||||
//script_iteration++
|
||||
//scriptstat = 0
|
||||
|
||||
if (shscript.len)
|
||||
previous_shscripts.Insert(1, 0)
|
||||
previous_shscripts[1] = shscript
|
||||
shscript = script_format( exec.fields.Copy() )
|
||||
//shscript.Insert(2, script_format( exec.fields.Copy() ))
|
||||
else
|
||||
//script_iteration = 1
|
||||
//scriptline = 1
|
||||
stack.len = 0
|
||||
shscript = script_format( exec.fields.Copy() )
|
||||
scriptvars["su"] = (read_user_field("group") == 0)
|
||||
|
||||
command_list.len = min(command_list.len, 8)
|
||||
|
||||
. = ""
|
||||
for (var/i = 1, i <= command_list.len, i++)
|
||||
scriptvars["arg[i-1]"] = command_list[i]
|
||||
. += "[. ? " " : null][command_list[i]]"
|
||||
|
||||
|
||||
scriptvars["*"] = .
|
||||
scriptvars["argc"] = command_list.len
|
||||
scriptvars["$"] = src.progid
|
||||
|
||||
return 2
|
||||
|
||||
return 0
|
||||
|
||||
script_process()
|
||||
spawn(0)
|
||||
while (shscript.len)
|
||||
|
||||
for (var/i = 1, i <= 5, i++)
|
||||
if (!shscript.len)
|
||||
if (previous_shscripts.len && istype(previous_shscripts[1], /list))
|
||||
shscript = previous_shscripts[1]
|
||||
previous_shscripts.Cut(1,2)
|
||||
scriptline = previous_scriptline[1]
|
||||
previous_scriptline.Cut(1,2)
|
||||
break
|
||||
|
||||
//Input_text should return 1 on an error, so break if we get that, I guess.
|
||||
if (src.input_text(shscript[1], script_iteration+1))
|
||||
message_user("Break at line [scriptline+1]")
|
||||
shscript.len = 0
|
||||
scriptline = 0
|
||||
script_iteration = 1
|
||||
return
|
||||
|
||||
if (scriptstat & SCRIPT_IN_LOOP)
|
||||
scriptstat &= ~SCRIPT_IN_LOOP //Turn this back off now
|
||||
continue
|
||||
|
||||
if (shscript.len)
|
||||
shscript.Cut(1, 2)
|
||||
scriptline++
|
||||
|
||||
scriptline *= (shscript.len > 0)
|
||||
sleep(10)
|
||||
return
|
||||
|
||||
script_format(var/list/scriptlist)
|
||||
if (!scriptlist || scriptlist.len < 2)
|
||||
return list()
|
||||
|
||||
//The first line should just be #!, so...
|
||||
scriptlist.Cut(1,2) //Don't need to copy the whole shebang, ha ha get it??
|
||||
|
||||
for (var/i = 1, i <= scriptlist.len, i++)
|
||||
//Check if it's a comment line...
|
||||
if (dd_hasprefix(trim_left(scriptlist[i]), "#"))
|
||||
scriptlist.Cut(i, i+1)
|
||||
i--
|
||||
continue
|
||||
scriptlist[i] = dd_replacetext(scriptlist[i], "|", "^")
|
||||
|
||||
return scriptlist
|
||||
|
||||
//Something something immersion something something 32-bit signed someting fixed point something.
|
||||
script_clampvalue(var/clampnum)
|
||||
//return round( min( max(text2num(clampnum), -2147483647), 2147483648) )
|
||||
return round( min( max(clampnum, -2147483647), 2147483648), 0.01 )
|
||||
|
||||
script_isNumResult(var/current, var/result)
|
||||
|
||||
if (isnum(text2num(current)) && isnum(text2num(result)))
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
script_evaluate2(var/list/command_stream, return_bool)
|
||||
|
||||
stack.len = 0
|
||||
while (command_stream && command_stream.len)
|
||||
var/current_command = command_stream[1]
|
||||
//boutput(world, "current_command = \[[current_command]]")
|
||||
command_stream.Cut(1,2)
|
||||
|
||||
if (text2num(current_command) != null)
|
||||
if (stack.len > MAX_STACK_DEPTH)
|
||||
return ERR_STACK_OVER
|
||||
|
||||
stack += script_clampvalue( text2num(current_command) )
|
||||
continue
|
||||
|
||||
var/result = null
|
||||
switch ( lowertext(current_command) )
|
||||
if ("+") //(1X 2X -- (1X + 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
result = stack[stack.len] + stack[stack.len-1]
|
||||
stack[--stack.len] = script_clampvalue( result )
|
||||
|
||||
else
|
||||
result = "[stack[stack.len-1] ][ stack[stack.len] ]"
|
||||
stack[--stack.len] = result
|
||||
|
||||
if ("-") //(1X 2X -- (1X - 2X)
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
result = stack[stack.len-1] - stack[stack.len]
|
||||
stack[--stack.len] = script_clampvalue( result )
|
||||
|
||||
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
|
||||
result = copytext(stack[stack.len-1], 1, max( length(stack[stack.len-1]) - stack[stack.len], 1) )
|
||||
stack[--stack.len] = result
|
||||
|
||||
else
|
||||
return ERR_UNDEFINED
|
||||
|
||||
if ("*") //(1X 2X -- (1X * 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
result = stack[stack.len-1] * stack[stack.len]
|
||||
stack[--stack.len] = script_clampvalue( result )
|
||||
|
||||
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
|
||||
result = ""
|
||||
var/repeatCount = stack[stack.len]
|
||||
while (repeatCount-- > 0)
|
||||
result += "[stack[stack.len-1]]"
|
||||
|
||||
stack[--stack.len] = copytext(result, 1, MAX_MESSAGE_LEN)
|
||||
|
||||
else
|
||||
return ERR_UNDEFINED
|
||||
|
||||
if ("/") //(1X 2X -- (1X / 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
if (stack[stack.len] == 0)
|
||||
return ERR_UNDEFINED
|
||||
|
||||
result = stack[stack.len-1] / stack[stack.len]
|
||||
stack[--stack.len] = script_clampvalue( result )
|
||||
|
||||
else if (istext(stack[stack.len]) && istext(stack[stack.len-1]))
|
||||
var/list/explodedString = dd_text2list("[stack[stack.len-1]]", "[stack[stack.len]]")
|
||||
if (explodedString.len + stack.len > MAX_STACK_DEPTH)
|
||||
return ERR_STACK_OVER
|
||||
|
||||
// reverselist is getting removed because it didnt actually do anything other than copy the list, if this line actually intended to reverse it, use reverse_list
|
||||
//explodedString = reverselist(explodedString)
|
||||
|
||||
stack.len -= 2
|
||||
stack += explodedString
|
||||
|
||||
else
|
||||
return ERR_UNDEFINED
|
||||
|
||||
if ("%")
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
if (stack[stack.len] == 0)
|
||||
return ERR_UNDEFINED
|
||||
|
||||
result = stack[stack.len-1] % stack[stack.len]
|
||||
stack[--stack.len] = script_clampvalue( result )
|
||||
|
||||
else
|
||||
return ERR_UNDEFINED
|
||||
|
||||
if ("eq") //(1X 2X -- (1X == 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
result = stack[stack.len-1] == stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
if ("ne") //(1X 2X -- (1X != 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
result = stack[stack.len-1] != stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
if ("gt") //(1X 2X -- (1X > 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
result = stack[stack.len-1] > stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
|
||||
result = length(stack[stack.len-1]) > stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
else if (isnum(stack[stack.len-1]) && istext(stack[stack.len]))
|
||||
result = stack[stack.len-1] > length(stack[stack.len])
|
||||
stack[--stack.len] = result
|
||||
|
||||
else
|
||||
result = length(stack[stack.len-1]) > length(stack[stack.len])
|
||||
stack[--stack.len] = result
|
||||
|
||||
if ("ge") //(1X 2X -- (1X >= 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
result = stack[stack.len-1] >= stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
|
||||
result = length(stack[stack.len-1]) >= stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
else if (isnum(stack[stack.len-1]) && istext(stack[stack.len]))
|
||||
result = stack[stack.len-1] >= length(stack[stack.len])
|
||||
stack[--stack.len] = result
|
||||
|
||||
else
|
||||
result = length(stack[stack.len-1]) >= length(stack[stack.len])
|
||||
stack[--stack.len] = result
|
||||
|
||||
if ("lt") //(1X 2X -- (1X < 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
result = stack[stack.len-1] < stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
|
||||
result = length(stack[stack.len-1]) < stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
else if (isnum(stack[stack.len-1]) && istext(stack[stack.len]))
|
||||
result = stack[stack.len-1] < length(stack[stack.len])
|
||||
stack[--stack.len] = result
|
||||
|
||||
else
|
||||
result = length(stack[stack.len-1]) < length(stack[stack.len])
|
||||
stack[--stack.len] = result
|
||||
|
||||
if ("le") //(1X 2X -- (1X <= 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
result = stack[stack.len-1] <= stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
|
||||
result = length(stack[stack.len-1]) <= stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
else if (isnum(stack[stack.len-1]) && istext(stack[stack.len]))
|
||||
result = stack[stack.len-1] <= length(stack[stack.len])
|
||||
stack[--stack.len] = result
|
||||
|
||||
else
|
||||
result = length(stack[stack.len-1]) <= length(stack[stack.len])
|
||||
stack[--stack.len] = result
|
||||
|
||||
if ("and") //(1X 2X -- (1X && 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
result = script_clampvalue( stack[stack.len] & stack[stack.len-1] )
|
||||
|
||||
else
|
||||
result = stack[stack.len] && stack[stack.len-1]
|
||||
|
||||
stack[--stack.len] = result
|
||||
|
||||
if ("or") //(1X 2X -- (1X || 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
result = script_clampvalue( stack[stack.len] | stack[stack.len-1] )
|
||||
|
||||
else
|
||||
result = stack[stack.len] || stack[stack.len-1]
|
||||
|
||||
stack[--stack.len] = result
|
||||
|
||||
if ("not","!") //(1X -- (!1X))
|
||||
if (!stack.len)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (isnum(stack[stack.len]))
|
||||
stack[stack.len] = ~stack[stack.len]
|
||||
|
||||
else
|
||||
stack[stack.len] = !stack[stack.len]
|
||||
|
||||
if ("xor","eor") //(1X 2X -- (1X ^ 2X))
|
||||
if (stack.len < 2)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
|
||||
result = stack[stack.len-1] ^ stack[stack.len]
|
||||
stack[--stack.len] = result
|
||||
|
||||
else
|
||||
return ERR_UNDEFINED
|
||||
|
||||
if ("dup")
|
||||
if (stack.len)
|
||||
stack.len++
|
||||
stack[stack.len] = stack[stack.len-1]
|
||||
|
||||
if ("'")
|
||||
var/newString
|
||||
while (command_stream.len)
|
||||
if (command_stream[1] == "\'" || command_stream[1] == "'")
|
||||
command_stream.Cut(1,2)
|
||||
break
|
||||
else if (dd_hassuffix(command_stream[1], "'"))
|
||||
if (newString)
|
||||
newString += " [copytext( command_stream[1],1,length(command_stream[1]-5) )]"
|
||||
|
||||
else
|
||||
newString = "[copytext( command_stream[1],1,length(command_stream[1]-5) )]"
|
||||
|
||||
command_stream.Cut(1,2)
|
||||
break
|
||||
|
||||
else
|
||||
if (newString)
|
||||
newString += " [command_stream[1]]"
|
||||
|
||||
else
|
||||
newString = "[command_stream[1]]"
|
||||
|
||||
command_stream.Cut(1,2)
|
||||
|
||||
if (newString)
|
||||
stack += newString
|
||||
|
||||
if ("d","e","f","x")
|
||||
if (!stack.len)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
. = stack[stack.len]
|
||||
if (!istext(.))
|
||||
return ERR_UNDEFINED
|
||||
|
||||
. = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[.]"))
|
||||
if (!istype(., /datum/computer))
|
||||
. = 0
|
||||
|
||||
else if (cmptext(current_command, "d"))
|
||||
. = istype(., /datum/computer/folder)
|
||||
|
||||
else if (cmptext(current_command, "x"))
|
||||
. = (istype(., /datum/computer/file/mainframe_program))// || (istype(., /datum/computer/file/record) && .:fields && .:fields[1] == "#!"))
|
||||
|
||||
else if (cmptext(current_command, "f"))
|
||||
. = istype(., /datum/computer/file)
|
||||
|
||||
else
|
||||
. = 1
|
||||
|
||||
|
||||
stack[stack.len] = .
|
||||
continue
|
||||
|
||||
if (":")
|
||||
//todo
|
||||
continue
|
||||
|
||||
if ("value", "to") //Define/Set a variable value.
|
||||
if (!stack.len)
|
||||
return ERR_STACK_UNDER
|
||||
|
||||
if (!command_stream.len)
|
||||
return ERR_UNDEFINED
|
||||
|
||||
var/valueName = lowertext(ckeyEx(command_stream[1]))
|
||||
if (!valueName)
|
||||
return ERR_UNDEFINED
|
||||
|
||||
scriptvars["[valueName]"] = stack[stack.len]
|
||||
stack.len--
|
||||
|
||||
else
|
||||
//boutput(world, "\[[lowertext(ckeyEx(current_command))]] in script vars?")
|
||||
if (lowertext(ckeyEx(current_command)) in scriptvars) //Lowertext(ckeyEx()) is equivalent to a ckey() that preserves underscores
|
||||
//boutput(world, "yes")
|
||||
result = scriptvars["[lowertext( ckeyEx(current_command) )]"]
|
||||
stack.len++
|
||||
stack[stack.len] = result
|
||||
|
||||
else if (istext(current_command))
|
||||
stack += "[current_command]"
|
||||
|
||||
//boutput(world, "STACK: [english_list(stack)]")
|
||||
if (return_bool)
|
||||
if (!stack.len)
|
||||
return EVAL_BOOL_FALSE
|
||||
return (stack[stack.len] ? EVAL_BOOL_TRUE : EVAL_BOOL_FALSE)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
receive_progsignal(var/sendid, var/list/data, var/datum/computer/file/theFile)
|
||||
if (..())
|
||||
return ESIG_GENERIC
|
||||
|
||||
if (!data["command"])
|
||||
return ESIG_GENERIC
|
||||
|
||||
switch (data["command"])
|
||||
if (DWAINE_COMMAND_MSG_TERM)
|
||||
if (piping)
|
||||
pipetemp += data["data"]
|
||||
else
|
||||
return message_user(data["data"], data["render"])
|
||||
|
||||
if (DWAINE_COMMAND_BREAK)
|
||||
if (shscript.len)
|
||||
message_user("Break at line [scriptline+1]")
|
||||
shscript.len = 0
|
||||
scriptline = 0
|
||||
script_iteration = 1
|
||||
return
|
||||
|
||||
|
||||
if (DWAINE_COMMAND_RECVFILE)
|
||||
//save to current dir.
|
||||
var/current_path = read_user_field("curpath")
|
||||
if (!current_path)
|
||||
return ESIG_GENERIC
|
||||
|
||||
if (!istype(theFile))
|
||||
return ESIG_NOFILE
|
||||
|
||||
return signal_program(1, list("command"=DWAINE_COMMAND_FWRITE, "path"=current_path,"replace"=1,"mkdir"=0), theFile)
|
||||
|
||||
return
|
||||
|
||||
message_user(var/msg, var/render=null)
|
||||
if (!useracc)
|
||||
return ESIG_NOTARGET
|
||||
|
||||
if (suppress_out)
|
||||
|
||||
if (dd_hassuffix(msg, "|n"))
|
||||
msg = copytext(msg, 1, -2)
|
||||
|
||||
previous_pipeout += dd_replacetext(msg, "|n", " ")
|
||||
|
||||
return ESIG_SUCCESS
|
||||
|
||||
previous_pipeout += msg
|
||||
if (render)
|
||||
return signal_program(parent_task.progid, list("command"=DWAINE_COMMAND_MSG_TERM, "data" = msg, "term" = useracc.user_id, "render" = render) )
|
||||
else
|
||||
return signal_program(parent_task.progid, list("command"=DWAINE_COMMAND_MSG_TERM, "data" = msg, "term" = useracc.user_id) )
|
||||
|
||||
|
||||
#undef SCRIPT_IF_TRUE
|
||||
#undef SCRIPT_IN_LOOP
|
||||
#undef MAX_SCRIPT_ITERATIONS
|
||||
#undef MAX_STACK_DEPTH
|
||||
#undef ERR_STACK_OVER
|
||||
#undef ERR_STACK_UNDER
|
||||
#undef ERR_UNDEFINED
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user