From ec2f666f29e53269987f0b4ab6c758c0be103d72 Mon Sep 17 00:00:00 2001 From: lordpidey Date: Sun, 31 Jul 2016 01:02:21 -0400 Subject: [PATCH] Devil agent (#19391) add: Added Devil agent gamemode, where multiple devils are each trying to buy more souls than the next in line. add: If you've already sold your soul, you can sell it again to a different devil. You can even go back and forth for INFINITE POWER. This adds a new gamemode. Devil Agent. It works much like Double Agent, except devils instead of traitors, and instead of killing, the devil simply has to control more souls than the enemy. Also, whether this is included in the rotation depends on the config settings. By default, it will be disabled. --- code/datums/mind.dm | 2 + .../devil/devil agent/devil_agent.dm | 43 +++++ code/game/gamemodes/devil/devil_game_mode.dm | 166 ++++++------------ code/game/gamemodes/devil/devilinfo.dm | 22 +-- code/game/gamemodes/devil/game_mode.dm | 111 ++++++++++++ code/game/gamemodes/devil/objectives.dm | 73 ++++++-- .../gamemodes/devil/true_devil/_true_devil.dm | 3 +- code/modules/admin/admin.dm | 8 +- code/modules/admin/topic.dm | 3 +- code/modules/events/devil.dm | 2 + code/modules/mob/living/carbon/human/human.dm | 7 +- code/modules/mob/living/living.dm | 3 + code/modules/paperwork/contract.dm | 25 +-- code/modules/spells/spell_types/devil.dm | 28 +-- config/game_options.txt | 2 + tgstation.dme | 2 + 16 files changed, 338 insertions(+), 162 deletions(-) create mode 100644 code/game/gamemodes/devil/devil agent/devil_agent.dm create mode 100644 code/game/gamemodes/devil/game_mode.dm 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"