Merge remote-tracking branch 'ParadiseSS13/master' into ci-upgrades
@@ -886,7 +886,7 @@
|
||||
},
|
||||
/obj/effect/decal/cleanable/cobweb,
|
||||
/obj/machinery/computer/prisoner{
|
||||
dir = 1
|
||||
dir = 4
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
|
||||
dir = 6
|
||||
@@ -4371,6 +4371,7 @@
|
||||
"sO" = (
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/machinery/computer/security{
|
||||
dir = 4;
|
||||
network = list("Labor Camp")
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
|
||||
@@ -5275,7 +5276,7 @@
|
||||
/area/mine/production)
|
||||
"VJ" = (
|
||||
/obj/machinery/computer/secure_data{
|
||||
dir = 1
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 1;
|
||||
|
||||
@@ -651,7 +651,9 @@
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/shuttle/administration)
|
||||
"cH" = (
|
||||
/obj/machinery/computer/shuttle/ferry,
|
||||
/obj/machinery/computer/shuttle/ferry{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/plating,
|
||||
/area/centcom/evac)
|
||||
"cI" = (
|
||||
@@ -661,7 +663,9 @@
|
||||
/turf/simulated/floor/plating/airless,
|
||||
/area/shuttle/specops)
|
||||
"cK" = (
|
||||
/obj/machinery/computer/shuttle/admin,
|
||||
/obj/machinery/computer/shuttle/admin{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/plating,
|
||||
/area/centcom/evac)
|
||||
"cL" = (
|
||||
@@ -1387,7 +1391,9 @@
|
||||
/turf/simulated/floor/wood,
|
||||
/area/syndicate_mothership)
|
||||
"fi" = (
|
||||
/obj/machinery/computer/shuttle/syndicate/recall,
|
||||
/obj/machinery/computer/shuttle/syndicate/recall{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/wood,
|
||||
/area/syndicate_mothership)
|
||||
"fj" = (
|
||||
@@ -1411,8 +1417,8 @@
|
||||
/turf/simulated/wall/indestructible/riveted,
|
||||
/area/centcom/gamma)
|
||||
"fn" = (
|
||||
/obj/machinery/computer/library/checkout,
|
||||
/obj/structure/table/wood,
|
||||
/obj/machinery/computer/library/checkout,
|
||||
/turf/simulated/floor/engine/cult,
|
||||
/area/wizard_station)
|
||||
"fo" = (
|
||||
@@ -2028,7 +2034,9 @@
|
||||
/turf/simulated/floor/plasteel/dark,
|
||||
/area/syndicate_mothership)
|
||||
"hP" = (
|
||||
/obj/machinery/computer/communications,
|
||||
/obj/machinery/computer/communications{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/shuttle/administration)
|
||||
"hQ" = (
|
||||
@@ -3500,7 +3508,9 @@
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/centcom/control)
|
||||
"mP" = (
|
||||
/obj/machinery/computer/pod/deathsquad,
|
||||
/obj/machinery/computer/pod/deathsquad{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/plasteel/dark{
|
||||
dir = 1;
|
||||
icon_state = "vault"
|
||||
@@ -3523,7 +3533,9 @@
|
||||
/turf/simulated/floor/wood,
|
||||
/area/centcom/control)
|
||||
"mV" = (
|
||||
/obj/machinery/computer/card/centcom,
|
||||
/obj/machinery/computer/card/centcom{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/wood,
|
||||
/area/centcom/control)
|
||||
"mW" = (
|
||||
@@ -3588,7 +3600,9 @@
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/centcom/control)
|
||||
"nh" = (
|
||||
/obj/machinery/computer/communications,
|
||||
/obj/machinery/computer/communications{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/centcom/control)
|
||||
"nj" = (
|
||||
@@ -4306,7 +4320,9 @@
|
||||
d2 = 8;
|
||||
icon_state = "0-8"
|
||||
},
|
||||
/obj/machinery/computer/mech_bay_power_console,
|
||||
/obj/machinery/computer/mech_bay_power_console{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/shuttle/gamma/space)
|
||||
"pu" = (
|
||||
@@ -4417,12 +4433,12 @@
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/centcom/specops)
|
||||
"pP" = (
|
||||
/obj/structure/table/wood,
|
||||
/obj/machinery/computer/security/telescreen{
|
||||
desc = "Used for watching the Special Ops.";
|
||||
name = "Special Ops. Monitor";
|
||||
network = list("ERT")
|
||||
},
|
||||
/obj/structure/table/wood,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/centcom/specops)
|
||||
"pQ" = (
|
||||
@@ -4430,10 +4446,12 @@
|
||||
/turf/simulated/floor/plasteel/dark,
|
||||
/area/centcom/specops)
|
||||
"pR" = (
|
||||
/obj/machinery/computer/station_alert,
|
||||
/obj/structure/sign/poster/official/nanotrasen_logo{
|
||||
pixel_x = 32
|
||||
},
|
||||
/obj/machinery/computer/station_alert{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 5;
|
||||
icon_state = "darkyellow"
|
||||
@@ -4940,7 +4958,9 @@
|
||||
},
|
||||
/area/centcom/evac)
|
||||
"rz" = (
|
||||
/obj/machinery/computer/communications,
|
||||
/obj/machinery/computer/communications{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/plasteel/dark,
|
||||
/area/centcom/specops)
|
||||
"rA" = (
|
||||
@@ -5185,10 +5205,12 @@
|
||||
/turf/simulated/floor/wood,
|
||||
/area/centcom/evac)
|
||||
"sy" = (
|
||||
/obj/machinery/computer/secure_data,
|
||||
/obj/machinery/light/spot{
|
||||
dir = 8
|
||||
},
|
||||
/obj/machinery/computer/secure_data{
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/centcom/evac)
|
||||
"sz" = (
|
||||
@@ -6168,7 +6190,9 @@
|
||||
/turf/simulated/floor/plasteel/grimy,
|
||||
/area/centcom/specops)
|
||||
"vf" = (
|
||||
/obj/machinery/computer/secure_data,
|
||||
/obj/machinery/computer/secure_data{
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/centcom/control)
|
||||
"vg" = (
|
||||
@@ -6185,7 +6209,9 @@
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/admin)
|
||||
"vi" = (
|
||||
/obj/machinery/computer/med_data,
|
||||
/obj/machinery/computer/med_data{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/centcom/control)
|
||||
"vj" = (
|
||||
@@ -6235,11 +6261,11 @@
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/admin)
|
||||
"vp" = (
|
||||
/obj/machinery/computer/mech_bay_power_console,
|
||||
/obj/structure/cable{
|
||||
d2 = 2;
|
||||
icon_state = "0-2"
|
||||
},
|
||||
/obj/machinery/computer/mech_bay_power_console,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/admin)
|
||||
"vr" = (
|
||||
@@ -6257,24 +6283,33 @@
|
||||
/area/admin)
|
||||
"vs" = (
|
||||
/obj/machinery/computer/security{
|
||||
dir = 1;
|
||||
network = list("SS13","Telecomms","Research Outpost","Mining Outpost","ERT","CentComm","Thunderdome")
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/centcom/control)
|
||||
"vt" = (
|
||||
/obj/machinery/computer/station_alert,
|
||||
/obj/machinery/computer/station_alert{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/centcom/control)
|
||||
"vu" = (
|
||||
/obj/machinery/computer/communications,
|
||||
/obj/machinery/computer/communications{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/centcom/control)
|
||||
"vv" = (
|
||||
/obj/machinery/computer/robotics,
|
||||
/obj/machinery/computer/robotics{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/centcom/control)
|
||||
"vw" = (
|
||||
/obj/machinery/computer/crew,
|
||||
/obj/machinery/computer/crew{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/centcom/control)
|
||||
"vx" = (
|
||||
@@ -6852,8 +6887,10 @@
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/admin)
|
||||
"wS" = (
|
||||
/obj/machinery/computer/secure_data,
|
||||
/obj/item/paper/sop,
|
||||
/obj/machinery/computer/secure_data{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/admin)
|
||||
"wT" = (
|
||||
@@ -6881,11 +6918,15 @@
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/admin)
|
||||
"wY" = (
|
||||
/obj/machinery/computer/communications,
|
||||
/obj/machinery/computer/communications{
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/admin)
|
||||
"wZ" = (
|
||||
/obj/machinery/computer/med_data,
|
||||
/obj/machinery/computer/med_data{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/admin)
|
||||
"xa" = (
|
||||
@@ -7363,7 +7404,9 @@
|
||||
},
|
||||
/area/trader_station/sol)
|
||||
"yJ" = (
|
||||
/obj/machinery/computer/communications,
|
||||
/obj/machinery/computer/communications{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/admin)
|
||||
"yK" = (
|
||||
@@ -7380,7 +7423,9 @@
|
||||
},
|
||||
/area/trader_station/sol)
|
||||
"yP" = (
|
||||
/obj/machinery/computer/atmos_alert,
|
||||
/obj/machinery/computer/atmos_alert{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/admin)
|
||||
"yQ" = (
|
||||
@@ -7390,12 +7435,15 @@
|
||||
},
|
||||
/area/centcom/evac)
|
||||
"yR" = (
|
||||
/obj/machinery/computer/message_monitor,
|
||||
/obj/item/paper/monitorkey,
|
||||
/obj/machinery/computer/message_monitor{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/admin)
|
||||
"yS" = (
|
||||
/obj/machinery/computer/account_database{
|
||||
dir = 1;
|
||||
name = "Admin Accounts Database"
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
@@ -7407,7 +7455,9 @@
|
||||
/turf/simulated/floor/plating,
|
||||
/area/centcom/evac)
|
||||
"yU" = (
|
||||
/obj/machinery/computer/secure_data,
|
||||
/obj/machinery/computer/secure_data{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/admin)
|
||||
"yV" = (
|
||||
@@ -7452,7 +7502,9 @@
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/admin)
|
||||
"zc" = (
|
||||
/obj/machinery/computer/arcade,
|
||||
/obj/machinery/computer/arcade{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/mineral/titanium/blue,
|
||||
/area/centcom/evac)
|
||||
"zd" = (
|
||||
@@ -7473,7 +7525,9 @@
|
||||
/turf/simulated/floor/plasteel/dark,
|
||||
/area/admin)
|
||||
"zh" = (
|
||||
/obj/machinery/computer/card,
|
||||
/obj/machinery/computer/card{
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/centcom/evac)
|
||||
"zi" = (
|
||||
@@ -7944,7 +7998,9 @@
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/admin)
|
||||
"AS" = (
|
||||
/obj/machinery/computer/teleporter,
|
||||
/obj/machinery/computer/teleporter{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/admin)
|
||||
"AT" = (
|
||||
@@ -8000,11 +8056,15 @@
|
||||
/turf/simulated/floor/plasteel/dark,
|
||||
/area/syndicate_mothership)
|
||||
"Bb" = (
|
||||
/obj/machinery/computer/crew,
|
||||
/obj/machinery/computer/crew{
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/mineral/titanium/blue,
|
||||
/area/centcom/evac)
|
||||
"Bc" = (
|
||||
/obj/machinery/computer/communications,
|
||||
/obj/machinery/computer/communications{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/mineral/titanium/blue,
|
||||
/area/centcom/evac)
|
||||
"Bd" = (
|
||||
@@ -8040,6 +8100,7 @@
|
||||
/area/centcom/evac)
|
||||
"Bj" = (
|
||||
/obj/machinery/computer{
|
||||
dir = 1;
|
||||
name = "EMERGENCY SHUTTLE COMPUTER"
|
||||
},
|
||||
/turf/simulated/floor/mineral/titanium/blue,
|
||||
@@ -8100,7 +8161,9 @@
|
||||
/turf/simulated/floor/plasteel/dark,
|
||||
/area/syndicate_mothership)
|
||||
"Bv" = (
|
||||
/obj/machinery/computer/camera_advanced,
|
||||
/obj/machinery/computer/camera_advanced{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/plasteel/dark,
|
||||
/area/syndicate_mothership)
|
||||
"Bw" = (
|
||||
@@ -8117,6 +8180,7 @@
|
||||
/area/syndicate_mothership)
|
||||
"By" = (
|
||||
/obj/machinery/computer/shuttle/syndicate{
|
||||
dir = 1;
|
||||
name = "Nuclear Operatives Shuttle Console"
|
||||
},
|
||||
/turf/simulated/floor/plasteel/dark,
|
||||
@@ -9000,7 +9064,9 @@
|
||||
/turf/simulated/floor/mineral/titanium/blue,
|
||||
/area/shuttle/supply)
|
||||
"FJ" = (
|
||||
/obj/machinery/computer/secure_data,
|
||||
/obj/machinery/computer/secure_data{
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 10;
|
||||
icon_state = "darkred"
|
||||
@@ -9043,7 +9109,9 @@
|
||||
},
|
||||
/area/shuttle/escape)
|
||||
"Ga" = (
|
||||
/obj/machinery/computer/shuttle/ert,
|
||||
/obj/machinery/computer/shuttle/ert{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/plasteel/dark,
|
||||
/area/centcom/specops)
|
||||
"Gd" = (
|
||||
@@ -9119,7 +9187,9 @@
|
||||
/turf/simulated/wall/mineral/plastitanium,
|
||||
/area/shuttle/syndicate_sit)
|
||||
"GD" = (
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate/sst,
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate/sst{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/shuttle/syndicate_elite)
|
||||
"GJ" = (
|
||||
@@ -9376,10 +9446,12 @@
|
||||
/turf/simulated/floor/plating,
|
||||
/area/tdome/tdome2)
|
||||
"Il" = (
|
||||
/obj/machinery/computer/communications,
|
||||
/obj/item/radio/intercom/specops{
|
||||
pixel_y = -28
|
||||
},
|
||||
/obj/machinery/computer/communications{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/shuttle/specops)
|
||||
"Io" = (
|
||||
@@ -9622,7 +9694,9 @@
|
||||
/turf/simulated/floor/mineral/plastitanium/red/nitrogen,
|
||||
/area/shuttle/vox)
|
||||
"JH" = (
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate/sit,
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate/sit{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/shuttle/syndicate_sit)
|
||||
"JM" = (
|
||||
@@ -9636,6 +9710,7 @@
|
||||
/area/shuttle/administration)
|
||||
"JO" = (
|
||||
/obj/machinery/computer/security{
|
||||
dir = 1;
|
||||
network = list("SS13","Research Outpost","Mining Outpost")
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
@@ -10628,7 +10703,9 @@
|
||||
},
|
||||
/area/shuttle/escape)
|
||||
"PU" = (
|
||||
/obj/machinery/computer/shuttle/sit,
|
||||
/obj/machinery/computer/shuttle/sit{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/shuttle/syndicate_sit)
|
||||
"PX" = (
|
||||
@@ -11190,12 +11267,13 @@
|
||||
},
|
||||
/area/holodeck/source_thunderdomecourt)
|
||||
"TA" = (
|
||||
/obj/machinery/computer/security{
|
||||
network = list("SS13","Research Outpost","Mining Outpost","Telecomms")
|
||||
},
|
||||
/obj/structure/sign/poster/official/nanotrasen_logo{
|
||||
pixel_x = -32
|
||||
},
|
||||
/obj/machinery/computer/security{
|
||||
dir = 4;
|
||||
network = list("SS13","Research Outpost","Mining Outpost","Telecomms")
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 9;
|
||||
icon_state = "darkred"
|
||||
@@ -11379,7 +11457,9 @@
|
||||
},
|
||||
/area/holodeck/source_knightarena)
|
||||
"UJ" = (
|
||||
/obj/machinery/computer/shuttle/sst,
|
||||
/obj/machinery/computer/shuttle/sst{
|
||||
dir = 1
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/shuttle/syndicate_elite)
|
||||
"UK" = (
|
||||
@@ -11495,6 +11575,7 @@
|
||||
/area/shuttle/escape)
|
||||
"Vr" = (
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/admin{
|
||||
dir = 8;
|
||||
name = "NTV Argos shuttle navigation computer"
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
@@ -11568,7 +11649,9 @@
|
||||
},
|
||||
/area/shuttle/escape)
|
||||
"VS" = (
|
||||
/obj/machinery/computer/atmos_alert,
|
||||
/obj/machinery/computer/atmos_alert{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 6;
|
||||
icon_state = "darkyellow"
|
||||
@@ -11600,6 +11683,7 @@
|
||||
/area/shuttle/vox)
|
||||
"Wc" = (
|
||||
/obj/machinery/computer/shuttle/admin{
|
||||
dir = 8;
|
||||
name = "NTV Argos shuttle console"
|
||||
},
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
@@ -12043,7 +12127,6 @@
|
||||
},
|
||||
/area/shuttle/escape)
|
||||
"YV" = (
|
||||
/obj/machinery/computer/shuttle/trade/sol,
|
||||
/obj/machinery/door_control{
|
||||
id = "soltrader_south";
|
||||
name = "Trade Deposits Door";
|
||||
@@ -12057,6 +12140,9 @@
|
||||
pixel_x = 24;
|
||||
pixel_y = -8
|
||||
},
|
||||
/obj/machinery/computer/shuttle/trade/sol{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/mineral/titanium/blue,
|
||||
/area/shuttle/trade/sol)
|
||||
"YW" = (
|
||||
|
||||
@@ -115,3 +115,11 @@
|
||||
#define _2FA_ENABLED_IP "ENABLED_IP"
|
||||
/// Client will be prompted for 2FA always
|
||||
#define _2FA_ENABLED_ALWAYS "ENABLED_ALWAYS"
|
||||
|
||||
|
||||
#define MAX_SAVE_SLOTS 30 // Save slots for regular players
|
||||
#define MAX_SAVE_SLOTS_MEMBER 30 // Save slots for BYOND members
|
||||
|
||||
#define TAB_CHAR 0
|
||||
#define TAB_GAME 1
|
||||
#define TAB_GEAR 2
|
||||
|
||||
@@ -51,3 +51,6 @@
|
||||
return A.plane - B.plane
|
||||
else
|
||||
return A.layer - B.layer
|
||||
|
||||
/proc/cmp_login_processor_priority(datum/client_login_processor/A, datum/client_login_processor/B)
|
||||
return A.priority - B.priority
|
||||
|
||||
@@ -128,6 +128,13 @@
|
||||
continue
|
||||
GLOB.world_topic_handlers[wth.topic_key] = topic_handler_type
|
||||
|
||||
// Setup client login processors.
|
||||
for(var/processor_type in subtypesof(/datum/client_login_processor))
|
||||
var/datum/client_login_processor/CLP = new processor_type
|
||||
GLOB.client_login_processors += CLP
|
||||
// Sort them by priority, lowest first
|
||||
sortTim(GLOB.client_login_processors, /proc/cmp_login_processor_priority)
|
||||
|
||||
/* // Uncomment to debug chemical reaction list.
|
||||
/client/verb/debug_chemical_list()
|
||||
|
||||
|
||||
@@ -1554,7 +1554,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
|
||||
if(orbiting == A) //make sure we haven't started orbiting something else.
|
||||
orbiting = null
|
||||
SpinAnimation(0, 0)
|
||||
SpinAnimation(0, 0, parallel = FALSE)
|
||||
transform = cached_transform
|
||||
|
||||
|
||||
|
||||
@@ -56,3 +56,5 @@ GLOBAL_LIST_INIT(cooking_ingredients, list(RECIPE_MICROWAVE = list(), RECIPE_OVE
|
||||
GLOBAL_LIST_INIT(cooking_reagents, list(RECIPE_MICROWAVE = list(), RECIPE_OVEN = list(), RECIPE_GRILL = list(), RECIPE_CANDY = list()))
|
||||
|
||||
#define EGG_LAYING_MESSAGES list("lays an egg.", "squats down and croons.", "begins making a huge racket.", "begins clucking raucously.")
|
||||
|
||||
GLOBAL_LIST_EMPTY(client_login_processors)
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
var/medal_hub_password = null
|
||||
/// Do we want the server to kill on reboot instead of keeping the same DD session
|
||||
var/shutdown_on_reboot = FALSE
|
||||
/// Is this server a production server (Has higher security and requires 2FA)
|
||||
var/is_production = FALSE
|
||||
/// If above is true, you can run a shell command
|
||||
var/shutdown_shell_command = null
|
||||
/// 2FA backend server host
|
||||
@@ -20,6 +22,7 @@
|
||||
/datum/configuration_section/system_configuration/load_data(list/data)
|
||||
// Use the load wrappers here. That way the default isnt made 'null' if you comment out the config line
|
||||
CONFIG_LOAD_BOOL(shutdown_on_reboot, data["shutdown_on_reboot"])
|
||||
CONFIG_LOAD_BOOL(is_production, data["is_production"])
|
||||
|
||||
CONFIG_LOAD_STR(topic_key, data["communications_password"])
|
||||
CONFIG_LOAD_STR(medal_hub_address, data["medal_hub_address"])
|
||||
|
||||
@@ -54,9 +54,8 @@ SUBSYSTEM_DEF(changelog)
|
||||
/datum/controller/subsystem/changelog/proc/UpdatePlayerChangelogDate(client/C)
|
||||
if(!ss_ready)
|
||||
return // Only return here, we dont have to worry about a queue list because this will be called from ShowChangelog()
|
||||
// Technically this is only for the date but we can also do the UI button at the same time
|
||||
var/datum/preferences/P = GLOB.preferences_datums[C.ckey]
|
||||
if(P.toggles & PREFTOGGLE_UI_DARKMODE)
|
||||
|
||||
if(C.prefs.toggles & PREFTOGGLE_UI_DARKMODE)
|
||||
winset(C, "rpane.changelog", "background-color=#40628a;font-color=#ffffff;font-style=none")
|
||||
else
|
||||
winset(C, "rpane.changelog", "background-color=none;font-style=none")
|
||||
|
||||
@@ -65,7 +65,7 @@ SUBSYSTEM_DEF(jobs)
|
||||
return type_occupations[jobtype]
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/GetPlayerAltTitle(mob/new_player/player, rank)
|
||||
return player.client.prefs.GetPlayerAltTitle(GetJob(rank))
|
||||
return player.client.prefs.active_character.GetPlayerAltTitle(GetJob(rank))
|
||||
|
||||
/datum/controller/subsystem/jobs/proc/AssignRole(mob/new_player/player, rank, latejoin = 0)
|
||||
Debug("Running AR, Player: [player], Rank: [rank], LJ: [latejoin]")
|
||||
@@ -121,7 +121,7 @@ SUBSYSTEM_DEF(jobs)
|
||||
Debug("Running FOC, Job: [job], Level: [level], Flag: [flag]")
|
||||
var/list/candidates = list()
|
||||
for(var/mob/new_player/player in unassigned)
|
||||
Debug(" - Player: [player] Banned: [jobban_isbanned(player, job.title)] Old Enough: [!job.player_old_enough(player.client)] AvInPlaytime: [job.available_in_playtime(player.client)] Flag && Be Special: [flag] && [player.client.prefs.be_special] Job Department: [player.client.prefs.GetJobDepartment(job, level)] Job Flag: [job.flag] Job Department Flag = [job.department_flag]")
|
||||
Debug(" - Player: [player] Banned: [jobban_isbanned(player, job.title)] Old Enough: [!job.player_old_enough(player.client)] AvInPlaytime: [job.available_in_playtime(player.client)] Flag && Be Special: [flag] && [player.client.prefs.be_special] Job Department: [player.client.prefs.active_character.GetJobDepartment(job, level)] Job Flag: [job.flag] Job Department Flag = [job.department_flag]")
|
||||
if(jobban_isbanned(player, job.title))
|
||||
Debug("FOC isbanned failed, Player: [player]")
|
||||
continue
|
||||
@@ -140,7 +140,7 @@ SUBSYSTEM_DEF(jobs)
|
||||
if(player.mind && (job.title in player.mind.restricted_roles))
|
||||
Debug("FOC incompatbile with antagonist role, Player: [player]")
|
||||
continue
|
||||
if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
|
||||
if(player.client.prefs.active_character.GetJobDepartment(job, level) & job.flag)
|
||||
Debug("FOC pass, Player: [player], Level:[level]")
|
||||
candidates += player
|
||||
return candidates
|
||||
@@ -367,12 +367,12 @@ SUBSYSTEM_DEF(jobs)
|
||||
continue
|
||||
|
||||
// If the player wants that job on this level, then try give it to him.
|
||||
if(player.client.prefs.GetJobDepartment(job, level) & job.flag)
|
||||
if(player.client.prefs.active_character.GetJobDepartment(job, level) & job.flag)
|
||||
|
||||
// If the job isn't filled
|
||||
if((job.current_positions < job.spawn_positions) || job.spawn_positions == -1)
|
||||
Debug("DO pass, Player: [player], Level:[level], Job:[job.title]")
|
||||
Debug(" - Job Flag: [job.flag] Job Department: [player.client.prefs.GetJobDepartment(job, level)] Job Current Pos: [job.current_positions] Job Spawn Positions = [job.spawn_positions]")
|
||||
Debug(" - Job Flag: [job.flag] Job Department: [player.client.prefs.active_character.GetJobDepartment(job, level)] Job Current Pos: [job.current_positions] Job Spawn Positions = [job.spawn_positions]")
|
||||
AssignRole(player, job.title)
|
||||
unassigned -= player
|
||||
break
|
||||
@@ -380,7 +380,7 @@ SUBSYSTEM_DEF(jobs)
|
||||
// Hand out random jobs to the people who didn't get any in the last check
|
||||
// Also makes sure that they got their preference correct
|
||||
for(var/mob/new_player/player in unassigned)
|
||||
if(player.client.prefs.alternate_option == GET_RANDOM_JOB)
|
||||
if(player.client.prefs.active_character.alternate_option == GET_RANDOM_JOB)
|
||||
GiveRandomJob(player)
|
||||
|
||||
Debug("DO, Standard Check end")
|
||||
@@ -390,7 +390,7 @@ SUBSYSTEM_DEF(jobs)
|
||||
// Antags, who have to get in, come first
|
||||
for(var/mob/new_player/player in unassigned)
|
||||
if(player.mind.special_role)
|
||||
if(player.client.prefs.alternate_option != BE_ASSISTANT)
|
||||
if(player.client.prefs.active_character.alternate_option != BE_ASSISTANT)
|
||||
GiveRandomJob(player)
|
||||
if(player in unassigned)
|
||||
AssignRole(player, "Civilian")
|
||||
@@ -399,10 +399,10 @@ SUBSYSTEM_DEF(jobs)
|
||||
|
||||
// Then we assign what we can to everyone else.
|
||||
for(var/mob/new_player/player in unassigned)
|
||||
if(player.client.prefs.alternate_option == BE_ASSISTANT)
|
||||
if(player.client.prefs.active_character.alternate_option == BE_ASSISTANT)
|
||||
Debug("AC2 Assistant located, Player: [player]")
|
||||
AssignRole(player, "Civilian")
|
||||
else if(player.client.prefs.alternate_option == RETURN_TO_LOBBY)
|
||||
else if(player.client.prefs.active_character.alternate_option == RETURN_TO_LOBBY)
|
||||
player.ready = 0
|
||||
unassigned -= player
|
||||
|
||||
@@ -564,11 +564,11 @@ SUBSYSTEM_DEF(jobs)
|
||||
if(job.barred_by_disability(player.client))
|
||||
disabled++
|
||||
continue
|
||||
if(player.client.prefs.GetJobDepartment(job, 1) & job.flag)
|
||||
if(player.client.prefs.active_character.GetJobDepartment(job, 1) & job.flag)
|
||||
high++
|
||||
else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag)
|
||||
else if(player.client.prefs.active_character.GetJobDepartment(job, 2) & job.flag)
|
||||
medium++
|
||||
else if(player.client.prefs.GetJobDepartment(job, 3) & job.flag)
|
||||
else if(player.client.prefs.active_character.GetJobDepartment(job, 3) & job.flag)
|
||||
low++
|
||||
else never++ //not selected
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ SUBSYSTEM_DEF(vote)
|
||||
|
||||
/datum/controller/subsystem/vote/proc/initiate_vote(vote_type, initiator_key, code_invoked = FALSE)
|
||||
if(!mode)
|
||||
if(started_time != null && !check_rights(R_ADMIN))
|
||||
if(usr && started_time != null && !check_rights(R_ADMIN)) // Allow the game to call votes whenever. But check other callers
|
||||
var/next_allowed_time = (started_time + GLOB.configuration.vote.vote_delay)
|
||||
if(next_allowed_time > world.time)
|
||||
return 0
|
||||
|
||||
@@ -55,6 +55,10 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
|
||||
var/list/announce_beacons = list() // Particular beacons that we'll notify the relevant department when we reach
|
||||
var/special = FALSE //Event/Station Goals/Admin enabled packs
|
||||
var/special_enabled = FALSE
|
||||
/// The number of times one can order a cargo crate, before it becomes restricted. -1 for infinite
|
||||
var/order_limit = -1
|
||||
/// Number of times a crate has been ordered in a shift
|
||||
var/times_ordered = 0
|
||||
/// List of names for being done in TGUI
|
||||
var/list/ui_manifest = list()
|
||||
|
||||
@@ -200,6 +204,7 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
|
||||
containertype = /obj/structure/closet/crate
|
||||
containername = "crate"
|
||||
hidden = 1
|
||||
order_limit = 5
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////// Security ////////////////////////////////////////
|
||||
|
||||
@@ -90,13 +90,11 @@
|
||||
|
||||
/atom/movable/proc/stop_pulling()
|
||||
if(pulling)
|
||||
pulling.pulledby = null
|
||||
var/mob/living/ex_pulled = pulling
|
||||
pulling.pulledby = null
|
||||
pulling = null
|
||||
pulledby = null
|
||||
if(isliving(ex_pulled))
|
||||
var/mob/living/L = ex_pulled
|
||||
L.update_canmove()// mob gets up if it was lyng down in a chokehold
|
||||
if(!QDELETED(ex_pulled) && istype(ex_pulled))
|
||||
ex_pulled.update_canmove()// mob gets up if it was lyng down in a chokehold
|
||||
|
||||
/atom/movable/proc/check_pulling()
|
||||
if(pulling)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
secondary_enemies = CEILING((secondary_enemies_scaling * num_players()), 1)
|
||||
|
||||
for(var/mob/new_player/player in GLOB.player_list)
|
||||
if((player.mind in possible_changelings) && (player.client.prefs.species in secondary_protected_species))
|
||||
if((player.mind in possible_changelings) && (player.client.prefs.active_character.species in secondary_protected_species))
|
||||
possible_changelings -= player.mind
|
||||
|
||||
if(possible_changelings.len > 0)
|
||||
|
||||
@@ -251,7 +251,7 @@
|
||||
// Get a list of all the people who want to be the antagonist for this round, except those with incompatible species
|
||||
for(var/mob/new_player/player in players)
|
||||
if(!player.client.skip_antag)
|
||||
if((role in player.client.prefs.be_special) && !(player.client.prefs.species in protected_species))
|
||||
if((role in player.client.prefs.be_special) && !(player.client.prefs.active_character.species in protected_species))
|
||||
player_draft_log += "[player.key] had [roletext] enabled, so we are drafting them."
|
||||
candidates += player.mind
|
||||
players -= player
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
/datum/intercept_text/proc/get_suspect()
|
||||
var/list/dudes = list()
|
||||
for(var/mob/living/carbon/human/man in GLOB.player_list)
|
||||
if(man.client && man.client.prefs.nanotrasen_relation == "Opposed")
|
||||
if(man.client && man.client.prefs.active_character.nanotrasen_relation == "Opposed")
|
||||
//don't include suspects who can't possibly be the antag based on their job (no suspecting the captain of being a damned dirty tator)
|
||||
if(man.mind && man.mind.assigned_role)
|
||||
if((man.mind.assigned_role in SSticker.mode.protected_jobs) || (man.mind.assigned_role in SSticker.mode.restricted_jobs))
|
||||
|
||||
@@ -279,14 +279,6 @@
|
||||
synd_mob.equip_to_slot_or_del(U, slot_in_backpack)
|
||||
|
||||
if(synd_mob.dna.species)
|
||||
|
||||
/*
|
||||
Incase anyone ever gets the burning desire to have nukeops with randomized apperances. -- Dave
|
||||
synd_mob.gender = pick(MALE, FEMALE) // Randomized appearances for the nukeops.
|
||||
var/datum/preferences/pref = new()
|
||||
A.randomize_appearance_for(synd_mob)
|
||||
*/
|
||||
|
||||
var/race = synd_mob.dna.species.name
|
||||
|
||||
switch(race)
|
||||
|
||||
@@ -507,7 +507,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
if(SSticker.current_state == GAME_STATE_SETTING_UP)
|
||||
for(var/mob/new_player/P in GLOB.player_list)
|
||||
if(P.client && P.ready && P.mind != owner)
|
||||
if(P.client.prefs && (P.client.prefs.species == "Machine")) // Special check for species that can't be absorbed. No better solution.
|
||||
if(P.client.prefs && (P.client.prefs.active_character.species == "Machine")) // Special check for species that can't be absorbed. No better solution.
|
||||
continue
|
||||
n_p++
|
||||
else if(SSticker.current_state == GAME_STATE_PLAYING)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
secondary_enemies = CEILING((secondary_enemies_scaling * num_players()), 1)
|
||||
|
||||
for(var/mob/new_player/player in GLOB.player_list)
|
||||
if((player.mind in possible_vampires) && (player.client.prefs.species in secondary_protected_species))
|
||||
if((player.mind in possible_vampires) && (player.client.prefs.active_character.species in secondary_protected_species))
|
||||
possible_vampires -= player.mind
|
||||
|
||||
if(possible_vampires.len > 0)
|
||||
|
||||
@@ -347,9 +347,9 @@ GLOBAL_LIST_EMPTY(multiverse)
|
||||
/obj/item/multisword/proc/spawn_copy(client/C, turf/T, mob/user)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
if(duplicate_self)
|
||||
user.client.prefs.copy_to(M)
|
||||
user.client.prefs.active_character.copy_to(M)
|
||||
else
|
||||
C.prefs.copy_to(M)
|
||||
C.prefs.active_character.copy_to(M)
|
||||
M.key = C.key
|
||||
M.mind.name = user.real_name
|
||||
to_chat(M, "<B>You are an alternate version of [user.real_name] from another universe! Help [user.p_them()] accomplish [user.p_their()] goals at all costs.</B>")
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
if(!G || !G.key)
|
||||
return // Let's not steal someone's soul here
|
||||
var/mob/living/carbon/human/new_character = new(pick(GLOB.latejoin))
|
||||
G.client.prefs.copy_to(new_character)
|
||||
G.client.prefs.active_character.copy_to(new_character)
|
||||
new_character.key = G.key
|
||||
return new_character
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
var/list/prohibited_disabilities = list(DISABILITY_FLAG_BLIND, DISABILITY_FLAG_DEAF, DISABILITY_FLAG_MUTE, DISABILITY_FLAG_DIZZY)
|
||||
for(var/i = 1, i < prohibited_disabilities.len, i++)
|
||||
var/this_disability = prohibited_disabilities[i]
|
||||
if(C.prefs.disabilities & this_disability)
|
||||
if(C.prefs.active_character.disabilities & this_disability)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -173,8 +173,8 @@
|
||||
if(box && H.dna.species.speciesbox)
|
||||
box = H.dna.species.speciesbox
|
||||
|
||||
if(allow_loadout && H.client && (H.client.prefs.loadout_gear && H.client.prefs.loadout_gear.len))
|
||||
for(var/gear in H.client.prefs.loadout_gear)
|
||||
if(allow_loadout && H.client && length(H.client.prefs.active_character.loadout_gear))
|
||||
for(var/gear in H.client.prefs.active_character.loadout_gear)
|
||||
var/datum/gear/G = GLOB.gear_datums[gear]
|
||||
if(G)
|
||||
var/permitted = FALSE
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
if(gear_leftovers.len)
|
||||
for(var/datum/gear/G in gear_leftovers)
|
||||
var/atom/placed_in = H.equip_or_collect(G.spawn_item(null, H.client.prefs.loadout_gear[G.display_name]))
|
||||
var/atom/placed_in = H.equip_or_collect(G.spawn_item(null, H.client.prefs.active_character.loadout_gear[G.display_name]))
|
||||
if(istype(placed_in))
|
||||
if(isturf(placed_in))
|
||||
to_chat(H, "<span class='notice'>Placing [G.display_name] on [placed_in]!</span>")
|
||||
|
||||
@@ -25,11 +25,9 @@
|
||||
|
||||
/obj/machinery/computer/operating/New()
|
||||
..()
|
||||
for(dir in list(NORTH,EAST,SOUTH,WEST))
|
||||
table = locate(/obj/machinery/optable, get_step(src, dir))
|
||||
if(table)
|
||||
table.computer = src
|
||||
break
|
||||
table = locate(/obj/machinery/optable, orange(1, src))
|
||||
if(table)
|
||||
table.computer = src
|
||||
|
||||
/obj/machinery/computer/operating/Destroy()
|
||||
if(table)
|
||||
|
||||
@@ -462,6 +462,17 @@
|
||||
drop_computer_parts()
|
||||
return ..() // will qdel the frame
|
||||
|
||||
/obj/structure/computerframe/AltClick(mob/user)
|
||||
if(user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
|
||||
return
|
||||
if(!Adjacent(user))
|
||||
return
|
||||
if(anchored)
|
||||
to_chat(user, "<span class='warning'>The frame is anchored to the floor!</span>")
|
||||
return
|
||||
setDir(turn(dir, 90))
|
||||
|
||||
/obj/structure/computerframe/obj_break(damage_flag)
|
||||
deconstruct()
|
||||
|
||||
@@ -544,7 +555,8 @@
|
||||
if(STATE_GLASS)
|
||||
to_chat(user, "<span class='notice'>You connect the monitor.</span>")
|
||||
I.play_tool_sound(src)
|
||||
var/B = new circuit.build_path(loc)
|
||||
var/obj/machinery/computer/B = new circuit.build_path(loc)
|
||||
B.setDir(dir)
|
||||
if(istype(circuit, /obj/item/circuitboard/supplycomp))
|
||||
var/obj/machinery/computer/supplycomp/SC = B
|
||||
var/obj/item/circuitboard/supplycomp/C = circuit
|
||||
|
||||
@@ -284,11 +284,6 @@
|
||||
|
||||
/obj/machinery/suit_storage_unit/Destroy()
|
||||
SStgui.close_uis(wires)
|
||||
QDEL_NULL(suit)
|
||||
QDEL_NULL(helmet)
|
||||
QDEL_NULL(mask)
|
||||
QDEL_NULL(boots)
|
||||
QDEL_NULL(storage)
|
||||
QDEL_NULL(wires)
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -41,10 +41,7 @@
|
||||
/obj/machinery/computer/teleporter/proc/link_power_station()
|
||||
if(power_station)
|
||||
return
|
||||
for(dir in list(NORTH,EAST,SOUTH,WEST))
|
||||
power_station = locate(/obj/machinery/teleport/station, get_step(src, dir))
|
||||
if(power_station)
|
||||
break
|
||||
power_station = locate(/obj/machinery/teleport/station, orange(1, src))
|
||||
return power_station
|
||||
|
||||
/obj/machinery/computer/teleporter/attackby(obj/item/I, mob/living/user, params)
|
||||
|
||||
@@ -84,7 +84,7 @@ GLOBAL_LIST_EMPTY(splatter_cache)
|
||||
|
||||
/obj/effect/decal/cleanable/blood/drip
|
||||
name = "drips of blood"
|
||||
desc = "It's red."
|
||||
desc = "A drop of blood in an ocean of mess."
|
||||
gender = PLURAL
|
||||
icon = 'icons/effects/drip.dmi'
|
||||
icon_state = "1"
|
||||
|
||||
@@ -204,6 +204,11 @@
|
||||
duration = 8
|
||||
randomdir = FALSE
|
||||
|
||||
/obj/effect/temp_visual/mummy_animation
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "mummy_revive"
|
||||
duration = 20
|
||||
|
||||
/obj/effect/temp_visual/heal //color is white by default, set to whatever is needed
|
||||
name = "healing glow"
|
||||
icon_state = "heal"
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
else if(issilicon(M))
|
||||
add_attack_logs(user, M, "Flashed with [src]")
|
||||
if(M.flash_eyes(affect_silicon = 1))
|
||||
M.Weaken(rand(5,10))
|
||||
M.Weaken(rand(4, 6))
|
||||
user.visible_message("<span class='disarm'>[user] overloads [M]'s sensors with [src]!</span>", "<span class='danger'>You overload [M]'s sensors with [src]!</span>")
|
||||
return 1
|
||||
user.visible_message("<span class='disarm'>[user] fails to blind [M] with [src]!</span>", "<span class='warning'>You fail to blind [M] with [src]!</span>")
|
||||
|
||||
@@ -31,6 +31,115 @@
|
||||
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
|
||||
add_attack_logs(user, M, "Stunned with [src] ([uppertext(user.a_intent)])")
|
||||
|
||||
#define CYBORG_HUGS 0
|
||||
#define CYBORG_HUG 1
|
||||
#define CYBORG_SHOCK 2
|
||||
#define CYBORG_CRUSH 3
|
||||
|
||||
/obj/item/borg/cyborghug
|
||||
name = "hugging module"
|
||||
icon_state = "hugmodule"
|
||||
desc = "For when a someone really needs a hug."
|
||||
var/mode = CYBORG_HUGS //0 = Hugs 1 = "Hug" 2 = Shock 3 = CRUSH
|
||||
var/ccooldown = 0
|
||||
var/scooldown = 0
|
||||
var/shockallowed = FALSE //Can it be a stunarm when emagged. Only PK borgs get this by default.
|
||||
|
||||
/obj/item/borg/cyborghug/attack_self(mob/living/user)
|
||||
if(isrobot(user))
|
||||
var/mob/living/silicon/robot/P = user
|
||||
if(P.emagged && shockallowed)
|
||||
if(mode < CYBORG_CRUSH)
|
||||
mode++
|
||||
else
|
||||
mode = CYBORG_HUGS
|
||||
else if(mode < CYBORG_HUG)
|
||||
mode++
|
||||
else
|
||||
mode = CYBORG_HUGS
|
||||
switch(mode)
|
||||
if(CYBORG_HUGS)
|
||||
to_chat(user, "Power reset. Hugs!")
|
||||
if(CYBORG_HUG)
|
||||
to_chat(user, "Power increased!")
|
||||
if(CYBORG_SHOCK)
|
||||
to_chat(user, "BZZT. Electrifying arms...")
|
||||
if(CYBORG_CRUSH)
|
||||
to_chat(user, "ERROR: ARM ACTUATORS OVERLOADED.")
|
||||
|
||||
/obj/item/borg/cyborghug/attack(mob/living/M, mob/living/silicon/robot/user, params)
|
||||
if(M == user)
|
||||
return
|
||||
switch(mode)
|
||||
if(CYBORG_HUGS)
|
||||
if(M.health >= 0)
|
||||
if(isanimal(M))
|
||||
var/list/modifiers = params2list(params)
|
||||
M.attack_hand(user, modifiers) //This enables borgs to get the floating heart icon and mob emote from simple_animal's that have petbonus == true.
|
||||
return
|
||||
if(user.zone_selected == BODY_ZONE_HEAD)
|
||||
user.visible_message("<span class='notice'>[user] playfully boops [M] on the head!</span>", "<span class='notice'>You playfully boop [M] on the head!</span>")
|
||||
user.do_attack_animation(M, ATTACK_EFFECT_BOOP)
|
||||
playsound(loc, 'sound/weapons/tap.ogg', 50, TRUE, -1)
|
||||
else if(ishuman(M))
|
||||
if(user.lying)
|
||||
user.visible_message("<span class='notice'>[user] shakes [M] trying to get [M.p_them()] up!</span>", "<span class='notice'>You shake [M] trying to get [M.p_them()] up!</span>")
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] hugs [M] to make [M.p_them()] feel better!</span>", "<span class='notice'>You hug [M] to make [M.p_them()] feel better!</span>")
|
||||
if(M.resting)
|
||||
M.resting = FALSE
|
||||
M.update_canmove()
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] pets [M]!</span>", "<span class='notice'>You pet [M]!</span>")
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
|
||||
if(CYBORG_HUG)
|
||||
if(M.health >= 0)
|
||||
if(ishuman(M))
|
||||
if(M.lying)
|
||||
user.visible_message("<span class='notice'>[user] shakes [M] trying to get [M.p_them()] up!</span>", "<span class='notice'>You shake [M] trying to get [M.p_them()] up!</span>")
|
||||
else if(user.zone_selected == BODY_ZONE_HEAD)
|
||||
user.visible_message("<span class='warning'>[user] bops [M] on the head!</span>", "<span class='warning'>You bop [M] on the head!</span>")
|
||||
user.do_attack_animation(M, ATTACK_EFFECT_PUNCH)
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] hugs [M] in a firm bear-hug! [M] looks uncomfortable...</span>", "<span class='warning'>You hug [M] firmly to make [M.p_them()] feel better! [M] looks uncomfortable...</span>")
|
||||
if(M.resting)
|
||||
M.resting = FALSE
|
||||
M.update_canmove()
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] bops [M] on the head!</span>", "<span class='warning'>You bop [M] on the head!</span>")
|
||||
playsound(loc, 'sound/weapons/tap.ogg', 50, TRUE, -1)
|
||||
if(CYBORG_SHOCK)
|
||||
if(scooldown < world.time)
|
||||
if(M.health >= 0)
|
||||
if(ishuman(M))
|
||||
M.electrocute_act(5, "[user]", flags = SHOCK_NOGLOVES)
|
||||
user.visible_message("<span class='userdanger'>[user] electrocutes [M] with [user.p_their()] touch!</span>", "<span class='danger'>You electrocute [M] with your touch!</span>")
|
||||
else
|
||||
if(!isrobot(M))
|
||||
M.adjustFireLoss(10)
|
||||
user.visible_message("<span class='userdanger'>[user] shocks [M]!</span>", "<span class='danger'>You shock [M]!</span>")
|
||||
else
|
||||
user.visible_message("<span class='userdanger'>[user] shocks [M]. It does not seem to have an effect</span>", "<span class='danger'>You shock [M] to no effect.</span>")
|
||||
playsound(loc, 'sound/effects/sparks2.ogg', 50, TRUE, -1)
|
||||
user.cell.use(500)
|
||||
scooldown = world.time + 20
|
||||
if(CYBORG_CRUSH)
|
||||
if(ccooldown < world.time)
|
||||
if(M.health >= 0)
|
||||
if(ishuman(M))
|
||||
user.visible_message("<span class='userdanger'>[user] crushes [M] in [user.p_their()] grip!</span>", "<span class='danger'>You crush [M] in your grip!</span>")
|
||||
else
|
||||
user.visible_message("<span class='userdanger'>[user] crushes [M]!</span>", "<span class='danger'>You crush [M]!</span>")
|
||||
playsound(loc, 'sound/weapons/smash.ogg', 50, TRUE, -1)
|
||||
M.adjustBruteLoss(15)
|
||||
user.cell.use(300)
|
||||
ccooldown = world.time + 10
|
||||
|
||||
#undef CYBORG_HUGS
|
||||
#undef CYBORG_HUG
|
||||
#undef CYBORG_SHOCK
|
||||
#undef CYBORG_CRUSH
|
||||
|
||||
/obj/item/borg/overdrive
|
||||
name = "Overdrive"
|
||||
icon = 'icons/obj/decals.dmi'
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
desc = "Some sterile gauze to wrap around bloody stumps."
|
||||
icon_state = "gauze"
|
||||
origin_tech = "biotech=2"
|
||||
max_amount = 12
|
||||
heal_brute = 10
|
||||
stop_bleeding = 1800
|
||||
|
||||
@@ -169,6 +170,7 @@
|
||||
singular_name = "advanced trauma kit"
|
||||
desc = "An advanced trauma kit for severe injuries."
|
||||
icon_state = "traumakit"
|
||||
max_amount = 6
|
||||
heal_brute = 25
|
||||
stop_bleeding = 0
|
||||
|
||||
@@ -233,6 +235,7 @@
|
||||
icon = 'icons/obj/hydroponics/harvest.dmi'
|
||||
icon_state = "tea_aspera_leaves"
|
||||
color = "#378C61"
|
||||
max_amount = 6
|
||||
stop_bleeding = 0
|
||||
heal_brute = 12
|
||||
drop_sound = 'sound/misc/moist_impact.ogg'
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#define CUT_TIME 100
|
||||
#define CLIMB_TIME 150
|
||||
#define FULL_CUT_TIME 300
|
||||
|
||||
#define NO_HOLE 0 //section is intact
|
||||
#define MEDIUM_HOLE 1 //medium hole in the section - can climb through
|
||||
@@ -88,29 +89,34 @@
|
||||
. = TRUE
|
||||
if(shock(user, 100))
|
||||
return
|
||||
if(!cuttable)
|
||||
to_chat(user, "<span class='warning'>This section of the fence can't be cut!</span>")
|
||||
return
|
||||
if(invulnerable)
|
||||
to_chat(user, "<span class='warning'>This fence is too strong to cut through!</span>")
|
||||
return
|
||||
if(!cuttable)
|
||||
user.visible_message("<span class='warning'>[user] starts dismantling [src] with [W].</span>",\
|
||||
"<span class='warning'>You start dismantling [src] with [W].</span>")
|
||||
if(W.use_tool(src, user, FULL_CUT_TIME, volume = W.tool_volume))
|
||||
user.visible_message("<span class='notice'>[user] completely dismantles [src].</span>",\
|
||||
"<span class='info'>You completely dismantle [src].</span>")
|
||||
qdel(src)
|
||||
return
|
||||
var/current_stage = hole_size
|
||||
user.visible_message("<span class='danger'>\The [user] starts cutting through \the [src] with \the [W].</span>",\
|
||||
"<span class='danger'>You start cutting through \the [src] with \the [W].</span>")
|
||||
user.visible_message("<span class='warning'>[user] starts cutting through [src] with [W].</span>",\
|
||||
"<span class='warning'>You start cutting through [src] with [W].</span>")
|
||||
if(W.use_tool(src, user, CUT_TIME * W.toolspeed, volume = W.tool_volume))
|
||||
if(current_stage == hole_size)
|
||||
switch(hole_size)
|
||||
if(NO_HOLE)
|
||||
visible_message("<span class='notice'>\The [user] cuts into \the [src] some more.</span>")
|
||||
to_chat(user, "<span class='info'>You could probably fit yourself through that hole now. Although climbing through would be much faster if you made it even bigger.</span>")
|
||||
user.visible_message("<span class='notice'>[user] cuts into [src] some more.</span>",\
|
||||
"<span class='info'>You could probably fit yourself through that hole now. Although climbing through would be much faster if you made it even bigger.</span>")
|
||||
hole_size = MEDIUM_HOLE
|
||||
if(MEDIUM_HOLE)
|
||||
visible_message("<span class='notice'>\The [user] completely cuts through \the [src].</span>")
|
||||
to_chat(user, "<span class='info'>The hole in \the [src] is now big enough to walk through.</span>")
|
||||
user.visible_message("<span class='notice'>[user] completely cuts through [src].</span>",\
|
||||
"<span class='info'>The hole in [src] is now big enough to walk through.</span>")
|
||||
hole_size = LARGE_HOLE
|
||||
if(LARGE_HOLE)
|
||||
visible_message("<span class='notice'>\The [user] completely dismantles \the [src].</span>")
|
||||
to_chat(user, "<span class='info'>You completely take apart \the [src].</span>")
|
||||
user.visible_message("<span class='notice'>[user] completely dismantles [src].</span>",\
|
||||
"<span class='info'>You completely take apart [src].</span>")
|
||||
qdel(src)
|
||||
return
|
||||
update_cut_status()
|
||||
@@ -208,6 +214,7 @@
|
||||
|
||||
#undef CUT_TIME
|
||||
#undef CLIMB_TIME
|
||||
#undef FULL_CUT_TIME
|
||||
|
||||
#undef NO_HOLE
|
||||
#undef MEDIUM_HOLE
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
climbable = TRUE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
var/currently_climbed = FALSE
|
||||
var/mover_dir = null
|
||||
|
||||
/obj/structure/railing/corner //aesthetic corner sharp edges hurt oof ouch
|
||||
icon_state = "railing_corner"
|
||||
@@ -73,7 +74,11 @@
|
||||
return TRUE
|
||||
if(mover.throwing)
|
||||
return TRUE
|
||||
if(get_dir(loc, target) != dir)
|
||||
mover_dir = get_dir(loc, target)
|
||||
//Due to how the other check is done, it would always return density for ordinal directions no matter what
|
||||
if(ordinal_direction_check())
|
||||
return FALSE
|
||||
if(mover_dir != dir)
|
||||
return density
|
||||
return FALSE
|
||||
|
||||
@@ -92,10 +97,30 @@
|
||||
return TRUE
|
||||
if(currently_climbed)
|
||||
return TRUE
|
||||
if(get_dir(O.loc, target) == dir)
|
||||
mover_dir = get_dir(O.loc, target)
|
||||
if(mover_dir == dir)
|
||||
return FALSE
|
||||
if(ordinal_direction_check())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Checks if the direction the mob is trying to move towards would be blocked by a corner railing
|
||||
/obj/structure/railing/proc/ordinal_direction_check()
|
||||
switch(dir)
|
||||
if(5)
|
||||
if(mover_dir == 1 || mover_dir == 4)
|
||||
return TRUE
|
||||
if(6)
|
||||
if(mover_dir == 2 || mover_dir == 4)
|
||||
return TRUE
|
||||
if(9)
|
||||
if(mover_dir == 1 || mover_dir == 8)
|
||||
return TRUE
|
||||
if(10)
|
||||
if(mover_dir == 2 || mover_dir == 8)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/structure/railing/do_climb(mob/living/user)
|
||||
var/initial_mob_loc = get_turf(user)
|
||||
. = ..()
|
||||
@@ -112,7 +137,7 @@
|
||||
to_chat(user, "<span class='warning'>[src] cannot be rotated while it is fastened to the floor!</span>")
|
||||
return FALSE
|
||||
|
||||
var/target_dir = turn(dir, -90)
|
||||
var/target_dir = turn(dir, -45)
|
||||
|
||||
if(!valid_window_location(loc, target_dir)) //Expanded to include rails, as well!
|
||||
to_chat(user, "<span class='warning'>[src] cannot be rotated in that direction!</span>")
|
||||
@@ -133,4 +158,4 @@
|
||||
if(!Adjacent(user))
|
||||
return
|
||||
if(can_be_rotated(user))
|
||||
setDir(turn(dir, 90))
|
||||
setDir(turn(dir, 45))
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/client/verb/webmap()
|
||||
set name = "webmap"
|
||||
set hidden = TRUE
|
||||
|
||||
if(!SSmapping.map_datum.webmap_url)
|
||||
to_chat(usr, "<span class='warning'>The current map has no defined webmap. Please file an issue report.</span>")
|
||||
return
|
||||
|
||||
if(alert(usr, "Do you want to open this map's Webmap in your browser?", "Webmap", "Yes", "No") != "Yes")
|
||||
return
|
||||
|
||||
usr << link(SSmapping.map_datum.webmap_url)
|
||||
@@ -130,7 +130,7 @@ GLOBAL_VAR_INIT(nologevent, 0)
|
||||
if(GLOB.configuration.url.forum_playerinfo_url)
|
||||
body += "<A href='?_src_=holder;webtools=[M.ckey]'>WebInfo</A> | "
|
||||
if(M.client)
|
||||
if(check_watchlist(M.client.ckey))
|
||||
if(M.client.watchlisted)
|
||||
body += "<A href='?_src_=holder;watchremove=[M.ckey]'>Remove from Watchlist</A> | "
|
||||
body += "<A href='?_src_=holder;watchedit=[M.ckey]'>Edit Watchlist Reason</A> "
|
||||
else
|
||||
|
||||
@@ -667,6 +667,10 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
to_chat(src, "Error while re-adminning, admin rank ([rank]) does not exist.")
|
||||
return
|
||||
|
||||
// Do a little check here
|
||||
if(GLOB.configuration.system.is_production && (GLOB.admin_ranks[rank] & R_ADMIN) && prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
|
||||
to_chat(src,"<span class='boldannounce'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // Very fucking obvious
|
||||
return
|
||||
D = new(rank, GLOB.admin_ranks[rank], ckey)
|
||||
else
|
||||
if(!SSdbcore.IsConnected())
|
||||
@@ -697,8 +701,12 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list(
|
||||
|
||||
if(istext(flags))
|
||||
flags = text2num(flags)
|
||||
// Do a little check here
|
||||
if(GLOB.configuration.system.is_production && (flags & R_ADMIN) && prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
|
||||
to_chat(src,"<span class='boldannounce'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // Very fucking obvious
|
||||
qdel(admin_read)
|
||||
return
|
||||
D = new(admin_rank, flags, ckey)
|
||||
|
||||
qdel(admin_read)
|
||||
|
||||
var/client/C = GLOB.directory[ckey]
|
||||
|
||||
@@ -95,6 +95,24 @@ you will have to do something like if(client.holder.rights & R_ADMIN) yourself.
|
||||
to_chat(user, "<font color='red'>Error: You are not an admin.</font>")
|
||||
return 0
|
||||
|
||||
// Basically the above proc but checks at a /client level
|
||||
/proc/check_rights_client(rights_required, show_msg = TRUE, client/C)
|
||||
if(C)
|
||||
if(rights_required)
|
||||
if(C.holder)
|
||||
if(rights_required & C.holder.rights)
|
||||
return TRUE
|
||||
else
|
||||
if(show_msg)
|
||||
to_chat(C, "<font color='red'>Error: You do not have sufficient rights to do that. You require one of the following flags:[rights2text(rights_required," ")].</font>")
|
||||
else
|
||||
if(C.holder)
|
||||
return TRUE
|
||||
else
|
||||
if(show_msg)
|
||||
to_chat(C, "<font color='red'>Error: You are not an admin.</font>")
|
||||
return FALSE
|
||||
|
||||
//probably a bit iffy - will hopefully figure out a better solution
|
||||
/proc/check_if_greater_rights_than(client/other)
|
||||
if(usr && usr.client)
|
||||
|
||||
@@ -1361,7 +1361,7 @@
|
||||
to_chat(usr, "<span class='warning'>[M] doesn't seem to have an active client.</span>")
|
||||
return
|
||||
|
||||
if(M.flavor_text == "" && M.client.prefs.flavor_text == "")
|
||||
if(M.flavor_text == "" && M.client.prefs.active_character.flavor_text == "")
|
||||
to_chat(usr, "<span class='warning'>[M] has no flavor text set.</span>")
|
||||
return
|
||||
|
||||
@@ -1375,8 +1375,8 @@
|
||||
M.flavor_text = ""
|
||||
|
||||
// Clear and save the DB character's flavor text
|
||||
M.client.prefs.flavor_text = ""
|
||||
M.client.prefs.save_character(M.client)
|
||||
M.client.prefs.active_character.flavor_text = ""
|
||||
M.client.prefs.active_character.save(M.client)
|
||||
|
||||
else if(href_list["userandomname"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
@@ -1399,12 +1399,12 @@
|
||||
message_admins("[key_name_admin(usr)] has forced [key_name_admin(M)] to use a random name.")
|
||||
|
||||
// Update the mob's name with a random one straight away
|
||||
var/random_name = random_name(M.client.prefs.gender, M.client.prefs.species)
|
||||
var/random_name = random_name(M.client.prefs.active_character.gender, M.client.prefs.active_character.species)
|
||||
M.rename_character(M.real_name, random_name)
|
||||
|
||||
// Save that random name for next rounds
|
||||
M.client.prefs.real_name = random_name
|
||||
M.client.prefs.save_character(M.client)
|
||||
M.client.prefs.active_character.real_name = random_name
|
||||
M.client.prefs.active_character.save(M.client)
|
||||
|
||||
else if(href_list["asays"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
|
||||
@@ -63,9 +63,10 @@
|
||||
for(var/mob/thisplayer in players_to_spawn)
|
||||
var/mob/living/carbon/human/H = new /mob/living/carbon/human(T)
|
||||
H.name = random_name(pick(MALE,FEMALE))
|
||||
var/datum/preferences/A = new() //Randomize appearance
|
||||
A.real_name = H.name
|
||||
A.copy_to(H)
|
||||
var/datum/character_save/S = new //Randomize appearance
|
||||
S.randomise()
|
||||
S.real_name = H.name
|
||||
S.copy_to(H)
|
||||
H.dna.ready_dna(H)
|
||||
|
||||
H.mind_initialize()
|
||||
|
||||
@@ -124,9 +124,10 @@ GLOBAL_VAR_INIT(sent_syndicate_infiltration_team, 0)
|
||||
|
||||
var/syndicate_infiltrator_name = random_name(pick(MALE,FEMALE))
|
||||
|
||||
var/datum/preferences/A = new() //Randomize appearance
|
||||
A.real_name = syndicate_infiltrator_name
|
||||
A.copy_to(new_syndicate_infiltrator)
|
||||
var/datum/character_save/S = new //Randomize appearance
|
||||
S.randomise()
|
||||
S.real_name = syndicate_infiltrator_name
|
||||
S.copy_to(new_syndicate_infiltrator)
|
||||
new_syndicate_infiltrator.dna.ready_dna(new_syndicate_infiltrator)
|
||||
|
||||
//Creates mind stuff.
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
if(M.stat || !M.mind || M.mind.special_role || M.mind.offstation_role)
|
||||
return FALSE
|
||||
if(temp)
|
||||
if((M.mind.assigned_role in temp.restricted_jobs) || (M.client.prefs.species in temp.protected_species))
|
||||
if((M.mind.assigned_role in temp.restricted_jobs) || (M.client.prefs.active_character.species in temp.protected_species))
|
||||
return FALSE
|
||||
if(role) // Don't even bother evaluating if there's no role
|
||||
if(player_old_enough_antag(M.client,role) && (role in M.client.prefs.be_special) && !M.client.skip_antag && (!jobban_isbanned(M, role)))
|
||||
@@ -374,8 +374,8 @@
|
||||
//First we spawn a dude.
|
||||
var/mob/living/carbon/human/new_character = new(pick(GLOB.latejoin))//The mob being spawned.
|
||||
|
||||
var/datum/preferences/A = new(G_found.client)
|
||||
A.copy_to(new_character)
|
||||
// Then clone stuff over
|
||||
G_found.client.prefs.active_character.copy_to(new_character)
|
||||
|
||||
new_character.dna.ready_dna(new_character)
|
||||
new_character.key = G_found.key
|
||||
@@ -388,13 +388,14 @@
|
||||
var/syndicate_commando_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major")
|
||||
var/syndicate_commando_name = pick(GLOB.last_names)
|
||||
|
||||
var/datum/preferences/A = new()//Randomize appearance for the commando.
|
||||
var/datum/character_save/S = new //Randomize appearance for the commando.
|
||||
S.randomise()
|
||||
if(syndicate_leader_selected)
|
||||
A.real_name = "[syndicate_commando_leader_rank] [syndicate_commando_name]"
|
||||
A.age = rand(35,45)
|
||||
S.real_name = "[syndicate_commando_leader_rank] [syndicate_commando_name]"
|
||||
S.age = rand(35, 45)
|
||||
else
|
||||
A.real_name = "[syndicate_commando_rank] [syndicate_commando_name]"
|
||||
A.copy_to(new_syndicate_commando)
|
||||
S.real_name = "[syndicate_commando_rank] [syndicate_commando_name]"
|
||||
S.copy_to(new_syndicate_commando)
|
||||
|
||||
new_syndicate_commando.dna.ready_dna(new_syndicate_commando)//Creates DNA.
|
||||
|
||||
@@ -576,7 +577,8 @@
|
||||
if(candidates.len)
|
||||
var/teamOneMembers = 5
|
||||
var/teamTwoMembers = 5
|
||||
var/datum/preferences/A = new()
|
||||
var/datum/character_save/S = new
|
||||
S.randomise()
|
||||
for(var/thing in GLOB.landmarks_list)
|
||||
var/obj/effect/landmark/L = thing
|
||||
if(L.name == "tdome1")
|
||||
@@ -585,7 +587,7 @@
|
||||
|
||||
var/mob/living/carbon/human/newMember = new(L.loc)
|
||||
|
||||
A.copy_to(newMember)
|
||||
S.copy_to(newMember)
|
||||
|
||||
newMember.dna.ready_dna(newMember)
|
||||
|
||||
@@ -607,7 +609,7 @@
|
||||
|
||||
var/mob/living/carbon/human/newMember = new(L.loc)
|
||||
|
||||
A.copy_to(newMember)
|
||||
S.copy_to(newMember)
|
||||
|
||||
newMember.dna.ready_dna(newMember)
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
continue
|
||||
if(is_type_in_list(H.dna.species, incompatible_species))
|
||||
H.set_species(/datum/species/human)
|
||||
var/datum/preferences/A = new() // Randomize appearance
|
||||
A.copy_to(H)
|
||||
var/datum/character_save/S = new // Randomize appearance
|
||||
S.randomise()
|
||||
S.copy_to(H)
|
||||
|
||||
SSticker.mode.traitors += H.mind
|
||||
H.mind.special_role = SPECIAL_ROLE_TRAITOR
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
continue
|
||||
if(is_type_in_list(H.dna.species, incompatible_species))
|
||||
H.set_species(/datum/species/human)
|
||||
var/datum/preferences/A = new() // Randomize appearance
|
||||
A.copy_to(H)
|
||||
var/datum/character_save/S = new // Randomize appearance
|
||||
S.randomise()
|
||||
S.copy_to(H)
|
||||
|
||||
for(var/obj/item/I in H)
|
||||
if(istype(I, /obj/item/implant))
|
||||
|
||||
@@ -396,10 +396,12 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
new_character.age = record_found.fields["age"]
|
||||
new_character.dna.blood_type = record_found.fields["blood_type"]
|
||||
else
|
||||
// We make a random character
|
||||
new_character.change_gender(pick(MALE,FEMALE))
|
||||
var/datum/preferences/A = new()
|
||||
A.real_name = G_found.real_name
|
||||
A.copy_to(new_character)
|
||||
var/datum/character_save/S = new
|
||||
S.randomise()
|
||||
S.real_name = G_found.real_name
|
||||
S.copy_to(new_character)
|
||||
|
||||
if(!new_character.real_name)
|
||||
new_character.real_name = random_name(new_character.gender)
|
||||
|
||||
@@ -138,13 +138,14 @@ GLOBAL_VAR_INIT(sent_strike_team, 0)
|
||||
var/commando_leader_rank = pick("Lieutenant", "Captain", "Major")
|
||||
var/commando_name = pick(GLOB.commando_names)
|
||||
|
||||
var/datum/preferences/A = new()//Randomize appearance for the commando.
|
||||
var/datum/character_save/S = new //Randomize appearance for the commando.
|
||||
S.randomise()
|
||||
if(is_leader)
|
||||
A.age = rand(35,45)
|
||||
A.real_name = "[commando_leader_rank] [commando_name]"
|
||||
S.age = rand(35, 45)
|
||||
S.real_name = "[commando_leader_rank] [commando_name]"
|
||||
else
|
||||
A.real_name = "[commando_name]"
|
||||
A.copy_to(new_commando)
|
||||
S.real_name = "[commando_name]"
|
||||
S.copy_to(new_commando)
|
||||
|
||||
|
||||
new_commando.dna.ready_dna(new_commando)//Creates DNA.
|
||||
|
||||
@@ -104,13 +104,14 @@ GLOBAL_VAR_INIT(sent_syndicate_strike_team, 0)
|
||||
var/syndicate_commando_rank = pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant 1st Class", "Master Sergeant", "Sergeant Major")
|
||||
var/syndicate_commando_name = pick(GLOB.last_names)
|
||||
|
||||
var/datum/preferences/A = new()//Randomize appearance for the commando.
|
||||
var/datum/character_save/S = new //Randomize appearance for the commando.
|
||||
S.randomise()
|
||||
if(is_leader)
|
||||
A.age = rand(35,45)
|
||||
A.real_name = "[syndicate_commando_leader_rank] [syndicate_commando_name]"
|
||||
S.age = rand(35, 45)
|
||||
S.real_name = "[syndicate_commando_leader_rank] [syndicate_commando_name]"
|
||||
else
|
||||
A.real_name = "[syndicate_commando_rank] [syndicate_commando_name]"
|
||||
A.copy_to(new_syndicate_commando)
|
||||
S.real_name = "[syndicate_commando_rank] [syndicate_commando_name]"
|
||||
S.copy_to(new_syndicate_commando)
|
||||
|
||||
new_syndicate_commando.dna.ready_dna(new_syndicate_commando)//Creates DNA.
|
||||
|
||||
|
||||
@@ -16,8 +16,21 @@
|
||||
qdel(query_watchfind)
|
||||
return
|
||||
else
|
||||
qdel(query_watchfind)
|
||||
target_ckey = new_ckey
|
||||
if(check_watchlist(target_ckey))
|
||||
|
||||
var/already_watched = FALSE
|
||||
var/datum/db_query/query_watch = SSdbcore.NewQuery("SELECT reason FROM watch WHERE ckey=:target_ckey", list(
|
||||
"target_ckey" = target_ckey
|
||||
))
|
||||
if(!query_watch.warn_execute())
|
||||
qdel(query_watch)
|
||||
return
|
||||
if(query_watch.NextRow())
|
||||
already_watched = TRUE
|
||||
qdel(query_watch)
|
||||
|
||||
if(already_watched)
|
||||
to_chat(usr, "<span class='redtext'>[target_ckey] is already on the watchlist.</span>")
|
||||
return
|
||||
var/reason = input(usr,"Please state the reason","Reason") as message|null
|
||||
@@ -132,18 +145,3 @@
|
||||
output += "<br>[reason]<hr style='background:#000000; border:0; height:1px'>"
|
||||
usr << browse(output, "window=watchwin;size=900x500")
|
||||
qdel(query_watchlist)
|
||||
|
||||
/proc/check_watchlist(target_ckey)
|
||||
var/datum/db_query/query_watch = SSdbcore.NewQuery("SELECT reason FROM watch WHERE ckey=:target_ckey", list(
|
||||
"target_ckey" = target_ckey
|
||||
))
|
||||
if(!query_watch.warn_execute())
|
||||
qdel(query_watch)
|
||||
return
|
||||
if(query_watch.NextRow())
|
||||
var/entry = query_watch.item[1]
|
||||
qdel(query_watch)
|
||||
return entry
|
||||
else
|
||||
qdel(query_watch)
|
||||
return 0
|
||||
|
||||
@@ -16,25 +16,28 @@
|
||||
/obj/item/golem_shell/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
var/static/list/golem_shell_species_types = list(
|
||||
/obj/item/stack/sheet/metal = /datum/species/golem,
|
||||
/obj/item/stack/sheet/glass = /datum/species/golem/glass,
|
||||
/obj/item/stack/sheet/plasteel = /datum/species/golem/plasteel,
|
||||
/obj/item/stack/ore/glass = /datum/species/golem/sand,
|
||||
/obj/item/stack/sheet/mineral/sandstone = /datum/species/golem/sand,
|
||||
/obj/item/stack/sheet/mineral/plasma = /datum/species/golem/plasma,
|
||||
/obj/item/stack/sheet/mineral/diamond = /datum/species/golem/diamond,
|
||||
/obj/item/stack/sheet/mineral/gold = /datum/species/golem/gold,
|
||||
/obj/item/stack/sheet/mineral/silver = /datum/species/golem/silver,
|
||||
/obj/item/stack/sheet/mineral/uranium = /datum/species/golem/uranium,
|
||||
/obj/item/stack/sheet/mineral/bananium = /datum/species/golem/bananium,
|
||||
/obj/item/stack/sheet/mineral/tranquillite = /datum/species/golem/tranquillite,
|
||||
/obj/item/stack/sheet/mineral/titanium = /datum/species/golem/titanium,
|
||||
/obj/item/stack/sheet/mineral/plastitanium = /datum/species/golem/plastitanium,
|
||||
/obj/item/stack/sheet/mineral/abductor = /datum/species/golem/alloy,
|
||||
/obj/item/stack/sheet/wood = /datum/species/golem/wood,
|
||||
/obj/item/stack/sheet/bluespace_crystal = /datum/species/golem/bluespace,
|
||||
/obj/item/stack/sheet/mineral/adamantine = /datum/species/golem/adamantine,
|
||||
/obj/item/stack/sheet/plastic = /datum/species/golem/plastic)
|
||||
/obj/item/stack/sheet/metal = /datum/species/golem,
|
||||
/obj/item/stack/sheet/glass = /datum/species/golem/glass,
|
||||
/obj/item/stack/sheet/plasteel = /datum/species/golem/plasteel,
|
||||
/obj/item/stack/ore/glass = /datum/species/golem/sand,
|
||||
/obj/item/stack/sheet/mineral/sandstone = /datum/species/golem/sand,
|
||||
/obj/item/stack/sheet/mineral/plasma = /datum/species/golem/plasma,
|
||||
/obj/item/stack/sheet/mineral/diamond = /datum/species/golem/diamond,
|
||||
/obj/item/stack/sheet/mineral/gold = /datum/species/golem/gold,
|
||||
/obj/item/stack/sheet/mineral/silver = /datum/species/golem/silver,
|
||||
/obj/item/stack/sheet/mineral/uranium = /datum/species/golem/uranium,
|
||||
/obj/item/stack/sheet/mineral/bananium = /datum/species/golem/bananium,
|
||||
/obj/item/stack/sheet/mineral/tranquillite = /datum/species/golem/tranquillite,
|
||||
/obj/item/stack/sheet/mineral/titanium = /datum/species/golem/titanium,
|
||||
/obj/item/stack/sheet/mineral/plastitanium = /datum/species/golem/plastitanium,
|
||||
/obj/item/stack/sheet/mineral/abductor = /datum/species/golem/alloy,
|
||||
/obj/item/stack/sheet/wood = /datum/species/golem/wood,
|
||||
/obj/item/stack/sheet/bluespace_crystal = /datum/species/golem/bluespace,
|
||||
/obj/item/stack/medical/bruise_pack = /datum/species/golem/cloth,
|
||||
/obj/item/stack/medical/bruise_pack/improvised = /datum/species/golem/cloth,
|
||||
/obj/item/stack/sheet/cloth = /datum/species/golem/cloth,
|
||||
/obj/item/stack/sheet/mineral/adamantine = /datum/species/golem/adamantine,
|
||||
/obj/item/stack/sheet/plastic = /datum/species/golem/plastic)
|
||||
|
||||
if(istype(I, /obj/item/stack))
|
||||
var/obj/item/stack/O = I
|
||||
|
||||
@@ -268,8 +268,8 @@
|
||||
show_update_prompt = TRUE
|
||||
else if(byond_version == SUGGESTED_CLIENT_VERSION && byond_build < SUGGESTED_CLIENT_BUILD)
|
||||
show_update_prompt = TRUE
|
||||
// Actually sent to client much later, so it appears after MOTD.
|
||||
|
||||
// Actually sent to client much later, so it appears after MOTD.
|
||||
to_chat(src, "<span class='warning'>If the title screen is black, resources are still downloading. Please be patient until the title screen appears.</span>")
|
||||
|
||||
GLOB.directory[ckey] = src
|
||||
@@ -278,25 +278,53 @@
|
||||
if(GLOB.configuration.admin.enable_localhost_autoadmin)
|
||||
if(is_connecting_from_localhost())
|
||||
new /datum/admins("!LOCALHOST!", R_HOST, ckey) // Makes localhost rank
|
||||
|
||||
holder = GLOB.admin_datums[ckey]
|
||||
if(holder)
|
||||
GLOB.admins += src
|
||||
holder.owner = src
|
||||
|
||||
//preferences datum - also holds some persistant data for the client (because we may as well keep these datums to a minimum)
|
||||
prefs = GLOB.preferences_datums[ckey]
|
||||
if(!prefs)
|
||||
prefs = new /datum/preferences(src)
|
||||
GLOB.preferences_datums[ckey] = prefs
|
||||
log_client_to_db(tdata) // Make sure our client exists in the DB
|
||||
|
||||
// This is where we load all of the clients stuff from the DB
|
||||
if(SSdbcore.IsConnected())
|
||||
// Load in all our client data from the DB
|
||||
var/list/datum/db_query/login_queries = list() // List of queries to run for login processing
|
||||
|
||||
for(var/datum/client_login_processor/CLP as anything in GLOB.client_login_processors)
|
||||
login_queries[CLP.type] = CLP.get_query(src)
|
||||
|
||||
SSdbcore.MassExecute(login_queries, TRUE, FALSE, TRUE, FALSE) // Warn, no qdel, assoc, no log
|
||||
|
||||
// Now do fancy things with the results
|
||||
for(var/datum/client_login_processor/CLP as anything in GLOB.client_login_processors)
|
||||
CLP.process_result(login_queries[CLP.type], src)
|
||||
|
||||
QDEL_LIST_ASSOC_VAL(login_queries) // Clear out the used queries
|
||||
else
|
||||
prefs.parent = src
|
||||
// Set vars here that need to be set if the DB is offline
|
||||
|
||||
// Give blank prefs
|
||||
prefs = new /datum/preferences(src)
|
||||
prefs.character_saves = list()
|
||||
|
||||
// Random character
|
||||
prefs.character_saves += new /datum/character_save
|
||||
prefs.active_character = prefs.character_saves[1]
|
||||
|
||||
// ToS accepted
|
||||
tos_consent = TRUE
|
||||
|
||||
|
||||
prefs.last_ip = address //these are gonna be used for banning
|
||||
prefs.last_id = computer_id //these are gonna be used for banning
|
||||
if(world.byond_version >= 511 && byond_version >= 511 && prefs.clientfps)
|
||||
fps = prefs.clientfps
|
||||
fps = prefs.clientfps
|
||||
|
||||
// Check if the client has or has not accepted TOS
|
||||
check_tos_consent()
|
||||
// Log alts
|
||||
if(length(related_accounts_ip))
|
||||
log_admin("[key_name(src)] Alts by IP: [jointext(related_accounts_ip, " ")]")
|
||||
if(length(related_accounts_cid))
|
||||
log_admin("[key_name(src)] Alts by CID: [jointext(related_accounts_cid, " ")]")
|
||||
|
||||
// This has to go here to avoid issues
|
||||
// If you sleep past this point, you will get SSinput errors as well as goonchat errors
|
||||
@@ -307,11 +335,21 @@
|
||||
spawn() // Goonchat does some non-instant checks in start()
|
||||
chatOutput.start()
|
||||
|
||||
var/_2fa_alert = FALSE // This is so we can display the message where it will be seen
|
||||
if(holder)
|
||||
on_holder_add()
|
||||
add_admin_verbs()
|
||||
// Must be async because any sleeps (happen in sql queries) will break connectings clients
|
||||
INVOKE_ASYNC(src, .proc/admin_memo_output, "Show", FALSE, TRUE)
|
||||
if(GLOB.configuration.system.is_production && (holder.rights & R_ADMIN) && prefs._2fa_status == _2FA_DISABLED) // If they are an admin and their 2FA is disabled
|
||||
// No, check_rights() does not work in the above proc, because we dont have a mob yet
|
||||
_2fa_alert = TRUE
|
||||
// This also has to be manually done since no mob to use check_rights() on
|
||||
deadmin()
|
||||
verbs += /client/proc/readmin
|
||||
GLOB.deadmins += ckey
|
||||
else
|
||||
on_holder_add()
|
||||
add_admin_verbs()
|
||||
// Must be async because any sleeps (happen in sql queries) will break connectings clients
|
||||
INVOKE_ASYNC(src, .proc/admin_memo_output, "Show", FALSE, TRUE)
|
||||
|
||||
|
||||
// Forcibly enable hardware-accelerated graphics, as we need them for the lighting overlays.
|
||||
// (but turn them off first, since sometimes BYOND doesn't turn them on properly otherwise)
|
||||
@@ -320,7 +358,6 @@
|
||||
winset(src, null, "command=\".configure graphics-hwmode off\"")
|
||||
winset(src, null, "command=\".configure graphics-hwmode on\"")
|
||||
|
||||
log_client_to_db(tdata)
|
||||
. = ..() //calls mob.Login()
|
||||
|
||||
|
||||
@@ -332,7 +369,6 @@
|
||||
if(SSinput.initialized)
|
||||
set_macros()
|
||||
|
||||
donator_check()
|
||||
check_ip_intel()
|
||||
send_resources()
|
||||
|
||||
@@ -383,11 +419,12 @@
|
||||
if(world.TgsAvailable() && length(GLOB.revision_info.testmerges))
|
||||
to_chat(src, GLOB.revision_info.get_testmerge_chatmessage(TRUE))
|
||||
|
||||
INVOKE_ASYNC(src, .proc/cid_count_check)
|
||||
|
||||
if(check_rights(R_ADMIN, FALSE, mob)) // Mob is required. Dont even try without it.
|
||||
to_chat(src, "The queue server is currently [SSqueue.queue_enabled ? "<font color='green'>enabled</font>" : "<font color='disabled'>disabled</font>"], with a threshold of <b>[SSqueue.queue_threshold]</b>. This <b>[SSqueue.persist_queue ? "will" : "will not"]</b> persist through rounds.")
|
||||
|
||||
if(_2fa_alert)
|
||||
to_chat(src,"<span class='boldannounce'><big>You do not have 2FA enabled. Admin verbs will be unavailable until you have enabled 2FA.</big></span>") // Very fucking obvious
|
||||
|
||||
|
||||
/client/proc/is_connecting_from_localhost()
|
||||
var/localhost_addresses = list("127.0.0.1", "::1") // Adresses
|
||||
@@ -420,52 +457,18 @@
|
||||
return QDEL_HINT_HARDDEL_NOW
|
||||
|
||||
|
||||
/client/proc/donator_check()
|
||||
set waitfor = FALSE // This needs to run async because any sleep() inside /client/New() breaks stuff badly
|
||||
if(IsGuestKey(key))
|
||||
return
|
||||
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
|
||||
if(check_rights(R_ADMIN, 0, mob)) // Yes, the mob is required, regardless of other examples in this file, it won't work otherwise
|
||||
donator_level = DONATOR_LEVEL_MAX
|
||||
donor_loadout_points()
|
||||
return
|
||||
|
||||
//Donator stuff.
|
||||
var/datum/db_query/query_donor_select = SSdbcore.NewQuery("SELECT ckey, tier, active FROM donators WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
|
||||
if(!query_donor_select.warn_execute())
|
||||
qdel(query_donor_select)
|
||||
return
|
||||
|
||||
while(query_donor_select.NextRow())
|
||||
if(!text2num(query_donor_select.item[3]))
|
||||
// Inactive donator.
|
||||
donator_level = 0
|
||||
qdel(query_donor_select)
|
||||
return
|
||||
donator_level = text2num(query_donor_select.item[2])
|
||||
donor_loadout_points()
|
||||
break
|
||||
qdel(query_donor_select)
|
||||
|
||||
/client/proc/donor_loadout_points()
|
||||
if(donator_level > 0 && prefs)
|
||||
prefs.max_gear_slots = GLOB.configuration.general.base_loadout_points + 5
|
||||
|
||||
/client/proc/log_client_to_db(connectiontopic)
|
||||
set waitfor = FALSE // This needs to run async because any sleep() inside /client/New() breaks stuff badly
|
||||
if(IsGuestKey(key))
|
||||
return
|
||||
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, datediff(Now(),firstseen) as age FROM player WHERE ckey=:ckey", list(
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT id, datediff(Now(), firstseen) as age FROM player WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
@@ -480,67 +483,29 @@
|
||||
break
|
||||
|
||||
qdel(query)
|
||||
var/datum/db_query/query_ip = SSdbcore.NewQuery("SELECT ckey FROM player WHERE ip=:address", list(
|
||||
"address" = address
|
||||
))
|
||||
if(!query_ip.warn_execute())
|
||||
qdel(query_ip)
|
||||
return
|
||||
related_accounts_ip = list()
|
||||
while(query_ip.NextRow())
|
||||
if(ckey != query_ip.item[1])
|
||||
related_accounts_ip.Add("[query_ip.item[1]]")
|
||||
|
||||
qdel(query_ip)
|
||||
|
||||
var/datum/db_query/query_cid = SSdbcore.NewQuery("SELECT ckey FROM player WHERE computerid=:cid", list(
|
||||
"cid" = computer_id
|
||||
))
|
||||
if(!query_cid.warn_execute())
|
||||
qdel(query_cid)
|
||||
return
|
||||
|
||||
related_accounts_cid = list()
|
||||
while(query_cid.NextRow())
|
||||
if(ckey != query_cid.item[1])
|
||||
related_accounts_cid.Add("[query_cid.item[1]]")
|
||||
|
||||
qdel(query_cid)
|
||||
|
||||
var/admin_rank = "Player"
|
||||
// Admins don't get slammed by this, I guess
|
||||
if(holder)
|
||||
admin_rank = holder.rank
|
||||
// Admins don't get slammed by this, I guess
|
||||
else
|
||||
if(check_randomizer(connectiontopic))
|
||||
return
|
||||
|
||||
|
||||
//Log all the alts
|
||||
if(related_accounts_cid.len)
|
||||
log_admin("[key_name(src)] alts:[jointext(related_accounts_cid, " - ")]")
|
||||
|
||||
|
||||
var/watchreason = check_watchlist(ckey)
|
||||
if(watchreason)
|
||||
message_admins("<font color='red'><B>Notice: </B></font><font color='#EB4E00'>[key_name_admin(src)] is on the watchlist and has just connected - Reason: [watchreason]</font>")
|
||||
SSdiscord.send2discord_simple_noadmins("**\[Watchlist]** [key_name(src)] is on the watchlist and has just connected - Reason: [watchreason]")
|
||||
watchlisted = TRUE
|
||||
|
||||
|
||||
//Just the standard check to see if it's actually a number
|
||||
if(sql_id)
|
||||
//Just the standard check to see if it's actually a number
|
||||
if(istext(sql_id))
|
||||
sql_id = text2num(sql_id)
|
||||
if(!isnum(sql_id))
|
||||
return
|
||||
return // Return here because if we somehow didnt pull a number from an INT column, EVERYTHING is breaking
|
||||
|
||||
if(sql_id)
|
||||
var/client_address = address
|
||||
if(!client_address) // Localhost can sometimes have no address set
|
||||
client_address = "127.0.0.1"
|
||||
|
||||
//Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE player SET lastseen = Now(), ip=:sql_ip, computerid=:sql_cid, lastadminrank=:sql_ar WHERE id=:sql_id", list(
|
||||
var/datum/db_query/query_update = SSdbcore.NewQuery("UPDATE player SET lastseen=NOW(), ip=:sql_ip, computerid=:sql_cid, lastadminrank=:sql_ar WHERE id=:sql_id", list(
|
||||
"sql_ip" = client_address,
|
||||
"sql_cid" = computer_id,
|
||||
"sql_ar" = admin_rank,
|
||||
@@ -550,6 +515,7 @@
|
||||
if(!query_update.warn_execute())
|
||||
qdel(query_update)
|
||||
return
|
||||
|
||||
qdel(query_update)
|
||||
// After the regular update
|
||||
INVOKE_ASYNC(src, /client/.proc/get_byond_account_date, FALSE) // Async to avoid other procs in the client chain being delayed by a web request
|
||||
@@ -565,7 +531,7 @@
|
||||
qdel(query_insert)
|
||||
return
|
||||
qdel(query_insert)
|
||||
// This is their first connection instance, so TRUE here to nofiy admins
|
||||
// This is their first connection instance, so TRUE here to notify admins
|
||||
// This needs to happen here to ensure they actually have a row to update
|
||||
INVOKE_ASYNC(src, /client/.proc/get_byond_account_date, TRUE) // Async to avoid other procs in the client chain being delayed by a web request
|
||||
|
||||
@@ -868,6 +834,7 @@
|
||||
winset(src, "rpane.forumb", "background-color=#40628a;text-color=#FFFFFF")
|
||||
winset(src, "rpane.rulesb", "background-color=#40628a;text-color=#FFFFFF")
|
||||
winset(src, "rpane.githubb", "background-color=#40628a;text-color=#FFFFFF")
|
||||
winset(src, "rpane.webmap", "background-color=#40628a;text-color=#FFFFFF")
|
||||
/* Mainwindow */
|
||||
winset(src, "mainwindow.saybutton", "background-color=#40628a;text-color=#FFFFFF")
|
||||
winset(src, "mainwindow.mebutton", "background-color=#40628a;text-color=#FFFFFF")
|
||||
@@ -900,6 +867,7 @@
|
||||
winset(src, "rpane.forumb", "background-color=none;text-color=#000000")
|
||||
winset(src, "rpane.rulesb", "background-color=none;text-color=#000000")
|
||||
winset(src, "rpane.githubb", "background-color=none;text-color=#000000")
|
||||
winset(src, "rpane.webmap", "background-color=none;text-color=#000000")
|
||||
/* Mainwindow */
|
||||
winset(src, "mainwindow.saybutton", "background-color=none;text-color=#000000")
|
||||
winset(src, "mainwindow.mebutton", "background-color=none;text-color=#000000")
|
||||
@@ -1051,7 +1019,7 @@
|
||||
|
||||
qdel(query_date)
|
||||
|
||||
// They have a date, lets bail
|
||||
// They have a date already, lets bail
|
||||
if(byondacc_date)
|
||||
return
|
||||
|
||||
@@ -1092,120 +1060,6 @@
|
||||
/client/proc/show_update_notice()
|
||||
to_chat(src, "<span class='userdanger'>Your BYOND client (v: [byond_version].[byond_build]) is out of date. This can cause glitches. We highly suggest you download the latest client from <a href='https://www.byond.com/download/'>byond.com</a> before playing. You can also update via the BYOND launcher application.</span>")
|
||||
|
||||
/**
|
||||
* Checks if the client has accepted TOS
|
||||
*
|
||||
* Runs some checks against vars and the DB to see if the client has accepted TOS.
|
||||
* Returns TRUE or FALSE if they have or have not
|
||||
*/
|
||||
/client/proc/check_tos_consent()
|
||||
// If there is no TOS, auto accept
|
||||
if(!GLOB.join_tos)
|
||||
tos_consent = TRUE
|
||||
return TRUE
|
||||
|
||||
// If theres no DB, assume yes
|
||||
if(!SSdbcore.IsConnected())
|
||||
tos_consent = TRUE
|
||||
return TRUE
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM privacy WHERE ckey=:ckey AND consent=1", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query.warn_execute())
|
||||
qdel(query)
|
||||
// If our query failed, just assume yes
|
||||
tos_consent = TRUE
|
||||
return TRUE
|
||||
|
||||
// If we returned a row, they accepted
|
||||
while(query.NextRow())
|
||||
qdel(query)
|
||||
tos_consent = TRUE
|
||||
return TRUE
|
||||
|
||||
qdel(query)
|
||||
// If we are here, they have not accepted, and need to read it
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Checks if the client has more than a configured amount of CIDs tied to them in the past
|
||||
*/
|
||||
/client/proc/cid_count_check()
|
||||
// If the config is 0, disable this
|
||||
if(GLOB.configuration.general.max_client_cid_history == 0)
|
||||
return
|
||||
|
||||
// If we have no DB, dont even bother
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
|
||||
// Now query how many cids they have
|
||||
var/datum/db_query/query_cidcheck = SSdbcore.NewQuery("SELECT COUNT(DISTINCT computerID) FROM connection_log WHERE ckey=:ckey", list(
|
||||
"ckey" = ckey
|
||||
))
|
||||
if(!query_cidcheck.warn_execute())
|
||||
qdel(query_cidcheck)
|
||||
return
|
||||
|
||||
var/cidcount = 0
|
||||
if(query_cidcheck.NextRow())
|
||||
cidcount = query_cidcheck.item[1]
|
||||
qdel(query_cidcheck)
|
||||
|
||||
if(cidcount > GLOB.configuration.general.max_client_cid_history)
|
||||
// Check their notes for CID tracking in the past
|
||||
var/has_note = FALSE
|
||||
var/note_text = ""
|
||||
var/datum/db_query/query_find_track_note = SSdbcore.NewQuery("SELECT notetext FROM notes WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
"ckey" = ckey,
|
||||
"ackey" = CIDTRACKING_PSUEDO_CKEY
|
||||
))
|
||||
if(!query_find_track_note.warn_execute())
|
||||
qdel(query_find_track_note)
|
||||
return
|
||||
if(query_find_track_note.NextRow())
|
||||
note_text = query_find_track_note.item[1] // Grab existing note text
|
||||
has_note = TRUE
|
||||
qdel(query_find_track_note)
|
||||
|
||||
|
||||
if(has_note) // They have a note. Update it.
|
||||
var/new_text = "Connected on the date of this note with unique CID #[cidcount]"
|
||||
// Only update the note if the text is different. Otherwise it bumps the timestamp when it shouldnt
|
||||
if(note_text != new_text)
|
||||
var/datum/db_query/query_update_track_note = SSdbcore.NewQuery("UPDATE notes SET notetext=:notetext, timestamp=NOW(), round_id=:rid WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
"notetext" = new_text,
|
||||
"ckey" = ckey,
|
||||
"ackey" = CIDTRACKING_PSUEDO_CKEY,
|
||||
"rid" = GLOB.round_id
|
||||
))
|
||||
if(!query_update_track_note.warn_execute())
|
||||
qdel(query_update_track_note)
|
||||
return
|
||||
qdel(query_update_track_note)
|
||||
|
||||
else // They dont have a note. Make one.
|
||||
// NOT logged because its automatic and will spam logs otherwise
|
||||
// Also right checking must be disabled because its a psuedockey, not a real one
|
||||
add_note(ckey, "Connected on the date of this note with unique CID #[cidcount]", adminckey = CIDTRACKING_PSUEDO_CKEY, logged = FALSE, checkrights = FALSE, automated = TRUE)
|
||||
|
||||
var/show_warning = TRUE
|
||||
// Check if they have a note that matches the warning suppressor
|
||||
var/datum/db_query/query_find_note = SSdbcore.NewQuery("SELECT id FROM notes WHERE ckey=:ckey AND notetext=:notetext", list(
|
||||
"ckey" = ckey,
|
||||
"notetext" = CIDWARNING_SUPPRESSED_NOTETEXT
|
||||
))
|
||||
if(!query_find_note.warn_execute())
|
||||
qdel(query_find_note)
|
||||
return
|
||||
if(query_find_note.NextRow())
|
||||
show_warning = FALSE
|
||||
qdel(query_find_note)
|
||||
|
||||
if(show_warning)
|
||||
message_admins("<font color='red'>[ckey] has just connected and has a history of [cidcount] different CIDs.</font> (<a href='?_src_=holder;webtools=[ckey]'>WebInfo</a>) (<a href='?_src_=holder;suppresscidwarning=[ckey]'>Suppress Warning</a>)")
|
||||
|
||||
/client/proc/update_ambience_pref()
|
||||
if(prefs.sound & SOUND_AMBIENCE)
|
||||
if(SSambience.ambience_listening_clients[src] > world.time)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/datum/client_login_processor/load_preferences
|
||||
priority = 10
|
||||
|
||||
/datum/client_login_processor/load_preferences/get_query(client/C)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"SELECT
|
||||
ooccolor,
|
||||
UI_style,
|
||||
UI_style_color,
|
||||
UI_style_alpha,
|
||||
be_role,
|
||||
default_slot,
|
||||
toggles,
|
||||
toggles_2,
|
||||
sound,
|
||||
volume_mixer,
|
||||
lastchangelog,
|
||||
exp,
|
||||
clientfps,
|
||||
atklog,
|
||||
fuid,
|
||||
parallax,
|
||||
2fa_status
|
||||
FROM player
|
||||
WHERE ckey=:ckey"}, list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
|
||||
return query
|
||||
|
||||
/datum/client_login_processor/load_preferences/process_result(datum/db_query/Q, client/C)
|
||||
C.prefs = new /datum/preferences(C, Q)
|
||||
@@ -0,0 +1,102 @@
|
||||
/datum/client_login_processor/load_characters
|
||||
priority = 20
|
||||
|
||||
/datum/client_login_processor/load_characters/get_query(client/C)
|
||||
// Get all their characters
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"SELECT
|
||||
OOC_Notes,
|
||||
real_name,
|
||||
name_is_always_random,
|
||||
gender,
|
||||
age,
|
||||
species,
|
||||
language,
|
||||
hair_colour,
|
||||
secondary_hair_colour,
|
||||
facial_hair_colour,
|
||||
secondary_facial_hair_colour,
|
||||
skin_tone,
|
||||
skin_colour,
|
||||
marking_colours,
|
||||
head_accessory_colour,
|
||||
hair_style_name,
|
||||
facial_style_name,
|
||||
marking_styles,
|
||||
head_accessory_style_name,
|
||||
alt_head_name,
|
||||
eye_colour,
|
||||
underwear,
|
||||
undershirt,
|
||||
backbag,
|
||||
b_type,
|
||||
alternate_option,
|
||||
job_support_high,
|
||||
job_support_med,
|
||||
job_support_low,
|
||||
job_medsci_high,
|
||||
job_medsci_med,
|
||||
job_medsci_low,
|
||||
job_engsec_high,
|
||||
job_engsec_med,
|
||||
job_engsec_low,
|
||||
job_karma_high,
|
||||
job_karma_med,
|
||||
job_karma_low,
|
||||
flavor_text,
|
||||
med_record,
|
||||
sec_record,
|
||||
gen_record,
|
||||
disabilities,
|
||||
player_alt_titles,
|
||||
organ_data,
|
||||
rlimb_data,
|
||||
nanotrasen_relation,
|
||||
speciesprefs,
|
||||
socks,
|
||||
body_accessory,
|
||||
gear,
|
||||
autohiss,
|
||||
slot
|
||||
FROM characters WHERE ckey=:ckey"}, list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
|
||||
return query
|
||||
|
||||
/datum/client_login_processor/load_characters/process_result(datum/db_query/Q, client/C)
|
||||
// If we already loaded their characters, dont do it all again
|
||||
if(C.prefs.characters_loaded)
|
||||
return
|
||||
// Step one, initialize their list of characters
|
||||
C.prefs.character_saves = list()
|
||||
C.prefs.character_saves.len = C.prefs.max_save_slots // Fill the list with empty indexes
|
||||
// Fill it with blank characters first
|
||||
for(var/i in 1 to C.prefs.max_save_slots)
|
||||
var/datum/character_save/CS = new
|
||||
CS.slot_number = i
|
||||
C.prefs.character_saves[i] = CS
|
||||
|
||||
// Did we load at all
|
||||
var/character_loaded = FALSE
|
||||
|
||||
while(Q.NextRow())
|
||||
character_loaded = TRUE
|
||||
var/datum/character_save/CS = C.prefs.character_saves[Q.item[53]] // Get the slot referenced by this query
|
||||
CS.load(Q) // Let the save handle the query processing
|
||||
CS.valid_save = TRUE
|
||||
|
||||
if(character_loaded)
|
||||
// They have a character, set their active as their default slot
|
||||
C.prefs.active_character = C.prefs.character_saves[C.prefs.default_slot]
|
||||
else
|
||||
// If we are here, they dont have a character. Lets make them a random one
|
||||
var/datum/character_save/CS = C.prefs.character_saves[1] // Get slot 1
|
||||
CS.randomise()
|
||||
CS.real_name = random_name(CS.gender) // Pick a name
|
||||
CS.valid_save = TRUE
|
||||
CS.save(C)
|
||||
C.prefs.active_character = C.prefs.character_saves[1] // Set slot 1 as their active
|
||||
C.prefs.default_slot = 1
|
||||
C.prefs.save_preferences(C)
|
||||
|
||||
C.prefs.characters_loaded = TRUE // Avoid this happening again
|
||||
@@ -0,0 +1,24 @@
|
||||
/datum/client_login_processor/tos_consent
|
||||
priority = 30
|
||||
|
||||
/datum/client_login_processor/tos_consent/get_query(client/C)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM privacy WHERE ckey=:ckey AND consent=1", list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
return query
|
||||
|
||||
/datum/client_login_processor/tos_consent/process_result(datum/db_query/Q, client/C)
|
||||
// If there is no TOS, auto accept
|
||||
if(!GLOB.join_tos)
|
||||
C.tos_consent = TRUE
|
||||
return
|
||||
|
||||
// If our query failed, just assume yes
|
||||
if(Q.last_error)
|
||||
C.tos_consent = TRUE
|
||||
return
|
||||
|
||||
// If we returned a row, they accepted
|
||||
while(Q.NextRow())
|
||||
C.tos_consent = TRUE
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/datum/client_login_processor/donator_check
|
||||
priority = 35
|
||||
|
||||
/datum/client_login_processor/donator_check/get_query(client/C)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey, tier, active FROM donators WHERE ckey=:ckey", list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
return query
|
||||
|
||||
/datum/client_login_processor/donator_check/process_result(datum/db_query/Q, client/C)
|
||||
if(IsGuestKey(C.key))
|
||||
return
|
||||
|
||||
// Admins get all donor perks
|
||||
if(check_rights_client(R_ADMIN, FALSE, C))
|
||||
C.donator_level = DONATOR_LEVEL_MAX
|
||||
C.donor_loadout_points()
|
||||
return
|
||||
|
||||
while(Q.NextRow())
|
||||
if(!text2num(Q.item[3]))
|
||||
// Inactive donator.
|
||||
C.donator_level = 0
|
||||
return
|
||||
|
||||
C.donator_level = text2num(Q.item[2])
|
||||
C.donor_loadout_points()
|
||||
@@ -0,0 +1,15 @@
|
||||
/datum/client_login_processor/watchlist
|
||||
priority = 36
|
||||
|
||||
/datum/client_login_processor/watchlist/get_query(client/C)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT reason FROM watch WHERE ckey=:ckey", list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
return query
|
||||
|
||||
/datum/client_login_processor/watchlist/process_result(datum/db_query/Q, client/C)
|
||||
if(Q.NextRow())
|
||||
var/watchreason = Q.item[1]
|
||||
message_admins("<font color='red'><B>Notice: </B></font><font color='#EB4E00'>[key_name_admin(C)] is on the watchlist and has just connected - Reason: [watchreason]</font>")
|
||||
SSdiscord.send2discord_simple_noadmins("**\[Watchlist]** [key_name(C)] is on the watchlist and has just connected - Reason: [watchreason]")
|
||||
C.watchlisted = TRUE
|
||||
@@ -0,0 +1,14 @@
|
||||
/datum/client_login_processor/alts_ip
|
||||
priority = 37
|
||||
|
||||
/datum/client_login_processor/alts_ip/get_query(client/C)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM player WHERE ip=:address", list(
|
||||
"address" = C.address
|
||||
))
|
||||
return query
|
||||
|
||||
/datum/client_login_processor/alts_ip/process_result(datum/db_query/Q, client/C)
|
||||
while(Q.NextRow())
|
||||
if("[Q.item[1]]" == C.ckey)
|
||||
continue
|
||||
C.related_accounts_ip += "[Q.item[1]]"
|
||||
@@ -0,0 +1,14 @@
|
||||
/datum/client_login_processor/alts_cid
|
||||
priority = 38
|
||||
|
||||
/datum/client_login_processor/alts_cid/get_query(client/C)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT ckey FROM player WHERE computerid=:cid", list(
|
||||
"cid" = C.computer_id
|
||||
))
|
||||
return query
|
||||
|
||||
/datum/client_login_processor/alts_cid/process_result(datum/db_query/Q, client/C)
|
||||
while(Q.NextRow())
|
||||
if("[Q.item[1]]" == C.ckey)
|
||||
continue
|
||||
C.related_accounts_cid += "[Q.item[1]]"
|
||||
@@ -0,0 +1,71 @@
|
||||
/datum/client_login_processor/cid_count
|
||||
priority = 39
|
||||
|
||||
/datum/client_login_processor/cid_count/get_query(client/C)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT COUNT(DISTINCT computerID) FROM connection_log WHERE ckey=:ckey", list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
return query
|
||||
|
||||
/datum/client_login_processor/cid_count/process_result(datum/db_query/Q, client/C)
|
||||
// If the config is 0, disable this
|
||||
if(GLOB.configuration.general.max_client_cid_history == 0)
|
||||
return
|
||||
|
||||
// Now query how many cids they have
|
||||
var/cidcount = 0
|
||||
if(Q.NextRow())
|
||||
cidcount = Q.item[1]
|
||||
|
||||
if(cidcount > GLOB.configuration.general.max_client_cid_history)
|
||||
// Check their notes for CID tracking in the past
|
||||
var/has_note = FALSE
|
||||
var/note_text = ""
|
||||
var/datum/db_query/query_find_track_note = SSdbcore.NewQuery("SELECT notetext FROM notes WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
"ckey" = C.ckey,
|
||||
"ackey" = CIDTRACKING_PSUEDO_CKEY
|
||||
))
|
||||
if(!query_find_track_note.warn_execute())
|
||||
qdel(query_find_track_note)
|
||||
return
|
||||
if(query_find_track_note.NextRow())
|
||||
note_text = query_find_track_note.item[1] // Grab existing note text
|
||||
has_note = TRUE
|
||||
qdel(query_find_track_note)
|
||||
|
||||
|
||||
if(has_note) // They have a note. Update it.
|
||||
var/new_text = "Connected on the date of this note with unique CID #[cidcount]"
|
||||
// Only update the note if the text is different. Otherwise it bumps the timestamp when it shouldnt
|
||||
if(note_text != new_text)
|
||||
var/datum/db_query/query_update_track_note = SSdbcore.NewQuery("UPDATE notes SET notetext=:notetext, timestamp=NOW(), round_id=:rid WHERE ckey=:ckey AND adminckey=:ackey", list(
|
||||
"notetext" = new_text,
|
||||
"ckey" = C.ckey,
|
||||
"ackey" = CIDTRACKING_PSUEDO_CKEY,
|
||||
"rid" = GLOB.round_id
|
||||
))
|
||||
if(!query_update_track_note.warn_execute())
|
||||
qdel(query_update_track_note)
|
||||
return
|
||||
qdel(query_update_track_note)
|
||||
|
||||
else // They dont have a note. Make one.
|
||||
// NOT logged because its automatic and will spam logs otherwise
|
||||
// Also right checking must be disabled because its a psuedockey, not a real one
|
||||
add_note(C.ckey, "Connected on the date of this note with unique CID #[cidcount]", adminckey = CIDTRACKING_PSUEDO_CKEY, logged = FALSE, checkrights = FALSE, automated = TRUE)
|
||||
|
||||
var/show_warning = TRUE
|
||||
// Check if they have a note that matches the warning suppressor
|
||||
var/datum/db_query/query_find_note = SSdbcore.NewQuery("SELECT id FROM notes WHERE ckey=:ckey AND notetext=:notetext", list(
|
||||
"ckey" = C.ckey,
|
||||
"notetext" = CIDWARNING_SUPPRESSED_NOTETEXT
|
||||
))
|
||||
if(!query_find_note.warn_execute())
|
||||
qdel(query_find_note)
|
||||
return
|
||||
if(query_find_note.NextRow())
|
||||
show_warning = FALSE
|
||||
qdel(query_find_note)
|
||||
|
||||
if(show_warning)
|
||||
message_admins("<font color='red'>[C.ckey] has just connected and has a history of [cidcount] different CIDs.</font> (<a href='?_src_=holder;webtools=[C.ckey]'>WebInfo</a>) (<a href='?_src_=holder;suppresscidwarning=[C.ckey]'>Suppress Warning</a>)")
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* # Client Login Processor Framework
|
||||
*
|
||||
* The holder class for all client data processing
|
||||
*
|
||||
* This framework is designed for loading in client data from the database.
|
||||
* Login processors have their own queries, which will be put into one async batch and
|
||||
* executed at the same time, to reduce the time it takes for a client to login.
|
||||
* Login processors can also be given priorities to have things fire in specific orders
|
||||
* EG: Load their preferences before their job bans, etc etc
|
||||
*
|
||||
* When creating these, please name the files with the priority at the start, and the typepath after
|
||||
* EG: 10-load_preferences.dm
|
||||
* This makes it easier to track stuff down -AA07
|
||||
*
|
||||
* Also if you have used other languages before with "interface" types (Java, C# (Microsoft Java), etc),
|
||||
* treat this class as one of those. [get_query(client/C)] and [process_result(datum/db_query/Q, client/C)] MUST be overriden
|
||||
*/
|
||||
/datum/client_login_processor
|
||||
/// The login priority. A lower priority will fire first
|
||||
var/priority = 0
|
||||
|
||||
/**
|
||||
* Query Getter
|
||||
*
|
||||
* Gets the DB query for this login processor
|
||||
*
|
||||
* Takes the client as an arg instead of just the ckey incase we need more data (IP, CID, etc).
|
||||
* Returns a DB query datum.
|
||||
*
|
||||
* Arguments:
|
||||
* * C - The client to use to generate the query
|
||||
*/
|
||||
/datum/client_login_processor/proc/get_query(client/C)
|
||||
RETURN_TYPE(/datum/db_query)
|
||||
CRASH("get_query() not overriden for [type]!")
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Result Processor
|
||||
*
|
||||
* Takes the (now executed) query and the client and parses the required data out
|
||||
* Note: This can be a no-op if you want to just update the DB, just return on the override
|
||||
*
|
||||
* Arguments:
|
||||
* * Q - The DB query to process data from
|
||||
* * C - The client to store stuff on
|
||||
*/
|
||||
/datum/client_login_processor/proc/process_result(datum/db_query/Q, client/C)
|
||||
CRASH("process_result() not overriden for [type]!")
|
||||
@@ -1,32 +1,6 @@
|
||||
/datum/preferences/proc/load_preferences(client/C)
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"SELECT
|
||||
ooccolor,
|
||||
UI_style,
|
||||
UI_style_color,
|
||||
UI_style_alpha,
|
||||
be_role,
|
||||
default_slot,
|
||||
toggles,
|
||||
toggles_2,
|
||||
sound,
|
||||
volume_mixer,
|
||||
lastchangelog,
|
||||
exp,
|
||||
clientfps,
|
||||
atklog,
|
||||
fuid,
|
||||
parallax,
|
||||
2fa_status
|
||||
FROM player
|
||||
WHERE ckey=:ckey"}, list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
|
||||
if(!query.warn_execute())
|
||||
qdel(query)
|
||||
return
|
||||
|
||||
/datum/preferences/proc/load_preferences(datum/db_query/query)
|
||||
// Looking for the query?
|
||||
// Check ../login_processing/10-load_preferences.dm
|
||||
|
||||
//general preferences
|
||||
while(query.NextRow())
|
||||
@@ -48,8 +22,6 @@
|
||||
parallax = text2num(query.item[16])
|
||||
_2fa_status = query.item[17]
|
||||
|
||||
qdel(query)
|
||||
|
||||
//Sanitize
|
||||
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
|
||||
UI_style = sanitize_inlist(UI_style, list("White", "Midnight", "Plasmafire", "Retro", "Slimecore", "Operative"), initial(UI_style))
|
||||
@@ -65,7 +37,7 @@
|
||||
atklog = sanitize_integer(atklog, 0, 100, initial(atklog))
|
||||
fuid = sanitize_integer(fuid, 0, 10000000, initial(fuid))
|
||||
parallax = sanitize_integer(parallax, 0, 16, initial(parallax))
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/preferences/proc/save_preferences(client/C)
|
||||
|
||||
@@ -126,550 +98,23 @@
|
||||
qdel(query)
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/load_character(client/C, slot)
|
||||
saved = FALSE
|
||||
|
||||
if(!slot)
|
||||
slot = default_slot
|
||||
slot = sanitize_integer(slot, 1, max_save_slots, initial(default_slot))
|
||||
if(slot != default_slot)
|
||||
default_slot = slot
|
||||
var/datum/db_query/firstquery = SSdbcore.NewQuery("UPDATE player SET default_slot=:slot WHERE ckey=:ckey", list(
|
||||
"slot" = slot,
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
if(!firstquery.warn_execute(async = FALSE)) // Dont make this async. It makes roundstart slow.
|
||||
qdel(firstquery)
|
||||
return
|
||||
qdel(firstquery)
|
||||
|
||||
if(!C) // If the client disconnected during the query, try again later.
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
// Let's not have this explode if you sneeze on the DB
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"SELECT
|
||||
OOC_Notes,
|
||||
real_name,
|
||||
name_is_always_random,
|
||||
gender,
|
||||
age,
|
||||
species,
|
||||
language,
|
||||
hair_colour,
|
||||
secondary_hair_colour,
|
||||
facial_hair_colour,
|
||||
secondary_facial_hair_colour,
|
||||
skin_tone,
|
||||
skin_colour,
|
||||
marking_colours,
|
||||
head_accessory_colour,
|
||||
hair_style_name,
|
||||
facial_style_name,
|
||||
marking_styles,
|
||||
head_accessory_style_name,
|
||||
alt_head_name,
|
||||
eye_colour,
|
||||
underwear,
|
||||
undershirt,
|
||||
backbag,
|
||||
b_type,
|
||||
alternate_option,
|
||||
job_support_high,
|
||||
job_support_med,
|
||||
job_support_low,
|
||||
job_medsci_high,
|
||||
job_medsci_med,
|
||||
job_medsci_low,
|
||||
job_engsec_high,
|
||||
job_engsec_med,
|
||||
job_engsec_low,
|
||||
job_karma_high,
|
||||
job_karma_med,
|
||||
job_karma_low,
|
||||
flavor_text,
|
||||
med_record,
|
||||
sec_record,
|
||||
gen_record,
|
||||
disabilities,
|
||||
player_alt_titles,
|
||||
organ_data,
|
||||
rlimb_data,
|
||||
nanotrasen_relation,
|
||||
speciesprefs,
|
||||
socks,
|
||||
body_accessory,
|
||||
gear,
|
||||
autohiss
|
||||
FROM characters WHERE ckey=:ckey AND slot=:slot"}, list(
|
||||
"ckey" = C.ckey,
|
||||
"slot" = slot
|
||||
))
|
||||
if(!query.warn_execute(async = FALSE)) // Dont make this async. It makes roundstart slow.
|
||||
qdel(query)
|
||||
return
|
||||
|
||||
while(query.NextRow())
|
||||
//Character
|
||||
metadata = query.item[1]
|
||||
real_name = query.item[2]
|
||||
be_random_name = text2num(query.item[3])
|
||||
gender = query.item[4]
|
||||
age = text2num(query.item[5])
|
||||
species = query.item[6]
|
||||
language = query.item[7]
|
||||
|
||||
h_colour = query.item[8]
|
||||
h_sec_colour = query.item[9]
|
||||
f_colour = query.item[10]
|
||||
f_sec_colour = query.item[11]
|
||||
s_tone = text2num(query.item[12])
|
||||
s_colour = query.item[13]
|
||||
m_colours = params2list(query.item[14])
|
||||
hacc_colour = query.item[15]
|
||||
h_style = query.item[16]
|
||||
f_style = query.item[17]
|
||||
m_styles = params2list(query.item[18])
|
||||
ha_style = query.item[19]
|
||||
alt_head = query.item[20]
|
||||
e_colour = query.item[21]
|
||||
underwear = query.item[22]
|
||||
undershirt = query.item[23]
|
||||
backbag = query.item[24]
|
||||
b_type = query.item[25]
|
||||
|
||||
|
||||
//Jobs
|
||||
alternate_option = text2num(query.item[26])
|
||||
job_support_high = text2num(query.item[27])
|
||||
job_support_med = text2num(query.item[28])
|
||||
job_support_low = text2num(query.item[29])
|
||||
job_medsci_high = text2num(query.item[30])
|
||||
job_medsci_med = text2num(query.item[31])
|
||||
job_medsci_low = text2num(query.item[32])
|
||||
job_engsec_high = text2num(query.item[33])
|
||||
job_engsec_med = text2num(query.item[34])
|
||||
job_engsec_low = text2num(query.item[35])
|
||||
job_karma_high = text2num(query.item[36])
|
||||
job_karma_med = text2num(query.item[37])
|
||||
job_karma_low = text2num(query.item[38])
|
||||
|
||||
//Miscellaneous
|
||||
flavor_text = query.item[39]
|
||||
med_record = query.item[40]
|
||||
sec_record = query.item[41]
|
||||
gen_record = query.item[42]
|
||||
// Apparently, the preceding vars weren't always encoded properly...
|
||||
if(findtext(flavor_text, "<")) // ... so let's clumsily check for tags!
|
||||
flavor_text = html_encode(flavor_text)
|
||||
if(findtext(med_record, "<"))
|
||||
med_record = html_encode(med_record)
|
||||
if(findtext(sec_record, "<"))
|
||||
sec_record = html_encode(sec_record)
|
||||
if(findtext(gen_record, "<"))
|
||||
gen_record = html_encode(gen_record)
|
||||
disabilities = text2num(query.item[43])
|
||||
player_alt_titles = params2list(query.item[44])
|
||||
organ_data = params2list(query.item[45])
|
||||
rlimb_data = params2list(query.item[46])
|
||||
nanotrasen_relation = query.item[47]
|
||||
speciesprefs = text2num(query.item[48])
|
||||
|
||||
//socks
|
||||
socks = query.item[49]
|
||||
body_accessory = query.item[50]
|
||||
loadout_gear = params2list(query.item[51])
|
||||
autohiss_mode = text2num(query.item[52])
|
||||
|
||||
saved = TRUE
|
||||
|
||||
qdel(query)
|
||||
//Sanitize
|
||||
var/datum/species/SP = GLOB.all_species[species]
|
||||
metadata = sanitize_text(metadata, initial(metadata))
|
||||
real_name = reject_bad_name(real_name, 1)
|
||||
if(isnull(species)) species = "Human"
|
||||
if(isnull(language)) language = "None"
|
||||
if(isnull(nanotrasen_relation)) nanotrasen_relation = initial(nanotrasen_relation)
|
||||
if(isnull(speciesprefs)) speciesprefs = initial(speciesprefs)
|
||||
if(!real_name) real_name = random_name(gender,species)
|
||||
be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name))
|
||||
gender = sanitize_gender(gender, FALSE, !SP.has_gender)
|
||||
age = sanitize_integer(age, AGE_MIN, AGE_MAX, initial(age))
|
||||
h_colour = sanitize_hexcolor(h_colour)
|
||||
h_sec_colour = sanitize_hexcolor(h_sec_colour)
|
||||
f_colour = sanitize_hexcolor(f_colour)
|
||||
f_sec_colour = sanitize_hexcolor(f_sec_colour)
|
||||
s_tone = sanitize_integer(s_tone, -185, 34, initial(s_tone))
|
||||
s_colour = sanitize_hexcolor(s_colour)
|
||||
for(var/marking_location in m_colours)
|
||||
m_colours[marking_location] = sanitize_hexcolor(m_colours[marking_location], DEFAULT_MARKING_COLOURS[marking_location])
|
||||
hacc_colour = sanitize_hexcolor(hacc_colour)
|
||||
h_style = sanitize_inlist(h_style, GLOB.hair_styles_public_list, initial(h_style))
|
||||
f_style = sanitize_inlist(f_style, GLOB.facial_hair_styles_list, initial(f_style))
|
||||
for(var/marking_location in m_styles)
|
||||
m_styles[marking_location] = sanitize_inlist(m_styles[marking_location], GLOB.marking_styles_list, DEFAULT_MARKING_STYLES[marking_location])
|
||||
ha_style = sanitize_inlist(ha_style, GLOB.head_accessory_styles_list, initial(ha_style))
|
||||
alt_head = sanitize_inlist(alt_head, GLOB.alt_heads_list, initial(alt_head))
|
||||
e_colour = sanitize_hexcolor(e_colour)
|
||||
underwear = sanitize_text(underwear, initial(underwear))
|
||||
undershirt = sanitize_text(undershirt, initial(undershirt))
|
||||
backbag = sanitize_text(backbag, initial(backbag))
|
||||
b_type = sanitize_text(b_type, initial(b_type))
|
||||
autohiss_mode = sanitize_integer(autohiss_mode, 0, 2, initial(autohiss_mode))
|
||||
|
||||
alternate_option = sanitize_integer(alternate_option, 0, 2, initial(alternate_option))
|
||||
job_support_high = sanitize_integer(job_support_high, 0, 65535, initial(job_support_high))
|
||||
job_support_med = sanitize_integer(job_support_med, 0, 65535, initial(job_support_med))
|
||||
job_support_low = sanitize_integer(job_support_low, 0, 65535, initial(job_support_low))
|
||||
job_medsci_high = sanitize_integer(job_medsci_high, 0, 65535, initial(job_medsci_high))
|
||||
job_medsci_med = sanitize_integer(job_medsci_med, 0, 65535, initial(job_medsci_med))
|
||||
job_medsci_low = sanitize_integer(job_medsci_low, 0, 65535, initial(job_medsci_low))
|
||||
job_engsec_high = sanitize_integer(job_engsec_high, 0, 65535, initial(job_engsec_high))
|
||||
job_engsec_med = sanitize_integer(job_engsec_med, 0, 65535, initial(job_engsec_med))
|
||||
job_engsec_low = sanitize_integer(job_engsec_low, 0, 65535, initial(job_engsec_low))
|
||||
job_karma_high = sanitize_integer(job_karma_high, 0, 65535, initial(job_karma_high))
|
||||
job_karma_med = sanitize_integer(job_karma_med, 0, 65535, initial(job_karma_med))
|
||||
job_karma_low = sanitize_integer(job_karma_low, 0, 65535, initial(job_karma_low))
|
||||
disabilities = sanitize_integer(disabilities, 0, 65535, initial(disabilities))
|
||||
|
||||
socks = sanitize_text(socks, initial(socks))
|
||||
body_accessory = sanitize_text(body_accessory, initial(body_accessory))
|
||||
|
||||
// if(isnull(disabilities)) disabilities = 0
|
||||
if(!player_alt_titles) player_alt_titles = new()
|
||||
if(!organ_data) src.organ_data = list()
|
||||
if(!rlimb_data) src.rlimb_data = list()
|
||||
if(!loadout_gear) loadout_gear = list()
|
||||
|
||||
// Check if the current body accessory exists
|
||||
if(!GLOB.body_accessory_by_name[body_accessory])
|
||||
body_accessory = null
|
||||
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/save_character(client/C)
|
||||
var/organlist
|
||||
var/rlimblist
|
||||
var/playertitlelist
|
||||
var/gearlist
|
||||
|
||||
var/markingcolourslist = list2params(m_colours)
|
||||
var/markingstyleslist = list2params(m_styles)
|
||||
if(!isemptylist(organ_data))
|
||||
organlist = list2params(organ_data)
|
||||
if(!isemptylist(rlimb_data))
|
||||
rlimblist = list2params(rlimb_data)
|
||||
if(!isemptylist(player_alt_titles))
|
||||
playertitlelist = list2params(player_alt_titles)
|
||||
if(!isemptylist(loadout_gear))
|
||||
gearlist = list2params(loadout_gear)
|
||||
|
||||
var/datum/db_query/firstquery = SSdbcore.NewQuery("SELECT slot FROM characters WHERE ckey=:ckey ORDER BY slot", list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
if(!firstquery.warn_execute())
|
||||
qdel(firstquery)
|
||||
return
|
||||
while(firstquery.NextRow())
|
||||
if(text2num(firstquery.item[1]) == default_slot)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"UPDATE characters
|
||||
SET
|
||||
OOC_Notes=:metadata,
|
||||
real_name=:real_name,
|
||||
name_is_always_random=:be_random_name,
|
||||
gender=:gender,
|
||||
age=:age,
|
||||
species=:species,
|
||||
language=:language,
|
||||
hair_colour=:h_colour,
|
||||
secondary_hair_colour=:h_sec_colour,
|
||||
facial_hair_colour=:f_colour,
|
||||
secondary_facial_hair_colour=:f_sec_colour,
|
||||
skin_tone=:s_tone,
|
||||
skin_colour=:s_colour,
|
||||
marking_colours=:markingcolourslist,
|
||||
head_accessory_colour=:hacc_colour,
|
||||
hair_style_name=:h_style,
|
||||
facial_style_name=:f_style,
|
||||
marking_styles=:markingstyleslist,
|
||||
head_accessory_style_name=:ha_style,
|
||||
alt_head_name=:alt_head,
|
||||
eye_colour=:e_colour,
|
||||
underwear=:underwear,
|
||||
undershirt=:undershirt,
|
||||
backbag=:backbag,
|
||||
b_type=:b_type,
|
||||
alternate_option=:alternate_option,
|
||||
job_support_high=:job_support_high,
|
||||
job_support_med=:job_support_med,
|
||||
job_support_low=:job_support_low,
|
||||
job_medsci_high=:job_medsci_high,
|
||||
job_medsci_med=:job_medsci_med,
|
||||
job_medsci_low=:job_medsci_low,
|
||||
job_engsec_high=:job_engsec_high,
|
||||
job_engsec_med=:job_engsec_med,
|
||||
job_engsec_low=:job_engsec_low,
|
||||
job_karma_high=:job_karma_high,
|
||||
job_karma_med=:job_karma_med,
|
||||
job_karma_low=:job_karma_low,
|
||||
flavor_text=:flavor_text,
|
||||
med_record=:med_record,
|
||||
sec_record=:sec_record,
|
||||
gen_record=:gen_record,
|
||||
player_alt_titles=:playertitlelist,
|
||||
disabilities=:disabilities,
|
||||
organ_data=:organlist,
|
||||
rlimb_data=:rlimblist,
|
||||
nanotrasen_relation=:nanotrasen_relation,
|
||||
speciesprefs=:speciesprefs,
|
||||
socks=:socks,
|
||||
body_accessory=:body_accessory,
|
||||
gear=:gearlist,
|
||||
autohiss=:autohiss_mode
|
||||
WHERE ckey=:ckey
|
||||
AND slot=:slot"}, list(
|
||||
// OH GOD SO MANY PARAMETERS
|
||||
"metadata" = metadata,
|
||||
"real_name" = real_name,
|
||||
"be_random_name" = be_random_name,
|
||||
"gender" = gender,
|
||||
"age" = age,
|
||||
"species" = species,
|
||||
"language" = language,
|
||||
"h_colour" = h_colour,
|
||||
"h_sec_colour" = h_sec_colour,
|
||||
"f_colour" = f_colour,
|
||||
"f_sec_colour" = f_sec_colour,
|
||||
"s_tone" = s_tone,
|
||||
"s_colour" = s_colour,
|
||||
"markingcolourslist" = markingcolourslist,
|
||||
"hacc_colour" = hacc_colour,
|
||||
"h_style" = h_style,
|
||||
"f_style" = f_style,
|
||||
"markingstyleslist" = markingstyleslist,
|
||||
"ha_style" = ha_style,
|
||||
"alt_head" = (alt_head ? alt_head : ""), // This it intentional. It wont work without it!
|
||||
"e_colour" = e_colour,
|
||||
"underwear" = underwear,
|
||||
"undershirt" = undershirt,
|
||||
"backbag" = backbag,
|
||||
"b_type" = b_type,
|
||||
"alternate_option" = alternate_option,
|
||||
"job_support_high" = job_support_high,
|
||||
"job_support_med" = job_support_med,
|
||||
"job_support_low" = job_support_low,
|
||||
"job_medsci_high" = job_medsci_high,
|
||||
"job_medsci_med" = job_medsci_med,
|
||||
"job_medsci_low" = job_medsci_low,
|
||||
"job_engsec_high" = job_engsec_high,
|
||||
"job_engsec_med" = job_engsec_med,
|
||||
"job_engsec_low" = job_engsec_low,
|
||||
"job_karma_high" = job_karma_high,
|
||||
"job_karma_med" = job_karma_med,
|
||||
"job_karma_low" = job_karma_low,
|
||||
"flavor_text" = flavor_text,
|
||||
"med_record" = med_record,
|
||||
"sec_record" = sec_record,
|
||||
"gen_record" = gen_record,
|
||||
"playertitlelist" = (playertitlelist ? playertitlelist : ""), // This it intentnional. It wont work without it!
|
||||
"disabilities" = disabilities,
|
||||
"organlist" = (organlist ? organlist : ""),
|
||||
"rlimblist" = (rlimblist ? rlimblist : ""),
|
||||
"nanotrasen_relation" = nanotrasen_relation,
|
||||
"speciesprefs" = speciesprefs,
|
||||
"socks" = socks,
|
||||
"body_accessory" = (body_accessory ? body_accessory : ""),
|
||||
"gearlist" = (gearlist ? gearlist : ""),
|
||||
"autohiss_mode" = autohiss_mode,
|
||||
"ckey" = C.ckey,
|
||||
"slot" = default_slot
|
||||
)
|
||||
)
|
||||
|
||||
if(!query.warn_execute())
|
||||
qdel(firstquery)
|
||||
qdel(query)
|
||||
return
|
||||
qdel(firstquery)
|
||||
qdel(query)
|
||||
return 1
|
||||
|
||||
qdel(firstquery)
|
||||
|
||||
var/datum/db_query/query = SSdbcore.NewQuery({"
|
||||
INSERT INTO characters (ckey, slot, OOC_Notes, real_name, name_is_always_random, gender,
|
||||
age, species, language,
|
||||
hair_colour, secondary_hair_colour,
|
||||
facial_hair_colour, secondary_facial_hair_colour,
|
||||
skin_tone, skin_colour,
|
||||
marking_colours,
|
||||
head_accessory_colour,
|
||||
hair_style_name,
|
||||
facial_style_name,
|
||||
marking_styles,
|
||||
head_accessory_style_name,
|
||||
alt_head_name,
|
||||
eye_colour,
|
||||
underwear, undershirt,
|
||||
backbag, b_type, alternate_option,
|
||||
job_support_high, job_support_med, job_support_low,
|
||||
job_medsci_high, job_medsci_med, job_medsci_low,
|
||||
job_engsec_high, job_engsec_med, job_engsec_low,
|
||||
job_karma_high, job_karma_med, job_karma_low,
|
||||
flavor_text,
|
||||
med_record,
|
||||
sec_record,
|
||||
gen_record,
|
||||
player_alt_titles,
|
||||
disabilities, organ_data, rlimb_data, nanotrasen_relation, speciesprefs,
|
||||
socks, body_accessory, gear, autohiss)
|
||||
|
||||
VALUES
|
||||
(:ckey, :slot, :metadata, :name, :be_random_name, :gender,
|
||||
:age, :species, :language,
|
||||
:h_colour, :h_sec_colour,
|
||||
:f_colour, :f_sec_colour,
|
||||
:s_tone, :s_colour,
|
||||
:markingcolourslist,
|
||||
:hacc_colour,
|
||||
:h_style,
|
||||
:f_style,
|
||||
:markingstyleslist,
|
||||
:ha_style,
|
||||
:alt_head,
|
||||
:e_colour,
|
||||
:underwear, :undershirt,
|
||||
:backbag, :b_type, :alternate_option,
|
||||
:job_support_high, :job_support_med, :job_support_low,
|
||||
:job_medsci_high, :job_medsci_med, :job_medsci_low,
|
||||
:job_engsec_high, :job_engsec_med, :job_engsec_low,
|
||||
:job_karma_high, :job_karma_med, :job_karma_low,
|
||||
:flavor_text,
|
||||
:med_record,
|
||||
:sec_record,
|
||||
:gen_record,
|
||||
:playertitlelist,
|
||||
:disabilities, :organlist, :rlimblist, :nanotrasen_relation, :speciesprefs,
|
||||
:socks, :body_accessory, :gearlist, :autohiss_mode)
|
||||
|
||||
"}, list(
|
||||
// This has too many params for anyone to look at this without going insae
|
||||
"ckey" = C.ckey,
|
||||
"slot" = default_slot,
|
||||
"metadata" = metadata,
|
||||
"name" = real_name,
|
||||
"be_random_name" = be_random_name,
|
||||
"gender" = gender,
|
||||
"age" = age,
|
||||
"species" = species,
|
||||
"language" = language,
|
||||
"h_colour" = h_colour,
|
||||
"h_sec_colour" = h_sec_colour,
|
||||
"f_colour" = f_colour,
|
||||
"f_sec_colour" = f_sec_colour,
|
||||
"s_tone" = s_tone,
|
||||
"s_colour" = s_colour,
|
||||
"markingcolourslist" = markingcolourslist,
|
||||
"hacc_colour" = hacc_colour,
|
||||
"h_style" = h_style,
|
||||
"f_style" = f_style,
|
||||
"markingstyleslist" = markingstyleslist,
|
||||
"ha_style" = ha_style,
|
||||
"alt_head" = alt_head,
|
||||
"e_colour" = e_colour,
|
||||
"underwear" = underwear,
|
||||
"undershirt" = undershirt,
|
||||
"backbag" = backbag,
|
||||
"b_type" = b_type,
|
||||
"alternate_option" = alternate_option,
|
||||
"job_support_high" = job_support_high,
|
||||
"job_support_med" = job_support_med,
|
||||
"job_support_low" = job_support_low,
|
||||
"job_medsci_high" = job_medsci_high,
|
||||
"job_medsci_med" = job_medsci_med,
|
||||
"job_medsci_low" = job_medsci_low,
|
||||
"job_engsec_high" = job_engsec_high,
|
||||
"job_engsec_med" = job_engsec_med,
|
||||
"job_engsec_low" = job_engsec_low,
|
||||
"job_karma_high" = job_karma_high,
|
||||
"job_karma_med" = job_karma_med,
|
||||
"job_karma_low" = job_karma_low,
|
||||
"flavor_text" = flavor_text,
|
||||
"med_record" = med_record,
|
||||
"sec_record" = sec_record,
|
||||
"gen_record" = gen_record,
|
||||
"playertitlelist" = (playertitlelist ? playertitlelist : ""), // This it intentnional. It wont work without it!
|
||||
"disabilities" = disabilities,
|
||||
"organlist" = (organlist ? organlist : ""),
|
||||
"rlimblist" = (rlimblist ? rlimblist : ""),
|
||||
"nanotrasen_relation" = nanotrasen_relation,
|
||||
"speciesprefs" = speciesprefs,
|
||||
"socks" = socks,
|
||||
"body_accessory" = (body_accessory ? body_accessory : ""),
|
||||
"gearlist" = (gearlist ? gearlist : ""),
|
||||
"autohiss_mode" = autohiss_mode
|
||||
))
|
||||
|
||||
if(!query.warn_execute())
|
||||
qdel(query)
|
||||
return
|
||||
|
||||
qdel(query)
|
||||
saved = TRUE
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/load_random_character_slot(client/C)
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT slot FROM characters WHERE ckey=:ckey ORDER BY slot", list(
|
||||
"ckey" = C.ckey
|
||||
))
|
||||
var/list/saves = list()
|
||||
var/list/datum/character_save/valid_slots = list()
|
||||
for(var/datum/character_save/CS in character_saves)
|
||||
if(CS.valid_save)
|
||||
valid_slots += CS
|
||||
|
||||
if(!query.warn_execute(async = FALSE)) // Dont async this. Youll make roundstart slow.
|
||||
qdel(query)
|
||||
if(!length(valid_slots))
|
||||
// They have no valid saves. Lets just randomise #1
|
||||
var/datum/character_save/CS = C.prefs.character_saves[1] // Get slot 1
|
||||
CS.randomise()
|
||||
CS.real_name = random_name(CS.gender) // Pick a name
|
||||
C.prefs.active_character = C.prefs.character_saves[1] // Set slot 1 as their active
|
||||
return
|
||||
|
||||
while(query.NextRow())
|
||||
saves += text2num(query.item[1])
|
||||
qdel(query)
|
||||
|
||||
if(!saves.len)
|
||||
load_character(C)
|
||||
return 0
|
||||
load_character(C,pick(saves))
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/clear_character_slot(client/C)
|
||||
. = FALSE
|
||||
// Is there a character in that slot?
|
||||
var/datum/db_query/query = SSdbcore.NewQuery("SELECT slot FROM characters WHERE ckey=:ckey AND slot=:slot", list(
|
||||
"ckey" = C.ckey,
|
||||
"slot" = default_slot
|
||||
))
|
||||
|
||||
if(!query.warn_execute())
|
||||
qdel(query)
|
||||
return
|
||||
|
||||
if(!query.NextRow())
|
||||
qdel(query)
|
||||
return
|
||||
|
||||
qdel(query)
|
||||
|
||||
var/datum/db_query/delete_query = SSdbcore.NewQuery("DELETE FROM characters WHERE ckey=:ckey AND slot=:slot", list(
|
||||
"ckey" = C.ckey,
|
||||
"slot" = default_slot
|
||||
))
|
||||
|
||||
if(!delete_query.warn_execute())
|
||||
qdel(delete_query)
|
||||
return
|
||||
|
||||
qdel(delete_query)
|
||||
|
||||
saved = FALSE
|
||||
return TRUE
|
||||
var/datum/character_save/CS = pick(valid_slots)
|
||||
C.prefs.active_character = CS
|
||||
|
||||
/**
|
||||
* Saves [/datum/preferences/proc/volume_mixer] for the current client.
|
||||
|
||||
@@ -458,10 +458,12 @@ BLIND // can't see anything
|
||||
/obj/item/clothing/shoes/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/match) && src.loc == user)
|
||||
var/obj/item/match/M = I
|
||||
if(M.matchignite()) // Match isn't lit, but isn't burnt.
|
||||
if(!M.lit && !M.burnt) // Match isn't lit, but isn't burnt.
|
||||
user.visible_message("<span class='warning'>[user] strikes a [M] on the bottom of [src], lighting it.</span>","<span class='warning'>You strike [M] on the bottom of [src] to light it.</span>")
|
||||
M.matchignite()
|
||||
playsound(user.loc, 'sound/goonstation/misc/matchstick_light.ogg', 50, 1)
|
||||
else
|
||||
return
|
||||
if(M.lit && !M.burnt)
|
||||
user.visible_message("<span class='warning'>[user] crushes [M] into the bottom of [src], extinguishing it.</span>","<span class='warning'>You crush [M] into the bottom of [src], extinguishing it.</span>")
|
||||
M.dropped()
|
||||
return
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
icon_state = "hardsuit0-ert_commander"
|
||||
item_state = "helm-command"
|
||||
item_color = "ert_commander"
|
||||
armor = list(melee = 45, bullet = 25, laser = 30, energy = 10, bomb = 25, bio = 100, rad = 50, fire = 80, acid = 80)
|
||||
armor = list(MELEE = 45, BULLET = 25, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 100, RAD = 50, FIRE = 80, ACID = 80)
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/obj/machinery/camera/camera
|
||||
var/has_camera = TRUE
|
||||
@@ -50,7 +50,7 @@
|
||||
item_state = "suit-command"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
allowed = list(/obj/item/gun,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/melee/baton,/obj/item/melee/energy/sword/saber,/obj/item/restraints/handcuffs,/obj/item/tank/internals)
|
||||
armor = list(melee = 45, bullet = 25, laser = 30, energy = 10, bomb = 25, bio = 100, rad = 50, fire = 80, acid = 80)
|
||||
armor = list(MELEE = 45, BULLET = 25, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 100, RAD = 50, FIRE = 80, ACID = 80)
|
||||
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/t_scanner, /obj/item/rcd, /obj/item/crowbar, \
|
||||
/obj/item/screwdriver, /obj/item/weldingtool, /obj/item/wirecutters, /obj/item/wrench, /obj/item/multitool, \
|
||||
/obj/item/radio, /obj/item/analyzer, /obj/item/gun, /obj/item/melee/baton, /obj/item/reagent_containers/spray/pepper, \
|
||||
@@ -121,6 +121,7 @@
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/ert/engineer
|
||||
name = "emergency response team engineer helmet"
|
||||
desc = "A helmet worn by engineers of a Nanotrasen Emergency Response Team. Has yellow highlights. Armoured and space ready."
|
||||
armor = list(MELEE = 45, BULLET = 25, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 100, RAD = 75, FIRE = 80, ACID = 80)
|
||||
icon_state = "hardsuit0-ert_engineer"
|
||||
item_state = "helm-orange"
|
||||
item_color = "ert_engineer"
|
||||
@@ -129,6 +130,7 @@
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/ert/engineer/gamma
|
||||
name = "elite emergency response team engineer helmet"
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
armor = list(MELEE = 45, BULLET = 25, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 100, RAD = 100, FIRE = 80, ACID = 80)
|
||||
icon_state = "hardsuit0-gammaengineer"
|
||||
item_color = "gammaengineer"
|
||||
|
||||
@@ -137,12 +139,14 @@
|
||||
desc = "A suit worn by the engineers of a Nanotrasen Emergency Response Team. Has yellow highlights. Armoured, space ready, and fire resistant."
|
||||
icon_state = "ert_engineer"
|
||||
item_state = "suit-orange"
|
||||
armor = list(MELEE = 45, BULLET = 25, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 100, RAD = 75, FIRE = 80, ACID = 80)
|
||||
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/engineer
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/ert/engineer/gamma
|
||||
name = "elite emergency response team engineer suit"
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
icon_state = "ert_gengineer"
|
||||
armor = list(MELEE = 45, BULLET = 25, LASER = 30, ENERGY = 10, BOMB = 25, BIO = 100, RAD = 100, FIRE = 80, ACID = 80)
|
||||
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/engineer/gamma
|
||||
|
||||
//Medical
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
var/mob/living/simple_animal/mouse/blobinfected/B = new(vent.loc)
|
||||
var/mob/M = pick(candidates)
|
||||
B.key = M.key
|
||||
B.mind.special_role = SPECIAL_ROLE_BLOB
|
||||
SSticker.mode.update_blob_icons_added(B.mind)
|
||||
|
||||
to_chat(B, "<span class='userdanger'>You are now a mouse, infected with blob spores. Find somewhere isolated... before you burst and become the blob! Use ventcrawl (alt-click on vents) to move around.</span>")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
name = "carp fillet"
|
||||
desc = "A fillet of spess carp meat."
|
||||
icon = 'icons/obj/food/seafood.dmi'
|
||||
icon_state = "fishfillet"
|
||||
icon_state = "carpfillet" // Sprite created by https://github.com/binarysudoku for Goonstation, They have relicensed it for our use.
|
||||
filling_color = "#FFDEFE"
|
||||
bitesize = 6
|
||||
list_reagents = list("protein" = 3, "carpotoxin" = 2, "vitamin" = 2)
|
||||
@@ -13,7 +13,7 @@
|
||||
name = "raw salmon"
|
||||
desc = "A fillet of raw salmon."
|
||||
icon = 'icons/obj/food/seafood.dmi'
|
||||
icon_state = "fishfillet"
|
||||
icon_state = "salmonfillet" // Sprite created by https://github.com/binarysudoku for Goonstation, They have relicensed it for our use.
|
||||
filling_color = "#FFDEFE"
|
||||
bitesize = 6
|
||||
list_reagents = list("protein" = 3, "vitamin" = 2)
|
||||
@@ -23,7 +23,7 @@
|
||||
name = "salmon steak"
|
||||
desc = "A fillet of freshly-grilled salmon meat."
|
||||
icon = 'icons/obj/food/seafood.dmi'
|
||||
icon_state = "salmonsteak"
|
||||
icon_state = "salmonsteak" // Sprite based on one created by https://github.com/binarysudoku for Goonstation, They have relicensed it for our use.
|
||||
trash = /obj/item/trash/plate
|
||||
filling_color = "#7A3D11"
|
||||
bitesize = 3
|
||||
@@ -34,7 +34,7 @@
|
||||
name = "raw catfish"
|
||||
desc = "A fillet of raw catfish."
|
||||
icon = 'icons/obj/food/seafood.dmi'
|
||||
icon_state = "fishfillet"
|
||||
icon_state = "catfishfillet" // Sprite created by https://github.com/binarysudoku for Goonstation, They have relicensed it for our use.
|
||||
filling_color = "#FFDEFE"
|
||||
bitesize = 6
|
||||
list_reagents = list("protein" = 3, "vitamin" = 2)
|
||||
|
||||
@@ -12,3 +12,5 @@
|
||||
var/technical_name
|
||||
/// Path to the map file
|
||||
var/map_path
|
||||
/// URL to the maps webmap
|
||||
var/webmap_url
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
fluff_name = "NSS Cyberiad"
|
||||
technical_name = "Cyberiad"
|
||||
map_path = "_maps/map_files/cyberiad/cyberiad.dmm"
|
||||
webmap_url = "https://affectedarc07.github.io/SS13WebMap/Paradise/Cyberiad/"
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
fluff_name = "NSS Kerberos"
|
||||
technical_name = "Delta"
|
||||
map_path = "_maps/map_files/Delta/delta.dmm"
|
||||
webmap_url = "https://affectedarc07.github.io/SS13WebMap/Paradise/Delta/"
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
fluff_name = "NSS Cerebron"
|
||||
technical_name = "MetaStation"
|
||||
map_path = "_maps/map_files/MetaStation/MetaStation.dmm"
|
||||
webmap_url = "https://affectedarc07.github.io/SS13WebMap/Paradise/MetaStation/"
|
||||
|
||||
@@ -82,23 +82,6 @@
|
||||
new random_crystal(loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/anomalous_crystal/honk //Strips and equips you as a clown. I apologize for nothing
|
||||
activation_method = "mob_bump"
|
||||
activation_sound = 'sound/items/bikehorn.ogg'
|
||||
|
||||
/obj/machinery/anomalous_crystal/honk/ActivationReaction(mob/user)
|
||||
if(..() && ishuman(user) && !(user in affected_targets))
|
||||
var/mob/living/carbon/human/H = user
|
||||
for(var/obj/item/W in H)
|
||||
H.unEquip(W)
|
||||
var/datum/job/clown/C = SSjobs.GetJob("Clown")
|
||||
C.equip(H)
|
||||
affected_targets.Add(H)
|
||||
|
||||
/obj/machinery/anomalous_crystal/honk/New()
|
||||
..()
|
||||
activation_method = pick("mob_bump","speech")
|
||||
|
||||
/obj/machinery/anomalous_crystal/theme_warp //Warps the area you're in to look like a new one
|
||||
activation_method = "touch"
|
||||
cooldown_add = 200
|
||||
|
||||
@@ -743,7 +743,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/new_char = new(get_turf(src))
|
||||
client.prefs.copy_to(new_char)
|
||||
client.prefs.active_character.copy_to(new_char)
|
||||
if(mind)
|
||||
mind.active = TRUE
|
||||
mind.transfer_to(new_char)
|
||||
|
||||
@@ -31,10 +31,6 @@
|
||||
update_static_data(owner, ui)
|
||||
. = TRUE
|
||||
|
||||
/datum/orbit_menu/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
return data
|
||||
|
||||
/datum/orbit_menu/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
@@ -96,6 +92,7 @@
|
||||
)
|
||||
if(SSticker && SSticker.mode)
|
||||
other_antags += list(
|
||||
"Blob" = (mind.special_role == SPECIAL_ROLE_BLOB),
|
||||
"Cultist" = (mind in SSticker.mode.cult),
|
||||
"Wizard" = (mind in SSticker.mode.wizards),
|
||||
"Wizard's Apprentice" = (mind in SSticker.mode.apprentices),
|
||||
@@ -121,6 +118,10 @@
|
||||
var/list/antag_serialized = serialized.Copy()
|
||||
antag_serialized["antag"] = "Terror Spider"
|
||||
antagonists += list(antag_serialized)
|
||||
else if(istype(M, /mob/living/simple_animal/revenant))
|
||||
var/list/antag_serialized = serialized.Copy()
|
||||
antag_serialized["antag"] = "Revenant"
|
||||
antagonists += list(antag_serialized)
|
||||
else
|
||||
misc += list(serialized)
|
||||
|
||||
|
||||
@@ -207,6 +207,14 @@
|
||||
items += s_store
|
||||
return items
|
||||
|
||||
/mob/living/proc/unequip_everything()
|
||||
var/list/items = list()
|
||||
items |= get_equipped_items(TRUE)
|
||||
for(var/I in items)
|
||||
unEquip(I)
|
||||
drop_l_hand()
|
||||
drop_r_hand()
|
||||
|
||||
/obj/item/proc/equip_to_best_slot(mob/M)
|
||||
if(src != M.get_active_hand())
|
||||
to_chat(M, "<span class='warning'>You are not holding anything to equip!</span>")
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
return message // no autohiss at this level
|
||||
|
||||
/mob/living/carbon/human/handle_autohiss(message, datum/language/L)
|
||||
if(!client || client.prefs.autohiss_mode == AUTOHISS_OFF) // no need to process if there's no client or they have autohiss off
|
||||
if(!client || client.prefs.active_character.autohiss_mode == AUTOHISS_OFF) // no need to process if there's no client or they have autohiss off
|
||||
return message
|
||||
return dna.species.handle_autohiss(message, L, client.prefs.autohiss_mode)
|
||||
return dna.species.handle_autohiss(message, L, client.prefs.active_character.autohiss_mode)
|
||||
|
||||
/client/verb/toggle_autohiss()
|
||||
set name = "Toggle Auto-Accent"
|
||||
set desc = "Toggle automatic accents for your species"
|
||||
set category = "OOC"
|
||||
|
||||
prefs.autohiss_mode = (prefs.autohiss_mode + 1) % AUTOHISS_NUM
|
||||
switch(prefs.autohiss_mode)
|
||||
prefs.active_character.autohiss_mode = (prefs.active_character.autohiss_mode + 1) % AUTOHISS_NUM
|
||||
switch(prefs.active_character.autohiss_mode)
|
||||
if(AUTOHISS_OFF)
|
||||
to_chat(src, "Auto-hiss is now OFF.")
|
||||
if(AUTOHISS_BASIC)
|
||||
@@ -20,7 +20,7 @@
|
||||
if(AUTOHISS_FULL)
|
||||
to_chat(src, "Auto-hiss is now FULL.")
|
||||
else
|
||||
prefs.autohiss_mode = AUTOHISS_OFF
|
||||
prefs.active_character.autohiss_mode = AUTOHISS_OFF
|
||||
to_chat(src, "Auto-hiss is now OFF.")
|
||||
|
||||
/datum/species
|
||||
@@ -61,7 +61,7 @@
|
||||
/datum/species/drask
|
||||
autohiss_basic_map = list(
|
||||
"o" = list ("oo", "ooo"),
|
||||
"u" = list ("uu", "uuu")
|
||||
"u" = list ("uu", "uuu")
|
||||
)
|
||||
autohiss_extra_map = list(
|
||||
"m" = list ("mm", "mmm")
|
||||
|
||||
@@ -1955,7 +1955,7 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
|
||||
|
||||
if(GLOB.configuration.general.allow_character_metadata)
|
||||
if(client)
|
||||
to_chat(usr, "[src]'s Metainfo:<br>[sanitize(client.prefs.metadata)]")
|
||||
to_chat(usr, "[src]'s Metainfo:<br>[sanitize(client.prefs.active_character.metadata)]")
|
||||
else
|
||||
to_chat(usr, "[src] does not have any stored infomation!")
|
||||
else
|
||||
|
||||
@@ -674,3 +674,107 @@
|
||||
|
||||
/datum/unarmed_attack/golem/tranquillite
|
||||
attack_sound = null
|
||||
|
||||
/datum/species/golem/cloth
|
||||
name = "Cloth Golem"
|
||||
icobase = 'icons/mob/human_races/r_cloth_golem.dmi'
|
||||
flesh_color = "#E9E9E9"
|
||||
blood_color = "#E9E9E9"
|
||||
info_text = "As a <span class='danger'>Cloth Golem</span>, you are able to reform yourself after death, provided your remains aren't burned or destroyed. You are, of course, very flammable. \
|
||||
Being made of cloth, your body is magic resistant and faster than that of other golems, but weaker and less resilient."
|
||||
inherent_traits = list(TRAIT_RESISTCOLD, TRAIT_NOBREATH, TRAIT_RESISTHIGHPRESSURE, TRAIT_RESISTLOWPRESSURE, TRAIT_RADIMMUNE, TRAIT_PIERCEIMMUNE, TRAIT_CHUNKYFINGERS, TRAIT_NOPAIN)
|
||||
inherent_biotypes = MOB_UNDEAD | MOB_HUMANOID
|
||||
brute_mod = 0.85 //15% damage reduction
|
||||
burn_mod = 1.7 // don't get burned
|
||||
tox_mod = 0.85
|
||||
clone_mod = 0.85
|
||||
brain_mod = 0.85
|
||||
stamina_mod = 0.85
|
||||
speed_mod = 1 // not as heavy as stone
|
||||
punchdamagelow = 4
|
||||
punchstunthreshold = 7
|
||||
punchdamagehigh = 8 // not as heavy as stone
|
||||
prefix = "Cloth"
|
||||
golem_colour = null
|
||||
special_names = null
|
||||
|
||||
/datum/species/golem/cloth/get_random_name()
|
||||
var/pharaoh_name = pick("Neferkare", "Hudjefa", "Khufu", "Mentuhotep", "Ahmose", "Amenhotep", "Thutmose", "Hatshepsut", "Tutankhamun", "Ramses", "Seti", \
|
||||
"Merenptah", "Djer", "Semerkhet", "Nynetjer", "Khafre", "Pepi", "Intef", "Ay") //yes, Ay was an actual pharaoh
|
||||
var/golem_name = "[pharaoh_name] \Roman[rand(1,99)]"
|
||||
return golem_name
|
||||
|
||||
/datum/species/golem/cloth/handle_life(mob/living/carbon/human/H)
|
||||
if(H.fire_stacks < 1)
|
||||
H.adjust_fire_stacks(1) //always prone to burning
|
||||
..()
|
||||
|
||||
/datum/species/golem/cloth/handle_death(gibbed, mob/living/carbon/human/H)
|
||||
if(gibbed)
|
||||
return
|
||||
if(H.on_fire)
|
||||
H.visible_message("<span class='danger'>[H] burns into ash!</span>")
|
||||
H.dust()
|
||||
return
|
||||
|
||||
H.visible_message("<span class='danger'>[H] falls apart into a pile of bandages!</span>")
|
||||
new /obj/structure/cloth_pile(get_turf(H), H)
|
||||
..()
|
||||
|
||||
/obj/structure/cloth_pile
|
||||
name = "pile of bandages"
|
||||
desc = "It emits a strange aura, as if there was still life within it..."
|
||||
max_integrity = 50
|
||||
armor = list(MELEE = 90, BULLET = 90, LASER = 25, ENERGY = 80, BOMB = 50, BIO = 100, FIRE = -50, ACID = -50)
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "pile_bandages"
|
||||
resistance_flags = FLAMMABLE
|
||||
var/revive_time = 900
|
||||
var/mob/living/carbon/human/cloth_golem
|
||||
|
||||
/obj/structure/cloth_pile/Initialize(mapload, mob/living/carbon/human/H)
|
||||
. = ..()
|
||||
if(!QDELETED(H) && is_species(H, /datum/species/golem/cloth))
|
||||
H.unequip_everything()
|
||||
H.forceMove(src)
|
||||
cloth_golem = H
|
||||
to_chat(cloth_golem, "<span class='notice'>You start gathering your life energy, preparing to rise again...</span>")
|
||||
addtimer(CALLBACK(src, .proc/revive), revive_time)
|
||||
else
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/structure/cloth_pile/Destroy()
|
||||
QDEL_NULL(cloth_golem)
|
||||
return ..()
|
||||
|
||||
/obj/structure/cloth_pile/burn()
|
||||
visible_message("<span class='danger'>[src] burns into ash!</span>")
|
||||
new /obj/effect/decal/cleanable/ash(get_turf(src))
|
||||
..()
|
||||
|
||||
/obj/structure/cloth_pile/proc/revive()
|
||||
if(QDELETED(src) || QDELETED(cloth_golem)) //QDELETED also checks for null, so if no cloth golem is set this won't runtime
|
||||
return
|
||||
if(cloth_golem.suiciding)
|
||||
QDEL_NULL(cloth_golem)
|
||||
return
|
||||
|
||||
invisibility = INVISIBILITY_MAXIMUM //disappear before the animation
|
||||
new /obj/effect/temp_visual/mummy_animation(get_turf(src))
|
||||
cloth_golem.revive()
|
||||
cloth_golem.grab_ghost() //won't pull if it's a suicide
|
||||
sleep(20)
|
||||
cloth_golem.forceMove(get_turf(src))
|
||||
cloth_golem.visible_message("<span class='danger'>[src] rises and reforms into [cloth_golem]!</span>", "<span class='userdanger'>You reform into yourself!</span>")
|
||||
cloth_golem = null
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/cloth_pile/attackby(obj/item/P, mob/living/carbon/human/user, params)
|
||||
. = ..()
|
||||
|
||||
if(resistance_flags & ON_FIRE)
|
||||
return
|
||||
|
||||
if(is_hot(P))
|
||||
visible_message("<span class='danger'>[src] bursts into flames!</span>")
|
||||
fire_act()
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
to_chat(H, "<span class='warning'>The water stings[volume < 10 ? " you, but isn't concentrated enough to harm you" : null]!</span>")
|
||||
|
||||
/datum/species/grey/after_equip_job(datum/job/J, mob/living/carbon/human/H)
|
||||
var/translator_pref = H.client.prefs.speciesprefs
|
||||
var/translator_pref = H.client.prefs.active_character.speciesprefs
|
||||
if(translator_pref || ((ismindshielded(H) || J.is_command || J.supervisors == "the captain") && HAS_TRAIT(H, TRAIT_WINGDINGS)))
|
||||
if(J.title == "Mime")
|
||||
return
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
H.unEquip(H.wear_mask)
|
||||
|
||||
H.equip_or_collect(new /obj/item/clothing/mask/breath/vox(H), slot_wear_mask)
|
||||
var/tank_pref = H.client && H.client.prefs ? H.client.prefs.speciesprefs : null
|
||||
var/tank_pref = H.client && H.client.prefs ? H.client.prefs.active_character.speciesprefs : null
|
||||
var/obj/item/tank/internal_tank
|
||||
if(tank_pref)//Diseasel, here you go
|
||||
internal_tank = new /obj/item/tank/internals/nitrogen(H)
|
||||
|
||||
@@ -300,7 +300,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
/mob/living/silicon/robot/proc/pick_module()
|
||||
if(module)
|
||||
return
|
||||
var/list/modules = list("Generalist", "Engineering", "Medical", "Miner", "Janitor", "Service", "Security")
|
||||
var/list/modules = list("Engineering", "Medical", "Miner", "Janitor", "Service")
|
||||
if(islist(force_modules) && force_modules.len)
|
||||
modules = force_modules.Copy()
|
||||
if(mmi != null && mmi.alien)
|
||||
@@ -315,14 +315,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
return
|
||||
|
||||
switch(modtype)
|
||||
if("Generalist")
|
||||
module = new /obj/item/robot_module/standard(src)
|
||||
module.channels = list("Engineering" = 1, "Medical" = 1, "Security" = 1, "Service" = 1, "Supply" = 1)
|
||||
module_sprites["Basic"] = "robot_old"
|
||||
module_sprites["Android"] = "droid"
|
||||
module_sprites["Default"] = "Standard"
|
||||
module_sprites["Noble-STD"] = "Noble-STD"
|
||||
|
||||
if("Service")
|
||||
module = new /obj/item/robot_module/butler(src)
|
||||
module.channels = list("Service" = 1)
|
||||
@@ -365,17 +357,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
see_reagents = TRUE
|
||||
|
||||
if("Security")
|
||||
if(!weapons_unlock)
|
||||
var/count_secborgs = 0
|
||||
for(var/mob/living/silicon/robot/R in GLOB.alive_mob_list)
|
||||
if(R && R.stat != DEAD && R.module && istype(R.module, /obj/item/robot_module/security))
|
||||
count_secborgs++
|
||||
var/max_secborgs = 2
|
||||
if(GLOB.security_level == SEC_LEVEL_GREEN)
|
||||
max_secborgs = 1
|
||||
if(count_secborgs >= max_secborgs)
|
||||
to_chat(src, "<span class='warning'>There are too many Security cyborgs active. Please choose another module.</span>")
|
||||
return
|
||||
module = new /obj/item/robot_module/security(src)
|
||||
module.channels = list("Security" = 1)
|
||||
module_sprites["Basic"] = "secborg"
|
||||
@@ -1349,7 +1330,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
|
||||
scrambledcodes = 1
|
||||
req_one_access = list(ACCESS_CENT_SPECOPS)
|
||||
ionpulse = 1
|
||||
force_modules = list("Engineering", "Medical", "Security")
|
||||
force_modules = list("Engineering", "Medical")
|
||||
static_radio_channels = 1
|
||||
allow_rename = FALSE
|
||||
weapons_unlock = TRUE
|
||||
|
||||
@@ -265,47 +265,6 @@
|
||||
/obj/item/robot_module/proc/handle_death(mob/living/silicon/robot/R, gibbed)
|
||||
return
|
||||
|
||||
// Standard cyborg module.
|
||||
/obj/item/robot_module/standard
|
||||
// if station is fine, assist with constructing station goal room, cleaning, and repairing cables chewed by rats
|
||||
// if medical crisis, assist by providing basic healthcare, retrieving corpses, and monitoring crew lifesigns
|
||||
// if eng crisis, assist by helping repair hull breaches
|
||||
// if sec crisis, assist by opening doors for sec and providing backup zipties on patrols
|
||||
name = "generalist robot module"
|
||||
module_type = "Standard"
|
||||
subsystems = list(/mob/living/silicon/proc/subsystem_power_monitor, /mob/living/silicon/proc/subsystem_crew_monitor)
|
||||
basic_modules = list(
|
||||
// sec
|
||||
/obj/item/flash/cyborg,
|
||||
/obj/item/restraints/handcuffs/cable/zipties/cyborg,
|
||||
// janitorial
|
||||
/obj/item/soap/nanotrasen,
|
||||
/obj/item/lightreplacer/cyborg,
|
||||
// eng
|
||||
/obj/item/crowbar/cyborg,
|
||||
/obj/item/wrench/cyborg,
|
||||
/obj/item/extinguisher, // for firefighting, and propulsion in space
|
||||
/obj/item/weldingtool/largetank/cyborg,
|
||||
// mining
|
||||
/obj/item/pickaxe,
|
||||
/obj/item/t_scanner/adv_mining_scanner,
|
||||
/obj/item/storage/bag/ore/cyborg,
|
||||
// med
|
||||
/obj/item/healthanalyzer,
|
||||
/obj/item/reagent_containers/borghypo/basic,
|
||||
/obj/item/roller_holder, // for taking the injured to medbay without worsening their injuries or leaving a blood trail the whole way
|
||||
/obj/item/stack/sheet/metal/cyborg,
|
||||
/obj/item/stack/cable_coil/cyborg,
|
||||
/obj/item/stack/rods/cyborg,
|
||||
/obj/item/stack/tile/plasteel/cyborg
|
||||
)
|
||||
emag_modules = list(/obj/item/melee/energy/sword/cyborg)
|
||||
special_rechargables = list(
|
||||
/obj/item/extinguisher,
|
||||
/obj/item/weldingtool/largetank/cyborg,
|
||||
/obj/item/lightreplacer/cyborg
|
||||
)
|
||||
|
||||
// Medical cyborg module.
|
||||
/obj/item/robot_module/medical
|
||||
name = "medical robot module"
|
||||
@@ -319,6 +278,7 @@
|
||||
/obj/item/borg_defib,
|
||||
/obj/item/handheld_defibrillator,
|
||||
/obj/item/roller_holder,
|
||||
/obj/item/borg/cyborghug,
|
||||
/obj/item/reagent_containers/borghypo,
|
||||
/obj/item/scalpel/laser/laser1,
|
||||
/obj/item/hemostat,
|
||||
|
||||
@@ -108,6 +108,8 @@
|
||||
to_chat(src, "You feel your being twine with that of [M] as you merge with its biomass.")
|
||||
throw_alert(gestalt_alert, /obj/screen/alert/nymph, new_master = src) //adds a screen alert that can call resist
|
||||
forceMove(M)
|
||||
else if(isrobot(M))
|
||||
M.visible_message("<span class='notice'>[M] playfully boops [src] on the head!</span>", "<span class='notice'>You playfully boop [src] on the head!</span>")
|
||||
else
|
||||
get_scooped(M)
|
||||
else
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//Gutlunches, passive mods that devour blood and gibs
|
||||
/mob/living/simple_animal/hostile/asteroid/gutlunch
|
||||
name = "gutlunch"
|
||||
desc = "A scavenger that eats raw meat, often found alongside ash walkers. Produces a thick, nutritious milk."
|
||||
desc = "A scavenger that eats raw meat, often found alongside ash walkers. Produces a thick, medicinally nutritious milk."
|
||||
icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
|
||||
icon_state = "gutlunch"
|
||||
icon_living = "gutlunch"
|
||||
@@ -104,7 +104,9 @@
|
||||
if(prob(60))
|
||||
reagents.add_reagent("cream", rand(2, 5))
|
||||
if(prob(45))
|
||||
reagents.add_reagent("salglu_solution", rand(2,5))
|
||||
reagents.add_reagent("salglu_solution", rand(2, 5))
|
||||
if(prob(30))
|
||||
reagents.add_reagent("epinephrine", rand(2, 5))
|
||||
|
||||
|
||||
//Male gutlunch. They're smaller and more colorful!
|
||||
|
||||
@@ -684,13 +684,13 @@ GLOBAL_LIST_INIT(intents, list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM
|
||||
/mob/proc/has_valid_preferences()
|
||||
if(!client)
|
||||
return FALSE //Not sure how this would get run without the mob having a client, but let's just be safe.
|
||||
if(client.prefs.alternate_option != RETURN_TO_LOBBY)
|
||||
if(client.prefs.active_character.alternate_option != RETURN_TO_LOBBY)
|
||||
return TRUE
|
||||
// If they have antags enabled, they're potentially doing this on purpose instead of by accident. Notify admins if so.
|
||||
var/has_antags = FALSE
|
||||
if(client.prefs.be_special.len > 0)
|
||||
has_antags = TRUE
|
||||
if(!client.prefs.check_any_job())
|
||||
if(!client.prefs.active_character.check_any_job())
|
||||
to_chat(src, "<span class='danger'>You have no jobs enabled, along with return to lobby if job is unavailable. This makes you ineligible for any round start role, please update your job preferences.</span>")
|
||||
if(has_antags)
|
||||
log_admin("[src.ckey] just got booted back to lobby with no jobs, but antags enabled.")
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
|
||||
/mob/new_player/proc/new_player_panel_proc()
|
||||
var/real_name = client.prefs.real_name
|
||||
var/real_name = client.prefs.active_character.real_name
|
||||
if(client.prefs.toggles2 & PREFTOGGLE_2_RANDOMSLOT)
|
||||
real_name = "Random Character Slot"
|
||||
var/output = "<center><p><a href='byond://?src=[UID()];show_preferences=1'>Setup Character</A><br /><i>[real_name]</i></p>"
|
||||
@@ -184,13 +184,13 @@
|
||||
to_chat(src, "<span class='notice'>Now teleporting.</span>")
|
||||
observer.forceMove(O.loc)
|
||||
observer.timeofdeath = world.time // Set the time of death so that the respawn timer works correctly.
|
||||
client.prefs.update_preview_icon(1)
|
||||
observer.icon = client.prefs.preview_icon
|
||||
client.prefs.active_character.update_preview_icon(1)
|
||||
observer.icon = client.prefs.active_character.preview_icon
|
||||
observer.alpha = 127
|
||||
|
||||
if(client.prefs.be_random_name)
|
||||
client.prefs.real_name = random_name(client.prefs.gender,client.prefs.species)
|
||||
observer.real_name = client.prefs.real_name
|
||||
if(client.prefs.active_character.be_random_name)
|
||||
client.prefs.active_character.real_name = random_name(client.prefs.active_character.gender,client.prefs.active_character.species)
|
||||
observer.real_name = client.prefs.active_character.real_name
|
||||
observer.name = observer.real_name
|
||||
observer.key = key
|
||||
QDEL_NULL(mind)
|
||||
@@ -212,10 +212,10 @@
|
||||
if(!SSticker || SSticker.current_state != GAME_STATE_PLAYING)
|
||||
to_chat(usr, "<span class='warning'>The round is either not ready, or has already finished...</span>")
|
||||
return
|
||||
if(client.prefs.species in GLOB.whitelisted_species)
|
||||
if(client.prefs.active_character.species in GLOB.whitelisted_species)
|
||||
|
||||
if(!is_alien_whitelisted(src, client.prefs.species))
|
||||
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.species]."))
|
||||
if(!is_alien_whitelisted(src, client.prefs.active_character.species))
|
||||
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.active_character.species]."))
|
||||
return FALSE
|
||||
|
||||
LateChoices()
|
||||
@@ -232,12 +232,12 @@
|
||||
if(client.prefs.toggles2 & PREFTOGGLE_2_RANDOMSLOT)
|
||||
client.prefs.load_random_character_slot(client)
|
||||
|
||||
if(client.prefs.species in GLOB.whitelisted_species)
|
||||
if(!is_alien_whitelisted(src, client.prefs.species))
|
||||
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.species]."))
|
||||
if(client.prefs.active_character.species in GLOB.whitelisted_species)
|
||||
if(!is_alien_whitelisted(src, client.prefs.active_character.species))
|
||||
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.active_character.species]."))
|
||||
return FALSE
|
||||
|
||||
AttemptLateSpawn(href_list["SelectedJob"],client.prefs.spawnpoint)
|
||||
AttemptLateSpawn(href_list["SelectedJob"],client.prefs.active_character.spawnpoint)
|
||||
return
|
||||
|
||||
if(!ready && href_list["preference"])
|
||||
@@ -543,9 +543,9 @@
|
||||
new_character.lastarea = get_area(loc)
|
||||
|
||||
if(SSticker.random_players || appearance_isbanned(new_character))
|
||||
client.prefs.random_character()
|
||||
client.prefs.real_name = random_name(client.prefs.gender)
|
||||
client.prefs.copy_to(new_character)
|
||||
client.prefs.active_character.randomise()
|
||||
client.prefs.active_character.real_name = random_name(client.prefs.active_character.gender)
|
||||
client.prefs.active_character.copy_to(new_character)
|
||||
|
||||
stop_sound_channel(CHANNEL_LOBBYMUSIC)
|
||||
|
||||
@@ -569,19 +569,19 @@
|
||||
// This is to check that the player only has preferences set that they're supposed to
|
||||
/mob/new_player/proc/check_prefs_are_sane()
|
||||
var/datum/species/chosen_species
|
||||
if(client.prefs.species)
|
||||
chosen_species = GLOB.all_species[client.prefs.species]
|
||||
if(client.prefs.active_character.species)
|
||||
chosen_species = GLOB.all_species[client.prefs.active_character.species]
|
||||
if(!(chosen_species && (is_species_whitelisted(chosen_species) || has_admin_rights())))
|
||||
// Have to recheck admin due to no usr at roundstart. Latejoins are fine though.
|
||||
log_runtime(EXCEPTION("[src] had species [client.prefs.species], though they weren't supposed to. Setting to Human."), src)
|
||||
client.prefs.species = "Human"
|
||||
log_runtime(EXCEPTION("[src] had species [client.prefs.active_character.species], though they weren't supposed to. Setting to Human."), src)
|
||||
client.prefs.active_character.species = "Human"
|
||||
|
||||
var/datum/language/chosen_language
|
||||
if(client.prefs.language)
|
||||
chosen_language = GLOB.all_languages[client.prefs.language]
|
||||
if((chosen_language == null && client.prefs.language != "None") || (chosen_language && chosen_language.flags & RESTRICTED))
|
||||
log_runtime(EXCEPTION("[src] had language [client.prefs.language], though they weren't supposed to. Setting to None."), src)
|
||||
client.prefs.language = "None"
|
||||
if(client.prefs.active_character.language)
|
||||
chosen_language = GLOB.all_languages[client.prefs.active_character.language]
|
||||
if((chosen_language == null && client.prefs.active_character.language != "None") || (chosen_language && chosen_language.flags & RESTRICTED))
|
||||
log_runtime(EXCEPTION("[src] had language [client.prefs.active_character.language], though they weren't supposed to. Setting to None."), src)
|
||||
client.prefs.active_character.language = "None"
|
||||
|
||||
/mob/new_player/proc/ViewManifest()
|
||||
GLOB.generic_crew_manifest.ui_interact(usr, state = GLOB.always_state)
|
||||
@@ -607,7 +607,7 @@
|
||||
|
||||
/mob/new_player/get_gender()
|
||||
if(!client || !client.prefs) ..()
|
||||
return client.prefs.gender
|
||||
return client.prefs.active_character.gender
|
||||
|
||||
/mob/new_player/is_ready()
|
||||
return ready && ..()
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
/obj/machinery/power/treadmill/proc/throw_off(atom/movable/A)
|
||||
// if 2fast, throw the person, otherwise they just slide off, if there's reasonable speed at all
|
||||
if(speed)
|
||||
if(speed && A.move_resist < INFINITY)
|
||||
var/dist = max(throw_dist * speed / MAX_SPEED, 1)
|
||||
A.throw_at(get_distant_turf(get_turf(src), reverse_direction(dir), dist), A.throw_range, A.throw_speed, src, 1)
|
||||
|
||||
|
||||
@@ -267,9 +267,10 @@
|
||||
if("human")
|
||||
new_mob = new /mob/living/carbon/human(M.loc)
|
||||
var/mob/living/carbon/human/H = new_mob
|
||||
var/datum/preferences/A = new() //Randomize appearance for the human
|
||||
A.species = get_random_species(TRUE)
|
||||
A.copy_to(new_mob)
|
||||
var/datum/character_save/S = new //Randomize appearance for the human
|
||||
S.species = get_random_species(TRUE)
|
||||
S.randomise()
|
||||
S.copy_to(new_mob)
|
||||
randomize = H.dna.species.name
|
||||
else
|
||||
return
|
||||
|
||||
@@ -319,6 +319,19 @@
|
||||
return
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/chem_dispenser/AltClick(mob/user)
|
||||
if(!is_drink || !Adjacent(user))
|
||||
return
|
||||
if(user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't do that right now!</span>")
|
||||
return
|
||||
if(anchored)
|
||||
to_chat(user, "<span class='warning'>[src] is anchored to the floor!</span>")
|
||||
return
|
||||
pixel_x = 0
|
||||
pixel_y = 0
|
||||
setDir(turn(dir, 90))
|
||||
|
||||
/obj/machinery/chem_dispenser/soda
|
||||
icon_state = "soda_dispenser"
|
||||
name = "soda fountain"
|
||||
|
||||
@@ -17,75 +17,76 @@
|
||||
//IMPORTANT NOTE! A negative number is a multiplier, a positive number is a flat amount to add. 0 means equal to the amount of the original reagent
|
||||
var/list/blend_items = list (
|
||||
|
||||
//Sheets
|
||||
/obj/item/stack/sheet/mineral/plasma = list("plasma_dust" = 20),
|
||||
/obj/item/stack/sheet/metal = list("iron" = 20),
|
||||
/obj/item/stack/rods = list("iron" = 10),
|
||||
/obj/item/stack/sheet/plasteel = list("iron" = 20, "plasma_dust" = 20),
|
||||
/obj/item/stack/sheet/wood = list("carbon" = 20),
|
||||
/obj/item/stack/sheet/glass = list("silicon" = 20),
|
||||
/obj/item/stack/sheet/rglass = list("silicon" = 20, "iron" = 20),
|
||||
/obj/item/stack/sheet/mineral/uranium = list("uranium" = 20),
|
||||
/obj/item/stack/sheet/mineral/bananium = list("banana" = 20),
|
||||
/obj/item/stack/sheet/mineral/tranquillite = list("nothing" = 20),
|
||||
/obj/item/stack/sheet/mineral/silver = list("silver" = 20),
|
||||
/obj/item/stack/sheet/mineral/gold = list("gold" = 20),
|
||||
/obj/item/grown/nettle/basic = list("wasabi" = 0),
|
||||
/obj/item/grown/nettle/death = list("facid" = 0, "sacid" = 0),
|
||||
/obj/item/grown/novaflower = list("capsaicin" = 0, "condensedcapsaicin" = 0),
|
||||
//Sheets
|
||||
/obj/item/stack/sheet/mineral/plasma = list("plasma_dust" = 20),
|
||||
/obj/item/stack/sheet/metal = list("iron" = 20),
|
||||
/obj/item/stack/rods = list("iron" = 10),
|
||||
/obj/item/stack/sheet/plasteel = list("iron" = 20, "plasma_dust" = 20),
|
||||
/obj/item/stack/sheet/wood = list("carbon" = 20),
|
||||
/obj/item/stack/sheet/glass = list("silicon" = 20),
|
||||
/obj/item/stack/sheet/rglass = list("silicon" = 20, "iron" = 20),
|
||||
/obj/item/stack/sheet/mineral/uranium = list("uranium" = 20),
|
||||
/obj/item/stack/sheet/mineral/bananium = list("banana" = 20),
|
||||
/obj/item/stack/sheet/mineral/tranquillite = list("nothing" = 20),
|
||||
/obj/item/stack/sheet/mineral/silver = list("silver" = 20),
|
||||
/obj/item/stack/sheet/mineral/gold = list("gold" = 20),
|
||||
|
||||
//Blender Stuff
|
||||
/obj/item/reagent_containers/food/snacks/grown/tomato = list("ketchup" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/wheat = list("flour" = -5),
|
||||
/obj/item/reagent_containers/food/snacks/grown/oat = list("flour" = -5),
|
||||
/obj/item/reagent_containers/food/snacks/grown/cherries = list("cherryjelly" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/bluecherries = list("bluecherryjelly" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/egg = list("egg" = -5),
|
||||
/obj/item/reagent_containers/food/snacks/grown/rice = list("rice" = -5),
|
||||
/obj/item/grown/nettle/basic = list("wasabi" = 0),
|
||||
/obj/item/grown/nettle/death = list("facid" = 0, "sacid" = 0),
|
||||
/obj/item/grown/novaflower = list("capsaicin" = 0, "condensedcapsaicin" = 0),
|
||||
|
||||
//Grinder stuff, but only if dry
|
||||
/obj/item/reagent_containers/food/snacks/grown/coffee/robusta = list("coffeepowder" = 0, "morphine" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/coffee = list("coffeepowder" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/tea/astra = list("teapowder" = 0, "salglu_solution" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/tea = list("teapowder" = 0),
|
||||
//Blender Stuff
|
||||
/obj/item/reagent_containers/food/snacks/grown/tomato = list("ketchup" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/wheat = list("flour" = -5),
|
||||
/obj/item/reagent_containers/food/snacks/grown/oat = list("flour" = -5),
|
||||
/obj/item/reagent_containers/food/snacks/grown/cherries = list("cherryjelly" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/bluecherries = list("bluecherryjelly" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/egg = list("egg" = -5),
|
||||
/obj/item/reagent_containers/food/snacks/grown/rice = list("rice" = -5),
|
||||
|
||||
//Grinder stuff, but only if dry
|
||||
/obj/item/reagent_containers/food/snacks/grown/coffee/robusta = list("coffeepowder" = 0, "morphine" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/coffee = list("coffeepowder" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/tea/astra = list("teapowder" = 0, "salglu_solution" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/tea = list("teapowder" = 0),
|
||||
|
||||
//All types that you can put into the grinder to transfer the reagents to the beaker. !Put all recipes above this.!
|
||||
/obj/item/slime_extract = list(),
|
||||
/obj/item/reagent_containers/food = list(),
|
||||
/obj/item/reagent_containers/honeycomb = list()
|
||||
//All types that you can put into the grinder to transfer the reagents to the beaker. !Put all recipes above this.!
|
||||
/obj/item/slime_extract = list(),
|
||||
/obj/item/reagent_containers/food = list(),
|
||||
/obj/item/reagent_containers/honeycomb = list()
|
||||
)
|
||||
|
||||
var/list/juice_items = list (
|
||||
|
||||
//Juicer Stuff
|
||||
/obj/item/reagent_containers/food/snacks/grown/soybeans = list("soymilk" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/corn = list("corn_starch" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/tomato = list("tomatojuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/carrot = list("carrotjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/berries = list("berryjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/banana = list("banana" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/potato = list("potato" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/citrus/lemon = list("lemonjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/citrus/orange = list("orangejuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/citrus/lime = list("limejuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/watermelon = list("watermelonjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/watermelonslice = list("watermelonjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/berries/poison = list("poisonberryjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/pumpkin = list("pumpkinjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/blumpkin = list("blumpkinjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/apple = list("applejuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/grapes = list("grapejuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/grapes/green = list("grapejuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/pineapple = list("pineapplejuice" = 0)
|
||||
//Juicer Stuff
|
||||
/obj/item/reagent_containers/food/snacks/grown/soybeans = list("soymilk" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/corn = list("corn_starch" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/tomato = list("tomatojuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/carrot = list("carrotjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/berries = list("berryjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/banana = list("banana" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/potato = list("potato" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/citrus/lemon = list("lemonjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/citrus/orange = list("orangejuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/citrus/lime = list("limejuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/watermelon = list("watermelonjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/watermelonslice = list("watermelonjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/berries/poison = list("poisonberryjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/pumpkin = list("pumpkinjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/blumpkin = list("blumpkinjuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/apple = list("applejuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/grapes = list("grapejuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/grapes/green = list("grapejuice" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/pineapple = list("pineapplejuice" = 0)
|
||||
)
|
||||
|
||||
var/list/dried_items = list(
|
||||
//Grinder stuff, but only if dry,
|
||||
/obj/item/reagent_containers/food/snacks/grown/coffee/robusta = list("coffeepowder" = 0, "morphine" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/coffee = list("coffeepowder" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/tea/astra = list("teapowder" = 0, "salglu_solution" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/tea = list("teapowder" = 0)
|
||||
|
||||
//Grinder stuff, but only if dry,
|
||||
/obj/item/reagent_containers/food/snacks/grown/coffee/robusta = list("coffeepowder" = 0, "morphine" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/coffee = list("coffeepowder" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/tea/astra = list("teapowder" = 0, "salglu_solution" = 0),
|
||||
/obj/item/reagent_containers/food/snacks/grown/tea = list("teapowder" = 0)
|
||||
)
|
||||
|
||||
var/list/holdingitems = list()
|
||||
@@ -231,59 +232,59 @@
|
||||
|
||||
|
||||
/obj/machinery/reagentgrinder/attack_ai(mob/user)
|
||||
return FALSE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/reagentgrinder/attack_hand(mob/user)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/reagentgrinder/interact(mob/user) // The microwave Menu
|
||||
var/is_chamber_empty = 0
|
||||
var/is_beaker_ready = 0
|
||||
var/processing_chamber = ""
|
||||
var/beaker_contents = ""
|
||||
var/dat = ""
|
||||
var/is_chamber_empty = 0
|
||||
var/is_beaker_ready = 0
|
||||
var/processing_chamber = ""
|
||||
var/beaker_contents = ""
|
||||
var/dat = ""
|
||||
|
||||
if(!operating)
|
||||
for (var/obj/item/O in holdingitems)
|
||||
processing_chamber += "\A [html_encode(O.name)]<BR>"
|
||||
if(!operating)
|
||||
for (var/obj/item/O in holdingitems)
|
||||
processing_chamber += "\A [html_encode(O.name)]<BR>"
|
||||
|
||||
if (!processing_chamber)
|
||||
is_chamber_empty = 1
|
||||
processing_chamber = "Nothing."
|
||||
if (!beaker)
|
||||
beaker_contents = "<B>No beaker attached.</B><br>"
|
||||
else
|
||||
is_beaker_ready = 1
|
||||
beaker_contents = "<B>The beaker contains:</B><br>"
|
||||
var/anything = 0
|
||||
for(var/datum/reagent/R in beaker.reagents.reagent_list)
|
||||
anything = 1
|
||||
beaker_contents += "[R.volume] - [R.name]<br>"
|
||||
if(!anything)
|
||||
beaker_contents += "Nothing<br>"
|
||||
|
||||
|
||||
dat = {"
|
||||
<b>Processing chamber contains:</b><br>
|
||||
[processing_chamber]<br>
|
||||
[beaker_contents]<hr>
|
||||
"}
|
||||
if (is_beaker_ready && !is_chamber_empty && !(stat & (NOPOWER|BROKEN)))
|
||||
dat += "<A href='?src=[src.UID()];action=grind'>Grind the reagents</a><BR>"
|
||||
dat += "<A href='?src=[src.UID()];action=juice'>Juice the reagents</a><BR><BR>"
|
||||
if(holdingitems && holdingitems.len > 0)
|
||||
dat += "<A href='?src=[src.UID()];action=eject'>Eject the reagents</a><BR>"
|
||||
if (beaker)
|
||||
dat += "<A href='?src=[src.UID()];action=detach'>Detach the beaker</a><BR>"
|
||||
if(!processing_chamber)
|
||||
is_chamber_empty = 1
|
||||
processing_chamber = "Nothing."
|
||||
if(!beaker)
|
||||
beaker_contents = "<B>No beaker attached.</B><br>"
|
||||
else
|
||||
dat += "Please wait..."
|
||||
is_beaker_ready = 1
|
||||
beaker_contents = "<B>The beaker contains:</B><br>"
|
||||
var/anything = 0
|
||||
for(var/datum/reagent/R in beaker.reagents.reagent_list)
|
||||
anything = 1
|
||||
beaker_contents += "[R.volume] - [R.name]<br>"
|
||||
if(!anything)
|
||||
beaker_contents += "Nothing<br>"
|
||||
|
||||
var/datum/browser/popup = new(user, "reagentgrinder", "All-In-One Grinder")
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open(1)
|
||||
return
|
||||
|
||||
dat = {"
|
||||
<b>Processing chamber contains:</b><br>
|
||||
[processing_chamber]<br>
|
||||
[beaker_contents]<hr>
|
||||
"}
|
||||
if(is_beaker_ready && !is_chamber_empty && !(stat & (NOPOWER|BROKEN)))
|
||||
dat += "<A href='?src=[src.UID()];action=grind'>Grind the reagents</a><BR>"
|
||||
dat += "<A href='?src=[src.UID()];action=juice'>Juice the reagents</a><BR><BR>"
|
||||
if(holdingitems && holdingitems.len > 0)
|
||||
dat += "<A href='?src=[src.UID()];action=eject'>Eject the reagents</a><BR>"
|
||||
if(beaker)
|
||||
dat += "<A href='?src=[src.UID()];action=detach'>Detach the beaker</a><BR>"
|
||||
else
|
||||
dat += "Please wait..."
|
||||
|
||||
var/datum/browser/popup = new(user, "reagentgrinder", "All-In-One Grinder")
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open(1)
|
||||
return
|
||||
|
||||
/obj/machinery/reagentgrinder/Topic(href, href_list)
|
||||
if(..())
|
||||
@@ -293,223 +294,228 @@
|
||||
updateUsrDialog()
|
||||
return
|
||||
switch(href_list["action"])
|
||||
if ("grind")
|
||||
if("grind")
|
||||
grind()
|
||||
if("juice")
|
||||
juice()
|
||||
if("eject")
|
||||
eject()
|
||||
if ("detach")
|
||||
if("detach")
|
||||
detach()
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/detach()
|
||||
|
||||
if (usr.stat != 0)
|
||||
return
|
||||
if (!beaker)
|
||||
return
|
||||
beaker.loc = src.loc
|
||||
beaker = null
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
if(usr.stat != 0)
|
||||
return
|
||||
if(!beaker)
|
||||
return
|
||||
beaker.loc = src.loc
|
||||
beaker = null
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/eject()
|
||||
if(usr.stat != 0)
|
||||
return
|
||||
if(holdingitems && holdingitems.len == 0)
|
||||
return
|
||||
|
||||
if (usr.stat != 0)
|
||||
return
|
||||
if (holdingitems && holdingitems.len == 0)
|
||||
return
|
||||
|
||||
for(var/obj/item/O in holdingitems)
|
||||
O.loc = src.loc
|
||||
holdingitems -= O
|
||||
holdingitems = list()
|
||||
updateUsrDialog()
|
||||
for(var/obj/item/O in holdingitems)
|
||||
O.loc = src.loc
|
||||
holdingitems -= O
|
||||
holdingitems = list()
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/is_allowed(obj/item/reagent_containers/O)
|
||||
for (var/i in blend_items)
|
||||
if(istype(O, i))
|
||||
return TRUE
|
||||
return FALSE
|
||||
for (var/i in blend_items)
|
||||
if(istype(O, i))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/get_allowed_by_id(obj/item/O)
|
||||
for (var/i in blend_items)
|
||||
if (istype(O, i))
|
||||
return blend_items[i]
|
||||
for (var/i in blend_items)
|
||||
if(istype(O, i))
|
||||
return blend_items[i]
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/get_allowed_snack_by_id(obj/item/reagent_containers/food/snacks/O)
|
||||
for(var/i in blend_items)
|
||||
if(istype(O, i))
|
||||
return blend_items[i]
|
||||
for(var/i in blend_items)
|
||||
if(istype(O, i))
|
||||
return blend_items[i]
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/get_allowed_juice_by_id(obj/item/reagent_containers/food/snacks/O)
|
||||
for(var/i in juice_items)
|
||||
if(istype(O, i))
|
||||
return juice_items[i]
|
||||
for(var/i in juice_items)
|
||||
if(istype(O, i))
|
||||
return juice_items[i]
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/get_grownweapon_amount(obj/item/grown/O)
|
||||
if (!istype(O) || !O.seed)
|
||||
return 5
|
||||
else if (O.seed.potency == -1)
|
||||
return 5
|
||||
else
|
||||
return round(O.seed.potency)
|
||||
if(!istype(O) || !O.seed)
|
||||
return 5
|
||||
else if(O.seed.potency == -1)
|
||||
return 5
|
||||
else
|
||||
return round(O.seed.potency)
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/get_juice_amount(obj/item/reagent_containers/food/snacks/grown/O)
|
||||
if (!istype(O) || !O.seed)
|
||||
return 5
|
||||
else if (O.seed.potency == -1)
|
||||
return 5
|
||||
else
|
||||
return round(5*sqrt(O.seed.potency))
|
||||
if(!istype(O) || !O.seed)
|
||||
return 5
|
||||
else if(O.seed.potency == -1)
|
||||
return 5
|
||||
else
|
||||
return round(5*sqrt(O.seed.potency))
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/remove_object(obj/item/O)
|
||||
holdingitems -= O
|
||||
qdel(O)
|
||||
holdingitems -= O
|
||||
qdel(O)
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/juice()
|
||||
power_change()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume))
|
||||
return
|
||||
playsound(src.loc, 'sound/machines/juicer.ogg', 20, 1)
|
||||
var/offset = prob(50) ? -2 : 2
|
||||
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking
|
||||
operating = 1
|
||||
power_change()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if(!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume))
|
||||
return
|
||||
playsound(src.loc, 'sound/machines/juicer.ogg', 20, 1)
|
||||
var/offset = prob(50) ? -2 : 2
|
||||
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking
|
||||
operating = 1
|
||||
updateUsrDialog()
|
||||
spawn(50)
|
||||
pixel_x = initial(pixel_x) //return to its spot after shaking
|
||||
operating = 0
|
||||
updateUsrDialog()
|
||||
spawn(50)
|
||||
pixel_x = initial(pixel_x) //return to its spot after shaking
|
||||
operating = 0
|
||||
updateUsrDialog()
|
||||
|
||||
//Snacks
|
||||
for (var/obj/item/reagent_containers/food/snacks/O in holdingitems)
|
||||
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
//Snacks
|
||||
for (var/obj/item/reagent_containers/food/snacks/O in holdingitems)
|
||||
if(beaker.reagents.holder_full())
|
||||
break
|
||||
|
||||
var/allowed = get_allowed_juice_by_id(O)
|
||||
if(isnull(allowed))
|
||||
break
|
||||
var/allowed = get_allowed_juice_by_id(O)
|
||||
if(isnull(allowed))
|
||||
break
|
||||
|
||||
for (var/r_id in allowed)
|
||||
for (var/r_id in allowed)
|
||||
|
||||
var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
|
||||
var/amount = get_juice_amount(O)
|
||||
var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
|
||||
var/amount = get_juice_amount(O)
|
||||
|
||||
beaker.reagents.add_reagent(r_id, min(amount*efficiency, space))
|
||||
beaker.reagents.add_reagent(r_id, min(amount * efficiency, space))
|
||||
|
||||
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
|
||||
remove_object(O)
|
||||
remove_object(O)
|
||||
|
||||
/obj/machinery/reagentgrinder/proc/grind()
|
||||
|
||||
power_change()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if (!beaker || (beaker && beaker.reagents.total_volume >= beaker.reagents.maximum_volume))
|
||||
return
|
||||
playsound(src.loc, 'sound/machines/blender.ogg', 50, 1)
|
||||
var/offset = prob(50) ? -2 : 2
|
||||
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking
|
||||
operating = 1
|
||||
power_change()
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if(!beaker || (beaker && beaker.reagents.holder_full()))
|
||||
return
|
||||
playsound(src.loc, 'sound/machines/blender.ogg', 50, 1)
|
||||
var/offset = prob(50) ? -2 : 2
|
||||
animate(src, pixel_x = pixel_x + offset, time = 0.2, loop = 250) //start shaking
|
||||
operating = 1
|
||||
updateUsrDialog()
|
||||
spawn(60)
|
||||
pixel_x = initial(pixel_x) //return to its spot after shaking
|
||||
operating = 0
|
||||
updateUsrDialog()
|
||||
spawn(60)
|
||||
pixel_x = initial(pixel_x) //return to its spot after shaking
|
||||
operating = 0
|
||||
updateUsrDialog()
|
||||
|
||||
//Snacks and Plants
|
||||
for (var/obj/item/reagent_containers/food/snacks/O in holdingitems)
|
||||
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
//Snacks and Plants
|
||||
for (var/obj/item/reagent_containers/food/snacks/O in holdingitems)
|
||||
if(beaker.reagents.holder_full())
|
||||
break
|
||||
|
||||
var/allowed = get_allowed_snack_by_id(O)
|
||||
if(isnull(allowed))
|
||||
break
|
||||
var/allowed = get_allowed_snack_by_id(O)
|
||||
if(isnull(allowed))
|
||||
break
|
||||
|
||||
for (var/r_id in allowed)
|
||||
for (var/r_id in allowed)
|
||||
|
||||
var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
|
||||
var/amount = allowed[r_id]
|
||||
if(amount <= 0)
|
||||
if(amount == 0)
|
||||
if (O.reagents != null && O.reagents.has_reagent("nutriment"))
|
||||
beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("nutriment")*efficiency, space))
|
||||
O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space))
|
||||
if (O.reagents != null && O.reagents.has_reagent("plantmatter"))
|
||||
beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("plantmatter")*efficiency, space))
|
||||
O.reagents.remove_reagent("plantmatter", min(O.reagents.get_reagent_amount("plantmatter"), space))
|
||||
else
|
||||
if (O.reagents != null && O.reagents.has_reagent("nutriment"))
|
||||
beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("nutriment")*abs(amount)*efficiency), space))
|
||||
O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space))
|
||||
if (O.reagents != null && O.reagents.has_reagent("plantmatter"))
|
||||
beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("plantmatter")*abs(amount)*efficiency), space))
|
||||
O.reagents.remove_reagent("plantmatter", min(O.reagents.get_reagent_amount("plantmatter"), space))
|
||||
var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
|
||||
var/amount = allowed[r_id]
|
||||
if(amount <= 0)
|
||||
if(amount == 0)
|
||||
if(O.reagents != null && O.reagents.has_reagent("nutriment"))
|
||||
beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("nutriment") * efficiency, space))
|
||||
O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space))
|
||||
if(O.reagents != null && O.reagents.has_reagent("plantmatter"))
|
||||
beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("plantmatter") * efficiency, space))
|
||||
O.reagents.remove_reagent("plantmatter", min(O.reagents.get_reagent_amount("plantmatter"), space))
|
||||
else
|
||||
if(O.reagents != null && O.reagents.has_reagent("nutriment"))
|
||||
beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("nutriment") * abs(amount) * efficiency), space))
|
||||
O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space))
|
||||
if(O.reagents != null && O.reagents.has_reagent("plantmatter"))
|
||||
beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("plantmatter") * abs(amount) * efficiency), space))
|
||||
O.reagents.remove_reagent("plantmatter", min(O.reagents.get_reagent_amount("plantmatter"), space))
|
||||
|
||||
|
||||
else
|
||||
O.reagents.trans_id_to(beaker, r_id, min(amount, space))
|
||||
else
|
||||
O.reagents.trans_id_to(beaker, r_id, min(amount, space))
|
||||
|
||||
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
if(beaker.reagents.holder_full())
|
||||
break
|
||||
|
||||
if(O.reagents.reagent_list.len == 0)
|
||||
remove_object(O)
|
||||
if(O.reagents.reagent_list.len == 0)
|
||||
remove_object(O)
|
||||
|
||||
//Sheets
|
||||
for (var/obj/item/stack/sheet/O in holdingitems)
|
||||
var/allowed = get_allowed_by_id(O)
|
||||
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
for(var/i = 1; i <= round(O.amount, 1); i++)
|
||||
for (var/r_id in allowed)
|
||||
var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
|
||||
var/amount = allowed[r_id]
|
||||
beaker.reagents.add_reagent(r_id,min(amount*efficiency, space))
|
||||
if (space < amount)
|
||||
break
|
||||
if (i == round(O.amount, 1))
|
||||
remove_object(O)
|
||||
break
|
||||
//Plants
|
||||
for (var/obj/item/grown/O in holdingitems)
|
||||
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
var/allowed = get_allowed_by_id(O)
|
||||
for (var/r_id in allowed)
|
||||
var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
|
||||
var/amount = allowed[r_id]
|
||||
if (amount == 0)
|
||||
if (O.reagents != null && O.reagents.has_reagent(r_id))
|
||||
beaker.reagents.add_reagent(r_id,min(O.reagents.get_reagent_amount(r_id)*efficiency, space))
|
||||
else
|
||||
beaker.reagents.add_reagent(r_id,min(amount*efficiency, space))
|
||||
//Sheets and rods(!)
|
||||
for (var/obj/item/stack/O in holdingitems)
|
||||
if(beaker.reagents.holder_full())
|
||||
break
|
||||
|
||||
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
var/allowed = get_allowed_by_id(O)
|
||||
if(isnull(allowed))
|
||||
break
|
||||
|
||||
var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
|
||||
while(O.amount) //Grind until there's no more reagents
|
||||
if(!space) //if no free space - exit
|
||||
break
|
||||
O.amount -= 1 //remove one from stack
|
||||
for (var/r_id in allowed)
|
||||
var/spaceused = min(allowed[r_id] * efficiency, space)
|
||||
space -= spaceused
|
||||
beaker.reagents.add_reagent(r_id, spaceused)
|
||||
if(O.amount < 1) //if leftover small - destroy
|
||||
remove_object(O)
|
||||
break
|
||||
|
||||
//Slime Extractis
|
||||
for (var/obj/item/slime_extract/O in holdingitems)
|
||||
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
|
||||
if (O.reagents != null)
|
||||
var/amount = O.reagents.total_volume
|
||||
O.reagents.trans_to(beaker, min(amount, space))
|
||||
if (O.Uses > 0)
|
||||
beaker.reagents.add_reagent("slimejelly",min(20*efficiency, space))
|
||||
remove_object(O)
|
||||
//Plants
|
||||
for (var/obj/item/grown/O in holdingitems)
|
||||
if(beaker.reagents.holder_full())
|
||||
break
|
||||
var/allowed = get_allowed_by_id(O)
|
||||
for (var/r_id in allowed)
|
||||
var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
|
||||
var/amount = allowed[r_id]
|
||||
if(amount == 0)
|
||||
if(O.reagents != null && O.reagents.has_reagent(r_id))
|
||||
beaker.reagents.add_reagent(r_id,min(O.reagents.get_reagent_amount(r_id) * efficiency, space))
|
||||
else
|
||||
beaker.reagents.add_reagent(r_id,min(amount * efficiency, space))
|
||||
|
||||
//Everything else - Transfers reagents from it into beaker
|
||||
for (var/obj/item/reagent_containers/O in holdingitems)
|
||||
if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
|
||||
break
|
||||
var/amount = O.reagents.total_volume
|
||||
O.reagents.trans_to(beaker, amount)
|
||||
if(!O.reagents.total_volume)
|
||||
remove_object(O)
|
||||
if(beaker.reagents.holder_full())
|
||||
break
|
||||
remove_object(O)
|
||||
|
||||
//Slime Extractis
|
||||
for (var/obj/item/slime_extract/O in holdingitems)
|
||||
if(beaker.reagents.holder_full())
|
||||
break
|
||||
var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume
|
||||
if(O.reagents != null)
|
||||
var/amount = O.reagents.total_volume
|
||||
O.reagents.trans_to(beaker, min(amount, space))
|
||||
if(O.Uses > 0)
|
||||
beaker.reagents.add_reagent("slimejelly",min(20 * efficiency, space))
|
||||
remove_object(O)
|
||||
|
||||
//Everything else - Transfers reagents from it into beaker
|
||||
for (var/obj/item/reagent_containers/O in holdingitems)
|
||||
if(beaker.reagents.holder_full())
|
||||
break
|
||||
var/amount = O.reagents.total_volume
|
||||
O.reagents.trans_to(beaker, amount)
|
||||
if(!O.reagents.total_volume)
|
||||
remove_object(O)
|
||||
|
||||
@@ -568,21 +568,21 @@
|
||||
/datum/reagent/fliptonium/on_mob_life(mob/living/M)
|
||||
var/update_flags = STATUS_UPDATE_NONE
|
||||
if(current_cycle == 5)
|
||||
M.SpinAnimation(speed = 11, loops = -1)
|
||||
M.SpinAnimation(speed = 11, loops = -1, parallel = FALSE)
|
||||
if(current_cycle == 10)
|
||||
M.SpinAnimation(speed = 10, loops = -1)
|
||||
M.SpinAnimation(speed = 10, loops = -1, parallel = FALSE)
|
||||
if(current_cycle == 15)
|
||||
M.SpinAnimation(speed = 9, loops = -1)
|
||||
M.SpinAnimation(speed = 9, loops = -1, parallel = FALSE)
|
||||
if(current_cycle == 20)
|
||||
M.SpinAnimation(speed = 8, loops = -1)
|
||||
M.SpinAnimation(speed = 8, loops = -1, parallel = FALSE)
|
||||
if(current_cycle == 25)
|
||||
M.SpinAnimation(speed = 7, loops = -1)
|
||||
M.SpinAnimation(speed = 7, loops = -1, parallel = FALSE)
|
||||
if(current_cycle == 30)
|
||||
M.SpinAnimation(speed = 6, loops = -1)
|
||||
M.SpinAnimation(speed = 6, loops = -1, parallel = FALSE)
|
||||
if(current_cycle == 40)
|
||||
M.SpinAnimation(speed = 5, loops = -1)
|
||||
M.SpinAnimation(speed = 5, loops = -1, parallel = FALSE)
|
||||
if(current_cycle == 50)
|
||||
M.SpinAnimation(speed = 4, loops = -1)
|
||||
M.SpinAnimation(speed = 4, loops = -1, parallel = FALSE)
|
||||
|
||||
M.AdjustDrowsy(-6)
|
||||
update_flags |= M.AdjustParalysis(-1.5, FALSE)
|
||||
@@ -594,11 +594,11 @@
|
||||
|
||||
/datum/reagent/fliptonium/reaction_mob(mob/living/M, method=REAGENT_TOUCH, volume)
|
||||
if(method == REAGENT_INGEST || method == REAGENT_TOUCH)
|
||||
M.SpinAnimation(speed = 12, loops = -1)
|
||||
M.SpinAnimation(speed = 12, loops = -1, parallel = FALSE)
|
||||
..()
|
||||
|
||||
/datum/reagent/fliptonium/on_mob_delete(mob/living/M)
|
||||
M.SpinAnimation(speed = 12, loops = -1)
|
||||
M.SpinAnimation(speed = 12, loops = -1, parallel = FALSE)
|
||||
|
||||
/datum/reagent/fliptonium/overdose_process(mob/living/M, severity)
|
||||
var/list/overdose_info = ..()
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
current_potion = O
|
||||
to_chat(user, "<span class='notice'>You load [O] in the console's potion slot[replaced ? ", replacing the one that was there before" : ""].</span>")
|
||||
return
|
||||
else if(istype(O, /obj/item/storage/bag))
|
||||
else if(istype(O, /obj/item/storage/bag) || istype(O, /obj/item/storage/box))
|
||||
var/obj/item/storage/P = O
|
||||
var/loaded = 0
|
||||
for(var/obj/item/reagent_containers/food/snacks/monkeycube/MC in P.contents)
|
||||
@@ -191,7 +191,10 @@
|
||||
var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = target
|
||||
|
||||
if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
|
||||
if(iswallturf(remote_eye.loc))
|
||||
to_chat(owner, "You can't place slime here.")
|
||||
return
|
||||
else if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
|
||||
for(var/mob/living/simple_animal/slime/S in X.stored_slimes)
|
||||
S.forceMove(remote_eye.loc)
|
||||
S.visible_message("[S] warps in!")
|
||||
@@ -238,6 +241,12 @@
|
||||
if(LAZYLEN(SSmobs.cubemonkeys) >= GLOB.configuration.general.monkey_cube_cap)
|
||||
to_chat(owner, "<span class='warning'>Bluespace harmonics prevent the spawning of more than [GLOB.configuration.general.monkey_cube_cap] monkeys on the station at one time!</span>")
|
||||
return
|
||||
else if(iswallturf(remote_eye.loc))
|
||||
to_chat(owner, "You can't place monkey here.")
|
||||
return
|
||||
else if(!X.monkeys)
|
||||
to_chat(owner, "[X] doesn't have monkeys.")
|
||||
return
|
||||
else if(X.monkeys >= 1)
|
||||
var/mob/living/carbon/human/monkey/food = new /mob/living/carbon/human/monkey(remote_eye.loc)
|
||||
SSmobs.cubemonkeys += food
|
||||
@@ -323,6 +332,8 @@
|
||||
to_chat(owner, "Ctrl-click a slime to scan it.")
|
||||
to_chat(owner, "Alt-click a slime to feed it a potion.")
|
||||
to_chat(owner, "Ctrl-click or a dead monkey to recycle it, or the floor to place a new monkey.")
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = owner.machine
|
||||
to_chat(owner, "[X] now has [X.monkeys] monkeys left.")
|
||||
|
||||
//
|
||||
// Alternate clicks for slime, monkey and open turf if using a xenobio console
|
||||
@@ -415,7 +426,10 @@
|
||||
var/mob/camera/aiEye/remote/xenobio/E = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
|
||||
var/area/turfarea = get_area(T)
|
||||
if(turfarea.name == E.allowed_area || turfarea.xenobiology_compatible)
|
||||
if(iswallturf(T))
|
||||
to_chat(user, "You can't place slime here.")
|
||||
return
|
||||
else if(turfarea.name == E.allowed_area || turfarea.xenobiology_compatible)
|
||||
for(var/mob/living/simple_animal/slime/S in X.stored_slimes)
|
||||
S.forceMove(T)
|
||||
S.visible_message("<span class='notice'>[S] warps in!</span>")
|
||||
@@ -430,8 +444,10 @@
|
||||
var/mob/camera/aiEye/remote/xenobio/E = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
|
||||
var/area/turfarea = get_area(T)
|
||||
|
||||
if(turfarea.name == E.allowed_area || turfarea.xenobiology_compatible)
|
||||
if(iswallturf(T))
|
||||
to_chat(user, "You can't place monkey here.")
|
||||
return
|
||||
else if(turfarea.name == E.allowed_area || turfarea.xenobiology_compatible)
|
||||
if(X.monkeys >= 1)
|
||||
var/mob/living/carbon/human/monkey/food = new /mob/living/carbon/human/monkey(T)
|
||||
food.LAssailant = C
|
||||
|
||||
@@ -521,6 +521,14 @@
|
||||
visible_message("<b>[src]</b>'s monitor flashes, \"[world.time - reqtime] seconds remaining until another requisition form may be printed.\"")
|
||||
return
|
||||
|
||||
var/datum/supply_packs/P = locateUID(params["crate"])
|
||||
if(!istype(P))
|
||||
return
|
||||
|
||||
if(P.times_ordered >= P.order_limit && P.order_limit != -1) //If the crate has reached the limit, do not allow it to be ordered.
|
||||
to_chat(usr, "<span class='warning'>[P.name] is out of stock, and can no longer be ordered.</span>")
|
||||
return
|
||||
|
||||
var/amount = 1
|
||||
if(params["multiple"] == "1") // 1 is a string here. DO NOT MAKE THIS A BOOLEAN YOU DORK
|
||||
var/num_input = input(usr, "Amount", "How many crates? (20 Max)") as null|num
|
||||
@@ -528,11 +536,6 @@
|
||||
return
|
||||
amount = clamp(round(num_input), 1, 20)
|
||||
|
||||
|
||||
var/datum/supply_packs/P = locateUID(params["crate"])
|
||||
if(!istype(P))
|
||||
return
|
||||
|
||||
var/timeout = world.time + 600 // If you dont type the reason within a minute, theres bigger problems here
|
||||
var/reason = input(usr, "Reason", "Why do you require this item?","") as null|text
|
||||
if(world.time > timeout || !reason || (!is_public && !is_authorized(usr)) || ..())
|
||||
@@ -573,10 +576,13 @@
|
||||
if(SO.ordernum == ordernum)
|
||||
O = SO
|
||||
P = O.object
|
||||
if(SSshuttle.points >= P.cost)
|
||||
if(P.times_ordered >= P.order_limit && P.order_limit != -1) //If this order would put it over the limit, deny it
|
||||
to_chat(usr, "<span class='warning'>[P.name] is out of stock, and can no longer be ordered.</span>")
|
||||
else if(SSshuttle.points >= P.cost)
|
||||
SSshuttle.requestlist.Cut(i,i+1)
|
||||
SSshuttle.points -= P.cost
|
||||
SSshuttle.shoppinglist += O
|
||||
P.times_ordered += 1
|
||||
investigate_log("[key_name(usr)] has authorized an order for [P.name]. Remaining points: [SSshuttle.points].", "cargo")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>There are insufficient supply points for this request.</span>")
|
||||
|
||||
@@ -719,6 +719,9 @@ shutdown_on_reboot = false
|
||||
#_2fa_auth_host = "http://127.0.0.1:8080"
|
||||
# List of IP addresses to be ignored by the world/Topic rate limiting. Useful if you have other services
|
||||
topic_ip_ratelimit_bypass = ["127.0.0.1"]
|
||||
# Turn this to true if you are running a production server
|
||||
is_production = false
|
||||
|
||||
|
||||
################################################################
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 901 KiB After Width: | Height: | Size: 900 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 199 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 11 KiB |