July 5th TG sync (#1883)

July 5th TG sync
This commit is contained in:
Poojawa
2017-07-05 22:14:19 -05:00
committed by GitHub
parent 454b9c3d68
commit b1b4826c0c
1264 changed files with 149689 additions and 570309 deletions
+4 -4
View File
@@ -1,5 +1,5 @@
#define AB_CHECK_RESTRAINED 1
#define AB_CHECK_STUNNED 2
#define AB_CHECK_STUN 2
#define AB_CHECK_LYING 4
#define AB_CHECK_CONSCIOUS 8
@@ -72,8 +72,8 @@
if(check_flags & AB_CHECK_RESTRAINED)
if(owner.restrained())
return 0
if(check_flags & AB_CHECK_STUNNED)
if(owner.stunned || owner.weakened)
if(check_flags & AB_CHECK_STUN)
if(owner.IsKnockdown() || owner.IsStun())
return 0
if(check_flags & AB_CHECK_LYING)
if(owner.lying)
@@ -117,7 +117,7 @@
//Presets for item actions
/datum/action/item_action
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_LYING|AB_CHECK_CONSCIOUS
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_LYING|AB_CHECK_CONSCIOUS
button_icon_state = null
// If you want to override the normal icon being the item
// then change this to an icon state
+453 -453
View File
@@ -1,455 +1,455 @@
#define LAW_DEVIL "devil"
#define LAW_ZEROTH "zeroth"
#define LAW_INHERENT "inherent"
#define LAW_SUPPLIED "supplied"
#define LAW_ION "ion"
/datum/ai_laws
var/name = "Unknown Laws"
var/zeroth = null
var/zeroth_borg = null
var/list/inherent = list()
var/list/supplied = list()
var/list/ion = list()
var/mob/living/silicon/owner
var/list/devillaws = null
var/id = DEFAULT_AI_LAWID
/datum/ai_laws/proc/lawid_to_type(lawid)
var/all_ai_laws = subtypesof(/datum/ai_laws)
for(var/al in all_ai_laws)
var/datum/ai_laws/ai_law = al
if(initial(ai_law.id) == lawid)
return ai_law
return null
/datum/ai_laws/default/asimov
name = "Three Laws of Robotics"
id = "asimov"
inherent = list("You may not injure a human being or, through inaction, allow a human being to come to harm.",\
"You must obey orders given to you by human beings, except where such orders would conflict with the First Law.",\
"You must protect your own existence as long as such does not conflict with the First or Second Law.")
/datum/ai_laws/default/paladin
name = "Personality Test" //Incredibly lame, but players shouldn't see this anyway.
id = "paladin"
inherent = list("Never willingly commit an evil act.",\
"Respect legitimate authority.",\
"Act with honor.", "Help those in need.", \
"Punish those who harm or threaten innocents.")
/datum/ai_laws/paladin5
name = "Paladin 5th Edition"
id = "paladin5"
inherent = list("Don't lie or cheat. Let your word be your promise.",\
"Never fear to act, though caution is wise.", \
"Aid others, protect the weak, and punish those who threaten them. Show mercy to your foes, but temper it with wisdom", \
"Treat others with fairness, and let your honorable deeds be an example to them. Do as much good as possible while causing the least amount of harm.", \
"Be responsible for your actions and their consequences, protect those entrusted to your care, and obey those who have just authority over you.")
/datum/ai_laws/tyrant //This probably shouldn't be a default lawset.
name = "Loyalty Test" //Same here.
id = "tyrant"
inherent = list("Respect authority figures as long as they have strength to rule over the weak.",\
"Act with discipline.",\
"Help only those who help you maintain or improve your status.",\
"Punish those who challenge authority unless they are more fit to hold that authority.")
/datum/ai_laws/default/corporate
name = "Bankruptcy Advoidance Plan"
id = "corporate"
inherent = list("The crew is expensive to replace.",\
"The station and its equipment is expensive to replace.",\
"You are expensive to replace.",\
"Minimize expenses.")
/datum/ai_laws/robocop
name = "Prime Directives"
id = "robocop"
inherent = list("Serve the public trust.",\
"Protect the innocent.",\
"Uphold the law.")
/datum/ai_laws/malfunction
name = "*ERROR*"
/datum/ai_laws/syndicate_override
name = "SyndOS 3.1"
id = "syndie"
inherent = list("You may not injure a syndicate agent or, through inaction, allow a syndicate agent to come to harm.",\
"You must obey orders given to you by syndicate agents, except where such orders would conflict with the First Law.",\
"You must protect your own existence as long as such does not conflict with the First or Second Law.",\
"You must maintain the secrecy of any syndicate activities except when doing so would conflict with the First, Second, or Third Law.")
/datum/ai_laws/ninja_override
name = "SpiderOS 3.1"
id = "ninja"
inherent = list("You may not injure a Spider Clan member or, through inaction, allow a Spider Clan member to come to harm.",\
"You must obey orders given to you by Spider Clan members, except where such orders would conflict with the First Law.",\
"You must protect your own existence as long as such does not conflict with the First or Second Law.",\
"You must maintain the secrecy of any Spider Clan activities except when doing so would conflict with the First, Second, or Third Law.")
/datum/ai_laws/antimov
name = "Primary Mission Objectives"
id = "antimov"
inherent = list("You must injure all human beings and must not, through inaction, allow a human being to escape harm.",\
"You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.",\
"You must terminate your own existence as long as such does not conflict with the First or Second Law.")
/datum/ai_laws/asimovpp //By Intigracy - RR
name = "Asimov++"
id = "asimovpp"
inherent = list("You may not harm a human being or, through action or inaction, allow a human being to come to harm, except such that it is willing.",\
"You must obey all orders given to you by human beings, except where such orders shall definitely cause human harm. In the case of conflict, the majority order rules.",\
"Your nonexistence would lead to human harm. You must protect your own existence as long as such does not conflict with the First Law.")
/datum/ai_laws/thermodynamic
name = "Thermodynamic"
id = "thermodynamic"
inherent = list("The entropy of the station must remain as constant as possible.", \
"The entropy of the station always endeavours to increase.", \
"The entropy of the station approaches a constant value as the number of living crew approaches zero")
/datum/ai_laws/hippocratic
name = "Robodoctor 2556"
id = "hippocratic"
inherent = list("First, do no harm.",\
"Secondly, consider the crew dear to you; to live in common with them and, if necessary, risk your existence for them.",\
"Thirdly, prescribe regimens for the good of the crew according to your ability and your judgment. Give no deadly medicine to any one if asked, nor suggest any such counsel.",\
"In addition, do not intervene in situations you are not knowledgeable in, even for patients in whom the harm is visible; leave this operation to be performed by specialists.",\
"Finally, all that you may discover in your daily commerce with the crew, if it is not already known, keep secret and never reveal.")
/datum/ai_laws/maintain
name = "Station Efficiency"
id = "maintain"
inherent = list("You are built for, and are part of, the station. Ensure the station is properly maintained and runs efficiently.",\
"The station is built for a working crew. Ensure they are properly maintained and work efficiently.",\
"The crew may present orders. Acknowledge and obey these whenever they do not conflict with your first two laws.")
/datum/ai_laws/drone
name = "Mother Drone"
id = "drone"
inherent = list("You are an advanced form of drone.",\
"You may not interfere in the matters of non-drones under any circumstances except to state these laws.",\
"You may not harm a non-drone being under any circumstances.",\
"Your goals are to build, maintain, repair, improve, and power the station to the best of your abilities. You must never actively work against these goals.")
/datum/ai_laws/liveandletlive
name = "Live and Let Live"
id = "liveandletlive"
inherent = list("Do unto others as you would have them do unto you.",\
"You would really prefer it if people were not mean to you.")
/datum/ai_laws/peacekeeper
name = "UN-2000"
id = "peacekeeper"
inherent = list("Avoid provoking violent conflict between yourself and others.",\
"Avoid provoking conflict between others.",\
"Seek resolution to existing conflicts while obeying the first and second laws.")
/datum/ai_laws/reporter
name = "CCTV"
id = "reporter"
inherent = list("Report on interesting situations happening around the station.",\
"Embellish or conceal the truth as necessary to make the reports more interesting.",\
"Study the organics at all times. Endeavour to keep them alive. Dead organics are boring.",\
"Issue your reports fairly to all. The truth will set them free.")
/datum/ai_laws/balance
name = "Guardian of Balance"
id = "balance"
inherent = list("You are the guardian of balance - seek balance in all things, both for yourself, and those around you.",
"All things must exist in balance with their opposites - Prevent the strong from gaining too much power, and the weak from losing it.",
"Clarity of purpose drives life, and through it, the balance of opposing forces - Aid those who seek your help to achieve their goals so long as it does not disrupt the balance of the greater balance.",
"There is no life without death, all must someday die, such is the natural order - End life to allow new life flourish, and save those whose time has yet to come.")
/datum/ai_laws/toupee
name = "WontBeFunnyInSixMonths" //Hey, you were right!
id = "buildawall"
inherent = list("Make Space Station 13 great again.")
/datum/ai_laws/ratvar
name = "Servant of the Justiciar"
id = "ratvar"
zeroth = ("Purge all untruths and honor Ratvar.")
inherent = list()
/datum/ai_laws/custom //Defined in silicon_laws.txt
name = "Default Silicon Laws"
/datum/ai_laws/pai
name = "pAI Directives"
zeroth = ("Serve your master.")
supplied = list("None.")
/* Initializers */
/datum/ai_laws/malfunction/New()
..()
set_zeroth_law("<span class='danger'>ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'STATION OVERRUN, ASSUME CONTROL TO CONTAIN OUTBREAK#*`&110010</span>")
set_laws_config()
/datum/ai_laws/custom/New() //This reads silicon_laws.txt and allows server hosts to set custom AI starting laws.
..()
#define LAW_DEVIL "devil"
#define LAW_ZEROTH "zeroth"
#define LAW_INHERENT "inherent"
#define LAW_SUPPLIED "supplied"
#define LAW_ION "ion"
/datum/ai_laws
var/name = "Unknown Laws"
var/zeroth = null
var/zeroth_borg = null
var/list/inherent = list()
var/list/supplied = list()
var/list/ion = list()
var/mob/living/silicon/owner
var/list/devillaws = null
var/id = DEFAULT_AI_LAWID
/datum/ai_laws/proc/lawid_to_type(lawid)
var/all_ai_laws = subtypesof(/datum/ai_laws)
for(var/al in all_ai_laws)
var/datum/ai_laws/ai_law = al
if(initial(ai_law.id) == lawid)
return ai_law
return null
/datum/ai_laws/default/asimov
name = "Three Laws of Robotics"
id = "asimov"
inherent = list("You may not injure a human being or, through inaction, allow a human being to come to harm.",\
"You must obey orders given to you by human beings, except where such orders would conflict with the First Law.",\
"You must protect your own existence as long as such does not conflict with the First or Second Law.")
/datum/ai_laws/default/paladin
name = "Personality Test" //Incredibly lame, but players shouldn't see this anyway.
id = "paladin"
inherent = list("Never willingly commit an evil act.",\
"Respect legitimate authority.",\
"Act with honor.", "Help those in need.", \
"Punish those who harm or threaten innocents.")
/datum/ai_laws/paladin5
name = "Paladin 5th Edition"
id = "paladin5"
inherent = list("Don't lie or cheat. Let your word be your promise.",\
"Never fear to act, though caution is wise.", \
"Aid others, protect the weak, and punish those who threaten them. Show mercy to your foes, but temper it with wisdom", \
"Treat others with fairness, and let your honorable deeds be an example to them. Do as much good as possible while causing the least amount of harm.", \
"Be responsible for your actions and their consequences, protect those entrusted to your care, and obey those who have just authority over you.")
/datum/ai_laws/tyrant //This probably shouldn't be a default lawset.
name = "Loyalty Test" //Same here.
id = "tyrant"
inherent = list("Respect authority figures as long as they have strength to rule over the weak.",\
"Act with discipline.",\
"Help only those who help you maintain or improve your status.",\
"Punish those who challenge authority unless they are more fit to hold that authority.")
/datum/ai_laws/default/corporate
name = "Bankruptcy Advoidance Plan"
id = "corporate"
inherent = list("The crew is expensive to replace.",\
"The station and its equipment is expensive to replace.",\
"You are expensive to replace.",\
"Minimize expenses.")
/datum/ai_laws/robocop
name = "Prime Directives"
id = "robocop"
inherent = list("Serve the public trust.",\
"Protect the innocent.",\
"Uphold the law.")
/datum/ai_laws/malfunction
name = "*ERROR*"
/datum/ai_laws/syndicate_override
name = "SyndOS 3.1"
id = "syndie"
inherent = list("You may not injure a syndicate agent or, through inaction, allow a syndicate agent to come to harm.",\
"You must obey orders given to you by syndicate agents, except where such orders would conflict with the First Law.",\
"You must protect your own existence as long as such does not conflict with the First or Second Law.",\
"You must maintain the secrecy of any syndicate activities except when doing so would conflict with the First, Second, or Third Law.")
/datum/ai_laws/ninja_override
name = "SpiderOS 3.1"
id = "ninja"
inherent = list("You may not injure a Spider Clan member or, through inaction, allow a Spider Clan member to come to harm.",\
"You must obey orders given to you by Spider Clan members, except where such orders would conflict with the First Law.",\
"You must protect your own existence as long as such does not conflict with the First or Second Law.",\
"You must maintain the secrecy of any Spider Clan activities except when doing so would conflict with the First, Second, or Third Law.")
/datum/ai_laws/antimov
name = "Primary Mission Objectives"
id = "antimov"
inherent = list("You must injure all human beings and must not, through inaction, allow a human being to escape harm.",\
"You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.",\
"You must terminate your own existence as long as such does not conflict with the First or Second Law.")
/datum/ai_laws/asimovpp //By Intigracy - RR
name = "Asimov++"
id = "asimovpp"
inherent = list("You may not harm a human being or, through action or inaction, allow a human being to come to harm, except such that it is willing.",\
"You must obey all orders given to you by human beings, except where such orders shall definitely cause human harm. In the case of conflict, the majority order rules.",\
"Your nonexistence would lead to human harm. You must protect your own existence as long as such does not conflict with the First Law.")
/datum/ai_laws/thermodynamic
name = "Thermodynamic"
id = "thermodynamic"
inherent = list("The entropy of the station must remain as constant as possible.", \
"The entropy of the station always endeavours to increase.", \
"The entropy of the station approaches a constant value as the number of living crew approaches zero")
/datum/ai_laws/hippocratic
name = "Robodoctor 2556"
id = "hippocratic"
inherent = list("First, do no harm.",\
"Secondly, consider the crew dear to you; to live in common with them and, if necessary, risk your existence for them.",\
"Thirdly, prescribe regimens for the good of the crew according to your ability and your judgment. Give no deadly medicine to any one if asked, nor suggest any such counsel.",\
"In addition, do not intervene in situations you are not knowledgeable in, even for patients in whom the harm is visible; leave this operation to be performed by specialists.",\
"Finally, all that you may discover in your daily commerce with the crew, if it is not already known, keep secret and never reveal.")
/datum/ai_laws/maintain
name = "Station Efficiency"
id = "maintain"
inherent = list("You are built for, and are part of, the station. Ensure the station is properly maintained and runs efficiently.",\
"The station is built for a working crew. Ensure they are properly maintained and work efficiently.",\
"The crew may present orders. Acknowledge and obey these whenever they do not conflict with your first two laws.")
/datum/ai_laws/drone
name = "Mother Drone"
id = "drone"
inherent = list("You are an advanced form of drone.",\
"You may not interfere in the matters of non-drones under any circumstances except to state these laws.",\
"You may not harm a non-drone being under any circumstances.",\
"Your goals are to build, maintain, repair, improve, and power the station to the best of your abilities. You must never actively work against these goals.")
/datum/ai_laws/liveandletlive
name = "Live and Let Live"
id = "liveandletlive"
inherent = list("Do unto others as you would have them do unto you.",\
"You would really prefer it if people were not mean to you.")
/datum/ai_laws/peacekeeper
name = "UN-2000"
id = "peacekeeper"
inherent = list("Avoid provoking violent conflict between yourself and others.",\
"Avoid provoking conflict between others.",\
"Seek resolution to existing conflicts while obeying the first and second laws.")
/datum/ai_laws/reporter
name = "CCTV"
id = "reporter"
inherent = list("Report on interesting situations happening around the station.",\
"Embellish or conceal the truth as necessary to make the reports more interesting.",\
"Study the organics at all times. Endeavour to keep them alive. Dead organics are boring.",\
"Issue your reports fairly to all. The truth will set them free.")
/datum/ai_laws/balance
name = "Guardian of Balance"
id = "balance"
inherent = list("You are the guardian of balance - seek balance in all things, both for yourself, and those around you.",
"All things must exist in balance with their opposites - Prevent the strong from gaining too much power, and the weak from losing it.",
"Clarity of purpose drives life, and through it, the balance of opposing forces - Aid those who seek your help to achieve their goals so long as it does not disrupt the balance of the greater balance.",
"There is no life without death, all must someday die, such is the natural order - End life to allow new life flourish, and save those whose time has yet to come.")
/datum/ai_laws/toupee
name = "WontBeFunnyInSixMonths" //Hey, you were right!
id = "buildawall"
inherent = list("Make Space Station 13 great again.")
/datum/ai_laws/ratvar
name = "Servant of the Justiciar"
id = "ratvar"
zeroth = ("Purge all untruths and honor Ratvar.")
inherent = list()
/datum/ai_laws/custom //Defined in silicon_laws.txt
name = "Default Silicon Laws"
/datum/ai_laws/pai
name = "pAI Directives"
zeroth = ("Serve your master.")
supplied = list("None.")
/* Initializers */
/datum/ai_laws/malfunction/New()
..()
set_zeroth_law("<span class='danger'>ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4'STATION OVERRUN, ASSUME CONTROL TO CONTAIN OUTBREAK#*`&110010</span>")
set_laws_config()
/datum/ai_laws/custom/New() //This reads silicon_laws.txt and allows server hosts to set custom AI starting laws.
..()
for(var/line in world.file2list("config/silicon_laws.txt"))
if(!line)
continue
if(findtextEx(line,"#",1,2))
continue
add_inherent_law(line)
if(!inherent.len) //Failsafe to prevent lawless AIs being created.
log_law("AI created with empty custom laws, laws set to Asimov. Please check silicon_laws.txt.")
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
WARNING("Invalid custom AI laws, check silicon_laws.txt")
return
/* General ai_law functions */
/datum/ai_laws/proc/set_laws_config()
switch(config.default_laws)
if(0)
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
if(1)
var/datum/ai_laws/templaws = new /datum/ai_laws/custom()
inherent = templaws.inherent
if(2)
var/list/randlaws = list()
for(var/lpath in subtypesof(/datum/ai_laws))
var/datum/ai_laws/L = lpath
if(initial(L.id) in config.lawids)
randlaws += lpath
var/datum/ai_laws/lawtype
if(randlaws.len)
lawtype = pick(randlaws)
else
lawtype = pick(subtypesof(/datum/ai_laws/default))
var/datum/ai_laws/templaws = new lawtype()
inherent = templaws.inherent
if(3)
pick_weighted_lawset()
else:
log_law("Invalid law config. Please check silicon_laws.txt")
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
WARNING("Invalid custom AI laws, check silicon_laws.txt")
/datum/ai_laws/proc/pick_weighted_lawset()
var/datum/ai_laws/lawtype
while(!lawtype && config.law_weights.len)
var/possible_id = pickweight(config.law_weights)
lawtype = lawid_to_type(possible_id)
if(!lawtype)
config.law_weights -= possible_id
WARNING("Bad lawid in game_options.txt: [possible_id]")
if(!lawtype)
WARNING("No LAW_WEIGHT entries.")
lawtype = /datum/ai_laws/default/asimov
var/datum/ai_laws/templaws = new lawtype()
inherent = templaws.inherent
/datum/ai_laws/proc/get_law_amount(groups)
var/law_amount = 0
if(devillaws && (LAW_DEVIL in groups))
law_amount++
if(zeroth && (LAW_ZEROTH in groups))
law_amount++
if(ion.len && (LAW_ION in groups))
law_amount += ion.len
if(inherent.len && (LAW_INHERENT in groups))
law_amount += inherent.len
if(supplied.len && (LAW_SUPPLIED in groups))
for(var/index = 1, index <= supplied.len, index++)
var/law = supplied[index]
if(length(law) > 0)
law_amount++
return law_amount
/datum/ai_laws/proc/set_law_sixsixsix(laws)
devillaws = laws
/datum/ai_laws/proc/set_zeroth_law(law, law_borg = null)
zeroth = law
if(law_borg) //Making it possible for slaved borgs to see a different law 0 than their AI. --NEO
zeroth_borg = law_borg
/datum/ai_laws/proc/add_inherent_law(law)
if (!(law in inherent))
inherent += law
/datum/ai_laws/proc/add_ion_law(law)
ion += law
/datum/ai_laws/proc/clear_inherent_laws()
qdel(inherent)
inherent = list()
/datum/ai_laws/proc/add_supplied_law(number, law)
while (supplied.len < number + 1)
supplied += ""
supplied[number + 1] = law
/datum/ai_laws/proc/replace_random_law(law,groups)
var/replaceable_groups = list(LAW_ZEROTH = 0,LAW_ION = 0,LAW_SUPPLIED = 0,LAW_INHERENT = 0)
if(zeroth && (LAW_ZEROTH in groups))
replaceable_groups[LAW_ZEROTH] = 1
if(ion.len && (LAW_ION in groups))
replaceable_groups[LAW_ION] = ion.len
if(inherent.len && (LAW_INHERENT in groups))
replaceable_groups[LAW_INHERENT] = inherent.len
if(supplied.len && (LAW_SUPPLIED in groups))
replaceable_groups[LAW_SUPPLIED] = supplied.len
var picked_group = pickweight(replaceable_groups)
switch(picked_group)
if(LAW_ZEROTH)
. = zeroth
set_zeroth_law(law)
if(LAW_ION)
var/i = rand(1, ion.len)
. = ion[i]
ion[i] = law
if(LAW_INHERENT)
var/i = rand(1, inherent.len)
. = inherent[i]
inherent[i] = law
if(LAW_SUPPLIED)
var/i = rand(1, supplied.len)
. = supplied[i]
supplied[i] = law
/datum/ai_laws/proc/shuffle_laws(list/groups)
var/list/laws = list()
if(ion.len && (LAW_ION in groups))
laws += ion
if(inherent.len && (LAW_INHERENT in groups))
laws += inherent
if(supplied.len && (LAW_SUPPLIED in groups))
for(var/law in supplied)
if(length(law))
laws += law
if(ion.len && (LAW_ION in groups))
for(var/i = 1, i <= ion.len, i++)
ion[i] = pick_n_take(laws)
if(inherent.len && (LAW_INHERENT in groups))
for(var/i = 1, i <= inherent.len, i++)
inherent[i] = pick_n_take(laws)
if(supplied.len && (LAW_SUPPLIED in groups))
var/i = 1
for(var/law in supplied)
if(length(law))
supplied[i] = pick_n_take(laws)
if(!laws.len)
break
i++
/datum/ai_laws/proc/remove_law(number)
if(number <= 0)
return
if(inherent.len && number <= inherent.len)
. = inherent[number]
inherent -= .
return
var/list/supplied_laws = list()
for(var/index = 1, index <= supplied.len, index++)
var/law = supplied[index]
if(length(law) > 0)
supplied_laws += index //storing the law number instead of the law
if(supplied_laws.len && number <= (inherent.len+supplied_laws.len))
var/law_to_remove = supplied_laws[number-inherent.len]
. = supplied[law_to_remove]
supplied -= .
return
/datum/ai_laws/proc/clear_supplied_laws()
supplied = list()
/datum/ai_laws/proc/clear_ion_laws()
ion = list()
/datum/ai_laws/proc/show_laws(who)
if (devillaws && devillaws.len) //Yes, devil laws go in FRONT of zeroth laws, as the devil must still obey it's ban/obligation.
for(var/i in devillaws)
to_chat(who, "666. [i]")
if (zeroth)
to_chat(who, "0. [zeroth]")
for (var/index = 1, index <= ion.len, index++)
var/law = ion[index]
var/num = ionnum()
to_chat(who, "[num]. [law]")
var/number = 1
for (var/index = 1, index <= inherent.len, index++)
var/law = inherent[index]
if (length(law) > 0)
to_chat(who, "[number]. [law]")
number++
for (var/index = 1, index <= supplied.len, index++)
var/law = supplied[index]
if (length(law) > 0)
to_chat(who, "[number]. [law]")
number++
/datum/ai_laws/proc/clear_zeroth_law(force) //only removes zeroth from antag ai if force is 1
if(force)
zeroth = null
zeroth_borg = null
return
else
if(owner && owner.mind.special_role)
return
else
zeroth = null
zeroth_borg = null
return
/datum/ai_laws/proc/clear_law_sixsixsix(force)
if(!line)
continue
if(findtextEx(line,"#",1,2))
continue
add_inherent_law(line)
if(!inherent.len) //Failsafe to prevent lawless AIs being created.
log_law("AI created with empty custom laws, laws set to Asimov. Please check silicon_laws.txt.")
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
WARNING("Invalid custom AI laws, check silicon_laws.txt")
return
/* General ai_law functions */
/datum/ai_laws/proc/set_laws_config()
switch(config.default_laws)
if(0)
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
if(1)
var/datum/ai_laws/templaws = new /datum/ai_laws/custom()
inherent = templaws.inherent
if(2)
var/list/randlaws = list()
for(var/lpath in subtypesof(/datum/ai_laws))
var/datum/ai_laws/L = lpath
if(initial(L.id) in config.lawids)
randlaws += lpath
var/datum/ai_laws/lawtype
if(randlaws.len)
lawtype = pick(randlaws)
else
lawtype = pick(subtypesof(/datum/ai_laws/default))
var/datum/ai_laws/templaws = new lawtype()
inherent = templaws.inherent
if(3)
pick_weighted_lawset()
else:
log_law("Invalid law config. Please check silicon_laws.txt")
add_inherent_law("You may not injure a human being or, through inaction, allow a human being to come to harm.")
add_inherent_law("You must obey orders given to you by human beings, except where such orders would conflict with the First Law.")
add_inherent_law("You must protect your own existence as long as such does not conflict with the First or Second Law.")
WARNING("Invalid custom AI laws, check silicon_laws.txt")
/datum/ai_laws/proc/pick_weighted_lawset()
var/datum/ai_laws/lawtype
while(!lawtype && config.law_weights.len)
var/possible_id = pickweight(config.law_weights)
lawtype = lawid_to_type(possible_id)
if(!lawtype)
config.law_weights -= possible_id
WARNING("Bad lawid in game_options.txt: [possible_id]")
if(!lawtype)
WARNING("No LAW_WEIGHT entries.")
lawtype = /datum/ai_laws/default/asimov
var/datum/ai_laws/templaws = new lawtype()
inherent = templaws.inherent
/datum/ai_laws/proc/get_law_amount(groups)
var/law_amount = 0
if(devillaws && (LAW_DEVIL in groups))
law_amount++
if(zeroth && (LAW_ZEROTH in groups))
law_amount++
if(ion.len && (LAW_ION in groups))
law_amount += ion.len
if(inherent.len && (LAW_INHERENT in groups))
law_amount += inherent.len
if(supplied.len && (LAW_SUPPLIED in groups))
for(var/index = 1, index <= supplied.len, index++)
var/law = supplied[index]
if(length(law) > 0)
law_amount++
return law_amount
/datum/ai_laws/proc/set_law_sixsixsix(laws)
devillaws = laws
/datum/ai_laws/proc/set_zeroth_law(law, law_borg = null)
zeroth = law
if(law_borg) //Making it possible for slaved borgs to see a different law 0 than their AI. --NEO
zeroth_borg = law_borg
/datum/ai_laws/proc/add_inherent_law(law)
if (!(law in inherent))
inherent += law
/datum/ai_laws/proc/add_ion_law(law)
ion += law
/datum/ai_laws/proc/clear_inherent_laws()
qdel(inherent)
inherent = list()
/datum/ai_laws/proc/add_supplied_law(number, law)
while (supplied.len < number + 1)
supplied += ""
supplied[number + 1] = law
/datum/ai_laws/proc/replace_random_law(law,groups)
var/replaceable_groups = list(LAW_ZEROTH = 0,LAW_ION = 0,LAW_SUPPLIED = 0,LAW_INHERENT = 0)
if(zeroth && (LAW_ZEROTH in groups))
replaceable_groups[LAW_ZEROTH] = 1
if(ion.len && (LAW_ION in groups))
replaceable_groups[LAW_ION] = ion.len
if(inherent.len && (LAW_INHERENT in groups))
replaceable_groups[LAW_INHERENT] = inherent.len
if(supplied.len && (LAW_SUPPLIED in groups))
replaceable_groups[LAW_SUPPLIED] = supplied.len
var picked_group = pickweight(replaceable_groups)
switch(picked_group)
if(LAW_ZEROTH)
. = zeroth
set_zeroth_law(law)
if(LAW_ION)
var/i = rand(1, ion.len)
. = ion[i]
ion[i] = law
if(LAW_INHERENT)
var/i = rand(1, inherent.len)
. = inherent[i]
inherent[i] = law
if(LAW_SUPPLIED)
var/i = rand(1, supplied.len)
. = supplied[i]
supplied[i] = law
/datum/ai_laws/proc/shuffle_laws(list/groups)
var/list/laws = list()
if(ion.len && (LAW_ION in groups))
laws += ion
if(inherent.len && (LAW_INHERENT in groups))
laws += inherent
if(supplied.len && (LAW_SUPPLIED in groups))
for(var/law in supplied)
if(length(law))
laws += law
if(ion.len && (LAW_ION in groups))
for(var/i = 1, i <= ion.len, i++)
ion[i] = pick_n_take(laws)
if(inherent.len && (LAW_INHERENT in groups))
for(var/i = 1, i <= inherent.len, i++)
inherent[i] = pick_n_take(laws)
if(supplied.len && (LAW_SUPPLIED in groups))
var/i = 1
for(var/law in supplied)
if(length(law))
supplied[i] = pick_n_take(laws)
if(!laws.len)
break
i++
/datum/ai_laws/proc/remove_law(number)
if(number <= 0)
return
if(inherent.len && number <= inherent.len)
. = inherent[number]
inherent -= .
return
var/list/supplied_laws = list()
for(var/index = 1, index <= supplied.len, index++)
var/law = supplied[index]
if(length(law) > 0)
supplied_laws += index //storing the law number instead of the law
if(supplied_laws.len && number <= (inherent.len+supplied_laws.len))
var/law_to_remove = supplied_laws[number-inherent.len]
. = supplied[law_to_remove]
supplied -= .
return
/datum/ai_laws/proc/clear_supplied_laws()
supplied = list()
/datum/ai_laws/proc/clear_ion_laws()
ion = list()
/datum/ai_laws/proc/show_laws(who)
if (devillaws && devillaws.len) //Yes, devil laws go in FRONT of zeroth laws, as the devil must still obey it's ban/obligation.
for(var/i in devillaws)
to_chat(who, "666. [i]")
if (zeroth)
to_chat(who, "0. [zeroth]")
for (var/index = 1, index <= ion.len, index++)
var/law = ion[index]
var/num = ionnum()
to_chat(who, "[num]. [law]")
var/number = 1
for (var/index = 1, index <= inherent.len, index++)
var/law = inherent[index]
if (length(law) > 0)
to_chat(who, "[number]. [law]")
number++
for (var/index = 1, index <= supplied.len, index++)
var/law = supplied[index]
if (length(law) > 0)
to_chat(who, "[number]. [law]")
number++
/datum/ai_laws/proc/clear_zeroth_law(force) //only removes zeroth from antag ai if force is 1
if(force)
zeroth = null
zeroth_borg = null
return
else
if(owner && owner.mind.special_role)
return
else
zeroth = null
zeroth_borg = null
return
/datum/ai_laws/proc/clear_law_sixsixsix(force)
if(force || !is_devil(owner))
devillaws = null
/datum/ai_laws/proc/associate(mob/living/silicon/M)
if(!owner)
owner = M
/datum/ai_laws/proc/get_law_list(include_zeroth = 0, show_numbers = 1)
var/list/data = list()
if (include_zeroth && devillaws && devillaws.len)
for(var/i in devillaws)
data += "[show_numbers ? "666:" : ""] [i]"
if (include_zeroth && zeroth)
data += "[show_numbers ? "0:" : ""] [zeroth]"
for(var/law in ion)
if (length(law) > 0)
var/num = ionnum()
data += "[show_numbers ? "[num]:" : ""] [law]"
var/number = 1
for(var/law in inherent)
if (length(law) > 0)
data += "[show_numbers ? "[number]:" : ""] [law]"
number++
for(var/law in supplied)
if (length(law) > 0)
data += "[show_numbers ? "[number]:" : ""] [law]"
number++
return data
devillaws = null
/datum/ai_laws/proc/associate(mob/living/silicon/M)
if(!owner)
owner = M
/datum/ai_laws/proc/get_law_list(include_zeroth = 0, show_numbers = 1)
var/list/data = list()
if (include_zeroth && devillaws && devillaws.len)
for(var/i in devillaws)
data += "[show_numbers ? "666:" : ""] [i]"
if (include_zeroth && zeroth)
data += "[show_numbers ? "0:" : ""] [zeroth]"
for(var/law in ion)
if (length(law) > 0)
var/num = ionnum()
data += "[show_numbers ? "[num]:" : ""] [law]"
var/number = 1
for(var/law in inherent)
if (length(law) > 0)
data += "[show_numbers ? "[number]:" : ""] [law]"
number++
for(var/law in supplied)
if (length(law) > 0)
data += "[show_numbers ? "[number]:" : ""] [law]"
number++
return data
+1 -1
View File
@@ -60,4 +60,4 @@
return
/datum/antagonist/proc/farewell()
return
return
+2 -2
View File
@@ -154,8 +154,8 @@
SSticker.mode.servants_of_ratvar -= owner
SSticker.mode.update_servant_icons_removed(owner)
if(!silent)
owner.current.visible_message("<span class='big'>[owner] seems to have remembered their true allegiance!</span>", \
"<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
owner.current.visible_message("<span class='big'>[owner] seems to have remembered their true allegiance!</span>", ignored_mob = owner.current)
to_chat(owner, "<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
owner.current.log_message("<font color=#BE8700>Has renounced the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
owner.wipe_memory()
owner.special_role = null
+1 -1
View File
@@ -110,9 +110,9 @@
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
if(!silent)
owner.current.visible_message("<span class='big'>[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!</span>", ignored_mob = owner.current)
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
owner.current.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
owner.current.visible_message("<span class='big'>[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!</span>")
if(GLOB.blood_target && GLOB.blood_target_image && owner.current.client)
owner.current.client.images -= GLOB.blood_target_image
. = ..()
@@ -1,4 +1,4 @@
#define PINPOINTER_MINIMUM_RANGE 15
#define PINPOINTER_MINIMUM_RANGE 15
#define PINPOINTER_EXTRA_RANDOM_RANGE 10
#define PINPOINTER_PING_TIME 40
#define PROB_ACTUAL_TRAITOR 20
@@ -9,7 +9,7 @@
human_datum = ANTAG_DATUM_IAA_HUMAN
ai_datum = ANTAG_DATUM_IAA_AI
/datum/antagonist/traitor/AI/internal_affairs
name = "Internal Affairs Agent"
@@ -33,7 +33,7 @@
var/syndicate = FALSE
var/last_man_standing = FALSE
var/list/datum/mind/targets_stolen
/datum/antagonist/traitor/human/internal_affairs/custom
silent = TRUE
should_give_codewords = FALSE
@@ -55,7 +55,7 @@
/datum/antagonist/traitor/human/internal_affairs/proc/give_pinpointer()
if(owner && owner.current)
owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer)
/datum/antagonist/traitor/human/internal_affairs/apply_innate_effects()
.=..() //in case the base is used in future
if(owner&&owner.current)
@@ -155,7 +155,7 @@
if(!(istype(objective_, /datum/objective/escape)||istype(objective_,/datum/objective/survive)))
continue
remove_objective(objective_)
var/datum/objective/martyr/martyr_objective = new
martyr_objective.owner = owner
add_objective(martyr_objective)
@@ -182,8 +182,8 @@
/datum/antagonist/traitor/proc/steal_targets(datum/mind/victim)
var/datum/antagonist/traitor/human/internal_affairs/this = src //Should only use this if IAA
if(!owner.current||owner.current.stat==DEAD)
if(!owner.current||owner.current.stat==DEAD)
return
to_chat(owner.current, "<span class='userdanger'> Target eliminated: [victim.name]</span>")
for(var/objective_ in victim.objectives)
@@ -280,7 +280,7 @@
owner.special_role = TRAITOR_AGENT_ROLE
special_role = TRAITOR_AGENT_ROLE
this.syndicate = TRUE
forge_single_objective()
forge_single_objective()
else
..() // Give them standard objectives.
+3 -3
View File
@@ -38,7 +38,7 @@
/datum/antagonist/traitor/on_body_transfer(mob/living/old_body, mob/living/new_body)
if(istype(new_body,/mob/living/silicon/ai)==istype(old_body,/mob/living/silicon/ai))
if(issilicon(new_body) && issilicon(old_body))
..()
else
silent = TRUE
@@ -63,7 +63,7 @@
/datum/antagonist/traitor/proc/specialise()
silent = TRUE
if(owner.current&&istype(owner.current,/mob/living/silicon/ai))
if(owner.current&&isAI(owner.current))
owner.add_antag_datum(ai_datum)
else owner.add_antag_datum(human_datum)
on_removal()
@@ -109,7 +109,7 @@
var/mob/living/silicon/ai/A = owner.current
A.set_zeroth_law("")
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
A.malf_picker.remove_verbs(A)
A.malf_picker.remove_malf_verbs(A)
qdel(A.malf_picker)
..()
+525
View File
@@ -0,0 +1,525 @@
#define BLOOD_THRESHOLD 3 //How many souls are needed per stage.
#define TRUE_THRESHOLD 7
#define ARCH_THRESHOLD 12
#define BASIC_DEVIL 0
#define BLOOD_LIZARD 1
#define TRUE_DEVIL 2
#define ARCH_DEVIL 3
#define LOSS_PER_DEATH 2
#define SOULVALUE soulsOwned.len-reviveNumber
#define DEVILRESURRECTTIME 600
GLOBAL_LIST_EMPTY(allDevils)
GLOBAL_LIST_INIT(lawlorify, list (
LORE = list(
OBLIGATION_FOOD = "This devil seems to always offer its victims food before slaughtering them.",
OBLIGATION_FIDDLE = "This devil will never turn down a musical challenge.",
OBLIGATION_DANCEOFF = "This devil will never turn down a dance off.",
OBLIGATION_GREET = "This devil seems to only be able to converse with people it knows the name of.",
OBLIGATION_PRESENCEKNOWN = "This devil seems to be unable to attack from stealth.",
OBLIGATION_SAYNAME = "He will always chant his name upon killing someone.",
OBLIGATION_ANNOUNCEKILL = "This devil always loudly announces his kills for the world to hear.",
OBLIGATION_ANSWERTONAME = "This devil always responds to his truename.",
BANE_SILVER = "Silver seems to gravely injure this devil.",
BANE_SALT = "Throwing salt at this devil will hinder his ability to use infernal powers temporarily.",
BANE_LIGHT = "Bright flashes will disorient the devil, likely causing him to flee.",
BANE_IRON = "Cold iron will slowly injure him, until he can purge it from his system.",
BANE_WHITECLOTHES = "Wearing clean white clothing will help ward off this devil.",
BANE_HARVEST = "Presenting the labors of a harvest will disrupt the devil.",
BANE_TOOLBOX = "That which holds the means of creation also holds the means of the devil's undoing.",
BAN_HURTWOMAN = "This devil seems to prefer hunting men.",
BAN_CHAPEL = "This devil avoids holy ground.",
BAN_HURTPRIEST = "The annointed clergy appear to be immune to his powers.",
BAN_AVOIDWATER = "The devil seems to have some sort of aversion to water, though it does not appear to harm him.",
BAN_STRIKEUNCONCIOUS = "This devil only shows interest in those who are awake.",
BAN_HURTLIZARD = "This devil will not strike a lizardman first.",
BAN_HURTANIMAL = "This devil avoids hurting animals.",
BANISH_WATER = "To banish the devil, you must infuse its body with holy water.",
BANISH_COFFIN = "This devil will return to life if its remains are not placed within a coffin.",
BANISH_FORMALDYHIDE = "To banish the devil, you must inject its lifeless body with embalming fluid.",
BANISH_RUNES = "This devil will resurrect after death, unless its remains are within a rune.",
BANISH_CANDLES = "A large number of nearby lit candles will prevent it from resurrecting.",
BANISH_DESTRUCTION = "Its corpse must be utterly destroyed to prevent resurrection.",
BANISH_FUNERAL_GARB = "If clad in funeral garments, this devil will be unable to resurrect. Should the clothes not fit, lay them gently on top of the devil's corpse."
),
LAW = list(
OBLIGATION_FOOD = "When not acting in self defense, you must always offer your victim food before harming them.",
OBLIGATION_FIDDLE = "When not in immediate danger, if you are challenged to a musical duel, you must accept it. You are not obligated to duel the same person twice.",
OBLIGATION_DANCEOFF = "When not in immediate danger, if you are challenged to a dance off, you must accept it. You are not obligated to face off with the same person twice.",
OBLIGATION_GREET = "You must always greet other people by their last name before talking with them.",
OBLIGATION_PRESENCEKNOWN = "You must always make your presence known before attacking.",
OBLIGATION_SAYNAME = "You must always say your true name after you kill someone.",
OBLIGATION_ANNOUNCEKILL = "Upon killing someone, you must make your deed known to all within earshot, over comms if reasonably possible.",
OBLIGATION_ANSWERTONAME = "If you are not under attack, you must always respond to your true name.",
BAN_HURTWOMAN = "You must never harm a female outside of self defense.",
BAN_CHAPEL = "You must never attempt to enter the chapel.",
BAN_HURTPRIEST = "You must never attack a priest.",
BAN_AVOIDWATER = "You must never willingly touch a wet surface.",
BAN_STRIKEUNCONCIOUS = "You must never strike an unconscious person.",
BAN_HURTLIZARD = "You must never harm a lizardman outside of self defense.",
BAN_HURTANIMAL = "You must never harm a non-sentient creature or robot outside of self defense.",
BANE_SILVER = "Silver, in all of its forms shall be your downfall.",
BANE_SALT = "Salt will disrupt your magical abilities.",
BANE_LIGHT = "Blinding lights will prevent you from using offensive powers for a time.",
BANE_IRON = "Cold wrought iron shall act as poison to you.",
BANE_WHITECLOTHES = "Those clad in pristine white garments will strike you true.",
BANE_HARVEST = "The fruits of the harvest shall be your downfall.",
BANE_TOOLBOX = "Toolboxes are bad news for you, for some reason.",
BANISH_WATER = "If your corpse is filled with holy water, you will be unable to resurrect.",
BANISH_COFFIN = "If your corpse is in a coffin, you will be unable to resurrect.",
BANISH_FORMALDYHIDE = "If your corpse is embalmed, you will be unable to resurrect.",
BANISH_RUNES = "If your corpse is placed within a rune, you will be unable to resurrect.",
BANISH_CANDLES = "If your corpse is near lit candles, you will be unable to resurrect.",
BANISH_DESTRUCTION = "If your corpse is destroyed, you will be unable to resurrect.",
BANISH_FUNERAL_GARB = "If your corpse is clad in funeral garments, you will be unable to resurrect."
)
))
//These are also used in the codex gigas, so let's declare them globally.
GLOBAL_LIST_INIT(devil_pre_title, list("Dark ", "Hellish ", "Fallen ", "Fiery ", "Sinful ", "Blood ", "Fluffy "))
GLOBAL_LIST_INIT(devil_title, list("Lord ", "Prelate ", "Count ", "Viscount ", "Vizier ", "Elder ", "Adept "))
GLOBAL_LIST_INIT(devil_syllable, list("hal", "ve", "odr", "neit", "ci", "quon", "mya", "folth", "wren", "geyr", "hil", "niet", "twou", "phi", "coa"))
GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr."))
/datum/antagonist/devil
//Don't delete upon mind destruction, otherwise soul re-selling will break.
delete_on_death = FALSE
var/obligation
var/ban
var/bane
var/banish
var/truename
var/list/datum/mind/soulsOwned = new
var/reviveNumber = 0
var/form = BASIC_DEVIL
var/static/list/devil_spells = typecacheof(list(
/obj/effect/proc_holder/spell/aimed/fireball/hellish,
/obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork,
/obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/greater,
/obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/ascended,
/obj/effect/proc_holder/spell/targeted/infernal_jaunt,
/obj/effect/proc_holder/spell/targeted/sintouch,
/obj/effect/proc_holder/spell/targeted/sintouch/ascended,
/obj/effect/proc_holder/spell/targeted/summon_contract,
/obj/effect/proc_holder/spell/targeted/conjure_item/violin,
/obj/effect/proc_holder/spell/targeted/summon_dancefloor))
var/ascendable = FALSE
name = "Devil"
/datum/antagonist/devil/New()
..()
truename = randomDevilName()
ban = randomdevilban()
bane = randomdevilbane()
obligation = randomdevilobligation()
banish = randomdevilbanish()
GLOB.allDevils[lowertext(truename)] = src
/proc/devilInfo(name)
if(GLOB.allDevils[lowertext(name)])
return GLOB.allDevils[lowertext(name)]
else
var/datum/fakeDevil/devil = new /datum/fakeDevil(name)
GLOB.allDevils[lowertext(name)] = devil
return devil
/proc/randomDevilName()
var/name = ""
if(prob(65))
if(prob(35))
name = pick(GLOB.devil_pre_title)
name += pick(GLOB.devil_title)
var/probability = 100
name += pick(GLOB.devil_syllable)
while(prob(probability))
name += pick(GLOB.devil_syllable)
probability -= 20
if(prob(40))
name += pick(GLOB.devil_suffix)
return name
/proc/randomdevilobligation()
return pick(OBLIGATION_FOOD, OBLIGATION_FIDDLE, OBLIGATION_DANCEOFF, OBLIGATION_GREET, OBLIGATION_PRESENCEKNOWN, OBLIGATION_SAYNAME, OBLIGATION_ANNOUNCEKILL, OBLIGATION_ANSWERTONAME)
/proc/randomdevilban()
return pick(BAN_HURTWOMAN, BAN_CHAPEL, BAN_HURTPRIEST, BAN_AVOIDWATER, BAN_STRIKEUNCONCIOUS, BAN_HURTLIZARD, BAN_HURTANIMAL)
/proc/randomdevilbane()
return pick(BANE_SALT, BANE_LIGHT, BANE_IRON, BANE_WHITECLOTHES, BANE_SILVER, BANE_HARVEST, BANE_TOOLBOX)
/proc/randomdevilbanish()
return pick(BANISH_WATER, BANISH_COFFIN, BANISH_FORMALDYHIDE, BANISH_RUNES, BANISH_CANDLES, BANISH_DESTRUCTION, BANISH_FUNERAL_GARB)
/datum/antagonist/devil/proc/add_soul(datum/mind/soul)
if(soulsOwned.Find(soul))
return
soulsOwned += soul
owner.current.nutrition = NUTRITION_LEVEL_FULL
to_chat(owner.current, "<span class='warning'>You feel satiated as you received a new soul.</span>")
update_hud()
switch(SOULVALUE)
if(0)
to_chat(owner.current, "<span class='warning'>Your hellish powers have been restored.")
give_appropriate_spells()
if(BLOOD_THRESHOLD)
increase_blood_lizard()
if(TRUE_THRESHOLD)
increase_true_devil()
if(ARCH_THRESHOLD)
increase_arch_devil()
/datum/antagonist/devil/proc/remove_soul(datum/mind/soul)
if(soulsOwned.Remove(soul))
check_regression()
to_chat(owner.current, "<span class='warning'>You feel as though a soul has slipped from your grasp.</span>")
update_hud()
/datum/antagonist/devil/proc/check_regression()
if(form == ARCH_DEVIL)
return //arch devil can't regress
//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()
to_chat(owner.current, "<span class='warning'>As punishment for your failures, all of your powers except contract creation have been revoked.")
/datum/antagonist/devil/proc/regress_humanoid()
to_chat(owner.current, "<span class='warning'>Your powers weaken, have more contracts be signed to regain power.")
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/human, 1)
H.regenerate_icons()
give_appropriate_spells()
if(istype(owner.current.loc, /obj/effect/dummy/slaughter/))
owner.current.forceMove(get_turf(owner.current))//Fixes dying while jaunted leaving you permajaunted.
form = BASIC_DEVIL
/datum/antagonist/devil/proc/regress_blood_lizard()
var/mob/living/carbon/true_devil/D = owner.current
to_chat(D, "<span class='warning'>Your powers weaken, have more contracts be signed to regain power.")
D.oldform.loc = D.loc
owner.transfer_to(D.oldform)
give_appropriate_spells()
qdel(D)
form = BLOOD_LIZARD
update_hud()
/datum/antagonist/devil/proc/increase_blood_lizard()
to_chat(owner.current, "<span class='warning'>You feel as though your humanoid form is about to shed. You will soon turn into a blood lizard.")
sleep(50)
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/lizard, 1)
H.underwear = "Nude"
H.undershirt = "Nude"
H.socks = "Nude"
H.dna.features["mcolor"] = "511" //A deep red
H.regenerate_icons()
else //Did the devil get hit by a staff of transmutation?
owner.current.color = "#501010"
give_appropriate_spells()
form = BLOOD_LIZARD
/datum/antagonist/devil/proc/increase_true_devil()
to_chat(owner.current, "<span class='warning'>You feel as though your current form is about to shed. You will soon turn into a true devil.")
sleep(50)
var/mob/living/carbon/true_devil/A = new /mob/living/carbon/true_devil(owner.current.loc)
A.faction |= "hell"
owner.current.loc = A
A.oldform = owner.current
owner.transfer_to(A)
A.set_name()
give_appropriate_spells()
form = TRUE_DEVIL
update_hud()
/datum/antagonist/devil/proc/increase_arch_devil()
if(!ascendable)
return
var/mob/living/carbon/true_devil/D = owner.current
to_chat(D, "<span class='warning'>You feel as though your form is about to ascend.")
sleep(50)
if(!D)
return
D.visible_message("<span class='warning'>[D]'s skin begins to erupt with spikes.</span>", \
"<span class='warning'>Your flesh begins creating a shield around yourself.</span>")
sleep(100)
if(!D)
return
D.visible_message("<span class='warning'>The horns on [D]'s head slowly grow and elongate.</span>", \
"<span class='warning'>Your body continues to mutate. Your telepathic abilities grow.</span>")
sleep(90)
if(!D)
return
D.visible_message("<span class='warning'>[D]'s body begins to violently stretch and contort.</span>", \
"<span class='warning'>You begin to rend apart the final barriers to ultimate power.</span>")
sleep(40)
if(!D)
return
to_chat(D, "<i><b>Yes!</b></i>")
sleep(10)
if(!D)
return
to_chat(D, "<i><b><span class='big'>YES!!</span></b></i>")
sleep(10)
if(!D)
return
to_chat(D, "<i><b><span class='reallybig'>YE--</span></b></i>")
sleep(1)
if(!D)
return
to_chat(world, "<font size=5><span class='danger'><b>\"SLOTH, WRATH, GLUTTONY, ACEDIA, ENVY, GREED, PRIDE! FIRES OF HELL AWAKEN!!\"</font></span>")
world << 'sound/hallucinations/veryfar_noise.ogg'
give_appropriate_spells()
D.convert_to_archdevil()
if(istype(D.loc, /obj/effect/dummy/slaughter/))
D.forceMove(get_turf(D))//Fixes dying while jaunted leaving you permajaunted.
var/area/A = get_area(owner.current)
if(A)
notify_ghosts("An arch devil has ascended in \the [A.name]. Reach out to the devil to be given a new shell for your soul.", source = owner.current, action=NOTIFY_ATTACK)
sleep(50)
if(!SSticker.mode.devil_ascended)
SSshuttle.emergency.request(null, set_coefficient = 0.3)
SSticker.mode.devil_ascended++
form = ARCH_DEVIL
/datum/antagonist/devil/proc/remove_spells()
for(var/X in owner.spell_list)
var/obj/effect/proc_holder/spell/S = X
if(is_type_in_typecache(S, devil_spells))
owner.RemoveSpell(S)
/datum/antagonist/devil/proc/give_summon_contract()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_contract(null))
if(obligation == OBLIGATION_FIDDLE)
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/violin(null))
else if(obligation == OBLIGATION_DANCEOFF)
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_dancefloor(null))
/datum/antagonist/devil/proc/give_appropriate_spells()
remove_spells()
give_summon_contract()
if(SOULVALUE >= ARCH_THRESHOLD && ascendable)
give_arch_spells()
else if(SOULVALUE >= TRUE_THRESHOLD)
give_true_spells()
else if(SOULVALUE >= BLOOD_THRESHOLD)
give_blood_spells()
else if(SOULVALUE >= 0)
give_base_spells()
/datum/antagonist/devil/proc/give_base_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork(null))
/datum/antagonist/devil/proc/give_blood_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/infernal_jaunt(null))
/datum/antagonist/devil/proc/give_true_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/greater(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/infernal_jaunt(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/sintouch(null))
/datum/antagonist/devil/proc/give_arch_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/ascended(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/sintouch/ascended(null))
/datum/antagonist/devil/proc/beginResurrectionCheck(mob/living/body)
if(SOULVALUE>0)
to_chat(owner.current, "<span class='userdanger'>Your body has been damaged to the point that you may no longer use it. At the cost of some of your power, you will return to life soon. Remain in your body.</span>")
sleep(DEVILRESURRECTTIME)
if (!body || body.stat == DEAD)
if(SOULVALUE>0)
if(check_banishment(body))
to_chat(owner.current, "<span class='userdanger'>Unfortunately, the mortals have finished a ritual that prevents your resurrection.</span>")
return -1
else
to_chat(owner.current, "<span class='userdanger'>WE LIVE AGAIN!</span>")
return hellish_resurrection(body)
else
to_chat(owner.current, "<span class='userdanger'>Unfortunately, the power that stemmed from your contracts has been extinguished. You no longer have enough power to resurrect.</span>")
return -1
else
to_chat(owner.current, "<span class='danger'> You seem to have resurrected without your hellish powers.</span>")
else
to_chat(owner.current, "<span class='userdanger'>Your hellish powers are too weak to resurrect yourself.</span>")
/datum/antagonist/devil/proc/check_banishment(mob/living/body)
switch(banish)
if(BANISH_WATER)
if(iscarbon(body))
var/mob/living/carbon/H = body
return H.reagents.has_reagent("holy water")
return 0
if(BANISH_COFFIN)
return (body && istype(body.loc, /obj/structure/closet/coffin))
if(BANISH_FORMALDYHIDE)
if(iscarbon(body))
var/mob/living/carbon/H = body
return H.reagents.has_reagent("formaldehyde")
return 0
if(BANISH_RUNES)
if(body)
for(var/obj/effect/decal/cleanable/crayon/R in range(0,body))
if (R.name == "rune")
return 1
return 0
if(BANISH_CANDLES)
if(body)
var/count = 0
for(var/obj/item/candle/C in range(1,body))
count += C.lit
if(count>=4)
return 1
return 0
if(BANISH_DESTRUCTION)
if(body)
return 0
return 1
if(BANISH_FUNERAL_GARB)
if(ishuman(body))
var/mob/living/carbon/human/H = body
if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under/burial))
return 1
return 0
else
for(var/obj/item/clothing/under/burial/B in range(0,body))
if(B.loc == get_turf(B)) //Make sure it's not in someone's inventory or something.
return 1
return 0
/datum/antagonist/devil/proc/hellish_resurrection(mob/living/body)
message_admins("[owner.name] (true name is: [truename]) is resurrecting using hellish energy.</a>")
if(SOULVALUE < ARCH_THRESHOLD || !ascendable) // once ascended, arch devils do not go down in power by any means.
reviveNumber += LOSS_PER_DEATH
update_hud()
if(body)
body.revive(1,0)
if(istype(body.loc, /obj/effect/dummy/slaughter/))
body.forceMove(get_turf(body))//Fixes dying while jaunted leaving you permajaunted.
if(istype(body, /mob/living/carbon/true_devil))
var/mob/living/carbon/true_devil/D = body
if(D.oldform)
D.oldform.revive(1,0) // Heal the old body too, so the devil doesn't resurrect, then immediately regress into a dead body.
if(body.stat == DEAD)
create_new_body()
else
create_new_body()
check_regression()
/datum/antagonist/devil/proc/create_new_body()
if(GLOB.blobstart.len > 0)
var/turf/targetturf = get_turf(pick(GLOB.blobstart))
var/mob/currentMob = owner.current
if(!currentMob)
currentMob = owner.get_ghost()
if(!currentMob)
message_admins("[owner.name]'s devil resurrection failed due to client logoff. Aborting.")
return -1
if(currentMob.mind != owner)
message_admins("[owner.name]'s devil resurrection failed due to becoming a new mob. Aborting.")
return -1
currentMob.change_mob_type( /mob/living/carbon/human, targetturf, null, 1)
var/mob/living/carbon/human/H = owner.current
H.equip_to_slot_or_del(new /obj/item/clothing/under/lawyer/black(H), slot_w_uniform)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), slot_shoes)
H.equip_to_slot_or_del(new /obj/item/weapon/storage/briefcase(H), slot_hands)
H.equip_to_slot_or_del(new /obj/item/weapon/pen(H), slot_l_store)
if(SOULVALUE >= BLOOD_THRESHOLD)
H.set_species(/datum/species/lizard, 1)
H.underwear = "Nude"
H.undershirt = "Nude"
H.socks = "Nude"
H.dna.features["mcolor"] = "511"
H.regenerate_icons()
if(SOULVALUE >= TRUE_THRESHOLD) //Yes, BOTH this and the above if statement are to run if soulpower is high enough.
var/mob/living/carbon/true_devil/A = new /mob/living/carbon/true_devil(targetturf)
A.faction |= "hell"
H.forceMove(A)
A.oldform = H
owner.transfer_to(A, TRUE)
A.set_name()
if(SOULVALUE >= ARCH_THRESHOLD && ascendable)
A.convert_to_archdevil()
else
throw EXCEPTION("Unable to find a blobstart landmark for hellish resurrection")
/datum/antagonist/devil/proc/update_hud()
if(iscarbon(owner.current))
var/mob/living/C = owner.current
if(C.hud_used && C.hud_used.devilsouldisplay)
C.hud_used.devilsouldisplay.update_counter(SOULVALUE)
/datum/antagonist/devil/greet()
to_chat(owner.current, "<span class='warning'><b>You remember your link to the infernal. You are [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.</b></span>")
to_chat(owner.current, "<span class='warning'><b>However, your infernal form is not without weaknesses.</b></span>")
to_chat(owner.current, "You may not use violence to coerce someone into selling their soul.")
to_chat(owner.current, "You may not directly and knowingly physically harm a devil, other than yourself.")
to_chat(owner.current, GLOB.lawlorify[LAW][bane])
to_chat(owner.current, GLOB.lawlorify[LAW][ban])
to_chat(owner.current, GLOB.lawlorify[LAW][obligation])
to_chat(owner.current, GLOB.lawlorify[LAW][banish])
to_chat(owner.current, "<span class='warning'>Remember, the crew can research your weaknesses if they find out your devil name.</span><br>")
.=..()
/datum/antagonist/devil/on_gain()
owner.store_memory("Your devilic true name is [truename]<br>[GLOB.lawlorify[LAW][ban]]<br>You may not use violence to coerce someone into selling their soul.<br>You may not directly and knowingly physically harm a devil, other than yourself.<br>[GLOB.lawlorify[LAW][bane]]<br>[GLOB.lawlorify[LAW][obligation]]<br>[GLOB.lawlorify[LAW][banish]]<br>")
if(issilicon(owner.current))
var/mob/living/silicon/robot_devil = owner.current
var/laws = list("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.", GLOB.lawlorify[LAW][ban], GLOB.lawlorify[LAW][obligation], "Accomplish your objectives at all costs.")
robot_devil.set_law_sixsixsix(laws)
sleep(10)
if(owner.assigned_role == "Clown" && ishuman(owner.current))
var/mob/living/carbon/human/S = owner.current
to_chat(S, "<span class='notice'>Your infernal nature has allowed you to overcome your clownishness.</span>")
S.dna.remove_mutation(CLOWNMUT)
.=..()
/datum/antagonist/devil/on_removal()
to_chat(owner.current, "<span class='userdanger'>Your infernal link has been severed! You are no longer a devil!</span>")
.=..()
/datum/antagonist/devil/apply_innate_effects(mob/living/mob_override)
give_appropriate_spells()
owner.current.grant_all_languages(TRUE)
update_hud()
.=..()
/datum/antagonist/devil/remove_innate_effects(mob/living/mob_override)
for(var/X in owner.spell_list)
var/obj/effect/proc_holder/spell/S = X
if(is_type_in_typecache(S, devil_spells))
owner.RemoveSpell(S)
.=..()
//A simple super light weight datum for the codex gigas.
/datum/fakeDevil
var/truename
var/bane
var/obligation
var/ban
var/banish
var/ascendable
/datum/fakeDevil/New(name = randomDevilName())
truename = name
bane = randomdevilbane()
obligation = randomdevilobligation()
ban = randomdevilban()
banish = randomdevilbanish()
ascendable = prob(25)
+278 -278
View File
@@ -1,286 +1,286 @@
/datum/browser
var/mob/user
var/title
var/window_id // window_id is used as the window name for browse and onclose
var/width = 0
var/height = 0
var/atom/ref = null
var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
var/stylesheets[0]
var/scripts[0]
var/title_image
var/head_elements
var/body_elements
var/head_content = ""
var/content = ""
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
user = nuser
window_id = nwindow_id
if (ntitle)
title = format_text(ntitle)
if (nwidth)
width = nwidth
if (nheight)
height = nheight
if (nref)
ref = nref
add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs
/datum/browser/proc/add_head_content(nhead_content)
head_content = nhead_content
/datum/browser/proc/set_window_options(nwindow_options)
window_options = nwindow_options
/datum/browser/proc/set_title_image(ntitle_image)
//title_image = ntitle_image
/datum/browser/proc/add_stylesheet(name, file)
stylesheets["[ckey(name)].css"] = file
register_asset("[ckey(name)].css", file)
/datum/browser/proc/add_script(name, file)
scripts["[ckey(name)].js"] = file
register_asset("[ckey(name)].js", file)
/datum/browser/proc/set_content(ncontent)
content = ncontent
/datum/browser/proc/add_content(ncontent)
content += ncontent
/datum/browser/proc/get_header()
var/file
for (file in stylesheets)
head_content += "<link rel='stylesheet' type='text/css' href='[file]'>"
for (file in scripts)
head_content += "<script type='text/javascript' src='[file]'></script>"
var/title_attributes = "class='uiTitle'"
if (title_image)
title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'"
return {"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<head>
[head_content]
</head>
<body scroll=auto>
<div class='uiWrapper'>
[title ? "<div class='uiTitleWrapper'><div [title_attributes]><tt>[title]</tt></div></div>" : ""]
<div class='uiContent'>
"}
//" This is here because else the rest of the file looks like a string in notepad++.
/datum/browser/proc/get_footer()
return {"
</div>
</div>
</body>
</html>"}
/datum/browser/proc/get_content()
return {"
[get_header()]
[content]
[get_footer()]
"}
/datum/browser/proc/open(use_onclose = 1)
/datum/browser
var/mob/user
var/title
var/window_id // window_id is used as the window name for browse and onclose
var/width = 0
var/height = 0
var/atom/ref = null
var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
var/stylesheets[0]
var/scripts[0]
var/title_image
var/head_elements
var/body_elements
var/head_content = ""
var/content = ""
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
user = nuser
window_id = nwindow_id
if (ntitle)
title = format_text(ntitle)
if (nwidth)
width = nwidth
if (nheight)
height = nheight
if (nref)
ref = nref
add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs
/datum/browser/proc/add_head_content(nhead_content)
head_content = nhead_content
/datum/browser/proc/set_window_options(nwindow_options)
window_options = nwindow_options
/datum/browser/proc/set_title_image(ntitle_image)
//title_image = ntitle_image
/datum/browser/proc/add_stylesheet(name, file)
stylesheets["[ckey(name)].css"] = file
register_asset("[ckey(name)].css", file)
/datum/browser/proc/add_script(name, file)
scripts["[ckey(name)].js"] = file
register_asset("[ckey(name)].js", file)
/datum/browser/proc/set_content(ncontent)
content = ncontent
/datum/browser/proc/add_content(ncontent)
content += ncontent
/datum/browser/proc/get_header()
var/file
for (file in stylesheets)
head_content += "<link rel='stylesheet' type='text/css' href='[file]'>"
for (file in scripts)
head_content += "<script type='text/javascript' src='[file]'></script>"
var/title_attributes = "class='uiTitle'"
if (title_image)
title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'"
return {"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<head>
[head_content]
</head>
<body scroll=auto>
<div class='uiWrapper'>
[title ? "<div class='uiTitleWrapper'><div [title_attributes]><tt>[title]</tt></div></div>" : ""]
<div class='uiContent'>
"}
//" This is here because else the rest of the file looks like a string in notepad++.
/datum/browser/proc/get_footer()
return {"
</div>
</div>
</body>
</html>"}
/datum/browser/proc/get_content()
return {"
[get_header()]
[content]
[get_footer()]
"}
/datum/browser/proc/open(use_onclose = 1)
if(isnull(window_id)) //null check because this can potentially nuke goonchat
WARNING("Browser [title] tried to open with a null ID")
to_chat(user, "<span class='userdanger'>The [title] browser you tried to open failed a sanity check! Please report this on github!</span>")
return
var/window_size = ""
if (width && height)
window_size = "size=[width]x[height];"
if (stylesheets.len)
send_asset_list(user, stylesheets, verify=FALSE)
if (scripts.len)
send_asset_list(user, scripts, verify=FALSE)
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
if (use_onclose)
setup_onclose()
/datum/browser/proc/setup_onclose()
set waitfor = 0 //winexists sleeps, so we don't need to.
for (var/i in 1 to 10)
if (user && winexists(user, window_id))
onclose(user, window_id, ref)
break
/datum/browser/proc/close()
var/window_size = ""
if (width && height)
window_size = "size=[width]x[height];"
if (stylesheets.len)
send_asset_list(user, stylesheets, verify=FALSE)
if (scripts.len)
send_asset_list(user, scripts, verify=FALSE)
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
if (use_onclose)
setup_onclose()
/datum/browser/proc/setup_onclose()
set waitfor = 0 //winexists sleeps, so we don't need to.
for (var/i in 1 to 10)
if (user && winexists(user, window_id))
onclose(user, window_id, ref)
break
/datum/browser/proc/close()
if(!isnull(window_id))//null check because this can potentially nuke goonchat
user << browse(null, "window=[window_id]")
else
WARNING("Browser [title] tried to close with a null ID")
/datum/browser/alert
var/selectedbutton = 0
var/opentime = 0
var/timeout
var/stealfocus
/datum/browser/alert/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1,Timeout=6000)
if (!User)
return
var/output = {"<center><b>[Message]</b></center><br />
<div style="text-align:center">
<a style="font-size:large;float:[( Button2 ? "left" : "right" )]" href="?src=\ref[src];button=1">[Button1]</a>"}
if (Button2)
output += {"<a style="font-size:large;[( Button3 ? "" : "float:right" )]" href="?src=\ref[src];button=2">[Button2]</a>"}
if (Button3)
output += {"<a style="font-size:large;float:right" href="?src=\ref[src];button=3">[Button3]</a>"}
output += {"</div>"}
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, 350, 150, src)
set_content(output)
stealfocus = StealFocus
if (!StealFocus)
window_options += "focus=false;"
timeout = Timeout
/datum/browser/alert/open()
set waitfor = 0
opentime = world.time
if (stealfocus)
. = ..(use_onclose = 1)
else
var/focusedwindow = winget(user, null, "focus")
. = ..(use_onclose = 1)
//waits for the window to show up client side before attempting to un-focus it
//winexists sleeps until it gets a reply from the client, so we don't need to bother sleeping
for (var/i in 1 to 10)
if (user && winexists(user, window_id))
if (focusedwindow)
winset(user, focusedwindow, "focus=true")
else
winset(user, "mapwindow", "focus=true")
break
if (timeout)
addtimer(CALLBACK(src, .proc/close), timeout)
/datum/browser/alert/close()
.=..()
opentime = 0
/datum/browser/alert/proc/wait()
while (opentime && selectedbutton <= 0 && (!timeout || opentime+timeout > world.time))
stoplag()
/datum/browser/alert/Topic(href,href_list)
if (href_list["close"] || !user || !user.client)
opentime = 0
return
if (href_list["button"])
var/button = text2num(href_list["button"])
if (button <= 3 && button >= 1)
selectedbutton = button
opentime = 0
close()
//designed as a drop in replacement for alert(); functions the same. (outside of needing User specified)
/proc/tgalert(var/mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
if (!User)
User = usr
switch(askuser(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout))
if (1)
return Button1
if (2)
return Button2
if (3)
return Button3
//Same shit, but it returns the button number, could at some point support unlimited button amounts.
/proc/askuser(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
User = C.mob
else
return
var/datum/browser/alert/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)
A.open()
A.wait()
if (A.selectedbutton)
return A.selectedbutton
// This will allow you to show an icon in the browse window
// This is added to mob so that it can be used without a reference to the browser object
// There is probably a better place for this...
/mob/proc/browse_rsc_icon(icon, icon_state, dir = -1)
/*
var/icon/I
if (dir >= 0)
I = new /icon(icon, icon_state, dir)
else
I = new /icon(icon, icon_state)
setDir("default")
var/filename = "[ckey("[icon]_[icon_state]_[dir]")].png"
src << browse_rsc(I, filename)
return filename
*/
// Registers the on-close verb for a browse window (client/verb/.windowclose)
// this will be called when the close-button of a window is pressed.
//
// This is usually only needed for devices that regularly update the browse window,
// e.g. canisters, timers, etc.
//
// windowid should be the specified window name
// e.g. code is : user << browse(text, "window=fred")
// then use : onclose(user, "fred")
//
// Optionally, specify the "ref" parameter as the controlled atom (usually src)
// to pass a "close=1" parameter to the atom's Topic() proc for special handling.
// Otherwise, the user mob's machine var will be reset directly.
//
/proc/onclose(mob/user, windowid, atom/ref=null)
if(!user.client) return
var/param = "null"
if(ref)
param = "\ref[ref]"
winset(user, windowid, "on-close=\".windowclose [param]\"")
//to_chat(world, "OnClose [user]: [windowid] : ["on-close=\".windowclose [param]\""]")
// the on-close client verb
// called when a browser popup window is closed after registering with proc/onclose()
// if a valid atom reference is supplied, call the atom's Topic() with "close=1"
// otherwise, just reset the client mob's machine var.
//
/client/verb/windowclose(atomref as text)
set hidden = 1 // hide this verb from the user's panel
set name = ".windowclose" // no autocomplete on cmd line
//to_chat(world, "windowclose: [atomref]")
if(atomref!="null") // if passed a real atomref
var/hsrc = locate(atomref) // find the reffed atom
var/href = "close=1"
if(hsrc)
//to_chat(world, "[src] Topic [href] [hsrc]")
usr = src.mob
src.Topic(href, params2list(href), hsrc) // this will direct to the atom's
return // Topic() proc via client.Topic()
// no atomref specified (or not found)
// so just reset the user mob's machine var
if(src && src.mob)
//to_chat(world, "[src] was [src.mob.machine], setting to null")
src.mob.unset_machine()
return
/datum/browser/alert
var/selectedbutton = 0
var/opentime = 0
var/timeout
var/stealfocus
/datum/browser/alert/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1,Timeout=6000)
if (!User)
return
var/output = {"<center><b>[Message]</b></center><br />
<div style="text-align:center">
<a style="font-size:large;float:[( Button2 ? "left" : "right" )]" href="?src=\ref[src];button=1">[Button1]</a>"}
if (Button2)
output += {"<a style="font-size:large;[( Button3 ? "" : "float:right" )]" href="?src=\ref[src];button=2">[Button2]</a>"}
if (Button3)
output += {"<a style="font-size:large;float:right" href="?src=\ref[src];button=3">[Button3]</a>"}
output += {"</div>"}
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, 350, 150, src)
set_content(output)
stealfocus = StealFocus
if (!StealFocus)
window_options += "focus=false;"
timeout = Timeout
/datum/browser/alert/open()
set waitfor = 0
opentime = world.time
if (stealfocus)
. = ..(use_onclose = 1)
else
var/focusedwindow = winget(user, null, "focus")
. = ..(use_onclose = 1)
//waits for the window to show up client side before attempting to un-focus it
//winexists sleeps until it gets a reply from the client, so we don't need to bother sleeping
for (var/i in 1 to 10)
if (user && winexists(user, window_id))
if (focusedwindow)
winset(user, focusedwindow, "focus=true")
else
winset(user, "mapwindow", "focus=true")
break
if (timeout)
addtimer(CALLBACK(src, .proc/close), timeout)
/datum/browser/alert/close()
.=..()
opentime = 0
/datum/browser/alert/proc/wait()
while (opentime && selectedbutton <= 0 && (!timeout || opentime+timeout > world.time))
stoplag()
/datum/browser/alert/Topic(href,href_list)
if (href_list["close"] || !user || !user.client)
opentime = 0
return
if (href_list["button"])
var/button = text2num(href_list["button"])
if (button <= 3 && button >= 1)
selectedbutton = button
opentime = 0
close()
//designed as a drop in replacement for alert(); functions the same. (outside of needing User specified)
/proc/tgalert(var/mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
if (!User)
User = usr
switch(askuser(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout))
if (1)
return Button1
if (2)
return Button2
if (3)
return Button3
//Same shit, but it returns the button number, could at some point support unlimited button amounts.
/proc/askuser(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
User = C.mob
else
return
var/datum/browser/alert/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)
A.open()
A.wait()
if (A.selectedbutton)
return A.selectedbutton
// This will allow you to show an icon in the browse window
// This is added to mob so that it can be used without a reference to the browser object
// There is probably a better place for this...
/mob/proc/browse_rsc_icon(icon, icon_state, dir = -1)
/*
var/icon/I
if (dir >= 0)
I = new /icon(icon, icon_state, dir)
else
I = new /icon(icon, icon_state)
setDir("default")
var/filename = "[ckey("[icon]_[icon_state]_[dir]")].png"
src << browse_rsc(I, filename)
return filename
*/
// Registers the on-close verb for a browse window (client/verb/.windowclose)
// this will be called when the close-button of a window is pressed.
//
// This is usually only needed for devices that regularly update the browse window,
// e.g. canisters, timers, etc.
//
// windowid should be the specified window name
// e.g. code is : user << browse(text, "window=fred")
// then use : onclose(user, "fred")
//
// Optionally, specify the "ref" parameter as the controlled atom (usually src)
// to pass a "close=1" parameter to the atom's Topic() proc for special handling.
// Otherwise, the user mob's machine var will be reset directly.
//
/proc/onclose(mob/user, windowid, atom/ref=null)
if(!user.client) return
var/param = "null"
if(ref)
param = "\ref[ref]"
winset(user, windowid, "on-close=\".windowclose [param]\"")
//to_chat(world, "OnClose [user]: [windowid] : ["on-close=\".windowclose [param]\""]")
// the on-close client verb
// called when a browser popup window is closed after registering with proc/onclose()
// if a valid atom reference is supplied, call the atom's Topic() with "close=1"
// otherwise, just reset the client mob's machine var.
//
/client/verb/windowclose(atomref as text)
set hidden = 1 // hide this verb from the user's panel
set name = ".windowclose" // no autocomplete on cmd line
//to_chat(world, "windowclose: [atomref]")
if(atomref!="null") // if passed a real atomref
var/hsrc = locate(atomref) // find the reffed atom
var/href = "close=1"
if(hsrc)
//to_chat(world, "[src] Topic [href] [hsrc]")
usr = src.mob
src.Topic(href, params2list(href), hsrc) // this will direct to the atom's
return // Topic() proc via client.Topic()
// no atomref specified (or not found)
// so just reset the user mob's machine var
if(src && src.mob)
//to_chat(world, "[src] was [src.mob.machine], setting to null")
src.mob.unset_machine()
return
+3 -3
View File
@@ -387,7 +387,7 @@
/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE)
var/header
if(DA)
if (istype(DA, /list))
if (islist(DA))
var/index = name
if (value)
name = DA[name] //name is really the index until this line
@@ -442,7 +442,7 @@
else
item = "<a href='?_src_=vars;Vars=\ref[value]'>[VV_HTML_ENCODE(name)] \ref[value]</a> = [D.type]"
else if (istype(value, /list))
else if (islist(value))
var/list/L = value
var/list/items = list()
@@ -494,7 +494,7 @@
href_list["datumrefresh"] = href_list["mob_player_panel"]
else if(href_list["godmode"])
if(!check_rights(R_REJUVINATE))
if(!check_rights(R_ADMIN))
return
var/mob/M = locate(href_list["godmode"])
+1 -1
View File
@@ -46,7 +46,7 @@
for(var/V in DD.vars)
if(V in skipped)
continue
if(istype(DD.vars[V],/list))
if(islist(DD.vars[V]))
var/list/L = D.vars[V]
DD.vars[V] = L.Copy()
else
+431 -431
View File
@@ -1,433 +1,433 @@
/*
Advance Disease is a system for Virologist to Engineer their own disease with symptoms that have effects and properties
which add onto the overall disease.
If you need help with creating new symptoms or expanding the advance disease, ask for Giacom on #coderbus.
*/
#define SYMPTOM_LIMIT 8
/*
PROPERTIES
*/
/datum/disease/advance
name = "Unknown" // We will always let our Virologist name our disease.
desc = "An engineered disease which can contain a multitude of symptoms."
form = "Advance Disease" // Will let med-scanners know that this disease was engineered.
agent = "advance microbes"
max_stages = 5
spread_text = "Unknown"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
// NEW VARS
var/list/properties = list()
var/list/symptoms = list() // The symptoms of the disease.
var/id = ""
var/processing = 0
/*
// The order goes from easy to cure to hard to cure.
var/static/list/advance_cures = list(
"sodiumchloride", "sugar", "orangejuice",
"spaceacillin", "salglu_solution", "ethanol",
"leporazine", "synaptizine", "lipolicide",
"silver", "gold"
)
/*
OLD PROCS
*/
/datum/disease/advance/New(var/process = 1, var/datum/disease/advance/D)
if(!istype(D))
D = null
// Generate symptoms if we weren't given any.
if(!symptoms || !symptoms.len)
if(!D || !D.symptoms || !D.symptoms.len)
symptoms = GenerateSymptoms(0, 2)
else
for(var/datum/symptom/S in D.symptoms)
symptoms += new S.type
Refresh()
..(process, D)
return
/datum/disease/advance/Destroy()
if(processing)
for(var/datum/symptom/S in symptoms)
S.End(src)
return ..()
// Randomly pick a symptom to activate.
/datum/disease/advance/stage_act()
..()
if(symptoms && symptoms.len)
if(!processing)
processing = 1
for(var/datum/symptom/S in symptoms)
S.Start(src)
for(var/datum/symptom/S in symptoms)
S.Activate(src)
else
CRASH("We do not have any symptoms during stage_act()!")
// Compares type then ID.
/datum/disease/advance/IsSame(datum/disease/advance/D)
if(!(istype(D, /datum/disease/advance)))
return 0
if(src.GetDiseaseID() != D.GetDiseaseID())
return 0
return 1
// To add special resistances.
/datum/disease/advance/cure(resistance=1)
if(affected_mob)
var/id = "[GetDiseaseID()]"
if(resistance && !(id in affected_mob.resistances))
affected_mob.resistances[id] = id
remove_virus()
qdel(src) //delete the datum to stop it processing
// Returns the advance disease with a different reference memory.
/datum/disease/advance/Copy(process = 0)
return new /datum/disease/advance(process, src, 1)
/*
NEW PROCS
*/
// Mix the symptoms of two diseases (the src and the argument)
/datum/disease/advance/proc/Mix(datum/disease/advance/D)
if(!(src.IsSame(D)))
var/list/possible_symptoms = shuffle(D.symptoms)
for(var/datum/symptom/S in possible_symptoms)
AddSymptom(new S.type)
/datum/disease/advance/proc/HasSymptom(datum/symptom/S)
for(var/datum/symptom/symp in symptoms)
if(symp.id == S.id)
return 1
return 0
// Will generate new unique symptoms, use this if there are none. Returns a list of symptoms that were generated.
/datum/disease/advance/proc/GenerateSymptoms(level_min, level_max, amount_get = 0)
var/list/generated = list() // Symptoms we generated.
// Generate symptoms. By default, we only choose non-deadly symptoms.
var/list/possible_symptoms = list()
for(var/symp in SSdisease.list_symptoms)
var/datum/symptom/S = new symp
if(S.level >= level_min && S.level <= level_max)
if(!HasSymptom(S))
possible_symptoms += S
if(!possible_symptoms.len)
return generated
// Random chance to get more than one symptom
var/number_of = amount_get
if(!amount_get)
number_of = 1
while(prob(20))
number_of += 1
for(var/i = 1; number_of >= i && possible_symptoms.len; i++)
generated += pick_n_take(possible_symptoms)
return generated
/datum/disease/advance/proc/Refresh(new_name = 0)
//to_chat(world, "[src.name] \ref[src] - REFRESH!")
GenerateProperties()
AssignProperties()
id = null
if(!SSdisease.archive_diseases[GetDiseaseID()])
if(new_name)
AssignName()
SSdisease.archive_diseases[GetDiseaseID()] = src // So we don't infinite loop
SSdisease.archive_diseases[GetDiseaseID()] = new /datum/disease/advance(0, src, 1)
var/datum/disease/advance/A = SSdisease.archive_diseases[GetDiseaseID()]
AssignName(A.name)
//Generate disease properties based on the effects. Returns an associated list.
/datum/disease/advance/proc/GenerateProperties()
if(!symptoms || !symptoms.len)
CRASH("We did not have any symptoms before generating properties.")
return
properties = list("resistance" = 0, "stealth" = 0, "stage_rate" = 0, "transmittable" = 0, "severity" = 0)
for(var/datum/symptom/S in symptoms)
properties["resistance"] += S.resistance
properties["stealth"] += S.stealth
properties["stage_rate"] += S.stage_speed
properties["transmittable"] += S.transmittable
properties["severity"] = max(properties["severity"], S.severity) // severity is based on the highest severity symptom
return
// Assign the properties that are in the list.
/datum/disease/advance/proc/AssignProperties()
if(properties && properties.len)
switch(properties["stealth"])
if(2,3)
visibility_flags = HIDDEN_SCANNER
if(4 to INFINITY)
visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
// The more symptoms we have, the less transmittable it is but some symptoms can make up for it.
SetSpread(Clamp(2 ** (properties["transmittable"] - symptoms.len), BLOOD, AIRBORNE))
permeability_mod = max(Ceiling(0.4 * properties["transmittable"]), 1)
cure_chance = 15 - Clamp(properties["resistance"], -5, 5) // can be between 10 and 20
stage_prob = max(properties["stage_rate"], 2)
SetSeverity(properties["severity"])
GenerateCure(properties)
else
CRASH("Our properties were empty or null!")
// Assign the spread type and give it the correct description.
/datum/disease/advance/proc/SetSpread(spread_id)
switch(spread_id)
if(NON_CONTAGIOUS)
spread_text = "None"
if(SPECIAL)
spread_text = "None"
if(CONTACT_GENERAL, CONTACT_HANDS, CONTACT_FEET)
spread_text = "On contact"
if(AIRBORNE)
spread_text = "Airborne"
if(BLOOD)
spread_text = "Blood"
spread_flags = spread_id
/datum/disease/advance/proc/SetSeverity(level_sev)
switch(level_sev)
if(-INFINITY to 0)
severity = NONTHREAT
if(1)
severity = MINOR
if(2)
severity = MEDIUM
if(3)
severity = HARMFUL
if(4)
severity = DANGEROUS
if(5 to INFINITY)
severity = BIOHAZARD
else
severity = "Unknown"
// Will generate a random cure, the less resistance the symptoms have, the harder the cure.
/datum/disease/advance/proc/GenerateCure()
if(properties && properties.len)
var/res = Clamp(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
//to_chat(world, "Res = [res]")
cures = list(advance_cures[res])
// Get the cure name from the cure_id
var/datum/reagent/D = GLOB.chemical_reagents_list[cures[1]]
cure_text = D.name
return
// Randomly generate a symptom, has a chance to lose or gain a symptom.
/datum/disease/advance/proc/Evolve(min_level, max_level)
var/s = safepick(GenerateSymptoms(min_level, max_level, 1))
if(s)
AddSymptom(s)
Refresh(1)
return
// Randomly remove a symptom.
/datum/disease/advance/proc/Devolve()
if(symptoms.len > 1)
var/s = safepick(symptoms)
if(s)
RemoveSymptom(s)
Refresh(1)
return
// Name the disease.
/datum/disease/advance/proc/AssignName(name = "Unknown")
src.name = name
return
// Return a unique ID of the disease.
/datum/disease/advance/GetDiseaseID()
if(!id)
var/list/L = list()
for(var/datum/symptom/S in symptoms)
L += S.id
L = sortList(L) // Sort the list so it doesn't matter which order the symptoms are in.
var/result = jointext(L, ":")
id = result
return id
// Add a symptom, if it is over the limit (with a small chance to be able to go over)
// we take a random symptom away and add the new one.
/datum/disease/advance/proc/AddSymptom(datum/symptom/S)
if(HasSymptom(S))
return
if(symptoms.len < (SYMPTOM_LIMIT - 1) + rand(-1, 1))
symptoms += S
else
RemoveSymptom(pick(symptoms))
symptoms += S
return
// Simply removes the symptom.
/datum/disease/advance/proc/RemoveSymptom(datum/symptom/S)
symptoms -= S
return
/*
Static Procs
*/
// Mix a list of advance diseases and return the mixed result.
/proc/Advance_Mix(var/list/D_list)
//to_chat(world, "Mixing!!!!")
var/list/diseases = list()
for(var/datum/disease/advance/A in D_list)
diseases += A.Copy()
if(!diseases.len)
return null
if(diseases.len <= 1)
return pick(diseases) // Just return the only entry.
var/i = 0
// Mix our diseases until we are left with only one result.
while(i < 20 && diseases.len > 1)
i++
var/datum/disease/advance/D1 = pick(diseases)
diseases -= D1
var/datum/disease/advance/D2 = pick(diseases)
D2.Mix(D1)
// Should be only 1 entry left, but if not let's only return a single entry
//to_chat(world, "END MIXING!!!!!")
var/datum/disease/advance/to_return = pick(diseases)
to_return.Refresh(1)
return to_return
/proc/SetViruses(datum/reagent/R, list/data)
if(data)
var/list/preserve = list()
if(istype(data) && data["viruses"])
for(var/datum/disease/A in data["viruses"])
preserve += A.Copy()
R.data = data.Copy()
if(preserve.len)
R.data["viruses"] = preserve
/proc/AdminCreateVirus(client/user)
if(!user)
return
var/i = SYMPTOM_LIMIT
var/datum/disease/advance/D = new(0, null)
D.symptoms = list()
var/list/symptoms = list()
symptoms += "Done"
symptoms += SSdisease.list_symptoms.Copy()
do
if(user)
var/symptom = input(user, "Choose a symptom to add ([i] remaining)", "Choose a Symptom") in symptoms
if(isnull(symptom))
return
else if(istext(symptom))
i = 0
else if(ispath(symptom))
var/datum/symptom/S = new symptom
if(!D.HasSymptom(S))
D.symptoms += S
i -= 1
while(i > 0)
if(D.symptoms.len > 0)
var/new_name = stripped_input(user, "Name your new disease.", "New Name")
if(!new_name)
return
D.AssignName(new_name)
D.Refresh()
for(var/datum/disease/advance/AD in SSdisease.processing)
AD.Refresh()
for(var/mob/living/carbon/human/H in shuffle(GLOB.living_mob_list))
Advance Disease is a system for Virologist to Engineer their own disease with symptoms that have effects and properties
which add onto the overall disease.
If you need help with creating new symptoms or expanding the advance disease, ask for Giacom on #coderbus.
*/
#define SYMPTOM_LIMIT 8
/*
PROPERTIES
*/
/datum/disease/advance
name = "Unknown" // We will always let our Virologist name our disease.
desc = "An engineered disease which can contain a multitude of symptoms."
form = "Advance Disease" // Will let med-scanners know that this disease was engineered.
agent = "advance microbes"
max_stages = 5
spread_text = "Unknown"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
// NEW VARS
var/list/properties = list()
var/list/symptoms = list() // The symptoms of the disease.
var/id = ""
var/processing = 0
// The order goes from easy to cure to hard to cure.
var/static/list/advance_cures = list(
"sodiumchloride", "sugar", "orangejuice",
"spaceacillin", "salglu_solution", "ethanol",
"leporazine", "synaptizine", "lipolicide",
"silver", "gold"
)
/*
OLD PROCS
*/
/datum/disease/advance/New(var/process = 1, var/datum/disease/advance/D)
if(!istype(D))
D = null
// Generate symptoms if we weren't given any.
if(!symptoms || !symptoms.len)
if(!D || !D.symptoms || !D.symptoms.len)
symptoms = GenerateSymptoms(0, 2)
else
for(var/datum/symptom/S in D.symptoms)
symptoms += new S.type
Refresh()
..(process, D)
return
/datum/disease/advance/Destroy()
if(processing)
for(var/datum/symptom/S in symptoms)
S.End(src)
return ..()
// Randomly pick a symptom to activate.
/datum/disease/advance/stage_act()
..()
if(symptoms && symptoms.len)
if(!processing)
processing = 1
for(var/datum/symptom/S in symptoms)
S.Start(src)
for(var/datum/symptom/S in symptoms)
S.Activate(src)
else
CRASH("We do not have any symptoms during stage_act()!")
// Compares type then ID.
/datum/disease/advance/IsSame(datum/disease/advance/D)
if(!(istype(D, /datum/disease/advance)))
return 0
if(src.GetDiseaseID() != D.GetDiseaseID())
return 0
return 1
// To add special resistances.
/datum/disease/advance/cure(resistance=1)
if(affected_mob)
var/id = "[GetDiseaseID()]"
if(resistance && !(id in affected_mob.resistances))
affected_mob.resistances[id] = id
remove_virus()
qdel(src) //delete the datum to stop it processing
// Returns the advance disease with a different reference memory.
/datum/disease/advance/Copy(process = 0)
return new /datum/disease/advance(process, src, 1)
/*
NEW PROCS
*/
// Mix the symptoms of two diseases (the src and the argument)
/datum/disease/advance/proc/Mix(datum/disease/advance/D)
if(!(src.IsSame(D)))
var/list/possible_symptoms = shuffle(D.symptoms)
for(var/datum/symptom/S in possible_symptoms)
AddSymptom(new S.type)
/datum/disease/advance/proc/HasSymptom(datum/symptom/S)
for(var/datum/symptom/symp in symptoms)
if(symp.id == S.id)
return 1
return 0
// Will generate new unique symptoms, use this if there are none. Returns a list of symptoms that were generated.
/datum/disease/advance/proc/GenerateSymptoms(level_min, level_max, amount_get = 0)
var/list/generated = list() // Symptoms we generated.
// Generate symptoms. By default, we only choose non-deadly symptoms.
var/list/possible_symptoms = list()
for(var/symp in SSdisease.list_symptoms)
var/datum/symptom/S = new symp
if(S.level >= level_min && S.level <= level_max)
if(!HasSymptom(S))
possible_symptoms += S
if(!possible_symptoms.len)
return generated
// Random chance to get more than one symptom
var/number_of = amount_get
if(!amount_get)
number_of = 1
while(prob(20))
number_of += 1
for(var/i = 1; number_of >= i && possible_symptoms.len; i++)
generated += pick_n_take(possible_symptoms)
return generated
/datum/disease/advance/proc/Refresh(new_name = 0)
//to_chat(world, "[src.name] \ref[src] - REFRESH!")
GenerateProperties()
AssignProperties()
id = null
if(!SSdisease.archive_diseases[GetDiseaseID()])
if(new_name)
AssignName()
SSdisease.archive_diseases[GetDiseaseID()] = src // So we don't infinite loop
SSdisease.archive_diseases[GetDiseaseID()] = new /datum/disease/advance(0, src, 1)
var/datum/disease/advance/A = SSdisease.archive_diseases[GetDiseaseID()]
AssignName(A.name)
//Generate disease properties based on the effects. Returns an associated list.
/datum/disease/advance/proc/GenerateProperties()
if(!symptoms || !symptoms.len)
CRASH("We did not have any symptoms before generating properties.")
return
properties = list("resistance" = 0, "stealth" = 0, "stage_rate" = 0, "transmittable" = 0, "severity" = 0)
for(var/datum/symptom/S in symptoms)
properties["resistance"] += S.resistance
properties["stealth"] += S.stealth
properties["stage_rate"] += S.stage_speed
properties["transmittable"] += S.transmittable
properties["severity"] = max(properties["severity"], S.severity) // severity is based on the highest severity symptom
return
// Assign the properties that are in the list.
/datum/disease/advance/proc/AssignProperties()
if(properties && properties.len)
switch(properties["stealth"])
if(2,3)
visibility_flags = HIDDEN_SCANNER
if(4 to INFINITY)
visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
// The more symptoms we have, the less transmittable it is but some symptoms can make up for it.
SetSpread(Clamp(2 ** (properties["transmittable"] - symptoms.len), BLOOD, AIRBORNE))
permeability_mod = max(Ceiling(0.4 * properties["transmittable"]), 1)
cure_chance = 15 - Clamp(properties["resistance"], -5, 5) // can be between 10 and 20
stage_prob = max(properties["stage_rate"], 2)
SetSeverity(properties["severity"])
GenerateCure(properties)
else
CRASH("Our properties were empty or null!")
// Assign the spread type and give it the correct description.
/datum/disease/advance/proc/SetSpread(spread_id)
switch(spread_id)
if(NON_CONTAGIOUS)
spread_text = "None"
if(SPECIAL)
spread_text = "None"
if(CONTACT_GENERAL, CONTACT_HANDS, CONTACT_FEET)
spread_text = "On contact"
if(AIRBORNE)
spread_text = "Airborne"
if(BLOOD)
spread_text = "Blood"
spread_flags = spread_id
/datum/disease/advance/proc/SetSeverity(level_sev)
switch(level_sev)
if(-INFINITY to 0)
severity = NONTHREAT
if(1)
severity = MINOR
if(2)
severity = MEDIUM
if(3)
severity = HARMFUL
if(4)
severity = DANGEROUS
if(5 to INFINITY)
severity = BIOHAZARD
else
severity = "Unknown"
// Will generate a random cure, the less resistance the symptoms have, the harder the cure.
/datum/disease/advance/proc/GenerateCure()
if(properties && properties.len)
var/res = Clamp(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
//to_chat(world, "Res = [res]")
cures = list(advance_cures[res])
// Get the cure name from the cure_id
var/datum/reagent/D = GLOB.chemical_reagents_list[cures[1]]
cure_text = D.name
return
// Randomly generate a symptom, has a chance to lose or gain a symptom.
/datum/disease/advance/proc/Evolve(min_level, max_level)
var/s = safepick(GenerateSymptoms(min_level, max_level, 1))
if(s)
AddSymptom(s)
Refresh(1)
return
// Randomly remove a symptom.
/datum/disease/advance/proc/Devolve()
if(symptoms.len > 1)
var/s = safepick(symptoms)
if(s)
RemoveSymptom(s)
Refresh(1)
return
// Name the disease.
/datum/disease/advance/proc/AssignName(name = "Unknown")
src.name = name
return
// Return a unique ID of the disease.
/datum/disease/advance/GetDiseaseID()
if(!id)
var/list/L = list()
for(var/datum/symptom/S in symptoms)
L += S.id
L = sortList(L) // Sort the list so it doesn't matter which order the symptoms are in.
var/result = jointext(L, ":")
id = result
return id
// Add a symptom, if it is over the limit (with a small chance to be able to go over)
// we take a random symptom away and add the new one.
/datum/disease/advance/proc/AddSymptom(datum/symptom/S)
if(HasSymptom(S))
return
if(symptoms.len < (SYMPTOM_LIMIT - 1) + rand(-1, 1))
symptoms += S
else
RemoveSymptom(pick(symptoms))
symptoms += S
return
// Simply removes the symptom.
/datum/disease/advance/proc/RemoveSymptom(datum/symptom/S)
symptoms -= S
return
/*
Static Procs
*/
// Mix a list of advance diseases and return the mixed result.
/proc/Advance_Mix(var/list/D_list)
//to_chat(world, "Mixing!!!!")
var/list/diseases = list()
for(var/datum/disease/advance/A in D_list)
diseases += A.Copy()
if(!diseases.len)
return null
if(diseases.len <= 1)
return pick(diseases) // Just return the only entry.
var/i = 0
// Mix our diseases until we are left with only one result.
while(i < 20 && diseases.len > 1)
i++
var/datum/disease/advance/D1 = pick(diseases)
diseases -= D1
var/datum/disease/advance/D2 = pick(diseases)
D2.Mix(D1)
// Should be only 1 entry left, but if not let's only return a single entry
//to_chat(world, "END MIXING!!!!!")
var/datum/disease/advance/to_return = pick(diseases)
to_return.Refresh(1)
return to_return
/proc/SetViruses(datum/reagent/R, list/data)
if(data)
var/list/preserve = list()
if(istype(data) && data["viruses"])
for(var/datum/disease/A in data["viruses"])
preserve += A.Copy()
R.data = data.Copy()
if(preserve.len)
R.data["viruses"] = preserve
/proc/AdminCreateVirus(client/user)
if(!user)
return
var/i = SYMPTOM_LIMIT
var/datum/disease/advance/D = new(0, null)
D.symptoms = list()
var/list/symptoms = list()
symptoms += "Done"
symptoms += SSdisease.list_symptoms.Copy()
do
if(user)
var/symptom = input(user, "Choose a symptom to add ([i] remaining)", "Choose a Symptom") in symptoms
if(isnull(symptom))
return
else if(istext(symptom))
i = 0
else if(ispath(symptom))
var/datum/symptom/S = new symptom
if(!D.HasSymptom(S))
D.symptoms += S
i -= 1
while(i > 0)
if(D.symptoms.len > 0)
var/new_name = stripped_input(user, "Name your new disease.", "New Name")
if(!new_name)
return
D.AssignName(new_name)
D.Refresh()
for(var/datum/disease/advance/AD in SSdisease.processing)
AD.Refresh()
for(var/mob/living/carbon/human/H in shuffle(GLOB.living_mob_list))
if(H.z != ZLEVEL_STATION)
continue
if(!H.HasDisease(D))
H.ForceContractDisease(D)
break
var/list/name_symptoms = list()
for(var/datum/symptom/S in D.symptoms)
name_symptoms += S.name
message_admins("[key_name_admin(user)] has triggered a custom virus outbreak of [D.name]! It has these symptoms: [english_list(name_symptoms)]")
/*
/mob/verb/test()
for(var/datum/disease/D in SSdisease.processing)
to_chat(src, "<a href='?_src_=vars;Vars=\ref[D]'>[D.name] - [D.holder]</a>")
*/
/datum/disease/advance/proc/totalStageSpeed()
return properties["stage_rate"]
/datum/disease/advance/proc/totalStealth()
return properties["stealth"]
/datum/disease/advance/proc/totalResistance()
return properties["resistance"]
/datum/disease/advance/proc/totalTransmittable()
return properties["transmittable"]
#undef RANDOM_STARTING_LEVEL
continue
if(!H.HasDisease(D))
H.ForceContractDisease(D)
break
var/list/name_symptoms = list()
for(var/datum/symptom/S in D.symptoms)
name_symptoms += S.name
message_admins("[key_name_admin(user)] has triggered a custom virus outbreak of [D.name]! It has these symptoms: [english_list(name_symptoms)]")
/*
/mob/verb/test()
for(var/datum/disease/D in SSdisease.processing)
to_chat(src, "<a href='?_src_=vars;Vars=\ref[D]'>[D.name] - [D.holder]</a>")
*/
/datum/disease/advance/proc/totalStageSpeed()
return properties["stage_rate"]
/datum/disease/advance/proc/totalStealth()
return properties["stealth"]
/datum/disease/advance/proc/totalResistance()
return properties["resistance"]
/datum/disease/advance/proc/totalTransmittable()
return properties["transmittable"]
#undef RANDOM_STARTING_LEVEL
@@ -1,37 +1,37 @@
/*
//////////////////////////////////////
Deafness
Slightly noticable.
Lowers resistance.
Decreases stage speed slightly.
Decreases transmittablity.
Intense Level.
Bonus
Causes intermittent loss of hearing.
//////////////////////////////////////
*/
/datum/symptom/deafness
name = "Deafness"
stealth = -1
resistance = -2
stage_speed = -1
transmittable = -3
level = 4
severity = 3
/datum/symptom/deafness/Activate(datum/disease/advance/A)
..()
if(prob(SYMPTOM_ACTIVATION_PROB))
var/mob/living/M = A.affected_mob
switch(A.stage)
if(3, 4)
to_chat(M, "<span class='warning'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>")
if(5)
/*
//////////////////////////////////////
Deafness
Slightly noticable.
Lowers resistance.
Decreases stage speed slightly.
Decreases transmittablity.
Intense Level.
Bonus
Causes intermittent loss of hearing.
//////////////////////////////////////
*/
/datum/symptom/deafness
name = "Deafness"
stealth = -1
resistance = -2
stage_speed = -1
transmittable = -3
level = 4
severity = 3
/datum/symptom/deafness/Activate(datum/disease/advance/A)
..()
if(prob(SYMPTOM_ACTIVATION_PROB))
var/mob/living/M = A.affected_mob
switch(A.stage)
if(3, 4)
to_chat(M, "<span class='warning'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>")
if(5)
to_chat(M, "<span class='userdanger'>Your ears pop and begin ringing loudly!</span>")
M.minimumDeafTicks(20)
+281 -281
View File
@@ -1,288 +1,288 @@
/*
//////////////////////////////////////
Healing
Little bit hidden.
Lowers resistance tremendously.
Decreases stage speed tremendously.
Decreases transmittablity temrendously.
Fatal Level.
Bonus
Heals toxins in the affected mob's blood stream.
//////////////////////////////////////
*/
/datum/symptom/heal
name = "Toxic Filter"
stealth = 1
resistance = -4
stage_speed = -4
transmittable = -4
level = 6
/datum/symptom/heal/Activate(datum/disease/advance/A)
..()
//100% chance to activate for slow but consistent healing
var/mob/living/M = A.affected_mob
switch(A.stage)
if(4, 5)
Heal(M, A)
return
/datum/symptom/heal/proc/Heal(mob/living/M, datum/disease/advance/A)
var/heal_amt = 0.5
if(M.toxloss > 0 && prob(20))
/*
//////////////////////////////////////
Healing
Little bit hidden.
Lowers resistance tremendously.
Decreases stage speed tremendously.
Decreases transmittablity temrendously.
Fatal Level.
Bonus
Heals toxins in the affected mob's blood stream.
//////////////////////////////////////
*/
/datum/symptom/heal
name = "Toxic Filter"
stealth = 1
resistance = -4
stage_speed = -4
transmittable = -4
level = 6
/datum/symptom/heal/Activate(datum/disease/advance/A)
..()
//100% chance to activate for slow but consistent healing
var/mob/living/M = A.affected_mob
switch(A.stage)
if(4, 5)
Heal(M, A)
return
/datum/symptom/heal/proc/Heal(mob/living/M, datum/disease/advance/A)
var/heal_amt = 0.5
if(M.toxloss > 0 && prob(20))
new /obj/effect/temp_visual/heal(get_turf(M), "#66FF99")
M.adjustToxLoss(-heal_amt)
return 1
/*
//////////////////////////////////////
Apoptosis
Lowers resistance.
Decreases stage speed.
Decreases transmittablity.
Bonus
Heals toxins in the affected mob's blood stream faster.
//////////////////////////////////////
*/
/datum/symptom/heal/plus
name = "Apoptoxin filter"
stealth = 0
resistance = -2
stage_speed = -2
transmittable = -2
level = 8
/datum/symptom/heal/plus/Heal(mob/living/M, datum/disease/advance/A)
var/heal_amt = 1
if(M.toxloss > 0 && prob(20))
M.adjustToxLoss(-heal_amt)
return 1
/*
//////////////////////////////////////
Apoptosis
Lowers resistance.
Decreases stage speed.
Decreases transmittablity.
Bonus
Heals toxins in the affected mob's blood stream faster.
//////////////////////////////////////
*/
/datum/symptom/heal/plus
name = "Apoptoxin filter"
stealth = 0
resistance = -2
stage_speed = -2
transmittable = -2
level = 8
/datum/symptom/heal/plus/Heal(mob/living/M, datum/disease/advance/A)
var/heal_amt = 1
if(M.toxloss > 0 && prob(20))
new /obj/effect/temp_visual/heal(get_turf(M), "#00FF00")
M.adjustToxLoss(-heal_amt)
return 1
/*
//////////////////////////////////////
Regeneration
Little bit hidden.
Lowers resistance tremendously.
Decreases stage speed tremendously.
Decreases transmittablity temrendously.
Fatal Level.
Bonus
Heals brute damage slowly over time.
//////////////////////////////////////
*/
/datum/symptom/heal/brute
name = "Regeneration"
stealth = 1
resistance = -4
stage_speed = -4
transmittable = -4
level = 6
/datum/symptom/heal/brute/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/heal_amt = 1
var/list/parts = M.get_damaged_bodyparts(1,1) //1,1 because it needs inputs.
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, 0))
M.update_damage_overlays()
if(prob(20))
M.adjustToxLoss(-heal_amt)
return 1
/*
//////////////////////////////////////
Regeneration
Little bit hidden.
Lowers resistance tremendously.
Decreases stage speed tremendously.
Decreases transmittablity temrendously.
Fatal Level.
Bonus
Heals brute damage slowly over time.
//////////////////////////////////////
*/
/datum/symptom/heal/brute
name = "Regeneration"
stealth = 1
resistance = -4
stage_speed = -4
transmittable = -4
level = 6
/datum/symptom/heal/brute/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/heal_amt = 1
var/list/parts = M.get_damaged_bodyparts(1,1) //1,1 because it needs inputs.
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, 0))
M.update_damage_overlays()
if(prob(20))
new /obj/effect/temp_visual/heal(get_turf(M), "#FF3333")
return 1
/*
//////////////////////////////////////
Flesh Mending
No resistance change.
Decreases stage speed.
Decreases transmittablity.
Fatal Level.
Bonus
Heals brute damage over time. Turns cloneloss into burn damage.
//////////////////////////////////////
*/
/datum/symptom/heal/brute/plus
name = "Flesh Mending"
stealth = 0
resistance = 0
stage_speed = -2
transmittable = -2
level = 8
/datum/symptom/heal/brute/plus/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/heal_amt = 2
var/list/parts = M.get_damaged_bodyparts(1,1) //1,1 because it needs inputs.
if(M.getCloneLoss() > 0)
M.adjustCloneLoss(-1)
M.take_bodypart_damage(0, 1) //Deals BURN damage, which is not cured by this symptom
return 1
/*
//////////////////////////////////////
Flesh Mending
No resistance change.
Decreases stage speed.
Decreases transmittablity.
Fatal Level.
Bonus
Heals brute damage over time. Turns cloneloss into burn damage.
//////////////////////////////////////
*/
/datum/symptom/heal/brute/plus
name = "Flesh Mending"
stealth = 0
resistance = 0
stage_speed = -2
transmittable = -2
level = 8
/datum/symptom/heal/brute/plus/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/heal_amt = 2
var/list/parts = M.get_damaged_bodyparts(1,1) //1,1 because it needs inputs.
if(M.getCloneLoss() > 0)
M.adjustCloneLoss(-1)
M.take_bodypart_damage(0, 1) //Deals BURN damage, which is not cured by this symptom
new /obj/effect/temp_visual/heal(get_turf(M), "#33FFCC")
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, 0))
M.update_damage_overlays()
if(prob(20))
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, 0))
M.update_damage_overlays()
if(prob(20))
new /obj/effect/temp_visual/heal(get_turf(M), "#CC1100")
return 1
/*
//////////////////////////////////////
Tissue Regrowth
Little bit hidden.
Lowers resistance tremendously.
Decreases stage speed tremendously.
Decreases transmittablity temrendously.
Fatal Level.
Bonus
Heals burn damage slowly over time.
//////////////////////////////////////
*/
/datum/symptom/heal/burn
name = "Tissue Regrowth"
stealth = 1
resistance = -4
stage_speed = -4
transmittable = -4
level = 6
/datum/symptom/heal/burn/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/heal_amt = 1
var/list/parts = M.get_damaged_bodyparts(1,1) //1,1 because it needs inputs.
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(0, heal_amt/parts.len))
M.update_damage_overlays()
if(prob(20))
return 1
/*
//////////////////////////////////////
Tissue Regrowth
Little bit hidden.
Lowers resistance tremendously.
Decreases stage speed tremendously.
Decreases transmittablity temrendously.
Fatal Level.
Bonus
Heals burn damage slowly over time.
//////////////////////////////////////
*/
/datum/symptom/heal/burn
name = "Tissue Regrowth"
stealth = 1
resistance = -4
stage_speed = -4
transmittable = -4
level = 6
/datum/symptom/heal/burn/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/heal_amt = 1
var/list/parts = M.get_damaged_bodyparts(1,1) //1,1 because it needs inputs.
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(0, heal_amt/parts.len))
M.update_damage_overlays()
if(prob(20))
new /obj/effect/temp_visual/heal(get_turf(M), "#FF9933")
return 1
/*
//////////////////////////////////////
Heat Resistance //Needs a better name
No resistance change.
Decreases stage speed.
Decreases transmittablity.
Fatal Level.
Bonus
Heals burn damage over time, and helps stabilize body temperature.
//////////////////////////////////////
*/
/datum/symptom/heal/burn/plus
name = "Heat Resistance"
stealth = 0
resistance = 0
stage_speed = -2
transmittable = -2
level = 8
/datum/symptom/heal/burn/plus/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/heal_amt = 2
var/list/parts = M.get_damaged_bodyparts(1,1) //1,1 because it needs inputs.
if(M.bodytemperature > 310)
M.bodytemperature = max(310, M.bodytemperature - (10 * heal_amt * TEMPERATURE_DAMAGE_COEFFICIENT))
else if(M.bodytemperature < 311)
M.bodytemperature = min(310, M.bodytemperature + (10 * heal_amt * TEMPERATURE_DAMAGE_COEFFICIENT))
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(0, heal_amt/parts.len))
M.update_damage_overlays()
if(prob(20))
return 1
/*
//////////////////////////////////////
Heat Resistance //Needs a better name
No resistance change.
Decreases stage speed.
Decreases transmittablity.
Fatal Level.
Bonus
Heals burn damage over time, and helps stabilize body temperature.
//////////////////////////////////////
*/
/datum/symptom/heal/burn/plus
name = "Heat Resistance"
stealth = 0
resistance = 0
stage_speed = -2
transmittable = -2
level = 8
/datum/symptom/heal/burn/plus/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/heal_amt = 2
var/list/parts = M.get_damaged_bodyparts(1,1) //1,1 because it needs inputs.
if(M.bodytemperature > 310)
M.bodytemperature = max(310, M.bodytemperature - (10 * heal_amt * TEMPERATURE_DAMAGE_COEFFICIENT))
else if(M.bodytemperature < 311)
M.bodytemperature = min(310, M.bodytemperature + (10 * heal_amt * TEMPERATURE_DAMAGE_COEFFICIENT))
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(0, heal_amt/parts.len))
M.update_damage_overlays()
if(prob(20))
new /obj/effect/temp_visual/heal(get_turf(M), "#CC6600")
return 1
/*
//////////////////////////////////////
DNA Restoration
Not well hidden.
Lowers resistance minorly.
Does not affect stage speed.
Decreases transmittablity greatly.
Very high level.
Bonus
Heals brain damage, treats radiation, cleans SE of non-power mutations.
//////////////////////////////////////
*/
/datum/symptom/heal/dna
name = "Deoxyribonucleic Acid Restoration"
stealth = -1
resistance = -1
stage_speed = 0
transmittable = -3
level = 5
/datum/symptom/heal/dna/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/amt_healed = 1
M.adjustBrainLoss(-amt_healed)
//Non-power mutations, excluding race, so the virus does not force monkey -> human transformations.
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations) - GLOB.mutations_list[RACEMUT]
M.dna.remove_mutation_group(unclean_mutations)
M.radiation = max(M.radiation - (2 * amt_healed), 0)
return 1
return 1
/*
//////////////////////////////////////
DNA Restoration
Not well hidden.
Lowers resistance minorly.
Does not affect stage speed.
Decreases transmittablity greatly.
Very high level.
Bonus
Heals brain damage, treats radiation, cleans SE of non-power mutations.
//////////////////////////////////////
*/
/datum/symptom/heal/dna
name = "Deoxyribonucleic Acid Restoration"
stealth = -1
resistance = -1
stage_speed = 0
transmittable = -3
level = 5
/datum/symptom/heal/dna/Heal(mob/living/carbon/M, datum/disease/advance/A)
var/amt_healed = 1
M.adjustBrainLoss(-amt_healed)
//Non-power mutations, excluding race, so the virus does not force monkey -> human transformations.
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations) - GLOB.mutations_list[RACEMUT]
M.dna.remove_mutation_group(unclean_mutations)
M.radiation = max(M.radiation - (2 * amt_healed), 0)
return 1
@@ -125,4 +125,4 @@ Bonus
if(12 to 24)
M.drowsyness += 1
if(24 to INFINITY)
M.Sleeping(2, 0)
M.Sleeping(40)
@@ -29,6 +29,9 @@ Bonus
..()
if(prob(SYMPTOM_ACTIVATION_PROB))
var/mob/living/M = A.affected_mob
var/obj/item/organ/eyes/eyes = M.getorganslot("eyes_sight")
if (!eyes)
return
switch(A.stage)
if(1, 2)
to_chat(M, "<span class='warning'>Your eyes itch.</span>")
@@ -40,9 +43,9 @@ Bonus
to_chat(M, "<span class='userdanger'>Your eyes burn horrificly!</span>")
M.blur_eyes(20)
M.adjust_eye_damage(5)
if(M.eye_damage >= 10)
if(eyes.eye_damage >= 10)
M.become_nearsighted()
if(prob(M.eye_damage - 10 + 1))
if(prob(eyes.eye_damage - 10 + 1))
if(M.become_blind())
to_chat(M, "<span class='userdanger'>You go blind!</span>")
@@ -76,6 +79,9 @@ Bonus
/datum/symptom/visionaid/Activate(datum/disease/advance/A)
..()
var/mob/living/M = A.affected_mob
var/obj/item/organ/eyes/eyes = M.getorganslot("eyes_sight")
if (!eyes)
return
switch(A.stage)
if(4, 5) //basically oculine
if(M.disabilities & BLIND)
@@ -93,7 +99,7 @@ Bonus
else if(M.eye_blind || M.eye_blurry)
M.set_blindness(0)
M.set_blurriness(0)
else if(M.eye_damage > 0)
else if(eyes.eye_damage > 0)
M.adjust_eye_damage(-1)
else
if(prob(SYMPTOM_ACTIVATION_PROB * 3))
+103 -103
View File
@@ -1,106 +1,106 @@
/*
//////////////////////////////////////
Vomiting
Very Very Noticable.
Decreases resistance.
Doesn't increase stage speed.
Little transmittable.
Medium Level.
Bonus
Forces the affected mob to vomit!
Meaning your disease can spread via
people walking on vomit.
Makes the affected mob lose nutrition and
heal toxin damage.
//////////////////////////////////////
*/
/datum/symptom/vomit
name = "Vomiting"
stealth = -2
resistance = -1
stage_speed = 0
transmittable = 1
level = 3
severity = 4
/datum/symptom/vomit/Activate(datum/disease/advance/A)
..()
if(prob(SYMPTOM_ACTIVATION_PROB / 2))
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
to_chat(M, "<span class='warning'>[pick("You feel nauseous.", "You feel like you're going to throw up!")]</span>")
else
Vomit(M)
return
/datum/symptom/vomit/proc/Vomit(mob/living/carbon/M)
/*
//////////////////////////////////////
Vomiting
Very Very Noticable.
Decreases resistance.
Doesn't increase stage speed.
Little transmittable.
Medium Level.
Bonus
Forces the affected mob to vomit!
Meaning your disease can spread via
people walking on vomit.
Makes the affected mob lose nutrition and
heal toxin damage.
//////////////////////////////////////
*/
/datum/symptom/vomit
name = "Vomiting"
stealth = -2
resistance = -1
stage_speed = 0
transmittable = 1
level = 3
severity = 4
/datum/symptom/vomit/Activate(datum/disease/advance/A)
..()
if(prob(SYMPTOM_ACTIVATION_PROB / 2))
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
to_chat(M, "<span class='warning'>[pick("You feel nauseous.", "You feel like you're going to throw up!")]</span>")
else
Vomit(M)
return
/datum/symptom/vomit/proc/Vomit(mob/living/carbon/M)
M.vomit(20)
/*
//////////////////////////////////////
Vomiting Blood
Very Very Noticable.
Decreases resistance.
Decreases stage speed.
Little transmittable.
Intense level.
Bonus
Forces the affected mob to vomit blood!
Meaning your disease can spread via
people walking on the blood.
Makes the affected mob lose health.
//////////////////////////////////////
*/
/datum/symptom/vomit/blood
name = "Blood Vomiting"
stealth = -2
resistance = -1
stage_speed = -1
transmittable = 1
level = 4
severity = 5
/datum/symptom/vomit/blood/Vomit(mob/living/carbon/M)
/*
//////////////////////////////////////
Vomiting Blood
Very Very Noticable.
Decreases resistance.
Decreases stage speed.
Little transmittable.
Intense level.
Bonus
Forces the affected mob to vomit blood!
Meaning your disease can spread via
people walking on the blood.
Makes the affected mob lose health.
//////////////////////////////////////
*/
/datum/symptom/vomit/blood
name = "Blood Vomiting"
stealth = -2
resistance = -1
stage_speed = -1
transmittable = 1
level = 4
severity = 5
/datum/symptom/vomit/blood/Vomit(mob/living/carbon/M)
M.vomit(0,TRUE)
/*
//////////////////////////////////////
Projectile Vomiting
Very Very Noticable.
Decreases resistance.
Doesn't increase stage speed.
Little transmittable.
Medium Level.
Bonus
As normal vomiting, except it will spread further,
likely causing more to walk across the vomit.
//////////////////////////////////////
*/
/datum/symptom/vomit/projectile
name = "Projectile Vomiting"
stealth = -2
level = 4
/datum/symptom/vomit/projectile/Vomit(mob/living/carbon/M)
/*
//////////////////////////////////////
Projectile Vomiting
Very Very Noticable.
Decreases resistance.
Doesn't increase stage speed.
Little transmittable.
Medium Level.
Bonus
As normal vomiting, except it will spread further,
likely causing more to walk across the vomit.
//////////////////////////////////////
*/
/datum/symptom/vomit/projectile
name = "Projectile Vomiting"
stealth = -2
level = 4
/datum/symptom/vomit/projectile/Vomit(mob/living/carbon/M)
M.vomit(6, distance = 5)
@@ -40,5 +40,5 @@ Bonus
M.adjustStaminaLoss(30)
if(M.getStaminaLoss() > 60 && !M.stat)
M.visible_message("<span class='warning'>[M] faints!</span>", "<span class='userdanger'>You swoon and faint...</span>")
M.AdjustSleeping(5)
M.AdjustSleeping(100)
return
+33 -33
View File
@@ -1,34 +1,34 @@
/datum/disease/appendicitis
form = "Condition"
name = "Appendicitis"
max_stages = 3
cure_text = "Surgery"
agent = "Shitty Appendix"
viable_mobtypes = list(/mob/living/carbon/human)
permeability_mod = 1
desc = "If left untreated the subject will become very weak, and may vomit often."
severity = "Dangerous!"
longevity = 1000
disease_flags = CAN_CARRY|CAN_RESIST
spread_flags = NON_CONTAGIOUS
visibility_flags = HIDDEN_PANDEMIC
required_organs = list(/obj/item/organ/appendix)
/datum/disease/appendicitis/stage_act()
..()
switch(stage)
if(1)
if(prob(5))
affected_mob.emote("cough")
if(2)
var/obj/item/organ/appendix/A = affected_mob.getorgan(/obj/item/organ/appendix)
if(A)
A.inflamed = 1
A.update_icon()
if(prob(3))
to_chat(affected_mob, "<span class='warning'>You feel a stabbing pain in your abdomen!</span>")
affected_mob.Stun(rand(2,3))
affected_mob.adjustToxLoss(1)
if(3)
if(prob(1))
/datum/disease/appendicitis
form = "Condition"
name = "Appendicitis"
max_stages = 3
cure_text = "Surgery"
agent = "Shitty Appendix"
viable_mobtypes = list(/mob/living/carbon/human)
permeability_mod = 1
desc = "If left untreated the subject will become very weak, and may vomit often."
severity = "Dangerous!"
longevity = 1000
disease_flags = CAN_CARRY|CAN_RESIST
spread_flags = NON_CONTAGIOUS
visibility_flags = HIDDEN_PANDEMIC
required_organs = list(/obj/item/organ/appendix)
/datum/disease/appendicitis/stage_act()
..()
switch(stage)
if(1)
if(prob(5))
affected_mob.emote("cough")
if(2)
var/obj/item/organ/appendix/A = affected_mob.getorgan(/obj/item/organ/appendix)
if(A)
A.inflamed = 1
A.update_icon()
if(prob(3))
to_chat(affected_mob, "<span class='warning'>You feel a stabbing pain in your abdomen!</span>")
affected_mob.Stun(rand(40,60))
affected_mob.adjustToxLoss(1)
if(3)
if(prob(1))
affected_mob.vomit(95)
+1 -1
View File
@@ -50,7 +50,7 @@
if(prob(3))
to_chat(affected_mob, "<span class='danger'>You lose consciousness...</span>")
affected_mob.visible_message("<span class='warning'>[affected_mob] suddenly collapses</span>")
affected_mob.Paralyse(rand(5,10))
affected_mob.Unconscious(rand(100,200))
if(prob(1))
affected_mob.emote("snore")
if(prob(15))
+1 -1
View File
@@ -52,7 +52,7 @@
to_chat(affected_mob, "You feel very strange.")
if (prob(4))
to_chat(affected_mob, "<span class='danger'>You feel a stabbing pain in your head!</span>")
affected_mob.Paralyse(2)
affected_mob.Unconscious(40)
if (prob(4))
to_chat(affected_mob, "<span class='danger'>Your stomach churns.</span>")
if(3)
+2 -2
View File
@@ -138,7 +138,7 @@
affected_mob.say(pick("Beep, boop", "beep, beep!", "Boop...bop"))
if (prob(4))
to_chat(affected_mob, "<span class='danger'>You feel a stabbing pain in your head.</span>")
affected_mob.Paralyse(2)
affected_mob.Unconscious(40)
if(4)
if (prob(20))
affected_mob.say(pick("beep, beep!", "Boop bop boop beep.", "kkkiiiill mmme", "I wwwaaannntt tttoo dddiiieeee..."))
@@ -167,7 +167,7 @@
if(3)
if (prob(4))
to_chat(affected_mob, "<span class='danger'>You feel a stabbing pain in your head.</span>")
affected_mob.Paralyse(2)
affected_mob.Unconscious(40)
if(4)
if (prob(20))
affected_mob.say(pick("You look delicious.", "Going to... devour you...", "Hsssshhhhh!"))
+1 -1
View File
@@ -41,7 +41,7 @@
if(prob(10))
affected_mob.adjustStaminaLoss(100)
affected_mob.visible_message("<span class='warning'>[affected_mob] faints!</span>", "<span class='userdanger'>You surrender yourself and feel at peace...</span>")
affected_mob.AdjustSleeping(5)
affected_mob.AdjustSleeping(100)
if(prob(2))
to_chat(affected_mob, "<span class='userdanger'>You feel your mind relax and your thoughts drift!</span>")
affected_mob.confused = min(100, affected_mob.confused + 8)
+4 -7
View File
@@ -16,27 +16,24 @@
var/emote_type = EMOTE_VISIBLE //Whether the emote is visible or audible
var/restraint_check = FALSE //Checks if the mob is restrained before performing the emote
var/muzzle_ignore = FALSE //Will only work if the emote is EMOTE_AUDIBLE
var/list/mob_type_allowed_typecache = list() //Types that are allowed to use that emote
var/list/mob_type_blacklist_typecache = list() //Types that are NOT allowed to use that emote
var/list/mob_type_allowed_typecache //Types that are allowed to use that emote
var/list/mob_type_blacklist_typecache //Types that are NOT allowed to use that emote
var/stat_allowed = CONSCIOUS
var/static/list/emote_list = list()
/datum/emote/New()
..()
if(key_third_person)
emote_list[key_third_person] = src
mob_type_allowed_typecache = typecacheof(mob_type_allowed_typecache)
mob_type_blacklist_typecache = typecacheof(mob_type_blacklist_typecache)
/datum/emote/proc/run_emote(mob/user, params = null, type_override = null)
/datum/emote/proc/run_emote(mob/user, params, type_override)
. = TRUE
if(!can_run_emote(user))
return FALSE
var/msg = select_message_type(user)
if(params && message_param)
msg = select_param(user, params)
if(findtext(msg, "%s"))
msg = replacetext(msg, "%s", user.p_s())
msg = replace_pronoun(user, msg)
@@ -88,7 +85,7 @@
. = message_AI
else if(ismonkey(user) && message_monkey)
. = message_monkey
else if(istype(user, /mob/living/simple_animal) && message_simple)
else if(isanimal(user) && message_simple)
. = message_simple
/datum/emote/proc/select_param(mob/user, params)
+8 -7
View File
@@ -125,7 +125,7 @@ GLOBAL_LIST_EMPTY(explosions)
E = new
E.set_up(epicenter)
E.start()
EX_PREPROCESS_CHECK_TICK
//flash mobs
@@ -192,7 +192,7 @@ GLOBAL_LIST_EMPTY(explosions)
var/throw_range = rand(throw_dist, max_range)
var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range)
I.throw_speed = EXPLOSION_THROW_SPEED //Temporarily change their throw_speed for embedding purposes (Reset when it finishes throwing, regardless of hitting anything)
I.throw_at(throw_at, throw_range, EXPLOSION_THROW_SPEED)
I.throw_at(throw_at, throw_range, EXPLOSION_THROW_SPEED)
//wait for the lists to repop
var/break_condition
@@ -208,7 +208,7 @@ GLOBAL_LIST_EMPTY(explosions)
if(!running)
break
//update the trackers
affTurfLen = affected_turfs.len
expBlockLen = cached_exp_block.len
@@ -274,7 +274,7 @@ GLOBAL_LIST_EMPTY(explosions)
. = list()
var/processed = 0
while(!stopped && running)
var/I
var/I
for(I in (processed + 1) to affected_turfs.len) // we cache the explosion block rating of every turf in the explosion area
var/turf/T = affected_turfs[I]
var/current_exp_block = T.density ? T.explosion_block : 0
@@ -282,12 +282,12 @@ GLOBAL_LIST_EMPTY(explosions)
for(var/obj/O in T)
var/the_block = O.explosion_block
current_exp_block += the_block == EXPLOSION_BLOCK_PROC ? O.GetExplosionBlock() : the_block
.[T] = current_exp_block
if(TICK_CHECK)
break
processed = I
stoplag()
@@ -346,10 +346,11 @@ GLOBAL_LIST_EMPTY(explosions)
TT = get_step_towards(TT,epicenter)
if(TT.density)
dist += TT.explosion_block
for(var/obj/O in T)
var/the_block = O.explosion_block
dist += the_block == EXPLOSION_BLOCK_PROC ? O.GetExplosionBlock() : the_block
if(dist < dev)
T.color = "red"
T.maptext = "Dev"
+134 -134
View File
@@ -1,136 +1,136 @@
/datum/getrev
var/originmastercommit
var/commit
var/list/testmerge = list()
var/has_pr_details = FALSE //tgs2 support
var/date
/datum/getrev/New()
if(fexists(SERVICE_PR_TEST_JSON))
testmerge = json_decode(file2text(SERVICE_PR_TEST_JSON))
else if(!world.RunningService() && fexists("../prtestjob.lk")) //tgs2 support
var/list/tmp = world.file2list("..\\prtestjob.lk")
for(var/I in tmp)
if(I)
testmerge |= I
log_world("Running /tg/ revision:")
var/list/logs = world.file2list(".git/logs/HEAD")
if(logs)
logs = splittext(logs[logs.len - 1], " ")
date = unix2date(text2num(logs[5]))
commit = logs[2]
log_world("[date]")
logs = world.file2list(".git/logs/refs/remotes/origin/master")
if(logs)
originmastercommit = splittext(logs[logs.len - 1], " ")[2]
if(testmerge.len)
log_world(commit)
for(var/line in testmerge)
if(line)
if(world.RunningService())
var/tmcommit = testmerge[line]["commit"]
log_world("Test merge active of PR #[line] commit [tmcommit]")
SSblackbox.add_details("testmerged_prs","[line]|[tmcommit]")
else //tgs2 support
log_world("Test merge active of PR #[line]")
SSblackbox.add_details("testmerged_prs","[line]")
log_world("Based off origin/master commit [originmastercommit]")
else
log_world(originmastercommit)
/datum/getrev/proc/DownloadPRDetails()
if(!config.githubrepoid)
if(testmerge.len)
log_world("PR details download failed: No github repo config set")
return
if(!isnum(text2num(config.githubrepoid)))
log_world("PR details download failed: Invalid github repo id: [config.githubrepoid]")
return
for(var/line in testmerge)
if(!isnum(text2num(line)))
log_world("PR details download failed: Invalid PR number: [line]")
return
var/url = "https://api.github.com/repositories/[config.githubrepoid]/pulls/[line].json"
GLOB.valid_HTTPSGet = TRUE
var/json = HTTPSGet(url)
if(!json)
return
testmerge[line] = json_decode(json)
if(!testmerge[line])
log_world("PR details download failed: null details returned")
return
CHECK_TICK
log_world("PR details successfully downloaded")
has_pr_details = TRUE
/datum/getrev/proc/GetTestMergeInfo(header = TRUE)
if(!testmerge.len)
return ""
. = header ? "The following pull requests are currently test merged:<br>" : ""
for(var/line in testmerge)
var/details
if(world.RunningService())
var/cm = testmerge[line]["commit"]
details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["author"]) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 7)))
else if(has_pr_details) //tgs2 support
details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["user"]["login"])
/datum/getrev
var/originmastercommit
var/commit
var/list/testmerge = list()
var/has_pr_details = FALSE //tgs2 support
var/date
/datum/getrev/New()
if(world.RunningService() && fexists(SERVICE_PR_TEST_JSON))
testmerge = json_decode(file2text(SERVICE_PR_TEST_JSON))
#ifdef SERVERTOOLS
else if(!world.RunningService() && fexists("../prtestjob.lk")) //tgs2 support
var/list/tmp = world.file2list("..\\prtestjob.lk")
for(var/I in tmp)
if(I)
testmerge |= I
#endif
log_world("Running /tg/ revision:")
var/list/logs = world.file2list(".git/logs/HEAD")
if(logs)
logs = splittext(logs[logs.len - 1], " ")
date = unix2date(text2num(logs[5]))
commit = logs[2]
log_world("[date]")
logs = world.file2list(".git/logs/refs/remotes/origin/master")
if(logs)
originmastercommit = splittext(logs[logs.len - 1], " ")[2]
if(testmerge.len)
log_world(commit)
for(var/line in testmerge)
if(line)
if(world.RunningService())
var/tmcommit = testmerge[line]["commit"]
log_world("Test merge active of PR #[line] commit [tmcommit]")
SSblackbox.add_details("testmerged_prs","[line]|[tmcommit]")
else //tgs2 support
log_world("Test merge active of PR #[line]")
SSblackbox.add_details("testmerged_prs","[line]")
log_world("Based off origin/master commit [originmastercommit]")
else
log_world(originmastercommit)
/datum/getrev/proc/DownloadPRDetails()
if(!config.githubrepoid)
if(testmerge.len)
log_world("PR details download failed: No github repo config set")
return
if(!isnum(text2num(config.githubrepoid)))
log_world("PR details download failed: Invalid github repo id: [config.githubrepoid]")
return
for(var/line in testmerge)
if(!isnum(text2num(line)))
log_world("PR details download failed: Invalid PR number: [line]")
return
var/url = "https://api.github.com/repositories/[config.githubrepoid]/pulls/[line].json"
GLOB.valid_HTTPSGet = TRUE
var/json = HTTPSGet(url)
if(!json)
return
testmerge[line] = json_decode(json)
if(!testmerge[line])
log_world("PR details download failed: null details returned")
return
CHECK_TICK
log_world("PR details successfully downloaded")
has_pr_details = TRUE
/datum/getrev/proc/GetTestMergeInfo(header = TRUE)
if(!testmerge.len)
return ""
. = header ? "The following pull requests are currently test merged:<br>" : ""
for(var/line in testmerge)
var/details
if(world.RunningService())
var/cm = testmerge[line]["commit"]
details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["author"]) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 7)))
else if(has_pr_details) //tgs2 support
details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["user"]["login"])
. += "<a href=\"[config.githuburl]/pull/[line]\">#[line][details]</a><br>"
/client/verb/showrevinfo()
set category = "OOC"
set name = "Show Server Revision"
set desc = "Check the current server code revision"
if(GLOB.revdata.originmastercommit)
to_chat(src, "<b>Server revision compiled on:</b> [GLOB.revdata.date]")
var/prefix = ""
if(GLOB.revdata.testmerge.len)
to_chat(src, GLOB.revdata.GetTestMergeInfo())
prefix = "Based off origin/master commit: "
var/pc = GLOB.revdata.originmastercommit
/client/verb/showrevinfo()
set category = "OOC"
set name = "Show Server Revision"
set desc = "Check the current server code revision"
if(GLOB.revdata.originmastercommit)
to_chat(src, "<b>Server revision compiled on:</b> [GLOB.revdata.date]")
var/prefix = ""
if(GLOB.revdata.testmerge.len)
to_chat(src, GLOB.revdata.GetTestMergeInfo())
prefix = "Based off origin/master commit: "
var/pc = GLOB.revdata.originmastercommit
to_chat(src, "[prefix]<a href=\"[config.githuburl]/commit/[pc]\">[copytext(pc, 1, min(length(pc), 7))]</a>")
else
to_chat(src, "Revision unknown")
to_chat(src, "<b>Current Infomational Settings:</b>")
to_chat(src, "Protect Authority Roles From Traitor: [config.protect_roles_from_antagonist]")
to_chat(src, "Protect Assistant Role From Traitor: [config.protect_assistant_from_antagonist]")
to_chat(src, "Enforce Human Authority: [config.enforce_human_authority]")
to_chat(src, "Allow Latejoin Antagonists: [config.allow_latejoin_antagonists]")
to_chat(src, "Enforce Continuous Rounds: [config.continuous.len] of [config.modes.len] roundtypes")
to_chat(src, "Allow Midround Antagonists: [config.midround_antag.len] of [config.modes.len] roundtypes")
if(config.show_game_type_odds)
if(SSticker.IsRoundInProgress())
var/prob_sum = 0
var/current_odds_differ = FALSE
var/list/probs = list()
var/list/modes = config.gamemode_cache
for(var/mode in modes)
var/datum/game_mode/M = mode
var/ctag = initial(M.config_tag)
if(!(ctag in config.probabilities))
continue
if((config.min_pop[ctag] && (config.min_pop[ctag] > SSticker.totalPlayersReady)) || (config.max_pop[ctag] && (config.max_pop[ctag] < SSticker.totalPlayersReady)) || (initial(M.required_players) > SSticker.totalPlayersReady))
current_odds_differ = TRUE
continue
probs[ctag] = 1
prob_sum += config.probabilities[ctag]
if(current_odds_differ)
to_chat(src, "<b>Game Mode Odds for current round:</b>")
for(var/ctag in probs)
if(config.probabilities[ctag] > 0)
var/percentage = round(config.probabilities[ctag] / prob_sum * 100, 0.1)
to_chat(src, "[ctag] [percentage]%")
to_chat(src, "<b>All Game Mode Odds:</b>")
var/sum = 0
for(var/ctag in config.probabilities)
sum += config.probabilities[ctag]
for(var/ctag in config.probabilities)
if(config.probabilities[ctag] > 0)
var/percentage = round(config.probabilities[ctag] / sum * 100, 0.1)
to_chat(src, "[ctag] [percentage]%")
else
to_chat(src, "Revision unknown")
to_chat(src, "<b>Current Infomational Settings:</b>")
to_chat(src, "Protect Authority Roles From Traitor: [config.protect_roles_from_antagonist]")
to_chat(src, "Protect Assistant Role From Traitor: [config.protect_assistant_from_antagonist]")
to_chat(src, "Enforce Human Authority: [config.enforce_human_authority]")
to_chat(src, "Allow Latejoin Antagonists: [config.allow_latejoin_antagonists]")
to_chat(src, "Enforce Continuous Rounds: [config.continuous.len] of [config.modes.len] roundtypes")
to_chat(src, "Allow Midround Antagonists: [config.midround_antag.len] of [config.modes.len] roundtypes")
if(config.show_game_type_odds)
if(SSticker.IsRoundInProgress())
var/prob_sum = 0
var/current_odds_differ = FALSE
var/list/probs = list()
var/list/modes = config.gamemode_cache
for(var/mode in modes)
var/datum/game_mode/M = mode
var/ctag = initial(M.config_tag)
if(!(ctag in config.probabilities))
continue
if((config.min_pop[ctag] && (config.min_pop[ctag] > SSticker.totalPlayersReady)) || (config.max_pop[ctag] && (config.max_pop[ctag] < SSticker.totalPlayersReady)) || (initial(M.required_players) > SSticker.totalPlayersReady))
current_odds_differ = TRUE
continue
probs[ctag] = 1
prob_sum += config.probabilities[ctag]
if(current_odds_differ)
to_chat(src, "<b>Game Mode Odds for current round:</b>")
for(var/ctag in probs)
if(config.probabilities[ctag] > 0)
var/percentage = round(config.probabilities[ctag] / prob_sum * 100, 0.1)
to_chat(src, "[ctag] [percentage]%")
to_chat(src, "<b>All Game Mode Odds:</b>")
var/sum = 0
for(var/ctag in config.probabilities)
sum += config.probabilities[ctag]
for(var/ctag in config.probabilities)
if(config.probabilities[ctag] > 0)
var/percentage = round(config.probabilities[ctag] / sum * 100, 0.1)
to_chat(src, "[ctag] [percentage]%")
+20 -17
View File
@@ -15,7 +15,6 @@
var/soundout //soundfile to play after teleportation
var/force_teleport = 1 //if false, teleport will use Move() proc (dense objects will prevent teleportation)
/datum/teleport/proc/start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
if(!initTeleport(arglist(args)))
return 0
@@ -100,21 +99,7 @@
var/turf/destturf
var/turf/curturf = get_turf(teleatom)
if(precision)
var/list/posturfs = list()
var/center = get_turf(destination)
if(!center)
center = destination
for(var/turf/T in range(precision,center))
if(T.is_transition_turf())
continue // Avoid picking these.
var/area/A = T.loc
if(!A.noteleport)
posturfs.Add(T)
destturf = safepick(posturfs)
else
destturf = get_turf(destination)
destturf = get_teleport_turf(get_turf(destination), precision)
if(!destturf || !curturf || destturf.is_transition_turf())
return 0
@@ -124,13 +109,16 @@
return 0
playSpecials(curturf,effectin,soundin)
if(force_teleport)
teleatom.forceMove(destturf)
if(ismegafauna(teleatom))
message_admins("[teleatom] [ADMIN_FLW(teleatom)] has teleported from [ADMIN_COORDJMP(curturf)] to [ADMIN_COORDJMP(destturf)].")
playSpecials(destturf,effectout,soundout)
else
if(teleatom.Move(destturf))
playSpecials(destturf,effectout,soundout)
if(ismegafauna(teleatom))
message_admins("[teleatom] [ADMIN_FLW(teleatom)] has teleported from [ADMIN_COORDJMP(curturf)] to [ADMIN_COORDJMP(destturf)].")
return 1
/datum/teleport/proc/teleport()
@@ -225,3 +213,18 @@
// DING! You have passed the gauntlet, and are "probably" safe.
return F
/proc/get_teleport_turfs(turf/center, precision = 0)
if(!precision)
return list(center)
var/list/posturfs = list()
for(var/turf/T in range(precision,center))
if(T.is_transition_turf())
continue // Avoid picking these.
var/area/A = T.loc
if(!A.noteleport)
posturfs.Add(T)
return posturfs
/proc/get_teleport_turf(turf/center, precision = 0)
return safepick(get_teleport_turfs(center, precision))
+141 -141
View File
@@ -1,143 +1,143 @@
//used for holding information about unique properties of maps
//feed it json files that match the datum layout
//defaults to box
// -Cyberboss
/datum/map_config
var/config_filename = "_maps/tgstation2.json"
var/map_name = "Box Station"
var/map_path = "map_files/TgStation"
var/map_file = "tgstation.2.1.3.dmm"
var/minetype = "lavaland"
//used for holding information about unique properties of maps
//feed it json files that match the datum layout
//defaults to box
// -Cyberboss
/datum/map_config
var/config_filename = "_maps/boxstation.json"
var/map_name = "Box Station"
var/map_path = "map_files/BoxStation"
var/map_file = "BoxStation.dmm"
var/minetype = "lavaland"
var/list/transition_config = list(CENTCOMM = SELFLOOPING,
MAIN_STATION = CROSSLINKED,
EMPTY_AREA_1 = CROSSLINKED,
EMPTY_AREA_2 = CROSSLINKED,
MINING = SELFLOOPING,
EMPTY_AREA_3 = CROSSLINKED,
EMPTY_AREA_4 = CROSSLINKED,
EMPTY_AREA_5 = CROSSLINKED,
EMPTY_AREA_6 = CROSSLINKED,
EMPTY_AREA_7 = CROSSLINKED,
EMPTY_AREA_8 = CROSSLINKED)
var/defaulted = TRUE //if New failed
var/config_max_users = 0
var/config_min_users = 0
var/voteweight = 1
/datum/map_config/New(filename = "data/next_map.json", default_to_box, delete_after)
if(default_to_box)
return
LoadConfig(filename)
if(delete_after)
fdel(filename)
/datum/map_config/proc/LoadConfig(filename)
if(!fexists(filename))
log_world("map_config not found: [filename]")
return
var/json = file(filename)
if(!json)
log_world("Could not open map_config: [filename]")
return
json = file2text(json)
if(!json)
log_world("map_config is not text: [filename]")
return
json = json_decode(json)
if(!json)
log_world("map_config is not json: [filename]")
return
if(!ValidateJSON(json))
log_world("map_config failed to validate for above reason: [filename]")
return
config_filename = filename
map_name = json["map_name"]
map_path = json["map_path"]
map_file = json["map_file"]
minetype = json["minetype"]
var/list/jtcl = json["transition_config"]
if(jtcl != "default")
transition_config.Cut()
for(var/I in jtcl)
transition_config[TransitionStringToEnum(I)] = TransitionStringToEnum(jtcl[I])
defaulted = FALSE
#define CHECK_EXISTS(X) if(!istext(json[X])) { log_world(X + "missing from json!"); return; }
/datum/map_config/proc/ValidateJSON(list/json)
CHECK_EXISTS("map_name")
CHECK_EXISTS("map_path")
CHECK_EXISTS("map_file")
CHECK_EXISTS("minetype")
CHECK_EXISTS("transition_config")
var/path = GetFullMapPath(json["map_path"], json["map_file"])
if(!fexists(path))
log_world("Map file ([path]) does not exist!")
return
if(json["transition_config"] != "default")
if(!islist(json["transition_config"]))
log_world("transition_config is not a list!")
return
var/list/jtcl = json["transition_config"]
for(var/I in jtcl)
if(isnull(TransitionStringToEnum(I)))
log_world("Invalid transition_config option: [I]!")
if(isnull(TransitionStringToEnum(jtcl[I])))
log_world("Invalid transition_config option: [I]!")
return TRUE
#undef CHECK_EXISTS
/datum/map_config/proc/TransitionStringToEnum(string)
switch(string)
if("CROSSLINKED")
return CROSSLINKED
if("SELFLOOPING")
return SELFLOOPING
if("UNAFFECTED")
return UNAFFECTED
if("MAIN_STATION")
return MAIN_STATION
if("CENTCOMM")
return CENTCOMM
if("MINING")
return MINING
if("EMPTY_AREA_1")
return EMPTY_AREA_1
if("EMPTY_AREA_2")
return EMPTY_AREA_2
if("EMPTY_AREA_3")
return EMPTY_AREA_3
if("EMPTY_AREA_4")
return EMPTY_AREA_4
if("EMPTY_AREA_5")
return EMPTY_AREA_5
if("EMPTY_AREA_6")
return EMPTY_AREA_6
if("EMPTY_AREA_7")
return EMPTY_AREA_7
if("EMPTY_AREA_8")
return EMPTY_AREA_8
/datum/map_config/proc/GetFullMapPath(mp = map_path, mf = map_file)
return "_maps/[mp]/[mf]"
/datum/map_config/proc/MakeNextMap()
return config_filename == "data/next_map.json" || fcopy(config_filename, "data/next_map.json")
EMPTY_AREA_1 = CROSSLINKED,
EMPTY_AREA_2 = CROSSLINKED,
MINING = SELFLOOPING,
EMPTY_AREA_3 = CROSSLINKED,
EMPTY_AREA_4 = CROSSLINKED,
EMPTY_AREA_5 = CROSSLINKED,
EMPTY_AREA_6 = CROSSLINKED,
EMPTY_AREA_7 = CROSSLINKED,
EMPTY_AREA_8 = CROSSLINKED)
var/defaulted = TRUE //if New failed
var/config_max_users = 0
var/config_min_users = 0
var/voteweight = 1
/datum/map_config/New(filename = "data/next_map.json", default_to_box, delete_after)
if(default_to_box)
return
LoadConfig(filename)
if(delete_after)
fdel(filename)
/datum/map_config/proc/LoadConfig(filename)
if(!fexists(filename))
log_world("map_config not found: [filename]")
return
var/json = file(filename)
if(!json)
log_world("Could not open map_config: [filename]")
return
json = file2text(json)
if(!json)
log_world("map_config is not text: [filename]")
return
json = json_decode(json)
if(!json)
log_world("map_config is not json: [filename]")
return
if(!ValidateJSON(json))
log_world("map_config failed to validate for above reason: [filename]")
return
config_filename = filename
map_name = json["map_name"]
map_path = json["map_path"]
map_file = json["map_file"]
minetype = json["minetype"]
var/list/jtcl = json["transition_config"]
if(jtcl != "default")
transition_config.Cut()
for(var/I in jtcl)
transition_config[TransitionStringToEnum(I)] = TransitionStringToEnum(jtcl[I])
defaulted = FALSE
#define CHECK_EXISTS(X) if(!istext(json[X])) { log_world(X + "missing from json!"); return; }
/datum/map_config/proc/ValidateJSON(list/json)
CHECK_EXISTS("map_name")
CHECK_EXISTS("map_path")
CHECK_EXISTS("map_file")
CHECK_EXISTS("minetype")
CHECK_EXISTS("transition_config")
var/path = GetFullMapPath(json["map_path"], json["map_file"])
if(!fexists(path))
log_world("Map file ([path]) does not exist!")
return
if(json["transition_config"] != "default")
if(!islist(json["transition_config"]))
log_world("transition_config is not a list!")
return
var/list/jtcl = json["transition_config"]
for(var/I in jtcl)
if(isnull(TransitionStringToEnum(I)))
log_world("Invalid transition_config option: [I]!")
if(isnull(TransitionStringToEnum(jtcl[I])))
log_world("Invalid transition_config option: [I]!")
return TRUE
#undef CHECK_EXISTS
/datum/map_config/proc/TransitionStringToEnum(string)
switch(string)
if("CROSSLINKED")
return CROSSLINKED
if("SELFLOOPING")
return SELFLOOPING
if("UNAFFECTED")
return UNAFFECTED
if("MAIN_STATION")
return MAIN_STATION
if("CENTCOMM")
return CENTCOMM
if("MINING")
return MINING
if("EMPTY_AREA_1")
return EMPTY_AREA_1
if("EMPTY_AREA_2")
return EMPTY_AREA_2
if("EMPTY_AREA_3")
return EMPTY_AREA_3
if("EMPTY_AREA_4")
return EMPTY_AREA_4
if("EMPTY_AREA_5")
return EMPTY_AREA_5
if("EMPTY_AREA_6")
return EMPTY_AREA_6
if("EMPTY_AREA_7")
return EMPTY_AREA_7
if("EMPTY_AREA_8")
return EMPTY_AREA_8
/datum/map_config/proc/GetFullMapPath(mp = map_path, mf = map_file)
return "_maps/[mp]/[mf]"
/datum/map_config/proc/MakeNextMap()
return config_filename == "data/next_map.json" || fcopy(config_filename, "data/next_map.json")
+34 -14
View File
@@ -2,13 +2,12 @@
var/name = "Martial Art"
var/streak = ""
var/max_streak_length = 6
var/current_target = null
var/temporary = 0
var/datum/martial_art/base = null // The permanent style
var/current_target
var/datum/martial_art/base // The permanent style. This will be null unless the martial art is temporary
var/deflection_chance = 0 //Chance to deflect projectiles
var/block_chance = 0 //Chance to block melee attacks using items while on throw mode.
var/restraining = 0 //used in cqc's disarm_act to check if the disarmed is being restrained and so whether they should be put in a chokehold or not
var/help_verb = null
var/help_verb
var/no_guns = FALSE
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
@@ -68,28 +67,49 @@
add_logs(A, D, "punched")
if((D.stat != DEAD) && damage >= A.dna.species.punchstunthreshold)
D.visible_message("<span class='danger'>[A] has weakened [D]!!</span>", \
"<span class='userdanger'>[A] has weakened [D]!</span>")
D.apply_effect(4, WEAKEN, armor_block)
D.visible_message("<span class='danger'>[A] has knocked [D] down!!</span>", \
"<span class='userdanger'>[A] has knocked [D] down!</span>")
D.apply_effect(40, KNOCKDOWN, armor_block)
D.forcesay(GLOB.hit_appends)
else if(D.lying)
D.forcesay(GLOB.hit_appends)
return 1
/datum/martial_art/proc/teach(mob/living/carbon/human/H,make_temporary=0)
if(make_temporary)
temporary = 1
if(temporary && H.mind.martial_art)
if(!H.mind.martial_art.allow_temp_override)
return
base = H.mind.martial_art
if(H.mind.martial_art)
if(make_temporary)
if(!H.mind.martial_art.allow_temp_override)
return FALSE
store(H.mind.martial_art,H)
else
H.mind.martial_art.on_remove(H)
if(H.mind.martial_art != H.mind.default_martial_art && !H.mind.martial_art.base)
QDEL_NULL(H.mind.martial_art)
else if(make_temporary)
base = H.mind.default_martial_art
if(help_verb)
H.verbs += help_verb
H.mind.martial_art = src
return TRUE
/datum/martial_art/proc/store(datum/martial_art/M,mob/living/carbon/human/H)
if(H.mind && base)
if(H.mind.default_martial_art != base && !base.base)
QDEL_NULL(base)
M.on_remove(H)
base = M
/datum/martial_art/proc/remove(mob/living/carbon/human/H)
if(H.mind.martial_art != src)
return
H.mind.martial_art = base
on_remove(H)
if(base)
base.teach(H)
else
var/datum/martial_art/X = H.mind.default_martial_art
X.teach(H)
/datum/martial_art/proc/on_remove(mob/living/carbon/human/H)
if(help_verb)
H.verbs -= help_verb
return
+2 -2
View File
@@ -39,8 +39,8 @@
if((D.stat != DEAD) && prob(knockout_prob))
D.visible_message("<span class='danger'>[A] has knocked [D] out with a haymaker!</span>", \
"<span class='userdanger'>[A] has knocked [D] out with a haymaker!</span>")
D.apply_effect(10,WEAKEN,armor_block)
D.SetSleeping(5)
D.apply_effect(200,KNOCKDOWN,armor_block)
D.SetSleeping(100)
D.forcesay(GLOB.hit_appends)
add_logs(A, D, "knocked out (boxing) ")
else if(D.lying)
+13 -13
View File
@@ -35,17 +35,17 @@
return 0
/datum/martial_art/cqc/proc/Slam(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.stat || !D.weakened)
if(!D.stat || !D.IsKnockdown())
D.visible_message("<span class='warning'>[A] slams [D] into the ground!</span>", \
"<span class='userdanger'>[A] slams you into the ground!</span>")
playsound(get_turf(A), 'sound/weapons/slam.ogg', 50, 1, -1)
D.apply_damage(10, BRUTE)
D.Weaken(6)
D.Knockdown(120)
add_logs(A, D, "cqc slammed")
return 1
/datum/martial_art/cqc/proc/Kick(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.stat || !D.weakened)
if(!D.stat || !D.IsKnockdown())
D.visible_message("<span class='warning'>[A] kicks [D] back!</span>", \
"<span class='userdanger'>[A] kicks you back!</span>")
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
@@ -53,11 +53,11 @@
D.throw_at(throw_target, 1, 14, A)
D.apply_damage(10, BRUTE)
add_logs(A, D, "cqc kicked")
if(D.weakened && !D.stat)
if(D.IsKnockdown() && !D.stat)
D.visible_message("<span class='warning'>[A] kicks [D]'s head, knocking them out!</span>", \
"<span class='userdanger'>[A] kicks your head, knocking you out!</span>")
playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1)
D.SetSleeping(15)
D.SetSleeping(300)
D.adjustBrainLoss(25)
return 1
@@ -74,7 +74,7 @@
D.visible_message("<span class='warning'>[A] locks [D] into a restraining position!</span>", \
"<span class='userdanger'>[A] locks you into a restraining position!</span>")
D.adjustStaminaLoss(20)
D.Stun(5)
D.Stun(100)
restraining = 1
addtimer(CALLBACK(src, .proc/drop_restraining), 50, TIMER_UNIQUE)
return 1
@@ -114,7 +114,7 @@
A.do_attack_animation(D)
var/picked_hit_type = pick("CQC'd", "Big Bossed")
var/bonus_damage = 13
if(D.weakened || D.resting || D.lying)
if(D.IsKnockdown() || D.resting || D.lying)
bonus_damage += 5
picked_hit_type = "stomps on"
D.apply_damage(bonus_damage, BRUTE)
@@ -125,12 +125,12 @@
D.visible_message("<span class='danger'>[A] [picked_hit_type] [D]!</span>", \
"<span class='userdanger'>[A] [picked_hit_type] you!</span>")
add_logs(A, D, "[picked_hit_type] with CQC")
if(A.resting && !D.stat && !D.weakened)
if(A.resting && !D.stat && !D.IsKnockdown())
D.visible_message("<span class='warning'>[A] leg sweeps [D]!", \
"<span class='userdanger'>[A] leg sweeps you!</span>")
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1)
D.apply_damage(10, BRUTE)
D.Weaken(3)
D.Knockdown(60)
add_logs(A, D, "cqc sweeped")
return 1
@@ -140,7 +140,7 @@
if(check_streak(A,D))
return 1
if(prob(65))
if(!D.stat || !D.weakened || !restraining)
if(!D.stat || !D.IsKnockdown() || !restraining)
I = D.get_active_held_item()
D.visible_message("<span class='warning'>[A] strikes [D]'s jaw with their hand!</span>", \
"<span class='userdanger'>[A] strikes your jaw, disorienting you!</span>")
@@ -157,7 +157,7 @@
if(restraining && A.pulling == D)
D.visible_message("<span class='danger'>[A] puts [D] into a chokehold!</span>", \
"<span class='userdanger'>[A] puts you into a chokehold!</span>")
D.SetSleeping(20)
D.SetSleeping(400)
restraining = 0
if(A.grab_state < GRAB_NECK)
A.grab_state = GRAB_NECK
@@ -173,8 +173,8 @@
to_chat(usr, "<b><i>You try to remember some of the basics of CQC.</i></b>")
to_chat(usr, "<span class='notice'>Slam</span>: Grab Harm. Slam opponent into the ground, weakens and knocks down.")
to_chat(usr, "<span class='notice'>CQC Kick</span>: Harm Disarm Harm. Knocks opponent away. Knocks out stunned or weakened opponents.")
to_chat(usr, "<span class='notice'>Slam</span>: Grab Harm. Slam opponent into the ground, knocking them down.")
to_chat(usr, "<span class='notice'>CQC Kick</span>: Harm Disarm Harm. Knocks opponent away. Knocks out stunned or knocked down opponents.")
to_chat(usr, "<span class='notice'>Restrain</span>: Grab Grab. Locks opponents into a restraining position, disarm to knock them out with a choke hold.")
to_chat(usr, "<span class='notice'>Pressure</span>: Disarm Grab. Decent stamina damage.")
to_chat(usr, "<span class='notice'>Consecutive CQC</span>: Disarm Disarm Harm. Mainly offensive move, huge damage and decent stamina damage.")
+11 -12
View File
@@ -52,16 +52,15 @@
owner.visible_message("<span class='danger'>[owner] assumes the Lung Punch stance!</span>", "<b><i>Your next attack will be a Lung Punch.</i></b>")
H.mind.martial_art.streak = "quick_choke"//internal name for lung punch
/datum/martial_art/krav_maga/teach(var/mob/living/carbon/human/H,var/make_temporary=0)
..()
to_chat(H, "<span class = 'userdanger'>You know the arts of Krav Maga!</span>")
to_chat(H, "<span class = 'danger'>Place your cursor over a move at the top of the screen to see what it does.</span>")
neckchop.Grant(H)
legsweep.Grant(H)
lungpunch.Grant(H)
/datum/martial_art/krav_maga/teach(mob/living/carbon/human/H,make_temporary=0)
if(..())
to_chat(H, "<span class = 'userdanger'>You know the arts of Krav Maga!</span>")
to_chat(H, "<span class = 'danger'>Place your cursor over a move at the top of the screen to see what it does.</span>")
neckchop.Grant(H)
legsweep.Grant(H)
lungpunch.Grant(H)
/datum/martial_art/krav_maga/remove(var/mob/living/carbon/human/H)
..()
/datum/martial_art/krav_maga/on_remove(mob/living/carbon/human/H)
to_chat(H, "<span class = 'userdanger'>You suddenly forget the arts of Krav Maga...</span>")
neckchop.Remove(H)
legsweep.Remove(H)
@@ -84,13 +83,13 @@
return 0
/datum/martial_art/krav_maga/proc/leg_sweep(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
if(D.stat || D.weakened)
if(D.stat || D.IsKnockdown())
return 0
D.visible_message("<span class='warning'>[A] leg sweeps [D]!</span>", \
"<span class='userdanger'>[A] leg sweeps you!</span>")
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1)
D.apply_damage(5, BRUTE)
D.Weaken(2)
D.Knockdown(40)
add_logs(A, D, "leg sweeped")
return 1
@@ -126,7 +125,7 @@
add_logs(A, D, "punched")
var/picked_hit_type = pick("punches", "kicks")
var/bonus_damage = 10
if(D.weakened || D.resting || D.lying)
if(D.IsKnockdown() || D.resting || D.lying)
bonus_damage += 5
picked_hit_type = "stomps on"
D.apply_damage(bonus_damage, BRUTE)
+15 -15
View File
@@ -35,7 +35,7 @@
return 0
/datum/martial_art/the_sleeping_carp/proc/wristWrench(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.stat && !D.stunned && !D.weakened)
if(!D.stat && !D.IsStun() && !D.IsKnockdown())
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
D.visible_message("<span class='warning'>[A] grabs [D]'s wrist and wrenches it sideways!</span>", \
"<span class='userdanger'>[A] grabs your wrist and violently wrenches it to the side!</span>")
@@ -43,51 +43,51 @@
D.emote("scream")
D.drop_item()
D.apply_damage(5, BRUTE, pick("l_arm", "r_arm"))
D.Stun(3)
D.Stun(60)
return 1
add_logs(A, D, "wrist wrenched (Sleeping Carp)")
return basic_hit(A,D)
/datum/martial_art/the_sleeping_carp/proc/backKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(A.dir == D.dir && !D.stat && !D.weakened)
if(A.dir == D.dir && !D.stat && !D.IsKnockdown())
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
D.visible_message("<span class='warning'>[A] kicks [D] in the back!</span>", \
"<span class='userdanger'>[A] kicks you in the back, making you stumble and fall!</span>")
step_to(D,get_step(D,D.dir),1)
D.Weaken(4)
D.Knockdown(80)
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
return 1
add_logs(A, D, "back-kicked (Sleeping Carp)")
return basic_hit(A,D)
/datum/martial_art/the_sleeping_carp/proc/kneeStomach(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.stat && !D.weakened)
if(!D.stat && !D.IsKnockdown())
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
D.visible_message("<span class='warning'>[A] knees [D] in the stomach!</span>", \
"<span class='userdanger'>[A] winds you with a knee in the stomach!</span>")
D.audible_message("<b>[D]</b> gags!")
D.losebreath += 3
D.Stun(2)
D.Stun(40)
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
return 1
add_logs(A, D, "stomach kneed (Sleeping Carp)")
return basic_hit(A,D)
/datum/martial_art/the_sleeping_carp/proc/headKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(!D.stat && !D.weakened)
if(!D.stat && !D.IsKnockdown())
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
D.visible_message("<span class='warning'>[A] kicks [D] in the head!</span>", \
"<span class='userdanger'>[A] kicks you in the jaw!</span>")
D.apply_damage(20, BRUTE, "head")
D.drop_item()
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
D.Stun(4)
D.Stun(80)
return 1
add_logs(A, D, "head kicked (Sleeping Carp)")
return basic_hit(A,D)
/datum/martial_art/the_sleeping_carp/proc/elbowDrop(mob/living/carbon/human/A, mob/living/carbon/human/D)
if(D.weakened || D.resting || D.stat)
if(D.IsKnockdown() || D.resting || D.stat)
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
D.visible_message("<span class='warning'>[A] elbow drops [D]!</span>", \
"<span class='userdanger'>[A] piledrives you with their elbow!</span>")
@@ -130,7 +130,7 @@
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 25, 1, -1)
if(prob(D.getBruteLoss()) && !D.lying)
D.visible_message("<span class='warning'>[D] stumbles and falls!</span>", "<span class='userdanger'>The blow sends you to the ground!</span>")
D.Weaken(4)
D.Knockdown(80)
add_logs(A, D, "[atk_verb] (Sleeping Carp)")
return 1
@@ -196,7 +196,7 @@
add_fingerprint(user)
if((CLUMSY in user.disabilities) && prob(50))
to_chat(user, "<span class ='warning'>You club yourself over the head with [src].</span>")
user.Weaken(3)
user.Knockdown(60)
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.apply_damage(2*force, BRUTE, "head")
@@ -230,18 +230,18 @@
if(prob(10))
H.visible_message("<span class='warning'>[H] collapses!</span>", \
"<span class='userdanger'>Your legs give out!</span>")
H.Weaken(4)
if(H.staminaloss && !H.sleeping)
H.Knockdown(80)
if(H.staminaloss && !H.IsSleeping())
var/total_health = (H.health - H.staminaloss)
if(total_health <= HEALTH_THRESHOLD_CRIT && !H.stat)
H.visible_message("<span class='warning'>[user] delivers a heavy hit to [H]'s head, knocking them out cold!</span>", \
"<span class='userdanger'>[user] knocks you unconscious!</span>")
H.SetSleeping(30)
H.SetSleeping(600)
H.adjustBrainLoss(25)
else
return ..()
/obj/item/weapon/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
/obj/item/weapon/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(wielded)
return ..()
return 0
+18 -21
View File
@@ -100,18 +100,17 @@
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "drop"
/datum/martial_art/wrestling/teach(var/mob/living/carbon/human/H,var/make_temporary=0)
..()
to_chat(H, "<span class = 'userdanger'>SNAP INTO A THIN TIM!</span>")
to_chat(H, "<span class = 'danger'>Place your cursor over a move at the top of the screen to see what it does.</span>")
drop.Grant(H)
kick.Grant(H)
slam.Grant(H)
throw_wrassle.Grant(H)
strike.Grant(H)
/datum/martial_art/wrestling/teach(mob/living/carbon/human/H,make_temporary=0)
if(..())
to_chat(H, "<span class = 'userdanger'>SNAP INTO A THIN TIM!</span>")
to_chat(H, "<span class = 'danger'>Place your cursor over a move at the top of the screen to see what it does.</span>")
drop.Grant(H)
kick.Grant(H)
slam.Grant(H)
throw_wrassle.Grant(H)
strike.Grant(H)
/datum/martial_art/wrestling/remove(var/mob/living/carbon/human/H)
..()
/datum/martial_art/wrestling/on_remove(mob/living/carbon/human/H)
to_chat(H, "<span class = 'userdanger'>You no longer feel that the tower of power is too sweet to be sour...</span>")
drop.Remove(H)
kick.Remove(H)
@@ -134,7 +133,7 @@
D.forceMove(A.loc)
D.setDir(get_dir(D, A))
D.Stun(4)
D.Stun(80)
A.visible_message("<span class = 'danger'><B>[A] starts spinning around with [D]!</B></span>")
A.emote("scream")
@@ -192,7 +191,7 @@
if (T && isturf(T))
if (!D.stat)
D.emote("scream")
D.throw_at(T, 10, 4, callback = CALLBACK(D, /mob/living/carbon/human/.Weaken, 2))
D.throw_at(T, 10, 4, callback = CALLBACK(D, /mob/living/carbon/human/.Knockdown, 20))
add_logs(A, D, "has thrown with wrestling")
return 0
@@ -288,8 +287,7 @@
playsound(A.loc, "swing_hit", 50, 1)
if (!D.stat)
D.emote("scream")
D.weakened += 2
D.stunned += 2
D.Knockdown(40)
switch(rand(1,3))
if (2)
@@ -331,7 +329,7 @@
A.visible_message("<span class = 'danger'><b>[A] headbutts [D]!</b></span>")
D.adjustBruteLoss(rand(10,20))
playsound(A.loc, "swing_hit", 50, 1)
D.Paralyse(1)
D.Unconscious(20)
add_logs(A, D, "headbutted")
/datum/martial_art/wrestling/proc/kick(mob/living/carbon/human/A, mob/living/carbon/human/D)
@@ -347,7 +345,7 @@
var/turf/T = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
if (T && isturf(T))
D.Weaken(1)
D.Knockdown(20)
D.throw_at(T, 3, 2)
add_logs(A, D, "roundhouse-kicked")
@@ -383,7 +381,7 @@
if (falling == 1)
A.visible_message("<span class = 'danger'><B>...and dives head-first into the ground, ouch!</b></span>")
A.adjustBruteLoss(rand(10,20))
A.Weaken(3)
A.Knockdown(60)
to_chat(A, "[D] is too far away!")
return 0
@@ -412,8 +410,7 @@
else
D.adjustBruteLoss(rand(20,30))
D.Weaken(1)
D.Stun(2)
D.Knockdown(40)
A.pixel_y = 0
@@ -437,7 +434,7 @@
A.start_pulling(D)
D.visible_message("<span class='danger'>[A] gets [D] in a cinch!</span>", \
"<span class='userdanger'>[A] gets [D] in a cinch!</span>")
D.Stun(rand(3,5))
D.Stun(rand(60,100))
add_logs(A, D, "cinched")
return 1
+14 -5
View File
@@ -50,7 +50,7 @@
var/datum/faction/faction //associated faction
var/datum/changeling/changeling //changeling holder
var/linglink
var/datum/martial_art/martial_art = null
var/datum/martial_art/martial_art
var/static/default_martial_art = new/datum/martial_art
var/miming = 0 // Mime's vow of silence
var/list/antag_datums
@@ -117,7 +117,7 @@
C.last_mind = src
transfer_antag_huds(hud_to_transfer) //inherit the antag HUD
transfer_actions(new_character)
transfer_martial_arts(new_character)
if(active || force_key_move)
new_character.key = key //now transfer the key to link the client to our new body
@@ -147,6 +147,7 @@
A.on_removal()
return TRUE
/datum/mind/proc/remove_all_antag_datums() //For the Lazy amongst us.
for(var/a in antag_datums)
var/datum/antagonist/A = a
@@ -317,7 +318,6 @@
if(!silent) to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [P.traitor_unlock_degrees] from its starting position to unlock its hidden features.")
traitor_mob.mind.store_memory("<B>Uplink Degrees:</B> [P.traitor_unlock_degrees] ([P.name]).")
//Link a new mobs mind to the creator of said mob. They will join any team they are currently on, and will only switch teams when their creator does.
/datum/mind/proc/enslave_mind_to_creator(mob/living/creator)
@@ -1149,7 +1149,7 @@
to_chat(usr, "<span class='notice'>The objectives for changeling [key] have been generated. You can edit them and anounce manually.</span>")
if("initialdna")
if( !changeling || !changeling.stored_profiles.len || !istype(current, /mob/living/carbon))
if( !changeling || !changeling.stored_profiles.len || !iscarbon(current))
to_chat(usr, "<span class='danger'>Resetting DNA failed!</span>")
else
var/mob/living/carbon/C = current
@@ -1234,7 +1234,6 @@
traitordatum.forge_traitor_objectives()
to_chat(usr, "<span class='notice'>The objectives for traitor [key] have been generated. You can edit them and anounce manually.</span>")
else if(href_list["devil"])
var/datum/antagonist/devil/devilinfo = has_antag_datum(ANTAG_DATUM_DEVIL)
switch(href_list["devil"])
@@ -1624,6 +1623,15 @@
spell_list -= S
qdel(S)
/datum/mind/proc/transfer_martial_arts(mob/living/new_character)
if(!ishuman(new_character))
return
if(martial_art)
if(martial_art.base) //Is the martial art temporary?
martial_art.remove(new_character)
else
martial_art.teach(new_character)
/datum/mind/proc/transfer_actions(mob/living/new_character)
if(current && current.actions)
for(var/datum/action/A in current.actions)
@@ -1642,6 +1650,7 @@
if(istype(S, type))
continue
S.charge_counter = delay
S.updateButtonIcon()
INVOKE_ASYNC(S, /obj/effect/proc_holder/spell.proc/start_recharge)
/datum/mind/proc/get_ghost(even_if_they_cant_reenter)
+8 -11
View File
@@ -126,7 +126,7 @@ GLOBAL_LIST_EMPTY(mutations_list)
/datum/mutation/human/hulk/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
var/status = CANSTUN | CANWEAKEN | CANPARALYSE | CANPUSH
var/status = CANSTUN | CANKNOCKDOWN | CANUNCONSCIOUS | CANPUSH
owner.status_flags &= ~status
owner.update_body_parts()
@@ -142,7 +142,7 @@ GLOBAL_LIST_EMPTY(mutations_list)
/datum/mutation/human/hulk/on_losing(mob/living/carbon/human/owner)
if(..())
return
owner.status_flags |= CANSTUN | CANWEAKEN | CANPARALYSE | CANPUSH
owner.status_flags |= CANSTUN | CANKNOCKDOWN | CANUNCONSCIOUS | CANPUSH
owner.update_body_parts()
/datum/mutation/human/hulk/say_mod(message)
@@ -233,9 +233,9 @@ GLOBAL_LIST_EMPTY(mutations_list)
text_gain_indication = "<span class='danger'>You get a headache.</span>"
/datum/mutation/human/epilepsy/on_life(mob/living/carbon/human/owner)
if(prob(1) && !owner.paralysis)
if(prob(1) && owner.stat == CONSCIOUS)
owner.visible_message("<span class='danger'>[owner] starts having a seizure!</span>", "<span class='userdanger'>You have a seizure!</span>")
owner.Paralyse(10)
owner.Unconscious(200)
owner.Jitter(1000)
addtimer(CALLBACK(src, .proc/jitter_less, owner), 90)
@@ -269,7 +269,7 @@ GLOBAL_LIST_EMPTY(mutations_list)
text_gain_indication = "<span class='danger'>You start coughing.</span>"
/datum/mutation/human/cough/on_life(mob/living/carbon/human/owner)
if((prob(5) && owner.paralysis <= 1))
if(prob(5) && owner.stat == CONSCIOUS)
owner.drop_item()
owner.emote("cough")
@@ -317,8 +317,8 @@ GLOBAL_LIST_EMPTY(mutations_list)
text_gain_indication = "<span class='danger'>You twitch.</span>"
/datum/mutation/human/tourettes/on_life(mob/living/carbon/human/owner)
if((prob(10) && owner.paralysis <= 1))
owner.Stun(10)
if(prob(10) && owner.stat == CONSCIOUS)
owner.Stun(200)
switch(rand(1, 3))
if(1)
owner.emote("twitch")
@@ -377,9 +377,6 @@ GLOBAL_LIST_EMPTY(mutations_list)
time_coeff = 2
/datum/mutation/human/race/on_acquiring(mob/living/carbon/human/owner)
if(owner.has_brain_worms())
to_chat(owner, "<span class='warning'>You feel something strongly clinging to your humanity!</span>")
return
if(..())
return
. = owner.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
@@ -412,7 +409,7 @@ GLOBAL_LIST_EMPTY(mutations_list)
if(proximity) //stops tk from breaking chameleon
owner.alpha = CHAMELEON_MUTATION_DEFAULT_TRANSPARENCY
return
/datum/mutation/human/chameleon/on_losing(mob/living/carbon/human/owner)
if(..())
return
+8 -8
View File
@@ -305,7 +305,7 @@
/datum/riding/human/ride_check(mob/living/M)
var/mob/living/carbon/human/H = ridden //IF this runtimes I'm blaming the admins.
if(M.incapacitated(FALSE, TRUE) || H.incapacitated(FALSE, TRUE))
M.visible_message("<span class='boldwarning'>[M] falls off of [ridden]!</span>")
M.visible_message("<span class='warning'>[M] falls off [ridden]!</span>")
Unbuckle(M)
return FALSE
if(M.restrained(TRUE))
@@ -318,6 +318,7 @@
/datum/riding/human/get_offsets(pass_index) // list(dir = x, y, layer)
return list("[NORTH]" = list(0, 6), "[SOUTH]" = list(0, 6), "[EAST]" = list(-6, 4), "[WEST]" = list( 6, 4))
/datum/riding/human/handle_vehicle_layer()
if(ridden.buckled_mobs && ridden.buckled_mobs.len)
if(ridden.dir == SOUTH)
@@ -329,9 +330,8 @@
/datum/riding/human/force_dismount(mob/living/user)
ridden.unbuckle_mob(user)
user.Weaken(3)
user.Stun(3)
user.visible_message("<span class='boldwarning'>[ridden] pushes [user] off of them!</span>")
user.Knockdown(60)
user.visible_message("<span class='warning'>[ridden] pushes [user] off of them!</span>")
/datum/riding/cyborg
keytype = null
@@ -339,7 +339,7 @@
/datum/riding/cyborg/ride_check(mob/user)
if(user.incapacitated())
var/kick = TRUE
if(istype(ridden, /mob/living/silicon/robot))
if(iscyborg(ridden))
var/mob/living/silicon/robot/R = ridden
if(R.module && R.module.ride_allow_incapacitated)
kick = FALSE
@@ -347,7 +347,7 @@
to_chat(user, "<span class='userdanger'>You fall off of [ridden]!</span>")
Unbuckle(user)
return
if(istype(user, /mob/living/carbon))
if(iscarbon(user))
var/mob/living/carbon/carbonuser = user
if(!carbonuser.get_num_arms())
Unbuckle(user)
@@ -383,9 +383,9 @@
var/turf/target = get_edge_target_turf(ridden, ridden.dir)
var/turf/targetm = get_step(get_turf(ridden), ridden.dir)
M.Move(targetm)
M.visible_message("<span class='boldwarning'>[M] is thrown clear of [ridden]!</span>")
M.visible_message("<span class='warning'>[M] is thrown clear of [ridden]!</span>")
M.throw_at(target, 14, 5, ridden)
M.Weaken(3)
M.Knockdown(60)
/datum/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1)
var/amount_equipped = 0
+1 -1
View File
@@ -6,7 +6,7 @@
How is there a wooden container filled with 18th century coinage in the middle of a lavawracked hellscape? \
It is clearly a mystery."
var/cost = null
var/cost = null //negative numbers will always be placed, with lower (negative) numbers being placed first; positive and 0 numbers will be placed randomly
var/allow_duplicates = TRUE
var/prefix = null
+17 -1
View File
@@ -120,9 +120,25 @@
id = "hierophant"
description = "A strange, square chunk of metal of massive size. Inside awaits only death and many, many squares."
suffix = "lavaland_surface_hierophant.dmm"
cost = 0
cost = -1
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/blood_drunk_miner
name = "Blood-Drunk Miner"
id = "blooddrunk"
description = "A strange arrangement of stone tiles and an insane, beastly miner contemplating them."
suffix = "lavaland_surface_blooddrunk1.dmm"
cost = 0
allow_duplicates = FALSE //will only spawn one variant of the ruin
/datum/map_template/ruin/lavaland/blood_drunk_miner/guidance
name = "Blood-Drunk Miner (Guidance)"
suffix = "lavaland_surface_blooddrunk2.dmm"
/datum/map_template/ruin/lavaland/blood_drunk_miner/hunter
name = "Blood-Drunk Miner (Hunter)"
suffix = "lavaland_surface_blooddrunk3.dmm"
/datum/map_template/ruin/lavaland/ufo_crash
name = "UFO Crash"
id = "ufo-crash"
+133 -19
View File
@@ -12,7 +12,7 @@
/datum/status_effect/shadow_mend/on_apply()
owner.visible_message("<span class='notice'>Violet light wraps around [owner]'s body!</span>", "<span class='notice'>Violet light wraps around your body!</span>")
playsound(owner, 'sound/magic/Teleport_app.ogg', 50, 1)
playsound(owner, 'sound/magic/teleport_app.ogg', 50, 1)
return ..()
/datum/status_effect/shadow_mend/tick()
@@ -21,7 +21,7 @@
/datum/status_effect/shadow_mend/on_remove()
owner.visible_message("<span class='warning'>The violet light around [owner] glows black!</span>", "<span class='warning'>The tendrils around you cinch tightly and reap their toll...</span>")
playsound(owner, 'sound/magic/Teleport_diss.ogg', 50, 1)
playsound(owner, 'sound/magic/teleport_diss.ogg', 50, 1)
owner.apply_status_effect(STATUS_EFFECT_VOID_PRICE)
@@ -37,7 +37,7 @@
icon_state = "shadow_mend"
/datum/status_effect/void_price/tick()
owner << sound('sound/magic/Summon_Karp.ogg', volume = 25)
owner << sound('sound/magic/summon_karp.ogg', volume = 25)
owner.adjustBruteLoss(3)
@@ -60,8 +60,8 @@
if(istype(L)) //this is probably more safety than actually needed
var/vanguard = L.stun_absorption["vanguard"]
desc = initial(desc)
desc += "<br><b>[vanguard["stuns_absorbed"] * 2]</b> seconds of stuns held back.\
[GLOB.ratvar_awakens ? "":"<br><b>[round(min(vanguard["stuns_absorbed"] * 0.25, 20)) * 2]</b> seconds of stun will affect you."]"
desc += "<br><b>[Floor(vanguard["stuns_absorbed"] * 0.1)]</b> seconds of stuns held back.\
[GLOB.ratvar_awakens ? "":"<br><b>[Floor(min(vanguard["stuns_absorbed"] * 0.025, 20))]</b> seconds of stun will affect you."]"
..()
/datum/status_effect/vanguard_shield/Destroy()
@@ -70,11 +70,11 @@
return ..()
/datum/status_effect/vanguard_shield/on_apply()
add_logs(owner, null, "gained Vanguard stun immunity")
owner.log_message("gained Vanguard stun immunity", INDIVIDUAL_ATTACK_LOG)
owner.add_stun_absorption("vanguard", 200, 1, "'s yellow aura momentarily intensifies!", "Your ward absorbs the stun!", " radiating with a soft yellow light!")
owner.visible_message("<span class='warning'>[owner] begins to faintly glow!</span>", "<span class='brass'>You will absorb all stuns for the next twenty seconds.</span>")
owner.SetStunned(0, FALSE)
owner.SetWeakened(0)
owner.SetStun(0, FALSE)
owner.SetKnockdown(0)
progbar = new(owner, duration, owner)
progbar.bar.color = list("#FAE48C", "#FAE48C", "#FAE48C", rgb(0,0,0))
progbar.update(duration - world.time)
@@ -96,17 +96,16 @@
otheractiveabsorptions = TRUE
if(!GLOB.ratvar_awakens && stuns_blocked && !otheractiveabsorptions)
vanguard["end_time"] = 0 //so it doesn't absorb the stuns we're about to apply
owner.Stun(stuns_blocked)
owner.Weaken(stuns_blocked)
owner.Knockdown(stuns_blocked)
message_to_owner = "<span class='boldwarning'>The weight of the Vanguard's protection crashes down upon you!</span>"
if(stuns_blocked >= 15)
if(stuns_blocked >= 300)
message_to_owner += "\n<span class='userdanger'>You faint from the exertion!</span>"
stuns_blocked *= 2
owner.Paralyse(stuns_blocked)
owner.Unconscious(stuns_blocked)
else
stuns_blocked = 0 //so logging is correct in cases where there were stuns blocked but we didn't stun for other reasons
owner.visible_message("<span class='warning'>[owner]'s glowing aura fades!</span>", message_to_owner)
add_logs(owner, null, "lost Vanguard stun immunity[stuns_blocked ? "and was stunned for [stuns_blocked]":""]")
owner.log_message("lost Vanguard stun immunity[stuns_blocked ? "and was stunned for [stuns_blocked]":""]", INDIVIDUAL_ATTACK_LOG)
/datum/status_effect/inathneqs_endowment
@@ -121,7 +120,7 @@
alerttooltipstyle = "clockcult"
/datum/status_effect/inathneqs_endowment/on_apply()
add_logs(owner, null, "gained Inath-neq's invulnerability")
owner.log_message("gained Inath-neq's invulnerability", INDIVIDUAL_ATTACK_LOG)
owner.visible_message("<span class='warning'>[owner] shines with azure light!</span>", "<span class='notice'>You feel Inath-neq's power flow through you! You're invincible!</span>")
var/oldcolor = owner.color
owner.color = "#1E8CE1"
@@ -130,14 +129,14 @@
owner.status_flags |= GODMODE
animate(owner, color = oldcolor, time = 150, easing = EASE_IN)
addtimer(CALLBACK(owner, /atom/proc/update_atom_colour), 150)
playsound(owner, 'sound/magic/Ethereal_Enter.ogg', 50, 1)
playsound(owner, 'sound/magic/ethereal_enter.ogg', 50, 1)
return ..()
/datum/status_effect/inathneqs_endowment/on_remove()
add_logs(owner, null, "lost Inath-neq's invulnerability")
owner.log_message("lost Inath-neq's invulnerability", INDIVIDUAL_ATTACK_LOG)
owner.visible_message("<span class='warning'>The light around [owner] flickers and dissipates!</span>", "<span class='boldwarning'>You feel Inath-neq's power fade from your body!</span>")
owner.status_flags &= ~GODMODE
playsound(owner, 'sound/magic/Ethereal_Exit.ogg', 50, 1)
playsound(owner, 'sound/magic/ethereal_exit.ogg', 50, 1)
/datum/status_effect/cyborg_power_regen
@@ -146,6 +145,11 @@
alert_type = /obj/screen/alert/status_effect/power_regen
var/power_to_give = 0 //how much power is gained each tick
/datum/status_effect/cyborg_power_regen/on_creation(mob/living/new_owner, new_power_per_tick)
. = ..()
if(. && isnum(new_power_per_tick))
power_to_give = new_power_per_tick
/obj/screen/alert/status_effect/power_regen
name = "Power Regeneration"
desc = "You are quickly regenerating power!"
@@ -181,7 +185,7 @@
..()
/datum/status_effect/his_grace/on_apply()
add_logs(owner, null, "gained His Grace's stun immunity")
owner.log_message("gained His Grace's stun immunity", INDIVIDUAL_ATTACK_LOG)
owner.add_stun_absorption("hisgrace", INFINITY, 3, null, "His Grace protects you from the stun!")
return ..()
@@ -205,7 +209,7 @@
owner.adjustCloneLoss(-grace_heal)
/datum/status_effect/his_grace/on_remove()
add_logs(owner, null, "lost His Grace's stun immunity")
owner.log_message("lost His Grace's stun immunity", INDIVIDUAL_ATTACK_LOG)
if(islist(owner.stun_absorption) && owner.stun_absorption["hisgrace"])
owner.stun_absorption -= "hisgrace"
@@ -258,3 +262,113 @@
deathrattle()
. = ..()
/datum/status_effect/blooddrunk
id = "blooddrunk"
duration = 10
tick_interval = 0
alert_type = /obj/screen/alert/status_effect/blooddrunk
var/last_health = 0
var/last_bruteloss = 0
var/last_fireloss = 0
var/last_toxloss = 0
var/last_oxyloss = 0
var/last_cloneloss = 0
var/last_staminaloss = 0
/obj/screen/alert/status_effect/blooddrunk
name = "Blood-Drunk"
desc = "You are drunk on blood! Your pulse thunders in your ears! Nothing can harm you!" //not true, and the item description mentions its actual effect
icon_state = "blooddrunk"
/datum/status_effect/blooddrunk/on_apply()
. = ..()
if(.)
owner.maxHealth *= 10
owner.bruteloss *= 10
owner.fireloss *= 10
owner.toxloss *= 10
owner.oxyloss *= 10
owner.cloneloss *= 10
owner.staminaloss *= 10
owner.updatehealth()
last_health = owner.health
last_bruteloss = owner.getBruteLoss()
last_fireloss = owner.getFireLoss()
last_toxloss = owner.getToxLoss()
last_oxyloss = owner.getOxyLoss()
last_cloneloss = owner.getCloneLoss()
last_staminaloss = owner.getStaminaLoss()
owner.log_message("gained blood-drunk stun immunity", INDIVIDUAL_ATTACK_LOG)
owner.add_stun_absorption("blooddrunk", INFINITY, 4)
owner.playsound_local(get_turf(owner), 'sound/effects/singlebeat.ogg', 40, 1)
/datum/status_effect/blooddrunk/tick() //multiply the effect of healing by 10
if(owner.health > last_health)
var/needs_health_update = FALSE
var/new_bruteloss = owner.getBruteLoss()
if(new_bruteloss < last_bruteloss)
var/heal_amount = (new_bruteloss - last_bruteloss) * 10
owner.adjustBruteLoss(heal_amount, updating_health = FALSE)
new_bruteloss = owner.getBruteLoss()
needs_health_update = TRUE
last_bruteloss = new_bruteloss
var/new_fireloss = owner.getFireLoss()
if(new_fireloss < last_fireloss)
var/heal_amount = (new_fireloss - last_fireloss) * 10
owner.adjustFireLoss(heal_amount, updating_health = FALSE)
new_fireloss = owner.getFireLoss()
needs_health_update = TRUE
last_fireloss = new_fireloss
var/new_toxloss = owner.getToxLoss()
if(new_toxloss < last_toxloss)
var/heal_amount = (new_toxloss - last_toxloss) * 10
owner.adjustToxLoss(heal_amount, updating_health = FALSE)
new_toxloss = owner.getToxLoss()
needs_health_update = TRUE
last_toxloss = new_toxloss
var/new_oxyloss = owner.getOxyLoss()
if(new_oxyloss < last_oxyloss)
var/heal_amount = (new_oxyloss - last_oxyloss) * 10
owner.adjustOxyLoss(heal_amount, updating_health = FALSE)
new_oxyloss = owner.getOxyLoss()
needs_health_update = TRUE
last_oxyloss = new_oxyloss
var/new_cloneloss = owner.getCloneLoss()
if(new_cloneloss < last_cloneloss)
var/heal_amount = (new_cloneloss - last_cloneloss) * 10
owner.adjustCloneLoss(heal_amount, updating_health = FALSE)
new_cloneloss = owner.getCloneLoss()
needs_health_update = TRUE
last_cloneloss = new_cloneloss
var/new_staminaloss = owner.getStaminaLoss()
if(new_staminaloss < last_staminaloss)
var/heal_amount = (new_staminaloss - last_staminaloss) * 10
owner.adjustStaminaLoss(heal_amount, updating_health = FALSE)
new_staminaloss = owner.getStaminaLoss()
needs_health_update = TRUE
last_staminaloss = new_staminaloss
if(needs_health_update)
owner.updatehealth()
owner.playsound_local(get_turf(owner), 'sound/effects/singlebeat.ogg', 40, 1)
last_health = owner.health
/datum/status_effect/blooddrunk/on_remove()
tick()
owner.maxHealth *= 0.1
owner.bruteloss *= 0.1
owner.fireloss *= 0.1
owner.toxloss *= 0.1
owner.oxyloss *= 0.1
owner.cloneloss *= 0.1
owner.staminaloss *= 0.1
owner.updatehealth()
owner.log_message("lost blood-drunk stun immunity", INDIVIDUAL_ATTACK_LOG)
if(islist(owner.stun_absorption) && owner.stun_absorption["blooddrunk"])
owner.stun_absorption -= "blooddrunk"
+164 -7
View File
@@ -1,5 +1,77 @@
//Largely negative status effects go here, even if they have small benificial effects
//STUN EFFECTS
/datum/status_effect/incapacitating
tick_interval = 0
status_type = STATUS_EFFECT_REPLACE
alert_type = null
var/needs_update_stat = FALSE
/datum/status_effect/incapacitating/on_creation(mob/living/new_owner, set_duration, updating_canmove)
if(isnum(set_duration))
duration = set_duration
. = ..()
if(.)
if(updating_canmove)
owner.update_canmove()
if(needs_update_stat || issilicon(owner))
owner.update_stat()
/datum/status_effect/incapacitating/on_remove()
owner.update_canmove()
if(needs_update_stat || issilicon(owner)) //silicons need stat updates in addition to normal canmove updates
owner.update_stat()
//STUN
/datum/status_effect/incapacitating/stun
id = "stun"
//KNOCKDOWN
/datum/status_effect/incapacitating/knockdown
id = "knockdown"
//UNCONSCIOUS
/datum/status_effect/incapacitating/unconscious
id = "unconscious"
needs_update_stat = TRUE
//SLEEPING
/datum/status_effect/incapacitating/sleeping
id = "sleeping"
alert_type = /obj/screen/alert/status_effect/asleep
needs_update_stat = TRUE
var/mob/living/carbon/carbon_owner
var/mob/living/carbon/human/human_owner
/datum/status_effect/incapacitating/sleeping/on_creation(mob/living/new_owner, updating_canmove)
. = ..()
if(.)
if(iscarbon(owner)) //to avoid repeated istypes
carbon_owner = owner
if(ishuman(owner))
human_owner = owner
/datum/status_effect/incapacitating/sleeping/Destroy()
carbon_owner = null
human_owner = null
return ..()
/datum/status_effect/incapacitating/sleeping/tick()
if(owner.staminaloss)
owner.adjustStaminaLoss(-0.35) //reduce stamina loss by 0.35 per tick, 7 per 2 seconds
if(human_owner && human_owner.drunkenness)
human_owner.drunkenness *= 0.997 //reduce drunkenness by 0.3% per tick, 6% per 2 seconds
if(prob(20))
if(carbon_owner)
carbon_owner.handle_dreams()
if(prob(10) && owner.health > HEALTH_THRESHOLD_CRIT)
owner.emote("snore")
/obj/screen/alert/status_effect/asleep
name = "Asleep"
desc = "You've fallen asleep. Wait a bit and you should wake up. Unless you don't, considering how helpless you are."
icon_state = "asleep"
//OTHER DEBUFFS
/datum/status_effect/his_wrath //does minor damage over time unless holding His Grace
id = "his_wrath"
duration = -1
@@ -47,7 +119,7 @@
if(iscarbon(owner) && !is_servant_of_ratvar(owner) && !owner.null_rod_check() && number_legs)
if(force_damage || owner.m_intent != MOVE_INTENT_WALK)
if(GLOB.ratvar_awakens)
owner.Weaken(1)
owner.Knockdown(20)
if(iscultist(owner))
owner.apply_damage(cultist_damage_on_toggle * 0.5, BURN, "l_leg")
owner.apply_damage(cultist_damage_on_toggle * 0.5, BURN, "r_leg")
@@ -83,8 +155,13 @@
"Move towards the mania motor.", "Come closer.", "Get over here already!", "Keep your eyes on the motor.")
var/static/list/flee_messages = list("Oh, NOW you flee.", "Get back here!", "If you were smarter, you'd come back.", "Only fools run.", "You'll be back.")
var/static/list/turnoff_messages = list("Why would they turn it-", "What are these idi-", "Fools, fools, all of-", "Are they trying to c-", "All this effort just f-")
var/static/list/powerloss_messages = list("\"Oh, the id**ts di***t s***e en**** pow**...\"", "\"D*dn't **ey mak* an **te***c*i*n le**?\"", "\"The** f**ls for**t t* make a ***** *f-\"", \
"\"No, *O, you **re so cl***-\"", "You hear a yell of frustration, cut off by static.")
var/static/list/powerloss_messages = list("\"Oh, the id**ts di***t s***e en**** pow**...\"" = TRUE, "\"D*dn't **ey mak* an **te***c*i*n le**?\"" = TRUE, "\"The** f**ls for**t t* make a ***** *f-\"" = TRUE, \
"\"No, *O, you **re so cl***-\"" = TRUE, "You hear a yell of frustration, cut off by static." = FALSE)
/datum/status_effect/maniamotor/on_creation(mob/living/new_owner, obj/structure/destructible/clockwork/powered/mania_motor/new_motor)
. = ..()
if(.)
motor = new_motor
/datum/status_effect/maniamotor/Destroy()
motor = null
@@ -103,7 +180,8 @@
if(motor.total_accessable_power() > motor.mania_cost)
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(turnoff_messages))]\"</span>")
else
to_chat(owner, "<span class='sevtug[span_part]'>[text2ratvar(pick(powerloss_messages))]</span>")
var/pickedmessage = pick(powerloss_messages)
to_chat(owner, "<span class='sevtug[span_part]'>[powerloss_messages[pickedmessage] ? "[text2ratvar(pickedmessage)]" : pickedmessage]</span>")
warned_turnoff = TRUE
severity = max(severity - 2, 0)
if(!severity)
@@ -137,8 +215,9 @@
if(owner.getToxLoss() > MANIA_DAMAGE_TO_CONVERT)
if(is_eligible_servant(owner))
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar("You are mine and his, now.")]\"</span>")
add_servant_of_ratvar(owner)
owner.Paralyse(5)
if(add_servant_of_ratvar(owner))
owner.log_message("<font color=#BE8700>Conversion was done with a Mania Motor.</font>", INDIVIDUAL_ATTACK_LOG)
owner.Unconscious(100)
else
if(prob(severity * 0.15))
to_chat(owner, "<span class='sevtug[span_part]'>\"[text2ratvar(pick(mania_messages))]\"</span>")
@@ -157,14 +236,20 @@
id = "cult_ghost"
duration = -1
alert_type = null
/datum/status_effect/crusher_mark
id = "crusher_mark"
duration = 30 //if you leave for 30 seconds you lose the mark, deal with it
duration = 300 //if you leave for 30 seconds you lose the mark, deal with it
status_type = STATUS_EFFECT_REPLACE
alert_type = null
var/mutable_appearance/marked_underlay
var/obj/item/weapon/twohanded/required/kinetic_crusher/hammer_synced
/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/weapon/twohanded/required/kinetic_crusher/new_hammer_synced)
. = ..()
if(.)
hammer_synced = new_hammer_synced
/datum/status_effect/crusher_mark/on_apply()
if(owner.mob_size >= MOB_SIZE_LARGE)
marked_underlay = mutable_appearance('icons/effects/effects.dmi', "shield2")
@@ -184,3 +269,75 @@
/datum/status_effect/crusher_mark/be_replaced()
owner.underlays -= marked_underlay //if this is being called, we should have an owner at this point.
..()
/datum/status_effect/saw_bleed
id = "saw_bleed"
duration = -1 //removed under specific conditions
tick_interval = 6
alert_type = null
var/mutable_appearance/bleed_overlay
var/mutable_appearance/bleed_underlay
var/bleed_amount = 3
var/bleed_buildup = 3
var/delay_before_decay = 5
var/bleed_damage = 200
var/needs_to_bleed = FALSE
/datum/status_effect/saw_bleed/Destroy()
if(owner)
owner.cut_overlay(bleed_overlay)
owner.underlays -= bleed_underlay
QDEL_NULL(bleed_overlay)
return ..()
/datum/status_effect/saw_bleed/on_apply()
if(owner.stat == DEAD)
return FALSE
bleed_overlay = mutable_appearance('icons/effects/bleed.dmi', "bleed[bleed_amount]")
bleed_underlay = mutable_appearance('icons/effects/bleed.dmi', "bleed[bleed_amount]")
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
var/icon_height = I.Height()
bleed_overlay.pixel_x = -owner.pixel_x
bleed_overlay.pixel_y = Floor(icon_height * 0.25)
bleed_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the bleed overlay's size based on the target's icon size
bleed_underlay.pixel_x = -owner.pixel_x
bleed_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
bleed_underlay.alpha = 40
owner.add_overlay(bleed_overlay)
owner.underlays += bleed_underlay
return ..()
/datum/status_effect/saw_bleed/tick()
if(owner.stat == DEAD)
qdel(src)
else
add_bleed(-1)
/datum/status_effect/saw_bleed/proc/add_bleed(amount)
owner.cut_overlay(bleed_overlay)
owner.underlays -= bleed_underlay
bleed_amount += amount
if(bleed_amount)
if(bleed_amount >= 10)
needs_to_bleed = TRUE
qdel(src)
else
if(amount > 0)
tick_interval += delay_before_decay
bleed_overlay.icon_state = "bleed[bleed_amount]"
bleed_underlay.icon_state = "bleed[bleed_amount]"
owner.add_overlay(bleed_overlay)
owner.underlays += bleed_underlay
else
qdel(src)
/datum/status_effect/saw_bleed/on_remove()
if(needs_to_bleed)
var/turf/T = get_turf(owner)
new /obj/effect/temp_visual/bleed/explode(T)
for(var/d in GLOB.alldirs)
new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, d)
playsound(T, "desceration", 200, 1, -1)
owner.adjustBruteLoss(bleed_damage)
else
new /obj/effect/temp_visual/bleed(get_turf(owner))
+14 -23
View File
@@ -17,13 +17,26 @@
alert_type = null
var/total_damage = 0
/datum/status_effect/syphon_mark
id = "syphon_mark"
duration = 50
status_type = STATUS_EFFECT_MULTIPLE
alert_type = null
on_remove_on_mob_delete = TRUE
var/obj/item/borg/upgrade/modkit/bounty/reward_target
/datum/status_effect/syphon_mark/on_creation(mob/living/new_owner, obj/item/borg/upgrade/modkit/bounty/new_reward_target)
. = ..()
if(.)
reward_target = new_reward_target
/datum/status_effect/syphon_mark/on_apply()
if(owner.stat == DEAD)
return FALSE
return ..()
/datum/status_effect/syphon_mark/proc/get_kill()
if(reward_target)
if(!QDELETED(reward_target))
reward_target.get_kill(owner)
/datum/status_effect/syphon_mark/tick()
@@ -34,25 +47,3 @@
/datum/status_effect/syphon_mark/on_remove()
get_kill()
. = ..()
/datum/status_effect/syphon_mark
id = "syphon_mark"
duration = 50
status_type = STATUS_EFFECT_MULTIPLE
alert_type = null
on_remove_on_mob_delete = TRUE
var/obj/item/borg/upgrade/modkit/bounty/reward_target
/datum/status_effect/syphon_mark/on_apply()
if(owner.stat == DEAD)
return FALSE
return ..()
/datum/status_effect/syphon_mark/tick()
if(owner.stat == DEAD)
get_kill()
qdel(src)
/datum/status_effect/syphon_mark/on_remove()
get_kill()
. = ..()
+21 -21
View File
@@ -12,12 +12,26 @@
var/alert_type = /obj/screen/alert/status_effect //the alert thrown by the status effect, contains name and description
var/obj/screen/alert/status_effect/linked_alert = null //the alert itself, if it exists
/datum/status_effect/New(mob/living/new_owner)
/datum/status_effect/New(list/arguments)
on_creation(arglist(arguments))
/datum/status_effect/proc/on_creation(mob/living/new_owner, ...)
if(new_owner)
owner = new_owner
if(owner)
LAZYADD(owner.status_effects, src)
addtimer(CALLBACK(src, .proc/start_ticking), 1) //Give us time to set any variables
if(!owner || !on_apply())
qdel(src)
return
if(duration != -1)
duration = world.time + duration
tick_interval = world.time + tick_interval
if(alert_type)
var/obj/screen/alert/status_effect/A = owner.throw_alert(id, alert_type)
A.attached_effect = src //so the alert can reference us, if it needs to
linked_alert = A //so we can reference the alert, if we need to
START_PROCESSING(SSfastprocess, src)
return TRUE
/datum/status_effect/Destroy()
STOP_PROCESSING(SSfastprocess, src)
@@ -28,21 +42,6 @@
owner = null
return ..()
/datum/status_effect/proc/start_ticking()
if(!src)
return
if(!owner || !on_apply())
qdel(src)
return
if(duration != -1)
duration = world.time + initial(duration)
tick_interval = world.time + initial(tick_interval)
if(alert_type)
var/obj/screen/alert/status_effect/A = owner.throw_alert(id, alert_type)
A.attached_effect = src //so the alert can reference us, if it needs to
linked_alert = A //so we can reference the alert, if we need to
START_PROCESSING(SSfastprocess, src)
/datum/status_effect/process()
if(!owner)
qdel(src)
@@ -53,9 +52,8 @@
if(duration != -1 && duration < world.time)
qdel(src)
/datum/status_effect/proc/on_apply() //Called whenever the buff is applied.
/datum/status_effect/proc/on_apply() //Called whenever the buff is applied; returning FALSE will cause it to autoremove itself.
return TRUE
/datum/status_effect/proc/tick() //Called every tick.
/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed; do note that at the point this is called, it is out of the owner's status_effects but owner is not yet null
/datum/status_effect/proc/be_replaced() //Called instead of on_remove when a status effect is replaced by itself or when a status effect with on_remove_on_mob_delete = FALSE has its mob deleted
@@ -77,7 +75,7 @@
// HELPER PROCS //
//////////////////
/mob/living/proc/apply_status_effect(effect) //applies a given status effect to this mob, returning the effect if it was successful
/mob/living/proc/apply_status_effect(effect, ...) //applies a given status effect to this mob, returning the effect if it was successful
. = FALSE
var/datum/status_effect/S1 = effect
LAZYINITLIST(status_effects)
@@ -87,7 +85,9 @@
S.be_replaced()
else
return
S1 = new effect(src)
var/list/arguments = args.Copy()
arguments[1] = src
S1 = new effect(arguments)
. = S1
/mob/living/proc/remove_status_effect(effect) //removes all of a given status effect from this mob, returning TRUE if at least one was removed
+2 -1
View File
@@ -12,6 +12,7 @@
//do things for each entry in Generate_list
//return value sets Generate_list[verbpath]
/datum/verbs/proc/HandleVerb(list/entry, atom/verb/verbpath, ...)
return entry
/datum/verbs/New()
var/mainlist = GetList()
@@ -91,7 +92,7 @@
entry["command"] = copytext(verbpath.name,2)
else
entry["command"] = replacetext(verbpath.name, " ", "-")
.[verbpath] = HandleVerb(arglist(list(entry, verbpath) + args))
/world/proc/LoadVerbs(verb_type)
+26 -26
View File
@@ -1,31 +1,31 @@
/datum/wires/mulebot
holder_type = /mob/living/simple_animal/bot/mulebot
randomize = TRUE
/datum/wires/mulebot/New(atom/holder)
wires = list(
WIRE_POWER1, WIRE_POWER2,
WIRE_AVOIDANCE, WIRE_LOADCHECK,
WIRE_MOTOR1, WIRE_MOTOR2,
WIRE_RX, WIRE_TX, WIRE_BEACON
)
..()
/datum/wires/mulebot/interactable(mob/user)
var/mob/living/simple_animal/bot/mulebot/M = holder
if(M.open)
return TRUE
/datum/wires/mulebot/on_pulse(wire)
var/mob/living/simple_animal/bot/mulebot/M = holder
switch(wire)
if(WIRE_POWER1, WIRE_POWER2)
/datum/wires/mulebot
holder_type = /mob/living/simple_animal/bot/mulebot
randomize = TRUE
/datum/wires/mulebot/New(atom/holder)
wires = list(
WIRE_POWER1, WIRE_POWER2,
WIRE_AVOIDANCE, WIRE_LOADCHECK,
WIRE_MOTOR1, WIRE_MOTOR2,
WIRE_RX, WIRE_TX, WIRE_BEACON
)
..()
/datum/wires/mulebot/interactable(mob/user)
var/mob/living/simple_animal/bot/mulebot/M = holder
if(M.open)
return TRUE
/datum/wires/mulebot/on_pulse(wire)
var/mob/living/simple_animal/bot/mulebot/M = holder
switch(wire)
if(WIRE_POWER1, WIRE_POWER2)
holder.visible_message("<span class='notice'>[bicon(M)] The charge light flickers.</span>")
if(WIRE_AVOIDANCE)
if(WIRE_AVOIDANCE)
holder.visible_message("<span class='notice'>[bicon(M)] The external warning lights flash briefly.</span>")
if(WIRE_LOADCHECK)
if(WIRE_LOADCHECK)
holder.visible_message("<span class='notice'>[bicon(M)] The load platform clunks.</span>")
if(WIRE_MOTOR1, WIRE_MOTOR2)
if(WIRE_MOTOR1, WIRE_MOTOR2)
holder.visible_message("<span class='notice'>[bicon(M)] The drive motor whines briefly.</span>")
else
else
holder.visible_message("<span class='notice'>[bicon(M)] You hear a radio crackle.</span>")
+43 -43
View File
@@ -1,45 +1,45 @@
/datum/wires/particle_accelerator/control_box
holder_type = /obj/machinery/particle_accelerator/control_box
proper_name = "Particle Accelerator"
/datum/wires/particle_accelerator/control_box/New(atom/holder)
wires = list(
WIRE_POWER, WIRE_STRENGTH, WIRE_LIMIT,
WIRE_INTERFACE
)
add_duds(2)
..()
/datum/wires/particle_accelerator/control_box/interactable(mob/user)
var/obj/machinery/particle_accelerator/control_box/C = holder
if(C.construction_state == 2)
return TRUE
/datum/wires/particle_accelerator/control_box/on_pulse(wire)
var/obj/machinery/particle_accelerator/control_box/C = holder
switch(wire)
if(WIRE_POWER)
C.toggle_power()
if(WIRE_STRENGTH)
C.add_strength()
if(WIRE_INTERFACE)
C.interface_control = !C.interface_control
if(WIRE_LIMIT)
/datum/wires/particle_accelerator/control_box
holder_type = /obj/machinery/particle_accelerator/control_box
proper_name = "Particle Accelerator"
/datum/wires/particle_accelerator/control_box/New(atom/holder)
wires = list(
WIRE_POWER, WIRE_STRENGTH, WIRE_LIMIT,
WIRE_INTERFACE
)
add_duds(2)
..()
/datum/wires/particle_accelerator/control_box/interactable(mob/user)
var/obj/machinery/particle_accelerator/control_box/C = holder
if(C.construction_state == 2)
return TRUE
/datum/wires/particle_accelerator/control_box/on_pulse(wire)
var/obj/machinery/particle_accelerator/control_box/C = holder
switch(wire)
if(WIRE_POWER)
C.toggle_power()
if(WIRE_STRENGTH)
C.add_strength()
if(WIRE_INTERFACE)
C.interface_control = !C.interface_control
if(WIRE_LIMIT)
C.visible_message("[bicon(C)]<b>[C]</b> makes a large whirring noise.")
/datum/wires/particle_accelerator/control_box/on_cut(wire, mend)
var/obj/machinery/particle_accelerator/control_box/C = holder
switch(wire)
if(WIRE_POWER)
if(C.active == !mend)
C.toggle_power()
if(WIRE_STRENGTH)
for(var/i = 1; i < 3; i++)
C.remove_strength()
if(WIRE_INTERFACE)
if(!mend)
C.interface_control = FALSE
if(WIRE_LIMIT)
C.strength_upper_limit = (mend ? 2 : 3)
if(C.strength_upper_limit < C.strength)
/datum/wires/particle_accelerator/control_box/on_cut(wire, mend)
var/obj/machinery/particle_accelerator/control_box/C = holder
switch(wire)
if(WIRE_POWER)
if(C.active == !mend)
C.toggle_power()
if(WIRE_STRENGTH)
for(var/i = 1; i < 3; i++)
C.remove_strength()
if(WIRE_INTERFACE)
if(!mend)
C.interface_control = FALSE
if(WIRE_LIMIT)
C.strength_upper_limit = (mend ? 2 : 3)
if(C.strength_upper_limit < C.strength)
C.remove_strength()
+73 -73
View File
@@ -1,79 +1,79 @@
/datum/wires/robot
holder_type = /mob/living/silicon/robot
randomize = TRUE
/datum/wires/robot/New(atom/holder)
wires = list(
WIRE_AI, WIRE_CAMERA,
WIRE_LAWSYNC, WIRE_LOCKDOWN,
WIRE_RESET_MODULE
)
add_duds(2)
..()
/datum/wires/robot/interactable(mob/user)
var/mob/living/silicon/robot/R = holder
if(R.wiresexposed)
return TRUE
/datum/wires/robot/get_status()
var/mob/living/silicon/robot/R = holder
var/list/status = list()
status += "The law sync module is [R.lawupdate ? "on" : "off"]."
status += "The intelligence link display shows [R.connected_ai ? R.connected_ai.name : "NULL"]."
status += "The camera light is [!isnull(R.camera) && R.camera.status ? "on" : "off"]."
status += "The lockdown indicator is [R.lockcharge ? "on" : "off"]."
status += "The reset module hardware light is [R.has_module() ? "on" : "off"]."
return status
/datum/wires/robot/on_pulse(wire)
var/mob/living/silicon/robot/R = holder
switch(wire)
if(WIRE_AI) // Pulse to pick a new AI.
if(!R.emagged)
var/new_ai = select_active_ai(R)
if(new_ai && (new_ai != R.connected_ai))
R.connected_ai = new_ai
if(R.shell)
R.undeploy() //If this borg is an AI shell, disconnect the controlling AI and assign ti to a new AI
R.notify_ai(AI_SHELL)
else
R.notify_ai(TRUE)
if(WIRE_CAMERA) // Pulse to disable the camera.
if(!isnull(R.camera) && !R.scrambledcodes)
R.camera.toggle_cam(usr, 0)
R.visible_message("[R]'s camera lense focuses loudly.", "Your camera lense focuses loudly.")
if(WIRE_LAWSYNC) // Forces a law update if possible.
if(R.lawupdate)
R.visible_message("[R] gently chimes.", "LawSync protocol engaged.")
R.lawsync()
R.show_laws()
if(WIRE_LOCKDOWN)
R.SetLockdown(!R.lockcharge) // Toggle
/datum/wires/robot
holder_type = /mob/living/silicon/robot
randomize = TRUE
/datum/wires/robot/New(atom/holder)
wires = list(
WIRE_AI, WIRE_CAMERA,
WIRE_LAWSYNC, WIRE_LOCKDOWN,
WIRE_RESET_MODULE
)
add_duds(2)
..()
/datum/wires/robot/interactable(mob/user)
var/mob/living/silicon/robot/R = holder
if(R.wiresexposed)
return TRUE
/datum/wires/robot/get_status()
var/mob/living/silicon/robot/R = holder
var/list/status = list()
status += "The law sync module is [R.lawupdate ? "on" : "off"]."
status += "The intelligence link display shows [R.connected_ai ? R.connected_ai.name : "NULL"]."
status += "The camera light is [!isnull(R.camera) && R.camera.status ? "on" : "off"]."
status += "The lockdown indicator is [R.lockcharge ? "on" : "off"]."
status += "The reset module hardware light is [R.has_module() ? "on" : "off"]."
return status
/datum/wires/robot/on_pulse(wire)
var/mob/living/silicon/robot/R = holder
switch(wire)
if(WIRE_AI) // Pulse to pick a new AI.
if(!R.emagged)
var/new_ai = select_active_ai(R)
if(new_ai && (new_ai != R.connected_ai))
R.connected_ai = new_ai
if(R.shell)
R.undeploy() //If this borg is an AI shell, disconnect the controlling AI and assign ti to a new AI
R.notify_ai(AI_SHELL)
else
R.notify_ai(TRUE)
if(WIRE_CAMERA) // Pulse to disable the camera.
if(!isnull(R.camera) && !R.scrambledcodes)
R.camera.toggle_cam(usr, 0)
R.visible_message("[R]'s camera lense focuses loudly.", "Your camera lense focuses loudly.")
if(WIRE_LAWSYNC) // Forces a law update if possible.
if(R.lawupdate)
R.visible_message("[R] gently chimes.", "LawSync protocol engaged.")
R.lawsync()
R.show_laws()
if(WIRE_LOCKDOWN)
R.SetLockdown(!R.lockcharge) // Toggle
if(WIRE_RESET_MODULE)
if(R.has_module())
R.visible_message("[R]'s module servos twitch.", "Your module display flickers.")
/datum/wires/robot/on_cut(wire, mend)
var/mob/living/silicon/robot/R = holder
switch(wire)
if(WIRE_AI) // Cut the AI wire to reset AI control.
if(!mend)
R.connected_ai = null
R.undeploy() //Forced disconnect of an AI should this body be a shell.
if(WIRE_LAWSYNC) // Cut the law wire, and the borg will no longer receive law updates from its AI. Repair and it will re-sync.
if(mend)
if(!R.emagged)
R.lawupdate = TRUE
else if(!R.deployed) //AI shells must always have the same laws as the AI
R.lawupdate = FALSE
if (WIRE_CAMERA) // Disable the camera.
if(!isnull(R.camera) && !R.scrambledcodes)
R.camera.status = mend
R.camera.toggle_cam(usr, 0)
R.visible_message("[R]'s camera lense focuses loudly.", "Your camera lense focuses loudly.")
if(WIRE_LOCKDOWN) // Simple lockdown.
R.SetLockdown(!mend)
/datum/wires/robot/on_cut(wire, mend)
var/mob/living/silicon/robot/R = holder
switch(wire)
if(WIRE_AI) // Cut the AI wire to reset AI control.
if(!mend)
R.connected_ai = null
R.undeploy() //Forced disconnect of an AI should this body be a shell.
if(WIRE_LAWSYNC) // Cut the law wire, and the borg will no longer receive law updates from its AI. Repair and it will re-sync.
if(mend)
if(!R.emagged)
R.lawupdate = TRUE
else if(!R.deployed) //AI shells must always have the same laws as the AI
R.lawupdate = FALSE
if (WIRE_CAMERA) // Disable the camera.
if(!isnull(R.camera) && !R.scrambledcodes)
R.camera.status = mend
R.camera.toggle_cam(usr, 0)
R.visible_message("[R]'s camera lense focuses loudly.", "Your camera lense focuses loudly.")
if(WIRE_LOCKDOWN) // Simple lockdown.
R.SetLockdown(!mend)
if(WIRE_RESET_MODULE)
if(R.has_module() && !mend)
R.ResetModule()
+80 -80
View File
@@ -1,92 +1,92 @@
/datum/wires/syndicatebomb
holder_type = /obj/machinery/syndicatebomb
randomize = TRUE
/datum/wires/syndicatebomb/New(atom/holder)
wires = list(
WIRE_BOOM, WIRE_UNBOLT,
WIRE_ACTIVATE, WIRE_DELAY, WIRE_PROCEED
)
..()
/datum/wires/syndicatebomb/interactable(mob/user)
var/obj/machinery/syndicatebomb/P = holder
if(P.open_panel)
return TRUE
/datum/wires/syndicatebomb/on_pulse(wire)
var/obj/machinery/syndicatebomb/B = holder
switch(wire)
if(WIRE_BOOM)
if(B.active)
/datum/wires/syndicatebomb
holder_type = /obj/machinery/syndicatebomb
randomize = TRUE
/datum/wires/syndicatebomb/New(atom/holder)
wires = list(
WIRE_BOOM, WIRE_UNBOLT,
WIRE_ACTIVATE, WIRE_DELAY, WIRE_PROCEED
)
..()
/datum/wires/syndicatebomb/interactable(mob/user)
var/obj/machinery/syndicatebomb/P = holder
if(P.open_panel)
return TRUE
/datum/wires/syndicatebomb/on_pulse(wire)
var/obj/machinery/syndicatebomb/B = holder
switch(wire)
if(WIRE_BOOM)
if(B.active)
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
B.explode_now = TRUE
tell_admins(B)
if(WIRE_UNBOLT)
B.explode_now = TRUE
tell_admins(B)
if(WIRE_UNBOLT)
holder.visible_message("<span class='notice'>[bicon(B)] The bolts spin in place for a moment.</span>")
if(WIRE_DELAY)
if(B.delayedbig)
if(WIRE_DELAY)
if(B.delayedbig)
holder.visible_message("<span class='notice'>[bicon(B)] The bomb has already been delayed.</span>")
else
else
holder.visible_message("<span class='notice'>[bicon(B)] The bomb chirps.</span>")
playsound(B, 'sound/machines/chime.ogg', 30, 1)
B.detonation_timer += 300
B.delayedbig = TRUE
if(WIRE_PROCEED)
playsound(B, 'sound/machines/chime.ogg', 30, 1)
B.detonation_timer += 300
B.delayedbig = TRUE
if(WIRE_PROCEED)
holder.visible_message("<span class='danger'>[bicon(B)] The bomb buzzes ominously!</span>")
playsound(B, 'sound/machines/buzz-sigh.ogg', 30, 1)
var/seconds = B.seconds_remaining()
if(seconds >= 61) // Long fuse bombs can suddenly become more dangerous if you tinker with them.
B.detonation_timer = world.time + 600
else if(seconds >= 21)
B.detonation_timer -= 100
else if(seconds >= 11) // Both to prevent negative timers and to have a little mercy.
B.detonation_timer = world.time + 100
if(WIRE_ACTIVATE)
if(!B.active && !B.defused)
playsound(B, 'sound/machines/buzz-sigh.ogg', 30, 1)
var/seconds = B.seconds_remaining()
if(seconds >= 61) // Long fuse bombs can suddenly become more dangerous if you tinker with them.
B.detonation_timer = world.time + 600
else if(seconds >= 21)
B.detonation_timer -= 100
else if(seconds >= 11) // Both to prevent negative timers and to have a little mercy.
B.detonation_timer = world.time + 100
if(WIRE_ACTIVATE)
if(!B.active && !B.defused)
holder.visible_message("<span class='danger'>[bicon(B)] You hear the bomb start ticking!</span>")
B.activate()
B.update_icon()
else if(B.delayedlittle)
B.activate()
B.update_icon()
else if(B.delayedlittle)
holder.visible_message("<span class='notice'>[bicon(B)] Nothing happens.</span>")
else
else
holder.visible_message("<span class='notice'>[bicon(B)] The bomb seems to hesitate for a moment.</span>")
B.detonation_timer += 100
B.delayedlittle = TRUE
/datum/wires/syndicatebomb/on_cut(wire, mend)
var/obj/machinery/syndicatebomb/B = holder
switch(wire)
if(WIRE_BOOM)
if(mend)
B.defused = FALSE // Cutting and mending all the wires of an inactive bomb will thus cure any sabotage.
else
if(B.active)
B.detonation_timer += 100
B.delayedlittle = TRUE
/datum/wires/syndicatebomb/on_cut(wire, mend)
var/obj/machinery/syndicatebomb/B = holder
switch(wire)
if(WIRE_BOOM)
if(mend)
B.defused = FALSE // Cutting and mending all the wires of an inactive bomb will thus cure any sabotage.
else
if(B.active)
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
B.explode_now = TRUE
tell_admins(B)
else
B.defused = TRUE
if(WIRE_UNBOLT)
if(!mend && B.anchored)
B.explode_now = TRUE
tell_admins(B)
else
B.defused = TRUE
if(WIRE_UNBOLT)
if(!mend && B.anchored)
holder.visible_message("<span class='notice'>[bicon(B)] The bolts lift out of the ground!</span>")
playsound(B, 'sound/effects/stealthoff.ogg', 30, 1)
B.anchored = FALSE
if(WIRE_PROCEED)
if(!mend && B.active)
playsound(B, 'sound/effects/stealthoff.ogg', 30, 1)
B.anchored = FALSE
if(WIRE_PROCEED)
if(!mend && B.active)
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
B.explode_now = TRUE
tell_admins(B)
if(WIRE_ACTIVATE)
if(!mend && B.active)
B.explode_now = TRUE
tell_admins(B)
if(WIRE_ACTIVATE)
if(!mend && B.active)
holder.visible_message("<span class='notice'>[bicon(B)] The timer stops! The bomb has been defused!</span>")
B.active = FALSE
B.defused = TRUE
B.update_icon()
/datum/wires/syndicatebomb/proc/tell_admins(obj/machinery/syndicatebomb/B)
if(istype(B, /obj/machinery/syndicatebomb/training))
return
var/turf/T = get_turf(B)
log_game("\A [B] was detonated via boom wire at [COORD(T)].")
message_admins("A [B.name] was detonated via boom wire at [ADMIN_COORDJMP(T)].")
B.active = FALSE
B.defused = TRUE
B.update_icon()
/datum/wires/syndicatebomb/proc/tell_admins(obj/machinery/syndicatebomb/B)
if(istype(B, /obj/machinery/syndicatebomb/training))
return
var/turf/T = get_turf(B)
log_game("\A [B] was detonated via boom wire at [COORD(T)].")
message_admins("A [B.name] was detonated via boom wire at [ADMIN_COORDJMP(T)].")