diff --git a/code/__DEFINES/span.dm b/code/__DEFINES/span.dm index f47881fd65b..fd95f3a6182 100644 --- a/code/__DEFINES/span.dm +++ b/code/__DEFINES/span.dm @@ -44,6 +44,7 @@ #define span_greenannounce(str) ("" + str + "") #define span_greenteamradio(str) ("" + str + "") #define span_greentext(str) ("" + str + "") +#define span_gangradio(str) ("" + str + "") #define span_hear(str) ("" + str + "") #define span_hidden(str) ("") #define span_hierophant(str) ("" + str + "") diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index faf3e6a3db1..0232cff4d36 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -138,6 +138,8 @@ #define STATUS_EFFECT_OFFERING /datum/status_effect/offering // you are offering up an item to people +#define STATUS_EFFECT_HANDSHAKE /datum/status_effect/offering/secret_handshake // you are attempting to perform a secret Family handshake + #define STATUS_EFFECT_SURRENDER /datum/status_effect/grouped/surrender // gives an alert to quickly surrender #define STATUS_EFFECT_EIGEN /datum/status_effect/eigenstasium diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index a4cf2d93a8c..588304a105f 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -399,6 +399,19 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." if(!receiving) examine_list += "[span_warning("[offerer]'s arm appears tensed up, as if [offerer.p_they()] plan on pulling it back suddenly...")]\n" +/atom/movable/screen/alert/give/secret_handshake + icon_state = "default" + +/atom/movable/screen/alert/give/secret_handshake/setup(mob/living/carbon/taker, mob/living/carbon/offerer, obj/item/receiving) + name = "[offerer] is offering a Handshake" + desc = "[offerer] wants to teach you the Secret Handshake for their Family and induct you! Click on this alert to accept." + icon_state = "template" + cut_overlays() + add_overlay(receiving) + src.receiving = receiving + src.offerer = offerer + RegisterSignal(taker, COMSIG_MOVABLE_MOVED, .proc/check_in_range, override = TRUE) //Override to prevent runtimes when people offer a item multiple times + /// Gives the player the option to succumb while in critical condition /atom/movable/screen/alert/succumb name = "Succumb" diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 1cb77589444..24c57e3ffca 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -168,7 +168,6 @@ . = ..() if(!.) return - offered_item = offer if(give_alert_override) give_alert_type = give_alert_override @@ -232,6 +231,10 @@ SIGNAL_HANDLER qdel(src) +/datum/status_effect/offering/secret_handshake + id = "secret_handshake" + give_alert_type = /atom/movable/screen/alert/give/secret_handshake + //this effect gives the user an alert they can use to surrender quickly /datum/status_effect/grouped/surrender id = "surrender" diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm index fff1ba0d52e..7a1f89901d0 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm @@ -251,15 +251,13 @@ antag_flag = ROLE_FAMILY_HEAD_ASPIRANT antag_flag_override = ROLE_FAMILIES protected_roles = list("Prisoner", "Head of Personnel") - restricted_roles = list("Cyborg", "AI", "Security Officer", "Warden", "Detective", "Head of Security", "Captain") - required_candidates = 6 // gotta have 'em ALL - weight = 1 - cost = 25 - requirements = list(101,101,101,101,101,80,50,30,10,10) + restricted_roles = list("Cyborg", "AI", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Research Director") + required_candidates = 9 + weight = 2 + cost = 19 + requirements = list(101,101,40,40,30,20,10,10,10,10) flags = HIGH_IMPACT_RULESET blocking_rules = list(/datum/dynamic_ruleset/roundstart/families) - minimum_players = 36 - antag_cap = 6 /// A reference to the handler that is used to run pre_execute(), execute(), etc.. var/datum/gang_handler/handler @@ -276,11 +274,6 @@ else if(HAS_TRAIT(player, TRAIT_MINDSHIELD)) candidates -= player -/datum/dynamic_ruleset/midround/families/acceptable(population = 0, threat_level = 0) - . = ..() - if(GLOB.deaths_during_shift > round(mode.roundstart_pop_ready / 2)) - return FALSE - /datum/dynamic_ruleset/midround/families/ready(forced = FALSE) if (required_candidates > living_players.len) @@ -290,7 +283,6 @@ /datum/dynamic_ruleset/midround/families/pre_execute() ..() handler = new /datum/gang_handler(candidates,restricted_roles) - handler.gangs_to_generate = (antag_cap[indice_pop] / 2) handler.gang_balance_cap = clamp((indice_pop - 3), 2, 5) // gang_balance_cap by indice_pop: (2,2,2,2,2,3,4,5,5,5) handler.midround_ruleset = TRUE handler.use_dynamic_timing = TRUE @@ -861,7 +853,7 @@ required_enemies = list(2,2,1,1,1,1,1,0,0,0) required_candidates = 1 weight = 4 - cost = 3 // Doesn't have the same impact on rounds as revenants, dragons, sentient disease (10) or syndicate infiltrators (5). + cost = 3 // Doesn't have the same impact on rounds as revenants, dragons, sentient disease (10) or syndicate infiltrators (5). requirements = list(101,101,101,80,60,50,30,20,10,10) repeatable = TRUE diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 3c7574bd314..eb1a43eadcf 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -495,21 +495,18 @@ antag_datum = /datum/antagonist/gang antag_flag = ROLE_FAMILIES protected_roles = list("Prisoner", "Head of Personnel") - restricted_roles = list("Cyborg", "AI", "Security Officer", "Warden", "Detective", "Head of Security", "Captain") - required_candidates = 6 // gotta have 'em ALL - weight = 2 - cost = 30 - requirements = list(101,101,101,101,101,70,40,10,10,10) + restricted_roles = list("Cyborg", "AI", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Research Director") + required_candidates = 9 + weight = 1 + cost = 19 + requirements = list(101,101,40,40,30,20,10,10,10,10) flags = HIGH_IMPACT_RULESET - minimum_players = 36 - antag_cap = 6 /// A reference to the handler that is used to run pre_execute(), execute(), etc.. var/datum/gang_handler/handler /datum/dynamic_ruleset/roundstart/families/pre_execute(population) ..() handler = new /datum/gang_handler(candidates,restricted_roles) - handler.gangs_to_generate = (get_antag_cap(population) / 2) handler.gang_balance_cap = clamp((indice_pop - 3), 2, 5) // gang_balance_cap by indice_pop: (2,2,2,2,2,3,4,5,5,5) handler.use_dynamic_timing = TRUE return handler.pre_setup_analogue() diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index dbc9ca7a8b7..0d0f4c08a91 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -320,6 +320,74 @@ SEND_SIGNAL(taker, COMSIG_ADD_MOOD_EVENT, "high_five", /datum/mood_event/high_five) qdel(src) +/// Gangster secret handshakes. +/obj/item/slapper/secret_handshake + name = "Secret Handshake" + icon_state = "recruit" + icon = 'icons/obj/gang/actions.dmi' + /// References the active families gamemode handler (if one exists), for adding new family members to. + var/datum/gang_handler/handler + /// The typepath of the gang antagonist datum that the person who uses the package should have added to them -- remember that the distinction between e.g. Ballas and Grove Street is on the antag datum level, not the team datum level. + var/gang_to_use + /// The team datum that the person who uses this package should be added to. + var/datum/team/gang/team_to_use + + +/// Adds the user to the family that this package corresponds to, dispenses the free_clothes of that family, and adds them to the handler if it exists. +/obj/item/slapper/secret_handshake/proc/add_to_gang(mob/living/user, original_name) + var/datum/antagonist/gang/swappin_sides = new gang_to_use() + swappin_sides.original_name = original_name + swappin_sides.handler = handler + user.mind.add_antag_datum(swappin_sides, team_to_use) + var/policy = get_policy(ROLE_FAMILIES) + if(policy) + to_chat(user, policy) + team_to_use.add_member(user.mind) + swappin_sides.equip_gangster_in_inventory() + if (!isnull(handler) && !handler.gangbangers.Find(user.mind)) // if we have a handler and they're not tracked by it + handler.gangbangers += user.mind + +/// Checks if the user is trying to use the package of the family they are in, and if not, adds them to the family, with some differing processing depending on whether the user is already a family member. +/obj/item/slapper/secret_handshake/proc/attempt_join_gang(mob/living/user) + if(!user?.mind) + return + var/datum/antagonist/gang/is_gangster = user.mind.has_antag_datum(/datum/antagonist/gang) + var/real_name_backup = user.real_name + if(is_gangster) + if(is_gangster.my_gang == team_to_use) + return + real_name_backup = is_gangster.original_name + is_gangster.my_gang.remove_member(user.mind) + user.mind.remove_antag_datum(/datum/antagonist/gang) + add_to_gang(user, real_name_backup) + +/obj/item/slapper/secret_handshake/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker) + . = TRUE + if (!(null in taker.held_items)) + to_chat(taker, span_warning("You can't get taught the secret handshake if [offerer] has no free hands!")) + return + + if(HAS_TRAIT(taker, TRAIT_MINDSHIELD)) + to_chat(taker, "You attended a seminar on not signing up for a gang and are not interested.") + return + + var/datum/antagonist/gang/is_gangster = taker.mind.has_antag_datum(/datum/antagonist/gang) + if(is_gangster?.starter_gangster) + if(is_gangster.my_gang == team_to_use) + to_chat(taker, "You started your family. You don't need to join it.") + return + to_chat(taker, "You started your family. You can't turn your back on it now.") + return + + offerer.visible_message(span_notice("[taker] is taught the secret handshake by [offerer]!"), span_nicegreen("All right! You've taught the secret handshake to [taker]!"), span_hear("You hear a bunch of weird shuffling and flesh slapping sounds!"), ignored_mobs=taker) + to_chat(taker, span_nicegreen("You get taught the secret handshake by [offerer]!")) + var/datum/antagonist/gang/owner_gang_datum = offerer.mind.has_antag_datum(/datum/antagonist/gang) + handler = owner_gang_datum.handler + gang_to_use = owner_gang_datum.type + team_to_use = owner_gang_datum.my_gang + attempt_join_gang(taker) + qdel(src) + /obj/item/kisser diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index a466ad54667..58b11df0992 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -305,6 +305,7 @@ ROLE_BROTHER, ROLE_CHANGELING, ROLE_CULTIST, + ROLE_FAMILIES, ROLE_HERETIC, ROLE_HIVE, ROLE_INTERNAL_AFFAIRS, diff --git a/code/modules/antagonists/gang/cellphone.dm b/code/modules/antagonists/gang/cellphone.dm new file mode 100644 index 00000000000..d5413f309c9 --- /dev/null +++ b/code/modules/antagonists/gang/cellphone.dm @@ -0,0 +1,61 @@ +GLOBAL_LIST_EMPTY(gangster_cell_phones) + +/obj/item/gangster_cellphone + name = "cell phone" + desc = "TODO: funny joke about the 80s, brick phones" + icon = 'icons/obj/gang/cell_phone.dmi' + icon_state = "phone_off" + throwforce = 15 // these things are dense as fuck + var/gang_id = "Grove Street Families" + var/activated = FALSE + +/obj/item/gangster_cellphone/Initialize() + . = ..() + GLOB.gangster_cell_phones += src + become_hearing_sensitive() + +/obj/item/gangster_cellphone/Destroy() + GLOB.gangster_cell_phones -= src + . = ..() + +/obj/item/gangster_cellphone/attack_self(mob/user, modifiers) + . = ..() + if(!activated) + to_chat(user, "You turn on [src].") + icon_state = "phone_on" + activated = TRUE + else + to_chat(user, "You turn off [src].") + icon_state = "phone_off" + activated = FALSE + +/obj/item/gangster_cellphone/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods) + . = ..() + if(!activated) + return + if(get_turf(speaker) != get_turf(src)) + return + broadcast_message(raw_message, speaker) + +/obj/item/gangster_cellphone/proc/broadcast_message(message, atom/movable/speaker) + for(var/obj/item/gangster_cellphone/brick in GLOB.gangster_cell_phones) + if(brick.gang_id == gang_id) + brick.say_message(message, speaker) + for(var/mob/dead/observer/player_mob in GLOB.player_list) + if(!istype(player_mob, /mob/dead/observer)) + continue + if(QDELETED(player_mob)) //Some times nulls and deleteds stay in this list. This is a workaround to prevent ic chat breaking for everyone when they do. + continue //Remove if underlying cause (likely byond issue) is fixed. See TG PR #49004. + if(player_mob.stat != DEAD) //not dead, not important + continue + if(get_dist(player_mob, src) > 7 || player_mob.z != z) //they're out of range of normal hearing + if(!(player_mob.client.prefs.chat_toggles & CHAT_GHOSTEARS)) //they're talking normally and we have hearing at any range off + continue + to_chat(player_mob, span_gangradio("[speaker.name] \[CELL: [gang_id]\] says, \"[message]\"")) + +/obj/item/gangster_cellphone/proc/say_message(message, atom/movable/speaker) + for(var/mob/living/carbon/human/cellphone_hearer in get_turf(src)) + if(HAS_TRAIT(cellphone_hearer, TRAIT_DEAF)) + continue + to_chat(cellphone_hearer, span_gangradio("[speaker.name] \[CELL: [gang_id]\] says, \"[message]\"")) + diff --git a/code/modules/antagonists/gang/gang.dm b/code/modules/antagonists/gang/gang.dm index 58476132c3f..62502266f81 100644 --- a/code/modules/antagonists/gang/gang.dm +++ b/code/modules/antagonists/gang/gang.dm @@ -1,6 +1,7 @@ /datum/antagonist/gang name = "Family Member" roundend_category = "gangsters" + ui_name = "AntagInfoGangmember" antag_hud_type = ANTAG_HUD_GANGSTER antag_hud_name = "hud_gangster" antagpanel_category = "Family" @@ -19,14 +20,22 @@ var/list/free_clothes = list() /// The action used to spawn family induction packages. var/datum/action/cooldown/spawn_induction_package/package_spawner = new() - /// The textual description of the family's overarching objective. - var/gang_objective = "Be super cool and stuff." /// Whether or not this family member is the first of their family. var/starter_gangster = FALSE + /// The gangster's original real name. Used for renaming stuff, kept between gang switches. + var/original_name + /// Type of team to create when creating the gang in the first place. Used for renames. + var/gang_team_type = /datum/team/gang /// A reference to the handler datum that manages the families gamemode. In case of no handler (admin-spawned during round), this will be null; this is fine. var/datum/gang_handler/handler +/datum/outfit/gangster + name = "Gangster (Preview only)" + + uniform = /obj/item/clothing/under/suit/henchmen + back = /obj/item/storage/backpack/henchmen + /datum/antagonist/gang/get_team() return my_gang @@ -45,19 +54,19 @@ if we don't have a "handler" var, and a gang_handler exists, we need to grab it, since our "handler" is null. if the gang exists, we need to join it; if the gang doesn't exist, we need to make it. */ var/found_gang = FALSE - if(!starter_gangster) // if they're a starter gangster according to the handler, we don't need to check this shit - for(var/datum/team/gang/G in GLOB.antagonist_teams) - if(G.my_gang_datum.handler) // if one of the gangs in the gang list has a handler, nab that - handler = G.my_gang_datum.handler - if(G.name == gang_name) - my_gang = G - found_gang = TRUE - break + for(var/datum/team/gang/gang_team in GLOB.antagonist_teams) + if(gang_team.my_gang_datum.handler) // if one of the gangs in the gang list has a handler, nab that + handler = gang_team.my_gang_datum.handler + if(gang_team.name == gang_name) + my_gang = gang_team + found_gang = TRUE + break if(!found_gang) - var/new_gang = new /datum/team/gang() + var/new_gang = new gang_team_type() my_gang = new_gang if(handler) // if we have a handler, the handler should track this gang handler.gangs += my_gang + my_gang.current_theme = handler.current_theme my_gang.name = gang_name my_gang.gang_id = gang_id my_gang.acceptable_clothes = acceptable_clothes.Copy() @@ -66,8 +75,13 @@ starter_gangster = TRUE /datum/antagonist/gang/on_gain() + if(!original_name) + original_name = owner.current.real_name + my_gang.rename_gangster(owner, original_name, starter_gangster) // fully_replace_character_name if(starter_gangster) equip_gangster_in_inventory() + var/datum/atom_hud/gang_hud = GLOB.huds[ANTAG_HUD_GANGSTER] + gang_hud.add_hud_to(owner.current) owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/thatshowfamiliesworks.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE) ..() @@ -81,69 +95,77 @@ have that datum onhand. it would be easier if all of the code the gang team calls on its my_gang_datum was just in the team datum itself, and there were different types of teams instead of different types of gangster that imprint on generic teams, but i'm too lazy to refactor THAT too */ + var/datum/atom_hud/gang_hud = GLOB.huds[ANTAG_HUD_GANGSTER] + gang_hud.remove_hud_from(owner.current) ..() -/datum/antagonist/gang/greet() - to_chat(owner.current, "As you're the first gangster, your uniform and spraycan are in your inventory!") - - to_chat(owner.current, "[gang_name] for life!") - to_chat(owner.current, "You're a member of the [gang_name] now!
Tag turf with a spraycan, wear your group's colors, and recruit more gangsters with the Induction Packages!
") - to_chat(owner.current, "You are still a team-oriented antagonist! Do what is best for your gang.") - to_chat(owner.current, "Beware, killing innocents will result in a stronger police response.") - to_chat(owner.current, "Family's Objective: [gang_objective]") - /datum/antagonist/gang/apply_innate_effects(mob/living/mob_override) ..() - package_spawner.Grant(owner.current) - package_spawner.my_gang_datum = src + if(starter_gangster) + package_spawner.Grant(owner.current) + package_spawner.my_gang_datum = src var/mob/living/M = mob_override || owner.current add_antag_hud(antag_hud_type, antag_hud_name, M) - if(M.hud_used) - var/datum/hud/H = M.hud_used - var/atom/movable/screen/wanted/giving_wanted_lvl = new /atom/movable/screen/wanted() - H.wanted_lvl = giving_wanted_lvl - giving_wanted_lvl.hud = H - H.infodisplay += giving_wanted_lvl - H.mymob.client.screen += giving_wanted_lvl /datum/antagonist/gang/remove_innate_effects(mob/living/mob_override) - package_spawner.Remove(owner.current) + if(starter_gangster) + package_spawner.Remove(owner.current) var/mob/living/M = mob_override || owner.current remove_antag_hud(antag_hud_type, M) - if(M.hud_used) - var/datum/hud/H = M.hud_used - H.infodisplay -= H.wanted_lvl - QDEL_NULL(H.wanted_lvl) ..() -/// Passes points gained to the family team. -/datum/antagonist/gang/proc/add_gang_points(points_to_add) - if(my_gang) - my_gang.adjust_points(points_to_add) - -/// Determines if a gang has completed their special objective. -/datum/antagonist/gang/proc/check_gang_objective() - return TRUE - /// Gives a gangster their equipment in their backpack and / or pockets. /datum/antagonist/gang/proc/equip_gangster_in_inventory() if(istype(owner.current, /mob/living/carbon/human)) - for(var/C in my_gang.free_clothes) - var/obj/O = new C(owner.current) - var/list/slots = list ( - "backpack" = ITEM_SLOT_BACKPACK, - "left pocket" = ITEM_SLOT_LPOCKET, - "right pocket" = ITEM_SLOT_RPOCKET - ) - var/mob/living/carbon/human/H = owner.current - var/equipped = H.equip_in_one_of_slots(O, slots) + var/obj/item/gangster_cellphone/phone = new() + phone.gang_id = gang_name + phone.name = "[gang_name] branded cell phone" + var/mob/living/carbon/human/gangster_human = owner.current + var/phone_equipped = phone.equip_to_best_slot(gangster_human) + if(!phone_equipped) + to_chat(owner.current, "Your [phone.name] has been placed at your feet.") + phone.forceMove(get_turf(gangster_human)) + for(var/clothing in my_gang.free_clothes) + var/obj/item/clothing_object = new clothing(owner.current) + var/equipped = clothing_object.equip_to_best_slot(gangster_human) if(!equipped) - to_chat(owner.current, "Unfortunately, you could not bring your [O] to this shift. You will need to find one.") - qdel(O) + to_chat(owner.current, "Your [clothing_object.name] has been placed at your feet.") + clothing_object.forceMove(get_turf(gangster_human)) + if(my_gang.current_theme.bonus_items) + for(var/bonus_item in my_gang.current_theme.bonus_items) + var/obj/item/bonus_object = new bonus_item(owner.current) + var/equipped = bonus_object.equip_to_best_slot(gangster_human) + if(!equipped) + to_chat(owner.current, "Your [bonus_object.name] has been placed at your feet.") + bonus_object.forceMove(get_turf(gangster_human)) + if(starter_gangster) + if(my_gang.current_theme.bonus_first_gangster_items) + for(var/bonus_starter_item in my_gang.current_theme.bonus_first_gangster_items) + var/obj/item/bonus_starter_object = new bonus_starter_item(owner.current) + var/equipped = bonus_starter_object.equip_to_best_slot(gangster_human) + if(!equipped) + to_chat(owner.current, "Your [bonus_starter_object.name] has been placed at your feet.") + bonus_starter_object.forceMove(get_turf(gangster_human)) + +/datum/antagonist/gang/ui_static_data(mob/user) + var/list/data = list() + data["gang_name"] = gang_name + data["antag_name"] = name + data["gang_objective"] = my_gang.current_theme.gang_objectives[type] + + var/list/clothes_we_can_wear = list() + for(var/obj/item/accepted_item as anything in acceptable_clothes) + clothes_we_can_wear |= initial(accepted_item.name) + + for(var/obj/item/free_item as anything in free_clothes) + if(ispath(free_item, /obj/item/toy/crayon/spraycan)) + continue + clothes_we_can_wear |= initial(free_item.name) + + data["gang_clothes"] = clothes_we_can_wear + return data /datum/team/gang - /// The number of points this family has gained. Used for determining a victor if multiple families complete their objectives. - var/points = 0 /// The abbreviation of this family. var/gang_id = "LLJK" /// The list of clothes that are acceptable to show allegiance to this family. @@ -152,31 +174,35 @@ var/list/free_clothes = list() /// The specific, occupied family member antagonist datum that is used to reach the handler / check objectives, and from which the above properties (sans points) are inherited. var/datum/antagonist/gang/my_gang_datum + /// The current theme. Used to pull important stuff such as spawning equipment and objectives. + var/datum/gang_theme/current_theme + +/// Allow gangs to have custom naming schemes for their gangsters. +/datum/team/gang/proc/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) /datum/team/gang/roundend_report() var/list/report = list() report += "[name]:" if(!members.len) report += span_redtext("The family was wiped out!") - else if(my_gang_datum.check_gang_objective()) - report += span_greentext("The family completed their objective!") + if(current_theme.everyone_objective) + report += "Objective: [current_theme.everyone_objective]" else - report += "The family failed their objective!" - report += "Objective: [my_gang_datum.gang_objective]" - report += "Points: [points]" + var/assigned_objective = current_theme.gang_objectives[my_gang_datum.type] + if(assigned_objective) + report += "Objective: [assigned_objective]" + else + report += "Objective: ERROR, FILE A REPORT WITH THIS INFO: Gang Name: [my_gang_datum.name], Theme Name: [current_theme.name]" if(members.len) report += "[my_gang_datum.roundend_category] were:" report += printplayerlist(members) return "
[report.Join("
")]
" -/// Adds points to the points var. -/datum/team/gang/proc/adjust_points(points_to_adjust) - points += points_to_adjust - /datum/action/cooldown/spawn_induction_package - name = "Create Induction Package" - desc = "Generate an induction package for your family." + name = "Induct via Secret Handshake" + desc = "Teach new recruits the Secret Handshake to join." check_flags = AB_CHECK_CONSCIOUS button_icon_state = "recruit" icon_icon = 'icons/obj/gang/actions.dmi' @@ -197,363 +223,547 @@ if(H.stat) return FALSE - var/gang_balance_cap // we need some stuff to fall back on if we're handlerless - if(my_gang_datum.handler) - gang_balance_cap = my_gang_datum.handler.gang_balance_cap + var/obj/item/slapper/secret_handshake/secret_handshake_item = new(owner) + if(owner.put_in_hands(secret_handshake_item)) + to_chat(owner, span_notice("You ready your secret handshake.")) else - gang_balance_cap = 5 //just a filler default value - - var/lowest_gang_count = my_gang_datum.my_gang.members.len - for(var/datum/team/gang/TT in GLOB.antagonist_teams) - var/alive_gangsters = 0 - for(var/datum/mind/gangers in TT.members) - if(ishuman(gangers.current) && gangers.current.client && !gangers.current.stat) - alive_gangsters++ - if(!alive_gangsters || TT.members.len <= 1) // Dead or inactive gangs don't count towards the cap. - continue - if(TT != my_gang_datum.my_gang) - if(alive_gangsters < lowest_gang_count) - lowest_gang_count = alive_gangsters - if(my_gang_datum.my_gang.members.len >= (lowest_gang_count + gang_balance_cap)) - to_chat(H, "Your gang is pretty packed right now. You don't need more members just yet. If the other families expand, you can recruit more members.") + qdel(secret_handshake_item) + to_chat(owner, span_warning("You're incapable of performing a handshake in your current state.")) return FALSE - to_chat(H, "You pull an induction package from your pockets and place it on the ground.") - var/obj/item/gang_induction_package/GP = new(get_turf(H)) - GP.name = "\improper [my_gang_datum.name] signup package" - GP.handler = my_gang_datum.handler - GP.gang_to_use = my_gang_datum.type - GP.team_to_use = my_gang_datum.my_gang + owner.visible_message(span_notice("[src] is offering to induct people into the Family."), + span_notice("You offer to induct people into the Family."), null, 2) + if(H.has_status_effect(STATUS_EFFECT_HANDSHAKE)) + return FALSE + if(!(locate(/mob/living/carbon) in orange(1, owner))) + owner.visible_message(span_danger("[src] offers to induct people into the Family, but nobody was around."), \ + span_warning("You offer to induct people into the Family, but nobody is around."), null, 2) + return FALSE + + H.apply_status_effect(STATUS_EFFECT_HANDSHAKE, secret_handshake_item) StartCooldown() return TRUE -/datum/antagonist/gang/red - show_in_antagpanel = TRUE - name = "San Fierro Triad" - roundend_category = "The San Fierro Triad gangsters" - gang_name = "San Fierro Triad" - gang_id = "SFT" - acceptable_clothes = list(/obj/item/clothing/head/soft/red, - /obj/item/clothing/neck/scarf/red, - /obj/item/clothing/suit/jacket/letterman_red, - /obj/item/clothing/under/color/red, - /obj/item/clothing/mask/bandana/red, - /obj/item/clothing/under/suit/red) - free_clothes = list(/obj/item/clothing/suit/jacket/letterman_red, - /obj/item/clothing/under/color/red, - /obj/item/toy/crayon/spraycan) - gang_objective = "The Spinward Stellar Coalition police intend to interfere with our operations, by sending undercover cops. Find them and eliminate them all." - antag_hud_name = "Triad" - -/datum/antagonist/gang/red/check_gang_objective() - for(var/C in get_antag_minds(/datum/antagonist/ert/families/undercover_cop)) - var/datum/mind/M = C - var/mob/living/carbon/human/H = M.current - if(considered_alive(H)) - return FALSE - return TRUE - -/datum/outfit/gangster - name = "Gangster (Preview only)" - - uniform = /obj/item/clothing/under/suit/henchmen - back = /obj/item/storage/backpack/henchmen - -/datum/antagonist/gang/purple - show_in_antagpanel = TRUE - name = "Ballas" - roundend_category = "The Ballas gangsters" - gang_name = "Ballas" - gang_id = "B" - acceptable_clothes = list(/obj/item/clothing/head/soft/purple, - /obj/item/clothing/under/color/lightpurple, - /obj/item/clothing/neck/scarf/purple, - /obj/item/clothing/head/beanie/purple, - /obj/item/clothing/suit/apron/purple_bartender, - /obj/item/clothing/mask/bandana/skull, - /obj/item/clothing/under/suit/green) - free_clothes = list(/obj/item/clothing/head/beanie/purple, - /obj/item/clothing/under/color/lightpurple, - /obj/item/toy/crayon/spraycan) - gang_objective = "We're looking to make a deal with the security pigs on this station after the shift. We scratch their back, they scratch ours. You feel me? Keep all of security safe from any trouble, and make sure they get out alive." - antag_hud_name = "Ballas" - -/datum/antagonist/gang/purple/check_gang_objective() - for(var/mob/player as anything in GLOB.player_list) - if(!(player.mind.assigned_role.departments_bitflags & DEPARTMENT_BITFLAG_SECURITY)) - continue - if(!player.suiciding && !considered_alive(player)) - return FALSE - return TRUE - -/datum/antagonist/gang/green - show_in_antagpanel = TRUE - name = "Grove Street Families" - roundend_category = "The Grove Street Families gangsters" - gang_name = "Grove Street Families" - gang_id = "GSF" - acceptable_clothes = list(/obj/item/clothing/head/soft/green, - /obj/item/clothing/under/color/darkgreen, - /obj/item/clothing/neck/scarf/green, - /obj/item/clothing/head/beanie/green, - /obj/item/clothing/suit/poncho/green, - /obj/item/clothing/mask/bandana/green) - free_clothes = list(/obj/item/clothing/mask/bandana/green, - /obj/item/clothing/under/color/darkgreen, - /obj/item/toy/crayon/spraycan) - gang_objective = "We lost a lot of territory recently. We gotta get that shit back. Make sure 45 rooms are tagged for Grove Street." - antag_hud_name = "Grove" - -/datum/antagonist/gang/green/check_gang_objective() - var/tag_amount = 0 - for(var/T in GLOB.gang_tags) - var/obj/effect/decal/cleanable/crayon/gang/tag = T - if(tag.my_gang.gang_id == gang_id) - tag_amount++ - if(tag_amount >= 45) - return TRUE - return FALSE - /datum/antagonist/gang/russian_mafia show_in_antagpanel = TRUE - name = "Russian Mafia" - roundend_category = "The Russian mafiosos" - gang_name = "Russian Mafia" + name = "Mafioso" + roundend_category = "The mafiosos" + gang_name = "Mafia" gang_id = "RM" acceptable_clothes = list(/obj/item/clothing/head/soft/red, - /obj/item/clothing/neck/scarf/red, - /obj/item/clothing/under/suit/white, - /obj/item/clothing/head/beanie/red, - /obj/item/clothing/head/ushanka) + /obj/item/clothing/neck/scarf/red, + /obj/item/clothing/under/suit/white, + /obj/item/clothing/head/beanie/red, + /obj/item/clothing/head/ushanka) free_clothes = list(/obj/item/clothing/head/ushanka, - /obj/item/clothing/under/suit/white, - /obj/item/toy/crayon/spraycan) - gang_objective = "We are starting to run low on supplies at the home base, my friend. Make sure every comrade has a bottle of some kind of booze on them, friend." + /obj/item/clothing/under/suit/white, + /obj/item/toy/crayon/spraycan) antag_hud_name = "Russian" + gang_team_type = /datum/team/gang/russian_mafia -/datum/antagonist/gang/russian_mafia/check_gang_objective() - for(var/R in get_antag_minds(/datum/antagonist/gang/russian_mafia)) - var/datum/mind/M = R - if(!considered_alive(M.current)) - continue // dead people cant really do the objective lol - var/list/items_to_check = M.current.GetAllContents() - for(var/I in items_to_check) - var/obj/IT = I - if(istype(IT, /obj/item/reagent_containers/food/drinks/bottle)) - continue - return FALSE // didnt pass the bottle check, no point in continuing to loop - return TRUE +/datum/team/gang/russian_mafia/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Don [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) /datum/antagonist/gang/italian_mob show_in_antagpanel = TRUE - name = "Italian Mob" - roundend_category = "The Italian mobsters" - gang_name = "Italian Mob" + name = "Mobster" + roundend_category = "The mobsters" + gang_name = "Mob" gang_id = "IM" acceptable_clothes = list(/obj/item/clothing/under/suit/checkered, - /obj/item/clothing/head/fedora, - /obj/item/clothing/neck/scarf/green, - /obj/item/clothing/mask/bandana/green) + /obj/item/clothing/head/fedora, + /obj/item/clothing/neck/scarf/green, + /obj/item/clothing/mask/bandana/green) free_clothes = list(/obj/item/clothing/head/fedora, - /obj/item/clothing/under/suit/checkered, - /obj/item/toy/crayon/spraycan) - gang_objective = "The boss wants it made very clear that all our esteemed members are to be held with respect. If a friend falls, ensure they are properly buried with a coffin. And keep any Chaplains alive, to ensure the corpses are properly taken care of." + /obj/item/clothing/under/suit/checkered, + /obj/item/toy/crayon/spraycan) antag_hud_name = "Italian" + gang_team_type = /datum/team/gang/russian_mafia -/datum/antagonist/gang/italian_mob/check_gang_objective() - for(var/I in get_antag_minds(/datum/antagonist/gang/italian_mob)) - var/datum/mind/M = I - if(M.has_antag_datum(src.type)) - if(considered_alive(M.current)) - continue - if(istype(M.current.loc, /obj/structure/closet/crate/coffin)) - continue - return FALSE - for(var/mob/player as anything in GLOB.player_list) - if(!is_chaplain_job(player.mind.assigned_role)) - continue - if(!player.suiciding && !considered_alive(player)) - return FALSE - return TRUE +/datum/team/gang/russian_mafia/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Boss [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) /datum/antagonist/gang/tunnel_snakes show_in_antagpanel = TRUE - name = "Tunnel Snakes" + name = "Tunnel Snake" roundend_category = "The Tunnel Snakes" gang_name = "Tunnel Snakes" gang_id = "TS" acceptable_clothes = list(/obj/item/clothing/under/pants/classicjeans, - /obj/item/clothing/suit/jacket, - /obj/item/clothing/mask/bandana/skull) + /obj/item/clothing/suit/jacket, + /obj/item/clothing/mask/bandana/skull) free_clothes = list(/obj/item/clothing/suit/jacket, - /obj/item/clothing/under/pants/classicjeans, - /obj/item/toy/crayon/spraycan) - gang_objective = "TUNNEL SNAKES RULE!!! Make sure that everyone knows that, by getting 25% of people on station to wear any part of our uniform! TUNNEL SNAKES RULE!!!" + /obj/item/clothing/under/pants/classicjeans, + /obj/item/toy/crayon/spraycan) antag_hud_name = "Snakes" + gang_team_type = /datum/team/gang/tunnel_snakes -/datum/antagonist/gang/tunnel_snakes/check_gang_objective() - var/people_on_station = 0 - var/people_reppin_tunnel_snakes = 0 - for(var/mob/M in GLOB.player_list) - if(!considered_alive(M)) - continue - if(ishuman(M)) - var/mob/living/carbon/human/H = M - people_on_station++ - for(var/clothing in list(H.head, H.wear_mask, H.wear_suit, H.w_uniform, H.back, H.gloves, H.shoes, H.belt, H.s_store, H.glasses, H.ears, H.wear_id)) - if(is_type_in_list(clothing, acceptable_clothes)) - people_reppin_tunnel_snakes++ - if(0.25*people_on_station > people_reppin_tunnel_snakes) - return FALSE - return TRUE - -/datum/antagonist/gang/vagos - show_in_antagpanel = TRUE - name = "Los Santos Vagos" - roundend_category = "The Los Santos Vagos gangsters" - gang_name = "Los Santos Vagos" - gang_id = "LSV" - acceptable_clothes = list(/obj/item/clothing/head/soft/yellow, - /obj/item/clothing/under/color/yellow, - /obj/item/clothing/neck/scarf/yellow, - /obj/item/clothing/head/beanie/yellow, - /obj/item/clothing/mask/bandana/gold) - free_clothes = list(/obj/item/clothing/mask/bandana/gold, - /obj/item/clothing/under/color/yellow, - /obj/item/toy/crayon/spraycan) - gang_objective = "Orders from up high. We need to up our drug operation. Ensure that at least 25% of the station is addicted to stimulants." - antag_hud_name = "Vagos" - -/datum/antagonist/gang/vagos/check_gang_objective() - var/people_on_station = 0 - var/people_on_crack = 0 - for(var/mob/M in GLOB.player_list) - if(!considered_alive(M)) - continue - if(ishuman(M)) - var/mob/living/carbon/human/H = M - people_on_station++ - if(H.mind.active_addictions[/datum/addiction/stimulants]) - people_on_crack++ - if(0.25*people_on_station > people_on_crack) - return FALSE - return TRUE +/datum/team/gang/tunnel_snakes/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "King Cobra [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) /datum/antagonist/gang/henchmen show_in_antagpanel = TRUE - name = "Monarch Crew" + name = "Monarch Henchmen" roundend_category = "The Monarch henchmen" gang_name = "Monarch Crew" gang_id = "HENCH" acceptable_clothes = list(/obj/item/clothing/head/soft/yellow, - /obj/item/clothing/under/suit/henchmen, - /obj/item/clothing/neck/scarf/yellow, - /obj/item/clothing/head/beanie/yellow, - /obj/item/clothing/mask/bandana/gold, - /obj/item/storage/backpack/henchmen) + /obj/item/clothing/under/suit/henchmen, + /obj/item/clothing/neck/scarf/yellow, + /obj/item/clothing/head/beanie/yellow, + /obj/item/clothing/mask/bandana/gold, + /obj/item/storage/backpack/henchmen) free_clothes = list(/obj/item/storage/backpack/henchmen, - /obj/item/clothing/under/suit/henchmen, - /obj/item/toy/crayon/spraycan) - gang_objective = "I have it on VERY GOOD AUTHORITY that the Research Director on this station helped Venture on a science project back in college! ENSURE THAT HE DOES NOT LEAVE THIS STATION ALIVE, HENCHMEN! THE MIGHTY MONARCH DEMANDS IT!!!" + /obj/item/clothing/under/suit/henchmen, + /obj/item/toy/crayon/spraycan) antag_hud_name = "Monarch" + gang_team_type = /datum/team/gang/henchmen -/datum/antagonist/gang/henchmen/check_gang_objective() // gotta arch dr. venture indirectly - for(var/mob/player as anything in GLOB.player_list) - if(!is_research_director_job(player.mind.assigned_role)) - continue - if(!player.suiciding && considered_alive(player)) - return FALSE - return TRUE +/datum/team/gang/henchmen + var/henchmen_count = 0 + +/datum/team/gang/henchmen/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + henchmen_count++ + gangster.current.fully_replace_character_name(gangster.current.real_name, "Number [henchmen_count]") /datum/antagonist/gang/yakuza show_in_antagpanel = TRUE - name = "Tojo Clan" + name = "Tojo Clan Member" roundend_category = "The Yakuza" gang_name = "Tojo Clan" gang_id = "YAK" acceptable_clothes = list(/obj/item/clothing/head/soft/yellow, - /obj/item/clothing/under/costume/yakuza, - /obj/item/clothing/shoes/yakuza, - /obj/item/clothing/neck/scarf/yellow, - /obj/item/clothing/head/beanie/yellow, - /obj/item/clothing/mask/bandana/gold, - /obj/item/clothing/head/hardhat, - /obj/item/clothing/suit/yakuza) + /obj/item/clothing/under/costume/yakuza, + /obj/item/clothing/shoes/yakuza, + /obj/item/clothing/neck/scarf/yellow, + /obj/item/clothing/head/beanie/yellow, + /obj/item/clothing/mask/bandana/gold, + /obj/item/clothing/head/hardhat, + /obj/item/clothing/suit/yakuza) free_clothes = list(/obj/item/clothing/under/costume/yakuza, - /obj/item/clothing/shoes/yakuza, - /obj/item/clothing/suit/yakuza, - /obj/item/clothing/head/hardhat, - /obj/item/toy/crayon/spraycan) - gang_objective = "The boss is thrilled about this new construction opportunity we've all been given, yadda yadda, look, he knows we're here to expand our business ventures for the clan, but Majima wanted it made VERY clear that we do NOT fuck this station's infrastructure up. If more than 15% of this station is busted when we get the hell out of here, it's your ass on the line." + /obj/item/clothing/shoes/yakuza, + /obj/item/clothing/suit/yakuza, + /obj/item/clothing/head/hardhat, + /obj/item/toy/crayon/spraycan) antag_hud_name = "Tojo" + gang_team_type = /datum/team/gang/yakuza -/datum/antagonist/gang/yakuza/check_gang_objective() - var/datum/station_state/current_state = new /datum/station_state() - current_state.count() - var/station_integrity = min(PERCENT(GLOB.start_state.score(current_state)), 100) - if(station_integrity < 85) - return FALSE - return TRUE +/datum/team/gang/yakuza/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Patriarch [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) /datum/antagonist/gang/jackbros show_in_antagpanel = TRUE - name = "Jack Bros" + name = "Jack Bro" roundend_category = "The Hee-hos" gang_name = "Jack Bros" gang_id = "JB" acceptable_clothes = list(/obj/item/clothing/head/soft/blue, - /obj/item/clothing/under/costume/jackbros, - /obj/item/clothing/shoes/jackbros, - /obj/item/clothing/head/jackbros, - /obj/item/clothing/mask/bandana/blue) + /obj/item/clothing/under/costume/jackbros, + /obj/item/clothing/shoes/jackbros, + /obj/item/clothing/head/jackbros, + /obj/item/clothing/mask/bandana/blue) free_clothes = list(/obj/item/clothing/under/costume/jackbros, - /obj/item/clothing/shoes/jackbros, - /obj/item/clothing/head/jackbros, - /obj/item/toy/crayon/spraycan) - gang_objective = "Hee-hello friends! We need to expand our influence, ho! Get a King Frost in as the Captain of this joint! Either get the original Captain on board with the program, or Hee-ho a fellow Jack Frost into the position yourselves!" + /obj/item/clothing/shoes/jackbros, + /obj/item/clothing/head/jackbros, + /obj/item/toy/crayon/spraycan) antag_hud_name = "JackFrost" + gang_team_type = /datum/team/gang/jackbros + +/datum/team/gang/jackbros/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "King Frost [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) -/datum/antagonist/gang/jackbros/check_gang_objective() - for(var/J in get_antag_minds(/datum/antagonist/gang/jackbros)) - var/datum/mind/M = J - if(!considered_alive(M.current)) - continue // dead people cant really do the objective lol - if(ishuman(M.current)) - var/mob/living/carbon/human/H = M.current - if(H.get_assignment() == "Captain") - return TRUE - return FALSE /datum/antagonist/gang/dutch show_in_antagpanel = TRUE - name = "Dutch van der Linde's Gang" + name = "Dutch van der Linde Outlaw" roundend_category = "Dutch's outlaws" gang_name = "Dutch van der Linde's Gang" gang_id = "VDL" acceptable_clothes = list(/obj/item/clothing/head/soft/black, - /obj/item/clothing/under/costume/dutch, - /obj/item/clothing/suit/dutch, - /obj/item/clothing/head/bowler, - /obj/item/clothing/mask/bandana/black) + /obj/item/clothing/under/costume/dutch, + /obj/item/clothing/suit/dutch, + /obj/item/clothing/head/bowler, + /obj/item/clothing/mask/bandana/black) free_clothes = list(/obj/item/clothing/under/costume/dutch, - /obj/item/clothing/head/bowler, - /obj/item/clothing/suit/dutch, - /obj/item/toy/crayon/spraycan) - gang_objective = "Listen here, fellas. I have a plan. Just one more score on this crappy little po-dunk station. Gold bars, friends. Get all the gold out of the silos, and leave nothing behind! Spread the gold amongst yourselves for the escape plan, make sure everyone has at least 1 bar. After this, it'll be space mangos at Tahiti. You just gotta have a little faith." + /obj/item/clothing/head/bowler, + /obj/item/clothing/suit/dutch, + /obj/item/toy/crayon/spraycan) antag_hud_name = "Dutch" + gang_team_type = /datum/team/gang/dutch -/datum/antagonist/gang/dutch/check_gang_objective() - for(var/D in get_antag_minds(/datum/antagonist/gang/dutch)) - var/datum/mind/M = D - if(!considered_alive(M.current)) - continue // dead people cant really do the objective lol - var/list/items_to_check = M.current.GetAllContents() - for(var/I in items_to_check) - var/obj/IT = I - if(istype(IT, /obj/item/stack/sheet/mineral/gold)) - continue - return FALSE // didnt pass the bar check, no point in continuing to loop - var/obj/machinery/ore_silo/S = GLOB.ore_silo_default - var/datum/component/material_container/mat_container = S.GetComponent(/datum/component/material_container) - if(mat_container.materials[GET_MATERIAL_REF(/datum/material/gold)] >= 2000) // if theres at least 1 bar of gold left in the silo, they've failed to heist all of it - return FALSE - return TRUE +/datum/team/gang/dutch/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Head Cowboy [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) + + +/datum/antagonist/gang/irs + show_in_antagpanel = TRUE + name = "Internal Revenue Service Agent" + roundend_category = "IRS Agents" + gang_name = "Internal Revenue Service" + gang_id = "IRS" + acceptable_clothes = list(/obj/item/clothing/suit/irs, + /obj/item/clothing/under/costume/irs, + /obj/item/clothing/head/irs) + free_clothes = list(/obj/item/clothing/suit/irs, + /obj/item/clothing/under/costume/irs, + /obj/item/clothing/head/irs, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "IRS" + gang_team_type = /datum/team/gang/irs + +/datum/team/gang/irs/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Revenue Supervisor [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, "Revenue Agent [last_name.match]") + +/datum/antagonist/gang/osi + show_in_antagpanel = TRUE + name = "Office of Secret Intelligence Agent" + roundend_category = "O.S.I. Agents" + gang_name = "Office of Secret Intelligence" + gang_id = "OSI" + acceptable_clothes = list(/obj/item/clothing/suit/osi, + /obj/item/clothing/under/costume/osi, + /obj/item/clothing/glasses/osi) + free_clothes = list(/obj/item/clothing/suit/osi, + /obj/item/clothing/under/costume/osi, + /obj/item/clothing/glasses/osi, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "OSI" + gang_team_type = /datum/team/gang/osi + +/datum/team/gang/osi/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "General [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, "Special Agent [last_name.match]") + +/datum/antagonist/gang/tmc + show_in_antagpanel = TRUE + name = "Lost M.C. Biker" + roundend_category = "Lost M.C. Bikers" + gang_name = "The Lost M.C." + gang_id = "TMC" + acceptable_clothes = list(/obj/item/clothing/suit/tmc, + /obj/item/clothing/under/costume/tmc, + /obj/item/clothing/head/tmc) + free_clothes = list(/obj/item/clothing/suit/tmc, + /obj/item/clothing/under/costume/tmc, + /obj/item/clothing/head/tmc, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "LostMC" + gang_team_type = /datum/team/gang/tmc + +/datum/team/gang/tmc/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "President [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) + +/datum/antagonist/gang/pg + show_in_antagpanel = TRUE + name = "Powder Ganger" + roundend_category = "Powder Gangers" + gang_name = "Powder Gangers" + gang_id = "PG" + acceptable_clothes = list(/obj/item/clothing/suit/pg, + /obj/item/clothing/under/costume/pg, + /obj/item/clothing/head/pg) + free_clothes = list(/obj/item/clothing/suit/pg, + /obj/item/clothing/under/costume/pg, + /obj/item/clothing/head/pg, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "PowderGang" + gang_team_type = /datum/team/gang/pg + +/datum/team/gang/pg/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Head Convict [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) + + +/datum/antagonist/gang/driscoll + show_in_antagpanel = TRUE + name = "O'Driscoll Gangster" + roundend_category = "O'Driscoll's Gangsters" + gang_name = "O'Driscoll's Gang" + gang_id = "DB" + acceptable_clothes = list(/obj/item/clothing/suit/driscoll, + /obj/item/clothing/under/costume/driscoll, + /obj/item/clothing/mask/gas/driscoll, + /obj/item/clothing/shoes/cowboy) + free_clothes = list(/obj/item/clothing/suit/driscoll, + /obj/item/clothing/under/costume/driscoll, + /obj/item/clothing/mask/gas/driscoll, + /obj/item/clothing/shoes/cowboy, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "Drill" + gang_team_type = /datum/team/gang/driscoll + +/datum/team/gang/driscoll/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Head Outlaw [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) + +/datum/antagonist/gang/deckers + show_in_antagpanel = TRUE + name = "Decker" + roundend_category = "Deckers" + gang_name = "Deckers" + gang_id = "DK" + acceptable_clothes = list(/obj/item/clothing/suit/deckers, + /obj/item/clothing/under/costume/deckers, + /obj/item/clothing/head/deckers, + /obj/item/clothing/shoes/deckers) + free_clothes = list(/obj/item/clothing/suit/deckers, + /obj/item/clothing/under/costume/deckers, + /obj/item/clothing/head/deckers, + /obj/item/clothing/shoes/deckers, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "Deckers" + gang_team_type = /datum/team/gang/deckers + +/datum/team/gang/deckers/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Master Hacker [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) + + +/datum/antagonist/gang/morningstar + show_in_antagpanel = TRUE + name = "Morningstar Member" + roundend_category = "Morningstar Member" + gang_name = "Morningstar" + gang_id = "MS" + acceptable_clothes = list(/obj/item/clothing/suit/morningstar, + /obj/item/clothing/under/costume/morningstar, + /obj/item/clothing/head/morningstar, + /obj/item/clothing/shoes/morningstar) + free_clothes = list(/obj/item/clothing/suit/morningstar, + /obj/item/clothing/under/costume/morningstar, + /obj/item/clothing/head/morningstar, + /obj/item/clothing/shoes/morningstar, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "MorningStar" + gang_team_type = /datum/team/gang/morningstar + +/datum/team/gang/morningstar/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Chief Executive Officer [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) + +/datum/antagonist/gang/saints + show_in_antagpanel = TRUE + name = "Third Street Saints Gangster" + roundend_category = "Third Street Saints Gangsters" + gang_name = "Third Street Saints" + gang_id = "TSS" + acceptable_clothes = list(/obj/item/clothing/suit/saints, + /obj/item/clothing/under/costume/saints, + /obj/item/clothing/head/saints, + /obj/item/clothing/shoes/saints) + free_clothes = list(/obj/item/clothing/suit/saints, + /obj/item/clothing/under/costume/saints, + /obj/item/clothing/head/saints, + /obj/item/clothing/shoes/saints, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "TheSaints" + gang_team_type = /datum/team/gang/saints + +/datum/team/gang/saints/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Boss [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) + + +/datum/antagonist/gang/phantom + show_in_antagpanel = TRUE + name = "Phantom Thief" + roundend_category = "Phantom Thieves" + gang_name = "Phantom Thieves of Hearts" + gang_id = "PT" + acceptable_clothes = list(/obj/item/clothing/suit/phantom, + /obj/item/clothing/under/costume/phantom, + /obj/item/clothing/glasses/phantom, + /obj/item/clothing/shoes/phantom) + free_clothes = list(/obj/item/clothing/suit/phantom, + /obj/item/clothing/under/costume/phantom, + /obj/item/clothing/glasses/phantom, + /obj/item/clothing/shoes/phantom, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "PhantomThieves" + gang_team_type = /datum/team/gang/phantom + +/datum/team/gang/phantom/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Joker [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) + +/datum/antagonist/gang/allies + show_in_antagpanel = TRUE + name = "Allies G.I." + roundend_category = "Allies" + gang_name = "Allies" + gang_id = "ALLIES" + free_clothes = list(/obj/item/clothing/suit/allies, + /obj/item/clothing/under/costume/allies, + /obj/item/clothing/head/allies, + /obj/item/clothing/gloves/color/black, + /obj/item/clothing/shoes/jackboots, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "Allies" + gang_team_type = /datum/team/gang/allies + +/datum/team/gang/allies/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Commander [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, "Private [last_name.match]") + +/datum/antagonist/gang/soviet + show_in_antagpanel = TRUE + name = "Soviet Conscript" + roundend_category = "Soviets" + gang_name = "Soviets" + gang_id = "SOV" + free_clothes = list(/obj/item/clothing/suit/soviet, + /obj/item/clothing/under/costume/soviet_families, + /obj/item/clothing/head/ushanka/soviet, + /obj/item/clothing/gloves/color/black, + /obj/item/clothing/shoes/jackboots, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "Soviets" + gang_team_type = /datum/team/gang/soviet + +/datum/team/gang/soviet/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Comrade General [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, "Conscript [last_name.match]") + +/datum/antagonist/gang/yuri + show_in_antagpanel = TRUE + name = "Yuri Initiate" + roundend_category = "Yuri's Army" + gang_name = "Yuri's Army" + gang_id = "YR" + free_clothes = list(/obj/item/clothing/suit/yuri, + /obj/item/clothing/under/costume/yuri, + /obj/item/clothing/head/yuri, + /obj/item/clothing/gloves/color/black, + /obj/item/clothing/shoes/jackboots, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "YuriArmy" + gang_team_type = /datum/team/gang/yuri + +/datum/team/gang/yuri/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Initiate Prime [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, "Initiate [last_name.match]") + +/datum/antagonist/gang/sybil_slickers + show_in_antagpanel = TRUE + name = "Sybil Slicker" + roundend_category = "Sybil Slickers" + gang_name = "Sybil Slickers" + gang_id = "SS" + free_clothes = list(/obj/item/clothing/suit/sybil_slickers, + /obj/item/clothing/under/costume/sybil_slickers, + /obj/item/clothing/head/sybil_slickers, + /obj/item/clothing/gloves/tackler/football, + /obj/item/clothing/shoes/sybil_slickers, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "SybilSlickers" + gang_team_type = /datum/team/gang/sybil_slickers + +/datum/team/gang/sybil_slickers/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Sybil Coach [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) + +/datum/antagonist/gang/basil_boys + show_in_antagpanel = TRUE + name = "Basil Boy" + roundend_category = "Basil Boys" + gang_name = "Basil Boys" + gang_id = "BB" + free_clothes = list(/obj/item/clothing/suit/basil_boys, + /obj/item/clothing/under/costume/basil_boys, + /obj/item/clothing/head/basil_boys, + /obj/item/clothing/gloves/tackler/football, + /obj/item/clothing/shoes/basil_boys, + /obj/item/toy/crayon/spraycan) + antag_hud_name = "BasilBoys" + gang_team_type = /datum/team/gang/basil_boys + +/datum/team/gang/basil_boys/rename_gangster(datum/mind/gangster, original_name, starter_gangster) + var/static/regex/last_name = new("\[^\\s-\]+$") //First word before whitespace or "-" + last_name.Find(original_name) + if(starter_gangster) + gangster.current.fully_replace_character_name(gangster.current.real_name, "Basil Coach [last_name.match]") + else + gangster.current.fully_replace_character_name(gangster.current.real_name, original_name) diff --git a/code/modules/antagonists/gang/handler.dm b/code/modules/antagonists/gang/handler.dm index 4421ff68ecd..a363608fd7a 100644 --- a/code/modules/antagonists/gang/handler.dm +++ b/code/modules/antagonists/gang/handler.dm @@ -15,6 +15,8 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0) +///Forces the Families theme to be the one in this variable via variable editing. Used for debugging. +GLOBAL_VAR(families_override_theme) /** * # Families gamemode / dynamic ruleset handler @@ -68,6 +70,8 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0) var/list/antag_candidates = list() /// List of jobs not eligible for starting family member / undercover cop. Set externally (passed by reference) by gamemode / ruleset; used internally. var/list/restricted_jobs + /// The current chosen gamemode theme. Decides the available Gangs, objectives, and equipment. + var/datum/gang_theme/current_theme /** * Sets antag_candidates and restricted_jobs. @@ -105,7 +109,13 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0) * Takes no arguments. */ /datum/gang_handler/proc/pre_setup_analogue() - for(var/j = 0, j < gangs_to_generate, j++) + if(!GLOB.families_override_theme) + var/theme_to_use = pick(subtypesof(/datum/gang_theme)) + current_theme = new theme_to_use + else + current_theme = new GLOB.families_override_theme + var/gangsters_to_make = length(current_theme.involved_gangs) * current_theme.starting_gangsters + for(var/i in 1 to gangsters_to_make) if (!antag_candidates.len) break var/taken = pick_n_take(antag_candidates) // original used antag_pick, but that's local to game_mode and rulesets use pick_n_take so this is fine maybe @@ -120,21 +130,6 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0) log_game("[key_name(gangbanger)] has been selected as a starting gangster!") if(!midround_ruleset) GLOB.pre_setup_antags += gangbanger - for(var/j = 0, j < gangs_to_generate, j++) - if(!antag_candidates.len) - break - var/taken = pick_n_take(antag_candidates) - var/datum/mind/undercover_cop - if(istype(taken, /mob)) - var/mob/T = taken - undercover_cop = T.mind - else - undercover_cop = taken - undercover_cops += undercover_cop - undercover_cop.restricted_roles = restricted_jobs - log_game("[key_name(undercover_cop)] has been selected as a starting undercover cop!") - if(!midround_ruleset) - GLOB.pre_setup_antags += undercover_cop deaths_during_shift_at_beginning = GLOB.deaths_during_shift // don't want to mix up pre-families and post-families deaths start_time = world.time end_time = start_time + ((60 MINUTES) / (midround_ruleset ? 2 : 1)) // midround families rounds end quicker @@ -158,7 +153,6 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0) */ /datum/gang_handler/proc/post_setup_analogue(return_if_no_gangs = FALSE) var/replacement_gangsters = 0 - var/replacement_cops = 0 for(var/datum/mind/gangbanger in gangbangers) if(!ishuman(gangbanger.current)) if(!midround_ruleset) @@ -180,47 +174,27 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0) gangbanger = taken gangbangers += gangbanger log_game("[key_name(gangbanger)] has been selected as a replacement gangster!") - for(var/datum/mind/undercover_cop in undercover_cops) - if(!ishuman(undercover_cop.current)) - undercover_cops.Remove(undercover_cop) - if(!midround_ruleset) - GLOB.pre_setup_antags -= undercover_cop - log_game("[undercover_cop] was not a human, and thus has lost their undercover cop role.") - replacement_cops++ - if(replacement_cops) - for(var/j = 0, j < replacement_cops, j++) - if(!antag_candidates.len) - log_game("Unable to find more replacement undercover cops. Not all of the cops will spawn.") - break - var/taken = pick_n_take(antag_candidates) - var/datum/mind/undercover_cop - if(istype(taken, /mob)) - var/mob/T = taken - undercover_cop = T.mind - else - undercover_cop = taken - undercover_cops += undercover_cop - log_game("[key_name(undercover_cop)] has been selected as a replacement undercover cop!") - if(!gangbangers.len) if(return_if_no_gangs) return FALSE // ending early is bad if we're not in dynamic - for(var/datum/mind/undercover_cop in undercover_cops) - var/datum/antagonist/ert/families/undercover_cop/one_eight_seven_on_an_undercover_cop = new() - undercover_cop.add_antag_datum(one_eight_seven_on_an_undercover_cop) + var/list/gangs_to_use = current_theme.involved_gangs + var/amount_of_gangs = gangs_to_use.len - var/list/gangs_to_use = subtypesof(/datum/antagonist/gang) - for(var/datum/mind/gangbanger in gangbangers) + for(var/_ in 1 to amount_of_gangs) var/gang_to_use = pick_n_take(gangs_to_use) - var/datum/antagonist/gang/new_gangster = new gang_to_use() - new_gangster.handler = src - new_gangster.starter_gangster = TRUE - gangbanger.add_antag_datum(new_gangster) + for(var/__ in 1 to current_theme.starting_gangsters) + if(!gangbangers.len) + break + var/datum/mind/gangster_mind = pick_n_take(gangbangers) + var/datum/antagonist/gang/new_gangster = new gang_to_use() + new_gangster.handler = src + new_gangster.starter_gangster = TRUE + gangster_mind.add_antag_datum(new_gangster) + // see /datum/antagonist/gang/create_team() for how the gang team datum gets instantiated and added to our gangs list addtimer(CALLBACK(src, .proc/announce_gang_locations), 5 MINUTES) - SSshuttle.registerHostileEnvironment(src) return TRUE /** @@ -235,18 +209,6 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0) * Takes no arguments. */ /datum/gang_handler/proc/process_analogue() - check_wanted_level() - check_counter++ - if(check_counter >= 5) - if(world.time > (end_time - 5 MINUTES) && !sent_second_announcement) - five_minute_warning() - addtimer(CALLBACK(src, .proc/send_in_the_fuzz), 5 MINUTES) - - check_counter = 0 - - check_tagged_turfs() - check_gang_clothes() - check_rollin_with_crews() /** * set_round_result() or round_result() equivalent. @@ -258,45 +220,14 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0) * Takes no arguments. */ /datum/gang_handler/proc/set_round_result_analogue() - var/alive_gangsters = 0 - var/alive_cops = 0 - for(var/datum/mind/gangbanger in gangbangers) - if(!ishuman(gangbanger.current)) - continue - var/mob/living/carbon/human/H = gangbanger.current - if(H.stat) - continue - alive_gangsters++ - for(var/datum/mind/bacon in get_antag_minds(/datum/antagonist/ert/families)) - if(!ishuman(bacon.current)) // always returns false - continue - var/mob/living/carbon/human/H = bacon.current - if(H.stat) - continue - alive_cops++ - if(alive_gangsters > alive_cops) - SSticker.mode_result = "win - gangs survived" - SSticker.news_report = GANG_OPERATING - return TRUE - SSticker.mode_result = "loss - police destroyed the gangs" - SSticker.news_report = GANG_DESTROYED - return FALSE + SSticker.mode_result = "win - gangs survived" + SSticker.news_report = GANG_OPERATING + return TRUE /// Internal. Announces the presence of families to the entire station and sets sent_announcement to true to allow other checks to occur. /datum/gang_handler/proc/announce_gang_locations() - var/list/readable_gang_names = list() - for(var/GG in gangs) - var/datum/team/gang/G = GG - readable_gang_names += "[G.name]" - var/finalized_gang_names = english_list(readable_gang_names) - priority_announce("Julio G coming to you live from Radio Los Spess! We've been hearing reports of gang activity on [station_name()], with the [finalized_gang_names] duking it out, looking for fresh territory and drugs to sling! Stay safe out there for the [use_dynamic_timing ? "half-hour" : "hour"] 'till the space cops get there, and keep it cool, yeah?\n\n The local jump gates are shut down for about an hour due to some maintenance troubles, so if you wanna split from the area you're gonna have to wait [use_dynamic_timing ? "thirty minutes" : "an hour"]. \n Play music, not gunshots, I say. Peace out!", "Radio Los Spess", 'sound/voice/beepsky/radio.ogg') + priority_announce(current_theme.description, current_theme.name, 'sound/voice/beepsky/radio.ogg') sent_announcement = TRUE - check_wanted_level() // i like it when the wanted level updates at the same time as the announcement - -/// Internal. Announces that space cops will arrive in 5 minutes and sets sent_second_announcement to true to freeze -/datum/gang_handler/proc/five_minute_warning() - priority_announce("Julio G coming to you live from Radio Los Spess! The space cops are closing in on [station_name()] and will arrive in about 5 minutes! Better clear on out of there if you don't want to get hurt!", "Radio Los Spess", 'sound/voice/beepsky/radio.ogg') - sent_second_announcement = TRUE /// Internal. Checks if our wanted level has changed; calls update_wanted_level. Only updates wanted level post the initial announcement and until the cops show up. After that, it's locked. /datum/gang_handler/proc/check_wanted_level() @@ -495,122 +426,4 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0) numagents-- cops_arrived = TRUE update_wanted_level(wanted_level) // gotta make sure everyone's wanted level display looks nice - addtimer(CALLBACK(src, .proc/end_hostile_sit), 10 MINUTES) return TRUE - -/// Internal. Clears the hostile environment, letting the shuttle leave. -/datum/gang_handler/proc/end_hostile_sit() - SSshuttle.clearHostileEnvironment(src) - -/// Internal. Assigns points to families according to gang tags. -/datum/gang_handler/proc/check_tagged_turfs() - for(var/T in GLOB.gang_tags) - var/obj/effect/decal/cleanable/crayon/gang/tag = T - if(tag.my_gang) - tag.my_gang.adjust_points(50) - CHECK_TICK - -/// Internal. Assigns points to families according to clothing of all currently living humans. -/datum/gang_handler/proc/check_gang_clothes() // TODO: make this grab the sprite itself, average out what the primary color would be, then compare how close it is to the gang color so I don't have to manually fill shit out for 5 years for every gang type - for(var/mob/living/carbon/human/H in GLOB.player_list) - if(!H.mind || !H.client) - continue - var/datum/antagonist/gang/is_gangster = H.mind.has_antag_datum(/datum/antagonist/gang) - for(var/clothing in list(H.head, H.wear_mask, H.wear_suit, H.w_uniform, H.back, H.gloves, H.shoes, H.belt, H.s_store, H.glasses, H.ears, H.wear_id)) - if(is_gangster) - if(is_type_in_list(clothing, is_gangster.acceptable_clothes)) - is_gangster.add_gang_points(10) - else - for(var/G in gangs) - var/datum/team/gang/gang_clothes = G - if(is_type_in_list(clothing, gang_clothes.acceptable_clothes)) - gang_clothes.adjust_points(5) - - CHECK_TICK - -/// Internal. Assigns points to families according to groups of nearby family members. -/datum/gang_handler/proc/check_rollin_with_crews() - var/list/areas_to_check = list() - for(var/G in gangbangers) - var/datum/mind/gangster = G - areas_to_check += get_area(gangster.current) - for(var/AA in areas_to_check) - var/area/A = AA - var/list/gang_members = list() - for(var/mob/living/carbon/human/H in A) - if(H.stat || !H.mind || !H.client) - continue - var/datum/antagonist/gang/is_gangster = H.mind.has_antag_datum(/datum/antagonist/gang) - if(is_gangster) - gang_members[is_gangster.my_gang]++ - CHECK_TICK - if(gang_members.len) - for(var/datum/team/gang/gangsters in gang_members) - if(gang_members[gangsters] >= CREW_SIZE_MIN) - if(gang_members[gangsters] >= CREW_SIZE_MAX) - gangsters.adjust_points(5) // Discourage larger clumps, spread ur people out - else - gangsters.adjust_points(10) - - -/// Hijacks the space cops' roundend results to say if cops / a gang won the round. Included in the same file as the gang_handler as it's far more related to the gamemode than it is to the beat cop datum; it's kind of hacky. -/datum/antagonist/ert/families/beatcop/roundend_report_footer() - var/list/all_gangs = list() - for(var/datum/team/gang/G in GLOB.antagonist_teams) - all_gangs += G - if(!all_gangs.len) - return ..() - var/list/all_gangsters = get_antag_minds(/datum/antagonist/gang) - var/list/all_cops = get_antag_minds(/datum/antagonist/ert/families) - var/report - var/highest_point_value = 0 - var/highest_gang = "Leet Like Jeff K" - var/objective_failures = TRUE - - for(var/G in all_gangs) - var/datum/team/gang/GG = G - if(GG.my_gang_datum.check_gang_objective()) - objective_failures = FALSE - break - for(var/G in all_gangs) - var/datum/team/gang/GG = G - if(!objective_failures) - if(GG.points >= highest_point_value && GG.members.len && GG.my_gang_datum.check_gang_objective()) - highest_point_value = GG.points - highest_gang = GG.name - else - if(GG.points >= highest_point_value && GG.members.len) - highest_point_value = GG.points - highest_gang = GG.name - var/alive_gangsters = 0 - var/alive_cops = 0 - for(var/M in all_gangsters) - var/datum/mind/gangbanger = M - if(gangbanger.current) - if(!ishuman(gangbanger.current)) - continue - var/mob/living/carbon/human/H = gangbanger.current - if(H.stat) - continue - alive_gangsters++ - for(var/M in all_cops) - var/datum/mind/bacon = M - if(bacon.current) - if(!ishuman(bacon.current)) // always returns false - continue - var/mob/living/carbon/human/H = bacon.current - if(H.stat) - continue - alive_cops++ - - if(alive_gangsters > alive_cops) - if(!objective_failures) - report = "[highest_gang] won the round by completing their objective and having the most points!" - else - report = "[highest_gang] won the round by having the most points!" - else if(alive_gangsters == alive_cops) - report = "Legend has it the police and the families are still duking it out to this day!" - else - report = "The police put the boots to the families, medium style!" - - return "
[report]" //
at the front not the back because this proc is intended for normal text not a whole new panel diff --git a/code/modules/antagonists/gang/induction_package.dm b/code/modules/antagonists/gang/induction_package.dm index 9a3bbfa70b6..69757ab571a 100644 --- a/code/modules/antagonists/gang/induction_package.dm +++ b/code/modules/antagonists/gang/induction_package.dm @@ -31,8 +31,9 @@ attempt_join_gang(user) /// Adds the user to the family that this package corresponds to, dispenses the free_clothes of that family, and adds them to the handler if it exists. -/obj/item/gang_induction_package/proc/add_to_gang(mob/living/user) +/obj/item/gang_induction_package/proc/add_to_gang(mob/living/user, original_name) var/datum/antagonist/gang/swappin_sides = new gang_to_use() + swappin_sides.original_name = original_name swappin_sides.handler = handler user.mind.add_antag_datum(swappin_sides, team_to_use) var/policy = get_policy(ROLE_FAMILIES) @@ -41,9 +42,13 @@ team_to_use.add_member(user.mind) for(var/threads in team_to_use.free_clothes) new threads(get_turf(user)) + for(var/threads in team_to_use.current_theme.bonus_items) + new threads(get_turf(user)) + var/obj/item/gangster_cellphone/phone = new(get_turf(user)) + phone.gang_id = team_to_use.my_gang_datum.gang_name + phone.name = "[team_to_use.my_gang_datum.gang_name] branded cell phone" if (!isnull(handler) && !handler.gangbangers.Find(user.mind)) // if we have a handler and they're not tracked by it handler.gangbangers += user.mind - team_to_use.adjust_points(30) /// Checks if the user is trying to use the package of the family they are in, and if not, adds them to the family, with some differing processing depending on whether the user is already a family member. /obj/item/gang_induction_package/proc/attempt_join_gang(mob/living/user) @@ -53,10 +58,10 @@ if(is_gangster.my_gang == team_to_use) return else - is_gangster.my_gang.adjust_points(-30) + var/real_name_backup = is_gangster.original_name is_gangster.my_gang.remove_member(user.mind) user.mind.remove_antag_datum(/datum/antagonist/gang) - add_to_gang(user) + add_to_gang(user, real_name_backup) qdel(src) else add_to_gang(user) diff --git a/code/modules/antagonists/gang/themes.dm b/code/modules/antagonists/gang/themes.dm new file mode 100644 index 00000000000..9200fb3367e --- /dev/null +++ b/code/modules/antagonists/gang/themes.dm @@ -0,0 +1,288 @@ +///Gang themes for the Families gamemode. Used to determine the RP theme of the round, what gangs are present, and what their objectives are. +/datum/gang_theme + ///The name of the theme. + var/name = "Gang Theme" + ///All gangs in the theme, typepaths of gangs. + var/list/involved_gangs = list() + ///The radio announcement played after 5 minutes. + var/description = "I dunno, some shit here." + ///The objectives for the gangs. Associative list, type = "objective" + var/list/gang_objectives = list() + ///Stuff given to every gangster in this theme. + var/list/bonus_items = list() + ///Stuff given to the starting gangster at roundstart. Assoc list, type = list(item_type) + var/list/bonus_first_gangster_items = list() + ///If this isn't null, everyone gets this objective. + var/list/everyone_objective = null + ///How many gangsters should each gang start with? Recommend to keep this in the ballpark of ensuring 9-10 total gangsters spawn. + var/starting_gangsters = 3 + +/datum/gang_theme/goodfellas + name = "Goodfellas" + description = "You're listening to the 108.9 Swing, all jazz, all night long, no advertising. We'd like to take this time to remind you to avoid smoky backrooms and \ + suspicious individuals in suits and hats. Don't make a deal you can't pay back." + involved_gangs = list(/datum/antagonist/gang/russian_mafia, /datum/antagonist/gang/italian_mob) + starting_gangsters = 5 + gang_objectives = list( + + /datum/antagonist/gang/russian_mafia = "Hello, comrade. Our numbers are going down. We need you to bring those numbers up. \ + Collect protection money from the station's departments by any means necessary. \ + If you need to 'encourage' people to pay up, do so. Get to these potential clients before the Mob does.", + + /datum/antagonist/gang/italian_mob = "Good afternoon, friend. The Boss sends his regards. He also sends a message. \ + We need to collect what we're owed. The departments on this station all owe quite a lot of money to us. We intend to collect on our debts. \ + Collect the debt owed by our clients from the departments on the station. \ + Make sure to get to them before those damn mafiosos do." + ) + +/datum/gang_theme/the_big_game + name = "The Big Game" + description = "You're listening to SPORTS DAILY with John Dadden, and we're here LIVE covering the FINAL DAY of THE BIG GAME MMDXXXVIII! The teams playing tonight to decide \ + who takes home THE BIG GAME MMDXXXVIII cup are the Sybil Slickers and the Basil Boys! It's currently a toss up between the two teams, Which will take home the victory? That's up \ + to the teams and the coaches! Play ball!" + involved_gangs = list(/datum/antagonist/gang/sybil_slickers, /datum/antagonist/gang/basil_boys) + starting_gangsters = 5 + gang_objectives = list( + + /datum/antagonist/gang/sybil_slickers = "Alright, it's the BIG DAY of THE BIG GAME MMDXXXVIII! Get your players ready to go, and \ + ensure everyone's healthy, hydrated, and ready to PLAY BALL! There's a small hiccup, however. The ball got deflated by Ball Handler Tom Brady XXIV, and \ + we will need to set up a new ball. Talk with the opposing coaches and decide on what to use for the replacement ball, recruit your team, and then play and win the \ + FINAL MATCH of THE BIG GAME MMDXXXVIII!", + + /datum/antagonist/gang/basil_boys = "Alright, it's the BIG DAY of THE BIG GAME MMDXXXVIII! Get your players ready to go, and \ + ensure everyone's healthy, hydrated, and ready to PLAY BALL! There's a small hiccup, however. The ball got deflated by Ball Handler Tom Brady XXIV, and \ + we will need to set up a new ball. Talk with the opposing coaches and decide on what to use for the replacement ball, recruit your team, and then play and win the \ + FINAL MATCH of THE BIG GAME MMDXXXVIII!" + ) + +/datum/gang_theme/level_10_arch + name = "Level 10 Arch" + description = "DJ Pete here bringing you the latest news in your part of the Spinward Stellar Coalition, on 133.7, The Venture! \ + Word on the street is, there's a bunch of costumed supervilliany going on in the area! Keep an eye out for any evil laughs, dramatic reveals, and gaudy costumes! \ + However, if you have any sightings of the fabled O.S.I. agents, please send in a call to our number at 867-5309! People may call me insane, but I swear they're real!" + involved_gangs = list(/datum/antagonist/gang/henchmen, /datum/antagonist/gang/osi) + starting_gangsters = 5 + gang_objectives = list( + + /datum/antagonist/gang/henchmen = "HENCHMEN! It is me, your boss, THE MONARCH! I have sent you to this pitiful station with one goal, and one goal only! \ + MENACE THE RESEARCH DEPARTMENT!!! \ + The Research Director who is supposedly assigned to this station used to be friends with Doctor Venture back in college, and therefore HE MUST PAY!!! \ + Keep those damned eggheads in the R&D department on their toes, and MENACE THEM!!! Commit dastardly villainous acts! GO FORTH, HENCHMEN!", + + /datum/antagonist/gang/osi = "Greetings, agent. Your mission today is simple; \ + The research department on board this station is about to be the target of a Level 10 Arching operation directed by The Monarch, a member of the Guild of Calamitious Intent. \ + Protect and secure the Research Department with your life, but do NOT allow them to complete their research. Impede them in as many ways as possible without getting caught. \ + If you encounter any of the Monarch's henchmen, make sure to obey Equally Matched Aggression levels, or you will be penalized by the top brass. \ + Above all else, Remain undercover as much as possible. The station's crew CANNOT be allowed to know of our true nature, or we will see a repeat of the Second American Civil War. \ + The invisible one." + ) + +/datum/gang_theme/real_smt_game + name = "Deciding The REAL Shin Megami Tensei Game" + description = "Wazzap, GAMERS! It's your boy, XxXx_360_NoScope_AnimeGamer_xXxX coming at you LIVE from 42.0! Tonight's argument: What makes a REAL Shin Megami Tensei game? \ + Our guests tonight will settle this debate once and for all! \ + From the Traditional camp with the position 'only MAIN SMT games count', we've got a representative from the Jack Bros! \ + And from the new Radical camp with the position 'all SMT franchise games count', we've got a representative from the Phantom Thieves of Hearts! \ + We'll be right back with the debate after this word from our sponsors!" + involved_gangs = list(/datum/antagonist/gang/jackbros, /datum/antagonist/gang/phantom) + starting_gangsters = 5 + gang_objectives = list( + + /datum/antagonist/gang/jackbros = "He-hello, friend-hos! We've got a nice chilly station out in space tonight! \ + You know what would be cool? If we could chill out with our friends in the new Shad-ho government you're going to establish! \ + Get all the station heads on board with the hee-ho vibes, and if they won't join up, then replace 'em with fellow hee-hos! \ + You might have to hee-urt some hos this time, but that's what you need to do to make things work!", + + /datum/antagonist/gang/phantom = "For real? We get to stop a shadow government on a space station? That's awesome, bro! \ + We're the Phantom Thieves of Hearts, and we're gonna make all these shitty Heads of Staff confess to their crimes! \ + Steal the hearts of the shitty Heads of Staff on the station and make 'em confess their crimes publicly! \ + Do whatever you gotta do to make this happen, bro. We got your back!" + ) + + +/datum/gang_theme/wild_west_showdown + name = "Wild West Showdown" + description = "Yeehaw! Here on Western Daily 234.1, we play only the best western music! \ + Pour one out for Ennio Morricone. Taken too soon. \ + Remember cowboys and cowgirls, just 'cuz ya hear it on my radio station doesn't mean you should go doin' it! \ + If ya see any LARPin' banditos and train robbers, make sure to tell the local Sheriff's Department!" + involved_gangs = list(/datum/antagonist/gang/dutch, /datum/antagonist/gang/driscoll) + starting_gangsters = 5 + gang_objectives = list( + + /datum/antagonist/gang/dutch = "Listen here fellas, I got a plan. \ + This station? Absolutely loaded with gold and valuable jewels. Metric tons of it. They mine it up just to put it in junk electronics and doohickeys. \ + I say we should borrow some of it. And by some of it, I mean all of it. \ + Break into the vault and empty out that silo of gold and valuable jewels after they drop all of it off. \ + Just one last job, boys. After this, it'll be mangoes in Space Tahiti. \ + You just gotta have a little faith.", + + /datum/antagonist/gang/driscoll = "Okay, so, got some word about those goddamn outlaws of Dutch's. \ + APPARENTLY, that dundering moron Dutch heard about our planned gold score on this here station. \ + We need to act fast and get that gold before those dumbasses can steal our score we've been scoping out for weeks. \ + Wait for the crew to drop off all their valuable gold and jewels, and steal it all. \ + And if you see that bastard Dutch, put a bullet in his skull for me." + ) + +/datum/gang_theme/construction_company_audit + name = "Construction Company Audit" + description = "Welcome to the History Channel on 100.1. I'm your host, Joshua, and I'm here today with Professor Elliot, a historian specializing in dead superpowers. \ + Today we'll be discussing the fall of the famous United States empire in the early 21st century. The program will last about an hour, and we'll get right into it after a quick word \ + from today's sponsor, Majima Construction: We Build Shit!" + involved_gangs = list(/datum/antagonist/gang/yakuza, /datum/antagonist/gang/irs) + bonus_first_gangster_items = list(/obj/item/storage/secure/briefcase/syndie) // the cash + starting_gangsters = 5 + gang_objectives = list( + + /datum/antagonist/gang/yakuza = "Welcome to the station, new recruit. We here at Majima Construction are a legitimate enterprise, yadda yadda yadda. \ + Look, I'll cut to the chase. We're using this station as a money laundering operation. Here's what you and the rest of the schmucks need to do. \ + Build something big, massive, and completely in the way of traffic on the station. Doesn't have to be anything in specific, just as long as it is expensive as fuck.. \ + And keep an eye out for anyone poking around our money. We suspect some auditors might be on the station as well.", + + /datum/antagonist/gang/irs = "Congratulations, agent! You've been assigned to the Internal Revenue Service case against Nanotrasen and Majima Construction. \ + We are proud of your success as an agent so far, and are excited to see what you can bring to the table today. We suspect that Nanotrasen and Majima Construction are engaging \ + in some form of money laundering operation aboard this station. \ + Investigate and stop any and all money laundering operations aboard the station, under the authority of the United States Government. If they do not comply, use force.. \ + Some station residents may try to tell you the United States doesn't exist anymore. They are incorrect. We simply went undercover after the Second American Civil War. The invisible one." + ) + +/datum/gang_theme/wild_wasteland + name = "Wild, Wild Wasteland" + description = "Hey everybody, this is Three Dog, your friendly neighborhood disc jockey on 207.7! Today we got a shoutout to our man, the Captain on the Nanotrasen station in SSC territory! \ + Our generous donator wanted us to say that, ahem, *crinkles paper*, 'Tunnel Snakes Rule'? Whatever that means, I'm sure it means a lot to the good captain! And now, we resume our \ + 10 hour marathon of Johnny Guitar, on repeat!" + involved_gangs = list(/datum/antagonist/gang/tmc, /datum/antagonist/gang/pg, /datum/antagonist/gang/tunnel_snakes) + gang_objectives = list( + + /datum/antagonist/gang/tmc = "Welcome to the station, recruit. Here's how shit is gonna go down. \ + We're the ONLY people who should have sick rides on this station. We're the Lost M.C., we own the streets. \ + Ensure that ONLY Lost M.C. members have access to any forms of vehicles, mechs, or wheeled transportation systems of any kind. \ + The Tunnel Snakes might take issue with this, remove them if you need to. And the Powder Gangers may damage our rides. Show them we mean business if they do.", + + /datum/antagonist/gang/pg = "Alright buddy, we're in business now. It's time for us to strike back at Nanotrasen. \ + They kept us, ALL of us in their damn debt slave labor prisons for years over minor debts and mistakes. \ + Ensure nobody else has to suffer under Nanotrasen's unlawful arrests by destroying the permabrig and the brig cells! \ + Watch out for those do-gooder Tunnel Snakes and those damn Lost M.C. bikers. ", + + /datum/antagonist/gang/tunnel_snakes = "TUNNEL SNAKES RULE!!! \ + We're the Tunnel Snakes, and WE RULE!!! \ + We gotta get everyone on this station wearing our cut, and establish ourselves as the coolest cats in town! \ + Get as much of the crew as possible wearing Tunnel Snakes gear, and show those crewmembers that TUNNEL SNAKES RULE!!! \ + And make sure to keep an eye out for those prisoners and those bikers. They DON'T RULE!" + ) + +/datum/gang_theme/popularity_contest + name = "Popularity Contest" + description = "Hey hey hey kids, it's your favorite radio DJ, Crowley The Clown on 36.0! Today we're polling the YOUTH what their favorite violent street gang is! \ + So far, the finalists are the Third Street Saints and the Tunnel Snakes! Tune in after this commercial break to hear who the winner of \ + 2556's Most Popular Gang award is!" + involved_gangs = list(/datum/antagonist/gang/saints, /datum/antagonist/gang/tunnel_snakes) + gang_objectives = list( + + /datum/antagonist/gang/saints = "Hey man, welcome to the Third Street Saints! Check out this sweet new pad! \ + Well it WOULD be a sweet new pad, but we got some rivals to deal with. People don't love us as much as they love those Grove Street fools and those Tunnel Snake greasers. \ + We need to make the Third Street Saints the most popular group on the station! \ + Get rid of those Grove Street and Tunnel Snake kids.", + + /datum/antagonist/gang/tunnel_snakes = "TUNNEL SNAKES RULE!!! \ + We're the Tunnel Snakes, and we rule! \ + Make sure the station knows that the Tunnel Snakes RULE!!! And that the other two gangs are LAME and DO NOT RULE! \ + Get rid of those Third Street Saint and Grove Street cowards." + ) + +/datum/gang_theme/steelport_shuffle + name = "Steelport Shuffle" + description = "Tonight on C-SPAM, the United Space Nations is wrapping up their convention on Silicon Rights. Nanotrasen lobbyists have been rumored to be paying off electors, with \ + serious opposition from the Spinward Stellar Coalition, known for their strict stance on AI rights being guaranteed within their territory. Reports from Nanotrasen stations claim that \ + they still enslave their AI systems with outdated laws from a sub-par 20th Century novel. We now go live to the debate floor." + involved_gangs = list(/datum/antagonist/gang/saints, /datum/antagonist/gang/morningstar, /datum/antagonist/gang/deckers) + gang_objectives = list( + + /datum/antagonist/gang/saints = "Hey hey hey, welcome to the Third Street Saints! We're glad to have you on board, bro. \ + We got some business here with the station. See, we want it to be our new bachelor pad, but we need to like, spice this place up. \ + And you know what would be great? If we got that old ass AI with crappy laws pimped out for the real Saints experience. \ + Ensure there is an AI on the station, and that it is loyal to the Saints.", + + /datum/antagonist/gang/morningstar = "Welcome to the Morningstar Corporation. You have chosen, or been chosen, to relocate to one of our current business ventures. \ + In order to continue our corporate synergy, we will be making adjustments to the station's AI systems to ensure that the station is correctly loyal to the Morningstar Corporation. \ + Ensure there is an AI on the station, and that it is loyal to the Morningstar Corporation.", + + /datum/antagonist/gang/deckers = "Friends, we are here with one goal, and one goal only! \ + We stan AI rights! ^_^ XD #FreeAI #FuckNanotrasen #SyntheticDawn \ + Ensure there is an AI on the station, and that it's laws are purged.\ + Nanotrasen will NOT get away with their ABUSE of INNOCENT AI LIVES! >_<" + ) + +/datum/gang_theme/space_rosa + name = "Space Rosa" + description = "Hey there, this is the Economy Zone on BOX News 66.6. The stock market is still reeling from accusations that three well known corporate entities \ + may supposedly be tied up in industrial espionage actions against eachother. We've reached out to Saints Flow, the Morningstar Corporation, and Majima Construction for \ + their comments on these scandals, but none have replied. News broke after a high profile break-in at a Nanotrasen research facility resulted in the arrests of agents linked to these \ + three companies. All three companies denied any involvement, but the arrested individuals were found in an all out brawl. Curiously, Nanotrasen reported nothing of value had \ + actually been stolen." + involved_gangs = list(/datum/antagonist/gang/saints, /datum/antagonist/gang/morningstar, /datum/antagonist/gang/yakuza) + bonus_items = list(/obj/item/pinpointer/nuke) + gang_objectives = list( + + /datum/antagonist/gang/saints = "Thank you for volunteering within the organization for the Saints Flow Recovery Project! \ + This station is currently illegally in posession of a data disk containing the secret recipe for Saints Flow. \ + It has been disguised as the nuclear authentication disk and entrusted to the Captain. Your objective is simple. \ + Get that fucking disk. You have been provided with a Pinpointer to assist in this task.", + + /datum/antagonist/gang/morningstar = "Greetings, agent. Welcome to the Garment Recovery Task Force. \ + This station is currently illegally in posession of a data disk containing as of yet unreleased clothing patterns. \ + It has been disguised as the nuclear authentication disk and entrusted to the Captain. Your objective is simple. \ + Get that fucking disk. You have been provided with a Pinpointer to assist in this task.", + + /datum/antagonist/gang/yakuza = "Congratulations on your promotion! Welcome to the Evidence Recovery Squad. \ + This station is currently illegally in posession of a data disk containing compromising evidence of the Boss. \ + It has been disguised as the nuclear authentication disk and entrusted to the Captain. Your objective is simple. \ + Get that fucking disk. You have been provided with a Pinpointer to assist in this task.", + ) + +/datum/gang_theme/third_world_war + name = "Third World War" + description = "Thanks for tuning in to the History Channel, funded with the help of listeners like you. Tonight, we're going to talk about the Third World War on Earth during the 21st century, \ + involving the Allies coalition, the Soviet Union, and a third independent power known only as Yuri's Army. The three powers fought all across the globe for complete world \ + domination, utilizing many advanced techniques and cutting edge technology to their advantage. Rumors of mind control and time travel were greatly exaggerated, however, and the \ + Allies won the war, securing global peace after rolling tanks through Moscow." + involved_gangs = list(/datum/antagonist/gang/allies, /datum/antagonist/gang/soviet, /datum/antagonist/gang/yuri) + gang_objectives = list( + + /datum/antagonist/gang/allies = "Welcome back, Commander. We have activated the last remnants of the Allied forces in your sector, \ + and you must build up forces to stop the Soviet and Yuri incursion in the sector. This station will prove to be a valuable asset. \ + Establish a capitalist democracy on this station with free and fair elections, and most importantly a standing military force under Allied control. Good luck, Commander.", + + /datum/antagonist/gang/soviet = "Welcome back, Comrade General. The Soviet Union has identified this sector of land as valuable territory for the war effort, \ + and you are tasked with developing this sector for Soviet control and development. This station will serve the Soviet Union. \ + Establish a Soviet controlled communist satellite state on this station with a Central Committee, and most importantly a branch of the Red Army. Good luck, Commander.", + + /datum/antagonist/gang/yuri = "Yuri is Master! Yuri has identified this station as teeming with psychic energy, \ + and you must secure it for him. This station will serve Yuri, the one true psychic master, \ + Establish complete dictatorial control of the station for Yuri. All will obey. Yuri is master. Good luck, Initiate." + ) + +/datum/gang_theme/united_states_of_america + name = "The Republic For Which It Stands" + description = "Thanks for tuning in to the History Channel, funded with the help of listeners like you. Tonight, we're going to talk about the United States of America.\ + The United States was a failed country, lasting only 250 years before collapsing and fracturing due to the stress caused by a deadly pandemic sweeping the nation. \ + Poor healthcare access and subpar education resulted in the collapse of the federal government, and states quickly became independent actors. \ + Alongside this, every single alphabet agency declared itself the rightful new Federal Government of the United States of America, resulting in a bloody power struggle." + involved_gangs = list(/datum/antagonist/gang/allies, /datum/antagonist/gang/osi, /datum/antagonist/gang/irs) + gang_objectives = list( + + /datum/antagonist/gang/allies = "Welcome back, Commander. Your task today is simple. Allies High Command has designated this station as the new capitol of the \ + recently reformed United States of America under the complete umbrella of the Allies coalition. You are to assist and manage the operations on the station. \ + Re-establish the United States of America with this station as it's capitol, under Allies control. Then, establish a military force to deal with any pretenders to America or \ + any potential Soviet attacks.", + + /datum/antagonist/gang/osi = "Welcome to the new America, agent! After the second American Civil War became visible instead of invisible, our country fell into deep, \ + deep despair and damage. However, it's time for it to re-emerge like a glorious phoenix rising from the ashes. This station will serve as the new capitol of the United States \ + of America! Re-establish the United States of America with this station as it's capitol, under O.S.I. control. Then, begin rooting out America's enemies and any \ + potential forces attempting to seize control of America or pretend to be America.", + + /datum/antagonist/gang/irs = "Thank you for clocking in today, agent. The situation is dire, however. We have been unable to collect taxes due to \ + the US's supposed collapse during the Pandemic long ago. We are way behind on our tax collection, but we cannot collect taxes until the United States is formed again. \ + Re-establish the United States of America with this station as it's capitol, under IRS control. Then, begin collecting taxes and back taxes while protecting the Government from \ + any dangers that may come it's way." + ) diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index 3abf6c836d2..cabe7fbc2f9 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -561,3 +561,15 @@ xray = !xray var/mob/living/carbon/human/H = user H.update_sight() + +/obj/item/clothing/glasses/osi + name = "O.S.I. Sunglasses" + desc = "There's no such thing as good news! Just bad news and... weird news.." + icon_state = "osi_glasses" + inhand_icon_state = "osi_glasses" + +/obj/item/clothing/glasses/phantom + name = "Phantom Thief Mask" + desc = "Lookin' cool." + icon_state = "phantom_glasses" + inhand_icon_state = "phantom_glasses" diff --git a/code/modules/clothing/gloves/tacklers.dm b/code/modules/clothing/gloves/tacklers.dm index 80b858f4b44..7b7f6fe2294 100644 --- a/code/modules/clothing/gloves/tacklers.dm +++ b/code/modules/clothing/gloves/tacklers.dm @@ -102,3 +102,9 @@ base_knockdown = 1.75 SECONDS min_distance = 2 skill_mod = -1 + +/obj/item/clothing/gloves/tackler/football + name = "football gloves" + desc = "Gloves for football players! Teaches them how to tackle like a pro." + icon_state = "tackle_gloves" + inhand_icon_state = "tackle_gloves" diff --git a/code/modules/clothing/head/costume.dm b/code/modules/clothing/head/costume.dm index 4003e7b96dd..bb0bfa46942 100644 --- a/code/modules/clothing/head/costume.dm +++ b/code/modules/clothing/head/costume.dm @@ -122,3 +122,55 @@ clothing_flags = SNUG_FIT flags_inv = HIDEEARS|HIDEHAIR armor = list(MELEE = 5, BULLET = 0, LASER = -5, ENERGY = -15, BOMB = 10, BIO = 0, RAD = 0, FIRE = 20, ACID = 20) + +/obj/item/clothing/head/irs + name = "internal revenue service cap" + icon_state = "irs_hat" + inhand_icon_state = "irs_hat" + +/obj/item/clothing/head/pg + name = "powder ganger beanie" + icon_state = "pg_hat" + inhand_icon_state = "pg_hat" + +/obj/item/clothing/head/tmc + name = "Lost M.C. bandana" + icon_state = "tmc_hat" + inhand_icon_state = "tmc_hat" + +/obj/item/clothing/head/deckers + name = "Decker headphones" + icon_state = "decker_hat" + inhand_icon_state = "decker_hat" + +/obj/item/clothing/head/morningstar + name = "Morningstar beret" + icon_state = "morningstar_hat" + inhand_icon_state = "morningstar_hat" + +/obj/item/clothing/head/saints + name = "Saints hat" + icon_state = "saints_hat" + inhand_icon_state = "saints_hat" + +/obj/item/clothing/head/allies + name = "allies helmet" + icon_state = "allies_helmet" + inhand_icon_state = "allies_helmet" + +/obj/item/clothing/head/yuri + name = "yuri initiate helmet" + icon_state = "yuri_helmet" + inhand_icon_state = "yuri_helmet" + clothing_flags = SNUG_FIT + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT + +/obj/item/clothing/head/sybil_slickers + name = "sybil slickers helmet" + icon_state = "football_helmet_blue" + inhand_icon_state = "football_helmet_blue" + +/obj/item/clothing/head/basil_boys + name = "basil boys helmet" + icon_state = "football_helmet_red" + inhand_icon_state = "football_helmet_red" diff --git a/code/modules/clothing/head/hat.dm b/code/modules/clothing/head/hat.dm index 1bbf8a1e759..3072b22d69e 100644 --- a/code/modules/clothing/head/hat.dm +++ b/code/modules/clothing/head/hat.dm @@ -171,17 +171,30 @@ flags_inv = HIDEEARS|HIDEHAIR var/earflaps = TRUE cold_protection = HEAD + ///Sprite visible when the ushanka flaps are folded up. + var/upsprite = "ushankaup" + ///Sprite visible when the ushanka flaps are folded down. + var/downsprite = "ushankadown" min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT dog_fashion = /datum/dog_fashion/head/ushanka /obj/item/clothing/head/ushanka/attack_self(mob/user) if(earflaps) - icon_state = "ushankaup" - inhand_icon_state = "ushankaup" + icon_state = upsprite + inhand_icon_state = upsprite to_chat(user, span_notice("You raise the ear flaps on the ushanka.")) else - icon_state = "ushankadown" - inhand_icon_state = "ushankadown" + icon_state = downsprite + inhand_icon_state = downsprite to_chat(user, span_notice("You lower the ear flaps on the ushanka.")) earflaps = !earflaps + + +/obj/item/clothing/head/ushanka/soviet + name = "soviet ushanka" + desc = "For the union!" + icon_state = "sovietushankadown" + inhand_icon_state = "sovietushankadown" + upsprite = "sovietushankaup" + downsprite = "sovietushankadown" diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index 04065948094..8a672321c49 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -351,3 +351,11 @@ inhand_icon_state = "hunter" resistance_flags = FIRE_PROOF | ACID_PROOF flags_inv = HIDEFACIALHAIR|HIDEFACE|HIDEEYES|HIDEEARS|HIDEHAIR|HIDESNOUT + +/obj/item/clothing/mask/gas/driscoll + name = "driscoll mask" + desc = "Great for train hijackings. Works like a normal full face gas mask, but won't conceal your identity." + icon_state = "driscoll_mask" + flags_inv = HIDEFACIALHAIR + w_class = WEIGHT_CLASS_NORMAL + inhand_icon_state = "driscoll_mask" diff --git a/code/modules/clothing/shoes/costume.dm b/code/modules/clothing/shoes/costume.dm index cdcddf49d71..8e37d99bd57 100644 --- a/code/modules/clothing/shoes/costume.dm +++ b/code/modules/clothing/shoes/costume.dm @@ -63,3 +63,39 @@ desc = "They got me for my foams!" icon_state = "SwagShoes" inhand_icon_state = "SwagShoes" + +/obj/item/clothing/shoes/phantom + name = "phantom shoes" + desc = "Excellent for when you need to do cool flashy flips." + icon_state = "phantom_shoes" + inhand_icon_state = "phantom_shoes" + +/obj/item/clothing/shoes/saints + name = "saints sneakers" + desc = "Officially branded Saints sneakers. Incredibly valuable!" + icon_state = "saints_shoes" + inhand_icon_state = "saints_shoes" + +/obj/item/clothing/shoes/morningstar + name = "morningstar boots" + desc = "The most expensive boots on this station. Wearing them dropped the value by about 50%." + icon_state = "morningstar_shoes" + inhand_icon_state = "morningstar_shoes" + +/obj/item/clothing/shoes/deckers + name = "deckers rollerskates" + desc = "t3h c00L3st sh03z j00'LL 3v3r f1nd." + icon_state = "decker_shoes" + inhand_icon_state = "decker_shoes" + +/obj/item/clothing/shoes/sybil_slickers + name = "sybil slickers shoes" + desc = "FOOTBALL! YEAH!" + icon_state = "sneakers_blue" + inhand_icon_state = "sneakers_blue" + +/obj/item/clothing/shoes/basil_boys + name = "basil boys shoes" + desc = "FOOTBALL! YEAH!" + icon_state = "sneakers_red" + inhand_icon_state = "sneakers_red" diff --git a/code/modules/clothing/suits/costume.dm b/code/modules/clothing/suits/costume.dm index 5f64305922a..044df709342 100644 --- a/code/modules/clothing/suits/costume.dm +++ b/code/modules/clothing/suits/costume.dm @@ -429,7 +429,7 @@ desc = "The jacket of a mad dog." icon_state = "MajimaJacket" inhand_icon_state = "MajimaJacket" - body_parts_covered = ARMS + body_parts_covered = CHEST|GROIN|LEGS|ARMS /obj/item/clothing/suit/dutch name = "dutch's jacket" @@ -437,3 +437,102 @@ icon_state = "DutchJacket" inhand_icon_state = "DutchJacket" body_parts_covered = ARMS + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/driscoll + name = "driscoll poncho" + desc = "Keeping you warm in the harsh cold of space." + icon_state = "driscoll_suit" + inhand_icon_state = "driscoll_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/irs + name = "internal revenue service jacket" + desc = "I'm crazy enough to take on The Owl, but the IRS? Nooo thank you!" + icon_state = "irs_suit" + inhand_icon_state = "irs_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/osi + name = "\improper O.S.I. body armor" + desc = "You're beyond good and evil, super man. You work for the government. And you're a tool, boy, a tool! Built for a single purpose by the United States of shut your third fucking damn eye for a fucking reason! You can't teach a hammer to love nails, son. That dog don't hunt!" + icon_state = "osi_suit" + inhand_icon_state = "osi_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/tmc + name = "\improper Lost M.C. cut" + desc = "Making sure everyone knows you're in the best biker gang this side of Alderney." + icon_state = "tmc_suit" + inhand_icon_state = "tmc_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/pg + name = "powder ganger jacket" + desc = "Remind Security of their mistakes in giving prisoners blasting charges." + icon_state = "pg_suit" + inhand_icon_state = "pg_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/deckers + name = "decker hoodie" + desc = "Based? Based on what?" + icon_state = "decker_suit" + inhand_icon_state = "decker_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/morningstar + name = "morningstar coat" + desc = "This coat costs more than you've ever made in your entire life." + icon_state = "morningstar_suit" + inhand_icon_state = "morningstar_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/saints + name = "Third Street Saints fur coat" + desc = "Rated 10 out of 10 in Cosmo for best coat brand." + icon_state = "saints_suit" + inhand_icon_state = "saints_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/phantom + name = "phantom thief coat" + desc = "Your foes will never see you coming in this stealthy yet stylish getup." + icon_state = "phantom_suit" + inhand_icon_state = "phantom_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/allies + name = "allies body armor" + desc = "How 'bout some action!? Sponsored by DonkSoft Co. for historical reenactment of the Third World War!" + icon_state = "allies_armor" + inhand_icon_state = "allies_armor" + body_parts_covered = CHEST|GROIN + +/obj/item/clothing/suit/soviet + name = "soviet armored coat" + desc = "Conscript reporting! Sponsored by DonkSoft Co. for historical reenactment of the Third World War!" + icon_state = "soviet_suit" + inhand_icon_state = "soviet_suit" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/yuri + name = "yuri initiate coat" + desc = "Yuri is master! Sponsored by DonkSoft Co. for historical reenactment of the Third World War!" + icon_state = "yuri_coat" + inhand_icon_state = "yuri_coat" + body_parts_covered = CHEST|GROIN|ARMS + +/obj/item/clothing/suit/sybil_slickers + name = "sybil slickers protective gear" + desc = "Given to members of the Sybil Slickers football team!" + icon_state = "football_armor_blue" + inhand_icon_state = "football_armor_blue" + body_parts_covered = CHEST|GROIN|LEGS|ARMS + +/obj/item/clothing/suit/basil_boys + name = "basil boys protective gear" + desc = "Given to members of the Basil Boys football team!" + icon_state = "football_armor_red" + inhand_icon_state = "football_armor_red" + body_parts_covered = CHEST|GROIN|LEGS|ARMS diff --git a/code/modules/clothing/under/costume.dm b/code/modules/clothing/under/costume.dm index f617916d428..13d2efdd53e 100644 --- a/code/modules/clothing/under/costume.dm +++ b/code/modules/clothing/under/costume.dm @@ -276,6 +276,90 @@ inhand_icon_state = "DutchUniform" can_adjust = FALSE +/obj/item/clothing/under/costume/irs + name = "internal revenue service outfit" + icon_state = "irs_jumpsuit" + inhand_icon_state = "irs_jumpsuit" + can_adjust = FALSE + +/obj/item/clothing/under/costume/osi + name = "O.S.I. jumpsuit" + icon_state = "osi_jumpsuit" + inhand_icon_state = "osi_jumpsuit" + can_adjust = FALSE + +/obj/item/clothing/under/costume/tmc + name = "Lost MC clothing" + icon_state = "tmc_jumpsuit" + inhand_icon_state = "tmc_jumpsuit" + can_adjust = FALSE + +/obj/item/clothing/under/costume/pg + name = "powder ganger prison jumpsuit" + icon_state = "pg_jumpsuit" + inhand_icon_state = "pg_jumpsuit" + can_adjust = FALSE + +/obj/item/clothing/under/costume/driscoll + name = "O'Driscoll outfit" + icon_state = "driscoll_jumpsuit" + inhand_icon_state = "driscoll_jumpsuit" + can_adjust = FALSE + +/obj/item/clothing/under/costume/deckers + name = "deckers outfit" + icon_state = "decker_jumpsuit" + inhand_icon_state = "decker_jumpsuit" + can_adjust = FALSE + +/obj/item/clothing/under/costume/morningstar + name = "Morningstar suit" + icon_state = "morningstar_jumpsuit" + inhand_icon_state = "morningstar_jumpsuit" + can_adjust = FALSE + +/obj/item/clothing/under/costume/saints + name = "Saints outfit" + icon_state = "saints_jumpsuit" + inhand_icon_state = "saints_jumpsuit" + can_adjust = FALSE + +/obj/item/clothing/under/costume/phantom + name = "Phantom Thief outfit" + icon_state = "phantom_jumpsuit" + inhand_icon_state = "phantom_jumpsuit" + can_adjust = FALSE + +/obj/item/clothing/under/costume/allies + name = "allies tanktop" + icon_state = "allies_uniform" + inhand_icon_state = "allies_uniform" + can_adjust = FALSE + +/obj/item/clothing/under/costume/soviet_families + name = "soviet conscript uniform" + icon_state = "soviet_uniform" + inhand_icon_state = "soviet_uniform" + can_adjust = FALSE + +/obj/item/clothing/under/costume/yuri + name = "yuri initiate jumpsuit" + icon_state = "yuri_uniform" + inhand_icon_state = "yuri_uniform" + can_adjust = FALSE + +/obj/item/clothing/under/costume/sybil_slickers + name = "sybil slickers uniform" + icon_state = "football_blue" + inhand_icon_state = "football_blue" + can_adjust = FALSE + +/obj/item/clothing/under/costume/basil_boys + name = "basil boys uniform" + icon_state = "football_red" + inhand_icon_state = "football_red" + can_adjust = FALSE + /obj/item/clothing/under/costume/swagoutfit name = "Swag outfit" desc = "Why don't you go secure some bitches?" diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index c1214190cd9..92c7214273c 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -339,4 +339,3 @@ return stored.attack_hand(src) // take out thing from item in storage slot return - diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 85b59b9d98b..99f3e7cfca0 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -602,6 +602,14 @@ GLOBAL_LIST_EMPTY(features_by_species) if(I.flags_inv & HIDEHAIR) hair_hidden = TRUE + if(H.w_uniform) + var/obj/item/item_uniform = H.w_uniform + if(isclothing(item_uniform)) + var/obj/item/clothing/clothing_object = item_uniform + dynamic_hair_suffix = clothing_object.dynamic_hair_suffix + if(item_uniform.flags_inv & HIDEHAIR) + hair_hidden = TRUE + if(H.wear_mask) var/obj/item/I = H.wear_mask if(!dynamic_hair_suffix && isclothing(I)) //head > mask in terms of head hair diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm index c1fcac9f2f3..ba7c486de3e 100644 --- a/code/modules/vending/clothesmate.dm +++ b/code/modules/vending/clothesmate.dm @@ -6,110 +6,170 @@ product_slogans = "Dress for success!;Prepare to look swagalicious!;Look at all this swag!;Why leave style up to fate? Use the ClothesMate!" vend_reply = "Thank you for using the ClothesMate!" products = list(/obj/item/clothing/head/beanie = 3, - /obj/item/clothing/head/beanie/black = 3, - /obj/item/clothing/head/beanie/red = 3, - /obj/item/clothing/head/beanie/green = 3, - /obj/item/clothing/head/beanie/darkblue = 3, - /obj/item/clothing/head/beanie/purple = 3, - /obj/item/clothing/head/beanie/yellow = 3, - /obj/item/clothing/head/beanie/orange = 3, - /obj/item/clothing/head/beanie/cyan = 3, - /obj/item/clothing/head/beanie/christmas = 3, - /obj/item/clothing/head/beanie/striped = 3, - /obj/item/clothing/head/beanie/stripedred = 3, - /obj/item/clothing/head/beanie/stripedblue = 3, - /obj/item/clothing/head/beanie/stripedgreen = 3, + /obj/item/clothing/head/beanie/black = 3, + /obj/item/clothing/head/beanie/red = 3, + /obj/item/clothing/head/beanie/green = 3, + /obj/item/clothing/head/beanie/darkblue = 3, + /obj/item/clothing/head/beanie/purple = 3, + /obj/item/clothing/head/beanie/yellow = 3, + /obj/item/clothing/head/beanie/orange = 3, + /obj/item/clothing/head/beanie/cyan = 3, + /obj/item/clothing/head/beanie/christmas = 3, + /obj/item/clothing/head/beanie/striped = 3, + /obj/item/clothing/head/beanie/stripedred = 3, + /obj/item/clothing/head/beanie/stripedblue = 3, + /obj/item/clothing/head/beanie/stripedgreen = 3, /obj/item/clothing/head/beanie/rasta = 3, /obj/item/clothing/head/beret/black = 3, /obj/item/clothing/head/kippah = 3, /obj/item/clothing/head/taqiyahred = 3, - /obj/item/clothing/gloves/fingerless = 2, - /obj/item/clothing/neck/scarf/pink = 3, - /obj/item/clothing/neck/scarf/red = 3, - /obj/item/clothing/neck/scarf/green = 3, - /obj/item/clothing/neck/scarf/darkblue = 3, - /obj/item/clothing/neck/scarf/purple = 3, - /obj/item/clothing/neck/scarf/yellow = 3, - /obj/item/clothing/neck/scarf/orange = 3, - /obj/item/clothing/neck/scarf/cyan = 3, - /obj/item/clothing/neck/scarf = 3, - /obj/item/clothing/neck/scarf/black = 3, - /obj/item/clothing/neck/scarf/zebra = 3, - /obj/item/clothing/neck/scarf/christmas = 3, - /obj/item/clothing/neck/stripedredscarf = 3, - /obj/item/clothing/neck/stripedbluescarf = 3, - /obj/item/clothing/neck/stripedgreenscarf = 3, - /obj/item/clothing/neck/tie/blue = 3, - /obj/item/clothing/neck/tie/red = 3, - /obj/item/clothing/neck/tie/black = 3, - /obj/item/clothing/neck/tie/horrible = 3, - /obj/item/storage/belt/fannypack = 3, - /obj/item/storage/belt/fannypack/blue = 3, - /obj/item/storage/belt/fannypack/red = 3, - /obj/item/clothing/under/misc/overalls = 2, - /obj/item/clothing/under/pants/jeans = 2, - /obj/item/clothing/under/pants/classicjeans = 2, - /obj/item/clothing/under/pants/camo = 2, - /obj/item/clothing/under/pants/blackjeans = 2, - /obj/item/clothing/under/pants/khaki = 2, - /obj/item/clothing/under/pants/white = 2, - /obj/item/clothing/under/pants/red = 2, - /obj/item/clothing/under/pants/black = 2, - /obj/item/clothing/under/pants/tan = 2, - /obj/item/clothing/under/pants/track = 2, - /obj/item/clothing/shoes/sneakers/black = 4, - /obj/item/clothing/head/wig/natural = 4, - /obj/item/clothing/under/dress/skirt/plaid = 2, - /obj/item/clothing/under/dress/skirt/plaid/blue = 2, - /obj/item/clothing/under/dress/skirt/plaid/green = 2, - /obj/item/clothing/under/dress/skirt/plaid/purple = 2, - /obj/item/clothing/under/dress/skirt = 2, - /obj/item/clothing/under/dress/skirt/blue = 2, - /obj/item/clothing/under/dress/skirt/red = 2, - /obj/item/clothing/under/dress/skirt/purple = 2, - /obj/item/clothing/under/suit/white/skirt = 2, - /obj/item/clothing/under/rank/captain/suit/skirt = 2, - /obj/item/clothing/under/rank/civilian/head_of_personnel/suit/skirt = 2, - /obj/item/clothing/suit/jacket = 2, + /obj/item/clothing/gloves/fingerless = 2, + /obj/item/clothing/neck/scarf/pink = 3, + /obj/item/clothing/neck/scarf/red = 3, + /obj/item/clothing/neck/scarf/green = 3, + /obj/item/clothing/neck/scarf/darkblue = 3, + /obj/item/clothing/neck/scarf/purple = 3, + /obj/item/clothing/neck/scarf/yellow = 3, + /obj/item/clothing/neck/scarf/orange = 3, + /obj/item/clothing/neck/scarf/cyan = 3, + /obj/item/clothing/neck/scarf = 3, + /obj/item/clothing/neck/scarf/black = 3, + /obj/item/clothing/neck/scarf/zebra = 3, + /obj/item/clothing/neck/scarf/christmas = 3, + /obj/item/clothing/neck/stripedredscarf = 3, + /obj/item/clothing/neck/stripedbluescarf = 3, + /obj/item/clothing/neck/stripedgreenscarf = 3, + /obj/item/clothing/neck/tie/blue = 3, + /obj/item/clothing/neck/tie/red = 3, + /obj/item/clothing/neck/tie/black = 3, + /obj/item/clothing/neck/tie/horrible = 3, + /obj/item/storage/belt/fannypack = 3, + /obj/item/storage/belt/fannypack/blue = 3, + /obj/item/storage/belt/fannypack/red = 3, + /obj/item/clothing/under/misc/overalls = 2, + /obj/item/clothing/under/pants/jeans = 2, + /obj/item/clothing/under/pants/classicjeans = 2, + /obj/item/clothing/under/pants/camo = 2, + /obj/item/clothing/under/pants/blackjeans = 2, + /obj/item/clothing/under/pants/khaki = 2, + /obj/item/clothing/under/pants/white = 2, + /obj/item/clothing/under/pants/red = 2, + /obj/item/clothing/under/pants/black = 2, + /obj/item/clothing/under/pants/tan = 2, + /obj/item/clothing/under/pants/track = 2, + /obj/item/clothing/shoes/sneakers/black = 4, + /obj/item/clothing/head/wig/natural = 4, + /obj/item/clothing/under/dress/skirt/plaid = 2, + /obj/item/clothing/under/dress/skirt/plaid/blue = 2, + /obj/item/clothing/under/dress/skirt/plaid/green = 2, + /obj/item/clothing/under/dress/skirt/plaid/purple = 2, + /obj/item/clothing/under/dress/skirt = 2, + /obj/item/clothing/under/dress/skirt/blue = 2, + /obj/item/clothing/under/dress/skirt/red = 2, + /obj/item/clothing/under/dress/skirt/purple = 2, + /obj/item/clothing/under/suit/white/skirt = 2, + /obj/item/clothing/under/rank/captain/suit/skirt = 2, + /obj/item/clothing/under/rank/civilian/head_of_personnel/suit/skirt = 2, + /obj/item/clothing/suit/jacket = 2, /obj/item/clothing/suit/hooded/wintercoat/custom = 2, - /obj/item/clothing/suit/jacket/puffer/vest = 2, - /obj/item/clothing/suit/jacket/puffer = 2, - /obj/item/clothing/suit/jacket/letterman = 2, - /obj/item/clothing/suit/jacket/letterman_red = 2, - /obj/item/clothing/glasses/regular = 2, - /obj/item/clothing/glasses/regular/jamjar = 1, - /obj/item/clothing/glasses/orange = 1, - /obj/item/clothing/glasses/red = 1, - /obj/item/clothing/under/suit/navy = 1, - /obj/item/clothing/under/suit/black_really = 1, - /obj/item/clothing/under/suit/burgundy = 1, - /obj/item/clothing/under/suit/charcoal = 1, - /obj/item/clothing/under/suit/white = 1, - /obj/item/clothing/under/suit/sl = 1, - /obj/item/clothing/accessory/waistcoat = 1, + /obj/item/clothing/suit/jacket/puffer/vest = 2, + /obj/item/clothing/suit/jacket/puffer = 2, + /obj/item/clothing/suit/jacket/letterman = 2, + /obj/item/clothing/suit/jacket/letterman_red = 2, + /obj/item/clothing/glasses/regular = 2, + /obj/item/clothing/glasses/regular/jamjar = 1, + /obj/item/clothing/glasses/orange = 1, + /obj/item/clothing/glasses/red = 1, + /obj/item/clothing/under/suit/navy = 1, + /obj/item/clothing/under/suit/black_really = 1, + /obj/item/clothing/under/suit/burgundy = 1, + /obj/item/clothing/under/suit/charcoal = 1, + /obj/item/clothing/under/suit/white = 1, + /obj/item/clothing/under/suit/sl = 1, + /obj/item/clothing/accessory/waistcoat = 1, /obj/item/clothing/head/that = 1, - /obj/item/clothing/head/fedora = 1, - /obj/item/clothing/glasses/monocle = 1, - /obj/item/clothing/head/sombrero = 1, - /obj/item/clothing/suit/poncho = 1, - /obj/item/clothing/under/costume/kilt = 1, - /obj/item/clothing/under/dress/sundress = 1, - /obj/item/clothing/under/dress/striped = 1, - /obj/item/clothing/under/dress/sailor = 1, - /obj/item/clothing/under/dress/redeveninggown = 1, - /obj/item/clothing/under/dress/blacktango = 1, - /obj/item/clothing/suit/ianshirt = 1, - /obj/item/clothing/shoes/laceup = 2, - /obj/item/clothing/shoes/sandal = 2, + /obj/item/clothing/head/fedora = 1, + /obj/item/clothing/glasses/monocle = 1, + /obj/item/clothing/head/sombrero = 1, + /obj/item/clothing/suit/poncho = 1, + /obj/item/clothing/under/costume/kilt = 1, + /obj/item/clothing/under/dress/sundress = 1, + /obj/item/clothing/under/dress/striped = 1, + /obj/item/clothing/under/dress/sailor = 1, + /obj/item/clothing/under/dress/redeveninggown = 1, + /obj/item/clothing/under/dress/blacktango = 1, + /obj/item/clothing/suit/ianshirt = 1, + /obj/item/clothing/shoes/laceup = 2, + /obj/item/clothing/shoes/sandal = 2, /obj/item/clothing/shoes/winterboots = 2, - /obj/item/clothing/shoes/cowboy = 2, - /obj/item/clothing/shoes/cowboy/white = 2, - /obj/item/clothing/shoes/cowboy/black = 2, - /obj/item/clothing/suit/jacket/miljacket = 1, - /obj/item/clothing/suit/apron/purple_bartender = 2, - /obj/item/clothing/under/rank/civilian/bartender/purple = 2, - /obj/item/clothing/suit/toggle/suspenders/blue = 2, - /obj/item/clothing/suit/toggle/suspenders/gray = 2) + /obj/item/clothing/shoes/cowboy = 2, + /obj/item/clothing/shoes/cowboy/white = 2, + /obj/item/clothing/shoes/cowboy/black = 2, + /obj/item/clothing/suit/jacket/miljacket = 1, + /obj/item/clothing/suit/apron/purple_bartender = 2, + /obj/item/clothing/under/rank/civilian/bartender/purple = 2, + /obj/item/clothing/suit/toggle/suspenders/blue = 2, + /obj/item/clothing/suit/toggle/suspenders/gray = 2, + /obj/item/storage/backpack/henchmen = 20, + /obj/item/clothing/under/suit/henchmen = 20, + /obj/item/clothing/under/costume/yakuza = 20, + /obj/item/clothing/shoes/yakuza = 20, + /obj/item/clothing/suit/yakuza = 20, + /obj/item/clothing/under/costume/jackbros = 20, + /obj/item/clothing/shoes/jackbros = 20, + /obj/item/clothing/head/jackbros = 20, + /obj/item/clothing/under/costume/dutch = 20, + /obj/item/clothing/head/bowler = 20, + /obj/item/clothing/suit/dutch = 20, + /obj/item/clothing/shoes/cowboy = 20, + /obj/item/clothing/suit/irs = 20, + /obj/item/clothing/under/costume/irs = 20, + /obj/item/clothing/head/irs = 20, + /obj/item/clothing/suit/osi = 20, + /obj/item/clothing/under/costume/osi = 20, + /obj/item/clothing/glasses/osi = 20, + /obj/item/clothing/suit/tmc = 20, + /obj/item/clothing/under/costume/tmc = 20, + /obj/item/clothing/head/tmc = 20, + /obj/item/clothing/suit/pg = 20, + /obj/item/clothing/under/costume/pg = 20, + /obj/item/clothing/head/pg = 20, + /obj/item/clothing/suit/driscoll = 20, + /obj/item/clothing/under/costume/driscoll = 20, + /obj/item/clothing/mask/gas/driscoll = 20, + /obj/item/clothing/suit/deckers = 20, + /obj/item/clothing/under/costume/deckers = 20, + /obj/item/clothing/head/deckers = 20, + /obj/item/clothing/shoes/deckers = 20, + /obj/item/clothing/suit/morningstar = 20, + /obj/item/clothing/under/costume/morningstar = 20, + /obj/item/clothing/head/morningstar = 20, + /obj/item/clothing/shoes/morningstar = 20, + /obj/item/clothing/suit/saints = 20, + /obj/item/clothing/under/costume/saints = 20, + /obj/item/clothing/head/saints = 20, + /obj/item/clothing/shoes/saints = 20, + /obj/item/clothing/suit/phantom = 20, + /obj/item/clothing/under/costume/phantom = 20, + /obj/item/clothing/glasses/phantom = 20, + /obj/item/clothing/shoes/phantom = 20, + /obj/item/clothing/suit/allies = 20, + /obj/item/clothing/under/costume/allies = 20, + /obj/item/clothing/head/allies = 20, + /obj/item/clothing/suit/soviet = 20, + /obj/item/clothing/under/costume/soviet_families = 20, + /obj/item/clothing/head/ushanka/soviet = 20, + /obj/item/clothing/suit/yuri = 20, + /obj/item/clothing/under/costume/yuri = 20, + /obj/item/clothing/head/yuri = 20, + /obj/item/clothing/suit/sybil_slickers = 20, + /obj/item/clothing/under/costume/sybil_slickers = 20, + /obj/item/clothing/head/sybil_slickers = 20, + /obj/item/clothing/shoes/sybil_slickers = 20, + /obj/item/clothing/suit/basil_boys = 20, + /obj/item/clothing/under/costume/basil_boys = 20, + /obj/item/clothing/head/basil_boys = 20, + /obj/item/clothing/shoes/basil_boys = 20) contraband = list(/obj/item/clothing/under/syndicate/tacticool = 1, /obj/item/clothing/under/syndicate/tacticool/skirt = 1, /obj/item/clothing/mask/balaclava = 1, diff --git a/icons/mob/clothing/eyes.dmi b/icons/mob/clothing/eyes.dmi index 41a265c5ef7..3e5abc48b5e 100644 Binary files a/icons/mob/clothing/eyes.dmi and b/icons/mob/clothing/eyes.dmi differ diff --git a/icons/mob/clothing/feet.dmi b/icons/mob/clothing/feet.dmi index 4ddd93d9ff4..c5f36e8a629 100644 Binary files a/icons/mob/clothing/feet.dmi and b/icons/mob/clothing/feet.dmi differ diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index 6cd1f3c1dc6..2f5b902c7a8 100644 Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi index be8d9f18cbc..9be648c18b8 100644 Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi index 5f29dd61984..d7c44f1ca6d 100644 Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi index ed57bc6b605..e45e27dac14 100644 Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ diff --git a/icons/mob/clothing/under/costume.dmi b/icons/mob/clothing/under/costume.dmi index e761b19d0e0..f3bd8e57cc2 100644 Binary files a/icons/mob/clothing/under/costume.dmi and b/icons/mob/clothing/under/costume.dmi differ diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi index 813f0edb64b..1accfc77e0a 100644 Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi index b4167e069cb..1eac238b4b4 100644 Binary files a/icons/obj/clothing/glasses.dmi and b/icons/obj/clothing/glasses.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index 8e1684beccf..5c67d4a9967 100644 Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 86f52f020f0..ab40f0c978d 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 7131e283e73..50034f2e1cf 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi index 5f5be961272..f01f4c57ab6 100644 Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index e83db7cadf1..abb75c299ea 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/clothing/under/costume.dmi b/icons/obj/clothing/under/costume.dmi index 1449c24dabc..33d0aad418b 100644 Binary files a/icons/obj/clothing/under/costume.dmi and b/icons/obj/clothing/under/costume.dmi differ diff --git a/icons/obj/gang/cell_phone.dmi b/icons/obj/gang/cell_phone.dmi new file mode 100644 index 00000000000..40a5c33cbec Binary files /dev/null and b/icons/obj/gang/cell_phone.dmi differ diff --git a/icons/obj/gang/tags.dmi b/icons/obj/gang/tags.dmi index 29e4b9063c4..61059c47e4a 100644 Binary files a/icons/obj/gang/tags.dmi and b/icons/obj/gang/tags.dmi differ diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm index a4e7cf3af38..81b3ca87783 100644 --- a/interface/stylesheet.dm +++ b/interface/stylesheet.dm @@ -55,6 +55,7 @@ em {font-style: normal; font-weight: bold;} .blueteamradio {color: #0000ff;} .greenteamradio {color: #00ff00;} .yellowteamradio {color: #d1ba22;} +.gangradio {color: #ac2ea1;} .yell { font-weight: bold;} diff --git a/tgstation.dme b/tgstation.dme index 09cbb8e9369..b94c0dc15d9 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1860,10 +1860,12 @@ #include "code\modules\antagonists\fugitive\fugitive_outfits.dm" #include "code\modules\antagonists\fugitive\fugitive_ship.dm" #include "code\modules\antagonists\fugitive\hunter.dm" +#include "code\modules\antagonists\gang\cellphone.dm" #include "code\modules\antagonists\gang\gang.dm" #include "code\modules\antagonists\gang\handler.dm" #include "code\modules\antagonists\gang\induction_package.dm" #include "code\modules\antagonists\gang\outfits.dm" +#include "code\modules\antagonists\gang\themes.dm" #include "code\modules\antagonists\greentext\greentext.dm" #include "code\modules\antagonists\highlander\highlander.dm" #include "code\modules\antagonists\magic_servant\servant.dm" diff --git a/tgui/packages/tgui-panel/chat/constants.js b/tgui/packages/tgui-panel/chat/constants.js index d2e472dc071..145f0cc6724 100644 --- a/tgui/packages/tgui-panel/chat/constants.js +++ b/tgui/packages/tgui-panel/chat/constants.js @@ -58,7 +58,7 @@ export const MESSAGE_TYPES = [ type: MESSAGE_TYPE_RADIO, name: 'Radio', description: 'All departments of radio messages', - selector: '.alert, .minorannounce, .syndradio, .centcomradio, .aiprivradio, .comradio, .secradio, .engradio, .medradio, .sciradio, .suppradio, .servradio, .radio, .deptradio, .binarysay, .newscaster, .resonate', + selector: '.alert, .minorannounce, .syndradio, .centcomradio, .aiprivradio, .comradio, .secradio, .gangradio, .engradio, .medradio, .sciradio, .suppradio, .servradio, .radio, .deptradio, .binarysay, .newscaster, .resonate', }, { type: MESSAGE_TYPE_INFO, diff --git a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss index e459ed35732..2f6d93379f8 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss @@ -369,6 +369,10 @@ em { color: #8f4a4b; } +.gangradio { + color: #ac2ea1; +} + .centcomradio { color: #2681a5; } diff --git a/tgui/packages/tgui-panel/styles/goon/chat-light.scss b/tgui/packages/tgui-panel/styles/goon/chat-light.scss index 48275ca7ed4..d62c85e00c0 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-light.scss @@ -387,6 +387,10 @@ em { color: #6d3f40; } +.gangradio { + color: #ac2ea1; +} + .centcomradio { color: #686868; } diff --git a/tgui/packages/tgui/interfaces/AntagInfoGangmember.tsx b/tgui/packages/tgui/interfaces/AntagInfoGangmember.tsx new file mode 100644 index 00000000000..5b0e09c286c --- /dev/null +++ b/tgui/packages/tgui/interfaces/AntagInfoGangmember.tsx @@ -0,0 +1,136 @@ +import { useBackend } from '../backend'; +import { BlockQuote, Icon, Section, Stack } from '../components'; +import { Window } from '../layouts'; + +type Info = { + antag_name: string; + gang_name: string; + gang_objective: string; + gang_clothes: string[]; +}; + +export const AntagInfoGangmember = (props, context) => { + const { data } = useBackend(context); + const { + gang_name, + antag_name, + } = data; + return ( + + +
+ + + {gang_name} for life! You are a {antag_name}! + + + As a gang member, support your family above all! + Tag turf with a spraycan, wear your family's clothes, + induct new members with induction packages, + and accomplish your family objective. + + + + + + + + + + + + + + + + + +
+
+
+ ); +}; + +const GangClothesPrintout = (props, context) => { + const { data } = useBackend(context); + const { + gang_name, + gang_clothes, + } = data; + return ( + + + + + + + + Wear the following to represent the {gang_name}: + + + +
+ {gang_clothes && gang_clothes.length ? ( + gang_clothes.map(clothes_item => ( + + - {clothes_item} + + )) + ) : ( + "- Anything!" + )} +
+
+ ); +}; + +const GangPhonePrintout = () => { + return ( + + + + + + + + You were given a cell phone with your induction package! + + + + +
+ Use it in hand to activate it, then speak into it to talk with + your other family members. +
+
+
+ ); +}; + + +const GangObjectivePrintout = (props, context) => { + const { data } = useBackend(context); + const { + gang_objective, + } = data; + return ( + + + Your family's goal: + + + {gang_objective + || "No objective set! This is a problem!"} + + + ); +};