Merge pull request #2 from quotefox/master

update
This commit is contained in:
Chloe
2021-01-16 00:02:57 +00:00
committed by GitHub
77 changed files with 1329 additions and 666 deletions
+56 -48
View File
@@ -536,7 +536,6 @@
/obj/machinery/computer/security/telescreen/entertainment{
pixel_y = 32
},
/obj/machinery/vr_sleeper,
/turf/open/floor/plasteel,
/area/security/prison)
"abn" = (
@@ -3073,9 +3072,8 @@
/turf/open/floor/plasteel,
/area/security/prison)
"afQ" = (
/obj/machinery/vr_sleeper,
/turf/open/floor/plasteel,
/area/security/prison)
/turf/closed/mineral/random/low_chance,
/area/space)
"afR" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 1
@@ -4492,12 +4490,16 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/fitness/recreation)
"aiE" = (
/obj/machinery/vr_sleeper,
/obj/effect/turf_decal/tile/neutral{
dir = 8
/obj/structure/closet/crate{
name = "Asshole Containment"
},
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
/obj/item/banhammer,
/obj/item/toy/plush/mammal/winfre{
item_state = "Winfre";
name = "Winfre, Destroyer of Fun"
},
/turf/open/floor/plating/asteroid/airless,
/area/space)
"aiF" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
dir = 8
@@ -5602,9 +5604,16 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/fitness/recreation)
"akB" = (
/obj/machinery/vr_sleeper,
/turf/open/floor/plasteel,
/area/crew_quarters/fitness/recreation)
/obj/structure/cable{
icon_state = "1-2"
},
/obj/machinery/door/poddoor/preopen{
id = "engsm";
name = "radiation shutters"
},
/obj/item/tank/internals/plasma/full,
/turf/open/floor/plating,
/area/engine/supermatter)
"akC" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/holopad,
@@ -6384,7 +6393,6 @@
/turf/open/floor/plasteel/dark,
/area/crew_quarters/fitness/recreation)
"alS" = (
/obj/machinery/vr_sleeper,
/obj/effect/turf_decal/tile/neutral{
dir = 1
},
@@ -11113,7 +11121,7 @@
/turf/open/floor/plating,
/area/maintenance/port/fore)
"auE" = (
/obj/machinery/computer/gulag_teleporter_computer{
/obj/machinery/computer/prisoner/gulag_teleporter_computer{
dir = 1
},
/turf/open/floor/plasteel/dark,
@@ -62923,6 +62931,7 @@
/obj/structure/cable/yellow{
icon_state = "1-8"
},
/obj/machinery/bloodbankgen,
/turf/open/floor/plasteel/white,
/area/medical/chemistry)
"cqw" = (
@@ -68690,6 +68699,7 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
/obj/machinery/chem_dispenser,
/turf/open/floor/plasteel/white,
/area/medical/medbay/aft)
"cAR" = (
@@ -77051,11 +77061,10 @@
/turf/open/floor/plasteel/white,
/area/medical/virology)
"cQM" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/structure/cable/yellow{
icon_state = "0-8"
},
/turf/open/floor/plating,
/turf/closed/wall/r_wall,
/area/medical/virology)
"cQN" = (
/turf/closed/wall,
@@ -77850,7 +77859,6 @@
/turf/open/floor/plating/airless,
/area/medical/virology)
"cSr" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 9
},
@@ -77860,7 +77868,7 @@
/obj/structure/cable/yellow{
icon_state = "0-4"
},
/turf/open/floor/plating,
/turf/closed/wall/r_wall,
/area/medical/virology)
"cSs" = (
/obj/machinery/atmospherics/components/unary/tank/air{
@@ -105073,7 +105081,7 @@ abl
abE
acd
aax
afQ
aaR
aaR
aaR
aaI
@@ -119734,9 +119742,9 @@ acP
afz
agz
ahQ
aiE
aiE
akB
ahP
ahP
alO
alS
alS
aou
@@ -125922,7 +125930,7 @@ aCF
aDR
aFi
aGI
aIv
akB
aJB
aKP
aLY
@@ -138453,9 +138461,9 @@ aaa
aaa
aaa
aaa
aaa
aaa
aaa
afQ
afQ
afQ
aaa
aaa
aaa
@@ -138709,11 +138717,11 @@ aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
afQ
afQ
afQ
afQ
afQ
aaa
aaa
aaa
@@ -138965,13 +138973,13 @@ aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
afQ
afQ
afQ
aiE
afQ
afQ
afQ
aaa
aaa
aaa
@@ -139222,12 +139230,12 @@ aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
afQ
afQ
afQ
afQ
afQ
afQ
aaa
aaa
aaa
@@ -139480,10 +139488,10 @@ aaa
aaa
aaa
aaa
aaa
aaa
aaa
aaa
afQ
afQ
afQ
afQ
aaa
aaa
aaa
+1 -1
View File
@@ -23,7 +23,7 @@
"aw" = (/obj/structure/flora/bush,/turf/open/floor/holofloor/snow,/area/holodeck/rec_center/winterwonderland)
"ax" = (/obj/effect/holodeck_effect/mobspawner/penguin,/obj/effect/holodeck_effect/mobspawner/penguin,/obj/item/toy/snowball{pixel_y = 6},/obj/item/toy/snowball{pixel_x = 5},/obj/item/toy/snowball{pixel_x = -4},/turf/open/floor/holofloor/snow,/area/holodeck/rec_center/winterwonderland)
"ay" = (/obj/structure/table,/obj/machinery/recharger,/turf/open/floor/holofloor/asteroid,/area/holodeck/rec_center/bunker)
"az" = (/obj/structure/table/wood,/obj/item/storage/box/matches{pixel_x = -4; pixel_y = 8},/turf/open/floor/holofloor{icon_state = "wood"; dir = 9},/area/holodeck/rec_center/lounge)
"az" = (/obj/structure/table/wood,/turf/open/floor/holofloor{icon_state = "wood"; dir = 9},/area/holodeck/rec_center/lounge)
"aA" = (/obj/structure/chair/wood/normal,/turf/open/floor/holofloor{icon_state = "wood"; dir = 9},/area/holodeck/rec_center/lounge)
"aB" = (/obj/effect/holodeck_effect/mobspawner,/turf/open/floor/holofloor/plating,/area/holodeck/rec_center/wildlife)
"aC" = (/obj/effect/holodeck_effect/sparks,/turf/open/floor/holofloor/plating/burnmix,/area/holodeck/rec_center/burn)
+2
View File
@@ -70,6 +70,7 @@
#define ADMIN_PUNISHMENT_FIREBALL "Fireball"
#define ADMIN_PUNISHMENT_CLUWNE "Floor Cluwne"
#define ADMIN_PUNISHMENT_ROD "Immovable Rod"
#define ADMIN_PUNISHMENT_SUPPLYPOD_QUICK "Supply Pod (Quick)"
#define ADMIN_PUNISHMENT_SUPPLYPOD "Supply Pod"
#define ADMIN_PUNISHMENT_MAZING "Puzzle"
#define ADMIN_PUNISHMENT_PIE "Cream Pie"
@@ -93,3 +94,4 @@
#define MAX_KEYPRESS_AUTOKICK 100
///Length of held key rolling buffer
#define HELD_KEY_BUFFER_LENGTH 15
+3 -1
View File
@@ -11,6 +11,7 @@
#define STYLE_FRUIT 11
#define STYLE_INVISIBLE 12
#define STYLE_GONDOLA 13
#define STYLE_SEETHROUGH 14
#define POD_ICON_STATE 1
#define POD_NAME 2
@@ -29,5 +30,6 @@
list("honkpod", "\improper HONK pod", "A brightly-colored supply pod. It likely originated from the Clown Federation."),\
list("fruitpod", "\improper Orange", "An angry orange."),\
list("", "\improper S.T.E.A.L.T.H. pod MKVII", "A supply pod that, under normal circumstances, is completely invisible to conventional methods of detection. How are you even seeing this?"),\
list("gondolapod", "gondola", "The silent walker. This one seems to be part of a delivery agency.")\
list("gondolapod", "gondola", "The silent walker. This one seems to be part of a delivery agency."),\
list("", "", "")\
)
+2
View File
@@ -32,6 +32,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define TESLA_IGNORE_1 (1<<13) // TESLA_IGNORE grants immunity from being targeted by tesla-style electricity
#define INITIALIZED_1 (1<<14) //Whether /atom/Initialize() has already run for the object
#define ADMIN_SPAWNED_1 (1<<15) //was this spawned by an admin? used for stat tracking stuff.
#define PREVENT_CONTENTS_EXPLOSION_1 (1<<16) /// should not get harmed if this gets caught by an explosion?
//turf-only flags
#define NOJAUNT_1 (1<<0)
@@ -91,3 +92,4 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
// radiation
#define RAD_PROTECT_CONTENTS (1<<0)
#define RAD_NO_CONTAMINATE (1<<1)
+5
View File
@@ -478,6 +478,11 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define AREASELECT_CORNERA "corner A"
#define AREASELECT_CORNERB "corner B"
#define VARSET_FROM_LIST(L, V) if(L && L[#V]) V = L[#V]
#define VARSET_FROM_LIST_IF(L, V, C...) if(L && L[#V] && (C)) V = L[#V]
#define VARSET_TO_LIST(L, V) if(L) L[#V] = V
#define VARSET_TO_LIST_IF(L, V, C...) if(L && (C)) L[#V] = V
#define PREF_SAVELOAD_COOLDOWN 5
#define VOMIT_TOXIC 1
+6
View File
@@ -573,3 +573,9 @@
L1[key] += other_value
else
L1[key] = other_value
/proc/assoc_list_strip_value(list/input)
var/list/ret = list()
for(var/key in input)
ret += key
return ret
+1 -1
View File
@@ -510,7 +510,7 @@
var/jobtext = ""
if(ply.assigned_role)
jobtext = " the <b>[ply.assigned_role]</b>"
var/text = "<b>[ply.key]</b> was <b>[ply.name]</b>[jobtext] and"
var/text = "<b>[ply.hide_ckey ? "<b>[ply.name]</b>[jobtext] " : "[ply.key]</b> was <b>[ply.name]</b>[jobtext] and "]"
if(ply.current)
if(ply.current.stat == DEAD)
text += " <span class='redtext'>died</span>"
+205 -11
View File
@@ -1,27 +1,34 @@
SUBSYSTEM_DEF(research)
name = "Research"
priority = FIRE_PRIORITY_RESEARCH
wait = 10
init_order = INIT_ORDER_RESEARCH
//TECHWEB STATIC
var/list/techweb_nodes = list() //associative id = node datum
var/list/techweb_designs = list() //associative id = node datum
var/list/datum/techweb/techwebs = list()
var/datum/techweb/science/science_tech
var/datum/techweb/admin/admin_tech
var/datum/techweb_node/error_node/error_node //These two are what you get if a node/design is deleted and somehow still stored in a console.
var/datum/design/error_design/error_design
//ERROR LOGGING
var/list/invalid_design_ids = list() //associative id = number of times
var/list/invalid_node_ids = list() //associative id = number of times
var/list/invalid_node_boost = list() //associative id = error message
var/list/obj/machinery/rnd/server/servers = list()
var/datum/techweb/science/science_tech
var/datum/techweb/admin/admin_tech
var/list/techweb_nodes = list() //associative id = node datum
var/list/techweb_categories = list() //category name = list(node.id = node)
var/list/techweb_designs = list() //associative id = node datum
var/list/techweb_nodes_starting = list() //associative id = node datum
var/list/techweb_nodes_starting = list() //associative id = TRUE
var/list/techweb_categories = list() //category name = list(node.id = TRUE)
var/list/techweb_boost_items = list() //associative double-layer path = list(id = list(point_type = point_discount))
var/list/techweb_nodes_hidden = list() //Nodes that should be hidden by default.
var/list/techweb_nodes_hidden = list() //Node ids that should be hidden by default.
var/list/techweb_point_items = list( //path = list(point type = value)
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 2500),
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 5000), // Cit three more anomalys anomalys
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 7500),
/obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 10000),
// - Slime Extracts! -
// - Slime Extracts! -
/obj/item/slime_extract/grey = list(TECHWEB_POINT_TYPE_GENERIC = 500), // Adds in slime core deconing
/obj/item/slime_extract/metal = list(TECHWEB_POINT_TYPE_GENERIC = 750),
/obj/item/slime_extract/purple = list(TECHWEB_POINT_TYPE_GENERIC = 750),
@@ -294,6 +301,8 @@ SUBSYSTEM_DEF(research)
science_tech = new /datum/techweb/science
admin_tech = new /datum/techweb/admin
autosort_categories()
error_design = new
error_node = new
return ..()
/datum/controller/subsystem/research/fire()
@@ -330,6 +339,191 @@ SUBSYSTEM_DEF(research)
for(var/i in techweb_nodes)
var/datum/techweb_node/I = techweb_nodes[i]
if(techweb_categories[I.category])
techweb_categories[I.category][I.id] = I
techweb_categories[I.category][I.id] = TRUE
else
techweb_categories[I.category] = list(I.id = I)
techweb_categories[I.category] = list(I.id = TRUE)
/datum/controller/subsystem/research/proc/techweb_node_by_id(id)
return techweb_nodes[id] || error_node
/datum/controller/subsystem/research/proc/techweb_design_by_id(id)
return techweb_designs[id] || error_design
/datum/controller/subsystem/research/proc/on_design_deletion(datum/design/D)
for(var/i in techweb_nodes)
var/datum/techweb_node/TN = techwebs[i]
TN.on_design_deletion(TN)
for(var/i in techwebs)
var/datum/techweb/T = i
T.recalculate_nodes(TRUE)
/datum/controller/subsystem/research/proc/on_node_deletion(datum/techweb_node/TN)
for(var/i in techweb_nodes)
var/datum/techweb_node/TN2 = techwebs[i]
TN2.on_node_deletion(TN)
for(var/i in techwebs)
var/datum/techweb/T = i
T.recalculate_nodes(TRUE)
/datum/controller/subsystem/research/proc/initialize_all_techweb_nodes(clearall = FALSE)
if(islist(techweb_nodes) && clearall)
QDEL_LIST(techweb_nodes)
if(islist(techweb_nodes_starting && clearall))
techweb_nodes_starting.Cut()
var/list/returned = list()
for(var/path in subtypesof(/datum/techweb_node))
var/datum/techweb_node/TN = path
if(isnull(initial(TN.id)))
continue
TN = new path
if(returned[initial(TN.id)])
stack_trace("WARNING: Techweb node ID clash with ID [initial(TN.id)] detected! Path: [path]")
errored_datums[TN] = initial(TN.id)
continue
returned[initial(TN.id)] = TN
if(TN.starting_node)
techweb_nodes_starting[TN.id] = TRUE
for(var/id in techweb_nodes)
var/datum/techweb_node/TN = techweb_nodes[id]
TN.Initialize()
techweb_nodes = returned
if (!verify_techweb_nodes()) //Verify all nodes have ids and such.
stack_trace("Invalid techweb nodes detected")
calculate_techweb_nodes()
calculate_techweb_boost_list()
if (!verify_techweb_nodes()) //Verify nodes and designs have been crosslinked properly.
CRASH("Invalid techweb nodes detected")
/datum/controller/subsystem/research/proc/initialize_all_techweb_designs(clearall = FALSE)
if(islist(techweb_designs) && clearall)
QDEL_LIST(techweb_designs)
var/list/returned = list()
for(var/path in subtypesof(/datum/design))
var/datum/design/DN = path
if(isnull(initial(DN.id)))
stack_trace("WARNING: Design with null ID detected. Build path: [initial(DN.build_path)]")
continue
else if(initial(DN.id) == DESIGN_ID_IGNORE)
continue
DN = new path
if(returned[initial(DN.id)])
stack_trace("WARNING: Design ID clash with ID [initial(DN.id)] detected! Path: [path]")
errored_datums[DN] = initial(DN.id)
continue
returned[initial(DN.id)] = DN
techweb_designs = returned
verify_techweb_designs()
/datum/controller/subsystem/research/proc/verify_techweb_nodes()
. = TRUE
for(var/n in techweb_nodes)
var/datum/techweb_node/N = techweb_nodes[n]
if(!istype(N))
WARNING("Invalid research node with ID [n] detected and removed.")
techweb_nodes -= n
research_node_id_error(n)
. = FALSE
for(var/p in N.prereq_ids)
var/datum/techweb_node/P = techweb_nodes[p]
if(!istype(P))
WARNING("Invalid research prerequisite node with ID [p] detected in node [N.display_name]\[[N.id]\] removed.")
N.prereq_ids -= p
research_node_id_error(p)
. = FALSE
for(var/d in N.design_ids)
var/datum/design/D = techweb_designs[d]
if(!istype(D))
WARNING("Invalid research design with ID [d] detected in node [N.display_name]\[[N.id]\] removed.")
N.design_ids -= d
design_id_error(d)
. = FALSE
for(var/u in N.unlock_ids)
var/datum/techweb_node/U = techweb_nodes[u]
if(!istype(U))
WARNING("Invalid research unlock node with ID [u] detected in node [N.display_name]\[[N.id]\] removed.")
N.unlock_ids -= u
research_node_id_error(u)
. = FALSE
for(var/p in N.boost_item_paths)
if(!ispath(p))
N.boost_item_paths -= p
WARNING("[p] is not a valid path.")
node_boost_error(N.id, "[p] is not a valid path.")
. = FALSE
var/list/points = N.boost_item_paths[p]
if(islist(points))
for(var/i in points)
if(!isnum(points[i]))
WARNING("[points[i]] is not a valid number.")
node_boost_error(N.id, "[points[i]] is not a valid number.")
. = FALSE
else if(!point_types[i])
WARNING("[i] is not a valid point type.")
node_boost_error(N.id, "[i] is not a valid point type.")
. = FALSE
else if(!isnull(points))
N.boost_item_paths -= p
node_boost_error(N.id, "No valid list.")
WARNING("No valid list.")
. = FALSE
CHECK_TICK
/datum/controller/subsystem/research/proc/verify_techweb_designs()
for(var/d in techweb_designs)
var/datum/design/D = techweb_designs[d]
if(!istype(D))
stack_trace("WARNING: Invalid research design with ID [d] detected and removed.")
techweb_designs -= d
CHECK_TICK
/datum/controller/subsystem/research/proc/research_node_id_error(id)
if(invalid_node_ids[id])
invalid_node_ids[id]++
else
invalid_node_ids[id] = 1
/datum/controller/subsystem/research/proc/design_id_error(id)
if(invalid_design_ids[id])
invalid_design_ids[id]++
else
invalid_design_ids[id] = 1
/datum/controller/subsystem/research/proc/calculate_techweb_nodes()
for(var/design_id in techweb_designs)
var/datum/design/D = techweb_designs[design_id]
D.unlocked_by.Cut()
for(var/node_id in techweb_nodes)
var/datum/techweb_node/node = techweb_nodes[node_id]
node.unlock_ids = list()
for(var/i in node.design_ids)
var/datum/design/D = techweb_designs[i]
node.design_ids[i] = TRUE
D.unlocked_by += node.id
if(node.hidden)
techweb_nodes_hidden[node.id] = TRUE
CHECK_TICK
generate_techweb_unlock_linking()
/datum/controller/subsystem/research/proc/generate_techweb_unlock_linking()
for(var/node_id in techweb_nodes) //Clear all unlock links to avoid duplication.
var/datum/techweb_node/node = techweb_nodes[node_id]
node.unlock_ids = list()
for(var/node_id in techweb_nodes)
var/datum/techweb_node/node = techweb_nodes[node_id]
for(var/prereq_id in node.prereq_ids)
var/datum/techweb_node/prereq_node = techweb_node_by_id(prereq_id)
prereq_node.unlock_ids[node.id] = node
/datum/controller/subsystem/research/proc/calculate_techweb_boost_list(clearall = FALSE)
if(clearall)
techweb_boost_items = list()
for(var/node_id in techweb_nodes)
var/datum/techweb_node/node = techweb_nodes[node_id]
for(var/path in node.boost_item_paths)
if(!ispath(path))
continue
if(length(techweb_boost_items[path]))
techweb_boost_items[path][node.id] = node.boost_item_paths[path]
else
techweb_boost_items[path] = list(node.id = node.boost_item_paths[path])
CHECK_TICK
+1 -1
View File
@@ -198,7 +198,7 @@ GLOBAL_LIST_EMPTY(explosions)
var/list/items = list()
for(var/I in T)
var/atom/A = I
if (!A.prevent_content_explosion()) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't.
if (!(A.flags_1 & PREVENT_CONTENTS_EXPLOSION_1)) //The atom/contents_explosion() proc returns null if the contents ex_acting has been handled by the atom, and TRUE if it hasn't.
items += A.GetAllContents()
for(var/O in items)
var/atom/A = O
+5
View File
@@ -41,6 +41,8 @@
var/special_role
var/list/restricted_roles = list()
var/hide_ckey = FALSE
var/list/datum/objective/objectives = list()
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
@@ -134,6 +136,8 @@
L.canbearoused = L.client.prefs.arousable //Technically this should make taking over a character mean the body gain the new minds setting...
L.update_arousal_hud() //Removes the old icon
hide_ckey = current.client?.prefs?.hide_ckey
/datum/mind/proc/store_memory(new_text)
if((length_char(memory) + length_char(new_text)) <= MAX_MESSAGE_LEN)
memory += "[new_text]<BR>"
@@ -853,6 +857,7 @@
if(!mind.name)
mind.name = real_name
mind.current = src
mind.hide_ckey = client?.prefs?.hide_ckey
/mob/living/carbon/mind_initialize()
..()
+1 -3
View File
@@ -345,9 +345,6 @@
to_chat(user, "<span class='warning'>You can't move while buckled to [src]!</span>")
return
/atom/proc/prevent_content_explosion()
return FALSE
/atom/proc/contents_explosion(severity, target)
return //For handling the effects of explosions on contents that would not normally be effected
@@ -875,3 +872,4 @@ Proc for attack log creation, because really why not
/atom/proc/intercept_zImpact(atom/movable/AM, levels = 1)
. |= SEND_SIGNAL(src, COMSIG_ATOM_INTERCEPT_Z_FALL, AM, levels)
@@ -17,7 +17,7 @@
antag_flag = ROLE_BLOODSUCKER
false_report_weight = 1
restricted_jobs = list("AI","Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
protected_jobs = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_players = 20
required_enemies = 2
recommended_enemies = 4
+1 -1
View File
@@ -11,7 +11,7 @@
var/list/no_hunter_jobs = list("AI","Cyborg")
// Set Restricted Jobs
if(CONFIG_GET(flag/protect_roles_from_antagonist))
no_hunter_jobs += list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
no_hunter_jobs += list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
no_hunter_jobs += "Assistant"
// Find Valid Hunters
+1 -1
View File
@@ -6,7 +6,7 @@
name = "traitor+brothers"
config_tag = "traitorbro"
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Research Director")
protected_jobs = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Quartermaster", "Chief Engineer", "Research Director")
announce_span = "danger"
announce_text = "There are Syndicate agents and Blood Brothers on the station!\n\
+1 -1
View File
@@ -11,7 +11,7 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
antag_flag = ROLE_CHANGELING
false_report_weight = 10
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to ling role blacklist
protected_jobs = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to ling role blacklist
required_players = 15
required_enemies = 1
recommended_enemies = 4
@@ -54,7 +54,7 @@
antag_datum = /datum/antagonist/traitor
antag_flag = ROLE_TRAITOR
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
weight = 7
cost = 5
@@ -108,4 +108,4 @@
new_head.remove_clumsy = TRUE
new_head = M.mind.add_antag_datum(new_head)
new_head.rev_team.max_headrevs = 1 // Only one revhead if it is latejoin.
return TRUE
return TRUE
@@ -208,7 +208,7 @@
antag_datum = /datum/antagonist/traitor
antag_flag = ROLE_TRAITOR
restricted_roles = list("AI", "Cyborg", "Positronic Brain")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
weight = 4
cost = 10
@@ -224,7 +224,7 @@
antag_datum = /datum/antagonist/traitor/thief
antag_flag = ROLE_TRAITOR
restricted_roles = list("AI", "Cyborg", "Positronic Brain")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
weight = 4
cost = 5
@@ -545,7 +545,7 @@
antag_datum = /datum/antagonist/cult
minimum_required_age = 14
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
weight = 5
cost = 20
@@ -823,7 +823,7 @@ datum/dynamic_ruleset/midround/bloodcult/trim_candidates()
antag_datum = ANTAG_DATUM_BLOODSUCKER
antag_flag = ROLE_TRAITOR
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
enemy_roles = list("Security Officer","Head of Security","Captain","AI","Cyborg","Chaplain","Curator")
required_enemies = list(3,2,2,2,2,2,2,2,2,2)
@@ -11,7 +11,7 @@
antag_flag = ROLE_TRAITOR
antag_datum = /datum/antagonist/traitor/
minimum_required_age = 0
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Cyborg", "Quartermaster")
protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Cyborg", "Quartermaster")
restricted_roles = list("Cyborg", "AI") //Malf is it's own ruleset
required_candidates = 1
weight = 5
@@ -28,7 +28,7 @@
antag_flag = ROLE_TRAITOR
antag_datum = /datum/antagonist/traitor/thief
minimum_required_age = 0
//protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Cyborg")
//protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Cyborg")
restricted_roles = list("Cyborg", "AI") //Malf is it's own ruleset
//required_candidates = 1
weight = 5
@@ -127,7 +127,7 @@
antag_flag = ROLE_BROTHER
antag_datum = /datum/antagonist/brother/
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 2
weight = 4
cost = 10
@@ -181,7 +181,7 @@
antag_flag = ROLE_CHANGELING
antag_datum = /datum/antagonist/changeling
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 1
weight = 3
cost = 10
@@ -279,7 +279,7 @@
antag_datum = /datum/antagonist/cult
minimum_required_age = 14
restricted_roles = list("AI", "Cyborg")
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
required_candidates = 2
weight = 1
cost = 30
@@ -839,7 +839,7 @@
antag_flag = ROLE_BLOODSUCKER
antag_datum = ANTAG_DATUM_BLOODSUCKER
minimum_required_age = 0
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
protected_roles = list("Rookie", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
restricted_roles = list("Cyborg", "AI")
required_candidates = 1
weight = 3
+3 -3
View File
@@ -176,7 +176,7 @@
matching_designs.Cut()
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(findtext(D.name,href_list["to_search"]))
matching_designs.Add(D)
updateUsrDialog()
@@ -252,7 +252,7 @@
dat += materials_printout()
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(!(selected_category in D.category))
continue
@@ -366,7 +366,7 @@
/obj/machinery/autolathe/proc/adjust_hacked(state)
hacked = state
for(var/id in SSresearch.techweb_designs)
var/datum/design/D = SSresearch.techweb_designs[id]
var/datum/design/D = SSresearch.techweb_design_by_id(id)
if((D.build_type & AUTOLATHE) && ("hacked" in D.category))
if(hacked)
stored_research.add_design(D)
+1 -1
View File
@@ -31,7 +31,7 @@
/obj/machinery/computer/operating/proc/sync_surgeries()
for(var/i in linked_techweb.researched_designs)
var/datum/design/surgery/D = linked_techweb.researched_designs[i]
var/datum/design/surgery/D = SSresearch.techweb_design_by_id(i)
if(!istype(D))
continue
advanced_surgeries |= D.surgery
+2 -2
View File
@@ -177,7 +177,7 @@
dat += materials_printout()
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(!(selected_category in D.category))
continue
if(disabled || !can_build(D))
@@ -219,7 +219,7 @@
if(obj_flags & EMAGGED)
return
for(var/id in SSresearch.techweb_designs)
var/datum/design/D = SSresearch.techweb_designs[id]
var/datum/design/D = SSresearch.techweb_design_by_id(id)
if((D.build_type & LIMBGROWER) && ("emagged" in D.category))
stored_research.add_design(D)
to_chat(user, "<span class='warning'>A warning flashes onto the screen, stating that safety overrides have been deactivated!</span>")
+9 -9
View File
@@ -85,7 +85,7 @@
/obj/machinery/mecha_part_fabricator/proc/output_parts_list(set_name)
var/output = ""
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
if(!(set_name in D.category))
continue
@@ -183,7 +183,7 @@
/obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(set_name)
if(set_name in part_sets)
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
if(set_name in D.category)
add_to_queue(D)
@@ -338,7 +338,7 @@
if(href_list["part"])
var/T = afilter.getStr("part")
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
if(D.id == T)
if(!processing_queue)
@@ -349,7 +349,7 @@
if(href_list["add_to_queue"])
var/T = afilter.getStr("add_to_queue")
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
if(D.id == T)
add_to_queue(D)
@@ -387,7 +387,7 @@
if(href_list["part_desc"])
var/T = afilter.getStr("part_desc")
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
if(D.id == T)
var/obj/part = D.build_path
@@ -404,11 +404,11 @@
updateUsrDialog()
return
/obj/machinery/mecha_part_fabricator/proc/do_process_queue()
if(processing_queue || being_built)
return FALSE
/obj/machinery/mecha_part_fabricator/proc/do_process_queue()
if(processing_queue || being_built)
return FALSE
processing_queue = 1
process_queue()
process_queue()
processing_queue = 0
/obj/machinery/mecha_part_fabricator/proc/eject_sheets(eject_sheet, eject_amt)
+3 -1
View File
@@ -213,7 +213,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/boostable_nodes = techweb_item_boost_check(src)
if (boostable_nodes)
for(var/id in boostable_nodes)
var/datum/techweb_node/node = SSresearch.techweb_nodes[id]
var/datum/techweb_node/node = SSresearch.techweb_node_by_id(id)
if(!node)
continue
research_msg += sep
research_msg += node.display_name
sep = ", "
@@ -0,0 +1,38 @@
/obj/item/implant/cqc
name = "CQC implant"
desc = "Teaches you the arts of CQC in 5 short instructional videos beamed directly into your eyeballs."
icon = 'icons/obj/library.dmi'
icon_state ="cqcmanual"
activated = 1
var/datum/martial_art/cqc/style = new
/obj/item/implant/cqc/get_data()
var/dat = {"<b>Implant Specifications:</b><BR>
<b>Name:</b> CQC Implant<BR>
<b>Life:</b> 4 hours after death of host<BR>
<b>Implant Details:</b> <BR>
<b>Function:</b> Teaches even the clumsiest host the arts of CQC."}
return dat
/obj/item/implant/cqc/activate()
. = ..()
var/mob/living/carbon/human/H = imp_in
if(!ishuman(H))
return
if(!H.mind)
return
if(H.mind.has_martialart(MARTIALART_CQC))
style.remove(H)
to_chat(H, "<span class='notice'>You forget the basics of CQC.</span>")
else
style.teach(H,1)
to_chat(H, "<span class='notice'>You remember the basics of CQC!</span>")
/obj/item/implanter/cqc
name = "implanter (CQC)"
imp_type = /obj/item/implant/cqc
/obj/item/implantcase/cqc
name = "implant case - 'CQC'"
desc = "A glass case containing an implant that can teach the user the arts of CQC."
imp_type = /obj/item/implant/cqc
@@ -1,8 +1,8 @@
/obj/item/implant/krav_maga
name = "krav maga implant"
desc = "Teaches you the arts of Krav Maga in 5 short instructional videos beamed directly into your eyeballs."
icon = 'icons/obj/wizard.dmi'
icon_state ="scroll2"
icon = 'icons/obj/clothing/gloves.dmi'
icon_state ="fightgloves"
activated = 1
var/datum/martial_art/krav_maga/style = new
@@ -0,0 +1,38 @@
/obj/item/implant/mushpunch
name = "Mushroom Punch implant"
desc = "Teaches you the arts of Mushroom Punch in 5 short instructional videos beamed directly into your eyeballs."
icon = 'icons/obj/hydroponics/harvest.dmi'
icon_state ="angel"
activated = 1
var/datum/martial_art/mushpunch/style = new
/obj/item/implant/mushpunch/get_data()
var/dat = {"<b>Implant Specifications:</b><BR>
<b>Name:</b> Mushroom Punch Implant<BR>
<b>Life:</b> 4 hours after death of host<BR>
<b>Implant Details:</b> <BR>
<b>Function:</b> Teaches even the clumsiest host the arts of Mushroom Punch."}
return dat
/obj/item/implant/mushpunch/activate()
. = ..()
var/mob/living/carbon/human/H = imp_in
if(!ishuman(H))
return
if(!H.mind)
return
if(H.mind.has_martialart(MARTIALART_MUSHPUNCH))
style.remove(H)
to_chat(H, "<span class='notice'>You forget the teachings of Mushroom Punch.</span>")
else
style.teach(H,1)
to_chat(H, "<span class='notice'>You learn the arts of Mushroom Punch!</span>")
/obj/item/implanter/mushpunch
name = "implanter (Mushroom Punch)"
imp_type = /obj/item/implant/mushpunch
/obj/item/implantcase/mushpunch
name = "implant case - 'Mushroom Punch'"
desc = "A glass case containing an implant that can teach the user the arts of Mushroom Punch."
imp_type = /obj/item/implant/mushpunch
@@ -0,0 +1,38 @@
/obj/item/implant/plasmafist
name = "Plasma Fist implant"
desc = "Teaches you the arts of Plasma Fist in 5 short instructional videos beamed directly into your eyeballs."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state ="disintegrate"
activated = 1
var/datum/martial_art/plasma_fist/style = new
/obj/item/implant/plasmafist/get_data()
var/dat = {"<b>Implant Specifications:</b><BR>
<b>Name:</b> Plasma Fist Implant<BR>
<b>Life:</b> 4 hours after death of host<BR>
<b>Implant Details:</b> <BR>
<b>Function:</b> Teaches even the clumsiest host the arts of Plasma Fist."}
return dat
/obj/item/implant/plasmafist/activate()
. = ..()
var/mob/living/carbon/human/H = imp_in
if(!ishuman(H))
return
if(!H.mind)
return
if(H.mind.has_martialart(MARTIALART_PLASMAFIST))
style.remove(H)
to_chat(H, "<span class='notice'>You forget the teachings of the Plasma Fist.</span>")
else
style.teach(H,1)
to_chat(H, "<span class='notice'>You learn the arts of the Plasma Fist!</span>")
/obj/item/implanter/plasmafist
name = "implanter (Plasma Fist)"
imp_type = /obj/item/implant/plasmafist
/obj/item/implantcase/plasmafist
name = "implant case - 'Plasma Fist'"
desc = "A glass case containing an implant that can teach the user the arts of Plasma Fist."
imp_type = /obj/item/implant/plasmafist
@@ -0,0 +1,38 @@
/obj/item/implant/psychobrawl
name = "Psychotic Brawling implant"
desc = "Teaches you the arts of Psychotic Brawling in 5 short instructional videos beamed directly into your eyeballs."
icon = 'icons/obj/surgery.dmi'
icon_state ="brain"
activated = 1
var/datum/martial_art/psychotic_brawling/style = new
/obj/item/implant/psychobrawl/get_data()
var/dat = {"<b>Implant Specifications:</b><BR>
<b>Name:</b> Psychotic Brawling Implant<BR>
<b>Life:</b> 4 hours after death of host<BR>
<b>Implant Details:</b> <BR>
<b>Function:</b> Teaches even the clumsiest host the arts of Psychotic Brawling."}
return dat
/obj/item/implant/psychobrawl/activate()
. = ..()
var/mob/living/carbon/human/H = imp_in
if(!ishuman(H))
return
if(!H.mind)
return
if(H.mind.has_martialart(MARTIALART_PSYCHOBRAWL))
style.remove(H)
to_chat(H, "<span class='notice'>You forget the teachings of Psychotic Brawling.</span>")
else
style.teach(H,1)
to_chat(H, "<span class='notice'>You learn the arts of Psychotic Brawling!</span>")
/obj/item/implanter/psychobrawl
name = "implanter (Psychotic Brawling)"
imp_type = /obj/item/implant/psychobrawl
/obj/item/implantcase/psychobrawl
name = "implant case - 'Psychotic Brawling'"
desc = "A glass case containing an implant that can teach the user the arts of Psychotic Brawling."
imp_type = /obj/item/implant/psychobrawl
@@ -0,0 +1,38 @@
/obj/item/implant/sleepingcarp
name = "Sleeping Carp implant"
desc = "Teaches you the arts of Sleeping Carp in 5 short instructional videos beamed directly into your eyeballs."
icon = 'icons/obj/wizard.dmi'
icon_state ="scroll2"
activated = 1
var/datum/martial_art/the_sleeping_carp/style = new
/obj/item/implant/sleepingcarp/get_data()
var/dat = {"<b>Implant Specifications:</b><BR>
<b>Name:</b> Sleeping Carp Implant<BR>
<b>Life:</b> 4 hours after death of host<BR>
<b>Implant Details:</b> <BR>
<b>Function:</b> Teaches even the clumsiest host the arts of Sleeping Carp."}
return dat
/obj/item/implant/sleepingcarp/activate()
. = ..()
var/mob/living/carbon/human/H = imp_in
if(!ishuman(H))
return
if(!H.mind)
return
if(H.mind.has_martialart(MARTIALART_SLEEPINGCARP))
style.remove(H)
to_chat(H, "<span class='notice'>You forget the teachings of the Sleeping Carp.</span>")
else
style.teach(H,1)
to_chat(H, "<span class='notice'>You learn the arts of the Sleeping Carp!</span>")
/obj/item/implanter/sleepingcarp
name = "implanter (Sleeping Carp)"
imp_type = /obj/item/implant/sleepingcarp
/obj/item/implantcase/sleepingcarp
name = "implant case - 'Sleeping Carp'"
desc = "A glass case containing an implant that can teach the user the arts of Sleeping Carp."
imp_type = /obj/item/implant/sleepingcarp
@@ -0,0 +1,38 @@
/obj/item/implant/wrestling
name = "Wrestling implant"
desc = "Teaches you the arts of Wrestling in 5 short instructional videos beamed directly into your eyeballs."
icon = 'icons/obj/clothing/masks.dmi'
icon_state ="luchador"
activated = 1
var/datum/martial_art/wrestling/style = new
/obj/item/implant/wrestling/get_data()
var/dat = {"<b>Implant Specifications:</b><BR>
<b>Name:</b> Wrestling Implant<BR>
<b>Life:</b> 4 hours after death of host<BR>
<b>Implant Details:</b> <BR>
<b>Function:</b> Teaches even the clumsiest host the arts of Wrestling."}
return dat
/obj/item/implant/wrestling/activate()
. = ..()
var/mob/living/carbon/human/H = imp_in
if(!ishuman(H))
return
if(!H.mind)
return
if(H.mind.has_martialart(MARTIALART_WRESTLING))
style.remove(H)
to_chat(H, "<span class='notice'>You forget the teachings of Wrestling.</span>")
else
style.teach(H,1)
to_chat(H, "<span class='notice'>You learn the arts of Wrestling!</span>")
/obj/item/implanter/wrestling
name = "implanter (Wrestling)"
imp_type = /obj/item/implant/wrestling
/obj/item/implantcase/wrestling
name = "implant case - 'Wrestling'"
desc = "A glass case containing an implant that can teach the user the arts of Wrestling."
imp_type = /obj/item/implant/wrestling
+27 -2
View File
@@ -710,20 +710,44 @@
if(!check_rights(R_SPAWN))
return
var/turf/T = get_turf(usr)
var/chosen = pick_closest_path(object)
if(!chosen)
return
if(ispath(chosen, /turf))
var/turf/T = get_turf(usr.loc)
T.ChangeTurf(chosen)
else
var/atom/A = new chosen(usr.loc)
var/atom/A = new chosen(T)
A.flags_1 |= ADMIN_SPAWNED_1
log_admin("[key_name(usr)] spawned [chosen] at [AREACOORD(usr)]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/datum/admins/proc/podspawn_atom(object as text)
set category = "Debug"
set desc = "(atom path) Spawn an atom via supply drop"
set name = "Podspawn"
if(!check_rights(R_SPAWN))
return
var/chosen = pick_closest_path(object)
if(!chosen)
return
var/turf/T = get_turf(usr)
if(ispath(chosen, /turf))
T.ChangeTurf(chosen)
else
var/obj/structure/closet/supplypod/centcompod/pod = new()
var/atom/A = new chosen(pod)
A.flags_1 |= ADMIN_SPAWNED_1
new /obj/effect/abstract/DPtarget(T, pod)
log_admin("[key_name(usr)] pod-spawned [chosen] at [AREACOORD(usr)]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Podspawn Atom") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/datum/admins/proc/spawn_cargo(object as text)
set category = "Debug"
set desc = "(atom path) Spawn a cargo crate"
@@ -1011,3 +1035,4 @@
log_admin("Man up global: [key_name(usr)] told everybody to man up")
message_admins("<span class='adminnotice'>[key_name_admin(usr)] told everybody to man up.</span>")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Man Up Global")
+1 -1
View File
@@ -112,7 +112,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list(
/client/proc/roll_dices //CIT CHANGE - Adds dice verb
))
GLOBAL_PROTECT(admin_verbs_spawn)
GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character))
GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/podspawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character))
GLOBAL_PROTECT(admin_verbs_server)
GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer())
/world/proc/AVerbsServer()
+13 -3
View File
@@ -2399,7 +2399,7 @@
var/atom/target //Where the object will be spawned
var/where = href_list["object_where"]
if (!( where in list("onfloor","inhand","inmarked") ))
if (!( where in list("onfloor","frompod","inhand","inmarked") ))
where = "onfloor"
@@ -2410,7 +2410,7 @@
where = "onfloor"
target = usr
if("onfloor")
if("onfloor", "frompod")
switch(href_list["offset_type"])
if ("absolute")
target = locate(0 + X,0 + Y,0 + Z)
@@ -2426,7 +2426,10 @@
else
target = marked_datum
var/obj/structure/closet/supplypod/centcompod/pod
if(target)
if(where == "frompod")
pod = new()
for (var/path in paths)
for (var/i = 0; i < number; i++)
if(path in typesof(/turf))
@@ -2435,7 +2438,11 @@
if(N && obj_name)
N.name = obj_name
else
var/atom/O = new path(target)
var/atom/O
if(where == "frompod")
O = new path(pod)
else
O = new path(target)
if(!QDELETED(O))
O.flags_1 |= ADMIN_SPAWNED_1
if(obj_dir)
@@ -2455,6 +2462,8 @@
R.module.add_module(I, TRUE, TRUE)
R.activate_module(I)
if(pod)
new /obj/effect/abstract/DPtarget(target, pod)
if (number == 1)
log_admin("[key_name(usr)] created a [english_list(paths)]")
@@ -2981,3 +2990,4 @@
else
to_chat(usr, "<span class='danger'>Failed to establish database connection. The changes will last only for the current round.</span>")
to_chat(usr, "<span class='adminnotice'>Mentor removed.</span>")
+28 -7
View File
@@ -1260,12 +1260,13 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
ADMIN_PUNISHMENT_BRAINDAMAGE,
ADMIN_PUNISHMENT_BSA,
ADMIN_PUNISHMENT_GIB,
ADMIN_PUNISHMENT_SUPPLYPOD_QUICK,
ADMIN_PUNISHMENT_SUPPLYPOD,
ADMIN_PUNISHMENT_MAZING,
ADMIN_PUNISHMENT_ROD,
ADMIN_PUNISHMENT_TABLETIDESTATIONWIDE,
ADMIN_PUNISHMENT_FAKEBWOINK,
ADMIN_PUNISHMENT_NUGGET,
ADMIN_PUNISHMENT_TABLETIDESTATIONWIDE,
ADMIN_PUNISHMENT_FAKEBWOINK,
ADMIN_PUNISHMENT_NUGGET,
ADMIN_PUNISHMENT_BREADIFY)
var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list
@@ -1304,6 +1305,22 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
var/turf/startT = spaceDebrisStartLoc(startside, T.z)
var/turf/endT = spaceDebrisFinishLoc(startside, T.z)
new /obj/effect/immovablerod(startT, endT,target)
if(ADMIN_PUNISHMENT_SUPPLYPOD_QUICK)
var/target_path = input(usr,"Enter typepath of an atom you'd like to send with the pod (type \"empty\" to send an empty pod):" ,"Typepath","/obj/item/reagent_containers/food/snacks/grown/harebell") as null|text
var/obj/structure/closet/supplypod/centcompod/pod = new()
pod.damage = 40
pod.explosionSize = list(0,0,0,2)
pod.effectStun = TRUE
if (isnull(target_path)) //The user pressed "Cancel"
return
if (target_path != "empty")//if you didn't type empty, we want to load the pod with a delivery
var/delivery = text2path(target_path)
if(!ispath(delivery))
delivery = pick_closest_path(target_path)
if(!delivery)
alert("ERROR: Incorrect / improper path given.")
new delivery(pod)
new /obj/effect/abstract/DPtarget(get_turf(target), pod)
if(ADMIN_PUNISHMENT_SUPPLYPOD)
var/datum/centcom_podlauncher/plaunch = new(usr)
if(!holder)
@@ -1316,6 +1333,8 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
plaunch.temp_pod.explosionSize = list(0,0,0,2)
plaunch.temp_pod.effectStun = TRUE
plaunch.ui_interact(usr)
return //We return here because punish_log() is handled by the centcom_podlauncher datum
if(ADMIN_PUNISHMENT_MAZING)
if(!puzzle_imprison(target))
to_chat(usr,"<span class='warning'>Imprisonment failed!</span>")
@@ -1357,12 +1376,13 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
addtimer(CALLBACK(GLOBAL_PROC, .proc/breadify, target), BREADIFY_TIME)
#undef BREADIFY_TIME
punish_log(target, punishment)
var/msg = "[key_name_admin(usr)] punished [key_name_admin(target)] with [punishment]."
/client/proc/punish_log(var/whom, var/punishment)
var/msg = "[key_name_admin(usr)] punished [key_name_admin(whom)] with [punishment]."
message_admins(msg)
admin_ticket_log(target, msg)
log_admin("[key_name(usr)] punished [key_name(target)] with [punishment].")
admin_ticket_log(whom, msg)
log_admin("[key_name(usr)] punished [key_name(whom)] with [punishment].")
/client/proc/trigger_centcom_recall()
if(!check_rights(R_ADMIN))
@@ -1432,3 +1452,4 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
else
message_admins("[key_name_admin(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name_admin(C)]")
log_admin("[key_name(usr)] has [newstate ? "activated" : "deactivated"] job exp exempt status on [key_name(C)]")
+99 -21
View File
@@ -19,7 +19,7 @@
//Variables declared to change how items in the launch bay are picked and launched. (Almost) all of these are changed in the ui_act proc
//Some effect groups are choices, while other are booleans. This is because some effects can stack, while others dont (ex: you can stack explosion and quiet, but you cant stack ordered launch and random launch)
/datum/centcom_podlauncher
var/static/list/ignored_atoms = typecacheof(list(null, /mob/dead, /obj/effect/landmark, /obj/docking_port, /atom/movable/lighting_object, /obj/effect/particle_effect/sparks, /obj/effect/DPtarget, /obj/effect/supplypod_selector ))
var/static/list/ignored_atoms = typecacheof(list(null, /mob/dead, /obj/effect/landmark, /obj/docking_port, /atom/movable/lighting_object, /obj/effect/particle_effect/sparks, /obj/effect/abstract/DPtarget, /obj/effect/supplypod_selector ))
var/turf/oldTurf //Keeps track of where the user was at if they use the "teleport to centcom" button, so they can go back
var/client/holder //client of whoever is using this datum
var/area/bay //What bay we're using to launch shit from.
@@ -29,9 +29,10 @@
var/damageChoice = 0 //Determines if we do no damage (0), custom amnt of damage (1), or gib + 5000dmg (2)
var/launcherActivated = FALSE //check if we've entered "launch mode" (when we click a pod is launched). Used for updating mouse cursor
var/effectBurst = FALSE //Effect that launches 5 at once in a 3x3 area centered on the target
var/effectAnnounce = TRUE
var/numTurfs = 0 //Counts the number of turfs with things we can launch in the chosen bay (in the centcom map)
var/launchCounter = 1 //Used with the "Ordered" launch mode (launchChoice = 1) to see what item is launched
var/specificTarget //Do we want to target a specific mob instead of where we click? Also used for smiting
var/atom/specificTarget //Do we want to target a specific mob instead of where we click? Also used for smiting
var/list/orderedArea = list() //Contains an ordered list of turfs in an area (filled in the createOrderedArea() proc), read top-left to bottom-right. Used for the "ordered" launch mode (launchChoice = 1)
var/list/acceptableTurfs = list() //Contians a list of turfs (in the "bay" area on centcom) that have items that can be launched. Taken from orderedArea
var/list/launchList = list() //Contains whatever is going to be put in the supplypod and fired. Taken from acceptableTurfs
@@ -66,12 +67,14 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
data["launchChoice"] = launchChoice //Launch turfs all at once (0), ordered (1), or randomly(1)
data["explosionChoice"] = explosionChoice //An explosion that occurs when landing. Can be no explosion (0), custom explosion (1), or maxcap (2)
data["damageChoice"] = damageChoice //Damage that occurs to any mob under the pod when it lands. Can be no damage (0), custom damage (1), or gib+5000dmg (2)
data["fallDuration"] = temp_pod.fallDuration //How long the pod's falling animation lasts
data["landingDelay"] = temp_pod.landingDelay //How long the pod takes to land after launching
data["openingDelay"] = temp_pod.openingDelay //How long the pod takes to open after landing
data["departureDelay"] = temp_pod.departureDelay //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom)
data["styleChoice"] = temp_pod.style //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the POD_STYLES list in cargo.dm defines to get the proper icon/name/desc for the pod.
data["effectStun"] = temp_pod.effectStun //If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish!
data["effectLimb"] = temp_pod.effectLimb //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands
data["effectOrgans"] = temp_pod.effectOrgans //If true, yeets the organs out of any bodies caught under the pod when it lands
data["effectBluespace"] = temp_pod.bluespace //If true, the pod deletes (in a shower of sparks) after landing
data["effectStealth"] = temp_pod.effectStealth //If true, a target icon isnt displayed on the turf where the pod will land
data["effectQuiet"] = temp_pod.effectQuiet //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc)
@@ -81,12 +84,14 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
data["effectReverse"] = temp_pod.reversing //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom
data["effectTarget"] = specificTarget //Launches the pod at the turf of a specific mob target, rather than wherever the user clicked. Useful for smites
data["effectName"] = temp_pod.adminNamed //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
data["effectAnnounce"] = effectAnnounce
data["giveLauncher"] = launcherActivated //If true, the user is in launch mode, and whenever they click a pod will be launched (either at their mouse position or at a specific target)
data["numObjects"] = numTurfs //Counts the number of turfs that contain a launchable object in the centcom supplypod bay
data["fallingSound"] = temp_pod.fallingSound != initial(temp_pod.fallingSound)//Admin sound to play as the pod falls
data["landingSound"] = temp_pod.landingSound //Admin sound to play when the pod lands
data["openingSound"] = temp_pod.openingSound //Admin sound to play when the pod opens
data["leavingSound"] = temp_pod.leavingSound //Admin sound to play when the pod leaves
data["soundVolume"] = temp_pod.soundVolume != 50 //Admin sound to play when the pod leaves
data["soundVolume"] = temp_pod.soundVolume != initial(temp_pod.soundVolume) //Admin sound to play when the pod leaves
return data
/datum/centcom_podlauncher/ui_act(action, params)
@@ -227,6 +232,9 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if("effectLimb") //Toggle: Anyone carbon mob under the pod loses a limb when it lands
temp_pod.effectLimb = !temp_pod.effectLimb
. = TRUE
if("effectOrgans") //Toggle: Any carbon mob under the pod loses every limb and organ
temp_pod.effectOrgans = !temp_pod.effectOrgans
. = TRUE
if("effectBluespace") //Toggle: Deletes the pod after landing
temp_pod.bluespace = !temp_pod.bluespace
. = TRUE
@@ -245,6 +253,9 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if("effectBurst") //Toggle: Launch 5 pods (with a very slight delay between) in a 3x3 area centered around the target
effectBurst = !effectBurst
. = TRUE
if("effectAnnounce") //Toggle: Sends a ghost announcement.
effectAnnounce = !effectAnnounce
. = TRUE
if("effectReverse") //Toggle: Don't send any items. Instead, after landing, close (taking any objects inside) and go back to the centcom bay it came from
temp_pod.reversing = !temp_pod.reversing
. = TRUE
@@ -261,11 +272,23 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
. = TRUE
////////////////////////////TIMER DELAYS//////////////////
if("fallDuration") //Change the falling animation duration
if (temp_pod.fallDuration != initial(temp_pod.fallDuration)) //If the fall duration has already been changed when we push the "change value" button, then set it to default
temp_pod.fallDuration = initial(temp_pod.fallDuration)
return
var/timeInput = input("Enter the duration of the pod's falling animation, in seconds", "Delay Time", initial(temp_pod.fallDuration) * 0.1) as null|num
if (isnull(timeInput))
return
if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default
alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.fallDuration)*0.1]) instead.")
timeInput = initial(temp_pod.fallDuration)
temp_pod.fallDuration = 10 * timeInput
. = TRUE
if("landingDelay") //Change the time it takes the pod to land, after firing
if (temp_pod.landingDelay != initial(temp_pod.landingDelay)) //If the landing delay has already been changed when we push the "change value" button, then set it to default
temp_pod.landingDelay = initial(temp_pod.landingDelay)
return
var/timeInput = input("Delay Time", "Enter the time it takes for the pod to land, in seconds", 0.5) as null|num
var/timeInput = input("Enter the time it takes for the pod to land, in seconds", "Delay Time", initial(temp_pod.landingDelay) * 0.1) as null|num
if (isnull(timeInput))
return
if (!isnum(timeInput)) //Sanitize input, if it doesnt check out, error and set to default
@@ -277,7 +300,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if (temp_pod.openingDelay != initial(temp_pod.openingDelay)) //If the opening delay has already been changed when we push the "change value" button, then set it to default
temp_pod.openingDelay = initial(temp_pod.openingDelay)
return
var/timeInput = input("Delay Time", "Enter the time it takes for the pod to open after landing, in seconds", 3) as null|num
var/timeInput = input("Enter the time it takes for the pod to open after landing, in seconds", "Delay Time", initial(temp_pod.openingDelay) * 0.1) as null|num
if (isnull(timeInput))
return
if (!isnum(timeInput)) //Sanitize input
@@ -289,7 +312,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if (temp_pod.departureDelay != initial(temp_pod.departureDelay)) //If the departure delay has already been changed when we push the "change value" button, then set it to default
temp_pod.departureDelay = initial(temp_pod.departureDelay)
return
var/timeInput = input("Delay Time", "Enter the time it takes for the pod to leave after opening, in seconds", 3) as null|num
var/timeInput = input("Enter the time it takes for the pod to leave after opening, in seconds", "Delay Time", initial(temp_pod.departureDelay) * 0.1) as null|num
if (isnull(timeInput))
return
if (!isnum(timeInput))
@@ -299,31 +322,57 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
. = TRUE
////////////////////////////ADMIN SOUNDS//////////////////
if("fallingSound") //Admin sound from a local file that plays when the pod falls
if ((temp_pod.fallingSound) != initial(temp_pod.fallingSound))
temp_pod.fallingSound = initial(temp_pod.fallingSound)
temp_pod.fallingSoundLength = initial(temp_pod.fallingSoundLength)
return
var/soundInput = input(holder, "Please pick a sound file to play when the pod lands! NOTICE: Take a note of exactly how long the sound is.", "Pick a Sound File") as null|sound
if (isnull(soundInput))
return
var/timeInput = input(holder, "What is the exact length of the sound file, in seconds. This number will be used to line the sound up so that it finishes right as the pod lands!", "Pick a Sound File", 0.3) as null|num
if (isnull(timeInput))
return
if (!isnum(timeInput))
alert(usr, "That wasnt a number! Value set to default ([initial(temp_pod.fallingSoundLength)*0.1]) instead.")
temp_pod.fallingSound = soundInput
temp_pod.fallingSoundLength = 10 * timeInput
. = TRUE
if("landingSound") //Admin sound from a local file that plays when the pod lands
if (!isnull(temp_pod.landingSound))
temp_pod.landingSound = null
return
temp_pod.landingSound = input(holder, "Please pick a sound file to play when the pod lands! I reccomend a nice \"oh shit, i'm sorry\", incase you hit someone with the pod.", "Pick a Sound File") as null|sound
var/soundInput = input(holder, "Please pick a sound file to play when the pod lands! I reccomend a nice \"oh shit, i'm sorry\", incase you hit someone with the pod.", "Pick a Sound File") as null|sound
if (isnull(soundInput))
return
temp_pod.landingSound = soundInput
. = TRUE
if("openingSound") //Admin sound from a local file that plays when the pod opens
if (!isnull(temp_pod.openingSound))
temp_pod.openingSound = null
return
temp_pod.openingSound = input(holder, "Please pick a sound file to play when the pod opens! I reccomend a stock sound effect of kids cheering at a party, incase your pod is full of fun exciting stuff!", "Pick a Sound File") as null|sound
var/soundInput = input(holder, "Please pick a sound file to play when the pod opens! I reccomend a stock sound effect of kids cheering at a party, incase your pod is full of fun exciting stuff!", "Pick a Sound File") as null|sound
if (isnull(soundInput))
return
temp_pod.openingSound = soundInput
. = TRUE
if("leavingSound") //Admin sound from a local file that plays when the pod leaves
if (!isnull(temp_pod.leavingSound))
temp_pod.leavingSound = null
return
temp_pod.leavingSound = input(holder, "Please pick a sound file to play when the pod leaves! I reccomend a nice slide whistle sound, especially if you're using the reverse pod effect.", "Pick a Sound File") as null|sound
var/soundInput = input(holder, "Please pick a sound file to play when the pod leaves! I reccomend a nice slide whistle sound, especially if you're using the reverse pod effect.", "Pick a Sound File") as null|sound
if (isnull(soundInput))
return
temp_pod.leavingSound = soundInput
. = TRUE
if("soundVolume") //Admin sound from a local file that plays when the pod leaves
if (temp_pod.soundVolume != 50)
temp_pod.soundVolume = 50
if (temp_pod.soundVolume != initial(temp_pod.soundVolume))
temp_pod.soundVolume = initial(temp_pod.soundVolume)
return
temp_pod.soundVolume = input(holder, "Please pick a volume. Default is between 1 and 100 with 50 being average, but pick whatever. I'm a notification, not a cop. If you still cant hear your sound, consider turning on the Quiet effect. It will silence all pod sounds except for the custom admin ones set by the previous three buttons.", "Pick Admin Sound Volume") as null|num
if (isnull(temp_pod.soundVolume))
temp_pod.soundVolume = 50
var/soundInput = input(holder, "Please pick a volume. Default is between 1 and 100 with 80 being average, but pick whatever. I'm a notification, not a cop. If you still cant hear your sound, consider turning on the Quiet effect. It will silence all pod sounds except for the custom admin ones set by the previous three buttons.", "Pick Admin Sound Volume") as null|num
if (isnull(soundInput))
return
temp_pod.soundVolume = soundInput
. = TRUE
////////////////////////////STYLE CHANGES//////////////////
//Style is a value that is used to keep track of what the pod is supposed to look like. It can be used with the POD_STYLES list (in cargo.dm defines)
@@ -364,6 +413,9 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if("styleGondola")
temp_pod.setStyle(STYLE_GONDOLA)
. = TRUE
if("styleSeeThrough")
temp_pod.setStyle(STYLE_SEETHROUGH)
. = TRUE
if("refresh") //Refresh the Pod bay. User should press this if they spawn something new in the centcom bay. Automatically called whenever the user launches a pod
refreshBay()
. = TRUE
@@ -403,12 +455,17 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if(left_click) //When we left click:
preLaunch() //Fill the acceptableTurfs list from the orderedArea list. Then, fill up the launchList list with items from the acceptableTurfs list based on the manner of launch (ordered, random, etc)
if (!isnull(specificTarget))
target = get_turf(specificTarget) //if we have a specific mob target, then always launch the pod at the turf of the mob
target = get_turf(specificTarget) //if we have a specific target, then always launch the pod at the turf of the target
else if (target)
target = get_turf(target) //Make sure we're aiming at a turf rather than an item or effect or something
else
return //if target is null and we don't have a specific target, cancel
if (effectAnnounce)
deadchat_broadcast("<span class='deadsay'>A special package is being launched at the station!</span>", turf_target = target)
var/list/bouttaDie = list()
for (var/mob/living/M in target)
bouttaDie.Add(M)
supplypod_punish_log(bouttaDie)
if (!effectBurst) //If we're not using burst mode, just launch normally.
launch(target)
else
@@ -422,7 +479,6 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
else
launch(target) //If we couldn't locate an adjacent turf, just launch at the normal target
sleep(rand()*2) //looks cooler than them all appearing at once. Gives the impression of burst fire.
log_admin("Centcom Supplypod Launch: [key_name(user)] launched a supplypod in [AREACOORD(target)]")
/datum/centcom_podlauncher/proc/refreshBay() //Called whenever the bay is switched, as well as wheneber a pod is launched
orderedArea = createOrderedArea(bay) //Create an ordered list full of turfs form the bay
@@ -486,11 +542,11 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if (launchClone) //We arent launching the actual items from the bay, rather we are creating clones and launching those
for (var/atom/movable/O in launchList)
DuplicateObject(O).forceMove(toLaunch) //Duplicate each atom/movable in launchList and forceMove them into the supplypod
new /obj/effect/DPtarget(A, toLaunch) //Create the DPTarget, which will eventually forceMove the temp_pod to it's location
else
new /obj/effect/abstract/DPtarget(A, toLaunch) //Create the DPTarget, which will eventually forceMove the temp_pod to it's location
else
for (var/atom/movable/O in launchList) //If we aren't cloning the objects, just go through the launchList
O.forceMove(toLaunch) //and forceMove any atom/moveable into the supplypod
new /obj/effect/DPtarget(A, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location
new /obj/effect/abstract/DPtarget(A, toLaunch) //Then, create the DPTarget effect, which will eventually forceMove the temp_pod to it's location
if (launchClone)
launchCounter++ //We only need to increment launchCounter if we are cloning objects.
//If we aren't cloning objects, taking and removing the first item each time from the acceptableTurfs list will inherently iterate through the list in order
@@ -508,4 +564,26 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
updateCursor(FALSE) //Make sure our moues cursor resets to default. False means we are not in launch mode
qdel(temp_pod) //Delete the temp_pod
qdel(selector) //Delete the selector effect
. = ..()
. = ..()
/datum/centcom_podlauncher/proc/supplypod_punish_log(var/list/whoDyin)
var/podString = effectBurst ? "5 pods" : "a pod"
var/whomString = ""
if (LAZYLEN(whoDyin))
for (var/mob/living/M in whoDyin)
whomString += "[key_name(M)], "
var/delayString = temp_pod.landingDelay == initial(temp_pod.landingDelay) ? "" : " Delay=[temp_pod.landingDelay*0.1]s"
var/damageString = temp_pod.damage == 0 ? "" : " Dmg=[temp_pod.damage]"
var/explosionString = ""
var/explosion_sum = temp_pod.explosionSize[1] + temp_pod.explosionSize[2] + temp_pod.explosionSize[3] + temp_pod.explosionSize[4]
if (explosion_sum != 0)
explosionString = " Boom=|"
for (var/X in temp_pod.explosionSize)
explosionString += "[X]|"
var/msg = "launched [podString][whomString].[delayString][damageString][explosionString]]"
message_admins("[key_name_admin(usr)] [msg] in [AREACOORD(specificTarget)].")
if (!isemptylist(whoDyin))
for (var/mob/living/M in whoDyin)
admin_ticket_log(M, "[key_name_admin(usr)] [msg]")
+3 -2
View File
@@ -183,7 +183,7 @@
LZ = pick(empty_turfs)
if (SO.pack.cost <= SSshuttle.points && LZ)//we need to call the cost check again because of the CHECK_TICK call
SSshuttle.points -= SO.pack.cost
new /obj/effect/DPtarget(LZ, podType, SO)
new /obj/effect/abstract/DPtarget(LZ, podType, SO)
. = TRUE
update_icon()
else
@@ -200,7 +200,8 @@
for(var/i in 1 to MAX_EMAG_ROCKETS)
var/LZ = pick(empty_turfs)
LAZYREMOVE(empty_turfs, LZ)
new /obj/effect/DPtarget(LZ, podType, SO)
new /obj/effect/abstract/DPtarget(LZ, podType, SO)
. = TRUE
update_icon()
CHECK_TICK
+10 -3
View File
@@ -39,15 +39,22 @@
set name = "Release Contents"
set category = "Gondola"
set desc = "Release any contents stored within your vast belly."
linked_pod.open(src, manual = TRUE)
linked_pod.open(src, forced = TRUE)
/mob/living/simple_animal/pet/gondola/gondolapod/examine(mob/user)
..()
if (contents.len)
to_chat(user, "<span class='notice'>It looks like it hasn't made its delivery yet.</b><span>")
else
to_chat(user, "<span class='notice'>It looks like it has already made its delivery.</b><span>")
/mob/living/simple_animal/pet/gondola/gondolapod/verb/check()
set name = "Count Contents"
set category = "Gondola"
set desc = "Take a deep look inside youself, and count up what's inside"
var/total = contents.len
if (total)
to_chat(src, "<span class='notice'>You detect [total] object[total > 1 ? "s" : ""] within your incredibly vast belly.</span>")
if (total)
to_chat(src, "<span class='notice'>You detect [total] object\s within your incredibly vast belly.</span>")
else
to_chat(src, "<span class='notice'>A closer look inside yourself reveals... nothing.</span>")
+1 -1
View File
@@ -12,7 +12,7 @@
/datum/supply_pack/emergency/vehicle
name = "Biker Gang Kit" //TUNNEL SNAKES OWN THIS TOWN
desc = "TUNNEL SNAKES OWN THIS TOWN. Contains an unbranded All Terrain Vehicle, and a complete gang outfit -- consists of black gloves, a menacing skull bandanna, and a SWEET leather overcoat!"
cost = 2500
cost = 7500
contraband = TRUE
contains = list(/obj/vehicle/ridden/atv,
/obj/item/key,
+95 -45
View File
@@ -15,15 +15,17 @@
armor = list("melee" = 30, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 100, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 80)
anchored = TRUE //So it cant slide around after landing
anchorable = FALSE
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
//*****NOTE*****: Many of these comments are similarly described in centcom_podlauncher.dm. If you change them here, please consider doing so in the centcom podlauncher code as well!
var/adminNamed = FALSE //Determines whether or not the pod has been named by an admin. If true, the pod's name will not get overridden when the style of the pod changes (changing the style of the pod normally also changes the name+desc)
var/bluespace = FALSE //If true, the pod deletes (in a shower of sparks) after landing
var/landingDelay = 30 //How long the pod takes to land after launching
var/openingDelay = 30 //How long the pod takes to open after landing
var/departureDelay = 30 //How long the pod takes to leave after opening (if bluespace=true, it deletes. if reversing=true, it flies back to centcom)
var/departureDelay = 30 //How long the pod takes to leave after opening. If bluespace = TRUE, it deletes. If reversing = TRUE, it flies back to centcom.
var/damage = 0 //Damage that occurs to any mob under the pod when it lands.
var/effectStun = FALSE //If true, stuns anyone under the pod when it launches until it lands, forcing them to get hit by the pod. Devilish!
var/effectLimb = FALSE //If true, pops off a limb (if applicable) from anyone caught under the pod when it lands
var/effectOrgans = FALSE //If true, yeets out every limb and organ from anyone caught under the pod when it lands
var/effectGib = FALSE //If true, anyone under the pod will be gibbed when it lands
var/effectStealth = FALSE //If true, a target icon isnt displayed on the turf where the pod will land
var/effectQuiet = FALSE //The female sniper. If true, the pod makes no noise (including related explosions, opening sounds, etc)
@@ -31,10 +33,13 @@
var/effectCircle = FALSE //If true, allows the pod to come in at any angle. Bit of a weird feature but whatever its here
var/style = STYLE_STANDARD //Style is a variable that keeps track of what the pod is supposed to look like. It acts as an index to the POD_STYLES list in cargo.dm defines to get the proper icon/name/desc for the pod.
var/reversing = FALSE //If true, the pod will not send any items. Instead, after opening, it will close again (picking up items/mobs) and fly back to centcom
var/fallDuration = 4
var/fallingSoundLength = 11
var/fallingSound = 'sound/weapons/mortar_long_whistle.ogg'//Admin sound to play before the pod lands
var/landingSound //Admin sound to play when the pod lands
var/openingSound //Admin sound to play when the pod opens
var/leavingSound //Admin sound to play when the pod leaves
var/soundVolume = 50 //Volume to play sounds at. Ignores the cap
var/soundVolume = 80 //Volume to play sounds at. Ignores the cap
var/bay //Used specifically for the centcom_podlauncher datum. Holds the current bay the user is launching objects from. Bays are specific rooms on the centcom map.
var/list/explosionSize = list(0,0,2,3)
@@ -48,16 +53,18 @@
style = STYLE_CENTCOM
bluespace = TRUE
explosionSize = list(0,0,0,0)
landingDelay = 5 //Very speedy!
landingDelay = 20 //Very speedy!
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/structure/closet/supplypod/Initialize()
..()
. = ..()
setStyle(style, TRUE) //Upon initialization, give the supplypod an iconstate, name, and description based on the "style" variable. This system is important for the centcom_podlauncher to function correctly
/obj/structure/closet/supplypod/update_icon()
cut_overlays()
if (style != STYLE_INVISIBLE) //If we're invisible, we dont bother adding any overlays
if (style == STYLE_SEETHROUGH || style == STYLE_INVISIBLE) //If we're invisible, we dont bother adding any overlays
return
else
if (opened)
add_overlay("[icon_state]_open")
else
@@ -75,7 +82,7 @@
update_icon()
/obj/structure/closet/supplypod/tool_interact(obj/item/W, mob/user)
if (bluespace) //We dont want to worry about interacting with bluespace pods, as they are due to delete themselves soon anyways.
if(bluespace) //We dont want to worry about interacting with bluespace pods, as they are due to delete themselves soon anyways.
return FALSE
else
..()
@@ -86,9 +93,6 @@
/obj/structure/closet/supplypod/contents_explosion() //Supplypods also protect their contents from the harmful effects of fucking exploding.
return
/obj/structure/closet/supplypod/prevent_content_explosion() //Useful for preventing epicenter explosions from damaging contents
return TRUE
/obj/structure/closet/supplypod/toggle(mob/living/user) //Supplypods shouldn't be able to be manually opened under any circumstances, as the open() proc generates supply order datums
return
@@ -101,17 +105,33 @@
if (effectLimb && iscarbon(M)) //If effectLimb is true (which means we pop limbs off when we hit people):
var/mob/living/carbon/CM = M
for (var/obj/item/bodypart/bodypart in CM.bodyparts) //Look at the bodyparts in our poor mob beneath our pod as it lands
if(bodypart.body_part != HEAD && bodypart.body_zone != CHEST)//we dont want to kill him, just teach em a lesson!
if(bodypart.body_part != HEAD && bodypart.body_part != CHEST)//we dont want to kill him, just teach em a lesson!
if (bodypart.dismemberable)
bodypart.dismember() //Using the power of flextape i've sawed this man's limb in half!
break
if (effectOrgans && iscarbon(M)) //effectOrgans means remove every organ in our mob
var/mob/living/carbon/CM = M
for(var/X in CM.internal_organs)
var/destination = get_edge_target_turf(T, pick(GLOB.alldirs)) //Pick a random direction to toss them in
var/obj/item/organ/O = X
O.Remove(CM) //Note that this isn't the same proc as for lists
O.forceMove(T) //Move the organ outta the body
O.throw_at(destination, 2, 3) //Thow the organ at a random tile 3 spots away
sleep(1)
for (var/obj/item/bodypart/bodypart in CM.bodyparts) //Look at the bodyparts in our poor mob beneath our pod as it lands
var/destination = get_edge_target_turf(T, pick(GLOB.alldirs))
if (bodypart.dismemberable)
bodypart.dismember() //Using the power of flextape i've sawed this man's bodypart in half!
bodypart.throw_at(destination, 2, 3)
sleep(1)
if (effectGib) //effectGib is on, that means whatever's underneath us better be fucking oof'd on
M.adjustBruteLoss(5000) //THATS A LOT OF DAMAGE (called just in case gib() doesnt work on em)
M.gib() //After adjusting the fuck outta that brute loss we finish the job with some satisfying gibs
M.adjustBruteLoss(damage)
if (B[1] || B[2] || B[3] || B[4]) //If the explosion list isn't all zeroes, call an explosion
else
M.adjustBruteLoss(damage)
var/explosion_sum = B[1] + B[2] + B[3] + B[4]
if (explosion_sum != 0) //If the explosion list isn't all zeroes, call an explosion
explosion(get_turf(src), B[1], B[2], B[3], flame_range = B[4], silent = effectQuiet, ignorecap = istype(src, /obj/structure/closet/supplypod/centcompod)) //less advanced equipment than bluespace pod, so larger explosion when landing
else if (!effectQuiet) //If our explosion list IS all zeroes, we still make a nice explosion sound (unless the effectQuiet var is true)
playsound(src, "explosion", landingSound ? 15 : 80, 1)
@@ -128,22 +148,31 @@
/obj/structure/closet/supplypod/open(atom/movable/holder, var/broken = FALSE, var/forced = FALSE) //The holder var represents an atom whose contents we will be working with
var/turf/T = get_turf(holder) //Get the turf of whoever's contents we're talking about
if (!holder)
return
if(opened)
return
opened = TRUE //This is to ensure we don't open something that has already been opened
var/mob/M
if (istype(holder, /mob)) //Allows mobs to assume the role of the holder, meaning we look at the mob's contents rather than the supplypod's contents. Typically by this point the supplypod's contents have already been moved over to the mob's contents
M = holder
if (M.key && !forced && !broken) //If we are player controlled, then we shouldnt open unless the opening is manual, or if it is due to being destroyed (represented by the "broken" parameter)
return
opened = TRUE //This is to ensure we don't open something that has already been opened
if (openingSound)
playsound(get_turf(holder), openingSound, soundVolume, 0, 0)
playsound(get_turf(holder), openingSound, soundVolume, 0, 0) //Special admin sound to play
INVOKE_ASYNC(holder, .proc/setOpened) //Use the INVOKE_ASYNC proc to call setOpened() on whatever the holder may be, without giving the atom/movable base class a setOpened() proc definition
if (style == STYLE_SEETHROUGH)
update_icon()
for (var/atom/movable/O in holder.contents) //Go through the contents of the holder
O.forceMove(T) //move everything from the contents of the holder to the turf of the holder
if (!effectQuiet) //If we aren't being quiet, play an open sound
if (!effectQuiet && !openingSound && style != STYLE_SEETHROUGH) //If we aren't being quiet, play the default pod open sound
playsound(get_turf(holder), open_sound, 15, 1, -3)
if (broken) //If the pod is opening because it's been destroyed, we end here
return
addtimer(CALLBACK(src, .proc/depart, holder), departureDelay) //Finish up the pod's duties after a certain amount of time
if (style == STYLE_SEETHROUGH)
depart(src)
else
addtimer(CALLBACK(src, .proc/depart, holder), departureDelay) //Finish up the pod's duties after a certain amount of time
/obj/structure/closet/supplypod/proc/depart(atom/movable/holder)
if (leavingSound)
@@ -151,7 +180,7 @@
if (reversing) //If we're reversing, we call the close proc. This sends the pod back up to centcom
close(holder)
else if (bluespace) //If we're a bluespace pod, then delete ourselves (along with our holder, if a seperate holder exists)
if (style != STYLE_INVISIBLE)
if (!effectQuiet && style != STYLE_INVISIBLE && style != STYLE_SEETHROUGH)
do_sparks(5, TRUE, holder) //Create some sparks right before closing
qdel(src) //Delete ourselves and the holder
if (holder != src)
@@ -164,13 +193,14 @@
if (ismob(O) && !isliving(O)) //We dont want to take ghosts with us
continue
O.forceMove(holder) //Put objects inside before we close
var/obj/effect/temp_visual/risingPod = new /obj/effect/temp_visual/DPfall(get_turf(holder), src) //Make a nice animation of flying back up
var/obj/effect/temp_visual/risingPod = new /obj/effect/abstract/DPfall(get_turf(holder), src) //Make a nice animation of flying back up
risingPod.pixel_z = 0 //The initial value of risingPod's pixel_z is 200 because it normally comes down from a high spot
holder.forceMove(bay) //Move the pod back to centcom, where it belongs
animate(risingPod, pixel_z = 200, time = 10, easing = LINEAR_EASING) //Animate our rising pod
QDEL_IN(risingPod, 10)
reversing = FALSE //Now that we're done reversing, we set this to false (otherwise we would get stuck in an infinite loop of calling the close proc at the bottom of open() )
bluespace = TRUE //Make it so that the pod doesn't stay in centcom forever
open(holder, forced = TRUE)
return
/obj/structure/closet/supplypod/proc/setOpened() //Proc exists here, as well as in any atom that can assume the role of a "holder" of a supplypod. Check the open() proc for more details
update_icon()
@@ -179,12 +209,11 @@
update_icon()
/obj/structure/closet/supplypod/Destroy()
if (!opened) //If we havent opened yet, we're opening because we've been destroyed. Lets dump our contents by opening up
open(src, broken = TRUE)
return ..()
open(src, broken = TRUE) //Lets dump our contents by opening up
. = ..()
//------------------------------------FALLING SUPPLY POD-------------------------------------//
/obj/effect/temp_visual/DPfall //Falling pod
/obj/effect/abstract/DPfall //Falling pod
name = ""
icon = 'icons/obj/supplypods.dmi'
pixel_x = -16
@@ -192,17 +221,22 @@
pixel_z = 200
desc = "Get out of the way!"
layer = FLY_LAYER//that wasnt flying, that was falling with style!
randomdir = FALSE
icon_state = ""
/obj/effect/temp_visual/DPfall/Initialize(dropLocation, obj/structure/closet/supplypod/pod)
if (pod.style != STYLE_INVISIBLE) //Check to ensure the pod isn't invisible
/obj/effect/abstract/DPfall/Initialize(dropLocation, obj/structure/closet/supplypod/pod)
if (pod.style == STYLE_SEETHROUGH)
pixel_x = -16
pixel_y = 0
for (var/atom/movable/O in pod.contents)
var/icon/I = getFlatIcon(O) //im so sorry
add_overlay(I)
else if (pod.style != STYLE_INVISIBLE) //Check to ensure the pod isn't invisible
icon_state = "[pod.icon_state]_falling"
name = pod.name
. = ..()
//------------------------------------TEMPORARY_VISUAL-------------------------------------//
/obj/effect/DPtarget //This is the object that forceMoves the supplypod to it's location
/obj/effect/abstract/DPtarget //This is the object that forceMoves the supplypod to it's location
name = "Landing Zone Indicator"
desc = "A holographic projection designating the landing zone of something. It's probably best to stand back."
icon = 'icons/mob/actions/actions_items.dmi'
@@ -212,45 +246,60 @@
var/obj/effect/temp_visual/fallingPod //Temporary "falling pod" that we animate
var/obj/structure/closet/supplypod/pod //The supplyPod that will be landing ontop of this target
/obj/effect/ex_act()
return
/obj/effect/DPtarget/Initialize(mapload, podParam, var/datum/supply_order/SO = null)
/obj/effect/abstract/DPtarget/Initialize(mapload, podParam, single_order = null)
. = ..()
if (ispath(podParam)) //We can pass either a path for a pod (as expressconsoles do), or a reference to an instantiated pod (as the centcom_podlauncher does)
podParam = new podParam() //If its just a path, instantiate it
pod = podParam
if (SO)
SO.generate(pod)
for (var/mob/living/M in podParam) //If there are any mobs in the supplypod, we want to forceMove them into the target. This is so that they can see where they are about to land, AND so that they don't get sent to the nullspace error room (as the pod is currently in nullspace)
if (single_order)
if (istype(single_order, /datum/supply_order))
var/datum/supply_order/SO = single_order
SO.generate(pod)
else if (istype(single_order, /atom/movable))
var/atom/movable/O = single_order
O.forceMove(pod)
for (var/mob/living/M in pod) //If there are any mobs in the supplypod, we want to forceMove them into the target. This is so that they can see where they are about to land, AND so that they don't get sent to the nullspace error room (as the pod is currently in nullspace)
M.forceMove(src)
if(pod.effectStun) //If effectStun is true, stun any mobs caught on this target until the pod gets a chance to hit them
for (var/mob/living/M in get_turf(src))
M.Stun(pod.landingDelay+10, ignore_canstun = TRUE)//you aint goin nowhere, kid.
if (pod.effectStealth) //If effectStealth is true we want to be invisible
alpha = 255
icon_state = ""
if (pod.fallDuration == initial(pod.fallDuration) && pod.landingDelay + pod.fallDuration < pod.fallingSoundLength)
pod.fallingSoundLength = 3 //The default falling sound is a little long, so if the landing time is shorter than the default falling sound, use a special, shorter default falling sound
pod.fallingSound = 'sound/weapons/mortar_whistle.ogg'
var/soundStartTime = pod.landingDelay - pod.fallingSoundLength + pod.fallDuration
if (soundStartTime < 0)
soundStartTime = 1
if (!pod.effectQuiet)
addtimer(CALLBACK(src, .proc/playFallingSound), soundStartTime)
addtimer(CALLBACK(src, .proc/beginLaunch, pod.effectCircle), pod.landingDelay)
/obj/effect/DPtarget/proc/beginLaunch(effectCircle) //Begin the animation for the pod falling. The effectCircle param determines whether the pod gets to come in from any descent angle
fallingPod = new /obj/effect/temp_visual/DPfall(drop_location(), pod)
/obj/effect/abstract/DPtarget/proc/playFallingSound()
playsound(src, pod.fallingSound, pod.soundVolume, 1, 6)
/obj/effect/abstract/DPtarget/proc/beginLaunch(effectCircle) //Begin the animation for the pod falling. The effectCircle param determines whether the pod gets to come in from any descent angle
fallingPod = new /obj/effect/abstract/DPfall(drop_location(), pod)
var/matrix/M = matrix(fallingPod.transform) //Create a new matrix that we can rotate
var/angle = effectCircle ? rand(0,360) : rand(70,110) //The angle that we can come in from
fallingPod.pixel_x = cos(angle)*200 //Use some ADVANCED MATHEMATICS to set the animated pod's position to somewhere on the edge of a circle with the center being the target
fallingPod.pixel_z = sin(angle)*200
fallingPod.pixel_x = cos(angle)*400 //Use some ADVANCED MATHEMATICS to set the animated pod's position to somewhere on the edge of a circle with the center being the target
fallingPod.pixel_z = sin(angle)*400
var/rotation = Get_Pixel_Angle(fallingPod.pixel_z, fallingPod.pixel_x) //CUSTOM HOMEBREWED proc that is just arctan with extra steps
M.Turn(rotation) //Turn our matrix accordingly
fallingPod.transform = M //Transform the animated pod according to the matrix
M = matrix(pod.transform) //Make another matrix based on the pod
M.Turn(rotation) //Turn the matrix
pod.transform = M //Turn the actual pod (Won't be visible until endLaunch() proc tho)
animate(fallingPod, pixel_z = 0, pixel_x = -16, time = 3, , easing = LINEAR_EASING) //Make the pod fall! At an angle!
addtimer(CALLBACK(src, .proc/endLaunch), 3, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation
animate(fallingPod, pixel_z = 0, pixel_x = -16, time = pod.fallDuration, , easing = LINEAR_EASING) //Make the pod fall! At an angle!
addtimer(CALLBACK(src, .proc/endLaunch), pod.fallDuration, TIMER_CLIENT_TIME) //Go onto the last step after a very short falling animation
/obj/effect/DPtarget/proc/endLaunch()
/obj/effect/abstract/DPtarget/proc/endLaunch()
pod.update_icon()
pod.forceMove(drop_location()) //The fallingPod animation is over, now's a good time to forceMove the actual pod into position
QDEL_NULL(fallingPod) //Delete the falling pod effect, because at this point its animation is over. We dont use temp_visual because we want to manually delete it as soon as the pod appears
for (var/mob/living/M in src) //Remember earlier (initialization) when we moved mobs into the DPTarget so they wouldnt get lost in nullspace? Time to get them out
M.forceMove(pod)
pod.preOpen() //Begin supplypod open procedures. Here effects like explosions, damage, and other dangerous (and potentially admin-caused, if the centcom_podlauncher datum was used) memes will take place
QDEL_NULL(fallingPod) //The fallingPod's (the animated effect, not the actual pod) purpose is complete. It can rest easy now
qdel(src) //ditto
//------------------------------------UPGRADES-------------------------------------//
@@ -261,3 +310,4 @@
icon_state = "cargodisk"
item_state = "card-id"
w_class = WEIGHT_CLASS_SMALL
+7
View File
@@ -240,6 +240,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/list/bgstate_options = list("000", "midgrey", "hiro", "FFF", "white", "steel", "techmaint", "dark", "plating", "reinforced")
var/show_mismatched_markings = FALSE //determines whether or not the markings lists should show markings that don't match the currently selected species. Intentionally left unsaved.
var/hide_ckey = FALSE //pref for hiding if your ckey shows round-end or not
/datum/preferences/New(client/C)
parent = C
@@ -368,6 +369,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "[medical_records]"
else
dat += "[TextPreview(medical_records)]...<BR>"
dat += "<br><a href='?_src_=prefs;preference=hide_ckey;task=input'><b>Hide ckey: [hide_ckey ? "Enabled" : "Disabled"]</b></a><br>"
dat += "</tr></table>"
//Character Appearance
@@ -1689,6 +1691,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
msg = msg
features["flavor_text"] = msg
if("hide_ckey")
hide_ckey = !hide_ckey
if(user)
user.mind?.hide_ckey = hide_ckey
if("hair")
var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null
if(new_hair)
+3 -1
View File
@@ -337,7 +337,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_human_ears"] >> features["ears"]
S["feature_deco_wings"] >> features["deco_wings"]
S["hide_ckey"] >> hide_ckey //saved per-character
//Custom names
@@ -591,6 +591,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Record Flavor Text
WRITE_FILE(S["security_records"] , security_records)
WRITE_FILE(S["medical_records"] , medical_records)
//hide c-key
WRITE_FILE(S["hide_ckey"] , hide_ckey)
//Quirks
WRITE_FILE(S["all_quirks"] , all_quirks)
+2 -3
View File
@@ -48,6 +48,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
pull_force = INFINITY
density = TRUE
anchored = TRUE
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
var/mob/living/wizard
var/z_original = 0
var/destination
@@ -103,9 +104,6 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
/obj/effect/immovablerod/ex_act(severity, target)
return 0
/obj/structure/closet/supplypod/prevent_content_explosion()
return TRUE
/obj/effect/immovablerod/singularity_act()
return
@@ -167,3 +165,4 @@ obj/effect/immovablerod/attack_hand(mob/living/user)
new /obj/structure/festivus/anchored(drop_location())
new /obj/effect/anomaly/flux(drop_location())
qdel(src)
+26 -2
View File
@@ -21,7 +21,8 @@ GLOBAL_LIST_INIT(hallucination_list, list(
/datum/hallucination/delusion = 2,
/datum/hallucination/shock = 1,
/datum/hallucination/death = 1,
/datum/hallucination/oh_yeah = 1
/datum/hallucination/oh_yeah = 1,
/datum/hallucination/sleeping_carp = 1
))
@@ -890,7 +891,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
SEND_SOUND(target, 'sound/ai/aimalf.ogg')
if("meteors") //Meteors inbound!
to_chat(target, "<h1 class='alert'>Meteor Alert</h1>")
to_chat(target, "<br><br><span class='alert'>Meteors have been detected on collision course with the station.</span><br><br>")
to_chat(target, "<br><br><span class='alert'>Meteors have been detected on collision course with the station. Estimated time until impact: [round(rand(300,600)/60)] minutes.</span><br><br>")
SEND_SOUND(target, 'sound/ai/meteors.ogg')
if("supermatter")
SEND_SOUND(target, 'sound/magic/charge.ogg')
@@ -1311,3 +1312,26 @@ GLOBAL_LIST_INIT(hallucination_list, list(
H.preparePixelProjectile(target, start)
H.fire()
qdel(src)
/datum/hallucination/sleeping_carp
/datum/hallucination/sleeping_carp/New(mob/living/carbon/C, forced = TRUE)
set waitfor = FALSE
..()
var/list/mobsyup
for (var/mob/living/carbon/A in orange(C,1))
if (get_dist(C,A) < 2)
LAZYADD(mobsyup,A)
if (!LAZYLEN(mobsyup))
qdel(src)
return
var/mob/living/carbon/G = pick(mobsyup)
if (prob(50))
C.visible_message("<span class='warning'>[C] falls to the ground screaming and clutching [C.p_their()] wrist!</span>", \
"<span class='userdanger'>[G] grabs your wrist and violently wrenches it to the side!</span>")
C.emote("scream")
C.dropItemToGround(C.get_active_held_item())
C.Knockdown(60)
else
to_chat(C,"<span class='userdanger'>[G] violently grabs you!</span>")
qdel(src)
+20 -8
View File
@@ -173,7 +173,7 @@
for(var/V in categories)
categories[V] = list()
for(var/V in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[V]
var/datum/design/D = SSresearch.techweb_design_by_id(V)
for(var/C in categories)
if(C in D.category)
categories[C] += D
@@ -185,11 +185,11 @@
dat += "<div class='statusDisplay'>"
for(var/V in categories[cat])
var/datum/design/D = V
dat += "[D.name]: <A href='?src=[REF(src)];create=[REF(D)];amount=1'>Make</A>"
dat += "[D.name]: <A href='?src=[REF(src)];create=[D.id];amount=1'>Make</A>"
if(cat in timesFiveCategories)
dat += "<A href='?src=[REF(src)];create=[REF(D)];amount=5'>x5</A>"
dat += "<A href='?src=[REF(src)];create=[D.id];amount=5'>x5</A>"
if(ispath(D.build_path, /obj/item/stack))
dat += "<A href='?src=[REF(src)];create=[REF(D)];amount=10'>x10</A>"
dat += "<A href='?src=[REF(src)];create=[D.id];amount=10'>x10</A>"
dat += "([D.materials[MAT_BIOMASS]/efficiency])<br>"
dat += "</div>"
else
@@ -210,9 +210,9 @@
var/S = 0
for(var/obj/item/reagent_containers/food/snacks/grown/I in contents)
S += 5
if(I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment) < 0.1)
if(I.reagents.get_reagent_amount("nutriment") < 0.1)
points += 1*productivity
else points += I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment)*10*productivity
else points += I.reagents.get_reagent_amount("nutriment")*10*productivity
qdel(I)
if(S)
processing = TRUE
@@ -306,8 +306,20 @@
var/amount = (text2num(href_list["amount"]))
//Can't be outside these (if you change this keep a sane limit)
amount = CLAMP(amount, 1, 50)
var/datum/design/D = locate(href_list["create"])
create_product(D, amount)
var/id = href_list["create"]
if(!stored_research.researched_designs.Find(id))
//naughty naughty
stack_trace("ID did not map to a researched datum [id]")
return
//Get design by id (or may return error design)
var/datum/design/D = SSresearch.techweb_design_by_id(id)
//Valid design datum, amount and the datum is not the error design, lets proceed
if(D && amount && !istype(D, /datum/design/error_design))
create_product(D, amount)
//This shouldnt happen normally but href forgery is real
else
stack_trace("ID could not be turned into a valid techweb design datum [id]")
updateUsrDialog()
else if(href_list["menu"])
+1 -1
View File
@@ -121,7 +121,7 @@
dat += "<b>Smelt Alloys</b><br>"
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
dat += "<span class=\"res_name\">[D.name] "
if (selected_alloy == D.id)
dat += " <i>Smelting</i>"
+1 -1
View File
@@ -209,7 +209,7 @@
data["alloys"] = list()
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
data["alloys"] += list(list("name" = D.name, "id" = D.id, "amount" = can_smelt_alloy(D)))
if (!mat_container)
+2 -3
View File
@@ -13,6 +13,7 @@
mob_biotypes = list(MOB_SILICON)
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
speech_span = SPAN_ROBOT
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS
var/last_lawchange_announce = 0
@@ -70,9 +71,6 @@
/mob/living/silicon/contents_explosion(severity, target)
return
/mob/living/silicon/prevent_content_explosion()
return TRUE
/mob/living/silicon/proc/cancelAlarm()
return
@@ -411,3 +409,4 @@
/mob/living/silicon/handle_high_gravity(gravity)
return
@@ -37,6 +37,10 @@
icon_state = "mouse_[body_color]"
icon_living = "mouse_[body_color]"
icon_dead = "mouse_[body_color]_dead"
if(name == "mouse") // Faster than checking for mobtypes, just checks if this mouse is a generic mouse.
if(prob(2)) //2% chance to turn a generic mouse into a boommouse
new /mob/living/simple_animal/mouse/boommouse(src.loc)
qdel(src)
/mob/living/simple_animal/mouse/proc/splat()
src.health = 0
@@ -121,3 +125,28 @@
/obj/item/reagent_containers/food/snacks/deadmouse/on_grind()
reagents.clear_reagents()
/mob/living/simple_animal/mouse/boommouse
name = "boommouse" //obviously inspired on rimworld
desc = "A mutated rat with a pack of... Plasma on its back? I wouldn't really touch it if I were you."
icon = 'hyperstation/icons/mob/animal.dmi'
icon_state = "mouse_brown"
icon_living = "mouse_brown"
icon_dead = "mouse_brown_dead"
see_in_dark = 12
maxHealth = 7
health = 7
chew_probability = 0
/mob/living/simple_animal/mouse/boommouse/Initialize()
. = ..()
//Force icons because mouse/initialize randomizes them
icon = 'hyperstation/icons/mob/animal.dmi'
icon_state = "mouse_plasma"
icon_living = "mouse_plasma"
icon_dead = "mouse_plasma" //No need for a dead sprite since it qdels itself on death
/mob/living/simple_animal/mouse/boommouse/death(gibbed, toast)
visible_message("<span class='danger'>The boommouse violently explodes!</span>")
atmos_spawn_air("plasma=15;TEMP=500")
explosion(src.loc, 0, 1, 2, 0, 1, 0, 2, 0, 0)
qdel(src)
@@ -27,6 +27,7 @@
mob_size = MOB_SIZE_LARGE
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
var/list/crusher_loot
var/medal_type
var/score_type = BOSS_SCORE
@@ -44,9 +45,6 @@
QDEL_NULL(internal)
. = ..()
/mob/living/simple_animal/hostile/megafauna/prevent_content_explosion()
return TRUE
/mob/living/simple_animal/hostile/megafauna/death(gibbed)
if(health > 0)
return
@@ -121,9 +119,10 @@
recovery_time = world.time + buffer_time
/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype, scoretype, crusher_kill)
if(!medal_type || (flags_1 & ADMIN_SPAWNED_1) || !SSmedals.hub_enabled) //Don't award medals if the medal type isn't set
if(!medal_type || (flags_1 & ADMIN_SPAWNED_1)) //Don't award medals if the medal type isn't set
return FALSE
if(!SSmedals.hub_enabled) // This allows subtypes to carry on other special rewards not tied with medals. (such as bubblegum's arena shuttle)
return TRUE
for(var/mob/living/L in view(7,src))
if(L.stat || !L.client)
continue
+1
View File
@@ -52,4 +52,5 @@
var/datum/callback/CB = foo
CB.Invoke()
mind?.hide_ckey = client?.prefs?.hide_ckey
log_message("Client [key_name(src)] has taken ownership of mob [src]([src.type])", LOG_OWNERSHIP)
+1 -1
View File
@@ -2,7 +2,7 @@
name = "ninja shoes"
desc = "A pair of running shoes. Excellent for running and even better for smashing skulls."
icon_state = "s-ninja"
item_state = "secshoes"
item_state = "s-ninja"
permeability_coefficient = 0.01
clothing_flags = NOSLIP
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
@@ -78,6 +78,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
icon_state = "darkmatter"
density = TRUE
anchored = TRUE
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
var/uid = 1
var/static/gl_uid = 1
light_range = 4
@@ -728,9 +729,6 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
/obj/machinery/power/supermatter_crystal/contents_explosion(severity, target)
return
/obj/machinery/power/supermatter_crystal/prevent_content_explosion()
return TRUE
/obj/machinery/power/supermatter_crystal/engine
is_main_engine = TRUE
@@ -607,6 +607,17 @@
color = "#F0FFF0"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
toxpwr = 0
overdose_threshold = 40
/datum/reagent/toxin/lipolicide/overdose_process(mob/living/carbon/C)
. = ..()
if(current_cycle >=41 && prob(15))
C.spew_organ()
C.vomit(10, TRUE, TRUE, 4)
to_chat(C, "<span class='userdanger'>You feel something lumpy come up as you vomit.</span>")
if(prob(1))
to_chat(C, "<span class='userdanger'>You feel like your organs are on fire!</span>")
C.IgniteMob()
/datum/reagent/toxin/lipolicide/on_mob_life(mob/living/carbon/M)
if(M.nutrition <= NUTRITION_LEVEL_STARVING)
+10 -26
View File
@@ -79,12 +79,12 @@
/obj/machinery/disposal/attackby(obj/item/I, mob/user, params)
add_fingerprint(user)
if(!pressure_charging && !full_pressure && !flush)
if(istype(I, /obj/item/screwdriver))
if(I.tool_behaviour == TOOL_SCREWDRIVER)
panel_open = !panel_open
I.play_tool_sound(src)
to_chat(user, "<span class='notice'>You [panel_open ? "remove":"attach"] the screws around the power connection.</span>")
return
else if(istype(I, /obj/item/weldingtool) && panel_open)
else if(I.tool_behaviour == TOOL_WELDER && panel_open)
if(!I.tool_start_check(user, amount=0))
return
@@ -99,7 +99,7 @@
return
place_item_in_disposal(I, user)
update_icon()
return 1 //no afterattack
return TRUE //no afterattack
else
return ..()
@@ -283,32 +283,16 @@
var/datum/oracle_ui/themed/nano/ui
obj_flags = CAN_BE_HIT | USES_TGUI | SHOVABLE_ONTO
// attack by item places it in to disposal
/obj/machinery/disposal/bin/attackby(obj/item/I, mob/user, params)
add_fingerprint(user)
if(!pressure_charging && !full_pressure && !flush)
if(I.tool_behaviour == TOOL_SCREWDRIVER)
panel_open = !panel_open
I.play_tool_sound(src)
to_chat(user, "<span class='notice'>You [panel_open ? "remove":"attach"] the screws around the power connection.</span>")
return
else if(I.tool_behaviour == TOOL_WELDER && panel_open)
if(!I.tool_start_check(user, amount=0))
return
to_chat(user, "<span class='notice'>You start slicing the floorweld off \the [src]...</span>")
if(I.use_tool(src, user, 20, volume=100) && panel_open)
to_chat(user, "<span class='notice'>You slice the floorweld off \the [src].</span>")
deconstruct()
return
if(user.a_intent != INTENT_HARM)
if((I.item_flags & ABSTRACT) || !user.temporarilyRemoveItemFromInventory(I))
return
place_item_in_disposal(I, user)
if(istype(I, /obj/item/storage/bag/trash)) //Not doing component overrides because this is a specific type.
var/obj/item/storage/bag/trash/T = I
var/datum/component/storage/STR = T.GetComponent(/datum/component/storage)
to_chat(user, "<span class='warning'>You empty the bag.</span>")
for(var/obj/item/O in T.contents)
STR.remove_from_storage(O,src)
T.update_icon()
update_icon()
return TRUE //no afterattack
else
return ..()
+6 -1
View File
@@ -27,6 +27,7 @@ other types of metals and chemistry for reagents).
*/
//DESIGNS ARE GLOBAL. DO NOT CREATE OR DESTROY THEM AT RUNTIME OUTSIDE OF INIT, JUST REFERENCE THEM TO WHATEVER YOU'RE DOING! //why are you yelling?
//DO NOT REFERENCE OUTSIDE OF SSRESEARCH. USE THE PROCS IN SSRESEARCH TO OBTAIN A REFERENCE.
/datum/design //Datum for object designs, used in construction
var/name = "Name" //Name of the created object.
@@ -48,8 +49,12 @@ other types of metals and chemistry for reagents).
var/research_icon_state
var/icon_cache
/datum/design/error_design
name = "ERROR"
desc = "This usually means something in the database has corrupted. If this doesn't go away automatically, inform Central Command so their techs can fix this ASAP(tm)"
/datum/design/Destroy()
CRASH("DESIGN DATUMS SHOULD NOT EVER BE DESTROYED AS THEY ARE ONLY MEANT TO BE IN A GLOBAL LIST AND REFERENCED FOR US.")
SSresearch.techweb_designs -= id
return ..()
/datum/design/proc/icon_html(client/user)
@@ -102,7 +102,7 @@ Note: Must be placed within 3 tiles of the R&D Console
return FALSE
if (id && id != RESEARCH_MATERIAL_RECLAMATION_ID)
var/datum/techweb_node/TN = get_techweb_node_by_id(id)
var/datum/techweb_node/TN = SSresearch.techweb_node_by_id(id)
if(!istype(TN))
return FALSE
var/dpath = loaded_item.type
@@ -123,7 +123,7 @@ Note: Must be placed within 3 tiles of the R&D Console
return FALSE
SSblackbox.record_feedback("nested tally", "item_deconstructed", 1, list("[TN.id]", "[loaded_item.type]"))
if(destroy_item(loaded_item))
linked_console.stored_research.boost_with_path(SSresearch.techweb_nodes[TN.id], dpath)
linked_console.stored_research.boost_with_path(SSresearch.techweb_node_by_id(TN.id), dpath)
else
var/list/point_value = techweb_item_point_check(loaded_item)
+6 -6
View File
@@ -128,13 +128,13 @@
var/list/res = list("<b><font color='blue'>Already researched:</font></b>")
var/list/boosted = list("<b><font color='red'>Already boosted:</font></b>")
for(var/node_id in listin)
var/datum/techweb_node/N = get_techweb_node_by_id(node_id)
var/datum/techweb_node/N = SSresearch.techweb_node_by_id(node_id)
var/str = "<b>[N.display_name]</b>: [listin[N]] points.</b>"
if(SSresearch.science_tech.researched_nodes[N])
if(SSresearch.science_tech.researched_nodes[N.id])
res += str
else if(SSresearch.science_tech.boosted_nodes[N])
else if(SSresearch.science_tech.boosted_nodes[N.id])
boosted += str
if(SSresearch.science_tech.visible_nodes[N]) //JOY OF DISCOVERY!
if(SSresearch.science_tech.visible_nodes[N.id]) //JOY OF DISCOVERY!
output += str
output += boosted + res
dat += output
@@ -182,10 +182,10 @@
experiment(dotype,process)
use_power(750)
if(dotype != FAIL)
var/list/datum/techweb_node/nodes = techweb_item_boost_check(process)
var/list/nodes = techweb_item_boost_check(process)
var/picked = pickweight(nodes) //This should work.
if(linked_console)
linked_console.stored_research.boost_with_path(picked, process.type)
linked_console.stored_research.boost_with_path(SSresearch.techweb_node_by_id(picked), process.type)
updateUsrDialog()
/obj/machinery/rnd/experimentor/proc/matchReaction(matching,reaction)
@@ -36,7 +36,7 @@
/obj/machinery/rnd/production/proc/update_designs()
cached_designs.Cut()
for(var/i in stored_research.researched_designs)
var/datum/design/d = stored_research.researched_designs[i]
var/datum/design/d = SSresearch.techweb_design_by_id(i)
if((isnull(allowed_department_flags) || (d.departmental_flags & allowed_department_flags)) && (d.build_type & allowed_buildtypes))
cached_designs |= d
@@ -113,7 +113,7 @@
amount = text2num(amount)
if(isnull(amount))
amount = 1
var/datum/design/D = (linked_console || requires_console)? linked_console.stored_research.researched_designs[id] : get_techweb_design_by_id(id)
var/datum/design/D = (linked_console || requires_console)? (linked_console.stored_research.researched_designs[id]? SSresearch.techweb_design_by_id(id) : null) : SSresearch.techweb_design_by_id(id)
if(!istype(D))
return FALSE
if(!(isnull(allowed_department_flags) || (D.departmental_flags & allowed_department_flags)))
@@ -160,7 +160,7 @@
/obj/machinery/rnd/production/proc/search(string)
matching_designs.Cut()
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(!(D.build_type & allowed_buildtypes) || !(isnull(allowed_department_flags) || (D.departmental_flags & allowed_department_flags)))
continue
if(findtext(D.name,string))
@@ -336,7 +336,7 @@
l += "<div class='statusDisplay'><h3>Browsing [selected_category]:</h3>"
var/coeff = efficiency_coeff
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(!(selected_category in D.category)|| !(D.build_type & allowed_buildtypes))
continue
if(!(isnull(allowed_department_flags) || (D.departmental_flags & allowed_department_flags)))
@@ -69,7 +69,7 @@
if(current_category != "Main")
var/list/program_list = list()
for(var/i in linked_techweb.researched_designs)
var/datum/design/nanites/D = linked_techweb.researched_designs[i]
var/datum/design/nanites/D = SSresearch.techweb_design_by_id(i)
if(!istype(D))
continue
if(current_category in D.category)
@@ -116,9 +116,9 @@
disk.program = null
disk.name = initial(disk.name)
. = TRUE
/obj/machinery/nanite_program_hub/admin/Initialize()
. = ..()
linked_techweb = SSresearch.admin_tech
+65 -63
View File
@@ -36,10 +36,10 @@ Nothing else in the console has ID requirements.
var/locked = FALSE
var/tdisk_uple = FALSE
var/ddisk_uple = FALSE
var/datum/techweb_node/selected_node
var/datum/design/selected_design
var/datum/selected_node_id
var/datum/selected_design_id
var/selected_category
var/list/datum/design/matching_designs
var/list/matching_design_ids
var/disk_slot_selected
var/searchstring = ""
var/searchtype = ""
@@ -88,7 +88,7 @@ Nothing else in the console has ID requirements.
. = ..()
stored_research = SSresearch.science_tech
stored_research.consoles_accessing[src] = TRUE
matching_designs = list()
matching_design_ids = list()
SyncRDevices()
/obj/machinery/computer/rdconsole/Destroy()
@@ -109,9 +109,7 @@ Nothing else in the console has ID requirements.
if(d_disk)
d_disk.forceMove(get_turf(src))
d_disk = null
matching_designs = null
selected_node = null
selected_design = null
matching_design_ids = null
return ..()
/obj/machinery/computer/rdconsole/attackby(obj/item/D, mob/user, params)
@@ -144,7 +142,7 @@ Nothing else in the console has ID requirements.
if(!stored_research.available_nodes[id] || stored_research.researched_nodes[id])
say("Node unlock failed: Either already researched or not available!")
return FALSE
var/datum/techweb_node/TN = SSresearch.techweb_nodes[id]
var/datum/techweb_node/TN = SSresearch.techweb_node_by_id(id)
if(!istype(TN))
say("Node unlock failed: Unknown error.")
return FALSE
@@ -153,7 +151,7 @@ Nothing else in the console has ID requirements.
investigate_log("[key_name(user)] researched [id]([json_encode(price)]) on techweb id [stored_research.id].", INVESTIGATE_RESEARCH)
if(stored_research == SSresearch.science_tech)
SSblackbox.record_feedback("associative", "science_techweb_unlock", 1, list("id" = "[id]", "name" = TN.display_name, "price" = "[json_encode(price)]", "time" = SQLtime()))
if(stored_research.research_node(SSresearch.techweb_nodes[id]))
if(stored_research.research_node_id(id))
say("Successfully researched [TN.display_name].")
var/logname = "Unknown"
if(isAI(user))
@@ -280,7 +278,7 @@ Nothing else in the console has ID requirements.
l += ui_protolathe_header()
l += "<div class='statusDisplay'><h3>Browsing [selected_category]:</h3>"
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(!(selected_category in D.category)|| !(D.build_type & PROTOLATHE))
continue
if(!(isnull(linked_lathe.allowed_department_flags) || (D.departmental_flags & linked_lathe.allowed_department_flags)))
@@ -335,7 +333,8 @@ Nothing else in the console has ID requirements.
RDSCREEN_UI_LATHE_CHECK
var/list/l = list()
l += ui_protolathe_header()
for(var/datum/design/D in matching_designs)
for(var/id in matching_design_ids)
var/datum/design/D = SSresearch.techweb_design_by_id(id)
if(!(isnull(linked_lathe.allowed_department_flags) || (D.departmental_flags & linked_lathe.allowed_department_flags)))
continue
var/temp_material
@@ -431,7 +430,7 @@ Nothing else in the console has ID requirements.
l += "<div class='statusDisplay'><h3>Browsing [selected_category]:</h3>"
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(!(selected_category in D.category) || !(D.build_type & IMPRINTER))
continue
if(!(isnull(linked_imprinter.allowed_department_flags) || (D.departmental_flags & linked_imprinter.allowed_department_flags)))
@@ -464,7 +463,8 @@ Nothing else in the console has ID requirements.
l += ui_circuit_header()
l += "<div class='statusDisplay'><h3>Search results:</h3>"
for(var/datum/design/D in matching_designs)
for(var/id in matching_design_ids)
var/datum/design/D = SSresearch.techweb_design_by_id(id)
if(!(isnull(linked_imprinter.allowed_department_flags) || (D.departmental_flags & linked_imprinter.allowed_department_flags)))
continue
var/temp_materials
@@ -524,7 +524,7 @@ Nothing else in the console has ID requirements.
l += "<A href='?src=[REF(src)];copy_tech=1'>Load Technology to Disk</A></div>"
l += "<div class='statusDisplay'><h3>Stored Technology Nodes:</h3>"
for(var/i in t_disk.stored_research.researched_nodes)
var/datum/techweb_node/N = t_disk.stored_research.researched_nodes[i]
var/datum/techweb_node/N = SSresearch.techweb_node_by_id(i)
l += "<A href='?src=[REF(src)];view_node=[i];back_screen=[screen]'>[N.display_name]</A>"
l += "</div>"
return l
@@ -550,7 +550,7 @@ Nothing else in the console has ID requirements.
l += "<A href='?src=[REF(src)];switch_screen=[RDSCREEN_DESIGNDISK];back_screen=[screen]'>Return to Disk Operations</A><div class='statusDisplay'>"
l += "<h3>Load Design to Disk:</h3>"
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
l += "[D.name] "
l += "<A href='?src=[REF(src)];copy_design=[disk_slot_selected];copy_design_ID=[D.id]'>Copy to Disk</A>"
l += "</div>"
@@ -571,7 +571,7 @@ Nothing else in the console has ID requirements.
for(var/id in boostable_nodes)
anything = TRUE
var/list/worth = boostable_nodes[id]
var/datum/techweb_node/N = get_techweb_node_by_id(id)
var/datum/techweb_node/N = SSresearch.techweb_node_by_id(id)
l += "<div class='statusDisplay'>[RDSCREEN_NOBREAK]"
if (stored_research.researched_nodes[N.id]) // already researched
@@ -635,32 +635,33 @@ Nothing else in the console has ID requirements.
var/list/columns = list()
var/max_tier = 0
for (var/node_ in stored_research.tiers)
var/datum/techweb_node/node = node_
var/tier = stored_research.tiers[node]
var/datum/techweb_node/node = SSresearch.techweb_node_by_id(node_)
var/tier = stored_research.tiers[node.id]
LAZYINITLIST(columns["[tier]"]) // String hackery to make the numbers associative
columns["[tier]"] += ui_techweb_single_node(node, minimal=(tier != 1))
max_tier = max(max_tier, tier)
l += "<table><tr><th align='left'>Researched</th><th align='left'>Available</th><th align='left'>Future</th></tr><tr>[RDSCREEN_NOBREAK]"
for(var/tier in 0 to max_tier)
l += "<td valign='top'>[RDSCREEN_NOBREAK]"
l += columns["[tier]"]
l += "</td>[RDSCREEN_NOBREAK]"
if(max_tier)
for(var/tier in 0 to max_tier)
l += "<td valign='top'>[RDSCREEN_NOBREAK]"
l += columns["[tier]"]
l += "</td>[RDSCREEN_NOBREAK]"
l += "</tr></table>[RDSCREEN_NOBREAK]"
else
var/list/avail = list() //This could probably be optimized a bit later.
var/list/unavail = list()
var/list/res = list()
for(var/v in stored_research.researched_nodes)
res += stored_research.researched_nodes[v]
res += SSresearch.techweb_node_by_id(v)
for(var/v in stored_research.available_nodes)
if(stored_research.researched_nodes[v])
continue
avail += stored_research.available_nodes[v]
avail += SSresearch.techweb_node_by_id(v)
for(var/v in stored_research.visible_nodes)
if(stored_research.available_nodes[v])
continue
unavail += stored_research.visible_nodes[v]
unavail += SSresearch.techweb_node_by_id(v)
l += "<h2>Technology Nodes:</h2>[RDSCREEN_NOBREAK]"
l += "<div><h3>Available for Research:</h3>"
for(var/datum/techweb_node/N in avail)
@@ -702,13 +703,14 @@ Nothing else in the console has ID requirements.
l += "<BR><span class='linkOff bad'>[node.price_display(stored_research)]</span>" // red - missing prereqs
if(ui_mode == RDCONSOLE_UI_MODE_NORMAL)
l += "[node.description]"
for(var/i in node.designs)
var/datum/design/D = node.designs[i]
for(var/i in node.design_ids)
var/datum/design/D = SSresearch.techweb_design_by_id(i)
l += "<span data-tooltip='[D.name]' onclick='location=\"?src=[REF(src)];view_design=[i];back_screen=[screen]\"'>[D.icon_html(usr)]</span>[RDSCREEN_NOBREAK]"
l += "</div>[RDSCREEN_NOBREAK]"
return l
/obj/machinery/computer/rdconsole/proc/ui_techweb_nodeview()
var/datum/techweb_node/selected_node = SSresearch.techweb_node_by_id(selected_node_id)
RDSCREEN_UI_SNODE_CHECK
var/list/l = list()
if(stored_research.hidden_nodes[selected_node.id])
@@ -716,65 +718,65 @@ Nothing else in the console has ID requirements.
return
l += "<table><tr>[RDSCREEN_NOBREAK]"
if (length(selected_node.prerequisites))
if (length(selected_node.prereq_ids))
l += "<th align='left'>Requires</th>[RDSCREEN_NOBREAK]"
l += "<th align='left'>Current Node</th>[RDSCREEN_NOBREAK]"
if (length(selected_node.unlocks))
if (length(selected_node.unlock_ids))
l += "<th align='left'>Unlocks</th>[RDSCREEN_NOBREAK]"
l += "</tr><tr>[RDSCREEN_NOBREAK]"
if (length(selected_node.prerequisites))
if (length(selected_node.unlock_ids))
l += "<td valign='top'>[RDSCREEN_NOBREAK]"
for (var/i in selected_node.prerequisites)
l += ui_techweb_single_node(selected_node.prerequisites[i])
for (var/i in selected_node.prereq_ids)
l += ui_techweb_single_node(SSresearch.techweb_node_by_id(i))
l += "</td>[RDSCREEN_NOBREAK]"
l += "<td valign='top'>[RDSCREEN_NOBREAK]"
l += ui_techweb_single_node(selected_node, selflink=FALSE)
l += "</td>[RDSCREEN_NOBREAK]"
if (length(selected_node.unlocks))
if (length(selected_node.unlock_ids))
l += "<td valign='top'>[RDSCREEN_NOBREAK]"
for (var/i in selected_node.unlocks)
l += ui_techweb_single_node(selected_node.unlocks[i])
for (var/i in selected_node.unlock_ids)
l += ui_techweb_single_node(SSresearch.techweb_node_by_id(i))
l += "</td>[RDSCREEN_NOBREAK]"
l += "</tr></table>[RDSCREEN_NOBREAK]"
return l
/obj/machinery/computer/rdconsole/proc/ui_techweb_designview() //Legacy code
var/datum/design/selected_design = SSresearch.techweb_design_by_id(selected_design_id)
RDSCREEN_UI_SDESIGN_CHECK
var/list/l = list()
var/datum/design/D = selected_design
l += "<div><table><tr><td>[D.icon_html(usr)]</td><td><b>[D.name]</b></td></tr></table>[RDSCREEN_NOBREAK]"
if(D.build_type)
l += "<div><table><tr><td>[selected_design.icon_html(usr)]</td><td><b>[selected_design.name]</b></td></tr></table>[RDSCREEN_NOBREAK]"
if(selected_design.build_type)
var/lathes = list()
if(D.build_type & IMPRINTER)
if(selected_design.build_type & IMPRINTER)
lathes += "<span data-tooltip='Circuit Imprinter'>[machine_icon(/obj/machinery/rnd/production/circuit_imprinter)]</span>[RDSCREEN_NOBREAK]"
if (linked_imprinter && D.id in stored_research.researched_designs)
l += "<A href='?src=[REF(src)];search=1;type=imprint;to_search=[D.name]'>Imprint</A>"
if(D.build_type & PROTOLATHE)
if (linked_imprinter && stored_research.researched_designs[selected_design.id])
l += "<A href='?src=[REF(src)];search=1;type=imprint;to_search=[selected_design.name]'>Imprint</A>"
if(selected_design.build_type & PROTOLATHE)
lathes += "<span data-tooltip='Protolathe'>[machine_icon(/obj/machinery/rnd/production/protolathe)]</span>[RDSCREEN_NOBREAK]"
if (linked_lathe && D.id in stored_research.researched_designs)
l += "<A href='?src=[REF(src)];search=1;type=proto;to_search=[D.name]'>Construct</A>"
if(D.build_type & AUTOLATHE)
if (linked_lathe && stored_research.researched_designs[selected_design.id])
l += "<A href='?src=[REF(src)];search=1;type=proto;to_search=[selected_design.name]'>Construct</A>"
if(selected_design.build_type & AUTOLATHE)
lathes += "<span data-tooltip='Autolathe'>[machine_icon(/obj/machinery/autolathe)]</span>[RDSCREEN_NOBREAK]"
if(D.build_type & MECHFAB)
if(selected_design.build_type & MECHFAB)
lathes += "<span data-tooltip='Exosuit Fabricator'>[machine_icon(/obj/machinery/mecha_part_fabricator)]</span>[RDSCREEN_NOBREAK]"
if(D.build_type & BIOGENERATOR)
if(selected_design.build_type & BIOGENERATOR)
lathes += "<span data-tooltip='Biogenerator'>[machine_icon(/obj/machinery/biogenerator)]</span>[RDSCREEN_NOBREAK]"
if(D.build_type & LIMBGROWER)
if(selected_design.build_type & LIMBGROWER)
lathes += "<span data-tooltip='Limbgrower'>[machine_icon(/obj/machinery/limbgrower)]</span>[RDSCREEN_NOBREAK]"
if(D.build_type & SMELTER)
if(selected_design.build_type & SMELTER)
lathes += "<span data-tooltip='Smelter'>[machine_icon(/obj/machinery/mineral/processing_unit)]</span>[RDSCREEN_NOBREAK]"
l += "Construction types:"
l += lathes
l += ""
l += "Required materials:"
var/all_mats = D.materials + D.reagents_list
var/all_mats = selected_design.materials + selected_design.reagents_list
for(var/M in all_mats)
l += "* [CallMaterialName(M)] x [all_mats[M]]"
l += "Unlocked by:"
for (var/node in D.unlocked_by)
l += ui_techweb_single_node(node)
for (var/i in selected_design.unlocked_by)
l += ui_techweb_single_node(SSresearch.techweb_node_by_id(i))
l += "[RDSCREEN_NOBREAK]</div>"
return l
@@ -965,7 +967,7 @@ Nothing else in the console has ID requirements.
qdel(t_disk.stored_research)
t_disk.stored_research = new
say("Wiping technology disk.")
if(ls["copy_tech"]) //Copy some technology la from the research holder to the disk.
if(ls["copy_tech"]) //Copy some technology from the research holder to the disk.
if(QDELETED(t_disk))
say("No Technology Disk Inserted!")
return
@@ -999,12 +1001,12 @@ Nothing else in the console has ID requirements.
return
say("Uploading technology disk.")
t_disk.stored_research.copy_research_to(stored_research)
if(ls["copy_design"]) //Copy design la from the research holder to the design disk.
if(ls["copy_design"]) //Copy design from the research holder to the design disk.
if(QDELETED(d_disk))
say("No Design Disk Inserted!")
return
var/slot = text2num(ls["copy_design"])
var/datum/design/D = stored_research.researched_designs[ls["copy_design_ID"]]
var/datum/design/D = SSresearch.techweb_design_by_id(ls["copy_design_ID"])
if(D)
var/autolathe_friendly = TRUE
if(D.reagents_list.len)
@@ -1031,12 +1033,12 @@ Nothing else in the console has ID requirements.
linked_destroy.unload_item()
screen = RDSCREEN_MENU
if(ls["view_node"])
selected_node = SSresearch.techweb_nodes[ls["view_node"]]
selected_node_id = ls["view_node"]
screen = RDSCREEN_TECHWEB_NODEVIEW
if(ls["view_design"])
selected_design = SSresearch.techweb_designs[ls["view_design"]]
selected_design_id = ls["view_design"]
screen = RDSCREEN_TECHWEB_DESIGNVIEW
if(ls["updt_design"]) //Uples the research holder with design la from the design disk.
if(ls["updt_design"]) //Uploads a design from disk to the techweb.
if(QDELETED(d_disk))
say("No design disk found.")
return
@@ -1044,9 +1046,9 @@ Nothing else in the console has ID requirements.
if(!n)
for(var/D in d_disk.blueprints)
if(D)
stored_research.add_design(D)
stored_research.add_design(D, TRUE)
else
stored_research.add_design(d_disk.blueprints[n])
stored_research.add_design(d_disk.blueprints[n], TRUE)
updateUsrDialog()
@@ -1075,17 +1077,17 @@ Nothing else in the console has ID requirements.
/obj/machinery/computer/rdconsole/proc/rescan_views()
var/compare
matching_designs.Cut()
matching_design_ids.Cut()
if(searchtype == "proto")
compare = PROTOLATHE
else if(searchtype == "imprint")
compare = IMPRINTER
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(!(D.build_type & compare))
continue
if(findtext(D.name,searchstring))
matching_designs.Add(D)
matching_design_ids.Add(D.id)
/obj/machinery/computer/rdconsole/proc/check_canprint(datum/design/D, buildtype)
var/amount = 50
@@ -1,48 +1,3 @@
/proc/initialize_all_techweb_nodes(clearall = FALSE)
if(islist(SSresearch.techweb_nodes) && clearall)
QDEL_LIST(SSresearch.techweb_nodes)
if(islist(SSresearch.techweb_nodes_starting && clearall))
QDEL_LIST(SSresearch.techweb_nodes_starting)
var/list/returned = list()
for(var/path in subtypesof(/datum/techweb_node))
var/datum/techweb_node/TN = path
if(isnull(initial(TN.id)))
continue
TN = new path
if(returned[initial(TN.id)])
stack_trace("WARNING: Techweb node ID clash with ID [initial(TN.id)] detected!")
SSresearch.errored_datums[TN] = initial(TN.id)
continue
returned[initial(TN.id)] = TN
if(TN.starting_node)
SSresearch.techweb_nodes_starting[TN.id] = TN
SSresearch.techweb_nodes = returned
verify_techweb_nodes() //Verify all nodes have ids and such.
calculate_techweb_nodes()
calculate_techweb_boost_list()
verify_techweb_nodes() //Verify nodes and designs have been crosslinked properly.
/proc/initialize_all_techweb_designs(clearall = FALSE)
if(islist(SSresearch.techweb_designs) && clearall)
QDEL_LIST(SSresearch.techweb_designs)
var/list/returned = list()
for(var/path in subtypesof(/datum/design))
var/datum/design/DN = path
if(isnull(initial(DN.id)))
stack_trace("WARNING: Design with null ID detected. Build path: [initial(DN.build_path)]")
continue
else if(initial(DN.id) == DESIGN_ID_IGNORE)
continue
DN = new path
if(returned[initial(DN.id)])
stack_trace("WARNING: Design ID clash with ID [initial(DN.id)] detected!")
SSresearch.errored_datums[DN] = initial(DN.id)
continue
returned[initial(DN.id)] = DN
SSresearch.techweb_designs = returned
verify_techweb_designs()
/proc/count_unique_techweb_nodes()
var/static/list/L = typesof(/datum/techweb_node)
return L.len
@@ -51,135 +6,10 @@
var/static/list/L = typesof(/datum/design)
return L.len
/proc/get_techweb_node_by_id(id)
if(SSresearch.techweb_nodes[id])
return SSresearch.techweb_nodes[id]
/proc/get_techweb_design_by_id(id)
if(SSresearch.techweb_designs[id])
return SSresearch.techweb_designs[id]
/proc/research_node_id_error(id)
if(SSresearch.invalid_node_ids[id])
SSresearch.invalid_node_ids[id]++
else
SSresearch.invalid_node_ids[id] = 1
/proc/design_id_error(id)
if(SSresearch.invalid_design_ids[id])
SSresearch.invalid_design_ids[id]++
else
SSresearch.invalid_design_ids[id] = 1
/proc/node_boost_error(id, message)
WARNING("Invalid boost information for node \[[id]\]: [message]")
SSresearch.invalid_node_boost[id] = message
/proc/verify_techweb_nodes()
for(var/n in SSresearch.techweb_nodes)
var/datum/techweb_node/N = SSresearch.techweb_nodes[n]
if(!istype(N))
WARNING("Invalid research node with ID [n] detected and removed.")
SSresearch.techweb_nodes -= n
research_node_id_error(n)
for(var/p in N.prereq_ids)
var/datum/techweb_node/P = SSresearch.techweb_nodes[p]
if(!istype(P))
WARNING("Invalid research prerequisite node with ID [p] detected in node [N.display_name]\[[N.id]\] removed.")
N.prereq_ids -= p
research_node_id_error(p)
for(var/d in N.design_ids)
var/datum/design/D = SSresearch.techweb_designs[d]
if(!istype(D))
WARNING("Invalid research design with ID [d] detected in node [N.display_name]\[[N.id]\] removed.")
N.designs -= d
design_id_error(d)
for(var/p in N.prerequisites)
var/datum/techweb_node/P = N.prerequisites[p]
if(!istype(P))
WARNING("Invalid research prerequisite node with ID [p] detected in node [N.display_name]\[[N.id]\] removed.")
N.prerequisites -= p
research_node_id_error(p)
for(var/u in N.unlocks)
var/datum/techweb_node/U = N.unlocks[u]
if(!istype(U))
WARNING("Invalid research unlock node with ID [u] detected in node [N.display_name]\[[N.id]\] removed.")
N.unlocks -= u
research_node_id_error(u)
for(var/d in N.designs)
var/datum/design/D = N.designs[d]
if(!istype(D))
WARNING("Invalid research design with ID [d] detected in node [N.display_name]\[[N.id]\] removed.")
N.designs -= d
design_id_error(d)
for(var/p in N.boost_item_paths)
if(!ispath(p))
N.boost_item_paths -= p
node_boost_error(N.id, "[p] is not a valid path.")
var/list/points = N.boost_item_paths[p]
if(islist(points))
for(var/i in points)
if(!isnum(points[i]))
node_boost_error(N.id, "[points[i]] is not a valid number.")
else if(!SSresearch.point_types[i])
node_boost_error(N.id, "[i] is not a valid point type.")
else if(!isnull(points))
N.boost_item_paths -= p
node_boost_error(N.id, "No valid list.")
CHECK_TICK
/proc/verify_techweb_designs()
for(var/d in SSresearch.techweb_designs)
var/datum/design/D = SSresearch.techweb_designs[d]
if(!istype(D))
stack_trace("WARNING: Invalid research design with ID [d] detected and removed.")
SSresearch.techweb_designs -= d
CHECK_TICK
/proc/calculate_techweb_nodes()
for(var/design_id in SSresearch.techweb_designs)
var/datum/design/D = SSresearch.techweb_designs[design_id]
D.unlocked_by.Cut()
for(var/node_id in SSresearch.techweb_nodes)
var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id]
node.prerequisites = list()
node.unlocks = list()
node.designs = list()
for(var/i in node.prereq_ids)
node.prerequisites[i] = SSresearch.techweb_nodes[i]
for(var/i in node.design_ids)
var/datum/design/D = SSresearch.techweb_designs[i]
node.designs[i] = D
D.unlocked_by += node
if(node.hidden)
SSresearch.techweb_nodes_hidden[node.id] = node
CHECK_TICK
generate_techweb_unlock_linking()
/proc/generate_techweb_unlock_linking()
for(var/node_id in SSresearch.techweb_nodes) //Clear all unlock links to avoid duplication.
var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id]
node.unlocks = list()
for(var/node_id in SSresearch.techweb_nodes)
var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id]
for(var/prereq_id in node.prerequisites)
var/datum/techweb_node/prereq_node = node.prerequisites[prereq_id]
prereq_node.unlocks[node.id] = node
/proc/calculate_techweb_boost_list(clearall = FALSE)
if(clearall)
SSresearch.techweb_boost_items = list()
for(var/node_id in SSresearch.techweb_nodes)
var/datum/techweb_node/node = SSresearch.techweb_nodes[node_id]
for(var/path in node.boost_item_paths)
if(!ispath(path))
continue
if(length(SSresearch.techweb_boost_items[path]))
SSresearch.techweb_boost_items[path][node.id] = node.boost_item_paths[path]
else
SSresearch.techweb_boost_items[path] = list(node.id = node.boost_item_paths[path])
CHECK_TICK
/proc/techweb_item_boost_check(obj/item/I) //Returns an associative list of techweb node datums with values of the boost it gives. var/list/returned = list()
if(SSresearch.techweb_boost_items[I.type])
return SSresearch.techweb_boost_items[I.type] //It should already be formatted in node datum = list(point type = value)
+69 -62
View File
@@ -5,12 +5,13 @@
//Techweb datums are meant to store unlocked research, being able to be stored on research consoles, servers, and disks. They are NOT global.
/datum/techweb
var/list/datum/techweb_node/researched_nodes = list() //Already unlocked and all designs are now available. Assoc list, id = datum
var/list/datum/techweb_node/visible_nodes = list() //Visible nodes, doesn't mean it can be researched. Assoc list, id = datum
var/list/datum/techweb_node/available_nodes = list() //Nodes that can immediately be researched, all reqs met. assoc list, id = datum
var/list/datum/design/researched_designs = list() //Designs that are available for use. Assoc list, id = datum
var/list/datum/techweb_node/boosted_nodes = list() //Already boosted nodes that can't be boosted again. node datum = path of boost object.
var/list/datum/techweb_node/hidden_nodes = list() //Hidden nodes. id = datum. Used for unhiding nodes when requirements are met by removing the entry of the node.
var/list/researched_nodes = list() //Already unlocked and all designs are now available. Assoc list, id = TRUE
var/list/visible_nodes = list() //Visible nodes, doesn't mean it can be researched. Assoc list, id = TRUE
var/list/available_nodes = list() //Nodes that can immediately be researched, all reqs met. assoc list, id = TRUE
var/list/researched_designs = list() //Designs that are available for use. Assoc list, id = TRUE
var/list/custom_designs = list() //Custom inserted designs like from disks that should survive recalculation.
var/list/boosted_nodes = list() //Already boosted nodes that can't be boosted again. node id = path of boost object.
var/list/hidden_nodes = list()
var/list/deconstructed_items = list() //items already deconstructed for a generic point boost. path = list(point_type = points)
var/list/research_points = list() //Available research points. type = number
var/list/obj/machinery/computer/rdconsole/consoles_accessing = list()
@@ -20,13 +21,13 @@
var/organization = "Third-Party" //Organization name, used for display.
var/list/last_bitcoins = list() //Current per-second production, used for display only.
var/list/discovered_mutations = list() //Mutations discovered by genetics, this way they are shared and cant be destroyed by destroying a single console
var/list/tiers = list() //Assoc list, datum = number, 1 is available, 2 is all reqs are 1, so on
var/list/tiers = list() //Assoc list, id = number, 1 is available, 2 is all reqs are 1, so on
/datum/techweb/New()
for(var/i in SSresearch.techweb_nodes_starting)
var/datum/techweb_node/DN = SSresearch.techweb_nodes_starting[i]
var/datum/techweb_node/DN = SSresearch.techweb_node_by_id(i)
research_node(DN, TRUE, FALSE)
hidden_nodes = SSresearch.techweb_nodes_hidden
hidden_nodes = SSresearch.techweb_nodes_hidden.Copy()
return ..()
/datum/techweb/admin
@@ -59,23 +60,24 @@
researched_designs = null
available_nodes = null
visible_nodes = null
custom_designs = null
SSresearch.techwebs -= src
return ..()
/datum/techweb/proc/recalculate_nodes(recalculate_designs = FALSE)
/datum/techweb/proc/recalculate_nodes(recalculate_designs = FALSE, wipe_custom_designs = FALSE)
var/list/datum/techweb_node/processing = list()
for(var/i in researched_nodes)
processing[i] = researched_nodes[i]
for(var/i in visible_nodes)
processing[i] = visible_nodes[i]
for(var/i in available_nodes)
processing[i] = available_nodes[i]
for(var/i in processing)
update_node_status(processing[i])
if(recalculate_designs) //Wipes custom added designs like from design disks or anything like that!
researched_designs = list()
for(var/i in processing)
var/datum/techweb_node/TN = processing[i]
update_node_status(TN, FALSE)
for(var/id in researched_nodes)
processing[id] = TRUE
for(var/id in visible_nodes)
processing[id] = TRUE
for(var/id in available_nodes)
processing[id] = TRUE
if(recalculate_designs)
researched_designs = custom_designs.Copy()
if(wipe_custom_designs)
custom_designs = list()
for(var/id in processing)
update_node_status(SSresearch.techweb_node_by_id(id), FALSE)
CHECK_TICK
for(var/v in consoles_accessing)
var/obj/machinery/computer/rdconsole/V = v
@@ -165,21 +167,27 @@
research_points[type] = max(0, research_points[type] - amount)
return TRUE
/datum/techweb/proc/add_design_by_id(id)
return add_design(get_techweb_design_by_id(id))
/datum/techweb/proc/add_design_by_id(id, custom = FALSE)
return add_design(SSresearch.techweb_design_by_id(id), custom)
/datum/techweb/proc/add_design(datum/design/design)
/datum/techweb/proc/add_design(datum/design/design, custom = FALSE)
if(!istype(design))
return FALSE
researched_designs[design.id] = design
researched_designs[design.id] = TRUE
if(custom)
custom_designs[design.id] = TRUE
return TRUE
/datum/techweb/proc/remove_design_by_id(id)
return remove_design(get_techweb_design_by_id(id))
/datum/techweb/proc/remove_design_by_id(id, custom = FALSE)
return remove_design(SSresearch.techweb_design_by_id(id), custom)
/datum/techweb/proc/remove_design(datum/design/design)
/datum/techweb/proc/remove_design(datum/design/design, custom = FALSE)
if(!istype(design))
return FALSE
if(custom_designs[design.id] && !custom)
return FALSE
custom_designs -= design.id
researched_designs -= design.id
return TRUE
@@ -193,7 +201,7 @@
return techweb_point_display_generic(research_points)
/datum/techweb/proc/research_node_id(id, force, auto_update_points)
return research_node(get_techweb_node_by_id(id), force, auto_update_points)
return research_node(SSresearch.techweb_node_by_id(id), force, auto_update_points)
/datum/techweb/proc/research_node(datum/techweb_node/node, force = FALSE, auto_adjust_cost = TRUE)
if(!istype(node))
@@ -204,17 +212,17 @@
return FALSE
if(auto_adjust_cost)
remove_point_list(node.get_price(src))
researched_nodes[node.id] = node //Add to our researched list
for(var/i in node.unlocks)
visible_nodes[i] = node.unlocks[i]
update_node_status(node.unlocks[i])
for(var/i in node.designs)
add_design(node.designs[i])
researched_nodes[node.id] = TRUE //Add to our researched list
for(var/id in node.unlock_ids)
visible_nodes[id] = TRUE
update_node_status(SSresearch.techweb_node_by_id(id))
for(var/id in node.design_ids)
add_design_by_id(id)
update_node_status(node)
return TRUE
/datum/techweb/proc/unresearch_node_id(id)
return unresearch_node(get_techweb_node_by_id(id))
return unresearch_node(SSresearch.techweb_node_by_id(id))
/datum/techweb/proc/unresearch_node(datum/techweb_node/node)
if(!istype(node))
@@ -225,9 +233,9 @@
/datum/techweb/proc/boost_with_path(datum/techweb_node/N, itempath)
if(!istype(N) || !ispath(itempath))
return FALSE
LAZYINITLIST(boosted_nodes[N])
LAZYINITLIST(boosted_nodes[N.id])
for(var/i in N.boost_item_paths[itempath])
boosted_nodes[N][i] = max(boosted_nodes[N][i], N.boost_item_paths[itempath][i])
boosted_nodes[N.id][i] = max(boosted_nodes[N.id][i], N.boost_item_paths[itempath][i])
if(N.autounlock_by_boost)
hidden_nodes -= N.id
update_node_status(N)
@@ -242,13 +250,13 @@
var/tier = 0
if (!researched_nodes[node.id]) // researched is tier 0
for (var/id in node.prereq_ids)
var/prereq_tier = tiers[node.prerequisites[id]]
var/prereq_tier = tiers[id]
tier = max(tier, prereq_tier + 1)
if (tier != tiers[node])
tiers[node] = tier
for (var/id in node.unlocks)
next += node.unlocks[id]
if (tier != tiers[node.id])
tiers[node.id] = tier
for (var/id in node.unlock_ids)
next += SSresearch.techweb_node_by_id(id)
current = next
/datum/techweb/proc/update_node_status(datum/techweb_node/node, autoupdate_consoles = TRUE)
@@ -258,8 +266,8 @@
if(researched_nodes[node.id])
researched = TRUE
var/needed = node.prereq_ids.len
for(var/i in node.prereq_ids)
if(researched_nodes[i])
for(var/id in node.prereq_ids)
if(researched_nodes[id])
visible = TRUE
needed--
if(!needed)
@@ -270,15 +278,15 @@
if(hidden_nodes[node.id]) //Hidden.
return
if(researched)
researched_nodes[node.id] = node
for(var/i in node.designs)
add_design(node.designs[i])
researched_nodes[node.id] = TRUE
for(var/id in node.design_ids)
add_design(SSresearch.techweb_design_by_id(id))
else
if(available)
available_nodes[node.id] = node
available_nodes[node.id] = TRUE
else
if(visible)
visible_nodes[node.id] = node
visible_nodes[node.id] = TRUE
update_tiers(node)
if(autoupdate_consoles)
for(var/v in consoles_accessing)
@@ -289,35 +297,34 @@
//Laggy procs to do specific checks, just in case. Don't use them if you can just use the vars that already store all this!
/datum/techweb/proc/designHasReqs(datum/design/D)
for(var/i in researched_nodes)
var/datum/techweb_node/N = researched_nodes[i]
for(var/I in N.designs)
if(D == N.designs[I])
return TRUE
var/datum/techweb_node/N = SSresearch.techweb_node_by_id(i)
if(N.design_ids[D.id])
return TRUE
return FALSE
/datum/techweb/proc/isDesignResearched(datum/design/D)
return isDesignResearchedID(D.id)
/datum/techweb/proc/isDesignResearchedID(id)
return researched_designs[id]
return researched_designs[id]? SSresearch.techweb_design_by_id(id) : FALSE
/datum/techweb/proc/isNodeResearched(datum/techweb_node/N)
return isNodeResearchedID(N.id)
/datum/techweb/proc/isNodeResearchedID(id)
return researched_nodes[id]
return researched_nodes[id]? SSresearch.techweb_design_by_id(id) : FALSE
/datum/techweb/proc/isNodeVisible(datum/techweb_node/N)
return isNodeResearchedID(N.id)
/datum/techweb/proc/isNodeVisibleID(id)
return visible_nodes[id]
return visible_nodes[id]? SSresearch.techweb_design_by_id(id) : FALSE
/datum/techweb/proc/isNodeAvailable(datum/techweb_node/N)
return isNodeAvailableID(N.id)
/datum/techweb/proc/isNodeAvailableID(id)
return available_nodes[id]
return available_nodes[id]? SSresearch.techweb_design_by_id(id) : FALSE
/datum/techweb/specialized
var/allowed_buildtypes = ALL
@@ -340,11 +347,11 @@
for(var/id in node_autounlock_ids)
research_node_id(id, TRUE, FALSE)
for(var/id in SSresearch.techweb_designs)
var/datum/design/D = SSresearch.techweb_designs[id]
var/datum/design/D = SSresearch.techweb_design_by_id(id)
if(D.build_type & design_autounlock_buildtypes)
for(var/i in D.category)
if(i in design_autounlock_categories)
add_design(D)
add_design_by_id(D.id)
break
/datum/techweb/specialized/autounlocking/autolathe
@@ -368,4 +375,4 @@
/datum/techweb/specialized/autounlocking/autobottler
design_autounlock_buildtypes = AUTOBOTTLER
allowed_buildtypes = AUTOBOTTLER
allowed_buildtypes = AUTOBOTTLER
+71 -6
View File
@@ -9,20 +9,85 @@
var/starting_node = FALSE //Whether it's available without any research.
var/list/prereq_ids = list()
var/list/design_ids = list()
var/list/datum/techweb_node/prerequisites = list() //Assoc list id = datum
var/list/datum/techweb_node/unlocks = list() //CALCULATED FROM OTHER NODE'S PREREQUISITES. Assoc list id = datum.
var/list/datum/design/designs = list() //Assoc list id = datum
var/list/unlock_ids = list()
var/list/boost_item_paths = list() //Associative list, path = list(point type = point_value).
var/autounlock_by_boost = TRUE //boosting this will autounlock this node.
var/export_price = 0 //Cargo export price.
var/list/research_costs = 0 //Point cost to research. type = amount
var/list/research_costs = list() //Point cost to research. type = amount
var/category = "Misc" //Category
/datum/techweb_node/error_node
id = "ERROR"
display_name = "ERROR"
description = "This usually means something in the database has corrupted. If it doesn't go away automatically, inform Central Command for their techs to fix it ASAP(tm)"
/datum/techweb_node/proc/Initialize()
//Make lists associative for lookup
for(var/id in prereq_ids)
prereq_ids[id] = TRUE
for(var/id in design_ids)
design_ids[id] = TRUE
for(var/id in unlock_ids)
unlock_ids[id] = TRUE
/datum/techweb_node/Destroy()
SSresearch.techweb_nodes -= id
return ..()
/datum/techweb_node/serialize_list(list/options)
. = list()
VARSET_TO_LIST(., id)
VARSET_TO_LIST(., display_name)
VARSET_TO_LIST(., hidden)
VARSET_TO_LIST(., starting_node)
VARSET_TO_LIST(., assoc_list_strip_value(prereq_ids))
VARSET_TO_LIST(., assoc_list_strip_value(design_ids))
VARSET_TO_LIST(., assoc_list_strip_value(unlock_ids))
VARSET_TO_LIST(., boost_item_paths)
VARSET_TO_LIST(., autounlock_by_boost)
VARSET_TO_LIST(., export_price)
VARSET_TO_LIST(., research_costs)
VARSET_TO_LIST(., category)
/datum/techweb_node/deserialize_list(list/input, list/options)
if(!input["id"])
return
VARSET_FROM_LIST(input, id)
VARSET_FROM_LIST(input, display_name)
VARSET_FROM_LIST(input, hidden)
VARSET_FROM_LIST(input, starting_node)
VARSET_FROM_LIST(input, prereq_ids)
VARSET_FROM_LIST(input, design_ids)
VARSET_FROM_LIST(input, unlock_ids)
VARSET_FROM_LIST(input, boost_item_paths)
VARSET_FROM_LIST(input, autounlock_by_boost)
VARSET_FROM_LIST(input, export_price)
VARSET_FROM_LIST(input, research_costs)
VARSET_FROM_LIST(input, category)
Initialize()
return src
/datum/techweb_node/proc/on_design_deletion(datum/design/D)
prune_design_id(D.id)
/datum/techweb_node/proc/on_node_deletion(datum/techweb_node/TN)
prune_node_id(TN.id)
/datum/techweb_node/proc/prune_design_id(design_id)
design_ids -= design_id
/datum/techweb_node/proc/prune_node_id(node_id)
prereq_ids -= node_id
unlock_ids -= node_id
/datum/techweb_node/proc/get_price(datum/techweb/host)
if(host)
var/list/actual_costs = research_costs
if(host.boosted_nodes[src])
var/list/L = host.boosted_nodes[src]
if(host.boosted_nodes[id])
var/list/L = host.boosted_nodes[id]
for(var/i in L)
if(actual_costs[i])
actual_costs[i] -= L[i]
+12 -10
View File
@@ -255,10 +255,21 @@
display_name = "Games and Toys"
description = "For the slackers on the station."
prereq_ids = list("comptech")
design_ids = list("arcade_battle", "arcade_orion", "slotmachine", "autoylathe")
design_ids = list("arcade_battle", "arcade_orion", "arcade_minesweeper", "slotmachine", "autoylathe")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000)
export_price = 5000
///datum/techweb_node/computer_board_gaming
// id = "computer_board_gaming"
// display_name = "Arcade Games"
// description = "For the slackers on the station."
// prereq_ids = list("comptech")
// design_ids = list("arcade_battle", "arcade_orion", "slotmachine") // Magic money
// research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500)
// export_price = 2000
/////////////////////////Bluespace tech/////////////////////////
/datum/techweb_node/bluespace_basic //Bluespace-memery
id = "bluespace_basic"
@@ -485,15 +496,6 @@
"portadrive_basic", "portadrive_advanced", "portadrive_super", "cardslot", "aislot", "miniprinter", "APClink", "bat_control", "bat_normal", "bat_advanced",
"bat_super", "bat_micro", "bat_nano", "cpu_normal", "pcpu_normal", "cpu_small", "pcpu_small")
/datum/techweb_node/computer_board_gaming
id = "computer_board_gaming"
display_name = "Arcade Games"
description = "For the slackers on the station."
prereq_ids = list("comptech")
design_ids = list("arcade_battle", "arcade_orion", "slotmachine") // Magic money
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500)
export_price = 2000
/datum/techweb_node/comp_recordkeeping
id = "comp_recordkeeping"
display_name = "Computerized Recordkeeping"
+6 -3
View File
@@ -29,7 +29,8 @@
icon_state = "retractor_a"
/obj/item/retractor/advanced/examine(mob/living/user)
to_chat(user, "<span class = 'notice> It resembles a retractor[tool_behaviour == TOOL_RETRACTOR ? "retractor" : "hemostat"]. </span>")
. = ..()
. += "<span class = 'notice> It resembles a [tool_behaviour == TOOL_RETRACTOR ? "retractor" : "hemostat"]. </span>"
/obj/item/retractor/augment
name = "retractor"
@@ -131,7 +132,8 @@
icon_state = "surgicaldrill_a"
/obj/item/surgicaldrill/advanced/examine(mob/living/user)
to_chat(user, "<span class = 'notice> It's set to [tool_behaviour == TOOL_DRILL ? "drilling" : "mending"] mode.</span>")
. = ..()
. += "<span class = 'notice> It's set to [tool_behaviour == TOOL_DRILL ? "drilling" : "mending"] mode.</span>"
/obj/item/surgicaldrill/augment
name = "surgical drill"
@@ -203,7 +205,8 @@
icon_state = "scalpel_a"
/obj/item/scalpel/advanced/examine(mob/living/user)
to_chat(user, "<span class = 'notice> It's set to [tool_behaviour == TOOL_SCALPEL ? "scalpel" : "saw"] mode. </span>")
. = ..()
. += "<span class = 'notice> It's set to [tool_behaviour == TOOL_SCALPEL ? "scalpel" : "saw"] mode. </span>"
/obj/item/scalpel/augment
name = "scalpel"
+2 -1
View File
@@ -40,6 +40,7 @@
Where:
<select name='object_where' style="width:320px">
<option value='onfloor'>On floor below own mob</option>
<option value='frompod'>On floor below own mob, dropped via supply pod</option>
<option value='inhand'>In own mob's hand</option>
<option value='inmarked'>In marked object</option>
</select>
@@ -105,4 +106,4 @@
</script>
</body>
</html>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -169,7 +169,7 @@
matching_designs.Cut()
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(findtext(D.name,href_list["to_search"]))
matching_designs.Add(D)
updateUsrDialog()
@@ -244,7 +244,7 @@
dat += materials_printout()
for(var/v in stored_research.researched_designs)
var/datum/design/D = stored_research.researched_designs[v]
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(!(selected_category in D.category))
continue
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
View File
@@ -25,3 +25,5 @@ sound/music/goodbyemoonmen.ogg
sound/music/flytothemoon_otomatone.ogg
sound/music/milkyway.ogg
sound/music/rocketridersprayer.ogg
sound/music/thewizard.ogg
sound/music/thesettler.ogg
+6
View File
@@ -941,19 +941,25 @@
#include "code\game\objects\items\implants\implant_abductor.dm"
#include "code\game\objects\items\implants\implant_chem.dm"
#include "code\game\objects\items\implants\implant_clown.dm"
#include "code\game\objects\items\implants\implant_CQC.dm"
#include "code\game\objects\items\implants\implant_exile.dm"
#include "code\game\objects\items\implants\implant_explosive.dm"
#include "code\game\objects\items\implants\implant_freedom.dm"
#include "code\game\objects\items\implants\implant_krav_maga.dm"
#include "code\game\objects\items\implants\implant_mindshield.dm"
#include "code\game\objects\items\implants\implant_misc.dm"
#include "code\game\objects\items\implants\implant_mushpunch.dm"
#include "code\game\objects\items\implants\implant_plasmafist.dm"
#include "code\game\objects\items\implants\implant_psychobrawl.dm"
#include "code\game\objects\items\implants\implant_radio.dm"
#include "code\game\objects\items\implants\implant_slave.dm"
#include "code\game\objects\items\implants\implant_sleepingcarp.dm"
#include "code\game\objects\items\implants\implant_spell.dm"
#include "code\game\objects\items\implants\implant_stealth.dm"
#include "code\game\objects\items\implants\implant_storage.dm"
#include "code\game\objects\items\implants\implant_track.dm"
#include "code\game\objects\items\implants\implant_uplink.dm"
#include "code\game\objects\items\implants\implant_wrestling.dm"
#include "code\game\objects\items\implants\implantcase.dm"
#include "code\game\objects\items\implants\implantchair.dm"
#include "code\game\objects\items\implants\implanter.dm"
+1 -1
View File
File diff suppressed because one or more lines are too long
+123 -92
View File
@@ -1,23 +1,29 @@
<ui-notice>
<span>To use this, simply spawn the atoms you want in one of the four Centcom Supplypod Bays. Items in the bay will then be launched inside your supplypod, one turf-full at a time! You can optionally use the following buttons to configure how the supplypod acts.</span>
<span>To use this, simply spawn the atoms you want in one of the five Centcom Supplypod Bays. Items in the bay will then be launched inside your supplypod, one turf-full at a time! You can optionally use the following buttons to configure how the supplypod acts.</span>
</ui-notice>
<ui-display title='Centcom Pod Customization (to be used against helen weinstein)'>
<ui-section label = 'Which supplypod bay will you use?'>
<ui-button style='{{data.bay == 1 ? "selected" : null}}' action='bay1'>Bay #1</ui-button>
<ui-button style='{{data.bay == 2 ? "selected" : null}}' action='bay2'>Bay #2</ui-button>
<ui-button style='{{data.bay == 3 ? "selected" : null}}' action='bay3'>Bay #3</ui-button>
<ui-button style='{{data.bay == 4 ? "selected" : null}}' action='bay4'>Bay #4</ui-button>
<ui-section label='Which supplypod bay will you use?'>
<ui-button style='{{data.bayNumber == 1 ? "selected" : null}}' action='bay1'>Bay #1</ui-button>
<ui-button style='{{data.bayNumber == 2 ? "selected" : null}}' action='bay2'>Bay #2</ui-button>
<ui-button style='{{data.bayNumber == 3 ? "selected" : null}}' action='bay3'>Bay #3</ui-button>
<ui-button style='{{data.bayNumber == 4 ? "selected" : null}}' action='bay4'>Bay #4</ui-button>
<ui-button style='{{data.bayNumber == 5 ? "selected" : null}}' action='bay5' tooltip-side='left' tooltip='This bay is located on the western edge of CentCom. Its the glass room directly west of where ERT spawn, and south of the CentCom ferry. Useful for launching ERT/Deathsquads/etc. onto the station via drop pods.'>ERT Bay</ui-button>
</ui-section>
<ui-section label = 'Useful teleport tools!'>
<ui-button action='teleportCentcom'>Teleport to Centcom's Supplypod Loading Bay</ui-button>
<ui-button state='{{data.oldArea ? null : "disabled"}}'action='teleportBack'>Teleport Back to {{data.oldArea ? data.oldArea : "where you were"}}</ui-button>
<ui-section label='Teleport to:'>
<ui-button action='teleportCentcom'>{{data.bay}}</ui-button>
<ui-button state='{{data.oldArea ? null : "disabled"}}'action='teleportBack'>{{data.oldArea ? data.oldArea : "where you were"}}</ui-button>
</ui-section>
<ui-section label='Keep stuff after launching?'>
<ui-button style='{{data.launchClone ? "selected" : null}}' action='launchClone' tooltip-side='left'
tooltip='Choosing this will create a duplicate of the item to be launched in Centcom, allowing you to send one type of item multiple times. Either way, the atoms are forceMoved into the supplypod after it lands (but before it opens).'>Clone and Launch</ui-button>
<ui-section label='Launch the real atoms?'>
<ui-button style='{{data.launchClone ? "selected" : null}}' action='launchClone' tooltip-side='left' tooltip='Choosing this will create a duplicate of the item to be launched in Centcom, allowing you to send one type of item multiple times. Either way, the atoms are forceMoved into the supplypod after it lands (but before it opens).'>Launch Clones</ui-button>
</ui-section>
<ui-section label='Launch all at once?'>
@@ -27,101 +33,126 @@
tooltip='Instead of launching everything in the bay at once, this will launch one random turf of items at a time.'>Random</ui-button>
</ui-section>
<ui-section label='Add an explosion?'>
<ui-button style='{{data.explosionChoice == 1? "selected" : null}}' action='explosionCustom' tooltip-side='left'
tooltip='This will cause an explosion of whatever size you like (including flame range) to occur as soon as the supplypod lands. Dont worry, supply-pods are explosion-proof!'>Custom Size</ui-button>
<ui-button style='{{data.explosionChoice == 2? "selected" : null}}' action='explosionBus' tooltip-side='left'
tooltip='This will cause a maxcap explosion (dependent on server config) to occur as soon as the supplypod lands. Dont worry, supply-pods are explosion-proof!'>Adminbus</ui-button>
</ui-section>
<ui-button style='{{data.explosionChoice == 1? "selected" : null}}' action='explosionCustom' tooltip-side='left'
tooltip='This will cause an explosion of whatever size you like (including flame range) to occur as soon as the supplypod lands. Dont worry, supply-pods are explosion-proof!'>Custom Size</ui-button>
<ui-button style='{{data.explosionChoice == 2? "selected" : null}}' action='explosionBus' tooltip-side='left'
tooltip='This will cause a maxcap explosion (dependent on server config) to occur as soon as the supplypod lands. Dont worry, supply-pods are explosion-proof!'>Adminbus</ui-button> </ui-section>
<ui-section label='Extra damage?' (default = None)>
<ui-button style='{{data.damageChoice == 1 ? "selected" : null}}' action='damageCustom' tooltip-side='left'
tooltip='Anyone caught under the pod when it lands will be dealt this amount of brute damage. Sucks to be them!'>Custom Damage</ui-button>
<ui-button style='{{data.damageChoice == 2 ? "selected" : null}}' action='damageGib' tooltip-side='left'
tooltip='This will attempt to gib any mob caught under the pod when it lands, as well as dealing a nice 5000 brute damage. Ya know, just to be sure!'>Gib</ui-button>
</ui-section>
<ui-button style='{{data.damageChoice == 1 ? "selected" : null}}' action='damageCustom' tooltip-side='left'
tooltip='Anyone caught under the pod when it lands will be dealt this amount of brute damage. Sucks to be them!'>Custom Damage</ui-button>
<ui-button style='{{data.damageChoice == 2 ? "selected" : null}}' action='damageGib' tooltip-side='left'
tooltip='This will attempt to gib any mob caught under the pod when it lands, as well as dealing a nice 5000 brute damage. Ya know, just to be sure!'>Gib</ui-button> </ui-section>
<ui-section label='Damaging effects?'>
<ui-button style='{{data.effectStun ? "selected" : null}}' action='effectStun' tooltip-side='left'
tooltip='Anyone who is on the turf when the supplypod is launched will be stunned until the supplypod lands. They cant get away that easy!'>Stun</ui-button>
<ui-button style='{{data.effectLimb ? "selected" : null}}' action='effectLimb' tooltip-side='left'
tooltip='This will cause anyone caught under the pod to lose a limb, excluding their head.'>Delimb</ui-button>
<ui-button style='{{data.effectOrgans ? "selected" : null}}' action='effectOrgans' tooltip-side='left'
tooltip='This will cause anyone caught under the pod to lose all their limbs and organs in a spectacular fashion.'>Yeet Organs</ui-button> </ui-section>
<ui-section label='Movement effects?'>
<ui-button style='{{data.effectBluespace ? "selected" : null}}' action='effectBluespace' tooltip-side='left'
tooltip='Gives the supplypod an advanced Bluespace Recyling Device. After opening, the supplypod will be warped directly to the surface of a nearby NT-designated trash planet (/r/ss13).'>Bluespace</ui-button>
<ui-button style='{{data.effectStealth ? "selected" : null}}' action='effectStealth' tooltip-side='left'
tooltip='This hides the red target icon from appearing when you launch the supplypod. Combos well with the "Invisible" style. Sneak attack, go!'>Stealth</ui-button>
<ui-button style='{{data.effectQuiet ? "selected" : null}}' action='effectQuiet' tooltip-side='left'
tooltip='This will keep the supplypod from making any sounds, except for those specifically set by admins in the Sound section.'>Quiet Landing</ui-button>
<ui-button style='{{data.effectReverse ? "selected" : null}}' action='effectReverse' tooltip-side='left'
tooltip='This pod will not send any items. Instead, after landing, the supplypod will close (similar to a normal closet closing), and then launch back to the right centcom bay to drop off any new contents.'>Reverse Mode</ui-button>
<ui-button style='{{data.effectMissile ? "selected" : null}}' action='effectMissile' tooltip-side='left'
tooltip='This pod will not send any items. Instead, it will immediatley delete after landing (Similar visually to setting openDelay & departDelay to 0, but this looks nicer). Useful if you just wanna fuck some shit up. Combos well with the Missile style.'>Missile Mode</ui-button>
<ui-button style='{{data.effectCircle ? "selected" : null}}' action='effectCircle' tooltip-side='left'
tooltip='This will make the supplypod come in from any angle. Im not sure why this feature exists, but here it is.'>Any Descent Angle</ui-button>
<ui-button style='{{data.effectBurst ? "selected" : null}}' action='effectBurst' tooltip-side='left'
tooltip='This will make each click launch 5 supplypods inaccuratly around the target turf (a 3x3 area). Combos well with the Missle Mode if you dont want shit lying everywhere after.'>Machine Gun Mode</ui-button>
<ui-button style='{{data.effectTarget ? "selected" : null}}' action='effectTarget' tooltip-side='left'
tooltip='This will make the supplypod target a specific atom, instead of the mouses position. Smiting does this automatically!'>Specific Target</ui-button> </ui-section>
<ui-section label='Change Name/Desc?'>
<ui-button style='{{data.effectName ? "selected" : null}}' action='effectName' tooltip-side='left'
tooltip='Allows you to add a custom name and description.'>Custom Name/Desc</ui-button>
<ui-button style='{{data.effectAnnounce ? "selected" : null}}' action='effectAnnounce' tooltip-side='left'
tooltip='Alerts ghosts when a pod is launched. Useful if some dumb shit is aboutta come outta the pod.'>Alert Ghosts</ui-button> </ui-section>
<ui-section label='Extra effects?'>
<ui-button style='{{data.effectStun ? "selected" : null}}' action='effectStun' tooltip-side='left'
tooltip='Anyone who is on the turf when the supplypod is launched will be stunned until the supplypod lands. They cant get away that easy!'>Stun</ui-button>
<ui-button style='{{data.effectLimb ? "selected" : null}}' action='effectLimb' tooltip-side='left'
tooltip='This will cause anyone caught under the pod to lose a limb, excluding their head.'>Delimb</ui-button>
<ui-button style='{{data.effectBluespace ? "selected" : null}}' action='effectBluespace' tooltip-side='left'
tooltip='Gives the supplypod an advanced Bluespace Recyling Device. After opening, the supplypod will be warped directly to the surface of a nearby NT-designated trash planet (/r/ss13).'>Bluespace</ui-button>
<ui-button style='{{data.effectStealth ? "selected" : null}}' action='effectStealth' tooltip-side='left'
tooltip='This hides the red target icon from appearing when you launch the supplypod. Combos well with the "Invisible" style. Sneak attack, go!'>Stealth</ui-button>
<ui-button style='{{data.effectQuiet ? "selected" : null}}' action='effectQuiet' tooltip-side='left'
tooltip='This will keep the supplypod from making any sounds, except for those specifically set by admins in the Sound section.'>Quiet Landing</ui-button>
<ui-button style='{{data.effectReverse ? "selected" : null}}' action='effectReverse' tooltip-side='left'
tooltip='This pod will not send any items. Instead, after landing, the supplypod will close (similar to a normal closet closing), and then launch back to the right centcom bay to drop off any new contents.'>Reverse Mode</ui-button>
<ui-button style='{{data.effectMissile ? "selected" : null}}' action='effectMissile' tooltip-side='left'
tooltip='This pod will not send any items. Instead, it will immediatley delete after landing (Similar visually to setting openDelay & departDelay to 0, but this looks nicer). Useful if you just wanna fuck some shit up. Combos well with the Missile style.'>Missile Mode</ui-button>
<ui-button style='{{data.effectCircle ? "selected" : null}}' action='effectCircle' tooltip-side='left'
tooltip='This will make the supplypod come in from any angle. Im not sure why this feature exists, but here it is.'>Any Descent Angle</ui-button>
<ui-button style='{{data.effectBurst ? "selected" : null}}' action='effectBurst' tooltip-side='left'
tooltip='This will make each click launch 5 supplypods inaccuratly around the target turf (a 3x3 area). Combos well with the Missle Mode if you dont want shit lying everywhere after.'>Machine Gun Mode</ui-button>
<ui-button style='{{data.effectTarget ? "selected" : null}}' action='effectTarget' tooltip-side='left'
tooltip='This will make the supplypod target a specific atom, instead of the mouses position. Smiting does this automatically!'>Specific Target</ui-button>
<ui-button style='{{data.effectName ? "selected" : null}}' action='effectName' tooltip-side='left'
tooltip='Allows you to add a custom name and description.'>Custom Name/Desc</ui-button>
</ui-section>
<ui-section label='Sound?'>
<ui-button style='{{data.landingSound ? "selected" : null}}' action='landingSound' tooltip-side='left'
tooltip='Choose a sound to play when the pod lands.'>Custom Landing Sound</ui-button>
<ui-button style='{{data.openingSound ? "selected" : null}}' action='openingSound' tooltip-side='left'
tooltip='Choose a sound to play when the pod opens.'>Custom Opening Sound</ui-button>
<ui-button style='{{data.leavingSound ? "selected" : null}}' action='leavingSound' tooltip-side='left'
tooltip='Choose a sound to play when the pod departs (whether that be delection in the case of a bluespace pod, or leaving for centcom for a reversing pod).'>Custom Leaving Sound</ui-button>
<ui-button style='{{data.soundVolume ? "selected" : null}}' action='soundVolume' tooltip-side='left'
tooltip='Choose the volume for the sound to play at. Default values are between 1 and 100, but hey, do whatever. Im a tooltip, not a cop.'>Admin Sound Volume</ui-button>
</ui-section>
<ui-button style='{{data.fallingSound ? "selected" : null}}' action='fallingSound' tooltip-side='left'
tooltip='Choose a sound to play as the pod falls. Note that for this to work right you should know the exact length of the sound, in seconds.'>Custom Falling Sound</ui-button>
<ui-button style='{{data.landingSound ? "selected" : null}}' action='landingSound' tooltip-side='left'
tooltip='Choose a sound to play when the pod lands.'>Custom Landing Sound</ui-button>
<ui-button style='{{data.openingSound ? "selected" : null}}' action='openingSound' tooltip-side='left'
tooltip='Choose a sound to play when the pod opens.'>Custom Opening Sound</ui-button>
<ui-button style='{{data.leavingSound ? "selected" : null}}' action='leavingSound' tooltip-side='left'
tooltip='Choose a sound to play when the pod departs (whether that be delection in the case of a bluespace pod, or leaving for centcom for a reversing pod).'>Custom Leaving Sound</ui-button>
<ui-button style='{{data.soundVolume ? "selected" : null}}' action='soundVolume' tooltip-side='left'
tooltip='Choose the volume for the sound to play at. Default values are between 1 and 100, but hey, do whatever. Im a tooltip, not a cop.'>Admin Sound Volume</ui-button> </ui-section>
<ui-section label='Delay timers?'>
<ui-button style='{{data.landingDelay != 5 ? "selected" : null}}' action='landingDelay' tooltip-side='left'
tooltip='Choose the amount of time it takes for the supplypod to hit the station. By default this value is 0.5 seconds.'>Custom Landing Time</ui-button>
<ui-button style='{{data.openingDelay != 30 ? "selected" : null}}' action='openingDelay' tooltip-side='left'
tooltip='Choose the amount of time it takes for the supplypod to open after landing. Useful for giving whatevers inside the pod a nice dramatic entrance! By default this value is 3 seconds.'>Custom Opening Time</ui-button>
<ui-button style='{{data.departureDelay != 30 ? "selected" : null}}' action='departureDelay' tooltip-side='left'
tooltip='Choose the amount of time it takes for the supplypod to leave after landing. By default this value is 3 seconds.'>Custom Leaving Time</ui-button>
</ui-section>
<ui-button style='{{data.fallDuration != 4 ? "selected" : null}}' action='fallDuration' tooltip-side='left'
tooltip='Set how long the animation for the pod falling lasts. Create dramatic, slow falling pods!'>Custom Falling Duration</ui-button>
<ui-button style='{{data.landingDelay != 20 ? "selected" : null}}' action='landingDelay' tooltip-side='left'
tooltip='Choose the amount of time it takes for the supplypod to hit the station. By default this value is 0.5 seconds.'>Custom Landing Time</ui-button>
<ui-button style='{{data.openingDelay != 30 ? "selected" : null}}' action='openingDelay' tooltip-side='left'
tooltip='Choose the amount of time it takes for the supplypod to open after landing. Useful for giving whatevers inside the pod a nice dramatic entrance! By default this value is 3 seconds.'>Custom Opening Time</ui-button>
<ui-button style='{{data.departureDelay != 30 ? "selected" : null}}' action='departureDelay' tooltip-side='left'
tooltip='Choose the amount of time it takes for the supplypod to leave after landing. By default this value is 3 seconds.'>Custom Leaving Time</ui-button> </ui-section>
<ui-section label='Style?'>
<ui-button style='{{data.styleChoice == 1 ? "selected" : null}}' action='styleStandard' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom color scheme to your standard Kinaris black and orange. Same color scheme as the normal station-used supplypods.'>Standard</ui-button>
<ui-button style='{{data.styleChoice == 2 ? "selected" : null}}' action='styleBluespace' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom color scheme to the same as the stations upgraded blue-and-white Bluespace Supplypods.'>Advanced</ui-button>
<ui-button style='{{data.styleChoice == 4 ? "selected" : null}}' action='styleSyndie' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom color scheme to a menacing black and blood-red. Great for sending meme-ops in style!'>Syndicate</ui-button>
<ui-button style='{{data.styleChoice == 5 ? "selected" : null}}' action='styleBlue' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom color scheme to a menacing black and dark blue. Great for sending deathsquads in style!'>Deathsquad</ui-button>
<ui-button style='{{data.styleChoice == 6 ? "selected" : null}}' action='styleCult' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom style to a blood and rune covered cult pod!'>Cult Pod</ui-button>
<ui-button style='{{data.styleChoice == 7 ? "selected" : null}}' action='styleMissile' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom style to a large missile. Combos well with a missile mode, so the missile doesnt stick around after landing.'>Missile</ui-button>
<ui-button style='{{data.styleChoice == 8 ? "selected" : null}}' action='styleSMissile' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom style to a large blood-red missile. Combos well with missile mode, so the missile doesnt stick around after landing.'>Syndicate Missile</ui-button>
<ui-button style='{{data.styleChoice == 9 ? "selected" : null}}' action='styleBox' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom style to a large, dark-green military supply crate.'>Supply Crate</ui-button>
<ui-button style='{{data.styleChoice == 10 ? "selected" : null}}' action='styleHONK' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom color scheme to a colorful, clown inspired look.'>HONK</ui-button>
<ui-button style='{{data.styleChoice == 11 ? "selected" : null}}' action='styleFruit' tooltip-side='left'
tooltip='for when an orange is angry'>Fruit~</ui-button>
<ui-button style='{{data.styleChoice== 12 ? "selected" : null}}' action='styleInvisible' tooltip-side='left'
tooltip='Makes the supplypod invisible! Useful for when you want to use this feature with a gateway or something. Combos well with the "Stealth" and "Quiet Landing" effects.'>Invisible</ui-button>
<ui-button style='{{data.styleChoice == 13 ? "selected" : null}}' action='styleGondola' tooltip-side='left'
tooltip='this gondola can control when he wants to deliver his supplies if he has a smart enough mind, so offer up his body to ghosts for maximum enjoyment. (Make sure to turn off bluespace and set a arbitrarily high open-time if you do!)'>Gondola (alive)</ui-button>
</ui-section>
<ui-button style='{{data.styleChoice == 2 ? "selected" : null}}' action='styleBluespace' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom color scheme to the same as the stations upgraded blue-and-white Bluespace Supplypods.'>Advanced</ui-button>
<ui-button style='{{data.styleChoice == 4 ? "selected" : null}}' action='styleSyndie' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom color scheme to a menacing black and blood-red. Great for sending meme-ops in style!'>Syndicate</ui-button>
<ui-button style='{{data.styleChoice == 5 ? "selected" : null}}' action='styleBlue' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom color scheme to a menacing black and dark blue. Great for sending deathsquads in style!'>Deathsquad</ui-button>
<ui-button style='{{data.styleChoice == 6 ? "selected" : null}}' action='styleCult' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom style to a blood and rune covered cult pod!'>Cult Pod</ui-button>
<ui-button style='{{data.styleChoice == 7 ? "selected" : null}}' action='styleMissile' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom style to a large missile. Combos well with a missile mode, so the missile doesnt stick around after landing.'>Missile</ui-button>
<ui-button style='{{data.styleChoice == 8 ? "selected" : null}}' action='styleSMissile' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom style to a large blood-red missile. Combos well with missile mode, so the missile doesnt stick around after landing.'>Syndicate Missile</ui-button>
<ui-button style='{{data.styleChoice == 9 ? "selected" : null}}' action='styleBox' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom style to a large, dark-green military supply crate.'>Supply Crate</ui-button>
<ui-button style='{{data.styleChoice == 10 ? "selected" : null}}' action='styleHONK' tooltip-side='left'
tooltip='Changes the pods style from the default Centcom color scheme to a colorful, clown inspired look.'>HONK</ui-button>
<ui-button style='{{data.styleChoice == 11 ? "selected" : null}}' action='styleFruit' tooltip-side='left'
tooltip='for when an orange is angry'>Fruit~</ui-button>
<ui-button style='{{data.styleChoice== 12 ? "selected" : null}}' action='styleInvisible' tooltip-side='left'
tooltip='Makes the supplypod invisible! Useful for when you want to use this feature with a gateway or something. Combos well with the "Stealth" and "Quiet Landing" effects.'>Invisible</ui-button>
<ui-button style='{{data.styleChoice == 13 ? "selected" : null}}' action='styleGondola' tooltip-side='left'
tooltip='this gondola can control when he wants to deliver his supplies if he has a smart enough mind, so offer up his body to ghosts for maximum enjoyment. (Make sure to turn off bluespace and set a arbitrarily high open-time if you do!)'>Gondola (alive)</ui-button>
<ui-button style='{{data.styleChoice == 14 ? "selected" : null}}' action='styleSeeThrough' tooltip-side='left'
tooltip='By selecting this, the pod will instead look like whatevers inside it (as if it were the contents falling by themselves, without a pod). Useful for launching mechs at the station and standing tall as they soar in from the heavens.'>Show Contents (See-Through Pod)!</ui-button>
</ui-section>
</ui-display>
<ui-display>
<ui-section label = '{{data.numObjects}} turfs with launchable atoms found in Bay #{{data.bay}}'>
<ui-button action='refresh' tooltip-side='right'
<ui-section label='{{data.numObjects}} turfs in {{data.bay}}' candystripe right>
<ui-button action='refresh' tooltip-side='left'
tooltip='Manually refreshes the possible things to launch in the pod bay.'>Refresh Pod Bay</ui-button>
</ui-section>
<ui-section>
<ui-button style='{{data.giveLauncher ? "selected" : null}}' action='giveLauncher' tooltip-side='right'
tooltip='THE CODEX ASTARTES CALLS THIS MANEUVER: STEEL RAIN!!'>Enter Launch Mode</ui-button>
<ui-button style='{{data.giveLauncher ? "selected" : null}}' action='giveLauncher' tooltip-side='left'
tooltip='THE CODEX ASTARTES CALLS THIS MANEUVER: STEEL RAIN'>Enter Launch Mode</ui-button>
<ui-button style='danger' action='clearBay' tooltip-side='left'
tooltip='This will delete all objs and mobs from the selected bay.'>Clear Selected Bay</ui-button>
</ui-section>
</ui-display>