diff --git a/code/__DEFINES/_flags/obj_flags.dm b/code/__DEFINES/_flags/obj_flags.dm index 724dc24fdd..e48146a1d0 100644 --- a/code/__DEFINES/_flags/obj_flags.dm +++ b/code/__DEFINES/_flags/obj_flags.dm @@ -18,8 +18,8 @@ /// Integrity defines for clothing (not flags but close enough) #define CLOTHING_PRISTINE 0 // We have no damage on the clothing -#define CLOTHING_DAMAGED 1 // There's some damage on the clothing but it still has at least one functioning bodypart and can be equipped -#define CLOTHING_SHREDDED 2 // The clothing is useless and cannot be equipped unless repaired first +#define CLOTHING_DAMAGED 1 // There's some damage on the clothing but it still has at least one functioning bodypart +#define CLOTHING_SHREDDED 2 // The clothing is near useless and has their sensors broken // If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support diff --git a/code/__DEFINES/_flags/shields.dm b/code/__DEFINES/_flags/shields.dm index f6de4226e8..72c2f996e2 100644 --- a/code/__DEFINES/_flags/shields.dm +++ b/code/__DEFINES/_flags/shields.dm @@ -1,18 +1,35 @@ /// Transparent, let beams pass #define SHIELD_TRANSPARENT (1<<0) + +/// Flammable, takes more damage from fire +#define SHIELD_ENERGY_WEAK (1<<1) +/// Fragile, takes more damage from brute +#define SHIELD_KINETIC_WEAK (1<<2) +/// Strong against kinetic, weak against energy +#define SHIELD_KINETIC_STRONG (1<<3) +/// Strong against energy, weak against kinetic +#define SHIELD_ENERGY_STRONG (1<<4) +/// Disabler and other stamina based energy weapons boost the damage done to the sheld +#define SHIELD_DISABLER_DISRUPTED (1<<5) + +/// Doesn't block ranged attacks whatsoever +#define SHIELD_NO_RANGED (1<<6) +/// Doesn't block melee attacks whatsoever +#define SHIELD_NO_MELEE (1<<7) + /// Can shield bash -#define SHIELD_CAN_BASH (1<<1) +#define SHIELD_CAN_BASH (1<<8) /// Shield bash knockdown on wall hit -#define SHIELD_BASH_WALL_KNOCKDOWN (1<<2) +#define SHIELD_BASH_WALL_KNOCKDOWN (1<<9) /// Shield bash always knockdown -#define SHIELD_BASH_ALWAYS_KNOCKDOWN (1<<3) +#define SHIELD_BASH_ALWAYS_KNOCKDOWN (1<<10) /// Shield bash disarm on wall hit -#define SHIELD_BASH_WALL_DISARM (1<<4) +#define SHIELD_BASH_WALL_DISARM (1<<11) /// Shield bash always disarm -#define SHIELD_BASH_ALWAYS_DISARM (1<<5) +#define SHIELD_BASH_ALWAYS_DISARM (1<<12) /// You can shieldbash target someone on the ground for ground slam -#define SHIELD_BASH_GROUND_SLAM (1<<6) +#define SHIELD_BASH_GROUND_SLAM (1<<13) /// Shield bashing someone on the ground will disarm -#define SHIELD_BASH_GROUND_SLAM_DISARM (1<<7) +#define SHIELD_BASH_GROUND_SLAM_DISARM (1<<14) #define SHIELD_FLAGS_DEFAULT (SHIELD_CAN_BASH | SHIELD_BASH_WALL_KNOCKDOWN | SHIELD_BASH_WALL_DISARM | SHIELD_BASH_GROUND_SLAM) diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 9cb8b42655..7933fab83f 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -24,6 +24,10 @@ // signals from globally accessible objects /// from SSsun when the sun changes position : (primary_sun, suns) #define COMSIG_SUN_MOVED "sun_moved" + +/// from SSactivity for things that add threat but aren't "global" (e.g. phylacteries) +#define COMSIG_THREAT_CALC "threat_calculation" + ////////////////////////////////////////////////////////////////// // /datum signals diff --git a/code/__DEFINES/loadout.dm b/code/__DEFINES/loadout.dm index 973457692e..c900a33d06 100644 --- a/code/__DEFINES/loadout.dm +++ b/code/__DEFINES/loadout.dm @@ -82,3 +82,12 @@ #define LOADOUT_CAN_NAME (1<<0) //renaming items #define LOADOUT_CAN_DESCRIPTION (1<<1) //adding a custom description to items #define LOADOUT_CAN_COLOR_POLYCHROMIC (1<<2) + +//the names of the customization tabs +#define SETTINGS_TAB 0 +#define GAME_PREFERENCES_TAB 1 +#define APPEARANCE_TAB 2 +#define SPEECH_TAB 3 +#define LOADOUT_TAB 4 +#define CONTENT_PREFERENCES_TAB 5 +#define KEYBINDINGS_TAB 6 diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 51d1b618fc..e56ab8dd24 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -173,8 +173,18 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) #define BROKEN_SENSORS -1 #define NO_SENSORS 0 -#define HAS_SENSORS 1 -#define LOCKED_SENSORS 2 +#define DAMAGED_SENSORS_LIVING 1 +#define DAMAGED_SENSORS_VITALS 2 +#define HAS_SENSORS 3 + +//suit sensor flags: sensor_flag defines +#define SENSOR_RANDOM (1<<0) +#define SENSOR_LOCKED (1<<1) + +//suit sensor integrity percentage threshold defines +#define SENSOR_INTEGRITY_COORDS 0.2 +#define SENSOR_INTEGRITY_VITALS 0.6 +#define SENSOR_INTEGRITY_BINARY 1 //Wet floor type flags. Stronger ones should be higher in number. #define TURF_DRY (0) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 9c67a6b36c..deb578464f 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -152,6 +152,7 @@ // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) #define FIRE_PRIORITY_VORE 5 +#define FIRE_PRIORITY_ACTIVITY 10 #define FIRE_PRIORITY_IDLE_NPC 10 #define FIRE_PRIORITY_SERVER_MAINT 10 #define FIRE_PRIORITY_RESEARCH 10 diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index afd8a7c223..75ce77302b 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -386,12 +386,15 @@ //ignore this comment, it fixes the broken sytax parsing caused by the " above else parts += "[FOURSPACES]Nobody died this shift!" + var/avg_threat = SSactivity.get_average_threat() + var/max_threat = SSactivity.get_max_threat() + parts += "[FOURSPACES]Threat at round end: [SSactivity.current_threat]" + parts += "[FOURSPACES]Average threat: [avg_threat]" + parts += "[FOURSPACES]Max threat: [max_threat]" if(istype(SSticker.mode, /datum/game_mode/dynamic)) var/datum/game_mode/dynamic/mode = SSticker.mode mode.update_playercounts() // ? - parts += "[FOURSPACES]Threat level: [mode.threat_level]" - parts += "[FOURSPACES]Threat left: [mode.threat]" - parts += "[FOURSPACES]Average threat: [mode.threat_average]" + parts += "[FOURSPACES]Target threat: [mode.threat_level]" parts += "[FOURSPACES]Executed rules:" for(var/datum/dynamic_ruleset/rule in mode.executed_rules) parts += "[FOURSPACES][FOURSPACES][rule.ruletype] - [rule.name]: -[rule.cost + rule.scaled_times * rule.scaling_cost] threat" @@ -400,8 +403,10 @@ parts += "[FOURSPACES][FOURSPACES][str]" for(var/entry in mode.threat_tallies) parts += "[FOURSPACES][FOURSPACES][entry] added [mode.threat_tallies[entry]]" - SSblackbox.record_feedback("tally","dynamic_threat",mode.threat_level,"Final threat level") - SSblackbox.record_feedback("tally","dynamic_threat",mode.threat,"Final Threat") + SSblackbox.record_feedback("tally","threat",mode.threat_level,"Target threat") + SSblackbox.record_feedback("tally","threat",SSactivity.current_threat,"Final Threat") + SSblackbox.record_feedback("tally","threat",avg_threat,"Average Threat") + SSblackbox.record_feedback("tally","threat",max_threat,"Max Threat") return parts.Join("
") /client/proc/roundend_report_file() diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 3fc275d436..b9cbfb7e35 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -259,6 +259,13 @@ GLOBAL_LIST_INIT(bitfields, list( ), "shield_flags" = list( "SHIELD_TRANSPARENT" = SHIELD_TRANSPARENT, + "SHIELD_ENERGY_WEAK" = SHIELD_ENERGY_WEAK, + "SHIELD_KINETIC_WEAK" = SHIELD_KINETIC_WEAK, + "SHIELD_KINETIC_STRONG" = SHIELD_KINETIC_STRONG, + "SHIELD_ENERGY_STRONG" = SHIELD_ENERGY_STRONG, + "SHIELD_DISABLER_DISRUPTED" = SHIELD_DISABLER_DISRUPTED, + "SHIELD_NO_RANGED" = SHIELD_NO_RANGED, + "SHIELD_NO_MELEE" = SHIELD_NO_MELEE, "SHIELD_CAN_BASH" = SHIELD_CAN_BASH, "SHIELD_BASH_WALL_KNOCKDOWN" = SHIELD_BASH_WALL_KNOCKDOWN, "SHIELD_BASH_ALWAYS_KNOCKDOWN" = SHIELD_BASH_ALWAYS_KNOCKDOWN, diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index afc01a6ec0..cf3f45e196 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -169,5 +169,9 @@ A.attack_robot(src) /atom/proc/attack_robot(mob/user) + if((isturf(src) || istype(src, /obj/structure/table) || istype(src, /obj/machinery/conveyor)) && get_dist(user, src) <= 1) + user.Move_Pulled(src) + return + attack_ai(user) return diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 64515260ec..34fd90f4f0 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -361,7 +361,7 @@ /obj/screen/mov_intent/update_icon_state() switch(hud?.mymob?.m_intent) if(MOVE_INTENT_WALK) - icon_state = "walking" + icon_state = CONFIG_GET(flag/sprint_enabled)? "walking" : "walking_nosprint" if(MOVE_INTENT_RUN) icon_state = CONFIG_GET(flag/sprint_enabled)? "running" : "running_nosprint" diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index 5d7de05598..6a5a4c4610 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -404,9 +404,9 @@ Example config: if(!Get(/datum/config_entry/flag/no_storyteller_threat_removal)) var/min_chaos = (probabilities in storyteller_min_chaos) ? storyteller_min_chaos[config_tag] : initial(S.min_chaos) var/max_chaos = (probabilities in storyteller_max_chaos) ? storyteller_max_chaos[config_tag] : initial(S.max_chaos) - if(SSpersistence.average_dynamic_threat < min_chaos) + if(SSpersistence.average_threat + 50 < min_chaos) continue - if(SSpersistence.average_dynamic_threat > max_chaos) + if(SSpersistence.average_threat + 50 > max_chaos) continue if(SSpersistence.saved_storytellers.len == repeated_mode_adjust.len) var/name = initial(S.name) diff --git a/code/controllers/subsystem/activity.dm b/code/controllers/subsystem/activity.dm new file mode 100644 index 0000000000..9c7492f83f --- /dev/null +++ b/code/controllers/subsystem/activity.dm @@ -0,0 +1,75 @@ +SUBSYSTEM_DEF(activity) + name = "Activity tracking" + flags = SS_BACKGROUND | SS_NO_TICK_CHECK + priority = FIRE_PRIORITY_ACTIVITY + wait = 1 MINUTES + var/list/deferred_threats = list() + var/current_threat = 0 + var/list/threat_history = list() + var/list/threats = list() + +/datum/controller/subsystem/activity/Initialize(timeofday) + RegisterSignal(SSdcs,COMSIG_GLOB_EXPLOSION,.proc/on_explosion) + RegisterSignal(SSdcs,COMSIG_GLOB_MOB_DEATH,.proc/on_death) + +/datum/controller/subsystem/activity/fire(resumed = 0) + calculate_threat() + +/datum/controller/subsystem/activity/proc/calculate_threat() + threats = deferred_threats.Copy() + deferred_threats.Cut() + threats["antagonists"] = 0 + for(var/datum/antagonist/A in GLOB.antagonists) + if(A?.owner?.current && A.owner.current.stat != DEAD) + threats["antagonists"] += A.threat() + threats["events"] = 0 + for(var/r in SSevents.running) + var/datum/round_event/R = r + threats["events"] += R.threat() + threats["players"] = 0 + SEND_SIGNAL(src, COMSIG_THREAT_CALC, threats) + for(var/m in GLOB.player_list) + var/mob/M = m + if (M?.mind?.assigned_role && M.stat != DEAD) + var/datum/job/J = SSjob.GetJob(M.mind.assigned_role) + if(J) + if(length(M.mind.antag_datums)) + threats["players"] += J.GetThreat() + else + threats["players"] -= J.GetThreat() + else if(M?.stat == DEAD && !M.voluntary_ghosted) + threats["dead_players"] += 1 + current_threat = 0 + for(var/threat_type in threats) + current_threat += threats[threat_type] + threat_history += "[world.time]" + threat_history["[world.time]"] = current_threat + +/datum/controller/subsystem/activity/proc/get_average_threat() + if(!length(threat_history)) + return 0 + var/total_weight = 0 + var/total_amt = 0 + for(var/i in 1 to threat_history.len-1) + var/weight = (text2num(threat_history[i+1])-text2num(threat_history[i])) + total_weight += weight + total_amt += weight * (threat_history[threat_history[i]]) + return round(total_amt / total_weight,0.1) + +/datum/controller/subsystem/activity/proc/get_max_threat() + . = 0 + for(var/threat in threat_history) + . = max(threat_history[threat], .) + +/datum/controller/subsystem/activity/proc/on_explosion(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range) + if(!("explosions" in deferred_threats)) + deferred_threats["explosions"] = 0 + var/area/A = get_area(epicenter) + if(is_station_level(epicenter.z) && A.blob_allowed && !istype(A, /area/asteroid)) + deferred_threats["explosions"] += devastation_range**2 + heavy_impact_range**2 / 4 + light_impact_range**2 / 8 // 75 for a maxcap + +/datum/controller/subsystem/activity/proc/on_death(mob/M, gibbed) + if(!("crew_deaths" in deferred_threats)) + deferred_threats["crew_deaths"] = 0 + if(M?.mind && SSjob.GetJob(M.mind.assigned_role)) + deferred_threats["crew_deaths"] += 1 diff --git a/code/controllers/subsystem/persistence/recent_votes_etc.dm b/code/controllers/subsystem/persistence/recent_votes_etc.dm index 87f1ec0d4f..45b866b1c6 100644 --- a/code/controllers/subsystem/persistence/recent_votes_etc.dm +++ b/code/controllers/subsystem/persistence/recent_votes_etc.dm @@ -6,7 +6,7 @@ var/list/saved_chaos = list(5,5,5) var/list/saved_dynamic_rules = list(list(),list(),list()) var/list/saved_storytellers = list("foo","bar","baz") - var/list/average_dynamic_threat = 50 + var/average_threat = 50 var/list/saved_maps /datum/controller/subsystem/persistence/SaveServerPersistence() @@ -38,9 +38,10 @@ saved_chaos[3] = saved_chaos[2] saved_chaos[2] = saved_chaos[1] saved_chaos[1] = SSticker.mode.get_chaos() + average_threat = (SSactivity.get_average_threat() + average_threat) / 2 json_file = file("data/RecentChaos.json") file_data = list() - file_data["data"] = saved_chaos + file_data["data"] = saved_chaos + average_threat fdel(json_file) WRITE_FILE(json_file, json_encode(file_data)) @@ -49,10 +50,9 @@ saved_storytellers[3] = saved_storytellers[2] saved_storytellers[2] = saved_storytellers[1] saved_storytellers[1] = mode.storyteller.name - average_dynamic_threat = (mode.max_threat + average_dynamic_threat) / 2 var/json_file = file("data/RecentStorytellers.json") var/list/file_data = list() - file_data["data"] = saved_storytellers + average_dynamic_threat + file_data["data"] = saved_storytellers fdel(json_file) WRITE_FILE(json_file, json_encode(file_data)) @@ -94,6 +94,9 @@ if(!json) return saved_chaos = json["data"] + if(saved_chaos.len > 3) + average_threat = saved_chaos[4] + saved_chaos.len = 3 /datum/controller/subsystem/persistence/proc/LoadRecentRulesets() var/json_file = file("data/RecentRulesets.json") @@ -112,9 +115,6 @@ if(!json) return saved_storytellers = json["data"] - if(saved_storytellers.len > 3) - average_dynamic_threat = saved_storytellers[4] - saved_storytellers.len = 3 /datum/controller/subsystem/persistence/proc/LoadRecentMaps() var/json_file = file("data/RecentMaps.json") diff --git a/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm b/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm index 0135cab77f..95361c3da2 100644 --- a/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm +++ b/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm @@ -16,7 +16,7 @@ /datum/crafting_recipe/strobeshield name = "Strobe Shield" - result = /obj/item/assembly/flash/shield + result = /obj/item/shield/riot/flash reqs = list(/obj/item/wallframe/flasher = 1, /obj/item/assembly/flash/handheld = 1, /obj/item/shield/riot = 1) diff --git a/code/datums/explosion.dm b/code/datums/explosion.dm index 9a29158b33..8cdfaa4308 100644 --- a/code/datums/explosion.dm +++ b/code/datums/explosion.dm @@ -317,6 +317,8 @@ GLOBAL_LIST_EMPTY(explosions) var/took = (REALTIMEOFDAY - started_at) / 10 + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_EXPLOSION,epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range) + //You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare if(GLOB.Debug2) log_world("## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds.") diff --git a/code/datums/materials/basemats.dm b/code/datums/materials/basemats.dm index 76e60bc6dc..a6496622ff 100644 --- a/code/datums/materials/basemats.dm +++ b/code/datums/materials/basemats.dm @@ -52,7 +52,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "diamond" desc = "Highly pressurized carbon" color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) - strength_modifier = 1.1 + strength_modifier = 1.2 alpha = 132 categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) sheet_type = /obj/item/stack/sheet/mineral/diamond @@ -85,6 +85,7 @@ Unless you know what you're doing, only use the first three numbers. They're in name = "plasma" desc = "Isn't plasma a state of matter? Oh whatever." color = list(298/255, 46/255, 352/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) + strength_modifier = 0.7 categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE) sheet_type = /obj/item/stack/sheet/mineral/plasma value_per_unit = 0.1 diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 6a16b62643..55f91ba3d3 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -58,14 +58,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null) var/threat_level = 0 /// The current antag threat. Recalculated every time a ruletype starts or ends. var/threat = 0 - /// Threat average over the course of the round, for endgame logs. - var/threat_average = 0 - /// Number of times threat average has been calculated, for calculating above. - var/threat_average_weight = 0 - /// Last time a threat average sample was taken. Used for weighting the rolling average. - var/last_threat_sample_time = 0 - /// Maximum threat recorded so far, for cross-round chaos adjustment. - var/max_threat = 0 /// Things that cause a rolling threat adjustment to be displayed at roundend. var/list/threat_tallies = list() /// Running information about the threat. Can store text or datum entries. @@ -745,17 +737,7 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null) continue if(!M.voluntary_ghosted) current_players[CURRENT_DEAD_PLAYERS].Add(M) // Players who actually died (and admins who ghosted, would be nice to avoid counting them somehow) - threat = storyteller.calculate_threat() + added_threat - max_threat = max(max_threat,threat) - if(threat_average_weight) - var/cur_sample_weight = world.time - last_threat_sample_time - threat_average = ((threat_average * threat_average_weight) + (threat * cur_sample_weight)) / (threat_average_weight + cur_sample_weight) - threat_average_weight += cur_sample_weight - last_threat_sample_time = world.time - else - threat_average = threat - threat_average_weight++ - last_threat_sample_time = world.time + threat = (SSactivity.current_threat * 0.6 + SSactivity.get_max_threat() * 0.2 + SSactivity.get_average_threat() * 0.2) + added_threat /// Removes type from the list /datum/game_mode/dynamic/proc/remove_from_list(list/type_list, type) diff --git a/code/game/gamemodes/dynamic/dynamic_storytellers.dm b/code/game/gamemodes/dynamic/dynamic_storytellers.dm index 03aa9d174a..927ab7796b 100644 --- a/code/game/gamemodes/dynamic/dynamic_storytellers.dm +++ b/code/game/gamemodes/dynamic/dynamic_storytellers.dm @@ -45,27 +45,6 @@ Property weights are added to the config weight of the ruleset. They are: var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max) mode.midround_injection_cooldown = round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time -/datum/dynamic_storyteller/proc/calculate_threat() - var/threat = 0 - for(var/datum/antagonist/A in GLOB.antagonists) - if(A?.owner?.current && A.owner.current.stat != DEAD) - threat += A.threat() - for(var/r in SSevents.running) - var/datum/round_event/R = r - threat += R.threat() - for(var/obj/item/phylactery/P in GLOB.poi_list) - threat += 25 // can't be giving them too much of a break - for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS]) - if (M?.mind?.assigned_role && M.stat != DEAD) - var/datum/job/J = SSjob.GetJob(M.mind.assigned_role) - if(J) - if(length(M.mind.antag_datums)) - threat += J.GetThreat() - else - threat -= J.GetThreat() - threat += (mode.current_players[CURRENT_DEAD_PLAYERS].len)*dead_player_weight - return round(threat,0.1) - /datum/dynamic_storyteller/proc/do_process() return @@ -95,7 +74,7 @@ Property weights are added to the config weight of the ruleset. They are: if(voters) GLOB.dynamic_curve_centre += (mean/voters) if(flags & USE_PREV_ROUND_WEIGHTS) - GLOB.dynamic_curve_centre += (50 - SSpersistence.average_dynamic_threat) / 10 + GLOB.dynamic_curve_centre += (SSpersistence.average_threat) / 10 GLOB.dynamic_forced_threat_level = forced_threat_level /datum/dynamic_storyteller/proc/get_midround_cooldown() diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 00ba621550..47343ea58f 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -3,7 +3,7 @@ icon_state = "0" state = 0 -/obj/structure/frame/computer/attackby(obj/item/P, mob/user, params) +/obj/structure/frame/computer/attackby(obj/item/P, mob/living/user, params) add_fingerprint(user) switch(state) if(0) @@ -11,7 +11,7 @@ to_chat(user, "You start wrenching the frame into place...") if(P.use_tool(src, user, 20, volume=50)) to_chat(user, "You wrench the frame into place.") - setAnchored(TRUE) + set_anchored(TRUE) state = 1 return if(P.tool_behaviour == TOOL_WELDER) @@ -19,7 +19,7 @@ return to_chat(user, "You start deconstructing the frame...") - if(P.use_tool(src, user, 20, volume=50) && state == 0) + if(P.use_tool(src, user, 20, volume=50)) to_chat(user, "You deconstruct the frame.") var/obj/item/stack/sheet/metal/M = new (drop_location(), 5) M.add_fingerprint(user) @@ -28,15 +28,15 @@ if(1) if(P.tool_behaviour == TOOL_WRENCH) to_chat(user, "You start to unfasten the frame...") - if(P.use_tool(src, user, 20, volume=50) && state == 1) + if(P.use_tool(src, user, 20, volume=50)) to_chat(user, "You unfasten the frame.") - setAnchored(FALSE) + set_anchored(FALSE) state = 0 return if(istype(P, /obj/item/circuitboard/computer) && !circuit) if(!user.transferItemToLoc(P, src)) return - playsound(src, 'sound/items/deconstruct.ogg', 50, 1) + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) to_chat(user, "You place [P] inside the frame.") icon_state = "1" circuit = P @@ -71,8 +71,10 @@ if(istype(P, /obj/item/stack/cable_coil)) if(!P.tool_start_check(user, amount=5)) return + if(state != 2) + return to_chat(user, "You start adding cables to the frame...") - if(P.use_tool(src, user, 20, 5, 50, CALLBACK(src, .proc/check_state, 2))) + if(P.use_tool(src, user, 20, volume=50, amount=5)) to_chat(user, "You add cables to the frame.") state = 3 icon_state = "3" @@ -90,9 +92,11 @@ if(istype(P, /obj/item/stack/sheet/glass)) if(!P.tool_start_check(user, amount=2)) return - playsound(src, 'sound/items/deconstruct.ogg', 50, 1) + if(state != 3) + return + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) to_chat(user, "You start to put in the glass panel...") - if(P.use_tool(src, user, 20, 2, 0, CALLBACK(src, .proc/check_state, 3))) + if(P.use_tool(src, user, 20, amount=2)) to_chat(user, "You put in the glass panel.") state = 4 src.icon_state = "4" @@ -109,14 +113,51 @@ if(P.tool_behaviour == TOOL_SCREWDRIVER) P.play_tool_sound(src) to_chat(user, "You connect the monitor.") - var/obj/B = new circuit.build_path (loc, circuit) - B.setDir(dir) - transfer_fingerprints_to(B) + + var/obj/machinery/new_machine = new circuit.build_path(loc) + new_machine.setDir(dir) + transfer_fingerprints_to(new_machine) + + if(istype(new_machine, /obj/machinery/computer)) + var/obj/machinery/computer/new_computer = new_machine + + // Machines will init with a set of default components. + // Triggering handle_atom_del will make the machine realise it has lost a component_parts and then deconstruct. + // Move to nullspace so we don't trigger handle_atom_del, then qdel. + // Finally, replace new machine's parts with this frame's parts. + if(new_computer.circuit) + // Move to nullspace and delete. + new_computer.circuit.moveToNullspace() + QDEL_NULL(new_computer.circuit) + for(var/old_part in new_computer.component_parts) + var/atom/movable/movable_part = old_part + // Move to nullspace and delete. + movable_part.moveToNullspace() + qdel(movable_part) + + // Set anchor state and move the frame's parts over to the new machine. + // Then refresh parts and call on_construction(). + new_computer.set_anchored(anchored) + new_computer.component_parts = list() + + circuit.forceMove(new_computer) + new_computer.component_parts += circuit + new_computer.circuit = circuit + + for(var/new_part in src) + var/atom/movable/movable_part = new_part + movable_part.forceMove(new_computer) + new_computer.component_parts += movable_part + + new_computer.RefreshParts() + new_computer.on_construction() + qdel(src) return if(user.a_intent == INTENT_HARM) return ..() + /obj/structure/frame/computer/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) if(state == 4) @@ -127,13 +168,12 @@ ..() /obj/structure/frame/computer/AltClick(mob/user) - . = ..() - if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) + ..() + if(!user.canUseTopic(src, BE_CLOSE, TRUE, FALSE)) return if(anchored) to_chat(usr, "You must unwrench [src] before rotating it!") - return TRUE + return setDir(turn(dir, -90)) - return TRUE diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index ff65a6e159..34528960b8 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -51,6 +51,11 @@ return FALSE return ACCESS_CAPTAIN in authorize_access +/obj/machinery/computer/communications/proc/authenticated_as_non_silicon_command(mob/user) + if (issilicon(user)) + return FALSE + return ACCESS_HEADS in authorize_access //Should always be the case if authorized as it usually needs head access to log in, buut lets be sure. + /// Are we a silicon, OR we're logged in as the captain? /obj/machinery/computer/communications/proc/authenticated_as_silicon_or_captain(mob/user) if (issilicon(user)) @@ -160,7 +165,7 @@ return make_announcement(usr) if ("messageAssociates") - if (!authenticated_as_non_silicon_captain(usr)) + if (!authenticated_as_non_silicon_command(usr)) return if (!COOLDOWN_FINISHED(src, important_action_cooldown)) return @@ -361,9 +366,9 @@ data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac(user, TRUE) if (authenticated_as_non_silicon_captain(user)) - data["canMessageAssociates"] = TRUE data["canRequestNuke"] = TRUE - + if (authenticated_as_non_silicon_command(user)) + data["canMessageAssociates"] = TRUE if (can_send_messages_to_other_sectors(user)) data["canSendToSectors"] = TRUE diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index bdf7a80c96..8cdec2f324 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -217,6 +217,8 @@ new_machine.RefreshParts() new_machine.on_construction() + // TODO: make sleepers not shit out parts PROPERLY THIS TIME. + new_machine.circuit.moveToNullspace() qdel(src) return diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 5be3e2a3a5..f2f8c20776 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -409,7 +409,10 @@ visible_message("\The [src] hums and hisses as it moves [mob_occupant.real_name] into storage.") // Ghost and delete the mob. - if(!mob_occupant.get_ghost(1)) + var/mob/dead/observer/G = mob_occupant.get_ghost(TRUE) + if(G) + G.voluntary_ghosted = TRUE + else mob_occupant.ghostize(FALSE, penalize = TRUE, voluntary = TRUE, cryo = TRUE) QDEL_NULL(occupant) diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm index 33f949aba4..aa1d05884e 100644 --- a/code/game/machinery/limbgrower.dm +++ b/code/game/machinery/limbgrower.dm @@ -178,6 +178,7 @@ limb.update_icon_dropped() limb.name = "\improper synthetic [lowertext(selected.name)] [limb.name]" limb.desc = "A synthetic [selected_category] limb that will morph on its first use in surgery. This one is for the [parse_zone(limb.body_zone)]." + limb.forcereplace = TRUE for(var/obj/item/bodypart/BP in limb) BP.base_bp_icon = selected.icon_limbs || DEFAULT_BODYPART_ICON_ORGANIC BP.species_id = selected.limbs_id diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 70edd3f43d..8c36703855 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -69,8 +69,7 @@ effective or pretty fucking useless. */ /obj/item/healthanalyzer/rad_laser - custom_materials = list(/datum/material/iron=400) - var/irradiate = 1 + var/irradiate = TRUE var/intensity = 10 // how much damage the radiation does var/wavelength = 10 // time it takes for the radiation to kick in, in seconds var/used = 0 // is it cooling down? @@ -92,16 +91,16 @@ effective or pretty fucking useless. addtimer(VARSET_CALLBACK(src, used, FALSE), cooldown) addtimer(VARSET_CALLBACK(src, icon_state, "health"), cooldown) to_chat(user, "Successfully irradiated [M].") - addtimer(CALLBACK(src, .proc/radiation_aftereffect, M), (wavelength+(intensity*4))*5) + addtimer(CALLBACK(src, .proc/radiation_aftereffect, M, intensity), (wavelength+(intensity*4))*5) else to_chat(user, "The radioactive microlaser is still recharging.") -/obj/item/healthanalyzer/rad_laser/proc/radiation_aftereffect(mob/living/M) - if(QDELETED(M)) +/obj/item/healthanalyzer/rad_laser/proc/radiation_aftereffect(mob/living/M, passed_intensity) + if(QDELETED(M) || !ishuman(M) || HAS_TRAIT(M, TRAIT_RADIMMUNE)) return - if(intensity >= 5) - M.apply_effect(round(intensity/0.075), EFFECT_UNCONSCIOUS) - M.rad_act(intensity*10) + if(passed_intensity >= 5) + M.apply_effect(round(passed_intensity/0.075), EFFECT_UNCONSCIOUS) //to save you some math, this is a round(intensity * (4/3)) second long knockout + M.rad_act(passed_intensity*10) /obj/item/healthanalyzer/rad_laser/proc/get_cooldown() return round(max(10, (stealth*30 + intensity*5 - wavelength/4))) diff --git a/code/game/objects/items/shields.dm b/code/game/objects/items/shields.dm index 5c3e4fd612..84faf27242 100644 --- a/code/game/objects/items/shields.dm +++ b/code/game/objects/items/shields.dm @@ -174,6 +174,10 @@ var/atom/movable/AM = object if(CHECK_BITFIELD(shield_flags, SHIELD_TRANSPARENT) && (AM.pass_flags & PASSGLASS)) return BLOCK_NONE + if(CHECK_BITFIELD(shield_flags, SHIELD_NO_RANGED) && (attack_type & ATTACK_TYPE_PROJECTILE)) + return BLOCK_NONE + if(CHECK_BITFIELD(shield_flags, SHIELD_NO_MELEE) && (attack_type & ATTACK_TYPE_MELEE)) + return BLOCK_NONE if(attack_type & ATTACK_TYPE_THROWN) final_block_chance += 30 if(attack_type & ATTACK_TYPE_TACKLE) @@ -238,30 +242,75 @@ new /obj/item/shard((get_turf(src))) /obj/item/shield/riot/on_shield_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) + var/final_damage = damage + + if(attack_type & ATTACK_TYPE_MELEE) + var/obj/hittingthing = object + if(hittingthing.damtype == BURN) + if(CHECK_BITFIELD(shield_flags, SHIELD_ENERGY_WEAK)) + final_damage *= 2 + else if(CHECK_BITFIELD(shield_flags, SHIELD_ENERGY_STRONG)) + final_damage *= 0.5 + + if(hittingthing.damtype == BRUTE) + if(CHECK_BITFIELD(shield_flags, SHIELD_KINETIC_WEAK)) + final_damage *= 2 + else if(CHECK_BITFIELD(shield_flags, SHIELD_KINETIC_STRONG)) + final_damage *= 0.5 + + if(hittingthing.damtype == STAMINA || hittingthing.damtype == TOX || hittingthing.damtype == CLONE || hittingthing.damtype == BRAIN || hittingthing.damtype == OXY) + final_damage = 0 + + if(attack_type & ATTACK_TYPE_PROJECTILE) + var/obj/item/projectile/shootingthing = object + if(is_energy_reflectable_projectile(shootingthing)) + if(CHECK_BITFIELD(shield_flags, SHIELD_ENERGY_WEAK)) + final_damage *= 2 + else if(CHECK_BITFIELD(shield_flags, SHIELD_ENERGY_STRONG)) + final_damage *= 0.5 + + if(!is_energy_reflectable_projectile(object)) + if(CHECK_BITFIELD(shield_flags, SHIELD_KINETIC_WEAK)) + final_damage *= 2 + else if(CHECK_BITFIELD(shield_flags, SHIELD_KINETIC_STRONG)) + final_damage *= 0.5 + + if(shootingthing.damage_type == STAMINA) + if(CHECK_BITFIELD(shield_flags, SHIELD_DISABLER_DISRUPTED)) + final_damage *= 3 //disablers melt these kinds of shields. Really meant more for holoshields. + else + final_damage = 0 + + if(shootingthing.damage_type == TOX || shootingthing.damage_type == CLONE || shootingthing.damage_type == BRAIN || shootingthing.damage_type == OXY) + final_damage = 0 + if(can_shatter && (obj_integrity <= damage)) var/turf/T = get_turf(owner) T.visible_message("[attack_text] destroys [src]!") shatter(owner) qdel(src) return FALSE - take_damage(damage) + take_damage(final_damage) return ..() -/obj/item/shield/riot/laser_proof - name = "laser resistant shield" - desc = "A far more frail shield made of dark glass meant to block lasers but suffers from being being weak to ballistic projectiles." +/obj/item/shield/riot/energy_proof + name = "energy resistant shield" + desc = "An ablative shield designed to absorb and disperse energy attacks. This comes at significant cost to its ability to withstand ballistics and kinetics, breaking apart easily." armor = list("melee" = 30, "bullet" = -10, "laser" = 80, "energy" = 80, "bomb" = -40, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 50) icon_state = "riot_laser" item_state = "riot_laser" lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' - shield_flags = SHIELD_FLAGS_DEFAULT + shield_flags = SHIELD_FLAGS_DEFAULT | SHIELD_ENERGY_STRONG | SHIELD_KINETIC_WEAK max_integrity = 300 -/obj/item/shield/riot/bullet_proof - name = "bullet resistant shield" - desc = "A far more frail shield made of resistant plastics and kevlar meant to block ballistics." +/obj/item/shield/riot/kinetic_proof + name = "kinetic resistant shield" + desc = "A polymer and ceramic shield designed to absorb ballistic projectiles and kinetic force. It doesn't do very well into energy attacks, especially from weapons that inflict burns." armor = list("melee" = 30, "bullet" = 80, "laser" = 0, "energy" = 0, "bomb" = -40, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 50) + icon_state = "riot_bullet" + item_state = "riot_bullet" + shield_flags = SHIELD_FLAGS_DEFAULT | SHIELD_KINETIC_STRONG | SHIELD_ENERGY_WEAK max_integrity = 300 /obj/item/shield/riot/roman @@ -277,8 +326,8 @@ /obj/item/shield/riot/roman/fake desc = "Bears an inscription on the inside: \"Romanes venio domus\". It appears to be a bit flimsy." - block_chance = 0 armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0) + shield_flags = SHIELD_ENERGY_WEAK | SHIELD_KINETIC_WEAK | SHIELD_NO_RANGED max_integrity = 40 /obj/item/shield/riot/roman/shatter(mob/living/carbon/human/owner) @@ -295,14 +344,80 @@ custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT * 10) resistance_flags = FLAMMABLE repair_material = /obj/item/stack/sheet/mineral/wood - block_chance = 30 - shield_flags = SHIELD_FLAGS_DEFAULT + shield_flags = SHIELD_FLAGS_DEFAULT | SHIELD_ENERGY_WEAK max_integrity = 150 /obj/item/shield/riot/buckler/shatter(mob/living/carbon/human/owner) playsound(owner, 'sound/effects/bang.ogg', 50) new /obj/item/stack/sheet/mineral/wood(get_turf(src)) +/obj/item/shield/riot/flash + name = "strobe shield" + desc = "A shield with a built in, high intensity light capable of blinding and disorienting suspects. Takes regular handheld flashes as bulbs." + icon_state = "flashshield" + item_state = "flashshield" + var/obj/item/assembly/flash/handheld/embedded_flash + +/obj/item/shield/riot/flash/Initialize() + . = ..() + embedded_flash = new(src) + +/obj/item/shield/riot/flash/ComponentInitialize() + . = .. () + AddElement(/datum/element/update_icon_updates_onmob) + +/obj/item/shield/riot/flash/attack(mob/living/M, mob/user) + . = embedded_flash.attack(M, user) + update_icon() + +/obj/item/shield/riot/flash/attack_self(mob/living/carbon/user) + . = embedded_flash.attack_self(user) + update_icon() + +/obj/item/shield/riot/flash/on_shield_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) + . = ..() + if (. && !embedded_flash.crit_fail) + embedded_flash.activate() + update_icon() + + +/obj/item/shield/riot/flash/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/assembly/flash/handheld)) + var/obj/item/assembly/flash/handheld/flash = W + if(flash.crit_fail) + to_chat(user, "No sense replacing it with a broken bulb!") + return + else + to_chat(user, "You begin to replace the bulb...") + if(do_after(user, 20, target = user)) + if(flash.crit_fail || !flash || QDELETED(flash)) + return + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) + qdel(embedded_flash) + embedded_flash = flash + flash.forceMove(src) + update_icon() + return + ..() + +/obj/item/shield/riot/flash/emp_act(severity) + . = ..() + embedded_flash.emp_act(severity) + update_icon() + +/obj/item/shield/riot/flash/update_icon_state() + if(!embedded_flash || embedded_flash.crit_fail) + icon_state = "riot" + item_state = "riot" + else + icon_state = "flashshield" + item_state = "flashshield" + +/obj/item/shield/riot/flash/examine(mob/user) + . = ..() + if (embedded_flash?.crit_fail) + . += "The mounted bulb has burnt out. You can try replacing it with a new one." + /obj/item/shield/riot/tele name = "telescopic shield" desc = "An advanced riot shield made of lightweight materials that collapses for easy storage." @@ -348,7 +463,7 @@ /obj/item/shield/makeshift name = "metal shield" - desc = "A large shield made of wired and welded sheets of metal. The handle is made of cloth and leather making it unwieldy." + desc = "A large shield made of wired and welded sheets of metal. The handle is made of cloth and leather, making it unwieldy." armor = list("melee" = 25, "bullet" = 25, "laser" = 5, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 80) lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' @@ -362,33 +477,34 @@ /obj/item/shield/riot/tower name = "tower shield" - desc = "A massive shield that can block a lot of attacks, can take a lot of abuse before braking." + desc = "An immense tower shield. Designed to ensure maximum protection to the user, at the expense of mobility." armor = list("melee" = 95, "bullet" = 95, "laser" = 75, "energy" = 60, "bomb" = 90, "bio" = 90, "rad" = 0, "fire" = 90, "acid" = 10) //Armor for the item, dosnt transfer to user item_state = "metal" icon_state = "metal" force = 16 slowdown = 2 - throwforce = 15 //Massive pice of metal + throwforce = 15 //Massive piece of metal + max_integrity = 600 w_class = WEIGHT_CLASS_HUGE - item_flags = SLOWS_WHILE_IN_HAND + item_flags = SLOWS_WHILE_IN_HAND | ITEM_CAN_BLOCK shield_flags = SHIELD_FLAGS_DEFAULT /obj/item/shield/riot/tower/swat name = "swat shield" - desc = "A massive, heavy shield that can block a lot of attacks, can take a lot of abuse before breaking." max_integrity = 250 /obj/item/shield/riot/implant - name = "telescoping shield implant" - desc = "A compact, arm-mounted telescopic shield. While nigh-indestructible when powered by a host user, it will eventually overload from damage. Recharges while inside its implant." - item_state = "metal" - icon_state = "metal" + name = "hardlight shield implant" + desc = "A hardlight plane of force projected from the implant. While it is capable of withstanding immense amounts of abuse, it will eventually overload from sustained impacts, especially against energy attacks. Recharges while retracted." + item_state = "holoshield" + icon_state = "holoshield" slowdown = 1 shield_flags = SHIELD_FLAGS_DEFAULT max_integrity = 100 obj_integrity = 100 can_shatter = FALSE - item_flags = SLOWS_WHILE_IN_HAND | ITEM_CAN_BLOCK + item_flags = ITEM_CAN_BLOCK + shield_flags = SHIELD_FLAGS_DEFAULT | SHIELD_KINETIC_STRONG | SHIELD_DISABLER_DISRUPTED var/recharge_timerid var/recharge_delay = 15 SECONDS @@ -400,7 +516,7 @@ if(obj_integrity == 0) if(ismob(loc)) var/mob/living/L = loc - playsound(src, 'sound/effects/glassbr3.ogg', 100) + playsound(src, "sparks", 100, TRUE) L.visible_message("[src] overloads from the damage sustained!") L.dropItemToGround(src) //implant component catch hook will grab it. diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index 426958b99a..b2bd394a53 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -117,8 +117,8 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \ new/datum/stack_recipe("Captain Statue", /obj/structure/statue/diamond/captain, 5, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("AI Hologram Statue", /obj/structure/statue/diamond/ai1, 5, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("AI Core Statue", /obj/structure/statue/diamond/ai2, 5, one_per_turf = 1, on_floor = 1), \ -// new/datum/stack_recipe("diamond brick", /obj/item/ingot/diamond, 6, time = 100), \ not yet - )) + new/datum/stack_recipe("diamond ingot", /obj/item/ingot/diamond, 6, time = 100), \ + )) /obj/item/stack/sheet/mineral/diamond/get_main_recipes() . = ..() diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index ae2f432d2e..2d8f680c12 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -1,7 +1,7 @@ /obj/item/storage/box/syndicate /obj/item/storage/box/syndicate/PopulateContents() - switch (pickweight(list("bloodyspai" = 3, "stealth" = 2, "bond" = 2, "screwed" = 2, "sabotage" = 3, "guns" = 2, "murder" = 2, "baseball" = 1, "implant" = 1, "hacker" = 3, "darklord" = 1, "sniper" = 1, "metaops" = 1, "ninja" = 1))) + switch (pickweight(list("bloodyspai" = 3, "stealth" = 2, "bond" = 2, "screwed" = 2, "sabotage" = 3, "guns" = 2, "murder" = 2, "baseball" = 1, "implant" = 1, "hacker" = 3, "darklord" = 1, "sniper" = 1, "metaops" = 1, "ninja" = 1, "ancient" = 1))) if("bloodyspai") // 30 tc now this is more right new /obj/item/clothing/under/chameleon(src) // 2 tc since it's not the full set new /obj/item/clothing/mask/chameleon(src) // Goes with above @@ -154,6 +154,20 @@ new /obj/item/storage/belt/chameleon(src) // Unique but worth at least 2 tc new /obj/item/card/id/syndicate(src) // 2 tc new /obj/item/chameleon(src) // 7 tc + + if("ancient") //A kit so old, it's probably older than you. //This bundle is filled with the entire unlink contents traitors had access to in 2006, from OpenSS13. Notably the esword was not a choice but existed in code. + new /obj/item/storage/toolbox/emergency/old/ancientbundle(src) //Items fit neatly into a classic toolbox just to remind you what the theme is. + +/obj/item/storage/toolbox/emergency/old/ancientbundle //So the subtype works + +/obj/item/storage/toolbox/emergency/old/ancientbundle/PopulateContents() + new /obj/item/card/emag(src) + new /obj/item/pen/sleepy(src) + new /obj/item/reagent_containers/pill/cyanide(src) + new /obj/item/chameleon(src) //its not the original cloaking device, but it will do. + new /obj/item/gun/ballistic/revolver(src) + new /obj/item/implanter/freedom(src) + new /obj/item/stack/telecrystal(src) //The failsafe/self destruct isn't an item we can physically include in the kit, but 1 TC is technically enough to buy the equivalent. /obj/item/storage/box/syndie_kit name = "box" diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index b8d14a6555..306868daba 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -662,6 +662,72 @@ to_chat(M,"You're once again longer hearing deadchat.") +/datum/action/disguise + name = "Disguise" + button_icon_state = "ling_transform" + icon_icon = 'icons/mob/actions/actions_changeling.dmi' + background_icon_state = "bg_mime" + var/currently_disguised = FALSE + var/static/list/mob_blacklist = typecacheof(list( + /mob/living/simple_animal/pet, + /mob/living/simple_animal/hostile/retaliate/goose, + /mob/living/simple_animal/hostile/poison, + /mob/living/simple_animal/hostile/retaliate/goat, + /mob/living/simple_animal/cow, + /mob/living/simple_animal/chick, + /mob/living/simple_animal/chicken, + /mob/living/simple_animal/kiwi, + /mob/living/simple_animal/babyKiwi, + /mob/living/simple_animal/deer, + /mob/living/simple_animal/parrot, + /mob/living/simple_animal/hostile/lizard, + /mob/living/simple_animal/crab, + /mob/living/simple_animal/cockroach, + /mob/living/simple_animal/butterfly, + /mob/living/simple_animal/mouse, + /mob/living/simple_animal/sloth, + /mob/living/simple_animal/opossum, + /mob/living/simple_animal/hostile/bear, + /mob/living/simple_animal/hostile/asteroid/polarbear, + /mob/living/simple_animal/hostile/asteroid/wolf, + /mob/living/carbon/monkey, + /mob/living/simple_animal/hostile/gorilla, + /mob/living/carbon/alien/larva, + /mob/living/simple_animal/hostile/retaliate/frog + )) + + +/datum/action/disguise/Trigger() + var/mob/living/carbon/human/H = owner + if(!currently_disguised) + var/user_object_type = input(H, "Disguising as OBJECT or MOB?") as null|anything in list("OBJECT", "MOB") + if(user_object_type) + var/search_term = stripped_input(H, "Enter the search term") + if(search_term) + var/list_to_search + if(user_object_type == "MOB") + list_to_search = subtypesof(/mob) - mob_blacklist + else + list_to_search = subtypesof(/obj) + var/list/filtered_results = list() + for(var/some_search_item in list_to_search) + if(findtext("[some_search_item]", search_term)) + filtered_results += some_search_item + if(!length(filtered_results)) + to_chat(H, "Nothing matched your search query!") + else + var/disguise_selection = input("Select item to disguise as") as null|anything in filtered_results + if(disguise_selection) + var/atom/disguise_item = disguise_selection + var/image/I = image(icon = initial(disguise_item.icon), icon_state = initial(disguise_item.icon_state), loc = H) + I.override = TRUE + I.layer = ABOVE_MOB_LAYER + H.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "ghost_cafe_disguise", I) + currently_disguised = TRUE + else + H.remove_alt_appearance("ghost_cafe_disguise") + currently_disguised = FALSE + /obj/effect/mob_spawn/human/ghostcafe/special(mob/living/carbon/human/new_spawn) if(new_spawn.client) new_spawn.client.prefs.copy_to(new_spawn) @@ -679,6 +745,8 @@ to_chat(new_spawn,"Ghosting is free!") var/datum/action/toggle_dead_chat_mob/D = new(new_spawn) D.Grant(new_spawn) + var/datum/action/disguise/disguise_action = new(new_spawn) + disguise_action.Grant(new_spawn) /datum/outfit/ghostcafe name = "ID, jumpsuit and shoes" diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index edb69236c6..fba79ac2b0 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -93,6 +93,9 @@ user.stop_pulling() return ..() +/obj/structure/table/attack_robot(mob/user) + on_attack_hand(user) + /obj/structure/table/attack_tk() return FALSE diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm index fb7b4f8a94..1b6979300f 100644 --- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm +++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/ratvarian_shield.dm @@ -8,7 +8,7 @@ desc = "A resilient shield made out of brass.. It feels warm to the touch." var/clockwork_desc = "A powerful shield of ratvarian making. It absorbs blocked attacks to charge devastating bashes." armor = list("melee" = 80, "bullet" = 70, "laser" = -10, "energy" = -20, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100) - shield_flags = SHIELD_FLAGS_DEFAULT + shield_flags = SHIELD_FLAGS_DEFAULT | SHIELD_KINETIC_STRONG | SHIELD_ENERGY_WEAK max_integrity = 300 //High integrity, extremely strong against melee / bullets, but still quite easy to destroy with lasers and energy repair_material = /obj/item/stack/tile/brass var/dam_absorbed = 0 diff --git a/code/modules/antagonists/eldritch_cult/eldritch_items.dm b/code/modules/antagonists/eldritch_cult/eldritch_items.dm index 1aa97f1321..0dd9cf6bea 100644 --- a/code/modules/antagonists/eldritch_cult/eldritch_items.dm +++ b/code/modules/antagonists/eldritch_cult/eldritch_items.dm @@ -69,7 +69,7 @@ /datum/action/innate/heretic_shatter/Activate() if(do_after(holder,10, target = holder)) var/turf/safe_turf = find_safe_turf(zlevels = sword.z, extended_safety_checks = TRUE) - do_teleport(holder,safe_turf,forceMove = TRUE) + do_teleport(holder,safe_turf,forceMove = TRUE,channel=TELEPORT_CHANNEL_MAGIC) to_chat(holder,"You feel a gust of energy flow through your body... the Rusted Hills heard your call...") qdel(sword) diff --git a/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm b/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm index 7b737f582d..9e71f34735 100644 --- a/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm +++ b/code/modules/antagonists/eldritch_cult/knowledge/flesh_lore.dm @@ -178,7 +178,7 @@ /datum/eldritch_knowledge/summon/stalker name = "Lonely Ritual" gain_text = "I was able to combine my greed and desires to summon an eldritch beast I had never seen before. An ever shapeshifting mass of flesh, it knew well my goals." - desc = "You can now summon a Stalker by transmutating a pair of eyes, a candle, a pen and a piece of paper. Stalkers can shapeshift into harmless animals to get close to the victim." + desc = "You can now summon a Stalker by transmutating a kitchen knife, a candle, a pen and a piece of paper. Stalkers can shapeshift into harmless animals to get close to the victim." cost = 1 required_atoms = list(/obj/item/kitchen/knife,/obj/item/candle,/obj/item/pen,/obj/item/paper) mob_to_summon = /mob/living/simple_animal/hostile/eldritch/stalker diff --git a/code/modules/antagonists/slaughter/slaughterevent.dm b/code/modules/antagonists/slaughter/slaughterevent.dm index 1c6412dcad..c8549d859c 100644 --- a/code/modules/antagonists/slaughter/slaughterevent.dm +++ b/code/modules/antagonists/slaughter/slaughterevent.dm @@ -7,7 +7,21 @@ earliest_start = 1 HOURS min_players = 20 - +/datum/round_event_control/slaughter/canSpawnEvent() + weight = initial(src.weight) + var/list/allowed_turf_typecache = typecacheof(/turf/open) - typecacheof(/turf/open/space) + var/list/allowed_z_cache = list() + for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) + allowed_z_cache[num2text(z)] = TRUE + for(var/obj/effect/decal/cleanable/C in world) + if(!C.loc || QDELETED(C)) + continue + if(!C.can_bloodcrawl_in()) + continue + if(!SSpersistence.IsValidDebrisLocation(C.loc, allowed_turf_typecache, allowed_z_cache, C.type, FALSE)) + continue + weight += 0.05 + return ..() /datum/round_event/ghost_role/slaughter minimum_required = 1 diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index 07a9f499f8..5eb1f77fd7 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -262,70 +262,6 @@ /obj/item/assembly/flash/armimplant/proc/cooldown() overheat = FALSE -/obj/item/assembly/flash/shield - name = "strobe shield" - desc = "A shield with a built in, high intensity light capable of blinding and disorienting suspects. Takes regular handheld flashes as bulbs." - icon = 'icons/obj/items_and_weapons.dmi' - icon_state = "flashshield" - item_state = "flashshield" - lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi' - slot_flags = ITEM_SLOT_BACK - force = 10 - throwforce = 5 - throw_speed = 2 - throw_range = 3 - w_class = WEIGHT_CLASS_BULKY - custom_materials = list(/datum/material/glass=7500, /datum/material/iron=1000) - attack_verb = list("shoved", "bashed") - block_chance = 50 - armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 70) - -/obj/item/assembly/flash/shield/flash_recharge(interval=10) - if(times_used >= 4) - burn_out() - return FALSE - return TRUE - -/obj/item/assembly/flash/shield/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/assembly/flash/handheld)) - var/obj/item/assembly/flash/handheld/flash = W - if(flash.crit_fail) - to_chat(user, "No sense replacing it with a broken bulb.") - return - else - to_chat(user, "You begin to replace the bulb.") - if(do_after(user, 20, target = src)) - if(flash.crit_fail || !flash || QDELETED(flash)) - return - crit_fail = FALSE - times_used = 0 - playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) - update_icon() - flash.crit_fail = TRUE - flash.update_icon() - return - ..() - -/obj/item/assembly/flash/shield/update_icon(flash = FALSE) - icon_state = "flashshield" - item_state = "flashshield" - - if(crit_fail) - icon_state = "riot" - item_state = "riot" - else if(flash) - icon_state = "flashshield_flash" - item_state = "flashshield_flash" - addtimer(CALLBACK(src, /atom/.proc/update_icon), 5) - - if(holder) - holder.update_icon() - -/obj/item/assembly/flash/shield/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return) - activate() - return ..() - //ported from tg - check to make sure it can't appear where it's not supposed to. /obj/item/assembly/flash/hypnotic desc = "A modified flash device, programmed to emit a sequence of subliminal flashes that can send a vulnerable target into a hypnotic trance." diff --git a/code/modules/cargo/blackmarket/blackmarket_item.dm b/code/modules/cargo/blackmarket/blackmarket_item.dm index 53c0004a7f..de5d7c2913 100644 --- a/code/modules/cargo/blackmarket/blackmarket_item.dm +++ b/code/modules/cargo/blackmarket/blackmarket_item.dm @@ -17,7 +17,7 @@ /datum/blackmarket_item/New() if(isnull(price)) - price = rand(price_min, price_max) + price = round(rand(price_min, price_max), 5) if(isnull(stock)) stock = rand(stock_min, stock_max) diff --git a/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm b/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm index a6ee19e38d..8890ed19fc 100644 --- a/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm +++ b/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm @@ -51,5 +51,30 @@ item = /obj/item/clothing/head/chameleon/broken price_min = 100 price_max = 200 - stock_max = 2 - availability_prob = 70 + stock_min = 3 + stock_max = 7 + availability_prob = 100 + +/datum/blackmarket_item/clothing/earmuffs + name = "Earmuffs" + desc = "Protect your precious ears from security's flashbangs with this handy device." + item = /obj/item/clothing/ears/earmuffs + price_min = 100 + price_max = 200 + stock_min = 3 + stock_max = 7 + availability_prob = 100 + +/* commented out until someone wants to port the actual boots + * i am unsure they are in accordance with server design ideals + +/datum/blackmarket_item/clothing/rocket_boots + name = "Rocket Boots" + desc = "We found a pair of jump boots and overclocked the hell out of them. No liability for grevious harm to or with a body." + item = /obj/item/clothing/shoes/bhop/rocket + price_min = 1500 + price_max = 3000 + stock_max = 1 + availability_prob = 30 + +*/ diff --git a/code/modules/cargo/blackmarket/blackmarket_items/consumables.dm b/code/modules/cargo/blackmarket/blackmarket_items/consumables.dm index 469c467c2f..76e5452062 100644 --- a/code/modules/cargo/blackmarket/blackmarket_items/consumables.dm +++ b/code/modules/cargo/blackmarket/blackmarket_items/consumables.dm @@ -14,11 +14,11 @@ name = "Box of Donk Pockets" desc = "A well packaged box containing the favourite snack of every spacefarer." item = /obj/item/storage/box/donkpockets - stock_min = 2 - stock_max = 5 - price_min = 325 - price_max = 400 - availability_prob = 80 + stock_min = 5 + stock_max = 10 + price_min = 250 + price_max = 350 + availability_prob = 100 /datum/blackmarket_item/consumable/suspicious_pills name = "Bottle of Suspicious Pills" @@ -46,13 +46,43 @@ stock_max = 35 price_min = 10 price_max = 60 - availability_prob = 50 + availability_prob = 70 /datum/blackmarket_item/consumable/pumpup name = "Shoddy Stimulants" desc = "Feel the energy inside each needle!" item = /obj/item/reagent_containers/hypospray/medipen/stimpack stock_max = 5 - price_min = 50 - price_max = 150 - availability_prob = 90 + price_min = 80 + price_max = 170 + availability_prob = 70 + +/datum/blackmarket_item/consumable/stray_drink + name = "A random drink" + desc = "A surprise drink direcly from the counter. No refunds if the glass breaks." // it will always break if it's launched at the station + item = /obj/item/reagent_containers/food/drinks/drinkingglass + stock_min = 10 + stock_max = 15 + price_min = 100 + price_max = 200 + availability_prob = 100 + // add new drinks here + var/list/counter = list( + /datum/reagent/consumable/ethanol/gintonic, + /datum/reagent/consumable/ethanol/cuba_libre, + /datum/reagent/consumable/ethanol/martini, + /datum/reagent/consumable/ethanol/b52, + /datum/reagent/consumable/ethanol/manhattan, + /datum/reagent/consumable/ethanol/bahama_mama, + /datum/reagent/consumable/ethanol/syndicatebomb, + /datum/reagent/consumable/ethanol/quadruple_sec + ) + +// i found no other way to fill a glass with a random reagent at runtime. and i definitely was not going to do the same done in bottle.dm +/datum/blackmarket_item/consumable/stray_drink/spawn_item(loc) + var/obj/item/reagent_containers/food/drinks/drinkingglass/drink = new item(loc) + var/picked = pick(counter) + drink.list_reagents = list() + drink.list_reagents[picked] = 50 + drink.add_initial_reagents() + return drink diff --git a/code/modules/cargo/blackmarket/blackmarket_items/misc.dm b/code/modules/cargo/blackmarket/blackmarket_items/misc.dm index 474be8d29c..83ccd43725 100644 --- a/code/modules/cargo/blackmarket/blackmarket_items/misc.dm +++ b/code/modules/cargo/blackmarket/blackmarket_items/misc.dm @@ -10,6 +10,15 @@ stock_max = 6 availability_prob = 80 +/datum/blackmarket_item/misc/clear_pda + name = "Clear PDA" + desc = "Show off your style with this limited edition clear PDA!." + item = /obj/item/pda/clear + price_min = 250 + price_max = 600 + stock_max = 4 + availability_prob = 50 + /datum/blackmarket_item/misc/shoulder_holster name = "Shoulder holster" desc = "Yeehaw, hardboiled friends! This holster is the first step in your dream of becoming a detective and being allowed to shoot real guns!" @@ -37,11 +46,11 @@ name = "Strange Seeds" desc = "An Exotic Variety of seed that can contain anything from glow to acid." item = /obj/item/seeds/random - price_min = 320 - price_max = 360 + price_min = 450 + price_max = 650 stock_min = 2 stock_max = 5 - availability_prob = 50 + availability_prob = 100 /datum/blackmarket_item/misc/smugglers_satchel name = "Smuggler's Satchel" @@ -51,3 +60,14 @@ price_max = 1000 stock_max = 2 availability_prob = 30 + +/datum/blackmarket_item/misc/internals_box + name = "Internals Box" + desc = "The same one Nanotrasen gives you before starting the shift. Totally not stolen from a dead space-man floating in space." + item = /obj/item/storage/box/survival + price_min = 250 + price_max = 350 + stock_min = 3 + stock_max = 6 + availability_prob = 100 + diff --git a/code/modules/cargo/blackmarket/blackmarket_items/tools.dm b/code/modules/cargo/blackmarket/blackmarket_items/tools.dm index 3da10b16fd..f0b2c2143f 100644 --- a/code/modules/cargo/blackmarket/blackmarket_items/tools.dm +++ b/code/modules/cargo/blackmarket/blackmarket_items/tools.dm @@ -59,7 +59,7 @@ name = "Thermite Bottle" desc = "30 units of Thermite to assist in creating a quick access point or get away!" item = /obj/item/reagent_containers/glass/bottle/thermite - price_min = 500 + price_min = 750 price_max = 1500 stock_max = 3 availability_prob = 30 @@ -68,7 +68,18 @@ name = "Science Goggles" desc = "These glasses scan the contents of containers and projects their contents to the user in an easy-to-read format." item = /obj/item/clothing/glasses/science - price_min = 150 - price_max = 200 - stock_max = 3 - availability_prob = 50 + price_min = 200 + price_max = 300 + stock_min = 3 + stock_max = 7 + availability_prob = 100 + +/datum/blackmarket_item/tool/meson_goggles + name = "Meson Goggles" + desc = "These let you see through walls and inspect other structures." + item = /obj/item/clothing/glasses/meson + price_min = 200 + price_max = 300 + stock_min = 3 + stock_max = 7 + availability_prob = 100 diff --git a/code/modules/cargo/blackmarket/blackmarket_items/weapons.dm b/code/modules/cargo/blackmarket/blackmarket_items/weapons.dm index 4978d688ae..a2e62ebe72 100644 --- a/code/modules/cargo/blackmarket/blackmarket_items/weapons.dm +++ b/code/modules/cargo/blackmarket/blackmarket_items/weapons.dm @@ -28,14 +28,23 @@ item = /obj/item/spear/bonespear price_min = 200 price_max = 300 - stock_max = 3 - availability_prob = 60 + stock_max = 0 + availability_prob = 0 /datum/blackmarket_item/weapon/emp_grenade name = "EMP Grenade" desc = "Use this grenade for SHOCKING results!" item = /obj/item/grenade/empgrenade - price_min = 100 - price_max = 400 + price_min = 300 + price_max = 600 stock_max = 2 - availability_prob = 50 + availability_prob = 20 + +/datum/blackmarket_item/weapon/smoke_grenade + name = "Smoke Grenade" + desc = "Used for obcuring a large area with thick smoke." + item = /obj/item/grenade/smokebomb + price_min = 100 + price_max = 300 + stock_max = 3 + availability_prob = 40 diff --git a/code/modules/cargo/blackmarket/blackmarket_uplink.dm b/code/modules/cargo/blackmarket/blackmarket_uplink.dm index bcbed59b38..7d5b333f13 100644 --- a/code/modules/cargo/blackmarket/blackmarket_uplink.dm +++ b/code/modules/cargo/blackmarket/blackmarket_uplink.dm @@ -1,5 +1,6 @@ /obj/item/blackmarket_uplink name = "Black Market Uplink" + desc = "A mishmash of a subspace amplifier, a radio, and an analyzer. Somehow able to access the black market, with a variable inventory in limited stock at inflated prices. No refunds, customer responsible for pick-ups." icon = 'icons/obj/blackmarket.dmi' icon_state = "uplink" // UI variables. diff --git a/code/modules/cargo/bounties/security.dm b/code/modules/cargo/bounties/security.dm index 6ed86cd4b7..5ddf456573 100644 --- a/code/modules/cargo/bounties/security.dm +++ b/code/modules/cargo/bounties/security.dm @@ -23,7 +23,7 @@ name = "Strobe Shield" description = "One of our Emergency Response Agents thinks there's vampires in a local station. Send him something to help with his fear of the dark and protect him, too." reward = 3000 - wanted_types = list(/obj/item/assembly/flash/shield) + wanted_types = list(/obj/item/shield/riot/flash) /datum/bounty/item/security/sechuds name = "Sec HUDs" diff --git a/code/modules/cargo/exports/weapons.dm b/code/modules/cargo/exports/weapons.dm index dc2703c146..c973ceed26 100644 --- a/code/modules/cargo/exports/weapons.dm +++ b/code/modules/cargo/exports/weapons.dm @@ -16,7 +16,7 @@ /datum/export/weapon/riot_shield cost = 70 unit_name = "flash shield" - export_types = list(/obj/item/assembly/flash/shield) + export_types = list(/obj/item/shield/riot/flash) /datum/export/weapon/tele_shield cost = 100 @@ -138,7 +138,7 @@ export_types = list(/obj/item/gun/energy/xray) /datum/export/weapon/ioncarbine - cost = 200 + cost = 200 unit_name = "ion carbine" export_types = list(/obj/item/gun/energy/ionrifle/carbine) diff --git a/code/modules/cargo/packs/service.dm b/code/modules/cargo/packs/service.dm index 2bb3934ac7..f53186d96e 100644 --- a/code/modules/cargo/packs/service.dm +++ b/code/modules/cargo/packs/service.dm @@ -171,7 +171,7 @@ /datum/supply_pack/service/replacementdb name = "Replacement Defensive Bar Shotgun" - desc = "Someone stole the Bartender's twin-barreled possession? Give them another one at a significant markup. Comes with one unused double-barrel shotgun, shells not included. Requires bartender access to open." + desc = "Someone stole the Bartender's twin-barreled possession? Give them another one at a significant markup. Comes with one unused double-barrel shotgun, additional shells not included. Requires bartender access to open." cost = 2200 access = ACCESS_BAR contraband = TRUE diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 257a520af8..3e4b962bc4 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -148,11 +148,11 @@ GLOBAL_LIST_EMPTY(preferences_datums) //Job preferences 2.0 - indexed by job title , no key or value implies never var/list/job_preferences = list() - // Want randomjob if preferences already filled - Donkie + // Want randomjob if preferences already filled - Donkie var/joblessrole = BERANDOMJOB //defaults to 1 for fewer assistants // 0 = character settings, 1 = game preferences - var/current_tab = 0 + var/current_tab = SETTINGS_TAB var/unlock_content = 0 @@ -274,13 +274,13 @@ GLOBAL_LIST_EMPTY(preferences_datums) update_preview_icon(current_tab) var/list/dat = list("
") - dat += "Character Settings" - dat += "Character Appearance" - dat += "Character Speech" - dat += "Loadout" - dat += "Game Preferences" - dat += "Content Preferences" - dat += "Keybindings" + dat += "Character Settings" + dat += "Character Appearance" + dat += "Character Speech" + dat += "Loadout" + dat += "Game Preferences" + dat += "Content Preferences" + dat += "Keybindings" if(!path) dat += "
Please create an account to save your preferences
" @@ -290,7 +290,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "
" switch(current_tab) - if (0) // Character Settings# + if(SETTINGS_TAB) // Character Settings# if(path) var/savefile/S = new /savefile(path) if(S) @@ -366,7 +366,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "" //Character Appearance - if(2) + if(APPEARANCE_TAB) if(path) var/savefile/S = new /savefile(path) if(S) @@ -670,7 +670,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "" dat += "" - if(3) + if(SPEECH_TAB) if(path) var/savefile/S = new /savefile(path) if(S) @@ -700,7 +700,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "" dat += "" - if (1) // Game Preferences + if(GAME_PREFERENCES_TAB) // Game Preferences dat += "" dat += "
" dat += "

