diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index 8f118599e67..1bc3a639cbd 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -27,3 +27,4 @@
#define BE_BLOB 512
#define BE_NINJA 1024
#define BE_MONKEY 2048
+#define BE_GANG 4096
\ No newline at end of file
diff --git a/code/_globalvars/configuration.dm b/code/_globalvars/configuration.dm
index 5d3a5f8030b..062be18c68d 100644
--- a/code/_globalvars/configuration.dm
+++ b/code/_globalvars/configuration.dm
@@ -45,5 +45,6 @@ var/list/be_special_flags = list(
"Cultist" = BE_CULTIST,
"Blob" = BE_BLOB,
"Ninja" = BE_NINJA,
- "Monkey" = BE_MONKEY
+ "Monkey" = BE_MONKEY,
+ "Gang" = BE_GANG
)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index ef0b79ac279..64daf57b074 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -161,6 +161,10 @@ datum/mind
remove_objectives()
remove_antag_equip()
+ proc/remove_gang()
+ ticker.mode.remove_gangster(src,0,1)
+ remove_objectives()
+
proc/remove_malf()
if(src in ticker.mode.malf_ai)
ticker.mode.malf_ai -= src
@@ -196,6 +200,7 @@ datum/mind
remove_cultist()
remove_rev()
remove_malf()
+ remove_gang()
proc/show_memory(mob/recipient, window=1)
if(!recipient)
@@ -224,6 +229,7 @@ datum/mind
var/list/sections = list(
"revolution",
+ "gang",
"cult",
"wizard",
"changeling",
@@ -243,7 +249,7 @@ datum/mind
if (assigned_role in command_positions)
text += "HEAD|loyal|employee|headrev|rev"
else if (src in ticker.mode.head_revolutionaries)
- text = "head|loyal|employee|HEADREV|rev"
+ text += "head|loyal|employee|HEADREV|rev"
text += " Flash: give"
var/list/L = current.get_contents()
@@ -267,6 +273,55 @@ datum/mind
text += "head|loyal|EMPLOYEE|headrev|rev"
sections["revolution"] = text
+ /** GANG ***/
+ text = "gang"
+ if (ticker.mode.config_tag=="gang")
+ text = uppertext(text)
+ text = "[text]: "
+ if (src in ticker.mode.A_bosses)
+ text += "loyal|none|(A)gangsterBOSS|(B) gangsterboss"
+ text += " Flash & Recaller: give"
+
+ var/list/L = current.get_contents()
+ var/obj/item/device/flash/flash = locate() in L
+ if (flash)
+ if(!flash.broken)
+ text += "|take equipment."
+ else
+ text += "|take equipment|repair flash."
+ else
+ text += "."
+
+ if (objectives.len==0)
+ text += " Objectives are empty! Set to kill all rival gang leaders."
+
+ else if (src in ticker.mode.B_bosses)
+ text += "loyal|none|(A) gangsterboss|(B)gangsterBOSS"
+ text += " Flash & Recaller: give"
+
+ var/list/L = current.get_contents()
+ var/obj/item/device/flash/flash = locate() in L
+ if (flash)
+ if(!flash.broken)
+ text += " take equipment."
+ else
+ text += " take equipment|repair flash."
+ else
+ text += "."
+
+ if (objectives.len==0)
+ text += " Objectives are empty! Set to kill all rival gang leaders."
+
+ else if (src in ticker.mode.A_gangsters)
+ text += "loyal|none|(A) GANGSTERboss|(B) gangsterboss"
+ else if (src in ticker.mode.B_gangsters)
+ text += "loyal|none|(A) gangsterboss|(B) GANGSTERboss"
+ else if(isloyal(current))
+ text += "LOYAL|none|(A) gangsterboss|(B) gangsterboss"
+ else
+ text += "loyal|NONE|(A) gangsterboss|(B) gangsterboss"
+ sections["gang"] = text
+
/** CULT ***/
text = "cult"
if (ticker.mode.config_tag=="cult")
@@ -448,7 +503,7 @@ datum/mind
out += "Announce objectives
"
- usr << browse(out, "window=edit_memory[src]")
+ usr << browse(out, "window=edit_memory[src];size=400x500")
Topic(href, href_list)
if(!check_rights(R_ADMIN)) return
@@ -684,6 +739,84 @@ datum/mind
if (fail)
usr << "\red Reequipping revolutionary goes wrong!"
+ else if (href_list["gang"])
+ switch(href_list["gang"])
+ if("clear")
+ remove_gang()
+ message_admins("[key_name_admin(usr)] has de-gang'ed [current].")
+ log_admin("[key_name(usr)] has de-gang'ed [current].")
+
+ if("agang")
+ if(src in ticker.mode.A_gangsters)
+ return
+ ticker.mode.remove_gangster(src, 0, 2)
+ ticker.mode.add_gangster(src,"A",0)
+ message_admins("[key_name_admin(usr)] has added [current] to the [ticker.mode.A_name] Gang (A).")
+ log_admin("[key_name(usr)] has added [current] to the [ticker.mode.A_name] Gang (A).")
+
+ if("aboss")
+ if(src in ticker.mode.A_bosses)
+ return
+ ticker.mode.remove_gangster(src, 0, 2)
+ ticker.mode.A_bosses += src
+ src.special_role = "[ticker.mode.A_name] Gang (A) Boss"
+ ticker.mode.update_gang_icons_added(src, "A")
+ current << "You are a [ticker.mode.A_name] Gang Boss!"
+ message_admins("[key_name_admin(usr)] has added [current] to the [ticker.mode.A_name] Gang (A) leadership.")
+ log_admin("[key_name(usr)] has added [current] to the [ticker.mode.A_name] Gang (A) leadership.")
+
+ if("bgang")
+ if(src in ticker.mode.B_gangsters)
+ return
+ ticker.mode.remove_gangster(src, 0, 2)
+ ticker.mode.add_gangster(src,"B",0)
+ message_admins("[key_name_admin(usr)] has added [current] to the [ticker.mode.B_name] Gang (B).")
+ log_admin("[key_name(usr)] has added [current] to the [ticker.mode.B_name] Gang (B).")
+
+ if("bboss")
+ if(src in ticker.mode.B_bosses)
+ return
+ ticker.mode.remove_gangster(src, 0, 2)
+ ticker.mode.B_bosses += src
+ src.special_role = "[ticker.mode.B_name] Gang (B) Boss"
+ ticker.mode.update_gang_icons_added(src, "B")
+ current << "You are a [ticker.mode.B_name] Gang Boss!"
+ message_admins("[key_name_admin(usr)] has added [current] to the [ticker.mode.B_name] Gang (B) leadership.")
+ log_admin("[key_name(usr)] has added [current] to the [ticker.mode.B_name] Gang (B) leadership.")
+
+ if("autoobjective")
+ ticker.mode.forge_gang_objectives(src)
+ ticker.mode.greet_gang(src,0)
+ usr << "Unable to equip flash!"
+ if(1)
+ usr << "Unable to equip recaller!"
+ if(0)
+ usr << "Unable to equip both flash and recaller!"
+
+ if("takeequip")
+ var/list/L = current.get_contents()
+ var/obj/item/device/flash/flash = locate() in L
+ if (!flash)
+ usr << "\red Deleting flash failed!"
+ qdel(flash)
+ var/obj/item/device/recaller/recaller = locate() in L
+ if (!recaller)
+ usr << "\red Deleting recaller failed!"
+ qdel(recaller)
+
+ if("repairflash")
+ var/list/L = current.get_contents()
+ var/obj/item/device/flash/flash = locate() in L
+ if (!flash)
+ usr << "\red Repairing flash failed!"
+ else
+ flash.broken = 0
+
else if (href_list["cult"])
switch(href_list["cult"])
if("clear")
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 7d6f10c52cc..fa326af8566 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -225,6 +225,7 @@
if(BE_OPERATIVE) roletext="operative"
if(BE_WIZARD) roletext="wizard"
if(BE_REV) roletext="revolutionary"
+ if(BE_GANG) roletext="gangster"
if(BE_CULTIST) roletext="cultist"
if(BE_MONKEY) roletext="monkey"
diff --git a/code/game/gamemodes/gang/gang.dm b/code/game/gamemodes/gang/gang.dm
new file mode 100644
index 00000000000..69d376cabfd
--- /dev/null
+++ b/code/game/gamemodes/gang/gang.dm
@@ -0,0 +1,447 @@
+//gang.dm
+//Gang War Game Mode
+
+/datum/game_mode
+ var/list/datum/mind/A_bosses = list() //gang A bosses
+ var/list/datum/mind/A_gangsters = list() //gang A Members
+ var/list/datum/mind/B_bosses = list() //gang B bosses
+ var/list/datum/mind/B_gangsters = list() //gang B Members
+ var/A_name = "Waffle"
+ var/B_name = "Donk"
+
+/datum/game_mode/gang
+ name = "gang war"
+ config_tag = "gang"
+ antag_flag = BE_GANG
+ restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer")
+ required_players = 20
+ required_enemies = 2
+ recommended_enemies = 4
+
+ var/finished = 0
+ var/checkwin_counter = 0
+///////////////////////////
+//Announces the game type//
+///////////////////////////
+/datum/game_mode/gang/announce()
+ world << "The current game mode is - Gang War!"
+ world << "A violent turf war has erupted on the station! \nGangsters - Take over the station by killing the rival gang's bosses! Recruit gangsters by flashing them! \nSecurity - Protect the Crew! Identify and stop the mob bosses!"
+
+
+///////////////////////////////////////////////////////////////////////////////
+//Gets the round setup, cancelling if there's not enough players at the start//
+///////////////////////////////////////////////////////////////////////////////
+/datum/game_mode/gang/pre_setup()
+
+ var/gang_name_pool = list("Clandestine", "Prima", "Blue", "Zero-G", "Max", "Blasto", "Waffle", "North", "Omni", "Newton", "Cyber", "Donk", "Gene", "Gib")
+ A_name = pick(gang_name_pool)
+ gang_name_pool -= A_name
+ B_name = pick(gang_name_pool)
+
+ if(config.protect_roles_from_antagonist)
+ restricted_jobs += protected_jobs
+
+ for(var/datum/mind/player in antag_candidates)
+ for(var/job in restricted_jobs)//Removing heads and such from the list
+ if(player.assigned_role == job)
+ antag_candidates -= player
+
+ if(antag_candidates.len > 2)
+ assign_bosses()
+ if(antag_candidates.len > 20)
+ assign_bosses()
+
+ if(!A_bosses.len || !B_bosses.len)
+ return 0
+
+ return 1
+
+
+/datum/game_mode/gang/post_setup()
+ spawn(rand(10,100))
+ for(var/datum/mind/boss_mind in A_bosses)
+ update_gang_icons_added(boss_mind, "A")
+ forge_gang_objectives(boss_mind, "A")
+ greet_gang(boss_mind)
+ equip_gang(boss_mind.current)
+
+ for(var/datum/mind/boss_mind in B_bosses)
+ update_gang_icons_added(boss_mind, "B")
+ forge_gang_objectives(boss_mind, "B")
+ greet_gang(boss_mind)
+ equip_gang(boss_mind.current)
+
+ modePlayer += A_bosses
+ modePlayer += B_bosses
+ ..()
+
+
+/datum/game_mode/gang/process()
+ checkwin_counter++
+ if(checkwin_counter >= 5)
+ if(!finished)
+ ticker.mode.check_win()
+ checkwin_counter = 0
+ return 0
+
+/datum/game_mode/gang/proc/assign_bosses()
+ var/datum/mind/boss = pick(antag_candidates)
+ A_bosses += boss
+ antag_candidates -= boss
+ boss.special_role = "[A_name] Gang (A) Boss"
+ log_game("[boss.key] (ckey) has been selected as a boss for the [A_name] Gang (A)")
+
+ boss = pick(antag_candidates)
+ B_bosses += boss
+ antag_candidates -= boss
+ boss.special_role = "[B_name] Gang (B) Boss"
+ log_game("[boss.key] (ckey) has been selected as a boss for the [B_name] Gang (B)")
+
+/datum/game_mode/proc/forge_gang_objectives(var/datum/mind/boss_mind)
+ var/datum/objective/rival_obj = new
+ rival_obj.owner = boss_mind
+ rival_obj.explanation_text = "Assassinate or exile the [(boss_mind in A_bosses) ? B_name : A_name] Gang's bosses."
+ boss_mind.objectives += rival_obj
+
+
+/datum/game_mode/proc/greet_gang(var/datum/mind/boss_mind, var/you_are=1)
+ var/obj_count = 1
+ if (you_are)
+ boss_mind.current << "You are a [(boss_mind in A_bosses) ? A_name : B_name] Gang Boss!"
+ for(var/datum/objective/objective in boss_mind.objectives)
+ boss_mind.current << "Objective #[obj_count]: [objective.explanation_text]"
+ obj_count++
+
+///////////////////////////////////////////////////////////////////////////
+//This equips the bosses with their gear, and makes the clown not clumsy//
+///////////////////////////////////////////////////////////////////////////
+/datum/game_mode/proc/equip_gang(mob/living/carbon/human/mob)
+ if(!istype(mob))
+ return
+
+ if (mob.mind)
+ if (mob.mind.assigned_role == "Clown")
+ mob << "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself."
+ mob.mutations.Remove(CLUMSY)
+
+
+ var/obj/item/device/flash/T = new(mob)
+ var/obj/item/device/recaller/recaller = new(mob)
+
+ var/list/slots = list (
+ "backpack" = slot_in_backpack,
+ "left pocket" = slot_l_store,
+ "right pocket" = slot_r_store,
+ "left hand" = slot_l_hand,
+ "right hand" = slot_r_hand,
+ )
+
+ . = 0
+
+ var/where = mob.equip_in_one_of_slots(T, slots)
+ if (!where)
+ mob << "Your Syndicate benefactors were unfortunately unable to get you a flash."
+ else
+ mob << "The flash in your [where] will help you to persuade the crew to work for you. Keep in mind that your underlings can only identify their bosses, but not each other."
+ . += 1
+
+ var/where2 = mob.equip_in_one_of_slots(recaller, slots)
+ if (!where2)
+ mob << "Your Syndicate benefactors were unfortunately unable to get you a Recaller."
+ else
+ mob << "The Recaller in your [where2] will allow you to prevent the station from prematurely evacuating. Use it to recall the emergency shuttle from anywhere on the station."
+ . += 2
+
+ mob.update_icons()
+
+ return .
+
+/////////////////////////////////////////////
+//Checks if the either gang have won or not//
+/////////////////////////////////////////////
+/datum/game_mode/gang/check_win()
+ var/A_victory = check_gang_victory(B_bosses) //Check if B bosses are dead or exiled
+ var/B_victory = check_gang_victory(A_bosses) //Check if A bosses are dead or exiled
+
+ if(A_victory && B_victory)
+ finished = "Draw" //Both teams fail. Allow for draws in case they're all incapacitated at the same time.
+
+ else if(A_victory)
+ finished = "A" //Gang A wins
+
+ else if(B_victory)
+ finished = "B" //Gang B wins
+
+///////////////////////////////
+//Checks if the round is over//
+///////////////////////////////
+/datum/game_mode/gang/check_finished()
+ if(finished)
+ return finished
+ return 0
+
+///////////////////////////////////////////
+//Deals with converting players to a gang//
+///////////////////////////////////////////
+/datum/game_mode/proc/add_gangster(datum/mind/gangster_mind, var/gang, var/check = 1)
+ if(check && isloyal(gangster_mind.current)) //Check to see if the potential gangster is implanted
+ return 0
+ if((gangster_mind in A_bosses) || (gangster_mind in A_gangsters) || (gangster_mind in B_bosses) || (gangster_mind in B_gangsters))
+ return 0
+ if(gang == "A")
+ A_gangsters += gangster_mind
+ else
+ B_gangsters += gangster_mind
+ gangster_mind.current << "You are now a member of the [gang=="A" ? A_name : B_name] Gang!"
+ gangster_mind.current << "Help your bosses take over the station by defeating their rivals. You can identify your bosses by the brown \"B\" icons, but only they know who is in your gang! Work with your boss to avoid attacking your own gang."
+ gangster_mind.current.attack_log += "\[[time_stamp()]\] Has been converted to the [gang=="A" ? "[A_name] Gang (A)" : "[B_name] Gang (B)"]!"
+ gangster_mind.special_role = "[gang=="A" ? "[A_name] Gang (A)" : "[B_name] Gang (B)"]"
+ update_gang_icons_added(gangster_mind,gang)
+ return 1
+//////////////////////////////////////////////////////////////
+//Deals with players going straight (Not a gangster anymore)//
+//////////////////////////////////////////////////////////////
+/datum/game_mode/proc/remove_gangster(datum/mind/gangster_mind, var/beingborged, var/silent)
+ var/gang
+
+ if(gangster_mind in A_bosses)
+ A_bosses -= gangster_mind
+ gang = "A"
+
+ else if(gangster_mind in A_gangsters)
+ A_gangsters -= gangster_mind
+ gang = "A"
+
+ else if(gangster_mind in B_bosses)
+ B_bosses -= gangster_mind
+ gang = "B"
+
+ else if(gangster_mind in B_gangsters)
+ B_gangsters -= gangster_mind
+ gang = "B"
+
+ if(!gang) //not a valid gangster
+ return
+
+ gangster_mind.special_role = null
+ if(silent < 2)
+ gangster_mind.current.attack_log += "\[[time_stamp()]\] Has reformed and defected from the [gang=="A" ? "[A_name] Gang (A)" : "[B_name] Gang (B)"]!"
+
+ if(beingborged)
+ if(!silent)
+ gangster_mind.current.visible_message("The frame beeps contentedly from the MMI before initalizing it.")
+ gangster_mind.current << "The frame's firmware detects and deletes your criminal behavior! You are no longer a gangster!"
+ message_admins("[key_name_admin(gangster_mind.current)] ? has been borged while being a member of the [gang=="A" ? "[A_name] Gang (A)" : "[B_name] Gang (B)"] Gang.")
+ else
+ if(!silent)
+ gangster_mind.current.visible_message("[gangster_mind.current] looks like they've given up the life of crime!")
+ gangster_mind.current << "You have been reformed! You are no longer a gangster!"
+
+ update_gang_icons_removed(gangster_mind)
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//Keeps track of players having the correct icons////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////
+/datum/game_mode/proc/update_all_gang_icons()
+ spawn(0)
+ var/list/all_gangsters = A_bosses + B_bosses + A_gangsters + B_gangsters
+
+ //Delete all gang icons
+ for(var/datum/mind/gang_mind in all_gangsters)
+ if(gang_mind.current)
+ if(gang_mind.current.client)
+ for(var/image/I in gang_mind.current.client.images)
+ if(I.icon_state == "gangster" || I.icon_state == "gang_boss")
+ del(I)
+
+ update_gang_icons("A")
+ update_gang_icons("B")
+
+/datum/game_mode/proc/update_gang_icons(var/gang)
+ var/list/bosses
+ var/list/gangsters
+ if(gang == "A")
+ bosses = A_bosses
+ gangsters = A_gangsters
+ else if(gang == "B")
+ bosses = B_bosses
+ gangsters = B_gangsters
+ else
+ world << "ERROR: Invalid gang in update_gang_icons()"
+
+ //Update gang icons for boss' visions
+ for(var/datum/mind/boss_mind in bosses)
+ if(boss_mind.current)
+ if(boss_mind.current.client)
+ for(var/datum/mind/gangster_mind in gangsters)
+ if(gangster_mind.current)
+ var/I = image('icons/mob/mob.dmi', loc = gangster_mind.current, icon_state = "gangster")
+ boss_mind.current.client.images += I
+ for(var/datum/mind/boss2_mind in bosses)
+ if(boss2_mind.current)
+ var/I = image('icons/mob/mob.dmi', loc = boss2_mind.current, icon_state = "gang_boss")
+ boss_mind.current.client.images += I
+
+ //Update boss and self icons for gangsters' visions
+ for(var/datum/mind/gangster_mind in gangsters)
+ if(gangster_mind.current)
+ if(gangster_mind.current.client)
+ for(var/datum/mind/boss_mind in bosses)
+ if(boss_mind.current)
+ var/I = image('icons/mob/mob.dmi', loc = boss_mind.current, icon_state = "gang_boss")
+ gangster_mind.current.client.images += I
+ //Tag themselves to see
+ var/K
+ if(gangster_mind in bosses) //If the new gangster is a boss himself
+ K = image('icons/mob/mob.dmi', loc = gangster_mind.current, icon_state = "gang_boss")
+ else
+ K = image('icons/mob/mob.dmi', loc = gangster_mind.current, icon_state = "gangster")
+ gangster_mind.current.client.images += K
+
+/////////////////////////////////////////////////
+//Assigns icons when a new gangster is recruited//
+/////////////////////////////////////////////////
+/datum/game_mode/proc/update_gang_icons_added(datum/mind/recruit_mind, var/gang)
+ var/list/bosses
+ if(gang == "A")
+ bosses = A_bosses
+ else if(gang == "B")
+ bosses = B_bosses
+ if(!gang)
+ world << "ERROR: Invalid gang in update_gang_icons_added()"
+
+ spawn(0)
+ for(var/datum/mind/boss_mind in bosses)
+ //Tagging the new gangster for the bosses to see
+ if(boss_mind.current)
+ if(boss_mind.current.client)
+ var/I
+ if(recruit_mind in bosses) //If the new gangster is a boss himself
+ I = image('icons/mob/mob.dmi', loc = recruit_mind.current, icon_state = "gang_boss")
+ else
+ I = image('icons/mob/mob.dmi', loc = recruit_mind.current, icon_state = "gangster")
+ boss_mind.current.client.images += I
+ //Tagging every boss for the new gangster to see
+ if(recruit_mind.current)
+ if(recruit_mind.current.client)
+ var/image/J = image('icons/mob/mob.dmi', loc = boss_mind.current, icon_state = "gang_boss")
+ recruit_mind.current.client.images += J
+ //Tag themselves to see
+ if(recruit_mind.current)
+ if(recruit_mind.current.client)
+ var/K
+ if(recruit_mind in bosses) //If the new gangster is a boss himself
+ K = image('icons/mob/mob.dmi', loc = recruit_mind.current, icon_state = "gang_boss")
+ else
+ K = image('icons/mob/mob.dmi', loc = recruit_mind.current, icon_state = "gangster")
+ recruit_mind.current.client.images += K
+
+////////////////////////////////////////
+//Keeps track of deconverted gangsters//
+////////////////////////////////////////
+/datum/game_mode/proc/update_gang_icons_removed(datum/mind/defector_mind)
+ var/list/all_gangsters = A_bosses + B_bosses + A_gangsters + B_gangsters
+
+ spawn(0)
+ //Remove defector's icon from gangsters' visions
+ for(var/datum/mind/boss_mind in all_gangsters)
+ if(boss_mind.current)
+ if(boss_mind.current.client)
+ for(var/image/I in boss_mind.current.client.images)
+ if((I.icon_state == "gangster" || I.icon_state == "gang_boss") && I.loc == defector_mind.current)
+ del(I)
+
+ //Remove gang icons from defector's vision
+ if(defector_mind.current)
+ if(defector_mind.current.client)
+ for(var/image/I in defector_mind.current.client.images)
+ if(I.icon_state == "gangster" || I.icon_state == "gang_boss")
+ del(I)
+
+///////////////////////////
+//Checks for gang victory//
+///////////////////////////
+/datum/game_mode/gang/proc/check_gang_victory(var/list/boss_list)
+ if(!boss_list.len)
+ return 0
+ for(var/datum/mind/boss_mind in boss_list)
+ if(boss_mind.current)
+ if(boss_mind.current.stat == DEAD || !ishuman(boss_mind.current) || !boss_mind.current.ckey || !boss_mind.current.client)
+ return 1
+ var/turf/T = get_turf(boss_mind.current)
+ if(T && (T.z != 1)) //If they leave the station they count as dead for this
+ return 1
+ return 0
+ return 1
+
+//////////////////////////////////////////////////////////////////////
+//Announces the end of the game with all relavent information stated//
+//////////////////////////////////////////////////////////////////////
+/datum/game_mode/gang/declare_completion()
+ if(!finished)
+ world << "The station was evacuated before either gang could claim it!"
+ if(finished == "Draw")
+ world << "All gang bosses have been killed or exiled!"
+ else
+ world << "The [finished=="A" ? A_name : B_name] Gang defeated their rivals!"
+ ..()
+ return 1
+
+/datum/game_mode/proc/auto_declare_completion_gang()
+ var/winner
+ var/datum/game_mode/gang/game_mode = ticker.mode
+ if(istype(game_mode))
+ winner = game_mode.finished
+
+ var/num_ganga = 0
+ var/list/agang = A_gangsters + A_bosses
+ for(var/datum/mind/agangster in agang)
+ if(agangster.current)
+ if(agangster.current in living_mob_list)
+ num_ganga++
+
+ var/num_gangb = 0
+ var/list/bgang = B_gangsters + B_bosses
+ for(var/datum/mind/bgangster in bgang)
+ if(bgangster.current)
+ if(bgangster.current in living_mob_list)
+ num_gangb++
+
+ if(A_bosses.len || A_gangsters.len)
+ if(winner == "A" || winner == "B")
+ world << " The [A_name] Gang was [winner=="A" ? "victorious!" : "defeated."]"
+ world << "[TAB][A_name] Gang strength: [round((num_ganga/living_mob_list.len)*100, 0.1)]%"
+ world << " The [A_name] Gang bosses were:"
+ gang_membership_report(A_bosses)
+ world << " The [A_name] Gangsters were:"
+ gang_membership_report(A_gangsters)
+
+ if(B_bosses.len || B_gangsters.len)
+ if(winner == "A" || winner == "B")
+ world << " The [B_name] Gang was [winner=="B" ? "victorious!" : "defeated."]"
+ world << "[TAB][B_name] Gang strength: [round((num_gangb/living_mob_list.len)*100, 0.1)]%"
+ world << " The [B_name] Gang bosses were:"
+ gang_membership_report(B_bosses)
+ world << " The [B_name] Gangsters were:"
+ gang_membership_report(B_gangsters)
+
+/datum/game_mode/proc/gang_membership_report(var/list/membership)
+ var/text = ""
+ for(var/datum/mind/gang_mind in membership)
+ text += " [gang_mind.key] was [gang_mind.name] ("
+ if(gang_mind.current)
+ if(gang_mind.current.stat == DEAD)
+ text += "died"
+ else if(gang_mind.current.z != 1)
+ text += "fled the station"
+ else
+ text += "survived"
+ if(gang_mind.current.real_name != gang_mind.name)
+ text += " as [gang_mind.current.real_name]"
+ else
+ text += "body destroyed"
+ text += ")"
+ text += " "
+
+ world << text
\ No newline at end of file
diff --git a/code/game/gamemodes/intercept_report.dm b/code/game/gamemodes/intercept_report.dm
index 35b5f42c699..0b64acb7eb4 100644
--- a/code/game/gamemodes/intercept_report.dm
+++ b/code/game/gamemodes/intercept_report.dm
@@ -61,6 +61,10 @@
src.text = ""
src.build_rev(correct_person)
return src.text
+ if("gang")
+ src.text = ""
+ src.build_gang(correct_person)
+ return src.text
if("cult")
src.text = ""
src.build_cult(correct_person)
@@ -220,6 +224,10 @@
src.text += " However, if this information is acted on without substantial evidence, those responsible will face severe repercussions."
*/
+/datum/intercept_text/proc/build_gang(datum/mind/correct_person)
+ src.text += "
Syndicate forces may be supplying opposing criminal organizations within your sector in an attempt at destabilizing our operations."
+ src.text += "Ensure law and order is maintained on the station and be on the lookout for violent confrontations between station factions."
+ src.text += "Forced labor on the mining asteroid is recommended for anyone convicted of heading a criminal organization."
/datum/intercept_text/proc/build_wizard(datum/mind/correct_person)
var/SWF_desc = pick(SWF_names)
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 30cc57e9c7f..a3c9a89af8d 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -90,7 +90,7 @@ datum/objective/mutiny/check_completion()
datum/objective/mutiny/update_explanation_text()
..()
if(target && target.current)
- explanation_text = "Assassinate [target.current.real_name], the [!target_role_type ? target.assigned_role : target.special_role]."
+ explanation_text = "Assassinate or exile [target.current.real_name], the [!target_role_type ? target.assigned_role : target.special_role]."
else
explanation_text = "Free Objective"
diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm
index 383fcb9c653..437e73eace5 100644
--- a/code/game/gamemodes/revolution/revolution.dm
+++ b/code/game/gamemodes/revolution/revolution.dm
@@ -79,10 +79,11 @@
rev_obj.explanation_text = "Assassinate [head_mind.name], the [head_mind.assigned_role]."
rev_mind.objectives += rev_obj
- // equip_traitor(rev_mind.current, 1) //changing how revs get assigned their uplink so they can get PDA uplinks. --NEO
- // Removing revolutionary uplinks. -Pete
- equip_revolutionary(rev_mind.current)
- update_rev_icons_added(rev_mind)
+ spawn(rand(10,100))
+ // equip_traitor(rev_mind.current, 1) //changing how revs get assigned their uplink so they can get PDA uplinks. --NEO
+ // Removing revolutionary uplinks. -Pete
+ equip_revolutionary(rev_mind.current)
+ update_rev_icons_added(rev_mind)
for(var/datum/mind/rev_mind in head_revolutionaries)
greet_revolutionary(rev_mind)
@@ -107,7 +108,7 @@
var/datum/objective/mutiny/rev_obj = new
rev_obj.owner = rev_mind
rev_obj.target = head_mind
- rev_obj.explanation_text = "Assassinate [head_mind.name], the [head_mind.assigned_role]."
+ rev_obj.explanation_text = "Assassinate or exile [head_mind.name], the [head_mind.assigned_role]."
rev_mind.objectives += rev_obj
/datum/game_mode/proc/greet_revolutionary(var/datum/mind/rev_mind, var/you_are=1)
@@ -200,7 +201,8 @@
rev_mind.current.attack_log += "\[[time_stamp()]\] Has renounced the revolution!"
if(beingborged)
- rev_mind.current << "\red The frame's firmware detects and deletes your neural reprogramming! You remember nothing from the moment you were flashed until now."
+ rev_mind.current << "\red The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you."
+ message_admins("[key_name_admin(rev_mind.current)] ? has been borged while being a member of the revolution.")
else
rev_mind.current << "\red You have been brainwashed! You are no longer a revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you..."
@@ -268,20 +270,36 @@
/datum/game_mode/proc/update_rev_icons_added(datum/mind/rev_mind)
spawn(0)
for(var/datum/mind/head_rev_mind in head_revolutionaries)
+
+ //Tagging the new rev for revheads to see
if(head_rev_mind.current)
if(head_rev_mind.current.client)
- var/I = image('icons/mob/mob.dmi', loc = rev_mind.current, icon_state = "rev")
+ var/I
+ if(rev_mind in head_revolutionaries) //If the new rev is a head rev
+ I = image('icons/mob/mob.dmi', loc = rev_mind.current, icon_state = "rev_head")
+ else
+ I = image('icons/mob/mob.dmi', loc = rev_mind.current, icon_state = "rev")
head_rev_mind.current.client.images += I
+
+ //Tagging the revheads for new rev to see
if(rev_mind.current)
if(rev_mind.current.client)
var/image/J = image('icons/mob/mob.dmi', loc = head_rev_mind.current, icon_state = "rev_head")
rev_mind.current.client.images += J
for(var/datum/mind/rev_mind_1 in revolutionaries)
+
+ //Tagging the new rev for fellow revs to see
if(rev_mind_1.current)
if(rev_mind_1.current.client)
- var/I = image('icons/mob/mob.dmi', loc = rev_mind.current, icon_state = "rev")
+ var/I
+ if(rev_mind in head_revolutionaries) //If the new rev is a head rev
+ I = image('icons/mob/mob.dmi', loc = rev_mind.current, icon_state = "rev_head")
+ else
+ I = image('icons/mob/mob.dmi', loc = rev_mind.current, icon_state = "rev")
rev_mind_1.current.client.images += I
+
+ //Tagging fellow revs for the new rev to see
if(rev_mind.current)
if(rev_mind.current.client)
var/image/J = image('icons/mob/mob.dmi', loc = rev_mind_1.current, icon_state = "rev")
@@ -340,7 +358,7 @@
/datum/game_mode/revolution/declare_completion()
if(finished == 1)
feedback_set_details("round_end_result","win - heads killed")
- world << "\red The heads of staff were killed or abandoned the station! The revolutionaries win!"
+ world << "\red The heads of staff were killed or exiled! The revolutionaries win!"
else if(finished == 2)
feedback_set_details("round_end_result","loss - rev heads killed")
world << "\red The heads of staff managed to stop the revolution!"
@@ -421,10 +439,4 @@
text += ""
text += " "
- world << text
-
-/proc/is_convertable_to_rev(datum/mind/mind)
- return istype(mind) && \
- istype(mind.current, /mob/living/carbon/human) && \
- !(mind.assigned_role in command_positions) && \
- !(mind.assigned_role in list("Security Officer", "Detective", "Warden"))
+ world << text
\ No newline at end of file
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index ec9da16ba30..58884d1ee05 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -174,17 +174,15 @@
// -- Mode/mind specific stuff goes here
- switch(ticker.mode.name)
- if("revolution")
- if((H.mind in ticker.mode:revolutionaries) || (H.mind in ticker.mode:head_revolutionaries))
- ticker.mode.update_all_rev_icons() //So the icon actually appears
- if("nuclear emergency")
- if(H.mind in ticker.mode.syndicates)
- ticker.mode.update_all_synd_icons()
- if("cult")
- if (H.mind in ticker.mode.cult)
- ticker.mode.add_cultist(src.occupant.mind)
- ticker.mode.update_all_cult_icons() //So the icon actually appears
+ if((H.mind in ticker.mode.revolutionaries) || (H.mind in ticker.mode.head_revolutionaries))
+ ticker.mode.update_all_rev_icons() //So the icon actually appears
+ if((H.mind in ticker.mode.A_bosses) || ((H.mind in ticker.mode.A_gangsters) || (H.mind in ticker.mode.B_bosses)) || (H.mind in ticker.mode.B_gangsters))
+ ticker.mode.update_all_gang_icons()
+ if(H.mind in ticker.mode.syndicates)
+ ticker.mode.update_all_synd_icons()
+ if (H.mind in ticker.mode.cult)
+ ticker.mode.add_cultist(src.occupant.mind)
+ ticker.mode.update_all_cult_icons() //So the icon actually appears
// -- End mode specific stuff
diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm
index 169d8ef70a9..f41a70a2032 100644
--- a/code/game/machinery/computer/ai_core.dm
+++ b/code/game/machinery/computer/ai_core.dm
@@ -143,6 +143,7 @@
ticker.mode.remove_cultist(M.brainmob.mind, 1)
ticker.mode.remove_revolutionary(M.brainmob.mind, 1)
+ ticker.mode.remove_gangster(M.brainmob.mind, 1)
user.drop_item()
M.loc = src
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 7ab878e4c54..2d60a854cad 100644
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -624,6 +624,7 @@ var/const/CALL_SHUTTLE_REASON_LENGTH = 12
emergency_shuttle.recall(signal_origin)
log_game("[key_name(user)] has recalled the shuttle.")
message_admins("[key_name_admin(user)] has recalled the shuttle.", 1)
+ return 1
return
/obj/machinery/computer/communications/proc/post_status(var/command, var/data1, var/data2)
diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm
index df97a6ab825..a2c5b5112b6 100644
--- a/code/game/objects/items/devices/flash.dm
+++ b/code/game/objects/items/devices/flash.dm
@@ -74,21 +74,22 @@
flick("e_flash", M.flash)
if(ishuman(M) && ishuman(user) && M.stat != DEAD)
- if(user.mind && user.mind in ticker.mode.head_revolutionaries)
+ if(user.mind && ((user.mind in ticker.mode.head_revolutionaries) || (user.mind in ticker.mode.A_bosses) || (user.mind in ticker.mode.B_bosses)))
if(M.client)
if(M.stat == CONSCIOUS)
- var/revsafe = 0
- if(isloyal(M))
- revsafe = 1
M.mind_initialize() //give them a mind datum if they don't have one.
-// if(M.mind.has_been_rev)
-// revsafe = 2
- if(!revsafe)
- M.mind.has_been_rev = 1
- ticker.mode.add_revolutionary(M.mind)
- else if(revsafe == 1)
- user << "Something seems to be blocking the flash!"
- else
+ M.mind.has_been_rev = 1
+ var/resisted
+ if(user.mind in ticker.mode.head_revolutionaries)
+ if(!ticker.mode.add_revolutionary(M.mind))
+ resisted = 1
+ if(user.mind in ticker.mode.A_bosses)
+ if(!ticker.mode.add_gangster(M.mind,"A"))
+ resisted = 1
+ if(user.mind in ticker.mode.B_bosses)
+ if(!ticker.mode.add_gangster(M.mind,"B"))
+ resisted = 1
+ if(resisted)
user << "This mind seems resistant to the flash!"
else
user << "They must be conscious before you can convert them!"
diff --git a/code/game/objects/items/devices/recaller.dm b/code/game/objects/items/devices/recaller.dm
new file mode 100644
index 00000000000..b95614c3034
--- /dev/null
+++ b/code/game/objects/items/devices/recaller.dm
@@ -0,0 +1,42 @@
+//Recaller device
+//Allows gang leaders to recall the shuttle
+/obj/item/device/recaller
+ name = "suspicious device"
+ desc = "A strange device of sorts. Hard to really make out what it actually does just by looking."
+ icon_state = "recaller"
+ item_state = "walkietalkie"
+ throwforce = 0
+ w_class = 1.0
+ throw_speed = 3
+ throw_range = 7
+ flags = CONDUCT
+ var/recalling = 0
+
+/obj/item/device/recaller/attack_self(mob/user)
+ if(recalling)
+ return
+ if((user.mind in ticker.mode.A_bosses) || (user.mind in ticker.mode.B_bosses))
+ var/turf/userturf = get_turf(user)
+ if(userturf.z != 1)
+ user << "Error: Device out of range of station communication arrays."
+ return
+
+ if(emergency_shuttle.location==0)
+ if (emergency_shuttle.online)
+ recalling = 1
+ user << "Generating shuttle recall order with codes retrieved from last call signal..."
+ sleep(10)
+ user << "Shuttle recall order generated."
+ sleep(5)
+ user << "Accessing station long-range communication arrays..."
+ sleep(10)
+ user << "Comm arrays accessed."
+ sleep(5)
+ user << "Broadcasting recall signal..."
+ sleep(20)
+ recalling = 0
+ if(!cancel_call_proc(user))
+ user << "No response recieved. Emergency shuttle cannot be recalled at this time."
+ return
+
+ user << "Emergency shuttle cannot be recalled at this time."
\ No newline at end of file
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index f88936e66d9..f7c8c2a4e71 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -196,7 +196,7 @@
user << "\red Sticking a dead brain into the frame would sort of defeat the purpose."
return
- if(M.brainmob.mind in ticker.mode.head_revolutionaries)
+ if((M.brainmob.mind in ticker.mode.head_revolutionaries) || (M.brainmob.mind in ticker.mode.A_bosses) || (M.brainmob.mind in ticker.mode.B_bosses))
user << "\red The frame's firmware lets out a shrill sound, and flashes 'Abnormal Memory Engram'. It refuses to accept the MMI."
return
diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm
index 860766ddeb4..fac7c352b25 100644
--- a/code/modules/admin/DB ban/functions.dm
+++ b/code/modules/admin/DB ban/functions.dm
@@ -365,7 +365,7 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
output += ""
for(var/j in nonhuman_positions)
output += ""
- for(var/j in list("traitor","changeling","operative","revolutionary","cultist","wizard"))
+ for(var/j in list("traitor","changeling","operative","revolutionary", "gangster","cultist","wizard"))
output += ""
output += ""
output += "Reason:
"
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index d9b91ef9f84..1d17c674f9a 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -430,6 +430,38 @@
dat += "
Head not found!
"
dat += ""
+ if(ticker.mode.A_bosses.len || ticker.mode.A_gangsters.len)
+ dat += "
[ticker.mode.A_name] Gang Members
"
+ for(var/datum/mind/N in ticker.mode.A_bosses)
+ var/mob/M = N.current
+ if(!M)
+ dat += "