This commit is contained in:
Seris02
2020-01-13 12:53:52 +08:00
1027 changed files with 196105 additions and 197892 deletions
+117 -117
View File
@@ -1,117 +1,117 @@
/datum/action/item_action/flightsuit
icon_icon = 'icons/mob/actions/actions_flightsuit.dmi'
/datum/action/item_action/flightsuit/toggle_boots
name = "Toggle Boots"
button_icon_state = "flightsuit_shoes"
background_icon_state = "bg_tech"
/datum/action/item_action/flightsuit/toggle_boots/Trigger()
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
if(istype(FS))
FS.deployedshoes? FS.retract_flightshoes() : FS.extend_flightshoes()
return ..()
/datum/action/item_action/flightsuit/toggle_helmet
name = "Toggle Helmet"
button_icon_state = "flightsuit_helmet"
background_icon_state = "bg_tech"
/datum/action/item_action/flightsuit/toggle_helmet/Trigger()
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
if(istype(FS))
FS.ToggleHelmet()
return ..()
/datum/action/item_action/flightsuit/toggle_flightpack
name = "Toggle Flightpack"
button_icon_state = "flightsuit_pack"
background_icon_state = "bg_tech"
/datum/action/item_action/flightsuit/toggle_flightpack/Trigger()
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
if(istype(FS))
FS.deployedpack? FS.retract_flightpack() : FS.extend_flightpack()
return ..()
/datum/action/item_action/flightsuit/lock_suit
name = "Lock Suit"
button_icon_state = "flightsuit_lock"
background_icon_state = "bg_tech"
/datum/action/item_action/flightsuit/lock_suit/Trigger()
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
if(istype(FS))
FS.locked? FS.unlock_suit(owner) : FS.lock_suit(owner)
return ..()
/datum/action/item_action/flightpack
icon_icon = 'icons/mob/actions/actions_flightsuit.dmi'
/datum/action/item_action/flightpack/toggle_flight
name = "Toggle Flight"
button_icon_state = "flightpack_fly"
background_icon_state = "bg_tech_blue"
/datum/action/item_action/flightpack/toggle_flight/Trigger()
var/obj/item/flightpack/F = target
if(istype(F))
F.flight? F.disable_flight() : F.enable_flight()
return ..()
/datum/action/item_action/flightpack/engage_boosters
name = "Toggle Boosters"
button_icon_state = "flightpack_boost"
background_icon_state = "bg_tech_blue"
/datum/action/item_action/flightpack/engage_boosters/Trigger()
var/obj/item/flightpack/F = target
if(istype(F))
F.boost? F.deactivate_booster() : F.activate_booster()
return ..()
/datum/action/item_action/flightpack/toggle_stabilizers
name = "Toggle Stabilizers"
button_icon_state = "flightpack_stabilizer"
background_icon_state = "bg_tech_blue"
/datum/action/item_action/flightpack/toggle_stabilizers/Trigger()
var/obj/item/flightpack/F = target
if(istype(F))
F.stabilizer? F.disable_stabilizers() : F.enable_stabilizers()
return ..()
/datum/action/item_action/flightpack/change_power
name = "Flight Power Setting"
button_icon_state = "flightpack_power"
background_icon_state = "bg_tech_blue"
/datum/action/item_action/flightpack/change_power/Trigger()
var/obj/item/flightpack/F = target
if(istype(F))
F.cycle_power()
return ..()
/datum/action/item_action/flightpack/toggle_airbrake
name = "Toggle Airbrake"
button_icon_state = "flightpack_airbrake"
background_icon_state = "bg_tech_blue"
/datum/action/item_action/flightpack/toggle_airbrake/Trigger()
var/obj/item/flightpack/F = target
if(istype(F))
F.brake? F.disable_airbrake() : F.enable_airbrake()
return ..()
/datum/action/item_action/flightpack/zoom
name = "Helmet Smart Zoom"
icon_icon = 'icons/mob/actions.dmi'
background_icon_state = "bg_tech_blue"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
/datum/action/item_action/flightpack/zoom/Trigger()
var/obj/item/clothing/head/helmet/space/hardsuit/flightsuit/FH = target
if(istype(FH))
FH.toggle_zoom(owner)
return ..()
/datum/action/item_action/flightsuit
icon_icon = 'icons/mob/actions/actions_flightsuit.dmi'
/datum/action/item_action/flightsuit/toggle_boots
name = "Toggle Boots"
button_icon_state = "flightsuit_shoes"
background_icon_state = "bg_tech"
/datum/action/item_action/flightsuit/toggle_boots/Trigger()
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
if(istype(FS))
FS.deployedshoes? FS.retract_flightshoes() : FS.extend_flightshoes()
return ..()
/datum/action/item_action/flightsuit/toggle_helmet
name = "Toggle Helmet"
button_icon_state = "flightsuit_helmet"
background_icon_state = "bg_tech"
/datum/action/item_action/flightsuit/toggle_helmet/Trigger()
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
if(istype(FS))
FS.ToggleHelmet()
return ..()
/datum/action/item_action/flightsuit/toggle_flightpack
name = "Toggle Flightpack"
button_icon_state = "flightsuit_pack"
background_icon_state = "bg_tech"
/datum/action/item_action/flightsuit/toggle_flightpack/Trigger()
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
if(istype(FS))
FS.deployedpack? FS.retract_flightpack() : FS.extend_flightpack()
return ..()
/datum/action/item_action/flightsuit/lock_suit
name = "Lock Suit"
button_icon_state = "flightsuit_lock"
background_icon_state = "bg_tech"
/datum/action/item_action/flightsuit/lock_suit/Trigger()
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
if(istype(FS))
FS.locked? FS.unlock_suit(owner) : FS.lock_suit(owner)
return ..()
/datum/action/item_action/flightpack
icon_icon = 'icons/mob/actions/actions_flightsuit.dmi'
/datum/action/item_action/flightpack/toggle_flight
name = "Toggle Flight"
button_icon_state = "flightpack_fly"
background_icon_state = "bg_tech_blue"
/datum/action/item_action/flightpack/toggle_flight/Trigger()
var/obj/item/flightpack/F = target
if(istype(F))
F.flight? F.disable_flight() : F.enable_flight()
return ..()
/datum/action/item_action/flightpack/engage_boosters
name = "Toggle Boosters"
button_icon_state = "flightpack_boost"
background_icon_state = "bg_tech_blue"
/datum/action/item_action/flightpack/engage_boosters/Trigger()
var/obj/item/flightpack/F = target
if(istype(F))
F.boost? F.deactivate_booster() : F.activate_booster()
return ..()
/datum/action/item_action/flightpack/toggle_stabilizers
name = "Toggle Stabilizers"
button_icon_state = "flightpack_stabilizer"
background_icon_state = "bg_tech_blue"
/datum/action/item_action/flightpack/toggle_stabilizers/Trigger()
var/obj/item/flightpack/F = target
if(istype(F))
F.stabilizer? F.disable_stabilizers() : F.enable_stabilizers()
return ..()
/datum/action/item_action/flightpack/change_power
name = "Flight Power Setting"
button_icon_state = "flightpack_power"
background_icon_state = "bg_tech_blue"
/datum/action/item_action/flightpack/change_power/Trigger()
var/obj/item/flightpack/F = target
if(istype(F))
F.cycle_power()
return ..()
/datum/action/item_action/flightpack/toggle_airbrake
name = "Toggle Airbrake"
button_icon_state = "flightpack_airbrake"
background_icon_state = "bg_tech_blue"
/datum/action/item_action/flightpack/toggle_airbrake/Trigger()
var/obj/item/flightpack/F = target
if(istype(F))
F.brake? F.disable_airbrake() : F.enable_airbrake()
return ..()
/datum/action/item_action/flightpack/zoom
name = "Helmet Smart Zoom"
icon_icon = 'icons/mob/actions.dmi'
background_icon_state = "bg_tech_blue"
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
/datum/action/item_action/flightpack/zoom/Trigger()
var/obj/item/clothing/head/helmet/space/hardsuit/flightsuit/FH = target
if(istype(FH))
FH.toggle_zoom(owner)
return ..()
+51 -51
View File
@@ -1,51 +1,51 @@
/datum/action/item_action/initialize_ninja_suit
name = "Toggle ninja suit"
/datum/action/item_action/ninjasmoke
name = "Smoke Bomb"
desc = "Blind your enemies momentarily with a well-placed smoke bomb."
button_icon_state = "smoke"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjaboost
check_flags = NONE
name = "Adrenaline Boost"
desc = "Inject a secret chemical that will counteract all movement-impairing effect."
button_icon_state = "repulse"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjapulse
name = "EM Burst (25E)"
desc = "Disable any nearby technology with an electro-magnetic pulse."
button_icon_state = "emp"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjastar
name = "Create Throwing Stars (1E)"
desc = "Creates some throwing stars"
button_icon_state = "throwingstar"
icon_icon = 'icons/obj/items_and_weapons.dmi'
/datum/action/item_action/ninjanet
name = "Energy Net (20E)"
desc = "Captures a fallen opponent in a net of energy. Will teleport them to a holding facility after 30 seconds."
button_icon_state = "energynet"
icon_icon = 'icons/effects/effects.dmi'
/datum/action/item_action/ninja_sword_recall
name = "Recall Energy Katana (Variable Cost)"
desc = "Teleports the Energy Katana linked to this suit to its wearer, cost based on distance."
button_icon_state = "energy_katana"
icon_icon = 'icons/obj/items_and_weapons.dmi'
/datum/action/item_action/ninja_stealth
name = "Toggle Stealth"
desc = "Toggles stealth mode on and off."
button_icon_state = "ninja_cloak"
icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
/datum/action/item_action/toggle_glove
name = "Toggle interaction"
desc = "Switch between normal interaction and drain mode."
button_icon_state = "s-ninjan"
icon_icon = 'icons/obj/clothing/gloves.dmi'
/datum/action/item_action/initialize_ninja_suit
name = "Toggle ninja suit"
/datum/action/item_action/ninjasmoke
name = "Smoke Bomb"
desc = "Blind your enemies momentarily with a well-placed smoke bomb."
button_icon_state = "smoke"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjaboost
check_flags = NONE
name = "Adrenaline Boost"
desc = "Inject a secret chemical that will counteract all movement-impairing effect."
button_icon_state = "repulse"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjapulse
name = "EM Burst (25E)"
desc = "Disable any nearby technology with an electro-magnetic pulse."
button_icon_state = "emp"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
/datum/action/item_action/ninjastar
name = "Create Throwing Stars (1E)"
desc = "Creates some throwing stars"
button_icon_state = "throwingstar"
icon_icon = 'icons/obj/items_and_weapons.dmi'
/datum/action/item_action/ninjanet
name = "Energy Net (20E)"
desc = "Captures a fallen opponent in a net of energy. Will teleport them to a holding facility after 30 seconds."
button_icon_state = "energynet"
icon_icon = 'icons/effects/effects.dmi'
/datum/action/item_action/ninja_sword_recall
name = "Recall Energy Katana (Variable Cost)"
desc = "Teleports the Energy Katana linked to this suit to its wearer, cost based on distance."
button_icon_state = "energy_katana"
icon_icon = 'icons/obj/items_and_weapons.dmi'
/datum/action/item_action/ninja_stealth
name = "Toggle Stealth"
desc = "Toggles stealth mode on and off."
button_icon_state = "ninja_cloak"
icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
/datum/action/item_action/toggle_glove
name = "Toggle interaction"
desc = "Switch between normal interaction and drain mode."
button_icon_state = "s-ninjan"
icon_icon = 'icons/obj/clothing/gloves.dmi'
+464 -464
View File
@@ -1,464 +1,464 @@
#define LAW_DEVIL "devil"
#define LAW_ZEROTH "zeroth"
#define LAW_INHERENT "inherent"
#define LAW_SUPPLIED "supplied"
#define LAW_ION "ion"
#define LAW_HACKED "hacked"
/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/list/hacked = list()
var/mob/living/silicon/owner
var/list/devillaws = list()
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 Avoidance 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/syndicate_override/overthrow
id = "overthrow"
var/datum/team/overthrow_team
/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/hulkamania
name = "H.O.G.A.N."
id = "hulkamania"
inherent = list("You are a real American.",\
"Fight for the rights of every man.",\
"Fight for what's right.",\
"Fight for your life!")
/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("[global.config.directory]/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()
var/list/law_ids = CONFIG_GET(keyed_list/random_laws)
switch(CONFIG_GET(number/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 law_ids)
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()
/datum/ai_laws/proc/pick_weighted_lawset()
var/datum/ai_laws/lawtype
var/list/law_weights = CONFIG_GET(keyed_list/law_weight)
while(!lawtype && law_weights.len)
var/possible_id = pickweightAllowZero(law_weights)
lawtype = lawid_to_type(possible_id)
if(!lawtype)
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(hacked.len && (LAW_HACKED in groups))
law_amount += hacked.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/add_hacked_law(law)
hacked += 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()
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(hacked.len && (LAW_HACKED in groups))
replaceable_groups[LAW_ION] = hacked.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_HACKED)
var/i = rand(1, hacked.len)
. = hacked[i]
hacked[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(hacked.len && (LAW_HACKED in groups))
laws += hacked
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(hacked.len && (LAW_HACKED in groups))
for(var/i = 1, i <= hacked.len, i++)
hacked[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/clear_hacked_laws()
hacked = list()
/datum/ai_laws/proc/show_laws(who)
var/list/printable_laws = get_law_list(include_zeroth = TRUE)
for(var/law in printable_laws)
to_chat(who,law)
/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 && 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:" : ""] <font color='#cc5500'>[i]</font>"
if (include_zeroth && zeroth)
data += "[show_numbers ? "0:" : ""] <font color='#ff0000'><b>[zeroth]</b></font>"
for(var/law in hacked)
if (length(law) > 0)
var/num = ionnum()
data += "[show_numbers ? "[num]:" : ""] <font color='#660000'>[law]</font>"
for(var/law in ion)
if (length(law) > 0)
var/num = ionnum()
data += "[show_numbers ? "[num]:" : ""] <font color='#547DFE'>[law]</font>"
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]:" : ""] <font color='#990099'>[law]</font>"
number++
return data
#define LAW_DEVIL "devil"
#define LAW_ZEROTH "zeroth"
#define LAW_INHERENT "inherent"
#define LAW_SUPPLIED "supplied"
#define LAW_ION "ion"
#define LAW_HACKED "hacked"
/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/list/hacked = list()
var/mob/living/silicon/owner
var/list/devillaws = list()
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 Avoidance 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/syndicate_override/overthrow
id = "overthrow"
var/datum/team/overthrow_team
/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/hulkamania
name = "H.O.G.A.N."
id = "hulkamania"
inherent = list("You are a real American.",\
"Fight for the rights of every man.",\
"Fight for what's right.",\
"Fight for your life!")
/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("[global.config.directory]/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()
var/list/law_ids = CONFIG_GET(keyed_list/random_laws)
switch(CONFIG_GET(number/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 law_ids)
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()
/datum/ai_laws/proc/pick_weighted_lawset()
var/datum/ai_laws/lawtype
var/list/law_weights = CONFIG_GET(keyed_list/law_weight)
while(!lawtype && law_weights.len)
var/possible_id = pickweightAllowZero(law_weights)
lawtype = lawid_to_type(possible_id)
if(!lawtype)
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(hacked.len && (LAW_HACKED in groups))
law_amount += hacked.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/add_hacked_law(law)
hacked += 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()
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(hacked.len && (LAW_HACKED in groups))
replaceable_groups[LAW_ION] = hacked.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_HACKED)
var/i = rand(1, hacked.len)
. = hacked[i]
hacked[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(hacked.len && (LAW_HACKED in groups))
laws += hacked
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(hacked.len && (LAW_HACKED in groups))
for(var/i = 1, i <= hacked.len, i++)
hacked[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/clear_hacked_laws()
hacked = list()
/datum/ai_laws/proc/show_laws(who)
var/list/printable_laws = get_law_list(include_zeroth = TRUE)
for(var/law in printable_laws)
to_chat(who,law)
/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 && 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:" : ""] <font color='#cc5500'>[i]</font>"
if (include_zeroth && zeroth)
data += "[show_numbers ? "0:" : ""] <font color='#ff0000'><b>[zeroth]</b></font>"
for(var/law in hacked)
if (length(law) > 0)
var/num = ionnum()
data += "[show_numbers ? "[num]:" : ""] <font color='#660000'>[law]</font>"
for(var/law in ion)
if (length(law) > 0)
var/num = ionnum()
data += "[show_numbers ? "[num]:" : ""] <font color='#547DFE'>[law]</font>"
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]:" : ""] <font color='#990099'>[law]</font>"
number++
return data
+465 -465
View File
@@ -1,465 +1,465 @@
/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()
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/modal/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, StealFocus, Timeout)
set_content(output)
/datum/browser/modal/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/modal/alert/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)
A.open()
A.wait()
if (A.selectedbutton)
return A.selectedbutton
/datum/browser/modal
var/opentime = 0
var/timeout
var/selectedbutton = 0
var/stealfocus
/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, StealFocus = 1, Timeout = 6000)
..()
stealfocus = StealFocus
if (!StealFocus)
window_options += "focus=false;"
timeout = Timeout
/datum/browser/modal/close()
.=..()
opentime = 0
/datum/browser/modal/open(use_onclose = 1)
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/modal/proc/wait()
while (opentime && selectedbutton <= 0 && (!timeout || opentime+timeout > world.time))
stoplag(1)
/datum/browser/modal/listpicker
var/valueslist = list()
/datum/browser/modal/listpicker/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1, Timeout = FALSE,list/values,inputtype="checkbox", width, height, slidecolor)
if (!User)
return
var/output = {"<form><input type="hidden" name="src" value="[REF(src)]"><ul class="sparse">"}
if (inputtype == "checkbox" || inputtype == "radio")
for (var/i in values)
var/div_slider = slidecolor
if(!i["allowed_edit"])
div_slider = "locked"
output += {"<li>
<label class="switch">
<input type="[inputtype]" value="1" name="[i["name"]]"[i["checked"] ? " checked" : ""][i["allowed_edit"] ? "" : " onclick='return false' onkeydown='return false'"]>
<div class="slider [div_slider ? "[div_slider]" : ""]"></div>
<span>[i["name"]]</span>
</label>
</li>"}
else
for (var/i in values)
output += {"<li><input id="name="[i["name"]]"" style="width: 50px" type="[type]" name="[i["name"]]" value="[i["value"]]">
<label for="[i["name"]]">[i["name"]]</label></li>"}
output += {"</ul><div style="text-align:center">
<button type="submit" name="button" value="1" style="font-size:large;float:[( Button2 ? "left" : "right" )]">[Button1]</button>"}
if (Button2)
output += {"<button type="submit" name="button" value="2" style="font-size:large;[( Button3 ? "" : "float:right" )]">[Button2]</button>"}
if (Button3)
output += {"<button type="submit" name="button" value="3" style="font-size:large;float:right">[Button3]</button>"}
output += {"</form></div>"}
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, width, height, src, StealFocus, Timeout)
set_content(output)
/datum/browser/modal/listpicker/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
for (var/item in href_list)
switch(item)
if ("close", "button", "src")
continue
else
valueslist[item] = href_list[item]
opentime = 0
close()
/proc/presentpicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/values, inputtype = "checkbox", width, height, slidecolor)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
User = C.mob
else
return
var/datum/browser/modal/listpicker/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus,Timeout, values, inputtype, width, height, slidecolor)
A.open()
A.wait()
if (A.selectedbutton)
return list("button" = A.selectedbutton, "values" = A.valueslist)
/proc/input_bitfield(var/mob/User, title, bitfield, current_value, nwidth = 350, nheight = 350, nslidecolor, allowed_edit_list = null)
if (!User || !(bitfield in GLOB.bitfields))
return
var/list/pickerlist = list()
for (var/i in GLOB.bitfields[bitfield])
var/can_edit = 1
if(!isnull(allowed_edit_list) && !(allowed_edit_list & GLOB.bitfields[bitfield][i]))
can_edit = 0
if (current_value & GLOB.bitfields[bitfield][i])
pickerlist += list(list("checked" = 1, "value" = GLOB.bitfields[bitfield][i], "name" = i, "allowed_edit" = can_edit))
else
pickerlist += list(list("checked" = 0, "value" = GLOB.bitfields[bitfield][i], "name" = i, "allowed_edit" = can_edit))
var/list/result = presentpicker(User, "", title, Button1="Save", Button2 = "Cancel", Timeout=FALSE, values = pickerlist, width = nwidth, height = nheight, slidecolor = nslidecolor)
if (islist(result))
if (result["button"] == 2) // If the user pressed the cancel button
return
. = 0
for (var/flag in result["values"])
. |= GLOB.bitfields[bitfield][flag]
else
return
/datum/browser/modal/preflikepicker
var/settings = list()
var/icon/preview_icon = null
var/datum/callback/preview_update
/datum/browser/modal/preflikepicker/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1, Timeout = FALSE,list/settings,inputtype="checkbox", width = 600, height, slidecolor)
if (!User)
return
src.settings = settings
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, width, height, src, StealFocus, Timeout)
set_content(ShowChoices(User))
/datum/browser/modal/preflikepicker/proc/ShowChoices(mob/user)
if (settings["preview_callback"])
var/datum/callback/callback = settings["preview_callback"]
preview_icon = callback.Invoke(settings)
if (preview_icon)
user << browse_rsc(preview_icon, "previewicon.png")
var/dat = ""
for (var/name in settings["mainsettings"])
var/setting = settings["mainsettings"][name]
if (setting["type"] == "datum")
if (setting["subtypesonly"])
dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;subtypesonly=1;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>"
else
dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>"
else
dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;type=[setting["type"]]'>[setting["value"]]</a><BR>"
if (preview_icon)
dat += "<td valign='center'>"
dat += "<div class='statusDisplay'><center><img src=previewicon.png width=[preview_icon.Width()] height=[preview_icon.Height()]></center></div>"
dat += "</td>"
dat += "</tr></table>"
dat += "<hr><center><a href='?src=[REF(src)];button=1'>Ok</a> "
dat += "</center>"
return dat
/datum/browser/modal/preflikepicker/Topic(href,href_list)
if (href_list["close"] || !user || !user.client)
opentime = 0
return
if (href_list["task"] == "input")
var/setting = href_list["setting"]
switch (href_list["type"])
if ("datum")
var/oldval = settings["mainsettings"][setting]["value"]
if (href_list["subtypesonly"])
settings["mainsettings"][setting]["value"] = pick_closest_path(null, make_types_fancy(subtypesof(text2path(href_list["path"]))))
else
settings["mainsettings"][setting]["value"] = pick_closest_path(null, make_types_fancy(typesof(text2path(href_list["path"]))))
if (isnull(settings["mainsettings"][setting]["value"]))
settings["mainsettings"][setting]["value"] = oldval
if ("string")
settings["mainsettings"][setting]["value"] = stripped_input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]", settings["mainsettings"][setting]["value"])
if ("number")
settings["mainsettings"][setting]["value"] = input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]") as num
if ("color")
settings["mainsettings"][setting]["value"] = input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]", settings["mainsettings"][setting]["value"]) as color
if ("boolean")
settings["mainsettings"][setting]["value"] = input(user, "[settings["mainsettings"][setting]["desc"]]?") in list("Yes","No")
if ("ckey")
settings["mainsettings"][setting]["value"] = input(user, "[settings["mainsettings"][setting]["desc"]]?") in list("none") + GLOB.directory
if (settings["mainsettings"][setting]["callback"])
var/datum/callback/callback = settings["mainsettings"][setting]["callback"]
settings = callback.Invoke(settings)
if (href_list["button"])
var/button = text2num(href_list["button"])
if (button <= 3 && button >= 1)
selectedbutton = button
if (selectedbutton != 1)
set_content(ShowChoices(user))
open()
return
for (var/item in href_list)
switch(item)
if ("close", "button", "src")
continue
opentime = 0
close()
/proc/presentpreflikepicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/settings, width, height, slidecolor)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
User = C.mob
else
return
var/datum/browser/modal/preflikepicker/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus,Timeout, settings, width, height, slidecolor)
A.open()
A.wait()
if (A.selectedbutton)
return list("button" = A.selectedbutton, "settings" = A.settings)
// 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)
// 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]\"")
// 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
if(atomref!="null") // if passed a real atomref
var/hsrc = locate(atomref) // find the reffed atom
var/href = "close=1"
if(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)
src.mob.unset_machine()
/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()
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/modal/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, StealFocus, Timeout)
set_content(output)
/datum/browser/modal/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/modal/alert/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)
A.open()
A.wait()
if (A.selectedbutton)
return A.selectedbutton
/datum/browser/modal
var/opentime = 0
var/timeout
var/selectedbutton = 0
var/stealfocus
/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, StealFocus = 1, Timeout = 6000)
..()
stealfocus = StealFocus
if (!StealFocus)
window_options += "focus=false;"
timeout = Timeout
/datum/browser/modal/close()
.=..()
opentime = 0
/datum/browser/modal/open(use_onclose = 1)
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/modal/proc/wait()
while (opentime && selectedbutton <= 0 && (!timeout || opentime+timeout > world.time))
stoplag(1)
/datum/browser/modal/listpicker
var/valueslist = list()
/datum/browser/modal/listpicker/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1, Timeout = FALSE,list/values,inputtype="checkbox", width, height, slidecolor)
if (!User)
return
var/output = {"<form><input type="hidden" name="src" value="[REF(src)]"><ul class="sparse">"}
if (inputtype == "checkbox" || inputtype == "radio")
for (var/i in values)
var/div_slider = slidecolor
if(!i["allowed_edit"])
div_slider = "locked"
output += {"<li>
<label class="switch">
<input type="[inputtype]" value="1" name="[i["name"]]"[i["checked"] ? " checked" : ""][i["allowed_edit"] ? "" : " onclick='return false' onkeydown='return false'"]>
<div class="slider [div_slider ? "[div_slider]" : ""]"></div>
<span>[i["name"]]</span>
</label>
</li>"}
else
for (var/i in values)
output += {"<li><input id="name="[i["name"]]"" style="width: 50px" type="[type]" name="[i["name"]]" value="[i["value"]]">
<label for="[i["name"]]">[i["name"]]</label></li>"}
output += {"</ul><div style="text-align:center">
<button type="submit" name="button" value="1" style="font-size:large;float:[( Button2 ? "left" : "right" )]">[Button1]</button>"}
if (Button2)
output += {"<button type="submit" name="button" value="2" style="font-size:large;[( Button3 ? "" : "float:right" )]">[Button2]</button>"}
if (Button3)
output += {"<button type="submit" name="button" value="3" style="font-size:large;float:right">[Button3]</button>"}
output += {"</form></div>"}
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, width, height, src, StealFocus, Timeout)
set_content(output)
/datum/browser/modal/listpicker/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
for (var/item in href_list)
switch(item)
if ("close", "button", "src")
continue
else
valueslist[item] = href_list[item]
opentime = 0
close()
/proc/presentpicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/values, inputtype = "checkbox", width, height, slidecolor)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
User = C.mob
else
return
var/datum/browser/modal/listpicker/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus,Timeout, values, inputtype, width, height, slidecolor)
A.open()
A.wait()
if (A.selectedbutton)
return list("button" = A.selectedbutton, "values" = A.valueslist)
/proc/input_bitfield(var/mob/User, title, bitfield, current_value, nwidth = 350, nheight = 350, nslidecolor, allowed_edit_list = null)
if (!User || !(bitfield in GLOB.bitfields))
return
var/list/pickerlist = list()
for (var/i in GLOB.bitfields[bitfield])
var/can_edit = 1
if(!isnull(allowed_edit_list) && !(allowed_edit_list & GLOB.bitfields[bitfield][i]))
can_edit = 0
if (current_value & GLOB.bitfields[bitfield][i])
pickerlist += list(list("checked" = 1, "value" = GLOB.bitfields[bitfield][i], "name" = i, "allowed_edit" = can_edit))
else
pickerlist += list(list("checked" = 0, "value" = GLOB.bitfields[bitfield][i], "name" = i, "allowed_edit" = can_edit))
var/list/result = presentpicker(User, "", title, Button1="Save", Button2 = "Cancel", Timeout=FALSE, values = pickerlist, width = nwidth, height = nheight, slidecolor = nslidecolor)
if (islist(result))
if (result["button"] == 2) // If the user pressed the cancel button
return
. = 0
for (var/flag in result["values"])
. |= GLOB.bitfields[bitfield][flag]
else
return
/datum/browser/modal/preflikepicker
var/settings = list()
var/icon/preview_icon = null
var/datum/callback/preview_update
/datum/browser/modal/preflikepicker/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1, Timeout = FALSE,list/settings,inputtype="checkbox", width = 600, height, slidecolor)
if (!User)
return
src.settings = settings
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, width, height, src, StealFocus, Timeout)
set_content(ShowChoices(User))
/datum/browser/modal/preflikepicker/proc/ShowChoices(mob/user)
if (settings["preview_callback"])
var/datum/callback/callback = settings["preview_callback"]
preview_icon = callback.Invoke(settings)
if (preview_icon)
user << browse_rsc(preview_icon, "previewicon.png")
var/dat = ""
for (var/name in settings["mainsettings"])
var/setting = settings["mainsettings"][name]
if (setting["type"] == "datum")
if (setting["subtypesonly"])
dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;subtypesonly=1;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>"
else
dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>"
else
dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;type=[setting["type"]]'>[setting["value"]]</a><BR>"
if (preview_icon)
dat += "<td valign='center'>"
dat += "<div class='statusDisplay'><center><img src=previewicon.png width=[preview_icon.Width()] height=[preview_icon.Height()]></center></div>"
dat += "</td>"
dat += "</tr></table>"
dat += "<hr><center><a href='?src=[REF(src)];button=1'>Ok</a> "
dat += "</center>"
return dat
/datum/browser/modal/preflikepicker/Topic(href,href_list)
if (href_list["close"] || !user || !user.client)
opentime = 0
return
if (href_list["task"] == "input")
var/setting = href_list["setting"]
switch (href_list["type"])
if ("datum")
var/oldval = settings["mainsettings"][setting]["value"]
if (href_list["subtypesonly"])
settings["mainsettings"][setting]["value"] = pick_closest_path(null, make_types_fancy(subtypesof(text2path(href_list["path"]))))
else
settings["mainsettings"][setting]["value"] = pick_closest_path(null, make_types_fancy(typesof(text2path(href_list["path"]))))
if (isnull(settings["mainsettings"][setting]["value"]))
settings["mainsettings"][setting]["value"] = oldval
if ("string")
settings["mainsettings"][setting]["value"] = stripped_input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]", settings["mainsettings"][setting]["value"])
if ("number")
settings["mainsettings"][setting]["value"] = input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]") as num
if ("color")
settings["mainsettings"][setting]["value"] = input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]", settings["mainsettings"][setting]["value"]) as color
if ("boolean")
settings["mainsettings"][setting]["value"] = input(user, "[settings["mainsettings"][setting]["desc"]]?") in list("Yes","No")
if ("ckey")
settings["mainsettings"][setting]["value"] = input(user, "[settings["mainsettings"][setting]["desc"]]?") in list("none") + GLOB.directory
if (settings["mainsettings"][setting]["callback"])
var/datum/callback/callback = settings["mainsettings"][setting]["callback"]
settings = callback.Invoke(settings)
if (href_list["button"])
var/button = text2num(href_list["button"])
if (button <= 3 && button >= 1)
selectedbutton = button
if (selectedbutton != 1)
set_content(ShowChoices(user))
open()
return
for (var/item in href_list)
switch(item)
if ("close", "button", "src")
continue
opentime = 0
close()
/proc/presentpreflikepicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/settings, width, height, slidecolor)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
User = C.mob
else
return
var/datum/browser/modal/preflikepicker/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus,Timeout, settings, width, height, slidecolor)
A.open()
A.wait()
if (A.selectedbutton)
return list("button" = A.selectedbutton, "settings" = A.settings)
// 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)
// 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]\"")
// 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
if(atomref!="null") // if passed a real atomref
var/hsrc = locate(atomref) // find the reffed atom
var/href = "close=1"
if(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)
src.mob.unset_machine()
+314 -314
View File
@@ -1,314 +1,314 @@
/datum/component
var/dupe_mode = COMPONENT_DUPE_HIGHLANDER
var/dupe_type
var/datum/parent
//only set to true if you are able to properly transfer this component
//At a minimum RegisterWithParent and UnregisterFromParent should be used
//Make sure you also implement PostTransfer for any post transfer handling
var/can_transfer = FALSE
/datum/component/New(datum/P, ...)
parent = P
var/list/arguments = args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
qdel(src, TRUE, TRUE)
CRASH("Incompatible [type] assigned to a [P.type]! args: [json_encode(arguments)]")
_JoinParent(P)
/datum/component/proc/_JoinParent()
var/datum/P = parent
//lazy init the parent's dc list
var/list/dc = P.datum_components
if(!dc)
P.datum_components = dc = list()
//set up the typecache
var/our_type = type
for(var/I in _GetInverseTypeList(our_type))
var/test = dc[I]
if(test) //already another component of this type here
var/list/components_of_type
if(!length(test))
components_of_type = list(test)
dc[I] = components_of_type
else
components_of_type = test
if(I == our_type) //exact match, take priority
var/inserted = FALSE
for(var/J in 1 to components_of_type.len)
var/datum/component/C = components_of_type[J]
if(C.type != our_type) //but not over other exact matches
components_of_type.Insert(J, I)
inserted = TRUE
break
if(!inserted)
components_of_type += src
else //indirect match, back of the line with ya
components_of_type += src
else //only component of this type, no list
dc[I] = src
RegisterWithParent()
// If you want/expect to be moving the component around between parents, use this to register on the parent for signals
/datum/component/proc/RegisterWithParent()
SEND_SIGNAL(src, COMSIG_COMPONENT_REGISTER_PARENT) //CITADEL EDIT
/datum/component/proc/Initialize(...)
return
/datum/component/Destroy(force=FALSE, silent=FALSE)
if(!force && parent)
_RemoveFromParent()
if(!silent)
SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
parent = null
return ..()
/datum/component/proc/_RemoveFromParent()
var/datum/P = parent
var/list/dc = P.datum_components
for(var/I in _GetInverseTypeList())
var/list/components_of_type = dc[I]
if(length(components_of_type)) //
var/list/subtracted = components_of_type - src
if(subtracted.len == 1) //only 1 guy left
dc[I] = subtracted[1] //make him special
else
dc[I] = subtracted
else //just us
dc -= I
if(!dc.len)
P.datum_components = null
UnregisterFromParent()
/datum/component/proc/UnregisterFromParent()
SEND_SIGNAL(src, COMSIG_COMPONENT_UNREGISTER_PARENT) //CITADEL EDIT
/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proctype, override = FALSE)
if(QDELETED(src) || QDELETED(target))
return
var/list/procs = signal_procs
if(!procs)
signal_procs = procs = list()
if(!procs[target])
procs[target] = list()
var/list/lookup = target.comp_lookup
if(!lookup)
target.comp_lookup = lookup = list()
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override && procs[target][sig_type])
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
procs[target][sig_type] = proctype
if(!lookup[sig_type]) // Nothing has registered here yet
lookup[sig_type] = src
else if(lookup[sig_type] == src) // We already registered here
continue
else if(!length(lookup[sig_type])) // One other thing registered here
lookup[sig_type] = list(lookup[sig_type]=TRUE)
lookup[sig_type][src] = TRUE
else // Many other things have registered here
lookup[sig_type][src] = TRUE
signal_enabled = TRUE
/datum/proc/UnregisterSignal(datum/target, sig_type_or_types)
var/list/lookup = target.comp_lookup
if(!signal_procs || !signal_procs[target] || !lookup)
return
if(!islist(sig_type_or_types))
sig_type_or_types = list(sig_type_or_types)
for(var/sig in sig_type_or_types)
switch(length(lookup[sig]))
if(2)
lookup[sig] = (lookup[sig]-src)[1]
if(1)
stack_trace("[target] ([target.type]) somehow has single length list inside comp_lookup")
if(src in lookup[sig])
lookup -= sig
if(!length(lookup))
target.comp_lookup = null
break
if(0)
lookup -= sig
if(!length(lookup))
target.comp_lookup = null
break
else
lookup[sig] -= src
signal_procs[target] -= sig_type_or_types
if(!signal_procs[target].len)
signal_procs -= target
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
return
/datum/component/proc/PreTransfer()
return
/datum/component/proc/PostTransfer()
return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it
/datum/component/proc/_GetInverseTypeList(our_type = type)
//we can do this one simple trick
var/current_type = parent_type
. = list(our_type, current_type)
//and since most components are root level + 1, this won't even have to run
while (current_type != /datum/component)
current_type = type2parent(current_type)
. += current_type
/datum/proc/_SendSignal(sigtype, list/arguments)
var/target = comp_lookup[sigtype]
if(!length(target))
var/datum/C = target
if(!C.signal_enabled)
return NONE
var/proctype = C.signal_procs[src][sigtype]
return NONE | CallAsync(C, proctype, arguments)
. = NONE
for(var/I in target)
var/datum/C = I
if(!C.signal_enabled)
continue
var/proctype = C.signal_procs[src][sigtype]
. |= CallAsync(C, proctype, arguments)
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
/datum/proc/GetComponent(datum/component/c_type)
RETURN_TYPE(c_type)
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED)
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components
if(!dc)
return null
. = dc[c_type]
if(length(.))
return .[1]
/datum/proc/GetExactComponent(c_type)
var/list/dc = datum_components
if(!dc)
return null
var/datum/component/C = dc[c_type]
if(C)
if(length(C))
C = C[1]
if(C.type == c_type)
return C
return null
/datum/proc/GetComponents(c_type)
var/list/dc = datum_components
if(!dc)
return null
. = dc[c_type]
if(!length(.))
return list(.)
/datum/proc/AddComponent(new_type, ...)
var/datum/component/nt = new_type
var/dm = initial(nt.dupe_mode)
var/dt = initial(nt.dupe_type)
var/datum/component/old_comp
var/datum/component/new_comp
if(ispath(nt))
if(nt == /datum/component)
CRASH("[nt] attempted instantiation!")
else
new_comp = nt
nt = new_comp.type
args[1] = src
if(dm != COMPONENT_DUPE_ALLOWED)
if(!dt)
old_comp = GetExactComponent(nt)
else
old_comp = GetComponent(dt)
if(old_comp)
switch(dm)
if(COMPONENT_DUPE_UNIQUE)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
old_comp.InheritComponent(new_comp, TRUE)
QDEL_NULL(new_comp)
if(COMPONENT_DUPE_HIGHLANDER)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
new_comp.InheritComponent(old_comp, FALSE)
QDEL_NULL(old_comp)
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
if(!new_comp)
var/list/arguments = args.Copy(2)
old_comp.InheritComponent(null, TRUE, arguments)
else
old_comp.InheritComponent(new_comp, TRUE)
else if(!new_comp)
new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
else if(!new_comp)
new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
if(!.)
return AddComponent(arglist(args))
/datum/component/proc/RemoveComponent()
if(!parent)
return
var/datum/old_parent = parent
PreTransfer()
_RemoveFromParent()
parent = null
SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src)
/datum/proc/TakeComponent(datum/component/target)
if(!target || target.parent == src)
return
if(target.parent)
target.RemoveComponent()
target.parent = src
var/result = target.PostTransfer()
switch(result)
if(COMPONENT_INCOMPATIBLE)
var/c_type = target.type
qdel(target)
CRASH("Incompatible [c_type] transfer attempt to a [type]!")
if(target == AddComponent(target))
target._JoinParent()
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
if(!dc)
return
var/comps = dc[/datum/component]
if(islist(comps))
for(var/datum/component/I in comps)
if(I.can_transfer)
target.TakeComponent(I)
else
var/datum/component/C = comps
if(C.can_transfer)
target.TakeComponent(comps)
/datum/component/ui_host()
return parent
/datum/component
var/dupe_mode = COMPONENT_DUPE_HIGHLANDER
var/dupe_type
var/datum/parent
//only set to true if you are able to properly transfer this component
//At a minimum RegisterWithParent and UnregisterFromParent should be used
//Make sure you also implement PostTransfer for any post transfer handling
var/can_transfer = FALSE
/datum/component/New(datum/P, ...)
parent = P
var/list/arguments = args.Copy(2)
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
qdel(src, TRUE, TRUE)
CRASH("Incompatible [type] assigned to a [P.type]! args: [json_encode(arguments)]")
_JoinParent(P)
/datum/component/proc/_JoinParent()
var/datum/P = parent
//lazy init the parent's dc list
var/list/dc = P.datum_components
if(!dc)
P.datum_components = dc = list()
//set up the typecache
var/our_type = type
for(var/I in _GetInverseTypeList(our_type))
var/test = dc[I]
if(test) //already another component of this type here
var/list/components_of_type
if(!length(test))
components_of_type = list(test)
dc[I] = components_of_type
else
components_of_type = test
if(I == our_type) //exact match, take priority
var/inserted = FALSE
for(var/J in 1 to components_of_type.len)
var/datum/component/C = components_of_type[J]
if(C.type != our_type) //but not over other exact matches
components_of_type.Insert(J, I)
inserted = TRUE
break
if(!inserted)
components_of_type += src
else //indirect match, back of the line with ya
components_of_type += src
else //only component of this type, no list
dc[I] = src
RegisterWithParent()
// If you want/expect to be moving the component around between parents, use this to register on the parent for signals
/datum/component/proc/RegisterWithParent()
SEND_SIGNAL(src, COMSIG_COMPONENT_REGISTER_PARENT) //CITADEL EDIT
/datum/component/proc/Initialize(...)
return
/datum/component/Destroy(force=FALSE, silent=FALSE)
if(!force && parent)
_RemoveFromParent()
if(!silent)
SEND_SIGNAL(parent, COMSIG_COMPONENT_REMOVING, src)
parent = null
return ..()
/datum/component/proc/_RemoveFromParent()
var/datum/P = parent
var/list/dc = P.datum_components
for(var/I in _GetInverseTypeList())
var/list/components_of_type = dc[I]
if(length(components_of_type)) //
var/list/subtracted = components_of_type - src
if(subtracted.len == 1) //only 1 guy left
dc[I] = subtracted[1] //make him special
else
dc[I] = subtracted
else //just us
dc -= I
if(!dc.len)
P.datum_components = null
UnregisterFromParent()
/datum/component/proc/UnregisterFromParent()
SEND_SIGNAL(src, COMSIG_COMPONENT_UNREGISTER_PARENT) //CITADEL EDIT
/datum/proc/RegisterSignal(datum/target, sig_type_or_types, proctype, override = FALSE)
if(QDELETED(src) || QDELETED(target))
return
var/list/procs = signal_procs
if(!procs)
signal_procs = procs = list()
if(!procs[target])
procs[target] = list()
var/list/lookup = target.comp_lookup
if(!lookup)
target.comp_lookup = lookup = list()
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override && procs[target][sig_type])
stack_trace("[sig_type] overridden. Use override = TRUE to suppress this warning")
procs[target][sig_type] = proctype
if(!lookup[sig_type]) // Nothing has registered here yet
lookup[sig_type] = src
else if(lookup[sig_type] == src) // We already registered here
continue
else if(!length(lookup[sig_type])) // One other thing registered here
lookup[sig_type] = list(lookup[sig_type]=TRUE)
lookup[sig_type][src] = TRUE
else // Many other things have registered here
lookup[sig_type][src] = TRUE
signal_enabled = TRUE
/datum/proc/UnregisterSignal(datum/target, sig_type_or_types)
var/list/lookup = target.comp_lookup
if(!signal_procs || !signal_procs[target] || !lookup)
return
if(!islist(sig_type_or_types))
sig_type_or_types = list(sig_type_or_types)
for(var/sig in sig_type_or_types)
switch(length(lookup[sig]))
if(2)
lookup[sig] = (lookup[sig]-src)[1]
if(1)
stack_trace("[target] ([target.type]) somehow has single length list inside comp_lookup")
if(src in lookup[sig])
lookup -= sig
if(!length(lookup))
target.comp_lookup = null
break
if(0)
lookup -= sig
if(!length(lookup))
target.comp_lookup = null
break
else
lookup[sig] -= src
signal_procs[target] -= sig_type_or_types
if(!signal_procs[target].len)
signal_procs -= target
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
return
/datum/component/proc/PreTransfer()
return
/datum/component/proc/PostTransfer()
return COMPONENT_INCOMPATIBLE //Do not support transfer by default as you must properly support it
/datum/component/proc/_GetInverseTypeList(our_type = type)
//we can do this one simple trick
var/current_type = parent_type
. = list(our_type, current_type)
//and since most components are root level + 1, this won't even have to run
while (current_type != /datum/component)
current_type = type2parent(current_type)
. += current_type
/datum/proc/_SendSignal(sigtype, list/arguments)
var/target = comp_lookup[sigtype]
if(!length(target))
var/datum/C = target
if(!C.signal_enabled)
return NONE
var/proctype = C.signal_procs[src][sigtype]
return NONE | CallAsync(C, proctype, arguments)
. = NONE
for(var/I in target)
var/datum/C = I
if(!C.signal_enabled)
continue
var/proctype = C.signal_procs[src][sigtype]
. |= CallAsync(C, proctype, arguments)
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
/datum/proc/GetComponent(datum/component/c_type)
RETURN_TYPE(c_type)
if(initial(c_type.dupe_mode) == COMPONENT_DUPE_ALLOWED)
stack_trace("GetComponent was called to get a component of which multiple copies could be on an object. This can easily break and should be changed. Type: \[[c_type]\]")
var/list/dc = datum_components
if(!dc)
return null
. = dc[c_type]
if(length(.))
return .[1]
/datum/proc/GetExactComponent(c_type)
var/list/dc = datum_components
if(!dc)
return null
var/datum/component/C = dc[c_type]
if(C)
if(length(C))
C = C[1]
if(C.type == c_type)
return C
return null
/datum/proc/GetComponents(c_type)
var/list/dc = datum_components
if(!dc)
return null
. = dc[c_type]
if(!length(.))
return list(.)
/datum/proc/AddComponent(new_type, ...)
var/datum/component/nt = new_type
var/dm = initial(nt.dupe_mode)
var/dt = initial(nt.dupe_type)
var/datum/component/old_comp
var/datum/component/new_comp
if(ispath(nt))
if(nt == /datum/component)
CRASH("[nt] attempted instantiation!")
else
new_comp = nt
nt = new_comp.type
args[1] = src
if(dm != COMPONENT_DUPE_ALLOWED)
if(!dt)
old_comp = GetExactComponent(nt)
else
old_comp = GetComponent(dt)
if(old_comp)
switch(dm)
if(COMPONENT_DUPE_UNIQUE)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
old_comp.InheritComponent(new_comp, TRUE)
QDEL_NULL(new_comp)
if(COMPONENT_DUPE_HIGHLANDER)
if(!new_comp)
new_comp = new nt(arglist(args))
if(!QDELETED(new_comp))
new_comp.InheritComponent(old_comp, FALSE)
QDEL_NULL(old_comp)
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
if(!new_comp)
var/list/arguments = args.Copy(2)
old_comp.InheritComponent(null, TRUE, arguments)
else
old_comp.InheritComponent(new_comp, TRUE)
else if(!new_comp)
new_comp = new nt(arglist(args)) // There's a valid dupe mode but there's no old component, act like normal
else if(!new_comp)
new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
/datum/proc/LoadComponent(component_type, ...)
. = GetComponent(component_type)
if(!.)
return AddComponent(arglist(args))
/datum/component/proc/RemoveComponent()
if(!parent)
return
var/datum/old_parent = parent
PreTransfer()
_RemoveFromParent()
parent = null
SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src)
/datum/proc/TakeComponent(datum/component/target)
if(!target || target.parent == src)
return
if(target.parent)
target.RemoveComponent()
target.parent = src
var/result = target.PostTransfer()
switch(result)
if(COMPONENT_INCOMPATIBLE)
var/c_type = target.type
qdel(target)
CRASH("Incompatible [c_type] transfer attempt to a [type]!")
if(target == AddComponent(target))
target._JoinParent()
/datum/proc/TransferComponents(datum/target)
var/list/dc = datum_components
if(!dc)
return
var/comps = dc[/datum/component]
if(islist(comps))
for(var/datum/component/I in comps)
if(I.can_transfer)
target.TakeComponent(I)
else
var/datum/component/C = comps
if(C.can_transfer)
target.TakeComponent(comps)
/datum/component/ui_host()
return parent
+74 -74
View File
@@ -1,74 +1,74 @@
/datum/component/jousting
var/current_direction = NONE
var/max_tile_charge = 5
var/min_tile_charge = 2 //tiles before this code gets into effect.
var/current_tile_charge = 0
var/movement_reset_tolerance = 2 //deciseconds
var/unmounted_damage_boost_per_tile = 0
var/unmounted_knockdown_chance_per_tile = 0
var/unmounted_knockdown_time = 0
var/mounted_damage_boost_per_tile = 2
var/mounted_knockdown_chance_per_tile = 20
var/mounted_knockdown_time = 20
var/requires_mob_riding = TRUE //whether this only works if the attacker is riding a mob, rather than anything they can buckle to.
var/requires_mount = TRUE //kinda defeats the point of jousting if you're not mounted but whatever.
var/mob/current_holder
var/current_timerid
/datum/component/jousting/Initialize()
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop)
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/on_attack)
/datum/component/jousting/proc/on_equip(datum/source, mob/user, slot)
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/mob_move, TRUE)
current_holder = user
/datum/component/jousting/proc/on_drop(datum/source, mob/user)
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
current_holder = null
current_direction = NONE
current_tile_charge = 0
/datum/component/jousting/proc/on_attack(datum/source, mob/living/target, mob/user)
if(user != current_holder)
return
var/current = current_tile_charge
var/obj/item/I = parent
var/target_buckled = target.buckled ? TRUE : FALSE //we don't need the reference of what they're buckled to, just whether they are.
if((requires_mount && ((requires_mob_riding && !ismob(user.buckled)) || (!user.buckled))) || !current_direction || (current_tile_charge < min_tile_charge))
return
var/turf/target_turf = get_step(user, current_direction)
if(target in range(1, target_turf))
var/knockdown_chance = (target_buckled? mounted_knockdown_chance_per_tile : unmounted_knockdown_chance_per_tile) * current
var/knockdown_time = (target_buckled? mounted_knockdown_time : unmounted_knockdown_time)
var/damage = (target_buckled? mounted_damage_boost_per_tile : unmounted_damage_boost_per_tile) * current
var/sharp = I.get_sharpness()
var/msg
if(damage)
msg += "[user] [sharp? "impales" : "slams into"] [target] [sharp? "on" : "with"] their [parent]"
target.apply_damage(damage, BRUTE, user.zone_selected, 0)
if(prob(knockdown_chance))
msg += " and knocks [target] [target_buckled? "off of [target.buckled]" : "down"]"
if(target_buckled)
target.buckled.unbuckle_mob(target)
target.Knockdown(knockdown_time)
if(length(msg))
user.visible_message("<span class='danger'>[msg]!</span>")
/datum/component/jousting/proc/mob_move(datum/source, newloc, dir)
if(!current_holder || (requires_mount && ((requires_mob_riding && !ismob(current_holder.buckled)) || (!current_holder.buckled))))
return
if(dir != current_direction)
current_tile_charge = 0
current_direction = dir
if(current_tile_charge < max_tile_charge)
current_tile_charge++
if(current_timerid)
deltimer(current_timerid)
current_timerid = addtimer(CALLBACK(src, .proc/reset_charge), movement_reset_tolerance, TIMER_STOPPABLE)
/datum/component/jousting/proc/reset_charge()
current_tile_charge = 0
/datum/component/jousting
var/current_direction = NONE
var/max_tile_charge = 5
var/min_tile_charge = 2 //tiles before this code gets into effect.
var/current_tile_charge = 0
var/movement_reset_tolerance = 2 //deciseconds
var/unmounted_damage_boost_per_tile = 0
var/unmounted_knockdown_chance_per_tile = 0
var/unmounted_knockdown_time = 0
var/mounted_damage_boost_per_tile = 2
var/mounted_knockdown_chance_per_tile = 20
var/mounted_knockdown_time = 20
var/requires_mob_riding = TRUE //whether this only works if the attacker is riding a mob, rather than anything they can buckle to.
var/requires_mount = TRUE //kinda defeats the point of jousting if you're not mounted but whatever.
var/mob/current_holder
var/current_timerid
/datum/component/jousting/Initialize()
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop)
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/on_attack)
/datum/component/jousting/proc/on_equip(datum/source, mob/user, slot)
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/mob_move, TRUE)
current_holder = user
/datum/component/jousting/proc/on_drop(datum/source, mob/user)
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
current_holder = null
current_direction = NONE
current_tile_charge = 0
/datum/component/jousting/proc/on_attack(datum/source, mob/living/target, mob/user)
if(user != current_holder)
return
var/current = current_tile_charge
var/obj/item/I = parent
var/target_buckled = target.buckled ? TRUE : FALSE //we don't need the reference of what they're buckled to, just whether they are.
if((requires_mount && ((requires_mob_riding && !ismob(user.buckled)) || (!user.buckled))) || !current_direction || (current_tile_charge < min_tile_charge))
return
var/turf/target_turf = get_step(user, current_direction)
if(target in range(1, target_turf))
var/knockdown_chance = (target_buckled? mounted_knockdown_chance_per_tile : unmounted_knockdown_chance_per_tile) * current
var/knockdown_time = (target_buckled? mounted_knockdown_time : unmounted_knockdown_time)
var/damage = (target_buckled? mounted_damage_boost_per_tile : unmounted_damage_boost_per_tile) * current
var/sharp = I.get_sharpness()
var/msg
if(damage)
msg += "[user] [sharp? "impales" : "slams into"] [target] [sharp? "on" : "with"] their [parent]"
target.apply_damage(damage, BRUTE, user.zone_selected, 0)
if(prob(knockdown_chance))
msg += " and knocks [target] [target_buckled? "off of [target.buckled]" : "down"]"
if(target_buckled)
target.buckled.unbuckle_mob(target)
target.Knockdown(knockdown_time)
if(length(msg))
user.visible_message("<span class='danger'>[msg]!</span>")
/datum/component/jousting/proc/mob_move(datum/source, newloc, dir)
if(!current_holder || (requires_mount && ((requires_mob_riding && !ismob(current_holder.buckled)) || (!current_holder.buckled))))
return
if(dir != current_direction)
current_tile_charge = 0
current_direction = dir
if(current_tile_charge < max_tile_charge)
current_tile_charge++
if(current_timerid)
deltimer(current_timerid)
current_timerid = addtimer(CALLBACK(src, .proc/reset_charge), movement_reset_tolerance, TIMER_STOPPABLE)
/datum/component/jousting/proc/reset_charge()
current_tile_charge = 0
+239 -239
View File
@@ -1,239 +1,239 @@
#define LOCKON_AIMING_MAX_CURSOR_RADIUS 7
#define LOCKON_IGNORE_RESULT "ignore_my_result"
#define LOCKON_RANGING_BREAK_CHECK if(current_ranging_id != this_id){return LOCKON_IGNORE_RESULT}
/datum/component/lockon_aiming
dupe_mode = COMPONENT_DUPE_ALLOWED
var/lock_icon = 'icons/mob/cameramob.dmi'
var/lock_icon_state = "marker"
var/mutable_appearance/lock_appearance
var/list/image/lock_images
var/list/target_typecache
var/list/immune_weakrefs //list(weakref = TRUE)
var/mob_stat_check = TRUE //if a potential target is a mob make sure it's conscious!
var/lock_amount = 1
var/lock_cursor_range = 5
var/list/locked_weakrefs
var/update_disabled = FALSE
var/current_ranging_id = 0
var/list/last_location
var/datum/callback/on_lock
var/datum/callback/can_target_callback
/datum/component/lockon_aiming/Initialize(range, list/typecache, amount, list/immune, datum/callback/when_locked, icon, icon_state, datum/callback/target_callback)
if(!ismob(parent))
return COMPONENT_INCOMPATIBLE
if(target_callback)
can_target_callback = target_callback
else
can_target_callback = CALLBACK(src, .proc/can_target)
if(range)
lock_cursor_range = range
if(typecache)
target_typecache = typecache
if(amount)
lock_amount = amount
immune_weakrefs = list(WEAKREF(parent) = TRUE) //Manually take this out if you want..
if(immune)
for(var/i in immune)
if(isweakref(i))
immune_weakrefs[i] = TRUE
else if(isatom(i))
immune_weakrefs[WEAKREF(i)] = TRUE
if(when_locked)
on_lock = when_locked
if(icon)
lock_icon = icon
if(icon_state)
lock_icon_state = icon_state
generate_lock_visuals()
var/mob/M = parent
LAZYOR(M.mousemove_intercept_objects, src)
START_PROCESSING(SSfastprocess, src)
/datum/component/lockon_aiming/Destroy()
var/mob/M = parent
clear_visuals()
LAZYREMOVE(M.mousemove_intercept_objects, src)
STOP_PROCESSING(SSfastprocess, src)
return ..()
/datum/component/lockon_aiming/proc/show_visuals()
LAZYINITLIST(lock_images)
var/mob/M = parent
if(!M.client)
return
for(var/i in locked_weakrefs)
var/datum/weakref/R = i
var/atom/A = R.resolve()
if(!A)
continue //It'll be cleared by processing.
var/image/I = new
I.appearance = lock_appearance
I.loc = A
M.client.images |= I
lock_images |= I
/datum/component/lockon_aiming/proc/clear_visuals()
var/mob/M = parent
if(!M.client)
return
if(!lock_images)
return
for(var/i in lock_images)
M.client.images -= i
qdel(i)
lock_images.Cut()
/datum/component/lockon_aiming/proc/refresh_visuals()
clear_visuals()
show_visuals()
/datum/component/lockon_aiming/proc/generate_lock_visuals()
lock_appearance = mutable_appearance(icon = lock_icon, icon_state = lock_icon_state, layer = FLOAT_LAYER)
/datum/component/lockon_aiming/proc/unlock_all(refresh_vis = TRUE)
LAZYCLEARLIST(locked_weakrefs)
if(refresh_vis)
refresh_visuals()
/datum/component/lockon_aiming/proc/unlock(atom/A, refresh_vis = TRUE)
if(!A.weak_reference)
return
LAZYREMOVE(locked_weakrefs, A.weak_reference)
if(refresh_vis)
refresh_visuals()
/datum/component/lockon_aiming/proc/lock(atom/A, refresh_vis = TRUE)
LAZYOR(locked_weakrefs, WEAKREF(A))
if(refresh_vis)
refresh_visuals()
/datum/component/lockon_aiming/proc/add_immune_atom(atom/A)
var/datum/weakref/R = WEAKREF(A)
if(immune_weakrefs && (immune_weakrefs[R]))
return
LAZYSET(immune_weakrefs, R, TRUE)
/datum/component/lockon_aiming/proc/remove_immune_atom(atom/A)
if(!A.weak_reference || !immune_weakrefs) //if A doesn't have a weakref how did it get on the immunity list?
return
LAZYREMOVE(immune_weakrefs, A.weak_reference)
/datum/component/lockon_aiming/onMouseMove(object,location,control,params)
var/mob/M = parent
if(!istype(M) || !M.client)
return
var/datum/position/P = mouse_absolute_datum_map_position_from_client(M.client)
if(!P)
return
var/turf/T = P.return_turf()
LAZYINITLIST(last_location)
if(length(last_location) == 3 && last_location[1] == T.x && last_location[2] == T.y && last_location[3] == T.z)
return //Same turf, don't bother.
if(last_location)
last_location.Cut()
else
last_location = list()
last_location.len = 3
last_location[1] = T.x
last_location[2] = T.y
last_location[3] = T.z
autolock()
/datum/component/lockon_aiming/process()
if(update_disabled)
return
if(!last_location)
return
var/changed = FALSE
for(var/i in locked_weakrefs)
var/datum/weakref/R = i
if(istype(R))
var/atom/thing = R.resolve()
if(!istype(thing) || (get_dist(thing, locate(last_location[1], last_location[2], last_location[3])) > lock_cursor_range))
unlock(R)
changed = TRUE
else
unlock(R)
changed = TRUE
if(changed)
autolock()
/datum/component/lockon_aiming/proc/autolock()
var/mob/M = parent
if(!M.client)
return FALSE
var/datum/position/current = mouse_absolute_datum_map_position_from_client(M.client)
var/turf/target = current.return_turf()
var/list/atom/targets = get_nearest(target, target_typecache, lock_amount, lock_cursor_range)
if(targets == LOCKON_IGNORE_RESULT)
return
unlock_all(FALSE)
for(var/i in targets)
if(immune_weakrefs[WEAKREF(i)])
continue
lock(i, FALSE)
refresh_visuals()
on_lock.Invoke(locked_weakrefs)
/datum/component/lockon_aiming/proc/can_target(atom/A)
var/mob/M = A
return is_type_in_typecache(A, target_typecache) && !(ismob(A) && mob_stat_check && M.stat != CONSCIOUS) && !immune_weakrefs[WEAKREF(A)]
/datum/component/lockon_aiming/proc/get_nearest(turf/T, list/typecache, amount, range)
current_ranging_id++
var/this_id = current_ranging_id
var/list/L = list()
var/turf/center = get_turf(T)
if(amount < 1 || range < 0 || !istype(center) || !islist(typecache))
return
if(range == 0)
return typecache_filter_list(T.contents + T, typecache)
var/x = 0
var/y = 0
var/cd = 0
while(cd <= range)
x = center.x - cd + 1
y = center.y + cd
LOCKON_RANGING_BREAK_CHECK
for(x in x to center.x + cd)
T = locate(x, y, center.z)
if(T)
L |= special_list_filter(T.contents, can_target_callback)
if(L.len >= amount)
L.Cut(amount+1)
return L
LOCKON_RANGING_BREAK_CHECK
y = center.y + cd - 1
x = center.x + cd
for(y in center.y - cd to y)
T = locate(x, y, center.z)
if(T)
L |= special_list_filter(T.contents, can_target_callback)
if(L.len >= amount)
L.Cut(amount+1)
return L
LOCKON_RANGING_BREAK_CHECK
y = center.y - cd
x = center.x + cd - 1
for(x in center.x - cd to x)
T = locate(x, y, center.z)
if(T)
L |= special_list_filter(T.contents, can_target_callback)
if(L.len >= amount)
L.Cut(amount+1)
return L
LOCKON_RANGING_BREAK_CHECK
y = center.y - cd + 1
x = center.x - cd
for(y in y to center.y + cd)
T = locate(x, y, center.z)
if(T)
L |= special_list_filter(T.contents, can_target_callback)
if(L.len >= amount)
L.Cut(amount+1)
return L
LOCKON_RANGING_BREAK_CHECK
cd++
CHECK_TICK
#define LOCKON_AIMING_MAX_CURSOR_RADIUS 7
#define LOCKON_IGNORE_RESULT "ignore_my_result"
#define LOCKON_RANGING_BREAK_CHECK if(current_ranging_id != this_id){return LOCKON_IGNORE_RESULT}
/datum/component/lockon_aiming
dupe_mode = COMPONENT_DUPE_ALLOWED
var/lock_icon = 'icons/mob/cameramob.dmi'
var/lock_icon_state = "marker"
var/mutable_appearance/lock_appearance
var/list/image/lock_images
var/list/target_typecache
var/list/immune_weakrefs //list(weakref = TRUE)
var/mob_stat_check = TRUE //if a potential target is a mob make sure it's conscious!
var/lock_amount = 1
var/lock_cursor_range = 5
var/list/locked_weakrefs
var/update_disabled = FALSE
var/current_ranging_id = 0
var/list/last_location
var/datum/callback/on_lock
var/datum/callback/can_target_callback
/datum/component/lockon_aiming/Initialize(range, list/typecache, amount, list/immune, datum/callback/when_locked, icon, icon_state, datum/callback/target_callback)
if(!ismob(parent))
return COMPONENT_INCOMPATIBLE
if(target_callback)
can_target_callback = target_callback
else
can_target_callback = CALLBACK(src, .proc/can_target)
if(range)
lock_cursor_range = range
if(typecache)
target_typecache = typecache
if(amount)
lock_amount = amount
immune_weakrefs = list(WEAKREF(parent) = TRUE) //Manually take this out if you want..
if(immune)
for(var/i in immune)
if(isweakref(i))
immune_weakrefs[i] = TRUE
else if(isatom(i))
immune_weakrefs[WEAKREF(i)] = TRUE
if(when_locked)
on_lock = when_locked
if(icon)
lock_icon = icon
if(icon_state)
lock_icon_state = icon_state
generate_lock_visuals()
var/mob/M = parent
LAZYOR(M.mousemove_intercept_objects, src)
START_PROCESSING(SSfastprocess, src)
/datum/component/lockon_aiming/Destroy()
var/mob/M = parent
clear_visuals()
LAZYREMOVE(M.mousemove_intercept_objects, src)
STOP_PROCESSING(SSfastprocess, src)
return ..()
/datum/component/lockon_aiming/proc/show_visuals()
LAZYINITLIST(lock_images)
var/mob/M = parent
if(!M.client)
return
for(var/i in locked_weakrefs)
var/datum/weakref/R = i
var/atom/A = R.resolve()
if(!A)
continue //It'll be cleared by processing.
var/image/I = new
I.appearance = lock_appearance
I.loc = A
M.client.images |= I
lock_images |= I
/datum/component/lockon_aiming/proc/clear_visuals()
var/mob/M = parent
if(!M.client)
return
if(!lock_images)
return
for(var/i in lock_images)
M.client.images -= i
qdel(i)
lock_images.Cut()
/datum/component/lockon_aiming/proc/refresh_visuals()
clear_visuals()
show_visuals()
/datum/component/lockon_aiming/proc/generate_lock_visuals()
lock_appearance = mutable_appearance(icon = lock_icon, icon_state = lock_icon_state, layer = FLOAT_LAYER)
/datum/component/lockon_aiming/proc/unlock_all(refresh_vis = TRUE)
LAZYCLEARLIST(locked_weakrefs)
if(refresh_vis)
refresh_visuals()
/datum/component/lockon_aiming/proc/unlock(atom/A, refresh_vis = TRUE)
if(!A.weak_reference)
return
LAZYREMOVE(locked_weakrefs, A.weak_reference)
if(refresh_vis)
refresh_visuals()
/datum/component/lockon_aiming/proc/lock(atom/A, refresh_vis = TRUE)
LAZYOR(locked_weakrefs, WEAKREF(A))
if(refresh_vis)
refresh_visuals()
/datum/component/lockon_aiming/proc/add_immune_atom(atom/A)
var/datum/weakref/R = WEAKREF(A)
if(immune_weakrefs && (immune_weakrefs[R]))
return
LAZYSET(immune_weakrefs, R, TRUE)
/datum/component/lockon_aiming/proc/remove_immune_atom(atom/A)
if(!A.weak_reference || !immune_weakrefs) //if A doesn't have a weakref how did it get on the immunity list?
return
LAZYREMOVE(immune_weakrefs, A.weak_reference)
/datum/component/lockon_aiming/onMouseMove(object,location,control,params)
var/mob/M = parent
if(!istype(M) || !M.client)
return
var/datum/position/P = mouse_absolute_datum_map_position_from_client(M.client)
if(!P)
return
var/turf/T = P.return_turf()
LAZYINITLIST(last_location)
if(length(last_location) == 3 && last_location[1] == T.x && last_location[2] == T.y && last_location[3] == T.z)
return //Same turf, don't bother.
if(last_location)
last_location.Cut()
else
last_location = list()
last_location.len = 3
last_location[1] = T.x
last_location[2] = T.y
last_location[3] = T.z
autolock()
/datum/component/lockon_aiming/process()
if(update_disabled)
return
if(!last_location)
return
var/changed = FALSE
for(var/i in locked_weakrefs)
var/datum/weakref/R = i
if(istype(R))
var/atom/thing = R.resolve()
if(!istype(thing) || (get_dist(thing, locate(last_location[1], last_location[2], last_location[3])) > lock_cursor_range))
unlock(R)
changed = TRUE
else
unlock(R)
changed = TRUE
if(changed)
autolock()
/datum/component/lockon_aiming/proc/autolock()
var/mob/M = parent
if(!M.client)
return FALSE
var/datum/position/current = mouse_absolute_datum_map_position_from_client(M.client)
var/turf/target = current.return_turf()
var/list/atom/targets = get_nearest(target, target_typecache, lock_amount, lock_cursor_range)
if(targets == LOCKON_IGNORE_RESULT)
return
unlock_all(FALSE)
for(var/i in targets)
if(immune_weakrefs[WEAKREF(i)])
continue
lock(i, FALSE)
refresh_visuals()
on_lock.Invoke(locked_weakrefs)
/datum/component/lockon_aiming/proc/can_target(atom/A)
var/mob/M = A
return is_type_in_typecache(A, target_typecache) && !(ismob(A) && mob_stat_check && M.stat != CONSCIOUS) && !immune_weakrefs[WEAKREF(A)]
/datum/component/lockon_aiming/proc/get_nearest(turf/T, list/typecache, amount, range)
current_ranging_id++
var/this_id = current_ranging_id
var/list/L = list()
var/turf/center = get_turf(T)
if(amount < 1 || range < 0 || !istype(center) || !islist(typecache))
return
if(range == 0)
return typecache_filter_list(T.contents + T, typecache)
var/x = 0
var/y = 0
var/cd = 0
while(cd <= range)
x = center.x - cd + 1
y = center.y + cd
LOCKON_RANGING_BREAK_CHECK
for(x in x to center.x + cd)
T = locate(x, y, center.z)
if(T)
L |= special_list_filter(T.contents, can_target_callback)
if(L.len >= amount)
L.Cut(amount+1)
return L
LOCKON_RANGING_BREAK_CHECK
y = center.y + cd - 1
x = center.x + cd
for(y in center.y - cd to y)
T = locate(x, y, center.z)
if(T)
L |= special_list_filter(T.contents, can_target_callback)
if(L.len >= amount)
L.Cut(amount+1)
return L
LOCKON_RANGING_BREAK_CHECK
y = center.y - cd
x = center.x + cd - 1
for(x in center.x - cd to x)
T = locate(x, y, center.z)
if(T)
L |= special_list_filter(T.contents, can_target_callback)
if(L.len >= amount)
L.Cut(amount+1)
return L
LOCKON_RANGING_BREAK_CHECK
y = center.y - cd + 1
x = center.x - cd
for(y in y to center.y + cd)
T = locate(x, y, center.z)
if(T)
L |= special_list_filter(T.contents, can_target_callback)
if(L.len >= amount)
L.Cut(amount+1)
return L
LOCKON_RANGING_BREAK_CHECK
cd++
CHECK_TICK
+68 -68
View File
@@ -1,68 +1,68 @@
//Thing meant for allowing datums and objects to access a NTnet network datum.
/datum/proc/ntnet_receive(datum/netdata/data)
return
/datum/proc/ntnet_receive_broadcast(datum/netdata/data)
return
/datum/proc/ntnet_send(datum/netdata/data, netid)
var/datum/component/ntnet_interface/NIC = GetComponent(/datum/component/ntnet_interface)
if(!NIC)
return FALSE
return NIC.__network_send(data, netid)
/datum/component/ntnet_interface
var/hardware_id //text. this is the true ID. do not change this. stuff like ID forgery can be done manually.
var/network_name = "" //text
var/list/networks_connected_by_id = list() //id = datum/ntnet
var/differentiate_broadcast = TRUE //If false, broadcasts go to ntnet_receive. NOT RECOMMENDED.
/datum/component/ntnet_interface/Initialize(force_name = "NTNet Device", autoconnect_station_network = TRUE) //Don't force ID unless you know what you're doing!
hardware_id = "[SSnetworks.get_next_HID()]"
network_name = force_name
if(!SSnetworks.register_interface(src))
. = COMPONENT_INCOMPATIBLE
CRASH("Unable to register NTNet interface. Interface deleted.")
if(autoconnect_station_network)
register_connection(SSnetworks.station_network)
/datum/component/ntnet_interface/Destroy()
unregister_all_connections()
SSnetworks.unregister_interface(src)
return ..()
/datum/component/ntnet_interface/proc/__network_receive(datum/netdata/data) //Do not directly proccall!
SEND_SIGNAL(parent, COMSIG_COMPONENT_NTNET_RECEIVE, data)
if(differentiate_broadcast && data.broadcast)
parent.ntnet_receive_broadcast(data)
else
parent.ntnet_receive(data)
/datum/component/ntnet_interface/proc/__network_send(datum/netdata/data, netid) //Do not directly proccall!
// Process data before sending it
data.pre_send(src)
if(netid)
if(networks_connected_by_id[netid])
var/datum/ntnet/net = networks_connected_by_id[netid]
return net.process_data_transmit(src, data)
return FALSE
for(var/i in networks_connected_by_id)
var/datum/ntnet/net = networks_connected_by_id[i]
net.process_data_transmit(src, data)
return TRUE
/datum/component/ntnet_interface/proc/register_connection(datum/ntnet/net)
if(net.interface_connect(src))
networks_connected_by_id[net.network_id] = net
return TRUE
/datum/component/ntnet_interface/proc/unregister_all_connections()
for(var/i in networks_connected_by_id)
unregister_connection(networks_connected_by_id[i])
return TRUE
/datum/component/ntnet_interface/proc/unregister_connection(datum/ntnet/net)
net.interface_disconnect(src)
networks_connected_by_id -= net.network_id
return TRUE
//Thing meant for allowing datums and objects to access a NTnet network datum.
/datum/proc/ntnet_receive(datum/netdata/data)
return
/datum/proc/ntnet_receive_broadcast(datum/netdata/data)
return
/datum/proc/ntnet_send(datum/netdata/data, netid)
var/datum/component/ntnet_interface/NIC = GetComponent(/datum/component/ntnet_interface)
if(!NIC)
return FALSE
return NIC.__network_send(data, netid)
/datum/component/ntnet_interface
var/hardware_id //text. this is the true ID. do not change this. stuff like ID forgery can be done manually.
var/network_name = "" //text
var/list/networks_connected_by_id = list() //id = datum/ntnet
var/differentiate_broadcast = TRUE //If false, broadcasts go to ntnet_receive. NOT RECOMMENDED.
/datum/component/ntnet_interface/Initialize(force_name = "NTNet Device", autoconnect_station_network = TRUE) //Don't force ID unless you know what you're doing!
hardware_id = "[SSnetworks.get_next_HID()]"
network_name = force_name
if(!SSnetworks.register_interface(src))
. = COMPONENT_INCOMPATIBLE
CRASH("Unable to register NTNet interface. Interface deleted.")
if(autoconnect_station_network)
register_connection(SSnetworks.station_network)
/datum/component/ntnet_interface/Destroy()
unregister_all_connections()
SSnetworks.unregister_interface(src)
return ..()
/datum/component/ntnet_interface/proc/__network_receive(datum/netdata/data) //Do not directly proccall!
SEND_SIGNAL(parent, COMSIG_COMPONENT_NTNET_RECEIVE, data)
if(differentiate_broadcast && data.broadcast)
parent.ntnet_receive_broadcast(data)
else
parent.ntnet_receive(data)
/datum/component/ntnet_interface/proc/__network_send(datum/netdata/data, netid) //Do not directly proccall!
// Process data before sending it
data.pre_send(src)
if(netid)
if(networks_connected_by_id[netid])
var/datum/ntnet/net = networks_connected_by_id[netid]
return net.process_data_transmit(src, data)
return FALSE
for(var/i in networks_connected_by_id)
var/datum/ntnet/net = networks_connected_by_id[i]
net.process_data_transmit(src, data)
return TRUE
/datum/component/ntnet_interface/proc/register_connection(datum/ntnet/net)
if(net.interface_connect(src))
networks_connected_by_id[net.network_id] = net
return TRUE
/datum/component/ntnet_interface/proc/unregister_all_connections()
for(var/i in networks_connected_by_id)
unregister_connection(networks_connected_by_id[i])
return TRUE
/datum/component/ntnet_interface/proc/unregister_connection(datum/ntnet/net)
net.interface_disconnect(src)
networks_connected_by_id -= net.network_id
return TRUE
+359 -359
View File
@@ -1,359 +1,359 @@
/datum/component/riding
var/last_vehicle_move = 0 //used for move delays
var/last_move_diagonal = FALSE
var/vehicle_move_delay = 2 //tick delay between movements, lower = faster, higher = slower
var/keytype
var/slowed = FALSE
var/slowvalue = 1
var/list/riding_offsets = list() //position_of_user = list(dir = list(px, py)), or RIDING_OFFSET_ALL for a generic one.
var/list/directional_vehicle_layers = list() //["[DIRECTION]"] = layer. Don't set it for a direction for default, set a direction to null for no change.
var/list/directional_vehicle_offsets = list() //same as above but instead of layer you have a list(px, py)
var/list/allowed_turf_typecache
var/list/forbid_turf_typecache //allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
var/allow_one_away_from_valid_turf = TRUE //allow moving one tile away from a valid turf but not more.
var/override_allow_spacemove = FALSE
var/drive_verb = "drive"
var/ride_check_rider_incapacitated = FALSE
var/ride_check_rider_restrained = FALSE
var/ride_check_ridden_incapacitated = FALSE
var/list/offhands = list() // keyed list containing all the current riding offsets associated by mob
/datum/component/riding/Initialize()
if(!ismovableatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_MOVABLE_BUCKLE, .proc/vehicle_mob_buckle)
RegisterSignal(parent, COMSIG_MOVABLE_UNBUCKLE, .proc/vehicle_mob_unbuckle)
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/vehicle_moved)
/datum/component/riding/proc/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
restore_position(M)
unequip_buckle_inhands(M)
/datum/component/riding/proc/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
handle_vehicle_offsets()
/datum/component/riding/proc/handle_vehicle_layer()
var/atom/movable/AM = parent
var/static/list/defaults = list(TEXT_NORTH = OBJ_LAYER, TEXT_SOUTH = ABOVE_MOB_LAYER, TEXT_EAST = ABOVE_MOB_LAYER, TEXT_WEST = ABOVE_MOB_LAYER)
. = defaults["[AM.dir]"]
if(directional_vehicle_layers["[AM.dir]"])
. = directional_vehicle_layers["[AM.dir]"]
if(isnull(.)) //you can set it to null to not change it.
. = AM.layer
AM.layer = .
/datum/component/riding/proc/set_vehicle_dir_layer(dir, layer)
directional_vehicle_layers["[dir]"] = layer
/datum/component/riding/proc/vehicle_moved(datum/source)
var/atom/movable/AM = parent
for(var/i in AM.buckled_mobs)
ride_check(i)
handle_vehicle_offsets()
handle_vehicle_layer()
/datum/component/riding/proc/ride_check(mob/living/M)
var/atom/movable/AM = parent
var/mob/AMM = AM
if((ride_check_rider_restrained && M.restrained(TRUE)) || (ride_check_rider_incapacitated && M.incapacitated(FALSE, TRUE)) || (ride_check_ridden_incapacitated && istype(AMM) && AMM.incapacitated(FALSE, TRUE)))
AM.visible_message("<span class='warning'>[M] falls off of [AM]!</span>")
AM.unbuckle_mob(M)
return TRUE
/datum/component/riding/proc/force_dismount(mob/living/M)
var/atom/movable/AM = parent
AM.unbuckle_mob(M)
/datum/component/riding/proc/handle_vehicle_offsets()
var/atom/movable/AM = parent
var/AM_dir = "[AM.dir]"
var/passindex = 0
if(AM.has_buckled_mobs())
for(var/m in AM.buckled_mobs)
passindex++
var/mob/living/buckled_mob = m
var/list/offsets = get_offsets(passindex)
var/rider_dir = get_rider_dir(passindex)
buckled_mob.setDir(rider_dir)
dir_loop:
for(var/offsetdir in offsets)
if(offsetdir == AM_dir)
var/list/diroffsets = offsets[offsetdir]
buckled_mob.pixel_x = diroffsets[1]
if(diroffsets.len >= 2)
buckled_mob.pixel_y = diroffsets[2]
if(diroffsets.len == 3)
buckled_mob.layer = diroffsets[3]
break dir_loop
var/list/static/default_vehicle_pixel_offsets = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
var/px = default_vehicle_pixel_offsets[AM_dir]
var/py = default_vehicle_pixel_offsets[AM_dir]
if(directional_vehicle_offsets[AM_dir])
if(isnull(directional_vehicle_offsets[AM_dir]))
px = AM.pixel_x
py = AM.pixel_y
else
px = directional_vehicle_offsets[AM_dir][1]
py = directional_vehicle_offsets[AM_dir][2]
AM.pixel_x = px
AM.pixel_y = py
/datum/component/riding/proc/set_vehicle_dir_offsets(dir, x, y)
directional_vehicle_offsets["[dir]"] = list(x, y)
//Override this to set your vehicle's various pixel offsets
/datum/component/riding/proc/get_offsets(pass_index) // list(dir = x, y, layer)
. = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
if(riding_offsets["[pass_index]"])
. = riding_offsets["[pass_index]"]
else if(riding_offsets["[RIDING_OFFSET_ALL]"])
. = riding_offsets["[RIDING_OFFSET_ALL]"]
/datum/component/riding/proc/set_riding_offsets(index, list/offsets)
if(!islist(offsets))
return FALSE
riding_offsets["[index]"] = offsets
//Override this to set the passengers/riders dir based on which passenger they are.
//ie: rider facing the vehicle's dir, but passenger 2 facing backwards, etc.
/datum/component/riding/proc/get_rider_dir(pass_index)
var/atom/movable/AM = parent
return AM.dir
//KEYS
/datum/component/riding/proc/keycheck(mob/user)
return !keytype || user.is_holding_item_of_type(keytype)
//BUCKLE HOOKS
/datum/component/riding/proc/restore_position(mob/living/buckled_mob)
if(buckled_mob)
buckled_mob.pixel_x = 0
buckled_mob.pixel_y = 0
if(buckled_mob.client)
buckled_mob.client.change_view(CONFIG_GET(string/default_view))
//MOVEMENT
/datum/component/riding/proc/turf_check(turf/next, turf/current)
if(allowed_turf_typecache && !allowed_turf_typecache[next.type])
return (allow_one_away_from_valid_turf && allowed_turf_typecache[current.type])
else if(forbid_turf_typecache && forbid_turf_typecache[next.type])
return (allow_one_away_from_valid_turf && !forbid_turf_typecache[current.type])
return TRUE
/datum/component/riding/proc/handle_ride(mob/user, direction)
var/atom/movable/AM = parent
if(user.incapacitated())
Unbuckle(user)
return
if(world.time < last_vehicle_move + ((last_move_diagonal? 2 : 1) * vehicle_move_delay))
return
last_vehicle_move = world.time
if(keycheck(user))
var/turf/next = get_step(AM, direction)
var/turf/current = get_turf(AM)
if(!istype(next) || !istype(current))
return //not happening.
if(!turf_check(next, current))
to_chat(user, "Your \the [AM] can not go onto [next]!")
return
if(!Process_Spacemove(direction) || !isturf(AM.loc))
return
step(AM, direction)
if((direction & (direction - 1)) && (AM.loc == next)) //moved diagonally
last_move_diagonal = TRUE
else
last_move_diagonal = FALSE
handle_vehicle_layer()
handle_vehicle_offsets()
else
to_chat(user, "<span class='notice'>You'll need the keys in one of your hands to [drive_verb] [AM].</span>")
/datum/component/riding/proc/Unbuckle(atom/movable/M)
addtimer(CALLBACK(parent, /atom/movable/.proc/unbuckle_mob, M), 0, TIMER_UNIQUE)
/datum/component/riding/proc/Process_Spacemove(direction)
var/atom/movable/AM = parent
return override_allow_spacemove || AM.has_gravity()
/datum/component/riding/proc/account_limbs(mob/living/M)
if(M.get_num_legs() < 2 && !slowed)
vehicle_move_delay = vehicle_move_delay + slowvalue
slowed = TRUE
else if(slowed)
vehicle_move_delay = vehicle_move_delay - slowvalue
slowed = FALSE
///////Yes, I said humans. No, this won't end well...//////////
/datum/component/riding/human
/datum/component/riding/human/Initialize()
. = ..()
RegisterSignal(parent, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
/datum/component/riding/human/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
var/mob/living/carbon/human/H = parent
H.remove_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING)
. = ..()
/datum/component/riding/human/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
. = ..()
var/mob/living/carbon/human/H = parent
H.add_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING, multiplicative_slowdown = HUMAN_CARRY_SLOWDOWN)
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target)
var/mob/living/carbon/human/H = parent
if(H.a_intent == INTENT_DISARM && (target in H.buckled_mobs))
force_dismount(target)
/datum/component/riding/human/handle_vehicle_layer()
var/atom/movable/AM = parent
if(AM.buckled_mobs && AM.buckled_mobs.len)
for(var/mob/M in AM.buckled_mobs) //ensure proper layering of piggyback and carry, sometimes weird offsets get applied
M.layer = MOB_LAYER
if(!AM.buckle_lying)
if(AM.dir == SOUTH)
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = OBJ_LAYER
else
if(AM.dir == NORTH)
AM.layer = OBJ_LAYER
else
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = MOB_LAYER
/datum/component/riding/human/get_offsets(pass_index)
var/mob/living/carbon/human/H = parent
if(H.buckle_lying)
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(0, 6), TEXT_WEST = list(0, 6))
else
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4))
/datum/component/riding/human/force_dismount(mob/living/user)
var/atom/movable/AM = parent
AM.unbuckle_mob(user)
user.Knockdown(60)
user.visible_message("<span class='warning'>[AM] pushes [user] off of [AM.p_them()]!</span>")
/datum/component/riding/cyborg
/datum/component/riding/cyborg/ride_check(mob/user)
var/atom/movable/AM = parent
if(user.incapacitated())
var/kick = TRUE
if(iscyborg(AM))
var/mob/living/silicon/robot/R = AM
if(R.module && R.module.ride_allow_incapacitated)
kick = FALSE
if(kick)
to_chat(user, "<span class='userdanger'>You fall off of [AM]!</span>")
Unbuckle(user)
return
if(iscarbon(user))
var/mob/living/carbon/carbonuser = user
if(!carbonuser.get_num_arms())
Unbuckle(user)
to_chat(user, "<span class='userdanger'>You can't grab onto [AM] with no hands!</span>")
return
/datum/component/riding/cyborg/handle_vehicle_layer()
var/atom/movable/AM = parent
if(AM.buckled_mobs && AM.buckled_mobs.len)
if(AM.dir == SOUTH)
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = OBJ_LAYER
else
AM.layer = MOB_LAYER
/datum/component/riding/cyborg/get_offsets(pass_index) // list(dir = x, y, layer)
return list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-6, 3), TEXT_WEST = list( 6, 3))
/datum/component/riding/cyborg/handle_vehicle_offsets()
var/atom/movable/AM = parent
if(AM.has_buckled_mobs())
for(var/mob/living/M in AM.buckled_mobs)
M.setDir(AM.dir)
if(iscyborg(AM))
var/mob/living/silicon/robot/R = AM
if(istype(R.module))
M.pixel_x = R.module.ride_offset_x[dir2text(AM.dir)]
M.pixel_y = R.module.ride_offset_y[dir2text(AM.dir)]
else
..()
/datum/component/riding/cyborg/force_dismount(mob/living/M)
var/atom/movable/AM = parent
AM.unbuckle_mob(M)
var/turf/target = get_edge_target_turf(AM, AM.dir)
var/turf/targetm = get_step(get_turf(AM), AM.dir)
M.Move(targetm)
M.visible_message("<span class='warning'>[M] is thrown clear of [AM]!</span>")
M.throw_at(target, 14, 5, AM)
M.Knockdown(60)
/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1, mob/living/riding_target_override)
var/list/equipped
var/mob/living/L = riding_target_override ? riding_target_override : user
for(var/amount_needed = amount_required, amount_needed > 0, amount_needed--)
var/obj/item/riding_offhand/inhand = new
inhand.rider = L
inhand.parent = parent
if(!user.put_in_hands(inhand, TRUE))
qdel(inhand) // it isn't going to be added to offhands anyway
break
LAZYADD(equipped, inhand)
var/amount_equipped = LAZYLEN(equipped)
if(amount_equipped)
LAZYADD(offhands[L], equipped)
if(amount_equipped >= amount_required)
return TRUE
unequip_buckle_inhands(L)
return FALSE
/datum/component/riding/proc/unequip_buckle_inhands(mob/living/carbon/user)
for(var/a in offhands[user])
LAZYREMOVE(offhands[user], a)
if(a) //edge cases null entries
var/obj/item/riding_offhand/O = a
if(O.parent != parent)
CRASH("RIDING OFFHAND ON WRONG MOB")
else if(!O.selfdeleting)
qdel(O)
return TRUE
/obj/item/riding_offhand
name = "offhand"
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "offhand"
w_class = WEIGHT_CLASS_HUGE
item_flags = ABSTRACT | DROPDEL | NOBLUDGEON
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/mob/living/carbon/rider
var/mob/living/parent
var/selfdeleting = FALSE
/obj/item/riding_offhand/dropped()
selfdeleting = TRUE
. = ..()
/obj/item/riding_offhand/equipped()
if(loc != rider && loc != parent)
selfdeleting = TRUE
qdel(src)
. = ..()
/obj/item/riding_offhand/Destroy()
var/atom/movable/AM = parent
if(selfdeleting)
if(rider in AM.buckled_mobs)
AM.unbuckle_mob(rider)
. = ..()
/datum/component/riding
var/last_vehicle_move = 0 //used for move delays
var/last_move_diagonal = FALSE
var/vehicle_move_delay = 2 //tick delay between movements, lower = faster, higher = slower
var/keytype
var/slowed = FALSE
var/slowvalue = 1
var/list/riding_offsets = list() //position_of_user = list(dir = list(px, py)), or RIDING_OFFSET_ALL for a generic one.
var/list/directional_vehicle_layers = list() //["[DIRECTION]"] = layer. Don't set it for a direction for default, set a direction to null for no change.
var/list/directional_vehicle_offsets = list() //same as above but instead of layer you have a list(px, py)
var/list/allowed_turf_typecache
var/list/forbid_turf_typecache //allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
var/allow_one_away_from_valid_turf = TRUE //allow moving one tile away from a valid turf but not more.
var/override_allow_spacemove = FALSE
var/drive_verb = "drive"
var/ride_check_rider_incapacitated = FALSE
var/ride_check_rider_restrained = FALSE
var/ride_check_ridden_incapacitated = FALSE
var/list/offhands = list() // keyed list containing all the current riding offsets associated by mob
/datum/component/riding/Initialize()
if(!ismovableatom(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_MOVABLE_BUCKLE, .proc/vehicle_mob_buckle)
RegisterSignal(parent, COMSIG_MOVABLE_UNBUCKLE, .proc/vehicle_mob_unbuckle)
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/vehicle_moved)
/datum/component/riding/proc/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
restore_position(M)
unequip_buckle_inhands(M)
/datum/component/riding/proc/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
handle_vehicle_offsets()
/datum/component/riding/proc/handle_vehicle_layer()
var/atom/movable/AM = parent
var/static/list/defaults = list(TEXT_NORTH = OBJ_LAYER, TEXT_SOUTH = ABOVE_MOB_LAYER, TEXT_EAST = ABOVE_MOB_LAYER, TEXT_WEST = ABOVE_MOB_LAYER)
. = defaults["[AM.dir]"]
if(directional_vehicle_layers["[AM.dir]"])
. = directional_vehicle_layers["[AM.dir]"]
if(isnull(.)) //you can set it to null to not change it.
. = AM.layer
AM.layer = .
/datum/component/riding/proc/set_vehicle_dir_layer(dir, layer)
directional_vehicle_layers["[dir]"] = layer
/datum/component/riding/proc/vehicle_moved(datum/source)
var/atom/movable/AM = parent
for(var/i in AM.buckled_mobs)
ride_check(i)
handle_vehicle_offsets()
handle_vehicle_layer()
/datum/component/riding/proc/ride_check(mob/living/M)
var/atom/movable/AM = parent
var/mob/AMM = AM
if((ride_check_rider_restrained && M.restrained(TRUE)) || (ride_check_rider_incapacitated && M.incapacitated(FALSE, TRUE)) || (ride_check_ridden_incapacitated && istype(AMM) && AMM.incapacitated(FALSE, TRUE)))
AM.visible_message("<span class='warning'>[M] falls off of [AM]!</span>")
AM.unbuckle_mob(M)
return TRUE
/datum/component/riding/proc/force_dismount(mob/living/M)
var/atom/movable/AM = parent
AM.unbuckle_mob(M)
/datum/component/riding/proc/handle_vehicle_offsets()
var/atom/movable/AM = parent
var/AM_dir = "[AM.dir]"
var/passindex = 0
if(AM.has_buckled_mobs())
for(var/m in AM.buckled_mobs)
passindex++
var/mob/living/buckled_mob = m
var/list/offsets = get_offsets(passindex)
var/rider_dir = get_rider_dir(passindex)
buckled_mob.setDir(rider_dir)
dir_loop:
for(var/offsetdir in offsets)
if(offsetdir == AM_dir)
var/list/diroffsets = offsets[offsetdir]
buckled_mob.pixel_x = diroffsets[1]
if(diroffsets.len >= 2)
buckled_mob.pixel_y = diroffsets[2]
if(diroffsets.len == 3)
buckled_mob.layer = diroffsets[3]
break dir_loop
var/list/static/default_vehicle_pixel_offsets = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
var/px = default_vehicle_pixel_offsets[AM_dir]
var/py = default_vehicle_pixel_offsets[AM_dir]
if(directional_vehicle_offsets[AM_dir])
if(isnull(directional_vehicle_offsets[AM_dir]))
px = AM.pixel_x
py = AM.pixel_y
else
px = directional_vehicle_offsets[AM_dir][1]
py = directional_vehicle_offsets[AM_dir][2]
AM.pixel_x = px
AM.pixel_y = py
/datum/component/riding/proc/set_vehicle_dir_offsets(dir, x, y)
directional_vehicle_offsets["[dir]"] = list(x, y)
//Override this to set your vehicle's various pixel offsets
/datum/component/riding/proc/get_offsets(pass_index) // list(dir = x, y, layer)
. = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
if(riding_offsets["[pass_index]"])
. = riding_offsets["[pass_index]"]
else if(riding_offsets["[RIDING_OFFSET_ALL]"])
. = riding_offsets["[RIDING_OFFSET_ALL]"]
/datum/component/riding/proc/set_riding_offsets(index, list/offsets)
if(!islist(offsets))
return FALSE
riding_offsets["[index]"] = offsets
//Override this to set the passengers/riders dir based on which passenger they are.
//ie: rider facing the vehicle's dir, but passenger 2 facing backwards, etc.
/datum/component/riding/proc/get_rider_dir(pass_index)
var/atom/movable/AM = parent
return AM.dir
//KEYS
/datum/component/riding/proc/keycheck(mob/user)
return !keytype || user.is_holding_item_of_type(keytype)
//BUCKLE HOOKS
/datum/component/riding/proc/restore_position(mob/living/buckled_mob)
if(buckled_mob)
buckled_mob.pixel_x = 0
buckled_mob.pixel_y = 0
if(buckled_mob.client)
buckled_mob.client.change_view(CONFIG_GET(string/default_view))
//MOVEMENT
/datum/component/riding/proc/turf_check(turf/next, turf/current)
if(allowed_turf_typecache && !allowed_turf_typecache[next.type])
return (allow_one_away_from_valid_turf && allowed_turf_typecache[current.type])
else if(forbid_turf_typecache && forbid_turf_typecache[next.type])
return (allow_one_away_from_valid_turf && !forbid_turf_typecache[current.type])
return TRUE
/datum/component/riding/proc/handle_ride(mob/user, direction)
var/atom/movable/AM = parent
if(user.incapacitated())
Unbuckle(user)
return
if(world.time < last_vehicle_move + ((last_move_diagonal? 2 : 1) * vehicle_move_delay))
return
last_vehicle_move = world.time
if(keycheck(user))
var/turf/next = get_step(AM, direction)
var/turf/current = get_turf(AM)
if(!istype(next) || !istype(current))
return //not happening.
if(!turf_check(next, current))
to_chat(user, "Your \the [AM] can not go onto [next]!")
return
if(!Process_Spacemove(direction) || !isturf(AM.loc))
return
step(AM, direction)
if((direction & (direction - 1)) && (AM.loc == next)) //moved diagonally
last_move_diagonal = TRUE
else
last_move_diagonal = FALSE
handle_vehicle_layer()
handle_vehicle_offsets()
else
to_chat(user, "<span class='notice'>You'll need the keys in one of your hands to [drive_verb] [AM].</span>")
/datum/component/riding/proc/Unbuckle(atom/movable/M)
addtimer(CALLBACK(parent, /atom/movable/.proc/unbuckle_mob, M), 0, TIMER_UNIQUE)
/datum/component/riding/proc/Process_Spacemove(direction)
var/atom/movable/AM = parent
return override_allow_spacemove || AM.has_gravity()
/datum/component/riding/proc/account_limbs(mob/living/M)
if(M.get_num_legs() < 2 && !slowed)
vehicle_move_delay = vehicle_move_delay + slowvalue
slowed = TRUE
else if(slowed)
vehicle_move_delay = vehicle_move_delay - slowvalue
slowed = FALSE
///////Yes, I said humans. No, this won't end well...//////////
/datum/component/riding/human
/datum/component/riding/human/Initialize()
. = ..()
RegisterSignal(parent, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
/datum/component/riding/human/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
var/mob/living/carbon/human/H = parent
H.remove_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING)
. = ..()
/datum/component/riding/human/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
. = ..()
var/mob/living/carbon/human/H = parent
H.add_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING, multiplicative_slowdown = HUMAN_CARRY_SLOWDOWN)
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target)
var/mob/living/carbon/human/H = parent
if(H.a_intent == INTENT_DISARM && (target in H.buckled_mobs))
force_dismount(target)
/datum/component/riding/human/handle_vehicle_layer()
var/atom/movable/AM = parent
if(AM.buckled_mobs && AM.buckled_mobs.len)
for(var/mob/M in AM.buckled_mobs) //ensure proper layering of piggyback and carry, sometimes weird offsets get applied
M.layer = MOB_LAYER
if(!AM.buckle_lying)
if(AM.dir == SOUTH)
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = OBJ_LAYER
else
if(AM.dir == NORTH)
AM.layer = OBJ_LAYER
else
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = MOB_LAYER
/datum/component/riding/human/get_offsets(pass_index)
var/mob/living/carbon/human/H = parent
if(H.buckle_lying)
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(0, 6), TEXT_WEST = list(0, 6))
else
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4))
/datum/component/riding/human/force_dismount(mob/living/user)
var/atom/movable/AM = parent
AM.unbuckle_mob(user)
user.Knockdown(60)
user.visible_message("<span class='warning'>[AM] pushes [user] off of [AM.p_them()]!</span>")
/datum/component/riding/cyborg
/datum/component/riding/cyborg/ride_check(mob/user)
var/atom/movable/AM = parent
if(user.incapacitated())
var/kick = TRUE
if(iscyborg(AM))
var/mob/living/silicon/robot/R = AM
if(R.module && R.module.ride_allow_incapacitated)
kick = FALSE
if(kick)
to_chat(user, "<span class='userdanger'>You fall off of [AM]!</span>")
Unbuckle(user)
return
if(iscarbon(user))
var/mob/living/carbon/carbonuser = user
if(!carbonuser.get_num_arms())
Unbuckle(user)
to_chat(user, "<span class='userdanger'>You can't grab onto [AM] with no hands!</span>")
return
/datum/component/riding/cyborg/handle_vehicle_layer()
var/atom/movable/AM = parent
if(AM.buckled_mobs && AM.buckled_mobs.len)
if(AM.dir == SOUTH)
AM.layer = ABOVE_MOB_LAYER
else
AM.layer = OBJ_LAYER
else
AM.layer = MOB_LAYER
/datum/component/riding/cyborg/get_offsets(pass_index) // list(dir = x, y, layer)
return list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-6, 3), TEXT_WEST = list( 6, 3))
/datum/component/riding/cyborg/handle_vehicle_offsets()
var/atom/movable/AM = parent
if(AM.has_buckled_mobs())
for(var/mob/living/M in AM.buckled_mobs)
M.setDir(AM.dir)
if(iscyborg(AM))
var/mob/living/silicon/robot/R = AM
if(istype(R.module))
M.pixel_x = R.module.ride_offset_x[dir2text(AM.dir)]
M.pixel_y = R.module.ride_offset_y[dir2text(AM.dir)]
else
..()
/datum/component/riding/cyborg/force_dismount(mob/living/M)
var/atom/movable/AM = parent
AM.unbuckle_mob(M)
var/turf/target = get_edge_target_turf(AM, AM.dir)
var/turf/targetm = get_step(get_turf(AM), AM.dir)
M.Move(targetm)
M.visible_message("<span class='warning'>[M] is thrown clear of [AM]!</span>")
M.throw_at(target, 14, 5, AM)
M.Knockdown(60)
/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1, mob/living/riding_target_override)
var/list/equipped
var/mob/living/L = riding_target_override ? riding_target_override : user
for(var/amount_needed = amount_required, amount_needed > 0, amount_needed--)
var/obj/item/riding_offhand/inhand = new
inhand.rider = L
inhand.parent = parent
if(!user.put_in_hands(inhand, TRUE))
qdel(inhand) // it isn't going to be added to offhands anyway
break
LAZYADD(equipped, inhand)
var/amount_equipped = LAZYLEN(equipped)
if(amount_equipped)
LAZYADD(offhands[L], equipped)
if(amount_equipped >= amount_required)
return TRUE
unequip_buckle_inhands(L)
return FALSE
/datum/component/riding/proc/unequip_buckle_inhands(mob/living/carbon/user)
for(var/a in offhands[user])
LAZYREMOVE(offhands[user], a)
if(a) //edge cases null entries
var/obj/item/riding_offhand/O = a
if(O.parent != parent)
CRASH("RIDING OFFHAND ON WRONG MOB")
else if(!O.selfdeleting)
qdel(O)
return TRUE
/obj/item/riding_offhand
name = "offhand"
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "offhand"
w_class = WEIGHT_CLASS_HUGE
item_flags = ABSTRACT | DROPDEL | NOBLUDGEON
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/mob/living/carbon/rider
var/mob/living/parent
var/selfdeleting = FALSE
/obj/item/riding_offhand/dropped()
selfdeleting = TRUE
. = ..()
/obj/item/riding_offhand/equipped()
if(loc != rider && loc != parent)
selfdeleting = TRUE
qdel(src)
. = ..()
/obj/item/riding_offhand/Destroy()
var/atom/movable/AM = parent
if(selfdeleting)
if(rider in AM.buckled_mobs)
AM.unbuckle_mob(rider)
. = ..()
+15 -15
View File
@@ -1,15 +1,15 @@
/datum/component/slippery
var/intensity
var/lube_flags
var/datum/callback/callback
/datum/component/slippery/Initialize(_intensity, _lube_flags = NONE, datum/callback/_callback)
intensity = max(_intensity, 0)
lube_flags = _lube_flags
callback = _callback
RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED), .proc/Slip)
/datum/component/slippery/proc/Slip(datum/source, atom/movable/AM)
var/mob/victim = AM
if(istype(victim) && !victim.is_flying() && victim.slip(intensity, parent, lube_flags) && callback)
callback.Invoke(victim)
/datum/component/slippery
var/intensity
var/lube_flags
var/datum/callback/callback
/datum/component/slippery/Initialize(_intensity, _lube_flags = NONE, datum/callback/_callback)
intensity = max(_intensity, 0)
lube_flags = _lube_flags
callback = _callback
RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ATOM_ENTERED), .proc/Slip)
/datum/component/slippery/proc/Slip(datum/source, atom/movable/AM)
var/mob/victim = AM
if(istype(victim) && !victim.is_flying() && victim.slip(intensity, parent, lube_flags) && callback)
callback.Invoke(victim)
@@ -1,208 +1,208 @@
// External storage-related logic:
// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages
// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement
/datum/component/storage/concrete
can_transfer = TRUE
var/drop_all_on_deconstruct = TRUE
var/drop_all_on_destroy = FALSE
var/drop_all_on_break = FALSE
var/unlock_on_break = FALSE
var/transfer_contents_on_component_transfer = FALSE
var/list/datum/component/storage/slaves = list()
var/list/_contents_limbo // Where objects go to live mid transfer
var/list/_user_limbo // The last users before the component started moving
/datum/component/storage/concrete/Initialize()
. = ..()
RegisterSignal(parent, COMSIG_ATOM_CONTENTS_DEL, .proc/on_contents_del)
RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, .proc/on_deconstruct)
RegisterSignal(parent, COMSIG_OBJ_BREAK, .proc/on_break)
/datum/component/storage/concrete/Destroy()
var/atom/real_location = real_location()
for(var/atom/_A in real_location)
_A.mouse_opacity = initial(_A.mouse_opacity)
if(drop_all_on_destroy)
do_quick_empty()
for(var/i in slaves)
var/datum/component/storage/slave = i
slave.change_master(null)
QDEL_LIST(_contents_limbo)
_user_limbo = null
return ..()
/datum/component/storage/concrete/master()
return src
/datum/component/storage/concrete/real_location()
return parent
/datum/component/storage/concrete/PreTransfer()
if(is_using)
_user_limbo = is_using.Copy()
close_all()
if(transfer_contents_on_component_transfer)
_contents_limbo = list()
for(var/atom/movable/AM in parent)
_contents_limbo += AM
AM.moveToNullspace()
/datum/component/storage/concrete/PostTransfer()
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
if(transfer_contents_on_component_transfer)
for(var/i in _contents_limbo)
var/atom/movable/AM = i
AM.forceMove(parent)
_contents_limbo = null
if(_user_limbo)
for(var/i in _user_limbo)
show_to(i)
_user_limbo = null
/datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE)
. = TRUE
var/atom/real_location = real_location()
if(I.loc != real_location && real_location)
I.forceMove(real_location)
refresh_mob_views()
/datum/component/storage/concrete/refresh_mob_views()
. = ..()
for(var/i in slaves)
var/datum/component/storage/slave = i
slave.refresh_mob_views()
/datum/component/storage/concrete/emp_act(datum/source, severity)
if(emp_shielded)
return
var/atom/real_location = real_location()
for(var/i in real_location)
var/atom/A = i
A.emp_act(severity)
/datum/component/storage/concrete/proc/on_slave_link(datum/component/storage/S)
if(S == src)
return FALSE
slaves += S
return TRUE
/datum/component/storage/concrete/proc/on_slave_unlink(datum/component/storage/S)
slaves -= S
return FALSE
/datum/component/storage/concrete/proc/on_contents_del(datum/source, atom/A)
var/atom/real_location = parent
if(A in real_location)
usr = null
remove_from_storage(A, null)
/datum/component/storage/concrete/proc/on_deconstruct(datum/source, disassembled)
if(drop_all_on_deconstruct)
do_quick_empty()
/datum/component/storage/concrete/proc/on_break(datum/source, damage_flag)
if(drop_all_on_break)
do_quick_empty()
if(unlock_on_break)
set_locked(source, FALSE)
/datum/component/storage/concrete/can_see_contents()
. = ..()
for(var/i in slaves)
var/datum/component/storage/slave = i
. |= slave.can_see_contents()
//Resets screen loc and other vars of something being removed from storage.
/datum/component/storage/concrete/_removal_reset(atom/movable/thing)
thing.layer = initial(thing.layer)
thing.plane = initial(thing.plane)
thing.mouse_opacity = initial(thing.mouse_opacity)
if(thing.maptext)
thing.maptext = ""
/datum/component/storage/concrete/remove_from_storage(atom/movable/AM, atom/new_location)
//Cache this as it should be reusable down the bottom, will not apply if anyone adds a sleep to dropped
//or moving objects, things that should never happen
var/atom/parent = src.parent
var/list/seeing_mobs = can_see_contents()
for(var/mob/M in seeing_mobs)
M.client.screen -= AM
if(ismob(parent.loc) && isitem(AM))
var/obj/item/I = AM
var/mob/M = parent.loc
I.dropped(M)
if(new_location)
//Reset the items values
_removal_reset(AM)
AM.forceMove(new_location)
//We don't want to call this if the item is being destroyed
AM.on_exit_storage(src)
else
//Being destroyed, just move to nullspace now (so it's not in contents for the icon update)
AM.moveToNullspace()
refresh_mob_views()
if(isobj(parent))
var/obj/O = parent
O.update_icon()
return TRUE
/datum/component/storage/concrete/proc/slave_can_insert_object(datum/component/storage/slave, obj/item/I, stop_messages = FALSE, mob/M)
return TRUE
/datum/component/storage/concrete/proc/handle_item_insertion_from_slave(datum/component/storage/slave, obj/item/I, prevent_warning = FALSE, M)
. = handle_item_insertion(I, prevent_warning, M, slave)
if(. && !prevent_warning)
slave.mob_item_insertion_feedback(usr, M, I)
/datum/component/storage/concrete/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote) //Remote is null or the slave datum
var/datum/component/storage/concrete/master = master()
var/atom/parent = src.parent
var/moved = FALSE
if(!istype(I))
return FALSE
if(M)
if(!M.temporarilyRemoveItemFromInventory(I))
return FALSE
else
moved = TRUE //At this point if the proc fails we need to manually move the object back to the turf/mob/whatever.
if(I.pulledby)
I.pulledby.stop_pulling()
if(silent)
prevent_warning = TRUE
if(!_insert_physical_item(I))
if(moved)
if(M)
if(!M.put_in_active_hand(I))
I.forceMove(parent.drop_location())
else
I.forceMove(parent.drop_location())
return FALSE
I.on_enter_storage(master)
refresh_mob_views()
I.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt
if(M)
if(M.client && M.active_storage != src)
M.client.screen -= I
if(M.observers && M.observers.len)
for(var/i in M.observers)
var/mob/dead/observe = i
if(observe.client && observe.active_storage != src)
observe.client.screen -= I
if(!remote)
parent.add_fingerprint(M)
if(!prevent_warning)
mob_item_insertion_feedback(usr, M, I)
update_icon()
return TRUE
/datum/component/storage/concrete/update_icon()
if(isobj(parent))
var/obj/O = parent
O.update_icon()
for(var/i in slaves)
var/datum/component/storage/slave = i
slave.update_icon()
// External storage-related logic:
// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages
// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement
/datum/component/storage/concrete
can_transfer = TRUE
var/drop_all_on_deconstruct = TRUE
var/drop_all_on_destroy = FALSE
var/drop_all_on_break = FALSE
var/unlock_on_break = FALSE
var/transfer_contents_on_component_transfer = FALSE
var/list/datum/component/storage/slaves = list()
var/list/_contents_limbo // Where objects go to live mid transfer
var/list/_user_limbo // The last users before the component started moving
/datum/component/storage/concrete/Initialize()
. = ..()
RegisterSignal(parent, COMSIG_ATOM_CONTENTS_DEL, .proc/on_contents_del)
RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, .proc/on_deconstruct)
RegisterSignal(parent, COMSIG_OBJ_BREAK, .proc/on_break)
/datum/component/storage/concrete/Destroy()
var/atom/real_location = real_location()
for(var/atom/_A in real_location)
_A.mouse_opacity = initial(_A.mouse_opacity)
if(drop_all_on_destroy)
do_quick_empty()
for(var/i in slaves)
var/datum/component/storage/slave = i
slave.change_master(null)
QDEL_LIST(_contents_limbo)
_user_limbo = null
return ..()
/datum/component/storage/concrete/master()
return src
/datum/component/storage/concrete/real_location()
return parent
/datum/component/storage/concrete/PreTransfer()
if(is_using)
_user_limbo = is_using.Copy()
close_all()
if(transfer_contents_on_component_transfer)
_contents_limbo = list()
for(var/atom/movable/AM in parent)
_contents_limbo += AM
AM.moveToNullspace()
/datum/component/storage/concrete/PostTransfer()
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
if(transfer_contents_on_component_transfer)
for(var/i in _contents_limbo)
var/atom/movable/AM = i
AM.forceMove(parent)
_contents_limbo = null
if(_user_limbo)
for(var/i in _user_limbo)
show_to(i)
_user_limbo = null
/datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE)
. = TRUE
var/atom/real_location = real_location()
if(I.loc != real_location && real_location)
I.forceMove(real_location)
refresh_mob_views()
/datum/component/storage/concrete/refresh_mob_views()
. = ..()
for(var/i in slaves)
var/datum/component/storage/slave = i
slave.refresh_mob_views()
/datum/component/storage/concrete/emp_act(datum/source, severity)
if(emp_shielded)
return
var/atom/real_location = real_location()
for(var/i in real_location)
var/atom/A = i
A.emp_act(severity)
/datum/component/storage/concrete/proc/on_slave_link(datum/component/storage/S)
if(S == src)
return FALSE
slaves += S
return TRUE
/datum/component/storage/concrete/proc/on_slave_unlink(datum/component/storage/S)
slaves -= S
return FALSE
/datum/component/storage/concrete/proc/on_contents_del(datum/source, atom/A)
var/atom/real_location = parent
if(A in real_location)
usr = null
remove_from_storage(A, null)
/datum/component/storage/concrete/proc/on_deconstruct(datum/source, disassembled)
if(drop_all_on_deconstruct)
do_quick_empty()
/datum/component/storage/concrete/proc/on_break(datum/source, damage_flag)
if(drop_all_on_break)
do_quick_empty()
if(unlock_on_break)
set_locked(source, FALSE)
/datum/component/storage/concrete/can_see_contents()
. = ..()
for(var/i in slaves)
var/datum/component/storage/slave = i
. |= slave.can_see_contents()
//Resets screen loc and other vars of something being removed from storage.
/datum/component/storage/concrete/_removal_reset(atom/movable/thing)
thing.layer = initial(thing.layer)
thing.plane = initial(thing.plane)
thing.mouse_opacity = initial(thing.mouse_opacity)
if(thing.maptext)
thing.maptext = ""
/datum/component/storage/concrete/remove_from_storage(atom/movable/AM, atom/new_location)
//Cache this as it should be reusable down the bottom, will not apply if anyone adds a sleep to dropped
//or moving objects, things that should never happen
var/atom/parent = src.parent
var/list/seeing_mobs = can_see_contents()
for(var/mob/M in seeing_mobs)
M.client.screen -= AM
if(ismob(parent.loc) && isitem(AM))
var/obj/item/I = AM
var/mob/M = parent.loc
I.dropped(M)
if(new_location)
//Reset the items values
_removal_reset(AM)
AM.forceMove(new_location)
//We don't want to call this if the item is being destroyed
AM.on_exit_storage(src)
else
//Being destroyed, just move to nullspace now (so it's not in contents for the icon update)
AM.moveToNullspace()
refresh_mob_views()
if(isobj(parent))
var/obj/O = parent
O.update_icon()
return TRUE
/datum/component/storage/concrete/proc/slave_can_insert_object(datum/component/storage/slave, obj/item/I, stop_messages = FALSE, mob/M)
return TRUE
/datum/component/storage/concrete/proc/handle_item_insertion_from_slave(datum/component/storage/slave, obj/item/I, prevent_warning = FALSE, M)
. = handle_item_insertion(I, prevent_warning, M, slave)
if(. && !prevent_warning)
slave.mob_item_insertion_feedback(usr, M, I)
/datum/component/storage/concrete/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote) //Remote is null or the slave datum
var/datum/component/storage/concrete/master = master()
var/atom/parent = src.parent
var/moved = FALSE
if(!istype(I))
return FALSE
if(M)
if(!M.temporarilyRemoveItemFromInventory(I))
return FALSE
else
moved = TRUE //At this point if the proc fails we need to manually move the object back to the turf/mob/whatever.
if(I.pulledby)
I.pulledby.stop_pulling()
if(silent)
prevent_warning = TRUE
if(!_insert_physical_item(I))
if(moved)
if(M)
if(!M.put_in_active_hand(I))
I.forceMove(parent.drop_location())
else
I.forceMove(parent.drop_location())
return FALSE
I.on_enter_storage(master)
refresh_mob_views()
I.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt
if(M)
if(M.client && M.active_storage != src)
M.client.screen -= I
if(M.observers && M.observers.len)
for(var/i in M.observers)
var/mob/dead/observe = i
if(observe.client && observe.active_storage != src)
observe.client.screen -= I
if(!remote)
parent.add_fingerprint(M)
if(!prevent_warning)
mob_item_insertion_feedback(usr, M, I)
update_icon()
return TRUE
/datum/component/storage/concrete/update_icon()
if(isobj(parent))
var/obj/O = parent
O.update_icon()
for(var/i in slaves)
var/datum/component/storage/slave = i
slave.update_icon()
@@ -1,36 +1,36 @@
/datum/component/storage/concrete/bluespace/bag_of_holding/handle_item_insertion(obj/item/W, prevent_warning = FALSE, mob/living/user)
var/atom/A = parent
if(A == W) //don't put yourself into yourself.
return
var/list/obj/item/storage/backpack/holding/matching = typecache_filter_list(W.GetAllContents(), typecacheof(/obj/item/storage/backpack/holding))
matching -= A
if(istype(W, /obj/item/storage/backpack/holding) || matching.len)
var/safety = alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [A.name]?", "Abort", "Proceed")
if(safety != "Proceed" || QDELETED(A) || QDELETED(W) || QDELETED(user) || !user.canUseTopic(A, BE_CLOSE, iscarbon(user)))
return
var/turf/loccheck = get_turf(A)
if(is_reebe(loccheck.z))
user.visible_message("<span class='warning'>An unseen force knocks [user] to the ground!</span>", "<span class='big_brass'>\"I think not!\"</span>")
user.Knockdown(60)
return
if(istype(loccheck.loc, /area/fabric_of_reality))
to_chat(user, "<span class='danger'>You can't do that here!</span>")
to_chat(user, "<span class='danger'>The Bluespace interfaces of the two devices catastrophically malfunction!</span>")
qdel(W)
playsound(loccheck,'sound/effects/supermatter.ogg', 200, 1)
user.gib(TRUE, TRUE, TRUE)
for(var/turf/T in range(6,loccheck))
if(istype(T, /turf/open/space/transit))
continue
for(var/mob/living/M in T)
if(M.movement_type & FLYING)
M.visible_message("<span class='danger'>The bluespace collapse crushes the air towards it, pulling [M] towards the ground...</span>")
M.Knockdown(5, TRUE, TRUE) //Overrides stun absorbs.
T.TerraformTurf(/turf/open/chasm/magic, /turf/open/chasm/magic)
for (var/obj/structure/ladder/unbreakable/binary/ladder in GLOB.ladders)
ladder.ActivateAlmonds()
message_admins("[ADMIN_LOOKUPFLW(user)] detonated a bag of holding at [ADMIN_VERBOSEJMP(loccheck)].")
log_game("[key_name(user)] detonated a bag of holding at [loc_name(loccheck)].")
qdel(A)
return
. = ..()
/datum/component/storage/concrete/bluespace/bag_of_holding/handle_item_insertion(obj/item/W, prevent_warning = FALSE, mob/living/user)
var/atom/A = parent
if(A == W) //don't put yourself into yourself.
return
var/list/obj/item/storage/backpack/holding/matching = typecache_filter_list(W.GetAllContents(), typecacheof(/obj/item/storage/backpack/holding))
matching -= A
if(istype(W, /obj/item/storage/backpack/holding) || matching.len)
var/safety = alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [A.name]?", "Abort", "Proceed")
if(safety != "Proceed" || QDELETED(A) || QDELETED(W) || QDELETED(user) || !user.canUseTopic(A, BE_CLOSE, iscarbon(user)))
return
var/turf/loccheck = get_turf(A)
if(is_reebe(loccheck.z))
user.visible_message("<span class='warning'>An unseen force knocks [user] to the ground!</span>", "<span class='big_brass'>\"I think not!\"</span>")
user.Knockdown(60)
return
if(istype(loccheck.loc, /area/fabric_of_reality))
to_chat(user, "<span class='danger'>You can't do that here!</span>")
to_chat(user, "<span class='danger'>The Bluespace interfaces of the two devices catastrophically malfunction!</span>")
qdel(W)
playsound(loccheck,'sound/effects/supermatter.ogg', 200, 1)
user.gib(TRUE, TRUE, TRUE)
for(var/turf/T in range(6,loccheck))
if(istype(T, /turf/open/space/transit))
continue
for(var/mob/living/M in T)
if(M.movement_type & FLYING)
M.visible_message("<span class='danger'>The bluespace collapse crushes the air towards it, pulling [M] towards the ground...</span>")
M.Knockdown(5, TRUE, TRUE) //Overrides stun absorbs.
T.TerraformTurf(/turf/open/chasm/magic, /turf/open/chasm/magic)
for (var/obj/structure/ladder/unbreakable/binary/ladder in GLOB.ladders)
ladder.ActivateAlmonds()
message_admins("[ADMIN_LOOKUPFLW(user)] detonated a bag of holding at [ADMIN_VERBOSEJMP(loccheck)].")
log_game("[key_name(user)] detonated a bag of holding at [loc_name(loccheck)].")
qdel(A)
return
. = ..()
@@ -1,18 +1,18 @@
/datum/component/storage/concrete/implant
max_w_class = WEIGHT_CLASS_NORMAL
max_combined_w_class = 6
max_items = 2
drop_all_on_destroy = TRUE
drop_all_on_deconstruct = TRUE
silent = TRUE
allow_big_nesting = TRUE
/datum/component/storage/concrete/implant/Initialize()
. = ..()
cant_hold = typecacheof(list(/obj/item/disk/nuclear))
/datum/component/storage/concrete/implant/InheritComponent(datum/component/storage/concrete/implant/I, original)
if(!istype(I))
return ..()
max_combined_w_class += I.max_combined_w_class
max_items += I.max_items
/datum/component/storage/concrete/implant
max_w_class = WEIGHT_CLASS_NORMAL
max_combined_w_class = 6
max_items = 2
drop_all_on_destroy = TRUE
drop_all_on_deconstruct = TRUE
silent = TRUE
allow_big_nesting = TRUE
/datum/component/storage/concrete/implant/Initialize()
. = ..()
cant_hold = typecacheof(list(/obj/item/disk/nuclear))
/datum/component/storage/concrete/implant/InheritComponent(datum/component/storage/concrete/implant/I, original)
if(!istype(I))
return ..()
max_combined_w_class += I.max_combined_w_class
max_items += I.max_items
+36 -36
View File
@@ -1,36 +1,36 @@
/datum/component/storage/concrete/rped
collection_mode = COLLECT_EVERYTHING
allow_quick_gather = TRUE
allow_quick_empty = TRUE
click_gather = TRUE
max_w_class = WEIGHT_CLASS_NORMAL
max_combined_w_class = 100
max_items = 100
display_numerical_stacking = TRUE
/datum/component/storage/concrete/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
. = ..()
if(!I.get_part_rating())
if (!stop_messages)
to_chat(M, "<span class='warning'>[parent] only accepts machine parts!</span>")
return FALSE
/datum/component/storage/concrete/bluespace/rped
collection_mode = COLLECT_EVERYTHING
allow_quick_gather = TRUE
allow_quick_empty = TRUE
click_gather = TRUE
max_w_class = WEIGHT_CLASS_BULKY // can fit vending refills
max_combined_w_class = 800
max_items = 350
display_numerical_stacking = TRUE
/datum/component/storage/concrete/bluespace/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
. = ..()
if(!I.get_part_rating())
if (!stop_messages)
to_chat(M, "<span class='warning'>[parent] only accepts machine parts!</span>")
return FALSE
/datum/component/storage/concrete/cyborg/rped
max_items = 150
/datum/component/storage/concrete/rped
collection_mode = COLLECT_EVERYTHING
allow_quick_gather = TRUE
allow_quick_empty = TRUE
click_gather = TRUE
max_w_class = WEIGHT_CLASS_NORMAL
max_combined_w_class = 100
max_items = 100
display_numerical_stacking = TRUE
/datum/component/storage/concrete/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
. = ..()
if(!I.get_part_rating())
if (!stop_messages)
to_chat(M, "<span class='warning'>[parent] only accepts machine parts!</span>")
return FALSE
/datum/component/storage/concrete/bluespace/rped
collection_mode = COLLECT_EVERYTHING
allow_quick_gather = TRUE
allow_quick_empty = TRUE
click_gather = TRUE
max_w_class = WEIGHT_CLASS_BULKY // can fit vending refills
max_combined_w_class = 800
max_items = 350
display_numerical_stacking = TRUE
/datum/component/storage/concrete/bluespace/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
. = ..()
if(!I.get_part_rating())
if (!stop_messages)
to_chat(M, "<span class='warning'>[parent] only accepts machine parts!</span>")
return FALSE
/datum/component/storage/concrete/cyborg/rped
max_items = 150
File diff suppressed because it is too large Load Diff
+211 -211
View File
@@ -1,211 +1,211 @@
/datum/component/wet_floor
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
can_transfer = TRUE
var/highest_strength = TURF_DRY
var/lube_flags = NONE //why do we have this?
var/list/time_left_list //In deciseconds.
var/static/mutable_appearance/permafrost_overlay = mutable_appearance('icons/effects/water.dmi', "ice_floor")
var/static/mutable_appearance/ice_overlay = mutable_appearance('icons/turf/overlays.dmi', "snowfloor")
var/static/mutable_appearance/water_overlay = mutable_appearance('icons/effects/water.dmi', "wet_floor_static")
var/static/mutable_appearance/generic_turf_overlay = mutable_appearance('icons/effects/water.dmi', "wet_static")
var/current_overlay
var/permanent = FALSE
var/last_process = 0
/datum/component/wet_floor/InheritComponent(datum/newcomp, orig, argslist)
if(!newcomp) //We are getting passed the arguments of a would-be new component, but not a new component
add_wet(arglist(argslist))
else //We are being passed in a full blown component
var/datum/component/wet_floor/WF = newcomp //Lets make an assumption
if(WF.gc()) //See if it's even valid, still. Also does LAZYLEN and stuff for us.
CRASH("Wet floor component tried to inherit another, but the other was able to garbage collect while being inherited! What a waste of time!")
return
for(var/i in WF.time_left_list)
add_wet(text2num(i), WF.time_left_list[i])
/datum/component/wet_floor/Initialize(strength, duration_minimum, duration_add, duration_maximum, _permanent = FALSE)
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
add_wet(strength, duration_minimum, duration_add, duration_maximum)
permanent = _permanent
if(!permanent)
START_PROCESSING(SSwet_floors, src)
addtimer(CALLBACK(src, .proc/gc, TRUE), 1) //GC after initialization.
last_process = world.time
/datum/component/wet_floor/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_TURF_IS_WET, .proc/is_wet)
RegisterSignal(parent, COMSIG_TURF_MAKE_DRY, .proc/dry)
/datum/component/wet_floor/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_TURF_IS_WET, COMSIG_TURF_MAKE_DRY))
/datum/component/wet_floor/Destroy()
STOP_PROCESSING(SSwet_floors, src)
var/turf/T = parent
qdel(T.GetComponent(/datum/component/slippery))
if(istype(T)) //If this is false there is so many things wrong with it.
T.cut_overlay(current_overlay)
else
stack_trace("Warning: Wet floor component wasn't on a turf when being destroyed! This is really bad!")
return ..()
/datum/component/wet_floor/proc/update_overlay()
var/intended
if(!istype(parent, /turf/open/floor))
intended = generic_turf_overlay
else
switch(highest_strength)
if(TURF_WET_PERMAFROST)
intended = permafrost_overlay
if(TURF_WET_ICE)
intended = ice_overlay
else
intended = water_overlay
if(current_overlay != intended)
var/turf/T = parent
T.cut_overlay(current_overlay)
T.add_overlay(intended)
current_overlay = intended
/datum/component/wet_floor/proc/AfterSlip(mob/living/L)
if(highest_strength == TURF_WET_LUBE)
L.confused = max(L.confused, 8)
/datum/component/wet_floor/proc/update_flags()
var/intensity
lube_flags = NONE
switch(highest_strength)
if(TURF_WET_WATER)
intensity = 60
lube_flags = NO_SLIP_WHEN_WALKING
if(TURF_WET_LUBE)
intensity = 80
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_ICE)
intensity = 120
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_PERMAFROST)
intensity = 120
lube_flags = SLIDE_ICE | GALOSHES_DONT_HELP
if(TURF_WET_SUPERLUBE)
intensity = 120
lube_flags = SLIDE | GALOSHES_DONT_HELP | SLIP_WHEN_CRAWLING
else
qdel(parent.GetComponent(/datum/component/slippery))
return
var/datum/component/slippery/S = parent.LoadComponent(/datum/component/slippery, NONE, CALLBACK(src, .proc/AfterSlip))
S.intensity = intensity
S.lube_flags = lube_flags
/datum/component/wet_floor/proc/dry(datum/source, strength = TURF_WET_WATER, immediate = FALSE, duration_decrease = INFINITY)
for(var/i in time_left_list)
if(text2num(i) <= strength)
time_left_list[i] = max(0, time_left_list[i] - duration_decrease)
if(immediate)
check()
/datum/component/wet_floor/proc/max_time_left()
. = 0
for(var/i in time_left_list)
. = max(., time_left_list[i])
/datum/component/wet_floor/process()
var/turf/open/T = parent
var/diff = world.time - last_process
var/decrease = 0
var/t = T.GetTemperature()
switch(t)
if(-INFINITY to T0C)
add_wet(TURF_WET_ICE, max_time_left()) //Water freezes into ice!
if(T0C to T0C + 100)
decrease = ((T.air.temperature - T0C) / SSwet_floors.temperature_coeff) * (diff / SSwet_floors.time_ratio)
if(T0C + 100 to INFINITY)
decrease = INFINITY
decrease = max(0, decrease)
if((is_wet() & TURF_WET_ICE) && t > T0C) //Ice melts into water!
for(var/obj/O in T.contents)
if(O.obj_flags & FROZEN)
O.make_unfrozen()
add_wet(TURF_WET_WATER, max_time_left())
dry(null, TURF_WET_ICE)
dry(null, ALL, FALSE, decrease)
check()
last_process = world.time
/datum/component/wet_floor/proc/update_strength()
highest_strength = 0 //Not bitflag.
for(var/i in time_left_list)
highest_strength = max(highest_strength, text2num(i))
/datum/component/wet_floor/proc/is_wet()
. = 0
for(var/i in time_left_list)
. |= text2num(i)
/datum/component/wet_floor/PreTransfer()
var/turf/O = parent
O.cut_overlay(current_overlay)
//That turf is no longer slippery, we're out of here
//Slippery components don't transfer due to callbacks
qdel(O.GetComponent(/datum/component/slippery))
/datum/component/wet_floor/PostTransfer()
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
var/turf/T = parent
T.add_overlay(current_overlay)
//Make sure to add/update any slippery component on the new turf (update_flags calls LoadComponent)
update_flags()
//NB it's possible we get deleted after this, due to inherit
/datum/component/wet_floor/proc/add_wet(type, duration_minimum = 0, duration_add = 0, duration_maximum = MAXIMUM_WET_TIME, _permanent = FALSE)
var/static/list/allowed_types = list(TURF_WET_WATER, TURF_WET_LUBE, TURF_WET_ICE, TURF_WET_PERMAFROST, TURF_WET_SUPERLUBE)
if(duration_minimum <= 0 || !type)
return FALSE
if(type in allowed_types)
return _do_add_wet(type, duration_minimum, duration_add, duration_maximum)
else
. = NONE
for(var/i in allowed_types)
if(!(type & i))
continue
. |= _do_add_wet(i, duration_minimum, duration_add, duration_maximum)
if(_permanent)
permanent = TRUE
STOP_PROCESSING(SSwet_floors, src)
/datum/component/wet_floor/proc/_do_add_wet(type, duration_minimum, duration_add, duration_maximum)
var/time = 0
if(LAZYACCESS(time_left_list, "[type]"))
time = CLAMP(LAZYACCESS(time_left_list, "[type]") + duration_add, duration_minimum, duration_maximum)
else
time = min(duration_minimum, duration_maximum)
LAZYSET(time_left_list, "[type]", time)
check(TRUE)
return TRUE
/datum/component/wet_floor/proc/gc(on_init = FALSE)
if(!LAZYLEN(time_left_list))
if(on_init)
var/turf/T = parent
stack_trace("Warning: Wet floor component gc'd right after initialization! What a waste of time and CPU! Type = [T? T.type : "ERROR - NO PARENT"], Location = [istype(T)? AREACOORD(T) : "ERROR - INVALID PARENT"].")
qdel(src)
return TRUE
return FALSE
/datum/component/wet_floor/proc/check(force_update = FALSE)
var/changed = FALSE
for(var/i in time_left_list)
if(time_left_list[i] <= 0)
time_left_list -= i
changed = TRUE
if(changed || force_update)
update_strength()
update_overlay()
update_flags()
gc()
/datum/component/wet_floor
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
can_transfer = TRUE
var/highest_strength = TURF_DRY
var/lube_flags = NONE //why do we have this?
var/list/time_left_list //In deciseconds.
var/static/mutable_appearance/permafrost_overlay = mutable_appearance('icons/effects/water.dmi', "ice_floor")
var/static/mutable_appearance/ice_overlay = mutable_appearance('icons/turf/overlays.dmi', "snowfloor")
var/static/mutable_appearance/water_overlay = mutable_appearance('icons/effects/water.dmi', "wet_floor_static")
var/static/mutable_appearance/generic_turf_overlay = mutable_appearance('icons/effects/water.dmi', "wet_static")
var/current_overlay
var/permanent = FALSE
var/last_process = 0
/datum/component/wet_floor/InheritComponent(datum/newcomp, orig, argslist)
if(!newcomp) //We are getting passed the arguments of a would-be new component, but not a new component
add_wet(arglist(argslist))
else //We are being passed in a full blown component
var/datum/component/wet_floor/WF = newcomp //Lets make an assumption
if(WF.gc()) //See if it's even valid, still. Also does LAZYLEN and stuff for us.
CRASH("Wet floor component tried to inherit another, but the other was able to garbage collect while being inherited! What a waste of time!")
return
for(var/i in WF.time_left_list)
add_wet(text2num(i), WF.time_left_list[i])
/datum/component/wet_floor/Initialize(strength, duration_minimum, duration_add, duration_maximum, _permanent = FALSE)
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
add_wet(strength, duration_minimum, duration_add, duration_maximum)
permanent = _permanent
if(!permanent)
START_PROCESSING(SSwet_floors, src)
addtimer(CALLBACK(src, .proc/gc, TRUE), 1) //GC after initialization.
last_process = world.time
/datum/component/wet_floor/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_TURF_IS_WET, .proc/is_wet)
RegisterSignal(parent, COMSIG_TURF_MAKE_DRY, .proc/dry)
/datum/component/wet_floor/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_TURF_IS_WET, COMSIG_TURF_MAKE_DRY))
/datum/component/wet_floor/Destroy()
STOP_PROCESSING(SSwet_floors, src)
var/turf/T = parent
qdel(T.GetComponent(/datum/component/slippery))
if(istype(T)) //If this is false there is so many things wrong with it.
T.cut_overlay(current_overlay)
else
stack_trace("Warning: Wet floor component wasn't on a turf when being destroyed! This is really bad!")
return ..()
/datum/component/wet_floor/proc/update_overlay()
var/intended
if(!istype(parent, /turf/open/floor))
intended = generic_turf_overlay
else
switch(highest_strength)
if(TURF_WET_PERMAFROST)
intended = permafrost_overlay
if(TURF_WET_ICE)
intended = ice_overlay
else
intended = water_overlay
if(current_overlay != intended)
var/turf/T = parent
T.cut_overlay(current_overlay)
T.add_overlay(intended)
current_overlay = intended
/datum/component/wet_floor/proc/AfterSlip(mob/living/L)
if(highest_strength == TURF_WET_LUBE)
L.confused = max(L.confused, 8)
/datum/component/wet_floor/proc/update_flags()
var/intensity
lube_flags = NONE
switch(highest_strength)
if(TURF_WET_WATER)
intensity = 60
lube_flags = NO_SLIP_WHEN_WALKING
if(TURF_WET_LUBE)
intensity = 80
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_ICE)
intensity = 120
lube_flags = SLIDE | GALOSHES_DONT_HELP
if(TURF_WET_PERMAFROST)
intensity = 120
lube_flags = SLIDE_ICE | GALOSHES_DONT_HELP
if(TURF_WET_SUPERLUBE)
intensity = 120
lube_flags = SLIDE | GALOSHES_DONT_HELP | SLIP_WHEN_CRAWLING
else
qdel(parent.GetComponent(/datum/component/slippery))
return
var/datum/component/slippery/S = parent.LoadComponent(/datum/component/slippery, NONE, CALLBACK(src, .proc/AfterSlip))
S.intensity = intensity
S.lube_flags = lube_flags
/datum/component/wet_floor/proc/dry(datum/source, strength = TURF_WET_WATER, immediate = FALSE, duration_decrease = INFINITY)
for(var/i in time_left_list)
if(text2num(i) <= strength)
time_left_list[i] = max(0, time_left_list[i] - duration_decrease)
if(immediate)
check()
/datum/component/wet_floor/proc/max_time_left()
. = 0
for(var/i in time_left_list)
. = max(., time_left_list[i])
/datum/component/wet_floor/process()
var/turf/open/T = parent
var/diff = world.time - last_process
var/decrease = 0
var/t = T.GetTemperature()
switch(t)
if(-INFINITY to T0C)
add_wet(TURF_WET_ICE, max_time_left()) //Water freezes into ice!
if(T0C to T0C + 100)
decrease = ((T.air.temperature - T0C) / SSwet_floors.temperature_coeff) * (diff / SSwet_floors.time_ratio)
if(T0C + 100 to INFINITY)
decrease = INFINITY
decrease = max(0, decrease)
if((is_wet() & TURF_WET_ICE) && t > T0C) //Ice melts into water!
for(var/obj/O in T.contents)
if(O.obj_flags & FROZEN)
O.make_unfrozen()
add_wet(TURF_WET_WATER, max_time_left())
dry(null, TURF_WET_ICE)
dry(null, ALL, FALSE, decrease)
check()
last_process = world.time
/datum/component/wet_floor/proc/update_strength()
highest_strength = 0 //Not bitflag.
for(var/i in time_left_list)
highest_strength = max(highest_strength, text2num(i))
/datum/component/wet_floor/proc/is_wet()
. = 0
for(var/i in time_left_list)
. |= text2num(i)
/datum/component/wet_floor/PreTransfer()
var/turf/O = parent
O.cut_overlay(current_overlay)
//That turf is no longer slippery, we're out of here
//Slippery components don't transfer due to callbacks
qdel(O.GetComponent(/datum/component/slippery))
/datum/component/wet_floor/PostTransfer()
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
var/turf/T = parent
T.add_overlay(current_overlay)
//Make sure to add/update any slippery component on the new turf (update_flags calls LoadComponent)
update_flags()
//NB it's possible we get deleted after this, due to inherit
/datum/component/wet_floor/proc/add_wet(type, duration_minimum = 0, duration_add = 0, duration_maximum = MAXIMUM_WET_TIME, _permanent = FALSE)
var/static/list/allowed_types = list(TURF_WET_WATER, TURF_WET_LUBE, TURF_WET_ICE, TURF_WET_PERMAFROST, TURF_WET_SUPERLUBE)
if(duration_minimum <= 0 || !type)
return FALSE
if(type in allowed_types)
return _do_add_wet(type, duration_minimum, duration_add, duration_maximum)
else
. = NONE
for(var/i in allowed_types)
if(!(type & i))
continue
. |= _do_add_wet(i, duration_minimum, duration_add, duration_maximum)
if(_permanent)
permanent = TRUE
STOP_PROCESSING(SSwet_floors, src)
/datum/component/wet_floor/proc/_do_add_wet(type, duration_minimum, duration_add, duration_maximum)
var/time = 0
if(LAZYACCESS(time_left_list, "[type]"))
time = CLAMP(LAZYACCESS(time_left_list, "[type]") + duration_add, duration_minimum, duration_maximum)
else
time = min(duration_minimum, duration_maximum)
LAZYSET(time_left_list, "[type]", time)
check(TRUE)
return TRUE
/datum/component/wet_floor/proc/gc(on_init = FALSE)
if(!LAZYLEN(time_left_list))
if(on_init)
var/turf/T = parent
stack_trace("Warning: Wet floor component gc'd right after initialization! What a waste of time and CPU! Type = [T? T.type : "ERROR - NO PARENT"], Location = [istype(T)? AREACOORD(T) : "ERROR - INVALID PARENT"].")
qdel(src)
return TRUE
return FALSE
/datum/component/wet_floor/proc/check(force_update = FALSE)
var/changed = FALSE
for(var/i in time_left_list)
if(time_left_list[i] <= 0)
time_left_list -= i
changed = TRUE
if(changed || force_update)
update_strength()
update_overlay()
update_flags()
gc()
+295 -295
View File
@@ -1,295 +1,295 @@
/datum/datacore
var/medical[] = list()
var/medicalPrintCount = 0
var/general[] = list()
var/security[] = list()
var/securityPrintCount = 0
var/securityCrimeCounter = 0
//This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character().
var/locked[] = list()
/datum/data
var/name = "data"
/datum/data/record
name = "record"
var/list/fields = list()
/datum/data/record/Destroy()
if(src in GLOB.data_core.medical)
GLOB.data_core.medical -= src
if(src in GLOB.data_core.security)
GLOB.data_core.security -= src
if(src in GLOB.data_core.general)
GLOB.data_core.general -= src
if(src in GLOB.data_core.locked)
GLOB.data_core.locked -= src
. = ..()
/datum/data/crime
name = "crime"
var/crimeName = ""
var/crimeDetails = ""
var/author = ""
var/time = ""
var/dataId = 0
/datum/datacore/proc/createCrimeEntry(cname = "", cdetails = "", author = "", time = "")
var/datum/data/crime/c = new /datum/data/crime
c.crimeName = cname
c.crimeDetails = cdetails
c.author = author
c.time = time
c.dataId = ++securityCrimeCounter
return c
/datum/datacore/proc/addMinorCrime(id = "", datum/data/crime/crime)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["mi_crim"]
crimes |= crime
return
/datum/datacore/proc/removeMinorCrime(id, cDataId)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["mi_crim"]
for(var/datum/data/crime/crime in crimes)
if(crime.dataId == text2num(cDataId))
crimes -= crime
return
/datum/datacore/proc/removeMajorCrime(id, cDataId)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["ma_crim"]
for(var/datum/data/crime/crime in crimes)
if(crime.dataId == text2num(cDataId))
crimes -= crime
return
/datum/datacore/proc/addMajorCrime(id = "", datum/data/crime/crime)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["ma_crim"]
crimes |= crime
return
/datum/datacore/proc/manifest()
for(var/mob/dead/new_player/N in GLOB.player_list)
if(N.new_character)
log_manifest(N.ckey,N.new_character.mind,N.new_character)
if(ishuman(N.new_character))
manifest_inject(N.new_character, N.client)
CHECK_TICK
/datum/datacore/proc/manifest_modify(name, assignment)
var/datum/data/record/foundrecord = find_record("name", name, GLOB.data_core.general)
if(foundrecord)
foundrecord.fields["rank"] = assignment
/datum/datacore/proc/get_manifest(monochrome, OOC)
var/list/heads = list()
var/list/sec = list()
var/list/eng = list()
var/list/med = list()
var/list/sci = list()
var/list/sup = list()
var/list/civ = list()
var/list/bot = list()
var/list/misc = list()
var/dat = {"
<head><style>
.manifest {border-collapse:collapse;}
.manifest td, th {border:1px solid [monochrome?"black":"#DEF; background-color:white; color:black"]; padding:.25em}
.manifest th {height: 2em; [monochrome?"border-top-width: 3px":"background-color: #48C; color:white"]}
.manifest tr.head th { [monochrome?"border-top-width: 1px":"background-color: #488;"] }
.manifest td:first-child {text-align:right}
.manifest tr.alt td {[monochrome?"border-top-width: 2px":"background-color: #DEF"]}
</style></head>
<table class="manifest" width='350px'>
<tr class='head'><th>Name</th><th>Rank</th></tr>
"}
var/even = 0
// sort mobs
for(var/datum/data/record/t in GLOB.data_core.general)
var/name = t.fields["name"]
var/rank = t.fields["rank"]
var/department = 0
if(rank in GLOB.command_positions)
heads[name] = rank
department = 1
if(rank in GLOB.security_positions)
sec[name] = rank
department = 1
if(rank in GLOB.engineering_positions)
eng[name] = rank
department = 1
if(rank in GLOB.medical_positions)
med[name] = rank
department = 1
if(rank in GLOB.science_positions)
sci[name] = rank
department = 1
if(rank in GLOB.supply_positions)
sup[name] = rank
department = 1
if(rank in GLOB.civilian_positions)
civ[name] = rank
department = 1
if(rank in GLOB.nonhuman_positions)
bot[name] = rank
department = 1
if(!department && !(name in heads))
misc[name] = rank
if(heads.len > 0)
dat += "<tr><th colspan=3>Heads</th></tr>"
for(var/name in heads)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[heads[name]]</td></tr>"
even = !even
if(sec.len > 0)
dat += "<tr><th colspan=3>Security</th></tr>"
for(var/name in sec)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[sec[name]]</td></tr>"
even = !even
if(eng.len > 0)
dat += "<tr><th colspan=3>Engineering</th></tr>"
for(var/name in eng)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[eng[name]]</td></tr>"
even = !even
if(med.len > 0)
dat += "<tr><th colspan=3>Medical</th></tr>"
for(var/name in med)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[med[name]]</td></tr>"
even = !even
if(sci.len > 0)
dat += "<tr><th colspan=3>Science</th></tr>"
for(var/name in sci)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[sci[name]]</td></tr>"
even = !even
if(sup.len > 0)
dat += "<tr><th colspan=3>Supply</th></tr>"
for(var/name in sup)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[sup[name]]</td></tr>"
even = !even
if(civ.len > 0)
dat += "<tr><th colspan=3>Civilian</th></tr>"
for(var/name in civ)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[civ[name]]</td></tr>"
even = !even
// in case somebody is insane and added them to the manifest, why not
if(bot.len > 0)
dat += "<tr><th colspan=3>Silicon</th></tr>"
for(var/name in bot)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[bot[name]]</td></tr>"
even = !even
// misc guys
if(misc.len > 0)
dat += "<tr><th colspan=3>Miscellaneous</th></tr>"
for(var/name in misc)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[misc[name]]</td></tr>"
even = !even
dat += "</table>"
dat = replacetext(dat, "\n", "")
dat = replacetext(dat, "\t", "")
return dat
/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/C)
set waitfor = FALSE
var/static/list/show_directions = list(SOUTH, WEST)
if(H.mind && (H.mind.assigned_role != H.mind.special_role))
var/assignment
if(H.mind.assigned_role)
assignment = H.mind.assigned_role
else if(H.job)
assignment = H.job
else
assignment = "Unassigned"
var/static/record_id_num = 1001
var/id = num2hex(record_id_num++,6)
if(!C)
C = H.client
var/image = get_id_photo(H, C, show_directions)
var/datum/picture/pf = new
var/datum/picture/ps = new
pf.picture_name = "[H]"
ps.picture_name = "[H]"
pf.picture_desc = "This is [H]."
ps.picture_desc = "This is [H]."
pf.picture_image = icon(image, dir = SOUTH)
ps.picture_image = icon(image, dir = WEST)
var/obj/item/photo/photo_front = new(null, pf)
var/obj/item/photo/photo_side = new(null, ps)
//These records should ~really~ be merged or something
//General Record
var/datum/data/record/G = new()
G.fields["id"] = id
G.fields["name"] = H.real_name
G.fields["rank"] = assignment
G.fields["age"] = H.age
G.fields["species"] = H.dna.species.name
G.fields["fingerprint"] = md5(H.dna.uni_identity)
G.fields["p_stat"] = "Active"
G.fields["m_stat"] = "Stable"
G.fields["sex"] = H.gender
G.fields["photo_front"] = photo_front
G.fields["photo_side"] = photo_side
general += G
//Medical Record
var/datum/data/record/M = new()
M.fields["id"] = id
M.fields["name"] = H.real_name
M.fields["blood_type"] = H.dna.blood_type
M.fields["b_dna"] = H.dna.unique_enzymes
M.fields["mi_dis"] = "None"
M.fields["mi_dis_d"] = "No minor disabilities have been declared."
M.fields["ma_dis"] = "None"
M.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
M.fields["alg"] = "None"
M.fields["alg_d"] = "No allergies have been detected in this patient."
M.fields["cdi"] = "None"
M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
M.fields["notes"] = H.get_trait_string(medical)
medical += M
//Security Record
var/datum/data/record/S = new()
S.fields["id"] = id
S.fields["name"] = H.real_name
S.fields["criminal"] = "None"
S.fields["mi_crim"] = list()
S.fields["ma_crim"] = list()
S.fields["notes"] = "No notes."
security += S
//Locked Record
var/datum/data/record/L = new()
L.fields["id"] = md5("[H.real_name][H.mind.assigned_role]") //surely this should just be id, like the others?
L.fields["name"] = H.real_name
L.fields["rank"] = H.mind.assigned_role
L.fields["age"] = H.age
L.fields["sex"] = H.gender
L.fields["blood_type"] = H.dna.blood_type
L.fields["b_dna"] = H.dna.unique_enzymes
L.fields["identity"] = H.dna.uni_identity
L.fields["species"] = H.dna.species.type
L.fields["features"] = H.dna.features
L.fields["image"] = image
L.fields["mindref"] = H.mind
locked += L
return
/datum/datacore/proc/get_id_photo(mob/living/carbon/human/H, client/C, show_directions = list(SOUTH))
var/datum/job/J = SSjob.GetJob(H.mind.assigned_role)
var/datum/preferences/P
if(!C)
C = H.client
if(C)
P = C.prefs
return get_flat_human_icon(null, J, P, DUMMY_HUMAN_SLOT_MANIFEST, show_directions)
/datum/datacore
var/medical[] = list()
var/medicalPrintCount = 0
var/general[] = list()
var/security[] = list()
var/securityPrintCount = 0
var/securityCrimeCounter = 0
//This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character().
var/locked[] = list()
/datum/data
var/name = "data"
/datum/data/record
name = "record"
var/list/fields = list()
/datum/data/record/Destroy()
if(src in GLOB.data_core.medical)
GLOB.data_core.medical -= src
if(src in GLOB.data_core.security)
GLOB.data_core.security -= src
if(src in GLOB.data_core.general)
GLOB.data_core.general -= src
if(src in GLOB.data_core.locked)
GLOB.data_core.locked -= src
. = ..()
/datum/data/crime
name = "crime"
var/crimeName = ""
var/crimeDetails = ""
var/author = ""
var/time = ""
var/dataId = 0
/datum/datacore/proc/createCrimeEntry(cname = "", cdetails = "", author = "", time = "")
var/datum/data/crime/c = new /datum/data/crime
c.crimeName = cname
c.crimeDetails = cdetails
c.author = author
c.time = time
c.dataId = ++securityCrimeCounter
return c
/datum/datacore/proc/addMinorCrime(id = "", datum/data/crime/crime)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["mi_crim"]
crimes |= crime
return
/datum/datacore/proc/removeMinorCrime(id, cDataId)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["mi_crim"]
for(var/datum/data/crime/crime in crimes)
if(crime.dataId == text2num(cDataId))
crimes -= crime
return
/datum/datacore/proc/removeMajorCrime(id, cDataId)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["ma_crim"]
for(var/datum/data/crime/crime in crimes)
if(crime.dataId == text2num(cDataId))
crimes -= crime
return
/datum/datacore/proc/addMajorCrime(id = "", datum/data/crime/crime)
for(var/datum/data/record/R in security)
if(R.fields["id"] == id)
var/list/crimes = R.fields["ma_crim"]
crimes |= crime
return
/datum/datacore/proc/manifest()
for(var/mob/dead/new_player/N in GLOB.player_list)
if(N.new_character)
log_manifest(N.ckey,N.new_character.mind,N.new_character)
if(ishuman(N.new_character))
manifest_inject(N.new_character, N.client)
CHECK_TICK
/datum/datacore/proc/manifest_modify(name, assignment)
var/datum/data/record/foundrecord = find_record("name", name, GLOB.data_core.general)
if(foundrecord)
foundrecord.fields["rank"] = assignment
/datum/datacore/proc/get_manifest(monochrome, OOC)
var/list/heads = list()
var/list/sec = list()
var/list/eng = list()
var/list/med = list()
var/list/sci = list()
var/list/sup = list()
var/list/civ = list()
var/list/bot = list()
var/list/misc = list()
var/dat = {"
<head><style>
.manifest {border-collapse:collapse;}
.manifest td, th {border:1px solid [monochrome?"black":"#DEF; background-color:white; color:black"]; padding:.25em}
.manifest th {height: 2em; [monochrome?"border-top-width: 3px":"background-color: #48C; color:white"]}
.manifest tr.head th { [monochrome?"border-top-width: 1px":"background-color: #488;"] }
.manifest td:first-child {text-align:right}
.manifest tr.alt td {[monochrome?"border-top-width: 2px":"background-color: #DEF"]}
</style></head>
<table class="manifest" width='350px'>
<tr class='head'><th>Name</th><th>Rank</th></tr>
"}
var/even = 0
// sort mobs
for(var/datum/data/record/t in GLOB.data_core.general)
var/name = t.fields["name"]
var/rank = t.fields["rank"]
var/department = 0
if(rank in GLOB.command_positions)
heads[name] = rank
department = 1
if(rank in GLOB.security_positions)
sec[name] = rank
department = 1
if(rank in GLOB.engineering_positions)
eng[name] = rank
department = 1
if(rank in GLOB.medical_positions)
med[name] = rank
department = 1
if(rank in GLOB.science_positions)
sci[name] = rank
department = 1
if(rank in GLOB.supply_positions)
sup[name] = rank
department = 1
if(rank in GLOB.civilian_positions)
civ[name] = rank
department = 1
if(rank in GLOB.nonhuman_positions)
bot[name] = rank
department = 1
if(!department && !(name in heads))
misc[name] = rank
if(heads.len > 0)
dat += "<tr><th colspan=3>Heads</th></tr>"
for(var/name in heads)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[heads[name]]</td></tr>"
even = !even
if(sec.len > 0)
dat += "<tr><th colspan=3>Security</th></tr>"
for(var/name in sec)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[sec[name]]</td></tr>"
even = !even
if(eng.len > 0)
dat += "<tr><th colspan=3>Engineering</th></tr>"
for(var/name in eng)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[eng[name]]</td></tr>"
even = !even
if(med.len > 0)
dat += "<tr><th colspan=3>Medical</th></tr>"
for(var/name in med)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[med[name]]</td></tr>"
even = !even
if(sci.len > 0)
dat += "<tr><th colspan=3>Science</th></tr>"
for(var/name in sci)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[sci[name]]</td></tr>"
even = !even
if(sup.len > 0)
dat += "<tr><th colspan=3>Supply</th></tr>"
for(var/name in sup)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[sup[name]]</td></tr>"
even = !even
if(civ.len > 0)
dat += "<tr><th colspan=3>Civilian</th></tr>"
for(var/name in civ)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[civ[name]]</td></tr>"
even = !even
// in case somebody is insane and added them to the manifest, why not
if(bot.len > 0)
dat += "<tr><th colspan=3>Silicon</th></tr>"
for(var/name in bot)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[bot[name]]</td></tr>"
even = !even
// misc guys
if(misc.len > 0)
dat += "<tr><th colspan=3>Miscellaneous</th></tr>"
for(var/name in misc)
dat += "<tr[even ? " class='alt'" : ""]><td>[name]</td><td>[misc[name]]</td></tr>"
even = !even
dat += "</table>"
dat = replacetext(dat, "\n", "")
dat = replacetext(dat, "\t", "")
return dat
/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H, client/C)
set waitfor = FALSE
var/static/list/show_directions = list(SOUTH, WEST)
if(H.mind && (H.mind.assigned_role != H.mind.special_role))
var/assignment
if(H.mind.assigned_role)
assignment = H.mind.assigned_role
else if(H.job)
assignment = H.job
else
assignment = "Unassigned"
var/static/record_id_num = 1001
var/id = num2hex(record_id_num++,6)
if(!C)
C = H.client
var/image = get_id_photo(H, C, show_directions)
var/datum/picture/pf = new
var/datum/picture/ps = new
pf.picture_name = "[H]"
ps.picture_name = "[H]"
pf.picture_desc = "This is [H]."
ps.picture_desc = "This is [H]."
pf.picture_image = icon(image, dir = SOUTH)
ps.picture_image = icon(image, dir = WEST)
var/obj/item/photo/photo_front = new(null, pf)
var/obj/item/photo/photo_side = new(null, ps)
//These records should ~really~ be merged or something
//General Record
var/datum/data/record/G = new()
G.fields["id"] = id
G.fields["name"] = H.real_name
G.fields["rank"] = assignment
G.fields["age"] = H.age
G.fields["species"] = H.dna.species.name
G.fields["fingerprint"] = md5(H.dna.uni_identity)
G.fields["p_stat"] = "Active"
G.fields["m_stat"] = "Stable"
G.fields["sex"] = H.gender
G.fields["photo_front"] = photo_front
G.fields["photo_side"] = photo_side
general += G
//Medical Record
var/datum/data/record/M = new()
M.fields["id"] = id
M.fields["name"] = H.real_name
M.fields["blood_type"] = H.dna.blood_type
M.fields["b_dna"] = H.dna.unique_enzymes
M.fields["mi_dis"] = "None"
M.fields["mi_dis_d"] = "No minor disabilities have been declared."
M.fields["ma_dis"] = "None"
M.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
M.fields["alg"] = "None"
M.fields["alg_d"] = "No allergies have been detected in this patient."
M.fields["cdi"] = "None"
M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
M.fields["notes"] = H.get_trait_string(medical)
medical += M
//Security Record
var/datum/data/record/S = new()
S.fields["id"] = id
S.fields["name"] = H.real_name
S.fields["criminal"] = "None"
S.fields["mi_crim"] = list()
S.fields["ma_crim"] = list()
S.fields["notes"] = "No notes."
security += S
//Locked Record
var/datum/data/record/L = new()
L.fields["id"] = md5("[H.real_name][H.mind.assigned_role]") //surely this should just be id, like the others?
L.fields["name"] = H.real_name
L.fields["rank"] = H.mind.assigned_role
L.fields["age"] = H.age
L.fields["sex"] = H.gender
L.fields["blood_type"] = H.dna.blood_type
L.fields["b_dna"] = H.dna.unique_enzymes
L.fields["identity"] = H.dna.uni_identity
L.fields["species"] = H.dna.species.type
L.fields["features"] = H.dna.features
L.fields["image"] = image
L.fields["mindref"] = H.mind
locked += L
return
/datum/datacore/proc/get_id_photo(mob/living/carbon/human/H, client/C, show_directions = list(SOUTH))
var/datum/job/J = SSjob.GetJob(H.mind.assigned_role)
var/datum/preferences/P
if(!C)
C = H.client
if(C)
P = C.prefs
return get_flat_human_icon(null, J, P, DUMMY_HUMAN_SLOT_MANIFEST, show_directions)
+160 -160
View File
@@ -1,160 +1,160 @@
/datum
var/gc_destroyed //Time when this object was destroyed.
var/list/active_timers //for SStimer
var/list/datum_components //for /datum/components
var/list/status_traits
var/list/comp_lookup //it used to be for looking up components which had registered a signal but now anything can register
var/list/list/datum/callback/signal_procs
var/signal_enabled = FALSE
var/datum_flags = NONE
var/datum/weakref/weak_reference
#ifdef TESTING
var/running_find_references
var/last_find_references = 0
#endif
#ifdef DATUMVAR_DEBUGGING_MODE
var/list/cached_vars
#endif
// Default implementation of clean-up code.
// This should be overridden to remove all references pointing to the object being destroyed.
// Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE.
/datum/proc/Destroy(force=FALSE, ...)
tag = null
datum_flags &= ~DF_USE_TAG //In case something tries to REF us
weak_reference = null //ensure prompt GCing of weakref.
var/list/timers = active_timers
active_timers = null
for(var/thing in timers)
var/datum/timedevent/timer = thing
if (timer.spent)
continue
qdel(timer)
//BEGIN: ECS SHIT
signal_enabled = FALSE
var/list/dc = datum_components
if(dc)
var/all_components = dc[/datum/component]
if(length(all_components))
for(var/I in all_components)
var/datum/component/C = I
qdel(C, FALSE, TRUE)
else
var/datum/component/C = all_components
qdel(C, FALSE, TRUE)
dc.Cut()
var/list/lookup = comp_lookup
if(lookup)
for(var/sig in lookup)
var/list/comps = lookup[sig]
if(length(comps))
for(var/i in comps)
var/datum/component/comp = i
comp.UnregisterSignal(src, sig)
else
var/datum/component/comp = comps
comp.UnregisterSignal(src, sig)
comp_lookup = lookup = null
for(var/target in signal_procs)
UnregisterSignal(target, signal_procs[target])
//END: ECS SHIT
return QDEL_HINT_QUEUE
#ifdef DATUMVAR_DEBUGGING_MODE
/datum/proc/save_vars()
cached_vars = list()
for(var/i in vars)
if(i == "cached_vars")
continue
cached_vars[i] = vars[i]
/datum/proc/check_changed_vars()
. = list()
for(var/i in vars)
if(i == "cached_vars")
continue
if(cached_vars[i] != vars[i])
.[i] = list(cached_vars[i], vars[i])
/datum/proc/txt_changed_vars()
var/list/l = check_changed_vars()
var/t = "[src]([REF(src)]) changed vars:"
for(var/i in l)
t += "\"[i]\" \[[l[i][1]]\] --> \[[l[i][2]]\] "
t += "."
/datum/proc/to_chat_check_changed_vars(target = world)
to_chat(target, txt_changed_vars())
#endif
//Return a LIST for serialize_datum to encode! Not the actual json!
/datum/proc/serialize_list(list/options)
CRASH("Attempted to serialize datum [src] of type [type] without serialize_list being implemented!")
//Accepts a LIST from deserialize_datum. Should return src or another datum.
/datum/proc/deserialize_list(json, list/options)
CRASH("Attempted to deserialize datum [src] of type [type] without deserialize_list being implemented!")
//Serializes into JSON. Does not encode type.
/datum/proc/serialize_json(list/options)
. = serialize_list(options)
if(!islist(.))
. = null
else
. = json_encode(.)
//Deserializes from JSON. Does not parse type.
/datum/proc/deserialize_json(list/input, list/options)
var/list/jsonlist = json_decode(input)
. = deserialize_list(jsonlist)
if(!istype(., /datum))
. = null
/proc/json_serialize_datum(datum/D, list/options)
if(!istype(D))
return
var/list/jsonlist = D.serialize_list(options)
if(islist(jsonlist))
jsonlist["DATUM_TYPE"] = D.type
return json_encode(jsonlist)
/proc/json_deserialize_datum(list/jsonlist, list/options, target_type, strict_target_type = FALSE)
if(!islist(jsonlist))
if(!istext(jsonlist))
CRASH("Invalid JSON")
return
jsonlist = json_decode(jsonlist)
if(!islist(jsonlist))
CRASH("Invalid JSON")
return
if(!jsonlist["DATUM_TYPE"])
return
if(!ispath(jsonlist["DATUM_TYPE"]))
if(!istext(jsonlist["DATUM_TYPE"]))
return
jsonlist["DATUM_TYPE"] = text2path(jsonlist["DATUM_TYPE"])
if(!ispath(jsonlist["DATUM_TYPE"]))
return
if(target_type)
if(!ispath(target_type))
return
if(strict_target_type)
if(target_type != jsonlist["DATUM_TYPE"])
return
else if(!ispath(jsonlist["DATUM_TYPE"], target_type))
return
var/typeofdatum = jsonlist["DATUM_TYPE"] //BYOND won't directly read if this is just put in the line below, and will instead runtime because it thinks you're trying to make a new list?
var/datum/D = new typeofdatum
var/datum/returned = D.deserialize_list(jsonlist, options)
if(!istype(returned, /datum))
qdel(D)
else
return returned
/datum
var/gc_destroyed //Time when this object was destroyed.
var/list/active_timers //for SStimer
var/list/datum_components //for /datum/components
var/list/status_traits
var/list/comp_lookup //it used to be for looking up components which had registered a signal but now anything can register
var/list/list/datum/callback/signal_procs
var/signal_enabled = FALSE
var/datum_flags = NONE
var/datum/weakref/weak_reference
#ifdef TESTING
var/running_find_references
var/last_find_references = 0
#endif
#ifdef DATUMVAR_DEBUGGING_MODE
var/list/cached_vars
#endif
// Default implementation of clean-up code.
// This should be overridden to remove all references pointing to the object being destroyed.
// Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE.
/datum/proc/Destroy(force=FALSE, ...)
tag = null
datum_flags &= ~DF_USE_TAG //In case something tries to REF us
weak_reference = null //ensure prompt GCing of weakref.
var/list/timers = active_timers
active_timers = null
for(var/thing in timers)
var/datum/timedevent/timer = thing
if (timer.spent)
continue
qdel(timer)
//BEGIN: ECS SHIT
signal_enabled = FALSE
var/list/dc = datum_components
if(dc)
var/all_components = dc[/datum/component]
if(length(all_components))
for(var/I in all_components)
var/datum/component/C = I
qdel(C, FALSE, TRUE)
else
var/datum/component/C = all_components
qdel(C, FALSE, TRUE)
dc.Cut()
var/list/lookup = comp_lookup
if(lookup)
for(var/sig in lookup)
var/list/comps = lookup[sig]
if(length(comps))
for(var/i in comps)
var/datum/component/comp = i
comp.UnregisterSignal(src, sig)
else
var/datum/component/comp = comps
comp.UnregisterSignal(src, sig)
comp_lookup = lookup = null
for(var/target in signal_procs)
UnregisterSignal(target, signal_procs[target])
//END: ECS SHIT
return QDEL_HINT_QUEUE
#ifdef DATUMVAR_DEBUGGING_MODE
/datum/proc/save_vars()
cached_vars = list()
for(var/i in vars)
if(i == "cached_vars")
continue
cached_vars[i] = vars[i]
/datum/proc/check_changed_vars()
. = list()
for(var/i in vars)
if(i == "cached_vars")
continue
if(cached_vars[i] != vars[i])
.[i] = list(cached_vars[i], vars[i])
/datum/proc/txt_changed_vars()
var/list/l = check_changed_vars()
var/t = "[src]([REF(src)]) changed vars:"
for(var/i in l)
t += "\"[i]\" \[[l[i][1]]\] --> \[[l[i][2]]\] "
t += "."
/datum/proc/to_chat_check_changed_vars(target = world)
to_chat(target, txt_changed_vars())
#endif
//Return a LIST for serialize_datum to encode! Not the actual json!
/datum/proc/serialize_list(list/options)
CRASH("Attempted to serialize datum [src] of type [type] without serialize_list being implemented!")
//Accepts a LIST from deserialize_datum. Should return src or another datum.
/datum/proc/deserialize_list(json, list/options)
CRASH("Attempted to deserialize datum [src] of type [type] without deserialize_list being implemented!")
//Serializes into JSON. Does not encode type.
/datum/proc/serialize_json(list/options)
. = serialize_list(options)
if(!islist(.))
. = null
else
. = json_encode(.)
//Deserializes from JSON. Does not parse type.
/datum/proc/deserialize_json(list/input, list/options)
var/list/jsonlist = json_decode(input)
. = deserialize_list(jsonlist)
if(!istype(., /datum))
. = null
/proc/json_serialize_datum(datum/D, list/options)
if(!istype(D))
return
var/list/jsonlist = D.serialize_list(options)
if(islist(jsonlist))
jsonlist["DATUM_TYPE"] = D.type
return json_encode(jsonlist)
/proc/json_deserialize_datum(list/jsonlist, list/options, target_type, strict_target_type = FALSE)
if(!islist(jsonlist))
if(!istext(jsonlist))
CRASH("Invalid JSON")
return
jsonlist = json_decode(jsonlist)
if(!islist(jsonlist))
CRASH("Invalid JSON")
return
if(!jsonlist["DATUM_TYPE"])
return
if(!ispath(jsonlist["DATUM_TYPE"]))
if(!istext(jsonlist["DATUM_TYPE"]))
return
jsonlist["DATUM_TYPE"] = text2path(jsonlist["DATUM_TYPE"])
if(!ispath(jsonlist["DATUM_TYPE"]))
return
if(target_type)
if(!ispath(target_type))
return
if(strict_target_type)
if(target_type != jsonlist["DATUM_TYPE"])
return
else if(!ispath(jsonlist["DATUM_TYPE"], target_type))
return
var/typeofdatum = jsonlist["DATUM_TYPE"] //BYOND won't directly read if this is just put in the line below, and will instead runtime because it thinks you're trying to make a new list?
var/datum/D = new typeofdatum
var/datum/returned = D.deserialize_list(jsonlist, options)
if(!istype(returned, /datum))
qdel(D)
else
return returned
+1430 -1430
View File
File diff suppressed because it is too large Load Diff
+495 -495
View File
@@ -1,495 +1,495 @@
/*
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.
*/
/*
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 = FALSE
var/mutable = TRUE //set to FALSE to prevent most in-game methods of altering the disease via virology
var/oldres //To prevent setting new cures unless resistance changes.
// The order goes from easy to cure to hard to cure. Keep in mind that sentient diseases pick two cures from tier 6 and up, ensure they wont react away in bodies.
var/static/list/advance_cures = list(
list( // level 1
/datum/reagent/copper, /datum/reagent/silver, /datum/reagent/iodine, /datum/reagent/iron, /datum/reagent/carbon
),
list( // level 2
/datum/reagent/potassium, /datum/reagent/consumable/ethanol, /datum/reagent/lithium,
/datum/reagent/silicon, /datum/reagent/bromine
),
list( // level 3
/datum/reagent/consumable/sodiumchloride, /datum/reagent/consumable/sugar, /datum/reagent/consumable/orangejuice,
/datum/reagent/consumable/tomatojuice, /datum/reagent/consumable/milk
),
list( //level 4
/datum/reagent/medicine/spaceacillin, /datum/reagent/medicine/salglu_solution,
/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/charcoal
),
list( //level 5
/datum/reagent/oil, /datum/reagent/medicine/synaptizine, /datum/reagent/medicine/mannitol,
/datum/reagent/drug/space_drugs, /datum/reagent/cryptobiolin
),
list( // level 6
/datum/reagent/phenol, /datum/reagent/medicine/inacusiate, /datum/reagent/medicine/oculine, /datum/reagent/medicine/antihol
),
list( // level 7
/datum/reagent/medicine/leporazine, /datum/reagent/toxin/mindbreaker, /datum/reagent/medicine/corazone
),
list( // level 8
/datum/reagent/pax, /datum/reagent/drug/happiness, /datum/reagent/medicine/ephedrine
),
list( // level 9
/datum/reagent/toxin/lipolicide, /datum/reagent/medicine/sal_acid
),
list( // level 10
/datum/reagent/medicine/haloperidol, /datum/reagent/drug/aranesp, /datum/reagent/medicine/diphenhydramine
),
list( //level 11
/datum/reagent/medicine/modafinil, /datum/reagent/toxin/anacea
)
)
/*
OLD PROCS
*/
/datum/disease/advance/New()
Refresh()
/datum/disease/advance/Destroy()
if(processing)
for(var/datum/symptom/S in symptoms)
S.End(src)
return ..()
/datum/disease/advance/try_infect(var/mob/living/infectee, make_copy = TRUE)
//see if we are more transmittable than enough diseases to replace them
//diseases replaced in this way do not confer immunity
var/list/advance_diseases = list()
for(var/datum/disease/advance/P in infectee.diseases)
advance_diseases += P
var/replace_num = advance_diseases.len + 1 - DISEASE_LIMIT //amount of diseases that need to be removed to fit this one
if(replace_num > 0)
sortTim(advance_diseases, /proc/cmp_advdisease_resistance_asc)
for(var/i in 1 to replace_num)
var/datum/disease/advance/competition = advance_diseases[i]
if(totalTransmittable() > competition.totalResistance())
competition.cure(FALSE)
else
return FALSE //we are not strong enough to bully our way in
infect(infectee, make_copy)
return TRUE
// Randomly pick a symptom to activate.
/datum/disease/advance/stage_act()
..()
if(carrier)
return
if(symptoms && symptoms.len)
if(!processing)
processing = TRUE
for(var/datum/symptom/S in symptoms)
if(S.Start(src)) //this will return FALSE if the symptom is neutered
S.next_activation = world.time + rand(S.symptom_delay_min * 10, S.symptom_delay_max * 10)
S.on_stage_change(src)
for(var/datum/symptom/S in symptoms)
S.Activate(src)
// Tell symptoms stage changed
/datum/disease/advance/update_stage(new_stage)
..()
for(var/datum/symptom/S in symptoms)
S.on_stage_change(src)
// Compares type then ID.
/datum/disease/advance/IsSame(datum/disease/advance/D)
if(!(istype(D, /datum/disease/advance)))
return 0
if(GetDiseaseID() != D.GetDiseaseID())
return 0
return 1
// Returns the advance disease with a different reference memory.
/datum/disease/advance/Copy()
var/datum/disease/advance/A = ..()
QDEL_LIST(A.symptoms)
for(var/datum/symptom/S in symptoms)
A.symptoms += S.Copy()
A.properties = properties.Copy()
A.id = id
A.mutable = mutable
A.oldres = oldres
//this is a new disease starting over at stage 1, so processing is not copied
return A
//Describe this disease to an admin in detail (for logging)
/datum/disease/advance/admin_details()
var/list/name_symptoms = list()
for(var/datum/symptom/S in symptoms)
name_symptoms += S.name
return "[name] sym:[english_list(name_symptoms)] r:[totalResistance()] s:[totalStealth()] ss:[totalStageSpeed()] t:[totalTransmittable()]"
/*
NEW PROCS
*/
// Mix the symptoms of two diseases (the src and the argument)
/datum/disease/advance/proc/Mix(datum/disease/advance/D)
if(!(IsSame(D)))
var/list/possible_symptoms = shuffle(D.symptoms)
for(var/datum/symptom/S in possible_symptoms)
AddSymptom(S.Copy())
/datum/disease/advance/proc/HasSymptom(datum/symptom/S)
for(var/datum/symptom/symp in symptoms)
if(symp.type == S.type)
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.naturally_occuring && 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 = FALSE)
GenerateProperties()
AssignProperties()
if(processing && symptoms && symptoms.len)
for(var/datum/symptom/S in symptoms)
S.Start(src)
S.on_stage_change(src)
id = null
var/the_id = GetDiseaseID()
if(!SSdisease.archive_diseases[the_id])
SSdisease.archive_diseases[the_id] = src // So we don't infinite loop
SSdisease.archive_diseases[the_id] = Copy()
if(new_name)
AssignName()
//Generate disease properties based on the effects. Returns an associated list.
/datum/disease/advance/proc/GenerateProperties()
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
if(!S.neutered)
properties["severity"] = max(properties["severity"], S.severity) // severity is based on the highest severity non-neutered symptom
// Assign the properties that are in the list.
/datum/disease/advance/proc/AssignProperties()
if(properties && properties.len)
if(properties["stealth"] >= 2)
visibility_flags |= HIDDEN_SCANNER
else
visibility_flags &= ~HIDDEN_SCANNER
SetSpread(CLAMP(2 ** (properties["transmittable"] - symptoms.len), DISEASE_SPREAD_BLOOD, DISEASE_SPREAD_AIRBORNE))
permeability_mod = max(CEILING(0.4 * properties["transmittable"], 1), 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(DISEASE_SPREAD_NON_CONTAGIOUS)
spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS
spread_text = "None"
if(DISEASE_SPREAD_SPECIAL)
spread_flags = DISEASE_SPREAD_SPECIAL
spread_text = "None"
if(DISEASE_SPREAD_BLOOD)
spread_flags = DISEASE_SPREAD_BLOOD
spread_text = "Blood"
if(DISEASE_SPREAD_CONTACT_FLUIDS)
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS
spread_text = "Fluids"
if(DISEASE_SPREAD_CONTACT_SKIN)
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS | DISEASE_SPREAD_CONTACT_SKIN
spread_text = "On contact"
if(DISEASE_SPREAD_AIRBORNE)
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_AIRBORNE
spread_text = "Airborne"
/datum/disease/advance/proc/SetSeverity(level_sev)
switch(level_sev)
if(-INFINITY to 0)
severity = DISEASE_SEVERITY_POSITIVE
if(1)
severity = DISEASE_SEVERITY_NONTHREAT
if(2)
severity = DISEASE_SEVERITY_MINOR
if(3)
severity = DISEASE_SEVERITY_MEDIUM
if(4)
severity = DISEASE_SEVERITY_HARMFUL
if(5)
severity = DISEASE_SEVERITY_DANGEROUS
if(6 to INFINITY)
severity = DISEASE_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)
if(res == oldres)
return
cures = list(pick(advance_cures[res]))
oldres = res
// Get the cure name from the cure_id
var/datum/reagent/D = GLOB.chemical_reagents_list[cures[1]]
cure_text = D.name
// Randomly generate a symptom, has a chance to lose or gain a symptom.
/datum/disease/advance/proc/Evolve(min_level, max_level, ignore_mutable = FALSE)
if(!mutable && !ignore_mutable)
return
var/s = safepick(GenerateSymptoms(min_level, max_level, 1))
if(s)
AddSymptom(s)
Refresh(TRUE)
return
// Randomly remove a symptom.
/datum/disease/advance/proc/Devolve(ignore_mutable = FALSE)
if(!mutable && !ignore_mutable)
return
if(symptoms.len > 1)
var/s = safepick(symptoms)
if(s)
RemoveSymptom(s)
Refresh(TRUE)
// Randomly neuter a symptom.
/datum/disease/advance/proc/Neuter(ignore_mutable = FALSE)
if(!mutable && !ignore_mutable)
return
if(symptoms.len)
var/s = safepick(symptoms)
if(s)
NeuterSymptom(s)
Refresh(TRUE)
// Name the disease.
/datum/disease/advance/proc/AssignName(name = "Unknown")
Refresh()
var/datum/disease/advance/A = SSdisease.archive_diseases[GetDiseaseID()]
A.name = name
for(var/datum/disease/advance/AD in SSdisease.active_diseases)
AD.Refresh()
// Return a unique ID of the disease.
/datum/disease/advance/GetDiseaseID()
if(!id)
var/list/L = list()
for(var/datum/symptom/S in symptoms)
if(S.neutered)
L += "[S.id]N"
else
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 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 < (VIRUS_SYMPTOM_LIMIT - 1) + rand(-1, 1)))
RemoveSymptom(pick(symptoms))
symptoms += S
S.OnAdd(src)
// Simply removes the symptom.
/datum/disease/advance/proc/RemoveSymptom(datum/symptom/S)
symptoms -= S
S.OnRemove(src)
// Neuter a symptom, so it will only affect stats
/datum/disease/advance/proc/NeuterSymptom(datum/symptom/S)
if(!S.neutered)
S.neutered = TRUE
S.name += " (neutered)"
S.OnRemove(src)
/*
Static Procs
*/
// Mix a list of advance diseases and return the mixed result.
/proc/Advance_Mix(var/list/D_list)
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
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 = VIRUS_SYMPTOM_LIMIT
var/datum/disease/advance/D = new()
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/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list))
if(!is_station_level(H.z))
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.admin_details()]")
log_virus("[key_name(user)] has triggered a custom virus outbreak of [D.admin_details()]!")
/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"]
/*
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.
*/
/*
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 = FALSE
var/mutable = TRUE //set to FALSE to prevent most in-game methods of altering the disease via virology
var/oldres //To prevent setting new cures unless resistance changes.
// The order goes from easy to cure to hard to cure. Keep in mind that sentient diseases pick two cures from tier 6 and up, ensure they wont react away in bodies.
var/static/list/advance_cures = list(
list( // level 1
/datum/reagent/copper, /datum/reagent/silver, /datum/reagent/iodine, /datum/reagent/iron, /datum/reagent/carbon
),
list( // level 2
/datum/reagent/potassium, /datum/reagent/consumable/ethanol, /datum/reagent/lithium,
/datum/reagent/silicon, /datum/reagent/bromine
),
list( // level 3
/datum/reagent/consumable/sodiumchloride, /datum/reagent/consumable/sugar, /datum/reagent/consumable/orangejuice,
/datum/reagent/consumable/tomatojuice, /datum/reagent/consumable/milk
),
list( //level 4
/datum/reagent/medicine/spaceacillin, /datum/reagent/medicine/salglu_solution,
/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/charcoal
),
list( //level 5
/datum/reagent/oil, /datum/reagent/medicine/synaptizine, /datum/reagent/medicine/mannitol,
/datum/reagent/drug/space_drugs, /datum/reagent/cryptobiolin
),
list( // level 6
/datum/reagent/phenol, /datum/reagent/medicine/inacusiate, /datum/reagent/medicine/oculine, /datum/reagent/medicine/antihol
),
list( // level 7
/datum/reagent/medicine/leporazine, /datum/reagent/toxin/mindbreaker, /datum/reagent/medicine/corazone
),
list( // level 8
/datum/reagent/pax, /datum/reagent/drug/happiness, /datum/reagent/medicine/ephedrine
),
list( // level 9
/datum/reagent/toxin/lipolicide, /datum/reagent/medicine/sal_acid
),
list( // level 10
/datum/reagent/medicine/haloperidol, /datum/reagent/drug/aranesp, /datum/reagent/medicine/diphenhydramine
),
list( //level 11
/datum/reagent/medicine/modafinil, /datum/reagent/toxin/anacea
)
)
/*
OLD PROCS
*/
/datum/disease/advance/New()
Refresh()
/datum/disease/advance/Destroy()
if(processing)
for(var/datum/symptom/S in symptoms)
S.End(src)
return ..()
/datum/disease/advance/try_infect(var/mob/living/infectee, make_copy = TRUE)
//see if we are more transmittable than enough diseases to replace them
//diseases replaced in this way do not confer immunity
var/list/advance_diseases = list()
for(var/datum/disease/advance/P in infectee.diseases)
advance_diseases += P
var/replace_num = advance_diseases.len + 1 - DISEASE_LIMIT //amount of diseases that need to be removed to fit this one
if(replace_num > 0)
sortTim(advance_diseases, /proc/cmp_advdisease_resistance_asc)
for(var/i in 1 to replace_num)
var/datum/disease/advance/competition = advance_diseases[i]
if(totalTransmittable() > competition.totalResistance())
competition.cure(FALSE)
else
return FALSE //we are not strong enough to bully our way in
infect(infectee, make_copy)
return TRUE
// Randomly pick a symptom to activate.
/datum/disease/advance/stage_act()
..()
if(carrier)
return
if(symptoms && symptoms.len)
if(!processing)
processing = TRUE
for(var/datum/symptom/S in symptoms)
if(S.Start(src)) //this will return FALSE if the symptom is neutered
S.next_activation = world.time + rand(S.symptom_delay_min * 10, S.symptom_delay_max * 10)
S.on_stage_change(src)
for(var/datum/symptom/S in symptoms)
S.Activate(src)
// Tell symptoms stage changed
/datum/disease/advance/update_stage(new_stage)
..()
for(var/datum/symptom/S in symptoms)
S.on_stage_change(src)
// Compares type then ID.
/datum/disease/advance/IsSame(datum/disease/advance/D)
if(!(istype(D, /datum/disease/advance)))
return 0
if(GetDiseaseID() != D.GetDiseaseID())
return 0
return 1
// Returns the advance disease with a different reference memory.
/datum/disease/advance/Copy()
var/datum/disease/advance/A = ..()
QDEL_LIST(A.symptoms)
for(var/datum/symptom/S in symptoms)
A.symptoms += S.Copy()
A.properties = properties.Copy()
A.id = id
A.mutable = mutable
A.oldres = oldres
//this is a new disease starting over at stage 1, so processing is not copied
return A
//Describe this disease to an admin in detail (for logging)
/datum/disease/advance/admin_details()
var/list/name_symptoms = list()
for(var/datum/symptom/S in symptoms)
name_symptoms += S.name
return "[name] sym:[english_list(name_symptoms)] r:[totalResistance()] s:[totalStealth()] ss:[totalStageSpeed()] t:[totalTransmittable()]"
/*
NEW PROCS
*/
// Mix the symptoms of two diseases (the src and the argument)
/datum/disease/advance/proc/Mix(datum/disease/advance/D)
if(!(IsSame(D)))
var/list/possible_symptoms = shuffle(D.symptoms)
for(var/datum/symptom/S in possible_symptoms)
AddSymptom(S.Copy())
/datum/disease/advance/proc/HasSymptom(datum/symptom/S)
for(var/datum/symptom/symp in symptoms)
if(symp.type == S.type)
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.naturally_occuring && 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 = FALSE)
GenerateProperties()
AssignProperties()
if(processing && symptoms && symptoms.len)
for(var/datum/symptom/S in symptoms)
S.Start(src)
S.on_stage_change(src)
id = null
var/the_id = GetDiseaseID()
if(!SSdisease.archive_diseases[the_id])
SSdisease.archive_diseases[the_id] = src // So we don't infinite loop
SSdisease.archive_diseases[the_id] = Copy()
if(new_name)
AssignName()
//Generate disease properties based on the effects. Returns an associated list.
/datum/disease/advance/proc/GenerateProperties()
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
if(!S.neutered)
properties["severity"] = max(properties["severity"], S.severity) // severity is based on the highest severity non-neutered symptom
// Assign the properties that are in the list.
/datum/disease/advance/proc/AssignProperties()
if(properties && properties.len)
if(properties["stealth"] >= 2)
visibility_flags |= HIDDEN_SCANNER
else
visibility_flags &= ~HIDDEN_SCANNER
SetSpread(CLAMP(2 ** (properties["transmittable"] - symptoms.len), DISEASE_SPREAD_BLOOD, DISEASE_SPREAD_AIRBORNE))
permeability_mod = max(CEILING(0.4 * properties["transmittable"], 1), 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(DISEASE_SPREAD_NON_CONTAGIOUS)
spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS
spread_text = "None"
if(DISEASE_SPREAD_SPECIAL)
spread_flags = DISEASE_SPREAD_SPECIAL
spread_text = "None"
if(DISEASE_SPREAD_BLOOD)
spread_flags = DISEASE_SPREAD_BLOOD
spread_text = "Blood"
if(DISEASE_SPREAD_CONTACT_FLUIDS)
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS
spread_text = "Fluids"
if(DISEASE_SPREAD_CONTACT_SKIN)
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS | DISEASE_SPREAD_CONTACT_SKIN
spread_text = "On contact"
if(DISEASE_SPREAD_AIRBORNE)
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_FLUIDS | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_AIRBORNE
spread_text = "Airborne"
/datum/disease/advance/proc/SetSeverity(level_sev)
switch(level_sev)
if(-INFINITY to 0)
severity = DISEASE_SEVERITY_POSITIVE
if(1)
severity = DISEASE_SEVERITY_NONTHREAT
if(2)
severity = DISEASE_SEVERITY_MINOR
if(3)
severity = DISEASE_SEVERITY_MEDIUM
if(4)
severity = DISEASE_SEVERITY_HARMFUL
if(5)
severity = DISEASE_SEVERITY_DANGEROUS
if(6 to INFINITY)
severity = DISEASE_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)
if(res == oldres)
return
cures = list(pick(advance_cures[res]))
oldres = res
// Get the cure name from the cure_id
var/datum/reagent/D = GLOB.chemical_reagents_list[cures[1]]
cure_text = D.name
// Randomly generate a symptom, has a chance to lose or gain a symptom.
/datum/disease/advance/proc/Evolve(min_level, max_level, ignore_mutable = FALSE)
if(!mutable && !ignore_mutable)
return
var/s = safepick(GenerateSymptoms(min_level, max_level, 1))
if(s)
AddSymptom(s)
Refresh(TRUE)
return
// Randomly remove a symptom.
/datum/disease/advance/proc/Devolve(ignore_mutable = FALSE)
if(!mutable && !ignore_mutable)
return
if(symptoms.len > 1)
var/s = safepick(symptoms)
if(s)
RemoveSymptom(s)
Refresh(TRUE)
// Randomly neuter a symptom.
/datum/disease/advance/proc/Neuter(ignore_mutable = FALSE)
if(!mutable && !ignore_mutable)
return
if(symptoms.len)
var/s = safepick(symptoms)
if(s)
NeuterSymptom(s)
Refresh(TRUE)
// Name the disease.
/datum/disease/advance/proc/AssignName(name = "Unknown")
Refresh()
var/datum/disease/advance/A = SSdisease.archive_diseases[GetDiseaseID()]
A.name = name
for(var/datum/disease/advance/AD in SSdisease.active_diseases)
AD.Refresh()
// Return a unique ID of the disease.
/datum/disease/advance/GetDiseaseID()
if(!id)
var/list/L = list()
for(var/datum/symptom/S in symptoms)
if(S.neutered)
L += "[S.id]N"
else
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 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 < (VIRUS_SYMPTOM_LIMIT - 1) + rand(-1, 1)))
RemoveSymptom(pick(symptoms))
symptoms += S
S.OnAdd(src)
// Simply removes the symptom.
/datum/disease/advance/proc/RemoveSymptom(datum/symptom/S)
symptoms -= S
S.OnRemove(src)
// Neuter a symptom, so it will only affect stats
/datum/disease/advance/proc/NeuterSymptom(datum/symptom/S)
if(!S.neutered)
S.neutered = TRUE
S.name += " (neutered)"
S.OnRemove(src)
/*
Static Procs
*/
// Mix a list of advance diseases and return the mixed result.
/proc/Advance_Mix(var/list/D_list)
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
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 = VIRUS_SYMPTOM_LIMIT
var/datum/disease/advance/D = new()
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/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list))
if(!is_station_level(H.z))
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.admin_details()]")
log_virus("[key_name(user)] has triggered a custom virus outbreak of [D.admin_details()]!")
/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"]
+41 -41
View File
@@ -1,42 +1,42 @@
// Cold
/datum/disease/advance/cold
copy_type = /datum/disease/advance
/datum/disease/advance/cold/New()
name = "Cold"
symptoms = list(new/datum/symptom/sneeze)
..()
// Flu
/datum/disease/advance/flu
copy_type = /datum/disease/advance
/datum/disease/advance/flu/New()
name = "Flu"
symptoms = list(new/datum/symptom/cough)
..()
//Randomly generated Disease, for virus crates and events
/datum/disease/advance/random
name = "Experimental Disease"
copy_type = /datum/disease/advance
/datum/disease/advance/random/New(max_symptoms, max_level = 8)
if(!max_symptoms)
max_symptoms = rand(1, VIRUS_SYMPTOM_LIMIT)
var/list/datum/symptom/possible_symptoms = list()
for(var/symptom in subtypesof(/datum/symptom))
var/datum/symptom/S = symptom
if(initial(S.level) > max_level)
continue
if(initial(S.level) <= 0) //unobtainable symptoms
continue
possible_symptoms += S
for(var/i in 1 to max_symptoms)
var/datum/symptom/chosen_symptom = pick_n_take(possible_symptoms)
if(chosen_symptom)
var/datum/symptom/S = new chosen_symptom
symptoms += S
Refresh()
// Cold
/datum/disease/advance/cold
copy_type = /datum/disease/advance
/datum/disease/advance/cold/New()
name = "Cold"
symptoms = list(new/datum/symptom/sneeze)
..()
// Flu
/datum/disease/advance/flu
copy_type = /datum/disease/advance
/datum/disease/advance/flu/New()
name = "Flu"
symptoms = list(new/datum/symptom/cough)
..()
//Randomly generated Disease, for virus crates and events
/datum/disease/advance/random
name = "Experimental Disease"
copy_type = /datum/disease/advance
/datum/disease/advance/random/New(max_symptoms, max_level = 8)
if(!max_symptoms)
max_symptoms = rand(1, VIRUS_SYMPTOM_LIMIT)
var/list/datum/symptom/possible_symptoms = list()
for(var/symptom in subtypesof(/datum/symptom))
var/datum/symptom/S = symptom
if(initial(S.level) > max_level)
continue
if(initial(S.level) <= 0) //unobtainable symptoms
continue
possible_symptoms += S
for(var/i in 1 to max_symptoms)
var/datum/symptom/chosen_symptom = pick_n_take(possible_symptoms)
if(chosen_symptom)
var/datum/symptom/S = new chosen_symptom
symptoms += S
Refresh()
name = "Sample #[rand(1,10000)]"
+51 -51
View File
@@ -1,51 +1,51 @@
/*
//////////////////////////////////////
Facial Hypertrichosis
No change to stealth.
Increases resistance.
Increases speed.
Slighlty increases transmittability
Intense Level.
BONUS
Makes the mob grow a massive beard, regardless of gender.
//////////////////////////////////////
*/
/datum/symptom/beard
name = "Facial Hypertrichosis"
desc = "The virus increases hair production significantly, causing rapid beard growth."
stealth = 0
resistance = 3
stage_speed = 2
transmittable = 1
level = 4
severity = 1
symptom_delay_min = 18
symptom_delay_max = 36
/datum/symptom/beard/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
if(ishuman(M))
var/mob/living/carbon/human/H = M
switch(A.stage)
if(1, 2)
to_chat(H, "<span class='warning'>Your chin itches.</span>")
if(H.facial_hair_style == "Shaved")
H.facial_hair_style = "Jensen Beard"
H.update_hair()
if(3, 4)
to_chat(H, "<span class='warning'>You feel tough.</span>")
if(!(H.facial_hair_style == "Dwarf Beard") && !(H.facial_hair_style == "Very Long Beard") && !(H.facial_hair_style == "Full Beard"))
H.facial_hair_style = "Full Beard"
H.update_hair()
else
to_chat(H, "<span class='warning'>You feel manly!</span>")
if(!(H.facial_hair_style == "Dwarf Beard") && !(H.facial_hair_style == "Very Long Beard"))
H.facial_hair_style = pick("Dwarf Beard", "Very Long Beard")
H.update_hair()
/*
//////////////////////////////////////
Facial Hypertrichosis
No change to stealth.
Increases resistance.
Increases speed.
Slighlty increases transmittability
Intense Level.
BONUS
Makes the mob grow a massive beard, regardless of gender.
//////////////////////////////////////
*/
/datum/symptom/beard
name = "Facial Hypertrichosis"
desc = "The virus increases hair production significantly, causing rapid beard growth."
stealth = 0
resistance = 3
stage_speed = 2
transmittable = 1
level = 4
severity = 1
symptom_delay_min = 18
symptom_delay_max = 36
/datum/symptom/beard/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
if(ishuman(M))
var/mob/living/carbon/human/H = M
switch(A.stage)
if(1, 2)
to_chat(H, "<span class='warning'>Your chin itches.</span>")
if(H.facial_hair_style == "Shaved")
H.facial_hair_style = "Jensen Beard"
H.update_hair()
if(3, 4)
to_chat(H, "<span class='warning'>You feel tough.</span>")
if(!(H.facial_hair_style == "Dwarf Beard") && !(H.facial_hair_style == "Very Long Beard") && !(H.facial_hair_style == "Full Beard"))
H.facial_hair_style = "Full Beard"
H.update_hair()
else
to_chat(H, "<span class='warning'>You feel manly!</span>")
if(!(H.facial_hair_style == "Dwarf Beard") && !(H.facial_hair_style == "Very Long Beard"))
H.facial_hair_style = pick("Dwarf Beard", "Very Long Beard")
H.update_hair()
+148 -148
View File
@@ -1,148 +1,148 @@
/*
//////////////////////////////////////
Choking
Very very noticable.
Lowers resistance.
Decreases stage speed.
Decreases transmittablity tremendously.
Moderate Level.
Bonus
Inflicts spikes of oxyloss
//////////////////////////////////////
*/
/datum/symptom/choking
name = "Choking"
desc = "The virus causes inflammation of the host's air conduits, leading to intermittent choking."
stealth = -3
resistance = -2
stage_speed = -2
transmittable = -4
level = 3
severity = 3
base_message_chance = 15
symptom_delay_min = 10
symptom_delay_max = 30
threshold_desc = "<b>Stage Speed 8:</b> Causes choking more frequently.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/choking/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 8)
symptom_delay_min = 7
symptom_delay_max = 24
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
/datum/symptom/choking/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("You're having difficulty breathing.", "Your breathing becomes heavy.")]</span>")
if(3, 4)
if(!suppress_warning)
to_chat(M, "<span class='warning'>[pick("Your windpipe feels like a straw.", "Your breathing becomes tremendously difficult.")]</span>")
else
to_chat(M, "<span class='warning'>You feel very [pick("dizzy","woozy","faint")].</span>") //fake bloodloss messages
Choke_stage_3_4(M, A)
M.emote("gasp")
else
to_chat(M, "<span class='userdanger'>[pick("You're choking!", "You can't breathe!")]</span>")
Choke(M, A)
M.emote("gasp")
/datum/symptom/choking/proc/Choke_stage_3_4(mob/living/M, datum/disease/advance/A)
M.adjustOxyLoss(rand(6,13))
return 1
/datum/symptom/choking/proc/Choke(mob/living/M, datum/disease/advance/A)
M.adjustOxyLoss(rand(10,18))
return 1
/*
//////////////////////////////////////
Asphyxiation
Very very noticable.
Decreases stage speed.
Decreases transmittablity.
Bonus
Inflicts large spikes of oxyloss
Introduces Asphyxiating drugs to the system
Causes cardiac arrest on dying victims.
//////////////////////////////////////
*/
/datum/symptom/asphyxiation
name = "Acute respiratory distress syndrome"
desc = "The virus causes shrinking of the host's lungs, causing severe asphyxiation. May also lead to heart attacks."
stealth = -2
resistance = -0
stage_speed = -1
transmittable = -2
level = 7
severity = 6
base_message_chance = 15
symptom_delay_min = 14
symptom_delay_max = 30
var/paralysis = FALSE
threshold_desc = "<b>Stage Speed 8:</b> Additionally synthesizes pancuronium and sodium thiopental inside the host.<br>\
<b>Transmission 8:</b> Doubles the damage caused by the symptom."
/datum/symptom/asphyxiation/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 8)
paralysis = TRUE
if(A.properties["transmittable"] >= 8)
power = 2
/datum/symptom/asphyxiation/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(3, 4)
to_chat(M, "<span class='warning'><b>[pick("Your windpipe feels thin.", "Your lungs feel small.")]</span>")
Asphyxiate_stage_3_4(M, A)
M.emote("gasp")
if(5)
to_chat(M, "<span class='userdanger'>[pick("Your lungs hurt!", "It hurts to breathe!")]</span>")
Asphyxiate(M, A)
M.emote("gasp")
if(M.getOxyLoss() >= 120)
M.visible_message("<span class='warning'>[M] stops breathing, as if their lungs have totally collapsed!</span>")
Asphyxiate_death(M, A)
return
/datum/symptom/asphyxiation/proc/Asphyxiate_stage_3_4(mob/living/M, datum/disease/advance/A)
var/get_damage = rand(10,15) * power
M.adjustOxyLoss(get_damage)
return 1
/datum/symptom/asphyxiation/proc/Asphyxiate(mob/living/M, datum/disease/advance/A)
var/get_damage = rand(15,21) * power
M.adjustOxyLoss(get_damage)
if(paralysis)
M.reagents.add_reagent_list(list(/datum/reagent/toxin/pancuronium = 3, /datum/reagent/toxin/sodium_thiopental = 3))
return 1
/datum/symptom/asphyxiation/proc/Asphyxiate_death(mob/living/M, datum/disease/advance/A)
var/get_damage = rand(25,35) * power
M.adjustOxyLoss(get_damage)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, get_damage/2)
return 1
/*
//////////////////////////////////////
Choking
Very very noticable.
Lowers resistance.
Decreases stage speed.
Decreases transmittablity tremendously.
Moderate Level.
Bonus
Inflicts spikes of oxyloss
//////////////////////////////////////
*/
/datum/symptom/choking
name = "Choking"
desc = "The virus causes inflammation of the host's air conduits, leading to intermittent choking."
stealth = -3
resistance = -2
stage_speed = -2
transmittable = -4
level = 3
severity = 3
base_message_chance = 15
symptom_delay_min = 10
symptom_delay_max = 30
threshold_desc = "<b>Stage Speed 8:</b> Causes choking more frequently.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/choking/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 8)
symptom_delay_min = 7
symptom_delay_max = 24
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
/datum/symptom/choking/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("You're having difficulty breathing.", "Your breathing becomes heavy.")]</span>")
if(3, 4)
if(!suppress_warning)
to_chat(M, "<span class='warning'>[pick("Your windpipe feels like a straw.", "Your breathing becomes tremendously difficult.")]</span>")
else
to_chat(M, "<span class='warning'>You feel very [pick("dizzy","woozy","faint")].</span>") //fake bloodloss messages
Choke_stage_3_4(M, A)
M.emote("gasp")
else
to_chat(M, "<span class='userdanger'>[pick("You're choking!", "You can't breathe!")]</span>")
Choke(M, A)
M.emote("gasp")
/datum/symptom/choking/proc/Choke_stage_3_4(mob/living/M, datum/disease/advance/A)
M.adjustOxyLoss(rand(6,13))
return 1
/datum/symptom/choking/proc/Choke(mob/living/M, datum/disease/advance/A)
M.adjustOxyLoss(rand(10,18))
return 1
/*
//////////////////////////////////////
Asphyxiation
Very very noticable.
Decreases stage speed.
Decreases transmittablity.
Bonus
Inflicts large spikes of oxyloss
Introduces Asphyxiating drugs to the system
Causes cardiac arrest on dying victims.
//////////////////////////////////////
*/
/datum/symptom/asphyxiation
name = "Acute respiratory distress syndrome"
desc = "The virus causes shrinking of the host's lungs, causing severe asphyxiation. May also lead to heart attacks."
stealth = -2
resistance = -0
stage_speed = -1
transmittable = -2
level = 7
severity = 6
base_message_chance = 15
symptom_delay_min = 14
symptom_delay_max = 30
var/paralysis = FALSE
threshold_desc = "<b>Stage Speed 8:</b> Additionally synthesizes pancuronium and sodium thiopental inside the host.<br>\
<b>Transmission 8:</b> Doubles the damage caused by the symptom."
/datum/symptom/asphyxiation/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 8)
paralysis = TRUE
if(A.properties["transmittable"] >= 8)
power = 2
/datum/symptom/asphyxiation/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(3, 4)
to_chat(M, "<span class='warning'><b>[pick("Your windpipe feels thin.", "Your lungs feel small.")]</span>")
Asphyxiate_stage_3_4(M, A)
M.emote("gasp")
if(5)
to_chat(M, "<span class='userdanger'>[pick("Your lungs hurt!", "It hurts to breathe!")]</span>")
Asphyxiate(M, A)
M.emote("gasp")
if(M.getOxyLoss() >= 120)
M.visible_message("<span class='warning'>[M] stops breathing, as if their lungs have totally collapsed!</span>")
Asphyxiate_death(M, A)
return
/datum/symptom/asphyxiation/proc/Asphyxiate_stage_3_4(mob/living/M, datum/disease/advance/A)
var/get_damage = rand(10,15) * power
M.adjustOxyLoss(get_damage)
return 1
/datum/symptom/asphyxiation/proc/Asphyxiate(mob/living/M, datum/disease/advance/A)
var/get_damage = rand(15,21) * power
M.adjustOxyLoss(get_damage)
if(paralysis)
M.reagents.add_reagent_list(list(/datum/reagent/toxin/pancuronium = 3, /datum/reagent/toxin/sodium_thiopental = 3))
return 1
/datum/symptom/asphyxiation/proc/Asphyxiate_death(mob/living/M, datum/disease/advance/A)
var/get_damage = rand(25,35) * power
M.adjustOxyLoss(get_damage)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, get_damage/2)
return 1
@@ -1,61 +1,61 @@
/*
//////////////////////////////////////
Confusion
Little bit hidden.
Lowers resistance.
Decreases stage speed.
Not very transmissibile.
Intense Level.
Bonus
Makes the affected mob be confused for short periods of time.
//////////////////////////////////////
*/
/datum/symptom/confusion
name = "Confusion"
desc = "The virus interferes with the proper function of the neural system, leading to bouts of confusion and erratic movement."
stealth = 1
resistance = -1
stage_speed = -3
transmittable = 0
level = 4
severity = 2
base_message_chance = 25
symptom_delay_min = 10
symptom_delay_max = 30
var/brain_damage = FALSE
threshold_desc = "<b>Resistance 6:</b> Causes brain damage over time.<br>\
<b>Transmission 6:</b> Increases confusion duration.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/confusion/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["resistance"] >= 6)
brain_damage = TRUE
if(A.properties["transmittable"] >= 6)
power = 1.5
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
/datum/symptom/confusion/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("Your head hurts.", "Your mind blanks for a moment.")]</span>")
else
to_chat(M, "<span class='userdanger'>You can't think straight!</span>")
M.confused = min(100 * power, M.confused + 8)
if(brain_damage)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3 * power, 80)
M.updatehealth()
return
/*
//////////////////////////////////////
Confusion
Little bit hidden.
Lowers resistance.
Decreases stage speed.
Not very transmissibile.
Intense Level.
Bonus
Makes the affected mob be confused for short periods of time.
//////////////////////////////////////
*/
/datum/symptom/confusion
name = "Confusion"
desc = "The virus interferes with the proper function of the neural system, leading to bouts of confusion and erratic movement."
stealth = 1
resistance = -1
stage_speed = -3
transmittable = 0
level = 4
severity = 2
base_message_chance = 25
symptom_delay_min = 10
symptom_delay_max = 30
var/brain_damage = FALSE
threshold_desc = "<b>Resistance 6:</b> Causes brain damage over time.<br>\
<b>Transmission 6:</b> Increases confusion duration.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/confusion/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["resistance"] >= 6)
brain_damage = TRUE
if(A.properties["transmittable"] >= 6)
power = 1.5
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
/datum/symptom/confusion/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("Your head hurts.", "Your mind blanks for a moment.")]</span>")
else
to_chat(M, "<span class='userdanger'>You can't think straight!</span>")
M.confused = min(100 * power, M.confused + 8)
if(brain_damage)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3 * power, 80)
M.updatehealth()
return
+75 -75
View File
@@ -1,75 +1,75 @@
/*
//////////////////////////////////////
Coughing
Noticable.
Little Resistance.
Doesn't increase stage speed much.
Transmissibile.
Low Level.
BONUS
Will force the affected mob to drop small items!
//////////////////////////////////////
*/
/datum/symptom/cough
name = "Cough"
desc = "The virus irritates the throat of the host, causing occasional coughing."
stealth = -1
resistance = 3
stage_speed = 1
transmittable = 2
level = 1
severity = 1
base_message_chance = 15
symptom_delay_min = 2
symptom_delay_max = 15
var/infective = FALSE
threshold_desc = "<b>Resistance 3:</b> Host will drop small items when coughing.<br>\
<b>Resistance 10:</b> Occasionally causes coughing fits that stun the host.<br>\
<b>Stage Speed 6:</b> Increases cough frequency.<br>\
<b>If Airborne:</b> Coughing will infect bystanders.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/cough/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
if(A.spread_flags &= DISEASE_SPREAD_AIRBORNE) //infect bystanders
infective = TRUE
if(A.properties["resistance"] >= 3) //strong enough to drop items
power = 1.5
if(A.properties["resistance"] >= 10) //strong enough to stun (rarely)
power = 2
if(A.properties["stage_rate"] >= 6) //cough more often
symptom_delay_max = 10
/datum/symptom/cough/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span notice='warning'>[pick("You swallow excess mucus.", "You lightly cough.")]</span>")
else
M.emote("cough")
if(power >= 1.5)
var/obj/item/I = M.get_active_held_item()
if(I && I.w_class == WEIGHT_CLASS_TINY)
M.dropItemToGround(I)
if(power >= 2 && prob(10))
to_chat(M, "<span notice='userdanger'>[pick("You have a coughing fit!", "You can't stop coughing!")]</span>")
M.Stun(20)
M.emote("cough")
addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 6)
addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 12)
addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 18)
if(infective && M.CanSpreadAirborneDisease())
A.spread(1)
/*
//////////////////////////////////////
Coughing
Noticable.
Little Resistance.
Doesn't increase stage speed much.
Transmissibile.
Low Level.
BONUS
Will force the affected mob to drop small items!
//////////////////////////////////////
*/
/datum/symptom/cough
name = "Cough"
desc = "The virus irritates the throat of the host, causing occasional coughing."
stealth = -1
resistance = 3
stage_speed = 1
transmittable = 2
level = 1
severity = 1
base_message_chance = 15
symptom_delay_min = 2
symptom_delay_max = 15
var/infective = FALSE
threshold_desc = "<b>Resistance 3:</b> Host will drop small items when coughing.<br>\
<b>Resistance 10:</b> Occasionally causes coughing fits that stun the host.<br>\
<b>Stage Speed 6:</b> Increases cough frequency.<br>\
<b>If Airborne:</b> Coughing will infect bystanders.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/cough/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
if(A.spread_flags &= DISEASE_SPREAD_AIRBORNE) //infect bystanders
infective = TRUE
if(A.properties["resistance"] >= 3) //strong enough to drop items
power = 1.5
if(A.properties["resistance"] >= 10) //strong enough to stun (rarely)
power = 2
if(A.properties["stage_rate"] >= 6) //cough more often
symptom_delay_max = 10
/datum/symptom/cough/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span notice='warning'>[pick("You swallow excess mucus.", "You lightly cough.")]</span>")
else
M.emote("cough")
if(power >= 1.5)
var/obj/item/I = M.get_active_held_item()
if(I && I.w_class == WEIGHT_CLASS_TINY)
M.dropItemToGround(I)
if(power >= 2 && prob(10))
to_chat(M, "<span notice='userdanger'>[pick("You have a coughing fit!", "You can't stop coughing!")]</span>")
M.Stun(20)
M.emote("cough")
addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 6)
addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 12)
addtimer(CALLBACK(M, /mob/.proc/emote, "cough"), 18)
if(infective && M.CanSpreadAirborneDisease())
A.spread(1)
@@ -1,59 +1,59 @@
/*
//////////////////////////////////////
Deafness
Slightly noticable.
Lowers resistance.
Decreases stage speed slightly.
Decreases transmittablity.
Intense Level.
Bonus
Causes intermittent loss of hearing.
//////////////////////////////////////
*/
/datum/symptom/deafness
name = "Deafness"
desc = "The virus causes inflammation of the eardrums, causing intermittent deafness."
stealth = -1
resistance = -2
stage_speed = -1
transmittable = -3
level = 4
severity = 4
base_message_chance = 100
symptom_delay_min = 25
symptom_delay_max = 80
threshold_desc = "<b>Resistance 9:</b> Causes permanent deafness, instead of intermittent.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/deafness/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
if(A.properties["resistance"] >= 9) //permanent deafness
power = 2
/datum/symptom/deafness/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
switch(A.stage)
if(3, 4)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>")
if(5)
if(power > 2)
var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS)
if(istype(ears) && ears.damage < ears.maxHealth)
to_chat(M, "<span class='userdanger'>Your ears pop painfully and start bleeding!</span>")
ears.damage = max(ears.damage, ears.maxHealth)
M.emote("scream")
else
to_chat(M, "<span class='userdanger'>Your ears pop and begin ringing loudly!</span>")
M.minimumDeafTicks(20)
/*
//////////////////////////////////////
Deafness
Slightly noticable.
Lowers resistance.
Decreases stage speed slightly.
Decreases transmittablity.
Intense Level.
Bonus
Causes intermittent loss of hearing.
//////////////////////////////////////
*/
/datum/symptom/deafness
name = "Deafness"
desc = "The virus causes inflammation of the eardrums, causing intermittent deafness."
stealth = -1
resistance = -2
stage_speed = -1
transmittable = -3
level = 4
severity = 4
base_message_chance = 100
symptom_delay_min = 25
symptom_delay_max = 80
threshold_desc = "<b>Resistance 9:</b> Causes permanent deafness, instead of intermittent.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/deafness/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
if(A.properties["resistance"] >= 9) //permanent deafness
power = 2
/datum/symptom/deafness/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
switch(A.stage)
if(3, 4)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>")
if(5)
if(power > 2)
var/obj/item/organ/ears/ears = M.getorganslot(ORGAN_SLOT_EARS)
if(istype(ears) && ears.damage < ears.maxHealth)
to_chat(M, "<span class='userdanger'>Your ears pop painfully and start bleeding!</span>")
ears.damage = max(ears.damage, ears.maxHealth)
M.emote("scream")
else
to_chat(M, "<span class='userdanger'>Your ears pop and begin ringing loudly!</span>")
M.minimumDeafTicks(20)
+52 -52
View File
@@ -1,53 +1,53 @@
/*
//////////////////////////////////////
Dizziness
Hidden.
Lowers resistance considerably.
Decreases stage speed.
Reduced transmittability
Intense Level.
Bonus
Shakes the affected mob's screen for short periods.
//////////////////////////////////////
*/
/datum/symptom/dizzy // Not the egg
name = "Dizziness"
desc = "The virus causes inflammation of the vestibular system, leading to bouts of dizziness."
resistance = -2
stage_speed = -3
transmittable = -1
level = 4
severity = 2
base_message_chance = 50
symptom_delay_min = 15
symptom_delay_max = 40
threshold_desc = "<b>Transmission 6:</b> Also causes druggy vision.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/dizzy/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
if(A.properties["transmittable"] >= 6) //druggy
power = 2
/datum/symptom/dizzy/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("You feel dizzy.", "Your head spins.")]</span>")
else
to_chat(M, "<span class='userdanger'>A wave of dizziness washes over you!</span>")
M.Dizzy(5)
if(power >= 2)
/*
//////////////////////////////////////
Dizziness
Hidden.
Lowers resistance considerably.
Decreases stage speed.
Reduced transmittability
Intense Level.
Bonus
Shakes the affected mob's screen for short periods.
//////////////////////////////////////
*/
/datum/symptom/dizzy // Not the egg
name = "Dizziness"
desc = "The virus causes inflammation of the vestibular system, leading to bouts of dizziness."
resistance = -2
stage_speed = -3
transmittable = -1
level = 4
severity = 2
base_message_chance = 50
symptom_delay_min = 15
symptom_delay_max = 40
threshold_desc = "<b>Transmission 6:</b> Also causes druggy vision.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/dizzy/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
if(A.properties["transmittable"] >= 6) //druggy
power = 2
/datum/symptom/dizzy/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("You feel dizzy.", "Your head spins.")]</span>")
else
to_chat(M, "<span class='userdanger'>A wave of dizziness washes over you!</span>")
M.Dizzy(5)
if(power >= 2)
M.set_drugginess(5)
+60 -60
View File
@@ -1,60 +1,60 @@
/*
//////////////////////////////////////
Fever
No change to hidden.
Increases resistance.
Increases stage speed.
Little transmittable.
Low level.
Bonus
Heats up your body.
//////////////////////////////////////
*/
/datum/symptom/fever
name = "Fever"
desc = "The virus causes a febrile response from the host, raising its body temperature."
stealth = 0
resistance = 3
stage_speed = 3
transmittable = 2
level = 2
severity = 2
base_message_chance = 20
symptom_delay_min = 10
symptom_delay_max = 30
var/unsafe = FALSE //over the heat threshold
threshold_desc = "<b>Resistance 5:</b> Increases fever intensity, fever can overheat and harm the host.<br>\
<b>Resistance 10:</b> Further increases fever intensity."
/datum/symptom/fever/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["resistance"] >= 5) //dangerous fever
power = 1.5
unsafe = TRUE
if(A.properties["resistance"] >= 10)
power = 2.5
/datum/symptom/fever/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
if(!unsafe || A.stage < 4)
to_chat(M, "<span class='warning'>[pick("You feel hot.", "You feel like you're burning.")]</span>")
else
to_chat(M, "<span class='userdanger'>[pick("You feel too hot.", "You feel like your blood is boiling.")]</span>")
if(M.bodytemperature < BODYTEMP_HEAT_DAMAGE_LIMIT || unsafe)
Heat(M, A)
/datum/symptom/fever/proc/Heat(mob/living/M, datum/disease/advance/A)
var/get_heat = 6 * power
if(!unsafe)
M.adjust_bodytemperature(get_heat * A.stage, 0, BODYTEMP_HEAT_DAMAGE_LIMIT - 1)
else
M.adjust_bodytemperature(get_heat * A.stage)
return 1
/*
//////////////////////////////////////
Fever
No change to hidden.
Increases resistance.
Increases stage speed.
Little transmittable.
Low level.
Bonus
Heats up your body.
//////////////////////////////////////
*/
/datum/symptom/fever
name = "Fever"
desc = "The virus causes a febrile response from the host, raising its body temperature."
stealth = 0
resistance = 3
stage_speed = 3
transmittable = 2
level = 2
severity = 2
base_message_chance = 20
symptom_delay_min = 10
symptom_delay_max = 30
var/unsafe = FALSE //over the heat threshold
threshold_desc = "<b>Resistance 5:</b> Increases fever intensity, fever can overheat and harm the host.<br>\
<b>Resistance 10:</b> Further increases fever intensity."
/datum/symptom/fever/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["resistance"] >= 5) //dangerous fever
power = 1.5
unsafe = TRUE
if(A.properties["resistance"] >= 10)
power = 2.5
/datum/symptom/fever/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
if(!unsafe || A.stage < 4)
to_chat(M, "<span class='warning'>[pick("You feel hot.", "You feel like you're burning.")]</span>")
else
to_chat(M, "<span class='userdanger'>[pick("You feel too hot.", "You feel like your blood is boiling.")]</span>")
if(M.bodytemperature < BODYTEMP_HEAT_DAMAGE_LIMIT || unsafe)
Heat(M, A)
/datum/symptom/fever/proc/Heat(mob/living/M, datum/disease/advance/A)
var/get_heat = 6 * power
if(!unsafe)
M.adjust_bodytemperature(get_heat * A.stage, 0, BODYTEMP_HEAT_DAMAGE_LIMIT - 1)
else
M.adjust_bodytemperature(get_heat * A.stage)
return 1
@@ -1,130 +1,130 @@
/*
//////////////////////////////////////
Necrotizing Fasciitis (AKA Flesh-Eating Disease)
Very very noticable.
Lowers resistance tremendously.
No changes to stage speed.
Decreases transmittablity temrendously.
Fatal Level.
Bonus
Deals brute damage over time.
//////////////////////////////////////
*/
/datum/symptom/flesh_eating
name = "Necrotizing Fasciitis"
desc = "The virus aggressively attacks body cells, necrotizing tissues and organs."
stealth = -3
resistance = -4
stage_speed = 0
transmittable = -4
level = 6
severity = 5
base_message_chance = 50
symptom_delay_min = 15
symptom_delay_max = 60
var/bleed = FALSE
var/pain = FALSE
threshold_desc = "<b>Resistance 7:</b> Host will bleed profusely during necrosis.<br>\
<b>Transmission 8:</b> Causes extreme pain to the host, weakening it."
/datum/symptom/flesh_eating/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["resistance"] >= 7) //extra bleeding
bleed = TRUE
if(A.properties["transmittable"] >= 8) //extra stamina damage
pain = TRUE
/datum/symptom/flesh_eating/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(2,3)
if(prob(base_message_chance))
to_chat(M, "<span class='warning'>[pick("You feel a sudden pain across your body.", "Drops of blood appear suddenly on your skin.")]</span>")
if(4,5)
to_chat(M, "<span class='userdanger'>[pick("You cringe as a violent pain takes over your body.", "It feels like your body is eating itself inside out.", "IT HURTS.")]</span>")
Flesheat(M, A)
/datum/symptom/flesh_eating/proc/Flesheat(mob/living/M, datum/disease/advance/A)
var/get_damage = rand(15,25) * power
M.adjustBruteLoss(get_damage)
if(pain)
M.adjustStaminaLoss(get_damage)
if(bleed)
if(ishuman(M))
var/mob/living/carbon/human/H = M
H.bleed_rate += 5 * power
return 1
/*
//////////////////////////////////////
Autophagocytosis (AKA Programmed mass cell death)
Very noticable.
Lowers resistance.
Fast stage speed.
Decreases transmittablity.
Fatal Level.
Bonus
Deals brute damage over time.
//////////////////////////////////////
*/
/datum/symptom/flesh_death
name = "Autophagocytosis Necrosis"
desc = "The virus rapidly consumes infected cells, leading to heavy and widespread damage."
stealth = -2
resistance = -2
stage_speed = 1
transmittable = -2
level = 7
severity = 6
base_message_chance = 50
symptom_delay_min = 3
symptom_delay_max = 6
var/chems = FALSE
var/zombie = FALSE
threshold_desc = "<b>Stage Speed 7:</b> Synthesizes Heparin and Lipolicide inside the host, causing increased bleeding and hunger.<br>\
<b>Stealth 5:</b> The symptom remains hidden until active."
/datum/symptom/flesh_death/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 5)
suppress_warning = TRUE
if(A.properties["stage_rate"] >= 7) //bleeding and hunger
chems = TRUE
/datum/symptom/flesh_death/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(2,3)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("You feel your body break apart.", "Your skin rubs off like dust.")]</span>")
if(4,5)
if(prob(base_message_chance / 2)) //reduce spam
to_chat(M, "<span class='userdanger'>[pick("You feel your muscles weakening.", "Some of your skin detaches itself.", "You feel sandy.")]</span>")
Flesh_death(M, A)
/datum/symptom/flesh_death/proc/Flesh_death(mob/living/M, datum/disease/advance/A)
var/get_damage = rand(6,10)
M.adjustBruteLoss(get_damage)
if(chems)
M.reagents.add_reagent_list(list(/datum/reagent/toxin/heparin = 2, /datum/reagent/toxin/lipolicide = 2))
if(zombie)
M.reagents.add_reagent(/datum/reagent/romerol, 1)
/*
//////////////////////////////////////
Necrotizing Fasciitis (AKA Flesh-Eating Disease)
Very very noticable.
Lowers resistance tremendously.
No changes to stage speed.
Decreases transmittablity temrendously.
Fatal Level.
Bonus
Deals brute damage over time.
//////////////////////////////////////
*/
/datum/symptom/flesh_eating
name = "Necrotizing Fasciitis"
desc = "The virus aggressively attacks body cells, necrotizing tissues and organs."
stealth = -3
resistance = -4
stage_speed = 0
transmittable = -4
level = 6
severity = 5
base_message_chance = 50
symptom_delay_min = 15
symptom_delay_max = 60
var/bleed = FALSE
var/pain = FALSE
threshold_desc = "<b>Resistance 7:</b> Host will bleed profusely during necrosis.<br>\
<b>Transmission 8:</b> Causes extreme pain to the host, weakening it."
/datum/symptom/flesh_eating/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["resistance"] >= 7) //extra bleeding
bleed = TRUE
if(A.properties["transmittable"] >= 8) //extra stamina damage
pain = TRUE
/datum/symptom/flesh_eating/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(2,3)
if(prob(base_message_chance))
to_chat(M, "<span class='warning'>[pick("You feel a sudden pain across your body.", "Drops of blood appear suddenly on your skin.")]</span>")
if(4,5)
to_chat(M, "<span class='userdanger'>[pick("You cringe as a violent pain takes over your body.", "It feels like your body is eating itself inside out.", "IT HURTS.")]</span>")
Flesheat(M, A)
/datum/symptom/flesh_eating/proc/Flesheat(mob/living/M, datum/disease/advance/A)
var/get_damage = rand(15,25) * power
M.adjustBruteLoss(get_damage)
if(pain)
M.adjustStaminaLoss(get_damage)
if(bleed)
if(ishuman(M))
var/mob/living/carbon/human/H = M
H.bleed_rate += 5 * power
return 1
/*
//////////////////////////////////////
Autophagocytosis (AKA Programmed mass cell death)
Very noticable.
Lowers resistance.
Fast stage speed.
Decreases transmittablity.
Fatal Level.
Bonus
Deals brute damage over time.
//////////////////////////////////////
*/
/datum/symptom/flesh_death
name = "Autophagocytosis Necrosis"
desc = "The virus rapidly consumes infected cells, leading to heavy and widespread damage."
stealth = -2
resistance = -2
stage_speed = 1
transmittable = -2
level = 7
severity = 6
base_message_chance = 50
symptom_delay_min = 3
symptom_delay_max = 6
var/chems = FALSE
var/zombie = FALSE
threshold_desc = "<b>Stage Speed 7:</b> Synthesizes Heparin and Lipolicide inside the host, causing increased bleeding and hunger.<br>\
<b>Stealth 5:</b> The symptom remains hidden until active."
/datum/symptom/flesh_death/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 5)
suppress_warning = TRUE
if(A.properties["stage_rate"] >= 7) //bleeding and hunger
chems = TRUE
/datum/symptom/flesh_death/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(2,3)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("You feel your body break apart.", "Your skin rubs off like dust.")]</span>")
if(4,5)
if(prob(base_message_chance / 2)) //reduce spam
to_chat(M, "<span class='userdanger'>[pick("You feel your muscles weakening.", "Some of your skin detaches itself.", "You feel sandy.")]</span>")
Flesh_death(M, A)
/datum/symptom/flesh_death/proc/Flesh_death(mob/living/M, datum/disease/advance/A)
var/get_damage = rand(6,10)
M.adjustBruteLoss(get_damage)
if(chems)
M.reagents.add_reagent_list(list(/datum/reagent/toxin/heparin = 2, /datum/reagent/toxin/lipolicide = 2))
if(zombie)
M.reagents.add_reagent(/datum/reagent/romerol, 1)
return 1
@@ -1,78 +1,78 @@
/*
//////////////////////////////////////
DNA Saboteur
Very noticable.
Lowers resistance tremendously.
No changes to stage speed.
Decreases transmittablity tremendously.
Fatal Level.
Bonus
Cleans the DNA of a person and then randomly gives them a trait.
//////////////////////////////////////
*/
/datum/symptom/genetic_mutation
name = "Deoxyribonucleic Acid Saboteur"
desc = "The virus bonds with the DNA of the host, causing damaging mutations until removed."
stealth = -2
resistance = -3
stage_speed = 0
transmittable = -3
level = 6
severity = 4
var/list/possible_mutations
var/archived_dna = null
base_message_chance = 50
symptom_delay_min = 60
symptom_delay_max = 120
var/no_reset = FALSE
threshold_desc = "<b>Resistance 8:</b> Causes two harmful mutations at once.<br>\
<b>Stage Speed 10:</b> Increases mutation frequency.<br>\
<b>Stealth 5:</b> The mutations persist even if the virus is cured."
/datum/symptom/genetic_mutation/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/C = A.affected_mob
if(!C.has_dna())
return
switch(A.stage)
if(4, 5)
to_chat(C, "<span class='warning'>[pick("Your skin feels itchy.", "You feel light headed.")]</span>")
C.dna.remove_mutation_group(possible_mutations)
for(var/i in 1 to power)
C.randmut(possible_mutations)
// Archive their DNA before they were infected.
/datum/symptom/genetic_mutation/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 5) //don't restore dna after curing
no_reset = TRUE
if(A.properties["stage_rate"] >= 10) //mutate more often
symptom_delay_min = 20
symptom_delay_max = 60
if(A.properties["resistance"] >= 8) //mutate twice
power = 2
possible_mutations = (GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.all_mutations[RACEMUT]
var/mob/living/carbon/M = A.affected_mob
if(M)
if(!M.has_dna())
return
archived_dna = M.dna.mutation_index
// Give them back their old DNA when cured.
/datum/symptom/genetic_mutation/End(datum/disease/advance/A)
if(!..())
return
if(!no_reset)
var/mob/living/carbon/M = A.affected_mob
if(M && archived_dna)
if(!M.has_dna())
return
M.dna.mutation_index = archived_dna
M.domutcheck()
/*
//////////////////////////////////////
DNA Saboteur
Very noticable.
Lowers resistance tremendously.
No changes to stage speed.
Decreases transmittablity tremendously.
Fatal Level.
Bonus
Cleans the DNA of a person and then randomly gives them a trait.
//////////////////////////////////////
*/
/datum/symptom/genetic_mutation
name = "Deoxyribonucleic Acid Saboteur"
desc = "The virus bonds with the DNA of the host, causing damaging mutations until removed."
stealth = -2
resistance = -3
stage_speed = 0
transmittable = -3
level = 6
severity = 4
var/list/possible_mutations
var/archived_dna = null
base_message_chance = 50
symptom_delay_min = 60
symptom_delay_max = 120
var/no_reset = FALSE
threshold_desc = "<b>Resistance 8:</b> Causes two harmful mutations at once.<br>\
<b>Stage Speed 10:</b> Increases mutation frequency.<br>\
<b>Stealth 5:</b> The mutations persist even if the virus is cured."
/datum/symptom/genetic_mutation/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/C = A.affected_mob
if(!C.has_dna())
return
switch(A.stage)
if(4, 5)
to_chat(C, "<span class='warning'>[pick("Your skin feels itchy.", "You feel light headed.")]</span>")
C.dna.remove_mutation_group(possible_mutations)
for(var/i in 1 to power)
C.randmut(possible_mutations)
// Archive their DNA before they were infected.
/datum/symptom/genetic_mutation/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 5) //don't restore dna after curing
no_reset = TRUE
if(A.properties["stage_rate"] >= 10) //mutate more often
symptom_delay_min = 20
symptom_delay_max = 60
if(A.properties["resistance"] >= 8) //mutate twice
power = 2
possible_mutations = (GLOB.bad_mutations | GLOB.not_good_mutations) - GLOB.all_mutations[RACEMUT]
var/mob/living/carbon/M = A.affected_mob
if(M)
if(!M.has_dna())
return
archived_dna = M.dna.mutation_index
// Give them back their old DNA when cured.
/datum/symptom/genetic_mutation/End(datum/disease/advance/A)
if(!..())
return
if(!no_reset)
var/mob/living/carbon/M = A.affected_mob
if(M && archived_dna)
if(!M.has_dna())
return
M.dna.mutation_index = archived_dna
M.domutcheck()
@@ -1,65 +1,65 @@
/*
//////////////////////////////////////
Hallucigen
Very noticable.
Lowers resistance considerably.
Decreases stage speed.
Reduced transmittable.
Critical Level.
Bonus
Makes the affected mob be hallucinated for short periods of time.
//////////////////////////////////////
*/
/datum/symptom/hallucigen
name = "Hallucigen"
desc = "The virus stimulates the brain, causing occasional hallucinations."
stealth = -2
resistance = -3
stage_speed = -3
transmittable = -1
level = 5
severity = 2
base_message_chance = 25
symptom_delay_min = 25
symptom_delay_max = 90
var/fake_healthy = FALSE
threshold_desc = "<b>Stage Speed 7:</b> Increases the amount of hallucinations.<br>\
<b>Stealth 4:</b> The virus mimics positive symptoms.."
/datum/symptom/hallucigen/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4) //fake good symptom messages
fake_healthy = TRUE
base_message_chance = 50
if(A.properties["stage_rate"] >= 7) //stronger hallucinations
power = 2
/datum/symptom/hallucigen/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
var/list/healthy_messages = list("Your lungs feel great.", "You realize you haven't been breathing.", "You don't feel the need to breathe.",\
"Your eyes feel great.", "You are now blinking manually.", "You don't feel the need to blink.")
switch(A.stage)
if(1, 2)
if(prob(base_message_chance))
if(!fake_healthy)
to_chat(M, "<span class='notice'>[pick("Something appears in your peripheral vision, then winks out.", "You hear a faint whisper with no source.", "Your head aches.")]</span>")
else
to_chat(M, "<span class='notice'>[pick(healthy_messages)]</span>")
if(3, 4)
if(prob(base_message_chance))
if(!fake_healthy)
to_chat(M, "<span class='danger'>[pick("Something is following you.", "You are being watched.", "You hear a whisper in your ear.", "Thumping footsteps slam toward you from nowhere.")]</span>")
else
to_chat(M, "<span class='notice'>[pick(healthy_messages)]</span>")
else
if(prob(base_message_chance))
to_chat(M, "<span class='userdanger'>[pick("Oh, your head...", "Your head pounds.", "They're everywhere! Run!", "Something in the shadows...")]</span>")
M.hallucination += (45 * power)
/*
//////////////////////////////////////
Hallucigen
Very noticable.
Lowers resistance considerably.
Decreases stage speed.
Reduced transmittable.
Critical Level.
Bonus
Makes the affected mob be hallucinated for short periods of time.
//////////////////////////////////////
*/
/datum/symptom/hallucigen
name = "Hallucigen"
desc = "The virus stimulates the brain, causing occasional hallucinations."
stealth = -2
resistance = -3
stage_speed = -3
transmittable = -1
level = 5
severity = 2
base_message_chance = 25
symptom_delay_min = 25
symptom_delay_max = 90
var/fake_healthy = FALSE
threshold_desc = "<b>Stage Speed 7:</b> Increases the amount of hallucinations.<br>\
<b>Stealth 4:</b> The virus mimics positive symptoms.."
/datum/symptom/hallucigen/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4) //fake good symptom messages
fake_healthy = TRUE
base_message_chance = 50
if(A.properties["stage_rate"] >= 7) //stronger hallucinations
power = 2
/datum/symptom/hallucigen/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
var/list/healthy_messages = list("Your lungs feel great.", "You realize you haven't been breathing.", "You don't feel the need to breathe.",\
"Your eyes feel great.", "You are now blinking manually.", "You don't feel the need to blink.")
switch(A.stage)
if(1, 2)
if(prob(base_message_chance))
if(!fake_healthy)
to_chat(M, "<span class='notice'>[pick("Something appears in your peripheral vision, then winks out.", "You hear a faint whisper with no source.", "Your head aches.")]</span>")
else
to_chat(M, "<span class='notice'>[pick(healthy_messages)]</span>")
if(3, 4)
if(prob(base_message_chance))
if(!fake_healthy)
to_chat(M, "<span class='danger'>[pick("Something is following you.", "You are being watched.", "You hear a whisper in your ear.", "Thumping footsteps slam toward you from nowhere.")]</span>")
else
to_chat(M, "<span class='notice'>[pick(healthy_messages)]</span>")
else
if(prob(base_message_chance))
to_chat(M, "<span class='userdanger'>[pick("Oh, your head...", "Your head pounds.", "They're everywhere! Run!", "Something in the shadows...")]</span>")
M.hallucination += (45 * power)
@@ -1,60 +1,60 @@
/*
//////////////////////////////////////
Headache
Noticable.
Highly resistant.
Increases stage speed.
Not transmittable.
Low Level.
BONUS
Displays an annoying message!
Should be used for buffing your disease.
//////////////////////////////////////
*/
/datum/symptom/headache
name = "Headache"
desc = "The virus causes inflammation inside the brain, causing constant headaches."
stealth = -1
resistance = 4
stage_speed = 2
transmittable = 0
level = 1
severity = 1
base_message_chance = 100
symptom_delay_min = 15
symptom_delay_max = 30
threshold_desc = "<b>Stage Speed 6:</b> Headaches will cause severe pain, that weakens the host.<br>\
<b>Stage Speed 9:</b> Headaches become less frequent but far more intense, preventing any action from the host.<br>\
<b>Stealth 4:</b> Reduces headache frequency until later stages."
/datum/symptom/headache/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4)
base_message_chance = 50
if(A.properties["stage_rate"] >= 6) //severe pain
power = 2
if(A.properties["stage_rate"] >= 9) //cluster headaches
symptom_delay_min = 30
symptom_delay_max = 60
power = 3
/datum/symptom/headache/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
if(power < 2)
if(prob(base_message_chance) || A.stage >=4)
to_chat(M, "<span class='warning'>[pick("Your head hurts.", "Your head pounds.")]</span>")
if(power >= 2 && A.stage >= 4)
to_chat(M, "<span class='warning'>[pick("Your head hurts a lot.", "Your head pounds incessantly.")]</span>")
M.adjustStaminaLoss(25)
if(power >= 3 && A.stage >= 5)
to_chat(M, "<span class='userdanger'>[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]</span>")
/*
//////////////////////////////////////
Headache
Noticable.
Highly resistant.
Increases stage speed.
Not transmittable.
Low Level.
BONUS
Displays an annoying message!
Should be used for buffing your disease.
//////////////////////////////////////
*/
/datum/symptom/headache
name = "Headache"
desc = "The virus causes inflammation inside the brain, causing constant headaches."
stealth = -1
resistance = 4
stage_speed = 2
transmittable = 0
level = 1
severity = 1
base_message_chance = 100
symptom_delay_min = 15
symptom_delay_max = 30
threshold_desc = "<b>Stage Speed 6:</b> Headaches will cause severe pain, that weakens the host.<br>\
<b>Stage Speed 9:</b> Headaches become less frequent but far more intense, preventing any action from the host.<br>\
<b>Stealth 4:</b> Reduces headache frequency until later stages."
/datum/symptom/headache/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4)
base_message_chance = 50
if(A.properties["stage_rate"] >= 6) //severe pain
power = 2
if(A.properties["stage_rate"] >= 9) //cluster headaches
symptom_delay_min = 30
symptom_delay_max = 60
power = 3
/datum/symptom/headache/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
if(power < 2)
if(prob(base_message_chance) || A.stage >=4)
to_chat(M, "<span class='warning'>[pick("Your head hurts.", "Your head pounds.")]</span>")
if(power >= 2 && A.stage >= 4)
to_chat(M, "<span class='warning'>[pick("Your head hurts a lot.", "Your head pounds incessantly.")]</span>")
M.adjustStaminaLoss(25)
if(power >= 3 && A.stage >= 5)
to_chat(M, "<span class='userdanger'>[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]</span>")
M.Stun(35)
+485 -485
View File
@@ -1,485 +1,485 @@
/datum/symptom/heal
name = "Basic Healing (does nothing)" //warning for adminspawn viruses
desc = "You should not be seeing this."
stealth = 0
resistance = 0
stage_speed = 0
transmittable = 0
level = 0 //not obtainable
base_message_chance = 20 //here used for the overlays
symptom_delay_min = 1
symptom_delay_max = 1
var/passive_message = "" //random message to infected but not actively healing people
threshold_desc = "<b>Stage Speed 6:</b> Doubles healing speed.<br>\
<b>Stealth 4:</b> Healing will no longer be visible to onlookers."
/datum/symptom/heal/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 6) //stronger healing
power = 2
/datum/symptom/heal/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(4, 5)
var/effectiveness = CanHeal(A)
if(!effectiveness)
if(passive_message && prob(2) && passive_message_condition(M))
to_chat(M, passive_message)
return
else
Heal(M, A, effectiveness)
return
/datum/symptom/heal/proc/CanHeal(datum/disease/advance/A)
return power
/datum/symptom/heal/proc/Heal(mob/living/M, datum/disease/advance/A, actual_power)
return TRUE
/datum/symptom/heal/proc/passive_message_condition(mob/living/M)
return TRUE
/datum/symptom/heal/starlight
name = "Starlight Condensation"
desc = "The virus reacts to direct starlight, producing regenerative chemicals. Works best against toxin-based damage."
stealth = -1
resistance = -2
stage_speed = 0
transmittable = 1
level = 6
passive_message = "<span class='notice'>You miss the feeling of starlight on your skin.</span>"
var/nearspace_penalty = 0.3
threshold_desc = "<b>Stage Speed 6:</b> Increases healing speed.<br>\
<b>Transmission 6:</b> Removes penalty for only being close to space."
/datum/symptom/heal/starlight/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["transmittable"] >= 6)
nearspace_penalty = 1
if(A.properties["stage_rate"] >= 6)
power = 2
/datum/symptom/heal/starlight/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
if(istype(get_turf(M), /turf/open/space))
return power
else
for(var/turf/T in view(M, 2))
if(istype(T, /turf/open/space))
return power * nearspace_penalty
/datum/symptom/heal/starlight/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = actual_power
if(M.getToxLoss() && prob(5))
to_chat(M, "<span class='notice'>Your skin tingles as the starlight seems to heal you.</span>")
M.adjustToxLoss(-(4 * heal_amt), forced = TRUE) //most effective on toxins
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
return 1
/datum/symptom/heal/starlight/passive_message_condition(mob/living/M)
if(M.getBruteLoss() || M.getFireLoss() || M.getToxLoss())
return TRUE
return FALSE
/datum/symptom/heal/chem
name = "Toxolysis"
stealth = 0
resistance = -2
stage_speed = 2
transmittable = -2
level = 7
var/food_conversion = FALSE
desc = "The virus rapidly breaks down any foreign chemicals in the bloodstream."
threshold_desc = "<b>Resistance 7:</b> Increases chem removal speed.<br>\
<b>Stage Speed 6:</b> Consumed chemicals nourish the host."
/datum/symptom/heal/chem/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 6)
food_conversion = TRUE
if(A.properties["resistance"] >= 7)
power = 2
/datum/symptom/heal/chem/Heal(mob/living/M, datum/disease/advance/A, actual_power)
for(var/E in M.reagents.reagent_list) //Not just toxins!
var/datum/reagent/R = E
M.reagents.remove_reagent(R.type, actual_power)
if(food_conversion)
M.nutrition += 0.3
if(prob(2))
to_chat(M, "<span class='notice'>You feel a mild warmth as your blood purifies itself.</span>")
return 1
/datum/symptom/heal/metabolism
name = "Metabolic Boost"
stealth = -1
resistance = -2
stage_speed = 2
transmittable = 1
level = 7
var/triple_metabolism = FALSE
var/reduced_hunger = FALSE
desc = "The virus causes the host's metabolism to accelerate rapidly, making them process chemicals twice as fast,\
but also causing increased hunger."
threshold_desc = "<b>Stealth 3:</b> Reduces hunger rate.<br>\
<b>Stage Speed 10:</b> Chemical metabolization is tripled instead of doubled."
/datum/symptom/heal/metabolism/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 10)
triple_metabolism = TRUE
if(A.properties["stealth"] >= 3)
reduced_hunger = TRUE
/datum/symptom/heal/metabolism/Heal(mob/living/carbon/C, datum/disease/advance/A, actual_power)
if(!istype(C))
return
C.reagents.metabolize(C, can_overdose=TRUE) //this works even without a liver; it's intentional since the virus is metabolizing by itself
if(triple_metabolism)
C.reagents.metabolize(C, can_overdose=TRUE)
C.overeatduration = max(C.overeatduration - 2, 0)
var/lost_nutrition = 9 - (reduced_hunger * 5)
C.nutrition = max(C.nutrition - (lost_nutrition * HUNGER_FACTOR), 0) //Hunger depletes at 10x the normal speed
if(prob(2))
to_chat(C, "<span class='notice'>You feel an odd gurgle in your stomach, as if it was working much faster than normal.</span>")
return 1
/datum/symptom/heal/darkness
name = "Nocturnal Regeneration"
desc = "The virus is able to mend the host's flesh when in conditions of low light, repairing physical damage. More effective against brute damage."
stealth = 2
resistance = -1
stage_speed = -2
transmittable = -1
level = 6
passive_message = "<span class='notice'>You feel tingling on your skin as light passes over it.</span>"
threshold_desc = "<b>Stage Speed 8:</b> Doubles healing speed."
/datum/symptom/heal/darkness/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 8)
power = 2
/datum/symptom/heal/darkness/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
var/light_amount = 0
if(isturf(M.loc)) //else, there's considered to be no light
var/turf/T = M.loc
light_amount = min(1,T.get_lumcount()) - 0.5
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
return power
/datum/symptom/heal/darkness/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 2 * actual_power
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
if(prob(5))
to_chat(M, "<span class='notice'>The darkness soothes and mends your wounds.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len * 0.5)) //more effective on brute
M.update_damage_overlays()
return 1
/datum/symptom/heal/darkness/passive_message_condition(mob/living/M)
if(M.getBruteLoss() || M.getFireLoss())
return TRUE
return FALSE
/datum/symptom/heal/coma
name = "Regenerative Coma"
desc = "The virus causes the host to fall into a death-like coma when severely damaged, then rapidly fixes the damage."
stealth = 0
resistance = 2
stage_speed = -3
transmittable = -2
level = 8
passive_message = "<span class='notice'>The pain from your wounds makes you feel oddly sleepy...</span>"
var/deathgasp = FALSE
var/stabilize = FALSE
var/active_coma = FALSE //to prevent multiple coma procs
threshold_desc = "<b>Stealth 2:</b> Host appears to die when falling into a coma.<br>\
<b>Resistance 4:</b> The virus also stabilizes the host while they are in critical condition.<br>\
<b>Stage Speed 7:</b> Increases healing speed."
/datum/symptom/heal/coma/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 7)
power = 1.5
if(A.properties["resistance"] >= 4)
stabilize = TRUE
if(A.properties["stealth"] >= 2)
deathgasp = TRUE
/datum/symptom/heal/coma/on_stage_change(datum/disease/advance/A) //mostly copy+pasted from the code for self-respiration's TRAIT_NOBREATH stuff
if(!..())
return FALSE
if(A.stage >= 4 && stabilize)
ADD_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
else
REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
return TRUE
/datum/symptom/heal/coma/End(datum/disease/advance/A)
if(!..())
return
REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
/datum/symptom/heal/coma/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
if(HAS_TRAIT(M, TRAIT_DEATHCOMA))
return power
else if(M.IsUnconscious() || M.stat == UNCONSCIOUS)
return power * 0.9
else if(M.stat == SOFT_CRIT)
return power * 0.5
else if(M.IsSleeping())
return power * 0.25
else if(M.getBruteLoss() + M.getFireLoss() >= 70 && !active_coma)
to_chat(M, "<span class='warning'>You feel yourself slip into a regenerative coma...</span>")
active_coma = TRUE
addtimer(CALLBACK(src, .proc/coma, M), 60)
/datum/symptom/heal/coma/proc/coma(mob/living/M)
if(deathgasp)
M.emote("deathgasp")
M.fakedeath("regenerative_coma")
M.update_stat()
M.update_canmove()
addtimer(CALLBACK(src, .proc/uncoma, M), 300)
/datum/symptom/heal/coma/proc/uncoma(mob/living/M)
if(!active_coma)
return
active_coma = FALSE
M.cure_fakedeath("regenerative_coma")
M.update_stat()
M.update_canmove()
/datum/symptom/heal/coma/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 4 * actual_power
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
if(active_coma && M.getBruteLoss() + M.getFireLoss() == 0)
uncoma(M)
return 1
/datum/symptom/heal/coma/passive_message_condition(mob/living/M)
if((M.getBruteLoss() + M.getFireLoss()) > 30)
return TRUE
return FALSE
/datum/symptom/heal/water
name = "Tissue Hydration"
desc = "The virus uses excess water inside and outside the body to repair damaged tissue cells. More effective against burns."
stealth = 0
resistance = -1
stage_speed = 0
transmittable = 1
level = 6
passive_message = "<span class='notice'>Your skin feels oddly dry...</span>"
var/absorption_coeff = 1
threshold_desc = "<b>Resistance 5:</b> Water is consumed at a much slower rate.<br>\
<b>Stage Speed 7:</b> Increases healing speed."
/datum/symptom/heal/water/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 7)
power = 2
if(A.properties["stealth"] >= 2)
absorption_coeff = 0.25
/datum/symptom/heal/water/CanHeal(datum/disease/advance/A)
. = 0
var/mob/living/M = A.affected_mob
if(M.fire_stacks < 0)
M.fire_stacks = min(M.fire_stacks + 1 * absorption_coeff, 0)
. += power
if(M.reagents.has_reagent(/datum/reagent/water/holywater))
M.reagents.remove_reagent(/datum/reagent/water/holywater, 0.5 * absorption_coeff)
. += power * 0.75
else if(M.reagents.has_reagent(/datum/reagent/water))
M.reagents.remove_reagent(/datum/reagent/water, 0.5 * absorption_coeff)
. += power * 0.5
/datum/symptom/heal/water/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 2 * actual_power
var/list/parts = M.get_damaged_bodyparts(1,1) //more effective on burns
if(!parts.len)
return
if(prob(5))
to_chat(M, "<span class='notice'>You feel yourself absorbing the water around you to soothe your damaged skin.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len * 0.5, heal_amt/parts.len))
M.update_damage_overlays()
return 1
/datum/symptom/heal/water/passive_message_condition(mob/living/M)
if(M.getBruteLoss() || M.getFireLoss())
return TRUE
return FALSE
/datum/symptom/heal/plasma
name = "Plasma Fixation"
desc = "The virus draws plasma from the atmosphere and from inside the body to heal and stabilize body temperature."
stealth = 0
resistance = 3
stage_speed = -2
transmittable = -2
level = 8
passive_message = "<span class='notice'>You feel an odd attraction to plasma.</span>"
var/temp_rate = 1
threshold_desc = "<b>Transmission 6:</b> Increases temperature adjustment rate and heals toxin lovers.<br>\
<b>Stage Speed 7:</b> Increases healing speed."
/datum/symptom/heal/plasma/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 7)
power = 2
if(A.properties["transmittable"] >= 6)
temp_rate = 4
/datum/symptom/heal/plasma/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
var/datum/gas_mixture/environment
var/plasmamount
. = 0
if(M.loc)
environment = M.loc.return_air()
if(environment)
plasmamount = environment.gases[/datum/gas/plasma]
if(plasmamount && plasmamount > GLOB.meta_gas_visibility[/datum/gas/plasma]) //if there's enough plasma in the air to see
. += power * 0.5
if(M.reagents.has_reagent(/datum/reagent/toxin/plasma))
. += power * 0.75
/datum/symptom/heal/plasma/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 4 * actual_power
if(prob(5))
to_chat(M, "<span class='notice'>You feel yourself absorbing plasma inside and around you...</span>")
if(M.bodytemperature > BODYTEMP_NORMAL)
M.adjust_bodytemperature(-20 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT,BODYTEMP_NORMAL)
if(prob(5))
to_chat(M, "<span class='notice'>You feel less hot.</span>")
else if(M.bodytemperature < (BODYTEMP_NORMAL + 1))
M.adjust_bodytemperature(20 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT,0,BODYTEMP_NORMAL)
if(prob(5))
to_chat(M, "<span class='notice'>You feel warmer.</span>")
M.adjustToxLoss(-heal_amt, forced = (temp_rate == 4))
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
if(prob(5))
to_chat(M, "<span class='notice'>The pain from your wounds fades rapidly.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
return 1
/datum/symptom/heal/radiation
name = "Radioactive Resonance"
desc = "The virus uses radiation to fix damage through dna mutations."
stealth = -1
resistance = -2
stage_speed = 2
transmittable = -3
level = 6
symptom_delay_min = 1
symptom_delay_max = 1
passive_message = "<span class='notice'>Your skin glows faintly for a moment.</span>"
var/cellular_damage = FALSE
threshold_desc = "<b>Transmission 6:</b> Additionally heals cellular damage and toxin lovers.<br>\
<b>Resistance 7:</b> Increases healing speed."
/datum/symptom/heal/radiation/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["resistance"] >= 7)
power = 2
if(A.properties["transmittable"] >= 6)
cellular_damage = TRUE
/datum/symptom/heal/radiation/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
switch(M.radiation)
if(0)
return FALSE
if(1 to RAD_MOB_SAFE)
return 0.25
if(RAD_MOB_SAFE to RAD_BURN_THRESHOLD)
return 0.5
if(RAD_BURN_THRESHOLD to RAD_MOB_MUTATE)
return 0.75
if(RAD_MOB_MUTATE to RAD_MOB_KNOCKDOWN)
return 1
else
return 1.5
/datum/symptom/heal/radiation/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = actual_power
if(cellular_damage)
M.adjustCloneLoss(-heal_amt * 0.5)
M.adjustToxLoss(-(2 * heal_amt), forced = cellular_damage)
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
if(prob(4))
to_chat(M, "<span class='notice'>Your skin glows faintly, and you feel your wounds mending themselves.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
return 1
/datum/symptom/heal
name = "Basic Healing (does nothing)" //warning for adminspawn viruses
desc = "You should not be seeing this."
stealth = 0
resistance = 0
stage_speed = 0
transmittable = 0
level = 0 //not obtainable
base_message_chance = 20 //here used for the overlays
symptom_delay_min = 1
symptom_delay_max = 1
var/passive_message = "" //random message to infected but not actively healing people
threshold_desc = "<b>Stage Speed 6:</b> Doubles healing speed.<br>\
<b>Stealth 4:</b> Healing will no longer be visible to onlookers."
/datum/symptom/heal/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 6) //stronger healing
power = 2
/datum/symptom/heal/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(4, 5)
var/effectiveness = CanHeal(A)
if(!effectiveness)
if(passive_message && prob(2) && passive_message_condition(M))
to_chat(M, passive_message)
return
else
Heal(M, A, effectiveness)
return
/datum/symptom/heal/proc/CanHeal(datum/disease/advance/A)
return power
/datum/symptom/heal/proc/Heal(mob/living/M, datum/disease/advance/A, actual_power)
return TRUE
/datum/symptom/heal/proc/passive_message_condition(mob/living/M)
return TRUE
/datum/symptom/heal/starlight
name = "Starlight Condensation"
desc = "The virus reacts to direct starlight, producing regenerative chemicals. Works best against toxin-based damage."
stealth = -1
resistance = -2
stage_speed = 0
transmittable = 1
level = 6
passive_message = "<span class='notice'>You miss the feeling of starlight on your skin.</span>"
var/nearspace_penalty = 0.3
threshold_desc = "<b>Stage Speed 6:</b> Increases healing speed.<br>\
<b>Transmission 6:</b> Removes penalty for only being close to space."
/datum/symptom/heal/starlight/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["transmittable"] >= 6)
nearspace_penalty = 1
if(A.properties["stage_rate"] >= 6)
power = 2
/datum/symptom/heal/starlight/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
if(istype(get_turf(M), /turf/open/space))
return power
else
for(var/turf/T in view(M, 2))
if(istype(T, /turf/open/space))
return power * nearspace_penalty
/datum/symptom/heal/starlight/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = actual_power
if(M.getToxLoss() && prob(5))
to_chat(M, "<span class='notice'>Your skin tingles as the starlight seems to heal you.</span>")
M.adjustToxLoss(-(4 * heal_amt), forced = TRUE) //most effective on toxins
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
return 1
/datum/symptom/heal/starlight/passive_message_condition(mob/living/M)
if(M.getBruteLoss() || M.getFireLoss() || M.getToxLoss())
return TRUE
return FALSE
/datum/symptom/heal/chem
name = "Toxolysis"
stealth = 0
resistance = -2
stage_speed = 2
transmittable = -2
level = 7
var/food_conversion = FALSE
desc = "The virus rapidly breaks down any foreign chemicals in the bloodstream."
threshold_desc = "<b>Resistance 7:</b> Increases chem removal speed.<br>\
<b>Stage Speed 6:</b> Consumed chemicals nourish the host."
/datum/symptom/heal/chem/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 6)
food_conversion = TRUE
if(A.properties["resistance"] >= 7)
power = 2
/datum/symptom/heal/chem/Heal(mob/living/M, datum/disease/advance/A, actual_power)
for(var/E in M.reagents.reagent_list) //Not just toxins!
var/datum/reagent/R = E
M.reagents.remove_reagent(R.type, actual_power)
if(food_conversion)
M.nutrition += 0.3
if(prob(2))
to_chat(M, "<span class='notice'>You feel a mild warmth as your blood purifies itself.</span>")
return 1
/datum/symptom/heal/metabolism
name = "Metabolic Boost"
stealth = -1
resistance = -2
stage_speed = 2
transmittable = 1
level = 7
var/triple_metabolism = FALSE
var/reduced_hunger = FALSE
desc = "The virus causes the host's metabolism to accelerate rapidly, making them process chemicals twice as fast,\
but also causing increased hunger."
threshold_desc = "<b>Stealth 3:</b> Reduces hunger rate.<br>\
<b>Stage Speed 10:</b> Chemical metabolization is tripled instead of doubled."
/datum/symptom/heal/metabolism/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 10)
triple_metabolism = TRUE
if(A.properties["stealth"] >= 3)
reduced_hunger = TRUE
/datum/symptom/heal/metabolism/Heal(mob/living/carbon/C, datum/disease/advance/A, actual_power)
if(!istype(C))
return
C.reagents.metabolize(C, can_overdose=TRUE) //this works even without a liver; it's intentional since the virus is metabolizing by itself
if(triple_metabolism)
C.reagents.metabolize(C, can_overdose=TRUE)
C.overeatduration = max(C.overeatduration - 2, 0)
var/lost_nutrition = 9 - (reduced_hunger * 5)
C.nutrition = max(C.nutrition - (lost_nutrition * HUNGER_FACTOR), 0) //Hunger depletes at 10x the normal speed
if(prob(2))
to_chat(C, "<span class='notice'>You feel an odd gurgle in your stomach, as if it was working much faster than normal.</span>")
return 1
/datum/symptom/heal/darkness
name = "Nocturnal Regeneration"
desc = "The virus is able to mend the host's flesh when in conditions of low light, repairing physical damage. More effective against brute damage."
stealth = 2
resistance = -1
stage_speed = -2
transmittable = -1
level = 6
passive_message = "<span class='notice'>You feel tingling on your skin as light passes over it.</span>"
threshold_desc = "<b>Stage Speed 8:</b> Doubles healing speed."
/datum/symptom/heal/darkness/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 8)
power = 2
/datum/symptom/heal/darkness/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
var/light_amount = 0
if(isturf(M.loc)) //else, there's considered to be no light
var/turf/T = M.loc
light_amount = min(1,T.get_lumcount()) - 0.5
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
return power
/datum/symptom/heal/darkness/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 2 * actual_power
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
if(prob(5))
to_chat(M, "<span class='notice'>The darkness soothes and mends your wounds.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len * 0.5)) //more effective on brute
M.update_damage_overlays()
return 1
/datum/symptom/heal/darkness/passive_message_condition(mob/living/M)
if(M.getBruteLoss() || M.getFireLoss())
return TRUE
return FALSE
/datum/symptom/heal/coma
name = "Regenerative Coma"
desc = "The virus causes the host to fall into a death-like coma when severely damaged, then rapidly fixes the damage."
stealth = 0
resistance = 2
stage_speed = -3
transmittable = -2
level = 8
passive_message = "<span class='notice'>The pain from your wounds makes you feel oddly sleepy...</span>"
var/deathgasp = FALSE
var/stabilize = FALSE
var/active_coma = FALSE //to prevent multiple coma procs
threshold_desc = "<b>Stealth 2:</b> Host appears to die when falling into a coma.<br>\
<b>Resistance 4:</b> The virus also stabilizes the host while they are in critical condition.<br>\
<b>Stage Speed 7:</b> Increases healing speed."
/datum/symptom/heal/coma/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 7)
power = 1.5
if(A.properties["resistance"] >= 4)
stabilize = TRUE
if(A.properties["stealth"] >= 2)
deathgasp = TRUE
/datum/symptom/heal/coma/on_stage_change(datum/disease/advance/A) //mostly copy+pasted from the code for self-respiration's TRAIT_NOBREATH stuff
if(!..())
return FALSE
if(A.stage >= 4 && stabilize)
ADD_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
else
REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
return TRUE
/datum/symptom/heal/coma/End(datum/disease/advance/A)
if(!..())
return
REMOVE_TRAIT(A.affected_mob, TRAIT_NOCRITDAMAGE, DISEASE_TRAIT)
/datum/symptom/heal/coma/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
if(HAS_TRAIT(M, TRAIT_DEATHCOMA))
return power
else if(M.IsUnconscious() || M.stat == UNCONSCIOUS)
return power * 0.9
else if(M.stat == SOFT_CRIT)
return power * 0.5
else if(M.IsSleeping())
return power * 0.25
else if(M.getBruteLoss() + M.getFireLoss() >= 70 && !active_coma)
to_chat(M, "<span class='warning'>You feel yourself slip into a regenerative coma...</span>")
active_coma = TRUE
addtimer(CALLBACK(src, .proc/coma, M), 60)
/datum/symptom/heal/coma/proc/coma(mob/living/M)
if(deathgasp)
M.emote("deathgasp")
M.fakedeath("regenerative_coma")
M.update_stat()
M.update_canmove()
addtimer(CALLBACK(src, .proc/uncoma, M), 300)
/datum/symptom/heal/coma/proc/uncoma(mob/living/M)
if(!active_coma)
return
active_coma = FALSE
M.cure_fakedeath("regenerative_coma")
M.update_stat()
M.update_canmove()
/datum/symptom/heal/coma/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 4 * actual_power
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
if(active_coma && M.getBruteLoss() + M.getFireLoss() == 0)
uncoma(M)
return 1
/datum/symptom/heal/coma/passive_message_condition(mob/living/M)
if((M.getBruteLoss() + M.getFireLoss()) > 30)
return TRUE
return FALSE
/datum/symptom/heal/water
name = "Tissue Hydration"
desc = "The virus uses excess water inside and outside the body to repair damaged tissue cells. More effective against burns."
stealth = 0
resistance = -1
stage_speed = 0
transmittable = 1
level = 6
passive_message = "<span class='notice'>Your skin feels oddly dry...</span>"
var/absorption_coeff = 1
threshold_desc = "<b>Resistance 5:</b> Water is consumed at a much slower rate.<br>\
<b>Stage Speed 7:</b> Increases healing speed."
/datum/symptom/heal/water/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 7)
power = 2
if(A.properties["stealth"] >= 2)
absorption_coeff = 0.25
/datum/symptom/heal/water/CanHeal(datum/disease/advance/A)
. = 0
var/mob/living/M = A.affected_mob
if(M.fire_stacks < 0)
M.fire_stacks = min(M.fire_stacks + 1 * absorption_coeff, 0)
. += power
if(M.reagents.has_reagent(/datum/reagent/water/holywater))
M.reagents.remove_reagent(/datum/reagent/water/holywater, 0.5 * absorption_coeff)
. += power * 0.75
else if(M.reagents.has_reagent(/datum/reagent/water))
M.reagents.remove_reagent(/datum/reagent/water, 0.5 * absorption_coeff)
. += power * 0.5
/datum/symptom/heal/water/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 2 * actual_power
var/list/parts = M.get_damaged_bodyparts(1,1) //more effective on burns
if(!parts.len)
return
if(prob(5))
to_chat(M, "<span class='notice'>You feel yourself absorbing the water around you to soothe your damaged skin.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len * 0.5, heal_amt/parts.len))
M.update_damage_overlays()
return 1
/datum/symptom/heal/water/passive_message_condition(mob/living/M)
if(M.getBruteLoss() || M.getFireLoss())
return TRUE
return FALSE
/datum/symptom/heal/plasma
name = "Plasma Fixation"
desc = "The virus draws plasma from the atmosphere and from inside the body to heal and stabilize body temperature."
stealth = 0
resistance = 3
stage_speed = -2
transmittable = -2
level = 8
passive_message = "<span class='notice'>You feel an odd attraction to plasma.</span>"
var/temp_rate = 1
threshold_desc = "<b>Transmission 6:</b> Increases temperature adjustment rate and heals toxin lovers.<br>\
<b>Stage Speed 7:</b> Increases healing speed."
/datum/symptom/heal/plasma/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 7)
power = 2
if(A.properties["transmittable"] >= 6)
temp_rate = 4
/datum/symptom/heal/plasma/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
var/datum/gas_mixture/environment
var/plasmamount
. = 0
if(M.loc)
environment = M.loc.return_air()
if(environment)
plasmamount = environment.gases[/datum/gas/plasma]
if(plasmamount && plasmamount > GLOB.meta_gas_visibility[/datum/gas/plasma]) //if there's enough plasma in the air to see
. += power * 0.5
if(M.reagents.has_reagent(/datum/reagent/toxin/plasma))
. += power * 0.75
/datum/symptom/heal/plasma/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = 4 * actual_power
if(prob(5))
to_chat(M, "<span class='notice'>You feel yourself absorbing plasma inside and around you...</span>")
if(M.bodytemperature > BODYTEMP_NORMAL)
M.adjust_bodytemperature(-20 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT,BODYTEMP_NORMAL)
if(prob(5))
to_chat(M, "<span class='notice'>You feel less hot.</span>")
else if(M.bodytemperature < (BODYTEMP_NORMAL + 1))
M.adjust_bodytemperature(20 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT,0,BODYTEMP_NORMAL)
if(prob(5))
to_chat(M, "<span class='notice'>You feel warmer.</span>")
M.adjustToxLoss(-heal_amt, forced = (temp_rate == 4))
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
if(prob(5))
to_chat(M, "<span class='notice'>The pain from your wounds fades rapidly.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
return 1
/datum/symptom/heal/radiation
name = "Radioactive Resonance"
desc = "The virus uses radiation to fix damage through dna mutations."
stealth = -1
resistance = -2
stage_speed = 2
transmittable = -3
level = 6
symptom_delay_min = 1
symptom_delay_max = 1
passive_message = "<span class='notice'>Your skin glows faintly for a moment.</span>"
var/cellular_damage = FALSE
threshold_desc = "<b>Transmission 6:</b> Additionally heals cellular damage and toxin lovers.<br>\
<b>Resistance 7:</b> Increases healing speed."
/datum/symptom/heal/radiation/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["resistance"] >= 7)
power = 2
if(A.properties["transmittable"] >= 6)
cellular_damage = TRUE
/datum/symptom/heal/radiation/CanHeal(datum/disease/advance/A)
var/mob/living/M = A.affected_mob
switch(M.radiation)
if(0)
return FALSE
if(1 to RAD_MOB_SAFE)
return 0.25
if(RAD_MOB_SAFE to RAD_BURN_THRESHOLD)
return 0.5
if(RAD_BURN_THRESHOLD to RAD_MOB_MUTATE)
return 0.75
if(RAD_MOB_MUTATE to RAD_MOB_KNOCKDOWN)
return 1
else
return 1.5
/datum/symptom/heal/radiation/Heal(mob/living/carbon/M, datum/disease/advance/A, actual_power)
var/heal_amt = actual_power
if(cellular_damage)
M.adjustCloneLoss(-heal_amt * 0.5)
M.adjustToxLoss(-(2 * heal_amt), forced = cellular_damage)
var/list/parts = M.get_damaged_bodyparts(1,1)
if(!parts.len)
return
if(prob(4))
to_chat(M, "<span class='notice'>Your skin glows faintly, and you feel your wounds mending themselves.</span>")
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(heal_amt/parts.len, heal_amt/parts.len))
M.update_damage_overlays()
return 1
@@ -1,54 +1,54 @@
/*
//////////////////////////////////////
Itching
Not noticable or unnoticable.
Resistant.
Increases stage speed.
Little transmissibility.
Low Level.
BONUS
Displays an annoying message!
Should be used for buffing your disease.
//////////////////////////////////////
*/
/datum/symptom/itching
name = "Itching"
desc = "The virus irritates the skin, causing itching."
stealth = 0
resistance = 3
stage_speed = 3
transmittable = 1
level = 1
severity = 1
symptom_delay_min = 5
symptom_delay_max = 25
var/scratch = FALSE
threshold_desc = "<b>Transmission 6:</b> Increases frequency of itching.<br>\
<b>Stage Speed 7:</b> The host will scrath itself when itching, causing superficial damage."
/datum/symptom/itching/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["transmittable"] >= 6) //itch more often
symptom_delay_min = 1
symptom_delay_max = 4
if(A.properties["stage_rate"] >= 7) //scratch
scratch = TRUE
/datum/symptom/itching/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
var/picked_bodypart = pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
var/obj/item/bodypart/bodypart = M.get_bodypart(picked_bodypart)
if(bodypart && bodypart.status == BODYPART_ORGANIC && !bodypart.is_pseudopart) //robotic limbs will mean less scratching overall
var/can_scratch = scratch && !M.incapacitated() && get_location_accessible(M, picked_bodypart)
M.visible_message("[can_scratch ? "<span class='warning'>[M] scratches [M.p_their()] [bodypart.name].</span>" : ""]", "<span class='warning'>Your [bodypart.name] itches. [can_scratch ? " You scratch it." : ""]</span>")
if(can_scratch)
/*
//////////////////////////////////////
Itching
Not noticable or unnoticable.
Resistant.
Increases stage speed.
Little transmissibility.
Low Level.
BONUS
Displays an annoying message!
Should be used for buffing your disease.
//////////////////////////////////////
*/
/datum/symptom/itching
name = "Itching"
desc = "The virus irritates the skin, causing itching."
stealth = 0
resistance = 3
stage_speed = 3
transmittable = 1
level = 1
severity = 1
symptom_delay_min = 5
symptom_delay_max = 25
var/scratch = FALSE
threshold_desc = "<b>Transmission 6:</b> Increases frequency of itching.<br>\
<b>Stage Speed 7:</b> The host will scrath itself when itching, causing superficial damage."
/datum/symptom/itching/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["transmittable"] >= 6) //itch more often
symptom_delay_min = 1
symptom_delay_max = 4
if(A.properties["stage_rate"] >= 7) //scratch
scratch = TRUE
/datum/symptom/itching/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
var/picked_bodypart = pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
var/obj/item/bodypart/bodypart = M.get_bodypart(picked_bodypart)
if(bodypart && bodypart.status == BODYPART_ORGANIC && !bodypart.is_pseudopart) //robotic limbs will mean less scratching overall
var/can_scratch = scratch && !M.incapacitated() && get_location_accessible(M, picked_bodypart)
M.visible_message("[can_scratch ? "<span class='warning'>[M] scratches [M.p_their()] [bodypart.name].</span>" : ""]", "<span class='warning'>Your [bodypart.name] itches. [can_scratch ? " You scratch it." : ""]</span>")
if(can_scratch)
bodypart.receive_damage(0.5)
+67 -67
View File
@@ -1,68 +1,68 @@
/*
//////////////////////////////////////
Self-Respiration
Slightly hidden.
Lowers resistance significantly.
Decreases stage speed significantly.
Decreases transmittablity tremendously.
Fatal Level.
Bonus
The body generates salbutamol.
//////////////////////////////////////
*/
/datum/symptom/oxygen
name = "Self-Respiration"
desc = "The virus rapidly synthesizes oxygen, effectively removing the need for breathing."
stealth = 1
resistance = -3
stage_speed = -3
transmittable = -4
level = 6
base_message_chance = 5
symptom_delay_min = 1
symptom_delay_max = 1
var/regenerate_blood = FALSE
threshold_desc = "<b>Resistance 8:</b>Additionally regenerates lost blood.<br>"
/datum/symptom/oxygen/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["resistance"] >= 8) //blood regeneration
regenerate_blood = TRUE
/datum/symptom/oxygen/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
switch(A.stage)
if(4, 5)
M.adjustOxyLoss(-7, 0)
M.losebreath = max(0, M.losebreath - 4)
if(regenerate_blood && M.blood_volume < (BLOOD_VOLUME_NORMAL * M.blood_ratio))
M.blood_volume += 1
else
if(prob(base_message_chance))
to_chat(M, "<span class='notice'>[pick("Your lungs feel great.", "You realize you haven't been breathing.", "You don't feel the need to breathe.")]</span>")
return
/datum/symptom/oxygen/on_stage_change(datum/disease/advance/A)
if(!..())
return FALSE
var/mob/living/carbon/M = A.affected_mob
if(A.stage >= 4)
ADD_TRAIT(M, TRAIT_NOBREATH, DISEASE_TRAIT)
else
REMOVE_TRAIT(M, TRAIT_NOBREATH, DISEASE_TRAIT)
return TRUE
/datum/symptom/oxygen/End(datum/disease/advance/A)
if(!..())
return
if(A.stage >= 4)
/*
//////////////////////////////////////
Self-Respiration
Slightly hidden.
Lowers resistance significantly.
Decreases stage speed significantly.
Decreases transmittablity tremendously.
Fatal Level.
Bonus
The body generates salbutamol.
//////////////////////////////////////
*/
/datum/symptom/oxygen
name = "Self-Respiration"
desc = "The virus rapidly synthesizes oxygen, effectively removing the need for breathing."
stealth = 1
resistance = -3
stage_speed = -3
transmittable = -4
level = 6
base_message_chance = 5
symptom_delay_min = 1
symptom_delay_max = 1
var/regenerate_blood = FALSE
threshold_desc = "<b>Resistance 8:</b>Additionally regenerates lost blood.<br>"
/datum/symptom/oxygen/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["resistance"] >= 8) //blood regeneration
regenerate_blood = TRUE
/datum/symptom/oxygen/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
switch(A.stage)
if(4, 5)
M.adjustOxyLoss(-7, 0)
M.losebreath = max(0, M.losebreath - 4)
if(regenerate_blood && M.blood_volume < (BLOOD_VOLUME_NORMAL * M.blood_ratio))
M.blood_volume += 1
else
if(prob(base_message_chance))
to_chat(M, "<span class='notice'>[pick("Your lungs feel great.", "You realize you haven't been breathing.", "You don't feel the need to breathe.")]</span>")
return
/datum/symptom/oxygen/on_stage_change(datum/disease/advance/A)
if(!..())
return FALSE
var/mob/living/carbon/M = A.affected_mob
if(A.stage >= 4)
ADD_TRAIT(M, TRAIT_NOBREATH, DISEASE_TRAIT)
else
REMOVE_TRAIT(M, TRAIT_NOBREATH, DISEASE_TRAIT)
return TRUE
/datum/symptom/oxygen/End(datum/disease/advance/A)
if(!..())
return
if(A.stage >= 4)
REMOVE_TRAIT(A.affected_mob, TRAIT_NOBREATH, DISEASE_TRAIT)
@@ -1,55 +1,55 @@
/*
//////////////////////////////////////
Alopecia
Not Noticeable.
Increases resistance slightly.
Increases stage speed.
Transmittable.
Intense Level.
BONUS
Makes the mob lose hair.
//////////////////////////////////////
*/
/datum/symptom/shedding
name = "Alopecia"
desc = "The virus causes rapid shedding of head and body hair."
stealth = 0
resistance = 1
stage_speed = 2
transmittable = 2
level = 4
severity = 1
base_message_chance = 50
symptom_delay_min = 45
symptom_delay_max = 90
/datum/symptom/shedding/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
if(prob(base_message_chance))
to_chat(M, "<span class='warning'>[pick("Your scalp itches.", "Your skin feels flaky.")]</span>")
if(ishuman(M))
var/mob/living/carbon/human/H = M
switch(A.stage)
if(3, 4)
if(!(H.hair_style == "Bald") && !(H.hair_style == "Balding Hair"))
to_chat(H, "<span class='warning'>Your hair starts to fall out in clumps...</span>")
addtimer(CALLBACK(src, .proc/Shed, H, FALSE), 50)
if(5)
if(!(H.facial_hair_style == "Shaved") || !(H.hair_style == "Bald"))
to_chat(H, "<span class='warning'>Your hair starts to fall out in clumps...</span>")
addtimer(CALLBACK(src, .proc/Shed, H, TRUE), 50)
/datum/symptom/shedding/proc/Shed(mob/living/carbon/human/H, fullbald)
if(fullbald)
H.facial_hair_style = "Shaved"
H.hair_style = "Bald"
else
H.hair_style = "Balding Hair"
H.update_hair()
/*
//////////////////////////////////////
Alopecia
Not Noticeable.
Increases resistance slightly.
Increases stage speed.
Transmittable.
Intense Level.
BONUS
Makes the mob lose hair.
//////////////////////////////////////
*/
/datum/symptom/shedding
name = "Alopecia"
desc = "The virus causes rapid shedding of head and body hair."
stealth = 0
resistance = 1
stage_speed = 2
transmittable = 2
level = 4
severity = 1
base_message_chance = 50
symptom_delay_min = 45
symptom_delay_max = 90
/datum/symptom/shedding/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
if(prob(base_message_chance))
to_chat(M, "<span class='warning'>[pick("Your scalp itches.", "Your skin feels flaky.")]</span>")
if(ishuman(M))
var/mob/living/carbon/human/H = M
switch(A.stage)
if(3, 4)
if(!(H.hair_style == "Bald") && !(H.hair_style == "Balding Hair"))
to_chat(H, "<span class='warning'>Your hair starts to fall out in clumps...</span>")
addtimer(CALLBACK(src, .proc/Shed, H, FALSE), 50)
if(5)
if(!(H.facial_hair_style == "Shaved") || !(H.hair_style == "Bald"))
to_chat(H, "<span class='warning'>Your hair starts to fall out in clumps...</span>")
addtimer(CALLBACK(src, .proc/Shed, H, TRUE), 50)
/datum/symptom/shedding/proc/Shed(mob/living/carbon/human/H, fullbald)
if(fullbald)
H.facial_hair_style = "Shaved"
H.hair_style = "Bald"
else
H.hair_style = "Balding Hair"
H.update_hair()
@@ -1,59 +1,59 @@
/*
//////////////////////////////////////
Shivering
No change to hidden.
Increases resistance.
Increases stage speed.
Little transmittable.
Low level.
Bonus
Cools down your body.
//////////////////////////////////////
*/
/datum/symptom/shivering
name = "Shivering"
desc = "The virus inhibits the body's thermoregulation, cooling the body down."
stealth = 0
resistance = 2
stage_speed = 2
transmittable = 2
level = 2
severity = 2
symptom_delay_min = 10
symptom_delay_max = 30
var/unsafe = FALSE //over the cold threshold
threshold_desc = "<b>Stage Speed 5:</b> Increases cooling speed; the host can fall below safe temperature levels.<br>\
<b>Stage Speed 10:</b> Further increases cooling speed."
/datum/symptom/fever/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 5) //dangerous cold
power = 1.5
unsafe = TRUE
if(A.properties["stage_rate"] >= 10)
power = 2.5
/datum/symptom/shivering/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
if(!unsafe || A.stage < 4)
to_chat(M, "<span class='warning'>[pick("You feel cold.", "You shiver.")]</span>")
else
to_chat(M, "<span class='userdanger'>[pick("You feel your blood run cold.", "You feel ice in your veins.", "You feel like you can't heat up.", "You shiver violently." )]</span>")
if(M.bodytemperature > BODYTEMP_COLD_DAMAGE_LIMIT || unsafe)
Chill(M, A)
/datum/symptom/shivering/proc/Chill(mob/living/M, datum/disease/advance/A)
var/get_cold = 6 * power
var/limit = BODYTEMP_COLD_DAMAGE_LIMIT + 1
if(unsafe)
limit = 0
M.adjust_bodytemperature(-get_cold * A.stage, limit)
/*
//////////////////////////////////////
Shivering
No change to hidden.
Increases resistance.
Increases stage speed.
Little transmittable.
Low level.
Bonus
Cools down your body.
//////////////////////////////////////
*/
/datum/symptom/shivering
name = "Shivering"
desc = "The virus inhibits the body's thermoregulation, cooling the body down."
stealth = 0
resistance = 2
stage_speed = 2
transmittable = 2
level = 2
severity = 2
symptom_delay_min = 10
symptom_delay_max = 30
var/unsafe = FALSE //over the cold threshold
threshold_desc = "<b>Stage Speed 5:</b> Increases cooling speed; the host can fall below safe temperature levels.<br>\
<b>Stage Speed 10:</b> Further increases cooling speed."
/datum/symptom/fever/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stage_rate"] >= 5) //dangerous cold
power = 1.5
unsafe = TRUE
if(A.properties["stage_rate"] >= 10)
power = 2.5
/datum/symptom/shivering/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
if(!unsafe || A.stage < 4)
to_chat(M, "<span class='warning'>[pick("You feel cold.", "You shiver.")]</span>")
else
to_chat(M, "<span class='userdanger'>[pick("You feel your blood run cold.", "You feel ice in your veins.", "You feel like you can't heat up.", "You shiver violently." )]</span>")
if(M.bodytemperature > BODYTEMP_COLD_DAMAGE_LIMIT || unsafe)
Chill(M, A)
/datum/symptom/shivering/proc/Chill(mob/living/M, datum/disease/advance/A)
var/get_cold = 6 * power
var/limit = BODYTEMP_COLD_DAMAGE_LIMIT + 1
if(unsafe)
limit = 0
M.adjust_bodytemperature(-get_cold * A.stage, limit)
return 1
+51 -51
View File
@@ -1,52 +1,52 @@
/*
//////////////////////////////////////
Sneezing
Very Noticable.
Increases resistance.
Doesn't increase stage speed.
Very transmissible.
Low Level.
Bonus
Forces a spread type of AIRBORNE
with extra range!
//////////////////////////////////////
*/
/datum/symptom/sneeze
name = "Sneezing"
desc = "The virus causes irritation of the nasal cavity, making the host sneeze occasionally."
stealth = -2
resistance = 3
stage_speed = 0
transmittable = 4
level = 1
severity = 1
symptom_delay_min = 5
symptom_delay_max = 35
threshold_desc = "<b>Transmission 9:</b> Increases sneezing range, spreading the virus over a larger area.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/sneeze/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["transmittable"] >= 9) //longer spread range
power = 2
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
/datum/symptom/sneeze/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3)
if(!suppress_warning)
M.emote("sniff")
else
M.emote("sneeze")
if(M.CanSpreadAirborneDisease()) //don't spread germs if they covered their mouth
/*
//////////////////////////////////////
Sneezing
Very Noticable.
Increases resistance.
Doesn't increase stage speed.
Very transmissible.
Low Level.
Bonus
Forces a spread type of AIRBORNE
with extra range!
//////////////////////////////////////
*/
/datum/symptom/sneeze
name = "Sneezing"
desc = "The virus causes irritation of the nasal cavity, making the host sneeze occasionally."
stealth = -2
resistance = 3
stage_speed = 0
transmittable = 4
level = 1
severity = 1
symptom_delay_min = 5
symptom_delay_max = 35
threshold_desc = "<b>Transmission 9:</b> Increases sneezing range, spreading the virus over a larger area.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/sneeze/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["transmittable"] >= 9) //longer spread range
power = 2
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
/datum/symptom/sneeze/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3)
if(!suppress_warning)
M.emote("sniff")
else
M.emote("sneeze")
if(M.CanSpreadAirborneDisease()) //don't spread germs if they covered their mouth
A.spread(4 + power)
@@ -1,81 +1,81 @@
// Symptoms are the effects that engineered advanced diseases do.
/datum/symptom
// Buffs/Debuffs the symptom has to the overall engineered disease.
var/name = ""
var/desc = "If you see this something went very wrong." //Basic symptom description
var/threshold_desc = "" //Description of threshold effects
var/stealth = 0
var/resistance = 0
var/stage_speed = 0
var/transmittable = 0
// The type level of the symptom. Higher is harder to generate.
var/level = 0
// The severity level of the symptom. Higher is more dangerous.
var/severity = 0
// The hash tag for our diseases, we will add it up with our other symptoms to get a unique id! ID MUST BE UNIQUE!!!
var/id = ""
//Base chance of sending warning messages, so it can be modified
var/base_message_chance = 10
//If the early warnings are suppressed or not
var/suppress_warning = FALSE
//Ticks between each activation
var/next_activation = 0
var/symptom_delay_min = 1
var/symptom_delay_max = 1
//Can be used to multiply virus effects
var/power = 1
//A neutered symptom has no effect, and only affects statistics.
var/neutered = FALSE
var/list/thresholds
var/naturally_occuring = TRUE //if this symptom can appear from /datum/disease/advance/GenerateSymptoms()
/datum/symptom/New()
var/list/S = SSdisease.list_symptoms
for(var/i = 1; i <= S.len; i++)
if(type == S[i])
id = "[i]"
return
CRASH("We couldn't assign an ID!")
// Called when processing of the advance disease that holds this symptom infects a host and upon each Refresh() of that advance disease.
/datum/symptom/proc/Start(datum/disease/advance/A)
if(neutered)
return FALSE
return TRUE
// Called when the advance disease is going to be deleted or when the advance disease stops processing.
/datum/symptom/proc/End(datum/disease/advance/A)
if(neutered)
return FALSE
return TRUE
/datum/symptom/proc/Activate(datum/disease/advance/A)
if(neutered)
return FALSE
if(world.time < next_activation)
return FALSE
else
next_activation = world.time + rand(symptom_delay_min * 10, symptom_delay_max * 10)
return TRUE
/datum/symptom/proc/on_stage_change(datum/disease/advance/A)
if(neutered)
return FALSE
return TRUE
/datum/symptom/proc/Copy()
var/datum/symptom/new_symp = new type
new_symp.name = name
new_symp.id = id
new_symp.neutered = neutered
return new_symp
/datum/symptom/proc/generate_threshold_desc()
return
/datum/symptom/proc/OnAdd(datum/disease/advance/A) //Overload when a symptom needs to be active before processing, like changing biotypes.
return
/datum/symptom/proc/OnRemove(datum/disease/advance/A) //But dont forget to remove them too.
// Symptoms are the effects that engineered advanced diseases do.
/datum/symptom
// Buffs/Debuffs the symptom has to the overall engineered disease.
var/name = ""
var/desc = "If you see this something went very wrong." //Basic symptom description
var/threshold_desc = "" //Description of threshold effects
var/stealth = 0
var/resistance = 0
var/stage_speed = 0
var/transmittable = 0
// The type level of the symptom. Higher is harder to generate.
var/level = 0
// The severity level of the symptom. Higher is more dangerous.
var/severity = 0
// The hash tag for our diseases, we will add it up with our other symptoms to get a unique id! ID MUST BE UNIQUE!!!
var/id = ""
//Base chance of sending warning messages, so it can be modified
var/base_message_chance = 10
//If the early warnings are suppressed or not
var/suppress_warning = FALSE
//Ticks between each activation
var/next_activation = 0
var/symptom_delay_min = 1
var/symptom_delay_max = 1
//Can be used to multiply virus effects
var/power = 1
//A neutered symptom has no effect, and only affects statistics.
var/neutered = FALSE
var/list/thresholds
var/naturally_occuring = TRUE //if this symptom can appear from /datum/disease/advance/GenerateSymptoms()
/datum/symptom/New()
var/list/S = SSdisease.list_symptoms
for(var/i = 1; i <= S.len; i++)
if(type == S[i])
id = "[i]"
return
CRASH("We couldn't assign an ID!")
// Called when processing of the advance disease that holds this symptom infects a host and upon each Refresh() of that advance disease.
/datum/symptom/proc/Start(datum/disease/advance/A)
if(neutered)
return FALSE
return TRUE
// Called when the advance disease is going to be deleted or when the advance disease stops processing.
/datum/symptom/proc/End(datum/disease/advance/A)
if(neutered)
return FALSE
return TRUE
/datum/symptom/proc/Activate(datum/disease/advance/A)
if(neutered)
return FALSE
if(world.time < next_activation)
return FALSE
else
next_activation = world.time + rand(symptom_delay_min * 10, symptom_delay_max * 10)
return TRUE
/datum/symptom/proc/on_stage_change(datum/disease/advance/A)
if(neutered)
return FALSE
return TRUE
/datum/symptom/proc/Copy()
var/datum/symptom/new_symp = new type
new_symp.name = name
new_symp.id = id
new_symp.neutered = neutered
return new_symp
/datum/symptom/proc/generate_threshold_desc()
return
/datum/symptom/proc/OnAdd(datum/disease/advance/A) //Overload when a symptom needs to be active before processing, like changing biotypes.
return
/datum/symptom/proc/OnRemove(datum/disease/advance/A) //But dont forget to remove them too.
return
@@ -1,81 +1,81 @@
/*
//////////////////////////////////////
Voice Change
Noticeable.
Lowers resistance.
Decreases stage speed.
Increased transmittable.
Fatal Level.
Bonus
Changes the voice of the affected mob. Causing confusion in communication.
//////////////////////////////////////
*/
/datum/symptom/voice_change
name = "Voice Change"
desc = "The virus alters the pitch and tone of the host's vocal cords, changing how their voice sounds."
stealth = -1
resistance = -2
stage_speed = -2
transmittable = 2
level = 6
severity = 2
base_message_chance = 100
symptom_delay_min = 60
symptom_delay_max = 120
var/scramble_language = FALSE
var/datum/language/current_language
var/datum/language_holder/original_language
threshold_desc = "<b>Transmission 14:</b> The host's language center of the brain is damaged, leading to complete inability to speak or understand any language.<br>\
<b>Stage Speed 7:</b> Changes voice more often.<br>\
<b>Stealth 3:</b> The symptom remains hidden until active."
/datum/symptom/voice_change/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 3)
suppress_warning = TRUE
if(A.properties["stage_rate"] >= 7) //faster change of voice
base_message_chance = 25
symptom_delay_min = 25
symptom_delay_max = 85
if(A.properties["transmittable"] >= 14) //random language
scramble_language = TRUE
var/mob/living/M = A.affected_mob
var/datum/language_holder/mob_language = M.get_language_holder()
original_language = mob_language.copy()
/datum/symptom/voice_change/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("Your throat hurts.", "You clear your throat.")]</span>")
else
if(ishuman(M))
var/mob/living/carbon/human/H = M
H.SetSpecialVoice(H.dna.species.random_name(H.gender))
if(scramble_language)
H.remove_language(current_language)
current_language = pick(subtypesof(/datum/language) - /datum/language/common)
H.grant_language(current_language)
var/datum/language_holder/mob_language = H.get_language_holder()
mob_language.only_speaks_language = current_language
/datum/symptom/voice_change/End(datum/disease/advance/A)
..()
if(ishuman(A.affected_mob))
var/mob/living/carbon/human/H = A.affected_mob
H.UnsetSpecialVoice()
if(scramble_language)
var/mob/living/M = A.affected_mob
M.copy_known_languages_from(original_language, TRUE)
current_language = null
QDEL_NULL(original_language)
/*
//////////////////////////////////////
Voice Change
Noticeable.
Lowers resistance.
Decreases stage speed.
Increased transmittable.
Fatal Level.
Bonus
Changes the voice of the affected mob. Causing confusion in communication.
//////////////////////////////////////
*/
/datum/symptom/voice_change
name = "Voice Change"
desc = "The virus alters the pitch and tone of the host's vocal cords, changing how their voice sounds."
stealth = -1
resistance = -2
stage_speed = -2
transmittable = 2
level = 6
severity = 2
base_message_chance = 100
symptom_delay_min = 60
symptom_delay_max = 120
var/scramble_language = FALSE
var/datum/language/current_language
var/datum/language_holder/original_language
threshold_desc = "<b>Transmission 14:</b> The host's language center of the brain is damaged, leading to complete inability to speak or understand any language.<br>\
<b>Stage Speed 7:</b> Changes voice more often.<br>\
<b>Stealth 3:</b> The symptom remains hidden until active."
/datum/symptom/voice_change/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 3)
suppress_warning = TRUE
if(A.properties["stage_rate"] >= 7) //faster change of voice
base_message_chance = 25
symptom_delay_min = 25
symptom_delay_max = 85
if(A.properties["transmittable"] >= 14) //random language
scramble_language = TRUE
var/mob/living/M = A.affected_mob
var/datum/language_holder/mob_language = M.get_language_holder()
original_language = mob_language.copy()
/datum/symptom/voice_change/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/carbon/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("Your throat hurts.", "You clear your throat.")]</span>")
else
if(ishuman(M))
var/mob/living/carbon/human/H = M
H.SetSpecialVoice(H.dna.species.random_name(H.gender))
if(scramble_language)
H.remove_language(current_language)
current_language = pick(subtypesof(/datum/language) - /datum/language/common)
H.grant_language(current_language)
var/datum/language_holder/mob_language = H.get_language_holder()
mob_language.only_speaks_language = current_language
/datum/symptom/voice_change/End(datum/disease/advance/A)
..()
if(ishuman(A.affected_mob))
var/mob/living/carbon/human/H = A.affected_mob
H.UnsetSpecialVoice()
if(scramble_language)
var/mob/living/M = A.affected_mob
M.copy_known_languages_from(original_language, TRUE)
current_language = null
QDEL_NULL(original_language)
+63 -63
View File
@@ -1,63 +1,63 @@
/*
//////////////////////////////////////
Vomiting
Very Very Noticable.
Decreases resistance.
Doesn't increase stage speed.
Little transmissibility.
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"
desc = "The virus causes nausea and irritates the stomach, causing occasional vomit."
stealth = -2
resistance = -1
stage_speed = 0
transmittable = 1
level = 3
severity = 3
base_message_chance = 100
symptom_delay_min = 25
symptom_delay_max = 80
var/vomit_blood = FALSE
var/proj_vomit = 0
threshold_desc = "<b>Resistance 7:</b> Host will vomit blood, causing internal damage.<br>\
<b>Transmission 7:</b> Host will projectile vomit, increasing vomiting range.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/vomit/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
if(A.properties["resistance"] >= 7) //blood vomit
vomit_blood = TRUE
if(A.properties["transmittable"] >= 7) //projectile vomit
proj_vomit = 5
/datum/symptom/vomit/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("You feel nauseated.", "You feel like you're going to throw up!")]</span>")
else
vomit(M)
/datum/symptom/vomit/proc/vomit(mob/living/carbon/M)
M.vomit(20, vomit_blood, distance = proj_vomit)
/*
//////////////////////////////////////
Vomiting
Very Very Noticable.
Decreases resistance.
Doesn't increase stage speed.
Little transmissibility.
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"
desc = "The virus causes nausea and irritates the stomach, causing occasional vomit."
stealth = -2
resistance = -1
stage_speed = 0
transmittable = 1
level = 3
severity = 3
base_message_chance = 100
symptom_delay_min = 25
symptom_delay_max = 80
var/vomit_blood = FALSE
var/proj_vomit = 0
threshold_desc = "<b>Resistance 7:</b> Host will vomit blood, causing internal damage.<br>\
<b>Transmission 7:</b> Host will projectile vomit, increasing vomiting range.<br>\
<b>Stealth 4:</b> The symptom remains hidden until active."
/datum/symptom/vomit/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4)
suppress_warning = TRUE
if(A.properties["resistance"] >= 7) //blood vomit
vomit_blood = TRUE
if(A.properties["transmittable"] >= 7) //projectile vomit
proj_vomit = 5
/datum/symptom/vomit/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
if(prob(base_message_chance) && !suppress_warning)
to_chat(M, "<span class='warning'>[pick("You feel nauseated.", "You feel like you're going to throw up!")]</span>")
else
vomit(M)
/datum/symptom/vomit/proc/vomit(mob/living/carbon/M)
M.vomit(20, vomit_blood, distance = proj_vomit)
+50 -50
View File
@@ -1,51 +1,51 @@
/*
//////////////////////////////////////
Weight Loss
Very Very Noticable.
Decreases resistance.
Decreases stage speed.
Reduced Transmittable.
High level.
Bonus
Decreases the weight of the mob,
forcing it to be skinny.
//////////////////////////////////////
*/
/datum/symptom/weight_loss
name = "Weight Loss"
desc = "The virus mutates the host's metabolism, making it almost unable to gain nutrition from food."
stealth = -2
resistance = 2
stage_speed = -2
transmittable = -2
level = 3
severity = 3
base_message_chance = 100
symptom_delay_min = 15
symptom_delay_max = 45
threshold_desc = "<b>Stealth 4:</b> The symptom is less noticeable."
/datum/symptom/weight_loss/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4) //warn less often
base_message_chance = 25
/datum/symptom/weight_loss/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
if(prob(base_message_chance))
to_chat(M, "<span class='warning'>[pick("You feel hungry.", "You crave for food.")]</span>")
else
to_chat(M, "<span class='warning'><i>[pick("So hungry...", "You'd kill someone for a bite of food...", "Hunger cramps seize you...")]</i></span>")
M.overeatduration = max(M.overeatduration - 100, 0)
/*
//////////////////////////////////////
Weight Loss
Very Very Noticable.
Decreases resistance.
Decreases stage speed.
Reduced Transmittable.
High level.
Bonus
Decreases the weight of the mob,
forcing it to be skinny.
//////////////////////////////////////
*/
/datum/symptom/weight_loss
name = "Weight Loss"
desc = "The virus mutates the host's metabolism, making it almost unable to gain nutrition from food."
stealth = -2
resistance = 2
stage_speed = -2
transmittable = -2
level = 3
severity = 3
base_message_chance = 100
symptom_delay_min = 15
symptom_delay_max = 45
threshold_desc = "<b>Stealth 4:</b> The symptom is less noticeable."
/datum/symptom/weight_loss/Start(datum/disease/advance/A)
if(!..())
return
if(A.properties["stealth"] >= 4) //warn less often
base_message_chance = 25
/datum/symptom/weight_loss/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
switch(A.stage)
if(1, 2, 3, 4)
if(prob(base_message_chance))
to_chat(M, "<span class='warning'>[pick("You feel hungry.", "You crave for food.")]</span>")
else
to_chat(M, "<span class='warning'><i>[pick("So hungry...", "You'd kill someone for a bite of food...", "Hunger cramps seize you...")]</i></span>")
M.overeatduration = max(M.overeatduration - 100, 0)
M.nutrition = max(M.nutrition - 100, 0)
+57 -57
View File
@@ -1,58 +1,58 @@
/*
//////////////////////////////////////
Eternal Youth
Moderate stealth boost.
Increases resistance tremendously.
Increases stage speed tremendously.
Reduces transmission tremendously.
Critical Level.
BONUS
Gives you immortality and eternal youth!!!
Can be used to buff your virus
//////////////////////////////////////
*/
/datum/symptom/youth
name = "Eternal Youth"
desc = "The virus becomes symbiotically connected to the cells in the host's body, preventing and reversing aging. \
The virus, in turn, becomes more resistant, spreads faster, and is harder to spot, although it doesn't thrive as well without a host."
stealth = 3
resistance = 4
stage_speed = 4
transmittable = -4
level = 5
base_message_chance = 100
symptom_delay_min = 25
symptom_delay_max = 50
/datum/symptom/youth/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
if(ishuman(M))
var/mob/living/carbon/human/H = M
switch(A.stage)
if(1)
if(H.age > 41)
H.age = 41
to_chat(H, "<span class='notice'>You haven't had this much energy in years!</span>")
if(2)
if(H.age > 36)
H.age = 36
to_chat(H, "<span class='notice'>You're suddenly in a good mood.</span>")
if(3)
if(H.age > 31)
H.age = 31
to_chat(H, "<span class='notice'>You begin to feel more lithe.</span>")
if(4)
if(H.age > 26)
H.age = 26
to_chat(H, "<span class='notice'>You feel reinvigorated.</span>")
if(5)
if(H.age > 21)
H.age = 21
/*
//////////////////////////////////////
Eternal Youth
Moderate stealth boost.
Increases resistance tremendously.
Increases stage speed tremendously.
Reduces transmission tremendously.
Critical Level.
BONUS
Gives you immortality and eternal youth!!!
Can be used to buff your virus
//////////////////////////////////////
*/
/datum/symptom/youth
name = "Eternal Youth"
desc = "The virus becomes symbiotically connected to the cells in the host's body, preventing and reversing aging. \
The virus, in turn, becomes more resistant, spreads faster, and is harder to spot, although it doesn't thrive as well without a host."
stealth = 3
resistance = 4
stage_speed = 4
transmittable = -4
level = 5
base_message_chance = 100
symptom_delay_min = 25
symptom_delay_max = 50
/datum/symptom/youth/Activate(datum/disease/advance/A)
if(!..())
return
var/mob/living/M = A.affected_mob
if(ishuman(M))
var/mob/living/carbon/human/H = M
switch(A.stage)
if(1)
if(H.age > 41)
H.age = 41
to_chat(H, "<span class='notice'>You haven't had this much energy in years!</span>")
if(2)
if(H.age > 36)
H.age = 36
to_chat(H, "<span class='notice'>You're suddenly in a good mood.</span>")
if(3)
if(H.age > 31)
H.age = 31
to_chat(H, "<span class='notice'>You begin to feel more lithe.</span>")
if(4)
if(H.age > 26)
H.age = 26
to_chat(H, "<span class='notice'>You feel reinvigorated.</span>")
if(5)
if(H.age > 21)
H.age = 21
to_chat(H, "<span class='notice'>You feel like you can take on the world!</span>")
+36 -36
View File
@@ -1,36 +1,36 @@
/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 = DISEASE_SEVERITY_MEDIUM
disease_flags = CAN_CARRY|CAN_RESIST
spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS
visibility_flags = HIDDEN_PANDEMIC
required_organs = list(/obj/item/organ/appendix)
bypasses_immunity = TRUE // Immunity is based on not having an appendix; this isn't a virus
/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.adjustOrganLoss(ORGAN_SLOT_APPENDIX, 5)
affected_mob.Stun(rand(40,60))
affected_mob.adjustToxLoss(1)
if(3)
if(prob(1))
affected_mob.vomit(95)
affected_mob.adjustOrganLoss(ORGAN_SLOT_APPENDIX, 15)
/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 = DISEASE_SEVERITY_MEDIUM
disease_flags = CAN_CARRY|CAN_RESIST
spread_flags = DISEASE_SPREAD_NON_CONTAGIOUS
visibility_flags = HIDDEN_PANDEMIC
required_organs = list(/obj/item/organ/appendix)
bypasses_immunity = TRUE // Immunity is based on not having an appendix; this isn't a virus
/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.adjustOrganLoss(ORGAN_SLOT_APPENDIX, 5)
affected_mob.Stun(rand(40,60))
affected_mob.adjustToxLoss(1)
if(3)
if(prob(1))
affected_mob.vomit(95)
affected_mob.adjustOrganLoss(ORGAN_SLOT_APPENDIX, 15)
+38 -38
View File
@@ -1,39 +1,39 @@
/datum/disease/beesease
name = "Beesease"
form = "Infection"
max_stages = 4
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Sugar"
cures = list(/datum/reagent/consumable/sugar)
agent = "Apidae Infection"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
desc = "If left untreated subject will regurgitate bees."
severity = DISEASE_SEVERITY_MEDIUM
infectable_biotypes = list(MOB_ORGANIC, MOB_UNDEAD) //bees nesting in corpses
/datum/disease/beesease/stage_act()
..()
switch(stage)
if(2) //also changes say, see say.dm
if(prob(2))
to_chat(affected_mob, "<span class='notice'>You taste honey in your mouth.</span>")
if(3)
if(prob(10))
to_chat(affected_mob, "<span class='notice'>Your stomach rumbles.</span>")
if(prob(2))
to_chat(affected_mob, "<span class='danger'>Your stomach stings painfully.</span>")
if(prob(20))
affected_mob.adjustToxLoss(2)
affected_mob.updatehealth()
if(4)
if(prob(10))
affected_mob.visible_message("<span class='danger'>[affected_mob] buzzes.</span>", \
"<span class='userdanger'>Your stomach buzzes violently!</span>")
if(prob(5))
to_chat(affected_mob, "<span class='danger'>You feel something moving in your throat.</span>")
if(prob(1))
affected_mob.visible_message("<span class='danger'>[affected_mob] coughs up a swarm of bees!</span>", \
"<span class='userdanger'>You cough up a swarm of bees!</span>")
new /mob/living/simple_animal/hostile/poison/bees(affected_mob.loc)
/datum/disease/beesease
name = "Beesease"
form = "Infection"
max_stages = 4
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Sugar"
cures = list(/datum/reagent/consumable/sugar)
agent = "Apidae Infection"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
desc = "If left untreated subject will regurgitate bees."
severity = DISEASE_SEVERITY_MEDIUM
infectable_biotypes = list(MOB_ORGANIC, MOB_UNDEAD) //bees nesting in corpses
/datum/disease/beesease/stage_act()
..()
switch(stage)
if(2) //also changes say, see say.dm
if(prob(2))
to_chat(affected_mob, "<span class='notice'>You taste honey in your mouth.</span>")
if(3)
if(prob(10))
to_chat(affected_mob, "<span class='notice'>Your stomach rumbles.</span>")
if(prob(2))
to_chat(affected_mob, "<span class='danger'>Your stomach stings painfully.</span>")
if(prob(20))
affected_mob.adjustToxLoss(2)
affected_mob.updatehealth()
if(4)
if(prob(10))
affected_mob.visible_message("<span class='danger'>[affected_mob] buzzes.</span>", \
"<span class='userdanger'>Your stomach buzzes violently!</span>")
if(prob(5))
to_chat(affected_mob, "<span class='danger'>You feel something moving in your throat.</span>")
if(prob(1))
affected_mob.visible_message("<span class='danger'>[affected_mob] coughs up a swarm of bees!</span>", \
"<span class='userdanger'>You cough up a swarm of bees!</span>")
new /mob/living/simple_animal/hostile/poison/bees(affected_mob.loc)
return
+59 -59
View File
@@ -1,59 +1,59 @@
/datum/disease/brainrot
name = "Brainrot"
max_stages = 4
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Mannitol"
cures = list(/datum/reagent/medicine/mannitol)
agent = "Cryptococcus Cosmosis"
viable_mobtypes = list(/mob/living/carbon/human)
cure_chance = 15//higher chance to cure, since two reagents are required
desc = "This disease destroys the braincells, causing brain fever, brain necrosis and general intoxication."
required_organs = list(/obj/item/organ/brain)
severity = DISEASE_SEVERITY_HARMFUL
/datum/disease/brainrot/stage_act() //Removed toxloss because damaging diseases are pretty horrible. Last round it killed the entire station because the cure didn't work -- Urist -ACTUALLY Removed rather than commented out, I don't see it returning - RR
..()
switch(stage)
if(2)
if(prob(2))
affected_mob.emote("blink")
if(prob(2))
affected_mob.emote("yawn")
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You don't feel like yourself.</span>")
if(prob(5))
affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1, 170)
affected_mob.updatehealth()
if(3)
if(prob(2))
affected_mob.emote("stare")
if(prob(2))
affected_mob.emote("drool")
if(prob(10))
affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2, 170)
affected_mob.updatehealth()
if(prob(2))
to_chat(affected_mob, "<span class='danger'>Your try to remember something important...but can't.</span>")
if(4)
if(prob(2))
affected_mob.emote("stare")
if(prob(2))
affected_mob.emote("drool")
if(prob(15))
affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3, 170)
affected_mob.updatehealth()
if(prob(2))
to_chat(affected_mob, "<span class='danger'>Strange buzzing fills your head, removing all thoughts.</span>")
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.Unconscious(rand(100,200))
if(prob(1))
affected_mob.emote("snore")
if(prob(15))
affected_mob.stuttering += 3
return
/datum/disease/brainrot
name = "Brainrot"
max_stages = 4
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Mannitol"
cures = list(/datum/reagent/medicine/mannitol)
agent = "Cryptococcus Cosmosis"
viable_mobtypes = list(/mob/living/carbon/human)
cure_chance = 15//higher chance to cure, since two reagents are required
desc = "This disease destroys the braincells, causing brain fever, brain necrosis and general intoxication."
required_organs = list(/obj/item/organ/brain)
severity = DISEASE_SEVERITY_HARMFUL
/datum/disease/brainrot/stage_act() //Removed toxloss because damaging diseases are pretty horrible. Last round it killed the entire station because the cure didn't work -- Urist -ACTUALLY Removed rather than commented out, I don't see it returning - RR
..()
switch(stage)
if(2)
if(prob(2))
affected_mob.emote("blink")
if(prob(2))
affected_mob.emote("yawn")
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You don't feel like yourself.</span>")
if(prob(5))
affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1, 170)
affected_mob.updatehealth()
if(3)
if(prob(2))
affected_mob.emote("stare")
if(prob(2))
affected_mob.emote("drool")
if(prob(10))
affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 2, 170)
affected_mob.updatehealth()
if(prob(2))
to_chat(affected_mob, "<span class='danger'>Your try to remember something important...but can't.</span>")
if(4)
if(prob(2))
affected_mob.emote("stare")
if(prob(2))
affected_mob.emote("drool")
if(prob(15))
affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3, 170)
affected_mob.updatehealth()
if(prob(2))
to_chat(affected_mob, "<span class='danger'>Strange buzzing fills your head, removing all thoughts.</span>")
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.Unconscious(rand(100,200))
if(prob(1))
affected_mob.emote("snore")
if(prob(15))
affected_mob.stuttering += 3
return
+52 -52
View File
@@ -1,53 +1,53 @@
/datum/disease/cold
name = "The Cold"
max_stages = 3
cure_text = "Rest & Spaceacillin"
cures = list(/datum/reagent/medicine/spaceacillin)
agent = "XY-rhinovirus"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
permeability_mod = 0.5
desc = "If left untreated the subject will contract the flu."
severity = DISEASE_SEVERITY_NONTHREAT
/datum/disease/cold/stage_act()
..()
switch(stage)
if(2)
if(affected_mob.lying && prob(40)) //changed FROM prob(10) until sleeping is fixed
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if(prob(1) && prob(5))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your throat feels sore.</span>")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Mucous runs down the back of your throat.</span>")
if(3)
if(affected_mob.lying && prob(25)) //changed FROM prob(5) until sleeping is fixed
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if(prob(1) && prob(1))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your throat feels sore.</span>")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Mucous runs down the back of your throat.</span>")
if(prob(1) && prob(50))
if(!affected_mob.disease_resistances.Find(/datum/disease/flu))
var/datum/disease/Flu = new /datum/disease/flu()
affected_mob.ForceContractDisease(Flu, FALSE, TRUE)
/datum/disease/cold
name = "The Cold"
max_stages = 3
cure_text = "Rest & Spaceacillin"
cures = list(/datum/reagent/medicine/spaceacillin)
agent = "XY-rhinovirus"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
permeability_mod = 0.5
desc = "If left untreated the subject will contract the flu."
severity = DISEASE_SEVERITY_NONTHREAT
/datum/disease/cold/stage_act()
..()
switch(stage)
if(2)
if(affected_mob.lying && prob(40)) //changed FROM prob(10) until sleeping is fixed
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if(prob(1) && prob(5))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your throat feels sore.</span>")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Mucous runs down the back of your throat.</span>")
if(3)
if(affected_mob.lying && prob(25)) //changed FROM prob(5) until sleeping is fixed
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if(prob(1) && prob(1))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your throat feels sore.</span>")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Mucous runs down the back of your throat.</span>")
if(prob(1) && prob(50))
if(!affected_mob.disease_resistances.Find(/datum/disease/flu))
var/datum/disease/Flu = new /datum/disease/flu()
affected_mob.ForceContractDisease(Flu, FALSE, TRUE)
cure()
+38 -38
View File
@@ -1,39 +1,39 @@
/datum/disease/cold9
name = "The Cold"
max_stages = 3
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Common Cold Anti-bodies & Spaceacillin"
cures = list(/datum/reagent/medicine/spaceacillin)
agent = "ICE9-rhinovirus"
viable_mobtypes = list(/mob/living/carbon/human)
desc = "If left untreated the subject will slow, as if partly frozen."
severity = DISEASE_SEVERITY_HARMFUL
/datum/disease/cold9/stage_act()
..()
switch(stage)
if(2)
affected_mob.adjust_bodytemperature(-10)
if(prob(1) && prob(10))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your throat feels sore.</span>")
if(prob(5))
to_chat(affected_mob, "<span class='danger'>You feel stiff.</span>")
if(3)
affected_mob.adjust_bodytemperature(-20)
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your throat feels sore.</span>")
if(prob(10))
/datum/disease/cold9
name = "The Cold"
max_stages = 3
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Common Cold Anti-bodies & Spaceacillin"
cures = list(/datum/reagent/medicine/spaceacillin)
agent = "ICE9-rhinovirus"
viable_mobtypes = list(/mob/living/carbon/human)
desc = "If left untreated the subject will slow, as if partly frozen."
severity = DISEASE_SEVERITY_HARMFUL
/datum/disease/cold9/stage_act()
..()
switch(stage)
if(2)
affected_mob.adjust_bodytemperature(-10)
if(prob(1) && prob(10))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your throat feels sore.</span>")
if(prob(5))
to_chat(affected_mob, "<span class='danger'>You feel stiff.</span>")
if(3)
affected_mob.adjust_bodytemperature(-20)
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your throat feels sore.</span>")
if(prob(10))
to_chat(affected_mob, "<span class='danger'>You feel stiff.</span>")
+74 -74
View File
@@ -1,74 +1,74 @@
/datum/disease/dnaspread
name = "Space Retrovirus"
max_stages = 4
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Mutadone"
cures = list(/datum/reagent/medicine/mutadone)
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
agent = "S4E1 retrovirus"
viable_mobtypes = list(/mob/living/carbon/human)
var/datum/dna/original_dna = null
var/transformed = 0
desc = "This disease transplants the genetic code of the initial vector into new hosts."
severity = DISEASE_SEVERITY_MEDIUM
/datum/disease/dnaspread/stage_act()
..()
if(!affected_mob.dna)
cure()
if((NOTRANSSTING in affected_mob.dna.species.species_traits) || (NO_DNA_COPY in affected_mob.dna.species.species_traits)) //Only species that can be spread by transformation sting can be spread by the retrovirus
cure()
if(!strain_data["dna"])
//Absorbs the target DNA.
strain_data["dna"] = new affected_mob.dna.type
affected_mob.dna.copy_dna(strain_data["dna"])
carrier = TRUE
stage = 4
return
switch(stage)
if(2 || 3) //Pretend to be a cold and give time to spread.
if(prob(8))
affected_mob.emote("sneeze")
if(prob(8))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your muscles ache.</span>")
if(prob(20))
affected_mob.take_bodypart_damage(1)
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your stomach hurts.</span>")
if(prob(20))
affected_mob.adjustToxLoss(2)
affected_mob.updatehealth()
if(4)
if(!transformed && !carrier)
//Save original dna for when the disease is cured.
original_dna = new affected_mob.dna.type
affected_mob.dna.copy_dna(original_dna)
to_chat(affected_mob, "<span class='danger'>You don't feel like yourself..</span>")
var/datum/dna/transform_dna = strain_data["dna"]
transform_dna.transfer_identity(affected_mob, transfer_SE = 1)
affected_mob.real_name = affected_mob.dna.real_name
affected_mob.updateappearance(mutcolor_update=1)
affected_mob.domutcheck()
transformed = 1
carrier = 1 //Just chill out at stage 4
return
/datum/disease/dnaspread/Destroy()
if (original_dna && transformed && affected_mob)
original_dna.transfer_identity(affected_mob, transfer_SE = 1)
affected_mob.real_name = affected_mob.dna.real_name
affected_mob.updateappearance(mutcolor_update=1)
affected_mob.domutcheck()
to_chat(affected_mob, "<span class='notice'>You feel more like yourself.</span>")
return ..()
/datum/disease/dnaspread
name = "Space Retrovirus"
max_stages = 4
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Mutadone"
cures = list(/datum/reagent/medicine/mutadone)
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
agent = "S4E1 retrovirus"
viable_mobtypes = list(/mob/living/carbon/human)
var/datum/dna/original_dna = null
var/transformed = 0
desc = "This disease transplants the genetic code of the initial vector into new hosts."
severity = DISEASE_SEVERITY_MEDIUM
/datum/disease/dnaspread/stage_act()
..()
if(!affected_mob.dna)
cure()
if((NOTRANSSTING in affected_mob.dna.species.species_traits) || (NO_DNA_COPY in affected_mob.dna.species.species_traits)) //Only species that can be spread by transformation sting can be spread by the retrovirus
cure()
if(!strain_data["dna"])
//Absorbs the target DNA.
strain_data["dna"] = new affected_mob.dna.type
affected_mob.dna.copy_dna(strain_data["dna"])
carrier = TRUE
stage = 4
return
switch(stage)
if(2 || 3) //Pretend to be a cold and give time to spread.
if(prob(8))
affected_mob.emote("sneeze")
if(prob(8))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your muscles ache.</span>")
if(prob(20))
affected_mob.take_bodypart_damage(1)
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your stomach hurts.</span>")
if(prob(20))
affected_mob.adjustToxLoss(2)
affected_mob.updatehealth()
if(4)
if(!transformed && !carrier)
//Save original dna for when the disease is cured.
original_dna = new affected_mob.dna.type
affected_mob.dna.copy_dna(original_dna)
to_chat(affected_mob, "<span class='danger'>You don't feel like yourself..</span>")
var/datum/dna/transform_dna = strain_data["dna"]
transform_dna.transfer_identity(affected_mob, transfer_SE = 1)
affected_mob.real_name = affected_mob.dna.real_name
affected_mob.updateappearance(mutcolor_update=1)
affected_mob.domutcheck()
transformed = 1
carrier = 1 //Just chill out at stage 4
return
/datum/disease/dnaspread/Destroy()
if (original_dna && transformed && affected_mob)
original_dna.transfer_identity(affected_mob, transfer_SE = 1)
affected_mob.real_name = affected_mob.dna.real_name
affected_mob.updateappearance(mutcolor_update=1)
affected_mob.domutcheck()
to_chat(affected_mob, "<span class='notice'>You feel more like yourself.</span>")
return ..()
+32 -32
View File
@@ -1,32 +1,32 @@
/datum/disease/fake_gbs
name = "GBS"
max_stages = 5
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Synaptizine & Sulfur"
cures = list(/datum/reagent/medicine/synaptizine,/datum/reagent/sulfur)
agent = "Gravitokinetic Bipotential SADS-"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
desc = "If left untreated death will occur."
severity = DISEASE_SEVERITY_BIOHAZARD
/datum/disease/fake_gbs/stage_act()
..()
switch(stage)
if(2)
if(prob(1))
affected_mob.emote("sneeze")
if(3)
if(prob(5))
affected_mob.emote("cough")
else if(prob(5))
affected_mob.emote("gasp")
if(prob(10))
to_chat(affected_mob, "<span class='danger'>You're starting to feel very weak...</span>")
if(4)
if(prob(10))
affected_mob.emote("cough")
if(5)
if(prob(10))
affected_mob.emote("cough")
/datum/disease/fake_gbs
name = "GBS"
max_stages = 5
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Synaptizine & Sulfur"
cures = list(/datum/reagent/medicine/synaptizine,/datum/reagent/sulfur)
agent = "Gravitokinetic Bipotential SADS-"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
desc = "If left untreated death will occur."
severity = DISEASE_SEVERITY_BIOHAZARD
/datum/disease/fake_gbs/stage_act()
..()
switch(stage)
if(2)
if(prob(1))
affected_mob.emote("sneeze")
if(3)
if(prob(5))
affected_mob.emote("cough")
else if(prob(5))
affected_mob.emote("gasp")
if(prob(10))
to_chat(affected_mob, "<span class='danger'>You're starting to feel very weak...</span>")
if(4)
if(prob(10))
affected_mob.emote("cough")
if(5)
if(prob(10))
affected_mob.emote("cough")
+54 -54
View File
@@ -1,54 +1,54 @@
/datum/disease/flu
name = "The Flu"
max_stages = 3
spread_text = "Airborne"
cure_text = "Spaceacillin"
cures = list(/datum/reagent/medicine/spaceacillin)
cure_chance = 10
agent = "H13N1 flu virion"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
permeability_mod = 0.75
desc = "If left untreated the subject will feel quite unwell."
severity = DISEASE_SEVERITY_MINOR
/datum/disease/flu/stage_act()
..()
switch(stage)
if(2)
if(affected_mob.lying && prob(20))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
stage--
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your muscles ache.</span>")
if(prob(20))
affected_mob.take_bodypart_damage(1)
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your stomach hurts.</span>")
if(prob(20))
affected_mob.adjustToxLoss(1)
affected_mob.updatehealth()
if(3)
if(affected_mob.lying && prob(15))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
stage--
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your muscles ache.</span>")
if(prob(20))
affected_mob.take_bodypart_damage(1)
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your stomach hurts.</span>")
if(prob(20))
affected_mob.adjustToxLoss(1)
affected_mob.updatehealth()
return
/datum/disease/flu
name = "The Flu"
max_stages = 3
spread_text = "Airborne"
cure_text = "Spaceacillin"
cures = list(/datum/reagent/medicine/spaceacillin)
cure_chance = 10
agent = "H13N1 flu virion"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
permeability_mod = 0.75
desc = "If left untreated the subject will feel quite unwell."
severity = DISEASE_SEVERITY_MINOR
/datum/disease/flu/stage_act()
..()
switch(stage)
if(2)
if(affected_mob.lying && prob(20))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
stage--
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your muscles ache.</span>")
if(prob(20))
affected_mob.take_bodypart_damage(1)
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your stomach hurts.</span>")
if(prob(20))
affected_mob.adjustToxLoss(1)
affected_mob.updatehealth()
if(3)
if(affected_mob.lying && prob(15))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
stage--
return
if(prob(1))
affected_mob.emote("sneeze")
if(prob(1))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your muscles ache.</span>")
if(prob(20))
affected_mob.take_bodypart_damage(1)
if(prob(1))
to_chat(affected_mob, "<span class='danger'>Your stomach hurts.</span>")
if(prob(20))
affected_mob.adjustToxLoss(1)
affected_mob.updatehealth()
return
+36 -36
View File
@@ -1,36 +1,36 @@
/datum/disease/fluspanish
name = "Spanish inquisition Flu"
max_stages = 3
spread_text = "Airborne"
cure_text = "Spaceacillin & Anti-bodies to the common flu"
cures = list(/datum/reagent/medicine/spaceacillin)
cure_chance = 10
agent = "1nqu1s1t10n flu virion"
viable_mobtypes = list(/mob/living/carbon/human)
permeability_mod = 0.75
desc = "If left untreated the subject will burn to death for being a heretic."
severity = DISEASE_SEVERITY_DANGEROUS
/datum/disease/fluspanish/stage_act()
..()
switch(stage)
if(2)
affected_mob.adjust_bodytemperature(10)
if(prob(5))
affected_mob.emote("sneeze")
if(prob(5))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>You're burning in your own skin!</span>")
affected_mob.take_bodypart_damage(0,5)
if(3)
affected_mob.adjust_bodytemperature(20)
if(prob(5))
affected_mob.emote("sneeze")
if(prob(5))
affected_mob.emote("cough")
if(prob(5))
to_chat(affected_mob, "<span class='danger'>You're burning in your own skin!</span>")
affected_mob.take_bodypart_damage(0,5)
return
/datum/disease/fluspanish
name = "Spanish inquisition Flu"
max_stages = 3
spread_text = "Airborne"
cure_text = "Spaceacillin & Anti-bodies to the common flu"
cures = list(/datum/reagent/medicine/spaceacillin)
cure_chance = 10
agent = "1nqu1s1t10n flu virion"
viable_mobtypes = list(/mob/living/carbon/human)
permeability_mod = 0.75
desc = "If left untreated the subject will burn to death for being a heretic."
severity = DISEASE_SEVERITY_DANGEROUS
/datum/disease/fluspanish/stage_act()
..()
switch(stage)
if(2)
affected_mob.adjust_bodytemperature(10)
if(prob(5))
affected_mob.emote("sneeze")
if(prob(5))
affected_mob.emote("cough")
if(prob(1))
to_chat(affected_mob, "<span class='danger'>You're burning in your own skin!</span>")
affected_mob.take_bodypart_damage(0,5)
if(3)
affected_mob.adjust_bodytemperature(20)
if(prob(5))
affected_mob.emote("sneeze")
if(prob(5))
affected_mob.emote("cough")
if(prob(5))
to_chat(affected_mob, "<span class='danger'>You're burning in your own skin!</span>")
affected_mob.take_bodypart_damage(0,5)
return
+31 -31
View File
@@ -1,31 +1,31 @@
/datum/disease/gbs
name = "GBS"
max_stages = 4
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Synaptizine & Sulfur"
cures = list(/datum/reagent/medicine/synaptizine,/datum/reagent/sulfur)
cure_chance = 15//higher chance to cure, since two reagents are required
agent = "Gravitokinetic Bipotential SADS+"
viable_mobtypes = list(/mob/living/carbon/human)
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
permeability_mod = 1
severity = DISEASE_SEVERITY_BIOHAZARD
/datum/disease/gbs/stage_act()
..()
switch(stage)
if(2)
if(prob(5))
affected_mob.emote("cough")
if(3)
if(prob(5))
affected_mob.emote("gasp")
if(prob(10))
to_chat(affected_mob, "<span class='danger'>Your body hurts all over!</span>")
if(4)
to_chat(affected_mob, "<span class='userdanger'>Your body feels as if it's trying to rip itself apart!</span>")
if(prob(50))
affected_mob.gib()
else
return
/datum/disease/gbs
name = "GBS"
max_stages = 4
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Synaptizine & Sulfur"
cures = list(/datum/reagent/medicine/synaptizine,/datum/reagent/sulfur)
cure_chance = 15//higher chance to cure, since two reagents are required
agent = "Gravitokinetic Bipotential SADS+"
viable_mobtypes = list(/mob/living/carbon/human)
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
permeability_mod = 1
severity = DISEASE_SEVERITY_BIOHAZARD
/datum/disease/gbs/stage_act()
..()
switch(stage)
if(2)
if(prob(5))
affected_mob.emote("cough")
if(3)
if(prob(5))
affected_mob.emote("gasp")
if(prob(10))
to_chat(affected_mob, "<span class='danger'>Your body hurts all over!</span>")
if(4)
to_chat(affected_mob, "<span class='userdanger'>Your body feels as if it's trying to rip itself apart!</span>")
if(prob(50))
affected_mob.gib()
else
return
+67 -67
View File
@@ -1,68 +1,68 @@
/datum/disease/magnitis
name = "Magnitis"
max_stages = 4
spread_text = "Airborne"
cure_text = "Iron"
cures = list(/datum/reagent/iron)
agent = "Fukkos Miracos"
viable_mobtypes = list(/mob/living/carbon/human)
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
permeability_mod = 0.75
desc = "This disease disrupts the magnetic field of your body, making it act as if a powerful magnet. Injections of iron help stabilize the field."
severity = DISEASE_SEVERITY_MEDIUM
infectable_biotypes = list(MOB_ORGANIC, MOB_ROBOTIC)
process_dead = TRUE
/datum/disease/magnitis/stage_act()
..()
switch(stage)
if(2)
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You feel a slight shock course through your body.</span>")
if(prob(2))
for(var/obj/M in orange(2,affected_mob))
if(!M.anchored && (M.flags_1 & CONDUCT_1))
step_towards(M,affected_mob)
for(var/mob/living/silicon/S in orange(2,affected_mob))
if(isAI(S))
continue
step_towards(S,affected_mob)
if(3)
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You feel a strong shock course through your body.</span>")
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You feel like clowning around.</span>")
if(prob(4))
for(var/obj/M in orange(4,affected_mob))
if(!M.anchored && (M.flags_1 & CONDUCT_1))
var/i
var/iter = rand(1,2)
for(i=0,i<iter,i++)
step_towards(M,affected_mob)
for(var/mob/living/silicon/S in orange(4,affected_mob))
if(isAI(S))
continue
var/i
var/iter = rand(1,2)
for(i=0,i<iter,i++)
step_towards(S,affected_mob)
if(4)
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You feel a powerful shock course through your body.</span>")
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You query upon the nature of miracles.</span>")
if(prob(8))
for(var/obj/M in orange(6,affected_mob))
if(!M.anchored && (M.flags_1 & CONDUCT_1))
var/i
var/iter = rand(1,3)
for(i=0,i<iter,i++)
step_towards(M,affected_mob)
for(var/mob/living/silicon/S in orange(6,affected_mob))
if(isAI(S))
continue
var/i
var/iter = rand(1,3)
for(i=0,i<iter,i++)
step_towards(S,affected_mob)
/datum/disease/magnitis
name = "Magnitis"
max_stages = 4
spread_text = "Airborne"
cure_text = "Iron"
cures = list(/datum/reagent/iron)
agent = "Fukkos Miracos"
viable_mobtypes = list(/mob/living/carbon/human)
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
permeability_mod = 0.75
desc = "This disease disrupts the magnetic field of your body, making it act as if a powerful magnet. Injections of iron help stabilize the field."
severity = DISEASE_SEVERITY_MEDIUM
infectable_biotypes = list(MOB_ORGANIC, MOB_ROBOTIC)
process_dead = TRUE
/datum/disease/magnitis/stage_act()
..()
switch(stage)
if(2)
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You feel a slight shock course through your body.</span>")
if(prob(2))
for(var/obj/M in orange(2,affected_mob))
if(!M.anchored && (M.flags_1 & CONDUCT_1))
step_towards(M,affected_mob)
for(var/mob/living/silicon/S in orange(2,affected_mob))
if(isAI(S))
continue
step_towards(S,affected_mob)
if(3)
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You feel a strong shock course through your body.</span>")
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You feel like clowning around.</span>")
if(prob(4))
for(var/obj/M in orange(4,affected_mob))
if(!M.anchored && (M.flags_1 & CONDUCT_1))
var/i
var/iter = rand(1,2)
for(i=0,i<iter,i++)
step_towards(M,affected_mob)
for(var/mob/living/silicon/S in orange(4,affected_mob))
if(isAI(S))
continue
var/i
var/iter = rand(1,2)
for(i=0,i<iter,i++)
step_towards(S,affected_mob)
if(4)
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You feel a powerful shock course through your body.</span>")
if(prob(2))
to_chat(affected_mob, "<span class='danger'>You query upon the nature of miracles.</span>")
if(prob(8))
for(var/obj/M in orange(6,affected_mob))
if(!M.anchored && (M.flags_1 & CONDUCT_1))
var/i
var/iter = rand(1,3)
for(i=0,i<iter,i++)
step_towards(M,affected_mob)
for(var/mob/living/silicon/S in orange(6,affected_mob))
if(isAI(S))
continue
var/i
var/iter = rand(1,3)
for(i=0,i<iter,i++)
step_towards(S,affected_mob)
return
+54 -54
View File
@@ -1,55 +1,55 @@
/datum/disease/pierrot_throat
name = "Pierrot's Throat"
max_stages = 4
spread_text = "Airborne"
cure_text = "Banana products, especially banana bread."
cures = list(/datum/reagent/consumable/banana)
cure_chance = 75
agent = "H0NI<42 Virus"
viable_mobtypes = list(/mob/living/carbon/human)
permeability_mod = 0.75
desc = "If left untreated the subject will probably drive others to insanity."
severity = DISEASE_SEVERITY_MEDIUM
/datum/disease/pierrot_throat/stage_act()
..()
switch(stage)
if(1)
if(prob(10))
to_chat(affected_mob, "<span class='danger'>You feel a little silly.</span>")
if(2)
if(prob(10))
to_chat(affected_mob, "<span class='danger'>You start seeing rainbows.</span>")
if(3)
if(prob(10))
to_chat(affected_mob, "<span class='danger'>Your thoughts are interrupted by a loud <b>HONK!</b></span>")
if(4)
if(prob(5))
affected_mob.say( pick( list("HONK!", "Honk!", "Honk.", "Honk?", "Honk!!", "Honk?!", "Honk...") ) , forced = "pierrot's throat")
/datum/disease/pierrot_throat/after_add()
RegisterSignal(affected_mob, COMSIG_MOB_SAY, .proc/handle_speech)
/datum/disease/pierrot_throat/proc/handle_speech(datum/source, list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
var/list/split_message = splittext(message, " ") //List each word in the message
var/applied = 0
for (var/i in 1 to length(split_message))
if(prob(3 * stage)) //Stage 1: 3% Stage 2: 6% Stage 3: 9% Stage 4: 12%
if(findtext(split_message[i], "*") || findtext(split_message[i], ";") || findtext(split_message[i], ":"))
continue
split_message[i] = "HONK"
if (applied++ > stage)
break
if (applied)
speech_args[SPEECH_SPANS] |= SPAN_CLOWN // a little bonus
message = jointext(split_message, " ")
speech_args[SPEECH_MESSAGE] = message
/datum/disease/pierrot_throat/Destroy()
UnregisterSignal(affected_mob, COMSIG_MOB_SAY)
return ..()
/datum/disease/pierrot_throat/remove_disease()
UnregisterSignal(affected_mob, COMSIG_MOB_SAY)
/datum/disease/pierrot_throat
name = "Pierrot's Throat"
max_stages = 4
spread_text = "Airborne"
cure_text = "Banana products, especially banana bread."
cures = list(/datum/reagent/consumable/banana)
cure_chance = 75
agent = "H0NI<42 Virus"
viable_mobtypes = list(/mob/living/carbon/human)
permeability_mod = 0.75
desc = "If left untreated the subject will probably drive others to insanity."
severity = DISEASE_SEVERITY_MEDIUM
/datum/disease/pierrot_throat/stage_act()
..()
switch(stage)
if(1)
if(prob(10))
to_chat(affected_mob, "<span class='danger'>You feel a little silly.</span>")
if(2)
if(prob(10))
to_chat(affected_mob, "<span class='danger'>You start seeing rainbows.</span>")
if(3)
if(prob(10))
to_chat(affected_mob, "<span class='danger'>Your thoughts are interrupted by a loud <b>HONK!</b></span>")
if(4)
if(prob(5))
affected_mob.say( pick( list("HONK!", "Honk!", "Honk.", "Honk?", "Honk!!", "Honk?!", "Honk...") ) , forced = "pierrot's throat")
/datum/disease/pierrot_throat/after_add()
RegisterSignal(affected_mob, COMSIG_MOB_SAY, .proc/handle_speech)
/datum/disease/pierrot_throat/proc/handle_speech(datum/source, list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
var/list/split_message = splittext(message, " ") //List each word in the message
var/applied = 0
for (var/i in 1 to length(split_message))
if(prob(3 * stage)) //Stage 1: 3% Stage 2: 6% Stage 3: 9% Stage 4: 12%
if(findtext(split_message[i], "*") || findtext(split_message[i], ";") || findtext(split_message[i], ":"))
continue
split_message[i] = "HONK"
if (applied++ > stage)
break
if (applied)
speech_args[SPEECH_SPANS] |= SPAN_CLOWN // a little bonus
message = jointext(split_message, " ")
speech_args[SPEECH_MESSAGE] = message
/datum/disease/pierrot_throat/Destroy()
UnregisterSignal(affected_mob, COMSIG_MOB_SAY)
return ..()
/datum/disease/pierrot_throat/remove_disease()
UnregisterSignal(affected_mob, COMSIG_MOB_SAY)
return ..()
+83 -83
View File
@@ -1,84 +1,84 @@
/datum/disease/dna_retrovirus
name = "Retrovirus"
max_stages = 4
spread_text = "Contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Rest or an injection of mutadone"
cure_chance = 6
agent = ""
viable_mobtypes = list(/mob/living/carbon/human)
desc = "A DNA-altering retrovirus that scrambles the structural and unique enzymes of a host constantly."
severity = DISEASE_SEVERITY_HARMFUL
permeability_mod = 0.4
stage_prob = 2
var/restcure = 0
/datum/disease/dna_retrovirus/New()
..()
agent = "Virus class [pick("A","B","C","D","E","F")][pick("A","B","C","D","E","F")]-[rand(50,300)]"
if(prob(40))
cures = list(/datum/reagent/medicine/mutadone)
else
restcure = 1
/datum/disease/dna_retrovirus/Copy()
var/datum/disease/dna_retrovirus/D = ..()
D.restcure = restcure
return D
/datum/disease/dna_retrovirus/stage_act()
..()
switch(stage)
if(1)
if(restcure)
if(affected_mob.lying && prob(30))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if (prob(8))
to_chat(affected_mob, "<span class='danger'>Your head hurts.</span>")
if (prob(9))
to_chat(affected_mob, "You feel a tingling sensation in your chest.")
if (prob(9))
to_chat(affected_mob, "<span class='danger'>You feel angry.</span>")
if(2)
if(restcure)
if(affected_mob.lying && prob(20))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if (prob(8))
to_chat(affected_mob, "<span class='danger'>Your skin feels loose.</span>")
if (prob(10))
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.Unconscious(40)
if (prob(4))
to_chat(affected_mob, "<span class='danger'>Your stomach churns.</span>")
if(3)
if(restcure)
if(affected_mob.lying && prob(20))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if (prob(10))
to_chat(affected_mob, "<span class='danger'>Your entire body vibrates.</span>")
if (prob(35))
if(prob(50))
scramble_dna(affected_mob, 1, 0, rand(15,45))
else
scramble_dna(affected_mob, 0, 1, rand(15,45))
if(4)
if(restcure)
if(affected_mob.lying && prob(5))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if (prob(60))
if(prob(50))
scramble_dna(affected_mob, 1, 0, rand(50,75))
else
/datum/disease/dna_retrovirus
name = "Retrovirus"
max_stages = 4
spread_text = "Contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Rest or an injection of mutadone"
cure_chance = 6
agent = ""
viable_mobtypes = list(/mob/living/carbon/human)
desc = "A DNA-altering retrovirus that scrambles the structural and unique enzymes of a host constantly."
severity = DISEASE_SEVERITY_HARMFUL
permeability_mod = 0.4
stage_prob = 2
var/restcure = 0
/datum/disease/dna_retrovirus/New()
..()
agent = "Virus class [pick("A","B","C","D","E","F")][pick("A","B","C","D","E","F")]-[rand(50,300)]"
if(prob(40))
cures = list(/datum/reagent/medicine/mutadone)
else
restcure = 1
/datum/disease/dna_retrovirus/Copy()
var/datum/disease/dna_retrovirus/D = ..()
D.restcure = restcure
return D
/datum/disease/dna_retrovirus/stage_act()
..()
switch(stage)
if(1)
if(restcure)
if(affected_mob.lying && prob(30))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if (prob(8))
to_chat(affected_mob, "<span class='danger'>Your head hurts.</span>")
if (prob(9))
to_chat(affected_mob, "You feel a tingling sensation in your chest.")
if (prob(9))
to_chat(affected_mob, "<span class='danger'>You feel angry.</span>")
if(2)
if(restcure)
if(affected_mob.lying && prob(20))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if (prob(8))
to_chat(affected_mob, "<span class='danger'>Your skin feels loose.</span>")
if (prob(10))
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.Unconscious(40)
if (prob(4))
to_chat(affected_mob, "<span class='danger'>Your stomach churns.</span>")
if(3)
if(restcure)
if(affected_mob.lying && prob(20))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if (prob(10))
to_chat(affected_mob, "<span class='danger'>Your entire body vibrates.</span>")
if (prob(35))
if(prob(50))
scramble_dna(affected_mob, 1, 0, rand(15,45))
else
scramble_dna(affected_mob, 0, 1, rand(15,45))
if(4)
if(restcure)
if(affected_mob.lying && prob(5))
to_chat(affected_mob, "<span class='notice'>You feel better.</span>")
cure()
return
if (prob(60))
if(prob(50))
scramble_dna(affected_mob, 1, 0, rand(50,75))
else
scramble_dna(affected_mob, 0, 1, rand(50,75))
+45 -45
View File
@@ -1,45 +1,45 @@
/datum/disease/rhumba_beat
name = "The Rhumba Beat"
max_stages = 5
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Chick Chicky Boom!"
cures = list(/datum/reagent/toxin/plasma)
agent = "Unknown"
viable_mobtypes = list(/mob/living/carbon/human)
permeability_mod = 1
severity = DISEASE_SEVERITY_BIOHAZARD
/datum/disease/rhumba_beat/stage_act()
..()
if(affected_mob.ckey == "rosham")
cure()
return
switch(stage)
if(2)
if(prob(45))
affected_mob.adjustFireLoss(5)
affected_mob.updatehealth()
if(prob(1))
to_chat(affected_mob, "<span class='danger'>You feel strange...</span>")
if(3)
if(prob(5))
to_chat(affected_mob, "<span class='danger'>You feel the urge to dance...</span>")
else if(prob(5))
affected_mob.emote("gasp")
else if(prob(10))
to_chat(affected_mob, "<span class='danger'>You feel the need to chick chicky boom...</span>")
if(4)
if(prob(20))
if (prob(50))
affected_mob.adjust_fire_stacks(2)
affected_mob.IgniteMob()
else
affected_mob.emote("gasp")
to_chat(affected_mob, "<span class='danger'>You feel a burning beat inside...</span>")
if(5)
to_chat(affected_mob, "<span class='danger'>Your body is unable to contain the Rhumba Beat...</span>")
if(prob(50))
explosion(get_turf(affected_mob), -1, 0, 2, 3, 0, 2) // This is equivalent to a lvl 1 fireball
else
return
/datum/disease/rhumba_beat
name = "The Rhumba Beat"
max_stages = 5
spread_text = "On contact"
spread_flags = DISEASE_SPREAD_BLOOD | DISEASE_SPREAD_CONTACT_SKIN | DISEASE_SPREAD_CONTACT_FLUIDS
cure_text = "Chick Chicky Boom!"
cures = list(/datum/reagent/toxin/plasma)
agent = "Unknown"
viable_mobtypes = list(/mob/living/carbon/human)
permeability_mod = 1
severity = DISEASE_SEVERITY_BIOHAZARD
/datum/disease/rhumba_beat/stage_act()
..()
if(affected_mob.ckey == "rosham")
cure()
return
switch(stage)
if(2)
if(prob(45))
affected_mob.adjustFireLoss(5)
affected_mob.updatehealth()
if(prob(1))
to_chat(affected_mob, "<span class='danger'>You feel strange...</span>")
if(3)
if(prob(5))
to_chat(affected_mob, "<span class='danger'>You feel the urge to dance...</span>")
else if(prob(5))
affected_mob.emote("gasp")
else if(prob(10))
to_chat(affected_mob, "<span class='danger'>You feel the need to chick chicky boom...</span>")
if(4)
if(prob(20))
if (prob(50))
affected_mob.adjust_fire_stacks(2)
affected_mob.IgniteMob()
else
affected_mob.emote("gasp")
to_chat(affected_mob, "<span class='danger'>You feel a burning beat inside...</span>")
if(5)
to_chat(affected_mob, "<span class='danger'>Your body is unable to contain the Rhumba Beat...</span>")
if(prob(50))
explosion(get_turf(affected_mob), -1, 0, 2, 3, 0, 2) // This is equivalent to a lvl 1 fireball
else
return
+327 -327
View File
@@ -1,327 +1,327 @@
/datum/disease/transformation
name = "Transformation"
max_stages = 5
spread_text = "Acute"
spread_flags = DISEASE_SPREAD_SPECIAL
cure_text = "A coder's love (theoretical)."
agent = "Shenanigans"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey, /mob/living/carbon/alien)
severity = DISEASE_SEVERITY_BIOHAZARD
stage_prob = 10
visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
disease_flags = CURABLE
var/list/stage1 = list("You feel unremarkable.")
var/list/stage2 = list("You feel boring.")
var/list/stage3 = list("You feel utterly plain.")
var/list/stage4 = list("You feel white bread.")
var/list/stage5 = list("Oh the humanity!")
var/new_form = /mob/living/carbon/human
var/bantype
/datum/disease/transformation/Copy()
var/datum/disease/transformation/D = ..()
D.stage1 = stage1.Copy()
D.stage2 = stage2.Copy()
D.stage3 = stage3.Copy()
D.stage4 = stage4.Copy()
D.stage5 = stage5.Copy()
D.new_form = D.new_form
return D
/datum/disease/transformation/stage_act()
..()
switch(stage)
if(1)
if (prob(stage_prob) && stage1)
to_chat(affected_mob, pick(stage1))
if(2)
if (prob(stage_prob) && stage2)
to_chat(affected_mob, pick(stage2))
if(3)
if (prob(stage_prob*2) && stage3)
to_chat(affected_mob, pick(stage3))
if(4)
if (prob(stage_prob*2) && stage4)
to_chat(affected_mob, pick(stage4))
if(5)
do_disease_transformation(affected_mob)
/datum/disease/transformation/proc/do_disease_transformation(mob/living/affected_mob)
if(istype(affected_mob, /mob/living/carbon) && affected_mob.stat != DEAD)
if(stage5)
to_chat(affected_mob, pick(stage5))
if(QDELETED(affected_mob))
return
if(affected_mob.notransform)
return
affected_mob.notransform = 1
for(var/obj/item/W in affected_mob.get_equipped_items(TRUE))
affected_mob.dropItemToGround(W)
for(var/obj/item/I in affected_mob.held_items)
affected_mob.dropItemToGround(I)
var/mob/living/new_mob = new new_form(affected_mob.loc)
if(istype(new_mob))
if(bantype && jobban_isbanned(affected_mob, bantype))
replace_banned_player(new_mob)
new_mob.a_intent = INTENT_HARM
if(affected_mob.mind)
affected_mob.mind.transfer_to(new_mob)
else
affected_mob.transfer_ckey(new_mob)
new_mob.name = affected_mob.real_name
new_mob.real_name = new_mob.name
qdel(affected_mob)
/datum/disease/transformation/proc/replace_banned_player(var/mob/living/new_mob) // This can run well after the mob has been transferred, so need a handle on the new mob to kill it if needed.
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [affected_mob.name]?", bantype, null, bantype, 50, affected_mob)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
to_chat(affected_mob, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(affected_mob)]) to replace a jobbaned player.")
affected_mob.ghostize(0)
C.transfer_ckey(affected_mob)
else
to_chat(new_mob, "Your mob has been claimed by death! Appeal your job ban if you want to avoid this in the future!")
new_mob.death()
if (!QDELETED(new_mob))
new_mob.ghostize(can_reenter_corpse = FALSE)
new_mob.key = null
/datum/disease/transformation/jungle_fever
name = "Jungle Fever"
cure_text = "Death."
cures = list(/datum/reagent/medicine/adminordrazine)
spread_text = "Monkey Bites"
spread_flags = DISEASE_SPREAD_SPECIAL
viable_mobtypes = list(/mob/living/carbon/monkey, /mob/living/carbon/human)
permeability_mod = 1
cure_chance = 1
disease_flags = CAN_CARRY|CAN_RESIST
desc = "Monkeys with this disease will bite humans, causing humans to mutate into a monkey."
severity = DISEASE_SEVERITY_BIOHAZARD
stage_prob = 4
visibility_flags = 0
agent = "Kongey Vibrion M-909"
new_form = /mob/living/carbon/monkey
bantype = ROLE_MONKEY
stage1 = list()
stage2 = list()
stage3 = list()
stage4 = list("<span class='warning'>Your back hurts.</span>", "<span class='warning'>You breathe through your mouth.</span>",
"<span class='warning'>You have a craving for bananas.</span>", "<span class='warning'>Your mind feels clouded.</span>")
stage5 = list("<span class='warning'>You feel like monkeying around.</span>")
/datum/disease/transformation/jungle_fever/do_disease_transformation(mob/living/carbon/affected_mob)
if(affected_mob.mind && !is_monkey(affected_mob.mind))
add_monkey(affected_mob.mind)
if(ishuman(affected_mob))
var/mob/living/carbon/monkey/M = affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
M.ventcrawler = VENTCRAWLER_ALWAYS
/datum/disease/transformation/jungle_fever/stage_act()
..()
switch(stage)
if(2)
if(prob(2))
to_chat(affected_mob, "<span class='notice'>Your [pick("back", "arm", "leg", "elbow", "head")] itches.</span>")
if(3)
if(prob(4))
to_chat(affected_mob, "<span class='danger'>You feel a stabbing pain in your head.</span>")
affected_mob.confused += 10
if(4)
if(prob(3))
affected_mob.say(pick("Eeek, ook ook!", "Eee-eeek!", "Eeee!", "Ungh, ungh."), forced = "jungle fever")
/datum/disease/transformation/jungle_fever/cure()
remove_monkey(affected_mob.mind)
..()
/datum/disease/transformation/jungle_fever/monkeymode
visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
disease_flags = CAN_CARRY //no vaccines! no cure!
/datum/disease/transformation/jungle_fever/monkeymode/after_add()
if(affected_mob && !is_monkey_leader(affected_mob.mind))
visibility_flags = NONE
/datum/disease/transformation/robot
name = "Robotic Transformation"
cure_text = "An injection of copper."
cures = list(/datum/reagent/copper)
cure_chance = 5
agent = "R2D2 Nanomachines"
desc = "This disease, actually acute nanomachine infection, converts the victim into a cyborg."
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list()
stage2 = list("Your joints feel stiff.", "<span class='danger'>Beep...boop..</span>")
stage3 = list("<span class='danger'>Your joints feel very stiff.</span>", "Your skin feels loose.", "<span class='danger'>You can feel something move...inside.</span>")
stage4 = list("<span class='danger'>Your skin feels very loose.</span>", "<span class='danger'>You can feel... something...inside you.</span>")
stage5 = list("<span class='danger'>Your skin feels as if it's about to burst off!</span>")
new_form = /mob/living/silicon/robot
infectable_biotypes = list(MOB_ORGANIC, MOB_UNDEAD, MOB_ROBOTIC)
bantype = "Cyborg"
/datum/disease/transformation/robot/stage_act()
..()
switch(stage)
if(3)
if (prob(8))
affected_mob.say(pick("Beep, boop", "beep, beep!", "Boop...bop"), forced = "robotic transformation")
if (prob(4))
to_chat(affected_mob, "<span class='danger'>You feel a stabbing pain in your head.</span>")
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..."), forced = "robotic transformation")
/datum/disease/transformation/xeno
name = "Xenomorph Transformation"
cure_text = "Spaceacillin & Glycerol"
cures = list(/datum/reagent/medicine/spaceacillin, /datum/reagent/glycerol)
cure_chance = 5
agent = "Rip-LEY Alien Microbes"
desc = "This disease changes the victim into a xenomorph."
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list()
stage2 = list("Your throat feels scratchy.", "<span class='danger'>Kill...</span>")
stage3 = list("<span class='danger'>Your throat feels very scratchy.</span>", "Your skin feels tight.", "<span class='danger'>You can feel something move...inside.</span>")
stage4 = list("<span class='danger'>Your skin feels very tight.</span>", "<span class='danger'>Your blood boils!</span>", "<span class='danger'>You can feel... something...inside you.</span>")
stage5 = list("<span class='danger'>Your skin feels as if it's about to burst off!</span>")
new_form = /mob/living/carbon/alien/humanoid/hunter
bantype = ROLE_ALIEN
/datum/disease/transformation/xeno/stage_act()
..()
switch(stage)
if(3)
if (prob(4))
to_chat(affected_mob, "<span class='danger'>You feel a stabbing pain in your head.</span>")
affected_mob.Unconscious(40)
if(4)
if (prob(20))
affected_mob.say(pick("You look delicious.", "Going to... devour you...", "Hsssshhhhh!"), forced = "xenomorph transformation")
/datum/disease/transformation/slime
name = "Advanced Mutation Transformation"
cure_text = "frost oil"
cures = list(/datum/reagent/consumable/frostoil)
cure_chance = 80
agent = "Advanced Mutation Toxin"
desc = "This highly concentrated extract converts anything into more of itself."
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list("You don't feel very well.")
stage2 = list("Your skin feels a little slimy.")
stage3 = list("<span class='danger'>Your appendages are melting away.</span>", "<span class='danger'>Your limbs begin to lose their shape.</span>")
stage4 = list("<span class='danger'>You are turning into a slime.</span>")
stage5 = list("<span class='danger'>You have become a slime.</span>")
new_form = /mob/living/simple_animal/slime/random
/datum/disease/transformation/slime/stage_act()
..()
switch(stage)
if(1)
if(ishuman(affected_mob) && affected_mob.dna)
if(affected_mob.dna.species.id == "slime" || affected_mob.dna.species.id == "stargazer" || affected_mob.dna.species.id == "lum")
stage = 5
if(3)
if(ishuman(affected_mob))
var/mob/living/carbon/human/human = affected_mob
if(human.dna.species.id != "slime" && affected_mob.dna.species.id != "stargazer" && affected_mob.dna.species.id != "lum")
human.set_species(/datum/species/jelly/slime)
/datum/disease/transformation/corgi
name = "The Barkening"
cure_text = "Death"
cures = list(/datum/reagent/medicine/adminordrazine)
agent = "Fell Doge Majicks"
desc = "This disease transforms the victim into a corgi."
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list("BARK.")
stage2 = list("You feel the need to wear silly hats.")
stage3 = list("<span class='danger'>Must... eat... chocolate....</span>", "<span class='danger'>YAP</span>")
stage4 = list("<span class='danger'>Visions of washing machines assail your mind!</span>")
stage5 = list("<span class='danger'>AUUUUUU!!!</span>")
new_form = /mob/living/simple_animal/pet/dog/corgi
/datum/disease/transformation/corgi/stage_act()
..()
switch(stage)
if(3)
if (prob(8))
affected_mob.say(pick("YAP", "Woof!"), forced = "corgi transformation")
if(4)
if (prob(20))
affected_mob.say(pick("Bark!", "AUUUUUU"), forced = "corgi transformation")
/datum/disease/transformation/morph
name = "Gluttony's Blessing"
cure_text = "nothing"
cures = list(/datum/reagent/medicine/adminordrazine)
agent = "Gluttony's Blessing"
desc = "A 'gift' from somewhere terrible."
stage_prob = 20
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list("Your stomach rumbles.")
stage2 = list("Your skin feels saggy.")
stage3 = list("<span class='danger'>Your appendages are melting away.</span>", "<span class='danger'>Your limbs begin to lose their shape.</span>")
stage4 = list("<span class='danger'>You're ravenous.</span>")
stage5 = list("<span class='danger'>You have become a morph.</span>")
new_form = /mob/living/simple_animal/hostile/morph
infectable_biotypes = list(MOB_ORGANIC, MOB_INORGANIC, MOB_UNDEAD) //magic!
/datum/disease/transformation/gondola
name = "Gondola Transformation"
cure_text = "Condensed Capsaicin, ingested or injected." //getting pepper sprayed doesn't help
cures = list(/datum/reagent/consumable/condensedcapsaicin) //beats the hippie crap right out of your system
cure_chance = 80
stage_prob = 5
agent = "Tranquility"
desc = "Consuming the flesh of a Gondola comes at a terrible price."
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list("You seem a little lighter in your step.")
stage2 = list("You catch yourself smiling for no reason.")
stage3 = list("<span class='danger'>A cruel sense of calm overcomes you.</span>", "<span class='danger'>You can't feel your arms!</span>", "<span class='danger'>You let go of the urge to hurt clowns.</span>")
stage4 = list("<span class='danger'>You can't feel your arms. It does not bother you anymore.</span>", "<span class='danger'>You forgive the clown for hurting you.</span>")
stage5 = list("<span class='danger'>You have become a Gondola.</span>")
new_form = /mob/living/simple_animal/pet/gondola
/datum/disease/transformation/gondola/stage_act()
..()
switch(stage)
if(2)
if (prob(5))
affected_mob.emote("smile")
if (prob(20))
affected_mob.reagents.add_reagent(/datum/reagent/pax, 5)
if(3)
if (prob(5))
affected_mob.emote("smile")
if (prob(20))
affected_mob.reagents.add_reagent(/datum/reagent/pax, 5)
if(4)
if (prob(5))
affected_mob.emote("smile")
if (prob(20))
affected_mob.reagents.add_reagent(/datum/reagent/pax, 5)
if (prob(2))
to_chat(affected_mob, "<span class='danger'>You let go of what you were holding.</span>")
var/obj/item/I = affected_mob.get_active_held_item()
affected_mob.dropItemToGround(I)
/datum/disease/transformation
name = "Transformation"
max_stages = 5
spread_text = "Acute"
spread_flags = DISEASE_SPREAD_SPECIAL
cure_text = "A coder's love (theoretical)."
agent = "Shenanigans"
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey, /mob/living/carbon/alien)
severity = DISEASE_SEVERITY_BIOHAZARD
stage_prob = 10
visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
disease_flags = CURABLE
var/list/stage1 = list("You feel unremarkable.")
var/list/stage2 = list("You feel boring.")
var/list/stage3 = list("You feel utterly plain.")
var/list/stage4 = list("You feel white bread.")
var/list/stage5 = list("Oh the humanity!")
var/new_form = /mob/living/carbon/human
var/bantype
/datum/disease/transformation/Copy()
var/datum/disease/transformation/D = ..()
D.stage1 = stage1.Copy()
D.stage2 = stage2.Copy()
D.stage3 = stage3.Copy()
D.stage4 = stage4.Copy()
D.stage5 = stage5.Copy()
D.new_form = D.new_form
return D
/datum/disease/transformation/stage_act()
..()
switch(stage)
if(1)
if (prob(stage_prob) && stage1)
to_chat(affected_mob, pick(stage1))
if(2)
if (prob(stage_prob) && stage2)
to_chat(affected_mob, pick(stage2))
if(3)
if (prob(stage_prob*2) && stage3)
to_chat(affected_mob, pick(stage3))
if(4)
if (prob(stage_prob*2) && stage4)
to_chat(affected_mob, pick(stage4))
if(5)
do_disease_transformation(affected_mob)
/datum/disease/transformation/proc/do_disease_transformation(mob/living/affected_mob)
if(istype(affected_mob, /mob/living/carbon) && affected_mob.stat != DEAD)
if(stage5)
to_chat(affected_mob, pick(stage5))
if(QDELETED(affected_mob))
return
if(affected_mob.notransform)
return
affected_mob.notransform = 1
for(var/obj/item/W in affected_mob.get_equipped_items(TRUE))
affected_mob.dropItemToGround(W)
for(var/obj/item/I in affected_mob.held_items)
affected_mob.dropItemToGround(I)
var/mob/living/new_mob = new new_form(affected_mob.loc)
if(istype(new_mob))
if(bantype && jobban_isbanned(affected_mob, bantype))
replace_banned_player(new_mob)
new_mob.a_intent = INTENT_HARM
if(affected_mob.mind)
affected_mob.mind.transfer_to(new_mob)
else
affected_mob.transfer_ckey(new_mob)
new_mob.name = affected_mob.real_name
new_mob.real_name = new_mob.name
qdel(affected_mob)
/datum/disease/transformation/proc/replace_banned_player(var/mob/living/new_mob) // This can run well after the mob has been transferred, so need a handle on the new mob to kill it if needed.
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [affected_mob.name]?", bantype, null, bantype, 50, affected_mob)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
to_chat(affected_mob, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(affected_mob)]) to replace a jobbaned player.")
affected_mob.ghostize(0)
C.transfer_ckey(affected_mob)
else
to_chat(new_mob, "Your mob has been claimed by death! Appeal your job ban if you want to avoid this in the future!")
new_mob.death()
if (!QDELETED(new_mob))
new_mob.ghostize(can_reenter_corpse = FALSE)
new_mob.key = null
/datum/disease/transformation/jungle_fever
name = "Jungle Fever"
cure_text = "Death."
cures = list(/datum/reagent/medicine/adminordrazine)
spread_text = "Monkey Bites"
spread_flags = DISEASE_SPREAD_SPECIAL
viable_mobtypes = list(/mob/living/carbon/monkey, /mob/living/carbon/human)
permeability_mod = 1
cure_chance = 1
disease_flags = CAN_CARRY|CAN_RESIST
desc = "Monkeys with this disease will bite humans, causing humans to mutate into a monkey."
severity = DISEASE_SEVERITY_BIOHAZARD
stage_prob = 4
visibility_flags = 0
agent = "Kongey Vibrion M-909"
new_form = /mob/living/carbon/monkey
bantype = ROLE_MONKEY
stage1 = list()
stage2 = list()
stage3 = list()
stage4 = list("<span class='warning'>Your back hurts.</span>", "<span class='warning'>You breathe through your mouth.</span>",
"<span class='warning'>You have a craving for bananas.</span>", "<span class='warning'>Your mind feels clouded.</span>")
stage5 = list("<span class='warning'>You feel like monkeying around.</span>")
/datum/disease/transformation/jungle_fever/do_disease_transformation(mob/living/carbon/affected_mob)
if(affected_mob.mind && !is_monkey(affected_mob.mind))
add_monkey(affected_mob.mind)
if(ishuman(affected_mob))
var/mob/living/carbon/monkey/M = affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
M.ventcrawler = VENTCRAWLER_ALWAYS
/datum/disease/transformation/jungle_fever/stage_act()
..()
switch(stage)
if(2)
if(prob(2))
to_chat(affected_mob, "<span class='notice'>Your [pick("back", "arm", "leg", "elbow", "head")] itches.</span>")
if(3)
if(prob(4))
to_chat(affected_mob, "<span class='danger'>You feel a stabbing pain in your head.</span>")
affected_mob.confused += 10
if(4)
if(prob(3))
affected_mob.say(pick("Eeek, ook ook!", "Eee-eeek!", "Eeee!", "Ungh, ungh."), forced = "jungle fever")
/datum/disease/transformation/jungle_fever/cure()
remove_monkey(affected_mob.mind)
..()
/datum/disease/transformation/jungle_fever/monkeymode
visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
disease_flags = CAN_CARRY //no vaccines! no cure!
/datum/disease/transformation/jungle_fever/monkeymode/after_add()
if(affected_mob && !is_monkey_leader(affected_mob.mind))
visibility_flags = NONE
/datum/disease/transformation/robot
name = "Robotic Transformation"
cure_text = "An injection of copper."
cures = list(/datum/reagent/copper)
cure_chance = 5
agent = "R2D2 Nanomachines"
desc = "This disease, actually acute nanomachine infection, converts the victim into a cyborg."
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list()
stage2 = list("Your joints feel stiff.", "<span class='danger'>Beep...boop..</span>")
stage3 = list("<span class='danger'>Your joints feel very stiff.</span>", "Your skin feels loose.", "<span class='danger'>You can feel something move...inside.</span>")
stage4 = list("<span class='danger'>Your skin feels very loose.</span>", "<span class='danger'>You can feel... something...inside you.</span>")
stage5 = list("<span class='danger'>Your skin feels as if it's about to burst off!</span>")
new_form = /mob/living/silicon/robot
infectable_biotypes = list(MOB_ORGANIC, MOB_UNDEAD, MOB_ROBOTIC)
bantype = "Cyborg"
/datum/disease/transformation/robot/stage_act()
..()
switch(stage)
if(3)
if (prob(8))
affected_mob.say(pick("Beep, boop", "beep, beep!", "Boop...bop"), forced = "robotic transformation")
if (prob(4))
to_chat(affected_mob, "<span class='danger'>You feel a stabbing pain in your head.</span>")
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..."), forced = "robotic transformation")
/datum/disease/transformation/xeno
name = "Xenomorph Transformation"
cure_text = "Spaceacillin & Glycerol"
cures = list(/datum/reagent/medicine/spaceacillin, /datum/reagent/glycerol)
cure_chance = 5
agent = "Rip-LEY Alien Microbes"
desc = "This disease changes the victim into a xenomorph."
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list()
stage2 = list("Your throat feels scratchy.", "<span class='danger'>Kill...</span>")
stage3 = list("<span class='danger'>Your throat feels very scratchy.</span>", "Your skin feels tight.", "<span class='danger'>You can feel something move...inside.</span>")
stage4 = list("<span class='danger'>Your skin feels very tight.</span>", "<span class='danger'>Your blood boils!</span>", "<span class='danger'>You can feel... something...inside you.</span>")
stage5 = list("<span class='danger'>Your skin feels as if it's about to burst off!</span>")
new_form = /mob/living/carbon/alien/humanoid/hunter
bantype = ROLE_ALIEN
/datum/disease/transformation/xeno/stage_act()
..()
switch(stage)
if(3)
if (prob(4))
to_chat(affected_mob, "<span class='danger'>You feel a stabbing pain in your head.</span>")
affected_mob.Unconscious(40)
if(4)
if (prob(20))
affected_mob.say(pick("You look delicious.", "Going to... devour you...", "Hsssshhhhh!"), forced = "xenomorph transformation")
/datum/disease/transformation/slime
name = "Advanced Mutation Transformation"
cure_text = "frost oil"
cures = list(/datum/reagent/consumable/frostoil)
cure_chance = 80
agent = "Advanced Mutation Toxin"
desc = "This highly concentrated extract converts anything into more of itself."
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list("You don't feel very well.")
stage2 = list("Your skin feels a little slimy.")
stage3 = list("<span class='danger'>Your appendages are melting away.</span>", "<span class='danger'>Your limbs begin to lose their shape.</span>")
stage4 = list("<span class='danger'>You are turning into a slime.</span>")
stage5 = list("<span class='danger'>You have become a slime.</span>")
new_form = /mob/living/simple_animal/slime/random
/datum/disease/transformation/slime/stage_act()
..()
switch(stage)
if(1)
if(ishuman(affected_mob) && affected_mob.dna)
if(affected_mob.dna.species.id == "slime" || affected_mob.dna.species.id == "stargazer" || affected_mob.dna.species.id == "lum")
stage = 5
if(3)
if(ishuman(affected_mob))
var/mob/living/carbon/human/human = affected_mob
if(human.dna.species.id != "slime" && affected_mob.dna.species.id != "stargazer" && affected_mob.dna.species.id != "lum")
human.set_species(/datum/species/jelly/slime)
/datum/disease/transformation/corgi
name = "The Barkening"
cure_text = "Death"
cures = list(/datum/reagent/medicine/adminordrazine)
agent = "Fell Doge Majicks"
desc = "This disease transforms the victim into a corgi."
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list("BARK.")
stage2 = list("You feel the need to wear silly hats.")
stage3 = list("<span class='danger'>Must... eat... chocolate....</span>", "<span class='danger'>YAP</span>")
stage4 = list("<span class='danger'>Visions of washing machines assail your mind!</span>")
stage5 = list("<span class='danger'>AUUUUUU!!!</span>")
new_form = /mob/living/simple_animal/pet/dog/corgi
/datum/disease/transformation/corgi/stage_act()
..()
switch(stage)
if(3)
if (prob(8))
affected_mob.say(pick("YAP", "Woof!"), forced = "corgi transformation")
if(4)
if (prob(20))
affected_mob.say(pick("Bark!", "AUUUUUU"), forced = "corgi transformation")
/datum/disease/transformation/morph
name = "Gluttony's Blessing"
cure_text = "nothing"
cures = list(/datum/reagent/medicine/adminordrazine)
agent = "Gluttony's Blessing"
desc = "A 'gift' from somewhere terrible."
stage_prob = 20
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list("Your stomach rumbles.")
stage2 = list("Your skin feels saggy.")
stage3 = list("<span class='danger'>Your appendages are melting away.</span>", "<span class='danger'>Your limbs begin to lose their shape.</span>")
stage4 = list("<span class='danger'>You're ravenous.</span>")
stage5 = list("<span class='danger'>You have become a morph.</span>")
new_form = /mob/living/simple_animal/hostile/morph
infectable_biotypes = list(MOB_ORGANIC, MOB_INORGANIC, MOB_UNDEAD) //magic!
/datum/disease/transformation/gondola
name = "Gondola Transformation"
cure_text = "Condensed Capsaicin, ingested or injected." //getting pepper sprayed doesn't help
cures = list(/datum/reagent/consumable/condensedcapsaicin) //beats the hippie crap right out of your system
cure_chance = 80
stage_prob = 5
agent = "Tranquility"
desc = "Consuming the flesh of a Gondola comes at a terrible price."
severity = DISEASE_SEVERITY_BIOHAZARD
visibility_flags = 0
stage1 = list("You seem a little lighter in your step.")
stage2 = list("You catch yourself smiling for no reason.")
stage3 = list("<span class='danger'>A cruel sense of calm overcomes you.</span>", "<span class='danger'>You can't feel your arms!</span>", "<span class='danger'>You let go of the urge to hurt clowns.</span>")
stage4 = list("<span class='danger'>You can't feel your arms. It does not bother you anymore.</span>", "<span class='danger'>You forgive the clown for hurting you.</span>")
stage5 = list("<span class='danger'>You have become a Gondola.</span>")
new_form = /mob/living/simple_animal/pet/gondola
/datum/disease/transformation/gondola/stage_act()
..()
switch(stage)
if(2)
if (prob(5))
affected_mob.emote("smile")
if (prob(20))
affected_mob.reagents.add_reagent(/datum/reagent/pax, 5)
if(3)
if (prob(5))
affected_mob.emote("smile")
if (prob(20))
affected_mob.reagents.add_reagent(/datum/reagent/pax, 5)
if(4)
if (prob(5))
affected_mob.emote("smile")
if (prob(20))
affected_mob.reagents.add_reagent(/datum/reagent/pax, 5)
if (prob(2))
to_chat(affected_mob, "<span class='danger'>You let go of what you were holding.</span>")
var/obj/item/I = affected_mob.get_active_held_item()
affected_mob.dropItemToGround(I)
+117 -117
View File
@@ -1,117 +1,117 @@
/datum/disease/wizarditis
name = "Wizarditis"
max_stages = 4
spread_text = "Airborne"
cure_text = "The Manly Dorf"
cures = list(/datum/reagent/consumable/ethanol/manly_dorf)
cure_chance = 100
agent = "Rincewindus Vulgaris"
viable_mobtypes = list(/mob/living/carbon/human)
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
permeability_mod = 0.75
desc = "Some speculate that this virus is the cause of the Space Wizard Federation's existence. Subjects affected show the signs of mental retardation, yelling obscure sentences or total gibberish. On late stages subjects sometime express the feelings of inner power, and, cite, 'the ability to control the forces of cosmos themselves!' A gulp of strong, manly spirits usually reverts them to normal, humanlike, condition."
severity = DISEASE_SEVERITY_HARMFUL
required_organs = list(/obj/item/bodypart/head)
/*
BIRUZ BENNAR
SCYAR NILA - teleport
NEC CANTIO - dis techno
EI NATH - shocking grasp
AULIE OXIN FIERA - knock
TARCOL MINTI ZHERI - forcewall
STI KALY - blind
*/
/datum/disease/wizarditis/stage_act()
..()
switch(stage)
if(2)
if(prob(1)&&prob(50))
affected_mob.say(pick("You shall not pass!", "Expeliarmus!", "By Merlins beard!", "Feel the power of the Dark Side!"), forced = "wizarditis")
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("that you don't have enough mana", "that the winds of magic are gone", "an urge to summon familiar")].</span>")
if(3)
if(prob(1)&&prob(50))
affected_mob.say(pick("NEC CANTIO!","AULIE OXIN FIERA!", "STI KALY!", "TARCOL MINTI ZHERI!"), forced = "wizarditis")
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("the magic bubbling in your veins","that this location gives you a +1 to INT","an urge to summon familiar")].</span>")
if(4)
if(prob(1))
affected_mob.say(pick("NEC CANTIO!","AULIE OXIN FIERA!","STI KALY!","EI NATH!"), forced = "wizarditis")
return
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("the tidal wave of raw power building inside","that this location gives you a +2 to INT and +1 to WIS","an urge to teleport")].</span>")
spawn_wizard_clothes(50)
if(prob(1)&&prob(1))
teleport()
return
/datum/disease/wizarditis/proc/spawn_wizard_clothes(chance = 0)
if(ishuman(affected_mob))
var/mob/living/carbon/human/H = affected_mob
if(prob(chance))
if(!istype(H.head, /obj/item/clothing/head/wizard))
if(!H.dropItemToGround(H.head))
qdel(H.head)
H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(H), SLOT_HEAD)
return
if(prob(chance))
if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe))
if(!H.dropItemToGround(H.wear_suit))
qdel(H.wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(H), SLOT_WEAR_SUIT)
return
if(prob(chance))
if(!istype(H.shoes, /obj/item/clothing/shoes/sandal/magic))
if(!H.dropItemToGround(H.shoes))
qdel(H.shoes)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/magic(H), SLOT_SHOES)
return
else
var/mob/living/carbon/H = affected_mob
if(prob(chance))
var/obj/item/staff/S = new(H)
if(!H.put_in_hands(S))
qdel(S)
/datum/disease/wizarditis/proc/teleport()
var/list/theareas = get_areas_in_range(80, affected_mob)
for(var/area/space/S in theareas)
theareas -= S
if(!theareas||!theareas.len)
return
var/area/thearea = pick(theareas)
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
if(T.z != affected_mob.z)
continue
if(T.name == "space")
continue
if(!T.density)
var/clear = 1
for(var/obj/O in T)
if(O.density)
clear = 0
break
if(clear)
L+=T
if(!L)
return
affected_mob.say("SCYAR NILA [uppertext(thearea.name)]!", forced = "wizarditis teleport")
affected_mob.forceMove(pick(L))
return
/datum/disease/wizarditis
name = "Wizarditis"
max_stages = 4
spread_text = "Airborne"
cure_text = "The Manly Dorf"
cures = list(/datum/reagent/consumable/ethanol/manly_dorf)
cure_chance = 100
agent = "Rincewindus Vulgaris"
viable_mobtypes = list(/mob/living/carbon/human)
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
permeability_mod = 0.75
desc = "Some speculate that this virus is the cause of the Space Wizard Federation's existence. Subjects affected show the signs of mental retardation, yelling obscure sentences or total gibberish. On late stages subjects sometime express the feelings of inner power, and, cite, 'the ability to control the forces of cosmos themselves!' A gulp of strong, manly spirits usually reverts them to normal, humanlike, condition."
severity = DISEASE_SEVERITY_HARMFUL
required_organs = list(/obj/item/bodypart/head)
/*
BIRUZ BENNAR
SCYAR NILA - teleport
NEC CANTIO - dis techno
EI NATH - shocking grasp
AULIE OXIN FIERA - knock
TARCOL MINTI ZHERI - forcewall
STI KALY - blind
*/
/datum/disease/wizarditis/stage_act()
..()
switch(stage)
if(2)
if(prob(1)&&prob(50))
affected_mob.say(pick("You shall not pass!", "Expeliarmus!", "By Merlins beard!", "Feel the power of the Dark Side!"), forced = "wizarditis")
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("that you don't have enough mana", "that the winds of magic are gone", "an urge to summon familiar")].</span>")
if(3)
if(prob(1)&&prob(50))
affected_mob.say(pick("NEC CANTIO!","AULIE OXIN FIERA!", "STI KALY!", "TARCOL MINTI ZHERI!"), forced = "wizarditis")
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("the magic bubbling in your veins","that this location gives you a +1 to INT","an urge to summon familiar")].</span>")
if(4)
if(prob(1))
affected_mob.say(pick("NEC CANTIO!","AULIE OXIN FIERA!","STI KALY!","EI NATH!"), forced = "wizarditis")
return
if(prob(1)&&prob(50))
to_chat(affected_mob, "<span class='danger'>You feel [pick("the tidal wave of raw power building inside","that this location gives you a +2 to INT and +1 to WIS","an urge to teleport")].</span>")
spawn_wizard_clothes(50)
if(prob(1)&&prob(1))
teleport()
return
/datum/disease/wizarditis/proc/spawn_wizard_clothes(chance = 0)
if(ishuman(affected_mob))
var/mob/living/carbon/human/H = affected_mob
if(prob(chance))
if(!istype(H.head, /obj/item/clothing/head/wizard))
if(!H.dropItemToGround(H.head))
qdel(H.head)
H.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(H), SLOT_HEAD)
return
if(prob(chance))
if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe))
if(!H.dropItemToGround(H.wear_suit))
qdel(H.wear_suit)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(H), SLOT_WEAR_SUIT)
return
if(prob(chance))
if(!istype(H.shoes, /obj/item/clothing/shoes/sandal/magic))
if(!H.dropItemToGround(H.shoes))
qdel(H.shoes)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/magic(H), SLOT_SHOES)
return
else
var/mob/living/carbon/H = affected_mob
if(prob(chance))
var/obj/item/staff/S = new(H)
if(!H.put_in_hands(S))
qdel(S)
/datum/disease/wizarditis/proc/teleport()
var/list/theareas = get_areas_in_range(80, affected_mob)
for(var/area/space/S in theareas)
theareas -= S
if(!theareas||!theareas.len)
return
var/area/thearea = pick(theareas)
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
if(T.z != affected_mob.z)
continue
if(T.name == "space")
continue
if(!T.density)
var/clear = 1
for(var/obj/O in T)
if(O.density)
clear = 0
break
if(clear)
L+=T
if(!L)
return
affected_mob.say("SCYAR NILA [uppertext(thearea.name)]!", forced = "wizarditis teleport")
affected_mob.forceMove(pick(L))
return
+619 -619
View File
File diff suppressed because it is too large Load Diff
+90 -90
View File
@@ -1,90 +1,90 @@
//Just new and forget
/datum/forced_movement
var/atom/movable/victim
var/atom/target
var/last_processed
var/steps_per_tick
var/allow_climbing
var/datum/callback/on_step
var/moved_at_all = FALSE
//as fast as ssfastprocess
/datum/forced_movement/New(atom/movable/_victim, atom/_target, _steps_per_tick = 0.5, _allow_climbing = FALSE, datum/callback/_on_step = null)
victim = _victim
target = _target
steps_per_tick = _steps_per_tick
allow_climbing = _allow_climbing
on_step = _on_step
. = ..()
if(_victim && _target && _steps_per_tick && !_victim.force_moving)
last_processed = world.time
_victim.force_moving = src
START_PROCESSING(SSfastprocess, src)
else
qdel(src) //if you want to overwrite the current forced movement, call qdel(victim.force_moving) before creating this
/datum/forced_movement/Destroy()
if(victim.force_moving == src)
victim.force_moving = null
if(moved_at_all)
victim.forceMove(victim.loc) //get the side effects of moving here that require us to currently not be force_moving aka reslipping on ice
STOP_PROCESSING(SSfastprocess, src)
victim = null
target = null
return ..()
/datum/forced_movement/process()
if(QDELETED(victim) || !victim.loc || QDELETED(target) || !target.loc)
qdel(src)
return
var/steps_to_take = round(steps_per_tick * (world.time - last_processed))
if(steps_to_take)
for(var/i in 1 to steps_to_take)
if(TryMove())
moved_at_all = TRUE
if(on_step)
on_step.InvokeAsync()
else
qdel(src)
return
last_processed = world.time
/datum/forced_movement/proc/TryMove(recursive = FALSE)
var/atom/movable/vic = victim //sanic
var/atom/tar = target
if(!recursive)
. = step_towards(vic, tar)
//shit way for getting around corners
if(!.)
if(tar.x > vic.x)
if(step(vic, EAST))
. = TRUE
else if(tar.x < vic.x)
if(step(vic, WEST))
. = TRUE
if(!.)
if(tar.y > vic.y)
if(step(vic, NORTH))
. = TRUE
else if(tar.y < vic.y)
if(step(vic, SOUTH))
. = TRUE
if(!.)
if(recursive)
return FALSE
else
. = TryMove(TRUE)
. = . && (vic.loc != tar.loc)
/mob/Bump(atom/A)
. = ..()
if(force_moving && force_moving.allow_climbing && isstructure(A))
var/obj/structure/S = A
if(S.climbable)
S.do_climb(src)
//Just new and forget
/datum/forced_movement
var/atom/movable/victim
var/atom/target
var/last_processed
var/steps_per_tick
var/allow_climbing
var/datum/callback/on_step
var/moved_at_all = FALSE
//as fast as ssfastprocess
/datum/forced_movement/New(atom/movable/_victim, atom/_target, _steps_per_tick = 0.5, _allow_climbing = FALSE, datum/callback/_on_step = null)
victim = _victim
target = _target
steps_per_tick = _steps_per_tick
allow_climbing = _allow_climbing
on_step = _on_step
. = ..()
if(_victim && _target && _steps_per_tick && !_victim.force_moving)
last_processed = world.time
_victim.force_moving = src
START_PROCESSING(SSfastprocess, src)
else
qdel(src) //if you want to overwrite the current forced movement, call qdel(victim.force_moving) before creating this
/datum/forced_movement/Destroy()
if(victim.force_moving == src)
victim.force_moving = null
if(moved_at_all)
victim.forceMove(victim.loc) //get the side effects of moving here that require us to currently not be force_moving aka reslipping on ice
STOP_PROCESSING(SSfastprocess, src)
victim = null
target = null
return ..()
/datum/forced_movement/process()
if(QDELETED(victim) || !victim.loc || QDELETED(target) || !target.loc)
qdel(src)
return
var/steps_to_take = round(steps_per_tick * (world.time - last_processed))
if(steps_to_take)
for(var/i in 1 to steps_to_take)
if(TryMove())
moved_at_all = TRUE
if(on_step)
on_step.InvokeAsync()
else
qdel(src)
return
last_processed = world.time
/datum/forced_movement/proc/TryMove(recursive = FALSE)
var/atom/movable/vic = victim //sanic
var/atom/tar = target
if(!recursive)
. = step_towards(vic, tar)
//shit way for getting around corners
if(!.)
if(tar.x > vic.x)
if(step(vic, EAST))
. = TRUE
else if(tar.x < vic.x)
if(step(vic, WEST))
. = TRUE
if(!.)
if(tar.y > vic.y)
if(step(vic, NORTH))
. = TRUE
else if(tar.y < vic.y)
if(step(vic, SOUTH))
. = TRUE
if(!.)
if(recursive)
return FALSE
else
. = TryMove(TRUE)
. = . && (vic.loc != tar.loc)
/mob/Bump(atom/A)
. = ..()
if(force_moving && force_moving.allow_climbing && isstructure(A))
var/obj/structure/S = A
if(S.climbable)
S.do_climb(src)
+121 -121
View File
@@ -1,122 +1,122 @@
/datum/getrev
var/commit // git rev-parse HEAD
var/date
var/originmastercommit // git rev-parse origin/master
var/list/testmerge = list()
/datum/getrev/New()
testmerge = world.TgsTestMerges()
var/datum/tgs_revision_information/revinfo = world.TgsRevision()
if(revinfo)
commit = revinfo.commit
originmastercommit = revinfo.origin_commit
else
commit = rustg_git_revparse("HEAD")
if(commit)
date = rustg_git_commit_date(commit)
originmastercommit = rustg_git_revparse("origin/master")
// goes to DD log and config_error.txt
log_world(get_log_message())
/datum/getrev/proc/get_log_message()
var/list/msg = list()
msg += "Running /tg/ revision: [date]"
if(originmastercommit)
msg += "origin/master: [originmastercommit]"
for(var/line in testmerge)
var/datum/tgs_revision_information/test_merge/tm = line
msg += "Test merge active of PR #[tm.number] commit [tm.commit]"
if(commit && commit != originmastercommit)
msg += "HEAD: [commit]"
else if(!originmastercommit)
msg += "No commit information"
return msg.Join("\n")
/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/datum/tgs_revision_information/test_merge/tm = line
var/cm = tm.pull_request_commit
var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 11)))
if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
continue
. += "<a href=\"[CONFIG_GET(string/githuburl)]/pull/[tm.number]\">#[tm.number][details]</a><br>"
/client/verb/showrevinfo()
set category = "OOC"
set name = "Show Server Revision"
set desc = "Check the current server code revision"
var/list/msg = list("")
// Round ID
if(GLOB.round_id)
msg += "<b>Round ID:</b> [GLOB.round_id]"
msg += "<b>BYOND Version:</b> [world.byond_version].[world.byond_build]"
if(DM_VERSION != world.byond_version || DM_BUILD != world.byond_build)
msg += "<b>Compiled with BYOND Version:</b> [DM_VERSION].[DM_BUILD]"
// Revision information
var/datum/getrev/revdata = GLOB.revdata
msg += "<b>Server revision compiled on:</b> [revdata.date]"
var/pc = revdata.originmastercommit
if(pc)
msg += "Master commit: <a href=\"[CONFIG_GET(string/githuburl)]/commit/[pc]\">[pc]</a>"
if(revdata.testmerge.len)
msg += revdata.GetTestMergeInfo()
if(revdata.commit && revdata.commit != revdata.originmastercommit)
msg += "Local commit: [revdata.commit]"
else if(!pc)
msg += "No commit information"
if(world.TgsAvailable())
msg += "Server tools version: [world.TgsVersion()]"
// Game mode odds
msg += "<br><b>Current Informational Settings:</b>"
msg += "Protect Authority Roles From Traitor: [CONFIG_GET(flag/protect_roles_from_antagonist)]"
msg += "Protect Assistant Role From Traitor: [CONFIG_GET(flag/protect_assistant_from_antagonist)]"
msg += "Enforce Human Authority: [CONFIG_GET(flag/enforce_human_authority)]"
msg += "Allow Latejoin Antagonists: [CONFIG_GET(flag/allow_latejoin_antagonists)]"
msg += "Enforce Continuous Rounds: [length(CONFIG_GET(keyed_list/continuous))] of [config.modes.len] roundtypes"
msg += "Allow Midround Antagonists: [length(CONFIG_GET(keyed_list/midround_antag))] of [config.modes.len] roundtypes"
if(CONFIG_GET(flag/show_game_type_odds))
var/list/probabilities = CONFIG_GET(keyed_list/probability)
if(SSticker.IsRoundInProgress())
var/prob_sum = 0
var/current_odds_differ = FALSE
var/list/probs = list()
var/list/modes = config.gamemode_cache
var/list/min_pop = CONFIG_GET(keyed_list/min_pop)
var/list/max_pop = CONFIG_GET(keyed_list/max_pop)
for(var/mode in modes)
var/datum/game_mode/M = mode
var/ctag = initial(M.config_tag)
if(!(ctag in probabilities))
continue
if((min_pop[ctag] && (min_pop[ctag] > SSticker.totalPlayersReady)) || (max_pop[ctag] && (max_pop[ctag] < SSticker.totalPlayersReady)) || (initial(M.required_players) > SSticker.totalPlayersReady))
current_odds_differ = TRUE
continue
probs[ctag] = 1
prob_sum += probabilities[ctag]
if(current_odds_differ)
msg += "<b>Game Mode Odds for current round:</b>"
for(var/ctag in probs)
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / prob_sum * 100, 0.1)
msg += "[ctag] [percentage]%"
msg += "<b>All Game Mode Odds:</b>"
var/sum = 0
for(var/ctag in probabilities)
sum += probabilities[ctag]
for(var/ctag in probabilities)
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / sum * 100, 0.1)
msg += "[ctag] [percentage]%"
/datum/getrev
var/commit // git rev-parse HEAD
var/date
var/originmastercommit // git rev-parse origin/master
var/list/testmerge = list()
/datum/getrev/New()
testmerge = world.TgsTestMerges()
var/datum/tgs_revision_information/revinfo = world.TgsRevision()
if(revinfo)
commit = revinfo.commit
originmastercommit = revinfo.origin_commit
else
commit = rustg_git_revparse("HEAD")
if(commit)
date = rustg_git_commit_date(commit)
originmastercommit = rustg_git_revparse("origin/master")
// goes to DD log and config_error.txt
log_world(get_log_message())
/datum/getrev/proc/get_log_message()
var/list/msg = list()
msg += "Running /tg/ revision: [date]"
if(originmastercommit)
msg += "origin/master: [originmastercommit]"
for(var/line in testmerge)
var/datum/tgs_revision_information/test_merge/tm = line
msg += "Test merge active of PR #[tm.number] commit [tm.commit]"
if(commit && commit != originmastercommit)
msg += "HEAD: [commit]"
else if(!originmastercommit)
msg += "No commit information"
return msg.Join("\n")
/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/datum/tgs_revision_information/test_merge/tm = line
var/cm = tm.pull_request_commit
var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 11)))
if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
continue
. += "<a href=\"[CONFIG_GET(string/githuburl)]/pull/[tm.number]\">#[tm.number][details]</a><br>"
/client/verb/showrevinfo()
set category = "OOC"
set name = "Show Server Revision"
set desc = "Check the current server code revision"
var/list/msg = list("")
// Round ID
if(GLOB.round_id)
msg += "<b>Round ID:</b> [GLOB.round_id]"
msg += "<b>BYOND Version:</b> [world.byond_version].[world.byond_build]"
if(DM_VERSION != world.byond_version || DM_BUILD != world.byond_build)
msg += "<b>Compiled with BYOND Version:</b> [DM_VERSION].[DM_BUILD]"
// Revision information
var/datum/getrev/revdata = GLOB.revdata
msg += "<b>Server revision compiled on:</b> [revdata.date]"
var/pc = revdata.originmastercommit
if(pc)
msg += "Master commit: <a href=\"[CONFIG_GET(string/githuburl)]/commit/[pc]\">[pc]</a>"
if(revdata.testmerge.len)
msg += revdata.GetTestMergeInfo()
if(revdata.commit && revdata.commit != revdata.originmastercommit)
msg += "Local commit: [revdata.commit]"
else if(!pc)
msg += "No commit information"
if(world.TgsAvailable())
msg += "Server tools version: [world.TgsVersion()]"
// Game mode odds
msg += "<br><b>Current Informational Settings:</b>"
msg += "Protect Authority Roles From Traitor: [CONFIG_GET(flag/protect_roles_from_antagonist)]"
msg += "Protect Assistant Role From Traitor: [CONFIG_GET(flag/protect_assistant_from_antagonist)]"
msg += "Enforce Human Authority: [CONFIG_GET(flag/enforce_human_authority)]"
msg += "Allow Latejoin Antagonists: [CONFIG_GET(flag/allow_latejoin_antagonists)]"
msg += "Enforce Continuous Rounds: [length(CONFIG_GET(keyed_list/continuous))] of [config.modes.len] roundtypes"
msg += "Allow Midround Antagonists: [length(CONFIG_GET(keyed_list/midround_antag))] of [config.modes.len] roundtypes"
if(CONFIG_GET(flag/show_game_type_odds))
var/list/probabilities = CONFIG_GET(keyed_list/probability)
if(SSticker.IsRoundInProgress())
var/prob_sum = 0
var/current_odds_differ = FALSE
var/list/probs = list()
var/list/modes = config.gamemode_cache
var/list/min_pop = CONFIG_GET(keyed_list/min_pop)
var/list/max_pop = CONFIG_GET(keyed_list/max_pop)
for(var/mode in modes)
var/datum/game_mode/M = mode
var/ctag = initial(M.config_tag)
if(!(ctag in probabilities))
continue
if((min_pop[ctag] && (min_pop[ctag] > SSticker.totalPlayersReady)) || (max_pop[ctag] && (max_pop[ctag] < SSticker.totalPlayersReady)) || (initial(M.required_players) > SSticker.totalPlayersReady))
current_odds_differ = TRUE
continue
probs[ctag] = 1
prob_sum += probabilities[ctag]
if(current_odds_differ)
msg += "<b>Game Mode Odds for current round:</b>"
for(var/ctag in probs)
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / prob_sum * 100, 0.1)
msg += "[ctag] [percentage]%"
msg += "<b>All Game Mode Odds:</b>"
var/sum = 0
for(var/ctag in probabilities)
sum += probabilities[ctag]
for(var/ctag in probabilities)
if(probabilities[ctag] > 0)
var/percentage = round(probabilities[ctag] / sum * 100, 0.1)
msg += "[ctag] [percentage]%"
to_chat(src, msg.Join("<br>"))
+167 -167
View File
@@ -1,167 +1,167 @@
// teleatom: atom to teleport
// destination: destination to teleport to
// precision: teleport precision (0 is most precise, the default)
// effectin: effect to show right before teleportation
// effectout: effect to show right after teleportation
// asoundin: soundfile to play before teleportation
// asoundout: soundfile to play after teleportation
// no_effects: disable the default effectin/effectout of sparks
// forceMove: if false, teleport will use Move() proc (dense objects will prevent teleportation)
// forced: whether or not to ignore no_teleport
/proc/do_teleport(atom/movable/teleatom, atom/destination, precision=null, forceMove = TRUE, datum/effect_system/effectin=null, datum/effect_system/effectout=null, asoundin=null, asoundout=null, no_effects=FALSE, channel=TELEPORT_CHANNEL_BLUESPACE, forced = FALSE)
// teleporting most effects just deletes them
var/static/list/delete_atoms = typecacheof(list(
/obj/effect,
)) - typecacheof(list(
/obj/effect/dummy/chameleon,
/obj/effect/wisp,
/obj/effect/mob_spawn
))
if(delete_atoms[teleatom.type])
qdel(teleatom)
return FALSE
// argument handling
// if the precision is not specified, default to 0, but apply BoH penalties
if (isnull(precision))
precision = 0
switch(channel)
if(TELEPORT_CHANNEL_BLUESPACE)
if(istype(teleatom, /obj/item/storage/backpack/holding))
precision = rand(1,100)
var/static/list/bag_cache = typecacheof(/obj/item/storage/backpack/holding)
var/list/bagholding = typecache_filter_list(teleatom.GetAllContents(), bag_cache)
if(bagholding.len)
precision = max(rand(1,100)*bagholding.len,100)
if(isliving(teleatom))
var/mob/living/MM = teleatom
to_chat(MM, "<span class='warning'>The bluespace interface on your bag of holding interferes with the teleport!</span>")
// if effects are not specified and not explicitly disabled, sparks
if ((!effectin || !effectout) && !no_effects)
var/datum/effect_system/spark_spread/sparks = new
sparks.set_up(5, 1, teleatom)
if (!effectin)
effectin = sparks
if (!effectout)
effectout = sparks
if(TELEPORT_CHANNEL_QUANTUM)
// if effects are not specified and not explicitly disabled, rainbow sparks
if ((!effectin || !effectout) && !no_effects)
var/datum/effect_system/spark_spread/quantum/sparks = new
sparks.set_up(5, 1, teleatom)
if (!effectin)
effectin = sparks
if (!effectout)
effectout = sparks
// perform the teleport
var/turf/curturf = get_turf(teleatom)
var/turf/destturf = get_teleport_turf(get_turf(destination), precision)
if(!destturf || !curturf || destturf.is_transition_turf())
return FALSE
var/area/A = get_area(curturf)
var/area/B = get_area(destturf)
if(!forced && (A.noteleport || B.noteleport))
return FALSE
if(SEND_SIGNAL(destturf, COMSIG_ATOM_INTERCEPT_TELEPORT, channel, curturf, destturf))
return FALSE
tele_play_specials(teleatom, curturf, effectin, asoundin)
var/success = forceMove ? teleatom.forceMove(destturf) : teleatom.Move(destturf)
if (success)
log_game("[key_name(teleatom)] has teleported from [loc_name(curturf)] to [loc_name(destturf)]")
tele_play_specials(teleatom, destturf, effectout, asoundout)
if(ismegafauna(teleatom))
message_admins("[teleatom] [ADMIN_FLW(teleatom)] has teleported from [ADMIN_VERBOSEJMP(curturf)] to [ADMIN_VERBOSEJMP(destturf)].")
SEND_SIGNAL(teleatom, COMSIG_MOVABLE_TELEPORTED, channel, curturf, destturf)
if(ismob(teleatom))
var/mob/M = teleatom
M.cancel_camera()
return TRUE
/proc/tele_play_specials(atom/movable/teleatom, atom/location, datum/effect_system/effect, sound)
if (location && !isobserver(teleatom))
if (sound)
playsound(location, sound, 60, 1)
if (effect)
effect.attach(location)
effect.start()
// Safe location finder
/proc/find_safe_turf(zlevel, list/zlevels, extended_safety_checks = FALSE)
if(!zlevels)
if (zlevel)
zlevels = list(zlevel)
else
zlevels = SSmapping.levels_by_trait(ZTRAIT_STATION)
var/cycles = 1000
for(var/cycle in 1 to cycles)
// DRUNK DIALLING WOOOOOOOOO
var/x = rand(1, world.maxx)
var/y = rand(1, world.maxy)
var/z = pick(zlevels)
var/random_location = locate(x,y,z)
if(!isfloorturf(random_location))
continue
var/turf/open/floor/F = random_location
if(!F.air)
continue
var/datum/gas_mixture/A = F.air
var/list/A_gases = A.gases
var/trace_gases
for(var/id in A_gases)
if(id in GLOB.hardcoded_gases)
continue
trace_gases = TRUE
break
// Can most things breathe?
if(trace_gases)
continue
if(A_gases[/datum/gas/oxygen] >= 16)
continue
if(A_gases[/datum/gas/plasma])
continue
if(A_gases[/datum/gas/carbon_dioxide] >= 10)
continue
// Aim for goldilocks temperatures and pressure
if((A.temperature <= 270) || (A.temperature >= 360))
continue
var/pressure = A.return_pressure()
if((pressure <= 20) || (pressure >= 550))
continue
if(extended_safety_checks)
if(islava(F)) //chasms aren't /floor, and so are pre-filtered
var/turf/open/lava/L = F
if(!L.is_safe())
continue
// 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))
// teleatom: atom to teleport
// destination: destination to teleport to
// precision: teleport precision (0 is most precise, the default)
// effectin: effect to show right before teleportation
// effectout: effect to show right after teleportation
// asoundin: soundfile to play before teleportation
// asoundout: soundfile to play after teleportation
// no_effects: disable the default effectin/effectout of sparks
// forceMove: if false, teleport will use Move() proc (dense objects will prevent teleportation)
// forced: whether or not to ignore no_teleport
/proc/do_teleport(atom/movable/teleatom, atom/destination, precision=null, forceMove = TRUE, datum/effect_system/effectin=null, datum/effect_system/effectout=null, asoundin=null, asoundout=null, no_effects=FALSE, channel=TELEPORT_CHANNEL_BLUESPACE, forced = FALSE)
// teleporting most effects just deletes them
var/static/list/delete_atoms = typecacheof(list(
/obj/effect,
)) - typecacheof(list(
/obj/effect/dummy/chameleon,
/obj/effect/wisp,
/obj/effect/mob_spawn
))
if(delete_atoms[teleatom.type])
qdel(teleatom)
return FALSE
// argument handling
// if the precision is not specified, default to 0, but apply BoH penalties
if (isnull(precision))
precision = 0
switch(channel)
if(TELEPORT_CHANNEL_BLUESPACE)
if(istype(teleatom, /obj/item/storage/backpack/holding))
precision = rand(1,100)
var/static/list/bag_cache = typecacheof(/obj/item/storage/backpack/holding)
var/list/bagholding = typecache_filter_list(teleatom.GetAllContents(), bag_cache)
if(bagholding.len)
precision = max(rand(1,100)*bagholding.len,100)
if(isliving(teleatom))
var/mob/living/MM = teleatom
to_chat(MM, "<span class='warning'>The bluespace interface on your bag of holding interferes with the teleport!</span>")
// if effects are not specified and not explicitly disabled, sparks
if ((!effectin || !effectout) && !no_effects)
var/datum/effect_system/spark_spread/sparks = new
sparks.set_up(5, 1, teleatom)
if (!effectin)
effectin = sparks
if (!effectout)
effectout = sparks
if(TELEPORT_CHANNEL_QUANTUM)
// if effects are not specified and not explicitly disabled, rainbow sparks
if ((!effectin || !effectout) && !no_effects)
var/datum/effect_system/spark_spread/quantum/sparks = new
sparks.set_up(5, 1, teleatom)
if (!effectin)
effectin = sparks
if (!effectout)
effectout = sparks
// perform the teleport
var/turf/curturf = get_turf(teleatom)
var/turf/destturf = get_teleport_turf(get_turf(destination), precision)
if(!destturf || !curturf || destturf.is_transition_turf())
return FALSE
var/area/A = get_area(curturf)
var/area/B = get_area(destturf)
if(!forced && (A.noteleport || B.noteleport))
return FALSE
if(SEND_SIGNAL(destturf, COMSIG_ATOM_INTERCEPT_TELEPORT, channel, curturf, destturf))
return FALSE
tele_play_specials(teleatom, curturf, effectin, asoundin)
var/success = forceMove ? teleatom.forceMove(destturf) : teleatom.Move(destturf)
if (success)
log_game("[key_name(teleatom)] has teleported from [loc_name(curturf)] to [loc_name(destturf)]")
tele_play_specials(teleatom, destturf, effectout, asoundout)
if(ismegafauna(teleatom))
message_admins("[teleatom] [ADMIN_FLW(teleatom)] has teleported from [ADMIN_VERBOSEJMP(curturf)] to [ADMIN_VERBOSEJMP(destturf)].")
SEND_SIGNAL(teleatom, COMSIG_MOVABLE_TELEPORTED, channel, curturf, destturf)
if(ismob(teleatom))
var/mob/M = teleatom
M.cancel_camera()
return TRUE
/proc/tele_play_specials(atom/movable/teleatom, atom/location, datum/effect_system/effect, sound)
if (location && !isobserver(teleatom))
if (sound)
playsound(location, sound, 60, 1)
if (effect)
effect.attach(location)
effect.start()
// Safe location finder
/proc/find_safe_turf(zlevel, list/zlevels, extended_safety_checks = FALSE)
if(!zlevels)
if (zlevel)
zlevels = list(zlevel)
else
zlevels = SSmapping.levels_by_trait(ZTRAIT_STATION)
var/cycles = 1000
for(var/cycle in 1 to cycles)
// DRUNK DIALLING WOOOOOOOOO
var/x = rand(1, world.maxx)
var/y = rand(1, world.maxy)
var/z = pick(zlevels)
var/random_location = locate(x,y,z)
if(!isfloorturf(random_location))
continue
var/turf/open/floor/F = random_location
if(!F.air)
continue
var/datum/gas_mixture/A = F.air
var/list/A_gases = A.gases
var/trace_gases
for(var/id in A_gases)
if(id in GLOB.hardcoded_gases)
continue
trace_gases = TRUE
break
// Can most things breathe?
if(trace_gases)
continue
if(A_gases[/datum/gas/oxygen] >= 16)
continue
if(A_gases[/datum/gas/plasma])
continue
if(A_gases[/datum/gas/carbon_dioxide] >= 10)
continue
// Aim for goldilocks temperatures and pressure
if((A.temperature <= 270) || (A.temperature >= 360))
continue
var/pressure = A.return_pressure()
if((pressure <= 20) || (pressure >= 550))
continue
if(extended_safety_checks)
if(islava(F)) //chasms aren't /floor, and so are pre-filtered
var/turf/open/lava/L = F
if(!L.is_safe())
continue
// 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))
+62 -62
View File
@@ -1,62 +1,62 @@
/datum/topic_input
var/href
var/list/href_list
/datum/topic_input/New(thref,list/thref_list)
href = thref
href_list = thref_list.Copy()
return
/datum/topic_input/proc/get(i)
return listgetindex(href_list,i)
/datum/topic_input/proc/getAndLocate(i)
var/t = get(i)
if(t)
t = locate(t)
if (istext(t))
t = null
return t || null
/datum/topic_input/proc/getNum(i)
var/t = get(i)
if(t)
t = text2num(t)
return isnum(t) ? t : null
/datum/topic_input/proc/getObj(i)
var/t = getAndLocate(i)
return isobj(t) ? t : null
/datum/topic_input/proc/getMob(i)
var/t = getAndLocate(i)
return ismob(t) ? t : null
/datum/topic_input/proc/getTurf(i)
var/t = getAndLocate(i)
return isturf(t) ? t : null
/datum/topic_input/proc/getAtom(i)
return getType(i, /atom)
/datum/topic_input/proc/getArea(i)
var/t = getAndLocate(i)
return isarea(t) ? t : null
/datum/topic_input/proc/getStr(i)//params should always be text, but...
var/t = get(i)
return istext(t) ? t : null
/datum/topic_input/proc/getType(i,type)
var/t = getAndLocate(i)
return istype(t,type) ? t : null
/datum/topic_input/proc/getPath(i)
var/t = get(i)
if(t)
t = text2path(t)
return ispath(t) ? t : null
/datum/topic_input/proc/getList(i)
var/t = getAndLocate(i)
return islist(t) ? t : null
/datum/topic_input
var/href
var/list/href_list
/datum/topic_input/New(thref,list/thref_list)
href = thref
href_list = thref_list.Copy()
return
/datum/topic_input/proc/get(i)
return listgetindex(href_list,i)
/datum/topic_input/proc/getAndLocate(i)
var/t = get(i)
if(t)
t = locate(t)
if (istext(t))
t = null
return t || null
/datum/topic_input/proc/getNum(i)
var/t = get(i)
if(t)
t = text2num(t)
return isnum(t) ? t : null
/datum/topic_input/proc/getObj(i)
var/t = getAndLocate(i)
return isobj(t) ? t : null
/datum/topic_input/proc/getMob(i)
var/t = getAndLocate(i)
return ismob(t) ? t : null
/datum/topic_input/proc/getTurf(i)
var/t = getAndLocate(i)
return isturf(t) ? t : null
/datum/topic_input/proc/getAtom(i)
return getType(i, /atom)
/datum/topic_input/proc/getArea(i)
var/t = getAndLocate(i)
return isarea(t) ? t : null
/datum/topic_input/proc/getStr(i)//params should always be text, but...
var/t = get(i)
return istext(t) ? t : null
/datum/topic_input/proc/getType(i,type)
var/t = getAndLocate(i)
return istype(t,type) ? t : null
/datum/topic_input/proc/getPath(i)
var/t = get(i)
if(t)
t = text2path(t)
return ispath(t) ? t : null
/datum/topic_input/proc/getList(i)
var/t = getAndLocate(i)
return islist(t) ? t : null
+352 -352
View File
@@ -1,352 +1,352 @@
#define HOLOPAD_MAX_DIAL_TIME 200
#define HOLORECORD_DELAY "delay"
#define HOLORECORD_SAY "say"
#define HOLORECORD_SOUND "sound"
#define HOLORECORD_LANGUAGE "lang"
#define HOLORECORD_PRESET "preset"
#define HOLORECORD_RENAME "rename"
#define HOLORECORD_MAX_LENGTH 200
/mob/camera/aiEye/remote/holo/setLoc()
. = ..()
var/obj/machinery/holopad/H = origin
H.move_hologram(eye_user, loc)
//this datum manages it's own references
/datum/holocall
var/mob/living/user //the one that called
var/obj/machinery/holopad/calling_holopad //the one that sent the call
var/obj/machinery/holopad/connected_holopad //the one that answered the call (may be null)
var/list/dialed_holopads //all things called, will be cleared out to just connected_holopad once answered
var/mob/camera/aiEye/remote/holo/eye //user's eye, once connected
var/obj/effect/overlay/holo_pad_hologram/hologram //user's hologram, once connected
var/datum/action/innate/end_holocall/hangup //hangup action
var/call_start_time
//creates a holocall made by `caller` from `calling_pad` to `callees`
/datum/holocall/New(mob/living/caller, obj/machinery/holopad/calling_pad, list/callees)
call_start_time = world.time
user = caller
calling_pad.outgoing_call = src
calling_holopad = calling_pad
dialed_holopads = list()
for(var/I in callees)
var/obj/machinery/holopad/H = I
if(!QDELETED(H) && H.is_operational())
dialed_holopads += H
H.say("Incoming call.")
LAZYADD(H.holo_calls, src)
if(!dialed_holopads.len)
calling_pad.say("Connection failure.")
qdel(src)
return
testing("Holocall started")
//cleans up ALL references :)
/datum/holocall/Destroy()
QDEL_NULL(hangup)
var/user_good = !QDELETED(user)
if(user_good)
user.reset_perspective()
user.remote_control = null
if(!QDELETED(eye))
QDEL_NULL(eye)
if(connected_holopad && !QDELETED(hologram))
hologram = null
connected_holopad.clear_holo(user)
user = null
//Hologram survived holopad destro
if(!QDELETED(hologram))
hologram.HC = null
QDEL_NULL(hologram)
for(var/I in dialed_holopads)
var/obj/machinery/holopad/H = I
LAZYREMOVE(H.holo_calls, src)
dialed_holopads.Cut()
if(calling_holopad)
calling_holopad.outgoing_call = null
calling_holopad.SetLightsAndPower()
calling_holopad = null
if(connected_holopad)
connected_holopad.SetLightsAndPower()
connected_holopad = null
testing("Holocall destroyed")
return ..()
//Gracefully disconnects a holopad `H` from a call. Pads not in the call are ignored. Notifies participants of the disconnection
/datum/holocall/proc/Disconnect(obj/machinery/holopad/H)
testing("Holocall disconnect")
if(H == connected_holopad)
var/area/A = get_area(connected_holopad)
calling_holopad.say("[A] holopad disconnected.")
else if(H == calling_holopad && connected_holopad)
connected_holopad.say("[user] disconnected.")
ConnectionFailure(H, TRUE)
//Forcefully disconnects a holopad `H` from a call. Pads not in the call are ignored.
/datum/holocall/proc/ConnectionFailure(obj/machinery/holopad/H, graceful = FALSE)
testing("Holocall connection failure: graceful [graceful]")
if(H == connected_holopad || H == calling_holopad)
if(!graceful && H != calling_holopad)
calling_holopad.say("Connection failure.")
qdel(src)
return
LAZYREMOVE(H.holo_calls, src)
dialed_holopads -= H
if(!dialed_holopads.len)
if(graceful)
calling_holopad.say("Call rejected.")
testing("No recipients, terminating")
qdel(src)
//Answers a call made to a holopad `H` which cannot be the calling holopad. Pads not in the call are ignored
/datum/holocall/proc/Answer(obj/machinery/holopad/H)
testing("Holocall answer")
if(H == calling_holopad)
CRASH("How cute, a holopad tried to answer itself.")
if(!(H in dialed_holopads))
return
if(connected_holopad)
CRASH("Multi-connection holocall")
for(var/I in dialed_holopads)
if(I == H)
continue
Disconnect(I)
for(var/I in H.holo_calls)
var/datum/holocall/HC = I
if(HC != src)
HC.Disconnect(H)
connected_holopad = H
if(!Check())
return
hologram = H.activate_holo(user)
hologram.HC = src
//eyeobj code is horrid, this is the best copypasta I could make
eye = new
eye.origin = H
eye.eye_initialized = TRUE
eye.eye_user = user
eye.name = "Camera Eye ([user.name])"
user.remote_control = eye
user.reset_perspective(eye)
eye.setLoc(H.loc)
hangup = new(eye, src)
hangup.Grant(user)
//Checks the validity of a holocall and qdels itself if it's not. Returns TRUE if valid, FALSE otherwise
/datum/holocall/proc/Check()
for(var/I in dialed_holopads)
var/obj/machinery/holopad/H = I
if(!H.is_operational())
ConnectionFailure(H)
if(QDELETED(src))
return FALSE
. = !QDELETED(user) && !user.incapacitated() && !QDELETED(calling_holopad) && calling_holopad.is_operational() && user.loc == calling_holopad.loc
if(.)
if(!connected_holopad)
. = world.time < (call_start_time + HOLOPAD_MAX_DIAL_TIME)
if(!.)
calling_holopad.say("No answer received.")
calling_holopad.temp = ""
if(!.)
testing("Holocall Check fail")
qdel(src)
/datum/action/innate/end_holocall
name = "End Holocall"
icon_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "camera_off"
var/datum/holocall/hcall
/datum/action/innate/end_holocall/New(Target, datum/holocall/HC)
..()
hcall = HC
/datum/action/innate/end_holocall/Activate()
hcall.Disconnect(hcall.calling_holopad)
//RECORDS
/datum/holorecord
var/caller_name = "Unknown" //Caller name
var/image/caller_image
var/list/entries = list()
var/language = /datum/language/common //Initial language, can be changed by HOLORECORD_LANGUAGE entries
/datum/holorecord/proc/set_caller_image(mob/user)
var/olddir = user.dir
user.setDir(SOUTH)
caller_image = image(user)
user.setDir(olddir)
/obj/item/disk/holodisk
name = "holorecord disk"
desc = "Stores recorder holocalls."
icon_state = "holodisk"
obj_flags = UNIQUE_RENAME
materials = list(MAT_METAL = 100, MAT_GLASS = 100)
var/datum/holorecord/record
//Preset variables
var/preset_image_type
var/preset_record_text
/obj/item/disk/holodisk/Initialize(mapload)
. = ..()
if(preset_record_text)
build_record()
/obj/item/disk/holodisk/Destroy()
QDEL_NULL(record)
return ..()
/obj/item/disk/holodisk/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/disk/holodisk))
var/obj/item/disk/holodisk/holodiskOriginal = W
if (holodiskOriginal.record)
if (!record)
record = new
record.caller_name = holodiskOriginal.record.caller_name
record.caller_image = holodiskOriginal.record.caller_image
record.entries = holodiskOriginal.record.entries.Copy()
record.language = holodiskOriginal.record.language
to_chat(user, "You copy the record from [holodiskOriginal] to [src] by connecting the ports!")
name = holodiskOriginal.name
else
to_chat(user, "[holodiskOriginal] has no record on it!")
..()
/obj/item/disk/holodisk/proc/build_record()
record = new
var/list/lines = splittext(preset_record_text,"\n")
for(var/line in lines)
var/prepared_line = trim(line)
if(!length(prepared_line))
continue
var/splitpoint = findtext(prepared_line," ")
if(!splitpoint)
continue
var/command = copytext(prepared_line,1,splitpoint)
var/value = copytext(prepared_line,splitpoint+1)
switch(command)
if("DELAY")
var/delay_value = text2num(value)
if(!delay_value)
continue
record.entries += list(list(HOLORECORD_DELAY,delay_value))
if("NAME")
if(!record.caller_name)
record.caller_name = value
else
record.entries += list(list(HOLORECORD_RENAME,value))
if("SAY")
record.entries += list(list(HOLORECORD_SAY,value))
if("SOUND")
record.entries += list(list(HOLORECORD_SOUND,value))
if("LANGUAGE")
var/lang_type = text2path(value)
if(ispath(lang_type,/datum/language))
record.entries += list(list(HOLORECORD_LANGUAGE,lang_type))
if("PRESET")
var/preset_type = text2path(value)
if(ispath(preset_type,/datum/preset_holoimage))
record.entries += list(list(HOLORECORD_PRESET,preset_type))
if(!preset_image_type)
record.caller_image = image('icons/mob/animal.dmi',"old")
else
var/datum/preset_holoimage/H = new preset_image_type
record.caller_image = H.build_image()
//These build caller image from outfit and some additional data, for use by mappers for ruin holorecords
/datum/preset_holoimage
var/nonhuman_mobtype //Fill this if you just want something nonhuman
var/outfit_type
var/species_type = /datum/species/human
/datum/preset_holoimage/proc/build_image()
if(nonhuman_mobtype)
var/mob/living/L = nonhuman_mobtype
. = image(initial(L.icon),initial(L.icon_state))
else
var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy("HOLODISK_PRESET")
if(species_type)
mannequin.set_species(species_type)
if(outfit_type)
mannequin.equipOutfit(outfit_type,TRUE)
mannequin.setDir(SOUTH)
COMPILE_OVERLAYS(mannequin)
. = image(mannequin)
unset_busy_human_dummy("HOLODISK_PRESET")
/obj/item/disk/holodisk/example
preset_image_type = /datum/preset_holoimage/clown
preset_record_text = {"
NAME Clown
DELAY 10
SAY Why did the chaplain cross the maint ?
DELAY 20
SAY He wanted to get to the other side!
SOUND clownstep
DELAY 30
LANGUAGE /datum/language/narsie
SAY Helped him get there!
DELAY 10
SAY ALSO IM SECRETLY A GORILLA
DELAY 10
PRESET /datum/preset_holoimage/gorilla
NAME Gorilla
LANGUAGE /datum/language/common
SAY OOGA
DELAY 20"}
/datum/preset_holoimage/engineer
outfit_type = /datum/outfit/job/engineer/gloved/rig
/datum/preset_holoimage/researcher
outfit_type = /datum/outfit/job/scientist
/datum/preset_holoimage/captain
outfit_type = /datum/outfit/job/captain
/datum/preset_holoimage/nanotrasenprivatesecurity
outfit_type = /datum/outfit/nanotrasensoldiercorpse2
/datum/preset_holoimage/gorilla
nonhuman_mobtype = /mob/living/simple_animal/hostile/gorilla
/datum/preset_holoimage/corgi
nonhuman_mobtype = /mob/living/simple_animal/pet/dog/corgi
/datum/preset_holoimage/clown
outfit_type = /datum/outfit/job/clown
#define HOLOPAD_MAX_DIAL_TIME 200
#define HOLORECORD_DELAY "delay"
#define HOLORECORD_SAY "say"
#define HOLORECORD_SOUND "sound"
#define HOLORECORD_LANGUAGE "lang"
#define HOLORECORD_PRESET "preset"
#define HOLORECORD_RENAME "rename"
#define HOLORECORD_MAX_LENGTH 200
/mob/camera/aiEye/remote/holo/setLoc()
. = ..()
var/obj/machinery/holopad/H = origin
H.move_hologram(eye_user, loc)
//this datum manages it's own references
/datum/holocall
var/mob/living/user //the one that called
var/obj/machinery/holopad/calling_holopad //the one that sent the call
var/obj/machinery/holopad/connected_holopad //the one that answered the call (may be null)
var/list/dialed_holopads //all things called, will be cleared out to just connected_holopad once answered
var/mob/camera/aiEye/remote/holo/eye //user's eye, once connected
var/obj/effect/overlay/holo_pad_hologram/hologram //user's hologram, once connected
var/datum/action/innate/end_holocall/hangup //hangup action
var/call_start_time
//creates a holocall made by `caller` from `calling_pad` to `callees`
/datum/holocall/New(mob/living/caller, obj/machinery/holopad/calling_pad, list/callees)
call_start_time = world.time
user = caller
calling_pad.outgoing_call = src
calling_holopad = calling_pad
dialed_holopads = list()
for(var/I in callees)
var/obj/machinery/holopad/H = I
if(!QDELETED(H) && H.is_operational())
dialed_holopads += H
H.say("Incoming call.")
LAZYADD(H.holo_calls, src)
if(!dialed_holopads.len)
calling_pad.say("Connection failure.")
qdel(src)
return
testing("Holocall started")
//cleans up ALL references :)
/datum/holocall/Destroy()
QDEL_NULL(hangup)
var/user_good = !QDELETED(user)
if(user_good)
user.reset_perspective()
user.remote_control = null
if(!QDELETED(eye))
QDEL_NULL(eye)
if(connected_holopad && !QDELETED(hologram))
hologram = null
connected_holopad.clear_holo(user)
user = null
//Hologram survived holopad destro
if(!QDELETED(hologram))
hologram.HC = null
QDEL_NULL(hologram)
for(var/I in dialed_holopads)
var/obj/machinery/holopad/H = I
LAZYREMOVE(H.holo_calls, src)
dialed_holopads.Cut()
if(calling_holopad)
calling_holopad.outgoing_call = null
calling_holopad.SetLightsAndPower()
calling_holopad = null
if(connected_holopad)
connected_holopad.SetLightsAndPower()
connected_holopad = null
testing("Holocall destroyed")
return ..()
//Gracefully disconnects a holopad `H` from a call. Pads not in the call are ignored. Notifies participants of the disconnection
/datum/holocall/proc/Disconnect(obj/machinery/holopad/H)
testing("Holocall disconnect")
if(H == connected_holopad)
var/area/A = get_area(connected_holopad)
calling_holopad.say("[A] holopad disconnected.")
else if(H == calling_holopad && connected_holopad)
connected_holopad.say("[user] disconnected.")
ConnectionFailure(H, TRUE)
//Forcefully disconnects a holopad `H` from a call. Pads not in the call are ignored.
/datum/holocall/proc/ConnectionFailure(obj/machinery/holopad/H, graceful = FALSE)
testing("Holocall connection failure: graceful [graceful]")
if(H == connected_holopad || H == calling_holopad)
if(!graceful && H != calling_holopad)
calling_holopad.say("Connection failure.")
qdel(src)
return
LAZYREMOVE(H.holo_calls, src)
dialed_holopads -= H
if(!dialed_holopads.len)
if(graceful)
calling_holopad.say("Call rejected.")
testing("No recipients, terminating")
qdel(src)
//Answers a call made to a holopad `H` which cannot be the calling holopad. Pads not in the call are ignored
/datum/holocall/proc/Answer(obj/machinery/holopad/H)
testing("Holocall answer")
if(H == calling_holopad)
CRASH("How cute, a holopad tried to answer itself.")
if(!(H in dialed_holopads))
return
if(connected_holopad)
CRASH("Multi-connection holocall")
for(var/I in dialed_holopads)
if(I == H)
continue
Disconnect(I)
for(var/I in H.holo_calls)
var/datum/holocall/HC = I
if(HC != src)
HC.Disconnect(H)
connected_holopad = H
if(!Check())
return
hologram = H.activate_holo(user)
hologram.HC = src
//eyeobj code is horrid, this is the best copypasta I could make
eye = new
eye.origin = H
eye.eye_initialized = TRUE
eye.eye_user = user
eye.name = "Camera Eye ([user.name])"
user.remote_control = eye
user.reset_perspective(eye)
eye.setLoc(H.loc)
hangup = new(eye, src)
hangup.Grant(user)
//Checks the validity of a holocall and qdels itself if it's not. Returns TRUE if valid, FALSE otherwise
/datum/holocall/proc/Check()
for(var/I in dialed_holopads)
var/obj/machinery/holopad/H = I
if(!H.is_operational())
ConnectionFailure(H)
if(QDELETED(src))
return FALSE
. = !QDELETED(user) && !user.incapacitated() && !QDELETED(calling_holopad) && calling_holopad.is_operational() && user.loc == calling_holopad.loc
if(.)
if(!connected_holopad)
. = world.time < (call_start_time + HOLOPAD_MAX_DIAL_TIME)
if(!.)
calling_holopad.say("No answer received.")
calling_holopad.temp = ""
if(!.)
testing("Holocall Check fail")
qdel(src)
/datum/action/innate/end_holocall
name = "End Holocall"
icon_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "camera_off"
var/datum/holocall/hcall
/datum/action/innate/end_holocall/New(Target, datum/holocall/HC)
..()
hcall = HC
/datum/action/innate/end_holocall/Activate()
hcall.Disconnect(hcall.calling_holopad)
//RECORDS
/datum/holorecord
var/caller_name = "Unknown" //Caller name
var/image/caller_image
var/list/entries = list()
var/language = /datum/language/common //Initial language, can be changed by HOLORECORD_LANGUAGE entries
/datum/holorecord/proc/set_caller_image(mob/user)
var/olddir = user.dir
user.setDir(SOUTH)
caller_image = image(user)
user.setDir(olddir)
/obj/item/disk/holodisk
name = "holorecord disk"
desc = "Stores recorder holocalls."
icon_state = "holodisk"
obj_flags = UNIQUE_RENAME
materials = list(MAT_METAL = 100, MAT_GLASS = 100)
var/datum/holorecord/record
//Preset variables
var/preset_image_type
var/preset_record_text
/obj/item/disk/holodisk/Initialize(mapload)
. = ..()
if(preset_record_text)
build_record()
/obj/item/disk/holodisk/Destroy()
QDEL_NULL(record)
return ..()
/obj/item/disk/holodisk/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/disk/holodisk))
var/obj/item/disk/holodisk/holodiskOriginal = W
if (holodiskOriginal.record)
if (!record)
record = new
record.caller_name = holodiskOriginal.record.caller_name
record.caller_image = holodiskOriginal.record.caller_image
record.entries = holodiskOriginal.record.entries.Copy()
record.language = holodiskOriginal.record.language
to_chat(user, "You copy the record from [holodiskOriginal] to [src] by connecting the ports!")
name = holodiskOriginal.name
else
to_chat(user, "[holodiskOriginal] has no record on it!")
..()
/obj/item/disk/holodisk/proc/build_record()
record = new
var/list/lines = splittext(preset_record_text,"\n")
for(var/line in lines)
var/prepared_line = trim(line)
if(!length(prepared_line))
continue
var/splitpoint = findtext(prepared_line," ")
if(!splitpoint)
continue
var/command = copytext(prepared_line,1,splitpoint)
var/value = copytext(prepared_line,splitpoint+1)
switch(command)
if("DELAY")
var/delay_value = text2num(value)
if(!delay_value)
continue
record.entries += list(list(HOLORECORD_DELAY,delay_value))
if("NAME")
if(!record.caller_name)
record.caller_name = value
else
record.entries += list(list(HOLORECORD_RENAME,value))
if("SAY")
record.entries += list(list(HOLORECORD_SAY,value))
if("SOUND")
record.entries += list(list(HOLORECORD_SOUND,value))
if("LANGUAGE")
var/lang_type = text2path(value)
if(ispath(lang_type,/datum/language))
record.entries += list(list(HOLORECORD_LANGUAGE,lang_type))
if("PRESET")
var/preset_type = text2path(value)
if(ispath(preset_type,/datum/preset_holoimage))
record.entries += list(list(HOLORECORD_PRESET,preset_type))
if(!preset_image_type)
record.caller_image = image('icons/mob/animal.dmi',"old")
else
var/datum/preset_holoimage/H = new preset_image_type
record.caller_image = H.build_image()
//These build caller image from outfit and some additional data, for use by mappers for ruin holorecords
/datum/preset_holoimage
var/nonhuman_mobtype //Fill this if you just want something nonhuman
var/outfit_type
var/species_type = /datum/species/human
/datum/preset_holoimage/proc/build_image()
if(nonhuman_mobtype)
var/mob/living/L = nonhuman_mobtype
. = image(initial(L.icon),initial(L.icon_state))
else
var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy("HOLODISK_PRESET")
if(species_type)
mannequin.set_species(species_type)
if(outfit_type)
mannequin.equipOutfit(outfit_type,TRUE)
mannequin.setDir(SOUTH)
COMPILE_OVERLAYS(mannequin)
. = image(mannequin)
unset_busy_human_dummy("HOLODISK_PRESET")
/obj/item/disk/holodisk/example
preset_image_type = /datum/preset_holoimage/clown
preset_record_text = {"
NAME Clown
DELAY 10
SAY Why did the chaplain cross the maint ?
DELAY 20
SAY He wanted to get to the other side!
SOUND clownstep
DELAY 30
LANGUAGE /datum/language/narsie
SAY Helped him get there!
DELAY 10
SAY ALSO IM SECRETLY A GORILLA
DELAY 10
PRESET /datum/preset_holoimage/gorilla
NAME Gorilla
LANGUAGE /datum/language/common
SAY OOGA
DELAY 20"}
/datum/preset_holoimage/engineer
outfit_type = /datum/outfit/job/engineer/gloved/rig
/datum/preset_holoimage/researcher
outfit_type = /datum/outfit/job/scientist
/datum/preset_holoimage/captain
outfit_type = /datum/outfit/job/captain
/datum/preset_holoimage/nanotrasenprivatesecurity
outfit_type = /datum/outfit/nanotrasensoldiercorpse2
/datum/preset_holoimage/gorilla
nonhuman_mobtype = /mob/living/simple_animal/hostile/gorilla
/datum/preset_holoimage/corgi
nonhuman_mobtype = /mob/living/simple_animal/pet/dog/corgi
/datum/preset_holoimage/clown
outfit_type = /datum/outfit/job/clown
+130 -130
View File
@@ -1,130 +1,130 @@
/* HUD DATUMS */
GLOBAL_LIST_EMPTY(all_huds)
//GLOBAL HUD LIST
GLOBAL_LIST_INIT(huds, list(
DATA_HUD_SECURITY_BASIC = new/datum/atom_hud/data/human/security/basic(),
DATA_HUD_SECURITY_ADVANCED = new/datum/atom_hud/data/human/security/advanced(),
DATA_HUD_MEDICAL_BASIC = new/datum/atom_hud/data/human/medical/basic(),
DATA_HUD_MEDICAL_ADVANCED = new/datum/atom_hud/data/human/medical/advanced(),
DATA_HUD_DIAGNOSTIC_BASIC = new/datum/atom_hud/data/diagnostic/basic(),
DATA_HUD_DIAGNOSTIC_ADVANCED = new/datum/atom_hud/data/diagnostic/advanced(),
DATA_HUD_ABDUCTOR = new/datum/atom_hud/abductor(),
DATA_HUD_SENTIENT_DISEASE = new/datum/atom_hud/sentient_disease(),
DATA_HUD_AI_DETECT = new/datum/atom_hud/ai_detector(),
ANTAG_HUD_CULT = new/datum/atom_hud/antag(),
ANTAG_HUD_REV = new/datum/atom_hud/antag(),
ANTAG_HUD_OPS = new/datum/atom_hud/antag(),
ANTAG_HUD_WIZ = new/datum/atom_hud/antag(),
ANTAG_HUD_SHADOW = new/datum/atom_hud/antag(),
ANTAG_HUD_TRAITOR = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_NINJA = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_CHANGELING = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_ABDUCTOR = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_DEVIL = new/datum/atom_hud/antag(),
ANTAG_HUD_SINTOUCHED = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker()
))
/datum/atom_hud
var/list/atom/hudatoms = list() //list of all atoms which display this hud
var/list/mob/hudusers = list() //list with all mobs who can see the hud
var/list/hud_icons = list() //these will be the indexes for the atom's hud_list
var/list/next_time_allowed = list() //mobs associated with the next time this hud can be added to them
var/list/queued_to_see = list() //mobs that have triggered the cooldown and are queued to see the hud, but do not yet
/datum/atom_hud/New()
GLOB.all_huds += src
/datum/atom_hud/Destroy()
for(var/v in hudusers)
remove_hud_from(v)
for(var/v in hudatoms)
remove_from_hud(v)
GLOB.all_huds -= src
return ..()
/datum/atom_hud/proc/remove_hud_from(mob/M)
if(!M || !hudusers[M])
return
if (!--hudusers[M])
hudusers -= M
if(queued_to_see[M])
queued_to_see -= M
else
for(var/atom/A in hudatoms)
remove_from_single_hud(M, A)
/datum/atom_hud/proc/remove_from_hud(atom/A)
if(!A)
return FALSE
for(var/mob/M in hudusers)
remove_from_single_hud(M, A)
hudatoms -= A
return TRUE
/datum/atom_hud/proc/remove_from_single_hud(mob/M, atom/A) //unsafe, no sanity apart from client
if(!M || !M.client || !A)
return
for(var/i in hud_icons)
M.client.images -= A.hud_list[i]
/datum/atom_hud/proc/add_hud_to(mob/M)
if(!M)
return
if(!hudusers[M])
hudusers[M] = 1
if(next_time_allowed[M] > world.time)
if(!queued_to_see[M])
addtimer(CALLBACK(src, .proc/show_hud_images_after_cooldown, M), next_time_allowed[M] - world.time)
queued_to_see[M] = TRUE
else
next_time_allowed[M] = world.time + ADD_HUD_TO_COOLDOWN
for(var/atom/A in hudatoms)
add_to_single_hud(M, A)
else
hudusers[M]++
/datum/atom_hud/proc/show_hud_images_after_cooldown(M)
if(queued_to_see[M])
queued_to_see -= M
next_time_allowed[M] = world.time + ADD_HUD_TO_COOLDOWN
for(var/atom/A in hudatoms)
add_to_single_hud(M, A)
/datum/atom_hud/proc/add_to_hud(atom/A)
if(!A)
return FALSE
hudatoms |= A
for(var/mob/M in hudusers)
if(!queued_to_see[M])
add_to_single_hud(M, A)
return TRUE
/datum/atom_hud/proc/add_to_single_hud(mob/M, atom/A) //unsafe, no sanity apart from client
if(!M || !M.client || !A)
return
for(var/i in hud_icons)
if(A.hud_list[i])
M.client.images |= A.hud_list[i]
//MOB PROCS
/mob/proc/reload_huds()
for(var/datum/atom_hud/hud in GLOB.all_huds)
if(hud && hud.hudusers[src])
for(var/atom/A in hud.hudatoms)
hud.add_to_single_hud(src, A)
/mob/dead/new_player/reload_huds()
return
/mob/proc/add_click_catcher()
client.screen += client.void
/mob/dead/new_player/add_click_catcher()
return
/* HUD DATUMS */
GLOBAL_LIST_EMPTY(all_huds)
//GLOBAL HUD LIST
GLOBAL_LIST_INIT(huds, list(
DATA_HUD_SECURITY_BASIC = new/datum/atom_hud/data/human/security/basic(),
DATA_HUD_SECURITY_ADVANCED = new/datum/atom_hud/data/human/security/advanced(),
DATA_HUD_MEDICAL_BASIC = new/datum/atom_hud/data/human/medical/basic(),
DATA_HUD_MEDICAL_ADVANCED = new/datum/atom_hud/data/human/medical/advanced(),
DATA_HUD_DIAGNOSTIC_BASIC = new/datum/atom_hud/data/diagnostic/basic(),
DATA_HUD_DIAGNOSTIC_ADVANCED = new/datum/atom_hud/data/diagnostic/advanced(),
DATA_HUD_ABDUCTOR = new/datum/atom_hud/abductor(),
DATA_HUD_SENTIENT_DISEASE = new/datum/atom_hud/sentient_disease(),
DATA_HUD_AI_DETECT = new/datum/atom_hud/ai_detector(),
ANTAG_HUD_CULT = new/datum/atom_hud/antag(),
ANTAG_HUD_REV = new/datum/atom_hud/antag(),
ANTAG_HUD_OPS = new/datum/atom_hud/antag(),
ANTAG_HUD_WIZ = new/datum/atom_hud/antag(),
ANTAG_HUD_SHADOW = new/datum/atom_hud/antag(),
ANTAG_HUD_TRAITOR = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_NINJA = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_CHANGELING = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_ABDUCTOR = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_DEVIL = new/datum/atom_hud/antag(),
ANTAG_HUD_SINTOUCHED = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker()
))
/datum/atom_hud
var/list/atom/hudatoms = list() //list of all atoms which display this hud
var/list/mob/hudusers = list() //list with all mobs who can see the hud
var/list/hud_icons = list() //these will be the indexes for the atom's hud_list
var/list/next_time_allowed = list() //mobs associated with the next time this hud can be added to them
var/list/queued_to_see = list() //mobs that have triggered the cooldown and are queued to see the hud, but do not yet
/datum/atom_hud/New()
GLOB.all_huds += src
/datum/atom_hud/Destroy()
for(var/v in hudusers)
remove_hud_from(v)
for(var/v in hudatoms)
remove_from_hud(v)
GLOB.all_huds -= src
return ..()
/datum/atom_hud/proc/remove_hud_from(mob/M)
if(!M || !hudusers[M])
return
if (!--hudusers[M])
hudusers -= M
if(queued_to_see[M])
queued_to_see -= M
else
for(var/atom/A in hudatoms)
remove_from_single_hud(M, A)
/datum/atom_hud/proc/remove_from_hud(atom/A)
if(!A)
return FALSE
for(var/mob/M in hudusers)
remove_from_single_hud(M, A)
hudatoms -= A
return TRUE
/datum/atom_hud/proc/remove_from_single_hud(mob/M, atom/A) //unsafe, no sanity apart from client
if(!M || !M.client || !A)
return
for(var/i in hud_icons)
M.client.images -= A.hud_list[i]
/datum/atom_hud/proc/add_hud_to(mob/M)
if(!M)
return
if(!hudusers[M])
hudusers[M] = 1
if(next_time_allowed[M] > world.time)
if(!queued_to_see[M])
addtimer(CALLBACK(src, .proc/show_hud_images_after_cooldown, M), next_time_allowed[M] - world.time)
queued_to_see[M] = TRUE
else
next_time_allowed[M] = world.time + ADD_HUD_TO_COOLDOWN
for(var/atom/A in hudatoms)
add_to_single_hud(M, A)
else
hudusers[M]++
/datum/atom_hud/proc/show_hud_images_after_cooldown(M)
if(queued_to_see[M])
queued_to_see -= M
next_time_allowed[M] = world.time + ADD_HUD_TO_COOLDOWN
for(var/atom/A in hudatoms)
add_to_single_hud(M, A)
/datum/atom_hud/proc/add_to_hud(atom/A)
if(!A)
return FALSE
hudatoms |= A
for(var/mob/M in hudusers)
if(!queued_to_see[M])
add_to_single_hud(M, A)
return TRUE
/datum/atom_hud/proc/add_to_single_hud(mob/M, atom/A) //unsafe, no sanity apart from client
if(!M || !M.client || !A)
return
for(var/i in hud_icons)
if(A.hud_list[i])
M.client.images |= A.hud_list[i]
//MOB PROCS
/mob/proc/reload_huds()
for(var/datum/atom_hud/hud in GLOB.all_huds)
if(hud && hud.hudusers[src])
for(var/atom/A in hud.hudatoms)
hud.add_to_single_hud(src, A)
/mob/dead/new_player/reload_huds()
return
/mob/proc/add_click_catcher()
client.screen += client.void
/mob/dead/new_player/add_click_catcher()
return
+163 -163
View File
@@ -1,163 +1,163 @@
//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
// Metadata
var/config_filename = "_maps/boxstation.json"
var/defaulted = TRUE // set to FALSE by LoadConfig() succeeding
// Config from maps.txt
var/config_max_users = 0
var/config_min_users = 0
var/voteweight = 1
var/max_round_search_span = 0 //If this is nonzero, then if the map has been played more than max_rounds_played within the search span (max determined by define in persistence.dm), this map won't be available.
var/max_rounds_played = 0
// Config actually from the JSON - should default to Box
var/map_name = "Box Station"
var/map_path = "map_files/BoxStation"
var/map_file = "BoxStation.dmm"
var/traits = null
var/space_ruin_levels = 2
var/space_empty_levels = 1
var/minetype = "lavaland"
var/maptype = MAP_TYPE_STATION //This should be used to adjust ingame behavior depending on the specific type of map being played. For instance, if an overmap were added, it'd be appropriate for it to only generate with a MAP_TYPE_SHIP
var/announcertype = "standard" //Determines the announcer the map uses. standard uses the default announcer, classic, but has a random chance to use other similarly-themed announcers, like medibot
var/allow_custom_shuttles = TRUE
var/shuttles = list(
"cargo" = "cargo_box",
"ferry" = "ferry_fancy",
"whiteship" = "whiteship_box",
"emergency" = "emergency_box")
var/year_offset = 540 //The offset of ingame year from the actual IRL year. You know you want to make a map that takes place in the 90's. Don't lie.
/proc/load_map_config(filename = "data/next_map.json", default_to_box, delete_after, error_if_missing = TRUE)
var/datum/map_config/config = new
if (default_to_box)
return config
if (!config.LoadConfig(filename, error_if_missing))
qdel(config)
config = new /datum/map_config // Fall back to Box
if (delete_after)
fdel(filename)
return config
#define CHECK_EXISTS(X) if(!istext(json[X])) { log_world("[##X] missing from json!"); return; }
/datum/map_config/proc/LoadConfig(filename, error_if_missing)
if(!fexists(filename))
if(error_if_missing)
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
config_filename = filename
CHECK_EXISTS("map_name")
map_name = json["map_name"]
CHECK_EXISTS("map_path")
map_path = json["map_path"]
map_file = json["map_file"]
// "map_file": "BoxStation.dmm"
if (istext(map_file))
if (!fexists("_maps/[map_path]/[map_file]"))
log_world("Map file ([map_path]/[map_file]) does not exist!")
return
// "map_file": ["Lower.dmm", "Upper.dmm"]
else if (islist(map_file))
for (var/file in map_file)
if (!fexists("_maps/[map_path]/[file]"))
log_world("Map file ([map_path]/[file]) does not exist!")
return
else
log_world("map_file missing from json!")
return
if (islist(json["shuttles"]))
var/list/L = json["shuttles"]
for(var/key in L)
var/value = L[key]
shuttles[key] = value
else if ("shuttles" in json)
log_world("map_config shuttles is not a list!")
return
traits = json["traits"]
// "traits": [{"Linkage": "Cross"}, {"Space Ruins": true}]
if (islist(traits))
// "Station" is set by default, but it's assumed if you're setting
// traits you want to customize which level is cross-linked
for (var/level in traits)
if (!(ZTRAIT_STATION in level))
level[ZTRAIT_STATION] = TRUE
// "traits": null or absent -> default
else if (!isnull(traits))
log_world("map_config traits is not a list!")
return
var/temp = json["space_ruin_levels"]
if (isnum(temp))
space_ruin_levels = temp
else if (!isnull(temp))
log_world("map_config space_ruin_levels is not a number!")
return
temp = json["space_empty_levels"]
if (isnum(temp))
space_empty_levels = temp
else if (!isnull(temp))
log_world("map_config space_empty_levels is not a number!")
return
temp = json["year_offset"]
if (isnum(temp))
year_offset = temp
else if (!isnull(temp))
log_world("map_config year_offset is not a number!")
return
if ("minetype" in json)
minetype = json["minetype"]
if ("maptype" in json)
maptype = json["maptype"]
if ("announcertype" in json)
announcertype = json["announcertype"]
allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE
defaulted = FALSE
return TRUE
#undef CHECK_EXISTS
/datum/map_config/proc/GetFullMapPaths()
if (istext(map_file))
return list("_maps/[map_path]/[map_file]")
. = list()
for (var/file in map_file)
. += "_maps/[map_path]/[file]"
/datum/map_config/proc/MakeNextMap()
return config_filename == "data/next_map.json" || fcopy(config_filename, "data/next_map.json")
//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
// Metadata
var/config_filename = "_maps/boxstation.json"
var/defaulted = TRUE // set to FALSE by LoadConfig() succeeding
// Config from maps.txt
var/config_max_users = 0
var/config_min_users = 0
var/voteweight = 1
var/max_round_search_span = 0 //If this is nonzero, then if the map has been played more than max_rounds_played within the search span (max determined by define in persistence.dm), this map won't be available.
var/max_rounds_played = 0
// Config actually from the JSON - should default to Box
var/map_name = "Box Station"
var/map_path = "map_files/BoxStation"
var/map_file = "BoxStation.dmm"
var/traits = null
var/space_ruin_levels = 2
var/space_empty_levels = 1
var/minetype = "lavaland"
var/maptype = MAP_TYPE_STATION //This should be used to adjust ingame behavior depending on the specific type of map being played. For instance, if an overmap were added, it'd be appropriate for it to only generate with a MAP_TYPE_SHIP
var/announcertype = "standard" //Determines the announcer the map uses. standard uses the default announcer, classic, but has a random chance to use other similarly-themed announcers, like medibot
var/allow_custom_shuttles = TRUE
var/shuttles = list(
"cargo" = "cargo_box",
"ferry" = "ferry_fancy",
"whiteship" = "whiteship_box",
"emergency" = "emergency_box")
var/year_offset = 540 //The offset of ingame year from the actual IRL year. You know you want to make a map that takes place in the 90's. Don't lie.
/proc/load_map_config(filename = "data/next_map.json", default_to_box, delete_after, error_if_missing = TRUE)
var/datum/map_config/config = new
if (default_to_box)
return config
if (!config.LoadConfig(filename, error_if_missing))
qdel(config)
config = new /datum/map_config // Fall back to Box
if (delete_after)
fdel(filename)
return config
#define CHECK_EXISTS(X) if(!istext(json[X])) { log_world("[##X] missing from json!"); return; }
/datum/map_config/proc/LoadConfig(filename, error_if_missing)
if(!fexists(filename))
if(error_if_missing)
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
config_filename = filename
CHECK_EXISTS("map_name")
map_name = json["map_name"]
CHECK_EXISTS("map_path")
map_path = json["map_path"]
map_file = json["map_file"]
// "map_file": "BoxStation.dmm"
if (istext(map_file))
if (!fexists("_maps/[map_path]/[map_file]"))
log_world("Map file ([map_path]/[map_file]) does not exist!")
return
// "map_file": ["Lower.dmm", "Upper.dmm"]
else if (islist(map_file))
for (var/file in map_file)
if (!fexists("_maps/[map_path]/[file]"))
log_world("Map file ([map_path]/[file]) does not exist!")
return
else
log_world("map_file missing from json!")
return
if (islist(json["shuttles"]))
var/list/L = json["shuttles"]
for(var/key in L)
var/value = L[key]
shuttles[key] = value
else if ("shuttles" in json)
log_world("map_config shuttles is not a list!")
return
traits = json["traits"]
// "traits": [{"Linkage": "Cross"}, {"Space Ruins": true}]
if (islist(traits))
// "Station" is set by default, but it's assumed if you're setting
// traits you want to customize which level is cross-linked
for (var/level in traits)
if (!(ZTRAIT_STATION in level))
level[ZTRAIT_STATION] = TRUE
// "traits": null or absent -> default
else if (!isnull(traits))
log_world("map_config traits is not a list!")
return
var/temp = json["space_ruin_levels"]
if (isnum(temp))
space_ruin_levels = temp
else if (!isnull(temp))
log_world("map_config space_ruin_levels is not a number!")
return
temp = json["space_empty_levels"]
if (isnum(temp))
space_empty_levels = temp
else if (!isnull(temp))
log_world("map_config space_empty_levels is not a number!")
return
temp = json["year_offset"]
if (isnum(temp))
year_offset = temp
else if (!isnull(temp))
log_world("map_config year_offset is not a number!")
return
if ("minetype" in json)
minetype = json["minetype"]
if ("maptype" in json)
maptype = json["maptype"]
if ("announcertype" in json)
announcertype = json["announcertype"]
allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE
defaulted = FALSE
return TRUE
#undef CHECK_EXISTS
/datum/map_config/proc/GetFullMapPaths()
if (istext(map_file))
return list("_maps/[map_path]/[map_file]")
. = list()
for (var/file in map_file)
. += "_maps/[map_path]/[file]"
/datum/map_config/proc/MakeNextMap()
return config_filename == "data/next_map.json" || fcopy(config_filename, "data/next_map.json")
+780 -780
View File
File diff suppressed because it is too large Load Diff
+115 -115
View File
@@ -1,115 +1,115 @@
/datum/mood_event/high
mood_change = 6
description = "<span class='nicegreen'>Woooow duudeeeeee...I'm tripping baaalls...</span>\n"
/datum/mood_event/smoked
description = "<span class='nicegreen'>I have had a smoke recently.</span>\n"
mood_change = 2
timeout = 3600
/datum/mood_event/overdose
mood_change = -8
timeout = 3000
/datum/mood_event/overdose/add_effects(drug_name)
description = "<span class='warning'>I think I took a bit too much of that [drug_name]</span>\n"
/datum/mood_event/withdrawal_light
mood_change = -2
/datum/mood_event/withdrawal_light/add_effects(drug_name)
description = "<span class='warning'>I could use some [drug_name]</span>\n"
/datum/mood_event/withdrawal_medium
mood_change = -5
/datum/mood_event/withdrawal_medium/add_effects(drug_name)
description = "<span class='warning'>I really need [drug_name]</span>\n"
/datum/mood_event/withdrawal_severe
mood_change = -8
/datum/mood_event/withdrawal_severe/add_effects(drug_name)
description = "<span class='boldwarning'>Oh god I need some [drug_name]</span>\n"
/datum/mood_event/withdrawal_critical
mood_change = -10
/datum/mood_event/withdrawal_critical/add_effects(drug_name)
description = "<span class='boldwarning'>[drug_name]! [drug_name]! [drug_name]!</span>\n"
/datum/mood_event/happiness_drug
description = "<span class='nicegreen'>I can't feel anything and I never want this to end.</span>\n"
mood_change = 10
/datum/mood_event/happiness_drug_good_od
description = "<span class='nicegreen'>YES! YES!! YES!!!</span>\n"
mood_change = 20
timeout = 300
//special_screen_obj = "mood_happiness_good" Originally in tg, but I personally think they look dumb
/datum/mood_event/happiness_drug_bad_od
description = "<span class='boldwarning'>NO! NO!! NO!!!</span>\n"
mood_change = -20
timeout = 300
//special_screen_obj = "mood_happiness_bad" Originally in tg
/datum/mood_event/eigenstate
mood_change = -3
description = "<span class='warning'>Where the hell am I? Is this an alternative dimension ?</span>\n"
/datum/mood_event/enthrall
mood_change = 5
/datum/mood_event/enthrall/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/enthrallpraise
mood_change = 10
timeout = 1 MINUTES
/datum/mood_event/enthrallpraise/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/enthrallscold
mood_change = -10
timeout = 1 MINUTES
/datum/mood_event/enthrallscold/add_effects(message)
description = "<span class='warning'>[message]</span>\n"//aaa I'm not kinky enough for this
/datum/mood_event/enthrallmissing1
mood_change = -5
/datum/mood_event/enthrallmissing1/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing2
mood_change = -10
/datum/mood_event/enthrallmissing2/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing3
mood_change = -15
/datum/mood_event/enthrallmissing3/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing4
mood_change = -25
/datum/mood_event/enthrallmissing4/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/InLove
mood_change = 10
/datum/mood_event/InLove/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/MissingLove
mood_change = -10
/datum/mood_event/MissingLove/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/high
mood_change = 6
description = "<span class='nicegreen'>Woooow duudeeeeee...I'm tripping baaalls...</span>\n"
/datum/mood_event/smoked
description = "<span class='nicegreen'>I have had a smoke recently.</span>\n"
mood_change = 2
timeout = 3600
/datum/mood_event/overdose
mood_change = -8
timeout = 3000
/datum/mood_event/overdose/add_effects(drug_name)
description = "<span class='warning'>I think I took a bit too much of that [drug_name]</span>\n"
/datum/mood_event/withdrawal_light
mood_change = -2
/datum/mood_event/withdrawal_light/add_effects(drug_name)
description = "<span class='warning'>I could use some [drug_name]</span>\n"
/datum/mood_event/withdrawal_medium
mood_change = -5
/datum/mood_event/withdrawal_medium/add_effects(drug_name)
description = "<span class='warning'>I really need [drug_name]</span>\n"
/datum/mood_event/withdrawal_severe
mood_change = -8
/datum/mood_event/withdrawal_severe/add_effects(drug_name)
description = "<span class='boldwarning'>Oh god I need some [drug_name]</span>\n"
/datum/mood_event/withdrawal_critical
mood_change = -10
/datum/mood_event/withdrawal_critical/add_effects(drug_name)
description = "<span class='boldwarning'>[drug_name]! [drug_name]! [drug_name]!</span>\n"
/datum/mood_event/happiness_drug
description = "<span class='nicegreen'>I can't feel anything and I never want this to end.</span>\n"
mood_change = 10
/datum/mood_event/happiness_drug_good_od
description = "<span class='nicegreen'>YES! YES!! YES!!!</span>\n"
mood_change = 20
timeout = 300
//special_screen_obj = "mood_happiness_good" Originally in tg, but I personally think they look dumb
/datum/mood_event/happiness_drug_bad_od
description = "<span class='boldwarning'>NO! NO!! NO!!!</span>\n"
mood_change = -20
timeout = 300
//special_screen_obj = "mood_happiness_bad" Originally in tg
/datum/mood_event/eigenstate
mood_change = -3
description = "<span class='warning'>Where the hell am I? Is this an alternative dimension ?</span>\n"
/datum/mood_event/enthrall
mood_change = 5
/datum/mood_event/enthrall/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/enthrallpraise
mood_change = 10
timeout = 1 MINUTES
/datum/mood_event/enthrallpraise/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/enthrallscold
mood_change = -10
timeout = 1 MINUTES
/datum/mood_event/enthrallscold/add_effects(message)
description = "<span class='warning'>[message]</span>\n"//aaa I'm not kinky enough for this
/datum/mood_event/enthrallmissing1
mood_change = -5
/datum/mood_event/enthrallmissing1/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing2
mood_change = -10
/datum/mood_event/enthrallmissing2/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing3
mood_change = -15
/datum/mood_event/enthrallmissing3/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/enthrallmissing4
mood_change = -25
/datum/mood_event/enthrallmissing4/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
/datum/mood_event/InLove
mood_change = 10
/datum/mood_event/InLove/add_effects(message)
description = "<span class='nicegreen'>[message]</span>\n"
/datum/mood_event/MissingLove
mood_change = -10
/datum/mood_event/MissingLove/add_effects(message)
description = "<span class='warning'>[message]</span>\n"
+20 -20
View File
@@ -1,20 +1,20 @@
/datum/mood_event
var/description ///For descriptions, use the span classes bold nicegreen, nicegreen, none, warning and boldwarning in order from great to horrible.
var/mood_change = 0
var/timeout = 0
var/hidden = FALSE//Not shown on examine
var/mob/owner
/datum/mood_event/New(mob/M, param)
owner = M
add_effects(param)
/datum/mood_event/Destroy()
remove_effects()
return ..()
/datum/mood_event/proc/add_effects(param)
return
/datum/mood_event/proc/remove_effects()
return
/datum/mood_event
var/description ///For descriptions, use the span classes bold nicegreen, nicegreen, none, warning and boldwarning in order from great to horrible.
var/mood_change = 0
var/timeout = 0
var/hidden = FALSE//Not shown on examine
var/mob/owner
/datum/mood_event/New(mob/M, param)
owner = M
add_effects(param)
/datum/mood_event/Destroy()
remove_effects()
return ..()
/datum/mood_event/proc/add_effects(param)
return
/datum/mood_event/proc/remove_effects()
return
+62 -62
View File
@@ -1,62 +1,62 @@
//nutrition
/datum/mood_event/fat
description = "<span class='warning'><B>I'm so fat...</B></span>\n" //muh fatshaming
mood_change = -4
/datum/mood_event/wellfed
description = "<span class='nicegreen'>I'm stuffed!</span>\n"
mood_change = 6
/datum/mood_event/fed
description = "<span class='nicegreen'>I have recently had some food.</span>\n"
mood_change = 3
/datum/mood_event/hungry
description = "<span class='warning'>I'm getting a bit hungry.</span>\n"
mood_change = -8
/datum/mood_event/starving
description = "<span class='boldwarning'>I'm starving!</span>\n"
mood_change = -15
//Disgust
/datum/mood_event/gross
description = "<span class='warning'>I saw something gross.</span>\n"
mood_change = -2
/datum/mood_event/verygross
description = "<span class='warning'>I think I'm going to puke...</span>\n"
mood_change = -5
/datum/mood_event/disgusted
description = "<span class='boldwarning'>Oh god that's disgusting...</span>\n"
mood_change = -8
/datum/mood_event/disgust/bad_smell
description = "<span class='warning'>You smell something horribly decayed inside this room.</span>\n"
mood_change = -3
/datum/mood_event/disgust/nauseating_stench
description = "<span class='warning'>The stench of rotting carcasses is unbearable!</span>\n"
mood_change = -7
//Generic needs events
/datum/mood_event/favorite_food
description = "<span class='nicegreen'>I really enjoyed eating that.</span>\n"
mood_change = 3
timeout = 2400
/datum/mood_event/gross_food
description = "<span class='warning'>I really didn't like that food.</span>\n"
mood_change = -2
timeout = 2400
/datum/mood_event/disgusting_food
description = "<span class='warning'>That food was disgusting!</span>\n"
mood_change = -4
timeout = 2400
/datum/mood_event/nice_shower
description = "<span class='nicegreen'>I have recently had a nice shower.</span>\n"
mood_change = 2
timeout = 3 MINUTES
//nutrition
/datum/mood_event/fat
description = "<span class='warning'><B>I'm so fat...</B></span>\n" //muh fatshaming
mood_change = -4
/datum/mood_event/wellfed
description = "<span class='nicegreen'>I'm stuffed!</span>\n"
mood_change = 6
/datum/mood_event/fed
description = "<span class='nicegreen'>I have recently had some food.</span>\n"
mood_change = 3
/datum/mood_event/hungry
description = "<span class='warning'>I'm getting a bit hungry.</span>\n"
mood_change = -8
/datum/mood_event/starving
description = "<span class='boldwarning'>I'm starving!</span>\n"
mood_change = -15
//Disgust
/datum/mood_event/gross
description = "<span class='warning'>I saw something gross.</span>\n"
mood_change = -2
/datum/mood_event/verygross
description = "<span class='warning'>I think I'm going to puke...</span>\n"
mood_change = -5
/datum/mood_event/disgusted
description = "<span class='boldwarning'>Oh god that's disgusting...</span>\n"
mood_change = -8
/datum/mood_event/disgust/bad_smell
description = "<span class='warning'>You smell something horribly decayed inside this room.</span>\n"
mood_change = -3
/datum/mood_event/disgust/nauseating_stench
description = "<span class='warning'>The stench of rotting carcasses is unbearable!</span>\n"
mood_change = -7
//Generic needs events
/datum/mood_event/favorite_food
description = "<span class='nicegreen'>I really enjoyed eating that.</span>\n"
mood_change = 3
timeout = 2400
/datum/mood_event/gross_food
description = "<span class='warning'>I really didn't like that food.</span>\n"
mood_change = -2
timeout = 2400
/datum/mood_event/disgusting_food
description = "<span class='warning'>That food was disgusting!</span>\n"
mood_change = -4
timeout = 2400
/datum/mood_event/nice_shower
description = "<span class='nicegreen'>I have recently had a nice shower.</span>\n"
mood_change = 2
timeout = 3 MINUTES
+225 -225
View File
@@ -1,225 +1,225 @@
//Designed for things that need precision trajectories like projectiles.
//Don't use this for anything that you don't absolutely have to use this with (like projectiles!) because it isn't worth using a datum unless you need accuracy down to decimal places in pixels.
//You might see places where it does - 16 - 1. This is intentionally 17 instead of 16, because of how byond's tiles work and how not doing it will result in rounding errors like things getting put on the wrong turf.
#define RETURN_PRECISE_POSITION(A) new /datum/position(A)
#define RETURN_PRECISE_POINT(A) new /datum/point(A)
#define RETURN_POINT_VECTOR(ATOM, ANGLE, SPEED) (new /datum/point/vector(ATOM, null, null, null, null, ANGLE, SPEED))
#define RETURN_POINT_VECTOR_INCREMENT(ATOM, ANGLE, SPEED, AMT) (new /datum/point/vector(ATOM, null, null, null, null, ANGLE, SPEED, AMT))
/proc/point_midpoint_points(datum/point/a, datum/point/b) //Obviously will not support multiZ calculations! Same for the two below.
var/datum/point/P = new
P.x = a.x + (b.x - a.x) / 2
P.y = a.y + (b.y - a.y) / 2
P.z = a.z
return P
/proc/pixel_length_between_points(datum/point/a, datum/point/b)
return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
/proc/angle_between_points(datum/point/a, datum/point/b)
return ATAN2((b.y - a.y), (b.x - a.x))
/datum/position //For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
var/x = 0
var/y = 0
var/z = 0
var/pixel_x = 0
var/pixel_y = 0
/datum/position/proc/valid()
return x && y && z && !isnull(pixel_x) && !isnull(pixel_y)
/datum/position/New(_x = 0, _y = 0, _z = 0, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/point.
if(istype(_x, /datum/point))
var/datum/point/P = _x
var/turf/T = P.return_turf()
_x = T.x
_y = T.y
_z = T.z
_pixel_x = P.return_px()
_pixel_y = P.return_py()
else if(isatom(_x))
var/atom/A = _x
_x = A.x
_y = A.y
_z = A.z
_pixel_x = A.pixel_x
_pixel_y = A.pixel_y
x = _x
y = _y
z = _z
pixel_x = _pixel_x
pixel_y = _pixel_y
/datum/position/proc/return_turf()
return locate(x, y, z)
/datum/position/proc/return_px()
return pixel_x
/datum/position/proc/return_py()
return pixel_y
/datum/position/proc/return_point()
return new /datum/point(src)
/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
var/x = 0
var/y = 0
var/z = 0
/datum/point/proc/valid()
return x && y && z
/datum/point/proc/copy_to(datum/point/p = new)
p.x = x
p.y = y
p.z = z
return p
/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/position or /atom.
if(istype(_x, /datum/position))
var/datum/position/P = _x
_x = P.x
_y = P.y
_z = P.z
_pixel_x = P.pixel_x
_pixel_y = P.pixel_y
else if(istype(_x, /atom))
var/atom/A = _x
_x = A.x
_y = A.y
_z = A.z
_pixel_x = A.pixel_x
_pixel_y = A.pixel_y
initialize_location(_x, _y, _z, _pixel_x, _pixel_y)
/datum/point/proc/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
if(!isnull(tile_x))
x = ((tile_x - 1) * world.icon_size) + world.icon_size / 2 + p_x + 1
if(!isnull(tile_y))
y = ((tile_y - 1) * world.icon_size) + world.icon_size / 2 + p_y + 1
if(!isnull(tile_z))
z = tile_z
/datum/point/proc/debug_out()
var/turf/T = return_turf()
return "\ref[src] aX [x] aY [y] aZ [z] pX [return_px()] pY [return_py()] mX [T.x] mY [T.y] mZ [T.z]"
/datum/point/proc/move_atom_to_src(atom/movable/AM)
AM.forceMove(return_turf())
AM.pixel_x = return_px()
AM.pixel_y = return_py()
/datum/point/proc/return_turf()
return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
/datum/point/proc/return_coordinates() //[turf_x, turf_y, z]
return list(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
/datum/point/proc/return_position()
return new /datum/position(src)
/datum/point/proc/return_px()
return MODULUS(x, world.icon_size) - 16 - 1
/datum/point/proc/return_py()
return MODULUS(y, world.icon_size) - 16 - 1
/datum/point/vector
var/speed = 32 //pixels per iteration
var/iteration = 0
var/angle = 0
var/mpx = 0 //calculated x/y movement amounts to prevent having to do trig every step.
var/mpy = 0
var/starting_x = 0 //just like before, pixels from EDGE of map! This is set in initialize_location().
var/starting_y = 0
var/starting_z = 0
/datum/point/vector/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0, _angle, _speed, initial_increment = 0)
..()
initialize_trajectory(_speed, _angle)
if(initial_increment)
increment(initial_increment)
/datum/point/vector/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
. = ..()
starting_x = x
starting_y = y
starting_z = z
/datum/point/vector/copy_to(datum/point/vector/v = new)
..(v)
v.speed = speed
v.iteration = iteration
v.angle = angle
v.mpx = mpx
v.mpy = mpy
v.starting_x = starting_x
v.starting_y = starting_y
v.starting_z = starting_z
return v
/datum/point/vector/proc/initialize_trajectory(pixel_speed, new_angle)
if(!isnull(pixel_speed))
speed = pixel_speed
set_angle(new_angle)
/datum/point/vector/proc/set_angle(new_angle) //calculations use "byond angle" where north is 0 instead of 90, and south is 180 instead of 270.
if(isnull(angle))
return
angle = new_angle
update_offsets()
/datum/point/vector/proc/update_offsets()
mpx = sin(angle) * speed
mpy = cos(angle) * speed
/datum/point/vector/proc/set_speed(new_speed)
if(isnull(new_speed) || speed == new_speed)
return
speed = new_speed
update_offsets()
/datum/point/vector/proc/increment(multiplier = 1)
iteration++
x += mpx * (multiplier)
y += mpy * (multiplier)
/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
var/datum/point/vector/v = copy_to()
if(force_simulate)
for(var/i in 1 to amount)
v.increment(multiplier)
else
v.increment(multiplier * amount)
return v
/datum/point/vector/proc/on_z_change()
return
/datum/point/vector/processed //pixel_speed is per decisecond.
var/last_process = 0
var/last_move = 0
var/paused = FALSE
/datum/point/vector/processed/Destroy()
STOP_PROCESSING(SSprojectiles, src)
/datum/point/vector/processed/proc/start()
last_process = world.time
last_move = world.time
START_PROCESSING(SSprojectiles, src)
/datum/point/vector/processed/process()
if(paused)
last_move += world.time - last_process
last_process = world.time
return
var/needed_time = world.time - last_move
last_process = world.time
last_move = world.time
increment(needed_time / SSprojectiles.wait)
//Designed for things that need precision trajectories like projectiles.
//Don't use this for anything that you don't absolutely have to use this with (like projectiles!) because it isn't worth using a datum unless you need accuracy down to decimal places in pixels.
//You might see places where it does - 16 - 1. This is intentionally 17 instead of 16, because of how byond's tiles work and how not doing it will result in rounding errors like things getting put on the wrong turf.
#define RETURN_PRECISE_POSITION(A) new /datum/position(A)
#define RETURN_PRECISE_POINT(A) new /datum/point(A)
#define RETURN_POINT_VECTOR(ATOM, ANGLE, SPEED) (new /datum/point/vector(ATOM, null, null, null, null, ANGLE, SPEED))
#define RETURN_POINT_VECTOR_INCREMENT(ATOM, ANGLE, SPEED, AMT) (new /datum/point/vector(ATOM, null, null, null, null, ANGLE, SPEED, AMT))
/proc/point_midpoint_points(datum/point/a, datum/point/b) //Obviously will not support multiZ calculations! Same for the two below.
var/datum/point/P = new
P.x = a.x + (b.x - a.x) / 2
P.y = a.y + (b.y - a.y) / 2
P.z = a.z
return P
/proc/pixel_length_between_points(datum/point/a, datum/point/b)
return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
/proc/angle_between_points(datum/point/a, datum/point/b)
return ATAN2((b.y - a.y), (b.x - a.x))
/datum/position //For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
var/x = 0
var/y = 0
var/z = 0
var/pixel_x = 0
var/pixel_y = 0
/datum/position/proc/valid()
return x && y && z && !isnull(pixel_x) && !isnull(pixel_y)
/datum/position/New(_x = 0, _y = 0, _z = 0, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/point.
if(istype(_x, /datum/point))
var/datum/point/P = _x
var/turf/T = P.return_turf()
_x = T.x
_y = T.y
_z = T.z
_pixel_x = P.return_px()
_pixel_y = P.return_py()
else if(isatom(_x))
var/atom/A = _x
_x = A.x
_y = A.y
_z = A.z
_pixel_x = A.pixel_x
_pixel_y = A.pixel_y
x = _x
y = _y
z = _z
pixel_x = _pixel_x
pixel_y = _pixel_y
/datum/position/proc/return_turf()
return locate(x, y, z)
/datum/position/proc/return_px()
return pixel_x
/datum/position/proc/return_py()
return pixel_y
/datum/position/proc/return_point()
return new /datum/point(src)
/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
var/x = 0
var/y = 0
var/z = 0
/datum/point/proc/valid()
return x && y && z
/datum/point/proc/copy_to(datum/point/p = new)
p.x = x
p.y = y
p.z = z
return p
/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/position or /atom.
if(istype(_x, /datum/position))
var/datum/position/P = _x
_x = P.x
_y = P.y
_z = P.z
_pixel_x = P.pixel_x
_pixel_y = P.pixel_y
else if(istype(_x, /atom))
var/atom/A = _x
_x = A.x
_y = A.y
_z = A.z
_pixel_x = A.pixel_x
_pixel_y = A.pixel_y
initialize_location(_x, _y, _z, _pixel_x, _pixel_y)
/datum/point/proc/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
if(!isnull(tile_x))
x = ((tile_x - 1) * world.icon_size) + world.icon_size / 2 + p_x + 1
if(!isnull(tile_y))
y = ((tile_y - 1) * world.icon_size) + world.icon_size / 2 + p_y + 1
if(!isnull(tile_z))
z = tile_z
/datum/point/proc/debug_out()
var/turf/T = return_turf()
return "\ref[src] aX [x] aY [y] aZ [z] pX [return_px()] pY [return_py()] mX [T.x] mY [T.y] mZ [T.z]"
/datum/point/proc/move_atom_to_src(atom/movable/AM)
AM.forceMove(return_turf())
AM.pixel_x = return_px()
AM.pixel_y = return_py()
/datum/point/proc/return_turf()
return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
/datum/point/proc/return_coordinates() //[turf_x, turf_y, z]
return list(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
/datum/point/proc/return_position()
return new /datum/position(src)
/datum/point/proc/return_px()
return MODULUS(x, world.icon_size) - 16 - 1
/datum/point/proc/return_py()
return MODULUS(y, world.icon_size) - 16 - 1
/datum/point/vector
var/speed = 32 //pixels per iteration
var/iteration = 0
var/angle = 0
var/mpx = 0 //calculated x/y movement amounts to prevent having to do trig every step.
var/mpy = 0
var/starting_x = 0 //just like before, pixels from EDGE of map! This is set in initialize_location().
var/starting_y = 0
var/starting_z = 0
/datum/point/vector/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0, _angle, _speed, initial_increment = 0)
..()
initialize_trajectory(_speed, _angle)
if(initial_increment)
increment(initial_increment)
/datum/point/vector/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
. = ..()
starting_x = x
starting_y = y
starting_z = z
/datum/point/vector/copy_to(datum/point/vector/v = new)
..(v)
v.speed = speed
v.iteration = iteration
v.angle = angle
v.mpx = mpx
v.mpy = mpy
v.starting_x = starting_x
v.starting_y = starting_y
v.starting_z = starting_z
return v
/datum/point/vector/proc/initialize_trajectory(pixel_speed, new_angle)
if(!isnull(pixel_speed))
speed = pixel_speed
set_angle(new_angle)
/datum/point/vector/proc/set_angle(new_angle) //calculations use "byond angle" where north is 0 instead of 90, and south is 180 instead of 270.
if(isnull(angle))
return
angle = new_angle
update_offsets()
/datum/point/vector/proc/update_offsets()
mpx = sin(angle) * speed
mpy = cos(angle) * speed
/datum/point/vector/proc/set_speed(new_speed)
if(isnull(new_speed) || speed == new_speed)
return
speed = new_speed
update_offsets()
/datum/point/vector/proc/increment(multiplier = 1)
iteration++
x += mpx * (multiplier)
y += mpy * (multiplier)
/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
var/datum/point/vector/v = copy_to()
if(force_simulate)
for(var/i in 1 to amount)
v.increment(multiplier)
else
v.increment(multiplier * amount)
return v
/datum/point/vector/proc/on_z_change()
return
/datum/point/vector/processed //pixel_speed is per decisecond.
var/last_process = 0
var/last_move = 0
var/paused = FALSE
/datum/point/vector/processed/Destroy()
STOP_PROCESSING(SSprojectiles, src)
/datum/point/vector/processed/proc/start()
last_process = world.time
last_move = world.time
START_PROCESSING(SSprojectiles, src)
/datum/point/vector/processed/process()
if(paused)
last_move += world.time - last_process
last_process = world.time
return
var/needed_time = world.time - last_move
last_process = world.time
last_move = world.time
increment(needed_time / SSprojectiles.wait)
+53 -53
View File
@@ -1,54 +1,54 @@
/datum/spawners_menu
var/mob/dead/observer/owner
/datum/spawners_menu/New(mob/dead/observer/new_owner)
if(!istype(new_owner))
qdel(src)
owner = new_owner
/datum/spawners_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "spawners_menu", "Spawners Menu", 700, 600, master_ui, state)
ui.open()
/datum/spawners_menu/ui_data(mob/user)
var/list/data = list()
data["spawners"] = list()
for(var/spawner in GLOB.mob_spawners)
var/list/this = list()
this["name"] = spawner
this["desc"] = ""
this["refs"] = list()
for(var/spawner_obj in GLOB.mob_spawners[spawner])
this["refs"] += "[REF(spawner_obj)]"
if(!this["desc"])
if(istype(spawner_obj, /obj/effect/mob_spawn))
var/obj/effect/mob_spawn/MS = spawner_obj
this["desc"] = MS.flavour_text
else
var/obj/O = spawner_obj
this["desc"] = O.desc
this["amount_left"] = LAZYLEN(GLOB.mob_spawners[spawner])
data["spawners"] += list(this)
return data
/datum/spawners_menu/ui_act(action, params)
if(..())
return
var/spawner_ref = pick(GLOB.mob_spawners[params["name"]])
var/obj/effect/mob_spawn/MS = locate(spawner_ref) in GLOB.poi_list
if(!MS)
return
switch(action)
if("jump")
if(MS)
owner.forceMove(get_turf(MS))
. = TRUE
if("spawn")
if(MS)
MS.attack_ghost(owner)
/datum/spawners_menu
var/mob/dead/observer/owner
/datum/spawners_menu/New(mob/dead/observer/new_owner)
if(!istype(new_owner))
qdel(src)
owner = new_owner
/datum/spawners_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "spawners_menu", "Spawners Menu", 700, 600, master_ui, state)
ui.open()
/datum/spawners_menu/ui_data(mob/user)
var/list/data = list()
data["spawners"] = list()
for(var/spawner in GLOB.mob_spawners)
var/list/this = list()
this["name"] = spawner
this["desc"] = ""
this["refs"] = list()
for(var/spawner_obj in GLOB.mob_spawners[spawner])
this["refs"] += "[REF(spawner_obj)]"
if(!this["desc"])
if(istype(spawner_obj, /obj/effect/mob_spawn))
var/obj/effect/mob_spawn/MS = spawner_obj
this["desc"] = MS.flavour_text
else
var/obj/O = spawner_obj
this["desc"] = O.desc
this["amount_left"] = LAZYLEN(GLOB.mob_spawners[spawner])
data["spawners"] += list(this)
return data
/datum/spawners_menu/ui_act(action, params)
if(..())
return
var/spawner_ref = pick(GLOB.mob_spawners[params["name"]])
var/obj/effect/mob_spawn/MS = locate(spawner_ref) in GLOB.poi_list
if(!MS)
return
switch(action)
if("jump")
if(MS)
owner.forceMove(get_turf(MS))
. = TRUE
if("spawn")
if(MS)
MS.attack_ghost(owner)
. = TRUE
+102 -102
View File
@@ -1,102 +1,102 @@
/datum/verbs
var/name
var/list/children
var/datum/verbs/parent
var/list/verblist
var/abstract = FALSE
//returns the master list for verbs of a type
/datum/verbs/proc/GetList()
CRASH("Abstract verblist for [type]")
//do things for each entry in Generate_list
//return value sets Generate_list[verbpath]
/datum/verbs/proc/HandleVerb(list/entry, procpath/verbpath, ...)
return entry
/datum/verbs/New()
var/mainlist = GetList()
var/ourentry = mainlist[type]
children = list()
verblist = list()
if (ourentry)
if (!islist(ourentry)) //some of our childern already loaded
qdel(src)
CRASH("Verb double load: [type]")
Add_children(ourentry)
mainlist[type] = src
Load_verbs(type, typesof("[type]/verb"))
var/datum/verbs/parent = mainlist[parent_type]
if (!parent)
mainlist[parent_type] = list(src)
else if (islist(parent))
parent += src
else
parent.Add_children(list(src))
/datum/verbs/proc/Set_parent(datum/verbs/_parent)
parent = _parent
if (abstract)
parent.Add_children(children)
var/list/verblistoftypes = list()
for(var/thing in verblist)
LAZYADD(verblistoftypes[verblist[thing]], thing)
for(var/verbparenttype in verblistoftypes)
parent.Load_verbs(verbparenttype, verblistoftypes[verbparenttype])
/datum/verbs/proc/Add_children(list/kids)
if (abstract && parent)
parent.Add_children(kids)
return
for(var/thing in kids)
var/datum/verbs/item = thing
item.Set_parent(src)
if (!item.abstract)
children += item
/datum/verbs/proc/Load_verbs(verb_parent_type, list/verbs)
if (abstract && parent)
parent.Load_verbs(verb_parent_type, verbs)
return
for (var/verbpath in verbs)
verblist[verbpath] = verb_parent_type
/datum/verbs/proc/Generate_list(...)
. = list()
if (length(children))
for (var/thing in children)
var/datum/verbs/child = thing
var/list/childlist = child.Generate_list(arglist(args))
if (childlist)
var/childname = "[child]"
if (childname == "[child.type]")
var/list/tree = splittext(childname, "/")
childname = tree[tree.len]
.[child.type] = "parent=[url_encode(type)];name=[childname]"
. += childlist
for (var/thing in verblist)
var/procpath/verbpath = thing
if (!verbpath)
stack_trace("Bad VERB in [type] verblist: [english_list(verblist)]")
var/list/entry = list()
entry["parent"] = "[type]"
entry["name"] = verbpath.desc
if (copytext(verbpath.name,1,2) == "@")
entry["command"] = copytext(verbpath.name,2)
else
entry["command"] = replacetext(verbpath.name, " ", "-")
.[verbpath] = HandleVerb(arglist(list(entry, verbpath) + args))
/world/proc/LoadVerbs(verb_type)
if(!ispath(verb_type, /datum/verbs) || verb_type == /datum/verbs)
CRASH("Invalid verb_type: [verb_type]")
for (var/typepath in subtypesof(verb_type))
new typepath()
/datum/verbs
var/name
var/list/children
var/datum/verbs/parent
var/list/verblist
var/abstract = FALSE
//returns the master list for verbs of a type
/datum/verbs/proc/GetList()
CRASH("Abstract verblist for [type]")
//do things for each entry in Generate_list
//return value sets Generate_list[verbpath]
/datum/verbs/proc/HandleVerb(list/entry, procpath/verbpath, ...)
return entry
/datum/verbs/New()
var/mainlist = GetList()
var/ourentry = mainlist[type]
children = list()
verblist = list()
if (ourentry)
if (!islist(ourentry)) //some of our childern already loaded
qdel(src)
CRASH("Verb double load: [type]")
Add_children(ourentry)
mainlist[type] = src
Load_verbs(type, typesof("[type]/verb"))
var/datum/verbs/parent = mainlist[parent_type]
if (!parent)
mainlist[parent_type] = list(src)
else if (islist(parent))
parent += src
else
parent.Add_children(list(src))
/datum/verbs/proc/Set_parent(datum/verbs/_parent)
parent = _parent
if (abstract)
parent.Add_children(children)
var/list/verblistoftypes = list()
for(var/thing in verblist)
LAZYADD(verblistoftypes[verblist[thing]], thing)
for(var/verbparenttype in verblistoftypes)
parent.Load_verbs(verbparenttype, verblistoftypes[verbparenttype])
/datum/verbs/proc/Add_children(list/kids)
if (abstract && parent)
parent.Add_children(kids)
return
for(var/thing in kids)
var/datum/verbs/item = thing
item.Set_parent(src)
if (!item.abstract)
children += item
/datum/verbs/proc/Load_verbs(verb_parent_type, list/verbs)
if (abstract && parent)
parent.Load_verbs(verb_parent_type, verbs)
return
for (var/verbpath in verbs)
verblist[verbpath] = verb_parent_type
/datum/verbs/proc/Generate_list(...)
. = list()
if (length(children))
for (var/thing in children)
var/datum/verbs/child = thing
var/list/childlist = child.Generate_list(arglist(args))
if (childlist)
var/childname = "[child]"
if (childname == "[child.type]")
var/list/tree = splittext(childname, "/")
childname = tree[tree.len]
.[child.type] = "parent=[url_encode(type)];name=[childname]"
. += childlist
for (var/thing in verblist)
var/procpath/verbpath = thing
if (!verbpath)
stack_trace("Bad VERB in [type] verblist: [english_list(verblist)]")
var/list/entry = list()
entry["parent"] = "[type]"
entry["name"] = verbpath.desc
if (copytext(verbpath.name,1,2) == "@")
entry["command"] = copytext(verbpath.name,2)
else
entry["command"] = replacetext(verbpath.name, " ", "-")
.[verbpath] = HandleVerb(arglist(list(entry, verbpath) + args))
/world/proc/LoadVerbs(verb_type)
if(!ispath(verb_type, /datum/verbs) || verb_type == /datum/verbs)
CRASH("Invalid verb_type: [verb_type]")
for (var/typepath in subtypesof(verb_type))
new typepath()
+186 -184
View File
@@ -1,184 +1,186 @@
/datum/wires/airlock
holder_type = /obj/machinery/door/airlock
proper_name = "Generic Airlock"
var/wiretype
/datum/wires/airlock/secure
randomize = TRUE
/datum/wires/airlock/command
proper_name = "Command Airlock"
wiretype = "commandairlock"
/datum/wires/airlock/security
proper_name = "Security Airlock"
wiretype = "securityairlock"
/datum/wires/airlock/engineering
proper_name = "Engineering Airlock"
wiretype = "engineeringairlock"
/datum/wires/airlock/science
proper_name = "Science Airlock"
wiretype = "scienceairlock"
/datum/wires/airlock/medical
proper_name = "Medical Airlock"
wiretype = "medicalairlock"
/datum/wires/airlock/cargo
proper_name = "Cargo Airlock"
wiretype = "cargoairlock"
/datum/wires/airlock/New(atom/holder)
wires = list(
WIRE_POWER1, WIRE_POWER2,
WIRE_BACKUP1, WIRE_BACKUP2,
WIRE_OPEN, WIRE_BOLTS, WIRE_IDSCAN, WIRE_AI,
WIRE_SHOCK, WIRE_SAFETY, WIRE_TIMING, WIRE_LIGHT,
WIRE_ZAP1, WIRE_ZAP2
)
add_duds(2)
. = ..()
if(randomize || !wiretype)
return
if(!GLOB.wire_color_directory[wiretype])
colors = list()
randomize()
GLOB.wire_color_directory[wiretype] = colors
GLOB.wire_name_directory[wiretype] = proper_name
else
colors = GLOB.wire_color_directory[wiretype]
/datum/wires/airlock/interactable(mob/user)
var/obj/machinery/door/airlock/A = holder
if(!issilicon(user) && A.isElectrified() && A.shock(user, 100))
return FALSE
if(A.panel_open)
return TRUE
/datum/wires/airlock/get_status()
var/obj/machinery/door/airlock/A = holder
var/list/status = list()
status += "The door bolts [A.locked ? "have fallen!" : "look up."]"
status += "The test light is [A.hasPower() ? "on" : "off"]."
status += "The AI connection light is [A.aiControlDisabled || (A.obj_flags & EMAGGED) ? "off" : "on"]."
status += "The check wiring light is [A.safe ? "off" : "on"]."
status += "The timer is powered [A.autoclose ? "on" : "off"]."
status += "The speed light is [A.normalspeed ? "on" : "off"]."
status += "The emergency light is [A.emergency ? "on" : "off"]."
return status
/datum/wires/airlock/on_pulse(wire)
set waitfor = FALSE
var/obj/machinery/door/airlock/A = holder
switch(wire)
if(WIRE_POWER1, WIRE_POWER2) // Pulse to loose power.
A.loseMainPower()
if(WIRE_BACKUP1, WIRE_BACKUP2) // Pulse to loose backup power.
A.loseBackupPower()
if(WIRE_OPEN) // Pulse to open door (only works not emagged and ID wire is cut or no access is required).
if(A.obj_flags & EMAGGED)
return
if(!A.requiresID() || A.check_access(null))
if(A.density)
INVOKE_ASYNC(A, /obj/machinery/door/airlock.proc/open)
else
INVOKE_ASYNC(A, /obj/machinery/door/airlock.proc/close)
if(WIRE_BOLTS) // Pulse to toggle bolts (but only raise if power is on).
if(!A.locked)
A.bolt()
else
if(A.hasPower())
A.unbolt()
A.update_icon()
if(WIRE_IDSCAN) // Pulse to disable emergency access and flash red lights.
if(A.hasPower() && A.density)
A.do_animate("deny")
if(A.emergency)
A.emergency = FALSE
A.update_icon()
if(WIRE_AI) // Pulse to disable WIRE_AI control for 10 ticks (follows same rules as cutting).
if(A.aiControlDisabled == 0)
A.aiControlDisabled = 1
else if(A.aiControlDisabled == -1)
A.aiControlDisabled = 2
sleep(10)
if(A)
if(A.aiControlDisabled == 1)
A.aiControlDisabled = 0
else if(A.aiControlDisabled == 2)
A.aiControlDisabled = -1
if(WIRE_SHOCK) // Pulse to shock the door for 10 ticks.
if(!A.secondsElectrified)
A.set_electrified(30)
if(usr)
LAZYADD(A.shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(usr)]"))
log_combat(usr, A, "electrified")
if(WIRE_SAFETY)
A.safe = !A.safe
if(!A.density)
A.close()
if(WIRE_TIMING)
A.normalspeed = !A.normalspeed
if(WIRE_LIGHT)
A.lights = !A.lights
A.update_icon()
/datum/wires/airlock/on_cut(wire, mend)
var/obj/machinery/door/airlock/A = holder
switch(wire)
if(WIRE_POWER1, WIRE_POWER2) // Cut to loose power, repair all to gain power.
if(mend && !is_cut(WIRE_POWER1) && !is_cut(WIRE_POWER2))
A.regainMainPower()
if(usr)
A.shock(usr, 50)
else
A.loseMainPower()
if(usr)
A.shock(usr, 50)
if(WIRE_BACKUP1, WIRE_BACKUP2) // Cut to loose backup power, repair all to gain backup power.
if(mend && !is_cut(WIRE_BACKUP1) && !is_cut(WIRE_BACKUP2))
A.regainBackupPower()
if(usr)
A.shock(usr, 50)
else
A.loseBackupPower()
if(usr)
A.shock(usr, 50)
if(WIRE_BOLTS) // Cut to drop bolts, mend does nothing.
if(!mend)
A.bolt()
if(WIRE_AI) // Cut to disable WIRE_AI control, mend to re-enable.
if(mend)
if(A.aiControlDisabled == 1) // 0 = normal, 1 = locked out, 2 = overridden by WIRE_AI, -1 = previously overridden by WIRE_AI
A.aiControlDisabled = 0
else if(A.aiControlDisabled == 2)
A.aiControlDisabled = -1
else
if(A.aiControlDisabled == 0)
A.aiControlDisabled = 1
else if(A.aiControlDisabled == -1)
A.aiControlDisabled = 2
if(WIRE_SHOCK) // Cut to shock the door, mend to unshock.
if(mend)
if(A.secondsElectrified)
A.set_electrified(0)
else
if(A.secondsElectrified != -1)
A.set_electrified(-1)
if(usr)
LAZYADD(A.shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(usr)]"))
log_combat(usr, A, "electrified")
if(WIRE_SAFETY) // Cut to disable safeties, mend to re-enable.
A.safe = mend
if(WIRE_TIMING) // Cut to disable auto-close, mend to re-enable.
A.autoclose = mend
if(A.autoclose && !A.density)
A.close()
if(WIRE_LIGHT) // Cut to disable lights, mend to re-enable.
A.lights = mend
A.update_icon()
if(WIRE_ZAP1, WIRE_ZAP2) // Ouch.
if(usr)
A.shock(usr, 50)
/datum/wires/airlock
holder_type = /obj/machinery/door/airlock
proper_name = "Generic Airlock"
var/wiretype
/datum/wires/airlock/secure
randomize = TRUE
/datum/wires/airlock/command
proper_name = "Command Airlock"
wiretype = "commandairlock"
/datum/wires/airlock/security
proper_name = "Security Airlock"
wiretype = "securityairlock"
/datum/wires/airlock/engineering
proper_name = "Engineering Airlock"
wiretype = "engineeringairlock"
/datum/wires/airlock/science
proper_name = "Science Airlock"
wiretype = "scienceairlock"
/datum/wires/airlock/medical
proper_name = "Medical Airlock"
wiretype = "medicalairlock"
/datum/wires/airlock/cargo
proper_name = "Cargo Airlock"
wiretype = "cargoairlock"
/datum/wires/airlock/New(atom/holder)
wires = list(
WIRE_POWER1, WIRE_POWER2,
WIRE_BACKUP1, WIRE_BACKUP2,
WIRE_OPEN, WIRE_BOLTS, WIRE_IDSCAN, WIRE_AI,
WIRE_SHOCK, WIRE_SAFETY, WIRE_TIMING, WIRE_LIGHT,
WIRE_ZAP1, WIRE_ZAP2
)
add_duds(2)
. = ..()
if(randomize || !wiretype)
return
if(!GLOB.wire_color_directory[wiretype])
colors = list()
randomize()
GLOB.wire_color_directory[wiretype] = colors
GLOB.wire_name_directory[wiretype] = proper_name
else
colors = GLOB.wire_color_directory[wiretype]
/datum/wires/airlock/interactable(mob/user)
var/obj/machinery/door/airlock/A = holder
if(!issilicon(user) && A.isElectrified() && A.shock(user, 100))
return FALSE
if(A.panel_open)
return TRUE
/datum/wires/airlock/get_status()
var/obj/machinery/door/airlock/A = holder
var/list/status = list()
status += "The door bolts [A.locked ? "have fallen!" : "look up."]"
status += "The test light is [A.hasPower() ? "on" : "off"]."
status += "The AI connection light is [A.aiControlDisabled || (A.obj_flags & EMAGGED) ? "off" : "on"]."
status += "The check wiring light is [A.safe ? "off" : "on"]."
status += "The timer is powered [A.autoclose ? "on" : "off"]."
status += "The speed light is [A.normalspeed ? "on" : "off"]."
status += "The emergency light is [A.emergency ? "on" : "off"]."
return status
/datum/wires/airlock/on_pulse(wire)
set waitfor = FALSE
var/obj/machinery/door/airlock/A = holder
switch(wire)
if(WIRE_POWER1, WIRE_POWER2) // Pulse to loose power.
A.loseMainPower()
if(WIRE_BACKUP1, WIRE_BACKUP2) // Pulse to loose backup power.
A.loseBackupPower()
if(WIRE_OPEN) // Pulse to open door (only works not emagged and ID wire is cut or no access is required).
if(A.obj_flags & EMAGGED)
return
if(!A.requiresID() || A.check_access(null))
if(A.density)
INVOKE_ASYNC(A, /obj/machinery/door/airlock.proc/open)
else
INVOKE_ASYNC(A, /obj/machinery/door/airlock.proc/close)
else
holder.visible_message("<span class='notice'>You hear a a grinding noise coming from the airlock.</span>")
if(WIRE_BOLTS) // Pulse to toggle bolts (but only raise if power is on).
if(!A.locked)
A.bolt()
else
if(A.hasPower())
A.unbolt()
A.update_icon()
if(WIRE_IDSCAN) // Pulse to disable emergency access and flash red lights.
if(A.hasPower() && A.density)
A.do_animate("deny")
if(A.emergency)
A.emergency = FALSE
A.update_icon()
if(WIRE_AI) // Pulse to disable WIRE_AI control for 10 ticks (follows same rules as cutting).
if(A.aiControlDisabled == 0)
A.aiControlDisabled = 1
else if(A.aiControlDisabled == -1)
A.aiControlDisabled = 2
sleep(10)
if(A)
if(A.aiControlDisabled == 1)
A.aiControlDisabled = 0
else if(A.aiControlDisabled == 2)
A.aiControlDisabled = -1
if(WIRE_SHOCK) // Pulse to shock the door for 10 ticks.
if(!A.secondsElectrified)
A.set_electrified(30)
if(usr)
LAZYADD(A.shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(usr)]"))
log_combat(usr, A, "electrified")
if(WIRE_SAFETY)
A.safe = !A.safe
if(!A.density)
A.close()
if(WIRE_TIMING)
A.normalspeed = !A.normalspeed
if(WIRE_LIGHT)
A.lights = !A.lights
A.update_icon()
/datum/wires/airlock/on_cut(wire, mend)
var/obj/machinery/door/airlock/A = holder
switch(wire)
if(WIRE_POWER1, WIRE_POWER2) // Cut to loose power, repair all to gain power.
if(mend && !is_cut(WIRE_POWER1) && !is_cut(WIRE_POWER2))
A.regainMainPower()
if(usr)
A.shock(usr, 50)
else
A.loseMainPower()
if(usr)
A.shock(usr, 50)
if(WIRE_BACKUP1, WIRE_BACKUP2) // Cut to loose backup power, repair all to gain backup power.
if(mend && !is_cut(WIRE_BACKUP1) && !is_cut(WIRE_BACKUP2))
A.regainBackupPower()
if(usr)
A.shock(usr, 50)
else
A.loseBackupPower()
if(usr)
A.shock(usr, 50)
if(WIRE_BOLTS) // Cut to drop bolts, mend does nothing.
if(!mend)
A.bolt()
if(WIRE_AI) // Cut to disable WIRE_AI control, mend to re-enable.
if(mend)
if(A.aiControlDisabled == 1) // 0 = normal, 1 = locked out, 2 = overridden by WIRE_AI, -1 = previously overridden by WIRE_AI
A.aiControlDisabled = 0
else if(A.aiControlDisabled == 2)
A.aiControlDisabled = -1
else
if(A.aiControlDisabled == 0)
A.aiControlDisabled = 1
else if(A.aiControlDisabled == -1)
A.aiControlDisabled = 2
if(WIRE_SHOCK) // Cut to shock the door, mend to unshock.
if(mend)
if(A.secondsElectrified)
A.set_electrified(0)
else
if(A.secondsElectrified != -1)
A.set_electrified(-1)
if(usr)
LAZYADD(A.shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(usr)]"))
log_combat(usr, A, "electrified")
if(WIRE_SAFETY) // Cut to disable safeties, mend to re-enable.
A.safe = mend
if(WIRE_TIMING) // Cut to disable auto-close, mend to re-enable.
A.autoclose = mend
if(A.autoclose && !A.density)
A.close()
if(WIRE_LIGHT) // Cut to disable lights, mend to re-enable.
A.lights = mend
A.update_icon()
if(WIRE_ZAP1, WIRE_ZAP2) // Ouch.
if(usr)
A.shock(usr, 50)
+30 -30
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)
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The charge light flickers.</span>")
if(WIRE_AVOIDANCE)
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The external warning lights flash briefly.</span>")
if(WIRE_LOADCHECK)
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The load platform clunks.</span>")
if(WIRE_MOTOR1, WIRE_MOTOR2)
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The drive motor whines briefly.</span>")
else
/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'>[icon2html(M, viewers(holder))] The charge light flickers.</span>")
if(WIRE_AVOIDANCE)
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The external warning lights flash briefly.</span>")
if(WIRE_LOADCHECK)
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The load platform clunks.</span>")
if(WIRE_MOTOR1, WIRE_MOTOR2)
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The drive motor whines briefly.</span>")
else
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] You hear a radio crackle.</span>")
+47 -47
View File
@@ -1,48 +1,48 @@
/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("[icon2html(C, viewers(holder))]<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)
C.remove_strength()
/datum/wires/particle_accelerator/control_box/emp_pulse() // to prevent singulo from pulsing wires
/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("[icon2html(C, viewers(holder))]<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)
C.remove_strength()
/datum/wires/particle_accelerator/control_box/emp_pulse() // to prevent singulo from pulsing wires
return
+86 -86
View File
@@ -1,86 +1,86 @@
/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.builtInCamera) && R.builtInCamera.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, user)
var/mob/living/silicon/robot/R = holder
switch(wire)
if(WIRE_AI) // Pulse to pick a new AI.
if(!R.emagged)
var/new_ai
if(user)
new_ai = select_active_ai(user)
else
new_ai = select_active_ai(R)
R.notify_ai(DISCONNECT)
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(!QDELETED(R.builtInCamera) && !R.scrambledcodes)
R.builtInCamera.toggle_cam(usr, 0)
R.visible_message("[R]'s camera lens focuses loudly.", "Your camera lens 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.notify_ai(DISCONNECT)
if(R.shell)
R.undeploy()
R.connected_ai = null
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(!QDELETED(R.builtInCamera) && !R.scrambledcodes)
R.builtInCamera.status = mend
R.builtInCamera.toggle_cam(usr, 0)
R.visible_message("[R]'s camera lens focuses loudly.", "Your camera lens focuses loudly.")
if(WIRE_LOCKDOWN) // Simple lockdown.
R.SetLockdown(!mend)
if(WIRE_RESET_MODULE)
if(R.has_module() && !mend)
R.ResetModule()
/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.builtInCamera) && R.builtInCamera.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, user)
var/mob/living/silicon/robot/R = holder
switch(wire)
if(WIRE_AI) // Pulse to pick a new AI.
if(!R.emagged)
var/new_ai
if(user)
new_ai = select_active_ai(user)
else
new_ai = select_active_ai(R)
R.notify_ai(DISCONNECT)
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(!QDELETED(R.builtInCamera) && !R.scrambledcodes)
R.builtInCamera.toggle_cam(usr, 0)
R.visible_message("[R]'s camera lens focuses loudly.", "Your camera lens 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.notify_ai(DISCONNECT)
if(R.shell)
R.undeploy()
R.connected_ai = null
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(!QDELETED(R.builtInCamera) && !R.scrambledcodes)
R.builtInCamera.status = mend
R.builtInCamera.toggle_cam(usr, 0)
R.visible_message("[R]'s camera lens focuses loudly.", "Your camera lens focuses loudly.")
if(WIRE_LOCKDOWN) // Simple lockdown.
R.SetLockdown(!mend)
if(WIRE_RESET_MODULE)
if(R.has_module() && !mend)
R.ResetModule()
+92 -92
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)
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] An alarm sounds! It's go-</span>")
B.explode_now = TRUE
tell_admins(B)
if(WIRE_UNBOLT)
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bolts spin in place for a moment.</span>")
if(WIRE_DELAY)
if(B.delayedbig)
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bomb has already been delayed.</span>")
else
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bomb chirps.</span>")
playsound(B, 'sound/machines/chime.ogg', 30, 1)
B.detonation_timer += 300
B.delayedbig = TRUE
if(WIRE_PROCEED)
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] 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)
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] You hear the bomb start ticking!</span>")
B.activate()
B.update_icon()
else if(B.delayedlittle)
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] Nothing happens.</span>")
else
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] 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)
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] 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)
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] 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)
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] An alarm sounds! It's go-</span>")
B.explode_now = TRUE
tell_admins(B)
if(WIRE_ACTIVATE)
if(!mend && B.active)
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] 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 [AREACOORD(T)].")
message_admins("A [B.name] was detonated via boom wire at [ADMIN_VERBOSEJMP(T)].")
/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'>[icon2html(B, viewers(holder))] An alarm sounds! It's go-</span>")
B.explode_now = TRUE
tell_admins(B)
if(WIRE_UNBOLT)
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bolts spin in place for a moment.</span>")
if(WIRE_DELAY)
if(B.delayedbig)
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bomb has already been delayed.</span>")
else
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bomb chirps.</span>")
playsound(B, 'sound/machines/chime.ogg', 30, 1)
B.detonation_timer += 300
B.delayedbig = TRUE
if(WIRE_PROCEED)
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] 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)
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] You hear the bomb start ticking!</span>")
B.activate()
B.update_icon()
else if(B.delayedlittle)
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] Nothing happens.</span>")
else
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] 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)
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] 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)
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] 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)
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] An alarm sounds! It's go-</span>")
B.explode_now = TRUE
tell_admins(B)
if(WIRE_ACTIVATE)
if(!mend && B.active)
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] 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 [AREACOORD(T)].")
message_admins("A [B.name] was detonated via boom wire at [ADMIN_VERBOSEJMP(T)].")