General Settings

" dat += "UI Style: [UI_style]
" @@ -871,7 +871,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "
" - if(4) + if(LOADOUT_TAB) //calculate your gear points from the chosen item gear_points = CONFIG_GET(number/initial_gear_points) var/list/chosen_gear = loadout_data["SAVE_[loadout_slot]"] @@ -990,7 +990,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "
[loadout_item ? (loadout_item[LOADOUT_CUSTOM_DESCRIPTION] ? loadout_item[LOADOUT_CUSTOM_DESCRIPTION] : gear.description) : gear.description] Progress: [min(progress_made, unlockable.progress_required)]/[unlockable.progress_required]
" - if(5) // Content preferences + if(CONTENT_PREFERENCES_TAB) // Content preferences dat += "
" dat += "

Fetish content prefs

" dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"]
" @@ -1014,7 +1014,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Automatic Wagging: [(cit_toggles & NO_AUTO_WAG) ? "Disabled" : "Enabled"]
" dat += "
" dat += "
" - if(6) // Custom keybindings + if(KEYBINDINGS_TAB) // Custom keybindings dat += "Keybindings: [(hotkeys) ? "Hotkeys" : "Input"]
" dat += "Keybindings mode controls how the game behaves with tab and map/input focus.
If it is on Hotkeys, the game will always attempt to force you to map focus, meaning keypresses are sent \ directly to the map instead of the input. You will still be able to use the command bar, but you need to tab to do it every time you click on the game map.
\ @@ -2721,7 +2721,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) save_character() if("tab") - if (href_list["tab"]) + if(href_list["tab"]) current_tab = text2num(href_list["tab"]) if(href_list["preference"] == "gear") if(href_list["clear_loadout"]) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index df05eee638..6e570e595a 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -277,7 +277,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/under/chameleon) item_state = "bl_suit" desc = "It's a plain jumpsuit. It has a small dial on the wrist." sensor_mode = SENSOR_OFF //Hey who's this guy on the Syndicate Shuttle?? - random_sensor = FALSE + sensor_flags = NONE resistance_flags = NONE can_adjust = FALSE armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 018c3d9a3f..416c6309d4 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -233,7 +233,7 @@ /obj/item/clothing/examine(mob/user) . = ..() if(damaged_clothes == CLOTHING_SHREDDED) - . += "It is completely shredded and requires mending before it can be worn again!" + . += "It is completely shredded and requires mending!" return for(var/zone in damage_by_parts) var/pct_damage_part = damage_by_parts[zone] / limb_integrity * 100 @@ -437,12 +437,10 @@ BLIND // can't see anything damaged_clothes = CLOTHING_SHREDDED body_parts_covered = NONE name = "shredded [initial(name)]" - slot_flags = NONE - update_clothes_damaged_state() + update_clothes_damaged_state(CLOTHING_SHREDDED) if(ismob(loc)) var/mob/M = loc - M.visible_message("[M]'s [src.name] falls off, completely shredded!", "Your [src.name] falls off, completely shredded!", vision_distance = COMBAT_MESSAGE_RANGE) - M.dropItemToGround(src) + M.visible_message("[M]'s [src.name] is completely shredded!", "Your [src.name] is completely shredded!", vision_distance = COMBAT_MESSAGE_RANGE) else ..() diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index fe08cbd63e..88fbc98280 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -78,10 +78,40 @@ speech_args[SPEECH_MESSAGE] = trim(message) /obj/item/clothing/mask/joy - name = "joy mask" - desc = "Express your happiness or hide your sorrows with this laughing face with crying tears of joy cutout." + name = "Emotional Mask" + desc = "Express your happiness or hide your sorrows with this modular cutout." icon_state = "joy" + clothing_flags = ALLOWINTERNALS mutantrace_variation = STYLE_MUZZLE + actions_types = list(/datum/action/item_action/adjust) + var/static/list/joymask_designs = list() + + +/obj/item/clothing/mask/joy/Initialize(mapload) + . = ..() + joymask_designs = list( + "Joy" = image(icon = src.icon, icon_state = "joy"), + "Flushed" = image(icon = src.icon, icon_state = "flushed"), + "Pensive" = image(icon = src.icon, icon_state = "pensive"), + "Angry" = image(icon = src.icon, icon_state = "angry"), + ) + +/obj/item/clothing/mask/joy/ui_action_click(mob/user) + if(!istype(user) || user.incapacitated()) + return + + var/static/list/options = list("Joy" = "joy", "Flushed" = "flushed", "Pensive" = "pensive","Angry" ="angry") + + var/choice = show_radial_menu(user, src, joymask_designs, custom_check = FALSE, radius = 36, require_near = TRUE) + + if(src && choice && !user.incapacitated() && in_range(user,src)) + icon_state = options[choice] + user.update_inv_wear_mask() + for(var/X in actions) + var/datum/action/A = X + A.UpdateButtonIcon() + to_chat(user, "Your Joy mask now has a [choice] Emotion!") + return 1 /obj/item/clothing/mask/pig name = "pig mask" diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 3207a5842f..59af632d2a 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -7,11 +7,14 @@ slot_flags = ITEM_SLOT_ICLOTHING armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 5) mutantrace_variation = STYLE_DIGITIGRADE|USE_TAUR_CLIP_MASK - limb_integrity = 30 + limb_integrity = 120 var/fitted = FEMALE_UNIFORM_FULL // For use in alternate clothing styles for women var/has_sensor = HAS_SENSORS // For the crew computer - var/random_sensor = TRUE + var/sensor_flags = SENSOR_RANDOM var/sensor_mode = NO_SENSORS + var/sensor_mode_intended = NO_SENSORS //if sensors become damaged and are repaired later, it will revert to the user's intended preferences + var/sensormaxintegrity = 200 //if this is zero, then our sensors can only be destroyed by shredded clothing + var/sensordamage = 0 //how much damage did our sensors take? var/can_adjust = TRUE var/adjusted = NORMAL_STYLE var/alt_covers_chest = FALSE // for adjusted/rolled-down jumpsuits, FALSE = exposes chest and arms, TRUE = exposes arms only @@ -31,30 +34,76 @@ . += accessory_overlay /obj/item/clothing/under/attackby(obj/item/I, mob/user, params) - if((has_sensor == BROKEN_SENSORS) && istype(I, /obj/item/stack/cable_coil)) - if(damaged_clothes) - to_chat(user,"You should repair the damage done to [src] first.") + if((sensordamage || (has_sensor < HAS_SENSORS && has_sensor != NO_SENSORS)) && istype(I, /obj/item/stack/cable_coil)) + if(damaged_clothes == CLOTHING_SHREDDED) + to_chat(user,"[src] is too damaged to have its suit sensors repaired! Repair it first.") return 0 var/obj/item/stack/cable_coil/C = I I.use_tool(src, user, 0, 1) has_sensor = HAS_SENSORS + sensordamage = 0 + sensor_mode = sensor_mode_intended to_chat(user,"You repair the suit sensors on [src] with [C].") return 1 + if(!attach_accessory(I, user)) return ..() +/obj/item/clothing/under/take_damage_zone(def_zone, damage_amount, damage_type, armour_penetration) + ..() + if(sensormaxintegrity == 0 || has_sensor == NO_SENSORS || sensordamage >= sensormaxintegrity) return //sensors are invincible if max integrity is 0 + var/damage_dealt = take_damage(damage_amount * 0.1, damage_type, armour_penetration, FALSE) * 10 // only deal 10% of the damage to the general integrity damage, then multiply it by 10 so we know how much to deal to limb + sensordamage += damage_dealt + var/integ = has_sensor + var/newinteg = sensorintegrity() + if(newinteg != integ) + if(newinteg < integ && iscarbon(src.loc)) //the first check is to see if for some inexplicable reason the attack healed our suit sensors + var/mob/living/carbon/C = src.loc + switch(newinteg) + if(DAMAGED_SENSORS_VITALS) + to_chat(C,"Your tracking beacon on your suit sensors have shorted out!") + if(DAMAGED_SENSORS_LIVING) + to_chat(C,"Your vital tracker on your suit sensors have shorted out!") + if(BROKEN_SENSORS) + to_chat(C,"Your suit sensors have shorted out completely!") + updatesensorintegrity(newinteg) + + +/obj/item/clothing/under/proc/sensorintegrity() + var/percentage = sensordamage/sensormaxintegrity //calculate the percentage of how much damage taken + if(percentage < SENSOR_INTEGRITY_COORDS) return HAS_SENSORS + else if(percentage < SENSOR_INTEGRITY_VITALS) return DAMAGED_SENSORS_VITALS + else if(percentage < SENSOR_INTEGRITY_BINARY) return DAMAGED_SENSORS_LIVING + else return BROKEN_SENSORS + +/obj/item/clothing/under/proc/updatesensorintegrity(integ = HAS_SENSORS) + if(sensormaxintegrity == 0 || has_sensor == NO_SENSORS) return //sanity check + has_sensor = integ + switch(has_sensor) + if(HAS_SENSORS) + sensor_mode = sensor_mode_intended + if(DAMAGED_SENSORS_VITALS) + if(sensor_mode > SENSOR_VITALS) sensor_mode = SENSOR_VITALS + if(DAMAGED_SENSORS_LIVING) + if(sensor_mode > SENSOR_LIVING) sensor_mode = SENSOR_LIVING + if(BROKEN_SENSORS) + sensor_mode = NO_SENSORS + + /obj/item/clothing/under/update_clothes_damaged_state() ..() if(ismob(loc)) var/mob/M = loc M.update_inv_w_uniform() - if(has_sensor > NO_SENSORS) + if(has_sensor > NO_SENSORS && damaged_clothes == CLOTHING_SHREDDED) has_sensor = BROKEN_SENSORS + sensordamage = sensormaxintegrity /obj/item/clothing/under/New() - if(random_sensor) + if(sensor_flags & SENSOR_RANDOM) //make the sensor mode favor higher levels, except coords. sensor_mode = pick(SENSOR_OFF, SENSOR_LIVING, SENSOR_LIVING, SENSOR_VITALS, SENSOR_VITALS, SENSOR_VITALS, SENSOR_COORDS, SENSOR_COORDS) + sensor_mode_intended = sensor_mode ..() /obj/item/clothing/under/equipped(mob/user, slot) @@ -143,9 +192,14 @@ . += "Alt-click on [src] to wear it normally." else . += "Alt-click on [src] to wear it casually." - if (has_sensor == BROKEN_SENSORS) - . += "Its sensors appear to be shorted out." - else if(has_sensor > NO_SENSORS) + switch(has_sensor) + if(BROKEN_SENSORS) + . += "Its sensors appear to be shorted out completely. It can be repaired using cable." + if(DAMAGED_SENSORS_LIVING) + . += "Its sensors appear to have its tracking beacon and vital tracker broken. It can be repaired using cable." + if(DAMAGED_SENSORS_VITALS) + . += "Its sensors appear to have its tracking beacon broken. It can be repaired using cable." + if(has_sensor > NO_SENSORS) switch(sensor_mode) if(SENSOR_OFF) . += "Its sensors appear to be disabled." @@ -167,12 +221,12 @@ return if (!can_use(M)) return - if(src.has_sensor == LOCKED_SENSORS) - to_chat(usr, "The controls are locked.") - return 0 if(src.has_sensor == BROKEN_SENSORS) to_chat(usr, "The sensors have shorted out!") return 0 + if(src.sensor_flags & SENSOR_LOCKED) + to_chat(usr, "The controls are locked.") + return 0 if(src.has_sensor <= NO_SENSORS) to_chat(usr, "This suit does not have any sensors.") return 0 @@ -182,18 +236,34 @@ if(get_dist(usr, src) > 1) to_chat(usr, "You have moved too far away!") return - sensor_mode = modes.Find(switchMode) - 1 + sensor_mode_intended = modes.Find(switchMode) - 1 if (src.loc == usr) - switch(sensor_mode) + switch(sensor_mode_intended) if(0) to_chat(usr, "You disable your suit's remote sensing equipment.") + sensor_mode = sensor_mode_intended if(1) to_chat(usr, "Your suit will now only report whether you are alive or dead.") + sensor_mode = sensor_mode_intended if(2) - to_chat(usr, "Your suit will now only report your exact vital lifesigns.") + if(src.has_sensor == DAMAGED_SENSORS_LIVING) + to_chat(usr, "Your suit's vital tracker is broken, so it will only report whether you are alive or dead.") + sensor_mode = SENSOR_LIVING + else + to_chat(usr, "Your suit will now only report your exact vital lifesigns.") + sensor_mode = sensor_mode_intended if(3) - to_chat(usr, "Your suit will now report your exact vital lifesigns as well as your coordinate position.") + switch(src.has_sensor) + if(DAMAGED_SENSORS_LIVING) + to_chat(usr, "Your suit's tracking beacon and vital tracker is broken, so it will only report whether you are alive or dead.") + sensor_mode = SENSOR_LIVING + if(DAMAGED_SENSORS_VITALS) + to_chat(usr, "Your suit's tracking beacon is broken, so it will only report your vital lifesigns.") + sensor_mode = SENSOR_VITALS + if(HAS_SENSORS) + to_chat(usr, "Your suit will now report your exact vital lifesigns as well as your coordinate position.") + sensor_mode = sensor_mode_intended if(ishuman(loc)) var/mob/living/carbon/human/H = loc @@ -210,19 +280,28 @@ if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) return - if(has_sensor == LOCKED_SENSORS) - to_chat(user, "The controls are locked.") - return - if(has_sensor == BROKEN_SENSORS) - to_chat(user, "The sensors have shorted out!") - return + if(src.has_sensor == BROKEN_SENSORS) + to_chat(usr, "The sensors have shorted out!") + return 0 + if(src.sensor_flags & SENSOR_LOCKED) + to_chat(usr, "The controls are locked.") + return 0 if(has_sensor <= NO_SENSORS) to_chat(user, "This suit does not have any sensors.") return - sensor_mode = SENSOR_COORDS + sensor_mode_intended = SENSOR_COORDS - to_chat(user, "Your suit will now report your exact vital lifesigns as well as your coordinate position.") + switch(src.has_sensor) + if(DAMAGED_SENSORS_LIVING) + to_chat(usr, "Your suit's tracking beacon and vital tracker is broken, so it will only report whether you are alive or dead.") + sensor_mode = SENSOR_LIVING + if(DAMAGED_SENSORS_VITALS) + to_chat(usr, "Your suit's tracking beacon is broken, so it will only report your vital lifesigns.") + sensor_mode = SENSOR_VITALS + if(HAS_SENSORS) + to_chat(usr, "Your suit will now report your exact vital lifesigns as well as your coordinate position.") + sensor_mode = sensor_mode_intended if(ishuman(user)) var/mob/living/carbon/human/H = user diff --git a/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm b/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm index 082d783bea..885e659bb2 100644 --- a/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm +++ b/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm @@ -59,7 +59,7 @@ item_state = "captain_envirosuit" armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 0, "fire" = 95, "acid" = 95, "wound" = 15) sensor_mode = SENSOR_COORDS - random_sensor = FALSE + sensor_flags = NONE /obj/item/clothing/under/plasmaman/mime name = "mime envirosuit" diff --git a/code/modules/clothing/under/jobs/Plasmaman/security.dm b/code/modules/clothing/under/jobs/Plasmaman/security.dm index 3330d72844..c9b7b494a3 100644 --- a/code/modules/clothing/under/jobs/Plasmaman/security.dm +++ b/code/modules/clothing/under/jobs/Plasmaman/security.dm @@ -5,7 +5,7 @@ item_state = "security_envirosuit" armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 0, "fire" = 95, "acid" = 95, "wound" = 10) sensor_mode = SENSOR_COORDS - random_sensor = FALSE + sensor_flags = NONE /obj/item/clothing/under/plasmaman/security/warden name = "warden plasma envirosuit" diff --git a/code/modules/clothing/under/jobs/command.dm b/code/modules/clothing/under/jobs/command.dm index cc07665063..1d4425bc82 100644 --- a/code/modules/clothing/under/jobs/command.dm +++ b/code/modules/clothing/under/jobs/command.dm @@ -5,7 +5,7 @@ item_state = "b_suit" armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0, "wound" = 15) sensor_mode = SENSOR_COORDS - random_sensor = FALSE + sensor_flags = NONE /obj/item/clothing/under/rank/captain/util name = "command utility uniform" diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm index 4438298dea..0b1fb99bf8 100644 --- a/code/modules/clothing/under/jobs/security.dm +++ b/code/modules/clothing/under/jobs/security.dm @@ -12,7 +12,7 @@ strip_delay = 50 alt_covers_chest = TRUE sensor_mode = SENSOR_COORDS - random_sensor = FALSE + sensor_flags = NONE /obj/item/clothing/under/rank/security/officer name = "security jumpsuit" diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 59e0832fef..e01ceba0bf 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -23,16 +23,15 @@ name = "prison jumpsuit" desc = "It's standardised Nanotrasen prisoner-wear. Its suit sensors are stuck in the \"Fully On\" position." icon_state = "prisoner" - item_state = "o_suit" - has_sensor = LOCKED_SENSORS + item_state = "prisoner" sensor_mode = SENSOR_COORDS - random_sensor = FALSE + sensor_flags = SENSOR_LOCKED /obj/item/clothing/under/rank/prisoner/skirt name = "prison jumpskirt" desc = "It's standardised Nanotrasen prisoner-wear. Its suit sensors are stuck in the \"Fully On\" position." icon_state = "prisoner_skirt" - item_state = "o_suit" + item_state = "prisoner_skirt" body_parts_covered = CHEST|GROIN|ARMS can_adjust = FALSE fitted = FEMALE_UNIFORM_TOP @@ -166,6 +165,7 @@ /obj/item/clothing/under/misc/gear_harness name = "gear harness" desc = "A simple, inconspicuous harness replacement for a jumpsuit." + limb_integrity = 180 icon_state = "gear_harness" item_state = "gear_harness" can_adjust = TRUE diff --git a/code/modules/events/supernova.dm b/code/modules/events/supernova.dm index a109d484e9..6fc2fb0c4c 100644 --- a/code/modules/events/supernova.dm +++ b/code/modules/events/supernova.dm @@ -25,7 +25,7 @@ supernova.power_mod = 0 /datum/round_event/supernova/announce() - var/message = "Our tachyon-doppler array has detected a supernova in your vicinity. Peak flux from the supernova estimated to be [round(power,0.1)] times current solar flux. [power > 4 ? "Short burts of radiation may be possible, so please prepare accordingly." : ""]" + var/message = "Our tachyon-doppler array has detected a supernova in your vicinity. Peak flux from the supernova estimated to be [round(power,0.1)] times current solar flux. [power > 1 ? "Short burts of radiation may be possible, so please prepare accordingly." : ""]" if(prob(power * 25)) priority_announce(message) else @@ -47,12 +47,11 @@ /datum/round_event/supernova/tick() var/midpoint = round((endWhen-startWhen)/2) - switch(activeFor) - if(startWhen to midpoint) - supernova.power_mod = min(supernova.power_mod*1.2, power) - if(endWhen-10 to endWhen) - supernova.power_mod /= 4 - if(prob(round(supernova.power_mod / 2)) && storm_count < 4 && !SSweather.get_weather_by_type(/datum/weather/rad_storm)) + if(activeFor < midpoint) + supernova.power_mod = min(supernova.power_mod*1.2, power) + if(activeFor > endWhen-10) + supernova.power_mod /= 4 + if(prob(round(supernova.power_mod)) && prob(5) && storm_count < 5 && !SSweather.get_weather_by_type(/datum/weather/rad_storm)) SSweather.run_weather(/datum/weather/rad_storm/supernova) storm_count++ @@ -63,5 +62,7 @@ /datum/weather/rad_storm/supernova weather_duration_lower = 50 weather_duration_upper = 100 - telegraph_duration = 100 - radiation_intensity = 50 + telegraph_duration = 200 + radiation_intensity = 1000 + weather_sound = null + telegraph_message = "The air begins to grow very warm!" diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index ba61169aac..9956fb1982 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -36,7 +36,7 @@ desc = "It's watching you suspiciously." /obj/structure/closet/crate/necropolis/tendril/magic/PopulateContents() - var/loot = rand(1,10) + var/loot = rand(1,9) switch(loot) if(1) new /obj/item/soulstone/anybody(src) @@ -57,10 +57,6 @@ new /obj/item/immortality_talisman(src) if(9) new /obj/item/gun/magic/wand/book/healing(src) - if(10) - new /obj/item/reagent_containers/glass/bottle/ichor/red(src) - new /obj/item/reagent_containers/glass/bottle/ichor/blue(src) - new /obj/item/reagent_containers/glass/bottle/ichor/green(src) /obj/structure/closet/crate/necropolis/tendril/weapon_armor/PopulateContents() var/loot = rand(1,11) @@ -132,7 +128,7 @@ new /obj/item/disk/design_disk/modkit_disc/rapid_repeater(src) /obj/structure/closet/crate/necropolis/tendril/all/PopulateContents() - var/loot = rand(1,29) + var/loot = rand(1,28) switch(loot) if(1) new /obj/item/shared_storage/red(src) @@ -196,10 +192,6 @@ new /obj/item/immortality_talisman(src) if(28) new /obj/item/gun/magic/wand/book/healing(src) - if(29) - new /obj/item/reagent_containers/glass/bottle/ichor/red(src) - new /obj/item/reagent_containers/glass/bottle/ichor/blue(src) - new /obj/item/reagent_containers/glass/bottle/ichor/green(src) //KA modkit design discs /obj/item/disk/design_disk/modkit_disc diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index 2e1ffe718f..d198140c5f 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -27,7 +27,7 @@ age = rand(AGE_MIN,AGE_MAX) /datum/preferences/proc/update_preview_icon(current_tab) - var/equip_job = (current_tab != 2) + var/equip_job = (current_tab != APPEARANCE_TAB) // Determine what job is marked as 'High' priority, and dress them up as such. var/datum/job/previewJob = get_highest_job() @@ -46,7 +46,7 @@ mannequin.add_overlay(mutable_appearance('modular_citadel/icons/ui/backgrounds.dmi', bgstate, layer = SPACE_LAYER)) copy_to(mannequin, initial_spawn = TRUE) - if(current_tab == 3) + if(current_tab == LOADOUT_TAB) //give it its loadout if not on the appearance tab SSjob.equip_loadout(parent.mob, mannequin, FALSE, bypass_prereqs = TRUE, can_drop = FALSE) else diff --git a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm index a964be3f8a..e17dc43950 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -514,6 +514,20 @@ icon = 'modular_citadel/icons/mob/mam_tails.dmi' matrixed_sections = MATRIX_RED_GREEN +/datum/sprite_accessory/tails/human/triple_kitsune + name = "Triple Kitsune Tails" + icon_state = "3sune" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + matrixed_sections = MATRIX_RED_GREEN + +/datum/sprite_accessory/tails_animated/human/triple_kitsune + name = "Triple Kitsune Tails" + icon_state = "3sune" + color_src = MATRIXED + icon = 'modular_citadel/icons/mob/mam_tails.dmi' + matrixed_sections = MATRIX_RED_GREEN + /datum/sprite_accessory/tails/human/tentacle name = "Tentacle" icon_state = "tentacle" @@ -965,6 +979,16 @@ icon_state = "9sune" matrixed_sections = MATRIX_RED_GREEN +/datum/sprite_accessory/tails/mam_tails/triple_kitsune + name = "Triple Kitsune Tails" + icon_state = "3sune" + matrixed_sections = MATRIX_RED_GREEN + +/datum/sprite_accessory/tails_animated/mam_tails_animated/triple_kitsune + name = "Triple Kitsune Tails" + icon_state = "3sune" + matrixed_sections = MATRIX_RED_GREEN + /datum/sprite_accessory/tails/mam_tails/tentacle name = "Tentacle" icon_state = "tentacle" diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index be9cd0aabb..5fd52975e0 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -87,7 +87,7 @@ addtimer(CALLBACK(src, .proc/med_hud_set_status), (DEFIB_TIME_LIMIT * 10) + 1) stop_pulling() - var/signal = SEND_SIGNAL(src, COMSIG_MOB_DEATH, gibbed) + var/signal = SEND_SIGNAL(src, COMSIG_MOB_DEATH, gibbed) | SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_DEATH, src, gibbed) var/turf/T = get_turf(src) if(mind && mind.name && mind.active && !istype(T.loc, /area/ctf) && !(signal & COMPONENT_BLOCK_DEATH_BROADCAST)) diff --git a/code/modules/projectiles/boxes_magazines/internal/shotgun.dm b/code/modules/projectiles/boxes_magazines/internal/shotgun.dm index 246260dbf8..12f4e1f1c5 100644 --- a/code/modules/projectiles/boxes_magazines/internal/shotgun.dm +++ b/code/modules/projectiles/boxes_magazines/internal/shotgun.dm @@ -55,3 +55,9 @@ name = "triple-barrel shotgun internal magazine" ammo_type = /obj/item/ammo_casing/shotgun/incapacitate max_ammo = 3 + +/obj/item/ammo_box/magazine/internal/shot/levergun + name = "levergun internal magazine" + ammo_type = /obj/item/ammo_casing/c38 // they're rubber by default, i guess + caliber = "38" + max_ammo = 7 diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index fa8099a257..1416dfa812 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -8,6 +8,7 @@ var/obj/item/ammo_box/magazine/magazine var/casing_ejector = TRUE //whether the gun ejects the chambered casing var/magazine_wording = "magazine" + var/sawn_item_state = "gun" /obj/item/gun/ballistic/Initialize() . = ..() @@ -198,13 +199,17 @@ name = "sawn-off [src.name]" desc = sawn_desc w_class = WEIGHT_CLASS_NORMAL - item_state = "gun" + item_state = sawn_item_state slot_flags &= ~ITEM_SLOT_BACK //you can't sling it on your back slot_flags |= ITEM_SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally) sawn_off = TRUE update_icon() return 1 +/// is something supposed to happen here? +/obj/item/gun/ballistic/proc/on_sawoff(mob/user) + return + // Sawing guns related proc /obj/item/gun/ballistic/proc/blow_up(mob/user) . = 0 diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 8035440906..3e7e2c9e9c 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -12,6 +12,7 @@ casing_ejector = FALSE var/recentpump = 0 // to prevent spammage weapon_weight = WEAPON_HEAVY + sawn_item_state = "sawnshotgun" /obj/item/gun/ballistic/shotgun/attackby(obj/item/A, mob/user, params) . = ..() @@ -335,3 +336,34 @@ //our hook gun! var/obj/item/gun/magic/hook/bounty/hook var/toggled = FALSE + +// hey you kids like +// LEVER GUNS? + +/obj/item/gun/ballistic/shotgun/leveraction + name = "lever-action rifle" + desc = "While lever-actions have been horribly out of date for hundreds of years now, \ + the reported potential versatility of .38 Special is worth paying attention to." + fire_sound = "sound/weapons/revolvershot.ogg" + mag_type = /obj/item/ammo_box/magazine/internal/shot/levergun + icon_state = "levercarabine" + item_state = "leveraction" + sawn_item_state = "maresleg" + +/obj/item/gun/ballistic/shotgun/leveraction/attackby(obj/item/A, mob/user, params) + ..() + if(A.tool_behaviour == TOOL_SAW || istype(A, /obj/item/gun/energy/plasmacutter)) + sawoff(user) + if(istype(A, /obj/item/melee/transforming/energy)) + var/obj/item/melee/transforming/energy/W = A + if(W.active) + sawoff(user) + +/obj/item/gun/ballistic/shotgun/leveraction/on_sawoff(mob/user) + magazine.max_ammo-- // sawing off drops from 7+1 to 6+1 + +/obj/item/gun/ballistic/shotgun/leveraction/update_icon_state() + if(current_skin) + icon_state = "[unique_reskin[current_skin]][sawn_off ? "-sawn" : ""][chambered ? "" : "-e"]" + else + icon_state = "[initial(icon_state)][sawn_off ? "-sawn" : ""][chambered ? "" : "-e"]" diff --git a/code/modules/research/designs/machine_desings/machine_designs_service.dm b/code/modules/research/designs/machine_desings/machine_designs_service.dm index af4f650793..743c365dee 100644 --- a/code/modules/research/designs/machine_desings/machine_designs_service.dm +++ b/code/modules/research/designs/machine_desings/machine_designs_service.dm @@ -85,7 +85,7 @@ name = "Machine Design (Automatic Hydroponics Tray Board)" desc = "The circuit board for an automatic hydroponics tray. GIVE ME THE PLANT, CAPTAIN." id = "autohydrotray" - build_path = /obj/machinery/hydroponics/constructable/automagic + build_path = /obj/item/circuitboard/machine/hydroponics/automagic category = list ("Hydroponics Machinery") departmental_flags = DEPARTMENTAL_FLAG_SERVICE | DEPARTMENTAL_FLAG_MEDICAL diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 11dd29a416..f7ba9e7e63 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -457,23 +457,23 @@ category = list("Weapons") departmental_flags = DEPARTMENTAL_FLAG_SECURITY -/datum/design/laser_shield - name = "Laser Resistant Riot Shield" - desc = "An advanced riot shield made of darker glasses to prevent laser fire from passing through." +/datum/design/energy_shield + name = "Energy Resistant Shield" + desc = "An ablative shield designed to stop energy-based attacks dead in their tracks, but shatter easily against kinetic blows." id = "laser_shield" build_type = PROTOLATHE materials = list(/datum/material/iron = 4000, /datum/material/glass = 1000, /datum/material/plastic = 4000, /datum/material/silver = 800, /datum/material/titanium = 600, /datum/material/plasma = 5000) - build_path = /obj/item/shield/riot/laser_proof + build_path = /obj/item/shield/riot/energy_proof category = list("Weapons") departmental_flags = DEPARTMENTAL_FLAG_SECURITY -/datum/design/bullet_shield - name = "Bullet Resistant Riot Shield" - desc = "An advanced riot shield made bullet resistant plastics and heavy metals to protect against projectile harm." +/datum/design/kinetic_shield + name = "Kinetic Resistant Shield" + desc = "An advanced polymer shield designed to stop kinetic-based attacks with ease, but splinter apart against energy-based attacks." id = "bullet_shield" build_type = PROTOLATHE materials = list(/datum/material/iron = 4000, /datum/material/glass = 1000, /datum/material/silver = 2000, /datum/material/titanium = 1200, /datum/material/plastic = 2500) - build_path = /obj/item/shield/riot/bullet_proof + build_path = /obj/item/shield/riot/kinetic_proof category = list("Weapons") departmental_flags = DEPARTMENTAL_FLAG_SECURITY diff --git a/code/modules/smithing/smithed_items.dm b/code/modules/smithing/smithed_items.dm index aff296b684..71e35ba989 100644 --- a/code/modules/smithing/smithed_items.dm +++ b/code/modules/smithing/smithed_items.dm @@ -50,7 +50,7 @@ custom_materials = list(/datum/material/iron=12000) /obj/item/ingot/diamond - custom_materials = list(/datum/material/diamond=12000) //yeah ok + custom_materials = list(/datum/material/diamond=12000) /obj/item/ingot/uranium custom_materials = list(/datum/material/uranium=12000) diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm index 3d54c7130c..fbe7a0ea40 100644 --- a/code/modules/spells/spell_types/lichdom.dm +++ b/code/modules/spells/spell_types/lichdom.dm @@ -93,12 +93,14 @@ active_phylacteries++ GLOB.poi_list |= src START_PROCESSING(SSobj, src) + RegisterSignal(SSactivity, COMSIG_THREAT_CALC, .proc/get_threat) set_light(lon_range) if(initial(SSticker.mode.round_ends_with_antag_death)) SSticker.mode.round_ends_with_antag_death = FALSE /obj/item/phylactery/Destroy(force=FALSE) STOP_PROCESSING(SSobj, src) + UnregisterSignal(SSactivity, COMSIG_THREAT_CALC) active_phylacteries-- GLOB.poi_list -= src if(!active_phylacteries) @@ -113,6 +115,12 @@ if(!mind.current || (mind.current && mind.current.stat == DEAD)) addtimer(CALLBACK(src, .proc/rise), respawn_time, TIMER_UNIQUE) +/obj/item/phylactery/proc/get_threat(list/threat_list) + if(mind?.current?.stat == DEAD) + if(!("phylactery" in threat_list)) + threat_list["phylactery"] = 0 + threat_list["phylactery"] += 25 + /obj/item/phylactery/proc/rise() if(mind.current && mind.current.stat != DEAD) return "[mind] already has a living body: [mind.current]" diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 962bc8c1ce..38f53c93a5 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -99,6 +99,9 @@ var/generic_bleedstacks /// If we have a gauze wrapping currently applied (not including splints) var/obj/item/stack/current_gauze + /// does this limb have replacement capability, despite probably not being robotic? + // see code\modules\surgery\limb_augmentation.dm, or code\game\machinery\limbgrower.dm + var/forcereplace = FALSE /obj/item/bodypart/examine(mob/user) . = ..() @@ -240,7 +243,13 @@ wounding_dmg *= (easy_dismember ? 1 : 0.75) if((mangled_state & BODYPART_MANGLED_BONE) && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)) return - // note that there's no handling for BIO_JUST_FLESH since we don't have any that are that right now (slimepeople maybe someday) + // if we're flesh only, all blunt attacks become weakened slashes in terms of wound damage + if(BIO_JUST_FLESH) + if(wounding_type == WOUND_BLUNT) + wounding_type = WOUND_SLASH + wounding_dmg *= (easy_dismember ? 1 : 0.3) + if((mangled_state & BODYPART_MANGLED_FLESH) && try_dismember(wounding_type, wounding_dmg, wound_bonus, bare_wound_bonus)) + return // standard humanoids if(BIO_FLESH_BONE) // if we've already mangled the skin (critical slash or piercing wound), then the bone is exposed, and we can damage it with sharp weapons at a reduced rate diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index c65f5f11f6..73ea29f254 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -10,7 +10,7 @@ if(istype(tool, /obj/item/organ_storage) && istype(tool.contents[1], /obj/item/bodypart)) tool = tool.contents[1] var/obj/item/bodypart/aug = tool - if(!aug.is_robotic_limb()) + if(!aug.is_robotic_limb() && !aug.forcereplace) // forcereplace used here to allow for replacing limbs with synthflesh variants to_chat(user, "That's not an augment, silly!") return -1 if(aug.body_zone != target_zone) @@ -18,9 +18,14 @@ return -1 L = surgery.operated_bodypart if(L) - display_results(user, target, "You begin to augment [target]'s [parse_zone(user.zone_selected)]...", - "[user] begins to augment [target]'s [parse_zone(user.zone_selected)] with [aug].", - "[user] begins to augment [target]'s [parse_zone(user.zone_selected)].") + if(aug.is_robotic_limb()) + display_results(user, target, "You begin to augment [target]'s [parse_zone(user.zone_selected)]...", + "[user] begins to augment [target]'s [parse_zone(user.zone_selected)] with [aug].", + "[user] begins to augment [target]'s [parse_zone(user.zone_selected)].") + else + display_results(user, target, "You begin to replace [target]'s [parse_zone(user.zone_selected)]...", + "[user] begins to replace [target]'s [parse_zone(user.zone_selected)] with [aug].", + "[user] begins to replace [target]'s [parse_zone(user.zone_selected)].") else user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...") @@ -47,10 +52,15 @@ tool = tool.contents[1] if(istype(tool) && user.temporarilyRemoveItemFromInventory(tool)) tool.replace_limb(target, TRUE) - display_results(user, target, "You successfully augment [target]'s [parse_zone(target_zone)].", - "[user] successfully augments [target]'s [parse_zone(target_zone)] with [tool]!", - "[user] successfully augments [target]'s [parse_zone(target_zone)]!") - log_combat(user, target, "augmented", addition="by giving him new [parse_zone(target_zone)] INTENT: [uppertext(user.a_intent)]") + if(tool.is_robotic_limb()) + display_results(user, target, "You successfully augment [target]'s [parse_zone(target_zone)].", + "[user] successfully augments [target]'s [parse_zone(target_zone)] with [tool]!", + "[user] successfully augments [target]'s [parse_zone(target_zone)]!") + else + display_results(user, target, "You successfully replace [target]'s [parse_zone(target_zone)].", + "[user] successfully replaces [target]'s [parse_zone(target_zone)] with [tool]!", + "[user] successfully replaces [target]'s [parse_zone(target_zone)]!") + log_combat(user, target, "augmented", addition="by giving them a new [parse_zone(target_zone)] INTENT: [uppertext(user.a_intent)]") else to_chat(user, "[target] has no organic [parse_zone(target_zone)] there!") return TRUE diff --git a/html/changelog.html b/html/changelog.html index 32c8dba4d6..9958a35ef6 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -50,6 +50,114 @@ -->
+

