From 68577766c0f6212e8564eb3b2e0766cf4ded1304 Mon Sep 17 00:00:00 2001 From: tool mind <106038874+toolmind@users.noreply.github.com> Date: Wed, 28 Jun 2023 10:24:50 -0500 Subject: [PATCH 01/49] Big Red Liaison Survivor (#3746) # About the pull request Adds a Corporate Liaison survivor to Solaris Ridge. Tested it, was able to spawn in and select it via the role category selection thing. # Explain why it's good for the game more options for roleplay are good, the map didn't have a survivor for the corporate category, plus it makes sense to have one because of the map's lore + the new liaison drip gets more use # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: IowaPotatoFarmer add: Solaris Ridge now has a Corporate Liaison survivor. /:cl: --- code/modules/gear_presets/survivors.dm | 14 ++++++++++++++ maps/bigredv2.json | 1 + 2 files changed, 15 insertions(+) diff --git a/code/modules/gear_presets/survivors.dm b/code/modules/gear_presets/survivors.dm index 42d5ec0915bb..97b974b8a5ec 100644 --- a/code/modules/gear_presets/survivors.dm +++ b/code/modules/gear_presets/survivors.dm @@ -346,6 +346,20 @@ ..() +/datum/equipment_preset/survivor/corporate/solaris + name = "Survivor - Solaris Ridge Corporate Liaison" + assignment = "Solaris Ridge Corporate Liaison" + +/datum/equipment_preset/survivor/corporate/solaris/load_gear(mob/living/carbon/human/new_human) + new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/outing/red(new_human), WEAR_BODY) + if(new_human.disabilities & NEARSIGHTED) + new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/prescription(new_human), WEAR_EYES) + else + new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses(new_human), WEAR_EYES) + new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + + ..() + // ----- Security Survivor /datum/equipment_preset/survivor/security diff --git a/maps/bigredv2.json b/maps/bigredv2.json index ecb2e1472c57..0a6db01cd498 100644 --- a/maps/bigredv2.json +++ b/maps/bigredv2.json @@ -12,6 +12,7 @@ "/datum/equipment_preset/survivor/trucker/solaris", "/datum/equipment_preset/survivor/security/solaris", "/datum/equipment_preset/survivor/colonial_marshal/solaris", + "/datum/equipment_preset/survivor/corporate/solaris", "/datum/equipment_preset/survivor/clf", "/datum/equipment_preset/survivor/civilian" ], From ef627f7c9d4228197d17a2365bb843e9070d0ce6 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Wed, 28 Jun 2023 16:38:16 +0100 Subject: [PATCH 02/49] Automatic changelog for PR #3746 [ci skip] --- html/changelogs/AutoChangeLog-pr-3746.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3746.yml diff --git a/html/changelogs/AutoChangeLog-pr-3746.yml b/html/changelogs/AutoChangeLog-pr-3746.yml new file mode 100644 index 000000000000..48b25b9efb1a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3746.yml @@ -0,0 +1,4 @@ +author: "IowaPotatoFarmer" +delete-after: True +changes: + - rscadd: "Solaris Ridge now has a Corporate Liaison survivor." \ No newline at end of file From 217829c39e8e32dfb58adf68b11568c2cf3d5c0d Mon Sep 17 00:00:00 2001 From: Diegoflores31 <47069269+Diegoflores31@users.noreply.github.com> Date: Wed, 28 Jun 2023 16:03:45 -0500 Subject: [PATCH 03/49] Reduces the Burst timer from 10 minutes to 7.5 minutes (#3748) # About the pull request Reduces the Burst timer from 10 minutes to 7.5 minutes # Explain why it's good for the game Being Hugged is something that should be a life threat situation . currently you can see most of marines getting hugged and not even going back into the almayer because of the extremely long time they have to get back , combined with stasis bag being hugged is as most a minor anoyance for marines instead of a game ending threat. PD Future implementation : a medicine made by chemistry that makes larva go on stasis winout needing the bag. ( like super peri) NOTE : this also affects HIVE burst timer . reducing it to 5 minutes from 6.6 minutes but it can be reverted if it proves to be too quick. # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: balance: reduced Larva Burst time from 10 minutes to 7.5 minutes refactor: changed 1 letter vars. /:cl: --- .../mob/living/carbon/xenomorph/Embryo.dm | 104 +++++++++--------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/Embryo.dm b/code/modules/mob/living/carbon/xenomorph/Embryo.dm index 29779480f143..d3c2b725d7ef 100644 --- a/code/modules/mob/living/carbon/xenomorph/Embryo.dm +++ b/code/modules/mob/living/carbon/xenomorph/Embryo.dm @@ -22,8 +22,8 @@ affected_mob.status_flags |= XENO_HOST START_PROCESSING(SSobj, src) if(iscarbon(affected_mob)) - var/mob/living/carbon/C = affected_mob - C.med_hud_set_status() + var/mob/living/carbon/affected_carbon = affected_mob + affected_carbon.med_hud_set_status() else return INITIALIZE_HINT_QDEL @@ -31,8 +31,8 @@ if(affected_mob) affected_mob.status_flags &= ~(XENO_HOST) if(iscarbon(affected_mob)) - var/mob/living/carbon/C = affected_mob - C.med_hud_set_status() + var/mob/living/carbon/affected_carbon = affected_mob + affected_carbon.med_hud_set_status() STOP_PROCESSING(SSobj, src) affected_mob = null GLOB.player_embryo_list -= src @@ -48,24 +48,24 @@ affected_mob.status_flags &= ~(XENO_HOST) STOP_PROCESSING(SSobj, src) if(iscarbon(affected_mob)) - var/mob/living/carbon/C = affected_mob - C.med_hud_set_status() + var/mob/living/carbon/affected_carbon = affected_mob + affected_carbon.med_hud_set_status() affected_mob = null return FALSE if(affected_mob.stat == DEAD) if(ishuman(affected_mob)) - var/mob/living/carbon/human/H = affected_mob - if(world.time > H.timeofdeath + H.revive_grace_period) //Can't be defibbed. - var/mob/living/carbon/xenomorph/larva/L = locate() in affected_mob - if(L) - L.chest_burst(affected_mob) + var/mob/living/carbon/human/affected_human = affected_mob + if(world.time > affected_human.timeofdeath + affected_human.revive_grace_period) //Can't be defibbed. + var/mob/living/carbon/xenomorph/larva/larva_embryo = locate() in affected_mob + if(larva_embryo) + larva_embryo.chest_burst(affected_mob) qdel(src) return FALSE else - var/mob/living/carbon/xenomorph/larva/L = locate() in affected_mob - if(L) - L.chest_burst(affected_mob) + var/mob/living/carbon/xenomorph/larva/larva_embryo = locate() in affected_mob + if(larva_embryo) + larva_embryo.chest_burst(affected_mob) STOP_PROCESSING(SSobj, src) return FALSE @@ -89,12 +89,12 @@ if(stage < 5) counter += 1 * hive.larva_gestation_multiplier - if(stage < 5 && counter >= 120) + if(stage < 5 && counter >= 90) counter = 0 stage++ if(iscarbon(affected_mob)) - var/mob/living/carbon/C = affected_mob - C.med_hud_set_status() + var/mob/living/carbon/affected_carbon = affected_mob + affected_carbon.med_hud_set_status() switch(stage) if(2) @@ -132,9 +132,9 @@ if(6) larva_autoburst_countdown-- if(!larva_autoburst_countdown) - var/mob/living/carbon/xenomorph/larva/L = locate() in affected_mob - if(L) - L.chest_burst(affected_mob) + var/mob/living/carbon/xenomorph/larva/larva_embryo = locate() in affected_mob + if(larva_embryo) + larva_embryo.chest_burst(affected_mob) //We look for a candidate. If found, we spawn the candidate as a larva //Order of priority is bursted individual (if xeno is enabled), then random candidate, and then it's up for grabs and spawns braindead @@ -256,36 +256,36 @@ victim.spawn_gibs() - for(var/mob/living/carbon/xenomorph/larva/L in victim) - var/datum/hive_status/hive = GLOB.hive_datum[L.hivenumber] - L.forceMove(get_turf(victim)) //moved to the turf directly so we don't get stuck inside a cryopod or another mob container. - playsound(L, pick('sound/voice/alien_chestburst.ogg','sound/voice/alien_chestburst2.ogg'), 25) + for(var/mob/living/carbon/xenomorph/larva/larva_embryo in victim) + var/datum/hive_status/hive = GLOB.hive_datum[larva_embryo.hivenumber] + larva_embryo.forceMove(get_turf(victim)) //moved to the turf directly so we don't get stuck inside a cryopod or another mob container. + playsound(larva_embryo, pick('sound/voice/alien_chestburst.ogg','sound/voice/alien_chestburst2.ogg'), 25) - if(L.client) - L.set_lighting_alpha_from_prefs(L.client) + if(larva_embryo.client) + larva_embryo.set_lighting_alpha_from_prefs(larva_embryo.client) - L.attack_log += "\[[time_stamp()]\] chestbursted from [key_name(victim)]" - victim.attack_log += "\[[time_stamp()]\] Was chestbursted, larva was [key_name(L)]" + larva_embryo.attack_log += "\[[time_stamp()]\] chestbursted from [key_name(victim)]" + victim.attack_log += "\[[time_stamp()]\] Was chestbursted, larva was [key_name(larva_embryo)]" if(burstcount) - step(L, pick(cardinal)) + step(larva_embryo, pick(cardinal)) if(round_statistics) round_statistics.total_larva_burst++ burstcount++ - if(!L.ckey && L.burrowable && loc && is_ground_level(loc.z) && (locate(/obj/structure/bed/nest) in loc) && hive.living_xeno_queen && hive.living_xeno_queen.z == loc.z) - L.visible_message(SPAN_XENODANGER("[L] quickly burrows into the ground.")) - if(round_statistics && !L.statistic_exempt) + if(!larva_embryo.ckey && larva_embryo.burrowable && loc && is_ground_level(loc.z) && (locate(/obj/structure/bed/nest) in loc) && hive.living_xeno_queen && hive.living_xeno_queen.z == loc.z) + larva_embryo.visible_message(SPAN_XENODANGER("[larva_embryo] quickly burrows into the ground.")) + if(round_statistics && !larva_embryo.statistic_exempt) round_statistics.track_new_participant(faction, -1) // keep stats sane hive.stored_larva++ hive.hive_ui.update_burrowed_larva() - qdel(L) + qdel(larva_embryo) if(!victim.first_xeno) - to_chat(L, SPAN_XENOHIGHDANGER("The Queen's will overwhelms your instincts...")) - to_chat(L, SPAN_XENOHIGHDANGER("\"[hive.hive_orders]\"")) - log_attack("[key_name(victim)] chestbursted, the larva was [key_name(L)].") //this is so that admins are not spammed with los logs + to_chat(larva_embryo, SPAN_XENOHIGHDANGER("The Queen's will overwhelms your instincts...")) + to_chat(larva_embryo, SPAN_XENOHIGHDANGER("\"[hive.hive_orders]\"")) + log_attack("[key_name(victim)] chestbursted, the larva was [key_name(larva_embryo)].") //this is so that admins are not spammed with los logs for(var/obj/item/alien_embryo/AE in victim) qdel(AE) @@ -295,31 +295,31 @@ victim.gib(cause) else if(ishuman(victim)) - var/mob/living/carbon/human/H = victim - H.last_damage_data = cause + var/mob/living/carbon/human/victim_human = victim + victim_human.last_damage_data = cause var/datum/internal_organ/O var/i for(i in list("heart","lungs")) //This removes (and later garbage collects) both organs. No heart means instant death. - O = H.internal_organs_by_name[i] - H.internal_organs_by_name -= i - H.internal_organs -= O + O = victim_human.internal_organs_by_name[i] + victim_human.internal_organs_by_name -= i + victim_human.internal_organs -= O victim.death(cause) // Certain species were still surviving bursting (predators), DEFINITELY kill them this time. victim.chestburst = 2 victim.update_burst() // Squeeze thru dense objects as a larva, as airlocks -/mob/living/carbon/xenomorph/larva/proc/scuttle(obj/structure/S) +/mob/living/carbon/xenomorph/larva/proc/scuttle(obj/structure/target) var/move_dir = get_dir(src, loc) - for(var/atom/movable/AM in get_turf(S)) - if(AM != S && AM.density && AM.BlockedPassDirs(src, move_dir)) - to_chat(src, SPAN_WARNING("\The [AM] prevents you from squeezing under \the [S]!")) + for(var/atom/movable/AM in get_turf(target)) + if(AM != target && AM.density && AM.BlockedPassDirs(src, move_dir)) + to_chat(src, SPAN_WARNING("\The [AM] prevents you from squeezing under \the [target]!")) return // Is it an airlock? - if(istype(S, /obj/structure/machinery/door/airlock)) - var/obj/structure/machinery/door/airlock/A = S - if(A.locked || A.welded) //Can't pass through airlocks that have been bolted down or welded - to_chat(src, SPAN_WARNING("\The [A] is locked down tight. You can't squeeze underneath!")) + if(istype(target, /obj/structure/machinery/door/airlock)) + var/obj/structure/machinery/door/airlock/selected_airlock = target + if(selected_airlock.locked || selected_airlock.welded) //Can't pass through airlocks that have been bolted down or welded + to_chat(src, SPAN_WARNING("\The [selected_airlock] is locked down tight. You can't squeeze underneath!")) return - visible_message(SPAN_WARNING("\The [src] scuttles underneath \the [S]!"), \ - SPAN_WARNING("You squeeze and scuttle underneath \the [S]."), null, 5) - forceMove(S.loc) + visible_message(SPAN_WARNING("\The [src] scuttles underneath \the [target]!"), \ + SPAN_WARNING("You squeeze and scuttle underneath \the [target]."), null, 5) + forceMove(target.loc) From 82cc0a16eba63c08e87cf94a9e446bbdc4539267 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Wed, 28 Jun 2023 22:13:29 +0100 Subject: [PATCH 04/49] Automatic changelog for PR #3748 [ci skip] --- html/changelogs/AutoChangeLog-pr-3748.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3748.yml diff --git a/html/changelogs/AutoChangeLog-pr-3748.yml b/html/changelogs/AutoChangeLog-pr-3748.yml new file mode 100644 index 000000000000..74c02e602003 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3748.yml @@ -0,0 +1,5 @@ +author: "Diegoflores31" +delete-after: True +changes: + - balance: "reduced Larva Burst time from 10 minutes to 7.5 minutes" + - refactor: "changed 1 letter vars." \ No newline at end of file From c3e8e59bb10fb2178b9484ecc1b5956fea2e2659 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 29 Jun 2023 01:43:15 +0000 Subject: [PATCH 05/49] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-3298.yml | 15 -------- html/changelogs/AutoChangeLog-pr-3666.yml | 4 -- html/changelogs/AutoChangeLog-pr-3717.yml | 4 -- html/changelogs/AutoChangeLog-pr-3718.yml | 4 -- html/changelogs/AutoChangeLog-pr-3723.yml | 4 -- html/changelogs/AutoChangeLog-pr-3730.yml | 4 -- html/changelogs/AutoChangeLog-pr-3731.yml | 4 -- html/changelogs/AutoChangeLog-pr-3736.yml | 4 -- html/changelogs/AutoChangeLog-pr-3742.yml | 6 --- html/changelogs/AutoChangeLog-pr-3743.yml | 4 -- html/changelogs/AutoChangeLog-pr-3746.yml | 4 -- html/changelogs/AutoChangeLog-pr-3748.yml | 5 --- html/changelogs/archive/2023-06.yml | 47 +++++++++++++++++++++++ 13 files changed, 47 insertions(+), 62 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-3298.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3666.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3717.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3718.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3723.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3730.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3731.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3736.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3742.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3743.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3746.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3748.yml diff --git a/html/changelogs/AutoChangeLog-pr-3298.yml b/html/changelogs/AutoChangeLog-pr-3298.yml deleted file mode 100644 index 0a75d2215043..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3298.yml +++ /dev/null @@ -1,15 +0,0 @@ -author: "realforest2001" -delete-after: True -changes: - - rscadd: "Added an admin button for an ARES bioscan. Slightly refactored how Bioscans trigger for marines, relying on an ARES processor." - - rscadd: "Added individual proccessors for ARES systems. These are WIP and will eventually have damage and repair interactions." - - rscadd: "Added an ARES interaction console in the AI Core room, which holds logs for most ARES functions." - - rscadd: "Added the ability for ARES console to call ERT or Distress." - - rscadd: "Added motion triggers in ARES core and shipside comms that send alerts over Apollo." - - rscadd: "Added a 1to1 conversation feature between ARES and users of the interface console." - - rscadd: "Added preset open versions of blended poddoors." - - rscadd: "Added a console for directing Working Joes. This is largely WIP for future PR(s)." - - rscadd: "Added subtypes of air pipes that don't explode on hijack, used these in ARES core." - - maptweak: "Remodelled ARES Core onto a fake-z, and added the new processors." - - bugfix: "door_control buttons now respect being indestructable when processing explosions." - - maptweak: "Fixed the M39s overflowing in brig armory due to use of landmarks." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3666.yml b/html/changelogs/AutoChangeLog-pr-3666.yml deleted file mode 100644 index d7d8860c237e..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3666.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Morrow" -delete-after: True -changes: - - balance: "Xenos no longer can pull dead xenos" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3717.yml b/html/changelogs/AutoChangeLog-pr-3717.yml deleted file mode 100644 index 6d6327ea63a7..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3717.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Drathek" -delete-after: True -changes: - - bugfix: "Fixed the crashsite offset for a hijack shuttle that gets deterred by the MGAD System" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3718.yml b/html/changelogs/AutoChangeLog-pr-3718.yml deleted file mode 100644 index 41f5322a2493..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3718.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheGamerdk" -delete-after: True -changes: - - balance: "Queen boosted building no longer has 2 second cooldown when far from hive" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3723.yml b/html/changelogs/AutoChangeLog-pr-3723.yml deleted file mode 100644 index 987b7eeec708..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3723.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheGamerdk" -delete-after: True -changes: - - bugfix: "Communications intel objective now actually works" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3730.yml b/html/changelogs/AutoChangeLog-pr-3730.yml deleted file mode 100644 index 9ae18e6bc788..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3730.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "fira" -delete-after: True -changes: - - bugfix: "Fixed a MC crash related to NPC huggers rebounding logic." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3731.yml b/html/changelogs/AutoChangeLog-pr-3731.yml deleted file mode 100644 index 21fd76664d2b..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3731.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "blackdragonTOW" -delete-after: True -changes: - - maptweak: "Added a small light to unlit rooms." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3736.yml b/html/changelogs/AutoChangeLog-pr-3736.yml deleted file mode 100644 index c1eba0beabfd..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3736.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Morrow" -delete-after: True -changes: - - rscdel: "Removed toxin mags on shivas" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3742.yml b/html/changelogs/AutoChangeLog-pr-3742.yml deleted file mode 100644 index 7319ac52f8d9..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3742.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "SpartanBobby" -delete-after: True -changes: - - maptweak: "Minor decal changes to LV522" - - maptweak: "Buffed sec armory on LV522" - - maptweak: "LV522 Breaching charge moved to the PROP APC made UNACIDABLE" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3743.yml b/html/changelogs/AutoChangeLog-pr-3743.yml deleted file mode 100644 index 084e74fc2c2e..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3743.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Katskan" -delete-after: True -changes: - - balance: "Removed G8A storage from various snow suits and parkas" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3746.yml b/html/changelogs/AutoChangeLog-pr-3746.yml deleted file mode 100644 index 48b25b9efb1a..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3746.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "IowaPotatoFarmer" -delete-after: True -changes: - - rscadd: "Solaris Ridge now has a Corporate Liaison survivor." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3748.yml b/html/changelogs/AutoChangeLog-pr-3748.yml deleted file mode 100644 index 74c02e602003..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3748.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Diegoflores31" -delete-after: True -changes: - - balance: "reduced Larva Burst time from 10 minutes to 7.5 minutes" - - refactor: "changed 1 letter vars." \ No newline at end of file diff --git a/html/changelogs/archive/2023-06.yml b/html/changelogs/archive/2023-06.yml index 71aeb035f4b8..b1040b8044de 100644 --- a/html/changelogs/archive/2023-06.yml +++ b/html/changelogs/archive/2023-06.yml @@ -383,3 +383,50 @@ - balance: explosive barricade upgrade provides strong protection against brute-based projectiles (50%) - balance: explosive barricade upgrade provides strong protection against fire (50%) +2023-06-29: + Diegoflores31: + - balance: reduced Larva Burst time from 10 minutes to 7.5 minutes + - refactor: changed 1 letter vars. + Drathek: + - bugfix: Fixed the crashsite offset for a hijack shuttle that gets deterred by + the MGAD System + IowaPotatoFarmer: + - rscadd: Solaris Ridge now has a Corporate Liaison survivor. + Katskan: + - balance: Removed G8A storage from various snow suits and parkas + Morrow: + - balance: Xenos no longer can pull dead xenos + - rscdel: Removed toxin mags on shivas + SpartanBobby: + - maptweak: Minor decal changes to LV522 + - maptweak: Buffed sec armory on LV522 + - maptweak: LV522 Breaching charge moved to the PROP APC made UNACIDABLE + TheGamerdk: + - bugfix: Communications intel objective now actually works + - balance: Queen boosted building no longer has 2 second cooldown when far from + hive + blackdragonTOW: + - maptweak: Added a small light to unlit rooms. + fira: + - bugfix: Fixed a MC crash related to NPC huggers rebounding logic. + realforest2001: + - rscadd: Added an admin button for an ARES bioscan. Slightly refactored how Bioscans + trigger for marines, relying on an ARES processor. + - rscadd: Added individual proccessors for ARES systems. These are WIP and will + eventually have damage and repair interactions. + - rscadd: Added an ARES interaction console in the AI Core room, which holds logs + for most ARES functions. + - rscadd: Added the ability for ARES console to call ERT or Distress. + - rscadd: Added motion triggers in ARES core and shipside comms that send alerts + over Apollo. + - rscadd: Added a 1to1 conversation feature between ARES and users of the interface + console. + - rscadd: Added preset open versions of blended poddoors. + - rscadd: Added a console for directing Working Joes. This is largely WIP for future + PR(s). + - rscadd: Added subtypes of air pipes that don't explode on hijack, used these in + ARES core. + - maptweak: Remodelled ARES Core onto a fake-z, and added the new processors. + - bugfix: door_control buttons now respect being indestructable when processing + explosions. + - maptweak: Fixed the M39s overflowing in brig armory due to use of landmarks. From 4b7aacdb2e4bf7023a941c8f5fef7f7a238c5ec5 Mon Sep 17 00:00:00 2001 From: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com> Date: Thu, 29 Jun 2023 04:55:04 +0200 Subject: [PATCH 06/49] Fixes being unable to re-enter your body when you're unnested (#3747) # About the pull request Turns out the parent call of unbuckle() calls afterbuckle() which deletes the nest and clears ghost_of_buckled_mob, which means it can't set your ghost to can_reenter_corpse = TRUE # Explain why it's good for the game Bugs bad # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: fix: You can now re-enter your body when unnested, marine mains, rejoice! /:cl: --- .../objects/structures/stool_bed_chair_nest/xeno_nest.dm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm index e306b894b021..37d46cbe6d5d 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/xeno_nest.dm @@ -289,11 +289,12 @@ if(buckled_human.stat == DEAD ) buckled_mob_density = FALSE - . = ..() - var/mob/dead/observer/G = ghost_of_buckled_mob var/datum/mind/M = G?.mind ghost_of_buckled_mob = null + + . = ..() //Very important that this comes after, since it deletes the nest and clears ghost_of_buckled_mob + if(!istype(buckled_human) || !istype(G) || !istype(M) || buckled_human.undefibbable || buckled_human.mind || M.original != buckled_human || buckled_human.chestburst) return // Zealous checking as most is handled by ghost code to_chat(G, FONT_SIZE_HUGE(SPAN_DANGER("You have been freed from your nest and may go back to your body! (Look for 'Re-enter Corpse' in Ghost verbs, or click here!)"))) From 46a6d7658dc87d88e1fec0bfd73dc3f856e312ec Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Thu, 29 Jun 2023 04:04:49 +0100 Subject: [PATCH 07/49] Automatic changelog for PR #3747 [ci skip] --- html/changelogs/AutoChangeLog-pr-3747.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3747.yml diff --git a/html/changelogs/AutoChangeLog-pr-3747.yml b/html/changelogs/AutoChangeLog-pr-3747.yml new file mode 100644 index 000000000000..c20e68184c69 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3747.yml @@ -0,0 +1,4 @@ +author: "TheGamerdk" +delete-after: True +changes: + - bugfix: "You can now re-enter your body when unnested, marine mains, rejoice!" \ No newline at end of file From 5eba560f8c137cdcf2dec1f829337917d4968d97 Mon Sep 17 00:00:00 2001 From: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com> Date: Thu, 29 Jun 2023 05:18:34 +0200 Subject: [PATCH 08/49] Lurker no longer decloaks if they pounce onto a dead guy. (#3724) # About the pull request Doesn't make sense to lose your cloak for pouncing at a dead guy. They'll still decloak if it's a living guy hiding under a dead guy. (This only happens if your pounce ends on a tile where there's a dead guy) # Explain why it's good for the game Inconsistent at best. Bad # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: fix: Lurkers no longer lose their pounce if they happen to end their pounce on a tile with a dead human /:cl: --- .../abilities/lurker/lurker_abilities.dm | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm index e0a29a034029..0c9358119def 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm @@ -14,20 +14,21 @@ can_be_shield_blocked = TRUE /datum/action/xeno_action/activable/pounce/lurker/additional_effects_always() - var/mob/living/carbon/xenomorph/X = owner - if (!istype(X)) + var/mob/living/carbon/xenomorph/xeno = owner + if (!istype(xeno)) return - - if (X.mutation_type == LURKER_NORMAL) + if (xeno.mutation_type == LURKER_NORMAL) var/found = FALSE - for (var/mob/living/carbon/human/H in get_turf(X)) + for (var/mob/living/carbon/human/human in get_turf(xeno)) + if(human.stat == DEAD) + continue found = TRUE break if (found) - var/datum/action/xeno_action/onclick/lurker_invisibility/LIA = get_xeno_action_by_type(X, /datum/action/xeno_action/onclick/lurker_invisibility) - if (istype(LIA)) - LIA.invisibility_off() + var/datum/action/xeno_action/onclick/lurker_invisibility/lurker_invis = get_xeno_action_by_type(xeno, /datum/action/xeno_action/onclick/lurker_invisibility) + if (istype(lurker_invis)) + lurker_invis.invisibility_off() /datum/action/xeno_action/activable/pounce/lurker/additional_effects(mob/living/L) var/mob/living/carbon/xenomorph/X = owner From 4715802ecf430793fc66c78cc510c5b834344ea7 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Thu, 29 Jun 2023 04:28:55 +0100 Subject: [PATCH 09/49] Automatic changelog for PR #3724 [ci skip] --- html/changelogs/AutoChangeLog-pr-3724.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3724.yml diff --git a/html/changelogs/AutoChangeLog-pr-3724.yml b/html/changelogs/AutoChangeLog-pr-3724.yml new file mode 100644 index 000000000000..031042a976c9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3724.yml @@ -0,0 +1,4 @@ +author: "TheGamerdk" +delete-after: True +changes: + - bugfix: "Lurkers no longer lose their pounce if they happen to end their pounce on a tile with a dead human" \ No newline at end of file From 53d1a3989d3168a22be4be1123aacaa21584ccba Mon Sep 17 00:00:00 2001 From: Drathek <76988376+Drulikar@users.noreply.github.com> Date: Thu, 29 Jun 2023 01:22:54 -0700 Subject: [PATCH 10/49] Port TG#74500: Adds VERB_REF and derivative (#3753) # About the pull request This PR ports another 515 compatibility PR from TGStation: https://github.com/tgstation/tgstation/pull/74500 # Explain why it's good for the game Future proofing. # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: Drathek code: Ported VERB_REF and TYPE_VERB_REF from TG for 515 compatibility /:cl: --- .github/guides/STANDARDS.md | 4 +++- code/_byond_version_compat.dm | 32 +++++++++++++++++++++++++------- code/_onclick/click.dm | 4 ++-- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/.github/guides/STANDARDS.md b/.github/guides/STANDARDS.md index fc764d09c816..c9b988bd07ff 100644 --- a/.github/guides/STANDARDS.md +++ b/.github/guides/STANDARDS.md @@ -126,7 +126,7 @@ While we normally encourage (and in some cases, even require) bringing out of da This is a simple one - as we will eventually move to 515, we will need to ditch this kind of callback. So please don't add any new ones. Make our lives easier. ### PROC_REF Macros - When referencing procs in RegisterSignal, Callback and other procs you should use PROC_REF,TYPE_PROC_REF and GLOBAL_PROC_REF macros. + When referencing procs in RegisterSignal, Callback and other procs you should use PROC_REF, TYPE_PROC_REF and GLOBAL_PROC_REF macros. They ensure compilation fails if the reffered to procs change names or get removed. The macro to be used depends on how the proc you're in relates to the proc you want to use: @@ -168,6 +168,8 @@ This is a simple one - as we will eventually move to 515, we will need to ditch addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(funny)), 100)) ``` + Note that the same rules go for verbs too! We have VERB_REF() and TYPE_VERB_REF() as you need it in these same cases. GLOBAL_VERB_REF() isn't a thing however, as verbs are not global. + ### Signal Handlers All procs that are registered to listen for signals using `RegisterSignal()` must contain at the start of the proc `SIGNAL_HANDLER` eg; diff --git a/code/_byond_version_compat.dm b/code/_byond_version_compat.dm index b5379a3b6d5c..df2f02d383b1 100644 --- a/code/_byond_version_compat.dm +++ b/code/_byond_version_compat.dm @@ -31,19 +31,37 @@ #define LIBCALL call_ext #endif -// So we want to have compile time guarantees these procs exist on local type, unfortunately 515 killed the .proc/procname syntax so we have to use nameof() +// So we want to have compile time guarantees these methods exist on local type, unfortunately 515 killed the .proc/procname and .verb/verbname syntax so we have to use nameof() +// For the record: GLOBAL_VERB_REF would be useless as verbs can't be global. + #if DM_VERSION < 515 -/// Call by name proc reference, checks if the proc exists on this type or as a global proc + +/// Call by name proc references, checks if the proc exists on either this type or as a global proc. #define PROC_REF(X) (.proc/##X) -/// Call by name proc reference, checks if the proc exists on given type or as a global proc +/// Call by name verb references, checks if the verb exists on either this type or as a global verb. +#define VERB_REF(X) (.verb/##X) + +/// Call by name proc reference, checks if the proc exists on either the given type or as a global proc #define TYPE_PROC_REF(TYPE, X) (##TYPE.proc/##X) -/// Call by name proc reference, checks if the proc is existing global proc +/// Call by name verb reference, checks if the verb exists on either the given type or as a global verb +#define TYPE_VERB_REF(TYPE, X) (##TYPE.verb/##X) + +/// Call by name proc reference, checks if the proc is an existing global proc #define GLOBAL_PROC_REF(X) (/proc/##X) + #else -/// Call by name proc reference, checks if the proc exists on this type or as a global proc + +/// Call by name proc references, checks if the proc exists on either this type or as a global proc. #define PROC_REF(X) (nameof(.proc/##X)) -/// Call by name proc reference, checks if the proc exists on given type or as a global proc +/// Call by name verb references, checks if the verb exists on either this type or as a global verb. +#define VERB_REF(X) (nameof(.verb/##X)) + +/// Call by name proc reference, checks if the proc exists on either the given type or as a global proc #define TYPE_PROC_REF(TYPE, X) (nameof(##TYPE.proc/##X)) -/// Call by name proc reference, checks if the proc is existing global proc +/// Call by name verb reference, checks if the verb exists on either the given type or as a global verb +#define TYPE_VERB_REF(TYPE, X) (nameof(##TYPE.verb/##X)) + +/// Call by name proc reference, checks if the proc is an existing global proc #define GLOBAL_PROC_REF(X) (/proc/##X) + #endif diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index affbc28cdd45..df7dd48a1dd1 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -82,7 +82,7 @@ return face_atom(A) - if(mods["middle"]) + if(mods["middle"]) return // Special type of click. if (is_mob_restrained()) @@ -334,7 +334,7 @@ if(prefs.adaptive_zoom) INVOKE_ASYNC(src, PROC_REF(adaptive_zoom)) else if(prefs.auto_fit_viewport) - INVOKE_ASYNC(src, .verb/fit_viewport) + INVOKE_ASYNC(src, VERB_REF(fit_viewport)) /client/proc/get_adaptive_zoom_factor() if(!prefs.adaptive_zoom) From 7841a59b9a7527fd083e739376340e2283aca89b Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Thu, 29 Jun 2023 09:45:13 +0100 Subject: [PATCH 11/49] Automatic changelog for PR #3753 [ci skip] --- html/changelogs/AutoChangeLog-pr-3753.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3753.yml diff --git a/html/changelogs/AutoChangeLog-pr-3753.yml b/html/changelogs/AutoChangeLog-pr-3753.yml new file mode 100644 index 000000000000..7105155792bd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3753.yml @@ -0,0 +1,4 @@ +author: "Drathek" +delete-after: True +changes: + - code_imp: "Ported VERB_REF and TYPE_VERB_REF from TG for 515 compatibility" \ No newline at end of file From 5700c6c7738336f4b11db55298113bd14cdf5f57 Mon Sep 17 00:00:00 2001 From: Drathek <76988376+Drulikar@users.noreply.github.com> Date: Thu, 29 Jun 2023 01:28:30 -0700 Subject: [PATCH 12/49] Fix minimap removeimage proc not checking z level correctly (#3752) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # About the pull request This PR fixes an issue where the removeimage proc in the minimap subsystem didn't get the turf of the target to correctly test what Z level they were added to such as being deleted in a cryopod. (Entering say a cryopod is not considered a onTransitZ trigger despite the z value changing) # Explain why it's good for the game This PR should fix runtimes such as: ``` [2023-06-28 07:08:53.119] runtime error: /list {len = 5}l"istress Signal"Êß@' - proc name: removeimage (/datum/controller/subsystem/minimaps/proc/removeimage) - source file: minimap.dm,266 - usr: null - src: Minimaps (/datum/controller/subsystem/minimaps) - call stack: - Minimaps (/datum/controller/subsystem/minimaps): removeimage(, Leroy Luna (/mob/living/carbon/human)) - /datum/callback (/datum/callback): Invoke() - Minimaps (/datum/controller/subsystem/minimaps): remove marker(Leroy Luna (/mob/living/carbon/human), null, null) - the marine senior command head... (/obj/item/device/radio/headset/almayer/mcom/cdrcom): dropped(Leroy Luna (/mob/living/carbon/human)) - Leroy Luna (/mob/living/carbon/human): u equip(the marine senior command head... (/obj/item/device/radio/headset/almayer/mcom/cdrcom), the hypersleep chamber (/obj/structure/machinery/cryopod/right), null, null) - Leroy Luna (/mob/living/carbon/human): u equip(the marine senior command head... (/obj/item/device/radio/headset/almayer/mcom/cdrcom), the hypersleep chamber (/obj/structure/machinery/cryopod/right), null, null) - Leroy Luna (/mob/living/carbon/human): u equip(the marine senior command head... (/obj/item/device/radio/headset/almayer/mcom/cdrcom), the hypersleep chamber (/obj/structure/machinery/cryopod/right), null, null) - Leroy Luna (/mob/living/carbon/human): drop inv item to loc(the marine senior command head... (/obj/item/device/radio/headset/almayer/mcom/cdrcom), the hypersleep chamber (/obj/structure/machinery/cryopod/right), null, null) - the hypersleep chamber (/obj/structure/machinery/cryopod/right): despawn occupant() - the hypersleep chamber (/obj/structure/machinery/cryopod/right): process() - Machinery (/datum/controller/subsystem/machinery): fire(0) - Machinery (/datum/controller/subsystem/machinery): ignite(0) - Master (/datum/controller/master): RunQueue() - Master (/datum/controller/master): Loop(2) - Master (/datum/controller/master): StartProcessing(0) ``` # Testing Photographs and Procedure
Screenshots & Videos ![cryo](https://github.com/cmss13-devs/cmss13/assets/76988376/9ade906e-cde1-4330-9cd7-cc82ffb938e4)
# Changelog :cl: Drathek fix: Fix runtimes with minimap subsystem not handling targets inside of objects during removal /:cl: --- code/controllers/subsystem/minimap.dm | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/code/controllers/subsystem/minimap.dm b/code/controllers/subsystem/minimap.dm index e365a9b60781..c3b2d36b8177 100644 --- a/code/controllers/subsystem/minimap.dm +++ b/code/controllers/subsystem/minimap.dm @@ -262,8 +262,12 @@ SUBSYSTEM_DEF(minimaps) * removes an image from raw tracked lists, invoked by callback */ /datum/controller/subsystem/minimaps/proc/removeimage(image/blip, atom/target) + var/turf/turf_gotten = get_turf(target) + if(!turf_gotten) + return + var/z_level = turf_gotten.z for(var/flag in GLOB.all_minimap_flags) - minimaps_by_z["[target.z]"].images_raw["[flag]"] -= blip + minimaps_by_z["[z_level]"].images_raw["[flag]"] -= blip blip.UnregisterSignal(target, COMSIG_MOVABLE_MOVED) removal_cbs -= target @@ -391,18 +395,24 @@ SUBSYSTEM_DEF(minimaps) owner.client.screen += map minimap_displayed = !minimap_displayed -/datum/action/minimap/give_to(mob/M) +/datum/action/minimap/give_to(mob/target) . = ..() if(default_overwatch_level) map = SSminimaps.fetch_minimap_object(default_overwatch_level, minimap_flags) else - RegisterSignal(M, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_owner_z_change)) - if(!SSminimaps.minimaps_by_z["[M.z]"] || !SSminimaps.minimaps_by_z["[M.z]"].hud_image) + RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(on_owner_z_change)) + + var/turf/turf_gotten = get_turf(target) + if(!turf_gotten) + return + var/z_level = turf_gotten.z + + if(!SSminimaps.minimaps_by_z["[z_level]"] || !SSminimaps.minimaps_by_z["[z_level]"].hud_image) return - map = SSminimaps.fetch_minimap_object(M.z, minimap_flags) + map = SSminimaps.fetch_minimap_object(z_level, minimap_flags) -/datum/action/minimap/remove_from(mob/M) +/datum/action/minimap/remove_from(mob/target) . = ..() if(minimap_displayed) owner?.client?.screen -= map From 156fa3991385d61d7cfd272889c9d676a9adeb9c Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Thu, 29 Jun 2023 10:00:36 +0100 Subject: [PATCH 13/49] Automatic changelog for PR #3752 [ci skip] --- html/changelogs/AutoChangeLog-pr-3752.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3752.yml diff --git a/html/changelogs/AutoChangeLog-pr-3752.yml b/html/changelogs/AutoChangeLog-pr-3752.yml new file mode 100644 index 000000000000..2890d9c60a41 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3752.yml @@ -0,0 +1,4 @@ +author: "Drathek" +delete-after: True +changes: + - bugfix: "Fix runtimes with minimap subsystem not handling targets inside of objects during removal" \ No newline at end of file From 2e675897fae2d016203e583c1f77ed7477443221 Mon Sep 17 00:00:00 2001 From: Drathek <76988376+Drulikar@users.noreply.github.com> Date: Thu, 29 Jun 2023 01:28:50 -0700 Subject: [PATCH 14/49] Remove dead code for langchat rotations (#3756) # About the pull request This PR removes some unused code as of #671 # Explain why it's good for the game Less work for the server when updating a mob's transform. # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: Drathek code: Removed unnecessary calculations when updating a mob's transform. /:cl: --- code/game/objects/objs.dm | 8 +++----- .../mob/living/carbon/human/update_icons.dm | 18 +++++++----------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 42a3a2f0b9ea..e98e3b527c5f 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -302,11 +302,9 @@ src.add_fingerprint(user) afterbuckle(target) if(buckle_lying) // Make sure buckling to beds/nests etc only turns, and doesn't give a random offset - var/matrix/M = matrix() - var/matrix/L = matrix() //Counterrotation for langchat text. - M.Turn(90) - L.Turn(270) - target.apply_transform(M) + var/matrix/new_matrix = matrix() + new_matrix.Turn(90) + target.apply_transform(new_matrix) return TRUE /obj/proc/send_buckling_message(mob/M, mob/user) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 355f69ca05a9..f74b65c2606d 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -94,23 +94,19 @@ There are several things that need to be remembered: if(lying == lying_prev && !force) return lying_prev = lying - var/matrix/M = matrix() - var/matrix/L = matrix() //Counter-rotation for langchat text. + var/matrix/new_matrix = matrix() if(lying) if(pulledby && pulledby.grab_level >= GRAB_CARRY) - M.Turn(90) - L.Turn(270) + new_matrix.Turn(90) else if(prob(50)) - M.Turn(90) - L.Turn(270) + new_matrix.Turn(90) else - M.Turn(270) - L.Turn(90) - M.Translate(rand(-10,10),rand(-10,10)) - apply_transform(M) + new_matrix.Turn(270) + new_matrix.Translate(rand(-10,10), rand(-10,10)) + apply_transform(new_matrix) else - apply_transform(M) + apply_transform(new_matrix) /mob/living/carbon/human/UpdateDamageIcon() for(var/obj/limb/O in limbs) From a6e8a4d2872dbc564fe75317c66e5309e493423b Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Thu, 29 Jun 2023 10:17:12 +0100 Subject: [PATCH 15/49] Automatic changelog for PR #3756 [ci skip] --- html/changelogs/AutoChangeLog-pr-3756.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3756.yml diff --git a/html/changelogs/AutoChangeLog-pr-3756.yml b/html/changelogs/AutoChangeLog-pr-3756.yml new file mode 100644 index 000000000000..77eb600b40f6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3756.yml @@ -0,0 +1,4 @@ +author: "Drathek" +delete-after: True +changes: + - code_imp: "Removed unnecessary calculations when updating a mob's transform." \ No newline at end of file From 2f1eb92f05dd275a153c0784289d3053c102854d Mon Sep 17 00:00:00 2001 From: morrowwolf Date: Thu, 29 Jun 2023 04:42:37 -0400 Subject: [PATCH 16/49] Removes wrong warden locker (#3751) # About the pull request Removes incorrect warden locker # Explain why it's good for the game This is not supposed to be here. # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: Morrow del: Removed wrong warden locker /:cl: --- maps/map_files/USS_Almayer/USS_Almayer.dmm | 1 - 1 file changed, 1 deletion(-) diff --git a/maps/map_files/USS_Almayer/USS_Almayer.dmm b/maps/map_files/USS_Almayer/USS_Almayer.dmm index 63562239f4dc..b15ee29dd20a 100644 --- a/maps/map_files/USS_Almayer/USS_Almayer.dmm +++ b/maps/map_files/USS_Almayer/USS_Almayer.dmm @@ -56372,7 +56372,6 @@ "pbh" = ( /obj/structure/disposalpipe/segment, /obj/structure/pipes/standard/simple/hidden/supply, -/obj/structure/closet/secure_closet/warden, /obj/structure/machinery/light{ dir = 4 }, From c3ffb3bf41b70f5cfdfad98f0d14be786f56317d Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Thu, 29 Jun 2023 10:30:05 +0100 Subject: [PATCH 17/49] Automatic changelog for PR #3751 [ci skip] --- html/changelogs/AutoChangeLog-pr-3751.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3751.yml diff --git a/html/changelogs/AutoChangeLog-pr-3751.yml b/html/changelogs/AutoChangeLog-pr-3751.yml new file mode 100644 index 000000000000..50c548407f5e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3751.yml @@ -0,0 +1,4 @@ +author: "Morrow" +delete-after: True +changes: + - rscdel: "Removed wrong warden locker" \ No newline at end of file From ae54d1f1de3839c5d261f762bda61946ab3b523a Mon Sep 17 00:00:00 2001 From: fira Date: Thu, 29 Jun 2023 09:44:39 +0100 Subject: [PATCH 18/49] Port /tg/ PR #75835 - Linux 515 fcopy() crash fix (#3525) Details here: https://github.com/tgstation/tgstation/pull/75835 --- code/_byond_version_compat.dm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/code/_byond_version_compat.dm b/code/_byond_version_compat.dm index df2f02d383b1..719d85654b5f 100644 --- a/code/_byond_version_compat.dm +++ b/code/_byond_version_compat.dm @@ -65,3 +65,15 @@ #define GLOBAL_PROC_REF(X) (/proc/##X) #endif + +#if (DM_VERSION == 515) +/// fcopy will crash on 515 linux if given a non-existant file, instead of returning 0 like on 514 linux or 515 windows +/// var case matches documentation for fcopy. +/world/proc/__fcopy(Src, Dst) + if (istext(Src) && !fexists(Src)) + return 0 + return fcopy(Src, Dst) + +#define fcopy(Src, Dst) world.__fcopy(Src, Dst) + +#endif From 49fc0dea934b89fc0f736888ea46cca192ca087d Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 30 Jun 2023 01:41:48 +0000 Subject: [PATCH 19/49] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-3724.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3747.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3751.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3752.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3753.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3756.yml | 4 ---- html/changelogs/archive/2023-06.yml | 12 ++++++++++++ 7 files changed, 12 insertions(+), 24 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-3724.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3747.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3751.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3752.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3753.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3756.yml diff --git a/html/changelogs/AutoChangeLog-pr-3724.yml b/html/changelogs/AutoChangeLog-pr-3724.yml deleted file mode 100644 index 031042a976c9..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3724.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheGamerdk" -delete-after: True -changes: - - bugfix: "Lurkers no longer lose their pounce if they happen to end their pounce on a tile with a dead human" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3747.yml b/html/changelogs/AutoChangeLog-pr-3747.yml deleted file mode 100644 index c20e68184c69..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3747.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheGamerdk" -delete-after: True -changes: - - bugfix: "You can now re-enter your body when unnested, marine mains, rejoice!" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3751.yml b/html/changelogs/AutoChangeLog-pr-3751.yml deleted file mode 100644 index 50c548407f5e..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3751.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Morrow" -delete-after: True -changes: - - rscdel: "Removed wrong warden locker" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3752.yml b/html/changelogs/AutoChangeLog-pr-3752.yml deleted file mode 100644 index 2890d9c60a41..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3752.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Drathek" -delete-after: True -changes: - - bugfix: "Fix runtimes with minimap subsystem not handling targets inside of objects during removal" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3753.yml b/html/changelogs/AutoChangeLog-pr-3753.yml deleted file mode 100644 index 7105155792bd..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3753.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Drathek" -delete-after: True -changes: - - code_imp: "Ported VERB_REF and TYPE_VERB_REF from TG for 515 compatibility" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3756.yml b/html/changelogs/AutoChangeLog-pr-3756.yml deleted file mode 100644 index 77eb600b40f6..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3756.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Drathek" -delete-after: True -changes: - - code_imp: "Removed unnecessary calculations when updating a mob's transform." \ No newline at end of file diff --git a/html/changelogs/archive/2023-06.yml b/html/changelogs/archive/2023-06.yml index b1040b8044de..e2d9dfed44d7 100644 --- a/html/changelogs/archive/2023-06.yml +++ b/html/changelogs/archive/2023-06.yml @@ -430,3 +430,15 @@ - bugfix: door_control buttons now respect being indestructable when processing explosions. - maptweak: Fixed the M39s overflowing in brig armory due to use of landmarks. +2023-06-30: + Drathek: + - bugfix: Fix runtimes with minimap subsystem not handling targets inside of objects + during removal + - code_imp: Ported VERB_REF and TYPE_VERB_REF from TG for 515 compatibility + - code_imp: Removed unnecessary calculations when updating a mob's transform. + Morrow: + - rscdel: Removed wrong warden locker + TheGamerdk: + - bugfix: You can now re-enter your body when unnested, marine mains, rejoice! + - bugfix: Lurkers no longer lose their pounce if they happen to end their pounce + on a tile with a dead human From 9b123cc367fea2e2de3cfc63e208d60d1bfd60dd Mon Sep 17 00:00:00 2001 From: Drathek <76988376+Drulikar@users.noreply.github.com> Date: Thu, 29 Jun 2023 23:38:23 -0700 Subject: [PATCH 20/49] Fix Facehugger Ban Oversight (#3766) # About the pull request This PR fixes an oversight where the xeno ban check wasn't being done for facehuggers (except the facehugger join verb). # Explain why it's good for the game Fixes #3739 # Testing Photographs and Procedure
Screenshots & Videos ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/861eed98-0810-40ed-8a4c-22529cdac345)
# Changelog :cl: Drathek fix: Fixed missing xeno ban check for playing as a facehugger /:cl: --- code/modules/mob/living/carbon/xenomorph/xeno_defines.dm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm index 5d3ee0b04ba7..7e1f31e66e67 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm @@ -286,7 +286,7 @@ var/bonus_larva_spawn_chance = 1 var/hijack_burrowed_surge = FALSE //at hijack, start spawning lots of burrowed /// how many burrowed is going to spawn during larva surge - var/hijack_burrowed_left = 0 + var/hijack_burrowed_left = 0 var/ignore_slots = FALSE var/dynamic_evolution = TRUE @@ -1006,7 +1006,10 @@ /datum/hive_status/proc/can_spawn_as_hugger(mob/dead/observer/user) if(!GLOB.hive_datum || ! GLOB.hive_datum[hivenumber]) - return + return FALSE + if(jobban_isbanned(user, JOB_XENOMORPH)) // User is jobbanned + to_chat(user, SPAN_WARNING("You are banned from playing aliens and cannot spawn as a xenomorph.")) + return FALSE if(world.time < hugger_timelock) to_chat(user, SPAN_WARNING("The hive cannot support facehuggers yet...")) return FALSE From 374014d9523d2ca615f2e114af184e668e7a4db7 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 30 Jun 2023 07:46:43 +0100 Subject: [PATCH 21/49] Automatic changelog for PR #3766 [ci skip] --- html/changelogs/AutoChangeLog-pr-3766.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3766.yml diff --git a/html/changelogs/AutoChangeLog-pr-3766.yml b/html/changelogs/AutoChangeLog-pr-3766.yml new file mode 100644 index 000000000000..6132f005140c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3766.yml @@ -0,0 +1,4 @@ +author: "Drathek" +delete-after: True +changes: + - bugfix: "Fixed missing xeno ban check for playing as a facehugger" \ No newline at end of file From 52eb64e8e0ec9cd3c94a84126f5d4a73f2e98ea3 Mon Sep 17 00:00:00 2001 From: Drathek <76988376+Drulikar@users.noreply.github.com> Date: Thu, 29 Jun 2023 23:39:03 -0700 Subject: [PATCH 22/49] Fixes wordiness about re-entering your body when you're unnested (#3761) # About the pull request This PR is a followup to #3597 that was requested but refused in #3747 to improve the situation where there is too much text in a tgui_alert when ghosting while nested. # Explain why it's good for the game Instead of: ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/aee760ce-ed79-4cac-be06-b2d265bd69c6) It is now: ![image](https://github.com/cmss13-devs/cmss13/assets/76988376/26859630-c185-4c2a-94e2-d275e85a620e) # Testing Photographs and Procedure 1. Get nested 2. Remain in body for the first prompt 3. Ghost # Changelog :cl: Drathek spellcheck: Tweaked message when ghosting while nested /:cl: --- code/modules/mob/dead/observer/observer.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index fcb95a6fd783..a22e46ad2911 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -398,7 +398,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp var/is_nested = (buckled && istype(buckled, /obj/structure/bed/nest)) ? TRUE : FALSE var/obj/structure/bed/nest/nest = FALSE if(is_nested) - text_prompt += "\nSince you're nested, you will be given a chance to reenter your body upon being freed." + text_prompt += "\nSince you're nested, you will get a chance to reenter your body if freed." nest = buckled var/response = tgui_alert(src, text_prompt, "Are you sure you want to ghost?", options) if(response == "Aghost") From a7701d66c7b005389a33694fefc940f946079797 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 30 Jun 2023 08:04:24 +0100 Subject: [PATCH 23/49] Automatic changelog for PR #3761 [ci skip] --- html/changelogs/AutoChangeLog-pr-3761.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3761.yml diff --git a/html/changelogs/AutoChangeLog-pr-3761.yml b/html/changelogs/AutoChangeLog-pr-3761.yml new file mode 100644 index 000000000000..75a499cd7e48 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3761.yml @@ -0,0 +1,4 @@ +author: "Drathek" +delete-after: True +changes: + - spellcheck: "Tweaked message when ghosting while nested" \ No newline at end of file From aa786c62e614bba140b6a7496d61b614d953f734 Mon Sep 17 00:00:00 2001 From: harryob Date: Fri, 30 Jun 2023 07:53:15 +0100 Subject: [PATCH 24/49] remove more references to GAs (#3759) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit removes some remaining floating references to GAs because i literally just control-fd for "gameplay architect" 🤦 no playerfacing changes etc --- .github/CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index c05d84e8122d..339d48c9fe39 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -74,10 +74,10 @@ These are the few directives we have for project maintainers. - Try to get secondary maintainer approval before merging if you are able to. - PRs with empty commits intended to generate a changelog. - Do not merge PRs that contain content from the [banned content list](./CONTRIBUTING.md#banned-content). -- Do not merge PRs that contain balance changes without GA approval. Exceptions include: - - Any PR that has been un-reviewed by a GA for 7 days. +- Do not merge PRs that contain balance changes without Maintainer Manager approval. Exceptions include: + - Any PR that has been un-reviewed by a Maintainer Manager for 7 days. - Do not remove the DNM label that another Maintainer has applied. Exceptions include: - - GAs removing a DNM label placed by a Maintainer for Balance/Design reasons + - Maintainer Managers removing a DNM label placed by a Maintainer for Balance/Design reasons These are not steadfast rules as maintainers are expected to use their best judgement when operating. From 21dc6cde59d9dc943f304d5edd7d84a496f7eaba Mon Sep 17 00:00:00 2001 From: TheGamerdk <5618080+TheGamerdk@users.noreply.github.com> Date: Fri, 30 Jun 2023 09:30:40 +0200 Subject: [PATCH 25/49] ARES will now announce how many Foxtrot marines woke up (#3675) # About the pull request It's neat to be able to see how many Foxtrot marines woke up at a glance. This also means you know *when* they've woken up. # Explain why it's good for the game Means CIC can actually know when, and how many, foxtrot woke up, at a glance. # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: add: ARES will announce how many Foxtrot marines that woke up. /:cl: --------- Co-authored-by: harryob --- code/datums/emergency_calls/cryo_marines.dm | 6 ++++-- code/datums/emergency_calls/cryo_marines_heavy.dm | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/code/datums/emergency_calls/cryo_marines.dm b/code/datums/emergency_calls/cryo_marines.dm index e5992a62ecdd..9bec8b3593dd 100644 --- a/code/datums/emergency_calls/cryo_marines.dm +++ b/code/datums/emergency_calls/cryo_marines.dm @@ -13,10 +13,12 @@ shuttle_id = "" var/leaders = 0 -/datum/emergency_call/cryo_squad/spawn_candidates(announce, override_spawn_loc) +/datum/emergency_call/cryo_squad/spawn_candidates(announce, override_spawn_loc, announce_dispatch_message) var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo] leaders = cryo_squad.num_leaders - return ..() + . = ..() + if(length(members)) + shipwide_ai_announcement("Successfully deployed [length(members)] Foxtrot marines.") /datum/emergency_call/cryo_squad/create_member(datum/mind/M, turf/override_spawn_loc) set waitfor = 0 diff --git a/code/datums/emergency_calls/cryo_marines_heavy.dm b/code/datums/emergency_calls/cryo_marines_heavy.dm index 6a3636568856..70ce52443573 100644 --- a/code/datums/emergency_calls/cryo_marines_heavy.dm +++ b/code/datums/emergency_calls/cryo_marines_heavy.dm @@ -16,10 +16,12 @@ var/leaders = 0 -/datum/emergency_call/cryo_squad_equipped/spawn_candidates(announce, override_spawn_loc) +/datum/emergency_call/cryo_squad_equipped/spawn_candidates(announce, override_spawn_loc, announce_dispatch_message) var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo] leaders = cryo_squad.num_leaders - return ..() + . = ..() + if(length(members)) + shipwide_ai_announcement("Successfully deployed [length(members)] Foxtrot marines.") /datum/emergency_call/cryo_squad_equipped/create_member(datum/mind/M, turf/override_spawn_loc) set waitfor = 0 From ec1d1d57849730172967a1b2baeb99a5247a661d Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 30 Jun 2023 08:43:00 +0100 Subject: [PATCH 26/49] Automatic changelog for PR #3675 [ci skip] --- html/changelogs/AutoChangeLog-pr-3675.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3675.yml diff --git a/html/changelogs/AutoChangeLog-pr-3675.yml b/html/changelogs/AutoChangeLog-pr-3675.yml new file mode 100644 index 000000000000..744b83d85b08 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3675.yml @@ -0,0 +1,4 @@ +author: "TheGamerdk" +delete-after: True +changes: + - rscadd: "ARES will announce how many Foxtrot marines that woke up." \ No newline at end of file From 0f36175cbcdab1be582ad40340291f9d8d650b85 Mon Sep 17 00:00:00 2001 From: ihatethisengine <115417687+ihatethisengine@users.noreply.github.com> Date: Fri, 30 Jun 2023 10:48:14 +0300 Subject: [PATCH 27/49] Dropship Sentry Camera (#3737) # About the pull request Adds cameras to dropship deployable sentries. Only work when deployed. # Explain why it's good for the game A bit more awareness for the most boring role in the game won't hurt. Also, it was a feature a few years ago, I still don't understand why it was removed, maybe just got dropped during refactoring or something. # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: ihatethisengine add: Added cameras to dropship deployable sentries. /:cl: --- code/modules/cm_marines/dropship_equipment.dm | 13 ++++++++++++- code/modules/defenses/sentry.dm | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/code/modules/cm_marines/dropship_equipment.dm b/code/modules/cm_marines/dropship_equipment.dm index 42bbd7f746e7..89d33134bdb8 100644 --- a/code/modules/cm_marines/dropship_equipment.dm +++ b/code/modules/cm_marines/dropship_equipment.dm @@ -256,6 +256,13 @@ deployed_turret.start_processing() deployed_turret.set_range() + deployed_turret.linked_cam = new(deployed_turret.loc, "[capitalize_first_letters(ship_base.name)] [capitalize_first_letters(name)]") + if (linked_shuttle.id == DROPSHIP_ALAMO) + deployed_turret.linked_cam.network = list(CAMERA_NET_ALAMO) + else if (linked_shuttle.id == DROPSHIP_NORMANDY) + deployed_turret.linked_cam.network = list(CAMERA_NET_NORMANDY) + + /obj/structure/dropship_equipment/sentry_holder/proc/undeploy_sentry() if(!deployed_turret) return @@ -267,8 +274,12 @@ deployed_turret.stop_processing() deployed_turret.unset_range() icon_state = "sentry_system_installed" + QDEL_NULL(deployed_turret.linked_cam) - +/obj/structure/dropship_equipment/sentry_holder/Destroy() + if(deployed_turret) + QDEL_NULL(deployed_turret.linked_cam) + . = ..() /// Holder for the dropship mannable machinegun system diff --git a/code/modules/defenses/sentry.dm b/code/modules/defenses/sentry.dm index 3d485f3abda7..946c347efaa0 100644 --- a/code/modules/defenses/sentry.dm +++ b/code/modules/defenses/sentry.dm @@ -539,11 +539,13 @@ choice_categories = list() selected_categories = list() var/obj/structure/dropship_equipment/sentry_holder/deployment_system + var/obj/structure/machinery/camera/cas/linked_cam /obj/structure/machinery/defenses/sentry/premade/dropship/Destroy() if(deployment_system) deployment_system.deployed_turret = null deployment_system = null + QDEL_NULL(linked_cam) . = ..() #define SENTRY_SNIPER_RANGE 10 From 6a457d9475b83fc2dd0796f1a47a9f7e5cebd4f4 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 30 Jun 2023 08:57:07 +0100 Subject: [PATCH 28/49] Automatic changelog for PR #3737 [ci skip] --- html/changelogs/AutoChangeLog-pr-3737.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3737.yml diff --git a/html/changelogs/AutoChangeLog-pr-3737.yml b/html/changelogs/AutoChangeLog-pr-3737.yml new file mode 100644 index 000000000000..770af461be67 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3737.yml @@ -0,0 +1,4 @@ +author: "ihatethisengine" +delete-after: True +changes: + - rscadd: "Added cameras to dropship deployable sentries." \ No newline at end of file From 4ad91f21deef23addf01b55a7a0851d55cffc7f2 Mon Sep 17 00:00:00 2001 From: harryob Date: Fri, 30 Jun 2023 17:59:50 +0100 Subject: [PATCH 29/49] you can't implant yourself with a motion detector anymore (#3767) this was covered by a rule clarification for ages but im trying to get rid of as many stupid niche rule clarifications as possible :cl: add: you can no longer implant yourself with a motion detector /:cl: --- code/__DEFINES/traits.dm | 3 +++ code/game/objects/items/devices/motion_detector.dm | 3 ++- code/modules/surgery/implant.dm | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index e5441090d60c..dd700ccde996 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -211,6 +211,9 @@ //ie. naming a regulation tape "example" will become regulation tape (example) #define TRAIT_ITEM_RENAME_SPECIAL "t_item_rename_special" +// This item can't be implanted into someone, regardless of the size of the item. +#define TRAIT_ITEM_NOT_IMPLANTABLE "t_item_not_implantable" + //-- structure traits -- // TABLE TRAITS /// If the table is being flipped, prevent any changes that will mess with adjacency handling diff --git a/code/game/objects/items/devices/motion_detector.dm b/code/game/objects/items/devices/motion_detector.dm index 01858ed486d0..ade74531bc91 100644 --- a/code/game/objects/items/devices/motion_detector.dm +++ b/code/game/objects/items/devices/motion_detector.dm @@ -22,6 +22,7 @@ item_state = "motion_detector" flags_atom = FPRINT| CONDUCT flags_equip_slot = SLOT_WAIST + inherent_traits = list(TRAIT_ITEM_NOT_IMPLANTABLE) var/list/blip_pool = list() var/detector_range = 14 var/detector_mode = MOTION_DETECTOR_LONG @@ -309,7 +310,7 @@ name = "hacked motion detector" desc = "A device that usually picks up non-USCM signals, but this one's been hacked to detect all non-freelancer movement instead. Fight fire with fire!" iff_signal = FACTION_MERCENARY - + /obj/item/device/motiondetector/hacked/pmc name = "corporate motion detector" desc = "A device that usually picks up non-USCM signals, but this one's been reprogrammed to detect all non-PMC movement instead. Very corporate." diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index cebd4b44da7d..8f2e6156831a 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -106,6 +106,8 @@ if(.) if(is_surgery_tool(tool)) //Make sure you still have all your tools after a surgery. return FALSE + if(HAS_TRAIT(tool, TRAIT_ITEM_NOT_IMPLANTABLE)) + return FALSE if(tool.w_class > get_max_wclass(surgery)) to_chat(user, SPAN_WARNING("[tool] is too big to implant into [surgery.target]'s [surgery.affected_limb.cavity]!")) return FALSE From ed901413b0c5a9358bca2f6218f2b080e2eecd48 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 30 Jun 2023 18:07:57 +0100 Subject: [PATCH 30/49] Automatic changelog for PR #3767 [ci skip] --- html/changelogs/AutoChangeLog-pr-3767.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3767.yml diff --git a/html/changelogs/AutoChangeLog-pr-3767.yml b/html/changelogs/AutoChangeLog-pr-3767.yml new file mode 100644 index 000000000000..468759acbbad --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3767.yml @@ -0,0 +1,4 @@ +author: "harryob" +delete-after: True +changes: + - rscadd: "you can no longer implant yourself with a motion detector" \ No newline at end of file From 96b578e761329e7b11aa8acfd884a087ebef8a49 Mon Sep 17 00:00:00 2001 From: Ben <91219575+Ben10083@users.noreply.github.com> Date: Fri, 30 Jun 2023 16:42:40 -0400 Subject: [PATCH 31/49] Prevents spamming open and close tarps (#3768) # About the pull request Fixes #3734 Deals with exploit that allows the user to spam open and close a tarp, making it hard for the Xeno to hit the marine, this makes it so when tarp is opened, 3 seconds must pass before it can be closed again. If 3 seconds isn't enough, delay can be lengthened. # Explain why it's good for the game I was tasked by the Xeno Agents to buff Xeno win rate by any means necessary, including fixing exploits. # Testing Photographs and Procedure
Screenshots & Videos https://github.com/cmss13-devs/cmss13/assets/91219575/999e0f72-a802-41d3-b1d8-5a4569d84e5a Before ![image](https://github.com/cmss13-devs/cmss13/assets/91219575/7eb71b25-4077-4042-bab6-760f0c429190) After
# Changelog :cl: fix: fixes exploit relating to cloaking tarps by adding a delay before tarp can be closed again. /:cl: --------- Co-authored-by: harryob --- .../objects/structures/crates_lockers/closets.dm | 2 +- code/modules/cm_marines/equipment/gear.dm | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 05355feeb154..e6c215d0208f 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -149,7 +149,7 @@ /obj/structure/closet/proc/toggle(mob/living/user) user.next_move = world.time + 5 - if(!(src.opened ? src.close() : src.open())) + if(!(src.opened ? src.close(user) : src.open())) to_chat(user, SPAN_NOTICE("It won't budge!")) return diff --git a/code/modules/cm_marines/equipment/gear.dm b/code/modules/cm_marines/equipment/gear.dm index 98e7dbcf49df..ff6c715b520b 100644 --- a/code/modules/cm_marines/equipment/gear.dm +++ b/code/modules/cm_marines/equipment/gear.dm @@ -58,6 +58,8 @@ var/is_animating = FALSE var/first_open = TRUE exit_stun = 0 + /// used to implement a delay before tarp can be entered again after opened (anti-exploit) + COOLDOWN_DECLARE(toggle_delay) /obj/structure/closet/bodybag/tarp/snow icon_state = "snowtarp_closed" @@ -91,9 +93,9 @@ exit_stun = 1 can_store_dead = TRUE -/obj/structure/closet/bodybag/tarp/reactive/scout/close() +/obj/structure/closet/bodybag/tarp/reactive/scout/close(mob/user) if(!skillcheck(usr, SKILL_SPEC_WEAPONS, SKILL_SPEC_ALL) && usr.skills.get_skill_level(SKILL_SPEC_WEAPONS) != SKILL_SPEC_SCOUT) - to_chat(usr, SPAN_WARNING("You don't seem to know how to use [src]...")) + to_chat(user, SPAN_WARNING("You don't seem to know how to use [src]...")) return . = ..() @@ -137,10 +139,14 @@ return /obj/structure/closet/bodybag/tarp/open() + COOLDOWN_START(src, toggle_delay, 3 SECONDS) //3 seconds must pass before tarp can be closed . = ..() handle_cloaking() -/obj/structure/closet/bodybag/tarp/close() +/obj/structure/closet/bodybag/tarp/close(mob/user) + if(!COOLDOWN_FINISHED(src, toggle_delay)) + to_chat(user, SPAN_WARNING("It is too soon to close [src]!")) + return FALSE . = ..() handle_cloaking() From f77fe82c83c538ac86ca1dbb43f370bee104417a Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 30 Jun 2023 21:53:17 +0100 Subject: [PATCH 32/49] Automatic changelog for PR #3768 [ci skip] --- html/changelogs/AutoChangeLog-pr-3768.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3768.yml diff --git a/html/changelogs/AutoChangeLog-pr-3768.yml b/html/changelogs/AutoChangeLog-pr-3768.yml new file mode 100644 index 000000000000..fc5830aa66ed --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3768.yml @@ -0,0 +1,4 @@ +author: "Ben10083" +delete-after: True +changes: + - bugfix: "fixes exploit relating to cloaking tarps by adding a delay before tarp can be closed again." \ No newline at end of file From 3795db8835e9795ccede3f58bf9bcf955be21e7f Mon Sep 17 00:00:00 2001 From: harryob Date: Fri, 30 Jun 2023 22:34:48 +0100 Subject: [PATCH 33/49] fixes the generate_documentation workflow --- .github/workflows/generate_documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate_documentation.yml b/.github/workflows/generate_documentation.yml index 6075e3029acd..59e6d1144c68 100644 --- a/.github/workflows/generate_documentation.yml +++ b/.github/workflows/generate_documentation.yml @@ -21,7 +21,7 @@ jobs: run: | ~/dmdoc touch dmdoc/.nojekyll - echo codedocs.tgstation13.org > dmdoc/CNAME + echo docs.cm-ss13.com > dmdoc/CNAME - name: Deploy uses: JamesIves/github-pages-deploy-action@3.7.1 with: From db2384b624fcaef906934fe9a0736fa46b57a37c Mon Sep 17 00:00:00 2001 From: Ben <91219575+Ben10083@users.noreply.github.com> Date: Fri, 30 Jun 2023 18:41:20 -0400 Subject: [PATCH 34/49] People with lisp now lisp on radio (#3760) # About the pull request The lisp trait did not affect a flag for speech, making it so lisping does not occur over radio, this should make it so what they say is transmitted properly. # Explain why it's good for the game Fixes an oversight and allows for lisp speech to be handled by the handle_speech_problems method. Also realism or something # Testing Photographs and Procedure
Screenshots & Videos ![image](https://github.com/cmss13-devs/cmss13/assets/91219575/7526b49e-ff74-4979-8024-71768501e43a) Poor marine trying to alert command
# Changelog :cl: fix: lisps now occur over radio as well refactor: Relevant variables relating to speech problems now use true and false instead of 1 and 0 /:cl: --- code/modules/character_traits/biology_traits.dm | 2 ++ .../mob/living/carbon/human/human_damage.dm | 4 ++-- .../mob/living/carbon/human/human_defines.dm | 2 +- .../carbon/human/life/handle_disabilities.dm | 4 ++-- .../human/life/handle_regular_status_updates.dm | 4 ++-- .../living/carbon/human/life/life_helpers.dm | 10 +++++----- code/modules/mob/living/carbon/human/say.dm | 17 +++++++++-------- 7 files changed, 23 insertions(+), 20 deletions(-) diff --git a/code/modules/character_traits/biology_traits.dm b/code/modules/character_traits/biology_traits.dm index e7625c391b75..87fb0b70ec36 100644 --- a/code/modules/character_traits/biology_traits.dm +++ b/code/modules/character_traits/biology_traits.dm @@ -59,11 +59,13 @@ return ADD_TRAIT(target, TRAIT_LISPING, TRAIT_SOURCE_QUIRK) + target.speech_problem_flag = TRUE ..() /datum/character_trait/biology/lisp/unapply_trait(mob/living/carbon/human/target) REMOVE_TRAIT(target, TRAIT_LISPING, TRAIT_SOURCE_QUIRK) + target.speech_problem_flag = FALSE ..() /datum/character_trait/biology/bad_leg diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 00659389decb..5c685cc3acac 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -287,7 +287,7 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t apply_damage(burn, BURN, picked, sharp, edge) UpdateDamageIcon() updatehealth() - speech_problem_flag = 1 + speech_problem_flag = TRUE //Heal MANY limbs, in random order @@ -308,7 +308,7 @@ In most cases it makes more sense to use apply_damage() instead! And make sure t parts -= picked updatehealth() - speech_problem_flag = 1 + speech_problem_flag = TRUE if(update) UpdateDamageIcon() // damage MANY limbs, in random order diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 7f9801145a8e..989ee52fa63c 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -64,7 +64,7 @@ var/voice - var/speech_problem_flag = 0 + var/speech_problem_flag = FALSE var/special_voice = "" // For changing our voice. Used by a symptom. diff --git a/code/modules/mob/living/carbon/human/life/handle_disabilities.dm b/code/modules/mob/living/carbon/human/life/handle_disabilities.dm index 46b1f3e15515..9ab234212108 100644 --- a/code/modules/mob/living/carbon/human/life/handle_disabilities.dm +++ b/code/modules/mob/living/carbon/human/life/handle_disabilities.dm @@ -17,7 +17,7 @@ return if(disabilities & TOURETTES) - speech_problem_flag = 1 + speech_problem_flag = TRUE if((prob(10) && knocked_out <= 1)) apply_effect(10, STUN) spawn() @@ -36,7 +36,7 @@ return if(disabilities & NERVOUS) - speech_problem_flag = 1 + speech_problem_flag = TRUE if(prob(10)) stuttering = max(10, stuttering) return diff --git a/code/modules/mob/living/carbon/human/life/handle_regular_status_updates.dm b/code/modules/mob/living/carbon/human/life/handle_regular_status_updates.dm index 4a6596104d4a..5c951a8112bf 100644 --- a/code/modules/mob/living/carbon/human/life/handle_regular_status_updates.dm +++ b/code/modules/mob/living/carbon/human/life/handle_regular_status_updates.dm @@ -59,7 +59,7 @@ if(regular_update && halloss > 0) apply_damage(-3, HALLOSS) else if(sleeping) - speech_problem_flag = 1 + speech_problem_flag = TRUE if(regular_update) handle_dreams() apply_damage(-3, HALLOSS) @@ -122,7 +122,7 @@ handle_statuses() if(paralyzed) - speech_problem_flag = 1 + speech_problem_flag = TRUE apply_effect(1, WEAKEN) silent = 1 blinded = TRUE diff --git a/code/modules/mob/living/carbon/human/life/life_helpers.dm b/code/modules/mob/living/carbon/human/life/life_helpers.dm index 0339bf6ec742..fedeaf9fd48c 100644 --- a/code/modules/mob/living/carbon/human/life/life_helpers.dm +++ b/code/modules/mob/living/carbon/human/life/life_helpers.dm @@ -216,18 +216,18 @@ /mob/living/carbon/human/handle_silent() if(..()) - speech_problem_flag = 1 + speech_problem_flag = TRUE return silent /mob/living/carbon/human/handle_slurring() if(..()) - speech_problem_flag = 1 + speech_problem_flag = TRUE return slurring /mob/living/carbon/human/handle_stunned() if(stunned) adjust_effect(-species.stun_reduction, STUN, EFFECT_FLAG_LIFE) - speech_problem_flag = 1 + speech_problem_flag = TRUE return stunned /mob/living/carbon/human/handle_dazed() @@ -237,7 +237,7 @@ var/final_reduction = skill_resistance + 1 adjust_effect(-final_reduction, DAZE, EFFECT_FLAG_LIFE) if(dazed) - speech_problem_flag = 1 + speech_problem_flag = TRUE return dazed /mob/living/carbon/human/handle_knocked_down() @@ -262,7 +262,7 @@ /mob/living/carbon/human/handle_stuttering() if(..()) - speech_problem_flag = 1 + speech_problem_flag = TRUE return stuttering #define HUMAN_TIMER_TO_EFFECT_CONVERSION (0.05) //(1/20) //once per 2 seconds, with effect equal to endurance, which is used later diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 46a44fc16611..4b86c827a069 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -262,20 +262,20 @@ for it but just ignore it. /mob/living/carbon/human/proc/handle_speech_problems(message) var/list/returns[3] var/verb = "says" - var/handled = 0 + var/handled = FALSE if(silent) message = "" - handled = 1 + handled = TRUE if(sdisabilities & DISABILITY_MUTE) message = "" - handled = 1 + handled = TRUE if(wear_mask) if(istype(wear_mask, /obj/item/clothing/mask/horsehead)) var/obj/item/clothing/mask/horsehead/hoers = wear_mask if(hoers.voicechange) message = pick("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!") verb = pick("whinnies","neighs", "says") - handled = 1 + handled = TRUE var/braindam = getBrainLoss() if(slurring || stuttering || dazed || braindam >= 60) @@ -283,17 +283,17 @@ for it but just ignore it. if(slurring) message = slur(message) verb = pick("stammers","stutters") - handled = 1 + handled = TRUE if(stuttering) message = NewStutter(message) verb = pick("stammers", "stutters") - handled = 1 + handled = TRUE if(dazed) message = DazedText(message) verb = pick("mumbles", "babbles") - handled = 1 + handled = TRUE if(braindam >= 60) - handled = 1 + handled = TRUE if(prob(braindam/4)) message = stutter(message, stuttering) verb = pick("stammers", "stutters") @@ -301,6 +301,7 @@ for it but just ignore it. message = uppertext(message) verb = pick("yells like an idiot","says rather loudly") if(HAS_TRAIT(src, TRAIT_LISPING)) + handled = TRUE var/old_message = message message = lisp_replace(message) if(old_message != message) From 0a68bd3a78c4e9b409490e1e3df089f3b10f0dd3 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Fri, 30 Jun 2023 23:51:53 +0100 Subject: [PATCH 35/49] Automatic changelog for PR #3760 [ci skip] --- html/changelogs/AutoChangeLog-pr-3760.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3760.yml diff --git a/html/changelogs/AutoChangeLog-pr-3760.yml b/html/changelogs/AutoChangeLog-pr-3760.yml new file mode 100644 index 000000000000..dfb133be6ba8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3760.yml @@ -0,0 +1,5 @@ +author: "Ben10083" +delete-after: True +changes: + - bugfix: "lisps now occur over radio as well" + - refactor: "Relevant variables relating to speech problems now use true and false instead of 1 and 0" \ No newline at end of file From f194c10a3201b9b62d71e85d3dd2d6d8956659fa Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sat, 1 Jul 2023 01:53:02 +0000 Subject: [PATCH 36/49] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-3675.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3737.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3760.yml | 5 ----- html/changelogs/AutoChangeLog-pr-3761.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3766.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3767.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3768.yml | 4 ---- html/changelogs/archive/2023-07.yml | 16 ++++++++++++++++ 8 files changed, 16 insertions(+), 29 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-3675.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3737.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3760.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3761.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3766.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3767.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3768.yml create mode 100644 html/changelogs/archive/2023-07.yml diff --git a/html/changelogs/AutoChangeLog-pr-3675.yml b/html/changelogs/AutoChangeLog-pr-3675.yml deleted file mode 100644 index 744b83d85b08..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3675.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TheGamerdk" -delete-after: True -changes: - - rscadd: "ARES will announce how many Foxtrot marines that woke up." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3737.yml b/html/changelogs/AutoChangeLog-pr-3737.yml deleted file mode 100644 index 770af461be67..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3737.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "ihatethisengine" -delete-after: True -changes: - - rscadd: "Added cameras to dropship deployable sentries." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3760.yml b/html/changelogs/AutoChangeLog-pr-3760.yml deleted file mode 100644 index dfb133be6ba8..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3760.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Ben10083" -delete-after: True -changes: - - bugfix: "lisps now occur over radio as well" - - refactor: "Relevant variables relating to speech problems now use true and false instead of 1 and 0" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3761.yml b/html/changelogs/AutoChangeLog-pr-3761.yml deleted file mode 100644 index 75a499cd7e48..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3761.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Drathek" -delete-after: True -changes: - - spellcheck: "Tweaked message when ghosting while nested" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3766.yml b/html/changelogs/AutoChangeLog-pr-3766.yml deleted file mode 100644 index 6132f005140c..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3766.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Drathek" -delete-after: True -changes: - - bugfix: "Fixed missing xeno ban check for playing as a facehugger" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3767.yml b/html/changelogs/AutoChangeLog-pr-3767.yml deleted file mode 100644 index 468759acbbad..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3767.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "harryob" -delete-after: True -changes: - - rscadd: "you can no longer implant yourself with a motion detector" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3768.yml b/html/changelogs/AutoChangeLog-pr-3768.yml deleted file mode 100644 index fc5830aa66ed..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3768.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ben10083" -delete-after: True -changes: - - bugfix: "fixes exploit relating to cloaking tarps by adding a delay before tarp can be closed again." \ No newline at end of file diff --git a/html/changelogs/archive/2023-07.yml b/html/changelogs/archive/2023-07.yml new file mode 100644 index 000000000000..36734311f334 --- /dev/null +++ b/html/changelogs/archive/2023-07.yml @@ -0,0 +1,16 @@ +2023-07-01: + Ben10083: + - bugfix: lisps now occur over radio as well + - refactor: Relevant variables relating to speech problems now use true and false + instead of 1 and 0 + - bugfix: fixes exploit relating to cloaking tarps by adding a delay before tarp + can be closed again. + Drathek: + - bugfix: Fixed missing xeno ban check for playing as a facehugger + - spellcheck: Tweaked message when ghosting while nested + TheGamerdk: + - rscadd: ARES will announce how many Foxtrot marines that woke up. + harryob: + - rscadd: you can no longer implant yourself with a motion detector + ihatethisengine: + - rscadd: Added cameras to dropship deployable sentries. From b64af8edd16fb4a690614072951c8ea2a0b4b704 Mon Sep 17 00:00:00 2001 From: fira Date: Sat, 1 Jul 2023 03:16:41 +0100 Subject: [PATCH 37/49] InfluxDB Metrics Backend (#3601) # About the pull request Wider scope version of #3480 This ships the following game metrics to InfluxDB: * Job occupations, tagged by "team" (humans/factions, xenos/hives...) * Online Players/Staff/Mentor * AHelp ticket statistics * Round-based statistics that are already DB-logged, such as chestbursts, FF hits, shots fired * Amount of pooled larvas * MC/SS timing info that was previously sent to SQL It uses two separate subsystems, one for collecting metrics, the other for shipping them - and provides procs for easily sending more data to wire up other code. # Explain why it's good for the game Gives fine grained control over game data that we don't have. Currently SOME of these are logged to SQL, and we'd need to create our own vis UI. Backing them by a TSDB allows to view evolutions over time, and means we can plug in standard dashboarding tooling like Grafana. # Testing Photographs and Procedure ![image](https://github.com/cmss13-devs/cmss13/assets/604624/fd3e9245-dea0-4acd-8f4f-68dff9ccba14) (okay it's technically from a TM of the older PR) # Changelog :cl: add: Added InfluxDB backed metrics logging for some of the most used game statistics. This will allow to graph them over time and give better insight as to what happens in rounds. /:cl: --- code/__DEFINES/subsystems.dm | 12 +- code/__HELPERS/text.dm | 5 + code/_globalvars/global_lists.dm | 1 + .../configuration/entries/general.dm | 19 +++ code/controllers/subsystem/influxdriver.dm | 132 +++++++++++++++ code/controllers/subsystem/influxmcstats.dm | 47 ++++++ code/controllers/subsystem/influxstats.dm | 156 ++++++++++++++++++ .../datums/statistics/entities/panel_stats.dm | 1 - .../datums/statistics/entities/round_stats.dm | 2 - .../mob/living/carbon/xenomorph/Embryo.dm | 1 + .../living/carbon/xenomorph/xeno_defines.dm | 13 ++ colonialmarines.dme | 3 + nano/templates/cm_stat_panel.tmpl | 3 - 13 files changed, 386 insertions(+), 9 deletions(-) create mode 100644 code/controllers/subsystem/influxdriver.dm create mode 100644 code/controllers/subsystem/influxmcstats.dm create mode 100644 code/controllers/subsystem/influxstats.dm diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 3c2527136ed6..662bcb458c55 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -113,7 +113,8 @@ #define SS_INIT_INPUT 85 #define SS_INIT_FAIL_TO_TOPIC 84 #define SS_INIT_TOPIC 83 -#define SS_INIT_RUST 26 +#define SS_INIT_RUST 30 +#define SS_INIT_INFLUXDRIVER 28 #define SS_INIT_SUPPLY_SHUTTLE 25 #define SS_INIT_GARBAGE 24 #define SS_INIT_EVENTS 23.5 @@ -133,7 +134,9 @@ #define SS_INIT_MORE_INIT 16 #define SS_INIT_AIR 15 #define SS_INIT_TELEPORTER 13 -#define SS_INIT_LIGHTING 12 +#define SS_INIT_INFLUXMCSTATS 12 +#define SS_INIT_INFLUXSTATS 11 +#define SS_INIT_LIGHTING 10 #define SS_INIT_DEFCON 9 #define SS_INIT_LAW 6 #define SS_INIT_FZ_TRANSITIONS 5 @@ -212,12 +215,15 @@ #define SS_PRIORITY_UNSPECIFIED 30 #define SS_PRIORITY_PROCESS 25 #define SS_PRIORITY_SOUNDSCAPE 24 +#define SS_PRIORITY_INFLUXDRIVER 23 #define SS_PRIORITY_PAGER_STATUS 22 #define SS_PRIORITY_LIGHTING 20 #define SS_PRIORITY_TRACKING 19 +#define SS_PRIORITY_DATABASE 15 #define SS_PRIORITY_MINIMAPS 11 #define SS_PRIORITY_PING 10 -#define SS_PRIORITY_DATABASE 15 +#define SS_PRIORITY_INFLUXMCSTATS 9 +#define SS_PRIORITY_INFLUXSTATS 8 #define SS_PRIORITY_PLAYTIME 5 #define SS_PRIORITY_PERFLOGGING 4 #define SS_PRIORITY_CORPSESPAWNER 3 diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 83da41b515a6..d4d9eb320633 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -164,6 +164,11 @@ t = "0[t]" return t +/proc/pad_trailing(text, padding, size) + while (length(text) < size) + text = "[text][padding]" + return text + //Adds 'u' number of spaces ahead of the text 't' /proc/add_lspace(t, u) while(length(t) < u) diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm index f0279907f635..586d5e71a92d 100644 --- a/code/_globalvars/global_lists.dm +++ b/code/_globalvars/global_lists.dm @@ -10,6 +10,7 @@ GLOBAL_LIST_EMPTY(GeneralFaxes) //Inter-machine faxes GLOBAL_LIST_EMPTY(fax_contents) //List of fax contents to maintain it even if source paper is deleted GLOBAL_LIST_EMPTY(failed_fultons) //A list of fultoned items which weren't collected and fell back down +GLOBAL_LIST_EMPTY(larva_burst_by_hive) GLOBAL_LIST_INIT_TYPED(custom_huds_list, /datum/custom_hud, setup_all_huds()) GLOBAL_LIST_INIT_TYPED(custom_human_huds, /datum/custom_hud, setup_human_huds()) diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 29dd0a88d3e0..7988ff6d1a95 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -529,6 +529,25 @@ This maintains a list of ip addresses that are able to bypass topic filtering. /datum/config_entry/string/round_results_webhook_url +/// InfluxDB v2 Host to connect to for sending statistics (over HTTP API) +/datum/config_entry/string/influxdb_host +/// InfluxDB v2 Bucket to send staistics to +/datum/config_entry/string/influxdb_bucket +/// InfluxDB v2 Organization to access buckets of +/datum/config_entry/string/influxdb_org +/// InfluxDB v2 API Token to access the organization and bucket +/datum/config_entry/string/influxdb_token + +/// How often to snapshot general game statistics to influxdb driver +/datum/config_entry/number/influxdb_stats_period + config_entry_value = 30 +/// How often to snapshot MC statistics +/datum/config_entry/number/influxdb_mcstats_period + config_entry_value = 60 +/// How often to send queued influxdb statistics +/datum/config_entry/number/influxdb_send_period + config_entry_value = 10 + /// logs all timers in buckets on automatic bucket reset (Useful for timer debugging) /datum/config_entry/flag/log_timers_on_bucket_reset diff --git a/code/controllers/subsystem/influxdriver.dm b/code/controllers/subsystem/influxdriver.dm new file mode 100644 index 000000000000..7e5289dfc518 --- /dev/null +++ b/code/controllers/subsystem/influxdriver.dm @@ -0,0 +1,132 @@ +/// Sends collected statistics to an influxdb v2 backend periodically +SUBSYSTEM_DEF(influxdriver) + name = "InfluxDB Driver" + wait = 10 SECONDS + init_order = SS_INIT_INFLUXDRIVER + priority = SS_PRIORITY_INFLUXDRIVER + runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY + + var/list/send_queue = list() + + /// Maximum amount of metric lines to send at most in one request + /// This is neccessary because sending a lot of metrics can get expensive + /// and drive the subsystem into overtime, but we can't split the work as it'd be even less efficient + var/max_batch = 150 + + /// Last timestamp in microseconds + var/timestamp_cache_realtime + /// Last tick time the timestamp was taken at + var/timestamp_cache_worldtime + +/datum/controller/subsystem/influxdriver/Initialize() + var/period = text2num(CONFIG_GET(number/influxdb_send_period)) + if(isnum(period)) + wait = max(period * (1 SECONDS), 2 SECONDS) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/influxdriver/stat_entry(msg) + msg += "period=[wait] queue=[length(send_queue)]" + return ..() + +/datum/controller/subsystem/influxdriver/proc/unix_timestamp_string() // pending change to rust-g + return RUSTG_CALL(RUST_G, "unix_timestamp")() + +/datum/controller/subsystem/influxdriver/proc/update_timestamp() + PRIVATE_PROC(TRUE) + // We make only one request to rustg per game tick, so we cache the result per world.time + var/whole_timestamp = unix_timestamp_string() // Format "7129739474.4758981" - timestamp with up to 7-8 decimals + var/list/tsparts = splittext(whole_timestamp, ".") + var/fractional = copytext(pad_trailing(tsparts[2], "0", 6), 1, 7) // in microseconds + timestamp_cache_worldtime = world.time + timestamp_cache_realtime = "[tsparts[1]][fractional]" + +/datum/controller/subsystem/influxdriver/fire(resumed) + var/maxlen = min(length(send_queue)+1, max_batch) + var/list/queue = send_queue.Copy(1, maxlen) + send_queue.Cut(1, maxlen) + flush_queue(queue) + +/// Flushes measurements batch to InfluxDB backend +/datum/controller/subsystem/influxdriver/proc/flush_queue(list/queue) + PRIVATE_PROC(TRUE) + + var/host = CONFIG_GET(string/influxdb_host) + var/token = CONFIG_GET(string/influxdb_token) + var/bucket = CONFIG_GET(string/influxdb_bucket) + var/org = CONFIG_GET(string/influxdb_org) + + if(!host || !token || !bucket || !org) + can_fire = FALSE + return + + if(!length(queue)) + return // Nothing to do + + var/url = "[host]/api/v2/write?org=[org]&bucket=[bucket]&precision=us" // microseconds + var/list/headers = list() + headers["Authorization"] = "Token [token]" + headers["Content-Type"] = "text/plain; charset=utf-8" + headers["Accept"] = "application/json" + + var/datum/http_request/request = new + var/payload = "" + for(var/line in queue) + payload += "[line]\n" + request.prepare(RUSTG_HTTP_METHOD_POST, url, payload, headers) + request.begin_async() + // TODO possibly check back result of request later + +/// Enqueues sending to InfluxDB Backend selected measurement values - round_id and timestamp are filled in automatically +/datum/controller/subsystem/influxdriver/proc/enqueue_stats(measurement, list/tags, list/fields) + . = FALSE + var/valid = FALSE + var/serialized = "[measurement],round_id=[GLOB.round_id]" + if(tags) + for(var/tag in tags) + var/serialized_tag = serialize_field(tag, tags[tag]) + if(serialized_tag) + serialized += ",[serialized_tag]" + serialized += " " + var/comma = "" + for(var/field in fields) + var/serialized_field = serialize_field(field, fields[field]) + if(serialized_field) + valid = TRUE + serialized += "[comma][serialized_field]" + comma = "," + if(!valid) + CRASH("Attempted to serialize to InfluxDB backend an invalid measurement (likely has no fields)") + if(timestamp_cache_worldtime != world.time) + update_timestamp() + serialized += " [timestamp_cache_realtime]" + send_queue += serialized + return TRUE + +/// Enqueues sending varied stats in a dumb and simpler format directly as: measurement count= +/datum/controller/subsystem/influxdriver/proc/enqueue_stats_crude(measurement, value, field_name = "count") + . = FALSE + var/serialized_field = serialize_field(field_name, value) + if(!length(serialized_field)) + return + if(timestamp_cache_worldtime != world.time) + update_timestamp() + var/serialized = "[measurement],round_id=[GLOB.round_id] [serialized_field] [timestamp_cache_realtime]" + send_queue += serialized + return TRUE + +/// Puts a single field or tag value into InfluxDB Line format +/datum/controller/subsystem/influxdriver/proc/serialize_field(field, value) + var/static/regex/whitelistedCharacters = regex(@{"([^a-zA-Z0-9_]+)"}, "g") + var/sanitized_field = whitelistedCharacters.Replace("[field]", "") + if(!length(sanitized_field) || copytext(sanitized_field, 1, 2) == "_") + CRASH("Invalid tag/field for InfluxDB serialization: '[sanitized_field]' (original: '[field]')") + var/sanitized_value + if(isnum(value)) + sanitized_value = value + else if(istext(value)) + sanitized_value = whitelistedCharacters.Replace("[value]", "") + if(!length(sanitized_value) || copytext(sanitized_value, 1, 2) == "_") + CRASH("Invalid value for InfluxDB serialization: '[sanitized_value]' (original: '[value]')") + else + CRASH("Invalid value type passed for InfluxDB serialization: '[value]'") + return "[sanitized_field]=[sanitized_value]" diff --git a/code/controllers/subsystem/influxmcstats.dm b/code/controllers/subsystem/influxmcstats.dm new file mode 100644 index 000000000000..a1bf171d81a3 --- /dev/null +++ b/code/controllers/subsystem/influxmcstats.dm @@ -0,0 +1,47 @@ +SUBSYSTEM_DEF(influxmcstats) + name = "InfluxDB MC Stats" + wait = 60 SECONDS + priority = SS_PRIORITY_INFLUXMCSTATS + init_order = SS_INIT_INFLUXMCSTATS + runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT + flags = SS_KEEP_TIMING + var/checkpoint = 0 + var/list/subsystem_name_cache = list() + +/datum/controller/subsystem/influxmcstats/Initialize() + var/period = text2num(CONFIG_GET(number/influxdb_mcstats_period)) + if(isnum(period)) + wait = max(period * (1 SECONDS), 10 SECONDS) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/influxmcstats/stat_entry(msg) + msg += "period=[wait] checkpoint=[checkpoint]" + return ..() + +/datum/controller/subsystem/influxmcstats/fire(resumed) + if(!SSinfluxdriver.can_fire) + can_fire = FALSE + return + + var/list/data = list() + data["time_dilation_current"] = SStime_track.time_dilation_current + data["time_dilation_avg"] = SStime_track.time_dilation_avg + data["time_dilation_avg_slow"] = SStime_track.time_dilation_avg_slow + data["time_dilation_avg_fast"] = SStime_track.time_dilation_avg_fast + SSinfluxdriver.enqueue_stats("tidi", null, data) + + SSinfluxdriver.enqueue_stats("cpu", null, list("cpu" = world.cpu, "map_cpu" = world.map_cpu)) + + var/static/regex/get_last_path_element = regex(@{"/([^/]+)$"}) + checkpoint++ + for(var/datum/controller/subsystem/SS in Master.subsystems) + if(!SS.can_fire) + continue + if(!subsystem_name_cache[SS.type]) + get_last_path_element.Find("[SS.type]") + subsystem_name_cache[SS.type] = "SS[get_last_path_element.group[1]]" + var/SSname = subsystem_name_cache[SS.type] + if(!SSname) + stack_trace("Influx MC Stats couldnt name a subsystem, type=[SS.type]") + continue + SSinfluxdriver.enqueue_stats("sstimings", list("ss" = SSname), list("cost" = SS.cost, "tick_overrun" = SS.tick_overrun, "tick_usage" = SS.tick_usage, "wait" = SS.wait)) diff --git a/code/controllers/subsystem/influxstats.dm b/code/controllers/subsystem/influxstats.dm new file mode 100644 index 000000000000..01015b83191d --- /dev/null +++ b/code/controllers/subsystem/influxstats.dm @@ -0,0 +1,156 @@ +/// Sends generic round running statistics to the InfluxDB backend +SUBSYSTEM_DEF(influxstats) + name = "InfluxDB Game Stats" + wait = 60 SECONDS + priority = SS_PRIORITY_INFLUXSTATS + init_order = SS_INIT_INFLUXSTATS + runlevels = RUNLEVEL_LOBBY|RUNLEVELS_DEFAULT + flags = SS_KEEP_TIMING + + var/checkpoint = 0 //! Counter of data snapshots sent + var/step = 1 //! Current task in progress, for pausing/resuming + +/datum/controller/subsystem/influxstats/Initialize() + var/period = text2num(CONFIG_GET(number/influxdb_stats_period)) + if(isnum(period)) + wait = max(period * (1 SECONDS), 10 SECONDS) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/influxstats/stat_entry(msg) + msg += "period=[wait] checkpoint=[checkpoint] step=[step]" + return ..() + +/datum/controller/subsystem/influxstats/fire(resumed) + if(!SSinfluxdriver.can_fire) + can_fire = FALSE + return + + checkpoint++ + while(step < 5) // Yes, you could make one SS per stats category, and have proper scheduling and variable periods, but... + switch(step++) + if(1) // Connected players statistics + run_player_statistics() + if(2) // Job occupations + if(SSticker.current_state == GAME_STATE_PLAYING) + run_job_statistics() + if(3) // Round-wide gameplay statistics held in entity + if(SSticker.current_state == GAME_STATE_PLAYING) + run_round_statistics() + if(4) // Handpicked Round-wide gameplay statistics + if(SSticker.current_state == GAME_STATE_PLAYING) + run_special_round_statistics() + if(MC_TICK_CHECK) + return + + step = 1 + +/datum/controller/subsystem/influxstats/proc/flatten_entity_list(list/data) + var/list/result = list() + for(var/key in data) + var/datum/entity/statistic/entry = data[key] + result[key] = entry.value + return result + +/datum/controller/subsystem/influxstats/proc/run_special_round_statistics() + for(var/hive_tag in GLOB.hive_datum) + var/datum/hive_status/hive = GLOB.hive_datum[hive_tag] + SSinfluxdriver.enqueue_stats("pooled_larva", list("hive" = hive.reporting_id), list("count" = hive.stored_larva)) + var/burst_larvas = GLOB.larva_burst_by_hive[hive] || 0 + SSinfluxdriver.enqueue_stats("burst_larva", list("hive" = hive.reporting_id), list("count" = burst_larvas)) + +/datum/controller/subsystem/influxstats/proc/run_round_statistics() + var/datum/entity/statistic/round/stats = SSticker?.mode?.round_stats + if(!stats) + return // Sadge + + SSinfluxdriver.enqueue_stats_crude("chestbursts", stats.total_larva_burst) + SSinfluxdriver.enqueue_stats_crude("hugged", stats.total_huggers_applied) + SSinfluxdriver.enqueue_stats_crude("friendlyfire", stats.total_friendly_fire_instances) + + var/list/participants = flatten_entity_list(stats.participants) + if(length(participants)) + SSinfluxdriver.enqueue_stats("participants", list(), participants) + + var/list/total_deaths = flatten_entity_list(stats.total_deaths) + if(length(total_deaths)) + SSinfluxdriver.enqueue_stats("deaths", list(), total_deaths) + + SSinfluxdriver.enqueue_stats("shots", list(), + list("fired" = stats.total_projectiles_fired, "hits" = stats.total_projectiles_hit, + "hits_human" = stats.total_projectiles_hit_human, "hits_xeno" = stats.total_projectiles_hit_xeno) + ) + +/datum/controller/subsystem/influxstats/proc/run_player_statistics() + var/staff_count = 0 + var/mentor_count = 0 + for(var/client/client in GLOB.admins) + if(CLIENT_IS_STAFF(client)) + staff_count++ + else if(CLIENT_HAS_RIGHTS(client, R_MENTOR)) + mentor_count++ + SSinfluxdriver.enqueue_stats("online", null, list("count" = length(GLOB.clients))) + + var/list/adm = get_admin_counts() + var/present_admins = length(adm["present"]) + var/afk_admins = length(adm["afk"]) + SSinfluxdriver.enqueue_stats("online_staff", null, list("total" = staff_count, "mentors" = mentor_count, "present" = present_admins, "afk" = afk_admins)) + + // Grab ahelp stats + SSinfluxdriver.enqueue_stats("tickets", null, list( + "open" = length(GLOB.ahelp_tickets.active_tickets), + "closed" = length(GLOB.ahelp_tickets.closed_tickets), + "resolved" = length(GLOB.ahelp_tickets.resolved_tickets), + )) + +/datum/controller/subsystem/influxstats/proc/run_job_statistics() + var/list/team_job_stats = list() + var/list/squad_job_stats = ROLES_SQUAD_ALL.Copy() + for(var/squad in squad_job_stats) + squad_job_stats[squad] = list() + + for(var/client/client in GLOB.clients) + var/team + var/mob/mob = client.mob + if(!mob || mob.statistic_exempt) + continue + var/area/area = get_area(mob) + if(!area || area.statistic_exempt) + continue + var/job = mob.job + if(isobserver(mob) || mob.stat == DEAD) + job = JOB_OBSERVER + team = "observers" + else if(!job) + continue + else if(mob.faction == FACTION_MARINE || mob.faction == FACTION_SURVIVOR) + team = "humans" + var/mob/living/carbon/human/employed_human = mob + if(istype(employed_human)) + var/squad = employed_human.assigned_squad?.name + if(squad in squad_job_stats) + squad_job_stats[squad][job] = (squad_job_stats[squad][job] || 0) + 1 + continue // Defer to squad stats instead + // else: So you're in the USCM and have a job but aren't an human? Tell me more Dr Jones... + else if(ishuman(mob)) + team = "humans_others" + else if(isxeno(mob)) + var/mob/living/xeno_enabled_mob = mob + var/datum/hive_status/hive = GLOB.hive_datum[xeno_enabled_mob.hivenumber] + if(!hive) + team = "xenos_others" + else + team = "xenos_[hive.reporting_id]" + else + team = "others" + LAZYINITLIST(team_job_stats[team]) + if(!team_job_stats[team][job]) + team_job_stats[team][job] = 0 + team_job_stats[team][job] += 1 + + for(var/team in team_job_stats) + for(var/job in team_job_stats[team]) + SSinfluxdriver.enqueue_stats("job_stats", list("team" = team, "job" = job), list("count" = team_job_stats[team][job])) + + for(var/squad in squad_job_stats) + for(var/job in squad_job_stats[squad]) + SSinfluxdriver.enqueue_stats("job_stats", list("team" = "humans", "job" = job, "squad" = squad), list("count" = squad_job_stats[squad][job])) diff --git a/code/datums/statistics/entities/panel_stats.dm b/code/datums/statistics/entities/panel_stats.dm index 44f95f2d91d9..d6e391e1731f 100644 --- a/code/datums/statistics/entities/panel_stats.dm +++ b/code/datums/statistics/entities/panel_stats.dm @@ -741,7 +741,6 @@ "total_projectiles_hit_xeno" = total_projectiles_hit_xeno, "total_slashes" = total_slashes, "total_friendly_fire_instances" = total_friendly_fire_instances, - "total_friendly_fire_kills" = total_friendly_fire_kills, "total_huggers_applied" = total_huggers_applied, "total_larva_burst" = total_larva_burst, "participants" = participants_list, diff --git a/code/datums/statistics/entities/round_stats.dm b/code/datums/statistics/entities/round_stats.dm index ec6aa4ac5bdc..0e1fb6e387db 100644 --- a/code/datums/statistics/entities/round_stats.dm +++ b/code/datums/statistics/entities/round_stats.dm @@ -20,7 +20,6 @@ var/total_projectiles_hit_human = 0 var/total_projectiles_hit_xeno = 0 var/total_friendly_fire_instances = 0 - var/total_friendly_fire_kills = 0 var/total_slashes = 0 // untracked data @@ -360,7 +359,6 @@ stats += "Total shots fired: [total_projectiles_fired]\n" stats += "Total friendly fire instances: [total_friendly_fire_instances]\n" - stats += "Total friendly fire kills: [total_friendly_fire_kills]\n" stats += "Marines remaining: [end_of_round_marines]\n" stats += "Xenos remaining: [end_of_round_xenos]\n" diff --git a/code/modules/mob/living/carbon/xenomorph/Embryo.dm b/code/modules/mob/living/carbon/xenomorph/Embryo.dm index d3c2b725d7ef..8b890de8a727 100644 --- a/code/modules/mob/living/carbon/xenomorph/Embryo.dm +++ b/code/modules/mob/living/carbon/xenomorph/Embryo.dm @@ -272,6 +272,7 @@ if(round_statistics) round_statistics.total_larva_burst++ + GLOB.larva_burst_by_hive[hive] = (GLOB.larva_burst_by_hive[hive] || 0) + 1 burstcount++ if(!larva_embryo.ckey && larva_embryo.burrowable && loc && is_ground_level(loc.z) && (locate(/obj/structure/bed/nest) in loc) && hive.living_xeno_queen && hive.living_xeno_queen.z == loc.z) diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm index 7e1f31e66e67..7506788c2576 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_defines.dm @@ -239,6 +239,9 @@ // Used for the faction of the xenomorph. Not recommended to modify. var/internal_faction + /// Short Hive ID as string used in stats reporting + var/reporting_id = "normal" + var/hivenumber = XENO_HIVE_NORMAL var/mob/living/carbon/xenomorph/queen/living_xeno_queen var/egg_planting_range = 15 @@ -1053,6 +1056,7 @@ /datum/hive_status/corrupted name = "Corrupted Hive" + reporting_id = "corrupted" hivenumber = XENO_HIVE_CORRUPTED prefix = "Corrupted " color = "#80ff80" @@ -1076,6 +1080,7 @@ /datum/hive_status/alpha name = "Alpha Hive" + reporting_id = "alpha" hivenumber = XENO_HIVE_ALPHA prefix = "Alpha " color = "#ff4040" @@ -1086,6 +1091,7 @@ /datum/hive_status/bravo name = "Bravo Hive" + reporting_id = "bravo" hivenumber = XENO_HIVE_BRAVO prefix = "Bravo " color = "#ffff80" @@ -1096,6 +1102,7 @@ /datum/hive_status/charlie name = "Charlie Hive" + reporting_id = "charlie" hivenumber = XENO_HIVE_CHARLIE prefix = "Charlie " color = "#bb40ff" @@ -1106,6 +1113,7 @@ /datum/hive_status/delta name = "Delta Hive" + reporting_id = "delta" hivenumber = XENO_HIVE_DELTA prefix = "Delta " color = "#8080ff" @@ -1116,6 +1124,7 @@ /datum/hive_status/feral name = "Feral Hive" + reporting_id = "feral" hivenumber = XENO_HIVE_FERAL prefix = "Feral " color = "#828296" @@ -1131,6 +1140,7 @@ /datum/hive_status/forsaken name = "Forsaken Hive" + reporting_id = "forsaken" hivenumber = XENO_HIVE_FORSAKEN prefix = "Forsaken " color = "#cc8ec4" @@ -1149,6 +1159,7 @@ /datum/hive_status/yautja name = "Hellhound Pack" + reporting_id = "hellhounds" hivenumber = XENO_HIVE_YAUTJA internal_faction = FACTION_YAUTJA @@ -1165,6 +1176,7 @@ /datum/hive_status/mutated name = "Mutated Hive" + reporting_id = "mutated" hivenumber = XENO_HIVE_MUTATED prefix = "Mutated " color = "#6abd99" @@ -1175,6 +1187,7 @@ /datum/hive_status/corrupted/tamed name = "Tamed Hive" + reporting_id = "tamed" hivenumber = XENO_HIVE_TAMED prefix = "Tamed " color = "#80ff80" diff --git a/colonialmarines.dme b/colonialmarines.dme index ebd73b3544dd..204c144c8916 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -241,6 +241,9 @@ #include "code\controllers\subsystem\htmlui.dm" #include "code\controllers\subsystem\human.dm" #include "code\controllers\subsystem\inactivity.dm" +#include "code\controllers\subsystem\influxdriver.dm" +#include "code\controllers\subsystem\influxmcstats.dm" +#include "code\controllers\subsystem\influxstats.dm" #include "code\controllers\subsystem\input.dm" #include "code\controllers\subsystem\interior.dm" #include "code\controllers\subsystem\item_cleanup.dm" diff --git a/nano/templates/cm_stat_panel.tmpl b/nano/templates/cm_stat_panel.tmpl index 97feebde5971..26de08f17054 100644 --- a/nano/templates/cm_stat_panel.tmpl +++ b/nano/templates/cm_stat_panel.tmpl @@ -159,9 +159,6 @@ Used in: /code/datums/statistics/entities/player_entity.dm
Total Friendly Fire Kills:
-
- {{:data.round.total_friendly_fire_kills}} -
Total Slashes:
From 4ca3edc5eeaa3f1ad8d711696887637199d542c0 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Sat, 1 Jul 2023 03:25:57 +0100 Subject: [PATCH 38/49] Automatic changelog for PR #3601 [ci skip] --- html/changelogs/AutoChangeLog-pr-3601.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3601.yml diff --git a/html/changelogs/AutoChangeLog-pr-3601.yml b/html/changelogs/AutoChangeLog-pr-3601.yml new file mode 100644 index 000000000000..f8efe976ab18 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3601.yml @@ -0,0 +1,4 @@ +author: "fira" +delete-after: True +changes: + - rscadd: "Added InfluxDB backed metrics logging for some of the most used game statistics. This will allow to graph them over time and give better insight as to what happens in rounds." \ No newline at end of file From ddb37366cd9707e6acf655c6729905c43e475244 Mon Sep 17 00:00:00 2001 From: ClairionCM <115504494+ClairionCM@users.noreply.github.com> Date: Sat, 1 Jul 2023 06:23:32 +0200 Subject: [PATCH 39/49] Fixes ranged Vampire Lurker headbiting (#3773) # About the pull request Fixes a bug where lurker headbite would still trigger after a target was moved away during windup by adding a proximity check after the headbite timer. # Explain why it's good for the game fixes #3643 # Changelog :cl: Clairion fix: Vampire Lurker headbite will no longer trigger if the target is moved away during windup. /:cl: --- .../carbon/xenomorph/abilities/lurker/lurker_powers.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm index 0c4ba1f2e86d..b58d94a6ed5b 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_powers.dm @@ -288,6 +288,11 @@ if(!do_after(xeno, 0.8 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_HOSTILE, numticks = 2)) // would be 0.75 but that doesn't really work with numticks return + // To make sure that the headbite does nothing if the target is moved away. + if(!xeno.Adjacent(target_carbon)) + to_chat(xeno, SPAN_XENOHIGHDANGER("You missed! Your target was moved away before you could finish headbiting them!")) + return + if(target_carbon.stat == DEAD) to_chat(xeno, SPAN_XENODANGER("They died before you could finish headbiting them! Be more careful next time!")) return From 22077c8c9d118b986d18973c1f076cde5e24c3e9 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Sat, 1 Jul 2023 05:31:35 +0100 Subject: [PATCH 40/49] Automatic changelog for PR #3773 [ci skip] --- html/changelogs/AutoChangeLog-pr-3773.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3773.yml diff --git a/html/changelogs/AutoChangeLog-pr-3773.yml b/html/changelogs/AutoChangeLog-pr-3773.yml new file mode 100644 index 000000000000..30ca2b7da175 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3773.yml @@ -0,0 +1,4 @@ +author: "Clairion" +delete-after: True +changes: + - bugfix: "Vampire Lurker headbite will no longer trigger if the target is moved away during windup." \ No newline at end of file From 840be46fea3ca37f5f93da56c3bc17218cfb20fb Mon Sep 17 00:00:00 2001 From: Cursor <102828457+theselfish@users.noreply.github.com> Date: Sat, 1 Jul 2023 08:27:23 +0100 Subject: [PATCH 41/49] Makes the MP Beret clickable. (#3622) # About the pull request Title. # Explain why it's good for the game Trying to click a tiny little sprite to take off a piece of headware is bad. Seriously. Other hats that suffer from this that I DID NOT fix because I'm not a spriter and I cannot make new sprites. (This one is from an old version of the dmi file that I had when I made my previous PRs); -Normal and tan berets. -Boonie Hats -Doo-Rags. -Patrol Caps # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: qol: Made the MP beret to be clickable. imageadd: Updated the MP beret obj sprite to be easier to click. /:cl: --- icons/obj/items/clothing/cm_hats.dmi | Bin 44665 -> 49494 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/items/clothing/cm_hats.dmi b/icons/obj/items/clothing/cm_hats.dmi index 33f600015a6f2ffe8ce2cf2e35e35a321721c332..7f798c2cd0bc278bf355977f90a64d45c0ac5af5 100644 GIT binary patch literal 49494 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%0AVg7(Jls$=9UN;n<;H*zrNJkpTB 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 z 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 F`X777jp6_R From ac81e1596f2e752dbdf58424f7b4e3d410146237 Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Sat, 1 Jul 2023 08:36:20 +0100 Subject: [PATCH 42/49] Automatic changelog for PR #3622 [ci skip] --- html/changelogs/AutoChangeLog-pr-3622.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3622.yml diff --git a/html/changelogs/AutoChangeLog-pr-3622.yml b/html/changelogs/AutoChangeLog-pr-3622.yml new file mode 100644 index 000000000000..262dc7e2a99a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3622.yml @@ -0,0 +1,5 @@ +author: "theselfish" +delete-after: True +changes: + - qol: "Made the MP beret to be clickable." + - imageadd: "Updated the MP beret obj sprite to be easier to click." \ No newline at end of file From b00aea01aafba508ef82f79901a208a88251dcd9 Mon Sep 17 00:00:00 2001 From: Cthulhu80 <122310258+Cthulhu80@users.noreply.github.com> Date: Sat, 1 Jul 2023 05:47:02 -0400 Subject: [PATCH 43/49] added camera shake to ob (#3658) # About the pull request Added a camera shake and stun feature based on the user's distance to the OB. This is a copy of an existing branch that I somehow managed to mess up -> https://github.com/cmss13-devs/cmss13/pull/3605 # Explain why it's good for the game OBs should feel like OBs, and adding this feature just helps make OBs feel like an actual large explosion. # Changelog :cl: add: added camera shake and stun to OB. /:cl: --- code/__DEFINES/conflict.dm | 1 + code/modules/admin/tabs/event_tab.dm | 19 ++++++--- code/modules/cm_marines/orbital_cannon.dm | 47 ++++++++++++++++++++++- 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/code/__DEFINES/conflict.dm b/code/__DEFINES/conflict.dm index 09be4793c552..141d69c69b11 100644 --- a/code/__DEFINES/conflict.dm +++ b/code/__DEFINES/conflict.dm @@ -232,6 +232,7 @@ //OB timings #define OB_TRAVEL_TIMING 12 SECONDS #define OB_CRASHING_DOWN 1 SECONDS +#define OB_CLUSTER_DURATION 45 SECONDS //================================================= //Health of various items diff --git a/code/modules/admin/tabs/event_tab.dm b/code/modules/admin/tabs/event_tab.dm index 20d98776c5ab..86f54b510ccf 100644 --- a/code/modules/admin/tabs/event_tab.dm +++ b/code/modules/admin/tabs/event_tab.dm @@ -830,7 +830,6 @@ if(isnull(OBShell.double_explosion_delay)) return statsmessage = "Custom HE OB ([OBShell.name]) Stats from [key_name(usr)]: Clear Power: [OBShell.clear_power], Clear Falloff: [OBShell.clear_falloff], Clear Delay: [OBShell.clear_delay], Blast Power: [OBShell.standard_power], Blast Falloff: [OBShell.standard_falloff], Blast Delay: [OBShell.double_explosion_delay]." warhead = OBShell - qdel(OBShell) if("Custom Cluster") var/obj/structure/ob_ammo/warhead/cluster/OBShell = new OBShell.name = input("What name should the warhead have?", "Set name", "Cluster orbital warhead") @@ -847,7 +846,6 @@ if(isnull(OBShell.explosion_falloff)) return statsmessage = "Custom Cluster OB ([OBShell.name]) Stats from [key_name(usr)]: Salvos: [OBShell.total_amount], Shot per Salvo: [OBShell.instant_amount], Explosion Power: [OBShell.explosion_power], Explosion Falloff: [OBShell.explosion_falloff]." warhead = OBShell - qdel(OBShell) if("Custom Incendiary") var/obj/structure/ob_ammo/warhead/incendiary/OBShell = new OBShell.name = input("What name should the warhead have?", "Set name", "Incendiary orbital warhead") @@ -876,19 +874,28 @@ if(isnull(OBShell.fire_color)) return statsmessage = "Custom Incendiary OB ([OBShell.name]) Stats from [key_name(usr)]: Clear Power: [OBShell.clear_power], Clear Falloff: [OBShell.clear_falloff], Clear Delay: [OBShell.clear_delay], Fire Distance: [OBShell.distance], Fire Duration: [OBShell.fire_level], Fire Strength: [OBShell.burn_level]." warhead = OBShell - qdel(OBShell) if(custom) - if(alert(usr, statsmessage, "Confirm Stats", "Yes", "No") != "Yes") return + if(alert(usr, statsmessage, "Confirm Stats", "Yes", "No") != "Yes") + qdel(warhead) + return message_admins(statsmessage) var/turf/target = get_turf(usr.loc) if(alert(usr, "Fire or Spawn Warhead?", "Mode", "Fire", "Spawn") == "Fire") - if(alert("Are you SURE you want to do this? It will create an OB explosion!",, "Yes", "No") != "Yes") return + if(alert("Are you SURE you want to do this? It will create an OB explosion!",, "Yes", "No") != "Yes") + qdel(warhead) + return + message_admins("[key_name(usr)] has fired \an [warhead.name] at ([target.x],[target.y],[target.z]).") warhead.warhead_impact(target) - QDEL_IN(warhead, OB_CRASHING_DOWN) + + if(istype(warhead, /obj/structure/ob_ammo/warhead/cluster)) + // so the user's screen can shake for the duration of the cluster, otherwise we get a runtime. + QDEL_IN(warhead, OB_CLUSTER_DURATION) + else + QDEL_IN(warhead, OB_CRASHING_DOWN) else warhead.loc = target diff --git a/code/modules/cm_marines/orbital_cannon.dm b/code/modules/cm_marines/orbital_cannon.dm index 14e990809f4f..ad214c954915 100644 --- a/code/modules/cm_marines/orbital_cannon.dm +++ b/code/modules/cm_marines/orbital_cannon.dm @@ -353,6 +353,9 @@ var/list/ob_type_fuel_requirements /obj/structure/ob_ammo/warhead name = "theoretical orbital ammo" var/warhead_kind + var/shake_frequency + var/max_shake_factor + var/max_knockdown_time /obj/structure/ob_ammo/warhead/proc/warhead_impact(turf/target) // make damn sure everyone hears it @@ -398,10 +401,37 @@ var/list/ob_type_fuel_requirements return TRUE return FALSE +/// proc designed for handling ob camera shakes, takes the target location as input and calculates camera shake based off user location. +/obj/structure/ob_ammo/warhead/proc/handle_ob_shake(turf/epicenter) + + var/radius_size = 30 + + for(var/mob/living/user in urange(radius_size, epicenter)) + + var/distance = get_accurate_dist(get_turf(user), epicenter) + var/distance_percent = ((radius_size - distance) / radius_size) + var/total_shake_factor = abs(max_shake_factor * distance_percent) + + // it's of type cluster. + if(!max_knockdown_time) + shake_camera(user, 0.5, total_shake_factor, shake_frequency) + continue + + shake_camera(user, 3, total_shake_factor, shake_frequency) + user.KnockDown(rand(max_knockdown_time * distance_percent, (max_knockdown_time * distance_percent + 1))) + + if(!user.knocked_down) + continue + to_chat(user, SPAN_WARNING("You are thrown off balance and fall to the ground!")) + /obj/structure/ob_ammo/warhead/explosive name = "\improper HE orbital warhead" warhead_kind = "explosive" icon_state = "ob_warhead_1" + shake_frequency = 3 + max_shake_factor = 15 + max_knockdown_time = 6 + var/clear_power = 1200 var/clear_falloff = 400 var/standard_power = 600 @@ -419,16 +449,20 @@ var/list/ob_type_fuel_requirements var/datum/cause_data/cause_data = create_cause_data(initial(name), source_mob) cell_explosion(target, clear_power, clear_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) //break shit around sleep(clear_delay) - //ACTUALLY BLOW SHIT UP + + // Explosion if turf is not a wall. if(!target.density) cell_explosion(target, standard_power, standard_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) + handle_ob_shake(target) sleep(double_explosion_delay) cell_explosion(target, standard_power, standard_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) return + // Checks turf around the target for(var/turf/T in range(2, target)) if(!T.density) cell_explosion(target, standard_power, standard_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) + handle_ob_shake(target) sleep(double_explosion_delay) cell_explosion(target, standard_power, standard_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) return @@ -437,6 +471,9 @@ var/list/ob_type_fuel_requirements name = "\improper Incendiary orbital warhead" warhead_kind = "incendiary" icon_state = "ob_warhead_2" + shake_frequency = 1 + max_shake_factor = 8 + max_knockdown_time = 3 var/clear_power = 1200 var/clear_falloff = 400 var/clear_delay = 3 @@ -457,6 +494,8 @@ var/list/ob_type_fuel_requirements sleep(10) var/datum/cause_data/cause_data = create_cause_data(initial(name), source_mob) cell_explosion(target, clear_power, clear_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) //break shit around + handle_ob_shake(target) + sleep(clear_delay) fire_spread(target, cause_data, distance, fire_level, burn_level, fire_color, fire_type, TURF_PROTECTION_OB) @@ -464,6 +503,9 @@ var/list/ob_type_fuel_requirements name = "\improper Cluster orbital warhead" warhead_kind = "cluster" icon_state = "ob_warhead_3" + shake_frequency = 2 + max_shake_factor = 1 + var/total_amount = 75 // how many times will the shell fire? var/instant_amount = 3 // how many explosions per time it fires? var/explosion_power = 350 @@ -492,11 +534,13 @@ var/list/ob_type_fuel_requirements if(protected_by_pylon(TURF_PROTECTION_OB, U)) //If the turf somehow gained OB protection while the cluster was firing continue fire_in_a_hole(U) + sleep(delay_between_clusters) /obj/structure/ob_ammo/warhead/cluster/proc/fire_in_a_hole(turf/loc) new /obj/effect/overlay/temp/blinking_laser (loc) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), loc, explosion_power, explosion_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)), 1 SECONDS) + addtimer(CALLBACK(src, PROC_REF(handle_ob_shake), loc), 1 SECONDS) /obj/structure/ob_ammo/ob_fuel name = "solid fuel" @@ -607,3 +651,4 @@ var/list/ob_type_fuel_requirements return TRUE tgui_interact(user) + From e9cd8b429c54278d2d44d518277d8213c9756b5e Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Sat, 1 Jul 2023 10:56:12 +0100 Subject: [PATCH 44/49] Automatic changelog for PR #3658 [ci skip] --- html/changelogs/AutoChangeLog-pr-3658.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3658.yml diff --git a/html/changelogs/AutoChangeLog-pr-3658.yml b/html/changelogs/AutoChangeLog-pr-3658.yml new file mode 100644 index 000000000000..f46a1a1b02c2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3658.yml @@ -0,0 +1,4 @@ +author: "Cthulhu80" +delete-after: True +changes: + - rscadd: "added camera shake and stun to OB." \ No newline at end of file From 8f495255db1dc028b743558caf632d16dfb7f93b Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sun, 2 Jul 2023 01:53:04 +0000 Subject: [PATCH 45/49] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-3601.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3622.yml | 5 ----- html/changelogs/AutoChangeLog-pr-3658.yml | 4 ---- html/changelogs/AutoChangeLog-pr-3773.yml | 4 ---- html/changelogs/archive/2023-07.yml | 13 +++++++++++++ 5 files changed, 13 insertions(+), 17 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-3601.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3622.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3658.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-3773.yml diff --git a/html/changelogs/AutoChangeLog-pr-3601.yml b/html/changelogs/AutoChangeLog-pr-3601.yml deleted file mode 100644 index f8efe976ab18..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3601.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "fira" -delete-after: True -changes: - - rscadd: "Added InfluxDB backed metrics logging for some of the most used game statistics. This will allow to graph them over time and give better insight as to what happens in rounds." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3622.yml b/html/changelogs/AutoChangeLog-pr-3622.yml deleted file mode 100644 index 262dc7e2a99a..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3622.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "theselfish" -delete-after: True -changes: - - qol: "Made the MP beret to be clickable." - - imageadd: "Updated the MP beret obj sprite to be easier to click." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3658.yml b/html/changelogs/AutoChangeLog-pr-3658.yml deleted file mode 100644 index f46a1a1b02c2..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3658.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Cthulhu80" -delete-after: True -changes: - - rscadd: "added camera shake and stun to OB." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-3773.yml b/html/changelogs/AutoChangeLog-pr-3773.yml deleted file mode 100644 index 30ca2b7da175..000000000000 --- a/html/changelogs/AutoChangeLog-pr-3773.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Clairion" -delete-after: True -changes: - - bugfix: "Vampire Lurker headbite will no longer trigger if the target is moved away during windup." \ No newline at end of file diff --git a/html/changelogs/archive/2023-07.yml b/html/changelogs/archive/2023-07.yml index 36734311f334..eb01ed3f4007 100644 --- a/html/changelogs/archive/2023-07.yml +++ b/html/changelogs/archive/2023-07.yml @@ -14,3 +14,16 @@ - rscadd: you can no longer implant yourself with a motion detector ihatethisengine: - rscadd: Added cameras to dropship deployable sentries. +2023-07-02: + Clairion: + - bugfix: Vampire Lurker headbite will no longer trigger if the target is moved + away during windup. + Cthulhu80: + - rscadd: added camera shake and stun to OB. + fira: + - rscadd: Added InfluxDB backed metrics logging for some of the most used game statistics. + This will allow to graph them over time and give better insight as to what happens + in rounds. + theselfish: + - qol: Made the MP beret to be clickable. + - imageadd: Updated the MP beret obj sprite to be easier to click. From 51bbd781ad5416e48d4eaafe148f769371eb8b8d Mon Sep 17 00:00:00 2001 From: ghostsheet <43085828+ghostsheet@users.noreply.github.com> Date: Sun, 2 Jul 2023 14:28:11 +1000 Subject: [PATCH 46/49] EB Velocity Bugfix (#3762) # About the pull request Extended barrels are currently bugged, each time you recalculate attachment stats, it gets +1 velocity. This fixes that, no more infinitely building up bullet velocity. # Explain why it's good for the game Bug Bad # Changelog :cl: ghostsheet fix: Fixed Extended Barrel bug of building up free bullet velocity. /:cl: --- code/__DEFINES/weapon_stats.dm | 2 +- code/modules/projectiles/gun.dm | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/code/__DEFINES/weapon_stats.dm b/code/__DEFINES/weapon_stats.dm index 58dad90b0710..bef8413e9615 100644 --- a/code/__DEFINES/weapon_stats.dm +++ b/code/__DEFINES/weapon_stats.dm @@ -1,7 +1,7 @@ #define HUMAN_UNIVERSAL_DAMAGEMULT 1 #define RECOIL_BUILDUP_VIEWPUNCH_MULTIPLIER 0.1 - +#define BASE_VELOCITY_BONUS 0 #define PROJ_BASE_ACCURACY_MULT 0.01 #define PROJ_BASE_DAMAGE_MULT 0.01 diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 5528755cf87c..263f5b07cca4 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -309,6 +309,7 @@ damage_mult = BASE_BULLET_DAMAGE_MULT damage_falloff_mult = DAMAGE_FALLOFF_TIER_10 damage_buildup_mult = DAMAGE_BUILDUP_TIER_1 + velocity_add = BASE_VELOCITY_BONUS recoil = RECOIL_OFF recoil_unwielded = RECOIL_OFF movement_onehanded_acc_penalty_mult = MOVEMENT_ACCURACY_PENALTY_MULT_TIER_1 From b32e80faacde97d6d25714991b810f9ff5e2e05a Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Sun, 2 Jul 2023 05:36:40 +0100 Subject: [PATCH 47/49] Automatic changelog for PR #3762 [ci skip] --- html/changelogs/AutoChangeLog-pr-3762.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3762.yml diff --git a/html/changelogs/AutoChangeLog-pr-3762.yml b/html/changelogs/AutoChangeLog-pr-3762.yml new file mode 100644 index 000000000000..708eac96abb7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3762.yml @@ -0,0 +1,4 @@ +author: "ghostsheet" +delete-after: True +changes: + - bugfix: "Fixed Extended Barrel bug of building up free bullet velocity." \ No newline at end of file From d87e833204462d76534e3b19ff2204f9a19974e6 Mon Sep 17 00:00:00 2001 From: blackdragonTOW <31581761+blackdragonTOW@users.noreply.github.com> Date: Sat, 1 Jul 2023 22:59:47 -0700 Subject: [PATCH 48/49] Dropship Missile Refactor (#3732) # About the pull request Refactors Dropship Missiles to not use Spawn(). # Explain why it's good for the game While proposing a new CAS feature, this part of the code uses a function we shouldn't be using. With a suggestion from Harry I simply swapped out the parts that we could replace without having to do a bigger overhaul. # Testing Photographs and Procedure
Screenshots & Videos Put screenshots and videos here with an empty line between the screenshots and the `
` tags.
# Changelog :cl: refactor: refactored dropship_ammo so that missiles don't use Spawn() /:cl: --- code/modules/cm_marines/dropship_ammo.dm | 29 ++++++++++-------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/code/modules/cm_marines/dropship_ammo.dm b/code/modules/cm_marines/dropship_ammo.dm index b4b585e1de89..3c01688b70d7 100644 --- a/code/modules/cm_marines/dropship_ammo.dm +++ b/code/modules/cm_marines/dropship_ammo.dm @@ -287,9 +287,8 @@ /obj/structure/ship_ammo/rocket/widowmaker/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 300, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) //Your standard HE splash damage rocket. Good damage, good range, good speed, it's an all rounder - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 300, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) //Your standard HE splash damage rocket. Good damage, good range, good speed, it's an all rounder + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/banshee name = "\improper AGM-227 'Banshee'" @@ -301,10 +300,9 @@ /obj/structure/ship_ammo/rocket/banshee/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 175, 20, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) //Small explosive power with a small fall off for a big explosion range - fire_spread(impact, create_cause_data(initial(name), source_mob), 4, 15, 50, "#00b8ff") //Very intense but the fire doesn't last very long - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 175, 20, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) //Small explosive power with a small fall off for a big explosion range + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fire_spread), impact, create_cause_data(initial(name), source_mob), 4, 15, 50, "#00b8ff"), 0.5 SECONDS) //Very intense but the fire doesn't last very long + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/keeper name = "\improper GBU-67 'Keeper II'" @@ -317,9 +315,8 @@ /obj/structure/ship_ammo/rocket/keeper/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 450, 100, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, create_cause_data(initial(name), source_mob)) //Insane fall off combined with insane damage makes the Keeper useful for single targets, but very bad against multiple. - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 450, 100, EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) //Insane fall off combined with insane damage makes the Keeper useful for single targets, but very bad against multiple. + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/harpoon name = "\improper AGM-84 'Harpoon'" @@ -333,9 +330,8 @@ //Looks kinda OP but all it can actually do is just to blow windows and some of other things out, cant do much damage. /obj/structure/ship_ammo/rocket/harpoon/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 150, 16, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 150, 16, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) + QDEL_IN(src, 0.5 SECONDS) /obj/structure/ship_ammo/rocket/napalm name = "\improper XN-99 'Napalm'" @@ -347,10 +343,9 @@ /obj/structure/ship_ammo/rocket/napalm/detonate_on(turf/impact) impact.ceiling_debris_check(3) - spawn(5) - cell_explosion(impact, 200, 25, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name), source_mob)) - fire_spread(impact, create_cause_data(initial(name), source_mob), 6, 60, 30, "#EE6515") //Color changed into napalm's color to better convey how intense the fire actually is. - qdel(src) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), impact, 200, 25, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data(initial(name)), source_mob), 0.5 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(fire_spread), impact, create_cause_data(initial(name), source_mob), 6, 60, 30, "#EE6515"), 0.5 SECONDS) //Color changed into napalm's color to better convey how intense the fire actually is. + QDEL_IN(src, 0.5 SECONDS) From 44fd728fdf249775337ab750682ed730062d50ee Mon Sep 17 00:00:00 2001 From: cm13-github <128137806+cm13-github@users.noreply.github.com> Date: Sun, 2 Jul 2023 07:08:20 +0100 Subject: [PATCH 49/49] Automatic changelog for PR #3732 [ci skip] --- html/changelogs/AutoChangeLog-pr-3732.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-3732.yml diff --git a/html/changelogs/AutoChangeLog-pr-3732.yml b/html/changelogs/AutoChangeLog-pr-3732.yml new file mode 100644 index 000000000000..1fcec99781cb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-3732.yml @@ -0,0 +1,4 @@ +author: "blackdragonTOW" +delete-after: True +changes: + - refactor: "refactored dropship_ammo so that missiles don't use Spawn()" \ No newline at end of file