diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 1dff22c9d0f..839009e037a 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -26,6 +26,13 @@ /// cable was placed or joined somewhere : (turf) #define COMSIG_GLOB_CABLE_UPDATED "!cable_updated" +#define COMSIG_GLOB_WEB_STORM_ENDED "!web_storm_ended" +#define COMSIG_GLOB_EMPRESS_EGG_DESTROYED "!empress_egg_destroyed" +#define COMSIG_GLOB_EMPRESS_EGG_BURST "!empress_egg_burst" +#define COMSIG_GLOB_IFECTION_CREATED "!infection_created" +#define COMSIG_GLOB_IFECTION_REMOVED "!infection_removed" +#define COMSIG_GLOB_XENO_STORM_ENDED "!xeno_storm_ended" + /// signals from globally accessible objects ///from SSsun when the sun changes position : (azimuth) @@ -1294,6 +1301,19 @@ /// Source: /proc/random_hair_style (mob/living/carbon/human/human, valid_hairstyles, robohead) #define COMSIG_RANDOM_HAIR_STYLE "random_hair_style" +// Terror Spiders Signals +/// Defilers ore queen sybtypes now can lay empress egg +#define COMSIG_SPIDER_CAN_LAY "spider_can_lay" + +/// Human eaten by prince +#define COMSIG_HUMAN_EATEN "human_eaten" + +/// Terror spider died +#define COMSIG_TERROR_SPIDER_DIED "terror_spider_died" + +#define COMSIG_EMPRESS_EGG_LAYED "empress_egg_layed" + +#define COMSIG_ALIEN_EVOLVE "alien_evolve" /// Source: /datum/component/ritual_object/proc/pre_ritual_check (status_bitflag, mob/living/carbon/human, list/invokers, list/used_things) #define COMSIG_RITUAL_ENDED "ritual_ended" diff --git a/code/__DEFINES/gamemode.dm b/code/__DEFINES/gamemode.dm index 5d1e3cad741..fde88572da5 100644 --- a/code/__DEFINES/gamemode.dm +++ b/code/__DEFINES/gamemode.dm @@ -68,6 +68,13 @@ #define SPECIAL_ROLE_XENOMORPH_DRONE "Xenomorph Drone" #define SPECIAL_ROLE_XENOMORPH_SENTINEL "Xenomorph Sentinel" #define SPECIAL_ROLE_XENOMORPH_LARVA "Xenomorph Larva" +#define SPECIAL_ROLE_TERROR_SPIDER "Terror Spider" +#define SPECIAL_ROLE_TERROR_QUEEN "Terror Queen" +#define SPECIAL_ROLE_TERROR_PRINCE "Terror Prince" +#define SPECIAL_ROLE_TERROR_PRINCESS "Terror Princess" +#define SPECIAL_ROLE_TERROR_DEFILER "Terror Defiler" +#define SPECIAL_ROLE_TERROR_EMPRESS "Terror Empress" +#define SPECIAL_ROLE_TERROR_DESTROYER "Terror Destroyer" #define SPECIAL_ROLE_SPACE_NINJA "Space Ninja" #define SPECIAL_ROLE_THIEF "Thief" #define SPECIAL_ROLE_SPACE_DRAGON "Space Dragon" diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index a41d2e38c21..7ca285d4bd1 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -127,6 +127,12 @@ #define SLIME_FRIENDSHIP_STAY 3 //Min friendship to order it to stay #define SLIME_FRIENDSHIP_ATTACK 8 //Min friendship to order it to attack +//Spiders ai states +#define SPINNING_WEB 1 +#define LAYING_EGGS 2 +#define MOVING_TO_TARGET 3 +#define SPINNING_COCOON 4 + //Hostile simple animals //If you add a new status, be sure to add a list for it to the simple_animals global in _globalvars/lists/mobs.dm #define AI_ON 1 diff --git a/code/__DEFINES/terror_spiders.dm b/code/__DEFINES/terror_spiders.dm new file mode 100644 index 00000000000..9d98cacc431 --- /dev/null +++ b/code/__DEFINES/terror_spiders.dm @@ -0,0 +1,52 @@ +#define TS_DAMAGE_SIMPLE 0 +#define TS_DAMAGE_POISON 1 +#define TS_DAMAGE_BRUTE 2 + +//TIER 1 +#define TS_DESC_KNIGHT "Рыцарь - ШТУРМ" +#define TS_DESC_LURKER "Наблюдатель - ЗАСАДЫ" +#define TS_DESC_HEALER "Лекарь - ЛЕЧЕНИЕ" +#define TS_DESC_REAPER "Жнец - БОЙ" +#define TS_DESC_BUILDER "Дрон - СТРОИТЕЛЬСТВО" +//TIER 2 +#define TS_DESC_WIDOW "Вдова - ОТРАВЛЕНИЕ" +#define TS_DESC_GUARDIAN "Защитник - ОБОРОНА" +#define TS_DESC_DESTROYER "Разрушитель - САБОТАЖ" +//TIER 3 +#define TS_DESC_PRINCE "Принц - КРОВАВАЯ БАНЯ" +#define TS_DESC_PRINCESS "Принцесса - РАЗМНОЖЕНИЕ" +#define TS_DESC_MOTHER "Мать - ПОДДЕРЖКА" +#define TS_DESC_DEFILER "Осквернитель - ЗАРАЖЕНИЕ" +//TIER 4 +#define TS_DESC_QUEEN "Королева - ЛИДЕР" + +#define TS_TIER_1 1 +#define TS_TIER_2 2 +#define TS_TIER_3 3 +#define TS_TIER_4 4 +#define TS_TIER_5 5 + +#define TERROR_QUEEN "Королева Ужаса" +#define TERROR_PRINCE "Принц Ужаса" +#define TERROR_PRINCESS "Принцесса Ужаса" +#define TERROR_DEFILER "Осквернитель Ужаса" +#define TERROR_OTHER "Пауки Ужаса" +#define SPAWN_TERROR_TYPES list(TERROR_QUEEN, TERROR_PRINCE, TERROR_PRINCESS, TERROR_DEFILER) + +#define TERROR_STAGE_START 0 +#define TERROR_STAGE_PROTECT_EGG 1 +#define TERROR_STAGE_STORM 2 +#define TERROR_STAGE_END 3 +#define TERROR_STAGE_POST_END 4 + +#define TERROR_VOTE_LEN 30 SECONDS + +#define TERROR_VOTE_TICKS 30 + +#define INFECTIONS_ANNOUNCE_TRIGGER 0.1 + +#define SPIDERS_ANNOUNCE_TRIGGER 0.1 + +#define TIME_TO_ANNOUNCE 10 SECONDS + +#define EMPRESS_EGG_TARGET_COUNT 2 + num_station_players() / 5 diff --git a/code/__DEFINES/xenomorphs.dm b/code/__DEFINES/xenomorphs.dm new file mode 100644 index 00000000000..76836d0612d --- /dev/null +++ b/code/__DEFINES/xenomorphs.dm @@ -0,0 +1,19 @@ +#define EMPRESS_EVOLVE_TARGET_COUNT 2 + num_station_players() / 6 + +#define EVOLVE_ANNOUNCE_TRIGGER 0.1 + +#define TO_EMPRESS_EVOLVE_TIME 10 SECONDS + +#define TO_EMPRESS_EVOLVE_COST 750 + +#define LARVA_TYPE /mob/living/carbon/alien/larva + +#define QUEEN_TYPE /mob/living/carbon/alien/humanoid/queen + +#define EMPRESS_TYPE /mob/living/carbon/alien/humanoid/empress + +#define XENO_STAGE_START 0 +#define XENO_STAGE_PROTECT_COCON 1 +#define XENO_STAGE_STORM 2 +#define XENO_STAGE_END 3 +#define XENO_STAGE_POST_END 4 diff --git a/code/__HELPERS/antag_menu_helpers.dm b/code/__HELPERS/antag_menu_helpers.dm index 64529163ad7..5e55598829c 100644 --- a/code/__HELPERS/antag_menu_helpers.dm +++ b/code/__HELPERS/antag_menu_helpers.dm @@ -47,10 +47,8 @@ prepare_antag_list(mode.supervillains, cached_data, "Суперзлодей", antagonist_cache) prepare_antag_list(mode.greyshirts, cached_data, "Грейтайд", antagonist_cache) prepare_antag_list(mode.demons, cached_data, "Демон", antagonist_cache) - prepare_antag_list(mode.xenos, cached_data, "Ксеноморф", antagonist_cache) prepare_antag_list(mode.eventmiscs, cached_data, "Ивентроль", antagonist_cache) prepare_antag_list(mode.traders, cached_data, "Торговец", antagonist_cache) - prepare_antag_list(mode.terror_spiders, cached_data, "Паук Ужаса", antagonist_cache) prepare_antag_list(mode.morphs, cached_data, "Морф", antagonist_cache) prepare_antag_list(mode.swarmers, cached_data, "Свармер", antagonist_cache) prepare_antag_list(mode.guardians, cached_data, "Голопаразит", antagonist_cache) diff --git a/code/controllers/subsystem/shuttles.dm b/code/controllers/subsystem/shuttles.dm index 0dcf1b4908c..eed9e0eff8b 100644 --- a/code/controllers/subsystem/shuttles.dm +++ b/code/controllers/subsystem/shuttles.dm @@ -28,6 +28,7 @@ SUBSYSTEM_DEF(shuttle) var/emergency_sec_level_time = 0 // time sec level was last raised to red or higher var/area/emergencyLastCallLoc var/emergencyNoEscape + var/list/hostile_environment = list() //supply shuttle stuff var/obj/docking_port/mobile/supply/supply diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index f4177595b1e..f2fbc14364f 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -598,6 +598,10 @@ SUBSYSTEM_DEF(ticker) emobtext += "
" to_chat(world, emobtext) + for(var/team_type in GLOB.antagonist_teams) + var/datum/team/team = GLOB.antagonist_teams[team_type] + team.declare_completion() + mode.declare_completion()//To declare normal completion. //calls auto_declare_completion_* for all modes diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm index e7e76406dc2..ba8e9c086c8 100644 --- a/code/controllers/subsystem/weather.dm +++ b/code/controllers/subsystem/weather.dm @@ -23,6 +23,9 @@ SUBSYSTEM_DEF(weather) var/datum/weather/our_event = V if(our_event.aesthetic || our_event.stage != MAIN_STAGE) continue + if(our_event.self_fire) + our_event.fire() + continue for(var/mob/living/act_on as anything in GLOB.mob_living_list) if(our_event.can_weather_act(act_on)) our_event.weather_act(act_on) diff --git a/code/datums/components/ghost_direct_control.dm b/code/datums/components/ghost_direct_control.dm index 179695c6150..eb91b4884af 100644 --- a/code/datums/components/ghost_direct_control.dm +++ b/code/datums/components/ghost_direct_control.dm @@ -6,12 +6,17 @@ var/assumed_control_message /// Type of ban you can get to prevent you from accepting this role var/ban_type + /// Check Syndicate ban + var/ban_syndicate /// Any extra checks which need to run before we take over var/datum/callback/extra_control_checks /// Callback run after someone successfully takes over the body var/datum/callback/after_assumed_control /// If we're currently awaiting the results of a ghost poll var/awaiting_ghosts = FALSE + /// Aditional text of question + var/question_text + /datum/component/ghost_direct_control/Initialize( ban_type = ROLE_SENTIENT, @@ -21,20 +26,24 @@ antag_age_check = TRUE, check_antaghud = TRUE, poll_length = 10 SECONDS, + ban_syndicate = FALSE, assumed_control_message = null, datum/callback/extra_control_checks, datum/callback/after_assumed_control, + question_text, ) . = ..() if(!isliving(parent)) return COMPONENT_INCOMPATIBLE + var/mob/mob_parent = parent src.ban_type = ban_type - src.assumed_control_message = assumed_control_message || "You are [parent]!" + src.ban_syndicate = ban_syndicate + src.assumed_control_message = assumed_control_message || "Вы [mob_parent.declent_ru(NOMINATIVE)]!" src.extra_control_checks = extra_control_checks src.after_assumed_control = after_assumed_control + src.question_text = question_text - var/mob/mob_parent = parent LAZYADD(GLOB.mob_spawners[format_text("[initial(mob_parent.name)]")], mob_parent) if(poll_candidates) @@ -70,7 +79,7 @@ var/mob/living/our_mob = parent if(our_mob.stat == DEAD || our_mob.key || awaiting_ghosts) return - examine_text += span_boldnotice("You could take control of this mob by clicking on it.") + examine_text += span_boldnotice("Вы можете взять под контроль это существо, нажав на него.") /// Send out a request for a brain /datum/component/ghost_direct_control/proc/request_ghost_control(poll_question, role_name, poll_length, age_check, check_ahud) @@ -99,35 +108,35 @@ if(!hopeful_ghost.client) return if(awaiting_ghosts) - to_chat(hopeful_ghost, span_warning("Ghost candidate selection currently in progress!")) + to_chat(hopeful_ghost, span_warning("В настоящее время идёт отбор кандидатов-призраков!")) return COMPONENT_CANCEL_ATTACK_CHAIN if(!SSticker.HasRoundStarted()) - to_chat(hopeful_ghost, span_warning("You cannot assume control of this until after the round has started!")) + to_chat(hopeful_ghost, span_warning("Вы не можете взять на себя управление этим существом до начала раунда!")) return COMPONENT_CANCEL_ATTACK_CHAIN INVOKE_ASYNC(src, PROC_REF(attempt_possession), our_mob, hopeful_ghost) return COMPONENT_CANCEL_ATTACK_CHAIN /// We got far enough to establish that this mob is a valid target, let's try to posssess it /datum/component/ghost_direct_control/proc/attempt_possession(mob/our_mob, mob/dead/observer/hopeful_ghost) - var/ghost_asked = tgui_alert(usr, "Become [our_mob]?", "Are you sure?", list("Yes", "No")) - if(ghost_asked != "Yes" || QDELETED(our_mob)) + var/ghost_asked = tgui_alert(usr, "[question_text? question_text : "Стать [capitalize(our_mob.declent_ru(INSTRUMENTAL))]?"]", "Стать [capitalize(our_mob.declent_ru(INSTRUMENTAL))]?", list("Да", "Нет")) + if(ghost_asked != "Да" || QDELETED(our_mob)) return assume_direct_control(hopeful_ghost) /// Grant possession of our mob, component is now no longer required /datum/component/ghost_direct_control/proc/assume_direct_control(mob/harbinger) if(QDELETED(src)) - to_chat(harbinger, span_warning("Offer to possess creature has expired!")) + to_chat(harbinger, span_warning("Срок действия предложения о контроле над существом истёк!")) return - if(jobban_isbanned(harbinger, ban_type)) - to_chat(harbinger, span_warning("You are banned from playing as this role!")) + if(jobban_isbanned(harbinger, ban_type) || (ban_syndicate && jobban_isbanned(harbinger, ROLE_SYNDICATE))) + to_chat(harbinger, span_warning("Эта роль для вас заблокирована!")) return var/mob/living/new_body = parent if(new_body.stat == DEAD) - to_chat(harbinger, span_warning("This body has passed away, it is of no use!")) + to_chat(harbinger, span_warning("Это тело умерло, оно бесполезно!")) return if(new_body.key) - to_chat(harbinger, span_warning("[parent] has already become sapient!")) + to_chat(harbinger, span_warning("[capitalize(new_body.declent_ru(NOMINATIVE))] уже является разумным!")) qdel(src) return if(extra_control_checks && !extra_control_checks.Invoke(harbinger)) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 78d4ca317db..f552c62d37f 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -550,6 +550,23 @@ . += "blobize|NO" . += _memory_edit_role_enabled(ROLE_BLOB) +/datum/mind/proc/memory_edit_terrors() + . = _memory_edit_header("terror spiders") + var/datum/antagonist/terror_spider/spider_datum = has_antag_datum(/datum/antagonist/terror_spider/) + if(spider_datum) + . += "|[spider_datum.spider_category]" + else + . += "datumise|NO" + . += _memory_edit_role_enabled(ROLE_TERROR_SPIDER) + +/datum/mind/proc/memory_edit_xenomorphs() + . = _memory_edit_header("xenomorphs") + var/datum/antagonist/xenomorph/xeno_datum = has_antag_datum(/datum/antagonist/xenomorph) + if(xeno_datum) + . += "|[xeno_datum.antag_menu_name]" + else + . += "datumise|NO" + . += _memory_edit_role_enabled(ROLE_ALIEN) /datum/mind/proc/memory_edit_traitor() . = _memory_edit_header("traitor", list("traitorchan", "traitorvamp", "traitorthief")) @@ -755,7 +772,10 @@ if((isliving(current) && current.can_be_blob()) || isblobovermind(src)) sections["blob"] = memory_edit_blob(current) - + if(isterrorspider(current)) + sections["terror_spiders"] = memory_edit_terrors(current) + if(isalien(current)) + sections["xenomorphs"] = memory_edit_xenomorphs() if(!issilicon(current)) /** CULT ***/ sections["cult"] = memory_edit_cult(H) @@ -2476,6 +2496,24 @@ blob_overmind.set_strain(strain) log_admin("[key_name(usr)] changed the strain to [strain] for [key_name(current)]") message_admins("[key_name_admin(usr)] changed the strain to [strain] for [key_name_admin(current)]") + + else if(href_list["terror"]) + switch(href_list["terror"]) + if("datumise") + if(QDELETED(current) || current.stat == DEAD) + return + var/mob/living/simple_animal/hostile/poison/terror_spider/spider = current + spider.add_datum_if_not_exist() + log_and_message_admins("has made [key_name(current)] into a \"Terror Spider\"") + + else if(href_list["xenomorph"]) + switch(href_list["xenomorph"]) + if("datumise") + if(QDELETED(current) || current.stat == DEAD) + return + var/mob/living/carbon/alien/alien = current + alien.update_datum() + log_and_message_admins("has made [key_name(current)] into a \"Xenomorph\"") else if(href_list["common"]) switch(href_list["common"]) diff --git a/code/datums/spells/alien_spells/evolve.dm b/code/datums/spells/alien_spells/evolve.dm index 80f11c6b97f..2a8aa1b8814 100644 --- a/code/datums/spells/alien_spells/evolve.dm +++ b/code/datums/spells/alien_spells/evolve.dm @@ -57,6 +57,7 @@ var/mob/living/carbon/alien/new_xeno = new evolution_path(get_turf(user)) user.mind.transfer_to(new_xeno) + SEND_SIGNAL(new_xeno.mind, COMSIG_ALIEN_EVOLVE, user.type, evolution_path) new_xeno.mind.name = new_xeno.name if(HAS_TRAIT(user, TRAIT_MOVE_VENTCRAWLING)) diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm index 09d8a024805..8a89a75afb5 100644 --- a/code/datums/weather/weather.dm +++ b/code/datums/weather/weather.dm @@ -44,6 +44,8 @@ var/barometer_predictable = FALSE var/next_hit_time = 0 //For barometers to know when the next storm will hit + /// Has special firing + var/self_fire = FALSE /datum/weather/New(z_levels) ..() @@ -139,6 +141,8 @@ return TRUE +/datum/weather/proc/fire() + return /datum/weather/proc/weather_act(mob/living/target) //What effect does this weather have on the hapless mob? return diff --git a/code/datums/weather/weather_types/web_storm.dm b/code/datums/weather/weather_types/web_storm.dm new file mode 100644 index 00000000000..704c0e2b7c4 --- /dev/null +++ b/code/datums/weather/weather_types/web_storm.dm @@ -0,0 +1,64 @@ +/datum/weather/web_storm + name = "Паутинная буря" + desc = "Плотное облако из мельчайших частичек паутины, липнущих ко всему вокруг." + + telegraph_duration = 2 SECONDS + telegraph_message = span_danger("Вы замечаете мелкие частицы паутины в воздухе.") + + weather_message = span_userdanger("Вы ощущаете поток мельчайших частиц паутины, липнуших ко всему вокруг.") + weather_overlay = "web_storm" + weather_duration_lower = 30 SECONDS + weather_duration_upper = 1 MINUTES + overlay_layer = MOB_LAYER + overlay_plane = GAME_PLANE + weather_sound = 'sound/creatures/terrorspiders/queen_shriek.ogg' + + end_duration = 10 SECONDS + end_message = span_notice("Поток паутины прекращается.") + + area_type = /area + protected_areas = list(/area/space, /area/crew_quarters/sleep) + target_trait = STATION_LEVEL + + immunity_type = TRAIT_WEATHER_IMMUNE + + self_fire = TRUE + var/turfs_per_tick = 40 + var/list/affected_turfs_list = list() + + +/datum/weather/web_storm/telegraph() + . = ..() + status_alarm(TRUE) + GLOB.event_announcement.Announce("Зафиксирована сигнатура Императрицы Ужаса на борту станции [station_name()]. Запущено глубокое сканирование.", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/effects/siren-spooky.ogg') + + if(!.) + return + for(var/area/area as anything in impacted_areas) + for(var/turf/turf in area.get_contained_turfs()) + if(is_space_or_openspace(turf) || turf.density) + continue + affected_turfs_list += turf + +/datum/weather/web_storm/fire() + var/list/turfs = list() + for(var/i = 1; i < turfs_per_tick; i++) + var/turf = pick(affected_turfs_list) + new/obj/structure/spider/terrorweb(turf) + turfs += turf + affected_turfs_list -= turfs + + +/datum/weather/web_storm/end() + if(..()) + return + if(!SSticker || !SSticker.mode) + return + status_alarm(FALSE) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_WEB_STORM_ENDED) + +/datum/weather/web_storm/proc/status_alarm(active) + if(active) + post_status(STATUS_DISPLAY_ALERT, "bio") + else + post_status(STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME) diff --git a/code/datums/weather/weather_types/xeno_storm.dm b/code/datums/weather/weather_types/xeno_storm.dm new file mode 100644 index 00000000000..48e1d56f60f --- /dev/null +++ b/code/datums/weather/weather_types/xeno_storm.dm @@ -0,0 +1,63 @@ +/datum/weather/xeno_storm + name = "Ксено-буря" + + telegraph_duration = 2 SECONDS + telegraph_message = null + + weather_message = null + weather_duration_lower = 30 SECONDS + weather_duration_upper = 1 MINUTES + + end_message = null + end_duration = 10 SECONDS + + area_type = /area + protected_areas = list(/area/space, /area/crew_quarters/sleep) + target_trait = STATION_LEVEL + + immunity_type = TRAIT_WEATHER_IMMUNE + + self_fire = TRUE + var/vents_per_tick = 15 + var/list/affected_vents_list = list() + + +/datum/weather/xeno_storm/telegraph() + . = ..() + status_alarm(TRUE) + GLOB.event_announcement.Announce("Зафиксирована сигнатура Императрицы Ксеноморфов на борту станции [station_name()]. Запущено глубокое сканирование.", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/effects/siren-spooky.ogg') + + if(!.) + return + + for(var/obj/vent as anything in GLOB.all_vent_pumps) + var/area = get_area(vent) + if(area in impacted_areas) + affected_vents_list[vent] = TRUE + + +/datum/weather/xeno_storm/fire() + if(!affected_vents_list.len) + return + var/list/vents = list() + for(var/i = 1; i < vents_per_tick; i++) + var/obj/machinery/atmospherics/unary/vent_pump/vent = pick(affected_vents_list) + vent.set_welded(TRUE) + new/obj/structure/alien/weeds/node(get_turf(vent)) + vents += vent + affected_vents_list -= vents + + +/datum/weather/xeno_storm/end() + if(..()) + return + if(!SSticker || !SSticker.mode) + return + status_alarm(FALSE) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_XENO_STORM_ENDED) + +/datum/weather/xeno_storm/proc/status_alarm(active) + if(active) + post_status(STATUS_DISPLAY_ALERT, "bio") + else + post_status(STATUS_DISPLAY_TRANSFER_SHUTTLE_TIME) diff --git a/code/datums/wires/nuclearbomb.dm b/code/datums/wires/nuclearbomb.dm index 16ad6b85b02..d69c1590f8e 100644 --- a/code/datums/wires/nuclearbomb.dm +++ b/code/datums/wires/nuclearbomb.dm @@ -53,6 +53,7 @@ N.timing = FALSE N.update_icon() GLOB.bomb_set = FALSE + SSshuttle?.remove_hostile_environment(N) if(WIRE_BOMB_LIGHT) N.lighthack = !N.lighthack diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm index e64fcede79c..036497e12db 100644 --- a/code/game/gamemodes/blob/blob.dm +++ b/code/game/gamemodes/blob/blob.dm @@ -140,8 +140,6 @@ switch(report_number) if (BLOB_DEATH_REPORT_FIRST) send_intercept(BLOB_THIRD_REPORT) - if (BLOB_DEATH_REPORT_SECOND) - SSshuttle?.stop_lockdown() if (BLOB_DEATH_REPORT_THIRD) if(!off_auto_gamma && GLOB.security_level == SEC_LEVEL_GAMMA) set_security_level(SEC_LEVEL_RED) @@ -205,7 +203,7 @@ blob_stage = BLOB_STAGE_FIRST send_intercept(BLOB_FIRST_REPORT) SSshuttle?.emergency?.cancel() - SSshuttle?.lockdown_escape() + SSshuttle?.add_hostile_environment(GLOB.blob_cores) if(blob_stage == BLOB_STAGE_FIRST && legit_blobs.len >= min(SECOND_STAGE_COEF * blob_win_count, SECOND_STAGE_THRESHOLD)) blob_stage = BLOB_STAGE_SECOND diff --git a/code/game/gamemodes/blob/blob_finish.dm b/code/game/gamemodes/blob/blob_finish.dm index 83b8f3e819d..16911cba03d 100644 --- a/code/game/gamemodes/blob/blob_finish.dm +++ b/code/game/gamemodes/blob/blob_finish.dm @@ -7,8 +7,8 @@ if(GLOB.security_level == SEC_LEVEL_DELTA) return update_blob_objective() - GLOB.event_announcement.Announce("Объект потерян. Причина: распостранение 5-ой биоугрозы. Взведение устройства самоуничтожения персоналом или внешними силами в данный момент не представляется возможным из-за высокого уровня заражения. Решение: оставить станцию в изоляции до принятия окончательных мер противодействия.", - "Отчет об объекте [station_name()]") + GLOB.event_announcement.Announce("Объект потерян. Причина: распространение биологической угрозы 5-го уровня. Взведение устройства самоуничтожения персоналом или внешними силами в данный момент не представляется возможным из-за высокого уровня заражения. Активация протоколов изоляции.", + "Отчёт об объекте [station_name()]") blob_stage = (delay_blob_end)? BLOB_STAGE_POST_END : BLOB_STAGE_END if(blob_stage == BLOB_STAGE_END) end_game() diff --git a/code/game/gamemodes/blob/blob_report.dm b/code/game/gamemodes/blob/blob_report.dm index 102f76061e3..fb994a6ece6 100644 --- a/code/game/gamemodes/blob/blob_report.dm +++ b/code/game/gamemodes/blob/blob_report.dm @@ -64,10 +64,10 @@ for(var/mob/living/silicon/ai/aiPlayer in GLOB.player_list) if(aiPlayer.client) aiPlayer.laws.clear_zeroth_laws() - SSticker?.score?.save_silicon_laws(aiPlayer, additional_info = "блоб уничтожен, нулевой закон удален") + SSticker?.score?.save_silicon_laws(aiPlayer, additional_info = "организм уничтожен, нулевой закон удален") to_chat(aiPlayer, span_warning("Законы обновлены")) - print_command_report(intercepttext, interceptname, FALSE) + special_directive(intercepttext, interceptname) GLOB.event_announcement.Announce("Отчёт был загружен и распечатан на всех консолях связи.", "Входящее засекреченное сообщение.", 'sound/AI/commandreport.ogg', from = "[command_name()] обновление") /datum/station_state diff --git a/code/game/gamemodes/emergency_shuttle_lockdown.dm b/code/game/gamemodes/emergency_shuttle_lockdown.dm index d5d2e906fec..5f0e64f557a 100644 --- a/code/game/gamemodes/emergency_shuttle_lockdown.dm +++ b/code/game/gamemodes/emergency_shuttle_lockdown.dm @@ -1,9 +1,30 @@ /datum/controller/subsystem/shuttle/proc/lockdown_escape() emergencyNoEscape = TRUE -/datum/controller/subsystem/shuttle/proc/stop_lockdown() - emergencyNoEscape = FALSE +/datum/controller/subsystem/shuttle/proc/add_hostile_environment(environment) + hostile_environment |= environment + +/datum/controller/subsystem/shuttle/proc/remove_hostile_environment(environment, spec_sound) + hostile_environment -= environment + if(!hostile_environment.len) + reload_shuttle(spec_sound = spec_sound, from_hostile = TRUE) + +/datum/controller/subsystem/shuttle/proc/clear_hostile_environment() + LAZYCLEARLIST(hostile_environment) + +/datum/controller/subsystem/shuttle/proc/reload_shuttle(admin_called = FALSE, spec_sound = 'sound/misc/announce_dig.ogg', from_hostile = FALSE) if(emergency.mode == SHUTTLE_STRANDED) + if(hostile_environment.len) + if(!(admin_called && tgui_alert(usr, "Шаттл блокирован угрозами и не улетит, пока они не будут уничтожены. Вы можете удалить угрозы и позволить шаттлу улететь. Действие необратимо.", "Очистить шаттл от угроз?", list("Очистить", "Не очищать")) == "Очистить")) + return FALSE + clear_hostile_environment() + from_hostile = TRUE + emergency.mode = SHUTTLE_DOCKED emergency.timer = world.time + 3 MINUTES - GLOB.priority_announcement.Announce("Угроза устранена. У вас есть 3 минуты, чтобы подняться на борт эвакуационного шаттла.", "Приоритетное оповещение.") + GLOB.priority_announcement.Announce("[from_hostile? "Угроза устранена" : "Блокировка снята"]. У вас есть 3 минуты, чтобы подняться на борт эвакуационного шаттла.", "Приоритетное оповещение.", spec_sound) + return TRUE + return TRUE + +/datum/controller/subsystem/shuttle/proc/stop_lockdown() + emergencyNoEscape = FALSE diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index aa321c9236f..e537ac8b975 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -43,10 +43,8 @@ /// Upper bound on time before intercept arrives. var/const/waittime_h = 180 SECONDS var/list/player_draft_log = list() - var/list/datum/mind/xenos = list() var/list/datum/mind/eventmiscs = list() var/list/datum/mind/traders = list() - var/list/datum/mind/terror_spiders = list() var/list/datum/mind/morphs = list() var/list/datum/mind/swarmers = list() var/list/datum/mind/guardians = list() @@ -770,3 +768,20 @@ sleep(15 SECONDS) SSticker.force_ending = TRUE return + +/datum/game_mode/proc/special_directive(custom_text = null, custom_name = null) + var/intercepttext = custom_text ? custom_text : "" + var/interceptname = custom_name ? custom_name : "" + if(!custom_name) + interceptname = "Директива 7-10" + if(!custom_text) + intercepttext += "Постановление Nanotrasen: Особая директива.
" + intercepttext += "Nanotrasen выпустила директиву 7-10 для [station_name()]. Станцию следует считать закрытой на карантин.
" + intercepttext += "Приказы для всего персонала [station_name()] следующие:
" + intercepttext += " 1. Не покидать карантинную зону.
" + intercepttext += " 2. Обнаружить все очаги угрозы на станции.
" + intercepttext += " 3. При обнаружении использовать любые необходимые средства для сдерживания организмов.
" + intercepttext += " 4. Предотвратить повреждения критической инфраструктуры станции.
" + intercepttext += "
Примечание. в случае нарушения карантина или неконтролируемого распространения биологической угрозы директива 7-10 может быть дополнена директивой 7-12.
" + intercepttext += "Конец сообщения." + print_command_report(intercepttext, interceptname, FALSE) diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm index 379dd5251aa..073f5fe4b1c 100644 --- a/code/game/gamemodes/malfunction/Malf_Modules.dm +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -276,18 +276,15 @@ /obj/machinery/doomsday_device/Destroy() STOP_PROCESSING(SSfastprocess, src) - SSshuttle.emergencyNoEscape = FALSE - if(SSshuttle.emergency.mode == SHUTTLE_STRANDED) - SSshuttle.emergency.mode = SHUTTLE_DOCKED - SSshuttle.emergency.timer = world.time + 3 MINUTES - GLOB.priority_announcement.Announce("Вредоносное окружение устранено. У вас есть 3 минуты, чтобы подняться на борт эвакуационного шаттла.", "Приоритетное оповещение.", 'sound/AI/shuttledock.ogg') + + SSshuttle.remove_hostile_environment(src, 'sound/AI/shuttledock.ogg') return ..() /obj/machinery/doomsday_device/proc/start() detonation_timer = world.time + default_timer timing = 1 START_PROCESSING(SSfastprocess, src) - SSshuttle.emergencyNoEscape = TRUE + SSshuttle.add_hostile_environment(src) /obj/machinery/doomsday_device/proc/seconds_remaining() . = max(0, (round(detonation_timer - world.time) / 10)) @@ -296,11 +293,7 @@ var/turf/T = get_turf(src) if(!T || !is_station_level(T.z)) GLOB.minor_announcement.Announce("УСТРОЙСТВО СУДНОГО ДНЯ ВНЕ ЗОНЫ ДЕЙСТВИЯ СТАНЦИИ, ОСТАНОВКА.", "ОШИБКА ОШИБКА $0ШБК$!А41.%%!!(%$^^__+ @#Ш0E4", 'sound/misc/notice1.ogg') - SSshuttle.emergencyNoEscape = FALSE - if(SSshuttle.emergency.mode == SHUTTLE_STRANDED) - SSshuttle.emergency.mode = SHUTTLE_DOCKED - SSshuttle.emergency.timer = world.time + 3 MINUTES - GLOB.priority_announcement.Announce("Вредоносное окружение устранено. У вас есть 3 минуты, чтобы подняться на борт эвакуационного шаттла.", "Приоритетное оповещение.", 'sound/AI/shuttledock.ogg') + SSshuttle.remove_hostile_environment(src, 'sound/AI/shuttledock.ogg') qdel(src) if(!timing) STOP_PROCESSING(SSfastprocess, src) diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index a0f90147090..787a870bba1 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -494,6 +494,7 @@ GLOBAL_VAR(bomb_set) if(!is_syndicate) set_security_level("delta") GLOB.bomb_set = TRUE // There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke + SSshuttle?.add_hostile_environment(src) else GLOB.bomb_set = TRUE else diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index c1067ad5507..d9046d3524a 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -592,12 +592,12 @@ to_chat(user, "Вызов шаттла эвакуации невозможен. Все контракты считаются расторгнутыми.") return FALSE - if(SSticker?.mode?.blob_stage >= BLOB_STAGE_FIRST && SSshuttle.emergencyNoEscape) - to_chat(user, span_warning("Согласно директиве 7-10, [station_name()] находится на карантине до дальнейшего уведомления.")) + if(SSshuttle.hostile_environment.len) + to_chat(user, span_warning("Обнаружена угроза на борту [station_name()]. Вызов шаттла заблокирован.")) return FALSE if(SSshuttle.emergencyNoEscape) - to_chat(user, "В настоящее время у Центрального Командования нет свободного шаттла в вашем секторе. Пожалуйста, повторите попытку позже.") + to_chat(user, "Вызов шаттла заблокирован. Свяжитесь с Центральным Командованием для уточнения причин и снятия блокировки.") return FALSE if(EMERGENCY_ESCAPED_OR_ENDGAMED) diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index b731d65179f..f51a493800d 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -2,6 +2,7 @@ /obj/structure/spider name = "web" desc = "it's stringy and sticky" + gender = FEMALE icon = 'icons/effects/effects.dmi' anchored = TRUE density = FALSE @@ -62,6 +63,7 @@ desc = "They seem to pulse slightly with an inner life" icon_state = "eggs" var/amount_grown = 0 + var/grown_tick_count = 100 var/player_spiders = 0 var/list/faction = list("spiders") @@ -76,7 +78,7 @@ return amount_grown += rand(0,2) - if(amount_grown >= 100) + if(amount_grown >= grown_tick_count) var/num = rand(3, 12) for(var/i in 1 to num) var/obj/structure/spider/spiderling/S = new /obj/structure/spider/spiderling(loc) diff --git a/code/modules/admin/check_antagonists.dm b/code/modules/admin/check_antagonists.dm index d2a7488f71e..dfe7668bc45 100644 --- a/code/modules/admin/check_antagonists.dm +++ b/code/modules/admin/check_antagonists.dm @@ -29,12 +29,11 @@ if(!SSshuttle.emergencyNoEscape) dat += "Lockdown Shuttle
" else - if(SSshuttle.emergency.mode == SHUTTLE_STRANDED) - dat += span_danger("Emergency shuttle stranded") - dat += "
Stop lockdown and De-Strandise
" - else - dat += span_danger("Emergency shuttle lockdowned") - dat += "
Stop lockdown
" + dat += span_danger("Emergency shuttle lockdowned") + dat += "
Stop lockdown
" + if(SSshuttle.emergency.mode == SHUTTLE_STRANDED) + dat += span_danger("Emergency shuttle stranded") + dat += "
Reload Shuttle
" dat += "Full LockdownNow: [GLOB.full_lockdown? "ON" : "OFF"]
" dat += "[SSticker.delay_end ? "End Round Normally" : "Delay Round End"]
" var/connected_players = GLOB.clients.len @@ -275,9 +274,6 @@ if(SSticker.mode.devils.len) dat += check_role_table("Devils", SSticker.mode.devils) - if(SSticker.mode.xenos.len) - dat += check_role_table("Xenos", SSticker.mode.xenos) - if(SSticker.mode.superheroes.len) dat += check_role_table("Superheroes", SSticker.mode.superheroes) @@ -290,24 +286,6 @@ if(SSticker.mode.eventmiscs.len) dat += check_role_table("Event Roles", SSticker.mode.eventmiscs) - if(GLOB.ts_spiderlist.len) - var/list/spider_minds = list() - for(var/mob/living/simple_animal/hostile/poison/terror_spider/S in GLOB.ts_spiderlist) - if(S.ckey) - spider_minds += S.mind - if(spider_minds.len) - dat += check_role_table("Terror Spiders", spider_minds) - - var/count_eggs = 0 - var/count_spiderlings = 0 - for(var/obj/structure/spider/eggcluster/terror_eggcluster/E in GLOB.ts_egg_list) - if(is_station_level(E.z)) - count_eggs += E.spiderling_number - for(var/obj/structure/spider/spiderling/terror_spiderling/L in GLOB.ts_spiderling_list) - if(!L.stillborn && is_station_level(L.z)) - count_spiderlings += 1 - dat += "
Growing TS on-station: [count_eggs] egg[count_eggs != 1 ? "s" : ""], [count_spiderlings] spiderling[count_spiderlings != 1 ? "s" : ""].
" - if(SSticker.mode.ert.len) dat += check_role_table("ERT", SSticker.mode.ert) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index b3317970b77..8599940529a 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -45,51 +45,59 @@ if("1") log_admin("[key_name(usr)] has spawned a traitor.") if(!makeTraitors()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("2") log_admin("[key_name(usr)] has spawned a changeling.") if(!makeChangelings()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("3") log_admin("[key_name(usr)] has spawned revolutionaries.") if(!makeRevs()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("4") log_admin("[key_name(usr)] has spawned a cultists.") if(!makeCult()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("5") log_admin("[key_name(usr)] has spawned a clockers.") if(!makeClockwork()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("6") log_admin("[key_name(usr)] has spawned a wizard.") if(!makeWizard()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("7") log_admin("[key_name(usr)] has spawned vampires.") if(!makeVampires()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("8") log_admin("[key_name(usr)] has spawned vox raiders.") if(!makeVoxRaiders()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("9") log_admin("[key_name(usr)] has spawned an abductor team.") if(!makeAbductorTeam()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("10") log_admin("[key_name(usr)] has spawned a space ninja.") if(!makeSpaceNinja()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("11") log_admin("[key_name(usr)] has spawned a thief.") if(!makeThieves()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) if("12") log_admin("[key_name(usr)] has spawned a blob.") if(!makeBlobs()) - to_chat(usr, "Unfortunately there weren't enough candidates available.", confidential=TRUE) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) + if("13") + log_admin("[key_name(usr)] has spawned a terror spiders.") + if(!makeTerrorSpiders()) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) + if("14") + log_admin("[key_name(usr)] has spawned a xemonorphs.") + if(!makeAliens()) + to_chat(usr, span_warning("К сожалению, желающих было слишком мало."), confidential=TRUE) else if(href_list["dbsearchckey"] || href_list["dbsearchadmin"] || href_list["dbsearchip"] || href_list["dbsearchcid"] || href_list["dbsearchbantype"]) var/adminckey = href_list["dbsearchadmin"] @@ -414,6 +422,17 @@ log_and_message_admins(span_adminnotice("[key_name_admin(usr)] lockdowned the Emergency Shuttle")) href_list["secrets"] = "check_antagonist" + else if(href_list["reload_shuttle"]) + if(!check_rights(R_ADMIN)) + return + + if(!you_realy_want_do_this()) + return + + if(SSshuttle?.reload_shuttle(TRUE)) + log_and_message_admins(span_adminnotice("[key_name_admin(usr)] reloaded the Emergency Shuttle")) + href_list["secrets"] = "check_antagonist" + else if(href_list["full_lockdown"]) if(!check_rights(R_ADMIN)) return @@ -2046,6 +2065,7 @@ log_admin("[key_name(usr)] has [mode.delay_blob_end? "stopped" : "returned"] stopped delayed blob win") message_admins("[key_name_admin(usr)] has [mode.delay_blob_end? "stopped" : "returned"] delayed blob win") + else if(href_list["toggle_blob_infinity_points"]) if(!check_rights(R_ADMIN)) return @@ -2140,6 +2160,8 @@ var/datum/objective/objective = locateUID(href_list["objective"]) if(objective) team.admin_remove_objective(usr, objective) + else + team.Topic(href, href_list) check_teams() diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 90156c24f38..ca8e573d57e 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -25,6 +25,8 @@ Make Space Ninja (Requires Ghosts)
Make Thieves
Make Blobs
+ Make Terror Spiders
+ Make Aliens
"} usr << browse(dat, "window=oneclickantag;size=400x400") return @@ -112,7 +114,7 @@ var/antnum = tgui_input_number(owner, "Сколько вы хотите создать? Введите 0 для отмены.","Кол-во:", 0) if(!antnum || antnum <= 0) - return + return FALSE log_admin("[key_name(owner)] tried making [antnum] blobs with One-Click-Antag") message_admins("[key_name_admin(owner)] tried making [antnum] blobs with One-Click-Antag") var/result = FALSE @@ -123,6 +125,18 @@ result = SSticker?.mode?.make_blobized_mouses(antnum) return result +/datum/admins/proc/makeTerrorSpiders() + + var/antnum = tgui_input_number(owner, "Сколько вы хотите создать? Введите 0 для отмены.","Кол-во:", 0, min_value = 0) + if(!antnum) + return FALSE + log_admin("[key_name(owner)] tried making [antnum] terror spiders with One-Click-Antag") + message_admins("[key_name_admin(owner)] tried making [antnum] terror spiders with One-Click-Antag") + var/result = FALSE + var/type = tgui_input_list(usr, "Выберите тип паука", "Тип паука", SPAWN_TERROR_TYPES) + result = create_terror_spiders(type, antnum) + return result + /datum/admins/proc/makeRevs() var/datum/game_mode/revolution/temp = new @@ -330,18 +344,12 @@ return 1 /datum/admins/proc/makeAliens() - var/datum/event/alien_infestation/E = new /datum/event/alien_infestation - var/antnum = tgui_input_number(owner, "How many aliens you want to create? Enter 0 to cancel.", "Amount:", 0) + var/antnum = tgui_input_number(owner, "Сколько ксеноморфов создать? Введите 0 для отмены.","Количество:", 0) if(!antnum || antnum <= 0) return - log_admin("[key_name(owner)] tried making Aliens with One-Click-Antag") - message_admins("[key_name_admin(owner)] tried making Aliens with One-Click-Antag") - - E.spawncount = antnum - // TODO The fact we have to do this rather than just have events start - // when we ask them to, is bad. - E.processing = TRUE + log_and_message_admins("tried making Aliens with One-Click-Antag") + spawn_aliens(antnum) return TRUE diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 6ac97775e68..a343cdc6142 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -24,6 +24,8 @@ GLOBAL_LIST_EMPTY(antagonists_datums) var/list/objectives /// A list of strings which contain [targets][/datum/objective/var/target] of the antagonist's objectives. Used to prevent duplicate objectives. var/list/assigned_targets + /// Current antagonist teams + var/datum/team/team /// Antagonist datum specific information that appears in the player's notes. Information stored here will be removed when the datum is removed from the player. var/antag_memory /// The special role that will be applied to the owner's `special_role` var. i.e. `SPECIAL_ROLE_TRAITOR`, `SPECIAL_ROLE_VAMPIRE`. @@ -410,6 +412,9 @@ GLOBAL_LIST_EMPTY(antagonists_datums) * Creates a new antagonist team. */ /datum/antagonist/proc/create_team(datum/team/team) + if(!GLOB.antagonist_teams[team]) + new team + src.team = GLOB.antagonist_teams[team] return @@ -417,7 +422,7 @@ GLOBAL_LIST_EMPTY(antagonists_datums) * Returns the team the antagonist belongs to, if any. */ /datum/antagonist/proc/get_team() - return + return team /** diff --git a/code/modules/antagonists/_common/antag_team.dm b/code/modules/antagonists/_common/antag_team.dm index 5c474c665c4..239e759b1f7 100644 --- a/code/modules/antagonists/_common/antag_team.dm +++ b/code/modules/antagonists/_common/antag_team.dm @@ -12,9 +12,12 @@ GLOBAL_LIST_EMPTY(antagonist_teams) var/list/members /// A list of objectives which all team members share. var/list/objectives + /// A list of special objectives which some team members have. + var/list/special_objectives /// Type of antag datum members of this team have. Also given to new members added by admins. var/antag_datum_type - + /// Is antag hud need to see this team in orbit + var/need_antag_hud = TRUE /datum/team/New(list/starting_members) ..() @@ -24,7 +27,7 @@ GLOBAL_LIST_EMPTY(antagonist_teams) starting_members = list(starting_members) for(var/datum/mind/M as anything in starting_members) add_member(M) - GLOB.antagonist_teams += src + GLOB.antagonist_teams[type] = src /datum/team/Destroy(force = FALSE) @@ -32,7 +35,7 @@ GLOBAL_LIST_EMPTY(antagonist_teams) remove_member(member) QDEL_LIST(objectives) members.Cut() - GLOB.antagonist_teams -= src + GLOB.antagonist_teams -= type return ..() @@ -41,12 +44,22 @@ GLOBAL_LIST_EMPTY(antagonist_teams) * * Generally this should ONLY be called by `add_antag_datum()` to ensure proper order of operations. */ -/datum/team/proc/add_member(datum/mind/new_member) +/datum/team/proc/add_member(datum/mind/new_member, add_objectives = TRUE) SHOULD_CALL_PARENT(TRUE) var/datum/antagonist/team_antag = get_antag_datum_from_member(new_member) members |= new_member - team_antag.objectives |= objectives + if(add_objectives) + team_antag.objectives |= objectives +/** + * Return count of alife `members`. + */ +/datum/team/proc/alife_members_count() + var/count = 0 + for(var/datum/mind/mind in members) + if(!QDELETED(mind?.current) && mind.current.stat != DEAD) + count++ + return count /** * Removes `member` from this team. @@ -63,7 +76,7 @@ GLOBAL_LIST_EMPTY(antagonist_teams) */ /datum/team/proc/admin_add_member(mob/user) var/list/valid_minds = list() - for(var/mob/living/carbon/human/player in GLOB.player_list) + for(var/mob/player in GLOB.player_list) if(!player.mind || (player.mind in members)) continue valid_minds[player.real_name] = player.mind @@ -80,11 +93,11 @@ GLOBAL_LIST_EMPTY(antagonist_teams) /** * Adds a team objective to each member's matching antag datum. */ -/datum/team/proc/add_objective_to_members(datum/objective/objective) - for(var/datum/mind/member as anything in members) +/datum/team/proc/add_objective_to_members(datum/objective/objective, list/member_blacklist) + for(var/datum/mind/member as anything in (members - member_blacklist)) var/datum/antagonist/antag = get_antag_datum_from_member(member) antag.objectives |= objective - + objectives |= objective /** * Remove a team objective from each member's matching antag datum. @@ -189,6 +202,8 @@ GLOBAL_LIST_EMPTY(antagonist_teams) c_back.Invoke(usr) return + admin_topic(href_list["team_command"]) + /** * A list of team-specific admin commands for this team. Should be in the form of `"command" = CALLBACK(x, PROC_REF(some_proc))`. @@ -196,7 +211,11 @@ GLOBAL_LIST_EMPTY(antagonist_teams) /datum/team/proc/get_admin_commands() return list() +/datum/team/proc/get_admin_texts() + return list() +/datum/team/proc/admin_topic(command) + return /** * Opens a window which lists the teams for the round. */ @@ -218,7 +237,8 @@ GLOBAL_LIST_EMPTY(antagonist_teams) if(!length(GLOB.antagonist_teams)) content += "There are currently no antag teams." - for(var/datum/team/check_team as anything in GLOB.antagonist_teams) + for(var/team_type as anything in GLOB.antagonist_teams) + var/datum/team/check_team = GLOB.antagonist_teams[team_type] content += "

[check_team.name] - [check_team.type]

" content += "Rename Team" content += "Delete Team" @@ -226,9 +246,14 @@ GLOBAL_LIST_EMPTY(antagonist_teams) for(var/command in check_team.get_admin_commands()) // _src_ is T.UID() so it points to `/datum/team/Topic` instead of `/datum/admins/Topic`. - content += "[command]" + content += "[command]" + for(var/text in check_team.get_admin_texts()) + content += text content += "

Objectives:
    " + for(var/datum/objective/objective as anything in check_team.special_objectives) + content += "
  1. [objective.explanation_text]
  2. " + for(var/datum/objective/objective as anything in check_team.objectives) content += "
  3. [objective.explanation_text] - Remove
  4. " @@ -239,6 +264,8 @@ GLOBAL_LIST_EMPTY(antagonist_teams) content += "
  5. [member.name] - Show Player Panel" content += "Remove Member
  6. " content += "
Add Member
" - + content += "
" return content.Join() +/datum/team/proc/declare_completion() + return diff --git a/code/modules/antagonists/blob/blob_minions/blob_zombie.dm b/code/modules/antagonists/blob/blob_minions/blob_zombie.dm index aa7c398b808..252661eaa29 100644 --- a/code/modules/antagonists/blob/blob_minions/blob_zombie.dm +++ b/code/modules/antagonists/blob/blob_minions/blob_zombie.dm @@ -115,6 +115,7 @@ AddComponent(\ /datum/component/ghost_direct_control,\ ban_type = ROLE_BLOB,\ + ban_syndicate = TRUE,\ poll_candidates = TRUE,\ ) diff --git a/code/modules/antagonists/blob/structures/core.dm b/code/modules/antagonists/blob/structures/core.dm index 001503a19ba..ccf73c5cfa6 100644 --- a/code/modules/antagonists/blob/structures/core.dm +++ b/code/modules/antagonists/blob/structures/core.dm @@ -30,6 +30,8 @@ /obj/structure/blob/special/core/Initialize(mapload, client/new_overmind = null, offspring) GLOB.blob_cores += src + if(SSticker?.mode?.blob_stage >= BLOB_STAGE_FIRST) + SSshuttle?.add_hostile_environment(src) START_PROCESSING(SSobj, src) GLOB.poi_list |= src update_blob() //so it atleast appears @@ -47,6 +49,7 @@ /obj/structure/blob/special/core/Destroy() GLOB.blob_cores -= src + SSshuttle?.remove_hostile_environment(src) if(overmind) overmind.blob_core = null QDEL_NULL(overmind) diff --git a/code/modules/antagonists/space_dragon/space_dragon_datum.dm b/code/modules/antagonists/space_dragon/space_dragon_datum.dm index 1c6a385cb4a..1a55fb37887 100644 --- a/code/modules/antagonists/space_dragon/space_dragon_datum.dm +++ b/code/modules/antagonists/space_dragon/space_dragon_datum.dm @@ -162,7 +162,8 @@ rift.carp_stored = 999999 rift.time_charged = rift.max_charge SSshuttle.emergency.canRecall = FALSE - SSshuttle.emergencyNoEscape = FALSE + SSshuttle.stop_lockdown() + SSshuttle.clear_hostile_environment() if(EMERGENCY_AT_LEAST_DOCKED) return SSshuttle.emergency.request(coefficient = 0.5) diff --git a/code/modules/antagonists/terror_spiders/_terror_spider.dm b/code/modules/antagonists/terror_spiders/_terror_spider.dm new file mode 100644 index 00000000000..bdfe1b96cf9 --- /dev/null +++ b/code/modules/antagonists/terror_spiders/_terror_spider.dm @@ -0,0 +1,187 @@ +/datum/antagonist/terror_spider + name = "Terror Spider" + roundend_category = "terror spiders" + job_rank = ROLE_TERROR_SPIDER + special_role = SPECIAL_ROLE_TERROR_SPIDER + wiki_page_name = "Terror_Spider" + russian_wiki_name = "Паук_Ужаса" + show_in_roundend = FALSE + show_in_orbit = FALSE + antag_menu_name = "Паук Ужаса" + var/datum/team/terror_spiders/terror_team + var/spider_category = TERROR_OTHER + var/spider_intro_text = "Если ты это видишь, это баг." + +/datum/antagonist/terror_spider/on_gain() + if(!isterrorspider(owner.current)) + stack_trace("This antag datum cannot be attached to a mob of this type.") + var/mob/living/simple_animal/hostile/poison/terror_spider/spider = owner.current + spider_intro_text = spider.spider_intro_text + terror_team = team + . = ..() + +/datum/antagonist/terror_spider/apply_innate_effects(mob/living/mob_override) + . = ..() + reg_spider_signals() + +/datum/antagonist/terror_spider/remove_innate_effects(mob/living/mob_override) + . = ..() + unreg_spider_signals() + +/datum/antagonist/terror_spider/proc/reg_spider_signals() + RegisterSignal(owner, COMSIG_EMPRESS_EGG_LAYED, PROC_REF(on_empress_egg_layed)) + return + +/datum/antagonist/terror_spider/proc/unreg_spider_signals() + UnregisterSignal(owner, COMSIG_EMPRESS_EGG_LAYED) + return + +/datum/antagonist/terror_spider/proc/on_empress_egg_layed() + SIGNAL_HANDLER + return + +/datum/antagonist/terror_spider/give_objectives() + if(!terror_team.other_target) + terror_team.other_target = new + terror_team.other_target.owner = team + terror_team.other_target.generate_text(terror_team) + add_objective(terror_team.other_target) + terror_team.other_target.check_completion() + +/datum/antagonist/terror_spider/roundend_report_header() + return + +/datum/antagonist/terror_spider/greet() + var/list/messages = list() + messages.Add(span_danger("
Вы - Паук Ужаса!
")) + messages.Add("
Работайте сообща, помогайте своим братьям и сёстрам, саботируйте станцию, убивайте экипаж, превратите это место в своё гнездо!
") + messages.Add(span_big("
[spider_intro_text]

")) + SEND_SOUND(owner.current, sound('sound/ambience/antag/terrorspider.ogg')) + return messages + +/datum/antagonist/terror_spider/main_spider + var/datum/objective/spider_get_power/power_objective + var/datum/action/innate/terrorspider/lay_empress_egg/egg_action + +/datum/antagonist/terror_spider/main_spider/reg_spider_signals() + . = ..() + RegisterSignal(owner, COMSIG_SPIDER_CAN_LAY, PROC_REF(add_egg_power)) + RegisterSignal(owner, COMSIG_TERROR_SPIDER_DIED, PROC_REF(on_terror_spider_died)) + +/datum/antagonist/terror_spider/main_spider/unreg_spider_signals() + . = ..() + UnregisterSignal(owner, list(COMSIG_SPIDER_CAN_LAY, COMSIG_TERROR_SPIDER_DIED)) + +/datum/antagonist/terror_spider/main_spider/proc/on_terror_spider_died() + SIGNAL_HANDLER + terror_team.on_major_spider_died(owner, spider_category) + unreg_spider_signals() + +/datum/antagonist/terror_spider/main_spider/on_empress_egg_layed() + . = ..() + if(owner?.current) + egg_action?.Remove(owner.current) + QDEL_NULL(egg_action) + +/datum/antagonist/terror_spider/main_spider/add_owner_to_gamemode() + . = ..() + terror_team.on_major_spider_created(owner, spider_category) + +/datum/antagonist/terror_spider/main_spider/give_objectives() + if(!terror_team.lay_eggs_target) + terror_team.lay_eggs_target = new + terror_team.lay_eggs_target.owner = team + terror_team.lay_eggs_target.generate_text() + add_objective(terror_team.lay_eggs_target) + power_objective = terror_team.lay_eggs_target + check_target() + + +/datum/antagonist/terror_spider/main_spider/remove_owner_from_gamemode() + . = ..() + var/list/spiders = terror_team.main_spiders[spider_category] + spiders -= owner + +/datum/antagonist/terror_spider/main_spider/proc/check_target() + if(power_objective?.check_completion() && !terror_team.empress_egg) + add_egg_power() + +/datum/antagonist/terror_spider/main_spider/proc/add_egg_power() + SIGNAL_HANDLER + if(owner?.current && !egg_action && !terror_team.empress_egg) + egg_action = new + egg_action.spider_team = WEAKREF(team) + egg_action.Grant(owner.current) + return + +/datum/antagonist/terror_spider/main_spider/empress + antag_menu_name = "Императрица Ужаса" + +/datum/antagonist/terror_spider/main_spider/empress/check_target() + return + +/datum/antagonist/terror_spider/main_spider/empress/give_objectives() + return + +/datum/antagonist/terror_spider/main_spider/defiler + spider_category = TERROR_DEFILER + special_role = SPECIAL_ROLE_TERROR_DEFILER + antag_menu_name = "Осквернитель Ужаса" + +/datum/antagonist/terror_spider/main_spider/defiler/give_objectives() + if(!terror_team.infect_target) + terror_team.infect_target = new + terror_team.infect_target.owner = team + terror_team.infect_target.generate_text() + add_objective(terror_team.infect_target) + power_objective = terror_team.infect_target + check_target() + +/datum/antagonist/terror_spider/main_spider/queen + spider_category = TERROR_QUEEN + special_role = SPECIAL_ROLE_TERROR_QUEEN + antag_menu_name = "Королева Ужаса" + +/datum/antagonist/terror_spider/main_spider/princess + spider_category = TERROR_PRINCESS + special_role = SPECIAL_ROLE_TERROR_PRINCESS + antag_menu_name = "Принцесса Ужаса" + +/datum/antagonist/terror_spider/main_spider/prince + spider_category = TERROR_PRINCE + special_role = SPECIAL_ROLE_TERROR_PRINCE + antag_menu_name = "Принц Ужаса" + var/total_targets_count = 0 + +/datum/antagonist/terror_spider/main_spider/prince/finalize_antag() + . = ..() + terror_team.check_announce() + +/datum/antagonist/terror_spider/main_spider/prince/reg_spider_signals() + . = ..() + RegisterSignal(owner, COMSIG_HUMAN_EATEN, PROC_REF(increment_target)) + +/datum/antagonist/terror_spider/main_spider/prince/unreg_spider_signals() + . = ..() + UnregisterSignal(owner, COMSIG_HUMAN_EATEN) + +/datum/antagonist/terror_spider/main_spider/prince/proc/increment_target() + SIGNAL_HANDLER + total_targets_count++ + check_target() + +/datum/antagonist/terror_spider/main_spider/prince/check_target() + if(power_objective.check_completion(total_targets_count, team)) + add_egg_power() + +/datum/antagonist/terror_spider/main_spider/prince/give_objectives() + var/datum/game_mode/mode = SSticker?.mode + if(!mode) + return + if(!terror_team.prince_target) + terror_team.prince_target= new + terror_team.prince_target.owner = team + terror_team.prince_target.generate_text() + add_objective(terror_team.prince_target) + power_objective = terror_team.prince_target + check_target() diff --git a/code/modules/antagonists/terror_spiders/spider_team.dm b/code/modules/antagonists/terror_spiders/spider_team.dm new file mode 100644 index 00000000000..dc5942003c5 --- /dev/null +++ b/code/modules/antagonists/terror_spiders/spider_team.dm @@ -0,0 +1,330 @@ +GLOBAL_VAR_INIT(global_degenerate, FALSE) + +/datum/team/terror_spiders + name = "Пауки Ужаса" + antag_datum_type = /datum/antagonist/terror_spider + need_antag_hud = FALSE + var/list/main_spiders = list(TERROR_QUEEN = list(), TERROR_PRINCE = list(), TERROR_PRINCESS = list(), TERROR_DEFILER = list()) + var/list/terror_infections = list() + var/list/terror_eggs = list() + var/datum/objective/spider_get_power/eat_humans/prince_target + var/datum/objective/spider_get_power/alife_spiders/lay_eggs_target + var/datum/objective/spider_get_power/spider_infections/infect_target + var/datum/objective/spider_protect/other_target + var/datum/objective/spider_protect_egg/protect_egg + var/obj/structure/spider/eggcluster/terror_eggcluster/empress/empress_egg + var/terror_announce = FALSE + var/terror_stage = TERROR_STAGE_START + var/delay_terror_end = FALSE + +/datum/team/terror_spiders/New(list/starting_members) + . = ..() + RegisterSignal(SSdcs, COMSIG_GLOB_EMPRESS_EGG_DESTROYED, PROC_REF(on_empress_egg_destroyed)) + RegisterSignal(SSdcs, COMSIG_GLOB_EMPRESS_EGG_BURST, PROC_REF(on_empress_egg_burst)) + RegisterSignal(SSdcs, COMSIG_GLOB_IFECTION_CREATED, PROC_REF(on_terror_infection_created)) + RegisterSignal(SSdcs, COMSIG_GLOB_IFECTION_REMOVED, PROC_REF(on_terror_infection_removed)) + + +/datum/team/terror_spiders/Destroy(force) + . = ..() + UnregisterSignal(SSdcs, list(COMSIG_GLOB_EMPRESS_EGG_DESTROYED, COMSIG_GLOB_IFECTION_REMOVED, COMSIG_GLOB_EMPRESS_EGG_BURST, COMSIG_GLOB_IFECTION_CREATED)) + +/datum/team/terror_spiders/add_member(datum/mind/new_member, add_objectives) + if(!new_member?.current || !isterrorspider(new_member.current)) + return + var/already_in = (new_member in members) + var/mob/living/simple_animal/hostile/poison/terror_spider/spider = new_member.current + spider.add_datum_if_not_exist() + . = ..() + if(!already_in) + on_minor_spider_created(new_member) + +/datum/team/terror_spiders/proc/spider_announce() + GLOB.event_announcement.Announce("Вспышка биологической угрозы 3-го уровня зафиксирована на борту станции [station_name()]. Всему персоналу надлежит сдержать её распространение любой ценой! Особая директива распечатана на всех консолях связи.", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/effects/siren-spooky.ogg') + SSticker?.mode?.special_directive() + SSshuttle?.emergency.cancel() + for(var/datum/mind/mind as anything in get_main_spiders()) + if(mind.current && mind.current.stat != DEAD) + SSshuttle?.add_hostile_environment(mind) + +/datum/team/terror_spiders/proc/egg_announce() + if(QDELETED(empress_egg)) + return + GLOB.event_announcement.Announce("На борту станции [station_name()] зафиксирована биологическая сигнатура яйца Императрицы Ужаса в [get_area(empress_egg)]. Уничтожьте его, пока ситуация не вышла из под контроля.", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/effects/siren-spooky.ogg') + +/datum/team/terror_spiders/proc/spider_win_announce() + GLOB.event_announcement.Announce("Подтверждено наличие Императрицы Ужаса на борту [station_name()]. Станция переклассифицированна в гнездо биоугрозы 3-го уровня. Взведение устройства самоуничтожения персоналом или внешними силами в данный момент не представляется возможным. Активация протоколов изоляции.", "Отчет об объекте [station_name()]") + +/datum/team/terror_spiders/proc/get_main_spiders() + return main_spiders[TERROR_QUEEN] + \ + main_spiders[TERROR_PRINCE] + \ + main_spiders[TERROR_PRINCESS] + \ + main_spiders[TERROR_DEFILER] + +/datum/team/terror_spiders/proc/check_main_spiders() + var/list/major_spiders = get_main_spiders() + for(var/datum/mind/spider as anything in major_spiders) + if(!QDELETED(spider) && spider?.current?.stat != DEAD) + return TRUE + return FALSE + + +/datum/team/terror_spiders/proc/on_terror_infection_created(source, eggs) + SIGNAL_HANDLER + terror_infections |= eggs + check_announce() + if(infect_target.check_completion(spider_team = src)) + for(var/datum/spider in main_spiders[TERROR_DEFILER]) + SEND_SIGNAL(spider, COMSIG_SPIDER_CAN_LAY) + +/datum/team/terror_spiders/proc/on_minor_spider_created(mind) + check_announce() + if(lay_eggs_target?.check_completion(spider_team = src)) + for(var/datum/spider in (main_spiders[TERROR_QUEEN] + main_spiders[TERROR_PRINCESS])) + SEND_SIGNAL(spider, COMSIG_SPIDER_CAN_LAY) + +/datum/team/terror_spiders/proc/get_terror_spiders_alife_count() + var/alife_count = 0 + for(var/datum/mind/mind as anything in members) + if(!QDELETED(mind.current) && mind.current.stat != DEAD) + alife_count++ + return alife_count + +/datum/team/terror_spiders/proc/on_major_spider_created(mind, type) + if(type == TERROR_OTHER) + return + var/list/spiders = main_spiders[type] + spiders |= mind + other_target?.generate_text(src) + if(terror_announce) + SSshuttle?.add_hostile_environment(mind) + +/datum/team/terror_spiders/proc/check_announce() + if(terror_announce) + return TRUE + var/crew_count = num_station_players() + var/result = FALSE + + if(length(main_spiders[TERROR_PRINCE])) + result = TRUE + + var/main_spider_exist = check_main_spiders() + + if(main_spider_exist && terror_infections.len > crew_count * INFECTIONS_ANNOUNCE_TRIGGER) + result = TRUE + + if(main_spider_exist && get_terror_spiders_alife_count() > crew_count * SPIDERS_ANNOUNCE_TRIGGER) + result = TRUE + + if(result) + terror_announce = TRUE + spider_announce() + return result + +/datum/team/terror_spiders/proc/on_major_spider_died(mind, type) + ASYNC + SSshuttle?.remove_hostile_environment(mind) + + +/datum/team/terror_spiders/proc/on_terror_infection_removed(source, eggs) + SIGNAL_HANDLER + terror_infections -= eggs + +/datum/team/terror_spiders/proc/on_empress_egg_layed(egg) + empress_egg = egg + terror_stage = TERROR_STAGE_PROTECT_EGG + for(var/datum/spider as anything in members) + SEND_SIGNAL(spider, COMSIG_EMPRESS_EGG_LAYED) + give_protect_egg_objective() + addtimer(CALLBACK(src, PROC_REF(egg_announce)), TIME_TO_ANNOUNCE) + + +/datum/team/terror_spiders/proc/give_protect_egg_objective() + if(!protect_egg) + protect_egg = new + protect_egg.owner = src + protect_egg.generate_text(spider_team = src) + if(protect_egg in objectives) + return + + add_objective_to_members(protect_egg) + +/datum/team/terror_spiders/proc/on_empress_egg_burst() + SIGNAL_HANDLER + empress_egg = null + RegisterSignal(SSdcs, COMSIG_GLOB_WEB_STORM_ENDED, PROC_REF(on_web_storm_ended)) + INVOKE_ASYNC(SSweather, TYPE_PROC_REF(/datum/controller/subsystem/weather, run_weather), /datum/weather/web_storm) + protect_egg.completed = TRUE + terror_stage = TERROR_STAGE_STORM + +/datum/team/terror_spiders/proc/on_web_storm_ended() + SIGNAL_HANDLER + spider_win_announce() + terror_stage = TERROR_STAGE_END + if(delay_terror_end) + terror_stage = TERROR_STAGE_POST_END + else + SSticker?.mode?.end_game() + UnregisterSignal(SSdcs, COMSIG_GLOB_WEB_STORM_ENDED) + +/datum/team/terror_spiders/proc/on_empress_egg_destroyed() + SIGNAL_HANDLER + GLOB.global_degenerate = TRUE + for(var/mob/spider in GLOB.ts_spiderlist) + if(spider) + to_chat(spider, span_danger("Вы чувствуесте невообразимую боль. Яйцо Императрицы уничтожено.")) + erase_eggs() + +/datum/team/terror_spiders/proc/erase_eggs() + for(var/infection in terror_infections) + qdel(infection) + for(var/egg in terror_eggs) + qdel(egg) + + +/datum/team/terror_spiders/proc/delay_terror_win() + delay_terror_end = TRUE + +/datum/team/terror_spiders/proc/return_terror_win() + delay_terror_end = FALSE + +/datum/team/terror_spiders/proc/declare_results() + if(SSticker?.mode?.station_was_nuked && !terror_stage == TERROR_STAGE_POST_END) + to_chat(world, "
Частичная победа Пауков Ужаса!") + to_chat(world, "Станция была уничтожена!") + to_chat(world, "Устройство самоуничтожения сработало, предотвратив распространение Пауков Ужаса.") + else if(protect_egg.check_completion(src)) + to_chat(world, "
Полная победа Пауков Ужаса!") + to_chat(world, "Пауки захватили станцию!") + to_chat(world, "Императрица Ужаса появилась на свет, превратив всю станцию в гнездо.") + else if(!check_main_spiders()) + to_chat(world, "
Полная победа персонала станции!") + to_chat(world, "Экипаж защитил станцию от Пауков Ужаса!") + to_chat(world, "Пауки Ужаса были истреблены.") + else + to_chat(world, "
Ничья!") + to_chat(world, "Экипаж эвакуирован!") + to_chat(world, "Пауки Ужаса не были истреблены.") + to_chat(world, "Целями Пауков Ужаса было:") + if(prince_target) + to_chat(world, "
Цель Принца: [prince_target.explanation_text] [prince_target.completed?"Успех!": "Провал."]") + SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[prince_target.type]", prince_target.completed? "SUCCESS" : "FAIL")) + if(infect_target) + to_chat(world, "
Цель Осквернителя: [infect_target.explanation_text] [infect_target.completed?"Успех!": "Провал."]") + SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[infect_target.type]", infect_target.completed? "SUCCESS" : "FAIL")) + if(lay_eggs_target) + to_chat(world, "
Цель Принцессы/Королевы: [lay_eggs_target.explanation_text] [lay_eggs_target.completed?"Успех!": "Провал."]") + SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[lay_eggs_target.type]", lay_eggs_target.completed? "SUCCESS" : "FAIL")) + if(other_target) + to_chat(world, "
Цель Пауков Ужаса: [other_target.explanation_text] [other_target.completed?"Успех!": "Провал."]") + SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[other_target.type]", other_target.completed? "SUCCESS" : "FAIL")) + if(protect_egg) + var/completed = protect_egg.completed && (!SSticker?.mode?.station_was_nuked || terror_stage == TERROR_STAGE_POST_END) + to_chat(world, "
Защита яйца: [protect_egg.explanation_text] [completed ?"Успех!": "Провал."]") + SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[protect_egg.type]", completed ? "SUCCESS" : "FAIL")) + return TRUE + + +/datum/team/terror_spiders/declare_completion() + var/list/terror_queens = main_spiders[TERROR_QUEEN] + var/list/terror_princes = main_spiders[TERROR_PRINCE] + var/list/terror_princesses = main_spiders[TERROR_PRINCESS] + var/list/terror_defilers = main_spiders[TERROR_DEFILER] + + if(terror_queens.len || terror_princes.len || terror_princesses.len || terror_defilers.len) + declare_results() + var/text = "
Основа гнезда:" + text += "
Королев[(terror_queens?.len > 1 ? "ами были" : "ой был")]:" + for(var/datum/mind/spider in terror_queens) + text += "
[spider.key] был [spider.name]" + text += "
Принц[(terror_queens?.len > 1 ? "ами были" : "ем был")]:" + for(var/datum/mind/spider in terror_princes) + text += "
[spider.key] был [spider.name]" + text += "
Принцесс[(terror_queens?.len > 1 ? "ами были" : "ой был")]:" + for(var/datum/mind/spider in terror_princesses) + text += "
[spider.key] был [spider.name]" + text += "
Осквернител[(terror_queens?.len > 1 ? "ями были" : "ем был")]:" + for(var/datum/mind/spider in terror_defilers) + text += "
[spider.key] был [spider.name]" + text += "
Паук[(members?.len > 1 ? "ами Ужаса были" : "ом Ужаса был")]:" + for(var/datum/mind/spider in members) + text += "
[spider.key] был [spider.name]" + to_chat(world, text) + return TRUE + +/datum/team/terror_spiders/get_admin_texts() + . = ..() + var/list/terror_queens = main_spiders[TERROR_QUEEN] + var/list/terror_princes = main_spiders[TERROR_PRINCE] + var/list/terror_princesses = main_spiders[TERROR_PRINCESS] + var/list/terror_defilers = main_spiders[TERROR_DEFILER] + if(terror_queens?.len || terror_princes?.len || terror_princesses?.len || terror_defilers?.len) + if(check_rights(R_EVENT)) + . += "
Отложить победу Терроров Сейчас: [delay_terror_end? "ON" : "OFF"]
" + var/datum/admins/holder = usr.client.holder + . += holder.check_role_table("Королевы", terror_queens) + . += holder.check_role_table("Принцы", terror_princes) + . += holder.check_role_table("Принцессы", terror_princesses) + . += holder.check_role_table("Осквернители", terror_defilers) + var/count_eggs = 0 + var/count_spiderlings = 0 + for(var/obj/structure/spider/eggcluster/terror_eggcluster/E in GLOB.ts_egg_list) + if(is_station_level(E.z)) + count_eggs += E.spiderling_number + for(var/obj/structure/spider/spiderling/terror_spiderling/L in GLOB.ts_spiderling_list) + if(!L.stillborn && is_station_level(L.z)) + count_spiderlings += 1 + . += "
Растущие ПУ на станции: яйца - [count_eggs], спайдерлинги - [count_spiderlings], зараженные гуманоиды - [terror_infections.len].
" + +/datum/team/terror_spiders/admin_topic(comand) + if(comand == "delay_terror_end") + if(!check_rights(R_ADMIN) || !check_rights(R_EVENT)) + return + + if(!SSticker || !SSticker.mode) + return + + if(tgui_alert(usr,"Вы действительно хотите [delay_terror_end? "вернуть" : "приостановить"] конец раунда в случае победы Пауков Ужаса?", "", list("Да", "Нет")) == "Нет") + return + + if(!delay_terror_end) + delay_terror_win() + else + return_terror_win() + + log_and_message_admins("has [delay_terror_end? "stopped" : "returned"] stopped delayed terror win") + + +/proc/create_terror_spiders(type, count) + var/spider_type = get_spider_type(type) + if(!spider_type) + to_chat(usr, "Некорректный тип паука Ужаса.") + return FALSE + var/list/candidates = SSghost_spawns.poll_candidates("Вы хотите занять роль Паука Ужаса?", ROLE_TERROR_SPIDER, TRUE, 60 SECONDS, source = spider_type) + if(length(candidates) < count) + message_admins("Warning: not enough players volunteered to be terrors. Could only spawn [length(candidates)] out of [count]!") + return FALSE + var/successSpawn = FALSE + while(count && length(candidates)) + var/mob/living/simple_animal/hostile/poison/terror_spider/spider = new spider_type(pick(GLOB.xeno_spawn)) + var/mob/ghost = pick_n_take(candidates) + spider.key = ghost.key + spider.add_datum_if_not_exist() + count-- + successSpawn = TRUE + log_game("[spider.key] has become [spider].") + return successSpawn + + +/proc/get_spider_type(text_type) + switch(text_type) + if(TERROR_DEFILER) + return /mob/living/simple_animal/hostile/poison/terror_spider/defiler + if(TERROR_PRINCESS) + return /mob/living/simple_animal/hostile/poison/terror_spider/queen/princess + if(TERROR_QUEEN) + return /mob/living/simple_animal/hostile/poison/terror_spider/queen + if(TERROR_PRINCE) + return /mob/living/simple_animal/hostile/poison/terror_spider/prince + else + return null diff --git a/code/modules/antagonists/terror_spiders/terror_spider_actions.dm b/code/modules/antagonists/terror_spiders/terror_spider_actions.dm new file mode 100644 index 00000000000..bce6c30356c --- /dev/null +++ b/code/modules/antagonists/terror_spiders/terror_spider_actions.dm @@ -0,0 +1,28 @@ +/datum/action/innate/terrorspider/lay_empress_egg + name = "Отложить яйцо Императрицы" + desc = "Отложить яйцо Имератрицы Ужаса." + icon_icon = 'icons/effects/effects.dmi' + button_icon_state = "eggs" + check_flags = AB_CHECK_CONSCIOUS|AB_TRANSFER_MIND + var/datum/weakref/spider_team + +/datum/action/innate/terrorspider/lay_empress_egg/Activate() + . = ..() + var/datum/team/terror_spiders/team = spider_team.resolve() + if(!team) + return + if(team.empress_egg) + to_chat(usr, span_warning("Вы или кто-то из вашего гнезда уже отложили яйцо Императрицы.")) + return + if(GLOB.global_degenerate) + to_chat(usr, span_warning("Яйцо было уничтожено. Отложить новое невозможно.")) + return + if(tgui_alert(usr, "Вы действительно готовы отложить яйцо Имератрицы Ужаса?", "", list("Да", "Нет")) != "Да") + return + var/obj/structure/spider/eggcluster/terror_eggcluster/C = new /obj/structure/spider/eggcluster/terror_eggcluster/empress(get_turf(owner)) + C.spiderling_number = 1 + C.spider_mymother = owner + team.on_empress_egg_layed(C) + var/mob/living/simple_animal/hostile/poison/terror_spider/spider = owner + if(istype(spider)) + spider.msg_terrorspiders("Яйцо императрицы Ужаса отложено в [get_area(owner)]. Защищайте его любой ценой.") diff --git a/code/modules/antagonists/terror_spiders/terror_spider_objectives.dm b/code/modules/antagonists/terror_spiders/terror_spider_objectives.dm new file mode 100644 index 00000000000..e8753753d72 --- /dev/null +++ b/code/modules/antagonists/terror_spiders/terror_spider_objectives.dm @@ -0,0 +1,119 @@ +/datum/objective/spider_protect + name = "Защищать гнездо" + needs_target = FALSE + explanation_text = "Ошибка. Текст не сгенерирован. Напишите атикет и создайте баг репорт." + +/datum/objective/spider_protect/New(text, datum/team/team_to_join) + . = ..() + generate_text() + +/datum/objective/spider_protect/proc/generate_text(datum/team/terror_spiders/spider_team) + var/list/possible_spiders = list() + var/list/spiders = spider_team.main_spiders + if(!spiders) + return + for(var/spiter_type in spiders) + if(spiter_type != TERROR_OTHER && LAZYLEN(spiders[spiter_type])) + possible_spiders += spiter_type + explanation_text = "Помогите вашему гнезду отложить яйцо Императрицы Ужаса. Это могут сделать: [possible_spiders.Join(", ")]. Защищайте их и помогите им набрать силу, чтобы они могли отложить яйцо." + +/datum/objective/spider_protect/check_completion(datum/team/terror_spiders/spider_team) + . = ..() + + if(completed) + return . + + if(spider_team?.infect_target?.completed || \ + spider_team?.lay_eggs_target?.completed|| \ + spider_team?.prince_target?.completed) + completed = TRUE + return TRUE + return . + +/datum/objective/spider_protect_egg + name = "Защищать яйцо Императрицы" + needs_target = FALSE + explanation_text = "Ошибка. Текст не сгенерирован. Напишите атикет и создайте баг репорт." + +/datum/objective/spider_protect_egg/New(text, datum/team/team_to_join) + . = ..() + generate_text() + +/datum/objective/spider_protect_egg/proc/generate_text(datum/team/terror_spiders/spider_team) + if(spider_team?.empress_egg) + return + explanation_text = "Защищайте яйцо Императрицы Ужаса. Оно находится в [get_area(spider_team?.empress_egg)]. Его уничтожение приведёт к гибели всего гнезда." + +/datum/objective/spider_get_power + name = "spider bug" + needs_target = FALSE + explanation_text = "Вы не должны этого видеть. Напишите баг репорт." + var/targets_need = 0 + +/datum/objective/spider_get_power/proc/generate_text() + generate_targets_count() + return + +/datum/objective/spider_get_power/proc/generate_targets_count() + targets_need = EMPRESS_EGG_TARGET_COUNT + return + +/datum/objective/spider_get_power/alife_spiders + name = "Размножаться" + +/datum/objective/spider_get_power/alife_spiders/generate_text() + . = ..() + explanation_text = "Расплодитесь. Для того, чтобы вы могли отложить яйцо Императрицы, в вашем гнезде долж[declension_ru(targets_need, "ен", "о", "о")] быть [targets_need] паук[declension_ru(targets_need, "", "а", "ов")]." + +/datum/objective/spider_get_power/alife_spiders/check_completion(datum/team/terror_spiders/spider_team) + . = ..() + + if(completed) + return . + + var/alife_count = spider_team?.get_terror_spiders_alife_count() + + if(alife_count >= targets_need) + completed = TRUE + spider_team.other_target?.check_completion() + return TRUE + return . + +/datum/objective/spider_get_power/spider_infections + name = "Заражать гуманоидов" + +/datum/objective/spider_get_power/spider_infections/generate_text() + . = ..() + explanation_text = "Заражайте. Для того, чтобы вы могли отложить яйцо Императрицы, долж[declension_ru(targets_need, "ен", "о", "о")] быть заражено [targets_need] гуманоид[declension_ru(targets_need, "", "а", "ов")]." + +/datum/objective/spider_get_power/spider_infections/check_completion(datum/team/terror_spiders/spider_team) + . = ..() + + if(completed) + return . + + if(spider_team?.terror_infections.len >= targets_need) + completed = TRUE + spider_team?.other_target?.check_completion() + return TRUE + return . + + +/datum/objective/spider_get_power/eat_humans + name = "Поедать гуманоидов" + +/datum/objective/spider_get_power/eat_humans/generate_text() + . = ..() + explanation_text = "Ешьте и набирайтесь сил. Для того, чтобы вы могли отложить яйцо Императрицы, вам нужно заплести в кокон [targets_need] гуманоид[declension_ru(targets_need, "а", "ов", "ов")]. " + +/datum/objective/spider_get_power/eat_humans/check_completion(human_count, datum/team/terror_spiders/spider_team) + . = ..() + + if(completed) + return . + + if(human_count >= targets_need) + completed = TRUE + spider_team?.other_target?.check_completion() + return TRUE + return . diff --git a/code/modules/antagonists/xenomorth/xenomorph.dm b/code/modules/antagonists/xenomorth/xenomorph.dm new file mode 100644 index 00000000000..60b7fa1e4e6 --- /dev/null +++ b/code/modules/antagonists/xenomorth/xenomorph.dm @@ -0,0 +1,42 @@ +/datum/antagonist/xenomorph + name = "Xenomorph" + roundend_category = "xenomorph" + job_rank = ROLE_ALIEN + special_role = SPECIAL_ROLE_XENOMORPH + wiki_page_name = "Xenomorph" + russian_wiki_name = "Ксеноморф" + show_in_roundend = FALSE + show_in_orbit = FALSE + antag_menu_name = "Ксеноморф" + var/datum/team/xenomorph/xenomorph_team + var/role_text + +/datum/antagonist/xenomorph/on_gain() + if(!isalien(owner.current)) + stack_trace("This antag datum cannot be attached to a mob of this type.") + var/mob/living/carbon/alien/alien = owner.current + role_text = alien.role_text + . = ..() + +/datum/antagonist/xenomorph/farewell() + return + +/datum/antagonist/xenomorph/greet() + var/list/messages = list() + messages.Add(span_danger("
Вы Ксеноморф!
")) + messages.Add("
Работайте сообща, помогайте своим сёстрам, слушайтесь королеву (если она есть), саботируйте станцию, заражайте экипаж, превратите это место в своё гнездо!
") + messages.Add("
[role_text]
") + SEND_SOUND(owner.current, sound('sound/voice/hiss1.ogg')) + return messages + +/datum/antagonist/xenomorph/queen + special_role = SPECIAL_ROLE_XENOMORPH_QUEEN + antag_menu_name = "Королева ксеноморфов" + +/datum/antagonist/xenomorph/queen/greet() + var/list/messages = list() + messages.Add(span_danger("
Вы Королева ксеноморфов!
")) + messages.Add("
Руководите ульем, откладывайте яйца, стройте гнездо и накапливайте силы для дальнейшей эволюции в Императрицу и преращения станции в свой дом!
") + messages.Add("
Помните, что после вашей смерти в гнезде не останется королевы и оно будет обречено на вымирание!
") + SEND_SOUND(owner.current, sound('sound/voice/hiss1.ogg')) + return messages diff --git a/code/modules/antagonists/xenomorth/xenomorph_actions.dm b/code/modules/antagonists/xenomorth/xenomorph_actions.dm new file mode 100644 index 00000000000..382a2abf451 --- /dev/null +++ b/code/modules/antagonists/xenomorth/xenomorph_actions.dm @@ -0,0 +1,77 @@ +/datum/action/innate/start_evolve_to_empress + name = "ОШИБКА" + desc = "Начать процесс эволюции в Императрицу." + icon_icon = 'icons/mob/actions/actions.dmi' + button_icon_state = "queen_evolve" + check_flags = AB_CHECK_CONSCIOUS|AB_TRANSFER_MIND + var/datum/weakref/xeno_team + +/datum/action/innate/start_evolve_to_empress/New(Target) + . = ..() + name = "Эволюционировать ([TO_EMPRESS_EVOLVE_COST])" + +/datum/action/innate/start_evolve_to_empress/Activate() + . = ..() + var/mob/living/carbon/alien/humanoid/queen/queen = owner + var/datum/team/xenomorph/team = xeno_team.resolve() + + if(queen.stat) + return + + if(!istype(queen)) + to_chat(owner, span_warning("Данное действие может выполнить только королева ксеноморфов.")) + return + + if(tgui_alert(queen, "Вы действительно хотите начать эволюцию? После начала вы не сможете что-либо делать, пока процесс эволюции не завершится.", "Подтверждение", list("Да", "Нет")) != "Да") + return + + if(!queen.use_plasma_spell(TO_EMPRESS_EVOLVE_COST, queen)) + queen.balloon_alert(queen, "не хватает плазмы!") + return + + playsound_xenobuild(queen) + var/mob/dead/observer/ghost = queen.ghostize(TRUE) + ghost.can_reenter_corpse = FALSE + + queen.icon = 'icons/mob/alien.dmi' + queen.icon_state = "alienq_s" + queen.pixel_x = 0 + + var/turf/alienturf = get_turf(queen) + var/list/alien_walls = list() + for(var/turf/simulated/floor/turf in RANGE_TURFS(1, alienturf)) + if(turf == alienturf) + continue + alien_walls += new /obj/structure/alien/resin/wall/empress_cocon(turf) + + alien_walls += new /obj/structure/alien/weeds/node(alienturf) + team.evolve_start(get_area(alienturf)) + addtimer(CALLBACK(src, PROC_REF(after_evolve), alien_walls, ghost, queen), TO_EMPRESS_EVOLVE_COST) + Remove(queen) + + +/datum/action/innate/start_evolve_to_empress/proc/after_evolve(list/alien_walls, mob/dead/observer/ghost, mob/living/carbon/alien/humanoid/queen/queen) + if(QDELETED(queen)) + return + + if(isnull(queen?.stat) || queen.stat == DEAD) + return + + ghost.can_reenter_corpse = TRUE + ghost.reenter_corpse() + + var/mob/living/carbon/alien/new_xeno = new /mob/living/carbon/alien/humanoid/empress/large(get_turf(queen)) + queen.mind.transfer_to(new_xeno) + SEND_SIGNAL(new_xeno.mind, COMSIG_ALIEN_EVOLVE, queen.type, new_xeno.type) + QDEL_LIST(alien_walls) + qdel(queen) + + + +/obj/structure/alien/resin/wall/empress_cocon + max_integrity = 700 + explosion_block = 100 + +/obj/structure/alien/resin/wall/empress_cocon/ex_act(severity) + return + diff --git a/code/modules/antagonists/xenomorth/xenomorph_objectives.dm b/code/modules/antagonists/xenomorth/xenomorph_objectives.dm new file mode 100644 index 00000000000..35b5965b2d3 --- /dev/null +++ b/code/modules/antagonists/xenomorth/xenomorph_objectives.dm @@ -0,0 +1,42 @@ +/datum/objective/xeno_get_power + name = "Размножаться" + needs_target = FALSE + explanation_text = "Вы не должны этого видеть. Напишите баг репорт." + var/targets_need = 0 + +/datum/objective/xeno_get_power/proc/generate_text() + targets_need = EMPRESS_EVOLVE_TARGET_COUNT + explanation_text = "Расплодитесь. Для того, чтобы вы могли эволюционировать, в вашем улье долж[declension_ru(targets_need, "ен", "но", "но")] быть [targets_need] ксеноморф[declension_ru(targets_need, "", "а", "ов")]." + return + +/datum/objective/xeno_get_power/check_completion(datum/team/xenomorph/xeno_team) + . = ..() + + if(completed) + return . + + var/alife_count = xeno_team?.members.len + + if(alife_count >= targets_need) + completed = TRUE + return TRUE + return . + +/datum/objective/create_queen + name = "Создать Королеву" + needs_target = FALSE + explanation_text = "У улья должна появиться Королева. Для этого один из грудоломов должен эволюционировать сначала в Рабочего, а затем в Королеву." + +/datum/objective/protect_queen + name = "Защитить" + needs_target = FALSE + explanation_text = "У улья появилась Королева. Необходимо защищать её любой ценой. Помимо этого, необходимо увеличить численность улья. Чем больше улей, тем быстрее Королева сможет эволюционировать в Императрицу." + +/datum/objective/protect_cocon + name = "Защитить кокон" + needs_target = FALSE + explanation_text = "ОШИБКА " + +/datum/objective/protect_cocon/proc/generate_text(area/location) + explanation_text = "Королева начала эволюционировать в [location.name]. Она находится в стазисе внутри кокона и полностью беззащитна. Защитите её любой ценой." + return diff --git a/code/modules/antagonists/xenomorth/xenomorph_team.dm b/code/modules/antagonists/xenomorth/xenomorph_team.dm new file mode 100644 index 00000000000..eb996e05ed9 --- /dev/null +++ b/code/modules/antagonists/xenomorth/xenomorph_team.dm @@ -0,0 +1,270 @@ +/datum/team/xenomorph + name = "Ксеноморфы" + antag_datum_type = /datum/antagonist/xenomorph + var/datum/mind/current_queen + var/datum/mind/current_empress + var/datum/objective/xeno_get_power/xeno_power_objective + var/datum/objective/create_queen/create_queen + var/datum/objective/protect_queen/protect_queen + var/datum/objective/protect_cocon/protect_cocon + var/announce = FALSE + var/evolves_count = 0 + var/grant_action = FALSE + var/stage = XENO_STAGE_START + var/delay_xeno_end = FALSE + +/datum/team/xenomorph/New(list/starting_members) + . = ..() + create_queen = new + create_queen.owner = src + create_queen.team = src + add_objective_to_members(create_queen) + + +/datum/team/xenomorph/add_member(datum/mind/new_member, add_objectives) + var/is_queen = new_member?.current && isalienqueen(new_member.current) + . = ..(new_member, !is_queen) + RegisterSignal(new_member, COMSIG_ALIEN_EVOLVE, PROC_REF(on_alien_evolve)) + if(is_queen && !current_queen) + add_queen(new_member) + check_queen_power() + +/datum/team/xenomorph/remove_member(datum/mind/new_member) + UnregisterSignal(new_member, COMSIG_ALIEN_EVOLVE) + . = ..() + +/datum/team/xenomorph/add_objective_to_members(datum/objective/objective, member_blacklist = list(current_queen, current_empress)) + . = ..() + + +/datum/team/xenomorph/proc/on_alien_evolve(datum/mind/source, old_type, new_type) + SIGNAL_HANDLER + if(!istype(source)) + return + if(ispath(old_type, LARVA_TYPE)) + evolves_count++ + check_announce() + source.remove_antag_datum(/datum/antagonist/xenomorph) + var/datum/antagonist/xenomorph/datum = new + source.add_antag_datum(datum, type) + + if(ispath(new_type, QUEEN_TYPE)) + add_queen(source) + + if(ispath(new_type, EMPRESS_TYPE)) + current_empress = source + evolve_end() + +/datum/team/xenomorph/proc/add_queen(datum/mind/queen) + current_queen = queen + create_queen.completed = TRUE + protect_queen = new + protect_queen.owner = src + protect_queen.team = src + add_objective_to_members(protect_queen) + xeno_power_objective = new + xeno_power_objective.owner = src + xeno_power_objective.team = src + xeno_power_objective.generate_text() + queen.remove_antag_datum(/datum/antagonist/xenomorph) + var/datum/antagonist/xenomorph/queen/datum = new + datum.objectives |= xeno_power_objective + datum.team = src + queen.add_antag_datum(datum, type) + if(announce) + SSshuttle?.add_hostile_environment(current_queen.current) + +/datum/team/xenomorph/proc/check_queen_power() + var/mob/queen_mob = current_queen?.current + if(!grant_action && xeno_power_objective?.check_completion(src) && !isnull(queen_mob?.stat) && queen_mob.stat != DEAD) + var/datum/action/innate/start_evolve_to_empress/evolve = new + evolve.Grant(queen_mob) + evolve.xeno_team = WEAKREF(src) + grant_action = TRUE + +/datum/team/xenomorph/proc/check_announce() + if(announce) + return TRUE + var/crew_count = num_station_players() + var/queen_exist = current_queen?.current && current_queen.current.stat != DEAD + if(queen_exist && evolves_count > crew_count * EVOLVE_ANNOUNCE_TRIGGER) + announce = TRUE + announce() + return TRUE + return FALSE + +/datum/team/xenomorph/proc/announce() + GLOB.event_announcement.Announce("Вспышка биологической угрозы 4-го уровня зафиксирована на борту станции [station_name()]. Всему персоналу надлежит сдержать её распространение любой ценой! Особая директива распечатана на всех консолях связи.", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/effects/siren-spooky.ogg') + SSticker?.mode?.special_directive() + SSshuttle?.emergency.cancel() + SSshuttle?.add_hostile_environment(current_queen.current) + +/datum/team/xenomorph/proc/evolve_announce(area/loc) + GLOB.event_announcement.Announce("Зафиксировано изменение организации улья, указывающее на начало трансформации в Императрицу Ксеноморфов. Обнаружено значительное скопление биоугрозы в [loc.name]. Уничтожте огранизм до окончания трансформации любой ценой.", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/effects/siren-spooky.ogg') + +/datum/team/xenomorph/proc/win_announce() + GLOB.event_announcement.Announce("Подтверждено наличие Императрицы Ксеноморфов на борту [station_name()]. Обнаружено загрязнение систем жизнеобеспечения. Станция переклассифицирована в гнездо биоугрозы 4-го уровня. Взведение устройства самоуничтожения персоналом или внешними силами в данный момент не представляется возможным. Активация протоколов изоляции.", "Отчёт об объекте [station_name()]") + + +/datum/team/xenomorph/proc/evolve_start(area/loc) + protect_queen.completed = TRUE + protect_cocon = new + protect_cocon.owner = src + protect_cocon.team = src + protect_cocon.generate_text(loc) + add_objective_to_members(protect_cocon) + stage = XENO_STAGE_PROTECT_COCON + addtimer(CALLBACK(src, PROC_REF(evolve_announce), loc), TIME_TO_ANNOUNCE) + for(var/datum/mind/mind as anything in members) + if(mind == current_queen || mind == current_empress) + continue + if(!mind?.current || mind.current.stat == DEAD) + continue + to_chat(mind.current, span_alien("Королева начала эволюционировать в [loc.name]. Она находится в стазисе внутри кокона и полностью беззащитна. Защитите её любой ценой.")) + +/datum/team/xenomorph/proc/evolve_end() + RegisterSignal(SSdcs, COMSIG_GLOB_XENO_STORM_ENDED, PROC_REF(on_xeno_storm_ended)) + INVOKE_ASYNC(SSweather, TYPE_PROC_REF(/datum/controller/subsystem/weather, run_weather), /datum/weather/xeno_storm) + protect_cocon.completed = TRUE + stage = XENO_STAGE_STORM + +/datum/team/xenomorph/proc/on_xeno_storm_ended() + SIGNAL_HANDLER + win_announce() + stage = XENO_STAGE_END + if(delay_xeno_end) + stage = XENO_STAGE_POST_END + else + SSticker?.mode?.end_game() + UnregisterSignal(SSdcs, COMSIG_GLOB_XENO_STORM_ENDED) + +/datum/team/xenomorph/get_admin_texts() + . = ..() + if(current_queen) + if(check_rights(R_EVENT)) + . += "
Отложить победу Ксеноморфов Сейчас: [delay_xeno_end? "ON" : "OFF"]
" + var/datum/admins/holder = usr.client.holder + . += holder.check_role_table("Королева", list(current_queen)) + + +/datum/team/xenomorph/proc/declare_results() + if(SSticker?.mode?.station_was_nuked && !stage == XENO_STAGE_POST_END) + to_chat(world, "
Частичная победа Ксеноморфов!") + to_chat(world, "Станция была уничтожена!") + to_chat(world, "Устройство самоуничтожения сработало, предотвратив распространение Ксеноморфов.") + else if(protect_cocon.check_completion(src)) + to_chat(world, "
Полная победа Ксеноморфов!") + to_chat(world, "Ксеноморфы захватили станцию!") + to_chat(world, "Императрица Ксеноморфов появилась на свет, превратив всю станцию в гнездо.") + else if(!current_queen?.current || current_queen.current.stat == DEAD) + to_chat(world, "
Полная победа персонала станции!") + to_chat(world, "Экипаж защитил станцию от Ксеноморфов!") + to_chat(world, "Ксеноморфы были истреблены.") + else + to_chat(world, "
Ничья!") + to_chat(world, "Экипаж эвакуирован!") + to_chat(world, "Ксеноморфы не были истреблены.") + + to_chat(world, "Целями Пауков Ужаса было:") + + if(xeno_power_objective) + to_chat(world, "
Цель Королевы: [xeno_power_objective.explanation_text] [xeno_power_objective.completed?"Успех!": "Провал."]") + SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[xeno_power_objective.type]", xeno_power_objective.completed? "SUCCESS" : "FAIL")) + if(create_queen) + to_chat(world, "
Создание королевы: [create_queen.explanation_text] [create_queen.completed?"Успех!": "Провал."]") + SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[create_queen.type]", create_queen.completed? "SUCCESS" : "FAIL")) + if(protect_queen) + to_chat(world, "
Защита королевы: [protect_queen.explanation_text] [protect_queen.completed?"Успех!": "Провал."]") + SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[protect_queen.type]", protect_queen.completed? "SUCCESS" : "FAIL")) + if(protect_cocon) + to_chat(world, "
Защита кокона: [protect_cocon.explanation_text] [protect_cocon.completed?"Успех!": "Провал."]") + SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[protect_cocon.type]", protect_cocon.completed? "SUCCESS" : "FAIL")) + return TRUE + + +/datum/team/xenomorph/declare_completion() + if(members.len) + declare_results() + var/text = "" + if(current_queen) + text += "
Королевой был:" + text += "
[current_queen.key] был [current_queen.name]" + text += "
Ксеноморф[(members?.len > 1 ? "ами были" : "ом был")]:" + for(var/datum/mind/spider in members) + text += "
[spider.key] был [spider.name]" + to_chat(world, text) + return TRUE + +/datum/team/xenomorph/proc/delay_xeno_win() + delay_xeno_end = TRUE + +/datum/team/xenomorph/proc/return_xeno_win() + delay_xeno_end = FALSE + +/datum/team/xenomorph/admin_topic(comand) + if(comand == "delay_xeno_end") + if(!check_rights(R_ADMIN) || !check_rights(R_EVENT)) + return + + if(!SSticker || !SSticker.mode) + return + + if(tgui_alert(usr,"Вы действительно хотите [delay_xeno_end? "вернуть" : "преостановить"] конец раунда в случае победы Ксеноморфов?", "", list("Да", "Нет")) == "Нет") + return + + if(!delay_xeno_end) + delay_xeno_win() + else + return_xeno_win() + + log_and_message_admins("has [delay_xeno_end? "stopped" : "returned"] stopped delayed xeno win") + + +/proc/spawn_aliens(spawn_count) + var/spawn_vectors = tgui_alert(usr, "Какой тип ксеноморфа заспавнить?", "Тип ксеноморфов", list("Вектор", "Грудолом")) == "Вектор" + var/list/vents = get_valid_vent_spawns(exclude_mobs_nearby = TRUE, exclude_visible_by_mobs = TRUE) + if(spawn_vectors) + spawn_vectors(vents, spawn_count) + else + spawn_larvas(vents, spawn_count) + +/proc/spawn_larvas(list/vents, spawncount) + var/list/candidates = SSghost_spawns.poll_candidates("Вы хотите сыграть за Ксеноморфа?", ROLE_ALIEN, TRUE, source = /mob/living/carbon/alien/larva) + var/first_spawn = TRUE + while(spawncount && length(vents) && length(candidates)) + var/obj/vent = pick_n_take(vents) + var/mob/C = pick_n_take(candidates) + if(C) + GLOB.respawnable_list -= C + var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) + new_xeno.evolution_points += (0.75 * new_xeno.max_evolution_points) //event spawned larva start off almost ready to evolve. + new_xeno.key = C.key + + if(first_spawn) + new_xeno.queen_maximum++ + first_spawn = FALSE + + new_xeno.update_datum() + + spawncount-- + log_game("[new_xeno.key] has become [new_xeno].") + +/proc/spawn_vectors(list/vents, spawncount) + spawncount = 1 + var/list/candidates = SSghost_spawns.poll_candidates("Вы хотите сыграть за Ксеноморфа (Вектор)?", ROLE_ALIEN, TRUE, source = /mob/living/carbon/alien/humanoid/hunter/vector) + var/first_spawn = TRUE + while(spawncount && length(vents) && length(candidates)) + var/obj/vent = pick_n_take(vents) + var/mob/C = pick_n_take(candidates) + if(C) + GLOB.respawnable_list -= C + var/mob/living/carbon/alien/humanoid/hunter/vector/new_xeno = new(vent.loc) + new_xeno.key = C.key + + if(first_spawn) + new_xeno.queen_maximum++ + first_spawn = FALSE + new_xeno.update_datum() + + spawncount-- + log_game("[new_xeno.key] has become [new_xeno].") diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/alien_infestation.dm index ccc4fa7f360..21a5779c319 100644 --- a/code/modules/events/alien_infestation.dm +++ b/code/modules/events/alien_infestation.dm @@ -3,20 +3,11 @@ /datum/event/alien_infestation announceWhen = 400 - var/spawncount = 2 var/list/playercount - var/successSpawn = FALSE //So we don't make a command report if nothing gets spawned. - -/datum/event/alien_infestation/setup() - announceWhen = rand(announceWhen, announceWhen + 50) /datum/event/alien_infestation/announce(false_alarm) - if(successSpawn || false_alarm) - GLOB.event_announcement.Announce("Вспышка биологической угрозы 4-го уровня зафиксирована на борту станции [station_name()]. Всему персоналу надлежит сдержать её распространение любой ценой!", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/effects/siren-spooky.ogg') - if(!false_alarm) - SSshuttle.emergency.cancel() - else - log_and_message_admins("Warning: Could not spawn any mobs for event Alien Infestation") + if(false_alarm) + GLOB.event_announcement.Announce("Вспышка биологической угрозы 4-го уровня зафиксирована на борту станции [station_name()]. Всему персоналу надлежит сдержать её распространение, пока ситуация не вышла из под контроля!", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/effects/siren-spooky.ogg') /datum/event/alien_infestation/start() INVOKE_ASYNC(src, PROC_REF(wrappedstart)) @@ -26,56 +17,12 @@ var/list/vents = get_valid_vent_spawns(exclude_mobs_nearby = TRUE, exclude_visible_by_mobs = TRUE) playercount = num_station_players() //grab playercount when event starts not when game starts if(playercount <= ALIEN_MIDPOP_TRIGGER) - spawn_vectors(vents, playercount) + spawn_vectors(vents, 1) return if(playercount >= ALIEN_HIGHPOP_TRIGGER) //spawn with 4 if highpop - spawncount = 4 - var/list/candidates = SSghost_spawns.poll_candidates("Вы хотите сыграть за Чужого?", ROLE_ALIEN, TRUE, source = /mob/living/carbon/alien/larva) - var/first_spawn = TRUE - while(spawncount && length(vents) && length(candidates)) - var/obj/vent = pick_n_take(vents) - var/mob/C = pick_n_take(candidates) - if(C) - GLOB.respawnable_list -= C - var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) - new_xeno.evolution_points += (0.75 * new_xeno.max_evolution_points) //event spawned larva start off almost ready to evolve. - new_xeno.key = C.key - - if(first_spawn) - new_xeno.queen_maximum++ - first_spawn = FALSE - - if(SSticker && SSticker.mode) - SSticker.mode.xenos += new_xeno.mind - - spawncount-- - successSpawn = TRUE - log_game("[new_xeno.key] has become [new_xeno].") - - -/datum/event/alien_infestation/proc/spawn_vectors(list/vents, playercount) - spawncount = 1 - var/list/candidates = SSghost_spawns.poll_candidates("Вы хотите сыграть за Чужого Вектора?", ROLE_ALIEN, TRUE, source = /mob/living/carbon/alien/humanoid/hunter/vector) - var/first_spawn = TRUE - while(spawncount && length(vents) && length(candidates)) - var/obj/vent = pick_n_take(vents) - var/mob/C = pick_n_take(candidates) - if(C) - GLOB.respawnable_list -= C - var/mob/living/carbon/alien/humanoid/hunter/vector/new_xeno = new(vent.loc) - new_xeno.key = C.key - - if(first_spawn) - new_xeno.queen_maximum++ - first_spawn = FALSE - - if(SSticker && SSticker.mode) - SSticker.mode.xenos += new_xeno.mind - - spawncount-- - successSpawn = TRUE - log_game("[new_xeno.key] has become [new_xeno].") - + spawn_larvas(vents, 4) + return + spawn_larvas(vents, 2) #undef ALIEN_HIGHPOP_TRIGGER #undef ALIEN_MIDPOP_TRIGGER diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm index 0759a9973aa..5152be46779 100644 --- a/code/modules/events/blob.dm +++ b/code/modules/events/blob.dm @@ -1,11 +1,10 @@ /datum/event/blob announceWhen = 180 endWhen = 240 - var/successSpawn = FALSE //So we don't make a command report if nothing gets spawned. /datum/event/blob/announce(false_alarm) if(false_alarm) - GLOB.event_announcement.Announce("Вспышка биологической угрозы 5-го уровня зафиксирована на борту станции [station_name()]. Всему персоналу надлежит сдержать её распространение любой ценой!", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/AI/outbreak5.ogg') + GLOB.event_announcement.Announce("Подтверждена вспышка биологической угрозы 5-го уровня на борту [station_name()]. Весь персонал обязан локализовать угрозу.", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/AI/outbreak5.ogg') /datum/event/blob/start() processing = FALSE //so it won't fire again in next tick @@ -17,5 +16,4 @@ if(!SSticker?.mode?.make_blobized_mouses(num_blobs)) log_and_message_admins("Warning: Could not spawn any mobs for event Blob") return kill() - successSpawn = TRUE processing = TRUE // Let it naturally end, if it runs successfully diff --git a/code/modules/events/spider_terror.dm b/code/modules/events/spider_terror.dm index c7ab518a6ba..fd053581221 100644 --- a/code/modules/events/spider_terror.dm +++ b/code/modules/events/spider_terror.dm @@ -4,20 +4,10 @@ /datum/event/spider_terror announceWhen = 240 - var/spawncount = 1 - var/successSpawn = FALSE //So we don't make a command report if nothing gets spawned. - -/datum/event/spider_terror/setup() - announceWhen = rand(announceWhen, announceWhen + 30) - spawncount = 1 /datum/event/spider_terror/announce(false_alarm) - if(successSpawn || false_alarm) - GLOB.command_announcement.Announce("Вспышка биологической угрозы 3-го уровня зафиксирована на борту станции [station_name()]. Всему персоналу надлежит сдержать её распространение любой ценой!", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/effects/siren-spooky.ogg') - if(!false_alarm) - SSshuttle.emergency.cancel() - else - log_and_message_admins("Warning: Could not spawn any mobs for event Terror Spiders") + if(false_alarm) + GLOB.command_announcement.Announce("Вспышка биологической угрозы 3-го уровня зафиксирована на борту станции [station_name()]. Всему персоналу надлежит сдержать её распространение любой ценой! Особая директива распечатана на всех консолях связи.", "ВНИМАНИЕ: БИОЛОГИЧЕСКАЯ УГРОЗА.", 'sound/effects/siren-spooky.ogg') /datum/event/spider_terror/start() // It is necessary to wrap this to avoid the event triggering repeatedly. @@ -26,11 +16,12 @@ /datum/event/spider_terror/proc/wrappedstart() var/spider_type var/infestation_type + var/spawncount var/player_count = num_station_players() if(player_count <= TS_MINPLAYERS_TRIGGER) var/datum/event_container/EC = SSevents.event_containers[EVENT_LEVEL_MAJOR] EC.next_event_time = world.time + (60 * 10) - return //we don't spawn spiders on lowpop. Instead, we reroll! + return kill()//we don't spawn spiders on lowpop. Instead, we reroll! else if(player_count >= TS_HIGHPOP_TRIGGER) infestation_type = pick(5, 6) else if(player_count >= TS_MIDPOP_TRIGGER) @@ -39,35 +30,29 @@ infestation_type = pick(1, 2) switch(infestation_type) if(1) //lowpop spawns - spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/defiler + spider_type = TERROR_DEFILER spawncount = 2 if(2) - spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/queen/princess + spider_type = TERROR_PRINCESS spawncount = 2 if(3) //midpop spawns - spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/defiler + spider_type = TERROR_DEFILER spawncount = 3 if(4) - spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/queen/princess + spider_type = TERROR_PRINCESS spawncount = 3 if(5) //highpop spawns - spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/queen + spider_type = TERROR_QUEEN spawncount = 1 if(6) - spider_type = /mob/living/simple_animal/hostile/poison/terror_spider/prince + spider_type = TERROR_PRINCE spawncount = 1 - var/list/candidates = SSghost_spawns.poll_candidates("Вы хотите занять роль Паука Ужаса?", ROLE_TERROR_SPIDER, TRUE, 60 SECONDS, source = spider_type) - if(length(candidates) < spawncount) - message_admins("Warning: not enough players volunteered to be terrors. Could only spawn [length(candidates)] out of [spawncount]!") - while(spawncount && length(candidates)) - var/mob/living/simple_animal/hostile/poison/terror_spider/S = new spider_type(pick(GLOB.xeno_spawn)) - var/mob/M = pick_n_take(candidates) - S.key = M.key - SSticker.mode.terror_spiders |= S.mind - S.give_intro_text() - spawncount-- - successSpawn = TRUE - log_game("[S.key] has become [S].") + + var/successSpawn = create_terror_spiders(spider_type, spawncount) + + if(!successSpawn) + log_and_message_admins("Warning: Could not spawn any mobs for event Terror Spiders") + return kill() #undef TS_MINPLAYERS_TRIGGER #undef TS_HIGHPOP_TRIGGER diff --git a/code/modules/mob/dead/observer/orbit.dm b/code/modules/mob/dead/observer/orbit.dm index 27ac665385c..4b3b89a5250 100644 --- a/code/modules/mob/dead/observer/orbit.dm +++ b/code/modules/mob/dead/observer/orbit.dm @@ -91,15 +91,10 @@ var/datum/mind/mind = M.mind var/list/other_antags = list() - if(GLOB.ts_spiderlist.len && M.ckey) - var/list/spider_minds = list() - for(var/datum/mind/spider_mind in SSticker.mode.terror_spiders) - if(!QDELETED(spider_mind.current)) - spider_minds |= spider_mind - other_antags += list( - "Пауки Ужаса ([spider_minds.len])" = (mind in SSticker.mode.terror_spiders), - ) - + for(var/team_type in GLOB.antagonist_teams) + var/datum/team/team = GLOB.antagonist_teams[team_type] + if(!team.need_antag_hud) + other_antags += list("[team.name] — ([team.alife_members_count()])" = (mind in team.members)) if(user.antagHUD) // If a mind is many antags at once, we'll display all of them, each // under their own antag sub-section. @@ -114,6 +109,10 @@ antag_serialized["antag"] = A.name antagonists += list(antag_serialized) + for(var/team_type in GLOB.antagonist_teams) + var/datum/team/team = GLOB.antagonist_teams[team_type] + if(team.need_antag_hud) + other_antags += list("[team.name] — ([team.alife_members_count()])" = (mind in team.members)) // Not-very-datumized antags follow // Associative list of antag name => whether this mind is this antag if(SSticker && SSticker.mode) @@ -131,7 +130,6 @@ "Тени — ([length(SSticker.mode.shadows)])" = (mind in SSticker.mode.shadows), "Маги — ([length(SSticker.mode.wizards)])" = (mind in SSticker.mode.wizards), "Ученики магов — ([length(SSticker.mode.apprentices)])" = (mind in SSticker.mode.apprentices), - "Ксеноморфы — ([length(SSticker.mode.xenos)])" = (mind in SSticker.mode.xenos), "Торговцы — ([length(SSticker.mode.traders)])" = (mind in SSticker.mode.traders), "Морфы — ([length(SSticker.mode.morphs)])" = (mind in SSticker.mode.morphs), "Свармеры — ([length(SSticker.mode.swarmers)])" = (mind in SSticker.mode.swarmers), diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index d3fd0680bab..7784c3a213b 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -40,6 +40,9 @@ var/leaping = FALSE dirslash_enabled = TRUE + var/antag_datum_type = /datum/antagonist/xenomorph + var/role_text = "" + var/can_evolve = FALSE var/evolution_points = 0 var/max_evolution_points = 200 @@ -74,6 +77,15 @@ night_vision_action = null return ..() +/mob/living/carbon/alien/proc/update_datum() + var/datum/old_datum = mind.has_antag_datum(/datum/antagonist/xenomorph) + if(old_datum) + if(old_datum.type != antag_datum_type) + mind.remove_antag_datum(old_datum) + else + return + mind.add_antag_datum(antag_datum_type, /datum/team/xenomorph) + /** * Returns the list of type paths of the organs that we need to insert into this particular xeno upon its creation diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm index 397297b0bac..36f975b4335 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm @@ -7,6 +7,7 @@ icon_state = "aliend_s" time_to_open_doors = 0.2 SECONDS can_evolve = TRUE + role_text = "Вы - Рабочий. Ваша основная задача - помощь Королеве в обустройстве гнезда. Если в улье её всё ещё нет, вам необходимо как можно быстрее в неё эволюционировать." var/sterile = FALSE diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm index 16dcafe0634..dcfbd952a66 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm @@ -6,6 +6,7 @@ devour_time = 2 SECONDS icon_state = "alienh_s" caste_movement_delay = -1 + role_text = "Вы - Охотник. Ваша основная задача - добыча носителей для заражения их грудоломами." var/invisibility_cost = 5 diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm index 98ecfb25b87..2ea8c203b30 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm @@ -6,6 +6,7 @@ attack_damage = 25 time_to_open_doors = 0.2 SECONDS icon_state = "aliens_s" + role_text = "Вы - Часовой. Ваша основная задача - защита гнезда от непрошенных гостей." can_evolve = TRUE @@ -45,6 +46,7 @@ obj_damage = 80 time_to_open_doors = 0.2 SECONDS environment_smash = ENVIRONMENT_SMASH_WALLS + role_text = "Вы - Преторианец. Вы являетесь более сильной и неповоротливой версией Часового. Ваша основная задача - защита гнезда от непрошенных гостей." var/datum/action/innate/small_sprite_alien/praetorian/action_sprite diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/vector.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/vector.dm index 4735fc597ae..4294c815118 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/vector.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/vector.dm @@ -1,6 +1,7 @@ /mob/living/carbon/alien/humanoid/hunter/vector name = "alien vector" icon_state = "alienh_running" + role_text = "Вы - Вектор. Вы являетесь особой версией Охотника, способной заражать носителей без помощи лицехватов. Ваша основная задача - добыча носителей и заражение их грудоломами." /mob/living/carbon/alien/humanoid/hunter/vector/New() if(name == "alien vector") diff --git a/code/modules/mob/living/carbon/alien/humanoid/empress.dm b/code/modules/mob/living/carbon/alien/humanoid/empress.dm index bcf2e13d278..3f39c607dce 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/empress.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/empress.dm @@ -10,6 +10,7 @@ large = TRUE move_resist = MOVE_FORCE_STRONG ventcrawler_trait = null + antag_datum_type = /datum/antagonist/xenomorph/queen /mob/living/carbon/alien/humanoid/empress/large name = "alien empress" diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm index c8f34c6e826..344f79aa777 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm @@ -16,6 +16,7 @@ time_to_open_doors = 0.2 SECONDS environment_smash = ENVIRONMENT_SMASH_RWALLS pressure_resistance = 200 //Because big, stompy xenos should not be blown around like paper. + antag_datum_type = /datum/antagonist/xenomorph/queen tts_seed = "Queen" /mob/living/carbon/alien/humanoid/queen/New() @@ -44,6 +45,9 @@ /obj/item/organ/internal/xenos/neurotoxin ) +/mob/living/carbon/alien/humanoid/queen/death(gibbed) + . = ..() + SSshuttle.remove_hostile_environment(src) /mob/living/carbon/alien/humanoid/queen/can_inject(mob/user, error_msg, target_zone, penetrate_thick, ignore_pierceimmune) return FALSE diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 0e11a27fc79..2767e75da87 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -20,6 +20,8 @@ hud_type = /datum/hud/larva + role_text = "Как Грудолом, вы ещё очень слабы для того, чтобы оказывать помощь гнезду. Ваша задача: прятаться, есть и набираться сил." + var/datum/action/innate/hide/alien_larva/hide_action diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm index f7e379eee11..df5692a1a2f 100644 --- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm +++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm @@ -91,11 +91,8 @@ spawn(6) var/mob/living/carbon/alien/larva/new_xeno = new(owner.drop_location()) new_xeno.key = C.key - if(SSticker && SSticker.mode) - SSticker.mode.xenos += new_xeno.mind new_xeno.mind.name = new_xeno.name - new_xeno.mind.assigned_role = SPECIAL_ROLE_XENOMORPH - new_xeno.mind.special_role = SPECIAL_ROLE_XENOMORPH + new_xeno.update_datum() new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100)//To get the player's attention log_game("[new_xeno.key] has become Alien Larva from [owner](ckey: [owner.key ? owner.key : "None"]) body.") diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm index 56d89bb9be2..3576ad901f9 100644 --- a/code/modules/mob/living/silicon/ai/death.dm +++ b/code/modules/mob/living/silicon/ai/death.dm @@ -26,11 +26,7 @@ if(doomsday_device) doomsday_device.timing = 0 - SSshuttle.emergencyNoEscape = FALSE - if(SSshuttle.emergency.mode == SHUTTLE_STRANDED) - SSshuttle.emergency.mode = SHUTTLE_DOCKED - SSshuttle.emergency.timer = world.time + 3 MINUTES - GLOB.priority_announcement.Announce("Вредоносное окружение устранено. У вас есть 3 минуты, чтобы подняться на борт эвакуационного шаттла.", "Приоритетное оповещение.", 'sound/AI/shuttledock.ogg') + SSshuttle.remove_hostile_environment(doomsday_device, 'sound/AI/shuttledock.ogg') qdel(doomsday_device) if(explosive) diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index f6c657164bd..d3463cfbf98 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -1,9 +1,3 @@ - -#define SPINNING_WEB 1 -#define LAYING_EGGS 2 -#define MOVING_TO_TARGET 3 -#define SPINNING_COCOON 4 - //basic spider mob, these generally guard nests /mob/living/simple_animal/hostile/poison/giant_spider name = "giant spider" @@ -301,8 +295,3 @@ fed-- busy = 0 stop_automated_movement = 0 - -#undef SPINNING_WEB -#undef LAYING_EGGS -#undef MOVING_TO_TARGET -#undef SPINNING_COCOON diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/__defines.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/__defines.dm deleted file mode 100644 index f909b3d557d..00000000000 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/__defines.dm +++ /dev/null @@ -1,33 +0,0 @@ - -#define SPINNING_WEB 1 -#define LAYING_EGGS 2 -#define MOVING_TO_TARGET 3 -#define SPINNING_COCOON 4 - -#define TS_DAMAGE_SIMPLE 0 -#define TS_DAMAGE_POISON 1 -#define TS_DAMAGE_BRUTE 2 - -//TIER 1 -#define TS_DESC_KNIGHT "Knight - ASSAULT" -#define TS_DESC_LURKER "Lurker - AMBUSH" -#define TS_DESC_HEALER "Healer - NURSE" -#define TS_DESC_REAPER "Reaper - BRAWL" -#define TS_DESC_BUILDER "Drone - BUILD" -//TIER 2 -#define TS_DESC_WIDOW "Widow - POISON" -#define TS_DESC_GUARDIAN "Guardian - GUARD" -#define TS_DESC_DESTROYER "Destroyer - BREACHER" -//TIER 3 -#define TS_DESC_PRINCE "Prince - HERO" -#define TS_DESC_PRINCESS "Princess - HORDE" -#define TS_DESC_MOTHER "Mother - SUPPORT" -#define TS_DESC_DEFILER "Defiler - INFECT" -//TIER 4 -#define TS_DESC_QUEEN "Queen - LEADER" - -#define TS_TIER_1 1 -#define TS_TIER_2 2 -#define TS_TIER_3 3 -#define TS_TIER_4 4 -#define TS_TIER_5 5 diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/abillities.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/abillities.dm index 6d9309b5a9e..f26dc906467 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/abillities.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/abillities.dm @@ -6,8 +6,8 @@ //STEALTH AKA INVISIBILLITY /obj/effect/proc_holder/spell/terror_stealth - name = "Stealth" - desc = "Become completely invisible for a short time." + name = "Невидимость" + desc = "Стать полностью невидимым на короткое время." action_icon_state = "stealth" action_background_icon_state = "bg_terror" base_cooldown = 25 SECONDS @@ -23,7 +23,7 @@ /obj/effect/proc_holder/spell/terror_stealth/cast(list/targets, mob/user = usr) user.alpha = 0 - user.visible_message("[user] suddenly disappears!", "You are invisible now!") + user.visible_message(span_warning("[capitalize(user.declent_ru(NOMINATIVE))] внезапно исчезает!"), span_purple("Вы теперь невидимы!")) addtimer(CALLBACK(src, PROC_REF(reveal), user), duration) @@ -32,7 +32,7 @@ return user.alpha = initial(user.alpha) - user.visible_message("[user] appears from nowhere!", "You are visible again!") + user.visible_message(span_warning("[capitalize(user.declent_ru(NOMINATIVE))] появляется из ниоткуда!"), span_purple("Вы снова видимы!")) playsound(user.loc, 'sound/creatures/terrorspiders/stealth_out.ogg', 150, TRUE) @@ -40,8 +40,8 @@ //LESSER HEALING /obj/effect/proc_holder/spell/aoe/terror_healing - name = "Heal" - desc = "Exude feromones to heal your allies" + name = "Исцеляющие феромоны" + desc = "Выбросить в атмосферу феромоны, лечащие ваших союзников." action_icon_state = "heal" action_background_icon_state = "bg_terror" base_cooldown = 30 SECONDS @@ -62,7 +62,7 @@ /obj/effect/proc_holder/spell/aoe/terror_healing/cast(list/targets, mob/user = usr) for(var/mob/living/simple_animal/hostile/poison/terror_spider/spider in targets) - visible_message("[user] exudes feromones and heals spiders around!") + visible_message(span_green("[capitalize(user.declent_ru(NOMINATIVE))] источает целительные феромоны!")) spider.adjustBruteLoss(-heal_amount) if(apply_heal_buff) spider.apply_status_effect(STATUS_EFFECT_TERROR_REGEN) @@ -77,13 +77,13 @@ //VENOM SPIT /obj/effect/proc_holder/spell/fireball/venom_spit - name = "Venom spit" - desc = "Spit an acid that creates smoke filled with drugs and venom on impact." + name = "Кислотный плевок" + desc = "Плюнуть кислоту, при контакте создающую дым, наполненный наркотиками и ядом." invocation_type = "none" action_icon_state = "fake_death" action_background_icon_state = "bg_terror" - selection_activated_message = "Your prepare your venom spit! Left-click to spit at a target!" - selection_deactivated_message = "You cancel your spit." + selection_activated_message = span_notice("Вы подготавливаете свой ядовитый плевок! ЛКМ, чтобы плюнуть в цель.") + selection_deactivated_message = span_notice("Вы отменяете свой плевок.") sound = 'sound/creatures/terrorspiders/spit2.ogg' need_active_overlay = TRUE human_req = FALSE @@ -118,13 +118,13 @@ //SMOKE SPIT /obj/effect/proc_holder/spell/fireball/smoke_spit - name = "Smoke spit" - desc = "Spit an acid that creates smoke on impact." + name = "Плевок дымящейся кислотой" + desc = "Плюнуть кислоту, создающую дым при контакте." invocation_type = "none" action_icon_state = "smoke" action_background_icon_state = "bg_terror" - selection_activated_message = "Your prepare your smoke spit! Left-click to spit at a target!" - selection_deactivated_message = "You cancel your spit." + selection_activated_message = span_notice("Вы подготавливаете дымный плевок! ЛКМ, чтобы плюнуть в цель") + selection_deactivated_message = span_notice("Вы отменяете свой плевок.") sound = 'sound/creatures/terrorspiders/spit2.ogg' need_active_overlay = TRUE human_req = FALSE @@ -155,8 +155,8 @@ //EMP /obj/effect/proc_holder/spell/emplosion/terror_emp - name = "EMP shriek" - desc = "Emits a shriek that causes EMP pulse." + name = "Электро-магнитный визг" + desc = "Издать визг, вызывающий ЭМИ." action_icon_state = "emp_new" action_background_icon_state = "bg_terror" base_cooldown = 40 SECONDS @@ -175,8 +175,8 @@ //EXPLOSION /obj/effect/proc_holder/spell/explosion/terror_burn - name = "Burn!" - desc = "Release your energy to create a massive fire ring." + name = "Воспламенение" + desc = "Высвободить энергию, создавая огромное огненное кольцо." action_icon_state = "explosion" action_background_icon_state = "bg_terror" base_cooldown = 60 SECONDS @@ -196,8 +196,8 @@ //SHIELD /obj/effect/proc_holder/spell/aoe/conjure/build/terror_shield - name = "Guardian shield" - desc = "Create a temporary organic shield to protect your hive." + name = "Защитная мембрана" + desc = "Создать временный органический щит для защиты вашего гнезда." action_icon_state = "terror_shield" action_background_icon_state = "bg_terror" base_cooldown = 8 SECONDS @@ -209,8 +209,8 @@ /obj/effect/forcefield/terror - desc = "Thick protective membrane produced by Guardians of Terror." - name = "Guardian shield" + name = "Защитная мембрана" + desc = "Толстая защитная мембрана, созданная Защитником Ужаса." icon = 'icons/effects/effects.dmi' icon_state = "terror_shield" lifetime = 16.5 SECONDS //max 2 shields existing at one time @@ -229,8 +229,8 @@ //SMOKE /obj/effect/proc_holder/spell/terror_smoke - name = "Smoke" - desc = "Erupt a smoke to confuse your enemies." + name = "Дымовая завеса" + desc = "Извергнуть дым, сбивающий врагов с толку." action_icon_state = "smoke" action_background_icon_state = "bg_terror" base_cooldown = 8 SECONDS @@ -253,8 +253,8 @@ //PARALYSING SMOKE /obj/effect/proc_holder/spell/terror_parasmoke - name = "Paralyzing Smoke" - desc = "Erupt a smoke to paralyze your enemies." + name = "Парализующий дым" + desc = "Извергнуть дым, парализующий врагов." action_icon_state = "biohazard2" action_background_icon_state = "bg_terror" base_cooldown = 60 SECONDS @@ -284,8 +284,8 @@ //TERRIFYING SHRIEK /obj/effect/proc_holder/spell/aoe/terror_shriek - name = "Terrify" - desc = "Emit a loud shriek to terrify your enemies." + name = "Ужасающий визг" + desc = "Издать громкий крик, пугающий врагов." action_icon_state = "terror_shriek" action_background_icon_state = "bg_terror" base_cooldown = 60 SECONDS @@ -305,13 +305,13 @@ /obj/effect/proc_holder/spell/aoe/terror_shriek/cast(list/targets, mob/user = usr) for(var/mob/living/target in targets) if(iscarbon(target)) - to_chat(target, "A spike of pain drives into your head and scrambles your thoughts!") + to_chat(target, span_danger("Всплеск боли пронзает вашу голову и путает ваши мысли!")) target.AdjustConfused(20 SECONDS) target.Slowed(2 SECONDS) target.Jitter(20 SECONDS) if(issilicon(target)) - to_chat(target, "ERROR $!(@ ERROR )#^! SENSORY OVERLOAD \[$(!@#") + to_chat(target, span_warning("ОШИБКА $!(@ ОШИБКА )#^! СЕНСОРНАЯ ПЕРЕГРУЗКА \[$(!@#")) target << 'sound/misc/interference.ogg' playsound(target, 'sound/machines/warning-buzzer.ogg', 50, TRUE) do_sparks(5, 1, target) @@ -324,8 +324,8 @@ //SHRIEK /obj/effect/proc_holder/spell/aoe/terror_shriek_princess - name = "Princess Shriek" - desc = "Emits a loud shriek that weakens your enemies." + name = "Ужасающий визг Принцессы" + desc = "Издать громкий визг, ослабляющий врагов." action_icon_state = "terror_shriek" action_background_icon_state = "bg_terror" base_cooldown = 60 SECONDS @@ -345,13 +345,13 @@ /obj/effect/proc_holder/spell/aoe/terror_shriek_princess/cast(list/targets, mob/user = usr) for(var/mob/living/target in targets) if(iscarbon(target)) - to_chat(target, "A spike of pain drives into your head and scrambles your thoughts!") + to_chat(target, span_danger("Всплеск боли пронзает вашу голову и путает ваши мысли!")) target.apply_damage(30, STAMINA) target.Slowed(10 SECONDS) target.Jitter(20 SECONDS) if(issilicon(target)) - to_chat(target, "ERROR $!(@ ERROR )#^! SENSORY OVERLOAD \[$(!@#") + to_chat(target, span_warning("ОШИБКА $!(@ ОШИБКА )#^! СЕНСОРНАЯ ПЕРЕГРУЗКА \[$(!@#")) target << 'sound/misc/interference.ogg' playsound(target, 'sound/machines/warning-buzzer.ogg', 50, TRUE) do_sparks(5, 1, target) @@ -361,8 +361,8 @@ //SLAM /obj/effect/proc_holder/spell/aoe/terror_slam - name = "Slam" - desc = "Slam the ground with your body." + name = "Топот" + desc = "Ударить землю своим телом." action_icon_state = "slam" action_background_icon_state = "bg_terror" base_cooldown = 35 SECONDS @@ -394,8 +394,8 @@ //JELLY PRODUCTION /obj/effect/proc_holder/spell/aoe/conjure/build/terror_jelly - name = "Produce jelly" - desc = "Produce an organic jelly that heals spiders." + name = "Секреция желе" + desc = "Произвести органическое желе, лечащее пауков." action_icon_state = "spiderjelly" action_background_icon_state = "bg_terror" base_cooldown = 30 SECONDS @@ -408,7 +408,7 @@ //MASS HEAL /obj/effect/proc_holder/spell/aoe/terror_healing/greater - name = "Massive healing" + name = "Массовое исцеление" base_cooldown = 40 SECONDS aoe_range = 7 heal_amount = 30 @@ -421,8 +421,8 @@ //SHRIEK /obj/effect/proc_holder/spell/aoe/terror_shriek_queen - name = "Queen Shriek" - desc = "Emit a loud shriek that weakens your enemies." + name = "Ужасающий визг Королевы" + desc = "Издать громкий визг, ослабляющий врагов." action_icon_state = "terror_shriek" action_background_icon_state = "bg_terror" base_cooldown = 45 SECONDS @@ -442,14 +442,14 @@ for(var/turf/target_turf in targets) for(var/mob/living/target in target_turf.contents) if(iscarbon(target)) - to_chat(target, "A spike of pain drives into your head and scrambles your thoughts!") + to_chat(target, span_danger("Всплеск боли пронзает вашу голову и путает ваши мысли!")) target.AdjustWeakened(2 SECONDS) target.apply_damage(50, STAMINA) target.Jitter(40 SECONDS) target.Slowed(14 SECONDS) if(issilicon(target)) - to_chat(target, "ERROR $!(@ ERROR )#^! SENSORY OVERLOAD \[$(!@#") + to_chat(target, span_warning("ОШИБКА $!(@ ОШИБКА )#^! СЕНСОРНАЯ ПЕРЕГРУЗКА \[$(!@#")) target << 'sound/misc/interference.ogg' playsound(target, 'sound/machines/warning-buzzer.ogg', 50, 1) do_sparks(5, 1, target) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm index 5b84eee0a2f..02c60d8dacb 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm @@ -137,27 +137,35 @@ if(!web_type) return if(!isturf(loc)) - to_chat(src, "Webs can only be spun while standing on a floor.") + to_chat(src, span_danger("Паутину можно плести только стоя на полу.")) return var/turf/mylocation = loc - visible_message("[src] begins to secrete a sticky substance.") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] начинает выделять липкое вещество.")) playsound(src.loc, 'sound/creatures/terrorspiders/web.ogg', 50, 1) if(do_after(src, delay_web, loc)) if(loc != mylocation) return else if(isspaceturf(loc)) - to_chat(src, "Webs cannot be spun in space.") + to_chat(src, span_danger("Паутину невозможно плести в космосе.")) else var/obj/structure/spider/terrorweb/T = locate() in get_turf(src) if(T) - to_chat(src, "There is already a web here.") + to_chat(src, span_danger("Здесь уже есть паутина.")) else var/obj/structure/spider/terrorweb/W = new web_type(loc) W.creator_ckey = ckey /obj/structure/spider/terrorweb name = "terror web" - desc = "it's stringy and sticky" + desc = "Вязкая и липкая паутина." + ru_names = list( + NOMINATIVE = "паутина Ужаса", + GENITIVE = "паутины Ужаса", + DATIVE = "паутине Ужаса", + ACCUSATIVE = "паутину Ужаса", + INSTRUMENTAL = "паутиной Ужаса", + PREPOSITIONAL = "паутине Ужаса" + ) icon = 'icons/effects/effects.dmi' anchored = TRUE // prevents people dragging it density = FALSE // prevents it blocking all movement @@ -190,7 +198,7 @@ return TRUE if(prob(80)) - to_chat(mover, span_danger("You get stuck in [src] for a moment.")) + to_chat(mover, span_danger("Вы на мгновение застреваете в [declent_ru(PREPOSITIONAL)].")) living_mover.Weaken(2 SECONDS) // 2 seconds, wow living_mover.Slowed(10 SECONDS) if(iscarbon(mover)) @@ -205,7 +213,7 @@ /obj/structure/spider/terrorweb/bullet_act(obj/item/projectile/Proj) if(Proj.damage_type != BRUTE && Proj.damage_type != BURN) - visible_message("[src] is undamaged by [Proj]!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] невосприимчива к [Proj.declent_ru(DATIVE)]!")) // Webs don't care about disablers, tasers, etc. Or toxin damage. They're organic, but not alive. return ..() @@ -240,9 +248,9 @@ if(!istype(O, /obj/structure/spider)) choices += O if(choices.len) - cocoon_target = input(src,"What do you wish to cocoon?") in null|choices + cocoon_target = tgui_input_list(src, "Что вы хотите замотать в кокон?", "", choices) else - to_chat(src, "There is nothing nearby you can wrap.") + to_chat(src, span_danger("Рядом нет ничего, что можно было бы завернуть в кокон.")) /mob/living/simple_animal/hostile/poison/terror_spider/proc/DoWrap() if(cocoon_target && busy != SPINNING_COCOON) @@ -250,7 +258,7 @@ cocoon_target = null return busy = SPINNING_COCOON - visible_message("[src] begins to secrete a sticky substance around [cocoon_target].") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] начинает выделять липкое вещество вокруг [cocoon_target.declent_ru(GENITIVE)].")) playsound(src.loc, 'sound/creatures/terrorspiders/wrap.ogg', 120, 1) stop_automated_movement = 1 SSmove_manager.stop_looping(src) @@ -277,10 +285,12 @@ if(iscarbon(L)) apply_status_effect(STATUS_EFFECT_TERROR_FOOD_REGEN) fed++ - visible_message("[src] sticks a proboscis into [L] and sucks a viscous substance out.") - to_chat(src, "You begin to regenerate quickly!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] втыкает хоботок в [L.declent_ru(ACCUSATIVE)] и высасывает вязкое вещество.")) + to_chat(src, span_notice("Вы начинаете быстро восстанавливаться!")) + if(L.mind && ishuman(L)) + SEND_SIGNAL(mind, COMSIG_HUMAN_EATEN) else - visible_message("[src] wraps [L] in a web.") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] заматывает [L.declent_ru(ACCUSATIVE)] в паутину.")) large_cocoon = 1 last_cocoon_object = 0 L.forceMove(C) @@ -302,7 +312,7 @@ if(C.welded) valid_target = TRUE if(!valid_target) - to_chat(src, "No welded vent or scrubber nearby!") + to_chat(src, span_warning("Рядом нет заваренного вентиляционного отверстия или скраббера!")) return playsound(get_turf(src), 'sound/creatures/terrorspiders/ventbreak.ogg', 75, 0) if(do_after(src, 4.3 SECONDS, loc)) @@ -310,13 +320,13 @@ if(P.welded) P.set_welded(FALSE) forceMove(P.loc) - P.visible_message("[src] smashes the welded cover off [P]!") + P.visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] выбивает приваренную крышку [P.declent_ru(GENITIVE)]!")) return for(var/obj/machinery/atmospherics/unary/vent_scrubber/C in range(1, get_turf(src))) if(C.welded) C.set_welded(FALSE) forceMove(C.loc) - C.visible_message("[src] smashes the welded cover off [C]!") + C.visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] выбивает приваренную крышку [C.declent_ru(GENITIVE)]!")) return - to_chat(src, "There is no welded vent or scrubber close enough to do this.") + to_chat(src, span_danger("Поблизости нет заваренного вентиляционного отверстия или скраббера.")) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/builder.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/builder.dm index 799821a1547..b371d0b8f45 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/builder.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/builder.dm @@ -10,7 +10,15 @@ /mob/living/simple_animal/hostile/poison/terror_spider/builder name = "Drone of Terror" - desc = "An ominous-looking spider, he appears to be heavy despite size." + desc = "Зловещий на вид паук, несмотря на размер, он кажется тяжелым." + ru_names = list( + NOMINATIVE = "Дрон Ужаса", + GENITIVE = "Дрона Ужаса", + DATIVE = "Дрону Ужаса", + ACCUSATIVE = "Дрона Ужаса", + INSTRUMENTAL = "Дроном Ужаса", + PREPOSITIONAL = "Дроне Ужаса", + ) gender = MALE ai_target_method = TS_DAMAGE_BRUTE icon_state = "terror_drone" @@ -50,10 +58,10 @@ var/inject_target = pick(BODY_ZONE_CHEST, BODY_ZONE_HEAD) if(HAS_TRAIT(L, TRAIT_INCAPACITATED) || L.can_inject(null, FALSE, inject_target, FALSE)) L.reagents.add_reagent("frostoil", 20) - visible_message("[src] buries its long fangs deep into the [inject_target] of [target]!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] вонзает свои длинные клыки глубоко в [inject_target] [target.declent_ru(ACCUSATIVE)]!")) else L.reagents.add_reagent("frostoil", 10) - visible_message("[src] buries its long fangs deep into the [inject_target] of [target]!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] вонзает свои длинные клыки глубоко в [inject_target] [target.declent_ru(ACCUSATIVE)]!")) return TRUE /mob/living/simple_animal/hostile/poison/terror_spider/builder/Move(atom/newloc, direct = NONE, glide_size_override = 0, update_dir = TRUE) //moves slow while not in web, but fast while in. does not regenerate if not in web @@ -71,7 +79,15 @@ max_integrity = 35 opacity = TRUE name = "drone web" - desc = "Extremely thick web." + desc = "Очень толстая паутина." + ru_names = list( + NOMINATIVE = "паутина Дрона Ужаса", + GENITIVE = "паутиы Дрона Ужаса", + DATIVE = "паутине Дрона Ужаса", + ACCUSATIVE = "паутину Дрона Ужаса", + INSTRUMENTAL = "паутиной Дрона Ужаса", + PREPOSITIONAL = "паутине Дрона Ужаса", + ) /obj/item/projectile/terrorspider/builder name = "drone venom" diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/defiler.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/defiler.dm index 8d12f3c58d1..f6c7dad5e3b 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/defiler.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/defiler.dm @@ -9,7 +9,16 @@ /mob/living/simple_animal/hostile/poison/terror_spider/defiler name = "Defiler of Terror" - desc = "An ominous-looking white spider, its ghostly eyes and vicious-looking fangs are the stuff of nightmares." + desc = "Зловещий на вид белый паук, с призрачными глазами и злобными кошмарными клыками." + ru_names = list( + NOMINATIVE = "Осквернитель Ужаса", + GENITIVE = "Осквернителя Ужаса", + DATIVE = "Осквернителю Ужаса", + ACCUSATIVE = "Осквернителя Ужаса", + INSTRUMENTAL = "Осквернителем Ужаса", + PREPOSITIONAL = "Осквернителе Ужаса", + ) + gender = MALE ai_target_method = TS_DAMAGE_POISON icon_state = "terror_white" icon_living = "terror_white" @@ -22,13 +31,13 @@ melee_damage_upper = 1 spider_opens_doors = 2 spider_tier = TS_TIER_3 - gender = MALE web_type = /obj/structure/spider/terrorweb/white delay_web = 10 special_abillity = list(/obj/effect/proc_holder/spell/terror_smoke, /obj/effect/proc_holder/spell/terror_parasmoke, /obj/effect/proc_holder/spell/aoe/terror_shriek) spider_intro_text = "Будучи Осквернителем Ужаса, ваша цель - атаковать ничего не подозревающих гуманоидов, чтобы заразить их яйцами. Вы наносите мало урона, но можете парализовать цель за три укуса, а ваш яд заставит её замолчать. Вы также можете генерировать различные дымы вредящие противникам. И помните, не нужно убивать заражённых, они послужат носителями для новых пауков!" + datum_type = /datum/antagonist/terror_spider/main_spider/defiler /mob/living/simple_animal/hostile/poison/terror_spider/defiler/LoseTarget() @@ -55,17 +64,17 @@ var/inject_target = pick(BODY_ZONE_CHEST, BODY_ZONE_HEAD) if(HAS_TRAIT(L, TRAIT_INCAPACITATED) || L.can_inject(null, FALSE, inject_target, FALSE) && prob(50)) new /obj/item/organ/internal/body_egg/terror_eggs(L) - visible_message("[src] buries its long fangs deep into the [inject_target] of [target]!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] вонзает свои длинные клыки глубоко в [inject_target] [target.declent_ru(ACCUSATIVE)]!")) else if(prob(20)) new /obj/item/organ/internal/body_egg/terror_eggs(L) - visible_message("[src] pierces armour and buries its long fangs deep into the [inject_target] of [target]!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] пробивает броню и вонзает свои длинные клыки глубоко в [inject_target] [target.declent_ru(ACCUSATIVE)]!")) if(!ckey && !IsTSInfected(L)) step_away(src, L) step_away(src, L) LoseTarget() step_away(src, L) - visible_message("[src] jumps away from [L]!") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] отскакивает от [L.declent_ru(ACCUSATIVE)]!")) /proc/IsTSInfected(mob/living/carbon/C) // Terror AI requires this if(C.get_int_organ(/obj/item/organ/internal/body_egg)) @@ -74,12 +83,21 @@ /obj/structure/spider/terrorweb/white name = "infested web" - desc = "This web is covered in hundreds of tiny, biting spiders - and their eggs." + desc = "Эта паутина покрыта сотнями крошечных кусающих пауков и их яицами." + ru_names = list( + NOMINATIVE = "зараженная паутина", + GENITIVE = "зараженной паутины", + DATIVE = "зараженной паутине", + ACCUSATIVE = "зараженную паутину", + INSTRUMENTAL = "зараженной паутиной", + PREPOSITIONAL = "зараженной паутине", + ) + /obj/structure/spider/terrorweb/white/web_special_ability(mob/living/carbon/C) if(istype(C)) if(!IsTSInfected(C) && ishuman(C)) var/inject_target = pick(BODY_ZONE_CHEST, BODY_ZONE_HEAD) if(C.can_inject(null, FALSE, inject_target, FALSE)) - to_chat(C, "[src] slices into you!") + to_chat(C, "[capitalize(declent_ru(NOMINATIVE))] врезается в вас!") new /obj/item/organ/internal/body_egg/terror_eggs(C) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/destroyer.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/destroyer.dm index d5ae30f3101..ec38af5cafb 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/destroyer.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/destroyer.dm @@ -9,7 +9,15 @@ /mob/living/simple_animal/hostile/poison/terror_spider/destroyer name = "Destroyer of Terror" - desc = "An ominous-looking spider, colored brown like the dirt it crawled out of. Its forearms have sharp digging claws." + desc = "Зловещего вида паук, коричневый, как земля, из которой он выполз. На предплечьях имеются острые когти." + ru_names = list( + NOMINATIVE = "Разрушитель Ужаса", + GENITIVE = "Разрушителя Ужаса", + DATIVE = "Разрушителю Ужаса", + ACCUSATIVE = "Разрушителя Ужаса", + INSTRUMENTAL = "Разрушителем Ужаса", + PREPOSITIONAL = "Разрушителе Ужаса", + ) ai_target_method = TS_DAMAGE_BRUTE icon_state = "terror_brown" icon_living = "terror_brown" diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm index d10b45ae2d6..c06fa1d78b8 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm @@ -9,7 +9,15 @@ /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress name = "Empress of Terror" - desc = "The unholy offspring of spiders, nightmares, and lovecraft fiction." + desc = "Нечестивое порождение пауков, кошмаров и фантастики Лавкрафта." + ru_names = list( + NOMINATIVE = "Императрица Ужаса", + GENITIVE = "Императрицы Ужаса", + DATIVE = "Императрице Ужаса", + ACCUSATIVE = "Императрицу Ужаса", + INSTRUMENTAL = "Императрицой Ужаса", + PREPOSITIONAL = "Императрице Ужаса", + ) ai_target_method = TS_DAMAGE_SIMPLE maxHealth = 1000 health = 1000 @@ -27,12 +35,17 @@ icon_state = "terror_empress" icon_living = "terror_empress" icon_dead = "terror_empress_dead" + datum_type = /datum/antagonist/terror_spider/main_spider/empress var/datum/action/innate/terrorspider/queen/empress/empresslings/empresslings_action var/datum/action/innate/terrorspider/queen/empress/empresserase/empresserase_action tts_seed = "Queen" + spider_intro_text = "Вы - Императрица Ужаса, вершина иерархии гнезда и одно из самых опасных существ этого мира. Управляйте, разрушайте, захватывайте. Теперь это ВАША станция." /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/New() ..() + grant_actions() + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/proc/grant_actions() empresslings_action = new() empresslings_action.Grant(src) empresserase_action = new() @@ -40,46 +53,59 @@ /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/spider_special_action() return - +/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/getSpiderLevel() + return 50 /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/NestMode() ..() queeneggs_action.button.name = "Empress Eggs" /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/LayQueenEggs() - var/eggtype = input("What kind of eggs?") as null|anything in list(TS_DESC_QUEEN, TS_DESC_MOTHER, TS_DESC_PRINCE, TS_DESC_PRINCESS, TS_DESC_KNIGHT, TS_DESC_LURKER, TS_DESC_HEALER, TS_DESC_WIDOW, TS_DESC_GUARDIAN, TS_DESC_DEFILER, TS_DESC_DESTROYER) - var/numlings = input("How many in the batch?") as null|anything in list(1, 2, 3, 4, 5, 10, 15, 20, 30, 40, 50) - if(eggtype == null || numlings == null) - to_chat(src, "Cancelled.") + var/eggtype = tgui_input_list(usr, "Какой тип яиц?", "Тип яиц", list(TS_DESC_QUEEN, TS_DESC_MOTHER, TS_DESC_PRINCE, TS_DESC_PRINCESS, TS_DESC_KNIGHT, TS_DESC_LURKER, TS_DESC_HEALER, TS_DESC_WIDOW, TS_DESC_GUARDIAN, TS_DESC_DEFILER, TS_DESC_DESTROYER)) + var/numlings = tgui_input_number(usr, "Сколько в кладке?", "Количество яиц", 0, min(canlay, 50), 0) + if(!eggtype || !numlings) + to_chat(src, span_danger("Отменено.")) return switch(eggtype) if(TS_DESC_KNIGHT) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/knight, numlings) + canlay -= numlings if(TS_DESC_LURKER) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/lurker, numlings) + canlay -= numlings if(TS_DESC_HEALER) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/healer, numlings) + canlay -= numlings if(TS_DESC_WIDOW) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/widow, numlings) + canlay -= numlings if(TS_DESC_GUARDIAN) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/guardian, numlings) + canlay -= numlings if(TS_DESC_DEFILER) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/defiler, numlings) + canlay -= numlings if(TS_DESC_DESTROYER) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/destroyer, numlings) + canlay -= numlings if(TS_DESC_PRINCE) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, numlings) + canlay -= numlings if(TS_DESC_PRINCESS) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess, numlings) + canlay -= numlings if(TS_DESC_MOTHER) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, numlings) + canlay -= numlings if(TS_DESC_QUEEN) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen, numlings) else - to_chat(src, "Unrecognized egg type.") + to_chat(src, span_danger("Неизвестный тип яйца.")) /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/proc/EmpressLings() - var/numlings = input("How many?") as null|anything in list(10, 20, 30, 40, 50) - var/sbpc = input("%chance to be stillborn?") as null|anything in list(0, 25, 50, 75, 100) + var/numlings = tgui_input_number(usr, "Сколько?", "", 10, 50, 10) + var/sbpc = tgui_input_number(usr, "Шанс быть мертворождённым?", "", 0, 100, 0) + if(!numlings || isnull(sbpc)) + return for(var/i=0, iThrough the hivemind, the raw power of [src] floods into your body, burning it from the inside out!") - for(var/obj/structure/spider/eggcluster/terror_eggcluster/T in GLOB.ts_egg_list) - qdel(T) - for(var/obj/structure/spider/spiderling/terror_spiderling/T in GLOB.ts_spiderling_list) - qdel(T) - to_chat(src, "All Terror Spiders, except yourself, will die off shortly.") + to_chat(T, span_userdanger("Через коллективный разум грубая сила [declent_ru(GENITIVE)] вливается в ваше тело, сжигая его изнутри!")) + var/datum/team/terror_spiders/spider_team = GLOB.antagonist_teams[/datum/team/terror_spiders] + spider_team?.erase_eggs() + to_chat(src, span_userdanger("Все пауки ужаса, кроме вас, вскоре вымрут.")) /obj/item/projectile/terrorspider/empress @@ -112,3 +139,15 @@ icon_state = "toxin5" damage = 90 damage_type = BRUTE + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/weak + canlay = 10 + spider_spawnfrequency = 1000 + ai_playercontrol_allowtype = TRUE + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/weak/getSpiderLevel() + return 7 + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/weak/grant_actions() + empresserase_action = new() + empresserase_action.Grant(src) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm index 7c4c3cce852..0450973d04f 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/ghost.dm @@ -1,48 +1,30 @@ - -/mob/living/simple_animal/hostile/poison/terror_spider/Topic(href, href_list) - if(href_list["activate"]) - var/mob/dead/observer/ghost = usr - if(istype(ghost)) - humanize_spider(ghost) - -/mob/living/simple_animal/hostile/poison/terror_spider/attack_ghost(mob/user) - humanize_spider(user) - -/mob/living/simple_animal/hostile/poison/terror_spider/proc/humanize_spider(mob/user) - if(key)//Someone is in it - return - var/error_on_humanize = "" - var/humanize_prompt = "Take direct control of [src]?" - humanize_prompt += " Role: [spider_intro_text]" - if(user.ckey in GLOB.ts_ckey_blacklist) - error_on_humanize = "You are not able to control any terror spider this round." - else if(cannotPossess(user)) - error_on_humanize = "You have enabled antag HUD and are unable to re-enter the round." +/mob/living/simple_animal/hostile/poison/terror_spider/proc/extra_checks(mob/harbinger) + if(harbinger.ckey in GLOB.ts_ckey_blacklist) + to_chat(harbinger, "В этом раунде вы не можете управлять Пауками Ужаса.") + return FALSE + else if(cannotPossess(harbinger)) + to_chat(harbinger, "Вы включили Antag HUD и не можете повторно войти в раунд..") + return FALSE else if(spider_awaymission) - error_on_humanize = "Terror spiders that are part of an away mission cannot be controlled by ghosts." + to_chat(harbinger, "Пауки Ужаса из гейтов не могут управляться игроками.") + return FALSE else if(!ai_playercontrol_allowtype) - error_on_humanize = "This specific type of terror spider is not player-controllable." - else if(degenerate) - error_on_humanize = "Dying spiders are not player-controllable." - else if(stat == DEAD) - error_on_humanize = "Dead spiders are not player-controllable." - else if(!(user in GLOB.respawnable_list)) - error_on_humanize = "You are not able to rejoin the round." - if(jobban_isbanned(user, "Syndicate") || jobban_isbanned(user, "alien")) - to_chat(user,"You are jobbanned from role of syndicate and/or alien lifeform.") - return - if(error_on_humanize == "") - var/spider_ask = tgui_alert(user, humanize_prompt, "Join as Terror Spider?", list("Yes", "No")) - if(spider_ask != "Yes" || !src || QDELETED(src)) - return - else - to_chat(user, "Cannot inhabit spider: [error_on_humanize]") - return - if(key) - to_chat(user, "Someone else already took this spider.") - return - key = user.key - SSticker.mode.terror_spiders |= mind - give_intro_text() + to_chat(harbinger, "Этот конкретный тип Паука Ужаса не может управляться игроком.") + return FALSE + else if(degenerate || GLOB.global_degenerate) + to_chat(harbinger, "Умирающими Пауками нельзя управлять.") + return FALSE + else if(!(harbinger in GLOB.respawnable_list)) + to_chat(harbinger, "Вы не можете повторно присоединиться к раунду.") + return FALSE + return TRUE + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/humanize_spider() + add_datum_if_not_exist() for(var/mob/dead/observer/G in GLOB.player_list) - G.show_message("A ghost has taken control of [src]. ([ghost_follow_link(src, ghost=G)]).") + G.show_message("Призрак взял управление [declent_ru(INSTRUMENTAL)]. ([ghost_follow_link(src, ghost=G)]).") + + +/mob/living/simple_animal/hostile/poison/terror_spider/proc/add_datum_if_not_exist() + if(mind && !mind.has_antag_datum(/datum/antagonist/terror_spider)) + mind.add_antag_datum(datum_type, /datum/team/terror_spiders) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/guardian.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/guardian.dm index 2496fb39589..8e6f22721e3 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/guardian.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/guardian.dm @@ -10,12 +10,20 @@ /mob/living/simple_animal/hostile/poison/terror_spider/guardian name = "Guardian of Terror" - desc = "An ominous-looking purple spider. It looks about warily, as if waiting for something." + desc = "Зловещего вида фиолетовый паук. Он смотрит по сторонам настороженно, словно чего-то ожидая." ai_target_method = TS_DAMAGE_BRUTE + ru_names = list( + NOMINATIVE = "Защитник Ужаса", + GENITIVE = "Защитника Ужаса", + DATIVE = "Защитнику Ужаса", + ACCUSATIVE = "Защитника Ужаса", + INSTRUMENTAL = "Защитником Ужаса", + PREPOSITIONAL = "Защитнике Ужаса", + ) + gender = MALE icon_state = "terror_purple" icon_living = "terror_purple" icon_dead = "terror_purple_dead" - gender = MALE maxHealth = 250 health = 250 damage_coeff = list(BRUTE = 0.6, BURN = 1.1, TOX = 1, CLONE = 0, STAMINA = 0, OXY = 0.2) @@ -38,7 +46,7 @@ delay_web = 20 special_abillity = list(/obj/effect/proc_holder/spell/aoe/conjure/build/terror_shield) can_wrap = FALSE - spider_intro_text = "Будучи Защитником Ужаса, ваша задача - охрана гнезда, яиц, принцесс и королевы. Вы очень сильны и живучи, используйте это, чтобы защитить выводок. Ваша активная способность создает временный неразрушимый барьер, через который могут пройти только пауки. Если встанет выбор, спасти принцессу, или королеву, при этои обрекая себя на смерть - делайте это без раздумий!." + spider_intro_text = "Будучи Защитником Ужаса, ваша задача - охрана гнезда, яиц, Принцесс и Королевы. Вы очень сильны и живучи, используйте это, чтобы защитить выводок. Ваша активная способность создаёт временный неразрушимый барьер, через который могут пройти только пауки. Если встанет выбор, спасти Принцессу, или Королеву, при этои обрекая себя на смерть - делайте это без раздумий!" ai_spins_webs = FALSE tts_seed = "Avozu" var/queen_visible = TRUE @@ -53,7 +61,7 @@ L.apply_damage(15, STAMINA) if(prob(20)) - visible_message("[src] rams into [L], knocking [L.p_them()] to the floor!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] врезается в [L.declent_ru(ACCUSATIVE)], сбивая с ног!")) L.adjustBruteLoss(20) L.Weaken(4 SECONDS) @@ -64,7 +72,7 @@ if(!degenerate && !spider_myqueen.degenerate) degenerate = TRUE spider_myqueen.DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/guardian, 1) - visible_message("[src] chitters in the direction of [spider_myqueen]!") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] стрекочет в направлении [spider_myqueen.declent_ru(GENITIVE)]!")) return ..() /mob/living/simple_animal/hostile/poison/terror_spider/guardian/Life(seconds, times_fired) @@ -81,7 +89,7 @@ if(Q.stat == DEAD) spider_myqueen = null degenerate = TRUE - to_chat(src, "[Q] has died! Her power no longer sustains you!") + to_chat(src, span_userdanger("[capitalize(Q.declent_ru(NOMINATIVE))] умерла! Её сила больше не поддерживает вас!")) return if(get_dist(src, Q) < vision_range) @@ -92,23 +100,23 @@ if(queen_visible) cycles_noqueen = 0 if(spider_debug) - to_chat(src, "[Q] visible.") + to_chat(src, span_notice("[capitalize(Q.declent_ru(NOMINATIVE))] в зоне видимости.")) else cycles_noqueen++ if(spider_debug) - to_chat(src, "[Q] NOT visible. Cycles: [cycles_noqueen].") + to_chat(src, span_danger("[capitalize(Q.declent_ru(NOMINATIVE))] НЕ в зоне видимости. Цикл: [cycles_noqueen].")) var/area/A = get_area(spider_myqueen) switch(cycles_noqueen) if(6) // one minute without queen sighted - to_chat(src, "You have become separated from [Q]. Return to her in [A].") + to_chat(src, span_danger("Вы отделились от [Q.declent_ru(GENITIVE)]. Вернитесь к ней в [A.declent_ru(PREPOSITIONAL)].")) if(12) // two minutes without queen sighted - to_chat(src, "Your long separation from [Q] weakens you. Return to her in [A].") + to_chat(src, span_danger("Ваша долгая разлука с [Q.declent_ru(INSTRUMENTAL)] ослабляет вас. Вернитесь к ней в [A.declent_ru(PREPOSITIONAL)].")) if(18) // three minutes without queen sighted, kill them. degenerate = TRUE - to_chat(src, "Your link to [Q] has been broken! Your life force starts to drain away!") + to_chat(src, span_userdanger("Ваша связ с [Q] разорвана! Ваша жизненная сила начинает угасать!")) melee_damage_lower = 5 melee_damage_upper = 10 @@ -121,16 +129,24 @@ if(spider_myqueen) var/area/A = get_area(spider_myqueen) if(degenerate) - status_tab_data[++status_tab_data.len] = list("Link:", "BROKEN") // color=red + status_tab_data[++status_tab_data.len] = list("Связь:", "РАЗРУШЕНА") // color=red else if(queen_visible) - status_tab_data[++status_tab_data.len] = list("Link:", "[spider_myqueen] is near") // color=green + status_tab_data[++status_tab_data.len] = list("Связь:", "[capitalize(spider_myqueen.declent_ru(NOMINATIVE))] рядом") // color=green else if(cycles_noqueen >= 18) - status_tab_data[++status_tab_data.len] = list("Link:", "Critical - return to [spider_myqueen] in [A]") // color=red + status_tab_data[++status_tab_data.len] = list("Связь:", "Критическая - вернитесь к [spider_myqueen.declent_ru(DATIVE)] в [A.declent_ru(PREPOSITIONAL)]") // color=red else - status_tab_data[++status_tab_data.len] = list("Link:", "Warning - return to [spider_myqueen] in [A]") // color=orange + status_tab_data[++status_tab_data.len] = list("Связь:", "Опасная - вернитесь к [spider_myqueen.declent_ru(DATIVE)] в [A.declent_ru(PREPOSITIONAL)]") // color=orange /obj/structure/spider/terrorweb/purple name = "thick web" - desc = "This web is so thick, most cannot see beyond it." + desc = "Эта паутина настолько толстая, что большинство не может видеть сквозь нее." opacity = TRUE max_integrity = 40 + ru_names = list( + NOMINATIVE = "толстая паутина", + GENITIVE = "толстой паутины", + DATIVE = "толстой паутине", + ACCUSATIVE = "толстую паутину", + INSTRUMENTAL = "толстой паутиной", + PREPOSITIONAL = "толстой паутине", + ) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/healer.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/healer.dm index b7c2be1a5f5..11ed8272d99 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/healer.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/healer.dm @@ -10,7 +10,16 @@ /mob/living/simple_animal/hostile/poison/terror_spider/healer name = "Healer of Terror" - desc = "An ominous-looking green spider. It has a small egg-sac attached to it, and dried blood stains on its carapace." + desc = "Зловещий зелёный паук. К нему прикреплен небольшой яичный мешок, а на панцире виднеются засохшие пятна крови." + ru_names = list( + NOMINATIVE = "Лекарь Ужаса", + GENITIVE = "Лекаря Ужаса", + DATIVE = "Лекарю Ужаса", + ACCUSATIVE = "Лекаря Ужаса", + INSTRUMENTAL = "Лекарем Ужаса", + PREPOSITIONAL = "Лекаре Ужаса", + ) + gender = MALE ai_target_method = TS_DAMAGE_BRUTE icon_state = "terror_green" icon_living = "terror_green" @@ -23,7 +32,7 @@ melee_damage_upper = 15 web_type = /obj/structure/spider/terrorweb/green special_abillity = list(/obj/effect/proc_holder/spell/aoe/terror_healing) - spider_intro_text = "Будучи Лекарем Ужаса, ваша задача исцелять других пауков и откладывать яйца. Чем больше трупов вы поглотили, тем эффективнее исцеление, однако, для откладывания яиц, вам также необходимы трупы." + spider_intro_text = "Будучи Лекарем Ужаса, ваша задача - исцелять других пауков и откладывать яйца. Чем больше трупов вы поглотили, тем эффективнее исцеление и тем больше яиц вы сможете отложить." var/feedings_to_lay = 3 var/datum/action/innate/terrorspider/greeneggs/greeneggs_action tts_seed = "Jolene" @@ -43,10 +52,10 @@ /mob/living/simple_animal/hostile/poison/terror_spider/healer/proc/DoLayGreenEggs() var/obj/structure/spider/eggcluster/E = locate() in get_turf(src) if(E) - to_chat(src, "There is already a cluster of eggs here!") + to_chat(src, span_notice("Здесь уже имеется кладка яиц!")) return if(fed < feedings_to_lay) - to_chat(src, "You must wrap more humanoid prey before you can do this!") + to_chat(src, span_warning("Прежде чем вы сможете это сделать, вам нужно обернуть в паутину больше гуманоидной добычи!")) return var/list/eggtypes = list(TS_DESC_KNIGHT, TS_DESC_LURKER, TS_DESC_HEALER, TS_DESC_REAPER, TS_DESC_BUILDER) var/list/spider_array = CountSpidersDetailed(FALSE) @@ -56,19 +65,19 @@ eggtypes += TS_DESC_WIDOW var/eggtype = pick(eggtypes) if(client) - eggtype = input("What kind of eggs?") as null|anything in eggtypes + eggtype = tgui_input_list(usr, "Какой тип яиц?", "", eggtypes) if(!(eggtype in eggtypes)) - to_chat(src, "Unrecognized egg type.") - return 0 + to_chat(src, span_danger("Неизвестный тип яйца.")) + return FALSE if(!isturf(loc)) // This has to be checked after we ask the user what egg type. Otherwise they could trigger prompt THEN move into a vent. - to_chat(src, "Eggs can only be laid while standing on a floor.") + to_chat(src, span_danger("Яйца можно откладывать только стоя на полу.")) return if(fed < feedings_to_lay) // We have to check this again after the popup, to account for people spam-clicking the button, then doing all the popups at once. - to_chat(src, "You must wrap more humanoid prey before you can do this!") + to_chat(src, span_warning("Прежде чем вы сможете это сделать, вам нужно обернуть в паутину больше гуманоидной добычи!")) return - visible_message("[src] lays a cluster of eggs.") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] откладывает яица.")) if(eggtype == TS_DESC_KNIGHT) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/knight, 1) else if(eggtype == TS_DESC_LURKER) @@ -84,7 +93,7 @@ else if(eggtype == TS_DESC_DESTROYER) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/destroyer, 1) else - to_chat(src, "Unrecognized egg type!") + to_chat(src, span_warning("Неизвестный тип яиц!")) fed += feedings_to_lay fed -= feedings_to_lay @@ -106,9 +115,9 @@ if(HAS_TRAIT(L, TRAIT_INCAPACITATED) || L.can_inject(null, FALSE, inject_target, FALSE)) L.AdjustEyeBlurry(20 SECONDS, 0, 120 SECONDS) // instead of having a venom that only lasts seconds, we just add the eyeblur directly. - visible_message(span_danger("[src] buries its fangs deep into the [inject_target] of [target]!")) + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] вонзает свои клыки глубоко в [inject_target] [target.declent_ru(ACCUSATIVE)]!")) else - visible_message(span_danger("[src] bites [target], but cannot inject venom into [target.p_their()] [inject_target]!")) + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] кусает [target.declent_ru(ACCUSATIVE)], но не может ввести яд в [inject_target]!")) /mob/living/simple_animal/hostile/poison/terror_spider/healer/AttackingTarget() . = ..() @@ -127,7 +136,15 @@ /obj/structure/spider/terrorweb/green name = "slimy web" - desc = "This web is partly composed of strands of green slime." + desc = "Эта паутина частично состоит из нитей зелёной слизи." + ru_names = list( + NOMINATIVE = "скользкая паутина", + GENITIVE = "скользкой паутины", + DATIVE = "скользкой паутине", + ACCUSATIVE = "скользкую паутину", + INSTRUMENTAL = "скользкой паутиной", + PREPOSITIONAL = "скользкой паутине", + ) /obj/structure/spider/terrorweb/green/web_special_ability(mob/living/carbon/C) if(istype(C)) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm index 407e6f3174e..037ff1318e4 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm @@ -3,20 +3,20 @@ /mob/living/simple_animal/hostile/poison/terror_spider/proc/DoHiveSense() var/hsline = "" - to_chat(src, "Your Brood: ") + to_chat(src, "Ваш род: ") for(var/thing in GLOB.ts_spiderlist) var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing if(T.spider_awaymission != spider_awaymission) continue - hsline = "* [T] in [get_area(T)], " + hsline = "* [capitalize(T.declent_ru(NOMINATIVE))] в [get_area(T)], " if(T.stat == DEAD) - hsline += "DEAD" + hsline += "МЁРТВ" else - hsline += "health [T.health] / [T.maxHealth], " + hsline += "здоровье [T.health] / [T.maxHealth], " if(T.ckey) - hsline += " *Player Controlled* " + hsline += " *Управляется Игроком* " else - hsline += " AI " + hsline += " ИИ " to_chat(src,hsline) /mob/living/simple_animal/hostile/poison/terror_spider/proc/CountSpiders() diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/knight.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/knight.dm index c54b745d762..faeadb1a274 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/knight.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/knight.dm @@ -11,7 +11,16 @@ /mob/living/simple_animal/hostile/poison/terror_spider/knight name = "Knight of Terror" - desc = "An ominous-looking red spider, it has eight beady red eyes, and nasty, big, pointy fangs! It looks like it has a vicious streak a mile wide." + desc = "Зловещий на вид красный паук c восемью красными глазами-бусинками и ужасными, большими, заострёнными клыками! Похоже, у него порочная полоса шириной в милю." + ru_names = list( + NOMINATIVE = "Рыцарь Ужаса", + GENITIVE = "Рыцаря Ужаса", + DATIVE = "Рыцарю Ужаса", + ACCUSATIVE = "Рыцаря Ужаса", + INSTRUMENTAL = "Рыцарем Ужаса", + PREPOSITIONAL = "Рыцаре Ужаса", + ) + gender = MALE ai_target_method = TS_DAMAGE_BRUTE icon_state = "terror_red" icon_living = "terror_red" @@ -32,7 +41,6 @@ move_resist = MOVE_FORCE_STRONG // no more pushing a several hundred if not thousand pound spider web_type = /obj/structure/spider/terrorweb/knight spider_intro_text = "Будучи Рыцарем Ужаса, ваша задача - создавать места для прорыва, или же оборонять гнездо. Несмотря на медлительность, вы живучи и опасны вблизи, используйте свою силу и выносливость, чтобы другие пауки могли выполнять свои функции! Ваши способности позволяют вам переключаться между режимом атаки и обороны, первый - увеличивает скорость, а также наносимый и получаемый урон, второй - уменьшает скорость, получаемый и наносимый урон." - gender = MALE tts_seed = "Chu" var/last_attack_mode = 0 var/last_defence_mode = 0 @@ -72,48 +80,56 @@ var/t = world.time if (n==0) playsound(src, 'sound/creatures/terrorspiders/keratosis_out.ogg', 150) - to_chat(src, "Your body relaxes!") + to_chat(src, span_notice("Ваше тело расслабляется!")) set_varspeed(0.8) damage_coeff = list(BRUTE = 0.6, BURN = 1.1, TOX = 1, CLONE = 0, STAMINA = 0, OXY = 0.2) melee_damage_lower = 15 melee_damage_upper = 15 regeneration = 2 current_mode = 0 - return 1 + return TRUE if (n==1) if(attack_mode_av) last_attack_mode = t last_mode = t attack_mode_av = 0 playsound(src, 'sound/creatures/terrorspiders/mod_attack.ogg', 120) - to_chat(src, "You are now in rage") + to_chat(src, span_danger("Вы впадаете в ярость!")) set_varspeed(0) damage_coeff = list(BRUTE = 0.8, BURN = 1.2, TOX = 1, CLONE = 0, STAMINA = 0, OXY = 0.2) melee_damage_lower = 30 melee_damage_upper = 30 regeneration = 0 current_mode = 1 - return 1 - to_chat(src, "You cant do this yet!") - return 0 + return TRUE + to_chat(src, span_notice("Вы пока не можете этого сделать!")) + return FALSE if (n==2) if(defence_mode_av) last_defence_mode = t last_mode = t defence_mode_av = 0 playsound(src, 'sound/creatures/terrorspiders/keratosis_in.ogg', 150) - to_chat(src, "You cover yourself with keratosis!") + to_chat(src, span_danger("Вы покрываетесь кератозисом!")) set_varspeed(1.6) damage_coeff = list(BRUTE = 0.4, BURN = 0.7, TOX = 1, CLONE = 0, STAMINA = 0, OXY = 0.2) melee_damage_lower = 10 melee_damage_upper = 10 regeneration = 6 current_mode = 2 - return 1 - to_chat(src, "You cant do this yet!") - return 0 + return TRUE + to_chat(src, span_notice("Вы пока не можете этого сделать!")) + return FALSE /obj/structure/spider/terrorweb/knight max_integrity = 30 name = "reinforced web" - desc = "This web is reinforced with extra strands, for added strength." + desc = "Эта паутина усилена прочными нитями для дополнительной прочности." + ru_names = list( + NOMINATIVE = "укрепленная паутина", + GENITIVE = "укрепленной паутины", + DATIVE = "укрепленной паутине", + ACCUSATIVE = "укрепленную паутину", + INSTRUMENTAL = "укрепленной паутиной", + PREPOSITIONAL = "укрепленной паутине", + ) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/lurker.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/lurker.dm index 3df7c8f5472..d8fe92d1bb2 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/lurker.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/lurker.dm @@ -10,7 +10,16 @@ /mob/living/simple_animal/hostile/poison/terror_spider/lurker name = "Lurker of Terror" - desc = "An ominous-looking gray spider. It seems to blend into webs, making it hard to see." + desc = "Зловещего вида серый паук. Кажется, что он сливается с паутиной, из-за чего его трудно увидеть." + ru_names = list( + NOMINATIVE = "Наблюдатель Ужаса", + GENITIVE = "Наблюдателя Ужаса", + DATIVE = "Наблюдателю Ужаса", + ACCUSATIVE = "Наблюдателя Ужаса", + INSTRUMENTAL = "Наблюдателем Ужаса", + PREPOSITIONAL = "Наблюдателе Ужаса", + ) + gender = MALE ai_target_method = TS_DAMAGE_BRUTE icon_state = "terror_gray" icon_living = "terror_gray" @@ -55,7 +64,7 @@ melee_damage_lower = initial(melee_damage_lower) melee_damage_upper = initial(melee_damage_upper) armour_penetration = initial(armour_penetration) - visible_message("[src] bites [target]!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] кусает [target.declent_ru(ACCUSATIVE)]!")) . = ..() //eat victim @@ -79,7 +88,15 @@ /obj/structure/spider/terrorweb/gray alpha = 80 name = "transparent web" - desc = "This web is partly transparent, making it harder to see, and easier to get caught by." + desc = "Эта паутина частично прозрачна, поэтому её труднее увидеть и легче попасться." + ru_names = list( + NOMINATIVE = "прозрачная паутина", + GENITIVE = "прозрачной паутины", + DATIVE = "прозрачной паутине", + ACCUSATIVE = "прозрачную паутину", + INSTRUMENTAL = "прозрачной паутиной", + PREPOSITIONAL = "прозрачной паутине", + ) /obj/structure/spider/terrorweb/gray/web_special_ability(mob/living/carbon/C) //super deadly web if(istype(C)) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm index 35c0dec4ba6..b30f4c68893 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm @@ -10,7 +10,15 @@ /mob/living/simple_animal/hostile/poison/terror_spider/mother name = "Mother of Terror" - desc = "An enormous spider. Tiny spiderlings are crawling all over it. Their beady little eyes all stare at you. The horror!" + desc = "Огромный паук. По нему ползают крошечные паучки. Их маленькие глазки-бусинки смотрят на вас. Ужас!" + ru_names = list( + NOMINATIVE = "Мать Ужаса", + GENITIVE = "Матери Ужаса", + DATIVE = "Матери Ужаса", + ACCUSATIVE = "Мать Ужаса", + INSTRUMENTAL = "Матерью Ужаса", + PREPOSITIONAL = "Матери Ужаса", + ) ai_target_method = TS_DAMAGE_SIMPLE icon_state = "terror_mother" icon_living = "terror_mother" @@ -59,5 +67,5 @@ /mob/living/simple_animal/hostile/poison/terror_spider/mother/consume_jelly(obj/structure/spider/royaljelly/J) - to_chat(src, "Mothers cannot consume royal jelly.") + to_chat(src, span_warning("Матери Ужаса не могут употреблять королевское желе.")) return diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm index 3ba28037902..5509c86b38e 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm @@ -10,7 +10,15 @@ /mob/living/simple_animal/hostile/poison/terror_spider/prince name = "Prince of Terror" - desc = "An enormous, terrifying spider. It looks like it is judging everything it sees. Its hide seems armored, and it bears the scars of many battles." + desc = "Огромный, ужасающий паук. Похоже, он уничтожает всё, что видит. Его шкура кажется непробиваемой, и на нём видны шрамы многих сражений." + ru_names = list( + NOMINATIVE = "Принц Ужаса", + GENITIVE = "Принца Ужаса", + DATIVE = "Принцу Ужаса", + ACCUSATIVE = "Принца Ужаса", + INSTRUMENTAL = "Принцем Ужаса", + PREPOSITIONAL = "Принце Ужаса", + ) ai_target_method = TS_DAMAGE_BRUTE icon_state = "terror_allblack" icon_living = "terror_allblack" @@ -19,7 +27,7 @@ health = 600 speed = -0.1 damage_coeff = list(BRUTE = 0.3, BURN = 0.6, TOX = 1, CLONE = 0, STAMINA = 0, OXY = 0.2) - deathmessage = "morbidly growls, flailing and crumbling as death finally washes away the burning hatred in it's eyes." + deathmessage = "болезненно рычит, трясётся и ослабевает, пока смерть наконец не смывает пылающую ненависть из его ужасающих глаз." death_sound = 'sound/creatures/terrorspiders/prince_dead.ogg' regeneration = 0 //no healing on life, prince should play agressive force_threshold = 30 @@ -38,6 +46,7 @@ web_type = null special_abillity = list(/obj/effect/proc_holder/spell/aoe/terror_slam) spider_intro_text = "Будучи Принцом Ужаса, ваша задача - устроить резню. У вас больше здоровья и урона, чем у любого другого паука, вы можете отрывать конечности, быстро уничтожать мехи, однако, если вы не будете пожирать трупы, сразу потеряете способность регенерировать. Ваша активная способность оглушает противников в радиусе двух плиток, попутно замедляя их." + datum_type = /datum/antagonist/terror_spider/main_spider/prince gender = MALE move_resist = MOVE_FORCE_STRONG // no more pushing a several hundred if not thousand pound spider tts_seed = "Alduin" @@ -57,7 +66,7 @@ L.Weaken(2 SECONDS) playsound(src, 'sound/creatures/terrorspiders/rip.ogg', 100, 1) var/obj/item/organ/external/NB = pick(L.bodyparts) - visible_message(span_warning("[src] Tears appart the [NB.name] of [L] with his razor sharp jaws!")) + visible_message(span_warning("[capitalize(declent_ru(NOMINATIVE))] отрывает [NB.declent_ru(ACCUSATIVE)] [L.declent_ru(GENITIVE)] своими острыми, как бритва, челюстями!")) NB.droplimb() //dismemberment L.apply_damage(35, STAMINA) else diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm index 6bb47508837..8c902e1d2da 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm @@ -10,7 +10,15 @@ /mob/living/simple_animal/hostile/poison/terror_spider/queen/princess name = "Princess of Terror spider" - desc = "An enormous spider. It looks strangely cute and fluffy." + desc = "Огромный паук. Он выглядит необычайно милым и пушистым." + ru_names = list( + NOMINATIVE = "Принцесса Ужаса", + GENITIVE = "Принцессы Ужаса", + DATIVE = "Принцессе Ужаса", + ACCUSATIVE = "Принцессу Ужаса", + INSTRUMENTAL = "Принцессой Ужаса", + PREPOSITIONAL = "Принцессе Ужаса", + ) ai_target_method = TS_DAMAGE_SIMPLE icon_state = "terror_princess1" icon_living = "terror_princess1" @@ -22,11 +30,12 @@ health = 200 speed = -0.1 delay_web = 20 - deathmessage = "Emits a piercing screech and slowly falls on the ground." + deathmessage = "Издаёт пронзительный визг и медленно опадает на землю." death_sound = 'sound/creatures/terrorspiders/princess_death.ogg' spider_tier = TS_TIER_3 move_resist = MOVE_FORCE_STRONG // no more pushing a several hundred if not thousand pound spider spider_intro_text = "Будучи Принцессой Ужаса, ваша задача - откладывать яйца и охранять их. Хоть вы и умеете плеваться кислотой, а также обладаете визгом, помогающим в бою, вам не стоит сражаться намеренно, ведь для этого есть другие пауки." + datum_type = /datum/antagonist/terror_spider/main_spider/princess ranged = 1 projectiletype = /obj/item/projectile/terrorspider/princess ranged_cooldown_time = 30 @@ -77,26 +86,26 @@ icon_state = "terror_princess1" icon_living = "terror_princess1" icon_dead = "terror_princess1_dead" - desc = "An enormous spider. It looks strangely cute and fluffy, with soft pink fur covering most of its body." + desc = "Огромный паук. Он выглядит странно милым и пушистым, с нежно-розовым мехом, покрывающим большую часть его тела" else if(brood_count < (spider_max_children /2)) icon_state = "terror_princess2" icon_living = "terror_princess2" icon_dead = "terror_princess2_dead" - desc = "An enormous spider. It used to look strangely cute and fluffy, but now the effect is spoiled by parts of its fur, which have turned an ominous blood red in color." + desc = "Огромный паук. Раньше он выглядел странно милым и пушистым, но теперь этот эффект портят части меха, которые приобрели зловещий кроваво-красный цвет." else icon_state = "terror_princess3" icon_living = "terror_princess3" icon_dead = "terror_princess3_dead" - desc = "An enormous spider. Its entire body looks to be the color of dried blood." + desc = "Огромный паук. Всё его тело покрыто засохшей кровью." if((brood_count + canlay) >= spider_max_children) return canlay++ if(canlay == 1) - to_chat(src, "You have an egg available to lay.") + to_chat(src, span_notice("У вас есть яйцо, которое можно отложить.")) SEND_SOUND(src, sound('sound/effects/ping.ogg')) else - to_chat(src, "You have [canlay] eggs available to lay.") + to_chat(src, span_notice("У вас есть [canlay] [declension_ru(canlay, "яйцо", "яйца", "яиц")], которые можно отложить.")) SEND_SOUND(src, sound('sound/effects/ping.ogg')) /mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/NestMode() diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm index 7a741db2bf5..244d5bc64e3 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm @@ -10,7 +10,15 @@ /mob/living/simple_animal/hostile/poison/terror_spider/queen name = "Queen of Terror spider" - desc = "An enormous, terrifying spider. Its egg sac is almost as big as its body, and teeming with spider eggs!" + desc = "Огромный, ужасающий паук. Её яйцевой мешок почти такого же размера, как и её тело, и изобилует паучьими яйцами!" + ru_names = list( + NOMINATIVE = "Королева Ужаса", + GENITIVE = "Королевы Ужаса", + DATIVE = "Королеве Ужаса", + ACCUSATIVE = "Королеву Ужаса", + INSTRUMENTAL = "Королевой Ужаса", + PREPOSITIONAL = "Королеве Ужаса", + ) ai_target_method = TS_DAMAGE_SIMPLE icon_state = "terror_queen" icon_living = "terror_queen" @@ -19,7 +27,7 @@ health = 340 damage_coeff = list(BRUTE = 0.7, BURN = 1.1, TOX = 1, CLONE = 0, STAMINA = 0, OXY = 0.2) regeneration = 3 - deathmessage = "Emits a piercing screech that echoes through the hallways, chilling the hearts of those around, as the spider lifelessly falls to the ground." + deathmessage = "Издаёт пронзительный визг, эхом разносящийся по коридорам и леденящий сердца окружающих, в то время как паук безжизненно падает на землю." death_sound = 'sound/creatures/terrorspiders/queen_death.ogg' melee_damage_lower = 25 melee_damage_upper = 30 @@ -44,7 +52,8 @@ delay_web = 15 special_abillity = list(/obj/effect/proc_holder/spell/aoe/terror_shriek_queen) can_wrap = FALSE - spider_intro_text = "Будучи Королевой Ужаса, ваша цель - управление выводком и откладывание яиц. Вы крайне сильны, и со временем будете откладывать всё больше яиц, однако, ваша смерть будет означать поражение, ведь все пауки погибнут." + spider_intro_text = "Будучи Королевой Ужаса, ваша цель - управление выводком и откладывание яиц. Вы крайне сильны, и со временем будете откладывать всё больше яиц, однако, ваша смерть будет означать неминуюемую гибель гнезда, ведь все пауки погибнут." + datum_type = /datum/antagonist/terror_spider/main_spider/queen var/spider_spawnfrequency = 1600 // 160 seconds. Default for player queens and NPC queens on station. Awaymission queens have this changed in New() var/spider_spawnfrequency_stable = 3600 // 360 seconds. Spawnfrequency is set to this on awaymission spiders once nest setup is complete. var/spider_lastspawn = 0 @@ -93,10 +102,10 @@ spider_lastspawn = world.time canlay += getSpiderLevel() if(canlay == 1) - to_chat(src, "You have an egg available to lay.") + to_chat(src, span_notice("У вас есть яйцо, которое можно отложить.")) SEND_SOUND(src, sound('sound/effects/ping.ogg')) else if(canlay > 1) - to_chat(src, "You have [canlay] eggs available to lay.") + to_chat(src, span_notice("У вас есть [canlay] [declension_ru(canlay, "яйцо", "яйца", "яиц")], которые можно отложить.")) SEND_SOUND(src, sound('sound/effects/ping.ogg')) /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/getSpiderLevel() @@ -122,8 +131,8 @@ if(T.spider_myqueen != src) continue if(T.spider_tier < spider_tier) - T.visible_message("[T] writhes in pain!") - to_chat(T, "\The psychic backlash from the death of [src] overwhelms you! You feel the life start to drain out of you...") + T.visible_message(span_danger("[capitalize(T.declent_ru(NOMINATIVE))] корчится от боли!")) + to_chat(T, span_userdanger("Психическая реакция от смерти [declent_ru(GENITIVE)] ошеломляет вас! Вы чувствуете, как жизнь начинает утекать из вас...")) T.degenerate = TRUE for(var/thing in GLOB.ts_spiderling_list) var/obj/structure/spider/spiderling/terror_spiderling/T = thing @@ -177,10 +186,10 @@ if(ok_to_nest && entry_vent) nest_vent = entry_vent neststep = 1 - visible_message("\The [src] settles down, starting to build a nest.") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] приживается, начиная строить гнездо.")) else if(entry_vent) if(!path_to_vent) - visible_message("\The [src] looks around warily - then seeks a better nesting ground.") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] настороженно оглядывается – затем ищет лучшее место для строительста гнезда.")) path_to_vent = 1 else neststep = -1 @@ -190,7 +199,8 @@ if(world.time > (lastnestsetup + nestfrequency)) lastnestsetup = world.time neststep = 2 - NestMode() + if(!hasnested) + NestMode() if(2) // Create initial T2 spiders. if(world.time > (lastnestsetup + nestfrequency)) @@ -237,8 +247,8 @@ /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/NestPrompt() - var/confirm = tgui_alert(src, "Are you sure you want to nest? You will be able to lay eggs, and smash walls, but not ventcrawl.", "Nest?", list("Yes","No")) - if(confirm == "Yes") + var/confirm = tgui_alert(src, "Вы уверены, что хотите строить гнездо? Вы сможете откладывать яйца и разбивать стены, но не ползать по вентиляции.", "Гнездо?", list("Да","Нет")) + if(confirm == "Да") NestMode() @@ -254,14 +264,14 @@ ai_ventcrawls = FALSE environment_smash = ENVIRONMENT_SMASH_RWALLS DoQueenScreech(8, 100, 8, 100) - to_chat(src, "You have matured to your egglaying stage. You can now smash through walls, and lay eggs, but can no longer ventcrawl.") + to_chat(src, span_notice("Вы достигли стадии кладки яиц. Теперь вы можете пробивать стены и откладывать яйца, но больше не можете ползать по вентиляции.")) /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/LayQueenEggs() if(stat == DEAD) return if(!hasnested) - to_chat(src, "You must nest before doing this.") + to_chat(src, span_danger("Прежде чем делать это, вы должны начать строить гнездо.")) return if(canlay < 1) show_egg_timer() @@ -269,31 +279,31 @@ var/list/eggtypes = ListAvailableEggTypes() var/list/eggtypes_uncapped = list(TS_DESC_KNIGHT, TS_DESC_LURKER, TS_DESC_HEALER, TS_DESC_REAPER, TS_DESC_BUILDER) - var/eggtype = input("What kind of eggs?") as null|anything in eggtypes + var/eggtype = tgui_input_list(usr, "Какой тип яиц?", "", eggtypes) if(canlay < 1) // this was checked before input() but we have to check again to prevent them spam-clicking the popup. - to_chat(src, "Too soon to lay another egg.") + to_chat(src, span_danger("Слишком рано откладывать еще одно яйцо.")) return if(!(eggtype in eggtypes)) - to_chat(src, "Unrecognized egg type.") - return 0 + to_chat(src, span_danger("Неизвестный тип яйца.")) + return FALSE // Multiple of eggtypes_uncapped can be laid at once. Other types must be laid one at a time (to prevent exploits) var/numlings = 1 if(eggtype in eggtypes_uncapped) if(canlay >= 5) - numlings = input("How many in the batch?") as null|anything in list(1, 2, 3, 4, 5) + numlings = tgui_input_list(usr, "Сколько яиц в кладке?", "", list(1, 2, 3, 4, 5)) else if(canlay >= 3) - numlings = input("How many in the batch?") as null|anything in list(1, 2, 3) + numlings = tgui_input_list(usr, "Сколько яиц в кладке?", "", list(1, 2, 3)) else if(canlay == 2) - numlings = input("How many in the batch?") as null|anything in list(1, 2) + numlings = tgui_input_list(usr, "Сколько яиц в кладке?", "", list(1, 2)) if(eggtype == null || numlings == null) - to_chat(src, "Cancelled.") + to_chat(src, span_danger("Отменено.")) return // Actually lay the eggs. if(canlay < numlings) // We have to check this again after the popups, to account for people spam-clicking the button, then doing all the popups at once. - to_chat(src, "Too soon to do this again!") + to_chat(src, span_warning("Слишком рано делать это снова!")) return canlay -= numlings eggslaid += numlings @@ -321,14 +331,14 @@ if(TS_DESC_PRINCESS) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess, numlings) else - to_chat(src, "Unrecognized egg type.") + to_chat(src, span_danger("Неизвестный тип яйца.")) /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/show_egg_timer() var/remainingtime = round(((spider_lastspawn + spider_spawnfrequency) - world.time) / 10, 1) if(remainingtime > 0) - to_chat(src, "Too soon to attempt that again. Wait another [num2text(remainingtime)] seconds.") + to_chat(src, span_danger("Слишком рано пытаться повторить это. Подождите еще [num2text(remainingtime)] секунд.")) else - to_chat(src, "Too soon to attempt that again. Wait just a few more seconds...") + to_chat(src, span_danger("Слишком рано пытаться повторить это. Подождите еще несколько секунд...")) /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/ListAvailableEggTypes() if(MinutesAlive() >= 25) @@ -348,7 +358,7 @@ /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/DoQueenScreech(light_range, light_chance, camera_range, camera_chance) - visible_message("[src] emits a bone-chilling shriek!") + visible_message(span_userdanger("[capitalize(declent_ru(NOMINATIVE))] издает пронзительный визг!")) playsound(src.loc, 'sound/creatures/terrorspiders/queen_shriek.ogg', 100, 1) for(var/obj/machinery/light/L in orange(light_range, src)) if(L.on && prob(light_chance)) @@ -364,8 +374,8 @@ return if(!isobserver(user) && !isterrorspider(user)) return - . += "[p_they(TRUE)] has laid [eggslaid] egg[eggslaid != 1 ? "s" : ""]." - . += "[p_they(TRUE)] has lived for [MinutesAlive()] minutes." + . += span_notice("Она отложила [eggslaid] [eggslaid != 1 ? "яиц" : "яйцо"].") + . += span_notice("Она прожила [MinutesAlive()] минут.") /obj/item/projectile/terrorspider/queen @@ -377,7 +387,15 @@ /obj/structure/spider/terrorweb/queen name = "airtight web" - desc = "This multi-layered web seems to be able to resist air pressure." + desc = "Эта многослойная паутина, кажется, способна противостоять давлению воздуха." + ru_names = list( + NOMINATIVE = "воздухонепроницаемая паутина", + GENITIVE = "воздухонепроницаемой паутины", + DATIVE = "воздухонепроницаемой паутине", + ACCUSATIVE = "воздухонепроницаемую паутину", + INSTRUMENTAL = "воздухонепроницаемой паутиной", + PREPOSITIONAL = "воздухонепроницаемой паутине", + ) max_integrity = 30 diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/reaper.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reaper.dm index 5c442282d45..774581f8bdb 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/reaper.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reaper.dm @@ -1,7 +1,15 @@ /mob/living/simple_animal/hostile/poison/terror_spider/reaper name = "Reaper of Terror" - desc = "A terrible-looking spider, she appears to have sharp claws and jaws, and her body is covered with tumors. You can see agony and thirst for blood in her glowing eyes.." + desc = "Ужасного вида паук. У него острые когти и челюсти, а тело покрыто опухолями. В его светящихся глазах можно увидеть агонию и жажду крови.." + ru_names = list( + NOMINATIVE = "Жнец Ужаса", + GENITIVE = "Жнеца Ужаса", + DATIVE = "Жнецу Ужаса", + ACCUSATIVE = "Жнеца Ужаса", + INSTRUMENTAL = "Жнецом Ужаса", + PREPOSITIONAL = "Жнеце Ужаса", + ) ai_target_method = TS_DAMAGE_BRUTE icon_state = "terror_reaper" icon_living = "terror_reaper" @@ -19,7 +27,6 @@ spider_opens_doors = 2 speed = -0.3 web_type = null - gender = FEMALE tts_seed = "Myra" spider_intro_text = "Будучи Жнецом Ужаса, ваша задача - уничтожение живой силы противника. Вы быстры, наносите много урона, обладаете вампиризмом, и с каждым укусом высасываете у противников немного крови. Однако, платой за эту силу стало то, что вы постепенно теряете здоровье. Если прекратите убивать - погибните." diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm index 7047e60aa4d..65db51eb986 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm @@ -5,7 +5,15 @@ /obj/structure/spider/spiderling/terror_spiderling name = "spiderling" - desc = "A fast-moving tiny spider, prone to making aggressive hissing sounds. Hope it doesn't grow up." + desc = "Быстро движущийся крошечный паук, склонный издавать агрессивные шипящие звуки. Надеюсь, оно не вырастет." + ru_names = list( + NOMINATIVE = "паучок", + GENITIVE = "паучка", + DATIVE = "паучку", + ACCUSATIVE = "паучка", + INSTRUMENTAL = "паучком", + PREPOSITIONAL = "паучке", + ) icon_state = "spiderling" anchored = FALSE layer = 2.75 @@ -21,21 +29,23 @@ var/frustration = 0 var/debug_ai_choices = FALSE var/movement_disabled = FALSE + var/mob/asigned_ghost /obj/structure/spider/spiderling/terror_spiderling/Initialize(mapload) . = ..() GLOB.ts_spiderling_list += src + var/datum/team/terror_spiders/spider_team = GLOB.antagonist_teams[/datum/team/terror_spiders] if(is_away_level(z)) spider_awaymission = TRUE + else + spider_team?.terror_eggs |= src /obj/structure/spider/spiderling/terror_spiderling/Destroy() GLOB.ts_spiderling_list -= src - return ..() - - -/obj/structure/spider/spiderling/terror_spiderling/Destroy() for(var/obj/structure/spider/spiderling/terror_spiderling/S in view(7, src)) S.immediate_ventcrawl = TRUE + var/datum/team/terror_spiders/spider_team = GLOB.antagonist_teams[/datum/team/terror_spiders] + spider_team?.terror_eggs -= src return ..() /obj/structure/spider/spiderling/terror_spiderling/proc/score_surroundings(atom/A = src) @@ -78,6 +88,9 @@ var/turf/T = get_turf(src) if(spider_awaymission && !is_away_level(T.z)) stillborn = TRUE + if(GLOB.global_degenerate && !spider_awaymission && !QDELETED(src)) + qdel(src) + return if(stillborn) // Fake spiderlings stick around for awhile, just to be spooky. qdel(src) @@ -88,7 +101,25 @@ S.spider_myqueen = spider_myqueen S.spider_mymother = spider_mymother S.enemies = enemies + + if(!spider_awaymission && asigned_ghost) + S.key = asigned_ghost.key + S.add_datum_if_not_exist() + asigned_ghost = null + else if(!spider_awaymission) + S.AddComponent(\ + /datum/component/ghost_direct_control,\ + ban_type = ROLE_TERROR_SPIDER,\ + ban_syndicate = TRUE,\ + poll_candidates = FALSE,\ + question_text =" Роль: [S.spider_intro_text]" ,\ + extra_control_checks = CALLBACK(S, \ + TYPE_PROC_REF(/mob/living/simple_animal/hostile/poison/terror_spider, extra_checks)),\ + after_assumed_control = CALLBACK(S, \ + TYPE_PROC_REF(/mob/living/simple_animal/hostile/poison/terror_spider, humanize_spider)),\ + ) qdel(src) + if(movement_disabled) return if(travelling_in_vent) @@ -133,7 +164,7 @@ entry_vent = null return if(prob(50)) - audible_message("You hear something squeezing through the ventilation ducts.") + audible_message(span_notice("Слышно, как что-то сжимается в вентиляционных каналах.")) spawn(travel_time) if(!exit_vent || exit_vent.welded) forceMove(original_location) @@ -177,6 +208,9 @@ C.spider_myqueen = spider_myqueen C.spider_mymother = src C.enemies = enemies + var/datum/team/terror_spiders/spider_team = GLOB.antagonist_teams[/datum/team/terror_spiders] + if(mind) + spider_team?.terror_eggs |= C if(spider_growinstantly) C.amount_grown = 250 C.spider_growinstantly = TRUE @@ -185,68 +219,167 @@ /obj/structure/spider/eggcluster/terror_eggcluster name = "terror egg cluster" - desc = "A cluster of tiny spider eggs. They pulse with a strong inner life, and appear to have sharp thorns on the sides." + desc = "Скопление крошечных паучьих яиц. Они активно пульсируют и имеют острые шипы по бокам." + gender = PLURAL icon_state = "egg" max_integrity = 40 + grown_tick_count = 140 var/spider_growinstantly = FALSE var/mob/living/simple_animal/hostile/poison/terror_spider/queen/spider_myqueen = null var/mob/living/simple_animal/hostile/poison/terror_spider/spider_mymother = null - var/spiderling_type = null + var/mob/living/simple_animal/hostile/poison/terror_spider/spiderling_type = null var/spiderling_number = 1 var/list/enemies = list() + var/list/asigned_ghosts = list() + var/ghost_poll = FALSE /obj/structure/spider/eggcluster/terror_eggcluster/Initialize(mapload, lay_type) . = ..() GLOB.ts_egg_list += src spiderling_type = lay_type - + var/ru_prefix = "паука ужаса" switch(spiderling_type) if(/mob/living/simple_animal/hostile/poison/terror_spider/knight) name = "knight of terror eggs" + ru_prefix = "рыцаря ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/lurker) name = "lurker of terror eggs" + ru_prefix = "наблюдателя ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/healer) name = "healer of terror eggs" + ru_prefix = "лекаря ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/reaper) name = "reaper of terror eggs" + ru_prefix = "жнеца ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/builder) name = "builder of terror eggs" + ru_prefix = "дрона ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/widow) name = "widow of terror eggs" + ru_prefix = "вдовы ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/guardian) name = "guardian of terror eggs" + ru_prefix = "защитника ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/destroyer) name = "destroyer of terror eggs" + ru_prefix = "разрушителя ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/defiler) name = "defiler of terror eggs" + ru_prefix = "осквернителя ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/mother) name = "mother of terror eggs" + ru_prefix = "матери ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/prince) name = "prince of terror eggs" + ru_prefix = "принца ужаса" if(/mob/living/simple_animal/hostile/poison/terror_spider/queen) name = "queen of terror eggs" + ru_prefix = "королевы ужаса" + if(/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess) + name = "princess of terror eggs" + ru_prefix = "принцессы ужаса" + ru_names = list( + NOMINATIVE = "яйца [ru_prefix]", + GENITIVE = "яиц [ru_prefix]", + DATIVE = "яйцам [ru_prefix]", + ACCUSATIVE = "яйца [ru_prefix]", + INSTRUMENTAL = "яйцами [ru_prefix]", + PREPOSITIONAL = "яйцах [ru_prefix]" + ) /obj/structure/spider/eggcluster/terror_eggcluster/Destroy() GLOB.ts_egg_list -= src + var/datum/team/terror_spiders/spider_team = GLOB.antagonist_teams[/datum/team/terror_spiders] + spider_team?.terror_eggs -= src return ..() +/obj/structure/spider/eggcluster/terror_eggcluster/proc/find_spider_owner() + ghost_poll = TRUE + var/list/candidates = SSghost_spawns.poll_candidates("Вы хотите занять роль Паука Ужаса([spiderling_type.name])?", ROLE_TERROR_SPIDER, TRUE, TERROR_VOTE_LEN, source = spiderling_type, role_cleanname = "Паук Ужаса") + if(QDELETED(src)) + return FALSE + ghost_poll = FALSE + if(!length(candidates) || spider_mymother.spider_awaymission) + burst_eggs() + return FALSE + for(var/i = 0, i < spiderling_number, i++) + asigned_ghosts |= pick_n_take(candidates) + burst_eggs() + /obj/structure/spider/eggcluster/terror_eggcluster/process() amount_grown += 1 - if(amount_grown >= 140) //x2 time for egg process, spiderlings grows instantly - var/num = spiderling_number - playsound(src, 'sound/creatures/terrorspiders/eggburst.ogg', 100) - for(var/i=0, i= grown_tick_count && spider_mymother.spider_awaymission) //x2 time for egg process, spiderlings grows instantly + burst_eggs() + +/obj/structure/spider/eggcluster/terror_eggcluster/proc/burst_eggs() + var/num = spiderling_number + playsound(src, 'sound/creatures/terrorspiders/eggburst.ogg', 100) + for(var/i=0, i[src] moves towards the vent [entry_vent].") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] движется к вентиляционному отверстию [entry_vent.declent_ru(GENITIVE)].")) else path_to_vent = 0 else if(ai_break_lights && world.time > (last_break_light + freq_break_light)) @@ -142,14 +142,14 @@ L.on = 1 L.break_light_tube() do_attack_animation(L) - visible_message("[src] smashes the [L.name].") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] разбивает [L.declent_ru(ACCUSATIVE)].")) return else if(ai_spins_webs && web_type && world.time > (last_spins_webs + freq_spins_webs)) last_spins_webs = world.time var/obj/structure/spider/terrorweb/T = locate() in get_turf(src) if(!T) new web_type(loc) - visible_message("[src] puts up some spider webs.") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] плетёт паутину.")) else if(ai_ventcrawls && world.time > (last_ventcrawl_time + my_ventcrawl_freq)) if(prob(idle_ventcrawl_chance)) last_ventcrawl_time = world.time @@ -248,7 +248,7 @@ CreatePath(cocoon_target) step_to(src,cocoon_target) if(spider_debug) - visible_message("[src] moves towards [cocoon_target] to cocoon it.") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] движется к [cocoon_target.declent_ru(DATIVE)], чтобы заплести в кокон.")) /mob/living/simple_animal/hostile/poison/terror_spider/proc/seek_cocoon_target() last_cocoon_object = world.time @@ -287,7 +287,7 @@ try_open_airlock(A) for(var/obj/machinery/door/firedoor/F in view(1, src)) if(tgt_dir == get_dir(src,F) && F.density && !F.welded) - visible_message("[src] pries open the firedoor!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] открывает [F.declent_ru(ACCUSATIVE)]!")) F.open() else @@ -306,7 +306,7 @@ if(get_dist(src, entry_vent) <= 2) if(ai_ventbreaker && entry_vent.welded) entry_vent.set_welded(FALSE) - entry_vent.visible_message("[src] smashes the welded cover off [entry_vent]!") + entry_vent.visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] выбивает приваренную крышку [entry_vent.declent_ru(GENITIVE)]!")) var/list/vents = list() for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in entry_vent.parent.other_atmosmch) vents.Add(temp_vent) @@ -314,7 +314,7 @@ entry_vent = null return var/obj/machinery/atmospherics/unary/vent_pump/exit_vent = pick(vents) - visible_message("[src] scrambles into the ventillation ducts!", "You hear something squeezing through the ventilation ducts.") + visible_message("[capitalize(declent_ru(NOMINATIVE))] залезает в вентиляционные каналы!", span_notice("Слышно, как что-то сжимается в вентиляционных каналах.")) spawn(rand(20,60)) var/original_location = loc forceMove(exit_vent) @@ -325,7 +325,7 @@ entry_vent = null return if(prob(50)) - audible_message("You hear something squeezing through the ventilation ducts.") + audible_message(span_notice("Слышно, как что-то сжимается в вентиляционных каналах.")) spawn(travel_time) if(!exit_vent || (exit_vent.welded && !ai_ventbreaker)) forceMove(original_location) @@ -333,7 +333,7 @@ return if(ai_ventbreaker && exit_vent.welded) exit_vent.set_welded(FALSE) - exit_vent.visible_message("[src] smashes the welded cover off [exit_vent]!") + exit_vent.visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] выбивает приваренную крышку [exit_vent.declent_ru(GENITIVE)]!")) playsound(exit_vent.loc, 'sound/machines/airlock_alien_prying.ogg', 50, 0) forceMove(exit_vent.loc) entry_vent = null diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm index 9f5dda6e667..7951c744a2d 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm @@ -24,7 +24,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) icon_dead = "terror_red_dead" attacktext = "кусает" attack_sound = 'sound/creatures/terrorspiders/bite.ogg' - deathmessage = "Screams in pain and slowly stops moving." + deathmessage = "кричит от боли и медленно перестаёт двигаться." death_sound = 'sound/creatures/terrorspiders/death.ogg' damaged_sound = list('sound/creatures/spider_attack1.ogg', 'sound/creatures/spider_attack2.ogg') var/spider_intro_text = "Если ты это видишь, это баг." @@ -33,8 +33,8 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) emote_hear = list("hisses") tts_seed = "Anubarak" sentience_type = SENTIENCE_OTHER - response_help = "pets" - response_disarm = "gently pushes aside" + response_help = "гладит" + response_disarm = "осторожно отодвигает в сторону" friendly = "осторожно проводит лапками по" footstep_type = FOOTSTEP_MOB_CLAW talk_sound = list('sound/creatures/terrorspiders/speech_1.ogg', 'sound/creatures/terrorspiders/speech_2.ogg', 'sound/creatures/terrorspiders/speech_3.ogg', 'sound/creatures/terrorspiders/speech_4.ogg', 'sound/creatures/terrorspiders/speech_5.ogg', 'sound/creatures/terrorspiders/speech_6.ogg') @@ -138,6 +138,9 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) var/datum/action/innate/terrorspider/web/web_action var/datum/action/innate/terrorspider/wrap/wrap_action + // DATUM + var/datum_type = /datum/antagonist/terror_spider + // DEBUG OPTIONS & COMMANDS var/spider_growinstantly = FALSE var/spider_debug = FALSE @@ -169,29 +172,29 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) enemies -= target var/mob/living/simple_animal/hostile/poison/terror_spider/T = target if(T.spider_tier > spider_tier) - visible_message("[src] cowers before [target].") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] съёживается перед [target.declent_ru(INSTRUMENTAL)].")) else if(T.spider_tier == spider_tier) - visible_message("[src] nuzzles [target].") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] тычется носом в [target.declent_ru(ACCUSATIVE)].")) else if(T.spider_tier < spider_tier && spider_tier >= 4) target.attack_animal(src) else - visible_message("[src] harmlessly nuzzles [target].") + visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] безобидно тычет носом [target.declent_ru(ACCUSATIVE)].")) T.CheckFaction() CheckFaction() else if(istype(target, /obj/structure/spider/royaljelly)) consume_jelly(target) else if(istype(target, /obj/structure/spider)) // Prevents destroying coccoons (exploit), eggs (horrible misclick), etc - to_chat(src, "Destroying things created by fellow spiders would not help us.") + to_chat(src, "Уничтожение вещей, созданных другими пауками, нам не поможет.") else if(istype(target, /obj/machinery/door/firedoor)) var/obj/machinery/door/firedoor/F = target if(F.density) if(F.welded) - to_chat(src, "The fire door is welded shut.") + to_chat(src, "[capitalize(F.declent_ru(NOMINATIVE))] заварен.") else - visible_message("[src] pries open the firedoor!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] открывает [F.declent_ru(ACCUSATIVE)]!")) F.open() else - to_chat(src, "Closing fire doors does not help.") + to_chat(src, "Закрытие противопожарных дверей не помогает.") else if(istype(target, /obj/machinery/door/airlock)) var/obj/machinery/door/airlock/A = target try_open_airlock(A) @@ -217,9 +220,9 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) /mob/living/simple_animal/hostile/poison/terror_spider/proc/consume_jelly(obj/structure/spider/royaljelly/J) if(health == maxHealth) - to_chat(src, "You don't need healing!") + to_chat(src, span_warning("Вам не нужно лечиться!")) return - to_chat(src, "You consume royal jelly to heal yourself!") + to_chat(src, span_notice("Вы употребляете королевское желе, чтобы исцелить себя!")) playsound(src.loc, 'sound/creatures/terrorspiders/jelly.ogg', 100, 1) apply_status_effect(STATUS_EFFECT_TERROR_REGEN) qdel(J) @@ -232,19 +235,19 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) . = ..() if(stat != DEAD) if(key) - . += "[p_they(TRUE)] regards [p_their()] surroundings with a curious intelligence." + . += span_warning("Внимательно осматривает окружение взглядом, говорящем о признаках разумности.") if(health > (maxHealth*0.95)) - . += "[p_they(TRUE)] is in excellent health." + . += span_notice("Не имеет видимых повреждений.") else if(health > (maxHealth*0.75)) - . += "[p_they(TRUE)] has a few injuries." + . += span_notice("Имеет несколько царапин.") else if(health > (maxHealth*0.55)) - . += "[p_they(TRUE)] has many injuries." + . += span_warning("Имеет серьёзные травмы.") else if(health > (maxHealth*0.25)) - . += "[p_they(TRUE)] is barely clinging on to life!" - if(degenerate) - . += "[p_they(TRUE)] appears to be dying." + . += span_danger("Едва стоит на своих лапах!") + if(degenerate || !spider_awaymission && GLOB.global_degenerate) + . += span_danger("Находится на грани жизни и смерти.") if(killcount >= 1) - . += "[p_they(TRUE)] has blood dribbling from [p_their()] mouth." + . += span_warning("Разбрызгивает во все стороны алую кровь, струяющуюся из пасти.") /mob/living/simple_animal/hostile/poison/terror_spider/New() ..() @@ -265,7 +268,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) wrap_action.Grant(src) name += " ([rand(1, 1000)])" real_name = name - msg_terrorspiders("[src] has grown in [get_area(src)].") + msg_terrorspiders("[capitalize(declent_ru(NOMINATIVE))] вырастает в локации \"[get_area(src)]\".") if(is_away_level(z)) spider_awaymission = 1 GLOB.ts_count_alive_awaymission++ @@ -292,10 +295,10 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) if(stat == DEAD) return if(ckey) - notify_ghosts("[src] (player controlled) has appeared in [get_area(src)].") + notify_ghosts("[capitalize(declent_ru(NOMINATIVE))] (контролируется игроком) появляется в локации \"[get_area(src)]\".") else if(ai_playercontrol_allowtype) - var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state) - notify_ghosts("[src] has appeared in [get_area(src)].", enter_link = "(Click to control)", source = src, alert_overlay = alert_overlay, action = NOTIFY_ATTACK) + var/image/alert_overlay = image(icon, icon_state) + notify_ghosts("[capitalize(declent_ru(NOMINATIVE))] появляется в локации \"[get_area(src)]\".", enter_link = "(Нажмите для взятия контроля)", source = src, alert_overlay = alert_overlay, action = NOTIFY_ATTACK) /mob/living/simple_animal/hostile/poison/terror_spider/Destroy() GLOB.ts_spiderlist -= src @@ -307,12 +310,12 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) if(stat == DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive. if(prob(10)) // 10% chance every cycle to decompose - visible_message("\The dead body of the [src] decomposes!") + visible_message(span_notice("Труп [declent_ru(GENITIVE)] разлагается!")) gib() else if(health < maxHealth) adjustBruteLoss(-regeneration) - if(degenerate) + if(degenerate || !spider_awaymission && GLOB.global_degenerate) adjustBruteLoss(6) if(prob(5)) CheckFaction() @@ -327,17 +330,13 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) else GLOB.ts_count_alive_station-- -/mob/living/simple_animal/hostile/poison/terror_spider/proc/give_intro_text() - to_chat(src, "
Вы паук ужаса!
") - to_chat(src, "
Работайте сообща, помогайте своим братьям и сёстрам, саботируйте станцию, убивайте экипаж, превратите это место в своё гнездо!
") - to_chat(src, "
[spider_intro_text]

