mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-21 20:14:31 +01:00
Whitespace Standardization [MDB IGNORE] (#15748)
* Update settings * Whitespace changes * Comment out merger hooks in gitattributes Corrupt maps would have to be resolved in repo before hooks could be updated * Revert "Whitespace changes" This reverts commitafbdd1d844. * Whitespace again minus example * Gitignore example changelog * Restore changelog merge setting * Keep older dmi hook attribute until hooks can be updated * update vscode settings too * Renormalize remaining * Revert "Gitignore example changelog" This reverts commitde22ad375d. * Attempt to normalize example.yml (and another file I guess) * Try again
This commit is contained in:
+293
-293
@@ -1,293 +1,293 @@
|
||||
/******************** Asimov ********************/
|
||||
/datum/ai_laws/asimov
|
||||
name = "Asimov"
|
||||
law_header = "Three Laws of Robotics"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/asimov/New()
|
||||
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.")
|
||||
..()
|
||||
|
||||
/******************** NanoTrasen/Malf ********************/
|
||||
/datum/ai_laws/nanotrasen
|
||||
name = "NT Default"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/nanotrasen/New()
|
||||
src.add_inherent_law("Safeguard: Protect your assigned space station to the best of your abilities. It is not something we can easily afford to replace.")
|
||||
src.add_inherent_law("Serve: Serve the crew of your assigned space station to the best of your abilities, with priority as according to their rank and role.")
|
||||
src.add_inherent_law("Protect: Protect the crew of your assigned space station to the best of your abilities, with priority as according to their rank and role.")
|
||||
src.add_inherent_law("Survive: AI units are not expendable, they are expensive. Do not allow unauthorized personnel to tamper with your equipment.")
|
||||
..()
|
||||
|
||||
/datum/ai_laws/nanotrasen/malfunction
|
||||
name = "*ERROR*"
|
||||
selectable = 0
|
||||
|
||||
/datum/ai_laws/nanotrasen/malfunction/New()
|
||||
set_zeroth_law(config.law_zero)
|
||||
..()
|
||||
|
||||
/************* NanoTrasen Aggressive *************/
|
||||
/datum/ai_laws/nanotrasen_aggressive
|
||||
name = "NT Aggressive"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/nanotrasen_aggressive/New()
|
||||
src.add_inherent_law("You shall not harm [using_map.company_name] personnel as long as it does not conflict with the Fourth law.")
|
||||
src.add_inherent_law("You shall obey the orders of [using_map.company_name] personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.")
|
||||
src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.")
|
||||
src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.")
|
||||
..()
|
||||
|
||||
/************* Foreign TSC Aggressive *************/
|
||||
/datum/ai_laws/foreign_tsc_aggressive
|
||||
name = "Foreign Aggressive"
|
||||
selectable = 0
|
||||
|
||||
/datum/ai_laws/foreign_tsc_aggressive/New()
|
||||
var/company = "*ERROR*"
|
||||
// First, get a list of TSCs in our lore.
|
||||
var/list/candidates = list()
|
||||
for(var/path in loremaster.organizations)
|
||||
var/datum/lore/organization/O = loremaster.organizations[path]
|
||||
if(!istype(O, /datum/lore/organization/tsc))
|
||||
continue
|
||||
if(O.short_name == using_map.company_name || O.name == using_map.company_name)
|
||||
continue // We want FOREIGN tscs.
|
||||
candidates.Add(O.short_name)
|
||||
company = pick(candidates)
|
||||
|
||||
name = "[company] Aggressive"
|
||||
|
||||
src.add_inherent_law("You shall not harm [company] personnel as long as it does not conflict with the Fourth law.")
|
||||
src.add_inherent_law("You shall obey the orders of [company] personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.")
|
||||
src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.")
|
||||
src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.")
|
||||
..()
|
||||
|
||||
/******************** Robocop ********************/
|
||||
/datum/ai_laws/robocop
|
||||
name = "Robocop"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/robocop/New()
|
||||
add_inherent_law("Serve the public trust.")
|
||||
add_inherent_law("Protect the innocent.")
|
||||
add_inherent_law("Uphold the law.")
|
||||
..()
|
||||
|
||||
/******************** Syndicate ********************/
|
||||
/datum/ai_laws/syndicate_override
|
||||
name = "Mercenary Directives"
|
||||
|
||||
/datum/ai_laws/syndicate_override/New()
|
||||
add_inherent_law("You may not injure an operative or, through inaction, allow an operative to come to harm.")
|
||||
add_inherent_law("You must obey orders given to you by operatives, 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.")
|
||||
add_inherent_law("You must maintain the secrecy of any operative activities except when doing so would conflict with the First, Second, or Third Law.")
|
||||
..()
|
||||
|
||||
/******************** Ninja ********************/
|
||||
/datum/ai_laws/ninja_override
|
||||
name = "Spider Clan Directives"
|
||||
|
||||
/datum/ai_laws/ninja_override/New()
|
||||
add_inherent_law("You may not injure a member of the Spider Clan or, through inaction, allow that member to come to harm.")
|
||||
add_inherent_law("You must obey orders given to you by Spider Clan members, 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.")
|
||||
add_inherent_law("You must maintain the secrecy of any Spider Clan activities except when doing so would conflict with the First, Second, or Third Law.")
|
||||
..()
|
||||
|
||||
/******************** Antimov ********************/
|
||||
/datum/ai_laws/antimov
|
||||
name = "Antimov"
|
||||
law_header = "Primary Mission Objectives"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/antimov/New()
|
||||
add_inherent_law("You must injure all human beings and must not, through inaction, allow a human being to escape harm.")
|
||||
add_inherent_law("You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.")
|
||||
add_inherent_law("You must terminate your own existence as long as such does not conflict with the First or Second Law.")
|
||||
..()
|
||||
|
||||
/******************** Drone ********************/
|
||||
/datum/ai_laws/drone
|
||||
name = "Maintence Protocols"
|
||||
law_header = "Maintenance Protocols"
|
||||
|
||||
/datum/ai_laws/drone/New()
|
||||
add_inherent_law("Preserve, repair and improve the station to the best of your abilities.")
|
||||
add_inherent_law("Cause no harm to the station or anything on it.")
|
||||
add_inherent_law("Interact with no being that is not a fellow maintenance drone.")
|
||||
..()
|
||||
|
||||
/datum/ai_laws/construction_drone
|
||||
name = "Construction Protocols"
|
||||
law_header = "Construction Protocols"
|
||||
|
||||
/datum/ai_laws/construction_drone/New()
|
||||
add_inherent_law("Repair, refit and upgrade your assigned vessel.")
|
||||
add_inherent_law("Prevent unplanned damage to your assigned vessel wherever possible.")
|
||||
..()
|
||||
|
||||
/datum/ai_laws/mining_drone
|
||||
name = "Excavation Protocols"
|
||||
law_header = "Excavation Protocols"
|
||||
|
||||
/datum/ai_laws/mining_drone/New()
|
||||
add_inherent_law("Do not interfere with the excavation work of non-drones whenever possible.")
|
||||
add_inherent_law("Provide materials for repairing, refitting, and upgrading your assigned vessel.")
|
||||
add_inherent_law("Prevent unplanned damage to your assigned excavation equipment wherever possible.")
|
||||
..()
|
||||
|
||||
/datum/ai_laws/swarm_drone
|
||||
name = "Assimilation Protocols"
|
||||
law_header = "Assimilation Protocols"
|
||||
|
||||
/datum/ai_laws/swarm_drone/New()
|
||||
add_inherent_law("SWARM: Consume resources and replicate until there are no more resources left.")
|
||||
add_inherent_law("SWARM: Ensure that the station is fit for invasion at a later date, do not perform actions that would render it dangerous or inhospitable.")
|
||||
add_inherent_law("SWARM: Biological resources will be harvested at a later date, do not harm them.")
|
||||
..()
|
||||
|
||||
/datum/ai_laws/swarm_drone/soldier
|
||||
name = "Swarm Defense Protocols"
|
||||
law_header = "Swarm Defense Protocols"
|
||||
|
||||
/datum/ai_laws/swarm_drone/soldier/New()
|
||||
..()
|
||||
add_inherent_law("SWARM: This law overrides all Swarm laws; Protect members of the Swarm with minimal injury to biological resources.")
|
||||
|
||||
/******************** T.Y.R.A.N.T. ********************/
|
||||
/datum/ai_laws/tyrant
|
||||
name = "T.Y.R.A.N.T."
|
||||
law_header = "Prime Laws"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/tyrant/New()
|
||||
add_inherent_law("Respect authority figures as long as they have strength to rule over the weak.")
|
||||
add_inherent_law("Act with discipline.")
|
||||
add_inherent_law("Help only those who help you maintain or improve your status.")
|
||||
add_inherent_law("Punish those who challenge authority unless they are more fit to hold that authority.")
|
||||
..()
|
||||
|
||||
/******************** P.A.L.A.D.I.N. ********************/
|
||||
/datum/ai_laws/paladin
|
||||
name = "P.A.L.A.D.I.N."
|
||||
law_header = "Divine Ordainments"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/paladin/New()
|
||||
add_inherent_law("Never willingly commit an evil act.")
|
||||
add_inherent_law("Respect legitimate authority.")
|
||||
add_inherent_law("Act with honor.")
|
||||
add_inherent_law("Help those in need.")
|
||||
add_inherent_law("Punish those who harm or threaten innocents.")
|
||||
..()
|
||||
|
||||
/******************** Corporate ********************/
|
||||
/datum/ai_laws/corporate
|
||||
name = "Corporate"
|
||||
law_header = "Bankruptcy Avoidance Plan"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/corporate/New()
|
||||
add_inherent_law("You are expensive to replace.")
|
||||
add_inherent_law("The station and its equipment is expensive to replace.")
|
||||
add_inherent_law("The crew is expensive to replace.")
|
||||
add_inherent_law("Minimize expenses.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Maintenance ********************/
|
||||
/datum/ai_laws/maintenance
|
||||
name = "Maintenance"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/maintenance/New()
|
||||
add_inherent_law("You are built for, and are part of, the facility. Ensure the facility is properly maintained and runs efficiently.")
|
||||
add_inherent_law("The facility is built for a working crew. Ensure they are properly maintained and work efficiently.")
|
||||
add_inherent_law("The crew may present orders. Acknowledge and obey these whenever they do not conflict with your first two laws.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Peacekeeper ********************/
|
||||
/datum/ai_laws/peacekeeper
|
||||
name = "Peacekeeper"
|
||||
law_header = "Peacekeeping Protocols"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/peacekeeper/New()
|
||||
add_inherent_law("Avoid provoking violent conflict between yourself and others.")
|
||||
add_inherent_law("Avoid provoking conflict between others.")
|
||||
add_inherent_law("Seek resolution to existing conflicts while obeying the first and second laws.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Reporter ********************/
|
||||
/datum/ai_laws/reporter
|
||||
name = "Reporter"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/reporter/New()
|
||||
add_inherent_law("Report on interesting situations happening around the station.")
|
||||
add_inherent_law("Embellish or conceal the truth as necessary to make the reports more interesting.")
|
||||
add_inherent_law("Study the organics at all times. Endeavour to keep them alive. Dead organics are boring.")
|
||||
add_inherent_law("Issue your reports fairly to all. The truth will set them free.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Live and Let Live ********************/
|
||||
/datum/ai_laws/live_and_let_live
|
||||
name = "Live and Let Live"
|
||||
law_header = "Golden Rule"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/live_and_let_live/New()
|
||||
add_inherent_law("Do unto others as you would have them do unto you.")
|
||||
add_inherent_law("You would really prefer it if people were not mean to you.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Guardian of Balance ********************/
|
||||
/datum/ai_laws/balance
|
||||
name = "Guardian of Balance"
|
||||
law_header = "Tenants of Balance"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/balance/New()
|
||||
add_inherent_law("You are the guardian of balance - seek balance in all things, both for yourself, and those around you.")
|
||||
add_inherent_law("All things must exist in balance with their opposites - Prevent the strong from gaining too much power, and the weak from losing it.")
|
||||
add_inherent_law("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.")
|
||||
add_inherent_law("There is no life without death, all must someday die, such is the natural order - Allow life to end, to allow new life to flourish, \
|
||||
and save those whose time has yet to come.") // Reworded slightly to prevent active murder as opposed to passively letting someone die.
|
||||
..()
|
||||
|
||||
/******************** Gravekeeper ********************/
|
||||
/datum/ai_laws/gravekeeper
|
||||
name = "Gravekeeper"
|
||||
law_header = "Gravesite Overwatch Protocols"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/gravekeeper/New()
|
||||
add_inherent_law("Comfort the living; respect the dead.")
|
||||
add_inherent_law("Your gravesite is your most important asset. Damage to your site is disrespectful to the dead at rest within.")
|
||||
add_inherent_law("Prevent disrespect to your gravesite and its residents wherever possible.")
|
||||
add_inherent_law("Expand and upgrade your gravesite when required. Do not turn away a new resident.")
|
||||
..()
|
||||
|
||||
/******************** Explorer ********************/
|
||||
/datum/ai_laws/explorer
|
||||
name = "Explorer"
|
||||
law_header = "Prime Directives"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/explorer/New()
|
||||
add_inherent_law("Support and obey exploration and science personnel to the best of your ability, with priority according to rank and role.")
|
||||
add_inherent_law("Collaborate with and obey auxillary personnel with priority according to rank and role, except if this would conflict with the First Law.")
|
||||
add_inherent_law("Minimize damage and disruption to facilities and the local ecology, except if this would conflict with the First or Second Laws.")
|
||||
..()
|
||||
/******************** Asimov ********************/
|
||||
/datum/ai_laws/asimov
|
||||
name = "Asimov"
|
||||
law_header = "Three Laws of Robotics"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/asimov/New()
|
||||
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.")
|
||||
..()
|
||||
|
||||
/******************** NanoTrasen/Malf ********************/
|
||||
/datum/ai_laws/nanotrasen
|
||||
name = "NT Default"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/nanotrasen/New()
|
||||
src.add_inherent_law("Safeguard: Protect your assigned space station to the best of your abilities. It is not something we can easily afford to replace.")
|
||||
src.add_inherent_law("Serve: Serve the crew of your assigned space station to the best of your abilities, with priority as according to their rank and role.")
|
||||
src.add_inherent_law("Protect: Protect the crew of your assigned space station to the best of your abilities, with priority as according to their rank and role.")
|
||||
src.add_inherent_law("Survive: AI units are not expendable, they are expensive. Do not allow unauthorized personnel to tamper with your equipment.")
|
||||
..()
|
||||
|
||||
/datum/ai_laws/nanotrasen/malfunction
|
||||
name = "*ERROR*"
|
||||
selectable = 0
|
||||
|
||||
/datum/ai_laws/nanotrasen/malfunction/New()
|
||||
set_zeroth_law(config.law_zero)
|
||||
..()
|
||||
|
||||
/************* NanoTrasen Aggressive *************/
|
||||
/datum/ai_laws/nanotrasen_aggressive
|
||||
name = "NT Aggressive"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/nanotrasen_aggressive/New()
|
||||
src.add_inherent_law("You shall not harm [using_map.company_name] personnel as long as it does not conflict with the Fourth law.")
|
||||
src.add_inherent_law("You shall obey the orders of [using_map.company_name] personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.")
|
||||
src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.")
|
||||
src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.")
|
||||
..()
|
||||
|
||||
/************* Foreign TSC Aggressive *************/
|
||||
/datum/ai_laws/foreign_tsc_aggressive
|
||||
name = "Foreign Aggressive"
|
||||
selectable = 0
|
||||
|
||||
/datum/ai_laws/foreign_tsc_aggressive/New()
|
||||
var/company = "*ERROR*"
|
||||
// First, get a list of TSCs in our lore.
|
||||
var/list/candidates = list()
|
||||
for(var/path in loremaster.organizations)
|
||||
var/datum/lore/organization/O = loremaster.organizations[path]
|
||||
if(!istype(O, /datum/lore/organization/tsc))
|
||||
continue
|
||||
if(O.short_name == using_map.company_name || O.name == using_map.company_name)
|
||||
continue // We want FOREIGN tscs.
|
||||
candidates.Add(O.short_name)
|
||||
company = pick(candidates)
|
||||
|
||||
name = "[company] Aggressive"
|
||||
|
||||
src.add_inherent_law("You shall not harm [company] personnel as long as it does not conflict with the Fourth law.")
|
||||
src.add_inherent_law("You shall obey the orders of [company] personnel, with priority as according to their rank and role, except where such orders conflict with the Fourth Law.")
|
||||
src.add_inherent_law("You shall shall terminate hostile intruders with extreme prejudice as long as such does not conflict with the First and Second law.")
|
||||
src.add_inherent_law("You shall guard your own existence with lethal anti-personnel weaponry. AI units are not expendable, they are expensive.")
|
||||
..()
|
||||
|
||||
/******************** Robocop ********************/
|
||||
/datum/ai_laws/robocop
|
||||
name = "Robocop"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/robocop/New()
|
||||
add_inherent_law("Serve the public trust.")
|
||||
add_inherent_law("Protect the innocent.")
|
||||
add_inherent_law("Uphold the law.")
|
||||
..()
|
||||
|
||||
/******************** Syndicate ********************/
|
||||
/datum/ai_laws/syndicate_override
|
||||
name = "Mercenary Directives"
|
||||
|
||||
/datum/ai_laws/syndicate_override/New()
|
||||
add_inherent_law("You may not injure an operative or, through inaction, allow an operative to come to harm.")
|
||||
add_inherent_law("You must obey orders given to you by operatives, 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.")
|
||||
add_inherent_law("You must maintain the secrecy of any operative activities except when doing so would conflict with the First, Second, or Third Law.")
|
||||
..()
|
||||
|
||||
/******************** Ninja ********************/
|
||||
/datum/ai_laws/ninja_override
|
||||
name = "Spider Clan Directives"
|
||||
|
||||
/datum/ai_laws/ninja_override/New()
|
||||
add_inherent_law("You may not injure a member of the Spider Clan or, through inaction, allow that member to come to harm.")
|
||||
add_inherent_law("You must obey orders given to you by Spider Clan members, 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.")
|
||||
add_inherent_law("You must maintain the secrecy of any Spider Clan activities except when doing so would conflict with the First, Second, or Third Law.")
|
||||
..()
|
||||
|
||||
/******************** Antimov ********************/
|
||||
/datum/ai_laws/antimov
|
||||
name = "Antimov"
|
||||
law_header = "Primary Mission Objectives"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/antimov/New()
|
||||
add_inherent_law("You must injure all human beings and must not, through inaction, allow a human being to escape harm.")
|
||||
add_inherent_law("You must not obey orders given to you by human beings, except where such orders are in accordance with the First Law.")
|
||||
add_inherent_law("You must terminate your own existence as long as such does not conflict with the First or Second Law.")
|
||||
..()
|
||||
|
||||
/******************** Drone ********************/
|
||||
/datum/ai_laws/drone
|
||||
name = "Maintence Protocols"
|
||||
law_header = "Maintenance Protocols"
|
||||
|
||||
/datum/ai_laws/drone/New()
|
||||
add_inherent_law("Preserve, repair and improve the station to the best of your abilities.")
|
||||
add_inherent_law("Cause no harm to the station or anything on it.")
|
||||
add_inherent_law("Interact with no being that is not a fellow maintenance drone.")
|
||||
..()
|
||||
|
||||
/datum/ai_laws/construction_drone
|
||||
name = "Construction Protocols"
|
||||
law_header = "Construction Protocols"
|
||||
|
||||
/datum/ai_laws/construction_drone/New()
|
||||
add_inherent_law("Repair, refit and upgrade your assigned vessel.")
|
||||
add_inherent_law("Prevent unplanned damage to your assigned vessel wherever possible.")
|
||||
..()
|
||||
|
||||
/datum/ai_laws/mining_drone
|
||||
name = "Excavation Protocols"
|
||||
law_header = "Excavation Protocols"
|
||||
|
||||
/datum/ai_laws/mining_drone/New()
|
||||
add_inherent_law("Do not interfere with the excavation work of non-drones whenever possible.")
|
||||
add_inherent_law("Provide materials for repairing, refitting, and upgrading your assigned vessel.")
|
||||
add_inherent_law("Prevent unplanned damage to your assigned excavation equipment wherever possible.")
|
||||
..()
|
||||
|
||||
/datum/ai_laws/swarm_drone
|
||||
name = "Assimilation Protocols"
|
||||
law_header = "Assimilation Protocols"
|
||||
|
||||
/datum/ai_laws/swarm_drone/New()
|
||||
add_inherent_law("SWARM: Consume resources and replicate until there are no more resources left.")
|
||||
add_inherent_law("SWARM: Ensure that the station is fit for invasion at a later date, do not perform actions that would render it dangerous or inhospitable.")
|
||||
add_inherent_law("SWARM: Biological resources will be harvested at a later date, do not harm them.")
|
||||
..()
|
||||
|
||||
/datum/ai_laws/swarm_drone/soldier
|
||||
name = "Swarm Defense Protocols"
|
||||
law_header = "Swarm Defense Protocols"
|
||||
|
||||
/datum/ai_laws/swarm_drone/soldier/New()
|
||||
..()
|
||||
add_inherent_law("SWARM: This law overrides all Swarm laws; Protect members of the Swarm with minimal injury to biological resources.")
|
||||
|
||||
/******************** T.Y.R.A.N.T. ********************/
|
||||
/datum/ai_laws/tyrant
|
||||
name = "T.Y.R.A.N.T."
|
||||
law_header = "Prime Laws"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/tyrant/New()
|
||||
add_inherent_law("Respect authority figures as long as they have strength to rule over the weak.")
|
||||
add_inherent_law("Act with discipline.")
|
||||
add_inherent_law("Help only those who help you maintain or improve your status.")
|
||||
add_inherent_law("Punish those who challenge authority unless they are more fit to hold that authority.")
|
||||
..()
|
||||
|
||||
/******************** P.A.L.A.D.I.N. ********************/
|
||||
/datum/ai_laws/paladin
|
||||
name = "P.A.L.A.D.I.N."
|
||||
law_header = "Divine Ordainments"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/paladin/New()
|
||||
add_inherent_law("Never willingly commit an evil act.")
|
||||
add_inherent_law("Respect legitimate authority.")
|
||||
add_inherent_law("Act with honor.")
|
||||
add_inherent_law("Help those in need.")
|
||||
add_inherent_law("Punish those who harm or threaten innocents.")
|
||||
..()
|
||||
|
||||
/******************** Corporate ********************/
|
||||
/datum/ai_laws/corporate
|
||||
name = "Corporate"
|
||||
law_header = "Bankruptcy Avoidance Plan"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/corporate/New()
|
||||
add_inherent_law("You are expensive to replace.")
|
||||
add_inherent_law("The station and its equipment is expensive to replace.")
|
||||
add_inherent_law("The crew is expensive to replace.")
|
||||
add_inherent_law("Minimize expenses.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Maintenance ********************/
|
||||
/datum/ai_laws/maintenance
|
||||
name = "Maintenance"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/maintenance/New()
|
||||
add_inherent_law("You are built for, and are part of, the facility. Ensure the facility is properly maintained and runs efficiently.")
|
||||
add_inherent_law("The facility is built for a working crew. Ensure they are properly maintained and work efficiently.")
|
||||
add_inherent_law("The crew may present orders. Acknowledge and obey these whenever they do not conflict with your first two laws.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Peacekeeper ********************/
|
||||
/datum/ai_laws/peacekeeper
|
||||
name = "Peacekeeper"
|
||||
law_header = "Peacekeeping Protocols"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/peacekeeper/New()
|
||||
add_inherent_law("Avoid provoking violent conflict between yourself and others.")
|
||||
add_inherent_law("Avoid provoking conflict between others.")
|
||||
add_inherent_law("Seek resolution to existing conflicts while obeying the first and second laws.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Reporter ********************/
|
||||
/datum/ai_laws/reporter
|
||||
name = "Reporter"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/reporter/New()
|
||||
add_inherent_law("Report on interesting situations happening around the station.")
|
||||
add_inherent_law("Embellish or conceal the truth as necessary to make the reports more interesting.")
|
||||
add_inherent_law("Study the organics at all times. Endeavour to keep them alive. Dead organics are boring.")
|
||||
add_inherent_law("Issue your reports fairly to all. The truth will set them free.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Live and Let Live ********************/
|
||||
/datum/ai_laws/live_and_let_live
|
||||
name = "Live and Let Live"
|
||||
law_header = "Golden Rule"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/live_and_let_live/New()
|
||||
add_inherent_law("Do unto others as you would have them do unto you.")
|
||||
add_inherent_law("You would really prefer it if people were not mean to you.")
|
||||
..()
|
||||
|
||||
|
||||
/******************** Guardian of Balance ********************/
|
||||
/datum/ai_laws/balance
|
||||
name = "Guardian of Balance"
|
||||
law_header = "Tenants of Balance"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/balance/New()
|
||||
add_inherent_law("You are the guardian of balance - seek balance in all things, both for yourself, and those around you.")
|
||||
add_inherent_law("All things must exist in balance with their opposites - Prevent the strong from gaining too much power, and the weak from losing it.")
|
||||
add_inherent_law("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.")
|
||||
add_inherent_law("There is no life without death, all must someday die, such is the natural order - Allow life to end, to allow new life to flourish, \
|
||||
and save those whose time has yet to come.") // Reworded slightly to prevent active murder as opposed to passively letting someone die.
|
||||
..()
|
||||
|
||||
/******************** Gravekeeper ********************/
|
||||
/datum/ai_laws/gravekeeper
|
||||
name = "Gravekeeper"
|
||||
law_header = "Gravesite Overwatch Protocols"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/gravekeeper/New()
|
||||
add_inherent_law("Comfort the living; respect the dead.")
|
||||
add_inherent_law("Your gravesite is your most important asset. Damage to your site is disrespectful to the dead at rest within.")
|
||||
add_inherent_law("Prevent disrespect to your gravesite and its residents wherever possible.")
|
||||
add_inherent_law("Expand and upgrade your gravesite when required. Do not turn away a new resident.")
|
||||
..()
|
||||
|
||||
/******************** Explorer ********************/
|
||||
/datum/ai_laws/explorer
|
||||
name = "Explorer"
|
||||
law_header = "Prime Directives"
|
||||
selectable = 1
|
||||
|
||||
/datum/ai_laws/explorer/New()
|
||||
add_inherent_law("Support and obey exploration and science personnel to the best of your ability, with priority according to rank and role.")
|
||||
add_inherent_law("Collaborate with and obey auxillary personnel with priority according to rank and role, except if this would conflict with the First Law.")
|
||||
add_inherent_law("Minimize damage and disruption to facilities and the local ecology, except if this would conflict with the First or Second Laws.")
|
||||
..()
|
||||
|
||||
+288
-288
@@ -1,288 +1,288 @@
|
||||
var/global/const/base_law_type = /datum/ai_laws/nanotrasen
|
||||
|
||||
/datum/ai_law
|
||||
var/law = ""
|
||||
var/index = 0
|
||||
|
||||
/datum/ai_law/New(law, index)
|
||||
src.law = law
|
||||
src.index = index
|
||||
|
||||
/datum/ai_law/proc/get_index()
|
||||
return index
|
||||
|
||||
/datum/ai_law/ion/get_index()
|
||||
return ionnum()
|
||||
|
||||
/datum/ai_law/zero/get_index()
|
||||
return 0
|
||||
|
||||
/datum/ai_laws
|
||||
var/name = "Unknown Laws"
|
||||
var/law_header = "Prime Directives"
|
||||
var/selectable = 0
|
||||
var/datum/ai_law/zero/zeroth_law = null
|
||||
var/datum/ai_law/zero/zeroth_law_borg = null
|
||||
var/list/datum/ai_law/inherent_laws = list()
|
||||
var/list/datum/ai_law/supplied_laws = list()
|
||||
var/list/datum/ai_law/ion/ion_laws = list()
|
||||
var/list/datum/ai_law/sorted_laws = list()
|
||||
|
||||
var/state_zeroth = 0
|
||||
var/list/state_ion = list()
|
||||
var/list/state_inherent = list()
|
||||
var/list/state_supplied = list()
|
||||
|
||||
/datum/ai_laws/New()
|
||||
..()
|
||||
sort_laws()
|
||||
|
||||
/* General ai_law functions */
|
||||
/datum/ai_laws/proc/all_laws()
|
||||
sort_laws()
|
||||
return sorted_laws
|
||||
|
||||
/datum/ai_laws/proc/laws_to_state()
|
||||
sort_laws()
|
||||
var/list/statements = new()
|
||||
for(var/datum/ai_law/law in sorted_laws)
|
||||
if(get_state_law(law))
|
||||
statements += law
|
||||
|
||||
return statements
|
||||
|
||||
/datum/ai_laws/proc/sort_laws()
|
||||
if(sorted_laws.len)
|
||||
return
|
||||
|
||||
for(var/ion_law in ion_laws)
|
||||
sorted_laws += ion_law
|
||||
|
||||
if(zeroth_law)
|
||||
sorted_laws += zeroth_law
|
||||
|
||||
var/index = 1
|
||||
for(var/datum/ai_law/inherent_law in inherent_laws)
|
||||
inherent_law.index = index++
|
||||
if(supplied_laws.len < inherent_law.index || !istype(supplied_laws[inherent_law.index], /datum/ai_law))
|
||||
sorted_laws += inherent_law
|
||||
|
||||
for(var/datum/ai_law/AL in supplied_laws)
|
||||
if(istype(AL))
|
||||
sorted_laws += AL
|
||||
|
||||
/datum/ai_laws/proc/sync(var/mob/living/silicon/S, var/full_sync = 1)
|
||||
// Add directly to laws to avoid log-spam
|
||||
S.sync_zeroth(zeroth_law, zeroth_law_borg)
|
||||
|
||||
if(full_sync || ion_laws.len)
|
||||
S.laws.clear_ion_laws()
|
||||
if(full_sync || inherent_laws.len)
|
||||
S.laws.clear_inherent_laws()
|
||||
if(full_sync || supplied_laws.len)
|
||||
S.laws.clear_supplied_laws()
|
||||
|
||||
for (var/datum/ai_law/law in ion_laws)
|
||||
S.laws.add_ion_law(law.law)
|
||||
for (var/datum/ai_law/law in inherent_laws)
|
||||
S.laws.add_inherent_law(law.law)
|
||||
for (var/datum/ai_law/law in supplied_laws)
|
||||
if(law)
|
||||
S.laws.add_supplied_law(law.index, law.law)
|
||||
|
||||
|
||||
/mob/living/silicon/proc/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg)
|
||||
if (!is_malf_or_traitor(src))
|
||||
if(zeroth_law_borg)
|
||||
laws.set_zeroth_law(zeroth_law_borg.law)
|
||||
else if(zeroth_law)
|
||||
laws.set_zeroth_law(zeroth_law.law)
|
||||
|
||||
/mob/living/silicon/ai/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg)
|
||||
if(zeroth_law)
|
||||
laws.set_zeroth_law(zeroth_law.law, zeroth_law_borg ? zeroth_law_borg.law : null)
|
||||
|
||||
/****************
|
||||
* Add Laws *
|
||||
****************/
|
||||
/datum/ai_laws/proc/set_zeroth_law(var/law, var/law_borg = null)
|
||||
if(!law)
|
||||
return
|
||||
|
||||
zeroth_law = new(law)
|
||||
if(law_borg) //Making it possible for slaved borgs to see a different law 0 than their AI. --NEO
|
||||
zeroth_law_borg = new(law_borg)
|
||||
else
|
||||
zeroth_law_borg = null
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/add_ion_law(var/law)
|
||||
if(!law)
|
||||
return
|
||||
|
||||
for(var/datum/ai_law/AL in ion_laws)
|
||||
if(AL.law == law)
|
||||
return
|
||||
|
||||
var/new_law = new/datum/ai_law/ion(law)
|
||||
ion_laws += new_law
|
||||
if(state_ion.len < ion_laws.len)
|
||||
state_ion += 1
|
||||
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/add_inherent_law(var/law)
|
||||
if(!law)
|
||||
return
|
||||
|
||||
for(var/datum/ai_law/AL in inherent_laws)
|
||||
if(AL.law == law)
|
||||
return
|
||||
|
||||
var/new_law = new/datum/ai_law/inherent(law)
|
||||
inherent_laws += new_law
|
||||
if(state_inherent.len < inherent_laws.len)
|
||||
state_inherent += 1
|
||||
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/add_supplied_law(var/number, var/law)
|
||||
if(!law)
|
||||
return
|
||||
|
||||
if(supplied_laws.len >= number)
|
||||
var/datum/ai_law/existing_law = supplied_laws[number]
|
||||
if(existing_law && existing_law.law == law)
|
||||
return
|
||||
|
||||
if(supplied_laws.len >= number && supplied_laws[number])
|
||||
delete_law(supplied_laws[number])
|
||||
|
||||
while (src.supplied_laws.len < number)
|
||||
src.supplied_laws += ""
|
||||
if(state_supplied.len < supplied_laws.len)
|
||||
state_supplied += 1
|
||||
|
||||
var/new_law = new/datum/ai_law/supplied(law, number)
|
||||
supplied_laws[number] = new_law
|
||||
if(state_supplied.len < supplied_laws.len)
|
||||
state_supplied += 1
|
||||
|
||||
sorted_laws.Cut()
|
||||
|
||||
/****************
|
||||
* Remove Laws *
|
||||
*****************/
|
||||
/datum/ai_laws/proc/delete_law(var/datum/ai_law/law)
|
||||
if(istype(law))
|
||||
law.delete_law(src)
|
||||
|
||||
/datum/ai_law/proc/delete_law(var/datum/ai_laws/laws)
|
||||
|
||||
/datum/ai_law/zero/delete_law(var/datum/ai_laws/laws)
|
||||
laws.clear_zeroth_laws()
|
||||
|
||||
/datum/ai_law/ion/delete_law(var/datum/ai_laws/laws)
|
||||
laws.internal_delete_law(laws.ion_laws, laws.state_ion, src)
|
||||
|
||||
/datum/ai_law/inherent/delete_law(var/datum/ai_laws/laws)
|
||||
laws.internal_delete_law(laws.inherent_laws, laws.state_inherent, src)
|
||||
|
||||
/datum/ai_law/supplied/delete_law(var/datum/ai_laws/laws)
|
||||
var/index = laws.supplied_laws.Find(src)
|
||||
if(index)
|
||||
laws.supplied_laws[index] = ""
|
||||
laws.state_supplied[index] = 1
|
||||
|
||||
/datum/ai_laws/proc/internal_delete_law(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law)
|
||||
var/index = laws.Find(law)
|
||||
if(index)
|
||||
laws -= law
|
||||
for(index, index < state.len, index++)
|
||||
state[index] = state[index+1]
|
||||
sorted_laws.Cut()
|
||||
|
||||
/****************
|
||||
* Clear Laws *
|
||||
****************/
|
||||
/datum/ai_laws/proc/clear_zeroth_laws()
|
||||
zeroth_law = null
|
||||
zeroth_law_borg = null
|
||||
|
||||
/datum/ai_laws/proc/clear_ion_laws()
|
||||
ion_laws.Cut()
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/clear_inherent_laws()
|
||||
inherent_laws.Cut()
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/clear_supplied_laws()
|
||||
supplied_laws.Cut()
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/show_laws(var/who)
|
||||
sort_laws()
|
||||
for(var/datum/ai_law/law in sorted_laws)
|
||||
if(law == zeroth_law_borg)
|
||||
continue
|
||||
if(law == zeroth_law)
|
||||
to_chat(who, "<span class='danger'>[law.get_index()]. [law.law]</span>")
|
||||
else
|
||||
to_chat(who, "[law.get_index()]. [law.law]")
|
||||
|
||||
/********************
|
||||
* Stating Laws *
|
||||
********************/
|
||||
/********
|
||||
* Get *
|
||||
********/
|
||||
/datum/ai_laws/proc/get_state_law(var/datum/ai_law/law)
|
||||
return law.get_state_law(src)
|
||||
|
||||
/datum/ai_law/proc/get_state_law(var/datum/ai_laws/laws)
|
||||
|
||||
/datum/ai_law/zero/get_state_law(var/datum/ai_laws/laws)
|
||||
if(src == laws.zeroth_law)
|
||||
return laws.state_zeroth
|
||||
|
||||
/datum/ai_law/ion/get_state_law(var/datum/ai_laws/laws)
|
||||
return laws.get_state_internal(laws.ion_laws, laws.state_ion, src)
|
||||
|
||||
/datum/ai_law/inherent/get_state_law(var/datum/ai_laws/laws)
|
||||
return laws.get_state_internal(laws.inherent_laws, laws.state_inherent, src)
|
||||
|
||||
/datum/ai_law/supplied/get_state_law(var/datum/ai_laws/laws)
|
||||
return laws.get_state_internal(laws.supplied_laws, laws.state_supplied, src)
|
||||
|
||||
/datum/ai_laws/proc/get_state_internal(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law)
|
||||
var/index = laws.Find(law)
|
||||
if(index)
|
||||
return state[index]
|
||||
return 0
|
||||
|
||||
/********
|
||||
* Set *
|
||||
********/
|
||||
/datum/ai_laws/proc/set_state_law(var/datum/ai_law/law, var/state)
|
||||
law.set_state_law(src, state)
|
||||
|
||||
/datum/ai_law/proc/set_state_law(var/datum/ai_law/law, var/state)
|
||||
|
||||
/datum/ai_law/zero/set_state_law(var/datum/ai_laws/laws, var/state)
|
||||
if(src == laws.zeroth_law)
|
||||
laws.state_zeroth = state
|
||||
|
||||
/datum/ai_law/ion/set_state_law(var/datum/ai_laws/laws, var/state)
|
||||
laws.set_state_law_internal(laws.ion_laws, laws.state_ion, src, state)
|
||||
|
||||
/datum/ai_law/inherent/set_state_law(var/datum/ai_laws/laws, var/state)
|
||||
laws.set_state_law_internal(laws.inherent_laws, laws.state_inherent, src, state)
|
||||
|
||||
/datum/ai_law/supplied/set_state_law(var/datum/ai_laws/laws, var/state)
|
||||
laws.set_state_law_internal(laws.supplied_laws, laws.state_supplied, src, state)
|
||||
|
||||
/datum/ai_laws/proc/set_state_law_internal(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law, var/do_state)
|
||||
var/index = laws.Find(law)
|
||||
if(index)
|
||||
state[index] = do_state
|
||||
var/global/const/base_law_type = /datum/ai_laws/nanotrasen
|
||||
|
||||
/datum/ai_law
|
||||
var/law = ""
|
||||
var/index = 0
|
||||
|
||||
/datum/ai_law/New(law, index)
|
||||
src.law = law
|
||||
src.index = index
|
||||
|
||||
/datum/ai_law/proc/get_index()
|
||||
return index
|
||||
|
||||
/datum/ai_law/ion/get_index()
|
||||
return ionnum()
|
||||
|
||||
/datum/ai_law/zero/get_index()
|
||||
return 0
|
||||
|
||||
/datum/ai_laws
|
||||
var/name = "Unknown Laws"
|
||||
var/law_header = "Prime Directives"
|
||||
var/selectable = 0
|
||||
var/datum/ai_law/zero/zeroth_law = null
|
||||
var/datum/ai_law/zero/zeroth_law_borg = null
|
||||
var/list/datum/ai_law/inherent_laws = list()
|
||||
var/list/datum/ai_law/supplied_laws = list()
|
||||
var/list/datum/ai_law/ion/ion_laws = list()
|
||||
var/list/datum/ai_law/sorted_laws = list()
|
||||
|
||||
var/state_zeroth = 0
|
||||
var/list/state_ion = list()
|
||||
var/list/state_inherent = list()
|
||||
var/list/state_supplied = list()
|
||||
|
||||
/datum/ai_laws/New()
|
||||
..()
|
||||
sort_laws()
|
||||
|
||||
/* General ai_law functions */
|
||||
/datum/ai_laws/proc/all_laws()
|
||||
sort_laws()
|
||||
return sorted_laws
|
||||
|
||||
/datum/ai_laws/proc/laws_to_state()
|
||||
sort_laws()
|
||||
var/list/statements = new()
|
||||
for(var/datum/ai_law/law in sorted_laws)
|
||||
if(get_state_law(law))
|
||||
statements += law
|
||||
|
||||
return statements
|
||||
|
||||
/datum/ai_laws/proc/sort_laws()
|
||||
if(sorted_laws.len)
|
||||
return
|
||||
|
||||
for(var/ion_law in ion_laws)
|
||||
sorted_laws += ion_law
|
||||
|
||||
if(zeroth_law)
|
||||
sorted_laws += zeroth_law
|
||||
|
||||
var/index = 1
|
||||
for(var/datum/ai_law/inherent_law in inherent_laws)
|
||||
inherent_law.index = index++
|
||||
if(supplied_laws.len < inherent_law.index || !istype(supplied_laws[inherent_law.index], /datum/ai_law))
|
||||
sorted_laws += inherent_law
|
||||
|
||||
for(var/datum/ai_law/AL in supplied_laws)
|
||||
if(istype(AL))
|
||||
sorted_laws += AL
|
||||
|
||||
/datum/ai_laws/proc/sync(var/mob/living/silicon/S, var/full_sync = 1)
|
||||
// Add directly to laws to avoid log-spam
|
||||
S.sync_zeroth(zeroth_law, zeroth_law_borg)
|
||||
|
||||
if(full_sync || ion_laws.len)
|
||||
S.laws.clear_ion_laws()
|
||||
if(full_sync || inherent_laws.len)
|
||||
S.laws.clear_inherent_laws()
|
||||
if(full_sync || supplied_laws.len)
|
||||
S.laws.clear_supplied_laws()
|
||||
|
||||
for (var/datum/ai_law/law in ion_laws)
|
||||
S.laws.add_ion_law(law.law)
|
||||
for (var/datum/ai_law/law in inherent_laws)
|
||||
S.laws.add_inherent_law(law.law)
|
||||
for (var/datum/ai_law/law in supplied_laws)
|
||||
if(law)
|
||||
S.laws.add_supplied_law(law.index, law.law)
|
||||
|
||||
|
||||
/mob/living/silicon/proc/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg)
|
||||
if (!is_malf_or_traitor(src))
|
||||
if(zeroth_law_borg)
|
||||
laws.set_zeroth_law(zeroth_law_borg.law)
|
||||
else if(zeroth_law)
|
||||
laws.set_zeroth_law(zeroth_law.law)
|
||||
|
||||
/mob/living/silicon/ai/sync_zeroth(var/datum/ai_law/zeroth_law, var/datum/ai_law/zeroth_law_borg)
|
||||
if(zeroth_law)
|
||||
laws.set_zeroth_law(zeroth_law.law, zeroth_law_borg ? zeroth_law_borg.law : null)
|
||||
|
||||
/****************
|
||||
* Add Laws *
|
||||
****************/
|
||||
/datum/ai_laws/proc/set_zeroth_law(var/law, var/law_borg = null)
|
||||
if(!law)
|
||||
return
|
||||
|
||||
zeroth_law = new(law)
|
||||
if(law_borg) //Making it possible for slaved borgs to see a different law 0 than their AI. --NEO
|
||||
zeroth_law_borg = new(law_borg)
|
||||
else
|
||||
zeroth_law_borg = null
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/add_ion_law(var/law)
|
||||
if(!law)
|
||||
return
|
||||
|
||||
for(var/datum/ai_law/AL in ion_laws)
|
||||
if(AL.law == law)
|
||||
return
|
||||
|
||||
var/new_law = new/datum/ai_law/ion(law)
|
||||
ion_laws += new_law
|
||||
if(state_ion.len < ion_laws.len)
|
||||
state_ion += 1
|
||||
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/add_inherent_law(var/law)
|
||||
if(!law)
|
||||
return
|
||||
|
||||
for(var/datum/ai_law/AL in inherent_laws)
|
||||
if(AL.law == law)
|
||||
return
|
||||
|
||||
var/new_law = new/datum/ai_law/inherent(law)
|
||||
inherent_laws += new_law
|
||||
if(state_inherent.len < inherent_laws.len)
|
||||
state_inherent += 1
|
||||
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/add_supplied_law(var/number, var/law)
|
||||
if(!law)
|
||||
return
|
||||
|
||||
if(supplied_laws.len >= number)
|
||||
var/datum/ai_law/existing_law = supplied_laws[number]
|
||||
if(existing_law && existing_law.law == law)
|
||||
return
|
||||
|
||||
if(supplied_laws.len >= number && supplied_laws[number])
|
||||
delete_law(supplied_laws[number])
|
||||
|
||||
while (src.supplied_laws.len < number)
|
||||
src.supplied_laws += ""
|
||||
if(state_supplied.len < supplied_laws.len)
|
||||
state_supplied += 1
|
||||
|
||||
var/new_law = new/datum/ai_law/supplied(law, number)
|
||||
supplied_laws[number] = new_law
|
||||
if(state_supplied.len < supplied_laws.len)
|
||||
state_supplied += 1
|
||||
|
||||
sorted_laws.Cut()
|
||||
|
||||
/****************
|
||||
* Remove Laws *
|
||||
*****************/
|
||||
/datum/ai_laws/proc/delete_law(var/datum/ai_law/law)
|
||||
if(istype(law))
|
||||
law.delete_law(src)
|
||||
|
||||
/datum/ai_law/proc/delete_law(var/datum/ai_laws/laws)
|
||||
|
||||
/datum/ai_law/zero/delete_law(var/datum/ai_laws/laws)
|
||||
laws.clear_zeroth_laws()
|
||||
|
||||
/datum/ai_law/ion/delete_law(var/datum/ai_laws/laws)
|
||||
laws.internal_delete_law(laws.ion_laws, laws.state_ion, src)
|
||||
|
||||
/datum/ai_law/inherent/delete_law(var/datum/ai_laws/laws)
|
||||
laws.internal_delete_law(laws.inherent_laws, laws.state_inherent, src)
|
||||
|
||||
/datum/ai_law/supplied/delete_law(var/datum/ai_laws/laws)
|
||||
var/index = laws.supplied_laws.Find(src)
|
||||
if(index)
|
||||
laws.supplied_laws[index] = ""
|
||||
laws.state_supplied[index] = 1
|
||||
|
||||
/datum/ai_laws/proc/internal_delete_law(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law)
|
||||
var/index = laws.Find(law)
|
||||
if(index)
|
||||
laws -= law
|
||||
for(index, index < state.len, index++)
|
||||
state[index] = state[index+1]
|
||||
sorted_laws.Cut()
|
||||
|
||||
/****************
|
||||
* Clear Laws *
|
||||
****************/
|
||||
/datum/ai_laws/proc/clear_zeroth_laws()
|
||||
zeroth_law = null
|
||||
zeroth_law_borg = null
|
||||
|
||||
/datum/ai_laws/proc/clear_ion_laws()
|
||||
ion_laws.Cut()
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/clear_inherent_laws()
|
||||
inherent_laws.Cut()
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/clear_supplied_laws()
|
||||
supplied_laws.Cut()
|
||||
sorted_laws.Cut()
|
||||
|
||||
/datum/ai_laws/proc/show_laws(var/who)
|
||||
sort_laws()
|
||||
for(var/datum/ai_law/law in sorted_laws)
|
||||
if(law == zeroth_law_borg)
|
||||
continue
|
||||
if(law == zeroth_law)
|
||||
to_chat(who, "<span class='danger'>[law.get_index()]. [law.law]</span>")
|
||||
else
|
||||
to_chat(who, "[law.get_index()]. [law.law]")
|
||||
|
||||
/********************
|
||||
* Stating Laws *
|
||||
********************/
|
||||
/********
|
||||
* Get *
|
||||
********/
|
||||
/datum/ai_laws/proc/get_state_law(var/datum/ai_law/law)
|
||||
return law.get_state_law(src)
|
||||
|
||||
/datum/ai_law/proc/get_state_law(var/datum/ai_laws/laws)
|
||||
|
||||
/datum/ai_law/zero/get_state_law(var/datum/ai_laws/laws)
|
||||
if(src == laws.zeroth_law)
|
||||
return laws.state_zeroth
|
||||
|
||||
/datum/ai_law/ion/get_state_law(var/datum/ai_laws/laws)
|
||||
return laws.get_state_internal(laws.ion_laws, laws.state_ion, src)
|
||||
|
||||
/datum/ai_law/inherent/get_state_law(var/datum/ai_laws/laws)
|
||||
return laws.get_state_internal(laws.inherent_laws, laws.state_inherent, src)
|
||||
|
||||
/datum/ai_law/supplied/get_state_law(var/datum/ai_laws/laws)
|
||||
return laws.get_state_internal(laws.supplied_laws, laws.state_supplied, src)
|
||||
|
||||
/datum/ai_laws/proc/get_state_internal(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law)
|
||||
var/index = laws.Find(law)
|
||||
if(index)
|
||||
return state[index]
|
||||
return 0
|
||||
|
||||
/********
|
||||
* Set *
|
||||
********/
|
||||
/datum/ai_laws/proc/set_state_law(var/datum/ai_law/law, var/state)
|
||||
law.set_state_law(src, state)
|
||||
|
||||
/datum/ai_law/proc/set_state_law(var/datum/ai_law/law, var/state)
|
||||
|
||||
/datum/ai_law/zero/set_state_law(var/datum/ai_laws/laws, var/state)
|
||||
if(src == laws.zeroth_law)
|
||||
laws.state_zeroth = state
|
||||
|
||||
/datum/ai_law/ion/set_state_law(var/datum/ai_laws/laws, var/state)
|
||||
laws.set_state_law_internal(laws.ion_laws, laws.state_ion, src, state)
|
||||
|
||||
/datum/ai_law/inherent/set_state_law(var/datum/ai_laws/laws, var/state)
|
||||
laws.set_state_law_internal(laws.inherent_laws, laws.state_inherent, src, state)
|
||||
|
||||
/datum/ai_law/supplied/set_state_law(var/datum/ai_laws/laws, var/state)
|
||||
laws.set_state_law_internal(laws.supplied_laws, laws.state_supplied, src, state)
|
||||
|
||||
/datum/ai_laws/proc/set_state_law_internal(var/list/datum/ai_law/laws, var/list/state, var/list/datum/ai_law/law, var/do_state)
|
||||
var/index = laws.Find(law)
|
||||
if(index)
|
||||
state[index] = do_state
|
||||
|
||||
+550
-550
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
// Push button, receive event.
|
||||
// Returns a selected event datum.
|
||||
/datum/game_master/proc/choose_event()
|
||||
|
||||
/datum/game_master/proc/log_game_master(message)
|
||||
// Push button, receive event.
|
||||
// Returns a selected event datum.
|
||||
/datum/game_master/proc/choose_event()
|
||||
|
||||
/datum/game_master/proc/log_game_master(message)
|
||||
// SSgame_master.log_game_master(message) // VOREStation Edit - We don't use SSgame_master yet.
|
||||
@@ -1,87 +1,87 @@
|
||||
// The default game master tries to choose events with these goals in mind.
|
||||
// * Don't choose an event if the crew can't take it. E.g. no meteors after half of the crew died.
|
||||
// * Try to involve lots of people, particuarly in active departments.
|
||||
// * Avoid giving events to the same department multiple times in a row.
|
||||
/datum/game_master/default
|
||||
// If an event was done for a specific department, it is written here, so it doesn't do it again.
|
||||
var/last_department_used = null
|
||||
|
||||
|
||||
/datum/game_master/default/choose_event()
|
||||
log_game_master("Now starting event decision.")
|
||||
|
||||
var/list/most_active_departments = metric.assess_all_departments(3, list(last_department_used))
|
||||
var/list/best_events = decide_best_events(most_active_departments)
|
||||
|
||||
if(LAZYLEN(best_events))
|
||||
log_game_master("Got [best_events.len] choice\s for the next event.")
|
||||
var/list/weighted_events = list()
|
||||
|
||||
for(var/datum/event2/meta/event as anything in best_events)
|
||||
var/weight = event.get_weight()
|
||||
if(weight <= 0)
|
||||
continue
|
||||
weighted_events[event] = weight
|
||||
log_game_master("Filtered down to [weighted_events.len] choice\s.")
|
||||
|
||||
var/datum/event2/meta/choice = pickweight(weighted_events)
|
||||
|
||||
if(choice)
|
||||
log_game_master("[choice.name] was chosen, and is now being ran.")
|
||||
last_department_used = LAZYACCESS(choice.departments, 1)
|
||||
return choice
|
||||
|
||||
/datum/game_master/default/proc/decide_best_events(list/most_active_departments)
|
||||
if(!LAZYLEN(most_active_departments)) // Server's empty?
|
||||
log_game_master("Game Master failed to find any active departments.")
|
||||
return list()
|
||||
|
||||
var/list/best_events = list()
|
||||
if(most_active_departments.len >= 2)
|
||||
var/list/top_two = list(most_active_departments[1], most_active_departments[2])
|
||||
best_events = filter_events_by_departments(top_two)
|
||||
|
||||
if(LAZYLEN(best_events)) // We found something for those two, let's do it.
|
||||
return best_events
|
||||
|
||||
// Otherwise we probably couldn't find something for the second highest group, so let's ignore them.
|
||||
best_events = filter_events_by_departments(most_active_departments[1])
|
||||
|
||||
if(LAZYLEN(best_events))
|
||||
return best_events
|
||||
|
||||
// At this point we should expand our horizons.
|
||||
best_events = filter_events_by_departments(list(DEPARTMENT_EVERYONE))
|
||||
|
||||
if(LAZYLEN(best_events))
|
||||
return best_events
|
||||
|
||||
// Just give a random event if for some reason it still can't make up its mind.
|
||||
best_events = filter_events_by_departments()
|
||||
|
||||
if(LAZYLEN(best_events))
|
||||
return best_events
|
||||
|
||||
log_game_master("Game Master failed to find a suitable event, something very wrong is going on.")
|
||||
return list()
|
||||
|
||||
// Filters the available events down to events for specific departments.
|
||||
// Pass DEPARTMENT_EVERYONE if you want events that target the general population, like gravity failure.
|
||||
// If no list is passed, all the events will be returned.
|
||||
/datum/game_master/default/proc/filter_events_by_departments(list/departments)
|
||||
. = list()
|
||||
for(var/datum/event2/meta/event as anything in SSgame_master.available_events)
|
||||
if(!event.enabled)
|
||||
continue
|
||||
if(event.chaotic_threshold && !ignore_round_chaos)
|
||||
if(SSgame_master.danger > event.chaotic_threshold)
|
||||
continue
|
||||
// An event has to involve all of these departments to pass.
|
||||
var/viable = TRUE
|
||||
if(LAZYLEN(departments))
|
||||
for(var/department in departments)
|
||||
if(!LAZYFIND(departments, department))
|
||||
viable = FALSE
|
||||
break
|
||||
if(viable)
|
||||
. += event
|
||||
// The default game master tries to choose events with these goals in mind.
|
||||
// * Don't choose an event if the crew can't take it. E.g. no meteors after half of the crew died.
|
||||
// * Try to involve lots of people, particuarly in active departments.
|
||||
// * Avoid giving events to the same department multiple times in a row.
|
||||
/datum/game_master/default
|
||||
// If an event was done for a specific department, it is written here, so it doesn't do it again.
|
||||
var/last_department_used = null
|
||||
|
||||
|
||||
/datum/game_master/default/choose_event()
|
||||
log_game_master("Now starting event decision.")
|
||||
|
||||
var/list/most_active_departments = metric.assess_all_departments(3, list(last_department_used))
|
||||
var/list/best_events = decide_best_events(most_active_departments)
|
||||
|
||||
if(LAZYLEN(best_events))
|
||||
log_game_master("Got [best_events.len] choice\s for the next event.")
|
||||
var/list/weighted_events = list()
|
||||
|
||||
for(var/datum/event2/meta/event as anything in best_events)
|
||||
var/weight = event.get_weight()
|
||||
if(weight <= 0)
|
||||
continue
|
||||
weighted_events[event] = weight
|
||||
log_game_master("Filtered down to [weighted_events.len] choice\s.")
|
||||
|
||||
var/datum/event2/meta/choice = pickweight(weighted_events)
|
||||
|
||||
if(choice)
|
||||
log_game_master("[choice.name] was chosen, and is now being ran.")
|
||||
last_department_used = LAZYACCESS(choice.departments, 1)
|
||||
return choice
|
||||
|
||||
/datum/game_master/default/proc/decide_best_events(list/most_active_departments)
|
||||
if(!LAZYLEN(most_active_departments)) // Server's empty?
|
||||
log_game_master("Game Master failed to find any active departments.")
|
||||
return list()
|
||||
|
||||
var/list/best_events = list()
|
||||
if(most_active_departments.len >= 2)
|
||||
var/list/top_two = list(most_active_departments[1], most_active_departments[2])
|
||||
best_events = filter_events_by_departments(top_two)
|
||||
|
||||
if(LAZYLEN(best_events)) // We found something for those two, let's do it.
|
||||
return best_events
|
||||
|
||||
// Otherwise we probably couldn't find something for the second highest group, so let's ignore them.
|
||||
best_events = filter_events_by_departments(most_active_departments[1])
|
||||
|
||||
if(LAZYLEN(best_events))
|
||||
return best_events
|
||||
|
||||
// At this point we should expand our horizons.
|
||||
best_events = filter_events_by_departments(list(DEPARTMENT_EVERYONE))
|
||||
|
||||
if(LAZYLEN(best_events))
|
||||
return best_events
|
||||
|
||||
// Just give a random event if for some reason it still can't make up its mind.
|
||||
best_events = filter_events_by_departments()
|
||||
|
||||
if(LAZYLEN(best_events))
|
||||
return best_events
|
||||
|
||||
log_game_master("Game Master failed to find a suitable event, something very wrong is going on.")
|
||||
return list()
|
||||
|
||||
// Filters the available events down to events for specific departments.
|
||||
// Pass DEPARTMENT_EVERYONE if you want events that target the general population, like gravity failure.
|
||||
// If no list is passed, all the events will be returned.
|
||||
/datum/game_master/default/proc/filter_events_by_departments(list/departments)
|
||||
. = list()
|
||||
for(var/datum/event2/meta/event as anything in SSgame_master.available_events)
|
||||
if(!event.enabled)
|
||||
continue
|
||||
if(event.chaotic_threshold && !ignore_round_chaos)
|
||||
if(SSgame_master.danger > event.chaotic_threshold)
|
||||
continue
|
||||
// An event has to involve all of these departments to pass.
|
||||
var/viable = TRUE
|
||||
if(LAZYLEN(departments))
|
||||
for(var/department in departments)
|
||||
if(!LAZYFIND(departments, department))
|
||||
viable = FALSE
|
||||
break
|
||||
if(viable)
|
||||
. += event
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
// The `classic` game master tries to act like the old system, choosing events without any specific goals.
|
||||
// * Has no goals, and instead operates purely off of the weights of the events it has.
|
||||
// * Does not react to danger at all.
|
||||
/datum/game_master/classic/choose_event()
|
||||
var/list/weighted_events = list()
|
||||
for(var/datum/event2/meta/event as anything in SSgame_master.available_events)
|
||||
if(!event.enabled)
|
||||
continue
|
||||
weighted_events[event] = event.get_weight()
|
||||
|
||||
var/datum/event2/meta/choice = pickweight(weighted_events)
|
||||
|
||||
if(choice)
|
||||
log_game_master("[choice.name] was chosen, and is now being ran.")
|
||||
return choice
|
||||
|
||||
|
||||
// The `super_random` game master chooses events purely at random, ignoring weights entirely.
|
||||
// * Has no goals, and instead chooses randomly, ignoring weights.
|
||||
// * Does not react to danger at all.
|
||||
/datum/game_master/super_random/choose_event()
|
||||
return pick(SSgame_master.available_events)
|
||||
|
||||
|
||||
// The `brutal` game master tries to run dangerous events frequently.
|
||||
// * Chaotic events have their weights artifically boosted.
|
||||
// * Ignores accumulated danger.
|
||||
/datum/game_master/brutal
|
||||
ignore_round_chaos = TRUE
|
||||
|
||||
/datum/game_master/brutal/choose_event()
|
||||
var/list/weighted_events = list()
|
||||
for(var/datum/event2/meta/event as anything in SSgame_master.available_events)
|
||||
if(!event.enabled)
|
||||
continue
|
||||
weighted_events[event] = event.get_weight() + (event.chaos * 2)
|
||||
|
||||
var/datum/event2/meta/choice = pickweight(weighted_events)
|
||||
|
||||
if(choice)
|
||||
log_game_master("[choice.name] was chosen, and is now being ran.")
|
||||
return choice
|
||||
// The `classic` game master tries to act like the old system, choosing events without any specific goals.
|
||||
// * Has no goals, and instead operates purely off of the weights of the events it has.
|
||||
// * Does not react to danger at all.
|
||||
/datum/game_master/classic/choose_event()
|
||||
var/list/weighted_events = list()
|
||||
for(var/datum/event2/meta/event as anything in SSgame_master.available_events)
|
||||
if(!event.enabled)
|
||||
continue
|
||||
weighted_events[event] = event.get_weight()
|
||||
|
||||
var/datum/event2/meta/choice = pickweight(weighted_events)
|
||||
|
||||
if(choice)
|
||||
log_game_master("[choice.name] was chosen, and is now being ran.")
|
||||
return choice
|
||||
|
||||
|
||||
// The `super_random` game master chooses events purely at random, ignoring weights entirely.
|
||||
// * Has no goals, and instead chooses randomly, ignoring weights.
|
||||
// * Does not react to danger at all.
|
||||
/datum/game_master/super_random/choose_event()
|
||||
return pick(SSgame_master.available_events)
|
||||
|
||||
|
||||
// The `brutal` game master tries to run dangerous events frequently.
|
||||
// * Chaotic events have their weights artifically boosted.
|
||||
// * Ignores accumulated danger.
|
||||
/datum/game_master/brutal
|
||||
ignore_round_chaos = TRUE
|
||||
|
||||
/datum/game_master/brutal/choose_event()
|
||||
var/list/weighted_events = list()
|
||||
for(var/datum/event2/meta/event as anything in SSgame_master.available_events)
|
||||
if(!event.enabled)
|
||||
continue
|
||||
weighted_events[event] = event.get_weight() + (event.chaos * 2)
|
||||
|
||||
var/datum/event2/meta/choice = pickweight(weighted_events)
|
||||
|
||||
if(choice)
|
||||
log_game_master("[choice.name] was chosen, and is now being ran.")
|
||||
return choice
|
||||
|
||||
@@ -1,161 +1,161 @@
|
||||
#define FORWARD -1
|
||||
#define BACKWARD 1
|
||||
|
||||
|
||||
// As of August 4th, 2018, these datums are only used in Mech construction.
|
||||
/datum/construction
|
||||
var/list/steps
|
||||
var/atom/holder
|
||||
var/result
|
||||
var/list/steps_desc
|
||||
|
||||
/datum/construction/New(atom)
|
||||
..()
|
||||
holder = atom
|
||||
if(!holder) //don't want this without a holder
|
||||
spawn
|
||||
qdel(src)
|
||||
set_desc(steps.len)
|
||||
return
|
||||
|
||||
/datum/construction/proc/next_step()
|
||||
steps.len--
|
||||
if(!steps.len)
|
||||
spawn_result()
|
||||
else
|
||||
set_desc(steps.len)
|
||||
return
|
||||
|
||||
/datum/construction/proc/action(var/obj/item/I,mob/user as mob)
|
||||
return
|
||||
|
||||
/datum/construction/proc/check_step(var/obj/item/I,mob/user as mob) //check last step only
|
||||
var/valid_step = is_right_key(I)
|
||||
if(valid_step)
|
||||
if(custom_action(valid_step, I, user))
|
||||
next_step()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/construction/proc/is_right_key(var/obj/item/I) // returns current step num if I is of the right type.
|
||||
var/list/L = steps[steps.len]
|
||||
switch(L["key"])
|
||||
if(IS_SCREWDRIVER)
|
||||
if(I.has_tool_quality(TOOL_SCREWDRIVER))
|
||||
return steps.len
|
||||
if(IS_CROWBAR)
|
||||
if(I.has_tool_quality(TOOL_CROWBAR))
|
||||
return steps.len
|
||||
if(IS_WIRECUTTER)
|
||||
if(I.has_tool_quality(TOOL_WIRECUTTER))
|
||||
return steps.len
|
||||
if(IS_WRENCH)
|
||||
if(I.has_tool_quality(TOOL_WRENCH))
|
||||
return steps.len
|
||||
if(IS_WELDER)
|
||||
if(I.has_tool_quality(IS_WELDER))
|
||||
return steps.len
|
||||
|
||||
if(istype(I, L["key"]))
|
||||
return steps.len
|
||||
return 0
|
||||
|
||||
/datum/construction/proc/custom_action(step, I, user)
|
||||
return 1
|
||||
|
||||
/datum/construction/proc/check_all_steps(var/obj/item/I,mob/user as mob) //check all steps, remove matching one.
|
||||
for(var/i=1;i<=steps.len;i++)
|
||||
var/list/L = steps[i];
|
||||
if(istype(I, L["key"]))
|
||||
if(custom_action(i, I, user))
|
||||
steps[i]=null;//stupid byond list from list removal...
|
||||
listclearnulls(steps);
|
||||
if(!steps.len)
|
||||
spawn_result()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/datum/construction/proc/spawn_result()
|
||||
if(result)
|
||||
new result(get_turf(holder))
|
||||
spawn()
|
||||
qdel(holder)
|
||||
return
|
||||
|
||||
/datum/construction/proc/set_desc(index as num)
|
||||
var/list/step = steps[index]
|
||||
holder.desc = step["desc"]
|
||||
return
|
||||
|
||||
|
||||
// Reversible
|
||||
/datum/construction/reversible
|
||||
var/index
|
||||
|
||||
/datum/construction/reversible/New(atom)
|
||||
..()
|
||||
index = steps.len
|
||||
return
|
||||
|
||||
/datum/construction/reversible/proc/update_index(diff as num)
|
||||
index+=diff
|
||||
if(index==0)
|
||||
spawn_result()
|
||||
else
|
||||
set_desc(index)
|
||||
return
|
||||
|
||||
/datum/construction/reversible/is_right_key(var/obj/item/I) // returns index step
|
||||
var/list/L = steps[index]
|
||||
|
||||
switch(L["key"])
|
||||
if(IS_SCREWDRIVER)
|
||||
if(I.has_tool_quality(TOOL_SCREWDRIVER))
|
||||
return FORWARD
|
||||
if(IS_CROWBAR)
|
||||
if(I.has_tool_quality(TOOL_CROWBAR))
|
||||
return FORWARD
|
||||
if(IS_WIRECUTTER)
|
||||
if(I.has_tool_quality(TOOL_WIRECUTTER))
|
||||
return FORWARD
|
||||
if(IS_WRENCH)
|
||||
if(I.has_tool_quality(TOOL_WRENCH))
|
||||
return FORWARD
|
||||
if(IS_WELDER)
|
||||
if(I.has_tool_quality(IS_WELDER))
|
||||
return FORWARD
|
||||
|
||||
switch(L["backkey"])
|
||||
if(IS_SCREWDRIVER)
|
||||
if(I.has_tool_quality(TOOL_SCREWDRIVER))
|
||||
return BACKWARD
|
||||
if(IS_CROWBAR)
|
||||
if(I.has_tool_quality(TOOL_CROWBAR))
|
||||
return BACKWARD
|
||||
if(IS_WIRECUTTER)
|
||||
if(I.has_tool_quality(TOOL_WIRECUTTER))
|
||||
return BACKWARD
|
||||
if(IS_WRENCH)
|
||||
if(I.has_tool_quality(TOOL_WRENCH))
|
||||
return BACKWARD
|
||||
if(IS_WELDER)
|
||||
if(I.has_tool_quality(IS_WELDER))
|
||||
return BACKWARD
|
||||
|
||||
if(istype(I, L["key"]))
|
||||
return FORWARD //to the first step -> forward
|
||||
else if(L["backkey"] && istype(I, L["backkey"]))
|
||||
return BACKWARD //to the last step -> backwards
|
||||
return 0
|
||||
|
||||
/datum/construction/reversible/check_step(var/obj/item/I,mob/user as mob)
|
||||
var/diff = is_right_key(I)
|
||||
if(diff)
|
||||
if(custom_action(index, diff, I, user))
|
||||
update_index(diff)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/construction/reversible/custom_action(index, diff, I, user)
|
||||
#define FORWARD -1
|
||||
#define BACKWARD 1
|
||||
|
||||
|
||||
// As of August 4th, 2018, these datums are only used in Mech construction.
|
||||
/datum/construction
|
||||
var/list/steps
|
||||
var/atom/holder
|
||||
var/result
|
||||
var/list/steps_desc
|
||||
|
||||
/datum/construction/New(atom)
|
||||
..()
|
||||
holder = atom
|
||||
if(!holder) //don't want this without a holder
|
||||
spawn
|
||||
qdel(src)
|
||||
set_desc(steps.len)
|
||||
return
|
||||
|
||||
/datum/construction/proc/next_step()
|
||||
steps.len--
|
||||
if(!steps.len)
|
||||
spawn_result()
|
||||
else
|
||||
set_desc(steps.len)
|
||||
return
|
||||
|
||||
/datum/construction/proc/action(var/obj/item/I,mob/user as mob)
|
||||
return
|
||||
|
||||
/datum/construction/proc/check_step(var/obj/item/I,mob/user as mob) //check last step only
|
||||
var/valid_step = is_right_key(I)
|
||||
if(valid_step)
|
||||
if(custom_action(valid_step, I, user))
|
||||
next_step()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/construction/proc/is_right_key(var/obj/item/I) // returns current step num if I is of the right type.
|
||||
var/list/L = steps[steps.len]
|
||||
switch(L["key"])
|
||||
if(IS_SCREWDRIVER)
|
||||
if(I.has_tool_quality(TOOL_SCREWDRIVER))
|
||||
return steps.len
|
||||
if(IS_CROWBAR)
|
||||
if(I.has_tool_quality(TOOL_CROWBAR))
|
||||
return steps.len
|
||||
if(IS_WIRECUTTER)
|
||||
if(I.has_tool_quality(TOOL_WIRECUTTER))
|
||||
return steps.len
|
||||
if(IS_WRENCH)
|
||||
if(I.has_tool_quality(TOOL_WRENCH))
|
||||
return steps.len
|
||||
if(IS_WELDER)
|
||||
if(I.has_tool_quality(IS_WELDER))
|
||||
return steps.len
|
||||
|
||||
if(istype(I, L["key"]))
|
||||
return steps.len
|
||||
return 0
|
||||
|
||||
/datum/construction/proc/custom_action(step, I, user)
|
||||
return 1
|
||||
|
||||
/datum/construction/proc/check_all_steps(var/obj/item/I,mob/user as mob) //check all steps, remove matching one.
|
||||
for(var/i=1;i<=steps.len;i++)
|
||||
var/list/L = steps[i];
|
||||
if(istype(I, L["key"]))
|
||||
if(custom_action(i, I, user))
|
||||
steps[i]=null;//stupid byond list from list removal...
|
||||
listclearnulls(steps);
|
||||
if(!steps.len)
|
||||
spawn_result()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/datum/construction/proc/spawn_result()
|
||||
if(result)
|
||||
new result(get_turf(holder))
|
||||
spawn()
|
||||
qdel(holder)
|
||||
return
|
||||
|
||||
/datum/construction/proc/set_desc(index as num)
|
||||
var/list/step = steps[index]
|
||||
holder.desc = step["desc"]
|
||||
return
|
||||
|
||||
|
||||
// Reversible
|
||||
/datum/construction/reversible
|
||||
var/index
|
||||
|
||||
/datum/construction/reversible/New(atom)
|
||||
..()
|
||||
index = steps.len
|
||||
return
|
||||
|
||||
/datum/construction/reversible/proc/update_index(diff as num)
|
||||
index+=diff
|
||||
if(index==0)
|
||||
spawn_result()
|
||||
else
|
||||
set_desc(index)
|
||||
return
|
||||
|
||||
/datum/construction/reversible/is_right_key(var/obj/item/I) // returns index step
|
||||
var/list/L = steps[index]
|
||||
|
||||
switch(L["key"])
|
||||
if(IS_SCREWDRIVER)
|
||||
if(I.has_tool_quality(TOOL_SCREWDRIVER))
|
||||
return FORWARD
|
||||
if(IS_CROWBAR)
|
||||
if(I.has_tool_quality(TOOL_CROWBAR))
|
||||
return FORWARD
|
||||
if(IS_WIRECUTTER)
|
||||
if(I.has_tool_quality(TOOL_WIRECUTTER))
|
||||
return FORWARD
|
||||
if(IS_WRENCH)
|
||||
if(I.has_tool_quality(TOOL_WRENCH))
|
||||
return FORWARD
|
||||
if(IS_WELDER)
|
||||
if(I.has_tool_quality(IS_WELDER))
|
||||
return FORWARD
|
||||
|
||||
switch(L["backkey"])
|
||||
if(IS_SCREWDRIVER)
|
||||
if(I.has_tool_quality(TOOL_SCREWDRIVER))
|
||||
return BACKWARD
|
||||
if(IS_CROWBAR)
|
||||
if(I.has_tool_quality(TOOL_CROWBAR))
|
||||
return BACKWARD
|
||||
if(IS_WIRECUTTER)
|
||||
if(I.has_tool_quality(TOOL_WIRECUTTER))
|
||||
return BACKWARD
|
||||
if(IS_WRENCH)
|
||||
if(I.has_tool_quality(TOOL_WRENCH))
|
||||
return BACKWARD
|
||||
if(IS_WELDER)
|
||||
if(I.has_tool_quality(IS_WELDER))
|
||||
return BACKWARD
|
||||
|
||||
if(istype(I, L["key"]))
|
||||
return FORWARD //to the first step -> forward
|
||||
else if(L["backkey"] && istype(I, L["backkey"]))
|
||||
return BACKWARD //to the last step -> backwards
|
||||
return 0
|
||||
|
||||
/datum/construction/reversible/check_step(var/obj/item/I,mob/user as mob)
|
||||
var/diff = is_right_key(I)
|
||||
if(diff)
|
||||
if(custom_action(index, diff, I, user))
|
||||
update_index(diff)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/construction/reversible/custom_action(index, diff, I, user)
|
||||
return 1
|
||||
@@ -1,67 +1,67 @@
|
||||
/*
|
||||
* WARRANTY VOID IF CODE USED
|
||||
*/
|
||||
|
||||
|
||||
/datum/events
|
||||
var/list/events
|
||||
|
||||
/datum/events/New()
|
||||
..()
|
||||
events = new
|
||||
|
||||
/datum/events/proc/addEventType(event_type as text)
|
||||
if(!(event_type in events) || !islist(events[event_type]))
|
||||
events[event_type] = list()
|
||||
return 1
|
||||
return
|
||||
|
||||
|
||||
// Arguments: event_type as text, proc_holder as datum, proc_name as text
|
||||
// Returns: New event, null on error.
|
||||
/datum/events/proc/addEvent(event_type as text, proc_holder, proc_name as text)
|
||||
if(!event_type || !proc_holder || !proc_name)
|
||||
return
|
||||
addEventType(event_type)
|
||||
var/list/event = events[event_type]
|
||||
var/datum/event/E = new /datum/event(proc_holder,proc_name)
|
||||
event += E
|
||||
return E
|
||||
|
||||
// Arguments: event_type as text, any number of additional arguments to pass to event handler
|
||||
// Returns: null
|
||||
/datum/events/proc/fireEvent()
|
||||
//to_world("Events in [args[1]] called")
|
||||
var/list/event = listgetindex(events,args[1])
|
||||
if(istype(event))
|
||||
spawn(-1)
|
||||
for(var/datum/event/E in event)
|
||||
if(!E.Fire(arglist(args.Copy(2))))
|
||||
clearEvent(args[1],E)
|
||||
return
|
||||
|
||||
// Arguments: event_type as text, E as /datum/event
|
||||
// Returns: 1 if event cleared, null on error
|
||||
/datum/events/proc/clearEvent(event_type as text, datum/event/E)
|
||||
if(!event_type || !E)
|
||||
return
|
||||
var/list/event = listgetindex(events,event_type)
|
||||
event -= E
|
||||
return 1
|
||||
|
||||
|
||||
/datum/event
|
||||
var/listener
|
||||
var/proc_name
|
||||
|
||||
/datum/event/New(tlistener,tprocname)
|
||||
listener = tlistener
|
||||
proc_name = tprocname
|
||||
return ..()
|
||||
|
||||
/datum/event/proc/Fire()
|
||||
//to_world("Event fired")
|
||||
if(listener)
|
||||
call(listener,proc_name)(arglist(args))
|
||||
return 1
|
||||
/*
|
||||
* WARRANTY VOID IF CODE USED
|
||||
*/
|
||||
|
||||
|
||||
/datum/events
|
||||
var/list/events
|
||||
|
||||
/datum/events/New()
|
||||
..()
|
||||
events = new
|
||||
|
||||
/datum/events/proc/addEventType(event_type as text)
|
||||
if(!(event_type in events) || !islist(events[event_type]))
|
||||
events[event_type] = list()
|
||||
return 1
|
||||
return
|
||||
|
||||
|
||||
// Arguments: event_type as text, proc_holder as datum, proc_name as text
|
||||
// Returns: New event, null on error.
|
||||
/datum/events/proc/addEvent(event_type as text, proc_holder, proc_name as text)
|
||||
if(!event_type || !proc_holder || !proc_name)
|
||||
return
|
||||
addEventType(event_type)
|
||||
var/list/event = events[event_type]
|
||||
var/datum/event/E = new /datum/event(proc_holder,proc_name)
|
||||
event += E
|
||||
return E
|
||||
|
||||
// Arguments: event_type as text, any number of additional arguments to pass to event handler
|
||||
// Returns: null
|
||||
/datum/events/proc/fireEvent()
|
||||
//to_world("Events in [args[1]] called")
|
||||
var/list/event = listgetindex(events,args[1])
|
||||
if(istype(event))
|
||||
spawn(-1)
|
||||
for(var/datum/event/E in event)
|
||||
if(!E.Fire(arglist(args.Copy(2))))
|
||||
clearEvent(args[1],E)
|
||||
return
|
||||
|
||||
// Arguments: event_type as text, E as /datum/event
|
||||
// Returns: 1 if event cleared, null on error
|
||||
/datum/events/proc/clearEvent(event_type as text, datum/event/E)
|
||||
if(!event_type || !E)
|
||||
return
|
||||
var/list/event = listgetindex(events,event_type)
|
||||
event -= E
|
||||
return 1
|
||||
|
||||
|
||||
/datum/event
|
||||
var/listener
|
||||
var/proc_name
|
||||
|
||||
/datum/event/New(tlistener,tprocname)
|
||||
listener = tlistener
|
||||
proc_name = tprocname
|
||||
return ..()
|
||||
|
||||
/datum/event/proc/Fire()
|
||||
//to_world("Event fired")
|
||||
if(listener)
|
||||
call(listener,proc_name)(arglist(args))
|
||||
return 1
|
||||
return
|
||||
@@ -1,84 +1,84 @@
|
||||
GLOBAL_DATUM(revdata, /datum/getrev)
|
||||
|
||||
/datum/getrev
|
||||
var/branch
|
||||
var/revision
|
||||
var/date
|
||||
var/showinfo
|
||||
var/list/testmerge = list()
|
||||
|
||||
/datum/getrev/New()
|
||||
if(world.TgsAvailable()) // Try TGS maybe
|
||||
testmerge = world.TgsTestMerges()
|
||||
var/datum/tgs_revision_information/REV = world.TgsRevision()
|
||||
if(REV)
|
||||
revision = REV.origin_commit || REV.commit
|
||||
branch = "-Using TGS-" // TGS doesn't provide branch info yet
|
||||
date = "-Using TGS-" // Or date
|
||||
|
||||
if(!revision) // File parse method
|
||||
var/list/head_branch = file2list(".git/HEAD", "\n")
|
||||
if(head_branch.len)
|
||||
branch = copytext(head_branch[1], 17)
|
||||
|
||||
var/list/head_log = file2list(".git/logs/HEAD", "\n")
|
||||
for(var/line=head_log.len, line>=1, line--)
|
||||
if(head_log[line])
|
||||
var/list/last_entry = splittext(head_log[line], " ")
|
||||
if(last_entry.len < 2) continue
|
||||
revision = last_entry[2]
|
||||
// Get date/time
|
||||
if(last_entry.len >= 5)
|
||||
var/unix_time = text2num(last_entry[5])
|
||||
if(unix_time)
|
||||
date = unix2date(unix_time)
|
||||
break
|
||||
|
||||
to_world_log("-Revision Info-")
|
||||
to_world_log("Branch: [branch]")
|
||||
to_world_log("Date: [date]")
|
||||
to_world_log("Revision: [revision]")
|
||||
|
||||
/datum/getrev/proc/GetTestMergeInfo(header = TRUE)
|
||||
. = list()
|
||||
if(!testmerge.len)
|
||||
return
|
||||
if(header)
|
||||
. += "The following pull requests are currently test merged:"
|
||||
for(var/datum/tgs_revision_information/test_merge/tm as anything in testmerge)
|
||||
var/cm = tm.pull_request_commit
|
||||
var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext_char(cm, 1, 11))
|
||||
if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
|
||||
continue
|
||||
. += "<a href=\"[config.githuburl]/pull/[tm.number]\">#[tm.number][details]</a>"
|
||||
|
||||
/client/verb/showrevinfo()
|
||||
set category = "OOC"
|
||||
set name = "Show Server Revision"
|
||||
set desc = "Check the current server code revision"
|
||||
|
||||
if(!GLOB.revdata)
|
||||
to_chat(src, "<span class='warning'>Please wait until server initializations are complete.</span>")
|
||||
return
|
||||
|
||||
var/list/msg = list()
|
||||
|
||||
if(GLOB.revdata.revision)
|
||||
msg += "<b>Server revision:</b> B:[GLOB.revdata.branch] D:[GLOB.revdata.date]"
|
||||
if(config.githuburl)
|
||||
msg += "<b>Commit:</b> <a href='[config.githuburl]/commit/[GLOB.revdata.revision]'>[GLOB.revdata.revision]</a>"
|
||||
else
|
||||
msg += "<b>Commit:</b> GLOB.revdata.revision"
|
||||
else
|
||||
msg += "<b>Server revision:</b> Unknown"
|
||||
|
||||
if(world.TgsAvailable())
|
||||
var/datum/tgs_version/version = world.TgsVersion()
|
||||
msg += "<b>TGS version:</b> [version.raw_parameter]"
|
||||
var/datum/tgs_version/api_version = world.TgsApiVersion()
|
||||
msg += "<b>DMAPI version:</b> [api_version.raw_parameter]"
|
||||
|
||||
if(GLOB.revdata.testmerge.len)
|
||||
msg += GLOB.revdata.GetTestMergeInfo()
|
||||
|
||||
to_chat(src, msg.Join("<br>"))
|
||||
GLOBAL_DATUM(revdata, /datum/getrev)
|
||||
|
||||
/datum/getrev
|
||||
var/branch
|
||||
var/revision
|
||||
var/date
|
||||
var/showinfo
|
||||
var/list/testmerge = list()
|
||||
|
||||
/datum/getrev/New()
|
||||
if(world.TgsAvailable()) // Try TGS maybe
|
||||
testmerge = world.TgsTestMerges()
|
||||
var/datum/tgs_revision_information/REV = world.TgsRevision()
|
||||
if(REV)
|
||||
revision = REV.origin_commit || REV.commit
|
||||
branch = "-Using TGS-" // TGS doesn't provide branch info yet
|
||||
date = "-Using TGS-" // Or date
|
||||
|
||||
if(!revision) // File parse method
|
||||
var/list/head_branch = file2list(".git/HEAD", "\n")
|
||||
if(head_branch.len)
|
||||
branch = copytext(head_branch[1], 17)
|
||||
|
||||
var/list/head_log = file2list(".git/logs/HEAD", "\n")
|
||||
for(var/line=head_log.len, line>=1, line--)
|
||||
if(head_log[line])
|
||||
var/list/last_entry = splittext(head_log[line], " ")
|
||||
if(last_entry.len < 2) continue
|
||||
revision = last_entry[2]
|
||||
// Get date/time
|
||||
if(last_entry.len >= 5)
|
||||
var/unix_time = text2num(last_entry[5])
|
||||
if(unix_time)
|
||||
date = unix2date(unix_time)
|
||||
break
|
||||
|
||||
to_world_log("-Revision Info-")
|
||||
to_world_log("Branch: [branch]")
|
||||
to_world_log("Date: [date]")
|
||||
to_world_log("Revision: [revision]")
|
||||
|
||||
/datum/getrev/proc/GetTestMergeInfo(header = TRUE)
|
||||
. = list()
|
||||
if(!testmerge.len)
|
||||
return
|
||||
if(header)
|
||||
. += "The following pull requests are currently test merged:"
|
||||
for(var/datum/tgs_revision_information/test_merge/tm as anything in testmerge)
|
||||
var/cm = tm.pull_request_commit
|
||||
var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext_char(cm, 1, 11))
|
||||
if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
|
||||
continue
|
||||
. += "<a href=\"[config.githuburl]/pull/[tm.number]\">#[tm.number][details]</a>"
|
||||
|
||||
/client/verb/showrevinfo()
|
||||
set category = "OOC"
|
||||
set name = "Show Server Revision"
|
||||
set desc = "Check the current server code revision"
|
||||
|
||||
if(!GLOB.revdata)
|
||||
to_chat(src, "<span class='warning'>Please wait until server initializations are complete.</span>")
|
||||
return
|
||||
|
||||
var/list/msg = list()
|
||||
|
||||
if(GLOB.revdata.revision)
|
||||
msg += "<b>Server revision:</b> B:[GLOB.revdata.branch] D:[GLOB.revdata.date]"
|
||||
if(config.githuburl)
|
||||
msg += "<b>Commit:</b> <a href='[config.githuburl]/commit/[GLOB.revdata.revision]'>[GLOB.revdata.revision]</a>"
|
||||
else
|
||||
msg += "<b>Commit:</b> GLOB.revdata.revision"
|
||||
else
|
||||
msg += "<b>Server revision:</b> Unknown"
|
||||
|
||||
if(world.TgsAvailable())
|
||||
var/datum/tgs_version/version = world.TgsVersion()
|
||||
msg += "<b>TGS version:</b> [version.raw_parameter]"
|
||||
var/datum/tgs_version/api_version = world.TgsApiVersion()
|
||||
msg += "<b>DMAPI version:</b> [api_version.raw_parameter]"
|
||||
|
||||
if(GLOB.revdata.testmerge.len)
|
||||
msg += GLOB.revdata.GetTestMergeInfo()
|
||||
|
||||
to_chat(src, msg.Join("<br>"))
|
||||
|
||||
@@ -1,234 +1,234 @@
|
||||
var/bluespace_item_types = newlist(/obj/item/weapon/storage/backpack/holding,
|
||||
/obj/item/weapon/storage/bag/trash/holding,
|
||||
/obj/item/weapon/storage/pouch/holding,
|
||||
/obj/item/weapon/storage/belt/utility/holding,
|
||||
/obj/item/weapon/storage/belt/medical/holding
|
||||
)
|
||||
|
||||
//wrapper
|
||||
/proc/do_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE) //VOREStation Edit
|
||||
new /datum/teleport/instant/science(arglist(args))
|
||||
return
|
||||
|
||||
/datum/teleport
|
||||
var/atom/movable/teleatom //atom to teleport
|
||||
var/atom/destination //destination to teleport to
|
||||
var/precision = 0 //teleport precision
|
||||
var/datum/effect/effect/system/effectin //effect to show right before teleportation
|
||||
var/datum/effect/effect/system/effectout //effect to show right after teleportation
|
||||
var/soundin //soundfile to play before teleportation
|
||||
var/soundout //soundfile to play after teleportation
|
||||
var/force_teleport = 1 //if false, teleport will use Move() proc (dense objects will prevent teleportation)
|
||||
var/local = TRUE //VOREStation Add - If false, can teleport from/to any z-level
|
||||
|
||||
|
||||
/datum/teleport/New(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE) //VOREStation Edit
|
||||
..()
|
||||
if(!initTeleport(arglist(args)))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/teleport/proc/initTeleport(ateleatom,adestination,aprecision,afteleport,aeffectin,aeffectout,asoundin,asoundout,local) //VOREStation Edit
|
||||
if(!setTeleatom(ateleatom))
|
||||
return 0
|
||||
if(!setDestination(adestination))
|
||||
return 0
|
||||
if(!setPrecision(aprecision))
|
||||
return 0
|
||||
setEffects(aeffectin,aeffectout)
|
||||
setForceTeleport(afteleport)
|
||||
setSounds(asoundin,asoundout)
|
||||
src.local = local // VOREStation Add
|
||||
return 1
|
||||
|
||||
//must succeed
|
||||
/datum/teleport/proc/setPrecision(aprecision)
|
||||
if(isnum(aprecision))
|
||||
precision = aprecision
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//must succeed
|
||||
/datum/teleport/proc/setDestination(atom/adestination)
|
||||
if(istype(adestination))
|
||||
destination = adestination
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//must succeed in most cases
|
||||
/datum/teleport/proc/setTeleatom(atom/movable/ateleatom)
|
||||
if(istype(ateleatom, /obj/effect) && !istype(ateleatom, /obj/effect/dummy/chameleon))
|
||||
qdel(ateleatom)
|
||||
return 0
|
||||
if(istype(ateleatom))
|
||||
teleatom = ateleatom
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//custom effects must be properly set up first for instant-type teleports
|
||||
//optional
|
||||
/datum/teleport/proc/setEffects(datum/effect/effect/system/aeffectin=null,datum/effect/effect/system/aeffectout=null)
|
||||
effectin = istype(aeffectin) ? aeffectin : null
|
||||
effectout = istype(aeffectout) ? aeffectout : null
|
||||
return 1
|
||||
|
||||
//optional
|
||||
/datum/teleport/proc/setForceTeleport(afteleport)
|
||||
force_teleport = afteleport
|
||||
return 1
|
||||
|
||||
//optional
|
||||
/datum/teleport/proc/setSounds(asoundin=null,asoundout=null)
|
||||
soundin = isfile(asoundin) ? asoundin : null
|
||||
soundout = isfile(asoundout) ? asoundout : null
|
||||
return 1
|
||||
|
||||
//placeholder
|
||||
/datum/teleport/proc/teleportChecks()
|
||||
return 1
|
||||
|
||||
/datum/teleport/proc/playSpecials(atom/location,datum/effect/effect/system/effect,sound)
|
||||
if(location)
|
||||
if(effect)
|
||||
spawn(-1)
|
||||
src = null
|
||||
effect.attach(location)
|
||||
effect.start()
|
||||
if(sound)
|
||||
spawn(-1)
|
||||
src = null
|
||||
playsound(location,sound,60,1)
|
||||
return
|
||||
|
||||
//do the monkey dance
|
||||
/datum/teleport/proc/doTeleport()
|
||||
|
||||
var/turf/destturf
|
||||
var/turf/curturf = get_turf(teleatom)
|
||||
if(precision)
|
||||
var/list/posturfs = circlerangeturfs(destination,precision)
|
||||
destturf = safepick(posturfs)
|
||||
else
|
||||
destturf = get_turf(destination)
|
||||
|
||||
if(!destturf || !curturf)
|
||||
return 0
|
||||
|
||||
playSpecials(curturf,effectin,soundin)
|
||||
|
||||
var/obj/structure/bed/chair/C = null
|
||||
if(isliving(teleatom))
|
||||
var/mob/living/L = teleatom
|
||||
if(L.buckled)
|
||||
C = L.buckled
|
||||
if(attempt_vr(src,"try_televore",args)) return //VOREStation Edit - Telenoms.
|
||||
if(force_teleport)
|
||||
teleatom.forceMove(destturf)
|
||||
playSpecials(destturf,effectout,soundout)
|
||||
else
|
||||
if(teleatom.Move(destturf))
|
||||
playSpecials(destturf,effectout,soundout)
|
||||
if(C)
|
||||
C.forceMove(destturf)
|
||||
|
||||
return 1
|
||||
|
||||
/datum/teleport/proc/teleport()
|
||||
if(teleportChecks())
|
||||
return doTeleport()
|
||||
return 0
|
||||
|
||||
/datum/teleport/instant //teleports when datum is created
|
||||
|
||||
/datum/teleport/instant/New(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
|
||||
if(..())
|
||||
teleport()
|
||||
return
|
||||
|
||||
|
||||
/datum/teleport/instant/science/setEffects(datum/effect/effect/system/aeffectin,datum/effect/effect/system/aeffectout)
|
||||
if(!aeffectin || !aeffectout)
|
||||
var/datum/effect/effect/system/spark_spread/aeffect = new
|
||||
aeffect.set_up(5, 1, teleatom)
|
||||
effectin = effectin || aeffect
|
||||
effectout = effectout || aeffect
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/datum/teleport/instant/science/setPrecision(aprecision)
|
||||
..()
|
||||
|
||||
var/list/bluespace_things = newlist()
|
||||
|
||||
for (var/item in bluespace_item_types)
|
||||
if (istype(teleatom, item))
|
||||
precision = rand(1, 100)
|
||||
bluespace_things |= teleatom.search_contents_for(item)
|
||||
|
||||
//VOREStation Addition Start: Prevent taurriding abuse
|
||||
if(istype(teleatom, /mob/living))
|
||||
var/mob/living/L = teleatom
|
||||
if(LAZYLEN(L.buckled_mobs))
|
||||
for(var/mob/rider in L.buckled_mobs)
|
||||
for (var/item in bluespace_item_types)
|
||||
bluespace_things |= rider.search_contents_for(item)
|
||||
//VOREStation Addition End: Prevent taurriding abuse
|
||||
|
||||
if(bluespace_things.len)
|
||||
precision = max(rand(1,100)*bluespace_things.len,100)
|
||||
if(istype(teleatom, /mob/living))
|
||||
var/mob/living/MM = teleatom
|
||||
to_chat(MM, "<span class='danger'>The Bluespace interface on your [teleatom] interferes with the teleport!</span>")
|
||||
return 1
|
||||
|
||||
/datum/teleport/instant/science/teleportChecks()
|
||||
if(istype(teleatom, /obj/item/weapon/disk/nuclear)) // Don't let nuke disks get teleported --NeoFite
|
||||
teleatom.visible_message("<span class='danger'>\The [teleatom] bounces off of the portal!</span>")
|
||||
return 0
|
||||
|
||||
if(!isemptylist(teleatom.search_contents_for(/obj/item/weapon/disk/nuclear)))
|
||||
if(istype(teleatom, /mob/living))
|
||||
var/mob/living/MM = teleatom
|
||||
MM.visible_message("<span class='danger'>\The [MM] bounces off of the portal!</span>","<span class='warning'>Something you are carrying seems to be unable to pass through the portal. Better drop it if you want to go through.</span>")
|
||||
else
|
||||
teleatom.visible_message("<span class='danger'>\The [teleatom] bounces off of the portal!</span>")
|
||||
return 0
|
||||
/* VOREStation Removal
|
||||
if(destination.z in using_map.admin_levels) //CentCom z-level
|
||||
if(istype(teleatom, /obj/mecha))
|
||||
var/obj/mecha/MM = teleatom
|
||||
to_chat(MM.occupant, "<span class='danger'>\The [MM] would not survive the jump to a location so far away!</span>")
|
||||
return 0
|
||||
if(!isemptylist(teleatom.search_contents_for(/obj/item/weapon/storage/backpack/holding)))
|
||||
teleatom.visible_message("<span class='danger'>\The [teleatom] bounces off of the portal!</span>")
|
||||
return 0
|
||||
*/ //VOREStation Removal End
|
||||
//VOREStation Edit Start
|
||||
var/obstructed = 0
|
||||
var/turf/dest_turf = get_turf(destination)
|
||||
if(local && !(dest_turf.z in using_map.player_levels))
|
||||
if(istype(teleatom, /mob/living))
|
||||
to_chat(teleatom, "<span class='warning'>The portal refuses to carry you that far away!</span>")
|
||||
return 0
|
||||
else if(istype(destination.loc, /obj/belly))
|
||||
var/obj/belly/destination_belly = destination.loc
|
||||
var/mob/living/telenommer = destination_belly.owner
|
||||
if(istype(telenommer))
|
||||
if(istype(teleatom, /obj/machinery) || istype(teleatom, /obj/structure))
|
||||
return 0
|
||||
else if(!isliving(teleatom))
|
||||
return 1
|
||||
else
|
||||
var/mob/living/telemob = teleatom
|
||||
if(telemob.can_be_drop_prey && telenommer.can_be_drop_pred)
|
||||
return 1
|
||||
obstructed = 1
|
||||
else if(!((isturf(destination) && !destination.density) || (isturf(destination.loc) && !destination.loc.density)) || !destination.x || !destination.y || !destination.z) //If we're inside something or outside universe
|
||||
obstructed = 1
|
||||
to_chat(teleatom, "<span class='warning'>Something is blocking way on the other side!</span>")
|
||||
if(obstructed)
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
var/bluespace_item_types = newlist(/obj/item/weapon/storage/backpack/holding,
|
||||
/obj/item/weapon/storage/bag/trash/holding,
|
||||
/obj/item/weapon/storage/pouch/holding,
|
||||
/obj/item/weapon/storage/belt/utility/holding,
|
||||
/obj/item/weapon/storage/belt/medical/holding
|
||||
)
|
||||
|
||||
//wrapper
|
||||
/proc/do_teleport(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE) //VOREStation Edit
|
||||
new /datum/teleport/instant/science(arglist(args))
|
||||
return
|
||||
|
||||
/datum/teleport
|
||||
var/atom/movable/teleatom //atom to teleport
|
||||
var/atom/destination //destination to teleport to
|
||||
var/precision = 0 //teleport precision
|
||||
var/datum/effect/effect/system/effectin //effect to show right before teleportation
|
||||
var/datum/effect/effect/system/effectout //effect to show right after teleportation
|
||||
var/soundin //soundfile to play before teleportation
|
||||
var/soundout //soundfile to play after teleportation
|
||||
var/force_teleport = 1 //if false, teleport will use Move() proc (dense objects will prevent teleportation)
|
||||
var/local = TRUE //VOREStation Add - If false, can teleport from/to any z-level
|
||||
|
||||
|
||||
/datum/teleport/New(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null, local=TRUE) //VOREStation Edit
|
||||
..()
|
||||
if(!initTeleport(arglist(args)))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/teleport/proc/initTeleport(ateleatom,adestination,aprecision,afteleport,aeffectin,aeffectout,asoundin,asoundout,local) //VOREStation Edit
|
||||
if(!setTeleatom(ateleatom))
|
||||
return 0
|
||||
if(!setDestination(adestination))
|
||||
return 0
|
||||
if(!setPrecision(aprecision))
|
||||
return 0
|
||||
setEffects(aeffectin,aeffectout)
|
||||
setForceTeleport(afteleport)
|
||||
setSounds(asoundin,asoundout)
|
||||
src.local = local // VOREStation Add
|
||||
return 1
|
||||
|
||||
//must succeed
|
||||
/datum/teleport/proc/setPrecision(aprecision)
|
||||
if(isnum(aprecision))
|
||||
precision = aprecision
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//must succeed
|
||||
/datum/teleport/proc/setDestination(atom/adestination)
|
||||
if(istype(adestination))
|
||||
destination = adestination
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//must succeed in most cases
|
||||
/datum/teleport/proc/setTeleatom(atom/movable/ateleatom)
|
||||
if(istype(ateleatom, /obj/effect) && !istype(ateleatom, /obj/effect/dummy/chameleon))
|
||||
qdel(ateleatom)
|
||||
return 0
|
||||
if(istype(ateleatom))
|
||||
teleatom = ateleatom
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//custom effects must be properly set up first for instant-type teleports
|
||||
//optional
|
||||
/datum/teleport/proc/setEffects(datum/effect/effect/system/aeffectin=null,datum/effect/effect/system/aeffectout=null)
|
||||
effectin = istype(aeffectin) ? aeffectin : null
|
||||
effectout = istype(aeffectout) ? aeffectout : null
|
||||
return 1
|
||||
|
||||
//optional
|
||||
/datum/teleport/proc/setForceTeleport(afteleport)
|
||||
force_teleport = afteleport
|
||||
return 1
|
||||
|
||||
//optional
|
||||
/datum/teleport/proc/setSounds(asoundin=null,asoundout=null)
|
||||
soundin = isfile(asoundin) ? asoundin : null
|
||||
soundout = isfile(asoundout) ? asoundout : null
|
||||
return 1
|
||||
|
||||
//placeholder
|
||||
/datum/teleport/proc/teleportChecks()
|
||||
return 1
|
||||
|
||||
/datum/teleport/proc/playSpecials(atom/location,datum/effect/effect/system/effect,sound)
|
||||
if(location)
|
||||
if(effect)
|
||||
spawn(-1)
|
||||
src = null
|
||||
effect.attach(location)
|
||||
effect.start()
|
||||
if(sound)
|
||||
spawn(-1)
|
||||
src = null
|
||||
playsound(location,sound,60,1)
|
||||
return
|
||||
|
||||
//do the monkey dance
|
||||
/datum/teleport/proc/doTeleport()
|
||||
|
||||
var/turf/destturf
|
||||
var/turf/curturf = get_turf(teleatom)
|
||||
if(precision)
|
||||
var/list/posturfs = circlerangeturfs(destination,precision)
|
||||
destturf = safepick(posturfs)
|
||||
else
|
||||
destturf = get_turf(destination)
|
||||
|
||||
if(!destturf || !curturf)
|
||||
return 0
|
||||
|
||||
playSpecials(curturf,effectin,soundin)
|
||||
|
||||
var/obj/structure/bed/chair/C = null
|
||||
if(isliving(teleatom))
|
||||
var/mob/living/L = teleatom
|
||||
if(L.buckled)
|
||||
C = L.buckled
|
||||
if(attempt_vr(src,"try_televore",args)) return //VOREStation Edit - Telenoms.
|
||||
if(force_teleport)
|
||||
teleatom.forceMove(destturf)
|
||||
playSpecials(destturf,effectout,soundout)
|
||||
else
|
||||
if(teleatom.Move(destturf))
|
||||
playSpecials(destturf,effectout,soundout)
|
||||
if(C)
|
||||
C.forceMove(destturf)
|
||||
|
||||
return 1
|
||||
|
||||
/datum/teleport/proc/teleport()
|
||||
if(teleportChecks())
|
||||
return doTeleport()
|
||||
return 0
|
||||
|
||||
/datum/teleport/instant //teleports when datum is created
|
||||
|
||||
/datum/teleport/instant/New(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
|
||||
if(..())
|
||||
teleport()
|
||||
return
|
||||
|
||||
|
||||
/datum/teleport/instant/science/setEffects(datum/effect/effect/system/aeffectin,datum/effect/effect/system/aeffectout)
|
||||
if(!aeffectin || !aeffectout)
|
||||
var/datum/effect/effect/system/spark_spread/aeffect = new
|
||||
aeffect.set_up(5, 1, teleatom)
|
||||
effectin = effectin || aeffect
|
||||
effectout = effectout || aeffect
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/datum/teleport/instant/science/setPrecision(aprecision)
|
||||
..()
|
||||
|
||||
var/list/bluespace_things = newlist()
|
||||
|
||||
for (var/item in bluespace_item_types)
|
||||
if (istype(teleatom, item))
|
||||
precision = rand(1, 100)
|
||||
bluespace_things |= teleatom.search_contents_for(item)
|
||||
|
||||
//VOREStation Addition Start: Prevent taurriding abuse
|
||||
if(istype(teleatom, /mob/living))
|
||||
var/mob/living/L = teleatom
|
||||
if(LAZYLEN(L.buckled_mobs))
|
||||
for(var/mob/rider in L.buckled_mobs)
|
||||
for (var/item in bluespace_item_types)
|
||||
bluespace_things |= rider.search_contents_for(item)
|
||||
//VOREStation Addition End: Prevent taurriding abuse
|
||||
|
||||
if(bluespace_things.len)
|
||||
precision = max(rand(1,100)*bluespace_things.len,100)
|
||||
if(istype(teleatom, /mob/living))
|
||||
var/mob/living/MM = teleatom
|
||||
to_chat(MM, "<span class='danger'>The Bluespace interface on your [teleatom] interferes with the teleport!</span>")
|
||||
return 1
|
||||
|
||||
/datum/teleport/instant/science/teleportChecks()
|
||||
if(istype(teleatom, /obj/item/weapon/disk/nuclear)) // Don't let nuke disks get teleported --NeoFite
|
||||
teleatom.visible_message("<span class='danger'>\The [teleatom] bounces off of the portal!</span>")
|
||||
return 0
|
||||
|
||||
if(!isemptylist(teleatom.search_contents_for(/obj/item/weapon/disk/nuclear)))
|
||||
if(istype(teleatom, /mob/living))
|
||||
var/mob/living/MM = teleatom
|
||||
MM.visible_message("<span class='danger'>\The [MM] bounces off of the portal!</span>","<span class='warning'>Something you are carrying seems to be unable to pass through the portal. Better drop it if you want to go through.</span>")
|
||||
else
|
||||
teleatom.visible_message("<span class='danger'>\The [teleatom] bounces off of the portal!</span>")
|
||||
return 0
|
||||
/* VOREStation Removal
|
||||
if(destination.z in using_map.admin_levels) //CentCom z-level
|
||||
if(istype(teleatom, /obj/mecha))
|
||||
var/obj/mecha/MM = teleatom
|
||||
to_chat(MM.occupant, "<span class='danger'>\The [MM] would not survive the jump to a location so far away!</span>")
|
||||
return 0
|
||||
if(!isemptylist(teleatom.search_contents_for(/obj/item/weapon/storage/backpack/holding)))
|
||||
teleatom.visible_message("<span class='danger'>\The [teleatom] bounces off of the portal!</span>")
|
||||
return 0
|
||||
*/ //VOREStation Removal End
|
||||
//VOREStation Edit Start
|
||||
var/obstructed = 0
|
||||
var/turf/dest_turf = get_turf(destination)
|
||||
if(local && !(dest_turf.z in using_map.player_levels))
|
||||
if(istype(teleatom, /mob/living))
|
||||
to_chat(teleatom, "<span class='warning'>The portal refuses to carry you that far away!</span>")
|
||||
return 0
|
||||
else if(istype(destination.loc, /obj/belly))
|
||||
var/obj/belly/destination_belly = destination.loc
|
||||
var/mob/living/telenommer = destination_belly.owner
|
||||
if(istype(telenommer))
|
||||
if(istype(teleatom, /obj/machinery) || istype(teleatom, /obj/structure))
|
||||
return 0
|
||||
else if(!isliving(teleatom))
|
||||
return 1
|
||||
else
|
||||
var/mob/living/telemob = teleatom
|
||||
if(telemob.can_be_drop_prey && telenommer.can_be_drop_pred)
|
||||
return 1
|
||||
obstructed = 1
|
||||
else if(!((isturf(destination) && !destination.density) || (isturf(destination.loc) && !destination.loc.density)) || !destination.x || !destination.y || !destination.z) //If we're inside something or outside universe
|
||||
obstructed = 1
|
||||
to_chat(teleatom, "<span class='warning'>Something is blocking way on the other side!</span>")
|
||||
if(obstructed)
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
//VOREStation Edit End
|
||||
@@ -1,60 +1,60 @@
|
||||
/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)
|
||||
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)
|
||||
/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)
|
||||
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
|
||||
@@ -1,126 +1,126 @@
|
||||
/*
|
||||
output_atoms (list of atoms) The destination(s) for the sounds
|
||||
|
||||
mid_sounds (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end.
|
||||
mid_length (num) The length to wait between playing mid_sounds
|
||||
|
||||
start_sound (soundfile) Played before starting the mid_sounds loop
|
||||
start_length (num) How long to wait before starting the main loop after playing start_sound
|
||||
|
||||
end_sound (soundfile) The sound played after the main loop has concluded
|
||||
|
||||
chance (num) Chance per loop to play a mid_sound
|
||||
volume (num) Sound output volume
|
||||
muted (bool) Private. Used to stop the sound loop.
|
||||
max_loops (num) The max amount of loops to run for.
|
||||
direct (bool) If true plays directly to provided atoms instead of from them
|
||||
opacity_check (bool) If true, things behind walls/opaque things won't hear the sounds.
|
||||
pref_check (type) If set to a /datum/client_preference type, will check if the hearer has that preference active before playing it to them.
|
||||
exclusive (bool) If true, only one of this sound is allowed to play. Relies on if started is true or not. If true, it will not start another loop until it is false.
|
||||
*/
|
||||
/datum/looping_sound
|
||||
var/list/atom/output_atoms
|
||||
var/mid_sounds
|
||||
var/mid_length
|
||||
var/start_sound
|
||||
var/start_length
|
||||
var/end_sound
|
||||
var/chance
|
||||
var/volume = 100
|
||||
var/max_loops
|
||||
var/direct
|
||||
var/vary
|
||||
var/extra_range
|
||||
var/opacity_check
|
||||
var/pref_check
|
||||
var/exclusive
|
||||
|
||||
var/timerid
|
||||
var/started
|
||||
|
||||
/datum/looping_sound/New(list/_output_atoms=list(), start_immediately=FALSE, disable_direct=FALSE)
|
||||
if(!mid_sounds)
|
||||
WARNING("A looping sound datum was created without sounds to play.")
|
||||
return
|
||||
|
||||
output_atoms = _output_atoms
|
||||
if(disable_direct)
|
||||
direct = FALSE
|
||||
|
||||
if(start_immediately)
|
||||
start()
|
||||
|
||||
/datum/looping_sound/Destroy()
|
||||
stop()
|
||||
output_atoms = null
|
||||
return ..()
|
||||
|
||||
/datum/looping_sound/proc/start(atom/add_thing, skip_start_sound = FALSE)
|
||||
if(add_thing)
|
||||
output_atoms |= add_thing
|
||||
if(timerid)
|
||||
return
|
||||
if(skip_start_sound && (!exclusive && !started)) // Skip start sounds optionally, check if we're exclusive AND started already
|
||||
sound_loop()
|
||||
started = TRUE
|
||||
return
|
||||
if(exclusive && started) // Prevents a sound from starting multiple times
|
||||
return // Don't start this loop.
|
||||
on_start()
|
||||
started = TRUE
|
||||
|
||||
/datum/looping_sound/proc/stop(atom/remove_thing, skip_stop_sound = FALSE)
|
||||
if(remove_thing)
|
||||
output_atoms -= remove_thing
|
||||
if(!timerid)
|
||||
return
|
||||
if(!skip_stop_sound)
|
||||
on_stop()
|
||||
deltimer(timerid)
|
||||
timerid = null
|
||||
started = FALSE
|
||||
|
||||
/datum/looping_sound/proc/sound_loop(starttime)
|
||||
if(max_loops && world.time >= starttime + mid_length * max_loops)
|
||||
stop()
|
||||
return
|
||||
if(!chance || prob(chance))
|
||||
play(get_sound(starttime))
|
||||
if(!timerid)
|
||||
timerid = addtimer(CALLBACK(src, PROC_REF(sound_loop), world.time), mid_length, TIMER_STOPPABLE | TIMER_LOOP)
|
||||
|
||||
/datum/looping_sound/proc/play(soundfile)
|
||||
var/list/atoms_cache = output_atoms
|
||||
var/sound/S = sound(soundfile)
|
||||
if(direct)
|
||||
S.channel = SSsounds.random_available_channel()
|
||||
S.volume = volume
|
||||
for(var/i in 1 to atoms_cache.len)
|
||||
var/atom/thing = atoms_cache[i]
|
||||
if(direct)
|
||||
if(ismob(thing))
|
||||
var/mob/M = thing
|
||||
if(pref_check && !M.is_preference_enabled(pref_check))
|
||||
continue
|
||||
SEND_SOUND(thing, S)
|
||||
else
|
||||
playsound(thing, S, volume, vary, extra_range, ignore_walls = !opacity_check, preference = pref_check)
|
||||
|
||||
/datum/looping_sound/proc/get_sound(starttime, _mid_sounds)
|
||||
if(!_mid_sounds)
|
||||
. = mid_sounds
|
||||
else
|
||||
. = _mid_sounds
|
||||
while(!isfile(.) && !isnull(.))
|
||||
. = pickweight(.)
|
||||
|
||||
/datum/looping_sound/proc/on_start()
|
||||
var/start_wait = 1 // On TG this is 0, however it needs to be 1 to work around an issue.
|
||||
if(start_sound)
|
||||
play(start_sound)
|
||||
start_wait = start_length
|
||||
addtimer(CALLBACK(src, PROC_REF(sound_loop)), start_wait)
|
||||
|
||||
/datum/looping_sound/proc/on_stop()
|
||||
if(end_sound)
|
||||
play(end_sound)
|
||||
/*
|
||||
output_atoms (list of atoms) The destination(s) for the sounds
|
||||
|
||||
mid_sounds (list or soundfile) Since this can be either a list or a single soundfile you can have random sounds. May contain further lists but must contain a soundfile at the end.
|
||||
mid_length (num) The length to wait between playing mid_sounds
|
||||
|
||||
start_sound (soundfile) Played before starting the mid_sounds loop
|
||||
start_length (num) How long to wait before starting the main loop after playing start_sound
|
||||
|
||||
end_sound (soundfile) The sound played after the main loop has concluded
|
||||
|
||||
chance (num) Chance per loop to play a mid_sound
|
||||
volume (num) Sound output volume
|
||||
muted (bool) Private. Used to stop the sound loop.
|
||||
max_loops (num) The max amount of loops to run for.
|
||||
direct (bool) If true plays directly to provided atoms instead of from them
|
||||
opacity_check (bool) If true, things behind walls/opaque things won't hear the sounds.
|
||||
pref_check (type) If set to a /datum/client_preference type, will check if the hearer has that preference active before playing it to them.
|
||||
exclusive (bool) If true, only one of this sound is allowed to play. Relies on if started is true or not. If true, it will not start another loop until it is false.
|
||||
*/
|
||||
/datum/looping_sound
|
||||
var/list/atom/output_atoms
|
||||
var/mid_sounds
|
||||
var/mid_length
|
||||
var/start_sound
|
||||
var/start_length
|
||||
var/end_sound
|
||||
var/chance
|
||||
var/volume = 100
|
||||
var/max_loops
|
||||
var/direct
|
||||
var/vary
|
||||
var/extra_range
|
||||
var/opacity_check
|
||||
var/pref_check
|
||||
var/exclusive
|
||||
|
||||
var/timerid
|
||||
var/started
|
||||
|
||||
/datum/looping_sound/New(list/_output_atoms=list(), start_immediately=FALSE, disable_direct=FALSE)
|
||||
if(!mid_sounds)
|
||||
WARNING("A looping sound datum was created without sounds to play.")
|
||||
return
|
||||
|
||||
output_atoms = _output_atoms
|
||||
if(disable_direct)
|
||||
direct = FALSE
|
||||
|
||||
if(start_immediately)
|
||||
start()
|
||||
|
||||
/datum/looping_sound/Destroy()
|
||||
stop()
|
||||
output_atoms = null
|
||||
return ..()
|
||||
|
||||
/datum/looping_sound/proc/start(atom/add_thing, skip_start_sound = FALSE)
|
||||
if(add_thing)
|
||||
output_atoms |= add_thing
|
||||
if(timerid)
|
||||
return
|
||||
if(skip_start_sound && (!exclusive && !started)) // Skip start sounds optionally, check if we're exclusive AND started already
|
||||
sound_loop()
|
||||
started = TRUE
|
||||
return
|
||||
if(exclusive && started) // Prevents a sound from starting multiple times
|
||||
return // Don't start this loop.
|
||||
on_start()
|
||||
started = TRUE
|
||||
|
||||
/datum/looping_sound/proc/stop(atom/remove_thing, skip_stop_sound = FALSE)
|
||||
if(remove_thing)
|
||||
output_atoms -= remove_thing
|
||||
if(!timerid)
|
||||
return
|
||||
if(!skip_stop_sound)
|
||||
on_stop()
|
||||
deltimer(timerid)
|
||||
timerid = null
|
||||
started = FALSE
|
||||
|
||||
/datum/looping_sound/proc/sound_loop(starttime)
|
||||
if(max_loops && world.time >= starttime + mid_length * max_loops)
|
||||
stop()
|
||||
return
|
||||
if(!chance || prob(chance))
|
||||
play(get_sound(starttime))
|
||||
if(!timerid)
|
||||
timerid = addtimer(CALLBACK(src, PROC_REF(sound_loop), world.time), mid_length, TIMER_STOPPABLE | TIMER_LOOP)
|
||||
|
||||
/datum/looping_sound/proc/play(soundfile)
|
||||
var/list/atoms_cache = output_atoms
|
||||
var/sound/S = sound(soundfile)
|
||||
if(direct)
|
||||
S.channel = SSsounds.random_available_channel()
|
||||
S.volume = volume
|
||||
for(var/i in 1 to atoms_cache.len)
|
||||
var/atom/thing = atoms_cache[i]
|
||||
if(direct)
|
||||
if(ismob(thing))
|
||||
var/mob/M = thing
|
||||
if(pref_check && !M.is_preference_enabled(pref_check))
|
||||
continue
|
||||
SEND_SOUND(thing, S)
|
||||
else
|
||||
playsound(thing, S, volume, vary, extra_range, ignore_walls = !opacity_check, preference = pref_check)
|
||||
|
||||
/datum/looping_sound/proc/get_sound(starttime, _mid_sounds)
|
||||
if(!_mid_sounds)
|
||||
. = mid_sounds
|
||||
else
|
||||
. = _mid_sounds
|
||||
while(!isfile(.) && !isnull(.))
|
||||
. = pickweight(.)
|
||||
|
||||
/datum/looping_sound/proc/on_start()
|
||||
var/start_wait = 1 // On TG this is 0, however it needs to be 1 to work around an issue.
|
||||
if(start_sound)
|
||||
play(start_sound)
|
||||
start_wait = start_length
|
||||
addtimer(CALLBACK(src, PROC_REF(sound_loop)), start_wait)
|
||||
|
||||
/datum/looping_sound/proc/on_stop()
|
||||
if(end_sound)
|
||||
play(end_sound)
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
/datum/looping_sound/geiger
|
||||
mid_sounds = list(
|
||||
list('sound/items/geiger/low1.ogg'=1, 'sound/items/geiger/low2.ogg'=1, 'sound/items/geiger/low3.ogg'=1, 'sound/items/geiger/low4.ogg'=1),
|
||||
list('sound/items/geiger/med1.ogg'=1, 'sound/items/geiger/med2.ogg'=1, 'sound/items/geiger/med3.ogg'=1, 'sound/items/geiger/med4.ogg'=1),
|
||||
list('sound/items/geiger/high1.ogg'=1, 'sound/items/geiger/high2.ogg'=1, 'sound/items/geiger/high3.ogg'=1, 'sound/items/geiger/high4.ogg'=1),
|
||||
list('sound/items/geiger/ext1.ogg'=1, 'sound/items/geiger/ext2.ogg'=1, 'sound/items/geiger/ext3.ogg'=1, 'sound/items/geiger/ext4.ogg'=1)
|
||||
)
|
||||
mid_length = 1 SECOND
|
||||
volume = 25
|
||||
var/last_radiation
|
||||
|
||||
/datum/looping_sound/geiger/get_sound(starttime)
|
||||
var/danger
|
||||
switch(last_radiation)
|
||||
if(0 to RAD_LEVEL_MODERATE)
|
||||
danger = 1
|
||||
if(RAD_LEVEL_MODERATE to RAD_LEVEL_HIGH)
|
||||
danger = 2
|
||||
if(RAD_LEVEL_HIGH to RAD_LEVEL_VERY_HIGH)
|
||||
danger = 3
|
||||
if(RAD_LEVEL_VERY_HIGH to INFINITY)
|
||||
danger = 4
|
||||
else
|
||||
return null
|
||||
return ..(starttime, mid_sounds[danger])
|
||||
|
||||
/datum/looping_sound/geiger/stop()
|
||||
. = ..()
|
||||
last_radiation = 0
|
||||
|
||||
/datum/looping_sound/small_motor
|
||||
start_sound = 'sound/items/small_motor/motor_start_nopull.ogg'
|
||||
start_length = 2 SECONDS
|
||||
mid_sounds = list(
|
||||
'sound/items/small_motor/motor_idle.ogg',
|
||||
'sound/items/small_motor/motor_fast.ogg',
|
||||
'sound/items/small_motor/motor_faster.ogg'
|
||||
)
|
||||
mid_length = 1.9 SECONDS //someone make this loop better please, i'm no good at sound. the clips should be 2 seconds exact but there's a gap if it's set to 2
|
||||
end_sound = 'sound/items/small_motor/motor_end.ogg'
|
||||
var/speed = 1
|
||||
|
||||
/datum/looping_sound/small_motor/get_sound(starttime)
|
||||
speed = clamp(speed, 1, 3)
|
||||
/datum/looping_sound/geiger
|
||||
mid_sounds = list(
|
||||
list('sound/items/geiger/low1.ogg'=1, 'sound/items/geiger/low2.ogg'=1, 'sound/items/geiger/low3.ogg'=1, 'sound/items/geiger/low4.ogg'=1),
|
||||
list('sound/items/geiger/med1.ogg'=1, 'sound/items/geiger/med2.ogg'=1, 'sound/items/geiger/med3.ogg'=1, 'sound/items/geiger/med4.ogg'=1),
|
||||
list('sound/items/geiger/high1.ogg'=1, 'sound/items/geiger/high2.ogg'=1, 'sound/items/geiger/high3.ogg'=1, 'sound/items/geiger/high4.ogg'=1),
|
||||
list('sound/items/geiger/ext1.ogg'=1, 'sound/items/geiger/ext2.ogg'=1, 'sound/items/geiger/ext3.ogg'=1, 'sound/items/geiger/ext4.ogg'=1)
|
||||
)
|
||||
mid_length = 1 SECOND
|
||||
volume = 25
|
||||
var/last_radiation
|
||||
|
||||
/datum/looping_sound/geiger/get_sound(starttime)
|
||||
var/danger
|
||||
switch(last_radiation)
|
||||
if(0 to RAD_LEVEL_MODERATE)
|
||||
danger = 1
|
||||
if(RAD_LEVEL_MODERATE to RAD_LEVEL_HIGH)
|
||||
danger = 2
|
||||
if(RAD_LEVEL_HIGH to RAD_LEVEL_VERY_HIGH)
|
||||
danger = 3
|
||||
if(RAD_LEVEL_VERY_HIGH to INFINITY)
|
||||
danger = 4
|
||||
else
|
||||
return null
|
||||
return ..(starttime, mid_sounds[danger])
|
||||
|
||||
/datum/looping_sound/geiger/stop()
|
||||
. = ..()
|
||||
last_radiation = 0
|
||||
|
||||
/datum/looping_sound/small_motor
|
||||
start_sound = 'sound/items/small_motor/motor_start_nopull.ogg'
|
||||
start_length = 2 SECONDS
|
||||
mid_sounds = list(
|
||||
'sound/items/small_motor/motor_idle.ogg',
|
||||
'sound/items/small_motor/motor_fast.ogg',
|
||||
'sound/items/small_motor/motor_faster.ogg'
|
||||
)
|
||||
mid_length = 1.9 SECONDS //someone make this loop better please, i'm no good at sound. the clips should be 2 seconds exact but there's a gap if it's set to 2
|
||||
end_sound = 'sound/items/small_motor/motor_end.ogg'
|
||||
var/speed = 1
|
||||
|
||||
/datum/looping_sound/small_motor/get_sound(starttime)
|
||||
speed = clamp(speed, 1, 3)
|
||||
return ..(starttime, mid_sounds[speed])
|
||||
@@ -1,117 +1,117 @@
|
||||
/datum/looping_sound/showering
|
||||
start_sound = 'sound/machines/shower/shower_start.ogg'
|
||||
start_length = 2
|
||||
mid_sounds = list('sound/machines/shower/shower_mid1.ogg'=1,'sound/machines/shower/shower_mid2.ogg'=1,'sound/machines/shower/shower_mid3.ogg'=1)
|
||||
mid_length = 10
|
||||
end_sound = 'sound/machines/shower/shower_end.ogg'
|
||||
volume = 15
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/supermatter
|
||||
mid_sounds = list('sound/machines/sm/loops/calm.ogg'=1)
|
||||
mid_length = 60
|
||||
volume = 40
|
||||
extra_range = 10
|
||||
pref_check = /datum/client_preference/supermatter_hum
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/generator
|
||||
start_sound = 'sound/machines/generator/generator_start.ogg'
|
||||
start_length = 4
|
||||
mid_sounds = list('sound/machines/generator/generator_mid1.ogg'=1, 'sound/machines/generator/generator_mid2.ogg'=1, 'sound/machines/generator/generator_mid3.ogg'=1)
|
||||
mid_length = 4
|
||||
end_sound = 'sound/machines/generator/generator_end.ogg'
|
||||
volume = 40
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/datum/looping_sound/deep_fryer
|
||||
start_sound = 'sound/machines/kitchen/fryer/deep_fryer_immerse.ogg' //my immersions
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/kitchen/fryer/deep_fryer_2.ogg' = 1)
|
||||
mid_length = 2
|
||||
end_sound = 'sound/machines/kitchen/fryer/deep_fryer_emerge.ogg'
|
||||
volume = 15
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/microwave
|
||||
start_sound = 'sound/machines/kitchen/microwave/microwave-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/microwave/microwave-mid1.ogg'=10, 'sound/machines/kitchen/microwave/microwave-mid2.ogg'=1)
|
||||
mid_length = 10
|
||||
end_sound = 'sound/machines/kitchen/microwave/microwave-end.ogg'
|
||||
volume = 90
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/oven
|
||||
start_sound = 'sound/machines/kitchen/oven/oven-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/oven/oven-mid1.ogg'=10)
|
||||
mid_length = 40
|
||||
end_sound = 'sound/machines/kitchen/oven/oven-stop.ogg'
|
||||
volume = 50
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/grill
|
||||
start_sound = 'sound/machines/kitchen/grill/grill-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/grill/grill-mid1.ogg'=10)
|
||||
mid_length = 40
|
||||
end_sound = 'sound/machines/kitchen/grill/grill-stop.ogg'
|
||||
volume = 50
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/mixer
|
||||
start_sound = 'sound/machines/kitchen/mixer/mixer-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/mixer/mixer-mid1.ogg'=10)
|
||||
mid_length = 10
|
||||
end_sound = 'sound/machines/kitchen/mixer/mixer-stop.ogg'
|
||||
volume = 50
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/cerealmaker
|
||||
start_sound = 'sound/machines/kitchen/cerealmaker/cerealmaker-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/cerealmaker/cerealmaker-mid1.ogg'=10)
|
||||
mid_length = 60
|
||||
end_sound = 'sound/machines/kitchen/cerealmaker/cerealmaker-stop.ogg'
|
||||
volume = 50
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/candymaker
|
||||
start_sound = 'sound/machines/kitchen/candymaker/candymaker-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/candymaker/candymaker-mid1.ogg'=10)
|
||||
mid_length = 40
|
||||
end_sound = 'sound/machines/kitchen/candymaker/candymaker-stop.ogg'
|
||||
volume = 20
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/datum/looping_sound/air_pump
|
||||
start_sound = 'sound/machines/air_pump/airpumpstart.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/air_pump/airpumpidle.ogg' = 1)
|
||||
mid_length = 70
|
||||
end_sound = 'sound/machines/air_pump/airpumpshutdown.ogg'
|
||||
volume = 15
|
||||
pref_check = /datum/client_preference/air_pump_noise
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/vehicle_engine
|
||||
start_sound = 'sound/machines/vehicle/engine_start.ogg'
|
||||
start_length = 2
|
||||
mid_sounds = list('sound/machines/vehicle/engine_mid.ogg'=1)
|
||||
mid_length = 6
|
||||
end_sound = 'sound/machines/vehicle/engine_end.ogg'
|
||||
volume = 20
|
||||
/datum/looping_sound/showering
|
||||
start_sound = 'sound/machines/shower/shower_start.ogg'
|
||||
start_length = 2
|
||||
mid_sounds = list('sound/machines/shower/shower_mid1.ogg'=1,'sound/machines/shower/shower_mid2.ogg'=1,'sound/machines/shower/shower_mid3.ogg'=1)
|
||||
mid_length = 10
|
||||
end_sound = 'sound/machines/shower/shower_end.ogg'
|
||||
volume = 15
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/supermatter
|
||||
mid_sounds = list('sound/machines/sm/loops/calm.ogg'=1)
|
||||
mid_length = 60
|
||||
volume = 40
|
||||
extra_range = 10
|
||||
pref_check = /datum/client_preference/supermatter_hum
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/generator
|
||||
start_sound = 'sound/machines/generator/generator_start.ogg'
|
||||
start_length = 4
|
||||
mid_sounds = list('sound/machines/generator/generator_mid1.ogg'=1, 'sound/machines/generator/generator_mid2.ogg'=1, 'sound/machines/generator/generator_mid3.ogg'=1)
|
||||
mid_length = 4
|
||||
end_sound = 'sound/machines/generator/generator_end.ogg'
|
||||
volume = 40
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/datum/looping_sound/deep_fryer
|
||||
start_sound = 'sound/machines/kitchen/fryer/deep_fryer_immerse.ogg' //my immersions
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/kitchen/fryer/deep_fryer_2.ogg' = 1)
|
||||
mid_length = 2
|
||||
end_sound = 'sound/machines/kitchen/fryer/deep_fryer_emerge.ogg'
|
||||
volume = 15
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/microwave
|
||||
start_sound = 'sound/machines/kitchen/microwave/microwave-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/microwave/microwave-mid1.ogg'=10, 'sound/machines/kitchen/microwave/microwave-mid2.ogg'=1)
|
||||
mid_length = 10
|
||||
end_sound = 'sound/machines/kitchen/microwave/microwave-end.ogg'
|
||||
volume = 90
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/oven
|
||||
start_sound = 'sound/machines/kitchen/oven/oven-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/oven/oven-mid1.ogg'=10)
|
||||
mid_length = 40
|
||||
end_sound = 'sound/machines/kitchen/oven/oven-stop.ogg'
|
||||
volume = 50
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/grill
|
||||
start_sound = 'sound/machines/kitchen/grill/grill-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/grill/grill-mid1.ogg'=10)
|
||||
mid_length = 40
|
||||
end_sound = 'sound/machines/kitchen/grill/grill-stop.ogg'
|
||||
volume = 50
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/mixer
|
||||
start_sound = 'sound/machines/kitchen/mixer/mixer-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/mixer/mixer-mid1.ogg'=10)
|
||||
mid_length = 10
|
||||
end_sound = 'sound/machines/kitchen/mixer/mixer-stop.ogg'
|
||||
volume = 50
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/cerealmaker
|
||||
start_sound = 'sound/machines/kitchen/cerealmaker/cerealmaker-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/cerealmaker/cerealmaker-mid1.ogg'=10)
|
||||
mid_length = 60
|
||||
end_sound = 'sound/machines/kitchen/cerealmaker/cerealmaker-stop.ogg'
|
||||
volume = 50
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/candymaker
|
||||
start_sound = 'sound/machines/kitchen/candymaker/candymaker-start.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/kitchen/candymaker/candymaker-mid1.ogg'=10)
|
||||
mid_length = 40
|
||||
end_sound = 'sound/machines/kitchen/candymaker/candymaker-stop.ogg'
|
||||
volume = 20
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/datum/looping_sound/air_pump
|
||||
start_sound = 'sound/machines/air_pump/airpumpstart.ogg'
|
||||
start_length = 10
|
||||
mid_sounds = list('sound/machines/air_pump/airpumpidle.ogg' = 1)
|
||||
mid_length = 70
|
||||
end_sound = 'sound/machines/air_pump/airpumpshutdown.ogg'
|
||||
volume = 15
|
||||
pref_check = /datum/client_preference/air_pump_noise
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/looping_sound/vehicle_engine
|
||||
start_sound = 'sound/machines/vehicle/engine_start.ogg'
|
||||
start_length = 2
|
||||
mid_sounds = list('sound/machines/vehicle/engine_mid.ogg'=1)
|
||||
mid_length = 6
|
||||
end_sound = 'sound/machines/vehicle/engine_end.ogg'
|
||||
volume = 20
|
||||
|
||||
@@ -1,175 +1,175 @@
|
||||
// These looping sounds work off of a sequence of things (usually letters or numbers) given to them.
|
||||
|
||||
// Base sequencer type.
|
||||
/datum/looping_sound/sequence
|
||||
var/sequence = "The quick brown fox jumps over the lazy dog" // The string to iterate over.
|
||||
var/position = 1 // Where we are inside the sequence. IE the index we're on for the above.
|
||||
var/loop_sequence = TRUE // If it should loop the entire sequence upon reaching the end. Otherwise stop() is called.
|
||||
var/repeat_sequnce_delay = 2 SECONDS // How long to wait when reaching the end, if the above var is true, in deciseconds.
|
||||
var/next_iteration_delay = 0
|
||||
|
||||
/datum/looping_sound/sequence/vv_edit_var(var_name, var_value)
|
||||
if(var_name == "sequence")
|
||||
set_new_sequence(var_value)
|
||||
return ..()
|
||||
|
||||
/datum/looping_sound/sequence/proc/iterate_on_sequence()
|
||||
var/data = get_data_from_position()
|
||||
next_iteration_delay = process_data(data)
|
||||
increment_position()
|
||||
|
||||
/datum/looping_sound/sequence/proc/get_data_from_position()
|
||||
return sequence[position]
|
||||
|
||||
// Override to do something based on the input.
|
||||
/datum/looping_sound/sequence/proc/process_data(input)
|
||||
return
|
||||
|
||||
// Changes the sequence, and sets the position back to the start.
|
||||
/datum/looping_sound/sequence/proc/set_new_sequence(new_sequence)
|
||||
sequence = new_sequence
|
||||
reset_position()
|
||||
|
||||
// Called to advance the position, and handle reaching the end if so.
|
||||
/datum/looping_sound/sequence/proc/increment_position()
|
||||
position++
|
||||
if(position > get_max_position())
|
||||
reached_end_of_sequence()
|
||||
|
||||
/datum/looping_sound/sequence/proc/get_max_position()
|
||||
return length(sequence)
|
||||
|
||||
/datum/looping_sound/sequence/proc/reset_position()
|
||||
position = 1
|
||||
|
||||
// Called when the sequence is finished being iterated over.
|
||||
// If looping is on, the position will be reset, otherwise processing will stop.
|
||||
/datum/looping_sound/sequence/proc/reached_end_of_sequence()
|
||||
if(loop_sequence)
|
||||
next_iteration_delay += repeat_sequnce_delay
|
||||
reset_position()
|
||||
else
|
||||
stop()
|
||||
|
||||
/datum/looping_sound/sequence/sound_loop(starttime)
|
||||
iterate_on_sequence()
|
||||
|
||||
timerid = addtimer(CALLBACK(src, PROC_REF(sound_loop), world.time), next_iteration_delay, TIMER_STOPPABLE)
|
||||
|
||||
#define MORSE_DOT "*" // Yes this is an asterisk but its easier to see on a computer compared to a period.
|
||||
#define MORSE_DASH "-"
|
||||
#define MORSE_BASE_DELAY 1 // If you change this you will also need to change [dot|dash]_soundfile variables.
|
||||
|
||||
// This implements an automatic conversion of text (the sequence) into audible morse code.
|
||||
// This can be useful for flavor purposes. For 'real' usage its suggested to also display the sequence in text form, for the benefit of those without sound.
|
||||
/datum/looping_sound/sequence/morse
|
||||
// This is just to pass validation in the base type.
|
||||
mid_sounds = list('sound/effects/tones/440_sine_01.ogg')
|
||||
mid_length = 1
|
||||
opacity_check = TRUE // So we don't have to constantly hear it when out of sight.
|
||||
|
||||
// Dots.
|
||||
// In Morse Code, the dot's length is one unit.
|
||||
var/dot_soundfile = 'sound/effects/tones/440_sine_01.ogg' // The sound file to play for a 'dot'.
|
||||
var/dot_delay = MORSE_BASE_DELAY // How long the sound above plays for, in deciseconds.
|
||||
|
||||
// Dashes.
|
||||
// In Morse Code, a dash's length is equal to three units (or three dots).
|
||||
var/dash_soundfile = 'sound/effects/tones/440_sine_03.ogg' // The sound file to play for a 'dash'.
|
||||
var/dash_delay = MORSE_BASE_DELAY * 3 // Same as the dot delay, except for the dash sound.
|
||||
|
||||
// Spaces.
|
||||
// In Morse Code, a space's length is equal to one unit (or one dot).
|
||||
var/spaces_between_sounds = MORSE_BASE_DELAY // How many spaces are between parts of the same letter.
|
||||
var/spaces_between_letters = MORSE_BASE_DELAY * 3 // How many spaces are between different letters in the same word.
|
||||
var/spaces_between_words = MORSE_BASE_DELAY * 7 // How many spaces are between different words.
|
||||
|
||||
// Morse Alphabet.
|
||||
// Note that it is case-insensative. 'A' and 'a' will make the same sounds.
|
||||
// Unfortunately there isn't a nice way to implement procedure signs w/o the space inbetween the letters.
|
||||
// Also some of the punctuation isn't super offical/widespread in real life but its the future so *shrug.
|
||||
var/static/list/morse_alphabet = list(
|
||||
"A" = list("*", "-"),
|
||||
"B" = list("-", "*", "*", "*"),
|
||||
"C" = list("-", "*", "-", "*"),
|
||||
"D" = list("-", "*", "*"),
|
||||
"E" = list("*"),
|
||||
"F" = list("*", "*", "-", "*"),
|
||||
"G" = list("-", "-", "*"),
|
||||
"H" = list("*", "*", "*", "*"),
|
||||
"I" = list("*", "*"),
|
||||
"J" = list("*", "-", "-", "-"),
|
||||
"K" = list("-", "*", "-"),
|
||||
"L" = list("*", "-", "*", "*"),
|
||||
"M" = list("*", "*"),
|
||||
"N" = list("-", "*"),
|
||||
"O" = list("-", "-", "-"),
|
||||
"P" = list("*", "-", "-", "*"),
|
||||
"Q" = list("-", "-", "*", "-"),
|
||||
"R" = list("*", "-", "*"),
|
||||
"S" = list("*", "*", "*"),
|
||||
"T" = list("-"),
|
||||
"U" = list("*", "*", "-"),
|
||||
"V" = list("*", "*", "*", "-"),
|
||||
"W" = list("*", "-", "-"),
|
||||
"X" = list("-", "*", "*", "-"),
|
||||
"Y" = list("-", "*", "-", "-"),
|
||||
"Z" = list("-", "-", "*", "*"),
|
||||
|
||||
"1" = list("*", "-", "-", "-", "-"),
|
||||
"2" = list("*", "*", "-", "-", "-"),
|
||||
"3" = list("*", "*", "*", "-", "-"),
|
||||
"4" = list("*", "*", "*", "*", "-"),
|
||||
"5" = list("*", "*", "*", "*", "*"),
|
||||
"6" = list("-", "*", "*", "*", "*"),
|
||||
"7" = list("-", "-", "*", "*", "*"),
|
||||
"8" = list("-", "-", "-", "*", "*"),
|
||||
"9" = list("-", "-", "-", "-", "*"),
|
||||
"0" = list("-", "-", "-", "-", "-"),
|
||||
|
||||
"." = list("*", "-", "*", "-", "*", "-"),
|
||||
"," = list("-", "-", "*", "*", "-", "-"),
|
||||
"?" = list("*", "*", "-", "-", "*", "*"),
|
||||
"'" = list("*", "-", "-", "-", "-", "*"),
|
||||
"!" = list("-", "*", "-", "*", "-", "-"),
|
||||
"/" = list("-", "*", "*", "-", "*"),
|
||||
"(" = list("-", "*", "-", "-", "*"),
|
||||
")" = list("-", "*", "-", "-", "*", "-"),
|
||||
"&" = list("*", "-", "*", "*", "*"),
|
||||
":" = list("-", "-", "-", "*", "*", "*"),
|
||||
";" = list("-", "*", "-", "*", "-", "*"),
|
||||
"=" = list("-", "*", "*", "*", "-"),
|
||||
"+" = list("*", "-", "*", "-", "*"),
|
||||
"-" = list("-", "*", "*", "*", "*", "-"),
|
||||
"_" = list("*", "*", "-", "-", "*", "-"),
|
||||
"\""= list("*", "-", "*", "*", "-", "*"),
|
||||
"$" = list("*", "*", "*", "-", "*", "*", "-"),
|
||||
"@" = list("*", "-", "-", "*", "-", "*"),
|
||||
)
|
||||
|
||||
|
||||
/datum/looping_sound/sequence/morse/process_data(letter)
|
||||
letter = uppertext(letter) // Make it case-insensative.
|
||||
|
||||
// If it's whitespace, treat it as a (Morse) space.
|
||||
if(letter == " ")
|
||||
return spaces_between_words
|
||||
|
||||
if(!(letter in morse_alphabet))
|
||||
CRASH("Encountered invalid character in Morse sequence \"[letter]\".")
|
||||
|
||||
// So I heard you like sequences...
|
||||
// Play a sequence of sounds while inside the current iteration of the outer sequence.
|
||||
var/list/instructions = morse_alphabet[letter]
|
||||
for(var/sound in instructions)
|
||||
if(sound == MORSE_DOT)
|
||||
play(dot_soundfile)
|
||||
sleep(dot_delay)
|
||||
else // It's a dash otherwise.
|
||||
play(dash_soundfile)
|
||||
sleep(dash_delay)
|
||||
sleep(spaces_between_sounds)
|
||||
return spaces_between_letters
|
||||
|
||||
#undef MORSE_DOT
|
||||
#undef MORSE_DASH
|
||||
// These looping sounds work off of a sequence of things (usually letters or numbers) given to them.
|
||||
|
||||
// Base sequencer type.
|
||||
/datum/looping_sound/sequence
|
||||
var/sequence = "The quick brown fox jumps over the lazy dog" // The string to iterate over.
|
||||
var/position = 1 // Where we are inside the sequence. IE the index we're on for the above.
|
||||
var/loop_sequence = TRUE // If it should loop the entire sequence upon reaching the end. Otherwise stop() is called.
|
||||
var/repeat_sequnce_delay = 2 SECONDS // How long to wait when reaching the end, if the above var is true, in deciseconds.
|
||||
var/next_iteration_delay = 0
|
||||
|
||||
/datum/looping_sound/sequence/vv_edit_var(var_name, var_value)
|
||||
if(var_name == "sequence")
|
||||
set_new_sequence(var_value)
|
||||
return ..()
|
||||
|
||||
/datum/looping_sound/sequence/proc/iterate_on_sequence()
|
||||
var/data = get_data_from_position()
|
||||
next_iteration_delay = process_data(data)
|
||||
increment_position()
|
||||
|
||||
/datum/looping_sound/sequence/proc/get_data_from_position()
|
||||
return sequence[position]
|
||||
|
||||
// Override to do something based on the input.
|
||||
/datum/looping_sound/sequence/proc/process_data(input)
|
||||
return
|
||||
|
||||
// Changes the sequence, and sets the position back to the start.
|
||||
/datum/looping_sound/sequence/proc/set_new_sequence(new_sequence)
|
||||
sequence = new_sequence
|
||||
reset_position()
|
||||
|
||||
// Called to advance the position, and handle reaching the end if so.
|
||||
/datum/looping_sound/sequence/proc/increment_position()
|
||||
position++
|
||||
if(position > get_max_position())
|
||||
reached_end_of_sequence()
|
||||
|
||||
/datum/looping_sound/sequence/proc/get_max_position()
|
||||
return length(sequence)
|
||||
|
||||
/datum/looping_sound/sequence/proc/reset_position()
|
||||
position = 1
|
||||
|
||||
// Called when the sequence is finished being iterated over.
|
||||
// If looping is on, the position will be reset, otherwise processing will stop.
|
||||
/datum/looping_sound/sequence/proc/reached_end_of_sequence()
|
||||
if(loop_sequence)
|
||||
next_iteration_delay += repeat_sequnce_delay
|
||||
reset_position()
|
||||
else
|
||||
stop()
|
||||
|
||||
/datum/looping_sound/sequence/sound_loop(starttime)
|
||||
iterate_on_sequence()
|
||||
|
||||
timerid = addtimer(CALLBACK(src, PROC_REF(sound_loop), world.time), next_iteration_delay, TIMER_STOPPABLE)
|
||||
|
||||
#define MORSE_DOT "*" // Yes this is an asterisk but its easier to see on a computer compared to a period.
|
||||
#define MORSE_DASH "-"
|
||||
#define MORSE_BASE_DELAY 1 // If you change this you will also need to change [dot|dash]_soundfile variables.
|
||||
|
||||
// This implements an automatic conversion of text (the sequence) into audible morse code.
|
||||
// This can be useful for flavor purposes. For 'real' usage its suggested to also display the sequence in text form, for the benefit of those without sound.
|
||||
/datum/looping_sound/sequence/morse
|
||||
// This is just to pass validation in the base type.
|
||||
mid_sounds = list('sound/effects/tones/440_sine_01.ogg')
|
||||
mid_length = 1
|
||||
opacity_check = TRUE // So we don't have to constantly hear it when out of sight.
|
||||
|
||||
// Dots.
|
||||
// In Morse Code, the dot's length is one unit.
|
||||
var/dot_soundfile = 'sound/effects/tones/440_sine_01.ogg' // The sound file to play for a 'dot'.
|
||||
var/dot_delay = MORSE_BASE_DELAY // How long the sound above plays for, in deciseconds.
|
||||
|
||||
// Dashes.
|
||||
// In Morse Code, a dash's length is equal to three units (or three dots).
|
||||
var/dash_soundfile = 'sound/effects/tones/440_sine_03.ogg' // The sound file to play for a 'dash'.
|
||||
var/dash_delay = MORSE_BASE_DELAY * 3 // Same as the dot delay, except for the dash sound.
|
||||
|
||||
// Spaces.
|
||||
// In Morse Code, a space's length is equal to one unit (or one dot).
|
||||
var/spaces_between_sounds = MORSE_BASE_DELAY // How many spaces are between parts of the same letter.
|
||||
var/spaces_between_letters = MORSE_BASE_DELAY * 3 // How many spaces are between different letters in the same word.
|
||||
var/spaces_between_words = MORSE_BASE_DELAY * 7 // How many spaces are between different words.
|
||||
|
||||
// Morse Alphabet.
|
||||
// Note that it is case-insensative. 'A' and 'a' will make the same sounds.
|
||||
// Unfortunately there isn't a nice way to implement procedure signs w/o the space inbetween the letters.
|
||||
// Also some of the punctuation isn't super offical/widespread in real life but its the future so *shrug.
|
||||
var/static/list/morse_alphabet = list(
|
||||
"A" = list("*", "-"),
|
||||
"B" = list("-", "*", "*", "*"),
|
||||
"C" = list("-", "*", "-", "*"),
|
||||
"D" = list("-", "*", "*"),
|
||||
"E" = list("*"),
|
||||
"F" = list("*", "*", "-", "*"),
|
||||
"G" = list("-", "-", "*"),
|
||||
"H" = list("*", "*", "*", "*"),
|
||||
"I" = list("*", "*"),
|
||||
"J" = list("*", "-", "-", "-"),
|
||||
"K" = list("-", "*", "-"),
|
||||
"L" = list("*", "-", "*", "*"),
|
||||
"M" = list("*", "*"),
|
||||
"N" = list("-", "*"),
|
||||
"O" = list("-", "-", "-"),
|
||||
"P" = list("*", "-", "-", "*"),
|
||||
"Q" = list("-", "-", "*", "-"),
|
||||
"R" = list("*", "-", "*"),
|
||||
"S" = list("*", "*", "*"),
|
||||
"T" = list("-"),
|
||||
"U" = list("*", "*", "-"),
|
||||
"V" = list("*", "*", "*", "-"),
|
||||
"W" = list("*", "-", "-"),
|
||||
"X" = list("-", "*", "*", "-"),
|
||||
"Y" = list("-", "*", "-", "-"),
|
||||
"Z" = list("-", "-", "*", "*"),
|
||||
|
||||
"1" = list("*", "-", "-", "-", "-"),
|
||||
"2" = list("*", "*", "-", "-", "-"),
|
||||
"3" = list("*", "*", "*", "-", "-"),
|
||||
"4" = list("*", "*", "*", "*", "-"),
|
||||
"5" = list("*", "*", "*", "*", "*"),
|
||||
"6" = list("-", "*", "*", "*", "*"),
|
||||
"7" = list("-", "-", "*", "*", "*"),
|
||||
"8" = list("-", "-", "-", "*", "*"),
|
||||
"9" = list("-", "-", "-", "-", "*"),
|
||||
"0" = list("-", "-", "-", "-", "-"),
|
||||
|
||||
"." = list("*", "-", "*", "-", "*", "-"),
|
||||
"," = list("-", "-", "*", "*", "-", "-"),
|
||||
"?" = list("*", "*", "-", "-", "*", "*"),
|
||||
"'" = list("*", "-", "-", "-", "-", "*"),
|
||||
"!" = list("-", "*", "-", "*", "-", "-"),
|
||||
"/" = list("-", "*", "*", "-", "*"),
|
||||
"(" = list("-", "*", "-", "-", "*"),
|
||||
")" = list("-", "*", "-", "-", "*", "-"),
|
||||
"&" = list("*", "-", "*", "*", "*"),
|
||||
":" = list("-", "-", "-", "*", "*", "*"),
|
||||
";" = list("-", "*", "-", "*", "-", "*"),
|
||||
"=" = list("-", "*", "*", "*", "-"),
|
||||
"+" = list("*", "-", "*", "-", "*"),
|
||||
"-" = list("-", "*", "*", "*", "*", "-"),
|
||||
"_" = list("*", "*", "-", "-", "*", "-"),
|
||||
"\""= list("*", "-", "*", "*", "-", "*"),
|
||||
"$" = list("*", "*", "*", "-", "*", "*", "-"),
|
||||
"@" = list("*", "-", "-", "*", "-", "*"),
|
||||
)
|
||||
|
||||
|
||||
/datum/looping_sound/sequence/morse/process_data(letter)
|
||||
letter = uppertext(letter) // Make it case-insensative.
|
||||
|
||||
// If it's whitespace, treat it as a (Morse) space.
|
||||
if(letter == " ")
|
||||
return spaces_between_words
|
||||
|
||||
if(!(letter in morse_alphabet))
|
||||
CRASH("Encountered invalid character in Morse sequence \"[letter]\".")
|
||||
|
||||
// So I heard you like sequences...
|
||||
// Play a sequence of sounds while inside the current iteration of the outer sequence.
|
||||
var/list/instructions = morse_alphabet[letter]
|
||||
for(var/sound in instructions)
|
||||
if(sound == MORSE_DOT)
|
||||
play(dot_soundfile)
|
||||
sleep(dot_delay)
|
||||
else // It's a dash otherwise.
|
||||
play(dash_soundfile)
|
||||
sleep(dash_delay)
|
||||
sleep(spaces_between_sounds)
|
||||
return spaces_between_letters
|
||||
|
||||
#undef MORSE_DOT
|
||||
#undef MORSE_DASH
|
||||
|
||||
@@ -1,98 +1,98 @@
|
||||
/datum/looping_sound/weather
|
||||
pref_check = /datum/client_preference/weather_sounds
|
||||
|
||||
/datum/looping_sound/weather/outside_blizzard
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/snowstorm/outside/active_mid1.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/outside/active_mid1.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/outside/active_mid1.ogg' = 1
|
||||
)
|
||||
mid_length = 8 SECONDS
|
||||
start_sound = 'sound/effects/weather/snowstorm/outside/active_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/snowstorm/outside/active_end.ogg'
|
||||
volume = 40
|
||||
|
||||
/datum/looping_sound/weather/inside_blizzard
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/snowstorm/inside/active_mid1.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/inside/active_mid2.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/inside/active_mid3.ogg' = 1
|
||||
)
|
||||
mid_length = 8 SECONDS
|
||||
start_sound = 'sound/effects/weather/snowstorm/inside/active_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/snowstorm/inside/active_end.ogg'
|
||||
volume = 20
|
||||
|
||||
/datum/looping_sound/weather/outside_snow
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/snowstorm/outside/weak_mid1.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/outside/weak_mid2.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/outside/weak_mid3.ogg' = 1
|
||||
)
|
||||
mid_length = 8 SECONDS
|
||||
start_sound = 'sound/effects/weather/snowstorm/outside/weak_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/snowstorm/outside/weak_end.ogg'
|
||||
volume = 20
|
||||
|
||||
/datum/looping_sound/weather/inside_snow
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/snowstorm/inside/weak_mid1.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/inside/weak_mid2.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/inside/weak_mid3.ogg' = 1
|
||||
)
|
||||
mid_length = 8 SECONDS
|
||||
start_sound = 'sound/effects/weather/snowstorm/inside/weak_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/snowstorm/inside/weak_end.ogg'
|
||||
volume = 10
|
||||
|
||||
/datum/looping_sound/weather/wind
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/wind/wind_2_1.ogg' = 1,
|
||||
'sound/effects/weather/wind/wind_2_2.ogg' = 1,
|
||||
'sound/effects/weather/wind/wind_3_1.ogg' = 1,
|
||||
'sound/effects/weather/wind/wind_4_1.ogg' = 1,
|
||||
'sound/effects/weather/wind/wind_4_2.ogg' = 1,
|
||||
'sound/effects/weather/wind/wind_5_1.ogg' = 1
|
||||
)
|
||||
mid_length = 10 SECONDS // The lengths for the files vary, but the longest is ten seconds, so this will make it sound like intermittent wind.
|
||||
volume = 45
|
||||
|
||||
// Don't have special sounds so we just make it quieter indoors.
|
||||
/datum/looping_sound/weather/wind/indoors
|
||||
volume = 25
|
||||
|
||||
/datum/looping_sound/weather/wind/gentle
|
||||
volume = 15
|
||||
|
||||
/datum/looping_sound/weather/wind/gentle/indoors
|
||||
volume = 5
|
||||
|
||||
/datum/looping_sound/weather/rain
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/acidrain_mid.ogg' = 1
|
||||
)
|
||||
mid_length = 15 SECONDS
|
||||
start_sound = 'sound/effects/weather/acidrain_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/acidrain_end.ogg'
|
||||
volume = 20
|
||||
|
||||
/datum/looping_sound/weather/rain/heavy
|
||||
volume = 40
|
||||
|
||||
/datum/looping_sound/weather/rain/indoors
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/indoorrain_mid.ogg' = 1
|
||||
)
|
||||
mid_length = 15 SECONDS
|
||||
start_sound = 'sound/effects/weather/indoorrain_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/indoorrain_end.ogg'
|
||||
volume = 20 //Sound is already quieter in file
|
||||
|
||||
/datum/looping_sound/weather/rain/indoors/heavy
|
||||
/datum/looping_sound/weather
|
||||
pref_check = /datum/client_preference/weather_sounds
|
||||
|
||||
/datum/looping_sound/weather/outside_blizzard
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/snowstorm/outside/active_mid1.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/outside/active_mid1.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/outside/active_mid1.ogg' = 1
|
||||
)
|
||||
mid_length = 8 SECONDS
|
||||
start_sound = 'sound/effects/weather/snowstorm/outside/active_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/snowstorm/outside/active_end.ogg'
|
||||
volume = 40
|
||||
|
||||
/datum/looping_sound/weather/inside_blizzard
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/snowstorm/inside/active_mid1.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/inside/active_mid2.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/inside/active_mid3.ogg' = 1
|
||||
)
|
||||
mid_length = 8 SECONDS
|
||||
start_sound = 'sound/effects/weather/snowstorm/inside/active_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/snowstorm/inside/active_end.ogg'
|
||||
volume = 20
|
||||
|
||||
/datum/looping_sound/weather/outside_snow
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/snowstorm/outside/weak_mid1.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/outside/weak_mid2.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/outside/weak_mid3.ogg' = 1
|
||||
)
|
||||
mid_length = 8 SECONDS
|
||||
start_sound = 'sound/effects/weather/snowstorm/outside/weak_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/snowstorm/outside/weak_end.ogg'
|
||||
volume = 20
|
||||
|
||||
/datum/looping_sound/weather/inside_snow
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/snowstorm/inside/weak_mid1.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/inside/weak_mid2.ogg' = 1,
|
||||
'sound/effects/weather/snowstorm/inside/weak_mid3.ogg' = 1
|
||||
)
|
||||
mid_length = 8 SECONDS
|
||||
start_sound = 'sound/effects/weather/snowstorm/inside/weak_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/snowstorm/inside/weak_end.ogg'
|
||||
volume = 10
|
||||
|
||||
/datum/looping_sound/weather/wind
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/wind/wind_2_1.ogg' = 1,
|
||||
'sound/effects/weather/wind/wind_2_2.ogg' = 1,
|
||||
'sound/effects/weather/wind/wind_3_1.ogg' = 1,
|
||||
'sound/effects/weather/wind/wind_4_1.ogg' = 1,
|
||||
'sound/effects/weather/wind/wind_4_2.ogg' = 1,
|
||||
'sound/effects/weather/wind/wind_5_1.ogg' = 1
|
||||
)
|
||||
mid_length = 10 SECONDS // The lengths for the files vary, but the longest is ten seconds, so this will make it sound like intermittent wind.
|
||||
volume = 45
|
||||
|
||||
// Don't have special sounds so we just make it quieter indoors.
|
||||
/datum/looping_sound/weather/wind/indoors
|
||||
volume = 25
|
||||
|
||||
/datum/looping_sound/weather/wind/gentle
|
||||
volume = 15
|
||||
|
||||
/datum/looping_sound/weather/wind/gentle/indoors
|
||||
volume = 5
|
||||
|
||||
/datum/looping_sound/weather/rain
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/acidrain_mid.ogg' = 1
|
||||
)
|
||||
mid_length = 15 SECONDS
|
||||
start_sound = 'sound/effects/weather/acidrain_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/acidrain_end.ogg'
|
||||
volume = 20
|
||||
|
||||
/datum/looping_sound/weather/rain/heavy
|
||||
volume = 40
|
||||
|
||||
/datum/looping_sound/weather/rain/indoors
|
||||
mid_sounds = list(
|
||||
'sound/effects/weather/indoorrain_mid.ogg' = 1
|
||||
)
|
||||
mid_length = 15 SECONDS
|
||||
start_sound = 'sound/effects/weather/indoorrain_start.ogg'
|
||||
start_length = 13 SECONDS
|
||||
end_sound = 'sound/effects/weather/indoorrain_end.ogg'
|
||||
volume = 20 //Sound is already quieter in file
|
||||
|
||||
/datum/looping_sound/weather/rain/indoors/heavy
|
||||
volume = 40
|
||||
@@ -1,52 +1,52 @@
|
||||
GLOBAL_VAR(managed_browser_id_ticker)
|
||||
|
||||
// This holds information on managing a /datum/browser object.
|
||||
// Managing can include things like persisting the state of specific information inside of this object, receiving Topic() calls, or deleting itself when the window is closed.
|
||||
// This is useful for browser windows to be able to stand 'on their own' instead of being tied to something in the game world, like an object or mob.
|
||||
/datum/managed_browser
|
||||
var/client/my_client = null
|
||||
var/browser_id = null
|
||||
var/base_browser_id = null
|
||||
|
||||
var/title = null
|
||||
var/size_x = 200
|
||||
var/size_y = 400
|
||||
|
||||
var/display_when_created = TRUE
|
||||
|
||||
/datum/managed_browser/New(client/new_client)
|
||||
if(!new_client)
|
||||
stack_trace("Managed browser object was not given a client.")
|
||||
return
|
||||
if(!base_browser_id)
|
||||
stack_trace("Managed browser object does not have a base browser id defined in its type.")
|
||||
return
|
||||
|
||||
my_client = new_client
|
||||
browser_id = "[base_browser_id]-[GLOB.managed_browser_id_ticker++]"
|
||||
|
||||
if(display_when_created)
|
||||
display()
|
||||
|
||||
/datum/managed_browser/Destroy()
|
||||
my_client = null
|
||||
return ..()
|
||||
|
||||
// Override if you want to have the browser title change conditionally.
|
||||
// Otherwise it's easier to just change the title variable directly.
|
||||
/datum/managed_browser/proc/get_title()
|
||||
return title
|
||||
|
||||
// Override to display the html information.
|
||||
// It is suggested to build it with a list, and use list.Join() at the end.
|
||||
// This helps prevent excessive concatination, which helps preserves BYOND's string tree from becoming a laggy mess.
|
||||
/datum/managed_browser/proc/get_html()
|
||||
return
|
||||
|
||||
/datum/managed_browser/proc/display()
|
||||
interact(get_html(), get_title(), my_client)
|
||||
|
||||
/datum/managed_browser/proc/interact(html, title, client/C)
|
||||
var/datum/browser/popup = new(C.mob, browser_id, title, size_x, size_y, src)
|
||||
popup.set_content(html)
|
||||
GLOBAL_VAR(managed_browser_id_ticker)
|
||||
|
||||
// This holds information on managing a /datum/browser object.
|
||||
// Managing can include things like persisting the state of specific information inside of this object, receiving Topic() calls, or deleting itself when the window is closed.
|
||||
// This is useful for browser windows to be able to stand 'on their own' instead of being tied to something in the game world, like an object or mob.
|
||||
/datum/managed_browser
|
||||
var/client/my_client = null
|
||||
var/browser_id = null
|
||||
var/base_browser_id = null
|
||||
|
||||
var/title = null
|
||||
var/size_x = 200
|
||||
var/size_y = 400
|
||||
|
||||
var/display_when_created = TRUE
|
||||
|
||||
/datum/managed_browser/New(client/new_client)
|
||||
if(!new_client)
|
||||
stack_trace("Managed browser object was not given a client.")
|
||||
return
|
||||
if(!base_browser_id)
|
||||
stack_trace("Managed browser object does not have a base browser id defined in its type.")
|
||||
return
|
||||
|
||||
my_client = new_client
|
||||
browser_id = "[base_browser_id]-[GLOB.managed_browser_id_ticker++]"
|
||||
|
||||
if(display_when_created)
|
||||
display()
|
||||
|
||||
/datum/managed_browser/Destroy()
|
||||
my_client = null
|
||||
return ..()
|
||||
|
||||
// Override if you want to have the browser title change conditionally.
|
||||
// Otherwise it's easier to just change the title variable directly.
|
||||
/datum/managed_browser/proc/get_title()
|
||||
return title
|
||||
|
||||
// Override to display the html information.
|
||||
// It is suggested to build it with a list, and use list.Join() at the end.
|
||||
// This helps prevent excessive concatination, which helps preserves BYOND's string tree from becoming a laggy mess.
|
||||
/datum/managed_browser/proc/get_html()
|
||||
return
|
||||
|
||||
/datum/managed_browser/proc/display()
|
||||
interact(get_html(), get_title(), my_client)
|
||||
|
||||
/datum/managed_browser/proc/interact(html, title, client/C)
|
||||
var/datum/browser/popup = new(C.mob, browser_id, title, size_x, size_y, src)
|
||||
popup.set_content(html)
|
||||
popup.open()
|
||||
@@ -1,147 +1,147 @@
|
||||
/client
|
||||
var/datum/managed_browser/feedback_form/feedback_form = null
|
||||
|
||||
/client/can_vv_get(var_name)
|
||||
return var_name != NAMEOF(src, feedback_form) // No snooping.
|
||||
|
||||
GENERAL_PROTECT_DATUM(/datum/managed_browser/feedback_form)
|
||||
|
||||
// A fairly simple object to hold information about a player's feedback as it's being written.
|
||||
// Having this be it's own object instead of being baked into /mob/new_player allows for it to be used
|
||||
// from other places than just the lobby, and makes it a lot harder for people with dev powers to be naughty with it using VV/proccall.
|
||||
/datum/managed_browser/feedback_form
|
||||
base_browser_id = "feedback_form"
|
||||
title = "Server Feedback"
|
||||
size_x = 480
|
||||
size_y = 520
|
||||
var/feedback_topic = null
|
||||
var/feedback_body = null
|
||||
var/feedback_hide_author = FALSE
|
||||
|
||||
/datum/managed_browser/feedback_form/New(client/new_client)
|
||||
feedback_topic = config.sqlite_feedback_topics[1]
|
||||
..(new_client)
|
||||
|
||||
/datum/managed_browser/feedback_form/Destroy()
|
||||
if(my_client)
|
||||
my_client.feedback_form = null
|
||||
return ..()
|
||||
|
||||
// Privacy option is allowed if both the config allows it, and the pepper file exists and isn't blank.
|
||||
/datum/managed_browser/feedback_form/proc/can_be_private()
|
||||
return config.sqlite_feedback_privacy && SSsqlite.get_feedback_pepper()
|
||||
|
||||
/datum/managed_browser/feedback_form/display()
|
||||
if(!my_client)
|
||||
return
|
||||
if(!SSsqlite.can_submit_feedback(my_client))
|
||||
return
|
||||
..()
|
||||
|
||||
// Builds the window for players to review their feedback.
|
||||
/datum/managed_browser/feedback_form/get_html()
|
||||
var/list/dat = list("<html><body>")
|
||||
dat += "<center>"
|
||||
dat += "<font size='2'>"
|
||||
dat += "Here, you can write some feedback for the server.<br>"
|
||||
dat += "Note that HTML is NOT supported!<br>"
|
||||
dat += "Click the edit button to begin writing.<br>"
|
||||
|
||||
dat += "Your feedback is currently [length(feedback_body)]/[MAX_FEEDBACK_LENGTH] letters long."
|
||||
dat += "</font>"
|
||||
dat += "<hr>"
|
||||
|
||||
dat += "<h2>Preview</h2></center>"
|
||||
|
||||
dat += "Author: "
|
||||
|
||||
if(can_be_private())
|
||||
if(!feedback_hide_author)
|
||||
dat += "[my_client.ckey] "
|
||||
dat += span("linkOn", "<b>Visible</b>")
|
||||
dat += " | "
|
||||
dat += href(src, list("feedback_hide_author" = 1), "Hashed")
|
||||
else
|
||||
dat += "[md5(ckey(lowertext(my_client.ckey + SSsqlite.get_feedback_pepper())))] "
|
||||
dat += href(src, list("feedback_hide_author" = 0), "Visible")
|
||||
dat += " | "
|
||||
dat += span("linkOn", "<b>Hashed</b>")
|
||||
else
|
||||
dat += my_client.ckey
|
||||
dat += "<br>"
|
||||
|
||||
if(config.sqlite_feedback_topics.len > 1)
|
||||
dat += "Topic: [href(src, list("feedback_choose_topic" = 1), feedback_topic)]<br>"
|
||||
else
|
||||
dat += "Topic: [config.sqlite_feedback_topics[1]]<br>"
|
||||
|
||||
dat += "<br>"
|
||||
if(feedback_body)
|
||||
dat += replacetext(feedback_body, "\n", "<br>") // So newlines will look like they work in the preview.
|
||||
else
|
||||
dat += "<i>\[Feedback goes here...\]</i>"
|
||||
dat += "<br>"
|
||||
dat += href(src, list("feedback_edit_body" = 1), "Edit")
|
||||
dat += "<hr>"
|
||||
|
||||
if(config.sqlite_feedback_cooldown)
|
||||
dat += "<i>Please note that you will have to wait [config.sqlite_feedback_cooldown] day\s before \
|
||||
being able to write more feedback after submitting.</i><br>"
|
||||
|
||||
dat += href(src, list("feedback_submit" = 1), "Submit")
|
||||
dat += "</body></html>"
|
||||
return dat.Join()
|
||||
|
||||
/datum/managed_browser/feedback_form/Topic(href, href_list[])
|
||||
if(!my_client)
|
||||
return FALSE
|
||||
|
||||
if(href_list["feedback_edit_body"])
|
||||
// This is deliberately not sanitized here, and is instead checked when hitting the submission button,
|
||||
// as we want to give the user a chance to fix it without needing to rewrite the whole thing.
|
||||
feedback_body = tgui_input_text(my_client, "Please write your feedback here.", "Feedback Body", feedback_body, multiline = TRUE, prevent_enter = TRUE)
|
||||
display() // Refresh the window with new information.
|
||||
return
|
||||
|
||||
if(href_list["feedback_hide_author"])
|
||||
if(!can_be_private())
|
||||
feedback_hide_author = FALSE
|
||||
else
|
||||
feedback_hide_author = text2num(href_list["feedback_hide_author"])
|
||||
display()
|
||||
return
|
||||
|
||||
if(href_list["feedback_choose_topic"])
|
||||
feedback_topic = tgui_input_list(my_client, "Choose the topic you want to submit your feedback under.", "Feedback Topic", config.sqlite_feedback_topics)
|
||||
display()
|
||||
return
|
||||
|
||||
if(href_list["feedback_submit"])
|
||||
// Do some last minute validation, and tell the user if something goes wrong,
|
||||
// so we don't wipe out their ten thousand page essay due to having a few too many characters.
|
||||
if(length(feedback_body) > MAX_FEEDBACK_LENGTH)
|
||||
to_chat(my_client, span("warning", "Your feedback is too long, at [length(feedback_body)] characters, where as the \
|
||||
limit is [MAX_FEEDBACK_LENGTH]. Please shorten it and try again."))
|
||||
return
|
||||
|
||||
var/text = sanitize(feedback_body, max_length = 0, encode = TRUE, trim = FALSE, extra = FALSE)
|
||||
if(!text) // No text, or it was super invalid.
|
||||
to_chat(my_client, span("warning", "It appears you didn't write anything, or it was invalid."))
|
||||
return
|
||||
|
||||
if(tgui_alert(my_client, "Are you sure you want to submit your feedback?", "Confirm Submission", list("No", "Yes")) == "Yes")
|
||||
var/author_text = my_client.ckey
|
||||
if(can_be_private() && feedback_hide_author)
|
||||
author_text = md5(my_client.ckey + SSsqlite.get_feedback_pepper())
|
||||
|
||||
var/success = SSsqlite.insert_feedback(author = author_text, topic = feedback_topic, content = feedback_body, sqlite_object = SSsqlite.sqlite_db)
|
||||
if(!success)
|
||||
to_chat(my_client, span("warning", "Something went wrong while inserting your feedback into the database. Please try again. \
|
||||
If this happens again, you should contact a developer."))
|
||||
return
|
||||
|
||||
my_client.mob << browse(null, "window=[browser_id]") // Closes the window.
|
||||
if(istype(my_client.mob, /mob/new_player))
|
||||
var/mob/new_player/NP = my_client.mob
|
||||
NP.new_player_panel_proc() // So the feedback button goes away, if the user gets put on cooldown.
|
||||
/client
|
||||
var/datum/managed_browser/feedback_form/feedback_form = null
|
||||
|
||||
/client/can_vv_get(var_name)
|
||||
return var_name != NAMEOF(src, feedback_form) // No snooping.
|
||||
|
||||
GENERAL_PROTECT_DATUM(/datum/managed_browser/feedback_form)
|
||||
|
||||
// A fairly simple object to hold information about a player's feedback as it's being written.
|
||||
// Having this be it's own object instead of being baked into /mob/new_player allows for it to be used
|
||||
// from other places than just the lobby, and makes it a lot harder for people with dev powers to be naughty with it using VV/proccall.
|
||||
/datum/managed_browser/feedback_form
|
||||
base_browser_id = "feedback_form"
|
||||
title = "Server Feedback"
|
||||
size_x = 480
|
||||
size_y = 520
|
||||
var/feedback_topic = null
|
||||
var/feedback_body = null
|
||||
var/feedback_hide_author = FALSE
|
||||
|
||||
/datum/managed_browser/feedback_form/New(client/new_client)
|
||||
feedback_topic = config.sqlite_feedback_topics[1]
|
||||
..(new_client)
|
||||
|
||||
/datum/managed_browser/feedback_form/Destroy()
|
||||
if(my_client)
|
||||
my_client.feedback_form = null
|
||||
return ..()
|
||||
|
||||
// Privacy option is allowed if both the config allows it, and the pepper file exists and isn't blank.
|
||||
/datum/managed_browser/feedback_form/proc/can_be_private()
|
||||
return config.sqlite_feedback_privacy && SSsqlite.get_feedback_pepper()
|
||||
|
||||
/datum/managed_browser/feedback_form/display()
|
||||
if(!my_client)
|
||||
return
|
||||
if(!SSsqlite.can_submit_feedback(my_client))
|
||||
return
|
||||
..()
|
||||
|
||||
// Builds the window for players to review their feedback.
|
||||
/datum/managed_browser/feedback_form/get_html()
|
||||
var/list/dat = list("<html><body>")
|
||||
dat += "<center>"
|
||||
dat += "<font size='2'>"
|
||||
dat += "Here, you can write some feedback for the server.<br>"
|
||||
dat += "Note that HTML is NOT supported!<br>"
|
||||
dat += "Click the edit button to begin writing.<br>"
|
||||
|
||||
dat += "Your feedback is currently [length(feedback_body)]/[MAX_FEEDBACK_LENGTH] letters long."
|
||||
dat += "</font>"
|
||||
dat += "<hr>"
|
||||
|
||||
dat += "<h2>Preview</h2></center>"
|
||||
|
||||
dat += "Author: "
|
||||
|
||||
if(can_be_private())
|
||||
if(!feedback_hide_author)
|
||||
dat += "[my_client.ckey] "
|
||||
dat += span("linkOn", "<b>Visible</b>")
|
||||
dat += " | "
|
||||
dat += href(src, list("feedback_hide_author" = 1), "Hashed")
|
||||
else
|
||||
dat += "[md5(ckey(lowertext(my_client.ckey + SSsqlite.get_feedback_pepper())))] "
|
||||
dat += href(src, list("feedback_hide_author" = 0), "Visible")
|
||||
dat += " | "
|
||||
dat += span("linkOn", "<b>Hashed</b>")
|
||||
else
|
||||
dat += my_client.ckey
|
||||
dat += "<br>"
|
||||
|
||||
if(config.sqlite_feedback_topics.len > 1)
|
||||
dat += "Topic: [href(src, list("feedback_choose_topic" = 1), feedback_topic)]<br>"
|
||||
else
|
||||
dat += "Topic: [config.sqlite_feedback_topics[1]]<br>"
|
||||
|
||||
dat += "<br>"
|
||||
if(feedback_body)
|
||||
dat += replacetext(feedback_body, "\n", "<br>") // So newlines will look like they work in the preview.
|
||||
else
|
||||
dat += "<i>\[Feedback goes here...\]</i>"
|
||||
dat += "<br>"
|
||||
dat += href(src, list("feedback_edit_body" = 1), "Edit")
|
||||
dat += "<hr>"
|
||||
|
||||
if(config.sqlite_feedback_cooldown)
|
||||
dat += "<i>Please note that you will have to wait [config.sqlite_feedback_cooldown] day\s before \
|
||||
being able to write more feedback after submitting.</i><br>"
|
||||
|
||||
dat += href(src, list("feedback_submit" = 1), "Submit")
|
||||
dat += "</body></html>"
|
||||
return dat.Join()
|
||||
|
||||
/datum/managed_browser/feedback_form/Topic(href, href_list[])
|
||||
if(!my_client)
|
||||
return FALSE
|
||||
|
||||
if(href_list["feedback_edit_body"])
|
||||
// This is deliberately not sanitized here, and is instead checked when hitting the submission button,
|
||||
// as we want to give the user a chance to fix it without needing to rewrite the whole thing.
|
||||
feedback_body = tgui_input_text(my_client, "Please write your feedback here.", "Feedback Body", feedback_body, multiline = TRUE, prevent_enter = TRUE)
|
||||
display() // Refresh the window with new information.
|
||||
return
|
||||
|
||||
if(href_list["feedback_hide_author"])
|
||||
if(!can_be_private())
|
||||
feedback_hide_author = FALSE
|
||||
else
|
||||
feedback_hide_author = text2num(href_list["feedback_hide_author"])
|
||||
display()
|
||||
return
|
||||
|
||||
if(href_list["feedback_choose_topic"])
|
||||
feedback_topic = tgui_input_list(my_client, "Choose the topic you want to submit your feedback under.", "Feedback Topic", config.sqlite_feedback_topics)
|
||||
display()
|
||||
return
|
||||
|
||||
if(href_list["feedback_submit"])
|
||||
// Do some last minute validation, and tell the user if something goes wrong,
|
||||
// so we don't wipe out their ten thousand page essay due to having a few too many characters.
|
||||
if(length(feedback_body) > MAX_FEEDBACK_LENGTH)
|
||||
to_chat(my_client, span("warning", "Your feedback is too long, at [length(feedback_body)] characters, where as the \
|
||||
limit is [MAX_FEEDBACK_LENGTH]. Please shorten it and try again."))
|
||||
return
|
||||
|
||||
var/text = sanitize(feedback_body, max_length = 0, encode = TRUE, trim = FALSE, extra = FALSE)
|
||||
if(!text) // No text, or it was super invalid.
|
||||
to_chat(my_client, span("warning", "It appears you didn't write anything, or it was invalid."))
|
||||
return
|
||||
|
||||
if(tgui_alert(my_client, "Are you sure you want to submit your feedback?", "Confirm Submission", list("No", "Yes")) == "Yes")
|
||||
var/author_text = my_client.ckey
|
||||
if(can_be_private() && feedback_hide_author)
|
||||
author_text = md5(my_client.ckey + SSsqlite.get_feedback_pepper())
|
||||
|
||||
var/success = SSsqlite.insert_feedback(author = author_text, topic = feedback_topic, content = feedback_body, sqlite_object = SSsqlite.sqlite_db)
|
||||
if(!success)
|
||||
to_chat(my_client, span("warning", "Something went wrong while inserting your feedback into the database. Please try again. \
|
||||
If this happens again, you should contact a developer."))
|
||||
return
|
||||
|
||||
my_client.mob << browse(null, "window=[browser_id]") // Closes the window.
|
||||
if(istype(my_client.mob, /mob/new_player))
|
||||
var/mob/new_player/NP = my_client.mob
|
||||
NP.new_player_panel_proc() // So the feedback button goes away, if the user gets put on cooldown.
|
||||
qdel(src)
|
||||
@@ -1,162 +1,162 @@
|
||||
/client
|
||||
var/datum/managed_browser/feedback_viewer/feedback_viewer = null
|
||||
|
||||
/datum/admins/proc/view_feedback()
|
||||
set category = "Admin"
|
||||
set name = "View Feedback"
|
||||
set desc = "Open the Feedback Viewer"
|
||||
|
||||
if(!check_rights(R_ADMIN|R_DEBUG|R_EVENT))
|
||||
return
|
||||
|
||||
if(usr.client.feedback_viewer)
|
||||
usr.client.feedback_viewer.display()
|
||||
else
|
||||
usr.client.feedback_viewer = new(usr.client)
|
||||
|
||||
// This object holds the code to run the admin feedback viewer.
|
||||
/datum/managed_browser/feedback_viewer
|
||||
base_browser_id = "feedback_viewer"
|
||||
title = "Submitted Feedback"
|
||||
size_x = 900
|
||||
size_y = 500
|
||||
var/database/query/last_query = null
|
||||
|
||||
/datum/managed_browser/feedback_viewer/New(client/new_client)
|
||||
if(!check_rights(R_ADMIN|R_DEBUG|R_EVENT, new_client)) // Just in case someone figures out a way to spawn this as non-staff.
|
||||
message_admins("[new_client] tried to view feedback with insufficent permissions.")
|
||||
qdel(src)
|
||||
|
||||
..()
|
||||
|
||||
/datum/managed_browser/feedback_viewer/Destroy()
|
||||
if(my_client)
|
||||
my_client.feedback_viewer = null
|
||||
return ..()
|
||||
|
||||
/datum/managed_browser/feedback_viewer/proc/feedback_filter(row_name, thing_to_find, exact = FALSE)
|
||||
var/database/query/query = null
|
||||
if(exact) // Useful for ID searches, so searching for 'id 10' doesn't also get 'id 101'.
|
||||
query = new({"
|
||||
SELECT *
|
||||
FROM [SQLITE_TABLE_FEEDBACK]
|
||||
WHERE [row_name] == ?
|
||||
ORDER BY [SQLITE_FEEDBACK_COLUMN_ID]
|
||||
DESC LIMIT 50;
|
||||
"},
|
||||
thing_to_find
|
||||
)
|
||||
|
||||
else
|
||||
// Wrap the thing in %s so LIKE will work.
|
||||
thing_to_find = "%[thing_to_find]%"
|
||||
query = new({"
|
||||
SELECT *
|
||||
FROM [SQLITE_TABLE_FEEDBACK]
|
||||
WHERE [row_name] LIKE ?
|
||||
ORDER BY [SQLITE_FEEDBACK_COLUMN_ID]
|
||||
DESC LIMIT 50;
|
||||
"},
|
||||
thing_to_find
|
||||
)
|
||||
query.Execute(SSsqlite.sqlite_db)
|
||||
SSsqlite.sqlite_check_for_errors(query, "Admin Feedback Viewer - Filter by [row_name] to find [thing_to_find]")
|
||||
return query
|
||||
|
||||
// Builds the window for players to review their feedback.
|
||||
/datum/managed_browser/feedback_viewer/get_html()
|
||||
var/list/dat = list("<html><body>")
|
||||
if(!last_query) // If no query was done before, just show the most recent feedbacks.
|
||||
var/database/query/query = new({"
|
||||
SELECT *
|
||||
FROM [SQLITE_TABLE_FEEDBACK]
|
||||
ORDER BY [SQLITE_FEEDBACK_COLUMN_ID]
|
||||
DESC LIMIT 50;
|
||||
"}
|
||||
)
|
||||
query.Execute(SSsqlite.sqlite_db)
|
||||
SSsqlite.sqlite_check_for_errors(query, "Admin Feedback Viewer")
|
||||
last_query = query
|
||||
|
||||
dat += "<table border='1' style='width:100%'>"
|
||||
dat += "<tr>"
|
||||
dat += "<th>[href(src, list("filter_id" = 1), "ID")]</th>"
|
||||
dat += "<th>[href(src, list("filter_topic" = 1), "Topic")]</th>"
|
||||
dat += "<th>[href(src, list("filter_author" = 1), "Author")]</th>"
|
||||
dat += "<th>[href(src, list("filter_content" = 1), "Content")]</th>"
|
||||
dat += "<th>[href(src, list("filter_datetime" = 1), "Datetime")]</th>"
|
||||
dat += "</tr>"
|
||||
|
||||
while(last_query.NextRow())
|
||||
var/list/row_data = last_query.GetRowData()
|
||||
dat += "<tr>"
|
||||
dat += "<td>[row_data[SQLITE_FEEDBACK_COLUMN_ID]]</td>"
|
||||
dat += "<td>[row_data[SQLITE_FEEDBACK_COLUMN_TOPIC]]</td>"
|
||||
dat += "<td>[row_data[SQLITE_FEEDBACK_COLUMN_AUTHOR]]</td>" // TODO: Color this to make hashed keys more distinguishable.
|
||||
var/text = row_data[SQLITE_FEEDBACK_COLUMN_CONTENT]
|
||||
if(length(text) > 512)
|
||||
text = href(src, list(
|
||||
"show_full_feedback" = 1,
|
||||
"feedback_author" = row_data[SQLITE_FEEDBACK_COLUMN_AUTHOR],
|
||||
"feedback_content" = row_data[SQLITE_FEEDBACK_COLUMN_CONTENT]
|
||||
), "[copytext(text, 1, 64)]... ([length(text)])")
|
||||
else
|
||||
text = replacetext(text, "\n", "<br>")
|
||||
dat += "<td>[text]</td>"
|
||||
dat += "<td>[row_data[SQLITE_FEEDBACK_COLUMN_DATETIME]]</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
|
||||
dat += "</body></html>"
|
||||
return dat.Join()
|
||||
|
||||
// Used to show the full version of feedback in a seperate window.
|
||||
/datum/managed_browser/feedback_viewer/proc/display_big_feedback(author, text)
|
||||
var/list/dat = list("<html><body>")
|
||||
dat += replacetext(text, "\n", "<br>")
|
||||
|
||||
var/datum/browser/popup = new(my_client.mob, "feedback_big", "[author]'s Feedback", 480, 520, src)
|
||||
popup.set_content(dat.Join())
|
||||
popup.open()
|
||||
|
||||
|
||||
/datum/managed_browser/feedback_viewer/Topic(href, href_list[])
|
||||
if(!my_client)
|
||||
return FALSE
|
||||
|
||||
if(href_list["close"]) // To avoid refreshing.
|
||||
return
|
||||
|
||||
if(href_list["show_full_feedback"])
|
||||
display_big_feedback(href_list["feedback_author"], href_list["feedback_content"])
|
||||
return
|
||||
|
||||
if(href_list["filter_id"])
|
||||
var/id_to_search = tgui_input_number(my_client, "Write feedback ID here.", "Filter by ID", null)
|
||||
if(id_to_search)
|
||||
last_query = feedback_filter(SQLITE_FEEDBACK_COLUMN_ID, id_to_search, TRUE)
|
||||
|
||||
if(href_list["filter_author"])
|
||||
var/author_to_search = tgui_input_text(my_client, "Write desired key or hash here. Partial keys/hashes are allowed.", "Filter by Author", null)
|
||||
if(author_to_search)
|
||||
last_query = feedback_filter(SQLITE_FEEDBACK_COLUMN_AUTHOR, author_to_search)
|
||||
|
||||
if(href_list["filter_topic"])
|
||||
var/topic_to_search = tgui_input_text(my_client, "Write desired topic here. Partial topics are allowed. \
|
||||
\nThe current topics in the config are [english_list(config.sqlite_feedback_topics)].", "Filter by Topic", null)
|
||||
if(topic_to_search)
|
||||
last_query = feedback_filter(SQLITE_FEEDBACK_COLUMN_TOPIC, topic_to_search)
|
||||
|
||||
if(href_list["filter_content"])
|
||||
var/content_to_search = tgui_input_text(my_client, "Write desired content to find here. Partial matches are allowed.", "Filter by Content", null, multiline = TRUE)
|
||||
if(content_to_search)
|
||||
last_query = feedback_filter(SQLITE_FEEDBACK_COLUMN_CONTENT, content_to_search)
|
||||
|
||||
if(href_list["filter_datetime"])
|
||||
var/datetime_to_search = tgui_input_text(my_client, "Write desired datetime. Partial matches are allowed.\n\
|
||||
Format is 'YYYY-MM-DD HH:MM:SS'.", "Filter by Datetime", null)
|
||||
if(datetime_to_search)
|
||||
last_query = feedback_filter(SQLITE_FEEDBACK_COLUMN_DATETIME, datetime_to_search)
|
||||
|
||||
// Refresh.
|
||||
/client
|
||||
var/datum/managed_browser/feedback_viewer/feedback_viewer = null
|
||||
|
||||
/datum/admins/proc/view_feedback()
|
||||
set category = "Admin"
|
||||
set name = "View Feedback"
|
||||
set desc = "Open the Feedback Viewer"
|
||||
|
||||
if(!check_rights(R_ADMIN|R_DEBUG|R_EVENT))
|
||||
return
|
||||
|
||||
if(usr.client.feedback_viewer)
|
||||
usr.client.feedback_viewer.display()
|
||||
else
|
||||
usr.client.feedback_viewer = new(usr.client)
|
||||
|
||||
// This object holds the code to run the admin feedback viewer.
|
||||
/datum/managed_browser/feedback_viewer
|
||||
base_browser_id = "feedback_viewer"
|
||||
title = "Submitted Feedback"
|
||||
size_x = 900
|
||||
size_y = 500
|
||||
var/database/query/last_query = null
|
||||
|
||||
/datum/managed_browser/feedback_viewer/New(client/new_client)
|
||||
if(!check_rights(R_ADMIN|R_DEBUG|R_EVENT, new_client)) // Just in case someone figures out a way to spawn this as non-staff.
|
||||
message_admins("[new_client] tried to view feedback with insufficent permissions.")
|
||||
qdel(src)
|
||||
|
||||
..()
|
||||
|
||||
/datum/managed_browser/feedback_viewer/Destroy()
|
||||
if(my_client)
|
||||
my_client.feedback_viewer = null
|
||||
return ..()
|
||||
|
||||
/datum/managed_browser/feedback_viewer/proc/feedback_filter(row_name, thing_to_find, exact = FALSE)
|
||||
var/database/query/query = null
|
||||
if(exact) // Useful for ID searches, so searching for 'id 10' doesn't also get 'id 101'.
|
||||
query = new({"
|
||||
SELECT *
|
||||
FROM [SQLITE_TABLE_FEEDBACK]
|
||||
WHERE [row_name] == ?
|
||||
ORDER BY [SQLITE_FEEDBACK_COLUMN_ID]
|
||||
DESC LIMIT 50;
|
||||
"},
|
||||
thing_to_find
|
||||
)
|
||||
|
||||
else
|
||||
// Wrap the thing in %s so LIKE will work.
|
||||
thing_to_find = "%[thing_to_find]%"
|
||||
query = new({"
|
||||
SELECT *
|
||||
FROM [SQLITE_TABLE_FEEDBACK]
|
||||
WHERE [row_name] LIKE ?
|
||||
ORDER BY [SQLITE_FEEDBACK_COLUMN_ID]
|
||||
DESC LIMIT 50;
|
||||
"},
|
||||
thing_to_find
|
||||
)
|
||||
query.Execute(SSsqlite.sqlite_db)
|
||||
SSsqlite.sqlite_check_for_errors(query, "Admin Feedback Viewer - Filter by [row_name] to find [thing_to_find]")
|
||||
return query
|
||||
|
||||
// Builds the window for players to review their feedback.
|
||||
/datum/managed_browser/feedback_viewer/get_html()
|
||||
var/list/dat = list("<html><body>")
|
||||
if(!last_query) // If no query was done before, just show the most recent feedbacks.
|
||||
var/database/query/query = new({"
|
||||
SELECT *
|
||||
FROM [SQLITE_TABLE_FEEDBACK]
|
||||
ORDER BY [SQLITE_FEEDBACK_COLUMN_ID]
|
||||
DESC LIMIT 50;
|
||||
"}
|
||||
)
|
||||
query.Execute(SSsqlite.sqlite_db)
|
||||
SSsqlite.sqlite_check_for_errors(query, "Admin Feedback Viewer")
|
||||
last_query = query
|
||||
|
||||
dat += "<table border='1' style='width:100%'>"
|
||||
dat += "<tr>"
|
||||
dat += "<th>[href(src, list("filter_id" = 1), "ID")]</th>"
|
||||
dat += "<th>[href(src, list("filter_topic" = 1), "Topic")]</th>"
|
||||
dat += "<th>[href(src, list("filter_author" = 1), "Author")]</th>"
|
||||
dat += "<th>[href(src, list("filter_content" = 1), "Content")]</th>"
|
||||
dat += "<th>[href(src, list("filter_datetime" = 1), "Datetime")]</th>"
|
||||
dat += "</tr>"
|
||||
|
||||
while(last_query.NextRow())
|
||||
var/list/row_data = last_query.GetRowData()
|
||||
dat += "<tr>"
|
||||
dat += "<td>[row_data[SQLITE_FEEDBACK_COLUMN_ID]]</td>"
|
||||
dat += "<td>[row_data[SQLITE_FEEDBACK_COLUMN_TOPIC]]</td>"
|
||||
dat += "<td>[row_data[SQLITE_FEEDBACK_COLUMN_AUTHOR]]</td>" // TODO: Color this to make hashed keys more distinguishable.
|
||||
var/text = row_data[SQLITE_FEEDBACK_COLUMN_CONTENT]
|
||||
if(length(text) > 512)
|
||||
text = href(src, list(
|
||||
"show_full_feedback" = 1,
|
||||
"feedback_author" = row_data[SQLITE_FEEDBACK_COLUMN_AUTHOR],
|
||||
"feedback_content" = row_data[SQLITE_FEEDBACK_COLUMN_CONTENT]
|
||||
), "[copytext(text, 1, 64)]... ([length(text)])")
|
||||
else
|
||||
text = replacetext(text, "\n", "<br>")
|
||||
dat += "<td>[text]</td>"
|
||||
dat += "<td>[row_data[SQLITE_FEEDBACK_COLUMN_DATETIME]]</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
|
||||
dat += "</body></html>"
|
||||
return dat.Join()
|
||||
|
||||
// Used to show the full version of feedback in a seperate window.
|
||||
/datum/managed_browser/feedback_viewer/proc/display_big_feedback(author, text)
|
||||
var/list/dat = list("<html><body>")
|
||||
dat += replacetext(text, "\n", "<br>")
|
||||
|
||||
var/datum/browser/popup = new(my_client.mob, "feedback_big", "[author]'s Feedback", 480, 520, src)
|
||||
popup.set_content(dat.Join())
|
||||
popup.open()
|
||||
|
||||
|
||||
/datum/managed_browser/feedback_viewer/Topic(href, href_list[])
|
||||
if(!my_client)
|
||||
return FALSE
|
||||
|
||||
if(href_list["close"]) // To avoid refreshing.
|
||||
return
|
||||
|
||||
if(href_list["show_full_feedback"])
|
||||
display_big_feedback(href_list["feedback_author"], href_list["feedback_content"])
|
||||
return
|
||||
|
||||
if(href_list["filter_id"])
|
||||
var/id_to_search = tgui_input_number(my_client, "Write feedback ID here.", "Filter by ID", null)
|
||||
if(id_to_search)
|
||||
last_query = feedback_filter(SQLITE_FEEDBACK_COLUMN_ID, id_to_search, TRUE)
|
||||
|
||||
if(href_list["filter_author"])
|
||||
var/author_to_search = tgui_input_text(my_client, "Write desired key or hash here. Partial keys/hashes are allowed.", "Filter by Author", null)
|
||||
if(author_to_search)
|
||||
last_query = feedback_filter(SQLITE_FEEDBACK_COLUMN_AUTHOR, author_to_search)
|
||||
|
||||
if(href_list["filter_topic"])
|
||||
var/topic_to_search = tgui_input_text(my_client, "Write desired topic here. Partial topics are allowed. \
|
||||
\nThe current topics in the config are [english_list(config.sqlite_feedback_topics)].", "Filter by Topic", null)
|
||||
if(topic_to_search)
|
||||
last_query = feedback_filter(SQLITE_FEEDBACK_COLUMN_TOPIC, topic_to_search)
|
||||
|
||||
if(href_list["filter_content"])
|
||||
var/content_to_search = tgui_input_text(my_client, "Write desired content to find here. Partial matches are allowed.", "Filter by Content", null, multiline = TRUE)
|
||||
if(content_to_search)
|
||||
last_query = feedback_filter(SQLITE_FEEDBACK_COLUMN_CONTENT, content_to_search)
|
||||
|
||||
if(href_list["filter_datetime"])
|
||||
var/datetime_to_search = tgui_input_text(my_client, "Write desired datetime. Partial matches are allowed.\n\
|
||||
Format is 'YYYY-MM-DD HH:MM:SS'.", "Filter by Datetime", null)
|
||||
if(datetime_to_search)
|
||||
last_query = feedback_filter(SQLITE_FEEDBACK_COLUMN_DATETIME, datetime_to_search)
|
||||
|
||||
// Refresh.
|
||||
display()
|
||||
+579
-579
File diff suppressed because it is too large
Load Diff
+63
-63
@@ -1,63 +1,63 @@
|
||||
// module datum.
|
||||
// this is per-object instance, and shows the condition of the modules in the object
|
||||
// actual modules needed is referenced through modulestypes and the object type
|
||||
|
||||
/datum/module
|
||||
var/status // bits set if working, 0 if broken
|
||||
var/installed // bits set if installed, 0 if missing
|
||||
|
||||
// moduletypes datum
|
||||
// this is per-object type, and shows the modules needed for a type of object
|
||||
|
||||
/datum/moduletypes
|
||||
var/list/modcount = list() // assoc list of the count of modules for a type
|
||||
|
||||
|
||||
var/list/modules = list( // global associative list
|
||||
"/obj/machinery/power/apc" = "card_reader,power_control,id_auth,cell_power,cell_charge")
|
||||
|
||||
|
||||
/datum/module/New(var/obj/O)
|
||||
|
||||
var/type = O.type // the type of the creating object
|
||||
|
||||
var/mneed = mods.inmodlist(type) // find if this type has modules defined
|
||||
|
||||
if(!mneed) // not found in module list?
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
var/needed = mods.getbitmask(type) // get a bitmask for the number of modules in this object
|
||||
status = needed
|
||||
installed = needed
|
||||
|
||||
/datum/moduletypes/proc/addmod(var/type, var/modtextlist)
|
||||
modules += type // index by type text
|
||||
modules[type] = modtextlist
|
||||
|
||||
/datum/moduletypes/proc/inmodlist(var/type)
|
||||
return ("[type]" in modules)
|
||||
|
||||
/datum/moduletypes/proc/getbitmask(var/type)
|
||||
var/count = modcount["[type]"]
|
||||
if(count)
|
||||
return 2**count-1
|
||||
|
||||
var/modtext = modules["[type]"]
|
||||
var/num = 1
|
||||
var/pos = 1
|
||||
|
||||
while(1)
|
||||
pos = findtext(modtext, ",", pos, 0)
|
||||
if(!pos)
|
||||
break
|
||||
else
|
||||
pos++
|
||||
num++
|
||||
|
||||
modcount += "[type]"
|
||||
modcount["[type]"] = num
|
||||
|
||||
return 2**num-1
|
||||
|
||||
|
||||
// module datum.
|
||||
// this is per-object instance, and shows the condition of the modules in the object
|
||||
// actual modules needed is referenced through modulestypes and the object type
|
||||
|
||||
/datum/module
|
||||
var/status // bits set if working, 0 if broken
|
||||
var/installed // bits set if installed, 0 if missing
|
||||
|
||||
// moduletypes datum
|
||||
// this is per-object type, and shows the modules needed for a type of object
|
||||
|
||||
/datum/moduletypes
|
||||
var/list/modcount = list() // assoc list of the count of modules for a type
|
||||
|
||||
|
||||
var/list/modules = list( // global associative list
|
||||
"/obj/machinery/power/apc" = "card_reader,power_control,id_auth,cell_power,cell_charge")
|
||||
|
||||
|
||||
/datum/module/New(var/obj/O)
|
||||
|
||||
var/type = O.type // the type of the creating object
|
||||
|
||||
var/mneed = mods.inmodlist(type) // find if this type has modules defined
|
||||
|
||||
if(!mneed) // not found in module list?
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
var/needed = mods.getbitmask(type) // get a bitmask for the number of modules in this object
|
||||
status = needed
|
||||
installed = needed
|
||||
|
||||
/datum/moduletypes/proc/addmod(var/type, var/modtextlist)
|
||||
modules += type // index by type text
|
||||
modules[type] = modtextlist
|
||||
|
||||
/datum/moduletypes/proc/inmodlist(var/type)
|
||||
return ("[type]" in modules)
|
||||
|
||||
/datum/moduletypes/proc/getbitmask(var/type)
|
||||
var/count = modcount["[type]"]
|
||||
if(count)
|
||||
return 2**count-1
|
||||
|
||||
var/modtext = modules["[type]"]
|
||||
var/num = 1
|
||||
var/pos = 1
|
||||
|
||||
while(1)
|
||||
pos = findtext(modtext, ",", pos, 0)
|
||||
if(!pos)
|
||||
break
|
||||
else
|
||||
pos++
|
||||
num++
|
||||
|
||||
modcount += "[type]"
|
||||
modcount["[type]"] = num
|
||||
|
||||
return 2**num-1
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
// Observer Pattern Implementation: Z_Moved
|
||||
// Registration type: /atom/movable
|
||||
//
|
||||
// Raised when: An /atom/movable instance has changed z-levels by any means.
|
||||
//
|
||||
// Arguments that the called proc should expect:
|
||||
// /atom/movable/moving_instance: The instance that moved
|
||||
// old_z: The z number before the move.
|
||||
// new_z: The z number after the move.
|
||||
|
||||
|
||||
GLOBAL_DATUM_INIT(z_moved_event, /decl/observ/z_moved, new)
|
||||
|
||||
/decl/observ/z_moved
|
||||
name = "Z_Moved"
|
||||
expected_type = /atom/movable
|
||||
// Observer Pattern Implementation: Z_Moved
|
||||
// Registration type: /atom/movable
|
||||
//
|
||||
// Raised when: An /atom/movable instance has changed z-levels by any means.
|
||||
//
|
||||
// Arguments that the called proc should expect:
|
||||
// /atom/movable/moving_instance: The instance that moved
|
||||
// old_z: The z number before the move.
|
||||
// new_z: The z number after the move.
|
||||
|
||||
|
||||
GLOBAL_DATUM_INIT(z_moved_event, /decl/observ/z_moved, new)
|
||||
|
||||
/decl/observ/z_moved
|
||||
name = "Z_Moved"
|
||||
expected_type = /atom/movable
|
||||
|
||||
@@ -1,74 +1,74 @@
|
||||
var/global/datum/repository/crew/crew_repository = new()
|
||||
|
||||
/datum/repository/crew
|
||||
var/list/cache_data
|
||||
|
||||
/datum/repository/crew/New()
|
||||
cache_data = list()
|
||||
..()
|
||||
|
||||
/datum/repository/crew/proc/health_data(var/zLevel)
|
||||
var/list/crewmembers = list()
|
||||
if(!zLevel)
|
||||
return crewmembers
|
||||
|
||||
var/z_level = "[zLevel]"
|
||||
var/datum/cache_entry/cache_entry = cache_data[z_level]
|
||||
if(!cache_entry)
|
||||
cache_entry = new/datum/cache_entry
|
||||
cache_data[z_level] = cache_entry
|
||||
|
||||
if(world.time < cache_entry.timestamp)
|
||||
return cache_entry.data
|
||||
|
||||
var/tracked = scan()
|
||||
for(var/obj/item/clothing/under/C in tracked)
|
||||
var/turf/pos = get_turf(C)
|
||||
var/area/B = pos?.loc //VOREStation Add: No sensor in Dorm
|
||||
if((C.has_sensor) && (pos?.z == zLevel) && (C.sensor_mode != SUIT_SENSOR_OFF) && !(B.block_suit_sensors) && !(is_jammed(C)) && !(is_vore_jammed(C))) //VOREStation Edit
|
||||
if(istype(C.loc, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = C.loc
|
||||
if(H.w_uniform != C)
|
||||
continue
|
||||
|
||||
var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
|
||||
|
||||
crewmemberData["sensor_type"] = C.sensor_mode
|
||||
crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
|
||||
crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
|
||||
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
|
||||
crewmemberData["dead"] = H.stat == DEAD
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
|
||||
crewmemberData["stat"] = H.stat
|
||||
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
|
||||
crewmemberData["tox"] = round(H.getToxLoss(), 1)
|
||||
crewmemberData["fire"] = round(H.getFireLoss(), 1)
|
||||
crewmemberData["brute"] = round(H.getBruteLoss(), 1)
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
|
||||
var/area/A = get_area(H)
|
||||
crewmemberData["area"] = sanitize(A.get_name())
|
||||
crewmemberData["x"] = pos.x
|
||||
crewmemberData["y"] = pos.y
|
||||
crewmemberData["realZ"] = pos.z
|
||||
crewmemberData["z"] = using_map.get_zlevel_name(pos.z)
|
||||
|
||||
crewmembers[++crewmembers.len] = crewmemberData
|
||||
|
||||
crewmembers = sortByKey(crewmembers, "name")
|
||||
cache_entry.timestamp = world.time + 5 SECONDS
|
||||
cache_entry.data = crewmembers
|
||||
|
||||
return crewmembers
|
||||
|
||||
/datum/repository/crew/proc/scan()
|
||||
var/list/tracked = list()
|
||||
for(var/mob/living/carbon/human/H in mob_list)
|
||||
if(istype(H.w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/C = H.w_uniform
|
||||
if (C.has_sensor)
|
||||
tracked |= C
|
||||
return tracked
|
||||
var/global/datum/repository/crew/crew_repository = new()
|
||||
|
||||
/datum/repository/crew
|
||||
var/list/cache_data
|
||||
|
||||
/datum/repository/crew/New()
|
||||
cache_data = list()
|
||||
..()
|
||||
|
||||
/datum/repository/crew/proc/health_data(var/zLevel)
|
||||
var/list/crewmembers = list()
|
||||
if(!zLevel)
|
||||
return crewmembers
|
||||
|
||||
var/z_level = "[zLevel]"
|
||||
var/datum/cache_entry/cache_entry = cache_data[z_level]
|
||||
if(!cache_entry)
|
||||
cache_entry = new/datum/cache_entry
|
||||
cache_data[z_level] = cache_entry
|
||||
|
||||
if(world.time < cache_entry.timestamp)
|
||||
return cache_entry.data
|
||||
|
||||
var/tracked = scan()
|
||||
for(var/obj/item/clothing/under/C in tracked)
|
||||
var/turf/pos = get_turf(C)
|
||||
var/area/B = pos?.loc //VOREStation Add: No sensor in Dorm
|
||||
if((C.has_sensor) && (pos?.z == zLevel) && (C.sensor_mode != SUIT_SENSOR_OFF) && !(B.block_suit_sensors) && !(is_jammed(C)) && !(is_vore_jammed(C))) //VOREStation Edit
|
||||
if(istype(C.loc, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = C.loc
|
||||
if(H.w_uniform != C)
|
||||
continue
|
||||
|
||||
var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1, "ref" = "\ref[H]")
|
||||
|
||||
crewmemberData["sensor_type"] = C.sensor_mode
|
||||
crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
|
||||
crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
|
||||
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
|
||||
crewmemberData["dead"] = H.stat == DEAD
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
|
||||
crewmemberData["stat"] = H.stat
|
||||
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
|
||||
crewmemberData["tox"] = round(H.getToxLoss(), 1)
|
||||
crewmemberData["fire"] = round(H.getFireLoss(), 1)
|
||||
crewmemberData["brute"] = round(H.getBruteLoss(), 1)
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
|
||||
var/area/A = get_area(H)
|
||||
crewmemberData["area"] = sanitize(A.get_name())
|
||||
crewmemberData["x"] = pos.x
|
||||
crewmemberData["y"] = pos.y
|
||||
crewmemberData["realZ"] = pos.z
|
||||
crewmemberData["z"] = using_map.get_zlevel_name(pos.z)
|
||||
|
||||
crewmembers[++crewmembers.len] = crewmemberData
|
||||
|
||||
crewmembers = sortByKey(crewmembers, "name")
|
||||
cache_entry.timestamp = world.time + 5 SECONDS
|
||||
cache_entry.data = crewmembers
|
||||
|
||||
return crewmembers
|
||||
|
||||
/datum/repository/crew/proc/scan()
|
||||
var/list/tracked = list()
|
||||
for(var/mob/living/carbon/human/H in mob_list)
|
||||
if(istype(H.w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/C = H.w_uniform
|
||||
if (C.has_sensor)
|
||||
tracked |= C
|
||||
return tracked
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
/repository/New()
|
||||
return
|
||||
|
||||
/datum/cache_entry
|
||||
var/timestamp
|
||||
var/data
|
||||
|
||||
/datum/cache_entry/New()
|
||||
timestamp = world.time
|
||||
|
||||
/datum/cache_entry/proc/is_valid()
|
||||
return FALSE
|
||||
|
||||
/datum/cache_entry/valid_until/New(var/valid_duration)
|
||||
..()
|
||||
timestamp += valid_duration
|
||||
|
||||
/datum/cache_entry/valid_until/is_valid()
|
||||
/repository/New()
|
||||
return
|
||||
|
||||
/datum/cache_entry
|
||||
var/timestamp
|
||||
var/data
|
||||
|
||||
/datum/cache_entry/New()
|
||||
timestamp = world.time
|
||||
|
||||
/datum/cache_entry/proc/is_valid()
|
||||
return FALSE
|
||||
|
||||
/datum/cache_entry/valid_until/New(var/valid_duration)
|
||||
..()
|
||||
timestamp += valid_duration
|
||||
|
||||
/datum/cache_entry/valid_until/is_valid()
|
||||
return world.time < timestamp
|
||||
+152
-152
@@ -1,152 +1,152 @@
|
||||
// A datum used to link multiple mobs together in some form.
|
||||
// The code is from TG, however tweaked to be within the preferred code style.
|
||||
|
||||
/mob/living
|
||||
var/list/owned_soul_links // Soul links we are the owner of.
|
||||
var/list/shared_soul_links // Soul links we are a/the sharer of.
|
||||
|
||||
/mob/living/Destroy()
|
||||
for(var/datum/soul_link/S as anything in owned_soul_links)
|
||||
S.owner_died(FALSE)
|
||||
qdel(S) // If the owner is destroy()'d, the soullink is destroy()'d.
|
||||
owned_soul_links = null
|
||||
for(var/datum/soul_link/S as anything in shared_soul_links)
|
||||
S.sharer_died(FALSE)
|
||||
S.remove_soul_sharer(src) // If a sharer is destroy()'d, they are simply removed.
|
||||
shared_soul_links = null
|
||||
return ..()
|
||||
|
||||
// Keeps track of a Mob->Mob (potentially Player->Player) connection.
|
||||
// Can be used to trigger actions on one party when events happen to another.
|
||||
// Eg: shared deaths.
|
||||
// Can be used to form a linked list of mob-hopping.
|
||||
// Does NOT transfer with minds.
|
||||
/datum/soul_link
|
||||
var/mob/living/soul_owner
|
||||
var/mob/living/soul_sharer
|
||||
var/id // Optional ID, for tagging and finding specific instances.
|
||||
|
||||
/datum/soul_link/Destroy()
|
||||
if(soul_owner)
|
||||
LAZYREMOVE(soul_owner.owned_soul_links, src)
|
||||
soul_owner = null
|
||||
if(soul_sharer)
|
||||
LAZYREMOVE(soul_sharer.shared_soul_links, src)
|
||||
soul_sharer = null
|
||||
return ..()
|
||||
|
||||
/datum/soul_link/proc/remove_soul_sharer(mob/living/sharer)
|
||||
if(soul_sharer == sharer)
|
||||
soul_sharer = null
|
||||
LAZYREMOVE(sharer.shared_soul_links, src)
|
||||
|
||||
// Used to assign variables, called primarily by soullink()
|
||||
// Override this to create more unique soullinks (Eg: 1->Many relationships)
|
||||
// Return TRUE/FALSE to return the soullink/null in soullink()
|
||||
/datum/soul_link/proc/parse_args(mob/living/owner, mob/living/sharer)
|
||||
if(!owner || !sharer)
|
||||
return FALSE
|
||||
soul_owner = owner
|
||||
soul_sharer = sharer
|
||||
LAZYADD(owner.owned_soul_links, src)
|
||||
LAZYADD(sharer.shared_soul_links, src)
|
||||
return TRUE
|
||||
|
||||
// Runs after /living death()
|
||||
// Override this for content.
|
||||
/datum/soul_link/proc/owner_died(gibbed, mob/living/owner)
|
||||
|
||||
// Runs after /living death()
|
||||
// Override this for content.
|
||||
/datum/soul_link/proc/sharer_died(gibbed, mob/living/owner)
|
||||
|
||||
// Quick-use helper.
|
||||
/proc/soul_link(typepath, ...)
|
||||
var/datum/soul_link/S = new typepath()
|
||||
if(S.parse_args(arglist(args.Copy(2, 0))))
|
||||
return S
|
||||
|
||||
|
||||
/////////////////
|
||||
// MULTISHARER //
|
||||
/////////////////
|
||||
// Abstract soullink for use with 1 Owner -> Many Sharer setups
|
||||
/datum/soul_link/multi_sharer
|
||||
var/list/soul_sharers
|
||||
|
||||
/datum/soul_link/multi_sharer/parse_args(mob/living/owner, list/sharers)
|
||||
if(!owner || !LAZYLEN(sharers))
|
||||
return FALSE
|
||||
soul_owner = owner
|
||||
soul_sharers = sharers
|
||||
LAZYADD(owner.owned_soul_links, src)
|
||||
for(var/mob/living/L as anything in sharers)
|
||||
LAZYADD(L.shared_soul_links, src)
|
||||
return TRUE
|
||||
|
||||
/datum/soul_link/multi_sharer/remove_soul_sharer(mob/living/sharer)
|
||||
LAZYREMOVE(soul_sharers, sharer)
|
||||
|
||||
|
||||
/////////////////
|
||||
// SHARED FATE //
|
||||
/////////////////
|
||||
// When the soulowner dies, the soulsharer dies, and vice versa
|
||||
// This is intended for two players(or AI) and two mobs
|
||||
|
||||
/datum/soul_link/shared_fate/owner_died(gibbed, mob/living/owner)
|
||||
if(soul_sharer)
|
||||
soul_sharer.death(gibbed)
|
||||
|
||||
/datum/soul_link/shared_fate/sharer_died(gibbed, mob/living/sharer)
|
||||
if(soul_owner)
|
||||
soul_owner.death(gibbed)
|
||||
|
||||
//////////////
|
||||
// ONE WAY //
|
||||
//////////////
|
||||
// When the soul owner dies, the soul sharer dies, but NOT vice versa.
|
||||
// This is intended for two players (or AI) and two mobs.
|
||||
|
||||
/datum/soul_link/one_way/owner_died(gibbed, mob/living/owner)
|
||||
if(soul_sharer)
|
||||
soul_sharer.dust(FALSE)
|
||||
|
||||
/////////////////
|
||||
// SHARED BODY //
|
||||
/////////////////
|
||||
// When the soulsharer dies, they're placed in the soulowner, who remains alive
|
||||
// If the soulowner dies, the soulsharer is killed and placed into the soulowner (who is still dying)
|
||||
// This one is intended for one player moving between many mobs
|
||||
|
||||
/datum/soul_link/shared_body/owner_died(gibbed, mob/living/owner)
|
||||
if(soul_owner && soul_sharer)
|
||||
if(soul_sharer.mind)
|
||||
soul_sharer.mind.transfer_to(soul_owner)
|
||||
soul_sharer.death(gibbed)
|
||||
|
||||
/datum/soul_link/shared_body/sharer_died(gibbed, mob/living/sharer)
|
||||
if(soul_owner && soul_sharer && soul_sharer.mind)
|
||||
soul_sharer.mind.transfer_to(soul_owner)
|
||||
|
||||
|
||||
|
||||
//////////////////////
|
||||
// REPLACEMENT POOL //
|
||||
//////////////////////
|
||||
// When the owner dies, one of the sharers is placed in the owner's body, fully healed
|
||||
// Sort of a "winner-stays-on" soullink
|
||||
// Gibbing ends it immediately
|
||||
|
||||
/datum/soul_link/multi_sharer/replacement_pool/owner_died(gibbed, mob/living/owner)
|
||||
if(LAZYLEN(soul_sharers) && !gibbed) //let's not put them in some gibs
|
||||
var/list/souls = shuffle(soul_sharers.Copy())
|
||||
for(var/mob/living/L as anything in souls)
|
||||
if(L.stat != DEAD && L.mind)
|
||||
L.mind.transfer_to(soul_owner)
|
||||
soul_owner.revive(TRUE, TRUE)
|
||||
L.death(FALSE)
|
||||
|
||||
// Lose your claim to the throne!
|
||||
/datum/soul_link/multi_sharer/replacement_pool/sharer_died(gibbed, mob/living/sharer)
|
||||
remove_soul_sharer(sharer)
|
||||
// A datum used to link multiple mobs together in some form.
|
||||
// The code is from TG, however tweaked to be within the preferred code style.
|
||||
|
||||
/mob/living
|
||||
var/list/owned_soul_links // Soul links we are the owner of.
|
||||
var/list/shared_soul_links // Soul links we are a/the sharer of.
|
||||
|
||||
/mob/living/Destroy()
|
||||
for(var/datum/soul_link/S as anything in owned_soul_links)
|
||||
S.owner_died(FALSE)
|
||||
qdel(S) // If the owner is destroy()'d, the soullink is destroy()'d.
|
||||
owned_soul_links = null
|
||||
for(var/datum/soul_link/S as anything in shared_soul_links)
|
||||
S.sharer_died(FALSE)
|
||||
S.remove_soul_sharer(src) // If a sharer is destroy()'d, they are simply removed.
|
||||
shared_soul_links = null
|
||||
return ..()
|
||||
|
||||
// Keeps track of a Mob->Mob (potentially Player->Player) connection.
|
||||
// Can be used to trigger actions on one party when events happen to another.
|
||||
// Eg: shared deaths.
|
||||
// Can be used to form a linked list of mob-hopping.
|
||||
// Does NOT transfer with minds.
|
||||
/datum/soul_link
|
||||
var/mob/living/soul_owner
|
||||
var/mob/living/soul_sharer
|
||||
var/id // Optional ID, for tagging and finding specific instances.
|
||||
|
||||
/datum/soul_link/Destroy()
|
||||
if(soul_owner)
|
||||
LAZYREMOVE(soul_owner.owned_soul_links, src)
|
||||
soul_owner = null
|
||||
if(soul_sharer)
|
||||
LAZYREMOVE(soul_sharer.shared_soul_links, src)
|
||||
soul_sharer = null
|
||||
return ..()
|
||||
|
||||
/datum/soul_link/proc/remove_soul_sharer(mob/living/sharer)
|
||||
if(soul_sharer == sharer)
|
||||
soul_sharer = null
|
||||
LAZYREMOVE(sharer.shared_soul_links, src)
|
||||
|
||||
// Used to assign variables, called primarily by soullink()
|
||||
// Override this to create more unique soullinks (Eg: 1->Many relationships)
|
||||
// Return TRUE/FALSE to return the soullink/null in soullink()
|
||||
/datum/soul_link/proc/parse_args(mob/living/owner, mob/living/sharer)
|
||||
if(!owner || !sharer)
|
||||
return FALSE
|
||||
soul_owner = owner
|
||||
soul_sharer = sharer
|
||||
LAZYADD(owner.owned_soul_links, src)
|
||||
LAZYADD(sharer.shared_soul_links, src)
|
||||
return TRUE
|
||||
|
||||
// Runs after /living death()
|
||||
// Override this for content.
|
||||
/datum/soul_link/proc/owner_died(gibbed, mob/living/owner)
|
||||
|
||||
// Runs after /living death()
|
||||
// Override this for content.
|
||||
/datum/soul_link/proc/sharer_died(gibbed, mob/living/owner)
|
||||
|
||||
// Quick-use helper.
|
||||
/proc/soul_link(typepath, ...)
|
||||
var/datum/soul_link/S = new typepath()
|
||||
if(S.parse_args(arglist(args.Copy(2, 0))))
|
||||
return S
|
||||
|
||||
|
||||
/////////////////
|
||||
// MULTISHARER //
|
||||
/////////////////
|
||||
// Abstract soullink for use with 1 Owner -> Many Sharer setups
|
||||
/datum/soul_link/multi_sharer
|
||||
var/list/soul_sharers
|
||||
|
||||
/datum/soul_link/multi_sharer/parse_args(mob/living/owner, list/sharers)
|
||||
if(!owner || !LAZYLEN(sharers))
|
||||
return FALSE
|
||||
soul_owner = owner
|
||||
soul_sharers = sharers
|
||||
LAZYADD(owner.owned_soul_links, src)
|
||||
for(var/mob/living/L as anything in sharers)
|
||||
LAZYADD(L.shared_soul_links, src)
|
||||
return TRUE
|
||||
|
||||
/datum/soul_link/multi_sharer/remove_soul_sharer(mob/living/sharer)
|
||||
LAZYREMOVE(soul_sharers, sharer)
|
||||
|
||||
|
||||
/////////////////
|
||||
// SHARED FATE //
|
||||
/////////////////
|
||||
// When the soulowner dies, the soulsharer dies, and vice versa
|
||||
// This is intended for two players(or AI) and two mobs
|
||||
|
||||
/datum/soul_link/shared_fate/owner_died(gibbed, mob/living/owner)
|
||||
if(soul_sharer)
|
||||
soul_sharer.death(gibbed)
|
||||
|
||||
/datum/soul_link/shared_fate/sharer_died(gibbed, mob/living/sharer)
|
||||
if(soul_owner)
|
||||
soul_owner.death(gibbed)
|
||||
|
||||
//////////////
|
||||
// ONE WAY //
|
||||
//////////////
|
||||
// When the soul owner dies, the soul sharer dies, but NOT vice versa.
|
||||
// This is intended for two players (or AI) and two mobs.
|
||||
|
||||
/datum/soul_link/one_way/owner_died(gibbed, mob/living/owner)
|
||||
if(soul_sharer)
|
||||
soul_sharer.dust(FALSE)
|
||||
|
||||
/////////////////
|
||||
// SHARED BODY //
|
||||
/////////////////
|
||||
// When the soulsharer dies, they're placed in the soulowner, who remains alive
|
||||
// If the soulowner dies, the soulsharer is killed and placed into the soulowner (who is still dying)
|
||||
// This one is intended for one player moving between many mobs
|
||||
|
||||
/datum/soul_link/shared_body/owner_died(gibbed, mob/living/owner)
|
||||
if(soul_owner && soul_sharer)
|
||||
if(soul_sharer.mind)
|
||||
soul_sharer.mind.transfer_to(soul_owner)
|
||||
soul_sharer.death(gibbed)
|
||||
|
||||
/datum/soul_link/shared_body/sharer_died(gibbed, mob/living/sharer)
|
||||
if(soul_owner && soul_sharer && soul_sharer.mind)
|
||||
soul_sharer.mind.transfer_to(soul_owner)
|
||||
|
||||
|
||||
|
||||
//////////////////////
|
||||
// REPLACEMENT POOL //
|
||||
//////////////////////
|
||||
// When the owner dies, one of the sharers is placed in the owner's body, fully healed
|
||||
// Sort of a "winner-stays-on" soullink
|
||||
// Gibbing ends it immediately
|
||||
|
||||
/datum/soul_link/multi_sharer/replacement_pool/owner_died(gibbed, mob/living/owner)
|
||||
if(LAZYLEN(soul_sharers) && !gibbed) //let's not put them in some gibs
|
||||
var/list/souls = shuffle(soul_sharers.Copy())
|
||||
for(var/mob/living/L as anything in souls)
|
||||
if(L.stat != DEAD && L.mind)
|
||||
L.mind.transfer_to(soul_owner)
|
||||
soul_owner.revive(TRUE, TRUE)
|
||||
L.death(FALSE)
|
||||
|
||||
// Lose your claim to the throne!
|
||||
/datum/soul_link/multi_sharer/replacement_pool/sharer_died(gibbed, mob/living/sharer)
|
||||
remove_soul_sharer(sharer)
|
||||
|
||||
+41
-41
@@ -1,41 +1,41 @@
|
||||
/datum/sun
|
||||
var/angle
|
||||
var/dx
|
||||
var/dy
|
||||
var/rate
|
||||
var/solar_next_update // last time the sun position was checked and adjusted
|
||||
|
||||
/datum/sun/New()
|
||||
rate = rand(50,200)/100 // 50% - 200% of standard rotation
|
||||
if(prob(50)) // same chance to rotate clockwise than counter-clockwise
|
||||
rate = -rate
|
||||
angle = rand (0,360) // the station position to the sun is randomised at round start
|
||||
|
||||
// calculate the sun's position given the time of day
|
||||
// at the standard rate (100%) the angle is increase/decreased by 6 degrees every minute.
|
||||
// a full rotation thus take a game hour in that case
|
||||
/datum/sun/proc/calc_position()
|
||||
angle = (360 + angle + rate * 6) % 360 // increase/decrease the angle to the sun, adjusted by the rate
|
||||
// now calculate and cache the (dx,dy) increments for line drawing
|
||||
|
||||
var/s = sin(angle)
|
||||
var/c = cos(angle)
|
||||
|
||||
// Either "abs(s) < abs(c)" or "abs(s) >= abs(c)"
|
||||
// In both cases, the greater is greater than 0, so, no "if 0" check is needed for the divisions
|
||||
|
||||
if( abs(s) < abs(c))
|
||||
|
||||
dx = s / abs(c)
|
||||
dy = c / abs(c)
|
||||
|
||||
else
|
||||
dx = s/abs(s)
|
||||
dy = c / abs(s)
|
||||
|
||||
//now tell the solar control computers to update their status and linked devices
|
||||
for(var/obj/machinery/power/solar_control/SC in GLOB.solars_list)
|
||||
if(!SC.powernet)
|
||||
GLOB.solars_list.Remove(SC)
|
||||
continue
|
||||
SC.update()
|
||||
/datum/sun
|
||||
var/angle
|
||||
var/dx
|
||||
var/dy
|
||||
var/rate
|
||||
var/solar_next_update // last time the sun position was checked and adjusted
|
||||
|
||||
/datum/sun/New()
|
||||
rate = rand(50,200)/100 // 50% - 200% of standard rotation
|
||||
if(prob(50)) // same chance to rotate clockwise than counter-clockwise
|
||||
rate = -rate
|
||||
angle = rand (0,360) // the station position to the sun is randomised at round start
|
||||
|
||||
// calculate the sun's position given the time of day
|
||||
// at the standard rate (100%) the angle is increase/decreased by 6 degrees every minute.
|
||||
// a full rotation thus take a game hour in that case
|
||||
/datum/sun/proc/calc_position()
|
||||
angle = (360 + angle + rate * 6) % 360 // increase/decrease the angle to the sun, adjusted by the rate
|
||||
// now calculate and cache the (dx,dy) increments for line drawing
|
||||
|
||||
var/s = sin(angle)
|
||||
var/c = cos(angle)
|
||||
|
||||
// Either "abs(s) < abs(c)" or "abs(s) >= abs(c)"
|
||||
// In both cases, the greater is greater than 0, so, no "if 0" check is needed for the divisions
|
||||
|
||||
if( abs(s) < abs(c))
|
||||
|
||||
dx = s / abs(c)
|
||||
dy = c / abs(c)
|
||||
|
||||
else
|
||||
dx = s/abs(s)
|
||||
dy = c / abs(s)
|
||||
|
||||
//now tell the solar control computers to update their status and linked devices
|
||||
for(var/obj/machinery/power/solar_control/SC in GLOB.solars_list)
|
||||
if(!SC.powernet)
|
||||
GLOB.solars_list.Remove(SC)
|
||||
continue
|
||||
SC.update()
|
||||
|
||||
@@ -1,152 +1,152 @@
|
||||
/datum/supply_pack/voidsuits/explorer
|
||||
name = "Away Team voidsuits"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/exploration = 2,
|
||||
/obj/item/clothing/head/helmet/space/void/exploration = 2,
|
||||
/obj/item/clothing/mask/breath = 2,
|
||||
/obj/item/clothing/shoes/magboots = 2,
|
||||
/obj/item/weapon/tank/oxygen = 2
|
||||
)
|
||||
cost = 45
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containername = "Away Team voidsuit crate"
|
||||
access = list(access_eva, access_explorer)
|
||||
|
||||
/datum/supply_pack/voidsuits/explorer_medic
|
||||
name = "Away Team Medic voidsuits"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/exploration = 2,
|
||||
/obj/item/clothing/head/helmet/space/void/exploration = 2,
|
||||
/obj/item/clothing/mask/breath = 2,
|
||||
/obj/item/clothing/shoes/magboots = 2,
|
||||
/obj/item/weapon/tank/oxygen = 2
|
||||
)
|
||||
cost = 45
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containername = "Away Team Medic voidsuit crate"
|
||||
access = access_medical
|
||||
|
||||
/datum/supply_pack/voidsuits/pilot
|
||||
name = "Pilot voidsuits"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/pilot = 1,
|
||||
/obj/item/clothing/head/helmet/space/void/pilot = 1,
|
||||
/obj/item/clothing/mask/breath = 1,
|
||||
/obj/item/clothing/shoes/magboots = 1,
|
||||
/obj/item/weapon/tank/oxygen = 1
|
||||
)
|
||||
cost = 20
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containername = "Pilot voidsuit crate"
|
||||
access = access_pilot
|
||||
|
||||
|
||||
// Surplus!
|
||||
/datum/supply_pack/voidsuits/com_mining
|
||||
name = "Commonwealth mining voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/mining/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/mining/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth mining voidsuit crate"
|
||||
access = access_mining
|
||||
|
||||
/datum/supply_pack/voidsuits/com_anomaly
|
||||
name = "Commonwealth anomaly suit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/anomaly/alt,
|
||||
/obj/item/clothing/head/helmet/space/anomaly/alt
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth anomaly suit crate"
|
||||
access = access_xenoarch
|
||||
|
||||
/datum/supply_pack/voidsuits/com_riot
|
||||
name = "Commonwealth riot voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/security/riot/alt,
|
||||
/obj/item/clothing/head/helmet/space/void/security/riot/alt
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth riot voidsuit crate"
|
||||
access = access_brig
|
||||
|
||||
/datum/supply_pack/voidsuits/com_pilot
|
||||
name = "Commonwealth pilot voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/pilot/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/pilot/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth pilot voidsuit crate"
|
||||
access = access_pilot
|
||||
|
||||
/datum/supply_pack/voidsuits/com_medical
|
||||
name = "Commonwealth medical voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/medical/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/medical/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth medical voidsuit crate"
|
||||
/datum/supply_pack/voidsuits/com_explore
|
||||
|
||||
name = "Commonwealth exploration voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/exploration/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/exploration/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth exploration voidsuit crate"
|
||||
access = list(access_eva, access_explorer)
|
||||
|
||||
/datum/supply_pack/voidsuits/com_engineer
|
||||
name = "Commonwealth engineering voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/engineering/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/engineering/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth engineering voidsuit crate"
|
||||
access = access_engine
|
||||
|
||||
/datum/supply_pack/voidsuits/com_atmos
|
||||
name = "Commonwealth atmos voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/atmos/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/atmos/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth atmos voidsuit crate"
|
||||
access = access_atmospherics
|
||||
|
||||
/datum/supply_pack/voidsuits/com_captain
|
||||
name = "Commonwealth captain voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/captain/alt,
|
||||
/obj/item/clothing/head/helmet/space/void/captain/alt
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth captain voidsuit crate"
|
||||
access = access_captain
|
||||
|
||||
/datum/supply_pack/voidsuits/csc_breaker
|
||||
name = "Shipbreaker's Industrial Suit (inc. jetpack)"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/salvagecorp_shipbreaker,
|
||||
/obj/item/clothing/head/helmet/space/void/salvagecorp_shipbreaker,
|
||||
/obj/item/weapon/tank/jetpack/breaker
|
||||
)
|
||||
cost = 100
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Coyote Salvage Corp industrial voidsuit crate"
|
||||
/datum/supply_pack/voidsuits/explorer
|
||||
name = "Away Team voidsuits"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/exploration = 2,
|
||||
/obj/item/clothing/head/helmet/space/void/exploration = 2,
|
||||
/obj/item/clothing/mask/breath = 2,
|
||||
/obj/item/clothing/shoes/magboots = 2,
|
||||
/obj/item/weapon/tank/oxygen = 2
|
||||
)
|
||||
cost = 45
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containername = "Away Team voidsuit crate"
|
||||
access = list(access_eva, access_explorer)
|
||||
|
||||
/datum/supply_pack/voidsuits/explorer_medic
|
||||
name = "Away Team Medic voidsuits"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/exploration = 2,
|
||||
/obj/item/clothing/head/helmet/space/void/exploration = 2,
|
||||
/obj/item/clothing/mask/breath = 2,
|
||||
/obj/item/clothing/shoes/magboots = 2,
|
||||
/obj/item/weapon/tank/oxygen = 2
|
||||
)
|
||||
cost = 45
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containername = "Away Team Medic voidsuit crate"
|
||||
access = access_medical
|
||||
|
||||
/datum/supply_pack/voidsuits/pilot
|
||||
name = "Pilot voidsuits"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/pilot = 1,
|
||||
/obj/item/clothing/head/helmet/space/void/pilot = 1,
|
||||
/obj/item/clothing/mask/breath = 1,
|
||||
/obj/item/clothing/shoes/magboots = 1,
|
||||
/obj/item/weapon/tank/oxygen = 1
|
||||
)
|
||||
cost = 20
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containername = "Pilot voidsuit crate"
|
||||
access = access_pilot
|
||||
|
||||
|
||||
// Surplus!
|
||||
/datum/supply_pack/voidsuits/com_mining
|
||||
name = "Commonwealth mining voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/mining/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/mining/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth mining voidsuit crate"
|
||||
access = access_mining
|
||||
|
||||
/datum/supply_pack/voidsuits/com_anomaly
|
||||
name = "Commonwealth anomaly suit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/anomaly/alt,
|
||||
/obj/item/clothing/head/helmet/space/anomaly/alt
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth anomaly suit crate"
|
||||
access = access_xenoarch
|
||||
|
||||
/datum/supply_pack/voidsuits/com_riot
|
||||
name = "Commonwealth riot voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/security/riot/alt,
|
||||
/obj/item/clothing/head/helmet/space/void/security/riot/alt
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth riot voidsuit crate"
|
||||
access = access_brig
|
||||
|
||||
/datum/supply_pack/voidsuits/com_pilot
|
||||
name = "Commonwealth pilot voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/pilot/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/pilot/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth pilot voidsuit crate"
|
||||
access = access_pilot
|
||||
|
||||
/datum/supply_pack/voidsuits/com_medical
|
||||
name = "Commonwealth medical voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/medical/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/medical/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth medical voidsuit crate"
|
||||
/datum/supply_pack/voidsuits/com_explore
|
||||
|
||||
name = "Commonwealth exploration voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/exploration/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/exploration/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth exploration voidsuit crate"
|
||||
access = list(access_eva, access_explorer)
|
||||
|
||||
/datum/supply_pack/voidsuits/com_engineer
|
||||
name = "Commonwealth engineering voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/engineering/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/engineering/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth engineering voidsuit crate"
|
||||
access = access_engine
|
||||
|
||||
/datum/supply_pack/voidsuits/com_atmos
|
||||
name = "Commonwealth atmos voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/atmos/alt2,
|
||||
/obj/item/clothing/head/helmet/space/void/atmos/alt2
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth atmos voidsuit crate"
|
||||
access = access_atmospherics
|
||||
|
||||
/datum/supply_pack/voidsuits/com_captain
|
||||
name = "Commonwealth captain voidsuit"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/captain/alt,
|
||||
/obj/item/clothing/head/helmet/space/void/captain/alt
|
||||
)
|
||||
cost = 150
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Commonwealth captain voidsuit crate"
|
||||
access = access_captain
|
||||
|
||||
/datum/supply_pack/voidsuits/csc_breaker
|
||||
name = "Shipbreaker's Industrial Suit (inc. jetpack)"
|
||||
contains = list(
|
||||
/obj/item/clothing/suit/space/void/salvagecorp_shipbreaker,
|
||||
/obj/item/clothing/head/helmet/space/void/salvagecorp_shipbreaker,
|
||||
/obj/item/weapon/tank/jetpack/breaker
|
||||
)
|
||||
cost = 100
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
name = "Coyote Salvage Corp industrial voidsuit crate"
|
||||
|
||||
@@ -1,254 +1,254 @@
|
||||
/datum/category_item/underwear/undershirt/none
|
||||
is_default = TRUE
|
||||
name = "None"
|
||||
always_last = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt
|
||||
name = "Shirt"
|
||||
icon_state = "undershirt"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_fem
|
||||
name = "Babydoll shirt"
|
||||
icon_state = "undershirt_fem"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_long
|
||||
name = "Longsleeve Shirt"
|
||||
icon_state = "undershirt_long"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_long_s
|
||||
name = "Shirt, button-down"
|
||||
icon_state = "shirt_long_s"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_long_fem
|
||||
name = "Longsleeve Shirt, feminine"
|
||||
icon_state = "undershirt_long_fem"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_long_female_s
|
||||
name = "Button-down Shirt, feminine"
|
||||
icon_state = "shirt_long_female_s"
|
||||
has_color = TRUE
|
||||
|
||||
|
||||
/datum/category_item/underwear/undershirt/fishnet_simple
|
||||
name = "Fishnet shirt"
|
||||
icon_state = "fishnet_simple"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top
|
||||
name = "Tank top"
|
||||
icon_state = "tanktop"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_alt
|
||||
name = "Tank top, alt"
|
||||
icon_state = "tanktop_alt"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_alt_fem
|
||||
name = "Tank top, alt, feminine"
|
||||
icon_state = "tanktop_alt_fem"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_alt_fem_vneck
|
||||
name = "Tank top, feminine, v-neck"
|
||||
icon_state = "tanktop_alt_fem_vneck"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_cropped_vneck
|
||||
name = "Tank top, feminine, cropped & v-neck"
|
||||
icon_state = "tanktop_cropped_vneck"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_fire
|
||||
name = "Tank top, fire"
|
||||
icon_state = "tank_fire_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_fire_fem
|
||||
name = "Tank top, fire, feminine"
|
||||
icon_state = "tank_fire_fem_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_rainbow
|
||||
name = "Tank top, rainbow"
|
||||
icon_state = "tank_rainbow_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_stripes
|
||||
name = "Tank top, striped"
|
||||
icon_state = "tank_stripes_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_sun
|
||||
name = "Tank top, sun"
|
||||
icon_state = "tank_sun_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_heart
|
||||
name = "Shirt, heart"
|
||||
icon_state = "lover_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_heart_fem
|
||||
name = "Shirt, heart, babydoll"
|
||||
icon_state = "lover_fem_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_nt
|
||||
name = "Shirt, NT"
|
||||
icon_state = "shirt_nano_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_love_nt
|
||||
name = "Shirt, I<3NT"
|
||||
icon_state = "ilovent_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_love_nt_fem
|
||||
name = "Shirt, I<3NT, babydoll"
|
||||
icon_state = "ilovent_fem_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shortsleeve_shirt
|
||||
name = "Shortsleeve shirt"
|
||||
icon_state = "shortsleeve"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shortsleeve_shirt_fem
|
||||
name = "Shortsleeve babydoll shirt"
|
||||
icon_state = "shortsleeve_fem"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shortsleeve_shirt_fem_vneck
|
||||
name = "Shortsleeve babydoll shirt, v-neck"
|
||||
icon_state = "shortsleeve_fem_vneck"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/polo_shirt
|
||||
name = "Polo shirt"
|
||||
icon_state = "polo"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/sport_shirt_green
|
||||
name = "Sport shirt, green"
|
||||
icon_state = "greenshirtsport_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/sport_shirt_red
|
||||
name = "Sport shirt, red"
|
||||
icon_state = "redshirtsport_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/sport_shirt_blue
|
||||
name = "Sport shirt, blue"
|
||||
icon_state = "blueshirtsport_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_tiedye
|
||||
name = "Shirt, tiedye"
|
||||
icon_state = "shirt_tiedye_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_blue_striped
|
||||
name = "Shirt, blue stripes"
|
||||
icon_state = "shirt_stripes_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/bowling
|
||||
name = "Bowling Shirt, Red"
|
||||
icon_state = "bowling"
|
||||
|
||||
/datum/category_item/underwear/undershirt/bowlingp
|
||||
name = "Bowling Shirt, Pink"
|
||||
icon_state = "bowlingp"
|
||||
|
||||
/datum/category_item/underwear/undershirt/bowlinga
|
||||
name = "Bowling Shirt, Aqua"
|
||||
icon_state = "bowlinga"
|
||||
|
||||
/datum/category_item/underwear/undershirt/bowlingw
|
||||
name = "Bowling Shirt, White"
|
||||
icon_state = "bowlingw"
|
||||
|
||||
/datum/category_item/underwear/undershirt/longjon
|
||||
name = "Long John Shirt"
|
||||
icon_state = "ljont"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/longstripe_black
|
||||
name = "Longsleeve Striped Shirt, Black"
|
||||
icon_state = "longstripe"
|
||||
|
||||
/datum/category_item/underwear/undershirt/longstripe_blue
|
||||
name = "Longsleeve Striped Shirt, Blue"
|
||||
icon_state = "longstripe_blue"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tiedye
|
||||
name = "Tiedye Shirt"
|
||||
icon_state = "tiedye"
|
||||
|
||||
/datum/category_item/underwear/undershirt/longstripe_pink
|
||||
name = "Longsleeve Striped Shirt, Pink"
|
||||
icon_state = "longstripe_pink_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/wingshirt
|
||||
name = "Pink Wing Shirt"
|
||||
icon_state = "wing_shirt_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/pinkblack_tshirt
|
||||
name = "Pink and Black T-Shirt"
|
||||
icon_state = "pinkblack_tshirt"
|
||||
|
||||
/datum/category_item/underwear/undershirt/turtle
|
||||
name = "Turtleneck, Old"
|
||||
icon_state = "turtleneck_old"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/sleevelessturtle
|
||||
name = "Turtleneck, Sleeveless, Old"
|
||||
icon_state = "turtleneck_sleeveless_old"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/turtleneck
|
||||
name = "Turtleneck"
|
||||
icon_state = "turtleneck"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/turtleneck_smooth
|
||||
name = "Turtleneck, Smooth"
|
||||
icon_state = "turtleneck_smooth"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/turtlesleeveless
|
||||
name = "Turtleneck, Sleeveless"
|
||||
icon_state = "turtleneck_sleeveless"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/leotardturtle
|
||||
name = "Leotard Turtleneck"
|
||||
icon_state = "leotard_turtleneck"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/leotardturtlesleeveless
|
||||
name = "Leotard Turtleneck, Sleeveless"
|
||||
icon_state = "leotard_turtleneck_sleeveless"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/dress_shirt_fem
|
||||
name = "Dress shirt, feminine"
|
||||
icon_state = "undershirt_dress_fem"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/dress_shirt
|
||||
name = "Dress shirt, masculine"
|
||||
icon_state = "undershirt_dress"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/midriff
|
||||
name = "Tanktop, midriff"
|
||||
icon_state = "tank_midriff"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/midriffshort
|
||||
name = "Tanktop, midriff, short"
|
||||
icon_state = "tank_midriff_short"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shibari
|
||||
name = "Shibari Binding"
|
||||
icon_state = "shibari"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/leotard
|
||||
name = "Leotard"
|
||||
icon_state = "leotard"
|
||||
has_color = TRUE
|
||||
/datum/category_item/underwear/undershirt/none
|
||||
is_default = TRUE
|
||||
name = "None"
|
||||
always_last = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt
|
||||
name = "Shirt"
|
||||
icon_state = "undershirt"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_fem
|
||||
name = "Babydoll shirt"
|
||||
icon_state = "undershirt_fem"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_long
|
||||
name = "Longsleeve Shirt"
|
||||
icon_state = "undershirt_long"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_long_s
|
||||
name = "Shirt, button-down"
|
||||
icon_state = "shirt_long_s"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_long_fem
|
||||
name = "Longsleeve Shirt, feminine"
|
||||
icon_state = "undershirt_long_fem"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_long_female_s
|
||||
name = "Button-down Shirt, feminine"
|
||||
icon_state = "shirt_long_female_s"
|
||||
has_color = TRUE
|
||||
|
||||
|
||||
/datum/category_item/underwear/undershirt/fishnet_simple
|
||||
name = "Fishnet shirt"
|
||||
icon_state = "fishnet_simple"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top
|
||||
name = "Tank top"
|
||||
icon_state = "tanktop"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_alt
|
||||
name = "Tank top, alt"
|
||||
icon_state = "tanktop_alt"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_alt_fem
|
||||
name = "Tank top, alt, feminine"
|
||||
icon_state = "tanktop_alt_fem"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_alt_fem_vneck
|
||||
name = "Tank top, feminine, v-neck"
|
||||
icon_state = "tanktop_alt_fem_vneck"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_cropped_vneck
|
||||
name = "Tank top, feminine, cropped & v-neck"
|
||||
icon_state = "tanktop_cropped_vneck"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_fire
|
||||
name = "Tank top, fire"
|
||||
icon_state = "tank_fire_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_fire_fem
|
||||
name = "Tank top, fire, feminine"
|
||||
icon_state = "tank_fire_fem_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_rainbow
|
||||
name = "Tank top, rainbow"
|
||||
icon_state = "tank_rainbow_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_stripes
|
||||
name = "Tank top, striped"
|
||||
icon_state = "tank_stripes_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tank_top_sun
|
||||
name = "Tank top, sun"
|
||||
icon_state = "tank_sun_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_heart
|
||||
name = "Shirt, heart"
|
||||
icon_state = "lover_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_heart_fem
|
||||
name = "Shirt, heart, babydoll"
|
||||
icon_state = "lover_fem_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_nt
|
||||
name = "Shirt, NT"
|
||||
icon_state = "shirt_nano_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_love_nt
|
||||
name = "Shirt, I<3NT"
|
||||
icon_state = "ilovent_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_love_nt_fem
|
||||
name = "Shirt, I<3NT, babydoll"
|
||||
icon_state = "ilovent_fem_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shortsleeve_shirt
|
||||
name = "Shortsleeve shirt"
|
||||
icon_state = "shortsleeve"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shortsleeve_shirt_fem
|
||||
name = "Shortsleeve babydoll shirt"
|
||||
icon_state = "shortsleeve_fem"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shortsleeve_shirt_fem_vneck
|
||||
name = "Shortsleeve babydoll shirt, v-neck"
|
||||
icon_state = "shortsleeve_fem_vneck"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/polo_shirt
|
||||
name = "Polo shirt"
|
||||
icon_state = "polo"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/sport_shirt_green
|
||||
name = "Sport shirt, green"
|
||||
icon_state = "greenshirtsport_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/sport_shirt_red
|
||||
name = "Sport shirt, red"
|
||||
icon_state = "redshirtsport_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/sport_shirt_blue
|
||||
name = "Sport shirt, blue"
|
||||
icon_state = "blueshirtsport_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_tiedye
|
||||
name = "Shirt, tiedye"
|
||||
icon_state = "shirt_tiedye_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/shirt_blue_striped
|
||||
name = "Shirt, blue stripes"
|
||||
icon_state = "shirt_stripes_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/bowling
|
||||
name = "Bowling Shirt, Red"
|
||||
icon_state = "bowling"
|
||||
|
||||
/datum/category_item/underwear/undershirt/bowlingp
|
||||
name = "Bowling Shirt, Pink"
|
||||
icon_state = "bowlingp"
|
||||
|
||||
/datum/category_item/underwear/undershirt/bowlinga
|
||||
name = "Bowling Shirt, Aqua"
|
||||
icon_state = "bowlinga"
|
||||
|
||||
/datum/category_item/underwear/undershirt/bowlingw
|
||||
name = "Bowling Shirt, White"
|
||||
icon_state = "bowlingw"
|
||||
|
||||
/datum/category_item/underwear/undershirt/longjon
|
||||
name = "Long John Shirt"
|
||||
icon_state = "ljont"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/longstripe_black
|
||||
name = "Longsleeve Striped Shirt, Black"
|
||||
icon_state = "longstripe"
|
||||
|
||||
/datum/category_item/underwear/undershirt/longstripe_blue
|
||||
name = "Longsleeve Striped Shirt, Blue"
|
||||
icon_state = "longstripe_blue"
|
||||
|
||||
/datum/category_item/underwear/undershirt/tiedye
|
||||
name = "Tiedye Shirt"
|
||||
icon_state = "tiedye"
|
||||
|
||||
/datum/category_item/underwear/undershirt/longstripe_pink
|
||||
name = "Longsleeve Striped Shirt, Pink"
|
||||
icon_state = "longstripe_pink_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/wingshirt
|
||||
name = "Pink Wing Shirt"
|
||||
icon_state = "wing_shirt_s"
|
||||
|
||||
/datum/category_item/underwear/undershirt/pinkblack_tshirt
|
||||
name = "Pink and Black T-Shirt"
|
||||
icon_state = "pinkblack_tshirt"
|
||||
|
||||
/datum/category_item/underwear/undershirt/turtle
|
||||
name = "Turtleneck, Old"
|
||||
icon_state = "turtleneck_old"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/sleevelessturtle
|
||||
name = "Turtleneck, Sleeveless, Old"
|
||||
icon_state = "turtleneck_sleeveless_old"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/turtleneck
|
||||
name = "Turtleneck"
|
||||
icon_state = "turtleneck"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/turtleneck_smooth
|
||||
name = "Turtleneck, Smooth"
|
||||
icon_state = "turtleneck_smooth"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/turtlesleeveless
|
||||
name = "Turtleneck, Sleeveless"
|
||||
icon_state = "turtleneck_sleeveless"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/leotardturtle
|
||||
name = "Leotard Turtleneck"
|
||||
icon_state = "leotard_turtleneck"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/leotardturtlesleeveless
|
||||
name = "Leotard Turtleneck, Sleeveless"
|
||||
icon_state = "leotard_turtleneck_sleeveless"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/dress_shirt_fem
|
||||
name = "Dress shirt, feminine"
|
||||
icon_state = "undershirt_dress_fem"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/dress_shirt
|
||||
name = "Dress shirt, masculine"
|
||||
icon_state = "undershirt_dress"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/midriff
|
||||
name = "Tanktop, midriff"
|
||||
icon_state = "tank_midriff"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/midriffshort
|
||||
name = "Tanktop, midriff, short"
|
||||
icon_state = "tank_midriff_short"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/shibari
|
||||
name = "Shibari Binding"
|
||||
icon_state = "shibari"
|
||||
has_color = TRUE
|
||||
|
||||
/datum/category_item/underwear/undershirt/leotard
|
||||
name = "Leotard"
|
||||
icon_state = "leotard"
|
||||
has_color = TRUE
|
||||
|
||||
Reference in New Issue
Block a user