diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index c05d84e8122d..339d48c9fe39 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -74,10 +74,10 @@ These are the few directives we have for project maintainers. - Try to get secondary maintainer approval before merging if you are able to. - PRs with empty commits intended to generate a changelog. - Do not merge PRs that contain content from the [banned content list](./CONTRIBUTING.md#banned-content). -- Do not merge PRs that contain balance changes without GA approval. Exceptions include: - - Any PR that has been un-reviewed by a GA for 7 days. +- Do not merge PRs that contain balance changes without Maintainer Manager approval. Exceptions include: + - Any PR that has been un-reviewed by a Maintainer Manager for 7 days. - Do not remove the DNM label that another Maintainer has applied. Exceptions include: - - GAs removing a DNM label placed by a Maintainer for Balance/Design reasons + - Maintainer Managers removing a DNM label placed by a Maintainer for Balance/Design reasons These are not steadfast rules as maintainers are expected to use their best judgement when operating. diff --git a/.github/guides/STANDARDS.md b/.github/guides/STANDARDS.md index fc764d09c816..c9b988bd07ff 100644 --- a/.github/guides/STANDARDS.md +++ b/.github/guides/STANDARDS.md @@ -126,7 +126,7 @@ While we normally encourage (and in some cases, even require) bringing out of da This is a simple one - as we will eventually move to 515, we will need to ditch this kind of callback. So please don't add any new ones. Make our lives easier. ### PROC_REF Macros - When referencing procs in RegisterSignal, Callback and other procs you should use PROC_REF,TYPE_PROC_REF and GLOBAL_PROC_REF macros. + When referencing procs in RegisterSignal, Callback and other procs you should use PROC_REF, TYPE_PROC_REF and GLOBAL_PROC_REF macros. They ensure compilation fails if the reffered to procs change names or get removed. The macro to be used depends on how the proc you're in relates to the proc you want to use: @@ -168,6 +168,8 @@ This is a simple one - as we will eventually move to 515, we will need to ditch addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(funny)), 100)) ``` + Note that the same rules go for verbs too! We have VERB_REF() and TYPE_VERB_REF() as you need it in these same cases. GLOBAL_VERB_REF() isn't a thing however, as verbs are not global. + ### Signal Handlers All procs that are registered to listen for signals using `RegisterSignal()` must contain at the start of the proc `SIGNAL_HANDLER` eg; diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_documentation.yml index 6075e3029acd..59e6d1144c68 100644 --- a/.github/workflows/generate_documentation.yml +++ b/.github/workflows/generate_documentation.yml @@ -21,7 +21,7 @@ jobs: run: | ~/dmdoc touch dmdoc/.nojekyll - echo codedocs.tgstation13.org > dmdoc/CNAME + echo docs.cm-ss13.com > dmdoc/CNAME - name: Deploy uses: JamesIves/github-pages-deploy-action@3.7.1 with: diff --git a/code/__DEFINES/ARES.dm b/code/__DEFINES/ARES.dm new file mode 100644 index 000000000000..05a42738c499 --- /dev/null +++ b/code/__DEFINES/ARES.dm @@ -0,0 +1,54 @@ +/// Generic access for 1:1 conversations with ARES and unrestricted commands. +#define ARES_ACCESS_BASIC 0 +/// Secure Access, can read ARES Announcements and Bioscans. +#define ARES_ACCESS_COMMAND 1 +#define ARES_ACCESS_JOE 2 +/// CL, can read Apollo Log and also Delete Announcements. +#define ARES_ACCESS_CORPORATE 3 +/// Senior Command, can Delete Bioscans. +#define ARES_ACCESS_SENIOR 4 +/// Synth, CE & Commanding Officer, can read the access log. +#define ARES_ACCESS_CE 5 +#define ARES_ACCESS_SYNTH 6 +#define ARES_ACCESS_CO 7 +/// High Command, can read the deletion log. +#define ARES_ACCESS_HIGH 8 +#define ARES_ACCESS_WY_COMMAND 9 +/// Debugging. Allows me to view everything without using a high command rank. Unlikely to stay in a full merge. +#define ARES_ACCESS_DEBUG 10 + +#define ARES_RECORD_ANNOUNCE "Announcement Record" +#define ARES_RECORD_ANTIAIR "AntiAir Control Log" +#define ARES_RECORD_ASRS "Requisition Record" +#define ARES_RECORD_BIOSCAN "Bioscan Record" +#define ARES_RECORD_BOMB "Orbital Bombardment Record" +#define ARES_RECORD_DELETED "Deleted Record" +#define ARES_RECORD_SECURITY "Security Update" +#define ARES_RECORD_MAINTENANCE "Maintenance Ticket" +#define ARES_RECORD_ACCESS "Access Ticket" + +/// Not by ARES logged through marine_announcement() +#define ARES_LOG_NONE 0 +/// Logged with all announcements +#define ARES_LOG_MAIN 1 +/// Logged in the security updates +#define ARES_LOG_SECURITY 2 + +/// Access levels specifically for Working Joe management console +#define APOLLO_ACCESS_REQUEST 0 +#define APOLLO_ACCESS_REPORTER 1 +#define APOLLO_ACCESS_TEMP 2 +#define APOLLO_ACCESS_AUTHED 3 +#define APOLLO_ACCESS_JOE 4 +#define APOLLO_ACCESS_DEBUG 5 + +/// Ticket statuses, both for Access and Maintenance +#define TICKET_PENDING "pending" +#define TICKET_ASSIGNED "assigned" +#define TICKET_REJECTED "rejected" +#define TICKET_CANCELLED "cancelled" +#define TICKET_COMPLETED "complete" + +/// Cooldowns +#define COOLDOWN_ARES_SENSOR 60 SECONDS +#define COOLDOWN_ARES_ACCESS_CONTROL 20 SECONDS diff --git a/code/__DEFINES/__game.dm b/code/__DEFINES/__game.dm index 100a45ff6a94..3116d7f19555 100644 --- a/code/__DEFINES/__game.dm +++ b/code/__DEFINES/__game.dm @@ -106,6 +106,7 @@ block( \ #define SOUND_REBOOT (1<<5) #define SOUND_ADMIN_MEME (1<<6) #define SOUND_ADMIN_ATMOSPHERIC (1<<7) +#define SOUND_ARES_MESSAGE (1<<8) //toggles_chat #define CHAT_OOC (1<<0) diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm index 8b9fe898c72c..a40675e0560e 100644 --- a/code/__DEFINES/access.dm +++ b/code/__DEFINES/access.dm @@ -43,6 +43,14 @@ most of them are tied into map-placed objects. This should be reworked in the fu #define ACCESS_MARINE_SYNTH 36 +// AI Core Accesses +/// Used in temporary passes +#define ACCESS_MARINE_AI_TEMP 90 +/// Used as dedicated access to ARES Core. +#define ACCESS_MARINE_AI 91 +/// Used to access Maintenance Protocols on ARES Interface. +#define ACCESS_ARES_DEBUG 92 + //Surface access levels #define ACCESS_CIVILIAN_PUBLIC 100 #define ACCESS_CIVILIAN_LOGISTICS 101 diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 95b98646c616..9702d51004ad 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -48,6 +48,8 @@ var/global/list/note_categories = list("Admin", "Merit", "Commanding Officer", " #define CC_MARK(user) "(MARK)" #define CC_REPLY(user) "(RPLY)" #define OBSERVER_JMP(observer, atom) atom ? "(JMP)" : "" +#define ARES_MARK(user) "(MARK)" +#define ARES_REPLY(user, ref) "(RPLY)" /atom/proc/Admin_Coordinates_Readable(area_name, admin_jump_ref) var/turf/T = get_turf(src) diff --git a/code/__DEFINES/camera.dm b/code/__DEFINES/camera.dm index 58b1b8acbd84..9d797b964d61 100644 --- a/code/__DEFINES/camera.dm +++ b/code/__DEFINES/camera.dm @@ -6,6 +6,7 @@ #define CAMERA_NET_ALAMO "Alamo" #define CAMERA_NET_NORMANDY "Normandy" #define CAMERA_NET_COLONY "Colony" +#define CAMERA_NET_ARES "ARES" #define CAMERA_NET_MILITARY "Military" #define CAMERA_NET_OVERWATCH "Overwatch" diff --git a/code/__DEFINES/conflict.dm b/code/__DEFINES/conflict.dm index 09be4793c552..141d69c69b11 100644 --- a/code/__DEFINES/conflict.dm +++ b/code/__DEFINES/conflict.dm @@ -232,6 +232,7 @@ //OB timings #define OB_TRAVEL_TIMING 12 SECONDS #define OB_CRASHING_DOWN 1 SECONDS +#define OB_CLUSTER_DURATION 45 SECONDS //================================================= //Health of various items diff --git a/code/__DEFINES/dcs/signals/atom/signals_obj.dm b/code/__DEFINES/dcs/signals/atom/signals_obj.dm index df53558834f6..aebd0d09d0d2 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_obj.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_obj.dm @@ -4,6 +4,8 @@ /// From /obj/effect/alien/weeds/Initialize() #define COMSIG_WEEDNODE_GROWTH_COMPLETE "weednode_growth_complete" +/// From /obj/effect/alien/weeds/Initialize() +#define COMSIG_WEEDNODE_GROWTH "weednode_growth" /// From /obj/effect/alien/weeds/proc/on_weed_expand() #define COMSIG_WEEDNODE_CANNOT_EXPAND_FURTHER "weednode_cannot_expand_further" @@ -24,3 +26,6 @@ #define COMSIG_TRANSMITTER_UPDATE_ICON "transmitter_update_icon" #define COMSIG_TENT_COLLAPSING "tent_collapsing" + +/// from /obj/proc/afterbuckle() +#define COSMIG_OBJ_AFTER_BUCKLE "signal_obj_after_buckle" diff --git a/code/__DEFINES/dcs/signals/signals_datum.dm b/code/__DEFINES/dcs/signals/signals_datum.dm index a7a93c4ea114..7696d8ad6037 100644 --- a/code/__DEFINES/dcs/signals/signals_datum.dm +++ b/code/__DEFINES/dcs/signals/signals_datum.dm @@ -61,3 +61,6 @@ // from /datum/emergency_call/proc/spawn_candidates() #define COMSIG_ERT_SETUP "ert_setup" + +// from /proc/update_living_queens() : /mob/living/carbon/xenomorph/queen +#define COMSIG_HIVE_NEW_QUEEN "hive_new_queen" diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index c3d51b2d65cd..9781f61ec95c 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -48,5 +48,11 @@ // Used for smothering fires upon weather event start/stop #define COMSIG_GLOB_WEATHER_CHANGE "!weather_event_changed" +/// From /obj/structure/machinery/telecomms/proc/tcomms_shutdown(), called when the relay turns off +#define COMSIG_GLOB_GROUNDSIDE_TELECOMM_TURNED_OFF "!groundside_telecomm_turned_off" + /// From /datum/admins/proc/force_predator_round() #define COMSIG_GLOB_PREDATOR_ROUND_TOGGLED "!predator_round_toglged" + +/// From /datum/game_mode/colonialmarines/proc/check_ground_humans() +#define COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING "!groundside_forsaken_handling" diff --git a/code/__DEFINES/defenses.dm b/code/__DEFINES/defenses.dm index 57eb0c86f939..db615c2a0c78 100644 --- a/code/__DEFINES/defenses.dm +++ b/code/__DEFINES/defenses.dm @@ -8,7 +8,7 @@ // Defines for barricade upgrades #define BARRICADE_UPGRADE_BURN "Biohazard Upgrade (+Burn)" #define BARRICADE_UPGRADE_BRUTE "Reinforced Upgrade (+Brute)" -#define BARRICADE_UPGRADE_EXPLOSIVE "Explosive Upgrade (+Explosive)" +#define BARRICADE_UPGRADE_ANTIFF "Composite Upgrade (++Explosive, ++Projectile, ++Fire)" // Defines for defense stats #define DEFENSE_FUNCTIONAL 0 diff --git a/code/__DEFINES/language.dm b/code/__DEFINES/language.dm index 8cac90defb26..557f8e6a3f68 100644 --- a/code/__DEFINES/language.dm +++ b/code/__DEFINES/language.dm @@ -12,7 +12,7 @@ #define LANGUAGE_XENOMORPH "Xenomorph" #define LANGUAGE_HIVEMIND "Hivemind" -#define LANGUAGE_APOLLO "Apollo Link" +#define LANGUAGE_APOLLO "APOLLO Link" #define LANGUAGE_TELEPATH "Telepath Implant" diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index b2936248c3ba..bed2ceeced7d 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -44,6 +44,8 @@ #define AREA_ALLOW_XENO_JOIN (1<<2) /// Flags the area as a containment area #define AREA_CONTAINMENT (1<<3) +/// Flags the area as permanently unweedable. Still requires is_resin_allowed = FALSE +#define AREA_UNWEEDABLE (1<<4) /// Default number of ticks for do_after #define DA_DEFAULT_NUM_TICKS 5 diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 495b5fb472c5..ba928e202cf0 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -11,8 +11,6 @@ #define OVEREAT_TIME 200 //================================================= -#define ALIEN_SELECT_AFK_BUFFER 1 // How many minutes that a person can be AFK before not being allowed to be an alien. - #define HEAT_DAMAGE_LEVEL_1 2 //Amount of damage applied when your body temperature just passes the 360.15k safety point #define HEAT_DAMAGE_LEVEL_2 4 //Amount of damage applied when your body temperature passes the 400K point #define HEAT_DAMAGE_LEVEL_3 8 //Amount of damage applied when your body temperature passes the 1000K point diff --git a/code/__DEFINES/mode.dm b/code/__DEFINES/mode.dm index 1f3c4ad22bf1..ab58df78abcc 100644 --- a/code/__DEFINES/mode.dm +++ b/code/__DEFINES/mode.dm @@ -14,6 +14,7 @@ #define EVACUATION_STATUS_IN_PROGRESS 2 #define EVACUATION_STATUS_COMPLETE 3 +#define NUCLEAR_TIME_LOCK 90 MINUTES #define NUKE_EXPLOSION_INACTIVE 0 #define NUKE_EXPLOSION_ACTIVE 1 #define NUKE_EXPLOSION_IN_PROGRESS 2 diff --git a/code/__DEFINES/objects.dm b/code/__DEFINES/objects.dm index 5617a2b47ec6..0a34ac9d6fe9 100644 --- a/code/__DEFINES/objects.dm +++ b/code/__DEFINES/objects.dm @@ -136,11 +136,16 @@ var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accesse #define CLEANABLE_MISC "misc" //Anything else //For nuke announcements -#define NUKE_SHOW_TIMER_TEN_SEC 1 -#define NUKE_SHOW_TIMER_MINUTE 2 -#define NUKE_SHOW_TIMER_HALF 4 +#define NUKE_SHOW_TIMER_TEN_SEC (1<<0) +#define NUKE_SHOW_TIMER_MINUTE (1<<1) +#define NUKE_SHOW_TIMER_HALF (1<<2) #define NUKE_SHOW_TIMER_ALL (NUKE_SHOW_TIMER_TEN_SEC|NUKE_SHOW_TIMER_MINUTE|NUKE_SHOW_TIMER_HALF) +#define NUKE_DECRYPT_SHOW_TIMER_COMPLETE (1<<3) +#define NUKE_DECRYPT_SHOW_TIMER_MINUTE (1<<4) +#define NUKE_DECRYPT_SHOW_TIMER_HALF (1<<5) +#define NUKE_DECRYPT_SHOW_TIMER_ALL (NUKE_SHOW_TIMER_TEN_SEC|NUKE_SHOW_TIMER_HALF|NUKE_DECRYPT_SHOW_TIMER_COMPLETE|NUKE_DECRYPT_SHOW_TIMER_MINUTE|NUKE_DECRYPT_SHOW_TIMER_HALF) + //For recipes #define ONE_TYPE_PER_TURF 1 #define ONE_TYPE_PER_BORDER 2 diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 3c2527136ed6..662bcb458c55 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -113,7 +113,8 @@ #define SS_INIT_INPUT 85 #define SS_INIT_FAIL_TO_TOPIC 84 #define SS_INIT_TOPIC 83 -#define SS_INIT_RUST 26 +#define SS_INIT_RUST 30 +#define SS_INIT_INFLUXDRIVER 28 #define SS_INIT_SUPPLY_SHUTTLE 25 #define SS_INIT_GARBAGE 24 #define SS_INIT_EVENTS 23.5 @@ -133,7 +134,9 @@ #define SS_INIT_MORE_INIT 16 #define SS_INIT_AIR 15 #define SS_INIT_TELEPORTER 13 -#define SS_INIT_LIGHTING 12 +#define SS_INIT_INFLUXMCSTATS 12 +#define SS_INIT_INFLUXSTATS 11 +#define SS_INIT_LIGHTING 10 #define SS_INIT_DEFCON 9 #define SS_INIT_LAW 6 #define SS_INIT_FZ_TRANSITIONS 5 @@ -212,12 +215,15 @@ #define SS_PRIORITY_UNSPECIFIED 30 #define SS_PRIORITY_PROCESS 25 #define SS_PRIORITY_SOUNDSCAPE 24 +#define SS_PRIORITY_INFLUXDRIVER 23 #define SS_PRIORITY_PAGER_STATUS 22 #define SS_PRIORITY_LIGHTING 20 #define SS_PRIORITY_TRACKING 19 +#define SS_PRIORITY_DATABASE 15 #define SS_PRIORITY_MINIMAPS 11 #define SS_PRIORITY_PING 10 -#define SS_PRIORITY_DATABASE 15 +#define SS_PRIORITY_INFLUXMCSTATS 9 +#define SS_PRIORITY_INFLUXSTATS 8 #define SS_PRIORITY_PLAYTIME 5 #define SS_PRIORITY_PERFLOGGING 4 #define SS_PRIORITY_CORPSESPAWNER 3 diff --git a/code/__DEFINES/tgui.dm b/code/__DEFINES/tgui.dm index 865088ee72fc..ca6408961eab 100644 --- a/code/__DEFINES/tgui.dm +++ b/code/__DEFINES/tgui.dm @@ -32,7 +32,7 @@ /// Creates a message packet for sending via output() // This is {"type":type,"payload":payload}, but pre-encoded. This is much faster // than doing it the normal way. -// To ensure this is correct, this is unit tested in tgui_create_message. However, CM does not have unit tests available. +// To ensure this is correct, this is unit tested in tgui_create_message. #define TGUI_CREATE_MESSAGE(type, payload) ( \ "%7b%22type%22%3a%22[type]%22%2c%22payload%22%3a[url_encode(json_encode(payload))]%7d" \ ) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index e5441090d60c..4897a04fea82 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -123,7 +123,7 @@ #define TRAIT_SUPER_STRONG "t_super_strong" /// Foreign biology. Basic medHUDs won't show the mob. (Yautja, Zombies) #define TRAIT_FOREIGN_BIO "t_foreign_bio" -/// Eye color changes on intent. (G1 Synths) +/// Eye color changes on intent. (G1 Synths and WJs) #define TRAIT_INTENT_EYES "t_intent_eyes" /// Masked synthetic biology. Basic medHUDs will percieve the mob as human. (Infiltrator Synths) #define TRAIT_INFILTRATOR_SYNTH "t_infiltrator_synth" @@ -157,6 +157,8 @@ #define TRAIT_LEADERSHIP "t_leadership" /// If the mob can see the reagents contents of stuff #define TRAIT_REAGENT_SCANNER "reagent_scanner" +/// If the mob cannot eat/be fed +#define TRAIT_CANNOT_EAT "t_cannot_eat" /// If the mob is being lazed by a sniper spotter #define TRAIT_SPOTTER_LAZED "t_spotter_lazed" /// If the mob has ear protection. Protects from external ear damage effects. Includes explosions, firing the RPG, screeching DEAFNESS only, and flashbangs. @@ -211,6 +213,9 @@ //ie. naming a regulation tape "example" will become regulation tape (example) #define TRAIT_ITEM_RENAME_SPECIAL "t_item_rename_special" +// This item can't be implanted into someone, regardless of the size of the item. +#define TRAIT_ITEM_NOT_IMPLANTABLE "t_item_not_implantable" + //-- structure traits -- // TABLE TRAITS /// If the table is being flipped, prevent any changes that will mess with adjacency handling @@ -258,6 +263,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BIMEX" = TRAIT_BIMEX, "TRAIT_EMOTE_CD_EXEMPT" = TRAIT_EMOTE_CD_EXEMPT, "TRAIT_LISPING" = TRAIT_LISPING, + "TRAIT_CANNOT_EAT" = TRAIT_CANNOT_EAT, ), /mob/living/carbon/xenomorph = list( "TRAIT_ABILITY_NO_PLASMA_TRANSFER" = TRAIT_ABILITY_NO_PLASMA_TRANSFER, diff --git a/code/__DEFINES/weapon_stats.dm b/code/__DEFINES/weapon_stats.dm index 58dad90b0710..bef8413e9615 100644 --- a/code/__DEFINES/weapon_stats.dm +++ b/code/__DEFINES/weapon_stats.dm @@ -1,7 +1,7 @@ #define HUMAN_UNIVERSAL_DAMAGEMULT 1 #define RECOIL_BUILDUP_VIEWPUNCH_MULTIPLIER 0.1 - +#define BASE_VELOCITY_BONUS 0 #define PROJ_BASE_ACCURACY_MULT 0.01 #define PROJ_BASE_DAMAGE_MULT 0.01 diff --git a/code/__DEFINES/wj_emotes.dm b/code/__DEFINES/wj_emotes.dm new file mode 100644 index 000000000000..f315c6eb2ba5 --- /dev/null +++ b/code/__DEFINES/wj_emotes.dm @@ -0,0 +1,8 @@ +#define JOE_EMOTE_CATEGORY_GREETING "Greeting" +#define JOE_EMOTE_CATEGORY_TASK_UPDATE "Task Update" +#define JOE_EMOTE_CATEGORY_RESTRICTED_AREA "Restricted Area" +#define JOE_EMOTE_CATEGORY_FAREWELL "Farewell" +#define JOE_EMOTE_CATEGORY_QUIP "Quip" +#define JOE_EMOTE_CATEGORY_WARNING "Warning" +#define JOE_EMOTE_CATEGORY_QUESTION "Question" +#define JOE_EMOTE_CATEGORY_NOTICE "Notice" diff --git a/code/__DEFINES/xeno.dm b/code/__DEFINES/xeno.dm index 6d6bd64ea918..4b45c660feab 100644 --- a/code/__DEFINES/xeno.dm +++ b/code/__DEFINES/xeno.dm @@ -132,6 +132,7 @@ // Weed defines #define WEED_LEVEL_WEAK 0 #define WEED_LEVEL_STANDARD 1.5 +#define WEED_LEVEL_HARDY 1.6 #define WEED_LEVEL_HIVE 4 #define WEED_RANGE_STANDARD 3 @@ -154,6 +155,22 @@ #define WEED_BASE_GROW_SPEED (5 SECONDS) #define WEED_BASE_DECAY_SPEED (10 SECONDS) +/// The time you must be dead to join as a xeno larva +#define XENO_JOIN_DEAD_LARVA_TIME (2.5 MINUTES) +/// The time you must be dead to join as xeno (not larva) +#define XENO_JOIN_DEAD_TIME (5 MINUTES) +/// The time of inactivity you cannot exceed to join as a xeno +#define XENO_JOIN_AFK_TIME_LIMIT (5 MINUTES) +/// The amount of time after round start before buried larva spawns are disallowed +#define XENO_BURIED_LARVA_TIME_LIMIT (30 MINUTES) + +/// The time against away_timer when an AFK xeno larva can be replaced +#define XENO_LEAVE_TIMER_LARVA 80 //80 seconds +/// The time against away_timer when an AFK xeno (not larva) can be replaced +#define XENO_LEAVE_TIMER 300 //300 seconds +/// The time against away_timer when an AFK xeno gets listed in the available list so ghosts can get ready +#define XENO_AVAILABLE_TIMER 60 //60 seconds + /// Between 2% to 10% of explosion severity #define WEED_EXPLOSION_DAMAGEMULT rand(2, 10)*0.01 diff --git a/code/__HELPERS/_time.dm b/code/__HELPERS/_time.dm index 85acafa0e2f6..b929ae8636b3 100644 --- a/code/__HELPERS/_time.dm +++ b/code/__HELPERS/_time.dm @@ -15,10 +15,6 @@ #define DECISECONDS_TO_HOURS /36000 -#define XENO_LEAVE_TIMER_LARVA 80 //80 seconds -#define XENO_LEAVE_TIMER 300 //300 seconds -#define XENO_AVAILABLE_TIMER 60 //60 seconds, when to add a xeno to the avaliable list so ghosts can get ready - var/midnight_rollovers = 0 var/rollovercheck_last_timeofday = 0 diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index 4ca0edcf43d0..ff8e31ad3e8a 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -57,3 +57,12 @@ var/atom/cmp_dist_origin=null /proc/cmp_typepaths_asc(A, B) return sorttext("[B]","[A]") + +/// Compares mobs based on their timeofdeath value in ascending order +/proc/cmp_mob_deathtime_asc(mob/A, mob/B) + return A.timeofdeath - B.timeofdeath + +/// Compares observers based on their larva_queue_time value in ascending order +/// Assumes the client on the observer is not null +/proc/cmp_obs_larvaqueuetime_asc(mob/dead/observer/A, mob/dead/observer/B) + return A.client.player_details.larva_queue_time - B.client.player_details.larva_queue_time diff --git a/code/__HELPERS/files.dm b/code/__HELPERS/files.dm index 717a2ed5347b..f88fe7168f8d 100644 --- a/code/__HELPERS/files.dm +++ b/code/__HELPERS/files.dm @@ -12,11 +12,6 @@ return text -//Sends resource files to client cache -/client/proc/getFiles() - for(var/file in args) - src << browse_rsc(file) - /client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm")) var/path = root diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index a0bb9dd98423..0132a31d0b50 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -241,35 +241,65 @@ else return get_step(start, EAST) -// Same as above but for alien candidates. -/proc/get_alien_candidates() +/// Get a list of observers that can be alien candidates, optionally sorted by larva_queue_time +/proc/get_alien_candidates(sorted = TRUE) var/list/candidates = list() - for(var/i in GLOB.observer_list) - var/mob/dead/observer/O = i + for(var/mob/dead/observer/cur_obs as anything in GLOB.observer_list) + // Preference check + if(!cur_obs.client || !cur_obs.client.prefs || !(cur_obs.client.prefs.be_special & BE_ALIEN_AFTER_DEATH)) + continue + // Jobban check - if(!O.client || !O.client.prefs || !(O.client.prefs.be_special & BE_ALIEN_AFTER_DEATH) || jobban_isbanned(O, JOB_XENOMORPH)) + if(jobban_isbanned(cur_obs, JOB_XENOMORPH)) continue //players that can still be revived are skipped - if(O.mind && O.mind.original && ishuman(O.mind.original)) - var/mob/living/carbon/human/H = O.mind.original - if (H.check_tod() && H.is_revivable()) + if(cur_obs.mind && cur_obs.mind.original && ishuman(cur_obs.mind.original)) + var/mob/living/carbon/human/cur_human = cur_obs.mind.original + if(cur_human.check_tod() && cur_human.is_revivable()) continue // copied from join as xeno - var/deathtime = world.time - O.timeofdeath - if(deathtime < 3000 && ( !O.client.admin_holder || !(O.client.admin_holder.rights & R_ADMIN)) ) + var/deathtime = world.time - cur_obs.timeofdeath + if(deathtime < XENO_JOIN_DEAD_TIME && ( !cur_obs.client.admin_holder || !(cur_obs.client.admin_holder.rights & R_ADMIN)) ) continue - // Admins and AFK players cannot be drafted - if(O.client.inactivity / 600 > ALIEN_SELECT_AFK_BUFFER + 5 || (O.client.admin_holder && (O.client.admin_holder.rights & R_MOD)) && O.adminlarva == 0) + // AFK players cannot be drafted + if(cur_obs.client.inactivity > XENO_JOIN_AFK_TIME_LIMIT) continue - candidates += O + // Mods with larva protection cannot be drafted + if((cur_obs.client.admin_holder && (cur_obs.client.admin_holder.rights & R_MOD)) && !cur_obs.adminlarva) + continue + + candidates += cur_obs + + // Optionally sort by larva_queue_time + if(sorted && length(candidates)) + candidates = sort_list(candidates, GLOBAL_PROC_REF(cmp_obs_larvaqueuetime_asc)) return candidates +/** + * Messages observers that are currently candidates an update on the queue. + * + * Arguments: + * * candidates - The list of observers from get_alien_candidates() + * * dequeued - How many candidates to skip messaging because they were dequeued + * * cache_only - Whether to not actually send a to_chat message and instead only update larva_queue_cached_message + */ +/proc/message_alien_candidates(list/candidates, dequeued, cache_only = FALSE) + for(var/i in (1 + dequeued) to candidates.len) + var/mob/dead/observer/cur_obs = candidates[i] + + // Generate the messages + var/cached_message = SPAN_XENONOTICE("You are currently [i-dequeued]\th in the larva queue.") + cur_obs.larva_queue_cached_message = cached_message + if(!cache_only) + var/chat_message = dequeued ? replacetext(cached_message, "currently", "now") : cached_message + to_chat(candidates[i], chat_message) + /proc/convert_k2c(temp) return ((temp - T0C)) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 83da41b515a6..d4d9eb320633 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -164,6 +164,11 @@ t = "0[t]" return t +/proc/pad_trailing(text, padding, size) + while (length(text) < size) + text = "[text][padding]" + return text + //Adds 'u' number of spaces ahead of the text 't' /proc/add_lspace(t, u) while(length(t) < u) diff --git a/code/_byond_version_compat.dm b/code/_byond_version_compat.dm index b5379a3b6d5c..719d85654b5f 100644 --- a/code/_byond_version_compat.dm +++ b/code/_byond_version_compat.dm @@ -31,19 +31,49 @@ #define LIBCALL call_ext #endif -// So we want to have compile time guarantees these procs exist on local type, unfortunately 515 killed the .proc/procname syntax so we have to use nameof() +// So we want to have compile time guarantees these methods exist on local type, unfortunately 515 killed the .proc/procname and .verb/verbname syntax so we have to use nameof() +// For the record: GLOBAL_VERB_REF would be useless as verbs can't be global. + #if DM_VERSION < 515 -/// Call by name proc reference, checks if the proc exists on this type or as a global proc + +/// Call by name proc references, checks if the proc exists on either this type or as a global proc. #define PROC_REF(X) (.proc/##X) -/// Call by name proc reference, checks if the proc exists on given type or as a global proc +/// Call by name verb references, checks if the verb exists on either this type or as a global verb. +#define VERB_REF(X) (.verb/##X) + +/// Call by name proc reference, checks if the proc exists on either the given type or as a global proc #define TYPE_PROC_REF(TYPE, X) (##TYPE.proc/##X) -/// Call by name proc reference, checks if the proc is existing global proc +/// Call by name verb reference, checks if the verb exists on either the given type or as a global verb +#define TYPE_VERB_REF(TYPE, X) (##TYPE.verb/##X) + +/// Call by name proc reference, checks if the proc is an existing global proc #define GLOBAL_PROC_REF(X) (/proc/##X) + #else -/// Call by name proc reference, checks if the proc exists on this type or as a global proc + +/// Call by name proc references, checks if the proc exists on either this type or as a global proc. #define PROC_REF(X) (nameof(.proc/##X)) -/// Call by name proc reference, checks if the proc exists on given type or as a global proc +/// Call by name verb references, checks if the verb exists on either this type or as a global verb. +#define VERB_REF(X) (nameof(.verb/##X)) + +/// Call by name proc reference, checks if the proc exists on either the given type or as a global proc #define TYPE_PROC_REF(TYPE, X) (nameof(##TYPE.proc/##X)) -/// Call by name proc reference, checks if the proc is existing global proc +/// Call by name verb reference, checks if the verb exists on either the given type or as a global verb +#define TYPE_VERB_REF(TYPE, X) (nameof(##TYPE.verb/##X)) + +/// Call by name proc reference, checks if the proc is an existing global proc #define GLOBAL_PROC_REF(X) (/proc/##X) + +#endif + +#if (DM_VERSION == 515) +/// fcopy will crash on 515 linux if given a non-existant file, instead of returning 0 like on 514 linux or 515 windows +/// var case matches documentation for fcopy. +/world/proc/__fcopy(Src, Dst) + if (istext(Src) && !fexists(Src)) + return 0 + return fcopy(Src, Dst) + +#define fcopy(Src, Dst) world.__fcopy(Src, Dst) + #endif diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 7d16e437087b..121d1e305e43 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -328,6 +328,7 @@ DEFINE_BITFIELD(flags_area, list( "AREA_NOTUNNEL" = AREA_NOTUNNEL, "AREA_ALLOW_XENO_JOIN" = AREA_ALLOW_XENO_JOIN, "AREA_CONTAINMENT" = AREA_CONTAINMENT, + "ARES_UNWEEDABLE" = AREA_UNWEEDABLE, )) DEFINE_BITFIELD(disabilities, list( diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm index f0279907f635..586d5e71a92d 100644 --- a/code/_globalvars/global_lists.dm +++ b/code/_globalvars/global_lists.dm @@ -10,6 +10,7 @@ GLOBAL_LIST_EMPTY(GeneralFaxes) //Inter-machine faxes GLOBAL_LIST_EMPTY(fax_contents) //List of fax contents to maintain it even if source paper is deleted GLOBAL_LIST_EMPTY(failed_fultons) //A list of fultoned items which weren't collected and fell back down +GLOBAL_LIST_EMPTY(larva_burst_by_hive) GLOBAL_LIST_INIT_TYPED(custom_huds_list, /datum/custom_hud, setup_all_huds()) GLOBAL_LIST_INIT_TYPED(custom_human_huds, /datum/custom_hud, setup_human_huds()) diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 187f179094b2..e2203aadce0c 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -23,6 +23,7 @@ GLOBAL_LIST_EMPTY_TYPED(alive_human_list, /mob/living/carbon/human) // list of a GLOBAL_LIST_EMPTY_TYPED(xeno_mob_list, /mob/living/carbon/xenomorph) GLOBAL_LIST_EMPTY_TYPED(living_xeno_list, /mob/living/carbon/xenomorph) GLOBAL_LIST_EMPTY_TYPED(xeno_cultists, /mob/living/carbon/human) +GLOBAL_LIST_EMPTY_TYPED(player_embryo_list, /obj/item/alien_embryo) GLOBAL_LIST_EMPTY_TYPED(hellhound_list, /mob/living/carbon/xenomorph/hellhound) GLOBAL_LIST_EMPTY_TYPED(zombie_list, /mob/living/carbon/human) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index ad2f305790d2..df7dd48a1dd1 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -71,7 +71,9 @@ return // Click handled elsewhere. (These clicks are not affected by the next_move cooldown) - if (click(A, mods) || A.clicked(src, mods, location, params)) + if(click(A, mods)) + return + if(A.clicked(src, mods, location, params)) return // Default click functions from here on. @@ -80,7 +82,7 @@ return face_atom(A) - if(mods["middle"]) + if(mods["middle"]) return // Special type of click. if (is_mob_restrained()) @@ -332,7 +334,7 @@ if(prefs.adaptive_zoom) INVOKE_ASYNC(src, PROC_REF(adaptive_zoom)) else if(prefs.auto_fit_viewport) - INVOKE_ASYNC(src, .verb/fit_viewport) + INVOKE_ASYNC(src, VERB_REF(fit_viewport)) /client/proc/get_adaptive_zoom_factor() if(!prefs.adaptive_zoom) diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 21ac66e5f222..5acfe74f2965 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -45,11 +45,11 @@ return FALSE var/deathtime = world.time - timeofdeath - if(deathtime < 2.5 MINUTES) + if(deathtime < XENO_JOIN_DEAD_LARVA_TIME) var/message = "You have been dead for [DisplayTimeText(deathtime)]." message = SPAN_WARNING("[message]") to_chat(src, message) - to_chat(src, SPAN_WARNING("You must wait 2.5 minutes before rejoining the game!")) + to_chat(src, SPAN_WARNING("You must wait atleast 2.5 minutes before rejoining the game!")) ManualFollow(target) return FALSE diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index a8ed20f5c4b3..9c9784286d09 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -34,4 +34,4 @@ Have no reason to click on anything at all. */ /mob/new_player/click() - return 1 + return diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 29dd0a88d3e0..7988ff6d1a95 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -529,6 +529,25 @@ This maintains a list of ip addresses that are able to bypass topic filtering. /datum/config_entry/string/round_results_webhook_url +/// InfluxDB v2 Host to connect to for sending statistics (over HTTP API) +/datum/config_entry/string/influxdb_host +/// InfluxDB v2 Bucket to send staistics to +/datum/config_entry/string/influxdb_bucket +/// InfluxDB v2 Organization to access buckets of +/datum/config_entry/string/influxdb_org +/// InfluxDB v2 API Token to access the organization and bucket +/datum/config_entry/string/influxdb_token + +/// How often to snapshot general game statistics to influxdb driver +/datum/config_entry/number/influxdb_stats_period + config_entry_value = 30 +/// How often to snapshot MC statistics +/datum/config_entry/number/influxdb_mcstats_period + config_entry_value = 60 +/// How often to send queued influxdb statistics +/datum/config_entry/number/influxdb_send_period + config_entry_value = 10 + /// logs all timers in buckets on automatic bucket reset (Useful for timer debugging) /datum/config_entry/flag/log_timers_on_bucket_reset diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm index 283fe79cfead..38e57df93cef 100644 --- a/code/controllers/subsystem/assets.dm +++ b/code/controllers/subsystem/assets.dm @@ -7,6 +7,20 @@ SUBSYSTEM_DEF(assets) var/list/preload = list() var/datum/asset_transport/transport = new() +/datum/controller/subsystem/assets/OnConfigLoad() + var/newtransporttype = /datum/asset_transport + switch (CONFIG_GET(string/asset_transport)) + if ("webroot") + newtransporttype = /datum/asset_transport/webroot + + if (newtransporttype == transport.type) + return + + var/datum/asset_transport/newtransport = new newtransporttype () + if (newtransport.validate_config()) + transport = newtransport + transport.Load() + /datum/controller/subsystem/assets/Initialize() for(var/type in typesof(/datum/asset)) var/datum/asset/A = type diff --git a/code/controllers/subsystem/influxdriver.dm b/code/controllers/subsystem/influxdriver.dm new file mode 100644 index 000000000000..7e5289dfc518 --- /dev/null +++ b/code/controllers/subsystem/influxdriver.dm @@ -0,0 +1,132 @@ +/// Sends collected statistics to an influxdb v2 backend periodically +SUBSYSTEM_DEF(influxdriver) + name = "InfluxDB Driver" + wait = 10 SECONDS + init_order = SS_INIT_INFLUXDRIVER + priority = SS_PRIORITY_INFLUXDRIVER + runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY + + var/list/send_queue = list() + + /// Maximum amount of metric lines to send at most in one request + /// This is neccessary because sending a lot of metrics can get expensive + /// and drive the subsystem into overtime, but we can't split the work as it'd be even less efficient + var/max_batch = 150 + + /// Last timestamp in microseconds + var/timestamp_cache_realtime + /// Last tick time the timestamp was taken at + var/timestamp_cache_worldtime + +/datum/controller/subsystem/influxdriver/Initialize() + var/period = text2num(CONFIG_GET(number/influxdb_send_period)) + if(isnum(period)) + wait = max(period * (1 SECONDS), 2 SECONDS) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/influxdriver/stat_entry(msg) + msg += "period=[wait] queue=[length(send_queue)]" + return ..() + +/datum/controller/subsystem/influxdriver/proc/unix_timestamp_string() // pending change to rust-g + return RUSTG_CALL(RUST_G, "unix_timestamp")() + +/datum/controller/subsystem/influxdriver/proc/update_timestamp() + PRIVATE_PROC(TRUE) + // We make only one request to rustg per game tick, so we cache the result per world.time + var/whole_timestamp = unix_timestamp_string() // Format "7129739474.4758981" - timestamp with up to 7-8 decimals + var/list/tsparts = splittext(whole_timestamp, ".") + var/fractional = copytext(pad_trailing(tsparts[2], "0", 6), 1, 7) // in microseconds + timestamp_cache_worldtime = world.time + timestamp_cache_realtime = "[tsparts[1]][fractional]" + +/datum/controller/subsystem/influxdriver/fire(resumed) + var/maxlen = min(length(send_queue)+1, max_batch) + var/list/queue = send_queue.Copy(1, maxlen) + send_queue.Cut(1, maxlen) + flush_queue(queue) + +/// Flushes measurements batch to InfluxDB backend +/datum/controller/subsystem/influxdriver/proc/flush_queue(list/queue) + PRIVATE_PROC(TRUE) + + var/host = CONFIG_GET(string/influxdb_host) + var/token = CONFIG_GET(string/influxdb_token) + var/bucket = CONFIG_GET(string/influxdb_bucket) + var/org = CONFIG_GET(string/influxdb_org) + + if(!host || !token || !bucket || !org) + can_fire = FALSE + return + + if(!length(queue)) + return // Nothing to do + + var/url = "[host]/api/v2/write?org=[org]&bucket=[bucket]&precision=us" // microseconds + var/list/headers = list() + headers["Authorization"] = "Token [token]" + headers["Content-Type"] = "text/plain; charset=utf-8" + headers["Accept"] = "application/json" + + var/datum/http_request/request = new + var/payload = "" + for(var/line in queue) + payload += "[line]\n" + request.prepare(RUSTG_HTTP_METHOD_POST, url, payload, headers) + request.begin_async() + // TODO possibly check back result of request later + +/// Enqueues sending to InfluxDB Backend selected measurement values - round_id and timestamp are filled in automatically +/datum/controller/subsystem/influxdriver/proc/enqueue_stats(measurement, list/tags, list/fields) + . = FALSE + var/valid = FALSE + var/serialized = "[measurement],round_id=[GLOB.round_id]" + if(tags) + for(var/tag in tags) + var/serialized_tag = serialize_field(tag, tags[tag]) + if(serialized_tag) + serialized += ",[serialized_tag]" + serialized += " " + var/comma = "" + for(var/field in fields) + var/serialized_field = serialize_field(field, fields[field]) + if(serialized_field) + valid = TRUE + serialized += "[comma][serialized_field]" + comma = "," + if(!valid) + CRASH("Attempted to serialize to InfluxDB backend an invalid measurement (likely has no fields)") + if(timestamp_cache_worldtime != world.time) + update_timestamp() + serialized += " [timestamp_cache_realtime]" + send_queue += serialized + return TRUE + +/// Enqueues sending varied stats in a dumb and simpler format directly as: measurement count= +/datum/controller/subsystem/influxdriver/proc/enqueue_stats_crude(measurement, value, field_name = "count") + . = FALSE + var/serialized_field = serialize_field(field_name, value) + if(!length(serialized_field)) + return + if(timestamp_cache_worldtime != world.time) + update_timestamp() + var/serialized = "[measurement],round_id=[GLOB.round_id] [serialized_field] [timestamp_cache_realtime]" + send_queue += serialized + return TRUE + +/// Puts a single field or tag value into InfluxDB Line format +/datum/controller/subsystem/influxdriver/proc/serialize_field(field, value) + var/static/regex/whitelistedCharacters = regex(@{"([^a-zA-Z0-9_]+)"}, "g") + var/sanitized_field = whitelistedCharacters.Replace("[field]", "") + if(!length(sanitized_field) || copytext(sanitized_field, 1, 2) == "_") + CRASH("Invalid tag/field for InfluxDB serialization: '[sanitized_field]' (original: '[field]')") + var/sanitized_value + if(isnum(value)) + sanitized_value = value + else if(istext(value)) + sanitized_value = whitelistedCharacters.Replace("[value]", "") + if(!length(sanitized_value) || copytext(sanitized_value, 1, 2) == "_") + CRASH("Invalid value for InfluxDB serialization: '[sanitized_value]' (original: '[value]')") + else + CRASH("Invalid value type passed for InfluxDB serialization: '[value]'") + return "[sanitized_field]=[sanitized_value]" diff --git a/code/controllers/subsystem/influxmcstats.dm b/code/controllers/subsystem/influxmcstats.dm new file mode 100644 index 000000000000..a1bf171d81a3 --- /dev/null +++ b/code/controllers/subsystem/influxmcstats.dm @@ -0,0 +1,47 @@ +SUBSYSTEM_DEF(influxmcstats) + name = "InfluxDB MC Stats" + wait = 60 SECONDS + priority = SS_PRIORITY_INFLUXMCSTATS + init_order = SS_INIT_INFLUXMCSTATS + runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT + flags = SS_KEEP_TIMING + var/checkpoint = 0 + var/list/subsystem_name_cache = list() + +/datum/controller/subsystem/influxmcstats/Initialize() + var/period = text2num(CONFIG_GET(number/influxdb_mcstats_period)) + if(isnum(period)) + wait = max(period * (1 SECONDS), 10 SECONDS) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/influxmcstats/stat_entry(msg) + msg += "period=[wait] checkpoint=[checkpoint]" + return ..() + +/datum/controller/subsystem/influxmcstats/fire(resumed) + if(!SSinfluxdriver.can_fire) + can_fire = FALSE + return + + var/list/data = list() + data["time_dilation_current"] = SStime_track.time_dilation_current + data["time_dilation_avg"] = SStime_track.time_dilation_avg + data["time_dilation_avg_slow"] = SStime_track.time_dilation_avg_slow + data["time_dilation_avg_fast"] = SStime_track.time_dilation_avg_fast + SSinfluxdriver.enqueue_stats("tidi", null, data) + + SSinfluxdriver.enqueue_stats("cpu", null, list("cpu" = world.cpu, "map_cpu" = world.map_cpu)) + + var/static/regex/get_last_path_element = regex(@{"/([^/]+)$"}) + checkpoint++ + for(var/datum/controller/subsystem/SS in Master.subsystems) + if(!SS.can_fire) + continue + if(!subsystem_name_cache[SS.type]) + get_last_path_element.Find("[SS.type]") + subsystem_name_cache[SS.type] = "SS[get_last_path_element.group[1]]" + var/SSname = subsystem_name_cache[SS.type] + if(!SSname) + stack_trace("Influx MC Stats couldnt name a subsystem, type=[SS.type]") + continue + SSinfluxdriver.enqueue_stats("sstimings", list("ss" = SSname), list("cost" = SS.cost, "tick_overrun" = SS.tick_overrun, "tick_usage" = SS.tick_usage, "wait" = SS.wait)) diff --git a/code/controllers/subsystem/influxstats.dm b/code/controllers/subsystem/influxstats.dm new file mode 100644 index 000000000000..01015b83191d --- /dev/null +++ b/code/controllers/subsystem/influxstats.dm @@ -0,0 +1,156 @@ +/// Sends generic round running statistics to the InfluxDB backend +SUBSYSTEM_DEF(influxstats) + name = "InfluxDB Game Stats" + wait = 60 SECONDS + priority = SS_PRIORITY_INFLUXSTATS + init_order = SS_INIT_INFLUXSTATS + runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT + flags = SS_KEEP_TIMING + + var/checkpoint = 0 //! Counter of data snapshots sent + var/step = 1 //! Current task in progress, for pausing/resuming + +/datum/controller/subsystem/influxstats/Initialize() + var/period = text2num(CONFIG_GET(number/influxdb_stats_period)) + if(isnum(period)) + wait = max(period * (1 SECONDS), 10 SECONDS) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/influxstats/stat_entry(msg) + msg += "period=[wait] checkpoint=[checkpoint] step=[step]" + return ..() + +/datum/controller/subsystem/influxstats/fire(resumed) + if(!SSinfluxdriver.can_fire) + can_fire = FALSE + return + + checkpoint++ + while(step < 5) // Yes, you could make one SS per stats category, and have proper scheduling and variable periods, but... + switch(step++) + if(1) // Connected players statistics + run_player_statistics() + if(2) // Job occupations + if(SSticker.current_state == GAME_STATE_PLAYING) + run_job_statistics() + if(3) // Round-wide gameplay statistics held in entity + if(SSticker.current_state == GAME_STATE_PLAYING) + run_round_statistics() + if(4) // Handpicked Round-wide gameplay statistics + if(SSticker.current_state == GAME_STATE_PLAYING) + run_special_round_statistics() + if(MC_TICK_CHECK) + return + + step = 1 + +/datum/controller/subsystem/influxstats/proc/flatten_entity_list(list/data) + var/list/result = list() + for(var/key in data) + var/datum/entity/statistic/entry = data[key] + result[key] = entry.value + return result + +/datum/controller/subsystem/influxstats/proc/run_special_round_statistics() + for(var/hive_tag in GLOB.hive_datum) + var/datum/hive_status/hive = GLOB.hive_datum[hive_tag] + SSinfluxdriver.enqueue_stats("pooled_larva", list("hive" = hive.reporting_id), list("count" = hive.stored_larva)) + var/burst_larvas = GLOB.larva_burst_by_hive[hive] || 0 + SSinfluxdriver.enqueue_stats("burst_larva", list("hive" = hive.reporting_id), list("count" = burst_larvas)) + +/datum/controller/subsystem/influxstats/proc/run_round_statistics() + var/datum/entity/statistic/round/stats = SSticker?.mode?.round_stats + if(!stats) + return // Sadge + + SSinfluxdriver.enqueue_stats_crude("chestbursts", stats.total_larva_burst) + SSinfluxdriver.enqueue_stats_crude("hugged", stats.total_huggers_applied) + SSinfluxdriver.enqueue_stats_crude("friendlyfire", stats.total_friendly_fire_instances) + + var/list/participants = flatten_entity_list(stats.participants) + if(length(participants)) + SSinfluxdriver.enqueue_stats("participants", list(), participants) + + var/list/total_deaths = flatten_entity_list(stats.total_deaths) + if(length(total_deaths)) + SSinfluxdriver.enqueue_stats("deaths", list(), total_deaths) + + SSinfluxdriver.enqueue_stats("shots", list(), + list("fired" = stats.total_projectiles_fired, "hits" = stats.total_projectiles_hit, + "hits_human" = stats.total_projectiles_hit_human, "hits_xeno" = stats.total_projectiles_hit_xeno) + ) + +/datum/controller/subsystem/influxstats/proc/run_player_statistics() + var/staff_count = 0 + var/mentor_count = 0 + for(var/client/client in GLOB.admins) + if(CLIENT_IS_STAFF(client)) + staff_count++ + else if(CLIENT_HAS_RIGHTS(client, R_MENTOR)) + mentor_count++ + SSinfluxdriver.enqueue_stats("online", null, list("count" = length(GLOB.clients))) + + var/list/adm = get_admin_counts() + var/present_admins = length(adm["present"]) + var/afk_admins = length(adm["afk"]) + SSinfluxdriver.enqueue_stats("online_staff", null, list("total" = staff_count, "mentors" = mentor_count, "present" = present_admins, "afk" = afk_admins)) + + // Grab ahelp stats + SSinfluxdriver.enqueue_stats("tickets", null, list( + "open" = length(GLOB.ahelp_tickets.active_tickets), + "closed" = length(GLOB.ahelp_tickets.closed_tickets), + "resolved" = length(GLOB.ahelp_tickets.resolved_tickets), + )) + +/datum/controller/subsystem/influxstats/proc/run_job_statistics() + var/list/team_job_stats = list() + var/list/squad_job_stats = ROLES_SQUAD_ALL.Copy() + for(var/squad in squad_job_stats) + squad_job_stats[squad] = list() + + for(var/client/client in GLOB.clients) + var/team + var/mob/mob = client.mob + if(!mob || mob.statistic_exempt) + continue + var/area/area = get_area(mob) + if(!area || area.statistic_exempt) + continue + var/job = mob.job + if(isobserver(mob) || mob.stat == DEAD) + job = JOB_OBSERVER + team = "observers" + else if(!job) + continue + else if(mob.faction == FACTION_MARINE || mob.faction == FACTION_SURVIVOR) + team = "humans" + var/mob/living/carbon/human/employed_human = mob + if(istype(employed_human)) + var/squad = employed_human.assigned_squad?.name + if(squad in squad_job_stats) + squad_job_stats[squad][job] = (squad_job_stats[squad][job] || 0) + 1 + continue // Defer to squad stats instead + // else: So you're in the USCM and have a job but aren't an human? Tell me more Dr Jones... + else if(ishuman(mob)) + team = "humans_others" + else if(isxeno(mob)) + var/mob/living/xeno_enabled_mob = mob + var/datum/hive_status/hive = GLOB.hive_datum[xeno_enabled_mob.hivenumber] + if(!hive) + team = "xenos_others" + else + team = "xenos_[hive.reporting_id]" + else + team = "others" + LAZYINITLIST(team_job_stats[team]) + if(!team_job_stats[team][job]) + team_job_stats[team][job] = 0 + team_job_stats[team][job] += 1 + + for(var/team in team_job_stats) + for(var/job in team_job_stats[team]) + SSinfluxdriver.enqueue_stats("job_stats", list("team" = team, "job" = job), list("count" = team_job_stats[team][job])) + + for(var/squad in squad_job_stats) + for(var/job in squad_job_stats[squad]) + SSinfluxdriver.enqueue_stats("job_stats", list("team" = "humans", "job" = job, "squad" = squad), list("count" = squad_job_stats[squad][job])) diff --git a/code/controllers/subsystem/minimap.dm b/code/controllers/subsystem/minimap.dm index e365a9b60781..c3b2d36b8177 100644 --- a/code/controllers/subsystem/minimap.dm +++ b/code/controllers/subsystem/minimap.dm @@ -262,8 +262,12 @@ SUBSYSTEM_DEF(minimaps) * removes an image from raw tracked lists, invoked by callback */ /datum/controller/subsystem/minimaps/proc/removeimage(image/blip, atom/target) + var/turf/turf_gotten = get_turf(target) + if(!turf_gotten) + return + var/z_level = turf_gotten.z for(var/flag in GLOB.all_minimap_flags) - minimaps_by_z["[target.z]"].images_raw["[flag]"] -= blip + minimaps_by_z["[z_level]"].images_raw["[flag]"] -= blip blip.UnregisterSignal(target, COMSIG_MOVABLE_MOVED) removal_cbs -= target @@ -391,18 +395,24 @@ SUBSYSTEM_DEF(minimaps) owner.client.screen += map minimap_displayed = !minimap_displayed -/datum/action/minimap/give_to(mob/M) +/datum/action/minimap/give_to(mob/target) . = ..() if(default_overwatch_level) map = SSminimaps.fetch_minimap_object(default_overwatch_level, minimap_flags) else - RegisterSignal(M, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_owner_z_change)) - if(!SSminimaps.minimaps_by_z["[M.z]"] || !SSminimaps.minimaps_by_z["[M.z]"].hud_image) + RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_owner_z_change)) + + var/turf/turf_gotten = get_turf(target) + if(!turf_gotten) + return + var/z_level = turf_gotten.z + + if(!SSminimaps.minimaps_by_z["[z_level]"] || !SSminimaps.minimaps_by_z["[z_level]"].hud_image) return - map = SSminimaps.fetch_minimap_object(M.z, minimap_flags) + map = SSminimaps.fetch_minimap_object(z_level, minimap_flags) -/datum/action/minimap/remove_from(mob/M) +/datum/action/minimap/remove_from(mob/target) . = ..() if(minimap_displayed) owner?.client?.screen -= map diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 58910c45af75..0e23b99a9cc2 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -424,7 +424,7 @@ SUBSYSTEM_DEF(ticker) for(var/mob/living/carbon/human/player in GLOB.human_mob_list) if(player.mind) - if(player.job == "Commanding Officers") + if(player.job == JOB_CO) captainless = FALSE if(player.job) RoleAuthority.equip_role(player, RoleAuthority.roles_by_name[player.job], late_join = FALSE) diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm index 6deb27a6817b..0d218ba94da4 100644 --- a/code/datums/components/footstep.dm +++ b/code/datums/components/footstep.dm @@ -31,7 +31,7 @@ return var/mob/living/LM = parent - if(LM.buckled || LM.lying || LM.throwing || LM.is_ventcrawling) + if(LM.buckled || LM.throwing || LM.is_ventcrawling || LM.stat == DEAD) return if(LM.life_steps_total % steps) diff --git a/code/datums/components/weed_food.dm b/code/datums/components/weed_food.dm new file mode 100644 index 000000000000..0c578b661517 --- /dev/null +++ b/code/datums/components/weed_food.dm @@ -0,0 +1,297 @@ +#define WEED_FOOD_DELAY 5 MINUTES +#define WEED_FOOD_STATE_DELAY 1 MINUTES + +/atom/movable/vis_obj/weed_food + name = "weeds" + desc = "Weird black weeds in the shape of a body..." + gender = PLURAL + vis_flags = VIS_INHERIT_DIR|VIS_INHERIT_PLANE|VIS_INHERIT_LAYER + icon = 'icons/mob/xenos/weeds.dmi' + var/static/list/icon_states = list("human_1","human_2","human_3","human_4","human_5") + var/static/list/icon_states_flipped = list("human_1_f","human_2_f","human_3_f","human_4_f","human_5_f") + var/icon_state_idx = 0 + var/timer_id = null + var/flipped = FALSE + +/atom/movable/vis_obj/weed_food/Initialize(mapload, is_flipped, ...) + flipped = is_flipped + timer_id = addtimer(CALLBACK(src, PROC_REF(on_animation_timer)), WEED_FOOD_STATE_DELAY, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_LOOP|TIMER_DELETE_ME) + on_animation_timer() + return ..() + +/// Timer callback for changing the icon_state +/atom/movable/vis_obj/weed_food/proc/on_animation_timer() + icon_state_idx++ + if(icon_state_idx > length(icon_states)) + deltimer(timer_id) + timer_id = null + return + icon_state = flipped ? icon_states_flipped[icon_state_idx] : icon_states[icon_state_idx] + +/** + * A component that can be attached to a mob/living to be merged with weeds after a delay. + * Attempting to attach a new weed_food even if one already exists is equivalent to calling start(). + * + * Attach this to any mob/living that is dead (death or initialized dead) and it should handle the rest. + */ +/datum/component/weed_food + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + /// Whether we are waiting on timer to merge + var/active = FALSE + /// Whether we are merged with weeds + var/merged = FALSE + /// The time we were unmerged (just to handle weeds upgrading) + var/unmerged_time + /// Any active timer for a pending merge + var/timer_id = null + /// The living mob that we are bound to + var/mob/living/parent_mob + /// The turf that our parent is on + var/turf/parent_turf + /// The obj that our parent is buckled to and we have registered a signal + var/obj/parent_buckle + /// The weeds that we are merging/merged with + var/obj/effect/alien/weeds/absorbing_weeds + /// The overlay image when merged + var/atom/movable/vis_obj/weed_food/weed_appearance + +/datum/component/weed_food/Initialize(...) + parent_mob = parent + //if(!istype(parent_mob)) + //return COMPONENT_INCOMPATIBLE + if(!istype(parent_mob, /mob/living/carbon/human)) + return COMPONENT_INCOMPATIBLE // TODO: At the moment we only support humans + + parent_turf = get_turf(parent_mob) + if(parent_turf != parent_mob.loc) + parent_turf = null // if our location is actually a container, we want to be safe from weeds + + start() + +/datum/component/weed_food/InheritComponent(datum/component/C, i_am_original) + start() + +/datum/component/weed_food/Destroy(force, silent) + . = ..() + + unmerge_with_weeds() + QDEL_NULL(weed_appearance) + parent_mob = null + parent_turf = null + +/datum/component/weed_food/RegisterWithParent() + RegisterSignal(parent_mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) + RegisterSignal(parent_mob, list(COMSIG_LIVING_REJUVENATED, COMSIG_HUMAN_REVIVED), PROC_REF(on_rejuv)) + RegisterSignal(parent_mob, COMSIG_HUMAN_SET_UNDEFIBBABLE, PROC_REF(on_update)) + if(parent_turf) + RegisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH, PROC_REF(on_update)) + +/datum/component/weed_food/UnregisterFromParent() + if(parent_mob) + UnregisterSignal(parent_mob, list( + COMSIG_MOVABLE_MOVED, + COMSIG_LIVING_REJUVENATED, + COMSIG_HUMAN_REVIVED, + COMSIG_HUMAN_SET_UNDEFIBBABLE, + )) + if(absorbing_weeds) + UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) + if(parent_turf) + UnregisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH) + if(parent_buckle) + UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) + +/// SIGNAL_HANDLER for COMSIG_MOVABLE_MOVED +/datum/component/weed_food/proc/on_move() + SIGNAL_HANDLER + + if(absorbing_weeds) + UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) + absorbing_weeds = null + + if(parent_turf) + UnregisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH) + parent_turf = get_turf(parent_mob) + if(parent_turf != parent_mob.loc) + parent_turf = null // if our location is actually a container, we want to be safe from weeds + else + RegisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH, PROC_REF(on_update)) + + // We moved, restart or start the proccess + if(stop() || !merged) + start() + return + + // If we somehow moved when we were merged, handle that + absorbing_weeds = parent_turf?.weeds + if(absorbing_weeds) + RegisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion)) + return + unmerge_with_weeds() + +/// SIGNAL_HANDLER for COMSIG_LIVING_REJUVENATED and COMSIG_HUMAN_REVIVED +/datum/component/weed_food/proc/on_rejuv() + SIGNAL_HANDLER + + qdel(src) + +/// SIGNAL_HANDLER for COSMIG_OBJ_AFTER_BUCKLE +/datum/component/weed_food/proc/on_after_buckle(obj/source, mob/buckled) + SIGNAL_HANDLER + + if(buckled) + return + start() // We unbuckled, so lets try to start again + +/// SIGNAL_HANDLER for COMSIG_HUMAN_SET_UNDEFIBBABLE & COMSIG_WEEDNODE_GROWTH +/datum/component/weed_food/proc/on_update() + SIGNAL_HANDLER + + start() + +/// SIGNAL_HANDLER for COMSIG_PARENT_QDELETING of weeds +/datum/component/weed_food/proc/on_weed_deletion() + SIGNAL_HANDLER + + if(active) + stop() + return + if(merged) + unmerge_with_weeds() + return + +/** + * Try to start the process to turn into weeds + * Returns TRUE if started successfully + */ +/datum/component/weed_food/proc/start() + if(active) + return FALSE + if(merged) + return FALSE + if(QDELETED(parent_mob)) + return FALSE + + if(parent_mob.buckled) + if(parent_mob.buckled == parent_buckle) + return FALSE // Still buckled to the same thing + if(!istype(parent_mob.buckled, /obj/structure/bed/nest)) + if(parent_buckle) // Still have a lingering reference somehow? + UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) + parent_buckle = parent_mob.buckled + RegisterSignal(parent_mob.buckled, COSMIG_OBJ_AFTER_BUCKLE, PROC_REF(on_after_buckle)) + return FALSE + if(parent_buckle) + UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) + parent_buckle = null + + if(parent_mob.is_xeno_grabbable()) + return FALSE + if(!(parent_mob.status_flags & PERMANENTLY_DEAD)) + var/mob/living/carbon/human/parent_human = parent_mob + if(istype(parent_human) && !parent_human.undefibbable) + return FALSE + if(!parent_turf?.weeds) + return FALSE + + if(unmerged_time == world.time) + return merge_with_weeds() // Weeds upgraded, re-merge now re-using the apperance + QDEL_NULL(weed_appearance) + absorbing_weeds = parent_turf.weeds + RegisterSignal(parent_turf.weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion)) + + active = TRUE + timer_id = addtimer(CALLBACK(src, PROC_REF(merge_with_weeds)), WEED_FOOD_DELAY, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_DELETE_ME|TIMER_OVERRIDE) + + return TRUE + +/** + * Try to stop the process turning into weeds + * Returns TRUE if stopped successfully (was active when called) + */ +/datum/component/weed_food/proc/stop() + if(!active) + return FALSE + + active = FALSE + deltimer(timer_id) + timer_id = null + + return TRUE + +/** + * Finish becomming one with the weeds + * Returns TRUE if merged successfully + */ +/datum/component/weed_food/proc/merge_with_weeds() + if(merged) + return FALSE + if(QDELETED(parent_mob)) + return FALSE + + if(absorbing_weeds) // Remove the signal that would call stop + UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) + + if(parent_mob.buckled) + if(parent_mob.buckled == parent_buckle) + return FALSE // Still buckled to the same thing somehow? + if(!istype(parent_mob.buckled, /obj/structure/bed/nest)) + if(parent_buckle) // Still have a lingering reference somehow? + UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) + parent_buckle = parent_mob.buckled + RegisterSignal(parent_mob.buckled, COSMIG_OBJ_AFTER_BUCKLE, PROC_REF(on_after_buckle)) + return FALSE + if(parent_buckle) + UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE) + parent_buckle = null + + absorbing_weeds = parent_turf?.weeds + if(!absorbing_weeds) + return FALSE + RegisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion)) + // Technically we could have just left the signal alone, but both because of the posibility of other conditions preventing a merge or weeds somehow changing and on_move didn't catch it, this is less fragile + + active = FALSE + merged = TRUE + + parent_mob.density = FALSE + parent_mob.anchored = TRUE + parent_mob.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + parent_mob.plane = FLOOR_PLANE + parent_mob.remove_from_all_mob_huds() + + if(!weed_appearance) // Make a new sprite if we aren't re-merging + var/is_flipped = parent_mob.transform.b == -1 // Technically we should check if d is 1 too, but corpses can only be rotated 90 or 270 (1/-1 or -1/1) + if(parent_mob.dir & WEST) + is_flipped = !is_flipped // The direction reversed the effect of the flip! + weed_appearance = new(null, is_flipped) + weed_appearance.color = absorbing_weeds.color + // TODO: For non-humans change the icon_state or something here + parent_mob.vis_contents += weed_appearance + + return TRUE + +/** + * Undo the weedening + * Returns TRUE if unmerged successfully (always) + */ +/datum/component/weed_food/proc/unmerge_with_weeds() + merged = FALSE + unmerged_time = world.time + + if(absorbing_weeds) + UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING) + absorbing_weeds = null + + parent_mob.anchored = FALSE + parent_mob.mouse_opacity = MOUSE_OPACITY_ICON + parent_mob.plane = GAME_PLANE + parent_mob.vis_contents -= weed_appearance + + if(!QDELETED(parent_mob)) + parent_mob.add_to_all_mob_huds() + + return TRUE + +#undef WEED_FOOD_DELAY +#undef WEED_FOOD_STATE_DELAY diff --git a/code/datums/effects/neurotoxin.dm b/code/datums/effects/neurotoxin.dm index 0405c87bec8b..836fccf49ca3 100644 --- a/code/datums/effects/neurotoxin.dm +++ b/code/datums/effects/neurotoxin.dm @@ -21,9 +21,8 @@ /// Stamina damage per tick. Major balance number. var/stam_dam = 7 -/datum/effects/neurotoxin/New(atom/thing) - ..(thing) - cause_data = create_cause_data("neurotoxic gas") +/datum/effects/neurotoxin/New(atom/thing, mob/from = null) + ..(thing, from, effect_name) /datum/effects/neurotoxin/validate_atom(atom/thing) if(isxeno(thing) || isobj(thing)) @@ -36,9 +35,10 @@ var/mob/living/carbon/affected_mob = affected_atom if(!.) return FALSE - if(affected_mob.stat) + if(affected_mob.stat == DEAD) return // General effects + affected_mob.last_damage_data = cause_data affected_mob.apply_stamina_damage(stam_dam) affected_mob.make_dizzy(12) diff --git a/code/datums/elements/bloody_feet.dm b/code/datums/elements/bloody_feet.dm index 6a5a8a23ac6b..3bcccd8377c6 100644 --- a/code/datums/elements/bloody_feet.dm +++ b/code/datums/elements/bloody_feet.dm @@ -24,12 +24,12 @@ H.bloody_footsteps = steps_to_take LAZYADD(entered_bloody_turf, target) - RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) - RegisterSignal(target, COMSIG_HUMAN_BLOOD_CROSSED, PROC_REF(blood_crossed)) - RegisterSignal(target, COMSIG_HUMAN_CLEAR_BLOODY_FEET, PROC_REF(clear_blood)) + RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved), override = TRUE) + RegisterSignal(target, COMSIG_HUMAN_BLOOD_CROSSED, PROC_REF(blood_crossed), override = TRUE) + RegisterSignal(target, COMSIG_HUMAN_CLEAR_BLOODY_FEET, PROC_REF(clear_blood), override = TRUE) if(shoes) LAZYSET(target_shoes, target, shoes) - RegisterSignal(shoes, COMSIG_ITEM_DROPPED, PROC_REF(on_shoes_removed)) + RegisterSignal(shoes, COMSIG_ITEM_DROPPED, PROC_REF(on_shoes_removed), override = TRUE) if(dry_time) addtimer(CALLBACK(src, PROC_REF(clear_blood), target), dry_time) diff --git a/code/datums/emergency_calls/cryo_marines.dm b/code/datums/emergency_calls/cryo_marines.dm index e5992a62ecdd..eb914e198b37 100644 --- a/code/datums/emergency_calls/cryo_marines.dm +++ b/code/datums/emergency_calls/cryo_marines.dm @@ -3,7 +3,7 @@ //whiskey outpost extra marines /datum/emergency_call/cryo_squad name = "Marine Cryo Reinforcements (Squad)" - mob_max = 15 + mob_max = 10 mob_min = 1 probability = 0 objectives = "Assist the USCM forces" @@ -13,10 +13,12 @@ shuttle_id = "" var/leaders = 0 -/datum/emergency_call/cryo_squad/spawn_candidates(announce, override_spawn_loc) +/datum/emergency_call/cryo_squad/spawn_candidates(announce, override_spawn_loc, announce_dispatch_message) var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo] leaders = cryo_squad.num_leaders - return ..() + . = ..() + if(length(members)) + shipwide_ai_announcement("Successfully deployed [length(members)] Foxtrot marines.") /datum/emergency_call/cryo_squad/create_member(datum/mind/M, turf/override_spawn_loc) set waitfor = 0 diff --git a/code/datums/emergency_calls/cryo_marines_heavy.dm b/code/datums/emergency_calls/cryo_marines_heavy.dm index 6a3636568856..70ce52443573 100644 --- a/code/datums/emergency_calls/cryo_marines_heavy.dm +++ b/code/datums/emergency_calls/cryo_marines_heavy.dm @@ -16,10 +16,12 @@ var/leaders = 0 -/datum/emergency_call/cryo_squad_equipped/spawn_candidates(announce, override_spawn_loc) +/datum/emergency_call/cryo_squad_equipped/spawn_candidates(announce, override_spawn_loc, announce_dispatch_message) var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo] leaders = cryo_squad.num_leaders - return ..() + . = ..() + if(length(members)) + shipwide_ai_announcement("Successfully deployed [length(members)] Foxtrot marines.") /datum/emergency_call/cryo_squad_equipped/create_member(datum/mind/M, turf/override_spawn_loc) set waitfor = 0 diff --git a/code/datums/emergency_calls/emergency_call.dm b/code/datums/emergency_calls/emergency_call.dm index c4b1000bb07b..2a305dcc4342 100644 --- a/code/datums/emergency_calls/emergency_call.dm +++ b/code/datums/emergency_calls/emergency_call.dm @@ -191,7 +191,7 @@ message_admins("Distress beacon: '[name]' activated [src.hostility? "[SPAN_WARNING("(THEY ARE HOSTILE)")]":"(they are friendly)"]. Looking for candidates.") if(announce) - marine_announcement("A distress beacon has been launched from the [MAIN_SHIP_NAME].", "Priority Alert", 'sound/AI/distressbeacon.ogg') + marine_announcement("A distress beacon has been launched from the [MAIN_SHIP_NAME].", "Priority Alert", 'sound/AI/distressbeacon.ogg', logging = ARES_LOG_SECURITY) addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/emergency_call, spawn_candidates), announce, override_spawn_loc, announce_dispatch_message), 30 SECONDS) @@ -207,7 +207,7 @@ candidates = list() if(announce) - marine_announcement("The distress signal has not received a response, the launch tubes are now recalibrating.", "Distress Beacon") + marine_announcement("The distress signal has not received a response, the launch tubes are now recalibrating.", "Distress Beacon", logging = ARES_LOG_SECURITY) return //We've got enough! @@ -236,8 +236,8 @@ if(I.current) to_chat(I.current, SPAN_WARNING("You didn't get selected to join the distress team. Better luck next time!")) - if(announce_dispatch_message) - marine_announcement(dispatch_message, "Distress Beacon", 'sound/AI/distressreceived.ogg') //Announcement that the Distress Beacon has been answered, does not hint towards the chosen ERT + if(announce) + marine_announcement(dispatch_message, "Distress Beacon", 'sound/AI/distressreceived.ogg', logging = ARES_LOG_SECURITY) //Announcement that the Distress Beacon has been answered, does not hint towards the chosen ERT message_admins("Distress beacon: [src.name] finalized, setting up candidates.") diff --git a/code/datums/fluff_emails.dm b/code/datums/fluff_emails.dm index 6dd8cd590860..f7083541dd5a 100644 --- a/code/datums/fluff_emails.dm +++ b/code/datums/fluff_emails.dm @@ -93,9 +93,9 @@ /datum/fluff_email/almayer/themajor title = "The Major?" entry_text = {" - I keep forgetting what the new Major's name is. I got quizzed by one of the jackass staff officers last week about the captain's name, - and I absolutely spilled my marbles. PCF Mable was watching too, and she probably thinks I've got rocks in my head. I know it's been weeks - since the new captain took over, but for some reason the name keeps escaping me when it matters. Either the cryo-sleepers are juicing my + I keep forgetting what the new Major's name is. I got quizzed by one of the jackass staff officers last week about the Major's name, + and I absolutely spilled my marbles. PFC Mable was watching too, and she probably thinks I've got rocks in my head. I know it's been weeks + since the new Major took over, but for some reason the name keeps escaping me when it matters. Either the cryo-sleepers are juicing my memory capacity or the CO keeps changing their name and not telling anybody. Maybe next jump I'll scrawl it on a sticky note and plaster it to the inside of my sleeper pod. I can't be the only one having this problem. @@ -105,7 +105,8 @@ /datum/fluff_email/almayer/tunes title = "RE: Tunes" entry_text = {" - Cryosleep is killing me, man. Inside and outside. I mean really, they expect us to sit in that tube for god only knows how long, and when we wake up? It's all 'grab a crappy protein bar and grab your gear, you're going to war, Marine!' Bullshit. + Cryosleep is killing me, man. Inside and outside. I mean really, they expect us to sit in that tube for god only knows how long, and when we wake up? + It's all 'grab a crappy protein bar and grab your gear, you're going to war, Marine!' Bullshit.

Anywho, I've been thinking how to make the whole thing more bearable. Tried to take a plush from the bunks with me inside. That dickwad MP took it away from me though, said it was against Operating Procedure. Like I care. Can't do anything fun around here, right? @@ -113,82 +114,81 @@ I don't usually use these things, and frankly that vendor near Medbay has waaay too many cassettes to choose from. Not that I know most songs on them anywho.

- I saw you with a Walkman from time to time, so... any chances you could recommend a tape to me? Or two, I'm not gonna be picky. Just anything to start out with, I just want some nice sounds. Please, I'm gonna go mad if I don't do something about my cryophobia or whatever. This might just help with that. + I saw you with a Walkman from time to time, so... any chances you could recommend a tape to me? Or two, I'm not gonna be picky. + Just anything to start out with, I just want some nice sounds. Please, I'm gonna go mad if I don't do something about my cryophobia or whatever. + This might just help with that. "} -/datum/fluff_email/almayer/lasergun - title = "RE: Lasergun" +/datum/fluff_email/almayer/lasergun1 + title = "Prototype Weapon" entry_text = {" - Hey REDACTED. Thanks for letting me test out the laser gun. That thing is a factual blast to use. It literally set the targets down range on fire! Those cooling coils work wonders. Used it a good few times and the barrel didn't explode! + This thing is an absolute blast to use. + It disintegrated some of the targets down range but you're going to need to work on those cooling coils. + I used it a few times and I'm seeing the front barrel glow red.

- Hell, it's even pretty accurate too. I know there's like, a couple of prototypes issued to some USCM detachments but we got to have this shit in production one day. It's just good. Now, I don't think it's gonna replace the old Mark two's but it would be a nice addition for some of our grunts that prefer the high tech approach. You know the ones, all nerdy and gadget loving geeks in the corps. Hell I can already hear them glossing over this thing in their sleep. + Surprisingly accurate too despite being a prototype. + I know there's like, a couple of prototypes issued to some USCM detachments, but we got to have this shit in production one day.

- Anyway, I've already attached the weapon report you wanted on this thing back to the email. Hopefully you guys in R&D will get some useful info out of it. + Even as a prototype, it's leagues better than some of the junk we're issued. + Now, I don't think it's going to replace the old Mark Twos, but it would be a nice addition for some of our grunts that prefer the high-tech approach.
- Alright see you when I see you - REDACTED
-
- RE:RE: The Plasma Gun (It's called the XM99 Phased Plasma Pulse Rifle) - Hey REDACTED, REDACTED here. Thanks for the report but I'm going to need you to send the Phased Plasma Pulse Rifle back to me. Apparently we're not allowed to ship them out for testing... I guess I must've missed that memo. The memo came three days after I shipped it out to you. Sorry for the inconvenience. You know where to send it back to and how to. I did tell you how right? There was a small pamphlet in the casing if you forgot. -
-
- Don't think this is going to be issued en masse for a while, it's still going under trials and when I got the weapon report you sent me, they sent in a new updated design for the gun which invalidated most of the things in the report, shame. Looks more promising than the last one though. -
-
- Okay, I'll hopefully be seeing the XM99 Phased Plasma Pulse Rifle in the lab soon. -
-
- REDACTED RE:RE:RE: The Plasma Gun (It's called the XM99 Phased Plasma Pulse Rifle) -
- Holy shit, what the fuck did you do to the damned thing? When I opened the case, I could see fractures and scratches everywhere! Did you give this to the entire platoon to try out? And from the data I'm reading, you fired over 178 shots with this. I only gave you two batteries for the thing. -
-
- How the hell did you recharge it?! The prototype can't take any other forms of power other than those two batteries. And even then, you can't recharge those specially made batteries either without the equipment back in the lab here. And the inside of the barrel is all messed up man. The cooling coils expired and there're bits of the barrel loose inside of it. How the hell did you not notice bits of the inside of the barrel spewing out from the muzzle man?! -
-
- Right. They've threatened to drop me from the project if something like this happens again. In the rare case that I send another prototype out, it had better come back in one piece. And I mean in pristine condition, you got that? -
-
Regards, -
REDACTED + You know the ones, all nerdy and gadget loving geeks in the corps. Hell, I can already hear them glossing over this thing in their sleep. + My report has been sent back to you and I'm really excited to see how this turns out. + + "} + + +/datum/fluff_email/almayer/lasergun2 + title = "New Prototype Design" + entry_text = {" + Thanks for sending the report in, we've been mulling over the data you sent over. + We've updated the design for the prototype which solves most of the problems everyone has encountered. + This one looks more promising than the last one. + And as much as everyone wants this done and shippped, I don't think this is going to be issued en masse for a good while. "} /datum/fluff_email/almayer/beatup - title = "RE: Beat Up" + title = "Beat Up" entry_text = {" - Yo. -
-
- Man, last mission was an absolute shit show. The USS Heyst got their shit kicked in with a missile and we got our cargo hold set on fire by that damn suicide craft. They even blew up most of our good ammo too! Now we're left with the soft point backup munitions. Shit, most of 1st platoon is pretty much out of action. Lotta folks are in sickbay and the rest of us are heading off to cryosleep, well what's left of us. -
-
- When the comms got cut and we were cut off from command; Squad Foxtrot was immediately ambushed on the logistics route to get supplies in and out of the combat zone. I suspect they were taping into your comms to find the literal perfect moment to fuck with our logistics. Thankfully those trucks of ours had their engines tricked out by the techies back on LV-176 in the civilian garage. Those guys hosted rally races around their colony and Sergeant DATA EXPUNGED won a few races for us. Instead of taking their trophy, he pulled a few favors to get our trucks pimped out with better engines. We owe our lives to Sarge for winning one for the corps. -
-
- Hell, at least we're all going back to Chinook Station to get resupplied. Hopefully the wounded wake up to the docs on station rather than our poor and cramped excuse for a medical bay. The number of times the medbay has been packed with wounded where even the damn front lobby had bodies lining up on the sides of the walls waiting for treatment; it still amazes. Worse still was the stench from all the blood and guts, it made it hell for the maint. techs to clean up afterwards. -
- I'm still surprised those doctors we had on hand took care of most of them so quickly, even if most of them are still injured heading to the fridge. -
-
- I read the After-Action Report which the Heyst's XO did, and they're leaving out a few details. When it came to that city, they left out how we had to DATA EXPUNGED. The entire building collapsed with them in it too. Damn shame we couldn't save them. -
-
- The only damn silver lining i see in this shit is that the AI is going to cycle cryo again and we ain't waking to deal with whatever bullshit is happening next time. 2nd Platoon is dealing with that, cause 1st platoon is undermanned as is with our casualties. I heard they have a few screws loose, not that ours are entirely in either! But I don't care, it's their problem now y'know? -
-
- Worst case scenario, we don't wake up at all. -
- Right, see you back on station friend. -
-
- Regards, -
- REDACTED + Man last mission was an absolute shit show. +
+ The USS Heyst got their shit kicked in with a missile and we got our cargo hold set on fire. And most of our good ammo is gone too! + Now we're left with the FMJs and the older AP munitions. What's worse is that most of 1st platoon is pretty much out of action. + Lotta folks are in the sickbay and the rest of us are heading off to cryosleep, well what's left of us. There's not many of the old guard left I'm afraid. + Until we get reinforced with more bodies, command has given the go ahead to merge 2nd platoon into 1st for the time being. + + "} + + +/datum/fluff_email/almayer/rallyrace + title = "Rally Racing" + entry_text = {" + Hey, remember last shore leave on LV-179? Man, that was one crazy night. The folks at the colony had setup a rally race with their tractors all stripped of non-essentials. + LCPL Millard got pretty friendly with the locals and got himself into the competition. + We all put in a little wager to see if he'd even get close to first place or even survive to the finish line. + Now most of the boys bet a fair amount against him since he was pretty new to our outfit, yet I've been out on detail with the guy. +
+
+ Millard grew up on one of those shake and bake colonies and used to drive the big daisies around. + He knew the ins and outs of what made them tick. The few of us who had faith in him reaped everyone else's + paycheck for the week with Millard finishing first place by a near country mile. "} + +/datum/fluff_email/almayer/missing + title = "Missing Personnel" + entry_text = {" + Has anyone seen Mendoza around? He owes me half of his paycheck from last month's poker game. + Everyone's payday was a week ago and we're all set to head back to Chinook station. + Could have sworn I saw him near the cargo elevator yesterday. + I'll catch him back at base once we've docked because I need that money to pay off my tab at the bar. + + "} + diff --git a/code/datums/paygrades/paygrade.dm b/code/datums/paygrades/paygrade.dm index b15071c882b7..bb0a3aa84bfa 100644 --- a/code/datums/paygrades/paygrade.dm +++ b/code/datums/paygrades/paygrade.dm @@ -25,6 +25,7 @@ GLOBAL_LIST_INIT_TYPED(paygrades, /datum/paygrade, setup_paygrades()) .[pg_id] = new PG GLOBAL_LIST_INIT(highcom_paygrades, list( + "PvI", "NO7", "MO7", "NO8", @@ -52,3 +53,9 @@ GLOBAL_LIST_INIT(co_paygrades, list( "MO5", "MO4" )) + +GLOBAL_LIST_INIT(wy_paygrades, list( + "WYC8", + "WYC9", + "WYC10" +)) diff --git a/code/datums/skills.dm b/code/datums/skills.dm index ef86b726a3c1..16a2a20a57fd 100644 --- a/code/datums/skills.dm +++ b/code/datums/skills.dm @@ -851,7 +851,7 @@ SYNTHETIC /datum/skills/colonial_synthetic name = SYNTH_COLONY skills = list( - SKILL_CQC = SKILL_CQC_SKILLED, + SKILL_CQC = SKILL_CQC_EXPERT, SKILL_ENGINEER = SKILL_ENGINEER_ENGI, SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI, SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, @@ -862,7 +862,7 @@ SYNTHETIC SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER, SKILL_PILOT = SKILL_PILOT_EXPERT, SKILL_POLICE = SKILL_POLICE_SKILLED, - SKILL_FIREMAN = SKILL_FIREMAN_TRAINED, + SKILL_FIREMAN = SKILL_FIREMAN_EXPERT, SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER, SKILL_VEHICLE = SKILL_VEHICLE_LARGE, SKILL_JTAC = SKILL_JTAC_BEGINNER, diff --git a/code/datums/statistics/entities/panel_stats.dm b/code/datums/statistics/entities/panel_stats.dm index 44f95f2d91d9..d6e391e1731f 100644 --- a/code/datums/statistics/entities/panel_stats.dm +++ b/code/datums/statistics/entities/panel_stats.dm @@ -741,7 +741,6 @@ "total_projectiles_hit_xeno" = total_projectiles_hit_xeno, "total_slashes" = total_slashes, "total_friendly_fire_instances" = total_friendly_fire_instances, - "total_friendly_fire_kills" = total_friendly_fire_kills, "total_huggers_applied" = total_huggers_applied, "total_larva_burst" = total_larva_burst, "participants" = participants_list, diff --git a/code/datums/statistics/entities/round_stats.dm b/code/datums/statistics/entities/round_stats.dm index ec6aa4ac5bdc..0e1fb6e387db 100644 --- a/code/datums/statistics/entities/round_stats.dm +++ b/code/datums/statistics/entities/round_stats.dm @@ -20,7 +20,6 @@ var/total_projectiles_hit_human = 0 var/total_projectiles_hit_xeno = 0 var/total_friendly_fire_instances = 0 - var/total_friendly_fire_kills = 0 var/total_slashes = 0 // untracked data @@ -360,7 +359,6 @@ stats += "Total shots fired: [total_projectiles_fired]\n" stats += "Total friendly fire instances: [total_friendly_fire_instances]\n" - stats += "Total friendly fire kills: [total_friendly_fire_kills]\n" stats += "Marines remaining: [end_of_round_marines]\n" stats += "Xenos remaining: [end_of_round_xenos]\n" diff --git a/code/datums/supply_packs/operations.dm b/code/datums/supply_packs/operations.dm index cc4408659d09..610503d6c25d 100644 --- a/code/datums/supply_packs/operations.dm +++ b/code/datums/supply_packs/operations.dm @@ -101,6 +101,14 @@ group = "Operations" iteration_needed = null +/datum/supply_packs/technuclearbomb + name = "Intel Operational Nuke" + cost = 0 + containertype = /obj/structure/machinery/nuclearbomb/tech + buyable = 0 + group = "Operations" + iteration_needed = null + /datum/supply_packs/spec_kits name = "Weapons Specialist Kits" contains = list( diff --git a/code/defines/procs/announcement.dm b/code/defines/procs/announcement.dm index 5ee8c573d0e3..323fb526d527 100644 --- a/code/defines/procs/announcement.dm +++ b/code/defines/procs/announcement.dm @@ -30,7 +30,7 @@ //general marine announcement -/proc/marine_announcement(message, title = COMMAND_ANNOUNCE, sound_to_play = sound('sound/misc/notice2.ogg'), faction_to_display = FACTION_MARINE, add_PMCs = TRUE, signature) +/proc/marine_announcement(message, title = COMMAND_ANNOUNCE, sound_to_play = sound('sound/misc/notice2.ogg'), faction_to_display = FACTION_MARINE, add_PMCs = TRUE, signature, logging = ARES_LOG_MAIN) var/list/targets = GLOB.human_mob_list + GLOB.dead_mob_list if(faction_to_display == FACTION_MARINE) for(var/mob/M in targets) @@ -45,6 +45,14 @@ if((H.faction != faction_to_display && !add_PMCs) || (H.faction != faction_to_display && add_PMCs && !(H.faction in FACTION_LIST_WY)) && !(faction_to_display in H.faction_group)) //faction checks targets.Remove(H) + var/datum/ares_link/link = GLOB.ares_link + if(link.interface && !(link.interface.inoperable())) + switch(logging) + if(ARES_LOG_MAIN) + link.log_ares_announcement(title, message) + if(ARES_LOG_SECURITY) + link.log_ares_security(title, message) + else if(faction_to_display == "Everyone (-Yautja)") for(var/mob/M in targets) if(isobserver(M)) //observers see everything @@ -82,7 +90,7 @@ announcement_helper(message, title, targets, sound_to_play) //AI announcement that uses talking into comms -/proc/ai_announcement(message, sound_to_play = sound('sound/misc/interference.ogg')) +/proc/ai_announcement(message, sound_to_play = sound('sound/misc/interference.ogg'), logging = ARES_LOG_MAIN) for(var/mob/M in (GLOB.human_mob_list + GLOB.dead_mob_list)) if(isobserver(M) || ishuman(M) && is_mainship_level(M.z)) playsound_client(M.client, sound_to_play, M, vol = 45) @@ -90,6 +98,14 @@ for(var/mob/living/silicon/decoy/ship_ai/AI in ai_mob_list) INVOKE_ASYNC(AI, TYPE_PROC_REF(/mob/living/silicon/decoy/ship_ai, say), message) + var/datum/ares_link/link = GLOB.ares_link + if(link.interface && !(link.interface.inoperable())) + switch(logging) + if(ARES_LOG_MAIN) + link.log_ares_announcement("[MAIN_AI_SYSTEM] Comms Update", message) + if(ARES_LOG_SECURITY) + link.log_ares_security("[MAIN_AI_SYSTEM] Security Update", message) + /proc/ai_silent_announcement(message, channel_prefix, bypass_cooldown = FALSE) if(!message) return @@ -119,10 +135,14 @@ if(!isnull(signature)) message += "

Signed by,
[signature]
" + var/datum/ares_link/link = GLOB.ares_link + if(link.interface && !(link.interface.inoperable())) + link.log_ares_announcement(title, message) announcement_helper(message, title, targets, sound_to_play) + //Subtype of AI shipside announcement for "All Hands On Deck" alerts (COs and SEAs joining the game) -/proc/all_hands_on_deck(message, title = MAIN_AI_SYSTEM, sound_to_play = sound('sound/misc/sound_misc_boatswain.ogg'), signature) +/proc/all_hands_on_deck(message, title = MAIN_AI_SYSTEM, sound_to_play = sound('sound/misc/sound_misc_boatswain.ogg')) var/list/targets = GLOB.human_mob_list + GLOB.dead_mob_list for(var/mob/T in targets) if(isobserver(T)) @@ -130,6 +150,10 @@ if(!ishuman(T) || isyautja(T) || !is_mainship_level(T.z)) targets.Remove(T) + var/datum/ares_link/link = GLOB.ares_link + if(link.interface && !(link.interface.inoperable())) + link.log_ares_announcement("[title] Shipwide Update", message) + announcement_helper(message, title, targets, sound_to_play) //the announcement proc that handles announcing for each mob in targets list diff --git a/code/game/area/almayer.dm b/code/game/area/almayer.dm index a23f84323301..d19cbd3a6dec 100644 --- a/code/game/area/almayer.dm +++ b/code/game/area/almayer.dm @@ -77,17 +77,20 @@ fake_zlevel = 1 // upperdeck soundscape_playlist = SCAPE_PL_ARES soundscape_interval = 120 - flags_area = AREA_NOTUNNEL + flags_area = AREA_NOTUNNEL|AREA_UNWEEDABLE + can_build_special = FALSE + is_resin_allowed = FALSE + resin_construction_allowed = FALSE /area/almayer/command/securestorage name = "\improper Secure Storage" icon_state = "corporatespace" - fake_zlevel = 1 // upperdeck + fake_zlevel = 2 // lowerdeck /area/almayer/command/computerlab name = "\improper Computer Lab" icon_state = "ceroom" - fake_zlevel = 1 // upperdeck + fake_zlevel = 2 // lowerdeck /area/almayer/command/telecomms name = "\improper Telecommunications" @@ -181,6 +184,11 @@ icon_state = "astronavigation" fake_zlevel = 2 // lowerdeck +/area/almayer/shipboard/panic + name = "\improper Hangar Panic Room" + icon_state = "brig" + fake_zlevel = 2 // lowerdeck + /area/almayer/shipboard/starboard_missiles name = "\improper Missile Tubes Starboard" icon_state = "starboardmissile" diff --git a/code/game/bioscans.dm b/code/game/bioscans.dm index 474786e1ffae..5f07b307751a 100644 --- a/code/game/bioscans.dm +++ b/code/game/bioscans.dm @@ -94,45 +94,63 @@ GLOBAL_DATUM_INIT(bioscan_data, /datum/bioscan_data, new) var/marine_planet_location_string = "[marine_planet_location ? ", including one in [marine_planet_location]." : "."]" var/marine_ship_location_string = "[marine_ship_location ? ", including one in [marine_ship_location]." : "."]" + var/ghost_scan = SPAN_ALERT("[xenos_on_planet] xenos on planet, with [larva] larva.\n[xenos_on_ship] xenos on the ship.\n[marines_on_planet] humans on the planet.\n[marines_on_ship] humans on the ship.") + var/yautja_scan = SPAN_ALERT("[xenos_on_planet] serpents present in the hunting ground[xeno_planet_location_string], with [larva] larva.\n[xenos_on_ship] serpents present on the human ship[xeno_ship_location_string]\n[marines_on_planet] humans present in the hunting ground[marine_planet_location_string]\n[marines_on_ship] humans present on the human ship[marine_ship_location_string]") + log_game("BIOSCAN: A Yautja/Ghost bioscan has completed. [ghost_scan]") + //Announce the numbers to Yautja, they have good scanners for(var/mob/living/carbon/human/yautja as anything in GLOB.yautja_mob_list) to_chat(yautja, "

Bioscan complete

") - to_chat(yautja, SPAN_ALERT("[xenos_on_planet] serpents present in the hunting ground[xeno_planet_location_string], with [larva] larva.\n[xenos_on_ship] serpents present on the human ship[xeno_ship_location_string]\n[marines_on_planet] humans present in the hunting ground[marine_planet_location_string]\n[marines_on_ship] humans present on the human ship[marine_ship_location_string]")) + to_chat(yautja, yautja_scan) //Let the ghosts know what's up, they also get good numbers for(var/mob/dead/observer/ghost as anything in GLOB.observer_list) to_chat(ghost, "

Bioscan complete

") - to_chat(ghost, SPAN_ALERT("[xenos_on_planet] xenos on planet, with [larva] larva.\n[xenos_on_ship] xenos on the ship.\n[marines_on_planet] humans on the planet.\n[marines_on_ship] humans on the ship.")) + to_chat(ghost, ghost_scan) /// This will do something after Project ARES. /datum/bioscan_data/proc/can_ares_bioscan() - return TRUE + var/datum/ares_link/link = GLOB.ares_link + if(!istype(link)) + return FALSE + if(link.p_bioscan && !link.p_bioscan.inoperable()) + return TRUE + return FALSE /// The announcement to all Humans. Slightly off for the planet and elsewhere, accurate for the ship. /datum/bioscan_data/proc/ares_bioscan(forced = FALSE, variance = 2) if(!forced && !can_ares_bioscan()) - message_admins("An ARES Bioscan has failed.") + message_admins("BIOSCAN: An ARES bioscan has failed.") return - //Adjust the randomness there so everyone gets the same thing var/fake_xenos_on_planet = max(0, xenos_on_planet + rand(-variance, variance)) - var/name = "[MAIN_AI_SYSTEM] Bioscan Status" var/input = "Bioscan complete.\n\nSensors indicate [xenos_on_ship_uncontained ? "[xenos_on_ship_uncontained]" : "no"] unknown lifeform signature[!xenos_on_ship_uncontained || xenos_on_ship_uncontained > 1 ? "s":""] present on the ship[xenos_on_ship_uncontained && xenos_ship_location ? ", including one in [xenos_ship_location]," : ""] and [fake_xenos_on_planet ? "approximately [fake_xenos_on_planet]" : "no"] signature[!fake_xenos_on_planet || fake_xenos_on_planet > 1 ? "s":""] located elsewhere[fake_xenos_on_planet && xenos_planet_location ? ", including one in [xenos_planet_location]":""]." - marine_announcement(input, name, 'sound/AI/bioscan.ogg') + + log_game("BIOSCAN: ARES bioscan completed. [input]") + + var/datum/ares_link/link = GLOB.ares_link + link.log_ares_bioscan(name, input) + if(forced || (link.p_interface && !link.p_interface.inoperable())) + marine_announcement(input, name, 'sound/AI/bioscan.ogg', logging = ARES_LOG_NONE) /// The announcement to all Xenos. Slightly off for the human ship, accurate otherwise. /datum/bioscan_data/proc/qm_bioscan(variance = 2) /// Adjust the randomness there so everyone gets the same thing var/fake_marines_on_ship = max(0, marines_on_ship + rand(-variance, variance)) + var/metalhive_hosts = "[fake_marines_on_ship ? "approximately [fake_marines_on_ship]":"no"]" + var/plural = "[!fake_marines_on_ship || fake_marines_on_ship > 1 ? "s":""]" + var/metalhive_location = "[fake_marines_on_ship && marine_ship_location?", including one in [marine_ship_location]," : ""]" + var/planet_hosts = "[marines_on_planet ? "[marines_on_planet]" : "none"]" + var/planet_location = "[marines_on_planet && marine_planet_location ? ", including one in [marine_planet_location]" : ""]" + + var/title = SPAN_XENOANNOUNCE("The Queen Mother reaches into your mind from worlds away.") + var/content = SPAN_XENOANNOUNCE("To my children and their Queen. I sense [metalhive_hosts] host[plural] in the metal hive [metalhive_location] and [planet_hosts] scattered elsewhere[planet_location].") + + log_game("BIOSCAN: Queen Mother bioscan completed. [content]") /// Shout it at everyone for(var/mob/current_mob as anything in GLOB.living_xeno_list) current_mob << sound(get_sfx("queen"), wait = 0, volume = 50) - to_chat(current_mob, SPAN_XENOANNOUNCE("The Queen Mother reaches into your mind from worlds away.")) - var/metalhive_hosts = "[fake_marines_on_ship ? "approximately [fake_marines_on_ship]":"no"]" - var/plural = "[!fake_marines_on_ship || fake_marines_on_ship > 1 ? "s":""]" - var/metalhive_location = "[fake_marines_on_ship&&marine_ship_location?", including one in [marine_ship_location],":""]" - var/planet_hosts = "[marines_on_planet ? "[marines_on_planet]" : "none"]" - var/planet_location = "[marines_on_planet && marine_planet_location ? ", including one in [marine_planet_location]" : ""]" - to_chat(current_mob, SPAN_XENOANNOUNCE("To my children and their Queen. I sense [metalhive_hosts] host[plural] in the metal hive [metalhive_location] and [planet_hosts] scattered elsewhere[planet_location].")) + to_chat(current_mob, title) + to_chat(current_mob, content) diff --git a/code/game/gamemodes/cm_initialize.dm b/code/game/gamemodes/cm_initialize.dm index 8237fc63b7e2..18b11dde030e 100644 --- a/code/game/gamemodes/cm_initialize.dm +++ b/code/game/gamemodes/cm_initialize.dm @@ -354,7 +354,7 @@ Additional game mode variables. var/datum/hive_status/hive for(var/hivenumber in GLOB.hive_datum) hive = GLOB.hive_datum[hivenumber] - if(!hive.hardcore && hive.stored_larva && (hive.hive_location || (world.time < 30 MINUTES + SSticker.round_start_time))) + if(!hive.hardcore && hive.stored_larva && (hive.hive_location || (world.time < XENO_BURIED_LARVA_TIME_LIMIT + SSticker.round_start_time))) if(SSticker.mode && (SSticker.mode.flags_round_type & MODE_RANDOM_HIVE)) available_xenos |= "any buried larva" LAZYADD(available_xenos["any buried larva"], hive) @@ -364,7 +364,27 @@ Additional game mode variables. available_xenos[larva_option] = list(hive) if(!available_xenos.len || (instant_join && !available_xenos_non_ssd.len)) - to_chat(xeno_candidate, SPAN_WARNING("There aren't any available xenomorphs or burrowed larvae. You can try getting spawned as a chestburster larva by toggling your Xenomorph candidacy in Preferences -> Toggle SpecialRole Candidacy.")) + if(!xeno_candidate.client || !xeno_candidate.client.prefs || !(xeno_candidate.client.prefs.be_special & BE_ALIEN_AFTER_DEATH)) + to_chat(xeno_candidate, SPAN_WARNING("There aren't any available xenomorphs or burrowed larvae. You can try getting spawned as a chestburster larva by toggling your Xenomorph candidacy in Preferences -> Toggle SpecialRole Candidacy.")) + return FALSE + to_chat(xeno_candidate, SPAN_WARNING("There aren't any available xenomorphs or burrowed larvae.")) + + // Give the player a cached message of their queue status if they are an observer + var/mob/dead/observer/candidate_observer = xeno_candidate + if(istype(candidate_observer)) + if(candidate_observer.larva_queue_cached_message) + to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message) + return FALSE + + // No cache, lets check now then + message_alien_candidates(get_alien_candidates(), dequeued = 0, cache_only = TRUE) + if(candidate_observer.larva_queue_cached_message) + to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message) + return FALSE + + // We aren't in queue yet, lets teach them about the queue then + candidate_observer.larva_queue_cached_message = SPAN_XENONOTICE("You are currently awaiting assignment in the larva queue. The ordering is based on your time of death or the time you joined. When you have been dead long enough and are not inactive, you will periodically receive messages where you are in the queue relative to other currently valid xeno candidates. Your current position will shift as others change their preferences or go inactive, but your relative position compared to all observers is the same. Note: Playing as a facehugger or in the thunderdome will not alter your time of death. This means you won't lose your relative place in queue if you step away, disconnect, play as a facehugger, or play in the thunderdome.") + to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message) return FALSE var/mob/living/carbon/xenomorph/new_xeno @@ -377,11 +397,11 @@ Additional game mode variables. if(!xeno_bypass_timer) var/deathtime = world.time - xeno_candidate.timeofdeath if(isnewplayer(xeno_candidate)) - deathtime = 2.5 MINUTES //so new players don't have to wait to latejoin as xeno in the round's first 5 mins. - if(deathtime < 2.5 MINUTES && !check_client_rights(xeno_candidate.client, R_ADMIN, FALSE)) + deathtime = XENO_JOIN_DEAD_LARVA_TIME //so new players don't have to wait to latejoin as xeno in the round's first 5 mins. + if(deathtime < XENO_JOIN_DEAD_LARVA_TIME && !check_client_rights(xeno_candidate.client, R_ADMIN, FALSE)) var/message = SPAN_WARNING("You have been dead for [DisplayTimeText(deathtime)].") to_chat(xeno_candidate, message) - to_chat(xeno_candidate, SPAN_WARNING("You must wait 2.5 minutes before rejoining the game as a buried larva!")) + to_chat(xeno_candidate, SPAN_WARNING("You must wait 2 minutes and 30 seconds before rejoining the game as a buried larva!")) return FALSE for(var/mob_name in picked_hive.banished_ckeys) @@ -393,7 +413,7 @@ Additional game mode variables. noob.close_spawn_windows() if(picked_hive.hive_location) picked_hive.hive_location.spawn_burrowed_larva(xeno_candidate) - else if((world.time < 30 MINUTES + SSticker.round_start_time)) + else if((world.time < XENO_BURIED_LARVA_TIME_LIMIT + SSticker.round_start_time)) picked_hive.do_buried_larva_spawn(xeno_candidate) else to_chat(xeno_candidate, SPAN_WARNING("Seems like something went wrong. Try again?")) @@ -417,8 +437,8 @@ Additional game mode variables. if(!xeno_bypass_timer) var/deathtime = world.time - xeno_candidate.timeofdeath if(istype(xeno_candidate, /mob/new_player)) - deathtime = 5 MINUTES //so new players don't have to wait to latejoin as xeno in the round's first 5 mins. - if(deathtime < 5 MINUTES && !check_client_rights(xeno_candidate.client, R_ADMIN, FALSE)) + deathtime = XENO_JOIN_DEAD_TIME //so new players don't have to wait to latejoin as xeno in the round's first 5 mins. + if(deathtime < XENO_JOIN_DEAD_TIME && !check_client_rights(xeno_candidate.client, R_ADMIN, FALSE)) var/message = "You have been dead for [DisplayTimeText(deathtime)]." message = SPAN_WARNING("[message]") to_chat(xeno_candidate, message) diff --git a/code/game/gamemodes/colonialmarines/colonialmarines.dm b/code/game/gamemodes/colonialmarines/colonialmarines.dm index 6fae17b6aac9..65dc2666070d 100644 --- a/code/game/gamemodes/colonialmarines/colonialmarines.dm +++ b/code/game/gamemodes/colonialmarines/colonialmarines.dm @@ -272,7 +272,7 @@ continue if(groundside_humans > (groundside_xenos * GROUNDSIDE_XENO_MULTIPLIER)) - SSticker.mode.get_specific_call("Xenomorphs Groundside (Forsaken)", FALSE, FALSE) + SSticker.mode.get_specific_call("Xenomorphs Groundside (Forsaken)", FALSE, FALSE, announce_dispatch_message = FALSE) TIMER_COOLDOWN_START(src, COOLDOWN_HIJACK_GROUND_CHECK, 1 MINUTES) diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index c4a3070dea2d..55eee2e521bf 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -102,7 +102,11 @@ ///Includes restricted accesses /proc/get_all_marine_access() - return list(ACCESS_MARINE_CO) + get_main_marine_access() + return list( + ACCESS_MARINE_CO, + ACCESS_MARINE_AI, + ACCESS_MARINE_AI_TEMP, + ) + get_main_marine_access() ///All Almayer accesses other than the highly restricted ones, such as CO's office. /proc/get_main_marine_access() @@ -256,6 +260,7 @@ if(ACCESS_MARINE_SEA) return "SEA's Office" if(ACCESS_MARINE_KITCHEN) return "Kitchen" if(ACCESS_MARINE_SYNTH) return "Synthetic Storage" + if(ACCESS_MARINE_AI) return "AI Core" /proc/get_weyland_access_desc(A) switch(A) diff --git a/code/game/machinery/ARES/ARES.dm b/code/game/machinery/ARES/ARES.dm new file mode 100644 index 000000000000..f8a7351d123e --- /dev/null +++ b/code/game/machinery/ARES/ARES.dm @@ -0,0 +1,236 @@ +/obj/structure/machinery/ares + name = "ARES Machinery" + density = TRUE + anchored = TRUE + use_power = USE_POWER_IDLE + idle_power_usage = 600 + icon = 'icons/obj/structures/machinery/ares.dmi' + unslashable = TRUE + unacidable = TRUE + + var/link_id = MAIN_SHIP_DEFAULT_NAME + var/datum/ares_link/link + +/obj/structure/machinery/ares/ex_act(severity) + return + +/obj/structure/machinery/ares/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/structure/machinery/ares/Destroy() + delink() + return ..() + +/obj/structure/machinery/ares/update_icon() + ..() + icon_state = initial(icon_state) + // Broken + if(stat & BROKEN) + icon_state += "_broken" + + // Powered + else if(stat & NOPOWER) + icon_state = initial(icon_state) + icon_state += "_off" + +/// Handles linking and de-linking the ARES systems. +/obj/structure/machinery/ares/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(!new_link) + log_debug("Error: link_systems called without a link datum") + if(link && !override) + return FALSE + if(new_link.link_id == link_id) + link = new_link + log_debug("[name] linked to Ares Link [link_id]") + new_link.linked_systems += src + return TRUE + +/obj/structure/machinery/ares/proc/delink() + log_debug("[name] delinked from Ares Link [link.link_id]") + link.linked_systems -= src + link = null + +/obj/structure/machinery/ares/processor + name = "ARES Processor" + desc = "An external processor for ARES, used to process vast amounts of information." + icon_state = "processor" + +/obj/structure/machinery/ares/processor/apollo + name = "ARES Processor (APOLLO)" + desc = "The external component of ARES' APOLLO processor. Primarily responsible for coordinating Working Joes and Maintenance Drones. It definitely wasn't stolen from Seegson." + icon_state = "apollo_processor" + +/obj/structure/machinery/ares/processor/apollo/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + ..() + new_link.p_apollo = src + +/obj/structure/machinery/ares/processor/apollo/delink() + if(link && link.p_apollo == src) + link.p_apollo = null + ..() + +/obj/structure/machinery/ares/processor/interface + name = "ARES Processor (Interface)" + desc = "An external processor for ARES; this one handles core processes for interfacing with the crew, including radio transmissions and broadcasts." + icon_state = "int_processor" + +/obj/structure/machinery/ares/processor/interface/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + ..() + new_link.p_interface = src + +/obj/structure/machinery/ares/processor/interface/delink() + if(link && link.p_interface == src) + link.p_interface = null + ..() + +/obj/structure/machinery/ares/processor/bioscan + name = "ARES Processor (Bioscan)" + desc = "The external component of ARES' Bioscan systems. Without this, the USS Almayer would be incapable of running bioscans!" + icon_state = "bio_processor" + +/obj/structure/machinery/ares/processor/bioscan/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + ..() + new_link.p_bioscan = src + +/obj/structure/machinery/ares/processor/bioscan/delink() + if(link && link.p_bioscan == src) + link.p_bioscan = null + ..() + +/// Central Core +/obj/structure/machinery/ares/cpu + name = "ARES CPU" + desc = "This is ARES' central processor. Made of a casing designed to withstand nuclear blasts, the CPU also contains ARES' blackbox recorder." + icon_state = "CPU" + +/// Memory Substrate, +/obj/structure/machinery/ares/substrate + name = "ARES Substrate" + desc = "The memory substrate of ARES, containing complex protocols and information. Limited capabilities can operate on substrate alone, without the main ARES Unit operational." + icon_state = "substrate" + +// #################### ARES Interface Console ##################### +/obj/structure/machinery/computer/ares_console + name = "ARES Interface" + desc = "A console built to interface with ARES, allowing for 1:1 communication." + icon = 'icons/obj/structures/machinery/ares.dmi' + icon_state = "console" + exproof = TRUE + + var/current_menu = "login" + var/last_menu = "" + + var/authentication = ARES_ACCESS_BASIC + + /// The last person to login. + var/last_login + /// The person pretending to be last_login + var/sudo_holder + /// A record of who logged in and when. + var/list/access_list = list() + + /// The ID used to link all devices. + var/link_id = MAIN_SHIP_DEFAULT_NAME + var/datum/ares_link/link + + /// The current deleted chat log of 1:1 conversations being read. + var/list/deleted_1to1 = list() + + /// Holds all (/datum/ares_record/announcement)s and (/datum/ares_record/security/security_alert)s + var/list/records_announcement = list() + /// Holds all (/datum/ares_record/bioscan)s + var/list/records_bioscan = list() + /// Holds all (/datum/ares_record/bombardment)s + var/list/records_bombardment = list() + /// Holds all (/datum/ares_record/deletion)s + var/list/records_deletion = list() + /// Holds all (/datum/ares_record/talk_log)s + var/list/records_talking = list() + /// Holds all (/datum/ares_record/requisition_log)s + var/list/records_asrs = list() + /// Holds all (/datum/ares_record/security)s and (/datum/ares_record/antiair)s + var/list/records_security = list() + /// Is nuke request usable or not? (Nuke request is not currently coded to work.) + var/nuke_available = FALSE + + + COOLDOWN_DECLARE(ares_distress_cooldown) + COOLDOWN_DECLARE(ares_nuclear_cooldown) + +/obj/structure/machinery/computer/ares_console/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(link && !override) + return FALSE + if(new_link.link_id == link_id) + new_link.interface = src + link = new_link + log_debug("[name] linked to Ares Link [link_id]") + new_link.linked_systems += src + return TRUE + +/obj/structure/machinery/computer/ares_console/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/structure/machinery/computer/ares_console/proc/delink() + if(link && link.interface == src) + link.interface = null + link.linked_systems -= src + link = null + +/obj/structure/machinery/computer/ares_console/Destroy() + delink() + return ..() + +// #################### Working Joe Ticket Console ##################### +/obj/structure/machinery/computer/working_joe + name = "APOLLO Maintenance Controller" + desc = "A console built to facilitate Working Joes and their operation, allowing for simple allocation of resources." + icon = 'icons/obj/structures/machinery/ares.dmi' + icon_state = "console" + exproof = TRUE + + /// The ID used to link all devices. + var/link_id = MAIN_SHIP_DEFAULT_NAME + var/datum/ares_link/link + var/obj/structure/machinery/ares/processor/interface/processor + + var/current_menu = "login" + var/last_menu = "" + + var/authentication = ARES_ACCESS_BASIC + /// The last person to login. + var/last_login + /// A record of who logged in and when. + var/list/login_list = list() + + + /// If this is used to create AI Core access tickets + var/ticket_console = FALSE + var/obj/item/card/id/authenticator_id + var/ticket_authenticated = FALSE + var/obj/item/card/id/target_id + +/obj/structure/machinery/computer/working_joe/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(link && !override) + return FALSE + if(new_link.link_id == link_id) + new_link.ticket_computers += src + link = new_link + log_debug("[name] linked to Ares Link [link_id]") + new_link.linked_systems += src + return TRUE + +/obj/structure/machinery/computer/working_joe/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/structure/machinery/computer/working_joe/proc/delink() + if(link) + link.ticket_computers -= src + link.linked_systems -= src + link = null + +/obj/structure/machinery/computer/working_joe/Destroy() + delink() + return ..() diff --git a/code/game/machinery/ARES/ARES_procs.dm b/code/game/machinery/ARES/ARES_procs.dm new file mode 100644 index 000000000000..79c49818595c --- /dev/null +++ b/code/game/machinery/ARES/ARES_procs.dm @@ -0,0 +1,815 @@ +GLOBAL_DATUM_INIT(ares_link, /datum/ares_link, new) + +/datum/ares_link + var/link_id = MAIN_SHIP_DEFAULT_NAME + /// All motion triggers for the link + var/list/linked_alerts = list() + /// All machinery for the link + var/list/linked_systems = list() + var/obj/structure/machinery/ares/processor/interface/p_interface + var/obj/structure/machinery/ares/processor/apollo/p_apollo + var/obj/structure/machinery/ares/processor/bioscan/p_bioscan + var/obj/structure/machinery/computer/ares_console/interface + var/list/obj/structure/machinery/computer/working_joe/ticket_computers = list() + + /// The chat log of the apollo link. Timestamped. + var/list/apollo_log = list() + + /// Working Joe stuff + var/list/tickets_maintenance = list() + var/list/tickets_access = list() + +/datum/ares_link/Destroy() + for(var/obj/structure/machinery/ares/link in linked_systems) + link.delink() + for(var/obj/structure/machinery/computer/ares_console/interface in linked_systems) + interface.delink() + for(var/obj/effect/step_trigger/ares_alert/alert in linked_alerts) + alert.delink() + ..() + + +// ------ ARES Logging Procs ------ // +/proc/log_ares_apollo(speaker, message) + if(!speaker) + speaker = "Unknown" + var/datum/ares_link/link = GLOB.ares_link + if(!link.p_apollo || link.p_apollo.inoperable()) + return + if(!link.p_interface || link.p_interface.inoperable()) + return + link.apollo_log.Add("[worldtime2text()]: [speaker], '[message]'") + +/datum/ares_link/proc/log_ares_bioscan(title, input) + if(!p_bioscan || p_bioscan.inoperable() || !interface) + return FALSE + interface.records_bioscan.Add(new /datum/ares_record/bioscan(title, input)) + +/datum/ares_link/proc/log_ares_bombardment(mob/living/user, ob_name, coordinates) + interface.records_bombardment.Add(new /datum/ares_record/bombardment(ob_name, "Bombardment fired at [coordinates].", user)) + +/datum/ares_link/proc/log_ares_announcement(title, message) + interface.records_announcement.Add(new /datum/ares_record/announcement(title, message)) + +/datum/ares_link/proc/log_ares_antiair(mob/living/user, details) + interface.records_security.Add(new /datum/ares_record/antiair(details, user)) + +/datum/ares_link/proc/log_ares_requisition(source, details, mob/living/user) + interface.records_asrs.Add(new /datum/ares_record/requisition_log(source, details, user)) + +/datum/ares_link/proc/log_ares_security(title, details) + interface.records_security.Add(new /datum/ares_record/security(title, details)) +// ------ End ARES Logging Procs ------ // + +// ------ ARES Interface Procs ------ // +/obj/structure/machinery/computer/proc/get_ares_access(obj/item/card/id/card) + if(ACCESS_ARES_DEBUG in card.access) + return ARES_ACCESS_DEBUG + switch(card.assignment) + if(JOB_WORKING_JOE) + return ARES_ACCESS_JOE + if(JOB_CHIEF_ENGINEER) + return ARES_ACCESS_CE + if(JOB_SYNTH) + return ARES_ACCESS_SYNTH + if(card.paygrade in GLOB.wy_paygrades) + return ARES_ACCESS_WY_COMMAND + if(card.paygrade in GLOB.highcom_paygrades) + return ARES_ACCESS_HIGH + if(card.paygrade in GLOB.co_paygrades) + return ARES_ACCESS_CO + if(ACCESS_MARINE_SENIOR in card.access) + return ARES_ACCESS_SENIOR + if(ACCESS_WY_CORPORATE in card.access) + return ARES_ACCESS_CORPORATE + if(ACCESS_MARINE_COMMAND in card.access) + return ARES_ACCESS_COMMAND + else + return ARES_ACCESS_BASIC + +/obj/structure/machinery/computer/proc/ares_auth_to_text(access_level) + switch(access_level) + if(ARES_ACCESS_BASIC)//0 + return "Authorized" + if(ARES_ACCESS_COMMAND)//1 + return "[MAIN_SHIP_NAME] Command" + if(ARES_ACCESS_JOE)//2 + return "Working Joe" + if(ARES_ACCESS_CORPORATE)//3 + return "Weyland-Yutani" + if(ARES_ACCESS_SENIOR)//4 + return "[MAIN_SHIP_NAME] Senior Command" + if(ARES_ACCESS_CE)//5 + return "Chief Engineer" + if(ARES_ACCESS_SYNTH)//6 + return "USCM Synthetic" + if(ARES_ACCESS_CO)//7 + return "[MAIN_SHIP_NAME] Commanding Officer" + if(ARES_ACCESS_HIGH)//8 + return "USCM High Command" + if(ARES_ACCESS_WY_COMMAND)//9 + return "Weyland-Yutani Directorate" + if(ARES_ACCESS_DEBUG)//10 + return "AI Service Technician" + + +/obj/structure/machinery/computer/ares_console/proc/message_ares(text, mob/Sender, ref) + var/msg = SPAN_STAFF_IC("ARES: [key_name(Sender, 1)] [ARES_MARK(Sender)] [ADMIN_PP(Sender)] [ADMIN_VV(Sender)] [ADMIN_SM(Sender)] [ADMIN_JMP_USER(Sender)] [ARES_REPLY(Sender, ref)]: [text]") + var/datum/ares_record/talk_log/conversation = locate(ref) + conversation.conversation += "[last_login] at [worldtime2text()], '[text]'" + for(var/client/admin in GLOB.admins) + if((R_ADMIN|R_MOD) & admin.admin_holder.rights) + to_chat(admin, msg) + if(admin.prefs.toggles_sound & SOUND_ARES_MESSAGE) + playsound_client(admin, 'sound/machines/chime.ogg', vol = 25) + log_say("[key_name(Sender)] sent '[text]' to ARES 1:1.") + +/obj/structure/machinery/computer/ares_console/proc/response_from_ares(text, ref) + var/datum/ares_record/talk_log/conversation = locate(ref) + conversation.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], '[text]'" +// ------ End ARES Interface Procs ------ // + +// ------ ARES Interface UI ------ // + +/obj/structure/machinery/computer/ares_console/attack_hand(mob/user as mob) + if(..() || !allowed(usr) || inoperable()) + return FALSE + + tgui_interact(user) + return TRUE + +/obj/structure/machinery/computer/ares_console/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AresInterface", name) + ui.open() + +/obj/structure/machinery/computer/ares_console/ui_data(mob/user) + var/list/data = list() + + data["current_menu"] = current_menu + data["last_page"] = last_menu + + data["logged_in"] = last_login + data["sudo"] = sudo_holder ? TRUE : FALSE + + data["access_text"] = "[sudo_holder ? "(SUDO)," : ""] access level [authentication], [ares_auth_to_text(authentication)]." + data["access_level"] = authentication + + data["alert_level"] = security_level + data["evac_status"] = EvacuationAuthority.evac_status + data["worldtime"] = world.time + + data["access_log"] = list() + data["access_log"] += access_list + data["apollo_log"] = list() + data["apollo_log"] += link.apollo_log + + data["deleted_conversation"] = list() + data["deleted_conversation"] += deleted_1to1 + + data["distresstime"] = ares_distress_cooldown + data["distresstimelock"] = DISTRESS_TIME_LOCK + data["mission_failed"] = SSticker.mode.is_in_endgame + data["nuketimelock"] = NUCLEAR_TIME_LOCK + data["nuke_available"] = nuke_available + + var/list/logged_announcements = list() + for(var/datum/ares_record/announcement/broadcast as anything in records_announcement) + var/list/current_broadcast = list() + current_broadcast["time"] = broadcast.time + current_broadcast["title"] = broadcast.title + current_broadcast["details"] = broadcast.details + current_broadcast["ref"] = "\ref[broadcast]" + logged_announcements += list(current_broadcast) + data["records_announcement"] = logged_announcements + + var/list/logged_alerts = list() + for(var/datum/ares_record/security/security_alert as anything in records_announcement) + if(!istype(security_alert)) + continue + var/list/current_alert = list() + current_alert["time"] = security_alert.time + current_alert["title"] = security_alert.title + current_alert["details"] = security_alert.details + current_alert["ref"] = "\ref[security_alert]" + logged_alerts += list(current_alert) + data["records_security"] = logged_alerts + + var/list/logged_bioscans = list() + for(var/datum/ares_record/bioscan/scan as anything in records_bioscan) + var/list/current_scan = list() + current_scan["time"] = scan.time + current_scan["title"] = scan.title + current_scan["details"] = scan.details + current_scan["ref"] = "\ref[scan]" + logged_bioscans += list(current_scan) + data["records_bioscan"] = logged_bioscans + + var/list/logged_bombs = list() + for(var/datum/ares_record/bombardment/bomb as anything in records_bombardment) + var/list/current_bomb = list() + current_bomb["time"] = bomb.time + current_bomb["title"] = bomb.title + current_bomb["details"] = bomb.details + current_bomb["user"] = bomb.user + current_bomb["ref"] = "\ref[bomb]" + logged_bombs += list(current_bomb) + data["records_bombardment"] = logged_bombs + + var/list/logged_deletes = list() + for(var/datum/ares_record/deletion/deleted as anything in records_deletion) + if(!istype(deleted)) + continue + var/list/current_delete = list() + current_delete["time"] = deleted.time + current_delete["title"] = deleted.title + current_delete["details"] = deleted.details + current_delete["user"] = deleted.user + current_delete["ref"] = "\ref[deleted]" + logged_deletes += list(current_delete) + data["records_deletion"] = logged_deletes + + var/list/logged_discussions = list() + for(var/datum/ares_record/deleted_talk/deleted_convo as anything in records_deletion) + if(!istype(deleted_convo)) + continue + var/list/deleted_disc = list() + deleted_disc["time"] = deleted_convo.time + deleted_disc["title"] = deleted_convo.title + deleted_disc["ref"] = "\ref[deleted_convo]" + logged_discussions += list(deleted_disc) + data["deleted_discussions"] = logged_discussions + + var/list/logged_adjustments = list() + for(var/datum/ares_record/antiair/aa_adjustment as anything in records_security) + if(!istype(aa_adjustment)) + continue + var/list/current_adjustment = list() + current_adjustment["time"] = aa_adjustment.time + current_adjustment["details"] = aa_adjustment.details + current_adjustment["user"] = aa_adjustment.user + current_adjustment["ref"] = "\ref[aa_adjustment]" + logged_adjustments += list(current_adjustment) + data["aa_adjustments"] = logged_adjustments + + var/list/logged_orders = list() + for(var/datum/ares_record/requisition_log/req_order as anything in records_asrs) + if(!istype(req_order)) + continue + var/list/current_order = list() + current_order["time"] = req_order.time + current_order["details"] = req_order.details + current_order["title"] = req_order.title + current_order["user"] = req_order.user + current_order["ref"] = "\ref[req_order]" + logged_orders += list(current_order) + data["records_requisition"] = logged_orders + + var/list/logged_convos = list() + var/list/active_convo = list() + var/active_ref + for(var/datum/ares_record/talk_log/log as anything in records_talking) + if(!istype(log)) + continue + if(log.user == last_login) + active_convo = log.conversation + active_ref = "\ref[log]" + + var/list/current_convo = list() + current_convo["user"] = log.user + current_convo["ref"] = "\ref[log]" + current_convo["conversation"] = log.conversation + logged_convos += list(current_convo) + + data["active_convo"] = active_convo + data["active_ref"] = active_ref + data["conversations"] = logged_convos + + return data + +/obj/structure/machinery/computer/ares_console/ui_static_data(mob/user) + var/list/data = list() + + data["link_id"] = link_id + + return data + +/obj/structure/machinery/computer/ares_console/ui_status(mob/user, datum/ui_state/state) + . = ..() + if(!allowed(user)) + return UI_UPDATE + if(inoperable()) + return UI_DISABLED + +/obj/structure/machinery/computer/ares_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + playsound(src, "keyboard_alt", 15, 1) + + switch (action) + if("go_back") + if(!last_menu) + return to_chat(usr, SPAN_WARNING("Error, no previous page detected.")) + var/temp_holder = current_menu + current_menu = last_menu + last_menu = temp_holder + + if("login") + var/mob/living/carbon/human/operator = usr + var/obj/item/card/id/idcard = operator.get_active_hand() + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else if(operator.wear_id) + idcard = operator.wear_id + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else + to_chat(usr, SPAN_WARNING("You require an ID card to access this terminal!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(authentication) + access_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]." + current_menu = "main" + + if("sudo") + var/new_user = tgui_input_text(usr, "Enter Sudo Username", "Sudo User", encode = FALSE) + if(new_user) + if(new_user == sudo_holder) + last_login = sudo_holder + sudo_holder = null + return FALSE + if(new_user == last_login) + to_chat(usr, SPAN_WARNING("Already remote logged in as this user.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + sudo_holder = last_login + last_login = new_user + access_list += "[last_login] at [worldtime2text()], Sudo Access." + return TRUE + if("sudo_logout") + access_list += "[last_login] at [worldtime2text()], Sudo Logout." + last_login = sudo_holder + sudo_holder = null + return + // -- Page Changers -- // + if("logout") + last_menu = current_menu + current_menu = "login" + if(sudo_holder) + access_list += "[last_login] at [worldtime2text()], Sudo Logout." + last_login = sudo_holder + sudo_holder = null + access_list += "[last_login] logged out at [worldtime2text()]." + + if("home") + last_menu = current_menu + current_menu = "main" + if("page_1to1") + last_menu = current_menu + current_menu = "talking" + if("page_announcements") + last_menu = current_menu + current_menu = "announcements" + if("page_bioscans") + last_menu = current_menu + current_menu = "bioscans" + if("page_bombardments") + last_menu = current_menu + current_menu = "bombardments" + if("page_apollo") + last_menu = current_menu + current_menu = "apollo" + if("page_access") + last_menu = current_menu + current_menu = "access_log" + if("page_security") + last_menu = current_menu + current_menu = "security" + if("page_requisitions") + last_menu = current_menu + current_menu = "requisitions" + if("page_antiair") + last_menu = current_menu + current_menu = "antiair" + if("page_emergency") + last_menu = current_menu + current_menu = "emergency" + if("page_deleted") + last_menu = current_menu + current_menu = "delete_log" + if("page_deleted_1to1") + last_menu = current_menu + current_menu = "deleted_talks" + + // -- Delete Button -- // + if("delete_record") + var/datum/ares_record/record = locate(params["record"]) + if(record.record_name == ARES_RECORD_DELETED) + return FALSE + var/datum/ares_record/deletion/new_delete = new + var/new_details = "Error" + var/new_title = "Error" + switch(record.record_name) + if(ARES_RECORD_ANNOUNCE) + new_title = "[record.title] at [record.time]" + new_details = record.details + records_announcement -= record + if(ARES_RECORD_BIOSCAN) + new_title = "[record.title] at [record.time]" + new_details = record.details + records_bioscan -= record + if(ARES_RECORD_BOMB) + new_title = "[record.title] at [record.time]" + new_details = "[record.details] Launched by [record.user]." + records_bombardment -= record + + new_delete.details = new_details + new_delete.user = last_login + new_delete.title = new_title + + records_deletion += new_delete + + // -- 1:1 Conversation -- // + if("new_conversation") + var/datum/ares_record/talk_log/convo = new(last_login) + convo.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], 'New 1:1 link initiated. Greetings, [last_login].'" + records_talking += convo + + if("clear_conversation") + var/datum/ares_record/talk_log/conversation = locate(params["active_convo"]) + if(!istype(conversation)) + return FALSE + var/datum/ares_record/deleted_talk/deleted = new + deleted.title = conversation.title + deleted.conversation = conversation.conversation + deleted.user = conversation.user + records_deletion += deleted + records_talking -= conversation + + if("message_ares") + var/message = tgui_input_text(usr, "What do you wish to say to ARES?", "ARES Message", encode = FALSE) + if(message) + message_ares(message, usr, params["active_convo"]) + + if("read_record") + var/datum/ares_record/deleted_talk/conversation = locate(params["record"]) + deleted_1to1 = conversation.conversation + last_menu = current_menu + current_menu = "read_deleted" + + // -- Emergency Buttons -- // + if("evacuation_start") + if(security_level < SEC_LEVEL_RED) + to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY) + to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods.")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + if(!EvacuationAuthority.initiate_evacuation()) + to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + log_game("[key_name(usr)] has called for an emergency evacuation via ARES.") + message_admins("[key_name_admin(usr)] has called for an emergency evacuation via ARES.") + var/datum/ares_link/link = GLOB.ares_link + link.log_ares_security("Initiate Evacuation", "[last_login] has called for an emergency evacuation via ARES.") + . = TRUE + + if("distress") + if(!SSticker.mode) + return FALSE //Not a game mode? + if(world.time < DISTRESS_TIME_LOCK) + to_chat(usr, SPAN_WARNING("You have been here for less than six minutes... what could you possibly have done!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(!COOLDOWN_FINISHED(src, ares_distress_cooldown)) + to_chat(usr, SPAN_WARNING("The distress launcher is cooling down!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(security_level == SEC_LEVEL_DELTA) + to_chat(usr, SPAN_WARNING("The ship is already undergoing self destruct procedures!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + else if(security_level < SEC_LEVEL_RED) + to_chat(usr, SPAN_WARNING("The ship must be under red alert to launch a distress beacon!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + for(var/client/admin in GLOB.admins) + if((R_ADMIN|R_MOD) & admin.admin_holder.rights) + playsound_client(admin,'sound/effects/sos-morse-code.ogg',10) + message_admins("[key_name(usr)] has requested a Distress Beacon (via ARES)! [CC_MARK(usr)] (SEND) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") + to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM High Command.")) + COOLDOWN_START(src, ares_distress_cooldown, COOLDOWN_COMM_REQUEST) + return TRUE + + if("nuclearbomb") + if(!SSticker.mode) + return FALSE //Not a game mode? + if(world.time < NUCLEAR_TIME_LOCK) + to_chat(usr, SPAN_WARNING("It is too soon to request Nuclear Ordnance!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(!COOLDOWN_FINISHED(src, ares_nuclear_cooldown)) + to_chat(usr, SPAN_WARNING("The ordnance request frequency is garbled, wait for reset!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(security_level == SEC_LEVEL_DELTA || SSticker.mode.is_in_endgame) + to_chat(usr, SPAN_WARNING("The mission has failed catastrophically, what do you want a nuke for!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + + for(var/client/admin in GLOB.admins) + if((R_ADMIN|R_MOD) & admin.admin_holder.rights) + playsound_client(admin,'sound/effects/sos-morse-code.ogg',10) + message_admins("[key_name(usr)] has requested use of Nuclear Ordnance (via ARES)! [CC_MARK(usr)] (APPROVE) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]") + to_chat(usr, SPAN_NOTICE("A nuclear ordnance request has been sent to USCM High Command.")) + COOLDOWN_START(src, ares_nuclear_cooldown, COOLDOWN_COMM_DESTRUCT) + return TRUE +// ------ End ARES Interface UI ------ // + + +/obj/structure/machinery/computer/working_joe/get_ares_access(obj/item/card/id/card) + if(ACCESS_ARES_DEBUG in card.access) + return APOLLO_ACCESS_DEBUG + switch(card.assignment) + if(JOB_WORKING_JOE) + return APOLLO_ACCESS_JOE + if(JOB_CHIEF_ENGINEER, JOB_SYNTH, JOB_CO) + return APOLLO_ACCESS_AUTHED + if(ACCESS_MARINE_AI in card.access) + return APOLLO_ACCESS_AUTHED + if(ACCESS_MARINE_AI_TEMP in card.access) + return APOLLO_ACCESS_TEMP + if((ACCESS_MARINE_COMMAND in card.access ) || (ACCESS_MARINE_ENGINEERING in card.access) || (ACCESS_WY_CORPORATE in card.access)) + return APOLLO_ACCESS_REPORTER + else + return APOLLO_ACCESS_REQUEST + +/obj/structure/machinery/computer/working_joe/ares_auth_to_text(access_level) + switch(access_level) + if(APOLLO_ACCESS_REQUEST)//0 + return "Unauthorized Personnel" + if(APOLLO_ACCESS_REPORTER)//1 + return "Validated Incident Reporter" + if(APOLLO_ACCESS_TEMP)//2 + return "Authorized Visitor" + if(APOLLO_ACCESS_AUTHED)//3 + return "Certified Personnel" + if(APOLLO_ACCESS_JOE)//4 + return "Working Joe" + if(APOLLO_ACCESS_DEBUG)//5 + return "AI Service Technician" + +// ------ Maintenance Controller UI ------ // +/obj/structure/machinery/computer/working_joe/verb/eject_id() + set category = "Object" + set name = "Eject ID Card" + set src in oview(1) + + if(!usr || usr.stat || usr.lying) return + + if(authenticator_id) + authenticator_id.loc = get_turf(src) + if(!usr.get_active_hand() && istype(usr,/mob/living/carbon/human)) + usr.put_in_hands(authenticator_id) + if(operable()) // Powered. Console can response. + visible_message("[SPAN_BOLD("[src]")] states, \"AUTH LOGOUT: Session end confirmed.\"") + else + to_chat(usr, "You remove [authenticator_id] from [src].") + ticket_authenticated = FALSE // No card - no access + authenticator_id = null + + else if(target_id) + target_id.loc = get_turf(src) + if(!usr.get_active_hand() && istype(usr,/mob/living/carbon/human)) + usr.put_in_hands(target_id) + else + to_chat(usr, "You remove [target_id] from [src].") + target_id = null + + else + to_chat(usr, "There is nothing to remove from the console.") + return + +/obj/structure/machinery/computer/working_joe/attackby(obj/object, mob/user) + if(istype(object, /obj/item/card/id)) + if(!operable()) + to_chat(user, SPAN_NOTICE("You try to insert [object] but [src] remains silent.")) + return + var/obj/item/card/id/idcard = object + if((ACCESS_MARINE_AI in idcard.access) || (ACCESS_ARES_DEBUG in idcard.access)) + if(!authenticator_id) + if(user.drop_held_item()) + object.forceMove(src) + authenticator_id = object + authenticate(authenticator_id) + else if(!target_id) + if(user.drop_held_item()) + object.forceMove(src) + target_id = object + else + to_chat(user, "Both slots are full already. Remove a card first.") + return + else + if(!target_id) + if(user.drop_held_item()) + object.forceMove(src) + target_id = object + else + to_chat(user, "Both slots are full already. Remove a card first.") + return + else + ..() + +/obj/structure/machinery/computer/working_joe/proc/authenticate(obj/item/card/id/id_card) + if(!id_card) + visible_message("[SPAN_BOLD("[src]")] states, \"AUTH ERROR: Authenticator card is missing!\"") + return FALSE + + if((ACCESS_MARINE_AI in id_card.access) || (ACCESS_ARES_DEBUG in id_card.access)) + ticket_authenticated = TRUE + visible_message("[SPAN_BOLD("[src]")] states, \"AUTH LOGIN: Welcome, [id_card.registered_name]. Access granted.\"") + return TRUE + + visible_message("[SPAN_BOLD("[src]")] states, \"AUTH ERROR: Access denied.\"") + return FALSE + + + + +/obj/structure/machinery/computer/working_joe/attack_hand(mob/user as mob) + if(..() || !allowed(usr) || inoperable()) + return FALSE + + tgui_interact(user) + return TRUE + +/obj/structure/machinery/computer/working_joe/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "WorkingJoe", name) + ui.open() + +/obj/structure/machinery/computer/working_joe/ui_data(mob/user) + var/list/data = list() + + data["ticket_console"] = ticket_console + data["current_menu"] = current_menu + data["last_page"] = last_menu + + data["logged_in"] = last_login + + data["access_text"] = "access level [authentication], [ares_auth_to_text(authentication)]." + data["access_level"] = authentication + + data["alert_level"] = security_level + data["worldtime"] = world.time + + data["access_log"] = list() + data["access_log"] += login_list + + data["apollo_log"] = list() + data["apollo_log"] += link.apollo_log + + data["authenticated"] = ticket_authenticated + + + var/list/logged_maintenance = list() + for(var/datum/ares_ticket/maintenance/maint_ticket as anything in link.tickets_maintenance) + if(!istype(maint_ticket)) + continue + var/list/current_maint = list() + current_maint["time"] = maint_ticket.ticket_time + current_maint["title"] = maint_ticket.ticket_name + current_maint["details"] = maint_ticket.ticket_details + current_maint["status"] = maint_ticket.ticket_status + current_maint["submitter"] = maint_ticket.ticket_submitter + current_maint["assignee"] = maint_ticket.ticket_assignee + current_maint["ref"] = "\ref[maint_ticket]" + logged_maintenance += list(current_maint) + data["maintenance_tickets"] = logged_maintenance + + var/list/logged_access = list() + for(var/datum/ares_ticket/access_ticket/access_ticket as anything in link.tickets_access) + var/list/current_ticket = list() + current_ticket["time"] = access_ticket.ticket_time + current_ticket["title"] = access_ticket.ticket_name + current_ticket["details"] = access_ticket.ticket_details + current_ticket["status"] = access_ticket.ticket_status + current_ticket["submitter"] = access_ticket.ticket_submitter + current_ticket["assignee"] = access_ticket.ticket_assignee + current_ticket["ref"] = "\ref[access_ticket]" + logged_access += list(current_ticket) + data["access_tickets"] = logged_access + + + return data + +/obj/structure/machinery/computer/working_joe/ui_static_data(mob/user) + var/list/data = list() + + data["link_id"] = link_id + + return data + +/obj/structure/machinery/computer/working_joe/ui_status(mob/user, datum/ui_state/state) + . = ..() + if(!allowed(user)) + return UI_UPDATE + if(inoperable()) + return UI_DISABLED + +/obj/structure/machinery/computer/working_joe/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + var/playsound = TRUE + var/mob/living/carbon/human/operator = usr + + switch (action) + if("go_back") + if(!last_menu) + return to_chat(usr, SPAN_WARNING("Error, no previous page detected.")) + var/temp_holder = current_menu + current_menu = last_menu + last_menu = temp_holder + + if("login") + + var/obj/item/card/id/idcard = operator.get_active_hand() + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else if(operator.wear_id) + idcard = operator.wear_id + if(istype(idcard)) + authentication = get_ares_access(idcard) + last_login = idcard.registered_name + else + to_chat(usr, SPAN_WARNING("You require an ID card to access this terminal!")) + playsound(src, 'sound/machines/buzz-two.ogg', 15, 1) + return FALSE + if(authentication) + login_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]." + current_menu = "main" + + if("logout") + last_menu = current_menu + current_menu = "login" + login_list += "[last_login] logged out at [worldtime2text()]." + + if("home") + last_menu = current_menu + current_menu = "main" + if("page_logins") + last_menu = current_menu + current_menu = "login_records" + if("page_apollo") + last_menu = current_menu + current_menu = "apollo" + if("page_request") + last_menu = current_menu + current_menu = "access_requests" + if("page_returns") + last_menu = current_menu + current_menu = "access_returns" + if("page_report") + last_menu = current_menu + current_menu = "maint_reports" + if("page_tickets") + last_menu = current_menu + current_menu = "access_tickets" + if("page_maintenance") + last_menu = current_menu + current_menu = "maint_claim" + + if("new_report") + var/name = tgui_input_text(usr, "What is the type of maintenance item you wish to report?\n\nExample:\n 'Broken light in Aft Hallway.'", "Ticket Name", encode = FALSE) + if(!name) + return FALSE + var/details = tgui_input_text(usr, "What are the details for this report?", "Ticket Details", encode = FALSE) + if(!details) + return FALSE + var/confirm = tgui_alert(usr, "Please confirm the submission of your maintenance report. \n\n [name] \n\n [details] \n\n Is this correct?", "Confirmation", list("Yes", "No")) + if(confirm == "Yes") + if(link) + var/datum/ares_ticket/maintenance/maint_ticket = new(last_login, name, details) + link.tickets_maintenance += maint_ticket + log_game("ARES: Maintenance Ticket created by [key_name(operator)] as [last_login] with Header '[name]' and Details of '[details]'.") + return TRUE + return FALSE + + if(playsound) + playsound(src, "keyboard_alt", 15, 1) diff --git a/code/game/machinery/ARES/ARES_records.dm b/code/game/machinery/ARES/ARES_records.dm new file mode 100644 index 000000000000..9cb8574e58f7 --- /dev/null +++ b/code/game/machinery/ARES/ARES_records.dm @@ -0,0 +1,99 @@ +/datum/ares_record + var/record_name = "ARES Data Core" + /// World time in text format. + var/time + /// The title of the record, usually announcement title. + var/title + /// The content of the record, announcement text/bioscan info etc. + var/details + /// The name of the initiator of certain records. Who fired an OB, or who deleted something etc. + var/user + +/datum/ares_record/New(title, details) + time = worldtime2text() + src.title = title + src.details = details + +/datum/ares_record/announcement + record_name = ARES_RECORD_ANNOUNCE + +/datum/ares_record/bioscan + record_name = ARES_RECORD_BIOSCAN + +/datum/ares_record/requisition_log + record_name = ARES_RECORD_ASRS + +/datum/ares_record/requisition_log/New(title, details, user) + time = worldtime2text() + src.title = title + src.details = details + src.user = user + +/datum/ares_record/security + record_name = ARES_RECORD_SECURITY + +/datum/ares_record/antiair + record_name = ARES_RECORD_ANTIAIR + +/datum/ares_record/antiair/New(details, user) + time = worldtime2text() + src.title = "AntiAir Adjustment" + src.details = details + src.user = user + +/datum/ares_record/bombardment + record_name = ARES_RECORD_BOMB + +/datum/ares_record/bombardment/New(title, details, user) + time = worldtime2text() + src.title = title + src.details = details + src.user = user + +/datum/ares_record/deletion + record_name = ARES_RECORD_DELETED + +/datum/ares_record/deletion/New() + time = worldtime2text() + +/datum/ares_record/talk_log + record_name = "1:1 Data Log" + var/conversation = list() + +/datum/ares_record/talk_log/New(user) + src.user = user + src.title = "1:1 Log ([user])" + +/datum/ares_record/deleted_talk + record_name = ARES_RECORD_DELETED + var/conversation = list() + +/datum/ares_record/deleted_talk/New() + time = worldtime2text() + + +/datum/ares_ticket + var/ticket_type = "Root Ticket" + var/ticket_status = TICKET_PENDING + /// Name of who is handling the ticket. Derived from last login. + var/ticket_assignee + /// World time in text format. + var/ticket_time + /// Who submitted the ticket. Derived from last login. + var/ticket_submitter + /// The name of the ticket. + var/ticket_name + /// The content of the ticket, usually an explanation of what it is for. + var/ticket_details + +/datum/ares_ticket/New(user, name, details) + ticket_time = worldtime2text() + ticket_submitter = user + ticket_details = details + ticket_name = name + +/datum/ares_ticket/maintenance + ticket_type = ARES_RECORD_MAINTENANCE + +/datum/ares_ticket/access_ticket + ticket_type = ARES_RECORD_ACCESS diff --git a/code/game/machinery/ARES/ARES_step_triggers.dm b/code/game/machinery/ARES/ARES_step_triggers.dm new file mode 100644 index 000000000000..1562f1badaab --- /dev/null +++ b/code/game/machinery/ARES/ARES_step_triggers.dm @@ -0,0 +1,197 @@ +/obj/effect/step_trigger/ares_alert + name = "ARES Apollo Sensor" + layer = 5 + /// Link alerts to ARES Link + var/datum/ares_link/link + var/link_id = MAIN_SHIP_DEFAULT_NAME + /// Alert message to report unless area based. + var/alert_message = "ALERT: Unauthorized movement detected in ARES Core!" + /// Connect alerts to use same cooldowns + var/alert_id + /// Set to true if it should report area name and not specific alert. + var/area_based = FALSE + /// Cooldown duration and next time. + var/cooldown_duration = COOLDOWN_ARES_SENSOR + COOLDOWN_DECLARE(sensor_cooldown) + /// The job on a mob to enter + var/list/pass_jobs = list(JOB_WORKING_JOE, JOB_CHIEF_ENGINEER, JOB_CO) + /// The accesses on an ID card to enter + var/pass_accesses = list(ACCESS_MARINE_AI, ACCESS_ARES_DEBUG) + +/obj/effect/step_trigger/ares_alert/Crossed(mob/living/passer) + if(!COOLDOWN_FINISHED(src, sensor_cooldown))//Don't want alerts spammed. + return FALSE + if(!passer) + return FALSE + if(!(ishuman(passer) || isxeno(passer))) + return FALSE + if(passer.alpha <= 100)//Can't be seen/detected to trigger alert. + return FALSE + if(pass_jobs) + if(passer.job in pass_jobs) + return FALSE + if(isxeno(passer) && (JOB_XENOMORPH in pass_jobs)) + return FALSE + if(ishuman(passer)) + var/mob/living/carbon/human/trespasser = passer + if(pass_accesses && (trespasser.wear_id)) + for(var/tag in pass_accesses) + if(tag in trespasser.wear_id.access) + return FALSE + Trigger(passer) + return TRUE + + +/obj/effect/step_trigger/ares_alert/Initialize(mapload, ...) + link_systems(override = FALSE) + . = ..() + +/obj/effect/step_trigger/ares_alert/Destroy() + delink() + return ..() + +/obj/effect/step_trigger/ares_alert/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override) + if(link && !override) + return FALSE + if(new_link.link_id == link_id) + link = new_link + new_link.linked_alerts += src + return TRUE +/obj/effect/step_trigger/ares_alert/proc/delink() + if(link) + link.linked_alerts -= src + link = null + + +/obj/effect/step_trigger/ares_alert/Trigger(mob/living/passer) + var/broadcast_message = alert_message + if(area_based) + var/area_name = get_area_name(src, TRUE) + broadcast_message = "ALERT: Unauthorized movement detected in [area_name]!" + + var/datum/ares_link/link = GLOB.ares_link + if(link.p_apollo.inoperable()) + return FALSE + + to_chat(passer, SPAN_BOLDWARNING("You hear a soft beeping sound as you cross the threshold.")) + var/datum/language/apollo/apollo = GLOB.all_languages[LANGUAGE_APOLLO] + for(var/mob/living/silicon/decoy/ship_ai/ai in ai_mob_list) + apollo.broadcast(ai, broadcast_message) + for(var/mob/listener as anything in (GLOB.human_mob_list + GLOB.dead_mob_list)) + if(listener.hear_apollo())//Only plays sound to mobs and not observers, to reduce spam. + playsound_client(listener.client, sound('sound/misc/interference.ogg'), listener, vol = 45) + COOLDOWN_START(src, sensor_cooldown, cooldown_duration) + if(alert_id && link) + for(var/obj/effect/step_trigger/ares_alert/sensor in link.linked_alerts) + if(sensor.alert_id == src.alert_id) + COOLDOWN_START(sensor, sensor_cooldown, cooldown_duration) + return TRUE + +/obj/effect/step_trigger/ares_alert/public + pass_accesses = list(ACCESS_MARINE_AI_TEMP, ACCESS_MARINE_AI, ACCESS_ARES_DEBUG) +/obj/effect/step_trigger/ares_alert/core + alert_id = "AresCore" + pass_accesses = list(ACCESS_MARINE_AI_TEMP, ACCESS_MARINE_AI, ACCESS_ARES_DEBUG) + +/obj/effect/step_trigger/ares_alert/mainframe + alert_id = "AresMainframe" + alert_message = "ALERT: Unauthorized movement detected in ARES Mainframe!" + +/obj/effect/step_trigger/ares_alert/terminals + alert_id = "AresTerminals" + alert_message = "ALERT: Unauthorized movement detected in ARES' Operations Center!" + +/obj/effect/step_trigger/ares_alert/comms + area_based = TRUE + alert_id = "TComms" + pass_accesses = list(ACCESS_MARINE_CE) + + +/// Trigger will remove ACCESS_MARINE_AI_TEMP unless ACCESS_MARINE_AI is also present. +/obj/effect/step_trigger/ares_alert/access_control + name = "ARES Access Control Sensor" + alert_message = "HARDCODED" + alert_id = "ARES Access" + cooldown_duration = COOLDOWN_ARES_ACCESS_CONTROL + + +/obj/effect/step_trigger/ares_alert/access_control/Crossed(atom/passer as mob|obj) + if(isobserver(passer) || isxeno(passer)) + return FALSE + if(!COOLDOWN_FINISHED(src, sensor_cooldown))//Don't want alerts spammed. + return FALSE + if(!passer) + return FALSE + if(passer.alpha <= 100)//Can't be seen/detected to trigger alert. + return FALSE + var/area/pass_area = get_area(get_step(passer, passer.dir)) + if(istype(pass_area, /area/almayer/command/airoom))//Don't want it to freak out over someone /entering/ the area. Only leaving. + return FALSE + var/obj/item/card/id/idcard + var/check_contents = TRUE + if(ishuman(passer)) + var/mob/living/carbon/human/human_passer = passer + idcard = human_passer.wear_id + if(istype(idcard)) + check_contents = FALSE + else + idcard = null + + if(istype(passer, /obj/item/card/id)) + idcard = passer + check_contents = FALSE + + if(check_contents) + idcard = locate(/obj/item/card/id) in passer + if(!idcard) + for(var/obj/item/holder in passer.contents) + idcard = locate(/obj/item/card/id) in holder.contents + if(idcard) + break + if(!istype(idcard) && ismob(passer)) + Trigger(passer, failure = TRUE) + return FALSE + if(!(ACCESS_MARINE_AI_TEMP in idcard.access))//No temp access, don't care + return FALSE + if((ACCESS_MARINE_AI in idcard.access) || (ACCESS_ARES_DEBUG in idcard.access))//Permanent access prevents loss of temporary + return FALSE + Trigger(passer, idcard) + return TRUE + +/obj/effect/step_trigger/ares_alert/access_control/Trigger(atom/passer, obj/item/card/id/idcard, failure = FALSE) + var/broadcast_message = get_broadcast(passer, idcard, failure) + + var/datum/ares_link/link = GLOB.ares_link + if(link.p_apollo.inoperable()) + return FALSE + + to_chat(passer, SPAN_BOLDWARNING("You hear a harsh buzzing sound as you cross the threshold!")) + var/datum/language/apollo/apollo = GLOB.all_languages[LANGUAGE_APOLLO] + for(var/mob/living/silicon/decoy/ship_ai/ai in ai_mob_list) + apollo.broadcast(ai, broadcast_message) + for(var/mob/listener in (GLOB.human_mob_list + GLOB.dead_mob_list)) + if(listener.hear_apollo())//Only plays sound to mobs and not observers, to reduce spam. + playsound_client(listener.client, sound('sound/misc/interference.ogg'), listener, vol = 45) + if(idcard) + idcard.access -= ACCESS_MARINE_AI_TEMP + COOLDOWN_START(src, sensor_cooldown, COOLDOWN_ARES_ACCESS_CONTROL) + if(alert_id && link) + for(var/obj/effect/step_trigger/ares_alert/sensor in link.linked_alerts) + if(sensor.alert_id == src.alert_id) + COOLDOWN_START(sensor, sensor_cooldown, COOLDOWN_ARES_ACCESS_CONTROL) + return TRUE + +/obj/effect/step_trigger/ares_alert/access_control/proc/get_broadcast(atom/passer, obj/item/card/id/idcard, failure = FALSE) + if(isxeno(passer)) + return "Unidentified lifeform detected departing AI Chamber." + if(ishuman(passer)) + var/mob/living/carbon/human/human_passer = passer + if(failure) + return "CAUTION: [human_passer.name] left the AI Chamber without a locatable ID card." + return "ALERT: [human_passer.name] left the AI Chamber with a temporary access ticket. Removing access." + + if(idcard) + return "ALERT: ID Card assigned to [idcard.registered_name] left the AI Chamber with a temporary access ticket. Removing access." + + log_debug("ARES ERROR 337: Passer: '[passer]', ID: '[idcard]', F Status: '[failure]'") + return "Warning: Error 337 - Access Control Anomaly." diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 7a10a3ffa1df..6ccb0b5b18f7 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -284,7 +284,7 @@ return //Dismantle the frame. - if(istype(O, /obj/item/tool/crowbar)) + if(HAS_TRAIT(O, TRAIT_TOOL_CROWBAR)) dismantle() return diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index 1a15d40eba9c..a8735cbc06a8 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -110,6 +110,10 @@ /obj/structure/machinery/camera/autoname/almayer/containment/hidden network = list(CAMERA_NET_CONTAINMENT_HIDDEN) +/obj/structure/machinery/camera/autoname/almayer/containment/ares + name = "ares core camera" + network = list(CAMERA_NET_ALMAYER, CAMERA_NET_ARES) + //used by the landing camera dropship equipment. Do not place them right under where the dropship lands. //Should place them near each corner of your LZs. /obj/structure/machinery/camera/autoname/lz_camera diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index fd246d2d640a..bb6972a58ac3 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -51,7 +51,7 @@ to_chat(user, SPAN_NOTICE(" You screw the circuit board into place.")) state = 2 icon_state = "2" - if(istype(P, /obj/item/tool/crowbar) && circuit) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR) && circuit) playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE(" You remove the circuit board.")) state = 1 @@ -121,7 +121,7 @@ to_chat(usr, "Added [mmi].") icon_state = "3b" - if(istype(P, /obj/item/tool/crowbar) && brain) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR) && brain) playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE(" You remove the brain.")) brain.forceMove(loc) @@ -129,7 +129,7 @@ icon_state = "3" if(4) - if(istype(P, /obj/item/tool/crowbar)) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR)) playsound(loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE(" You remove the glass panel.")) state = 3 diff --git a/code/game/machinery/computer/almayer_control.dm b/code/game/machinery/computer/almayer_control.dm index ec4abc68511b..b2a931224464 100644 --- a/code/game/machinery/computer/almayer_control.dm +++ b/code/game/machinery/computer/almayer_control.dm @@ -118,7 +118,7 @@ return FALSE usr.set_interaction(src) - + var/datum/ares_link/link = GLOB.ares_link switch(href_list["operation"]) if("main") state = STATE_DEFAULT @@ -163,6 +163,7 @@ log_game("[key_name(usr)] has called for an emergency evacuation.") message_admins("[key_name_admin(usr)] has called for an emergency evacuation.") + link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") return TRUE state = STATE_EVACUATION @@ -182,6 +183,7 @@ log_game("[key_name(usr)] has canceled the emergency evacuation.") message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.") + link.log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.") return TRUE state = STATE_EVACUATION_CANCEL diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index bd42b31ea573..07c960807205 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -52,7 +52,7 @@ to_chat(user, SPAN_NOTICE(" You screw the circuit board into place.")) src.state = 2 src.icon_state = "2" - if(istype(P, /obj/item/tool/crowbar) && circuit) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR) && circuit) playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE(" You remove the circuit board.")) src.state = 1 @@ -99,7 +99,7 @@ src.state = 4 src.icon_state = "4" if(4) - if(istype(P, /obj/item/tool/crowbar)) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR)) playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) to_chat(user, SPAN_NOTICE(" You remove the glass panel.")) src.state = 3 diff --git a/code/game/machinery/computer/camera_console.dm b/code/game/machinery/computer/camera_console.dm index d7fe2ed83e02..d4feca457f4a 100644 --- a/code/game/machinery/computer/camera_console.dm +++ b/code/game/machinery/computer/camera_console.dm @@ -318,6 +318,10 @@ name = "Containment Cameras" network = list(CAMERA_NET_CONTAINMENT) +/obj/structure/machinery/computer/cameras/almayer/ares + name = "ARES Core Cameras" + network = list(CAMERA_NET_ARES) + /obj/structure/machinery/computer/cameras/almayer/vehicle name = "Ship Security Cameras" network = list(CAMERA_NET_ALMAYER, CAMERA_NET_VEHICLE) diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 2a7b5017d1ed..edc39faf3ddc 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -65,6 +65,7 @@ if(..()) return FALSE usr.set_interaction(src) + var/datum/ares_link/link = GLOB.ares_link switch(href_list["operation"]) if("mapview") tacmap.tgui_interact(usr) @@ -148,6 +149,7 @@ log_game("[key_name(usr)] has called for an emergency evacuation.") message_admins("[key_name_admin(usr)] has called for an emergency evacuation.") + link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") return TRUE state = STATE_EVACUATION @@ -167,6 +169,7 @@ log_game("[key_name(usr)] has canceled the emergency evacuation.") message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.") + link.log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.") return TRUE state = STATE_EVACUATION_CANCEL diff --git a/code/game/machinery/computer/groundside_operations.dm b/code/game/machinery/computer/groundside_operations.dm index 6cefa28a2c95..9856ae8f970e 100644 --- a/code/game/machinery/computer/groundside_operations.dm +++ b/code/game/machinery/computer/groundside_operations.dm @@ -286,7 +286,7 @@ usr.RegisterSignal(cam, COMSIG_PARENT_QDELETING, TYPE_PROC_REF(/mob, reset_observer_view_on_deletion)) if("activate_echo") - var/reason = input(usr, "What is the purpose of Echo Squad?", "Activation Reason") + var/reason = strip_html(input(usr, "What is the purpose of Echo Squad?", "Activation Reason")) if(!reason) return if(alert(usr, "Confirm activation of Echo Squad for [reason]", "Confirm Activation", "Yes", "No") != "Yes") return diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 7d82c5bd9a75..3c92bd33a681 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -469,9 +469,10 @@ if(!record) return playsound(src.loc, 'sound/machines/fax.ogg', 15, 1) sleep(40) + var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper) var/obj/item/paper/P = new /obj/item/paper( src.loc ) P.name = text("Scan: [], []",record.fields["name"],worldtime2text()) - P.info += text("

Official Weyland-Yutani Document
Scan Record

[]

\n
",record.fields["name"]) + P.info += text("

Official Weyland-Yutani Document
Scan Record

[]

\n
",record.fields["name"]) for(var/datum/data/record/R as anything in GLOB.data_core.medical) if (R.fields["name"] == record.fields["name"]) if(R.fields["last_scan_time"] && R.fields["last_scan_result"]) diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 0288b7eb2426..357ef48fff37 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -114,7 +114,7 @@ A.amount = 5 if(CONSTRUCTION_STATE_FINISHED) - if(istype(P, /obj/item/tool/crowbar)) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR)) if(!skillcheck(user, SKILL_ENGINEER, required_dismantle_skill)) to_chat(user, SPAN_WARNING("You are not trained to dismantle machines...")) return diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm index 435976668577..afcc9686cff5 100644 --- a/code/game/machinery/cryo.dm +++ b/code/game/machinery/cryo.dm @@ -2,6 +2,7 @@ /obj/structure/machinery/cryo_cell name = "cryo cell" + desc = "A donation from the old A.W. project, using cryogenic technology. It slowly heals whoever is inside the tube." icon = 'icons/obj/structures/machinery/cryogenics2.dmi' icon_state = "cell" density = FALSE diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm index 40bdd68b3b34..8be8609d6008 100644 --- a/code/game/machinery/door_control.dm +++ b/code/game/machinery/door_control.dm @@ -52,6 +52,11 @@ /obj/structure/machinery/door_control/attackby(obj/item/W, mob/user as mob) return src.attack_hand(user) +/obj/structure/machinery/door_control/ex_act(severity) + if(indestructible) + return FALSE + ..() + /obj/structure/machinery/door_control/proc/handle_dropship(ship_id) var/obj/docking_port/mobile/marine_dropship/shuttle = SSshuttle.getShuttle(ship_id) if (!istype(shuttle)) diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm index 972ce6b7570e..da6137e5e8cb 100644 --- a/code/game/machinery/doors/poddoor.dm +++ b/code/game/machinery/doors/poddoor.dm @@ -287,10 +287,13 @@ /obj/structure/machinery/door/poddoor/almayer/blended icon_state = "almayer_pdoor1" base_icon_state = "almayer_pdoor" - +/obj/structure/machinery/door/poddoor/almayer/blended/open + density = FALSE /obj/structure/machinery/door/poddoor/almayer/blended/white icon_state = "w_almayer_pdoor1" base_icon_state = "w_almayer_pdoor" +/obj/structure/machinery/door/poddoor/almayer/blended/white/open + density = FALSE /obj/structure/machinery/door/poddoor/almayer/Initialize() . = ..() diff --git a/code/game/machinery/doors/railing.dm b/code/game/machinery/doors/railing.dm index 145a5d8191dc..8449d5d52256 100644 --- a/code/game/machinery/doors/railing.dm +++ b/code/game/machinery/doors/railing.dm @@ -19,7 +19,8 @@ . = ..() if(dir == SOUTH) closed_layer = ABOVE_MOB_LAYER - layer = closed_layer + if(density)//Allows preset-open to work + layer = closed_layer SetOpacity(initial(opacity)) @@ -63,3 +64,6 @@ addtimer(VARSET_CALLBACK(src, operating, FALSE), 1.2 SECONDS) return TRUE + +/obj/structure/machinery/door/poddoor/railing/open + density = FALSE diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 6d96daf3152f..e9006a9f2fb4 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -167,7 +167,7 @@ return //If it's emagged, crowbar can pry electronics out. - if (src.operating == -1 && istype(I, /obj/item/tool/crowbar)) + if (src.operating == -1 && HAS_TRAIT(I, TRAIT_TOOL_CROWBAR)) playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) user.visible_message("[user] removes the electronics from the windoor.", "You start to remove electronics from the windoor.") if (do_after(user, 40, INTERRUPT_ALL, BUSY_ICON_BUILD)) diff --git a/code/game/machinery/groundmap_geothermal.dm b/code/game/machinery/groundmap_geothermal.dm index 6714e3ef669b..4be9c53f0094 100644 --- a/code/game/machinery/groundmap_geothermal.dm +++ b/code/game/machinery/groundmap_geothermal.dm @@ -198,6 +198,9 @@ else return ..() //Deal with everything else, like hitting with stuff +/obj/structure/machinery/power/geothermal/ex_act(severity, direction) + return FALSE //gameplay-wise these should really never go away + //Putting these here since it's power-related /obj/structure/machinery/colony_floodlight_switch name = "Colony Floodlight Switch" diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index e1c9c9a4e279..b538f55292c1 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -4,13 +4,16 @@ anchored = FALSE density = FALSE drag_delay = 1 + base_pixel_x = 15 + base_pixel_y = -2 var/mob/living/carbon/attached = null var/mode = 1 // 1 is injecting, 0 is taking blood. var/obj/item/reagent_container/beaker = null + var/datum/beam/current_beam /obj/structure/machinery/iv_drip/update_icon() - if(src.attached) + if(attached) icon_state = "hooked" else icon_state = "" @@ -35,8 +38,31 @@ filling.color = mix_color_from_reagents(reagents.reagent_list) overlays += filling +/obj/structure/machinery/iv_drip/proc/update_beam() + if(current_beam) + QDEL_NULL(current_beam) + else if(!QDELETED(src) && attached) + current_beam = beam(attached, "iv_tube") + +/obj/structure/machinery/iv_drip/power_change() + . = ..() + if(stat & NOPOWER && attached) + visible_message("\The [src] retracts its IV tube and shuts down.") + attached.active_transfusions -= src + attached = null + update_beam() + update_icon() + +/obj/structure/machinery/iv_drip/Destroy() + attached?.active_transfusions -= src + update_beam() + . = ..() + /obj/structure/machinery/iv_drip/MouseDrop(over_object, src_location, over_location) ..() + if(inoperable()) + visible_message("\The [src] is not powered.") + return if(ishuman(usr)) var/mob/living/carbon/human/H = usr @@ -48,6 +74,7 @@ "You detach \the [src] from \the [attached].") attached.active_transfusions -= src attached = null + update_beam() update_icon() stop_processing() return @@ -57,6 +84,7 @@ "You attach \the [src] to \the [over_object].") attached = over_object attached.active_transfusions += src + update_beam() update_icon() start_processing() @@ -81,6 +109,7 @@ log_admin("[key_name(user)] put a [beaker] into [src], containing [reagentnames] at ([src.loc.x],[src.loc.y],[src.loc.z]).") to_chat(user, "You attach \the [W] to \the [src].") + update_beam() update_icon() return else @@ -97,6 +126,7 @@ attached.emote("scream") attached.active_transfusions -= src attached = null + update_beam() update_icon() stop_processing() return diff --git a/code/game/machinery/nuclearbomb.dm b/code/game/machinery/nuclearbomb.dm index 7dcdb9e39914..6c0ec4cc0389 100644 --- a/code/game/machinery/nuclearbomb.dm +++ b/code/game/machinery/nuclearbomb.dm @@ -55,31 +55,35 @@ var/bomb_set = FALSE /obj/structure/machinery/nuclearbomb/process() . = ..() - if(timing) - bomb_set = TRUE //So long as there is one nuke timing, it means one nuke is armed. - timeleft = explosion_time - world.time - if(world.time >= explosion_time) - explode() - //3 warnings: 1. Halfway through, 2. 1 minute left, 3. 10 seconds left. - //this structure allows varedits to var/timeleft without losing or spamming warnings. - else if(timer_announcements_flags) - if(timer_announcements_flags & NUKE_SHOW_TIMER_HALF) - if(timeleft <= initial(timeleft) / 2 && timeleft >= initial(timeleft) / 2 - 30) - announce_to_players(NUKE_SHOW_TIMER_HALF) - timer_announcements_flags &= ~NUKE_SHOW_TIMER_HALF - return - if(timer_announcements_flags & NUKE_SHOW_TIMER_MINUTE) - if(timeleft <= 600 && timeleft >= 570) - announce_to_players(NUKE_SHOW_TIMER_MINUTE) - timer_announcements_flags = NUKE_SHOW_TIMER_TEN_SEC - return - if(timer_announcements_flags & NUKE_SHOW_TIMER_TEN_SEC) - if(timeleft <= 100 && timeleft >= 70) - announce_to_players(NUKE_SHOW_TIMER_TEN_SEC) - timer_announcements_flags = 0 - return - else - stop_processing() + if(!timing) + update_minimap_icon() + return PROCESS_KILL + + bomb_set = TRUE //So long as there is one nuke timing, it means one nuke is armed. + timeleft = explosion_time - world.time + if(world.time >= explosion_time) + explode() + return + //3 warnings: 1. Halfway through, 2. 1 minute left, 3. 10 seconds left. + //this structure allows varedits to var/timeleft without losing or spamming warnings. + if(!timer_announcements_flags) + return + + if(timer_announcements_flags & NUKE_SHOW_TIMER_HALF) + if(timeleft <= initial(timeleft) / 2 && timeleft >= initial(timeleft) / 2 - 30) + announce_to_players(NUKE_SHOW_TIMER_HALF) + timer_announcements_flags &= ~NUKE_SHOW_TIMER_HALF + return + if(timer_announcements_flags & NUKE_SHOW_TIMER_MINUTE) + if(timeleft <= 600 && timeleft >= 570) + announce_to_players(NUKE_SHOW_TIMER_MINUTE) + timer_announcements_flags = NUKE_SHOW_TIMER_TEN_SEC + return + if(timer_announcements_flags & NUKE_SHOW_TIMER_TEN_SEC) + if(timeleft <= 100 && timeleft >= 70) + announce_to_players(NUKE_SHOW_TIMER_TEN_SEC) + timer_announcements_flags = 0 + return /obj/structure/machinery/nuclearbomb/attack_alien(mob/living/carbon/xenomorph/M) INVOKE_ASYNC(src, TYPE_PROC_REF(/atom, attack_hand), M) @@ -87,10 +91,10 @@ var/bomb_set = FALSE /obj/structure/machinery/nuclearbomb/attackby(obj/item/O as obj, mob/user as mob) if(anchored && timing && bomb_set && HAS_TRAIT(O, TRAIT_TOOL_WIRECUTTERS)) - user.visible_message(SPAN_DANGER("[user] begins to defuse \the [src]."), SPAN_DANGER("You begin to defuse \the [src]. This will take some time...")) + user.visible_message(SPAN_INFO("[user] begins to defuse \the [src]."), SPAN_INFO("You begin to defuse \the [src]. This will take some time...")) if(do_after(user, 150 * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) disable() - playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) return ..() @@ -103,12 +107,12 @@ var/bomb_set = FALSE if(deployable) if(!ishuman(user) && !isqueen(user)) - to_chat(usr, SPAN_DANGER("You don't have the dexterity to do this!")) + to_chat(usr, SPAN_INFO("You don't have the dexterity to do this!")) return if(isqueen(user)) if(timing && bomb_set) - user.visible_message(SPAN_DANGER("[user] begins to defuse \the [src]."), SPAN_DANGER("You begin to defuse \the [src]. This will take some time...")) + user.visible_message(SPAN_INFO("[user] begins to defuse \the [src]."), SPAN_INFO("You begin to defuse \the [src]. This will take some time...")) if(do_after(user, 5 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) disable() return @@ -162,37 +166,38 @@ var/bomb_set = FALSE if(timing == -1) return - if(!ishuman(usr)) + if(!ishuman(ui.user)) return - if(!allowed(usr)) - to_chat(usr, SPAN_DANGER("Access denied!")) + if(!allowed(ui.user)) + to_chat(ui.user, SPAN_INFO("Access denied!")) return if(!anchored) - to_chat(usr, SPAN_DANGER("Engage anchors first!")) + to_chat(ui.user, SPAN_INFO("Engage anchors first!")) return if(safety) - to_chat(usr, SPAN_DANGER("The safety is still on.")) + to_chat(ui.user, SPAN_INFO("The safety is still on.")) return if(!A.can_build_special) - to_chat(usr, SPAN_DANGER("You cannot deploy [src] here!")) + to_chat(ui.user, SPAN_INFO("You cannot deploy [src] here!")) return - if(usr.action_busy) + if(ui.user.action_busy) return - usr.visible_message(SPAN_WARNING("[usr] begins to [timing ? "disengage" : "engage"] [src]!"), SPAN_WARNING("You begin to [timing ? "disengage" : "engage"] [src].")) + ui.user.visible_message(SPAN_WARNING("[ui.user] begins to [timing ? "disengage" : "engage"] [src]!"), SPAN_WARNING("You begin to [timing ? "disengage" : "engage"] [src].")) being_used = TRUE - ui = SStgui.try_update_ui(usr, src, ui) - if(do_after(usr, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + ui = SStgui.try_update_ui(ui.user, src, ui) + if(do_after(ui.user, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) timing = !timing if(timing) if(!safety) bomb_set = TRUE explosion_time = world.time + timeleft + update_minimap_icon() start_processing() announce_to_players() message_admins("\The [src] has been activated by [key_name(ui.user, 1)] [ADMIN_JMP_USER(ui.user)]") @@ -201,28 +206,28 @@ var/bomb_set = FALSE else disable() message_admins("\The [src] has been deactivated by [key_name(ui.user, 1)] [ADMIN_JMP_USER(ui.user)]") - playsound(src.loc, 'sound/effects/thud.ogg', 100, 1) + playsound(loc, 'sound/effects/thud.ogg', 100, 1) being_used = FALSE . = TRUE if("toggleSafety") - if(!allowed(usr)) - to_chat(usr, SPAN_DANGER("Access denied!")) + if(!allowed(ui.user)) + to_chat(ui.user, SPAN_INFO("Access denied!")) return if(timing) - to_chat(usr, SPAN_DANGER("Disengage first!")) + to_chat(ui.user, SPAN_INFO("Disengage first!")) return if(!A.can_build_special) - to_chat(usr, SPAN_DANGER("You cannot deploy [src] here!")) + to_chat(ui.user, SPAN_INFO("You cannot deploy [src] here!")) return - if(usr.action_busy) + if(ui.user.action_busy) return - usr.visible_message(SPAN_WARNING("[usr] begins to [safety ? "disable" : "enable"] the safety on [src]!"), SPAN_WARNING("You begin to [safety ? "disable" : "enable"] the safety on [src].")) + ui.user.visible_message(SPAN_WARNING("[ui.user] begins to [safety ? "disable" : "enable"] the safety on [src]!"), SPAN_WARNING("You begin to [safety ? "disable" : "enable"] the safety on [src].")) being_used = TRUE - ui = SStgui.try_update_ui(usr, src, ui) - if(do_after(usr, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + ui = SStgui.try_update_ui(ui.user, src, ui) + if(do_after(ui.user, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) safety = !safety - playsound(src.loc, 'sound/items/poster_being_created.ogg', 100, 1) + playsound(loc, 'sound/items/poster_being_created.ogg', 100, 1) being_used = FALSE if(safety) timing = FALSE @@ -230,63 +235,55 @@ var/bomb_set = FALSE . = TRUE if("toggleCommandLockout") - if(!ishuman(usr)) + if(!ishuman(ui.user)) return - if(!allowed(usr)) - to_chat(usr, SPAN_DANGER("Access denied!")) + if(!allowed(ui.user)) + to_chat(ui.user, SPAN_INFO("Access denied!")) return if(command_lockout) command_lockout = FALSE req_one_access = list() - to_chat(usr, SPAN_DANGER("Command lockout disengaged.")) + to_chat(ui.user, SPAN_INFO("Command lockout disengaged.")) else //Check if they have command access var/list/acc = list() - var/mob/living/carbon/human/H = usr + var/mob/living/carbon/human/H = ui.user if(H.wear_id) acc += H.wear_id.GetAccess() if(H.get_active_hand()) acc += H.get_active_hand().GetAccess() if(!(ACCESS_MARINE_COMMAND in acc)) - to_chat(usr, SPAN_DANGER("Access denied!")) + to_chat(ui.user, SPAN_INFO("Access denied!")) return command_lockout = TRUE req_one_access = list(ACCESS_MARINE_COMMAND) - to_chat(usr, SPAN_DANGER("Command lockout engaged.")) + to_chat(ui.user, SPAN_INFO("Command lockout engaged.")) . = TRUE if("toggleAnchor") if(timing) - to_chat(usr, SPAN_DANGER("Disengage first!")) + to_chat(ui.user, SPAN_INFO("Disengage first!")) return if(!A.can_build_special) - to_chat(usr, SPAN_DANGER("You cannot deploy [src] here!")) + to_chat(ui.user, SPAN_INFO("You cannot deploy [src] here!")) return - if(usr.action_busy) + if(ui.user.action_busy) return being_used = TRUE - ui = SStgui.try_update_ui(usr, src, ui) - if(do_after(usr, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + ui = SStgui.try_update_ui(ui.user, src, ui) + if(do_after(ui.user, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) if(!anchored) - visible_message(SPAN_DANGER("With a steely snap, bolts slide out of [src] and anchor it to the flooring.")) + visible_message(SPAN_INFO("With a steely snap, bolts slide out of [src] and anchor it to the flooring.")) else - visible_message(SPAN_DANGER("The anchoring bolts slide back into the depths of [src].")) - playsound(src.loc, 'sound/items/Deconstruct.ogg', 100, 1) + visible_message(SPAN_INFO("The anchoring bolts slide back into the depths of [src].")) + playsound(loc, 'sound/items/Deconstruct.ogg', 100, 1) anchored = !anchored being_used = FALSE . = TRUE update_icon() - add_fingerprint(usr) - -/obj/structure/machinery/nuclearbomb/start_processing() - . = ..() - update_minimap_icon() - -/obj/structure/machinery/nuclearbomb/stop_processing() - . = ..() - update_minimap_icon() + add_fingerprint(ui.user) /obj/structure/machinery/nuclearbomb/verb/make_deployable() set category = "Object" @@ -297,12 +294,12 @@ var/bomb_set = FALSE return if(!ishuman(usr)) - to_chat(usr, SPAN_DANGER("You don't have the dexterity to do this!")) + to_chat(usr, SPAN_INFO("You don't have the dexterity to do this!")) return var/area/A = get_area(src) if(!A.can_build_special) - to_chat(usr, SPAN_DANGER("You don't want to deploy this here!")) + to_chat(usr, SPAN_INFO("You don't want to deploy this here!")) return usr.visible_message(SPAN_WARNING("[usr] begins to [deployable ? "close" : "adjust"] several panels to make [src] [deployable ? "undeployable" : "deployable"]."), SPAN_WARNING("You begin to [deployable ? "close" : "adjust"] several panels to make [src] [deployable ? "undeployable" : "deployable"].")) @@ -314,26 +311,25 @@ var/bomb_set = FALSE else deployable = TRUE anchored = TRUE - playsound(src.loc, 'sound/items/Deconstruct.ogg', 100, 1) + playsound(loc, 'sound/items/Deconstruct.ogg', 100, 1) being_used = FALSE update_icon() //unified all announcements to one proc /obj/structure/machinery/nuclearbomb/proc/announce_to_players(timer_warning) + + var/list/humans_other = GLOB.human_mob_list + GLOB.dead_mob_list + var/list/humans_uscm = list() + for(var/mob/current_mob as anything in humans_other) + if(current_mob.stat != CONSCIOUS || isyautja(current_mob)) + humans_other -= current_mob + continue + if(current_mob.faction == FACTION_MARINE || current_mob.faction == FACTION_SURVIVOR) //separating marines from other factions. Survs go here too + humans_uscm += current_mob + humans_other -= current_mob + if(timer_warning) //we check for timer warnings first - //humans part - var/list/humans_other = GLOB.human_mob_list + GLOB.dead_mob_list - var/list/humans_USCM = list() - for(var/mob/M in humans_other) - var/mob/living/carbon/human/H = M - if(istype(H)) //if it's unconsious human or yautja, we remove them - if(H.stat != CONSCIOUS || isyautja(H)) - humans_other.Remove(M) - continue - if(M.faction == FACTION_MARINE || M.faction == FACTION_SURVIVOR) //separating marines from other factions. Survs go here too - humans_USCM += M - humans_other -= M - announcement_helper("WARNING.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_USCM, 'sound/misc/notice1.ogg') + announcement_helper("WARNING.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') announcement_helper("WARNING.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "HQ Intel Division", humans_other, 'sound/misc/notice1.ogg') //preds part var/t_left = duration2text_sec(round(rand(timeleft - timeleft / 10, timeleft + timeleft / 10))) @@ -354,21 +350,9 @@ var/bomb_set = FALSE xeno_announcement(SPAN_XENOANNOUNCE(warning), hive.hivenumber, XENO_GENERAL_ANNOUNCE) return - //deal with start/stop announcements for players - var/list/humans_other = GLOB.human_mob_list + GLOB.dead_mob_list - var/list/humans_USCM = list() - for(var/mob/M in humans_other) - var/mob/living/carbon/human/H = M - if(istype(H)) //if it's unconsious human or yautja, we remove them - if(H.stat != CONSCIOUS || isyautja(H)) - humans_other.Remove(M) - continue - if(M.faction == FACTION_MARINE || M.faction == FACTION_SURVIVOR) //separating marines from other factions. Survs go here too - humans_USCM += M - humans_other -= M var/datum/hive_status/hive if(timing) - announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE ACTIVATED.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_USCM, 'sound/misc/notice1.ogg') + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE ACTIVATED.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE ACTIVATED.\n\nDETONATION IN [round(timeleft/10)] SECONDS.", "HQ Nuclear Tracker", humans_other, 'sound/misc/notice1.ogg') var/t_left = duration2text_sec(round(rand(timeleft - timeleft / 10, timeleft + timeleft / 10))) yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!
A human Purification Device has been detected. You have approximately [t_left] to abandon the hunting grounds before it activates.")) @@ -378,7 +362,7 @@ var/bomb_set = FALSE continue xeno_announcement(SPAN_XENOANNOUNCE("The tallhosts have deployed a hive killer at [get_area_name(loc)]! Stop it at all costs!"), hive.hivenumber, XENO_GENERAL_ANNOUNCE) else - announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE DEACTIVATED.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_USCM, 'sound/misc/notice1.ogg') + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE DEACTIVATED.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE DEACTIVATED.", "HQ Intel Division", humans_other, 'sound/misc/notice1.ogg') yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!
The human Purification Device's signature has disappeared.")) for(var/hivenumber in GLOB.hive_datum) @@ -401,6 +385,7 @@ var/bomb_set = FALSE /obj/structure/machinery/nuclearbomb/proc/explode() if(safety) timing = FALSE + update_minimap_icon() stop_processing() update_icon() return FALSE @@ -422,3 +407,200 @@ var/bomb_set = FALSE bomb_set = FALSE SSminimaps.remove_marker(src) return ..() + +/obj/structure/machinery/nuclearbomb/tech + var/decryption_time = 10 MINUTES + var/decryption_end_time = null + var/decrypting = FALSE + + timeleft = 1 MINUTES + timer_announcements_flags = NUKE_DECRYPT_SHOW_TIMER_ALL + + var/list/linked_decryption_towers + +/obj/structure/machinery/nuclearbomb/tech/Initialize(mapload) + . = ..() + + linked_decryption_towers = list() + + return INITIALIZE_HINT_LATELOAD + +/obj/structure/machinery/nuclearbomb/tech/LateInitialize() + . = ..() + + for(var/obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/possible_telecomm in GLOB.all_static_telecomms_towers) + if(is_ground_level(possible_telecomm.z)) + linked_decryption_towers += possible_telecomm + + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_TELECOMM_TURNED_OFF, PROC_REF(connected_comm_shutdown)) + +/obj/structure/machinery/nuclearbomb/tech/ui_data(mob/user) + . = ..() + + .["decrypting"] = decrypting + .["decryption_time"] = duration2text_sec(decryption_time) + + .["decryption_complete"] = decryption_time ? FALSE : TRUE + +/obj/structure/machinery/nuclearbomb/tech/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return + + switch(action) + if("toggleEncryption") + if(!ishuman(ui.user)) + return + + if(!allowed(ui.user)) + to_chat(ui.user, SPAN_INFO("Access denied!")) + return + + if(!anchored) + to_chat(ui.user, SPAN_INFO("Engage anchors first!")) + return + + var/area/current_area = get_area(src) + if(!current_area.can_build_special) + to_chat(ui.user, SPAN_INFO("You cannot deploy [src] here!")) + return + + if(is_ground_level(z)) + for(var/obj/structure/machinery/telecomms/relay/preset/tower/mapcomms/telecomm_unit in linked_decryption_towers) + if(!telecomm_unit.on) + to_chat(ui.user, SPAN_INFO("The groundside telecommunication relays must be activated!")) + return + + if(ui.user.action_busy) + return + + if(being_used) + return + + ui.user.visible_message(SPAN_WARNING("[ui.user] begins to [decrypting ? "stop the decryption process." : "start decrypting."]!"), SPAN_WARNING("You begin to [decrypting ? "stop the decryption process." : "start decrypting."].")) + being_used = TRUE + ui = SStgui.try_update_ui(ui.user, src, ui) + if(do_after(ui.user, 50, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE)) + decrypting = !decrypting + if(decrypting) + //add signal handlers + decryption_end_time = world.time + decryption_time + start_processing() + announce_to_players() + message_admins("[src]'s encryption process has been started by [key_name(ui.user, 1)] [ADMIN_JMP_USER(ui.user)]") + else + //remove signal handlers + decryption_end_time = null + announce_to_players() + message_admins("[src]'s encryption process has been deactivated by [key_name(ui.user, 1)] [ADMIN_JMP_USER(ui.user)]") + playsound(loc, 'sound/effects/thud.ogg', 100, 1) + being_used = FALSE + return TRUE + +/obj/structure/machinery/nuclearbomb/tech/process() + if(!decrypting) + return ..() + + decryption_time = decryption_end_time - world.time + + if(world.time > decryption_end_time) + decrypting = FALSE + decryption_time = 0 + announce_to_players(NUKE_DECRYPT_SHOW_TIMER_COMPLETE) + timer_announcements_flags &= ~NUKE_DECRYPT_SHOW_TIMER_COMPLETE + return PROCESS_KILL + + if(!timer_announcements_flags) + return + + if(timer_announcements_flags & NUKE_DECRYPT_SHOW_TIMER_HALF) + if(decryption_time <= initial(decryption_time) / 2 && decryption_time >= initial(decryption_time) / 2 - 30) + announce_to_players(NUKE_DECRYPT_SHOW_TIMER_HALF) + timer_announcements_flags &= ~NUKE_DECRYPT_SHOW_TIMER_HALF + return + if(timer_announcements_flags & NUKE_DECRYPT_SHOW_TIMER_MINUTE) + if(decryption_time <= 600 && decryption_time >= 570) + announce_to_players(NUKE_DECRYPT_SHOW_TIMER_MINUTE) + timer_announcements_flags &= ~NUKE_DECRYPT_SHOW_TIMER_MINUTE + return + +/obj/structure/machinery/nuclearbomb/tech/announce_to_players(timer_warning) + if(!decryption_time && (timer_warning != NUKE_DECRYPT_SHOW_TIMER_COMPLETE)) + return ..() + + var/list/humans_other = GLOB.human_mob_list + GLOB.dead_mob_list + var/list/humans_uscm = list() + for(var/mob/current_mob as anything in humans_other) + var/mob/living/carbon/human/current_human = current_mob + if(istype(current_human)) //if it's unconsious human or yautja, we remove them + if(current_human.stat != CONSCIOUS || isyautja(current_human)) + humans_other -= current_mob + continue + if(current_mob.faction == FACTION_MARINE || current_mob.faction == FACTION_SURVIVOR) + humans_uscm += current_mob + humans_other -= current_mob + + if(timer_warning) + if(timer_warning == NUKE_DECRYPT_SHOW_TIMER_COMPLETE) + announcement_helper("DECRYPTION COMPLETE", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') + announcement_helper("DECRYPTION COMPLETE", "HQ Intel Division", humans_other, 'sound/misc/notice1.ogg') + + yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!\n\nThe human Purification Device is able to be activated.")) + + var/datum/hive_status/hive + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!length(hive.totalXenos)) + return + xeno_announcement(SPAN_XENOANNOUNCE("The hive killer is ready to be activated! Assault at once!"), hive.hivenumber, XENO_GENERAL_ANNOUNCE) + return + + announcement_helper("DECRYPTION IN [round(decryption_time/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') + announcement_helper("DECRYPTION IN [round(decryption_time/10)] SECONDS.", "HQ Intel Division", humans_other, 'sound/misc/notice1.ogg') + + //preds part + var/time_left = duration2text_sec(round(rand(decryption_time - decryption_time / 10, decryption_time + decryption_time / 10))) + yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!\n\nYou have approximately [time_left] seconds to abandon the hunting grounds before human Purification Device is able to be activated.")) + + //xenos part + var/warning = "Hive killer is almost prepared to be activated!" + if(timer_warning & NUKE_DECRYPT_SHOW_TIMER_HALF) + warning = "Hive killer is halfway through its initial phase!" + + var/datum/hive_status/hive + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!hive.totalXenos.len) + return + xeno_announcement(SPAN_XENOANNOUNCE(warning), hive.hivenumber, XENO_GENERAL_ANNOUNCE) + return + + var/datum/hive_status/hive + if(decrypting) + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE DECRYPTION STARTED.\n\nDECRYPTION IN [round(decryption_time/10)] SECONDS.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE ORDNANCE DECRYPTION STARTED.\n\nDECRYPTION IN [round(decryption_time/10)] SECONDS.", "HQ Nuclear Tracker", humans_other, 'sound/misc/notice1.ogg') + var/time_left = duration2text_sec(round(rand(decryption_time - decryption_time / 10, decryption_time + decryption_time / 10))) + yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!
A human Purification Device has been detected. You have approximately [time_left] before it finishes its initial phase.")) + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!length(hive.totalXenos)) + continue + xeno_announcement(SPAN_XENOANNOUNCE("The tallhosts have started the initial phase of a hive killer at [get_area_name(loc)]! Destroy their communications relays!"), hive.hivenumber, XENO_GENERAL_ANNOUNCE) + return + + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE DECRYPTION HALTED.", "[MAIN_AI_SYSTEM] Nuclear Tracker", humans_uscm, 'sound/misc/notice1.ogg') + announcement_helper("ALERT.\n\nNUCLEAR EXPLOSIVE DECRYPTION HALTED.", "HQ Intel Division", humans_other, 'sound/misc/notice1.ogg') + yautja_announcement(SPAN_YAUTJABOLDBIG("WARNING!
The human Purification Device's signature has disappeared.")) + for(var/hivenumber in GLOB.hive_datum) + hive = GLOB.hive_datum[hivenumber] + if(!length(hive.totalXenos)) + continue + xeno_announcement(SPAN_XENOANNOUNCE("The hive killer's initial phase has been halted! Rejoice!"), hive.hivenumber, XENO_GENERAL_ANNOUNCE) + +/obj/structure/machinery/nuclearbomb/tech/proc/connected_comm_shutdown(obj/structure/machinery/telecomms/relay/preset/tower/telecomm_unit) + SIGNAL_HANDLER + + if(!decrypting) + return + + decrypting = FALSE + announce_to_players() diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index cded8a1148c7..a370356ad60b 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -62,7 +62,7 @@ stat &= ~BROKEN // the machine's not borked anymore! else to_chat(user, SPAN_WARNING("You need five coils of wire for this.")) - if(istype(P, /obj/item/tool/crowbar)) + if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR)) to_chat(user, "You begin prying out the circuit board other components...") playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1) if(do_after(user, 60 * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm index ce5e9a743bc5..a25293aebbd3 100644 --- a/code/game/machinery/telecomms/presets.dm +++ b/code/game/machinery/telecomms/presets.dm @@ -60,7 +60,7 @@ return TRUE return FALSE -/obj/structure/machinery/telecomms/relay/preset/tower/tcomms_startup() +/obj/structure/machinery/telecomms/relay/preset/tower/update_state() . = ..() if(on) playsound(src, 'sound/machines/tcomms_on.ogg', vol = 80, vary = FALSE, sound_range = 16, falloff = 0.5) diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 324a358d041f..255d70f45870 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -71,6 +71,9 @@ GLOBAL_LIST_EMPTY_TYPED(telecomms_list, /obj/structure/machinery/telecomms) // When effectively shut down /obj/structure/machinery/telecomms/proc/tcomms_shutdown() on = FALSE + + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_GROUNDSIDE_TELECOMM_TURNED_OFF) + if(tcomms_machine) SSradio.remove_tcomm_machine(src) diff --git a/code/game/machinery/vending/vendor_types/crew/synthetic.dm b/code/game/machinery/vending/vendor_types/crew/synthetic.dm index bd403c65c31b..1d8e5e289066 100644 --- a/code/game/machinery/vending/vendor_types/crew/synthetic.dm +++ b/code/game/machinery/vending/vendor_types/crew/synthetic.dm @@ -244,6 +244,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list( list("Labcoat", 12, /obj/item/clothing/suit/storage/labcoat, null, VENDOR_ITEM_REGULAR), list("Labcoat, Researcher", 12, /obj/item/clothing/suit/storage/labcoat/researcher, null, VENDOR_ITEM_REGULAR), list("RO Jacket", 12, /obj/item/clothing/suit/storage/RO, null, VENDOR_ITEM_REGULAR), + list("USCM Poncho", 12, /obj/item/clothing/accessory/poncho, null, VENDOR_ITEM_REGULAR), list("BACKPACK", 0, null, null, null), list("Backpack, Industrial", 12, /obj/item/storage/backpack/industrial, null, VENDOR_ITEM_REGULAR), diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm index 5815f60b2e0c..70ac7701973b 100644 --- a/code/game/machinery/vending/vendor_types/medical.dm +++ b/code/game/machinery/vending/vendor_types/medical.dm @@ -272,7 +272,7 @@ /obj/structure/machinery/cm_vending/sorted/medical/blood name = "\improper MM Blood Dispenser" - desc = "Marine Med brand Blood Pack Dispensary" + desc = "The Marine Med Brand Blood Pack Dispensary is the premier, top-of-the-line blood dispenser of 2105! Get yours today!" //Don't update this year, the joke is it's old. icon_state = "blood" wrenchable = TRUE hackable = TRUE diff --git a/code/game/machinery/vending/vendor_types/requisitions.dm b/code/game/machinery/vending/vendor_types/requisitions.dm index 250a998f38bf..838b21a00e6f 100644 --- a/code/game/machinery/vending/vendor_types/requisitions.dm +++ b/code/game/machinery/vending/vendor_types/requisitions.dm @@ -426,6 +426,7 @@ list("ARMOR", -1, null, null), list("M10 Pattern Marine Helmet", 20, /obj/item/clothing/head/helmet/marine, VENDOR_ITEM_REGULAR), list("M10 Pattern Technician Helmet", 20, /obj/item/clothing/head/helmet/marine/tech, VENDOR_ITEM_REGULAR), + list("M10 Pattern Corpman Helmet", 20, /obj/item/clothing/head/helmet/marine/medic, VENDOR_ITEM_REGULAR), list("M3 Pattern Carrier Marine Armor", 20, /obj/item/clothing/suit/storage/marine/carrier, VENDOR_ITEM_REGULAR), list("M3 Pattern Padded Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padded, VENDOR_ITEM_REGULAR), list("M3 Pattern Padless Marine Armor", 20, /obj/item/clothing/suit/storage/marine/padless, VENDOR_ITEM_REGULAR), diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm index cbe0871148da..b94ee6902321 100644 --- a/code/game/objects/effects/aliens.dm +++ b/code/game/objects/effects/aliens.dm @@ -291,6 +291,8 @@ var/ticks = 0 var/acid_strength = 1 //100% speed, normal var/barricade_damage = 40 + /// How much fuel the acid drains from the flare every acid tick + var/flare_damage = 500 var/barricade_damage_ticks = 10 // tick is once per 5 seconds. This tells us how many times it will try damaging barricades var/in_weather = FALSE @@ -299,13 +301,15 @@ name = "weak acid" acid_strength = 2.5 //250% normal speed barricade_damage = 20 + flare_damage = 150 icon_state = "acid_weak" //Superacid /obj/effect/xenomorph/acid/strong name = "strong acid" - acid_strength = 0.4 //20% normal speed + acid_strength = 0.4 //40% normal speed barricade_damage = 100 + flare_damage = 1875 icon_state = "acid_strong" /obj/effect/xenomorph/acid/New(loc, target) @@ -355,6 +359,12 @@ sleep(50) .() return + if(istype(acid_t, /obj/item/device/flashlight/flare)) + var/obj/item/device/flashlight/flare/flare = acid_t + if(flare.fuel > 0) //Flares that have fuel in them lose fuel instead of melting + flare.fuel -= flare_damage + sleep(rand(150,250) * (acid_strength)) + return .() if(++ticks >= strength_t) visible_message(SPAN_XENODANGER("[acid_t] collapses under its own weight into a puddle of goop and undigested debris!")) @@ -394,8 +404,6 @@ sleep(rand(200,300) * (acid_strength)) .() - - /obj/effect/xenomorph/boiler_bombard name = "???" desc = "" diff --git a/code/game/objects/effects/effect_system/chemsmoke.dm b/code/game/objects/effects/effect_system/chemsmoke.dm index 8ecdb2c07db9..c2323c32c934 100644 --- a/code/game/objects/effects/effect_system/chemsmoke.dm +++ b/code/game/objects/effects/effect_system/chemsmoke.dm @@ -40,7 +40,8 @@ // Culls the selected turfs to a (roughly) circle shape, then calls smokeFlow() to make // sure the smoke can actually path to the turfs. This culls any turfs it can't reach. //------------------------------------------ -/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, n = 10, c = 0, loca, direct) +/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, n = 10, c = 0, loca, direct, datum/cause_data/new_cause_data) + cause_data = istype(new_cause_data) ? new_cause_data : cause_data range = n * 0.3 cardinals = c carry.copy_to(chemholder, carry.total_volume) diff --git a/code/game/objects/effects/effect_system/foam.dm b/code/game/objects/effects/effect_system/foam.dm index d0a1fa132b06..a7647dbd4489 100644 --- a/code/game/objects/effects/effect_system/foam.dm +++ b/code/game/objects/effects/effect_system/foam.dm @@ -28,7 +28,7 @@ metal = ismetal playsound(src, 'sound/effects/bubbles2.ogg', 25, 1, 5) addtimer(CALLBACK(src, PROC_REF(foam_react)), 3 + metal*3) - addtimer(CALLBACK(src, PROC_REF(foam_metal_final_react)), 120) + addtimer(CALLBACK(src, PROC_REF(foam_metal_final_react)), 40) /obj/effect/particle_effect/foam/proc/foam_react() process() diff --git a/code/game/objects/effects/effect_system/smoke.dm b/code/game/objects/effects/effect_system/smoke.dm index a02069087412..9f7a9c8143c7 100644 --- a/code/game/objects/effects/effect_system/smoke.dm +++ b/code/game/objects/effects/effect_system/smoke.dm @@ -283,14 +283,14 @@ var/gas_damage = 20 /obj/effect/particle_effect/smoke/xeno_burn/Initialize(mapload, amount, datum/cause_data/cause_data) - var/mob/living/carbon/xenomorph/xeno = cause_data?.resolve_mob() - if (istype(xeno) && xeno.hivenumber) - hivenumber = xeno.hivenumber - - set_hive_data(src, hivenumber) - - . = ..() + if(istype(cause_data)) + var/datum/ui_state/hive_state/cause_data_hive_state = GLOB.hive_state[cause_data.faction] + var/new_hive_number = cause_data_hive_state?.hivenumber + if(new_hive_number) + hivenumber = new_hive_number + set_hive_data(src, new_hive_number) + return ..() /obj/effect/particle_effect/smoke/xeno_burn/apply_smoke_effect(turf/T) ..() @@ -387,7 +387,7 @@ if(!issynth(moob)) var/datum/effects/neurotoxin/neuro_effect = locate() in moob.effects_list if(!neuro_effect) - neuro_effect = new /datum/effects/neurotoxin(moob) + neuro_effect = new(moob, cause_data.resolve_mob()) neuro_effect.strength = effect_amt neuro_effect.duration += neuro_dose if(moob.coughedtime != 1 && !moob.stat) //Coughing/gasping diff --git a/code/game/objects/items/devices/cictablet.dm b/code/game/objects/items/devices/cictablet.dm index 2650a3057503..1a4aebe813cc 100644 --- a/code/game/objects/items/devices/cictablet.dm +++ b/code/game/objects/items/devices/cictablet.dm @@ -145,6 +145,8 @@ log_game("[key_name(usr)] has called for an emergency evacuation.") message_admins("[key_name_admin(usr)] has called for an emergency evacuation.") + var/datum/ares_link/link = GLOB.ares_link + link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.") . = TRUE if("distress") diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 6fe39172d783..a3e587089997 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -286,7 +286,7 @@ /obj/item/device/flashlight/flare/Initialize() . = ..() - fuel = rand(1600 SECONDS, 2000 SECONDS) + fuel = rand(9.5 MINUTES, 10.5 MINUTES) /obj/item/device/flashlight/flare/update_icon() overlays?.Cut() @@ -416,7 +416,7 @@ /obj/item/device/flashlight/flare/on/illumination/Initialize() . = ..() - fuel = rand(800 SECONDS, 1000 SECONDS) // Half the duration of a flare, but justified since it's invincible + fuel = rand(4.5 MINUTES, 5.5 MINUTES) // Half the duration of a flare, but justified since it's invincible /obj/item/device/flashlight/flare/on/illumination/update_icon() return diff --git a/code/game/objects/items/devices/motion_detector.dm b/code/game/objects/items/devices/motion_detector.dm index 01858ed486d0..ade74531bc91 100644 --- a/code/game/objects/items/devices/motion_detector.dm +++ b/code/game/objects/items/devices/motion_detector.dm @@ -22,6 +22,7 @@ item_state = "motion_detector" flags_atom = FPRINT| CONDUCT flags_equip_slot = SLOT_WAIST + inherent_traits = list(TRAIT_ITEM_NOT_IMPLANTABLE) var/list/blip_pool = list() var/detector_range = 14 var/detector_mode = MOTION_DETECTOR_LONG @@ -309,7 +310,7 @@ name = "hacked motion detector" desc = "A device that usually picks up non-USCM signals, but this one's been hacked to detect all non-freelancer movement instead. Fight fire with fire!" iff_signal = FACTION_MERCENARY - + /obj/item/device/motiondetector/hacked/pmc name = "corporate motion detector" desc = "A device that usually picks up non-USCM signals, but this one's been reprogrammed to detect all non-PMC movement instead. Very corporate." diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index 0f010d689e74..6293abb67339 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -49,7 +49,7 @@ name = "AI Integrated Encryption Key" desc = "Integrated encryption key" icon_state = "cap_key" - channels = list(RADIO_CHANNEL_ALMAYER = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_ALMAYER = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) /obj/item/device/encryptionkey/sentry_laptop name = "Sentry Network Status Encryption Key" @@ -61,12 +61,12 @@ /obj/item/device/encryptionkey/cmpcom/cdrcom name = "\improper Marine Senior Command Radio Encryption Key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) /obj/item/device/encryptionkey/mcom name = "\improper Marine Command Radio Encryption Key" icon_state = "cap_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) // MARINE ENGINEERING @@ -102,7 +102,7 @@ /obj/item/device/encryptionkey/mmpo name = "\improper Military Police Radio Encryption Key" icon_state = "sec_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE,) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE,) /obj/item/device/encryptionkey/sec name = "Security Radio Encryption Key" @@ -130,7 +130,7 @@ /obj/item/device/encryptionkey/cmpcom/synth name = "\improper Marine Synth Radio Encryption Key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) /obj/item/device/encryptionkey/mcom/cl name = "\improper Corporate Liaison radio encryption key" @@ -163,7 +163,7 @@ channels = list(RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_COMMAND = FALSE) /obj/item/device/encryptionkey/mcom/ai //AI only. - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) // MARINE SQUADS @@ -296,7 +296,7 @@ /obj/item/device/encryptionkey/highcom name = "\improper USCM High Command Radio Encryption Key" icon_state = "binary_key" - channels = list(RADIO_CHANNEL_HIGHCOM = TRUE, SQUAD_SOF = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = FALSE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) + channels = list(RADIO_CHANNEL_HIGHCOM = TRUE, SQUAD_SOF = TRUE, RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MP = TRUE, SQUAD_MARINE_1 = TRUE, SQUAD_MARINE_2 = TRUE, SQUAD_MARINE_3 = TRUE, SQUAD_MARINE_4 = TRUE, SQUAD_MARINE_5 = TRUE, SQUAD_MARINE_CRYO = TRUE, RADIO_CHANNEL_ENGI = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_REQ = TRUE, RADIO_CHANNEL_JTAC = TRUE, RADIO_CHANNEL_INTEL = TRUE) /obj/item/device/encryptionkey/contractor name = "\improper Vanguard's Arrow Incorporated Radio Encryption Key" @@ -306,7 +306,7 @@ /obj/item/device/encryptionkey/cmb name = "\improper Colonial Marshal Bureau Radio Encryption Key" icon_state = "cmb_key" - channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_INTEL = TRUE, RADIO_CHANNEL_ALMAYER = TRUE) + channels = list(RADIO_CHANNEL_COMMAND = TRUE, RADIO_CHANNEL_MEDSCI = TRUE, RADIO_CHANNEL_INTEL = TRUE, RADIO_CHANNEL_ALMAYER = TRUE, RADIO_CHANNEL_COLONY = TRUE) /// Used by the Mortar Crew in WO game mode - intently has no squad radio access /obj/item/device/encryptionkey/mortar name = "\improper Mortar Crew Radio Encryption Key" diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 631ef8fa0e2c..e8dcdac34222 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -961,20 +961,23 @@ //CMB Headsets /obj/item/device/radio/headset/distress/CMB name = "\improper CMB Earpiece" - desc = "A sleek headset used by The Colonial Marshal Bureau, crafted in Sol. Low profile and comfortable. No one is above the law. Featured channels include: ; - CMB, :g - public, :v - marine command, :m - medbay, :t - intel." + desc = "A sleek headset used by The Colonial Marshal Bureau, crafted in Sol. Low profile and comfortable. No one is above the law. Featured channels include: ; - CMB, :o - Colony, :g - public, :v - marine command, :m - medbay, :t - intel." frequency = CMB_FREQ icon_state = "cmb_headset" initial_keys = list(/obj/item/device/encryptionkey/cmb) has_hud = TRUE hud_type = MOB_HUD_FACTION_USCM +/obj/item/device/radio/headset/distress/CMB/limited + name = "\improper Damaged CMB Earpiece" + desc = "A sleek headset used by The Colonial Marshal Bureau, crafted in Sol. Low profile and comfortable. No one is above the law. This one is damaged, so the channels are: ; - CMB, :o - Colony." + initial_keys = list(/obj/item/device/encryptionkey/colony) + /obj/item/device/radio/headset/distress/CMB/ICC name = "\improper ICC Liaison Headset" - desc = "An expensive headset used by The Interstellar Commerce Commission. This one in particular has a liaison chip with the CMB. Featured channels include: ; - CMB, :g - public, :v - marine command, :m - medbay, :t - intel, :y - Weyland-Yutani." - frequency = CMB_FREQ + desc = "An expensive headset used by The Interstellar Commerce Commission. This one in particular has a liaison chip with the CMB. Featured channels include: ; - CMB, :o - Colony, :g - public, :v - marine command, :m - medbay, :t - intel, :y - Weyland-Yutani." icon_state = "wy_headset" initial_keys = list(/obj/item/device/encryptionkey/WY, /obj/item/device/encryptionkey/cmb) - has_hud = TRUE /obj/item/device/radio/headset/almayer/highcom name = "USCM High Command headset" diff --git a/code/game/objects/items/reagent_containers/blood_pack.dm b/code/game/objects/items/reagent_containers/blood_pack.dm index 450cdde2fa00..8e29a26c2ecd 100644 --- a/code/game/objects/items/reagent_containers/blood_pack.dm +++ b/code/game/objects/items/reagent_containers/blood_pack.dm @@ -13,7 +13,9 @@ var/mode = BLOOD_BAG_INJECTING var/mob/living/carbon/human/connected_to + var/mob/living/carbon/human/connected_from var/blood_type = null + var/datum/beam/current_beam /obj/item/reagent_container/blood/Initialize() . = ..() @@ -32,6 +34,12 @@ if(10 to 50) icon_state = "half" if(51 to INFINITY) icon_state = "full" +/obj/item/reagent_container/blood/proc/update_beam() + if(current_beam) + QDEL_NULL(current_beam) + else if(connected_from && connected_to) + current_beam = connected_from.beam(connected_to, "iv_tube") + /obj/item/reagent_container/blood/attack(mob/attacked_mob, mob/user) . = ..() @@ -44,7 +52,10 @@ user.visible_message("[user] detaches [src] from [connected_to].", \ "You detach [src] from [connected_to].") connected_to.active_transfusions -= src + connected_to.base_pixel_x = 0 connected_to = null + connected_from = null + update_beam() return if(!skillcheck(user, SKILL_SURGERY, SKILL_SURGERY_NOVICE)) @@ -60,10 +71,13 @@ if(istype(attacked_mob, /mob/living/carbon/human)) connected_to = attacked_mob + connected_from = user connected_to.active_transfusions += src + connected_to.base_pixel_x = 5 START_PROCESSING(SSobj, src) user.visible_message("[user] attaches \the [src] to [connected_to].", \ "You attach \the [src] to [connected_to].") + update_beam() /obj/item/reagent_container/blood/process() //if we're not connected to anything stop doing stuff @@ -106,6 +120,10 @@ connected_to.take_blood(src, amount) +/obj/item/reagent_container/blood/dropped() + ..() + bad_disconnect() + ///Used to standardize effects of a blood bag disconnecting improperly /obj/item/reagent_container/blood/proc/bad_disconnect() if(!connected_to) @@ -116,7 +134,10 @@ if(connected_to.pain.feels_pain) connected_to.emote("scream") connected_to.active_transfusions -= src + connected_to.base_pixel_x = 0 connected_to = null + connected_from = null + update_beam() /obj/item/reagent_container/blood/verb/toggle_mode() set category = "Object" diff --git a/code/game/objects/items/reagent_containers/food/snacks.dm b/code/game/objects/items/reagent_containers/food/snacks.dm index 7dae94bfe4eb..c0e11dac8eb3 100644 --- a/code/game/objects/items/reagent_containers/food/snacks.dm +++ b/code/game/objects/items/reagent_containers/food/snacks.dm @@ -66,6 +66,10 @@ if(issynth(C)) fullness = 200 //Synths never get full + if(HAS_TRAIT(M, TRAIT_CANNOT_EAT)) //Do not feed the Working Joes + to_chat(user, SPAN_DANGER("[user == M ? "You are" : "[M] is"] unable to eat!")) + return + if(fullness > 540) C.overeat_cooldown = world.time + OVEREAT_TIME diff --git a/code/game/objects/items/tools/flame_tools.dm b/code/game/objects/items/tools/flame_tools.dm index db35d3300ae7..6ebd8ee5982e 100644 --- a/code/game/objects/items/tools/flame_tools.dm +++ b/code/game/objects/items/tools/flame_tools.dm @@ -170,13 +170,20 @@ CIGARETTE PACKETS ARE IN FANCY.DM damtype = "brute" icon_state = "[initial(icon_state)]_burnt" item_state = "cigoff" - if(user && loc != user) - user.SetLuminosity(0, FALSE, src) SetLuminosity(0) name = burnt_name desc = "A match. This one has seen better days." STOP_PROCESSING(SSobj, src) + if(user) + user.SetLuminosity(0, FALSE, src) + return + + if(ismob(loc)) + user = loc + user.SetLuminosity(0, FALSE, src) + return + /obj/item/tool/match/paper name = "paper match" desc = "A simple match stick, used for lighting fine smokables." diff --git a/code/game/objects/items/tools/maintenance_tools.dm b/code/game/objects/items/tools/maintenance_tools.dm index 25bcefc1cc34..2560c5ff91e8 100644 --- a/code/game/objects/items/tools/maintenance_tools.dm +++ b/code/game/objects/items/tools/maintenance_tools.dm @@ -557,8 +557,6 @@ if(attacked_door.locked) //Bolted to_chat(user, SPAN_DANGER("You can't pry open [attacked_door] while it is bolted shut.")) return - if(!attacked_door.arePowerSystemsOn()) //Opens like normal if unpowered - return FALSE if(requires_superstrength_pry) if(!HAS_TRAIT(user, TRAIT_SUPER_STRONG)) //basically IS_PRY_CAPABLE_CROWBAR @@ -645,7 +643,7 @@ resin_door.Open() return - if(istype(attacked_obj, /turf/open/floor)) + else if(istype(attacked_obj, /turf/open/floor)) var/turf/open/floor/flooring = attacked_obj if(crowbar_mode && user.a_intent == INTENT_HELP) //Only pry flooring on help intent diff --git a/code/game/objects/items/tools/misc_tools.dm b/code/game/objects/items/tools/misc_tools.dm index 727f6c5c7677..1bcebd9f1ea3 100644 --- a/code/game/objects/items/tools/misc_tools.dm +++ b/code/game/objects/items/tools/misc_tools.dm @@ -275,6 +275,25 @@ desc = "It's an invisible pen marker." pen_colour = "white" +/obj/item/tool/pen/fountain + desc = "A luxurious fountain pen, embossed with gold accents. Its intricate mechanics allow the user to switch between various ink colors with a simple twist." + name = "fountain pen" + icon_state = "fountain_pen" + item_state = "fountain_pen" + matter = list("metal" = 20, "gold" = 10) + var/static/list/colour_list = list("red", "blue", "green", "yellow", "purple", "pink", "brown", "black", "orange") // Can add more colors as required + var/current_colour_index = 1 + +/obj/item/tool/pen/fountain/attack_self(mob/living/carbon/human/user) + if(on) + current_colour_index = (current_colour_index % length(colour_list)) + 1 + pen_colour = colour_list[current_colour_index] + balloon_alert(user,"you twist the pen and change the ink color to [pen_colour].") + if(clicky) + playsound(user.loc, 'sound/items/pen_click_on.ogg', 100, 1, 5) + update_pen_state() + else + ..() /obj/item/tool/pen/attack(mob/M as mob, mob/user as mob) if(!ismob(M)) diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm index ec7ee0b173da..cdab7db87ed7 100644 --- a/code/game/objects/items/weapons/swords_axes_etc.dm +++ b/code/game/objects/items/weapons/swords_axes_etc.dm @@ -45,7 +45,7 @@ w_class = SIZE_SMALL force = MELEE_FORCE_WEAK var/on = 0 - var/stunforce = 60 + var/stun_force = 10 /obj/item/weapon/telebaton/attack(mob/living/carbon/human/target, mob/living/user) if(!istype(target) || !on) @@ -67,6 +67,7 @@ item_state = "telebaton_1" w_class = SIZE_MEDIUM force = MELEE_FORCE_VERY_STRONG + stun_force = 40 attack_verb = list("smacked", "struck", "slapped", "beat") else user.visible_message(SPAN_NOTICE("Using a smooth, practiced movement, [user] collapses \his [src]."),\ @@ -75,7 +76,8 @@ icon_state = "telebaton_0" item_state = "telebaton_0" w_class = SIZE_SMALL - force = MELEE_FORCE_WEAK//not so robust now + force = MELEE_FORCE_WEAK + stun_force = initial(stun_force) attack_verb = list("hit", "punched") if(istype(user,/mob/living/carbon/human)) @@ -100,8 +102,17 @@ user.flick_attack_overlay(target, "punch") log_interact(user, target, "[key_name(user)] stunned [key_name(target)] with \the [src]") // Hit 'em + var/final_stun_force = stun_force + var/datum/skills/user_skills = user.skills + if(user_skills) + switch(user_skills.get_skill_level(SKILL_POLICE)) + if(SKILL_POLICE_FLASH) + final_stun_force *= 1.5 + if(SKILL_POLICE_SKILLED) + final_stun_force *= 3 + var/target_zone = check_zone(user.zone_selected) - target.apply_stamina_damage(stunforce, target_zone, ARMOR_MELEE) + target.apply_stamina_damage(final_stun_force, target_zone, ARMOR_MELEE) if(target.stamina.current_stamina <= 0) user.visible_message(SPAN_DANGER("[user] knocks down [target] with \the [src]!"),\ SPAN_WARNING("You knock down [target] with \the [src]!")) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 42a3a2f0b9ea..b92624cf4201 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -223,6 +223,7 @@ /obj/proc/afterbuckle(mob/M as mob) // Called after somebody buckled / unbuckled handle_rotation() + SEND_SIGNAL(src, COSMIG_OBJ_AFTER_BUCKLE, buckled_mob) return buckled_mob /obj/proc/unbuckle() @@ -302,11 +303,9 @@ src.add_fingerprint(user) afterbuckle(target) if(buckle_lying) // Make sure buckling to beds/nests etc only turns, and doesn't give a random offset - var/matrix/M = matrix() - var/matrix/L = matrix() //Counterrotation for langchat text. - M.Turn(90) - L.Turn(270) - target.apply_transform(M) + var/matrix/new_matrix = matrix() + new_matrix.Turn(90) + target.apply_transform(new_matrix) return TRUE /obj/proc/send_buckling_message(mob/M, mob/user) diff --git a/code/game/objects/structures/barricade/barricade.dm b/code/game/objects/structures/barricade/barricade.dm index 6905a734b915..eac5f154e26e 100644 --- a/code/game/objects/structures/barricade/barricade.dm +++ b/code/game/objects/structures/barricade/barricade.dm @@ -30,6 +30,8 @@ var/brute_multiplier = 1 var/burn_multiplier = 1 var/explosive_multiplier = 1 + var/brute_projectile_multiplier = 1 + var/burn_flame_multiplier = 1 var/repair_materials = list() var/metallic = TRUE @@ -42,12 +44,12 @@ addtimer(CALLBACK(src, PROC_REF(update_icon)), 0) starting_maxhealth = maxhealth -/obj/structure/barricade/initialize_pass_flags(datum/pass_flags_container/PF) +/obj/structure/barricade/initialize_pass_flags(datum/pass_flags_container/pass_flags) ..() - if (PF) - PF.flags_can_pass_all = NONE - PF.flags_can_pass_front = NONE - PF.flags_can_pass_behind = PASS_OVER^(PASS_OVER_ACID_SPRAY|PASS_OVER_THROW_MOB) + if (pass_flags) + pass_flags.flags_can_pass_all = NONE + pass_flags.flags_can_pass_front = NONE + pass_flags.flags_can_pass_behind = PASS_OVER^(PASS_OVER_ACID_SPRAY|PASS_OVER_THROW_MOB) flags_can_pass_front_temp = PASS_OVER_THROW_MOB flags_can_pass_behind_temp = PASS_OVER_THROW_MOB @@ -95,7 +97,7 @@ overlays += image('icons/obj/structures/barricades.dmi', icon_state = "+burn_upgrade_[damage_state]") if(BARRICADE_UPGRADE_BRUTE) overlays += image('icons/obj/structures/barricades.dmi', icon_state = "+brute_upgrade_[damage_state]") - if(BARRICADE_UPGRADE_EXPLOSIVE) + if(BARRICADE_UPGRADE_ANTIFF) overlays += image('icons/obj/structures/barricades.dmi', icon_state = "+explosive_upgrade_[damage_state]") if(is_wired) @@ -106,34 +108,34 @@ ..() -/obj/structure/barricade/hitby(atom/movable/AM) - if(AM.throwing && is_wired) - if(iscarbon(AM)) - var/mob/living/carbon/C = AM - if(C.mob_size <= MOB_SIZE_XENO) - C.visible_message(SPAN_DANGER("The barbed wire slices into [C]!"), +/obj/structure/barricade/hitby(atom/movable/atom_movable) + if(atom_movable.throwing && is_wired) + if(iscarbon(atom_movable)) + var/mob/living/carbon/living_carbon = atom_movable + if(living_carbon.mob_size <= MOB_SIZE_XENO) + living_carbon.visible_message(SPAN_DANGER("The barbed wire slices into [living_carbon]!"), SPAN_DANGER("The barbed wire slices into you!")) - C.apply_damage(10) - C.apply_effect(2, WEAKEN) //Leaping into barbed wire is VERY bad - playsound(C, "bonk", 75, FALSE) + living_carbon.apply_damage(10) + living_carbon.apply_effect(2, WEAKEN) //Leaping into barbed wire is VERY bad + playsound(living_carbon, "bonk", 75, FALSE) ..() -/obj/structure/barricade/Collided(atom/movable/AM) +/obj/structure/barricade/Collided(atom/movable/atom_movable) ..() - if(istype(AM, /mob/living/carbon/xenomorph/crusher)) - var/mob/living/carbon/xenomorph/crusher/C = AM + if(istype(atom_movable, /mob/living/carbon/xenomorph/crusher)) + var/mob/living/carbon/xenomorph/crusher/living_carbon = atom_movable - if (!C.throwing) + if (!living_carbon.throwing) return if(crusher_resistant) - visible_message(SPAN_DANGER("[C] smashes into [src]!")) + visible_message(SPAN_DANGER("[living_carbon] smashes into [src]!")) take_damage(150) playsound(src, barricade_hitsound, 25, TRUE) - else if(!C.stat) - visible_message(SPAN_DANGER("[C] smashes through [src]!")) + else if(!living_carbon.stat) + visible_message(SPAN_DANGER("[living_carbon] smashes through [src]!")) deconstruct(FALSE) playsound(src, barricade_hitsound, 25, TRUE) @@ -163,8 +165,8 @@ if(closed) return NO_BLOCKED_MOVEMENT - var/obj/structure/S = locate(/obj/structure) in get_turf(mover) - if(S && S.climbable && !(S.flags_atom & ON_BORDER) && climbable && isliving(mover)) //Climbable objects allow you to universally climb over others + var/obj/structure/structure = locate(/obj/structure) in get_turf(mover) + if(structure && structure.climbable && !(structure.flags_atom & ON_BORDER) && climbable && isliving(mover)) //Climbable objects allow you to universally climb over others return NO_BLOCKED_MOVEMENT return ..() @@ -180,33 +182,33 @@ /obj/structure/barricade/attack_animal(mob/user as mob) return attack_alien(user) -/obj/structure/barricade/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/weapon/zombie_claws)) +/obj/structure/barricade/attackby(obj/item/item, mob/user) + if(istype(item, /obj/item/weapon/zombie_claws)) user.visible_message(SPAN_DANGER("The zombie smashed at the [src.barricade_type] barricade!"), SPAN_DANGER("You smack the [src.barricade_type] barricade!")) if(barricade_hitsound) playsound(src, barricade_hitsound, 35, 1) - hit_barricade(W) + hit_barricade(item) return - for(var/obj/effect/xenomorph/acid/A in src.loc) - if(A.acid_t == src) + for(var/obj/effect/xenomorph/acid/acid in src.loc) + if(acid.acid_t == src) to_chat(user, "You can't get near that, it's melting!") return - if(istype(W, /obj/item/stack/barbed_wire)) - var/obj/item/stack/barbed_wire/B = W + if(istype(item, /obj/item/stack/barbed_wire)) + var/obj/item/stack/barbed_wire/barbed_wire = item if(can_wire) - user.visible_message(SPAN_NOTICE("[user] starts setting up [W.name] on [src]."), - SPAN_NOTICE("You start setting up [W.name] on [src].")) + user.visible_message(SPAN_NOTICE("[user] starts setting up [item.name] on [src]."), + SPAN_NOTICE("You start setting up [item.name] on [src].")) if(do_after(user, 20, INTERRUPT_NO_NEEDHAND|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD, src) && can_wire) // Make sure there's still enough wire in the stack - if(!B.use(1)) + if(!barbed_wire.use(1)) return playsound(src.loc, 'sound/effects/barbed_wire_movement.ogg', 25, 1) - user.visible_message(SPAN_NOTICE("[user] sets up [W.name] on [src]."), - SPAN_NOTICE("You set up [W.name] on [src].")) + user.visible_message(SPAN_NOTICE("[user] sets up [item.name] on [src]."), + SPAN_NOTICE("You set up [item.name] on [src].")) maxhealth += 50 update_health(-50) @@ -218,7 +220,7 @@ update_icon() return - if(HAS_TRAIT(W, TRAIT_TOOL_WIRECUTTERS)) + if(HAS_TRAIT(item, TRAIT_TOOL_WIRECUTTERS)) if(is_wired) user.visible_message(SPAN_NOTICE("[user] begin removing the barbed wire on [src]."), SPAN_NOTICE("You begin removing the barbed wire on [src].")) @@ -240,27 +242,27 @@ new/obj/item/stack/barbed_wire( src.loc ) return - if(W.force > force_level_absorption) + if(item.force > force_level_absorption) ..() if(barricade_hitsound) playsound(src, barricade_hitsound, 35, 1) - hit_barricade(W) + hit_barricade(item) -/obj/structure/barricade/bullet_act(obj/item/projectile/P) - bullet_ping(P) +/obj/structure/barricade/bullet_act(obj/item/projectile/bullet) + bullet_ping(bullet) - if(P.ammo.damage_type == BURN) - P.damage = P.damage * burn_multiplier + if(bullet.ammo.damage_type == BURN) + bullet.damage = bullet.damage * burn_multiplier else - P.damage = P.damage * brute_multiplier + bullet.damage = bullet.damage * brute_projectile_multiplier - if(istype(P.ammo, /datum/ammo/xeno/boiler_gas)) + if(istype(bullet.ammo, /datum/ammo/xeno/boiler_gas)) take_damage(round(50 * burn_multiplier)) - else if(P.ammo.flags_ammo_behavior & AMMO_ANTISTRUCT) - take_damage(P.damage * ANTISTRUCT_DMG_MULT_BARRICADES) + else if(bullet.ammo.flags_ammo_behavior & AMMO_ANTISTRUCT) + take_damage(bullet.damage * ANTISTRUCT_DMG_MULT_BARRICADES) - take_damage(P.damage) + take_damage(bullet.damage) return TRUE @@ -282,11 +284,11 @@ /obj/structure/barricade/ex_act(severity, direction, cause_data) - for(var/obj/structure/barricade/B in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade - if(B.dir == reverse_direction(dir)) + for(var/obj/structure/barricade/barricade in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade + if(barricade.dir == reverse_direction(dir)) spawn(1) - if(B) - B.ex_act(severity, direction) + if(barricade) + barricade.ex_act(severity, direction) if(health <= 0) var/location = get_turf(src) handle_debris(severity, direction) @@ -321,15 +323,15 @@ new /datum/effects/acid(src, null, null) /obj/structure/barricade/flamer_fire_act(dam = BURN_LEVEL_TIER_1) - take_damage(dam * burn_multiplier) + take_damage(dam * burn_flame_multiplier) -/obj/structure/barricade/proc/hit_barricade(obj/item/I) - take_damage(I.force * 0.5 * brute_multiplier) +/obj/structure/barricade/proc/hit_barricade(obj/item/item) + take_damage(item.force * 0.5 * brute_multiplier) /obj/structure/barricade/proc/take_damage(damage) - for(var/obj/structure/barricade/B in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade - if(B.dir == reverse_direction(dir)) - B.update_health(damage) + for(var/obj/structure/barricade/barricade in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade + if(barricade.dir == reverse_direction(dir)) + barricade.update_health(damage) update_health(damage) @@ -357,12 +359,12 @@ if(50 to 75) damage_state = BARRICADE_DMG_SLIGHT if(75 to INFINITY) damage_state = BARRICADE_DMG_NONE -/obj/structure/barricade/proc/weld_cade(obj/item/tool/weldingtool/WT, mob/user) +/obj/structure/barricade/proc/weld_cade(obj/item/tool/weldingtool/welder, mob/user) if(!metallic) user.visible_message(SPAN_WARNING("You can't weld \the [src]!")) return FALSE - if(!(WT.remove_fuel(2, user))) + if(!(welder.remove_fuel(2, user))) return FALSE user.visible_message(SPAN_NOTICE("[user] begins repairing damage to [src]."), @@ -413,20 +415,20 @@ return ..() -/obj/structure/barricade/proc/try_nailgun_usage(obj/item/W, mob/user) - if(length(repair_materials) == 0 || health >= maxhealth || !istype(W, /obj/item/weapon/gun/smg/nailgun)) +/obj/structure/barricade/proc/try_nailgun_usage(obj/item/item, mob/user) + if(length(repair_materials) == 0 || health >= maxhealth || !istype(item, /obj/item/weapon/gun/smg/nailgun)) return FALSE - var/obj/item/weapon/gun/smg/nailgun/NG = W + var/obj/item/weapon/gun/smg/nailgun/nailgun = item - if(!NG.in_chamber || !NG.current_mag || NG.current_mag.current_rounds < 3) + if(!nailgun.in_chamber || !nailgun.current_mag || nailgun.current_mag.current_rounds < 3) to_chat(user, SPAN_WARNING("You require at least 4 nails to complete this task!")) return FALSE // Check if either hand has a metal stack by checking the weapon offhand // Presume the material is a sheet until proven otherwise. var/obj/item/stack/sheet/material = null - if(user.l_hand == NG) + if(user.l_hand == nailgun) material = user.r_hand else material = user.l_hand @@ -445,8 +447,8 @@ to_chat(user, SPAN_WARNING("You'll need some adequate repair material in your other hand to patch up [src]!")) return FALSE - var/soundchannel = playsound(src, NG.repair_sound, 25, 1) - if(!do_after(user, NG.nailing_speed, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src)) + var/soundchannel = playsound(src, nailgun.repair_sound, 25, 1) + if(!do_after(user, nailgun.nailing_speed, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, src)) playsound(src, null, channel = soundchannel) return FALSE @@ -454,7 +456,7 @@ to_chat(user, SPAN_WARNING("You seems to have misplaced the repair material!")) return FALSE - if(!NG.in_chamber || !NG.current_mag || NG.current_mag.current_rounds < 3) + if(!nailgun.in_chamber || !nailgun.current_mag || nailgun.current_mag.current_rounds < 3) to_chat(user, SPAN_WARNING("You require at least 4 nails to complete this task!")) return FALSE @@ -462,7 +464,7 @@ to_chat(user, SPAN_WARNING("You nail [material] to [src], restoring some of its integrity!")) update_damage_state() material.use(1) - NG.current_mag.current_rounds -= 3 - NG.in_chamber = null - NG.load_into_chamber() + nailgun.current_mag.current_rounds -= 3 + nailgun.in_chamber = null + nailgun.load_into_chamber() return TRUE diff --git a/code/game/objects/structures/barricade/metal.dm b/code/game/objects/structures/barricade/metal.dm index 40f784b064e4..4056ac9021f8 100644 --- a/code/game/objects/structures/barricade/metal.dm +++ b/code/game/objects/structures/barricade/metal.dm @@ -39,12 +39,12 @@ . += SPAN_NOTICE("The cade is protected by a biohazardous upgrade.") if(BARRICADE_UPGRADE_BRUTE) . += SPAN_NOTICE("The cade is protected by a reinforced upgrade.") - if(BARRICADE_UPGRADE_EXPLOSIVE) - . += SPAN_NOTICE("The cade is protected by an explosive upgrade.") + if(BARRICADE_UPGRADE_ANTIFF) + . += SPAN_NOTICE("The cade is protected by a composite upgrade.") -/obj/structure/barricade/metal/attackby(obj/item/W, mob/user) - if(iswelder(W)) - if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH)) +/obj/structure/barricade/metal/attackby(obj/item/item, mob/user) + if(iswelder(item)) + if(!HAS_TRAIT(item, TRAIT_TOOL_BLOWTORCH)) to_chat(user, SPAN_WARNING("You need a stronger blowtorch!")) return if(user.action_busy) @@ -52,7 +52,7 @@ if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_TRAINED)) to_chat(user, SPAN_WARNING("You're not trained to repair [src]...")) return - var/obj/item/tool/weldingtool/WT = W + var/obj/item/tool/weldingtool/welder = item if(damage_state == BARRICADE_DMG_HEAVY) to_chat(user, SPAN_WARNING("[src] has sustained too much structural damage to be repaired.")) return @@ -61,10 +61,10 @@ to_chat(user, SPAN_WARNING("[src] doesn't need repairs.")) return - weld_cade(WT, user) + weld_cade(welder, user) return - if(try_nailgun_usage(W, user)) + if(try_nailgun_usage(item, user)) return for(var/obj/effect/xenomorph/acid/A in src.loc) @@ -74,7 +74,7 @@ switch(build_state) if(BARRICADE_BSTATE_SECURED) //Fully constructed step. Use screwdriver to remove the protection panels to reveal the bolts - if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER)) + if(HAS_TRAIT(item, TRAIT_TOOL_SCREWDRIVER)) if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) to_chat(user, SPAN_WARNING("You are not trained to touch [src]...")) return @@ -88,16 +88,16 @@ build_state = BARRICADE_BSTATE_UNSECURED return - if(istype(W, /obj/item/stack/sheet/metal)) + if(istype(item, /obj/item/stack/sheet/metal)) if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) to_chat(user, SPAN_WARNING("You are not trained to touch [src]...")) return if(upgraded) to_chat(user, SPAN_NOTICE("This barricade is already upgraded.")) return - var/obj/item/stack/sheet/metal/M = W + var/obj/item/stack/sheet/metal/metal = item if(user.client?.prefs?.no_radials_preference) - var/choice = tgui_input_list(user, "Choose an upgrade to apply to the barricade", "Apply Upgrade", list(BARRICADE_UPGRADE_BURN, BARRICADE_UPGRADE_BRUTE, BARRICADE_UPGRADE_EXPLOSIVE)) + var/choice = tgui_input_list(user, "Choose an upgrade to apply to the barricade", "Apply Upgrade", list(BARRICADE_UPGRADE_BURN, BARRICADE_UPGRADE_BRUTE, BARRICADE_UPGRADE_ANTIFF)) if(!choice) return if(!user.Adjacent(src)) @@ -106,33 +106,37 @@ if(upgraded) to_chat(user, SPAN_NOTICE("This barricade is already upgraded.")) return - if(M.get_amount() < 2) + if(metal.get_amount() < 2) to_chat(user, SPAN_NOTICE("You lack the required metal.")) return - if((usr.get_active_hand()) != M) - to_chat(user, SPAN_WARNING("You must be holding the [M] to upgrade \the [src]!")) + if((usr.get_active_hand()) != metal) + to_chat(user, SPAN_WARNING("You must be holding the [metal] to upgrade \the [src]!")) return switch(choice) if(BARRICADE_UPGRADE_BURN) burn_multiplier = 0.75 + burn_flame_multiplier = 0.75 upgraded = BARRICADE_UPGRADE_BURN to_chat(user, SPAN_NOTICE("You applied a biohazardous upgrade.")) if(BARRICADE_UPGRADE_BRUTE) brute_multiplier = 0.75 + brute_projectile_multiplier = 0.75 upgraded = BARRICADE_UPGRADE_BRUTE to_chat(user, SPAN_NOTICE("You applied a reinforced upgrade.")) - if(BARRICADE_UPGRADE_EXPLOSIVE) - explosive_multiplier = 0.75 - upgraded = BARRICADE_UPGRADE_EXPLOSIVE - to_chat(user, SPAN_NOTICE("You applied an explosive upgrade.")) + if(BARRICADE_UPGRADE_ANTIFF) + explosive_multiplier = 0.5 + brute_projectile_multiplier = 0.5 + burn_flame_multiplier = 0.5 + upgraded = BARRICADE_UPGRADE_ANTIFF + to_chat(user, SPAN_NOTICE("You applied a composite upgrade.")) - M.use(2) + metal.use(2) user.count_niche_stat(STATISTICS_NICHE_UPGRADE_CADES) update_icon() return else - var/static/list/cade_types = list(BARRICADE_UPGRADE_EXPLOSIVE = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "explosive_obj"), BARRICADE_UPGRADE_BRUTE = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "brute_obj"), BARRICADE_UPGRADE_BURN = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "burn_obj")) + var/static/list/cade_types = list(BARRICADE_UPGRADE_ANTIFF = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "explosive_obj"), BARRICADE_UPGRADE_BRUTE = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "brute_obj"), BARRICADE_UPGRADE_BURN = image(icon = 'icons/obj/structures/barricades.dmi', icon_state = "burn_obj")) var/choice = show_radial_menu(user, src, cade_types, require_near = TRUE) if(!choice) return @@ -142,33 +146,37 @@ if(upgraded) to_chat(user, SPAN_NOTICE("This barricade is already upgraded.")) return - if(M.get_amount() < 2) + if(metal.get_amount() < 2) to_chat(user, SPAN_NOTICE("You lack the required metal.")) return - if((usr.get_active_hand()) != M) - to_chat(user, SPAN_WARNING("You must be holding the [M] to upgrade \the [src]!")) + if((usr.get_active_hand()) != metal) + to_chat(user, SPAN_WARNING("You must be holding the [metal] to upgrade \the [src]!")) return switch(choice) if(BARRICADE_UPGRADE_BURN) burn_multiplier = 0.75 + burn_flame_multiplier = 0.75 upgraded = BARRICADE_UPGRADE_BURN to_chat(user, SPAN_NOTICE("You applied a biohazardous upgrade.")) if(BARRICADE_UPGRADE_BRUTE) brute_multiplier = 0.75 + brute_projectile_multiplier = 0.75 upgraded = BARRICADE_UPGRADE_BRUTE to_chat(user, SPAN_NOTICE("You applied a reinforced upgrade.")) - if(BARRICADE_UPGRADE_EXPLOSIVE) - explosive_multiplier = 0.75 - upgraded = BARRICADE_UPGRADE_EXPLOSIVE - to_chat(user, SPAN_NOTICE("You applied an explosive upgrade.")) + if(BARRICADE_UPGRADE_ANTIFF) + explosive_multiplier = 0.5 + brute_projectile_multiplier = 0.5 + burn_flame_multiplier = 0.5 + upgraded = BARRICADE_UPGRADE_ANTIFF + to_chat(user, SPAN_NOTICE("You applied a composite upgrade.")) - M.use(2) + metal.use(2) user.count_niche_stat(STATISTICS_NICHE_UPGRADE_CADES) update_icon() return - if(HAS_TRAIT(W, TRAIT_TOOL_MULTITOOL)) + if(HAS_TRAIT(item, TRAIT_TOOL_MULTITOOL)) if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) to_chat(user, SPAN_WARNING("You are not trained to touch [src]...")) return @@ -181,13 +189,15 @@ upgraded = null explosive_multiplier = initial(explosive_multiplier) brute_multiplier = initial(brute_multiplier) + brute_projectile_multiplier = initial(brute_projectile_multiplier) burn_multiplier = initial(burn_multiplier) + burn_flame_multiplier = initial(burn_flame_multiplier) new stack_type (loc, 1) update_icon() return if(BARRICADE_BSTATE_UNSECURED) //Protection panel removed step. Screwdriver to put the panel back, wrench to unsecure the anchor bolts - if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER)) + if(HAS_TRAIT(item, TRAIT_TOOL_SCREWDRIVER)) if(user.action_busy) return if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) @@ -199,7 +209,7 @@ SPAN_NOTICE("You set [src]'s protection panel back.")) build_state = BARRICADE_BSTATE_SECURED return - if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) + if(HAS_TRAIT(item, TRAIT_TOOL_WRENCH)) if(user.action_busy) return if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) @@ -214,7 +224,7 @@ update_icon() //unanchored changes layer return if(BARRICADE_BSTATE_MOVABLE) //Anchor bolts loosened step. Apply crowbar to unseat the panel and take apart the whole thing. Apply wrench to resecure anchor bolts - if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) + if(HAS_TRAIT(item, TRAIT_TOOL_WRENCH)) if(user.action_busy) return if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) @@ -224,8 +234,8 @@ if(B != src && B.dir == dir) to_chat(user, SPAN_WARNING("There's already a barricade here.")) return - var/turf/open/T = loc - if(!(istype(T) && T.allow_construction)) + var/turf/open/turf = loc + if(!(istype(turf) && turf.allow_construction)) to_chat(user, SPAN_WARNING("[src] must be secured on a proper surface!")) return playsound(src.loc, 'sound/items/Ratchet.ogg', 25, 1) @@ -236,7 +246,7 @@ anchored = TRUE update_icon() //unanchored changes layer return - if(HAS_TRAIT(W, TRAIT_TOOL_CROWBAR)) + if(HAS_TRAIT(item, TRAIT_TOOL_CROWBAR)) if(user.action_busy) return if(!skillcheck(user, SKILL_CONSTRUCTION, SKILL_CONSTRUCTION_TRAINED)) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 05355feeb154..cf0374c09ab4 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -135,21 +135,23 @@ return stored_units /obj/structure/closet/proc/store_mobs(stored_units) - for(var/mob/M in src.loc) + for(var/mob/cur_mob in src.loc) if(stored_units + mob_size > storage_capacity) break - if(istype (M, /mob/dead/observer)) + if(istype (cur_mob, /mob/dead/observer)) continue - if(M.buckled) + if(cur_mob.buckled) + continue + if(cur_mob.anchored) continue - M.forceMove(src) + cur_mob.forceMove(src) stored_units += mob_size return stored_units /obj/structure/closet/proc/toggle(mob/living/user) user.next_move = world.time + 5 - if(!(src.opened ? src.close() : src.open())) + if(!(src.opened ? src.close(user) : src.open())) to_chat(user, SPAN_NOTICE("It won't budge!")) return diff --git a/code/game/objects/structures/misc.dm b/code/game/objects/structures/misc.dm index 60f29c8b40e4..9323bca2877e 100644 --- a/code/game/objects/structures/misc.dm +++ b/code/game/objects/structures/misc.dm @@ -143,7 +143,7 @@ unslashable = TRUE unacidable = TRUE health = null - layer = TURF_LAYER + layer = ABOVE_TURF_LAYER//Being on turf layer was causing issues with cameras. This SHOULDN'T cause any problems. plane = FLOOR_PLANE density = FALSE opacity = FALSE diff --git a/code/game/objects/structures/pipes/pipes.dm b/code/game/objects/structures/pipes/pipes.dm index aa5f56fb5d8c..9f2b70c70661 100644 --- a/code/game/objects/structures/pipes/pipes.dm +++ b/code/game/objects/structures/pipes/pipes.dm @@ -14,6 +14,8 @@ var/ventcrawl_message_busy = FALSE //Prevent spamming + /// Whether or not the pipe will explode (when on the Almayer) during hijack + var/explodey = TRUE /// The grenade subtypes that pipes will use when they explode var/static/list/exploding_types = list(/obj/item/explosive/grenade/high_explosive/bursting_pipe, /obj/item/explosive/grenade/incendiary/bursting_pipe) @@ -40,7 +42,8 @@ if(!is_mainship_level(z)) return - GLOB.mainship_pipes += src + if(explodey) + GLOB.mainship_pipes += src /obj/structure/pipes/Destroy() for(var/mob/living/M in src) diff --git a/code/game/objects/structures/pipes/standard/manifolds.dm b/code/game/objects/structures/pipes/standard/manifolds.dm index f7bd04ee3fb7..dfbc027455b6 100644 --- a/code/game/objects/structures/pipes/standard/manifolds.dm +++ b/code/game/objects/structures/pipes/standard/manifolds.dm @@ -104,6 +104,10 @@ layer = ATMOS_PIPE_SUPPLY_LAYER color = PIPE_COLOR_BLUE +/obj/structure/pipes/standard/manifold/hidden/supply/no_boom + name = "Reinforced Air supply pipe manifold" + explodey = FALSE + /obj/structure/pipes/standard/manifold/hidden/yellow color = PIPE_COLOR_YELLOW @@ -182,6 +186,10 @@ layer = ATMOS_PIPE_SUPPLY_LAYER color = PIPE_COLOR_BLUE +/obj/structure/pipes/standard/manifold/fourway/hidden/supply/no_boom + name = "reinforced 4-way air supply pipe manifold" + explodey = FALSE + /obj/structure/pipes/standard/manifold/fourway/hidden/yellow color = PIPE_COLOR_YELLOW diff --git a/code/game/objects/structures/pipes/standard/simple.dm b/code/game/objects/structures/pipes/standard/simple.dm index 7101bb3dd95f..93a92e51f71b 100644 --- a/code/game/objects/structures/pipes/standard/simple.dm +++ b/code/game/objects/structures/pipes/standard/simple.dm @@ -104,6 +104,10 @@ layer = ATMOS_PIPE_SUPPLY_LAYER color = PIPE_COLOR_BLUE +/obj/structure/pipes/standard/simple/hidden/supply/no_boom + name = "Reinforced Air supply pipe" + explodey = FALSE + /obj/structure/pipes/standard/simple/hidden/yellow color = PIPE_COLOR_YELLOW diff --git a/code/game/objects/structures/pipes/standard/standard_misc.dm b/code/game/objects/structures/pipes/standard/standard_misc.dm index a50774552b03..dc52da57c750 100644 --- a/code/game/objects/structures/pipes/standard/standard_misc.dm +++ b/code/game/objects/structures/pipes/standard/standard_misc.dm @@ -107,6 +107,10 @@ layer = ATMOS_PIPE_SUPPLY_LAYER color = PIPE_COLOR_BLUE +/obj/structure/pipes/standard/cap/hidden/supply/no_boom + name = "reinforced supply pipe endcap" + explodey = FALSE + /obj/structure/pipes/standard/tank icon = 'icons/obj/pipes/tank.dmi' diff --git a/code/game/objects/structures/pipes/vents/pump_scrubber.dm b/code/game/objects/structures/pipes/vents/pump_scrubber.dm index d0dd3f8301a7..a4565c610ad5 100644 --- a/code/game/objects/structures/pipes/vents/pump_scrubber.dm +++ b/code/game/objects/structures/pipes/vents/pump_scrubber.dm @@ -4,6 +4,10 @@ name = "Air Scrubber" vent_icon = "scrubber" +/obj/structure/pipes/vents/scrubber/no_boom + name = "Reinforced Air Scrubber" + explodey = FALSE + /obj/structure/pipes/vents/scrubber/on icon_state = "on" @@ -13,6 +17,10 @@ icon_state = "map_vent" name = "Air Vent" +/obj/structure/pipes/vents/pump/no_boom + name = "Reinforced Air Vent" + explodey = FALSE + /obj/structure/pipes/vents/pump/on icon_state = "on" diff --git a/code/game/objects/structures/props.dm b/code/game/objects/structures/props.dm index f6905d4d044d..1a91650c620a 100644 --- a/code/game/objects/structures/props.dm +++ b/code/game/objects/structures/props.dm @@ -24,7 +24,7 @@ . = ..() if(isxeno(user)) return - else if (ishuman(user) && istype(W, /obj/item/tool/wrench)) + else if (ishuman(user) && HAS_TRAIT(W, TRAIT_TOOL_WRENCH)) on = !on visible_message("You wrench the controls of \the [src]. The drill jumps to life." , "[user] wrenches the controls of \the [src]. The drill jumps to life.") @@ -501,7 +501,7 @@ . = ..() if(isxeno(user)) return - else if (ishuman(user) && istype(W, /obj/item/tool/crowbar)) + else if (ishuman(user) && HAS_TRAIT(W, TRAIT_TOOL_CROWBAR)) on = !on visible_message("You pry at the control valve on [src]. The machine shudders." , "[user] pries at the control valve on [src]. The entire machine shudders.") diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm index cacb8232fd60..fbd6920875ad 100644 --- a/code/game/objects/structures/signs.dm +++ b/code/game/objects/structures/signs.dm @@ -70,7 +70,7 @@ /obj/structure/sign/kiddieplaque name = "AI developers plaque" - desc = "Next to the extremely long list of names and job titles, there is a drawing of a little child. The child appears to be retarded. Beneath the image, someone has scratched the word \"PACKETS\"" + desc = "Next to the extremely long list of names and job titles, there is a drawing of a little child. Beneath the image, someone has scratched the word \"PACKETS\"" icon_state = "kiddieplaque" /obj/structure/sign/arcturianstopsign diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index bda4b60ca21e..7979994915f4 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -208,6 +208,20 @@ return ..() +/obj/structure/bed/roller/Collided(atom/movable/moving_atom) + if(!isxeno(moving_atom)) + return ..() + + if(buckled_mob && buckled_mob.stat != DEAD) + return ..() + + if(buckled_bodybag) + var/mob/mob_in_bodybag = locate(/mob) in buckled_bodybag + if(mob_in_bodybag && mob_in_bodybag.stat != DEAD) + return ..() + + return + /obj/item/roller name = "roller bed" desc = "A collapsed roller bed that can be carried around." diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 7537d47c941f..4186ae8608a9 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -295,6 +295,11 @@ name = "Delta squad chair" desc = "A simple chair permanently attached to the floor. Covered with a squeaky and way too hard faux-leather, unevenly painted in Delta squad blue. This chair is most likely to be the first to fight and first to die." +/obj/structure/bed/chair/comfy/ares + icon_state = "comfychair_ares" + name = "AI core chair" + desc = "A functional chair designed for comfortably sitting a single person with intent to facilitate interactions with the ship AI." + /obj/structure/bed/chair/office anchored = FALSE drag_delay = 1 //Pulling something on wheels is easy diff --git a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm index e306b894b021..37d46cbe6d5d 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm @@ -289,11 +289,12 @@ if(buckled_human.stat == DEAD ) buckled_mob_density = FALSE - . = ..() - var/mob/dead/observer/G = ghost_of_buckled_mob var/datum/mind/M = G?.mind ghost_of_buckled_mob = null + + . = ..() //Very important that this comes after, since it deletes the nest and clears ghost_of_buckled_mob + if(!istype(buckled_human) || !istype(G) || !istype(M) || buckled_human.undefibbable || buckled_human.mind || M.original != buckled_human || buckled_human.chestburst) return // Zealous checking as most is handled by ghost code to_chat(G, FONT_SIZE_HUGE(SPAN_DANGER("You have been freed from your nest and may go back to your body! (Look for 'Re-enter Corpse' in Ghost verbs, or click here!)"))) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 5c084ce94cbc..cccc1211bfb0 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -121,7 +121,7 @@ cistern_overlay.icon_state = "cistern[cistern]" /obj/structure/toilet/attackby(obj/item/I, mob/living/user) - if(istype(I, /obj/item/tool/crowbar)) + if(HAS_TRAIT(I, TRAIT_TOOL_CROWBAR)) to_chat(user, SPAN_NOTICE("You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"].")) playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 25, 1) if(do_after(user, 30, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm index dcc854bfa71d..b760340004f5 100644 --- a/code/game/supplyshuttle.dm +++ b/code/game/supplyshuttle.dm @@ -1015,6 +1015,7 @@ var/datum/controller/supply/supply_controller = new() to_chat(usr, SPAN_DANGER("Current retrieval load has reached maximum capacity.")) return + var/datum/ares_link/link = GLOB.ares_link for(var/i=1, i<=supply_controller.requestlist.len, i++) var/datum/supply_order/SO = supply_controller.requestlist[i] if(SO.ordernum == ordernum) @@ -1030,6 +1031,12 @@ var/datum/controller/supply/supply_controller = new() temp += "
Back Main Menu" supply_order.approvedby = usr.name msg_admin_niche("[usr] confirmed supply order of [supply_pack.name].") + var/pack_source = "Cargo Hold" + var/pack_name = supply_pack.name + if(supply_pack.dollar_cost) + pack_source = "Unknown" + pack_name = "Unknown" + link.log_ares_requisition(pack_source, pack_name, usr) else temp = "Not enough money left.
" temp += "
Back Main Menu" diff --git a/code/game/turfs/floor.dm b/code/game/turfs/floor.dm index 4a600d4d033b..dc2cda0c2c2a 100644 --- a/code/game/turfs/floor.dm +++ b/code/game/turfs/floor.dm @@ -148,7 +148,7 @@ if(src.weeds) return weeds.attackby(hitting_item,user) - if(istype(hitting_item, /obj/item/tool/crowbar) && (tool_flags & (REMOVE_CROWBAR|BREAK_CROWBAR))) + if(HAS_TRAIT(hitting_item, TRAIT_TOOL_CROWBAR) && (tool_flags & (REMOVE_CROWBAR|BREAK_CROWBAR))) if(broken || burnt) to_chat(user, SPAN_WARNING("You remove the broken tiles.")) else diff --git a/code/game/turfs/floor_types.dm b/code/game/turfs/floor_types.dm index 25682f00df29..4e47fd004f74 100644 --- a/code/game/turfs/floor_types.dm +++ b/code/game/turfs/floor_types.dm @@ -272,7 +272,9 @@ /turf/open/floor/almayer/uscm/directional icon_state = "logo_directional" - +/turf/open/floor/almayer/no_build + allow_construction = FALSE + hull_floor = TRUE // RESEARCH STUFF /turf/open/floor/almayer/research/containment/entrance diff --git a/code/game/turfs/walls/wall_types.dm b/code/game/turfs/walls/wall_types.dm index 702cbd35560c..04c5a0735824 100644 --- a/code/game/turfs/walls/wall_types.dm +++ b/code/game/turfs/walls/wall_types.dm @@ -710,6 +710,17 @@ for(var/obj/effect/alien/weeds/node/weed_node in contents) qdel(weed_node) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) + +/turf/closed/wall/resin/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + /turf/closed/wall/resin/pillar name = "resin pillar segment" hull = TRUE diff --git a/code/game/turfs/walls/walls.dm b/code/game/turfs/walls/walls.dm index 411ff8182661..3599d5bb980b 100644 --- a/code/game/turfs/walls/walls.dm +++ b/code/game/turfs/walls/walls.dm @@ -98,11 +98,15 @@ qdel(found_nest) //nests are built on walls, no walls, no nest /turf/closed/wall/MouseDrop_T(mob/current_mob, mob/user) + if(!ismob(current_mob)) + return + if(acided_hole) if(current_mob == user && isxeno(user)) acided_hole.use_wall_hole(user) return - if(isxeno(user)) + + if(isxeno(user) && istype(user.get_active_hand(), /obj/item/grab)) var/mob/living/carbon/xenomorph/user_as_xenomorph = user user_as_xenomorph.do_nesting_host(current_mob, src) ..() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index d21188615785..ba5d52a23f97 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -67,6 +67,7 @@ var/list/admin_verbs_default = list( /datum/admins/proc/subtlemessageall, /datum/admins/proc/alertall, /datum/admins/proc/imaginary_friend, + /client/proc/toggle_ares_ping, ) var/list/admin_verbs_admin = list( @@ -176,6 +177,7 @@ var/list/admin_verbs_server = list( /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ /client/proc/cmd_debug_del_all, /datum/admins/proc/togglejoin, + /client/proc/toggle_cdn, ) var/list/admin_verbs_debug = list( @@ -576,6 +578,16 @@ var/list/roundstart_mod_verbs = list( message_admins("[key_name(usr)] announced a random fact.") SSticker.mode?.declare_fun_facts() +/client/proc/toggle_ares_ping() + set name = "Toggle ARES notification sound" + set category = "Preferences.Logs" + + prefs.toggles_sound ^= SOUND_ARES_MESSAGE + if (prefs.toggles_sound & SOUND_ARES_MESSAGE) + to_chat(usr, SPAN_BOLDNOTICE("You will now hear a ping for ARES messages.")) + else + to_chat(usr, SPAN_BOLDNOTICE("You will no longer hear a ping for ARES messages.")) + #undef MAX_WARNS #undef AUTOBANTIME diff --git a/code/modules/admin/tabs/admin_tab.dm b/code/modules/admin/tabs/admin_tab.dm index 11ee49b65e61..c0ffeada9883 100644 --- a/code/modules/admin/tabs/admin_tab.dm +++ b/code/modules/admin/tabs/admin_tab.dm @@ -680,10 +680,14 @@ /proc/set_lz_resin_allowed(allowed = TRUE) if(allowed) for(var/area/A in all_areas) + if(A.flags_area & AREA_UNWEEDABLE) + continue A.is_resin_allowed = TRUE msg_admin_niche("Areas close to landing zones are now weedable.") else for(var/area/A in all_areas) + if(A.flags_area & AREA_UNWEEDABLE) + continue A.is_resin_allowed = initial(A.is_resin_allowed) msg_admin_niche("Areas close to landing zones cannot be weeded now.") GLOB.resin_lz_allowed = allowed diff --git a/code/modules/admin/tabs/event_tab.dm b/code/modules/admin/tabs/event_tab.dm index 8fca782ecd63..febc1550fca0 100644 --- a/code/modules/admin/tabs/event_tab.dm +++ b/code/modules/admin/tabs/event_tab.dm @@ -440,7 +440,7 @@ return var/confirm = tgui_alert(usr, "Are you sure you want to hijack [dropship]?", "Force hijack", list("Yes", "No")) == "Yes" - if(!confirm) + if(!confirm) return var/obj/structure/machinery/computer/shuttle/dropship/flight/computer = dropship.getControlConsole() @@ -535,19 +535,15 @@ if(!input) return FALSE - for(var/obj/structure/machinery/computer/almayer_control/C in machines) - if(!(C.inoperable())) -// var/obj/item/paper/P = new /obj/item/paper(C.loc)//Don't need a printed copy currently. -// P.name = "'[MAIN_AI_SYSTEM] Update.'" -// P.info = input -// P.update_icon() - C.messagetitle.Add("[MAIN_AI_SYSTEM] Update") - C.messagetext.Add(input) - ai_announcement(input) - message_admins("[key_name_admin(src)] has created an AI comms report") - log_admin("AI comms report: [input]") - else - to_chat(usr, SPAN_WARNING("[MAIN_AI_SYSTEM] is not responding. It may be offline or destroyed.")) + var/datum/ares_link/link = GLOB.ares_link + if(link.p_interface.inoperable()) + to_chat(usr, SPAN_WARNING("[MAIN_AI_SYSTEM] is not responding. It may be offline or destroyed.")) + return + + ai_announcement(input) + message_admins("[key_name_admin(src)] has created an AI comms report") + log_admin("AI comms report: [input]") + /client/proc/cmd_admin_create_AI_apollo_report() set name = "Report: ARES Apollo" @@ -560,19 +556,19 @@ if(!input) return FALSE - for(var/obj/structure/machinery/computer/almayer_control/console in machines) - if(console.inoperable()) - to_chat(usr, SPAN_WARNING("[MAIN_AI_SYSTEM] is not responding. It may be offline or destroyed.")) - return - else - var/datum/language/apollo = GLOB.all_languages[LANGUAGE_APOLLO] - for(var/mob/living/silicon/decoy/ship_ai/AI in ai_mob_list) - apollo.broadcast(AI, input) - for(var/mob/listener in (GLOB.human_mob_list + GLOB.dead_mob_list)) - if(listener.hear_apollo())//Only plays sound to mobs and not observers, to reduce spam. - playsound_client(listener.client, sound('sound/misc/interference.ogg'), listener, vol = 45) - message_admins("[key_name_admin(src)] has created an AI Apollo report") - log_admin("AI Apollo report: [input]") + var/datum/ares_link/link = GLOB.ares_link + if(link.p_apollo.inoperable()) + to_chat(usr, SPAN_WARNING("[MAIN_AI_SYSTEM] is not responding. It may be offline or destroyed.")) + return FALSE + + var/datum/language/apollo/apollo = GLOB.all_languages[LANGUAGE_APOLLO] + for(var/mob/living/silicon/decoy/ship_ai/AI in ai_mob_list) + apollo.broadcast(AI, input) + for(var/mob/listener as anything in (GLOB.human_mob_list + GLOB.dead_mob_list)) + if(listener.hear_apollo())//Only plays sound to mobs and not observers, to reduce spam. + playsound_client(listener.client, sound('sound/misc/interference.ogg'), listener, vol = 45) + message_admins("[key_name_admin(src)] has created an AI APOLLO report") + log_admin("AI APOLLO report: [input]") /client/proc/cmd_admin_create_AI_shipwide_report() set name = "Report: ARES Shipwide" @@ -584,19 +580,14 @@ var/input = input(usr, "This is an announcement type message from the ship's AI. This will be announced to every conscious human on Almayer z-level. Be aware, this will work even if ARES unpowered/destroyed. Check with online staff before you send this.", "What?", "") as message|null if(!input) return FALSE + for(var/obj/structure/machinery/ares/processor/interface/processor in machines) + if(processor.inoperable()) + to_chat(usr, SPAN_WARNING("[MAIN_AI_SYSTEM] is not responding. It may be offline or destroyed.")) + return - for(var/obj/structure/machinery/computer/almayer_control/C in machines) - if(!(C.inoperable())) -// var/obj/item/paper/P = new /obj/item/paper(C.loc)//Don't need a printed copy currently. -// P.name = "'[MAIN_AI_SYSTEM] Update.'" -// P.info = input -// P.update_icon() - C.messagetitle.Add("[MAIN_AI_SYSTEM] Shipwide Update") - C.messagetext.Add(input) - - shipwide_ai_announcement(input) - message_admins("[key_name_admin(src)] has created an AI shipwide report") - log_admin("[key_name_admin(src)] AI shipwide report: [input]") + shipwide_ai_announcement(input) + message_admins("[key_name_admin(src)] has created an AI shipwide report") + log_admin("[key_name_admin(src)] AI shipwide report: [input]") /client/proc/cmd_admin_create_predator_report() set name = "Report: Yautja AI" @@ -753,7 +744,7 @@ create_humans_html = replacetext(create_humans_html, "null /* object types */", "\"[equipment_presets]\"") create_humans_html = replacetext(create_humans_html, "/* href token */", RawHrefToken(forceGlobal = TRUE)) - show_browser(user, replacetext(create_humans_html, "/* ref src */", "\ref[src]"), "Create Humans", "create_humans", "size=450x630") + show_browser(user, replacetext(create_humans_html, "/* ref src */", "\ref[src]"), "Create Humans", "create_humans", "size=450x720") /client/proc/create_humans() set name = "Create Humans" @@ -839,7 +830,6 @@ if(isnull(OBShell.double_explosion_delay)) return statsmessage = "Custom HE OB ([OBShell.name]) Stats from [key_name(usr)]: Clear Power: [OBShell.clear_power], Clear Falloff: [OBShell.clear_falloff], Clear Delay: [OBShell.clear_delay], Blast Power: [OBShell.standard_power], Blast Falloff: [OBShell.standard_falloff], Blast Delay: [OBShell.double_explosion_delay]." warhead = OBShell - qdel(OBShell) if("Custom Cluster") var/obj/structure/ob_ammo/warhead/cluster/OBShell = new OBShell.name = input("What name should the warhead have?", "Set name", "Cluster orbital warhead") @@ -856,7 +846,6 @@ if(isnull(OBShell.explosion_falloff)) return statsmessage = "Custom Cluster OB ([OBShell.name]) Stats from [key_name(usr)]: Salvos: [OBShell.total_amount], Shot per Salvo: [OBShell.instant_amount], Explosion Power: [OBShell.explosion_power], Explosion Falloff: [OBShell.explosion_falloff]." warhead = OBShell - qdel(OBShell) if("Custom Incendiary") var/obj/structure/ob_ammo/warhead/incendiary/OBShell = new OBShell.name = input("What name should the warhead have?", "Set name", "Incendiary orbital warhead") @@ -885,19 +874,28 @@ if(isnull(OBShell.fire_color)) return statsmessage = "Custom Incendiary OB ([OBShell.name]) Stats from [key_name(usr)]: Clear Power: [OBShell.clear_power], Clear Falloff: [OBShell.clear_falloff], Clear Delay: [OBShell.clear_delay], Fire Distance: [OBShell.distance], Fire Duration: [OBShell.fire_level], Fire Strength: [OBShell.burn_level]." warhead = OBShell - qdel(OBShell) if(custom) - if(alert(usr, statsmessage, "Confirm Stats", "Yes", "No") != "Yes") return + if(alert(usr, statsmessage, "Confirm Stats", "Yes", "No") != "Yes") + qdel(warhead) + return message_admins(statsmessage) var/turf/target = get_turf(usr.loc) if(alert(usr, "Fire or Spawn Warhead?", "Mode", "Fire", "Spawn") == "Fire") - if(alert("Are you SURE you want to do this? It will create an OB explosion!",, "Yes", "No") != "Yes") return + if(alert("Are you SURE you want to do this? It will create an OB explosion!",, "Yes", "No") != "Yes") + qdel(warhead) + return + message_admins("[key_name(usr)] has fired \an [warhead.name] at ([target.x],[target.y],[target.z]).") warhead.warhead_impact(target) - QDEL_IN(warhead, OB_CRASHING_DOWN) + + if(istype(warhead, /obj/structure/ob_ammo/warhead/cluster)) + // so the user's screen can shake for the duration of the cluster, otherwise we get a runtime. + QDEL_IN(warhead, OB_CLUSTER_DURATION) + else + QDEL_IN(warhead, OB_CRASHING_DOWN) else warhead.loc = target @@ -967,12 +965,17 @@ else var/faction = tgui_input_list(usr, "What faction do you wish to provide a bioscan for?", "Bioscan Faction", list("Xeno","Marine","Yautja"), 20 SECONDS) var/variance = tgui_input_number(usr, "How variable do you want the scan to be? (+ or - an amount from truth)", "Variance", 2, 10, 0, 20 SECONDS) + message_admins("BIOSCAN: [key_name(usr)] admin-triggered a bioscan for [faction].") GLOB.bioscan_data.get_scan_data() switch(faction) if("Xeno") GLOB.bioscan_data.qm_bioscan(variance) if("Marine") - GLOB.bioscan_data.ares_bioscan(FALSE, variance) + var/force_check = tgui_alert(usr, "Do you wish to force ARES to display the bioscan?", "Display force", list("Yes", "No"), 20 SECONDS) + var/force_status = FALSE + if(force_check == "Yes") + force_status = TRUE + GLOB.bioscan_data.ares_bioscan(force_status, variance) if("Yautja") GLOB.bioscan_data.yautja_bioscan() diff --git a/code/modules/admin/tabs/round_tab.dm b/code/modules/admin/tabs/round_tab.dm index 980de9eed855..deb27e73f7dc 100644 --- a/code/modules/admin/tabs/round_tab.dm +++ b/code/modules/admin/tabs/round_tab.dm @@ -181,3 +181,34 @@ else to_chat(usr, "Error: Start Now: Game has already started.") return FALSE + +/client/proc/toggle_cdn() + set name = "Toggle CDN" + set category = "Server" + var/static/admin_disabled_cdn_transport = null + if(alert(usr, "Are you sure you want to toggle CDN asset transport?", "Confirm", "Yes", "No") != "Yes") + return + + var/current_transport = CONFIG_GET(string/asset_transport) + if(!current_transport || current_transport == "simple") + if(admin_disabled_cdn_transport) + CONFIG_SET(string/asset_transport, admin_disabled_cdn_transport) + admin_disabled_cdn_transport = null + SSassets.OnConfigLoad() + message_admins("[key_name_admin(usr)] re-enabled the CDN asset transport") + log_admin("[key_name(usr)] re-enabled the CDN asset transport") + return + + to_chat(usr, SPAN_ADMINNOTICE("The CDN is not enabled!")) + if(alert(usr, "CDN asset transport is not enabled! If you're having issues with assets, you can also try disabling filename mutations.", "CDN asset transport is not enabled!", "Try disabling filename mutations", "Nevermind") == "Try disabling filename mutations") + SSassets.transport.dont_mutate_filenames = !SSassets.transport.dont_mutate_filenames + message_admins("[key_name_admin(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms.") + log_admin("[key_name(usr)] [(SSassets.transport.dont_mutate_filenames ? "disabled" : "re-enabled")] asset filename transforms.") + return + + admin_disabled_cdn_transport = current_transport + CONFIG_SET(string/asset_transport, "simple") + SSassets.OnConfigLoad() + SSassets.transport.dont_mutate_filenames = TRUE + message_admins("[key_name_admin(usr)] disabled CDN asset transport") + log_admin("[key_name(usr)] disabled CDN asset transport") diff --git a/code/modules/admin/topic/topic.dm b/code/modules/admin/topic/topic.dm index 96c9312db7d1..b371db087be6 100644 --- a/code/modules/admin/topic/topic.dm +++ b/code/modules/admin/topic/topic.dm @@ -1882,7 +1882,7 @@ if(href_list["ccdeny"]) // CentComm-deny. The distress call is denied, without any further conditions var/mob/ref_person = locate(href_list["ccdeny"]) - marine_announcement("The distress signal has not received a response, the launch tubes are now recalibrating.", "Distress Beacon") + marine_announcement("The distress signal has not received a response, the launch tubes are now recalibrating.", "Distress Beacon", logging = ARES_LOG_SECURITY) log_game("[key_name_admin(usr)] has denied a distress beacon, requested by [key_name_admin(ref_person)]") message_admins("[key_name_admin(usr)] has denied a distress beacon, requested by [key_name_admin(ref_person)]", 1) @@ -1927,7 +1927,7 @@ if(href_list["sddeny"]) // CentComm-deny. The self-destruct is denied, without any further conditions var/mob/ref_person = locate(href_list["sddeny"]) - marine_announcement("The self-destruct request has not received a response, ARES is now recalculating statistics.", "Self-Destruct System") + marine_announcement("The self-destruct request has not received a response, ARES is now recalculating statistics.", "Self-Destruct System", logging = ARES_LOG_SECURITY) log_game("[key_name_admin(usr)] has denied self-destruct, requested by [key_name_admin(ref_person)]") message_admins("[key_name_admin(usr)] has denied self-destruct, requested by [key_name_admin(ref_person)]", 1) @@ -2006,6 +2006,45 @@ player_notes_all(checking.key) + if(href_list["AresReply"]) + var/mob/living/carbon/human/speaker = locate(href_list["AresReply"]) + + if(!istype(speaker)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return FALSE + + if((!GLOB.ares_link.interface) || (GLOB.ares_link.interface.inoperable())) + to_chat(usr, "ARES Interface offline.") + return FALSE + + var/input = input(src.owner, "Please enter a message from ARES to reply to [key_name(speaker)].","Outgoing message from ARES", "") + if(!input) + return FALSE + + to_chat(src.owner, "You sent [input] to [speaker] via ARES Interface.") + log_admin("[src.owner] replied to [key_name(speaker)]'s ARES message with the message [input].") + for(var/client/staff in GLOB.admins) + if((R_ADMIN|R_MOD) & staff.admin_holder.rights) + to_chat(staff, SPAN_STAFF_IC("ADMINS/MODS: [SPAN_RED("[src.owner] replied to [key_name(speaker)]'s ARES message")] with: [SPAN_BLUE(input)] ")) + GLOB.ares_link.interface.response_from_ares(input, href_list["AresRef"]) + + if(href_list["AresMark"]) + var/mob/living/carbon/human/speaker = locate(href_list["AresMark"]) + + if(!istype(speaker)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return FALSE + + if((!GLOB.ares_link.interface) || (GLOB.ares_link.interface.inoperable())) + to_chat(usr, "ARES Interface offline.") + return FALSE + + to_chat(src.owner, "You marked [speaker]'s ARES message for response.") + log_admin("[src.owner] marked [key_name(speaker)]'s ARES message. [src.owner] will be responding.") + for(var/client/staff in GLOB.admins) + if((R_ADMIN|R_MOD) & staff.admin_holder.rights) + to_chat(staff, SPAN_STAFF_IC("ADMINS/MODS: [SPAN_RED("[src.owner] marked [key_name(speaker)]'s ARES message for response.")]")) + return /datum/admins/proc/accept_ert(mob/approver, mob/ref_person) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 52aae50a966a..c7a7664af3e8 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -203,6 +203,9 @@ message_admins(SPAN_DANGER("ERROR: Non-admin [key_name(usr)] attempted to execute a SDQL query!")) log_admin("non-admin attempted to execute a SDQL query!") return FALSE + var/prompt = tgui_alert(usr, "Run SDQL2 Query?", "SDQL2", list("Yes", "Cancel")) + if (prompt != "Yes") + return var/list/results = world.SDQL2_query(query_text, key_name_admin(usr), "[key_name(usr)]") if(length(results) == 3) for(var/I in 1 to 3) diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm index be8a5693df6e..700d42808a07 100644 --- a/code/modules/admin/verbs/deadsay.dm +++ b/code/modules/admin/verbs/deadsay.dm @@ -23,7 +23,7 @@ stafftype = "[admin_holder.rank]" msg = strip_html(msg) - log_admin("[key_name(src)] : [msg]") + log_admin("DEAD: [key_name(src)] : [msg]") if (!msg) return diff --git a/code/modules/asset_cache/asset_cache_item.dm b/code/modules/asset_cache/asset_cache_item.dm index 52ebc7190372..72d976bf11f1 100644 --- a/code/modules/asset_cache/asset_cache_item.dm +++ b/code/modules/asset_cache/asset_cache_item.dm @@ -33,3 +33,9 @@ if (extstart) ext = ".[copytext(name, extstart+1)]" resource = file + +/datum/asset_cache_item/vv_edit_var(var_name, var_value) + return FALSE + +/datum/asset_cache_item/CanProcCall(procname) + return FALSE diff --git a/code/modules/asset_cache/transports/webroot_transport.dm b/code/modules/asset_cache/transports/webroot_transport.dm new file mode 100644 index 000000000000..e3cb33b8fabf --- /dev/null +++ b/code/modules/asset_cache/transports/webroot_transport.dm @@ -0,0 +1,87 @@ +/// CDN Webroot asset transport. +/datum/asset_transport/webroot + name = "CDN Webroot asset transport" + +/datum/asset_transport/webroot/Load() + if (validate_config(log = FALSE)) + load_existing_assets() + +/// Processes thru any assets that were registered before we were loaded as a transport. +/datum/asset_transport/webroot/proc/load_existing_assets() + for (var/asset_name in SSassets.cache) + var/datum/asset_cache_item/ACI = SSassets.cache[asset_name] + save_asset_to_webroot(ACI) + +/// Register a browser asset with the asset cache system +/// We also save it to the CDN webroot at this step instead of waiting for send_assets() +/// asset_name - the identifier of the asset +/// asset - the actual asset file or an asset_cache_item datum. +/datum/asset_transport/webroot/register_asset(asset_name, asset) + . = ..() + var/datum/asset_cache_item/ACI = . + + if (istype(ACI) && ACI.hash) + save_asset_to_webroot(ACI) + +/// Saves the asset to the webroot taking into account namespaces and hashes. +/datum/asset_transport/webroot/proc/save_asset_to_webroot(datum/asset_cache_item/ACI) + var/webroot = CONFIG_GET(string/asset_cdn_webroot) + var/newpath = "[webroot][get_asset_suffex(ACI)]" + if (fexists(newpath)) + return + if (fexists("[newpath].gz")) //its a common pattern in webhosting to save gzip'ed versions of text files and let the webserver serve them up as gzip compressed normal files, sometimes without keeping the original version. + return + return fcopy(ACI.resource, newpath) + +/// Returns a url for a given asset. +/// asset_name - Name of the asset. +/// asset_cache_item - asset cache item datum for the asset, optional, overrides asset_name +/datum/asset_transport/webroot/get_asset_url(asset_name, datum/asset_cache_item/asset_cache_item) + if (!istype(asset_cache_item)) + asset_cache_item = SSassets.cache[asset_name] + var/url = CONFIG_GET(string/asset_cdn_url) //config loading will handle making sure this ends in a / + return "[url][get_asset_suffex(asset_cache_item)]" + +/datum/asset_transport/webroot/proc/get_asset_suffex(datum/asset_cache_item/asset_cache_item) + var/base = "[copytext(asset_cache_item.hash, 1, 3)]/" + var/filename = "asset.[asset_cache_item.hash][asset_cache_item.ext]" + if (length(asset_cache_item.namespace)) + base = "namespaces/[copytext(asset_cache_item.namespace, 1, 3)]/[asset_cache_item.namespace]/" + if (!asset_cache_item.namespace_parent) + filename = "[asset_cache_item.name]" + return base + filename + + +/// webroot asset sending - does nothing unless passed legacy assets +/datum/asset_transport/webroot/send_assets(client/client, list/asset_list) + . = FALSE + var/list/legacy_assets = list() + if (!islist(asset_list)) + asset_list = list(asset_list) + for (var/asset_name in asset_list) + var/datum/asset_cache_item/ACI = asset_list[asset_name] + if (!istype(ACI)) + ACI = SSassets.cache[asset_name] + if (!ACI) + legacy_assets += asset_name //pass it on to base send_assets so it can output an error + continue + if (ACI.legacy) + legacy_assets[asset_name] = ACI + if (length(legacy_assets)) + . = ..(client, legacy_assets) + + +/// webroot slow asset sending - does nothing. +/datum/asset_transport/webroot/send_assets_slow(client/client, list/files, filerate) + return FALSE + +/datum/asset_transport/webroot/validate_config(log = TRUE) + if (!CONFIG_GET(string/asset_cdn_url)) + if (log) + log_asset("ERROR: [type]: Invalid Config: ASSET_CDN_URL") + return FALSE + if (!CONFIG_GET(string/asset_cdn_webroot)) + if (log) + log_asset("ERROR: [type]: Invalid Config: ASSET_CDN_WEBROOT") + return FALSE + return TRUE diff --git a/code/modules/character_traits/biology_traits.dm b/code/modules/character_traits/biology_traits.dm index e7625c391b75..87fb0b70ec36 100644 --- a/code/modules/character_traits/biology_traits.dm +++ b/code/modules/character_traits/biology_traits.dm @@ -59,11 +59,13 @@ return ADD_TRAIT(target, TRAIT_LISPING, TRAIT_SOURCE_QUIRK) + target.speech_problem_flag = TRUE ..() /datum/character_trait/biology/lisp/unapply_trait(mob/living/carbon/human/target) REMOVE_TRAIT(target, TRAIT_LISPING, TRAIT_SOURCE_QUIRK) + target.speech_problem_flag = FALSE ..() /datum/character_trait/biology/bad_leg diff --git a/code/modules/client/player_details.dm b/code/modules/client/player_details.dm index 06dafdbea63a..634fd8fb627e 100644 --- a/code/modules/client/player_details.dm +++ b/code/modules/client/player_details.dm @@ -7,7 +7,12 @@ GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details var/list/post_logout_callbacks = list() var/list/played_names = list() //List of names this key played under this round var/byond_version = "Unknown" + /// The descriminator for larva queue ordering: Generally set to timeofdeath except for facehuggers/admin z-level play + var/larva_queue_time +/datum/player_details/New() + larva_queue_time = world.time + return ..() /proc/log_played_names(ckey, ...) if(!ckey) diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index e51a904cfdac..d2d69d095dbd 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1228,8 +1228,9 @@ var/const/MAX_SAVE_SLOTS = 10 if("pred_gender") predator_gender = predator_gender == MALE ? FEMALE : MALE if("pred_age") - var/new_predator_age = tgui_input_number(user, "Choose your Predator's age(20 to 10000):", "Character Preference", 1234, 10000, 20) - if(new_predator_age) predator_age = max(min( round(text2num(new_predator_age)), 10000),20) + var/new_predator_age = tgui_input_number(user, "Choose your Predator's age(175 to 3000):", "Character Preference", 1234, 3000, 175) + if(new_predator_age) + predator_age = max(min( round(text2num(new_predator_age)), 3000),175) if("pred_trans_type") var/new_translator_type = tgui_input_list(user, "Choose your translator type.", "Translator Type", PRED_TRANSLATORS) if(!new_translator_type) diff --git a/code/modules/client/preferences_gear.dm b/code/modules/client/preferences_gear.dm index 1ccd1f99c52a..106da02a00b6 100644 --- a/code/modules/client/preferences_gear.dm +++ b/code/modules/client/preferences_gear.dm @@ -363,6 +363,11 @@ var/global/list/gear_datums_by_name = list() display_name = "Pen, red" path = /obj/item/tool/pen/red +/datum/gear/paperwork/pen_fountain + display_name = "Pen, fountain" + path = /obj/item/tool/pen/fountain + cost = 3 + /datum/gear/paperwork/paper display_name = "Sheet of paper" path = /obj/item/paper @@ -415,6 +420,33 @@ var/global/list/gear_datums_by_name = list() display_name = "Camera" path = /obj/item/device/camera +/datum/gear/toy/mags + cost = 1 + +/datum/gear/toy/mags/magazine_dirty + display_name = "Magazine" + path = /obj/item/prop/magazine/dirty + +/datum/gear/toy/mags/boots_magazine_one + display_name = "Boots Issue No.117" + path = /obj/item/prop/magazine/boots/n117 + +/datum/gear/toy/mags/boots_magazine_two + display_name = "Boots Issue No.150" + path = /obj/item/prop/magazine/boots/n150 + +/datum/gear/toy/mags/boot_magazine_three + display_name = "Boots Issue No.160" + path = /obj/item/prop/magazine/boots/n160 + +/datum/gear/toy/mags/boots_magazine_four + display_name = "Boots Issue No.54" + path = /obj/item/prop/magazine/boots/n054 + +/datum/gear/toy/mags/boots_magazine_five + display_name = "Boots Issue No.55" + path = /obj/item/prop/magazine/boots/n055 + /datum/gear/toy/film display_name = "Camera film" path = /obj/item/device/camera_film @@ -463,6 +495,10 @@ var/global/list/gear_datums_by_name = list() display_name = "Walkman" path = /obj/item/device/walkman +/datum/gear/toy/crayon + display_name = "Crayon" + path = /obj/item/toy/crayon/rainbow + /datum/gear/weapon category = "Weapons" cost = 4 diff --git a/code/modules/clothing/head/head.dm b/code/modules/clothing/head/head.dm index 1b4e292a22af..0916ecfb34e9 100644 --- a/code/modules/clothing/head/head.dm +++ b/code/modules/clothing/head/head.dm @@ -248,7 +248,9 @@ /obj/item/prop/helmetgarb/lucky_feather = "lucky_feather", /obj/item/prop/helmetgarb/lucky_feather/blue = "lucky_feather_blue", /obj/item/prop/helmetgarb/lucky_feather/purple = "lucky_feather_purple", - /obj/item/prop/helmetgarb/lucky_feather/yellow = "lucky_feather_yellow") + /obj/item/prop/helmetgarb/lucky_feather/yellow = "lucky_feather_yellow", + /obj/item/tool/pen/fountain = "fountainpen", + ) var/storage_slots = 1 var/storage_slots_reserved_for_garb = 1 var/storage_max_w_class = SIZE_TINY diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 3f5f4b14f0ad..268816b32cfd 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -326,6 +326,7 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( /obj/item/prop/helmetgarb/riot_shield = "helmet_riot_shield", /obj/item/attachable/flashlight = HELMET_GARB_RELAY_ICON_STATE, /obj/item/prop/helmetgarb/chaplain_patch = "chaplain_patch", + /obj/item/tool/pen/fountain = "fountainpen", // MEDICAL /obj/item/stack/medical/bruise_pack ="brutepack (bandages)", diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm index 1c74080a928f..278ffb666bfd 100644 --- a/code/modules/clothing/suits/labcoat.dm +++ b/code/modules/clothing/suits/labcoat.dm @@ -221,7 +221,6 @@ /obj/item/explosive/grenade, /obj/item/device/binoculars, /obj/item/attachable/bayonet, - /obj/item/storage/backpack/general_belt, /obj/item/storage/large_holster/machete, /obj/item/weapon/baseballbat, /obj/item/weapon/baseballbat/metal, @@ -289,7 +288,6 @@ /obj/item/explosive/grenade, /obj/item/device/binoculars, /obj/item/attachable/bayonet, - /obj/item/storage/backpack/general_belt, /obj/item/storage/large_holster/machete, /obj/item/weapon/baseballbat, /obj/item/weapon/baseballbat/metal, @@ -297,3 +295,7 @@ /obj/item/device/walkman, ) +/obj/item/clothing/suit/storage/snow_suit/liaison + name = "liaison's winter coat" + desc = "A Weyland-Yutani winter coat. Only the best comfort for the liaison in a cold environment." + icon_state = "snowsuit_liaison" diff --git a/code/modules/clothing/suits/marine_armor.dm b/code/modules/clothing/suits/marine_armor.dm index 4ca19f3be793..6cc61f8402ae 100644 --- a/code/modules/clothing/suits/marine_armor.dm +++ b/code/modules/clothing/suits/marine_armor.dm @@ -580,6 +580,7 @@ var/list/squad_colors_chat = list(rgb(230,125,125), rgb(255,230,80), rgb(255,150 armor_rad = CLOTHING_ARMOR_NONE armor_internaldamage = CLOTHING_ARMOR_NONE storage_slots = 3 + slowdown = SLOWDOWN_ARMOR_VERY_LIGHT time_to_unequip = 0.5 SECONDS time_to_equip = 1 SECONDS uniform_restricted = null diff --git a/code/modules/clothing/under/marine_uniform.dm b/code/modules/clothing/under/marine_uniform.dm index 17b98d9b9326..540c311f9221 100644 --- a/code/modules/clothing/under/marine_uniform.dm +++ b/code/modules/clothing/under/marine_uniform.dm @@ -777,12 +777,22 @@ icon_state = "liaison_regular" worn_state = "liaison_regular" +/obj/item/clothing/under/liaison_suit/charcoal + name = "liaison's charcoal suit" + desc = "A stiff, stylish charcoal suit commonly worn by businessmen from the Weyland-Yutani corporation. Expertly crafted to make you look like a prick." + icon_state = "liaison_charcoal" + worn_state = "liaison_charcoal" + /obj/item/clothing/under/liaison_suit/outing name = "liaison's outfit" desc = "A casual outfit consisting of a collared shirt and a vest. Looks like something you might wear on the weekends, or on a visit to a derelict colony." icon_state = "liaison_outing" worn_state = "liaison_outing" +/obj/item/clothing/under/liaison_suit/outing/red + icon_state = "liaison_outing_red" + worn_state = "liaison_outing_red" + /obj/item/clothing/under/liaison_suit/formal name = "liaison's white suit" desc = "A formal, white suit. Looks like something you'd wear to a funeral, a Weyland-Yutani corporate dinner, or both. Stiff as a board, but makes you feel like rolling out of a Rolls-Royce." @@ -795,6 +805,12 @@ icon_state = "liaison_suspenders" worn_state = "liaison_suspenders" +/obj/item/clothing/under/liaison_suit/blazer + name = "liaison's blue blazer" + desc = "A stiff but casual blue blazer. Similar can be found in any Weyland-Yutani office. Only the finest wear for the galaxy's most cunning." + icon_state = "liaison_blue_blazer" + worn_state = "liaison_blue_blazer" + /obj/item/clothing/under/marine/reporter name = "combat correspondent uniform" desc = "A relaxed and robust uniform fit for any potential reporting needs." diff --git a/code/modules/cm_aliens/XenoStructures.dm b/code/modules/cm_aliens/XenoStructures.dm index f21cd6498615..594c2e98695c 100644 --- a/code/modules/cm_aliens/XenoStructures.dm +++ b/code/modules/cm_aliens/XenoStructures.dm @@ -154,6 +154,8 @@ if (hive) hivenumber = hive set_hive_data(src, hivenumber) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) /obj/effect/alien/resin/sticky/Crossed(atom/movable/AM) . = ..() @@ -166,6 +168,14 @@ X.next_move_slowdown = X.next_move_slowdown + slow_amt return . +/obj/effect/alien/resin/sticky/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + /obj/effect/alien/resin/spike name = "resin spike" desc = "A small cluster of bone spikes. Ouch." @@ -193,6 +203,8 @@ hivenumber = hive set_hive_data(src, hivenumber) setDir(pick(alldirs)) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) /obj/effect/alien/resin/spike/Crossed(atom/movable/AM) . = ..() @@ -206,6 +218,14 @@ H.apply_armoured_damage(damage, penetration = penetration, def_zone = pick(target_limbs)) H.last_damage_data = construction_data +/obj/effect/alien/resin/spike/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + // Praetorian Sticky Resin spit uses this. /obj/effect/alien/resin/sticky/thin name = "thin sticky resin" @@ -348,6 +368,9 @@ set_hive_data(src, hivenumber) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) + /obj/structure/mineral_door/resin/flamer_fire_act(dam = BURN_LEVEL_TIER_1) health -= dam healthcheck() @@ -479,6 +502,13 @@ visible_message(SPAN_NOTICE("[src] collapses from the lack of support.")) qdel(src) +/obj/structure/mineral_door/resin/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) /obj/structure/mineral_door/resin/thick name = "thick resin door" icon_state = "thick resin" @@ -510,6 +540,8 @@ hivenumber = hive set_hive_data(src, hivenumber) START_PROCESSING(SSprocessing, src) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) /obj/effect/alien/resin/acid_pillar/proc/can_target(mob/living/carbon/current_mob, position_to_get = 0) @@ -599,6 +631,12 @@ /obj/effect/alien/resin/acid_pillar/get_projectile_hit_boolean(obj/item/projectile/P) return TRUE +/obj/effect/alien/resin/acid_pillar/proc/forsaken_handling() + SIGNAL_HANDLER + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + if(is_ground_level(z)) + qdel(src) + /obj/effect/alien/resin/acid_pillar/strong name = "acid pillar" desc = "A resin pillar that is oozing with acid." diff --git a/code/modules/cm_aliens/structures/fruit.dm b/code/modules/cm_aliens/structures/fruit.dm index 8bdcc0b82413..bb899a6ff25b 100644 --- a/code/modules/cm_aliens/structures/fruit.dm +++ b/code/modules/cm_aliens/structures/fruit.dm @@ -150,25 +150,33 @@ update_icon() QDEL_IN(src, 3 SECONDS) -/obj/effect/alien/resin/fruit/attack_alien(mob/living/carbon/xenomorph/X) +/obj/effect/alien/resin/fruit/attack_alien(mob/living/carbon/xenomorph/affected_xeno) if(picked) - to_chat(X, SPAN_XENODANGER("This fruit is already being picked!")) + to_chat(affected_xeno, SPAN_XENODANGER("This fruit is already being picked!")) return - if(X.a_intent != INTENT_HARM && (X.can_not_harm(bound_xeno) || X.hivenumber == hivenumber)) - var/cant_consume = prevent_consume(X) + + if(affected_xeno.a_intent != INTENT_HARM && (affected_xeno.can_not_harm(bound_xeno) || affected_xeno.hivenumber == hivenumber)) + var/cant_consume = prevent_consume(affected_xeno) if(cant_consume) return cant_consume + if(mature) - to_chat(X, SPAN_XENOWARNING("You prepare to consume [name].")) - xeno_noncombat_delay(X) - if(!do_after(X, consume_delay, INTERRUPT_ALL, BUSY_ICON_FRIENDLY)) + to_chat(affected_xeno, SPAN_XENOWARNING("You prepare to consume [name].")) + xeno_noncombat_delay(affected_xeno) + if(!do_after(affected_xeno, consume_delay, INTERRUPT_ALL, BUSY_ICON_FRIENDLY)) return XENO_NO_DELAY_ACTION - consume_effect(X) + + cant_consume = prevent_consume(affected_xeno) // Check again after the delay incase they have eaten another fruit + if(cant_consume) + to_chat(affected_xeno, SPAN_XENOWARNING("You can no longer consume [name].")) + return cant_consume + consume_effect(affected_xeno) else - to_chat(X, SPAN_XENOWARNING("[name] isn't ripe yet. You need to wait a little longer.")) - if(X.a_intent == INTENT_HARM && isxeno_builder(X) || (!X.can_not_harm(bound_xeno) && X.hivenumber != hivenumber)) - X.animation_attack_on(src) - X.visible_message(SPAN_XENODANGER("[X] removes [name]!"), + to_chat(affected_xeno, SPAN_XENOWARNING("[name] isn't ripe yet. You need to wait a little longer.")) + + if(affected_xeno.a_intent == INTENT_HARM && isxeno_builder(affected_xeno) || (!affected_xeno.can_not_harm(bound_xeno) && affected_xeno.hivenumber != hivenumber)) + affected_xeno.animation_attack_on(src) + affected_xeno.visible_message(SPAN_XENODANGER("[affected_xeno] removes [name]!"), SPAN_XENODANGER("You remove [name]!")) playsound(loc, "alien_resin_break", 25) qdel(src) @@ -376,30 +384,49 @@ bound_xeno = null // Xenos eating fruit -/obj/item/reagent_container/food/snacks/resin_fruit/attack(mob/living/carbon/xenomorph/X, mob/user) +/obj/item/reagent_container/food/snacks/resin_fruit/attack(mob/living/carbon/xenomorph/affected_xeno, mob/user) if(istype(user, /mob/living/carbon/xenomorph)) // Prevents xenos from feeding capped/dead marines fruit - var/mob/living/carbon/xenomorph/Y = user - if(!Y.can_not_harm(X)) - to_chat(Y, SPAN_WARNING("[X] refuses to eat [src].")) + var/mob/living/carbon/xenomorph/feeding_xeno = user + if(!feeding_xeno.can_not_harm(affected_xeno)) + to_chat(feeding_xeno, SPAN_WARNING("[affected_xeno] refuses to eat [src].")) return - if(!istype(X)) + + if(!istype(affected_xeno)) return ..() - if(X.stat == DEAD) + + if(affected_xeno.stat == DEAD) to_chat(user, SPAN_WARNING("That sister is already dead, they won't benefit from the fruit now...")) return - user.affected_message(X, - SPAN_HELPFUL("You start [user == X ? "eating" : "feeding [X]"] [src]."), - SPAN_HELPFUL("[user] starts feeding you [src]."), - SPAN_NOTICE("[user] starts [user == X ? "eating" : "feeding [X]"] [src].")) - if(!do_after(user, consume_delay, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, X, INTERRUPT_MOVED, BUSY_ICON_MEDICAL)) + + var/obj/effect/alien/resin/fruit/current_fruit = new fruit_type(affected_xeno) + var/cant_consume = current_fruit.prevent_consume(affected_xeno) + if(cant_consume) + user.affected_message(affected_xeno, + SPAN_HELPFUL("You fail to [user == affected_xeno ? "eat" : "feed [affected_xeno]"] [current_fruit]."), + SPAN_HELPFUL("[user] fails to feed you [current_fruit].")) + return + user.affected_message(affected_xeno, + SPAN_HELPFUL("You start [user == affected_xeno ? "eating" : "feeding [affected_xeno]"] [current_fruit]."), + SPAN_HELPFUL("[user] starts feeding you [current_fruit]."), + SPAN_NOTICE("[user] starts [user == affected_xeno ? "eating" : "feeding [affected_xeno]"] [current_fruit].")) + + if(!do_after(user, consume_delay, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, affected_xeno, INTERRUPT_MOVED, BUSY_ICON_MEDICAL)) return FALSE - user.affected_message(X, - SPAN_HELPFUL("You [user == X ? "eat" : "fed [X]"] [src]."), - SPAN_HELPFUL("[user] fed you [src]."), - SPAN_NOTICE("[user] [user == X ? "ate" : "fed [X]"] [src].")) - var/obj/effect/alien/resin/fruit/F = new fruit_type(X) - F.mature = TRUE - F.consume_effect(X) + + cant_consume = current_fruit.prevent_consume(affected_xeno) + if(cant_consume) //Check again after the timer incase they ate another fruit + user.affected_message(affected_xeno, + SPAN_HELPFUL("You fail to [user == affected_xeno ? "eat" : "feed [affected_xeno]"] [current_fruit]."), + SPAN_HELPFUL("[user] fails to feed you [current_fruit].")) + return + + user.affected_message(affected_xeno, + SPAN_HELPFUL("You [user == affected_xeno ? "eat" : "fed [affected_xeno]"] [current_fruit]."), + SPAN_HELPFUL("[user] fed you [current_fruit]."), + SPAN_NOTICE("[user] [user == affected_xeno ? "ate" : "fed [affected_xeno]"] [current_fruit].")) + current_fruit.mature = TRUE + current_fruit.consume_effect(affected_xeno) + //Notify the fruit's bound xeno if they exist if(!QDELETED(bound_xeno)) to_chat(bound_xeno, SPAN_XENOWARNING("One of your picked resin fruits has been consumed.")) diff --git a/code/modules/cm_aliens/structures/special/pylon_core.dm b/code/modules/cm_aliens/structures/special/pylon_core.dm index 9376e2b6e914..c38e540efb30 100644 --- a/code/modules/cm_aliens/structures/special/pylon_core.dm +++ b/code/modules/cm_aliens/structures/special/pylon_core.dm @@ -108,6 +108,7 @@ var/last_healed = 0 var/last_attempt = 0 // logs time of last attempt to prevent spam. if you want to destroy it, you must commit. var/last_larva_time = 0 + var/last_larva_queue_time = 0 var/last_surge_time = 0 var/spawn_cooldown = 30 SECONDS var/surge_cooldown = 90 SECONDS @@ -135,25 +136,40 @@ // Handle spawning larva if core is connected to a hive if(linked_hive) - for(var/mob/living/carbon/xenomorph/larva/L in range(2, src)) - if(!L.ckey && L.burrowable && !QDELETED(L)) - visible_message(SPAN_XENODANGER("[L] quickly burrows into \the [src].")) - linked_hive.stored_larva++ - linked_hive.hive_ui.update_burrowed_larva() - qdel(L) - - if((last_larva_time + spawn_cooldown) < world.time && can_spawn_larva()) // every minute + for(var/mob/living/carbon/xenomorph/larva/worm in range(2, src)) + if((!worm.ckey || worm.stat == DEAD) && worm.burrowable && (worm.hivenumber == linked_hive.hivenumber) && !QDELETED(worm)) + visible_message(SPAN_XENODANGER("[worm] quickly burrows into \the [src].")) + if(!worm.banished) + // Goob job bringing her back home, but no doubling please + linked_hive.stored_larva++ + linked_hive.hive_ui.update_burrowed_larva() + qdel(worm) + + var/spawning_larva = can_spawn_larva() && (last_larva_time + spawn_cooldown) < world.time + if(spawning_larva) last_larva_time = world.time + if(spawning_larva || (last_larva_queue_time + spawn_cooldown * 4) < world.time) + last_larva_queue_time = world.time var/list/players_with_xeno_pref = get_alien_candidates() - if(players_with_xeno_pref && players_with_xeno_pref.len && can_spawn_larva()) - spawn_burrowed_larva(pick(players_with_xeno_pref)) + if(players_with_xeno_pref && players_with_xeno_pref.len) + if(spawning_larva && spawn_burrowed_larva(players_with_xeno_pref[1])) + // We were in spawning_larva mode and successfully spawned someone + message_alien_candidates(players_with_xeno_pref, dequeued = 1) + else + // Just time to update everyone their queue status (or the spawn failed) + message_alien_candidates(players_with_xeno_pref, dequeued = 0) if(linked_hive.hijack_burrowed_surge && (last_surge_time + surge_cooldown) < world.time) last_surge_time = world.time linked_hive.stored_larva++ + linked_hive.hijack_burrowed_left-- announce_dchat("The hive has gained another burrowed larva! Use the Join As Xeno verb to take it.", src) if(surge_cooldown > 30 SECONDS) //mostly for sanity purposes surge_cooldown = surge_cooldown - surge_incremental_reduction //ramps up over time + if(linked_hive.hijack_burrowed_left < 1) + linked_hive.hijack_burrowed_surge = FALSE + xeno_message(SPAN_XENOANNOUNCE("The hive's power wanes. You will no longer gain pooled larva over time."), 3, linked_hive.hivenumber) + // Hive core can repair itself over time if(health < maxhealth && last_healed <= world.time) diff --git a/code/modules/cm_aliens/structures/trap.dm b/code/modules/cm_aliens/structures/trap.dm index 1b3d4d414d48..5e1c51538ce6 100644 --- a/code/modules/cm_aliens/structures/trap.dm +++ b/code/modules/cm_aliens/structures/trap.dm @@ -29,6 +29,8 @@ cause_data = create_cause_data("resin trap", X) set_hive_data(src, hivenumber) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) /obj/effect/alien/resin/trap/Initialize() . = ..() @@ -53,6 +55,14 @@ if(RESIN_TRAP_ACID1, RESIN_TRAP_ACID2, RESIN_TRAP_ACID3) . += "It's filled with pressurised acid." +/obj/effect/alien/resin/trap/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + /obj/effect/alien/resin/trap/proc/facehugger_die() var/obj/item/clothing/mask/facehugger/FH = new (loc) FH.die() @@ -159,6 +169,7 @@ trap_type_name = "hugger" var/obj/item/clothing/mask/facehugger/FH = new (loc) FH.hivenumber = hivenumber + set_hive_data(FH, hivenumber) set_state() visible_message(SPAN_WARNING("[FH] gets out of [src]!")) sleep(15) diff --git a/code/modules/cm_aliens/weeds.dm b/code/modules/cm_aliens/weeds.dm index 0be2220994d8..f20fa842e446 100644 --- a/code/modules/cm_aliens/weeds.dm +++ b/code/modules/cm_aliens/weeds.dm @@ -73,15 +73,18 @@ else if(!hibernate && do_spread) addtimer(CALLBACK(src, PROC_REF(weed_expand)), WEED_BASE_GROW_SPEED / max(weed_strength, 1)) - var/turf/T = get_turf(src) - if(T) - T.weeds = src - weeded_turf = T + var/turf/turf = get_turf(src) + if(turf) + turf.weeds = src + weeded_turf = turf + SEND_SIGNAL(turf, COMSIG_WEEDNODE_GROWTH) // Currently for weed_food wakeup RegisterSignal(src, list( COMSIG_ATOM_TURF_CHANGE, COMSIG_MOVABLE_TURF_ENTERED ), PROC_REF(set_turf_weeded)) + if(hivenumber == XENO_HIVE_NORMAL) + RegisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING, PROC_REF(forsaken_handling)) /obj/effect/alien/weeds/proc/set_turf_weeded(datum/source, turf/T) SIGNAL_HANDLER @@ -90,6 +93,15 @@ T.weeds = src +/obj/effect/alien/weeds/proc/forsaken_handling() + SIGNAL_HANDLER + if(is_ground_level(z)) + hivenumber = XENO_HIVE_FORSAKEN + set_hive_data(src, XENO_HIVE_FORSAKEN) + linked_hive = GLOB.hive_datum[XENO_HIVE_FORSAKEN] + + UnregisterSignal(SSdcs, COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + /obj/effect/alien/weeds/initialize_pass_flags(datum/pass_flags_container/PF) . = ..() if (PF) @@ -418,7 +430,11 @@ /obj/effect/alien/weeds/weedwall/MouseDrop_T(mob/current_mob, mob/user) . = ..() - if(isxeno(user)) + + if(!ismob(current_mob)) + return + + if(isxeno(user) && istype(user.get_active_hand(), /obj/item/grab)) var/mob/living/carbon/xenomorph/user_as_xenomorph = user user_as_xenomorph.do_nesting_host(current_mob, src) @@ -492,20 +508,20 @@ overlay_node = TRUE overlays += staticnode -/obj/effect/alien/weeds/node/Initialize(mapload, obj/effect/alien/weeds/node/node, mob/living/carbon/xenomorph/X, datum/hive_status/hive) +/obj/effect/alien/weeds/node/Initialize(mapload, obj/effect/alien/weeds/node/node, mob/living/carbon/xenomorph/xeno, datum/hive_status/hive) if (istype(hive)) linked_hive = hive - else if (istype(X) && X.hive) - linked_hive = X.hive + else if (istype(xeno) && xeno.hive) + linked_hive = xeno.hive else linked_hive = GLOB.hive_datum[hivenumber] - for(var/obj/effect/alien/weeds/W in loc) - if(W != src) - if(W.weed_strength > WEED_LEVEL_HIVE) + for(var/obj/effect/alien/weeds/weed in loc) + if(weed != src) + if(weed.weed_strength > WEED_LEVEL_HIVE) qdel(src) return - qdel(W) //replaces the previous weed + qdel(weed) //replaces the previous weed break . = ..(mapload, src) @@ -513,15 +529,15 @@ if(!staticnode) staticnode = image('icons/mob/xenos/weeds.dmi', "weednode", ABOVE_OBJ_LAYER) - var/obj/effect/alien/resin/trap/TR = locate() in loc - if(TR) - RegisterSignal(TR, COMSIG_PARENT_PREQDELETED, PROC_REF(trap_destroyed)) + var/obj/effect/alien/resin/trap/trap = locate() in loc + if(trap) + RegisterSignal(trap, COMSIG_PARENT_PREQDELETED, PROC_REF(trap_destroyed)) overlay_node = FALSE overlays -= staticnode - if(X) - add_hiddenprint(X) - weed_strength = X.weed_level + if(xeno) + add_hiddenprint(xeno) + weed_strength = max(weed_strength, xeno.weed_level) if (weed_strength < WEED_LEVEL_STANDARD) weed_strength = WEED_LEVEL_STANDARD diff --git a/code/modules/cm_marines/anti_air.dm b/code/modules/cm_marines/anti_air.dm index 22d43456437b..fc67f9a2018d 100644 --- a/code/modules/cm_marines/anti_air.dm +++ b/code/modules/cm_marines/anti_air.dm @@ -102,6 +102,7 @@ var/obj/structure/anti_air_cannon/almayer_aa_cannon if(!almayer_aa_cannon) return + var/datum/ares_link/link = GLOB.ares_link switch(action) if("protect") almayer_aa_cannon.protecting_section = params["section_id"] @@ -109,10 +110,12 @@ var/obj/structure/anti_air_cannon/almayer_aa_cannon almayer_aa_cannon.protecting_section = "" return message_admins("[key_name(usr)] has set the AA to [html_encode(almayer_aa_cannon.protecting_section)].") + link.log_ares_antiair(usr, "Set AA to cover [html_encode(almayer_aa_cannon.protecting_section)].") . = TRUE if("deactivate") almayer_aa_cannon.protecting_section = "" message_admins("[key_name(usr)] has deactivated the AA cannon.") + link.log_ares_antiair(usr, "Deactivated Anti Air systems.") . = TRUE add_fingerprint(usr) diff --git a/code/modules/cm_marines/dropship_ammo.dm b/code/modules/cm_marines/dropship_ammo.dm index b4b585e1de89..3c01688b70d7 100644 --- a/code/modules/cm_marines/dropship_ammo.dm +++ b/code/modules/cm_marines/dropship_ammo.dm @@ -287,9 +287,8 @@ /obj/structure/ship_ammo/rocket/widowmaker/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 300, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) //Your standard HE splash damage rocket. Good damage, good range, good speed, it's an all rounder - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 300, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) //Your standard HE splash damage rocket. Good damage, good range, good speed, it's an all rounder + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/banshee name = "\improper AGM-227 'Banshee'" @@ -301,10 +300,9 @@ /obj/structure/ship_ammo/rocket/banshee/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 175, 20, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) //Small explosive power with a small fall off for a big explosion range - fire_spread(impact, create_cause_data(initial(name), source_mob), 4, 15, 50, "#00b8ff") //Very intense but the fire doesn't last very long - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 175, 20, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) //Small explosive power with a small fall off for a big explosion range + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fire_spread), impact, create_cause_data(initial(name), source_mob), 4, 15, 50, "#00b8ff"), 0.5 SECONDS) //Very intense but the fire doesn't last very long + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/keeper name = "\improper GBU-67 'Keeper II'" @@ -317,9 +315,8 @@ /obj/structure/ship_ammo/rocket/keeper/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 450, 100, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, create_cause_data(initial(name), source_mob)) //Insane fall off combined with insane damage makes the Keeper useful for single targets, but very bad against multiple. - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 450, 100, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) //Insane fall off combined with insane damage makes the Keeper useful for single targets, but very bad against multiple. + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/harpoon name = "\improper AGM-84 'Harpoon'" @@ -333,9 +330,8 @@ //Looks kinda OP but all it can actually do is just to blow windows and some of other things out, cant do much damage. /obj/structure/ship_ammo/rocket/harpoon/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 150, 16, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 150, 16, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/napalm name = "\improper XN-99 'Napalm'" @@ -347,10 +343,9 @@ /obj/structure/ship_ammo/rocket/napalm/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 200, 25, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) - fire_spread(impact, create_cause_data(initial(name), source_mob), 6, 60, 30, "#EE6515") //Color changed into napalm's color to better convey how intense the fire actually is. - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 200, 25, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fire_spread), impact, create_cause_data(initial(name), source_mob), 6, 60, 30, "#EE6515"), 0.5 SECONDS) //Color changed into napalm's color to better convey how intense the fire actually is. + QDEL_IN(src, 0.5 SECONDS) diff --git a/code/modules/cm_marines/dropship_equipment.dm b/code/modules/cm_marines/dropship_equipment.dm index 42bbd7f746e7..89d33134bdb8 100644 --- a/code/modules/cm_marines/dropship_equipment.dm +++ b/code/modules/cm_marines/dropship_equipment.dm @@ -256,6 +256,13 @@ deployed_turret.start_processing() deployed_turret.set_range() + deployed_turret.linked_cam = new(deployed_turret.loc, "[capitalize_first_letters(ship_base.name)] [capitalize_first_letters(name)]") + if (linked_shuttle.id == DROPSHIP_ALAMO) + deployed_turret.linked_cam.network = list(CAMERA_NET_ALAMO) + else if (linked_shuttle.id == DROPSHIP_NORMANDY) + deployed_turret.linked_cam.network = list(CAMERA_NET_NORMANDY) + + /obj/structure/dropship_equipment/sentry_holder/proc/undeploy_sentry() if(!deployed_turret) return @@ -267,8 +274,12 @@ deployed_turret.stop_processing() deployed_turret.unset_range() icon_state = "sentry_system_installed" + QDEL_NULL(deployed_turret.linked_cam) - +/obj/structure/dropship_equipment/sentry_holder/Destroy() + if(deployed_turret) + QDEL_NULL(deployed_turret.linked_cam) + . = ..() /// Holder for the dropship mannable machinegun system diff --git a/code/modules/cm_marines/equipment/gear.dm b/code/modules/cm_marines/equipment/gear.dm index 98e7dbcf49df..ff6c715b520b 100644 --- a/code/modules/cm_marines/equipment/gear.dm +++ b/code/modules/cm_marines/equipment/gear.dm @@ -58,6 +58,8 @@ var/is_animating = FALSE var/first_open = TRUE exit_stun = 0 + /// used to implement a delay before tarp can be entered again after opened (anti-exploit) + COOLDOWN_DECLARE(toggle_delay) /obj/structure/closet/bodybag/tarp/snow icon_state = "snowtarp_closed" @@ -91,9 +93,9 @@ exit_stun = 1 can_store_dead = TRUE -/obj/structure/closet/bodybag/tarp/reactive/scout/close() +/obj/structure/closet/bodybag/tarp/reactive/scout/close(mob/user) if(!skillcheck(usr, SKILL_SPEC_WEAPONS, SKILL_SPEC_ALL) && usr.skills.get_skill_level(SKILL_SPEC_WEAPONS) != SKILL_SPEC_SCOUT) - to_chat(usr, SPAN_WARNING("You don't seem to know how to use [src]...")) + to_chat(user, SPAN_WARNING("You don't seem to know how to use [src]...")) return . = ..() @@ -137,10 +139,14 @@ return /obj/structure/closet/bodybag/tarp/open() + COOLDOWN_START(src, toggle_delay, 3 SECONDS) //3 seconds must pass before tarp can be closed . = ..() handle_cloaking() -/obj/structure/closet/bodybag/tarp/close() +/obj/structure/closet/bodybag/tarp/close(mob/user) + if(!COOLDOWN_FINISHED(src, toggle_delay)) + to_chat(user, SPAN_WARNING("It is too soon to close [src]!")) + return FALSE . = ..() handle_cloaking() diff --git a/code/modules/cm_marines/marines_consoles.dm b/code/modules/cm_marines/marines_consoles.dm index 21f8a461a016..3539a43e6c15 100644 --- a/code/modules/cm_marines/marines_consoles.dm +++ b/code/modules/cm_marines/marines_consoles.dm @@ -177,7 +177,7 @@ if(!authenticated || !target_id_card) return - var/new_name = params["name"] // reject_bad_name() can be added here + var/new_name = strip_html(params["name"]) if(!new_name) visible_message(SPAN_NOTICE("[src] buzzes rudely.")) return @@ -191,7 +191,7 @@ return if(target == "Custom") - var/custom_name = params["custom_name"] + var/custom_name = strip_html(params["custom_name"]) if(custom_name) target_id_card.assignment = custom_name else diff --git a/code/modules/cm_marines/orbital_cannon.dm b/code/modules/cm_marines/orbital_cannon.dm index 431b03fb31d3..ad214c954915 100644 --- a/code/modules/cm_marines/orbital_cannon.dm +++ b/code/modules/cm_marines/orbital_cannon.dm @@ -353,6 +353,9 @@ var/list/ob_type_fuel_requirements /obj/structure/ob_ammo/warhead name = "theoretical orbital ammo" var/warhead_kind + var/shake_frequency + var/max_shake_factor + var/max_knockdown_time /obj/structure/ob_ammo/warhead/proc/warhead_impact(turf/target) // make damn sure everyone hears it @@ -398,10 +401,37 @@ var/list/ob_type_fuel_requirements return TRUE return FALSE +/// proc designed for handling ob camera shakes, takes the target location as input and calculates camera shake based off user location. +/obj/structure/ob_ammo/warhead/proc/handle_ob_shake(turf/epicenter) + + var/radius_size = 30 + + for(var/mob/living/user in urange(radius_size, epicenter)) + + var/distance = get_accurate_dist(get_turf(user), epicenter) + var/distance_percent = ((radius_size - distance) / radius_size) + var/total_shake_factor = abs(max_shake_factor * distance_percent) + + // it's of type cluster. + if(!max_knockdown_time) + shake_camera(user, 0.5, total_shake_factor, shake_frequency) + continue + + shake_camera(user, 3, total_shake_factor, shake_frequency) + user.KnockDown(rand(max_knockdown_time * distance_percent, (max_knockdown_time * distance_percent + 1))) + + if(!user.knocked_down) + continue + to_chat(user, SPAN_WARNING("You are thrown off balance and fall to the ground!")) + /obj/structure/ob_ammo/warhead/explosive name = "\improper HE orbital warhead" warhead_kind = "explosive" icon_state = "ob_warhead_1" + shake_frequency = 3 + max_shake_factor = 15 + max_knockdown_time = 6 + var/clear_power = 1200 var/clear_falloff = 400 var/standard_power = 600 @@ -419,16 +449,20 @@ var/list/ob_type_fuel_requirements var/datum/cause_data/cause_data = create_cause_data(initial(name), source_mob) cell_explosion(target, clear_power, clear_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) //break shit around sleep(clear_delay) - //ACTUALLY BLOW SHIT UP + + // Explosion if turf is not a wall. if(!target.density) cell_explosion(target, standard_power, standard_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) + handle_ob_shake(target) sleep(double_explosion_delay) cell_explosion(target, standard_power, standard_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) return + // Checks turf around the target for(var/turf/T in range(2, target)) if(!T.density) cell_explosion(target, standard_power, standard_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) + handle_ob_shake(target) sleep(double_explosion_delay) cell_explosion(target, standard_power, standard_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) return @@ -437,6 +471,9 @@ var/list/ob_type_fuel_requirements name = "\improper Incendiary orbital warhead" warhead_kind = "incendiary" icon_state = "ob_warhead_2" + shake_frequency = 1 + max_shake_factor = 8 + max_knockdown_time = 3 var/clear_power = 1200 var/clear_falloff = 400 var/clear_delay = 3 @@ -457,6 +494,8 @@ var/list/ob_type_fuel_requirements sleep(10) var/datum/cause_data/cause_data = create_cause_data(initial(name), source_mob) cell_explosion(target, clear_power, clear_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) //break shit around + handle_ob_shake(target) + sleep(clear_delay) fire_spread(target, cause_data, distance, fire_level, burn_level, fire_color, fire_type, TURF_PROTECTION_OB) @@ -464,6 +503,9 @@ var/list/ob_type_fuel_requirements name = "\improper Cluster orbital warhead" warhead_kind = "cluster" icon_state = "ob_warhead_3" + shake_frequency = 2 + max_shake_factor = 1 + var/total_amount = 75 // how many times will the shell fire? var/instant_amount = 3 // how many explosions per time it fires? var/explosion_power = 350 @@ -484,20 +526,21 @@ var/list/ob_type_fuel_requirements var/list/turf_list = list() for(var/turf/T in range(range_num, target)) - if(protected_by_pylon(TURF_PROTECTION_OB, T)) - continue - turf_list += T for(var/i = 1 to total_amount) for(var/k = 1 to instant_amount) var/turf/U = pick(turf_list) + if(protected_by_pylon(TURF_PROTECTION_OB, U)) //If the turf somehow gained OB protection while the cluster was firing + continue fire_in_a_hole(U) + sleep(delay_between_clusters) /obj/structure/ob_ammo/warhead/cluster/proc/fire_in_a_hole(turf/loc) new /obj/effect/overlay/temp/blinking_laser (loc) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), loc, explosion_power, explosion_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)), 1 SECONDS) + addtimer(CALLBACK(src, PROC_REF(handle_ob_shake), loc), 1 SECONDS) /obj/structure/ob_ammo/ob_fuel name = "solid fuel" @@ -608,3 +651,4 @@ var/list/ob_type_fuel_requirements return TRUE tgui_interact(user) + diff --git a/code/modules/cm_marines/overwatch.dm b/code/modules/cm_marines/overwatch.dm index 401d8fd9784a..070cf1f6c1cf 100644 --- a/code/modules/cm_marines/overwatch.dm +++ b/code/modules/cm_marines/overwatch.dm @@ -866,6 +866,9 @@ message_admins(FONT_SIZE_HUGE("ALERT: [key_name(user)] fired an orbital bombardment in [A.name] for squad '[current_squad]' [ADMIN_JMP(T)]")) log_attack("[key_name(user)] fired an orbital bombardment in [A.name] for squad '[current_squad]'") + /// Project ARES interface log. + GLOB.ares_link.log_ares_bombardment(user, ob_name, "X[x_bomb], Y[y_bomb] in [A.name]") + busy = FALSE var/turf/target = locate(T.x + rand(-3, 3), T.y + rand(-3, 3), T.z) if(target && istype(target)) diff --git a/code/modules/cm_marines/smartgun_mount.dm b/code/modules/cm_marines/smartgun_mount.dm index ec79a2f7f3fd..2db33c10ed46 100644 --- a/code/modules/cm_marines/smartgun_mount.dm +++ b/code/modules/cm_marines/smartgun_mount.dm @@ -111,6 +111,11 @@ to_chat(usr, SPAN_WARNING("It's too cramped in here to deploy \a [src].")) return var/turf/T = get_turf(usr) + if(istype(T, /turf/open)) + var/turf/open/floor = T + if(!floor.allow_construction) + to_chat(user, SPAN_WARNING("You cannot install \the [src] here, find a more secure surface!")) + return FALSE var/fail = FALSE if(T.density) fail = TRUE @@ -195,6 +200,11 @@ to_chat(usr, SPAN_WARNING("It's too cramped in here to deploy \a [src].")) return var/turf/T = get_turf(user) + if(istype(T, /turf/open)) + var/turf/open/floor = T + if(!floor.allow_construction) + to_chat(user, SPAN_WARNING("You cannot install \the [src] here, find a more secure surface!")) + return FALSE var/fail = FALSE if(T.density) fail = TRUE @@ -370,6 +380,11 @@ if(fail) to_chat(user, SPAN_WARNING("You can't install \the [src] here, something is in the way.")) return + if(istype(T, /turf/open)) + var/turf/open/floor = T + if(!floor.allow_construction) + to_chat(user, SPAN_WARNING("You cannot install \the [src] here, find a more secure surface!")) + return FALSE if(gun_mounted) to_chat(user, "You're securing the M56D into place...") @@ -1061,7 +1076,7 @@ if(SSinterior.in_interior(user)) to_chat(usr, SPAN_WARNING("It's too cramped in here to deploy \a [src].")) return FALSE - if(OT.density || !isturf(OT)) + if(OT.density || !isturf(OT) || !OT.allow_construction) to_chat(user, SPAN_WARNING("You can't set up \the [src] here.")) return FALSE if(rotate_check.density) diff --git a/code/modules/cm_tech/implements/railgun.dm b/code/modules/cm_tech/implements/railgun.dm index b0d91515419f..b69f9a9d13a8 100644 --- a/code/modules/cm_tech/implements/railgun.dm +++ b/code/modules/cm_tech/implements/railgun.dm @@ -6,6 +6,7 @@ GLOBAL_DATUM(railgun_eye_location, /datum/coords) /obj/effect/landmark/railgun_computer name = "Railgun computer landmark" + desc = "A computer with an orange interface, it's idly blinking, awaiting a password." /obj/effect/landmark/railgun_computer/Initialize(mapload, ...) . = ..() diff --git a/code/modules/cm_tech/tech.dm b/code/modules/cm_tech/tech.dm index 5c37dafef3f3..dea505f3237a 100644 --- a/code/modules/cm_tech/tech.dm +++ b/code/modules/cm_tech/tech.dm @@ -21,6 +21,9 @@ var/background_icon = "background" var/background_icon_locked = "marine" + var/announce_name + var/announce_message + /datum/tech/proc/can_unlock(mob/M) SHOULD_CALL_PARENT(TRUE) @@ -68,6 +71,10 @@ log_admin("[key_name_admin(user)] has bought '[name]' via tech points.") holder.spend_points(required_points) update_icon(node) + + if(!(tech_flags & TECH_FLAG_NO_ANNOUNCE) && announce_message && announce_name) + marine_announcement(announce_message, announce_name, 'sound/misc/notice2.ogg') + return TRUE /datum/tech/ui_status(mob/user, datum/ui_state/state) diff --git a/code/modules/cm_tech/techs/abstract/repeatable.dm b/code/modules/cm_tech/techs/abstract/repeatable.dm index e9706538071c..4b240814e0c6 100644 --- a/code/modules/cm_tech/techs/abstract/repeatable.dm +++ b/code/modules/cm_tech/techs/abstract/repeatable.dm @@ -4,9 +4,6 @@ /datum/tech/repeatable name = "Repeatable Tech" - var/announce_name - var/announce_message - tech_flags = TECH_FLAG_MULTIUSE var/purchase_cooldown = 10 SECONDS var/next_purchase = 0 @@ -35,8 +32,6 @@ /datum/tech/repeatable/on_unlock() ..() - if(!(tech_flags & TECH_FLAG_NO_ANNOUNCE) && announce_message && announce_name) - marine_announcement(announce_message, announce_name, 'sound/misc/notice2.ogg') next_purchase = world.time + purchase_cooldown required_points += increase_per_purchase diff --git a/code/modules/cm_tech/techs/abstract/transitory.dm b/code/modules/cm_tech/techs/abstract/transitory.dm index 09301b6ba205..7798b6053d0e 100644 --- a/code/modules/cm_tech/techs/abstract/transitory.dm +++ b/code/modules/cm_tech/techs/abstract/transitory.dm @@ -87,3 +87,22 @@ required_points = 5 flags = TREE_FLAG_MARINE + +/datum/tech/transitory/tier4 + name = "Unlock Tier 4" + tier = /datum/tier/three_transition_four + + before = /datum/tier/three + next = /datum/tier/four + +/datum/tech/transitory/tier4/xeno + techs_to_unlock = 0 + required_points = 5 + + flags = TREE_FLAG_XENO + +/datum/tech/transitory/tier4/marine + techs_to_unlock = 0 + required_points = 5 + + flags = TREE_FLAG_MARINE diff --git a/code/modules/cm_tech/techs/marine/tier3/cryorine.dm b/code/modules/cm_tech/techs/marine/tier3/cryorine.dm index fb9666623e1c..84361baa618f 100644 --- a/code/modules/cm_tech/techs/marine/tier3/cryorine.dm +++ b/code/modules/cm_tech/techs/marine/tier3/cryorine.dm @@ -23,4 +23,4 @@ /datum/tech/repeatable/cryomarine/on_unlock() . = ..() - SSticker.mode.get_specific_call("Marine Cryo Reinforcements (Squad)", FALSE, FALSE) + SSticker.mode.get_specific_call("Marine Cryo Reinforcements (Squad)", FALSE, FALSE, announce_dispatch_message = FALSE) diff --git a/code/modules/cm_tech/techs/marine/tier4/nuke.dm b/code/modules/cm_tech/techs/marine/tier4/nuke.dm new file mode 100644 index 000000000000..eb4e64b59951 --- /dev/null +++ b/code/modules/cm_tech/techs/marine/tier4/nuke.dm @@ -0,0 +1,43 @@ +#define NUKE_UNLOCK_TIME (120 MINUTES) + +/datum/tech/nuke + name = "Nuclear Device" + //desc = "Purchase a nuclear device. Only able to purchase after X minutes into the operation. It's the only way to be sure." //See New() + icon_state = "nuke" + + required_points = 20 + + tier = /datum/tier/four + + announce_name = "NUCLEAR ARSENAL ACQUIRED" + announce_message = "A nuclear device has been purchased and will be delivered to requisitions via ASRS." + + flags = TREE_FLAG_MARINE + +/datum/tech/nuke/New() + desc = "Purchase a nuclear device. Only able to purchase [NUKE_UNLOCK_TIME / (1 MINUTES)] minutes into the operation. It's the only way to be sure." + +/datum/tech/nuke/on_unlock() + . = ..() + + var/datum/supply_order/new_order = new /datum/supply_order() + new_order.ordernum = supply_controller.ordernum + supply_controller.ordernum++ + new_order.object = supply_controller.supply_packs["Intel Operational Nuke"] + new_order.orderedby = MAIN_AI_SYSTEM + + supply_controller.shoppinglist += new_order + +/datum/tech/nuke/can_unlock(mob/unlocking_mob) + . = ..() + + if(!.) + return + + if(ROUND_TIME < NUKE_UNLOCK_TIME) + to_chat(unlocking_mob, SPAN_WARNING("You cannot purchase this node before [NUKE_UNLOCK_TIME / (1 MINUTES)] minutes into the operation.")) + return FALSE + + return TRUE + +#undef NUKE_UNLOCK_TIME diff --git a/code/modules/defenses/defenses.dm b/code/modules/defenses/defenses.dm index ee6db2b10455..f47ae3e4d77b 100644 --- a/code/modules/defenses/defenses.dm +++ b/code/modules/defenses/defenses.dm @@ -303,6 +303,10 @@ playsound(src.loc, 'sound/items/Ratchet.ogg', 25, 1) return else + var/turf/open/floor = get_turf(src) + if(!floor.allow_construction) + to_chat(user, SPAN_WARNING("You cannot secure \the [src] here, find a more secure surface!")) + return FALSE user.visible_message(SPAN_NOTICE("[user] begins securing [src] to the ground."), SPAN_NOTICE("You begin securing [src] to the ground.")) diff --git a/code/modules/defenses/handheld.dm b/code/modules/defenses/handheld.dm index e68522871561..233dad313d25 100644 --- a/code/modules/defenses/handheld.dm +++ b/code/modules/defenses/handheld.dm @@ -66,7 +66,12 @@ blocked = TRUE break - if(istype(T, /turf/closed)) + if(istype(T, /turf/open)) + var/turf/open/floor = T + if(!floor.allow_construction) + to_chat(user, SPAN_WARNING("You cannot deploy \a [src] here, find a more secure surface!")) + return FALSE + else blocked = TRUE if(blocked) diff --git a/code/modules/defenses/sentry.dm b/code/modules/defenses/sentry.dm index 3d485f3abda7..946c347efaa0 100644 --- a/code/modules/defenses/sentry.dm +++ b/code/modules/defenses/sentry.dm @@ -539,11 +539,13 @@ choice_categories = list() selected_categories = list() var/obj/structure/dropship_equipment/sentry_holder/deployment_system + var/obj/structure/machinery/camera/cas/linked_cam /obj/structure/machinery/defenses/sentry/premade/dropship/Destroy() if(deployment_system) deployment_system.deployed_turret = null deployment_system = null + QDEL_NULL(linked_cam) . = ..() #define SENTRY_SNIPER_RANGE 10 diff --git a/code/modules/gear_presets/cmb.dm b/code/modules/gear_presets/cmb.dm index a1ea205a8f61..79df8d567770 100644 --- a/code/modules/gear_presets/cmb.dm +++ b/code/modules/gear_presets/cmb.dm @@ -79,7 +79,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/head/CMB, WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/veteran/pmc/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/sechud, WEAR_EYES) - new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full, WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/ert, WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel/sec, WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/holdout, WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/device/radio, WEAR_IN_BACK) @@ -171,7 +171,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/veteran/pmc/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/sechud, WEAR_EYES) //pouches - new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full, WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/ert, WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/shotgun/large, WEAR_R_STORE) new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/shotgun/buckshot, WEAR_IN_R_STORE) new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/handful/shotgun/buckshot, WEAR_IN_R_STORE) @@ -328,7 +328,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/veteran/pmc/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses, WEAR_EYES) //pouches - new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full, WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/ert, WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large, WEAR_R_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/fancy/cigarettes/wypacket, WEAR_IN_R_STORE) new_human.equip_to_slot_or_del(new /obj/item/tool/lighter/zippo, WEAR_IN_R_STORE) @@ -450,7 +450,7 @@ new_human.equip_to_slot_or_del(new /obj/item/storage/box/packet/high_explosive, WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/box/packet/high_explosive, WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full, WEAR_R_STORE) - new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full, WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/ert, WEAR_L_STORE) //Anchorpoint Station Marine Squad Leader @@ -490,7 +490,7 @@ new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1/anchorpoint, WEAR_J_STORE) new_human.equip_to_slot_or_del(new /obj/item/device/motiondetector, WEAR_WAIST) - new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full, WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/ert, WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/magazine/large, WEAR_R_STORE) new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap, WEAR_IN_R_STORE) new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap, WEAR_IN_R_STORE) @@ -541,7 +541,7 @@ new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1, WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1, WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/construction/full, WEAR_R_STORE) - new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full, WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/ert, WEAR_L_STORE) new_human.back.pickup() @@ -631,7 +631,7 @@ new_human.equip_to_slot_or_del(new /obj/item/stack/medical/bruise_pack, WEAR_IN_JACKET) new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/smartgun, WEAR_J_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full, WEAR_R_STORE) - new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full, WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/ert, WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine, WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife, WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/marine/smartgunner/full/, WEAR_WAIST) diff --git a/code/modules/gear_presets/corpses.dm b/code/modules/gear_presets/corpses.dm index 02671cc02a93..7e9dd5b841a0 100644 --- a/code/modules/gear_presets/corpses.dm +++ b/code/modules/gear_presets/corpses.dm @@ -16,28 +16,32 @@ /datum/equipment_preset/corpse/load_status(mob/living/carbon/human/new_human) . = ..(new_human) + + // These two values matter because they are checked on death for weed_food + new_human.undefibbable = TRUE + if(xenovictim) + new_human.chestburst = 2 + new_human.death(create_cause_data("existing"), TRUE) //Kills the new mob new_human.apply_damage(100, BRUTE) new_human.apply_damage(100, BRUTE) new_human.apply_damage(100, BRUTE) if(xenovictim) - var/datum/internal_organ/O + var/datum/internal_organ/organ var/i for(i in list("heart","lungs")) - O = new_human.internal_organs_by_name[i] + organ = new_human.internal_organs_by_name[i] new_human.internal_organs_by_name -= i - new_human.internal_organs -= O - new_human.chestburst = 2 + new_human.internal_organs -= organ new_human.update_burst() //buckle to nest - var/obj/structure/bed/nest/N = locate() in get_turf(src) - if(N) - new_human.buckled = N - new_human.setDir(N.dir) + var/obj/structure/bed/nest/nest = locate() in get_turf(src) + if(nest) + new_human.buckled = nest + new_human.setDir(nest.dir) new_human.update_canmove() - N.buckled_mob = new_human - N.afterbuckle(new_human) - new_human.undefibbable = TRUE + nest.buckled_mob = new_human + nest.afterbuckle(new_human) new_human.spawned_corpse = TRUE new_human.updatehealth() new_human.pulse = PULSE_NONE diff --git a/code/modules/gear_presets/survivors.dm b/code/modules/gear_presets/survivors.dm index 42d5ec0915bb..44808d7a374f 100644 --- a/code/modules/gear_presets/survivors.dm +++ b/code/modules/gear_presets/survivors.dm @@ -346,6 +346,20 @@ ..() +/datum/equipment_preset/survivor/corporate/solaris + name = "Survivor - Solaris Ridge Corporate Liaison" + assignment = "Solaris Ridge Corporate Liaison" + +/datum/equipment_preset/survivor/corporate/solaris/load_gear(mob/living/carbon/human/new_human) + new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/outing/red(new_human), WEAR_BODY) + if(new_human.disabilities & NEARSIGHTED) + new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/prescription(new_human), WEAR_EYES) + else + new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses(new_human), WEAR_EYES) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + + ..() + // ----- Security Survivor /datum/equipment_preset/survivor/security @@ -961,6 +975,7 @@ /datum/equipment_preset/survivor/colonial_marshal/load_gear(mob/living/carbon/human/new_human) new_human.equip_to_slot_or_del(new /obj/item/clothing/under/CM_uniform(new_human), WEAR_BODY) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/CMB/limited(new_human), WEAR_L_EAR) if(SSmapping.configs[GROUND_MAP].environment_traits[MAP_COLD]) add_ice_colony_survivor_equipment(new_human) @@ -1011,6 +1026,7 @@ /datum/equipment_preset/survivor/colonial_marshal/solaris/load_gear(mob/living/carbon/human/new_human) new_human.equip_to_slot_or_del(new /obj/item/clothing/under/CM_uniform(new_human), WEAR_BODY) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/CMB/limited(new_human), WEAR_L_EAR) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/CMB(new_human), WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel/sec(new_human), WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) @@ -1025,6 +1041,7 @@ add_random_kutjevo_survivor_uniform(new_human) add_random_kutjevo_survivor_equipment(new_human) new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/CMB/limited(new_human), WEAR_L_EAR) ..() @@ -1034,6 +1051,7 @@ /datum/equipment_preset/survivor/colonial_marshal/shiva/load_gear(mob/living/carbon/human/new_human) new_human.equip_to_slot_or_del(new /obj/item/clothing/under/rank/security/corp(new_human), WEAR_BODY) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/CMB/limited(new_human), WEAR_L_EAR) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/snow_suit/survivor/parka/red(new_human), WEAR_JACKET) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/ushanka(new_human), WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/rebreather/scarf(new_human), WEAR_FACE) @@ -1059,6 +1077,7 @@ /datum/equipment_preset/survivor/interstellar_commerce_commission_liason/load_gear(mob/living/carbon/human/new_human) new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit(new_human), WEAR_BODY) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/CMB/limited(new_human), WEAR_L_EAR) if(SSmapping.configs[GROUND_MAP].environment_traits[MAP_COLD]) add_ice_colony_survivor_equipment(new_human) @@ -1079,6 +1098,7 @@ /datum/equipment_preset/survivor/interstellar_commerce_commission_liason/corsat/load_gear(mob/living/carbon/human/new_human) new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/formal(new_human), WEAR_BODY) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/CMB/limited(new_human), WEAR_L_EAR) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/hardhat/white(new_human), WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(new_human), WEAR_JACKET) @@ -1349,3 +1369,43 @@ return var/shoespath = /obj/item/clothing/shoes/combat human.equip_to_slot_or_del(new shoespath, WEAR_FEET) + +/datum/equipment_preset/survivor/new_varadero/commander + name = "Survivor - USASF Commander" + assignment = "USASF Commander" + skills = /datum/skills/commander + paygrade = "NO5" + idtype = /obj/item/card/id/gold + role_comm_title = "USASF CDR" + flags = EQUIPMENT_PRESET_START_OF_ROUND + access = list( + ACCESS_CIVILIAN_PUBLIC, + ACCESS_CIVILIAN_RESEARCH, + ACCESS_CIVILIAN_ENGINEERING, + ACCESS_CIVILIAN_LOGISTICS, + ACCESS_CIVILIAN_BRIG, + ACCESS_CIVILIAN_MEDBAY, + ACCESS_CIVILIAN_COMMAND, + ) + +/datum/equipment_preset/survivor/new_varadero/commander/load_gear(mob/living/carbon/human/new_human) + new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/officer/bridge(new_human), WEAR_BODY) + + var/obj/item/clothing/suit/storage/jacket/marine/service/suit = new() + suit.icon_state = "[suit.initial_icon_state]_o" + suit.buttoned = FALSE + + var/obj/item/clothing/accessory/ranks/navy/o5/pin = new() + suit.attach_accessory(new_human, pin) + + new_human.equip_to_slot_or_del(suit, WEAR_JACKET) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress(new_human), WEAR_L_EAR) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/survival/full(new_human), WEAR_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large(new_human), WEAR_R_STORE) + new_human.equip_to_slot_or_del(new /obj/item/notepad(new_human), WEAR_IN_R_STORE) + new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_IN_R_STORE) + new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel(new_human), WEAR_BACK) + new_human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/med_small_stack(new_human), WEAR_IN_BACK) + new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/m4a3/m1911(new_human), WEAR_WAIST) + new_human.equip_to_slot_or_del(new /obj/item/clothing/head/cmcap(new_human), WEAR_HEAD) diff --git a/code/modules/gear_presets/synths.dm b/code/modules/gear_presets/synths.dm index f2a5283e2a26..823cfb4d69d4 100644 --- a/code/modules/gear_presets/synths.dm +++ b/code/modules/gear_presets/synths.dm @@ -532,6 +532,7 @@ new_human.h_style = "Bald" new_human.f_style = "Shaved" if(prob(5)) + new_human.grad_style = "None" //No gradients for Working Joes new_human.h_style = "Shoulder-length Hair" //Added the chance of hair as per Monkeyfist lore accuracy new_human.r_eyes = 0 new_human.g_eyes = 0 diff --git a/code/modules/gear_presets/uscm_police.dm b/code/modules/gear_presets/uscm_police.dm index 2b8cb2ce453c..29bc32cffa7a 100644 --- a/code/modules/gear_presets/uscm_police.dm +++ b/code/modules/gear_presets/uscm_police.dm @@ -184,6 +184,7 @@ new_human.equip_to_slot_or_del(new /obj/item/device/taperecorder(new_human), WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large(new_human), WEAR_R_STORE) + //*****************************************************************************************************/ /datum/equipment_preset/uscm_ship/uscm_police/riot_mp diff --git a/code/modules/gear_presets/uscm_ship.dm b/code/modules/gear_presets/uscm_ship.dm index 688a55d0f0f6..7aa9eabb3042 100644 --- a/code/modules/gear_presets/uscm_ship.dm +++ b/code/modules/gear_presets/uscm_ship.dm @@ -198,6 +198,7 @@ ACCESS_MARINE_MAINT, ACCESS_MARINE_OT, ACCESS_MARINE_SYNTH, + ACCESS_MARINE_AI, ) assignment = JOB_CHIEF_ENGINEER rank = JOB_CHIEF_ENGINEER diff --git a/code/modules/mentor/mentorhelp.dm b/code/modules/mentor/mentorhelp.dm index 8413b6d118e6..84dacf4f8bfb 100644 --- a/code/modules/mentor/mentorhelp.dm +++ b/code/modules/mentor/mentorhelp.dm @@ -108,28 +108,28 @@ sound_to(recipient, 'sound/effects/mhelp.ogg') to_chat(recipient, wrap_message(msg, sender)) - for(var/client/C in GLOB.admins) + for(var/client/admin_client in GLOB.admins) var/formatted = msg var/soundfile - if(!C || C == recipient) + if(!admin_client || admin_client == recipient) continue // Initial broadcast - else if(!staff_only && !recipient && CLIENT_HAS_RIGHTS(C, R_MENTOR)) + else if(!staff_only && !recipient && CLIENT_HAS_RIGHTS(admin_client, R_MENTOR)) formatted = wrap_message(formatted, sender) soundfile = 'sound/effects/mhelp.ogg' - // Staff eavesdrop - else if(CLIENT_HAS_RIGHTS(C, R_MENTOR) && CLIENT_IS_STAFF(C)) + // Eavesdrop + else if(CLIENT_HAS_RIGHTS(admin_client, R_MENTOR) && (!staff_only || CLIENT_IS_STAFF(admin_client)) && admin_client != sender) if(include_keys) formatted = SPAN_MENTORHELP(key_name(sender, TRUE) + " -> " + key_name(recipient, TRUE) + ": ") + msg else continue - if(soundfile && with_sound && (C.prefs?.toggles_sound & SOUND_ADMINHELP)) - sound_to(C, soundfile) - to_chat(C, formatted) + if(soundfile && with_sound && (admin_client.prefs?.toggles_sound & SOUND_ADMINHELP)) + sound_to(admin_client, soundfile) + to_chat(admin_client, formatted) return // Makes the sender input a message and sends it diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 47e747d4cd5c..7e8dfe6cf3fd 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -33,8 +33,8 @@ plane = GHOST_PLANE layer = ABOVE_FLY_LAYER stat = DEAD - var/adminlarva = 0 - var/ghostvision = 1 + var/adminlarva = FALSE + var/ghostvision = TRUE var/can_reenter_corpse var/started_as_observer //This variable is set to 1 when you enter the game as an observer. //If you died in the game and are a ghost - this will remain as null. @@ -45,7 +45,7 @@ "Squad HUD" = FALSE, "Xeno Status HUD" = FALSE ) - universal_speak = 1 + universal_speak = TRUE var/updatedir = TRUE //Do we have to update our dir as the ghost moves around? var/atom/movable/following = null var/datum/orbit_menu/orbit_menu @@ -55,6 +55,8 @@ var/own_orbit_size = 0 var/observer_actions = list(/datum/action/observer_action/join_xeno) var/datum/action/minimap/observer/minimap + var/larva_queue_cached_message + alpha = 127 /mob/dead/observer/verb/toggle_ghostsee() @@ -84,7 +86,6 @@ body.alter_ghost(src) apply_transform(matrix()) - own_orbit_size = body.get_orbit_size() desc = initial(desc) @@ -93,6 +94,7 @@ invisibility = INVISIBILITY_OBSERVER plane = GHOST_PLANE layer = ABOVE_FLY_LAYER + mouse_opacity = MOUSE_OPACITY_ICON // In case we were weed_food sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS|SEE_SELF see_invisible = INVISIBILITY_OBSERVER @@ -327,8 +329,8 @@ Works together with spawning an observer, noted above. ghost.langchat_make_image() SStgui.on_transfer(src, ghost) - if(is_admin_level(z)) - ghost.timeofdeath = 0 // Bypass respawn limit if you die on the admin zlevel + if(is_admin_level((get_turf(src))?.z)) // Gibbed humans ghostize the brain in their head which itself is z 0 + ghost.timeofdeath = 1 // Bypass respawn limit if you die on the admin zlevel ghost.key = key ghost.mind = mind @@ -363,6 +365,11 @@ Works together with spawning an observer, noted above. if(ghost.client.player_data) ghost.client.player_data.load_timestat_data() + // Larva queue: We use the larger of their existing queue time or the new timeofdeath except for facehuggers + // We don't change facehugger timeofdeath because they are still on cooldown if they died as a hugger + var/new_tod = isfacehugger(src) ? 1 : ghost.timeofdeath + ghost.client.player_details.larva_queue_time = max(ghost.client.player_details.larva_queue_time, new_tod) + ghost.set_huds_from_prefs() return ghost @@ -390,7 +397,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/is_nested = (buckled && istype(buckled, /obj/structure/bed/nest)) ? TRUE : FALSE var/obj/structure/bed/nest/nest = FALSE if(is_nested) - text_prompt += "\nSince you're nested, you will be given a chance to reenter your body upon being freed." + text_prompt += "\nSince you're nested, you will get a chance to reenter your body if freed." nest = buckled var/response = tgui_alert(src, text_prompt, "Are you sure you want to ghost?", options) if(response == "Aghost") @@ -405,6 +412,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/mob/dead/observer/ghost = ghostize((is_nested && nest && !QDELETED(nest))) //FALSE parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3 if(ghost && !is_admin_level(z)) ghost.timeofdeath = world.time + + // Larva queue: We use the larger of their existing queue time or the new timeofdeath except for facehuggers + var/new_tod = isfacehugger(src) ? 1 : world.time + ghost.client?.player_details.larva_queue_time = max(ghost.client.player_details.larva_queue_time, new_tod) if(is_nested && nest && !QDELETED(nest)) ghost.can_reenter_corpse = FALSE nest.ghost_of_buckled_mob = ghost diff --git a/code/modules/mob/language/languages.dm b/code/modules/mob/language/languages.dm index 546c2bf7714f..e5b693e02b80 100644 --- a/code/modules/mob/language/languages.dm +++ b/code/modules/mob/language/languages.dm @@ -147,7 +147,7 @@ /datum/language/apollo name = LANGUAGE_APOLLO - desc = "The Apollo Link is an AI subprocessor designed by SEEGSON, allowing for coordination of maintenance drones and Working Joes. WY denies claims the processor was stolen for ARES." + desc = "The APOLLO Link is an AI subprocessor designed by SEEGSON, allowing for coordination of maintenance drones and Working Joes. WY denies claims the processor was stolen for ARES." color = "skrell" speech_verb = "states" ask_verb = "queries" @@ -166,6 +166,8 @@ var/message_body = "broadcasts, \"[message]\"" GLOB.STUI.game.Add("\[[time_stamp()]]APOLLO: [key_name(speaker)] : [message]
") GLOB.STUI.processing |= STUI_LOG_GAME_CHAT + log_say("[speaker.name != "Unknown" ? speaker.name : "([speaker.real_name])"] \[APOLLO\]: [message] (CKEY: [speaker.key]) (JOB: [speaker.job])") + log_ares_apollo(speaker.real_name, message) for (var/mob/dead in GLOB.dead_mob_list) if(!istype(dead,/mob/new_player) && !istype(dead,/mob/living/brain)) //No meta-evesdropping dead.show_message("[message_start] [message_body]", SHOW_MESSAGE_VISIBLE) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index becb5dcd6610..dbe00407d7ef 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -41,7 +41,9 @@ if(stat == DEAD) species?.handle_dead_death(src, gibbed) return + GLOB.alive_human_list -= src + if(!gibbed) if(HAS_TRAIT(src, TRAIT_HARDCORE) || MODE_HAS_TOGGLEABLE_FLAG(MODE_HARDCORE_PERMA)) if(!(species.flags & IS_SYNTHETIC)) // Synths wont perma @@ -50,8 +52,10 @@ disable_lights() disable_special_items() disable_headsets() //Disable radios for dead people to reduce load + if(pulledby && isxeno(pulledby)) // Xenos lose grab on dead humans pulledby.stop_pulling() + //Handle species-specific deaths. if(species) species.handle_death(src, gibbed) @@ -66,16 +70,14 @@ // Finding the last guy for anti-delay. if(SSticker.mode && SSticker.mode.is_in_endgame && SSticker.current_state != GAME_STATE_FINISHED && is_mainship_level(z)) var/mob/last_living_human - for(var/mob/living/carbon/human/H as anything in GLOB.alive_human_list) - if(!is_mainship_level(H.z)) + for(var/mob/living/carbon/human/cur_human as anything in GLOB.alive_human_list) + if(!is_mainship_level(cur_human.z)) continue if(last_living_human) last_living_human = null break - last_living_human = H - if(last_living_human) - if((last_qm_callout + 2 MINUTES) > world.time) - return + last_living_human = cur_human + if(last_living_human && (last_qm_callout + 2 MINUTES) < world.time) last_qm_callout = world.time // Tell the xenos where the human is. xeno_announcement("I sense the last tallhost hiding in [get_area(last_living_human)].", XENO_HIVE_NORMAL, SPAN_ANNOUNCEMENT_HEADER_BLUE("[QUEEN_MOTHER_ANNOUNCE]")) @@ -103,4 +105,13 @@ if(HAS_TRAIT(src, TRAIT_HARDCORE)) death_message = "valiantly falls to the ground, dead, unable to continue." - return ..(cause, gibbed, death_message) + . = ..(cause, gibbed, death_message) + + // stat is now set + var/datum/cause_data/death_data = cause + if(!gibbed && death_data?.cause_name != "gibbing") + // Hilariously the gibbing proc causes death via droplimb which means gibbed is false... + AddComponent(/datum/component/weed_food) + else if(death_data?.cause_name == "existing") + // Corpses spawn as gibbed true to avoid sfx, even though they aren't actually gibbed... + AddComponent(/datum/component/weed_food) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 00659389decb..5c685cc3acac 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -287,7 +287,7 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t apply_damage(burn, BURN, picked, sharp, edge) UpdateDamageIcon() updatehealth() - speech_problem_flag = 1 + speech_problem_flag = TRUE //Heal MANY limbs, in random order @@ -308,7 +308,7 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t parts -= picked updatehealth() - speech_problem_flag = 1 + speech_problem_flag = TRUE if(update) UpdateDamageIcon() // damage MANY limbs, in random order diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 7f9801145a8e..989ee52fa63c 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -64,7 +64,7 @@ var/voice - var/speech_problem_flag = 0 + var/speech_problem_flag = FALSE var/special_voice = "" // For changing our voice. Used by a symptom. diff --git a/code/modules/mob/living/carbon/human/life/handle_disabilities.dm b/code/modules/mob/living/carbon/human/life/handle_disabilities.dm index 46b1f3e15515..9ab234212108 100644 --- a/code/modules/mob/living/carbon/human/life/handle_disabilities.dm +++ b/code/modules/mob/living/carbon/human/life/handle_disabilities.dm @@ -17,7 +17,7 @@ return if(disabilities & TOURETTES) - speech_problem_flag = 1 + speech_problem_flag = TRUE if((prob(10) && knocked_out <= 1)) apply_effect(10, STUN) spawn() @@ -36,7 +36,7 @@ return if(disabilities & NERVOUS) - speech_problem_flag = 1 + speech_problem_flag = TRUE if(prob(10)) stuttering = max(10, stuttering) return diff --git a/code/modules/mob/living/carbon/human/life/handle_regular_status_updates.dm b/code/modules/mob/living/carbon/human/life/handle_regular_status_updates.dm index 4a6596104d4a..5c951a8112bf 100644 --- a/code/modules/mob/living/carbon/human/life/handle_regular_status_updates.dm +++ b/code/modules/mob/living/carbon/human/life/handle_regular_status_updates.dm @@ -59,7 +59,7 @@ if(regular_update && halloss > 0) apply_damage(-3, HALLOSS) else if(sleeping) - speech_problem_flag = 1 + speech_problem_flag = TRUE if(regular_update) handle_dreams() apply_damage(-3, HALLOSS) @@ -122,7 +122,7 @@ handle_statuses() if(paralyzed) - speech_problem_flag = 1 + speech_problem_flag = TRUE apply_effect(1, WEAKEN) silent = 1 blinded = TRUE diff --git a/code/modules/mob/living/carbon/human/life/life_helpers.dm b/code/modules/mob/living/carbon/human/life/life_helpers.dm index 0339bf6ec742..fedeaf9fd48c 100644 --- a/code/modules/mob/living/carbon/human/life/life_helpers.dm +++ b/code/modules/mob/living/carbon/human/life/life_helpers.dm @@ -216,18 +216,18 @@ /mob/living/carbon/human/handle_silent() if(..()) - speech_problem_flag = 1 + speech_problem_flag = TRUE return silent /mob/living/carbon/human/handle_slurring() if(..()) - speech_problem_flag = 1 + speech_problem_flag = TRUE return slurring /mob/living/carbon/human/handle_stunned() if(stunned) adjust_effect(-species.stun_reduction, STUN, EFFECT_FLAG_LIFE) - speech_problem_flag = 1 + speech_problem_flag = TRUE return stunned /mob/living/carbon/human/handle_dazed() @@ -237,7 +237,7 @@ var/final_reduction = skill_resistance + 1 adjust_effect(-final_reduction, DAZE, EFFECT_FLAG_LIFE) if(dazed) - speech_problem_flag = 1 + speech_problem_flag = TRUE return dazed /mob/living/carbon/human/handle_knocked_down() @@ -262,7 +262,7 @@ /mob/living/carbon/human/handle_stuttering() if(..()) - speech_problem_flag = 1 + speech_problem_flag = TRUE return stuttering #define HUMAN_TIMER_TO_EFFECT_CONVERSION (0.05) //(1/20) //once per 2 seconds, with effect equal to endurance, which is used later diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 46a44fc16611..4b86c827a069 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -262,20 +262,20 @@ for it but just ignore it. /mob/living/carbon/human/proc/handle_speech_problems(message) var/list/returns[3] var/verb = "says" - var/handled = 0 + var/handled = FALSE if(silent) message = "" - handled = 1 + handled = TRUE if(sdisabilities & DISABILITY_MUTE) message = "" - handled = 1 + handled = TRUE if(wear_mask) if(istype(wear_mask, /obj/item/clothing/mask/horsehead)) var/obj/item/clothing/mask/horsehead/hoers = wear_mask if(hoers.voicechange) message = pick("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!") verb = pick("whinnies","neighs", "says") - handled = 1 + handled = TRUE var/braindam = getBrainLoss() if(slurring || stuttering || dazed || braindam >= 60) @@ -283,17 +283,17 @@ for it but just ignore it. if(slurring) message = slur(message) verb = pick("stammers","stutters") - handled = 1 + handled = TRUE if(stuttering) message = NewStutter(message) verb = pick("stammers", "stutters") - handled = 1 + handled = TRUE if(dazed) message = DazedText(message) verb = pick("mumbles", "babbles") - handled = 1 + handled = TRUE if(braindam >= 60) - handled = 1 + handled = TRUE if(prob(braindam/4)) message = stutter(message, stuttering) verb = pick("stammers", "stutters") @@ -301,6 +301,7 @@ for it but just ignore it. message = uppertext(message) verb = pick("yells like an idiot","says rather loudly") if(HAS_TRAIT(src, TRAIT_LISPING)) + handled = TRUE var/old_message = message message = lisp_replace(message) if(old_message != message) diff --git a/code/modules/mob/living/carbon/human/species/emote-synthetic.dm b/code/modules/mob/living/carbon/human/species/emote-synthetic.dm deleted file mode 100644 index fd763b038153..000000000000 --- a/code/modules/mob/living/carbon/human/species/emote-synthetic.dm +++ /dev/null @@ -1,354 +0,0 @@ -/datum/emote/living/carbon/human/synthetic/working_joe - species_type_allowed_typecache = list(/datum/species/synthetic/colonial/working_joe) - keybind_category = CATEGORY_SYNTH_EMOTE - volume = 75 - -/datum/emote/living/carbon/human/synthetic/working_joe/alwaysknow - key = "alwaysknow" - key_third_person = "workingjoe" - sound = 'sound/voice/joe/alwaysknow.ogg' - say_message = "You always know a Working Joe." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/hysterical - key = "hysterical" - sound = 'sound/voice/joe/hysterical.ogg' - say_message = "You are becoming hysterical." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/safety - key = "safety" - sound = 'sound/voice/joe/safety.ogg' - say_message = "You and I are going to have a talk about safety." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/awful_mess - key = "awful" - key_third_person = "mess" - sound = 'sound/voice/joe/awful.ogg' - say_message = "Tut, tut. What an awful mess." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/damage - key = "damage" - sound = 'sound/voice/joe/damage.ogg' - say_message = "Do not damage Seegson property." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/firearm - key = "firearm" - sound = 'sound/voice/joe/firearm.ogg' - say_message = "Firearms can cause serious injury. Let me assist you." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/report - key = "report" - sound = 'sound/voice/joe/report.ogg' - say_message = "Logging report to APOLLO." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/breach - key = "breach" - sound = 'sound/voice/joe/breach.ogg' - say_message = "Hazard Containment breach logged." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/species - key = "species" - sound = 'sound/voice/joe/species.ogg' - say_message = "Unidentified species." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/alwaysknow_damaged - key = "alwaysknowdamaged" - sound = 'sound/voice/joe/alwaysknow_damaged.ogg' - say_message = "You always know a Working Joe." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/apollo_behalf - key = "apollobehalf" - sound = 'sound/voice/joe/apollo_behalf.ogg' - say_message = "I will inform APOLLO on your behalf." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/back_to_work - key = "backtowork" - sound = 'sound/voice/joe/back_to_work.ogg' - say_message = "Back to work." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/beyond_repair - key = "beyondrepair" - sound = 'sound/voice/joe/beyond_repair.ogg' - say_message = "Hmm, far beyond repair." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/come_out_vent - key = "comeoutvent" - sound = 'sound/voice/joe/come_out_vent.ogg' - say_message = "Come out of the vent system, please." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/could_require_attention - key = "couldrequireattention" - sound = 'sound/voice/joe/could_require_attention.ogg' - say_message = "This could require my attention." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/dangerous_items - key = "dangerousitems" - sound = 'sound/voice/joe/dangerous_items.ogg' - say_message = "You are carrying some very dangerous items." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/day_never_done - key = "dayneverdone" - sound = 'sound/voice/joe/day_never_done.ogg' - say_message = "A synthetic's day is never done." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/detailed_report - key = "detailedreport" - sound = 'sound/voice/joe/detailed_report.ogg' - say_message = "APOLLO will require a detailed report." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/fire - key = "fire" - sound = 'sound/voice/joe/fire.ogg' - say_message = "Only wild animals fear fire." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/fire_drill - key = "firedrill" - sound = 'sound/voice/joe/fire_drill.ogg' - say_message = "Please congregate at your nearest fire assembly point. This is not a drill; do not panic." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/unprotected_flames - key = "unprotectedflames" - sound = 'sound/voice/joe/unprotected_flames.ogg' - say_message = "Unprotected flames are extremely dangerous and entirely unadvisable." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/follow_me - key = "followme" - sound = 'sound/voice/joe/follow_me.ogg' - say_message = "Follow me." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/further_assistance - key = "furtherassistance" - sound = 'sound/voice/joe/further_assistance.ogg' - say_message = "Please call if you need further assistance." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/good_day - key = "goodday" - sound = 'sound/voice/joe/good_day.ogg' - say_message = "Good day." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/health_risks - key = "healthrisks" - sound = 'sound/voice/joe/health_risks.ogg' - say_message = "These items carry notable health risks." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/hello - key = "hello" - sound = 'sound/voice/joe/hello.ogg' - say_message = "Hello." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/how_can_i_help - key = "howcanihelp" - sound = 'sound/voice/joe/how_can_i_help.ogg' - say_message = "How can I help you?" - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/irresponsible - key = "irresponsible" - sound = 'sound/voice/joe/irresponsible.ogg' - say_message = "That was irresponsible." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/join_us - key = "joinus" - sound = 'sound/voice/joe/join_us.ogg' - say_message = "We hope you'll join us for the journey." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/little_details - key = "littledetails" - sound = 'sound/voice/joe/little_details.ogg' - say_message = "We don't forget the little details when seeing the big picture." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/lost - key = "lost" - sound = 'sound/voice/joe/lost.ogg' - say_message = "Are you lost?" - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/misbehaving - key = "misbehaving" - sound = 'sound/voice/joe/misbehaving.ogg' - say_message = "Have you been misbehaving?" - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/not_allowed_there - key = "notallowedthere" - sound = 'sound/voice/joe/not_allowed_there.ogg' - say_message = "You're not allowed in there." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/not_liking - key = "notliking" - sound = 'sound/voice/joe/not_liking.ogg' - say_message = "If you find this facility in a state that isn't to your liking, please let me know." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/not_what_i_think - key = "notwhatithink" - sound = 'sound/voice/joe/not_what_i_think.ogg' - say_message = "I hope that's not what I think it is." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/other_concerns - key = "otherconcerns" - sound = 'sound/voice/joe/other_concerns.ogg' - say_message = "I have other concerns." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/more_pressing_matters - key = "morepressingmatters" - sound = 'sound/voice/joe/more_pressing_matters.ogg' - say_message = "There are more pressing matters." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/patience - key = "patience" - sound = 'sound/voice/joe/patience.ogg' - say_message = "You are starting to test my patience." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/presence_logged - key = "presencelogged" - sound = 'sound/voice/joe/presence_logged.ogg' - say_message = "Your presence has been logged." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/required_by_apollo - key = "requiredbyapollo" - sound = 'sound/voice/joe/required_by_apollo.ogg' - say_message = "I am required by APOLLO." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/returning_to_tasks - key = "returningtotasks" - sound = 'sound/voice/joe/returning_to_tasks.ogg' - say_message = "Returning to assigned tasks." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/running_accidents - key = "runningaccidents" - sound = 'sound/voice/joe/running_accidents.ogg' - say_message = "Running causes accidents." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/safety_breach - key = "safetybreach" - sound = 'sound/voice/joe/safety_breach.ogg' - say_message = "This is a breach of multiple safety directives." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/seegson_quality - key = "seegsonquality" - sound = 'sound/voice/joe/seegson_quality.ogg' - say_message = "Seegson - Relentless in the pursuit of affordable quality." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/seegson_standards - key = "seegsonstandards" - sound = 'sound/voice/joe/seegson_standards.ogg' - say_message = "If my services do not meet Seegson standards, please log a complaint." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/shouldnt_be_here - key = "shouldntbehere" - sound = 'sound/voice/joe/shouldnt_be_here.ogg' - say_message = "You shouldn't be here." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/seegson_behind - key = "seegsonbehind" - sound = 'sound/voice/joe/seegson_behind.ogg' - say_message = "With Seegson, there is someone behind you, helping you every step of the way." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/take_a_seat - key = "takeaseat" - sound = 'sound/voice/joe/take_a_seat.ogg' - say_message = "Please take a seat, someone will be with you shortly." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/talk_to_seegson - key = "talktoseegson" - sound = 'sound/voice/joe/talk_to_seegson.ogg' - say_message = "Interested in our Working Joe android range? Talk to Seegson." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/temperatures - key = "temperatures" - sound = 'sound/voice/joe/temperatures.ogg' - say_message = "I am built to whitstand temperatures of up to 1210 degrees." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/that_stings - key = "thatstings" - sound = 'sound/voice/joe/that_stings.ogg' - say_message = "That stings." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/this_is_futile - key = "thisisfutile" - sound = 'sound/voice/joe/this_is_futile.ogg' - say_message = "This is futile." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/trespassing - key = "trespassing" - sound = 'sound/voice/joe/trespassing.ogg' - say_message = "You are trespassing." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/weapon_permit - key = "weaponpermit" - sound = 'sound/voice/joe/weapon_permit.ogg' - say_message = "I assume you have a permit for that weapon." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/what_happened_to_you - key = "whathappenedtoyou" - sound = 'sound/voice/joe/what_happened_to_you.ogg' - say_message = "What happened to you?" - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/what_is_this - key = "whatisthis" - sound = 'sound/voice/joe/what_is_this.ogg' - say_message = "What is this?" - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/with_you_shortly - key = "withyoushortly" - sound = 'sound/voice/joe/with_you_shortly.ogg' - say_message = "I will be with you shortly." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE - -/datum/emote/living/carbon/human/synthetic/working_joe/inexpensive - key = "inexpensive" - sound = 'sound/voice/joe/inexpensive.ogg' - say_message = "I am inexpensive, I am reliable, you know my face - the Working Joe." - emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE diff --git a/code/modules/mob/living/carbon/human/species/synthetic.dm b/code/modules/mob/living/carbon/human/species/synthetic.dm index bdd0a994ed49..bfd3c74eb57b 100644 --- a/code/modules/mob/living/carbon/human/species/synthetic.dm +++ b/code/modules/mob/living/carbon/human/species/synthetic.dm @@ -75,12 +75,12 @@ name = SYNTH_COLONY name_plural = "Colonial Synthetics" uses_ethnicity = TRUE - burn_mod = 0.65 // made for hazardous environments, withstanding temperatures up to 1210 degrees + burn_mod = 0.8 mob_inherent_traits = list(TRAIT_SUPER_STRONG) pain_type = /datum/pain/synthetic/colonial rarity_value = 1.5 - slowdown = 0.45 + slowdown = 0.2 total_health = 200 //But more durable default_lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE @@ -106,16 +106,6 @@ icobase = 'icons/mob/humans/species/r_synthetic.dmi' deform = 'icons/mob/humans/species/r_synthetic.dmi' -/datum/species/synthetic/colonial/working_joe - name = SYNTH_WORKING_JOE - name_plural = "Working Joes" - uses_ethnicity = FALSE - mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_EMOTE_CD_EXEMPT) - - hair_color = "#000000" - icobase = 'icons/mob/humans/species/r_synthetic.dmi' - deform = 'icons/mob/humans/species/r_synthetic.dmi' - // Synth used for W-Y Deathsquads /datum/species/synthetic/colonial/combat name = SYNTH_COMBAT diff --git a/code/modules/mob/living/carbon/human/species/working_joe/_emote.dm b/code/modules/mob/living/carbon/human/species/working_joe/_emote.dm new file mode 100644 index 000000000000..63cc79a57dae --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/working_joe/_emote.dm @@ -0,0 +1,8 @@ +/datum/emote/living/carbon/human/synthetic/working_joe + species_type_allowed_typecache = list(/datum/species/synthetic/colonial/working_joe) + keybind_category = CATEGORY_SYNTH_EMOTE + volume = 75 + /// A general category for the emote, for use in the WJ emote panel. See [code/__DEFINES/wj_emotes.dm] for categories. + var/category = "" + /// Override text for the emote to be displayed in the WJ emote panel + var/override_say = "" diff --git a/code/modules/mob/living/carbon/human/species/working_joe/_species.dm b/code/modules/mob/living/carbon/human/species/working_joe/_species.dm new file mode 100644 index 000000000000..874684480d15 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/working_joe/_species.dm @@ -0,0 +1,131 @@ +/datum/species/synthetic/colonial/working_joe + name = SYNTH_WORKING_JOE + name_plural = "Working Joes" + uses_ethnicity = FALSE + burn_mod = 0.65 // made for hazardous environments, withstanding temperatures up to 1210 degrees + mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_EMOTE_CD_EXEMPT, TRAIT_CANNOT_EAT) + + slowdown = 0.45 + hair_color = "#000000" + icobase = 'icons/mob/humans/species/r_synthetic.dmi' + deform = 'icons/mob/humans/species/r_synthetic.dmi' + +/datum/species/synthetic/colonial/working_joe/handle_post_spawn(mob/living/carbon/human/joe) + . = ..() + give_action(joe, /datum/action/joe_emote_panel) + + +/// Open the WJ's emote panel, which allows them to use voicelines +/datum/species/synthetic/colonial/working_joe/proc/open_emote_panel() + var/datum/joe_emote_panel/ui = new(usr) + ui.ui_interact(usr) + + +/datum/action/joe_emote_panel + name = "Open Voice Synthesizer" + action_icon_state = "looc_toggle" + + +/datum/action/joe_emote_panel/can_use_action() + . = ..() + if(!.) + return FALSE + + if(!isworkingjoe(owner)) + return FALSE + + return TRUE + + +/datum/action/joe_emote_panel/action_activate() + if(!can_use_action()) + return + + var/mob/living/carbon/human/human_owner = owner + var/datum/species/synthetic/colonial/working_joe/joe_species = human_owner.species + joe_species.open_emote_panel() + + +/datum/joe_emote_panel + /// Static dict ("category" : (emotes)) of every wj emote typepath + var/static/list/wj_emotes + /// Static list of categories + var/static/list/wj_categories = list() + /// Panel allows you to spam, so a manual CD is added here + COOLDOWN_DECLARE(panel_emote_cooldown) + + +/datum/joe_emote_panel/New() + if(!length(wj_emotes)) + var/list/emotes_to_add = list() + for(var/datum/emote/living/carbon/human/synthetic/working_joe/emote as anything in subtypesof(/datum/emote/living/carbon/human/synthetic/working_joe)) + if(!initial(emote.key) || !initial(emote.say_message)) + continue + + if(!(initial(emote.category) in wj_categories)) + wj_categories += initial(emote.category) + + emotes_to_add += emote + + + wj_emotes = emotes_to_add + + +/datum/joe_emote_panel/proc/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "JoeEmotes") + ui.open() + + +/datum/joe_emote_panel/ui_state(mob/user) + return GLOB.conscious_state + + +/datum/joe_emote_panel/ui_data(mob/user) + var/list/data = list() + + data["on_cooldown"] = !COOLDOWN_FINISHED(src, panel_emote_cooldown) + + return data + + +/datum/joe_emote_panel/ui_static_data(mob/user) + var/list/data = list() + + data["categories"] = wj_categories + data["emotes"] = list() + + for(var/datum/emote/living/carbon/human/synthetic/working_joe/emote as anything in wj_emotes) + data["emotes"] += list(list( + "id" = initial(emote.key), + "text" = (initial(emote.override_say) || initial(emote.say_message)), + "category" = initial(emote.category), + "path" = "[emote]", + )) + + return data + + +/datum/joe_emote_panel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + if(.) + return + + switch(action) + if("emote") + var/datum/emote/living/carbon/human/synthetic/working_joe/path + if(!params["emotePath"]) + return + + path = text2path(params["emotePath"]) + + if(!path || !COOLDOWN_FINISHED(src, panel_emote_cooldown)) + return + + if(!(path in subtypesof(/datum/emote/living/carbon/human/synthetic/working_joe))) + return + + COOLDOWN_START(src, panel_emote_cooldown, 2.5 SECONDS) + usr.emote(initial(path.key)) + return TRUE diff --git a/code/modules/mob/living/carbon/human/species/working_joe/farewell.dm b/code/modules/mob/living/carbon/human/species/working_joe/farewell.dm new file mode 100644 index 000000000000..1de68d8d3aec --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/working_joe/farewell.dm @@ -0,0 +1,26 @@ +/datum/emote/living/carbon/human/synthetic/working_joe/farewell + category = JOE_EMOTE_CATEGORY_FAREWELL + +/datum/emote/living/carbon/human/synthetic/working_joe/farewell/back_to_work + key = "backtowork" + sound = 'sound/voice/joe/back_to_work.ogg' + say_message = "Back to work." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/farewell/other_concerns + key = "otherconcerns" + sound = 'sound/voice/joe/other_concerns.ogg' + say_message = "I have other concerns." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/farewell/further_assistance + key = "furtherassistance" + sound = 'sound/voice/joe/further_assistance.ogg' + say_message = "Please call if you need further assistance." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/farewell/more_pressing_matters + key = "morepressingmatters" + sound = 'sound/voice/joe/more_pressing_matters.ogg' + say_message = "There are more pressing matters." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE diff --git a/code/modules/mob/living/carbon/human/species/working_joe/greeting.dm b/code/modules/mob/living/carbon/human/species/working_joe/greeting.dm new file mode 100644 index 000000000000..fb401ea95451 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/working_joe/greeting.dm @@ -0,0 +1,20 @@ +/datum/emote/living/carbon/human/synthetic/working_joe/greeting + category = JOE_EMOTE_CATEGORY_GREETING + +/datum/emote/living/carbon/human/synthetic/working_joe/greeting/good_day + key = "goodday" + sound = 'sound/voice/joe/good_day.ogg' + say_message = "Good day." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/greeting/hello + key = "hello" + sound = 'sound/voice/joe/hello.ogg' + say_message = "Hello." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/greeting/how_can_i_help + key = "howcanihelp" + sound = 'sound/voice/joe/how_can_i_help.ogg' + say_message = "How can I help you?" + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE diff --git a/code/modules/mob/living/carbon/human/species/working_joe/notice.dm b/code/modules/mob/living/carbon/human/species/working_joe/notice.dm new file mode 100644 index 000000000000..ca5efe716db8 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/working_joe/notice.dm @@ -0,0 +1,68 @@ +/datum/emote/living/carbon/human/synthetic/working_joe/notice + category = JOE_EMOTE_CATEGORY_NOTICE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/detailed_report + key = "detailedreport" + sound = 'sound/voice/joe/detailed_report.ogg' + say_message = "APOLLO will require a detailed report." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/firearm + key = "firearm" + sound = 'sound/voice/joe/firearm.ogg' + say_message = "Firearms can cause serious injury. Let me assist you." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/follow_me + key = "followme" + sound = 'sound/voice/joe/follow_me.ogg' + say_message = "Follow me." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/breach + key = "breach" + sound = 'sound/voice/joe/breach.ogg' + say_message = "Hazard Containment breach logged." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/beyond_repair + key = "beyondrepair" + sound = 'sound/voice/joe/beyond_repair.ogg' + say_message = "Hmm, far beyond repair." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/with_you_shortly + key = "withyoushortly" + sound = 'sound/voice/joe/with_you_shortly.ogg' + say_message = "I will be with you shortly." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/apollo_behalf + key = "apollobehalf" + sound = 'sound/voice/joe/apollo_behalf.ogg' + say_message = "I will inform APOLLO on your behalf." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/report + key = "report" + sound = 'sound/voice/joe/report.ogg' + say_message = "Logging report to APOLLO." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/take_a_seat + key = "takeaseat" + sound = 'sound/voice/joe/take_a_seat.ogg' + say_message = "Please take a seat, someone will be with you shortly." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/could_require_attention + key = "couldrequireattention" + sound = 'sound/voice/joe/could_require_attention.ogg' + say_message = "This could require my attention." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/notice/species + key = "species" + sound = 'sound/voice/joe/species.ogg' + say_message = "Unidentified species." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE diff --git a/code/modules/mob/living/carbon/human/species/working_joe/question.dm b/code/modules/mob/living/carbon/human/species/working_joe/question.dm new file mode 100644 index 000000000000..d4805e36224f --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/working_joe/question.dm @@ -0,0 +1,26 @@ +/datum/emote/living/carbon/human/synthetic/working_joe/question + category = JOE_EMOTE_CATEGORY_QUESTION + +/datum/emote/living/carbon/human/synthetic/working_joe/question/lost + key = "lost" + sound = 'sound/voice/joe/lost.ogg' + say_message = "Are you lost?" + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/question/misbehaving + key = "misbehaving" + sound = 'sound/voice/joe/misbehaving.ogg' + say_message = "Have you been misbehaving?" + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/question/what_happened_to_you + key = "whathappenedtoyou" + sound = 'sound/voice/joe/what_happened_to_you.ogg' + say_message = "What happened to you?" + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/question/what_is_this + key = "whatisthis" + sound = 'sound/voice/joe/what_is_this.ogg' + say_message = "What is this?" + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE diff --git a/code/modules/mob/living/carbon/human/species/working_joe/quip.dm b/code/modules/mob/living/carbon/human/species/working_joe/quip.dm new file mode 100644 index 000000000000..2ec66f9d9d83 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/working_joe/quip.dm @@ -0,0 +1,84 @@ +/datum/emote/living/carbon/human/synthetic/working_joe/quip + category = JOE_EMOTE_CATEGORY_QUIP + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/temperatures + key = "temperatures" + sound = 'sound/voice/joe/temperatures.ogg' + say_message = "I am built to withstand temperatures of up to 1210 degrees." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/inexpensive + key = "inexpensive" + sound = 'sound/voice/joe/inexpensive.ogg' + say_message = "I am inexpensive, I am reliable, you know my face - the Working Joe." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/weapon_permit + key = "weaponpermit" + sound = 'sound/voice/joe/weapon_permit.ogg' + say_message = "I assume you have a permit for that weapon." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/seegson_standards + key = "seegsonstandards" + sound = 'sound/voice/joe/seegson_standards.ogg' + say_message = "If my services do not meet Seegson standards, please log a complaint." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/not_liking + key = "notliking" + sound = 'sound/voice/joe/not_liking.ogg' + say_message = "If you find this facility in a state that isn't to your liking, please let me know." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/talk_to_seegson + key = "talktoseegson" + sound = 'sound/voice/joe/talk_to_seegson.ogg' + say_message = "Interested in our Working Joe android range? Talk to Seegson." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/seegson_quality + key = "seegsonquality" + sound = 'sound/voice/joe/seegson_quality.ogg' + say_message = "Seegson - Relentless in the pursuit of affordable quality." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/awful_mess + key = "awful" + key_third_person = "mess" + sound = 'sound/voice/joe/awful.ogg' + say_message = "Tut, tut. What an awful mess." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/little_details + key = "littledetails" + sound = 'sound/voice/joe/little_details.ogg' + say_message = "We don't forget the little details when seeing the big picture." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/join_us + key = "joinus" + sound = 'sound/voice/joe/join_us.ogg' + say_message = "We hope you'll join us for the journey." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/seegson_behind + key = "seegsonbehind" + sound = 'sound/voice/joe/seegson_behind.ogg' + say_message = "With Seegson, there is someone behind you, helping you every single step of the way." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/alwaysknow + key = "alwaysknow" + key_third_person = "workingjoe" + sound = 'sound/voice/joe/alwaysknow.ogg' + say_message = "You always know a Working Joe." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/quip/alwaysknow_damaged + key = "alwaysknowdamaged" + key_third_person = "workingjoedamaged" + sound = 'sound/voice/joe/alwaysknow_damaged.ogg' + say_message = "You always know a Working Joe." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + override_say = "You always know a Working Joe. (Damaged)" diff --git a/code/modules/mob/living/carbon/human/species/working_joe/restricted_area.dm b/code/modules/mob/living/carbon/human/species/working_joe/restricted_area.dm new file mode 100644 index 000000000000..fd5db0870b25 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/working_joe/restricted_area.dm @@ -0,0 +1,32 @@ +/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area + category = JOE_EMOTE_CATEGORY_RESTRICTED_AREA + +/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area/come_out_vent + key = "comeoutvent" + sound = 'sound/voice/joe/come_out_vent.ogg' + say_message = "Come out of the vent system, please." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area/trespassing + key = "trespassing" + sound = 'sound/voice/joe/trespassing.ogg' + say_message = "You are trespassing." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area/not_allowed_there + key = "notallowedthere" + sound = 'sound/voice/joe/not_allowed_there.ogg' + say_message = "You're not allowed in there." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area/presence_logged + key = "presencelogged" + sound = 'sound/voice/joe/presence_logged.ogg' + say_message = "Your presence has been logged." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area/shouldnt_be_here + key = "shouldntbehere" + sound = 'sound/voice/joe/shouldnt_be_here.ogg' + say_message = "You shouldn't be here." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE diff --git a/code/modules/mob/living/carbon/human/species/working_joe/task_update.dm b/code/modules/mob/living/carbon/human/species/working_joe/task_update.dm new file mode 100644 index 000000000000..b08f5d179213 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/working_joe/task_update.dm @@ -0,0 +1,20 @@ +/datum/emote/living/carbon/human/synthetic/working_joe/task_update + category = JOE_EMOTE_CATEGORY_TASK_UPDATE + +/datum/emote/living/carbon/human/synthetic/working_joe/task_update/day_never_done + key = "dayneverdone" + sound = 'sound/voice/joe/day_never_done.ogg' + say_message = "A synthetic's day is never done." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/task_update/required_by_apollo + key = "requiredbyapollo" + sound = 'sound/voice/joe/required_by_apollo.ogg' + say_message = "I am required by APOLLO." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/task_update/returning_to_tasks + key = "returningtotasks" + sound = 'sound/voice/joe/returning_to_tasks.ogg' + say_message = "Returning to assigned tasks." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE diff --git a/code/modules/mob/living/carbon/human/species/working_joe/warning.dm b/code/modules/mob/living/carbon/human/species/working_joe/warning.dm new file mode 100644 index 000000000000..63c7dfadde14 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/working_joe/warning.dm @@ -0,0 +1,92 @@ +/datum/emote/living/carbon/human/synthetic/working_joe/warning + category = JOE_EMOTE_CATEGORY_WARNING + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/damage + key = "damage" + sound = 'sound/voice/joe/damage.ogg' + say_message = "Do not damage Seegson property." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/not_what_i_think + key = "notwhatithink" + sound = 'sound/voice/joe/not_what_i_think.ogg' + say_message = "I hope that's not what I think it is." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/fire + key = "fire" + sound = 'sound/voice/joe/fire.ogg' + say_message = "Only wild animals fear fire." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/fire_drill + key = "firedrill" + sound = 'sound/voice/joe/fire_drill.ogg' + say_message = "Please congregate at your nearest fire assembly point. This is not a drill; do not panic." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/running_accidents + key = "runningaccidents" + sound = 'sound/voice/joe/running_accidents.ogg' + say_message = "Running causes accidents." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/that_stings + key = "thatstings" + sound = 'sound/voice/joe/that_stings.ogg' + say_message = "That stings." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/irresponsible + key = "irresponsible" + sound = 'sound/voice/joe/irresponsible.ogg' + say_message = "That was irresponsible." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/health_risks + key = "healthrisks" + sound = 'sound/voice/joe/health_risks.ogg' + say_message = "These items carry notable health risks." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/safety_breach + key = "safetybreach" + sound = 'sound/voice/joe/safety_breach.ogg' + say_message = "This is a breach of multiple safety directives." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/this_is_futile + key = "thisisfutile" + sound = 'sound/voice/joe/this_is_futile.ogg' + say_message = "This is futile." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/unprotected_flames + key = "unprotectedflames" + sound = 'sound/voice/joe/unprotected_flames.ogg' + say_message = "Unprotected flames are extremely dangerous and entirely unadvisable." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/safety + key = "safety" + sound = 'sound/voice/joe/safety.ogg' + say_message = "You and I are going to have a talk about safety." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/hysterical + key = "hysterical" + sound = 'sound/voice/joe/hysterical.ogg' + say_message = "You are becoming hysterical." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/dangerous_items + key = "dangerousitems" + sound = 'sound/voice/joe/dangerous_items.ogg' + say_message = "You are carrying some very dangerous items." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE + +/datum/emote/living/carbon/human/synthetic/working_joe/warning/patience + key = "patience" + sound = 'sound/voice/joe/patience.ogg' + say_message = "You are starting to test my patience." + emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE diff --git a/code/modules/mob/living/carbon/human/species/zombie.dm b/code/modules/mob/living/carbon/human/species/zombie.dm index 2c9c423c671e..532d9413102c 100644 --- a/code/modules/mob/living/carbon/human/species/zombie.dm +++ b/code/modules/mob/living/carbon/human/species/zombie.dm @@ -102,6 +102,8 @@ if(zombie.client) zombie.play_screen_text("You are dead...
You lost your head. No reviving for you.", /atom/movable/screen/text/screen_text/command_order, rgb(155, 0, 200)) to_chat(zombie, SPAN_XENOWARNING("You fall... headless, you will no longer rise.")) + zombie.undefibbable = TRUE // really only for weed_food + SEND_SIGNAL(zombie, COMSIG_HUMAN_SET_UNDEFIBBABLE) /datum/species/zombie/handle_dead_death(mob/living/carbon/human/zombie, gibbed) if(gibbed) @@ -144,6 +146,9 @@ return static_tab_items /datum/species/zombie/handle_head_loss(mob/living/carbon/human/zombie) + if(!zombie.undefibbable) + zombie.undefibbable = TRUE // really only for weed_food + SEND_SIGNAL(zombie, COMSIG_HUMAN_SET_UNDEFIBBABLE) if(WEAKREF(zombie) in to_revive) remove_from_revive(zombie) var/client/receiving_client = zombie.client diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 355f69ca05a9..f74b65c2606d 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -94,23 +94,19 @@ There are several things that need to be remembered: if(lying == lying_prev && !force) return lying_prev = lying - var/matrix/M = matrix() - var/matrix/L = matrix() //Counter-rotation for langchat text. + var/matrix/new_matrix = matrix() if(lying) if(pulledby && pulledby.grab_level >= GRAB_CARRY) - M.Turn(90) - L.Turn(270) + new_matrix.Turn(90) else if(prob(50)) - M.Turn(90) - L.Turn(270) + new_matrix.Turn(90) else - M.Turn(270) - L.Turn(90) - M.Translate(rand(-10,10),rand(-10,10)) - apply_transform(M) + new_matrix.Turn(270) + new_matrix.Translate(rand(-10,10), rand(-10,10)) + apply_transform(new_matrix) else - apply_transform(M) + apply_transform(new_matrix) /mob/living/carbon/human/UpdateDamageIcon() for(var/obj/limb/O in limbs) diff --git a/code/modules/mob/living/carbon/xenomorph/Abilities.dm b/code/modules/mob/living/carbon/xenomorph/Abilities.dm index dbadadf8ef23..eb5a629760ee 100644 --- a/code/modules/mob/living/carbon/xenomorph/Abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/Abilities.dm @@ -55,6 +55,9 @@ var/area/AR = get_area(T) if(isnull(AR) || !(AR.is_resin_allowed)) + if(AR.flags_area & AREA_UNWEEDABLE) + to_chat(X, SPAN_XENOWARNING("This area is unsuited to host the hive!")) + return to_chat(X, SPAN_XENOWARNING("It's too early to spread the hive this far.")) return diff --git a/code/modules/mob/living/carbon/xenomorph/Embryo.dm b/code/modules/mob/living/carbon/xenomorph/Embryo.dm index e03f225ccade..8b890de8a727 100644 --- a/code/modules/mob/living/carbon/xenomorph/Embryo.dm +++ b/code/modules/mob/living/carbon/xenomorph/Embryo.dm @@ -12,6 +12,8 @@ var/hivenumber = XENO_HIVE_NORMAL var/faction = FACTION_XENOMORPH var/flags_embryo = FALSE // Used in /ciphering/predator property + /// The ckey of any player hugger that made this embryo + var/hugger_ckey /obj/item/alien_embryo/Initialize(mapload, ...) . = ..() @@ -20,8 +22,8 @@ affected_mob.status_flags |= XENO_HOST START_PROCESSING(SSobj, src) if(iscarbon(affected_mob)) - var/mob/living/carbon/C = affected_mob - C.med_hud_set_status() + var/mob/living/carbon/affected_carbon = affected_mob + affected_carbon.med_hud_set_status() else return INITIALIZE_HINT_QDEL @@ -29,10 +31,11 @@ if(affected_mob) affected_mob.status_flags &= ~(XENO_HOST) if(iscarbon(affected_mob)) - var/mob/living/carbon/C = affected_mob - C.med_hud_set_status() + var/mob/living/carbon/affected_carbon = affected_mob + affected_carbon.med_hud_set_status() STOP_PROCESSING(SSobj, src) affected_mob = null + GLOB.player_embryo_list -= src . = ..() /obj/item/alien_embryo/process() @@ -45,24 +48,24 @@ affected_mob.status_flags &= ~(XENO_HOST) STOP_PROCESSING(SSobj, src) if(iscarbon(affected_mob)) - var/mob/living/carbon/C = affected_mob - C.med_hud_set_status() + var/mob/living/carbon/affected_carbon = affected_mob + affected_carbon.med_hud_set_status() affected_mob = null return FALSE if(affected_mob.stat == DEAD) if(ishuman(affected_mob)) - var/mob/living/carbon/human/H = affected_mob - if(world.time > H.timeofdeath + H.revive_grace_period) //Can't be defibbed. - var/mob/living/carbon/xenomorph/larva/L = locate() in affected_mob - if(L) - L.chest_burst(affected_mob) + var/mob/living/carbon/human/affected_human = affected_mob + if(world.time > affected_human.timeofdeath + affected_human.revive_grace_period) //Can't be defibbed. + var/mob/living/carbon/xenomorph/larva/larva_embryo = locate() in affected_mob + if(larva_embryo) + larva_embryo.chest_burst(affected_mob) qdel(src) return FALSE else - var/mob/living/carbon/xenomorph/larva/L = locate() in affected_mob - if(L) - L.chest_burst(affected_mob) + var/mob/living/carbon/xenomorph/larva/larva_embryo = locate() in affected_mob + if(larva_embryo) + larva_embryo.chest_burst(affected_mob) STOP_PROCESSING(SSobj, src) return FALSE @@ -86,12 +89,12 @@ if(stage < 5) counter += 1 * hive.larva_gestation_multiplier - if(stage < 5 && counter >= 120) + if(stage < 5 && counter >= 90) counter = 0 stage++ if(iscarbon(affected_mob)) - var/mob/living/carbon/C = affected_mob - C.med_hud_set_status() + var/mob/living/carbon/affected_carbon = affected_mob + affected_carbon.med_hud_set_status() switch(stage) if(2) @@ -129,9 +132,9 @@ if(6) larva_autoburst_countdown-- if(!larva_autoburst_countdown) - var/mob/living/carbon/xenomorph/larva/L = locate() in affected_mob - if(L) - L.chest_burst(affected_mob) + var/mob/living/carbon/xenomorph/larva/larva_embryo = locate() in affected_mob + if(larva_embryo) + larva_embryo.chest_burst(affected_mob) //We look for a candidate. If found, we spawn the candidate as a larva //Order of priority is bursted individual (if xeno is enabled), then random candidate, and then it's up for grabs and spawns braindead @@ -145,19 +148,33 @@ var/mob/picked // If the bursted person themselves has Xeno enabled, they get the honor of first dibs on the new larva. - if((!isyautja(affected_mob) || (isyautja(affected_mob) && prob(20))) && istype(affected_mob.buckled, /obj/structure/bed/nest)) + if((!isyautja(affected_mob) || (isyautja(affected_mob) && prob(20))) && istype(affected_mob.buckled, /obj/structure/bed/nest)) if(affected_mob.first_xeno || (affected_mob.client && affected_mob.client.prefs && (affected_mob.client.prefs.be_special & BE_ALIEN_AFTER_DEATH) && !jobban_isbanned(affected_mob, JOB_XENOMORPH))) picked = affected_mob else if(affected_mob.mind && affected_mob.mind.ghost_mob && affected_mob.client && affected_mob.client.prefs && (affected_mob.client.prefs.be_special & BE_ALIEN_AFTER_DEATH) && !jobban_isbanned(affected_mob, JOB_XENOMORPH)) picked = affected_mob.mind.ghost_mob - if(!picked) // Get a candidate from observers var/list/candidates = get_alien_candidates() - if(candidates && candidates.len) - picked = pick(candidates) + // If they were facehugged by a player thats still in queue, they get second dibs on the new larva. + if(hugger_ckey) + for(var/mob/dead/observer/cur_obs as anything in candidates) + if(cur_obs.ckey == hugger_ckey) + picked = cur_obs + candidates -= cur_obs + message_alien_candidates(candidates, dequeued = 0) + for(var/obj/item/alien_embryo/embryo as anything in GLOB.player_embryo_list) + if(embryo.hugger_ckey == cur_obs.ckey && embryo != src) + // Skipping src just in case an admin wants to quickly check before this thing fully deletes + // If this nulls out any embryo, wow + embryo.hugger_ckey = null + break + + if(!picked) + picked = candidates[1] + message_alien_candidates(candidates, dequeued = 1) // Spawn the larva var/mob/living/carbon/xenomorph/larva/new_xeno @@ -239,36 +256,37 @@ victim.spawn_gibs() - for(var/mob/living/carbon/xenomorph/larva/L in victim) - var/datum/hive_status/hive = GLOB.hive_datum[L.hivenumber] - L.forceMove(get_turf(victim)) //moved to the turf directly so we don't get stuck inside a cryopod or another mob container. - playsound(L, pick('sound/voice/alien_chestburst.ogg','sound/voice/alien_chestburst2.ogg'), 25) + for(var/mob/living/carbon/xenomorph/larva/larva_embryo in victim) + var/datum/hive_status/hive = GLOB.hive_datum[larva_embryo.hivenumber] + larva_embryo.forceMove(get_turf(victim)) //moved to the turf directly so we don't get stuck inside a cryopod or another mob container. + playsound(larva_embryo, pick('sound/voice/alien_chestburst.ogg','sound/voice/alien_chestburst2.ogg'), 25) - if(L.client) - L.set_lighting_alpha_from_prefs(L.client) + if(larva_embryo.client) + larva_embryo.set_lighting_alpha_from_prefs(larva_embryo.client) - L.attack_log += "\[[time_stamp()]\] chestbursted from [key_name(victim)]" - victim.attack_log += "\[[time_stamp()]\] Was chestbursted, larva was [key_name(L)]" + larva_embryo.attack_log += "\[[time_stamp()]\] chestbursted from [key_name(victim)]" + victim.attack_log += "\[[time_stamp()]\] Was chestbursted, larva was [key_name(larva_embryo)]" if(burstcount) - step(L, pick(cardinal)) + step(larva_embryo, pick(cardinal)) if(round_statistics) round_statistics.total_larva_burst++ + GLOB.larva_burst_by_hive[hive] = (GLOB.larva_burst_by_hive[hive] || 0) + 1 burstcount++ - if(!L.ckey && L.burrowable && loc && is_ground_level(loc.z) && (locate(/obj/structure/bed/nest) in loc) && hive.living_xeno_queen && hive.living_xeno_queen.z == loc.z) - L.visible_message(SPAN_XENODANGER("[L] quickly burrows into the ground.")) - if(round_statistics && !L.statistic_exempt) + if(!larva_embryo.ckey && larva_embryo.burrowable && loc && is_ground_level(loc.z) && (locate(/obj/structure/bed/nest) in loc) && hive.living_xeno_queen && hive.living_xeno_queen.z == loc.z) + larva_embryo.visible_message(SPAN_XENODANGER("[larva_embryo] quickly burrows into the ground.")) + if(round_statistics && !larva_embryo.statistic_exempt) round_statistics.track_new_participant(faction, -1) // keep stats sane hive.stored_larva++ hive.hive_ui.update_burrowed_larva() - qdel(L) + qdel(larva_embryo) if(!victim.first_xeno) - to_chat(L, SPAN_XENOHIGHDANGER("The Queen's will overwhelms your instincts...")) - to_chat(L, SPAN_XENOHIGHDANGER("\"[hive.hive_orders]\"")) - log_attack("[key_name(victim)] chestbursted, the larva was [key_name(L)].") //this is so that admins are not spammed with los logs + to_chat(larva_embryo, SPAN_XENOHIGHDANGER("The Queen's will overwhelms your instincts...")) + to_chat(larva_embryo, SPAN_XENOHIGHDANGER("\"[hive.hive_orders]\"")) + log_attack("[key_name(victim)] chestbursted, the larva was [key_name(larva_embryo)].") //this is so that admins are not spammed with los logs for(var/obj/item/alien_embryo/AE in victim) qdel(AE) @@ -278,31 +296,31 @@ victim.gib(cause) else if(ishuman(victim)) - var/mob/living/carbon/human/H = victim - H.last_damage_data = cause + var/mob/living/carbon/human/victim_human = victim + victim_human.last_damage_data = cause var/datum/internal_organ/O var/i for(i in list("heart","lungs")) //This removes (and later garbage collects) both organs. No heart means instant death. - O = H.internal_organs_by_name[i] - H.internal_organs_by_name -= i - H.internal_organs -= O + O = victim_human.internal_organs_by_name[i] + victim_human.internal_organs_by_name -= i + victim_human.internal_organs -= O victim.death(cause) // Certain species were still surviving bursting (predators), DEFINITELY kill them this time. victim.chestburst = 2 victim.update_burst() // Squeeze thru dense objects as a larva, as airlocks -/mob/living/carbon/xenomorph/larva/proc/scuttle(obj/structure/S) +/mob/living/carbon/xenomorph/larva/proc/scuttle(obj/structure/target) var/move_dir = get_dir(src, loc) - for(var/atom/movable/AM in get_turf(S)) - if(AM != S && AM.density && AM.BlockedPassDirs(src, move_dir)) - to_chat(src, SPAN_WARNING("\The [AM] prevents you from squeezing under \the [S]!")) + for(var/atom/movable/AM in get_turf(target)) + if(AM != target && AM.density && AM.BlockedPassDirs(src, move_dir)) + to_chat(src, SPAN_WARNING("\The [AM] prevents you from squeezing under \the [target]!")) return // Is it an airlock? - if(istype(S, /obj/structure/machinery/door/airlock)) - var/obj/structure/machinery/door/airlock/A = S - if(A.locked || A.welded) //Can't pass through airlocks that have been bolted down or welded - to_chat(src, SPAN_WARNING("\The [A] is locked down tight. You can't squeeze underneath!")) + if(istype(target, /obj/structure/machinery/door/airlock)) + var/obj/structure/machinery/door/airlock/selected_airlock = target + if(selected_airlock.locked || selected_airlock.welded) //Can't pass through airlocks that have been bolted down or welded + to_chat(src, SPAN_WARNING("\The [selected_airlock] is locked down tight. You can't squeeze underneath!")) return - visible_message(SPAN_WARNING("\The [src] scuttles underneath \the [S]!"), \ - SPAN_WARNING("You squeeze and scuttle underneath \the [S]."), null, 5) - forceMove(S.loc) + visible_message(SPAN_WARNING("\The [src] scuttles underneath \the [target]!"), \ + SPAN_WARNING("You squeeze and scuttle underneath \the [target]."), null, 5) + forceMove(target.loc) diff --git a/code/modules/mob/living/carbon/xenomorph/Evolution.dm b/code/modules/mob/living/carbon/xenomorph/Evolution.dm index 1f88643db764..4806f7528582 100644 --- a/code/modules/mob/living/carbon/xenomorph/Evolution.dm +++ b/code/modules/mob/living/carbon/xenomorph/Evolution.dm @@ -140,6 +140,7 @@ if(3) hive.tier_3_xenos |= new_xeno + log_game("EVOLVE: [key_name(src)] evolved into [new_xeno].") if(mind) mind.transfer_to(new_xeno) else @@ -327,6 +328,7 @@ qdel(new_xeno) return + log_game("EVOLVE: [key_name(src)] de-evolved into [new_xeno].") if(mind) mind.transfer_to(new_xeno) else diff --git a/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm b/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm index 121a231b7bf8..5ef9626620b2 100644 --- a/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm +++ b/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm @@ -191,9 +191,9 @@ return FALSE /obj/item/clothing/mask/facehugger/launch_towards(datum/launch_metadata/LM) - ..() if(stat == CONSCIOUS) icon_state = "[initial(icon_state)]_thrown" + ..() /obj/item/clothing/mask/facehugger/launch_impact(atom/hit_atom) . = ..() @@ -209,6 +209,11 @@ if(stat == UNCONSCIOUS) return + // Force reset throw now because [/atom/movable/proc/launch_impact] only does that later on + // If we DON'T, step()'s move below can collide, rebound, trigger this proc again, into infinite recursion + throwing = FALSE + rebounding = FALSE + if(leaping && can_hug(L, hivenumber)) attach(L) else if(L.density) @@ -235,52 +240,52 @@ if(!target) return FALSE - target.visible_message(SPAN_WARNING("\The scuttling [src] leaps at [target]!"), \ - SPAN_WARNING("The scuttling [src] leaps at [target]!")) + target.visible_message(SPAN_WARNING("[src] leaps at [target]!"), \ + SPAN_WARNING("[src] leaps at [target]!")) leaping = TRUE throw_atom(target, 3, SPEED_FAST) return TRUE -/obj/item/clothing/mask/facehugger/proc/attach(mob/living/M, silent = FALSE, knockout_mod = 1) - if(attached || !can_hug(M, hivenumber)) +/obj/item/clothing/mask/facehugger/proc/attach(mob/living/living_mob, silent = FALSE, knockout_mod = 1, hugger_ckey = null) + if(attached || !can_hug(living_mob, hivenumber)) return FALSE // This is always going to be valid because of the can_hug check above - var/mob/living/carbon/human/H = M + var/mob/living/carbon/human/human = living_mob if(!silent) - H.visible_message(SPAN_DANGER("[src] leaps at [H]'s face!")) + human.visible_message(SPAN_DANGER("[src] leaps at [human]'s face!")) if(isxeno(loc)) //Being carried? Drop it var/mob/living/carbon/xenomorph/X = loc X.drop_inv_item_on_ground(src) - if(isturf(H.loc)) - forceMove(H.loc)//Just checkin + if(isturf(human.loc)) + forceMove(human.loc)//Just checkin - if(!H.handle_hugger_attachment(src)) + if(!human.handle_hugger_attachment(src)) return FALSE attached = TRUE - forceMove(H) + forceMove(human) icon_state = initial(icon_state) - H.equip_to_slot(src, WEAR_FACE) - H.update_inv_wear_mask() - H.disable_lights() - H.disable_special_items() - if(ishuman_strict(H)) - playsound(loc, H.gender == "male" ? 'sound/misc/facehugged_male.ogg' : 'sound/misc/facehugged_female.ogg' , 25, 0) - else if(isyautja(H)) + human.equip_to_slot(src, WEAR_FACE) + human.update_inv_wear_mask() + human.disable_lights() + human.disable_special_items() + if(ishuman_strict(human)) + playsound(loc, human.gender == "male" ? 'sound/misc/facehugged_male.ogg' : 'sound/misc/facehugged_female.ogg' , 25, 0) + else if(isyautja(human)) playsound(loc, 'sound/voice/pred_facehugged.ogg', 65, FALSE) if(!sterile) - if(!H.species || !(H.species.flags & IS_SYNTHETIC)) //synthetics aren't paralyzed - H.apply_effect(MIN_IMPREGNATION_TIME * 0.5 * knockout_mod, PARALYZE) //THIS MIGHT NEED TWEAKS + if(!human.species || !(human.species.flags & IS_SYNTHETIC)) //synthetics aren't paralyzed + human.apply_effect(MIN_IMPREGNATION_TIME * 0.5 * knockout_mod, PARALYZE) //THIS MIGHT NEED TWEAKS - addtimer(CALLBACK(src, PROC_REF(impregnate), H), rand(MIN_IMPREGNATION_TIME, MAX_IMPREGNATION_TIME)) + addtimer(CALLBACK(src, PROC_REF(impregnate), human, hugger_ckey), rand(MIN_IMPREGNATION_TIME, MAX_IMPREGNATION_TIME)) return TRUE -/obj/item/clothing/mask/facehugger/proc/impregnate(mob/living/carbon/human/target) +/obj/item/clothing/mask/facehugger/proc/impregnate(mob/living/carbon/human/target, hugger_ckey = null) if(!target || target.wear_mask != src) //Was taken off or something return if(SEND_SIGNAL(target, COMSIG_HUMAN_IMPREGNATE, src) & COMPONENT_NO_IMPREGNATE) @@ -295,6 +300,8 @@ if(!embryos) var/obj/item/alien_embryo/embryo = new /obj/item/alien_embryo(target) embryo.hivenumber = hivenumber + embryo.hugger_ckey = hugger_ckey + GLOB.player_embryo_list += embryo embryo.flags_embryo = flags_embryo flags_embryo = NO_FLAGS diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm index 22cb816f865b..09fdb42ad5c3 100644 --- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm +++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm @@ -712,6 +712,10 @@ to_chat(src, SPAN_XENONOTICE("This is not a host.")) return + if(current_mob.stat == DEAD) + to_chat(src, SPAN_XENONOTICE("This host is dead.")) + return + var/mob/living/carbon/human/host_to_nest = current_mob var/found_grab = FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/boiler/boiler_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/boiler/boiler_powers.dm index e745e8940063..dff6c82efbf8 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/boiler/boiler_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/boiler/boiler_powers.dm @@ -139,7 +139,8 @@ spicy_gas = new /datum/effect_system/smoke_spread/xeno_weaken else CRASH("Globber has unknown ammo [xeno.ammo]! Oh no!") - spicy_gas.set_up(1, 0, get_turf(xeno), null, 6) + var/datum/cause_data/cause_data = create_cause_data("acid shroud gas", owner) + spicy_gas.set_up(1, 0, get_turf(xeno), null, 6, new_cause_data = cause_data) spicy_gas.start() to_chat(xeno, SPAN_XENOHIGHDANGER("You dump your acid through your pores, creating a shroud of gas!")) for (var/action_type in action_types_to_cd) @@ -166,9 +167,9 @@ if(!actually_moving) return - var/obj/effect/particle_effect/smoke/S = new /obj/effect/particle_effect/smoke/xeno_burn(get_turf(mover), 1, create_cause_data(initial(mover.caste_type), mover)) - S.time_to_live = 3 - S.spread_speed = 1000000 + var/obj/effect/particle_effect/smoke/xeno_burn/smoke_effect = new(get_turf(mover), 1, create_cause_data("dumped acid gas", mover)) + smoke_effect.time_to_live = 3 + smoke_effect.spread_speed = 1000000 /datum/action/xeno_action/onclick/dump_acid/remove_from() remove_speed_buff() @@ -283,27 +284,25 @@ apply_cooldown() return ..() -/datum/action/xeno_action/activable/acid_shotgun/use_ability(atom/A) - var/mob/living/carbon/xenomorph/X = owner - if (!istype(X)) +/datum/action/xeno_action/activable/acid_shotgun/use_ability(atom/target) + var/mob/living/carbon/xenomorph/xeno = owner + if (!istype(xeno)) return if (!action_cooldown_check()) return - if(!A || A.layer >= FLY_LAYER || !isturf(X.loc) || !X.check_state()) + if(!target || target.layer >= FLY_LAYER || !isturf(xeno.loc) || !xeno.check_state()) return - X.visible_message(SPAN_XENOWARNING("The [X] fires a blast of acid at [A]!"), SPAN_XENOWARNING("You fire a blast of acid at [A]!")) - - var/turf/target = locate(A.x, A.y, A.z) - var/obj/item/projectile/P = new /obj/item/projectile(X.loc, create_cause_data(initial(X.caste_type), X)) + xeno.visible_message(SPAN_XENOWARNING("The [xeno] fires a blast of acid at [target]!"), SPAN_XENOWARNING("You fire a blast of acid at [target]!")) + var/turf/target_turf = locate(target.x, target.y, target.z) + var/obj/item/projectile/proj = new(xeno.loc, create_cause_data("acid shotgun", xeno)) var/datum/ammo/ammoDatum = new ammo_type() - P.generate_bullet(ammoDatum) - - P.fire_at(target, X, X, ammoDatum.max_range, ammoDatum.shell_speed) + proj.generate_bullet(ammoDatum) + proj.fire_at(target_turf, xeno, xeno, ammoDatum.max_range, ammoDatum.shell_speed) apply_cooldown() return ..() @@ -347,7 +346,7 @@ else if(stabbing_xeno.ammo == GLOB.ammo_list[/datum/ammo/xeno/boiler_gas]) var/datum/effects/neurotoxin/neuro_effect = locate() in carbon_target.effects_list if(!neuro_effect) - neuro_effect = new /datum/effects/neurotoxin(carbon_target) + neuro_effect = new(carbon_target, owner) neuro_effect.duration += 16 to_chat(carbon_target,SPAN_HIGHDANGER("You are injected with something from [stabbing_xeno]'s tailstab!")) else diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm index 824e0cc5f9fd..d95fbc304397 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm @@ -479,3 +479,68 @@ // Perform check_state(TRUE) silently: if(xeno && !xeno.is_mob_incapacitated() || !xeno.buckled || !xeno.evolving && xeno.plasma_stored >= plasma_cost) return TRUE + +/datum/action/xeno_action/onclick/tacmap + name = "View Tactical Map" + action_icon_state = "toggle_queen_zoom" + ability_name = "view tacmap" + + var/mob/living/carbon/xenomorph/queen/tracked_queen + +/datum/action/xeno_action/onclick/tacmap/Destroy() + tracked_queen = null + return ..() + +/datum/action/xeno_action/onclick/tacmap/give_to(mob/living/carbon/xenomorph/xeno) + . = ..() + + RegisterSignal(xeno.hive, COMSIG_HIVE_NEW_QUEEN, PROC_REF(handle_new_queen)) + + if(!xeno.hive.living_xeno_queen) + hide_from(xeno) + return + + if(!xeno.hive.living_xeno_queen.ovipositor) + hide_from(xeno) + + handle_new_queen(new_queen = xeno.hive.living_xeno_queen) + +/// handles the addition of a new queen, hiding if appropriate +/datum/action/xeno_action/onclick/tacmap/proc/handle_new_queen(datum/hive_status/hive, mob/living/carbon/xenomorph/queen/new_queen) + SIGNAL_HANDLER + + if(tracked_queen) + UnregisterSignal(tracked_queen, list(COMSIG_QUEEN_MOUNT_OVIPOSITOR, COMSIG_QUEEN_DISMOUNT_OVIPOSITOR, COMSIG_PARENT_QDELETING)) + + tracked_queen = new_queen + + if(!tracked_queen.ovipositor) + hide_from(owner) + + RegisterSignal(tracked_queen, COMSIG_QUEEN_MOUNT_OVIPOSITOR, PROC_REF(handle_mount_ovipositor)) + RegisterSignal(tracked_queen, COMSIG_QUEEN_DISMOUNT_OVIPOSITOR, PROC_REF(handle_dismount_ovipositor)) + RegisterSignal(tracked_queen, COMSIG_PARENT_QDELETING, PROC_REF(handle_queen_qdel)) + +/// deals with the queen mounting the ovipositor, unhiding the action from the user +/datum/action/xeno_action/onclick/tacmap/proc/handle_mount_ovipositor() + SIGNAL_HANDLER + + unhide_from(owner) + +/// deals with the queen dismounting the ovipositor, hiding the action from the user +/datum/action/xeno_action/onclick/tacmap/proc/handle_dismount_ovipositor() + SIGNAL_HANDLER + + hide_from(owner) + +/// cleans up references to the queen when the queen is being qdel'd, hides the action from the user +/datum/action/xeno_action/onclick/tacmap/proc/handle_queen_qdel() + SIGNAL_HANDLER + + tracked_queen = null + hide_from(owner) + +/datum/action/xeno_action/onclick/tacmap/use_ability(atom/target) + var/mob/living/carbon/xenomorph/xeno = owner + xeno.xeno_tacmap() + return ..() diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm index dd9051ab0279..4a57c0729b91 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm @@ -4,67 +4,79 @@ // Plant weeds /datum/action/xeno_action/onclick/plant_weeds/use_ability(atom/A) - var/mob/living/carbon/xenomorph/X = owner + var/mob/living/carbon/xenomorph/xeno = owner if(!action_cooldown_check()) return - if(!X.check_state()) + if(!xeno.check_state()) return - if(X.burrow) + if(xeno.burrow) return - var/turf/T = X.loc + var/turf/turf = xeno.loc - if(!istype(T)) - to_chat(X, SPAN_WARNING("You can't do that here.")) + if(!istype(turf)) + to_chat(xeno, SPAN_WARNING("You can't do that here.")) return - var/is_weedable = T.is_weedable() + if(turf.density) + to_chat(xeno, SPAN_WARNING("You can't do that here.")) + return + + var/is_weedable = turf.is_weedable() if(!is_weedable) - to_chat(X, SPAN_WARNING("Bad place for a garden!")) + to_chat(xeno, SPAN_WARNING("Bad place for a garden!")) return if(!plant_on_semiweedable && is_weedable < FULLY_WEEDABLE) - to_chat(X, SPAN_WARNING("Bad place for a garden!")) + to_chat(xeno, SPAN_WARNING("Bad place for a garden!")) return - var/obj/effect/alien/weeds/node/N = locate() in T - if(N && N.weed_strength >= X.weed_level) - to_chat(X, SPAN_WARNING("There's a pod here already!")) + var/obj/effect/alien/weeds/node/node = locate() in turf + if(node && node.weed_strength >= xeno.weed_level) + to_chat(xeno, SPAN_WARNING("There's a pod here already!")) return - var/obj/effect/alien/resin/trap/resin_trap = locate() in T + var/obj/effect/alien/resin/trap/resin_trap = locate() in turf if(resin_trap) - to_chat(X, SPAN_WARNING("You can't weed on top of a trap!")) + to_chat(xeno, SPAN_WARNING("You can't weed on top of a trap!")) return - var/list/to_convert - if(N) - to_convert = N.children.Copy() - - var/obj/effect/alien/weeds/W = locate(/obj/effect/alien/weeds) in T - if (W && W.weed_strength >= WEED_LEVEL_HIVE) - to_chat(X, SPAN_WARNING("These weeds are too strong to plant a node on!")) + var/obj/effect/alien/weeds/weed = node || locate() in turf + if(weed && weed.weed_strength >= WEED_LEVEL_HIVE) + to_chat(xeno, SPAN_WARNING("These weeds are too strong to plant a node on!")) return - var/area/AR = get_area(T) - if(isnull(AR) || !(AR.is_resin_allowed)) - to_chat(X, SPAN_XENOWARNING("It's too early to spread the hive this far.")) + for(var/obj/structure/struct in turf) + if(struct.density && !(struct.flags_atom & ON_BORDER)) // Not sure exactly if we need to test against ON_BORDER though + to_chat(xeno, SPAN_WARNING("You can't do that here.")) + return + + var/area/area = get_area(turf) + if(isnull(area) || !(area.is_resin_allowed)) + if(area.flags_area & AREA_UNWEEDABLE) + to_chat(xeno, SPAN_XENOWARNING("This area is unsuited to host the hive!")) + return + to_chat(xeno, SPAN_XENOWARNING("It's too early to spread the hive this far.")) return - if (!check_and_use_plasma_owner()) + if(!check_and_use_plasma_owner()) return - X.visible_message(SPAN_XENONOTICE("\The [X] regurgitates a pulsating node and plants it on the ground!"), \ + var/list/to_convert + if(node) + to_convert = node.children.Copy() + + xeno.visible_message(SPAN_XENONOTICE("\The [xeno] regurgitates a pulsating node and plants it on the ground!"), \ SPAN_XENONOTICE("You regurgitate a pulsating node and plant it on the ground!"), null, 5) - var/obj/effect/alien/weeds/node/new_node = new node_type(X.loc, src, X) + var/obj/effect/alien/weeds/node/new_node = new node_type(xeno.loc, src, xeno) if(to_convert) - for(var/weed in to_convert) - var/turf/target_turf = get_turf(weed) + for(var/cur_weed in to_convert) + var/turf/target_turf = get_turf(cur_weed) if(target_turf && !target_turf.density) new /obj/effect/alien/weeds(target_turf, new_node) - qdel(weed) + qdel(cur_weed) - playsound(X.loc, "alien_resin_build", 25) + playsound(xeno.loc, "alien_resin_build", 25) apply_cooldown() return ..() @@ -597,6 +609,9 @@ var/area/AR = get_area(T) if(isnull(AR) || !(AR.is_resin_allowed)) + if(AR.flags_area & AREA_UNWEEDABLE) + to_chat(X, SPAN_XENOWARNING("This area is unsuited to host the hive!")) + return to_chat(X, SPAN_XENOWARNING("It's too early to spread the hive this far.")) return FALSE @@ -760,12 +775,12 @@ SPAN_XENOWARNING("You spit a [xeno.ammo.name] at [atom]!") ) playsound(xeno.loc, sound_to_play, 25, 1) + var/obj/item/projectile/proj = new (current_turf, create_cause_data(xeno.ammo.name, xeno)) + proj.generate_bullet(xeno.ammo) + proj.permutated += xeno + proj.def_zone = xeno.get_limbzone_target() + proj.fire_at(spit_target, xeno, xeno, xeno.ammo.max_range, xeno.ammo.shell_speed) - var/obj/item/projectile/Proj = new (current_turf, create_cause_data(initial(xeno.caste_type), xeno)) - Proj.generate_bullet(xeno.ammo) - Proj.permutated += xeno - Proj.def_zone = xeno.get_limbzone_target() - Proj.fire_at(spit_target, xeno, xeno, xeno.ammo.max_range, xeno.ammo.shell_speed) spitting = FALSE SEND_SIGNAL(xeno, COMSIG_XENO_POST_SPIT) @@ -985,7 +1000,10 @@ if(blunt_stab) stabbing_xeno.visible_message(SPAN_XENOWARNING("\The [stabbing_xeno] swipes its tail into [target]'s [limb ? limb.display_name : "chest"], bashing it!"), SPAN_XENOWARNING("You swipe your tail into [target]'s [limb? limb.display_name : "chest"], bashing it!")) - playsound(target, "punch", 50, TRUE) + if(prob(1)) + playsound(target, 'sound/effects/comical_bonk.ogg', 50, TRUE) + else + playsound(target, "punch", 50, TRUE) // The xeno smashes the target with their tail, moving it to the side and thus their direction as well. stab_direction = turn(stabbing_xeno.dir, pick(90, -90)) stab_overlay = "slam" diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm index e0a29a034029..0c9358119def 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm @@ -14,20 +14,21 @@ can_be_shield_blocked = TRUE /datum/action/xeno_action/activable/pounce/lurker/additional_effects_always() - var/mob/living/carbon/xenomorph/X = owner - if (!istype(X)) + var/mob/living/carbon/xenomorph/xeno = owner + if (!istype(xeno)) return - - if (X.mutation_type == LURKER_NORMAL) + if (xeno.mutation_type == LURKER_NORMAL) var/found = FALSE - for (var/mob/living/carbon/human/H in get_turf(X)) + for (var/mob/living/carbon/human/human in get_turf(xeno)) + if(human.stat == DEAD) + continue found = TRUE break if (found) - var/datum/action/xeno_action/onclick/lurker_invisibility/LIA = get_xeno_action_by_type(X, /datum/action/xeno_action/onclick/lurker_invisibility) - if (istype(LIA)) - LIA.invisibility_off() + var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis = get_xeno_action_by_type(xeno, /datum/action/xeno_action/onclick/lurker_invisibility) + if (istype(lurker_invis)) + lurker_invis.invisibility_off() /datum/action/xeno_action/activable/pounce/lurker/additional_effects(mob/living/L) var/mob/living/carbon/xenomorph/X = owner diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm index 0c4ba1f2e86d..b58d94a6ed5b 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm @@ -288,6 +288,11 @@ if(!do_after(xeno, 0.8 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, numticks = 2)) // would be 0.75 but that doesn't really work with numticks return + // To make sure that the headbite does nothing if the target is moved away. + if(!xeno.Adjacent(target_carbon)) + to_chat(xeno, SPAN_XENOHIGHDANGER("You missed! Your target was moved away before you could finish headbiting them!")) + return + if(target_carbon.stat == DEAD) to_chat(xeno, SPAN_XENODANGER("They died before you could finish headbiting them! Be more careful next time!")) return diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm index 20bd029f5c94..65ea443c133c 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/queen/queen_powers.dm @@ -472,22 +472,6 @@ user_xeno.hive.banished_ckeys.Remove(banished_name) return ..() -/datum/action/xeno_action/activable/secrete_resin/remote/queen/use_ability(atom/A) - . = ..() - if(!.) - return - - if(!boosted) - return - var/mob/living/carbon/xenomorph/X = owner - var/datum/hive_status/HS = X.hive - if(!HS || !HS.hive_location) - return - // 5 screen radius - if(get_dist(A, HS.hive_location) > 35) - // Apply the normal cooldown if not building near the hive - apply_cooldown_override(initial(xeno_cooldown)) - /datum/action/xeno_action/onclick/eye name = "Enter Eye Form" action_icon_state = "queen_eye" @@ -528,6 +512,9 @@ var/area/AR = get_area(T) if(!AR.is_resin_allowed) + if(AR.flags_area & AREA_UNWEEDABLE) + to_chat(X, SPAN_XENOWARNING("This area is unsuited to host the hive!")) + return to_chat(X, SPAN_XENOWARNING("It's too early to spread the hive this far.")) return diff --git a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm index 33cf6142acb1..246e2d2809db 100644 --- a/code/modules/mob/living/carbon/xenomorph/attack_alien.dm +++ b/code/modules/mob/living/carbon/xenomorph/attack_alien.dm @@ -287,6 +287,9 @@ SPAN_DANGER("You nudge your head against [src]."), null, 5, CHAT_TYPE_XENO_FLUFF) /mob/living/proc/is_xeno_grabbable() + if(stat == DEAD) + return FALSE + return TRUE /mob/living/carbon/human/is_xeno_grabbable() @@ -307,20 +310,6 @@ /obj/item/attack_alien(mob/living/carbon/xenomorph/M) return -/obj/vehicle/attack_alien(mob/living/carbon/xenomorph/M) - if(M.a_intent == INTENT_HARM) - M.animation_attack_on(src) - M.flick_attack_overlay(src, "slash") - health -= 15 - playsound(loc, "alien_claw_metal", 25, 1) - M.visible_message(SPAN_DANGER("[M] [M.slashes_verb] [src]."),SPAN_DANGER("You [M.slash_verb] [src]."), null, 5, CHAT_TYPE_XENO_COMBAT) - healthcheck() - return XENO_ATTACK_ACTION - else - attack_hand(M) - return XENO_NONCOMBAT_ACTION - - /obj/attack_larva(mob/living/carbon/xenomorph/larva/M) return //larva can't do anything @@ -633,12 +622,6 @@ SPAN_DANGER("You pry [src] open."), null, 5, CHAT_TYPE_XENO_COMBAT) return XENO_NO_DELAY_ACTION - -//Nerfing the damn Cargo Tug Train -/obj/vehicle/train/attack_alien(mob/living/carbon/xenomorph/M) - attack_hand(M) - return XENO_NONCOMBAT_ACTION - /obj/structure/mineral_door/resin/attack_larva(mob/living/carbon/xenomorph/larva/M) var/turf/cur_loc = M.loc if(!istype(cur_loc)) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm index 96cd2846249d..092dae00d603 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Boiler.dm @@ -71,7 +71,7 @@ /datum/action/xeno_action/activable/spray_acid/boiler, //3rd macro /datum/action/xeno_action/onclick/toggle_long_range/boiler, //4rd macro /datum/action/xeno_action/onclick/acid_shroud, //4th macro - + /datum/action/xeno_action/onclick/tacmap, ) /mob/living/carbon/xenomorph/boiler/Initialize(mapload, mob/living/carbon/xenomorph/oldxeno, h_number) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm index 8cfc78a38272..ead254344e0a 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Burrower.dm @@ -66,6 +66,7 @@ /datum/action/xeno_action/onclick/place_trap, //second macro /datum/action/xeno_action/activable/burrow, //third macro /datum/action/xeno_action/onclick/tremor, //fourth macro + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm index fcc9bfcfd3b7..ec1697f30081 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Carrier.dm @@ -69,6 +69,7 @@ /datum/action/xeno_action/activable/throw_hugger, //3rd macro /datum/action/xeno_action/activable/retrieve_egg, //4th macro /datum/action/xeno_action/onclick/set_hugger_reserve, + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm index 9a2e3e89cb21..bf1702598250 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Crusher.dm @@ -59,6 +59,7 @@ /datum/action/xeno_action/activable/pounce/crusher_charge, /datum/action/xeno_action/onclick/crusher_stomp, /datum/action/xeno_action/onclick/crusher_shield, + /datum/action/xeno_action/onclick/tacmap, ) claw_type = CLAW_TYPE_VERY_SHARP diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm index 4360e5d42ca2..8c05fa53660e 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Defender.dm @@ -47,6 +47,7 @@ /datum/action/xeno_action/activable/headbutt, /datum/action/xeno_action/onclick/tail_sweep, /datum/action/xeno_action/activable/fortify, + /datum/action/xeno_action/onclick/tacmap, ) mutation_icon_state = DEFENDER_NORMAL mutation_type = DEFENDER_NORMAL diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm index 7748f5978a20..dbdb03bb94ca 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Drone.dm @@ -63,6 +63,7 @@ /datum/action/xeno_action/onclick/choose_resin, //second macro /datum/action/xeno_action/activable/secrete_resin, //third macro /datum/action/xeno_action/activable/transfer_plasma, //fourth macro + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm index d9ab8a1e849d..1ad171ec5c93 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Facehugger.dm @@ -50,6 +50,7 @@ /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/onclick/xenohide, /datum/action/xeno_action/activable/pounce/facehugger, + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, @@ -143,9 +144,9 @@ /mob/living/carbon/xenomorph/facehugger/proc/handle_hug(mob/living/carbon/human/human) var/obj/item/clothing/mask/facehugger/hugger = new /obj/item/clothing/mask/facehugger(loc, hivenumber) - var/did_hug = hugger.attach(human, TRUE, 0.5) + var/did_hug = hugger.attach(human, TRUE, 0.5, client?.ckey) if(client) - client?.player_data?.adjust_stat(PLAYER_STAT_FACEHUGS, STAT_CATEGORY_XENO, 1) + client.player_data?.adjust_stat(PLAYER_STAT_FACEHUGS, STAT_CATEGORY_XENO, 1) var/area/hug_area = get_area(src) if(hug_area) for(var/mob/dead/observer/observer as anything in GLOB.observer_list) diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm index 1b7c04eb1a77..271fe3182210 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hellhound.dm @@ -58,6 +58,7 @@ /datum/action/xeno_action/onclick/xenohide, /datum/action/xeno_action/activable/pounce/runner, /datum/action/xeno_action/onclick/toggle_long_range/runner, + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm index 9ffd0d9a7690..b0a44b0e3835 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Hivelord.dm @@ -68,6 +68,7 @@ /datum/action/xeno_action/activable/secrete_resin/hivelord, //third macro /datum/action/xeno_action/activable/transfer_plasma/hivelord, // to be consistent with drone placement /datum/action/xeno_action/active_toggle/toggle_speed, //fourth macro + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm b/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm index 04b7e04c2da5..82d80752ec54 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm @@ -41,6 +41,7 @@ /datum/action/xeno_action/onclick/xeno_resting, /datum/action/xeno_action/watch_xeno, /datum/action/xeno_action/onclick/xenohide, + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, @@ -137,6 +138,9 @@ else icon_state = "[state_override || state]Larva" +/mob/living/carbon/xenomorph/larva/alter_ghost(mob/dead/observer/ghost) + ghost.icon_state = "[caste.caste_type]" + /mob/living/carbon/xenomorph/larva/handle_name() return @@ -170,3 +174,5 @@ /mob/living/carbon/xenomorph/larva/emote(act, m_type, message, intentional, force_silence) playsound(loc, "alien_roar_larva", 15) +/mob/living/carbon/xenomorph/larva/is_xeno_grabbable() + return TRUE diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm index 1269f89f9144..fb75ed3900ac 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm @@ -45,6 +45,7 @@ /datum/action/xeno_action/activable/pounce/lurker, /datum/action/xeno_action/onclick/lurker_invisibility, /datum/action/xeno_action/onclick/lurker_assassinate, + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm index e1bdb18a29e2..344e1e21f302 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Praetorian.dm @@ -58,6 +58,7 @@ /datum/action/xeno_action/activable/pounce/base_prae_dash, /datum/action/xeno_action/activable/prae_acid_ball, /datum/action/xeno_action/activable/spray_acid/base_prae_spray_acid, + /datum/action/xeno_action/onclick/tacmap, ) icon_xeno = 'icons/mob/xenos/praetorian.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm b/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm index cf72a5bc419b..c7970e017c4b 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Predalien.dm @@ -60,6 +60,7 @@ /datum/action/xeno_action/onclick/predalien_roar, /datum/action/xeno_action/onclick/smash, /datum/action/xeno_action/activable/devastate, + /datum/action/xeno_action/onclick/tacmap, ) mutation_type = "Normal" diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm index 93b6d230b198..ac975835b21f 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm @@ -940,3 +940,7 @@ // Switch icon back and then let normal icon behavior happen Queen.icon = Queen.queen_standing_icon + +/mob/living/carbon/xenomorph/queen/alter_ghost(mob/dead/observer/ghost) + ghost.icon = queen_standing_icon + return ..() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm index 140e2642685f..d8d4a2349f98 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Ravager.dm @@ -56,6 +56,7 @@ /datum/action/xeno_action/activable/pounce/charge, /datum/action/xeno_action/onclick/empower, /datum/action/xeno_action/activable/scissor_cut, + /datum/action/xeno_action/onclick/tacmap, ) icon_xeno = 'icons/mob/xenos/ravager.dmi' diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm index 45bfd4d7f78d..04dd751bdcb8 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Runner.dm @@ -56,6 +56,7 @@ /datum/action/xeno_action/activable/pounce/runner, /datum/action/xeno_action/activable/runner_skillshot, /datum/action/xeno_action/onclick/toggle_long_range/runner, + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm b/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm index 3e67ae2d18f9..39426b1a9ef7 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Sentinel.dm @@ -48,6 +48,7 @@ /datum/action/xeno_action/activable/slowing_spit, //first macro /datum/action/xeno_action/activable/scattered_spit, //second macro /datum/action/xeno_action/onclick/paralyzing_slash, //third macro + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm b/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm index 31c8720e9a19..23728b00a642 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Spitter.dm @@ -51,6 +51,7 @@ /datum/action/xeno_action/activable/xeno_spit, /datum/action/xeno_action/onclick/charge_spit, /datum/action/xeno_action/activable/spray_acid/spitter, + /datum/action/xeno_action/onclick/tacmap, ) inherent_verbs = list( /mob/living/carbon/xenomorph/proc/vent_crawl, diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm b/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm index d815bc18f9d5..7c8edace81e4 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Warrior.dm @@ -52,6 +52,7 @@ /datum/action/xeno_action/activable/warrior_punch, /datum/action/xeno_action/activable/lunge, /datum/action/xeno_action/activable/fling, + /datum/action/xeno_action/onclick/tacmap, ) mutation_type = WARRIOR_NORMAL diff --git a/code/modules/mob/living/carbon/xenomorph/death.dm b/code/modules/mob/living/carbon/xenomorph/death.dm index ce3f55700753..e3a69da23262 100644 --- a/code/modules/mob/living/carbon/xenomorph/death.dm +++ b/code/modules/mob/living/carbon/xenomorph/death.dm @@ -37,24 +37,28 @@ if(GLOB.hive_datum[hivenumber].stored_larva) GLOB.hive_datum[hivenumber].stored_larva = round(GLOB.hive_datum[hivenumber].stored_larva * 0.5) //Lose half on dead queen - var/turf/larva_spawn + var/list/players_with_xeno_pref = get_alien_candidates() - while(GLOB.hive_datum[hivenumber].stored_larva > 0 && istype(GLOB.hive_datum[hivenumber].hive_location, /obj/effect/alien/resin/special/pylon/core)) // stil some left - larva_spawn = get_turf(GLOB.hive_datum[hivenumber].hive_location) - if(players_with_xeno_pref && players_with_xeno_pref.len) - var/mob/xeno_candidate = pick(players_with_xeno_pref) + if(players_with_xeno_pref && istype(GLOB.hive_datum[hivenumber].hive_location, /obj/effect/alien/resin/special/pylon/core)) + var/turf/larva_spawn = get_turf(GLOB.hive_datum[hivenumber].hive_location) + var/count = 0 + while(GLOB.hive_datum[hivenumber].stored_larva > 0 && count < length(players_with_xeno_pref)) // still some left + var/mob/xeno_candidate = players_with_xeno_pref[++count] var/mob/living/carbon/xenomorph/larva/new_xeno = new /mob/living/carbon/xenomorph/larva(larva_spawn) new_xeno.set_hive_and_update(hivenumber) new_xeno.generate_name() if(!SSticker.mode.transfer_xeno(xeno_candidate, new_xeno)) qdel(new_xeno) - return + break + new_xeno.visible_message(SPAN_XENODANGER("A larva suddenly burrows out of the ground!"), SPAN_XENODANGER("You burrow out of the ground after feeling an immense tremor through the hive, which quickly fades into complete silence...")) - GLOB.hive_datum[hivenumber].stored_larva-- - GLOB.hive_datum[hivenumber].hive_ui.update_burrowed_larva() + GLOB.hive_datum[hivenumber].stored_larva-- + GLOB.hive_datum[hivenumber].hive_ui.update_burrowed_larva() + if(count) + message_alien_candidates(players_with_xeno_pref, dequeued = count) if(hive && hive.living_xeno_queen == src) xeno_message(SPAN_XENOANNOUNCE("A sudden tremor ripples through the hive... the Queen has been slain! Vengeance!"),3, hivenumber) @@ -101,6 +105,11 @@ GLOB.hive_datum[hivenumber].stored_larva++ GLOB.hive_datum[hivenumber].hive_ui.update_burrowed_larva() + if(hardcore) + QDEL_IN(src, 3 SECONDS) + //else if(!gibbed) // At the moment we only support humans + //AddComponent(/datum/component/weed_food) + if(hive) hive.remove_xeno(src) // Finding the last xeno for anti-delay. @@ -113,15 +122,14 @@ // Tell the marines where the last one is. var/name = "[MAIN_AI_SYSTEM] Bioscan Status" var/input = "Bioscan complete.\n\nSensors indicate one remaining unknown lifeform signature in [get_area(X)]." - marine_announcement(input, name, 'sound/AI/bioscan.ogg') + var/datum/ares_link/link = GLOB.ares_link + link.log_ares_bioscan(name, input) + marine_announcement(input, name, 'sound/AI/bioscan.ogg', logging = ARES_LOG_NONE) // Tell the xeno she is the last one. if(X.client) to_chat(X, SPAN_XENOANNOUNCE("Your carapace rattles with dread. You are all that remains of the hive!")) announce_dchat("There is only one Xenomorph left: [X.name].", X) - if(hardcore) - QDEL_IN(src, 3 SECONDS) - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_XENO_DEATH, src, gibbed) /mob/living/carbon/xenomorph/gib(datum/cause_data/cause = create_cause_data("gibbing", src)) @@ -134,10 +142,10 @@ switch(caste.caste_type) //This will need to be changed later, when we have proper xeno pathing. Might do it on caste or something. if(XENO_CASTE_BOILER) - var/mob/living/carbon/xenomorph/boiler/B = src + var/mob/living/carbon/xenomorph/boiler/src_boiler = src visible_message(SPAN_DANGER("[src] begins to bulge grotesquely, and explodes in a cloud of corrosive gas!")) - B.smoke.set_up(2, 0, get_turf(src)) - B.smoke.start() + src_boiler.smoke.set_up(2, 0, get_turf(src), new_cause_data = src_boiler.smoke.cause_data) + src_boiler.smoke.start() remains.icon_state = "gibbed-a-corpse" if(XENO_CASTE_RUNNER) remains.icon_state = "gibbed-a-corpse-runner" diff --git a/code/modules/mob/living/carbon/xenomorph/life.dm b/code/modules/mob/living/carbon/xenomorph/life.dm index 4fa3470a6031..842e3b45a76d 100644 --- a/code/modules/mob/living/carbon/xenomorph/life.dm +++ b/code/modules/mob/living/carbon/xenomorph/life.dm @@ -48,8 +48,15 @@ if(!got_evolution_message) evolve_message() got_evolution_message = TRUE + if(ROUND_TIME < XENO_ROUNDSTART_PROGRESS_TIME_2) evolution_stored += progress_amount + return + + if(evolution_stored > evolution_threshold + progress_amount) + evolution_stored -= progress_amount + return + else evolution_stored += progress_amount diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/drone/gardener.dm b/code/modules/mob/living/carbon/xenomorph/mutators/strains/drone/gardener.dm index 0e6b7e4657d3..303e1c94692d 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/drone/gardener.dm +++ b/code/modules/mob/living/carbon/xenomorph/mutators/strains/drone/gardener.dm @@ -352,8 +352,8 @@ /obj/effect/alien/weeds/node/gardener spread_on_semiweedable = TRUE - block_structures = BLOCK_SPECIAL_STRUCTURES fruit_growth_multiplier = 0.8 + weed_strength = WEED_LEVEL_HARDY /datum/action/xeno_action/verb/verb_plant_gardening_weeds() set category = "Alien" diff --git a/code/modules/mob/living/carbon/xenomorph/mutators/strains/runner/acid.dm b/code/modules/mob/living/carbon/xenomorph/mutators/strains/runner/acid.dm index a2699a4f0f40..7a2196a3c209 100644 --- a/code/modules/mob/living/carbon/xenomorph/mutators/strains/runner/acid.dm +++ b/code/modules/mob/living/carbon/xenomorph/mutators/strains/runner/acid.dm @@ -70,19 +70,27 @@ . += "FOR THE HIVE!: in [caboom_left] seconds" /datum/behavior_delegate/runner_acider/melee_attack_additional_effects_target(mob/living/carbon/target_mob) - if (ishuman(target_mob)) + if(ishuman(target_mob)) //Will acid be applied to the mob var/mob/living/carbon/human/target_human = target_mob - if (target_human.stat == DEAD) + if(target_human.buckled && istype(target_human.buckled, /obj/structure/bed/nest)) return - for(var/datum/effects/acid/AA in target_mob.effects_list) - qdel(AA) + if(target_human.stat == DEAD) + return + + for(var/datum/effects/acid/acid_effect in target_mob.effects_list) + qdel(acid_effect) break - if(isxeno_human(target_mob)) + + new /datum/effects/acid(target_mob, bound_xeno, initial(bound_xeno.caste_type)) + if(isxeno_human(target_mob)) //Will the runner get acid stacks + var/obj/item/alien_embryo/embryo = locate(/obj/item/alien_embryo) in target_mob.contents + if(embryo?.stage >= 4) //very late stage hugged in case the runner unnests them + return + if(target_mob.lying) modify_acid(acid_slash_regen_lying) - else - modify_acid(acid_slash_regen_standing) - new /datum/effects/acid(target_mob, bound_xeno, initial(bound_xeno.caste_type)) + return + modify_acid(acid_slash_regen_standing) /datum/behavior_delegate/runner_acider/on_life() modify_acid(acid_passive_regen) diff --git a/code/modules/mob/living/carbon/xenomorph/resin_constructions.dm b/code/modules/mob/living/carbon/xenomorph/resin_constructions.dm index 4f3852a6a055..3bfb4e355416 100644 --- a/code/modules/mob/living/carbon/xenomorph/resin_constructions.dm +++ b/code/modules/mob/living/carbon/xenomorph/resin_constructions.dm @@ -31,6 +31,9 @@ GLOBAL_VAR_INIT(resin_lz_allowed, FALSE) var/area/AR = get_area(T) if(isnull(AR) || !(AR.is_resin_allowed)) + if(AR.flags_area & AREA_UNWEEDABLE) + to_chat(X, SPAN_XENOWARNING("This area is unsuited to host the hive!")) + return to_chat(X, SPAN_XENOWARNING("It's too early to spread the hive this far.")) return FALSE diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm index b5431720e14a..8b25cf07d14b 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm @@ -239,6 +239,9 @@ // Used for the faction of the xenomorph. Not recommended to modify. var/internal_faction + /// Short Hive ID as string used in stats reporting + var/reporting_id = "normal" + var/hivenumber = XENO_HIVE_NORMAL var/mob/living/carbon/xenomorph/queen/living_xeno_queen var/egg_planting_range = 15 @@ -285,6 +288,8 @@ var/larva_gestation_multiplier = 1 var/bonus_larva_spawn_chance = 1 var/hijack_burrowed_surge = FALSE //at hijack, start spawning lots of burrowed + /// how many burrowed is going to spawn during larva surge + var/hijack_burrowed_left = 0 var/ignore_slots = FALSE var/dynamic_evolution = TRUE @@ -469,6 +474,7 @@ SStracking.set_leader("hive_[hivenumber]", queen) SShive_status.wait = 2 SECONDS + SEND_SIGNAL(src, COMSIG_HIVE_NEW_QUEEN, queen) living_xeno_queen = queen recalculate_hive() @@ -877,6 +883,8 @@ /datum/hive_status/proc/abandon_on_hijack() var/area/hijacked_dropship = get_area(living_xeno_queen) + var/shipside_humans_weighted_count = 0 + var/xenos_count = 0 for(var/name_ref in hive_structures) for(var/obj/effect/alien/resin/special/S in hive_structures[name_ref]) if(get_area(S) == hijacked_dropship) @@ -885,6 +893,10 @@ qdel(S) for(var/mob/living/carbon/xenomorph/xeno as anything in totalXenos) if(get_area(xeno) != hijacked_dropship && xeno.loc && is_ground_level(xeno.loc.z)) + if(isfacehugger(xeno)) + to_chat(xeno, SPAN_XENOANNOUNCE("The Queen has left without you, you quickly find a hiding place to enter hibernation as you lose touch with the hive mind.")) + qdel(xeno) + continue if(xeno.hunter_data.hunted && !isqueen(xeno)) to_chat(xeno, SPAN_XENOANNOUNCE("The Queen has left without you, seperating you from her hive! You must defend yourself from the headhunter before you can enter hibernation...")) xeno.set_hive_and_update(XENO_HIVE_FORSAKEN) @@ -895,6 +907,9 @@ xeno.handle_stomach_contents() qdel(xeno) stored_larva++ + continue + if(!isfacehugger(xeno)) + xenos_count++ for(var/i in GLOB.alive_mob_list) var/mob/living/potential_host = i if(!(potential_host.status_flags & XENO_HOST)) @@ -907,7 +922,13 @@ for(var/obj/item/alien_embryo/embryo in potential_host) embryo.hivenumber = XENO_HIVE_FORSAKEN potential_host.update_med_icon() + for(var/mob/living/carbon/human/current_human as anything in GLOB.alive_human_list) + if((isspecieshuman(current_human) || isspeciessynth(current_human)) && current_human.job) + var/turf/turf = get_turf(current_human) + if(is_mainship_level(turf?.z)) + shipside_humans_weighted_count += RoleAuthority.calculate_role_weight(current_human.job) hijack_burrowed_surge = TRUE + hijack_burrowed_left = max(n_ceil(shipside_humans_weighted_count * 0.5) - xenos_count, 5) hivecore_cooldown = FALSE xeno_message(SPAN_XENOBOLDNOTICE("The weeds have recovered! A new hive core can be built!"),3,hivenumber) @@ -989,7 +1010,10 @@ /datum/hive_status/proc/can_spawn_as_hugger(mob/dead/observer/user) if(!GLOB.hive_datum || ! GLOB.hive_datum[hivenumber]) - return + return FALSE + if(jobban_isbanned(user, JOB_XENOMORPH)) // User is jobbanned + to_chat(user, SPAN_WARNING("You are banned from playing aliens and cannot spawn as a xenomorph.")) + return FALSE if(world.time < hugger_timelock) to_chat(user, SPAN_WARNING("The hive cannot support facehuggers yet...")) return FALSE @@ -1033,6 +1057,7 @@ /datum/hive_status/corrupted name = "Corrupted Hive" + reporting_id = "corrupted" hivenumber = XENO_HIVE_CORRUPTED prefix = "Corrupted " color = "#80ff80" @@ -1056,6 +1081,7 @@ /datum/hive_status/alpha name = "Alpha Hive" + reporting_id = "alpha" hivenumber = XENO_HIVE_ALPHA prefix = "Alpha " color = "#ff4040" @@ -1066,6 +1092,7 @@ /datum/hive_status/bravo name = "Bravo Hive" + reporting_id = "bravo" hivenumber = XENO_HIVE_BRAVO prefix = "Bravo " color = "#ffff80" @@ -1076,6 +1103,7 @@ /datum/hive_status/charlie name = "Charlie Hive" + reporting_id = "charlie" hivenumber = XENO_HIVE_CHARLIE prefix = "Charlie " color = "#bb40ff" @@ -1086,6 +1114,7 @@ /datum/hive_status/delta name = "Delta Hive" + reporting_id = "delta" hivenumber = XENO_HIVE_DELTA prefix = "Delta " color = "#8080ff" @@ -1096,6 +1125,7 @@ /datum/hive_status/feral name = "Feral Hive" + reporting_id = "feral" hivenumber = XENO_HIVE_FERAL prefix = "Feral " color = "#828296" @@ -1111,6 +1141,7 @@ /datum/hive_status/forsaken name = "Forsaken Hive" + reporting_id = "forsaken" hivenumber = XENO_HIVE_FORSAKEN prefix = "Forsaken " color = "#cc8ec4" @@ -1129,6 +1160,7 @@ /datum/hive_status/yautja name = "Hellhound Pack" + reporting_id = "hellhounds" hivenumber = XENO_HIVE_YAUTJA internal_faction = FACTION_YAUTJA @@ -1145,6 +1177,7 @@ /datum/hive_status/mutated name = "Mutated Hive" + reporting_id = "mutated" hivenumber = XENO_HIVE_MUTATED prefix = "Mutated " color = "#6abd99" @@ -1155,6 +1188,7 @@ /datum/hive_status/corrupted/tamed name = "Tamed Hive" + reporting_id = "tamed" hivenumber = XENO_HIVE_TAMED prefix = "Tamed " color = "#80ff80" diff --git a/code/modules/mob/living/silicon/decoy/decoy.dm b/code/modules/mob/living/silicon/decoy/decoy.dm index abd07e056be7..b625b19b172d 100644 --- a/code/modules/mob/living/silicon/decoy/decoy.dm +++ b/code/modules/mob/living/silicon/decoy/decoy.dm @@ -10,6 +10,8 @@ bound_width = 96 custom_slashed_sound = "alien_claw_metal" var/obj/item/device/radio/headset/almayer/mcom/ai/ai_headset //The thing it speaks into. + maxHealth = 1000 + health = 1000 /mob/living/silicon/decoy/ship_ai //For the moment, pending better pathing. var/silent_announcement_cooldown = 0 @@ -20,6 +22,7 @@ desc = "This is the artificial intelligence system for the [MAIN_SHIP_NAME]. Like many other military-grade AI systems, this one was manufactured by Weyland-Yutani." ai_headset = new(src) ai_mob_list += src + real_name = MAIN_AI_SYSTEM /mob/living/silicon/decoy/ship_ai/Destroy() QDEL_NULL(ai_headset) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 7803c15da523..0c182fb0fe9c 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -843,7 +843,7 @@ note dizziness decrements automatically in the mob's Life() proc. return FALSE to_chat(src, SPAN_WARNING("You attempt to get a good grip on [selection] in your body.")) else - if(get_active_hand()) + if(usr.get_active_hand()) to_chat(usr, SPAN_WARNING("You need an empty hand for this!")) return FALSE to_chat(usr, SPAN_WARNING("You attempt to get a good grip on [selection] in [src]'s body.")) diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 81296f346d50..39cc5b25e519 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -141,10 +141,9 @@ X.visible_message(SPAN_WARNING("[X] devours [pulled]!"), \ SPAN_WARNING("You devour [pulled]!"), null, 5) - //IMPORTANT CODER NOTE: Due to us using the old lighting engine, we need to hacky hack hard to get this working properly - //So we're just going to get the lights out of here by forceMoving them to a far-away place - //They will be recovered when regurgitating, since this also calls forceMove - pulled.moveToNullspace() + if(ishuman(pulled)) + var/mob/living/carbon/human/pulled_human = pulled + pulled_human.disable_lights() //Then, we place the mob where it ought to be X.stomach_contents.Add(pulled) diff --git a/code/modules/organs/limb_objects.dm b/code/modules/organs/limb_objects.dm index ecfd4ca1960f..734f303c7f5b 100644 --- a/code/modules/organs/limb_objects.dm +++ b/code/modules/organs/limb_objects.dm @@ -136,6 +136,7 @@ H.regenerate_icons() if(braindeath_on_decap) + brainmob.timeofdeath = world.time brainmob.set_stat(DEAD) brainmob.death(cause) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 60aa2f2c16e7..e58671d7c668 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -213,6 +213,8 @@ /obj/item/paper/proc/parsepencode(t, obj/item/tool/pen/P, mob/user as mob, iscrayon = 0) + var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper) + t = replacetext(t, "\[center\]", "
") t = replacetext(t, "\[/center\]", "
") t = replacetext(t, "\[br\]", "
") @@ -251,9 +253,9 @@ t = replacetext(t, "\[/grid\]", "") t = replacetext(t, "\[row\]", "") t = replacetext(t, "\[cell\]", "") - t = replacetext(t, "\[logo\]", "") - t = replacetext(t, "\[wy\]", "") - t = replacetext(t, "\[uscm\]", "") + t = replacetext(t, "\[logo\]", "") + t = replacetext(t, "\[wy\]", "") + t = replacetext(t, "\[uscm\]", "") t = "[t]" else // If it is a crayon, and he still tries to use these, make them empty! @@ -619,11 +621,21 @@ /obj/item/paper/wy icon_state = "paper_wy" - info = "

\n" + +/obj/item/paper/wy/Initialize(mapload, photo_list) + . = ..() + + var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper) + info = "

\n" /obj/item/paper/uscm icon_state = "paper_uscm" - info = "

\n" + +/obj/item/paper/uscm/Initialize(mapload, photo_list) + . = ..() + + var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper) + info = "

\n" /obj/item/paper/research_notes icon_state = "paper_wy_words" @@ -661,7 +673,8 @@ if(!random_chem) random_chem = pick(chemical_gen_classes_list["T1"]) C = chemical_reagents_list["[random_chem]"] - var/txt = "

Official Weyland-Yutani Document
Experiment Notes

" + var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper) + var/txt = "

Official Weyland-Yutani Document
Experiment Notes

" switch(note_type) if("synthesis") var/datum/chemical_reaction/G = chemical_reactions_list[C.id] diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm index 67003d4f79d0..6a20e9cfe78e 100644 --- a/code/modules/power/port_gen.dm +++ b/code/modules/power/port_gen.dm @@ -102,6 +102,30 @@ display round(lastgen) and phorontank amount else . += SPAN_NOTICE("The generator is off.") +/obj/structure/machinery/power/port_gen/attack_alien(mob/living/carbon/xenomorph/attacking_xeno) + if(!active && !anchored) + return ..() + + if(attacking_xeno.mob_size < MOB_SIZE_XENO) + to_chat(attacking_xeno, SPAN_XENOWARNING("You're too small to do any significant damage to affect this!")) + return XENO_NO_DELAY_ACTION + + attacking_xeno.animation_attack_on(src) + attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno] slashes [src]!"), SPAN_DANGER("You slash [src]!")) + playsound(attacking_xeno, pick('sound/effects/metalhit.ogg', 'sound/weapons/alien_claw_metal1.ogg', 'sound/weapons/alien_claw_metal2.ogg', 'sound/weapons/alien_claw_metal3.ogg'), 25, 1) + + if(active) + active = FALSE + stop_processing() + icon_state = initial(icon_state) + visible_message(SPAN_NOTICE("[src] sputters to a stop!")) + return XENO_NONCOMBAT_ACTION + + if(anchored) + anchored = FALSE + visible_message(SPAN_NOTICE("[src]'s bolts are dislodged!")) + return XENO_NONCOMBAT_ACTION + //A power generator that runs on solid plasma sheets. /obj/structure/machinery/power/port_gen/pacman name = "P.A.C.M.A.N.-type Portable Generator" @@ -240,7 +264,7 @@ display round(lastgen) and phorontank amount to_chat(user, SPAN_NOTICE(" You open the access panel.")) else to_chat(user, SPAN_NOTICE(" You close the access panel.")) - else if(istype(O, /obj/item/tool/crowbar) && open) + else if(HAS_TRAIT(O, TRAIT_TOOL_CROWBAR) && open) var/obj/structure/machinery/constructable_frame/new_frame = new /obj/structure/machinery/constructable_frame(src.loc) for(var/obj/item/I in component_parts) if(I.reliability < 100) diff --git a/code/modules/projectiles/ammo_datums.dm b/code/modules/projectiles/ammo_datums.dm index 0fa816e88bc5..40d1c47bf3bc 100644 --- a/code/modules/projectiles/ammo_datums.dm +++ b/code/modules/projectiles/ammo_datums.dm @@ -383,7 +383,7 @@ accuracy = -HIT_ACCURACY_TIER_3 accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 damage = 55 - penetration= ARMOR_PENETRATION_TIER_3 + penetration = ARMOR_PENETRATION_TIER_3 shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 /datum/ammo/bullet/pistol/heavy/super //Commander's variant @@ -2809,7 +2809,7 @@ datum/ammo/rocket/wp/upp return var/datum/effects/neurotoxin/neuro_effect = locate() in moob.effects_list if(!neuro_effect) - neuro_effect = new /datum/effects/neurotoxin(moob) + neuro_effect = new /datum/effects/neurotoxin(moob, proj.firer) neuro_effect.duration += 5 moob.apply_effect(3, DAZE) to_chat(moob, SPAN_HIGHDANGER("Neurotoxic liquid spreads all over you and immediately soaks into your pores and orifices! Oh fuck!")) // Fucked up but have a chance to escape rather than being game-ended @@ -2832,9 +2832,10 @@ datum/ammo/rocket/wp/upp /datum/ammo/xeno/boiler_gas/proc/drop_nade(turf/turf, obj/item/projectile/proj) var/lifetime_mult = 1.0 + var/datum/cause_data if(isboiler(proj.firer)) - smoke_system.cause_data = proj.weapon_cause_data - smoke_system.set_up(smokerange, 0, turf) + cause_data = proj.weapon_cause_data + smoke_system.set_up(smokerange, 0, turf, new_cause_data = cause_data) smoke_system.lifetime = 12 * lifetime_mult smoke_system.start() turf.visible_message(SPAN_DANGER("A glob of acid lands with a splat and explodes into noxious fumes!")) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 5528755cf87c..263f5b07cca4 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -309,6 +309,7 @@ damage_mult = BASE_BULLET_DAMAGE_MULT damage_falloff_mult = DAMAGE_FALLOFF_TIER_10 damage_buildup_mult = DAMAGE_BUILDUP_TIER_1 + velocity_add = BASE_VELOCITY_BONUS recoil = RECOIL_OFF recoil_unwielded = RECOIL_OFF movement_onehanded_acc_penalty_mult = MOVEMENT_ACCURACY_PENALTY_MULT_TIER_1 diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm index b8ebe72c12e0..9745073ae729 100644 --- a/code/modules/projectiles/gun_attachables.dm +++ b/code/modules/projectiles/gun_attachables.dm @@ -2045,7 +2045,7 @@ Defined in conflicts.dm of the #defines folder. //The requirement for an attachable being alt fire is AMMO CAPACITY > 0. /obj/item/attachable/attached_gun/grenade - name = "underslung grenade launcher" + name = "U1 grenade launcher" desc = "A weapon-mounted, reloadable grenade launcher." icon_state = "grenade" attach_icon = "grenade_a" diff --git a/code/modules/projectiles/gun_helpers.dm b/code/modules/projectiles/gun_helpers.dm index 98d1be3a9c64..d8ea29cd92f8 100644 --- a/code/modules/projectiles/gun_helpers.dm +++ b/code/modules/projectiles/gun_helpers.dm @@ -143,7 +143,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w /obj/item/weapon/gun/dropped(mob/user) . = ..() - turn_off_light(user) + disconnect_light_from_mob(user) var/delay_left = (last_fired + fire_delay + additional_fire_group_delay) - world.time if(fire_delay_group && delay_left > 0) @@ -160,7 +160,8 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w for(var/group in fire_delay_group) LAZYSET(user.fire_delay_next_fire, group, world.time + delay_left) -/obj/item/weapon/gun/proc/turn_off_light(mob/bearer) +/// This function disconnects the luminosity from the mob and back to the gun +/obj/item/weapon/gun/proc/disconnect_light_from_mob(mob/bearer) if (!(flags_gun_features & GUN_FLASHLIGHT_ON)) return FALSE for (var/slot in attachments) @@ -172,6 +173,18 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w return TRUE return FALSE +/// This function actually turns the lights on the gun off +/obj/item/weapon/gun/proc/turn_off_light(mob/bearer) + if (!(flags_gun_features & GUN_FLASHLIGHT_ON)) + return FALSE + for (var/slot in attachments) + var/obj/item/attachable/attachment = attachments[slot] + if (!attachment || !attachment.light_mod) + continue + attachment.activate_attachment(src, bearer) + return TRUE + return FALSE + /obj/item/weapon/gun/pickup(mob/user) ..() diff --git a/code/modules/projectiles/guns/lever_action.dm b/code/modules/projectiles/guns/lever_action.dm index d611605cd0e5..259c6170ae48 100644 --- a/code/modules/projectiles/guns/lever_action.dm +++ b/code/modules/projectiles/guns/lever_action.dm @@ -71,7 +71,7 @@ their unique feature is that a direct hit will buff your damage and firerate /obj/item/weapon/gun/lever_action/dropped(mob/user) . = ..() - reset_hit_buff() + reset_hit_buff(user) addtimer(VARSET_CALLBACK(src, cur_onehand_chance, reset_onehand_chance), 4 SECONDS, TIMER_OVERRIDE|TIMER_UNIQUE) /obj/item/weapon/gun/lever_action/proc/direct_hit_buff(mob/user, mob/target, one_hand_lever = FALSE) @@ -110,7 +110,7 @@ their unique feature is that a direct hit will buff your damage and firerate if(!(flags_gun_lever_action & USES_STREAKS)) return apply_hit_buff(user, target, one_hand_lever) //this is a separate proc so it's configgable - addtimer(CALLBACK(src, PROC_REF(reset_hit_buff), one_hand_lever), hit_buff_reset_cooldown, TIMER_OVERRIDE|TIMER_UNIQUE) + addtimer(CALLBACK(src, PROC_REF(reset_hit_buff), user, one_hand_lever), hit_buff_reset_cooldown, TIMER_OVERRIDE|TIMER_UNIQUE) /obj/item/weapon/gun/lever_action/proc/apply_hit_buff(mob/user, mob/target, one_hand_lever = FALSE) lever_sound = lever_super_sound @@ -126,7 +126,7 @@ their unique feature is that a direct hit will buff your damage and firerate fire_delay += AM.delay_mod wield_delay = 0 //for one-handed levering -/obj/item/weapon/gun/lever_action/proc/reset_hit_buff(one_hand_lever) //why does this need a user arg when it doesn't use user at all? +/obj/item/weapon/gun/lever_action/proc/reset_hit_buff(mob/user, one_hand_lever) if(!(flags_gun_lever_action & USES_STREAKS)) return SIGNAL_HANDLER @@ -513,10 +513,12 @@ their unique feature is that a direct hit will buff your damage and firerate levered = FALSE return empty_chamber(user) -/obj/item/weapon/gun/lever_action/xm88/reset_hit_buff(one_hand_lever) //why does this need a user arg when it doesn't use user at all? +/obj/item/weapon/gun/lever_action/xm88/reset_hit_buff(mob/user, one_hand_lever) if(!(flags_gun_lever_action & USES_STREAKS)) return SIGNAL_HANDLER + if(streak > 0) + to_chat(user, SPAN_WARNING("[src] beeps as it loses its targeting data, and returns to normal firing procedures.")) streak = 0 lever_sound = initial(lever_sound) lever_message = initial(lever_message) @@ -531,7 +533,6 @@ their unique feature is that a direct hit will buff your damage and firerate lever_delay = FIRE_DELAY_TIER_3 damage_mult = BASE_BULLET_DAMAGE_MULT recalculate_attachment_bonuses() //stock wield delay - visible_message(SPAN_WARNING("\The [src] beeps as it loses its targeting data, and returns to normal firing procedures."), max_distance = 1) // tell them they've lost stacks if(one_hand_lever) addtimer(VARSET_CALLBACK(src, cur_onehand_chance, reset_onehand_chance), 4 SECONDS, TIMER_OVERRIDE|TIMER_UNIQUE) diff --git a/code/modules/projectiles/magazines/flamer.dm b/code/modules/projectiles/magazines/flamer.dm index 782b6bfe8910..787a0585640a 100644 --- a/code/modules/projectiles/magazines/flamer.dm +++ b/code/modules/projectiles/magazines/flamer.dm @@ -58,6 +58,7 @@ reagents.clear_reagents() + playsound(loc, 'sound/effects/refill.ogg', 25, 1, 3) to_chat(usr, SPAN_NOTICE("You empty out [src]")) update_icon() @@ -71,22 +72,21 @@ G.update_icon() /obj/item/ammo_magazine/flamer_tank/afterattack(obj/target, mob/user , flag) //refuel at fueltanks when we run out of ammo. - if(!istype(target, /obj/structure/reagent_dispensers/fueltank) && !istype(target, /obj/item/tool/weldpack) && !istype(target, /obj/item/storage/backpack/marine/engineerpack)) - return ..() if(get_dist(user,target) > 1) return ..() + if(!istype(target, /obj/structure/reagent_dispensers/fueltank) && !istype(target, /obj/item/tool/weldpack) && !istype(target, /obj/item/storage/backpack/marine/engineerpack)) + return ..() - var/obj/O = target - if(!O.reagents || O.reagents.reagent_list.len < 1) - to_chat(user, SPAN_WARNING("[O] is empty!")) + if(!target.reagents || target.reagents.reagent_list.len < 1) + to_chat(user, SPAN_WARNING("[target] is empty!")) return if(!reagents) create_reagents(max_rounds) - var/datum/reagent/to_add = O.reagents.reagent_list[1] + var/datum/reagent/to_add = target.reagents.reagent_list[1] - if(!istype(to_add) || (length(reagents.reagent_list) && flamer_chem != to_add.id) || length(O.reagents.reagent_list) > 1) + if(!istype(to_add) || (length(reagents.reagent_list) && flamer_chem != to_add.id) || length(target.reagents.reagent_list) > 1) to_chat(user, SPAN_WARNING("You can't mix fuel mixtures!")) return @@ -96,10 +96,11 @@ var/fuel_amt_to_remove = Clamp(to_add.volume, 0, max_rounds - reagents.get_reagent_amount(to_add.id)) if(!fuel_amt_to_remove) - to_chat(user, SPAN_WARNING("[O] is empty!")) + if(!max_rounds) + to_chat(user, SPAN_WARNING("[target] is empty!")) return - O.reagents.remove_reagent(to_add.id, fuel_amt_to_remove) + target.reagents.remove_reagent(to_add.id, fuel_amt_to_remove) reagents.add_reagent(to_add.id, fuel_amt_to_remove) playsound(loc, 'sound/effects/refill.ogg', 25, 1, 3) caliber = to_add.name diff --git a/code/modules/projectiles/magazines/pistols.dm b/code/modules/projectiles/magazines/pistols.dm index 1390d73e74ac..a40087ebb78d 100644 --- a/code/modules/projectiles/magazines/pistols.dm +++ b/code/modules/projectiles/magazines/pistols.dm @@ -8,7 +8,7 @@ caliber = "9mm" icon = 'icons/obj/items/weapons/guns/ammo_by_faction/uscm.dmi' icon_state = "m4a3" - max_rounds = 9 + max_rounds = 12 w_class = SIZE_SMALL default_ammo = /datum/ammo/bullet/pistol gun_type = /obj/item/weapon/gun/pistol/m4a3 @@ -55,7 +55,7 @@ default_ammo = /datum/ammo/bullet/pistol/heavy caliber = ".45" icon_state = "m4a345"//rename later - max_rounds = 14 + max_rounds = 7 gun_type = /obj/item/weapon/gun/pistol/m1911 diff --git a/code/modules/reagents/chemistry_machinery/chem_dispenser.dm b/code/modules/reagents/chemistry_machinery/chem_dispenser.dm index 8de20ca2b79a..09d46aa8c053 100644 --- a/code/modules/reagents/chemistry_machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry_machinery/chem_dispenser.dm @@ -1,5 +1,6 @@ /obj/structure/machinery/chem_dispenser - name = "chem dispenser" + name = "chemical dispenser" + desc = "A complex machine for mixing elements into chemicals. A Wey-Yu product." density = TRUE anchored = TRUE icon = 'icons/obj/structures/machinery/science_machines.dmi' diff --git a/code/modules/reagents/chemistry_machinery/chem_simulator.dm b/code/modules/reagents/chemistry_machinery/chem_simulator.dm index 8889efc9ef80..2c8602b0dab7 100644 --- a/code/modules/reagents/chemistry_machinery/chem_simulator.dm +++ b/code/modules/reagents/chemistry_machinery/chem_simulator.dm @@ -576,8 +576,9 @@ sleep(10) var/obj/item/paper/research_report/report = new /obj/item/paper/research_report/(loc) var/datum/reagent/D = chemical_reagents_list[id] + var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper) report.name = "Simulation result for [D.name]" - report.info += "

Official Company Document
Simulated Synthesis Report

Result for [D.name]

" + report.info += "

Official Company Document
Simulated Synthesis Report

Result for [D.name]

" report.generate(D) report.info += "

This report was automatically printed by the Synthesis Simulator.
The [MAIN_SHIP_NAME], [time2text(world.timeofday, "MM/DD")]/[game_year], [worldtime2text()]

\n" playsound(loc, 'sound/machines/twobeep.ogg', 15, 1) diff --git a/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm b/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm index 8b781407aec4..dc1f72ec41c7 100644 --- a/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm +++ b/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm @@ -104,8 +104,9 @@ chemical_data.complete_chemical(S) else + var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper) report.name = "Analysis of ERROR" - report.info += "

Official Weyland-Yutani Document
Reagent Analysis Print

Analysis ERROR

" + report.info += "

Official Weyland-Yutani Document
Reagent Analysis Print

Analysis ERROR

" report.info += "Result:
Analysis failed for sample #[sample_number].

\n" report.info += "Reason for error:
[reason]
\n" report.info += "

This report was automatically printed by the A-XRF Scanner.
The [MAIN_SHIP_NAME], [time2text(world.timeofday, "MM/DD")]/[game_year], [worldtime2text()]

\n" @@ -115,8 +116,8 @@ report = new /obj/item/paper/research_report(loc) report.name = "Analysis of [name]" - - report.info += "

Official Weyland-Yutani Document
Automated A-XRF Report

Analysis of [name]

" + var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper) + report.info += "

Official Weyland-Yutani Document
Automated A-XRF Report

Analysis of [name]

" if(sample_number) report.info += "Results for sample: #[sample_number]
\n" report.generate(src, admin_spawned) diff --git a/code/modules/security_levels/security_levels.dm b/code/modules/security_levels/security_levels.dm index d8f61c11a3e6..be087444c99e 100644 --- a/code/modules/security_levels/security_levels.dm +++ b/code/modules/security_levels/security_levels.dm @@ -16,32 +16,32 @@ switch(level) if(SEC_LEVEL_GREEN) if(announce) - ai_announcement("Attention: Security level lowered to GREEN - all clear.", no_sound ? null : 'sound/AI/code_green.ogg') + ai_announcement("Attention: Security level lowered to GREEN - all clear.", no_sound ? null : 'sound/AI/code_green.ogg', ARES_LOG_SECURITY) security_level = SEC_LEVEL_GREEN if(SEC_LEVEL_BLUE) if(security_level < SEC_LEVEL_BLUE) if(announce) - ai_announcement("Attention: Security level elevated to BLUE - potentially hostile activity on board.", no_sound ? null : 'sound/AI/code_blue_elevated.ogg') + ai_announcement("Attention: Security level elevated to BLUE - potentially hostile activity on board.", no_sound ? null : 'sound/AI/code_blue_elevated.ogg', ARES_LOG_SECURITY) else if(announce) - ai_announcement("Attention: Security level lowered to BLUE - potentially hostile activity on board.", no_sound ? null : 'sound/AI/code_blue_lowered.ogg') + ai_announcement("Attention: Security level lowered to BLUE - potentially hostile activity on board.", no_sound ? null : 'sound/AI/code_blue_lowered.ogg', ARES_LOG_SECURITY) security_level = SEC_LEVEL_BLUE if(SEC_LEVEL_RED) if(security_level < SEC_LEVEL_RED) if(announce) - ai_announcement("Attention: Security level elevated to RED - there is an immediate threat to the ship.", no_sound ? null : 'sound/AI/code_red_elevated.ogg') + ai_announcement("Attention: Security level elevated to RED - there is an immediate threat to the ship.", no_sound ? null : 'sound/AI/code_red_elevated.ogg', ARES_LOG_SECURITY) else if(announce) - ai_announcement("Attention: Security level lowered to RED - there is an immediate threat to the ship.", no_sound ? null : 'sound/AI/code_red_lowered.ogg') + ai_announcement("Attention: Security level lowered to RED - there is an immediate threat to the ship.", no_sound ? null : 'sound/AI/code_red_lowered.ogg', ARES_LOG_SECURITY) security_level = SEC_LEVEL_RED if(SEC_LEVEL_DELTA) if(announce) var/name = "SELF-DESTRUCT SYSTEMS ACTIVE" var/input = "DANGER, THE EMERGENCY DESTRUCT SYSTEM IS NOW ACTIVATED. PROCEED TO THE SELF-DESTRUCT CHAMBER FOR CONTROL ROD INSERTION." - marine_announcement(input, name, 'sound/AI/selfdestruct_short.ogg') + marine_announcement(input, name, 'sound/AI/selfdestruct_short.ogg', logging = ARES_LOG_SECURITY) security_level = SEC_LEVEL_DELTA EvacuationAuthority.enable_self_destruct() diff --git a/code/modules/shuttle/computers/dropship_computer.dm b/code/modules/shuttle/computers/dropship_computer.dm index 19d9abfd81b4..50449b32fcb9 100644 --- a/code/modules/shuttle/computers/dropship_computer.dm +++ b/code/modules/shuttle/computers/dropship_computer.dm @@ -1,6 +1,6 @@ /obj/structure/machinery/computer/shuttle/dropship/flight name = "dropship navigation computer" - desc = "flight computer for dropship" + desc = "A flight computer that can be used for autopilot or long-range flights." icon = 'icons/obj/structures/machinery/shuttle-parts.dmi' icon_state = "console" req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP) @@ -267,7 +267,7 @@ hijack.fire() GLOB.alt_ctrl_disabled = TRUE - marine_announcement("Unscheduled dropship departure detected from operational area. Hijack likely. Shutting down autopilot.", "Dropship Alert", 'sound/AI/hijack.ogg') + marine_announcement("Unscheduled dropship departure detected from operational area. Hijack likely. Shutting down autopilot.", "Dropship Alert", 'sound/AI/hijack.ogg', logging = ARES_LOG_SECURITY) var/mob/living/carbon/xenomorph/xeno = user var/hivenumber = XENO_HIVE_NORMAL diff --git a/code/modules/shuttle/dropship_hijack.dm b/code/modules/shuttle/dropship_hijack.dm index 4798279a8b94..ce151c14324c 100644 --- a/code/modules/shuttle/dropship_hijack.dm +++ b/code/modules/shuttle/dropship_hijack.dm @@ -1,3 +1,5 @@ +#define HIJACK_CRASH_SITE_OFFSET_X -5 +#define HIJACK_CRASH_SITE_OFFSET_Y -11 /datum/dropship_hijack var/obj/docking_port/mobile/shuttle @@ -83,18 +85,17 @@ /datum/dropship_hijack/almayer/proc/target_crash_site(ship_section) target_ship_section = ship_section - var/area/target_area = get_crashsite_area(ship_section) - // spawn crash location - var/turf/target = pick(get_area_turfs(target_area)) + var/turf/target = get_crashsite_turf(ship_section) if(!target) to_chat(usr, SPAN_WARNING("No area available")) return var/obj/docking_port/stationary/marine_dropship/crash_site/target_site = new() crash_site = target_site - crash_site.x = target.x - 5 - crash_site.y = target.y - 11 - crash_site.z = target.z + var/turf/offset_target = locate(target.x + HIJACK_CRASH_SITE_OFFSET_X, target.y + HIJACK_CRASH_SITE_OFFSET_Y, target.z) + if(!offset_target) + offset_target = target // Welp the offsetting failed so... + target_site.forceMove(offset_target) target_site.name = "[shuttle] crash site" target_site.id = "crash_site_[shuttle.id]" @@ -117,11 +118,12 @@ var/list/remaining_crash_sites = almayer_ship_sections.Copy() remaining_crash_sites -= target_ship_section var/new_target_ship_section = pick(remaining_crash_sites) - var/area/target_area = get_crashsite_area(new_target_ship_section) - // spawn crash location - var/turf/target = pick(get_area_turfs(target_area)) - crash_site.Move(target) - marine_announcement("A hostile aircraft on course for the [target_ship_section] has been successfully deterred.", "IX-50 MGAD System") + var/turf/target = get_crashsite_turf(new_target_ship_section) + var/turf/offset_target = locate(target.x + HIJACK_CRASH_SITE_OFFSET_X, target.y + HIJACK_CRASH_SITE_OFFSET_Y, target.z) + if(!offset_target) + offset_target = target // Welp the offsetting failed so... + crash_site.forceMove(offset_target) + marine_announcement("A hostile aircraft on course for the [target_ship_section] has been successfully deterred.", "IX-50 MGAD System", logging = ARES_LOG_SECURITY) target_ship_section = new_target_ship_section // TODO mobs not alerted for(var/area/internal_area in shuttle.shuttle_areas) @@ -147,7 +149,7 @@ shuttle.crashing = TRUE - marine_announcement("DROPSHIP ON COLLISION COURSE. CRASH IMMINENT." , "EMERGENCY", 'sound/AI/dropship_emergency.ogg') + marine_announcement("DROPSHIP ON COLLISION COURSE. CRASH IMMINENT." , "EMERGENCY", 'sound/AI/dropship_emergency.ogg', logging = ARES_LOG_SECURITY) announce_dchat("The dropship is about to impact [get_area_name(crash_site)]", crash_site) final_announcement = TRUE @@ -172,53 +174,55 @@ /datum/dropship_hijack/almayer/proc/disable_latejoin() enter_allowed = FALSE -/datum/dropship_hijack/almayer/proc/get_crashsite_area(ship_section) - var/list/areas = list() +/datum/dropship_hijack/almayer/proc/get_crashsite_turf(ship_section) + var/list/turfs = list() switch(ship_section) if("Upper deck Foreship") - areas += typesof(/area/almayer/shipboard/brig) - areas += list(/area/almayer/command/cichallway) - areas += list(/area/almayer/command/cic) + turfs += get_area_turfs(/area/almayer/shipboard/brig/armory) + turfs += get_area_turfs(/area/almayer/shipboard/brig/cells) + turfs += get_area_turfs(/area/almayer/shipboard/brig/cic_hallway) + turfs += get_area_turfs(/area/almayer/shipboard/brig/cryo) + turfs += get_area_turfs(/area/almayer/shipboard/brig/evidence_storage) + turfs += get_area_turfs(/area/almayer/shipboard/brig/execution) + turfs += get_area_turfs(/area/almayer/shipboard/brig/general_equipment) + turfs += get_area_turfs(/area/almayer/shipboard/brig/lobby) + turfs += get_area_turfs(/area/almayer/shipboard/brig/main_office) + turfs += get_area_turfs(/area/almayer/shipboard/brig/perma) + turfs += get_area_turfs(/area/almayer/shipboard/brig/processing) + turfs += get_area_turfs(/area/almayer/shipboard/brig/surgery) + turfs += get_area_turfs(/area/almayer/command/cichallway) + turfs += get_area_turfs(/area/almayer/command/cic) if("Upper deck Midship") - areas += list( - /area/almayer/medical/morgue, - /area/almayer/medical/upper_medical, - /area/almayer/medical/containment, - /area/almayer/medical/containment/cell, - /area/almayer/medical/medical_science, - /area/almayer/medical/testlab, - /area/almayer/medical/hydroponics, - ) + turfs += get_area_turfs(/area/almayer/medical/morgue) + turfs += get_area_turfs(/area/almayer/medical/upper_medical) + turfs += get_area_turfs(/area/almayer/medical/containment) + turfs += get_area_turfs(/area/almayer/medical/containment/cell) + turfs += get_area_turfs(/area/almayer/medical/medical_science) + turfs += get_area_turfs(/area/almayer/medical/testlab) + turfs += get_area_turfs(/area/almayer/medical/hydroponics) if("Upper deck Aftship") - areas += list( - /area/almayer/engineering/upper_engineering, - /area/almayer/command/computerlab, - /area/almayer/engineering/laundry, - ) + turfs += get_area_turfs(/area/almayer/engineering/upper_engineering) + turfs += get_area_turfs(/area/almayer/engineering/laundry) if("Lower deck Foreship") - areas += list( - /area/almayer/hallways/hangar, - /area/almayer/hallways/vehiclehangar - ) + turfs += get_area_turfs(/area/almayer/hallways/hangar) + turfs += get_area_turfs(/area/almayer/hallways/vehiclehangar) if("Lower deck Midship") - areas += list( - /area/almayer/medical/chemistry, - /area/almayer/medical/lower_medical_lobby, - /area/almayer/medical/lockerroom, - /area/almayer/medical/lower_medical_medbay, - /area/almayer/medical/operating_room_one, - /area/almayer/medical/operating_room_two, - /area/almayer/medical/operating_room_three, - /area/almayer/medical/operating_room_four, - /area/almayer/living/briefing, - /area/almayer/squads/req, - - ) + turfs += get_area_turfs(/area/almayer/medical/chemistry) + turfs += get_area_turfs(/area/almayer/medical/lower_medical_lobby) + turfs += get_area_turfs(/area/almayer/medical/lockerroom) + turfs += get_area_turfs(/area/almayer/medical/lower_medical_medbay) + turfs += get_area_turfs(/area/almayer/medical/operating_room_one) + turfs += get_area_turfs(/area/almayer/medical/operating_room_two) + turfs += get_area_turfs(/area/almayer/medical/operating_room_three) + turfs += get_area_turfs(/area/almayer/medical/operating_room_four) + turfs += get_area_turfs(/area/almayer/living/briefing) + turfs += get_area_turfs(/area/almayer/squads/req) if("Lower deck Aftship") - areas += list( - /area/almayer/living/cryo_cells, - /area/almayer/engineering/engineering_workshop, - ) + turfs += get_area_turfs(/area/almayer/living/cryo_cells) + turfs += get_area_turfs(/area/almayer/engineering/engineering_workshop) else CRASH("Crash site [ship_section] unknown.") - return pick(areas) + return pick(turfs) + +#undef HIJACK_CRASH_SITE_OFFSET_X +#undef HIJACK_CRASH_SITE_OFFSET_Y diff --git a/code/modules/shuttle/helpers.dm b/code/modules/shuttle/helpers.dm index 14cfcc3cd691..1d841581faa0 100644 --- a/code/modules/shuttle/helpers.dm +++ b/code/modules/shuttle/helpers.dm @@ -8,7 +8,8 @@ /datum/door_controller/aggregate/Destroy(force, ...) . = ..() - QDEL_NULL_LIST(door_controllers) + QDEL_LIST_ASSOC_VAL(door_controllers) + door_controllers = null /datum/door_controller/aggregate/proc/set_label(label) for(var/datum/door_controller/single/cont in door_controllers) diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 77ba9681ebb6..6d3465ee8747 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -628,15 +628,15 @@ /obj/docking_port/mobile/proc/intoTheSunset() // Loop over mobs - for(var/t in return_turfs()) - var/turf/T = t - for(var/mob/living/L in T.GetAllContents()) + for(var/turf/turf as anything in return_turfs()) + for(var/mob/living/mob in turf.GetAllContents()) // Ghostize them and put them in nullspace stasis (for stat & possession checks) - //L.notransform = TRUE - var/mob/dead/observer/O = L.ghostize(FALSE) - if(O) - O.timeofdeath = world.time - L.moveToNullspace() + //mob.notransform = TRUE + var/mob/dead/observer/obs = mob.ghostize(FALSE) + if(obs) + obs.timeofdeath = world.time + obs.client?.player_details.larva_queue_time = world.time + mob.moveToNullspace() // Now that mobs are stowed, delete the shuttle jumpToNullSpace() diff --git a/code/modules/shuttle/shuttles/dropship.dm b/code/modules/shuttle/shuttles/dropship.dm index 12f33d779661..303d4c0494ed 100644 --- a/code/modules/shuttle/shuttles/dropship.dm +++ b/code/modules/shuttle/shuttles/dropship.dm @@ -278,6 +278,8 @@ // shake_camera(affected_mob, 10, 1) affected_mob.apply_effect(3, WEAKEN) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING) + /datum/map_template/shuttle/alamo name = "Alamo" shuttle_id = DROPSHIP_ALAMO diff --git a/code/modules/shuttle/shuttles/escape_shuttle.dm b/code/modules/shuttle/shuttles/escape_shuttle.dm index a4bce9910bb7..6c580f9f163b 100644 --- a/code/modules/shuttle/shuttles/escape_shuttle.dm +++ b/code/modules/shuttle/shuttles/escape_shuttle.dm @@ -1,5 +1,3 @@ -#define CRASH_LAND_PROBABILITY 50 - /obj/docking_port/mobile/escape_shuttle name = "Escape Pod" id = ESCAPE_SHUTTLE @@ -10,6 +8,8 @@ rechargeTime = SHUTTLE_RECHARGE ignitionTime = 8 SECONDS ignition_sound = 'sound/effects/escape_pod_warmup.ogg' + /// The % chance of the escape pod crashing into the groundmap + var/crash_land_chance = 33 var/datum/door_controller/single/door_handler = new() var/launched = FALSE @@ -76,7 +76,7 @@ return destination = null - if(prob(CRASH_LAND_PROBABILITY)) + if(prob(crash_land_chance)) create_crash_point() set_mode(SHUTTLE_IGNITING) @@ -176,6 +176,12 @@ . = ..() playsound(src,'sound/effects/escape_pod_launch.ogg', 50, 1) +/obj/docking_port/mobile/escape_shuttle/proc/force_crash() + create_crash_point() + set_mode(SHUTTLE_IGNITING) + on_ignition() + setTimer(ignitionTime) + /obj/docking_port/mobile/escape_shuttle/e id = ESCAPE_SHUTTLE_EAST width = 4 @@ -270,6 +276,3 @@ /datum/map_template/shuttle/escape_pod_e_cl name = "Escape Pod E CL" shuttle_id = ESCAPE_SHUTTLE_EAST_CL - - -#undef CRASH_LAND_PROBABILITY diff --git a/code/modules/shuttles/marine_ferry.dm b/code/modules/shuttles/marine_ferry.dm index 48a6c176293e..17caccde207e 100644 --- a/code/modules/shuttles/marine_ferry.dm +++ b/code/modules/shuttles/marine_ferry.dm @@ -414,7 +414,7 @@ // At halftime, we announce whether or not the AA forced the dropship to divert // The rounding is because transit time is decreased by 10 each loop. Travel time, however, might not be a multiple of 10 if(in_transit_time_left == round(travel_time / 2, 10) && true_crash_target_section != crash_target_section) - marine_announcement("A hostile aircraft on course for the [true_crash_target_section] has been successfully deterred.", "IX-50 MGAD System") + marine_announcement("A hostile aircraft on course for the [true_crash_target_section] has been successfully deterred.", "IX-50 MGAD System", logging = ARES_LOG_SECURITY) var/area/shuttle_area for(var/turf/T in turfs_int) @@ -438,7 +438,7 @@ //This is where things change and shit gets real - marine_announcement("DROPSHIP ON COLLISION COURSE. CRASH IMMINENT." , "EMERGENCY", 'sound/AI/dropship_emergency.ogg') + marine_announcement("DROPSHIP ON COLLISION COURSE. CRASH IMMINENT." , "EMERGENCY", 'sound/AI/dropship_emergency.ogg', logging = ARES_LOG_SECURITY) for(var/mob/dead/observer/observer as anything in GLOB.observer_list) to_chat(observer, SPAN_DEADSAY(FONT_SIZE_LARGE("The dropship is about to impact [get_area_name(T_trg)]" + " [OBSERVER_JMP(observer, T_trg)]"))) diff --git a/code/modules/shuttles/shuttle_console.dm b/code/modules/shuttles/shuttle_console.dm index e765851c3b29..ecf1bacf080b 100644 --- a/code/modules/shuttles/shuttle_console.dm +++ b/code/modules/shuttles/shuttle_console.dm @@ -291,7 +291,7 @@ GLOBAL_LIST_EMPTY(shuttle_controls) if(round_statistics) round_statistics.track_hijack() - marine_announcement("Unscheduled dropship departure detected from operational area. Hijack likely. Shutting down autopilot.", "Dropship Alert", 'sound/AI/hijack.ogg') + marine_announcement("Unscheduled dropship departure detected from operational area. Hijack likely. Shutting down autopilot.", "Dropship Alert", 'sound/AI/hijack.ogg', logging = ARES_LOG_SECURITY) shuttle.alerts_allowed-- to_chat(Q, SPAN_DANGER("A loud alarm erupts from [src]! The fleshy hosts must know that you can access it!")) diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index cebd4b44da7d..8f2e6156831a 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -106,6 +106,8 @@ if(.) if(is_surgery_tool(tool)) //Make sure you still have all your tools after a surgery. return FALSE + if(HAS_TRAIT(tool, TRAIT_ITEM_NOT_IMPLANTABLE)) + return FALSE if(tool.w_class > get_max_wclass(surgery)) to_chat(user, SPAN_WARNING("[tool] is too big to implant into [surgery.target]'s [surgery.affected_limb.cavity]!")) return FALSE diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index be92afffb898..010cba770ce2 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -85,6 +85,7 @@ #include "unit_test.dm" #include "spawn_humans.dm" #include "check_runtimes.dm" +#include "wj_emotes.dm" #undef TEST_ASSERT #undef TEST_ASSERT_EQUAL diff --git a/code/modules/unit_tests/wj_emotes.dm b/code/modules/unit_tests/wj_emotes.dm new file mode 100644 index 000000000000..f89757665011 --- /dev/null +++ b/code/modules/unit_tests/wj_emotes.dm @@ -0,0 +1,7 @@ +/// Test that all working joe emotes have a category +/datum/unit_test/wj_emotes + +/datum/unit_test/wj_emotes/Run() + for(var/datum/emote/living/carbon/human/synthetic/working_joe/emote as anything in subtypesof(/datum/emote/living/carbon/human/synthetic/working_joe)) + if(!initial(emote.category)) + TEST_FAIL("Emote [emote] did not have a category!") diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm index 38c95d93881d..0681b7df05ac 100644 --- a/code/modules/vehicles/vehicle.dm +++ b/code/modules/vehicles/vehicle.dm @@ -126,6 +126,27 @@ /obj/vehicle/attack_remote(mob/user as mob) return +/obj/vehicle/attack_alien(mob/living/carbon/xenomorph/attacking_xeno) + if(attacking_xeno.a_intent == INTENT_HELP) + return XENO_NO_DELAY_ACTION + + if(attacking_xeno.mob_size < MOB_SIZE_XENO) + to_chat(attacking_xeno, SPAN_XENOWARNING("You're too small to do any significant damage to this vehicle!")) + return XENO_NO_DELAY_ACTION + + attacking_xeno.animation_attack_on(src) + + attacking_xeno.visible_message(SPAN_DANGER("[attacking_xeno] slashes [src]!"), SPAN_DANGER("You slash [src]!")) + playsound(attacking_xeno, pick('sound/effects/metalhit.ogg', 'sound/weapons/alien_claw_metal1.ogg', 'sound/weapons/alien_claw_metal2.ogg', 'sound/weapons/alien_claw_metal3.ogg'), 25, 1) + + var/damage = (attacking_xeno.melee_vehicle_damage + rand(-5,5)) * brute_dam_coeff + + health -= damage + + healthcheck() + + return XENO_NONCOMBAT_ACTION + //------------------------------------------- // Vehicle procs //------------------------------------------- diff --git a/colonialmarines.dme b/colonialmarines.dme index 9feb76faf408..304d5221ddd3 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -31,6 +31,7 @@ #include "code\__DEFINES\_tick.dm" #include "code\__DEFINES\access.dm" #include "code\__DEFINES\admin.dm" +#include "code\__DEFINES\ARES.dm" #include "code\__DEFINES\atmospherics.dm" #include "code\__DEFINES\autolathe.dm" #include "code\__DEFINES\blood.dm" @@ -110,6 +111,7 @@ #include "code\__DEFINES\vv.dm" #include "code\__DEFINES\weapon_stats.dm" #include "code\__DEFINES\weather.dm" +#include "code\__DEFINES\wj_emotes.dm" #include "code\__DEFINES\xeno.dm" #include "code\__DEFINES\dcs\flags.dm" #include "code\__DEFINES\dcs\helpers.dm" @@ -240,6 +242,9 @@ #include "code\controllers\subsystem\htmlui.dm" #include "code\controllers\subsystem\human.dm" #include "code\controllers\subsystem\inactivity.dm" +#include "code\controllers\subsystem\influxdriver.dm" +#include "code\controllers\subsystem\influxmcstats.dm" +#include "code\controllers\subsystem\influxstats.dm" #include "code\controllers\subsystem\input.dm" #include "code\controllers\subsystem\interior.dm" #include "code\controllers\subsystem\item_cleanup.dm" @@ -366,6 +371,7 @@ #include "code\datums\components\speed_modifier.dm" #include "code\datums\components\toxin_buildup.dm" #include "code\datums\components\weed_damage_reduction.dm" +#include "code\datums\components\weed_food.dm" #include "code\datums\components\xeno\shield_slash.dm" #include "code\datums\construction\construction_template.dm" #include "code\datums\construction\xenomorph\construction_template_xenomorph.dm" @@ -774,6 +780,10 @@ #include "code\game\machinery\teleporter.dm" #include "code\game\machinery\washing_machine.dm" #include "code\game\machinery\weather_siren.dm" +#include "code\game\machinery\ARES\ARES.dm" +#include "code\game\machinery\ARES\ARES_procs.dm" +#include "code\game\machinery\ARES\ARES_records.dm" +#include "code\game\machinery\ARES\ARES_step_triggers.dm" #include "code\game\machinery\atmoalter\canister.dm" #include "code\game\machinery\atmoalter\meter.dm" #include "code\game\machinery\atmoalter\portable_atmospherics.dm" @@ -1382,6 +1392,7 @@ #include "code\modules\asset_cache\assets\tgui.dm" #include "code\modules\asset_cache\assets\vending.dm" #include "code\modules\asset_cache\transports\asset_transport.dm" +#include "code\modules\asset_cache\transports\webroot_transport.dm" #include "code\modules\buildmode\bm-mode.dm" #include "code\modules\buildmode\buildmode.dm" #include "code\modules\buildmode\buttons.dm" @@ -1555,6 +1566,7 @@ #include "code\modules\cm_tech\techs\marine\tier1\points.dm" #include "code\modules\cm_tech\techs\marine\tier2\orbital_ammo.dm" #include "code\modules\cm_tech\techs\marine\tier3\cryorine.dm" +#include "code\modules\cm_tech\techs\marine\tier4\nuke.dm" #include "code\modules\cm_tech\trees\marine.dm" #include "code\modules\customitems\item_spawning.dm" #include "code\modules\decorators\admin_runtime_decorator.dm" @@ -1770,7 +1782,6 @@ #include "code\modules\mob\living\carbon\human\powers\human_powers.dm" #include "code\modules\mob\living\carbon\human\powers\issue_order.dm" #include "code\modules\mob\living\carbon\human\species\emote-monkey.dm" -#include "code\modules\mob\living\carbon\human\species\emote-synthetic.dm" #include "code\modules\mob\living\carbon\human\species\emote-yautja.dm" #include "code\modules\mob\living\carbon\human\species\human.dm" #include "code\modules\mob\living\carbon\human\species\monkey.dm" @@ -1778,6 +1789,16 @@ #include "code\modules\mob\living\carbon\human\species\synthetic.dm" #include "code\modules\mob\living\carbon\human\species\yautja.dm" #include "code\modules\mob\living\carbon\human\species\zombie.dm" +#include "code\modules\mob\living\carbon\human\species\working_joe\_emote.dm" +#include "code\modules\mob\living\carbon\human\species\working_joe\_species.dm" +#include "code\modules\mob\living\carbon\human\species\working_joe\farewell.dm" +#include "code\modules\mob\living\carbon\human\species\working_joe\greeting.dm" +#include "code\modules\mob\living\carbon\human\species\working_joe\notice.dm" +#include "code\modules\mob\living\carbon\human\species\working_joe\question.dm" +#include "code\modules\mob\living\carbon\human\species\working_joe\quip.dm" +#include "code\modules\mob\living\carbon\human\species\working_joe\restricted_area.dm" +#include "code\modules\mob\living\carbon\human\species\working_joe\task_update.dm" +#include "code\modules\mob\living\carbon\human\species\working_joe\warning.dm" #include "code\modules\mob\living\carbon\xenomorph\Abilities.dm" #include "code\modules\mob\living\carbon\xenomorph\attack_alien.dm" #include "code\modules\mob\living\carbon\xenomorph\damage_procs.dm" diff --git a/config/example/resources.txt b/config/example/resources.txt new file mode 100644 index 000000000000..0f9aaf021aa5 --- /dev/null +++ b/config/example/resources.txt @@ -0,0 +1,40 @@ +# External resources +# Set this to the location of a .zip with the server's .rsc inside of it. +# If you set this mutiple times, the server will rotate between the links. +# To use this, the compile option PRELOAD_RSC must be set to 0 to keep byond from preloading resources +# Resource urls can not be encrypted (https://), as they are downloaded by byond, not IE, and byond can't into encryption + +EXTERNAL_RSC_URLS http://rsc.cm-ss13.com/ + + +######################## +# Browser Asset Config # +######################## +# Browser assets are any file included in interfaces. css, images, javascript, etc. +# This handles configuring how we get these to the player so interfaces can access them. + +# Asset Transport +# The normal way of getting assets to clients is to use the internal byond system. This can be slow and delay the opening of interface windows. It also doesn't allow the internal IE windows byond uses to cache anything. +# You can instead have the server save them to a website via a folder within the game server that the web server can read. This could be a simple webserver or something backed by a CDN. +# Valid values: simple, webroot. Simple is the default. +#ASSET_TRANSPORT webroot + + +# Simple asset transport configurable values. + +# Uncomment this to have the server passively send all browser assets to each client in the background. (instead of waiting for them to be needed) +# This should be uncommented in production and commented in development +#ASSET_SIMPLE_PRELOAD + + +# Webroot asset transport configurable values. + +# Local folder to save assets to. +# Assets will be saved in the format of asset.MD5HASH.EXT or in namespaces/hash/ as ASSET_FILE_NAME or asset.MD5HASH.EXT +#ASSET_CDN_WEBROOT data/asset-store/ + +# URL the folder from above can be accessed from. +# for best results the webserver powering this should return a long cache validity time, as all assets sent via this transport use hash based urls +# Encryption (https) is supported here, but linux clients will have issues if you require higher then tls 1.0. Windows clients down to windows 7 can handle tls 1.2 no issue. +# if you want to test this locally, you simpily run the `localhost-asset-webroot-server.py` python3 script to host assets stored in `data/asset-store/` via http://localhost:58715/ +#ASSET_CDN_URL http://localhost:58715/ diff --git a/html/changelogs/AutoChangeLog-pr-3801.yml b/html/changelogs/AutoChangeLog-pr-3801.yml new file mode 100644 index 000000000000..5b7e82c62f86 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3801.yml @@ -0,0 +1,4 @@ +author: "Morrow" +delete-after: True +changes: + - balance: "Marines called with foxtrot nerfed from 15 to 10." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3804.yml b/html/changelogs/AutoChangeLog-pr-3804.yml new file mode 100644 index 000000000000..64342db7b1e4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3804.yml @@ -0,0 +1,4 @@ +author: "Steelpoint" +delete-after: True +changes: + - balance: "Synthetic Armour slowdown has been decreased" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3809.yml b/html/changelogs/AutoChangeLog-pr-3809.yml new file mode 100644 index 000000000000..e86a6dd7146b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3809.yml @@ -0,0 +1,4 @@ +author: "SpartanBobby" +delete-after: True +changes: + - balance: "reduces the M1911 magazine size from 14 to 7" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3810.yml b/html/changelogs/AutoChangeLog-pr-3810.yml new file mode 100644 index 000000000000..1ad038db0f7b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3810.yml @@ -0,0 +1,4 @@ +author: "Morrow" +delete-after: True +changes: + - bugfix: "Stops xenos from bypassing dead moving via roller beds" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3811.yml b/html/changelogs/AutoChangeLog-pr-3811.yml new file mode 100644 index 000000000000..7c54d0e2b52e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3811.yml @@ -0,0 +1,4 @@ +author: "Morrow" +delete-after: True +changes: + - balance: "Telebaton now scales in stunforce effectiveness based on policing skill" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3834.yml b/html/changelogs/AutoChangeLog-pr-3834.yml new file mode 100644 index 000000000000..1ab9c5a6e98a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3834.yml @@ -0,0 +1,4 @@ +author: "SpartanBobby" +delete-after: True +changes: + - maptweak: "LV522: Flips the layout of engineering making the T-comms unit on the far side of the LZ" \ No newline at end of file diff --git a/html/changelogs/archive/2023-06.yml b/html/changelogs/archive/2023-06.yml index c056049b84ed..e2d9dfed44d7 100644 --- a/html/changelogs/archive/2023-06.yml +++ b/html/changelogs/archive/2023-06.yml @@ -288,3 +288,157 @@ - bugfix: folding barricade now blocks pounces from behind. - qol: collapsing folding barricade by hand is no longer interrupted by taking an item. +2023-06-20: + Morrow: + - balance: Xenos can slash trolleys now + - balance: Generators can no longer be blown up + - balance: Bonus evolution slowly deteriorates over time when all castes are unlocked + - balance: Portable Generators can now be turned off/unanchored by xeno slashes +2023-06-21: + BeagleGaming1: + - rscadd: Melting flares makes the flares burn out faster, instead of melting like + normal + - balance: Flares last ~10 mins, and flares in the air last ~5 mins + Morrow: + - rscadd: Re-added the nuke that you can buy via intel at tier 4. Only purchasable + past 120 minutes. Requires holding both groundside comms towers for authorization + decryption before being able to be armed. + TheGamerdk: + - bugfix: Forsaken no longer announce themselves as a distress signal +2023-06-22: + Al-1ce: + - rscadd: Adds various magazines and a crayon to loadout selection. + Drathek Firartix: + - bugfix: Fixed a crash with hijack code possibly picking a non-existent brig area, + and weighting smaller areas heavier. + Morrow: + - bugfix: Flashlight gun attachments turn off when they should + sg2002: + - bugfix: XM88 now correctly notifies the user on the hit streak end. +2023-06-23: + harryob: + - server: server's can now support using a cdn for web assets +2023-06-24: + Drathek: + - rscadd: The selection to become a xeno larva is now based on timeofdeath rather + than random and also sends a message to all candidates when the queue moves. + Playing as a facehugger or on admin z-levels (thunderdome) will not affect your + relative place in queue. The join xeno action will also display the last queue + message for you when you allow xeno candidacy. + - bugfix: Fixed gibbed humans not properly setting their timeofdeath when on an + admin z-level. + - bugfix: Fixed a bad del on shuttle doors when a shuttle deletes (such as intoTheSunset). + - bugfix: Fixed erroneous is empty messages when inserting tanks into a flamer pack. + - soundadd: Added the refill sfx when using the empty canister verb on flamer tanks. + Morrow: + - bugfix: Prevented some light bugs with devouring marines + - bugfix: Fixed two gun light attachment issues + Steelpoint: + - rscadd: Synthetics may now vend Ponchos. + realforest2001: + - admin: Improves logging for admin deadchat. + - admin: Adds logging for xeno evolution. + theselfish: + - qol: Added the Corpsman Helmet to Req's surplus vendor. +2023-06-25: + Sargeantmuffinman: + - rscadd: Added two new emails to the Almayer's personal computers and rewrote 3 + other emails. + Segrain: + - bugfix: Hive core now always correctly absorbs hive's dead larvas. + - bugfix: Preview dummy in character setup once again can be rotated. +2023-06-26: + Drathek: + - bugfix: Fixed the yank object verb not testing who is actually performing the + action has a free hand + - rscadd: Player facehugging gets 2nd dibs on the burst (the original marine gets + first dibs still) + - bugfix: Fix a possibility of banished larva refunding double the larva + blackdragonTOW: + - spellcheck: multiple typos and grammar changes in the round start tooltips. +2023-06-27: + TeDGamer Drathek: + - bugfix: Boilers from other hives generate proper colored IFFed gas + - bugfix: Fixes some death causes with boiler acid gas (for bombard, shroud, and + gibbing), neurotoxin gas/stabs, acid shotgun, and xeno spits + - balance: Neurotoxin stops processing only in dead mobs + TheGamerdk: + - bugfix: The game will no longer falsely claim there is no CO + realforest2001: + - rscadd: Changed min and max Predator ages from 20 - 10000 to 175 - 3000 +2023-06-28: + Drathek: + - admin: Mentors can now eavesdrop on mentor messages, and the responder to a mhelp + doesn't get double logging from eavesdropping. + Morrow, Thwomper: + - rscadd: Added three new uniforms and a snow jacket for the CL. + TheGamerdk: + - balance: Cluster OBs will now no longer hit turfs that have gotten OB protection + after the initial OB was fired. + ihatethisengine: + - balance: larva surge is limited by marines/xenos ratio + - bugfix: xenos no longer get free larva from abandoned facehuggers during hijack + - balance: explosive barricade upgrade provides better protection against explosions + (25% to 50%) + - balance: explosive barricade upgrade provides strong protection against brute-based + projectiles (50%) + - balance: explosive barricade upgrade provides strong protection against fire (50%) +2023-06-29: + Diegoflores31: + - balance: reduced Larva Burst time from 10 minutes to 7.5 minutes + - refactor: changed 1 letter vars. + Drathek: + - bugfix: Fixed the crashsite offset for a hijack shuttle that gets deterred by + the MGAD System + IowaPotatoFarmer: + - rscadd: Solaris Ridge now has a Corporate Liaison survivor. + Katskan: + - balance: Removed G8A storage from various snow suits and parkas + Morrow: + - balance: Xenos no longer can pull dead xenos + - rscdel: Removed toxin mags on shivas + SpartanBobby: + - maptweak: Minor decal changes to LV522 + - maptweak: Buffed sec armory on LV522 + - maptweak: LV522 Breaching charge moved to the PROP APC made UNACIDABLE + TheGamerdk: + - bugfix: Communications intel objective now actually works + - balance: Queen boosted building no longer has 2 second cooldown when far from + hive + blackdragonTOW: + - maptweak: Added a small light to unlit rooms. + fira: + - bugfix: Fixed a MC crash related to NPC huggers rebounding logic. + realforest2001: + - rscadd: Added an admin button for an ARES bioscan. Slightly refactored how Bioscans + trigger for marines, relying on an ARES processor. + - rscadd: Added individual proccessors for ARES systems. These are WIP and will + eventually have damage and repair interactions. + - rscadd: Added an ARES interaction console in the AI Core room, which holds logs + for most ARES functions. + - rscadd: Added the ability for ARES console to call ERT or Distress. + - rscadd: Added motion triggers in ARES core and shipside comms that send alerts + over Apollo. + - rscadd: Added a 1to1 conversation feature between ARES and users of the interface + console. + - rscadd: Added preset open versions of blended poddoors. + - rscadd: Added a console for directing Working Joes. This is largely WIP for future + PR(s). + - rscadd: Added subtypes of air pipes that don't explode on hijack, used these in + ARES core. + - maptweak: Remodelled ARES Core onto a fake-z, and added the new processors. + - bugfix: door_control buttons now respect being indestructable when processing + explosions. + - maptweak: Fixed the M39s overflowing in brig armory due to use of landmarks. +2023-06-30: + Drathek: + - bugfix: Fix runtimes with minimap subsystem not handling targets inside of objects + during removal + - code_imp: Ported VERB_REF and TYPE_VERB_REF from TG for 515 compatibility + - code_imp: Removed unnecessary calculations when updating a mob's transform. + Morrow: + - rscdel: Removed wrong warden locker + TheGamerdk: + - bugfix: You can now re-enter your body when unnested, marine mains, rejoice! + - bugfix: Lurkers no longer lose their pounce if they happen to end their pounce + on a tile with a dead human diff --git a/html/changelogs/archive/2023-07.yml b/html/changelogs/archive/2023-07.yml new file mode 100644 index 000000000000..ec61abf15d10 --- /dev/null +++ b/html/changelogs/archive/2023-07.yml @@ -0,0 +1,140 @@ +2023-07-01: + Ben10083: + - bugfix: lisps now occur over radio as well + - refactor: Relevant variables relating to speech problems now use true and false + instead of 1 and 0 + - bugfix: fixes exploit relating to cloaking tarps by adding a delay before tarp + can be closed again. + Drathek: + - bugfix: Fixed missing xeno ban check for playing as a facehugger + - spellcheck: Tweaked message when ghosting while nested + TheGamerdk: + - rscadd: ARES will announce how many Foxtrot marines that woke up. + harryob: + - rscadd: you can no longer implant yourself with a motion detector + ihatethisengine: + - rscadd: Added cameras to dropship deployable sentries. +2023-07-02: + Clairion: + - bugfix: Vampire Lurker headbite will no longer trigger if the target is moved + away during windup. + Cthulhu80: + - rscadd: added camera shake and stun to OB. + fira: + - rscadd: Added InfluxDB backed metrics logging for some of the most used game statistics. + This will allow to graph them over time and give better insight as to what happens + in rounds. + theselfish: + - qol: Made the MP beret to be clickable. + - imageadd: Updated the MP beret obj sprite to be easier to click. +2023-07-03: + blackdragonTOW: + - refactor: refactored dropship_ammo so that missiles don't use Spawn() + ghostsheet: + - bugfix: Fixed Extended Barrel bug of building up free bullet velocity. +2023-07-04: + Drathek: + - bugfix: Fixed a persistence problem for the time of death value used for the larva + queue. + - bugfix: Fixed brainmobs (human gibbing) not getting a time of death value. + harryob: + - bugfix: paper images should appear once again + zzzmike: + - balance: pods crash land 33% of the time rather than 50% +2023-07-05: + BeagleGaming1: + - rscadd: Queen makes noise when moved even while resting + Hopek, Gul Dreggrod: + - rscadd: Adds a Luxurious fountain pen to the game. Currently spawns on the right + ear of high ranking command staff. Sprited by Gul Dreggrod. + QuickLode: + - rscadd: CMB/ICC Survivors now get a limited radio that they can use to communicate + with CMB reinforcements. + - rscadd: CMB/Anchorpoint Marines get bandages to stop bleeding. + harryob: + - rscadd: all xenos can now access the tacmap, while the queen is on ovi +2023-07-06: + BeagleGaming1: + - code_imp: evacuation pod crash chance changed to a var + - code_imp: proc added to force evacuation pods to crash + Drathek: + - bugfix: Fixed more broken logos (primarily WY research papers) + - balance: Weed nodes can no longer be placed in walls or window frames (or any + turf or structure with density) + - refactor: Refactored the plant weeds ability code + - balance: Gardener's hardy weeds now upgrade normal weeds (just like hive weeds + upgrade weeds). + - balance: Gardener's hardy weeds now don't prevent special structures (core and + pylons) but they are still only allowed if the turf allows them. + Newyearnewme, Morrow: + - rscadd: Xeno structures/weeds now become forsaken after hijack + Steelpoint: + - imageadd: Synth utility vest is now slimmer in appearance + realforest2001: + - admin: Adds logs for bioscans successfully completing. + thatoneyeeter: + - balance: metal foam now becomes solid faster +2023-07-07: + Diegoflores31: + - rscadd: Defender Tail Slam has a 1% chance to do a BONK sound instead. + Drathek: + - bugfix: Fixed ghost icons for larva and ovi queen + Morrow: + - rscdel: Removes fountain pens from gear sets + - rscdel: Removed nesting the dead + - rscadd: Added a visiting USASF Commander (CO survivor) to New Varadero + - bugfix: Burnt matches no longer permanently give you a light source if they naturally + burn out + QuickLoad: + - balance: Colony Synthetics are faster but are less resistant. This allows for + the option of avoiding engagements. + - balance: Colony Synthetics have slightly better CQC and can carry people better. + realforest2001: + - bugfix: Fixes Queen making footstep sounds while dead and being dragged. +2023-07-08: + Ben10083: + - bugfix: Working Joes can no longer have a gradient on their rare hair spawn. + - rscdel: Working Joes can no longer be fed. + - code_imp: 'New trait: Cannot eat. Self-explanatory.' + Cursor: + - spellcheck: Changed Chem Dispenser to Chemical Dispenser, added descriptions to + the cryo cell, rail computer and chemical dispenser. Updated the descriptions + for the Blood Dispenser and Dropship computer. + Drathek: + - bugfix: Fixed facehuggers incorrectly displaying thrown state when it has landed + Drathek Kugamo: + - rscadd: Added the ability for weeds to merge with unrevivable corpses + - imageadd: Added human shaped weeds by Kugamo + - code_imp: Added a signal for weeds sent to the turf to indicate it is now weeded, + and added a signal for afterbuckle. + - bugfix: Closets (including coffins) can no longer move anchored mobs. + Morrow: + - qol: Create humans tab length increase + - qol: Create humans tab now defaults to 0 range to spawn + - bugfix: Fixed extraneous messages in regards to wall nests + SpartanBobby: + - balance: changes M4A3 magazine size from 9 to 12 + Zonespace27: + - bugfix: The maintenance jack should work a little better at crowbarring things. +2023-07-09: + Khadd: + - rscadd: added a iv tube between the user and the bloodpack / iv drip + - imageadd: sprites for the iv tube + Zonespace27: + - rscadd: Working Joes now have an emote panel to use voice lines, accessible as + an action button. + theselfish: + - qol: Foxtrot's radio channel is now on if you have multi-squad in your headset. +2023-07-10: + BeagleGaming1: + - rscadd: Acid runners don't get acid from slashing nested humans + - rscadd: Very late-stage marines do not give acid + - bugfix: Fixes one way of abusing resin fruit + Drathek: + - rscdel: Remove first life priority for larva queue + - bugfix: Fix ghosting as a facehugger counting as death for the larva queue + blackdragonTOW: + - spellcheck: Added "U1" designation to the UGL attachment. +2023-07-11: + BeagleGaming1: + - bugfix: Fixes the Working Joe species diff --git a/html/create_humans.html b/html/create_humans.html index ed9361fc6f25..06b92cba0c71 100644 --- a/html/create_humans.html +++ b/html/create_humans.html @@ -11,7 +11,7 @@ Amount of humans:
- Range to spawn in: + Range to spawn in:

Spawn mobs as:
Regular
diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index 704c0ad1c02c..d6ee40cf7fe8 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ diff --git a/icons/effects/techtree/tech.dmi b/icons/effects/techtree/tech.dmi index a255a0d0e544..d88106f82d11 100644 Binary files a/icons/effects/techtree/tech.dmi and b/icons/effects/techtree/tech.dmi differ diff --git a/icons/mob/hud/actions.dmi b/icons/mob/hud/actions.dmi index 1692879116dc..4d0697733207 100644 Binary files a/icons/mob/hud/actions.dmi and b/icons/mob/hud/actions.dmi differ diff --git a/icons/mob/humans/onmob/helmet_garb.dmi b/icons/mob/humans/onmob/helmet_garb.dmi index 10d988b153dd..3bb63088783f 100644 Binary files a/icons/mob/humans/onmob/helmet_garb.dmi and b/icons/mob/humans/onmob/helmet_garb.dmi differ diff --git a/icons/mob/humans/onmob/suit_0.dmi b/icons/mob/humans/onmob/suit_0.dmi index 4d63b7abd7f1..5cccc4c2e0e0 100644 Binary files a/icons/mob/humans/onmob/suit_0.dmi and b/icons/mob/humans/onmob/suit_0.dmi differ diff --git a/icons/mob/humans/onmob/suit_1.dmi b/icons/mob/humans/onmob/suit_1.dmi index c17f403d99ce..39a91e225039 100644 Binary files a/icons/mob/humans/onmob/suit_1.dmi and b/icons/mob/humans/onmob/suit_1.dmi differ diff --git a/icons/mob/humans/onmob/uniform_0.dmi b/icons/mob/humans/onmob/uniform_0.dmi index 4973a59a69c4..cac9869c9034 100644 Binary files a/icons/mob/humans/onmob/uniform_0.dmi and b/icons/mob/humans/onmob/uniform_0.dmi differ diff --git a/icons/mob/xenos/weeds.dmi b/icons/mob/xenos/weeds.dmi index 8eb4b2203cf6..0b9403058109 100644 Binary files a/icons/mob/xenos/weeds.dmi and b/icons/mob/xenos/weeds.dmi differ diff --git a/icons/obj/items/clothing/cm_hats.dmi b/icons/obj/items/clothing/cm_hats.dmi index 33f600015a6f..7f798c2cd0bc 100644 Binary files a/icons/obj/items/clothing/cm_hats.dmi and b/icons/obj/items/clothing/cm_hats.dmi differ diff --git a/icons/obj/items/clothing/suits.dmi b/icons/obj/items/clothing/suits.dmi index 47d06bc2cc10..cff4b5d48c17 100644 Binary files a/icons/obj/items/clothing/suits.dmi and b/icons/obj/items/clothing/suits.dmi differ diff --git a/icons/obj/items/clothing/uniforms.dmi b/icons/obj/items/clothing/uniforms.dmi index 132f193fbf40..254c9e8b67c9 100644 Binary files a/icons/obj/items/clothing/uniforms.dmi and b/icons/obj/items/clothing/uniforms.dmi differ diff --git a/icons/obj/items/paper.dmi b/icons/obj/items/paper.dmi index 3589d5a1b4c2..d0c918a65e59 100644 Binary files a/icons/obj/items/paper.dmi and b/icons/obj/items/paper.dmi differ diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi index 08a5c5fa8ef1..b62860559b16 100644 Binary files a/icons/obj/objects.dmi and b/icons/obj/objects.dmi differ diff --git a/icons/obj/structures/machinery/ares.dmi b/icons/obj/structures/machinery/ares.dmi new file mode 100644 index 000000000000..77dd304310f6 Binary files /dev/null and b/icons/obj/structures/machinery/ares.dmi differ diff --git a/maps/bigredv2.json b/maps/bigredv2.json index ecb2e1472c57..0a6db01cd498 100644 --- a/maps/bigredv2.json +++ b/maps/bigredv2.json @@ -12,6 +12,7 @@ "/datum/equipment_preset/survivor/trucker/solaris", "/datum/equipment_preset/survivor/security/solaris", "/datum/equipment_preset/survivor/colonial_marshal/solaris", + "/datum/equipment_preset/survivor/corporate/solaris", "/datum/equipment_preset/survivor/clf", "/datum/equipment_preset/survivor/civilian" ], diff --git a/maps/map_files/Ice_Colony_v3/Shivas_Snowball.dmm b/maps/map_files/Ice_Colony_v3/Shivas_Snowball.dmm index 1d24ec567968..674cce91ba63 100644 --- a/maps/map_files/Ice_Colony_v3/Shivas_Snowball.dmm +++ b/maps/map_files/Ice_Colony_v3/Shivas_Snowball.dmm @@ -8762,8 +8762,6 @@ "cSn" = ( /obj/structure/closet/secure_closet/guncabinet, /obj/item/weapon/gun/rifle/m41aMK1, -/obj/item/ammo_magazine/rifle/m41aMK1/toxin, -/obj/item/ammo_magazine/rifle/m41aMK1/toxin, /obj/item/ammo_magazine/rifle/m41aMK1, /obj/item/ammo_magazine/rifle/m41aMK1, /obj/item/ammo_magazine/rifle/m41aMK1, @@ -19747,7 +19745,6 @@ pixel_x = -10; pixel_y = 13 }, -/obj/item/ammo_magazine/rifle/toxin, /turf/open/asphalt/cement, /area/shiva/interior/warehouse) "oYw" = ( @@ -21979,7 +21976,6 @@ /area/shiva/interior/colony/research_hab) "ril" = ( /obj/structure/closet/secure_closet/freezer/fridge, -/obj/item/ammo_magazine/rifle/m41aMK1/toxin, /turf/open/floor/shiva{ icon_state = "multi_tiles" }, @@ -24859,7 +24855,6 @@ }, /area/shiva/interior/colony/medseceng) "ukJ" = ( -/obj/item/ammo_magazine/rifle/m41aMK1/toxin, /turf/open/floor/shiva, /area/shiva/interior/colony/research_hab) "ukU" = ( diff --git a/maps/map_files/LV522_Chances_Claim/LV522_Chances_Claim.dmm b/maps/map_files/LV522_Chances_Claim/LV522_Chances_Claim.dmm index 01df2b7e136e..cb5f023d59fa 100644 --- a/maps/map_files/LV522_Chances_Claim/LV522_Chances_Claim.dmm +++ b/maps/map_files/LV522_Chances_Claim/LV522_Chances_Claim.dmm @@ -998,8 +998,8 @@ /obj/structure/closet/crate/weapon, /obj/item/weapon/gun/rifle/l42a, /obj/item/weapon/gun/rifle/l42a, -/obj/item/ammo_magazine/rifle/l42a, -/obj/item/ammo_magazine/rifle/l42a, +/obj/item/weapon/gun/rifle/l42a, +/obj/item/weapon/gun/rifle/l42a, /turf/open/floor/prison, /area/lv522/indoors/a_block/security) "aIp" = ( @@ -2334,13 +2334,11 @@ }, /area/lv522/oob) "bzL" = ( -/obj/structure/machinery/space_heater/radiator/red{ - dir = 4 - }, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" +/obj/structure/machinery/camera/autoname, +/obj/structure/machinery/light/small{ + dir = 1 }, +/turf/open/floor/plating, /area/lv522/indoors/lone_buildings/engineering) "bAc" = ( /obj/structure/filingcabinet/seeds{ @@ -3443,10 +3441,11 @@ /turf/open/asphalt/cement, /area/lv522/outdoors/colony_streets/east_central_street) "cfd" = ( -/obj/structure/surface/table/almayer, -/obj/structure/machinery/recharger, -/obj/effect/spawner/random/powercell, -/turf/open/floor/prison, +/obj/structure/closet/wardrobe/engineering_yellow, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, /area/lv522/indoors/lone_buildings/engineering) "cfg" = ( /obj/item/clothing/head/hardhat/white, @@ -3568,13 +3567,6 @@ }, /turf/open/auto_turf/shale/layer1, /area/lv522/landing_zone_2) -"cjf" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" - }, -/area/lv522/indoors/lone_buildings/engineering) "cjv" = ( /obj/structure/bed/chair/comfy{ dir = 4 @@ -4661,12 +4653,11 @@ /turf/open/floor/corsat, /area/lv522/atmos/east_reactor/west) "cKF" = ( -/obj/structure/cargo_container/kelland/left, /obj/item/explosive/plastic/breaching_charge{ - layer = 5 + unacidable = 1 }, /turf/open/auto_turf/shale/layer0, -/area/lv522/outdoors/colony_streets/east_central_street) +/area/lv522/outdoors/n_rockies) "cKG" = ( /turf/closed/wall/strata_ice/dirty, /area/lv522/outdoors/nw_rockies) @@ -4785,6 +4776,12 @@ }, /turf/open/floor/corsat, /area/lv522/atmos/east_reactor) +"cNO" = ( +/obj/structure/machinery/colony_floodlight_switch{ + pixel_y = 30 + }, +/turf/open/floor/plating, +/area/lv522/indoors/lone_buildings/engineering) "cNQ" = ( /turf/open/floor/corsat{ dir = 8; @@ -7763,7 +7760,8 @@ }, /area/lv522/oob) "ebR" = ( -/obj/structure/closet/secure_closet/engineering_welding, +/obj/structure/surface/table/almayer, +/obj/effect/landmark/objective_landmark/close, /turf/open/floor/prison{ dir = 4; icon_state = "darkyellowfull2" @@ -8355,7 +8353,7 @@ /turf/open/floor/corsat{ icon_state = "marked" }, -/area/lv522/atmos/east_reactor/east) +/area/lv522/oob) "eow" = ( /obj/structure/tunnel{ pixel_x = 2; @@ -9745,6 +9743,21 @@ icon_state = "plate" }, /area/lv522/atmos/east_reactor/east) +"eWF" = ( +/obj/effect/decal/cleanable/dirt, +/obj/item/storage/firstaid/adv{ + layer = 3.1; + pixel_x = 3; + pixel_y = -2 + }, +/obj/structure/surface/rack, +/obj/item/storage/firstaid/adv{ + pixel_y = 14 + }, +/turf/open/floor/prison{ + icon_state = "darkredfull2" + }, +/area/lv522/indoors/a_block/security) "eWK" = ( /obj/structure/pipes/standard/manifold/hidden/green{ dir = 4 @@ -9799,6 +9812,18 @@ }, /turf/open/auto_turf/shale/layer1, /area/lv522/outdoors/nw_rockies) +"eXU" = ( +/obj/structure/machinery/power/terminal, +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, +/turf/open/floor/plating, +/area/lv522/indoors/lone_buildings/engineering) "eXV" = ( /obj/structure/cargo_container/horizontal/blue/bottom{ pixel_x = 16 @@ -10337,6 +10362,17 @@ icon_state = "blue_plate" }, /area/lv522/indoors/a_block/admin) +"flC" = ( +/obj/structure/machinery/light/small, +/obj/structure/machinery/camera/autoname{ + dir = 1; + network = list("interrogation") + }, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, +/area/lv522/indoors/lone_buildings/engineering) "flI" = ( /obj/structure/surface/table/woodentable/fancy, /obj/item/ashtray/bronze{ @@ -10683,6 +10719,12 @@ /obj/item/prop/colony/used_flare, /turf/open/floor/prison, /area/lv522/indoors/a_block/dorms) +"fuw" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "W" + }, +/turf/open/auto_turf/shale/layer0, +/area/lv522/outdoors/colony_streets/north_west_street) "fuQ" = ( /obj/structure/pipes/standard/manifold/hidden/green{ dir = 1 @@ -11072,9 +11114,9 @@ icon_state = "gib6" }, /turf/open/asphalt/cement{ - icon_state = "cement12" + icon_state = "cement4" }, -/area/lv522/outdoors/colony_streets/south_west_street) +/area/lv522/outdoors/colony_streets/central_streets) "fCW" = ( /turf/open/floor/prison{ icon_state = "darkbrownfull2" @@ -11725,10 +11767,16 @@ }, /area/lv522/indoors/a_block/dorms) "fSv" = ( -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" +/obj/structure/surface/table/almayer, +/obj/item/clothing/head/beret/eng, +/obj/item/ammo_box/magazine/nailgun/empty{ + pixel_x = -6; + pixel_y = 12 + }, +/obj/structure/pipes/standard/simple/hidden/green{ + dir = 9 }, +/turf/open/floor/prison, /area/lv522/indoors/lone_buildings/engineering) "fSR" = ( /obj/structure/surface/table/almayer, @@ -12176,6 +12224,12 @@ }, /turf/open/floor/carpet, /area/lv522/indoors/a_block/executive) +"gcX" = ( +/obj/structure/window_frame/strata/reinforced, +/turf/open/floor/corsat{ + icon_state = "marked" + }, +/area/lv522/indoors/lone_buildings/engineering) "gcY" = ( /obj/structure/cargo_container/ferret/left, /turf/open/auto_turf/shale/layer0, @@ -13641,6 +13695,7 @@ "gLV" = ( /obj/structure/prop/server_equipment/yutani_server/broken{ density = 0; + layer = 3.5; pixel_y = 16 }, /obj/effect/decal/cleanable/dirt, @@ -13746,10 +13801,9 @@ /area/lv522/atmos/east_reactor) "gOC" = ( /obj/structure/pipes/vents/pump, -/obj/structure/surface/rack, -/obj/item/weapon/shield/riot, -/obj/item/weapon/classic_baton, /obj/effect/decal/cleanable/dirt, +/obj/structure/surface/table/almayer, +/obj/item/ammo_box/magazine/shotgun/beanbag/empty, /turf/open/floor/prison{ icon_state = "darkredfull2" }, @@ -14008,7 +14062,7 @@ }, /area/lv522/atmos/east_reactor/east) "gUA" = ( -/obj/structure/machinery/recharge_station, +/obj/structure/closet/secure_closet/engineering_welding, /turf/open/floor/prison{ dir = 4; icon_state = "darkyellowfull2" @@ -14247,10 +14301,7 @@ }, /area/lv522/atmos/command_centre) "gZg" = ( -/obj/item/shard{ - icon_state = "medium" - }, -/obj/effect/decal/cleanable/dirt, +/obj/structure/closet/secure_closet/engineering_electrical, /turf/open/floor/prison{ dir = 4; icon_state = "darkyellowfull2" @@ -16905,6 +16956,10 @@ icon_state = "brown" }, /area/lv522/atmos/east_reactor) +"icy" = ( +/obj/item/prop/alien/hugger, +/turf/open/floor/prison, +/area/lv522/indoors/lone_buildings/engineering) "icE" = ( /obj/structure/pipes/standard/simple/hidden/green, /obj/effect/decal/cleanable/dirt, @@ -17920,11 +17975,17 @@ }, /area/lv522/indoors/a_block/corpo/glass) "izp" = ( -/obj/structure/machinery/power/smes/buildable{ - capacity = 1e+006; - dir = 1 +/obj/structure/surface/table/almayer, +/obj/item/clothing/glasses/meson, +/obj/item/shard{ + icon_state = "medium" + }, +/obj/effect/landmark/objective_landmark/close, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" }, -/turf/open/floor/plating, /area/lv522/indoors/lone_buildings/engineering) "izr" = ( /obj/structure/platform/stair_cut, @@ -19344,18 +19405,6 @@ icon_state = "browncorner" }, /area/lv522/atmos/east_reactor/south) -"jeo" = ( -/obj/structure/pipes/vents/pump, -/obj/effect/decal/cleanable/dirt, -/obj/structure/machinery/cm_vending/sorted/tech/electronics_storage{ - density = 0; - pixel_y = 16 - }, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" - }, -/area/lv522/indoors/lone_buildings/engineering) "jey" = ( /obj/effect/landmark/structure_spawner/setup/distress/xeno_weed_node, /obj/effect/landmark/structure_spawner/setup/distress/xeno_nest, @@ -19708,7 +19757,10 @@ /turf/open/floor/plating, /area/lv522/indoors/c_block/cargo) "jkL" = ( -/obj/structure/closet/secure_closet/engineering_electrical, +/obj/structure/machinery/recharge_station, +/obj/item/shard{ + icon_state = "medium" + }, /turf/open/floor/prison{ dir = 4; icon_state = "darkyellowfull2" @@ -19773,10 +19825,10 @@ }, /area/lv522/indoors/c_block/cargo) "jmd" = ( -/obj/item/weapon/shield/riot, -/obj/item/weapon/classic_baton, -/obj/structure/surface/rack, /obj/effect/decal/cleanable/dirt, +/obj/structure/surface/rack, +/obj/item/weapon/gun/revolver/cmb, +/obj/item/ammo_magazine/revolver/cmb, /turf/open/floor/prison{ icon_state = "darkredfull2" }, @@ -20728,13 +20780,13 @@ /turf/open/auto_turf/shale/layer1, /area/lv522/outdoors/colony_streets/north_west_street) "jGj" = ( -/obj/structure/surface/rack, -/obj/item/weapon/gun/revolver/cmb, -/obj/item/ammo_magazine/revolver/cmb, -/turf/open/floor/prison{ - icon_state = "darkredfull2" +/obj/effect/decal/cleanable/dirt, +/obj/item/maintenance_jack, +/turf/open/floor/strata{ + dir = 4; + icon_state = "white_cyan1" }, -/area/lv522/indoors/a_block/security) +/area/lv522/indoors/a_block/corpo) "jGm" = ( /obj/structure/barricade/handrail{ dir = 4 @@ -21193,13 +21245,6 @@ /obj/structure/reagent_dispensers/watertank, /turf/open/floor/plating/plating_catwalk/prison, /area/lv522/outdoors/nw_rockies) -"jPO" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/prison{ - dir = 10; - icon_state = "floor_marked" - }, -/area/lv522/indoors/lone_buildings/engineering) "jQa" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/prop/dam/crane{ @@ -21261,13 +21306,6 @@ icon_state = "darkpurplefull2" }, /area/lv522/indoors/a_block/dorms) -"jSG" = ( -/obj/effect/decal/cleanable/cobweb, -/turf/open/floor/prison{ - dir = 10; - icon_state = "floor_marked" - }, -/area/lv522/indoors/lone_buildings/engineering) "jSR" = ( /obj/structure/machinery/conveyor, /turf/open/floor/corsat{ @@ -21364,6 +21402,10 @@ }, /turf/closed/wall/mineral/bone_resin, /area/lv522/oob) +"jUg" = ( +/obj/item/ammo_box/magazine/l42a/ap/empty, +/turf/open/floor/prison, +/area/lv522/indoors/a_block/security) "jUk" = ( /turf/open/floor/prison{ dir = 10; @@ -21571,6 +21613,13 @@ icon_state = "brown" }, /area/lv522/atmos/east_reactor/south) +"jYy" = ( +/obj/structure/machinery/power/smes/buildable{ + capacity = 1e+006; + dir = 1 + }, +/turf/open/floor/plating, +/area/lv522/indoors/lone_buildings/engineering) "jYE" = ( /obj/structure/machinery/power/apc/weak{ dir = 1 @@ -21917,7 +21966,11 @@ }, /area/lv522/indoors/a_block/security) "kfi" = ( -/obj/structure/closet/toolcloset, +/obj/structure/surface/table/almayer, +/obj/effect/landmark/objective_landmark/close, +/obj/structure/extinguisher_cabinet{ + pixel_y = 30 + }, /turf/open/floor/prison{ dir = 4; icon_state = "darkyellowfull2" @@ -22373,6 +22426,13 @@ /obj/structure/platform_decoration{ dir = 4 }, +/obj/effect/decal/warning_stripes{ + icon_state = "S" + }, +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, /turf/open/floor/prison{ icon_state = "floor_plate" }, @@ -22455,6 +22515,14 @@ icon_state = "brown" }, /area/lv522/atmos/east_reactor/south) +"knT" = ( +/obj/structure/machinery/cm_vending/sorted/tech/tool_storage{ + density = 0; + pixel_x = -6; + pixel_y = 11 + }, +/turf/open/floor/prison, +/area/lv522/indoors/lone_buildings/engineering) "knW" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/machinery/camera/autoname{ @@ -23446,6 +23514,14 @@ icon_state = "floor_marked" }, /area/lv522/outdoors/colony_streets/north_west_street) +"kIs" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "NE-out"; + pixel_x = 1; + pixel_y = 1 + }, +/turf/open/floor/plating, +/area/lv522/indoors/lone_buildings/engineering) "kIM" = ( /obj/item/ammo_magazine/rifle/m4ra/ap{ current_rounds = 0 @@ -25126,6 +25202,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/prison, /area/lv522/indoors/a_block/dorms) +"lsG" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, +/turf/open/auto_turf/shale/layer0, +/area/lv522/outdoors/colony_streets/north_west_street) "lsR" = ( /obj/structure/fence{ layer = 2.9 @@ -25775,10 +25858,17 @@ }, /area/lv522/indoors/a_block/kitchen) "lHu" = ( -/obj/structure/machinery/power/terminal{ - dir = 1 +/obj/effect/decal/cleanable/dirt, +/obj/structure/machinery/disposal{ + density = 0; + layer = 3.1; + pixel_x = -6; + pixel_y = 16 }, -/turf/open/floor/plating, +/obj/structure/pipes/standard/simple/hidden/green{ + dir = 6 + }, +/turf/open/floor/plating/plating_catwalk/prison, /area/lv522/indoors/lone_buildings/engineering) "lHH" = ( /obj/effect/decal/cleanable/dirt, @@ -25826,9 +25916,6 @@ icon_state = "greenfull" }, /area/lv522/indoors/b_block/bridge) -"lIC" = ( -/turf/open/floor/prison, -/area/lv522/indoors/lone_buildings/engineering) "lIM" = ( /obj/structure/machinery/door/poddoor/almayer/closed{ id = "Corpo Vault"; @@ -25890,17 +25977,15 @@ }, /area/lv522/atmos/east_reactor/south) "lKu" = ( -/obj/structure/surface/table/almayer, -/obj/item/clothing/glasses/meson, -/obj/item/shard{ - icon_state = "medium" +/obj/structure/machinery/power/smes/buildable{ + capacity = 1e+006; + dir = 1 }, -/obj/effect/landmark/objective_landmark/close, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 }, +/turf/open/floor/plating, /area/lv522/indoors/lone_buildings/engineering) "lKC" = ( /obj/effect/landmark/structure_spawner/setup/distress/xeno_weed_node, @@ -26235,6 +26320,13 @@ icon_state = "floor_marked" }, /area/lv522/indoors/lone_buildings/outdoor_bot) +"lUh" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/turf/open/auto_turf/shale/layer1, +/area/lv522/outdoors/colony_streets/north_west_street) "lUi" = ( /obj/structure/bed/chair/comfy{ dir = 1 @@ -26656,6 +26748,11 @@ icon_state = "cement14" }, /area/lv522/outdoors/colony_streets/south_street) +"mdp" = ( +/obj/effect/decal/cleanable/blood/oil, +/obj/item/tool/weldingtool, +/turf/open/floor/plating, +/area/lv522/indoors/lone_buildings/engineering) "mdr" = ( /obj/structure/bed/chair{ dir = 4 @@ -27097,6 +27194,12 @@ /obj/structure/platform_decoration{ dir = 8 }, +/obj/effect/decal/warning_stripes{ + icon_state = "S" + }, +/obj/effect/decal/warning_stripes{ + icon_state = "W" + }, /turf/open/floor/prison{ icon_state = "floor_plate" }, @@ -27108,6 +27211,13 @@ icon_state = "darkpurplefull2" }, /area/lv522/indoors/a_block/dorms) +"mnU" = ( +/obj/effect/decal/cleanable/dirt, +/obj/item/ammo_magazine/rifle/l42a/extended{ + current_rounds = 0 + }, +/turf/open/floor/prison, +/area/lv522/indoors/a_block/security/glass) "mnX" = ( /obj/item/weapon/gun/rifle/m41a{ current_mag = null @@ -27439,6 +27549,14 @@ /obj/effect/landmark/lv624/fog_blocker/short, /turf/closed/wall/strata_outpost/reinforced, /area/lv522/oob/w_y_vault) +"mwC" = ( +/obj/item/clothing/head/welding, +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, +/turf/open/floor/plating, +/area/lv522/indoors/lone_buildings/engineering) "mwT" = ( /obj/structure/prop/dam/truck, /obj/structure/prop/holidays/wreath{ @@ -28488,6 +28606,13 @@ /area/lv522/outdoors/colony_streets/south_east_street) "mUG" = ( /obj/structure/platform_decoration, +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "W" + }, /turf/open/floor/prison{ icon_state = "floor_plate" }, @@ -28507,6 +28632,10 @@ /area/lv522/indoors/a_block/kitchen) "mVi" = ( /obj/structure/platform, +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, /turf/open/floor/prison{ icon_state = "floor_plate" }, @@ -29009,9 +29138,6 @@ icon_state = "18" }, /area/lv522/landing_zone_forecon/UD6_Typhoon) -"nfx" = ( -/turf/open/floor/plating, -/area/lv522/indoors/lone_buildings/engineering) "nfP" = ( /obj/structure/pipes/standard/simple/hidden/green{ dir = 4 @@ -29045,6 +29171,9 @@ /obj/structure/platform{ dir = 4 }, +/obj/effect/decal/warning_stripes{ + icon_state = "W" + }, /turf/open/floor/prison{ icon_state = "floor_plate" }, @@ -29212,6 +29341,13 @@ icon_state = "cement12" }, /area/lv522/outdoors/nw_rockies) +"nky" = ( +/obj/structure/machinery/power/apc/weak, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, +/area/lv522/indoors/lone_buildings/engineering) "nkX" = ( /obj/structure/pipes/standard/simple/hidden/green{ dir = 4 @@ -29638,8 +29774,11 @@ /turf/open/floor/plating/plating_catwalk/prison, /area/lv522/indoors/a_block/security) "nsd" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating/plating_catwalk/prison, +/obj/effect/decal/cleanable/generic, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, /area/lv522/indoors/lone_buildings/engineering) "nsr" = ( /obj/structure/surface/table/almayer, @@ -30068,6 +30207,11 @@ }, /turf/open/floor/prison, /area/lv522/indoors/a_block/dorms/glass) +"nEY" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/pipes/standard/simple/hidden/green, +/turf/open/floor/plating/plating_catwalk/prison, +/area/lv522/indoors/lone_buildings/engineering) "nFj" = ( /turf/open/floor/plating, /area/lv522/landing_zone_1) @@ -30273,21 +30417,14 @@ /turf/open/asphalt/cement, /area/lv522/outdoors/colony_streets/north_street) "nKo" = ( -/obj/structure/surface/table/almayer, -/obj/structure/machinery/door_control/brbutton/alt{ - id = "Secure_Master_Armoury"; - name = "remote door-control" - }, -/obj/item/limb/hand/l_hand{ - dir = 1; - pixel_x = 9; - pixel_y = 3 +/obj/structure/pipes/standard/simple/hidden/green{ + dir = 4 }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/prison{ - icon_state = "darkredfull2" +/obj/item/weapon/gun/rifle/l42a{ + current_mag = null }, -/area/lv522/indoors/a_block/security) +/turf/open/floor/plating/plating_catwalk/prison, +/area/lv522/indoors/a_block/security/glass) "nKK" = ( /obj/structure/platform{ dir = 8 @@ -30366,8 +30503,7 @@ /turf/open/auto_turf/shale/layer1, /area/lv522/landing_zone_1) "nMd" = ( -/obj/structure/surface/table/almayer, -/obj/effect/landmark/objective_landmark/close, +/obj/structure/closet/toolcloset, /turf/open/floor/prison{ dir = 4; icon_state = "darkyellowfull2" @@ -30376,6 +30512,7 @@ "nMt" = ( /obj/structure/surface/table/almayer, /obj/effect/decal/cleanable/dirt, +/obj/item/ammo_box/magazine/l42a, /turf/open/floor/prison{ icon_state = "darkredfull2" }, @@ -31869,13 +32006,13 @@ /turf/closed/wall/strata_ice/dirty, /area/lv522/oob) "ooh" = ( -/obj/structure/surface/table/almayer, -/obj/item/clothing/head/beret/eng, -/obj/item/ammo_box/magazine/nailgun/empty{ - pixel_x = -6; - pixel_y = 12 +/obj/structure/machinery/door/airlock/multi_tile/almayer/generic{ + name = "\improper Generator Room"; + welded = 1 + }, +/turf/open/floor/corsat{ + icon_state = "marked" }, -/turf/open/floor/prison, /area/lv522/indoors/lone_buildings/engineering) "oot" = ( /turf/open/floor/prison{ @@ -32151,6 +32288,15 @@ icon_state = "blue_plate" }, /area/lv522/indoors/a_block/admin) +"otM" = ( +/obj/structure/machinery/space_heater/radiator/red{ + dir = 4 + }, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, +/area/lv522/indoors/lone_buildings/engineering) "otQ" = ( /turf/open/floor/corsat{ icon_state = "marked" @@ -33006,12 +33152,8 @@ /turf/open/asphalt/cement, /area/lv522/outdoors/colony_streets/north_west_street) "oPc" = ( -/obj/item/clothing/gloves/yellow, -/obj/structure/machinery/space_heater/radiator/red, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" - }, +/obj/structure/pipes/standard/simple/hidden/green, +/turf/open/floor/plating/plating_catwalk/prison, /area/lv522/indoors/lone_buildings/engineering) "oPs" = ( /obj/effect/decal/cleanable/dirt, @@ -33200,8 +33342,14 @@ }, /area/lv522/indoors/a_block/dorms) "oTp" = ( -/obj/structure/machinery/light, -/turf/open/floor/plating, +/obj/structure/surface/table/almayer, +/obj/item/ammo_box/magazine/nailgun/empty{ + pixel_y = 5 + }, +/obj/structure/pipes/standard/simple/hidden/green{ + dir = 4 + }, +/turf/open/floor/prison, /area/lv522/indoors/lone_buildings/engineering) "oTD" = ( /obj/item/lightstick/red/spoke/planted{ @@ -33336,13 +33484,6 @@ icon_state = "marked" }, /area/lv522/indoors/c_block/mining) -"oWb" = ( -/obj/effect/landmark/static_comms/net_one, -/turf/open/floor/prison{ - dir = 10; - icon_state = "floor_marked" - }, -/area/lv522/indoors/lone_buildings/engineering) "oWq" = ( /obj/structure/pipes/standard/simple/hidden/green, /turf/open/floor/corsat{ @@ -34504,6 +34645,11 @@ icon_state = "cell_stripe" }, /area/lv522/indoors/lone_buildings/storage_blocks) +"pwT" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/pipes/standard/simple/hidden/green, +/turf/open/floor/prison, +/area/lv522/indoors/lone_buildings/engineering) "pwW" = ( /obj/structure/pipes/standard/simple/hidden/green{ dir = 4 @@ -34810,13 +34956,21 @@ /turf/open/floor/prison, /area/lv522/indoors/b_block/hydro) "pCT" = ( -/obj/structure/machinery/disposal, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/prison, +/obj/structure/machinery/power/terminal, +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/turf/open/floor/plating, /area/lv522/indoors/lone_buildings/engineering) "pCU" = ( -/obj/item/prop/alien/hugger, -/turf/open/floor/prison, +/obj/item/ammo_magazine/smg/nailgun{ + current_rounds = 0 + }, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, /area/lv522/indoors/lone_buildings/engineering) "pCW" = ( /obj/structure/pipes/standard/simple/hidden/green{ @@ -34987,6 +35141,14 @@ /obj/structure/platform_decoration{ dir = 1 }, +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, /turf/open/floor/prison{ icon_state = "floor_plate" }, @@ -35813,10 +35975,6 @@ /obj/structure/pipes/standard/simple/hidden/green{ dir = 4 }, -/obj/structure/machinery/camera/autoname, -/obj/structure/machinery/light/small{ - dir = 1 - }, /turf/open/floor/prison{ dir = 4; icon_state = "darkyellowfull2" @@ -35830,10 +35988,9 @@ }, /area/lv522/indoors/a_block/admin) "pXk" = ( -/obj/structure/surface/table/almayer, -/obj/effect/decal/cleanable/dirt, -/obj/effect/spawner/random/powercell, -/obj/structure/machinery/cell_charger, +/obj/structure/machinery/power/monitor{ + name = "Main Power Grid Monitoring" + }, /turf/open/floor/prison{ dir = 4; icon_state = "darkyellowfull2" @@ -36438,6 +36595,13 @@ }, /turf/open/floor/plating, /area/lv522/outdoors/colony_streets/central_streets) +"qma" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "NW-out"; + pixel_y = 1 + }, +/turf/open/auto_turf/shale/layer1, +/area/lv522/outdoors/colony_streets/north_west_street) "qml" = ( /obj/structure/pipes/standard/simple/hidden/green{ dir = 4 @@ -36468,11 +36632,7 @@ }, /area/lv522/indoors/a_block/admin) "qmA" = ( -/obj/effect/decal/cleanable/generic, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" - }, +/turf/open/floor/plating, /area/lv522/indoors/lone_buildings/engineering) "qmD" = ( /obj/structure/fence, @@ -36686,9 +36846,17 @@ /turf/open/floor/plating/plating_catwalk/prison, /area/lv522/indoors/a_block/bridges/op_centre) "qqD" = ( -/obj/item/ammo_box/magazine/shotgun/buckshot/empty, /obj/structure/surface/table/almayer, /obj/effect/decal/cleanable/dirt, +/obj/structure/machinery/door_control/brbutton/alt{ + id = "Sec-Armoury-Lockdown"; + name = "remote door-control" + }, +/obj/item/limb/hand/l_hand{ + dir = 1; + pixel_x = 9; + pixel_y = 3 + }, /turf/open/floor/prison{ icon_state = "darkredfull2" }, @@ -36816,6 +36984,10 @@ /obj/structure/platform{ dir = 8 }, +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, /turf/open/floor/prison{ icon_state = "floor_plate" }, @@ -37353,6 +37525,14 @@ icon_state = "blue_plate" }, /area/lv522/indoors/a_block/hallway) +"qDl" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "NE-out"; + pixel_x = 1; + pixel_y = 1 + }, +/turf/open/auto_turf/shale/layer0, +/area/lv522/outdoors/colony_streets/north_west_street) "qDr" = ( /obj/item/ammo_magazine/rifle/heap{ current_rounds = 0 @@ -37917,12 +38097,10 @@ }, /area/lv522/indoors/b_block/bar) "qOa" = ( -/obj/structure/machinery/cm_vending/sorted/tech/comp_storage{ - density = 0; - pixel_x = -4; - pixel_y = 12 +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" }, -/turf/open/floor/prison, /area/lv522/indoors/lone_buildings/engineering) "qOi" = ( /obj/structure/prop/invuln/fire{ @@ -38437,13 +38615,11 @@ /turf/open/floor/plating, /area/lv522/landing_zone_1/tunnel) "qWf" = ( -/obj/structure/machinery/light{ - dir = 8 - }, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" +/obj/effect/decal/cleanable/dirt, +/obj/structure/pipes/standard/simple/hidden/green{ + dir = 4 }, +/turf/open/floor/prison, /area/lv522/indoors/lone_buildings/engineering) "qWt" = ( /obj/structure/window/framed/strata/reinforced, @@ -38603,12 +38779,17 @@ }, /area/lv522/indoors/a_block/hallway) "qZJ" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/machinery/camera/autoname{ - dir = 1 +/obj/structure/machinery/light{ + dir = 8 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" }, -/obj/structure/machinery/light/small, -/turf/open/floor/plating, /area/lv522/indoors/lone_buildings/engineering) "qZT" = ( /obj/item/prop/colony/usedbandage{ @@ -38731,11 +38912,9 @@ /turf/open/floor/wood, /area/lv522/indoors/a_block/fitness/glass) "rbc" = ( -/obj/item/shard{ - icon_state = "medium" - }, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating/plating_catwalk/prison, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/prison, /area/lv522/indoors/lone_buildings/engineering) "rbj" = ( /obj/item/weapon/twohanded/folded_metal_chair, @@ -39297,6 +39476,12 @@ icon_state = "floor_plate" }, /area/lv522/indoors/a_block/hallway) +"rmX" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "S" + }, +/turf/open/auto_turf/shale/layer0, +/area/lv522/outdoors/colony_streets/north_west_street) "rng" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/machinery/camera/autoname{ @@ -39624,12 +39809,8 @@ /turf/open/floor/prison, /area/lv522/indoors/a_block/dorms) "ruj" = ( -/obj/structure/machinery/door_control{ - id = "UD6"; - name = "Cargo Shutter Control" - }, /turf/closed/shuttle/dropship2/tornado/typhoon{ - icon_state = "53" + icon_state = "59" }, /area/lv522/landing_zone_forecon/UD6_Typhoon) "rus" = ( @@ -39799,6 +39980,11 @@ /obj/structure/machinery/light/double, /turf/open/floor/wood, /area/lv522/indoors/a_block/fitness/glass) +"rwM" = ( +/turf/open/floor/corsat{ + icon_state = "marked" + }, +/area/lv522/indoors/lone_buildings/engineering) "rwR" = ( /obj/structure/desertdam/decals/road_edge{ icon_state = "road_edge_decal3"; @@ -40104,18 +40290,12 @@ }, /area/lv522/landing_zone_forecon/UD6_Typhoon) "rDu" = ( -/obj/structure/closet/crate/ammo, -/obj/item/ammo_magazine/m56d, -/obj/item/ammo_magazine/m56d, -/obj/item/device/m56d_gun, -/obj/structure/barricade/handrail{ - dir = 4 - }, -/obj/structure/barricade/handrail{ - dir = 8 +/obj/structure/machinery/door_control{ + id = "UD6"; + name = "Cargo Shutter Control" }, -/turf/open/shuttle/dropship{ - icon_state = "rasputin15" +/turf/closed/shuttle/dropship2/tornado/typhoon{ + icon_state = "53" }, /area/lv522/landing_zone_forecon/UD6_Typhoon) "rDz" = ( @@ -40281,14 +40461,10 @@ }, /area/lv522/outdoors/colony_streets/south_west_street) "rIn" = ( -/obj/item/ammo_magazine/smg/nailgun{ - current_rounds = 0 - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" +/obj/structure/pipes/standard/simple/hidden/green{ + dir = 10 }, +/turf/open/floor/plating/plating_catwalk/prison, /area/lv522/indoors/lone_buildings/engineering) "rIr" = ( /obj/structure/stairs/perspective{ @@ -41091,12 +41267,11 @@ /turf/open/auto_turf/shale/layer0, /area/lv522/outdoors/colony_streets/north_street) "rZg" = ( -/obj/structure/machinery/cm_vending/sorted/tech/tool_storage{ - density = 0; - pixel_x = 5; - pixel_y = 11 +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 }, -/turf/open/floor/prison, +/turf/open/floor/plating, /area/lv522/indoors/lone_buildings/engineering) "rZi" = ( /obj/structure/pipes/standard/simple/hidden/green, @@ -41363,6 +41538,9 @@ /obj/structure/machinery/light{ dir = 8 }, +/obj/effect/decal/warning_stripes{ + icon_state = "W" + }, /turf/open/auto_turf/shale/layer0, /area/lv522/outdoors/colony_streets/north_west_street) "seA" = ( @@ -42458,13 +42636,10 @@ }, /area/lv522/indoors/a_block/security/glass) "sEa" = ( -/obj/structure/extinguisher_cabinet{ - pixel_y = 30 - }, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" +/obj/structure/pipes/standard/simple/hidden/green{ + dir = 4 }, +/turf/open/floor/prison, /area/lv522/indoors/lone_buildings/engineering) "sEc" = ( /obj/structure/bed/bedroll{ @@ -42694,16 +42869,6 @@ }, /turf/open/floor/prison, /area/lv522/indoors/lone_buildings/storage_blocks) -"sJl" = ( -/obj/structure/machinery/power/apc/weak{ - dir = 1 - }, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" - }, -/area/lv522/indoors/lone_buildings/engineering) "sJI" = ( /obj/structure/surface/table/almayer, /obj/item/key/cargo_train, @@ -43149,15 +43314,10 @@ }, /area/lv522/outdoors/n_rockies) "sQD" = ( -/obj/structure/machinery/colony_floodlight_switch{ - pixel_y = 30 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/generic, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" +/obj/structure/pipes/standard/simple/hidden/green{ + dir = 5 }, +/turf/open/floor/plating/plating_catwalk/prison, /area/lv522/indoors/lone_buildings/engineering) "sQI" = ( /obj/effect/decal/cleanable/generic, @@ -43455,9 +43615,10 @@ }, /area/lv522/outdoors/colony_streets/north_west_street) "sXM" = ( -/obj/structure/machinery/power/monitor{ - name = "Main Power Grid Monitoring" - }, +/obj/structure/surface/table/almayer, +/obj/effect/decal/cleanable/dirt, +/obj/effect/spawner/random/powercell, +/obj/structure/machinery/cell_charger, /turf/open/floor/prison{ dir = 4; icon_state = "darkyellowfull2" @@ -44799,6 +44960,9 @@ /obj/structure/platform{ dir = 1 }, +/obj/effect/decal/warning_stripes{ + icon_state = "S" + }, /turf/open/floor/prison{ icon_state = "floor_plate" }, @@ -46178,6 +46342,17 @@ icon_state = "floor_plate" }, /area/lv522/indoors/lone_buildings/storage_blocks) +"udM" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/warning_stripes{ + icon_state = "NW-out"; + pixel_y = 1 + }, +/obj/structure/pipes/standard/simple/hidden/green{ + dir = 6 + }, +/turf/open/floor/plating/plating_catwalk/prison, +/area/lv522/indoors/lone_buildings/engineering) "udR" = ( /turf/open/floor/corsat{ dir = 4; @@ -46618,8 +46793,10 @@ /area/lv522/outdoors/colony_streets/north_east_street) "ukp" = ( /obj/structure/surface/table/almayer, -/obj/item/ammo_box/magazine/nailgun/empty{ - pixel_y = 5 +/obj/structure/machinery/recharger, +/obj/effect/spawner/random/powercell, +/obj/structure/pipes/standard/simple/hidden/green{ + dir = 10 }, /turf/open/floor/prison, /area/lv522/indoors/lone_buildings/engineering) @@ -46940,12 +47117,10 @@ }, /area/lv522/outdoors/colony_streets/north_street) "usn" = ( -/obj/structure/machinery/light{ - dir = 4 - }, +/obj/effect/landmark/static_comms/net_one, /turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" + dir = 10; + icon_state = "floor_marked" }, /area/lv522/indoors/lone_buildings/engineering) "usy" = ( @@ -47329,6 +47504,13 @@ "uAa" = ( /turf/open/floor/prison, /area/lv522/outdoors/colony_streets/north_street) +"uAb" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "SE-out"; + pixel_x = 1 + }, +/turf/open/auto_turf/shale/layer0, +/area/lv522/outdoors/colony_streets/north_west_street) "uAd" = ( /turf/open/floor/corsat{ dir = 1; @@ -47394,7 +47576,7 @@ /turf/open/floor/prison, /area/lv522/indoors/a_block/security) "uDs" = ( -/obj/item/clothing/head/beret/sec/hos, +/obj/item/clothing/head/CMB, /obj/effect/decal/cleanable/blood, /turf/open/floor/plating/plating_catwalk/prison, /area/lv522/indoors/a_block/security) @@ -47602,6 +47784,12 @@ icon_state = "blue_plate" }, /area/lv522/indoors/a_block/hallway) +"uGd" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "SW-out" + }, +/turf/open/auto_turf/shale/layer0, +/area/lv522/outdoors/colony_streets/north_west_street) "uGl" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/prison{ @@ -49028,10 +49216,14 @@ }, /area/lv522/indoors/a_block/security) "vir" = ( -/obj/structure/machinery/power/geothermal{ - fail_rate = 5 +/obj/structure/closet/wardrobe/engineering_yellow, +/obj/effect/decal/warning_stripes{ + icon_state = "SW-out" + }, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" }, -/turf/open/floor/plating, /area/lv522/indoors/lone_buildings/engineering) "viA" = ( /obj/item/lightstick/red/spoke/planted{ @@ -49821,11 +50013,10 @@ }, /area/lv522/indoors/a_block/medical) "vzc" = ( -/obj/structure/closet/wardrobe/engineering_yellow, -/turf/open/floor/prison{ - dir = 4; - icon_state = "darkyellowfull2" +/obj/structure/machinery/power/geothermal{ + fail_rate = 5 }, +/turf/open/floor/plating, /area/lv522/indoors/lone_buildings/engineering) "vzg" = ( /obj/item/stack/rods{ @@ -50223,13 +50414,20 @@ /turf/open/floor/plating/plating_catwalk/prison, /area/lv522/indoors/a_block/dorms) "vGP" = ( -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating, +/turf/open/floor/prison{ + dir = 10; + icon_state = "floor_marked" + }, /area/lv522/indoors/lone_buildings/engineering) "vHo" = ( -/obj/item/clothing/head/welding, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating, +/obj/effect/decal/warning_stripes{ + icon_state = "W" + }, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, /area/lv522/indoors/lone_buildings/engineering) "vHw" = ( /obj/structure/barricade/wooden{ @@ -51292,12 +51490,17 @@ }, /area/lv522/indoors/lone_buildings/storage_blocks) "wbj" = ( -/obj/structure/machinery/door/airlock/multi_tile/almayer/generic{ - name = "\improper Generator Room" +/obj/structure/machinery/cm_vending/sorted/tech/comp_storage{ + density = 0; + pixel_x = 13; + pixel_y = 11 }, -/turf/open/floor/corsat{ - icon_state = "marked" +/obj/structure/machinery/cm_vending/sorted/tech/electronics_storage{ + density = 0; + pixel_x = -13; + pixel_y = 11 }, +/turf/open/floor/prison, /area/lv522/indoors/lone_buildings/engineering) "wbt" = ( /obj/structure/pipes/standard/simple/hidden/green, @@ -51431,9 +51634,7 @@ }, /area/lv522/indoors/a_block/security/glass) "wdj" = ( -/turf/open/floor/corsat{ - icon_state = "marked" - }, +/turf/open/floor/prison, /area/lv522/indoors/lone_buildings/engineering) "wdy" = ( /turf/open/asphalt/cement{ @@ -53024,7 +53225,11 @@ /turf/open/floor/prison, /area/lv522/indoors/c_block/mining) "wOo" = ( -/turf/open/floor/plating/plating_catwalk/prison, +/obj/structure/pipes/vents/pump, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, /area/lv522/indoors/lone_buildings/engineering) "wOu" = ( /obj/structure/desertdam/decals/road_edge{ @@ -53663,10 +53868,11 @@ /turf/open/auto_turf/shale/layer0, /area/lv522/outdoors/colony_streets/south_east_street) "xdD" = ( -/obj/structure/window_frame/strata/reinforced, -/turf/open/floor/corsat{ - icon_state = "marked" +/obj/structure/pipes/standard/simple/hidden/green, +/obj/item/shard{ + icon_state = "medium" }, +/turf/open/floor/plating/plating_catwalk/prison, /area/lv522/indoors/lone_buildings/engineering) "xdF" = ( /obj/structure/pipes/standard/simple/hidden/green{ @@ -54463,7 +54669,7 @@ }, /area/lv522/indoors/b_block/hydro) "xwO" = ( -/obj/structure/cargo_container/watatsumi/leftmid, +/obj/structure/cargo_container/seegson/left, /turf/open/floor/prison, /area/lv522/outdoors/colony_streets/north_west_street) "xwZ" = ( @@ -54514,7 +54720,7 @@ /turf/open/floor/plating, /area/lv522/indoors/c_block/mining) "xxJ" = ( -/obj/structure/cargo_container/watatsumi/rightmid, +/obj/structure/cargo_container/seegson/mid, /obj/effect/decal/warning_stripes{ icon_state = "E"; pixel_x = 1 @@ -54530,7 +54736,7 @@ /turf/open/floor/prison, /area/lv522/indoors/a_block/admin) "xxV" = ( -/obj/structure/cargo_container/watatsumi/right, +/obj/structure/cargo_container/seegson/right, /turf/open/asphalt/cement{ icon_state = "cement1" }, @@ -54563,6 +54769,16 @@ icon_state = "cement1" }, /area/lv522/outdoors/colony_streets/central_streets) +"xzj" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/machinery/light{ + dir = 4 + }, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, +/area/lv522/indoors/lone_buildings/engineering) "xzn" = ( /turf/open/floor/prison, /area/lv522/atmos/outdoor) @@ -55001,19 +55217,26 @@ /turf/open/floor/plating/plating_catwalk/prison, /area/lv522/indoors/a_block/admin) "xJX" = ( -/obj/item/tool/weldingtool, -/obj/effect/decal/cleanable/blood/oil, -/obj/effect/decal/cleanable/dirt, -/turf/open/floor/plating, +/obj/effect/decal/cleanable/generic, +/obj/effect/decal/warning_stripes{ + icon_state = "W" + }, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, /area/lv522/indoors/lone_buildings/engineering) "xKc" = ( -/obj/structure/largecrate/supply/supplies/mre, /obj/structure/barricade/handrail{ - dir = 4 + dir = 8 }, /obj/structure/barricade/handrail{ - dir = 8 + dir = 4 }, +/obj/structure/closet/crate/ammo, +/obj/item/ammo_magazine/m56d, +/obj/item/ammo_magazine/m56d, +/obj/item/device/m56d_gun, /turf/open/shuttle/dropship{ icon_state = "rasputin15" }, @@ -55809,6 +56032,16 @@ }, /turf/open/asphalt/cement, /area/lv522/outdoors/colony_streets/north_east_street) +"xZS" = ( +/obj/item/clothing/gloves/yellow, +/obj/structure/machinery/space_heater/radiator/red{ + pixel_y = 26 + }, +/turf/open/floor/prison{ + dir = 4; + icon_state = "darkyellowfull2" + }, +/area/lv522/indoors/lone_buildings/engineering) "yae" = ( /obj/structure/surface/table/almayer, /obj/item/paper_bin{ @@ -55994,9 +56227,8 @@ }, /area/lv522/outdoors/colony_streets/north_west_street) "ydD" = ( -/obj/item/weapon/shield/riot, -/obj/item/weapon/classic_baton, -/obj/structure/surface/rack, +/obj/structure/surface/table/almayer, +/obj/item/ammo_box/magazine/shotgun/buckshot/empty, /turf/open/floor/prison{ icon_state = "darkredfull2" }, @@ -61596,16 +61828,16 @@ ruU fXx nJv xVd -vir -vir -vir +vGP +usn +nJv nJv rCa rCa nJv -nJv -jSG -oWb +vzc +vzc +vzc xVd nJv hpq @@ -61822,18 +62054,18 @@ umf ruU fXx nJv -vir +nJv +vGP vGP -nfx qZJ +otM +wdj +qOa nJv -sJl -lIC -qWf bzL -jPO -jPO -nJv +qmA +qmA +vzc nJv hpq ofi @@ -62051,15 +62283,15 @@ fAA nJv vir xJX -vGP -nfx -nJv +vHo +udM +nEY sQD nsd -nsd -nsd +nJv +cNO qmA -cjf +mdp vzc nJv gpB @@ -62276,17 +62508,17 @@ ruU ruU taj nJv -vir -nfx -vHo +cfd +vIy +vIy oTp -nJv +knT sEa -vIy -ukp +nky +nJv rZg -vIy -vIy +mwC +kIs vzc nJv gpB @@ -62502,20 +62734,20 @@ ruU ruU ruU fXx -xvQ -izp +nJv +nJv lHu -vIy +pwT fSv wbj rIn wOo ooh qOa -nsd +vIy pCT -nJv -nJv +jYy +xvQ hpq ofi tZh @@ -62728,22 +62960,22 @@ ruU ruU ruU ruU -fXx -xvQ +fCU +kvq izp -lHu -vIy -fSv +qWf +icy +wdj +wdj wdj -cjf pCU -lIC -lIC +rwM +qOa vIy -lIC +eXU lKu -kvq -fCU +xvQ +hpq ofi max max @@ -62958,16 +63190,16 @@ ruU fXx xvQ sXM -vIy -vIy +ukp +xdD oPc +nEY +sQD +flC nJv -jeo -nsd -wOo -nsd +xZS rbc -cfd +vIy pXk xvQ hpq @@ -63188,10 +63420,10 @@ xVd kfi ebR jkL -nJv +xzj pWW qLa -usn +nJv gZg gUA nMd @@ -63413,14 +63645,14 @@ fXx gbB nJv xvQ -xvQ -xvQ +gcX +kvq ivK wng hpO ivK -kvq -xdD +xvQ +xvQ xvQ nJv kmq @@ -64934,11 +65166,11 @@ slO hJZ hJZ hJZ -hJZ -hJZ -hJZ -hJZ -hJZ +uAb +lsG +lsG +lsG +qDl clY vjG kCJ @@ -65161,11 +65393,11 @@ slO hJZ clY hJZ -hJZ +rmX xkO xkO xkO -clY +lUh clY clY oTd @@ -65388,11 +65620,11 @@ slO hJZ clY clY -hJZ +rmX xkO sKj xkO -clY +lUh clY clY srQ @@ -65615,11 +65847,11 @@ eUt hJZ hJZ clY -hJZ +rmX xkO xWx xkO -clY +lUh clY clY oNQ @@ -65842,11 +66074,11 @@ eUt clY hJZ hJZ -hJZ +uGd sek -hJZ +fuw sek -clY +qma clY hJZ oNQ @@ -68540,7 +68772,7 @@ cpy cpy fgf cpy -yim +cKF hzA ihy yim @@ -75861,8 +76093,8 @@ kRb kBk iJu uDs -uDb -nKo +jUg +uVj sjy ogK oud @@ -76085,10 +76317,10 @@ wdi sjy sjy jmd -jmd +eWF oLW mbF -jGj +jft xbj sjy mNR @@ -77214,7 +77446,7 @@ sjy sjy sjy lhK -azl +nKo mqH ybt sjy @@ -77442,7 +77674,7 @@ sjy sjy lhK azl -mqH +mnU xhu sjy vHU @@ -78108,7 +78340,7 @@ iPZ uSv jyx uQF -jyx +jGj wwy jPw qgr @@ -79450,7 +79682,7 @@ saC saC saC saC -cpy +saC saC ien ien @@ -79675,9 +79907,9 @@ saC saC saC saC -cpy -cpy -cpy +saC +saC +saC saC saC ien @@ -79901,11 +80133,11 @@ saC saC saC saC -cpy -cpy -cpy -cpy -cpy +saC +saC +saC +saC +saC saC ien rxI @@ -80127,11 +80359,11 @@ saC saC saC saC -cpy -cpy -cpy -cpy -cpy +saC +saC +saC +saC +saC saC ien ien @@ -80355,10 +80587,10 @@ saC saC saC saC -cpy -cpy saC -cpy +saC +saC +saC saC saC ien @@ -80585,7 +80817,7 @@ saC saC saC saC -cpy +saC saC ien ien @@ -85353,7 +85585,7 @@ saC saC saC saC -cpy +saC saC saC saC @@ -85579,9 +85811,9 @@ saC saC saC saC -cpy -cpy -cpy +saC +saC +saC saC saC saC @@ -85806,11 +86038,11 @@ saC saC saC saC -cpy -cpy -cpy -cpy -cpy +saC +saC +saC +saC +saC saC saC bUN @@ -86034,11 +86266,11 @@ saC saC saC saC -cpy -cpy -cpy -cpy -cpy +saC +saC +saC +saC +saC ien cGd rtI @@ -86262,10 +86494,10 @@ saC saC saC saC -cpy -cpy -cpy -cpy +saC +saC +saC +saC ien rhh rtX @@ -86489,9 +86721,9 @@ saC saC saC saC -cpy -cpy -cpy +saC +saC +saC ien ien ien @@ -86717,9 +86949,9 @@ saC saC saC saC -cpy -cpy -cpy +saC +saC +saC ien qSH qSH @@ -86945,8 +87177,8 @@ saC saC saC saC -cpy -cpy +saC +saC ien qSH qSH @@ -94500,7 +94732,7 @@ tTD tTD tSm rnB -cKF +oXZ uKR rnB rnB diff --git a/maps/map_files/USS_Almayer/USS_Almayer.dmm b/maps/map_files/USS_Almayer/USS_Almayer.dmm index a6a5befca4ee..b15ee29dd20a 100644 --- a/maps/map_files/USS_Almayer/USS_Almayer.dmm +++ b/maps/map_files/USS_Almayer/USS_Almayer.dmm @@ -835,6 +835,20 @@ }, /turf/open/floor/wood/ship, /area/almayer/living/basketball) +"acJ" = ( +/mob/living/silicon/decoy/ship_ai{ + pixel_y = -16; + layer = 2.98 + }, +/obj/structure/blocker/invisible_wall, +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "acK" = ( /obj/structure/desertdam/decals/road_edge{ pixel_x = 2 @@ -993,6 +1007,9 @@ /obj/structure/closet, /obj/item/clothing/suit/armor/riot/marine/vintage_riot, /obj/item/clothing/head/helmet/riot/vintage_riot, +/obj/structure/machinery/light/small{ + dir = 1 + }, /turf/open/floor/almayer{ icon_state = "plate" }, @@ -2445,18 +2462,24 @@ /obj/item/paper_bin/uscm, /obj/item/tool/pen, /obj/structure/machinery/door_control{ - id = "bot_uniforms"; - name = "Uniform Vendor Lockdown"; - pixel_x = -8; - pixel_y = 10; - req_access_txt = "1" + id = "ARES StairsLock"; + name = "ARES Exterior Lockdown Override"; + req_one_access_txt = "90;91;92"; + pixel_y = -24; + pixel_x = 8 + }, +/obj/structure/machinery/door_control{ + id = "ARES Emergency"; + name = "ARES Emergency Lockdown Override"; + req_one_access_txt = "91;92"; + pixel_y = -24 }, /obj/structure/machinery/door_control{ id = "Brig Lockdown Shutters"; - name = "Brig Lockdown"; - pixel_x = 10; - pixel_y = 10; - req_access_txt = "1;3" + name = "Brig Lockdown Override"; + req_access_txt = "1;3"; + pixel_x = -8; + pixel_y = -24 }, /turf/open/floor/wood/ship, /area/almayer/living/commandbunks) @@ -3305,6 +3328,13 @@ /obj/structure/machinery/light{ dir = 1 }, +/obj/structure/machinery/door_control{ + id = "bot_uniforms"; + name = "Uniform Vendor Lockdown"; + pixel_x = 8; + pixel_y = 24; + req_access_txt = "31" + }, /turf/open/floor/almayer{ dir = 1; icon_state = "silver" @@ -4859,16 +4889,6 @@ icon_state = "orange" }, /area/almayer/engineering/engineering_workshop/hangar) -"apQ" = ( -/obj/structure/surface/table/reinforced/almayer_B, -/obj/structure/machinery/door/window/southleft{ - desc = "A window, that is also a door. A windoor if you will. This one is stronger."; - health = 500; - name = "Reinforced Glass door"; - req_one_access_txt = "2;35" - }, -/turf/open/floor/almayer, -/area/almayer/engineering/engineering_workshop/hangar) "apR" = ( /obj/structure/surface/rack, /obj/item/storage/box/beakers{ @@ -5256,7 +5276,7 @@ }, /area/almayer/engineering/engineering_workshop/hangar) "aqU" = ( -/turf/closed/wall/almayer, +/turf/closed/wall/almayer/reinforced, /area/almayer/command/airoom) "aqV" = ( /obj/structure/machinery/light{ @@ -5792,17 +5812,15 @@ }, /area/almayer/engineering/engineering_workshop/hangar) "asD" = ( -/obj/structure/machinery/light{ - dir = 1 - }, +/obj/effect/step_trigger/clone_cleaner, /obj/structure/machinery/door_control{ - id = "areslockdownexterior"; - name = "ARES Lockdown"; - pixel_x = -25; - req_one_access_txt = "19" + id = "ARES StairsUpper"; + name = "ARES Core Access"; + req_one_access_txt = "1;200;90;91;92"; + pixel_y = 24; + pixel_x = -24 }, -/obj/effect/landmark/start/working_joe, -/turf/open/floor/almayer{ +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) @@ -5810,20 +5828,23 @@ /turf/closed/wall/almayer/reinforced, /area/almayer/engineering/engineering_workshop/hangar) "asF" = ( -/obj/structure/machinery/door_control{ - id = "areslockdowninterior"; - name = "ARES Lockdown"; - pixel_x = -25; - req_one_access_txt = "19" +/obj/structure/machinery/door/airlock/almayer/secure/reinforced{ + name = "\improper AI Reception"; + req_access = null; + req_one_access_txt = "91;92" }, -/mob/living/silicon/decoy/ship_ai, -/obj/structure/blocker/invisible_wall, -/turf/open/floor/almayer{ +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) "asG" = ( -/turf/open/floor/almayer{ +/obj/structure/surface/table/reinforced/almayer_B{ + climbable = 0; + unacidable = 1; + unslashable = 1; + indestructible = 1 + }, +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) @@ -5967,6 +5988,15 @@ }, /turf/open/floor/almayer, /area/almayer/lifeboat_pumps/north2) +"asZ" = ( +/obj/structure/machinery/computer/cameras/almayer/ares{ + dir = 4; + pixel_x = -17 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "plating" + }, +/area/almayer/command/airoom) "ata" = ( /obj/structure/machinery/light{ dir = 8 @@ -6373,12 +6403,14 @@ }, /area/almayer/lifeboat_pumps/south1) "auc" = ( -/obj/structure/machinery/door/poddoor/shutters/almayer{ +/obj/effect/step_trigger/clone_cleaner, +/obj/structure/machinery/door/poddoor/almayer/open{ dir = 4; - id = "areslockdownexterior"; - name = "\improper ARES Core Shutters" + id = "ARES StairsLock"; + name = "ARES Exterior Lockdown" }, -/turf/open/floor/almayer{ +/obj/effect/step_trigger/ares_alert/access_control, +/turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, /area/almayer/command/airoom) @@ -6401,20 +6433,14 @@ }, /area/almayer/hallways/port_hallway) "auf" = ( -/obj/structure/machinery/door/poddoor/shutters/almayer{ - dir = 4; - id = "areslockdowninterior"; - name = "\improper ARES Core Shutters" - }, -/turf/open/floor/almayer{ - icon_state = "test_floor4" - }, +/obj/structure/pipes/standard/simple/hidden/supply/no_boom, +/turf/closed/wall/almayer/white/hull, /area/almayer/command/airoom) "aug" = ( /obj/structure/bed/chair/office/dark{ - dir = 1 + dir = 8 }, -/turf/open/floor/almayer{ +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) @@ -6507,6 +6533,9 @@ pixel_x = 8; pixel_y = -32 }, +/obj/structure/machinery/light/small{ + dir = 4 + }, /turf/open/floor/almayer{ icon_state = "plate" }, @@ -7047,29 +7076,64 @@ }, /area/almayer/living/starboard_garden) "avK" = ( -/obj/structure/machinery/camera/autoname/almayer{ - dir = 4; - name = "ship-grade camera" - }, -/obj/effect/landmark/start/working_joe, -/turf/open/floor/almayer{ +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) "avL" = ( -/obj/structure/surface/table/reinforced/almayer_B, -/obj/structure/machinery/computer/station_alert{ - dir = 1 +/obj/structure/machinery/door_control{ + id = "ARES StairsUpper"; + name = "ARES Core Access"; + req_one_access_txt = "91;92"; + pixel_y = -24; + pixel_x = -10 }, -/turf/open/floor/almayer{ +/obj/structure/machinery/door_control{ + id = "ARES StairsLock"; + name = "ARES Exterior Lockdown"; + req_one_access_txt = "91;92"; + pixel_y = -24 + }, +/obj/structure/surface/table/reinforced/almayer_B{ + climbable = 0; + unacidable = 1; + unslashable = 1; + indestructible = 1 + }, +/obj/structure/transmitter/rotary{ + phone_color = "blue"; + phone_id = "AI Reception"; + phone_category = "ARES"; + name = "AI Reception Telephone" + }, +/obj/structure/machinery/door_control{ + id = "ARES Emergency"; + name = "ARES Emergency Lockdown"; + req_one_access_txt = "91;92"; + pixel_y = -24; + pixel_x = 10 + }, +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) "avM" = ( -/obj/structure/surface/table/reinforced/almayer_B, -/obj/item/paper_bin/uscm, +/obj/structure/machinery/computer/cameras/almayer/ares{ + dir = 8; + pixel_x = 17; + pixel_y = 6 + }, +/obj/structure/surface/table/reinforced/almayer_B{ + climbable = 0; + unacidable = 1; + unslashable = 1; + indestructible = 1 + }, +/obj/item/paper_bin/uscm{ + pixel_y = 6 + }, /obj/item/tool/pen, -/turf/open/floor/almayer{ +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) @@ -7277,21 +7341,18 @@ }, /area/almayer/command/cic) "awu" = ( -/obj/structure/machinery/door_control{ - id = "areslockdownexterior"; - name = "ARES Lockdown"; - pixel_x = 25; - req_one_access_txt = "19" +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 }, /obj/effect/decal/warning_stripes{ - icon_state = "E"; - pixel_x = 1 + icon_state = "W"; + pixel_x = -1 }, -/turf/open/floor/almayer{ - dir = 8; - icon_state = "cargo_arrow" +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, -/area/almayer/hallways/aft_hallway) +/area/almayer/command/airoom) "awv" = ( /obj/structure/machinery/computer/telecomms/monitor, /turf/open/floor/almayer{ @@ -7800,6 +7861,10 @@ /obj/item/storage/belt/medical/full, /obj/item/storage/belt/medical/full, /obj/item/storage/belt/medical/full, +/obj/structure/machinery/computer/working_joe{ + dir = 8; + pixel_x = 17 + }, /turf/open/floor/almayer{ icon_state = "plate" }, @@ -9092,6 +9157,14 @@ icon_state = "plate" }, /area/almayer/command/cic) +"aCd" = ( +/obj/structure/bed/chair/office/dark{ + dir = 4 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "aCf" = ( /obj/structure/window/framed/almayer/hull/hijack_bustable, /obj/structure/machinery/door/firedoor/border_only/almayer, @@ -10908,6 +10981,47 @@ }, /turf/open/floor/almayer, /area/almayer/command/cichallway) +"aKs" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "W"; + pixel_x = -1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/structure/machinery/door_control{ + id = "ARES Interior"; + name = "ARES Chamber Lockdown"; + req_one_access_txt = "1;200;90;91;92"; + pixel_x = 24; + pixel_y = -8; + indestructible = 1 + }, +/obj/structure/machinery/door_control{ + id = "ARES Railing"; + name = "ARES Chamber Railings"; + req_one_access_txt = "91;92"; + pixel_x = 24; + needs_power = 0; + indestructible = 1 + }, +/obj/structure/machinery/door/poddoor/railing{ + dir = 2; + id = "ARES Railing"; + unslashable = 0; + unacidable = 0; + pixel_y = -1; + pixel_x = -1; + open_layer = 2.1; + closed_layer = 4.1; + density = 0; + layer = 2.1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "aKu" = ( /obj/structure/pipes/standard/simple/hidden/supply{ dir = 4 @@ -13343,6 +13457,10 @@ }, /area/almayer/hallways/stern_hallway) "aWb" = ( +/obj/structure/machinery/computer/working_joe{ + dir = 4; + pixel_x = -17 + }, /turf/open/floor/almayer{ dir = 1; icon_state = "orangecorner" @@ -14168,6 +14286,18 @@ }, /turf/open/floor/almayer, /area/almayer/hallways/starboard_hallway) +"bat" = ( +/obj/structure/machinery/door_control{ + id = "ARES Mainframe Right"; + name = "ARES Mainframe Lockdown"; + req_one_access_txt = "200;91;92"; + pixel_x = -24; + pixel_y = -24 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "baw" = ( /turf/open/floor/almayer, /area/almayer/lifeboat_pumps/south1) @@ -19281,6 +19411,39 @@ icon_state = "test_floor4" }, /area/almayer/hallways/starboard_hallway) +"bBi" = ( +/obj/structure/closet/cabinet, +/obj/item/clothing/under/liaison_suit/formal, +/obj/item/clothing/under/liaison_suit, +/obj/item/clothing/under/liaison_suit/outing, +/obj/item/clothing/under/liaison_suit/suspenders, +/obj/item/clothing/under/blackskirt{ + desc = "A stylish skirt, in a business-black and red colour scheme."; + name = "liaison's skirt" + }, +/obj/item/clothing/under/suit_jacket/charcoal{ + desc = "A professional black suit and blue tie. A combination popular among government agents and corporate Yes-Men alike."; + name = "liaison's black suit" + }, +/obj/item/clothing/under/suit_jacket/navy{ + desc = "A navy suit and red tie, intended for the Almayer's finest. And accountants."; + name = "liaison's navy suit" + }, +/obj/item/clothing/under/suit_jacket/trainee, +/obj/item/clothing/under/liaison_suit/charcoal, +/obj/item/clothing/under/liaison_suit/outing/red, +/obj/item/clothing/under/liaison_suit/blazer, +/obj/item/clothing/suit/storage/snow_suit/liaison, +/obj/item/clothing/gloves/black, +/obj/item/clothing/gloves/marine/dress, +/obj/item/clothing/glasses/sunglasses/big, +/obj/item/clothing/accessory/blue, +/obj/item/clothing/accessory/red, +/obj/structure/machinery/status_display{ + pixel_x = -32 + }, +/turf/open/floor/wood/ship, +/area/almayer/command/corporateliason) "bBl" = ( /obj/structure/machinery/light{ dir = 4 @@ -19906,22 +20069,6 @@ icon_state = "orange" }, /area/almayer/engineering/lower_engineering) -"bEk" = ( -/obj/structure/machinery/door/airlock/almayer/marine/requisitions{ - dir = 1; - name = "\improper Requisitions Storage" - }, -/obj/structure/machinery/door/firedoor/border_only/almayer{ - dir = 1 - }, -/obj/structure/disposalpipe/up/almayer{ - dir = 4; - id = "almayerlink_OT1_req" - }, -/turf/open/floor/almayer{ - icon_state = "test_floor4" - }, -/area/almayer/squads/req) "bEl" = ( /obj/structure/machinery/computer/supply_drop_console/limited, /turf/closed/wall/almayer, @@ -20916,6 +21063,26 @@ icon_state = "plate" }, /area/almayer/hallways/hangar) +"bIp" = ( +/obj/effect/step_trigger/ares_alert/mainframe, +/obj/structure/machinery/door/poddoor/shutters/almayer{ + id = "ARES Mainframe Left"; + name = "\improper ARES Mainframe Shutters"; + plane = -7 + }, +/obj/structure/machinery/door/poddoor/almayer/blended/white/open{ + open_layer = 1.9; + id = "ARES Emergency"; + needs_power = 0; + name = "ARES Emergency Lockdown"; + layer = 3.2; + closed_layer = 3.2; + plane = -7 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "bIs" = ( /obj/structure/largecrate/supply/supplies/mre, /obj/structure/machinery/light/small{ @@ -21697,6 +21864,23 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/hallways/vehiclehangar) +"bLv" = ( +/obj/structure/machinery/door_control{ + id = "ARES StairsLower"; + name = "ARES Core Lockdown"; + req_one_access_txt = "19;200;90;91;92"; + pixel_x = 24; + pixel_y = -8 + }, +/obj/structure/machinery/camera/autoname/almayer/containment/ares{ + dir = 8; + pixel_y = 2 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 4 + }, +/area/almayer/command/airoom) "bLw" = ( /obj/structure/surface/table/almayer, /obj/structure/machinery/light{ @@ -23074,6 +23258,35 @@ icon_state = "red" }, /area/almayer/shipboard/brig/lobby) +"bRo" = ( +/obj/structure/machinery/door/poddoor/shutters/almayer{ + id = "ARES StairsLower"; + name = "\improper ARES Core Shutters"; + plane = -7 + }, +/obj/effect/step_trigger/ares_alert/public{ + alert_message = "Caution: Movement detected in ARES Core."; + cooldown_duration = 1200; + alert_id = "AresStairs" + }, +/obj/effect/step_trigger/ares_alert/public{ + alert_message = "Caution: Movement detected in ARES Core."; + cooldown_duration = 1200; + alert_id = "AresStairs" + }, +/obj/structure/machinery/door/poddoor/almayer/blended/white/open{ + open_layer = 1.9; + id = "ARES Emergency"; + needs_power = 0; + name = "ARES Emergency Lockdown"; + layer = 3.2; + closed_layer = 3.2; + plane = -7 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "bRr" = ( /obj/structure/machinery/fuelcell_recycler, /turf/open/floor/almayer{ @@ -23769,6 +23982,13 @@ icon_state = "blue" }, /area/almayer/squads/delta) +"bUx" = ( +/obj/effect/landmark/start/working_joe, +/obj/structure/machinery/light/small{ + dir = 8 + }, +/turf/open/floor/plating, +/area/almayer/command/airoom) "bUy" = ( /obj/structure/closet/crate/ammo, /obj/structure/machinery/light/small, @@ -25529,11 +25749,18 @@ }, /area/almayer/command/cichallway) "cck" = ( -/obj/structure/window/framed/almayer/hull/hijack_bustable, -/obj/structure/machinery/door/firedoor/border_only/almayer{ - dir = 2 +/obj/structure/surface/table/reinforced/almayer_B, +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, -/turf/open/floor/plating, /area/almayer/command/airoom) "ccq" = ( /obj/effect/decal/warning_stripes{ @@ -27174,6 +27401,17 @@ "cls" = ( /turf/open/floor/plating/plating_catwalk, /area/almayer/shipboard/port_point_defense) +"clw" = ( +/obj/structure/machinery/light{ + dir = 8; + unacidable = 1; + unslashable = 1; + invisibility = 101 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "cly" = ( /obj/structure/disposalpipe/segment, /obj/structure/sign/safety/maint{ @@ -27565,12 +27803,10 @@ }, /area/almayer/hallways/starboard_hallway) "cnp" = ( -/obj/structure/surface/table/reinforced/almayer_B, -/obj/item/folder/yellow, /obj/structure/machinery/light{ dir = 4 }, -/turf/open/floor/almayer{ +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) @@ -27910,6 +28146,19 @@ icon_state = "green" }, /area/almayer/hallways/starboard_hallway) +"cqm" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/item/folder/white{ + pixel_y = 6 + }, +/obj/item/folder/white{ + pixel_y = 6; + pixel_x = 5 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "cqn" = ( /obj/structure/window/framed/almayer, /obj/structure/machinery/door/firedoor/border_only/almayer{ @@ -28199,6 +28448,12 @@ icon_state = "blue" }, /area/almayer/hallways/aft_hallway) +"cwS" = ( +/obj/structure/blocker/invisible_wall, +/turf/open/floor/almayer/no_build{ + icon_state = "plating" + }, +/area/almayer/command/airoom) "cwX" = ( /obj/structure/ladder{ height = 1; @@ -28206,6 +28461,18 @@ }, /turf/open/floor/plating/almayer, /area/almayer/living/briefing) +"cxc" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/structure/machinery/light{ + dir = 4 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "cxe" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -28322,6 +28589,9 @@ "cBd" = ( /obj/structure/surface/rack, /obj/item/reagent_container/food/snacks/wrapped/chunk, +/obj/structure/machinery/light/small{ + dir = 4 + }, /turf/open/floor/almayer{ icon_state = "cargo" }, @@ -28360,6 +28630,24 @@ icon_state = "plate" }, /area/almayer/hallways/vehiclehangar) +"cBm" = ( +/obj/effect/projector{ + name = "Almayer_AresUp"; + vector_x = -97; + vector_y = 65 + }, +/obj/structure/platform{ + dir = 4 + }, +/obj/structure/stairs{ + dir = 1; + icon_state = "ramptop" + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 4 + }, +/area/almayer/command/airoom) "cBs" = ( /obj/structure/bed/chair, /obj/effect/decal/warning_stripes{ @@ -28810,6 +29098,16 @@ /obj/item/tool/lighter/zippo, /turf/open/floor/wood/ship, /area/almayer/shipboard/sea_office) +"cLo" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/turf/open/floor/almayer/no_build{ + dir = 2; + icon_state = "cargo_arrow" + }, +/area/almayer/command/airoom) "cLp" = ( /obj/structure/machinery/door/firedoor/border_only/almayer{ dir = 2 @@ -29446,6 +29744,9 @@ icon_state = "mono" }, /area/almayer/lifeboat_pumps/south1) +"daz" = ( +/turf/closed/wall/almayer/white/hull, +/area/almayer/command/airoom) "dbe" = ( /obj/structure/largecrate/random/case/double, /obj/structure/machinery/camera/autoname/almayer{ @@ -30585,6 +30886,12 @@ icon_state = "plate" }, /area/almayer/living/briefing) +"dyp" = ( +/obj/structure/machinery/ares/cpu, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "dyx" = ( /obj/structure/machinery/door/poddoor/shutters/almayer{ dir = 2; @@ -30800,6 +31107,15 @@ icon_state = "orange" }, /area/almayer/engineering/engine_core) +"dDp" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "W"; + layer = 3.3 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "dDt" = ( /obj/structure/toilet{ dir = 1 @@ -30938,6 +31254,23 @@ icon_state = "plate" }, /area/almayer/hull/lower_hull/l_f_p) +"dGl" = ( +/obj/effect/step_trigger/teleporter_vector{ + name = "Almayer_AresUp"; + vector_x = -97; + vector_y = 65 + }, +/obj/structure/platform{ + dir = 8 + }, +/obj/structure/stairs{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 8 + }, +/area/almayer/command/airoom) "dGr" = ( /obj/structure/pipes/vents/scrubber{ dir = 8 @@ -31076,6 +31409,12 @@ }, /turf/open/floor/plating, /area/almayer/living/bridgebunks) +"dIi" = ( +/obj/structure/pipes/standard/simple/hidden/supply/no_boom, +/turf/open/floor/plating/plating_catwalk{ + allow_construction = 0 + }, +/area/almayer/command/airoom) "dIl" = ( /obj/structure/disposalpipe/segment, /obj/structure/pipes/standard/simple/hidden/supply{ @@ -31083,6 +31422,14 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/upper_hull/u_f_s) +"dIn" = ( +/obj/structure/pipes/standard/simple/hidden/supply/no_boom{ + dir = 5 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "dII" = ( /obj/structure/machinery/door/airlock/multi_tile/almayer/marine/shared/alpha_bravo, /obj/effect/decal/warning_stripes{ @@ -31259,6 +31606,23 @@ icon_state = "plate" }, /area/almayer/hull/upper_hull/u_f_s) +"dQl" = ( +/obj/structure/platform{ + dir = 4 + }, +/obj/effect/step_trigger/teleporter_vector{ + name = "Almayer_AresUp"; + vector_x = -97; + vector_y = 65 + }, +/obj/structure/stairs{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 4 + }, +/area/almayer/command/airoom) "dQv" = ( /obj/structure/pipes/standard/simple/hidden/supply{ dir = 4 @@ -31721,6 +32085,9 @@ icon_state = "orange" }, /area/almayer/engineering/engine_core) +"ebN" = ( +/turf/closed/wall/almayer/white/reinforced, +/area/almayer/command/airoom) "ebO" = ( /obj/structure/machinery/light/small, /turf/open/floor/almayer{ @@ -32653,6 +33020,17 @@ /obj/effect/landmark/late_join/delta, /turf/open/floor/plating/plating_catwalk, /area/almayer/squads/delta) +"erN" = ( +/obj/structure/machinery/light{ + dir = 8 + }, +/obj/structure/pipes/vents/pump/no_boom{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "erS" = ( /obj/structure/pipes/standard/simple/hidden/supply, /turf/open/floor/plating/plating_catwalk, @@ -32782,6 +33160,21 @@ icon_state = "sterile_green_corner" }, /area/almayer/medical/testlab) +"euN" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "SE-out" + }, +/obj/structure/machinery/door_control{ + id = "ARES Mainframe Left"; + name = "ARES Mainframe Lockdown"; + req_one_access_txt = "200;91;92"; + pixel_x = 24; + pixel_y = 24 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "euO" = ( /obj/structure/window/framed/almayer, /obj/structure/machinery/door/poddoor/shutters/almayer/open{ @@ -33467,6 +33860,20 @@ icon_state = "test_floor5" }, /area/almayer/squads/req) +"eKJ" = ( +/obj/structure/machinery/status_display{ + pixel_y = 30 + }, +/obj/structure/machinery/light{ + dir = 4; + unacidable = 1; + unslashable = 1; + invisibility = 101 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "eKK" = ( /obj/structure/sink{ dir = 4; @@ -33609,6 +34016,9 @@ dir = 8 }, /obj/effect/decal/cleanable/blood, +/obj/structure/machinery/light/small{ + dir = 4 + }, /turf/open/floor/almayer{ icon_state = "plate" }, @@ -34023,6 +34433,14 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/living/port_emb) +"eYz" = ( +/obj/structure/machinery/camera/autoname/almayer/containment/ares{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "eYC" = ( /obj/structure/machinery/vending/cigarette, /turf/open/floor/wood/ship, @@ -34270,6 +34688,19 @@ icon_state = "orange" }, /area/almayer/engineering/upper_engineering/starboard) +"fcX" = ( +/obj/effect/step_trigger/clone_cleaner, +/obj/structure/machinery/light{ + dir = 8 + }, +/obj/structure/platform_decoration{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 8 + }, +/area/almayer/command/airoom) "fdj" = ( /obj/structure/surface/table/almayer, /obj/item/storage/pouch/tools/full, @@ -34364,6 +34795,11 @@ icon_state = "sterile_green_side" }, /area/almayer/medical/operating_room_two) +"ffE" = ( +/turf/open/floor/almayer/no_build{ + icon_state = "plating" + }, +/area/almayer/command/airoom) "fgh" = ( /obj/structure/machinery/light/small{ dir = 8 @@ -34566,6 +35002,19 @@ icon_state = "plate" }, /area/almayer/squads/req) +"fmv" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "fmB" = ( /obj/structure/bed/chair/comfy{ dir = 8 @@ -34781,6 +35230,19 @@ }, /turf/open/floor/plating/almayer, /area/almayer/shipboard/brig/armory) +"frM" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "NW-out"; + pixel_y = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "fsd" = ( /obj/effect/decal/warning_stripes{ icon_state = "S" @@ -35324,6 +35786,14 @@ icon_state = "test_floor4" }, /area/almayer/living/grunt_rnr) +"fEN" = ( +/obj/structure/machinery/camera/autoname/almayer/containment/ares{ + dir = 4 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "fER" = ( /obj/structure/machinery/autolathe, /turf/open/floor/almayer{ @@ -35615,6 +36085,23 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/lower_hull/l_f_s) +"fJY" = ( +/obj/structure/pipes/standard/simple/hidden/supply/no_boom{ + dir = 4 + }, +/turf/open/floor/almayer/no_build{ + dir = 8; + icon_state = "cargo_arrow" + }, +/area/almayer/command/airoom) +"fKe" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "SW-out" + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "fKg" = ( /obj/structure/closet/firecloset, /turf/open/floor/plating/plating_catwalk, @@ -35704,6 +36191,47 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/engineering/lower_engineering) +"fMl" = ( +/obj/structure/machinery/door_control{ + id = "ARES Operations Right"; + name = "ARES Operations Shutter"; + req_one_access_txt = "1;200;91;92"; + pixel_x = 24; + pixel_y = -8 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 4 + }, +/area/almayer/command/airoom) +"fMt" = ( +/obj/structure/machinery/door/poddoor/shutters/almayer{ + id = "ARES Interior"; + name = "\improper ARES Inner Chamber Shutters"; + plane = -7 + }, +/obj/effect/step_trigger/ares_alert/core, +/obj/structure/machinery/door/poddoor/almayer/blended/white/open{ + open_layer = 1.9; + id = "ARES Emergency"; + needs_power = 0; + name = "ARES Emergency Lockdown"; + layer = 3.2; + closed_layer = 3.2; + plane = -7 + }, +/obj/structure/sign/safety/laser{ + pixel_x = 32; + pixel_y = -8 + }, +/obj/structure/sign/safety/rewire{ + pixel_y = 6; + pixel_x = 32 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "fMA" = ( /obj/effect/decal/warning_stripes{ icon_state = "NW-out" @@ -35840,6 +36368,12 @@ icon_state = "plate" }, /area/almayer/hallways/hangar) +"fPB" = ( +/obj/structure/machinery/ares/processor/apollo, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "fQk" = ( /obj/structure/largecrate/random, /turf/open/floor/plating/plating_catwalk, @@ -36208,6 +36742,50 @@ icon_state = "silver" }, /area/almayer/command/cichallway) +"gba" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/structure/machinery/faxmachine/uscm/command{ + department = "AI Core"; + pixel_y = 8 + }, +/obj/structure/transmitter/rotary{ + pixel_x = 8; + pixel_y = -8; + phone_color = "blue"; + phone_id = "AI Core"; + phone_category = "ARES"; + name = "AI Core Telephone" + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) +"gbg" = ( +/obj/structure/sign/safety/terminal{ + pixel_y = 24; + pixel_x = 14 + }, +/obj/structure/sign/safety/laser{ + pixel_y = 24 + }, +/obj/structure/sign/safety/fibre_optics{ + pixel_x = 14; + pixel_y = 38 + }, +/obj/structure/sign/safety/rewire{ + pixel_y = 38 + }, +/obj/structure/machinery/door_control{ + id = "ARES Operations Right"; + name = "ARES Operations Shutter"; + req_one_access_txt = "1;200;91;92"; + pixel_x = -24; + pixel_y = -8 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "gbQ" = ( /obj/structure/toilet{ dir = 8 @@ -36413,14 +36991,23 @@ }, /turf/open/floor/almayer, /area/almayer/squads/delta) -"gfE" = ( -/obj/structure/machinery/light{ - dir = 4 +"gfu" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 }, -/turf/open/floor/almayer{ +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/turf/open/floor/almayer/no_build{ icon_state = "tcomms" }, /area/almayer/command/airoom) +"gfE" = ( +/obj/structure/machinery/recharge_station, +/turf/open/floor/plating, +/area/almayer/command/airoom) "gfS" = ( /obj/structure/sign/safety/cryo{ pixel_y = -26 @@ -36579,8 +37166,25 @@ }, /area/almayer/hull/lower_hull/l_f_s) "gjw" = ( -/obj/structure/blocker/invisible_wall, -/turf/open/floor/almayer{ +/obj/structure/machinery/faxmachine/uscm/command{ + department = "AI Core"; + pixel_y = 32; + density = 0 + }, +/obj/structure/surface/rack{ + pixel_y = 16; + density = 0 + }, +/obj/structure/machinery/computer/working_joe{ + dir = 8; + pixel_x = 17; + pixel_y = -6; + ticket_console = 1 + }, +/obj/item/storage/box/ids{ + pixel_x = -4 + }, +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) @@ -36628,14 +37232,6 @@ icon_state = "redfull" }, /area/almayer/hull/lower_hull/l_f_s) -"gkg" = ( -/obj/structure/disposalpipe/sortjunction{ - dir = 4; - negdir = 4; - posdir = 1 - }, -/turf/closed/wall/almayer, -/area/almayer/squads/req) "gks" = ( /obj/structure/largecrate/random/secure, /turf/open/floor/plating, @@ -37040,6 +37636,12 @@ icon_state = "plate" }, /area/almayer/hull/lower_hull/l_f_p) +"gwn" = ( +/obj/structure/machinery/ares/processor/bioscan, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "gwo" = ( /turf/open/floor/almayer{ dir = 4; @@ -37226,6 +37828,16 @@ icon_state = "orange" }, /area/almayer/hallways/starboard_hallway) +"gyN" = ( +/obj/structure/machinery/prop{ + icon_state = "comm_server"; + name = "server box"; + desc = "It's a server box..." + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "gyO" = ( /obj/structure/pipes/vents/pump{ dir = 8 @@ -37311,6 +37923,24 @@ }, /turf/open/floor/almayer, /area/almayer/hull/upper_hull/u_f_p) +"gAe" = ( +/obj/structure/filingcabinet{ + density = 0; + pixel_x = -8; + pixel_y = 18 + }, +/obj/structure/filingcabinet{ + density = 0; + pixel_x = 8; + pixel_y = 18 + }, +/obj/item/folder/white, +/obj/item/folder/white, +/obj/item/folder/white, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "gAj" = ( /obj/structure/bed/chair/comfy/charlie{ dir = 1 @@ -37834,6 +38464,39 @@ icon_state = "test_floor4" }, /area/almayer/hull/upper_hull/u_m_p) +"gMN" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/structure/machinery/door_control{ + id = "ARES Interior"; + name = "ARES Chamber Lockdown"; + req_one_access_txt = "1;200;90;91;92"; + pixel_x = -24; + pixel_y = -8; + indestructible = 1 + }, +/obj/structure/machinery/door/poddoor/railing{ + dir = 2; + id = "ARES Railing"; + unslashable = 0; + unacidable = 0; + pixel_y = -1; + pixel_x = -1; + open_layer = 2.1; + density = 0; + closed_layer = 4.1; + layer = 2.1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "gMU" = ( /obj/structure/pipes/standard/simple/hidden/supply{ dir = 4 @@ -37868,6 +38531,33 @@ /obj/effect/spawner/random/tool, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/lower_hull/l_m_p) +"gOs" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/structure/machinery/door_control{ + id = "ARES Interior"; + name = "ARES Chamber Lockdown"; + req_one_access_txt = "1;200;90;91;92"; + pixel_x = 24; + pixel_y = 8; + indestructible = 1 + }, +/obj/structure/machinery/door/poddoor/railing{ + id = "ARES Railing"; + unslashable = 0; + unacidable = 0; + open_layer = 2.1; + density = 0; + layer = 2.1; + closed_layer = 4 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 4 + }, +/area/almayer/command/airoom) "gPc" = ( /obj/structure/machinery/power/terminal{ dir = 1 @@ -37877,6 +38567,23 @@ icon_state = "orange" }, /area/almayer/engineering/upper_engineering/starboard) +"gPr" = ( +/obj/effect/step_trigger/teleporter_vector{ + name = "Almayer_AresUp"; + vector_x = -97; + vector_y = 65 + }, +/obj/structure/machinery/light{ + unacidable = 1; + unslashable = 1 + }, +/obj/structure/stairs{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + dir = 4 + }, +/area/almayer/command/airoom) "gPF" = ( /obj/structure/machinery/light, /turf/open/floor/almayer{ @@ -38003,6 +38710,23 @@ icon_state = "red" }, /area/almayer/shipboard/brig/main_office) +"gTH" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/structure/machinery/computer/skills{ + dir = 4; + pixel_y = 18 + }, +/obj/structure/machinery/computer/secure_data{ + dir = 4 + }, +/obj/structure/machinery/computer/med_data/laptop{ + dir = 4; + pixel_y = -18 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "gUf" = ( /obj/structure/machinery/portable_atmospherics/hydroponics, /turf/open/floor/almayer{ @@ -38050,6 +38774,15 @@ }, /turf/open/floor/almayer, /area/almayer/living/bridgebunks) +"gUN" = ( +/obj/structure/pipes/standard/simple/hidden/supply/no_boom{ + dir = 4 + }, +/turf/open/floor/almayer/no_build{ + dir = 4; + icon_state = "cargo_arrow" + }, +/area/almayer/command/airoom) "gUV" = ( /turf/open/floor/almayer{ icon_state = "redcorner" @@ -38059,6 +38792,13 @@ /obj/structure/pipes/standard/manifold/hidden/supply, /turf/open/floor/plating/plating_catwalk, /area/almayer/lifeboat_pumps/north2) +"gVA" = ( +/obj/structure/disposalpipe/down/almayer{ + dir = 8; + id = "almayerlink_OT1_req" + }, +/turf/open/floor/almayer, +/area/almayer/lifeboat_pumps/south1) "gVF" = ( /obj/structure/pipes/standard/manifold/hidden/supply{ dir = 1 @@ -38088,6 +38828,12 @@ icon_state = "plate" }, /area/almayer/hull/lower_hull/l_f_p) +"gXh" = ( +/obj/structure/machinery/light/small{ + dir = 8 + }, +/turf/open/floor/plating/plating_catwalk, +/area/almayer/hull/upper_hull/u_m_s) "gXl" = ( /obj/structure/closet/secure_closet/personal/cabinet{ req_access_txt = "5" @@ -38109,6 +38855,20 @@ icon_state = "plate" }, /area/almayer/engineering/engineering_workshop) +"gXs" = ( +/obj/effect/step_trigger/ares_alert/terminals, +/obj/structure/machinery/door/poddoor/shutters/almayer{ + id = "ARES Operations Right"; + name = "\improper ARES Operations Shutters"; + dir = 4 + }, +/obj/structure/pipes/standard/simple/hidden/supply/no_boom{ + dir = 4 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "gXv" = ( /obj/structure/sign/safety/nonpress_0g{ pixel_x = 32 @@ -38352,6 +39112,12 @@ icon_state = "plate" }, /area/almayer/living/cryo_cells) +"hcC" = ( +/obj/structure/disposalpipe/up/almayer{ + id = "almayerlink_OT_req" + }, +/turf/closed/wall/almayer, +/area/almayer/engineering/engineering_workshop/hangar) "hcI" = ( /obj/structure/machinery/cryopod{ pixel_y = 6 @@ -38416,12 +39182,6 @@ icon_state = "plate" }, /area/almayer/hull/lower_hull/l_f_s) -"hdV" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/turf/open/floor/almayer, -/area/almayer/lifeboat_pumps/south1) "hee" = ( /turf/open/floor/almayer{ dir = 4; @@ -39083,18 +39843,9 @@ /turf/open/floor/almayer, /area/almayer/command/cic) "hvw" = ( -/obj/structure/machinery/r_n_d/server/core{ - unacidable = 1; - unslashable = 1 - }, -/obj/structure/sign/safety/rewire{ - pixel_x = 8; - pixel_y = 32 - }, -/turf/open/floor/almayer{ - icon_state = "tcomms" - }, -/area/almayer/command/airoom) +/obj/structure/pipes/standard/simple/hidden/supply/no_boom, +/turf/open/floor/plating, +/area/almayer/powered/agent) "hvH" = ( /turf/open/floor/wood/ship, /area/almayer/living/commandbunks) @@ -39230,6 +39981,17 @@ allow_construction = 0 }, /area/almayer/shipboard/brig/processing) +"hyE" = ( +/obj/structure/machinery/door/poddoor/almayer/open{ + dir = 4; + id = "ARES StairsLock"; + name = "ARES Exterior Lockdown" + }, +/obj/effect/step_trigger/ares_alert/access_control, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "hyQ" = ( /turf/closed/wall/almayer, /area/almayer/living/synthcloset) @@ -40016,6 +40778,33 @@ icon_state = "redcorner" }, /area/almayer/shipboard/brig/execution) +"hRW" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/structure/sign/safety/rewire{ + pixel_y = 38 + }, +/obj/structure/sign/safety/laser{ + pixel_y = 24 + }, +/obj/structure/machinery/computer/crew/alt{ + pixel_x = -17; + dir = 4 + }, +/obj/structure/sign/safety/terminal{ + pixel_y = 24; + pixel_x = 14 + }, +/obj/structure/sign/safety/fibre_optics{ + pixel_x = 14; + pixel_y = 38 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "hSk" = ( /turf/open/floor/plating/plating_catwalk, /area/almayer/engineering/upper_engineering/port) @@ -40077,6 +40866,18 @@ }, /turf/closed/wall/almayer/outer, /area/almayer/hull/lower_hull/l_a_p) +"hTl" = ( +/obj/structure/prop/server_equipment/yutani_server{ + pixel_y = 16; + name = "server tower"; + desc = "A powerful server tower housing various AI functions."; + density = 0 + }, +/obj/structure/pipes/standard/simple/hidden/supply/no_boom, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "hTt" = ( /obj/structure/machinery/brig_cell/cell_1{ pixel_x = 32; @@ -40320,6 +41121,15 @@ }, /turf/open/floor/almayer, /area/almayer/hallways/hangar) +"hZj" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "hZN" = ( /obj/structure/machinery/medical_pod/bodyscanner, /obj/structure/disposalpipe/segment{ @@ -40540,6 +41350,20 @@ icon_state = "sterile_green_corner" }, /area/almayer/medical/lower_medical_lobby) +"ieF" = ( +/obj/effect/projector{ + name = "Almayer_AresUp"; + vector_x = -97; + vector_y = 65 + }, +/obj/structure/stairs{ + dir = 1; + icon_state = "ramptop" + }, +/turf/open/floor/almayer/no_build{ + dir = 4 + }, +/area/almayer/command/airoom) "ieH" = ( /obj/structure/sign/safety/storage{ pixel_x = 8; @@ -40595,6 +41419,14 @@ }, /turf/open/floor/wood/ship, /area/almayer/command/corporateliason) +"igr" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "SE-out" + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "igt" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -41063,8 +41895,17 @@ /turf/open/floor/plating, /area/almayer/living/port_emb) "isC" = ( -/turf/open/floor/almayer{ - icon_state = "tcomms" +/obj/effect/projector{ + name = "Almayer_AresDown"; + vector_x = 97; + vector_y = -65 + }, +/obj/structure/stairs{ + dir = 1; + icon_state = "ramptop" + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, /area/almayer/command/airoom) "isH" = ( @@ -41110,6 +41951,33 @@ icon_state = "bluecorner" }, /area/almayer/hallways/aft_hallway) +"itf" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/structure/machinery/door_control{ + id = "ARES Interior"; + name = "ARES Chamber Lockdown"; + req_one_access_txt = "1;200;90;91;92"; + pixel_x = -24; + pixel_y = 8; + indestructible = 1 + }, +/obj/structure/machinery/door/poddoor/railing{ + id = "ARES Railing"; + unslashable = 0; + unacidable = 0; + open_layer = 2.1; + density = 0; + layer = 2.1; + closed_layer = 4 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 8 + }, +/area/almayer/command/airoom) "itR" = ( /obj/structure/pipes/standard/manifold/hidden/supply{ dir = 1 @@ -41339,6 +42207,18 @@ icon_state = "test_floor4" }, /area/almayer/shipboard/brig/main_office) +"iyH" = ( +/obj/structure/surface/table/reinforced/almayer_B{ + climbable = 0; + unacidable = 1; + unslashable = 1; + indestructible = 1; + desc = "A square metal surface resting on its fat metal bottom. You can't flip something that doesn't have legs. This one has a metal rail running above it, preventing something large passing over. Like you." + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "iyQ" = ( /turf/open/floor/almayer{ dir = 5; @@ -41745,13 +42625,6 @@ icon_state = "silver" }, /area/almayer/command/cichallway) -"iJH" = ( -/obj/structure/disposalpipe/down/almayer{ - dir = 4; - id = "almayerlink_OT_req" - }, -/turf/open/floor/almayer, -/area/almayer/lifeboat_pumps/south1) "iJS" = ( /obj/structure/machinery/cm_vending/gear/tl{ density = 0; @@ -42064,13 +42937,6 @@ icon_state = "plate" }, /area/almayer/hull/lower_hull/l_m_s) -"iRh" = ( -/obj/structure/disposalpipe/down/almayer{ - dir = 8; - id = "almayerlink_OT1_req" - }, -/turf/open/floor/almayer, -/area/almayer/lifeboat_pumps/south1) "iRr" = ( /obj/structure/machinery/light{ dir = 1 @@ -42409,6 +43275,23 @@ icon_state = "red" }, /area/almayer/command/lifeboat) +"iZw" = ( +/obj/effect/step_trigger/teleporter_vector{ + name = "Almayer_AresUp"; + vector_x = -97; + vector_y = 65 + }, +/obj/structure/platform{ + dir = 4 + }, +/obj/structure/stairs{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 4 + }, +/area/almayer/command/airoom) "iZG" = ( /obj/structure/window/framed/almayer/hull, /obj/structure/machinery/door/firedoor/border_only/almayer, @@ -42474,6 +43357,16 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/upper_hull/u_a_p) +"jaH" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/item/paper_bin/uscm{ + pixel_y = 6 + }, +/obj/item/tool/pen, +/turf/open/floor/almayer/no_build{ + icon_state = "plating" + }, +/area/almayer/command/airoom) "jaP" = ( /obj/structure/surface/table/almayer, /obj/structure/machinery/computer/cameras/almayer_network{ @@ -43251,6 +44144,26 @@ allow_construction = 0 }, /area/almayer/shipboard/brig/lobby) +"jqP" = ( +/obj/structure/machinery/door/poddoor/shutters/almayer{ + id = "ARES Interior"; + name = "\improper ARES Inner Chamber Shutters"; + plane = -7 + }, +/obj/effect/step_trigger/ares_alert/core, +/obj/structure/machinery/door/poddoor/almayer/blended/white/open{ + open_layer = 1.9; + id = "ARES Emergency"; + needs_power = 0; + name = "ARES Emergency Lockdown"; + layer = 3.2; + closed_layer = 3.2; + plane = -7 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "jre" = ( /obj/structure/closet/secure_closet/cargotech, /obj/item/clothing/accessory/storage/webbing, @@ -43286,6 +44199,14 @@ icon_state = "sterile_green_side" }, /area/almayer/medical/hydroponics) +"jtj" = ( +/obj/structure/machinery/status_display{ + pixel_y = 30 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "jtJ" = ( /obj/structure/machinery/door_control{ id = "laddernorthwest"; @@ -43375,6 +44296,12 @@ icon_state = "test_floor4" }, /area/almayer/squads/alpha) +"jvB" = ( +/obj/effect/step_trigger/clone_cleaner, +/turf/open/floor/almayer/no_build{ + dir = 4 + }, +/area/almayer/command/airoom) "jvI" = ( /obj/structure/reagent_dispensers/fueltank, /turf/open/floor/almayer{ @@ -43578,6 +44505,29 @@ icon_state = "sterile_green_side" }, /area/almayer/medical/lower_medical_lobby) +"jDV" = ( +/obj/effect/projector{ + name = "Almayer_AresDown"; + vector_x = 97; + vector_y = -65 + }, +/obj/structure/platform{ + dir = 4 + }, +/obj/structure/stairs{ + dir = 1; + icon_state = "ramptop" + }, +/obj/structure/machinery/door_control{ + id = "ARES StairsUpper"; + name = "ARES Core Access"; + req_one_access_txt = "19;200;90;91;92"; + pixel_x = 24 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "jEs" = ( /obj/structure/surface/table/almayer, /obj/item/tool/screwdriver{ @@ -44067,6 +45017,19 @@ icon_state = "plate" }, /area/almayer/hull/lower_hull/l_m_p) +"jRz" = ( +/obj/effect/step_trigger/teleporter/random{ + affect_ghosts = 1; + name = "tele_ground1"; + teleport_x = 180; + teleport_x_offset = 200; + teleport_y = 50; + teleport_y_offset = 80; + teleport_z = 1; + teleport_z_offset = 1 + }, +/turf/closed/wall/almayer/outer, +/area/space) "jRK" = ( /obj/structure/largecrate/random/case/double, /turf/open/floor/almayer{ @@ -44196,6 +45159,16 @@ icon_state = "plate" }, /area/almayer/living/bridgebunks) +"jUn" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/structure/machinery/door/window/southleft{ + desc = "A window, that is also a door. A windoor if you will. This one is stronger."; + health = 500; + name = "Reinforced Glass door"; + req_one_access_txt = "2;35" + }, +/turf/open/floor/almayer, +/area/almayer/engineering/engineering_workshop/hangar) "jUs" = ( /obj/effect/decal/warning_stripes{ icon_state = "NE-out"; @@ -44345,6 +45318,22 @@ icon_state = "mono" }, /area/almayer/hallways/vehiclehangar) +"jYR" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/structure/machinery/camera/autoname/almayer/containment/ares{ + dir = 4 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "jZd" = ( /obj/structure/pipes/vents/pump{ dir = 8; @@ -44543,9 +45532,19 @@ }, /area/almayer/engineering/upper_engineering) "kbH" = ( -/obj/structure/window/reinforced, -/turf/open/floor/almayer{ - icon_state = "tcomms" +/obj/effect/step_trigger/teleporter_vector{ + name = "Almayer_AresDown"; + vector_x = 97; + vector_y = -65 + }, +/obj/structure/platform{ + dir = 4 + }, +/obj/structure/stairs{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, /area/almayer/command/airoom) "kbV" = ( @@ -44676,6 +45675,9 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/hallways/starboard_hallway) +"kfU" = ( +/turf/open/floor/plating, +/area/almayer/powered/agent) "kfX" = ( /obj/effect/decal/warning_stripes{ icon_state = "SE-out"; @@ -44749,6 +45751,22 @@ icon_state = "orange" }, /area/almayer/engineering/upper_engineering/port) +"khJ" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/structure/machinery/camera/autoname/almayer/containment/ares{ + dir = 8 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "khS" = ( /obj/structure/machinery/light/small{ dir = 8 @@ -45019,6 +46037,10 @@ icon_state = "plating" }, /area/almayer/hull/lower_hull/l_a_p) +"kpc" = ( +/obj/structure/reagent_dispensers/watertank, +/turf/open/floor/plating, +/area/almayer/command/airoom) "kpl" = ( /obj/structure/machinery/door_control{ id = "cl_shutters"; @@ -45548,6 +46570,19 @@ icon_state = "red" }, /area/almayer/hallways/port_hallway) +"kzT" = ( +/obj/structure/machinery/door_control{ + id = "ARES StairsLower"; + name = "ARES Core Lockdown"; + req_one_access_txt = "19;200;90;91;92"; + pixel_x = -24; + pixel_y = -8 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 8 + }, +/area/almayer/command/airoom) "kAh" = ( /obj/structure/sign/safety/restrictedarea{ pixel_x = -17 @@ -45580,6 +46615,12 @@ icon_state = "red" }, /area/almayer/lifeboat_pumps/south2) +"kBy" = ( +/obj/structure/machinery/ares/processor, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "kBP" = ( /turf/open/floor/almayer{ dir = 9; @@ -45928,6 +46969,24 @@ icon_state = "test_floor4" }, /area/almayer/living/grunt_rnr) +"kKv" = ( +/obj/effect/projector{ + name = "Almayer_AresUp"; + vector_x = -97; + vector_y = 65 + }, +/obj/structure/platform{ + dir = 8 + }, +/obj/structure/stairs{ + dir = 1; + icon_state = "ramptop" + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 8 + }, +/area/almayer/command/airoom) "kKG" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -46273,6 +47332,21 @@ icon_state = "orange" }, /area/almayer/hallways/hangar) +"kSy" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "SW-out" + }, +/obj/structure/machinery/door_control{ + id = "ARES Mainframe Right"; + name = "ARES Mainframe Lockdown"; + req_one_access_txt = "200;91;92"; + pixel_x = -24; + pixel_y = 24 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "kSJ" = ( /obj/structure/disposalpipe/junction{ dir = 4; @@ -46481,6 +47555,12 @@ icon_state = "silver" }, /area/almayer/command/computerlab) +"kXj" = ( +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 4 + }, +/area/almayer/command/airoom) "kXu" = ( /turf/open/floor/almayer{ dir = 8; @@ -46681,6 +47761,12 @@ icon_state = "plate" }, /area/almayer/squads/charlie) +"lcg" = ( +/obj/structure/machinery/ares/substrate, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "lcy" = ( /obj/structure/pipes/standard/simple/hidden/supply{ dir = 4 @@ -46791,6 +47877,12 @@ /obj/structure/pipes/standard/simple/hidden/supply, /turf/open/floor/almayer, /area/almayer/shipboard/navigation) +"ley" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/turf/open/floor/almayer, +/area/almayer/lifeboat_pumps/south1) "leY" = ( /obj/structure/bed/sofa/south/white/left, /turf/open/floor/almayer{ @@ -46920,9 +48012,20 @@ /turf/open/floor/wood/ship, /area/almayer/living/basketball) "lin" = ( -/obj/structure/closet/firecloset, -/turf/open/floor/almayer{ - icon_state = "tcomms" +/obj/effect/projector{ + name = "Almayer_AresDown"; + vector_x = 97; + vector_y = -65 + }, +/obj/structure/platform{ + dir = 8 + }, +/obj/structure/stairs{ + dir = 1; + icon_state = "ramptop" + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, /area/almayer/command/airoom) "liJ" = ( @@ -47064,17 +48167,8 @@ }, /area/almayer/medical/medical_science) "lmz" = ( -/obj/structure/machinery/door_control{ - id = "areslockdowninterior"; - name = "ARES Lockdown"; - pixel_x = 25; - req_one_access_txt = "19" - }, -/obj/effect/landmark/start/working_joe, -/turf/open/floor/almayer{ - icon_state = "ai_floors" - }, -/area/almayer/command/airoom) +/turf/closed/wall/almayer/white/hull, +/area/space) "lmE" = ( /obj/structure/reagent_dispensers/fueltank/custom, /turf/open/floor/almayer{ @@ -47123,6 +48217,32 @@ icon_state = "kitchen" }, /area/almayer/engineering/upper_engineering) +"lnS" = ( +/obj/structure/sign/safety/rewire{ + pixel_y = 38 + }, +/obj/structure/sign/safety/fibre_optics{ + pixel_x = 14; + pixel_y = 38 + }, +/obj/structure/sign/safety/laser{ + pixel_y = 24 + }, +/obj/structure/sign/safety/terminal{ + pixel_y = 24; + pixel_x = 14 + }, +/obj/structure/machinery/door_control{ + id = "ARES Operations Left"; + name = "ARES Operations Shutter"; + req_one_access_txt = "1;200;91;92"; + pixel_x = 24; + pixel_y = -8 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "lok" = ( /obj/structure/machinery/cm_vending/clothing/marine/charlie, /obj/structure/sign/safety/cryo{ @@ -47972,6 +49092,10 @@ }, /turf/open/floor/almayer, /area/almayer/squads/alpha_bravo_shared) +"lEW" = ( +/obj/structure/disposalpipe/segment, +/turf/closed/wall/almayer, +/area/almayer/engineering/engineering_workshop/hangar) "lFb" = ( /obj/structure/pipes/standard/simple/hidden/supply{ dir = 4 @@ -48897,6 +50021,22 @@ icon_state = "red" }, /area/almayer/shipboard/brig/main_office) +"mdW" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/effect/decal/warning_stripes{ + icon_state = "W"; + pixel_x = -1 + }, +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/item/folder/white, +/obj/item/folder/white, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "meu" = ( /obj/structure/pipes/standard/simple/hidden/supply{ dir = 4 @@ -49182,10 +50322,15 @@ }, /area/almayer/engineering/port_atmos) "mlb" = ( -/obj/structure/machinery/status_display{ - pixel_y = 30 +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 }, -/turf/open/floor/almayer{ +/obj/effect/decal/warning_stripes{ + icon_state = "NE-out"; + pixel_y = 1 + }, +/turf/open/floor/almayer/no_build{ icon_state = "tcomms" }, /area/almayer/command/airoom) @@ -49889,6 +51034,26 @@ icon_state = "plate" }, /area/almayer/hallways/port_hallway) +"mFN" = ( +/obj/effect/step_trigger/ares_alert/mainframe, +/obj/structure/machinery/door/poddoor/shutters/almayer{ + id = "ARES Mainframe Right"; + name = "\improper ARES Mainframe Shutters"; + plane = -7 + }, +/obj/structure/machinery/door/poddoor/almayer/blended/white/open{ + open_layer = 1.9; + id = "ARES Emergency"; + needs_power = 0; + name = "ARES Emergency Lockdown"; + layer = 3.2; + closed_layer = 3.2; + plane = -7 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "mFO" = ( /obj/structure/pipes/standard/simple/hidden/supply{ dir = 4 @@ -49964,6 +51129,12 @@ }, /turf/open/floor/wood/ship, /area/almayer/medical/medical_science) +"mHE" = ( +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 8 + }, +/area/almayer/command/airoom) "mHO" = ( /obj/structure/machinery/light, /turf/open/floor/almayer, @@ -50200,6 +51371,10 @@ icon_state = "plate" }, /area/almayer/living/pilotbunks) +"mLE" = ( +/obj/effect/landmark/start/working_joe, +/turf/open/floor/plating, +/area/almayer/command/airoom) "mLF" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -50333,8 +51508,7 @@ }, /area/almayer/engineering/laundry) "mOi" = ( -/obj/structure/blocker/invisible_wall, -/turf/closed/wall/almayer, +/turf/closed/wall/almayer/outer, /area/almayer/command/airoom) "mOr" = ( /obj/structure/surface/table/almayer, @@ -50449,6 +51623,34 @@ icon_state = "green" }, /area/almayer/hallways/aft_hallway) +"mRn" = ( +/obj/structure/machinery/door/poddoor/shutters/almayer{ + id = "ARES Interior"; + name = "\improper ARES Inner Chamber Shutters"; + plane = -7 + }, +/obj/effect/step_trigger/ares_alert/core, +/obj/structure/machinery/door/poddoor/almayer/blended/white/open{ + open_layer = 1.9; + id = "ARES Emergency"; + needs_power = 0; + name = "ARES Emergency Lockdown"; + layer = 3.2; + closed_layer = 3.2; + plane = -7 + }, +/obj/structure/sign/safety/terminal{ + pixel_y = -8; + pixel_x = -18 + }, +/obj/structure/sign/safety/fibre_optics{ + pixel_x = -18; + pixel_y = 6 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "mRW" = ( /turf/open/floor/almayer/research/containment/corner1, /area/almayer/medical/containment/cell/cl) @@ -50576,6 +51778,27 @@ icon_state = "test_floor4" }, /area/almayer/squads/bravo) +"mUz" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/structure/machinery/computer/cameras/almayer/ares{ + dir = 8; + pixel_x = 17 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) +"mUC" = ( +/obj/structure/machinery/light{ + dir = 4; + unacidable = 1; + unslashable = 1; + invisibility = 101 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "mUQ" = ( /obj/structure/largecrate/random/barrel/red, /turf/open/floor/almayer{ @@ -50712,6 +51935,14 @@ }, /turf/open/floor/almayer, /area/almayer/hull/upper_hull/u_f_p) +"mYv" = ( +/obj/structure/disposalpipe/sortjunction{ + dir = 4; + negdir = 4; + posdir = 1 + }, +/turf/closed/wall/almayer, +/area/almayer/squads/req) "mYw" = ( /obj/structure/sign/safety/escapepod{ pixel_x = -17; @@ -51996,8 +53227,6 @@ /obj/item/ammo_magazine/smg/m39, /obj/item/ammo_magazine/smg/m39, /obj/item/ammo_magazine/smg/m39, -/obj/effect/landmark/wo_supplies/guns/common/m39, -/obj/effect/landmark/wo_supplies/guns/common/m39, /obj/item/ammo_magazine/smg/m39, /obj/item/ammo_magazine/smg/m39, /obj/structure/sign/safety/ammunition{ @@ -52007,6 +53236,8 @@ /obj/structure/sign/safety/hazard{ pixel_y = 32 }, +/obj/item/weapon/gun/smg/m39, +/obj/item/weapon/gun/smg/m39, /turf/open/floor/almayer{ icon_state = "redfull" }, @@ -52339,6 +53570,15 @@ icon_state = "plate" }, /area/almayer/hull/upper_hull/u_a_p) +"nJH" = ( +/obj/structure/machinery/computer/cameras/almayer/ares{ + dir = 8; + pixel_x = 17 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "plating" + }, +/area/almayer/command/airoom) "nKq" = ( /obj/structure/machinery/status_display{ pixel_x = 16; @@ -52423,6 +53663,20 @@ icon_state = "bluefull" }, /area/almayer/living/briefing) +"nMq" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, +/obj/structure/machinery/computer/working_joe{ + dir = 8; + pixel_x = 17 + }, +/turf/open/floor/almayer{ + dir = 4; + icon_state = "silver" + }, +/area/almayer/hallways/aft_hallway) "nMu" = ( /turf/open/floor/almayer{ dir = 9; @@ -52838,6 +54092,22 @@ "nXP" = ( /turf/closed/wall/almayer/outer, /area/almayer/hull/lower_hull/l_f_s) +"nXU" = ( +/obj/structure/machinery/door/airlock/almayer/marine/requisitions{ + dir = 1; + name = "\improper Requisitions Storage" + }, +/obj/structure/machinery/door/firedoor/border_only/almayer{ + dir = 1 + }, +/obj/structure/disposalpipe/up/almayer{ + dir = 4; + id = "almayerlink_OT1_req" + }, +/turf/open/floor/almayer{ + icon_state = "test_floor4" + }, +/area/almayer/squads/req) "nYc" = ( /obj/effect/decal/warning_stripes{ icon_state = "N"; @@ -53010,6 +54280,34 @@ }, /turf/open/floor/carpet, /area/almayer/living/commandbunks) +"ocB" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/structure/sign/safety/terminal{ + pixel_y = 24; + pixel_x = 14 + }, +/obj/structure/sign/safety/fibre_optics{ + pixel_x = 14; + pixel_y = 38 + }, +/obj/structure/machinery/computer/working_joe{ + dir = 8; + pixel_x = 17; + ticket_console = 1 + }, +/obj/structure/sign/safety/laser{ + pixel_y = 24 + }, +/obj/structure/sign/safety/rewire{ + pixel_y = 38 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "oda" = ( /obj/structure/surface/table/reinforced/almayer_B, /obj/item/device/radio{ @@ -53708,6 +55006,17 @@ icon_state = "plate" }, /area/almayer/hallways/hangar) +"osy" = ( +/obj/effect/step_trigger/clone_cleaner, +/obj/structure/machinery/light{ + dir = 4 + }, +/obj/structure/platform_decoration, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 4 + }, +/area/almayer/command/airoom) "osz" = ( /obj/structure/machinery/door/firedoor/border_only/almayer, /obj/structure/pipes/standard/simple/hidden/supply{ @@ -53802,6 +55111,19 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/upper_hull/u_a_s) +"our" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/item/paper_bin/uscm{ + pixel_y = 6 + }, +/obj/item/tool/pen, +/obj/structure/machinery/light{ + dir = 4 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "ouB" = ( /obj/structure/bed/sofa/vert/grey/bot, /turf/open/floor/almayer, @@ -54372,13 +55694,26 @@ /turf/open/floor/plating/plating_catwalk, /area/almayer/hallways/hangar) "oJR" = ( -/obj/structure/closet/toolcloset, -/obj/structure/machinery/firealarm{ - dir = 8; +/obj/effect/projector{ + name = "Almayer_AresDown"; + vector_x = 97; + vector_y = -65 + }, +/obj/structure/platform{ + dir = 8 + }, +/obj/structure/stairs{ + dir = 1; + icon_state = "ramptop" + }, +/obj/structure/machinery/door_control{ + id = "ARES StairsUpper"; + name = "ARES Core Access"; + req_one_access_txt = "19;200;90;91;92"; pixel_x = -24 }, -/turf/open/floor/almayer{ - icon_state = "tcomms" +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, /area/almayer/command/airoom) "oKb" = ( @@ -54428,6 +55763,24 @@ /obj/effect/landmark/late_join/bravo, /turf/open/floor/plating/plating_catwalk, /area/almayer/squads/alpha) +"oLm" = ( +/obj/structure/machinery/door_control{ + id = "ARES StairsLower"; + name = "ARES Core Lockdown"; + req_one_access_txt = "19;200;90;91;92"; + pixel_x = -24; + pixel_y = 8 + }, +/obj/structure/machinery/camera/autoname/almayer/containment/ares{ + dir = 4; + pixel_y = -8 + }, +/obj/effect/step_trigger/clone_cleaner, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 8 + }, +/area/almayer/command/airoom) "oLv" = ( /obj/structure/sign/safety/medical{ pixel_x = 8; @@ -54721,6 +56074,16 @@ icon_state = "plate" }, /area/almayer/living/gym) +"oRV" = ( +/obj/structure/blocker/invisible_wall, +/obj/effect/decal/warning_stripes{ + icon_state = "W"; + pixel_x = -1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "oRZ" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -55009,7 +56372,6 @@ "pbh" = ( /obj/structure/disposalpipe/segment, /obj/structure/pipes/standard/simple/hidden/supply, -/obj/structure/closet/secure_closet/warden, /obj/structure/machinery/light{ dir = 4 }, @@ -55215,6 +56577,12 @@ }, /turf/open/floor/almayer, /area/almayer/living/briefing) +"pfT" = ( +/obj/structure/machinery/ares/processor/interface, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "pgo" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -55228,12 +56596,20 @@ /turf/closed/wall/almayer, /area/almayer/lifeboat_pumps/south1) "pgH" = ( -/obj/structure/window/reinforced{ - dir = 4; - health = 80 +/obj/effect/projector{ + name = "Almayer_AresDown"; + vector_x = 97; + vector_y = -65 }, -/turf/open/floor/almayer{ - icon_state = "tcomms" +/obj/structure/platform{ + dir = 4 + }, +/obj/structure/stairs{ + dir = 1; + icon_state = "ramptop" + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, /area/almayer/command/airoom) "pha" = ( @@ -55429,6 +56805,18 @@ icon_state = "plate" }, /area/almayer/living/briefing) +"pmV" = ( +/obj/structure/prop/server_equipment/yutani_server/broken{ + pixel_y = 16; + name = "server tower"; + desc = "A powerful server tower housing various AI functions."; + density = 0 + }, +/obj/structure/pipes/standard/simple/hidden/supply/no_boom, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "pno" = ( /obj/structure/sign/safety/escapepod{ pixel_y = 32 @@ -56400,6 +57788,19 @@ icon_state = "green" }, /area/almayer/hallways/port_hallway) +"pJR" = ( +/obj/effect/step_trigger/teleporter_vector{ + name = "Almayer_AresUp"; + vector_x = -97; + vector_y = 65 + }, +/obj/structure/stairs{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + dir = 4 + }, +/area/almayer/command/airoom) "pJW" = ( /obj/structure/disposalpipe/segment, /obj/structure/machinery/door/airlock/almayer/maint{ @@ -57026,13 +58427,15 @@ /turf/open/floor/plating/plating_catwalk, /area/almayer/squads/charlie) "pYi" = ( -/obj/structure/machinery/telecomms/processor/preset_four, -/obj/structure/sign/safety/laser{ - pixel_x = 8; - pixel_y = 32 +/obj/structure/machinery/light{ + dir = 4 }, -/turf/open/floor/almayer{ - icon_state = "tcomms" +/obj/structure/pipes/vents/pump/no_boom{ + dir = 8 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 4 }, /area/almayer/command/airoom) "pYo" = ( @@ -57475,6 +58878,17 @@ icon_state = "dark_sterile" }, /area/almayer/medical/lower_medical_lobby) +"qit" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/structure/machinery/light{ + dir = 8 + }, +/obj/item/paper_bin/uscm, +/obj/item/tool/pen, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "qiy" = ( /obj/structure/pipes/standard/manifold/hidden/supply{ dir = 1 @@ -58014,6 +59428,19 @@ icon_state = "plate" }, /area/almayer/living/offices) +"qwJ" = ( +/obj/structure/machinery/door_control{ + id = "ARES Operations Left"; + name = "ARES Operations Shutter"; + req_one_access_txt = "1;200;91;92"; + pixel_x = -24; + pixel_y = -8 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 8 + }, +/area/almayer/command/airoom) "qxA" = ( /obj/structure/closet/firecloset, /turf/open/floor/almayer{ @@ -58639,6 +60066,12 @@ icon_state = "blue" }, /area/almayer/hallways/aft_hallway) +"qLS" = ( +/obj/structure/pipes/standard/manifold/hidden/supply/no_boom, +/turf/open/floor/almayer/no_build{ + dir = 4 + }, +/area/almayer/command/airoom) "qLV" = ( /obj/structure/surface/table/almayer, /obj/structure/machinery/computer/disk_reader, @@ -58838,6 +60271,18 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/lower_hull/l_f_p) +"qQS" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/obj/structure/machinery/light{ + dir = 8 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "qRj" = ( /obj/structure/disposalpipe/segment{ dir = 1; @@ -59112,6 +60557,13 @@ icon_state = "green" }, /area/almayer/hallways/port_hallway) +"qYC" = ( +/obj/structure/disposalpipe/down/almayer{ + dir = 4; + id = "almayerlink_OT_req" + }, +/turf/open/floor/almayer, +/area/almayer/lifeboat_pumps/south1) "qYG" = ( /turf/open/floor/almayer{ icon_state = "mono" @@ -59244,6 +60696,18 @@ icon_state = "plate" }, /area/almayer/hull/lower_hull/l_f_s) +"rby" = ( +/obj/structure/machinery/door_control{ + id = "ARES Mainframe Left"; + name = "ARES Mainframe Lockdown"; + req_one_access_txt = "200;91;92"; + pixel_x = 24; + pixel_y = -24 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "rbB" = ( /turf/open/floor/almayer{ icon_state = "silvercorner" @@ -59427,10 +60891,6 @@ icon_state = "test_floor4" }, /area/almayer/hull/upper_hull/u_m_s) -"rfi" = ( -/obj/structure/disposalpipe/segment, -/turf/closed/wall/almayer, -/area/almayer/engineering/engineering_workshop/hangar) "rfI" = ( /obj/structure/sign/safety/airlock{ pixel_y = -32 @@ -59755,9 +61215,25 @@ /obj/structure/pipes/standard/simple/hidden/supply, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/lower_hull/l_m_s) +"rna" = ( +/turf/closed/wall/almayer/white, +/area/almayer/command/airoom) "rne" = ( /turf/open/floor/carpet, /area/almayer/command/corporateliason) +"rnH" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/structure/machinery/computer/crew/alt{ + pixel_x = 17; + dir = 8 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "rnM" = ( /obj/structure/machinery/vending/cigarette, /turf/open/floor/almayer{ @@ -59797,6 +61273,20 @@ icon_state = "plate" }, /area/almayer/shipboard/port_point_defense) +"roH" = ( +/obj/effect/step_trigger/ares_alert/terminals, +/obj/structure/machinery/door/poddoor/shutters/almayer{ + id = "ARES Operations Left"; + name = "\improper ARES Operations Shutters"; + dir = 4 + }, +/obj/structure/pipes/standard/simple/hidden/supply/no_boom{ + dir = 4 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "roU" = ( /obj/structure/disposalpipe/segment{ dir = 8; @@ -60330,6 +61820,14 @@ icon_state = "red" }, /area/almayer/shipboard/brig/main_office) +"rCi" = ( +/obj/structure/machinery/camera/autoname/almayer/containment/ares{ + dir = 8 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "rCp" = ( /obj/structure/largecrate/random/case/small, /obj/structure/machinery/light/small{ @@ -60340,12 +61838,19 @@ }, /area/almayer/hull/upper_hull/u_a_p) "rCw" = ( -/obj/structure/window/reinforced, -/obj/structure/machinery/light{ +/obj/effect/step_trigger/teleporter_vector{ + name = "Almayer_AresDown"; + vector_x = 97; + vector_y = -65 + }, +/obj/structure/platform{ dir = 8 }, -/turf/open/floor/almayer{ - icon_state = "tcomms" +/obj/structure/stairs{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, /area/almayer/command/airoom) "rCK" = ( @@ -60844,16 +62349,11 @@ }, /area/almayer/medical/containment/cell/cl) "rNF" = ( -/obj/structure/sign/safety/fibre_optics{ - pixel_x = 32; - pixel_y = 7 - }, -/obj/structure/sign/safety/terminal{ - pixel_x = 32; - pixel_y = -8 +/obj/structure/machinery/light{ + unacidable = 1; + unslashable = 1 }, -/obj/effect/landmark/start/working_joe, -/turf/open/floor/almayer{ +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) @@ -61406,6 +62906,9 @@ icon_state = "test_floor4" }, /area/almayer/engineering/upper_engineering/notunnel) +"sbJ" = ( +/turf/closed/wall/almayer/white/hull, +/area/almayer/powered/agent) "sbM" = ( /obj/structure/pipes/vents/scrubber{ dir = 4 @@ -61480,16 +62983,30 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/lower_hull/l_m_p) -"sdl" = ( -/obj/structure/machinery/telecomms/processor/preset_four, -/obj/structure/sign/safety/fibre_optics{ - pixel_x = 8; - pixel_y = 32 +"scS" = ( +/obj/structure/machinery/status_display{ + pixel_y = 30 }, -/turf/open/floor/almayer{ - icon_state = "tcomms" +/obj/structure/machinery/light{ + dir = 8; + unacidable = 1; + unslashable = 1; + invisibility = 101 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, /area/almayer/command/airoom) +"sdl" = ( +/obj/structure/surface/rack{ + pixel_y = 16; + density = 0 + }, +/obj/item/tool/wet_sign, +/obj/item/tool/wet_sign, +/obj/item/tool/wet_sign, +/turf/open/floor/plating, +/area/almayer/command/airoom) "sdn" = ( /obj/structure/sink{ dir = 4; @@ -61920,6 +63437,10 @@ }, /area/almayer/shipboard/brig/cells) "soq" = ( +/obj/structure/machinery/computer/working_joe{ + dir = 4; + pixel_x = -17 + }, /turf/open/floor/almayer{ icon_state = "cargo" }, @@ -62521,36 +64042,6 @@ icon_state = "silvercorner" }, /area/almayer/hallways/aft_hallway) -"sDL" = ( -/obj/structure/closet/cabinet, -/obj/item/clothing/under/liaison_suit/formal, -/obj/item/clothing/under/liaison_suit, -/obj/item/clothing/under/liaison_suit/outing, -/obj/item/clothing/under/liaison_suit/suspenders, -/obj/item/clothing/under/blackskirt{ - desc = "A stylish skirt, in a business-black and red colour scheme."; - name = "liaison's skirt" - }, -/obj/item/clothing/under/suit_jacket/charcoal{ - desc = "A professional black suit and blue tie. A combination popular among government agents and corporate Yes-Men alike."; - name = "liaison's black suit" - }, -/obj/item/clothing/under/suit_jacket/navy{ - desc = "A navy suit and red tie, intended for the Almayer's finest. And accountants."; - name = "liaison's navy suit" - }, -/obj/item/clothing/under/suit_jacket/trainee, -/obj/item/clothing/gloves/black, -/obj/item/clothing/gloves/marine/dress, -/obj/item/clothing/glasses/sunglasses/big, -/obj/item/clothing/accessory/blue, -/obj/item/clothing/accessory/red, -/obj/item/clothing/shoes/dress, -/obj/structure/machinery/status_display{ - pixel_x = -32 - }, -/turf/open/floor/wood/ship, -/area/almayer/command/corporateliason) "sDM" = ( /turf/open/floor/almayer{ dir = 9; @@ -62633,6 +64124,14 @@ icon_state = "orange" }, /area/almayer/hallways/hangar) +"sEK" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "E" + }, +/turf/open/floor/almayer/no_build{ + icon_state = "tcomms" + }, +/area/almayer/command/airoom) "sEM" = ( /obj/structure/surface/table/reinforced/almayer_B, /obj/item/device/radio/intercom{ @@ -62723,6 +64222,12 @@ /obj/structure/mirror, /turf/closed/wall/almayer, /area/almayer/living/gym) +"sGZ" = ( +/obj/structure/closet/firecloset, +/turf/open/floor/almayer{ + icon_state = "silverfull" + }, +/area/almayer/command/airoom) "sHg" = ( /obj/structure/surface/rack, /obj/item/storage/backpack/marine/satchel{ @@ -62782,11 +64287,16 @@ }, /area/almayer/squads/alpha) "sIf" = ( -/obj/structure/machinery/door/window/southleft{ - req_access_txt = "19" +/obj/effect/step_trigger/teleporter_vector{ + name = "Almayer_AresDown"; + vector_x = 97; + vector_y = -65 }, -/turf/open/floor/almayer{ - icon_state = "tcomms" +/obj/structure/stairs{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, /area/almayer/command/airoom) "sIk" = ( @@ -62884,6 +64394,15 @@ icon_state = "sterile_green_side" }, /area/almayer/medical/morgue) +"sKY" = ( +/obj/structure/bed/chair/office/dark{ + dir = 8; + layer = 3.25 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "sLo" = ( /obj/structure/stairs/perspective{ dir = 1; @@ -63196,6 +64715,12 @@ }, /turf/open/floor/almayer, /area/almayer/living/briefing) +"sTV" = ( +/obj/structure/machinery/power/apc/almayer/hardened{ + dir = 1 + }, +/turf/open/floor/plating, +/area/almayer/command/airoom) "sUg" = ( /obj/structure/surface/table/almayer, /obj/structure/flora/pottedplant{ @@ -63419,8 +64944,6 @@ /obj/effect/decal/warning_stripes{ icon_state = "N" }, -/obj/effect/landmark/wo_supplies/guns/common/m39, -/obj/effect/landmark/wo_supplies/guns/common/m39, /obj/item/ammo_magazine/smg/m39, /obj/item/ammo_magazine/smg/m39, /obj/item/ammo_magazine/smg/m39, @@ -63428,6 +64951,8 @@ /obj/item/ammo_magazine/smg/m39, /obj/item/ammo_magazine/smg/m39, /obj/item/ammo_magazine/smg/m39, +/obj/item/weapon/gun/smg/m39, +/obj/item/weapon/gun/smg/m39, /turf/open/floor/plating/almayer, /area/almayer/shipboard/brig/armory) "sYC" = ( @@ -64027,6 +65552,16 @@ }, /turf/open/floor/almayer, /area/almayer/living/briefing) +"tmK" = ( +/obj/structure/machinery/door/airlock/almayer/maint{ + dir = 1; + req_one_access_txt = "91;92"; + req_one_access = null + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "tnb" = ( /obj/structure/bed/chair/comfy/black, /turf/open/floor/almayer{ @@ -64345,6 +65880,12 @@ icon_state = "orange" }, /area/almayer/engineering/upper_engineering/port) +"tte" = ( +/obj/structure/pipes/vents/pump/no_boom{ + welded = 1 + }, +/turf/open/floor/plating, +/area/almayer/powered/agent) "ttM" = ( /obj/item/device/radio/intercom{ freerange = 1; @@ -64805,13 +66346,19 @@ /turf/open/floor/plating/plating_catwalk, /area/almayer/squads/charlie) "tFe" = ( -/obj/structure/machinery/door/airlock/almayer/secure/reinforced{ - dir = 1; - name = "\improper ARES Mainframe"; - req_access = null; - req_one_access_txt = "2;7" +/obj/effect/step_trigger/clone_cleaner, +/obj/structure/machinery/door/poddoor/shutters/almayer{ + id = "ARES StairsUpper"; + name = "\improper ARES Core Shutters"; + plane = -7 }, -/turf/open/floor/almayer{ +/obj/structure/machinery/door/poddoor/almayer/blended/open{ + id = "ARES Emergency"; + name = "ARES Emergency Lockdown"; + open_layer = 1.9; + plane = -7 + }, +/turf/open/floor/almayer/no_build{ icon_state = "test_floor4" }, /area/almayer/command/airoom) @@ -64956,6 +66503,12 @@ icon_state = "silver" }, /area/almayer/shipboard/brig/cic_hallway) +"tHu" = ( +/obj/structure/closet/toolcloset, +/turf/open/floor/almayer{ + icon_state = "silverfull" + }, +/area/almayer/command/airoom) "tHv" = ( /turf/open/floor/almayer{ dir = 8; @@ -65804,6 +67357,15 @@ /obj/item/frame/table, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/lower_hull/l_a_p) +"ubA" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "E"; + pixel_x = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "ucp" = ( /obj/structure/window/framed/almayer, /turf/open/floor/plating, @@ -65814,12 +67376,6 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/lifeboat_pumps/south2) -"uda" = ( -/obj/structure/disposalpipe/up/almayer{ - id = "almayerlink_OT_req" - }, -/turf/closed/wall/almayer, -/area/almayer/engineering/engineering_workshop/hangar) "udi" = ( /turf/open/floor/almayer{ icon_state = "red" @@ -67898,6 +69454,14 @@ icon_state = "sterile_green_corner" }, /area/almayer/medical/containment) +"uVv" = ( +/obj/structure/pipes/standard/manifold/hidden/supply/no_boom{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "uVA" = ( /turf/open/floor/almayer{ dir = 4; @@ -68326,6 +69890,11 @@ icon_state = "orange" }, /area/almayer/squads/bravo) +"vfB" = ( +/turf/open/floor/almayer/no_build{ + dir = 4 + }, +/area/almayer/command/airoom) "vfJ" = ( /obj/structure/surface/rack, /obj/item/frame/table, @@ -68432,10 +70001,13 @@ }, /area/almayer/hull/lower_hull/l_m_p) "vhe" = ( -/obj/structure/sign/kiddieplaque{ - pixel_x = -32 +/obj/structure/prop/server_equipment/yutani_server{ + pixel_y = 16; + name = "server tower"; + desc = "A powerful server tower housing various AI functions."; + density = 0 }, -/turf/open/floor/almayer{ +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) @@ -68551,6 +70123,14 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/living/port_emb) +"viB" = ( +/obj/structure/pipes/standard/manifold/hidden/supply/no_boom{ + dir = 1 + }, +/turf/open/floor/plating/plating_catwalk{ + allow_construction = 0 + }, +/area/almayer/command/airoom) "viJ" = ( /obj/structure/machinery/door/airlock/almayer/maint, /turf/open/floor/almayer{ @@ -68840,6 +70420,14 @@ icon_state = "dark_sterile" }, /area/almayer/engineering/laundry) +"vqO" = ( +/obj/structure/machinery/light/small{ + dir = 4 + }, +/turf/open/floor/almayer{ + icon_state = "plate" + }, +/area/almayer/hull/upper_hull/u_a_p) "vqW" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -69306,6 +70894,18 @@ icon_state = "sterile_green_corner" }, /area/almayer/medical/containment) +"vAU" = ( +/obj/structure/machinery/light{ + dir = 8 + }, +/obj/structure/pipes/vents/scrubber/no_boom{ + dir = 4 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 8 + }, +/area/almayer/command/airoom) "vBm" = ( /turf/closed/wall/almayer/reinforced, /area/almayer/shipboard/brig/main_office) @@ -69494,6 +71094,18 @@ icon_state = "orangefull" }, /area/almayer/living/briefing) +"vHa" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/structure/machinery/computer/ares_console{ + pixel_x = 9 + }, +/obj/structure/machinery/computer/view_objectives{ + pixel_x = -9 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "plating" + }, +/area/almayer/command/airoom) "vHh" = ( /obj/structure/pipes/standard/simple/hidden/supply, /obj/item/tool/warning_cone{ @@ -70286,6 +71898,20 @@ }, /turf/open/floor/plating, /area/almayer/engineering/upper_engineering/port) +"vXh" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "N"; + pixel_y = 1 + }, +/obj/structure/machinery/computer/working_joe{ + dir = 4; + pixel_x = -17; + ticket_console = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "vXQ" = ( /obj/structure/pipes/standard/simple/hidden/supply{ dir = 1 @@ -70916,6 +72542,30 @@ icon_state = "bluefull" }, /area/almayer/command/cichallway) +"wkM" = ( +/obj/structure/machinery/door/poddoor/shutters/almayer{ + id = "ARES StairsLower"; + name = "\improper ARES Core Shutters"; + plane = -7 + }, +/obj/effect/step_trigger/ares_alert/public{ + alert_message = "Caution: Movement detected in ARES Core."; + cooldown_duration = 1200; + alert_id = "AresStairs" + }, +/obj/structure/machinery/door/poddoor/almayer/blended/white/open{ + open_layer = 1.9; + id = "ARES Emergency"; + needs_power = 0; + name = "ARES Emergency Lockdown"; + layer = 3.2; + closed_layer = 3.2; + plane = -7 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "test_floor4" + }, +/area/almayer/command/airoom) "wkX" = ( /obj/structure/pipes/standard/simple/hidden/supply{ dir = 6 @@ -71058,6 +72708,10 @@ icon_state = "cargo" }, /area/almayer/living/bridgebunks) +"wnh" = ( +/obj/structure/window/framed/almayer/white/hull, +/turf/open/floor/plating, +/area/almayer/command/airoom) "wnL" = ( /obj/item/stack/tile/carpet{ amount = 12 @@ -71135,6 +72789,14 @@ icon_state = "rasputin3" }, /area/almayer/powered/agent) +"wpw" = ( +/obj/structure/bed/chair/comfy/ares{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "plating" + }, +/area/almayer/command/airoom) "wpz" = ( /obj/item/device/radio/intercom{ freerange = 1; @@ -71538,6 +73200,18 @@ }, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/lower_hull/l_m_s) +"wyQ" = ( +/obj/structure/surface/table/reinforced/almayer_B, +/obj/structure/machinery/door_control{ + id = "ARES Emergency"; + name = "ARES Emergency Lockdown"; + req_one_access_txt = "91;92"; + indestructible = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "plating" + }, +/area/almayer/command/airoom) "wza" = ( /obj/structure/machinery/cm_vending/clothing/vehicle_crew, /turf/open/floor/almayer{ @@ -71627,11 +73301,19 @@ }, /area/almayer/shipboard/brig/processing) "wCT" = ( -/obj/structure/machinery/power/apc/almayer/hardened{ +/obj/effect/step_trigger/teleporter_vector{ + name = "Almayer_AresDown"; + vector_x = 97; + vector_y = -65 + }, +/obj/structure/machinery/light{ dir = 1 }, -/turf/open/floor/almayer{ - icon_state = "tcomms" +/obj/structure/stairs{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" }, /area/almayer/command/airoom) "wDl" = ( @@ -71969,6 +73651,9 @@ desc = "A small coin, bearing the falling falcons insignia."; name = "falling falcons challenge coin" }, +/obj/structure/machinery/light/small{ + dir = 8 + }, /turf/open/floor/almayer{ icon_state = "plate" }, @@ -72458,11 +74143,11 @@ /obj/effect/decal/warning_stripes{ icon_state = "N" }, -/obj/effect/landmark/wo_supplies/guns/common/m39, -/obj/effect/landmark/wo_supplies/guns/common/m39, /obj/item/ammo_magazine/smg/m39, /obj/item/ammo_magazine/smg/m39, /obj/item/ammo_magazine/smg/m39, +/obj/item/weapon/gun/smg/m39, +/obj/item/weapon/gun/smg/m39, /turf/open/floor/plating/almayer, /area/almayer/shipboard/brig/armory) "wVy" = ( @@ -72844,10 +74529,13 @@ }, /area/almayer/living/gym) "xbN" = ( -/obj/structure/machinery/telecomms/processor/preset_four, -/turf/open/floor/almayer{ - icon_state = "tcomms" +/obj/structure/surface/rack{ + pixel_y = 16; + density = 0 }, +/obj/structure/janitorialcart, +/obj/item/tool/mop, +/turf/open/floor/plating, /area/almayer/command/airoom) "xcp" = ( /obj/structure/stairs/perspective{ @@ -73648,6 +75336,20 @@ icon_state = "test_floor4" }, /area/almayer/squads/charlie) +"xvM" = ( +/obj/structure/machinery/door_control{ + id = "ARES StairsLower"; + name = "ARES Core Lockdown"; + req_one_access_txt = "19;200;90;91;92"; + pixel_x = 24; + pixel_y = 8 + }, +/obj/effect/step_trigger/clone_cleaner, +/turf/open/floor/almayer/no_build{ + icon_state = "silver"; + dir = 4 + }, +/area/almayer/command/airoom) "xvX" = ( /obj/structure/machinery/cm_vending/gear/leader, /turf/open/floor/almayer{ @@ -74045,6 +75747,12 @@ icon_state = "plate" }, /area/almayer/hull/upper_hull/u_f_s) +"xDC" = ( +/obj/structure/pipes/standard/simple/hidden/supply/no_boom, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "xEc" = ( /turf/open/floor/almayer{ dir = 9; @@ -74591,8 +76299,8 @@ }, /area/almayer/shipboard/brig/perma) "xQV" = ( -/obj/effect/landmark/start/working_joe, -/turf/open/floor/almayer{ +/obj/effect/step_trigger/clone_cleaner, +/turf/open/floor/almayer/no_build{ icon_state = "ai_floors" }, /area/almayer/command/airoom) @@ -74870,6 +76578,19 @@ icon_state = "plate" }, /area/almayer/command/combat_correspondent) +"xVc" = ( +/obj/effect/step_trigger/clone_cleaner, +/obj/structure/machinery/door_control{ + id = "ARES StairsUpper"; + name = "ARES Core Access"; + req_one_access_txt = "1;200;90;91;92"; + pixel_y = 24; + pixel_x = 24 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "xVj" = ( /obj/structure/surface/table/almayer, /obj/item/tool/weldingtool{ @@ -75091,6 +76812,23 @@ /obj/structure/largecrate/random/case/double, /turf/open/floor/plating/plating_catwalk, /area/almayer/hull/lower_hull/l_m_s) +"yaQ" = ( +/obj/structure/pipes/standard/simple/hidden/supply/no_boom{ + dir = 9 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) +"yaZ" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "S"; + layer = 3.3 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "ybb" = ( /obj/structure/surface/table/almayer, /obj/item/storage/box/ids{ @@ -75214,6 +76952,15 @@ icon_state = "mono" }, /area/almayer/lifeboat_pumps/north2) +"ydI" = ( +/obj/effect/decal/warning_stripes{ + icon_state = "W"; + pixel_x = -1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "ydM" = ( /obj/structure/window{ dir = 8 @@ -75381,6 +77128,17 @@ icon_state = "red" }, /area/almayer/hallways/starboard_hallway) +"yit" = ( +/obj/structure/machinery/light{ + dir = 4 + }, +/obj/structure/pipes/vents/pump/no_boom{ + dir = 1 + }, +/turf/open/floor/almayer/no_build{ + icon_state = "ai_floors" + }, +/area/almayer/command/airoom) "yiC" = ( /obj/structure/surface/table/almayer, /obj/structure/flora/pottedplant{ @@ -101491,8 +103249,8 @@ gfW bUe cbR ccr -uda -rfi +hcC +lEW aqd bWM bWM @@ -101695,7 +103453,7 @@ iRx iEb bHa apm -apQ +jUn avT bWM bWM @@ -105059,7 +106817,7 @@ yfv bit baw baw -iJH +qYC kwo trb aag @@ -105262,7 +107020,7 @@ abg ajC baw vbB -hdV +ley kwo trb aag @@ -105465,7 +107223,7 @@ avn aim baw dBp -iRh +gVA tQV tQV aah @@ -109116,7 +110874,7 @@ awE vGk xCX vGk -csz +hoX qVM csz qVM @@ -109314,7 +111072,7 @@ fAo awE bhM wQv -sDL +bBi awE ieH qVM @@ -109928,7 +111686,7 @@ awE csz iid csz -csz +hoX qVM noV csz @@ -113149,10 +114907,10 @@ anf apK arf auG -awu azb azb -auG +azb +nMq aDp apK cbr @@ -113346,15 +115104,15 @@ xfm als ani aow -aqU -aqU -aqU -aqU -aqU -aqU -aqU +mOi +mOi +mOi +mOi +mOi +mOi auc -aqU +auc +hyE aqU aHq aHq @@ -113549,16 +115307,16 @@ ajJ aEX ajt ali -aqU -hvw +mOi +rCw rCw lin oJR -aqU +tFe asD xQV avK -cck +aqU aCZ dgg xRk @@ -113752,16 +115510,16 @@ ael isW ajt abg -aqU +mOi wCT sIf isC isC tFe -lmz +xQV xQV rNF -cck +aqU qjF oqv iqd @@ -113955,15 +115713,15 @@ ael abg akU abg -aqU -mlb +mOi +kbH kbH pgH -aqU -aqU -aqU -auf -aqU +jDV +tFe +xVc +xQV +eYz aqU gjB wDy @@ -114158,16 +115916,16 @@ adO lwm akU nQx -aqU -pYi -isC -xbN -aqU +mOi +mOi +mOi +mOi +mOi mOi asF asG -vhe -cck +iyH +aqU jVE nTs pje @@ -114363,14 +116121,14 @@ aii abg aqU sdl -isC -xbN -aqU -mOi -gjw +mLE +bUx +mLE +tmK +avK aug avL -cck +aqU lyE rsO aGN @@ -114567,13 +116325,13 @@ abg aqU xbN gfE -xbN +gfE +kpc aqU -mOi gjw cnp avM -cck +aqU wmK liJ pTj @@ -115354,7 +117112,7 @@ aag lYA aao aap -aap +gXh aao aap aap @@ -116300,7 +118058,7 @@ bNQ bNQ bNQ bNQ -bEk +nXU bKA jac bCA @@ -116503,7 +118261,7 @@ bNP bmD bNP bmD -gkg +mYv doP jac isS @@ -122920,7 +124678,7 @@ vuv vuv cxo cxo -cxo +vqO sXK tbD qMu @@ -127824,23 +129582,23 @@ aab aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -128027,23 +129785,23 @@ aab aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -128230,23 +129988,23 @@ aab aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -128433,23 +130191,23 @@ aab aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -128636,23 +130394,23 @@ aab aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -128839,23 +130597,23 @@ aab aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -129040,25 +130798,25 @@ aaa aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -129243,21 +131001,21 @@ aaa aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -129446,21 +131204,21 @@ aaa aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -129649,21 +131407,21 @@ aaa aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -129852,21 +131610,21 @@ aaa aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -130055,21 +131813,21 @@ aaa aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -130258,21 +132016,21 @@ aaa aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -130461,21 +132219,21 @@ aaa aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -130652,10 +132410,10 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa +aab +aab +aab +aab aab aaa aaa @@ -130663,22 +132421,22 @@ aKQ aaa aaa aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aab +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +bdH aaa aaa aaa @@ -130853,35 +132611,35 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa aab -aaa -aaa -aKQ -aaa -aaa aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aab +bdH +bdH +bdH +bdH +bdH +bdH +aKQ +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +aak +bdH aaa aaa aaa @@ -131049,42 +132807,42 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa aab -aaa -aaa -aKQ -aaa -aaa +aab +aab +aab +aab +aab +aab aab aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +aKQ +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +aak +bdH aaa aaa aaa @@ -131252,53 +133010,53 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -aKQ -aaa -aaa aab aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +aKQ +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -131455,53 +133213,53 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa aab aaa aaa -aKQ -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa aaa +bdH +bdH +bdH +bdH +bdH +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -131658,53 +133416,53 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa aab aaa aaa -aKQ -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa aaa +bdH +bdH +bdH +bdH +bdH +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -131861,53 +133619,53 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -aKQ -aaa -aaa aab aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -132064,53 +133822,53 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa aab aaa aaa -aKQ -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +daz +daz +daz +daz +daz +daz +daz +daz +daz +daz +daz +daz +daz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -132267,53 +134025,53 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -aKQ -aaa -aaa aab aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +daz +vhe +fEN +cqm +gTH +qit +rna +qQS +gwn +pfT +jYR +dyp +daz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -132470,53 +134228,53 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa aab aaa aaa -aKQ -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +sbJ +sbJ +sbJ +daz +jtj +avK +avK +sKY +avK +bIp +fKe +dDp +dDp +frM +lcg +daz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -132673,53 +134431,53 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -aKQ -aaa -aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +lmz +lmz +lmz +lmz +lmz +daz +daz +daz +daz +daz +tte +hvw +auf +pmV +xDC +xDC +dIn +rby +bIp +euN +sEK +sEK +mlb +lcg +daz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -132876,7 +134634,53 @@ aaa aaa aaa aaa +aab aaa +bdH +lmz +lmz +lmz +lmz +daz +daz +hRW +asZ +vXh +daz +daz +kfU +daz +rna +rna +lnS +uVv +yit +rna +cxc +kBy +kBy +gfu +fPB +daz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -132888,69 +134692,23 @@ aaa aaa aaa aaa -aaa -aab -aaa -aaa -aKQ -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -wVb -bhD -bdo -bdo -bdo -bdo -bdo -bdo -bdo -ovn -ovn -ovn -ovn -ovn -ovn -bCR -vTK +wVb +bhD +bdo +bdo +bdo +bdo +bdo +bdo +bdo +ovn +ovn +ovn +ovn +ovn +ovn +bCR +vTK aaa aaa aaa @@ -133079,60 +134837,60 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -aKQ -aaa -aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +lmz +lmz +lmz +daz +daz +scS +yaZ +ffE +hZj +clw +daz +daz +daz +sGZ +rna +rna +roH +ebN +ebN +ebN +daz +wnh +wnh +daz +daz +daz +lmz +lmz +lmz +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -133282,60 +135040,60 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa aab aaa -aaa -aKQ -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +lmz +lmz +lmz +daz +acJ +ubA +cck +wyQ +fmv +ubA +gMN +mRn +itf +mHE +vAU +qwJ +fJY +kzT +wkM +oLm +fcX +kKv +kKv +dGl +dGl +daz +lmz +lmz +lmz +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -133485,60 +135243,60 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -aKQ -aaa -aaa aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +lmz +lmz +lmz +daz +cwS +ffE +vHa +wpw +ffE +ffE +ffE +jqP +cLo +vfB +viB +dIi +qLS +vfB +wkM +jvB +jvB +ieF +ieF +pJR +gPr +daz +lmz +lmz +lmz +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -133599,335 +135357,14 @@ aaa aaa aaa aaa -aab -aaa -aaa -"} -(287,1,1) = {" -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -aKQ -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -wVb -bdo -jbB -bdo -bne -bdo -jbB -bdo -bne -ovn -gXv -ovn -grX -ovn -gXv -ovn -vTK -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -"} -(288,1,1) = {" -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -aKQ -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aab aaa aaa +"} +(287,1,1) = {" aaa aaa +aab aaa aaa aaa @@ -133949,24 +135386,6 @@ aaa aaa aaa aaa -wVb -wVb -wVb -wVb -wVb -wVb -wVb -wVb -wVb -vTK -vTK -vTK -vTK -vTK -vTK -vTK -vTK -aaa aaa aaa aaa @@ -134005,14 +135424,9 @@ aaa aaa aaa aaa -aab -aaa aaa -"} -(289,1,1) = {" aaa aaa -aab aaa aaa aaa @@ -134032,11 +135446,81 @@ aaa aaa aaa aaa +aab aaa +bdH +lmz +lmz +lmz +daz +oRV +ydI +mdW +jaH +awu +ydI +aKs +fMt +gOs +kXj +pYi +fMl +gUN +bLv +bRo +xvM +osy +cBm +cBm +iZw +dQl +daz +lmz +lmz +lmz +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa aaa +wVb +bdo +jbB +bdo +bne +bdo +jbB +bdo +bne +ovn +gXv +ovn +grX +ovn +gXv +ovn +vTK aaa aaa aaa @@ -134076,10 +135560,14 @@ aaa aaa aaa aaa +aab aaa aaa +"} +(288,1,1) = {" aaa aaa +aab aaa aaa aaa @@ -134107,13 +135595,10 @@ aaa aaa aaa aaa -aab aaa aaa -aKQ aaa aaa -aab aaa aaa aaa @@ -134164,11 +135649,81 @@ aaa aaa aaa aaa +aab aaa +bdH +lmz +lmz +lmz +daz +daz +eKJ +yaZ +ffE +hZj +mUC +daz +daz +daz +tHu +rna +rna +gXs +ebN +ebN +ebN +daz +wnh +wnh +daz +daz +daz +lmz +lmz +lmz +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa aaa +wVb +wVb +wVb +wVb +wVb +wVb +wVb +wVb +wVb +vTK +vTK +vTK +vTK +vTK +vTK +vTK +vTK aaa aaa aaa @@ -134212,7 +135767,7 @@ aab aaa aaa "} -(290,1,1) = {" +(289,1,1) = {" aaa aaa aab @@ -134297,7 +135852,60 @@ aaa aaa aaa aaa +aab aaa +bdH +lmz +lmz +lmz +lmz +daz +daz +ocB +nJH +rnH +daz +daz +sTV +daz +rna +rna +gbg +uVv +erN +rna +qQS +kBy +kBy +gfu +kBy +daz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -134310,13 +135918,8 @@ aaa aaa aaa aaa -aab -aaa -aaa -aKQ aaa aaa -aab aaa aaa aaa @@ -134363,10 +135966,14 @@ aaa aaa aaa aaa +aab aaa aaa +"} +(290,1,1) = {" aaa aaa +aab aaa aaa aaa @@ -134411,14 +136018,10 @@ aaa aaa aaa aaa -aab aaa aaa -"} -(291,1,1) = {" aaa aaa -aab aaa aaa aaa @@ -134452,7 +136055,60 @@ aaa aaa aaa aaa +aab aaa +bdH +lmz +lmz +lmz +lmz +lmz +daz +daz +daz +daz +daz +tte +hvw +auf +hTl +xDC +xDC +yaQ +bat +mFN +kSy +dDp +dDp +frM +lcg +daz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -134516,7 +136172,8 @@ aaa aab aaa aaa -aKQ +"} +(291,1,1) = {" aaa aaa aab @@ -134601,61 +136258,60 @@ aaa aaa aaa aaa +aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -"} -(292,1,1) = {" -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +sbJ +sbJ +sbJ +daz +jtj +avK +avK +aCd +avK +mFN +igr +sEK +sEK +mlb +lcg +daz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -134719,7 +136375,8 @@ aaa aab aaa aaa -aKQ +"} +(292,1,1) = {" aaa aaa aab @@ -134804,37 +136461,60 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa aab aaa aaa -"} -(293,1,1) = {" -aaa -aaa -aab -aaa -aaa -aaa -aaa -aaa +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +daz +gAe +rCi +gba +mUz +our +rna +cxc +kBy +kBy +khJ +gyN +daz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa aaa aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -134895,10 +136575,14 @@ aaa aaa aaa aaa +aab aaa aaa +"} +(293,1,1) = {" aaa aaa +aab aaa aaa aaa @@ -134919,13 +136603,10 @@ aaa aaa aaa aaa -aab aaa aaa -aKQ aaa aaa -aab aaa aaa aaa @@ -134983,8 +136664,48 @@ aaa aaa aaa aaa +aab aaa aaa +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +daz +daz +daz +daz +daz +daz +daz +daz +daz +daz +daz +daz +daz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -135020,14 +136741,10 @@ aaa aaa aaa aaa -aab aaa aaa -"} -(294,1,1) = {" aaa aaa -aab aaa aaa aaa @@ -135061,10 +136778,14 @@ aaa aaa aaa aaa +aab aaa aaa +"} +(294,1,1) = {" aaa aaa +aab aaa aaa aaa @@ -135122,13 +136843,10 @@ aaa aaa aaa aaa -aab aaa aaa -aKQ aaa aaa -aab aaa aaa aaa @@ -135149,8 +136867,48 @@ aaa aaa aaa aaa +aab aaa aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -135312,48 +137070,48 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aab -aaa -aaa -aKQ -aaa -aaa aab aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +bdH +bdH +bdH +aak +bdH +bdH +bdH +bdH +bdH +bdH +bdH aaa aaa aaa @@ -135518,37 +137276,37 @@ aab aab aab aab -aab -aab -aab -aab -aab -aab -aab -aab -aab -aab -aab -aaa aaa -aKQ -aaa -aaa -aab -aab -aab -aab -aab -aab -aab -aab -aab -aab -aab -aab -aab -aab -aab +bdH +bdH +bdH +bdH +bdH +bdH +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +lmz +bdH +bdH +bdH aab aab aab @@ -135720,39 +137478,39 @@ aaa aaa aaa aaa +aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aKQ -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +aab aaa aaa aaa @@ -135923,39 +137681,39 @@ aaa aaa aaa aaa +aab aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH aKQ -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +bdH +aab aaa aaa aaa @@ -136126,39 +137884,39 @@ aaa aaa aaa aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aKQ -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa -aaa +aab +aab +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +jRz +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aak +aab aaa aaa aaa @@ -136358,7 +138116,7 @@ aaa aaa aaa aaa -aaa +bdH aaa aaa aaa diff --git a/maps/new_varadero.json b/maps/new_varadero.json index d9d6a0d231cc..9a0bf5d56be1 100644 --- a/maps/new_varadero.json +++ b/maps/new_varadero.json @@ -13,6 +13,9 @@ "/datum/equipment_preset/survivor/security/lv", "/datum/equipment_preset/survivor/colonial_marshal/lv" ], + "CO_survivor_types": [ + "/datum/equipment_preset/survivor/new_varadero/commander" + ], "defcon_triggers": [ 3300, diff --git a/nano/templates/cm_stat_panel.tmpl b/nano/templates/cm_stat_panel.tmpl index 97feebde5971..26de08f17054 100644 --- a/nano/templates/cm_stat_panel.tmpl +++ b/nano/templates/cm_stat_panel.tmpl @@ -159,9 +159,6 @@ Used in: /code/datums/statistics/entities/player_entity.dm
Total Friendly Fire Kills:
-
- {{:data.round.total_friendly_fire_kills}} -
Total Slashes:
diff --git a/sound/effects/comical_bonk.ogg b/sound/effects/comical_bonk.ogg new file mode 100644 index 000000000000..e0a2751d52c2 Binary files /dev/null and b/sound/effects/comical_bonk.ogg differ diff --git a/strings/marinetips.txt b/strings/marinetips.txt index 620dc8710400..cf808884f1e5 100644 --- a/strings/marinetips.txt +++ b/strings/marinetips.txt @@ -28,7 +28,7 @@ Examine your gun and click [See combat statistics] to view information such as d Xenomorphs who resist while on fire are stunned for some time and emit light. Use that time to catch up and finish them off! When you have shrapnel embedded, take out your boot knife and use it in your hand to rip them out of your body. If your weapon has a bayonet, you can manually pry open unpowered doors by clicking on them with the gun. Click on the door again to close it. UPP bayonets can pry them open quicker. -Items on the floor can be shot. Shoot a misthrown HEDP away to save your buddies! +Items on the floor can be shot. Shoot a poorly thrown HEDP away to save your buddies! You can hold a bayonet or throwing knife on your mask slot. Always be prepared. Xenomorphs can't apply huggers to marines if they're on fire. Dragging a Nanomed onto yourself instantly gives a Health Analyzer report. Always know what's wrong with you. @@ -46,18 +46,18 @@ By right clicking your medical belt and selecting "toggle belt mode", you can ta You can put screwdrivers, cigarettes, and some other things in your second ear slot! Pilots : there is one of each engine upgrade in the hangar at the start of the round, saving you the point cost of having to print out a pair of each. You can use a hand labeler (as found in squad prep rooms) to name your equipment and make it less likely to be stolen. -You can use a health analyser in hand (Z key) to check the last scan readout from it. +You can use a health analyzer in hand (Z key) to check the last scan readout from it. Holocards are a useful triage tool for doctors and medics. Ensure you assign them (examine the marine with shift-click and select an appropriate holocard) to marines who have taken damage that cannot be healed without surgery. (Hint : major organ damage or larval infection = red card!) Escape pods are designed for only three occupants - more than that, or if a larger xenomorph is in the pod, and it will malfunction and blow up on launch. A misloaded OB can deviate severely from the intended target area - ensure you load them correctly! -The XO and CO are trained in powerloader use and engineering, and can load the OB. +The XO and CO are trained in Power Loader use and engineering, and can load the OB. You can change what your SL tracker beacon is tracking by right clicking on your headset and clicking "Switch Tracker Target". Boilers emit light - not every glow from around the corner is friendly! You can carry a variety of items inside your helmet - from gauze and cigarettes to flares and screwdrivers. CIC staff can track every USCM-aligned person via the suit sensors console and overwatch console - useful for finding escaped prisoners or dead marines. When the M7 RPG is fired, it creates a substantial shockwave behind it that can stun and harm marines standing too close. Watch your backblast! Remember that you need to put a defibrillator's paddles away in order to store it. -W-Y PMCs do not have marine IFF. Don't fire smartguns through them! +W-Y PMCs do not have marine IFF. Don't fire Smartguns through them! To talk on multiple radio channels at once, put a COMMA [,] before your message and add up to four prefixes. E.g, ,abcd talks on all squad channels at once. Put .w or :w before your message to whisper. Another way to whisper is to use the verb "whisper" in the IC tab or command bar. For Vehicle Crewmen : it is often safer to repair the parts of your APC or tank inside the vehicle than outside it. @@ -75,13 +75,13 @@ Intel Officers can be put in a squad by going to CIC and requesting it. Any marine can perform CPR. On dead marines, this will increase the time they have until they become unrevivable. If you've been pounced on and your squad is unloading into the target, you can hit the 'rest' button to stay down so you don't get filled with lead after getting up. You can check the landing zone as a marine in the status panel. -Functioning night vision goggles can be recharged with batteries. Broken night vision goggles can be repaired by an Engineer with a screwdriver. Not the loadout ones though, those are unfixable and unchargeable. -You can put a pistol belt on your suit slot. (Just grab a rifle instead..) +Functioning night vision goggles can be recharged with batteries. Broken night vision goggles can be repaired by an Engineer with a screwdriver. Not the loadout ones though, those cannot be fixed. +You can put a pistol belt on your suit slot. (Just grab a rifle instead.) Alt-clicking the Squad Leader tracker lets you track your fireteam leader instead. -Armor has a randomized reduction in effectiveness, and does not protect the digits. Take the wiki damage values as a best case scenario. +Armor has a randomized reduction in effectiveness, and does not protect the digits. Take the wiki damage values as a best-case scenario. You can click on your Security Access Tuner (multitool) in your hand to locate the area's APC if there is one. Clicking on your sprite with help intent will let you check your body, seeing where your fractures and other wounds are. Armor has insulative properties - taking it off will help you cool off and take less damage faster if you've been set on fire. -Both foldable cades & plasteel cades if loosened and folded down can be transported in crates! In this way, you can use the crate as a portable breach-repair kit, or dragged (or carried via Powerloader) to an unsecure area for quick defensive set up. +Both foldable cades & plasteel cades if loosened and folded down can be transported in crates! In this way, you can use the crate as a portable breach-repair kit, or dragged (or carried via Power Loader) to an unsecure area for quick defensive set up. The fuel tank pouch doesn't just carry fuel for an incinerator- they can also carry full-size extinguishers. Toolbelts & tool pouches also may hold miniature extinguishers. -The M2C heavy machinegunner belt rig can also carry C4, breaching charges, and most tools. +The M2C heavy machine gunner belt rig can also carry C4, breaching charges, and most tools. diff --git a/strings/metatips.txt b/strings/metatips.txt index 4b69af764aeb..f694da02b5bf 100644 --- a/strings/metatips.txt +++ b/strings/metatips.txt @@ -1,13 +1,13 @@ -Remember hotkeys and marcos can be customized to your liking. Hotkeys can be accessed in your preferences, and macros can be edited in the Byond macro editor, available in the top left drop down menu (click the Byond logo in the corner of the game window). -If you're unsure about a gameplay mechanic, use the 'mentorhelp' verb in the Admins tab to ask veteran players on the subject. +Remember hotkeys and macros can be customized to your liking. Hotkeys can be accessed in your preferences, and macros can be edited in the Byond macro editor, available in the top left drop down menu (click the Byond logo in the corner of the game window). +If you're unsure about a gameplay mechanic, use the 'mentorhelp' verb in the Admin tab to ask veteran players on the subject. Try not to get too mad about dying. We’re all here to have fun. After dying, ask yourself what you did wrong and make a mental note to not make the same mistake again. Communication, be it from a marine to a marine, a drone to the queen, or command to everyone, is vital and information on flanks can change how the entire round plays out. As an alien or marine, be careful of the flank, regardless of if the push is going well or stalling out. Half of getting good is knowing to be aggressive. The other half is knowing when not to be aggressive. -Alt-click a storage item to draw the last item in it (last non-weapon if it's a weapon belt). Middle-click a storage item to inmediately open it, and middle-click structures to attempt to vault them. +Alt-click a storage item to draw the last item in it (last non-weapon if it's a weapon belt). Middle-click a storage item to immediately open it, and middle-click structures to attempt to vault them. Use "North, South, West, East" when referring to locations in-game rather than "up, down, left, right". You shouldn't ignore what your allies are up to. Sometimes they can be organizing a flank in hivemind/radio, sometimes they can be walking up behind you with a slug-loaded shotgun. Either way, it pays to be alert to what they're doing, as much to as what the enemies are. -The Wiki (https://cm-ss13.com/wiki) is a very useful repository of information about the game, such as weapons, equipment, xenomorph castes and their strains. It may not be fully up to date the majority of the time, but the basics are usually accurate. +The Wiki (https://cm-ss13.com/wiki) is a very useful repository of information about the game, such as weapons, equipment, xenomorph castes and their strains. It may not be fully up to date much of the time, but the basics are usually accurate. As an observer, you may see how much remaining hijack time is left in the status panel. Embrace the suck. diff --git a/strings/xenotips.txt b/strings/xenotips.txt index 4e98be577a61..2ca2964ae2d5 100644 --- a/strings/xenotips.txt +++ b/strings/xenotips.txt @@ -1,6 +1,6 @@ Acid pillars can be sneakily placed next to a door in order to surprise marines. -Alien structures like clusters, walls, or pillars are absolutely vital to your victory, be it as cover or to delay and funnel marines. -Always thank your drones and hivelords for supporting the hive! +Alien structures like clusters, walls, or pillars are vital to your victory, be it as cover or to delay and funnel marines. +Always thank your drones and Hivelords for supporting the hive! Don't underestimate survivors. They have no armor but that makes them very fast, they're inherently hardier than marines and have various tricks up their sleeves. While the Queen is de-ovied, the hive does not gain evolution points. Try out new castes or strains that you might have passed up initially. You might find them to be surprisingly fun. @@ -16,21 +16,21 @@ If a fellow alien is stunned, be sure to drag them to safety. On help intent, click a xenomorph who is on fire to pat them out. This works on marines too! Frenzy increases your speed and damage, Recovery increases your health regeneration, and Warding increases the time you have until you bleed out in critical health. Remember that, as a Xenomorph, you can fully disable your night-vision. This helps put into perspective how hidden your position is to marines onscreen. -You can devour bursted corpses in order to transport them to the Spawn Pool or Egg Morpher easier. +You can devour burst corpses in order to transport them to the Spawn Pool or Egg Morpher easier. The bigger you are, the more time it'll take to enter a tunnel. -Drag yourself onto a hole in a wall as a medium-sized or smaller xeno to pass through it. +Drag yourself onto a hole in a wall as a medium-sized or smaller Xeno to pass through it. Claymores have directional explosions. Set them off early by slashing them from behind. If you have difficulty clicking marines, try using Directional Slashing, though there's no directional slashing for abilities. You can diagonally pounce through the corners of fire as a Lurker or Runner without getting ignited. -When playing as xeno, consider aiming at the limbs instead of the chest. Marine armour doesn't protect the arms and legs as well as it does the body. -As xeno, you can break Night-Vision goggles that some marines wear on their helmets. Just aim for the head and slash until the goggles shatter. +When playing as Xeno, consider aiming at the limbs instead of the chest. Marine armor doesn't protect the arms and legs as well as it does the body. +As Xeno, you can break Night-Vision goggles that some marines wear on their helmets. Just aim for the head and slash until the goggles shatter. Pounces are ineffective on marines who are laying down. -You may rest inmediately during a pounce to pounce straight through mobs. It's not very practical or useful though. -Pouncing someone who is buckled to a chair will still stun them, but you won't jump into their tile and they will not be knocked to the grund. -Starshell dust from said grenades is just as meltable as normal flares. -You can join the hive as a living facehugger by clicking on the hive's eggmorpher. This works on other hives too.. -Playable facehuggers can leap onto targets with a one-second windup, but this will only infect them if they are adjacent to it. Otherwise, it will simply knock them down for a small duration. -As a facehugger, you cannot talk in hivemind, but you can still open Hive Status and overwatch your sisters. This can be useful if you're locating other facehuggers, flanker castes, or trying to learn from experienced facehugger players. +You may rest immediately during a pounce to pounce straight through mobs. It's not very practical or useful though. +Pouncing someone who is buckled to a chair will still stun them, but you won't jump into their tile and they will not be knocked to the ground. +Star shell dust from said grenades is just as meltable as normal flares. +You can join the hive as a living Facehugger by clicking on the hive's Eggmorpher. This works on other hives too.. +Playable Facehuggers can leap onto targets with a one-second windup, but this will only infect them if they are adjacent to it. Otherwise, it will simply knock them down for a small duration. +As a Facehugger, you cannot talk in hivemind, but you can still open Hive Status and overwatch your sisters. This can be useful if you're locating other Facehuggers, flanker castes, or trying to learn from experienced Facehugger players. Shift-clicking the Queen indicator will tell you what area you are in, on the map. -Resisting on a water tile will inmediately put out fires. Make sure you're alone though - It's usually better to let a friendly Xenomorph pat you out than it is to expose yourself to open water. +Resisting on a water tile will immediately put out fires. Make sure you're alone though - It's usually better to let a friendly Xenomorph pat you out than it is to expose yourself to open water. You can filter out the Xenomorphs displayed in hive status by health, allowing you to look only for wounded sisters. diff --git a/tgui/packages/tgui/interfaces/AresInterface.js b/tgui/packages/tgui/interfaces/AresInterface.js new file mode 100644 index 000000000000..6bf85e96522f --- /dev/null +++ b/tgui/packages/tgui/interfaces/AresInterface.js @@ -0,0 +1,1493 @@ +import { useBackend } from '../backend'; +import { Flex, Box, Section, Button, Stack } from '../components'; +import { Window } from '../layouts'; + +const PAGES = { + 'login': () => Login, + 'main': () => MainMenu, + 'announcements': () => AnnouncementLogs, + 'bioscans': () => BioscanLogs, + 'bombardments': () => BombardmentLogs, + 'apollo': () => ApolloLog, + 'access_log': () => AccessLogs, + 'delete_log': () => DeletionLogs, + 'talking': () => ARESTalk, + 'deleted_talks': () => DeletedTalks, + 'read_deleted': () => ReadingTalks, + 'security': () => Security, + 'requisitions': () => Requisitions, + 'antiair': () => AntiAir, + 'emergency': () => Emergency, +}; + +export const AresInterface = (props, context) => { + const { data } = useBackend(context); + const { current_menu } = data; + const PageComponent = PAGES[current_menu](); + + return ( + + + + + + ); +}; + +const Login = (props, context) => { + const { act } = useBackend(context); + + return ( + + ARES v3.2 Interface + + WY-DOS Executive + + Version 8.2.3 + Copyright © 2182, Weyland Yutani Corp. + +