diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm
index 7be3533d47..60fb49f780 100644
--- a/code/__DEFINES/DNA.dm
+++ b/code/__DEFINES/DNA.dm
@@ -105,6 +105,7 @@
#define MATRIXED 22 //if icon is color matrix'd
#define SKINTONE 23 //uses skin tones
#define HORNCOLOR 24
+#define WINGCOLOR 25
//organ slots
#define ORGAN_SLOT_BRAIN "brain"
diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm
index c9d545fc03..c2021a86f2 100644
--- a/code/__DEFINES/access.dm
+++ b/code/__DEFINES/access.dm
@@ -6,7 +6,7 @@
#define ACCESS_MORGUE 6
#define ACCESS_TOX 7 //R&D department, R&D console, burn chamber on some maps
#define ACCESS_TOX_STORAGE 8 //Toxins storage, burn chamber on some maps
-#define ACCESS_GENETICS 9
+#define ACCESS_GENETICS 9
#define ACCESS_ENGINE 10 //Engineering area, power monitor, power flow control console
#define ACCESS_ENGINE_EQUIP 11 //APCs, EngiVend/YouTool, engineering equipment lockers
#define ACCESS_MAINT_TUNNELS 12
@@ -64,6 +64,8 @@
#define ACCESS_WEAPONS 66 //Weapon authorization for secbots
#define ACCESS_NETWORK 67 //NTnet diagnostics/monitoring software
#define ACCESS_CLONING 68 //Cloning room and clone pod ejection
+#define ACCESS_ENTER_GENPOP 69
+#define ACCESS_LEAVE_GENPOP 70
//BEGIN CENTCOM ACCESS
/*Should leave plenty of room if we need to add more access levels.
diff --git a/code/__DEFINES/clockcult.dm b/code/__DEFINES/clockcult.dm
index 47b00e67f7..2f2f94413b 100644
--- a/code/__DEFINES/clockcult.dm
+++ b/code/__DEFINES/clockcult.dm
@@ -8,6 +8,7 @@
GLOBAL_VAR_INIT(clockwork_construction_value, 0) //The total value of all structures built by the clockwork cult
GLOBAL_VAR_INIT(clockwork_vitality, 0) //How much Vitality is stored, total
GLOBAL_VAR_INIT(clockwork_power, 0) //How many watts of power are globally available to the clockwork cult
+GLOBAL_VAR_INIT(neovgre_exists, 0) //Does neovgre exist?
GLOBAL_LIST_EMPTY(all_clockwork_objects) //All clockwork items, structures, and effects in existence
GLOBAL_LIST_EMPTY(all_clockwork_mobs) //All clockwork SERVANTS (not creatures) in existence
diff --git a/code/__DEFINES/movespeed_modification.dm b/code/__DEFINES/movespeed_modification.dm
index 4336ad28f7..12a3c331ec 100644
--- a/code/__DEFINES/movespeed_modification.dm
+++ b/code/__DEFINES/movespeed_modification.dm
@@ -33,4 +33,6 @@
#define MOVESPEED_ID_SANITY "MOOD_SANITY"
#define MOVESPEED_ID_PRONE_DRAGGING "PRONE_DRAG"
-#define MOVESPEED_ID_HUMAN_CARRYING "HUMAN_CARRY"
\ No newline at end of file
+#define MOVESPEED_ID_HUMAN_CARRYING "HUMAN_CARRY"
+
+#define MOVESPEED_ID_TASED_STATUS "TASED"
\ No newline at end of file
diff --git a/code/__DEFINES/reactions.dm b/code/__DEFINES/reactions.dm
index 7cebc37d94..9579571174 100644
--- a/code/__DEFINES/reactions.dm
+++ b/code/__DEFINES/reactions.dm
@@ -31,41 +31,14 @@
#define STIMULUM_RESEARCH_AMOUNT 50
//Plasma fusion properties
#define FUSION_ENERGY_THRESHOLD 3e9 //Amount of energy it takes to start a fusion reaction
-#define FUSION_TEMPERATURE_THRESHOLD 1000 //Temperature required to start a fusion reaction
#define FUSION_MOLE_THRESHOLD 250 //Mole count required (tritium/plasma) to start a fusion reaction
-#define FUSION_RELEASE_ENERGY_SUPER 3e9 //Amount of energy released in the fusion process, super tier
-#define FUSION_RELEASE_ENERGY_HIGH 1e9 //Amount of energy released in the fusion process, high tier
-#define FUSION_RELEASE_ENERGY_MID 5e8 //Amount of energy released in the fusion process, mid tier
-#define FUSION_RELEASE_ENERGY_LOW 1e8 //Amount of energy released in the fusion process, low tier
-#define FUSION_MEDIATION_FACTOR 80 //Arbitrary
-#define FUSION_SUPER_TIER_THRESHOLD 50 //anything above this is super tier
-#define FUSION_HIGH_TIER_THRESHOLD 20 //anything above this and below 50 is high tier
-#define FUSION_MID_TIER_THRESHOLD 5 //anything above this and below 20 is mid tier - below this is low tier, but that doesnt need a define
-#define FUSION_ENERGY_DIVISOR_SUPER 25 //power_ratio is divided by this during energy calculations
-#define FUSION_ENERGY_DIVISOR_HIGH 20
-#define FUSION_ENERGY_DIVISOR_MID 10
-#define FUSION_ENERGY_DIVISOR_LOW 2
-#define FUSION_GAS_CREATION_FACTOR_TRITIUM 0.40 //trit - one gas rather than two, so think about that when calculating stuff - 40% in total
-#define FUSION_GAS_CREATION_FACTOR_STIM 0.05 //stim percentage creation from high tier - 5%, 60% in total with pluox
-#define FUSION_GAS_CREATION_FACTOR_PLUOX 0.55 //pluox percentage creation from high tier - 55%, 60% in total with stim
-#define FUSION_GAS_CREATION_FACTOR_NITRYL 0.20 //nitryl and N2O - 80% in total
-#define FUSION_GAS_CREATION_FACTOR_N2O 0.60 //nitryl and N2O - 80% in total
-#define FUSION_GAS_CREATION_FACTOR_BZ 0.05 //BZ - 5% - 90% in total with CO2
-#define FUSION_GAS_CREATION_FACTOR_CO2 0.85 //CO2 - 85% - 90% in total with BZ
-#define FUSION_MID_TIER_RAD_PROB_FACTOR 2 //probability of radpulse is power ratio * this for whatever tier
-#define FUSION_LOW_TIER_RAD_PROB_FACTOR 5
-#define FUSION_EFFICIENCY_BASE 60 //used in the fusion efficiency calculations
-#define FUSION_EFFICIENCY_DIVISOR 0.6 //ditto
-#define FUSION_RADIATION_FACTOR 15000 //horizontal asymptote
-#define FUSION_RADIATION_CONSTANT 30 //equation is form of (ax) / (x + b), where a = radiation factor and b = radiation constant and x = power ratio (https://www.desmos.com/calculator/4i1f296phl)
-#define FUSION_ZAP_POWER_ASYMPTOTE 50000 //maximum value - not enough to instacrit but it'll still hurt like shit
-#define FUSION_ZAP_POWER_CONSTANT 75 //equation is of from [ax / (x + b)] + c, where a = zap power asymptote, b = zap power constant, c = zap power base and x = power ratio
-#define FUSION_ZAP_POWER_BASE 1000 //(https://www.desmos.com/calculator/vvbmhf4unm)
-#define FUSION_ZAP_RANGE_SUPER 9 //range of the tesla zaps that occur from fusion
-#define FUSION_ZAP_RANGE_HIGH 7
-#define FUSION_ZAP_RANGE_MID 5
-#define FUSION_ZAP_RANGE_LOW 3
-#define FUSION_PARTICLE_FACTOR_SUPER 4 //# of particles fired out is equal to rand(3,6) * this for whatever tier
-#define FUSION_PARTICLE_FACTOR_HIGH 3
-#define FUSION_PARTICLE_FACTOR_MID 2
-#define FUSION_PARTICLE_FACTOR_LOW 1
+#define FUSION_TRITIUM_CONVERSION_COEFFICIENT (1e-10)
+#define INSTABILITY_GAS_POWER_FACTOR 0.003
+#define FUSION_TRITIUM_MOLES_USED 1
+#define PLASMA_BINDING_ENERGY 20000000
+#define TOROID_VOLUME_BREAKEVEN 1000
+#define FUSION_TEMPERATURE_THRESHOLD 10000
+#define PARTICLE_CHANCE_CONSTANT (-20000000)
+#define FUSION_RAD_MAX 2000
+#define FUSION_RAD_COEFFICIENT (-1000)
+#define FUSION_INSTABILITY_ENDOTHERMALITY 2
diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm
index 0820d63247..a05e6f6160 100644
--- a/code/__DEFINES/robots.dm
+++ b/code/__DEFINES/robots.dm
@@ -50,3 +50,7 @@
#define ASSEMBLY_THIRD_STEP 2
#define ASSEMBLY_FOURTH_STEP 3
#define ASSEMBLY_FIFTH_STEP 4
+
+
+//Checks to determine borg availability depending on the server's config. These are defines in the interest of reducing copypasta
+#define BORG_SEC_AVAILABLE (!CONFIG_GET(flag/disable_secborg) && GLOB.security_level >= CONFIG_GET(number/minimum_secborg_alert))
\ No newline at end of file
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index 3cd64af8c7..332d36f2f4 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -44,6 +44,8 @@
#define STATUS_EFFECT_SLEEPING /datum/status_effect/incapacitating/sleeping //the affected is asleep
+#define STATUS_EFFECT_TASED /datum/status_effect/electrode //the affected has been tased, preventing fine muscle control
+
#define STATUS_EFFECT_PACIFY /datum/status_effect/pacify //the affected is pacified, preventing direct hostile actions
#define STATUS_EFFECT_BELLIGERENT /datum/status_effect/belligerent //forces the affected to walk, doing damage if they try to run
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 39d58ec15a..19d126f08f 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -400,6 +400,12 @@ GLOBAL_LIST_EMPTY(species_list)
. = 0
break
+ if(isliving(user))
+ var/mob/living/L = user
+ if(L.recoveringstam)
+ . = 0
+ break
+
if(!QDELETED(Tloc) && (QDELETED(target) || Tloc != target.loc))
if((Uloc != Tloc || Tloc != user) && !drifting)
. = 0
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index cfd57b4850..cf0caebb61 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -70,6 +70,9 @@
/datum/config_entry/flag/disable_peaceborg
+/datum/config_entry/number/minimum_secborg_alert //Minimum alert level for secborgs to be chosen.
+ config_entry_value = 3
+
/datum/config_entry/number/traitor_scaling_coeff //how much does the amount of players get divided by to determine traitors
config_entry_value = 6
min_val = 1
diff --git a/code/datums/components/storage/concrete/pockets.dm b/code/datums/components/storage/concrete/pockets.dm
index 84be4fdca4..fe5e1e5217 100644
--- a/code/datums/components/storage/concrete/pockets.dm
+++ b/code/datums/components/storage/concrete/pockets.dm
@@ -56,7 +56,7 @@
/obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector,
/obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/dropper,
/obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini,
- /obj/item/firing_pin
+ /obj/item/firing_pin, /obj/item/gun/ballistic/automatic/pistol/mag
))
/datum/component/storage/concrete/pockets/shoes/clown/Initialize()
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index da59c79ac5..186c988595 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -80,6 +80,36 @@
desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are."
icon_state = "asleep"
+//TASER
+/datum/status_effect/electrode
+ id = "tased"
+ blocks_combatmode = TRUE
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+
+/datum/status_effect/electrode/on_creation(mob/living/new_owner, set_duration)
+ if(isnum(set_duration))
+ duration = set_duration
+ . = ..()
+ if(iscarbon(owner))
+ var/mob/living/carbon/C = owner
+ if(C.combatmode)
+ C.toggle_combat_mode(TRUE)
+ C.add_movespeed_modifier(MOVESPEED_ID_TASED_STATUS, TRUE, override = TRUE, multiplicative_slowdown = 8)
+
+/datum/status_effect/electrode/on_remove()
+ if(iscarbon(owner))
+ var/mob/living/carbon/C = owner
+ C.remove_movespeed_modifier(MOVESPEED_ID_TASED_STATUS)
+ . = ..()
+
+/datum/status_effect/electrode/tick()
+ if(owner)
+ owner.adjustStaminaLoss(5) //if you really want to try to stamcrit someone with a taser alone, you can, but it'll take time and good timing.
+
+/datum/status_effect/electrode/nextmove_modifier() //why is this a proc. its no big deal since this doesnt get called often at all but literally w h y
+ return 2
+
//OTHER DEBUFFS
/datum/status_effect/his_wrath //does minor damage over time unless holding His Grace
id = "his_wrath"
diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm
index c8bcd831e2..bc1cfba112 100644
--- a/code/datums/status_effects/status_effect.dm
+++ b/code/datums/status_effects/status_effect.dm
@@ -11,6 +11,7 @@
var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted
var/examine_text //If defined, this text will appear when the mob is examined - to use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves
var/alert_type = /obj/screen/alert/status_effect //the alert thrown by the status effect, contains name and description
+ var/blocks_combatmode //Does this status effect prevent the user from toggling combat mode?
var/obj/screen/alert/status_effect/linked_alert = null //the alert itself, if it exists
/datum/status_effect/New(list/arguments)
diff --git a/code/datums/weather/weather_types/radiation_storm.dm b/code/datums/weather/weather_types/radiation_storm.dm
index f3b8118087..6765cdf2cd 100644
--- a/code/datums/weather/weather_types/radiation_storm.dm
+++ b/code/datums/weather/weather_types/radiation_storm.dm
@@ -18,7 +18,7 @@
area_type = /area
protected_areas = list(/area/maintenance, /area/ai_monitored/turret_protected/ai_upload, /area/ai_monitored/turret_protected/ai_upload_foyer,
- /area/ai_monitored/turret_protected/ai, /area/storage/emergency/starboard, /area/storage/emergency/port, /area/shuttle)
+ /area/ai_monitored/turret_protected/ai, /area/storage/emergency/starboard, /area/storage/emergency/port, /area/shuttle, /area/security/prison)
target_trait = ZTRAIT_STATION
immunity_type = "rad"
diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm
index d4fe3e27a2..c912586ea3 100644
--- a/code/game/machinery/computer/medical.dm
+++ b/code/game/machinery/computer/medical.dm
@@ -575,7 +575,7 @@
if(user)
if(message)
if(authenticated)
- if(user.canUseTopic(src, BE_CLOSE))
+ if(user.canUseTopic(src, !issilicon(user)))
if(!record1 || record1 == active1)
if(!record2 || record2 == active2)
return 1
diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm
index 1823e34100..efb1039b8b 100644
--- a/code/game/machinery/computer/security.dm
+++ b/code/game/machinery/computer/security.dm
@@ -801,7 +801,7 @@ What a mess.*/
/obj/machinery/computer/secure_data/proc/canUseSecurityRecordsConsole(mob/user, message1 = 0, record1, record2)
if(user)
if(authenticated)
- if(user.canUseTopic(src, BE_CLOSE))
+ if(user.canUseTopic(src, !issilicon(user)))
if(!trim(message1))
return 0
if(!record1 || record1 == active1)
diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm
index 0e6a059c7b..f4f20aecc9 100644
--- a/code/game/machinery/computer/teleporter.dm
+++ b/code/game/machinery/computer/teleporter.dm
@@ -139,7 +139,7 @@
L[avoid_assoc_duplicate_keys(M.real_name, areaindex)] = M
var/desc = input("Please select a location to lock in.", "Locking Computer") as null|anything in L
- if(!user.canUseTopic(src, BE_CLOSE, NO_DEXTERY)) //check if we are still around
+ if(!user.canUseTopic(src, !issilicon(user), NO_DEXTERY)) //check if we are still around
return
target = L[desc]
if(imp_t)
@@ -167,7 +167,7 @@
to_chat(user, "No active connected stations located.")
return
var/desc = input("Please select a station to lock in.", "Locking Computer") as null|anything in L
- if(!user.canUseTopic(src, BE_CLOSE, NO_DEXTERY)) //again, check if we are still around
+ if(!user.canUseTopic(src, !issilicon(user), NO_DEXTERY)) //again, check if we are still around
return
var/obj/machinery/teleport/station/target_station = L[desc]
if(!target_station || !target_station.teleporter_hub)
diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm
index b0a75c99dc..165170cf0f 100644
--- a/code/game/machinery/porta_turret/portable_turret.dm
+++ b/code/game/machinery/porta_turret/portable_turret.dm
@@ -40,6 +40,8 @@
var/stun_projectile = null //stun mode projectile type
var/stun_projectile_sound
+ var/nonlethal_projectile //projectile to use in stun mode when the target is resting, if any
+ var/nonlethal_projectile_sound
var/lethal_projectile = null //lethal mode projectile type
var/lethal_projectile_sound
@@ -535,13 +537,22 @@
T = closer
break
+ var/mob/living/carbon/C
+ if(iscarbon(target))
+ C = target
+
update_icon()
var/obj/item/projectile/A
//any emagged turrets drains 2x power and uses a different projectile?
if(mode == TURRET_STUN)
- use_power(reqpower)
- A = new stun_projectile(T)
- playsound(loc, stun_projectile_sound, 75, 1)
+ if(nonlethal_projectile && C && C.resting)
+ use_power(reqpower*0.5)
+ A = new nonlethal_projectile(T)
+ playsound(loc, nonlethal_projectile_sound, 75, 1)
+ else
+ use_power(reqpower)
+ A = new stun_projectile(T)
+ playsound(loc, stun_projectile_sound, 75, 1)
else
use_power(reqpower * 2)
A = new lethal_projectile(T)
@@ -653,6 +664,8 @@
base_icon_state = "standard"
stun_projectile = /obj/item/projectile/energy/electrode
stun_projectile_sound = 'sound/weapons/taser.ogg'
+ nonlethal_projectile = /obj/item/projectile/beam/disabler
+ nonlethal_projectile_sound = 'sound/weapons/taser2.ogg'
lethal_projectile = /obj/item/projectile/beam/laser
lethal_projectile_sound = 'sound/weapons/laser.ogg'
desc = "An energy blaster auto-turret."
@@ -662,6 +675,8 @@
base_icon_state = "standard"
stun_projectile = /obj/item/projectile/energy/electrode
stun_projectile_sound = 'sound/weapons/taser.ogg'
+ nonlethal_projectile = /obj/item/projectile/beam/disabler
+ nonlethal_projectile_sound = 'sound/weapons/taser2.ogg'
lethal_projectile = /obj/item/projectile/beam/laser/heavylaser
lethal_projectile_sound = 'sound/weapons/lasercannonfire.ogg'
desc = "An energy blaster auto-turret."
@@ -681,6 +696,8 @@
/obj/machinery/porta_turret/ai
faction = list("silicon")
+ nonlethal_projectile = /obj/item/projectile/beam/disabler
+ nonlethal_projectile_sound = 'sound/weapons/taser2.ogg'
/obj/machinery/porta_turret/ai/assess_perp(mob/living/carbon/human/perp)
return 10 //AI turrets shoot at everything not in their faction
diff --git a/code/game/machinery/turnstile.dm b/code/game/machinery/turnstile.dm
new file mode 100644
index 0000000000..1fd78056d4
--- /dev/null
+++ b/code/game/machinery/turnstile.dm
@@ -0,0 +1,84 @@
+/obj/machinery/turnstile
+ name = "turnstile"
+ desc = "A mechanical door that permits one-way access and prevents tailgating."
+ icon = 'icons/obj/turnstile.dmi'
+ icon_state = "turnstile_map"
+ density = FALSE
+ armor = list(melee = 50, bullet = 50, laser = 50, energy = 50, bomb = 10, bio = 100, rad = 100, fire = 90, acid = 70)
+ anchored = TRUE
+ use_power = FALSE
+ idle_power_usage = 2
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ layer = OPEN_DOOR_LAYER
+
+/obj/machinery/turnstile/Initialize()
+ . = ..()
+ icon_state = "turnstile"
+
+/obj/machinery/turnstile/CanAtmosPass(turf/T)
+ return TRUE
+
+/obj/machinery/turnstile/bullet_act(obj/item/projectile/P, def_zone)
+ return -1 //Pass through!
+
+/obj/machinery/turnstile/proc/allowed_access(var/mob/B)
+ if(B.pulledby && ismob(B.pulledby))
+ return allowed(B.pulledby) | allowed(B)
+ else
+ return allowed(B)
+
+/obj/machinery/turnstile/CanPass(atom/movable/AM, turf/T)
+ if(ismob(AM))
+ var/mob/B = AM
+ if(isliving(AM))
+ var/mob/living/M = AM
+
+ if(world.time - M.last_bumped <= 5)
+ return FALSE
+ M.last_bumped = world.time
+
+ var/allowed_access = FALSE
+ var/turf/behind = get_step(src, dir)
+
+ if(B in behind.contents)
+ allowed_access = allowed_access(B)
+ else
+ to_chat(usr, "\the [src] resists your efforts.")
+ return FALSE
+
+ if(allowed_access)
+ flick("operate", src)
+ playsound(src,'sound/items/ratchet.ogg',50,0,3)
+ return TRUE
+ else
+ flick("deny", src)
+ playsound(src,'sound/machines/deniedbeep.ogg',50,0,3)
+ return FALSE
+ if(ispath(AM, /obj/item/))
+ return TRUE
+ else
+ return FALSE
+
+/obj/machinery/turnstile/CheckExit(atom/movable/AM as mob|obj, target)
+ if(isliving(AM))
+ var/mob/living/M = AM
+ var/outdir = dir
+ if(allowed_access(M))
+ switch(dir)
+ if(NORTH)
+ outdir = SOUTH
+ if(SOUTH)
+ outdir = NORTH
+ if(EAST)
+ outdir = WEST
+ if(WEST)
+ outdir = EAST
+ var/turf/outturf = get_step(src, outdir)
+ var/canexit = (target == src.loc) | (target == outturf)
+
+ if(!canexit && world.time - M.last_bumped <= 5)
+ to_chat(usr, "\the [src] resists your efforts.")
+ M.last_bumped = world.time
+ return canexit
+ else
+ return TRUE
\ No newline at end of file
diff --git a/code/game/mecha/combat/neovgre.dm b/code/game/mecha/combat/neovgre.dm
new file mode 100644
index 0000000000..2b2ed150e2
--- /dev/null
+++ b/code/game/mecha/combat/neovgre.dm
@@ -0,0 +1,96 @@
+/obj/mecha/combat/neovgre
+ name = "Neovgre, the Anima Bulwark"
+ desc = "Nezbere's most powerful creation, a mighty war machine of unmatched power said to have ended wars in a single night."
+ icon = 'icons/mecha/neovgre.dmi'
+ icon_state = "neovgre"
+ max_integrity = 500 //This is THE ratvarian superweaon, its deployment is an investment
+ armor = list("melee" = 50, "bullet" = 40, "laser" = 25, "energy" = 25, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100) //Its similar to the clockwork armour albeit with a few buffs becuase RATVARIAN SUPERWEAPON!!
+ force = 50 //SMASHY SMASHY!!
+ internal_damage_threshold = 0
+ step_in = 3
+ pixel_x = -16
+ layer = ABOVE_MOB_LAYER
+ breach_time = 100 //ten seconds till all goes to shit
+ recharge_rate = 100
+ wreckage = /obj/structure/mecha_wreckage/durand/neovgre
+
+/obj/mecha/combat/neovgre/GrantActions(mob/living/user, human_occupant = 0) //No Eject action for you sonny jim, your life for Ratvar!
+ internals_action.Grant(user, src)
+ cycle_action.Grant(user, src)
+ lights_action.Grant(user, src)
+ stats_action.Grant(user, src)
+ strafing_action.Grant(user, src)
+
+/obj/mecha/combat/neovgre/RemoveActions(mob/living/user, human_occupant = 0)
+ internals_action.Remove(user)
+ cycle_action.Remove(user)
+ lights_action.Remove(user)
+ stats_action.Remove(user)
+ strafing_action.Remove(user)
+
+/obj/mecha/combat/neovgre/MouseDrop_T(mob/M, mob/user)
+ if(!is_servant_of_ratvar(user))
+ to_chat(user, "BEGONE HERETIC!")
+ return
+ else
+ ..()
+
+/obj/mecha/combat/neovgre/moved_inside(mob/living/carbon/human/H)
+ var/list/Itemlist = H.get_contents()
+ for(var/obj/item/clockwork/slab/W in Itemlist)
+ to_chat(H, "You safely store [W] inside [src].")
+ qdel(W)
+ . = ..()
+
+/obj/mecha/combat/neovgre/obj_destruction()
+ for(var/mob/M in src)
+ to_chat(M, "You are consumed by the fires raging within Neovgre...")
+ M.dust()
+ playsound(src, 'sound/magic/lightning_chargeup.ogg', 100, 0)
+ src.visible_message("The reactor has gone critical, its going to blow!")
+ addtimer(CALLBACK(src,.proc/go_critical),breach_time)
+
+/obj/mecha/combat/neovgre/proc/go_critical()
+ explosion(get_turf(loc), 3, 5, 10, 20, 30)
+ Destroy(src)
+
+/obj/mecha/combat/neovgre/container_resist(mob/living/user)
+ to_chat(user, "Neovgre requires a lifetime commitment friend, no backing out now!")
+ return
+
+/obj/mecha/combat/neovgre/process()
+ ..()
+ if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hople to stop the superweapon
+ cell.charge = INFINITY
+ max_integrity = INFINITY
+ obj_integrity = max_integrity
+ CHECK_TICK //Just to be on the safe side lag wise
+ else if(cell.charge < cell.maxcharge)
+ for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
+ var/delta = min(recharge_rate, cell.maxcharge - cell.charge)
+ if (get_clockwork_power() <= delta)
+ cell.charge += delta
+ adjust_clockwork_power(-delta)
+ CHECK_TICK
+
+/obj/mecha/combat/neovgre/Initialize()
+ .=..()
+ GLOB.neovgre_exists ++
+ var/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/N = new
+ N.attach(src)
+
+/obj/structure/mecha_wreckage/durand/neovgre
+ name = "\improper Neovgre wreckage?"
+ desc = "On closer inspection this looks like the wreck of a durand with some spraypainted cardboard duct taped to it!"
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre
+ equip_cooldown = 8 //Rapid fire heavy laser cannon, simple yet elegant
+ energy_drain = 30
+ name = "Aribter Laser Cannon"
+ desc = "Please re-attach this to neovgre and stop asking questions about why it looks like a normal Nanotrasen issue Solaris laser cannon - Nezbere"
+ fire_sound = "sound/weapons/neovgre_laser.ogg"
+
+/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/can_attach(obj/mecha/combat/neovgre/M)
+ if(istype(M))
+ return 1
+ return 0
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 22aac63d2b..7348c8a575 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -49,6 +49,8 @@
var/lights = FALSE
var/lights_power = 6
var/last_user_hud = 1 // used to show/hide the mecha hud while preserving previous preference
+ var/breach_time = 0
+ var/recharge_rate = 0
var/bumpsmash = 0 //Whether or not the mech destroys walls by running into it.
//inner atmos
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index 05ffcbf2fd..875a4bd04f 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -342,12 +342,41 @@ update_label("John Doe", "Clowny")
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
assignment = "Prisoner"
- registered_name = "Scum"
+ access = list(ACCESS_ENTER_GENPOP)
+
+ //Lavaland labor camp
var/goal = 0 //How far from freedom?
var/points = 0
+ //Genpop
+ var/sentence = 0 //When world.time is greater than this number, the card will have its ACCESS_ENTER_GENPOP access replaced with ACCESS_LEAVE_GENPOP the next time it's checked, unless this value is 0/null
+ var/crime= "\[REDACTED\]"
-/obj/item/card/id/prisoner/attack_self(mob/user)
- to_chat(usr, "You have accumulated [points] out of the [goal] points you need for freedom.")
+/obj/item/card/id/prisoner/GetAccess()
+ if((sentence && world.time >= sentence) || (goal && points >= goal))
+ access = list(ACCESS_LEAVE_GENPOP)
+ return ..()
+
+/obj/item/card/id/prisoner/process()
+ if(!sentence)
+ STOP_PROCESSING(SSobj, src)
+ return
+ if(world.time >= sentence)
+ playsound(loc, 'sound/machines/ping.ogg', 50, 1)
+ if(isliving(loc))
+ to_chat(loc, "[src] buzzes: You have served your sentence! You may now exit prison through the turnstiles and collect your belongings.")
+ STOP_PROCESSING(SSobj, src)
+ return
+
+/obj/item/card/id/prisoner/examine(mob/user)
+ . = ..()
+ if(sentence && world.time < sentence)
+ to_chat(user, "You're currently serving a sentence for [crime]. [DisplayTimeText(sentence - world.time)] left.")
+ else if(goal)
+ to_chat(user, "You have accumulated [points] out of the [goal] points you need for freedom.")
+ else if(!sentence)
+ to_chat(user, "You are currently serving a permanent sentence for [crime].")
+ else
+ to_chat(user, "Your sentence is up! You're free!")
/obj/item/card/id/prisoner/one
name = "Prisoner #13-001"
diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm
index 709fedbe5a..1956a1f317 100644
--- a/code/game/objects/items/grenades/plastic.dm
+++ b/code/game/objects/items/grenades/plastic.dm
@@ -174,6 +174,7 @@
gender = PLURAL
var/open_panel = 0
can_attach_mob = TRUE
+ full_damage_on_mobs = TRUE
/obj/item/grenade/plastic/c4/New()
wires = new /datum/wires/explosive/c4(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/genpop.dm b/code/game/objects/structures/crates_lockers/closets/genpop.dm
new file mode 100644
index 0000000000..80b64aaedc
--- /dev/null
+++ b/code/game/objects/structures/crates_lockers/closets/genpop.dm
@@ -0,0 +1,117 @@
+/obj/structure/closet/secure_closet/genpop
+ desc = "It's a secure locker for inmates's personal belongings."
+ var/default_desc = "It's a secure locker for the storage inmates's personal belongings during their time in prison."
+ name = "prisoner closet"
+ var/default_name = "prisoner closet"
+ req_access = list(ACCESS_BRIG)
+ var/obj/item/card/id/prisoner/registered_id = null
+ icon_state = "prisoner"
+ locked = FALSE
+ anchored = TRUE
+ opened = TRUE
+ density = FALSE
+
+/obj/structure/closet/secure_closet/genpop/attackby(obj/item/W, mob/user, params)
+ if(!broken && locked && W == registered_id) //Prisoner opening
+ handle_prisoner_id(user)
+ return
+
+ return ..()
+
+/obj/structure/closet/secure_closet/genpop/proc/handle_prisoner_id(mob/user)
+ var/obj/item/card/id/prisoner/prisoner_id = null
+ for(prisoner_id in user.held_items)
+ if(prisoner_id != registered_id)
+ prisoner_id = null
+ else
+ break
+
+ if(!prisoner_id)
+ to_chat(user, "Access Denied.")
+ return FALSE
+
+ qdel(registered_id)
+ registered_id = null
+ locked = FALSE
+ open(user)
+ desc = "It's a secure locker for prisoner effects."
+ to_chat(user, "You insert your prisoner id into \the [src] and it springs open!")
+
+ return TRUE
+
+/obj/structure/closet/secure_closet/genpop/proc/handle_edit_sentence(mob/user)
+ var/prisoner_name = input(user, "Please input the name of the prisoner.", "Prisoner Name", registered_id.registered_name) as text|null
+ if(prisoner_name == null | !user.Adjacent(src))
+ return FALSE
+ var/sentence_length = input(user, "Please input the length of their sentence in minutes (0 for perma).", "Sentence Length", registered_id.sentence) as num|null
+ if(sentence_length == null | !user.Adjacent(src))
+ return FALSE
+ var/crimes = input(user, "Please input their crimes.", "Crimes", registered_id.crime) as text|null
+ if(crimes == null | !user.Adjacent(src))
+ return FALSE
+
+ registered_id.registered_name = prisoner_name
+ var/filteredsentlength = text2num(sentence_length)
+ registered_id.sentence = filteredsentlength ? (filteredsentlength MINUTES) + world.time : 0
+ registered_id.crime = crimes
+ registered_id.update_label(prisoner_name, registered_id.assignment)
+ if(registered_id.sentence)
+ START_PROCESSING(SSobj, registered_id)
+ else
+ STOP_PROCESSING(SSobj, registered_id)
+
+ name = "[default_name] ([prisoner_name])"
+ desc = "[default_desc] It contains the personal effects of [prisoner_name]."
+
+ return TRUE
+
+/obj/structure/closet/secure_closet/genpop/togglelock(mob/living/user)
+ if(!allowed(user))
+ return ..()
+
+ if(!broken && locked && registered_id != null)
+ var/name = registered_id.registered_name
+ var/result = alert(user, "This locker currently contains [name]'s personal belongings ","Locker In Use","Reset","Amend ID", "Open")
+ if(!user.Adjacent(src))
+ return
+ if(result == "Reset")
+ name = default_name
+ desc = default_desc
+ registered_id = null
+ if(result == "Open" | result == "Reset")
+ locked = FALSE
+ open(user)
+ if(result == "Amend ID")
+ handle_edit_sentence(user)
+ else
+ return ..()
+
+/obj/structure/closet/secure_closet/genpop/close(mob/living/user)
+ if(registered_id != null)
+ locked = TRUE
+ return ..()
+
+/obj/structure/closet/secure_closet/genpop/attack_hand(mob/user)
+ if(user.lying && get_dist(src, user) > 0)
+ return
+
+ if(!broken && registered_id != null && registered_id in user.held_items)
+ handle_prisoner_id(user)
+ return
+
+ if(!broken && opened && !locked && allowed(user) && !registered_id) //Genpop setup
+
+ registered_id = new /obj/item/card/id/prisoner/(src.contents)
+ if(handle_edit_sentence(user))
+ close(user)
+ locked = TRUE
+ update_icon()
+ registered_id.forceMove(src.loc)
+ new /obj/item/clothing/under/rank/prisoner(src.loc)
+ else
+ qdel(registered_id)
+ registered_id = null
+
+ return
+
+ ..()
\ No newline at end of file
diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm
index 80eb007605..e8d30e8dbe 100644
--- a/code/modules/antagonists/abductor/abductor.dm
+++ b/code/modules/antagonists/abductor/abductor.dm
@@ -26,7 +26,7 @@
sub_role = "Scientist"
outfit = /datum/outfit/abductor/scientist
landmark_type = /obj/effect/landmark/abductor/scientist
- greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
+ greet_text = "Use your experimental console and surgical equipment to monitor your agent and experiment upon abducted humans."
show_in_antagpanel = TRUE
/datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team)
@@ -40,15 +40,14 @@
return team
/datum/antagonist/abductor/on_gain()
- owner.special_role = "[name] [sub_role]"
- owner.assigned_role = "[name] [sub_role]"
- owner.objectives += team.objectives
+ owner.special_role = "[name]"
+ owner.assigned_role = "[name]"
+ objectives += team.objectives
finalize_abductor()
ADD_TRAIT(owner, TRAIT_ABDUCTOR_TRAINING, ABDUCTOR_ANTAGONIST)
return ..()
/datum/antagonist/abductor/on_removal()
- owner.objectives -= team.objectives
if(owner.current)
to_chat(owner.current,"You are no longer the [owner.special_role]!")
owner.special_role = null
@@ -66,6 +65,7 @@
//Equip
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/abductor)
+
H.real_name = "[team.name] [sub_role]"
H.equipOutfit(outfit)
@@ -99,8 +99,8 @@
else
return
new_owner.add_antag_datum(src)
- log_admin("[key_name(usr)] made [key_name(new_owner.current)] [name] on [choice]!")
- message_admins("[key_name_admin(usr)] made [key_name_admin(new_owner.current)] [name] on [choice] !")
+ log_admin("[key_name(usr)] made [key_name(new_owner)] [name] on [choice]!")
+ message_admins("[key_name_admin(usr)] made [key_name_admin(new_owner)] [name] on [choice] !")
/datum/antagonist/abductor/get_admin_commands()
. = ..()
@@ -153,7 +153,7 @@
result += ""
for(var/datum/mind/abductor_mind in members)
result += printplayer(abductor_mind)
- result += printobjectives(abductor_mind)
+ result += printobjectives(objectives)
return "
[result.Join("
")]
"
@@ -178,7 +178,6 @@
var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
var/datum/objective/abductee/O = new objtype()
objectives += O
- owner.objectives += objectives
/datum/antagonist/abductee/apply_innate_effects(mob/living/mob_override)
update_abductor_icons_added(mob_override ? mob_override.mind : owner,"abductee")
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index 7620aa752b..ed26b894d9 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -135,12 +135,14 @@
/obj/item/abductor/proc/AbductorCheck(mob/user)
if(HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING))
return TRUE
+ if (istype(user) && user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING))
+ return TRUE
to_chat(user, "You can't figure how this works!")
return FALSE
/obj/item/abductor/proc/ScientistCheck(mob/user)
- var/training = HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING)
- var/sci_training = HAS_TRAIT(user, TRAIT_ABDUCTOR_SCIENTIST_TRAINING)
+ var/training = HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING) || (user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING))
+ var/sci_training = HAS_TRAIT(user, TRAIT_ABDUCTOR_SCIENTIST_TRAINING) || (user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_SCIENTIST_TRAINING))
if(training && !sci_training)
to_chat(user, "You're not trained to use this!")
diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm
index cc52b3e910..a35cbbf0e4 100644
--- a/code/modules/antagonists/abductor/equipment/gland.dm
+++ b/code/modules/antagonists/abductor/equipment/gland.dm
@@ -19,7 +19,7 @@
/obj/item/organ/heart/gland/examine(mob/user)
. = ..()
- if(HAS_TRAIT(user, TRAIT_ABDUCTOR_SCIENTIST_TRAINING) || isobserver(user))
+ if((user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_SCIENTIST_TRAINING)) || isobserver(user))
to_chat(user, "It is \a [true_name].")
/obj/item/organ/heart/gland/proc/ownerCheck()
@@ -48,19 +48,19 @@
/obj/item/organ/heart/gland/proc/mind_control(command, mob/living/user)
if(!ownerCheck() || !mind_control_uses || active_mind_control)
- return
+ return FALSE
mind_control_uses--
to_chat(owner, "You suddenly feel an irresistible compulsion to follow an order...")
to_chat(owner, "[command]")
active_mind_control = TRUE
- log_admin("[key_name(user)] sent an abductor mind control message to [key_name(owner)]: [command]")
+ message_admins("[key_name(user)] sent an abductor mind control message to [key_name(owner)]: [command]")
update_gland_hud()
addtimer(CALLBACK(src, .proc/clear_mind_control), mind_control_duration)
/obj/item/organ/heart/gland/proc/clear_mind_control()
if(!ownerCheck() || !active_mind_control)
- return
+ return FALSE
to_chat(owner, "You feel the compulsion fade, and you completely forget about your previous orders.")
active_mind_control = FALSE
diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm
index 30b82398ff..9a9b1a6ba0 100644
--- a/code/modules/antagonists/abductor/machinery/console.dm
+++ b/code/modules/antagonists/abductor/machinery/console.dm
@@ -28,7 +28,7 @@
. = ..()
if(.)
return
- if(!HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING))
+ if(!HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING) && !HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING))
to_chat(user, "You start mashing alien buttons at random!")
if(do_after(user,100, target = src))
TeleporterSend()
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm
index da499065d7..3d467350ff 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm
@@ -119,3 +119,33 @@
var/datum/clockwork_scripture/create_object/construct/clockwork_marauder/CM = new()
CM.recent_marauders--
qdel(CM)
+
+//Summon Neovgre: Summon a very powerful combat mech that explodes when destroyed for massive damage.
+/datum/clockwork_scripture/create_object/summon_arbiter
+ descname = "Powerful Assault Mech"
+ name = "Summon Neovgre, the Anima Bulwark"
+ desc = "Calls forth the mighty Anima Bulwark, a weapon of unmatched power,\
+ mech with superior defensive and offensive capabilities. It will \
+ steadily regenerate HP and triple its regeneration speed while standing \
+ on a clockwork tile. It will automatically draw power from nearby sigils of \
+ transmission should the need arise. Its Arbiter laser cannon can decimate foes \
+ from a range and is capable of smashing through any barrier presented to it. \
+ Be warned, choosing to pilot Neovgre is a lifetime commitment, once you are \
+ in you cannot leave and when it is destroyed it will explode catastrophically with you inside."
+ invocations = list("By the strength of the alloy...!!", "...call forth the Arbiter!!")
+ channel_time = 200 // This is a strong fucking weapon, 20 seconds channel time is getting off light I tell ya.
+ power_cost = 75000 //75 KW
+ usage_tip = "Neovgre is a powerful mech that will crush your enemies!"
+ invokers_required = 5
+ multiple_invokers_used = TRUE
+ object_path = /obj/mecha/combat/neovgre
+ tier = SCRIPTURE_APPLICATION
+ primary_component = BELLIGERENT_EYE
+ sort_priority = 2
+ creator_message = "Neovgre, the Anima Bulwark towers over you... your enemies reckoning has come."
+
+/datum/clockwork_scripture/create_object/summon_arbiter/check_special_requirements()
+ if(GLOB.neovgre_exists)
+ to_chat(invoker, "\"You've already got one...\"")
+ return FALSE
+ return ..()
diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm
index 8e320b2f3e..f9c831a65a 100644
--- a/code/modules/atmospherics/gasmixtures/reactions.dm
+++ b/code/modules/atmospherics/gasmixtures/reactions.dm
@@ -210,9 +210,9 @@
return cached_results["fire"] ? REACTING : NO_REACTION
-//fusion: a terrible idea that was fun but broken. Now reworked to be less broken and more interesting. Again (and again, and again)
+//fusion: a terrible idea that was fun but broken. Now reworked to be less broken and more interesting. Again (and again, and again). Again!
//Fusion Rework Counter: Please increment this if you make a major overhaul to this system again.
-//5 reworks
+//6 reworks
/datum/gas_reaction/fusion
exclude = FALSE
@@ -220,100 +220,79 @@
name = "Plasmic Fusion"
id = "fusion"
-//Since fusion isn't really intended to happen in successive chains, the requirements are very high
/datum/gas_reaction/fusion/init_reqs()
min_requirements = list(
"TEMP" = FUSION_TEMPERATURE_THRESHOLD,
- "ENER" = FUSION_ENERGY_THRESHOLD,
+ /datum/gas/tritium = FUSION_TRITIUM_MOLES_USED,
/datum/gas/plasma = FUSION_MOLE_THRESHOLD,
- /datum/gas/tritium = FUSION_MOLE_THRESHOLD
- )
+ /datum/gas/carbon_dioxide = FUSION_MOLE_THRESHOLD)
/datum/gas_reaction/fusion/react(datum/gas_mixture/air, datum/holder)
var/list/cached_gases = air.gases
- var/temperature = air.temperature
- if(!air.analyzer_results)
- air.analyzer_results = new
- var/list/cached_scan_results = air.analyzer_results
var/turf/open/location
if (istype(holder,/datum/pipeline)) //Find the tile the reaction is occuring on, or a random part of the network if it's a pipenet.
var/datum/pipeline/fusion_pipenet = holder
location = get_turf(pick(fusion_pipenet.members))
else
location = get_turf(holder)
-
+ if(!air.analyzer_results)
+ air.analyzer_results = new
+ var/list/cached_scan_results = air.analyzer_results
var/old_heat_capacity = air.heat_capacity()
- var/reaction_energy = 0
-
- var/mediation = FUSION_MEDIATION_FACTOR*(air.heat_capacity()-(cached_gases[/datum/gas/plasma]*GLOB.meta_gas_specific_heats[/datum/gas/plasma]))/(air.total_moles()-cached_gases[/datum/gas/plasma]) //This is the average specific heat of the mixture,not including plasma.
-
- var/gases_fused = air.total_moles() - cached_gases[/datum/gas/plasma]
- var/plasma_differential = (cached_gases[/datum/gas/plasma] - gases_fused) / air.total_moles()
- var/reaction_efficiency = FUSION_EFFICIENCY_BASE ** -((plasma_differential ** 2) / FUSION_EFFICIENCY_DIVISOR) //https://www.desmos.com/calculator/6jjx3vdrvx
-
+ var/reaction_energy = 0 //Reaction energy can be negative or positive, for both exothermic and endothermic reactions.
+ var/initial_plasma = cached_gases[/datum/gas/plasma]
+ var/initial_carbon = cached_gases[/datum/gas/carbon_dioxide]
+ var/scale_factor = (air.volume)/(PI) //We scale it down by volume/Pi because for fusion conditions, moles roughly = 2*volume, but we want it to be based off something constant between reactions.
+ var/toroidal_size = (2*PI)+TORADIANS(arctan((air.volume-TOROID_VOLUME_BREAKEVEN)/TOROID_VOLUME_BREAKEVEN)) //The size of the phase space hypertorus
var/gas_power = 0
+ var/list/gas_fusion_powers = GLOB.meta_gas_fusions
for (var/gas_id in cached_gases)
- gas_power += reaction_efficiency * (GLOB.meta_gas_fusions[gas_id]*cached_gases[gas_id])
+ gas_power += (gas_fusion_powers[gas_id]*cached_gases[gas_id])
+ var/instability = MODULUS((gas_power*INSTABILITY_GAS_POWER_FACTOR)**2,toroidal_size) //Instability effects how chaotic the behavior of the reaction is
+ cached_scan_results[id] = instability//used for analyzer feedback
- var/power_ratio = gas_power/mediation
- cached_scan_results[id] = power_ratio //used for analyzer feedback
+ var/plasma = (initial_plasma-FUSION_MOLE_THRESHOLD)/(scale_factor) //We have to scale the amounts of carbon and plasma down a significant amount in order to show the chaotic dynamics we want
+ var/carbon = (initial_carbon-FUSION_MOLE_THRESHOLD)/(scale_factor) //We also subtract out the threshold amount to make it harder for fusion to burn itself out.
- for (var/gas_id in cached_gases) //and now we fuse
- cached_gases[gas_id] = 0
+ //The reaction is a specific form of the Kicked Rotator system, which displays chaotic behavior and can be used to model particle interactions.
+ plasma = MODULUS(plasma - (instability*sin(TODEGREES(carbon))), toroidal_size)
+ carbon = MODULUS(carbon - plasma, toroidal_size)
- var/radiation_power = (FUSION_RADIATION_FACTOR * power_ratio) / (power_ratio + FUSION_RADIATION_CONSTANT) //https://www.desmos.com/calculator/4i1f296phl
- var/zap_power = ((FUSION_ZAP_POWER_ASYMPTOTE * power_ratio) / (power_ratio + FUSION_ZAP_POWER_CONSTANT)) + FUSION_ZAP_POWER_BASE //https://www.desmos.com/calculator/n0zkdpxnrr
- var/do_explosion = FALSE
- var/zap_range //these ones are set later
- var/fusion_prepare_to_die_edition_rng
- if (power_ratio > FUSION_SUPER_TIER_THRESHOLD) //power ratio 50+: SUPER TIER. The gases become so energized that they fuse into a ton of tritium, which is pretty nice! Until you consider the fact that everything just exploded, the canister is probably going to break and you're irradiated.
- reaction_energy += gases_fused * FUSION_RELEASE_ENERGY_SUPER * (power_ratio / FUSION_ENERGY_DIVISOR_SUPER)
- cached_gases[/datum/gas/tritium] += gases_fused * FUSION_GAS_CREATION_FACTOR_TRITIUM //60% of the gas is converted to energy, 40% to trit
- fusion_prepare_to_die_edition_rng = 100 //Wait a minute..
- do_explosion = TRUE
- zap_range = FUSION_ZAP_RANGE_SUPER
+ cached_gases[/datum/gas/plasma] = plasma*scale_factor + FUSION_MOLE_THRESHOLD //Scales the gases back up
+ cached_gases[/datum/gas/carbon_dioxide] = carbon*scale_factor + FUSION_MOLE_THRESHOLD
+ var/delta_plasma = initial_plasma - cached_gases[/datum/gas/plasma]
- else if (power_ratio > FUSION_HIGH_TIER_THRESHOLD) //power ratio 20-50; High tier. The reaction is so energized that it fuses into a small amount of stimulum, and some pluoxium. Very dangerous, but super cool and super useful.
- reaction_energy += gases_fused * FUSION_RELEASE_ENERGY_HIGH * (power_ratio / FUSION_ENERGY_DIVISOR_HIGH)
- cached_gases[/datum/gas/stimulum] += gases_fused * FUSION_GAS_CREATION_FACTOR_STIM //40% of the gas is converted to energy, 60% to stim and pluox
- cached_gases[/datum/gas/pluoxium] += gases_fused * FUSION_GAS_CREATION_FACTOR_PLUOX
- fusion_prepare_to_die_edition_rng = power_ratio //Now we're getting into dangerous territory
- do_explosion = TRUE
- zap_range = FUSION_ZAP_RANGE_HIGH
-
- else if (power_ratio > FUSION_MID_TIER_THRESHOLD) //power_ratio 5 to 20; Mediation is overpowered, fusion reaction starts to break down.
- reaction_energy += gases_fused * FUSION_RELEASE_ENERGY_MID * (power_ratio / FUSION_ENERGY_DIVISOR_MID)
- cached_gases[/datum/gas/nitryl] += gases_fused * FUSION_GAS_CREATION_FACTOR_NITRYL //20% of the gas is converted to energy, 80% to nitryl and N2O
- cached_gases[/datum/gas/nitrous_oxide] += gases_fused * FUSION_GAS_CREATION_FACTOR_N2O
- fusion_prepare_to_die_edition_rng = power_ratio * FUSION_MID_TIER_RAD_PROB_FACTOR //Still unlikely, but don't stand next to the reaction unprotected
- zap_range = FUSION_ZAP_RANGE_MID
-
- else //power ratio 0 to 5; Gas power is overpowered. Fusion isn't nearly as powerful.
- reaction_energy += gases_fused * FUSION_RELEASE_ENERGY_LOW * (power_ratio / FUSION_ENERGY_DIVISOR_LOW)
- cached_gases[/datum/gas/bz] += gases_fused * FUSION_GAS_CREATION_FACTOR_BZ //10% of the gas is converted to energy, 90% to BZ and CO2
- cached_gases[/datum/gas/carbon_dioxide] += gases_fused * FUSION_GAS_CREATION_FACTOR_CO2
- fusion_prepare_to_die_edition_rng = power_ratio * FUSION_LOW_TIER_RAD_PROB_FACTOR //Low, but still something to look out for
- zap_range = FUSION_ZAP_RANGE_LOW
-
- //All the deadly consequences of fusion, consolidated for your viewing pleasure
- if (location)
- if(prob(fusion_prepare_to_die_edition_rng)) //Some.. permanent effects
- if(do_explosion)
- explosion(location, 0, 0, 5, power_ratio, TRUE, TRUE) //large shockwave, the actual radius is quite small - people will recognize that you're doing fusion
- radiation_pulse(location, radiation_power) //You mean causing a super-tier fusion reaction in the halls is a bad idea?
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, 30000)//The science is cool though.
- playsound(location, 'sound/effects/supermatter.ogg', 100, 0)
- else
- playsound(location, 'sound/effects/phasein.ogg', 75, 0)
- //These will always happen, so be prepared
- tesla_zap(location, zap_range, zap_power, TESLA_FUSION_FLAGS) //larpers beware
- location.fire_nuclear_particles(power_ratio) //see code/modules/projectile/energy/nuclear_particle.dm
+ reaction_energy += delta_plasma*PLASMA_BINDING_ENERGY //Energy is gained or lost corresponding to the creation or destruction of mass.
+ if(instability < FUSION_INSTABILITY_ENDOTHERMALITY)
+ reaction_energy = max(reaction_energy,0) //Stable reactions don't end up endothermic.
+ else if (reaction_energy < 0)
+ reaction_energy *= (instability-FUSION_INSTABILITY_ENDOTHERMALITY)**0.5
+ if(air.thermal_energy() + reaction_energy < 0) //No using energy that doesn't exist.
+ cached_gases[/datum/gas/plasma] = initial_plasma
+ cached_gases[/datum/gas/carbon_dioxide] = initial_carbon
+ return NO_REACTION
+ cached_gases[/datum/gas/tritium] -= FUSION_TRITIUM_MOLES_USED
+ //The decay of the tritium and the reaction's energy produces waste gases, different ones depending on whether the reaction is endo or exothermic
if(reaction_energy > 0)
+ cached_gases[/datum/gas/oxygen] += FUSION_TRITIUM_MOLES_USED*(reaction_energy*FUSION_TRITIUM_CONVERSION_COEFFICIENT)
+ cached_gases[/datum/gas/nitrous_oxide] += FUSION_TRITIUM_MOLES_USED*(reaction_energy*FUSION_TRITIUM_CONVERSION_COEFFICIENT)
+ else
+ cached_gases[/datum/gas/bz] += FUSION_TRITIUM_MOLES_USED*(reaction_energy*-FUSION_TRITIUM_CONVERSION_COEFFICIENT)
+ cached_gases[/datum/gas/nitryl] += FUSION_TRITIUM_MOLES_USED*(reaction_energy*-FUSION_TRITIUM_CONVERSION_COEFFICIENT)
+
+ if(reaction_energy)
+ if(location)
+ var/particle_chance = ((PARTICLE_CHANCE_CONSTANT)/(reaction_energy-PARTICLE_CHANCE_CONSTANT)) + 1//Asymptopically approaches 100% as the energy of the reaction goes up.
+ if(prob(PERCENT(particle_chance)))
+ location.fire_nuclear_particle()
+ var/rad_power = max((FUSION_RAD_COEFFICIENT/instability) + FUSION_RAD_MAX,0)
+ radiation_pulse(location,rad_power)
+
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.temperature = max(((temperature*old_heat_capacity + reaction_energy)/new_heat_capacity),TCMB)
+ air.temperature = CLAMP(((air.temperature*old_heat_capacity + reaction_energy)/new_heat_capacity),TCMB,INFINITY)
return REACTING
/datum/gas_reaction/nitrylformation //The formation of nitryl. Endothermic. Requires N2O as a catalyst.
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index c6166ca970..47c3293c35 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -86,6 +86,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/skin_tone = "caucasian1" //Skin color
var/eye_color = "000" //Eye color
var/horn_color = "85615a" //Horn color
+ var/wing_color = "fff" //Wing color
var/datum/species/pref_species = new /datum/species/human() //Mutant race
var/list/features = list("mcolor" = "FFF",
"tail_lizard" = "Smooth",
@@ -591,6 +592,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Decorative wings
"
dat += "[features["deco_wings"]]"
+ dat += " Change
"
+
if("insect_wings" in pref_species.default_features)
if(!mutant_category)
dat += APPEARANCE_CATEGORY_COLUMN
@@ -598,6 +601,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Insect wings
"
dat += "[features["insect_wings"]]"
+ dat += " Change
"
mutant_category++
if(mutant_category >= MAX_MUTANT_ROWS)
dat += ""
@@ -1689,7 +1693,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("horns_color")
var/new_horn_color = input(user, "Choose your character's horn colour:", "Character Preference","#"+horn_color) as color|null
if(new_horn_color)
- horn_color = sanitize_hexcolor(new_horn_color)
+ if (new_horn_color == "#000000")
+ horn_color = "#85615A"
+ else
+ horn_color = sanitize_hexcolor(new_horn_color)
if("wings")
var/new_wings
@@ -1697,6 +1704,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(new_wings)
features["wings"] = new_wings
+ if("wings_color")
+ var/new_wing_color = input(user, "Choose your character's wing colour:", "Character Preference","#"+wing_color) as color|null
+ if(new_wing_color)
+ if (new_wing_color == "#000000")
+ wing_color = "#FFFFFF"
+ else
+ wing_color = sanitize_hexcolor(new_wing_color)
+
if("frills")
var/new_frills
new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in GLOB.frills_list
@@ -1730,13 +1745,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
new_insect_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_wings_list
if(new_insect_wings)
features["insect_wings"] = new_insect_wings
-
+
if("deco_wings")
var/new_deco_wings
new_deco_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.deco_wings_list
if(new_deco_wings)
features["deco_wings"] = new_deco_wings
-
+
if("insect_fluffs")
var/new_insect_fluff
new_insect_fluff = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_fluffs_list
@@ -2262,6 +2277,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.hair_color = hair_color
character.facial_hair_color = facial_hair_color
character.horn_color = horn_color
+ character.wing_color = wing_color
character.skin_tone = skin_tone
character.hair_style = hair_style
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 94c1158885..01a46a44a0 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -317,6 +317,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(!S["features["mcolor"]"] || S["features["mcolor"]"] == "#000")
WRITE_FILE(S["features["mcolor"]"] , "#FFF")
+ if(!S["features["horn_color"]"] || S["features["horn_color"]"] == "#000")
+ WRITE_FILE(S["features["horn_color"]"] , "#85615a")
+
+ if(!S["features["wing_color"]"] || S["features["wing_color"]"] == "#000")
+ WRITE_FILE(S["features["wing_color"]"] , "#FFF")
+
//Character
S["real_name"] >> real_name
S["nameless"] >> nameless
@@ -338,6 +344,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["socks"] >> socks
S["socks_color"] >> socks_color
S["horn_color"] >> horn_color
+ S["wing_color"] >> wing_color
S["backbag"] >> backbag
S["jumpsuit_style"] >> jumpsuit_style
S["uplink_loc"] >> uplink_spawn_loc
@@ -449,6 +456,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(!features["mcolor"] || features["mcolor"] == "#000")
features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
+ if(!features["horn_color"] || features["horn_color"] == "#000")
+ features["horn_color"] = "85615a"
+
+ if(!features["wing_color"] || features["wing_color"] == "#000")
+ features["wing_color"] = "FFFFFF"
+
nameless = sanitize_integer(nameless, 0, 1, initial(nameless))
be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name))
be_random_body = sanitize_integer(be_random_body, 0, 1, initial(be_random_body))
@@ -471,6 +484,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
eye_color = sanitize_hexcolor(eye_color, 3, 0)
skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones)
horn_color = sanitize_hexcolor(horn_color, 3, FALSE)
+ wing_color = sanitize_hexcolor(wing_color, 3, FALSE, "#FFFFFF")
backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag))
jumpsuit_style = sanitize_inlist(jumpsuit_style, GLOB.jumpsuitlist, initial(jumpsuit_style))
uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc))
@@ -485,7 +499,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
features["body_markings"] = sanitize_inlist(features["body_markings"], GLOB.body_markings_list)
features["feature_lizard_legs"] = sanitize_inlist(features["legs"], GLOB.legs_list)
features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list)
- features["deco_wings"] = sanitize_inlist(features["deco_wings"], GLOB.deco_wings_list)
+ features["deco_wings"] = sanitize_inlist(features["deco_wings"], GLOB.deco_wings_list, "None")
features["insect_fluff"] = sanitize_inlist(features["insect_fluff"], GLOB.insect_fluffs_list)
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
@@ -540,6 +554,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["socks"] , socks)
WRITE_FILE(S["socks_color"] , socks_color)
WRITE_FILE(S["horn_color"] , horn_color)
+ WRITE_FILE(S["wing_color"] , wing_color)
WRITE_FILE(S["backbag"] , backbag)
WRITE_FILE(S["jumpsuit_style"] , jumpsuit_style)
WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc)
diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm
index 3008043156..342429e480 100644
--- a/code/modules/clothing/suits/_suits.dm
+++ b/code/modules/clothing/suits/_suits.dm
@@ -55,7 +55,7 @@
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]")
IF_HAS_BLOOD_DNA(src)
- if(taurmode >= SNEK_TAURIC)
+ if(tauric)
. += mutable_appearance('modular_citadel/icons/mob/64x32_effects.dmi', "[blood_overlay_type]blood")
else
. += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood")
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index 5f8f1f145d..f86691c067 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -133,18 +133,6 @@
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
-/datum/crafting_recipe/minigun
- name = "Laser Minigun"
- result = /obj/item/minigunpack2
- reqs = list(/obj/item/gun/energy/laser/carbine = 3,
- /obj/item/stack/sheet/plasteel = 5,
- /obj/item/stack/cable_coil = 30,
- /obj/item/stock_parts/cell/bluespace = 2)
- tools = list(TOOL_WIRECUTTER, TOOL_SCREWDRIVER, TOOL_WELDER)
- time = 150
- category = CAT_WEAPONRY
- subcategory = CAT_WEAPON
-
/datum/crafting_recipe/ed209
name = "ED209"
result = /mob/living/simple_animal/bot/ed209
diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm
index c575c97901..604e203cd6 100644
--- a/code/modules/events/meteor_wave.dm
+++ b/code/modules/events/meteor_wave.dm
@@ -32,8 +32,6 @@
determine_wave_type()
/datum/round_event/meteor_wave/proc/determine_wave_type()
- if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
- wave_name = "halloween"
if(!wave_name)
wave_name = pickweight(list(
"normal" = 50,
@@ -45,7 +43,10 @@
if("threatening")
wave_type = GLOB.meteors_threatening
if("catastrophic")
- wave_type = GLOB.meteors_catastrophic
+ if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
+ wave_type = GLOB.meteorsSPOOKY
+ else
+ wave_type = GLOB.meteors_catastrophic
if("meaty")
wave_type = GLOB.meteorsB
if("space dust")
diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index 88f72d27c3..bac2e0bb65 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -771,7 +771,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
..()
var/turf/source = random_far_turf()
if(!sound_type)
- sound_type = pick("airlock","airlock pry","console","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack")
+ sound_type = pick("airlock","airlock pry","console","flash","explosion","far explosion","mech","glass","alarm","beepsky","mech","wall decon","door hack")
feedback_details += "Type: [sound_type]"
//Strange audio
switch(sound_type)
@@ -788,6 +788,8 @@ GLOBAL_LIST_INIT(hallucination_list, list(
target.playsound_local(source,'sound/effects/explosion1.ogg', 50, 1)
else
target.playsound_local(source, 'sound/effects/explosion2.ogg', 50, 1)
+ if("flash")
+ target.playsound_local(source, 'sound/weapons/flash.ogg', 50, 1)
if("far explosion")
target.playsound_local(source, 'sound/effects/explosionfar.ogg', 50, 1)
if("glass")
@@ -1291,4 +1293,4 @@ GLOBAL_LIST_INIT(hallucination_list, list(
H.hal_target = target
H.preparePixelProjectile(target, start)
H.fire()
- qdel(src)
\ No newline at end of file
+ qdel(src)
diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm
index e88a80514a..1ffdff2347 100644
--- a/code/modules/jobs/access.dm
+++ b/code/modules/jobs/access.dm
@@ -121,7 +121,7 @@
return list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_CENT_BAR)
/proc/get_all_accesses()
- return list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS, ACCESS_COURT,
+ return list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS, ACCESS_COURT, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP,
ACCESS_MEDICAL, ACCESS_GENETICS, ACCESS_MORGUE, ACCESS_RD,
ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_CHEMISTRY, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_MAINT_TUNNELS,
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD,
@@ -157,7 +157,7 @@
if(1) //station general
return list(ACCESS_KITCHEN,ACCESS_BAR, ACCESS_HYDROPONICS, ACCESS_JANITOR, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_LIBRARY, ACCESS_THEATRE, ACCESS_LAWYER)
if(2) //security
- return list(ACCESS_SEC_DOORS, ACCESS_WEAPONS, ACCESS_SECURITY, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS, ACCESS_COURT, ACCESS_HOS)
+ return list(ACCESS_SEC_DOORS, ACCESS_WEAPONS, ACCESS_SECURITY, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS, ACCESS_COURT, ACCESS_HOS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP,)
if(3) //medbay
return list(ACCESS_MEDICAL, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_SURGERY, ACCESS_CMO)
if(4) //research
@@ -312,6 +312,10 @@
return "Gateway"
if(ACCESS_SEC_DOORS)
return "Brig"
+ if(ACCESS_ENTER_GENPOP)
+ return "Prison Turnstile Entrance"
+ if(ACCESS_LEAVE_GENPOP)
+ return "Prison Turnstile Exit"
if(ACCESS_MINERAL_STOREROOM)
return "Mineral Storage"
if(ACCESS_MINISAT)
diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm
index f6b5dbd3ef..33c8856d81 100644
--- a/code/modules/jobs/job_types/head_of_security.dm
+++ b/code/modules/jobs/job_types/head_of_security.dm
@@ -19,11 +19,11 @@
outfit = /datum/outfit/job/hos
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS,
+ access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP,
ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS,
ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING,
ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS,
+ minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP,
ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS,
ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING,
ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index 4f12d6a19c..ae50f71c0c 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -15,8 +15,8 @@
outfit = /datum/outfit/job/security
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) // See /datum/job/officer/get_access()
+ access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MINERAL_STOREROOM) // See /datum/job/officer/get_access()
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
index a5c16ab5cf..1787d13ee3 100644
--- a/code/modules/jobs/job_types/warden.dm
+++ b/code/modules/jobs/job_types/warden.dm
@@ -15,8 +15,8 @@
outfit = /datum/outfit/job/warden
- access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
- minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) // See /datum/job/warden/get_access()
+ access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
+ minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MINERAL_STOREROOM) // See /datum/job/warden/get_access()
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm
index 23ec02976d..559ffc0673 100644
--- a/code/modules/mining/equipment/explorer_gear.dm
+++ b/code/modules/mining/equipment/explorer_gear.dm
@@ -11,6 +11,7 @@
heat_protection = CHEST|GROIN|LEGS|ARMS
hoodtype = /obj/item/clothing/head/hooded/explorer
armor = list("melee" = 30, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 50, "bio" = 100, "rad" = 50, "fire" = 50, "acid" = 50)
+ flags_inv = HIDEJUMPSUIT|HIDETAUR
allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe)
resistance_flags = FIRE_PROOF
tauric = TRUE //Citadel Add for tauric hardsuits
@@ -129,7 +130,7 @@
/obj/item/clothing/suit/hooded/explorer/seva
name = "SEVA Suit"
- desc = "A fire-proof suit for exploring hot environments."
+ desc = "A fire-proof suit for exploring hot environments. Its design and material make it easier for a Goliath to keep their grip on the wearer."
icon_state = "seva"
item_state = "seva"
w_class = WEIGHT_CLASS_BULKY
@@ -141,7 +142,7 @@
/obj/item/clothing/head/hooded/explorer/seva
name = "SEVA Hood"
- desc = "A fire-proof hood for exploring hot environments."
+ desc = "A fire-proof hood for exploring hot environments. Its design and material make it easier for a Goliath to keep their grip on the wearer."
icon_state = "seva"
item_state = "seva"
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
@@ -159,7 +160,7 @@
/obj/item/clothing/suit/hooded/explorer/exo
name = "Exo-suit"
- desc = "A robust suit for exploring dangerous environments."
+ desc = "A robust suit for fighting dangerous animals. Its design and material make it harder for a Goliath to keep their grip on the wearer."
icon_state = "exo"
item_state = "exo"
w_class = WEIGHT_CLASS_BULKY
@@ -170,7 +171,7 @@
/obj/item/clothing/head/hooded/explorer/exo
name = "Exo-hood"
- desc = "A robust helmet for exploring dangerous environments."
+ desc = "A robust helmet for fighting dangerous animals. Its design and material make it harder for a Goliath to keep their grip on the wearer."
icon_state = "exo"
item_state = "exo"
armor = list("melee" = 65, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 60, "bio" = 25, "rad" = 10, "fire" = 0, "acid" = 0)
diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm
index 994d082585..d54b8256a9 100644
--- a/code/modules/mob/dead/new_player/preferences_setup.dm
+++ b/code/modules/mob/dead/new_player/preferences_setup.dm
@@ -17,6 +17,8 @@
hair_color = random_short_color()
facial_hair_color = hair_color
eye_color = random_eye_color()
+ horn_color = "85615a"
+ wing_color = "fff"
if(!pref_species)
var/rando_race = pick(GLOB.roundstart_races)
pref_species = new rando_race()
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
index 554b7edfdb..6c42177c3c 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
@@ -30,6 +30,7 @@
// Decorative wings
/datum/sprite_accessory/deco_wings
icon = 'icons/mob/wings.dmi'
+ color_src = WINGCOLOR
/datum/sprite_accessory/deco_wings/plain
name = "Plain"
@@ -104,6 +105,22 @@
center = TRUE
dimension_y = 34
+/datum/sprite_accessory/deco_wings/bee
+ name = "Bee"
+ icon_state = "bee"
+
+/datum/sprite_accessory/deco_wings/fairy
+ name = "Fairy"
+ icon_state = "fairy"
+
+/datum/sprite_accessory/deco_wings/bat
+ name = "Bat"
+ icon_state = "bat"
+
+/datum/sprite_accessory/deco_wings/feathery
+ name = "Feathery"
+ icon_state = "feathery"
+
/datum/sprite_accessory/deco_wings/none
name = "None"
icon_state = "none"
@@ -113,7 +130,7 @@
/datum/sprite_accessory/insect_wings
icon = 'icons/mob/wings.dmi'
- color_src = null
+ color_src = WINGCOLOR
/datum/sprite_accessory/insect_wings/none
name = "None"
@@ -183,35 +200,10 @@
name = "Snow"
icon_state = "snow"
-/datum/sprite_accessory/insect_wings/colored
- name = "Colored (Hair)"
- icon_state = "snowplain"
- color_src = HAIR
-
-/datum/sprite_accessory/insect_fluff/colored1
- name = "Colored (Primary)"
- icon_state = "snowplain"
- color_src = MUTCOLORS
-
-/datum/sprite_accessory/insect_fluff/colored2
- name = "Colored (Secondary)"
- icon_state = "snowplain"
- color_src = MUTCOLORS2
-
-/datum/sprite_accessory/insect_fluff/colored3
- name = "Colored (Tertiary)"
- icon_state = "snowplain"
- color_src = MUTCOLORS3
-
/datum/sprite_accessory/insect_wings/bee
name = "Bee"
icon_state = "bee"
-/datum/sprite_accessory/insect_wings/bee_color
- name = "Bee (Hair colored)"
- icon_state = "bee"
- color_src = HAIR
-
/datum/sprite_accessory/insect_wings/fairy
name = "Fairy"
icon_state = "fairy"
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index e32d073500..657c32ba01 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -19,6 +19,8 @@
var/horn_color = "85615a" //specific horn colors, because why not?
+ var/wing_color = "fff" //wings too
+
var/skin_tone = "caucasian1" //Skin tone
var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 1f843483ee..a59d9e914b 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -37,6 +37,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/hair_alpha = 255 // the alpha used by the hair. 255 is completely solid, 0 is transparent.
var/horn_color //specific horn colors, because why not?
+ var/wing_color
var/use_skintones = 0 // does it use skintones or not? (spoiler alert this is only used by humans)
var/exotic_blood = "" // If your race wants to bleed something other than bog standard blood, change this to reagent id.
@@ -869,6 +870,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
accessory_overlay.color = "#[H.eye_color]"
if(HORNCOLOR)
accessory_overlay.color = "#[H.horn_color]"
+ if(WINGCOLOR)
+ accessory_overlay.color = "#[H.wing_color]"
else
accessory_overlay.color = forced_colour
else
@@ -946,6 +949,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(HORNCOLOR)
extra_accessory_overlay.color = "#[H.horn_color]"
+ if(WINGCOLOR)
+ extra_accessory_overlay.color = "#[H.wing_color]"
if(OFFSET_MUTPARTS in H.dna.species.offset_features)
extra_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
@@ -985,6 +990,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
extra2_accessory_overlay.color = "#[H.hair_color]"
if(HORNCOLOR)
extra2_accessory_overlay.color = "#[H.horn_color]"
+ if(WINGCOLOR)
+ extra2_accessory_overlay.color = "#[H.wing_color]"
if(OFFSET_MUTPARTS in H.dna.species.offset_features)
extra2_accessory_overlay.pixel_x += H.dna.species.offset_features[OFFSET_MUTPARTS][1]
diff --git a/code/modules/mob/living/carbon/human/species_types/bugmen.dm b/code/modules/mob/living/carbon/human/species_types/bugmen.dm
index 94dba550b6..b4e55b60a5 100644
--- a/code/modules/mob/living/carbon/human/species_types/bugmen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/bugmen.dm
@@ -3,7 +3,7 @@
id = "insect"
say_mod = "flutters"
default_color = "00FF00"
- species_traits = list(LIPS,NOEYES,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR)
+ species_traits = list(LIPS,NOEYES,HAIR,FACEHAIR,MUTCOLORS,HORNCOLOR,WINGCOLOR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
mutant_bodyparts = list("mam_ears", "mam_snout", "mam_tail", "taur", "insect_wings", "mam_snouts", "insect_fluff","horns")
default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_tail" = "None", "mam_ears" = "None",
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 1ee697d66c..ec58a3be9c 100644
--- a/code/modules/mob/living/carbon/human/species_types/felinid.dm
+++ b/code/modules/mob/living/carbon/human/species_types/felinid.dm
@@ -4,8 +4,8 @@
id = "felinid"
limbs_id = "human"
- mutant_bodyparts = list("mam_ears", "mam_tail")
- default_features = list("mcolor" = "FFF", "mam_tail" = "Cat", "mam_ears" = "Cat", "wings" = "None")
+ mutant_bodyparts = list("mam_ears", "mam_tail", "deco_wings")
+ default_features = list("mcolor" = "FFF", "mam_tail" = "Cat", "mam_ears" = "Cat", "wings" = "None", "deco_wings" = "None")
mutantears = /obj/item/organ/ears/cat
mutanttail = /obj/item/organ/tail/cat
diff --git a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
index 07e594d20b..0390d4accc 100644
--- a/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/furrypeople.dm
@@ -3,7 +3,7 @@
id = "mammal"
default_color = "4B4B4B"
should_draw_citadel = TRUE
- species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR)
+ species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR,HORNCOLOR,WINGCOLOR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "mam_snouts", "deco_wings", "taur", "horns", "legs")
default_features = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "deco_wings" = "None",
diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm
index 96b43795a2..3332465c78 100644
--- a/code/modules/mob/living/carbon/human/species_types/humans.dm
+++ b/code/modules/mob/living/carbon/human/species_types/humans.dm
@@ -1,41 +1,42 @@
-/datum/species/human
- name = "Human"
- id = "human"
- default_color = "FFFFFF"
- species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY)
- mutant_bodyparts = list("ears", "tail_human", "wings", "taur") // CITADEL EDIT gives humans snowflake parts
- default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF","tail_human" = "None", "ears" = "None", "wings" = "None", "taur" = "None")
- use_skintones = 1
- skinned_type = /obj/item/stack/sheet/animalhide/human
- disliked_food = GROSS | RAW
- liked_food = JUNKFOOD | FRIED
-
-/datum/species/human/qualifies_for_rank(rank, list/features)
- return TRUE //Pure humans are always allowed in all roles.
-
-/datum/species/human/spec_death(gibbed, mob/living/carbon/human/H)
- if(H)
- stop_wagging_tail(H)
-
-/datum/species/human/spec_stun(mob/living/carbon/human/H,amount)
- if(H)
- stop_wagging_tail(H)
- . = ..()
-
-/datum/species/human/can_wag_tail(mob/living/carbon/human/H)
- return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts)
-
-/datum/species/human/is_wagging_tail(mob/living/carbon/human/H)
- return ("waggingtail_human" in mutant_bodyparts)
-
-/datum/species/human/start_wagging_tail(mob/living/carbon/human/H)
- if("tail_human" in mutant_bodyparts)
- mutant_bodyparts -= "tail_human"
- mutant_bodyparts |= "waggingtail_human"
- H.update_body()
-
-/datum/species/human/stop_wagging_tail(mob/living/carbon/human/H)
- if("waggingtail_human" in mutant_bodyparts)
- mutant_bodyparts -= "waggingtail_human"
- mutant_bodyparts |= "tail_human"
- H.update_body()
+/datum/species/human
+ name = "Human"
+ id = "human"
+ default_color = "FFFFFF"
+
+ species_traits = list(EYECOLOR,HAIR,FACEHAIR,LIPS,MUTCOLORS_PARTSONLY,WINGCOLOR)
+ mutant_bodyparts = list("ears", "tail_human", "wings", "taur", "deco_wings") // CITADEL EDIT gives humans snowflake parts
+ default_features = list("mcolor" = "FFF", "mcolor2" = "FFF","mcolor3" = "FFF","tail_human" = "None", "ears" = "None", "wings" = "None", "taur" = "None", "deco_wings" = "None")
+ use_skintones = 1
+ skinned_type = /obj/item/stack/sheet/animalhide/human
+ disliked_food = GROSS | RAW
+ liked_food = JUNKFOOD | FRIED
+
+/datum/species/human/qualifies_for_rank(rank, list/features)
+ return TRUE //Pure humans are always allowed in all roles.
+
+/datum/species/human/spec_death(gibbed, mob/living/carbon/human/H)
+ if(H)
+ stop_wagging_tail(H)
+
+/datum/species/human/spec_stun(mob/living/carbon/human/H,amount)
+ if(H)
+ stop_wagging_tail(H)
+ . = ..()
+
+/datum/species/human/can_wag_tail(mob/living/carbon/human/H)
+ return ("tail_human" in mutant_bodyparts) || ("waggingtail_human" in mutant_bodyparts)
+
+/datum/species/human/is_wagging_tail(mob/living/carbon/human/H)
+ return ("waggingtail_human" in mutant_bodyparts)
+
+/datum/species/human/start_wagging_tail(mob/living/carbon/human/H)
+ if("tail_human" in mutant_bodyparts)
+ mutant_bodyparts -= "tail_human"
+ mutant_bodyparts |= "waggingtail_human"
+ H.update_body()
+
+/datum/species/human/stop_wagging_tail(mob/living/carbon/human/H)
+ if("waggingtail_human" in mutant_bodyparts)
+ mutant_bodyparts -= "waggingtail_human"
+ mutant_bodyparts |= "tail_human"
+ H.update_body()
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 03cd514300..8e98569644 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -4,10 +4,10 @@
id = "jelly"
default_color = "00FF90"
say_mod = "chirps"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD)
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD,WINGCOLOR)
mutantlungs = /obj/item/organ/lungs/slime
- mutant_bodyparts = list("mam_tail", "mam_ears", "mam_snouts", "taur") //CIT CHANGE
- default_features = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None") //CIT CHANGE
+ mutant_bodyparts = list("mam_tail", "mam_ears", "mam_snouts", "taur", "deco_wings") //CIT CHANGE
+ default_features = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None", "deco_wings" = "None") //CIT CHANGE
inherent_traits = list(TRAIT_TOXINLOVER)
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
exotic_blood = "slimejelly"
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 4dbfd23df8..a719f2eda0 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -4,16 +4,16 @@
id = "lizard"
say_mod = "hisses"
default_color = "00FF00"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR)
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,LIPS,HORNCOLOR,WINGCOLOR)
inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_REPTILE)
- mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur")
+ mutant_bodyparts = list("tail_lizard", "snout", "spines", "horns", "frills", "body_markings", "legs", "taur", "deco_wings")
mutanttongue = /obj/item/organ/tongue/lizard
mutanttail = /obj/item/organ/tail/lizard
coldmod = 1.5
heatmod = 0.67
default_features = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "snout" = "Round",
"horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None",
- "legs" = "Digitigrade", "taur" = "None")
+ "legs" = "Digitigrade", "taur" = "None", "deco_wings" = "None")
attack_verb = "slash"
attack_sound = 'sound/weapons/slash.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index 563ab7cfb6..fbb6074ba2 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -79,7 +79,7 @@
-/mob/living/proc/apply_effect(effect = 0,effecttype = EFFECT_STUN, blocked = FALSE)
+/mob/living/proc/apply_effect(effect = 0,effecttype = EFFECT_STUN, blocked = FALSE, knockdown_stamoverride, knockdown_stammax)
var/hit_percent = (100-blocked)/100
if(!effect || (hit_percent <= 0))
return 0
@@ -87,7 +87,7 @@
if(EFFECT_STUN)
Stun(effect * hit_percent)
if(EFFECT_KNOCKDOWN)
- Knockdown(effect * hit_percent)
+ Knockdown(effect * hit_percent, override_stamdmg = knockdown_stammax ? CLAMP(knockdown_stamoverride, 0, knockdown_stammax-getStaminaLoss()) : knockdown_stamoverride)
if(EFFECT_UNCONSCIOUS)
Unconscious(effect * hit_percent)
if(EFFECT_IRRADIATE)
@@ -107,13 +107,13 @@
return 1
-/mob/living/proc/apply_effects(stun = 0, knockdown = 0, unconscious = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = FALSE, stamina = 0, jitter = 0)
+/mob/living/proc/apply_effects(stun = 0, knockdown = 0, unconscious = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = FALSE, stamina = 0, jitter = 0, kd_stamoverride, kd_stammax)
if(blocked >= 100)
return 0
if(stun)
apply_effect(stun, EFFECT_STUN, blocked)
if(knockdown)
- apply_effect(knockdown, EFFECT_KNOCKDOWN, blocked)
+ apply_effect(knockdown, EFFECT_KNOCKDOWN, blocked, kd_stamoverride, kd_stammax)
if(unconscious)
apply_effect(unconscious, EFFECT_UNCONSCIOUS, blocked)
if(irradiate)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 6c58921abc..2b2cc4c0b5 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -226,6 +226,9 @@
to_chat(src,"ERROR: Module installer reply timeout. Please check internal connections.")
return
+ if(!CONFIG_GET(flag/disable_secborg) && GLOB.security_level < CONFIG_GET(number/minimum_secborg_alert))
+ to_chat(src, "NOTICE: Due to local station regulations, the security cyborg module and its variants are only available during [num2seclevel(CONFIG_GET(number/minimum_secborg_alert))] alert and greater.")
+
var/list/modulelist = list("Standard" = /obj/item/robot_module/standard, \
"Engineering" = /obj/item/robot_module/engineering, \
"Medical" = /obj/item/robot_module/medical, \
@@ -234,7 +237,7 @@
"Service" = /obj/item/robot_module/butler)
if(!CONFIG_GET(flag/disable_peaceborg))
modulelist["Peacekeeper"] = /obj/item/robot_module/peacekeeper
- if(!CONFIG_GET(flag/disable_secborg))
+ if(BORG_SEC_AVAILABLE)
modulelist["Security"] = /obj/item/robot_module/security
modulelist += get_cit_modules() //Citadel change - adds Citadel's borg modules.
diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm
index 8bf1874d84..d31809e9aa 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/support.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm
@@ -30,7 +30,7 @@
C.adjustBruteLoss(-5)
C.adjustFireLoss(-5)
C.adjustOxyLoss(-5)
- C.adjustToxLoss(-5)
+ C.adjustToxLoss(-5, forced = TRUE)
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(C))
if(namedatum)
H.color = namedatum.colour
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 120976b61f..8d2162a0ff 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -421,7 +421,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
if(prob(50))
radiation_pulse(src, power * (1 + (tritiumcomp * TRITIUM_RADIOACTIVITY_MODIFIER) + ((pluoxiumcomp * PLUOXIUM_RADIOACTIVITY_MODIFIER) * pluoxiumbonus) * (power_transmission_bonus/(10-(bzcomp * BZ_RADIOACTIVITY_MODIFIER))))) // Rad Modifiers BZ(500%), Tritium(300%), and Pluoxium(-200%)
if(bzcomp >= 0.4 && prob(30 * bzcomp))
- src.fire_nuclear_particles() // Start to emit radballs at a maximum of 30% chance per tick
+ fire_nuclear_particle() // Start to emit radballs at a maximum of 30% chance per tick
var/device_energy = power * REACTION_POWER_MODIFIER
diff --git a/code/modules/projectiles/ammunition/energy/laser.dm b/code/modules/projectiles/ammunition/energy/laser.dm
index 638711e8d4..0940144721 100644
--- a/code/modules/projectiles/ammunition/energy/laser.dm
+++ b/code/modules/projectiles/ammunition/energy/laser.dm
@@ -71,9 +71,3 @@
projectile_type = /obj/item/projectile/beam/mindflayer
select_name = "MINDFUCK"
fire_sound = 'sound/weapons/laser.ogg'
-
-/obj/item/ammo_casing/energy/laser/weak
- projectile_type = /obj/item/projectile/beam/weak/minigun
- e_cost = 10
- fire_sound = 'sound/weapons/gatling.ogg'
- click_cooldown_override = 1
diff --git a/code/modules/projectiles/guns/energy/minigun.dm b/code/modules/projectiles/guns/energy/minigun.dm
deleted file mode 100644
index d903cda47c..0000000000
--- a/code/modules/projectiles/guns/energy/minigun.dm
+++ /dev/null
@@ -1,149 +0,0 @@
-//The ammo/gun is stored in a back slot item
-/obj/item/minigunpack2
- name = " Laser Gatling Pack"
- desc = "A massive battery pack with an attached laser gatling gun!"
- icon = 'icons/obj/guns/minigun.dmi'
- icon_state = "holstered"
- item_state = "backpack"
- lefthand_file = 'icons/mob/inhands/equipment/backpack_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/backpack_righthand.dmi'
- slot_flags = ITEM_SLOT_BACK
- w_class = WEIGHT_CLASS_HUGE
- var/obj/item/gun/energy/minigun/gun
- var/armed = 0 //whether the gun is attached, 0 is attached, 1 is the gun is wielded.
- var/overheat = 0
- var/overheat_max = 60
- var/heat_diffusion = 5
-
-/obj/item/minigunpack2/Initialize()
- . = ..()
- gun = new(src)
- START_PROCESSING(SSobj, src)
-
-/obj/item/minigunpack2/Destroy()
- STOP_PROCESSING(SSobj, src)
- return ..()
-
-/obj/item/minigunpack2/process()
- overheat = max(0, overheat - heat_diffusion)
-
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/minigunpack2/attack_hand(var/mob/living/carbon/user)
- if(src.loc == user)
- if(!armed)
- if(user.get_item_by_slot(SLOT_BACK) == src)
- armed = 1
- if(!user.put_in_hands(gun))
- armed = 0
- to_chat(user, "You need a free hand to hold the gun!")
- return
- update_icon()
- user.update_inv_back()
- else
- to_chat(user, "You are already holding the gun!")
- else
- ..()
-
-/obj/item/minigunpack2/attackby(obj/item/W, mob/user, params)
- if(W == gun) //Don't need armed check, because if you have the gun assume its armed.
- user.dropItemToGround(gun, TRUE)
- else
- ..()
-
-/obj/item/minigunpack2/dropped(mob/user)
- if(armed)
- user.dropItemToGround(gun, TRUE)
-
-/obj/item/minigunpack2/MouseDrop(atom/over_object)
- . = ..()
- if(armed)
- return
- if(iscarbon(usr))
- var/mob/M = usr
-
- if(!over_object)
- return
-
- if(!M.incapacitated())
-
- if(istype(over_object, /obj/screen/inventory/hand))
- var/obj/screen/inventory/hand/H = over_object
- M.putItemFromInventoryInHandIfPossible(src, H.held_index)
-
-
-/obj/item/minigunpack2/update_icon()
- if(armed)
- icon_state = "notholstered"
- else
- icon_state = "holstered"
-
-/obj/item/minigunpack2/proc/attach_gun(var/mob/user)
- if(!gun)
- gun = new(src)
- gun.forceMove(src)
- armed = 0
- if(user)
- to_chat(user, "You attach the [gun.name] to the [name].")
- else
- src.visible_message("The [gun.name] snaps back onto the [name]!")
- update_icon()
- user.update_inv_back()
-
-
-/obj/item/gun/energy/minigun
- name = "laser gatling gun"
- desc = "An advanced laser cannon with an incredible rate of fire. Requires a bulky backpack power source to use."
- icon = 'icons/obj/guns/minigun.dmi'
- icon_state = "minigun_spin"
- item_state = "minigun"
- flags_1 = CONDUCT_1
- force = 15
- recoil = 2
- slowdown = 1
- slot_flags = null
- w_class = WEIGHT_CLASS_HUGE
- materials = list()
- ammo_type = list(/obj/item/ammo_casing/energy/laser/weak)
- burst_size = 2
- automatic = 1
- can_charge = 0
- selfcharge = EGUN_SELFCHARGE
- charge_tick = 2
- charge_delay = 5
- weapon_weight = WEAPON_HEAVY
- item_flags = NEEDS_PERMIT | SLOWS_WHILE_IN_HAND
- var/obj/item/minigunpack2/ammo_pack
-
-/obj/item/gun/energy/minigun/Initialize()
- if(istype(loc, /obj/item/minigunpack2)) //We should spawn inside an ammo pack so let's use that one.
- ammo_pack = loc
- else
- return INITIALIZE_HINT_QDEL //No pack, no gun
-
- return ..()
-
-/obj/item/gun/energy/minigun/attack_self(mob/living/user)
- return
-
-/obj/item/gun/energy/minigun/dropped(mob/user)
- if(ammo_pack)
- ammo_pack.attach_gun(user)
- else
- qdel(src)
-
-/obj/item/gun/energy/minigun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
- if(ammo_pack)
- if(ammo_pack.overheat < ammo_pack.overheat_max)
- ammo_pack.overheat += burst_size
- ..()
- else
- to_chat(user, "The gun's heat sensor locked the trigger to prevent lens damage.")
-
-/obj/item/gun/energy/minigun/afterattack(atom/target, mob/living/user, flag, params)
- if(!ammo_pack || ammo_pack.loc != user)
- to_chat(user, "You need the backpack power source to fire the gun!")
- . = ..()
-
-/obj/item/gun/energy/minigun/dropped(mob/living/user)
- ammo_pack.attach_gun(user)
-
diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm
index 44c7894467..c5d4c36813 100644
--- a/code/modules/projectiles/guns/energy/stun.dm
+++ b/code/modules/projectiles/guns/energy/stun.dm
@@ -20,7 +20,7 @@
name = "hybrid taser"
desc = "A dual-mode taser designed to fire both short-range high-power electrodes and long-range disabler beams."
icon_state = "advtaser"
- ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/disabler)
+ ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/electrode)
ammo_x_offset = 2
/obj/item/gun/energy/e_gun/advtaser/cyborg
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index efae090707..dace31c2f7 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -88,6 +88,8 @@
//Effects
var/stun = 0
var/knockdown = 0
+ var/knockdown_stamoverride
+ var/knockdown_stam_max
var/unconscious = 0
var/irradiate = 0
var/stutter = 0
@@ -202,7 +204,7 @@
else
L.log_message("has been shot by [firer] with [src]", LOG_ATTACK, color="orange")
- return L.apply_effects(stun, knockdown, unconscious, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter)
+ return L.apply_effects(stun, knockdown, unconscious, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter, knockdown_stamoverride, knockdown_stam_max)
/obj/item/projectile/proc/vol_by_damage()
if(src.damage)
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index d8154b367d..e43eb5a3bc 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -39,14 +39,6 @@
/obj/item/projectile/beam/weak
damage = 15
-/obj/item/projectile/beam/weak/minigun
- damage = 12.5
- armour_penetration = 40
-
-/obj/item/projectile/beam/weak/minigun/Initialize()
- .=..()
- speed = pick(0.7,0.75,0.8,0.85,0.9,0.95,1,1.05,1.1,1.15)
-
/obj/item/projectile/beam/weak/penetrator
armour_penetration = 50
diff --git a/code/modules/projectiles/projectile/energy/nuclear_particle.dm b/code/modules/projectiles/projectile/energy/nuclear_particle.dm
index 1753587ad3..e08f806fe5 100644
--- a/code/modules/projectiles/projectile/energy/nuclear_particle.dm
+++ b/code/modules/projectiles/projectile/energy/nuclear_particle.dm
@@ -3,10 +3,9 @@
name = "nuclear particle"
icon_state = "nuclear_particle"
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
- damage = 20
- damage_type = TOX
- irradiate = 2500 //enough to knockdown and induce vomiting
- speed = 0.4
+ flag = "rad"
+ irradiate = 5000
+ speed = 0.4
hitsound = 'sound/weapons/emitter2.ogg'
impact_type = /obj/effect/projectile/impact/xray
var/static/list/particle_colors = list(
@@ -25,22 +24,6 @@
add_atom_colour(particle_colors[our_color], FIXED_COLOUR_PRIORITY)
set_light(4, 3, particle_colors[our_color]) //Range of 4, brightness of 3 - Same range as a flashlight
-/atom/proc/fire_nuclear_particles(power_ratio) //used by fusion to fire random # of nuclear particles - power ratio determines about how many are fired
- var/random_particles = rand(3,6)
- var/particles_to_fire
- var/particles_fired
- switch(power_ratio) //multiply random_particles * factor for whatever tier
- if(0 to FUSION_MID_TIER_THRESHOLD)
- particles_to_fire = random_particles * FUSION_PARTICLE_FACTOR_LOW
- if(FUSION_MID_TIER_THRESHOLD to FUSION_HIGH_TIER_THRESHOLD)
- particles_to_fire = random_particles * FUSION_PARTICLE_FACTOR_MID
- if(FUSION_HIGH_TIER_THRESHOLD to FUSION_SUPER_TIER_THRESHOLD)
- particles_to_fire = random_particles * FUSION_PARTICLE_FACTOR_HIGH
- if(FUSION_SUPER_TIER_THRESHOLD to INFINITY)
- particles_to_fire = random_particles * FUSION_PARTICLE_FACTOR_SUPER
- while(particles_to_fire)
- particles_fired++
- var/angle = rand(0,360)
- var/obj/item/projectile/energy/nuclear_particle/P = new /obj/item/projectile/energy/nuclear_particle(src)
- addtimer(CALLBACK(P, /obj/item/projectile.proc/fire, angle), particles_fired) //multiply particles fired * delay so the particles end up stagnated (once every decisecond)
- particles_to_fire--
\ No newline at end of file
+/atom/proc/fire_nuclear_particle(angle = rand(0,360)) //used by fusion to fire random nuclear particles. Fires one particle in a random direction.
+ var/obj/item/projectile/energy/nuclear_particle/P = new /obj/item/projectile/energy/nuclear_particle(src)
+ P.fire(angle)
diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm
index 895a165f49..d7c8b8b082 100644
--- a/code/modules/projectiles/projectile/energy/stun.dm
+++ b/code/modules/projectiles/projectile/energy/stun.dm
@@ -3,7 +3,9 @@
icon_state = "spark"
color = "#FFFF00"
nodamage = 1
- knockdown = 100
+ knockdown = 60
+ knockdown_stamoverride = 36
+ knockdown_stam_max = 50
stutter = 5
jitter = 20
hitsound = 'sound/weapons/taserhit.ogg'
@@ -11,6 +13,7 @@
tracer_type = /obj/effect/projectile/tracer/stun
muzzle_type = /obj/effect/projectile/muzzle/stun
impact_type = /obj/effect/projectile/impact/stun
+ var/tase_duration = 50
/obj/item/projectile/energy/electrode/on_hit(atom/target, blocked = FALSE)
. = ..()
@@ -23,6 +26,7 @@
if(C.dna && C.dna.check_mutation(HULK))
C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
else if((C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE))
+ C.apply_status_effect(STATUS_EFFECT_TASED, tase_duration)
addtimer(CALLBACK(C, /mob/living/carbon.proc/do_jitter_animation, jitter), 5)
/obj/item/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet
diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm
index 1d660df794..e81cbf528f 100644
--- a/code/modules/surgery/surgery.dm
+++ b/code/modules/surgery/surgery.dm
@@ -42,7 +42,7 @@
if(replaced_by == /datum/surgery)
return FALSE
- if(HAS_TRAIT(user, TRAIT_SURGEON))
+ if(HAS_TRAIT(user, TRAIT_SURGEON) || HAS_TRAIT(user.mind, TRAIT_SURGEON))
if(replaced_by)
return FALSE
else
diff --git a/config/game_options.txt b/config/game_options.txt
index 2e346ce0ac..02d620eb31 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -267,6 +267,10 @@ ALLOW_AI_MULTICAM
## Uncomment to prevent the security cyborg module from being chosen
#DISABLE_SECBORG
+## Determines the minimum alert level for the security cyborg model to be chosen
+## 0: Green, 1:Blue, 2:Amber, 3:Red, 4:Delta
+MINIMUM_SECBORG_ALERT 3
+
## Peacekeeper Borg ###
## Uncomment to prevent the peacekeeper cyborg module from being chosen
#DISABLE_PEACEBORG
diff --git a/html/changelogs/AutoChangeLog-pr-9214.yml b/html/changelogs/AutoChangeLog-pr-9214.yml
new file mode 100644
index 0000000000..edc41426f2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9214.yml
@@ -0,0 +1,7 @@
+author: "original by GuyonBroadway, SkowronX, and Arizon5. port by sishen1542 and kerse"
+delete-after: True
+changes:
+ - rscadd: "Clockwork cultists may now summon forth Neovgre, the ratvrarian super weapon. This powerful mech can be summoned when applications scripture has been unlocked, boasts superior offensive and defensive capabilities, however once a pilot enters he cannot leave and is doomed to die with the mech."
+ - imageadd: "Sexy Sprite work courtesy or SkowronX from /tg/"
+ - imageadd: "brass edits by Arizon5"
+ - soundadd: "steamy laser by kerse"
diff --git a/html/changelogs/AutoChangeLog-pr-9246.yml b/html/changelogs/AutoChangeLog-pr-9246.yml
new file mode 100644
index 0000000000..adffae737b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9246.yml
@@ -0,0 +1,8 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - bugfix: "blood on your body floating a bit to your right if you're a taur"
+ - bugfix: "some suits having no icon on tauric characters"
+ - tweak: "front facing CMO hardsuit icon for naga taurs"
+ - tweak: "colour of medical cross on CMO hardsuit for taurs"
+ - bugfix: "taur body and jumpsuit showing through mining suits"
diff --git a/html/changelogs/AutoChangeLog-pr-9466.yml b/html/changelogs/AutoChangeLog-pr-9466.yml
new file mode 100644
index 0000000000..473ec04eec
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9466.yml
@@ -0,0 +1,5 @@
+author: "Bhijn"
+delete-after: True
+changes:
+ - tweak: "Security borgs and K9s are now only available during red alert or higher."
+ - server: "Headmins or other folks with access to the server's config can choose the minimum alert level for secborgs to be chosen via the MINIMUM_SECBORG_ALERT config option. See the default game_options.txt for more info."
diff --git a/html/changelogs/AutoChangeLog-pr-9503.yml b/html/changelogs/AutoChangeLog-pr-9503.yml
new file mode 100644
index 0000000000..7b79ad7185
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9503.yml
@@ -0,0 +1,6 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "The taser's electrode has been reworked. Instead of being a strong knockdown that deals a heavy amount of stamloss, it now causes a weak knockdown, applies a debilitating status effect for 5 seconds, and deals 35 stamloss on hit up to a maximum 50 total stamloss."
+ - balance: "Roundstart turrets now have a nonlethal projectile that gets used when they're set to stun and the target is resting"
+ - tweak: "Hybrid tasers now have disablers set as their default mode."
diff --git a/html/changelogs/AutoChangeLog-pr-9520.yml b/html/changelogs/AutoChangeLog-pr-9520.yml
new file mode 100644
index 0000000000..20188b7137
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9520.yml
@@ -0,0 +1,4 @@
+author: "r4d6"
+delete-after: True
+changes:
+ - rscadd: "Added Decorative Wings for Humans, Felinids, Slimepersons and Lizardpeoples."
diff --git a/html/changelogs/AutoChangeLog-pr-9524.yml b/html/changelogs/AutoChangeLog-pr-9524.yml
new file mode 100644
index 0000000000..df1ff4959a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9524.yml
@@ -0,0 +1,7 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - rscadd: "Decorative and insect wings can now be coloured individually, similar to horns."
+ - bugfix: "people getting assigned wings if their savefile is old."
+ - rscdel: "wings that take the hair colour. Unnecessary if you can just set the colour."
+ - tweak: "Cannot make horns pure black. Trying to do so will set it to a default value."
diff --git a/html/changelogs/AutoChangeLog-pr-9525.yml b/html/changelogs/AutoChangeLog-pr-9525.yml
new file mode 100644
index 0000000000..a77b9e28b2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9525.yml
@@ -0,0 +1,4 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - bugfix: "decorative angel wings being invisible"
diff --git a/html/changelogs/AutoChangeLog-pr-9534.yml b/html/changelogs/AutoChangeLog-pr-9534.yml
new file mode 100644
index 0000000000..4654503f9b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9534.yml
@@ -0,0 +1,5 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - bugfix: "abductors now actually work"
+ - tweak: "abductor scientist has their own greet message now"
diff --git a/html/changelogs/AutoChangeLog-pr-9536.yml b/html/changelogs/AutoChangeLog-pr-9536.yml
new file mode 100644
index 0000000000..ffac8e8f6f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9536.yml
@@ -0,0 +1,4 @@
+author: "r4d6"
+delete-after: True
+changes:
+ - tweak: "Change the SEVA suit & Exo-suit's descriptions"
diff --git a/html/changelogs/AutoChangeLog-pr-9537.yml b/html/changelogs/AutoChangeLog-pr-9537.yml
new file mode 100644
index 0000000000..24318d4364
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9537.yml
@@ -0,0 +1,4 @@
+author: "Hatterhat"
+delete-after: True
+changes:
+ - rscadd: "Magnetic pistols now fit in boot pockets - jackboots, workboots, etc."
diff --git a/html/changelogs/AutoChangeLog-pr-9540.yml b/html/changelogs/AutoChangeLog-pr-9540.yml
new file mode 100644
index 0000000000..8dd4e46bc6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9540.yml
@@ -0,0 +1,4 @@
+author: "YakumoChen"
+delete-after: True
+changes:
+ - rscdel: "Reverted laser miniguns."
diff --git a/html/changelogs/AutoChangeLog-pr-9545.yml b/html/changelogs/AutoChangeLog-pr-9545.yml
new file mode 100644
index 0000000000..970e463f41
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9545.yml
@@ -0,0 +1,4 @@
+author: "Ghommie (original PR by Barhandar"
+delete-after: True
+changes:
+ - bugfix: "Pumpkin meteors on Halloween now replace catastrophic meteor waves, instead of ALL OF THEM."
diff --git a/html/changelogs/AutoChangeLog-pr-9547.yml b/html/changelogs/AutoChangeLog-pr-9547.yml
new file mode 100644
index 0000000000..7e0abca8f4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9547.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Silicons can now operate teleporter, medical and security records console from a distance again."
diff --git a/icons/mecha/neovgre.dmi b/icons/mecha/neovgre.dmi
new file mode 100644
index 0000000000..ba9d57daf9
Binary files /dev/null and b/icons/mecha/neovgre.dmi differ
diff --git a/icons/mob/wings.dmi b/icons/mob/wings.dmi
index 58f4cb735c..105da7d865 100644
Binary files a/icons/mob/wings.dmi and b/icons/mob/wings.dmi differ
diff --git a/icons/obj/closet.dmi b/icons/obj/closet.dmi
index 1b8eada39c..d3f055d1f2 100644
Binary files a/icons/obj/closet.dmi and b/icons/obj/closet.dmi differ
diff --git a/icons/obj/turnstile.dmi b/icons/obj/turnstile.dmi
new file mode 100644
index 0000000000..0107ade705
Binary files /dev/null and b/icons/obj/turnstile.dmi differ
diff --git a/modular_citadel/code/modules/mob/living/carbon/carbon.dm b/modular_citadel/code/modules/mob/living/carbon/carbon.dm
index 43931db689..02b98bdbf2 100644
--- a/modular_citadel/code/modules/mob/living/carbon/carbon.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/carbon.dm
@@ -18,9 +18,13 @@
return FALSE
return .
-/mob/living/carbon/proc/toggle_combat_mode()
+/mob/living/carbon/proc/toggle_combat_mode(forced)
if(recoveringstam)
return TRUE
+ if(!forced)
+ for(var/datum/status_effect/S in status_effects)
+ if(S.blocks_combatmode)
+ return TRUE
combatmode = !combatmode
if(voremode)
toggle_vore_mode()
diff --git a/modular_citadel/code/modules/mob/living/living.dm b/modular_citadel/code/modules/mob/living/living.dm
index ac79ea7f25..ed33041d58 100644
--- a/modular_citadel/code/modules/mob/living/living.dm
+++ b/modular_citadel/code/modules/mob/living/living.dm
@@ -116,7 +116,7 @@
to_chat(src, "You're too exhausted to keep going...")
resting = TRUE
if(combatmode)
- toggle_combat_mode()
+ toggle_combat_mode(TRUE)
recoveringstam = TRUE
filters += CIT_FILTER_STAMINACRIT
update_canmove()
diff --git a/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm b/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm
index b16ac1d586..c063d8b9ef 100644
--- a/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/modular_citadel/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -13,7 +13,7 @@
/mob/living/silicon/robot/proc/get_cit_modules()
var/list/modulelist = list()
modulelist["MediHound"] = /obj/item/robot_module/medihound
- if(!CONFIG_GET(flag/disable_secborg))
+ if(BORG_SEC_AVAILABLE)
modulelist["Security K-9"] = /obj/item/robot_module/k9
modulelist["Scrub Puppy"] = /obj/item/robot_module/scrubpup
modulelist["Borgi"] = /obj/item/robot_module/borgi
diff --git a/modular_citadel/code/modules/projectiles/projectile/energy.dm b/modular_citadel/code/modules/projectiles/projectile/energy.dm
deleted file mode 100644
index a32f23f0fc..0000000000
--- a/modular_citadel/code/modules/projectiles/projectile/energy.dm
+++ /dev/null
@@ -1,2 +0,0 @@
-/obj/item/projectile/energy/electrode
- stamina = 36
diff --git a/modular_citadel/icons/mob/taur_canine.dmi b/modular_citadel/icons/mob/taur_canine.dmi
index 0242d2e673..15d6214446 100644
Binary files a/modular_citadel/icons/mob/taur_canine.dmi and b/modular_citadel/icons/mob/taur_canine.dmi differ
diff --git a/modular_citadel/icons/mob/taur_hooved.dmi b/modular_citadel/icons/mob/taur_hooved.dmi
index e9860f2014..63e604b430 100644
Binary files a/modular_citadel/icons/mob/taur_hooved.dmi and b/modular_citadel/icons/mob/taur_hooved.dmi differ
diff --git a/modular_citadel/icons/mob/taur_naga.dmi b/modular_citadel/icons/mob/taur_naga.dmi
index 1ca4509db7..7214ec7073 100644
Binary files a/modular_citadel/icons/mob/taur_naga.dmi and b/modular_citadel/icons/mob/taur_naga.dmi differ
diff --git a/sound/weapons/gatling.ogg b/sound/weapons/gatling.ogg
deleted file mode 100644
index 0f8045560d..0000000000
Binary files a/sound/weapons/gatling.ogg and /dev/null differ
diff --git a/sound/weapons/neovgre_laser.ogg b/sound/weapons/neovgre_laser.ogg
new file mode 100644
index 0000000000..da97117ae8
Binary files /dev/null and b/sound/weapons/neovgre_laser.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index f13e7c4763..612a98974c 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -623,6 +623,7 @@
#include "code\game\machinery\syndicatebomb.dm"
#include "code\game\machinery\teleporter.dm"
#include "code\game\machinery\transformer.dm"
+#include "code\game\machinery\turnstile.dm"
#include "code\game\machinery\washing_machine.dm"
#include "code\game\machinery\wishgranter.dm"
#include "code\game\machinery\camera\camera.dm"
@@ -714,6 +715,7 @@
#include "code\game\mecha\combat\gygax.dm"
#include "code\game\mecha\combat\honker.dm"
#include "code\game\mecha\combat\marauder.dm"
+#include "code\game\mecha\combat\neovgre.dm"
#include "code\game\mecha\combat\phazon.dm"
#include "code\game\mecha\combat\reticence.dm"
#include "code\game\mecha\equipment\mecha_equipment.dm"
@@ -1038,6 +1040,7 @@
#include "code\game\objects\structures\crates_lockers\closets\bodybag.dm"
#include "code\game\objects\structures\crates_lockers\closets\cardboardbox.dm"
#include "code\game\objects\structures\crates_lockers\closets\fitness.dm"
+#include "code\game\objects\structures\crates_lockers\closets\genpop.dm"
#include "code\game\objects\structures\crates_lockers\closets\gimmick.dm"
#include "code\game\objects\structures\crates_lockers\closets\job_closets.dm"
#include "code\game\objects\structures\crates_lockers\closets\l3closet.dm"
@@ -2487,7 +2490,6 @@
#include "code\modules\projectiles\guns\energy\kinetic_accelerator.dm"
#include "code\modules\projectiles\guns\energy\laser.dm"
#include "code\modules\projectiles\guns\energy\megabuster.dm"
-#include "code\modules\projectiles\guns\energy\minigun.dm"
#include "code\modules\projectiles\guns\energy\mounted.dm"
#include "code\modules\projectiles\guns\energy\plasma_cit.dm"
#include "code\modules\projectiles\guns\energy\pulse.dm"
@@ -3116,7 +3118,6 @@
#include "modular_citadel\code\modules\projectiles\guns\ballistic\spinfusor.dm"
#include "modular_citadel\code\modules\projectiles\guns\energy\energy_gun.dm"
#include "modular_citadel\code\modules\projectiles\guns\energy\laser.dm"
-#include "modular_citadel\code\modules\projectiles\projectile\energy.dm"
#include "modular_citadel\code\modules\projectiles\projectiles\reusable.dm"
#include "modular_citadel\code\modules\reagents\chemistry\reagents\astrogen.dm"
#include "modular_citadel\code\modules\reagents\chemistry\reagents\eigentstasium.dm"