diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index 91bc36feb3..c4f46b5084 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -349,21 +349,3 @@ CREATE TABLE `messages` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; /*!40101 SET character_set_client = @saved_cs_client */; - --- --- Mentor stufs --- - -DROP TABLE IF EXISTS `mentor`; -CREATE TABLE `mentor` ( - `ckey` text NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -DROP TABLE IF EXISTS `mentor_memo`; -CREATE TABLE `mentor_memo` ( - `ckey` varchar(32) NOT NULL, - `memotext` text NOT NULL, - `timestamp` datetime NOT NULL, - `last_editor` varchar(32) DEFAULT NULL, - `edits` text, - PRIMARY KEY (`ckey`) diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 940412d12f..c23d3e5ac7 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -20993,6 +20993,7 @@ /obj/machinery/atmospherics/pipe/simple/supply/hidden{ dir = 5 }, +/obj/structure/chair/stool, /turf/open/floor/plasteel/redyellow, /area/crew_quarters/bar/atrium) "aMI" = ( @@ -24027,6 +24028,7 @@ /area/crew_quarters/bar/atrium) "aRI" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/obj/structure/chair/stool, /turf/open/floor/plasteel/redyellow, /area/crew_quarters/bar/atrium) "aRJ" = ( @@ -78208,7 +78210,7 @@ /turf/closed/wall, /area/maintenance/electrical) "cHL" = ( -/obj/machinery/atmospherics/pipe/manifold/supply/visible{ +/obj/machinery/atmospherics/pipe/manifold/supply/hidden{ tag = "icon-manifold (NORTH)"; icon_state = "manifold"; dir = 1 @@ -107878,15 +107880,6 @@ pixel_y = 3 }, /obj/machinery/atmospherics/pipe/simple/supply/hidden, -/obj/machinery/doorButtons/access_button{ - dir = 1; - idDoor = "virology_airlock_exterior"; - idSelf = "virology_airlock_control"; - name = "Virology Access Button"; - pixel_x = 0; - pixel_y = -24; - req_access_txt = "39" - }, /turf/open/floor/plasteel/whitegreen/corner{ dir = 8 }, @@ -108190,6 +108183,15 @@ name = "Virology Exterior Airlock"; req_access_txt = "39" }, +/obj/machinery/doorButtons/access_button{ + dir = 1; + idDoor = "virology_airlock_exterior"; + idSelf = "virology_airlock_control"; + name = "Virology Access Button"; + pixel_x = -24; + pixel_y = -2; + req_access_txt = "39" + }, /turf/open/floor/plasteel{ tag = "icon-plasteel_warn_side (EAST)" }, @@ -108660,6 +108662,12 @@ /turf/open/floor/plating, /area/medical/virology) "dKi" = ( +/obj/item/weapon/twohanded/required/kirbyplants{ + icon_state = "plant-21"; + layer = 4.1; + pixel_x = -3; + pixel_y = 3 + }, /turf/open/floor/plasteel/whitegreen/corner{ dir = 1 }, @@ -109068,6 +109076,14 @@ name = "Virology Interior Airlock"; req_access_txt = "39" }, +/obj/machinery/doorButtons/access_button{ + idDoor = "virology_airlock_interior"; + idSelf = "virology_airlock_control"; + name = "Virology Access Button"; + pixel_x = 0; + pixel_y = 22; + req_access_txt = "39" + }, /turf/open/floor/plasteel, /area/medical/virology) "dKZ" = ( @@ -118113,8 +118129,8 @@ }, /area/crew_quarters/electronic_marketing_den) "ecc" = ( -/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, -/turf/closed/wall, +/obj/structure/closet/wardrobe/grey, +/turf/open/floor/plasteel/neutral, /area/crew_quarters/electronic_marketing_den) "ecd" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, @@ -118148,23 +118164,29 @@ /turf/open/floor/plasteel, /area/hydroponics/Abandoned_Garden) "ech" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/vent_scrubber{ - dir = 4; - on = 1; - scrub_Toxins = 0 +/obj/machinery/button/door{ + id = "Dorm2"; + name = "Dormitory Door Lock"; + normaldoorcontrol = 1; + pixel_x = -26; + pixel_y = 7; + req_access_txt = "0"; + specialfunctions = 4 }, -/turf/open/floor/plasteel/hydrofloor, -/area/hydroponics/Abandoned_Garden) +/turf/open/floor/wood, +/area/crew_quarters/sleep) "eci" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ - tag = "icon-manifold (EAST)"; - icon_state = "manifold"; - dir = 4 +/obj/machinery/button/door{ + id = "Dorm4"; + name = "Dormitory Door Lock"; + normaldoorcontrol = 1; + pixel_x = -26; + pixel_y = 7; + req_access_txt = "0"; + specialfunctions = 4 }, -/turf/open/floor/plasteel/hydrofloor, -/area/hydroponics/Abandoned_Garden) +/turf/open/floor/wood, +/area/crew_quarters/sleep) "ecj" = ( /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, /turf/open/floor/plasteel/hydrofloor, @@ -118500,102 +118522,51 @@ /obj/machinery/deepfryer, /turf/open/floor/plasteel/red, /area/crew_quarters/kitchen) -"ecc" = ( -/obj/structure/closet/wardrobe/green, -/turf/open/floor/plasteel/neutral/side, -/area/shuttle/arrival) -"ecd" = ( -/obj/machinery/doorButtons/access_button{ +"edc" = ( +/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden, +/turf/closed/wall, +/area/crew_quarters/electronic_marketing_den) +"edd" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/components/unary/vent_scrubber{ dir = 4; - idDoor = "virology_airlock_interior"; - idSelf = "virology_airlock_control"; - name = "Virology Access Button"; - pixel_x = -10; - pixel_y = 0; - req_access_txt = "39" + on = 1; + scrub_Toxins = 0 }, -/turf/closed/wall/r_wall, -/area/medical/virology) -"ece" = ( -/obj/structure/cable/white{ - d2 = 2; - icon_state = "0-2"; - tag = "icon-0-2" - }, -/turf/closed/wall/r_wall, -/area/medical/virology) -"ecf" = ( -/obj/structure/cable/white{ - tag = "icon-4-8"; - icon_state = "4-8" - }, -/obj/structure/cable/white{ - tag = "icon-2-4"; - icon_state = "2-4" - }, -/obj/structure/cable/white{ - tag = "icon-1-4"; - icon_state = "1-4" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 2 +/turf/open/floor/plasteel/hydrofloor, +/area/hydroponics/Abandoned_Garden) +"ede" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{ + tag = "icon-manifold (EAST)"; + icon_state = "manifold"; + dir = 4 }, +/turf/open/floor/plasteel/hydrofloor, +/area/hydroponics/Abandoned_Garden) +"edf" = ( +/obj/structure/table/wood, +/obj/item/clothing/head/hardhat/cakehat, +/turf/open/floor/plasteel/redyellow, +/area/crew_quarters/bar/atrium) +"edg" = ( /obj/machinery/doorButtons/airlock_controller{ idExterior = "virology_airlock_exterior"; idInterior = "virology_airlock_interior"; idSelf = "virology_airlock_control"; name = "Virology Access Console"; - pixel_x = 0; - pixel_y = 22; + pixel_x = -10; + pixel_y = 24; req_access_txt = "39" }, +/obj/structure/cable/white{ + tag = "icon-4-8"; + icon_state = "4-8" + }, /turf/open/floor/plasteel{ tag = "icon-plasteel_warn_side (WEST)" }, /area/medical/virology) -"ecg" = ( -/obj/structure/cable/white, -/turf/closed/wall/r_wall, -/area/medical/virology) -"ech" = ( -/obj/machinery/button/door{ - id = "Dorm2"; - name = "Dormitory Door Lock"; - normaldoorcontrol = 1; - pixel_x = -26; - pixel_y = 7; - req_access_txt = "0"; - specialfunctions = 4 - }, -/turf/open/floor/wood, -/area/crew_quarters/sleep) -"eci" = ( -/obj/machinery/button/door{ - id = "Dorm4"; - name = "Dormitory Door Lock"; - normaldoorcontrol = 1; - pixel_x = -26; - pixel_y = 7; - req_access_txt = "0"; - specialfunctions = 4 - }, -/turf/open/floor/wood, -/area/crew_quarters/sleep) -"ecj" = ( -/obj/item/weapon/reagent_containers/food/condiment/saltshaker{ - pixel_x = -8; - pixel_y = 5 - }, -/obj/item/weapon/reagent_containers/food/condiment/peppermill{ - pixel_x = -8 - }, -/obj/structure/table/wood, -/obj/item/clothing/head/hardhat/cakehat{ - pixel_x = 4; - pixel_y = 3 - }, -/turf/open/floor/plasteel/redyellow, -/area/crew_quarters/bar/atrium) (1,1,1) = {" aaa @@ -149776,7 +149747,7 @@ aic awb awX ayh -ech +edd azo azo aCw @@ -150024,7 +149995,7 @@ alb amb anl aoj -ecc +edc aUJ ecd asz @@ -150033,7 +150004,7 @@ auT awc ecf ecg -eci +ede ecj eck aCx @@ -155695,7 +155666,7 @@ aEf aFB aGX aGY -aGY +aJA aKZ aMI aGY @@ -155950,7 +155921,7 @@ aBF aCP aEg aFC -aGY +aGX aGY aJA aLa @@ -156213,9 +156184,9 @@ aJA aLb aMK aGY -ecj +edf aRH -aGY +aJA aGY aGZ aYv @@ -165305,7 +165276,7 @@ dGR cKs cKs dJl -ecd +dJp dKY dJp dJp @@ -165562,9 +165533,9 @@ dGS cDe aaa aaa -ece -ecf -ecg +dJp +edg +dJp aaa aaa dJp @@ -168866,8 +168837,8 @@ cEq cGb cHs cvP -cCg eci +cCg cNS cxw cvP diff --git a/code/__DEFINES/clockcult.dm b/code/__DEFINES/clockcult.dm index d97dbc6cf5..8b140cb8b7 100644 --- a/code/__DEFINES/clockcult.dm +++ b/code/__DEFINES/clockcult.dm @@ -87,9 +87,9 @@ var/global/list/all_scripture = list() //a list containing scripture instances; #define CLOCKCULT_ESCAPE "escape" -#define CLOCKCULT_SILICONS "silicons" - //misc clockcult stuff #define MARAUDER_EMERGE_THRESHOLD 65 //marauders cannot emerge unless host is at this% or less health #define SIGIL_ACCESS_RANGE 2 //range at which transmission sigils can access power + +#define PROSELYTIZER_REPAIR_PER_TICK 4 //how much a proselytizer repairs each tick, and also how many deciseconds each tick is diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 4424f05436..d4acb7f4b4 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -408,4 +408,4 @@ var/global/list/ghost_others_options = list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE #define TURF_DECAL_PAINT "paint" #define TURF_DECAL_DAMAGE "damage" -#define TURF_DECAL_DIRT "dirt" \ No newline at end of file +#define TURF_DECAL_DIRT "dirt" diff --git a/code/__DEFINES/monkeys.dm b/code/__DEFINES/monkeys.dm index 76f7ea850c..52ef4b5590 100644 --- a/code/__DEFINES/monkeys.dm +++ b/code/__DEFINES/monkeys.dm @@ -35,4 +35,4 @@ #define MONKEY_HUNT_FRUSTRATION_LIMIT 8 // Chase after an enemy before giving up #define MONKEY_DISPOSE_FRUSTRATION_LIMIT 16 // Dispose of a body before giving up -#define MONKEY_AGGRESSIVE_MVM_PROB 1 // If you mass edit monkies to be aggressive. there is a small chance of in-fighting \ No newline at end of file +#define MONKEY_AGGRESSIVE_MVM_PROB 0 // If you mass edit monkies to be aggressive. there is a small chance of in-fighting \ No newline at end of file diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index ae1f2b26ec..5e82a8ab26 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -465,3 +465,4 @@ #define LAZYADD(L, I) if(!L) { L = list(); } L += I; #define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null) #define LAZYLEN(L) length(L) +#define LAZYCLEARLIST(L) if(L) L.Cut() \ No newline at end of file diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index b301fab1c3..4036470cf7 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -38,6 +38,8 @@ var/turf_visible if(pixel_turf) turf_visible = cameranet.checkTurfVis(pixel_turf) + if(istype(loc, /obj/item/device/aicard) && (pixel_turf in view(client.view, loc))) + turf_visible = TRUE if(!turf_visible) log_admin("[key_name_admin(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([COORD(pixel_turf)])") message_admins("[key_name_admin(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([ADMIN_COORDJMP(pixel_turf)]))") @@ -184,4 +186,4 @@ // /mob/living/silicon/ai/TurfAdjacent(var/turf/T) - return (cameranet && cameranet.checkTurfVis(T)) + return (cameranet && cameranet.checkTurfVis(T)) \ No newline at end of file diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 18fc45bb47..8a8faea5c4 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -20,8 +20,8 @@ var/name = "Configuration" // datum name var/server_name = null // server name (the name of the game window) + var/server_sql_name = null // short form server name used for the DB var/station_name = null // station name (the name of the station in-game) - var/server_suffix = 0 // generate numeric suffix based on server port var/lobby_countdown = 120 // In between round countdown. var/round_end_countdown = 25 // Post round murder death kill countdown var/hub = 0 @@ -78,8 +78,7 @@ var/forbid_singulo_possession = 0 var/useircbot = 0 - var/announce_watchlist = 0 - var/announce_adminhelps = 0 + var/check_randomizer = 0 var/allow_panic_bunker_bounce = 0 //Send new players somewhere else @@ -95,6 +94,11 @@ var/mentors_mobname_only = 0 // Only display mob name to mentors in mentorhelps var/mentor_legacy_system = 0 // Whether to use the legacy mentor system (flat file) instead of SQL + // Discord crap. + var/discord_url = "hfdksjhfa.com" + var/discord_password + var/announce_watchlist = 0 + var/announce_adminhelps = 0 var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt @@ -242,10 +246,6 @@ var/list/gamemode_cache = null - // Discord crap. - var/discord_url = "hfdksjhfa.com" - var/discord_password - var/minutetopiclimit var/secondtopiclimit @@ -359,10 +359,10 @@ config.respawn = 0 if("servername") config.server_name = value + if("serversqlname") + config.server_sql_name = 1 if("stationname") config.station_name = value - if("serversuffix") - config.server_suffix = 1 if("hostedby") config.hostedby = value if("server") @@ -499,16 +499,16 @@ config.client_error_version = text2num(value) if("client_error_message") config.client_error_message = value + if("minute_topic_limit") + config.minutetopiclimit = text2num(value) + if("second_topic_limit") + config.secondtopiclimit = text2num(value) if("announce_adminhelps") config.announce_adminhelps = 1 if("discord_url") config.discord_url = value if("discord_password") config.discord_password = value - if("minute_topic_limit") - config.minutetopiclimit = text2num(value) - if("second_topic_limit") - config.secondtopiclimit = text2num(value) else diary << "Unknown setting in configuration: '[name]'" diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 86d1a4672e..dd88760e5f 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -322,6 +322,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING SS_flags = SS.flags if (SS_flags & SS_NO_FIRE) subsystemstocheck -= SS + continue if (!(SS_flags & SS_TICKER) && (SS_flags & SS_KEEP_TIMING) && SS.last_fire + (SS.wait * 0.75) > world.time) continue SS.enqueue() diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 5eb987f2f3..ab6cb29061 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -39,28 +39,34 @@ var/datum/subsystem/air/SSair var/list/currentrun = list() var/currentpart = SSAIR_PIPENETS + var/map_loading = TRUE + var/list/queued_for_activation /datum/subsystem/air/New() NEW_SS_GLOBAL(SSair) /datum/subsystem/air/stat_entry(msg) msg += "C:{" - msg += "AT:[round(cost_turfs)]|" - msg += "EG:[round(cost_groups)]|" - msg += "HP:[round(cost_highpressure)]|" - msg += "HS:[round(cost_hotspots)]|" - msg += "SC:[round(cost_superconductivity)]|" - msg += "PN:[round(cost_pipenets)]|" - msg += "AM:[round(cost_atmos_machinery)]" + msg += "AT:[round(cost_turfs,1)]|" + msg += "EG:[round(cost_groups,1)]|" + msg += "HP:[round(cost_highpressure,1)]|" + msg += "HS:[round(cost_hotspots,1)]|" + msg += "SC:[round(cost_superconductivity,1)]|" + msg += "PN:[round(cost_pipenets,1)]|" + msg += "AM:[round(cost_atmos_machinery,1)]" msg += "} " - msg += "AT:[active_turfs.len]|" - msg += "EG:[excited_groups.len]|" - msg += "HS:[hotspots.len]|" - msg += "AS:[active_super_conductivity.len]" + msg += "AT:[active_turfs.len]|" + msg += "EG:[excited_groups.len]|" + msg += "HS:[hotspots.len]|" + msg += "PN:[networks.len]|" + msg += "HP:[high_pressure_delta.len]|" + msg += "AS:[active_super_conductivity.len]|" + msg += "AT/MS:[round((cost ? active_turfs.len/cost : 0),0.1)]" ..(msg) /datum/subsystem/air/Initialize(timeofday) + map_loading = FALSE setup_allturfs() setup_atmos_machinery() setup_pipenets() @@ -244,7 +250,6 @@ var/datum/subsystem/air/SSair if(T.excited_group) T.excited_group.garbage_collect() - /datum/subsystem/air/proc/add_to_active(turf/open/T, blockchanges = 1) if(istype(T) && T.air) T.excited = 1 @@ -253,10 +258,25 @@ var/datum/subsystem/air/SSair currentrun |= T if(blockchanges && T.excited_group) T.excited_group.garbage_collect() - else + else if(T.initialized) for(var/turf/S in T.atmos_adjacent_turfs) add_to_active(S) + else if(map_loading) + if(queued_for_activation) + queued_for_activation[T] = T + return + else + T.requires_activation = TRUE +/datum/subsystem/air/proc/begin_map_load() + LAZYINITLIST(queued_for_activation) + map_loading = TRUE + +/datum/subsystem/air/proc/end_map_load() + map_loading = FALSE + for(var/T in queued_for_activation) + add_to_active(T) + queued_for_activation.Cut() /datum/subsystem/air/proc/setup_allturfs() var/list/turfs_to_init = block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz)) diff --git a/code/controllers/subsystem/processing/objects.dm b/code/controllers/subsystem/processing/objects.dm index 01957e766f..6bbd0ffeb3 100644 --- a/code/controllers/subsystem/processing/objects.dm +++ b/code/controllers/subsystem/processing/objects.dm @@ -27,26 +27,52 @@ var/datum/subsystem/objects/SSobj /datum/subsystem/objects/proc/InitializeAtoms(list/objects = null) if(initialized == INITIALIZATION_INSSOBJ) return + + var/list/late_loaders + initialized = INITIALIZATION_INNEW_MAPLOAD + if(objects) for(var/I in objects) var/atom/A = I if(!A.initialized) //this check is to make sure we don't call it twice on an object that was created in a previous Initialize call var/start_tick = world.time - A.Initialize(TRUE) + if(A.Initialize(TRUE)) + LAZYADD(late_loaders, A) if(start_tick != world.time) WARNING("[A]: [A.type] slept during it's Initialize!") CHECK_TICK + testing("Initialized [objects.len] atoms") else + #ifdef TESTING + var/count = 0 + #endif for(var/atom/A in world) if(!A.initialized) //this check is to make sure we don't call it twice on an object that was created in a previous Initialize call var/start_tick = world.time - A.Initialize(TRUE) + if(A.Initialize(TRUE)) + LAZYADD(late_loaders, A) + #ifdef TESTING + else + ++count + #endif TESTING if(start_tick != world.time) WARNING("[A]: [A.type] slept during it's Initialize!") CHECK_TICK + testing("Roundstart initialized [count] atoms") + initialized = INITIALIZATION_INNEW_REGULAR + if(late_loaders) + for(var/I in late_loaders) + var/atom/A = I + var/start_tick = world.time + A.Initialize(FALSE) + if(start_tick != world.time) + WARNING("[A]: [A.type] slept during it's Initialize!") + CHECK_TICK + testing("Late-initialized [late_loaders.len] atoms") + /datum/subsystem/objects/proc/map_loader_begin() old_initialized = initialized initialized = INITIALIZATION_INSSOBJ diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index 56d887eb8b..2b23ac485a 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -66,11 +66,11 @@ var/datum/subsystem/throwing/SSthrowing /datum/thrownthing/proc/tick() var/atom/movable/AM = thrownthing if (!isturf(AM.loc) || !AM.throwing) - finialize() + finalize() return if (dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept - finialize() + finalize() return var/atom/step @@ -79,7 +79,7 @@ var/datum/subsystem/throwing/SSthrowing var/tilestomove = round(min(((((world.time+world.tick_lag) - start_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait)) while (tilestomove-- > 0) if ((dist_travelled >= maxrange || AM.loc == target_turf) && AM.has_gravity(AM.loc)) - finialize() + finalize() return if (dist_travelled <= max(dist_x, dist_y)) //if we haven't reached the target yet we home in on it, otherwise we use the initial direction @@ -93,47 +93,52 @@ var/datum/subsystem/throwing/SSthrowing diagonal_error += (diagonal_error < 0) ? dist_x/2 : -dist_y if (!step) // going off the edge of the map makes get_step return null, don't let things go off the edge - finialize() + finalize() return AM.Move(step, get_dir(AM, step)) if (!AM.throwing) // we hit something during our move - finialize(hit = TRUE) + finalize(hit = TRUE) return dist_travelled++ if (dist_travelled > MAX_THROWING_DIST) - finialize() + finalize() return -/datum/thrownthing/proc/finialize(hit = FALSE) +/datum/thrownthing/proc/finalize(hit = FALSE) set waitfor = 0 SSthrowing.processing -= thrownthing //done throwing, either because it hit something or it finished moving - thrownthing.throwing = 0 + thrownthing.throwing = null if (!hit) for (var/thing in get_turf(thrownthing)) //looking for our target on the turf we land on. var/atom/A = thing if (A == target) hit = 1 - thrownthing.throw_impact(A) + thrownthing.throw_impact(A, src) break if (!hit) - thrownthing.throw_impact(get_turf(thrownthing)) // we haven't hit something yet and we still must, let's hit the ground. + thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground. thrownthing.newtonian_move(init_dir) else thrownthing.newtonian_move(init_dir) if (callback) callback.Invoke() +/datum/thrownthing/proc/hit_atom(atom/A) + thrownthing.throw_impact(A, src) + thrownthing.newtonian_move(init_dir) + finalize(TRUE) + /datum/thrownthing/proc/hitcheck() for (var/thing in get_turf(thrownthing)) var/atom/movable/AM = thing if (AM == thrownthing) continue if (AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags & ON_BORDER)) - thrownthing.throwing = 0 - thrownthing.throw_impact(AM) - return 1 + thrownthing.throwing = null + thrownthing.throw_impact(AM, src) + return TRUE diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm index e226aff2c8..08fd4f60c0 100644 --- a/code/datums/helper_datums/getrev.dm +++ b/code/datums/helper_datums/getrev.dm @@ -9,7 +9,10 @@ var/global/datum/getrev/revdata = new() /datum/getrev/New() var/head_file = return_file_text(".git/logs/HEAD") if(SERVERTOOLS && fexists("..\\prtestjob.lk")) - testmerge = file2list("..\\prtestjob.lk") + var/list/tmp = file2list("..\\prtestjob.lk") + for(var/I in tmp) + if(I) + testmerge |= I var/testlen = max(testmerge.len - 1, 0) var/regex/head_log = new("(\\w{40}) .+> (\\d{10}).+(?=(\n.*(\\w{40}).*){[testlen]}\n*\\Z)") head_log.Find(head_file) @@ -81,4 +84,4 @@ var/global/datum/getrev/revdata = new() if(config.probabilities[ctag] > 0) var/percentage = round(config.probabilities[ctag] / sum * 100, 0.1) src << "[ctag] [percentage]%" - return \ No newline at end of file + return diff --git a/code/datums/helper_datums/map_template.dm b/code/datums/helper_datums/map_template.dm index 19f9c1ff0d..1912be6a27 100644 --- a/code/datums/helper_datums/map_template.dm +++ b/code/datums/helper_datums/map_template.dm @@ -31,6 +31,7 @@ for(var/L in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]), locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ]))) var/turf/B = L + atoms += B for(var/A in B) atoms += A if(istype(A,/obj/structure/cable)) @@ -43,6 +44,7 @@ SSobj.InitializeAtoms(atoms) SSmachine.setup_template_powernets(cables) SSair.setup_template_machinery(atmos_machines) + SSair.end_map_load() /datum/map_template/proc/load(turf/T, centered = FALSE) if(centered) @@ -54,8 +56,10 @@ if(T.y+height > world.maxy) return + SSair.begin_map_load() var/list/bounds = maploader.load_map(get_file(), T.x, T.y, T.z, cropMap=TRUE) if(!bounds) + SSair.end_map_load() return 0 //initialize things that are normally initialized after map load diff --git a/code/datums/riding.dm b/code/datums/riding.dm index 9695dbae12..27911b88df 100644 --- a/code/datums/riding.dm +++ b/code/datums/riding.dm @@ -297,3 +297,75 @@ handle_vehicle_offsets() else user << "You'll need something to guide the [ridden.name]." + +//CYBORGS. NO, THEY ARE NOT ANIMALS. +/datum/riding/cyborg + keytype = null + vehicle_move_delay = 1 + +/datum/riding/cyborg/proc/ride_check(mob/user) + if(user.incapacitated()) + var/kick = TRUE + if(istype(ridden, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = ridden + if(R.module && R.module.ride_allow_incapacitated) + kick = FALSE + if(kick) + user << "You fall off of [ridden]!" + ridden.unbuckle_mob(user) + return + if(istype(user, /mob/living/carbon)) + var/mob/living/carbon/carbonuser = user + if(!carbonuser.get_num_arms()) + ridden.unbuckle_mob(user) + user << "You can't grab onto [ridden] with no hands!" + return + +/datum/riding/cyborg/handle_vehicle_layer() + if(ridden.dir == SOUTH) + ridden.layer = ABOVE_MOB_LAYER + else + ridden.layer = OBJ_LAYER + if(!ridden.buckled_mobs) + ridden.layer = MOB_LAYER + +/datum/riding/cyborg/handle_vehicle_offsets() + if(ridden.has_buckled_mobs()) + for(var/mob/living/M in ridden.buckled_mobs) + M.setDir(ridden.dir) + if(iscyborg(ridden)) + var/mob/living/silicon/robot/R = ridden + if(istype(R.module)) + M.pixel_x = R.module.ride_offset_x[dir2text(ridden.dir)] + M.pixel_y = R.module.ride_offset_y[dir2text(ridden.dir)] + else + switch(ridden.dir) + if(NORTH) + M.pixel_x = 0 + M.pixel_y = 4 + if(SOUTH) + M.pixel_x = 0 + M.pixel_y = 4 + if(EAST) + M.pixel_x = -6 + M.pixel_y = 3 + if(WEST) + M.pixel_x = 6 + M.pixel_y = 3 + +/datum/riding/cyborg/proc/on_vehicle_move() + for(var/mob/living/M in ridden.buckled_mobs) + ride_check(M) + handle_vehicle_offsets() + handle_vehicle_layer() + +/datum/riding/cyborg/proc/force_dismount() + for(var/mob/living/M in ridden.buckled_mobs) + ridden.unbuckle_mob(M) + var/turf/target = get_edge_target_turf(ridden, ridden.dir) + var/turf/targetm = get_step(get_turf(ridden), ridden.dir) + M.Move(targetm) + M.visible_message("[M] is thrown clear of [ridden] by rapid spinning!") + M.throw_at(target, 14, 5, ridden) + M.Weaken(3) + diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm index 911a37280a..aac65a7a44 100644 --- a/code/datums/shuttles.dm +++ b/code/datums/shuttles.dm @@ -73,6 +73,19 @@ admin_notes = "Due to the limited space for non paying crew, this shuttle may cause a riot." credit_cost = 10000 + +/datum/map_template/shuttle/emergency/arena + suffix = "arena" + name = "The Arena" + description = "The crew must pass through an otherworldy arena to board this shuttle. Expect massive casualties. The source of the Bloody Signal must be tracked down and eliminated to unlock this shuttle." + admin_notes = "RIP AND TEAR." + credit_cost = 10000 + +/datum/map_template/shuttle/emergency/arena/prerequisites_met() + if("bubblegum" in SSshuttle.shuttle_purchase_requirements_met) + return TRUE + return FALSE + /datum/map_template/shuttle/emergency/birdboat suffix = "birdboat" name = "Birdboat Station Emergency Shuttle" @@ -104,7 +117,6 @@ \n\ Contains contraband armory guns, maintenance loot, and abandoned crates!" admin_notes = "Due to origin as a solo piloted secure vessel, has an active GPS onboard labeled STV5." - credit_cost = -7500 /datum/map_template/shuttle/emergency/meta suffix = "meta" @@ -160,8 +172,8 @@ /datum/map_template/shuttle/emergency/goon suffix = "goon" name = "NES Port" - description = "The Nanotrasen Emergency Shuttle Port(NES Port for short) is a shuttle used at other less known nanotrasen facilities and has a more open inside for larger crowds." - credit_cost = 3000 + description = "The Nanotrasen Emergency Shuttle Port(NES Port for short) is a shuttle used at other less known Nanotrasen facilities and has a more open inside for larger crowds, but fewer onboard shuttle facilities." + credit_cost = 500 /datum/map_template/shuttle/emergency/wabbajack suffix = "wabbajack" @@ -219,4 +231,4 @@ name = "Delta Station Emergency Shuttle" description = "A large shuttle for a large station, this shuttle can comfortably fit all your overpopulation and crowding needs. Complete with all facilities plus additional equipment." admin_notes = "Go big or go home." - credit_cost = 7500 + credit_cost = 7500 \ No newline at end of file diff --git a/code/game/atoms.dm b/code/game/atoms.dm index b7289f58b4..4df19f3201 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -41,11 +41,26 @@ if(luminosity) light = new(src) - var/initialized = SSobj.initialized - if(initialized > INITIALIZATION_INSSOBJ) - Initialize(initialized == INITIALIZATION_INNEW_MAPLOAD) + var/do_initialize = SSobj.initialized + if(do_initialize > INITIALIZATION_INSSOBJ) + Initialize(do_initialize == INITIALIZATION_INNEW_MAPLOAD) //. = ..() //uncomment if you are dumb enough to add a /datum/New() proc +//Called after New if the map is being loaded. mapload = TRUE +//Called from base of New if the map is being loaded. mapload = FALSE +//This base must be called or derivatives must set initialized to TRUE to prevent repeat calls +//Derivatives must not sleep +//Returning TRUE while mapload is TRUE will cause the object to be initialized again with mapload = FALSE when everything else is done +//(Useful for things that requires turfs to have air). This base may only be called once, however + +//Note: the following functions don't call the base for optimization and must copypasta: +// /turf/Initialize +// /turf/open/space/Initialize +/atom/proc/Initialize(mapload) + if(initialized) + stack_trace("Warning: [src]([type]) initialized multiple times!") + initialized = TRUE + /atom/Destroy() if(alternate_appearances) for(var/aakey in alternate_appearances) @@ -435,17 +450,6 @@ var/list/blood_splatter_icons = list() sleep(1) stoplag() -//Called after New if the world is not loaded with TRUE -//Called from base of New if the world is loaded with FALSE -//This base must be called or derivatives must set initialized to TRUE to prevent repeat calls -//Derivatives must not sleep -/atom/proc/Initialize(mapload) -#ifdef TESTING - if(initialized) - stack_trace("Warning: [src]([type]) initialized multiple times!") -#endif - initialized = TRUE - //the vision impairment to give to the mob whose perspective is set to that atom (e.g. an unfocused camera giving you an impaired vision when looking through it) /atom/proc/get_remote_view_fullscreens(mob/user) return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 7331123317..2984cb38d8 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -2,7 +2,7 @@ layer = OBJ_LAYER var/last_move = null var/anchored = 0 - var/throwing = 0 + var/datum/thrownthing/throwing = null var/throw_speed = 2 //How many tiles to move per ds when being thrown. Float values are fully supported var/throw_range = 7 var/mob/pulledby = null @@ -130,14 +130,12 @@ /atom/movable/Bump(atom/A, yes) //the "yes" arg is to differentiate our Bump proc from byond's, without it every Bump() call would become a double Bump(). if((A && yes)) if(throwing) - throwing = 0 - throw_impact(A) + throwing.hit_atom(A) . = 1 if(!A || QDELETED(A)) return A.Bumped(src) - /atom/movable/proc/forceMove(atom/destination) if(destination) if(pulledby) @@ -222,7 +220,7 @@ /atom/movable/proc/checkpass(passflag) return pass_flags&passflag -/atom/movable/proc/throw_impact(atom/hit_atom) +/atom/movable/proc/throw_impact(atom/hit_atom, throwingdatum) return hit_atom.hitby(src) /atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked) @@ -297,7 +295,7 @@ if(pulledby) pulledby.stop_pulling() - throwing = 1 + throwing = TT if(spin) SpinAnimation(5, 1) diff --git a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm index eb1f6626c0..b361e47d64 100644 --- a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm +++ b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm @@ -22,6 +22,7 @@ E.sight_flags -= SEE_MOBS E.flash_protect = 2 user << "We adjust our eyes to protect them from bright lights." + user.update_sight() else user << "We can't adjust our eyes if we don't have any!" diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm index 1b3e59e518..e470a4eca9 100644 --- a/code/game/gamemodes/changeling/powers/mutations.dm +++ b/code/game/gamemodes/changeling/powers/mutations.dm @@ -150,7 +150,7 @@ icon = 'icons/obj/weapons.dmi' icon_state = "arm_blade" item_state = "arm_blade" - flags = ABSTRACT | NODROP + flags = ABSTRACT | NODROP | DROPDEL w_class = WEIGHT_CLASS_HUGE force = 25 throwforce = 0 //Just to be on the safe side @@ -203,7 +203,6 @@ ..() if(can_drop) new /obj/item/weapon/melee/synthetic_arm_blade(get_turf(user)) - qdel(src) /***************************************\ |***********COMBAT TENTACLES*************| @@ -303,11 +302,10 @@ for(var/obj/item/I in H.held_items) if(I.is_sharp()) C.visible_message("[H] impales [C] with [H.p_their()] [I.name]!", "[H] impales you with [H.p_their()] [I.name]!") - C.apply_damage(I.force*2, BRUTE, "chest") + C.apply_damage(I.force, BRUTE, "chest") H.do_item_attack_animation(C, used_item = I) H.add_mob_blood(C) playsound(get_turf(H),I.hitsound,75,1) - C.Weaken(4) return /obj/item/projectile/tentacle/on_hit(atom/target, blocked = 0) @@ -355,7 +353,6 @@ if(INTENT_HARM) C.visible_message("[L] is thrown towards [H] by a tentacle!","A tentacle grabs you and throws you towards [H]!") - C.Weaken(3) C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(src, .proc/tentacle_stab, H, C)) return 1 else diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index 693f74d871..5e70ce0a6f 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -84,8 +84,6 @@ Credit where due: /datum/game_mode var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar - var/required_escapees = 0 //How many servants need to escape, if applicable - var/required_silicon_converts = 0 //How many robotic lifeforms need to be converted, if applicable var/clockwork_objective = CLOCKCULT_GATEWAY //The objective that the servants must fulfill var/clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar." //The description of the current objective @@ -141,20 +139,12 @@ Credit where due: /datum/game_mode/clockwork_cult/proc/forge_clock_objectives() //Determine what objective that Ratvar's servants will fulfill var/list/possible_objectives = list(CLOCKCULT_ESCAPE, CLOCKCULT_GATEWAY) - var/silicons_possible = FALSE - for(var/mob/living/silicon/ai/S in living_mob_list) - silicons_possible = TRUE - if(silicons_possible) - possible_objectives += CLOCKCULT_SILICONS clockwork_objective = pick(possible_objectives) switch(clockwork_objective) if(CLOCKCULT_ESCAPE) - required_escapees = round(max(1, roundstart_player_count / 3)) //33% of the player count must be cultists - clockwork_explanation = "Ensure that [required_escapees] servants of Ratvar escape from [station_name()]." + clockwork_explanation = "Construct a Gateway to the Celestial Derelict and proselytize the entire station." if(CLOCKCULT_GATEWAY) clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar." - if(CLOCKCULT_SILICONS) - clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar and Application scripture is unlocked." return 1 /datum/game_mode/clockwork_cult/proc/greet_servant(mob/M) //Description of their role @@ -199,27 +189,8 @@ Credit where due: /datum/game_mode/clockwork_cult/proc/check_clockwork_victory() switch(clockwork_objective) if(CLOCKCULT_ESCAPE) - var/surviving_servants = 0 - for(var/datum/mind/M in servants_of_ratvar) - if(M.current && M.current.stat != DEAD && (M.current.onCentcom() || M.current.onSyndieBase())) - surviving_servants++ - clockwork_explanation = "Ensure that [required_escapees] servant(s) of Ratvar escape from [station_name()].
[surviving_servants] managed to escape!" - if(surviving_servants >= required_escapees) - ticker.news_report = CULT_ESCAPE - return TRUE - if(CLOCKCULT_SILICONS) - var/total_silicons = 0 - var/valid_silicons = 0 - for(var/mob/living/silicon/S in mob_list) //Only check robots and AIs - if(isAI(S) || iscyborg(S)) - total_silicons++ - if(is_servant_of_ratvar(S) || S.stat == DEAD) - valid_silicons++ - clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar and Application scripture is unlocked.
\ - [valid_silicons]/[total_silicons] silicons were killed or converted!" - var/list/scripture_states = scripture_unlock_check() - if(valid_silicons >= total_silicons && scripture_states[SCRIPTURE_APPLICATION]) - ticker.news_report = CLOCK_SILICONS + if(clockwork_gateway_activated) + ticker.news_report = CLOCK_PROSELYTIZATION return TRUE if(CLOCKCULT_GATEWAY) if(ratvar_awakens) @@ -241,18 +212,16 @@ Credit where due: feedback_set_details("round_end_result", "win - servants completed their objective ([clockwork_objective])") else var/half_victory = FALSE - if(clockwork_objective == CLOCKCULT_GATEWAY) - var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = locate() in all_clockwork_objects - if(G) - half_victory = TRUE + var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = locate() in all_clockwork_objects + if(G) + half_victory = TRUE if(half_victory) - text += "The crew escaped before Ratvar could rise, but the gateway was successfully constructed!" + text += "The crew escaped before [clockwork_objective == CLOCKCULT_GATEWAY ? "Ratvar could rise":"the station could be proselytized"], but the gateway \ + was successfully constructed!" feedback_set_details("round_end_result", "halfwin - round ended before the gateway finished") else text += "Ratvar's servants have failed!" feedback_set_details("round_end_result", "loss - servants failed their objective ([clockwork_objective])") - if(clockwork_gateway_activated && clockwork_objective != CLOCKCULT_GATEWAY) - ticker.news_report = CLOCK_PROSELYTIZATION text += "
The servants' objective was:
[clockwork_explanation]" text += "
Ratvar's servants had [clockwork_caches] Tinkerer's Caches." text += "
Construction Value(CV) was: [clockwork_construction_value]" diff --git a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm index 3822cc35a2..42c4a418c7 100644 --- a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm +++ b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm @@ -159,11 +159,10 @@ /obj/effect/clockwork/sigil/submission/accession/post_channel(mob/living/L) if(L.isloyal()) - var/mob/living/carbon/C = L delete_on_finish = TRUE - C.visible_message("[C] visibly trembles!", \ + L.visible_message("[L] visibly trembles!", \ "[text2ratvar("You will be mine and his. This puny trinket will not stop me.")]") - for(var/obj/item/weapon/implant/mindshield/M in C.implants) + for(var/obj/item/weapon/implant/mindshield/M in L.implants) qdel(M) diff --git a/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm b/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm index a77580b2f9..6338f759a9 100644 --- a/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm +++ b/code/game/gamemodes/clock_cult/clock_helpers/proselytizer_helpers.dm @@ -159,7 +159,7 @@ /obj/item/stack/tile/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) if(source) return FALSE - return list("operation_time" = amount, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_FLOOR), "spawn_dir" = SOUTH) + return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_FLOOR), "spawn_dir" = SOUTH) //Airlock conversion /obj/machinery/door/airlock/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) @@ -263,42 +263,18 @@ //Hitting a clockwork structure will try to repair it. /obj/structure/destructible/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) . = TRUE - if(!can_be_repaired) - user << "[src] cannot be repaired!" - return - if(obj_integrity >= max_integrity) - user << "[src] is at maximum integrity!" - return - var/amount_to_heal = max_integrity - obj_integrity - var/healing_for_cycle = min(amount_to_heal, repair_amount) - var/power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER) - if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required))) - user << "You need at least [power_required]W power to start repairing [src], and at least \ - [round(amount_to_heal*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]W to fully repair it!" + var/list/repair_values = list() + if(!proselytizer.proselytizer_repair_checks(repair_values, src, user)) return user.visible_message("[user]'s [proselytizer.name] starts covering [src] in glowing orange energy...", \ "You start repairing [src]...") - //hugeass while because we need to re-check after the do_after proselytizer.repairing = src - while(proselytizer && user && src && obj_integrity < max_integrity) - amount_to_heal = max_integrity - obj_integrity - if(amount_to_heal <= 0) + while(proselytizer && user && src) + if(!do_after(user, repair_values["healing_for_cycle"] * proselytizer.speed_multiplier, target = src, \ + extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytizer_repair_checks, repair_values, src, user, TRUE))) break - healing_for_cycle = min(amount_to_heal, repair_amount) - power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER) - if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)) || \ - !do_after(user, healing_for_cycle * proselytizer.speed_multiplier, target = src) || \ - !proselytizer || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required))) - break - amount_to_heal = max_integrity - obj_integrity - if(amount_to_heal <= 0) - break - healing_for_cycle = min(amount_to_heal, repair_amount) - power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER) - if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required))) - break - obj_integrity = Clamp(obj_integrity + healing_for_cycle, 0, max_integrity) - proselytizer.modify_stored_power(-power_required) + obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity) + proselytizer.modify_stored_power(-repair_values["power_required"]) playsound(src, 'sound/machines/click.ogg', 50, 1) if(proselytizer) @@ -309,42 +285,18 @@ //Proselytizer mob heal proc, to avoid as much copypaste as possible. /mob/living/proc/proselytizer_heal(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) - if(!is_servant_of_ratvar(src)) - user << "[src] does not serve Ratvar!" - return FALSE - if(health >= maxHealth || (flags & GODMODE)) - user << "[src == user ? "You" : "[src]"] [src == user ? "are" : "is"] at maximum health!" - return FALSE - var/amount_to_heal = maxHealth - health - var/healing_for_cycle = min(amount_to_heal, 4) - var/power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER) - if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required))) - user << "You need at least [power_required]W power to start repairing[src == user ? " yourself" : " [src]"], and at least \ - [round(amount_to_heal*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]W to fully repair [src == user ? "yourself" : "[p_them()]"]!" - return FALSE + var/list/repair_values = list() + if(!proselytizer.proselytizer_repair_checks(repair_values, src, user)) + return user.visible_message("[user]'s [proselytizer.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...", \ "You start repairin[src == user ? "g yourself" : "g [src]"]...") - //hugeass while because we need to re-check after the do_after proselytizer.repairing = src - while(proselytizer && user && src && health < maxHealth) - amount_to_heal = maxHealth - health - if(amount_to_heal <= 0) + while(proselytizer && user && src) + if(!do_after(user, repair_values["healing_for_cycle"] * proselytizer.speed_multiplier, target = src, \ + extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytizer_repair_checks, repair_values, src, user, TRUE))) break - healing_for_cycle = min(amount_to_heal, 4) - power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER) - if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required)) || \ - !do_after(user, healing_for_cycle * proselytizer.speed_multiplier, target = src) || \ - !proselytizer || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required))) - break - amount_to_heal = maxHealth - health - if(amount_to_heal <= 0) - break - healing_for_cycle = min(amount_to_heal, 4) - power_required = round(healing_for_cycle*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER) - if(!healing_for_cycle || (!proselytizer.can_use_power(RATVAR_POWER_CHECK) && !proselytizer.can_use_power(power_required))) - break - proselytizer_heal_tick(healing_for_cycle) - proselytizer.modify_stored_power(-power_required) + proselytizer_heal_tick(repair_values["healing_for_cycle"]) + proselytizer.modify_stored_power(-repair_values["power_required"]) playsound(src, 'sound/machines/click.ogg', 50, 1) if(proselytizer) @@ -382,14 +334,17 @@ if(health < maxHealth && !(flags & GODMODE)) user.visible_message("[user]'s [proselytizer.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...", \ "You start repairin[src == user ? "g yourself" : "g [src]"]...") + proselytizer.repairing = src if(do_after(user,80*proselytizer.speed_multiplier, target=src)) adjustHealth(-maxHealth) user.visible_message("[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.", \ "You finish repairin[src == user ? "g yourself" : "g [src]"].") + if(proselytizer) + proselytizer.repairing = null else user << "[src == user ? "You" : "[src]"] [src == user ? "are" : "is"] at maximum health!" -//Convert shards and replicant alloy directly to power +//Convert shards and gear bits directly to power /obj/item/clockwork/alloy_shards/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -POWER_STANDARD, "spawn_dir" = SOUTH) @@ -404,6 +359,3 @@ /obj/item/clockwork/alloy_shards/small/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.02), "spawn_dir" = SOUTH) - -/obj/item/clockwork/component/replicant_alloy/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) - return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "power_cost" = -CLOCKCULT_POWER_UNIT, "spawn_dir" = SOUTH) diff --git a/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm b/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm index f67e49802f..318b0c07a3 100644 --- a/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm +++ b/code/game/gamemodes/clock_cult/clock_items/clockwork_proselytizer.dm @@ -196,22 +196,17 @@ if(proselytize_values["power_cost"] > 0) proselytize_values["power_cost"] *= 2 - if(!can_use_power(proselytize_values["power_cost"])) - if(stored_power - proselytize_values["power_cost"] < 0) - user << "You need [proselytize_values["power_cost"]]W power to proselytize [target]!" - else if(stored_power - proselytize_values["power_cost"] > max_power) - user << "Your [name] contains too much power to proselytize [target]!" + var/target_type = target.type + + if(!proselytize_checks(proselytize_values, target, target_type, user)) return FALSE proselytize_values["operation_time"] *= speed_multiplier playsound(target, 'sound/machines/click.ogg', 50, 1) if(proselytize_values["operation_time"]) - var/target_type = target.type user.visible_message("[user]'s [name] begins tearing apart [target]!", "You begin proselytizing [target]...") - if(!do_after(user, proselytize_values["operation_time"], target = target)) - return FALSE - if(repairing || !can_use_power(proselytize_values["power_cost"]) || !target || target.type != target_type) //Check again to prevent bypassing via spamclick + if(!do_after(user, proselytize_values["operation_time"], target = target, extra_checks = CALLBACK(src, .proc/proselytize_checks, proselytize_values, target, target_type, user, TRUE))) return FALSE user.visible_message("[user]'s [name] covers [target] in golden energy!", "You proselytize [target].") else @@ -234,3 +229,64 @@ if(no_table_check) return TRUE return FALSE + +/obj/item/clockwork/clockwork_proselytizer/proc/proselytize_checks(list/proselytize_values, atom/target, expected_type, mob/user, silent) //checked constantly while proselytizing + if(!islist(proselytize_values) || !target || QDELETED(target) || !user) + return FALSE + if(repairing) + return FALSE + if(target.type != expected_type) + return FALSE + if(can_use_power(RATVAR_POWER_CHECK)) + proselytize_values["power_cost"] = 0 + if(!can_use_power(proselytize_values["power_cost"])) + if(stored_power - proselytize_values["power_cost"] < 0) + if(!silent) + user << "You need [proselytize_values["power_cost"]]W power to proselytize [target]!" + else if(stored_power - proselytize_values["power_cost"] > max_power) + if(!silent) + user << "Your [name] contains too much power to proselytize [target]!" + return FALSE + return TRUE + +//The repair check proc. +//Is dark magic. Can probably kill you. +/obj/item/clockwork/clockwork_proselytizer/proc/proselytizer_repair_checks(list/repair_values, atom/target, mob/user, silent) //Exists entirely to avoid an otherwise unreadable series of checks. + if(!islist(repair_values) || !target || QDELETED(target) || !user) + return FALSE + if(isliving(target)) + var/mob/living/L = target + if(!is_servant_of_ratvar(L)) + if(!silent) + user << "[L] does not serve Ratvar!" + return FALSE + if(L.health >= L.maxHealth || (L.flags & GODMODE)) + if(!silent) + user << "[L == user ? "You are" : "[L] is"] at maximum health!" + return FALSE + repair_values["amount_to_heal"] = L.maxHealth - L.health + else if(isobj(target)) + if(istype(target, /obj/structure/destructible/clockwork)) + var/obj/structure/destructible/clockwork/C = target + if(!C.can_be_repaired) + if(!silent) + user << "[C] cannot be repaired!" + return FALSE + var/obj/O = target + if(O.obj_integrity >= O.max_integrity) + if(!silent) + user << "[O] is at maximum integrity!" + return FALSE + repair_values["amount_to_heal"] = O.max_integrity - O.obj_integrity + else + return FALSE + if(repair_values["amount_to_heal"] <= 0) + return FALSE + repair_values["healing_for_cycle"] = min(repair_values["amount_to_heal"], PROSELYTIZER_REPAIR_PER_TICK) + repair_values["power_required"] = round(repair_values["healing_for_cycle"]*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER) + if(!can_use_power(RATVAR_POWER_CHECK) && !can_use_power(repair_values["power_required"])) + if(!silent) + user << "You need at least [repair_values["power_required"]]W power to start repairin[target == user ? "g yourself" : "g [target]"], and at least \ + [round(repair_values["amount_to_heal"]*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]W to fully repair [target == user ? "yourself" : "[target.p_them()]"]!" + return FALSE + return TRUE diff --git a/code/game/gamemodes/clock_cult/clock_scripture.dm b/code/game/gamemodes/clock_cult/clock_scripture.dm index 579da88c8d..a0664aed72 100644 --- a/code/game/gamemodes/clock_cult/clock_scripture.dm +++ b/code/game/gamemodes/clock_cult/clock_scripture.dm @@ -179,7 +179,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or if(!channel_time) return TRUE for(var/invocation in invocations) - if(!check_special_requirements() || !do_after(invoker, channel_time / invocations.len, target = invoker) || !check_special_requirements()) + if(!do_after(invoker, channel_time / invocations.len, target = invoker, extra_checks = CALLBACK(src, .proc/check_special_requirements))) slab.busy = null return FALSE if(multiple_invokers_used) @@ -206,9 +206,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or /datum/clockwork_scripture/channeled/scripture_effects() for(var/i in 1 to chant_amount) - if(!can_recite()) - break - if(!do_after(invoker, chant_interval, target = invoker)) + if(!do_after(invoker, chant_interval, target = invoker, extra_checks = CALLBACK(src, .proc/can_recite))) break clockwork_say(invoker, text2ratvar(pick(chant_invocations)), whispered) if(!chant_effects(i)) diff --git a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm index 96ee1d61a8..3fa1143222 100644 --- a/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm +++ b/code/game/gamemodes/clock_cult/clock_scriptures/scripture_judgement.dm @@ -3,7 +3,7 @@ /////////////// //Ark of the Clockwork Justiciar: Creates a Gateway to the Celestial Derelict, either summoning ratvar or proselytizing everything. -/datum/clockwork_scripture/ark_of_the_clockwork_justiciar +/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar descname = "Structure, Win Condition" name = "Ark of the Clockwork Justiciar" desc = "Tears apart a rift in spacetime to Reebe, the Celestial Derelict.\n\ @@ -15,19 +15,21 @@ consumed_components = list(BELLIGERENT_EYE = 10, VANGUARD_COGWHEEL = 10, GEIS_CAPACITOR = 10, REPLICANT_ALLOY = 10, HIEROPHANT_ANSIBLE = 10) invokers_required = 5 multiple_invokers_used = TRUE + object_path = /obj/structure/destructible/clockwork/massive/celestial_gateway + creator_message = null usage_tip = "The gateway is completely vulnerable to attack during its five-minute duration. It will periodically give indication of its general position to everyone on the station \ as well as being loud enough to be heard throughout the entire sector. Defend it with your life!" tier = SCRIPTURE_JUDGEMENT sort_priority = 1 -/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/New() +/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar/New() if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY) invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! I CALL UPON YOU!!", \ "THIS STATION WILL BE A BEACON OF HOPE IN THE DARKNESS OF SPACE!!", \ "HELP US MAKE THIS SHOW ENGINE'S GLORY!!") ..() -/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/check_special_requirements() +/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar/check_special_requirements() if(!slab.no_cost) if(ratvar_awakens) invoker << "\"I am already here, idiot.\"" @@ -47,11 +49,4 @@ else invoker << "Ratvar's recent banishment renders him too weak to be wrung forth from Reebe!" return FALSE - return TRUE - -/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/scripture_effects() - var/turf/T = get_turf(invoker) - if(T) - new/obj/structure/destructible/clockwork/massive/celestial_gateway(T) - return TRUE - return FALSE + return ..() diff --git a/code/game/gamemodes/clock_cult/clock_structure.dm b/code/game/gamemodes/clock_cult/clock_structure.dm index 0cd51b624e..2aa3377b15 100644 --- a/code/game/gamemodes/clock_cult/clock_structure.dm +++ b/code/game/gamemodes/clock_cult/clock_structure.dm @@ -9,8 +9,7 @@ anchored = 1 density = 1 resistance_flags = FIRE_PROOF | ACID_PROOF - var/repair_amount = 4 //how much a proselytizer can repair each cycle - var/can_be_repaired = TRUE //if a proselytizer can repair it at all + var/can_be_repaired = TRUE //if a proselytizer can repair it break_message = "The frog isn't a meme after all!" //The message shown when a structure breaks break_sound = 'sound/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks debris = list(/obj/item/clockwork/alloy_shards/large = 1, \ @@ -72,9 +71,10 @@ . *= min(max_integrity/max(obj_integrity, 1), 4) . = round(., 0.01) -/obj/structure/destructible/clockwork/can_be_unfasten_wrench(mob/user) +/obj/structure/destructible/clockwork/can_be_unfasten_wrench(mob/user, silent) if(anchored && obj_integrity <= round(max_integrity * 0.25, 1)) - user << "[src] is too damaged to unsecure!" + if(!silent) + user << "[src] is too damaged to unsecure!" return FAILED_UNFASTEN return ..() @@ -158,9 +158,10 @@ var/powered = total_accessable_power() return powered == PROCESS_KILL ? 25 : powered //make sure we don't accidentally return the arbitrary PROCESS_KILL define -/obj/structure/destructible/clockwork/powered/can_be_unfasten_wrench(mob/user) +/obj/structure/destructible/clockwork/powered/can_be_unfasten_wrench(mob/user, silent) if(active) - user << "[src] needs to be disabled before it can be unsecured!" + if(!silent) + user << "[src] needs to be disabled before it can be unsecured!" return FAILED_UNFASTEN return ..() diff --git a/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm index f123579e34..9ca1606d10 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm @@ -74,8 +74,6 @@ hierophant_message("A gateway to the Celestial Derelict has been created in [gate_area.map_name]!", FALSE, src) if(!objective_is_gateway) ratvar_portal = FALSE - hierophant_message("This newly constructed gateway will not free Ratvar, \ - and will instead simply proselytize and convert everything and everyone on the station.", TRUE) SSshuttle.registerHostileEnvironment(src) START_PROCESSING(SSprocessing, src) @@ -210,13 +208,14 @@ animate(glow, transform = matrix() * 3, alpha = 0, time = 5) var/turf/startpoint = get_turf(src) QDEL_IN(src, 3) - clockwork_gateway_activated = TRUE if(ratvar_portal) sleep(3) + clockwork_gateway_activated = TRUE new/obj/structure/destructible/clockwork/massive/ratvar(startpoint) else INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency.proc/request, null, 0) //call the shuttle immediately sleep(3) + clockwork_gateway_activated = TRUE send_to_playing_players("\"[text2ratvar("Behold")]!\"\n\"[text2ratvar("See Engine's mercy")]!\"\n\ \"[text2ratvar("Observe Engine's design skills")]!\"\n\"[text2ratvar("Behold Engine's light")]!!\"\n\ \"[text2ratvar("Gaze upon Engine's power")]!\"") @@ -234,13 +233,8 @@ dist = FALSE T.ratvar_act(dist) CHECK_TICK - for(var/mob/living/silicon/robot/R in silicon_mobs) - if(R && R.stat != DEAD && !is_servant_of_ratvar(R)) - add_servant_of_ratvar(R) - for(var/i in ai_list) - var/mob/living/silicon/ai/A = i - if(A && A.stat != DEAD && !is_servant_of_ratvar(A)) - add_servant_of_ratvar(A) + for(var/mob/living/L in living_mob_list) + L.ratvar_act() for(var/I in all_clockwork_mobs) var/mob/M = I if(M.stat == CONSCIOUS) diff --git a/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm b/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm index caae687cd4..a52cf68ebf 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/clockwork_obelisk.dm @@ -25,9 +25,10 @@ if(is_servant_of_ratvar(user) || isobserver(user)) user << "It requires [hierophant_cost]W to broadcast over the Hierophant Network, and [gateway_cost]W to open a Spatial Gateway." -/obj/structure/destructible/clockwork/powered/clockwork_obelisk/can_be_unfasten_wrench(mob/user) +/obj/structure/destructible/clockwork/powered/clockwork_obelisk/can_be_unfasten_wrench(mob/user, silent) if(active) - user << "[src] is currently sustaining a gateway!" + if(!silent) + user << "[src] is currently sustaining a gateway!" return FAILED_UNFASTEN return ..() diff --git a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm index 665ef9c2fc..f2768588c6 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/ocular_warden.dm @@ -32,14 +32,16 @@ /obj/structure/destructible/clockwork/ocular_warden/hulk_damage() return 25 -/obj/structure/destructible/clockwork/ocular_warden/can_be_unfasten_wrench(mob/user) +/obj/structure/destructible/clockwork/ocular_warden/can_be_unfasten_wrench(mob/user, silent) if(anchored) if(obj_integrity <= max_integrity * 0.25) - user << "[src] is too damaged to unsecure!" + if(!silent) + user << "[src] is too damaged to unsecure!" return FAILED_UNFASTEN else for(var/obj/structure/destructible/clockwork/ocular_warden/W in orange(3, src)) - user << "You sense another ocular warden too near this location. Activating this one this close would cause them to fight." + if(!silent) + user << "You sense another ocular warden too near this location. Activating this one this close would cause them to fight." return FAILED_UNFASTEN return SUCCESSFUL_UNFASTEN diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 5eb2379d2a..d03f2759a0 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -498,9 +498,9 @@ var/list/teleport_runes = list() sleep(40) if(src) color = "#FF0000" - new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed if(cult_mode) cult_mode.eldergod = 0 + new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed /obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal. if((istype(I, /obj/item/weapon/tome) && iscultist(user))) diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm index b5abae7489..2a86b4766f 100644 --- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm +++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm @@ -196,9 +196,32 @@ /obj/item/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) return S.Integrate(src) +/obj/item/proc/IntegrateAmount() //returns the amount of resources gained when eating this item + if(materials[MAT_METAL] || materials[MAT_GLASS]) + return 1 + return 0 + /obj/item/weapon/gun/swarmer_act()//Stops you from eating the entire armory return FALSE +/obj/item/clockwork/alloy_shards/IntegrateAmount() + return 10 + +/obj/item/stack/tile/brass/IntegrateAmount() + return 5 + +/obj/item/clockwork/alloy_shards/medium/gear_bit/large/IntegrateAmount() + return 4 + +/obj/item/clockwork/alloy_shards/large/IntegrateAmount() + return 3 + +/obj/item/clockwork/alloy_shards/medium/IntegrateAmount() + return 2 + +/obj/item/clockwork/alloy_shards/small/IntegrateAmount() + return 1 + /turf/open/floor/swarmer_act()//ex_act() on turf calls it on its contents, this is to prevent attacking mobs by DisIntegrate()'ing the floor return FALSE @@ -316,6 +339,10 @@ S << "This communications relay should be preserved, it will be a useful resource to our masters in the future. Aborting." return FALSE +/obj/machinery/deepfryer/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + S << "This kitchen appliance should be preserved, it will make delicious unhealthy snacks for our masters in the future. Aborting." + return FALSE + /obj/machinery/power/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) S << "Disrupting the power grid would bring no benefit to us. Aborting." return FALSE @@ -362,6 +389,10 @@ S << "This object is receiving unactivated swarmer shells to help us. Aborting." return FALSE +/obj/structure/destructible/clockwork/massive/celestial_gateway/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) + S << "This object is multiplying existing resources. Aborting." + return FALSE + /obj/structure/lattice/catwalk/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) . = ..() var/turf/here = get_turf(src) @@ -373,13 +404,12 @@ /obj/item/device/unactivated_swarmer/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) - if(S.resources + 50 > S.max_resources) - S << "We have too many resources to reconsume this shell. Aborting." - else - ..() - S.resources += 49 //refund the whole thing + ..() return FALSE //would logically be TRUE, but we don't want AI swarmers eating player spawn chances. +/obj/item/device/unactivated_swarmer/IntegrateAmount() + return 50 + /obj/machinery/hydroponics/soil/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) S << "This object does not contain enough materials to work with." return FALSE @@ -396,13 +426,13 @@ return 0 return new fabrication_object(loc) - /mob/living/simple_animal/hostile/swarmer/proc/Integrate(obj/item/target) - if(resources >= max_resources) + var/resource_gain = target.IntegrateAmount() + if(resources + resource_gain > max_resources) src << "We cannot hold more materials!" return TRUE - if((target.materials[MAT_METAL]) || (target.materials[MAT_GLASS])) - resources++ + if(resource_gain) + resources += resource_gain do_attack_animation(target) changeNext_move(CLICK_CD_MELEE) var/obj/effect/overlay/temp/swarmer/integrate/I = new /obj/effect/overlay/temp/swarmer/integrate(get_turf(target)) diff --git a/code/game/gamemodes/nuclear/nuclear_challenge.dm b/code/game/gamemodes/nuclear/nuclear_challenge.dm index b343f2bdf6..941e469d28 100644 --- a/code/game/gamemodes/nuclear/nuclear_challenge.dm +++ b/code/game/gamemodes/nuclear/nuclear_challenge.dm @@ -57,6 +57,7 @@ U.hidden_uplink.telecrystals = CHALLENGE_TELECRYSTALS U.hidden_uplink.set_gamemode(/datum/game_mode/nuclear) config.shuttle_refuel_delay = max(config.shuttle_refuel_delay, CHALLENGE_SHUTTLE_DELAY) + feedback_set("nuclear_challenge_mode",1) qdel(src) /obj/item/device/nuclear_challenge/proc/check_allowed(mob/living/user) diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index c222189cc8..b66caf4402 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -20,7 +20,7 @@ var/bomb_set density = 1 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - var/timer_set = 60 + var/timer_set = 90 var/default_timer_set = 90 var/minimum_timer_set = 90 var/maximum_timer_set = 3600 diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 630e989975..a4bb52ead6 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -72,6 +72,7 @@ /obj/machinery/door/firedoor/attack_hand(mob/user) if(operating || !density) return + user.changeNext_move(CLICK_CD_MELEE) user.visible_message("[user] bangs on \the [src].", "You bang on \the [src].") diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index c358a173e7..29fa0e2a67 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -96,7 +96,7 @@ return var/area/A = get_area(src) A.firealert(src) - playsound(src.loc, 'sound/ambience/signal.ogg', 75, 0) + playsound(src.loc, 'goon/sound/machinery/FireAlarm.ogg', 75, 0) /obj/machinery/firealarm/proc/alarm_in(time) addtimer(CALLBACK(src, .proc/alarm), time) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 8722bcc074..117a4e9e8e 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -356,13 +356,13 @@ Class Procs: return 1 return 0 -/obj/proc/can_be_unfasten_wrench(mob/user) +/obj/proc/can_be_unfasten_wrench(mob/user, silent) //if we can unwrench this object; returns SUCCESSFUL_UNFASTEN and FAILED_UNFASTEN, which are both TRUE, or CANT_UNFASTEN, which isn't. if(!isfloorturf(loc) && !anchored) user << "[src] needs to be on the floor to be secured!" return FAILED_UNFASTEN return SUCCESSFUL_UNFASTEN -/obj/proc/default_unfasten_wrench(mob/user, obj/item/weapon/wrench/W, time = 20) +/obj/proc/default_unfasten_wrench(mob/user, obj/item/weapon/wrench/W, time = 20) //try to unwrench an object in a WONDERFUL DYNAMIC WAY if(istype(W) && !(flags & NODECONSTRUCT)) var/can_be_unfasten = can_be_unfasten_wrench(user) if(!can_be_unfasten || can_be_unfasten == FAILED_UNFASTEN) @@ -372,10 +372,7 @@ Class Procs: playsound(loc, W.usesound, 50, 1) var/prev_anchored = anchored //as long as we're the same anchored state and we're either on a floor or are anchored, toggle our anchored state - if(!time || (do_after(user, time*W.toolspeed, target = src) && anchored == prev_anchored)) - can_be_unfasten = can_be_unfasten_wrench(user) - if(!can_be_unfasten || can_be_unfasten == FAILED_UNFASTEN) - return can_be_unfasten + if(!time || do_after(user, time*W.toolspeed, target = src, extra_checks = CALLBACK(src, .proc/unfasten_wrench_check, prev_anchored, user))) user << "You [anchored ? "un" : ""]secure [src]." anchored = !anchored playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) @@ -383,6 +380,13 @@ Class Procs: return FAILED_UNFASTEN return CANT_UNFASTEN +/obj/proc/unfasten_wrench_check(prev_anchored, mob/user) //for the do_after, this checks if unfastening conditions are still valid + if(anchored != prev_anchored) + return FALSE + if(can_be_unfasten_wrench(user, TRUE) != SUCCESSFUL_UNFASTEN) //if we aren't explicitly successful, cancel the fuck out + return FALSE + return TRUE + /obj/machinery/proc/exchange_parts(mob/user, obj/item/weapon/storage/part_replacer/W) if(!istype(W)) return diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 23f2b10ad8..f834a52e73 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -123,6 +123,8 @@ switch(mode) if(1,2,4,5) user << "The display says:
\t[message1]
\t[message2]" + if(mode == 1 && SSshuttle.emergency) + user << "Current Shuttle: [SSshuttle.emergency.name]" /obj/machinery/status_display/proc/set_message(m1, m2) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 12dd33e998..faa1f0d851 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -762,7 +762,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C /obj/machinery/vending/cigarette name = "\improper ShadyCigs Deluxe" - desc = "If you want to get cancer, might as well do it in style" + desc = "If you want to get cancer, might as well do it in style." product_slogans = "Space cigs taste good like a cigarette should.;I'd rather toolbox than switch.;Smoke!;Don't believe the reports - smoke today!" product_ads = "Probably not bad for you!;Don't believe the scientists!;It's good for you!;Don't quit, buy more!;Smoke!;Nicotine heaven.;Best cigarettes since 2150.;Award-winning cigs." icon_state = "cigs" diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 3dd395d01f..b1945d7b74 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -358,8 +358,11 @@ occupant.throw_alert("mech damage", /obj/screen/alert/low_mech_integrity, 3) else occupant.clear_alert("mech damage") - - if(occupant.loc != src) //something went wrong + var/actual_loc = occupant.loc + if(istype(actual_loc, /obj/item/device/mmi)) + var/obj/item/device/mmi/M = actual_loc + actual_loc = M.mecha + if(actual_loc != src) //something went wrong occupant.clear_alert("charge") occupant.clear_alert("mech damage") RemoveActions(occupant, human_occupant=1) @@ -859,57 +862,58 @@ else return 0 -/obj/mecha/proc/mmi_move_inside(obj/item/device/mmi/mmi_as_oc,mob/user) +/obj/mecha/proc/mmi_move_inside(obj/item/device/mmi/mmi_as_oc, mob/user) if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client) user << "Consciousness matrix not detected!" - return 0 + return FALSE else if(mmi_as_oc.brainmob.stat) user << "Beta-rhythm below acceptable level!" - return 0 + return FALSE else if(occupant) user << "Occupant detected!" - return 0 - else if(dna_lock && (!mmi_as_oc.brainmob.stored_dna || dna_lock!=mmi_as_oc.brainmob.stored_dna.unique_enzymes)) + return FALSE + else if(dna_lock && (!mmi_as_oc.brainmob.stored_dna || (dna_lock != mmi_as_oc.brainmob.stored_dna.unique_enzymes))) user << "Access denied. [name] is secured with a DNA lock." - return 0 + return FALSE visible_message("[user] starts to insert an MMI into [name].") if(do_after(user, 40, target = src)) if(!occupant) - return mmi_moved_inside(mmi_as_oc,user) + return mmi_moved_inside(mmi_as_oc, user) else user << "Occupant detected!" else user << "You stop inserting the MMI." - return 0 + return FALSE -/obj/mecha/proc/mmi_moved_inside(obj/item/device/mmi/mmi_as_oc,mob/user) - if(mmi_as_oc && user in range(1)) - if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client) - user << "Consciousness matrix not detected!" - return 0 - else if(mmi_as_oc.brainmob.stat) - user << "Beta-rhythm below acceptable level!" - return 0 - if(!user.transferItemToLoc(mmi_as_oc, src)) - user << "\the [mmi_as_oc] is stuck to your hand, you cannot put it in \the [src]!" - return - var/mob/brainmob = mmi_as_oc.brainmob - occupant = brainmob - brainmob.forceMove(src) //should allow relaymove - brainmob.reset_perspective(src) - brainmob.canmove = 1 - mmi_as_oc.mecha = src - icon_state = initial(icon_state) - setDir(dir_in) - log_message("[mmi_as_oc] moved in as pilot.") - if(!internal_damage) - occupant << sound('sound/mecha/nominal.ogg',volume=50) - GrantActions(brainmob) - return 1 - else - return 0 +/obj/mecha/proc/mmi_moved_inside(obj/item/device/mmi/mmi_as_oc, mob/user) + if(!(Adjacent(mmi_as_oc) && Adjacent(user))) + return FALSE + if(!mmi_as_oc.brainmob || !mmi_as_oc.brainmob.client) + user << "Consciousness matrix not detected!" + return FALSE + else if(mmi_as_oc.brainmob.stat) + user << "Beta-rhythm below acceptable level!" + return FALSE + if(!user.transferItemToLoc(mmi_as_oc, src)) + user << "\the [mmi_as_oc] is stuck to your hand, you cannot put it in \the [src]!" + return FALSE + var/mob/brainmob = mmi_as_oc.brainmob + mmi_as_oc.mecha = src + occupant = brainmob + brainmob.forceMove(src) //should allow relaymove + brainmob.reset_perspective(src) + brainmob.remote_control = src + brainmob.update_canmove() + icon_state = initial(icon_state) + update_icon() + setDir(dir_in) + log_message("[mmi_as_oc] moved in as pilot.") + if(!internal_damage) + occupant << sound('sound/mecha/nominal.ogg',volume=50) + GrantActions(brainmob) + return TRUE /obj/mecha/container_resist(mob/living/user) go_out() @@ -1046,4 +1050,4 @@ var/year_integer = text2num(year) // = 2013??? /obj/mecha/update_remote_sight(mob/living/user) if(occupant_sight_flags) if(user == occupant) - user.sight |= occupant_sight_flags + user.sight |= occupant_sight_flags \ No newline at end of file diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm index f8c4afd06b..e14c20ebf0 100644 --- a/code/game/mecha/working/ripley.dm +++ b/code/game/mecha/working/ripley.dm @@ -43,10 +43,6 @@ ..() update_icon() -/obj/mecha/working/ripley/mmi_moved_inside(obj/item/device/mmi/mmi_as_oc,mob/user) - ..() - update_icon() - /obj/mecha/working/ripley/update_icon() ..() if (hides) @@ -178,4 +174,4 @@ cargo -= O else if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded. - user << "You fail to push [O] out of [src]!" + user << "You fail to push [O] out of [src]!" \ No newline at end of file diff --git a/code/game/objects/effects/contraband.dm b/code/game/objects/effects/contraband.dm index bf1ea9346e..13c2131517 100644 --- a/code/game/objects/effects/contraband.dm +++ b/code/game/objects/effects/contraband.dm @@ -104,9 +104,9 @@ list(name = "- Carbon Dioxide", desc = " This informational poster teaches the v icon = 'icons/obj/contraband.dmi' force = 0 resistance_flags = FLAMMABLE - var/serial_number = 0 + var/serial = 0 var/obj/structure/sign/poster/resulting_poster = null //The poster that will be created is initialised and stored through contraband/poster's constructor - var/official = 0 + var/rolled_official = 0 /obj/item/weapon/poster/contraband @@ -118,20 +118,20 @@ list(name = "- Carbon Dioxide", desc = " This informational poster teaches the v name = "motivational poster" icon_state = "rolled_legit" desc = "An official Nanotrasen-issued poster to foster a compliant and obedient workforce. It comes with state-of-the-art adhesive backing, for easy pinning to any vertical surface." - official = 1 + rolled_official = 1 /obj/item/weapon/poster/New(turf/loc, given_serial = 0) if(given_serial == 0) - if(!official) - serial_number = rand(1, NUM_OF_POSTER_DESIGNS) - resulting_poster = new(serial_number,official) + if(!rolled_official) + serial = rand(1, NUM_OF_POSTER_DESIGNS) + resulting_poster = new(serial,rolled_official) else - serial_number = rand(1, NUM_OF_POSTER_DESIGNS_LEGIT) - resulting_poster = new(serial_number,official) + serial = rand(1, NUM_OF_POSTER_DESIGNS_LEGIT) + resulting_poster = new(serial,rolled_official) else - serial_number = given_serial + serial = given_serial //We don't give it a resulting_poster because if we called it with a given_serial it means that we're rerolling an already used poster. - name += " - No. [serial_number]" + name += " - No. [serial]" ..(loc) @@ -182,8 +182,10 @@ list(name = "- Carbon Dioxide", desc = " This informational poster teaches the v var/placespeed = 37 // don't change this, otherwise the animation will not sync to the progress bar /obj/structure/sign/poster/New(serial,rolled_official) - serial_number = serial - official = rolled_official + if (!serial_number) + serial_number = serial + if(!official) + official = rolled_official if(serial_number == loc) if(!official) serial_number = rand(1, NUM_OF_POSTER_DESIGNS) //This is for the mappers that want individual posters without having to use rolled posters. @@ -259,7 +261,7 @@ list(name = "- Carbon Dioxide", desc = " This informational poster teaches the v var/temp_loc = get_turf(user) flick("poster_being_set",D) D.loc = src - D.official = P.official + D.official = P.rolled_official qdel(P) //delete it now to cut down on sanity checks afterwards. Agouri's code supports rerolling it anyway playsound(D.loc, 'sound/items/poster_being_created.ogg', 100, 1) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 8a26b20444..3efc7d82b2 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -234,7 +234,8 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s var/obj/item/weapon/storage/S = loc S.remove_from_storage(src, user.loc) - throwing = 0 + if(throwing) + throwing.finalize(FALSE) if(loc == user) if(!user.dropItemToGround(src)) return @@ -255,7 +256,8 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s var/obj/item/weapon/storage/S = loc S.remove_from_storage(src, user.loc) - throwing = 0 + if(throwing) + throwing.finalize(FALSE) if(loc == user) if(!user.dropItemToGround(src)) return diff --git a/code/game/objects/items/charter.dm b/code/game/objects/items/charter.dm index bfe699ad33..ead1f9e820 100644 --- a/code/game/objects/items/charter.dm +++ b/code/game/objects/items/charter.dm @@ -1,3 +1,5 @@ +#define STATION_RENAME_TIME_LIMIT 3000 + /obj/item/station_charter name = "station charter" icon = 'icons/obj/wizard.dmi' @@ -33,7 +35,7 @@ if(used) user << "This charter has already been used to name the station." return - if(!ignores_timeout && (world.time-round_start_time > CHALLENGE_TIME_LIMIT)) //5 minutes + if(!ignores_timeout && (world.time-round_start_time > STATION_RENAME_TIME_LIMIT)) //5 minutes user << "The crew has already settled into the shift. \ It probably wouldn't be good to rename the station right now." return @@ -93,3 +95,5 @@ if(!unlimited_uses) used = TRUE + +#undef STATION_RENAME_TIME_LIMIT diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index 5cd509b69d..aa06cc380b 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -7,7 +7,6 @@ w_class = WEIGHT_CLASS_TINY origin_tech = "engineering=2;bluespace=1" var/translate_binary = 0 - var/translate_hive = 0 var/syndie = 0 var/centcom = 0 var/list/channels = list() diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 0fabb5e70a..bdd0508aeb 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -273,9 +273,6 @@ if(keyslot2.translate_binary) src.translate_binary = 1 - if(keyslot2.translate_hive) - src.translate_hive = 1 - if(keyslot2.syndie) src.syndie = 1 diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 4b90010de2..38c53ed8d6 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -17,7 +17,6 @@ var/broadcasting = 0 var/listening = 1 var/translate_binary = 0 - var/translate_hive = 0 var/freerange = 0 // 0 - Sanitize frequencies, 1 - Full range var/list/channels = list() //see communications.dm for full list. First channes is a "default" for :h var/obj/item/device/encryptionkey/keyslot //To allow the radio to accept encryption keys. @@ -58,7 +57,6 @@ /obj/item/device/radio/proc/recalculateChannels() channels = list() translate_binary = 0 - translate_hive = 0 syndie = 0 centcom = 0 @@ -72,9 +70,6 @@ if(keyslot.translate_binary) translate_binary = 1 - if(keyslot.translate_hive) - translate_hive = 1 - if(keyslot.syndie) syndie = 1 diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index dea7b94aa5..503ecba450 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -272,12 +272,17 @@ /obj/item/device/tape/attackby(obj/item/I, mob/user, params) - if(ruined && istype(I, /obj/item/weapon/screwdriver)) - user << "You start winding the tape back in..." - if(do_after(user, 120*I.toolspeed, target = src)) - user << "You wound the tape back in." - fix() - + if(ruined) + var/delay = -1 + if (istype(I, /obj/item/weapon/screwdriver)) + delay = 120*I.toolspeed + else if(istype(I, /obj/item/weapon/pen)) + delay = 120*1.5 + if (delay != -1) + user << "You start winding the tape back in..." + if(do_after(user, delay, target = src)) + user << "You wound the tape back in." + fix() //Random colour tapes /obj/item/device/tape/random/New() diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 668e5ae7d3..763031cdd8 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -251,7 +251,7 @@ //get amount from user var/min = 0 var/max = src.get_amount() - var/stackmaterial = input(user,"How many sheets do you wish to take out of this stack? (Maximum [max]") as num + var/stackmaterial = round(input(user,"How many sheets do you wish to take out of this stack? (Maximum [max]") as num) if(stackmaterial == null || stackmaterial <= min || stackmaterial >= src.get_amount()) return else diff --git a/code/game/objects/items/weapons/RPD.dm b/code/game/objects/items/weapons/RPD.dm index 7f0b5671fd..baff623a2d 100644 --- a/code/game/objects/items/weapons/RPD.dm +++ b/code/game/objects/items/weapons/RPD.dm @@ -522,43 +522,39 @@ var/global/list/RPD_recipes=list( if(!user.IsAdvancedToolUser() || istype(A,/turf/open/space/transit)) return ..() + //make sure what we're clicking is valid for the current mode + var/is_paintable = (p_class == PAINT_MODE && istype(A, /obj/machinery/atmospherics/pipe)) + var/is_consumable = (p_class == EATING_MODE && (istype(A, /obj/item/pipe) || istype(A, /obj/item/pipe_meter) || istype(A, /obj/structure/disposalconstruct))) + var/can_make_pipe = ((p_class == ATMOS_MODE || p_class == METER_MODE || p_class == DISPOSALS_MODE) && isturf(A)) + + if(!is_paintable && !is_consumable && !can_make_pipe) + return ..() + //So that changing the menu settings doesn't affect the pipes already being built. var/queued_p_type = p_type var/queued_p_dir = p_dir var/queued_p_flipped = p_flipped . = FALSE - switch(p_class) - if(PAINT_MODE) // Paint pipes - if(!istype(A,/obj/machinery/atmospherics/pipe)) - // Avoid spewing errors about invalid mode -2 when clicking on stuff that aren't pipes. - user << "\The [src]'s error light flickers! Perhaps you need to only use it on pipes and pipe meters?" - return + switch(p_class) //if we've gotten this var, the target is valid + if(PAINT_MODE) //Paint pipes var/obj/machinery/atmospherics/pipe/P = A playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) P.add_atom_colour(paint_colors[paint_color], FIXED_COLOUR_PRIORITY) P.pipe_color = paint_colors[paint_color] user.visible_message("[user] paints \the [P] [paint_color].","You paint \the [P] [paint_color].") - //P.update_icon() P.update_node_icon() return - if(EATING_MODE) // Eating pipes - // Must click on an actual pipe or meter. - if(!(istype(A,/obj/item/pipe) || istype(A,/obj/item/pipe_meter) || istype(A,/obj/structure/disposalconstruct))) - // Avoid spewing errors about invalid mode -1 when clicking on stuff that aren't pipes. - user << "The [src]'s error light flickers! Perhaps you need to only use it on pipes and pipe meters?" - return - user << "You start destroying pipe..." + + if(EATING_MODE) //Eating pipes + user << "You start destroying a pipe..." playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) if(do_after(user, 2, target = A)) activate() qdel(A) - if(ATMOS_MODE) - if(!isturf(A)) - user << "The [src]'s error light flickers!" - return - user << "You start building pipes..." + if(ATMOS_MODE) //Making pipes + user << "You start building a pipe..." playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) if(do_after(user, 2, target = A)) activate() @@ -567,21 +563,18 @@ var/global/list/RPD_recipes=list( P.update() P.add_fingerprint(usr) - if(METER_MODE) - if(!isturf(A)) - user << "The [src]'s error light flickers!" - return 0 + if(METER_MODE) //Making pipe meters user << "You start building a meter..." playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) if(do_after(user, 2, target = A)) activate() new /obj/item/pipe_meter(A) - if(DISPOSALS_MODE) - if(!isturf(A) || is_anchored_dense_turf(A)) - user << "The [src]'s error light flickers!" + if(DISPOSALS_MODE) //Making disposals pipes + if(!is_anchored_dense_turf(A)) + user << "The [src]'s error light flickers; there's something in the way!" return - user << "You start building pipes..." + user << "You start building a disposals pipe..." playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) if(do_after(user, 20, target = A)) var/obj/structure/disposalconstruct/C = new (A, queued_p_type ,queued_p_dir) diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm index 5073aa33f9..d7207bd398 100644 --- a/code/game/objects/items/weapons/dice.dm +++ b/code/game/objects/items/weapons/dice.dm @@ -172,7 +172,7 @@ user.visible_message("[user] has thrown [src]. It lands on [result]. [comment]", \ "You throw [src]. It lands on [result]. [comment]", \ "You hear [src] rolling, it sounds like a [fake_result].") - else if(src.throwing == 0) //Dice was thrown and is coming to rest + else if(!src.throwing) //Dice was thrown and is coming to rest visible_message("[src] rolls to a stop, landing on [result]. [comment]") /obj/item/weapon/dice/d4/Crossed(mob/living/carbon/human/H) diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 2c958efbd3..e91211f1b2 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -37,12 +37,11 @@ //What does the implant do upon injection? //return 1 if the implant injects -//return -1 if the implant fails to inject -//return 0 if there is no room for implant +//return 0 if there is no room for implant / it fails /obj/item/weapon/implant/proc/implant(mob/living/target, mob/user, silent = 0) LAZYINITLIST(target.implants) if(!target.can_be_implanted() || !can_be_implanted_in(target)) - return -1 + return 0 for(var/X in target.implants) if(istype(X, type)) var/obj/item/weapon/implant/imp_e = X diff --git a/code/game/objects/items/weapons/implants/implant_gang.dm b/code/game/objects/items/weapons/implants/implant_gang.dm index 19d9adbe60..20a481171b 100644 --- a/code/game/objects/items/weapons/implants/implant_gang.dm +++ b/code/game/objects/items/weapons/implants/implant_gang.dm @@ -43,7 +43,7 @@ target.visible_message("[target] seems to resist the implant!", "You feel the influence of your enemies try to invade your mind!") qdel(src) - return -1 + return 0 /obj/item/weapon/implanter/gang name = "implanter (gang)" diff --git a/code/game/objects/items/weapons/implants/implant_loyality.dm b/code/game/objects/items/weapons/implants/implant_loyality.dm index daf085c6b8..619b19f1f7 100644 --- a/code/game/objects/items/weapons/implants/implant_loyality.dm +++ b/code/game/objects/items/weapons/implants/implant_loyality.dm @@ -24,14 +24,14 @@ target.visible_message("[target] seems to resist the implant!", "You feel something interfering with your mental conditioning, but you resist it!") removed(target, 1) qdel(src) - return -1 + return 0 if(target.mind in ticker.mode.get_gangsters()) ticker.mode.remove_gangster(target.mind) if(!silent) target.visible_message("[src] was destroyed in the process!", "You feel a sense of peace and security. You are now protected from brainwashing.") removed(target, 1) qdel(src) - return -1 + return 0 if(target.mind in ticker.mode.revolutionaries) ticker.mode.remove_revolutionary(target.mind) if(!silent) diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index 4949d0d276..71216dcc3a 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -38,6 +38,8 @@ M.visible_message("[user] has implanted [M].", "[user] implants you.") imp = null update_icon() + else + user << "[src] fails to implant [M]." /obj/item/weapon/implanter/attackby(obj/item/weapon/W, mob/user, params) if(istype(W, /obj/item/weapon/pen)) diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 0a929233c9..9bdcda7939 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -574,7 +574,6 @@ user.changeNext_move(CLICK_CD_MELEE) playsound(loc, "rustle", 50, 1, -5) user.visible_message("[user] hugs \the [src].","You hug \the [src].") - return /obj/item/weapon/storage/box/hug/medical/New() ..() diff --git a/code/game/objects/items/weapons/storage/toolbox.dm b/code/game/objects/items/weapons/storage/toolbox.dm index 4ee796006f..d97232ce79 100644 --- a/code/game/objects/items/weapons/storage/toolbox.dm +++ b/code/game/objects/items/weapons/storage/toolbox.dm @@ -34,6 +34,10 @@ new /obj/item/device/flashlight/flare(src) new /obj/item/device/radio/off(src) +/obj/item/weapon/storage/toolbox/emergency/old + name = "rusty red toolbox" + item_state = "toolbox_red_old" + /obj/item/weapon/storage/toolbox/mechanical name = "mechanical toolbox" icon_state = "blue" @@ -48,6 +52,10 @@ new /obj/item/device/analyzer(src) new /obj/item/weapon/wirecutters(src) +/obj/item/weapon/storage/toolbox/mechanical/old + name = "rusty blue toolbox" + item_state = "toolbox_blue_old" + /obj/item/weapon/storage/toolbox/electrical name = "electrical toolbox" icon_state = "yellow" diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index 1371818487..ea47fbb9df 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -306,3 +306,7 @@ ..() for(var/i in 1 to 3) new/obj/item/weapon/grenade/chem_grenade/ez_clean(src) + +/obj/item/weapon/storage/box/hug/reverse_revolver/New() + ..() + new /obj/item/weapon/gun/ballistic/revolver/reverse(src) diff --git a/code/game/objects/items/weapons/tanks/jetpack.dm b/code/game/objects/items/weapons/tanks/jetpack.dm index 76a2df3f0c..8b6a1a946a 100644 --- a/code/game/objects/items/weapons/tanks/jetpack.dm +++ b/code/game/objects/items/weapons/tanks/jetpack.dm @@ -9,6 +9,7 @@ var/gas_type = "o2" var/on = FALSE var/stabilizers = FALSE + var/full_speed = TRUE // If the jetpack will have a speedboost in space/nograv or not var/datum/effect_system/trail_follow/ion/ion_trail /obj/item/weapon/tank/jetpack/New() @@ -133,6 +134,7 @@ volume = 1 slot_flags = null gas_type = null + full_speed = FALSE var/datum/gas_mixture/temp_air_contents var/obj/item/weapon/tank/internals/tank = null diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 37f5984f1f..ca48ec94bb 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -113,7 +113,7 @@ if(throwing) // you keep some momentum when getting out of a thrown closet step(AM, dir) if(throwing) - throwing = 0 + throwing.finalize(FALSE) /obj/structure/closet/proc/take_contents() var/turf/T = get_turf(src) @@ -438,3 +438,7 @@ for(var/atom/A in contents) A.ex_act(severity, target) CHECK_TICK + +/obj/structure/closet/singularity_act() + dump_contents() + ..() diff --git a/code/game/objects/structures/musician.dm b/code/game/objects/structures/musician.dm index 6ce6b6b63d..236043a3df 100644 --- a/code/game/objects/structures/musician.dm +++ b/code/game/objects/structures/musician.dm @@ -107,6 +107,15 @@ cur_acc[cur_note] = "#" // so shift is never required else cur_oct[cur_note] = text2num(ni) + if(user.dizziness > 0 && prob(user.dizziness / 2)) + cur_note = Clamp(cur_note + rand(round(-user.dizziness / 10), round(user.dizziness / 10)), 1, 7) + if(user.dizziness > 0 && prob(user.dizziness / 5)) + if(prob(30)) + cur_acc[cur_note] = "#" + else if(prob(42)) + cur_acc[cur_note] = "b" + else if(prob(75)) + cur_acc[cur_note] = "n" playnote(cur_note, cur_acc[cur_note], cur_oct[cur_note]) if(notes.len >= 2 && text2num(notes[2])) sleep(sanitize_tempo(tempo / text2num(notes[2]))) diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index 5cd62b1381..2c8456f338 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -30,23 +30,20 @@ /turf/closed/indestructible/splashscreen name = "Space Station 13" icon = 'icons/misc/fullscreen.dmi' - icon_state = "title1" + icon_state = "title" layer = FLY_LAYER + var/titlescreen = TITLESCREEN -/turf/closed/indestructible/splashscreen/New() +/turf/closed/indestructible/splashscreen/Initialize() ..() - icon_state = pick("title1","title2","title3","title4","title5") + if(titlescreen) + icon_state = titlescreen /turf/closed/indestructible/riveted icon = 'icons/turf/walls/riveted.dmi' icon_state = "riveted" smooth = SMOOTH_TRUE -/turf/closed/indestructible/New() - ..() - if(smooth) - queue_smooth(src) - /turf/closed/indestructible/riveted/uranium icon = 'icons/turf/walls/uranium_wall.dmi' icon_state = "uranium" @@ -64,7 +61,7 @@ smooth = SMOOTH_TRUE icon = 'icons/obj/smooth_structures/reinforced_window.dmi' -/turf/closed/indestructible/fakeglass/New() +/turf/closed/indestructible/fakeglass/Initialize() ..() icon_state = null //set the icon state to null, so our base state isn't visible var/image/I = image('icons/obj/structures.dmi', loc = src, icon_state = "grille") diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index df3b680b91..c30df6d1e0 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -29,22 +29,20 @@ baseturf = /turf/open/indestructible/necropolis initial_gas_mix = "o2=14;n2=23;TEMP=300" -/turf/open/indestructible/necropolis/New() +/turf/open/indestructible/necropolis/Initialize() ..() if(prob(12)) icon_state = "necro[rand(2,3)]" +/turf/open/indestructible/necropolis/air + initial_gas_mix = "o2=22;n2=82;TEMP=293.15" + /turf/open/indestructible/hierophant icon = 'icons/turf/floors/hierophant_floor.dmi' initial_gas_mix = "o2=14;n2=23;TEMP=300" baseturf = /turf/open/indestructible/hierophant smooth = SMOOTH_TRUE -/turf/open/indestructible/hierophant/New() - ..() - if(smooth) - queue_smooth(src) - /turf/open/indestructible/hierophant/two /turf/open/indestructible/paper diff --git a/code/game/turfs/simulated/chasm.dm b/code/game/turfs/simulated/chasm.dm index f1e71ff25d..2f478df8ba 100644 --- a/code/game/turfs/simulated/chasm.dm +++ b/code/game/turfs/simulated/chasm.dm @@ -69,7 +69,7 @@ L.adjustBruteLoss(30) -/turf/open/chasm/straight_down/New() +/turf/open/chasm/straight_down/Initialize() ..() drop_x = x drop_y = y diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index f478f1e27c..88d58314cb 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -33,7 +33,7 @@ var/list/icons_to_ignore_at_floor_init = list("damaged1","damaged2","damaged3"," var/list/broken_states var/list/burnt_states -/turf/open/floor/New() +/turf/open/floor/Initialize(mapload) if (!broken_states) broken_states = list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5") if (!burnt_states) @@ -43,6 +43,8 @@ var/list/icons_to_ignore_at_floor_init = list("damaged1","damaged2","damaged3"," icon_regular_floor = "floor" else icon_regular_floor = icon_state + if(mapload) + MakeDirty() /turf/open/floor/ex_act(severity, target) var/shielded = is_shielded() @@ -179,10 +181,5 @@ var/list/icons_to_ignore_at_floor_init = list("damaged1","damaged2","damaged3"," if(.) ChangeTurf(/turf/open/floor/clockwork) -/turf/open/floor/Initialize(mapload) - ..() - if(mapload) - MakeDirty() - /turf/open/floor/acid_melt() ChangeTurf(baseturf) diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index 5b8482cc52..d303d8ac53 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -36,10 +36,9 @@ flags = NONE var/ore_type = /obj/item/weapon/ore/glass -/turf/open/floor/grass/New() +/turf/open/floor/grass/Initialize() ..() - spawn(1) - update_icon() + update_icon() /turf/open/floor/grass/attackby(obj/item/C, mob/user, params) if(istype(C, /obj/item/weapon/shovel) && params) @@ -76,7 +75,7 @@ initial_gas_mix = "o2=14;n2=23;TEMP=300" slowdown = 0 -/turf/open/floor/grass/snow/basalt/New() +/turf/open/floor/grass/snow/basalt/Initialize() ..() if(prob(15)) icon_state = "basalt[rand(0, 12)]" @@ -96,10 +95,9 @@ canSmoothWith = null flags = NONE -/turf/open/floor/carpet/New() +/turf/open/floor/carpet/Initialize() ..() - spawn(1) - update_icon() + update_icon() /turf/open/floor/carpet/update_icon() if(!..()) @@ -131,6 +129,6 @@ broken_states = list("damaged") plane = PLANE_SPACE -/turf/open/floor/fakespace/New() +/turf/open/floor/fakespace/Initialize() ..() icon_state = "[rand(0,25)]" diff --git a/code/game/turfs/simulated/floor/light_floor.dm b/code/game/turfs/simulated/floor/light_floor.dm index 19a1357504..b078a220c4 100644 --- a/code/game/turfs/simulated/floor/light_floor.dm +++ b/code/game/turfs/simulated/floor/light_floor.dm @@ -12,7 +12,7 @@ var/can_modify_colour = TRUE -/turf/open/floor/light/New() +/turf/open/floor/light/Initialize() ..() update_icon() diff --git a/code/game/turfs/simulated/floor/mineral_floor.dm b/code/game/turfs/simulated/floor/mineral_floor.dm index 73ffc696c8..64c6be6520 100644 --- a/code/game/turfs/simulated/floor/mineral_floor.dm +++ b/code/game/turfs/simulated/floor/mineral_floor.dm @@ -16,7 +16,7 @@ -/turf/open/floor/mineral/New() +/turf/open/floor/mineral/Initialize() broken_states = list("[initial(icon_state)]_dam") ..() if (!icons) @@ -221,7 +221,7 @@ floor_tile = /obj/item/stack/tile/mineral/abductor icons = list("alienpod1", "alienpod2", "alienpod3", "alienpod4", "alienpod5", "alienpod6", "alienpod7", "alienpod8", "alienpod9") -/turf/open/floor/mineral/abductor/New() +/turf/open/floor/mineral/abductor/Initialize() ..() icon_state = "alienpod[rand(1,9)]" diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm index 2d9cd76f4a..82eb9c7bd7 100644 --- a/code/game/turfs/simulated/floor/misc_floor.dm +++ b/code/game/turfs/simulated/floor/misc_floor.dm @@ -13,9 +13,9 @@ icon_state = "bcircuit" floor_tile = /obj/item/stack/tile/plasteel -/turf/open/floor/bluegrid/New() - ..() +/turf/open/floor/bluegrid/Initialize() SSmapping.nuke_tiles += src + ..() /turf/open/floor/bluegrid/Destroy() SSmapping.nuke_tiles -= src @@ -67,7 +67,7 @@ icon_state = "plating" var/obj/effect/clockwork/overlay/floor/realappearence -/turf/open/floor/clockwork/New() +/turf/open/floor/clockwork/Initialize() ..() new /obj/effect/overlay/temp/ratvar/floor(src) new /obj/effect/overlay/temp/ratvar/beam(src) diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index de9cabe70b..c65865786c 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -13,7 +13,7 @@ icon_state = "plating" intact = 0 -/turf/open/floor/plating/New() +/turf/open/floor/plating/Initialize() if (!broken_states) broken_states = list("platingdmg1", "platingdmg2", "platingdmg3") if (!burnt_states) diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm index 272e3a68e1..9cc15172f9 100644 --- a/code/game/turfs/simulated/floor/plating/asteroid.dm +++ b/code/game/turfs/simulated/floor/plating/asteroid.dm @@ -15,7 +15,7 @@ var/sand_type = /obj/item/weapon/ore/glass var/floor_variance = 20 //probability floor has a different icon state -/turf/open/floor/plating/asteroid/New() +/turf/open/floor/plating/asteroid/Initialize() var/proper_name = name ..() name = proper_name @@ -117,7 +117,7 @@ /turf/open/floor/plating/asteroid/basalt/airless initial_gas_mix = "TEMP=2.7" -/turf/open/floor/plating/asteroid/basalt/New() +/turf/open/floor/plating/asteroid/basalt/Initialize() ..() switch(icon_state) if("basalt1", "basalt2", "basalt3") //5 and 9 are too dark to glow and make the amount of glows in tunnels too high @@ -176,7 +176,7 @@ /turf/open/floor/plating/asteroid/airless/cave/volcanic/has_data //subtype for producing a tunnel with given data has_data = TRUE -/turf/open/floor/plating/asteroid/airless/cave/New(loc) +/turf/open/floor/plating/asteroid/airless/cave/Initialize() if (!mob_spawn_list) mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/goldgrub = 1, /mob/living/simple_animal/hostile/asteroid/goliath = 5, /mob/living/simple_animal/hostile/asteroid/basilisk = 4, /mob/living/simple_animal/hostile/asteroid/hivelord = 3) if (!megafauna_spawn_list) @@ -186,7 +186,8 @@ if(!has_data) produce_tunnel_from_data() - ..() + else + ..() //do not continue after changeturfing or we will do a double initialize /turf/open/floor/plating/asteroid/airless/cave/proc/get_cave_data(set_length, exclude_dir = -1) // If set_length (arg1) isn't defined, get a random length; otherwise assign our length to the length arg. diff --git a/code/game/turfs/simulated/floor/plating/lava.dm b/code/game/turfs/simulated/floor/plating/lava.dm index 68aa66a1c3..4b52420394 100644 --- a/code/game/turfs/simulated/floor/plating/lava.dm +++ b/code/game/turfs/simulated/floor/plating/lava.dm @@ -7,12 +7,6 @@ baseturf = /turf/open/floor/plating/lava //lava all the way down slowdown = 2 luminosity = 1 - var/static/list/safeties_typecache = list(/obj/structure/lattice/catwalk) - //if anything matching this typecache is found in the lava, we don't burn things - -/turf/open/floor/plating/lava/New() - ..() - safeties_typecache = typecacheof(safeties_typecache) /turf/open/floor/plating/lava/ex_act() return @@ -51,7 +45,9 @@ /turf/open/floor/plating/lava/proc/is_safe() - var/list/found_safeties = typecache_filter_list(contents, safeties_typecache) + //if anything matching this typecache is found in the lava, we don't burn things + var/static/list/lava_safeties_typecache = typecacheof(list(/obj/structure/lattice/catwalk)) + var/list/found_safeties = typecache_filter_list(contents, lava_safeties_typecache) return LAZYLEN(found_safeties) diff --git a/code/game/turfs/simulated/floor/plating/misc_plating.dm b/code/game/turfs/simulated/floor/plating/misc_plating.dm index 730cc7b0ab..081b4becc6 100644 --- a/code/game/turfs/simulated/floor/plating/misc_plating.dm +++ b/code/game/turfs/simulated/floor/plating/misc_plating.dm @@ -7,7 +7,7 @@ name = "alien floor" icon_state = "alienpod1" -/turf/open/floor/plating/abductor/New() +/turf/open/floor/plating/abductor/Initialize() ..() icon_state = "alienpod[rand(1,9)]" @@ -41,7 +41,7 @@ initial_gas_mix = "o2=14;n2=23;TEMP=300" planetary_atmos = TRUE -/turf/open/floor/plating/ashplanet/New() +/turf/open/floor/plating/ashplanet/Initialize() if(smooth) pixel_y = -4 pixel_x = -4 @@ -72,7 +72,7 @@ icon_state = "wateryrock" slowdown = 2 -/turf/open/floor/plating/ashplanet/wateryrock/New() +/turf/open/floor/plating/ashplanet/wateryrock/Initialize() icon_state = "[icon_state][rand(1, 9)]" ..() @@ -113,7 +113,7 @@ name = "iron sand" desc = "Like sand, but more metal." -/turf/open/floor/plating/ironsand/New() +/turf/open/floor/plating/ironsand/Initialize() ..() icon_state = "ironsand[rand(1,15)]" diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm index 8ee346905d..ab01971446 100644 --- a/code/game/turfs/simulated/floor/reinf_floor.dm +++ b/code/game/turfs/simulated/floor/reinf_floor.dm @@ -106,7 +106,7 @@ icon_state = "plating" var/obj/effect/clockwork/overlay/floor/bloodcult/realappearence -/turf/open/floor/engine/cult/New() +/turf/open/floor/engine/cult/Initialize() ..() new /obj/effect/overlay/temp/cult/turf/floor(src) realappearence = new /obj/effect/clockwork/overlay/floor/bloodcult(src) diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index b15607f5b6..0883c19491 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -24,7 +24,7 @@ var/scan_state = null //Holder for the image we display when we're pinged by a mining scanner var/defer_change = 0 -/turf/closed/mineral/New() +/turf/closed/mineral/Initialize() if (!canSmoothWith) canSmoothWith = list(/turf/closed) pixel_y = -4 @@ -139,7 +139,7 @@ var/mineralChance = 13 var/display_icon_state = "rock" -/turf/closed/mineral/random/New() +/turf/closed/mineral/random/Initialize() if (!mineralSpawnChanceList) mineralSpawnChanceList = list( /turf/closed/mineral/uranium = 5, /turf/closed/mineral/diamond = 1, /turf/closed/mineral/gold = 10, @@ -385,7 +385,7 @@ var/activated_name = null var/activated_image = null -/turf/closed/mineral/gibtonite/New() +/turf/closed/mineral/gibtonite/Initialize() det_time = rand(8,10) //So you don't know exactly when the hot potato will explode ..() diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm index ce0b8a6107..a2828271a9 100644 --- a/code/game/turfs/simulated/wall/misc_walls.dm +++ b/code/game/turfs/simulated/wall/misc_walls.dm @@ -8,7 +8,7 @@ sheet_amount = 1 girder_type = /obj/structure/girder/cult -/turf/closed/wall/mineral/cult/New() +/turf/closed/wall/mineral/cult/Initialize() new /obj/effect/overlay/temp/cult/turf(src) ..() @@ -50,7 +50,7 @@ var/obj/effect/clockwork/overlay/wall/realappearence var/obj/structure/destructible/clockwork/cache/linkedcache -/turf/closed/wall/clockwork/New() +/turf/closed/wall/clockwork/Initialize() ..() new /obj/effect/overlay/temp/ratvar/wall(src) new /obj/effect/overlay/temp/ratvar/beam(src) diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index f922ba7dce..c0190a0fb2 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -15,15 +15,16 @@ var/global/datum/gas_mixture/space/space_gas = new plane = PLANE_SPACE -/turf/open/space/New() +/turf/open/space/Initialize() icon_state = SPACE_ICON_STATE air = space_gas + + if(initialized) + stack_trace("Warning: [src]([type]) initialized multiple times!") + initialized = TRUE -/turf/open/space/Destroy(force) - if(force) - . = ..() - else - return QDEL_HINT_LETMELIVE + if(requires_activation) + SSair.add_to_active(src) /turf/open/space/attack_ghost(mob/dead/observer/user) if(destination_z) diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm index 11e66e1680..dd772aa1ac 100644 --- a/code/game/turfs/space/transit.dm +++ b/code/game/turfs/space/transit.dm @@ -61,14 +61,12 @@ /turf/open/space/transit/attackby() return -/turf/open/space/transit/New() +/turf/open/space/transit/Initialize() ..() update_icon() for(var/atom/movable/AM in src) throw_atom(AM) - - /turf/open/space/transit/proc/update_icon() var/p = 9 var/angle = 0 diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 15c72dd107..640095ae48 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -23,14 +23,17 @@ var/explosion_id = 0 var/list/decals + var/requires_activation //add to air processing after initialize? /turf/SDQL_update(const/var_name, new_value) if(var_name == "x" || var_name == "y" || var_name == "z") return FALSE . = ..() -/turf/New() - ..() +/turf/Initialize() + if(initialized) + stack_trace("Warning: [src]([type]) initialized multiple times!") + initialized = TRUE levelupdate() if(smooth) @@ -40,11 +43,17 @@ for(var/atom/movable/AM in src) Entered(AM) + if(requires_activation) + CalculateAdjacentTurfs() + SSair.add_to_active(src) + /turf/proc/Initalize_Atmos(times_fired) CalculateAdjacentTurfs() /turf/Destroy() visibilityChanged() + initialized = FALSE + requires_activation = FALSE ..() return QDEL_HINT_HARDDEL_NOW @@ -454,4 +463,4 @@ /turf/proc/remove_decal(group) LAZYINITLIST(decals) overlays -= decals[group] - decals[group] = null \ No newline at end of file + decals[group] = null diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm index ee9b3f26c5..0405adb1cd 100644 --- a/code/modules/admin/fun_balloon.dm +++ b/code/modules/admin/fun_balloon.dm @@ -100,44 +100,6 @@ qdel(src) -//Luxury Shuttle Blockers - -/obj/effect/forcefield/luxury_shuttle - var/threshhold = 500 - var/list/approved_passengers = list() - -/obj/effect/forcefield/luxury_shuttle/CanPass(atom/movable/mover, turf/target, height=0) - if(mover in approved_passengers) - return 1 - - if(!isliving(mover)) //No stowaways - return 0 - - var/total_cash = 0 - var/list/counted_money = list() - - for(var/obj/item/weapon/coin/C in mover) - total_cash += C.value - counted_money += C - if(total_cash >= threshhold) - break - for(var/obj/item/stack/spacecash/S in mover) - total_cash += S.value * S.amount - counted_money += S - if(total_cash >= threshhold) - break - - if(total_cash >= threshhold) - for(var/obj/I in counted_money) - qdel(I) - - mover << "Thank you for your payment! Please enjoy your flight." - approved_passengers += mover - return 1 - else - mover << "You don't have enough money to enter the main shuttle. You'll have to fly coach." - return 0 - //Shuttle Build /obj/effect/shuttle_build @@ -149,4 +111,69 @@ /obj/effect/shuttle_build/New() SSshuttle.emergency.dock(SSshuttle.getDock("emergency_home")) - qdel(src) \ No newline at end of file + qdel(src) + +//Arena + +/obj/effect/forcefield/arena_shuttle + name = "portal" + var/list/warp_points = list() + + +/obj/effect/forcefield/arena_shuttle/Bumped(mob/M as mob|obj) + if(!warp_points.len) + warp_points = get_area_turfs(/area/shuttle/escape) + for(var/turf/T in warp_points) + for(var/atom/movable/AM in T) + if(AM.density && AM.anchored) + warp_points -= T + break + if(!isliving(M)) + return + else + var/mob/living/L = M + if(L.pulling && istype(L.pulling, /obj/item/bodypart/head)) + L << "Your offering is accepted. You may pass." + qdel(L.pulling) + var/turf/LA = pick(warp_points) + L.forceMove(LA) + L.hallucination = 0 + L << "The battle is won. Your bloodlust subsides." + for(var/obj/item/weapon/twohanded/required/chainsaw/doomslayer/chainsaw in L) + qdel(chainsaw) + else + L << "You are not yet worthy of passing. Drag a severed head to the barrier to be allowed entry to the hall of champions." + +/obj/effect/landmark/shuttle_arena_safe + name = "hall of champions" + desc = "For the winners." + +/obj/effect/landmark/shuttle_arena_entrance + name = "the arena" + desc = "A lava filled battlefield." + + +/obj/effect/forcefield/arena_shuttle_entrance + name = "portal" + var/list/warp_points = list() + +/obj/effect/forcefield/arena_shuttle_entrance/Bumped(mob/M as mob|obj) + if(!warp_points.len) + for(var/obj/effect/landmark/shuttle_arena_entrance/S in landmarks_list) + warp_points |= S + if(!isliving(M)) + return + + var/obj/effect/landmark/LA = pick(warp_points) + + M.forceMove(get_turf(LA)) + M << "You're trapped in a deadly arena! To escape, you'll need to drag a severed head to the escape portals." + spawn() + var/obj/effect/mine/pickup/bloodbath/B = new(M) + B.mineEffect(M) + + +/area/shuttle_arena + name = "arena" + has_gravity = 1 + requires_power = 0 diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 4320efd9b9..d987c30728 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -337,10 +337,40 @@ dat += "Time limit: [config.midround_antag_time_check] minutes into round
" dat += "Living crew limit: [config.midround_antag_life_check * 100]% of crew alive
" dat += "If limits past: [ticker.mode.round_ends_with_antag_death ? "End The Round" : "Continue As Extended"]
" - - dat += "
" dat += "End Round Now
" - dat += "[ticker.delay_end ? "End Round Normally" : "Delay Round End"]
" + dat += "[ticker.delay_end ? "End Round Normally" : "Delay Round End"]" + var/connected_players = clients.len + var/lobby_players = 0 + var/observers = 0 + var/observers_connected = 0 + var/living_players = 0 + var/living_players_connected = 0 + var/living_players_antagonist = 0 + var/other_players = 0 + for(var/mob/M in mob_list) + if(M.ckey) + if(isnewplayer(M)) + lobby_players++ + continue + else if(M.stat != DEAD && M.mind && !isbrain(M)) + living_players++ + if(M.mind.special_role) + living_players_antagonist++ + if(M.client) + living_players_connected++ + else if((M.stat == DEAD )||(isobserver(M))) + observers++ + if(M.client) + observers_connected++ + else + other_players++ + dat += "
Players:|[connected_players - lobby_players] ingame|[connected_players] connected|[lobby_players] lobby|" + dat += "
Living Players:|[living_players_connected] active|[living_players - living_players_connected] disconnected|[living_players_antagonist] antagonists|" + dat += "
Dead/Observing players:|[observers_connected] active|[observers - observers_connected] disconnected|" + if(other_players) + dat += "
[other_players] players in invalid state or the statistics code is bugged!" + dat += "
" + if(ticker.mode.syndicates.len) dat += "
" for(var/datum/mind/N in ticker.mode.syndicates) diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm index 15732e6218..aa71596b10 100644 --- a/code/modules/admin/sql_message_system.dm +++ b/code/modules/admin/sql_message_system.dm @@ -35,8 +35,8 @@ if(!timestamp) timestamp = SQLtime() if(!server) - if (config && config.server_name) - server = config.server_name + if (config && config.server_sql_name) + server = config.server_sql_name server = sanitizeSQL(server) if(isnull(secret)) switch(alert("Hide note from being viewed by players?", "Secret note?","Yes","No","Cancel")) @@ -332,7 +332,7 @@ proc/get_message_output(type, target_ckey) return if("watchlist entry") message_admins("Notice: [key_name_admin(target_ckey)] is on the watchlist and has just connected - Reason: [text]") - // send2irc_adminless_only("Watchlist", "[key_name(target_ckey)] is on the watchlist and has just connected - Reason: [text]") + send2irc_adminless_only("Watchlist", "[key_name(target_ckey)] is on the watchlist and has just connected - Reason: [text]") if("memo") output += "Memo by [admin_ckey] on [timestamp]" if(editor_ckey) @@ -352,8 +352,8 @@ proc/get_message_output(type, target_ckey) var/notetext notesfile >> notetext var/server - if(config && config.server_name) - server = config.server_name + if(config && config.server_sql_name) + server = config.server_sql_name var/regex/note = new("^(\\d{2}-\\w{3}-\\d{4}) \\| (.+) ~(\\w+)$", "i") note.Find(notetext) var/timestamp = note.group[1] diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 1ebe4e4fd1..9717beb688 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -1,4 +1,4 @@ -/proc/keywords_lookup(msg) +/proc/keywords_lookup(msg,irc) //This is a list of words which are ignored by the parser when comparing message contents for names. MUST BE IN LOWER CASE! var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","alien","as", "i") @@ -10,9 +10,11 @@ var/list/surnames = list() var/list/forenames = list() var/list/ckeys = list() + var/founds = "" for(var/mob/M in mob_list) var/list/indexing = list(M.real_name, M.name) - if(M.mind) indexing += M.mind.name + if(M.mind) + indexing += M.mind.name for(var/string in indexing) var/list/L = splittext(string, " ") @@ -52,9 +54,19 @@ mobs_found += found if(!ai_found && isAI(found)) ai_found = 1 - msg += "[original_word](?|F) " + var/is_antag = 0 + if(found.mind && found.mind.special_role) + is_antag = 1 + founds += "Name: [found.name]([found.real_name]) Ckey: [found.ckey] [is_antag ? "(Antag)" : null] " + msg += "[original_word](?|F) " continue msg += "[original_word] " + if(irc) + if(founds == "") + return "Search Failed" + else + return founds + return msg @@ -78,7 +90,20 @@ return if(src.handle_spam_prevention(msg,MUTE_ADMINHELP)) return - var/ref_mob = "\ref[mob]" + + + //clean the input msg + if(!msg) + return + msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN)) + if(!msg) return + var/original_msg = msg + + msg = keywords_lookup(msg) + + if(!mob) + return //this doesn't happen + var/ref_client = "\ref[src]" for(var/datum/adminticket/T in admintickets) if(T.permckey == src.ckey && T.resolved == "No") @@ -87,7 +112,7 @@ if(T.admin == "N/A") usr << "Due to the fact your Adminhelp had no assigned admin, admins have been pinged." message_admins("[src.ckey] has bumped their adminhelp #[T.ID], still no assigned admin!") - msg = "HELP: [key_name(src)] [ADMIN_QUE(mob)] [ADMIN_PP(mob)] [ADMIN_VV(mob)] [ADMIN_SM(mob)] [ADMIN_FLW(mob)] [ADMIN_TP(mob)] (REJT) (IC) (R): [msg]" + msg = "HELP: [key_name(src)] [ADMIN_QUE(mob)] [ADMIN_PP(mob)] [ADMIN_VV(mob)] [ADMIN_SM(mob)] [ADMIN_FLW(mob)] [ADMIN_TP(mob)] (REJT) (IC) (R): [msg]" for(var/client/X in admins) if(X.prefs.toggles & SOUND_ADMINHELP) X << 'sound/effects/adminhelp.ogg' @@ -104,27 +129,10 @@ src.verbs -= /client/verb/adminhelp adminhelptimerid = addtimer(CALLBACK(src, .proc/giveadminhelpverb), 1200, TIMER_STOPPABLE) - //clean the input msg - if(!msg) return - msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN)) - if(!msg) return - var/original_msg = msg - - msg = keywords_lookup(msg) - - if(!mob) return //this doesn't happen + for(var/datum/adminticket/T in admintickets) + msg = "HELP: [key_name(src)] [ADMIN_QUE(mob)] [ADMIN_PP(mob)] [ADMIN_VV(mob)] [ADMIN_SM(mob)] [ADMIN_FLW(mob)] [ADMIN_TP(mob)] (REJT) (IC) (R): [msg]" createticket(src, msg, src.ckey, mob) - - var/datum/adminticket/ticket - - for(var/datum/adminticket/T in admintickets) - if(T.permckey == src.ckey) - ticket = T - - msg = "ADMINHELP: [key_name(src)] (?) (PP) (VV) (SM) (TP) (FLW) (R): [msg]" - - //send this msg to all admins for(var/client/X in admins) @@ -138,88 +146,72 @@ src << "PM to-Admins: [original_msg]" //send it to irc if nobody is on and tell us how many were on - var/admin_number_present = send2irc_admin_notice_handler("adminhelp", ckey, original_msg) - log_admin("ADMINHELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins who have +BAN.") + var/admin_number_present = send2admindiscord(ckey,original_msg) + log_admin("HELP: [key_name(src)]: [original_msg] - heard by [admin_number_present] non-AFK admins who have +BAN.") + if(admin_number_present <= 0) + src << "No active admins are online, your adminhelp was sent to the admin irc." feedback_add_details("admin_verb","AH") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return -/proc/calculate_admins(type, requiredflags = R_BAN) - var/admin_number_total = 0 //Total number of admins - var/admin_number_afk = 0 //Holds the number of admins who are afk - var/admin_number_ignored = 0 //Holds the number of admins without +BAN (so admins who are not really admins) - var/admin_number_decrease = 0 //Holds the number of admins with are afk, ignored or both +/proc/get_admin_counts(requiredflags = R_BAN) + . = list("total" = list(), "noflags" = list(), "afk" = list(), "stealth" = list(), "present" = list()) for(var/client/X in admins) - admin_number_total++; - var/invalid = 0 + .["total"] += X if(requiredflags != 0 && !check_rights_for(X, requiredflags)) - admin_number_ignored++ - invalid = 1 - if(X.is_afk()) - admin_number_afk++ - invalid = 1 - if(X.holder.fakekey) - admin_number_ignored++ - invalid = 1 - if(invalid) - admin_number_decrease++ - switch(type) - if("ignored") - return admin_number_ignored - if("total") - return admin_number_total - if("away") - return admin_number_afk - if("present") - return admin_number_total - admin_number_decrease - return 0 + .["noflags"] += X + else if(X.is_afk()) + .["afk"] += X + else if(X.holder.fakekey) + .["stealth"] += X + else + .["present"] += X +/proc/send2irc_adminless_only(source, msg, requiredflags = R_BAN) + var/list/adm = get_admin_counts(requiredflags) + var/list/activemins = adm["present"] + . = activemins.len + if(. <= 0) + var/final = "" + var/list/afkmins = adm["afk"] + var/list/stealthmins = adm["stealth"] + var/list/powerlessmins = adm["noflags"] + var/list/allmins = adm["total"] + if(!afkmins.len && !stealthmins.len && !powerlessmins.len) + final = "[msg] - No admins online" + else + final = "[msg] - All admins stealthed\[[english_list(stealthmins)]\], AFK\[[english_list(afkmins)]\], or lacks +BAN\[[english_list(powerlessmins)]\]! Total: [allmins.len] " + send2irc(source,final) + send2admindiscord(source,final) -/proc/send2irc_admin_notice_handler(type, source, msg) - var/afk_admins = calculate_admins("away") - var/total_admins = calculate_admins("total") - var/ignored_admins = calculate_admins("ignored") - var/admin_number_present = calculate_admins("present") //Number of admins who are neither afk nor invalid - var/irc_message_afk = "[msg] - All admins AFK ([afk_admins]/[total_admins]) or skipped ([ignored_admins]/[total_admins])" - var/irc_message_normal = "[msg] - heard by [admin_number_present] non-AFK admins who have +BAN." - var/irc_message_adminless = "[msg] - No admins online" - - switch(type) - if("adminhelp") - if(config.announce_adminhelps) - send2irc(source, irc_message_normal) - else - if(admin_number_present <= 0) - if(!afk_admins && !ignored_admins) - send2admindiscord(source, irc_message_adminless) - else if(afk_admins >= 1) - send2admindiscord(source, irc_message_afk) - else - send2admindiscord(source, irc_message_normal) - if("watchlist") - if(config.announce_watchlist) - send2irc(source, irc_message_normal) - else - if(admin_number_present <= 0) - if(!afk_admins && !ignored_admins) - send2admindiscord(source, irc_message_adminless) - else if(afk_admins >= 1) - send2admindiscord(source, irc_message_afk) - else - send2admindiscord(source, irc_message_normal) - if("new_player") - if(config.irc_first_connection_alert) - send2irc(source, irc_message_normal) - else - if(admin_number_present <= 0) - if(!afk_admins && !ignored_admins) - send2admindiscord(source, irc_message_adminless) - else if(afk_admins >= 1) - send2admindiscord(source, irc_message_afk) - else - send2admindiscord(source, irc_message_normal) - return admin_number_present /proc/send2irc(msg,msg2) if(config.useircbot) - shell("python nudge.py [msg] \"[msg2]\"") - return \ No newline at end of file + shell("python nudge.py [msg] [msg2]") + return + +/proc/send2otherserver(source,msg,type = "Ahelp") + if(global.cross_allowed) + var/list/message = list() + message["message_sender"] = source + message["message"] = msg + message["source"] = "([config.cross_name])" + message["key"] = global.comms_key + message["crossmessage"] = type + + world.Export("[global.cross_address]?[list2params(message)]") + + +/proc/ircadminwho() + var/list/message = list("Admins: ") + var/list/admin_keys = list() + for(var/adm in admins) + var/client/C = adm + admin_keys += "[C][C.holder.fakekey ? "(Stealth)" : ""][C.is_afk() ? "(AFK)" : ""]" + + for(var/admin in admin_keys) + if(LAZYLEN(admin_keys) > 1) + message += ", [admin]" + else + message += "[admin]" + + return jointext(message, "") \ No newline at end of file diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 2e845e9c16..e6134d0c83 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -1,3 +1,5 @@ +#define IRCREPLYCOUNT 2 + //allows right clicking mobs to send an admin PM to their client, forwards the selected mob's client to cmd_admin_pm /client/proc/cmd_admin_pm_context(mob/M in mob_list) set category = null @@ -5,7 +7,8 @@ if(!holder) src << "Error: Admin-PM-Context: Only administrators may use this command." return - if( !ismob(M) || !M.client ) return + if( !ismob(M) || !M.client ) + return cmd_admin_pm(M.client,null) feedback_add_details("admin_verb","APMM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -19,16 +22,15 @@ var/list/client/targets[0] for(var/client/T) if(T.mob) - if(istype(T.mob, /mob/new_player)) + if(isnewplayer(T.mob)) targets["(New Player) - [T]"] = T - else if(istype(T.mob, /mob/dead/observer)) + else if(isobserver(T.mob)) targets["[T.mob.name](Ghost) - [T]"] = T else targets["[T.mob.real_name](as [T.mob.name]) - [T]"] = T else targets["(No Mob) - [T]"] = T - var/list/sorted = sortList(targets) - var/target = input(src,"To whom shall we send a message?","Admin PM",null) in sorted|null + var/target = input(src,"To whom shall we send a message?","Admin PM",null) as null|anything in sortList(targets) cmd_admin_pm(targets[target],null) feedback_add_details("admin_verb","APM") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! @@ -44,7 +46,8 @@ else if(istype(whom,/client)) C = whom if(!C) - if(holder) src << "Error: Admin-PM: Client not found." + if(holder) + src << "Error: Admin-PM: Client not found." return var/datum/adminticket/ticket @@ -205,4 +208,51 @@ //we don't use message_admins here because the sender/receiver might get it too for(var/client/X in admins) if(X.key!=key && X.key!=C.key) //check client/X is an admin and isn't the sender or recipient - X << "PM: [key_name(src, X, 0)]->[key_name(C, X, 0)]: \blue [keywordparsedmsg]" //inform X \ No newline at end of file + X << "PM: [key_name(src, X, 0)]->[key_name(C, X, 0)]: \blue [keywordparsedmsg]" //inform X + +/proc/IrcPm(target,msg,sender) + + var/client/C = directory[target] + + var/static/stealthkey + var/adminname = config.showircname ? "[sender](IRC)" : "Administrator" + + if(!C) + return "No client" + + if(!stealthkey) + stealthkey = GenIrcStealthKey() + + msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN)) + if(!msg) + return "No message" + + message_admins("IRC message from [sender] to [key_name_admin(C)] : [msg]") + log_admin("IRC PM: [sender] -> [key_name(C)] : [msg]") + msg = emoji_parse(msg) + + C << "-- Administrator private message --" + C << "Admin PM from-[adminname]: [msg]" + C << "Click on the administrator's name to reply." + window_flash(C) + //always play non-admin recipients the adminhelp sound + C << 'sound/effects/adminhelp.ogg' + + C.ircreplyamount = IRCREPLYCOUNT + + return "Message Successful" + +/proc/GenIrcStealthKey() + var/num = (rand(0,1000)) + var/i = 0 + while(i == 0) + i = 1 + for(var/P in stealthminID) + if(num == stealthminID[P]) + num++ + i = 0 + var/stealth = "@[num2text(num)]" + stealthminID["IRCKEY"] = stealth + return stealth + +#undef IRCREPLYCOUNT \ No newline at end of file diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index cfe320c407..b767248455 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -118,16 +118,19 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that if(isnull(argnum)) return - var/list/lst = list() - + . = list() + var/list/named_args = list() while(argnum--) + var/named_arg = input("Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument") as text|null var/value = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT)) if (!value["class"]) return - lst += value["value"] - - return lst - + if(named_arg) + named_args[named_arg] = value["value"] + else + . += value["value"] + if(LAZYLEN(named_args)) + . += named_args /client/proc/get_callproc_returnval(returnval,procname) . = "" diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index dadb31ba61..47fa529912 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -35,11 +35,11 @@ var/list/atmos_overlay_types //gas IDs of current active gas overlays -/turf/open/New() - ..() +/turf/open/Initialize() if(!blocks_air) air = new air.copy_from_turf(src) + ..() /turf/open/Destroy() if(active_hotspot) @@ -113,11 +113,12 @@ /turf/open/proc/tile_graphic() . = new /list - var/list/gases = air.gases - for(var/id in gases) - var/gas = gases[id] - if(gas[GAS_META][META_GAS_OVERLAY] && gas[MOLES] > gas[GAS_META][META_GAS_MOLES_VISIBLE]) - . += gas[GAS_META][META_GAS_OVERLAY] + if(air) + var/list/gases = air.gases + for(var/id in gases) + var/gas = gases[id] + if(gas[GAS_META][META_GAS_OVERLAY] && gas[MOLES] > gas[GAS_META][META_GAS_MOLES_VISIBLE]) + . += gas[GAS_META][META_GAS_OVERLAY] /////////////////////////////SIMULATION/////////////////////////////////// diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index d691cbb631..1c7277638e 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -99,26 +99,28 @@ flags_cover = MASKCOVERSEYES resistance_flags = FLAMMABLE actions_types = list(/datum/action/item_action/adjust) + -/obj/item/clothing/mask/gas/mime/attack_self(mob/user) - cycle_mask(user) +/obj/item/clothing/mask/gas/mime/ui_action_click(mob/user) + if(!istype(user) || user.incapacitated()) + return -/obj/item/clothing/mask/gas/mime/proc/cycle_mask(mob/user) - switch(icon_state) - if("mime") - icon_state = "sadmime" - if("sadmime") - icon_state = "scaredmime" - if("scaredmime") - icon_state = "sexymime" - if("sexymime") - icon_state = "mime" - user.update_inv_wear_mask() - for(var/X in actions) - var/datum/action/A = X - A.UpdateButtonIcon() - user << "You adjust your mask to portray a different emotion." - return 1 + var/list/options = list() + options["Blanc"] = "mime" + options["Triste"] = "sadmime" + options["Effrayé"] = "scaredmime" + options["Excité"] ="sexymime" + + var/choice = input(user,"To what form do you wish to Morph this mask?","Morph Mask") in options + + if(src && choice && !user.incapacitated() && in_range(user,src)) + icon_state = options[choice] + user.update_inv_wear_mask() + for(var/X in actions) + var/datum/action/A = X + A.UpdateButtonIcon() + user << "Your Mime Mask has now morphed into [choice]!" + return 1 /obj/item/clothing/mask/gas/monkeymask name = "monkey mask" @@ -170,6 +172,7 @@ resistance_flags = FLAMMABLE obj_integrity = 100 max_integrity = 100 + actions_types = list(/datum/action/item_action/adjust) dog_fashion = null @@ -186,7 +189,6 @@ obj/item/clothing/mask/gas/tiki_mask/ui_action_click(mob/user) if(src && choice && !M.stat && in_range(M,src)) icon_state = options[choice] - item_state = options[choice] user.update_inv_wear_mask() for(var/X in actions) var/datum/action/A = X diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index afe9d3d6da..8e44d2df01 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -268,6 +268,11 @@ /obj/item/clothing/suit/armor/reactive/tesla name = "reactive tesla armor" desc = "An experimental suit of armor with sensitive detectors hooked up to a huge capacitor grid, with emitters strutting out of it. Zap." + siemens_coefficient = -1 + var/tesla_power = 25000 + var/tesla_range = 20 + var/tesla_boom = FALSE + var/tesla_stun = FALSE /obj/item/clothing/suit/armor/reactive/tesla/hit_reaction(mob/living/carbon/human/owner, attack_text) if(!active) @@ -277,15 +282,10 @@ var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread sparks.set_up(1, 1, src) sparks.start() - owner.visible_message("The tesla capacitors on [owner]'s reactive telsa armor are still recharging! The armor merely emits some sparks.") + owner.visible_message("The tesla capacitors on [owner]'s reactive tesla armor are still recharging! The armor merely emits some sparks.") return owner.visible_message("The [src] blocks the [attack_text], sending out arcs of lightning!") - for(var/mob/living/M in view(6, owner)) - if(M == owner) - continue - owner.Beam(M,icon_state="lightning[rand(1, 12)]",time=5) - M.adjustFireLoss(25) - playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1) + tesla_zap(owner,tesla_range,tesla_power,tesla_boom, tesla_stun) reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration return 1 diff --git a/code/modules/events/sentience.dm b/code/modules/events/sentience.dm index f82b266175..8036f6d8f9 100644 --- a/code/modules/events/sentience.dm +++ b/code/modules/events/sentience.dm @@ -3,9 +3,12 @@ typepath = /datum/round_event/ghost_role/sentience weight = 10 + /datum/round_event/ghost_role/sentience minimum_required = 1 role_name = "random animal" + var/animals = 1 + var/one = "one" /datum/round_event/ghost_role/sentience/start() var/sentience_report = "[command_name()] Medium-Priority Update" @@ -14,7 +17,7 @@ var/pets = pick("animals/bots", "bots/animals", "pets", "simple animals", "lesser lifeforms", "\[REDACTED\]") var/strength = pick("human", "moderate", "lizard", "security", "command", "clown", "low", "very low", "\[REDACTED\]") - sentience_report += "

Based on [data], we believe that one of the station's [pets] has developed [strength] level intelligence, and the ability to communicate." + sentience_report += "

Based on [data], we believe that [one] of the station's [pets] has developed [strength] level intelligence, and the ability to communicate." print_command_report(sentience_report, "Classified [command_name()] Update") priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg') @@ -36,25 +39,40 @@ if(!potential.len) return WAITING_FOR_SOMETHING - var/mob/living/simple_animal/SA = pick(potential) if(!candidates.len) return NOT_ENOUGH_PLAYERS - var/mob/dead/observer/SG = pick(candidates) - SA.key = SG.key - SA.languages_spoken |= HUMAN - SA.languages_understood |= HUMAN - SA.sentience_act() + var/spawned_animals = 0 + while(spawned_animals < animals && candidates.len && potential.len) + var/mob/living/simple_animal/SA = pick_n_take(potential) + var/mob/dead/observer/SG = pick_n_take(candidates) - SA.maxHealth = max(SA.maxHealth, 200) - SA.health = SA.maxHealth - SA.del_on_death = FALSE + spawned_animals++ - spawned_mobs += SA + SA.key = SG.key + SA.languages_spoken |= HUMAN + SA.languages_understood |= HUMAN + SA.sentience_act() - SA << "Hello world!" - SA << "Due to freak radiation and/or chemicals \ - and/or lucky chance, you have gained human level intelligence \ - and the ability to speak and understand human language!" + SA.maxHealth = max(SA.maxHealth, 200) + SA.health = SA.maxHealth + SA.del_on_death = FALSE + + spawned_mobs += SA + + SA << "Hello world!" + SA << "Due to freak radiation and/or chemicals \ + and/or lucky chance, you have gained human level intelligence \ + and the ability to speak and understand human language!" return SUCCESSFUL_SPAWN + +/datum/round_event_control/sentience/all + name = "Station-wide Human-level Intelligence" + typepath = /datum/round_event/ghost_role/sentience/all + weight = 0 + +/datum/round_event/ghost_role/sentience/all + one = "all" + animals = INFINITY // as many as there are ghosts and animals + // cockroach pride, station wide diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm index dc0225c70b..f353cb4ff2 100644 --- a/code/modules/food_and_drinks/food/condiment.dm +++ b/code/modules/food_and_drinks/food/condiment.dm @@ -124,6 +124,12 @@ list_reagents = list("sodiumchloride" = 20) possible_states = list() +/obj/item/weapon/reagent_containers/food/condiment/saltshaker/on_reagent_change() + if(reagents.reagent_list.len == 0) + icon_state = "emptyshaker" + else + icon_state = "saltshakersmall" + /obj/item/weapon/reagent_containers/food/condiment/saltshaker/suicide_act(mob/user) user.visible_message("[user] begins to swap forms with the salt shaker! It looks like [user.p_theyre()] trying to commit suicide!") var/newname = "[name]" @@ -156,6 +162,12 @@ list_reagents = list("blackpepper" = 20) possible_states = list() +/obj/item/weapon/reagent_containers/food/condiment/peppermill/on_reagent_change() + if(reagents.reagent_list.len == 0) + icon_state = "emptyshaker" + else + icon_state = "peppermillsmall" + /obj/item/weapon/reagent_containers/food/condiment/milk name = "space milk" desc = "It's milk. White and nutritious goodness!" diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm index 56b1c12fee..e87a530ed2 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm @@ -18,6 +18,15 @@ insert ascii eagle on american flag background here container_type = OPENCONTAINER var/obj/item/frying = null //What's being fried RIGHT NOW? var/cook_time = 0 + var/static/list/blacklisted_items = typecacheof(list( + /obj/item/weapon/screwdriver, + /obj/item/weapon/crowbar, + /obj/item/weapon/wrench, + /obj/item/weapon/wirecutters, + /obj/item/device/multitool, + /obj/item/weapon/weldingtool, + /obj/item/weapon/reagent_containers/glass, + /obj/item/weapon/storage/part_replacer)) /obj/item/weapon/circuitboard/machine/deep_fryer name = "circuit board (Deep Fryer)" @@ -46,8 +55,16 @@ insert ascii eagle on american flag background here if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/deepfryholder)) user << "Your cooking skills are not up to the legendary Doublefry technique." return + if(default_unfasten_wrench(user, I)) + return + else if(exchange_parts(user, I)) + return + else if(default_deconstruction_screwdriver(user, "fryer_off", "fryer_off" ,I)) //where's the open maint panel icon?! + return else - if(user.drop_item() && !frying) + if(is_type_in_typecache(I, blacklisted_items)) + . = ..() + else if(user.drop_item() && !frying) user << "You put [I] into [src]." frying = I frying.forceMove(src) @@ -78,6 +95,7 @@ insert ascii eagle on american flag background here S.overlays = frying.overlays S.icon_state = frying.icon_state S.desc = frying.desc + S.w_class = frying.w_class reagents.trans_to(S, 2*(cook_time/15)) switch(cook_time) if(0 to 15) diff --git a/code/modules/holodeck/area_copy.dm b/code/modules/holodeck/area_copy.dm index a3c3e6c2b3..a8e0bebf20 100644 --- a/code/modules/holodeck/area_copy.dm +++ b/code/modules/holodeck/area_copy.dm @@ -110,7 +110,7 @@ if(V == "air") var/turf/open/O1 = B var/turf/open/O2 = T - O1.air.copy_from(O2.air) + O1.air.copy_from(O2.return_air()) continue B.vars[V] = T.vars[V] toupdate += B diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index de43b317af..e177894651 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -64,25 +64,25 @@ ..() /obj/machinery/computer/holodeck/Initialize(mapload) - ..() - if(!mapload && ticker.current_state < GAME_STATE_PLAYING) - return - program_cache = list() - emag_programs = list() - for(var/typekey in subtypesof(program_type)) - var/area/holodeck/A = locate(typekey) - if(!A || A == offline_program) continue - if(A.contents.len == 0) continue // not loaded - if(A.restricted) - emag_programs += A - else - program_cache += A - if(typekey == init_program) - load_program(A,force=1) - if(random_program && program_cache.len && init_program == null) - load_program(pick(program_cache),force=1) - else if(!program) - load_program(offline_program) + . = mapload //late-initialize, area_copy need turfs to have air + if(!mapload) + ..() + program_cache = list() + emag_programs = list() + for(var/typekey in subtypesof(program_type)) + var/area/holodeck/A = locate(typekey) + if(!A || A == offline_program) continue + if(A.contents.len == 0) continue // not loaded + if(A.restricted) + emag_programs += A + else + program_cache += A + if(typekey == init_program) + load_program(A,force=1) + if(random_program && program_cache.len && init_program == null) + load_program(pick(program_cache),force=1) + else if(!program) + load_program(offline_program) /obj/machinery/computer/holodeck/power_change() ..() diff --git a/code/modules/holodeck/turfs.dm b/code/modules/holodeck/turfs.dm index e62fb393fe..b853f6d336 100644 --- a/code/modules/holodeck/turfs.dm +++ b/code/modules/holodeck/turfs.dm @@ -42,7 +42,7 @@ name = "asteroid" icon_state = "asteroid0" -/turf/open/floor/holofloor/asteroid/New() +/turf/open/floor/holofloor/asteroid/Initialize() icon_state = "asteroid[pick(0,1,2,3,4,5,6,7,8,9,10,11,12)]" ..() @@ -50,7 +50,7 @@ name = "basalt" icon_state = "basalt0" -/turf/open/floor/holofloor/basalt/New() +/turf/open/floor/holofloor/basalt/Initialize() icon_state = "basalt[pick(0,1,2,3,4,5,6,7,8,9,10,11,12)]" ..() @@ -59,7 +59,7 @@ icon = 'icons/turf/space.dmi' icon_state = "0" -/turf/open/floor/holofloor/space/New() +/turf/open/floor/holofloor/space/Initialize() icon_state = SPACE_ICON_STATE // so realistic ..() @@ -68,11 +68,11 @@ icon = 'icons/turf/space.dmi' icon_state = "speedspace_ns_1" -/turf/open/floor/holofloor/hyperspace/New() +/turf/open/floor/holofloor/hyperspace/Initialize() icon_state = "speedspace_ns_[(x + 5*y + (y%2+1)*7)%15+1]" ..() -/turf/open/floor/holofloor/hyperspace/ns/New() +/turf/open/floor/holofloor/hyperspace/ns/Initialize() ..() icon_state = "speedspace_ns_[(x + 5*y + (y%2+1)*7)%15+1]" @@ -86,7 +86,7 @@ smooth = SMOOTH_TRUE canSmoothWith = null -/turf/open/floor/holofloor/carpet/New() +/turf/open/floor/holofloor/carpet/Initialize() ..() addtimer(CALLBACK(src, .proc/update_icon), 1) diff --git a/code/modules/library/soapstone.dm b/code/modules/library/soapstone.dm index a313d6aa0f..a512f12125 100644 --- a/code/modules/library/soapstone.dm +++ b/code/modules/library/soapstone.dm @@ -1,40 +1,22 @@ -#define SOAPSTONE_PREFIX_FILE "strings/soapstone_prefixes.txt" -#define SOAPSTONE_SUFFIX_FILE "soapstone_suffixes.json" -//Vocabulary lists; soapstones use a prefix and a suffix. Optionally, they can have a prefix and suffix, then a conjunction that links another set. -var/global/list/soapstone_prefixes = list() //Read from "strings/soapstone_prefixes.txt"; if you're adding your own, put **** where the subject should be! -var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffixes.json" /obj/item/soapstone name = "chisel" - desc = "Leave \"informative\" messages for the crew, including the crew of future shifts!\n\ - (Not suitable for engraving on shuttles, off station or on cats. Side effects may include beatings, bannings and orbital bombardment.)" + desc = "Leave informative messages for the crew, including the crew of future shifts!\nEven if out of uses, it can still be used to remove messages.\n(Not suitable for engraving on shuttles, off station or on cats. Side effects may include beatings, bannings and orbital bombardment.)" icon = 'icons/obj/items.dmi' icon_state = "soapstone" throw_speed = 3 throw_range = 5 w_class = WEIGHT_CLASS_TINY + var/tool_speed = 50 var/remaining_uses = 3 var/non_dull_name + var/w_engrave = "engrave" + var/w_engraving = "engraving" + var/w_chipping = "chipping" var/w_dull = "dull" /obj/item/soapstone/New() . = ..() - if(!soapstone_prefixes.len) - soapstone_prefixes = file2list(SOAPSTONE_PREFIX_FILE, "\n") - if(!soapstone_suffixes.len) - soapstone_suffixes = list(\ - "Characters" = strings(SOAPSTONE_SUFFIX_FILE, "Characters"), \ - "Careers" = strings(SOAPSTONE_SUFFIX_FILE, "Careers"), \ - "Antagonists" = strings(SOAPSTONE_SUFFIX_FILE, "Antagonists"), \ - "Objects" = strings(SOAPSTONE_SUFFIX_FILE, "Objects"), \ - "Techniques" = strings(SOAPSTONE_SUFFIX_FILE, "Techniques"), \ - "Actions" = strings(SOAPSTONE_SUFFIX_FILE, "Actions"), \ - "Geography" = strings(SOAPSTONE_SUFFIX_FILE, "Geography"), \ - "Orientation" = strings(SOAPSTONE_SUFFIX_FILE, "Orientation"), \ - "Body parts" = strings(SOAPSTONE_SUFFIX_FILE, "Body parts"), \ - "Concepts" = strings(SOAPSTONE_SUFFIX_FILE, "Concepts"), \ - "Musings" = strings(SOAPSTONE_SUFFIX_FILE, "Musings"), \ - ) random_name() check_name() // could start empty @@ -43,6 +25,9 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi non_dull_name = name if(name == "chalk" || name == "magic marker") desc = replacetext(desc, "engraving", "scribbling") + w_engrave = "scribble" + w_engraving = "scribbling" + w_chipping = "sketching" if(name == "chalk") w_dull = "used" if(name == "magic marker") @@ -50,6 +35,9 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi if(name == "soapstone" || name == "chisel") desc = replacetext(desc, "scribbling", "engraving") + w_engrave = initial(w_engrave) + w_engraving = initial(w_engraving) + w_chipping = initial(w_chipping) w_dull = "dull" /obj/item/soapstone/examine(mob/user) @@ -60,48 +48,59 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi user << "It looks like it can be used an unlimited number of times." /obj/item/soapstone/afterattack(atom/target, mob/user, proximity) - if(!remaining_uses) - user << "[src] is [w_dull] and can't be used anymore!" - return var/turf/T = get_turf(target) if(!proximity) return - var/obj/structure/chisel_message/msg = locate() in T - if(msg) - if(msg.creator_key != user.ckey) - user << "There's already a message there!" - return - else - if(alert(user, "Erase this message?", name, "Yes", "No") == "Yes") - user.visible_message("[user] erases [msg].", "You permanently erase [msg].") - playsound(T, 'sound/items/gavel.ogg', 50, 1) - refund_use() - msg.persists = 0 - qdel(msg) - return - return + + + var/obj/structure/chisel_message/already_message = locate(/obj/structure/chisel_message) in T + + var/our_message = FALSE + if(already_message) + our_message = already_message.creator_key == user.ckey + + if(!remaining_uses && !already_message) + // The dull chisel is dull. + user << "[src] is [w_dull]." + return + if(!good_chisel_message_location(T)) - user << "You can't write there!" + user << "It's not appropriate to [w_engrave] on [T]." return - var/prefix = input(user, "Choose a prefix for your message.", name) as null|anything in soapstone_prefixes - if(!prefix) + + if(already_message) + user.visible_message("[user] starts erasing [already_message].", "You start erasing [already_message].", "You hear a [w_chipping] sound.") + playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1) + + // Removing our own messages refunds a charge + + if(do_after(user, tool_speed, target=target)) + user.visible_message("[user] has erased [already_message].", "You erased [already_message].") + already_message.persists = FALSE + qdel(already_message) + playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1) + if(our_message) + refund_use() return - var/suffix_category_string = input(user, "Choose a suffix category.", "[prefix]...") as null|anything in soapstone_suffixes - var/list/suffix_category = soapstone_suffixes[suffix_category_string] - if(!suffix_category || !suffix_category.len) + + var/message = stripped_input(user, "What would you like to [w_engrave]?", "[name] Message") + if(!message) + user << "You decide not to [w_engrave] anything." return - var/suffix = input(user, "Choose a suffix.", "[prefix]...") as null|anything in suffix_category - if(!suffix) + + if(!target.Adjacent(user) && locate(/obj/structure/chisel_message) in T) + user << "You decide not to [w_engrave] anything." return - var/processed_message = replacetext(prefix, "****", suffix) - if(!user.Adjacent(T) || !good_chisel_message_location(T) || locate(/obj/structure/chisel_message) in T) - return - user.visible_message("[user] writes a message onto [T]!", "You write a message onto [T].") - playsound(T, 'sound/items/gavel.ogg', 50, 1) - var/obj/structure/chisel_message/M = new(T) - M.register(user, processed_message) - remove_use() - return 1 + + playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1) + user.visible_message("[user] starts [w_engraving] a message into [T].", "You start [w_engraving] a message into [T].", "You hear a [w_chipping] sound.") + if(can_use() && do_after(user, tool_speed, target=T) && can_use()) + if(!locate(/obj/structure/chisel_message in T)) + user << "You [w_engrave] a message into [T]." + playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1) + var/obj/structure/chisel_message/M = new(T) + M.register(user, message) + remove_use() /obj/item/soapstone/proc/can_use() if(remaining_uses == -1 || remaining_uses >= 0) @@ -172,34 +171,6 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi var/map var/persists = TRUE - var/positive_ratings = 0 - var/negative_ratings = 0 - - var/list/raters = list() //Ckeys who have rated this message - -/obj/structure/chisel_message/attack_hand(mob/user) - if(user.ckey == creator_key) - user << "You can't rate your own messages!" - return - if(raters[user.ckey]) - user << "You've already rated this message!" - return - switch(alert(user, "How would you like to rate this message?", "Message Rating", "Positive", "Negative", "Cancel")) - if("Positive") - for(var/client/C in clients) - if(C.ckey == creator_key) - C.mob << "One of your messages was rated as positive!" - user << "You rated this message as positive." - positive_ratings++ - raters[user.ckey] = "positive" - if("Negative") - for(var/client/C in clients) - if(C.ckey == creator_key) - C.mob << "One of your messages was rated as negative!" - user << "You rated this message as negative." - negative_ratings++ - raters[user.ckey] = "negative" - /obj/structure/chisel_message/New(newloc) ..() SSpersistence.chisel_messages += src @@ -219,6 +190,12 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi map = MAP_NAME update_icon() +/obj/structure/chisel_message/update_icon() + ..() + var/hash = md5(hidden_message) + var/newcolor = copytext(hash, 1, 7) + add_atom_colour("#[newcolor]", FIXED_COLOUR_PRIORITY) + /obj/structure/chisel_message/proc/pack() var/list/data = list() data["hidden_message"] = hidden_message @@ -229,9 +206,6 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi var/turf/T = get_turf(src) data["x"] = T.x data["y"] = T.y - data["pos_ratings"] = positive_ratings - data["neg_ratings"] = positive_ratings - data["raters"] = raters return data /obj/structure/chisel_message/proc/unpack(list/data) @@ -239,9 +213,6 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi creator_name = data["creator_name"] creator_key = data["creator_key"] realdate = data["realdate"] - positive_ratings = data["pos_ratings"] - negative_ratings = data["neg_ratings"] - raters = data["raters"] var/x = data["x"] var/y = data["y"] @@ -251,10 +222,7 @@ var/global/list/soapstone_suffixes = list() //Read from "strings/soapstone_suffi /obj/structure/chisel_message/examine(mob/user) ..() - user << "[hidden_message]" - user << "Ratings: [positive_ratings] [negative_ratings]" - if(raters[user.ckey]) - user << "You rated this message as [raters[user.ckey]]." + user << "[hidden_message]" /obj/structure/chisel_message/Destroy() if(persists) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index fba1682828..6b9f4226c0 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -91,20 +91,29 @@ return 1 return ..() -/mob/living/carbon/throw_impact(atom/hit_atom) +/mob/living/carbon/throw_impact(atom/hit_atom, throwingdatum) . = ..() + var/hurt = TRUE + if(istype(throwingdatum, /datum/thrownthing)) + var/datum/thrownthing/D = throwingdatum + if(iscyborg(D.thrower)) + var/mob/living/silicon/robot/R = D.thrower + if(!R.emagged) + hurt = FALSE if(hit_atom.density && isturf(hit_atom)) - Weaken(1) - take_bodypart_damage(10) + if(hurt) + Weaken(1) + take_bodypart_damage(10) if(iscarbon(hit_atom) && hit_atom != src) var/mob/living/carbon/victim = hit_atom if(victim.movement_type & FLYING) return - victim.Weaken(1) - Weaken(1) - victim.take_bodypart_damage(10) - take_bodypart_damage(10) - visible_message("[src] crashes into [victim], knocking them both over!", "You violently crash into [victim]!") + if(hurt) + victim.take_bodypart_damage(10) + take_bodypart_damage(10) + victim.Weaken(1) + Weaken(1) + visible_message("[src] crashes into [victim], knocking them both over!", "You violently crash into [victim]!") playsound(src,'sound/weapons/punch1.ogg',50,1) @@ -231,23 +240,6 @@ /mob/living/carbon/is_muzzled() return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle)) -/mob/living/carbon/proc/spin(spintime, speed) - set waitfor = 0 - var/D = dir - while(spintime >= speed) - sleep(speed) - switch(D) - if(NORTH) - D = EAST - if(SOUTH) - D = WEST - if(EAST) - D = SOUTH - if(WEST) - D = NORTH - setDir(D) - spintime -= speed - /mob/living/carbon/resist_buckle() if(restrained()) changeNext_move(CLICK_CD_BREAKOUT) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 70592e6c62..3403bd86bb 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -168,7 +168,7 @@ O.emp_act(severity) ..() -/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0) +/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE) if(tesla_shock && tesla_ignore) return FALSE shock_damage *= siemens_coeff @@ -190,11 +190,11 @@ jitteriness += 1000 //High numbers for violent convulsions do_jitter_animation(jitteriness) stuttering += 2 - if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) + if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun) Stun(2) spawn(20) jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less - if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) + if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun) Stun(3) Weaken(3) if(override) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 5b7e2e28c6..93e4e67302 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -436,7 +436,7 @@ //Added a safety check in case you want to shock a human mob directly through electrocute_act. -/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0) +/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE) if(tesla_shock) var/total_coeff = 1 if(gloves) @@ -447,6 +447,8 @@ var/obj/item/clothing/suit/S = wear_suit if(S.siemens_coefficient <= 0) total_coeff -= 0.95 + else if(S.siemens_coefficient == (-1)) + total_coeff -= 1 siemens_coeff = total_coeff if(tesla_ignore) siemens_coeff = 0 @@ -461,7 +463,7 @@ heart_attack = 0 if(stat == CONSCIOUS) src << "You feel your heart beating again!" - . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion) + . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock, illusion, stun) if(.) electrocution_animation(40) @@ -754,4 +756,4 @@ torn_items += leg_clothes for(var/obj/item/I in torn_items) - I.take_damage(damage_amount, damage_type, damage_flag, 0) \ No newline at end of file + I.take_damage(damage_amount, damage_type, damage_flag, 0) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 6b97157507..443fb6e3fb 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1015,7 +1015,7 @@ var/obj/item/organ/cyberimp/chest/thrusters/T = H.getorganslot("thrusters") if(!istype(J) && istype(C)) J = C.jetpack - if(istype(J) && J.allow_thrust(0.01, H)) //Prevents stacking + if(istype(J) && J.full_speed && J.allow_thrust(0.01, H)) //Prevents stacking . -= 2 else if(istype(T) && T.allow_thrust(0.01, H)) . -= 2 diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index a4628812ea..9bf97266d8 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -150,4 +150,14 @@ return 1 /mob/living/carbon/monkey/can_use_guns(var/obj/item/weapon/gun/G) - return 1 \ No newline at end of file + return 1 + +/mob/living/carbon/monkey/angry + aggressive = TRUE + +/mob/living/carbon/monkey/angry/Initialize() + ..() + if(prob(10)) + var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src) + equip_to_slot_or_del(helmet,slot_head) + helmet.attack_self(src) // todo encapsulate toggle \ No newline at end of file diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index ac631e8095..97105c3994 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -93,6 +93,7 @@ if(istype(S) && S.deathmessage) message_simple = S.deathmessage . = ..() + message_simple = initial(message_simple) if(. && isalienadult(user)) playsound(user.loc, 'sound/voice/hiss6.ogg', 80, 1, 1) @@ -451,3 +452,15 @@ message = "beeps." message_param = "beeps at %t." sound = 'sound/machines/twobeep.ogg' + +/datum/emote/living/spin + key = "spin" + key_third_person = "spins" + message = "spins around dizzily!" + +/datum/emote/living/spin/run_emote(mob/user) + user.spin(20, 1) + if(istype(user, /mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = user + R.riding_datum.force_dismount() + ..() \ No newline at end of file diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 8486f85145..0d10db0cd6 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -274,8 +274,7 @@ take_bodypart_damage(acidpwr * min(1, acid_volume * 0.1)) return 1 - -/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0) +/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE) if(tesla_shock && tesla_ignore) return FALSE if(shock_damage > 0) @@ -325,13 +324,16 @@ /mob/living/ratvar_act() - if(stat != DEAD && !is_servant_of_ratvar(src) && !add_servant_of_ratvar(src)) - src << "A blinding light boils you alive! Run!" - adjustFireLoss(35) - if(src) - adjust_fire_stacks(1) - IgniteMob() - return FALSE + if(stat != DEAD && !is_servant_of_ratvar(src)) + for(var/obj/item/weapon/implant/mindshield/M in implants) + qdel(M) + if(!add_servant_of_ratvar(src)) + src << "A blinding light boils you alive! Run!" + adjustFireLoss(35) + if(src) + adjust_fire_stacks(1) + IgniteMob() + return FALSE return TRUE diff --git a/code/modules/mob/living/silicon/pai/examine.dm b/code/modules/mob/living/silicon/pai/examine.dm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 1cadb8ec40..f1c0d9566b 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -57,11 +57,11 @@ var/chassis = "repairbot" var/list/possible_chassis = list("cat", "mouse", "monkey", "corgi", "fox", "repairbot", "rabbit") - var/emitterhealth = 50 - var/emittermaxhealth = 50 - var/emitterregen = 0.5 - var/emittercd = 20 - var/emitteroverloadcd = 50 + var/emitterhealth = 20 + var/emittermaxhealth = 20 + var/emitterregen = 0.25 + var/emittercd = 50 + var/emitteroverloadcd = 100 var/emittersemicd = FALSE var/overload_ventcrawl = 0 @@ -235,4 +235,4 @@ /mob/living/silicon/pai/process() emitterhealth = Clamp((emitterhealth + emitterregen), -50, emittermaxhealth) - hit_slowdown = Clamp((hit_slowdown - 1), 0, 100) + hit_slowdown = Clamp((hit_slowdown - 1), 0, 100) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm index d03aeada87..3e531eaaa0 100644 --- a/code/modules/mob/living/silicon/robot/death.dm +++ b/code/modules/mob/living/silicon/robot/death.dm @@ -30,4 +30,6 @@ update_icons() - sql_report_death(src) \ No newline at end of file + unbuckle_all_mobs(TRUE) + + sql_report_death(src) diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm index f4639706b9..04228c06c9 100644 --- a/code/modules/mob/living/silicon/robot/emote.dm +++ b/code/modules/mob/living/silicon/robot/emote.dm @@ -69,4 +69,4 @@ "You announce you are operating in low power mode.") playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0) else - src << "You can only use this emote when you're out of charge." \ No newline at end of file + src << "You can only use this emote when you're out of charge." diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 84471f1870..cddc2f3db9 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -89,7 +89,9 @@ /obj/item/clothing/head/sombrero, /obj/item/clothing/head/witchunter_hat) - + can_buckle = TRUE + buckle_lying = FALSE + var/datum/riding/cyborg/riding_datum = null /mob/living/silicon/robot/New(loc) spark_system = new /datum/effect_system/spark_spread() @@ -995,3 +997,90 @@ hat = new_hat new_hat.forceMove(src) update_icons() + +/mob/living/silicon/robot/MouseDrop_T(mob/living/M, mob/living/user) + . = ..() + if(!(M in buckled_mobs)) + buckle_mob(M) + +/mob/living/silicon/robot/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) + if(!riding_datum) + riding_datum = new /datum/riding/cyborg + riding_datum.ridden = src + if(buckled_mobs) + if(buckled_mobs.len >= max_buckled_mobs) + return + if(M in buckled_mobs) + return + if(stat) + return + if(incapacitated()) + return + if(M.restrained()) + return + if(iscyborg(M)) + M.visible_message("[M] really can't seem to mount the [src]...") + return + if(isbot(M)) + M.visible_message("No. Just... no.") + return + if(module) + if(!module.allow_riding) + M.visible_message("Unfortunately, [M] just can't seem to hold onto [src]!") + return + if(iscarbon(M)) + if(!equip_buckle_inhands(M)) //MAKE SURE THIS IS LAST! + M.visible_message("[M] can't climb onto [src] because his hands are full!") + return + . = ..(M, force, check_loc) + riding_datum.handle_vehicle_offsets() + +/mob/living/silicon/robot/unbuckle_mob(mob/user) + if(iscarbon(user)) + unequip_buckle_inhands(user) + . = ..(user) + riding_datum.restore_position(user) + +/mob/living/silicon/robot/proc/unequip_buckle_inhands(mob/living/carbon/user) + for(var/obj/item/cyborgride_offhand/O in user.contents) + if(O.ridden != src) + CRASH("RIDING OFFHAND ON WRONG MOB") + continue + if(O.selfdeleting) + continue + else + qdel(O) + return TRUE + +/mob/living/silicon/robot/proc/equip_buckle_inhands(mob/living/carbon/user) + var/obj/item/cyborgride_offhand/inhand = new /obj/item/cyborgride_offhand(user) + inhand.rider = user + inhand.ridden = src + return user.put_in_hands(inhand, TRUE) + +/obj/item/cyborgride_offhand + name = "offhand" + icon = 'icons/obj/weapons.dmi' + icon_state = "offhand" + w_class = WEIGHT_CLASS_HUGE + flags = ABSTRACT | DROPDEL | NOBLUDGEON + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + var/mob/living/carbon/rider + var/mob/living/silicon/robot/ridden + var/selfdeleting = FALSE + +/obj/item/cyborgride_offhand/dropped() + selfdeleting = TRUE + . = ..() + +/obj/item/cyborgride_offhand/equipped() + if(loc != rider) + selfdeleting = TRUE + qdel(src) + . = ..() + +/obj/item/cyborgride_offhand/Destroy() + if(selfdeleting) + if(rider in ridden.buckled_mobs) + ridden.unbuckle_mob(rider) + . = ..() diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 6b04e762bf..ff9f623b37 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -26,6 +26,11 @@ var/hat_offset = -3 + var/list/ride_offset_x = list("north" = 0, "south" = 0, "east" = -6, "west" = 6) + var/list/ride_offset_y = list("north" = 4, "south" = 4, "east" = 3, "west" = 3) + var/ride_allow_incapacitated = FALSE + var/allow_riding = TRUE + /obj/item/weapon/robot_module/New() ..() for(var/i in basic_modules) diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm index cbfed648cf..4f1396e010 100644 --- a/code/modules/mob/living/silicon/robot/robot_movement.dm +++ b/code/modules/mob/living/silicon/robot/robot_movement.dm @@ -17,3 +17,8 @@ /mob/living/silicon/robot/experience_pressure_difference(pressure_difference, direction) if(!magpulse) return ..() + +/mob/living/silicon/robot/Moved() + . = ..() + if(riding_datum) + riding_datum.on_vehicle_move() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index b9d27aebb6..06114cf1bf 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -26,6 +26,11 @@ /mob/living/silicon/attack_animal(mob/living/simple_animal/M) if(..()) var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) + if(prob(damage)) + for(var/mob/living/N in buckled_mobs) + N.Weaken(1) + unbuckle_mob(N) + N.visible_message("[N] is knocked off of [src] by [M]!") switch(M.melee_damage_type) if(BRUTE) adjustBruteLoss(damage) @@ -73,6 +78,10 @@ return 0 /mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0) + if(buckled_mobs) + for(var/mob/living/M in buckled_mobs) + unbuckle_mob(M) + M.electrocute_act(shock_damage/100, source, siemens_coeff, safety, tesla_shock, illusion) //Hard metal shell conducts! return 0 //So borgs they don't die trying to fix wiring /mob/living/silicon/emp_act(severity) @@ -83,12 +92,26 @@ src.take_bodypart_damage(10) src << "*BZZZT*" src << "Warning: Electromagnetic pulse detected." + for(var/mob/living/M in buckled_mobs) + if(prob(severity*50)) + unbuckle_mob(M) + M.Weaken(2) + M.visible_message("[M] is thrown off of [src]!") flash_act(affect_silicon = 1) ..() /mob/living/silicon/bullet_act(obj/item/projectile/Proj) if((Proj.damage_type == BRUTE || Proj.damage_type == BURN)) adjustBruteLoss(Proj.damage) + if(prob(Proj.damage*1.5)) + for(var/mob/living/M in buckled_mobs) + M.visible_message("[M] is knocked off of [src]!") + unbuckle_mob(M) + M.Weaken(2) + if(Proj.stun || Proj.weaken) + for(var/mob/living/M in buckled_mobs) + unbuckle_mob(M) + M.visible_message("[M] is knocked off of [src] by the [Proj]!") Proj.on_hit(src) return 2 diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index afef74db8c..cc0062775c 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -145,8 +145,9 @@ Auto Patrol: []"}, mode = BOT_HUNT /mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H) - if(H.a_intent == INTENT_HARM) + if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM)) retaliate(H) + return ..() /mob/living/simple_animal/bot/secbot/attackby(obj/item/weapon/W, mob/user, params) @@ -409,4 +410,4 @@ Auto Patrol: []"}, ..() /obj/machinery/bot_core/secbot - req_access = list(access_security) + req_access = list(access_security) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index 6623271f95..253968d20a 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -98,7 +98,7 @@ Difficulty: Hard INVOKE_ASYNC(src, .proc/charge) else if(prob(70) || warped) - INVOKE_ASYNC(src, .proc/triple_charge) + INVOKE_ASYNC(src, .proc/charge, 2) else INVOKE_ASYNC(src, .proc/warp_charge) @@ -141,12 +141,7 @@ Difficulty: Hard blood_warp() charge() -/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge() - charge() - charge() - charge() - -/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge() +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge(bonus_charges) var/turf/T = get_turf(target) if(!T || T == loc) return @@ -156,14 +151,18 @@ Difficulty: Hard walk(src, 0) setDir(get_dir(src, T)) var/obj/effect/overlay/temp/decoy/D = new /obj/effect/overlay/temp/decoy(loc,src) - animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 5) - sleep(5) - throw_at(T, get_dist(src, T), 1, src, 0, callback = CALLBACK(src, .charge_end)) -/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge_end() + animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 3) + sleep(3) + throw_at(T, get_dist(src, T), 0.5, src, 0, callback = CALLBACK(src, .charge_end, bonus_charges)) + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge_end(bonus_charges) charging = 0 try_bloodattack() if(target) - Goto(target, move_to_delay, minimum_distance) + if(bonus_charges) + charge(bonus_charges--) + else + Goto(target, move_to_delay, minimum_distance) /mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A) @@ -312,8 +311,8 @@ Difficulty: Hard DA.color = "#FF0000" var/oldtransform = DA.transform DA.transform = matrix()*2 - animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 5) - sleep(5) + animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 3) + sleep(3) qdel(DA) var/obj/effect/decal/cleanable/blood/found_bloodpool diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 8770fa79a1..3ed5f93c81 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -299,21 +299,20 @@ if(!gibbed) if(death_sound) playsound(get_turf(src),death_sound, 200, 1) - if(deathmessage && !del_on_death) + if(deathmessage || !del_on_death) emote("deathgasp") if(del_on_death) - ghostize() + ..() //Prevent infinite loops if the mob Destroy() is overriden in such //a manner as to cause a call to death() again del_on_death = FALSE qdel(src) - return else health = 0 icon_state = icon_dead density = 0 lying = 1 - ..() + ..() /mob/living/simple_animal/proc/CanAttack(atom/the_target) if(see_invisible < the_target.invisibility) @@ -551,4 +550,4 @@ /mob/living/simple_animal/buckle_mob(mob/living/buckled_mob, force = 0, check_loc = 1) . = ..() - riding_datum = new/datum/riding/animal + riding_datum = new/datum/riding/animal \ No newline at end of file diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 3dba061fd9..e97286b7e9 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1,6 +1,5 @@ /mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game. mob_list -= src - SSmob.currentrun -= src dead_mob_list -= src living_mob_list -= src all_clockwork_mobs -= src @@ -28,8 +27,8 @@ var/next_mob_id = 0 dead_mob_list += src else living_mob_list += src - prepare_huds() hook_vr("mob_new",list(src)) + prepare_huds() ..() /atom/proc/prepare_huds() @@ -112,7 +111,7 @@ var/next_mob_id = 0 if(self_message) msg = self_message else - if(M.see_invisible= speed) + sleep(speed) + switch(D) + if(NORTH) + D = EAST + if(SOUTH) + D = WEST + if(EAST) + D = SOUTH + if(WEST) + D = NORTH + setDir(D) + spintime -= speed + /mob/verb/stop_pulling() set name = "Stop Pulling" set category = "IC" @@ -452,30 +456,7 @@ proc/get_top_level_mob(var/mob/S) // M.Login() //wat return -/mob/proc/update_flavor_text() - set src in usr - if(usr != src) - usr << "No." - var/msg = input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavor Text",html_decode(flavor_text)) as message|null - if(msg != null) - msg = copytext(msg, 1, MAX_MESSAGE_LEN) - msg = html_encode(msg) - - flavor_text = msg - -/mob/proc/warn_flavor_changed() - if(flavor_text && flavor_text != "") // don't spam people that don't use it! - src << "

OOC Warning:

" - src << "Your flavor text is likely out of date! Change" - -/mob/proc/print_flavor_text() - if(flavor_text && flavor_text != "") - var/msg = replacetext(flavor_text, "\n", " ") - if(lentext(msg) <= 40) - return "\blue [msg]" - else - return "\blue [copytext(msg, 1, 37)]... More..." /mob/verb/cancel_camera() set name = "Cancel Camera View" @@ -571,7 +552,6 @@ proc/get_top_level_mob(var/mob/S) stat(null, "Next Map: [nextmap.friendlyname]") stat(null, "Server Time: [time2text(world.realtime, "YYYY-MM-DD hh:mm")]") if(SSshuttle.emergency) - stat(null, "Current Shuttle: [SSshuttle.emergency.name]") var/ETA = SSshuttle.emergency.getModeStr() if(ETA) stat(null, "[ETA] [SSshuttle.emergency.getTimerStr()]") @@ -967,5 +947,4 @@ proc/get_top_level_mob(var/mob/S) switch(var_name) if ("attack_log") return debug_variable(var_name, attack_log, 0, src, FALSE) - . = ..() \ No newline at end of file diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index e19ea6f8df..3e6cb63df3 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -175,7 +175,8 @@ moving = 0 if(mob && .) - mob.throwing = 0 + if(mob.throwing) + mob.throwing.finalize(FALSE) for(var/obj/O in mob) O.on_mob_move(direct, src) @@ -424,7 +425,7 @@ /client/verb/toggle_walk_run() set name = "toggle-walk-run" set hidden = TRUE - set instant = TRUE + set instant = TRUE if(mob) mob.toggle_move_intent() diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm index 2cb4634758..c867b6e719 100644 --- a/code/modules/mob/say_vr.dm +++ b/code/modules/mob/say_vr.dm @@ -69,4 +69,41 @@ /mob/proc/emote_vr(var/act, var/type, var/message) //This would normally go in say.dm if(act == "me") - return custom_emote_vr(type, message) \ No newline at end of file + return custom_emote_vr(type, message) + +/mob/proc/update_flavor_text() + set src in usr + if(usr != src) + usr << "No." + var/msg = input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavor Text",html_decode(flavor_text)) as message|null + + if(msg != null) + msg = copytext(msg, 1, MAX_MESSAGE_LEN) + msg = html_encode(msg) + + flavor_text = msg + +/mob/proc/warn_flavor_changed() + if(flavor_text && flavor_text != "") // don't spam people that don't use it! + src << "

OOC Warning:

" + src << "Your flavor text is likely out of date! Change" + +/mob/proc/print_flavor_text() + if(flavor_text && flavor_text != "") + var/msg = replacetext(flavor_text, "\n", " ") + if(lentext(msg) <= 40) + return "\blue [msg]" + else + return "\blue [copytext(msg, 1, 37)]... More..." + +/mob/proc/get_top_level_mob() + if(istype(src.loc,/mob)&&src.loc!=src) + var/mob/M=src.loc + return M.get_top_level_mob() + return src + +proc/get_top_level_mob(var/mob/S) + if(istype(S.loc,/mob)&&S.loc!=S) + var/mob/M=S.loc + return M.get_top_level_mob() + return S \ No newline at end of file diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 7f83bba8ab..615a6c5157 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -29,6 +29,18 @@ var/list/stamped var/rigged = 0 var/spam_flag = 0 + var/contact_poison // Reagent ID to transfer on contact + var/contact_poison_volume = 0 + + +/obj/item/weapon/paper/pickup(user) + if(contact_poison && ishuman(user)) + var/mob/living/carbon/human/H = user + var/obj/item/clothing/gloves/G = H.gloves + if(!istype(G) || G.transfer_prints) + H.reagents.add_reagent(contact_poison,contact_poison_volume) + contact_poison = null + ..() /obj/item/weapon/paper/New() @@ -166,7 +178,7 @@ /obj/item/weapon/paper/proc/clearpaper() info = null stamps = null - stamped = list() + LAZYCLEARLIST(stamped) cut_overlays() updateinfolinks() update_icon() @@ -289,7 +301,7 @@ else info += t // Oh, he wants to edit to the end of the file, let him. updateinfolinks() - + i.on_write(src,usr) usr << browse("[name][info_links]
[stamps]", "window=[name]") // Update the window update_icon() @@ -326,9 +338,7 @@ stampoverlay.icon_state = "paper_[P.icon_state]" - if(!stamped) - stamped = new - stamped += P.icon_state + LAZYADD(stamped, P.icon_state) add_overlay(stampoverlay) user << "You stamp the paper with your rubber stamp." diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm index a272617396..01f07b6e14 100644 --- a/code/modules/paperwork/paperplane.dm +++ b/code/modules/paperwork/paperplane.dm @@ -12,7 +12,6 @@ max_integrity = 50 var/obj/item/weapon/paper/internalPaper - var/list/stamped = list() /obj/item/weapon/paperplane/New(loc, obj/item/weapon/paper/newPaper) ..() @@ -20,13 +19,18 @@ pixel_x = rand(-9, 9) if(newPaper) internalPaper = newPaper - src.flags = newPaper.flags - stamped = internalPaper.stamped + flags = newPaper.flags newPaper.forceMove(src) else internalPaper = new /obj/item/weapon/paper(src) update_icon() +/obj/item/weapon/paperplane/Destroy() + if(internalPaper) + qdel(internalPaper) + internalPaper = null + return ..() + /obj/item/weapon/paperplane/suicide_act(mob/user) user.Stun(10) user.visible_message("[user] jams the [src] in [user.p_their()] nose. It looks like [user.p_theyre()] trying to commit suicide!") @@ -37,18 +41,18 @@ /obj/item/weapon/paperplane/update_icon() cut_overlays() - if(!stamped) - stamped = new - else if(stamped) + var/list/stamped = internalPaper.stamped + if(stamped) for(var/S in stamped) - var/obj/item/weapon/stamp/stamp = S - var/image/stampoverlay = image('icons/obj/bureaucracy.dmi', "paperplane_[initial(stamp.icon_state)]") + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi', "paperplane_[stamped]") add_overlay(stampoverlay) /obj/item/weapon/paperplane/attack_self(mob/user) user << "You unfold [src]." + var/internal_paper_tmp = internalPaper + internalPaper = null qdel(src) - user.put_in_hands(internalPaper) + user.put_in_hands(internal_paper_tmp) /obj/item/weapon/paperplane/attackby(obj/item/weapon/P, mob/living/carbon/human/user, params) ..() @@ -57,15 +61,7 @@ return else if(istype(P, /obj/item/weapon/stamp)) //we don't randomize stamps on a paperplane - - if (!stamped) - stamped = new - - stamped += P.type - internalPaper.stamps += "" //stamps the paper inside! - internalPaper.stamped = stamped - internalPaper.attackby(P) //spoofed attack to update internal paper. - user << "You stamp [src] with your rubber stamp." + internalPaper.attackby(P, user) //spoofed attack to update internal paper. update_icon() else if(P.is_hot()) @@ -108,7 +104,7 @@ return user << "You fold [src] into the shape of a plane!" user.temporarilyRemoveItemFromInventory(src) - I = new /obj/item/weapon/paperplane(loc, src) + I = new /obj/item/weapon/paperplane(user, src) user.put_in_hands(I) else user << " You lack the dexterity to fold \the [src]. " diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 08a03aae29..2d3bdf0281 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -162,3 +162,12 @@ else icon_state = initial(icon_state) //looks like a normal pen when off. item_state = initial(item_state) + +//Crayons path disambiguity sigh. +/obj/item/proc/on_write(obj/item/weapon/paper/P, mob/user) + return + +/obj/item/weapon/pen/poison/on_write(obj/item/weapon/paper/P, mob/user) + P.contact_poison = "delayed_toxin" + P.contact_poison_volume = 10 + add_logs(user,P,"used poison pen on") \ No newline at end of file diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm index 7cc01ba0ba..17ac046a03 100644 --- a/code/modules/power/singularity/collector.dm +++ b/code/modules/power/singularity/collector.dm @@ -53,9 +53,10 @@ var/global/list/rad_collectors = list() return ..() -/obj/machinery/power/rad_collector/can_be_unfasten_wrench(mob/user) +/obj/machinery/power/rad_collector/can_be_unfasten_wrench(mob/user, silent) if(loaded_tank) - user << "Remove the plasma tank first!" + if(!silent) + user << "Remove the plasma tank first!" return FAILED_UNFASTEN return ..() diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index eef1a5a799..886932cc34 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -128,7 +128,7 @@ return 1 /obj/machinery/power/emitter/attack_animal(mob/living/simple_animal/M) - if(ismegafauna(M)) + if(ismegafauna(M) && anchored) state = 0 anchored = FALSE M.visible_message("[M] rips [src] free from its moorings!") @@ -217,9 +217,10 @@ A.starting = loc A.fire() -/obj/machinery/power/emitter/can_be_unfasten_wrench(mob/user) +/obj/machinery/power/emitter/can_be_unfasten_wrench(mob/user, silent) if(state == EM_WELDED) - user << "[src] is welded to the floor!" + if(!silent) + user << "[src] is welded to the floor!" return FAILED_UNFASTEN return ..() diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm index d3c6d0104c..d444d7d8ca 100644 --- a/code/modules/power/singularity/field_generator.dm +++ b/code/modules/power/singularity/field_generator.dm @@ -77,9 +77,10 @@ field_generator power level display else user << "The [src] needs to be firmly secured to the floor first!" -/obj/machinery/field/generator/can_be_unfasten_wrench(mob/user) +/obj/machinery/field/generator/can_be_unfasten_wrench(mob/user, silent) if(state == FG_WELDED) - user << "[src] is welded to the floor!" + if(!silent) + user << "[src] is welded to the floor!" return FAILED_UNFASTEN return ..() diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 8092b59d90..a0a49ea6d5 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -160,7 +160,7 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics, var/mob/living/carbon/C = A C.dust() -/proc/tesla_zap(atom/source, zap_range = 3, power, explosive = FALSE) +/proc/tesla_zap(atom/source, zap_range = 3, power, explosive = FALSE, stun_mobs = TRUE) . = source.dir if(power < 1000) return @@ -251,26 +251,27 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics, //per type stuff: if(closest_tesla_coil) - closest_tesla_coil.tesla_act(power, explosive) + closest_tesla_coil.tesla_act(power, explosive, stun_mobs) else if(closest_grounding_rod) - closest_grounding_rod.tesla_act(power, explosive) + closest_grounding_rod.tesla_act(power, explosive, stun_mobs) else if(closest_mob) var/shock_damage = Clamp(round(power/400), 10, 90) + rand(-5, 5) - closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1) + closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1, stun = stun_mobs) if(issilicon(closest_mob)) var/mob/living/silicon/S = closest_mob - S.emp_act(2) - tesla_zap(S, 7, power / 1.5) // metallic folks bounce it further + if(stun_mobs) + S.emp_act(2) + tesla_zap(S, 7, power / 1.5, stun_mobs) // metallic folks bounce it further else - tesla_zap(closest_mob, 5, power / 1.5) + tesla_zap(closest_mob, 5, power / 1.5, stun_mobs) else if(closest_machine) - closest_machine.tesla_act(power, explosive) + closest_machine.tesla_act(power, explosive, stun_mobs) else if(closest_blob) - closest_blob.tesla_act(power, explosive) + closest_blob.tesla_act(power, explosive, stun_mobs) else if(closest_structure) - closest_structure.tesla_act(power, explosive) + closest_structure.tesla_act(power, explosive, stun_mobs) diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index f133b08a79..48d50750a5 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -355,4 +355,3 @@ user.emote("scream") user.drop_item() user.Weaken(4) - return diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index f80f2676cc..e2ba1aaa6d 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -165,6 +165,9 @@ /obj/item/weapon/gun/ballistic/shotgun/boltaction/enchanted/arcane_barrage/discard_gun(mob/user) return +/obj/item/weapon/gun/ballistic/shotgun/boltaction/enchanted/attack_self() + return + /obj/item/weapon/gun/ballistic/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1) ..() if(guns_left) diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index df867c4444..ba4798b5d7 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -376,28 +376,32 @@ /obj/item/borg/upgrade/modkit/chassis_mod name = "super chassis" desc = "Makes your KA yellow. All the fun of having a more powerful KA without actually having a more powerful KA." - cost = 10 + cost = 0 denied_type = /obj/item/borg/upgrade/modkit/chassis_mod var/chassis_icon = "kineticgun_u" + var/chassis_name = "super-kinetic accelerator" /obj/item/borg/upgrade/modkit/chassis_mod/install(obj/item/weapon/gun/energy/kinetic_accelerator/KA, mob/user) . = ..() if(.) KA.icon_state = chassis_icon + KA.name = chassis_name /obj/item/borg/upgrade/modkit/chassis_mod/uninstall(obj/item/weapon/gun/energy/kinetic_accelerator/KA) KA.icon_state = initial(KA.icon_state) + KA.name = initial(KA.name) ..() /obj/item/borg/upgrade/modkit/chassis_mod/orange name = "hyper chassis" desc = "Makes your KA orange. All the fun of having explosive blasts without actually having explosive blasts." chassis_icon = "kineticgun_h" + chassis_name = "hyper-kinetic accelerator" /obj/item/borg/upgrade/modkit/tracer name = "white tracer bolts" desc = "Causes kinetic accelerator bolts to have a white tracer trail and explosion." - cost = 4 + cost = 0 denied_type = /obj/item/borg/upgrade/modkit/tracer var/bolt_color = "#FFFFFF" diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 8d12c8b27e..fc79232e8f 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -814,3 +814,23 @@ if(prob(30)) M << "You should sit down and take a rest..." ..() + +/datum/reagent/toxin/delayed + name = "Toxin Microcapsules" + id = "delayed_toxin" + description = "Causes heavy toxin damage after a brief time of inactivity." + reagent_state = LIQUID + metabolization_rate = 0 //stays in the system until active. + var/actual_metaboliztion_rate = REAGENTS_METABOLISM + toxpwr = 0 + var/actual_toxpwr = 5 + var/delay = 30 + +/datum/reagent/toxin/delayed/on_mob_life(mob/living/M) + if(current_cycle > delay) + holder.remove_reagent(id, actual_metaboliztion_rate * M.metabolism_efficiency) + M.adjustToxLoss(actual_toxpwr*REM, 0) + if(prob(10)) + M.Weaken(1, 0) + . = 1 + ..() \ No newline at end of file diff --git a/code/modules/recycling/disposal-unit.dm b/code/modules/recycling/disposal-unit.dm index 3423673612..80c123397d 100644 --- a/code/modules/recycling/disposal-unit.dm +++ b/code/modules/recycling/disposal-unit.dm @@ -62,16 +62,17 @@ deconstruct() /obj/machinery/disposal/Initialize(mapload) - ..() - if(!mapload) - return - //this will get a copy of the air turf and take a SEND PRESSURE amount of air from it - var/atom/L = loc - var/datum/gas_mixture/env = new - env.copy_from(L.return_air()) - var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1) - air_contents.merge(removed) - trunk_check() + . = mapload //late-initialize, we need turfs to have air + if(initialized) //will only be run on late mapload initialization + //this will get a copy of the air turf and take a SEND PRESSURE amount of air from it + var/atom/L = loc + var/datum/gas_mixture/env = new + env.copy_from(L.return_air()) + var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1) + air_contents.merge(removed) + trunk_check() + else + ..() /obj/machinery/disposal/attackby(obj/item/I, mob/user, params) add_fingerprint(user) diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index af4cd2063b..76839102a8 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -389,7 +389,9 @@ launch_status = UNLAUNCHED /obj/docking_port/mobile/pod/request() - if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA) + var/obj/machinery/computer/shuttle/S = getControlConsole() + + if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA || (S && S.emagged)) if(launch_status == UNLAUNCHED) launch_status = EARLY_LAUNCHED return ..() @@ -418,6 +420,11 @@ /obj/machinery/computer/shuttle/pod/update_icon() return +/obj/machinery/computer/shuttle/pod/emag_act(mob/user) + if(!emagged) + emagged = TRUE + user << "You fry the pod's alert level checking system." + /obj/docking_port/stationary/random name = "escape pod" id = "pod" @@ -469,6 +476,7 @@ density = 0 icon = 'icons/obj/storage.dmi' icon_state = "safe" + var/unlocked = FALSE /obj/item/weapon/storage/pod/New() ..() @@ -488,13 +496,18 @@ return /obj/item/weapon/storage/pod/MouseDrop(over_object, src_location, over_location) - if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA) + if(security_level == SEC_LEVEL_RED || security_level == SEC_LEVEL_DELTA || unlocked) . = ..() else usr << "The storage unit will only unlock during a Red or Delta security alert." /obj/item/weapon/storage/pod/attack_hand(mob/user) - return + return MouseDrop(user) + +/obj/item/weapon/storage/pod/onShuttleMove() + unlocked = TRUE + // If the pod was launched, the storage will always open. + return ..() /obj/docking_port/mobile/emergency/backup diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 153a5badd3..37f2aa7abd 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -699,4 +699,13 @@ else dst = destination . += " towards [dst ? dst.name : "unknown location"] ([timeLeft(600)] minutes)" + + +// attempts to locate /obj/machinery/computer/shuttle with matching ID inside the shuttle +/obj/docking_port/mobile/proc/getControlConsole() + for(var/obj/machinery/computer/shuttle/S in areaInstance) + if(S.shuttleId == id) + return S + return null + #undef DOCKING_PORT_HIGHLIGHT diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index fd82fb7032..c724fbb35c 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -216,3 +216,42 @@ var/obj/item/weapon/card/id/ID = user.get_idcard() if(ID && (access_cent_bar in ID.access)) return TRUE + +//Luxury Shuttle Blockers + +/obj/effect/forcefield/luxury_shuttle + var/threshhold = 500 + var/static/list/approved_passengers = list() + +/obj/effect/forcefield/luxury_shuttle/CanPass(atom/movable/mover, turf/target, height=0) + if(mover in approved_passengers) + return 1 + + if(!isliving(mover)) //No stowaways + return 0 + + var/total_cash = 0 + var/list/counted_money = list() + + for(var/obj/item/weapon/coin/C in mover.GetAllContents()) + total_cash += C.value + counted_money += C + if(total_cash >= threshhold) + break + for(var/obj/item/stack/spacecash/S in mover.GetAllContents()) + total_cash += S.value * S.amount + counted_money += S + if(total_cash >= threshhold) + break + + if(total_cash >= threshhold) + for(var/obj/I in counted_money) + qdel(I) + + mover << "Thank you for your payment! Please enjoy your flight." + approved_passengers += mover + return 1 + else + mover << "You don't have enough money to enter the main shuttle. You'll have to fly coach." + return 0 + diff --git a/code/modules/spells/spell_types/aimed.dm b/code/modules/spells/spell_types/aimed.dm index 111094d5d7..f95e0f2c9b 100644 --- a/code/modules/spells/spell_types/aimed.dm +++ b/code/modules/spells/spell_types/aimed.dm @@ -6,6 +6,7 @@ var/active_msg = "You charge your projectile!" var/base_icon_state = "projectile" var/active_icon_state = "projectile" + var/projectile_damage_override = -1 /obj/effect/proc_holder/spell/aimed/Click() var/mob/living/user = usr @@ -54,6 +55,11 @@ var/obj/item/projectile/P = new projectile_type(user.loc) P.current = get_turf(user) P.preparePixelProjectile(target, get_turf(target), user) + if(projectile_damage_override != -1) + P.damage = projectile_damage_override + P.nodamage = TRUE + if(P.damage) + P.nodamage = FALSE P.fire() return TRUE @@ -80,6 +86,11 @@ var/obj/item/projectile/magic/aoe/lightning/P = new /obj/item/projectile/magic/aoe/lightning(user.loc) P.current = get_turf(user) P.preparePixelProjectile(target, get_turf(target), user) + if(projectile_damage_override != -1) + P.damage = projectile_damage_override + P.nodamage = TRUE + if(P.damage) + P.nodamage = FALSE P.tesla_power = tesla_power P.tesla_range = tesla_range P.tesla_boom = tesla_boom diff --git a/code/modules/uplink/uplink_item.dm b/code/modules/uplink/uplink_item.dm index 56300c2545..786b2b0a9e 100644 --- a/code/modules/uplink/uplink_item.dm +++ b/code/modules/uplink/uplink_item.dm @@ -618,6 +618,13 @@ var/list/uplink_items = list() // Global list so we only initialize this once. cost = 4 exclude_modes = list(/datum/game_mode/nuclear,/datum/game_mode/gang) +/datum/uplink_item/stealthy_weapons/poison_pen + name = "Poison Pen" + desc = "Cutting edge of deadly writing implements technology, this gadget will infuse any piece of paper with delayed contact poison." + item = /obj/item/weapon/pen/poison + cost = 2 + exclude_modes = list(/datum/game_mode/nuclear) + /datum/uplink_item/stealthy_weapons/soap name = "Syndicate Soap" desc = "A sinister-looking surfactant used to clean blood stains to hide murders and prevent DNA analysis. \ @@ -1166,13 +1173,14 @@ var/list/uplink_items = list() // Global list so we only initialize this once. /datum/uplink_item/role_restricted category = "Role-Restricted" exclude_modes = list(/datum/game_mode/nuclear) + surplus = 0 /datum/uplink_item/role_restricted/reverse_revolver name = "Reverse Revolver" desc = "A revolver that always fires at its user. \"Accidentally\" drop your weapon, then watch as the greedy corporate pigs blow their own brains all over the wall. \ - The revolver itself is actually real. Only clumsy people, and clowns, can fire it normally. Honk." + The revolver itself is actually real. Only clumsy people, and clowns, can fire it normally. Comes in a box of hugs. Honk." cost = 14 - item = /obj/item/weapon/gun/ballistic/revolver/reverse + item = /obj/item/weapon/storage/box/hug/reverse_revolver restricted_roles = list("Clown") /datum/uplink_item/role_restricted/ez_clean_bundle diff --git a/code/world.dm b/code/world.dm index 78b309c259..ad41f6781e 100644 --- a/code/world.dm +++ b/code/world.dm @@ -9,7 +9,6 @@ name = "/tg/ Station 13" fps = 20 visibility = 0 - #ifdef GC_FAILURE_HARD_LOOKUP loop_checks = FALSE #endif @@ -17,8 +16,8 @@ var/list/map_transition_config = MAP_TRANSITION_CONFIG /world/New() + world.log << "World loaded at [world.timeofday]" map_ready = 1 - world.log << "Map is ready." #if (PRELOAD_RSC == 0) external_rsc_urls = file2list("config/external_rsc_urls.txt","\n") @@ -49,9 +48,6 @@ var/list/map_transition_config = MAP_TRANSITION_CONFIG LoadBans() investigate_reset() - if(config && config.server_name != null && config.server_suffix && world.port > 0) - config.server_name += " #[(world.port % 1000) / 100]" - timezoneOffset = text2num(time2text(0,"hh")) * 36000 if(config.sql_enabled) @@ -74,7 +70,6 @@ var/list/map_transition_config = MAP_TRANSITION_CONFIG Master.Setup(10, FALSE) - #define IRC_STATUS_THROTTLE 50 var/last_irc_status = 0 @@ -101,12 +96,13 @@ var/last_irc_status = 0 else if("ircstatus" in input) if(world.time - last_irc_status < IRC_STATUS_THROTTLE) return -// var/list/adm = get_admin_counts() -// var/status = "Admins: [adm["total"]] (Active: [adm["present"]] AFK: [adm["afk"]] Stealth: [adm["stealth"]] Skipped: [adm["noflags"]]). " + var/list/adm = get_admin_counts() + var/list/allmins = adm["total"] + var/status = "Admins: [allmins.len] (Active: [english_list(adm["present"])] AFK: [english_list(adm["afk"])] Stealth: [english_list(adm["stealth"])] Skipped: [english_list(adm["noflags"])]). " status += "Players: [clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [ticker.mode.name]." send2irc("Status", status) last_irc_status = world.time - send2maindiscord("**Server starting up** on `[config.server? "byond://[config.server]" : "byond://[world.address]:[world.port]"]`. Map is **Probably Box Station**") + send2maindiscord("**Server starting up**. [clients.len] (Active: [get_active_player_count(0,1,0)]). Mode: [ticker.mode.name].`. Map is **Probably Box Station**") else if("status" in input) var/list/s = list() @@ -121,21 +117,17 @@ var/last_irc_status = 0 s["players"] = clients.len s["revision"] = revdata.commit s["revision_date"] = revdata.date - - var/admins = 0 var/mentors = 0 for(var/client/C in clients) var/mentor = mentor_datums[C.ckey] if(mentor) mentors++ - if(C.holder) - if(C.holder.fakekey) - continue //so stealthmins aren't revealed by the hub - admins++ - - s["gamestate"] = 1 - s["admins"] = admins s["mentors"] = mentors + var/list/adm = get_admin_counts() + var/list/presentmins = adm["present"] + var/list/afkmins = adm["afk"] + s["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho + s["gamestate"] = 1 if(ticker) s["gamestate"] = ticker.current_state @@ -183,30 +175,30 @@ var/last_irc_status = 0 else if("adminmsg" in input) if(!key_valid) return "Bad Key" -// else -// return IrcPm(input["adminmsg"],input["msg"],input["sender"]) + else + return IrcPm(input["adminmsg"],input["msg"],input["sender"]) else if("namecheck" in input) if(!key_valid) return "Bad Key" -// else -// log_admin("IRC Name Check: [input["sender"]] on [input["namecheck"]]") -// message_admins("IRC name checking on [input["namecheck"]] from [input["sender"]]") -// return keywords_lookup(input["namecheck"],1) + else + log_admin("IRC Name Check: [input["sender"]] on [input["namecheck"]]") + message_admins("IRC name checking on [input["namecheck"]] from [input["sender"]]") + return keywords_lookup(input["namecheck"],1) else if("adminwho" in input) if(!key_valid) return "Bad Key" -// else -// return ircadminwho() - + else + return ircadminwho() +#define WORLD_REBOOT(X) world.log << "World rebooted at [world.timeofday]"; ..(X) /world/Reboot(var/reason, var/feedback_c, var/feedback_r, var/time) if (reason == 1) //special reboot, do none of the normal stuff if (usr) log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools") message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools") world << "Rebooting World immediately due to host request" - return ..(1) + WORLD_REBOOT(1) var/delay if(time) delay = time @@ -215,7 +207,7 @@ var/last_irc_status = 0 if(ticker.delay_end) world << "An admin has delayed the round end." return - world << "Rebooting World in [delay/10] [delay > 10 ? "seconds" : "second"]. [reason]" + world << "Rebooting World in [delay/10] [(delay >= 10 && delay < 20) ? "second" : "seconds"]. [reason]" var/round_end_sound_sent = FALSE if(ticker.round_end_sound) round_end_sound_sent = TRUE @@ -237,12 +229,12 @@ var/last_irc_status = 0 Reboot("Map change timed out", time = 10) return OnReboot(reason, feedback_c, feedback_r, round_end_sound_sent) - ..(0) + WORLD_REBOOT(0) +#undef WORLD_REBOOT /world/proc/OnReboot(reason, feedback_c, feedback_r, round_end_sound_sent) feedback_set_details("[feedback_c]","[feedback_r]") log_game("Rebooting World. [reason]") - kick_clients_in_lobby("The round came to an end with you in the lobby.", 1) //second parameter ensures only afk clients are kicked #ifdef dellogging var/log = file("data/logs/del.log") log << time2text(world.realtime) @@ -251,30 +243,40 @@ var/last_irc_status = 0 if(count > 10) log << "#[count]\t[index]" #endif - var/soundwait = 0 - if (ticker.round_end_sound && !round_end_sound_sent) - soundwait = 10 - for(var/thing in clients) - var/client/C = thing - if (!C) - continue - C.Export("##action=load_rsc", ticker.round_end_sound) - spawn(soundwait/2) - if(ticker && ticker.round_end_sound) - world << sound(ticker.round_end_sound) - else - world << sound(pick('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg','sound/misc/leavingtg.ogg', 'sound/misc/its_only_game.ogg', 'sound/misc/yeehaw.ogg', 'sound/misc/disappointed.ogg')) // random end sounds!! - LastyBatsy if(blackbox) blackbox.save_all_data_to_sql() - sleep(soundwait) Master.Shutdown() //run SS shutdowns + RoundEndSound(round_end_sound_sent) + kick_clients_in_lobby("The round came to an end with you in the lobby.", 1) //second parameter ensures only afk clients are kicked + world << "Rebooting world. Loading next map..." for(var/thing in clients) var/client/C = thing - if (!C) - continue - if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite + if(C && config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite C << link("byond://[config.server]") +/world/proc/RoundEndSound(round_end_sound_sent) + set waitfor = FALSE + var/round_end_sound + if(!ticker && ticker.round_end_sound) + round_end_sound = ticker.round_end_sound + if (!round_end_sound_sent) + for(var/thing in clients) + var/client/C = thing + if (!C) + continue + C.Export("##action=load_rsc", round_end_sound) + else + round_end_sound = pick(\ + 'sound/roundend/newroundsexy.ogg', + 'sound/roundend/apcdestroyed.ogg', + 'sound/roundend/bangindonk.ogg', + 'sound/roundend/leavingtg.ogg', + 'sound/roundend/its_only_game.ogg', + 'sound/roundend/yeehaw.ogg', + 'sound/roundend/disappointed.ogg'\ + ) + world << sound(round_end_sound) + var/inerror = 0 /world/Error(var/exception/e) //runtime while processing runtimes diff --git a/goon/sound/machinery/FireAlarm.ogg b/goon/sound/machinery/FireAlarm.ogg new file mode 100644 index 0000000000..a19fd01ea6 Binary files /dev/null and b/goon/sound/machinery/FireAlarm.ogg differ diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi index 9aa9735d55..86530d4608 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/mob/belt.dmi b/icons/mob/belt.dmi index 31a6983b86..c16a14b1ab 100644 Binary files a/icons/mob/belt.dmi and b/icons/mob/belt.dmi differ diff --git a/icons/mob/belt_mirror.dmi b/icons/mob/belt_mirror.dmi index 70875774ad..807c684ed9 100644 Binary files a/icons/mob/belt_mirror.dmi and b/icons/mob/belt_mirror.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index dac5dfd819..e53258905e 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index 352adcab43..ca33570374 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/obj/food/containers.dmi b/icons/obj/food/containers.dmi index 0c04e2546d..2672732597 100644 Binary files a/icons/obj/food/containers.dmi and b/icons/obj/food/containers.dmi differ diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi index 0eb3441812..1b3f2eecd8 100644 Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ diff --git a/icons/obj/tank.dmi b/icons/obj/tank.dmi index 7087814bb8..1c91ecd270 100644 Binary files a/icons/obj/tank.dmi and b/icons/obj/tank.dmi differ diff --git a/sound/misc/apcdestroyed.ogg b/sound/roundend/apcdestroyed.ogg similarity index 100% rename from sound/misc/apcdestroyed.ogg rename to sound/roundend/apcdestroyed.ogg diff --git a/sound/misc/bangindonk.ogg b/sound/roundend/bangindonk.ogg similarity index 100% rename from sound/misc/bangindonk.ogg rename to sound/roundend/bangindonk.ogg diff --git a/sound/misc/disappointed.ogg b/sound/roundend/disappointed.ogg similarity index 100% rename from sound/misc/disappointed.ogg rename to sound/roundend/disappointed.ogg diff --git a/sound/misc/its_only_game.ogg b/sound/roundend/its_only_game.ogg similarity index 100% rename from sound/misc/its_only_game.ogg rename to sound/roundend/its_only_game.ogg diff --git a/sound/misc/leavingtg.ogg b/sound/roundend/leavingtg.ogg similarity index 100% rename from sound/misc/leavingtg.ogg rename to sound/roundend/leavingtg.ogg diff --git a/sound/roundend/newroundsexy.ogg b/sound/roundend/newroundsexy.ogg new file mode 100644 index 0000000000..afe5630f04 Binary files /dev/null and b/sound/roundend/newroundsexy.ogg differ diff --git a/sound/misc/yeehaw.ogg b/sound/roundend/yeehaw.ogg similarity index 100% rename from sound/misc/yeehaw.ogg rename to sound/roundend/yeehaw.ogg diff --git a/strings/soapstone_prefixes.txt b/strings/soapstone_prefixes.txt deleted file mode 100644 index 728e073983..0000000000 --- a/strings/soapstone_prefixes.txt +++ /dev/null @@ -1,14 +0,0 @@ -**** -****? -****! -try **** -**** ahead -be wary of **** -need **** -imminent **** -weakness: **** -huh, it's a ****... -visions of ****.... -could this be a ****? -time for **** -praise the ****! \ No newline at end of file diff --git a/strings/soapstone_suffixes.json b/strings/soapstone_suffixes.json deleted file mode 100644 index 2b2ab81a48..0000000000 --- a/strings/soapstone_suffixes.json +++ /dev/null @@ -1,234 +0,0 @@ -{ - "Characters": [ - "human", - "lizard", - "monkey", - "xeno", - "slimeperson", - "snowflake", - "enemy", - "tough enemy", - "Nanotrasen", - "Syndicate", - "skeleton", - "flier", - "statue", - "monster", - "strange creature", - "demon", - "boss", - "dark spirit", - "saint", - "wretch", - "charmer", - "miscreant", - "liar", - "fatty", - "beanpole", - "merchant", - "prisoner" - ], - - "Careers": [ - "assistant", - "captain", - "head of personnel", - "head of security", - "warden", - "security officer", - "detective", - "chief engineer", - "engineer", - "atmos tech", - "research director", - "scientist", - "robotics", - "chief medical officer", - "doctor", - "chemist", - "geneticist", - "virologist", - "janitor", - "bartender", - "cook", - "clown", - "mime", - "chaplain", - "librarian", - "quartermaster", - "cargo tech", - "miner", - "lawyer", - "AI", - "cyborg", - "drone", - "pAI" - ], - - "Antagonists": [ - "traitor", - "changeling", - "nuke op", - "wizard", - "alien", - "ghost", - "blob", - "cultist", - "devil" - ], - - "Objects": [ - "airlock", - "table", - "rack", - "weapon", - "trap", - "false wall", - "window", - "item", - "loot", - "teleporter", - "blueprints", - "boots", - "clothes", - "clothing", - "drugs", - "medicine", - "crate", - "locker", - "handcuffs", - "plant", - "food", - "drink", - "tool", - "amazing item", - "amazing loot", - "amazing clothing", - "amazing drugs", - "amazing rack" - ], - - "Techniques": [ - "close-ranged battle", - "ranged battle", - "eliminating one at a time", - "luring it out", - "beating to a pulp", - "lying in ambush", - "stealth", - "fleeing", - "charging", - "stabbing in the back" - ], - - "Actions": [ - "attacking", - "hacking", - "sneaking", - "slipping", - "running", - "walking", - "sprinting", - "running away", - "holding with both hands", - "jumping", - "restraining", - "crying", - "cheering" - ], - - "Geography": [ - "hallway", - "room", - "corridor", - "airlock", - "space", - "hidden path", - "gorgeous view", - "open area", - "tight spot", - "tunnel", - "dark area", - "bright area", - "shuttle", - "pod", - "security", - "arrivals", - "escape", - "engineering", - "atmospherics", - "medbay", - "science", - "brig", - "prison", - "asteroid", - "cargo", - "mining", - "cave", - "maintenance" - ], - - "Orientation": [ - "front", - "back", - "left", - "right", - "up", - "down", - "north", - "south", - "east", - "west", - "northeast", - "northwest", - "southeast", - "southwest", - "that way" - ], - - "Body parts": [ - "head", - "neck", - "stomach", - "back", - "arm", - "leg", - "heel", - "rear", - "tail", - "wings", - "anywhere", - "everywhere" - ], - - "Concepts": [ - "chance", - "hint", - "secret", - "happiness", - "sorrow", - "life", - "death", - "elation", - "grief", - "hope", - "despair", - "light", - "dark", - "bravery", - "resignation", - "comfort", - "tears" - ], - - "Musings": [ - "I can't take this...", - "it'll happen to you too", - "you don't deserve this", - "you bastard", - "you can do it", - "don't give up", - "don't you dare", - "do it" - ] -} \ No newline at end of file
Syndicates