diff --git a/code/__DEFINES/text.dm b/code/__DEFINES/text.dm index 711ca4cc716..3cffec0521f 100644 --- a/code/__DEFINES/text.dm +++ b/code/__DEFINES/text.dm @@ -21,6 +21,9 @@ /// Simply removes the < and > characters, and limits the length of the message. #define STRIP_HTML_SIMPLE(text, limit) (GLOB.angular_brackets.Replace(copytext(text, 1, limit), "")) +/// Removes everything enclose in < and > inclusive of the bracket, and limits the length of the message. +#define STRIP_HTML_FULL(text, limit) (GLOB.html_tags.Replace(copytext(text, 1, limit), "")) + /// Folder directory for strings #define STRING_DIRECTORY "strings" diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index e8aeafc329a..91837dfb3ea 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -44,6 +44,11 @@ return sanitize(STRIP_HTML_SIMPLE(text, limit)) +/// Runs STRIP_HTML_FULL and sanitize. +/proc/strip_html_full(text, limit = MAX_MESSAGE_LEN) + return sanitize(STRIP_HTML_FULL(text, limit)) + + /// Runs STRIP_HTML_SIMPLE and byond's sanitization proc. /proc/adminscrub(text, limit = MAX_MESSAGE_LEN) return html_encode(STRIP_HTML_SIMPLE(text, limit)) diff --git a/code/_globalvars/_regexes.dm b/code/_globalvars/_regexes.dm index 7e571576213..63d9c73c451 100644 --- a/code/_globalvars/_regexes.dm +++ b/code/_globalvars/_regexes.dm @@ -13,6 +13,9 @@ GLOBAL_DATUM_INIT(has_discord_embeddable_links, /regex, regex("(https?://\[^\\s| //All < and > characters GLOBAL_DATUM_INIT(angular_brackets, /regex, regex(@"[<>]", "g")) +//All characters between < a > inclusive of the bracket +GLOBAL_DATUM_INIT(html_tags, /regex, regex(@"<.*?>", "g")) + //All characters forbidden by filenames: ", \, \n, \t, /, ?, %, *, :, |, <, >, .. GLOBAL_DATUM_INIT(filename_forbidden_chars, /regex, regex(@{""|[\\\n\t/?%*:|<>]|\.\."}, "g")) GLOBAL_PROTECT(filename_forbidden_chars) diff --git a/code/datums/components/shielded.dm b/code/datums/components/shielded.dm index 86364155223..86bcbf5369e 100644 --- a/code/datums/components/shielded.dm +++ b/code/datums/components/shielded.dm @@ -23,6 +23,8 @@ var/shield_inhand = FALSE /// Should the shield lose charges equal to the damage dealt by a hit? var/lose_multiple_charges = FALSE + /// Should the shield's alpha change to show its remaining charge + var/show_charge_as_alpha = FALSE /// The item we use for recharging var/recharge_path /// The cooldown tracking when we were last hit @@ -32,7 +34,7 @@ /// A callback for the sparks/message that play when a charge is used, see [/datum/component/shielded/proc/default_run_hit_callback] var/datum/callback/on_hit_effects -/datum/component/shielded/Initialize(max_charges = 3, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, recharge_path = null, starting_charges = null, shield_icon_file = 'icons/effects/effects.dmi', shield_icon = "shield-old", shield_inhand = FALSE, run_hit_callback) +/datum/component/shielded/Initialize(max_charges = 3, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, show_charge_as_alpha = FALSE, recharge_path = null, starting_charges = null, shield_icon_file = 'icons/effects/effects.dmi', shield_icon = "shield-old", shield_inhand = FALSE, run_hit_callback) if(!isitem(parent) || max_charges <= 0) return COMPONENT_INCOMPATIBLE @@ -41,6 +43,7 @@ src.charge_increment_delay = charge_increment_delay src.charge_recovery = charge_recovery src.lose_multiple_charges = lose_multiple_charges + src.show_charge_as_alpha = show_charge_as_alpha src.recharge_path = recharge_path src.shield_icon_file = shield_icon_file src.shield_icon = shield_icon @@ -132,7 +135,10 @@ /datum/component/shielded/proc/on_update_overlays(atom/parent_atom, list/overlays) SIGNAL_HANDLER - overlays += mutable_appearance(shield_icon_file, (current_charges > 0 ? shield_icon : "broken"), MOB_SHIELD_LAYER) + var/mutable_appearance/shield_appearance = mutable_appearance(shield_icon_file, (current_charges > 0 ? shield_icon : "broken"), MOB_SHIELD_LAYER) + if(show_charge_as_alpha) + shield_appearance.alpha = (current_charges/max_charges)*255 + overlays += shield_appearance /** * This proc fires when we're hit, and is responsible for checking if we're charged, then deducting one + returning that we're blocking if so. diff --git a/code/modules/balloon_alert/balloon_alert.dm b/code/modules/balloon_alert/balloon_alert.dm index b9481969136..b814491e41c 100644 --- a/code/modules/balloon_alert/balloon_alert.dm +++ b/code/modules/balloon_alert/balloon_alert.dm @@ -54,16 +54,12 @@ viewer_client?.images += balloon_alert - var/duration_mult = 1 - var/duration_length = length(text) - BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN - - if(duration_length > 0) - duration_mult += duration_length*BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT + var/length_mult = 1 + max(0, length(strip_html_full(text)) - BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN) * BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT animate( balloon_alert, pixel_y = world.icon_size * 1.2, - time = BALLOON_TEXT_TOTAL_LIFETIME(1), + time = BALLOON_TEXT_TOTAL_LIFETIME(length_mult), easing = SINE_EASING | EASE_OUT, ) @@ -76,7 +72,7 @@ animate( alpha = 0, - time = BALLOON_TEXT_FULLY_VISIBLE_TIME*duration_mult, + time = BALLOON_TEXT_FULLY_VISIBLE_TIME * length_mult, easing = CUBIC_EASING | EASE_IN, ) @@ -84,8 +80,8 @@ // These two timers are not the same // One manages the relation to the atom that spawned us, the other to the client we're displaying to // We could lose our loc, and still need to talk to our client, so they are done seperately - addtimer(CALLBACK(balloon_alert.loc, PROC_REF(forget_balloon_alert), balloon_alert), BALLOON_TEXT_TOTAL_LIFETIME(duration_mult)) - addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_image_from_client), balloon_alert, viewer_client), BALLOON_TEXT_TOTAL_LIFETIME(duration_mult)) + addtimer(CALLBACK(balloon_alert.loc, PROC_REF(forget_balloon_alert), balloon_alert), BALLOON_TEXT_TOTAL_LIFETIME(length_mult)) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_image_from_client), balloon_alert, viewer_client), BALLOON_TEXT_TOTAL_LIFETIME(length_mult)) /atom/proc/forget_balloon_alert(image/balloon_alert) LAZYREMOVE(update_on_z, balloon_alert) diff --git a/code/modules/capture_the_flag/ctf_classes.dm b/code/modules/capture_the_flag/ctf_classes.dm index 50be334aca7..95a61bcf64f 100644 --- a/code/modules/capture_the_flag/ctf_classes.dm +++ b/code/modules/capture_the_flag/ctf_classes.dm @@ -11,7 +11,7 @@ belt = /obj/item/gun/ballistic/automatic/pistol/deagle/ctf l_pocket = /obj/item/ammo_box/magazine/recharge/ctf r_pocket = /obj/item/ammo_box/magazine/recharge/ctf - r_hand = /obj/item/gun/ballistic/automatic/laser/ctf + l_hand = /obj/item/gun/ballistic/automatic/laser/ctf ///Description to be shown in the class selection menu var/class_description = "General purpose combat class. Armed with a laser rifle and backup pistol." @@ -60,7 +60,7 @@ /datum/outfit/ctf/instagib name = "CTF Instagib (Solo)" - r_hand = /obj/item/gun/energy/laser/instakill/ctf + l_hand = /obj/item/gun/energy/laser/instakill/ctf shoes = /obj/item/clothing/shoes/jackboots/fast icon_state = "ctf_instakill" class_description = "General purpose combat class. Armed with a laser rifle and backup pistol." @@ -68,7 +68,7 @@ /datum/outfit/ctf/assault name = "CTF Assaulter (Solo)" suit = /obj/item/clothing/suit/armor/vest/ctf/light - r_hand = /obj/item/gun/ballistic/shotgun/ctf + l_hand = /obj/item/gun/ballistic/shotgun/ctf gloves = /obj/item/clothing/gloves/tackler/rocket l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun @@ -78,7 +78,7 @@ /datum/outfit/ctf/marksman name = "CTF Marksman (Solo)" - r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman + l_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman belt = null @@ -90,7 +90,7 @@ /datum/outfit/ctf/red name = "CTF Rifleman (Red)" suit = /obj/item/clothing/suit/armor/vest/ctf/red - r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/red + l_hand = /obj/item/gun/ballistic/automatic/laser/ctf/red l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/red r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/red id = /obj/item/card/id/red //it's red @@ -98,14 +98,14 @@ /datum/outfit/ctf/red/instagib name = "CTF Instagib (Red)" - r_hand = /obj/item/gun/energy/laser/instakill/ctf/red + l_hand = /obj/item/gun/energy/laser/instakill/ctf/red shoes = /obj/item/clothing/shoes/jackboots/fast team_radio_freq = FREQ_CTF_RED /datum/outfit/ctf/assault/red name = "CTF Assaulter (Red)" suit = /obj/item/clothing/suit/armor/vest/ctf/light/red - r_hand = /obj/item/gun/ballistic/shotgun/ctf/red + l_hand = /obj/item/gun/ballistic/shotgun/ctf/red l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/red r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/red id = /obj/item/card/id/red @@ -114,7 +114,7 @@ /datum/outfit/ctf/marksman/red name = "CTF Marksman (Red)" suit = /obj/item/clothing/suit/armor/vest/ctf/red - r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/red + l_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/red l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/red r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/red id = /obj/item/card/id/red @@ -125,7 +125,7 @@ /datum/outfit/ctf/blue name = "CTF Rifleman (Blue)" suit = /obj/item/clothing/suit/armor/vest/ctf/blue - r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/blue + l_hand = /obj/item/gun/ballistic/automatic/laser/ctf/blue l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/blue r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/blue id = /obj/item/card/id/blue //it's blue @@ -133,14 +133,14 @@ /datum/outfit/ctf/blue/instagib name = "CTF Instagib (Blue)" - r_hand = /obj/item/gun/energy/laser/instakill/ctf/blue + l_hand = /obj/item/gun/energy/laser/instakill/ctf/blue shoes = /obj/item/clothing/shoes/jackboots/fast team_radio_freq = FREQ_CTF_BLUE /datum/outfit/ctf/assault/blue name = "CTF Assaulter (Blue)" suit = /obj/item/clothing/suit/armor/vest/ctf/light/blue - r_hand = /obj/item/gun/ballistic/shotgun/ctf/blue + l_hand = /obj/item/gun/ballistic/shotgun/ctf/blue l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/blue r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/blue id = /obj/item/card/id/blue @@ -149,7 +149,7 @@ /datum/outfit/ctf/marksman/blue name = "CTF Marksman (Blue)" suit = /obj/item/clothing/suit/armor/vest/ctf/blue - r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/blue + l_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/blue l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/blue r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/blue id = /obj/item/card/id/blue @@ -160,7 +160,7 @@ /datum/outfit/ctf/green name = "CTF Rifleman (Green)" suit = /obj/item/clothing/suit/armor/vest/ctf/green - r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/green + l_hand = /obj/item/gun/ballistic/automatic/laser/ctf/green l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/green r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/green id = /obj/item/card/id/green //it's green @@ -168,14 +168,14 @@ /datum/outfit/ctf/green/instagib name = "CTF Instagib (Green)" - r_hand = /obj/item/gun/energy/laser/instakill/ctf/green + l_hand = /obj/item/gun/energy/laser/instakill/ctf/green shoes = /obj/item/clothing/shoes/jackboots/fast team_radio_freq = FREQ_CTF_GREEN /datum/outfit/ctf/assault/green name = "CTF Assaulter (Green)" suit = /obj/item/clothing/suit/armor/vest/ctf/light/green - r_hand = /obj/item/gun/ballistic/shotgun/ctf/green + l_hand = /obj/item/gun/ballistic/shotgun/ctf/green l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/green r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/green id = /obj/item/card/id/green @@ -184,7 +184,7 @@ /datum/outfit/ctf/marksman/green name = "CTF Marksman (Green)" suit = /obj/item/clothing/suit/armor/vest/ctf/green - r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/green + l_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/green l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/green r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/green id = /obj/item/card/id/green @@ -195,7 +195,7 @@ /datum/outfit/ctf/yellow name = "CTF Rifleman (Yellow)" suit = /obj/item/clothing/suit/armor/vest/ctf/yellow - r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/yellow + l_hand = /obj/item/gun/ballistic/automatic/laser/ctf/yellow l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/yellow r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/rifle/yellow id = /obj/item/card/id/yellow //it's yellow @@ -203,14 +203,14 @@ /datum/outfit/ctf/yellow/instagib name = "CTF Instagib (Yellow)" - r_hand = /obj/item/gun/energy/laser/instakill/ctf/yellow + l_hand = /obj/item/gun/energy/laser/instakill/ctf/yellow shoes = /obj/item/clothing/shoes/jackboots/fast team_radio_freq = FREQ_CTF_YELLOW /datum/outfit/ctf/assault/yellow name = "CTF Assaulter (Yellow)" suit = /obj/item/clothing/suit/armor/vest/ctf/light/yellow - r_hand = /obj/item/gun/ballistic/shotgun/ctf/yellow + l_hand = /obj/item/gun/ballistic/shotgun/ctf/yellow l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/yellow r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/shotgun/yellow id = /obj/item/card/id/yellow @@ -219,7 +219,7 @@ /datum/outfit/ctf/marksman/yellow name = "CTF Marksman (Yellow)" suit = /obj/item/clothing/suit/armor/vest/ctf/yellow - r_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/yellow + l_hand = /obj/item/gun/ballistic/automatic/laser/ctf/marksman/yellow l_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/yellow r_pocket = /obj/item/ammo_box/magazine/recharge/ctf/marksman/yellow id = /obj/item/card/id/yellow diff --git a/code/modules/capture_the_flag/ctf_equipment.dm b/code/modules/capture_the_flag/ctf_equipment.dm index 13109488c05..2ff0cf9b447 100644 --- a/code/modules/capture_the_flag/ctf_equipment.dm +++ b/code/modules/capture_the_flag/ctf_equipment.dm @@ -206,9 +206,19 @@ ///Icon state to be fed into the shielded component var/team_shield_icon = "shield-old" + var/max_charges = 150 + var/recharge_start_delay = 20 SECONDS + var/charge_increment_delay = 1 SECONDS + var/charge_recovery = 30 + var/lose_multiple_charges = TRUE + var/show_charge_as_alpha = TRUE -/obj/item/clothing/suit/armor/vest/ctf/setup_shielding() - AddComponent(/datum/component/shielded, max_charges = 150, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 30, lose_multiple_charges = TRUE, shield_icon = team_shield_icon) +/obj/item/clothing/suit/armor/vest/ctf/equipped(mob/user, slot) + . = ..() + if(!slot || slot & ITEM_SLOT_HANDS) + return + AddComponent(/datum/component/shielded, max_charges = max_charges, recharge_start_delay = recharge_start_delay, charge_increment_delay = charge_increment_delay, \ + charge_recovery = charge_recovery, lose_multiple_charges = lose_multiple_charges, show_charge_as_alpha = show_charge_as_alpha, shield_icon = team_shield_icon) // LIGHT SHIELDED VEST @@ -220,8 +230,7 @@ greyscale_config_worn = /datum/greyscale_config/ctf_light_worn slowdown = -0.25 -/obj/item/clothing/suit/armor/vest/ctf/light/setup_shielding() - AddComponent(/datum/component/shielded, max_charges = 30, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 30, lose_multiple_charges = TRUE, shield_icon = team_shield_icon) + max_charges = 30 // RED TEAM GUNS diff --git a/code/modules/capture_the_flag/ctf_game.dm b/code/modules/capture_the_flag/ctf_game.dm index b9ce443ce47..d9be15db3cc 100644 --- a/code/modules/capture_the_flag/ctf_game.dm +++ b/code/modules/capture_the_flag/ctf_game.dm @@ -240,6 +240,7 @@ desc = "Used for running friendly games of capture the flag." icon = 'icons/obj/device.dmi' icon_state = "syndbeacon" + density = TRUE resistance_flags = INDESTRUCTIBLE var/game_id = CTF_GHOST_CTF_GAME_ID @@ -377,7 +378,7 @@ var/client/new_team_member = user.client team_members |= new_team_member.ckey - to_chat(user, "You are now a member of [src.team]. Get the enemy flag and bring it back to your team's controller!") + to_chat(user, "You are now a member of [src.team]. Get the enemy flag and bring it back to your team's controller!") spawn_team_member(new_team_member) @@ -423,7 +424,8 @@ //there isn't a game going on any more, you are no longer a member of this team (perhaps a new match already started?) chosen_class = ctf_gear[choice] - var/mob/living/carbon/human/M = new /mob/living/carbon/human(get_turf(src)) + var/turf/spawn_point = pick(get_adjacent_open_turfs(get_turf(src))) + var/mob/living/carbon/human/M = new /mob/living/carbon/human(spawn_point) new_team_member.prefs.safe_transfer_prefs_to(M, is_antag = TRUE) if(M.dna.species.outfit_important_for_life) M.set_species(/datum/species/human) @@ -640,6 +642,15 @@ if(controlling.control_points >= controlling.control_points_to_win) controlling.victory() + var/scores + + for(var/obj/machinery/capture_the_flag/team as anything in GLOB.ctf_panel.ctf_machines) + if (!team.ctf_enabled) + continue + scores += UNLINT("[team.team] - [team.control_points]/[team.control_points_to_win]\n") + + balloon_alert_to_viewers(scores) + /obj/machinery/control_point/attackby(mob/user, params) capture(user) @@ -651,14 +662,14 @@ /obj/machinery/control_point/proc/capture(mob/user) if(do_after(user, 30, target = src)) - for(var/obj/machinery/capture_the_flag/CTF as anything in GLOB.ctf_panel.ctf_machines) - if(CTF.ctf_enabled && (user.ckey in CTF.team_members)) - controlling = CTF - icon_state = "dominator-[CTF.team]" + for(var/obj/machinery/capture_the_flag/team as anything in GLOB.ctf_panel.ctf_machines) + if(team.ctf_enabled && (user.ckey in team.team_members)) + controlling = team + icon_state = "dominator-[team.team]" for(var/mob/M in GLOB.player_list) var/area/mob_area = get_area(M) if(istype(mob_area, game_area)) - to_chat(M, span_userdanger("[user.real_name] has captured \the [src], claiming it for [CTF.team]! Go take it back!")) + to_chat(M, "[user.real_name] has captured \the [src], claiming it for [team.team]! Go take it back!") break /proc/is_ctf_target(atom/target) diff --git a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss index 2e1e100b53c..b32181b8e13 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss @@ -371,19 +371,19 @@ em { } .redteamradio { - color: #ff4444; + color: #ff4444 !important; } .blueteamradio { - color: #3434fd; + color: #3434fd !important; } .greenteamradio { - color: #34fd34; + color: #34fd34 !important; } .yellowteamradio { - color: #fdfd34; + color: #fdfd34 !important; } .yell { diff --git a/tgui/packages/tgui-panel/styles/goon/chat-light.scss b/tgui/packages/tgui-panel/styles/goon/chat-light.scss index f29871ab9d5..44fbdc37411 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-light.scss @@ -388,19 +388,19 @@ em { } .redteamradio { - color: #ff0000; + color: #ff0000 !important; } .blueteamradio { - color: #0000ff; + color: #0000ff !important; } .greenteamradio { - color: #00ff00; + color: #00ff00 !important; } .yellowteamradio { - color: #d1ba22; + color: #d1ba22 !important; } .yell {