29 March 2021

+

BlueWildrose updated:

+ +

YakumoChen updated:

+ +

qweq12yt updated:

+ +

silicons updated:

+ + +

28 March 2021

+

CuteMoff updated:

+ +

Hatterhat updated:

+ +

Putnam3145 updated:

+ +

R3dtail updated:

+ +

Shadow-Quill updated:

+ +

dzahlus updated:

+ +

keronshb updated:

+ +

necromanceranne updated:

+ +

timothyteakettle updated:

+ +

zeroisthebiggay updated:

+ + +

26 March 2021

+

BlueWildrose updated:

+ +

CuteMoff updated:

+ +

Hatterhat updated:

+ +

timothyteakettle updated:

+ + +

25 March 2021

+

zeroisthebiggay updated:

+ +

24 March 2021

BlueWildrose updated:

- -

27 January 2021

-

ArcaneMusic, ported by Hatterhat updated:

- -

Arturlang updated:

- -

DeltaFire15 updated:

- -

Hatterhat updated:

- -

MrJWhit updated:

- -

SandPoot updated:

- -

raspy-on-osu updated:

- -

shellspeed1 updated:

- -

timothyteakettle updated:

- - -

25 January 2021

-

MrJWhit updated:

- -

raspy-on-osu updated:

- -

