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 commit afbdd1d844.

* 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 commit de22ad375d.

* Attempt to normalize example.yml (and another file I guess)

* Try again
This commit is contained in:
Drathek
2024-02-20 02:28:51 -08:00
committed by GitHub
parent 3b61f677b3
commit 7c8bb85de3
1175 changed files with 818171 additions and 818145 deletions
+293 -293
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -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.
+87 -87
View File
@@ -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
+42 -42
View File
@@ -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
+160 -160
View File
@@ -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
+66 -66
View File
@@ -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
+84 -84
View File
@@ -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>"))
+233 -233
View File
@@ -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
+59 -59
View File
@@ -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
+126 -126
View File
@@ -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)
+44 -44
View File
@@ -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])
+117 -117
View File
@@ -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
+175 -175
View File
@@ -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
+97 -97
View File
@@ -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()
+146 -146
View File
@@ -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)
+161 -161
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+63 -63
View File
@@ -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
+16 -16
View File
@@ -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
+74 -74
View File
@@ -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
+18 -18
View File
@@ -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
View File
@@ -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
View File
@@ -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()
+152 -152
View File
@@ -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"
+254 -254
View File
@@ -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