Ports Families gamemode to Dynamic roundstart + midround rulesets (#51244)

* stage one

doesn't compile yet

* step 2

added newer changes and goof's balance requests. still doesn't compile

* phase 3

somewhere along the way, wanted code got fucked, and i have to commit to switch branches to debug it better

* documentation, first dyn rulesets

-deprecates a proc nobody needed
-documents a lot of things, hopefully enough of them
-reorganizes a lot of things to allow for admin-spawned families
-adds dynamic rulesets (unfinished, debug settings left in)
-hopefully finally fixes wanted level displays. all code sucks; ui code sucks especially. why can i put an acid level on a screen element? Fuck you
-implements fully functional jewish qabbalah system to replace families gamemode. discover secret names of god + knowledge of universe structure through study of tanach and talmud, use them to secure the station for israel 2
-introduces gay agenda to unsuspecting stationgoers
-remind me to check out gang tag code for mentions of ssticker.mode etc. if one of my later commits doesn't say i did that

* finishes up rulesets

-rulesets work now
-hopefully cleaned up the debug code for them
-minor adjustment to check_wanted_level() proc to ensure wanted stars update appearance correctly post-space cops
-i resisted the urge to modify one of the systems so that it was more "elegant" or whatever because knowing my luck it'd result in another 10 years of failures and tests
-checked out gang tag code; seems fine. perhaps the only part of families code i haven't gotten my mitts on. hopefully it won't break
-you can now print fully functional geneseed organs from the roundstart medlathe for use in self-augmentation
-consumed my soul and replaced it with a pathetic, empty husk
-implemented social security number skimming operation
-removed herobrine

* addressing issues

from the github

* suggestions

cleanin some things up

* more tweaks

goof requested on discord that i ensure 3 families every time, and adding the highlander ruleset flag makes sense because it means the 1-2 families-revs or families-nukies punch is less likely

* adjustments for midround ruleset

-wanted level no longer cares about deaths that happened before the handler's pre_setup_analogue() proc is called
-midround ruleset will not trigger if more people have died during the shift than there were people readied up at roundstart (in addition to the minimum population of 36).
-changes to antagonist code; only nonhumans may roll antagonist. if you have more than 1 hour of time spent playing as a human you are ineligible. something something 13%

* #51315 compatibility

removes useless "high_population_requirement" vars on families rulesets

* moves stuff

team creation should have gone in create_team() not on_gain() since the former gets called directly before the latter

* shuffles some procs

removes unnecessasry blocking_rules list for roundstart families gamemode
This commit is contained in:
tmtmtl30
2020-06-11 14:29:18 -07:00
committed by GitHub
parent 88ec237843
commit a2b60fcbce
13 changed files with 1026 additions and 647 deletions
-2
View File
@@ -488,8 +488,6 @@
var/list/all_antagonists = list()
for(var/datum/team/A in GLOB.antagonist_teams)
if(!A.members)
continue
all_teams |= A
for(var/datum/antagonist/A in GLOB.antagonists)
+7 -7
View File
@@ -4,16 +4,16 @@
icon = 'icons/obj/gang/wanted_160x32.dmi'
icon_state = "wanted_0"
screen_loc = ui_wanted_lvl
///Wanted level, affects the hud icon.
var/level
///Boolean, have the cops arrived? If so, the icon stops changing and remains the same.
var/cops_arrived
/// Wanted level, affects the hud icon. Level 0 is default, and the level 0 icon is blank, so in case of no families gamemode (and thus no wanted level), this HUD element will never appear.
var/level = 0
/// Boolean, have the cops arrived? If so, the icon stops changing and remains the same.
var/cops_arrived = 0
/obj/screen/wanted/New()
return ..()
/obj/screen/wanted/Initialize()
. = ..()
var/datum/game_mode/gang/F = SSticker.mode
level = F.wanted_level
cops_arrived = F.cops_arrived
update_icon()
/obj/screen/wanted/MouseEntered(location,control,params)
+2 -1
View File
@@ -539,11 +539,12 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
if(highlander_executed)
return FALSE
if ((forced || (new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat)))
if((new_rule.acceptable(current_players[CURRENT_LIVING_PLAYERS].len, threat_level) && new_rule.cost <= threat) || forced)
new_rule.trim_candidates()
if (new_rule.ready(forced))
spend_threat(new_rule.cost)
threat_log += "[worldtime2text()]: Forced rule [new_rule.name] spent [new_rule.cost]"
new_rule.pre_execute()
if (new_rule.execute()) // This should never fail since ready() returned 1
if(new_rule.flags & HIGHLANDER_RULESET)
highlander_executed = TRUE
@@ -207,6 +207,72 @@
M.mind.add_antag_datum(newTraitor)
return TRUE
//////////////////////////////////////////////
// //
// FAMILIES //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/midround/families
name = "Family Head Aspirants"
persistent = TRUE
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 = 1
cost = 25
requirements = list(101,101,101,101,101,80,50,30,10,10)
flags = HIGHLANDER_RULESET
blocking_rules = list(/datum/dynamic_ruleset/roundstart/families)
minimum_players = 36
antag_cap = list(6,6,6,6,6,6,6,6,6,6)
/// A reference to the handler that is used to run pre_execute(), execute(), etc..
var/datum/gang_handler/handler
/datum/dynamic_ruleset/midround/families/trim_candidates()
..()
candidates = living_players
for(var/mob/living/player in candidates)
if(issilicon(player))
candidates -= player
continue
if(is_centcom_level(player.z))
candidates -= player
continue
if(player.mind && (player.mind.special_role || player.mind.antag_datums?.len > 0))
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
return ..()
/datum/dynamic_ruleset/midround/families/ready(forced = FALSE)
if (required_candidates > living_players.len)
return FALSE
return ..()
/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
return handler.pre_setup_analogue()
/datum/dynamic_ruleset/midround/families/execute()
return handler.post_setup_analogue(TRUE)
/datum/dynamic_ruleset/midround/families/clean_up()
QDEL_NULL(handler)
..()
/datum/dynamic_ruleset/midround/families/rule_process()
return handler.process_analogue()
/datum/dynamic_ruleset/midround/families/round_result()
return handler.set_round_result_analogue()
//////////////////////////////////////////////
// //
@@ -450,6 +450,48 @@
SSticker.mode_result = "loss - rev heads killed"
SSticker.news_report = REVS_LOSE
//////////////////////////////////////////////
// //
// FAMILIES //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/families
name = "Families"
persistent = TRUE
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)
flags = HIGHLANDER_RULESET
minimum_players = 36
antag_cap = list(6,6,6,6,6,6,6,6,6,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()
..()
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)
return handler.pre_setup_analogue()
/datum/dynamic_ruleset/roundstart/families/execute()
return handler.post_setup_analogue(TRUE)
/datum/dynamic_ruleset/roundstart/families/clean_up()
QDEL_NULL(handler)
..()
/datum/dynamic_ruleset/roundstart/families/rule_process()
return handler.process_analogue()
/datum/dynamic_ruleset/roundstart/families/round_result()
return handler.set_round_result_analogue()
// Admin only rulesets. The threat requirement is 101 so it is not possible to roll them.
//////////////////////////////////////////////
+19 -474
View File
@@ -1,20 +1,3 @@
#define LOWPOP_FAMILIES_COUNT 50
#define TWO_STARS_HIGHPOP 11
#define THREE_STARS_HIGHPOP 16
#define FOUR_STARS_HIGHPOP 21
#define FIVE_STARS_HIGHPOP 31
#define TWO_STARS_LOW 6
#define THREE_STARS_LOW 9
#define FOUR_STARS_LOW 12
#define FIVE_STARS_LOW 15
#define CREW_SIZE_MIN 4
#define CREW_SIZE_MAX 8
GLOBAL_VAR_INIT(deaths_during_shift, 0)
/datum/game_mode/gang
name = "Families"
config_tag = "families"
@@ -28,478 +11,40 @@ GLOBAL_VAR_INIT(deaths_during_shift, 0)
reroll_friendly = FALSE
restricted_jobs = list("Cyborg", "AI", "Prisoner","Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel")//N O
protected_jobs = list()
var/check_counter = 0
var/endtime = null
var/start_time = null
var/fuckingdone = FALSE
var/time_to_end = 60 MINUTES
var/gangs_to_generate = 3
var/list/gangs_to_use
var/list/datum/mind/gangbangers = list()
var/list/datum/mind/pigs = list()
var/list/datum/mind/undercover_cops = list()
var/list/gangs = list()
var/gangs_still_alive = 0
var/sent_announcement = FALSE
var/list/gang_locations = list()
var/cops_arrived = FALSE
var/gang_balance_cap = 5
var/wanted_level = 0
/// A reference to the handler that is used to run pre_setup(), post_setup(), etc..
var/datum/gang_handler/handler
/datum/game_mode/gang/warriors
name = "Warriors"
config_tag = "warriors"
announce_text = "Can you survive this onslaught?"
gangs_to_generate = 11
gang_balance_cap = 3
/datum/game_mode/gang/warriors/pre_setup()
gangs_to_use = subtypesof(/datum/antagonist/gang)
gangs_to_generate = gangs_to_use.len
. = ..()
handler = new /datum/gang_handler(antag_candidates,restricted_jobs)
var/list/datum/antagonist/gang/gangs_to_generate = subtypesof(/datum/antagonist/gang)
handler.gangs_to_generate = gangs_to_generate.len
handler.gang_balance_cap = 3
return handler.pre_setup_analogue()
/datum/game_mode/gang/pre_setup()
gangs_to_use = subtypesof(/datum/antagonist/gang)
for(var/j = 0, j < gangs_to_generate, j++)
if (!antag_candidates.len)
break
var/datum/mind/gangbanger = antag_pick(antag_candidates)
gangbangers += gangbanger
gangbanger.restricted_roles = restricted_jobs
log_game("[key_name(gangbanger)] has been selected as a starting gangster!")
antag_candidates.Remove(gangbanger)
for(var/j = 0, j < gangs_to_generate, j++)
if(!antag_candidates.len)
break
var/datum/mind/one_eight_seven_on_an_undercover_cop = antag_pick(antag_candidates)
pigs += one_eight_seven_on_an_undercover_cop
undercover_cops += one_eight_seven_on_an_undercover_cop
one_eight_seven_on_an_undercover_cop.restricted_roles = restricted_jobs
log_game("[key_name(one_eight_seven_on_an_undercover_cop)] has been selected as a starting undercover cop!")
antag_candidates.Remove(one_eight_seven_on_an_undercover_cop)
endtime = world.time + time_to_end
start_time = world.time
return TRUE
handler = new /datum/gang_handler(antag_candidates,restricted_jobs)
return handler.pre_setup_analogue()
/datum/game_mode/gang/Destroy()
QDEL_NULL(handler)
return ..()
/datum/game_mode/gang/post_setup()
var/replacement_gangsters = 0
var/replacement_cops = 0
for(var/datum/mind/gangbanger in gangbangers)
if(!ishuman(gangbanger.current))
gangbangers.Remove(gangbanger)
log_game("[gangbanger] was not a human, and thus has lost their gangster role.")
replacement_gangsters++
if(replacement_gangsters)
for(var/j = 0, j < replacement_gangsters, j++)
if(!antag_candidates.len)
log_game("Unable to find more replacement gangsters. Not all of the gangs will spawn.")
break
var/datum/mind/gangbanger = antag_pick(antag_candidates)
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)
pigs.Remove(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 gangs will spawn.")
break
var/datum/mind/undercover_cop = antag_pick(antag_candidates)
undercover_cops += undercover_cop
pigs += undercover_cop
log_game("[key_name(undercover_cop)] has been selected as a replacement undercover cop!")
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)
for(var/datum/mind/gangbanger in gangbangers)
var/gang_to_use = pick_n_take(gangs_to_use)
var/datum/antagonist/gang/new_gangster = new gang_to_use()
var/datum/team/gang/ballas = new /datum/team/gang()
new_gangster.my_gang = ballas
new_gangster.starter_gangster = TRUE
gangs += ballas
ballas.add_member(gangbanger)
ballas.name = new_gangster.gang_name
ballas.acceptable_clothes = new_gangster.acceptable_clothes.Copy()
ballas.free_clothes = new_gangster.free_clothes.Copy()
ballas.my_gang_datum = new_gangster
for(var/C in ballas.free_clothes)
var/obj/O = new C(gangbanger.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 = gangbanger.current
var/equipped = H.equip_in_one_of_slots(O, slots)
if(!equipped)
to_chat(gangbanger.current, "Unfortunately, you could not bring your [O] to this shift. You will need to find one.")
qdel(O)
gangbanger.add_antag_datum(new_gangster)
gangbanger.current.playsound_local(gangbanger.current, 'sound/ambience/antag/thatshowfamiliesworks.ogg', 100, FALSE, pressure_affected = FALSE)
to_chat(gangbanger.current, "<B>As you're the first gangster, your uniform and spraycan are in your inventory!</B>")
addtimer(CALLBACK(src, .proc/announce_gang_locations), 5 MINUTES)
addtimer(CALLBACK(src, .proc/five_minute_warning), time_to_end - 5 MINUTES)
SSshuttle.registerHostileEnvironment(src)
handler.post_setup_analogue(FALSE)
gamemode_ready = TRUE
..()
/datum/game_mode/gang/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 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 an hour. \n Play music, not gunshots, I say. Peace out!", "Radio Los Spess", 'sound/voice/beepsky/radio.ogg')
sent_announcement = TRUE
/datum/game_mode/gang/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')
/datum/game_mode/gang/set_round_result()
var/alive_gangsters = 0
var/alive_cops = 0
for(var/G in gangbangers)
var/datum/mind/gangbanger = G
if(!ishuman(gangbanger.current))
continue
var/mob/living/carbon/human/H = gangbanger.current
if(H.stat)
continue
alive_gangsters++
for(var/B in pigs)
var/datum/mind/bacon = B
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
return ..()
/datum/game_mode/gang/process()
check_wanted_level()
check_counter++
if(check_counter >= 5)
if (world.time > endtime && !fuckingdone)
fuckingdone = TRUE
send_in_the_fuzz()
check_counter = 0
check_tagged_turfs()
check_gang_clothes()
check_rollin_with_crews()
///Checks if our wanted level has changed. Only actually does something post the initial announcement and until the cops are here. After that its locked.
/datum/game_mode/gang/proc/check_wanted_level()
if(!sent_announcement || cops_arrived)
return
var/new_wanted_level
if(GLOB.joined_player_list.len > LOWPOP_FAMILIES_COUNT)
switch(GLOB.deaths_during_shift)
if(0 to TWO_STARS_HIGHPOP-1)
new_wanted_level = 1
if(TWO_STARS_HIGHPOP to THREE_STARS_HIGHPOP-1)
new_wanted_level = 2
if(THREE_STARS_HIGHPOP to FOUR_STARS_HIGHPOP-1)
new_wanted_level = 3
if(FOUR_STARS_HIGHPOP to FIVE_STARS_HIGHPOP-1)
new_wanted_level = 4
if(FIVE_STARS_HIGHPOP to INFINITY)
new_wanted_level = 5
else
switch(GLOB.deaths_during_shift)
if(0 to TWO_STARS_LOW-1)
new_wanted_level = 1
if(TWO_STARS_LOW to THREE_STARS_LOW-1)
new_wanted_level = 2
if(THREE_STARS_LOW to FOUR_STARS_LOW-1)
new_wanted_level = 3
if(FOUR_STARS_LOW to FIVE_STARS_LOW-1)
new_wanted_level = 4
if(FIVE_STARS_LOW to INFINITY)
new_wanted_level = 5
update_wanted_level(new_wanted_level)
///Updates the icon states for everyone and sends outs announcements regarding the police.
/datum/game_mode/gang/proc/update_wanted_level(newlevel)
if(newlevel > wanted_level)
on_gain_wanted_level(newlevel)
else if (newlevel < wanted_level)
on_lower_wanted_level(newlevel)
wanted_level = newlevel
for(var/i in GLOB.player_list)
var/mob/M = i
if(!M.hud_used?.wanted_lvl)
continue
var/datum/hud/H = M.hud_used
H.wanted_lvl.level = newlevel
H.wanted_lvl.cops_arrived = cops_arrived
H.wanted_lvl.update_icon()
/datum/game_mode/gang/proc/on_gain_wanted_level(newlevel)
var/announcement_message
switch(newlevel)
if(2)
announcement_message = "Small amount of police vehicles have been spotted en route towards [station_name()]. They will arrive at the 50 minute mark."
endtime = start_time + 50 MINUTES
if(3)
announcement_message = "A large detachment police vehicles have been spotted en route towards [station_name()]. They will arrive at the 40 minute mark."
endtime = start_time + 40 MINUTES
if(4)
announcement_message = "A detachment of top-trained agents has been spotted on their way to [station_name()]. They will arrive at the 35 minute mark."
endtime = start_time + 35 MINUTES
if(5)
announcement_message = "The fleet enroute to [station_name()] now consists of national guard personnel. They will arrive at the 30 minute mark."
endtime = start_time + 30 MINUTES
priority_announce(announcement_message, "Station Spaceship Detection Systems")
/datum/game_mode/gang/proc/on_lower_wanted_level(newlevel)
var/announcement_message
switch(newlevel)
if(1)
announcement_message = "There are now only a few police vehicle headed towards [station_name()]. They will arrive at the 60 minute mark."
endtime = start_time + 60 MINUTES
if(2)
announcement_message = "There seem to be fewer police vehicles headed towards [station_name()]. They will arrive at the 50 minute mark."
endtime = start_time + 50 MINUTES
if(3)
announcement_message = "There are no longer top-trained agents in the fleet headed towards [station_name()]. They will arrive at the 40 minute mark."
endtime = start_time + 40 MINUTES
if(4)
announcement_message = "The convoy enroute to [station_name()] seems to no longer consist of national guard personnel. They will arrive at the 35 minute mark."
endtime = start_time + 35 MINUTES
priority_announce(announcement_message, "Station Spaceship Detection Systems")
/datum/game_mode/gang/proc/send_in_the_fuzz()
var/team_size
var/cops_to_send
var/announcement_message = "PUNK ASS BALLA BITCH"
var/announcer = "Spinward Stellar Coalition"
if(GLOB.joined_player_list.len > LOWPOP_FAMILIES_COUNT)
switch(wanted_level)
if(1)
team_size = 8
cops_to_send = /datum/antagonist/ert/families/beatcop
announcement_message = "Hello, crewmembers of [station_name()]! We've received a few calls about some potential violent gang activity on board your station, so we're sending some beat cops to check things out. Nothing extreme, just a courtesy call. However, while they check things out for about 10 minutes, we're going to have to ask that you keep your escape shuttle parked.\n\nHave a pleasant day!"
announcer = "Spinward Stellar Coalition Police Department"
if(2)
team_size = 9
cops_to_send = /datum/antagonist/ert/families/beatcop/armored
announcement_message = "Crewmembers of [station_name()]. We have received confirmed reports of violent gang activity from your station. We are dispatching some armed officers to help keep the peace and investigate matters. Do not get in their way, and comply with any and all requests from them. We have blockaded the local warp gate, and your shuttle cannot depart for another 10 minutes.\n\nHave a secure day."
announcer = "Spinward Stellar Coalition Police Department"
if(3)
team_size = 10
cops_to_send = /datum/antagonist/ert/families/beatcop/swat
announcement_message = "Crewmembers of [station_name()]. We have received confirmed reports of extreme gang activity from your station resulting in heavy civilian casualties. The Spinward Stellar Coalition does not tolerate abuse towards our citizens, and we will be responding in force to keep the peace and reduce civilian casualties. We have your station surrounded, and all gangsters must drop their weapons and surrender peacefully.\n\nHave a secure day."
announcer = "Spinward Stellar Coalition Police Department"
if(4)
team_size = 11
cops_to_send = /datum/antagonist/ert/families/beatcop/fbi
announcement_message = "We are dispatching our top agents to [station_name()] at the request of the Spinward Stellar Coalition government due to an extreme terrorist level threat against this Nanotrasen owned station. All gangsters must surrender IMMEDIATELY. Failure to comply can and will result in death. We have blockaded your warp gates and will not allow any escape until the situation is resolved within our standard response time of 10 minutes.\n\nSurrender now or face the consequences of your actions."
announcer = "Federal Bureau of Investigation"
if(5)
team_size = 12
cops_to_send = /datum/antagonist/ert/families/beatcop/military
announcement_message = "Due to an insane level of civilian casualties aboard [station_name()], we have dispatched the National Guard to curb any and all gang activity on board the station. We have heavy cruisers watching the shuttle. Attempt to leave before we allow you to, and we will obliterate your station and your escape shuttle.\n\nYou brought this on yourselves by murdering so many civilians."
announcer = "Spinward Stellar Coalition National Guard"
else
switch(wanted_level)
if(1)
team_size = 5
cops_to_send = /datum/antagonist/ert/families/beatcop
announcement_message = "Hello, crewmembers of [station_name()]! We've received a few calls about some potential violent gang activity on board your station, so we're sending some beat cops to check things out. Nothing extreme, just a courtesy call. However, while they check things out for about 10 minutes, we're going to have to ask that you keep your escape shuttle parked.\n\nHave a pleasant day!"
announcer = "Spinward Stellar Coalition Police Department"
if(2)
team_size = 6
cops_to_send = /datum/antagonist/ert/families/beatcop/armored
announcement_message = "Crewmembers of [station_name()]. We have received confirmed reports of violent gang activity from your station. We are dispatching some armed officers to help keep the peace and investigate matters. Do not get in their way, and comply with any and all requests from them. We have blockaded the local warp gate, and your shuttle cannot depart for another 10 minutes.\n\nHave a secure day."
announcer = "Spinward Stellar Coalition Police Department"
if(3)
team_size = 7
cops_to_send = /datum/antagonist/ert/families/beatcop/swat
announcement_message = "Crewmembers of [station_name()]. We have received confirmed reports of extreme gang activity from your station resulting in heavy civilian casualties. The Spinward Stellar Coalition does not tolerate abuse towards our citizens, and we will be responding in force to keep the peace and reduce civilian casualties. We have your station surrounded, and all gangsters must drop their weapons and surrender peacefully.\n\nHave a secure day."
announcer = "Spinward Stellar Coalition Police Department"
if(4)
team_size = 8
cops_to_send = /datum/antagonist/ert/families/beatcop/fbi
announcement_message = "We are dispatching our top agents to [station_name()] at the request of the Spinward Stellar Coalition government due to an extreme terrorist level threat against this Nanotrasen owned station. All gangsters must surrender IMMEDIATELY. Failure to comply can and will result in death. We have blockaded your warp gates and will not allow any escape until the situation is resolved within our standard response time of 10 minutes.\n\nSurrender now or face the consequences of your actions."
announcer = "Federal Bureau of Investigation"
if(5)
team_size = 10
cops_to_send = /datum/antagonist/ert/families/beatcop/military
announcement_message = "Due to an insane level of civilian casualties aboard [station_name()], we have dispatched the National Guard to curb any and all gang activity on board the station. We have heavy cruisers watching the shuttle. Attempt to leave before we allow you to, and we will obliterate your station and your escape shuttle.\n\nYou brought this on yourselves by murdering so many civilians."
announcer = "Spinward Stellar Coalition National Guard"
priority_announce(announcement_message, announcer, 'sound/effects/families_police.ogg')
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to help clean up crime on this station?", "deathsquad", null)
if(candidates.len)
//Pick the (un)lucky players
var/numagents = min(team_size,candidates.len)
var/list/spawnpoints = GLOB.emergencyresponseteamspawn
var/index = 0
while(numagents && candidates.len)
var/spawnloc = spawnpoints[index+1]
//loop through spawnpoints one at a time
index = (index + 1) % spawnpoints.len
var/mob/dead/observer/chosen_candidate = pick(candidates)
candidates -= chosen_candidate
if(!chosen_candidate.key)
continue
//Spawn the body
var/mob/living/carbon/human/cop = new(spawnloc)
chosen_candidate.client.prefs.copy_to(cop)
cop.key = chosen_candidate.key
//Give antag datum
var/datum/antagonist/ert/ert_antag = new cops_to_send
cop.mind.add_antag_datum(ert_antag)
cop.mind.assigned_role = ert_antag.name
SSjob.SendToLateJoin(cop)
//Logging and cleanup
log_game("[key_name(cop)] has been selected as an [ert_antag.name]")
numagents--
cops_arrived = TRUE
update_wanted_level() //Will make sure our icon updates properly
addtimer(CALLBACK(src, .proc/end_hostile_sit), 10 MINUTES)
return TRUE
/datum/game_mode/gang/proc/end_hostile_sit()
SSshuttle.clearHostileEnvironment(src)
/datum/game_mode/gang/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
/datum/game_mode/gang/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
/datum/game_mode/gang/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)
handler.process_analogue()
/datum/game_mode/gang/set_round_result()
return handler.set_round_result_analogue()
/datum/game_mode/gang/generate_report()
return "Potential violent criminal activity has been detected on board your station, and we believe the Spinward Stellar Coalition may be conducting an audit of us. Keep an eye out for tagging of turf, color coordination, and suspicious people asking you to say things a little closer to their chest."
/datum/game_mode/gang/send_intercept(report = 0)
return
/datum/game_mode/gang/special_report()
var/list/report = list()
var/highest_point_value = 0
var/highest_gang = "Leet Like Jeff K"
report += "<span class='header'>The families in the round were:</span>"
var/objective_failures = TRUE
for(var/datum/team/gang/GG in gangs)
if(GG.my_gang_datum.check_gang_objective())
objective_failures = FALSE
break
for(var/datum/team/gang/G in gangs)
report += "<span class='header'>[G.name]:</span>"
if(G.members.len)
report += "[G.my_gang_datum.roundend_category] were:"
report += printplayerlist(G.members)
report += "<span class='header'>Points: [G.points]</span>"
report += "<span class='header'>Objective: [G.my_gang_datum.gang_objective]</span>"
if(G.my_gang_datum.check_gang_objective())
report += "<span class='greentext'>The family completed their objective!</span>"
else
report += "<span class='redtext'>The family failed their objective!</span>"
else
report += "<span class='redtext'>The family was wiped out!</span>"
if(!objective_failures)
if(G.points >= highest_point_value && G.members.len && G.my_gang_datum.check_gang_objective())
highest_point_value = G.points
highest_gang = G.name
else
if(G.points >= highest_point_value && G.members.len)
highest_point_value = G.points
highest_gang = G.name
var/alive_gangsters = 0
var/alive_cops = 0
for(var/datum/mind/gangbanger in gangbangers)
if(gangbanger.current)
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 pigs)
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 += "<span class='header greentext'>[highest_gang] won the round by completing their objective and having the most points!</span>"
else
report += "<span class='header greentext'>[highest_gang] won the round by having the most points!</span>"
else if(alive_gangsters == alive_cops)
report += "<span class='header redtext'>Legend has it the police and the families are still duking it out to this day!</span>"
else
report += "<span class='header greentext'>The police put the boots to the families, medium style!</span>"
return "<div class='panel redborder'>[report.Join("<br>")]</div>"
+614
View File
@@ -0,0 +1,614 @@
#define LOWPOP_FAMILIES_COUNT 50
#define TWO_STARS_HIGHPOP 11
#define THREE_STARS_HIGHPOP 16
#define FOUR_STARS_HIGHPOP 21
#define FIVE_STARS_HIGHPOP 31
#define TWO_STARS_LOW 6
#define THREE_STARS_LOW 9
#define FOUR_STARS_LOW 12
#define FIVE_STARS_LOW 15
#define CREW_SIZE_MIN 4
#define CREW_SIZE_MAX 8
GLOBAL_VAR_INIT(deaths_during_shift, 0)
/**
* # Families gamemode / dynamic ruleset handler
*
* A special datum used by the families gamemode and dynamic rulesets to centralize code. "Family" and "gang" used interchangeably in code.
*
* This datum centralizes code used for the families gamemode / dynamic rulesets. Families incorporates a significant
* amount of unique processing; without this datum, that could would be duplicated. To ensure the maintainability
* of the families gamemode / rulesets, the code was moved to this datum. The gamemode / rulesets instance this
* datum, pass it lists (lists are passed by reference; removing candidates here removes candidates in the gamemode),
* and call its procs. Additionally, the families antagonist datum and families induction package also
* contain vars that reference this datum, allowing for new families / family members to add themselves
* to this datum's lists thereof (primarily used for point calculation). Despite this, the basic team mechanics
* themselves should function regardless of this datum's instantiation, should a player have the gang or cop
* antagonist datum added to them through methods external to the families gamemode / rulesets.
*
*/
/datum/gang_handler
/// A counter used to minimize the overhead of computationally intensive, periodic family point gain checks. Used and set internally.
var/check_counter = 0
/// The time, in deciseconds, that the datum's pre_setup() occured at. Used in end_time. Used and set internally.
var/start_time = null
/// The time, in deciseconds, that the space cops will arrive at. Calculated based on wanted level and start_time. Used and set internally.
var/end_time = null
/// Whether the gamemode-announcing announcement has been sent. Used and set internally.
var/sent_announcement = FALSE
/// Whether the "5 minute warning" announcement has been sent. Used and set internally.
var/sent_second_announcement = FALSE
/// Whether the space cops have arrived. Set internally; used internally, and for updating the wanted HUD.
var/cops_arrived = FALSE
/// The current wanted level. Set internally; used internally, and for updating the wanted HUD.
var/wanted_level
/// List of all /datum/team/gang. Used internally; added to externally by /datum/antagonist/gang when it generates a new /datum/team/gang.
var/list/gangs = list()
/// List of all family member minds. Used internally; added to internally, and externally by /obj/item/gang_induction_package when used to induct a new family member.
var/list/gangbangers = list()
/// List of all undercover cop minds. Used and set internally.
var/list/undercover_cops = list()
/// The number of families (and 1:1 corresponding undercover cops) that should be generated. Can be set externally; used internally.
var/gangs_to_generate = 3
/// The number of family members more that a family may have over other active families. Can be set externally; used internally.
var/gang_balance_cap = 5
/// Whether the handler corresponds to a ruleset that does not trigger at round start. Should be set externally only if applicable; used internally.
var/midround_ruleset = FALSE
/// Keeps track of the amount of deaths since the calling of pre_setup_analogue() if this is a midround handler. Used to prevent a high wanted level due to a large amount of deaths during the shift prior to the activation of this handler / the midround ruleset.
var/deaths_during_shift_at_beginning = 0
/// List of all eligible starting family members / undercover cops. Set externally (passed by reference) by gamemode / ruleset; used internally. Note that dynamic uses a list of mobs to handle candidates while game_modes use lists of minds! Don't be fooled!
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
/**
* Sets antag_candidates and restricted_jobs.
*
* Sets the antag_candidates and restricted_jobs lists to the equivalent
* lists of its instantiating game_mode / dynamic_ruleset datum. As lists
* are passed by reference, the variable set in this datum and the passed list
* list used to set it are literally the same; changes to one affect the other.
* Like all New() procs, called when the datum is first instantiated.
* There's an annoying caveat here, though -- dynamic rulesets don't have
* lists of minds for candidates, they have lists of mobs. Ghost mobs, before
* the round has started. But we still want to preserve the structure of the candidates
* list by not duplicating it and making sure to remove the candidates as we use them.
* So there's a little bit of boilerplate throughout to preserve the sanctity of this reference.
* Arguments:
* * given_candidates - The antag_candidates list or equivalent of the datum instantiating this one.
* * revised_restricted - The restricted_jobs list or equivalent of the datum instantiating this one.
*/
/datum/gang_handler/New(list/given_candidates, list/revised_restricted)
antag_candidates = given_candidates
restricted_jobs = revised_restricted
/**
* pre_setup() or pre_execute() equivalent.
*
* This proc is always called externally, by the instantiating game_mode / dynamic_ruleset.
* This is done during the pre_setup() or pre_execute() phase, after first instantiation
* and the modification of gangs_to_generate, gang_balance_cap, and midround_ruleset.
* It is intended to take the place of the code that would normally occupy the pre_setup()
* or pre_execute() proc, were the code localized to the game_mode or dynamic_ruleset datum respectively
* as opposed to this handler. As such, it picks players to be chosen for starting familiy members
* or undercover cops prior to assignment to jobs. Sets start_time, default end_time,
* and the current value of deaths_during_shift, to ensure the wanted level only cares about
* the deaths since this proc has been called.
* Takes no arguments.
*/
/datum/gang_handler/proc/pre_setup_analogue()
for(var/j = 0, j < gangs_to_generate, j++)
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
var/datum/mind/gangbanger
if(istype(taken, /mob))
var/mob/T = taken
gangbanger = T.mind
else
gangbanger = taken
gangbangers += gangbanger
gangbanger.restricted_roles = restricted_jobs
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
return TRUE
/**
* post_setup() or execute() equivalent.
*
* This proc is always called externally, by the instantiating game_mode / dynamic_ruleset.
* This is done during the post_setup() or execute() phase, after the pre_setup() / pre_execute() phase.
* It is intended to take the place of the code that would normally occupy the pre_setup()
* or pre_execute() proc. As such, it ensures that all prospective starting family members /
* undercover cops are eligible, and picks replacements if there were ineligible cops / family members.
* It then assigns gear to the finalized family members and undercover cops, adding them to its lists,
* and sets the families announcement proc (that does the announcing) to trigger in five minutes.
* Additionally, if given the argument TRUE, it will return FALSE if there are no eligible starting family members.
* This is only to be done if the instantiating datum is a dynamic_ruleset, as these require returns
* while a game_mode is not expected to return early during this phase.
* Arguments:
* * return_if_no_gangs - Boolean that determines if the proc should return FALSE should it find no eligible family members. Should be used for dynamic only.
*/
/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)
GLOB.pre_setup_antags -= gangbanger
gangbangers.Remove(gangbanger)
log_game("[gangbanger] was not a human, and thus has lost their gangster role.")
replacement_gangsters++
if(replacement_gangsters)
for(var/j = 0, j < replacement_gangsters, j++)
if(!antag_candidates.len)
log_game("Unable to find more replacement gangsters. Not all of the gangs will spawn.")
break
var/taken = pick_n_take(antag_candidates)
var/datum/mind/gangbanger
if(istype(taken, /mob)) // boilerplate needed because antag_candidates might not contain minds
var/mob/T = taken
gangbanger = T.mind
else
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 = subtypesof(/datum/antagonist/gang)
for(var/datum/mind/gangbanger in gangbangers)
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)
// 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
/**
* process() or rule_process() equivalent.
*
* This proc is always called externally, by the instantiating game_mode / dynamic_ruleset.
* This is done during the process() or rule_process() phase, after post_setup() or
* execute() and at regular intervals thereafter. process() and rule_process() are optional
* for a game_mode / dynamic_ruleset, but are important for this gamemode. It is of central
* importance to the gamemode's flow, calculating wanted level updates, family point gain,
* and announcing + executing the arrival of the space cops, achieved through calling internal procs.
* 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.
*
* This proc is always called externally, by the instantiating game_mode / dynamic_ruleset.
* This is done by the set_round_result() or round_result() procs, at roundend.
* Sets the ticker subsystem to the correct result based off of the relative populations
* of space cops and family members.
* 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
/// 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 [midround_ruleset ? "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 an hour. \n Play music, not gunshots, I say. Peace out!", "Radio Los Spess", '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()
if(cops_arrived)
update_wanted_level(wanted_level) // at this point, we still want to update people's star huds, even though they're mostly locked, because not everyone is around for the last update before the rest of this proc gets shut off forever, and that's when the wanted bar switches from gold stars to red / blue to signify the arrival of the space cops
return
if(!sent_announcement)
return
var/new_wanted_level
if(GLOB.joined_player_list.len > LOWPOP_FAMILIES_COUNT)
switch(GLOB.deaths_during_shift - deaths_during_shift_at_beginning) // if this is a midround ruleset, we only care about the deaths since the families were activated, not since shiftstart
if(0 to TWO_STARS_HIGHPOP-1)
new_wanted_level = 1
if(TWO_STARS_HIGHPOP to THREE_STARS_HIGHPOP-1)
new_wanted_level = 2
if(THREE_STARS_HIGHPOP to FOUR_STARS_HIGHPOP-1)
new_wanted_level = 3
if(FOUR_STARS_HIGHPOP to FIVE_STARS_HIGHPOP-1)
new_wanted_level = 4
if(FIVE_STARS_HIGHPOP to INFINITY)
new_wanted_level = 5
else
switch(GLOB.deaths_during_shift - deaths_during_shift_at_beginning)
if(0 to TWO_STARS_LOW-1)
new_wanted_level = 1
if(TWO_STARS_LOW to THREE_STARS_LOW-1)
new_wanted_level = 2
if(THREE_STARS_LOW to FOUR_STARS_LOW-1)
new_wanted_level = 3
if(FOUR_STARS_LOW to FIVE_STARS_LOW-1)
new_wanted_level = 4
if(FIVE_STARS_LOW to INFINITY)
new_wanted_level = 5
update_wanted_level(new_wanted_level)
/// Internal. Updates the icon states for everyone, and calls procs that send out announcements / change the end_time if the wanted level has changed.
/datum/gang_handler/proc/update_wanted_level(newlevel)
if(newlevel > wanted_level)
on_gain_wanted_level(newlevel)
else if (newlevel < wanted_level)
on_lower_wanted_level(newlevel)
wanted_level = newlevel
for(var/i in GLOB.player_list)
var/mob/M = i
if(!M.hud_used?.wanted_lvl)
continue
var/datum/hud/H = M.hud_used
H.wanted_lvl.level = newlevel
H.wanted_lvl.cops_arrived = cops_arrived
H.wanted_lvl.update_icon()
/// Internal. Updates the end_time and sends out an announcement if the wanted level has increased. Called by update_wanted_level().
/datum/gang_handler/proc/on_gain_wanted_level(newlevel)
var/announcement_message
switch(newlevel)
if(2)
if(!sent_second_announcement) // when you hear that they're "arriving in 5 minutes," that's a goddamn guarantee
end_time = start_time + ((50 MINUTES) / (midround_ruleset ? 2 : 1))
announcement_message = "Small amount of police vehicles have been spotted en route towards [station_name()]."
if(3)
if(!sent_second_announcement)
end_time = start_time + ((40 MINUTES) / (midround_ruleset ? 2 : 1))
announcement_message = "A large detachment police vehicles have been spotted en route towards [station_name()]."
if(4)
if(!sent_second_announcement)
end_time = start_time + ((35 MINUTES) / (midround_ruleset ? 2 : 1))
announcement_message = "A detachment of top-trained agents has been spotted on their way to [station_name()]."
if(5)
if(!sent_second_announcement)
end_time = start_time + ((30 MINUTES) / (midround_ruleset ? 2 : 1))
announcement_message = "The fleet enroute to [station_name()] now consists of national guard personnel."
if(!midround_ruleset) // stops midround rulesets from announcing janky ass times
announcement_message += " They will arrive at the [(end_time - start_time) / (1 MINUTES)] minute mark."
if(newlevel == 1) // specific exception to stop the announcement from triggering right after the families themselves are announced because aesthetics
return
priority_announce(announcement_message, "Station Spaceship Detection Systems")
/// Internal. Updates the end_time and sends out an announcement if the wanted level has decreased. Called by update_wanted_level().
/datum/gang_handler/proc/on_lower_wanted_level(newlevel)
var/announcement_message
switch(newlevel)
if(1)
if(!sent_second_announcement)
end_time = start_time + ((60 MINUTES) / (midround_ruleset ? 2 : 1))
announcement_message = "There are now only a few police vehicle headed towards [station_name()]."
if(2)
if(!sent_second_announcement)
end_time = start_time + ((50 MINUTES) / (midround_ruleset ? 2 : 1))
announcement_message = "There seem to be fewer police vehicles headed towards [station_name()]."
if(3)
if(!sent_second_announcement)
end_time = start_time + ((40 MINUTES) / (midround_ruleset ? 2 : 1))
announcement_message = "There are no longer top-trained agents in the fleet headed towards [station_name()]."
if(4)
if(!sent_second_announcement)
end_time = start_time + ((35 MINUTES) / (midround_ruleset ? 2 : 1))
announcement_message = "The convoy enroute to [station_name()] seems to no longer consist of national guard personnel."
if(!midround_ruleset)
announcement_message += " They will arrive at the [(end_time - start_time) / (1 MINUTES)] minute mark."
priority_announce(announcement_message, "Station Spaceship Detection Systems")
/// Internal. Polls ghosts and sends in a team of space cops according to the wanted level, accompanied by an announcement. Will let the shuttle leave 10 minutes after sending. Freezes the wanted level.
/datum/gang_handler/proc/send_in_the_fuzz()
var/team_size
var/cops_to_send
var/announcement_message = "PUNK ASS BALLA BITCH"
var/announcer = "Spinward Stellar Coalition"
if(GLOB.joined_player_list.len > LOWPOP_FAMILIES_COUNT)
switch(wanted_level)
if(1)
team_size = 8
cops_to_send = /datum/antagonist/ert/families/beatcop
announcement_message = "Hello, crewmembers of [station_name()]! We've received a few calls about some potential violent gang activity on board your station, so we're sending some beat cops to check things out. Nothing extreme, just a courtesy call. However, while they check things out for about 10 minutes, we're going to have to ask that you keep your escape shuttle parked.\n\nHave a pleasant day!"
announcer = "Spinward Stellar Coalition Police Department"
if(2)
team_size = 9
cops_to_send = /datum/antagonist/ert/families/beatcop/armored
announcement_message = "Crewmembers of [station_name()]. We have received confirmed reports of violent gang activity from your station. We are dispatching some armed officers to help keep the peace and investigate matters. Do not get in their way, and comply with any and all requests from them. We have blockaded the local warp gate, and your shuttle cannot depart for another 10 minutes.\n\nHave a secure day."
announcer = "Spinward Stellar Coalition Police Department"
if(3)
team_size = 10
cops_to_send = /datum/antagonist/ert/families/beatcop/swat
announcement_message = "Crewmembers of [station_name()]. We have received confirmed reports of extreme gang activity from your station resulting in heavy civilian casualties. The Spinward Stellar Coalition does not tolerate abuse towards our citizens, and we will be responding in force to keep the peace and reduce civilian casualties. We have your station surrounded, and all gangsters must drop their weapons and surrender peacefully.\n\nHave a secure day."
announcer = "Spinward Stellar Coalition Police Department"
if(4)
team_size = 11
cops_to_send = /datum/antagonist/ert/families/beatcop/fbi
announcement_message = "We are dispatching our top agents to [station_name()] at the request of the Spinward Stellar Coalition government due to an extreme terrorist level threat against this Nanotrasen owned station. All gangsters must surrender IMMEDIATELY. Failure to comply can and will result in death. We have blockaded your warp gates and will not allow any escape until the situation is resolved within our standard response time of 10 minutes.\n\nSurrender now or face the consequences of your actions."
announcer = "Federal Bureau of Investigation"
if(5)
team_size = 12
cops_to_send = /datum/antagonist/ert/families/beatcop/military
announcement_message = "Due to an insane level of civilian casualties aboard [station_name()], we have dispatched the National Guard to curb any and all gang activity on board the station. We have heavy cruisers watching the shuttle. Attempt to leave before we allow you to, and we will obliterate your station and your escape shuttle.\n\nYou brought this on yourselves by murdering so many civilians."
announcer = "Spinward Stellar Coalition National Guard"
else
switch(wanted_level)
if(1)
team_size = 5
cops_to_send = /datum/antagonist/ert/families/beatcop
announcement_message = "Hello, crewmembers of [station_name()]! We've received a few calls about some potential violent gang activity on board your station, so we're sending some beat cops to check things out. Nothing extreme, just a courtesy call. However, while they check things out for about 10 minutes, we're going to have to ask that you keep your escape shuttle parked.\n\nHave a pleasant day!"
announcer = "Spinward Stellar Coalition Police Department"
if(2)
team_size = 6
cops_to_send = /datum/antagonist/ert/families/beatcop/armored
announcement_message = "Crewmembers of [station_name()]. We have received confirmed reports of violent gang activity from your station. We are dispatching some armed officers to help keep the peace and investigate matters. Do not get in their way, and comply with any and all requests from them. We have blockaded the local warp gate, and your shuttle cannot depart for another 10 minutes.\n\nHave a secure day."
announcer = "Spinward Stellar Coalition Police Department"
if(3)
team_size = 7
cops_to_send = /datum/antagonist/ert/families/beatcop/swat
announcement_message = "Crewmembers of [station_name()]. We have received confirmed reports of extreme gang activity from your station resulting in heavy civilian casualties. The Spinward Stellar Coalition does not tolerate abuse towards our citizens, and we will be responding in force to keep the peace and reduce civilian casualties. We have your station surrounded, and all gangsters must drop their weapons and surrender peacefully.\n\nHave a secure day."
announcer = "Spinward Stellar Coalition Police Department"
if(4)
team_size = 8
cops_to_send = /datum/antagonist/ert/families/beatcop/fbi
announcement_message = "We are dispatching our top agents to [station_name()] at the request of the Spinward Stellar Coalition government due to an extreme terrorist level threat against this Nanotrasen owned station. All gangsters must surrender IMMEDIATELY. Failure to comply can and will result in death. We have blockaded your warp gates and will not allow any escape until the situation is resolved within our standard response time of 10 minutes.\n\nSurrender now or face the consequences of your actions."
announcer = "Federal Bureau of Investigation"
if(5)
team_size = 10
cops_to_send = /datum/antagonist/ert/families/beatcop/military
announcement_message = "Due to an insane level of civilian casualties aboard [station_name()], we have dispatched the National Guard to curb any and all gang activity on board the station. We have heavy cruisers watching the shuttle. Attempt to leave before we allow you to, and we will obliterate your station and your escape shuttle.\n\nYou brought this on yourselves by murdering so many civilians."
announcer = "Spinward Stellar Coalition National Guard"
priority_announce(announcement_message, announcer, 'sound/effects/families_police.ogg')
var/list/candidates = pollGhostCandidates("Do you want to help clean up crime on this station?", "deathsquad", null)
if(candidates.len)
//Pick the (un)lucky players
var/numagents = min(team_size,candidates.len)
var/list/spawnpoints = GLOB.emergencyresponseteamspawn
var/index = 0
while(numagents && candidates.len)
var/spawnloc = spawnpoints[index+1]
//loop through spawnpoints one at a time
index = (index + 1) % spawnpoints.len
var/mob/dead/observer/chosen_candidate = pick(candidates)
candidates -= chosen_candidate
if(!chosen_candidate.key)
continue
//Spawn the body
var/mob/living/carbon/human/cop = new(spawnloc)
chosen_candidate.client.prefs.copy_to(cop)
cop.key = chosen_candidate.key
//Give antag datum
var/datum/antagonist/ert/families/ert_antag = new cops_to_send
cop.mind.add_antag_datum(ert_antag)
cop.mind.assigned_role = ert_antag.name
SSjob.SendToLateJoin(cop)
//Logging and cleanup
log_game("[key_name(cop)] has been selected as an [ert_antag.name]")
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 = "<span class='header greentext'>[highest_gang] won the round by completing their objective and having the most points!</span>"
else
report = "<span class='header greentext'>[highest_gang] won the round by having the most points!</span>"
else if(alive_gangsters == alive_cops)
report = "<span class='header redtext'>Legend has it the police and the families are still duking it out to this day!</span>"
else
report = "<span class='header greentext'>The police put the boots to the families, medium style!</span>"
return "</div><div class='panel redborder'>[report]" // </div> at the front not the back because this proc is intended for normal text not a whole new panel
+14 -8
View File
@@ -2,7 +2,11 @@
name = "family signup package"
icon = 'icons/obj/gang/signup_points.dmi'
icon_state = "signup_book"
/// 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
@@ -19,27 +23,29 @@
return
var/datum/antagonist/gang/is_gangster = user.mind.has_antag_datum(/datum/antagonist/gang)
if(is_gangster && is_gangster.starter_gangster)
if(is_gangster.my_gang == team_to_use)
to_chat(user, "You started your family. You don't need to join it.")
return
to_chat(user, "You started your family. You can't turn your back on it now.")
return
attempt_join_gang(user)
/obj/item/gang_induction_package/proc/add_to_gang(var/mob/living/user)
var/datum/game_mode/gang/F = SSticker.mode
/// 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)
var/datum/antagonist/gang/swappin_sides = new gang_to_use()
user.mind.add_antag_datum(swappin_sides)
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)
swappin_sides.my_gang = team_to_use
user.playsound_local(user, 'sound/ambience/antag/thatshowfamiliesworks.ogg', 100, FALSE, pressure_affected = FALSE)
team_to_use.add_member(user.mind)
for(var/threads in team_to_use.free_clothes)
new threads(get_turf(user))
if (!F.gangbangers.Find(user.mind))
F.gangbangers += user.mind
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)
if(user && user.mind)
var/datum/antagonist/gang/is_gangster = user.mind.has_antag_datum(/datum/antagonist/gang)
@@ -6,14 +6,3 @@
continue
if(!antag_type || !specific && istype(A,antag_type) || specific && A.type == antag_type)
. += A.owner
//Get all teams [of type team_type]
/proc/get_all_teams(team_type)
. = list()
for(var/V in GLOB.antagonists)
var/datum/antagonist/A = V
if(!A.owner)
continue
var/datum/team/T = A.get_team()
if(!team_type || istype(T,team_type))
. |= T
@@ -96,7 +96,7 @@
/datum/antagonist/abductor/admin_add(datum/mind/new_owner,mob/admin)
var/list/current_teams = list()
for(var/datum/team/abductor_team/T in get_all_teams(/datum/team/abductor_team))
for(var/datum/team/abductor_team/T in GLOB.antagonist_teams)
current_teams[T.name] = T
var/choice = input(admin,"Add to which team ?") as null|anything in (current_teams + "new team")
if (choice == "new team")
+18 -14
View File
@@ -207,8 +207,11 @@
add_antag_hud(antag_hud_type, antag_hud_name, M)
if(M.hud_used)
var/datum/hud/H = M.hud_used
H.wanted_lvl = new /obj/screen/wanted
H.infodisplay += H.wanted_lvl
var/obj/screen/wanted/giving_wanted_lvl = new /obj/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/ert/families/remove_innate_effects(mob/living/mob_override)
@@ -250,18 +253,19 @@
random_names = FALSE
/datum/antagonist/ert/families/undercover_cop/on_gain()
for(var/C in 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)
if(!equipped)
to_chat(owner.current, "Unfortunately, you could not bring your [O] to this shift. You will need to find one.")
qdel(O)
if(istype(owner.current, /mob/living/carbon/human))
for(var/C in 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)
if(!equipped)
to_chat(owner.current, "Unfortunately, you could not bring your [O] to this shift. You will need to find one.")
qdel(O)
. = ..()
+242 -129
View File
@@ -1,16 +1,94 @@
/datum/antagonist/gang
name = "Family Member"
roundend_category = "gangsters"
var/gang_name = "Leet Like Jeff K"
var/gang_id = "LLJK"
var/datum/team/gang/my_gang
var/list/acceptable_clothes = list()
var/list/free_clothes = list()
var/datum/action/cooldown/spawn_induction_package/package_spawner = new()
var/gang_objective = "Be super cool and stuff."
var/starter_gangster = FALSE
antag_hud_type = ANTAG_HUD_GANGSTER
antag_hud_name = "hud_gangster"
antagpanel_category = "Family"
show_in_antagpanel = FALSE // i don't *think* this base class is buggy but it's too worthless to test
/// The overarching family that the owner of this datum is a part of. Family teams are generic and imprinted upon by the per-person antagonist datums.
var/datum/team/gang/my_gang
/// The name of the family corresponding to this family member datum.
var/gang_name = "Leet Like Jeff K"
/// The abbreviation of the family corresponding to this family member datum.
var/gang_id = "LLJK"
/// The list of clothes that are acceptable to show allegiance to this family.
var/list/acceptable_clothes = list()
/// The list of clothes that are given to family members upon induction into the family.
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
/// 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/antagonist/gang/get_team()
return my_gang
/datum/antagonist/gang/get_admin_commands()
. = ..()
.["Give extra equipment"] = CALLBACK(src,.proc/equip_gangster_in_inventory)
/datum/antagonist/gang/create_team(team_given) // gets called whenever add_antag_datum() is called on a mind
if(team_given)
my_gang = team_given
return
/* if team_given is falsey, this gang member didn't join a gang by using a recruitment package. so there are two things we need to consider
1. does a gang handler exist -- does this round have a gang_handler instanced by the families gamemode or ruleset?
2. does the gang we're trying to join already exist?
if 1 is true and 2 is false, we were probably added by the gang_handler, and probably already have a "handler" var.
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
if(!found_gang)
var/new_gang = new /datum/team/gang()
my_gang = new_gang
if(handler) // if we have a handler, the handler should track this gang
handler.gangs += my_gang
my_gang.name = gang_name
my_gang.gang_id = gang_id
my_gang.acceptable_clothes = acceptable_clothes.Copy()
my_gang.free_clothes = free_clothes.Copy()
my_gang.my_gang_datum = src
starter_gangster = TRUE
/datum/antagonist/gang/on_gain()
if(starter_gangster)
equip_gangster_in_inventory()
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/thatshowfamiliesworks.ogg', 100, FALSE, pressure_affected = FALSE)
..()
/datum/antagonist/gang/on_removal()
if(my_gang.my_gang_datum == src) // if we're the first gangster, we need to replace ourselves so that objectives function correctly
var/datum/antagonist/gang/replacement_datum = new type()
replacement_datum.handler = handler
replacement_datum.my_gang = my_gang
my_gang.my_gang_datum = replacement_datum
/* all we need to replace; the gang's "my_gang_datum" is just a person's datum because we assign it while we
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 */
..()
/datum/antagonist/gang/greet()
to_chat(owner.current, "<B>As you're the first gangster, your uniform and spraycan are in your inventory!</B>")
to_chat(owner.current, "<B><font size=3 color=red>[gang_name] for life!</font></B>")
to_chat(owner.current, "<B><font size=2 color=red>You're a member of the [gang_name] now!<br>Tag turf with a spraycan, wear your group's colors, and recruit more gangsters with the Induction Packages!</font></B>")
to_chat(owner.current, "<B><font size=4 color=red>Don't fuck with non-gangsters unless they fuck with you first.</font></B>")
to_chat(owner.current, "<B><font size=4 color=red>Don't blow shit up or make the station uninhabitable.</font></B>")
to_chat(owner.current, "<B><font size=4 color=red>Family's Objective:</B> [gang_objective]</font>")
/datum/antagonist/gang/apply_innate_effects(mob/living/mob_override)
..()
@@ -20,9 +98,11 @@
add_antag_hud(antag_hud_type, antag_hud_name, M)
if(M.hud_used)
var/datum/hud/H = M.hud_used
H.wanted_lvl = new /obj/screen/wanted
H.infodisplay += H.wanted_lvl
var/obj/screen/wanted/giving_wanted_lvl = new /obj/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)
@@ -34,25 +114,118 @@
QDEL_NULL(H.wanted_lvl)
..()
/datum/antagonist/gang/get_team()
return my_gang
/datum/antagonist/gang/proc/add_gang_points(var/points_to_add)
/// 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)
/datum/antagonist/gang/proc/check_gang_objective() // used to determine if a gang has completed their special objective
/// Determines if a gang has completed their special objective.
/datum/antagonist/gang/proc/check_gang_objective()
return TRUE
/datum/antagonist/gang/greet()
to_chat(owner.current, "<B><font size=3 color=red>[gang_name] for life!</font></B>")
to_chat(owner.current, "<B><font size=2 color=red>You're a member of the [gang_name] now!<br>Tag turf with a spraycan, wear your group's colors, and recruit more gangsters with the Induction Packages!</font></B>")
to_chat(owner.current, "<B><font size=4 color=red>Don't fuck with non-gangsters unless they fuck with you first.</font></B>")
to_chat(owner.current, "<B><font size=4 color=red>Don't blow shit up or make the station uninhabitable.</font></B>")
to_chat(owner.current, "<B><font size=4 color=red>Family's Objective:</B> [gang_objective]</font>")
/// 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)
if(!equipped)
to_chat(owner.current, "Unfortunately, you could not bring your [O] to this shift. You will need to find one.")
qdel(O)
/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.
var/list/acceptable_clothes = list()
/// The list of clothes that are given to family members upon induction into the family.
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
/datum/team/gang/roundend_report()
var/list/report = list()
report += "<span class='header'>[name]:</span>"
if(!members.len)
report += "<span class='redtext'>The family was wiped out!</span>"
else if(my_gang_datum.check_gang_objective())
report += "<span class='greentext'>The family completed their objective!</span>"
else
report += "<span class='redtext big'>The family failed their objective!</span>"
report += "Objective: [my_gang_datum.gang_objective]"
report += "Points: [points]"
if(members.len)
report += "[my_gang_datum.roundend_category] were:"
report += printplayerlist(members)
return "<div class='panel redborder'>[report.Join("<br>")]</div>"
/// Adds points to the points var.
/datum/team/gang/proc/adjust_points(var/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."
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "recruit"
icon_icon = 'icons/obj/gang/actions.dmi'
cooldown_time = 300
/// The family antagonist datum of the "owner" of this action.
var/datum/antagonist/gang/my_gang_datum
/datum/action/cooldown/spawn_induction_package/Trigger()
if(!..())
return FALSE
if(!IsAvailable())
return FALSE
if(!my_gang_datum)
return FALSE
if(!istype(owner, /mob/living/carbon/human))
return FALSE
var/mob/living/carbon/human/H = owner
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
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.")
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
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"
@@ -70,14 +243,15 @@
antag_hud_name = "Triad"
/datum/antagonist/gang/red/check_gang_objective()
var/datum/game_mode/gang/F = SSticker.mode
for(var/datum/mind/M in F.undercover_cops)
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/antagonist/gang/purple
show_in_antagpanel = TRUE
name = "Ballas"
roundend_category = "The Ballas gangsters"
gang_name = "Ballas"
@@ -104,6 +278,7 @@
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"
@@ -119,6 +294,7 @@
/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)
@@ -129,8 +305,8 @@
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"
@@ -147,22 +323,20 @@
antag_hud_name = "Russian"
/datum/antagonist/gang/russian_mafia/check_gang_objective()
var/datum/game_mode/gang/F = SSticker.mode
for(var/M in F.gangbangers)
var/datum/mind/MI = M
if(MI.has_antag_datum(src.type))
if(!considered_alive(MI.current))
continue // dead people cant really do the objective lol
var/list/items_to_check = MI.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
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/antagonist/gang/italian_mob
show_in_antagpanel = TRUE
name = "Italian Mob"
roundend_category = "The Italian mobsters"
gang_name = "Italian Mob"
@@ -178,13 +352,12 @@
antag_hud_name = "Italian"
/datum/antagonist/gang/italian_mob/check_gang_objective()
var/datum/game_mode/gang/F = SSticker.mode
for(var/M in F.gangbangers)
var/datum/mind/MI = M
if(MI.has_antag_datum(src.type))
if(considered_alive(MI.current))
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(MI.current.loc, /obj/structure/closet/crate/coffin))
if(istype(M.current.loc, /obj/structure/closet/crate/coffin))
continue
return FALSE
for(var/mob/M in GLOB.player_list)
@@ -194,6 +367,7 @@
return TRUE
/datum/antagonist/gang/tunnel_snakes
show_in_antagpanel = TRUE
name = "Tunnel Snakes"
roundend_category = "The Tunnel Snakes"
gang_name = "Tunnel Snakes"
@@ -224,6 +398,7 @@
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"
@@ -239,7 +414,6 @@
gang_objective = "Orders from up high. We need to up our drug operation. Ensure that at least 25% of the station is addicted to meth."
antag_hud_name = "Vagos"
/datum/antagonist/gang/vagos/check_gang_objective()
var/people_on_station = 0
var/people_on_crack = 0
@@ -256,8 +430,8 @@
return FALSE
return TRUE
/datum/antagonist/gang/henchmen
show_in_antagpanel = TRUE
name = "Monarch Crew"
roundend_category = "The Monarch henchmen"
gang_name = "Monarch Crew"
@@ -282,6 +456,7 @@
return TRUE
/datum/antagonist/gang/yakuza
show_in_antagpanel = TRUE
name = "Tojo Clan"
roundend_category = "The Yakuza"
gang_name = "Tojo Clan"
@@ -311,6 +486,7 @@
return TRUE
/datum/antagonist/gang/jackbros
show_in_antagpanel = TRUE
name = "Jack Bros"
roundend_category = "The Hee-hos"
gang_name = "Jack Bros"
@@ -328,20 +504,18 @@
antag_hud_name = "JackFrost"
/datum/antagonist/gang/jackbros/check_gang_objective()
var/datum/game_mode/gang/F = SSticker.mode
for(var/M in F.gangbangers)
var/datum/mind/MI = M
if(MI.has_antag_datum(src.type))
if(!considered_alive(MI.current))
continue // dead people cant really do the objective lol
if(ishuman(MI.current))
var/mob/living/carbon/human/H = MI.current
if(H.get_assignment() == "Captain")
return TRUE
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"
roundend_category = "Dutch's outlaws"
gang_name = "Dutch van der Linde's Gang"
@@ -359,79 +533,18 @@
antag_hud_name = "Dutch"
/datum/antagonist/gang/dutch/check_gang_objective()
var/datum/game_mode/gang/F = SSticker.mode
for(var/M in F.gangbangers)
var/datum/mind/MI = M
if(MI.has_antag_datum(src.type))
if(!considered_alive(MI.current))
continue // dead people cant really do the objective lol
var/list/items_to_check = MI.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
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[SSmaterials.GetMaterialRef(/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
var/points = 0
var/gang_id = "LLJK"
var/list/acceptable_clothes = list()
var/list/free_clothes = list()
var/datum/antagonist/gang/my_gang_datum
/datum/team/gang/proc/adjust_points(var/points_to_adjust)
points += points_to_adjust
/datum/team/gang/roundend_report()
return
/datum/action/cooldown/spawn_induction_package
name = "Create Induction Package"
desc = "Generate an induction package for your family."
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "recruit"
icon_icon = 'icons/obj/gang/actions.dmi'
cooldown_time = 300
var/datum/antagonist/gang/my_gang_datum
/datum/action/cooldown/spawn_induction_package/Trigger()
if(!..())
return FALSE
if(!IsAvailable())
return FALSE
if(!my_gang_datum)
return FALSE
if(!istype(owner, /mob/living/carbon/human))
return FALSE
var/mob/living/carbon/human/H = owner
if(H.stat)
return FALSE
var/datum/game_mode/gang/mode = SSticker.mode
var/lowest_gang_count = my_gang_datum.my_gang.members.len
for(var/datum/team/gang/TT in mode.gangs)
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 + mode.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.")
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.gang_to_use = my_gang_datum.type
GP.team_to_use = my_gang_datum.my_gang
StartCooldown()
return TRUE
+1
View File
@@ -687,6 +687,7 @@
#include "code\game\gamemodes\dynamic\dynamic_rulesets_roundstart.dm"
#include "code\game\gamemodes\extended\extended.dm"
#include "code\game\gamemodes\gang\gang.dm"
#include "code\game\gamemodes\gang\gang_handler.dm"
#include "code\game\gamemodes\gang\gang_things.dm"
#include "code\game\gamemodes\meteor\meteor.dm"
#include "code\game\gamemodes\meteor\meteors.dm"