Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Hawk_v3
2018-10-14 17:09:41 +01:00
105 changed files with 3030 additions and 584 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ sudo: false
env:
global:
- BYOND_MAJOR="512"
- BYOND_MINOR="1412"
- BYOND_MINOR="1453"
- MACRO_COUNT=4
matrix:
- TEST_DEFINE="MAP_TEST" TEST_FILE="code/_map_tests.dm" RUN="0"
+24
View File
@@ -45,3 +45,27 @@
#define SMITE_BLUESPACEARTILLERY "Bluespace Artillery"
#define SMITE_SPONTANEOUSCOMBUSTION "Spontaneous Combustion"
#define SMITE_LIGHTNINGBOLT "Lightning Bolt"
#define ADMIN_QUE(user) "(<a href='?_src_=holder;adminmoreinfo=\ref[user]'>?</a>)"
#define ADMIN_FLW(user) "(<a href='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</a>)"
#define ADMIN_PP(user) "(<a href='?_src_=holder;adminplayeropts=\ref[user]'>PP</a>)"
#define ADMIN_VV(atom) "(<a href='?_src_=vars;Vars=\ref[atom]'>VV</a>)"
#define ADMIN_SM(user) "(<a href='?_src_=holder;subtlemessage=\ref[user]'>SM</a>)"
#define ADMIN_TP(user) "(<a href='?_src_=holder;traitor=\ref[user]'>TP</a>)"
#define ADMIN_BSA(user) "(<a href='?_src_=holder;BlueSpaceArtillery=\ref[user]'>BSA</a>)"
#define ADMIN_KICK(user) "(<a href='?_src_=holder;boot2=\ref[user]'>KICK</a>)"
#define ADMIN_CENTCOM_REPLY(user) "(<a href='?_src_=holder;CentcommReply=\ref[user]'>RPLY</a>)"
#define ADMIN_SYNDICATE_REPLY(user) "(<a href='?_src_=holder;SyndicateReply=\ref[user]'>RPLY</a>)"
#define ADMIN_SC(user) "(<a href='?_src_=holder;adminspawncookie=\ref[user]'>SC</a>)"
#define ADMIN_SMITE(user) "(<a href='?_src_=holder;adminsmite=\ref[user]'>SMITE</a>)"
#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]"
#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]"
#define ADMIN_FULLMONTY_NONAME(user) "[ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)]"
#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_FULLMONTY_NONAME(user)]"
#define ADMIN_JMP(src) "(<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>)"
#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]"
#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]"
#define AHELP_ACTIVE 1
#define AHELP_CLOSED 2
#define AHELP_RESOLVED 3
+1
View File
@@ -149,6 +149,7 @@
#define MAT_GLASS "glass"
#define MAT_SILVER "silver"
#define MAT_GOLD "gold"
#define MAT_URANIUM "uranium" //Did it
#define MAT_TITANIUM "titanium"
#define MAT_PHORON "phoron"
#define MAT_DIAMOND "diamond"
+8 -1
View File
@@ -20,4 +20,11 @@
#define QDELING(X) (X.gc_destroyed)
#define QDELETED(X) (!X || X.gc_destroyed)
#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); }
/proc/______qdel_list_wrapper(list/L) //the underscores are to encourage people not to use this directly.
QDEL_LIST(L)
+6
View File
@@ -0,0 +1,6 @@
//Byond type ids
#define TYPEID_NULL "0"
#define TYPEID_NORMAL_LIST "f"
//helper macros
#define GET_TYPEID(ref) ( ( (lentext(ref) <= 10) ? "TYPEID_NULL" : copytext(ref, 4, lentext(ref)-6) ) )
#define IS_NORMAL_LIST(L) (GET_TYPEID("\ref[L]") == TYPEID_NORMAL_LIST)
+5 -1
View File
@@ -1 +1,5 @@
GLOBAL_LIST_EMPTY(all_observable_events)
GLOBAL_LIST_EMPTY(all_observable_events)
GLOBAL_VAR_INIT(timezoneOffset, 0) // The difference betwen midnight (of the host computer) and 0 world.ticks.
GLOBAL_VAR_INIT(TAB, "&nbsp;&nbsp;&nbsp;&nbsp;")
+4 -1
View File
@@ -1,2 +1,5 @@
GLOBAL_LIST_EMPTY(admins) //all clients whom are admins
GLOBAL_PROTECT(admins)
GLOBAL_PROTECT(admins)
GLOBAL_LIST_EMPTY(deadmins) //all ckeys who have used the de-admin verb.
GLOBAL_LIST_EMPTY(stealthminID)
GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client
+15 -10
View File
@@ -26,17 +26,17 @@
max_z = max(z, max_z)
return max_z
/proc/get_area(O)
var/turf/loc = get_turf(O)
if(loc)
var/area/res = loc.loc
.= res
/proc/get_area(atom/A)
if(isarea(A))
return A
var/turf/T = get_turf(A)
return T ? T.loc : null
/proc/get_area_name(N) //get area by its name
for(var/area/A in all_areas)
if(A.name == N)
return A
return 0
/proc/get_area_name(atom/X, format_text = FALSE)
var/area/A = isarea(X) ? X : get_area(X)
if(!A)
return null
return format_text ? format_text(A.name) : A.name
/proc/get_area_master(const/O)
var/area/A = get_area(O)
@@ -605,3 +605,8 @@ datum/projectile_data
/proc/SecondsToTicks(var/seconds)
return seconds * 10
/proc/window_flash(var/client_or_usr)
if (!client_or_usr)
return
winset(client_or_usr, "mainwindow", "flash=5")
+4 -2
View File
@@ -106,11 +106,12 @@ var/global/list/global_egg_types = list(
"Tajaran" = TAJARAN_EGG,
"Akula" = AKULA_EGG,
"Skrell" = SKRELL_EGG,
"Nevrean" = NEVREAN_EGG,
"Sergal" = SERGAL_EGG,
"Human" = HUMAN_EGG,
"Slime" = SLIME_EGG,
"Egg" = EGG_EGG,
"Xenochimera" = XENOCHIMERA_EGG,
"Xenochimera" = XENOCHIMERA_EGG,
"Xenomorph" = XENOMORPH_EGG)
var/global/list/tf_egg_types = list(
@@ -119,10 +120,11 @@ var/global/list/tf_egg_types = list(
"Akula" = /obj/structure/closet/secure_closet/egg/shark,
"Skrell" = /obj/structure/closet/secure_closet/egg/skrell,
"Sergal" = /obj/structure/closet/secure_closet/egg/sergal,
"Nevrean" = /obj/structure/closet/secure_closet/egg/nevrean,
"Human" = /obj/structure/closet/secure_closet/egg/human,
"Slime" = /obj/structure/closet/secure_closet/egg/slime,
"Egg" = /obj/structure/closet/secure_closet/egg,
"Xenochimera" = /obj/structure/closet/secure_closet/egg/scree,
"Xenochimera" = /obj/structure/closet/secure_closet/egg/scree,
"Xenomorph" = /obj/structure/closet/secure_closet/egg/xenomorph)
var/global/list/edible_trash = list(/obj/item/trash,
+11
View File
@@ -240,6 +240,17 @@ proc/listclearnulls(list/list)
for(var/i in L)
. |= i
//same, but returns nothing and acts on list in place (also handles associated values properly)
/proc/uniqueList_inplace(list/L)
var/temp = L.Copy()
L.len = 0
for(var/key in temp)
if (isnum(key))
L |= key
else
L[key] = temp[key]
//Mergesort: divides up the list into halves to begin the sort
/proc/sortKey(var/list/client/L, var/order = 1)
if(isnull(L) || L.len < 2)
+103 -1
View File
@@ -64,6 +64,11 @@ var/next_station_date_change = 1 DAY
var/time_portion = time2text(world.timeofday, "hh:mm:ss")
return "[date_portion]T[time_portion]"
/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
if(!wtime)
wtime = world.time
return time2text(wtime - GLOB.timezoneOffset, format)
/* Returns 1 if it is the selected month and day */
proc/isDay(var/month, var/day)
if(isnum(month) && isnum(day))
@@ -137,4 +142,101 @@ var/round_start_time = 0
i *= 2
while (TICK_USAGE > min(TICK_LIMIT_TO_RUN, GLOB.CURRENT_TICKLIMIT))
#undef DELTA_CALC
#undef DELTA_CALC
//Takes a value of time in deciseconds.
//Returns a text value of that number in hours, minutes, or seconds.
/proc/DisplayTimeText(time_value, truncate = FALSE)
var/second = (time_value)*0.1
var/second_adjusted = null
var/second_rounded = FALSE
var/minute = null
var/hour = null
var/day = null
if(!second)
return "0 seconds"
if(second >= 60)
minute = FLOOR(second/60, 1)
second = round(second - (minute*60), 0.1)
second_rounded = TRUE
if(second) //check if we still have seconds remaining to format, or if everything went into minute.
second_adjusted = round(second) //used to prevent '1 seconds' being shown
if(day || hour || minute)
if(second_adjusted == 1 && second >= 1)
second = " and 1 second"
else if(second > 1)
second = " and [second_adjusted] seconds"
else //shows a fraction if seconds is < 1
if(second_rounded) //no sense rounding again if it's already done
second = " and [second] seconds"
else
second = " and [round(second, 0.1)] seconds"
else
if(second_adjusted == 1 && second >= 1)
second = "[truncate ? "second" : "1 second"]"
else if(second > 1)
second = "[second_adjusted] seconds"
else
if(second_rounded)
second = "[second] seconds"
else
second = "[round(second, 0.1)] seconds"
else
second = null
if(!minute)
return "[second]"
if(minute >= 60)
hour = FLOOR(minute/60, 1)
minute = (minute - (hour*60))
if(minute) //alot simpler from here since you don't have to worry about fractions
if(minute != 1)
if((day || hour) && second)
minute = ", [minute] minutes"
else if((day || hour) && !second)
minute = " and [minute] minutes"
else
minute = "[minute] minutes"
else
if((day || hour) && second)
minute = ", 1 minute"
else if((day || hour) && !second)
minute = " and 1 minute"
else
minute = "[truncate ? "minute" : "1 minute"]"
else
minute = null
if(!hour)
return "[minute][second]"
if(hour >= 24)
day = FLOOR(hour/24, 1)
hour = (hour - (day*24))
if(hour)
if(hour != 1)
if(day && (minute || second))
hour = ", [hour] hours"
else if(day && (!minute || !second))
hour = " and [hour] hours"
else
hour = "[hour] hours"
else
if(day && (minute || second))
hour = ", 1 hour"
else if(day && (!minute || !second))
hour = " and 1 hour"
else
hour = "[truncate ? "hour" : "1 hour"]"
else
hour = null
if(!day)
return "[hour][minute][second]"
if(day > 1)
day = "[day] days"
else
day = "[truncate ? "day" : "1 day"]"
return "[day][hour][minute][second]"
+8
View File
@@ -522,6 +522,14 @@ Turf and target are seperate in case you want to teleport some distance from a t
return "[round((powerused * 0.000001),0.001)] MW"
return "[round((powerused * 0.000000001),0.0001)] GW"
/proc/get_mob_by_ckey(key)
if(!key)
return
var/list/mobs = sortmobs()
for(var/mob/M in mobs)
if(M.ckey == key)
return M
//Forces a variable to be posative
/proc/modulus(var/M)
if(M >= 0)
+2 -2
View File
@@ -60,13 +60,13 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1)
access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,
access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station,
access_hop, access_RC_announce, access_keycard_auth, access_gateway)
access_hop, access_RC_announce, access_keycard_auth) //, access_gateway) //VOREStation Edit
minimal_access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers,
access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,
access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,
access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station,
access_hop, access_RC_announce, access_keycard_auth, access_gateway)
access_hop, access_RC_announce, access_keycard_auth) //, access_gateway) //VOREStation Edit
/datum/job/secretary
title = "Command Secretary"
+1
View File
@@ -434,6 +434,7 @@ var/global/datum/controller/occupations/job_master
H.job = rank
log_game("JOINED [key_name(H)] as \"[rank]\"")
log_game("SPECIES [key_name(H)] is a: \"[H.species.name]\"") //VOREStation Add
// If they're head, give them the account info for their department
if(H.mind && job.head_position)
+1 -1
View File
@@ -395,7 +395,7 @@
return 0
// Do after stuff here
user << "<span class='notice'>You start to weld the [src]..</span>"
user << "<span class='notice'>You start to weld [src]..</span>"
playsound(src.loc, WT.usesound, 50, 1)
WT.eyecheck(user)
busy = 1
@@ -20,6 +20,7 @@
/obj/machinery/computer/atmoscontrol/laptop
name = "Atmospherics Laptop"
desc = "A cheap laptop."
icon_screen = "atmoslaptop"
icon_state = "laptop"
icon_keyboard = "laptop_key"
density = 0
+1
View File
@@ -5,6 +5,7 @@
desc = "Used to view, edit and maintain medical records."
icon_keyboard = "med_key"
icon_screen = "medcomp"
density = 0 //Why does a laptop blocks peoples.
light_color = "#315ab4"
req_one_access = list(access_medical, access_forensics_lockers, access_robotics)
circuit = /obj/item/weapon/circuitboard/med_data
+9 -12
View File
@@ -33,7 +33,7 @@
if(breather.internals)
breather.internals.icon_state = "internal0"
breather.remove_from_mob(contained)
visible_message("<span class='notice'>The mask rapidly retracts just before /the [src] is destroyed!</span>")
visible_message("<span class='notice'>\The [contained] rapidly retracts just before /the [src] is destroyed!</span>")
breather = null
QDEL_NULL(tank)
@@ -45,11 +45,11 @@
if(istype(target) && CanMouseDrop(target))
if(!can_apply_to_target(target, usr)) // There is no point in attempting to apply a mask if it's impossible.
return
usr.visible_message("\The [usr] begins placing the mask onto [target]..")
usr.visible_message("\The [usr] begins placing \the [contained] onto [target].")
if(!do_mob(usr, target, 25) || !can_apply_to_target(target, usr))
return
// place mask and add fingerprints
usr.visible_message("\The [usr] has placed \the mask on [target]'s mouth.")
usr.visible_message("\The [usr] has placed \the [contained] on [target]'s mouth.")
attach_mask(target)
src.add_fingerprint(usr)
@@ -69,7 +69,7 @@
tank.forceMove(src)
breather.remove_from_mob(contained)
contained.forceMove(src)
src.visible_message("<span class='notice'>\The [user] makes \The [contained] rapidly retracts back into \the [src]!</span>")
src.visible_message("<span class='notice'>\The [user] makes \the [contained] rapidly retract back into \the [src]!</span>")
if(breather.internals)
breather.internals.icon_state = "internal0"
breather = null
@@ -112,7 +112,7 @@
to_chat(user, "<span class='warning'>There is no tank in \the [src].</span>")
return
if(stat & MAINT)
to_chat(user, "<span class='warning'>Please close \the maintenance hatch first.</span>")
to_chat(user, "<span class='warning'>Please close the maintenance hatch first.</span>")
return
if(!Adjacent(target))
to_chat(user, "<span class='warning'>Please stay close to \the [src].</span>")
@@ -123,18 +123,15 @@
return
//Checking if breather is still valid
if(target == breather && target.wear_mask != contained)
to_chat(user, "<span class='warning'>\The [target] is not using the supplied mask.</span>")
to_chat(user, "<span class='warning'>\The [target] is not using the supplied [contained].</span>")
return
return 1
/obj/machinery/oxygen_pump/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(W.is_screwdriver())
stat ^= MAINT
user.visible_message("<span class='notice'>\The [user] [stat & MAINT ? "opens" : "closes"] \the [src].</span>", "<span class='notice'>You [stat & MAINT ? "open" : "close"] \the [src].</span>")
if(stat & MAINT)
icon_state = icon_state_open
if(!stat)
icon_state = icon_state_closed
user.visible_message("<span class='notice'>\The [user] [(stat & MAINT) ? "opens" : "closes"] \the [src].</span>", "<span class='notice'>You [(stat & MAINT) ? "open" : "close"] \the [src].</span>")
icon_state = (stat & MAINT) ? icon_state_open : icon_state_closed
//TO-DO: Open icon
if(istype(W, /obj/item/weapon/tank) && (stat & MAINT))
if(tank)
@@ -151,7 +148,7 @@
/obj/machinery/oxygen_pump/examine(var/mob/user)
. = ..()
if(tank)
to_chat(user, "The meter shows [round(tank.air_contents.return_pressure())]")
to_chat(user, "The meter shows [round(tank.air_contents.return_pressure())] kPa.")
else
to_chat(user, "<span class='warning'>It is missing a tank!</span>")
@@ -14,7 +14,7 @@ var/global/list/ashtray_cache = list()
if(!material)
qdel(src)
return
max_butts = round(material.hardness/10) //This is arbitrary but whatever.
max_butts = round(material.hardness/5) //This is arbitrary but whatever.
src.pixel_y = rand(-5, 5)
src.pixel_x = rand(-6, 6)
update_icon()
@@ -3,7 +3,7 @@
* Welding Tool
*/
/obj/item/weapon/weldingtool
name = "welding tool"
name = "\improper welding tool"
icon = 'icons/obj/tools.dmi'
icon_state = "welder"
item_state = "welder"
@@ -9,18 +9,26 @@
var/icon_closed = "closed"
var/icon_opened = "open"
var/opened = 0
var/welded = 0
var/sealed = 0
var/seal_tool = /obj/item/weapon/weldingtool //Tool used to seal the closet, defaults to welder
var/wall_mounted = 0 //never solid (You can always pass over it)
var/health = 100
var/breakout = 0 //if someone is currently breaking out. mutex
var/breakout_time = 2 //2 minutes by default
var/breakout_sound = 'sound/effects/grillehit.ogg' //Sound that plays while breaking out
var/storage_capacity = 2 * MOB_MEDIUM //This is so that someone can't pack hundreds of items in a locker/crate
//then open it in a populated area to crash clients.
var/storage_cost = 40 //How much space this closet takes up if it's stuffed in another closet
var/open_sound = 'sound/machines/click.ogg'
var/close_sound = 'sound/machines/click.ogg'
var/store_misc = 1
var/store_items = 1
var/store_mobs = 1
var/store_misc = 1 //Chameleon item check
var/store_items = 1 //Will the closet store items?
var/store_mobs = 1 //Will the closet store mobs?
var/max_closets = 0 //Number of other closets allowed on tile before it won't close.
var/list/starts_with
@@ -42,7 +50,7 @@
content_size += Ceiling(I.w_class/2)
if(content_size > storage_capacity-5)
storage_capacity = content_size + 5
update_icon()
/obj/structure/closet/examine(mob/user)
if(..(user, 1) && !opened)
@@ -51,29 +59,33 @@
if(!I.anchored)
content_size += Ceiling(I.w_class/2)
if(!content_size)
user << "It is empty."
to_chat(user, "It is empty.")
else if(storage_capacity > content_size*4)
user << "It is barely filled."
to_chat(user, "It is barely filled.")
else if(storage_capacity > content_size*2)
user << "It is less than half full."
to_chat(user, "It is less than half full.")
else if(storage_capacity > content_size)
user << "There is still some free space."
to_chat(user, "There is still some free space.")
else
user << "It is full."
to_chat(user, "It is full.")
/obj/structure/closet/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(air_group || (height==0 || wall_mounted)) return 1
return (!density)
/obj/structure/closet/proc/can_open()
if(src.welded)
if(src.sealed)
return 0
return 1
/obj/structure/closet/proc/can_close()
var/closet_count = 0
for(var/obj/structure/closet/closet in get_turf(src))
if(closet != src)
return 0
if(!closet.anchored)
closet_count ++
if(closet_count > max_closets)
return 0
return 1
/obj/structure/closet/proc/dump_contents()
@@ -102,7 +114,7 @@
src.icon_state = src.icon_opened
src.opened = 1
playsound(src.loc, open_sound, 15, 1, -3)
density = 0
density = !density
return 1
/obj/structure/closet/proc/close()
@@ -119,12 +131,14 @@
stored_units += store_items(stored_units)
if(store_mobs)
stored_units += store_mobs(stored_units)
if(max_closets)
stored_units += store_closets(stored_units)
src.icon_state = src.icon_closed
src.opened = 0
playsound(src.loc, close_sound, 15, 1, -3)
density = 1
density = !density
return 1
//Cham Projector Exception
@@ -162,9 +176,25 @@
added_units += M.mob_size
return added_units
/obj/structure/closet/proc/store_closets(var/stored_units)
var/added_units = 0
for(var/obj/structure/closet/C in src.loc)
if(C == src) //Don't store ourself
continue
if(C.anchored) //Don't worry about anchored things on the same tile
continue
if(C.max_closets) //Prevents recursive storage
continue
if(stored_units + added_units + storage_cost > storage_capacity)
break
C.forceMove(src)
added_units += storage_cost
return added_units
/obj/structure/closet/proc/toggle(mob/user as mob)
if(!(src.opened ? src.close() : src.open()))
user << "<span class='notice'>It won't budge!</span>"
to_chat(user, "<span class='notice'>It won't budge!</span>")
return
update_icon()
@@ -222,7 +252,7 @@
if(!WT.isOn())
return
else
user << "<span class='notice'>You need more welding fuel to complete this task.</span>"
to_chat(user, "<span class='notice'>You need more welding fuel to complete this task.</span>")
return
playsound(src, WT.usesound, 50)
new /obj/item/stack/material/steel(src.loc)
@@ -248,21 +278,25 @@
W.forceMove(src.loc)
else if(istype(W, /obj/item/weapon/packageWrap))
return
else if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(!WT.remove_fuel(0,user))
if(!WT.isOn())
return
else
user << "<span class='notice'>You need more welding fuel to complete this task.</span>"
return
playsound(src, WT.usesound, 50)
src.welded = !src.welded
src.update_icon()
for(var/mob/M in viewers(src))
M.show_message("<span class='warning'>[src] has been [welded?"welded shut":"unwelded"] by [user.name].</span>", 3, "You hear welding.", 2)
else if(seal_tool)
if(istype(W, seal_tool))
var/obj/item/weapon/S = W
if(istype(S, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = S
if(!WT.remove_fuel(0,user))
if(!WT.isOn())
return
else
to_chat(user, "<span class='notice'>You need more welding fuel to complete this task.</span>")
return
if(do_after(user, 20 * S.toolspeed))
playsound(src, S.usesound, 50)
src.sealed = !src.sealed
src.update_icon()
for(var/mob/M in viewers(src))
M.show_message("<span class='warning'>[src] has been [sealed?"sealed":"unsealed"] by [user.name].</span>", 3)
else if(W.is_wrench())
if(welded)
if(sealed)
if(anchored)
user.visible_message("\The [user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
else
@@ -270,7 +304,7 @@
playsound(src, W.usesound, 50)
if(do_after(user, 20 * W.toolspeed))
if(!src) return
user << "<span class='notice'>You [anchored? "un" : ""]secured \the [src]!</span>"
to_chat(user, "<span class='notice'>You [anchored? "un" : ""]secured \the [src]!</span>")
anchored = !anchored
else
src.attack_hand(user)
@@ -306,7 +340,7 @@
return
if(!src.open())
user << "<span class='notice'>It won't budge!</span>"
to_chat(user, "<span class='notice'>It won't budge!</span>")
/obj/structure/closet/attack_hand(mob/user as mob)
src.add_fingerprint(user)
@@ -316,7 +350,7 @@
/obj/structure/closet/attack_self_tk(mob/user as mob)
src.add_fingerprint(user)
if(!src.toggle())
usr << "<span class='notice'>It won't budge!</span>"
to_chat(usr, "<span class='notice'>It won't budge!</span>")
/obj/structure/closet/attack_ghost(mob/ghost)
if(ghost.client && ghost.client.inquisitive_ghost)
@@ -336,14 +370,14 @@
src.add_fingerprint(usr)
src.toggle(usr)
else
usr << "<span class='warning'>This mob type can't use this verb.</span>"
to_chat(usr, "<span class='warning'>This mob type can't use this verb.</span>")
/obj/structure/closet/update_icon()//Putting the welded stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
/obj/structure/closet/update_icon()//Putting the sealed stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
overlays.Cut()
if(!opened)
icon_state = icon_closed
if(welded)
overlays += "welded"
if(sealed)
overlays += "sealed"
else
icon_state = icon_opened
@@ -359,20 +393,19 @@
/obj/structure/closet/proc/req_breakout()
if(opened)
return 0 //Door's open... wait, why are you in it's contents then?
if(!welded)
return 0 //closed but not welded...
if(!sealed)
return 0 //closed but not sealed...
return 1
/obj/structure/closet/proc/mob_breakout(var/mob/living/escapee)
var/breakout_time = 2 //2 minutes by default
if(breakout || !req_breakout())
return
escapee.setClickCooldown(100)
//okay, so the closet is either welded or locked... resist!!!
escapee << "<span class='warning'>You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)</span>"
//okay, so the closet is either sealed or locked... resist!!!
to_chat(escapee, "<span class='warning'>You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)</span>")
visible_message("<span class='danger'>\The [src] begins to shake violently!</span>")
@@ -389,20 +422,20 @@
breakout = 0
return
playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1)
playsound(src.loc, breakout_sound, 100, 1)
animate_shake()
add_fingerprint(escapee)
//Well then break it!
breakout = 0
escapee << "<span class='warning'>You successfully break out!</span>"
to_chat(escapee, "<span class='warning'>You successfully break out!</span>")
visible_message("<span class='danger'>\The [escapee] successfully broke out of \the [src]!</span>")
playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1)
playsound(src.loc, breakout_sound, 100, 1)
break_open()
animate_shake()
/obj/structure/closet/proc/break_open()
welded = 0
sealed = 0
update_icon()
//Do this to prevent contents from being opened into nullspace (read: bluespace)
if(istype(loc, /obj/structure/bigDelivery))
@@ -421,3 +454,9 @@
/obj/structure/closet/AllowDrop()
return TRUE
/obj/structure/closet/return_air_for_internal_lifeform(var/mob/living/L)
if(src.loc)
if(istype(src.loc, /obj/structure/closet))
return (loc.return_air_for_internal_lifeform(L))
return return_air()
@@ -4,9 +4,161 @@
icon_state = "coffin"
icon_closed = "coffin"
icon_opened = "coffin_open"
seal_tool = /obj/item/weapon/tool/screwdriver
breakout_sound = 'sound/weapons/tablehit1.ogg'
/obj/structure/closet/coffin/update_icon()
if(!opened)
icon_state = icon_closed
else
icon_state = icon_opened
/* Graves */
/obj/structure/closet/grave
name = "grave"
desc = "Dirt."
icon_state = "grave"
icon_closed = "grave"
icon_opened = "grave_open"
seal_tool = null
breakout_sound = 'sound/weapons/thudswoosh.ogg'
anchored = 1
max_closets = 1
opened = 1
/obj/structure/closet/grave/attack_hand(mob/user as mob)
if(opened)
visible_message("<span class='notice'>[user] starts to climb into \the [src.name].</span>", \
"<span class='notice'>You start to lower yourself into \the [src.name].</span>")
if(do_after(user, 50))
user.forceMove(src.loc)
visible_message("<span class='notice'>[user] climbs into \the [src.name].</span>", \
"<span class='notice'>You climb into \the [src.name].</span>")
else
visible_message("<span class='notice'>[user] decides not to climb into \the [src.name].</span>", \
"<span class='notice'>You stop climbing into \the [src.name].</span>")
return
/obj/structure/closet/grave/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(opened && ismob(mover))
var/mob/M = mover
add_fingerprint(M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.m_intent == "walk")
to_chat(H, "<span class='warning'>You stop at the edge of \the [src.name].</span>")
return FALSE
else
to_chat(H, "<span class='warning'>You fall into \the [src.name]!</span>")
fall_in(H)
return TRUE
if(isrobot(M))
var/mob/living/silicon/robot/R = M
if(R.a_intent == I_HELP)
to_chat(R, "<span class='warning'>You stop at the edge of \the [src.name].</span>")
return FALSE
else
to_chat(R, "<span class='warning'>You enter \the [src.name].</span>")
return TRUE
return TRUE //Everything else can move over the graves
/obj/structure/closet/grave/proc/fall_in(mob/living/L) //Only called on humans for now, but still
L.Weaken(5)
if(ishuman(L))
var/mob/living/carbon/human/H = L
var/limb_damage = rand(5,25)
H.adjustBruteLoss(limb_damage)
/obj/structure/closet/grave/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(src.opened)
if(istype(W, /obj/item/weapon/shovel))
user.visible_message("<span class='notice'>[user] piles dirt into \the [src.name].</span>", \
"<span class='notice'>You start to pile dirt into \the [src.name].</span>", \
"<span class='notice'>You hear dirt being moved.</span>")
if(do_after(user, 40 * W.toolspeed))
user.visible_message("<span class='notice'>[user] pats down the dirt on top of \the [src.name].</span>", \
"<span class='notice'>You finish filling in \the [src.name].</span>")
close()
return
else
user.visible_message("<span class='notice'>[user] stops filling in \the [src.name].</span>", \
"<span class='notice'>You change your mind and stop filling in \the [src.name].</span>")
return
if(istype(W, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = W
src.MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet
return 0
if(istype(W,/obj/item/tk_grab))
return 0
if(istype(W, /obj/item/weapon/storage/laundry_basket) && W.contents.len)
var/obj/item/weapon/storage/laundry_basket/LB = W
var/turf/T = get_turf(src)
for(var/obj/item/I in LB.contents)
LB.remove_from_storage(I, T)
user.visible_message("<span class='notice'>[user] empties \the [LB] into \the [src].</span>", \
"<span class='notice'>You empty \the [LB] into \the [src].</span>", \
"<span class='notice'>You hear rustling of clothes.</span>")
return
if(isrobot(user))
return
if(W.loc != user) // This should stop mounted modules ending up outside the module.
return
usr.drop_item()
if(W)
W.forceMove(src.loc)
else
if(istype(W, /obj/item/weapon/shovel))
if(user.a_intent == I_HURT) // Hurt intent means you're trying to kill someone, or just get rid of the grave
user.visible_message("<span class='notice'>[user] begins to smoothe out the dirt of \the [src.name].</span>", \
"<span class='notice'>You start to smoothe out the dirt of \the [src.name].</span>", \
"<span class='notice'>You hear dirt being moved.</span>")
if(do_after(user, 40 * W.toolspeed))
user.visible_message("<span class='notice'>[user] finishes smoothing out \the [src.name].</span>", \
"<span class='notice'>You finish smoothing out \the [src.name].</span>")
if(LAZYLEN(contents))
alpha = 40 // If we've got stuff inside, like maybe a person, just make it hard to see us
else
qdel(src) // Else, go away
return
else
user.visible_message("<span class='notice'>[user] stops concealing \the [src.name].</span>", \
"<span class='notice'>You stop concealing \the [src.name].</span>")
return
else
user.visible_message("<span class='notice'>[user] begins to unearth \the [src.name].</span>", \
"<span class='notice'>You start to unearth \the [src.name].</span>", \
"<span class='notice'>You hear dirt being moved.</span>")
if(do_after(user, 40 * W.toolspeed))
user.visible_message("<span class='notice'>[user] reaches the bottom of \the [src.name].</span>", \
"<span class='notice'>You finish digging out \the [src.name].</span>")
break_open()
return
else
user.visible_message("<span class='notice'>[user] stops digging out \the [src.name].</span>", \
"<span class='notice'>You stop digging out \the [src.name].</span>")
return
return
/obj/structure/closet/grave/close()
..()
if(!opened)
sealed = TRUE
/obj/structure/closet/grave/open()
.=..()
alpha = 255 // Needed because of grave hiding
/obj/structure/closet/grave/bullet_act(var/obj/item/projectile/P)
return PROJECTILE_CONTINUE // It's a hole in the ground, doesn't usually stop or even care about bullets
/obj/structure/closet/grave/return_air_for_internal_lifeform(var/mob/living/L)
var/gasid = "carbon_dioxide"
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.species && H.species.exhale_type)
gasid = H.species.exhale_type
var/datum/gas_mixture/grave_breath = new()
var/datum/gas_mixture/above_air = return_air()
grave_breath.adjust_gas(gasid, BREATH_MOLES)
grave_breath.temperature = (above_air.temperature) - 30 //Underground
return grave_breath
@@ -10,7 +10,7 @@
open_sound = 'sound/vore/schlorp.ogg'
close_sound = 'sound/vore/schlorp.ogg'
opened = 0
welded = 0 //Don't touch this.
sealed = 0 //Don't touch this.
health = 100
/obj/structure/closet/secure_closet/egg/attackby(obj/item/weapon/W, mob/user as mob) //This also prevents crew from welding the eggs and making them unable to be opened.
@@ -43,8 +43,8 @@
overlays += icon(src.icon, "door")
if(welded)
overlays += icon(src.icon,"welded")
if(sealed)
overlays += icon(src.icon,"sealed")
if(broken)
overlays += icon(src.icon,"broken")
@@ -46,23 +46,23 @@
/obj/structure/closet/secure_closet/proc/togglelock(mob/user as mob)
if(src.opened)
user << "<span class='notice'>Close the locker first.</span>"
to_chat(user, "<span class='notice'>Close the locker first.</span>")
return
if(src.broken)
user << "<span class='warning'>The locker appears to be broken.</span>"
to_chat(user, "<span class='warning'>The locker appears to be broken.</span>")
return
if(user.loc == src)
user << "<span class='notice'>You can't reach the lock from inside.</span>"
to_chat(user, "<span class='notice'>You can't reach the lock from inside.</span>")
return
if(src.allowed(user))
src.locked = !src.locked
playsound(src.loc, 'sound/machines/click.ogg', 15, 1, -3)
for(var/mob/O in viewers(user, 3))
if((O.client && !( O.blinded )))
O << "<span class='notice'>The locker has been [locked ? null : "un"]locked by [user].</span>"
to_chat(O, "<span class='notice'>The locker has been [locked ? null : "un"]locked by [user].</span>")
update_icon()
else
user << "<span class='notice'>Access Denied</span>"
to_chat(user, "<span class='notice'>Access Denied</span>")
/obj/structure/closet/secure_closet/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(src.opened)
@@ -73,7 +73,7 @@
if(src.large)
src.MouseDrop_T(G.affecting, user) //act like they were dragged onto the closet
else
user << "<span class='notice'>The locker is too small to stuff [G.affecting] into!</span>"
to_chat(user, "<span class='notice'>The locker is too small to stuff [G.affecting] into!</span>")
if(isrobot(user))
return
if(W.loc != user) // This should stop mounted modules ending up outside the module.
@@ -89,14 +89,14 @@
playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1)
playsound(src.loc, "sparks", 50, 1)
else if(W.is_wrench())
if(welded)
if(sealed)
if(anchored)
user.visible_message("\The [user] begins unsecuring \the [src] from the floor.", "You start unsecuring \the [src] from the floor.")
else
user.visible_message("\The [user] begins securing \the [src] to the floor.", "You start securing \the [src] to the floor.")
if(do_after(user, 20 * W.toolspeed))
if(!src) return
user << "<span class='notice'>You [anchored? "un" : ""]secured \the [src]!</span>"
to_chat(user, "<span class='notice'>You [anchored? "un" : ""]secured \the [src]!</span>")
anchored = !anchored
return
else if(istype(W,/obj/item/weapon/packageWrap) || istype(W,/obj/item/weapon/weldingtool))
@@ -143,9 +143,9 @@
src.add_fingerprint(usr)
src.togglelock(usr)
else
usr << "<span class='warning'>This mob type can't use this verb.</span>"
to_chat(usr, "<span class='warning'>This mob type can't use this verb.</span>")
/obj/structure/closet/secure_closet/update_icon()//Putting the welded stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
/obj/structure/closet/secure_closet/update_icon()//Putting the sealed stuff in updateicon() so it's easy to overwrite for special cases (Fridges, cabinets, and whatnot)
overlays.Cut()
if(!opened)
@@ -155,8 +155,8 @@
icon_state = icon_locked
else
icon_state = icon_closed
if(welded)
overlays += "welded"
if(sealed)
overlays += "sealed"
else
icon_state = icon_opened
+22 -1
View File
@@ -593,6 +593,25 @@ var/list/admin_verbs_event_manager = list(
feedback_add_details("admin_verb","OC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return
/client/proc/findStealthKey(txt)
if(txt)
for(var/P in GLOB.stealthminID)
if(GLOB.stealthminID[P] == txt)
return P
txt = GLOB.stealthminID[ckey]
return txt
/client/proc/createStealthKey()
var/num = (rand(0,1000))
var/i = 0
while(i == 0)
i = 1
for(var/P in GLOB.stealthminID)
if(num == GLOB.stealthminID[P])
num++
i = 0
GLOB.stealthminID["[ckey]"] = "@[num2text(num)]"
/client/proc/stealth()
set category = "Admin"
set name = "Stealth Mode"
@@ -603,10 +622,12 @@ var/list/admin_verbs_event_manager = list(
mob.name = capitalize(ckey)
else
var/new_key = ckeyEx(input("Enter your desired display name.", "Fake Key", key) as text|null)
if(!new_key) return
if(!new_key)
return
if(length(new_key) >= 26)
new_key = copytext(new_key, 1, 26)
holder.fakekey = new_key
createStealthKey()
if(istype(mob, /mob/new_player))
mob.name = new_key
log_admin("[key_name(usr)] has turned stealth mode [holder.fakekey ? "ON" : "OFF"]")
+20 -2
View File
@@ -10,6 +10,20 @@
check_antagonists()
return
if(href_list["ahelp"])
if(!check_rights(R_ADMIN))
return
var/ahelp_ref = href_list["ahelp"]
var/datum/admin_help/AH = locate(ahelp_ref)
if(AH)
AH.Action(href_list["ahelp_action"])
else
to_chat(usr, "Ticket [ahelp_ref] has been deleted!")
else if(href_list["ahelp_tickets"])
GLOB.ahelp_tickets.BrowseTickets(text2num(href_list["ahelp_tickets"]))
if(href_list["dbsearchckey"] || href_list["dbsearchadmin"])
var/adminckey = href_list["dbsearchadmin"]
@@ -841,7 +855,9 @@
M << "<font color='red'>No ban appeals URL has been set.</font>"
log_admin("[usr.client.ckey] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.")
message_admins("<font color='blue'>[usr.client.ckey] has banned [M.ckey].\nReason: [reason]\nThis will be removed in [mins] minutes.</font>")
var/datum/admin_help/AH = M.client ? M.client.current_ticket : null
if(AH)
AH.Resolve()
qdel(M.client)
//qdel(M) // See no reason why to delete mob. Important stuff can be lost. And ban can be lifted before round ends.
if("No")
@@ -867,7 +883,9 @@
message_admins("<font color='blue'>[usr.client.ckey] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.</font>")
feedback_inc("ban_perma",1)
DB_ban_record(BANTYPE_PERMA, M, -1, reason)
var/datum/admin_help/AH = M.client ? M.client.current_ticket : null
if(AH)
AH.Resolve()
qdel(M.client)
//qdel(M)
if("Cancel")
+595 -64
View File
@@ -1,32 +1,599 @@
/client/var/datum/admin_help/current_ticket //the current ticket the (usually) not-admin client is dealing with
//This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE!
var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as")
//
//TICKET MANAGER
//
GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
/datum/admin_help_tickets
var/list/active_tickets = list()
var/list/closed_tickets = list()
var/list/resolved_tickets = list()
var/obj/effect/statclick/ticket_list/astatclick = new(null, null, AHELP_ACTIVE)
var/obj/effect/statclick/ticket_list/cstatclick = new(null, null, AHELP_CLOSED)
var/obj/effect/statclick/ticket_list/rstatclick = new(null, null, AHELP_RESOLVED)
/datum/admin_help_tickets/Destroy()
QDEL_LIST(active_tickets)
QDEL_LIST(closed_tickets)
QDEL_LIST(resolved_tickets)
QDEL_NULL(astatclick)
QDEL_NULL(cstatclick)
QDEL_NULL(rstatclick)
return ..()
//private
/datum/admin_help_tickets/proc/ListInsert(datum/admin_help/new_ticket)
var/list/ticket_list
switch(new_ticket.state)
if(AHELP_ACTIVE)
ticket_list = active_tickets
if(AHELP_CLOSED)
ticket_list = closed_tickets
if(AHELP_RESOLVED)
ticket_list = resolved_tickets
else
CRASH("Invalid ticket state: [new_ticket.state]")
var/num_closed = ticket_list.len
if(num_closed)
for(var/I in 1 to num_closed)
var/datum/admin_help/AH = ticket_list[I]
if(AH.id > new_ticket.id)
ticket_list.Insert(I, new_ticket)
return
ticket_list += new_ticket
//opens the ticket listings for one of the 3 states
/datum/admin_help_tickets/proc/BrowseTickets(state)
var/list/l2b
var/title
switch(state)
if(AHELP_ACTIVE)
l2b = active_tickets
title = "Active Tickets"
if(AHELP_CLOSED)
l2b = closed_tickets
title = "Closed Tickets"
if(AHELP_RESOLVED)
l2b = resolved_tickets
title = "Resolved Tickets"
if(!l2b)
return
var/list/dat = list("<html><head><title>[title]</title></head>")
dat += "<A HREF='?_src_=holder;ahelp_tickets=[state]'>Refresh</A><br><br>"
for(var/I in l2b)
var/datum/admin_help/AH = I
dat += "<span class='adminnotice'><span class='adminhelp'>Ticket #[AH.id]</span>: <A HREF='?_src_=holder;ahelp=\ref[AH];ahelp_action=ticket'>[AH.initiator_key_name]: [AH.name]</A></span><br>"
usr << browse(dat.Join(), "window=ahelp_list[state];size=600x480")
//Tickets statpanel
/datum/admin_help_tickets/proc/stat_entry()
var/num_disconnected = 0
stat("Active Tickets:", astatclick.update("[active_tickets.len]"))
for(var/I in active_tickets)
var/datum/admin_help/AH = I
if(AH.initiator)
stat("#[AH.id]. [AH.initiator_key_name]:", AH.statclick.update())
else
++num_disconnected
if(num_disconnected)
stat("Disconnected:", astatclick.update("[num_disconnected]"))
stat("Closed Tickets:", cstatclick.update("[closed_tickets.len]"))
stat("Resolved Tickets:", rstatclick.update("[resolved_tickets.len]"))
//Reassociate still open ticket if one exists
/datum/admin_help_tickets/proc/ClientLogin(client/C)
C.current_ticket = CKey2ActiveTicket(C.ckey)
if(C.current_ticket)
C.current_ticket.AddInteraction("Client reconnected.")
C.current_ticket.initiator = C
//Dissasociate ticket
/datum/admin_help_tickets/proc/ClientLogout(client/C)
if(C.current_ticket)
C.current_ticket.AddInteraction("Client disconnected.")
C.current_ticket.initiator = null
C.current_ticket = null
//Get a ticket given a ckey
/datum/admin_help_tickets/proc/CKey2ActiveTicket(ckey)
for(var/I in active_tickets)
var/datum/admin_help/AH = I
if(AH.initiator_ckey == ckey)
return AH
//
//TICKET LIST STATCLICK
//
/obj/effect/statclick/ticket_list
var/current_state
/obj/effect/statclick/ticket_list/New(loc, name, state)
current_state = state
..()
/obj/effect/statclick/ticket_list/Click()
GLOB.ahelp_tickets.BrowseTickets(current_state)
//
//TICKET DATUM
//
/datum/admin_help
var/id
var/name
var/state = AHELP_ACTIVE
var/opened_at
var/closed_at
var/client/initiator //semi-misnomer, it's the person who ahelped/was bwoinked
var/initiator_ckey
var/initiator_key_name
var/list/_interactions //use AddInteraction() or, preferably, admin_ticket_log()
var/obj/effect/statclick/ahelp/statclick
var/static/ticket_counter = 0
//call this on its own to create a ticket, don't manually assign current_ticket
//msg is the title of the ticket: usually the ahelp text
//is_bwoink is TRUE if this ticket was started by an admin PM
/datum/admin_help/New(msg, client/C, is_bwoink)
//clean the input msg
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
if(!msg || !C || !C.mob)
qdel(src)
return
id = ++ticket_counter
opened_at = world.time
name = msg
initiator = C
initiator_ckey = initiator.ckey
initiator_key_name = key_name(initiator, FALSE, TRUE)
if(initiator.current_ticket) //This is a bug
log_debug("Multiple ahelp current_tickets")
initiator.current_ticket.AddInteraction("Ticket erroneously left open by code")
initiator.current_ticket.Close()
initiator.current_ticket = src
var/parsed_message = keywords_lookup(msg)
statclick = new(null, src)
_interactions = list()
if(is_bwoink)
AddInteraction("<font color='blue'>[key_name_admin(usr)] PM'd [LinkedReplyName()]</font>")
message_admins("<font color='blue'>Ticket [TicketHref("#[id]")] created</font>")
else
MessageNoRecipient(parsed_message)
//show it to the person adminhelping too
to_chat(C, "<span class='adminnotice'>PM to-<b>Admins</b>: [name]</span>")
//send it to irc if nobody is on and tell us how many were on
var/admin_number_present = send2irc_adminless_only(initiator_ckey, name)
log_admin("Ticket #[id]: [key_name(initiator)]: [name] - heard by [admin_number_present] non-AFK admins who have +BAN.")
if(admin_number_present <= 0)
to_chat(C, "<span class='notice'>No active admins are online, your adminhelp was sent to the admin irc.</span>")
send2adminchat() //VOREStation Add
GLOB.ahelp_tickets.active_tickets += src
/datum/admin_help/Destroy()
RemoveActive()
GLOB.ahelp_tickets.closed_tickets -= src
GLOB.ahelp_tickets.resolved_tickets -= src
return ..()
/datum/admin_help/proc/AddInteraction(formatted_message)
_interactions += "[gameTimestamp()]: [formatted_message]"
//private
/datum/admin_help/proc/FullMonty(ref_src)
if(!ref_src)
ref_src = "\ref[src]"
. = ADMIN_FULLMONTY_NONAME(initiator.mob)
if(state == AHELP_ACTIVE)
. += ClosureLinks(ref_src)
//private
/datum/admin_help/proc/ClosureLinks(ref_src)
if(!ref_src)
ref_src = "\ref[src]"
. = " (<A HREF='?_src_=holder;ahelp=[ref_src];ahelp_action=reject'>REJT</A>)"
. += " (<A HREF='?_src_=holder;ahelp=[ref_src];ahelp_action=icissue'>IC</A>)"
. += " (<A HREF='?_src_=holder;ahelp=[ref_src];ahelp_action=close'>CLOSE</A>)"
. += " (<A HREF='?_src_=holder;ahelp=[ref_src];ahelp_action=resolve'>RSLVE</A>)"
. += " (<A HREF='?_src_=holder;ahelp=[ref_src];ahelp_action=handleissue'>HANDLE</A>)"
//private
/datum/admin_help/proc/LinkedReplyName(ref_src)
if(!ref_src)
ref_src = "\ref[src]"
return "<A HREF='?_src_=holder;ahelp=[ref_src];ahelp_action=reply'>[initiator_key_name]</A>"
//private
/datum/admin_help/proc/TicketHref(msg, ref_src, action = "ticket")
if(!ref_src)
ref_src = "\ref[src]"
return "<A HREF='?_src_=holder;ahelp=[ref_src];ahelp_action=[action]'>[msg]</A>"
//message from the initiator without a target, all admins will see this
//won't bug irc
/datum/admin_help/proc/MessageNoRecipient(msg)
var/ref_src = "\ref[src]"
var/chat_msg = "<span class='adminnotice'><span class='adminhelp'>Ticket [TicketHref("#[id]", ref_src)]</span><b>: [LinkedReplyName(ref_src)] [FullMonty(ref_src)]:</b> [msg]</span>"
AddInteraction("<font color='red'>[LinkedReplyName(ref_src)]: [msg]</font>")
//send this msg to all admins
for(var/client/X in admins)
if(X.is_preference_enabled(/datum/client_preference/holder/play_adminhelp_ping))
X << 'sound/effects/adminhelp.ogg'
window_flash(X)
to_chat(X, chat_msg)
//Reopen a closed ticket
/datum/admin_help/proc/Reopen()
if(state == AHELP_ACTIVE)
to_chat(usr, "<span class='warning'>This ticket is already open.</span>")
return
if(GLOB.ahelp_tickets.CKey2ActiveTicket(initiator_ckey))
to_chat(usr, "<span class='warning'>This user already has an active ticket, cannot reopen this one.</span>")
return
statclick = new(null, src)
GLOB.ahelp_tickets.active_tickets += src
GLOB.ahelp_tickets.closed_tickets -= src
GLOB.ahelp_tickets.resolved_tickets -= src
switch(state)
if(AHELP_CLOSED)
feedback_dec("ahelp_close")
if(AHELP_RESOLVED)
feedback_dec("ahelp_resolve")
state = AHELP_ACTIVE
closed_at = null
if(initiator)
initiator.current_ticket = src
AddInteraction("<font color='purple'>Reopened by [key_name_admin(usr)]</font>")
if(initiator)
to_chat(initiator, "<font color='purple'>Ticket [TicketHref("#[id]")] was reopened by [key_name(usr)].</font>")
var/msg = "<span class='adminhelp'>Ticket [TicketHref("#[id]")] reopened by [key_name_admin(usr)].</span>"
message_admins(msg)
log_admin(msg)
feedback_inc("ahelp_reopen")
TicketPanel() //can only be done from here, so refresh it
//private
/datum/admin_help/proc/RemoveActive()
if(state != AHELP_ACTIVE)
return
closed_at = world.time
QDEL_NULL(statclick)
GLOB.ahelp_tickets.active_tickets -= src
if(initiator && initiator.current_ticket == src)
initiator.current_ticket = null
//Mark open ticket as closed/meme
/datum/admin_help/proc/Close(silent = FALSE)
if(state != AHELP_ACTIVE)
return
RemoveActive()
state = AHELP_CLOSED
GLOB.ahelp_tickets.ListInsert(src)
AddInteraction("<font color='red'>Closed by [key_name_admin(usr)].</font>")
if(initiator)
to_chat(initiator, "<font color='red'>Ticket [TicketHref("#[id]")] was closed by [key_name(usr)].</font>")
if(!silent)
feedback_inc("ahelp_close")
var/msg = "Ticket [TicketHref("#[id]")] closed by [key_name_admin(usr)]."
message_admins(msg)
log_admin(msg)
//Mark open ticket as resolved/legitimate, returns ahelp verb
/datum/admin_help/proc/Resolve(silent = FALSE)
if(state != AHELP_ACTIVE)
return
RemoveActive()
state = AHELP_RESOLVED
GLOB.ahelp_tickets.ListInsert(src)
AddInteraction("<font color='green'>Resolved by [key_name_admin(usr)].</font>")
if(initiator)
to_chat(initiator, "<font color='green'>Ticket [TicketHref("#[id]")] was marked resolved by [key_name(usr)].</font>")
if(!silent)
feedback_inc("ahelp_resolve")
var/msg = "Ticket [TicketHref("#[id]")] resolved by [key_name_admin(usr)]"
message_admins(msg)
log_admin(msg)
//Close and return ahelp verb, use if ticket is incoherent
/datum/admin_help/proc/Reject(key_name = key_name_admin(usr))
if(state != AHELP_ACTIVE)
return
if(initiator)
initiator << 'sound/effects/adminhelp.ogg'
to_chat(initiator, "<font color='red' size='4'><b>- AdminHelp Rejected! -</b></font>")
to_chat(initiator, "<font color='red'><b>Your admin help was rejected.</b></font>")
to_chat(initiator, "Please try to be calm, clear, and descriptive in admin helps, do not assume the admin has seen any related events, and clearly state the names of anybody you are reporting.")
feedback_inc("ahelp_reject")
var/msg = "Ticket [TicketHref("#[id]")] rejected by [key_name_admin(usr)]"
message_admins(msg)
log_admin(msg)
AddInteraction("Rejected by [key_name_admin(usr)].")
Close(silent = TRUE)
//Resolve ticket with IC Issue message
/datum/admin_help/proc/ICIssue(key_name = key_name_admin(usr))
if(state != AHELP_ACTIVE)
return
var/msg = "<font color='red' size='4'><b>- AdminHelp marked as IC issue! -</b></font><br>"
msg += "<font color='red'><b>Losing is part of the game!</b></font><br>"
msg += "<font color='red'>Your AdminHelp may also be unabled to be answered due to ongoing events.</font>"
if(initiator)
to_chat(initiator, msg)
feedback_inc("ahelp_icissue")
msg = "Ticket [TicketHref("#[id]")] marked as IC by [key_name_admin(usr)]"
message_admins(msg)
log_admin(msg)
AddInteraction("Marked as IC issue by [key_name_admin(usr)]")
Resolve(silent = TRUE)
//Resolve ticket with IC Issue message
/datum/admin_help/proc/HandleIssue()
if(state != AHELP_ACTIVE)
return
var/msg = "<font color='red'>Your AdminHelp is being handled by [key_name(usr)] please be patient.</font>"
if(initiator)
to_chat(initiator, msg)
feedback_inc("ahelp_icissue")
msg = "Ticket [TicketHref("#[id]")] being handled by [key_name(usr)]"
message_admins(msg)
log_admin(msg)
AddInteraction("[key_name_admin(usr)] is now handling this ticket.")
//Show the ticket panel
/datum/admin_help/proc/TicketPanel()
var/list/dat = list("<html><head><title>Ticket #[id]</title></head>")
var/ref_src = "\ref[src]"
dat += "<h4>Admin Help Ticket #[id]: [LinkedReplyName(ref_src)]</h4>"
dat += "<b>State: "
switch(state)
if(AHELP_ACTIVE)
dat += "<font color='red'>OPEN</font>"
if(AHELP_RESOLVED)
dat += "<font color='green'>RESOLVED</font>"
if(AHELP_CLOSED)
dat += "CLOSED"
else
dat += "UNKNOWN"
dat += "</b>[GLOB.TAB][TicketHref("Refresh", ref_src)][GLOB.TAB][TicketHref("Re-Title", ref_src, "retitle")]"
if(state != AHELP_ACTIVE)
dat += "[GLOB.TAB][TicketHref("Reopen", ref_src, "reopen")]"
dat += "<br><br>Opened at: [gameTimestamp(wtime = opened_at)] (Approx [(world.time - opened_at) / 600] minutes ago)"
if(closed_at)
dat += "<br>Closed at: [gameTimestamp(wtime = closed_at)] (Approx [(world.time - closed_at) / 600] minutes ago)"
dat += "<br><br>"
if(initiator)
dat += "<b>Actions:</b> [FullMonty(ref_src)]<br>"
else
dat += "<b>DISCONNECTED</b>[GLOB.TAB][ClosureLinks(ref_src)]<br>"
dat += "<br><b>Log:</b><br><br>"
for(var/I in _interactions)
dat += "[I]<br>"
usr << browse(dat.Join(), "window=ahelp[id];size=620x480")
/datum/admin_help/proc/Retitle()
var/new_title = input(usr, "Enter a title for the ticket", "Rename Ticket", name) as text|null
if(new_title)
name = new_title
//not saying the original name cause it could be a long ass message
var/msg = "Ticket [TicketHref("#[id]")] titled [name] by [key_name_admin(usr)]"
message_admins(msg)
log_admin(msg)
TicketPanel() //we have to be here to do this
//Forwarded action from admin/Topic
/datum/admin_help/proc/Action(action)
testing("Ahelp action: [action]")
switch(action)
if("ticket")
TicketPanel()
if("retitle")
Retitle()
if("reject")
Reject()
if("reply")
usr.client.cmd_ahelp_reply(initiator)
if("icissue")
ICIssue()
if("close")
Close()
if("resolve")
Resolve()
if("handleissue")
HandleIssue()
if("reopen")
Reopen()
//
// TICKET STATCLICK
//
/obj/effect/statclick/ahelp
var/datum/admin_help/ahelp_datum
/obj/effect/statclick/ahelp/New(loc, datum/admin_help/AH)
ahelp_datum = AH
..(loc)
/obj/effect/statclick/ahelp/update()
return ..(ahelp_datum.name)
/obj/effect/statclick/ahelp/Click()
ahelp_datum.TicketPanel()
/obj/effect/statclick/ahelp/Destroy()
ahelp_datum = null
return ..()
//
// CLIENT PROCS
//
/client/verb/adminhelp(msg as text)
set category = "Admin"
set name = "Adminhelp"
if(say_disabled) //This is here to try to identify lag problems
usr << "<font color='red'>Speech is currently admin-disabled.</font>"
to_chat(usr, "<span class='danger'>Speech is currently admin-disabled.</span>")
return
//handle muting and automuting
if(prefs.muted & MUTE_ADMINHELP)
src << "<font color='red'>Error: Admin-PM: You cannot send adminhelps (Muted).</font>"
to_chat(src, "<span class='danger'>Error: Admin-PM: You cannot send adminhelps (Muted).</span>")
return
if(handle_spam_prevention(msg,MUTE_ADMINHELP))
return
adminhelped = 1 //Determines if they get the message to reply by clicking the name.
if(msg)
handle_spam_prevention(MUTE_ADMINHELP)
//clean the input msg
if(!msg)
return
msg = sanitize(msg)
if(!msg)
//remove out adminhelp verb temporarily to prevent spamming of admins.
src.verbs -= /client/verb/adminhelp
spawn(1200)
src.verbs += /client/verb/adminhelp // 2 minute cool-down for adminhelps
feedback_add_details("admin_verb","Adminhelp") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(current_ticket)
if(alert(usr, "You already have a ticket open. Is this for the same issue?",,"Yes","No") != "No")
if(current_ticket)
current_ticket.MessageNoRecipient(msg)
return
else
to_chat(usr, "<span class='warning'>Ticket not found, creating new one...</span>")
else
current_ticket.AddInteraction("[key_name_admin(usr)] opened a new ticket.")
current_ticket.Close()
new /datum/admin_help(msg, src, FALSE)
//admin proc
/client/proc/cmd_admin_ticket_panel()
set name = "Show Ticket List"
set category = "Admin"
if(!check_rights(R_ADMIN, TRUE))
return
var/original_msg = msg
var/browse_to
switch(input("Display which ticket list?") as null|anything in list("Active Tickets", "Closed Tickets", "Resolved Tickets"))
if("Active Tickets")
browse_to = AHELP_ACTIVE
if("Closed Tickets")
browse_to = AHELP_CLOSED
if("Resolved Tickets")
browse_to = AHELP_RESOLVED
else
return
GLOB.ahelp_tickets.BrowseTickets(browse_to)
//
// LOGGING
//
//Use this proc when an admin takes action that may be related to an open ticket on what
//what can be a client, ckey, or mob
/proc/admin_ticket_log(what, message)
var/client/C
var/mob/Mob = what
if(istype(Mob))
C = Mob.client
else
C = what
if(istype(C) && C.current_ticket)
C.current_ticket.AddInteraction(message)
return C.current_ticket
if(istext(what)) //ckey
var/datum/admin_help/AH = GLOB.ahelp_tickets.CKey2ActiveTicket(what)
if(AH)
AH.AddInteraction(message)
return AH
//
// HELPER PROCS
//
/proc/get_admin_counts(requiredflags = R_BAN)
. = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list())
for(var/client/X in admins)
.["total"] += X
if(requiredflags != 0 && !check_rights(rights_required = requiredflags, show_msg = FALSE, C = X)) //VOREStation Edit
.["noflags"] += X
else if(X.is_afk())
.["afk"] += X
else if(X.holder.fakekey)
.["stealth"] += X
else
.["present"] += X
/proc/send2irc_adminless_only(source, msg, requiredflags = R_BAN)
var/list/adm = get_admin_counts()
var/list/activemins = adm["present"]
. = activemins.len
if(. <= 0)
var/final = ""
var/list/afkmins = adm["afk"]
var/list/stealthmins = adm["stealth"]
var/list/powerlessmins = adm["noflags"]
var/list/allmins = adm["total"]
if(!afkmins.len && !stealthmins.len && !powerlessmins.len)
final = "[msg] - No admins online"
else
final = "[msg] - All admins stealthed\[[english_list(stealthmins)]\], AFK\[[english_list(afkmins)]\], or lacks +BAN\[[english_list(powerlessmins)]\]! Total: [allmins.len] "
send2irc(source,final)
/proc/ircadminwho()
var/list/message = list("Admins: ")
var/list/admin_keys = list()
for(var/adm in admins)
var/client/C = adm
admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]"
for(var/admin in admin_keys)
if(LAZYLEN(admin_keys) > 1)
message += ", [admin]"
else
message += "[admin]"
return jointext(message, "")
/proc/keywords_lookup(msg,irc)
//This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE!
var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as", "i")
//explode the input msg into a list
var/list/msglist = splittext(msg, " ")
@@ -35,9 +602,11 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
var/list/surnames = list()
var/list/forenames = list()
var/list/ckeys = list()
var/founds = ""
for(var/mob/M in mob_list)
var/list/indexing = list(M.real_name, M.name)
if(M.mind) indexing += M.mind.name
if(M.mind)
indexing += M.mind.name
for(var/string in indexing)
var/list/L = splittext(string, " ")
@@ -77,55 +646,17 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
mobs_found += found
if(!ai_found && isAI(found))
ai_found = 1
msg += "<b><font color='black'>[original_word] (<A HREF='?_src_=holder;adminmoreinfo=\ref[found]'>?</A>)</font></b> "
var/is_antag = 0
if(found.mind && found.mind.special_role)
is_antag = 1
founds += "Name: [found.name]([found.real_name]) Ckey: [found.ckey] [is_antag ? "(Antag)" : null] "
msg += "[original_word]<font size='1' color='[is_antag ? "red" : "black"]'>(<A HREF='?_src_=holder;adminmoreinfo=\ref[found]'>?</A>|<A HREF='?_src_=holder;adminplayerobservefollow=\ref[found]'>F</A>)</font> "
continue
msg += "[original_word] "
if(!mob) //this doesn't happen
return
var/ai_cl
if(ai_found)
ai_cl = " (<A HREF='?_src_=holder;adminchecklaws=\ref[mob]'>CL</A>)"
//Options bar: mob, details ( admin = 2, dev = 3, event manager = 4, character name (0 = just ckey, 1 = ckey and character name), link? (0 no don't make it a link, 1 do so),
// highlight special roles (0 = everyone has same looking name, 1 = antags / special roles get a golden name)
msg = "<b><font color=red>Request for Help: </font></b><font color='blue'><b>[get_options_bar(mob, 2, 1, 1)][ai_cl]</b> [msg]</font>"
var/admin_number_afk = 0
for(var/client/X in admins)
if((R_ADMIN|R_MOD|R_EVENT|R_SERVER) & X.holder.rights)
if(X.is_afk())
admin_number_afk++
X << msg
if(X.is_preference_enabled(/datum/client_preference/holder/play_adminhelp_ping))
X << 'sound/effects/adminhelp.ogg'
//show it to the person adminhelping too
src << "<font color='blue'>PM to-<b>Staff </b>: [original_msg]</font>"
var/admin_number_present = admins.len - admin_number_afk
log_admin("HELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins.")
if(admin_number_present <= 0)
send2adminirc("Request for Help from [key_name(src)]: [html_decode(original_msg)] - !![admin_number_afk ? "All admins AFK ([admin_number_afk])" : "No admins online"]!!")
else
send2adminirc("Request for Help from [key_name(src)]: [html_decode(original_msg)]")
feedback_add_details("admin_verb","AH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
// VoreStation Edit Start
if (config.chat_webhook_url)
spawn(0)
var/query_string = "type=adminhelp"
query_string += "&key=[url_encode(config.chat_webhook_key)]"
query_string += "&from=[url_encode(key_name(src))]"
query_string += "&msg=[url_encode(html_decode(original_msg))]"
query_string += "&admin_number=[admins.len]"
query_string += "&admin_number_afk=[admin_number_afk]"
world.Export("[config.chat_webhook_url]?[query_string]")
// VoreStation Edit End
//YW EDIT START
SERVER_TOOLS_RELAY_BROADCAST("ADMINHELP: FROM: [key_name(src)] - MSG: **[strip_html_properly(original_msg)]** - Heard by [admins.len-admin_number_afk] NON-AFK staff members.")
//YW EDIT END
return
msg += "[original_word] "
if(irc)
if(founds == "")
return "Search Failed"
else
return founds
return msg
+16
View File
@@ -0,0 +1,16 @@
/datum/admin_help/proc/send2adminchat()
if(!config.chat_webhook_url)
return
var/list/adm = get_admin_counts()
var/list/afkmins = adm["afk"]
var/list/allmins = adm["total"]
spawn(0) //Unreliable world.Exports()
var/query_string = "type=adminhelp"
query_string += "&key=[url_encode(config.chat_webhook_key)]"
query_string += "&from=[url_encode(key_name(initiator))]"
query_string += "&msg=[url_encode(html_decode(name))]"
query_string += "&admin_number=[allmins.len]"
query_string += "&admin_number_afk=[afkmins.len]"
world.Export("[config.chat_webhook_url]?[query_string]")
+12 -6
View File
@@ -109,8 +109,10 @@
if(!check_rights(R_ADMIN|R_MOD|R_DEBUG))
return
if(config.allow_admin_jump)
log_admin("[key_name(usr)] teleported [key_name(M)]")
message_admins("[key_name_admin(usr)] teleported [key_name_admin(M)]", 1)
log_admin("[key_name(usr)] jumped to [key_name(M)]")
var/msg = "[key_name_admin(usr)] jumped to [key_name_admin(M)]"
message_admins(msg)
admin_ticket_log(M, msg)
M.on_mob_jump()
M.loc = get_turf(usr)
feedback_add_details("admin_verb","GM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -137,7 +139,9 @@
if(!M)
return
log_admin("[key_name(usr)] teleported [key_name(M)]")
message_admins("[key_name_admin(usr)] teleported [key_name(M)]", 1)
var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)]"
message_admins(msg)
admin_ticket_log(M, msg)
if(M)
M.on_mob_jump()
M.loc = get_turf(usr)
@@ -157,7 +161,9 @@
M.loc = pick(get_area_turfs(A))
feedback_add_details("admin_verb","SMOB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
log_admin("[key_name(usr)] teleported [key_name(M)] to [A]")
message_admins("[key_name_admin(usr)] teleported [key_name_admin(M)] to [A]", 1)
log_admin("[key_name(usr)] teleported [key_name(M)]")
var/msg = "[key_name_admin(usr)] teleported [ADMIN_LOOKUPFLW(M)]"
message_admins(msg)
admin_ticket_log(M, msg)
else
alert("Admin jumping disabled")
alert("Admin jumping disabled")
+229 -91
View File
@@ -1,148 +1,286 @@
#define IRCREPLYCOUNT 2
//allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm
/client/proc/cmd_admin_pm_context(mob/M as mob in mob_list)
/client/proc/cmd_admin_pm_context(mob/M in mob_list)
set category = null
set name = "Admin PM Mob"
if(!holder)
src << "<font color='red'>Error: Admin-PM-Context: Only administrators may use this command.</font>"
to_chat(src, "<font color='red'>Error: Admin-PM-Context: Only administrators may use this command.</font>")
return
if( !ismob(M) || !M.client )
return
if( !ismob(M) || !M.client ) return
cmd_admin_pm(M.client,null)
feedback_add_details("admin_verb","APMM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
feedback_add_details("admin_verb","Admin PM Mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
//shows a list of clients we could send PMs to, then forwards our choice to cmd_admin_pm
/client/proc/cmd_admin_pm_panel()
set category = "Admin"
set name = "Admin PM"
if(!holder)
src << "<font color='red'>Error: Admin-PM-Panel: Only administrators may use this command.</font>"
to_chat(src, "<font color='red'>Error: Admin-PM-Panel: Only administrators may use this command.</font>")
return
var/list/client/targets[0]
for(var/client/T)
if(T.mob)
if(istype(T.mob, /mob/new_player))
if(isnewplayer(T.mob))
targets["(New Player) - [T]"] = T
else if(istype(T.mob, /mob/observer/dead))
else if(isobserver(T.mob))
targets["[T.mob.name](Ghost) - [T]"] = T
else
targets["[T.mob.real_name](as [T.mob.name]) - [T]"] = T
else
targets["(No Mob) - [T]"] = T
var/list/sorted = sortList(targets)
var/target = input(src,"To whom shall we send a message?","Admin PM",null) in sorted|null
var/target = input(src,"To whom shall we send a message?","Admin PM",null) as null|anything in sortList(targets)
cmd_admin_pm(targets[target],null)
feedback_add_details("admin_verb","APM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
feedback_add_details("admin_verb","Admin PM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_ahelp_reply(whom)
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<font color='red'>Error: Admin-PM: You are unable to use admin PM-s (muted).</font>")
return
var/client/C
if(istext(whom))
if(cmptext(copytext(whom,1,2),"@"))
whom = findStealthKey(whom)
C = GLOB.directory[whom]
else if(istype(whom,/client))
C = whom
if(!C)
if(holder)
to_chat(src, "<font color='red'>Error: Admin-PM: Client not found.</font>")
return
var/datum/admin_help/AH = C.current_ticket
if(AH)
message_admins("[key_name_admin(src)] has started replying to [key_name(C, 0, 0)]'s admin help.")
var/msg = input(src,"Message:", "Private message to [key_name(C, 0, 0)]") as text|null
if (!msg)
message_admins("[key_name_admin(src)] has cancelled their reply to [key_name(C, 0, 0)]'s admin help.")
return
cmd_admin_pm(whom, msg, AH)
//takes input from cmd_admin_pm_context, cmd_admin_pm_panel or /client/Topic and sends them a PM.
//Fetching a message if needed. src is the sender and C is the target client
/client/proc/cmd_admin_pm(var/client/C, var/msg = null)
/client/proc/cmd_admin_pm(whom, msg, datum/admin_help/AH)
if(prefs.muted & MUTE_ADMINHELP)
src << "<font color='red'>Error: Private-Message: You are unable to use PM-s (muted).</font>"
to_chat(src, "<font color='red'>Error: Admin-PM: You are unable to use admin PM-s (muted).</font>")
return
if(!istype(C,/client))
if(holder) src << "<font color='red'>Error: Private-Message: Client not found.</font>"
else src << "<font color='red'>Error: Private-Message: Client not found. They may have lost connection, so try using an adminhelp!</font>"
if(!holder && !current_ticket) //no ticket? https://www.youtube.com/watch?v=iHSPf6x1Fdo
to_chat(src, "<font color='red'>You can no longer reply to this ticket, please open another one by using the Adminhelp verb if need be.</font>")
to_chat(src, "<font color='blue'>Message: [msg]</font>")
return
//get message text, limit it's length.and clean/escape html
if(!msg)
msg = input(src,"Message:", "Private message to [key_name(C, 0, holder ? 1 : 0)]") as text|null
var/client/recipient
var/irc = 0
if(istext(whom))
if(cmptext(copytext(whom,1,2),"@"))
whom = findStealthKey(whom)
if(whom == "IRCKEY")
irc = 1
else
recipient = GLOB.directory[whom]
else if(istype(whom,/client))
recipient = whom
if(!msg) return
if(!C)
if(holder) src << "<font color='red'>Error: Admin-PM: Client not found.</font>"
else src << "<font color='red'>Error: Private-Message: Client not found. They may have lost connection, so try using an adminhelp!</font>"
if(irc)
if(!ircreplyamount) //to prevent people from spamming irc
return
if(!msg)
msg = input(src,"Message:", "Private message to Administrator") as text|null
if(!msg)
return
if(holder)
to_chat(src, "<font color='red'>Error: Use the admin IRC channel, nerd.</font>")
return
else
if(!recipient)
if(holder)
to_chat(src, "<font color='red'>Error: Admin-PM: Client not found.</font>")
to_chat(src, msg)
else
current_ticket.MessageNoRecipient(msg)
return
//get message text, limit it's length.and clean/escape html
if(!msg)
msg = input(src,"Message:", "Private message to [key_name(recipient, 0, 0)]") as text|null
if(!msg)
return
if(prefs.muted & MUTE_ADMINHELP)
to_chat(src, "<font color='red'>Error: Admin-PM: You are unable to use admin PM-s (muted).</font>")
return
if(!recipient)
if(holder)
to_chat(src, "<font color='red'>Error: Admin-PM: Client not found.</font>")
else
current_ticket.MessageNoRecipient(msg)
return
if (src.handle_spam_prevention(msg,MUTE_ADMINHELP))
return
//clean the message if it's not sent by a high-rank admin
//todo: sanitize for all???
if(!check_rights(R_SERVER|R_DEBUG,0))
msg = sanitize(msg)
if(!msg) return
if(!check_rights(R_SERVER|R_DEBUG,0)||irc)//no sending html to the poor bots
msg = trim(sanitize(copytext(msg,1,MAX_MESSAGE_LEN)))
if(!msg)
return
var/recieve_pm_type = "Player"
if(holder)
//mod PMs are maroon
//PMs sent from admins and mods display their rank
if(holder)
if(!C.holder && holder && holder.fakekey)
recieve_pm_type = "Admin"
else
recieve_pm_type = holder.rank
var/rawmsg = msg
else if(!C.holder)
src << "<font color='red'>Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.</font>"
return
var/keywordparsedmsg = keywords_lookup(msg)
var/recieve_message
if(irc)
to_chat(src, "<font color='blue'>PM to-<b>Admins</b>: [rawmsg]</font>")
admin_ticket_log(src, "<font color='red'>Reply PM from-<b>[key_name(src, TRUE, TRUE)]</b> to <i>IRC</i>: [keywordparsedmsg]</font>")
ircreplyamount--
send2irc("Reply: [ckey]",rawmsg)
else
if(recipient.holder)
if(holder) //both are admins
to_chat(recipient, "<font color='red'>Admin PM from-<b>[key_name(src, recipient, 1)]</b>: [keywordparsedmsg]</font>")
to_chat(src, "<font color='blue'>Admin PM to-<b>[key_name(recipient, src, 1)]</b>: [keywordparsedmsg]</font>")
if(holder && !C.holder)
recieve_message = "<span class='pm'><span class='howto'><b>-- Click the [recieve_pm_type]'s name to reply --</b></span></span>\n"
if(C.adminhelped)
C << recieve_message
C.adminhelped = 0
//omg this is dumb, just fill in both their tickets
var/interaction_message = "<font color='purple'>PM from-<b>[key_name(src, recipient, 1)]</b> to-<b>[key_name(recipient, src, 1)]</b>: [keywordparsedmsg]</font>"
admin_ticket_log(src, interaction_message)
if(recipient != src) //reeee
admin_ticket_log(recipient, interaction_message)
//AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn
if(config.popup_admin_pm)
spawn(0) //so we don't hold the caller proc up
var/sender = src
var/sendername = key
var/reply = sanitize(input(C, msg,"[recieve_pm_type] PM from [sendername]", "") as text|null) //show message and await a reply
if(C && reply)
if(sender)
C.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them
else
adminhelp(reply) //sender has left, adminhelp instead
else //recipient is an admin but sender is not
var/replymsg = "<font color='red'>Reply PM from-<b>[key_name(src, recipient, 1)]</b>: [keywordparsedmsg]</font>"
admin_ticket_log(src, replymsg)
to_chat(recipient, replymsg)
to_chat(src, "<font color='blue'>PM to-<b>Admins</b>: [msg]</font>")
//play the recieving admin the adminhelp sound (if they have them enabled)
if(recipient.is_preference_enabled(/datum/client_preference/holder/play_adminhelp_ping))
recipient << 'sound/effects/adminhelp.ogg'
else
if(holder) //sender is an admin but recipient is not. Do BIG RED TEXT
if(!recipient.current_ticket)
new /datum/admin_help(msg, recipient, TRUE)
to_chat(recipient, "<font color='red' size='4'><b>-- Administrator private message --</b></font>")
to_chat(recipient, "<font color='red'>Admin PM from-<b>[key_name(src, recipient, 0)]</b>: [msg]</font>")
to_chat(recipient, "<font color='red'><i>Click on the administrator's name to reply.</i></font>")
to_chat(src, "<font color='blue'>Admin PM to-<b>[key_name(recipient, src, 1)]</b>: [msg]</font>")
admin_ticket_log(recipient, "<font color='blue'>PM From [key_name_admin(src)]: [keywordparsedmsg]</font>")
//always play non-admin recipients the adminhelp sound
recipient << 'sound/effects/adminhelp.ogg'
//AdminPM popup for ApocStation and anybody else who wants to use it. Set it with POPUP_ADMIN_PM in config.txt ~Carn
if(config.popup_admin_pm)
spawn() //so we don't hold the caller proc up
var/sender = src
var/sendername = key
var/reply = input(recipient, msg,"Admin PM from-[sendername]", "") as text|null //show message and await a reply
if(recipient && reply)
if(sender)
recipient.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them
else
adminhelp(reply) //sender has left, adminhelp instead
return
else //neither are admins
to_chat(src, "<font color='red'>Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.</font>")
return
src << "<span class='pm'><span class='out'>" + create_text_tag("pm_out_alt", "PM", src) + " to <span class='name'>[get_options_bar(C, holder ? 1 : 0, holder ? 1 : 0, 1)]</span>: <span class='message'>[msg]</span></span></span>"
C << "<span class='pm'><span class='in'>" + create_text_tag("pm_in", "", C) + " <b>\[[recieve_pm_type] PM\]</b> <span class='name'>[get_options_bar(src, C.holder ? 1 : 0, C.holder ? 1 : 0, 1)]</span>: <span class='message'>[msg]</span></span></span>"
//play the recieving admin the adminhelp sound (if they have them enabled)
//non-admins shouldn't be able to disable this
if(C.is_preference_enabled(/datum/client_preference/holder/play_adminhelp_ping))
C << 'sound/effects/adminhelp.ogg'
if(irc)
log_admin("PM: [key_name(src)]->IRC: [rawmsg]")
for(var/client/X in admins)
to_chat(X, "<font color='blue'><B>PM: [key_name(src, X, 0)]-&gt;IRC:</B> [keywordparsedmsg]</font>")
else
log_admin("PM: [key_name(src)]->[key_name(recipient)]: [rawmsg]")
//we don't use message_admins here because the sender/receiver might get it too
for(var/client/X in admins)
if(X.key!=key && X.key!=recipient.key) //check client/X is an admin and isn't the sender or recipient
to_chat(X, "<font color='blue'><B>PM: [key_name(src, X, 0)]-&gt;[key_name(recipient, X, 0)]:</B> [keywordparsedmsg]</font>" )
log_adminpm(msg,src,C)
send2adminirc("Reply: [key_name(src)]->[key_name(C)]: [html_decode(msg)]")
/proc/IrcPm(target,msg,sender)
var/client/C = GLOB.directory[target]
//we don't use message_admins here because the sender/receiver might get it too
for(var/client/X in admins)
//check client/X is an admin and isn't the sender or recipient
if(X == C || X == src)
continue
if(X.key != key && X.key != C.key && (X.holder.rights & R_ADMIN|R_MOD|R_EVENT))
X << "<span class='pm'><span class='other'>" + create_text_tag("pm_other", "PM:", X) + " <span class='name'>[key_name(src, X, 0)]</span> to <span class='name'>[key_name(C, X, 0)]</span>: <span class='message'>[msg]</span></span></span>"
var/datum/admin_help/ticket = C ? C.current_ticket : GLOB.ahelp_tickets.CKey2ActiveTicket(target)
var/compliant_msg = trim(lowertext(msg))
var/irc_tagged = "[sender](IRC)"
var/list/splits = splittext(compliant_msg, " ")
if(splits.len && splits[1] == "ticket")
if(splits.len < 2)
return "Usage: ticket <close|resolve|icissue|reject>"
switch(splits[2])
if("close")
if(ticket)
ticket.Close(irc_tagged)
return "Ticket #[ticket.id] successfully closed"
if("resolve")
if(ticket)
ticket.Resolve(irc_tagged)
return "Ticket #[ticket.id] successfully resolved"
if("icissue")
if(ticket)
ticket.ICIssue(irc_tagged)
return "Ticket #[ticket.id] successfully marked as IC issue"
if("reject")
if(ticket)
ticket.Reject(irc_tagged)
return "Ticket #[ticket.id] successfully rejected"
else
return "Usage: ticket <close|resolve|icissue|reject>"
return "Error: Ticket could not be found"
/client/proc/cmd_admin_irc_pm(sender)
if(prefs.muted & MUTE_ADMINHELP)
src << "<font color='red'>Error: Private-Message: You are unable to use PM-s (muted).</font>"
return
var/static/stealthkey
var/adminname = "Administrator"
var/msg = input(src,"Message:", "Reply private message to [sender] on IRC / 400 character limit") as text|null
if(!C)
return "Error: No client"
if(!stealthkey)
stealthkey = GenIrcStealthKey()
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
if(!msg)
return
return "Error: No message"
sanitize(msg)
message_admins("IRC message from [sender] to [key_name_admin(C)] : [msg]")
log_admin("IRC PM: [sender] -> [key_name(C)] : [msg]")
// Handled on Bot32's end, unsure about other bots
// if(length(msg) > 400) // TODO: if message length is over 400, divide it up into seperate messages, the message length restriction is based on IRC limitations. Probably easier to do this on the bots ends.
// src << "<span class='warning'>Your message was not sent because it was more then 400 characters find your message below for ease of copy/pasting</span>"
// src << "<span class='notice'>[msg]</span>"
// return
to_chat(C, "<font color='red' size='4'><b>-- Administrator private message --</b></font>")
to_chat(C, "<font color='red'>Admin PM from-<b><a href='?priv_msg=[stealthkey]'>[adminname]</A></b>: [msg]</font>")
to_chat(C, "<font color='red'><i>Click on the administrator's name to reply.</i></font>")
send2adminirc("PlayerPM to [sender] from [key_name(src)]: [html_decode(msg)]")
admin_ticket_log(C, "<font color='blue'>PM From [irc_tagged]: [msg]</font>")
src << "<span class='pm'><span class='out'>" + create_text_tag("pm_out_alt", "", src) + " to <span class='name'>IRC-[sender]</span>: <span class='message'>[msg]</span></span></span>"
window_flash(C, ignorepref = TRUE)
//always play non-admin recipients the adminhelp sound
C << 'sound/effects/adminhelp.ogg'
log_admin("PM: [key_name(src)]->IRC-[sender]: [msg]")
for(var/client/X in admins)
if(X == src)
continue
if(X.holder.rights & R_ADMIN|R_MOD)
X << "<span class='pm'><span class='other'>" + create_text_tag("pm_other", "PM:", X) + " <span class='name'>[key_name(src, X, 0)]</span> to <span class='name'>IRC-[sender]</span>: <span class='message'>[msg]</span></span></span>"
C.ircreplyamount = IRCREPLYCOUNT
return "Message Successful"
/proc/GenIrcStealthKey()
var/num = (rand(0,1000))
var/i = 0
while(i == 0)
i = 1
for(var/P in GLOB.stealthminID)
if(num == GLOB.stealthminID[P])
num++
i = 0
var/stealth = "@[num2text(num)]"
GLOB.stealthminID["IRCKEY"] = stealth
return stealth
#undef IRCREPLYCOUNT
+13 -5
View File
@@ -96,7 +96,9 @@
M << "<B>You hear a voice in your head...</B> <i>[msg]</i>"
log_admin("SubtlePM: [key_name(usr)] -> [key_name(M)] : [msg]")
message_admins("<font color='blue'><B>SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] : [msg]</B></font>", 1)
msg = "<span class='adminnotice'><b> SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] :</b> [msg]</span>"
message_admins(msg)
admin_ticket_log(M, msg)
feedback_add_details("admin_verb","SMS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_admin_world_narrate() // Allows administrators to fluff events a little easier -- TLE
@@ -135,9 +137,11 @@
if( !msg )
return
M << msg
to_chat(M, msg)
log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]")
message_admins("<font color='blue'><B> DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]<BR></B></font>", 1)
msg = "<span class='adminnotice'><b> DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]):</b> [msg]<BR></span>"
message_admins(msg)
admin_ticket_log(M, msg)
feedback_add_details("admin_verb","DIRN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_admin_godmode(mob/M as mob in mob_list)
@@ -150,7 +154,9 @@
usr << "<font color='blue'> Toggled [(M.status_flags & GODMODE) ? "ON" : "OFF"]</font>"
log_admin("[key_name(usr)] has toggled [key_name(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]")
message_admins("[key_name_admin(usr)] has toggled [key_name_admin(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]", 1)
var/msg = "[key_name_admin(usr)] has toggled [ADMIN_LOOKUPFLW(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]"
message_admins(msg)
admin_ticket_log(M, msg)
feedback_add_details("admin_verb","GOD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -550,7 +556,9 @@ Traitors and the like can also be revived with the previous role mostly intact.
M.revive()
log_admin("[key_name(usr)] healed / revived [key_name(M)]")
message_admins("<font color='red'>Admin [key_name_admin(usr)] healed / revived [key_name_admin(M)]!</font>", 1)
var/msg = "<span class='danger'>Admin [key_name_admin(usr)] healed / revived [ADMIN_LOOKUPFLW(M)]!</span>"
message_admins(msg)
admin_ticket_log(M, msg)
else
alert("Admin revive disabled")
feedback_add_details("admin_verb","REJU") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+4 -4
View File
@@ -39,17 +39,17 @@
wait = world.time + config.gateway_delay //+ thirty minutes default
awaygate = locate(/obj/machinery/gateway/centeraway)
. = ..()
density = 1 //VOREStation Add
/obj/machinery/gateway/centerstation/update_icon()
if(active)
icon_state = "oncenter"
return
icon_state = "offcenter"
/* VOREStation Removal - Doesn't do anything
/obj/machinery/gateway/centerstation/New()
density = 1
*/ //VOREStation Removal End
obj/machinery/gateway/centerstation/process()
if(stat & (NOPOWER))
@@ -90,7 +90,7 @@ obj/machinery/gateway/centerstation/process()
if(world.time < wait)
user << "<span class='notice'>Error: Warpspace triangulation in progress. Estimated time to completion: [round(((wait - world.time) / 10) / 60)] minutes.</span>"
return
if(!awaygate.calibrated && LAZYLEN(awaydestinations))
if(!awaygate.calibrated && !LAZYLEN(awaydestinations)) //VOREStation Edit
user << "<span class='notice'>Error: Destination gate uncalibrated. Gateway unsafe to use without far-end calibration update.</span>"
return
+1
View File
@@ -12,6 +12,7 @@
var/last_message = "" //Contains the last message sent by this client - used to protect against copy-paste spamming.
var/last_message_count = 0 //contins a number of how many times a message identical to last_message was sent.
var/ircreplyamount = 0
/////////
//OTHER//
+4 -1
View File
@@ -57,7 +57,7 @@
if(mute_irc)
usr << "<span class='warning'You cannot use this as your client has been muted from sending messages to the admins on IRC</span>"
return
cmd_admin_irc_pm(href_list["irc_msg"])
send2adminirc(href_list["irc_msg"])
return
@@ -112,6 +112,8 @@
clients += src
directory[ckey] = src
GLOB.ahelp_tickets.ClientLogin(src)
//Admin Authorisation
holder = admin_datums[ckey]
if(holder)
@@ -179,6 +181,7 @@
if(holder)
holder.owner = null
admins -= src
GLOB.ahelp_tickets.ClientLogout(src)
directory -= ckey
clients -= src
return ..()
@@ -353,25 +353,17 @@
sols[initial(sol.name)] = sol
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(sols))*/ // Vorestation removal.
/datum/gear/head/surgical/black
display_name = "surgical cap, black"
path = /obj/item/clothing/head/surgery/black
/datum/gear/head/surgical
display_name = "surgical cap selection"
path = /obj/item/clothing/head/surgery
/datum/gear/head/surgical/blue
display_name = "surgical cap, blue"
path = /obj/item/clothing/head/surgery/blue
/datum/gear/head/surgical/green
display_name = "surgical cap, green"
path = /obj/item/clothing/head/surgery/green
/datum/gear/head/surgical/navyblue
display_name = "surgical cap, navy blue"
path = /obj/item/clothing/head/surgery/navyblue
/datum/gear/head/surgical/purple
display_name = "surgical cap, purple"
path = /obj/item/clothing/head/surgery/purple
/datum/gear/head/surgical/New()
..()
var/list/caps = list()
for(var/surgery in typesof(/obj/item/clothing/head/surgery))
var/obj/item/clothing/head/surgery/cap_type = caps
caps[initial(cap_type.name)] = cap_type
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(caps))
/datum/gear/head/circuitry
display_name = "headwear, circuitry (empty)"
@@ -4,6 +4,7 @@ var/AKULA_EGG = "Akula"
var/SKRELL_EGG = "Skrell"
var/SERGAL_EGG = "Sergal"
var/HUMAN_EGG = "Human"
var/NEVREAN_EGG = "nevrean"
var/SLIME_EGG = "Slime"
var/EGG_EGG = "Egg"
var/XENOCHIMERA_EGG = "Xenochimera"
@@ -87,6 +87,10 @@
var/S = pref.custom_base ? pref.custom_base : "Human"
var/datum/species/custom/new_CS = CS.produceCopy(S, pref.pos_traits + pref.neu_traits + pref.neg_traits, character)
//Statistics for this would be nice
var/english_traits = english_list(new_CS.traits, and_text = ";", comma_text = ";")
log_game("TRAITS [pref.client_ckey]/([character]) with: [english_traits]") //Terrible 'fake' key_name()... but they aren't in the same entity yet
//Any additional non-trait settings can be applied here
new_CS.blood_color = pref.blood_color
@@ -179,7 +179,7 @@
qdel(H)
spawn(50)
new /obj/item/honey_frame(loc)
new /obj/item/stack/wax(loc)
new /obj/item/stack/material/wax(loc)
honey += processing
processing = 0
icon_state = "centrifuge"
@@ -234,14 +234,14 @@
qdel(src)
return
/obj/item/stack/wax
/obj/item/stack/material/wax
name = "wax"
singular_name = "wax piece"
desc = "Soft substance produced by bees. Used to make candles."
icon = 'icons/obj/beekeeping.dmi'
icon_state = "wax"
/obj/item/stack/wax/New()
/obj/item/stack/material/wax/New()
..()
recipes = wax_recipes
+1 -1
View File
@@ -157,7 +157,7 @@ var/global/use_preloader = FALSE
++turfsSkipped
#endif
CHECK_TICK
maxx = max(maxx, ++xcrd)
maxx = max(maxx, xcrd++)
key_list[++key_list.len] = line_keys
// Rotate the list according to orientation
-5
View File
@@ -30,11 +30,6 @@
var/excavation_amount = 200
/obj/item/weapon/pickaxe/hammer
name = "sledgehammer"
//icon_state = "sledgehammer" Waiting on sprite
desc = "A mining hammer made of reinforced metal. You feel like smashing your boss in the face with this."
/obj/item/weapon/pickaxe/silver
name = "silver pickaxe"
icon_state = "spickaxe"
@@ -729,7 +729,7 @@
src << "blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag, \
frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, handshake, hug-(none)/mob, laugh, look-(none)/mob, moan, mumble, nod, pale, point-atom, \
raise, salute, scream, sneeze, shake, shiver, shrug, sigh, signal-#1-10, slap-(none)/mob, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, sway/wag, swish, tremble, twitch, \
twitch_v, vomit, whimper, wink, yawn. Synthetics: beep, buzz, yes, no, rcough, rsneeze, ping"
twitch_v, vomit, whimper, wink, yawn. Synthetics: beep, buzz, yess, no, rcough, rsneeze, ping"
else
src << "<font color='blue'>Unusable emote '[act]'. Say *help for a list.</font>"
@@ -33,6 +33,7 @@
/mob/living/proc/flying_toggle,
/mob/living/proc/start_wings_hovering) //Xenochimera get all the special verbs since they can't select traits.
virus_immune = 1 // They practically ARE one.
min_age = 18
max_age = 80
@@ -51,6 +52,16 @@
flags = NO_SCAN | NO_INFECT //Dying as a chimera is, quite literally, a death sentence. Well, if it wasn't for their revive, that is.
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_EYE_COLOR
has_organ = list( //Same organ list as tajarans.
O_HEART = /obj/item/organ/internal/heart,
O_LUNGS = /obj/item/organ/internal/lungs,
O_VOICE = /obj/item/organ/internal/voicebox,
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain,
O_EYES = /obj/item/organ/internal/eyes
)
flesh_color = "#AFA59E"
base_color = "#333333"
blood_color = "#14AD8B"
@@ -122,8 +122,8 @@
/datum/trait/winged_flight
name = "Winged Flight"
desc = "Allows you to fly by using your wings."
cost = 2 //Some in game value.
desc = "Allows you to fly by using your wings. Don't forget to bring them!"
cost = 1
/datum/trait/winged_flight/apply(var/datum/species/S,var/mob/living/carbon/human/H)
..(S,H)
@@ -1,43 +0,0 @@
//kobold
/mob/living/simple_animal/kobold
name = "kobold"
desc = "A small, rat-like creature."
icon = 'icons/mob/mob.dmi'
icon_state = "kobold_idle"
icon_living = "kobold_idle"
icon_dead = "kobold_dead"
intelligence_level = SA_HUMANOID
run_at_them = 0
cooperative = 1
turns_per_move = 5
see_in_dark = 6
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "kicks"
min_oxy = 16 //Require atleast 16kPA oxygen
minbodytemp = 223 //Below -50 Degrees Celcius
maxbodytemp = 323 //Above 50 Degrees Celcius
speak_chance = 5
speak = list("You no take candle!","Ooh, pretty shiny.","Me take?","Where gold here...","Me likey.")
speak_emote = list("mutters","hisses","grumbles")
emote_hear = list("mutters under it's breath.","grumbles.", "yips!")
emote_see = list("looks around suspiciously.", "scratches it's arm.","putters around a bit.")
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/monkey
/mob/living/simple_animal/kobold/Life()
. = ..()
if(!.) return
if(prob(5))
flick("kobold_act",src)
/mob/living/simple_animal/kobold/Move(var/dir)
..()
if(!stat)
flick("kobold_walk",src)
@@ -393,7 +393,7 @@
//Resisting out of closets
if(istype(loc,/obj/structure/closet))
var/obj/structure/closet/C = loc
if(C.welded)
if(C.sealed)
handle_resist()
else
C.open()
@@ -12,6 +12,10 @@
var/vore_bump_chance = 0 // Chance of trying to eat anyone that bumps into them, regardless of hostility
var/vore_bump_emote = "grabs hold of" // Allow messages for bumpnom mobs to have a flavorful bumpnom
var/vore_pounce_chance = 5 // Chance of this mob knocking down an opponent
var/vore_pounce_cooldown = 0 // Cooldown timer - if it fails a pounce it won't pounce again for a while
var/vore_pounce_successrate = 100 // Chance of a pounce succeeding against a theoretical 0-health opponent
var/vore_pounce_falloff = 1 // Success rate falloff per %health of target mob.
var/vore_pounce_maxhealth = 80 // Mob will not attempt to pounce targets above this %health
var/vore_standing_too = 0 // Can also eat non-stunned mobs
var/vore_ignores_undigestable = 1 // Refuse to eat mobs who are undigestable by the prefs toggle.
var/swallowsound = null // What noise plays when you succeed in eating the mob.
@@ -92,21 +96,49 @@
/mob/living/simple_animal/PunchTarget()
ai_log("vr/PunchTarget() [target_mob]", 3)
// For things we don't want to eat, call the sideways "parent" to do normal punching
if(!vore_active || !will_eat(target_mob))
// If we're not hungry, call the sideways "parent" to do normal punching
if(!vore_active)
return ..()
// If target is standing we might pounce and eat them
if(target_mob.canmove && prob(vore_pounce_chance))
target_mob.Weaken(5)
target_mob.visible_message("<span class='danger'>\the [src] pounces on \the [target_mob]!</span>!")
// If target is standing we might pounce and knock them down instead of attacking
var/pouncechance = CanPounceTarget()
if(pouncechance)
return PounceTarget(pouncechance)
// If they're down or we can eat standing, do it
if(!target_mob.canmove || vore_standing_too)
// We're not attempting a pounce, if they're down or we can eat standing, do it as long as they're edible. Otherwise, hit normally.
if(will_eat(target_mob) && (!target_mob.canmove || vore_standing_too))
return EatTarget()
else
return ..()
/mob/living/simple_animal/proc/CanPounceTarget() //returns either FALSE or a %chance of success
if(!target_mob.canmove || issilicon(target_mob) || world.time < vore_pounce_cooldown) //eliminate situations where pouncing CANNOT happen
return FALSE
if(!prob(vore_pounce_chance)) //mob doesn't want to pounce
return FALSE
if(will_eat(target_mob) && vore_standing_too) //100% chance of hitting people we can eat on the spot
return 100
var/TargetHealthPercent = (target_mob.health/target_mob.getMaxHealth())*100 //now we start looking at the target itself
if (TargetHealthPercent > vore_pounce_maxhealth) //target is too healthy to pounce
return FALSE
else
return max(0,(vore_pounce_successrate - (vore_pounce_falloff * TargetHealthPercent)))
/mob/living/simple_animal/proc/PounceTarget(var/successrate = 100)
vore_pounce_cooldown = world.time + 20 SECONDS // don't attempt another pounce for a while
if(prob(successrate)) // pounce success!
target_mob.Weaken(5)
target_mob.visible_message("<span class='danger'>\the [src] pounces on \the [target_mob]!</span>!")
else // pounce misses!
target_mob.visible_message("<span class='danger'>\the [src] attempts to pounce \the [target_mob] but misses!</span>!")
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
if(will_eat(target_mob) && (!target_mob.canmove || vore_standing_too)) //if they're edible then eat them too
return EatTarget()
else
return //just leave them
// Attempt to eat target
// TODO - Review this. Could be some issues here
/mob/living/simple_animal/proc/EatTarget()
@@ -117,7 +149,7 @@
. = animal_nom(target_mob)
playsound(src, swallowsound, 50, 1)
update_icon()
if(.)
// If we succesfully ate them, lose the target
LoseTarget()
@@ -29,6 +29,7 @@
var/random_skin = 1
var/list/skins = list(
"catgirl",
"catgirlnude",
"catgirlbikini",
"catgirlrednude",
@@ -241,7 +241,7 @@
if(specific_targets && isliving(A)) //Healing!
var/mob/living/L = A
var/health_percent = (L.health/L.maxHealth)*100
if(health_percent <= 50)
if(health_percent <= 50 && will_eat(A))
return A
. = ..()
@@ -17,7 +17,7 @@
eye_desc = "red eyes"
vore_stomach_flavor = "You slip passed pointy triangle teeth and down the slick, \
vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, \
slippery gullet of the creature. It's warm, and the air is thick. You can hear \
its body squelch and shift around you as you settle into its stomach! Thick digestive \
enzymes cling to you within that dark space, tingling and stinging immediately! The weight of \
@@ -64,11 +64,11 @@
eye_desc = "blue eyes"
shy_approach = TRUE
stalker = TRUE
vore_stomach_flavor = "You slip passed pointy triangle teeth and down the slick, \
vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, \
slippery gullet of the creature. It's warm, and the air is thick. You can hear its body \
squelch and shift around you as you settle into its stomach! It's oddly calm, and very dark. \
The doughy flesh rolls across your form in gentle waves. The aches and pains across your form slowly begin to \
diminish, your body is healing much faster than normal! Youre also soon soaked in harmless slime."
diminish, your body is healing much faster than normal! You're also soon soaked in harmless slime."
player_msg = "You've chosen to generate your own energy rather than taking \
it from others. Most of the time, anyway. You don't have a need to steal energy from others, and gather it up \
@@ -106,10 +106,10 @@
eye_desc = "purple eyes"
shy_approach = TRUE
stalker = TRUE
vore_stomach_flavor = "You slip passed pointy triangle teeth and down the slick, slippery gullet of the creature. \
vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, slippery gullet of the creature. \
It's warm, and the air is thick. You can hear its body squelch and shift around you as you settle into its stomach! \
Its relatively calm inside the dark organ. Wet and almost molten for how gooey your surroundings feel. \
You can feel the doughy walls cling to you posessively... Its almost like you could sink into them. \
It's relatively calm inside the dark organ. Wet and almost molten for how gooey your surroundings feel. \
You can feel the doughy walls cling to you posessively... It's almost like you could sink into them. \
There is also an ominous gurgling from somewhere nearby..."
player_msg = "You're familiar with generating your own energy, but occasionally \
@@ -147,10 +147,10 @@
eye_desc = "yellow eyes"
stalker = FALSE
vore_stomach_flavor = "You slip passed pointy triangle teeth and down the slick, slippery gullet \
vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, slippery gullet \
of the creature. It's warm, and the air is thick. You can hear its body squelch and shift around you \
as you settle into its stomach! The doughy walls within cling to you heavily, churning down on you, wearing \
you out!! There doesnt appear to be any actual danger here, harmless slime clings to you, but its getting \
you out!! There doesn't appear to be any actual danger here, harmless slime clings to you, but it's getting \
harder and harder to move as those walls press in on you insistently!"
player_msg = "Your kind rarely ventures into realspace. Being in any well-lit \
@@ -187,10 +187,10 @@
eye_desc = "green eyes"
stalker = TRUE
vore_stomach_flavor = "You slip passed pointy triangle teeth and down the slick, slippery gullet \
vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, slippery gullet \
of the creature. It's warm, and the air is thick. You can hear its body squelch and shift around you \
as you settle into its stomach! The doughy walls within cling to you heavily, churning down on you, wearing \
you out!! There doesnt appear to be any actual danger here, harmless slime clings to you, but its getting \
you out!! There doesn't appear to be any actual danger here, harmless slime clings to you, but it's getting \
harder and harder to move as those walls press in on you insistently!"
player_msg = "Your kind rarely ventures into realspace. Being in any well-lit area is very taxing on you, but you \
@@ -224,7 +224,7 @@
eye_desc = "orange eyes"
vore_stomach_flavor = "You slip passed pointy triangle teeth and down the slick, \
vore_stomach_flavor = "You slip past pointy triangle teeth and down the slick, \
slippery gullet of the creature. It's warm, and the air is thick. You can hear \
its body squelch and shift around you as you settle into its stomach! Thick digestive \
enzymes cling to you within that dark space, tingling and stinging immediately! The weight of \
@@ -248,8 +248,8 @@
desc = "She appears to be a fluffer of some sort. Deep blue eyes and curious attitude."
icon_state = "rivyr"
eye_desc = ""
vore_stomach_flavor = "Blue flesh gleams in the fading light as you slip down the little mars gullet! \
Gooey flesh and heat surrounds your form as youre tucked away into the darkness of her stomach! Thick slimes cling \
vore_stomach_flavor = "Blue flesh gleams in the fading light as you slip down the little mar's gullet! \
Gooey flesh and heat surrounds your form as you're tucked away into the darkness of her stomach! Thick slimes cling \
to you, but they seem to be harmless. The organ gently churns around you, clinging to your shape and forcing \
you to curl up a bit. You can feel her rub at you some through the layers of flesh and fluff, while aches \
and pains begin to fade away across your body."
@@ -162,6 +162,7 @@
vore_pounce_chance = 100
vore_digest_chance = 0 // just use the toggle
vore_default_mode = DM_HOLD //can use the toggle if you wanna be catfood
vore_standing_too = TRUE //gonna get pounced
/mob/living/simple_animal/cat/fluff/EatTarget()
var/mob/living/TM = target_mob
@@ -201,6 +202,7 @@
vore_pounce_chance = 100
vore_digest_chance = 0 // just use the toggle
vore_default_mode = DM_HOLD //can use the toggle if you wanna be foxfood
vore_standing_too = TRUE // gonna get pounced
/mob/living/simple_animal/fox/fluff/EatTarget()
var/mob/living/TM = target_mob
+4 -1
View File
@@ -703,7 +703,10 @@
stat(null)
for(var/datum/controller/subsystem/SS in Master.subsystems)
SS.stat_entry()
if(statpanel("Tickets"))
GLOB.ahelp_tickets.stat_entry()
if(listed_turf && client)
if(!TurfAdjacent(listed_turf))
listed_turf = null
@@ -988,7 +988,7 @@
color_blend_mode = ICON_MULTIPLY
body_parts = list(BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_L_HAND,BP_R_HAND,BP_TORSO)
spirit_panels_head
spirit_lights_head
name = "Ward - Spirit FBP Lights (head)"
icon_state = "lights"
color_blend_mode = ICON_MULTIPLY
+1
View File
@@ -148,6 +148,7 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
can_assist = FALSE
/obj/item/organ/internal/brain/slime
icon = 'icons/obj/surgery_vr.dmi' // Vorestation edit
name = "slime core"
desc = "A complex, organic knot of jelly and crystalline particles."
icon_state = "core"
+1 -1
View File
@@ -255,7 +255,7 @@
if(istype(W, /obj/item/stack/cable_coil) && !terminal && !building_terminal)
building_terminal = 1
var/obj/item/stack/cable_coil/CC = W
if (CC.get_amount() <= 10)
if (CC.get_amount() < 10)
to_chat(user, "<span class='warning'>You need more cables.</span>")
building_terminal = 0
return 0
+4 -4
View File
@@ -31,8 +31,8 @@
/obj/machinery/chem_master/New()
..()
var/datum/reagents/R = new/datum/reagents(120)
reagents = R
var/datum/reagents/R = new/datum/reagents(900) //Just a huge random number so the buffer should (probably) never dump your reagents.
reagents = R //There should be a nano ui thingy to warn of this.
R.my_atom = src
/obj/machinery/chem_master/ex_act(severity)
@@ -55,7 +55,7 @@
src.beaker = B
user.drop_item()
B.loc = src
to_chat(user, "You add \the [B] to the machine!")
to_chat(user, "You add \the [B] to the machine.")
icon_state = "mixer1"
else if(istype(B, /obj/item/weapon/storage/pill_bottle))
@@ -67,7 +67,7 @@
src.loaded_pill_bottle = B
user.drop_item()
B.loc = src
to_chat(user, "You add \the [loaded_pill_bottle] into the dispenser slot!")
to_chat(user, "You add \the [loaded_pill_bottle] into the dispenser slot.")
else if(default_unfasten_wrench(user, B, 20))
return
+2 -2
View File
@@ -284,7 +284,7 @@
if (src.amount > 3 && !O.opened)
var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc))
P.wrapped = O
O.welded = 1
O.sealed = 1
O.loc = P
src.amount -= 3
user.visible_message("\The [user] wraps \a [target] with \a [src].",\
@@ -311,7 +311,7 @@
wrapped.forceMove(get_turf(src))
if(istype(wrapped, /obj/structure/closet))
var/obj/structure/closet/O = wrapped
O.welded = 0
O.sealed = 0
wrapped = null
var/turf/T = get_turf(src)
for(var/atom/movable/AM in contents)
+14 -10
View File
@@ -121,7 +121,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
//Loading a disk into it.
if(istype(D, /obj/item/weapon/disk))
if(t_disk || d_disk)
user << "A disk is already loaded into the machine."
to_chat(user, "A disk is already loaded into the machine.")
return
if(istype(D, /obj/item/weapon/disk/tech_disk))
@@ -129,11 +129,11 @@ won't update every console in existence) but it's more of a hassle to do. Also,
else if (istype(D, /obj/item/weapon/disk/design_disk))
d_disk = D
else
user << "<span class='notice'>Machine cannot accept disks in that format.</span>"
to_chat(user, "<span class='notice'>Machine cannot accept disks in that format.</span>")
return
user.drop_item()
D.loc = src
user << "<span class='notice'>You add \the [D] to the machine.</span>"
to_chat(user, "<span class='notice'>You add \the [D] to the machine.</span>")
else
//The construction/deconstruction of the console code.
..()
@@ -145,7 +145,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
if(!emagged)
playsound(src.loc, 'sound/effects/sparks4.ogg', 75, 1)
emagged = 1
user << "<span class='notice'>You you disable the security protocols.</span>"
to_chat(user, "<span class='notice'>You you disable the security protocols.</span>")
return 1
/obj/machinery/computer/rdconsole/Topic(href, href_list)
@@ -155,12 +155,16 @@ won't update every console in existence) but it's more of a hassle to do. Also,
add_fingerprint(usr)
usr.set_machine(src)
if((screen < 1 || (screen == 1.6 && href_list["menu"] != "1.0")) && (!allowed(usr) && !emagged)) //Stops people from HREF exploiting out of the lock screen, but allow it if they have the access.
to_chat(usr, "Unauthorized Access")
return
if(href_list["menu"]) //Switches menu screens. Converts a sent text string into a number. Saves a LOT of code.
var/temp_screen = text2num(href_list["menu"])
if(temp_screen <= 1.1 || (3 <= temp_screen && 4.9 >= temp_screen) || allowed(usr) || emagged) //Unless you are making something, you need access.
screen = temp_screen
else
usr << "Unauthorized Access."
to_chat(usr, "Unauthorized Access.")
else if(href_list["updt_tech"]) //Update the research holder with information from the technology disk.
screen = 0.0
@@ -211,7 +215,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
else if(href_list["eject_item"]) //Eject the item inside the destructive analyzer.
if(linked_destroy)
if(linked_destroy.busy)
usr << "<span class='notice'>The destructive analyzer is busy at the moment.</span>"
to_chat(usr, "<span class='notice'>The destructive analyzer is busy at the moment.</span>")
else if(linked_destroy.loaded_item)
linked_destroy.loaded_item.loc = linked_destroy.loc
@@ -222,7 +226,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
else if(href_list["deconstruct"]) //Deconstruct the item in the destructive analyzer and update the research holder.
if(linked_destroy)
if(linked_destroy.busy)
usr << "<span class='notice'>The destructive analyzer is busy at the moment.</span>"
to_chat(usr, "<span class='notice'>The destructive analyzer is busy at the moment.</span>")
else
if(alert("Proceeding will destroy loaded item. Continue?", "Destructive analyzer confirmation", "Yes", "No") == "No" || !linked_destroy)
return
@@ -234,7 +238,7 @@ won't update every console in existence) but it's more of a hassle to do. Also,
if(linked_destroy)
linked_destroy.busy = 0
if(!linked_destroy.loaded_item)
usr <<"<span class='notice'>The destructive analyzer appears to be empty.</span>"
to_chat(usr, "<span class='notice'>The destructive analyzer appears to be empty.</span>")
screen = 1.0
return
@@ -270,12 +274,12 @@ won't update every console in existence) but it's more of a hassle to do. Also,
if(allowed(usr))
screen = text2num(href_list["lock"])
else
usr << "Unauthorized Access."
to_chat(usr, "Unauthorized Access.")
else if(href_list["sync"]) //Sync the research holder with all the R&D consoles in the game that aren't sync protected.
screen = 0.0
if(!sync)
usr << "<span class='notice'>You must connect to the network first.</span>"
to_chat(usr, "<span class='notice'>You must connect to the network first.</span>")
else
griefProtection() //Putting this here because I dont trust the sync process
spawn(30)
@@ -1229,3 +1229,259 @@
icon_state = "zenghu_taj"
//Taurs moved to a separate file due to extra code around them
//Buggo Abdomens!
/datum/sprite_accessory/tail/buggo
name = "Bug abdomen, colorable"
desc = ""
icon_state = "buggo_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/tail/buggobee
name = "Bug abdomen, bee top, dual-colorable"
desc = ""
icon_state = "buggo_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggobee_markings"
/datum/sprite_accessory/tail/buggobeefull
name = "Bug abdomen, bee full, dual-colorable"
desc = ""
icon_state = "buggo_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggobeefull_markings"
/datum/sprite_accessory/tail/buggounder
name = "Bug abdomen, underside, dual-colorable"
desc = ""
icon_state = "buggo_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggounder_markings"
/datum/sprite_accessory/tail/buggofirefly
name = "Bug abdomen, firefly, dual-colorable"
desc = ""
icon_state = "buggo_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofirefly_markings"
/datum/sprite_accessory/tail/buggofat
name = "Fat bug abdomen, colorable"
desc = ""
icon_state = "buggofat_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/tail/buggofatbee
name = "Fat bug abdomen, bee top, dual-colorable"
desc = ""
icon_state = "buggofat_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofatbee_markings"
/datum/sprite_accessory/tail/buggofatbeefull
name = "Fat bug abdomen, bee full, dual-colorable"
desc = ""
icon_state = "buggofat_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofatbeefull_markings"
/datum/sprite_accessory/tail/buggofatunder
name = "Fat bug abdomen, underside, dual-colorable"
desc = ""
icon_state = "buggofat_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofatunder_markings"
/datum/sprite_accessory/tail/buggofatfirefly
name = "Fat bug abdomen, firefly, dual-colorable"
desc = ""
icon_state = "buggofat_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofatfirefly_markings"
/datum/sprite_accessory/tail/buggowag
name = "Bug abdomen, colorable, vwag change"
desc = ""
icon_state = "buggo_s"
ani_state = "buggofat_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/tail/buggobeewag
name = "Bug abdomen, bee top, dual color, vwag"
desc = ""
icon_state = "buggo_s"
ani_state = "buggofat_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggobee_markings"
extra_overlay_w = "buggofatbee_markings"
/datum/sprite_accessory/tail/buggobeefullwag
name = "Bug abdomen, bee full, dual color, vwag"
desc = ""
icon_state = "buggo_s"
ani_state = "buggofat_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggobeefull_markings"
extra_overlay_w = "buggofatbeefull_markings"
/datum/sprite_accessory/tail/buggounderwag
name = "Bug abdomen, underside, dual color, vwag"
desc = ""
icon_state = "buggo_s"
ani_state = "buggofat_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggounder_markings"
extra_overlay_w = "buggofatunder_markings"
/datum/sprite_accessory/tail/buggofireflywag
name = "Bug abdomen, firefly, dual color, vwag"
desc = ""
icon_state = "buggo_s"
ani_state = "buggofat_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofirefly_markings"
extra_overlay_w = "buggofatfirefly_markings"
//Vass buggo variants!
/datum/sprite_accessory/tail/buggovass
name = "Bug abdomen, vass, colorable"
desc = ""
icon_state = "buggo_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/tail/buggovassbee
name = "Bug abdomen, bee top, dc, vass"
desc = ""
icon_state = "buggo_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggobee_vass_markings"
/datum/sprite_accessory/tail/buggovassbeefull
name = "Bug abdomen, bee full, dc, vass"
desc = ""
icon_state = "buggo_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggobeefull_vass_markings"
/datum/sprite_accessory/tail/buggovassunder
name = "Bug abdomen, underside, dc, vass"
desc = ""
icon_state = "buggo_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggounder_vass_markings"
/datum/sprite_accessory/tail/buggovassfirefly
name = "Bug abdomen, firefly, dc, vass"
desc = ""
icon_state = "buggo_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofirefly_vass_markings"
/datum/sprite_accessory/tail/buggovassfat
name = "Fat bug abdomen, vass, colorable"
desc = ""
icon_state = "buggofat_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/tail/buggovassfatbee
name = "Fat bug abdomen, bee top, dc, vass"
desc = ""
icon_state = "buggofat_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofatbee_vass_markings"
/datum/sprite_accessory/tail/buggovassfatbeefull
name = "Fat bug abdomen, bee full, dc, vass"
desc = ""
icon_state = "buggofat_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofatbeefull_vass_markings"
/datum/sprite_accessory/tail/buggovassfatunder
name = "Fat bug abdomen, underside, dc, vass"
desc = ""
icon_state = "buggofat_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofatunder_vass_markings"
/datum/sprite_accessory/tail/buggovassfatfirefly
name = "Fat bug abdomen, firefly, dc, vass"
desc = ""
icon_state = "buggofat_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofatfirefly_vass_markings"
/datum/sprite_accessory/tail/buggovasswag
name = "Bug abdomen, vass, colorable, vwag change"
desc = ""
icon_state = "buggo_vass_s"
ani_state = "buggofat_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
/datum/sprite_accessory/tail/buggovassbeewag
name = "Bug abdomen, bee top, dc, vass, vwag"
desc = ""
icon_state = "buggo_vass_s"
ani_state = "buggofat_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggobee_vass_markings"
extra_overlay_w = "buggofatbee_vass_markings"
/datum/sprite_accessory/tail/buggovassbeefullwag
name = "Bug abdomen, bee full, dc, vass, vwag"
desc = ""
icon_state = "buggo_vass_s"
ani_state = "buggofat_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggobeefull_vass_markings"
extra_overlay_w = "buggofatbeefull_vass_markings"
/datum/sprite_accessory/tail/buggovassunderwag
name = "Bug abdomen, underside, dc, vass, vwag"
desc = ""
icon_state = "buggo_vass_s"
ani_state = "buggofat_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggounder_vass_markings"
extra_overlay_w = "buggofatunder_vass_markings"
/datum/sprite_accessory/tail/buggovassfireflywag
name = "Bug abdomen, firefly, dc, vass, vwag"
desc = ""
icon_state = "buggo_vass_s"
ani_state = "buggofat_vass_s"
do_colouration = 1
color_blend_mode = ICON_MULTIPLY
extra_overlay = "buggofirefly_vass_markings"
extra_overlay_w = "buggofatfirefly_vass_markings"
@@ -910,7 +910,7 @@
icon_state = "khi_uniform_cmd_i"
item_state = "khi_uniform_cmd"
worn_state = "khi_uniform_cmd"
armor = list(melee = 5, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 0, rad = 0)
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
/obj/item/clothing/under/rank/khi/sec //Security version
name = "KHI security suit"
@@ -926,7 +926,7 @@
icon_state = "khi_uniform_med_i"
item_state = "khi_uniform_med"
worn_state = "khi_uniform_med"
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 50, rad = 5)
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 10, rad = 0)
/obj/item/clothing/under/rank/khi/eng //Engineering version
name = "KHI engineering suit"
@@ -942,7 +942,7 @@
icon_state = "khi_uniform_sci_i"
item_state = "khi_uniform_sci"
worn_state = "khi_uniform_sci"
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 5, bio = 0, rad = 5)
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 10, bio = 0, rad = 0)
/obj/item/clothing/under/rank/khi/fluff/aronai //Aro fluff version
name = "KHI meditech suit"
@@ -950,7 +950,7 @@
icon_state = "khi_uniform_aro_i"
item_state = "khi_uniform_aro"
worn_state = "khi_uniform_aro"
armor = list(melee = 5, bullet = 5, laser = 5, energy = 0, bomb = 0, bio = 0, rad = 0)
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 10, rad = 0)
//jacobdragon:Earthen Breath
/obj/item/clothing/under/fluff/earthenbreath
@@ -1192,14 +1192,14 @@ Departamental Swimsuits, for general use
desc = "The uniform worn by command officers in the mid 2260s."
icon_state = "trek_command"
item_state = "trek_command"
armor = list(melee = 10, bullet = 10, laser = 10,energy = 0, bomb = 0, bio = 10, rad = 10, fire = 0, acid = 0) // Considering only staff heads get to pick it
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) // Considering only staff heads get to pick it
/obj/item/clothing/under/rank/trek/engsec
name = "Operations Uniform"
desc = "The uniform worn by operations officers of the mid 2260s. You feel strangely vulnerable just seeing this..."
icon_state = "trek_engsec"
item_state = "trek_engsec"
armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 10, fire = 0, acid = 0) // since they're shared between jobs and kinda moot.
armor = list(melee = 10, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) // since they're shared between jobs and kinda moot.
/obj/item/clothing/under/rank/trek/medsci
name = "MedSci Uniform"
@@ -1207,7 +1207,7 @@ Departamental Swimsuits, for general use
icon_state = "trek_medsci"
item_state = "trek_medsci"
permeability_coefficient = 0.50
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0, fire = 0, acid = 0) // basically a copy of vanilla sci/med
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0) // basically a copy of vanilla sci/med
//TNG
/obj/item/clothing/under/rank/trek/command/next
+6 -1
View File
@@ -63,6 +63,8 @@ var/global/datum/global_init/init = new ()
// if(config && config.log_runtime)
// log = file("data/logs/runtime/[time2text(world.realtime,"YYYY-MM-DD-(hh-mm-ss)")]-runtime.log")
GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
callHook("startup")
//Emergency Fix
load_mods()
@@ -171,7 +173,10 @@ var/world_topic_spam_protect_time = world.timeofday
s["players"] = players.len
s["playerlist"] = list2params(players)
s["admins"] = admins.len
var/list/adm = get_admin_counts()
var/list/presentmins = adm["present"]
var/list/afkmins = adm["afk"]
s["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho
s["adminlist"] = list2params(admins)
else
var/n = 0
+36
View File
@@ -0,0 +1,36 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
#################################
# Your name.
author: Anewbe
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- rscadd: "Graves are now a thing in the code, will need some testing and probably more work before they get more common."
Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

+1 -1
View File
@@ -6,7 +6,7 @@
if(config.wikiurl)
if(query)
if(config.wikisearchurl)
var/output = replacetext(config.wikisearchurl, "%s", url_encode(query))
var/output = replacetext(config.wikisearchurl, "%s", url_encode(query))
src << link(output)
else
src << "<span class='warning'> The wiki search URL is not set in the server configuration.</span>"
+2 -2
View File
@@ -1587,7 +1587,7 @@
"EA" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/outpost/mining_main/eva)
"EB" = (/obj/machinery/power/apc{dir = 4; name = "east bump"; pixel_x = 24},/obj/structure/cable/blue{d2 = 8; icon_state = "0-8"},/obj/item/device/radio/intercom{name = "Station Intercom (General)"; pixel_y = -21},/turf/simulated/floor/tiled,/area/outpost/mining_main/eva)
"EC" = (/obj/structure/table/rack,/obj/item/weapon/pickaxe,/obj/item/weapon/tool/wrench,/obj/item/weapon/tool/crowbar,/obj/item/weapon/shovel,/obj/machinery/light,/turf/simulated/floor/tiled/dark,/area/outpost/mining_main/storage)
"ED" = (/obj/structure/table/rack,/obj/item/weapon/pickaxe/hammer,/obj/item/weapon/tool/wrench,/obj/item/weapon/tool/crowbar,/obj/item/weapon/shovel,/turf/simulated/floor/tiled/dark,/area/outpost/mining_main/storage)
"ED" = (/obj/structure/table/rack,/obj/item/weapon/pickaxe,/obj/item/weapon/tool/wrench,/obj/item/weapon/tool/crowbar,/obj/item/weapon/shovel,/turf/simulated/floor/tiled/dark,/area/outpost/mining_main/storage)
"EE" = (/turf/simulated/wall,/area/outpost/mining_main/storage)
"EF" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/obj/machinery/camera/network/mining{c_tag = "OPM - Mining Hallway Aft"; dir = 4},/obj/item/device/radio/intercom{dir = 8; name = "Station Intercom (General)"; pixel_x = -21},/turf/simulated/floor/tiled,/area/outpost/mining_main/south_hall)
"EG" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/turf/simulated/floor/tiled,/area/outpost/mining_main/south_hall)
@@ -1912,7 +1912,7 @@
"KN" = (/obj/structure/lattice,/obj/structure/grille{density = 0; icon_state = "brokengrille"},/turf/space,/area/space)
"KO" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/space)
"KP" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow,/turf/simulated/floor/airless{icon_state = "asteroidplating2"},/area/outpost/engineering/solarsoutside/aft)
(1,1,1) = {"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+2 -3
View File
@@ -98,8 +98,8 @@
"bT" = (/obj/structure/ore_box,/obj/effect/floor_decal/corner/brown{dir = 10},/turf/simulated/floor/tiled,/area/surface/outpost/mining_main/storage)
"bU" = (/obj/structure/reagent_dispensers/watertank,/obj/effect/floor_decal/corner/brown{dir = 10},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/surface/outpost/mining_main/storage)
"bV" = (/obj/structure/reagent_dispensers/fueltank,/obj/effect/floor_decal/corner/brown{dir = 10},/turf/simulated/floor/tiled,/area/surface/outpost/mining_main/storage)
"bW" = (/obj/structure/table/rack,/obj/item/weapon/pickaxe/hammer,/obj/item/weapon/tool/wrench,/obj/item/weapon/tool/crowbar,/obj/item/weapon/shovel,/obj/effect/floor_decal/corner/brown{dir = 10},/turf/simulated/floor/tiled,/area/surface/outpost/mining_main/storage)
"bX" = (/obj/structure/table/rack,/obj/item/weapon/pickaxe/hammer,/obj/item/weapon/tool/wrench,/obj/item/weapon/tool/crowbar,/obj/item/weapon/shovel,/obj/effect/floor_decal/corner/brown{dir = 10},/obj/machinery/firealarm{dir = 1; pixel_x = 0; pixel_y = -24},/turf/simulated/floor/tiled,/area/surface/outpost/mining_main/storage)
"bW" = (/obj/structure/table/rack,/obj/item/weapon/pickaxe,/obj/item/weapon/tool/wrench,/obj/item/weapon/tool/crowbar,/obj/item/weapon/shovel,/obj/effect/floor_decal/corner/brown{dir = 10},/turf/simulated/floor/tiled,/area/surface/outpost/mining_main/storage)
"bX" = (/obj/structure/table/rack,/obj/item/weapon/pickaxe,/obj/item/weapon/tool/wrench,/obj/item/weapon/tool/crowbar,/obj/item/weapon/shovel,/obj/effect/floor_decal/corner/brown{dir = 10},/obj/machinery/firealarm{dir = 1; pixel_x = 0; pixel_y = -24},/turf/simulated/floor/tiled,/area/surface/outpost/mining_main/storage)
"bY" = (/obj/effect/floor_decal/corner/brown{dir = 8},/turf/simulated/floor/tiled,/area/surface/outpost/mining_main)
"bZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/surface/outpost/mining_main)
"ca" = (/obj/effect/floor_decal/industrial/warning/corner,/turf/simulated/floor/tiled,/area/surface/outpost/mining_main)
@@ -1818,4 +1818,3 @@ aaafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafDADADADADA
aaafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafagafafafafafafafafDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDVDMDWDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDJDJDKDKDJDJDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDQDVDMDWDQDQDQDQDQDQDQDQDQDQDQDQDQDQafafafafafafafafafafafafagafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafafaa
aaaaaaaaaaaaaaaaabababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaabababababababababababababababababababababababababababababababababababDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDQDYDYDYDQDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDQDZDZDZDZDZDZDQDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDXDQDYDYDYDQDXDXDXDXDXDXDXDXDXDXDXDXDXababababababababababababababababababababababababababababababababababababaaaaaaaaaaaaaaaaaaaaaaaaaaababababababababababababababababababababababababab
"}
@@ -19,6 +19,6 @@ var/const/PATHFINDER =(1<<13) //VOREStation Edit - Added Pathfinder
idtype = /obj/item/weapon/card/id/science/head/pathfinder
economic_modifier = 7
access = list(access_eva, access_maint_tunnels, access_external_airlocks, access_pilot, access_explorer, access_research)
minimal_access = list(access_eva, access_pilot, access_explorer, access_research)
access = list(access_eva, access_maint_tunnels, access_external_airlocks, access_pilot, access_explorer, access_research, access_gateway)
minimal_access = list(access_eva, access_pilot, access_explorer, access_research, access_gateway)
outfit_type = /decl/hierarchy/outfit/job/pathfinder
+1
View File
@@ -36,6 +36,7 @@
/datum/map_z_level/tether_lateload/underdark
name = "Underdark"
flags = MAP_LEVEL_CONTACT|MAP_LEVEL_PLAYER
base_turf = /turf/simulated/mineral/floor/virgo3b
/datum/map_template/tether_lateload/tether_underdark/on_map_loaded(z)
. = ..()
+7
View File
@@ -14,12 +14,19 @@
name = "\improper Unknown Area AU" //Nobody will know what this means if they see it, anyway.
requires_power = 1
dynamic_lighting = 1
power_equip = FALSE
power_environ = FALSE
power_light = FALSE
/area/submap/admin_upload/pow
name = "\improper Unknown Area AU+P"
requires_power = 0
/area/submap/admin_upload/lit
name = "\improper Unknown Area AU+L"
requires_power = 1
dynamic_lighting = 0
power_equip = FALSE
power_environ = FALSE
power_light = FALSE
/area/submap/admin_upload/powlit
name = "\improper Unknown Area AU+PL"
requires_power = 0
+1
View File
@@ -189,6 +189,7 @@
/area/tether_away/cave
flags = RAD_SHIELDED
ambience = list('sound/ambience/ambimine.ogg', 'sound/ambience/song_game.ogg')
base_turf = /turf/simulated/mineral/floor/ignore_mapgen/cave
/area/tether_away/cave/explored/normal
name = "\improper Away Mission - Virgo 4 Cave (E)"
+1 -1
View File
@@ -1802,7 +1802,7 @@
/area/tether/surfacebase/mining_main/storage)
"adU" = (
/obj/structure/table/rack,
/obj/item/weapon/pickaxe/hammer,
/obj/item/weapon/pickaxe,
/obj/item/weapon/tool/wrench,
/obj/item/weapon/tool/crowbar,
/obj/item/weapon/shovel,
+13 -15
View File
@@ -8455,13 +8455,11 @@
opacity = 0
},
/obj/structure/grille,
/obj/structure/window/reinforced/full,
/turf/simulated/floor,
/area/security/security_processing)
"oh" = (
/obj/machinery/door/firedoor/glass,
/obj/structure/grille,
/obj/structure/window/reinforced/full,
/obj/structure/window/reinforced/polarized{
dir = 10;
icon_state = "fwindow";
id = "sec_processing"
},
/turf/simulated/floor,
/area/security/security_processing)
"oi" = (
@@ -13671,9 +13669,6 @@
/turf/simulated/floor/plating,
/area/quartermaster/office)
"wb" = (
/obj/machinery/computer/supplycomp{
dir = 1
},
/obj/structure/cable/green{
d1 = 1;
d2 = 2;
@@ -13685,6 +13680,9 @@
/obj/effect/floor_decal/corner/brown/border{
dir = 8
},
/obj/machinery/computer/supplycomp/control{
dir = 1
},
/turf/simulated/floor/tiled,
/area/quartermaster/office)
"wc" = (
@@ -35028,7 +35026,7 @@ cS
jk
jk
jk
oh
qQ
oE
po
pO
@@ -35170,7 +35168,7 @@ cT
jy
jk
jk
oh
qQ
oF
pp
pP
@@ -35313,9 +35311,9 @@ mH
lD
lD
of
oh
oh
oh
qQ
qQ
qQ
qk
qQ
qQ
+2
View File
@@ -122,8 +122,10 @@
// Mining Underdark
/area/mine/unexplored/underdark
name = "\improper Mining Underdark"
base_turf = /turf/simulated/mineral/floor/virgo3b
/area/mine/explored/underdark
name = "\improper Mining Underdark"
base_turf = /turf/simulated/mineral/floor/virgo3b
// Mining outpost areas
/area/outpost/mining_main/passage
+5
View File
@@ -72,6 +72,11 @@
{{:helper.link('', 'pill pill' + data.pillSprite, {'tab_select' : 'pill'}, null, 'link32')}}
{{:helper.link('', 'pill bottle' + data.bottleSprite, {'tab_select' : 'bottle'}, null, 'link32')}}
</div>
{{else}}
<hr>
<div class='item'>
{{:helper.link('Create bottle (50 units max)', null, {'createbottle' : 1})}}
</div>
{{/if}}
{{/if}}
@@ -14,6 +14,10 @@ automatically by GUI tools like TortoiseGit and GitHub for Windows, but
## Current Hooks
* **Pre-commit**: Runs [mapmerge2] on changed maps, if any.
* **DMI merger**: Attempts to [fix icon conflicts] when performing a git merge.
If it succeeds, the file is marked merged. If it fails, it logs what states
are still in conflict and adds them to the .dmi file, where the desired
resolution can be chosen.
## Adding New Hooks
@@ -34,3 +38,4 @@ version of Python is found.
[merge drivers]: https://git-scm.com/docs/gitattributes#_performing_a_three_way_merge
[Git for Windows]: https://gitforwindows.org/
[mapmerge2]: ../mapmerge2/README.md
[fix icon conflicts]: ../mapmerge2/merge_driver_dmi.py
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
exec tools/hooks/python.sh -m merge_driver_dmi "$@"
+16
View File
@@ -0,0 +1,16 @@
@echo off
cd %~dp0
for %%f in (*.hook) do (
echo Installing hook: %%~nf
copy %%f ..\..\.git\hooks\%%~nf >nul
)
for %%f in (*.merge) do (
echo Installing merge driver: %%~nf
echo [merge "%%~nf"]^
driver = tools/hooks/%%f %%P %%O %%A %%B %%L >> ..\..\.git\config
)
echo Installing Python dependencies
python -m pip install -r ..\mapmerge2\requirements.txt
echo Done
pause
+15
View File
@@ -0,0 +1,15 @@
#!/bin/bash
set -e
shopt -s nullglob
cd "$(dirname "$0")"
for f in *.hook; do
echo Installing hook: ${f%.hook}
cp $f ../../.git/hooks/${f%.hook}
done
for f in *.merge; do
echo Installing merge driver: ${f%.merge}
git config --replace-all merge.${f%.merge}.driver "tools/hooks/$f %P %O %A %B %L"
done
echo Installing Python dependencies
./python.sh -m pip install -r ../mapmerge2/requirements.txt
echo "Done"
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
exec tools/hooks/python.sh -m precommit
-7
View File
@@ -1,7 +0,0 @@
cd ../../maps/tether
FOR %%f IN (*.dmm) DO (
copy %%f %%f.backup
)
pause
-8
View File
@@ -1,8 +0,0 @@
SET z_levels=10
cd
FOR %%f IN (../../maps/tether/*.dmm) DO (
java -jar MapPatcher.jar -clean ../../maps/tether/%%f.backup ../../maps/tether/%%f ../../maps/tether/%%f
)
pause
Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
#!/bin/sh
for MAPFILE in ../../maps/*.dmm
do
MAPNAME=$(basename $MAPFILE)
git show HEAD:maps/$MAPNAME > tmp.dmm
java -jar MapPatcher.jar -clean tmp.dmm $MAPFILE $MAPFILE
rm tmp.dmm
done
-6
View File
@@ -1,6 +0,0 @@
@echo off
set tab=
echo. >> ../../.git/config
echo [merge "merge-dmm"] >> ../../.git/config
echo %tab%name = mapmerge driver >> ../../.git/config
echo %tab%driver = ./tools/mapmerge/mapmerge.sh %%O %%A %%B >> ../../.git/config
-6
View File
@@ -1,6 +0,0 @@
F="../../.git/config"
echo '' >> $F
echo '[merge "merge-dmm"]' >> $F
echo ' name = mapmerge driver' >> $F
echo ' driver = ./tools/mapmerge/mapmerge.sh %O %A %B' >> $F
-19
View File
@@ -1,19 +0,0 @@
1. Install java(http://www.java.com/en/download/index.jsp)
2. Make sure java is in your PATH. To test this, open git bash, and type "java". If it says unknown command, you need to add JAVA/bin to your PATH variable (A guide for this can be found at https://www.java.com/en/download/help/path.xml ).
Committing
1. Before starting to edit the map, double-click "prepare_map.bat" in the tools/mapmerge/ directory.
2. After finishing your edit, and before your commit, double-click "clean_map.bat" in the tools/mapmerge/ directory.
This will make sure in the new version of your map, no paths are needlessly changed, thus instead of 8000 lines changed you'll get 50 lines changed. This not only reduces size of your commit, it also makes it possible to get an overview of your map changes on the "files changed" page in your pull request.
Merging
The easiest way to do merging is to install the merge driver. For this, open `Baystation12/.git/config` in a text editor, and paste the following lines to the end of it:
[merge "merge-dmm"]
name = mapmerge driver
driver = ./tools/mapmerge/mapmerge.sh %O %A %B
You may optionally instead run git_merge_installer.bat or git_merge_installer.sh which should automatically insert these lines for you at the appropriate location.
After this, merging maps should happen automagically unless there are conflicts(a tile that both you and someone else changed). If there are conflicts, you will unfortunately still be stuck with opening both versions in a map editor, and manually resolving the issues.
-9
View File
@@ -1,9 +0,0 @@
java -jar tools/mapmerge/MapPatcher.jar -merge $1 $2 $3 $2
if [ "$?" -gt 0 ]
then
echo "Unable to automatically resolve map conflicts, please merge manually."
exit 1
fi
java -jar tools/mapmerge/MapPatcher.jar -clean $3 $2 $2
exit 0
-52
View File
@@ -1,52 +0,0 @@
# Map Merge 2
**Map Merge 2** is an improvement over previous map merging scripts, with
better merge-conflict prevention, multi-Z support, and automatic handling of
key overflow. For up-to-date tips and tricks, also visit the [Map Merger] wiki article.
## What Map Merging Is
The "map merge" operation describes the process of rewriting a map file written
by the DreamMaker map editor to A) use a format more amenable to Git's conflict
resolution and B) differ in the least amount textually from the previous
version of the map while maintaining all the actual changes. It requires an old
version of the map to use as a reference and a new version of the map which
contains the desired changes.
## Installation
To install Python dependencies, run `requirements-install.bat`, or run
`python -m pip install -r requirements.txt` directly. See the [Git hooks]
documentation to install the Git pre-commit hook which runs the map merger
automatically, or use `tools/mapmerge/Prepare Maps.bat` to save backups before
running `mapmerge.bat`.
For up-to-date installation and detailed troubleshooting instructions, visit
the [Map Merger] wiki article.
## Code Structure
Frontend scripts are meant to be run directly. They obey the environment
variables `TGM` to set whether files are saved in TGM (1) or DMM (0) format,
and `MAPROOT` to determine where maps are kept. By default, TGM is used and
the map root is autodetected. Each script may either prompt for the desired map
or be run with command-line parameters indicating which maps to act on. The
scripts include:
* `convert.py` for converting maps to and from the TGM format. Used by
`tgm2dmm.bat` and `dmm2tgm.bat`.
* `mapmerge.py` for running the map merge on map backups saved by
`Prepare Maps.bat`. Used by `mapmerge.bat`
Implementation modules:
* `dmm.py` includes the map reader and writer.
* `mapmerge.py` includes the implementation of the map merge operation.
* `frontend.py` includes the common code for the frontend scripts.
`precommit.py` is run by the [Git hooks] if installed, and merges the new
version of any map saved in the index (`git add`ed) with the old version stored
in Git when run.
[Map Merger]: https://tgstation13.org/wiki/Map_Merger
[Git hooks]: ../hooks/README.md
+253
View File
@@ -0,0 +1,253 @@
# Tools for working with modern DreamMaker icon files (PNGs + metadata)
import math
from PIL import Image
from PIL.PngImagePlugin import PngInfo
DEFAULT_SIZE = 32, 32
LOOP_UNLIMITED = 0
LOOP_ONCE = 1
NORTH = 1
SOUTH = 2
EAST = 4
WEST = 8
SOUTHEAST = SOUTH|EAST
SOUTHWEST = SOUTH|WEST
NORTHEAST = NORTH|EAST
NORTHWEST = NORTH|WEST
CARDINALS = [NORTH, SOUTH, EAST, WEST]
DIR_ORDER = [SOUTH, NORTH, EAST, WEST, SOUTHEAST, SOUTHWEST, NORTHEAST, NORTHWEST]
DIR_NAMES = {
'SOUTH': SOUTH,
'NORTH': NORTH,
'EAST': EAST,
'WEST': WEST,
'SOUTHEAST': SOUTHEAST,
'SOUTHWEST': SOUTHWEST,
'NORTHEAST': NORTHEAST,
'NORTHWEST': NORTHWEST,
**{str(x): x for x in DIR_ORDER},
**{x: x for x in DIR_ORDER},
'0': SOUTH,
None: SOUTH,
}
class Dmi:
version = "4.0"
def __init__(self, width, height):
self.width = width
self.height = height
self.states = []
@classmethod
def from_file(cls, fname):
image = Image.open(fname)
# no metadata = regular image file
if 'Description' not in image.info:
dmi = Dmi(*image.size)
state = dmi.state("")
state.frame(image)
return dmi
# read metadata
metadata = image.info['Description']
line_iter = iter(metadata.splitlines())
assert next(line_iter) == "# BEGIN DMI"
assert next(line_iter) == f"version = {cls.version}"
dmi = Dmi(*DEFAULT_SIZE)
state = None
for line in line_iter:
if line == "# END DMI":
break
key, value = line.lstrip().split(" = ")
if key == 'width':
dmi.width = int(value)
elif key == 'height':
dmi.height = int(value)
elif key == 'state':
state = dmi.state(unescape(value))
elif key == 'dirs':
state.dirs = int(value)
elif key == 'frames':
state._nframes = int(value)
elif key == 'delay':
state.delays = [parse_num(x) for x in value.split(',')]
elif key == 'loop':
state.loop = int(value)
elif key == 'rewind':
state.rewind = parse_bool(value)
elif key == 'hotspot':
x, y, frm = [int(x) for x in value.split(',')]
state.hotspot(frm - 1, x, y)
elif key == 'movement':
state.movement = parse_bool(value)
else:
raise NotImplementedError(key)
# cut image into frames
width, height = image.size
gridwidth = width // dmi.width
i = 0
for state in dmi.states:
for frame in range(state._nframes):
for dir in range(state.dirs):
px = dmi.width * (i % gridwidth)
py = dmi.height * (i // gridwidth)
im = image.crop((px, py, px + dmi.width, py + dmi.height))
assert im.size == (dmi.width, dmi.height)
state.frames.append(im)
i += 1
state._nframes = None
return dmi
def state(self, *args, **kwargs):
s = State(self, *args, **kwargs)
self.states.append(s)
return s
@property
def default_state(self):
return self.states[0]
def get_state(self, name):
for state in self.states:
if state.name == name:
return state
raise KeyError(name)
return self.default_state
def _assemble_comment(self):
comment = "# BEGIN DMI\n"
comment += f"version = {self.version}\n"
comment += f"\twidth = {self.width}\n"
comment += f"\theight = {self.height}\n"
for state in self.states:
comment += f"state = {escape(state.name)}\n"
comment += f"\tdirs = {state.dirs}\n"
comment += f"\tframes = {state.framecount}\n"
if state.framecount > 1 and len(state.delays): #any(x != 1 for x in state.delays):
comment += "\tdelay = " + ",".join(map(str, state.delays)) + "\n"
if state.loop != 0:
comment += f"\tloop = {state.loop}\n"
if state.rewind:
comment += "\trewind = 1\n"
if state.movement:
comment += "\tmovement = 1\n"
if state.hotspots and any(state.hotspots):
current = None
for i, value in enumerate(state.hotspots):
if value != current:
x, y = value
comment += f"\thotspot = {x},{y},{i + 1}\n"
current = value
comment += "# END DMI"
return comment
def to_file(self, filename, *, palette=False):
# assemble comment
comment = self._assemble_comment()
# assemble spritesheet
W, H = self.width, self.height
num_frames = sum(len(state.frames) for state in self.states)
sqrt = math.ceil(math.sqrt(num_frames))
output = Image.new('RGBA', (sqrt * W, math.ceil(num_frames / sqrt) * H))
i = 0
for state in self.states:
for frame in state.frames:
output.paste(frame, ((i % sqrt) * W, (i // sqrt) * H))
i += 1
# save
pnginfo = PngInfo()
pnginfo.add_text('Description', comment, zip=True)
if palette:
output = output.convert('P')
output.save(filename, 'png', optimize=True, pnginfo=pnginfo)
class State:
def __init__(self, dmi, name, *, loop=LOOP_UNLIMITED, rewind=False, movement=False, dirs=1):
self.dmi = dmi
self.name = name
self.loop = loop
self.rewind = rewind
self.movement = movement
self.dirs = dirs
self._nframes = None # used during loading only
self.frames = []
self.delays = []
self.hotspots = None
@property
def framecount(self):
if self._nframes is not None:
return self._nframes
else:
return len(self.frames) // self.dirs
def frame(self, image, *, delay=1):
assert image.size == (self.dmi.width, self.dmi.height)
self.delays.append(delay)
self.frames.append(image)
def hotspot(self, first_frame, x, y):
if self.hotspots is None:
self.hotspots = [None] * self.framecount
for i in range(first_frame, self.framecount):
self.hotspots[i] = x, y
def _frame_index(self, frame=0, dir=None):
ofs = DIR_ORDER.index(DIR_NAMES[dir])
if ofs >= self.dirs:
ofs = 0
return frame * self.dirs + ofs
def get_frame(self, *args, **kwargs):
return self.frames[self._frame_index(*args, **kwargs)]
def escape(text):
assert '\\' not in text and '"' not in text
return f'"{text}"'
def unescape(text, quote='"'):
if text == 'null':
return None
if not (text.startswith(quote) and text.endswith(quote)):
raise ValueError(text)
text = text[1:-1]
assert '\\' not in text and quote not in text
return text
def parse_num(value):
if '.' in value:
return float(value)
return int(value)
def parse_bool(value):
if value not in ('0', '1'):
raise ValueError(value)
return value == '1'
if __name__ == '__main__':
# test: can we load every DMI in the tree
import os
count = 0
for dirpath, dirnames, filenames in os.walk('.'):
if '.git' in dirnames:
dirnames.remove('.git')
for filename in filenames:
if filename.endswith('.dmi'):
Dmi.from_file(os.path.join(dirpath, filename))
count += 1
print(f"Successfully parsed {count} dmi files")
+70 -4
View File
@@ -58,6 +58,23 @@ class DMM:
raise RuntimeError("ran out of keys, this shouldn't happen")
def overwrite_key(self, key, fixed, bad_keys):
try:
self.dictionary[key] = fixed
return None
except bidict.DuplicationError:
old_key = self.dictionary.inv[fixed]
bad_keys[key] = old_key
print(f"Merging '{num_to_key(key, self.key_length)}' into '{num_to_key(old_key, self.key_length)}'")
return old_key
def reassign_bad_keys(self, bad_keys):
if not bad_keys:
return
for k, v in self.grid.items():
# reassign the grid entries which used the old key
self.grid[k] = bad_keys.get(v, v)
def _presave_checks(self):
# last-second handling of bogus keys to help prevent and fix broken maps
self._ensure_free_keys(0)
@@ -70,9 +87,16 @@ class DMM:
new_key = bad_keys[k] = self.generate_new_key()
self.dictionary.forceput(new_key, self.dictionary[k])
print(f" {num_to_key(k, self.key_length, True)} -> {num_to_key(new_key, self.key_length)}")
for k, v in self.grid.items():
# reassign the grid entries which used the old key
self.grid[k] = bad_keys.get(v, v)
# handle entries in the dictionary which have atoms in the wrong order
keys = list(self.dictionary.keys())
for key in keys:
value = self.dictionary[key]
if is_bad_atom_ordering(num_to_key(key, self.key_length, True), value):
fixed = tuple(fix_atom_ordering(value))
self.overwrite_key(key, fixed, bad_keys)
self.reassign_bad_keys(bad_keys)
def _ensure_free_keys(self, desired):
# ensure that free keys exist by increasing the key length if necessary
@@ -179,6 +203,45 @@ def parse_map_atom(atom):
return path, vars
def is_bad_atom_ordering(key, atoms):
seen_turfs = 0
seen_areas = 0
can_fix = False
for each in atoms:
if each.startswith('/turf'):
if seen_turfs == 1:
print(f"Warning: key '{key}' has multiple turfs!")
if seen_areas:
print(f"Warning: key '{key}' has area before turf (autofixing...)")
can_fix = True
seen_turfs += 1
elif each.startswith('/area'):
if seen_areas == 1:
print(f"Warning: key '{key}' has multiple areas!!!")
seen_areas += 1
else:
if (seen_turfs or seen_areas) and not can_fix:
print(f"Warning: key '{key}' has movable after turf or area (autofixing...)")
can_fix = True
if not seen_areas or not seen_turfs:
print(f"Warning: key '{key}' is missing either a turf or area")
return can_fix
def fix_atom_ordering(atoms):
movables = []
turfs = []
areas = []
for each in atoms:
if each.startswith('/turf'):
turfs.append(each)
elif each.startswith('/area'):
areas.append(each)
else:
movables.append(each)
movables.extend(turfs)
movables.extend(areas)
return movables
# ----------
# TGM writer
@@ -307,7 +370,7 @@ def _parse(map_raw_text):
continue
elif in_comment_line:
continue
elif char == "\t":
elif char in "\r\t":
continue
if char == "/" and not in_quote_block:
@@ -415,6 +478,9 @@ def _parse(map_raw_text):
# grid block
for char in it:
if char == "\r":
continue
if in_coord_block:
if char == ",":
if reading_coord == "x":
+1 -1
View File
@@ -1,5 +1,5 @@
@echo off
set MAPROOT=../../_maps/
set MAPROOT=../../maps/
set TGM=1
python convert.py
pause
-15
View File
@@ -1,15 +0,0 @@
@echo off
cd %~dp0
for %%f in (*.hook) do (
echo Installing hook: %%~nf
mkdir ..\..\..\.git\hooks
copy %%f ..\..\..\.git\hooks\%%~nf >nul
)
for %%f in (*.merge) do (
echo Installing merge driver: %%~nf
echo [merge "%%~nf"]^
driver = tools/hooks/%%f %%P %%O %%A %%B %%L >> ..\..\..\.git\config
)
echo Done
pause
-11
View File
@@ -1,11 +0,0 @@
#!/bin/bash
cd "$(dirname "$0")"
for f in *.hook; do
echo Installing hook: ${f%.hook}
cp $f ../../../.git/hooks/${f%.hook}
done
for f in *.merge; do
echo Installing merge driver: ${f%.merge}
git config --replace-all merge.${f%.merge}.driver "tools/mapmerge2/hooks/$f %P %O %A %B %L"
done
echo "Done"
-2
View File
@@ -1,2 +0,0 @@
#!/bin/bash
exec tools/mapmerge2/hooks/python.sh -m precommit
@@ -0,0 +1,465 @@
/turf/open/floor/circuit/killroom : /turf/open/floor/circuit/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/airless/asteroid : /obj/effect/turf_decal/sand , /turf/open/floor/plasteel/airless {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/airless/bar : /obj/effect/turf_decal/tile/bar , /obj/effect/turf_decal/tile/bar {dir=1} , /turf/open/floor/plasteel/airless {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/arrival {dir=1} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
/turf/open/floor/plasteel/arrival {dir=@UNSET} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/arrival {dir=2} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/arrival {dir=4} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/arrival {dir=5} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/arrival {dir=6} : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/arrival {dir=8} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
/turf/open/floor/plasteel/arrival {dir=9} : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
/turf/open/floor/plasteel/arrival {dir=10} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/arrival/corner {dir=1} : /turf/open/floor/plasteel/white/corner {@OLD}
/turf/open/floor/plasteel/arrival/corner {dir=@UNSET} : /turf/open/floor/plasteel/white/corner {@OLD}
/turf/open/floor/plasteel/arrival/corner {dir=2} : /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/arrival/corner {dir=4} : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/arrival/corner {dir=8} : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/asteroid : /obj/effect/turf_decal/sand , /turf/open/floor/plasteel
/turf/open/floor/plasteel/bar : /obj/effect/turf_decal/tile/bar , /obj/effect/turf_decal/tile/bar {dir=1} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/barber : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blueyellow : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blueyellow/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blueyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blueyellow/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blueyellow/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blueyellow/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blueyellow/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blueyellow/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blueyellow/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/blueyellow/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brownold {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brownold {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brownold {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brownold {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brownold {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brownold {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brownold {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brownold {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brownold {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/brownold/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/caution {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1}
/turf/open/floor/plasteel/caution {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/caution {dir=2} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/caution {dir=4} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/caution {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/checker {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/caution {dir=6} : /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/caution {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1}
/turf/open/floor/plasteel/caution {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1}
/turf/open/floor/plasteel/caution {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/checker {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/caution/corner {dir=1} : /turf/open/floor/plasteel/dark/corner {@OLD}
/turf/open/floor/plasteel/caution/corner {dir=@UNSET} : /turf/open/floor/plasteel/dark/corner {@OLD}
/turf/open/floor/plasteel/caution/corner {dir=2} : /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/caution/corner {dir=4} : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/caution/corner {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/cmo : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/dark/telecomms/mainframe : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/dark/telecomms/server : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/dark/telecomms/server/walkway : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkblue/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown/side {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown/side {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown/side {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown/side {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown/side {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown/side {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown/side {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown/side {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown/side {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkbrown/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkred/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/escape {dir=1} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
/turf/open/floor/plasteel/escape {dir=@UNSET} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/escape {dir=2} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/escape {dir=4} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/escape {dir=5} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/escape {dir=6} : /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/escape {dir=8} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
/turf/open/floor/plasteel/escape {dir=9} : /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
/turf/open/floor/plasteel/escape {dir=10} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/escape/corner {dir=1} : /turf/open/floor/plasteel/white/corner {@OLD}
/turf/open/floor/plasteel/escape/corner {dir=@UNSET} : /turf/open/floor/plasteel/white/corner {@OLD}
/turf/open/floor/plasteel/escape/corner {dir=2} : /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/escape/corner {dir=4} : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/escape/corner {dir=8} : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/green/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/greenyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/hydrofloor : /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/corner : /obj/effect/turf_decal/tile/neutral {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/neutral/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/orange/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/purple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/red/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/redside {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/redside {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/redside {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/redside {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/redside {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/redside {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/redside {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/redside {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/redside {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/blueside {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/blueside {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/blueside {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/blueside {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/blueside {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/blueside {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/blueside {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/blueside {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redblue/blueside {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redgreen/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redyellow : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redyellow/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redyellow/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redyellow/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redyellow/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redyellow/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redyellow/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redyellow/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/redyellow/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/airless : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/airless {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/snowdin : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/snowdin {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/telecomms : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/telecomms/mainframe : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/killroom : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/side {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/side {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/side {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/side {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/side {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/side {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/side {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/side {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/side {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/vault/corner : /obj/effect/turf_decal/tile/neutral {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitegreen/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whitered/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/whiteyellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
/turf/open/floor/plasteel/yellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+177
View File
@@ -0,0 +1,177 @@
#!/usr/bin/env python3
import sys
import dmi
def images_equal(left, right):
if left.size != right.size:
return False
w, h = left.size
left_load, right_load = left.load(), right.load()
for y in range(0, h):
for x in range(0, w):
lpixel, rpixel = left_load[x, y], right_load[x, y]
# quietly ignore changes where both pixels are fully transparent
if lpixel != rpixel and (lpixel[3] != 0 or rpixel[3] != 0):
return False
return True
def states_equal(left, right):
result = True
# basic properties
for attr in ('loop', 'rewind', 'movement', 'dirs', 'delays', 'hotspots', 'framecount'):
lval, rval = getattr(left, attr), getattr(right, attr)
if lval != rval:
result = False
# frames
for (left_frame, right_frame) in zip(left.frames, right.frames):
if not images_equal(left_frame, right_frame):
result = False
return result
def key_of(state):
return (state.name, state.movement)
def dictify(sheet):
result = {}
for state in sheet.states:
k = key_of(state)
if k in result:
print(f" duplicate {k!r}")
result[k] = state
return result
def three_way_merge(base, left, right):
base_dims = base.width, base.height
if base_dims != (left.width, left.height) or base_dims != (right.width, right.height):
print("Dimensions have changed:")
print(f" Base: {base.width} x {base.height}")
print(f" Ours: {left.width} x {left.height}")
print(f" Theirs: {right.width} x {right.height}")
return True, None
base_states, left_states, right_states = dictify(base), dictify(left), dictify(right)
new_left = {k: v for k, v in left_states.items() if k not in base_states}
new_right = {k: v for k, v in right_states.items() if k not in base_states}
new_both = {}
conflicts = []
for key, state in list(new_left.items()):
in_right = new_right.get(key, None)
if in_right:
if states_equal(state, in_right):
# allow it
new_both[key] = state
else:
# generate conflict states
print(f" C: {state.name!r}: added differently in both!")
state.name = f"{state.name} !CONFLICT! left"
conflicts.append(state)
in_right.name = f"{state.name} !CONFLICT! right"
conflicts.append(in_right)
# don't add it a second time
del new_left[key]
del new_right[key]
final_states = []
# add states that are currently in the base
for state in base.states:
in_left = left_states.get(key_of(state), None)
in_right = right_states.get(key_of(state), None)
left_equals = in_left and states_equal(state, in_left)
right_equals = in_right and states_equal(state, in_right)
if not in_left and not in_right:
# deleted in both left and right, it's just deleted
print(f" {state.name!r}: deleted in both")
elif not in_left:
# left deletes
print(f" {state.name!r}: deleted in left")
if not right_equals:
print(f" ... but modified in right")
final_states.append(in_right)
elif not in_right:
# right deletes
print(f" {state.name!r}: deleted in right")
if not left_equals:
print(f" ... but modified in left")
final_states.append(in_left)
elif left_equals and right_equals:
# changed in neither
#print(f"Same in both: {state.name!r}")
final_states.append(state)
elif left_equals:
# changed only in right
print(f" {state.name!r}: changed in left")
final_states.append(in_right)
elif right_equals:
# changed only in left
print(f" {state.name!r}: changed in right")
final_states.append(in_left)
elif states_equal(in_left, in_right):
# changed in both, to the same thing
print(f" {state.name!r}: changed same in both")
final_states.append(in_left) # either or
else:
# changed in both
name = state.name
print(f" C: {name!r}: changed differently in both!")
state.name = f"{name} !CONFLICT! base"
conflicts.append(state)
in_left.name = f"{name} !CONFLICT! left"
conflicts.append(in_left)
in_right.name = f"{name} !CONFLICT! right"
conflicts.append(in_right)
# add states which both left and right added the same
for key, state in new_both.items():
print(f" {state.name!r}: added same in both")
final_states.append(state)
# add states that are brand-new in the left
for key, state in new_left.items():
print(f" {state.name!r}: added in left")
final_states.append(state)
# add states that are brand-new in the right
for key, state in new_right.items():
print(f" {state.name!r}: added in right")
final_states.append(state)
final_states.extend(conflicts)
merged = dmi.Dmi(base.width, base.height)
merged.states = final_states
return len(conflicts), merged
def main(path, original, left, right):
print(f"Merging icon: {path}")
icon_orig = dmi.Dmi.from_file(original)
icon_left = dmi.Dmi.from_file(left)
icon_right = dmi.Dmi.from_file(right)
trouble, merged = three_way_merge(icon_orig, icon_left, icon_right)
if merged:
merged.to_file(left)
if trouble:
print("!!! Manual merge required!")
if merged:
print(" A best-effort merge was performed. You must edit the icon and remove all")
print(" icon states marked with !CONFLICT!, leaving only the desired icon.")
else:
print(" The icon was totally unable to be merged, you must start with one version")
print(" or the other and manually resolve the conflict.")
print(" Information about which states conflicted is listed above.")
return trouble
if __name__ == '__main__':
if len(sys.argv) != 6:
print("DMI merge driver called with wrong number of arguments")
print(" usage: merge-driver-dmi %P %O %A %B %L")
exit(1)
# "left" is also the file that ought to be overwritten
_, path, original, left, right, conflict_size_marker = sys.argv
exit(main(path, original, left, right))
+9 -2
View File
@@ -9,6 +9,13 @@ def main(repo):
print("You need to resolve merge conflicts first.")
return 1
try:
repo.lookup_reference('MERGE_HEAD')
print("Not running mapmerge for merge commit.")
return 0
except KeyError:
pass
changed = 0
for path, status in repo.status().items():
if path.endswith(".dmm") and (status & (pygit2.GIT_STATUS_INDEX_MODIFIED | pygit2.GIT_STATUS_INDEX_NEW)):
@@ -20,12 +27,12 @@ def main(repo):
head_blob = repo[repo[repo.head.target].tree[path].id]
except KeyError:
# New map, no entry in HEAD
print(f"Converting new map: {path}")
print(f"Converting new map: {path}", flush=True)
assert (status & pygit2.GIT_STATUS_INDEX_NEW)
merged_map = index_map
else:
# Entry in HEAD, merge the index over it
print(f"Merging map: {path}")
print(f"Merging map: {path}", flush=True)
assert not (status & pygit2.GIT_STATUS_INDEX_NEW)
head_map = dmm.DMM.from_bytes(head_blob.read_raw())
merged_map = merge_map(index_map, head_map)

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