silicons updated:

- - -

22 January 2021

-

Arturlang updated:

- - -

21 January 2021

-

Acer202 updated:

- -

Acer202, with minor help from The0bserver updated:

- -

ArcaneMusic, The0bserver-sys updated:

- -

ArchieBeepBoop updated:

- -

Arturlang updated:

- -

Bhijn updated:

- -

BlackMajor updated:

- -

BlueWildrose updated:

- -

Chiirno updated:

- -

Delams-The-SM updated:

- -

DeltaFire15 updated:

- -

Detective-Google updated:

- -

ERP mains updated:

- -

EdgeLordExe, MoonFalcon updated:

- -

EmeraldSundisk updated:

- -

Ghommie updated:

- -

Ghommie, porting PRs by MMMiracles and pireamaineach, credits to BlueWildrose too. updated:

- -

Hatterhat updated:

- -

HeroWithYay updated:

- -

KeRSedChaplain updated:

- -

LetterN updated:

- -

Linzolle updated:

- -

MrJWhit updated:

- -

NT Cleaning Crews On Break updated:

- -

Putnam3145 updated:

- -

Ryll/Shaps updated:

- -

SandPoot updated:

- -

SiliconMain updated:

- -

Sonic121x updated:

- -

SpaceManiac updated:

- -