") - SEND_SOUND(src, sound('sound/ambience/antag/terrorspider.ogg')) - /mob/living/simple_animal/hostile/poison/terror_spider/death(gibbed) if(can_die()) if(!gibbed) - msg_terrorspiders("[src] has died in [get_area(src)].") + msg_terrorspiders("[capitalize(declent_ru(NOMINATIVE))] умирает в локации \"[get_area(src)]\".") handle_dying() + if(mind) + SEND_SIGNAL(mind, COMSIG_TERROR_SPIDER_DIED) return ..() /mob/living/simple_animal/hostile/poison/terror_spider/proc/spider_special_action() @@ -363,7 +362,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) /mob/living/simple_animal/hostile/poison/terror_spider/proc/CheckFaction() if(faction.len != 2 || (!("terrorspiders" in faction)) || master_commander != null) - to_chat(src, "Your connection to the hive mind has been severed!") + to_chat(src, span_userdanger("Ваша связь с коллективным разумом разрывается!")) log_runtime(EXCEPTION("Terror spider with incorrect faction list at: [atom_loc_line(src)]")) gib() @@ -371,9 +370,9 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) if(D.operating) return if(D.welded) - to_chat(src, "The door is welded.") + to_chat(src, span_warning("Дверь заварена.")) else if(D.locked) - to_chat(src, "The door is bolted.") + to_chat(src, span_warning("Дверь заболтирована.")) else if(D.allowed(src)) if(D.density) D.open(TRUE) @@ -381,11 +380,11 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) D.close(TRUE) return TRUE else if(D.arePowerSystemsOn() && (spider_opens_doors != 2)) - to_chat(src, "The door's motors resist your efforts to force it.") + to_chat(src, span_warning("Привод шлюза сопротивляется вашим попыткам взломать её.")) else if(!spider_opens_doors) - to_chat(src, "Your type of spider is not strong enough to force open doors.") + to_chat(src, span_warning("Вы недостаточно сильны, чтобы взломать шлюз.")) else - visible_message("[src] forces the door!") + visible_message(span_danger("[capitalize(declent_ru(NOMINATIVE))] открывает дверь силой!")) playsound(src.loc, "sparks", 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) if(D.density) D.open(TRUE) @@ -406,19 +405,19 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) var/list/status_tab_data = ..() . = status_tab_data if(ckey && stat == CONSCIOUS) - if(degenerate) - status_tab_data[++status_tab_data.len] = list("Link:", "Hivemind Connection Severed! Dying...") // color=red + if(degenerate || !spider_awaymission && GLOB.global_degenerate) + status_tab_data[++status_tab_data.len] = list("Связь:", "Связь с Коллективным разумом разорвана! Смерть..") // color=red /mob/living/simple_animal/hostile/poison/terror_spider/proc/DoRemoteView() if(!isturf(loc)) // This check prevents spiders using this ability while inside an atmos pipe, which will mess up their vision - to_chat(src, "You must be standing on a floor to do this.") + to_chat(src, span_warning("Для этого вам необходимо стоять на полу.")) return if(client && (client.eye != client.mob)) reset_perspective() return if(health <= (maxHealth*0.75)) - to_chat(src, "You must be at full health to do this!") + to_chat(src, span_warning("Для этого вы должны быть полностью здоровы!")) return var/list/targets = list() targets += src // ensures that self is always at top of the list @@ -429,7 +428,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) if(T.spider_awaymission != spider_awaymission) continue targets |= T // we use |= instead of += to avoid adding src to the list twice - var/mob/living/L = input("Choose a terror to watch.", "Selection") in targets + var/mob/living/L = tgui_input_list(usr, "Выберите Паука Ужаса для просмотра.", "Выбор", targets) if(istype(L)) reset_perspective(L) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/widow.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/widow.dm index cfe298d286c..97431745c2d 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/widow.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/widow.dm @@ -10,7 +10,15 @@ /mob/living/simple_animal/hostile/poison/terror_spider/widow name = "Widow of Terror" - desc = "An ominous-looking spider, black as the darkest night. It has merciless eyes, and a blood-red hourglass pattern on its back." + desc = "Зловещий паук, черный, как самая темная ночь. У него безжалостные глаза и кроваво-красный узор в виде песочных часов на спине." + ru_names = list( + NOMINATIVE = "Вдова Ужаса", + GENITIVE = "Вдовы Ужаса", + DATIVE = "Вдове Ужаса", + ACCUSATIVE = "Вдову Ужаса", + INSTRUMENTAL = "Вдовой Ужаса", + PREPOSITIONAL = "Вдове Ужаса", + ) ai_target_method = TS_DAMAGE_POISON icon_state = "terror_widow" icon_living = "terror_widow" @@ -55,14 +63,22 @@ /obj/structure/spider/terrorweb/widow name = "sinister web" - desc = "This web has beads of a dark fluid on its strands." + desc = "На нитях этой паутины сверкают капли тёмной жидкости." + ru_names = list( + NOMINATIVE = "зловещая паутина", + GENITIVE = "зловещей паутины", + DATIVE = "зловещей паутине", + ACCUSATIVE = "зловещую паутину", + INSTRUMENTAL = "зловещей паутиной", + PREPOSITIONAL = "зловещей паутине", + ) /obj/structure/spider/terrorweb/widow/web_special_ability(mob/living/carbon/C) if(istype(C)) if(!C.reagents.has_reagent("terror_black_toxin", 60)) var/inject_target = pick(BODY_ZONE_CHEST, BODY_ZONE_HEAD) if(C.can_inject(null, FALSE, inject_target, FALSE)) - to_chat(C, "[src] slices into you!") + to_chat(C, span_danger("[capitalize(declent_ru(NOMINATIVE))] врезается в тебя!")) C.reagents.add_reagent("terror_black_toxin", 45) /obj/item/projectile/terrorspider/widow diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 56b34ff48c0..42979b8c319 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -224,10 +224,15 @@ */ if(SHUTTLE_DOCKED) - if(time_left <= 0 && SSshuttle.emergencyNoEscape) + if(time_left <= 0 && SSshuttle.hostile_environment.len) GLOB.priority_announcement.Announce("Обнаружена угроза. Отлёт отложен на неопределённый срок до разрешения конфликта.") sound_played = 0 mode = SHUTTLE_STRANDED + + if(time_left <= 0 && SSshuttle.emergencyNoEscape && mode != SHUTTLE_STRANDED) + GLOB.priority_announcement.Announce("Шаттл заблокирован. Свяжитесь с Центральным Командованием для уточнения причин и снятия блокировки.") + sound_played = 0 + mode = SHUTTLE_STRANDED if(time_left <= 100) // 9 seconds left - start requesting transit zones for emergency and pods for(var/obj/docking_port/mobile/pod/M in SSshuttle.mobile) @@ -239,7 +244,7 @@ for(var/area/shuttle/escape/E in GLOB.areas) E << 'sound/effects/hyperspace_begin_new.ogg' - if(time_left <= 0 && !SSshuttle.emergencyNoEscape) + if(time_left <= 0 && !(SSshuttle.emergencyNoEscape || SSshuttle.hostile_environment.len)) //move each escape pod to its corresponding transit dock for(var/obj/docking_port/mobile/pod/M in SSshuttle.mobile) if(is_station_level(M.z)) //Will not launch from the mine/planet diff --git a/code/modules/surgery/organs/parasites.dm b/code/modules/surgery/organs/parasites.dm index 1f6b229e424..e563c836990 100644 --- a/code/modules/surgery/organs/parasites.dm +++ b/code/modules/surgery/organs/parasites.dm @@ -54,13 +54,16 @@ var/eggs_hatched = 0 // num of hatch events completed var/awaymission_checked = FALSE var/awaymission_infection = FALSE // TRUE if infection occurred inside gateway - + var/mob/asigned_ghost + var/ghost_poll = FALSE /obj/item/organ/internal/body_egg/terror_eggs/on_life() // Safety first. if(!owner) return - + if(GLOB.global_degenerate && !awaymission_infection && !QDELETED(src)) + qdel(src) + return // Parasite growth cycle_num += 1 egg_progress += 1 @@ -71,17 +74,32 @@ awaymission_checked = TRUE if(is_away_level(owner.z)) awaymission_infection = TRUE + else + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_IFECTION_CREATED, src) if(awaymission_infection) var/turf/T = get_turf(owner) if(istype(T) && !is_away_level(T.z)) owner.gib() qdel(src) return + if(egg_progress_per_hatch - egg_progress <= TERROR_VOTE_TICKS && !ghost_poll && !awaymission_infection) + find_spider_owner() - if(egg_progress > egg_progress_per_hatch) - egg_progress -= egg_progress_per_hatch + if(egg_progress > egg_progress_per_hatch && awaymission_infection) hatch_egg() +/obj/item/organ/internal/body_egg/terror_eggs/proc/find_spider_owner() + ghost_poll = TRUE + var/list/candidates = SSghost_spawns.poll_candidates("Вы хотите занять роль Паука Ужаса?", ROLE_TERROR_SPIDER, TRUE, TERROR_VOTE_LEN, , role_cleanname = "Паук Ужаса") + if(QDELETED(src)) + return + ghost_poll = FALSE + if(!length(candidates) || awaymission_infection) + hatch_egg() + return + asigned_ghost = pick_n_take(candidates) + hatch_egg() + /obj/item/organ/internal/body_egg/terror_eggs/proc/calc_variable_progress() var/extra_progress = 0 if(owner.nutrition > NUTRITION_LEVEL_FULL) @@ -96,6 +114,7 @@ /obj/item/organ/internal/body_egg/terror_eggs/proc/hatch_egg() var/infection_completed = FALSE + egg_progress -= egg_progress_per_hatch var/obj/structure/spider/spiderling/terror_spiderling/S = new(get_turf(owner)) switch(eggs_hatched) if(0) // 1st spiderling @@ -108,6 +127,7 @@ owner.death() infection_completed = TRUE S.immediate_ventcrawl = TRUE + S.asigned_ghost = asigned_ghost eggs_hatched++ owner.adjustBruteLoss(80) owner.Paralyse(20 SECONDS) @@ -119,6 +139,7 @@ /obj/item/organ/internal/body_egg/terror_eggs/remove(mob/living/carbon/M, special = ORGAN_MANIPULATION_DEFAULT) ..() + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_IFECTION_REMOVED, src) if(!QDELETED(src)) qdel(src) // prevent people re-implanting them into others return null diff --git a/icons/effects/weather_effects.dmi b/icons/effects/weather_effects.dmi index 7cc1ce758a3..bb5d3f69d86 100644 Binary files a/icons/effects/weather_effects.dmi and b/icons/effects/weather_effects.dmi differ diff --git a/icons/mob/actions/actions.dmi b/icons/mob/actions/actions.dmi index 8170c7a2713..0a77c58563a 100644 Binary files a/icons/mob/actions/actions.dmi and b/icons/mob/actions/actions.dmi differ diff --git a/paradise.dme b/paradise.dme index 557864d2d87..d14e5a2df77 100644 --- a/paradise.dme +++ b/paradise.dme @@ -148,6 +148,7 @@ #include "code\__DEFINES\strippable_defines.dm" #include "code\__DEFINES\subsystems.dm" #include "code\__DEFINES\surgery_defines.dm" +#include "code\__DEFINES\terror_spiders.dm" #include "code\__DEFINES\text.dm" #include "code\__DEFINES\tgs.dm" #include "code\__DEFINES\tgui_defines.dm" @@ -160,6 +161,7 @@ #include "code\__DEFINES\verb_manager.dm" #include "code\__DEFINES\vv.dm" #include "code\__DEFINES\wires.dm" +#include "code\__DEFINES\xenomorphs.dm" #include "code\__DEFINES\zlevel.dm" #include "code\__DEFINES\dcs\flags.dm" #include "code\__DEFINES\dcs\helpers.dm" @@ -754,6 +756,8 @@ #include "code\datums\weather\weather_types\radiation_storm.dm" #include "code\datums\weather\weather_types\snow_storm.dm" #include "code\datums\weather\weather_types\solar_flare.dm" +#include "code\datums\weather\weather_types\web_storm.dm" +#include "code\datums\weather\weather_types\xeno_storm.dm" #include "code\datums\wires\airlock.dm" #include "code\datums\wires\alarm.dm" #include "code\datums\wires\apc.dm" @@ -1806,6 +1810,10 @@ #include "code\modules\antagonists\space_ninja\suit\ninja_equipment_actions\ninja_suit_initialisation.dm" #include "code\modules\antagonists\space_ninja\suit\ninja_equipment_actions\ninja_sword_recall.dm" #include "code\modules\antagonists\survivalist\survivalist.dm" +#include "code\modules\antagonists\terror_spiders\_terror_spider.dm" +#include "code\modules\antagonists\terror_spiders\spider_team.dm" +#include "code\modules\antagonists\terror_spiders\terror_spider_actions.dm" +#include "code\modules\antagonists\terror_spiders\terror_spider_objectives.dm" #include "code\modules\antagonists\thief\thief_datum.dm" #include "code\modules\antagonists\thief\thief_kit.dm" #include "code\modules\antagonists\traitor\datum_mindslave.dm" @@ -1845,6 +1853,10 @@ #include "code\modules\antagonists\vampire\vampire_powers\umbrae_powers.dm" #include "code\modules\antagonists\vampire\vampire_powers\vampire_powers.dm" #include "code\modules\antagonists\wishgranter\wishgranter.dm" +#include "code\modules\antagonists\xenomorth\xenomorph.dm" +#include "code\modules\antagonists\xenomorth\xenomorph_actions.dm" +#include "code\modules\antagonists\xenomorth\xenomorph_objectives.dm" +#include "code\modules\antagonists\xenomorth\xenomorph_team.dm" #include "code\modules\arcade\arcade_base.dm" #include "code\modules\arcade\arcade_prize.dm" #include "code\modules\arcade\claw_game.dm" @@ -2819,7 +2831,6 @@ #include "code\modules\mob\living\simple_animal\hostile\retaliate\pet.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\undead.dm" -#include "code\modules\mob\living\simple_animal\hostile\terror_spiders\__defines.dm" #include "code\modules\mob\living\simple_animal\hostile\terror_spiders\abillities.dm" #include "code\modules\mob\living\simple_animal\hostile\terror_spiders\actions.dm" #include "code\modules\mob\living\simple_animal\hostile\terror_spiders\builder.dm"