diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 50bce2a1f48..0d823aa07a8 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -1197,7 +1197,9 @@
ticker.mode.devils += src
special_role = "devil"
ticker.mode.finalize_devil(src)
+ ticker.mode.add_devil_objectives(src, 2)
announceDevilLaws()
+ announce_objectives()
if("sintouched")
if(ishuman(current))
ticker.mode.sintouched += src
diff --git a/code/game/gamemodes/devil/devil agent/devil_agent.dm b/code/game/gamemodes/devil/devil agent/devil_agent.dm
new file mode 100644
index 00000000000..dfdb957153a
--- /dev/null
+++ b/code/game/gamemodes/devil/devil agent/devil_agent.dm
@@ -0,0 +1,43 @@
+/datum/game_mode/devil/devil_agents
+ name = "Devil Agents"
+ config_tag = "devil_agents"
+ required_players = 25
+ required_enemies = 3
+ recommended_enemies = 8
+ reroll_friendly = 0
+
+ traitors_possible = 10 //hard limit on traitors if scaling is turned off
+ num_modifier = 4
+ objective_count = 2
+
+ var/list/target_list = list()
+ var/list/late_joining_list = list()
+ minimum_devils = 3
+
+ announce_text = "There are devil agents onboard the station, trying to outbid each other!\n\
+ + Devils: Purchase souls and interfere with your rivals!\n\
+ + Crew: Resist the lure of sin and remain pure!"
+
+/datum/game_mode/devil/devil_agents/post_setup()
+ var/i = 0
+ for(var/datum/mind/devil in devils)
+ i++
+ if(i + 1 > devils.len)
+ i = 0
+ target_list[devil] = devils[i + 1]
+ ..()
+
+/datum/game_mode/devil/devil_agents/add_devil_objectives(datum/mind/devil_mind, quantity)
+ ..(devil_mind, quantity - give_outsell_objective(devil_mind))
+
+/datum/game_mode/devil/devil_agents/proc/give_outsell_objective(datum/mind/devil)
+ //If you override this method, have it return the number of objectives added.
+ if(target_list.len && target_list[devil]) // Is a double agent
+ var/datum/mind/target_mind = target_list[devil]
+ var/datum/objective/devil/outsell/outsellobjective = new
+ outsellobjective.owner = devil
+ outsellobjective.target = target_mind
+ outsellobjective.update_explanation_text()
+ devil.objectives += outsellobjective
+ return 1
+ return 0
diff --git a/code/game/gamemodes/devil/devil_game_mode.dm b/code/game/gamemodes/devil/devil_game_mode.dm
index 97411e87e66..c64653a986b 100644
--- a/code/game/gamemodes/devil/devil_game_mode.dm
+++ b/code/game/gamemodes/devil/devil_game_mode.dm
@@ -1,111 +1,61 @@
-/datum/game_mode
- var/list/datum/mind/sintouched = list()
- var/list/datum/mind/devils = list()
- var/devil_ascended = 0 // Number of arch devils on station
-
-/datum/game_mode/proc/auto_declare_completion_sintouched()
- var/text = ""
- if(sintouched.len)
- text += "
The sintouched were:"
- var/list/sintouchedUnique = uniqueList(sintouched)
- for(var/S in sintouchedUnique)
- var/datum/mind/sintouched_mind = S
- text += printplayer(sintouched_mind)
- text += printobjectives(sintouched_mind)
- text += "
"
- text += "
"
- world << text
-
-/datum/game_mode/proc/auto_declare_completion_devils()
- /var/text = ""
- if(devils.len)
- text += "
The devils were:"
- for(var/D in devils)
- var/datum/mind/devil = D
- text += printplayer(devil)
- text += printdevilinfo(devil)
- text += printobjectives(devil)
- text += "
"
- world << text
-
/datum/game_mode/devil
+ name = "devil"
+ config_tag = "devil"
+ antag_flag = ROLE_DEVIL
+ protected_jobs = list("Lawyer", "Librarian", "Chaplain", "Head of Security", "Captain", "AI")
+ required_players = 0
+ required_enemies = 1
+ recommended_enemies = 4
+ reroll_friendly = 1
+ enemy_minimum_age = 0
+
+ var/traitors_possible = 4 //hard limit on devils if scaling is turned off
+ var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual.
+ var/objective_count = 2
+ var/minimum_devils = 1
+
+ announce_text = "There are devils onboard the station!\n\
+ + Devils: Purchase souls and tempt the crew to sin!\n\
+ + Crew: Resist the lure of sin and remain pure!"
+
+/datum/game_mode/devil/pre_setup()
+
+ if(config.protect_roles_from_antagonist)
+ restricted_jobs += protected_jobs
+ if(config.protect_assistant_from_antagonist)
+ restricted_jobs += "Assistant"
+
+ var/num_devils = 1
+
+ if(config.traitor_scaling_coeff)
+ num_devils = max(minimum_devils, min( round(num_players()/(config.traitor_scaling_coeff*3))+ 2 + num_modifier, round(num_players()/(config.traitor_scaling_coeff*1.5)) + num_modifier ))
+ else
+ num_devils = max(minimum_devils, min(num_players(), traitors_possible))
+
+ for(var/j = 0, j < num_devils, j++)
+ if (!antag_candidates.len)
+ break
+ var/datum/mind/devil = pick(antag_candidates)
+ devils += devil
+ devil.special_role = traitor_name
+ devil.restricted_roles = restricted_jobs
+
+ log_game("[devil.key] (ckey) has been selected as a [traitor_name]")
+ antag_candidates.Remove(devil)
+
+ if(devils.len < required_enemies)
+ return 0
+ return 1
-/datum/game_mode/proc/finalize_devil(datum/mind/devil_mind)
- var/mob/living/carbon/human/S = devil_mind.current
- var/trueName= randomDevilName()
- var/datum/objective/devil/soulquantity/soulquant = new
- soulquant.owner = devil_mind
- var/datum/objective/devil/obj_2 = pick(new /datum/objective/devil/soulquality(null), new /datum/objective/devil/sintouch(null))
- obj_2.owner = devil_mind
- devil_mind.objectives += obj_2
- devil_mind.objectives += soulquant
- devil_mind.devilinfo = devilInfo(trueName, 1)
- devil_mind.store_memory("Your devilic true name is [devil_mind.devilinfo.truename]
[lawlorify[LAW][devil_mind.devilinfo.ban]]
You may not use violence to coerce someone into selling their soul.
You may not directly and knowingly physically harm a devil, other than yourself.
[lawlorify[LAW][devil_mind.devilinfo.bane]]
[lawlorify[LAW][devil_mind.devilinfo.obligation]]
[lawlorify[LAW][devil_mind.devilinfo.banish]]
")
- devil_mind.devilinfo.owner = devil_mind
- devil_mind.devilinfo.give_base_spells(1)
- spawn(10)
- devil_mind.devilinfo.update_hud()
- if(devil_mind.assigned_role == "Clown")
- S << "Your infernal nature has allowed you to overcome your clownishness."
- S.dna.remove_mutation(CLOWNMUT)
-
-/datum/mind/proc/announceDevilLaws()
- if(!devilinfo)
- return
- current << "You remember your link to the infernal. You are [src.devilinfo.truename], an agent of hell, a devil. And you were sent to the plane of creation for a reason. A greater purpose. Convince the crew to sin, and embroiden Hell's grasp."
- current << "However, your infernal form is not without weaknesses."
- current << "You may not use violence to coerce someone into selling their soul."
- current << "You may not directly and knowingly physically harm a devil, other than yourself."
- current << lawlorify[LAW][src.devilinfo.bane]
- current << lawlorify[LAW][src.devilinfo.ban]
- current << lawlorify[LAW][src.devilinfo.obligation]
- current << lawlorify[LAW][src.devilinfo.banish]
- current << "
Remember, the crew can research your weaknesses if they find out your devil name.
"
- var/obj_count = 1
- current << "Your current objectives:"
- for(var/O in objectives)
- var/datum/objective/objective = O
- current << "Objective #[obj_count]: [objective.explanation_text]"
- obj_count++
-
-/datum/game_mode/proc/printdevilinfo(datum/mind/ply)
- if(!ply.devilinfo)
- return ""
- var/text = "The devil's true name is: [ply.devilinfo.truename]"
- text += "The devil's bans were:"
- text += " [lawlorify[LORE][ply.devilinfo.ban]]"
- text += " [lawlorify[LORE][ply.devilinfo.bane]]"
- text += " [lawlorify[LORE][ply.devilinfo.obligation]]"
- text += " [lawlorify[LORE][ply.devilinfo.banish]]"
- return text
-
-/datum/game_mode/proc/update_devil_icons_added(datum/mind/devil_mind)
- var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_DEVIL]
- hud.join_hud(devil_mind.current)
- set_antag_hud(devil_mind.current, "devil")
-
-/datum/game_mode/proc/update_devil_icons_removed(datum/mind/devil_mind)
- var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_DEVIL]
- hud.leave_hud(devil_mind.current)
- set_antag_hud(devil_mind.current, null)
-
-/datum/game_mode/proc/update_sintouch_icons_added(datum/mind/sin_mind)
- var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_SINTOUCHED]
- hud.join_hud(sin_mind.current)
- set_antag_hud(sin_mind.current, "sintouched")
-
-/datum/game_mode/proc/update_sintouch_icons_removed(datum/mind/sin_mind)
- var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_SINTOUCHED]
- hud.leave_hud(sin_mind.current)
- set_antag_hud(sin_mind.current, null)
-
-/datum/game_mode/proc/update_soulless_icons_added(datum/mind/soulless_mind)
- var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_SOULLESS]
- hud.join_hud(soulless_mind.current)
- set_antag_hud(soulless_mind.current, "soulless")
-
-/datum/game_mode/proc/update_soulless_icons_removed(datum/mind/soulless_mind)
- var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_SOULLESS]
- hud.leave_hud(soulless_mind.current)
- set_antag_hud(soulless_mind.current, null)
+/datum/game_mode/devil/post_setup()
+ for(var/datum/mind/devil in devils)
+ spawn(rand(10,100))
+ finalize_devil(devil, objective_count)
+ spawn(100)
+ add_devil_objectives(devil, objective_count) //This has to be in a separate loop, as we need devil names to be generated before we give objectives in devil agent.
+ devil.announceDevilLaws()
+ devil.announce_objectives()
+ modePlayer += devils
+ ..()
+ return 1
diff --git a/code/game/gamemodes/devil/devilinfo.dm b/code/game/gamemodes/devil/devilinfo.dm
index 75d5c0ca724..0b9b4b59213 100644
--- a/code/game/gamemodes/devil/devilinfo.dm
+++ b/code/game/gamemodes/devil/devilinfo.dm
@@ -7,6 +7,8 @@
#define TRUE_DEVIL 2
#define ARCH_DEVIL 3
+#define LOSS_PER_DEATH 2
+
#define SOULVALUE soulsOwned.len-reviveNumber
#define DEVILRESURRECTTIME 600
@@ -162,16 +164,16 @@ var/global/list/lawlorify = list (
update_hud()
/datum/devilinfo/proc/check_regression()
- if (form == ARCH_DEVIL)
+ if(form == ARCH_DEVIL)
return //arch devil can't regress
- switch(SOULVALUE)
- if(-1)
- remove_spells()
- owner.current << "As punishment for your failures, all of your powers except contract creation have been revoked."
- if(BLOOD_THRESHOLD-1)
- regress_humanoid()
- if(TRUE_THRESHOLD-1)
- regress_blood_lizard()
+ //Yes, fallthrough behavior is intended, so I can't use a switch statement.
+ if(form == TRUE_DEVIL && SOULVALUE < TRUE_THRESHOLD)
+ regress_blood_lizard()
+ if(form == BLOOD_LIZARD && SOULVALUE < BLOOD_THRESHOLD)
+ regress_humanoid()
+ if(SOULVALUE < 0)
+ remove_spells()
+ owner.current << "As punishment for your failures, all of your powers except contract creation have been revoked."
/datum/devilinfo/proc/increase_form()
switch(form)
@@ -386,7 +388,7 @@ var/global/list/lawlorify = list (
/datum/devilinfo/proc/hellish_resurrection(mob/living/body)
message_admins("[owner.name] (true name is: [truename]) is resurrecting using hellish energy.")
if(SOULVALUE <= ARCH_THRESHOLD) // once ascended, arch devils do not go down in power by any means.
- reviveNumber++
+ reviveNumber += LOSS_PER_DEATH
update_hud()
if(body)
body.revive(1,0)
diff --git a/code/game/gamemodes/devil/game_mode.dm b/code/game/gamemodes/devil/game_mode.dm
new file mode 100644
index 00000000000..5f0846ac1e4
--- /dev/null
+++ b/code/game/gamemodes/devil/game_mode.dm
@@ -0,0 +1,111 @@
+/datum/game_mode
+ var/list/datum/mind/sintouched = list()
+ var/list/datum/mind/devils = list()
+ var/devil_ascended = 0 // Number of arch devils on station
+
+/datum/game_mode/proc/auto_declare_completion_sintouched()
+ var/text = ""
+ if(sintouched.len)
+ text += "
The sintouched were:"
+ var/list/sintouchedUnique = uniqueList(sintouched)
+ for(var/S in sintouchedUnique)
+ var/datum/mind/sintouched_mind = S
+ text += printplayer(sintouched_mind)
+ text += printobjectives(sintouched_mind)
+ text += "
"
+ text += "
"
+ world << text
+
+/datum/game_mode/proc/auto_declare_completion_devils()
+ /var/text = ""
+ if(devils.len)
+ text += "
The devils were:"
+ for(var/D in devils)
+ var/datum/mind/devil = D
+ text += printplayer(devil)
+ text += printdevilinfo(devil)
+ text += printobjectives(devil)
+ text += "
"
+ text += "
"
+ world << text
+
+
+/datum/game_mode/proc/finalize_devil(datum/mind/devil_mind)
+ var/mob/living/carbon/human/S = devil_mind.current
+ var/trueName= randomDevilName()
+
+ devil_mind.devilinfo = devilInfo(trueName, 1)
+ devil_mind.store_memory("Your devilic true name is [devil_mind.devilinfo.truename]
[lawlorify[LAW][devil_mind.devilinfo.ban]]
You may not use violence to coerce someone into selling their soul.
You may not directly and knowingly physically harm a devil, other than yourself.
[lawlorify[LAW][devil_mind.devilinfo.bane]]
[lawlorify[LAW][devil_mind.devilinfo.obligation]]
[lawlorify[LAW][devil_mind.devilinfo.banish]]
")
+ devil_mind.devilinfo.owner = devil_mind
+ devil_mind.devilinfo.give_base_spells(1)
+ spawn(10)
+ devil_mind.devilinfo.update_hud()
+ if(devil_mind.assigned_role == "Clown")
+ S << "Your infernal nature has allowed you to overcome your clownishness."
+ S.dna.remove_mutation(CLOWNMUT)
+
+/datum/game_mode/proc/add_devil_objectives(datum/mind/devil_mind, quantity)
+ var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target)
+ for(var/i = 1 to quantity)
+ var/type = pick(validtypes)
+ var/datum/objective/devil/objective = new type(null)
+ objective.owner = devil_mind
+ devil_mind.objectives += objective
+ if(!istype(objective, /datum/objective/devil/buy_target))
+ validtypes -= type //prevent duplicate objectives, EXCEPT for buy_target.
+ else
+ objective.find_target()
+
+/datum/mind/proc/announceDevilLaws()
+ if(!devilinfo)
+ return
+ current << "You remember your link to the infernal. You are [src.devilinfo.truename], an agent of hell, a devil. And you were sent to the plane of creation for a reason. A greater purpose. Convince the crew to sin, and embroiden Hell's grasp."
+ current << "However, your infernal form is not without weaknesses."
+ current << "You may not use violence to coerce someone into selling their soul."
+ current << "You may not directly and knowingly physically harm a devil, other than yourself."
+ current << lawlorify[LAW][src.devilinfo.bane]
+ current << lawlorify[LAW][src.devilinfo.ban]
+ current << lawlorify[LAW][src.devilinfo.obligation]
+ current << lawlorify[LAW][src.devilinfo.banish]
+ current << "
Remember, the crew can research your weaknesses if they find out your devil name.
"
+
+/datum/game_mode/proc/printdevilinfo(datum/mind/ply)
+ if(!ply.devilinfo)
+ return "Target is not a devil."
+ var/text = "The devil's true name is: [ply.devilinfo.truename]"
+ text += "The devil's bans were:"
+ text += " [lawlorify[LORE][ply.devilinfo.ban]]"
+ text += " [lawlorify[LORE][ply.devilinfo.bane]]"
+ text += " [lawlorify[LORE][ply.devilinfo.obligation]]"
+ text += " [lawlorify[LORE][ply.devilinfo.banish]]"
+ return text
+
+/datum/game_mode/proc/update_devil_icons_added(datum/mind/devil_mind)
+ var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_DEVIL]
+ hud.join_hud(devil_mind.current)
+ set_antag_hud(devil_mind.current, "devil")
+
+/datum/game_mode/proc/update_devil_icons_removed(datum/mind/devil_mind)
+ var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_DEVIL]
+ hud.leave_hud(devil_mind.current)
+ set_antag_hud(devil_mind.current, null)
+
+/datum/game_mode/proc/update_sintouch_icons_added(datum/mind/sin_mind)
+ var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_SINTOUCHED]
+ hud.join_hud(sin_mind.current)
+ set_antag_hud(sin_mind.current, "sintouched")
+
+/datum/game_mode/proc/update_sintouch_icons_removed(datum/mind/sin_mind)
+ var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_SINTOUCHED]
+ hud.leave_hud(sin_mind.current)
+ set_antag_hud(sin_mind.current, null)
+
+/datum/game_mode/proc/update_soulless_icons_added(datum/mind/soulless_mind)
+ var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_SOULLESS]
+ hud.join_hud(soulless_mind.current)
+ set_antag_hud(soulless_mind.current, "soulless")
+
+/datum/game_mode/proc/update_soulless_icons_removed(datum/mind/soulless_mind)
+ var/datum/atom_hud/antag/hud = huds[ANTAG_HUD_SOULLESS]
+ hud.leave_hud(soulless_mind.current)
+ set_antag_hud(soulless_mind.current, null)
diff --git a/code/game/gamemodes/devil/objectives.dm b/code/game/gamemodes/devil/objectives.dm
index 0a9d7083e92..bd4d3091273 100644
--- a/code/game/gamemodes/devil/objectives.dm
+++ b/code/game/gamemodes/devil/objectives.dm
@@ -3,29 +3,33 @@
/datum/objective/devil/soulquantity
explanation_text = "You shouldn't see this text. Error:DEVIL1"
- var/quantity = 4
+ target_amount = 4
/datum/objective/devil/soulquantity/New()
- quantity = pick(6,8)
- explanation_text = "Purchase, and retain control over at least [quantity] souls."
+ target_amount = pick(6,7,8)
+ update_explanation_text()
+
+/datum/objective/devil/soulquantity/update_explanation_text()
+ explanation_text = "Purchase, and retain control over at least [target_amount] souls."
/datum/objective/devil/soulquantity/check_completion()
var/count = 0
for(var/S in owner.devilinfo.soulsOwned)
var/datum/mind/L = S
- if(L.soulOwner != L)
+ if(L.soulOwner == owner)
count++
- return count >= quantity
+ return count >= target_amount
+
+
/datum/objective/devil/soulquality
explanation_text = "You shouldn't see this text. Error:DEVIL2"
var/contractType
- var/quantity
+ var/contractName
/datum/objective/devil/soulquality/New()
contractType = pick(CONTRACT_POWER, CONTRACT_WEALTH, CONTRACT_PRESTIGE, CONTRACT_MAGIC, CONTRACT_REVIVE, CONTRACT_KNOWLEDGE/*, CONTRACT_UNWILLING*/)
- var/contractName
- quantity = pick(1,2)
+ target_amount = pick(1,2)
switch(contractType)
if(CONTRACT_POWER)
contractName = "for power"
@@ -41,7 +45,10 @@
contractName = "for knowledge"
//if(CONTRACT_UNWILLING) //Makes round unfun.
// contractName = "against their will"
- explanation_text = "Have mortals sign at least [quantity] contracts [contractName]"
+ update_explanation_text()
+
+/datum/objective/devil/soulquality/update_explanation_text()
+ explanation_text = "Have mortals sign at least [target_amount] contracts [contractName]"
/datum/objective/devil/soulquality/check_completion()
var/count = 0
@@ -49,14 +56,52 @@
var/datum/mind/L = S
if(L.soulOwner != L && L.damnation_type == contractType)
count++
- return count>=quantity
+ return count>=target_amount
+
+
/datum/objective/devil/sintouch
- var/quantity
+ explanation_text = "You shouldn't see this text. Error:DEVIL3"
/datum/objective/devil/sintouch/New()
- quantity = pick(4,5)
- explanation_text = "Ensure at least [quantity] mortals are sintouched."
+ target_amount = pick(4,5)
+ explanation_text = "Ensure at least [target_amount] mortals are sintouched."
/datum/objective/devil/sintouch/check_completion()
- return quantity>=ticker.mode.sintouched.len
\ No newline at end of file
+ return target_amount>=ticker.mode.sintouched.len
+
+
+
+/datum/objective/devil/buy_target
+ explanation_text = "You shouldn't see this text. Error:DEVIL4"
+
+/datum/objective/devil/buy_target/update_explanation_text()
+ if(target)
+ explanation_text = "Purchase and retain the soul of [target.name], the [target.assigned_role]."
+ else
+ explanation_text = "Free objective."
+
+/datum/objective/devil/buy_target/check_completion()
+ return target.soulOwner == owner
+
+
+/datum/objective/devil/outsell
+ explanation_text = "You shouldn't see this text. Error:DEVIL5"
+
+/datum/objective/devil/outsell/New()
+
+/datum/objective/devil/outsell/update_explanation_text()
+ explanation_text = "Purchase and retain control over more souls than [target.devilinfo.truename], known to mortals as [target.name], the [target.assigned_role]."
+
+/datum/objective/devil/outsell/check_completion()
+ var/selfcount = 0
+ for(var/S in owner.devilinfo.soulsOwned)
+ var/datum/mind/L = S
+ if(L.soulOwner == owner)
+ selfcount++
+ var/targetcount = 0
+ for(var/S in target.devilinfo.soulsOwned)
+ var/datum/mind/L = S
+ if(L.soulOwner == target)
+ targetcount++
+ return selfcount > targetcount
diff --git a/code/game/gamemodes/devil/true_devil/_true_devil.dm b/code/game/gamemodes/devil/true_devil/_true_devil.dm
index 474024a4231..a99c95801d1 100644
--- a/code/game/gamemodes/devil/true_devil/_true_devil.dm
+++ b/code/game/gamemodes/devil/true_devil/_true_devil.dm
@@ -12,7 +12,7 @@
health = 350
maxHealth = 350
ventcrawler = 0
- density = 0
+ density = 1
pass_flags = 0
var/ascended = 0
sight = (SEE_TURFS | SEE_OBJS)
@@ -45,6 +45,7 @@
/mob/living/carbon/true_devil/Login()
..()
mind.announceDevilLaws()
+ mind.announce_objectives()
/mob/living/carbon/true_devil/death(gibbed)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 90e04375553..844fcd3a1c6 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -703,7 +703,7 @@ var/global/BSACooldown = 0
if(!ai_number)
usr << "No AIs located" //Just so you know the thing is actually working and not just ignoring you.
-/datum/admins/proc/output_devil_info()
+/datum/admins/proc/output_all_devil_info()
var/devil_number = 0
for(var/D in ticker.mode.devils)
devil_number++
@@ -711,6 +711,12 @@ var/global/BSACooldown = 0
if(!devil_number)
usr << "No Devils located" //Just so you know the thing is actually working and not just ignoring you.
+/datum/admins/proc/output_devil_info(mob/living/M)
+ if(istype(M) && M.mind && M.mind.devilinfo)
+ usr << ticker.mode.printdevilinfo(M.mind)
+ else
+ usr << "[M] is not a devil."
+
/datum/admins/proc/manage_free_slots()
if(!check_rights())
return
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 5526308de7b..618c5303b6f 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1621,7 +1621,8 @@
output_ai_laws()
else if(href_list["admincheckdevilinfo"])
- output_devil_info()
+ var/mob/M = locate(href_list["admincheckdevilinfo"])
+ output_devil_info(M)
else if(href_list["adminmoreinfo"])
var/mob/M = locate(href_list["adminmoreinfo"])
diff --git a/code/modules/events/devil.dm b/code/modules/events/devil.dm
index 21fad5037da..4f683a8f6f2 100644
--- a/code/modules/events/devil.dm
+++ b/code/modules/events/devil.dm
@@ -33,7 +33,9 @@
var/mob/living/carbon/human/devil = create_event_devil(spawn_loc)
Mind.transfer_to(devil)
ticker.mode.finalize_devil(Mind)
+ ticker.mode.add_devil_objectives(src, 2)
Mind.announceDevilLaws()
+ Mind.announce_objectives()
spawned_mobs += devil
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index ab5600cfa12..eb4e7d9c45d 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1062,12 +1062,7 @@
O = new /datum/objective/sintouched/pride
ticker.mode.sintouched += src.mind
src.mind.objectives += O
- var/obj_count = 1
- src << "Your current objectives:"
- for(O in src.mind.objectives)
- var/datum/objective/objective = O
- src << "Objective #[obj_count]: [objective.explanation_text]"
- obj_count++
+ src.mind.announce_objectives()
/mob/living/carbon/human/check_weakness(obj/item/weapon, mob/living/attacker)
. = ..()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index be826e0fd91..a7036f009e5 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1036,7 +1036,10 @@ Sorry Giacom. Please don't be mad :(
return 1
/mob/living/proc/return_soul()
+ hellbound = 0
if(mind)
+ if(mind.soulOwner.devilinfo)//Not sure how this could happen, but whatever.
+ mind.soulOwner.devilinfo.remove_soul(mind)
mind.soulOwner = mind
/mob/living/proc/has_bane(banetype)
diff --git a/code/modules/paperwork/contract.dm b/code/modules/paperwork/contract.dm
index 9974737affd..5817b793899 100644
--- a/code/modules/paperwork/contract.dm
+++ b/code/modules/paperwork/contract.dm
@@ -3,7 +3,7 @@
/obj/item/weapon/paper/contract
throw_range = 3
throw_speed = 3
- var/signed = 0
+ var/signed = FALSE
var/datum/mind/target
flags = NOBLUDGEON
@@ -107,7 +107,7 @@
..()
/obj/item/weapon/paper/contract/infernal/update_text()
- info = "This shouldn't be seen. Error DEVIL:5"
+ info = "This shouldn't be seen. Error DEVIL:6"
/obj/item/weapon/paper/contract/infernal/power/update_text(var/signature = "____________")
info = "Contract for infernal power
I, [target] of sound mind, do hereby willingly offer my soul to the infernal hells by way of the infernal agent [owner.devilinfo.truename], in exchange for power and physical strength. I understand that upon my demise, my soul shall fall into the infernal hells, and my body may not be resurrected, cloned, or otherwise brought back to life. I also understand that this will prevent my brain from being used in an MMI.
Signed, [signature]"
@@ -143,25 +143,28 @@
/obj/item/weapon/paper/contract/infernal/attack(mob/M, mob/living/user)
add_fingerprint(user)
- if(M == user && target == M.mind && M.mind.soulOwner == M.mind && attempt_signature(user))
+ if(M == user && target == M.mind && M.mind.soulOwner != owner && attempt_signature(user))
user.visible_message("[user] slices their wrist with [src], and scrawls their name in blood.", "You slice your wrist open and scrawl your name in blood.")
user.blood_volume = max(user.blood_volume - 10, 0)
else
return ..()
/obj/item/weapon/paper/contract/infernal/proc/attempt_signature(mob/living/carbon/human/user)
- if(user.IsAdvancedToolUser())
+ if(user.IsAdvancedToolUser() && user.is_literate())
if(user.mind == target)
- if(user.mind.soulOwner == user.mind)
+ if(user.mind.soulOwner != owner)
if (contractType == CONTRACT_REVIVE)
user << "You are already alive, this contract would do nothing."
else
- user << "You quickly scrawl your name on the contract"
- if(FulfillContract()<=0)
- user << "But it seemed to have no effect, perhaps even Hell itself cannot grant this boon?"
- return 1
+ if(signed)
+ user<< "This contract has already been signed. It may not be signed again."
+ else
+ user << "You quickly scrawl your name on the contract"
+ if(FulfillContract()<=0)
+ user << "But it seemed to have no effect, perhaps even Hell itself cannot grant this boon?"
+ return 1
else
- user << "You are not in possession of your soul, you may not sell it."
+ user << "This devil already owns your soul, you may not sell it to them again."
else
user << "Your signature simply slides off the sheet, it seems this contract is not meant for you to sign."
else
@@ -196,6 +199,8 @@
/obj/item/weapon/paper/contract/infernal/proc/FulfillContract(mob/living/carbon/human/user = target.current)
signed = 1
+ if(user.mind.soulOwner != user.mind) //They already sold their soul to someone else?
+ user.mind.soulOwner.devilinfo.remove_soul(user.mind) //Then they lose their claim.
user.mind.soulOwner = owner
user.hellbound = contractType
user.mind.damnation_type = contractType
diff --git a/code/modules/spells/spell_types/devil.dm b/code/modules/spells/spell_types/devil.dm
index 87e1d2fcd24..04792d84b6c 100644
--- a/code/modules/spells/spell_types/devil.dm
+++ b/code/modules/spells/spell_types/devil.dm
@@ -108,12 +108,17 @@
if(istype(user))
if(istype(user.loc, /obj/effect/dummy/slaughter/))
var/continuing = 0
- for(var/mob/living/C in orange(2, get_turf(user.loc)))
- if (C.mind && C.mind.soulOwner == C.mind)
- continuing = 1
- break
+ if(istype(get_area(user), /area/shuttle/)) // Can always phase in in a shuttle.
+ continuing = 1
+ else
+ for(var/mob/living/C in orange(2, get_turf(user.loc))) //Can also phase in when nearby a potential buyer.
+ if (C.mind && C.mind.soulOwner == C.mind)
+ continuing = 1
+ break
if(continuing)
- addtimer(user,"infernalphasein",150,TRUE)
+ user << "You are now phasing in."
+ if(do_mob(user,user,150))
+ user.infernalphasein()
else
user << "You can only re-appear near a potential signer."
revert_cast()
@@ -122,21 +127,22 @@
user.notransform = 1
user.fakefire()
src << "You begin to phase back into sinful flames."
- addtimer(user, "infernalphaseout",150,TRUE,get_turf(user))
+ if(do_mob(user,user,150))
+ user.infernalphaseout()
+ else
+ user << "You must remain still while exiting."
+ user.ExtinguishMob()
start_recharge()
return
revert_cast()
-/mob/living/proc/infernalphaseout(var/turf/mobloc)
- if(get_turf(src) != mobloc)
- src << "You must remain still while exiting."
- return
+/mob/living/proc/infernalphaseout()
dust_animation()
spawn_dust()
src.visible_message("[src] disappears in a flashfire!")
playsound(get_turf(src), 'sound/magic/enter_blood.ogg', 100, 1, -1)
- var/obj/effect/dummy/slaughter/holder = PoolOrNew(/obj/effect/dummy/slaughter,mobloc)
+ var/obj/effect/dummy/slaughter/holder = PoolOrNew(/obj/effect/dummy/slaughter,loc)
src.ExtinguishMob()
if(buckled)
buckled.unbuckle_mob(src,force=1)
diff --git a/config/game_options.txt b/config/game_options.txt
index 696eb46c1f8..798460b4c1b 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -96,6 +96,8 @@ PROBABILITY RAGINMAGES 2
PROBABILITY MONKEY 0
PROBABILITY METEOR 0
PROBABILITY EXTENDED 0
+PROBABILITY DEVIL 0
+PROBABILITY DEVIL_AGENTS 0
## You probably want to keep sandbox off by default for secret and random.
PROBABILITY SANDBOX 0
diff --git a/tgstation.dme b/tgstation.dme
index b9f4e975f30..dc0efcc497d 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -343,7 +343,9 @@
#include "code\game\gamemodes\devil\devil.dm"
#include "code\game\gamemodes\devil\devil_game_mode.dm"
#include "code\game\gamemodes\devil\devilinfo.dm"
+#include "code\game\gamemodes\devil\game_mode.dm"
#include "code\game\gamemodes\devil\objectives.dm"
+#include "code\game\gamemodes\devil\devil agent\devil_agent.dm"
#include "code\game\gamemodes\devil\imp\imp.dm"
#include "code\game\gamemodes\devil\true_devil\_true_devil.dm"
#include "code\game\gamemodes\devil\true_devil\inventory.dm"