Thalpy updated:

- -

The Grinch updated:

- -

TheObserver updated:

- -

TheObserver-sys updated:

- -

TheSpaghetti updated:

- -

Trilbyspaceclone updated:

- -

TripleShades updated:

- -

Tupinambis updated:

- -

Vynzill updated:

- -

Xantholne updated:

- -

Yakumo Chen updated:

- -

YakumoChen updated:

- -

Zandario updated:

- -

corin9090 updated:

- -

kappa-sama updated:

- -

keronshb updated:

- -

kittycat2002 updated:

- -

kiwedespars updated:

- -

necromanceranne updated:

- -

qwertyquerty updated:

- -

raspy-on-osu updated:

- -

shellspeed1 updated:

- -

silicons updated:

- -

timothyteakettle updated:

- -

uomo91 updated:

- -

yorii updated:

- -

zeroisthebiggay updated:

-
GoonStation 13 Development Team diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 8ee6b9291f..a5b0757748 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -28851,3 +28851,90 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. will show properly when the LTSRBT is built zeroisthebiggay: - rscadd: biodegrade works on legcuffs +2021-03-25: + zeroisthebiggay: + - balance: strained muscles isn't free +2021-03-26: + BlueWildrose: + - balance: Clothing no longer drops when shredded. It just becomes useless. + - balance: Suit sensors are guaranteed to short out when the clothes become shredded, + not damaged now. + - balance: Uniform limb integrity increased from 30 to 120. + - balance: 'Suit sensor damage has been added. The more damaged your suit sensors + get, the less features that will be available from these suit sensors. It takes + two e-sword hits to ruin your tracking beacon for instance. tweak: Examine text + on uniforms is now more clear about needing cable coil to repair your suit sensors.' + - bugfix: Fixed prisoner uniform sprite paths + CuteMoff: + - balance: Diamond's forcemod was changed from 1.1x to 1.2x + Hatterhat: + - rscadd: Lever-action rifles, chambered in .38, are now sitting in the code. They + might be buyable from Cargo or the Black Market soon. Watch this space. + - rscadd: Sawed-off shotguns now look like shotguns, but short, when inhand, instead + of "generic gun". + timothyteakettle: + - bugfix: slimes can be delimbed + - bugfix: the loadout now colours pet collars correctly +2021-03-28: + CuteMoff: + - balance: Changed Strength Modifier from the default (1.0) too .7 + Hatterhat: + - bugfix: As a heretic, shattering your blade no longer interferes with bluespace. + Putnam3145: + - rscadd: Threat tracking is now universal, rather than dynamic-only + - rscadd: Slaughter demon event now increases weight based on how much blood there + is. + R3dtail: + - rscdel: Removed ichor creates + - balance: Removed ichor crates and adjusted crate rolling appropriately + - balance: Removed the bonespear from the blackmarket uplink, and made EMP grenades + harder to get from the same item. + - rscadd: Added a description to the black market uplink + Shadow-Quill: + - imageadd: Added small versions of the walk icon for all hud styles, except Retro. + dzahlus: + - rscadd: Added radial menu to joy mask for alt reskins + - imageadd: added pensive, angry and flushed sprites to joy mask + keronshb: + - balance: Radioactive microlasers can no longer knock out creatures who are immune + to the effects of radiation. + - bugfix: The radioactive microlaser now calculates the strength of its delay effect + using the intensity setting it had when you initially used it on your victim, + not the intensity setting it currently has. This prevents people from "cheating + out" its intensity 20 effect with only a 2 second delay and a 1 second cooldown. + - balance: Radioactive microlasers no longer contain twice as much metal as normal + health analyzers do. + necromanceranne: + - rscadd: Replaces the useless bullet and laser shields with new Kinetic and Ablative + shields, which do as they advertise. + - rscadd: Replaces the shield implants shield with a hardlight shield that can take + large amounts of brute damage, but disintegrates when shot with disablers. + - bugfix: Fixes Fake Roman Shields being able to be used as normal riot shields. + - bugfix: Fixes nonlethal/non-physical damage types destroying shields. (stamina, + toxins, oxygen, clone, brain) + - bugfix: Fixes tower shields not doing anything, while also giving them intergrity + to match their advertised durability. + - bugfix: Uses additional flags to determine what kind effects work well and what + works poorly against various shields. + timothyteakettle: + - rscadd: ghost cafe residents can now disguise themselves as any mob or object + - bugfix: fixes character preview not updating when selecting the loadout tab + zeroisthebiggay: + - rscadd: triple kitsune tail +2021-03-29: + BlueWildrose: + - bugfix: Fixed being unable to fix suit sensors if damaged at all unless destroyed + completely + YakumoChen: + - rscadd: A less-than-new Syndicate bundle that reminds you of the good old days + when we didn't need all those newfangled traitor items the young-uns get. We + had 6 items in the uplink and we had Monkey in rotation and by god we made do. + qweq12yt: + - rscadd: Added Earmuffs + - rscadd: Added Random Drink + - rscadd: Added Clear PDA + - rscadd: Added Internals Box + - rscadd: Added Meson Goggles + - rscadd: Added Smoke Grenade + silicons: + - bugfix: automated hydroponics system design now works properly diff --git a/html/changelogs/AutoChangeLog-pr-14483.yml b/html/changelogs/AutoChangeLog-pr-14483.yml deleted file mode 100644 index 9dd9dc4296..0000000000 --- a/html/changelogs/AutoChangeLog-pr-14483.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zeroisthebiggay" -delete-after: True -changes: - - balance: "strained muscles isn't free" diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi index 4653d2a5b8..d06f9cf899 100644 Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ diff --git a/icons/mob/clothing/mask_muzzled.dmi b/icons/mob/clothing/mask_muzzled.dmi index 8ca05969bf..807d944172 100644 Binary files a/icons/mob/clothing/mask_muzzled.dmi and b/icons/mob/clothing/mask_muzzled.dmi differ diff --git a/icons/mob/inhands/equipment/shields_lefthand.dmi b/icons/mob/inhands/equipment/shields_lefthand.dmi index 850bbaa043..26658559d4 100644 Binary files a/icons/mob/inhands/equipment/shields_lefthand.dmi and b/icons/mob/inhands/equipment/shields_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/shields_righthand.dmi b/icons/mob/inhands/equipment/shields_righthand.dmi index d4db35b9b2..2bf98e4aa4 100644 Binary files a/icons/mob/inhands/equipment/shields_righthand.dmi and b/icons/mob/inhands/equipment/shields_righthand.dmi differ diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi index aa6d38ad07..07000f43aa 100644 Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi index 01f77ca8c9..cf07bbba91 100644 Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 26784cc796..9f1c0cbd2a 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi index d23e48b4f7..88c7e848dc 100644 Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ diff --git a/icons/obj/shields.dmi b/icons/obj/shields.dmi index c8b1110e1a..23033c505a 100644 Binary files a/icons/obj/shields.dmi and b/icons/obj/shields.dmi differ diff --git a/modular_citadel/code/modules/client/loadout/neck.dm b/modular_citadel/code/modules/client/loadout/neck.dm index 7c9bafc86d..6be13b75d9 100644 --- a/modular_citadel/code/modules/client/loadout/neck.dm +++ b/modular_citadel/code/modules/client/loadout/neck.dm @@ -21,6 +21,8 @@ /datum/gear/neck/collar name = "Collar" path = /obj/item/clothing/neck/petcollar + loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC + loadout_initial_colors = list("#00BBBB") /datum/gear/neck/leathercollar name = "Leather collar" diff --git a/modular_citadel/icons/mob/mam_tails.dmi b/modular_citadel/icons/mob/mam_tails.dmi index 7073328655..5e5a87c199 100644 Binary files a/modular_citadel/icons/mob/mam_tails.dmi and b/modular_citadel/icons/mob/mam_tails.dmi differ diff --git a/modular_citadel/icons/ui/screen_clockwork.dmi b/modular_citadel/icons/ui/screen_clockwork.dmi index 82fd91026b..6e7a94334d 100644 Binary files a/modular_citadel/icons/ui/screen_clockwork.dmi and b/modular_citadel/icons/ui/screen_clockwork.dmi differ diff --git a/modular_citadel/icons/ui/screen_midnight.dmi b/modular_citadel/icons/ui/screen_midnight.dmi index 8990650347..2367d0b9d5 100644 Binary files a/modular_citadel/icons/ui/screen_midnight.dmi and b/modular_citadel/icons/ui/screen_midnight.dmi differ diff --git a/modular_citadel/icons/ui/screen_operative.dmi b/modular_citadel/icons/ui/screen_operative.dmi index 9a784fb14a..5e8abb5431 100644 Binary files a/modular_citadel/icons/ui/screen_operative.dmi and b/modular_citadel/icons/ui/screen_operative.dmi differ diff --git a/modular_citadel/icons/ui/screen_plasmafire.dmi b/modular_citadel/icons/ui/screen_plasmafire.dmi index 9a546cad6e..d251e09c04 100644 Binary files a/modular_citadel/icons/ui/screen_plasmafire.dmi and b/modular_citadel/icons/ui/screen_plasmafire.dmi differ diff --git a/modular_citadel/icons/ui/screen_slimecore.dmi b/modular_citadel/icons/ui/screen_slimecore.dmi index 22f97207df..3c086d7f19 100644 Binary files a/modular_citadel/icons/ui/screen_slimecore.dmi and b/modular_citadel/icons/ui/screen_slimecore.dmi differ diff --git a/strings/tips.txt b/strings/tips.txt index 68d1cbe57a..ead853263b 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -90,7 +90,7 @@ As the Chief Engineer, you can rename areas or create entirely new ones using yo As the Chief Engineer, your hardsuit is significantly better than everybody else's. It has the best features of both engineering and atmospherics hardsuits - boasting nigh-invulnerability to radiation and all atmospheric conditions. As the Chief Engineer, you can spy on and even forge PDA communications with the message monitor console! The key is in your office. As the Chief Engineer, your locker contains a jetpack upgrade that can be attached to hardsuits. -As the Chief Engineer, the power flow control console in your office will show you APC infos and lets you control them remotely. +As the Chief Engineer, the power flow control console in your office will show you APC infos and lets you control them remotely. As an Engineer, the supermatter shard is an extremely dangerous piece of equipment: touching it will disintegrate you. As an Engineer, you can electrify grilles by placing wire "nodes" beneath them: the big seemingly unconnected bulges from a half completed wiring job. As an Engineer, return to Engineering once in a while to check on the engine and SMES cells. It's always a good idea to make sure containment isn't compromised. @@ -112,7 +112,7 @@ As an Atmospheric Technician, your backpack firefighter tank can launch resin. T As an Atmospheric Technician, your ATMOS holofan projectors can blocks gases and heat while allowing objects to pass through. With it, you can quickly contain gas spills, fires and hull breaches. Or, use it to create a plasmaman friendly lounge. As an Atmospheric Technician, burning a plasma/oxygen mix inside the incinerator will not only produce power, but also gases such as tritium and water vapor. As an Atmospheric Technician, you can change the layer of a pipe by clicking with it on a wrenched pipe or other atmos component of the desired layer. -As an Atmospheric Technician, you can take a few cans worth of N2/N2O and cool it down at local freezers. This is a good idea when dealing with (or preparing for) a supermatter meltdown. +As an Atmospheric Technician, you can take a few cans worth of N2/N2O and cool it down at local freezers. This is a good idea when dealing with (or preparing for) a supermatter meltdown. As the Head of Security, you are expected to coordinate your security force to handle any threat that comes to the station. Sometimes it means making use of the armory to handle a blob, sometimes it means being ruthless during a revolution or cult. As the Head of Security, you can call for executions or forced cyborgization, but may require the Captain's approval. As the Head of Security, don't let the power go to your head. You may have high access, great equipment, and a miniature army at your side, but being a terrible person without a good reason is grounds for banning. @@ -121,14 +121,14 @@ As the Warden, keep a close eye on the armory at all times, as it is a favored s As the Warden, if a prisoner's crimes are heinous enough you can put them in permabrig or the gulag. Make sure to check on them once in a while! As the Warden, never underestimate the power of tech slugs! Scattershot fires a cone of weaker lasers with little damage fall off, Ion slugs fires EMPs that only effect the tiles they hit, and Pulse slugs fire a singular laser that can one-hit almost any wall! As the Warden, you can use a surgical saw on riot shotguns to shorten the barrel, making them able to fit in your backpack. Make sure to empty them prior lest you blast yourself in the face! -As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals. +As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals. As the Warden, you can use handcuffs on orange prisoner shoes to turn them into cuffed shoes, forcing prisoners to walk and potentially thwarting an escape. As the Warden, tracker implants can be used on crewmembers. Doing this will let you track their person even without suit sensors and even instantly teleport to them at the local teleporter, although the implant will biodegrade after 5 minutes if its holder ever expires. As the Warden, cryostasis shotgun darts hold 10u of chemicals that will not react until it hits someone. As the Warden, chemical implants can be loaded with a cocktail of healing or combat chems, perfect for the HoS or other security officers to make use of in a pinch. Be sure to keep a eye on them though, as they cannot be injected without the prisoner management console! EMPs or starvation might lead to the chemical implant going off preemptively. As the Warden, tracker implants can be used on your security officers. Doing this will let you be able to message them when telecomms are out, or when you suspect comms are compromised. This is also good against rogue AIs as the prisoner tracker doesn't leave logs or alarms for the AI. As a Security Officer, remember that correlation does not equal causation. Someone may have just been at the wrong place at the wrong time! -As a Security Officer, remember that your belt can hold more than one stun baton. +As a Security Officer, remember that your belt can hold more than one stun baton. As a Security Officer, remember harm beating someone in the head with a blunt object can deconvert them form a being a revolutionary! This sadly doesn't work against either cult, nor does this protect them from getting reconverted unlike a mindshield implant. As a Security Officer, remember that you can attach a seclite to your taser or your helmet! As a Security Officer, communicate and coordinate with your fellow officers using the security channel (:s) to avoid confusion. @@ -283,7 +283,7 @@ As a Ghost, you can double click on just about anything to follow it. Or just wa As a Ghost, there's a button in the OOC tab labeled Observe, it lets you see through someone's eyes as if you were the one who's playing them. As a Devil, you gain power for every three souls you control, however you also become more obvious. As a Devil, as long as you control at least one other soul, you will automatically resurrect, as long as a banishment ritual is not performed. -At which time a Devil's nameth is spake on the tongue of man, the Devil may appeareth. +At which time a Devil's nameth is spake on the tongue of man, the Devil may appeareth. You can swap floor tiles by holding a crowbar in one hand and a stack of tiles in the other. When hacking doors, cutting and mending a "test light wire" will restore power to the door. When crafting most items, you can either manually combine parts or use the crafting menu. @@ -301,3 +301,5 @@ Being out of combat mode makes makes you deal less damage to people and objects Resting makes you deal less damage to people and objects when attacking. This stacks with the penalty incurred by being out of combat mode. You do not regenerate as much stamina while in combat mode. Resting (being on the ground) makes you regenerate stamina faster. Keybinds can be reassigned in character setup on the keybindings tab. This is extremely useful, especially if you know how to use independent binds. +If your suit sensors have been shorted out, you can use cable coil to fix them by using the coil on your suit. Your suit needs to be in proper condition, however. +Most clothing when damaged can be repaired using cloth, but there may be some clothes out there that will require different stacks of materials. diff --git a/tgstation.dme b/tgstation.dme index 84f80d6240..f59457ed2f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -303,6 +303,7 @@ #include "code\controllers\configuration\entries\stamina_combat.dm" #include "code\controllers\subsystem\achievements.dm" #include "code\controllers\subsystem\acid.dm" +#include "code\controllers\subsystem\activity.dm" #include "code\controllers\subsystem\adjacent_air.dm" #include "code\controllers\subsystem\air.dm" #include "code\controllers\subsystem\air_turfs.dm" diff --git a/tools/WebhookProcessor/github_webhook_processor.php b/tools/WebhookProcessor/github_webhook_processor.php index b4609c3a03..89c6729813 100644 --- a/tools/WebhookProcessor/github_webhook_processor.php +++ b/tools/WebhookProcessor/github_webhook_processor.php @@ -323,12 +323,14 @@ function handle_pr($payload) { set_labels($payload, $labels, $remove); if($no_changelog) check_dismiss_changelog_review($payload); + /* if(get_pr_code_friendliness($payload) <= 0){ $balances = pr_balances(); $author = $payload['pull_request']['user']['login']; if(isset($balances[$author]) && $balances[$author] < 0 && !is_maintainer($payload, $author)) create_comment($payload, 'You currently have a negative Fix/Feature pull request delta of ' . $balances[$author] . '. Maintainers may close this PR at will. Fixing issues or improving the codebase will improve this score.'); } + */ break; case 'edited': check_dismiss_changelog_review($payload); diff --git a/tools/requirements.txt b/tools/requirements.txt index 20f350ca46..3cbaf81f5b 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -3,5 +3,5 @@ bidict==0.13.1 Pillow==8.1.1 # changelogs -PyYaml==5.3.1 +PyYaml==5.4 beautifulsoup4==4.9.3