Initial Commit

This commit is contained in:
Tobba
2016-03-06 20:52:14 +01:00
commit b181d0b552
4325 changed files with 579453 additions and 0 deletions
+4
View File
@@ -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.
+1
View File
@@ -0,0 +1 @@
Official release of goonstation from 2016-03-04, based on revision 35cd644.
+8
View File
@@ -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
+601
View File
@@ -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"
*/
+353
View File
@@ -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
+241
View File
@@ -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
+943
View File
@@ -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
+114
View File
@@ -0,0 +1,114 @@
/turf/simulated/proc/find_group()
//Basically, join any nearby valid groups
// If more than one, pick one with most members at my borders
// If can not find any but there was an ungrouped at border with me, call for group assembly
var/turf/simulated/floor/north = get_step(src,NORTH)
var/turf/simulated/floor/south = get_step(src,SOUTH)
var/turf/simulated/floor/east = get_step(src,EAST)
var/turf/simulated/floor/west = get_step(src,WEST)
//Clear those we do not have access to
if(!CanPass(null, north, null, 1) || !istype(north))
north = null
if(!CanPass(null, south, null, 1) || !istype(south))
south = null
if(!CanPass(null, east, null, 1) || !istype(east))
east = null
if(!CanPass(null, west, null, 1) || !istype(west))
west = null
var/new_group_possible = 0
var/north_votes = 0
var/south_votes = 0
var/east_votes = 0
if(north)
if(north.parent)
north_votes = 1
if(south && (south.parent == north.parent))
north_votes++
south = null
if(east && (east.parent == north.parent))
north_votes++
east = null
if(west && (west.parent == north.parent))
north_votes++
west = null
else
new_group_possible = 1
if(south)
if(south.parent)
south_votes = 1
if(east && (east.parent == south.parent))
south_votes++
east = null
if(west && (west.parent == south.parent))
south_votes++
west = null
else
new_group_possible = 1
if(east)
if(east.parent)
east_votes = 1
if(west && (west.parent == east.parent))
east_votes++
west = null
else
new_group_possible = 1
// 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
+133
View File
@@ -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
+399
View File
@@ -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
+637
View File
@@ -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
+425
View File
@@ -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)
+499
View File
@@ -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()
+399
View File
@@ -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
+391
View File
@@ -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
+674
View File
@@ -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")
+34
View File
@@ -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]")
+225
View File
@@ -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
+532
View File
@@ -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? *****************
+250
View File
@@ -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()
..()
+629
View File
@@ -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
+196
View File
@@ -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
+164
View File
@@ -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)
+413
View File
@@ -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))
+152
View File
@@ -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
+650
View File
@@ -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, " ", "&nbsp;")
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, " ", "&nbsp;"), "\\\"", "\"")
pos = NQ + 1
state = NONE
var/list/el = dd_text2list(buf, " ")
var/list/ret = list()
for (var/s in el)
ret += dd_replacetext(s, "&nbsp;", " ")
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 ..()
+13
View File
@@ -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
+435
View File
@@ -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 ? "&nbsp;ACTIVE&nbsp;" : "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>&nbsp;ACTIVE&nbsp;</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
+212
View File
@@ -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
+91
View File
@@ -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)
+222
View File
@@ -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
+330
View File
@@ -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
+342
View File
@@ -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
+588
View File
@@ -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
*/
+416
View File
@@ -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))
+298
View File
@@ -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
+309
View File
@@ -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
+91
View File
@@ -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">&nbsp;</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 = "&nbsp;";
currentVal = "";
}
var i = 0
while (i++ < 4 && currentVal.length < 4)
{
if (t.length)
{
document.getElementById("readout").innerHTML += t.substr(0,1) + "&nbsp;";
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
+134
View File
@@ -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
+580
View File
@@ -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")
+770
View File
@@ -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
+83
View File
@@ -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
+736
View File
@@ -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
+171
View File
@@ -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")
+207
View File
@@ -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
+92
View File
@@ -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)
+256
View File
@@ -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")
+250
View File
@@ -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()
+275
View File
@@ -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)
+799
View File
@@ -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)
+657
View File
@@ -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
+104
View File
@@ -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
+120
View File
@@ -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)
+179
View File
@@ -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
+782
View File
@@ -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()
+291
View File
@@ -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
+317
View File
@@ -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
+291
View File
@@ -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
+213
View File
@@ -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 : "&lt;not set&gt;"]</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'>&lt;not set&gt;</a>"
dat += "<br>"
dat += "<b>Action:</b> <a href='?src=\ref[src];action=1'>[filter_action ? filter_action : "&lt;not set&gt;"]</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 : "&lt;not set&gt;"]</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 ("&#39;")
var/newString
while (command_stream.len)
if (command_stream[1] == "\'" || command_stream[1] == "&#39;")
command_stream.Cut(1,2)
break
else if (dd_hassuffix(command_stream[1], "&#39;"))
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