diff --git a/SQL/database_changelog.txt b/SQL/database_changelog.txt index b9636784fc8b..98200d21b1d4 100644 --- a/SQL/database_changelog.txt +++ b/SQL/database_changelog.txt @@ -1,13 +1,28 @@ Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255. -The latest database version is 5.6; The query to update the schema revision table is: +The latest database version is 5.10; The query to update the schema revision table is: -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 9); +INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 10); or -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 9); +INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 10); In any query remember to add a prefix to the table names if you use one. +version 5.10 2022-05-18, alexkar598 +Adds credentials binding + +CREATE TABLE `bound_credentials` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `ckey` varchar(32) NOT NULL, + `computerid` varchar(32) DEFAULT NULL, + `ip` int(10) unsigned DEFAULT NULL, + `flags` set('bypass_bans') DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_ckey_lookup` (`ckey`), + KEY `idx_cid_lookup` (`computerid`), + KEY `idx_ip_lookup` (`ip`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + version 5.9 23 November 2021, by adamsogm Adds the datetime column to the primary key for the MFA table diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index 19dc029cf724..f6e3eeece052 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -116,6 +116,19 @@ CREATE TABLE IF NOT EXISTS `ban` ( ) ENGINE=InnoDB AUTO_INCREMENT=39587 DEFAULT CHARSET=utf8; +DROP TABLE IF EXISTS `bound_credentials`; +CREATE TABLE `bound_credentials` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `ckey` varchar(32) NOT NULL, + `computerid` varchar(32) DEFAULT NULL, + `ip` int(10) unsigned DEFAULT NULL, + `flags` set('bypass_bans') DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_ckey_lookup` (`ckey`), + KEY `idx_cid_lookup` (`computerid`), + KEY `idx_ip_lookup` (`ip`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + DROP TABLE IF EXISTS `connection_log`; CREATE TABLE IF NOT EXISTS `connection_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql index 057947cd58b4..de658b319467 100644 --- a/SQL/tgstation_schema_prefixed.sql +++ b/SQL/tgstation_schema_prefixed.sql @@ -116,6 +116,18 @@ CREATE TABLE IF NOT EXISTS `SS13_ban` ( KEY `idx_ban_count` (`bantime`,`a_ckey`,`applies_to_admins`,`unbanned_datetime`,`expiration_time`) ) ENGINE=InnoDB AUTO_INCREMENT=39587 DEFAULT CHARSET=utf8; +DROP TABLE IF EXISTS `SS13_bound_credentials`; +CREATE TABLE `SS13_bound_credentials` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `ckey` varchar(32) NOT NULL, + `computerid` varchar(32) DEFAULT NULL, + `ip` int(10) unsigned DEFAULT NULL, + `flags` set('bypass_bans') DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `idx_ckey_lookup` (`ckey`), + KEY `idx_cid_lookup` (`computerid`), + KEY `idx_ip_lookup` (`ip`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `SS13_connection_log`; CREATE TABLE IF NOT EXISTS `SS13_connection_log` ( diff --git a/_maps/map_files/YogStation/YogStation.dmm b/_maps/map_files/YogStation/YogStation.dmm index 220aa0461c73..d614c14c3382 100644 --- a/_maps/map_files/YogStation/YogStation.dmm +++ b/_maps/map_files/YogStation/YogStation.dmm @@ -25012,6 +25012,13 @@ }, /turf/open/floor/plasteel, /area/hallway/primary/central) +"cCz" = ( +/obj/machinery/light{ + dir = 8 + }, +/obj/machinery/suit_storage_unit/captain, +/turf/open/floor/wood, +/area/crew_quarters/heads/captain) "cCF" = ( /obj/machinery/air_sensor{ id_tag = "n2o_sensor" @@ -29005,6 +29012,16 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/plasteel/white, /area/medical/virology) +"eGj" = ( +/obj/item/radio/intercom{ + dir = 8; + freerange = 1; + name = "Station Intercom (Command)"; + pixel_x = -28 + }, +/obj/structure/filingcabinet, +/turf/open/floor/wood, +/area/crew_quarters/heads/captain) "eGz" = ( /obj/item/radio/intercom{ name = "Station Intercom (General)"; @@ -31087,16 +31104,6 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/dorms) -"fNu" = ( -/obj/item/radio/intercom{ - dir = 8; - freerange = 1; - name = "Station Intercom (Command)"; - pixel_x = -28 - }, -/obj/machinery/suit_storage_unit/captain, -/turf/open/floor/wood, -/area/crew_quarters/heads/captain) "fNw" = ( /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ dir = 10 @@ -39967,6 +39974,14 @@ }, /turf/open/floor/plasteel/freezer, /area/crew_quarters/toilet/locker) +"kgY" = ( +/obj/machinery/recharger/wallrecharger{ + pixel_x = -21; + pixel_y = -3 + }, +/obj/machinery/papershredder, +/turf/open/floor/wood, +/area/crew_quarters/heads/captain) "khm" = ( /obj/effect/turf_decal/stripes, /obj/structure/railing/corner, @@ -60467,14 +60482,6 @@ /obj/item/book/manual/wiki/surgery, /turf/open/floor/plasteel/white, /area/medical/surgery) -"urw" = ( -/obj/structure/filingcabinet, -/obj/machinery/recharger/wallrecharger{ - pixel_x = -21; - pixel_y = -3 - }, -/turf/open/floor/wood, -/area/crew_quarters/heads/captain) "urG" = ( /obj/structure/closet/emcloset, /obj/machinery/atmospherics/components/unary/vent_pump/layer2{ @@ -62673,13 +62680,6 @@ /obj/effect/turf_decal/trimline/blue/filled/corner, /turf/open/floor/plasteel/white, /area/medical/storage) -"vCQ" = ( -/obj/machinery/light{ - dir = 8 - }, -/obj/machinery/papershredder, -/turf/open/floor/wood, -/area/crew_quarters/heads/captain) "vCX" = ( /obj/structure/janitorialcart, /obj/effect/turf_decal/delivery, @@ -98907,10 +98907,10 @@ aZV fqv ruZ nCL -vCQ +cCz wxL -urw -fNu +kgY +eGj aZV aZV aZV diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index b86c64771bb0..a78ed06ec1ee 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -32,10 +32,17 @@ /// blob gets a free reroll every X time #define BLOB_REROLL_TIME 2400 #define BLOB_SPREAD_COST 4 +#define OVERMIND_STARTING_AUTO_PLACE_TIME 6 MINUTES /// blob refunds this much if it attacks and doesn't spread #define BLOB_ATTACK_REFUND 2 #define BLOB_REFLECTOR_COST 15 +/// Forces the blob to place the core where they currently are, ignoring any checks. +#define BLOB_FORCE_PLACEMENT -1 +/// Normal blob placement, does the regular checks to make sure the blob isn't placing itself in an invalid location +#define BLOB_NORMAL_PLACEMENT 0 +/// Selects a random location for the blob to be placed. +#define BLOB_RANDOM_PLACEMENT 1 //ERT Types #define ERT_BLUE "Blue" diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index c51cb4aa953a..f23e64b6ef19 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -60,6 +60,8 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 /// Blocks ruins spawning on the turf #define NO_RUINS_1 (1<<10) +/// If blobs can spawn there and if it counts towards their score. +#define BLOBS_ALLOWED (1<<1) /* These defines are used specifically with the atom/pass_flags bitmask the atom/checkpass() proc uses them (tables will call movable atom checkpass(PASSTABLE) for example) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 6b68b5783364..b1aa07a34b97 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -21,7 +21,7 @@ * make sure you add an update to the schema_version stable in the db changelog */ -#define DB_MINOR_VERSION 9 +#define DB_MINOR_VERSION 10 //! ## Timing subsystem /** diff --git a/code/__DEFINES/{yogs_defines}/mobs.dm b/code/__DEFINES/{yogs_defines}/mobs.dm index 2a3c925f4581..93d471d69db0 100644 --- a/code/__DEFINES/{yogs_defines}/mobs.dm +++ b/code/__DEFINES/{yogs_defines}/mobs.dm @@ -18,4 +18,6 @@ #define DARKSPAWN_BRIGHT_LIGHT 0.3 //light of this intensity causes rapid burn damage #define DARKSPAWN_DARK_HEAL 5 //how much damage of each type (with fire damage half rate) is healed in the dark -#define DARKSPAWN_LIGHT_BURN 7 //how much damage the darkspawn receives per tick in lit areas \ No newline at end of file +#define DARKSPAWN_LIGHT_BURN 7 //how much damage the darkspawn receives per tick in lit areas + +#define MONKIFY_BLOOD_COEFFICIENT (BLOOD_VOLUME_MONKEY/BLOOD_VOLUME_GENERIC) //the ratio of monkey to human blood volume so a 100% blood volume monkey will not instantly die when you turn it into a human with ~58% blood volume diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 572a75459647..95dda12cb3ce 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -241,9 +241,9 @@ If you're feeling frisky, examine yourself and click the underlined item to pull icon_state = "embeddedobject" /obj/screen/alert/embeddedobject/Click() - if(isliving(usr)) - var/mob/living/carbon/human/M = usr - return M.help_shake_act(M) + if(iscarbon(usr)) + var/mob/living/carbon/C = usr + return C.try_remove_embedded_object(C) /obj/screen/alert/weightless name = "Weightless" diff --git a/code/_onclick/hud/blob_overmind.dm b/code/_onclick/hud/blob_overmind.dm index 07cd76acdabd..5e352112f26b 100644 --- a/code/_onclick/hud/blob_overmind.dm +++ b/code/_onclick/hud/blob_overmind.dm @@ -48,7 +48,7 @@ if(isovermind(usr)) var/mob/camera/blob/B = usr if(!B.placed) - B.place_blob_core(0) + B.place_blob_core(BLOB_NORMAL_PLACEMENT) B.transport_core() /obj/screen/blob/Blobbernaut diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm index ca4f7f2c7610..33e7b62ebb35 100644 --- a/code/datums/components/crafting/recipes.dm +++ b/code/datums/components/crafting/recipes.dm @@ -371,7 +371,7 @@ name = "Depleted Uranium Slug Shell" result = /obj/item/ammo_casing/shotgun/uraniumpenetrator reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1, - /datum/material/uranium = 3, + /obj/item/stack/sheet/mineral/uranium = 3, /obj/item/stack/rods = 2, /datum/reagent/thermite = 5) tools = list(TOOL_SCREWDRIVER) diff --git a/code/datums/diseases/plague.dm b/code/datums/diseases/plague.dm new file mode 100644 index 000000000000..ea12611cc456 --- /dev/null +++ b/code/datums/diseases/plague.dm @@ -0,0 +1,54 @@ +/datum/disease/plague + form = "Disease" + name = "Plague" + max_stages = 5 + spread_text = "Airborne" + cure_text = "Spaceacillin" + cures = list(/datum/reagent/medicine/spaceacillin) + agent = "Plague rats" + viable_mobtypes = list(/mob/living/carbon/human) + cure_chance = 20 + desc = "A deadly disease, spread by infected animals and insects. It causes fever, weakness, headache and choking." + required_organs = list(/obj/item/organ/lungs) + severity = DISEASE_SEVERITY_BIOHAZARD + bypasses_immunity = TRUE + +/datum/disease/tuberculosis/stage_act() + ..() + switch(stage) + if(2) + if(prob(2)) + affected_mob.emote("cough") + to_chat(affected_mob, span_danger("Your chest hurts.")) + if(prob(2)) + to_chat(affected_mob, span_danger("Your head pounds.")) + if(4) + if(prob(2)) + to_chat(affected_mob, span_userdanger("You can't keep steady!")) + affected_mob.Dizzy(5) + if(prob(2)) + to_chat(affected_mob, span_danger("You can barely breathe!")) + affected_mob.adjustOxyLoss(5) + affected_mob.emote("gasp") + if(prob(10)) + to_chat(affected_mob, span_danger("You can't breathe!")) + affected_mob.adjustOxyLoss(20) + affected_mob.emote("gasp") + if(prob(2)) + to_chat(affected_mob, span_danger("You feel weak!")) + affected_mob.adjustStaminaLoss(40) + if(5) + if(prob(10)) + affected_mob.vomit(20) + if(prob(15)) + affected_mob.adjust_bodytemperature(30) + to_chat(affected_mob, span_danger("You feel hot!")) + if(prob(2)) + to_chat(affected_mob, span_danger("You feel very weak!")) + affected_mob.adjustStaminaLoss(100) + if(prob(6)) + to_chat(affected_mob, span_danger("Your lungs feel full of fluid! You're unable to breathe!")) + affected_mob.adjustOxyLoss(35) + affected_mob.emote("gasp") + return + diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index 0c313b35005e..463021d82c03 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -92,14 +92,18 @@ /datum/mutation/human/dwarfism/on_acquiring(mob/living/carbon/human/owner) if(..()) return - owner.transform = owner.transform.Scale(1, 0.8) + var/matrix/new_transform = matrix() + new_transform.Scale(1, 0.8) + owner.transform = new_transform.Multiply(owner.transform) passtable_on(owner, GENETIC_MUTATION) owner.visible_message(span_danger("[owner] suddenly shrinks!"), span_notice("Everything around you seems to grow..")) /datum/mutation/human/dwarfism/on_losing(mob/living/carbon/human/owner) if(..()) return - owner.transform = owner.transform.Scale(1, 1.25) + var/matrix/new_transform = matrix() + new_transform.Scale(1, 1.25) + owner.transform = new_transform.Multiply(owner.transform) passtable_off(owner, GENETIC_MUTATION) owner.visible_message(span_danger("[owner] suddenly grows!"), span_notice("Everything around you seems to shrink..")) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index d079055c9e59..98c4410e2f70 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -493,7 +493,7 @@ . = FALSE if(destination) var/turf/new_turf = get_turf(destination) - if(ismob(src)) + if(new_turf && ismob(src)) var/mob/M = src if(is_secret_level(new_turf.z) && !M.client?.holder) return diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index 349af313f67f..2303efc70016 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -361,7 +361,7 @@ enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") required_enemies = list(2,2,1,1,1,1,1,0,0,0) required_candidates = 1 - weight = 4 + weight = 2 cost = 10 requirements = list(100,100,100,80,60,50,45,30,20,20) repeatable = TRUE @@ -370,6 +370,41 @@ var/body = applicant.become_overmind() return body +// Infects a random player, making them explode into a blob. +/datum/dynamic_ruleset/midround/blob_infection + name = "Blob Infection" + antag_datum = /datum/antagonist/blob + antag_flag = ROLE_BLOB + protected_roles = list("Prisoner", "Security Officer", "Warden", "Detective", "Head of Security", "Captain") + restricted_roles = list("Cyborg", "AI", "Positronic Brain") + enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 2 + cost = 10 + requirements = list(101,101,101,80,60,50,30,20,10,10) + repeatable = TRUE + +/datum/dynamic_ruleset/midround/blob_infection/trim_candidates() + ..() + candidates = living_players + for(var/mob/living/player as anything in candidates) + var/turf/player_turf = get_turf(player) + if(!player_turf || !is_station_level(player_turf.z)) + candidates -= player + continue + + if(player.mind && (player.mind.special_role || length(player.mind.antag_datums) > 0)) + candidates -= player + +/datum/dynamic_ruleset/midround/blob_infection/execute() + if(!candidates || !candidates.len) + return FALSE + var/mob/living/carbon/human/blob_antag = pick_n_take(candidates) + assigned += blob_antag.mind + blob_antag.mind.special_role = antag_flag + return ..() + ////////////////////////////////////////////// // // // XENOMORPH (GHOST) // @@ -653,3 +688,109 @@ message_admins("[ADMIN_LOOKUPFLW(selected_mobs)] was selected by the [name] ruleset and has been made into a midround Bloodsucker.") log_game("DYNAMIC: [key_name(selected_mobs)] was selected by the [name] ruleset and has been made into a midround Bloodsucker.") return TRUE + +/// Revenant ruleset +/datum/dynamic_ruleset/midround/from_ghosts/revenant + name = "Revenant" + antag_datum = /datum/antagonist/revenant + antag_flag = "Revenant" + antag_flag_override = ROLE_REVENANT + enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 4 + cost = 10 + requirements = list(101,101,101,70,50,40,20,15,10,10) + repeatable = TRUE + var/dead_mobs_required = 20 + var/need_extra_spawns_value = 15 + var/list/spawn_locs = list() + + +/datum/dynamic_ruleset/midround/from_ghosts/revenant/acceptable(population=0, threat=0) + if(GLOB.dead_mob_list.len < dead_mobs_required) + return FALSE + return ..() + +/datum/dynamic_ruleset/midround/from_ghosts/revenant/execute() + for(var/mob/living/corpse in GLOB.dead_mob_list) //look for any dead bodies + var/turf/corpse_turf = get_turf(corpse) + if(corpse_turf && is_station_level(corpse_turf.z)) + spawn_locs += corpse_turf + if(!spawn_locs.len || spawn_locs.len < need_extra_spawns_value) //look for any morgue trays, crematoriums, ect if there weren't alot of dead bodies on the station to pick from + for(var/obj/structure/bodycontainer/corpse_container in GLOB.bodycontainers) + var/turf/container_turf = get_turf(corpse_container) + if(container_turf && is_station_level(container_turf.z)) + spawn_locs += container_turf + if(!spawn_locs.len) //If we can't find any valid spawnpoints, try the carp spawns + for(var/obj/effect/landmark/carpspawn/carp_spawnpoint in GLOB.landmarks_list) + if(isturf(carp_spawnpoint.loc)) + spawn_locs += carp_spawnpoint.loc + if(!spawn_locs.len) //If we can't find THAT, then just give up and cry + return FALSE + . = ..() + +/datum/dynamic_ruleset/midround/from_ghosts/revenant/generate_ruleset_body(mob/applicant) + var/mob/living/simple_animal/revenant/revenant = new(pick(spawn_locs)) + revenant.key = applicant.key + message_admins("[ADMIN_LOOKUPFLW(revenant)] has been made into a revenant by the midround ruleset.") + log_game("[key_name(revenant)] was spawned as a revenant by the midround ruleset.") + return revenant + +/// Sentient Disease ruleset +/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease + name = "Sentient Disease" + antag_datum = /datum/antagonist/disease + antag_flag = "Sentient Disease" + antag_flag_override = ROLE_ALIEN + required_candidates = 1 + weight = 4 + cost = 10 + requirements = list(101,101,101,80,60,50,30,20,10,10) + repeatable = TRUE + +/datum/dynamic_ruleset/midround/from_ghosts/sentient_disease/generate_ruleset_body(mob/applicant) + var/mob/camera/disease/virus = new /mob/camera/disease(SSmapping.get_station_center()) + virus.key = applicant.key + INVOKE_ASYNC(virus, /mob/camera/disease/proc/pick_name) + message_admins("[ADMIN_LOOKUPFLW(virus)] has been made into a sentient disease by the midround ruleset.") + log_game("[key_name(virus)] was spawned as a sentient disease by the midround ruleset.") + return virus + + +/// Obsessed ruleset +/datum/dynamic_ruleset/midround/obsessed + name = "Obsessed" + antag_datum = /datum/antagonist/obsessed + antag_flag = ROLE_OBSESSED + restricted_roles = list("Cyborg", "AI", "Positronic Brain") + enemy_roles = list("Security Officer", "Detective", "Head of Security", "Captain") + required_enemies = list(2,2,1,1,1,1,1,0,0,0) + required_candidates = 1 + weight = 4 + cost = 10 + requirements = list(101,101,101,80,60,50,30,20,10,10) + repeatable = TRUE + +/datum/dynamic_ruleset/midround/obsessed/trim_candidates() + ..() + candidates = living_players + for(var/mob/living/carbon/human/candidate in candidates) + if( \ + !candidate.getorgan(/obj/item/organ/brain) \ + || candidate.mind.has_antag_datum(/datum/antagonist/obsessed) \ + || candidate.stat == DEAD \ + || !(ROLE_OBSESSED in candidate.client?.prefs?.be_special) \ + || !SSjob.GetJob(candidate.mind.assigned_role) \ + || (candidate.mind.assigned_role in GLOB.nonhuman_positions) \ + ) + candidates -= candidate + +/datum/dynamic_ruleset/midround/obsessed/execute() + if(!candidates || !candidates.len) + return FALSE + var/mob/living/carbon/human/obsessed = pick_n_take(candidates) + obsessed.gain_trauma(/datum/brain_trauma/special/obsessed) + message_admins("[ADMIN_LOOKUPFLW(obsessed)] has been made Obsessed by the midround ruleset.") + log_game("[key_name(obsessed)] was made Obsessed by the midround ruleset.") + return ..() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 1b625bd68f16..00b7f02692f0 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -153,7 +153,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) item_flags |= FORCE_STRING_OVERRIDE if(!hitsound) - if(damtype == FIRE) + if(damtype == BURN) hitsound = 'sound/items/welder.ogg' if(damtype == "brute") hitsound = "swing_hit" @@ -878,3 +878,20 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) if(ismob(loc)) var/mob/mob_loc = loc mob_loc.regenerate_icons() +/** + * Called when this object is first embedded into a carbon + */ +/obj/item/proc/on_embed(mob/living/carbon/human/embedde, obj/item/bodypart/part) + return TRUE + +/** + * Called when this object is no longer embedded into a carbon + */ +/obj/item/proc/on_embed_removal(mob/living/carbon/human/embedde) + return TRUE + +/** + * Called every life tick when the object is embedded in a carbon + */ +/obj/item/proc/embed_tick(mob/living/carbon/human/embedde, obj/item/bodypart/part) + return diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index e4408481748e..fdb30bf146fc 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -42,7 +42,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM playsound(src, "sound/items/match_strike.ogg", 15, TRUE) lit = TRUE icon_state = "match_lit" - damtype = FIRE + damtype = BURN force = 3 hitsound = 'sound/items/welder.ogg' item_state = "cigon" @@ -183,7 +183,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM name = "lit [name]" attack_verb = list("burnt", "singed") hitsound = 'sound/items/welder.ogg' - damtype = FIRE + damtype = BURN force = 4 if(reagents.get_reagent_amount(/datum/reagent/toxin/plasma)) // the plasma explodes when exposed to fire var/datum/effect_system/reagents_explosion/e = new() @@ -588,7 +588,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM lit = new_lit if(lit) force = 5 - damtype = FIRE + damtype = BURN hitsound = 'sound/items/welder.ogg' attack_verb = list("burnt", "singed") set_light(1) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index e6ff2e6f9ee5..137cd9315539 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -339,7 +339,7 @@ force = on_damage name = "lit [initial(src.name)]" desc = "[initial(src.desc)] This one is lit." - damtype = FIRE + damtype = BURN attack_verb = list("burnt","scorched","scalded") hitsound = 'sound/items/welder.ogg' START_PROCESSING(SSobj, src) diff --git a/code/game/objects/items/supermatter_delaminator.dm b/code/game/objects/items/supermatter_delaminator.dm index 1ba52f551070..46668d2432a2 100644 --- a/code/game/objects/items/supermatter_delaminator.dm +++ b/code/game/objects/items/supermatter_delaminator.dm @@ -153,7 +153,7 @@ icon = 'icons/obj/supermatter_delaminator.dmi' icon_state = "antinoblium_tongs" toolspeed = 0.75 - damtype = FIRE + damtype = BURN var/obj/item/supermatter_delaminator/antinoblium_shard/shard /obj/item/hemostat/antinoblium/Destroy() diff --git a/code/game/objects/items/theft_tools.dm b/code/game/objects/items/theft_tools.dm index 90c601982b34..20b2c08d132e 100644 --- a/code/game/objects/items/theft_tools.dm +++ b/code/game/objects/items/theft_tools.dm @@ -201,7 +201,7 @@ icon = 'icons/obj/nuke_tools.dmi' icon_state = "supermatter_scalpel" toolspeed = 0.5 - damtype = FIRE + damtype = BURN usesound = 'sound/weapons/bladeslice.ogg' var/usesLeft @@ -215,7 +215,7 @@ icon = 'icons/obj/nuke_tools.dmi' icon_state = "supermatter_tongs" toolspeed = 0.75 - damtype = FIRE + damtype = BURN var/obj/item/nuke_core/supermatter_sliver/sliver /obj/item/hemostat/supermatter/Destroy() diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index cf9323485256..3bd3fa8f26fe 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -75,7 +75,7 @@ //Welders left on now use up fuel, but lets not have them run out quite that fast if(1) force = 15 - damtype = FIRE + damtype = BURN ++burned_fuel_for if(burned_fuel_for >= WELDER_FUEL_BURN_INTERVAL) use(1) @@ -172,7 +172,7 @@ to_chat(user, span_notice("You switch [src] on.")) playsound(loc, acti_sound, 50, 1) force = 15 - damtype = FIRE + damtype = BURN hitsound = 'sound/items/welder.ogg' update_icon() START_PROCESSING(SSobj, src) diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index 795f7e90d41e..c0be2909fc79 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -22,7 +22,7 @@ var/scan_state = "" //Holder for the image we display when we're pinged by a mining scanner var/defer_change = FALSE var/hardness = 1 //how hard the material is, we'll have to have more powerful stuff if we want to blast harder materials. - + /turf/closed/mineral/Initialize() if (!canSmoothWith) canSmoothWith = list(/turf/closed/mineral, /turf/closed/indestructible) @@ -695,9 +695,12 @@ . = ..() /turf/closed/mineral/gibtonite/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/t_scanner/adv_mining_scanner/goat_scanner) && stage == 1) + user.visible_message(span_notice("[user] holds [I] to [src]..."), span_notice("[I] locates where to cut off the chain reaction and stops it.")) + defuse(force_perfect = TRUE) if(istype(I, /obj/item/mining_scanner) || istype(I, /obj/item/t_scanner/adv_mining_scanner) && stage == 1) user.visible_message(span_notice("[user] holds [I] to [src]..."), span_notice("You use [I] to locate where to cut off the chain reaction and attempt to stop it...")) - defuse() + defuse(force_perfect = FALSE) ..() /turf/closed/mineral/gibtonite/proc/explosive_reaction(mob/user = null, triggered_by_explosion = 0) @@ -732,13 +735,17 @@ stage = GIBTONITE_DETONATE explosion(bombturf,1,3,5, adminlog = notify_admins) -/turf/closed/mineral/gibtonite/proc/defuse() +/turf/closed/mineral/gibtonite/proc/defuse(force_perfect = FALSE) if(stage == GIBTONITE_ACTIVE) cut_overlay(activated_overlay) activated_overlay.icon_state = "rock_Gibtonite_inactive" add_overlay(activated_overlay) desc = "An inactive gibtonite reserve. The ore can be extracted." stage = GIBTONITE_STABLE + if(force_perfect) + det_time = 0 + visible_message(span_notice("The chain reaction was stopped at its highest potency!")) + return if(det_time < 0) det_time = 0 visible_message(span_notice("The chain reaction was stopped! The gibtonite had [det_time] reactions left till the explosion!")) @@ -814,4 +821,3 @@ /turf/closed/mineral/magmite/volcanic/hard smooth_icon = 'icons/turf/smoothrocks_hard.dmi' hardness = 2 - diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 4a8c4517ef21..89e97d038643 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -94,6 +94,49 @@ Yogs End*/ if (message) message_admins(msg) else + if(!real_bans_only) + var/datum/DBQuery/query_get_bound_creds = SSdbcore.NewQuery({" + SELECT + ckey, + ip, + computerid + FROM [format_table_name("bound_credentials")] + WHERE + (ip = INET_ATON(:ip) OR computerid = :computerid) + "}, list("ckey" = ckey, "ip" = address, "computerid" = computer_id)) + if(!query_get_bound_creds.warn_execute()) + qdel(query_get_bound_creds) + return + + //Null = unchecked, false = verified, true = reject + var/reject_bound_cid + var/reject_bound_ip + + while(query_get_bound_creds.NextRow()) + var/bound_ckey = query_get_bound_creds.item[1] + var/bound_ip = query_get_bound_creds.item[2] + var/bound_cid = query_get_bound_creds.item[3] + + //We have yet to confirm the ip and this entry specifies one + if(bound_ip && (reject_bound_ip != FALSE)) + //If it matches, we set it to false and we stop checking bound ips + // Otherwise, we set it to true and it will reject the login if no bound ip is found + reject_bound_ip = (bound_ckey != ckey) + + //Same logic but for cids + if(bound_cid && (reject_bound_cid != FALSE)) + reject_bound_cid = (bound_ckey != ckey) + + if(reject_bound_cid || reject_bound_ip) + var/cause = reject_bound_cid ? "computer ID" : "IP address" + var/msg = {"This [cause] has been bound to another account. + Please visit [CONFIG_GET(string/banappeals) || "the forums"] if this was done in error or if you have recently changed BYOND accounts."} + log_access("Failed Login: [key] [computer_id] [address] - Bound [cause]") + key_cache[key] = 0 + return list("reason" = "bound [cause]", "desc" = msg) + + qdel(query_get_bound_creds) + var/list/ban_details = is_banned_from_with_details(ckey, address, computer_id, "Server") for(var/i in ban_details) if(admin) diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index eca0e881b379..8199bacb3c70 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -52,8 +52,33 @@ //checks DB ban table if a ckey, ip and/or cid is banned from a specific role //returns an associative nested list of each matching row's ban id, bantime, ban round id, expiration time, ban duration, applies to admins, reason, key, ip, cid and banning admin's key in that order /proc/is_banned_from_with_details(player_ckey, player_ip, player_cid, role) + var/datum/DBQuery/query_get_bypass_creds = SSdbcore.NewQuery({" + SELECT + computerid, + INET_NTOA(ip) + FROM [format_table_name("bound_credentials")] + WHERE + ckey = :ckey AND + FIND_IN_SET('bypass_bans', [format_table_name("bound_credentials")].flags) + "}, list("ckey" = player_ckey)); + if(!query_get_bypass_creds.warn_execute()) + qdel(query_get_bypass_creds) + return + + while(query_get_bypass_creds.NextRow()) + var/bound_cid = query_get_bypass_creds.item[1] + var/bound_ip = query_get_bypass_creds.item[2] + + //If we bypass, set the thing to null so that we can not check it + if(bound_cid == player_cid) + player_cid = null + if(bound_ip == player_ip) + player_ip = null + qdel(query_get_bypass_creds) + if(!player_ckey && !player_ip && !player_cid) return + var/datum/DBQuery/query_check_ban = SSdbcore.NewQuery({" SELECT id, diff --git a/code/modules/antagonists/blob/blob.dm b/code/modules/antagonists/blob/blob.dm index 864e9ac69941..a7efe42ffa11 100644 --- a/code/modules/antagonists/blob/blob.dm +++ b/code/modules/antagonists/blob/blob.dm @@ -22,13 +22,25 @@ return basic_report /datum/antagonist/blob/greet() + to_chat(owner.current, span_notice("You are the Blob!")) + owner.announce_objectives() if(!isovermind(owner.current)) - to_chat(owner,span_userdanger("You feel bloated.")) + to_chat(owner.current, span_notice("Use the pop ability to place your blob core! It is recommended you do this away from anyone else, as you'll be taking on the entire crew!")) + + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/blobalert.ogg', 100, FALSE, pressure_affected = FALSE) /datum/antagonist/blob/on_gain() create_objectives() . = ..() +/datum/antagonist/blob/remove_innate_effects() + QDEL_NULL(pop_action) + return ..() + +/datum/antagonist/blob/farewell() + to_chat(owner.current, "You are no longer the Blob!") + return ..() + /datum/antagonist/blob/proc/create_objectives() var/datum/objective/blob_takeover/main = new main.owner = owner @@ -49,21 +61,49 @@ desc = "Unleash the blob" icon_icon = 'icons/mob/blob.dmi' button_icon_state = "blob" + var/autoplace_time = OVERMIND_STARTING_AUTO_PLACE_TIME -/datum/action/innate/blobpop/Activate() + +/datum/action/innate/blobpop/Grant(Target) + . = ..() + if(owner) + addtimer(CALLBACK(src, .proc/Activate, TRUE), autoplace_time, TIMER_UNIQUE|TIMER_OVERRIDE) + to_chat(owner, "You will automatically pop and place your blob core in [DisplayTimeText(autoplace_time)].") + +/datum/action/innate/blobpop/Activate(timer_activated = FALSE) var/mob/old_body = owner + if(!owner) + return var/datum/antagonist/blob/blobtag = owner.mind.has_antag_datum(/datum/antagonist/blob) if(!blobtag) - Remove() + Remove(owner) return - var/mob/camera/blob/B = new /mob/camera/blob(get_turf(old_body), blobtag.starting_points_human_blob) - owner.mind.transfer_to(B) + + . = TRUE + var/turf/target_turf = get_turf(owner) + if(target_turf.density) + to_chat(owner, "This spot is too dense to place a blob core on!") + . = FALSE + if(isspaceturf(target_turf) || !is_station_level(target_turf.z)) + to_chat(owner, "You cannot place your core here!") + . = FALSE + + var/placement_override = BLOB_FORCE_PLACEMENT + if(!.) + if(!timer_activated) + return + placement_override = BLOB_RANDOM_PLACEMENT + to_chat(owner, "Because your current location is an invalid starting spot and you need to pop, you've been moved to a random location!") + + var/mob/camera/blob/blob_cam = new /mob/camera/blob(get_turf(old_body), blobtag.starting_points_human_blob) + owner.mind.transfer_to(blob_cam) old_body.gib() - B.place_blob_core(blobtag.point_rate_human_blob, pop_override = TRUE) + blob_cam.place_blob_core(placement_override, pop_override = TRUE) + playsound(get_turf(blob_cam), 'sound/ambience/antag/blobalert.ogg', 50, FALSE) /datum/antagonist/blob/antag_listing_status() . = ..() if(owner && owner.current) - var/mob/camera/blob/B = owner.current - if(istype(B)) - . += "(Progress: [B.blobs_legit.len]/[B.blobwincount])" \ No newline at end of file + var/mob/camera/blob/blob_cam = owner.current + if(istype(blob_cam)) + . += "(Progress: [length(blob_cam.blobs_legit)]/[blob_cam.blobwincount])" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index f2fc261437b0..1ccbe664239b 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -86,6 +86,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) //Quirk list var/list/all_quirks = list() + var/mood_tail_wagging = TRUE + //Job preferences 2.0 - indexed by job title , no key or value implies never var/list/job_preferences = list() @@ -753,6 +755,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) //yogs start -- Mood preference toggling if(CONFIG_GET(flag/disable_human_mood)) dat += "Mood: [yogtoggles & PREF_MOOD ? "Enabled" : "Disabled"]
" + dat += "Mood Tail Wagging: [mood_tail_wagging ? "Enabled" : "Disabled"]
" //yogs end dat += "" @@ -2084,6 +2087,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("mood") yogtoggles ^= PREF_MOOD + + if("moodtailwagging") + mood_tail_wagging = !mood_tail_wagging // yogs end ShowChoices(user) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 3c15b43d5840..05fc4a1d845b 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -232,6 +232,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car READ_FILE(S["yogtoggles"], yogtoggles) READ_FILE(S["accent"], accent) // Accents, too! + + READ_FILE(S["mood_tail_wagging"], mood_tail_wagging) // yogs end //try to fix any outdated data if necessary @@ -368,6 +370,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["purrbation"], purrbation) WRITE_FILE(S["accent"], accent) // Accents, too! + + WRITE_FILE(S["mood_tail_wagging"], mood_tail_wagging) // yogs end save_keybindings(S) // yogs - Custom keybindings diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 2b90306967f0..0ca986a8f82f 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -354,3 +354,10 @@ desc = "A relic from the past. Its effectiveness as a stylish hat was never debated." icon_state = "unberet" item_state = "unberet" + +/obj/item/clothing/head/halo + name = "Transdimensional halo" + desc = "An aetherial halo that magically hovers above the head." + icon_state = "halo" + item_state = "halo" + layer = EARS_LAYER diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm index 02c7deb929a6..cdf6fa08b422 100644 --- a/code/modules/events/spacevine.dm +++ b/code/modules/events/spacevine.dm @@ -124,7 +124,7 @@ return 1 /datum/spacevine_mutation/fire_proof/on_hit(obj/structure/spacevine/holder, mob/hitter, obj/item/I, expected_damage) - if(I && I.damtype == FIRE) + if(I && I.damtype == BURN) . = 0 else . = expected_damage diff --git a/code/modules/food_and_drinks/food/snacks/meat.dm b/code/modules/food_and_drinks/food/snacks/meat.dm index e8a291e4e377..15c73412feb7 100644 --- a/code/modules/food_and_drinks/food/snacks/meat.dm +++ b/code/modules/food_and_drinks/food/snacks/meat.dm @@ -340,6 +340,19 @@ icon_state = "shadowmeat" desc = "It is covered in a strange darkness. This slab's magical properties appear to be drastically weakened due to the synthetic nature of the meat." +/obj/item/reagent_containers/food/snacks/meat/slab/plagued + name = "meat" + desc = "A slab of disease-ridden meat. Eating it is a questionable idea." + icon_state = "meat" + dried_type = /obj/item/reagent_containers/food/snacks/sosjerky/ + bitesize = 3 + list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/cooking_oil = 2, /datum/reagent/plaguebacteria = 3) //It is infected by plague + slice_path = /obj/item/reagent_containers/food/snacks/meat/raw_cutlet/plain + slices_num = 3 + filling_color = "#FF0000" + tastes = list("meat" = 2, "decay" = 1) + foodtype = MEAT | RAW + ////////////////////////////////////// MEAT STEAKS /////////////////////////////////////////////////////////// @@ -435,7 +448,7 @@ /obj/item/reagent_containers/food/snacks/meat/raw_cutlet/initialize_cooked_food(obj/item/reagent_containers/food/snacks/S, cooking_efficiency) ..() S.name = "[meat_type] cutlet" - + /obj/item/reagent_containers/food/snacks/meat/raw_cutlet/plain diff --git a/code/modules/hydroponics/grown/flowers.dm b/code/modules/hydroponics/grown/flowers.dm index 1c5f96a004e9..0efcd749a192 100644 --- a/code/modules/hydroponics/grown/flowers.dm +++ b/code/modules/hydroponics/grown/flowers.dm @@ -151,7 +151,7 @@ icon_state = "sunflower" lefthand_file = 'icons/mob/inhands/weapons/plants_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/plants_righthand.dmi' - damtype = FIRE + damtype = BURN force = 0 slot_flags = ITEM_SLOT_HEAD throwforce = 0 diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm index 4e7b2590e139..f0a7c0eee3e0 100644 --- a/code/modules/hydroponics/grown/nettle.dm +++ b/code/modules/hydroponics/grown/nettle.dm @@ -36,7 +36,7 @@ icon_state = "nettle" lefthand_file = 'icons/mob/inhands/weapons/plants_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/plants_righthand.dmi' - damtype = FIRE + damtype = BURN force = 15 wound_bonus = CANT_WOUND hitsound = 'sound/weapons/bladeslice.ogg' diff --git a/code/modules/mining/equipment/mineral_scanner.dm b/code/modules/mining/equipment/mineral_scanner.dm index dadbdf2af3f6..ae1f92a328d3 100644 --- a/code/modules/mining/equipment/mineral_scanner.dm +++ b/code/modules/mining/equipment/mineral_scanner.dm @@ -54,6 +54,12 @@ range = 4 cooldown = 50 +/obj/item/t_scanner/adv_mining_scanner/goat_scanner + desc = "An advanced scanner used by the goat king to sate his appetite for explosions; It allows the user to always receive high potency gibtonite after defusing them." + name = "goat king's scanner" + icon_state = "goat_mining0" + cooldown = 20 + /obj/item/t_scanner/adv_mining_scanner/scan() if(current_cooldown <= world.time) current_cooldown = world.time + cooldown @@ -85,3 +91,4 @@ /obj/effect/temp_visual/mining_overlay/Initialize() . = ..() animate(src, alpha = 0, time = duration, easing = EASE_IN) + diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index fce9e766e563..41fdb3dcd4bc 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -226,11 +226,19 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ GibtoniteReaction(user) return if(primed) + if(istype(I, /obj/item/t_scanner/adv_mining_scanner/goat_scanner)) + primed = FALSE + if(det_timer) + deltimer(det_timer) + user.visible_message("The chain reaction was stopped... the ore's quality seems to have improved!", span_notice("You stopped the chain reaction... the ore's quality seems to have improved!")) + icon_state = "Gibtonite ore 3" + quality = GIBTONITE_QUALITY_HIGH + return if(istype(I, /obj/item/mining_scanner) || istype(I, /obj/item/t_scanner/adv_mining_scanner) || I.tool_behaviour == TOOL_MULTITOOL) primed = FALSE if(det_timer) deltimer(det_timer) - user.visible_message("The chain reaction was stopped! ...The ore's quality looks diminished.", span_notice("You stopped the chain reaction. ...The ore's quality looks diminished.")) + user.visible_message("The chain reaction was stopped! ...The ore's quality looks diminished.", span_notice("You stopped the chain reaction... the ore's quality looks diminished.")) icon_state = "Gibtonite ore" quality = GIBTONITE_QUALITY_LOW return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 91c2c08c3ca7..9393e24fd022 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -77,6 +77,7 @@ var/obj/item/bodypart/affecting = get_bodypart(check_zone(user.zone_selected)) if(user.a_intent != INTENT_HARM && I.tool_behaviour == TOOL_WELDER && affecting?.status == BODYPART_ROBOTIC) + user.changeNext_move(CLICK_CD_MELEE) if(I.use_tool(src, user, 0, volume=50, amount=1)) if(user == src) user.visible_message(span_notice("[user] starts to fix some of the dents on [src]'s [affecting.name]."), @@ -273,6 +274,26 @@ visible_message(span_danger("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name]."), \ span_userdanger("[usr] [internal ? "opens" : "closes"] the valve on [src]'s [ITEM.name].")) + // Embed Stuff + if(href_list["embedded_object"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY)) + var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts + if(!L) + return + var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects + if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore + return + var/time_taken = I.embedding.embedded_unsafe_removal_time*I.w_class + usr.visible_message(span_warning("[usr] attempts to remove [I] from [usr.p_their()] [L.name]."),span_notice("You attempt to remove [I] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)")) + if(do_after(usr, time_taken, needhand = 1, target = src)) + if(!I || !L || I.loc != src) + return + var/damage_amount = I.embedding.embedded_unsafe_removal_pain_multiplier * I.w_class + L.receive_damage(damage_amount, sharpness = SHARP_EDGED)//It hurts to rip it out, get surgery you dingus. + if(remove_embedded_object(I, get_turf(src), damage_amount)) + usr.put_in_hands(I) + usr.visible_message("[usr] successfully rips [I] out of [usr.p_their()] [L.name]!", span_notice("You successfully remove [I] from your [L.name].")) + return + /mob/living/carbon/fall(forced) if(loc) loc.handle_fall(src, forced)//it's loc so it doesn't call the mob's handle_fall which does nothing diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index dc226b36efd4..569f80b1732f 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -50,10 +50,15 @@ return TRUE /mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum) - if(!skipcatch) //ugly, but easy - if(can_catch_item()) - if(istype(AM, /obj/item)) - var/obj/item/I = AM + var/obj/item/I = AM + if(istype(I, /obj/item)) + if(((throwingdatum ? throwingdatum.speed : I.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || I.embedding.embedded_ignore_throwspeed_threshold) + var/obj/item/bodypart/body_part = pick(bodyparts) + if(prob(clamp(I.embedding.embed_chance - run_armor_check(body_part, MELEE), 0, 100)) && embed_object(I, deal_damage = TRUE)) + hitpush = FALSE + skipcatch = TRUE //can't catch the now embedded item + if(!skipcatch) //ugly, but easy + if(can_catch_item()) if(I.item_flags & UNCATCHABLE) return FALSE if(isturf(I.loc)) @@ -68,6 +73,83 @@ return TRUE ..() +/** + * Embeds an object into this carbon + */ +/mob/living/carbon/proc/embed_object(obj/item/embedding, part, deal_damage, silent, forced) + if(!(forced || (can_embed(embedding) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE)))) + return FALSE + var/obj/item/bodypart/body_part = part + // In case its a zone + if(!istype(body_part) && body_part) + body_part = get_bodypart(body_part) + // Otherwise pick one + if(!istype(body_part)) + body_part = pick(bodyparts) + // Thats probably not good + if(!istype(body_part)) + return FALSE + if(!embedding.on_embed(src, body_part)) + return + body_part.embedded_objects |= embedding + embedding.add_mob_blood(src)//it embedded itself in you, of course it's bloody! + embedding.forceMove(src) + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded) + if(deal_damage) + body_part.receive_damage(embedding.w_class*embedding.embedding.embedded_impact_pain_multiplier, wound_bonus=-30, sharpness = TRUE) + if(!silent) + throw_alert("embeddedobject", /obj/screen/alert/embeddedobject) + visible_message(span_danger("[embedding] embeds itself in [src]'s [body_part.name]!"), span_userdanger("[embedding] embeds itself in your [body_part.name]!")) + return TRUE + +/** + * Removes the given embedded object from this carbon + */ +/mob/living/carbon/proc/remove_embedded_object(obj/item/embedded, new_loc, silent, forced) + var/obj/item/bodypart/body_part + for(var/obj/item/bodypart/part in bodyparts) + if(embedded in part.embedded_objects) + body_part = part + if(!body_part) + return + if(!embedded.on_embed_removal(src)) + return + body_part.embedded_objects -= embedded + if(!silent) + emote("scream") + if(!has_embedded_objects()) + clear_alert("embeddedobject") + SEND_SIGNAL(usr, COMSIG_CLEAR_MOOD_EVENT, "embedded") + if(new_loc) + embedded.forceMove(new_loc) + return TRUE + +/** + * Called when a mob tries to remove an embedded object from this carbon + */ +/mob/living/carbon/proc/try_remove_embedded_object(mob/user) + var/list/choice_list = list() + var/obj/item/bodypart/body_part + for(var/obj/item/bodypart/part in bodyparts) + for(var/obj/item/embedded in part.embedded_objects) + choice_list[embedded] = image(embedded) + var/obj/item/choice = show_radial_menu(user, src, choice_list, tooltips = TRUE) + for(var/obj/item/bodypart/part in bodyparts) + if(choice in part.embedded_objects) + body_part = part + if(!istype(choice) || !(choice in choice_list)) + return + var/time_taken = choice.embedding.embedded_unsafe_removal_time * choice.w_class + user.visible_message(span_warning("[user] attempts to remove [choice] from [usr.p_their()] [body_part.name]."),span_notice("You attempt to remove [choice] from your [body_part.name]... (It will take [DisplayTimeText(time_taken)].)")) + if(!do_after(user, time_taken, needhand = 1, target = src) && !(choice in body_part.embedded_objects)) + return + var/damage_amount = choice.embedding.embedded_unsafe_removal_pain_multiplier * choice.w_class + body_part.receive_damage(damage_amount > 0, sharpness = SHARP_EDGED)//It hurts to rip it out, get surgery you dingus. + if(remove_embedded_object(choice, get_turf(src), damage_amount)) + user.put_in_hands(choice) + user.visible_message("[user] successfully rips [choice] out of [user == src? p_their() : "[src]'s"] [body_part.name]!", span_notice("You successfully remove [choice] from your [body_part.name].")) + return TRUE + /mob/living/carbon/proc/get_interaction_efficiency(zone) var/obj/item/bodypart/limb = get_bodypart(zone) if(!limb) diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index f563234e99ac..75a3cb178ae5 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -32,6 +32,17 @@ else if(get_bodypart(BODY_ZONE_HEAD)) . += span_deadsay("It appears that [t_his] brain is missing...") + var/list/disabled = list() + for(var/X in bodyparts) + var/obj/item/bodypart/body_part = X + if(body_part.bodypart_disabled) + disabled += body_part + for(var/obj/item/I in body_part.embedded_objects) + . += "[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [body_part.name]!\n" + for(var/i in body_part.wounds) + var/datum/wound/iter_wound = i + . += "[iter_wound.get_examine_description(user)]\n" + var/list/missing = get_missing_limbs() for(var/t in missing) if(t==BODY_ZONE_HEAD) @@ -68,12 +79,6 @@ else msg += "[t_He] [t_is] severely deformed!\n" - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - for(var/i in BP.wounds) - var/datum/wound/W = i - msg += "[W.get_examine_description(user)]\n" - if(HAS_TRAIT(src, TRAIT_DUMB)) msg += "[t_He] seem[p_s()] to be clumsy and unable to think.\n" diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index a2a23a1d0654..8d8b545aef56 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -231,29 +231,6 @@ spreadFire(AM) /mob/living/carbon/human/Topic(href, href_list) - if(href_list["embedded_object"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY)) - var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts - if(!L) - return - var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects - if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore - return - var/time_taken = I.embedding.embedded_unsafe_removal_time*I.w_class - usr.visible_message(span_warning("[usr] attempts to remove [I] from [usr.p_their()] [L.name]."),span_notice("You attempt to remove [I] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)")) - if(do_after(usr, time_taken, needhand = 1, target = src)) - if(!I || !L || I.loc != src || !(I in L.embedded_objects)) - return - L.embedded_objects -= I - L.receive_damage(I.embedding.embedded_unsafe_removal_pain_multiplier*I.w_class, sharpness=SHARP_EDGED)//It hurts to rip it out, get surgery you dingus. - I.forceMove(get_turf(src)) - usr.put_in_hands(I) - usr.emote("scream") - usr.visible_message("[usr] successfully rips [I] out of [usr.p_their()] [L.name]!",span_notice("You successfully remove [I] from your [L.name].")) - if(!has_embedded_objects()) - clear_alert("embeddedobject") - SEND_SIGNAL(usr, COMSIG_CLEAR_MOOD_EVENT, "embedded") - return - if(href_list["item"]) //canUseTopic check for this is handled by mob/Topic() var/slot = text2num(href_list["item"]) if(slot in check_obscured_slots(TRUE)) @@ -1235,6 +1212,9 @@ /mob/living/carbon/human/species/lizard/ashwalker race = /datum/species/lizard/ashwalker +/mob/living/carbon/human/species/lizard/draconid + race = /datum/species/lizard/draconid + /mob/living/carbon/human/species/moth race = /datum/species/moth diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index de8cc108f01b..e5e3a041939b 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -169,21 +169,6 @@ hitpush = FALSE skipcatch = TRUE blocked = TRUE - else if(I) - if(((throwingdatum ? throwingdatum.speed : I.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || I.embedding.embedded_ignore_throwspeed_threshold) - if(can_embed(I)) - if(prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE)) - throw_alert("embeddedobject", /obj/screen/alert/embeddedobject) - var/obj/item/bodypart/L = pick(bodyparts) - L.embedded_objects |= I - I.add_mob_blood(src)//it embedded itself in you, of course it's bloody! - I.forceMove(src) - L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier, wound_bonus=-30, sharpness = TRUE) - visible_message(span_danger("[I] embeds itself in [src]'s [L.name]!"),span_userdanger("[I] embeds itself in your [L.name]!")) - SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded) - hitpush = FALSE - skipcatch = TRUE //can't catch the now embedded item - return ..() /mob/living/carbon/human/grippedby(mob/living/user, instant = FALSE) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index ef6081b5d79e..a685a17423ce 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -38,10 +38,6 @@ //heart attack stuff handle_heart() - if(stat != DEAD) - //Stuff jammed in your limbs hurts - handle_embedded_objects() - dna.species.spec_life(src) // for mutantraces else for(var/i in all_wounds) @@ -307,31 +303,6 @@ return TRUE return ..() - -/mob/living/carbon/human/proc/handle_embedded_objects() - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - for(var/obj/item/I in BP.embedded_objects) - var/pain_chance_current = I.embedding.embedded_pain_chance - if(!(mobility_flags & MOBILITY_STAND)) - pain_chance_current *= 0.2 - if(prob(pain_chance_current)) - BP.receive_damage(I.w_class*I.embedding.embedded_pain_multiplier, wound_bonus = CANT_WOUND) - to_chat(src, span_userdanger("[I] embedded in your [BP.name] hurts!")) - - var/fall_chance_current = I.embedding.embedded_fall_chance - if(!(mobility_flags & MOBILITY_STAND)) - fall_chance_current *= 0.2 - - if(prob(fall_chance_current)) - BP.receive_damage(I.w_class*I.embedding.embedded_fall_pain_multiplier, wound_bonus = CANT_WOUND) // can wound - BP.embedded_objects -= I - I.forceMove(drop_location()) - visible_message(span_danger("[I] falls out of [name]'s [BP.name]!"),span_userdanger("[I] falls out of your [BP.name]!")) - if(!has_embedded_objects()) - clear_alert("embeddedobject") - SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded") - /mob/living/carbon/human/proc/handle_heart() var/we_breath = !HAS_TRAIT_FROM(src, TRAIT_NOBREATH, SPECIES_TRAIT) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 664127201015..110bd170405a 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1219,7 +1219,7 @@ GLOBAL_LIST_EMPTY(mentor_races) /datum/species/proc/check_species_weakness(obj/item, mob/living/attacker) return 0 //This is not a boolean, it's the multiplier for the damage that the user takes from the item.It is added onto the check_weakness value of the mob, and then the force of the item is multiplied by this value -//////// + //////// //LIFE// //////// diff --git a/code/modules/mob/living/carbon/human/species_types/felinid.dm b/code/modules/mob/living/carbon/human/species_types/felinid.dm index 1aa3fb9ec101..b45554bbdcf4 100644 --- a/code/modules/mob/living/carbon/human/species_types/felinid.dm +++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm @@ -166,3 +166,28 @@ /datum/species/human/felinid/get_scream_sound(mob/living/carbon/human/H) return pick(screamsound) + +/datum/species/human/felinid/spec_life(mob/living/carbon/human/H) + . = ..() + if((H.client && H.client.prefs.mood_tail_wagging) && !is_wagging_tail() && H.mood_enabled) + var/datum/component/mood/mood = H.GetComponent(/datum/component/mood) + if(!istype(mood) || !(mood.shown_mood >= MOOD_LEVEL_HAPPY2)) + return + var/chance = 0 + switch(mood.shown_mood) + if(0 to MOOD_LEVEL_SAD4) + chance = -0.1 + if(MOOD_LEVEL_SAD4 to MOOD_LEVEL_SAD3) + chance = -0.01 + if(MOOD_LEVEL_HAPPY2 to MOOD_LEVEL_HAPPY3) + chance = 0.001 + if(MOOD_LEVEL_HAPPY3 to MOOD_LEVEL_HAPPY4) + chance = 0.1 + if(MOOD_LEVEL_HAPPY4 to INFINITY) + chance = 1 + if(prob(abs(chance))) + switch(SIGN(chance)) + if(1) + H.emote("wag") + if(-1) + stop_wagging_tail(H) diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 97b6808573b3..f35e61b924dc 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -62,6 +62,32 @@ stunmod *= heat_stun_mult //however many times, and if it goes down we multiply by 1.1 //This gets us an effective stunmod of 0.91, 1, 1.1, 1.21, 1.33, based on temp +/datum/species/lizard/spec_life(mob/living/carbon/human/H) + . = ..() + if((H.client && H.client.prefs.mood_tail_wagging) && !is_wagging_tail() && H.mood_enabled) + var/datum/component/mood/mood = H.GetComponent(/datum/component/mood) + if(!istype(mood) || !(mood.shown_mood >= MOOD_LEVEL_HAPPY2)) + return + var/chance = 0 + switch(mood.shown_mood) + if(0 to MOOD_LEVEL_SAD4) + chance = -0.1 + if(MOOD_LEVEL_SAD4 to MOOD_LEVEL_SAD3) + chance = -0.01 + if(MOOD_LEVEL_HAPPY2 to MOOD_LEVEL_HAPPY3) + chance = 0.001 + if(MOOD_LEVEL_HAPPY3 to MOOD_LEVEL_HAPPY4) + chance = 0.1 + if(MOOD_LEVEL_HAPPY4 to INFINITY) + chance = 1 + if(prob(abs(chance))) + switch(SIGN(chance)) + if(1) + H.emote("wag") + if(-1) + stop_wagging_tail(H) + + /* Lizard subspecies: ASHWALKERS */ diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 8014bfe5ae8a..9cafc79fab95 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -37,6 +37,10 @@ if(stat != DEAD) handle_liver() + if(stat != DEAD) + //Stuff jammed in your limbs hurts + handle_embedded_objects() + else . = ..() @@ -654,6 +658,35 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put var/datum/brain_trauma/BT = T BT.on_life() + +//////////// +// EMBEDS // +//////////// + +/mob/living/carbon/proc/handle_embedded_objects() + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + for(var/obj/item/I in BP.embedded_objects) + I.embed_tick(src, BP) + var/pain_chance_current = I.embedding.embedded_pain_chance + if(!(mobility_flags & MOBILITY_STAND)) + pain_chance_current *= 0.2 + if(prob(pain_chance_current)) + BP.receive_damage(I.w_class*I.embedding.embedded_pain_multiplier, wound_bonus = CANT_WOUND) + to_chat(src, span_userdanger("[I] embedded in your [BP.name] hurts!")) + + var/fall_chance_current = I.embedding.embedded_fall_chance + if(!(mobility_flags & MOBILITY_STAND)) + fall_chance_current *= 0.2 + + if(prob(fall_chance_current)) + BP.receive_damage(I.w_class*I.embedding.embedded_fall_pain_multiplier, wound_bonus = CANT_WOUND) // can wound + remove_embedded_object(I, drop_location(), FALSE) + visible_message(span_danger("[I] falls out of [name]'s [BP.name]!"), span_userdanger("[I] falls out of your [BP.name]!")) + if(!has_embedded_objects()) + clear_alert("embeddedobject") + SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded") + ///////////////////////////////////// //MONKEYS WITH TOO MUCH CHOLOESTROL// ///////////////////////////////////// diff --git a/code/modules/mob/living/simple_animal/hostile/plague_rat.dm b/code/modules/mob/living/simple_animal/hostile/plague_rat.dm new file mode 100644 index 000000000000..1c6a59de9383 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/plague_rat.dm @@ -0,0 +1,89 @@ +/mob/living/simple_animal/hostile/plaguerat + name = "rat" + desc = "It's a large rodent, afflicted with both anger issues and a terrible disease." + icon_state = "mouse_gray" + icon_living = "mouse_gray" + icon_dead = "mouse_gray_dead" + speak = list("Skree!","SKREEE!","Squeak?") + speak_emote = list("squeaks") + emote_hear = list("Hisses.") + emote_see = list("runs in a circle.", "stands on its hind legs.") + melee_damage_lower = 5 //stronk + melee_damage_upper = 5 + obj_damage = 5 + speak_chance = 1 + turns_per_move = 5 + see_in_dark = 6 + maxHealth = 20 + health = 20 + butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/plagued = 1) + density = FALSE + ventcrawler = VENTCRAWLER_ALWAYS + pass_flags = PASSTABLE | PASSGRILLE | PASSMOB + mob_size = MOB_SIZE_TINY + mob_biotypes = list(MOB_ORGANIC,MOB_BEAST) + faction = list("rat") + var/playstyle_string = "You are a Plague Rat, \ + Your goal is to spread The Plague as much as possible, by infecting anyone you can. \ + You can do this by licking their food, or by directly biting them. \ + You can also nibble on dead bodies to slightly heal yourself! \ + However, you are still very fragile! You're just are a small rat, after all." + +/mob/living/simple_animal/hostile/plaguerat/AttackingTarget() + ..() + var/mob/living/carbon/C = target + if(isliving(C) && (C.stat != DEAD)) //It is for injecting plague reagent into people via biting them. + if(C.reagents) + var/obj/item/I = C.get_item_by_slot(ITEM_SLOT_OCLOTHING) + if(!istype(I, /obj/item/clothing/suit/space/hardsuit) && !istype(I, /obj/item/clothing/suit/armor)) + C.reagents.add_reagent(/datum/reagent/plaguebacteria, 3) + + if(C.stat == DEAD) //It is for biting dead bodies to heal. + src.visible_message(span_warning("[src] starts biting into [C]!"),span_notice("You start eating [C]...")) + if(do_mob(src, target, 3 SECONDS)) + to_chat(src, span_notice ("You finish eating [C].")) + heal_bodypart_damage(5) + C.adjustBruteLoss(15) + return + + if (!isliving(target) && target.reagents && target.is_injectable(src, allowmobs = TRUE)) //It is for injecting plague reagent into food and reagent containers by licking them. Not to be confused with biting people. + src.visible_message(span_warning("[src] starts licking [target]!"),span_notice("You start licking [target]...")) + if (do_mob(src, target, 2 SECONDS)) + target.reagents.add_reagent(/datum/reagent/plaguebacteria,rand(1,2),no_react = TRUE) + to_chat(src, span_notice("You finish licking [target].")) + return + +//Spawn Event + +/datum/round_event_control/plaguerat + name = "Spawn a Plague Rat" + typepath = /datum/round_event/ghost_role/plaguerat + weight = 6 + max_occurrences = 1 + earliest_start = 30 MINUTES + +/datum/round_event/ghost_role/plaguerat + minimum_required = 1 + role_name = "plaguerat" + +/datum/round_event/ghost_role/plaguerat/spawn_role() + var/list/candidates = get_candidates(ROLE_SENTIENCE, null, ROLE_SENTIENCE) + if(!candidates.len) + return NOT_ENOUGH_PLAYERS + + var/mob/dead/selected = pick_n_take(candidates) + + var/datum/mind/player_mind = new /datum/mind(selected.key) + player_mind.active = 1 + if(!GLOB.xeno_spawn) + return MAP_ERROR + var/mob/living/simple_animal/hostile/plaguerat/S = new /mob/living/simple_animal/hostile/plaguerat/(pick(GLOB.xeno_spawn)) + player_mind.transfer_to(S) + player_mind.assigned_role = "Plague rat" + player_mind.special_role = "Plague rat" + to_chat(S, S.playstyle_string) + SEND_SOUND(S, sound('sound/magic/mutate.ogg')) + message_admins("[ADMIN_LOOKUPFLW(S)] has been made into a plague rat by an event.") + log_game("[key_name(S)] was spawned as a plague rat by an event.") + spawned_mobs += S + return SUCCESSFUL_SPAWN diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 6eb0199246dc..cda8328ca0bb 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -89,6 +89,7 @@ O.setOrganLoss(ORGAN_SLOT_BRAIN, getOrganLoss(ORGAN_SLOT_BRAIN)) O.updatehealth() O.radiation = radiation + O.blood_volume = blood_volume * MONKIFY_BLOOD_COEFFICIENT //re-add implants to new mob if (tr_flags & TR_KEEPIMPLANTS) @@ -265,6 +266,7 @@ O.adjustOrganLoss(ORGAN_SLOT_BRAIN, getOrganLoss(ORGAN_SLOT_BRAIN)) O.updatehealth() O.radiation = radiation + O.blood_volume = blood_volume / MONKIFY_BLOOD_COEFFICIENT //re-add implants to new mob if (tr_flags & TR_KEEPIMPLANTS) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index e21a9523c3ea..d6ba58699933 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -283,8 +283,8 @@ if(13 to INFINITY) M.visible_message("[M] suddenly ignites in a brilliant flash of white!", span_userdanger("You suddenly ignite in a holy fire!")) M.adjust_fire_stacks(3) - M.IgniteMob() - M.adjustFireLoss(4) + M.IgniteMob() + M.adjustFireLoss(4) holder.remove_reagent(type, 0.4) //fixed consumption to prevent balancing going out of whack /datum/reagent/water/holywater/reaction_turf(turf/T, reac_volume) @@ -2043,3 +2043,14 @@ wounded_part.heal_damage(0.25, 0.25) M.adjustStaminaLoss(-0.25*REM) // the more wounds, the more stamina regen ..() + + +/datum/reagent/plaguebacteria + name = "Yersinia pestis" + description = "A horrible plague, in a container. It is a TERRIBLE idea to drink this." + color = "#7CFC00" + taste_description = "death" + can_synth = FALSE + +/datum/reagent/plaguebacteria/reaction_mob(mob/living/L, method=TOUCH, reac_volume, show_message = 1, touch_protection = 0) + L.ForceContractDisease(new /datum/disease/plague(), FALSE, TRUE) \ No newline at end of file diff --git a/code/modules/spells/spell_types/summonitem.dm b/code/modules/spells/spell_types/summonitem.dm index 6bee83f5488c..0382ccc81738 100644 --- a/code/modules/spells/spell_types/summonitem.dm +++ b/code/modules/spells/spell_types/summonitem.dm @@ -86,11 +86,8 @@ for(var/X in C.bodyparts) var/obj/item/bodypart/part = X if(item_to_retrieve in part.embedded_objects) - part.embedded_objects -= item_to_retrieve + C.remove_embedded_object(item_to_retrieve, silent = TRUE, forced = TRUE) to_chat(C, span_warning("The [item_to_retrieve] that was embedded in your [L] has mysteriously vanished. How fortunate!")) - if(!C.has_embedded_objects()) - C.clear_alert("embeddedobject") - SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "embedded") break else diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index a3c5b18e1cec..9e5d282cc961 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -104,8 +104,7 @@ break for(var/obj/item/I in embedded_objects) - embedded_objects -= I - I.forceMove(src) + phantom_owner.remove_embedded_object(I, src, TRUE, TRUE) if(!phantom_owner.has_embedded_objects()) phantom_owner.clear_alert("embeddedobject") SEND_SIGNAL(phantom_owner, COMSIG_CLEAR_MOOD_EVENT, "embedded") diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index d8896ad88966..594f36c97ca9 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -161,6 +161,7 @@ for(var/X in bodyparts) var/obj/item/bodypart/L = X for(var/obj/item/I in L.embedded_objects) + remove_embedded_object(I, T, TRUE, TRUE) L.embedded_objects -= I I.forceMove(T) @@ -168,11 +169,11 @@ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded") /mob/living/carbon/proc/has_embedded_objects() - . = 0 + . = FALSE for(var/X in bodyparts) var/obj/item/bodypart/L = X for(var/obj/item/I in L.embedded_objects) - return 1 + return TRUE //Helper for quickly creating a new limb - used by augment code in species.dm spec_attacked_by diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm index f6994a28a0d3..3b4f542f5d3a 100644 --- a/code/modules/surgery/remove_embedded_object.dm +++ b/code/modules/surgery/remove_embedded_object.dm @@ -1,14 +1,16 @@ /datum/surgery/embedded_removal name = "Removal of embedded objects" - steps = list(/datum/surgery_step/incise, /datum/surgery_step/remove_object) + steps = list(/datum/surgery_step/incise, /datum/surgery_step/remove_object, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) /datum/surgery_step/remove_object name = "remove embedded objects" - time = 32 - accept_hand = 1 + time = 1.5 SECONDS + accept_hand = TRUE fuckup_damage = 0 + repeatable = TRUE + var/obj/item/target_item = null var/obj/item/bodypart/L = null @@ -25,25 +27,20 @@ /datum/surgery_step/remove_object/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(L) - if(ishuman(target)) - var/mob/living/carbon/human/H = target - var/objects = 0 - for(var/obj/item/I in L.embedded_objects) - objects++ - I.forceMove(get_turf(H)) - L.embedded_objects -= I - if(!H.has_embedded_objects()) - H.clear_alert("embeddedobject") - SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "embedded") - - if(objects > 0) - display_results(user, target, span_notice("You successfully remove [objects] objects from [H]'s [L.name]."), - "[user] successfully removes [objects] objects from [H]'s [L]!", - "[user] successfully removes [objects] objects from [H]'s [L]!") + if(iscarbon(target)) + if(L.embedded_objects) + var/mob/living/carbon/C = target + var/obj/item/I = pick(L.embedded_objects) + if(C.remove_embedded_object(I, C.drop_location(), TRUE)) + display_results(user, target, span_notice("You successfully remove \the [I] from [C]'s [L.name]."), + "[user] successfully removes \the [I] from [C]'s [L]!", + "[user] successfully removes \the [I] from [C]'s [L]!") + else + to_chat(user, span_warning("You fail to remove \the [I] from [C]'s [L.name]!")) else - to_chat(user, span_warning("You find no objects embedded in [H]'s [L]!")) + to_chat(user, span_warning("You find no objects embedded in [target]'s [L]!")) else to_chat(user, span_warning("You can't find [target]'s [parse_zone(user.zone_selected)], let alone any objects embedded in it!")) - return 1 + return FALSE diff --git a/config/config.txt b/config/config.txt index d6a1e94356d6..95a5a3c5f268 100644 --- a/config/config.txt +++ b/config/config.txt @@ -399,10 +399,10 @@ BASE_MC_TICK_RATE 1 HIGH_POP_MC_TICK_RATE 1.1 ##Engage high pop mode if player count raises above this (Player in this context means any connected user. Lobby, ghost or in-game all count) -HIGH_POP_MC_MODE_AMOUNT 60 +HIGH_POP_MC_MODE_AMOUNT 65 ##Disengage high pop mode if player count drops below this -DISABLE_HIGH_POP_MC_MODE_AMOUNT 50 +DISABLE_HIGH_POP_MC_MODE_AMOUNT 60 ## Uncomment to prevent the world from sleeping while no players are connected after initializations #RESUME_AFTER_INITIALIZATIONS diff --git a/html/changelog.html b/html/changelog.html index d84212eca5e4..50f3204f4c1d 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -58,6 +58,186 @@ -->
+

22 May 2022

+

ToasterBiome updated:

+
    +
  • fixes runtime in forceMove if you move to some place without a turf
  • +
+

nmajask updated:

+
    +
  • Carbons can now be embedded with objects.
  • +
  • Removing embedded objects now uses a radial menu.
  • +
  • Embeds now respect armor.
  • +
+ +

21 May 2022

+

@cuackles updated:

+
    +
  • Added goat king loot
  • +
  • added sprite for scanner
  • +
+

[IndieanaJones](https://github.com/IndieanaJones) and [Watermelon914](https://github.com/Watermelon914), ported to Yogstation by SuperSlayer updated:

+
    +
  • Ports some PR's from TG that add some midround rulesets for dynamic
  • +
+

MajManatee updated:

+
    +
  • Swaps the position of the filing cabinet, paper shredder, and armor storage on YogBox
  • +
+

Mqiib updated:

+
    +
  • Dying in bat form now actually hurts
  • +
+

SomeguyManperson updated:

+
    +
  • welders now respect attack cooldowns when repairing limbs
  • +
+

ToasterBiome updated:

+
    +
  • Fixes lag when server is above 60 population
  • +
+

TymurShatillo updated:

+
    +
  • Adds plague rat - VERY MINOR midround antagonist
  • +
  • Adds plague disease
  • +
+

UselessTheremin updated:

+
    +
  • no more becoming a spaghetti creature with dwarfism
  • +
+

cuackles updated:

+
    +
  • Added new ckey donor exclusive item
  • +
  • added some icons and images for said donor item
  • +
+ +

20 May 2022

+

SomeguyManperson updated:

+
    +
  • TONS of stuff that is supposed to deal burn damage no longer does literally fucking nothing because it's trying to deal "fire" damage
  • +
+ +

18 May 2022

+

Chubbygummibear updated:

+
    +
  • blood level is persistent through monkey transforming
  • +
  • proper blood scaling between monkey and human
  • +
+

MajManatee updated:

+
    +
  • The crafting recipe for the Uranium Slugs actually works now
  • +
+ +

17 May 2022

+

@cuackles, MajesticManateee updated:

+
    +
  • Adds new donor beret for myself
  • +
  • added sprites for said beret
  • +
+

Cakey, Cajoes, Ghommie updated:

+
    +
  • added 3/4 sprites for paper bins, paper shredders, fax machines, and towel bins
  • +
+

Mqiib, Nmajask updated:

+
    +
  • The hivemind has found DNA blueprints for a devastating new weapon: the flesh maul!
  • +
  • Fixes the changeling tentacle arm sprites being backwards
  • +
  • Sprites for new ling item
  • +
  • Balance decisions pending
  • +
+

TemporalOroboros updated:

+
    +
  • Added defines for the damage flags. Please use them!
  • +
+

[tralezab](https://github.com/tralezab), ported to Yogstation by SuperSlayer updated:

+
    +
  • Simplemobs now have healthdolls
  • +
+

ArcaneMusic, MrDoomBringer, ynot01 updated:

+
    +
  • Added Medical Kiosk
  • +
+

Chubbygummibear updated:

+
    +
  • Inducers can be used to charge Preternis but this process burns them
  • +
+

Fikou, ported by TheGamerDK updated:

+
    +
  • Secret Gateways can now be a thing enabled by config. They are not on the repository, instead, loaded from a config folder.
  • +
  • Adds the secret and anti-phasing z level traits used by Secret Gateways, secret prevents observers from looking at the z level in any way other than observing through another player's eyes
  • +
  • admin loaded away missions can be secret as well
  • +
+

JohnFulpWillard, Tatax, ToastyBiome updated:

+
    +
  • bloodsucker bugfixes
  • +
+

MajManatee updated:

+
    +
  • Adds Depleted Uranium Slugs
  • +
  • Adds Cryoshot buckshot shells
  • +
  • adds unique shells and projectiles for both ammo types
  • +
  • Adds cool new electrical buckshot ammo
  • +
  • adds a new yellow, electrically charged shell
  • +
+

Marmio64 updated:

+
    +
  • Monster hunter gets interactions with demons of sin
  • +
+

SomeguyManperson updated:

+
    +
  • non-combat mechs can no longer throw people
  • +
  • Both advanced stack healing items (adv mesh + medicated suture) have had their stack size increased by 10
  • +
  • Advanced sutures are applied to wounds twice as fast as normal sutures
  • +
  • sutures now have 15 items in each stack isntead of 10 because why 10 when mesh has 15
  • +
  • touch healing chems (silver sulf/styptic) now heal 75% less damage passively (no change to on touch healing), and can only heal on touch for up to 45 points of damage/chemical
  • +
  • touch healing chems (silver sulf/styptic) now apply their reagent to the bloodstream when splashed
  • +
  • lesser form now costs 1 dna and 5 chemicals, cannot be used if stunned or cuffed
  • +
  • new emote pointdown
  • +
  • embeds will act more often when standing instead of acting more often when lying down
  • +
  • sandbag icon should be back
  • +
+

TheGamerdk updated:

+
    +
  • An area with an AI data core can no longer experience power failure from random events
  • +
  • The Sig Tech has been renamed to Network Admin and is now in charge of general AI upgrades
  • +
  • The Network Admin can combine CPUs and RAM to create racks to upgrade the AI, instead of using individual cards.
  • +
  • This is done using the new rack creator machine. You insert printed CPUs and then add RAM sticks. Then you finalize and it will print the full rack.
  • +
  • The AI is now upgraded by inserting server racks into expansion card holders (Now called server cabinets)
  • +
  • The Network Admin can now overclock CPUs in their workshop. Increase the speed as much as possible while minimizing the power draw!
  • +
  • Adds up to tier 3/4 AI hardware, unlockable through Research.
  • +
  • AI cpu now works off of percentage, adds support for fractional CPU speeds (Overclocking)
  • +
  • Fixes off-station hijacking and downloading of the AI
  • +
+

ToasterBiome updated:

+
    +
  • marrow weaver drop uranium
  • +
+

adamsong updated:

+
    +
  • Added more notification methods for tickets with no present admins
  • +
+

cuackles updated:

+
    +
  • new snack, vermin bites
  • +
  • new snack sprites, vermin bites
  • +
  • Added new makeshift item: makeshift ID
  • +
  • added some icons for the makeshift ID
  • +
+

maxion12345 updated:

+
    +
  • Added new airlock to secondary datacore and added secondary datacore to event blacklist for APC failure and anomalies.
  • +
+

nmajask updated:

+
    +
  • Added chance for felinids and lizards to wag their tail when they are happy and if they aren't doing so already
  • +
  • Added human subtypes for some species that were missing them, making it posable to spawn them in with spawn
  • +
+

ynot01 updated:

+
    +
  • Fixed being able to interact with cryo cells from within
  • +
  • Throwing a body at the wall is no longer silent
  • +
+

16 May 2022

ToasterBiome, tatax updated:

    @@ -1977,88 +2157,6 @@
  • Added a second set of weights to make ion lawsets independent from roundstart lawsets
  • Adds a separate probability for adding an ion law, allowing it to be tweaked separate from other ion effects
- -

20 February 2022

-

Imaginos16 updated:

-
    -
  • Removes soul from the Security TV, Smartfridge, and Booze-o-Mat
  • -
-

Xoxeyos updated:

-
    -
  • AI Core Tutorial disk can now be found in the RD's office and AI sat on YogsBox.
  • -
-

tattax updated:

-
    -
  • hammer now looks epic
  • -
  • blue hamoroo is gone
  • -
- -

19 February 2022

-

TheGamerdk updated:

-
    -
  • The AI core on Boxstation has been properly fortified. No more avoiding turrets or spacing the room to kill the AI.
  • -
- -

18 February 2022

-

TheGamerdk updated:

-
    -
  • Swimming pool -> swimming pool
  • -
-

tattax updated:

-
    -
  • mice now cheese up on cheesie honkers
  • -
-

wejengin2 updated:

-
    -
  • fixes an airlock to space on meta
  • -
- -

17 February 2022

-

ToasterBiome updated:

-
    -
  • fixes anomaly cores dropping on every blob tile destruction
  • -
  • no bible antimagic if you are a powergamer
  • -
-

nmajask updated:

-
    -
  • fixed mining medic's PDA not being assigned to them round start
  • -
- -

16 February 2022

-

JamieD1 updated:

-
    -
  • Blob now drops anomaly core on death
  • -
-

wejengin2 updated:

-
    -
  • fixed a typo in topkake description
  • -
- -

15 February 2022

-

Xoxeyos updated:

-
    -
  • Eclipse now has a secondary AI datacore south of the RD's office.
  • -
  • New tutorial holodisk for creation of AI cores, you will find these within your local RD's office, or within the AI data core storage, depending on the station.
  • -
  • OmegaStation now has a proper AI core.
  • -
  • Fixed a fucked up door in front of a table.
  • -
  • Removed a stray wire on Omega.
  • -
-

Anvilman6 updated:

-
    -
  • Updated syntax and wording on the "AI Changes" roundstart informational announcement
  • -
-

TheGamerdk updated:

-
    -
  • AI Projects have the ability to give active abilities
  • -
  • New project allows AI to charge a borg remotely
  • -
  • New project allows AI to keep APC operational even without power for a short duration
  • -
  • New project that notifies the AI when a tagged individual re-enters camera view.
  • -
  • Adds AI abilities that can be recharged by using CPU power
  • -
-

UselessTheremin updated:

-
    -
  • wheelchairs can now use turnstiles
  • -
GoonStation 13 Development Team diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index b98e07c28dbf..68019a2b4d1c 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -31517,3 +31517,137 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. ToasterBiome: - tweak: makes tape recursively check contents to make sure theres no grenades or explosives in the taped item +2022-05-17: + ' @cuackles, MajesticManateee': + - rscadd: Adds new donor beret for myself + - imageadd: added sprites for said beret + ' Cakey, Cajoes, Ghommie': + - imageadd: added 3/4 sprites for paper bins, paper shredders, fax machines, and + towel bins + ' Mqiib, Nmajask': + - rscadd: 'The hivemind has found DNA blueprints for a devastating new weapon: the + flesh maul!' + - imageadd: Fixes the changeling tentacle arm sprites being backwards + - imageadd: Sprites for new ling item + - wip: Balance decisions pending + ' TemporalOroboros': + - tweak: Added defines for the damage flags. Please use them! + ' [tralezab](https://github.com/tralezab), ported to Yogstation by SuperSlayer': + - tweak: Simplemobs now have healthdolls + ArcaneMusic, MrDoomBringer, ynot01: + - rscadd: Added Medical Kiosk + Chubbygummibear: + - rscadd: Inducers can be used to charge Preternis but this process burns them + Fikou, ported by TheGamerDK: + - rscadd: Secret Gateways can now be a thing enabled by config. They are not on + the repository, instead, loaded from a config folder. + - rscadd: Adds the secret and anti-phasing z level traits used by Secret Gateways, + secret prevents observers from looking at the z level in any way other than + observing through another player's eyes + - experiment: admin loaded away missions can be secret as well + JohnFulpWillard, Tatax, ToastyBiome: + - bugfix: bloodsucker bugfixes + MajManatee: + - rscadd: Adds Depleted Uranium Slugs + - rscadd: Adds Cryoshot buckshot shells + - imageadd: adds unique shells and projectiles for both ammo types + - rscadd: Adds cool new electrical buckshot ammo + - imageadd: adds a new yellow, electrically charged shell + Marmio64: + - rscadd: Monster hunter gets interactions with demons of sin + SomeguyManperson: + - bugfix: non-combat mechs can no longer throw people + - tweak: Both advanced stack healing items (adv mesh + medicated suture) have had + their stack size increased by 10 + - tweak: Advanced sutures are applied to wounds twice as fast as normal sutures + - tweak: sutures now have 15 items in each stack isntead of 10 because why 10 when + mesh has 15 + - tweak: touch healing chems (silver sulf/styptic) now heal 75% less damage passively + (no change to on touch healing), and can only heal on touch for up to 45 points + of damage/chemical + - tweak: touch healing chems (silver sulf/styptic) now apply their reagent to the + bloodstream when splashed + - tweak: lesser form now costs 1 dna and 5 chemicals, cannot be used if stunned + or cuffed + - rscadd: new emote pointdown + - bugfix: embeds will act more often when standing instead of acting more often + when lying down + - bugfix: sandbag icon should be back + TheGamerdk: + - tweak: An area with an AI data core can no longer experience power failure from + random events + - rscadd: The Sig Tech has been renamed to Network Admin and is now in charge of + general AI upgrades + - rscadd: The Network Admin can combine CPUs and RAM to create racks to upgrade + the AI, instead of using individual cards. + - rscadd: This is done using the new rack creator machine. You insert printed CPUs + and then add RAM sticks. Then you finalize and it will print the full rack. + - rscadd: The AI is now upgraded by inserting server racks into expansion card holders + (Now called server cabinets) + - rscadd: The Network Admin can now overclock CPUs in their workshop. Increase the + speed as much as possible while minimizing the power draw! + - rscadd: Adds up to tier 3/4 AI hardware, unlockable through Research. + - tweak: AI cpu now works off of percentage, adds support for fractional CPU speeds + (Overclocking) + - bugfix: Fixes off-station hijacking and downloading of the AI + ToasterBiome: + - rscadd: marrow weaver drop uranium + adamsong: + - rscadd: Added more notification methods for tickets with no present admins + cuackles: + - rscadd: new snack, vermin bites + - imageadd: new snack sprites, vermin bites + - rscadd: 'Added new makeshift item: makeshift ID' + - imageadd: added some icons for the makeshift ID + maxion12345: + - rscadd: Added new airlock to secondary datacore and added secondary datacore to + event blacklist for APC failure and anomalies. + nmajask: + - rscadd: Added chance for felinids and lizards to wag their tail when they are + happy and if they aren't doing so already + - rscadd: Added human subtypes for some species that were missing them, making it + posable to spawn them in with spawn + ynot01: + - bugfix: Fixed being able to interact with cryo cells from within + - tweak: Throwing a body at the wall is no longer silent +2022-05-18: + Chubbygummibear: + - bugfix: blood level is persistent through monkey transforming + - bugfix: proper blood scaling between monkey and human + MajManatee: + - bugfix: The crafting recipe for the Uranium Slugs actually works now +2022-05-20: + SomeguyManperson: + - bugfix: TONS of stuff that is supposed to deal burn damage no longer does literally + fucking nothing because it's trying to deal "fire" damage +2022-05-21: + ' @cuackles': + - rscadd: Added goat king loot + - imageadd: added sprite for scanner + ? ' [IndieanaJones](https://github.com/IndieanaJones) and [Watermelon914](https://github.com/Watermelon914), + ported to Yogstation by SuperSlayer' + : - rscadd: Ports some PR's from TG that add some midround rulesets for dynamic + MajManatee: + - tweak: Swaps the position of the filing cabinet, paper shredder, and armor storage + on YogBox + Mqiib: + - tweak: Dying in bat form now actually hurts + SomeguyManperson: + - bugfix: welders now respect attack cooldowns when repairing limbs + ToasterBiome: + - experiment: Fixes lag when server is above 60 population + TymurShatillo: + - rscadd: Adds plague rat - VERY MINOR midround antagonist + - rscadd: Adds plague disease + UselessTheremin: + - bugfix: no more becoming a spaghetti creature with dwarfism + cuackles: + - rscadd: Added new ckey donor exclusive item + - imageadd: added some icons and images for said donor item +2022-05-22: + ToasterBiome: + - bugfix: fixes runtime in forceMove if you move to some place without a turf + nmajask: + - tweak: Carbons can now be embedded with objects. + - tweak: Removing embedded objects now uses a radial menu. + - tweak: Embeds now respect armor. diff --git a/html/changelogs/AutoChangelog-pr-13686.yml b/html/changelogs/AutoChangelog-pr-13686.yml deleted file mode 100644 index 3ee62fb4f23f..000000000000 --- a/html/changelogs/AutoChangelog-pr-13686.yml +++ /dev/null @@ -1,11 +0,0 @@ -author: "TheGamerdk" -delete-after: true -changes: - - rscadd: "The Sig Tech has been renamed to Network Admin and is now in charge of general AI upgrades" - - rscadd: "The Network Admin can combine CPUs and RAM to create racks to upgrade the AI, instead of using individual cards." - - rscadd: "This is done using the new rack creator machine. You insert printed CPUs and then add RAM sticks. Then you finalize and it will print the full rack." - - rscadd: "The AI is now upgraded by inserting server racks into expansion card holders (Now called server cabinets)" - - rscadd: "The Network Admin can now overclock CPUs in their workshop. Increase the speed as much as possible while minimizing the power draw!" - - rscadd: "Adds up to tier 3/4 AI hardware, unlockable through Research." - - tweak: "AI cpu now works off of percentage, adds support for fractional CPU speeds (Overclocking)" - - bugfix: "Fixes off-station hijacking and downloading of the AI" diff --git a/html/changelogs/AutoChangelog-pr-13967.yml b/html/changelogs/AutoChangelog-pr-13967.yml deleted file mode 100644 index c4053ae39834..000000000000 --- a/html/changelogs/AutoChangelog-pr-13967.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Fikou, ported by TheGamerDK" -delete-after: true -changes: - - rscadd: "Secret Gateways can now be a thing enabled by config. They are not on the repository, instead, loaded from a config folder." - - rscadd: "Adds the secret and anti-phasing z level traits used by Secret Gateways, secret prevents observers from looking at the z level in any way other than observing through another player's eyes" - - experiment: "admin loaded away missions can be secret as well" diff --git a/html/changelogs/AutoChangelog-pr-14043.yml b/html/changelogs/AutoChangelog-pr-14043.yml deleted file mode 100644 index c4641725e407..000000000000 --- a/html/changelogs/AutoChangelog-pr-14043.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "adamsong" -delete-after: true -changes: - - rscadd: "Added more notification methods for tickets with no present admins" diff --git a/html/changelogs/AutoChangelog-pr-14050.yml b/html/changelogs/AutoChangelog-pr-14050.yml deleted file mode 100644 index 6ee6f3ad7c9b..000000000000 --- a/html/changelogs/AutoChangelog-pr-14050.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: " TemporalOroboros" -delete-after: true -changes: - - tweak: "Added defines for the damage flags. Please use them!" diff --git a/html/changelogs/AutoChangelog-pr-14071.yml b/html/changelogs/AutoChangelog-pr-14071.yml deleted file mode 100644 index c66de7571cf6..000000000000 --- a/html/changelogs/AutoChangelog-pr-14071.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "cuackles" -delete-after: true -changes: - - rscadd: "Added new makeshift item: makeshift ID" - - imageadd: "added some icons for the makeshift ID" diff --git a/html/changelogs/AutoChangelog-pr-14074.yml b/html/changelogs/AutoChangelog-pr-14074.yml deleted file mode 100644 index 28da8c7755e7..000000000000 --- a/html/changelogs/AutoChangelog-pr-14074.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "MajManatee" -delete-after: true -changes: - - rscadd: "Adds cool new electrical buckshot ammo" - - imageadd: "adds a new yellow, electrically charged shell" diff --git a/html/changelogs/AutoChangelog-pr-14083.yml b/html/changelogs/AutoChangelog-pr-14083.yml deleted file mode 100644 index 6a3283644a86..000000000000 --- a/html/changelogs/AutoChangelog-pr-14083.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "cuackles" -delete-after: true -changes: - - rscadd: "new snack, vermin bites" - - imageadd: "new snack sprites, vermin bites" diff --git a/html/changelogs/AutoChangelog-pr-14089.yml b/html/changelogs/AutoChangelog-pr-14089.yml deleted file mode 100644 index b147e81a56e9..000000000000 --- a/html/changelogs/AutoChangelog-pr-14089.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: " [tralezab](https://github.com/tralezab), ported to Yogstation by SuperSlayer" -delete-after: true -changes: - - tweak: "Simplemobs now have healthdolls" diff --git a/html/changelogs/AutoChangelog-pr-14091.yml b/html/changelogs/AutoChangelog-pr-14091.yml deleted file mode 100644 index b2c32d2ab6e0..000000000000 --- a/html/changelogs/AutoChangelog-pr-14091.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ArcaneMusic, MrDoomBringer, ynot01" -delete-after: true -changes: - - rscadd: "Added Medical Kiosk" diff --git a/html/changelogs/AutoChangelog-pr-14093.yml b/html/changelogs/AutoChangelog-pr-14093.yml deleted file mode 100644 index e83292f62d8c..000000000000 --- a/html/changelogs/AutoChangelog-pr-14093.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ynot01" -delete-after: true -changes: - - tweak: "Throwing a body at the wall is no longer silent" diff --git a/html/changelogs/AutoChangelog-pr-14096.yml b/html/changelogs/AutoChangelog-pr-14096.yml deleted file mode 100644 index d819aa2b68ed..000000000000 --- a/html/changelogs/AutoChangelog-pr-14096.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SomeguyManperson" -delete-after: true -changes: - - bugfix: "sandbag icon should be back" diff --git a/html/changelogs/AutoChangelog-pr-14097.yml b/html/changelogs/AutoChangelog-pr-14097.yml deleted file mode 100644 index eb4619956d15..000000000000 --- a/html/changelogs/AutoChangelog-pr-14097.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "MajManatee" -delete-after: true -changes: - - rscadd: "Adds Depleted Uranium Slugs" - - rscadd: "Adds Cryoshot buckshot shells" - - imageadd: "adds unique shells and projectiles for both ammo types" diff --git a/html/changelogs/AutoChangelog-pr-14105.yml b/html/changelogs/AutoChangelog-pr-14105.yml deleted file mode 100644 index 869463edcf5e..000000000000 --- a/html/changelogs/AutoChangelog-pr-14105.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: " @cuackles, MajesticManateee" -delete-after: true -changes: - - rscadd: "Adds new donor beret for myself" - - imageadd: "added sprites for said beret" diff --git a/html/changelogs/AutoChangelog-pr-14116.yml b/html/changelogs/AutoChangelog-pr-14116.yml deleted file mode 100644 index 87ec1977f13c..000000000000 --- a/html/changelogs/AutoChangelog-pr-14116.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SomeguyManperson" -delete-after: true -changes: - - tweak: "lesser form now costs 1 dna and 5 chemicals, cannot be used if stunned or cuffed" diff --git a/html/changelogs/AutoChangelog-pr-14117.yml b/html/changelogs/AutoChangelog-pr-14117.yml deleted file mode 100644 index 4de701b48fc2..000000000000 --- a/html/changelogs/AutoChangelog-pr-14117.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SomeguyManperson" -delete-after: true -changes: - - bugfix: "non-combat mechs can no longer throw people" diff --git a/html/changelogs/AutoChangelog-pr-14119.yml b/html/changelogs/AutoChangelog-pr-14119.yml deleted file mode 100644 index 7d3fa1508de2..000000000000 --- a/html/changelogs/AutoChangelog-pr-14119.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ynot01" -delete-after: true -changes: - - bugfix: "Fixed being able to interact with cryo cells from within" diff --git a/html/changelogs/AutoChangelog-pr-14122.yml b/html/changelogs/AutoChangelog-pr-14122.yml deleted file mode 100644 index 1f1140853148..000000000000 --- a/html/changelogs/AutoChangelog-pr-14122.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: " Mqiib, Nmajask" -delete-after: true -changes: - - rscadd: "The hivemind has found DNA blueprints for a devastating new weapon: the flesh maul!" - - imageadd: "Fixes the changeling tentacle arm sprites being backwards" - - imageadd: "Sprites for new ling item" - - wip: "Balance decisions pending" diff --git a/html/changelogs/AutoChangelog-pr-14126.yml b/html/changelogs/AutoChangelog-pr-14126.yml deleted file mode 100644 index 54b72324bd4f..000000000000 --- a/html/changelogs/AutoChangelog-pr-14126.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "JohnFulpWillard, Tatax, ToastyBiome" -delete-after: true -changes: - - bugfix: "bloodsucker bugfixes" diff --git a/html/changelogs/AutoChangelog-pr-14129.yml b/html/changelogs/AutoChangelog-pr-14129.yml deleted file mode 100644 index cd4c72cac20f..000000000000 --- a/html/changelogs/AutoChangelog-pr-14129.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Marmio64" -delete-after: true -changes: - - rscadd: "Monster hunter gets interactions with demons of sin" diff --git a/html/changelogs/AutoChangelog-pr-14135.yml b/html/changelogs/AutoChangelog-pr-14135.yml deleted file mode 100644 index 6c985b31d7b9..000000000000 --- a/html/changelogs/AutoChangelog-pr-14135.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "SomeguyManperson" -delete-after: true -changes: - - tweak: "touch healing chems (silver sulf/styptic) now heal 75% less damage passively (no change to on touch healing), and can only heal on touch for up to 45 points of damage/chemical" - - tweak: "touch healing chems (silver sulf/styptic) now apply their reagent to the bloodstream when splashed" diff --git a/html/changelogs/AutoChangelog-pr-14137.yml b/html/changelogs/AutoChangelog-pr-14137.yml deleted file mode 100644 index 2dd8b4261917..000000000000 --- a/html/changelogs/AutoChangelog-pr-14137.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ToasterBiome" -delete-after: true -changes: - - rscadd: "marrow weaver drop uranium" diff --git a/html/changelogs/AutoChangelog-pr-14139.yml b/html/changelogs/AutoChangelog-pr-14139.yml deleted file mode 100644 index 971a9b758fcc..000000000000 --- a/html/changelogs/AutoChangelog-pr-14139.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: " Cakey, Cajoes, Ghommie" -delete-after: true -changes: - - imageadd: "added 3/4 sprites for paper bins, paper shredders, fax machines, and towel bins" diff --git a/html/changelogs/AutoChangelog-pr-14142.yml b/html/changelogs/AutoChangelog-pr-14142.yml deleted file mode 100644 index 7f503c1888f2..000000000000 --- a/html/changelogs/AutoChangelog-pr-14142.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "SomeguyManperson" -delete-after: true -changes: - - tweak: "Both advanced stack healing items (adv mesh + medicated suture) have had their stack size increased by 10" - - tweak: "Advanced sutures are applied to wounds twice as fast as normal sutures" - - tweak: "sutures now have 15 items in each stack isntead of 10 because why 10 when mesh has 15" diff --git a/html/changelogs/AutoChangelog-pr-14145.yml b/html/changelogs/AutoChangelog-pr-14145.yml deleted file mode 100644 index 239cb6e9cc71..000000000000 --- a/html/changelogs/AutoChangelog-pr-14145.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SomeguyManperson" -delete-after: true -changes: - - rscadd: "new emote pointdown" diff --git a/html/changelogs/AutoChangelog-pr-14149.yml b/html/changelogs/AutoChangelog-pr-14149.yml deleted file mode 100644 index 294f4aad41d4..000000000000 --- a/html/changelogs/AutoChangelog-pr-14149.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "maxion12345" -delete-after: true -changes: - - rscadd: "Added new airlock to secondary datacore and added secondary datacore to event blacklist for APC failure and anomalies." diff --git a/html/changelogs/AutoChangelog-pr-14150.yml b/html/changelogs/AutoChangelog-pr-14150.yml deleted file mode 100644 index fa23d8400df2..000000000000 --- a/html/changelogs/AutoChangelog-pr-14150.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheGamerdk" -delete-after: true -changes: - - tweak: "An area with an AI data core can no longer experience power failure from random events" diff --git a/html/changelogs/AutoChangelog-pr-14151.yml b/html/changelogs/AutoChangelog-pr-14151.yml deleted file mode 100644 index 18555238bf45..000000000000 --- a/html/changelogs/AutoChangelog-pr-14151.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Chubbygummibear" -delete-after: true -changes: - - rscadd: "Inducers can be used to charge Preternis but this process burns them" diff --git a/html/changelogs/AutoChangelog-pr-14152.yml b/html/changelogs/AutoChangelog-pr-14152.yml deleted file mode 100644 index 70442bd3c5b4..000000000000 --- a/html/changelogs/AutoChangelog-pr-14152.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SomeguyManperson" -delete-after: true -changes: - - bugfix: "embeds will act more often when standing instead of acting more often when lying down" diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index fac6642ca423..5551f92f715c 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 4beba9fd6cb0..da2652ccbf98 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 5cb6dfd0d03f..241d639a114d 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/sound/ambience/antag/blobalert.ogg b/sound/ambience/antag/blobalert.ogg new file mode 100644 index 000000000000..c9fcfbee4489 Binary files /dev/null and b/sound/ambience/antag/blobalert.ogg differ diff --git a/yogstation.dme b/yogstation.dme index 8bcd39b50e8d..20f125d7284b 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -509,6 +509,7 @@ #include "code\datums\diseases\magnitis.dm" #include "code\datums\diseases\parrotpossession.dm" #include "code\datums\diseases\pierrot_throat.dm" +#include "code\datums\diseases\plague.dm" #include "code\datums\diseases\retrovirus.dm" #include "code\datums\diseases\rhumba_beat.dm" #include "code\datums\diseases\sleepy.dm" @@ -2537,6 +2538,7 @@ #include "code\modules\mob\living\simple_animal\hostile\nanotrasen.dm" #include "code\modules\mob\living\simple_animal\hostile\netherworld.dm" #include "code\modules\mob\living\simple_animal\hostile\pirate.dm" +#include "code\modules\mob\living\simple_animal\hostile\plague_rat.dm" #include "code\modules\mob\living\simple_animal\hostile\rat.dm" #include "code\modules\mob\living\simple_animal\hostile\regalrat.dm" #include "code\modules\mob\living\simple_animal\hostile\russian.dm" diff --git a/yogstation/code/game/gamemodes/vampire/vampire_bat.dm b/yogstation/code/game/gamemodes/vampire/vampire_bat.dm index 9211e678ae71..10fa8338cb89 100644 --- a/yogstation/code/game/gamemodes/vampire/vampire_bat.dm +++ b/yogstation/code/game/gamemodes/vampire/vampire_bat.dm @@ -49,6 +49,7 @@ mind.transfer_to(controller) controller.status_flags &= ~GODMODE controller.Knockdown(120) - to_chat(controller, span_userdanger("The force of being exiled from your bat form knocks you down!")) + controller.adjustBruteLoss(20) + to_chat(controller, span_userdanger("The force of being exiled from your bat form painfully throws you to the ground!")) qdel() . = ..() \ No newline at end of file diff --git a/yogstation/code/modules/donor/unique_donator_items.dm b/yogstation/code/modules/donor/unique_donator_items.dm index 0acf23c2e235..bb5158c1d6c4 100644 --- a/yogstation/code/modules/donor/unique_donator_items.dm +++ b/yogstation/code/modules/donor/unique_donator_items.dm @@ -140,6 +140,11 @@ Uncomment this and use atomproccall as necessary, then copypaste the output into ckey = "Majesticmanateee" unlock_path = /obj/item/clothing/head/peacekeeperberet +/datum/donator_gear/Hisakaki + name = "Transdimensional halo" + ckey = "Hisakaki" + unlock_path = /obj/item/clothing/head/halo + ///Generic donator hats, ckey agnostic. /datum/donator_gear/beanie name = "Beanie" diff --git a/yogstation/code/modules/mob/living/carbon/human/human.dm b/yogstation/code/modules/mob/living/carbon/human/human.dm index b24d66fb7edf..0eca183532ba 100644 --- a/yogstation/code/modules/mob/living/carbon/human/human.dm +++ b/yogstation/code/modules/mob/living/carbon/human/human.dm @@ -4,7 +4,16 @@ /mob/living/carbon/human/species/egg race = /datum/species/egg +/mob/living/carbon/human/species/preternis + race = /datum/species/preternis + +/mob/living/carbon/human/species/lizard/ashwalker/cosmic + race = /datum/species/lizard/ashwalker/cosmic + +/mob/living/carbon/human/species/szlachta + race = /datum/species/szlachta + /mob/living/carbon/human/get_blood_state() if(NOBLOOD in dna.species.species_traits) //Can't have blood problems if your species doesn't have any blood, innit? return BLOOD_SAFE - . = ..() \ No newline at end of file + . = ..() diff --git a/yogstation/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm b/yogstation/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm index 87ee10f354cd..c89b0f58df8b 100644 --- a/yogstation/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm +++ b/yogstation/code/modules/mob/living/simple_animal/hostile/retaliate/king_of_goats.dm @@ -289,7 +289,8 @@ Difficulty: Insanely Hard visible_message(span_cult("\The [src] shrieks as the seal on his power breaks and he starts to break apart!")) new /obj/structure/ladder/unbreakable/goat(loc) new /obj/item/toy/plush/goatplushie/angry/kinggoat(loc) //If someone dies from this after beating the king goat im going to laugh - + new /obj/item/t_scanner/adv_mining_scanner/goat_scanner(loc) + /mob/living/simple_animal/hostile/retaliate/goat/king/death() ..() OnDeath()