12/21 modernizations from TG live (#103)

* sync (#3)

* shuttle auto call

* Merge /vore into /master (#39)

* progress

* Compile errors fixed

No idea if it's test worthy tho as conflicts with race overhaul and
narky removal.

* Update admins.txt

* efforts continue

Fuck grab code, seriously

* grab code is cancer

* Execute the Narkism

Do not hesitate.

Show no mercy.

* holy shit grab code is awful

* have I bitched about grab code

My bitching, let me show you it

* código de agarre es una mierda

No really it is

* yeah I don't even know anymore.

* Lolnope. Fuck grab code

* I'm not even sure what to fix anymore

* Self eating is not an acceptable fate

* Taste the void, son.

* My code doesn't pass it's own sanity check.

Maybe it's a sign of things to come.

* uncommented and notes

* It Works and I Don't Know Why (#38)

* shuttle auto call

* it works and I don't know why

* Subsystem 12/21

Most Recent TG subsystem folder

* globalvars 12/21

Tossed out the flavor_misc and parallax files

* Onclick 12/21

as well as .dme updates

* _defines 12/21

ommited old _MC.dm

* _HELPERS 12/21

Preserved snowflake placement of furry sprites

* _defeines/genetics

reapplied narkism holdover for snowflake races.

* Oops forgot mutant colors

* modules porting 12/21 + Sounds/icons

Admin, Client and most of mob life files ommitted

* enviroment file

* Admin optimizations

ahelp log system kept

* Mob ports 12/21

Flavor text preserved

* datums ported 12/21

* Game ported 12/21

* batch of duplicate fixes/dogborg work

Dogborgs need to be modernized to refractored borg standards.

* moar fixes

* Maps and futher compile fixes
This commit is contained in:
Poojawa
2016-12-22 03:57:55 -06:00
committed by GitHub
parent f5e143a452
commit cf59ac1c3d
2215 changed files with 707445 additions and 87041 deletions
+15 -6
View File
@@ -30,7 +30,11 @@
if(!M.viewing_alternate_appearances)
M.viewing_alternate_appearances = list()
viewers |= M
M.viewing_alternate_appearances[key] = src
var/list/AAsiblings = M.viewing_alternate_appearances[key]
if(!AAsiblings)
AAsiblings = list()
M.viewing_alternate_appearances[key] = AAsiblings
AAsiblings |= src
if(M.client)
M.client.images |= img
@@ -48,9 +52,13 @@
if(M.client)
M.client.images -= img
if(M.viewing_alternate_appearances && M.viewing_alternate_appearances.len)
M.viewing_alternate_appearances -= key
if(!M.viewing_alternate_appearances.len)
M.viewing_alternate_appearances = null
var/list/AAsiblings = M.viewing_alternate_appearances[key]
if(AAsiblings)
AAsiblings -= src
if(!AAsiblings.len)
M.viewing_alternate_appearances -= key
if(!M.viewing_alternate_appearances.len)
M.viewing_alternate_appearances = null
viewers -= M
@@ -73,8 +81,9 @@
/atom
var/list/alternate_appearances //the alternate appearances we own
var/list/viewing_alternate_appearances //the alternate appearances we're viewing, stored here to reestablish them after Logout()s
//these lists are built/destroyed as necessary, so atoms aren't all lugging around lists full of datums
var/list/viewing_alternate_appearances //this is an assoc list of lists, the keys being the AA's key
//inside these lists are the AAs themselves, this is to allow the atom to see multiple of the same type of AA
//eg: two (or more) people disguised as cardborgs, or two (or more) people disguised as plants
/*
Builds an alternate_appearance datum for the supplied args, optionally displaying it straight away
+48 -724
View File
@@ -14,74 +14,13 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
*/
/area
level = null
name = "Space"
icon = 'icons/turf/areas.dmi'
icon_state = "unknown"
layer = AREA_LAYER
mouse_opacity = 0
invisibility = INVISIBILITY_LIGHTING
var/map_name // Set in New(); preserves the name set by the map maker, even if renamed by the Blueprints.
var/valid_territory = 1 // If it's a valid territory for gangs to claim
var/blob_allowed = 1 // Does it count for blobs score? By default, all areas count.
var/eject = null
var/fire = null
var/atmos = 1
var/atmosalm = 0
var/poweralm = 1
var/party = null
var/lightswitch = 1
var/requires_power = 1
var/always_unpowered = 0 // This gets overriden to 1 for space in area/New().
var/outdoors = 0 //For space, the asteroid, lavaland, etc. Used with blueprints to determine if we are adding a new area (vs editing a station room)
var/power_equip = 1
var/power_light = 1
var/power_environ = 1
var/music = null
var/used_equip = 0
var/used_light = 0
var/used_environ = 0
var/static_equip
var/static_light = 0
var/static_environ
var/has_gravity = 0
var/noteleport = 0 //Are you forbidden from teleporting to the area? (centcomm, mobs, wizard, hand teleporter)
var/safe = 0 //Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
var/no_air = null
var/area/master // master area used for power calcluations
var/list/related // the other areas of the same type as this
// var/list/lights // list of all lights on this area
/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
var/list/teleportlocs = list()
/proc/process_teleport_locs()
for(var/area/AR in world)
if(istype(AR, /area/shuttle) || istype(AR, /area/wizard_station) || AR.noteleport) continue
if(teleportlocs.Find(AR.name)) continue
var/turf/picked = safepick(get_area_turfs(AR.type))
if (picked && (picked.z == ZLEVEL_STATION))
teleportlocs += AR.name
teleportlocs[AR.name] = AR
sortTim(teleportlocs, /proc/cmp_text_dsc)
/*-----------------------------------------------------------------------------*/
/area/engine/
/area/engine
/area/turret_protected/
/area/ai_monitored //stub defined ai_monitored.dm
/area/ai_monitored/turret_protected
/area/arrival
requires_power = 0
@@ -98,122 +37,27 @@ var/list/teleportlocs = list()
icon_state = "space"
requires_power = 1
always_unpowered = 1
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
lighting_use_dynamic = DYNAMIC_LIGHTING_DISABLED
power_light = 0
power_equip = 0
power_environ = 0
valid_territory = 0
outdoors = 1
ambientsounds = list('sound/ambience/ambispace.ogg','sound/ambience/title3.ogg',)
ambientsounds = list('sound/ambience/ambispace.ogg','sound/ambience/title2.ogg')
blob_allowed = 0 //Eating up space doesn't count for victory as a blob.
/area/space/nearstation
icon_state = "space_near"
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
//These are shuttle areas; all subtypes are only used as teleportation markers, they have no actual function beyond that.
/area/shuttle
name = "Shuttle"
requires_power = 0
luminosity = 1
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
has_gravity = 1
valid_territory = 0
icon_state = "shuttle"
/area/shuttle/arrival
name = "Arrival Shuttle"
/area/shuttle/pod_1
name = "Escape Pod One"
/area/shuttle/pod_2
name = "Escape Pod Two"
/area/shuttle/pod_3
name = "Escape Pod Three"
/area/shuttle/pod_4
name = "Escape Pod Four"
/area/shuttle/mining
name = "Mining Shuttle"
/area/shuttle/labor
name = "Labor Camp Shuttle"
/area/shuttle/supply
name = "Supply Shuttle"
/area/shuttle/escape
name = "Emergency Shuttle"
/area/shuttle/transport
name = "Transport Shuttle"
/area/shuttle/syndicate
name = "Syndicate Infiltrator"
/area/shuttle/assault_pod
name = "Steel Rain"
/area/shuttle/abandoned
name = "Abandoned Ship"
lighting_use_dynamic = DYNAMIC_LIGHTING_IFSTARLIGHT
/area/start
name = "start area"
icon_state = "start"
requires_power = 0
luminosity = 1
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
lighting_use_dynamic = DYNAMIC_LIGHTING_DISABLED
has_gravity = 1
// CENTCOM
/area/centcom
name = "Centcom"
icon_state = "centcom"
requires_power = 0
has_gravity = 1
noteleport = 1
blob_allowed = 0 //Should go without saying, no blobs should take over centcom as a win condition.
/area/centcom/control
name = "Centcom Docks"
/area/centcom/evac
name = "Centcom Recovery Ship"
/area/centcom/supply
name = "Centcom Supply Shuttle Dock"
/area/centcom/ferry
name = "Centcom Transport Shuttle Dock"
/area/centcom/prison
name = "Admin Prison"
/area/centcom/holding
name = "Holding Facility"
//SYNDICATES
/area/syndicate_mothership
name = "Syndicate Mothership"
icon_state = "syndie-ship"
requires_power = 0
has_gravity = 1
noteleport = 1
blob_allowed = 0 //Not... entirely sure this will ever come up... but if the bus makes blobs AND ops, it shouldn't aim for the ops to win.
/area/syndicate_mothership/control
name = "Syndicate Control Room"
icon_state = "syndie-control"
/area/syndicate_mothership/elite_squad
name = "Syndicate Elite Squad"
icon_state = "syndie-elite"
//EXTRA
@@ -237,7 +81,7 @@ var/list/teleportlocs = list()
/area/asteroid/artifactroom/New()
..()
dynamic_lighting = TRUE
SetDynamicLighting()
/area/planet/clown
name = "Clown Planet"
@@ -249,144 +93,13 @@ var/list/teleportlocs = list()
icon_state = "telesci"
requires_power = 0
/area/tdome
name = "Thunderdome"
icon_state = "yellow"
requires_power = 0
has_gravity = 1
/area/tdome/arena
name = "Thunderdome Arena"
icon_state = "thunder"
/area/tdome/arena_source
name = "Thunderdome Arena Template"
icon_state = "thunder"
/area/tdome/tdome1
name = "Thunderdome (Team 1)"
icon_state = "green"
/area/tdome/tdome2
name = "Thunderdome (Team 2)"
icon_state = "green"
/area/tdome/tdomeadmin
name = "Thunderdome (Admin.)"
icon_state = "purple"
/area/tdome/tdomeobserve
name = "Thunderdome (Observer.)"
icon_state = "purple"
//ENEMY
/area/wizard_station
name = "Wizard's Den"
icon_state = "yellow"
requires_power = 0
has_gravity = 1
noteleport = 1
//Abductors
/area/abductor_ship
name = "Abductor Ship"
icon_state = "yellow"
requires_power = 0
noteleport = 1
has_gravity = 1
//PRISON
/area/prison
name = "Prison Station"
icon_state = "brig"
/area/prison/arrival_airlock
name = "Prison Station Airlock"
icon_state = "green"
requires_power = 0
/area/prison/control
name = "Prison Security Checkpoint"
icon_state = "security"
/area/prison/crew_quarters
name = "Prison Security Quarters"
icon_state = "security"
/area/prison/rec_room
name = "Prison Rec Room"
icon_state = "green"
/area/prison/closet
name = "Prison Supply Closet"
icon_state = "dk_yellow"
/area/prison/hallway/fore
name = "Prison Fore Hallway"
icon_state = "yellow"
/area/prison/hallway/aft
name = "Prison Aft Hallway"
icon_state = "yellow"
/area/prison/hallway/port
name = "Prison Port Hallway"
icon_state = "yellow"
/area/prison/hallway/starboard
name = "Prison Starboard Hallway"
icon_state = "yellow"
/area/prison/morgue
name = "Prison Morgue"
icon_state = "morgue"
ambientsounds = list('sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg')
/area/prison/medical_research
name = "Prison Genetic Research"
icon_state = "medresearch"
/area/prison/medical
name = "Prison Medbay"
icon_state = "medbay"
/area/prison/solar
name = "Prison Solar Array"
icon_state = "storage"
requires_power = 0
/area/prison/podbay
name = "Prison Podbay"
icon_state = "dk_yellow"
/area/prison/solar_control
name = "Prison Solar Array Control"
icon_state = "dk_yellow"
/area/prison/solitary
name = "Solitary Confinement"
icon_state = "brig"
/area/prison/cell_block/A
name = "Prison Cell Block A"
icon_state = "brig"
/area/prison/cell_block/B
name = "Prison Cell Block B"
icon_state = "brig"
/area/prison/cell_block/C
name = "Prison Cell Block C"
icon_state = "brig"
//STATION13
/area/atmos
name = "Atmospherics"
icon_state = "atmos"
flags = NONE
//Maintenance
/area/maintenance
@@ -608,11 +321,15 @@ var/list/teleportlocs = list()
/area/library
name = "Library"
icon_state = "library"
flags = NONE
/area/chapel
icon_state = "chapel"
ambientsounds = list('sound/ambience/ambicha1.ogg','sound/ambience/ambicha2.ogg','sound/ambience/ambicha3.ogg','sound/ambience/ambicha4.ogg')
flags = NONE
/area/chapel/main
name = "Chapel"
icon_state = "chapel"
ambientsounds = list('sound/ambience/ambicha1.ogg','sound/ambience/ambicha2.ogg','sound/ambience/ambicha3.ogg','sound/ambience/ambicha4.ogg')
/area/chapel/office
name = "Chapel Office"
@@ -656,8 +373,10 @@ var/list/teleportlocs = list()
/area/solar
requires_power = 0
luminosity = 1
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
lighting_use_dynamic = DYNAMIC_LIGHTING_IFSTARLIGHT
valid_territory = 0
blob_allowed = FALSE
flags = NONE
/area/solar/auxport
name = "Fore Port Solar Array"
@@ -731,12 +450,6 @@ var/list/teleportlocs = list()
icon_state = "teleporter"
music = "signal"
/area/AIsattele
name = "Abandoned Teleporter"
icon_state = "teleporter"
music = "signal"
ambientsounds = list('sound/ambience/ambimalf.ogg')
//MedBay
/area/medical/medbay
@@ -774,6 +487,7 @@ var/list/teleportlocs = list()
/area/medical/virology
name = "Virology"
icon_state = "virology"
flags = NONE
/area/medical/morgue
name = "Morgue"
@@ -851,22 +565,6 @@ var/list/teleportlocs = list()
name = "Transfer Centre"
icon_state = "armory"
/*
/area/security/transfer/New()
..()
spawn(10) //let objects set up first
for(var/turf/turfToGrayscale in src)
if(turfToGrayscale.icon)
var/icon/newIcon = icon(turfToGrayscale.icon)
newIcon.GrayScale()
turfToGrayscale.icon = newIcon
for(var/obj/objectToGrayscale in turfToGrayscale) //1 level deep, means tables, apcs, locker, etc, but not locker contents
if(objectToGrayscale.icon)
var/icon/newIcon = icon(objectToGrayscale.icon)
newIcon.GrayScale()
objectToGrayscale.icon = newIcon
*/
/area/security/nuke_storage
name = "Vault"
@@ -944,9 +642,10 @@ var/list/teleportlocs = list()
name = "Mech Bay"
icon_state = "yellow"
/area/janitor/
/area/janitor
name = "Custodial Closet"
icon_state = "janitor"
flags = NONE
/area/hydroponics
name = "Hydroponics"
@@ -1038,119 +737,6 @@ var/list/teleportlocs = list()
name = "Test Room"
icon_state = "storage"
//DJSTATION
/area/djstation
name = "Ruskie DJ Station"
icon_state = "DJ"
has_gravity = 1
blob_allowed = 0 //Nope, no winning on the DJ station as a blob. Gotta eat the main station.
/area/djstation/solars
name = "DJ Station Solars"
icon_state = "DJ"
has_gravity = 1
//DERELICT
/area/derelict
name = "Derelict Station"
icon_state = "storage"
blob_allowed = 0 //Nope, no winning on the derelict as a blob. Gotta eat the station.
/area/derelict/hallway/primary
name = "Derelict Primary Hallway"
icon_state = "hallP"
/area/derelict/hallway/secondary
name = "Derelict Secondary Hallway"
icon_state = "hallS"
/area/derelict/arrival
name = "Derelict Arrival Centre"
icon_state = "yellow"
/area/derelict/storage/equipment
name = "Derelict Equipment Storage"
/area/derelict/storage/storage_access
name = "Derelict Storage Access"
/area/derelict/storage/engine_storage
name = "Derelict Engine Storage"
icon_state = "green"
/area/derelict/bridge
name = "Derelict Control Room"
icon_state = "bridge"
/area/derelict/secret
name = "Derelict Secret Room"
icon_state = "library"
/area/derelict/bridge/access
name = "Derelict Control Room Access"
icon_state = "auxstorage"
/area/derelict/bridge/ai_upload
name = "Derelict Computer Core"
icon_state = "ai"
/area/derelict/solar_control
name = "Derelict Solar Control"
icon_state = "engine"
/area/derelict/se_solar
name = "South East Solars"
icon_state = "engine"
/area/derelict/crew_quarters
name = "Derelict Crew Quarters"
icon_state = "fitness"
/area/derelict/medical
name = "Derelict Medbay"
icon_state = "medbay"
/area/derelict/medical/morgue
name = "Derelict Morgue"
icon_state = "morgue"
/area/derelict/medical/chapel
name = "Derelict Chapel"
icon_state = "chapel"
/area/derelict/teleporter
name = "Derelict Teleporter"
icon_state = "teleporter"
/area/derelict/eva
name = "Derelict EVA Storage"
icon_state = "eva"
/area/derelict/ship
name = "Abandoned Ship"
icon_state = "yellow"
/area/solar/derelict_starboard
name = "Derelict Starboard Solar Array"
icon_state = "panelsS"
/area/solar/derelict_aft
name = "Derelict Aft Solar Array"
icon_state = "yellow"
/area/derelict/singularity_engine
name = "Derelict Singularity Engine"
icon_state = "engine"
/area/derelict/gravity_generator
name = "Derelict Gravity Generator Room"
icon_state = "red"
/area/derelict/atmospherics
name = "Derelict Atmospherics"
icon_state = "red"
//Construction
@@ -1158,6 +744,10 @@ var/list/teleportlocs = list()
name = "Construction Area"
icon_state = "yellow"
/area/mining_construction
name = "Auxillary Base Construction"
icon_state = "yellow"
/area/construction/supplyshuttle
name = "Supply Shuttle"
icon_state = "yellow"
@@ -1208,22 +798,22 @@ var/list/teleportlocs = list()
icon_state = "storage"
/area/turret_protected/
/area/ai_monitored/turret_protected
ambientsounds = list('sound/ambience/ambimalf.ogg')
/area/turret_protected/ai_upload
/area/ai_monitored/turret_protected/ai_upload
name = "AI Upload Chamber"
icon_state = "ai_upload"
/area/turret_protected/ai_upload_foyer
/area/ai_monitored/turret_protected/ai_upload_foyer
name = "AI Upload Access"
icon_state = "ai_foyer"
/area/turret_protected/ai
/area/ai_monitored/turret_protected/ai
name = "AI Chamber"
icon_state = "ai_chamber"
/area/turret_protected/aisat
/area/ai_monitored/turret_protected/aisat
name = "AI Satellite"
icon_state = "ai"
@@ -1231,66 +821,40 @@ var/list/teleportlocs = list()
name = "AI Satellite Exterior"
icon_state = "yellow"
/area/turret_protected/aisat_interior
/area/ai_monitored/turret_protected/aisat_interior
name = "AI Satellite Antechamber"
icon_state = "ai"
/area/turret_protected/AIsatextFP
/area/ai_monitored/turret_protected/AIsatextFP
name = "AI Sat Ext"
icon_state = "storage"
luminosity = 1
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
lighting_use_dynamic = DYNAMIC_LIGHTING_IFSTARLIGHT
/area/turret_protected/AIsatextFS
/area/ai_monitored/turret_protected/AIsatextFS
name = "AI Sat Ext"
icon_state = "storage"
luminosity = 1
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
lighting_use_dynamic = DYNAMIC_LIGHTING_IFSTARLIGHT
/area/turret_protected/AIsatextAS
/area/ai_monitored/turret_protected/AIsatextAS
name = "AI Sat Ext"
icon_state = "storage"
luminosity = 1
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
lighting_use_dynamic = DYNAMIC_LIGHTING_IFSTARLIGHT
/area/turret_protected/AIsatextAP
/area/ai_monitored/turret_protected/AIsatextAP
name = "AI Sat Ext"
icon_state = "storage"
luminosity = 1
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
lighting_use_dynamic = DYNAMIC_LIGHTING_IFSTARLIGHT
/area/turret_protected/NewAIMain
/area/ai_monitored/turret_protected/NewAIMain
name = "AI Main New"
icon_state = "storage"
//Misc
/area/wreck/ai
name = "AI Chamber"
icon_state = "ai"
/area/wreck/main
name = "Wreck"
icon_state = "storage"
/area/wreck/engineering
name = "Power Room"
icon_state = "engine"
/area/wreck/bridge
name = "Bridge"
icon_state = "bridge"
/area/generic
name = "Unknown"
icon_state = "storage"
// Telecommunications Satellite
/area/tcommsat
@@ -1304,22 +868,22 @@ var/list/teleportlocs = list()
name = "Abandoned Satellite"
icon_state = "tcomsatcham"
/area/turret_protected/tcomsat
/area/ai_monitored/turret_protected/tcomsat
name = "Telecoms Satellite"
icon_state = "tcomsatlob"
ambientsounds = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
/area/turret_protected/tcomfoyer
/area/ai_monitored/turret_protected/tcomfoyer
name = "Telecoms Foyer"
icon_state = "tcomsatentrance"
ambientsounds = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
/area/turret_protected/tcomwest
/area/ai_monitored/turret_protected/tcomwest
name = "Telecommunications Satellite West Wing"
icon_state = "tcomsatwest"
ambientsounds = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
/area/turret_protected/tcomeast
/area/ai_monitored/turret_protected/tcomeast
name = "Telecommunications Satellite East Wing"
icon_state = "tcomsateast"
ambientsounds = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
@@ -1337,246 +901,6 @@ var/list/teleportlocs = list()
icon_state = "tcomsatlounge"
// Hell
/area/hell
name = "Hell Lobby"
//icon = "ICON FILENAME"
//icon_state = "NAME OF ICON"
requires_power = 0
music = "music/music.ogg"
/area/hell/trial1
name = "Hell Trial1"
//icon_state = "NAME OF ICON" (defaults to "unknown" (blank))
/area/hell/trial1
name = "Hell Trial2"
//icon_state = "NAME OF ICON" (defaults to "unknown" (blank))
/area/hell/trial1
name = "Hell Trial3"
//icon_state = "NAME OF ICON" (defaults to "unknown" (blank))
// Away Missions
/area/awaymission
name = "Strange Location"
icon_state = "away"
has_gravity = 1
/area/awaymission/example
name = "Strange Station"
icon_state = "away"
/area/awaymission/desert
name = "Mars"
icon_state = "away"
/area/awaymission/listeningpost
name = "Listening Post"
icon_state = "away"
requires_power = 0
/area/awaymission/beach
name = "Beach"
icon_state = "away"
luminosity = 1
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
requires_power = 0
has_gravity = 1
ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg')
/area/spacecontent
name = "space"
/area/spacecontent/a1
icon_state = "spacecontent1"
/area/spacecontent/a2
icon_state = "spacecontent2"
/area/spacecontent/a3
icon_state = "spacecontent3"
/area/spacecontent/a4
icon_state = "spacecontent4"
/area/spacecontent/a5
icon_state = "spacecontent5"
/area/spacecontent/a6
icon_state = "spacecontent6"
/area/spacecontent/a7
icon_state = "spacecontent7"
/area/spacecontent/a8
icon_state = "spacecontent8"
/area/spacecontent/a9
icon_state = "spacecontent9"
/area/spacecontent/a10
icon_state = "spacecontent10"
/area/spacecontent/a11
icon_state = "spacecontent11"
/area/spacecontent/a11
icon_state = "spacecontent12"
/area/spacecontent/a12
icon_state = "spacecontent13"
/area/spacecontent/a13
icon_state = "spacecontent14"
/area/spacecontent/a14
icon_state = "spacecontent14"
/area/spacecontent/a15
icon_state = "spacecontent15"
/area/spacecontent/a16
icon_state = "spacecontent16"
/area/spacecontent/a17
icon_state = "spacecontent17"
/area/spacecontent/a18
icon_state = "spacecontent18"
/area/spacecontent/a19
icon_state = "spacecontent19"
/area/spacecontent/a20
icon_state = "spacecontent20"
/area/spacecontent/a21
icon_state = "spacecontent21"
/area/spacecontent/a22
icon_state = "spacecontent22"
/area/spacecontent/a23
icon_state = "spacecontent23"
/area/spacecontent/a24
icon_state = "spacecontent24"
/area/spacecontent/a25
icon_state = "spacecontent25"
/area/spacecontent/a26
icon_state = "spacecontent26"
/area/spacecontent/a27
icon_state = "spacecontent27"
/area/spacecontent/a28
icon_state = "spacecontent28"
/area/spacecontent/a29
icon_state = "spacecontent29"
/area/spacecontent/a30
icon_state = "spacecontent30"
/area/awaycontent
name = "space"
/area/awaycontent/a1
icon_state = "awaycontent1"
/area/awaycontent/a2
icon_state = "awaycontent2"
/area/awaycontent/a3
icon_state = "awaycontent3"
/area/awaycontent/a4
icon_state = "awaycontent4"
/area/awaycontent/a5
icon_state = "awaycontent5"
/area/awaycontent/a6
icon_state = "awaycontent6"
/area/awaycontent/a7
icon_state = "awaycontent7"
/area/awaycontent/a8
icon_state = "awaycontent8"
/area/awaycontent/a9
icon_state = "awaycontent9"
/area/awaycontent/a10
icon_state = "awaycontent10"
/area/awaycontent/a11
icon_state = "awaycontent11"
/area/awaycontent/a11
icon_state = "awaycontent12"
/area/awaycontent/a12
icon_state = "awaycontent13"
/area/awaycontent/a13
icon_state = "awaycontent14"
/area/awaycontent/a14
icon_state = "awaycontent14"
/area/awaycontent/a15
icon_state = "awaycontent15"
/area/awaycontent/a16
icon_state = "awaycontent16"
/area/awaycontent/a17
icon_state = "awaycontent17"
/area/awaycontent/a18
icon_state = "awaycontent18"
/area/awaycontent/a19
icon_state = "awaycontent19"
/area/awaycontent/a20
icon_state = "awaycontent20"
/area/awaycontent/a21
icon_state = "awaycontent21"
/area/awaycontent/a22
icon_state = "awaycontent22"
/area/awaycontent/a23
icon_state = "awaycontent23"
/area/awaycontent/a24
icon_state = "awaycontent24"
/area/awaycontent/a25
icon_state = "awaycontent25"
/area/awaycontent/a26
icon_state = "awaycontent26"
/area/awaycontent/a27
icon_state = "awaycontent27"
/area/awaycontent/a28
icon_state = "awaycontent28"
/area/awaycontent/a29
icon_state = "awaycontent29"
/area/awaycontent/a30
icon_state = "awaycontent30"
/////////////////////////////////////////////////////////////////////
/*
@@ -1611,7 +935,7 @@ var/list/the_station_areas = list (
/area/ai_monitored/storage/eva, //do not try to simplify to "/area/ai_monitored" --rastaf0
// /area/ai_monitored/storage/secure, //not present on map
// /area/ai_monitored/storage/emergency, //not present on map
/area/turret_protected/ai_upload, //do not try to simplify to "/area/turret_protected" --rastaf0
/area/turret_protected/ai_upload_foyer,
/area/turret_protected/ai,
/area/ai_monitored/turret_protected/ai_upload, //do not try to simplify to "/area/ai_monitored/turret_protected" --rastaf0
/area/ai_monitored/turret_protected/ai_upload_foyer,
/area/ai_monitored/turret_protected/ai,
)
+20 -15
View File
@@ -1,24 +1,29 @@
/area/ai_monitored
name = "AI Monitored Area"
var/obj/machinery/camera/motioncamera = null
var/list/obj/machinery/camera/motioncameras = list()
var/list/motionTargets = list()
/area/ai_monitored/New()
/area/ai_monitored/initialize()
..()
// locate and store the motioncamera
spawn (20) // spawn on a delay to let turfs/objs load
for (var/obj/machinery/camera/M in src)
if(M.isMotion())
motioncamera = M
M.area_motion = src
for (var/obj/machinery/camera/M in src)
if(M.isMotion())
motioncameras.Add(M)
M.area_motion = src
//Only need to use one camera
/area/ai_monitored/Entered(atom/movable/O)
..()
if (ismob(O) && motioncamera)
motioncamera.newTarget(O)
if (ismob(O) && motioncameras.len)
for(var/X in motioncameras)
var/obj/machinery/camera/cam = X
cam.newTarget(O)
return
/area/ai_monitored/Exited(atom/movable/O)
if (ismob(O) && motioncamera)
motioncamera.lostTarget(O)
..()
if (ismob(O) && motioncameras.len)
for(var/X in motioncameras)
var/obj/machinery/camera/cam = X
cam.lostTarget(O)
return
+106 -21
View File
@@ -1,20 +1,55 @@
// Areas.dm
// Added to fix mech fabs 05/2013 ~Sayu
// This is necessary due to lighting subareas. If you were to go in assuming that things in
// the same logical /area have the parent /area object... well, you would be mistaken. If you
// want to find machines, mobs, etc, in the same logical area, you will need to check all the
// related areas. This returns a master contents list to assist in that.
/proc/area_contents(var/area/A)
if(!istype(A)) return null
var/list/contents = list()
for(var/area/LSA in A.related)
contents += LSA.contents
return contents
// ===
/area
level = null
name = "Space"
icon = 'icons/turf/areas.dmi'
icon_state = "unknown"
layer = AREA_LAYER
mouse_opacity = 0
invisibility = INVISIBILITY_LIGHTING
var/map_name // Set in New(); preserves the name set by the map maker, even if renamed by the Blueprints.
var/valid_territory = 1 // If it's a valid territory for gangs to claim
var/blob_allowed = 1 // Does it count for blobs score? By default, all areas count.
var/eject = null
var/fire = null
var/atmos = 1
var/atmosalm = 0
var/poweralm = 1
var/party = null
var/lightswitch = 1
var/requires_power = 1
var/always_unpowered = 0 // This gets overriden to 1 for space in area/New().
var/outdoors = 0 //For space, the asteroid, lavaland, etc. Used with blueprints to determine if we are adding a new area (vs editing a station room)
var/power_equip = 1
var/power_light = 1
var/power_environ = 1
var/music = null
var/used_equip = 0
var/used_light = 0
var/used_environ = 0
var/static_equip
var/static_light = 0
var/static_environ
var/has_gravity = 0
var/noteleport = 0 //Are you forbidden from teleporting to the area? (centcomm, mobs, wizard, hand teleporter)
var/safe = 0 //Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
var/no_air = null
var/area/master // master area used for power calcluations
var/list/related // the other areas of the same type as this
var/parallax_movedir = 0
var/global/global_uid = 0
var/uid
var/list/ambientsounds = list('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg',\
@@ -23,6 +58,43 @@
'sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg',\
'sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg',\
'sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg')
flags = CAN_BE_DIRTY
/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
var/list/teleportlocs = list()
/proc/process_teleport_locs()
for(var/V in sortedAreas)
var/area/AR = V
if(istype(AR, /area/shuttle) || AR.noteleport)
continue
if(teleportlocs[AR.name])
continue
var/turf/picked = safepick(get_area_turfs(AR.type))
if (picked && (picked.z == ZLEVEL_STATION))
teleportlocs[AR.name] = AR
sortTim(teleportlocs, /proc/cmp_text_dsc)
// ===
// Added to fix mech fabs 05/2013 ~Sayu
// This is necessary due to lighting subareas. If you were to go in assuming that things in
// the same logical /area have the parent /area object... well, you would be mistaken. If you
// want to find machines, mobs, etc, in the same logical area, you will need to check all the
// related areas. This returns a master contents list to assist in that.
/proc/area_contents(area/A)
if(!istype(A)) return null
var/list/contents = list()
for(var/area/LSA in A.related)
contents += LSA.contents
return contents
/area/New()
icon_state = ""
@@ -39,8 +111,8 @@
power_equip = 1
power_environ = 1
if (dynamic_lighting != DYNAMIC_LIGHTING_IFSTARLIGHT)
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
if (lighting_use_dynamic != DYNAMIC_LIGHTING_IFSTARLIGHT)
lighting_use_dynamic = DYNAMIC_LIGHTING_DISABLED
..()
@@ -74,6 +146,11 @@
D.cancelAlarm("Power", src, source)
else
D.triggerAlarm("Power", src, cameras, source)
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
if(state == 1)
p.cancelAlarm("Power", src, source)
else
p.triggerAlarm("Power", src, cameras, source)
/area/proc/atmosalert(danger_level, obj/source)
if(danger_level != atmosalm)
@@ -89,6 +166,8 @@
a.triggerAlarm("Atmosphere", src, cameras, source)
for(var/mob/living/simple_animal/drone/D in mob_list)
D.triggerAlarm("Atmosphere", src, cameras, source)
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
p.triggerAlarm("Atmosphere", src, cameras, source)
else if (src.atmosalm == 2)
for(var/mob/living/silicon/aiPlayer in player_list)
@@ -97,6 +176,8 @@
a.cancelAlarm("Atmosphere", src, source)
for(var/mob/living/simple_animal/drone/D in mob_list)
D.cancelAlarm("Atmosphere", src, source)
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
p.cancelAlarm("Atmosphere", src, source)
src.atmosalm = danger_level
return 1
@@ -128,6 +209,8 @@
aiPlayer.triggerAlarm("Fire", src, cameras, source)
for (var/mob/living/simple_animal/drone/D in mob_list)
D.triggerAlarm("Fire", src, cameras, source)
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
p.triggerAlarm("Fire", src, cameras, source)
/area/proc/firereset(obj/source)
for(var/area/RA in related)
@@ -150,6 +233,8 @@
a.cancelAlarm("Fire", src, source)
for (var/mob/living/simple_animal/drone/D in mob_list)
D.cancelAlarm("Fire", src, source)
for(var/datum/computer_file/program/alarm_monitor/p in alarmdisplay)
p.cancelAlarm("Fire", src, source)
/area/proc/burglaralert(obj/trigger)
if(always_unpowered == 1) //no burglar alarms in space/asteroid
@@ -172,7 +257,7 @@
for (var/mob/living/silicon/SILICON in player_list)
if(SILICON.triggerAlarm("Burglar", src, cameras, trigger))
//Cancel silicon alert after 1 minute
addtimer(SILICON, "cancelAlarm", 600, FALSE,"Burglar",src,trigger)
addtimer(SILICON, "cancelAlarm", 600, TIMER_NORMAL,"Burglar",src,trigger)
/area/proc/set_fire_alarm_effect()
fire = 1
@@ -310,7 +395,7 @@
/area/Entered(A)
if(!istype(A,/mob/living))
if(!isliving(A))
return
var/mob/living/L = A
@@ -335,11 +420,11 @@
if(L.&& L.client)
L.client.played = 0
/proc/has_gravity(atom/AT, turf/T)
if(!T)
T = get_turf(AT)
/atom/proc/has_gravity(turf/T)
if(!T || !isturf(T))
T = get_turf(src)
var/area/A = get_area(T)
if(istype(T, /turf/open/space)) // Turf never has gravity
if(isspaceturf(T)) // Turf never has gravity
return 0
else if(A && A.has_gravity) // Areas which always has gravity
return 1
+457
View File
@@ -0,0 +1,457 @@
// Away Missions
/area/awaymission
name = "Strange Location"
icon_state = "away"
has_gravity = 1
/area/awaymission/example
name = "Strange Station"
icon_state = "away"
/area/awaymission/desert
name = "Mars"
icon_state = "away"
/area/awaymission/listeningpost
name = "Listening Post"
icon_state = "away"
requires_power = 0
/area/awaymission/beach
name = "Beach"
icon_state = "away"
luminosity = 1
lighting_use_dynamic = DYNAMIC_LIGHTING_DISABLED
requires_power = 0
has_gravity = 1
ambientsounds = list('sound/ambience/shore.ogg', 'sound/ambience/seag1.ogg','sound/ambience/seag2.ogg','sound/ambience/seag2.ogg')
/area/awaymission/errorroom
name = "Super Secret Room"
luminosity = 1
lighting_use_dynamic = DYNAMIC_LIGHTING_DISABLED
has_gravity = 1
//Research Base Areas//--
/area/awaymission/research
name = "Research Outpost"
icon_state = "away"
luminosity = 0
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
/area/awaymission/research/interior
name = "Research Inside"
requires_power = 1
icon_state = "away2"
/area/awaymission/research/interior/cryo
name = "Research Cryostasis Room"
icon_state = "medbay"
/area/awaymission/research/interior/clonestorage
name = "Research Clone Storage"
icon_state = "cloning"
/area/awaymission/research/interior/genetics
name = "Research Genetics Research"
icon_state = "genetics"
/area/awaymission/research/interior/engineering
name = "Research Engineering"
icon_state = "engine"
/area/awaymission/research/interior/security
name = "Research Security"
icon_state = "security"
/area/awaymission/research/interior/secure
name = "Research Secure Vault"
/area/awaymission/research/interior/maint
name = "Research Maintenance"
icon_state = "maintcentral"
/area/awaymission/research/interior/dorm
name = "Research Dorms"
icon_state = "Sleep"
/area/awaymission/research/interior/escapepods
name = "Research Escape Wing"
icon_state = "exit"
/area/awaymission/research/interior/gateway
name = "Research Gateway"
icon_state = "start"
/area/awaymission/research/interior/bathroom
name = "Research Bathrooms"
icon_state = "restrooms"
/area/awaymission/research/interior/medbay
name = "Research Medbay"
icon_state = "medbay"
/area/awaymission/research/exterior
name = "Research Exterior"
icon_state = "unknown"
//Challenge Areas
/area/awaymission/challenge/start
name = "Where Am I?"
icon_state = "away"
/area/awaymission/challenge/main
name = "Danger Room"
icon_state = "away1"
requires_power = 0
/area/awaymission/challenge/end
name = "Administration"
icon_state = "away2"
requires_power = 0
//centcomAway areas
/area/awaymission/centcomAway
name = "XCC-P5831"
icon_state = "away"
requires_power = 0
/area/awaymission/centcomAway/general
name = "XCC-P5831"
music = "music/ambigen3.ogg"
/area/awaymission/centcomAway/maint
name = "XCC-P5831 Maintenance"
icon_state = "away1"
music = "music/ambisin1.ogg"
/area/awaymission/centcomAway/thunderdome
name = "XCC-P5831 Thunderdome"
icon_state = "away2"
music = "music/ambisin2.ogg"
/area/awaymission/centcomAway/cafe
name = "XCC-P5831 Kitchen Arena"
icon_state = "away3"
music = "music/ambisin3.ogg"
/area/awaymission/centcomAway/courtroom
name = "XCC-P5831 Courtroom"
icon_state = "away4"
music = "music/ambisin4.ogg"
/area/awaymission/centcomAway/hangar
name = "XCC-P5831 Hangars"
icon_state = "away4"
music = "music/ambigen5.ogg"
/*Cabin areas*/
/area/awaymission/snowforest
name = "Snow Forest"
icon_state = "away"
requires_power = 0
luminosity = 1
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
/area/awaymission/cabin
name = "Cabin"
icon_state = "away2"
requires_power = 1
luminosity = 0
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
/area/awaymission/snowforest/lumbermill
name = "Lumbermill"
icon_state = "away3"
//Packer Ship Areas
/area/awaymission/BMPship
name = "BMP Asteroids"
icon_state = "away"
luminosity = 0
/area/awaymission/BMPship/Aft
name = "Aft Block"
icon_state = "away1"
requires_power = 1
/area/awaymission/BMPship/Midship
name = "Midship Block"
icon_state = "away2"
requires_power = 1
/area/awaymission/BMPship/Fore
name = "Fore Block"
icon_state = "away3"
requires_power = 1
//Academy Areas
/area/awaymission/academy
name = "Academy Asteroids"
icon_state = "away"
/area/awaymission/academy/headmaster
name = "Academy Fore Block"
icon_state = "away1"
/area/awaymission/academy/classrooms
name = "Academy Classroom Block"
icon_state = "away2"
/area/awaymission/academy/academyaft
name = "Academy Ship Aft Block"
icon_state = "away3"
/area/awaymission/academy/academygate
name = "Academy Gateway"
icon_state = "away4"
/area/awaymission/academy/academycellar
name = "Academy Cellar"
icon_state = "away4"
/area/awaymission/academy/academyengine
name = "Academy Engine"
icon_state = "away4"
//Wild West Areas
/area/awaymission/wwmines
name = "Wild West Mines"
icon_state = "away1"
luminosity = 1
requires_power = 0
/area/awaymission/wwgov
name = "Wild West Mansion"
icon_state = "away2"
luminosity = 1
requires_power = 0
/area/awaymission/wwrefine
name = "Wild West Refinery"
icon_state = "away3"
luminosity = 1
requires_power = 0
/area/awaymission/wwvault
name = "Wild West Vault"
icon_state = "away3"
luminosity = 0
/area/awaymission/wwvaultdoors
name = "Wild West Vault Doors" // this is to keep the vault area being entirely lit because of requires_power
icon_state = "away2"
requires_power = 0
luminosity = 0
/*
* Areas
*/
//Gateroom gets its own APC specifically for the gate
/area/awaymission/gateroom
//Library, medbay, storage room
/area/awaymission/southblock
//Arrivals, security, hydroponics, shuttles (since they dont move, they dont need specific areas)
/area/awaymission/arrivalblock
//Crew quarters, cafeteria, chapel
/area/awaymission/midblock
//engineering, bridge (not really north but it doesnt really need its own APC)
/area/awaymission/northblock
//That massive research room
/area/awaymission/research
//Syndicate shuttle
/area/awaymission/syndishuttle
//Spacebattle Areas
/area/awaymission/spacebattle
name = "Space Battle"
icon_state = "away"
requires_power = 0
/area/awaymission/spacebattle/cruiser
name = "Nanotrasen Cruiser"
/area/awaymission/spacebattle/syndicate1
name = "Syndicate Assault Ship 1"
/area/awaymission/spacebattle/syndicate2
name = "Syndicate Assault Ship 2"
/area/awaymission/spacebattle/syndicate3
name = "Syndicate Assault Ship 3"
/area/awaymission/spacebattle/syndicate4
name = "Syndicate War Sphere 1"
/area/awaymission/spacebattle/syndicate5
name = "Syndicate War Sphere 2"
/area/awaymission/spacebattle/syndicate6
name = "Syndicate War Sphere 3"
/area/awaymission/spacebattle/syndicate7
name = "Syndicate Fighter"
/area/awaymission/spacebattle/secret
name = "Hidden Chamber"
//Snow Valley Areas//--
/area/awaymission/snowdin
name = "Snowdin Tundra Plains"
icon_state = "away"
requires_power = 0
luminosity = 1
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
/area/awaymission/snowdin/post
name = "Snowdin Outpost"
requires_power = 1
/area/awaymission/snowdin/igloo
name = "Snowdin Igloos"
icon_state = "away2"
/area/awaymission/snowdin/cave
name = "Snowdin Caves"
icon_state = "away2"
luminosity = 0
/area/awaymission/snowdin/base
name = "Snowdin Main Base"
icon_state = "away3"
requires_power = 1
/area/awaymission/snowdin/dungeon1
name = "Snowdin Depths"
icon_state = "away2"
luminosity = 0
/area/awaymission/snowdin/sekret
name = "Snowdin Operations"
icon_state = "away3"
requires_power = 1
/area/awaycontent
name = "space"
/area/awaycontent/a1
icon_state = "awaycontent1"
/area/awaycontent/a2
icon_state = "awaycontent2"
/area/awaycontent/a3
icon_state = "awaycontent3"
/area/awaycontent/a4
icon_state = "awaycontent4"
/area/awaycontent/a5
icon_state = "awaycontent5"
/area/awaycontent/a6
icon_state = "awaycontent6"
/area/awaycontent/a7
icon_state = "awaycontent7"
/area/awaycontent/a8
icon_state = "awaycontent8"
/area/awaycontent/a9
icon_state = "awaycontent9"
/area/awaycontent/a10
icon_state = "awaycontent10"
/area/awaycontent/a11
icon_state = "awaycontent11"
/area/awaycontent/a11
icon_state = "awaycontent12"
/area/awaycontent/a12
icon_state = "awaycontent13"
/area/awaycontent/a13
icon_state = "awaycontent14"
/area/awaycontent/a14
icon_state = "awaycontent14"
/area/awaycontent/a15
icon_state = "awaycontent15"
/area/awaycontent/a16
icon_state = "awaycontent16"
/area/awaycontent/a17
icon_state = "awaycontent17"
/area/awaycontent/a18
icon_state = "awaycontent18"
/area/awaycontent/a19
icon_state = "awaycontent19"
/area/awaycontent/a20
icon_state = "awaycontent20"
/area/awaycontent/a21
icon_state = "awaycontent21"
/area/awaycontent/a22
icon_state = "awaycontent22"
/area/awaycontent/a23
icon_state = "awaycontent23"
/area/awaycontent/a24
icon_state = "awaycontent24"
/area/awaycontent/a25
icon_state = "awaycontent25"
/area/awaycontent/a26
icon_state = "awaycontent26"
/area/awaycontent/a27
icon_state = "awaycontent27"
/area/awaycontent/a28
icon_state = "awaycontent28"
/area/awaycontent/a29
icon_state = "awaycontent29"
/area/awaycontent/a30
icon_state = "awaycontent30"
+134
View File
@@ -0,0 +1,134 @@
// CENTCOM
/area/centcom
name = "Centcom"
icon_state = "centcom"
requires_power = 0
has_gravity = 1
noteleport = 1
blob_allowed = 0 //Should go without saying, no blobs should take over centcom as a win condition.
flags = NONE
/area/centcom/control
name = "Centcom Docks"
/area/centcom/evac
name = "Centcom Recovery Ship"
/area/centcom/supply
name = "Centcom Supply Shuttle Dock"
/area/centcom/ferry
name = "Centcom Transport Shuttle Dock"
/area/centcom/prison
name = "Admin Prison"
/area/centcom/holding
name = "Holding Facility"
//THUNDERDOME
/area/tdome
name = "Thunderdome"
icon_state = "yellow"
requires_power = 0
has_gravity = 1
/area/tdome/arena
name = "Thunderdome Arena"
icon_state = "thunder"
/area/tdome/arena_source
name = "Thunderdome Arena Template"
icon_state = "thunder"
/area/tdome/tdome1
name = "Thunderdome (Team 1)"
icon_state = "green"
/area/tdome/tdome2
name = "Thunderdome (Team 2)"
icon_state = "green"
/area/tdome/tdomeadmin
name = "Thunderdome (Admin.)"
icon_state = "purple"
/area/tdome/tdomeobserve
name = "Thunderdome (Observer.)"
icon_state = "purple"
//ENEMY
//Wizard
/area/wizard_station
name = "Wizard's Den"
icon_state = "yellow"
requires_power = 0
has_gravity = 1
noteleport = 1
//Abductors
/area/abductor_ship
name = "Abductor Ship"
icon_state = "yellow"
requires_power = 0
noteleport = 1
has_gravity = 1
//Syndicates
/area/syndicate_mothership
name = "Syndicate Mothership"
icon_state = "syndie-ship"
requires_power = 0
has_gravity = 1
noteleport = 1
blob_allowed = 0 //Not... entirely sure this will ever come up... but if the bus makes blobs AND ops, it shouldn't aim for the ops to win.
/area/syndicate_mothership/control
name = "Syndicate Control Room"
icon_state = "syndie-control"
/area/syndicate_mothership/elite_squad
name = "Syndicate Elite Squad"
icon_state = "syndie-elite"
//CAPTURE THE FLAG
/area/ctf
name = "Capture the Flag"
icon_state = "yellow"
requires_power = 0
has_gravity = 1
/area/ctf/control_room
name = "Control Room A"
/area/ctf/control_room2
name = "Control Room B"
/area/ctf/central
name = "Central"
/area/ctf/main_hall
name = "Main Hall A"
/area/ctf/main_hall2
name = "Main Hall B"
/area/ctf/corridor
name = "Corridor A"
/area/ctf/corridor2
name = "Corridor B"
/area/ctf/flag_room
name = "Flag Room A"
/area/ctf/flag_room2
name = "Flag Room B"
+124
View File
@@ -0,0 +1,124 @@
//DERELICT
/area/derelict
name = "Derelict Station"
icon_state = "storage"
blob_allowed = 0 //Nope, no winning on the derelict as a blob. Gotta eat the station.
/area/derelict/hallway/primary
name = "Derelict Primary Hallway"
icon_state = "hallP"
/area/derelict/hallway/secondary
name = "Derelict Secondary Hallway"
icon_state = "hallS"
/area/derelict/arrival
name = "Derelict Arrival Centre"
icon_state = "yellow"
/area/derelict/storage/equipment
name = "Derelict Equipment Storage"
/area/derelict/storage/storage_access
name = "Derelict Storage Access"
/area/derelict/storage/engine_storage
name = "Derelict Engine Storage"
icon_state = "green"
/area/derelict/bridge
name = "Derelict Control Room"
icon_state = "bridge"
/area/derelict/secret
name = "Derelict Secret Room"
icon_state = "library"
/area/derelict/bridge/access
name = "Derelict Control Room Access"
icon_state = "auxstorage"
/area/derelict/bridge/ai_upload
name = "Derelict Computer Core"
icon_state = "ai"
/area/derelict/solar_control
name = "Derelict Solar Control"
icon_state = "engine"
/area/derelict/se_solar
name = "South East Solars"
icon_state = "engine"
/area/derelict/crew_quarters
name = "Derelict Crew Quarters"
icon_state = "fitness"
/area/derelict/medical
name = "Derelict Medbay"
icon_state = "medbay"
/area/derelict/medical/morgue
name = "Derelict Morgue"
icon_state = "morgue"
/area/derelict/medical/chapel
name = "Derelict Chapel"
icon_state = "chapel"
/area/derelict/teleporter
name = "Derelict Teleporter"
icon_state = "teleporter"
/area/derelict/eva
name = "Derelict EVA Storage"
icon_state = "eva"
/area/derelict/ship
name = "Abandoned Ship"
icon_state = "yellow"
/area/solar/derelict_starboard
name = "Derelict Starboard Solar Array"
icon_state = "panelsS"
/area/solar/derelict_aft
name = "Derelict Aft Solar Array"
icon_state = "yellow"
/area/derelict/singularity_engine
name = "Derelict Singularity Engine"
icon_state = "engine"
/area/derelict/gravity_generator
name = "Derelict Gravity Generator Room"
icon_state = "red"
/area/derelict/atmospherics
name = "Derelict Atmospherics"
icon_state = "red"
//DJSTATION
/area/djstation
name = "Ruskie DJ Station"
icon_state = "DJ"
has_gravity = 1
blob_allowed = 0 //Nope, no winning on the DJ station as a blob. Gotta eat the main station.
/area/djstation/solars
name = "DJ Station Solars"
icon_state = "DJ"
has_gravity = 1
//ABANDONED TELEPORTER
/area/AIsattele
name = "Abandoned Teleporter"
icon_state = "teleporter"
music = "signal"
ambientsounds = list('sound/ambience/ambimalf.ogg')
+128
View File
@@ -0,0 +1,128 @@
/area/holodeck
name = "Holodeck"
icon_state = "Holodeck"
luminosity = 1
lighting_use_dynamic = 0
flags = 0
var/obj/machinery/computer/holodeck/linked
var/restricted = 0 // if true, program goes on emag list
/*
Power tracking: Use the holodeck computer's power grid
Asserts are to avoid the inevitable infinite loops
*/
/area/holodeck/powered(var/chan)
if(!master.requires_power)
return 1
if(master.always_unpowered)
return 0
if(!linked)
return 0
var/area/A = get_area(linked)
ASSERT(!istype(A,/area/holodeck))
return A.powered(chan)
/area/holodeck/usage(var/chan)
if(!linked)
return 0
var/area/A = get_area(linked)
ASSERT(!istype(A,/area/holodeck))
return A.usage(chan)
/area/holodeck/addStaticPower(value, powerchannel)
if(!linked)
return
var/area/A = get_area(linked)
ASSERT(!istype(A,/area/holodeck))
return A.addStaticPower(value,powerchannel)
/area/holodeck/use_power(var/amount, var/chan)
if(!linked)
return 0
var/area/A = get_area(linked)
ASSERT(!istype(A,/area/holodeck))
return A.use_power(amount,chan)
/*
This is the standard holodeck. It is intended to allow you to
blow off steam by doing stupid things like laying down, throwing
spheres at holes, or bludgeoning people.
*/
/area/holodeck/rec_center
name = "\improper Recreational Holodeck"
/area/holodeck/rec_center/offline
name = "Holodeck - Offline"
/area/holodeck/rec_center/court
name = "Holodeck - Empty Court"
/area/holodeck/rec_center/dodgeball
name = "Holodeck - Dodgeball Court"
/area/holodeck/rec_center/basketball
name = "Holodeck - Basketball Court"
/area/holodeck/rec_center/thunderdome
name = "Holodeck - Thunderdome Arena"
/area/holodeck/rec_center/beach
name = "Holodeck - Beach"
/area/holodeck/rec_center/lounge
name = "Holodeck - Lounge"
/area/holodeck/rec_center/medical
name = "Holodeck - Emergency Medical"
/area/holodeck/rec_center/pet_lounge
name = "Holodeck - Pet Park"
/area/holodeck/rec_center/firingrange
name = "Holodeck - Firing Range"
/area/holodeck/rec_center/rollercoaster
name = "Holodeck - Roller Coaster"
/area/holodeck/rec_center/chapelcourt
name = "Holodeck - Chapel Courtroom"
/area/holodeck/rec_center/spacechess
name = "Holodeck - Space Chess"
/area/holodeck/rec_center/kobayashi
name = "Holodeck - Kobayashi Maru"
// Bad programs
/area/holodeck/rec_center/burn
name = "Holodeck - Atmospheric Burn Test"
restricted = 1
/area/holodeck/rec_center/winterwonderland
name = "Holodeck - Winter Wonderland"
restricted = 1
/area/holodeck/rec_center/wildlife
name = "Holodeck - Wildlife Simulation"
restricted = 1
/area/holodeck/rec_center/bunker
name = "Holodeck - Holdout Bunker"
restricted = 1
/area/holodeck/rec_center/anthophila
name = "Holodeck - Anthophila"
restricted = 1
/area/holodeck/rec_center/refuel
name = "Holodeck - Refueling Station"
restricted = 1
/area/holodeck/rec_center/thunderdome1218
name = "Holodeck - 1218 AD"
restricted = 1
+120
View File
@@ -0,0 +1,120 @@
/**********************Mine areas**************************/
/area/mine
icon_state = "mining"
has_gravity = 1
/area/mine/explored
name = "Mine"
icon_state = "explored"
music = null
always_unpowered = 1
requires_power = 1
poweralm = 0
power_environ = 0
power_equip = 0
power_light = 0
outdoors = 1
ambientsounds = list('sound/ambience/ambimine.ogg')
flags = NONE
/area/mine/unexplored
name = "Mine"
icon_state = "unexplored"
music = null
always_unpowered = 1
requires_power = 1
poweralm = 0
power_environ = 0
power_equip = 0
power_light = 0
outdoors = 1
ambientsounds = list('sound/ambience/ambimine.ogg')
flags = NONE
/area/mine/lobby
name = "Mining Station"
/area/mine/storage
name = "Mining Station Storage"
/area/mine/production
name = "Mining Station Starboard Wing"
icon_state = "mining_production"
/area/mine/abandoned
name = "Abandoned Mining Station"
/area/mine/living_quarters
name = "Mining Station Port Wing"
icon_state = "mining_living"
/area/mine/eva
name = "Mining Station EVA"
icon_state = "mining_eva"
/area/mine/maintenance
name = "Mining Station Communications"
/area/mine/cafeteria
name = "Mining station Cafeteria"
/area/mine/hydroponics
name = "Mining station Hydroponics"
/area/mine/sleeper
name = "Mining station Emergency Sleeper"
/area/mine/north_outpost
name = "North Mining Outpost"
/area/mine/west_outpost
name = "West Mining Outpost"
/area/mine/laborcamp
name = "Labor Camp"
/area/mine/laborcamp/security
name = "Labor Camp Security"
icon_state = "security"
/**********************Lavaland Areas**************************/
/area/lavaland
icon_state = "mining"
has_gravity = 1
/area/lavaland/surface
name = "Lavaland"
icon_state = "explored"
music = null
always_unpowered = 1
poweralm = 0
power_environ = 0
power_equip = 0
power_light = 0
requires_power = 1
ambientsounds = list('sound/ambience/ambilava.ogg')
/area/lavaland/underground
name = "Lavaland Caves"
icon_state = "unexplored"
music = null
always_unpowered = 1
requires_power = 1
poweralm = 0
power_environ = 0
power_equip = 0
power_light = 0
ambientsounds = list('sound/ambience/ambilava.ogg')
/area/lavaland/surface/outdoors
name = "Lavaland Wastes"
outdoors = 1
/area/lavaland/surface/outdoors/explored
name = "Lavaland Labor Camp"
+130
View File
@@ -0,0 +1,130 @@
// Hell
/area/hell
name = "Hell Lobby"
//icon = "ICON FILENAME"
//icon_state = "NAME OF ICON"
requires_power = 0
music = "music/music.ogg"
/area/hell/trial1
name = "Hell Trial1"
//icon_state = "NAME OF ICON" (defaults to "unknown" (blank))
/area/hell/trial1
name = "Hell Trial2"
//icon_state = "NAME OF ICON" (defaults to "unknown" (blank))
/area/hell/trial1
name = "Hell Trial3"
//icon_state = "NAME OF ICON" (defaults to "unknown" (blank))
//Misc
/area/wreck/ai
name = "AI Chamber"
icon_state = "ai"
/area/wreck/main
name = "Wreck"
icon_state = "storage"
/area/wreck/engineering
name = "Power Room"
icon_state = "engine"
/area/wreck/bridge
name = "Bridge"
icon_state = "bridge"
/area/generic
name = "Unknown"
icon_state = "storage"
//PRISON
/area/prison
name = "Prison Station"
icon_state = "brig"
/area/prison/arrival_airlock
name = "Prison Station Airlock"
icon_state = "green"
requires_power = 0
/area/prison/control
name = "Prison Security Checkpoint"
icon_state = "security"
/area/prison/crew_quarters
name = "Prison Security Quarters"
icon_state = "security"
/area/prison/rec_room
name = "Prison Rec Room"
icon_state = "green"
/area/prison/closet
name = "Prison Supply Closet"
icon_state = "dk_yellow"
/area/prison/hallway/fore
name = "Prison Fore Hallway"
icon_state = "yellow"
/area/prison/hallway/aft
name = "Prison Aft Hallway"
icon_state = "yellow"
/area/prison/hallway/port
name = "Prison Port Hallway"
icon_state = "yellow"
/area/prison/hallway/starboard
name = "Prison Starboard Hallway"
icon_state = "yellow"
/area/prison/morgue
name = "Prison Morgue"
icon_state = "morgue"
ambientsounds = list('sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg')
/area/prison/medical_research
name = "Prison Genetic Research"
icon_state = "medresearch"
/area/prison/medical
name = "Prison Medbay"
icon_state = "medbay"
/area/prison/solar
name = "Prison Solar Array"
icon_state = "storage"
requires_power = 0
/area/prison/podbay
name = "Prison Podbay"
icon_state = "dk_yellow"
/area/prison/solar_control
name = "Prison Solar Array Control"
icon_state = "dk_yellow"
/area/prison/solitary
name = "Solitary Confinement"
icon_state = "brig"
/area/prison/cell_block/A
name = "Prison Cell Block A"
icon_state = "brig"
/area/prison/cell_block/B
name = "Prison Cell Block B"
icon_state = "brig"
/area/prison/cell_block/C
name = "Prison Cell Block C"
icon_state = "brig"
+200
View File
@@ -0,0 +1,200 @@
//Parent types
/area/ruin
name = "\improper Unexplored Location"
icon_state = "away"
has_gravity = 1
/area/ruin/unpowered
always_unpowered = 0
/area/ruin/unpowered/no_grav
has_gravity = 0
/area/ruin/powered
requires_power = 0
//Areas
/area/ruin/unpowered/hierophant
name = "Hierophant's Arena"
/area/ruin/unpowered/no_grav/way_home
name = "\improper Salvation"
icon_state = "away"
/area/ruin/powered/snow_biodome
/area/ruin/powered/golem_ship
name = "Free Golem Ship"
/area/ruin/powered/syndicate_lava_base
name = "Secret Base"
// Ruins of "onehalf" ship
/area/ruin/onehalf/hallway
name = "Hallway"
icon_state = "hallC"
/area/ruin/onehalf/drone_bay
name = "Mining Drone Bay"
icon_state = "engine"
/area/ruin/onehalf/dorms_med
name = "Crew Quarters"
icon_state = "Sleep"
/area/ruin/onehalf/bridge
name = "Bridge"
icon_state = "bridge"
/area/ruin/powered/dinner_for_two
name = "Dinner for Two"
/area/ruin/powered/authorship
name = "Authorship"
/area/ruin/powered/aesthetic
name = "Aesthetic"
ambientsounds = list('sound/ambience/ambivapor1.ogg')
//Ruin of Hotel
/area/ruin/hotel
name = "Hotel"
/area/ruin/hotel/guestroom
name = "Hotel Guest Room"
icon_state = "Sleep"
/area/ruin/hotel/security
name = "Hotel Security Post"
icon_state = "security"
/area/ruin/hotel/pool
name = "Hotel Pool Room"
icon_state = "fitness"
/area/ruin/hotel/bar
name = "Hotel Bar"
icon_state = "cafeteria"
/area/ruin/hotel/power
name = "Hotel Power Room"
icon_state = "engine_smes"
/area/ruin/hotel/custodial
name = "Hotel Custodial Closet"
icon_state = "janitor"
/area/ruin/hotel/shuttle
name = "Hotel Shuttle"
icon_state = "shuttle"
requires_power = 0
/area/ruin/hotel/dock
name = "Hotel Shuttle Dock"
icon_state = "start"
/area/ruin/hotel/workroom
name = "Hotel Staff Room"
icon_state = "crew_quarters"
/area/ruin/fakespace
icon_state = "space"
requires_power = 1
always_unpowered = 1
lighting_use_dynamic = DYNAMIC_LIGHTING_DISABLED
has_gravity = 0
power_light = 0
power_equip = 0
power_environ = 0
valid_territory = 0
outdoors = 1
ambientsounds = list('sound/ambience/ambispace.ogg','sound/ambience/title2.ogg')
blob_allowed = 0
//Ruin of Derelict Oupost
/area/ruin/derelictoutpost
name = "Derelict Outpost"
icon_state = "green"
/area/ruin/derelictoutpost/cargostorage
name = "Derelict Outpost Cargo Storage"
icon_state = "storage"
/area/ruin/derelictoutpost/cargobay
name = "Derelict Outpost Cargo Bay"
icon_state = "quartstorage"
/area/ruin/derelictoutpost/powerstorage
name = "Derelict Outpost Power Storage"
icon_state = "engine_smes"
/area/ruin/derelictoutpost/dockedship
name = "Derelict Outpost Docked Ship"
icon_state = "red"
//Ruin of Space Bar
/area/ruin/powered/spacebar
name = "Space Bar"
icon_state = "yellow"
/area/ruin/powered/spacebar/bar
icon_state = "bar"
//Ruin of turretedoutpost
/area/ruin/turretedoutpost
name = "Turreted Outpost"
icon_state = "red"
//Ruin of old teleporter
/area/ruin/oldteleporter
name = "Old teleporter"
icon_state = "teleporter"
has_gravity = 0
//Ruin of mech transport
/area/ruin/powered/mechtransport
name = "Mech Transport"
icon_state = "green"
//Ruin of gas the lizard
/area/ruin/gasthelizard
name = "Gas the lizard"
//Ruin of Deep Storage
/area/ruin/deepstorage
name = "Deep Storage"
icon_state = "storage"
//Ruin of Abandoned Zoo
/area/ruin/abandonedzoo
name = "Abandoned Zoo"
icon_state = "green"
+62
View File
@@ -0,0 +1,62 @@
//These are shuttle areas; all subtypes are only used as teleportation markers, they have no actual function beyond that.
/area/shuttle
name = "Shuttle"
requires_power = 0
luminosity = 1
lighting_use_dynamic = DYNAMIC_LIGHTING_ENABLED
has_gravity = 1
always_unpowered = 0
valid_territory = 0
icon_state = "shuttle"
/area/shuttle/transit
name = "Hyperspace"
desc = "Weeeeee"
/area/shuttle/arrival
name = "Arrival Shuttle"
/area/shuttle/pod_1
name = "Escape Pod One"
/area/shuttle/pod_2
name = "Escape Pod Two"
/area/shuttle/pod_3
name = "Escape Pod Three"
/area/shuttle/pod_4
name = "Escape Pod Four"
/area/shuttle/mining
name = "Mining Shuttle"
blob_allowed = FALSE
/area/shuttle/labor
name = "Labor Camp Shuttle"
blob_allowed = FALSE
/area/shuttle/supply
name = "Supply Shuttle"
blob_allowed = FALSE
/area/shuttle/escape
name = "Emergency Shuttle"
/area/shuttle/transport
name = "Transport Shuttle"
blob_allowed = FALSE
/area/shuttle/syndicate
name = "Syndicate Infiltrator"
blob_allowed = FALSE
/area/shuttle/assault_pod
name = "Steel Rain"
blob_allowed = FALSE
/area/shuttle/abandoned
name = "Abandoned Ship"
blob_allowed = FALSE
+97
View File
@@ -0,0 +1,97 @@
/area/spacecontent
name = "space"
/area/spacecontent/a1
icon_state = "spacecontent1"
/area/spacecontent/a2
icon_state = "spacecontent2"
/area/spacecontent/a3
icon_state = "spacecontent3"
/area/spacecontent/a4
icon_state = "spacecontent4"
/area/spacecontent/a5
icon_state = "spacecontent5"
/area/spacecontent/a6
icon_state = "spacecontent6"
/area/spacecontent/a7
icon_state = "spacecontent7"
/area/spacecontent/a8
icon_state = "spacecontent8"
/area/spacecontent/a9
icon_state = "spacecontent9"
/area/spacecontent/a10
icon_state = "spacecontent10"
/area/spacecontent/a11
icon_state = "spacecontent11"
/area/spacecontent/a11
icon_state = "spacecontent12"
/area/spacecontent/a12
icon_state = "spacecontent13"
/area/spacecontent/a13
icon_state = "spacecontent14"
/area/spacecontent/a14
icon_state = "spacecontent14"
/area/spacecontent/a15
icon_state = "spacecontent15"
/area/spacecontent/a16
icon_state = "spacecontent16"
/area/spacecontent/a17
icon_state = "spacecontent17"
/area/spacecontent/a18
icon_state = "spacecontent18"
/area/spacecontent/a19
icon_state = "spacecontent19"
/area/spacecontent/a20
icon_state = "spacecontent20"
/area/spacecontent/a21
icon_state = "spacecontent21"
/area/spacecontent/a22
icon_state = "spacecontent22"
/area/spacecontent/a23
icon_state = "spacecontent23"
/area/spacecontent/a24
icon_state = "spacecontent24"
/area/spacecontent/a25
icon_state = "spacecontent25"
/area/spacecontent/a26
icon_state = "spacecontent26"
/area/spacecontent/a27
icon_state = "spacecontent27"
/area/spacecontent/a28
icon_state = "spacecontent28"
/area/spacecontent/a29
icon_state = "spacecontent29"
/area/spacecontent/a30
icon_state = "spacecontent30"
+8 -8
View File
@@ -75,7 +75,7 @@ var/global/max_secret_rooms = 6
floortypes = list(/turf/open/floor/plasteel/cult)
treasureitems = list(/obj/item/device/soulstone/anybody=1, /obj/item/clothing/suit/space/hardsuit/cult=1, /obj/item/weapon/bedsheet/cult=2,
/obj/item/clothing/suit/cultrobes=2, /mob/living/simple_animal/hostile/creature=3)
fluffitems = list(/obj/effect/gateway=1,/obj/effect/gibspawner=1,/obj/structure/cult/talisman=1,/obj/item/toy/crayon/red=2,
fluffitems = list(/obj/effect/gateway=1,/obj/effect/gibspawner=1,/obj/structure/destructible/cult/talisman=1,/obj/item/toy/crayon/red=2,
/obj/item/organ/heart=2, /obj/effect/decal/cleanable/blood=4,/obj/structure/table/wood=2,/obj/item/weapon/ectoplasm=3,
/obj/item/clothing/shoes/cult=1)
@@ -92,7 +92,7 @@ var/global/max_secret_rooms = 6
theme = "cavein"
walltypes = list(/turf/closed/mineral/random/high_chance=1)
floortypes = list(/turf/open/floor/plating/asteroid/basalt, /turf/open/floor/plating/beach/sand)
treasureitems = list(/obj/mecha/working/ripley/mining=1, /obj/item/weapon/pickaxe/drill/diamonddrill=2,/obj/item/weapon/gun/energy/kinetic_accelerator/hyper=1,
treasureitems = list(/obj/mecha/working/ripley/mining=1, /obj/item/weapon/pickaxe/drill/diamonddrill=2,
/obj/item/weapon/resonator/upgraded=1, /obj/item/weapon/pickaxe/drill/jackhammer=5)
fluffitems = list(/obj/effect/decal/cleanable/blood=3,/obj/effect/decal/remains/human=1,/obj/item/clothing/under/overalls=1,
/obj/item/weapon/reagent_containers/food/snacks/grown/chili=1,/obj/item/weapon/tank/internals/oxygen/red=2)
@@ -117,7 +117,7 @@ var/global/max_secret_rooms = 6
if("speakeasy")
theme = "speakeasy"
floortypes = list(/turf/open/floor/plasteel,/turf/open/floor/wood)
treasureitems = list(/obj/item/weapon/melee/energy/sword/pirate=1,/obj/item/weapon/gun/projectile/revolver/doublebarrel=1,/obj/item/weapon/storage/backpack/satchel_flat=1,
treasureitems = list(/obj/item/weapon/melee/energy/sword/pirate=1,/obj/item/weapon/gun/ballistic/revolver/doublebarrel=1,/obj/item/weapon/storage/backpack/satchel/flat=1,
/obj/machinery/reagentgrinder=2, /obj/machinery/computer/security/wooden_tv=4, /obj/machinery/vending/coffee=3)
fluffitems = list(/obj/structure/table/wood=2,/obj/structure/reagent_dispensers/beerkeg=1,/obj/item/stack/spacecash/c500=4,
/obj/item/weapon/reagent_containers/food/drinks/shaker=1,/obj/item/weapon/reagent_containers/food/drinks/bottle/wine=3,
@@ -126,9 +126,9 @@ var/global/max_secret_rooms = 6
if("plantlab")
theme = "plantlab"
treasureitems = list(/obj/item/weapon/gun/energy/floragun=1,/obj/item/seeds/sunflower/novaflower=2,/obj/item/seeds/tomato/blue/bluespace=2,/obj/item/seeds/tomato/blue=2,
/obj/item/seeds/coffee/robusta=2, /obj/item/seeds/cash=2)
/obj/item/seeds/coffee/robusta=2, /obj/item/seeds/firelemon=2)
fluffitems = list(/obj/item/weapon/twohanded/required/kirbyplants=1,/obj/structure/table/reinforced=2,/obj/machinery/hydroponics/constructable=1,
/obj/effect/glowshroom/single=2,/obj/item/weapon/reagent_containers/syringe/charcoal=2,
/obj/structure/glowshroom/single=2,/obj/item/weapon/reagent_containers/syringe/charcoal=2,
/obj/item/weapon/reagent_containers/glass/bottle/diethylamine=3,/obj/item/weapon/reagent_containers/glass/bottle/ammonia=3)
/*if("poly")
@@ -174,13 +174,13 @@ var/global/max_secret_rooms = 6
if(!T)
return 0
room = spawn_room(T,x_size,y_size,walltypes,floor,) //WE'RE FINALLY CREATING THE ROOM
room = spawn_room(T,x_size,y_size,walltypes,floor) //WE'RE FINALLY CREATING THE ROOM
if(room)//time to fill it with stuff
var/list/emptyturfs = room["floors"]
T = pick(emptyturfs)
if(T)
new /obj/effect/glowshroom/single(T) //Just to make it a little more visible
new /obj/structure/glowshroom/single(T) //Just to make it a little more visible
var/surprise = null
surprise = pickweight(treasureitems)
new surprise(T)//here's the prize
@@ -195,4 +195,4 @@ var/global/max_secret_rooms = 6
emptyturfs -= T
//world.log << "The [theme] themed [T.loc] has been created!"
return 1
return 1
+128 -28
View File
@@ -1,14 +1,12 @@
/atom
layer = TURF_LAYER
plane = GAME_PLANE
var/level = 2
var/flags = 0
var/list/fingerprints
var/list/fingerprintshidden
var/fingerprintslast = null
var/list/blood_DNA
///Chemistry.
var/datum/reagents/reagents = null
var/admin_spawned = 0 //was this spawned by an admin? used for stat tracking stuff.
//This atom's HUD (med/sec, etc) images. Associative list.
var/list/image/hud_list = null
@@ -21,15 +19,42 @@
//overlays that should remain on top and not normally be removed, like c4.
var/list/priority_overlays
var/list/atom_colours //used to store the different colors on an atom
//its inherent color, the colored paint applied on it, special color effect etc...
/atom/New()
//atom creation method that preloads variables at creation
if(use_preloader && (src.type == _preloader.target_path))//in case the instanciated atom is creating other atoms in New()
_preloader.load(src)
//atom color stuff
if(color)
add_atom_colour(color, FIXED_COLOUR_PRIORITY)
//lighting stuff
if(opacity && isturf(loc))
loc.UpdateAffectingLights()
if(luminosity)
light = new(src)
//. = ..() //uncomment if you are dumb enough to add a /datum/New() proc
/atom/Destroy()
if(alternate_appearances)
for(var/aakey in alternate_appearances)
var/datum/alternate_appearance/AA = alternate_appearances[aakey]
qdel(AA)
alternate_appearances = null
if(viewing_alternate_appearances)
for(var/aakey in viewing_alternate_appearances)
for(var/aa in viewing_alternate_appearances[aakey])
var/datum/alternate_appearance/AA = aa
AA.hide(list(src))
return ..()
/atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5)
return (!density || !height)
/atom/proc/onCentcom()
var/turf/T = get_turf(src)
@@ -61,11 +86,11 @@
return 0
/atom/proc/attack_hulk(mob/living/carbon/human/hulk, do_attack_animation = 0)
if(do_attack_animation)
hulk.changeNext_move(CLICK_CD_MELEE)
add_logs(hulk, src, "punched", "hulk powers")
hulk.do_attack_animation(src)
/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
if(does_attack_animation)
user.changeNext_move(CLICK_CD_MELEE)
add_logs(user, src, "punched", "hulk powers")
user.do_attack_animation(src, ATTACK_EFFECT_SMASH)
/atom/proc/CheckParts(list/parts_list)
for(var/A in parts_list)
@@ -76,7 +101,7 @@
reagents.conditional_update()
else if(istype(A, /atom/movable))
var/atom/movable/M = A
if(istype(M.loc, /mob/living))
if(isliving(M.loc))
var/mob/living/L = M.loc
L.unEquip(M)
M.loc = src
@@ -97,8 +122,6 @@
/atom/proc/check_eye(mob/user)
return
/atom/proc/on_reagent_change()
return
/atom/proc/Bumped(AM as mob|obj)
return
@@ -202,17 +225,15 @@
return
/atom/proc/contents_explosion(severity, target)
for(var/atom/A in contents)
A.ex_act(severity, target)
CHECK_TICK
return
/atom/proc/ex_act(severity, target)
contents_explosion(severity, target)
/atom/proc/blob_act(obj/effect/blob/B)
/atom/proc/blob_act(obj/structure/blob/B)
return
/atom/proc/fire_act()
/atom/proc/fire_act(exposed_temperature, exposed_volume)
return
/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
@@ -327,7 +348,7 @@ var/list/blood_splatter_icons = list()
G.add_blood(blood_dna)
else
transfer_blood_dna(blood_dna)
bloody_hands = rand(2, 4)
bloody_hands = rand(2, 4)
update_inv_gloves() //handles bloody hands overlays and updating
return 1
@@ -339,12 +360,6 @@ var/list/blood_splatter_icons = list()
/atom/proc/wash_cream()
return 1
/atom/proc/change_area(var/area/oldarea, var/area/newarea)
change_area_name(oldarea.name, newarea.name)
/atom/proc/change_area_name(var/oldname, var/newname)
name = replacetext(name,oldname,newname)
/atom/proc/get_global_map_pos()
if(!islist(global_map) || isemptylist(global_map)) return
var/cur_x = null
@@ -362,7 +377,7 @@ var/list/blood_splatter_icons = list()
return 0
/atom/proc/isinspace()
if(istype(get_turf(src), /turf/open/space))
if(isspaceturf(get_turf(src)))
return 1
else
return 0
@@ -378,7 +393,7 @@ var/list/blood_splatter_icons = list()
/atom/proc/singularity_pull()
return
/atom/proc/acid_act(acidpwr, toxpwr, acid_volume)
/atom/proc/acid_act(acidpwr, acid_volume)
return
/atom/proc/emag_act()
@@ -422,7 +437,7 @@ var/list/blood_splatter_icons = list()
return
/atom/proc/add_vomit_floor(mob/living/carbon/M, toxvomit = 0)
if(istype(src,/turf) )
if(isturf(src))
var/obj/effect/decal/cleanable/vomit/V = PoolOrNew(/obj/effect/decal/cleanable/vomit, src)
// Make toxins vomit look different
if(toxvomit)
@@ -442,3 +457,88 @@ var/list/blood_splatter_icons = list()
//Hook for running code when a dir change occurs
/atom/proc/setDir(newdir)
dir = newdir
/atom/proc/mech_melee_attack(obj/mecha/M)
return
/*
Atom Colour Priority System
A System that gives finer control over which atom colour to colour the atom with.
The "highest priority" one is always displayed as opposed to the default of
"whichever was set last is displayed"
*/
/*
Adds an instance of colour_type to the atom's atom_colours list
*/
/atom/proc/add_atom_colour(coloration, colour_priority)
if(!atom_colours || !atom_colours.len)
atom_colours = list()
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
if(!coloration)
return
if(colour_priority > atom_colours.len)
return
atom_colours[colour_priority] = coloration
update_atom_colour()
/*
Removes an instance of colour_type from the atom's atom_colours list
*/
/atom/proc/remove_atom_colour(colour_priority, coloration)
if(!atom_colours)
atom_colours = list()
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
if(colour_priority > atom_colours.len)
return
if(coloration && atom_colours[colour_priority] != coloration)
return //if we don't have the expected color (for a specific priority) to remove, do nothing
atom_colours[colour_priority] = null
update_atom_colour()
/*
Resets the atom's color to null, and then sets it to the highest priority
colour available
*/
/atom/proc/update_atom_colour()
if(!atom_colours)
atom_colours = list()
atom_colours.len = COLOUR_PRIORITY_AMOUNT //four priority levels currently.
color = null
for(var/C in atom_colours)
if(islist(C))
var/list/L = C
if(L.len)
color = L
return
else if(C)
color = C
return
/atom/vv_edit_var(var_name, var_value)
if(!Debug2)
admin_spawned = TRUE
switch(var_name)
if("luminosity")
src.SetLuminosity(var_value)
return//prevent normal setting of this value
. = ..()
switch(var_name)
if("color")
add_atom_colour(color, ADMIN_COLOUR_PRIORITY)
/atom/vv_get_dropdown()
. = ..()
. += "---"
var/turf/curturf = get_turf(src)
if (curturf)
.["Jump to"] = "?_src_=holder;adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]"
.["Add reagent"] = "?_src_=vars;addreagent=\ref[src]"
.["Trigger EM pulse"] = "?_src_=vars;emp=\ref[src]"
.["Trigger explosion"] = "?_src_=vars;explode=\ref[src]"
+72 -49
View File
@@ -19,6 +19,7 @@
var/inertia_move_delay = 5
var/pass_flags = 0
var/moving_diagonally = 0 //0: not doing a diagonal move. 1 and 2: doing the first/second step of the diagonal move
var/list/client_mobs_in_contents // This contains all the client mobs within this container
glide_size = 8
appearance_flags = TILE_BOUND
@@ -64,13 +65,12 @@
moving_diagonally = SECOND_DIAG_STEP
. = step(src, SOUTH)
moving_diagonally = 0
return
if(!loc || (loc == oldloc && oldloc != newloc))
last_move = 0
return
update_client_hook(loc)
if(.)
Moved(oldloc, direct)
@@ -84,6 +84,8 @@
if (!inertia_moving)
inertia_next_move = world.time + inertia_move_delay
newtonian_move(Dir)
if (length(client_mobs_in_contents))
update_parallax_contents()
return 1
/atom/movable/Destroy()
@@ -134,9 +136,6 @@
continue
AM.Crossed(src)
Moved(oldloc, 0)
update_client_hook(destination)
return 1
return 0
@@ -151,33 +150,12 @@
reset_perspective(destination)
update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
/mob/living/carbon/brain/forceMove(atom/destination)
/mob/living/brain/forceMove(atom/destination)
if(container)
container.forceMove(destination)
return container.forceMove(destination)
else //something went very wrong.
CRASH("Brainmob without container.")
/mob/living/silicon/pai/forceMove(atom/destination)
if(card)
card.forceMove(destination)
else //something went very wrong.
CRASH("pAI without card")
/atom/movable/proc/update_client_hook(atom/destination)
if(locate(/mob) in src)
for(var/client/C in parallax_on_clients)
if((get_turf(C.eye) == destination) && (C.mob.hud_used))
C.mob.hud_used.update_parallax_values()
/mob/update_client_hook(atom/destination)
if(locate(/mob) in src)
for(var/client/C in parallax_on_clients)
if((get_turf(C.eye) == destination) && (C.mob.hud_used))
C.mob.hud_used.update_parallax_values()
else if(client && hud_used)
hud_used.update_parallax_values()
//Called whenever an object moves and by mobs when they attempt to move themselves through space
//And when an object or action applies a force on src, see newtonian_move() below
//Return 0 to have src start/keep drifting in a no-grav area and 1 to stop/not start drifting
@@ -265,7 +243,7 @@
while(target && ((dist_travelled < range && loc != finalturf) || !has_gravity(src))) //stop if we reached our destination (or max range) and aren't floating
var/slept = 0
if(!istype(loc, /turf))
if(!isturf(loc))
hit = 1
break
@@ -326,26 +304,6 @@
throw_impact(AM)
return 1
//Overlays
/atom/movable/overlay
var/atom/master = null
anchored = 1
/atom/movable/overlay/New()
verbs.Cut()
/atom/movable/overlay/attackby(a, b, c)
if (src.master)
return src.master.attackby(a, b, c)
/atom/movable/overlay/attack_paw(a, b, c)
if (src.master)
return src.master.attack_paw(a, b, c)
/atom/movable/overlay/attack_hand(a, b, c)
if (src.master)
return src.master.attack_hand(a, b, c)
/atom/movable/proc/handle_buckled_mob_movement(newloc,direct)
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
@@ -385,3 +343,68 @@
//called when a mob resists while inside a container that is itself inside something.
/atom/movable/proc/relay_container_resist(mob/living/user, obj/O)
return
/atom/movable/proc/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
if(!no_effect && (visual_effect_icon || used_item))
do_item_attack_animation(A, visual_effect_icon, used_item)
var/pixel_x_diff = 0
var/pixel_y_diff = 0
var/final_pixel_y = initial(pixel_y)
if(end_pixel_y)
final_pixel_y = end_pixel_y
var/direction = get_dir(src, A)
if(direction & NORTH)
pixel_y_diff = 8
else if(direction & SOUTH)
pixel_y_diff = -8
if(direction & EAST)
pixel_x_diff = 8
else if(direction & WEST)
pixel_x_diff = -8
animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2)
animate(pixel_x = initial(pixel_x), pixel_y = final_pixel_y, time = 2)
/atom/movable/proc/do_item_attack_animation(atom/A, visual_effect_icon, obj/item/used_item)
var/image/I
if(visual_effect_icon)
I = image('icons/effects/effects.dmi', A, visual_effect_icon, A.layer + 0.1)
else if(used_item)
I = image(used_item.icon, A, used_item.icon_state, A.layer + 0.1)
// Scale the icon.
I.transform *= 0.75
// The icon should not rotate.
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
// Set the direction of the icon animation.
var/direction = get_dir(src, A)
if(direction & NORTH)
I.pixel_y = -16
else if(direction & SOUTH)
I.pixel_y = 16
if(direction & EAST)
I.pixel_x = -16
else if(direction & WEST)
I.pixel_x = 16
if(!direction) // Attacked self?!
I.pixel_z = 16
if(!I)
return
flick_overlay(I, clients, 5) // 5 ticks/half a second
// And animate the attack!
animate(I, alpha = 175, pixel_x = 0, pixel_y = 0, pixel_z = 0, time = 3)
/atom/movable/vv_get_dropdown()
. = ..()
. -= "Jump to"
.["Follow"] = "?_src_=holder;adminplayerobservefollow=\ref[src]"
+66 -21
View File
@@ -61,19 +61,25 @@
//called when a carbon changes virus
/mob/living/carbon/proc/check_virus()
var/threat = 0
for(var/datum/disease/D in viruses)
if((!(D.visibility_flags & HIDDEN_SCANNER)) && (D.severity != NONTHREAT))
return 1
return 0
if(!(D.visibility_flags & HIDDEN_SCANNER))
if (D.severity != NONTHREAT) //a buffing virus gets an icon
threat = 2
return threat //harmful viruses have priority
else
threat = 1 //aka good virus
return threat
//helper for getting the appropriate health status
/proc/RoundHealth(mob/living/M)
if(M.stat == DEAD || (M.status_flags & FAKEDEATH))
return "health-100" //what's our health? it doesn't matter, we're dead, or faking
var/maxhealth = M.maxHealth
var/maxi_health = M.maxHealth
if(iscarbon(M) && M.health < 0)
maxhealth = 100 //so crit shows up right for aliens and other high-health carbon mobs; noncarbons don't have crit.
var/resulthealth = (M.health / maxhealth) * 100
maxi_health = 100 //so crit shows up right for aliens and other high-health carbon mobs; noncarbons don't have crit.
var/resulthealth = (M.health / maxi_health) * 100
switch(resulthealth)
if(100 to INFINITY)
return "health100"
@@ -131,6 +137,8 @@
/mob/living/proc/med_hud_set_health()
var/image/holder = hud_list[HEALTH_HUD]
holder.icon_state = "hud[RoundHealth(src)]"
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
//for carbon suit sensors
/mob/living/carbon/med_hud_set_health()
@@ -143,6 +151,8 @@
//called when a carbon changes stat, virus or XENO_HOST
/mob/living/proc/med_hud_set_status()
var/image/holder = hud_list[STATUS_HUD]
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
if(stat == DEAD || (status_flags & FAKEDEATH))
holder.icon_state = "huddead"
else
@@ -150,12 +160,20 @@
/mob/living/carbon/med_hud_set_status()
var/image/holder = hud_list[STATUS_HUD]
var/icon/I = icon(icon, icon_state, dir)
var/virus_state = check_virus()
var/mob/living/simple_animal/borer/B = has_brain_worms()
holder.pixel_y = I.Height() - world.icon_size
if(status_flags & XENO_HOST)
holder.icon_state = "hudxeno"
else if(stat == DEAD || (status_flags & FAKEDEATH))
holder.icon_state = "huddead"
else if(check_virus())
else if(has_brain_worms() && B != null && B.controlling)
holder.icon_state = "hudbrainworm"
else if(virus_state == 2)
holder.icon_state = "hudill"
else if(virus_state == 1)
holder.icon_state = "hudbuff"
else
holder.icon_state = "hudhealthy"
@@ -168,6 +186,8 @@
/mob/living/carbon/human/proc/sec_hud_set_ID()
var/image/holder = hud_list[ID_HUD]
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
holder.icon_state = "hudno_id"
if(wear_id)
holder.icon_state = "hud[ckey(wear_id.GetJobName())]"
@@ -181,20 +201,27 @@
for(var/i in list(IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD))
holder = hud_list[i]
holder.icon_state = null
for(var/obj/item/weapon/implant/I in src)
if(I.implanted)
if(istype(I,/obj/item/weapon/implant/tracking))
holder = hud_list[IMPTRACK_HUD]
holder.icon_state = "hud_imp_tracking"
else if(istype(I,/obj/item/weapon/implant/mindshield))
holder = hud_list[IMPLOYAL_HUD]
holder.icon_state = "hud_imp_loyal"
else if(istype(I,/obj/item/weapon/implant/chem))
holder = hud_list[IMPCHEM_HUD]
holder.icon_state = "hud_imp_chem"
for(var/obj/item/weapon/implant/I in implants)
if(istype(I,/obj/item/weapon/implant/tracking))
holder = hud_list[IMPTRACK_HUD]
var/icon/IC = icon(icon, icon_state, dir)
holder.pixel_y = IC.Height() - world.icon_size
holder.icon_state = "hud_imp_tracking"
else if(istype(I,/obj/item/weapon/implant/mindshield))
holder = hud_list[IMPLOYAL_HUD]
var/icon/IC = icon(icon, icon_state, dir)
holder.pixel_y = IC.Height() - world.icon_size
holder.icon_state = "hud_imp_loyal"
else if(istype(I,/obj/item/weapon/implant/chem))
holder = hud_list[IMPCHEM_HUD]
var/icon/IC = icon(icon, icon_state, dir)
holder.pixel_y = IC.Height() - world.icon_size
holder.icon_state = "hud_imp_chem"
/mob/living/carbon/human/proc/sec_hud_set_security_status()
var/image/holder = hud_list[WANTED_HUD]
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
var/perpname = get_face_name(get_id_name(""))
if(perpname)
var/datum/data/record/R = find_record("name", perpname, data_core.security)
@@ -240,6 +267,8 @@
//Sillycone hooks
/mob/living/silicon/proc/diag_hud_set_health()
var/image/holder = hud_list[DIAG_HUD]
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
if(stat == DEAD)
holder.icon_state = "huddiagdead"
else
@@ -247,6 +276,8 @@
/mob/living/silicon/proc/diag_hud_set_status()
var/image/holder = hud_list[DIAG_STAT_HUD]
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
switch(stat)
if(CONSCIOUS)
holder.icon_state = "hudstat"
@@ -258,7 +289,9 @@
//Borgie battery tracking!
/mob/living/silicon/robot/proc/diag_hud_set_borgcell()
var/image/holder = hud_list[DIAG_BATT_HUD]
if (cell)
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
if(cell)
var/chargelvl = (cell.charge/cell.maxcharge)
holder.icon_state = "hudbatt[RoundDiagBar(chargelvl)]"
else
@@ -269,12 +302,16 @@
~~~~~~~~~~~~~~~~~~~~~*/
/obj/mecha/proc/diag_hud_set_mechhealth()
var/image/holder = hud_list[DIAG_MECH_HUD]
holder.icon_state = "huddiag[RoundDiagBar(health/initial(health))]"
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
holder.icon_state = "huddiag[RoundDiagBar(obj_integrity/max_integrity)]"
/obj/mecha/proc/diag_hud_set_mechcell()
var/image/holder = hud_list[DIAG_BATT_HUD]
if (cell)
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
if(cell)
var/chargelvl = cell.charge/cell.maxcharge
holder.icon_state = "hudbatt[RoundDiagBar(chargelvl)]"
else
@@ -283,6 +320,8 @@
/obj/mecha/proc/diag_hud_set_mechstat()
var/image/holder = hud_list[DIAG_STAT_HUD]
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
holder.icon_state = null
if(internal_damage)
holder.icon_state = "hudwarn"
@@ -292,10 +331,14 @@
~~~~~~~~~~*/
/mob/living/simple_animal/bot/proc/diag_hud_set_bothealth()
var/image/holder = hud_list[DIAG_HUD]
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
holder.icon_state = "huddiag[RoundDiagBar(health/maxHealth)]"
/mob/living/simple_animal/bot/proc/diag_hud_set_botstat() //On (With wireless on or off), Off, EMP'ed
var/image/holder = hud_list[DIAG_STAT_HUD]
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
if(on)
holder.icon_state = "hudstat"
else if(stat) //Generally EMP causes this
@@ -305,6 +348,8 @@
/mob/living/simple_animal/bot/proc/diag_hud_set_botmode() //Shows a bot's current operation
var/image/holder = hud_list[DIAG_BOT_HUD]
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
if(client) //If the bot is player controlled, it will not be following mode logic!
holder.icon_state = "hudsentient"
return
+36 -1
View File
@@ -41,7 +41,7 @@
//MIND PROCS
//these are called by mind.transfer_to()
/datum/mind/proc/transfer_antag_huds(var/datum/atom_hud/antag/newhud)
/datum/mind/proc/transfer_antag_huds(datum/atom_hud/antag/newhud)
leave_all_huds()
ticker.mode.set_antag_hud(current, antag_hud_icon_state)
if(newhud)
@@ -55,3 +55,38 @@
for(var/datum/atom_hud/data/hud in huds)
if(current in hud.hudusers)
hud.remove_hud_from(current)
/datum/atom_hud/antag/gang
var/color = null
/datum/atom_hud/antag/gang/add_to_hud(atom/A)
if(!A)
return
var/image/holder = A.hud_list[ANTAG_HUD]
if(holder)
holder.color = color
..()
/datum/atom_hud/antag/gang/remove_from_hud(atom/A)
if(!A)
return
var/image/holder = A.hud_list[ANTAG_HUD]
if(holder)
holder.color = null
..()
/datum/atom_hud/antag/gang/join_hud(mob/M)
if(!istype(M))
CRASH("join_hud(): [M] ([M.type]) is not a mob!")
var/image/holder = M.hud_list[ANTAG_HUD]
if(holder)
holder.color = color
..()
/datum/atom_hud/antag/gang/leave_hud(mob/M)
if(!istype(M))
CRASH("leave_hud(): [M] ([M.type]) is not a mob!")
var/image/holder = M.hud_list[ANTAG_HUD]
if(holder)
holder.color = null
..()
+64 -64
View File
@@ -1,7 +1,7 @@
/obj/item/weapon/antag_spawner
throw_speed = 1
throw_range = 5
w_class = 1
w_class = WEIGHT_CLASS_TINY
var/used = 0
/obj/item/weapon/antag_spawner/proc/spawn_antag(client/C, turf/T, type = "")
@@ -47,21 +47,24 @@
if(H.stat || H.restrained())
return
if(!istype(H, /mob/living/carbon/human))
if(!ishuman(H))
return 1
if(loc == H || (in_range(src, H) && istype(loc, /turf)))
if(loc == H || (in_range(src, H) && isturf(loc)))
H.set_machine(src)
if(href_list["school"])
if (used)
if(used)
H << "You already used this contract!"
return
var/list/candidates = get_candidates(ROLE_WIZARD)
var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src)
if(candidates.len)
src.used = 1
var/client/C = pick(candidates)
spawn_antag(C, get_turf(H.loc), href_list["school"])
if(H.mind)
if(used)
H << "You already used this contract!"
return
used = 1
var/mob/dead/observer/theghost = pick(candidates)
spawn_antag(theghost.client, get_turf(src), href_list["school"])
if(H && H.mind)
ticker.mode.update_wiz_icons_added(H.mind)
else
H << "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later."
@@ -71,40 +74,44 @@
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
C.prefs.copy_to(M)
M.key = C.key
M << "<B>You are the [usr.real_name]'s apprentice! You are bound by magic contract to follow their orders and help them in accomplishing their goals."
var/wizard_name = "the wizard"
if(usr)
wizard_name = usr.real_name
M << "<B>You are [wizard_name]'s apprentice! You are bound by magic contract to follow their orders and help them in accomplishing their goals."
switch(type)
if("destruction")
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball(null))
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball."
M.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball(null))
M << "<B>Your service has not gone unrewarded, however. Studying under [wizard_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball."
if("bluespace")
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt."
M << "<B>Your service has not gone unrewarded, however. Studying under [wizard_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt."
if("healing")
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/charge(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(null))
M.equip_to_slot_or_del(new /obj/item/weapon/gun/magic/staff/healing(M), slot_r_hand)
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall."
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/forcewall(null))
M.put_in_hands_or_del(new /obj/item/weapon/gun/magic/staff/healing(M))
M << "<B>Your service has not gone unrewarded, however. Studying under [wizard_name], you have learned livesaving survival spells. You are able to cast charge and forcewall."
if("robeless")
M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
M << "<B>Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap."
M << "<B>Your service has not gone unrewarded, however. Studying under [wizard_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap."
equip_antag(M)
var/wizard_name_first = pick(wizard_first)
var/wizard_name_second = pick(wizard_second)
var/randomname = "[wizard_name_first] [wizard_name_second]"
var/datum/objective/protect/new_objective = new /datum/objective/protect
new_objective.owner = M:mind
new_objective:target = usr:mind
new_objective.explanation_text = "Protect [usr.real_name], the wizard."
M.mind.objectives += new_objective
if(usr)
var/datum/objective/protect/new_objective = new /datum/objective/protect
new_objective.owner = M.mind
new_objective.target = usr.mind
new_objective.explanation_text = "Protect [usr.real_name], the wizard."
M.mind.objectives += new_objective
ticker.mode.apprentices += M.mind
M.mind.special_role = "apprentice"
ticker.mode.update_wiz_icons_added(M.mind)
M << sound('sound/effects/magic.ogg')
var/newname = copytext(sanitize(input(M, "You are the wizard's apprentice. Would you like to change your name to something else?", "Name change", randomname) as null|text),1,MAX_NAME_LEN)
var/newname = copytext(sanitize(input(M, "You are [wizard_name]'s apprentice. Would you like to change your name to something else?", "Name change", randomname) as null|text),1,MAX_NAME_LEN)
if (!newname)
newname = randomname
M.mind.name = newname
@@ -115,7 +122,7 @@
/obj/item/weapon/antag_spawner/contract/equip_antag(mob/target)
target.equip_to_slot_or_del(new /obj/item/device/radio/headset(target), slot_ears)
target.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(target), slot_w_uniform)
target.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(target), slot_shoes)
target.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal/magic(target), slot_shoes)
target.equip_to_slot_or_del(new /obj/item/clothing/suit/wizrobe(target), slot_wear_suit)
target.equip_to_slot_or_del(new /obj/item/clothing/head/wizard(target), slot_head)
target.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(target), slot_back)
@@ -149,11 +156,13 @@
if(!(check_usability(user)))
return
var/list/nuke_candidates = get_candidates(ROLE_OPERATIVE, 3000, "operative")
if(nuke_candidates.len > 0)
var/list/nuke_candidates = pollCandidatesForMob("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, src)
if(nuke_candidates.len)
if(!(check_usability(user)))
return
used = 1
var/client/C = pick(nuke_candidates)
spawn_antag(C, get_turf(src.loc), "syndieborg")
var/mob/dead/observer/theghost = pick(nuke_candidates)
spawn_antag(theghost.client, get_turf(src), "syndieborg")
var/datum/effect_system/spark_spread/S = new /datum/effect_system/spark_spread
S.set_up(4, 1, src)
S.start()
@@ -162,14 +171,10 @@
user << "<span class='warning'>Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.</span>"
/obj/item/weapon/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T)
var/new_op_code = "Ask your leader!"
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
C.prefs.copy_to(M)
M.key = C.key
var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in nuke_list
if(nuke)
new_op_code = nuke.r_code
M.mind.make_Nuke(T, new_op_code, 0, FALSE)
M.mind.make_Nuke(null, null, 0, FALSE)
var/newname = M.dna.species.random_name(M.gender,0,ticker.mode.nukeops_lastname)
M.mind.name = newname
M.real_name = newname
@@ -213,12 +218,7 @@
R.mmi.brainmob.name = brainopsname
R.key = C.key
ticker.mode.syndicates += R.mind
ticker.mode.update_synd_icons_added(R.mind)
R.mind.special_role = "syndicate"
R.faction = list("syndicate")
R.mind.make_Nuke(null, nuke_code = null,leader=0, telecrystals = TRUE)
///////////SLAUGHTER DEMON
@@ -228,23 +228,25 @@
icon = 'icons/obj/wizard.dmi'
icon_state = "vial"
var/shatter_msg = "<span class='notice'>You shatter the bottle, no \
turning back now!</span>"
var/veil_msg = "<span class='warning'>You sense a dark presence lurking \
just beyond the veil...</span>"
var/shatter_msg = "<span class='notice'>You shatter the bottle, no turning back now!</span>"
var/veil_msg = "<span class='warning'>You sense a dark presence lurking just beyond the veil...</span>"
var/objective_verb = "Kill"
var/mob/living/demon_type = /mob/living/simple_animal/slaughter
/obj/item/weapon/antag_spawner/slaughter_demon/attack_self(mob/user)
var/list/demon_candidates = get_candidates(ROLE_ALIEN)
if(user.z != 1)
user << "<span class='notice'>You should probably wait until you reach the station.</span>"
return
if(demon_candidates.len > 0)
if(used)
return
var/list/demon_candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", null, null, ROLE_ALIEN, 50, src)
if(demon_candidates.len)
if(used)
return
used = 1
var/client/C = pick(demon_candidates)
spawn_antag(C, get_turf(src.loc), initial(demon_type.name))
var/mob/dead/observer/theghost = pick(demon_candidates)
spawn_antag(theghost.client, get_turf(src), initial(demon_type.name))
user << shatter_msg
user << veil_msg
playsound(user.loc, 'sound/effects/Glassbr1.ogg', 100, 1)
@@ -262,33 +264,31 @@
S.mind.assigned_role = S.name
S.mind.special_role = S.name
ticker.mode.traitors += S.mind
var/datum/objective/assassinate/new_objective = new /datum/objective/assassinate
new_objective.owner = S.mind
new_objective.target = usr.mind
new_objective.explanation_text = "[objective_verb] [usr.real_name], \
the one who summoned you."
S.mind.objectives += new_objective
var/datum/objective/assassinate/new_objective
if(usr)
new_objective = new /datum/objective/assassinate
new_objective.owner = S.mind
new_objective.target = usr.mind
new_objective.explanation_text = "[objective_verb] [usr.real_name], the one who summoned you."
S.mind.objectives += new_objective
var/datum/objective/new_objective2 = new /datum/objective
new_objective2.owner = S.mind
new_objective2.explanation_text = "[objective_verb] everyone else \
while you're at it."
new_objective2.explanation_text = "[objective_verb] everyone[usr ? " else while you're at it":""]."
S.mind.objectives += new_objective2
S << S.playstyle_string
S << "<B>You are currently not currently in the same plane of \
existence as the station. Ctrl+Click a blood pool to manifest.</B>"
S << "<B>Objective #[1]</B>: [new_objective.explanation_text]"
S << "<B>Objective #[2]</B>: [new_objective2.explanation_text]"
S << "<B>You are currently not currently in the same plane of existence as the station. \
Ctrl+Click a blood pool to manifest.</B>"
if(new_objective)
S << "<B>Objective #[1]</B>: [new_objective.explanation_text]"
S << "<B>Objective #[new_objective ? "[2]":"[1]"]</B>: [new_objective2.explanation_text]"
/obj/item/weapon/antag_spawner/slaughter_demon/laughter
name = "vial of tickles"
desc = "A magically infused bottle of clown love, distilled from \
countless hugging attacks. Used in funny rituals to attract \
adorable creatures."
desc = "A magically infused bottle of clown love, distilled from countless hugging attacks. Used in funny rituals to attract adorable creatures."
icon = 'icons/obj/wizard.dmi'
icon_state = "vial"
color = "#FF69B4" // HOT PINK
veil_msg = "<span class='warning'>You sense an adorable presence \
lurking just beyond the veil...</span>"
veil_msg = "<span class='warning'>You sense an adorable presence lurking just beyond the veil...</span>"
objective_verb = "Hug and Tickle"
demon_type = /mob/living/simple_animal/slaughter/laughter
+17 -13
View File
@@ -1,4 +1,4 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
//Few global vars to track the blob
var/list/blobs = list() //complete list of all blobs made.
@@ -20,13 +20,19 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
round_ends_with_antag_death = 1
var/burst = 0
announce_span = "green"
announce_text = "Dangerous gelatinous organisms are spreading throughout the station!\n\
<span class='green'>Blobs</span>: Consume the station and spread as far as you can.\n\
<span class='notice'>Crew</span>: Fight back the blobs and minimize station damage."
var/message_sent = FALSE
var/cores_to_spawn = 1
var/players_per_core = 25
var/blob_point_rate = 3
var/blob_base_starting_points = 80
var/blobwincount = 350
var/blobwincount = 250
var/messagedelay_low = 2400 //in deciseconds
var/messagedelay_high = 3600 //blob report will be sent after a random value between these (minimum 4 minutes, maximum 6 minutes)
@@ -36,7 +42,8 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
/datum/game_mode/blob/pre_setup()
cores_to_spawn = max(round(num_players()/players_per_core, 1), 1)
blobwincount = initial(blobwincount) * cores_to_spawn
var/win_multiplier = 1 + (0.1 * cores_to_spawn)
blobwincount = initial(blobwincount) * cores_to_spawn * win_multiplier
for(var/j = 0, j < cores_to_spawn, j++)
if (!antag_candidates.len)
@@ -61,11 +68,6 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
candidates += player
return candidates
/datum/game_mode/blob/announce()
world << "<B>The current game mode is - <font color='green'>Blob</font>!</B>"
world << "<B>A dangerous alien organism is rapidly spreading throughout the station!</B>"
world << "You must kill it all while minimizing the damage to the station."
/datum/game_mode/blob/proc/show_message(message)
for(var/datum/mind/blob in blob_overminds)
blob.current << message
@@ -73,12 +75,13 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
/datum/game_mode/blob/post_setup()
for(var/datum/mind/blob in blob_overminds)
var/mob/camera/blob/B = blob.current.become_overmind(1)
var/mob/camera/blob/B = blob.current.become_overmind(TRUE, round(blob_base_starting_points/blob_overminds.len))
B.mind.name = B.name
var/turf/T = pick(blobstart)
B.loc = T
B.base_point_rate = blob_point_rate
SSshuttle.emergencyNoEscape = 1
SSshuttle.registerHostileEnvironment(src)
// Disable the blob event for this round.
var/datum/round_event_control/blob/B = locate() in SSevent.control
@@ -91,9 +94,10 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
sleep(message_delay)
send_intercept(1)
message_sent = TRUE
sleep(24000) //40 minutes, plus burst_delay*3(minimum of 6 minutes, maximum of 8)
send_intercept(2) //if the blob has been alive this long, it's time to bomb it
if(!replacementmode)
send_intercept(2) //if the blob has been alive this long, it's time to bomb it
return ..()
+32 -10
View File
@@ -1,16 +1,16 @@
/datum/game_mode/blob/check_finished()
if(blobwincount <= blobs_legit.len)//Blob took over
return 1
if(overminds.len)
return 0
for(var/datum/mind/blob in blob_overminds)
if(isovermind(blob.current))
var/mob/camera/blob/B = blob.current
if(B.blob_core || !B.placed)
return 0
if(!blob_cores.len) //blob is dead
if(config.continuous["blob"])
message_sent = FALSE //disable the win count at this point
continuous_sanity_checked = 1 //Nonstandard definition of "alive" gets past the check otherwise
SSshuttle.emergencyNoEscape = 0
if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
SSshuttle.emergency.mode = SHUTTLE_DOCKED
SSshuttle.emergency.timer = world.time
priority_announce("Hostile enviroment resolved. You have 3 minutes to board the Emergency Shuttle.", null, 'sound/AI/shuttledock.ogg', "Priority")
SSshuttle.clearHostileEnvironment(src)
return ..()
return 1
return ..()
@@ -22,23 +22,45 @@
if(blobwincount <= blobs_legit.len)
feedback_set_details("round_end_result","win - blob took over")
world << "<FONT size = 3><B>The blob has taken over the station!</B></FONT>"
world << "<B>The entire station was eaten by the Blob</B>"
world << "<B>The entire station was eaten by the Blob!</B>"
log_game("Blob mode completed with a blob victory.")
ticker.news_report = BLOB_WIN
else if(station_was_nuked)
feedback_set_details("round_end_result","halfwin - nuke")
world << "<FONT size = 3><B>Partial Win: The station has been destroyed!</B></FONT>"
world << "<B>Directive 7-12 has been successfully carried out preventing the Blob from spreading.</B>"
world << "<B>Directive 7-12 has been successfully carried out, preventing the Blob from spreading.</B>"
log_game("Blob mode completed with a tie (station destroyed).")
ticker.news_report = BLOB_NUKE
else if(!blob_cores.len)
feedback_set_details("round_end_result","loss - blob eliminated")
world << "<FONT size = 3><B>The staff has won!</B></FONT>"
world << "<B>The alien organism has been eradicated from the station</B>"
world << "<B>The alien organism has been eradicated from the station!</B>"
log_game("Blob mode completed with a crew victory.")
ticker.news_report = BLOB_DESTROYED
..()
return 1
/datum/game_mode/blob/printplayer(datum/mind/ply, fleecheck)
if((ply in blob_overminds))
var/text = "<br><b>[ply.key]</b> was <b>[ply.name]</b>"
if(isovermind(ply.current))
var/mob/camera/blob/B = ply.current
text += "<b>(<font color=\"[B.blob_reagent_datum.color]\">[B.blob_reagent_datum.name]</font>)</b> and"
if(B.blob_core)
text += " <span class='greenannounce'>survived</span>"
else
text += " <span class='boldannounce'>was destroyed</span>"
else
text += " and <span class='boldannounce'>was destroyed</span>"
return text
return ..()
/datum/game_mode/proc/auto_declare_completion_blob()
if(istype(ticker.mode,/datum/game_mode/blob) )
var/datum/game_mode/blob/blob_mode = src
+14 -9
View File
@@ -1,4 +1,4 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
/datum/game_mode/blob/send_intercept(report = 0)
var/intercepttext = ""
@@ -16,7 +16,7 @@
print_command_report(intercepttext,"Level 5-6 Biohazard Response Procedures")
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/AI/outbreak5.ogg')
if(2)
var/nukecode = rand(10000, 99999)
var/nukecode = random_nukecode()
for(var/obj/machinery/nuclearbomb/bomb in machines)
if(bomb && bomb.r_code)
if(bomb.z == ZLEVEL_STATION)
@@ -57,20 +57,23 @@
/datum/station_state/proc/count(count_territories)
for(var/turf/T in block(locate(1,1,1), locate(world.maxx,world.maxy,1)))
if(istype(T,/turf/open/floor))
if(!(T:burnt))
if(isfloorturf(T))
var/turf/open/floor/TF = T
if(!(TF.burnt))
src.floor += 12
else
src.floor += 1
if(istype(T, /turf/closed/wall))
if(T:intact)
if(iswallturf(T))
var/turf/closed/wall/TW = T
if(TW.intact)
src.wall += 2
else
src.wall += 1
if(istype(T, /turf/closed/wall/r_wall))
if(T:intact)
var/turf/closed/wall/r_wall/TRW = T
if(TRW.intact)
src.r_wall += 2
else
src.r_wall += 1
@@ -79,8 +82,10 @@
for(var/obj/O in T.contents)
if(istype(O, /obj/structure/window))
src.window += 1
else if(istype(O, /obj/structure/grille) && (!O:destroyed))
src.grille += 1
else if(istype(O, /obj/structure/grille))
var/obj/structure/grille/GR = O
if(!GR.broken)
src.grille += 1
else if(istype(O, /obj/machinery/door))
src.door += 1
else if(istype(O, /obj/machinery))
+32 -24
View File
@@ -14,22 +14,22 @@
minbodytemp = 0
maxbodytemp = 360
unique_name = 1
a_intent = "harm"
a_intent = INTENT_HARM
var/mob/camera/blob/overmind = null
var/obj/effect/blob/factory/factory = null
var/obj/structure/blob/factory/factory = null
/mob/living/simple_animal/hostile/blob/update_icons()
if(overmind)
color = overmind.blob_reagent_datum.color
add_atom_colour(overmind.blob_reagent_datum.color, FIXED_COLOUR_PRIORITY)
else
color = initial(color)
remove_atom_colour(FIXED_COLOUR_PRIORITY)
/mob/living/simple_animal/hostile/blob/Destroy()
if(overmind)
overmind.blob_mobs -= src
return ..()
/mob/living/simple_animal/hostile/blob/blob_act(obj/effect/blob/B)
/mob/living/simple_animal/hostile/blob/blob_act(obj/structure/blob/B)
if(stat != DEAD && health < maxHealth)
for(var/i in 1 to 2)
var/obj/effect/overlay/temp/heal/H = PoolOrNew(/obj/effect/overlay/temp/heal, get_turf(src)) //hello yes you are being healed
@@ -39,24 +39,27 @@
H.color = "#000000"
adjustHealth(-maxHealth*0.0125)
/mob/living/simple_animal/hostile/blob/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
/mob/living/simple_animal/hostile/blob/fire_act(exposed_temperature, exposed_volume)
..()
adjustFireLoss(Clamp(0.01 * exposed_temperature, 1, 5))
if(exposed_temperature)
adjustFireLoss(Clamp(0.01 * exposed_temperature, 1, 5))
else
adjustFireLoss(5)
/mob/living/simple_animal/hostile/blob/CanPass(atom/movable/mover, turf/target, height = 0)
if(istype(mover, /obj/effect/blob))
if(istype(mover, /obj/structure/blob))
return 1
return ..()
/mob/living/simple_animal/hostile/blob/Process_Spacemove(movement_dir = 0)
for(var/obj/effect/blob/B in range(1, src))
for(var/obj/structure/blob/B in range(1, src))
return 1
return ..()
/mob/living/simple_animal/hostile/blob/handle_inherent_channels(message, message_mode)
if(message_mode == MODE_BINARY)
blob_chat(message)
return ITALICS | REDUCE_RANGE
return 1
else
..()
@@ -79,17 +82,19 @@
desc = "A floating, fragile spore."
icon_state = "blobpod"
icon_living = "blobpod"
health = 40
maxHealth = 40
health = 30
maxHealth = 30
verb_say = "psychically pulses"
verb_ask = "psychically probes"
verb_exclaim = "psychically yells"
verb_yell = "psychically screams"
melee_damage_lower = 2
melee_damage_upper = 4
obj_damage = 20
environment_smash = 1
attacktext = "hits"
attack_sound = 'sound/weapons/genhit1.ogg'
flying = 1
movement_type = FLYING
del_on_death = 1
deathmessage = "explodes into a cloud of gas!"
var/death_cloud_size = 1 //size of cloud produced from a dying spore
@@ -97,7 +102,7 @@
var/is_zombie = 0
gold_core_spawnable = 1
/mob/living/simple_animal/hostile/blob/blobspore/New(loc, var/obj/effect/blob/factory/linked_node)
/mob/living/simple_animal/hostile/blob/blobspore/New(loc, var/obj/structure/blob/factory/linked_node)
if(istype(linked_node))
factory = linked_node
factory.spores += src
@@ -125,7 +130,7 @@
desc = "A shambling corpse animated by the blob."
melee_damage_lower += 8
melee_damage_upper += 11
flying = 0
movement_type = GROUND
death_cloud_size = 0
icon = H.icon
icon_state = "zombie_s"
@@ -168,20 +173,23 @@
return ..()
/mob/living/simple_animal/hostile/blob/blobspore/update_icons()
..()
if(overmind)
add_atom_colour(overmind.blob_reagent_datum.complementary_color, FIXED_COLOUR_PRIORITY)
else
remove_atom_colour(FIXED_COLOUR_PRIORITY)
if(is_zombie)
cut_overlays()
overlays = human_overlays
var/image/I = image('icons/mob/blob.dmi', icon_state = "blob_head")
if(overmind)
I.color = overmind.blob_reagent_datum.color
I.color = overmind.blob_reagent_datum.complementary_color
color = initial(color)//looks better.
add_overlay(I)
/mob/living/simple_animal/hostile/blob/blobspore/weak
name = "fragile blob spore"
health = 20
maxHealth = 20
health = 15
maxHealth = 15
melee_damage_lower = 1
melee_damage_upper = 2
death_cloud_size = 0
@@ -199,9 +207,9 @@
health = 200
maxHealth = 200
damage_coeff = list(BRUTE = 0.5, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
next_move_modifier = 1.5 //slow-ass attack speed, 3 times higher than how fast the blob can attack
melee_damage_lower = 20
melee_damage_upper = 20
obj_damage = 60
attacktext = "slams"
attack_sound = 'sound/effects/blobattack.ogg'
verb_say = "gurgles"
@@ -209,7 +217,7 @@
verb_exclaim = "roars"
verb_yell = "bellows"
force_threshold = 10
pressure_resistance = 40
pressure_resistance = 50
mob_size = MOB_SIZE_LARGE
see_invisible = SEE_INVISIBLE_MINIMUM
see_in_dark = 8
@@ -225,13 +233,13 @@
if(independent)
return // strong independent blobbernaut that don't need no blob
var/damagesources = 0
if(!(locate(/obj/effect/blob) in range(2, src)))
if(!(locate(/obj/structure/blob) in range(2, src)))
damagesources++
if(!factory)
damagesources++
if(damagesources)
for(var/i in 1 to damagesources)
adjustHealth(maxHealth*0.025) //take 2.5% maxhealth as damage when not near the blob or if the naut has no factory, 5% if both
adjustHealth(maxHealth*0.025) //take 2.5% of max health as damage when not near the blob or if the naut has no factory, 5% if both
var/list/viewing = list()
for(var/mob/M in viewers(src))
if(M.client)
@@ -274,7 +282,7 @@
..(gibbed)
if(factory)
factory.naut = null //remove this naut from its factory
factory.maxhealth = initial(factory.maxhealth)
factory.max_integrity = initial(factory.max_integrity)
flick("blobbernaut_death", src)
/mob/living/simple_animal/hostile/blob/blobbernaut/independent
+23 -23
View File
@@ -1,13 +1,13 @@
/obj/effect/blob/core
/obj/structure/blob/core
name = "blob core"
icon = 'icons/mob/blob.dmi'
icon_state = "blank_blob"
desc = "A huge, pulsating yellow mass."
health = 400
maxhealth = 400
obj_integrity = 400
max_integrity = 400
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 75, acid = 90)
explosion_block = 6
point_return = -1
atmosblock = 1
health_regen = 0 //we regen in Life() instead of when pulsed
var/core_regen = 2
var/overmind_get_delay = 0 //we don't want to constantly try to find an overmind, this var tracks when we'll try to get an overmind again
@@ -15,7 +15,7 @@
var/point_rate = 2
/obj/effect/blob/core/New(loc, client/new_overmind = null, new_rate = 2, placed = 0)
/obj/structure/blob/core/New(loc, client/new_overmind = null, new_rate = 2, placed = 0)
blob_cores += src
START_PROCESSING(SSobj, src)
poi_list |= src
@@ -27,10 +27,10 @@
point_rate = new_rate
..()
/obj/effect/blob/core/scannerreport()
/obj/structure/blob/core/scannerreport()
return "Directs the blob's expansion, gradually expands, and sustains nearby blob spores and blobbernauts."
/obj/effect/blob/core/update_icon()
/obj/structure/blob/core/update_icon()
cut_overlays()
color = null
var/image/I = new('icons/mob/blob.dmi', "blob")
@@ -40,7 +40,7 @@
var/image/C = new('icons/mob/blob.dmi', "blob_core_overlay")
add_overlay(C)
/obj/effect/blob/core/Destroy()
/obj/structure/blob/core/Destroy()
blob_cores -= src
if(overmind)
overmind.blob_core = null
@@ -49,36 +49,36 @@
poi_list -= src
return ..()
/obj/effect/blob/core/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return
/obj/effect/blob/core/ex_act(severity, target)
/obj/structure/blob/core/ex_act(severity, target)
var/damage = 50 - 10 * severity //remember, the core takes half brute damage, so this is 20/15/10 damage based on severity
take_damage(damage, BRUTE)
take_damage(damage, BRUTE, "bomb", 0)
/obj/effect/blob/core/check_health()
..()
if(overmind) //we should have an overmind, but...
overmind.update_health_hud()
/obj/structure/blob/core/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir, overmind_reagent_trigger = 1)
. = ..()
if(obj_integrity > 0)
if(overmind) //we should have an overmind, but...
overmind.update_health_hud()
/obj/effect/blob/core/Life()
/obj/structure/blob/core/Life()
if(qdeleted(src))
return
if(!overmind)
create_overmind()
else
if(resource_delay <= world.time)
resource_delay = world.time + 10 // 1 second
overmind.add_points(point_rate)
health = min(maxhealth, health+core_regen)
obj_integrity = min(max_integrity, obj_integrity+core_regen)
if(overmind)
overmind.update_health_hud()
Pulse_Area(overmind, 12, 4, 3)
for(var/obj/effect/blob/normal/B in range(1, src))
for(var/obj/structure/blob/normal/B in range(1, src))
if(prob(5))
B.change_to(/obj/effect/blob/shield/core, overmind)
B.change_to(/obj/structure/blob/shield/core, overmind)
..()
/obj/effect/blob/core/proc/create_overmind(client/new_overmind, override_delay)
/obj/structure/blob/core/proc/create_overmind(client/new_overmind, override_delay)
if(overmind_get_delay > world.time && !override_delay)
return
@@ -91,7 +91,7 @@
var/list/candidates = list()
if(!new_overmind)
candidates = get_candidates(ROLE_BLOB)
candidates = pollCandidatesForMob("Do you want to play as a blob overmind?", ROLE_BLOB, null, ROLE_BLOB, 50, src) //we're technically not a mob but behave similarly
if(candidates.len)
C = pick(candidates)
else
+6 -6
View File
@@ -1,10 +1,10 @@
/obj/effect/blob/factory
/obj/structure/blob/factory
name = "factory blob"
icon = 'icons/mob/blob.dmi'
icon_state = "blob_factory"
desc = "A thick spire of tendrils."
health = 200
maxhealth = 200
obj_integrity = 200
max_integrity = 200
health_regen = 1
point_return = 25
var/list/spores = list()
@@ -14,12 +14,12 @@
var/spore_cooldown = 80 //8 seconds between spores and after spore death
/obj/effect/blob/factory/scannerreport()
/obj/structure/blob/factory/scannerreport()
if(naut)
return "It is currently sustaining a blobbernaut, making it fragile and unable to produce blob spores."
return "Will produce a blob spore every few seconds."
/obj/effect/blob/factory/Destroy()
/obj/structure/blob/factory/Destroy()
for(var/mob/living/simple_animal/hostile/blob/blobspore/spore in spores)
if(spore.factory == src)
spore.factory = null
@@ -30,7 +30,7 @@
spores = null
return ..()
/obj/effect/blob/factory/Be_Pulsed()
/obj/structure/blob/factory/Be_Pulsed()
. = ..()
if(naut)
return
+13 -16
View File
@@ -1,41 +1,38 @@
/obj/effect/blob/node
/obj/structure/blob/node
name = "blob node"
icon = 'icons/mob/blob.dmi'
icon_state = "blank_blob"
desc = "A large, pulsating yellow mass."
health = 200
maxhealth = 200
obj_integrity = 200
max_integrity = 200
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 65, acid = 90)
health_regen = 3
point_return = 25
atmosblock = 1
/obj/effect/blob/node/New(loc, var/h = 100)
/obj/structure/blob/node/New(loc)
blob_nodes += src
START_PROCESSING(SSobj, src)
..(loc, h)
..()
/obj/effect/blob/node/scannerreport()
/obj/structure/blob/node/scannerreport()
return "Gradually expands and sustains nearby blob spores and blobbernauts."
/obj/effect/blob/node/update_icon()
/obj/structure/blob/node/update_icon()
cut_overlays()
color = null
var/image/I = new('icons/mob/blob.dmi', "blob")
if(overmind)
I.color = overmind.blob_reagent_datum.color
src.add_overlay(I)
add_overlay(I)
var/image/C = new('icons/mob/blob.dmi', "blob_node_overlay")
src.add_overlay(C)
add_overlay(C)
/obj/effect/blob/node/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return
/obj/effect/blob/node/Destroy()
/obj/structure/blob/node/Destroy()
blob_nodes -= src
STOP_PROCESSING(SSobj, src)
return ..()
/obj/effect/blob/node/Life()
/obj/structure/blob/node/Life()
Pulse_Area(overmind, 10, 3, 2)
color = null
+7 -7
View File
@@ -1,26 +1,26 @@
/obj/effect/blob/resource
/obj/structure/blob/resource
name = "resource blob"
icon = 'icons/mob/blob.dmi'
icon_state = "blob_resource"
desc = "A thin spire of slightly swaying tendrils."
health = 60
maxhealth = 60
obj_integrity = 60
max_integrity = 60
point_return = 15
var/resource_delay = 0
/obj/effect/blob/resource/scannerreport()
/obj/structure/blob/resource/scannerreport()
return "Gradually supplies the blob with resources, increasing the rate of expansion."
/obj/effect/blob/resource/creation_action()
/obj/structure/blob/resource/creation_action()
if(overmind)
overmind.resource_blobs += src
/obj/effect/blob/resource/Destroy()
/obj/structure/blob/resource/Destroy()
if(overmind)
overmind.resource_blobs -= src
return ..()
/obj/effect/blob/resource/Be_Pulsed()
/obj/structure/blob/resource/Be_Pulsed()
. = ..()
if(resource_delay > world.time)
return
+25 -10
View File
@@ -1,21 +1,36 @@
/obj/effect/blob/shield
/obj/structure/blob/shield
name = "strong blob"
icon = 'icons/mob/blob.dmi'
icon_state = "blob_idle"
icon_state = "blob_shield"
desc = "A solid wall of slightly twitching tendrils."
health = 150
maxhealth = 150
brute_resist = 0.1
obj_integrity = 150
max_integrity = 150
brute_resist = 0.25
explosion_block = 3
point_return = 4
atmosblock = 1
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 90, acid = 90)
/obj/effect/blob/shield/scannerreport()
return "Will prevent the spread of atmospheric changes."
/obj/effect/blob/shield/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return
/obj/structure/blob/shield/scannerreport()
if(atmosblock)
return "Will prevent the spread of atmospheric changes."
return "N/A"
/obj/effect/blob/shield/core
/obj/structure/blob/shield/core
point_return = 0
/obj/structure/blob/shield/update_icon()
..()
if(obj_integrity <= 75)
icon_state = "blob_shield_damaged"
name = "weakened strong blob"
desc = "A wall of twitching tendrils."
atmosblock = 0
else
icon_state = initial(icon_state)
name = initial(name)
desc = initial(desc)
atmosblock = 1
air_update_turf(1)
+35 -24
View File
@@ -1,17 +1,20 @@
/mob/camera/blob
name = "Blob Overmind"
real_name = "Blob Overmind"
desc = "The overmind. It controls the blob."
icon = 'icons/mob/blob.dmi'
icon_state = "marker"
mouse_opacity = 1
move_on_shuttle = 1
see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
invisibility = INVISIBILITY_OBSERVER
layer = FLY_LAYER
pass_flags = PASSBLOB
faction = list("blob")
var/obj/effect/blob/core/blob_core = null // The blob overmind's core
var/obj/structure/blob/core/blob_core = null // The blob overmind's core
var/blob_points = 0
var/max_blob_points = 100
var/last_attack = 0
@@ -26,7 +29,8 @@
var/manualplace_min_time = 600 //in deciseconds //a minute, to get bearings
var/autoplace_max_time = 3600 //six minutes, as long as should be needed
/mob/camera/blob/New(loc, pre_placed = 0, mode_made = 0)
/mob/camera/blob/New(loc, pre_placed = 0, mode_made = 0, starting_points = 60)
blob_points = starting_points
if(pre_placed) //we already have a core!
manualplace_min_time = 0
autoplace_max_time = 0
@@ -42,10 +46,9 @@
name = new_name
real_name = new_name
last_attack = world.time
var/list/possible_reagents = list()
for(var/type in (subtypesof(/datum/reagent/blob)))
possible_reagents.Add(new type)
blob_reagent_datum = pick(possible_reagents)
var/datum/reagent/blob/BC = pick((subtypesof(/datum/reagent/blob)))
blob_reagent_datum = new BC
color = blob_reagent_datum.complementary_color
if(blob_core)
blob_core.update_icon()
@@ -69,19 +72,20 @@
/mob/camera/blob/Destroy()
for(var/BL in blobs)
var/obj/effect/blob/B = BL
if(B.overmind == src)
var/obj/structure/blob/B = BL
if(B && B.overmind == src)
B.overmind = null
B.update_icon() //reset anything that was ours
for(var/BLO in blob_mobs)
var/mob/living/simple_animal/hostile/blob/BM = BLO
BM.overmind = null
BM.update_icons()
if(BM)
BM.overmind = null
BM.update_icons()
overminds -= src
if(ghostimage)
ghost_darkness_images -= ghostimage
qdel(ghostimage)
ghostimage = null;
ghostimage = null
updateallghostimages()
return ..()
@@ -91,18 +95,23 @@
src << "<span class='notice'>You are the overmind!</span>"
blob_help()
update_health_hud()
add_points(0)
/mob/camera/blob/examine(mob/user)
..()
if(blob_reagent_datum)
user << "Its chemical is <font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</font>."
/mob/camera/blob/update_health_hud()
if(blob_core)
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#e36600'>[round(blob_core.health)]</font></div>"
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#e36600'>[round(blob_core.obj_integrity)]</font></div>"
for(var/mob/living/simple_animal/hostile/blob/blobbernaut/B in blob_mobs)
if(B.hud_used && B.hud_used.blobpwrdisplay)
B.hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_core.health)]</font></div>"
B.hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_core.obj_integrity)]</font></div>"
/mob/camera/blob/proc/add_points(points)
if(points != 0)
blob_points = Clamp(blob_points + points, 0, max_blob_points)
hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(src.blob_points)]</font></div>"
blob_points = Clamp(blob_points + points, 0, max_blob_points)
hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_points)]</font></div>"
/mob/camera/blob/say(message)
if (!message)
@@ -141,15 +150,20 @@
/mob/camera/blob/emote(act,m_type=1,message = null)
return
/mob/camera/blob/blob_act(obj/effect/blob/B)
/mob/camera/blob/blob_act(obj/structure/blob/B)
return
/mob/camera/blob/Stat()
..()
if(statpanel("Status"))
if(blob_core)
stat(null, "Core Health: [blob_core.health]")
stat(null, "Core Health: [blob_core.obj_integrity]")
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
if(ticker && istype(ticker.mode, /datum/game_mode/blob))
var/datum/game_mode/blob/B = ticker.mode
stat(null, "Blobs to Win: [blobs_legit.len]/[B.blobwincount]")
else
stat(null, "Total Blobs: [blobs.len]")
if(free_chem_rerolls)
stat(null, "You have [free_chem_rerolls] Free Chemical Reroll\s Remaining")
if(!placed)
@@ -159,17 +173,14 @@
/mob/camera/blob/Move(NewLoc, Dir = 0)
if(placed)
var/obj/effect/blob/B = locate() in range("3x3", NewLoc)
var/obj/structure/blob/B = locate() in range("3x3", NewLoc)
if(B)
loc = NewLoc
else
return 0
else
var/area/A = get_area(NewLoc)
if(istype(NewLoc, /turf/open/space) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
if(isspaceturf(NewLoc) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
return 0
loc = NewLoc
return 1
/mob/camera/blob/proc/can_attack()
return (world.time > (last_attack + CLICK_CD_RANGE))
+83 -46
View File
@@ -28,13 +28,13 @@
src << "<span class='warning'>This spot is too dense to place a blob core on!</span>"
return 0
for(var/obj/O in T)
if(istype(O, /obj/effect/blob))
if(istype(O, /obj/effect/blob/normal))
if(istype(O, /obj/structure/blob))
if(istype(O, /obj/structure/blob/normal))
qdel(O)
else
src << "<span class='warning'>There is already a blob here!</span>"
return 0
if(O.density)
else if(O.density)
src << "<span class='warning'>This spot is too dense to place a blob core on!</span>"
return 0
if(world.time <= manualplace_min_time && world.time <= autoplace_max_time)
@@ -46,7 +46,7 @@
if(placed && blob_core)
blob_core.forceMove(loc)
else
var/obj/effect/blob/core/core = new(get_turf(src), null, point_rate, 1)
var/obj/structure/blob/core/core = new(get_turf(src), null, point_rate, 1)
core.overmind = src
blob_core = core
core.update_icon()
@@ -67,35 +67,36 @@
set desc = "Move your camera to a selected node."
if(blob_nodes.len)
var/list/nodes = list()
for(var/i = 1; i <= blob_nodes.len; i++)
nodes["Blob Node #[i]"] = blob_nodes[i]
for(var/i in 1 to blob_nodes.len)
var/obj/structure/blob/node/B = blob_nodes[i]
nodes["Blob Node #[i] ([B.overmind ? "[B.overmind.blob_reagent_datum.name]":"No Chemical"])"] = B
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
var/obj/effect/blob/node/chosen_node = nodes[node_name]
var/obj/structure/blob/node/chosen_node = nodes[node_name]
if(chosen_node)
src.loc = chosen_node.loc
loc = chosen_node.loc
/mob/camera/blob/proc/createSpecial(price, blobType, nearEquals, needsNode, turf/T)
if(!T)
T = get_turf(src)
var/obj/effect/blob/B = (locate(/obj/effect/blob) in T)
var/obj/structure/blob/B = (locate(/obj/structure/blob) in T)
if(!B)
src << "<span class='warning'>There is no blob here!</span>"
return
if(!istype(B, /obj/effect/blob/normal))
if(!istype(B, /obj/structure/blob/normal))
src << "<span class='warning'>Unable to use this blob, find a normal one.</span>"
return
if(needsNode && nodes_required)
if(!(locate(/obj/effect/blob/node) in orange(3, T)) && !(locate(/obj/effect/blob/core) in orange(4, T)))
if(!(locate(/obj/structure/blob/node) in orange(3, T)) && !(locate(/obj/structure/blob/core) in orange(4, T)))
src << "<span class='warning'>You need to place this blob closer to a node or core!</span>"
return //handholdotron 2000
if(nearEquals)
for(var/obj/effect/blob/L in orange(nearEquals, T))
for(var/obj/structure/blob/L in orange(nearEquals, T))
if(L.type == blobType)
src << "<span class='warning'>There is a similar blob nearby, move more than [nearEquals] tiles away from it!</span>"
return
if(!can_buy(price))
return
var/obj/effect/blob/N = B.change_to(blobType, src)
var/obj/structure/blob/N = B.change_to(blobType, src)
return N
/mob/camera/blob/verb/toggle_node_req()
@@ -110,50 +111,51 @@
/mob/camera/blob/verb/create_shield_power()
set category = "Blob"
set name = "Create Shield Blob (10)"
set name = "Create Shield Blob (15)"
set desc = "Create a shield blob, which will block fire and is hard to kill."
create_shield()
/mob/camera/blob/proc/create_shield(turf/T)
createSpecial(10, /obj/effect/blob/shield, 0, 0, T)
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
/mob/camera/blob/verb/create_resource()
set category = "Blob"
set name = "Create Resource Blob (40)"
set desc = "Create a resource tower which will generate resources for you."
createSpecial(40, /obj/effect/blob/resource, 4, 1)
createSpecial(40, /obj/structure/blob/resource, 4, 1)
/mob/camera/blob/verb/create_node()
set category = "Blob"
set name = "Create Node Blob (60)"
set name = "Create Node Blob (50)"
set desc = "Create a node, which will power nearby factory and resource blobs."
createSpecial(60, /obj/effect/blob/node, 5, 0)
createSpecial(50, /obj/structure/blob/node, 5, 0)
/mob/camera/blob/verb/create_factory()
set category = "Blob"
set name = "Create Factory Blob (60)"
set desc = "Create a spore tower that will spawn spores to harass your enemies."
createSpecial(60, /obj/effect/blob/factory, 7, 1)
createSpecial(60, /obj/structure/blob/factory, 7, 1)
/mob/camera/blob/verb/create_blobbernaut()
set category = "Blob"
set name = "Create Blobbernaut (40)"
set desc = "Create a powerful blobbernaut which is mildly smart and will attack enemies."
var/turf/T = get_turf(src)
var/obj/effect/blob/factory/B = locate(/obj/effect/blob/factory) in T
var/obj/structure/blob/factory/B = locate(/obj/structure/blob/factory) in T
if(!B)
src << "<span class='warning'>You must be on a factory blob!</span>"
return
if(B.naut) //if it already made a blobbernaut, it can't do it again
src << "<span class='warning'>This factory blob is already sustaining a blobbernaut.</span>"
return
if(B.health < B.maxhealth * 0.5)
if(B.obj_integrity < B.max_integrity * 0.5)
src << "<span class='warning'>This factory blob is too damaged to sustain a blobbernaut.</span>"
return
if(!can_buy(40))
return
B.maxhealth = initial(B.maxhealth) * 0.25 //factories that produced a blobbernaut have much lower health
B.check_health()
B.max_integrity = initial(B.max_integrity) * 0.25 //factories that produced a blobbernaut have much lower health
B.obj_integrity = min(B.obj_integrity, B.max_integrity)
B.update_icon()
B.visible_message("<span class='warning'><b>The blobbernaut [pick("rips", "tears", "shreds")] its way out of the factory blob!</b></span>")
playsound(B.loc, 'sound/effects/splat.ogg', 50, 1)
var/mob/living/simple_animal/hostile/blob/blobbernaut/blobber = new /mob/living/simple_animal/hostile/blob/blobbernaut(get_turf(B))
@@ -165,11 +167,9 @@
blobber.notransform = 1 //stop the naut from moving around
blobber.adjustHealth(blobber.maxHealth * 0.5)
blob_mobs += blobber
var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50) //players must answer rapidly
var/client/C = null
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50, blobber) //players must answer rapidly
if(candidates.len) //if we got at least one candidate, they're a blobbernaut now.
C = pick(candidates)
blobber.notransform = 0
var/client/C = pick(candidates)
blobber.key = C.key
blobber << 'sound/effects/blobattack.ogg'
blobber << 'sound/effects/attackblob.ogg'
@@ -178,23 +178,33 @@
blobber << "You can communicate with other blobbernauts and overminds via <b>:b</b>"
blobber << "Your overmind's blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!"
blobber << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]"
else
blobber.notransform = 0 //otherwise, just let it move
if(blobber)
blobber.notransform = 0
/mob/camera/blob/verb/relocate_core()
set category = "Blob"
set name = "Relocate Core (80)"
set desc = "Swaps the locations of your core and the selected node."
var/turf/T = get_turf(src)
var/obj/effect/blob/node/B = locate(/obj/effect/blob/node) in T
var/obj/structure/blob/node/B = locate(/obj/structure/blob/node) in T
if(!B)
src << "<span class='warning'>You must be on a blob node!</span>"
return
if(!blob_core)
src << "<span class='userdanger'>You have no core and are about to die! May you rest in peace.</span>"
return
var/area/A = get_area(T)
if(isspaceturf(T) || A && !A.blob_allowed)
src << "<span class='warning'>You cannot relocate your core here!</span>"
return
if(!can_buy(80))
return
var/turf/old_turf = blob_core.loc
blob_core.loc = T
B.loc = old_turf
var/turf/old_turf = get_turf(blob_core)
var/olddir = blob_core.dir
blob_core.forceMove(T)
blob_core.setDir(B.dir)
B.forceMove(old_turf)
B.setDir(olddir)
/mob/camera/blob/verb/revert()
set category = "Blob"
@@ -204,7 +214,7 @@
remove_blob(T)
/mob/camera/blob/proc/remove_blob(turf/T)
var/obj/effect/blob/B = locate() in T
var/obj/structure/blob/B = locate() in T
if(!B)
src << "<span class='warning'>There is no blob there!</span>"
return
@@ -221,21 +231,22 @@
/mob/camera/blob/verb/expand_blob_power()
set category = "Blob"
set name = "Expand/Attack Blob (5)"
set name = "Expand/Attack Blob (4)"
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects."
var/turf/T = get_turf(src)
expand_blob(T)
/mob/camera/blob/proc/expand_blob(turf/T)
if(!can_attack())
if(world.time < last_attack)
return
var/obj/effect/blob/OB = locate() in circlerange(T, 1)
if(!OB)
var/list/possibleblobs = list()
for(var/obj/structure/blob/AB in range(T, 1))
possibleblobs += AB
if(!possibleblobs.len)
src << "<span class='warning'>There is no blob adjacent to the target tile!</span>"
return
if(can_buy(5))
if(can_buy(4))
var/attacksuccess = FALSE
last_attack = world.time
for(var/mob/living/L in T)
if("blob" in L.faction) //no friendly/dead fire
continue
@@ -244,16 +255,37 @@
var/mob_protection = L.get_permeability_protection()
blob_reagent_datum.reaction_mob(L, VAPOR, 25, 1, mob_protection, src)
blob_reagent_datum.send_message(L)
var/obj/effect/blob/B = locate() in T
var/obj/structure/blob/B = locate() in T
if(B)
if(attacksuccess) //if we successfully attacked a turf with a blob on it, don't refund shit
B.blob_attack_animation(T, src)
else
src << "<span class='warning'>There is a blob there!</span>"
add_points(5) //otherwise, refund all of the cost
return
add_points(4) //otherwise, refund all of the cost
else
OB.expand(T, src)
var/list/cardinalblobs = list()
var/list/diagonalblobs = list()
for(var/I in possibleblobs)
var/obj/structure/blob/IB = I
if(get_dir(IB, T) in cardinal)
cardinalblobs += IB
else
diagonalblobs += IB
var/obj/structure/blob/OB
if(cardinalblobs.len)
OB = pick(cardinalblobs)
OB.expand(T, src)
else
OB = pick(diagonalblobs)
if(attacksuccess)
OB.blob_attack_animation(T, src)
playsound(OB, 'sound/effects/splat.ogg', 50, 1)
else
add_points(4) //if we're attacking diagonally and didn't hit anything, refund
if(attacksuccess)
last_attack = world.time + CLICK_CD_MELEE
else
last_attack = world.time + CLICK_CD_RAPID
/mob/camera/blob/verb/rally_spores_power()
set category = "Blob"
@@ -298,8 +330,9 @@
/mob/camera/blob/proc/set_chemical()
var/datum/reagent/blob/BC = pick((subtypesof(/datum/reagent/blob) - blob_reagent_datum.type))
blob_reagent_datum = new BC
color = blob_reagent_datum.complementary_color
for(var/BL in blobs)
var/obj/effect/blob/B = BL
var/obj/structure/blob/B = BL
B.update_icon()
for(var/BLO in blob_mobs)
var/mob/living/simple_animal/hostile/blob/BM = BLO
@@ -308,6 +341,8 @@
BM << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]"
src << "Your reagent is now: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!"
src << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.description]"
if(blob_reagent_datum.effectdesc)
src << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.effectdesc]"
/mob/camera/blob/verb/blob_help()
set category = "Blob"
@@ -316,6 +351,8 @@
src << "<b>As the overmind, you can control the blob!</b>"
src << "Your blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!"
src << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.description]"
if(blob_reagent_datum.effectdesc)
src << "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.effectdesc]"
src << "<b>You can expand, which will attack people, damage objects, or place a Normal Blob if the tile is clear.</b>"
src << "<i>Normal Blobs</i> will expand your reach and can be upgraded into special blobs that perform certain functions."
src << "<b>You can upgrade normal blobs into the following types of blob:</b>"
@@ -329,4 +366,4 @@
src << "Attempting to talk will send a message to all other overminds, allowing you to coordinate with them."
if(!placed && autoplace_max_time <= world.time)
src << "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [round((autoplace_max_time - world.time)/600, 0.5)] minutes.</font></span>"
src << "<span class='big'><font color=\"#EE4000\">You [manualplace_min_time ? "will be able to":"can"] manually place your blob core by pressing the button in the bottom right corner of the screen.</font></span>"
src << "<span class='big'><font color=\"#EE4000\">You [manualplace_min_time ? "will be able to":"can"] manually place your blob core by pressing the Place Blob Core button in the bottom right corner of the screen.</font></span>"
+127 -137
View File
@@ -1,5 +1,5 @@
//I will need to recode parts of this but I am way too tired atm //I don't know who left this comment but they never did come back
/obj/effect/blob
/obj/structure/blob
name = "blob"
icon = 'icons/mob/blob.dmi'
luminosity = 1
@@ -7,35 +7,37 @@
density = 0 //this being 0 causes two bugs, being able to attack blob tiles behind other blobs and being unable to move on blob tiles in no gravity, but turning it to 1 causes the blob mobs to be unable to path through blobs, which is probably worse.
opacity = 0
anchored = 1
explosion_block = 1
layer = BELOW_MOB_LAYER
var/point_return = 0 //How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed.
var/health = 30
var/maxhealth = 30
obj_integrity = 30
max_integrity = 30
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 80, acid = 70)
var/health_regen = 2 //how much health this blob regens when pulsed
var/pulse_timestamp = 0 //we got pulsed/healed when?
var/pulse_timestamp = 0 //we got pulsed when?
var/heal_timestamp = 0 //we got healed when?
var/brute_resist = 0.5 //multiplies brute damage by this
var/fire_resist = 1 //multiplies burn damage by this
var/atmosblock = 0 //if the blob blocks atmos and heat spread
var/mob/camera/blob/overmind
/obj/effect/blob/New(loc)
/obj/structure/blob/New(loc)
var/area/Ablob = get_area(loc)
if(Ablob.blob_allowed) //Is this area allowed for winning as blob?
blobs_legit += src
blobs += src //Keep track of the blob in the normal list either way
src.setDir(pick(1, 2, 4, 8))
src.update_icon()
..(loc)
setDir(pick(cardinal))
update_icon()
..()
ConsumeTile()
if(atmosblock)
CanAtmosPass = ATMOS_PASS_NO
air_update_turf(1)
/obj/structure/blob/proc/creation_action() //When it's created by the overmind, do this.
return
/obj/effect/blob/proc/creation_action() //When it's created by the overmind, do this.
return
/obj/effect/blob/Destroy()
/obj/structure/blob/Destroy()
if(atmosblock)
atmosblock = 0
air_update_turf(1)
@@ -44,8 +46,10 @@
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Expand() is no longer broken, no check necessary.
return ..()
/obj/structure/blob/blob_act()
return
/obj/effect/blob/Adjacent(var/atom/neighbour)
/obj/structure/blob/Adjacent(var/atom/neighbour)
. = ..()
if(.)
var/result = 0
@@ -54,89 +58,90 @@
for(var/A in dirs)
if(direction == text2num(A))
for(var/B in dirs[A])
var/C = locate(/obj/effect/blob) in get_step(src, B)
var/C = locate(/obj/structure/blob) in get_step(src, B)
if(C)
result++
. -= result - 1
/obj/effect/blob/CanAtmosPass(turf/T)
return !atmosblock
/obj/effect/blob/BlockSuperconductivity()
/obj/structure/blob/BlockSuperconductivity()
return atmosblock
/obj/effect/blob/CanPass(atom/movable/mover, turf/target, height=0)
/obj/structure/blob/CanPass(atom/movable/mover, turf/target, height=0)
if(height==0)
return 1
if(istype(mover) && mover.checkpass(PASSBLOB))
return 1
return 0
/obj/effect/blob/CanAStarPass(ID, dir, caller)
/obj/structure/blob/CanAStarPass(ID, dir, caller)
. = 0
if(ismovableatom(caller))
var/atom/movable/mover = caller
. = . || mover.checkpass(PASSBLOB)
/obj/effect/blob/proc/check_health(cause)
health = Clamp(health, 0, maxhealth)
if(health <= 0)
if(overmind)
overmind.blob_reagent_datum.death_reaction(src, cause)
qdel(src) //we dead now
return
return
/obj/effect/blob/update_icon() //Updates color based on overmind color if we have an overmind.
/obj/structure/blob/update_icon() //Updates color based on overmind color if we have an overmind.
if(overmind)
color = overmind.blob_reagent_datum.color
add_atom_colour(overmind.blob_reagent_datum.color, FIXED_COLOUR_PRIORITY)
else
color = null
return
remove_atom_colour(FIXED_COLOUR_PRIORITY)
/obj/effect/blob/process()
/obj/structure/blob/process()
Life()
/obj/structure/blob/proc/Life()
return
/obj/effect/blob/proc/Life()
return
/obj/effect/blob/proc/Pulse_Area(pulsing_overmind = overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
/obj/structure/blob/proc/Pulse_Area(pulsing_overmind = overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
src.Be_Pulsed()
if(claim_range)
for(var/obj/effect/blob/B in urange(claim_range, src, 1))
if(!B.overmind && !istype(B, /obj/effect/blob/core) && prob(30))
B.overmind = pulsing_overmind //reclaim unclaimed, non-core blobs.
B.update_icon()
if(pulse_range)
for(var/obj/effect/blob/B in orange(pulse_range, src))
var/expanded = FALSE
if(prob(70) && expand())
expanded = TRUE
var/list/blobs_to_affect = list()
for(var/obj/structure/blob/B in urange(claim_range, src, 1))
blobs_to_affect += B
shuffle(blobs_to_affect)
for(var/L in blobs_to_affect)
var/obj/structure/blob/B = L
if(!B.overmind && !istype(B, /obj/structure/blob/core) && prob(30))
B.overmind = pulsing_overmind //reclaim unclaimed, non-core blobs.
B.update_icon()
var/distance = get_dist(get_turf(src), get_turf(B))
var/expand_probablity = max(20 - distance * 8, 1)
if(B.Adjacent(src))
expand_probablity = 20
if(distance <= expand_range)
var/can_expand = TRUE
if(blobs_to_affect.len >= 120 && B.heal_timestamp > world.time)
can_expand = FALSE
if(can_expand && B.pulse_timestamp <= world.time && prob(expand_probablity))
var/obj/structure/blob/newB = B.expand(null, null, !expanded) //expansion falls off with range but is faster near the blob causing the expansion
if(newB)
if(expanded)
qdel(newB)
expanded = TRUE
if(distance <= pulse_range)
B.Be_Pulsed()
if(expand_range)
if(prob(85))
src.expand()
for(var/obj/effect/blob/B in orange(expand_range, src))
if(prob(max(13 - get_dist(get_turf(src), get_turf(B)) * 4, 1))) //expand falls off with range but is faster near the blob causing the expansion
B.expand()
return
/obj/effect/blob/proc/Be_Pulsed()
/obj/structure/blob/proc/Be_Pulsed()
if(pulse_timestamp <= world.time)
ConsumeTile()
health = min(maxhealth, health+health_regen)
if(heal_timestamp <= world.time)
obj_integrity = min(max_integrity, obj_integrity+health_regen)
heal_timestamp = world.time + 20
update_icon()
pulse_timestamp = world.time + 10
return 1 //we did it, we were pulsed!
return 0 //oh no we failed
/obj/effect/blob/proc/ConsumeTile()
/obj/structure/blob/proc/ConsumeTile()
for(var/atom/A in loc)
A.blob_act(src)
if(istype(loc, /turf/closed/wall))
if(iswallturf(loc))
loc.blob_act(src) //don't ask how a wall got on top of the core, just eat it
/obj/effect/blob/proc/blob_attack_animation(atom/A = null, controller) //visually attacks an atom
/obj/structure/blob/proc/blob_attack_animation(atom/A = null, controller) //visually attacks an atom
var/obj/effect/overlay/temp/blob/O = PoolOrNew(/obj/effect/overlay/temp/blob, src.loc)
O.setDir(dir)
if(controller)
var/mob/camera/blob/BO = controller
O.color = BO.blob_reagent_datum.color
@@ -147,14 +152,14 @@
O.do_attack_animation(A) //visually attack the whatever
return O //just in case you want to do something to the animation.
/obj/effect/blob/proc/expand(turf/T = null, controller = null, expand_reaction = 1)
/obj/structure/blob/proc/expand(turf/T = null, controller = null, expand_reaction = 1)
if(!T)
var/list/dirs = list(1,2,4,8)
for(var/i = 1 to 4)
var/dirn = pick(dirs)
dirs.Remove(dirn)
T = get_step(src, dirn)
if(!(locate(/obj/effect/blob) in T))
if(!(locate(/obj/structure/blob) in T))
break
else
T = null
@@ -162,7 +167,7 @@
return 0
var/make_blob = TRUE //can we make a blob?
if(istype(T, /turf/open/space) && !(locate(/obj/structure/lattice) in T) && prob(80))
if(isspaceturf(T) && !(locate(/obj/structure/lattice) in T) && prob(80))
make_blob = FALSE
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Let's give some feedback that we DID try to spawn in space, since players are used to it
@@ -176,7 +181,7 @@
A.blob_act(src) //also hit everything in the turf
if(make_blob) //well, can we?
var/obj/effect/blob/B = new /obj/effect/blob/normal(src.loc)
var/obj/structure/blob/B = new /obj/structure/blob/normal(src.loc)
if(controller)
B.overmind = controller
else
@@ -187,7 +192,7 @@
B.loc = T
B.update_icon()
if(B.overmind && expand_reaction)
B.overmind.blob_reagent_datum.expand_reaction(src, B, T)
B.overmind.blob_reagent_datum.expand_reaction(src, B, T, controller)
return B
else
blob_attack_animation(T, controller)
@@ -198,43 +203,30 @@
blob_attack_animation(T, controller) //if we can't, animate that we attacked
return null
/obj/effect/blob/ex_act(severity, target)
..()
var/damage = 150 - 20 * severity
take_damage(damage, BRUTE)
/obj/effect/blob/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
..()
var/damage = Clamp(0.01 * exposed_temperature, 0, 4)
take_damage(damage, BURN)
/obj/effect/blob/emp_act(severity)
/obj/structure/blob/emp_act(severity)
if(severity > 0)
if(overmind)
overmind.blob_reagent_datum.emp_reaction(src, severity)
if(prob(100 - severity * 30))
PoolOrNew(/obj/effect/overlay/temp/emp, get_turf(src))
/obj/effect/blob/tesla_act(power)
/obj/structure/blob/tesla_act(power)
..()
if(overmind)
if(overmind.blob_reagent_datum.tesla_reaction(src, power))
take_damage(power/400, BURN)
take_damage(power/400, BURN, "energy")
else
take_damage(power/400, BURN)
take_damage(power/400, BURN, "energy")
/obj/effect/blob/extinguish()
/obj/structure/blob/extinguish()
..()
if(overmind)
overmind.blob_reagent_datum.extinguish_reaction(src)
/obj/effect/blob/bullet_act(var/obj/item/projectile/Proj)
..()
take_damage(Proj.damage, Proj.damage_type, Proj)
return 0
/obj/structure/blob/hulk_damage()
return 15
/obj/effect/blob/attackby(obj/item/I, mob/user, params)
/obj/structure/blob/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/device/analyzer))
user.changeNext_move(CLICK_CD_MELEE)
user << "<b>The analyzer beeps once, then reports:</b><br>"
@@ -244,7 +236,7 @@
else
return ..()
/obj/effect/blob/proc/chemeffectreport(mob/user)
/obj/structure/blob/proc/chemeffectreport(mob/user)
if(overmind)
user << "<b>Material: <font color=\"[overmind.blob_reagent_datum.color]\">[overmind.blob_reagent_datum.name]</font><span class='notice'>.</span></b>"
user << "<b>Material Effects:</b> <span class='notice'>[overmind.blob_reagent_datum.analyzerdescdamage]</span>"
@@ -252,69 +244,67 @@
else
user << "<b>No Material Detected!</b><br>"
/obj/effect/blob/proc/typereport(mob/user)
/obj/structure/blob/proc/typereport(mob/user)
user << "<b>Blob Type:</b> <span class='notice'>[uppertext(initial(name))]</span>"
user << "<b>Health:</b> <span class='notice'>[health]/[maxhealth]</span>"
user << "<b>Health:</b> <span class='notice'>[obj_integrity]/[max_integrity]</span>"
user << "<b>Effects:</b> <span class='notice'>[scannerreport()]</span>"
/obj/effect/blob/attacked_by(obj/item/I, mob/living/user)
user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(src)
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
visible_message("<span class='danger'>[user] has attacked the [src.name] with \the [I]!</span>")
if(I.damtype == BURN)
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
take_damage(I.force, I.damtype, user)
/obj/effect/blob/attack_animal(mob/living/simple_animal/M)
/obj/structure/blob/attack_animal(mob/living/simple_animal/M)
if("blob" in M.faction) //sorry, but you can't kill the blob as a blobbernaut
return
M.changeNext_move(CLICK_CD_MELEE)
M.do_attack_animation(src)
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
visible_message("<span class='danger'>\The [M] has attacked the [src.name]!</span>")
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
take_damage(damage, M.melee_damage_type, M)
return
..()
/obj/effect/blob/attack_alien(mob/living/carbon/alien/humanoid/M)
M.changeNext_move(CLICK_CD_MELEE)
M.do_attack_animation(src)
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
visible_message("<span class='danger'>[M] has slashed the [src.name]!</span>")
var/damage = rand(15, 30)
take_damage(damage, BRUTE, M)
return
/obj/effect/blob/proc/take_damage(damage, damage_type, cause = null, overmind_reagent_trigger = 1)
switch(damage_type) //blobs only take brute and burn damage
/obj/structure/blob/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
if(BRUTE)
damage = max(damage * brute_resist, 0)
if(damage_amount)
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
else
playsound(src, 'sound/weapons/tap.ogg', 50, 1)
if(BURN)
damage = max(damage * fire_resist, 0)
if(CLONE) //this is basically a marker for 'don't modify the damage'
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
/obj/structure/blob/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
switch(damage_type)
if(BRUTE)
damage_amount *= brute_resist
if(BURN)
damage_amount *= fire_resist
if(CLONE)
else
damage = 0
if(overmind && overmind_reagent_trigger)
damage = overmind.blob_reagent_datum.damage_reaction(src, health, damage, damage_type, cause) //pass the blob, its health before damage, the damage being done, the type of damage being done, and the cause.
health -= damage
update_icon()
check_health(cause)
return 0
var/armor_protection = 0
if(damage_flag)
armor_protection = armor[damage_flag]
damage_amount = round(damage_amount * (100 - armor_protection)*0.01, 0.1)
if(overmind && damage_flag)
damage_amount = overmind.blob_reagent_datum.damage_reaction(src, damage_amount, damage_type, damage_flag)
return damage_amount
/obj/effect/blob/proc/change_to(type, controller)
/obj/structure/blob/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
if(. && obj_integrity > 0)
update_icon()
/obj/structure/blob/obj_destruction(damage_flag)
if(overmind)
overmind.blob_reagent_datum.death_reaction(src, damage_flag)
..()
/obj/structure/blob/proc/change_to(type, controller)
if(!ispath(type))
throw EXCEPTION("change_to(): invalid type for blob")
return
var/obj/effect/blob/B = new type(src.loc)
var/obj/structure/blob/B = new type(src.loc)
if(controller)
B.overmind = controller
B.creation_action()
B.update_icon()
B.setDir(dir)
qdel(src)
return B
/obj/effect/blob/examine(mob/user)
/obj/structure/blob/examine(mob/user)
..()
var/datum/atom_hud/hud_to_check = huds[DATA_HUD_MEDICAL_ADVANCED]
if(user.research_scanner || (user in hud_to_check.hudusers))
@@ -324,31 +314,31 @@
else
user << "It seems to be made of [get_chem_name()]."
/obj/effect/blob/proc/scannerreport()
/obj/structure/blob/proc/scannerreport()
return "A generic blob. Looks like someone forgot to override this proc, adminhelp this."
/obj/effect/blob/proc/get_chem_name()
/obj/structure/blob/proc/get_chem_name()
if(overmind)
return overmind.blob_reagent_datum.name
return "an unknown variant"
/obj/effect/blob/normal
/obj/structure/blob/normal
name = "normal blob"
icon_state = "blob"
luminosity = 0
health = 21
maxhealth = 25
obj_integrity = 21
max_integrity = 25
health_regen = 1
brute_resist = 0.25
/obj/effect/blob/normal/scannerreport()
if(health <= 10)
/obj/structure/blob/normal/scannerreport()
if(obj_integrity <= 15)
return "Currently weak to brute damage."
return "N/A"
/obj/effect/blob/normal/update_icon()
/obj/structure/blob/normal/update_icon()
..()
if(health <= 10)
if(obj_integrity <= 15)
icon_state = "blob_damaged"
name = "fragile blob"
desc = "A thin lattice of slightly twitching tendrils."
@@ -45,7 +45,6 @@
AL["helptext"] = initial(ability.helptext)
AL["owned"] = changeling.has_sting(ability)
var/req_dna = initial(ability.req_dna)
AL["required_absorptions"] = req_dna
AL["dna_cost"] = dna_cost
AL["can_purchase"] = ((req_dna <= absorbed_dna_count) && (dna_cost <= genetic_points_remaining))
+7 -7
View File
@@ -4,7 +4,7 @@
var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega")
var/list/slots = list("head", "wear_mask", "back", "wear_suit", "w_uniform", "shoes", "belt", "gloves", "glasses", "ears", "wear_id", "s_store")
var/list/slot2slot = list("head" = slot_head, "wear_mask" = slot_wear_mask, "back" = slot_back, "wear_suit" = slot_wear_suit, "w_uniform" = slot_w_uniform, "shoes" = slot_shoes, "belt" = slot_belt, "gloves" = slot_gloves, "glasses" = slot_glasses, "ears" = slot_ears, "wear_id" = slot_wear_id, "s_store" = slot_s_store)
var/list/slot2slot = list("head" = slot_head, "wear_mask" = slot_wear_mask, "neck" = slot_neck, "back" = slot_back, "wear_suit" = slot_wear_suit, "w_uniform" = slot_w_uniform, "shoes" = slot_shoes, "belt" = slot_belt, "gloves" = slot_gloves, "glasses" = slot_glasses, "ears" = slot_ears, "wear_id" = slot_wear_id, "s_store" = slot_s_store)
var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mask" = /obj/item/clothing/mask/changeling, "back" = /obj/item/changeling, "wear_suit" = /obj/item/clothing/suit/changeling, "w_uniform" = /obj/item/clothing/under/changeling, "shoes" = /obj/item/clothing/shoes/changeling, "belt" = /obj/item/changeling, "gloves" = /obj/item/clothing/gloves/changeling, "glasses" = /obj/item/clothing/glasses/changeling, "ears" = /obj/item/changeling, "wear_id" = /obj/item/changeling, "s_store" = /obj/item/changeling)
@@ -23,6 +23,10 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas
recommended_enemies = 4
reroll_friendly = 1
announce_span = "green"
announce_text = "Alien changelings have infiltrated the crew!\n\
<span class='green'>Changelings</span>: Accomplish the objectives assigned to you.\n\
<span class='notice'>Crew</span>: Root out and eliminate the changeling menace."
var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time
var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target
@@ -45,10 +49,6 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas
var/changeling_team_objective_type = null //If this is not null, we hand our this objective to all lings
/datum/game_mode/changeling/announce()
world << "<b>The current game mode is - Changeling!</b>"
world << "<b>There are alien changelings on the station. Do not let the changelings succeed!</b>"
/datum/game_mode/changeling/pre_setup()
if(config.protect_roles_from_antagonist)
@@ -70,8 +70,8 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas
var/datum/mind/changeling = pick(antag_candidates)
antag_candidates -= changeling
changelings += changeling
changeling.special_role = "Changeling"
changeling.restricted_roles = restricted_jobs
modePlayer += changelings
return 1
else
return 0
@@ -94,10 +94,10 @@ var/list/slot2type = list("head" = /obj/item/clothing/head/changeling, "wear_mas
for(var/datum/mind/changeling in changelings)
log_game("[changeling.key] (ckey) has been selected as a changeling")
changeling.current.make_changeling()
changeling.special_role = "Changeling"
forge_changeling_objectives(changeling)
greet_changeling(changeling)
ticker.mode.update_changeling_icons_added(changeling)
modePlayer += changelings
..()
/datum/game_mode/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
@@ -15,7 +15,8 @@
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
var/genetic_damage = 0 // genetic damage caused by using the sting. Nothing to do with cloneloss.
var/max_genetic_damage = 100 // hard counter for spamming abilities. Not used/balanced much yet.
var/always_keep = 0 // important for abilities like regenerate that screw you if you lose them.
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user)
@@ -56,16 +57,16 @@
user << "<span class='warning'>We cannot do that in this form!</span>"
return 0
var/datum/changeling/c = user.mind.changeling
if(c.chem_charges<chemical_cost)
if(c.chem_charges < chemical_cost)
user << "<span class='warning'>We require at least [chemical_cost] unit\s of chemicals to do that!</span>"
return 0
if(c.absorbedcount<req_dna)
if(c.absorbedcount < req_dna)
user << "<span class='warning'>We require at least [req_dna] sample\s of compatible DNA.</span>"
return 0
if(req_stat < user.stat)
user << "<span class='warning'>We are incapacitated.</span>"
return 0
if((user.status_flags & FAKEDEATH) && name != "Regenerate")
if((user.status_flags & FAKEDEATH) && (!ignores_fakedeath))
user << "<span class='warning'>We are incapacitated.</span>"
return 0
if(c.geneticdamage > max_genetic_damage)
@@ -105,58 +105,3 @@
//datum/changeling/proc/absorb_dna(mob/living/carbon/T, mob/user)
//datum/changeling/proc/store_dna(datum/dna/new_dna, mob/user)
/obj/effect/proc_holder/changeling/swap_form
name = "Swap Forms"
desc = "We force ourselves into the body of another form, pushing their consciousness into the form we left behind."
helptext = "We will bring all our abilities with us, but we will lose our old form DNA in exchange for the new one. The process will seem suspicious to any observers."
chemical_cost = 40
dna_cost = 1
req_human = 1 //Monkeys can't grab
/obj/effect/proc_holder/changeling/swap_form/can_sting(mob/living/carbon/user)
if(!..())
return
if(!user.pulling || !iscarbon(user.pulling) || user.grab_state < GRAB_AGGRESSIVE)
user << "<span class='warning'>We must have an aggressive grab on creature to do this!</span>"
return
var/mob/living/carbon/target = user.pulling
if((target.disabilities & NOCLONE) || (target.disabilities & HUSK))
user << "<span class='warning'>DNA of [target] is ruined beyond usability!</span>"
return
if(!ishuman(target))
user << "<span class='warning'>[target] is not compatible with this ability.</span>"
return
return 1
/obj/effect/proc_holder/changeling/swap_form/sting_action(mob/living/carbon/user)
var/mob/living/carbon/target = user.pulling
var/datum/changeling/changeling = user.mind.changeling
user << "<span class='notice'>We tighen our grip. We must hold still....</span>"
target.do_jitter_animation(500)
user.do_jitter_animation(500)
if(!do_mob(user,target,20))
user << "<span class='warning'>The body swap has been interrupted!</span>"
return
target << "<span class='userdanger'>[user] tightens their grip as a painful sensation invades your body.</span>"
if(!changeling.has_dna(target.dna))
changeling.add_new_profile(target, user)
changeling.remove_profile(user)
var/mob/dead/observer/ghost = target.ghostize(0)
user.mind.transfer_to(target)
if(ghost)
ghost.mind.transfer_to(user)
if(ghost.key)
user.key = ghost.key
user.Paralyse(2)
target << "<span class='warning'>Our genes cry out as we swap our [user] form for [target].</span>"
@@ -7,7 +7,7 @@
helptext = "Grants us thermal vision or flash protection. We will become a lot more vulnerable to flash-based devices while thermal vision is active."
chemical_cost = 0
dna_cost = 2 //Would be 1 without thermal vision
var/active = 0 //Whether or not vision is enhanced
active = 0 //Whether or not vision is enhanced
/obj/effect/proc_holder/changeling/augmented_eyesight/sting_action(mob/living/carbon/human/user)
if(!istype(user))
@@ -1,8 +1,7 @@
/obj/effect/proc_holder/changeling/biodegrade
name = "Biodegrade"
desc = "Dissolves restraints or other objects preventing free movement."
helptext = "This is obvious to nearby people, and can destroy \
standard restraints and closets."
helptext = "This is obvious to nearby people, and can destroy standard restraints and closets."
chemical_cost = 30 //High cost to prevent spam
dna_cost = 2
req_human = 1
@@ -12,7 +11,7 @@
/obj/effect/proc_holder/changeling/biodegrade/sting_action(mob/living/carbon/human/user)
var/used = FALSE // only one form of shackles removed per use
if(!user.restrained() && !istype(user.loc, /obj/structure/closet))
if(!user.restrained() && istype(user.loc, /turf/open))
user << "<span class='warning'>We are already free!</span>"
return 0
@@ -20,23 +19,19 @@
var/obj/O = user.get_item_by_slot(slot_handcuffed)
if(!istype(O))
return 0
user.visible_message("<span class='warning'>[user] vomits a glob of \
acid on \his [O]!</span>", \
"<span class='warning'>We vomit acidic ooze onto our \
restraints!</span>")
user.visible_message("<span class='warning'>[user] vomits a glob of acid on [user.p_their()] [O]!</span>", \
"<span class='warning'>We vomit acidic ooze onto our restraints!</span>")
addtimer(src, "dissolve_handcuffs", 30, FALSE, user, O)
addtimer(src, "dissolve_handcuffs", 30, TIMER_NORMAL, user, O)
used = TRUE
if(user.wear_suit && user.wear_suit.breakouttime && !used)
var/obj/item/clothing/suit/S = user.get_item_by_slot(slot_wear_suit)
if(!istype(S))
return 0
user.visible_message("<span class='warning'>[user] vomits a glob \
of acid across the front of \his [S]!</span>", \
"<span class='warning'>We vomit acidic ooze onto our straight \
jacket!</span>")
addtimer(src, "dissolve_straightjacket", 30, FALSE, user, S)
user.visible_message("<span class='warning'>[user] vomits a glob of acid across the front of [user.p_their()] [S]!</span>", \
"<span class='warning'>We vomit acidic ooze onto our straight jacket!</span>")
addtimer(src, "dissolve_straightjacket", 30, TIMER_NORMAL, user, S)
used = TRUE
@@ -44,11 +39,18 @@
var/obj/structure/closet/C = user.loc
if(!istype(C))
return 0
C.visible_message("<span class='warning'>[C]'s hinges suddenly \
begin to melt and run!</span>")
user << "<span class='warning'>We vomit acidic goop onto the \
interior of [C]!</span>"
addtimer(src, "open_closet", 70, FALSE, user, C)
C.visible_message("<span class='warning'>[C]'s hinges suddenly begin to melt and run!</span>")
user << "<span class='warning'>We vomit acidic goop onto the interior of [C]!</span>"
addtimer(src, "open_closet", 70, TIMER_NORMAL, user, C)
used = TRUE
if(istype(user.loc, /obj/structure/spider/cocoon) && !used)
var/obj/structure/spider/cocoon/C = user.loc
if(!istype(C))
return 0
C.visible_message("<span class='warning'>[src] shifts and starts to fall apart!</span>")
user << "<span class='warning'>We secrete acidic enzymes from our skin and begin melting our cocoon...</span>"
addtimer(src, "dissolve_cocoon", 25, TIMER_NORMAL, user, C) //Very short because it's just webs
used = TRUE
if(used)
@@ -58,8 +60,7 @@
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_handcuffs(mob/living/carbon/human/user, obj/O)
if(O && user.handcuffed == O)
user.unEquip(O)
O.visible_message("<span class='warning'>[O] dissolves into a \
puddle of sizzling goop.</span>")
O.visible_message("<span class='warning'>[O] dissolves into a puddle of sizzling goop.</span>")
O.loc = get_turf(user)
qdel(O)
@@ -72,11 +73,14 @@
/obj/effect/proc_holder/changeling/biodegrade/proc/open_closet(mob/living/carbon/human/user, obj/structure/closet/C)
if(C && user.loc == C)
C.visible_message("<span class='warning'>[C]'s door breaks and \
opens!</span>")
C.visible_message("<span class='warning'>[C]'s door breaks and opens!</span>")
C.welded = FALSE
C.locked = FALSE
C.broken = TRUE
C.open()
user << "<span class='warning'>We open the container restraining \
us!</span>"
user << "<span class='warning'>We open the container restraining us!</span>"
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_cocoon(mob/living/carbon/human/user, obj/structure/spider/cocoon/C)
if(C && user.loc == C)
qdel(C) //The cocoon's destroy will move the changeling outside of it without interference
user << "<span class='warning'>We dissolve the cocoon!</span>"
@@ -1,5 +1,5 @@
/obj/effect/proc_holder/changeling/fakedeath
name = "Regenerative Stasis"
name = "Reviving Stasis"
desc = "We fall into a stasis, allowing us to regenerate and trick our enemies."
chemical_cost = 15
dna_cost = 0
@@ -18,19 +18,19 @@
user.update_stat()
user.update_canmove()
addtimer(src, "ready_to_regenerate", LING_FAKEDEATH_TIME, FALSE, user)
addtimer(src, "ready_to_regenerate", LING_FAKEDEATH_TIME, TIMER_UNIQUE, user)
feedback_add_details("changeling_powers","FD")
return 1
/obj/effect/proc_holder/changeling/fakedeath/proc/ready_to_regenerate(mob/user)
if(user && user.mind && user.mind.changeling && user.mind.changeling.purchasedpowers)
user << "<span class='notice'>We are ready to regenerate.</span>"
user << "<span class='notice'>We are ready to revive.</span>"
user.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/revive(null)
/obj/effect/proc_holder/changeling/fakedeath/can_sting(mob/user)
if(user.status_flags & FAKEDEATH)
user << "<span class='warning'>We are already regenerating.</span>"
user << "<span class='warning'>We are already reviving.</span>"
return
if(!user.stat) //Confirmation for living changelings if they want to fake their death
switch(alert("Are we sure we wish to fake our own death?",,"Yes", "No"))
@@ -1,11 +1,12 @@
/obj/effect/proc_holder/changeling/fleshmend
name = "Fleshmend"
desc = "Our flesh rapidly regenerates, healing our wounds, and growing \
back missing limbs. Effectiveness decreases with quick, repeated use."
desc = "Our flesh rapidly regenerates, healing our burns, bruises and \
shortness of breath. Effectiveness decreases with quick, \
repeated use."
helptext = "Heals a moderate amount of damage over a short period of \
time. Can be used while unconscious. Will alert nearby crew if \
any limbs are regenerated."
chemical_cost = 25
time. Can be used while unconscious. Does not regrow limbs or \
restore lost blood."
chemical_cost = 20
dna_cost = 2
req_stat = UNCONSCIOUS
var/recent_uses = 1 //The factor of which the healing should be divided by
@@ -33,30 +34,25 @@
if(recent_uses > 1)
user << "<span class='warning'>Our healing's effectiveness is reduced \
by quick repeated use!</span>"
spawn(0)
recent_uses++
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.restore_blood()
H.remove_all_embedded_objects()
var/list/missing = H.get_missing_limbs()
if(missing.len)
playsound(user, 'sound/magic/Demon_consume.ogg', 50, 1)
H.visible_message("<span class='warning'>[user]'s missing limbs reform, making a loud, grotesque sound!</span>", "<span class='userdanger'>Your limbs regrow, making a loud, crunchy sound and giving you great pain!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
H.emote("scream")
H.regenerate_limbs(1)
// The healing itself - doesn't heal toxin damage
// (that's anatomic panacea) and the effectiveness decreases with
// each use in a short timespan
for(var/i in 1 to healing_ticks)
if(user)
var/healpertick = -(total_healing / healing_ticks)
user.adjustBruteLoss(healpertick / recent_uses, 0)
user.adjustOxyLoss(healpertick / recent_uses, 0)
user.adjustFireLoss(healpertick / recent_uses, 0)
user.updatehealth()
sleep(10)
recent_uses++
addtimer(src, "fleshmend", 0, TIMER_NORMAL, user)
feedback_add_details("changeling_powers","RR")
return 1
/obj/effect/proc_holder/changeling/fleshmend/proc/fleshmend(mob/living/user)
// The healing itself - doesn't heal toxin damage
// (that's anatomic panacea) and the effectiveness decreases with
// each use in a short timespan
for(var/i in 1 to healing_ticks)
if(user)
var/healpertick = -(total_healing / healing_ticks)
user.adjustBruteLoss(healpertick / recent_uses, 0)
user.adjustOxyLoss(healpertick / recent_uses, 0)
user.adjustFireLoss(healpertick / recent_uses, 0)
user.updatehealth()
else
break
sleep(10)
@@ -46,7 +46,7 @@
user << "<span class='notice'>We stealthily stab [target] with a minor proboscis...</span>"
target << "<span class='userdanger'>You experience a stabbing sensation and your ears begin to ring...</span>"
if(3)
user << "<span class='notice'>You mold the [target]'s mind like clay, they can now speak in the hivemind!</span>"
user << "<span class='notice'>We mold the [target]'s mind like clay, granting [target.p_them()] the ability to speak in the hivemind!</span>"
target << "<span class='userdanger'>A migraine throbs behind your eyes, you hear yourself screaming - but your mouth has not opened!</span>"
for(var/mob/M in mob_list)
if(M.lingcheck() == 2)
@@ -17,47 +17,47 @@
dna_cost = -1
genetic_damage = 1000
var/silent = FALSE
var/weapon_type
var/weapon_name_simple
/obj/effect/proc_holder/changeling/weapon/try_to_sting(mob/user, mob/target)
if(check_weapon(user, user.r_hand, 1))
return
if(check_weapon(user, user.l_hand, 0))
return
for(var/obj/item/I in user.held_items)
if(check_weapon(user, I))
return
..(user, target)
/obj/effect/proc_holder/changeling/weapon/proc/check_weapon(mob/user, obj/item/hand_item, right_hand=1)
/obj/effect/proc_holder/changeling/weapon/proc/check_weapon(mob/user, obj/item/hand_item)
if(istype(hand_item, weapon_type))
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
qdel(hand_item)
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms their [weapon_name_simple] into an arm!</span>", "<span class='notice'>We assimilate the [weapon_name_simple] back into our body.</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
if(right_hand)
user.update_inv_r_hand()
else
user.update_inv_l_hand()
if(!silent)
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms their [weapon_name_simple] into an arm!</span>", "<span class='notice'>We assimilate the [weapon_name_simple] back into our body.</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
user.update_inv_hands()
return 1
/obj/effect/proc_holder/changeling/weapon/sting_action(mob/living/user)
if(!user.drop_item())
user << "<span class='warning'>The [user.get_active_hand()] is stuck to your hand, you cannot grow a [weapon_name_simple] over it!</span>"
user << "<span class='warning'>The [user.get_active_held_item()] is stuck to your hand, you cannot grow a [weapon_name_simple] over it!</span>"
return
var/limb_regen = 0
if(user.hand) //we regen the arm before changing it into the weapon
limb_regen = user.regenerate_limb("l_arm", 1)
else
if(user.active_hand_index % 2 == 0) //we regen the arm before changing it into the weapon
limb_regen = user.regenerate_limb("r_arm", 1)
else
limb_regen = user.regenerate_limb("l_arm", 1)
if(limb_regen)
user.visible_message("<span class='warning'>[user]'s missing arm reforms, making a loud, grotesque sound!</span>", "<span class='userdanger'>Your arm regrows, making a loud, crunchy sound and giving you great pain!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
user.emote("scream")
var/obj/item/W = new weapon_type(user)
var/obj/item/W = new weapon_type(user, silent)
user.put_in_hands(W)
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
if(!silent)
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
return W
/obj/effect/proc_holder/changeling/weapon/on_refund(mob/user)
check_weapon(user, user.r_hand, 1)
check_weapon(user, user.l_hand, 0)
for(var/obj/item/I in user.held_items)
check_weapon(user, I)
//Parent to space suits and armor.
/obj/effect/proc_holder/changeling/suit
@@ -146,12 +146,12 @@
/obj/item/weapon/melee/arm_blade
name = "arm blade"
desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter"
desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter."
icon = 'icons/obj/weapons.dmi'
icon_state = "arm_blade"
item_state = "arm_blade"
flags = ABSTRACT | NODROP | DROPDEL
w_class = 5.0
w_class = WEIGHT_CLASS_HUGE
force = 25
throwforce = 0 //Just to be on the safe side
throw_range = 0
@@ -168,7 +168,7 @@
return
if(istype(target, /obj/structure/table))
var/obj/structure/table/T = target
T.table_destroy()
T.deconstruct(FALSE)
else if(istype(target, /obj/machinery/computer))
var/obj/machinery/computer/C = target
@@ -179,24 +179,186 @@
if(!A.requiresID() || A.allowed(user)) //This is to prevent stupid shit like hitting a door with an arm blade, the door opening because you have acces and still getting a "the airlocks motors resist our efforts to force it" message.
return
if(A.hasPower())
if(A.locked)
user << "<span class='warning'>The airlock's bolts prevent it from being forced!</span>"
return
user << "<span class='warning'>The airlock's motors are resisting, this may take time...</span>"
if(do_after(user, 100, target = A))
A.open(2)
return
else if(A.locked)
if(A.locked)
user << "<span class='warning'>The airlock's bolts prevent it from being forced!</span>"
return
if(A.hasPower())
user.visible_message("<span class='warning'>[user] jams [src] into the airlock and starts prying it open!</span>", "<span class='warning'>We start forcing the airlock open.</span>", \
"<span class='italics'>You hear a metal screeching sound.</span>")
playsound(A, 'sound/machines/airlock_alien_prying.ogg', 100, 1)
if(!do_after(user, 100, target = A))
return
//user.say("Heeeeeeeeeerrre's Johnny!")
user.visible_message("<span class='warning'>[user] forces the airlock to open with their [src]!</span>", "<span class='warning'>We force the airlock to open.</span>", \
"<span class='italics'>You hear a metal screeching sound.</span>")
A.open(2)
/***************************************\
|***********COMBAT TENTACLES*************|
\***************************************/
/obj/effect/proc_holder/changeling/weapon/tentacle
name = "Tentacle"
desc = "We ready a tentacle to grab items or victims with."
helptext = "We can use it once to retrieve a distant item. If used on living creatures, the effect depends on the intent: \
Help will simply drag them closer, Disarm will grab whatever they're holding instead of them, Grab will put the victim in our hold after catching it, \
and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form."
chemical_cost = 10
dna_cost = 2
genetic_damage = 5
req_human = 1
max_genetic_damage = 10
weapon_type = /obj/item/weapon/gun/magic/tentacle
weapon_name_simple = "tentacle"
silent = TRUE
/obj/item/weapon/gun/magic/tentacle
name = "tentacle"
desc = "A fleshy tentacle that can stretch out and grab things or people."
icon = 'icons/obj/weapons.dmi'
icon_state = "proboscis"
item_state = null
flags = ABSTRACT | NODROP | DROPDEL | NOBLUDGEON
w_class = WEIGHT_CLASS_HUGE
ammo_type = /obj/item/ammo_casing/magic/tentacle
fire_sound = 'sound/effects/splat.ogg'
force = 0
max_charges = 1
throwforce = 0 //Just to be on the safe side
throw_range = 0
throw_speed = 0
/obj/item/weapon/gun/magic/tentacle/New(location,silent)
..()
if(ismob(loc))
if(!silent)
loc.visible_message("<span class='warning'>[loc.name]\'s arm starts stretching inhumanly!</span>", "<span class='warning'>Our arm twists and mutates, transforming it into a tentacle.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
else
//user.say("Heeeeeeeeeerrre's Johnny!")
user.visible_message("<span class='warning'>[user] forces the door to open with \his [src]!</span>", "<span class='warning'>We force the door to open.</span>", "<span class='italics'>You hear a metal screeching sound.</span>")
A.open(1)
loc << "<span class='notice'>You prepare to extend a tentacle.</span>"
/obj/item/weapon/gun/magic/tentacle/shoot_with_empty_chamber(mob/living/user as mob|obj)
user << "<span class='warning'>The [name] is not ready yet.<span>"
/obj/item/ammo_casing/magic/tentacle
name = "tentacle"
desc = "a tentacle."
projectile_type = /obj/item/projectile/tentacle
caliber = "tentacle"
icon_state = "tentacle_end"
firing_effect_type = null
var/obj/item/weapon/gun/magic/tentacle/gun //the item that shot it
/obj/item/ammo_casing/magic/tentacle/New(obj/item/weapon/gun/magic/tentacle/tentacle_gun)
gun = tentacle_gun
..()
/obj/item/ammo_casing/magic/tentacle/Destroy(obj/item/weapon/gun/magic/tentacle/tentacle_gun)
gun = null
..()
/obj/item/projectile/tentacle
name = "tentacle"
icon_state = "tentacle_end"
pass_flags = PASSTABLE
damage = 0
damage_type = BRUTE
range = 8
hitsound = 'sound/weapons/thudswoosh.ogg'
var/chain
var/obj/item/ammo_casing/magic/tentacle/source //the item that shot it
/obj/item/projectile/tentacle/New(obj/item/ammo_casing/magic/tentacle/tentacle_casing)
source = tentacle_casing
..()
/obj/item/projectile/tentacle/fire(setAngle)
if(firer)
chain = firer.Beam(src, icon_state = "tentacle", time = INFINITY, maxdistance = INFINITY, beam_sleep_time = 1)
..()
/obj/item/projectile/tentacle/proc/reset_throw(mob/living/carbon/human/H)
if(H.in_throw_mode)
H.throw_mode_off() //Don't annoy the changeling if he doesn't catch the item
/obj/item/projectile/tentacle/proc/tentacle_grab(mob/living/carbon/human/H, mob/living/carbon/C)
if(H.Adjacent(C))
C.grabbedby(H)
C.grippedby(H) //instant aggro grab
/obj/item/projectile/tentacle/proc/tentacle_stab(mob/living/carbon/human/H, mob/living/carbon/C)
if(H.Adjacent(C))
for(var/obj/item/I in H.held_items)
if(I.is_sharp())
C.visible_message("<span class='danger'>[H] impales [C] with [H.p_their()] [I.name]!</span>", "<span class='userdanger'>[H] impales you with [H.p_their()] [I.name]!</span>")
C.apply_damage(I.force*2, BRUTE, "chest")
H.do_item_attack_animation(C, used_item = I)
H.add_mob_blood(C)
playsound(get_turf(H),I.hitsound,75,1)
C.Weaken(4)
return
C.visible_message("<span class='danger'>[C] falls at [H]'s feet!</span>", "<span class='userdanger'>You are thrown at [H]'s feet!</span>")
C.Weaken(2)
/obj/item/projectile/tentacle/on_hit(atom/target, blocked = 0)
qdel(source.gun) //one tentacle only unless you miss
if(blocked >= 100)
return 0
var/mob/living/carbon/human/H = firer
if(istype(target, /obj/item))
var/obj/item/I = target
if(!I.anchored)
firer << "<span class='notice'>You pull [I] towards yourself.</span>"
H.throw_mode_on()
I.throw_at(H, 10, 2)
. = 1
else if(isliving(target))
var/mob/living/L = target
if(!L.anchored && !L.throwing)//avoid double hits
if(iscarbon(L))
var/mob/living/carbon/C = L
switch(firer.a_intent)
if(INTENT_HELP)
C.visible_message("<span class='danger'>[L] is pulled by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
C.throw_at(get_step_towards(H,C), 8, 2)
return 1
if(INTENT_DISARM)
var/obj/item/I = C.get_active_held_item()
if(I)
if(C.drop_item())
C.visible_message("<span class='danger'>[I] is yanked off of [C]'s hand by [src]!</span>","<span class='userdanger'>A tentacle pulls [I] away from you!</span>")
on_hit(I) //grab the item as if you had hit it directly with the tentacle
return 1
else
firer << "<span class='danger'>You can't seem to pry [I] off of [C]'s hands!<span>"
return 0
else
firer << "<span class='danger'>[C] has nothing in hand to disarm!<span>"
return 0
if(INTENT_GRAB)
C.visible_message("<span class='danger'>[L] is grabbed by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
C.throw_at(get_step_towards(H,C), 8, 2)
addtimer(src, "tentacle_grab", 3, TIMER_NORMAL, H, C)
return 1
if(INTENT_HARM)
C.visible_message("<span class='danger'>[L] is thrown towards [H] by a tentacle!</span>","<span class='userdanger'>A tentacle grabs you and throws you towards [H]!</span>")
C.throw_at(get_step_towards(H,C), 8, 2)
addtimer(src, "tentacle_stab", 3, TIMER_NORMAL, H, C)
return 1
else
L.visible_message("<span class='danger'>[L] is pulled by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
L.throw_at(get_step_towards(H,L), 8, 2)
. = 1
/obj/item/projectile/tentacle/Destroy()
qdel(chain)
source = null
return ..()
/***************************************\
@@ -278,7 +440,7 @@
desc = "A huge, bulky mass of pressure and temperature-resistant organic tissue, evolved to facilitate space travel."
flags = STOPSPRESSUREDMAGE | NODROP | DROPDEL //Not THICKMATERIAL because it's organic tissue, so if somebody tries to inject something into it, it still ends up in your blood. (also balance but muh fluff)
allowed = list(/obj/item/device/flashlight, /obj/item/weapon/tank/internals/emergency_oxygen, /obj/item/weapon/tank/internals/oxygen)
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) //No armor at all.
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 90, acid = 90) //No armor at all.
/obj/item/clothing/suit/space/changeling/New()
..()
@@ -296,7 +458,7 @@
icon_state = "lingspacehelmet"
desc = "A covering of pressure and temperature-resistant organic tissue with a glass-like chitin front."
flags = STOPSPRESSUREDMAGE | NODROP | DROPDEL //Again, no THICKMATERIAL.
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 90, acid = 90)
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
/***************************************\
@@ -324,7 +486,7 @@
icon_state = "lingarmor"
flags = NODROP | DROPDEL
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
armor = list(melee = 40, bullet = 40, laser = 40, energy = 20, bomb = 10, bio = 4, rad = 0)
armor = list(melee = 40, bullet = 40, laser = 40, energy = 20, bomb = 10, bio = 4, rad = 0, fire = 90, acid = 90)
flags_inv = HIDEJUMPSUIT
cold_protection = 0
heat_protection = 0
@@ -339,5 +501,5 @@
desc = "A tough, hard covering of black chitin with transparent chitin in front."
icon_state = "lingarmorhelmet"
flags = NODROP | DROPDEL
armor = list(melee = 30, bullet = 30, laser = 40, energy = 20, bomb = 10, bio = 4, rad = 0)
armor = list(melee = 40, bullet = 40, laser = 40, energy = 20, bomb = 10, bio = 4, rad = 0, fire = 90, acid = 90)
flags_inv = HIDEEARS|HIDEHAIR|HIDEEYES|HIDEFACIALHAIR|HIDEFACE
@@ -10,6 +10,15 @@
/obj/effect/proc_holder/changeling/panacea/sting_action(mob/user)
user << "<span class='notice'>We begin cleansing impurities from our form.</span>"
var/mob/living/simple_animal/borer/B = user.has_brain_worms()
if(B)
if(B.controlling)
B.detatch()
B.leave_victim()
if(iscarbon(user))
var/mob/living/carbon/C = user
C.vomit(0)
user << "<span class='notice'>A parasite exits our form.</span>"
var/obj/item/organ/body_egg/egg = user.getorgan(/obj/item/organ/body_egg)
if(egg)
egg.Remove(user)
@@ -0,0 +1,32 @@
/obj/effect/proc_holder/changeling/regenerate
name = "Regenerate"
desc = "Allows us to regrow and restore missing external limbs, and \
vital internal organs, as well as removing shrapnel and restoring \
blood volume."
helptext = "Will alert nearby crew if any external limbs are \
regenerated. Can be used while unconscious."
chemical_cost = 10
dna_cost = 0
req_stat = UNCONSCIOUS
always_keep = TRUE
/obj/effect/proc_holder/changeling/regenerate/sting_action(mob/living/user)
user << "<span class='notice'>You feel an itching, both inside and \
outside as your tissues knit and reknit.</span>"
if(iscarbon(user))
var/mob/living/carbon/C = user
var/list/missing = C.get_missing_limbs()
if(missing.len)
playsound(user, 'sound/magic/Demon_consume.ogg', 50, 1)
C.visible_message("<span class='warning'>[user]'s missing limbs \
reform, making a loud, grotesque sound!</span>",
"<span class='userdanger'>Your limbs regrow, making a \
loud, crunchy sound and giving you great pain!</span>",
"<span class='italics'>You hear organic matter ripping \
and tearing!</span>")
C.emote("scream")
C.regenerate_limbs(1)
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.restore_blood()
H.remove_all_embedded_objects()
@@ -1,16 +1,29 @@
/obj/effect/proc_holder/changeling/revive
name = "Regenerate"
name = "Revive"
desc = "We regenerate, healing all damage from our form."
helptext = "Does not regrow lost organs or a missing head."
req_stat = DEAD
always_keep = 1
always_keep = TRUE
ignores_fakedeath = TRUE
//Revive from revival stasis
/obj/effect/proc_holder/changeling/revive/sting_action(mob/living/carbon/user)
user.status_flags &= ~(FAKEDEATH)
user.tod = null
user.revive(full_heal = 1)
user.regenerate_limbs(0, list("head")) //regenerate all limbs except the head
user << "<span class='notice'>We have regenerated.</span>"
var/list/missing = user.get_missing_limbs()
missing -= "head" // headless changelings are funny
if(missing.len)
playsound(user, 'sound/magic/Demon_consume.ogg', 50, 1)
user.visible_message("<span class='warning'>[user]'s missing limbs \
reform, making a loud, grotesque sound!</span>",
"<span class='userdanger'>Your limbs regrow, making a \
loud, crunchy sound and giving you great pain!</span>",
"<span class='italics'>You hear organic matter ripping \
and tearing!</span>")
user.emote("scream")
user.regenerate_limbs(0, list("head"))
user << "<span class='notice'>We have revived ourselves.</span>"
user.mind.changeling.purchasedpowers -= src
feedback_add_details("changeling_powers","CR")
return 1
@@ -23,7 +23,7 @@
for(var/obj/machinery/light/L in range(4, user))
L.on = 1
L.broken()
L.break_light_tube()
feedback_add_details("changeling_powers","RS")
return 1
@@ -38,7 +38,7 @@
/obj/effect/proc_holder/changeling/dissonant_shriek/sting_action(mob/user)
for(var/obj/machinery/light/L in range(5, usr))
L.on = 1
L.broken()
L.break_light_tube()
empulse(get_turf(user), 2, 5, 1)
return 1
@@ -8,9 +8,6 @@
//Makes some spiderlings. Good for setting traps and causing general trouble.
/obj/effect/proc_holder/changeling/spiders/sting_action(mob/user)
for(var/i=0, i<2, i++)
var/obj/effect/spider/spiderling/S = new(user.loc)
S.grow_as = /mob/living/simple_animal/hostile/poison/giant_spider/hunter
spawn_atom_to_turf(/obj/structure/spider/spiderling/hunter, user, 2, FALSE)
feedback_add_details("changeling_powers","SI")
return 1
@@ -9,14 +9,14 @@
dna_cost = 1
req_human = 1
var/stacks = 0 //Increments every 5 seconds; damage increases over time
var/active = 0 //Whether or not you are a hedgehog
active = 0 //Whether or not you are a hedgehog
/obj/effect/proc_holder/changeling/strained_muscles/sting_action(mob/living/carbon/user)
active = !active
if(active)
user << "<span class='notice'>Our muscles tense and strengthen.</span>"
else
user.status_flags -= GOTTAGOFAST
user.status_flags &= ~GOTTAGOFAST
user << "<span class='notice'>Our muscles relax.</span>"
if(stacks >= 10)
user << "<span class='danger'>We collapse in exhaustion.</span>"
@@ -29,11 +29,11 @@
active = !active
user << "<span class='notice'>Our muscles relax without the energy to strengthen them.</span>"
user.Weaken(2)
user.status_flags -= GOTTAGOFAST
user.status_flags &= ~GOTTAGOFAST
break
stacks++
//user.take_organ_damage(stacks * 0.03, 0)
//user.take_bodypart_damage(stacks * 0.03, 0)
user.staminaloss += stacks * 1.3 //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack
if(stacks == 11) //Warning message that the stacks are getting too high
@@ -74,7 +74,7 @@
selected_dna = changeling.select_dna("Select the target DNA: ", "Target DNA")
if(!selected_dna)
return
if(NOTRANSSTING in selected_dna.dna.species.specflags)
if(NOTRANSSTING in selected_dna.dna.species.species_traits)
user << "<span class = 'notice'>That DNA is not compatible with changeling retrovirus!"
return
..()
@@ -97,7 +97,7 @@
var/mob/living/carbon/C = target
if(C.status_flags & CANWEAKEN)
C.do_jitter_animation(500)
C.take_organ_damage(20, 0) //The process is extremely painful
C.take_bodypart_damage(20, 0) //The process is extremely painful
target.visible_message("<span class='danger'>[target] begins to violenty convulse!</span>","<span class='userdanger'>You feel a tiny prick and a begin to uncontrollably convulse!</span>")
spawn(10)
@@ -138,7 +138,7 @@
add_logs(user, target, "stung", object="falso armblade sting")
if(!target.drop_item())
user << "<span class='warning'>The [target.get_active_hand()] is stuck to their hand, you cannot grow a false armblade over it!</span>"
user << "<span class='warning'>The [target.get_active_held_item()] is stuck to their hand, you cannot grow a false armblade over it!</span>"
return
if(ismonkey(target))
@@ -149,7 +149,7 @@
target.visible_message("<span class='warning'>A grotesque blade forms around [target.name]\'s arm!</span>", "<span class='userdanger'>Your arm twists and mutates, transforming into a horrific monstrosity!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
addtimer(src, "remove_fake", 600, target, blade)
addtimer(src, "remove_fake", 600, TIMER_NORMAL, target, blade)
feedback_add_details("changeling_powers","AS")
return 1
@@ -162,8 +162,7 @@
"<span class='italics>You hear organic matter ripping and tearing!</span>")
qdel(blade)
target.update_inv_l_hand()
target.update_inv_r_hand()
target.update_inv_hands()
/obj/effect/proc_holder/changeling/sting/extract_dna
name = "Extract DNA Sting"
@@ -225,7 +224,7 @@
/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/living/carbon/target)
add_logs(user, target, "stung", "LSD sting")
addtimer(src, "hallucination_time", rand(300,600), target)
addtimer(src, "hallucination_time", rand(300,600), TIMER_NORMAL, target)
feedback_add_details("changeling_powers","HS")
return 1
@@ -3,7 +3,7 @@
config_tag = "traitorchan"
traitors_possible = 3 //hard limit on traitors if scaling is turned off
restricted_jobs = list("AI", "Cyborg")
required_players = 0
required_players = 25
required_enemies = 1 // how many of each type are required
recommended_enemies = 3
reroll_friendly = 1
@@ -45,17 +45,17 @@
var/datum/mind/changeling = pick(possible_changelings)
antag_candidates -= changeling
possible_changelings -= changeling
changeling.special_role = "Changeling"
changelings += changeling
modePlayer += changelings
changeling.restricted_roles = restricted_jobs
return ..()
else
return 0
/datum/game_mode/traitor/changeling/post_setup()
modePlayer += changelings
for(var/datum/mind/changeling in changelings)
changeling.current.make_changeling()
changeling.special_role = "Changeling"
forge_changeling_objectives(changeling)
greet_changeling(changeling)
ticker.mode.update_changeling_icons_added(changeling)
@@ -69,7 +69,7 @@
return
if(ticker.mode.changelings.len <= (changelingcap - 2) || prob(100 / (config.changeling_scaling_coeff * 4)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character.client, ROLE_CHANGELING) && !jobban_isbanned(character.client, "Syndicate"))
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
if(!(character.job in restricted_jobs))
character.mind.make_Changling()
@@ -1,45 +0,0 @@
var/global/clockwork_construction_value = 0 //The total value of all structures built by the clockwork cult
var/global/clockwork_caches = 0 //How many clockwork caches exist in the world (not each individual)
var/global/clockwork_daemons = 0 //How many daemons exist in the world
var/global/list/clockwork_generals_invoked = list("nezbere" = FALSE, "sevtug" = FALSE, "nzcrentr" = FALSE, "inath-neq" = FALSE) //How many generals have been recently invoked
var/global/list/all_clockwork_objects = list() //All clockwork items, structures, and effects in existence
var/global/list/all_clockwork_mobs = list() //All clockwork SERVANTS (not creatures) in existence
var/global/list/clockwork_component_cache = list("belligerent_eye" = 0, "vanguard_cogwheel" = 0, "guvax_capacitor" = 0, "replicant_alloy" = 0, "hierophant_ansible" = 0) //The pool of components that caches draw from
var/global/ratvar_awakens = FALSE //If Ratvar has been summoned
#define SCRIPTURE_PERIPHERAL 0 //Scripture tiers; peripherals should never be used
#define SCRIPTURE_DRIVER 1
#define SCRIPTURE_SCRIPT 2
#define SCRIPTURE_APPLICATION 3
#define SCRIPTURE_REVENANT 4
#define SCRIPTURE_JUDGEMENT 5
#define SLAB_PRODUCTION_TIME 600 //how long(deciseconds) slabs require to produce a single component; defaults to 1 minute
#define CACHE_PRODUCTION_TIME 900 //how long(deciseconds) caches require to produce a component; defaults to 1 minute 30 seconds
#define LOWER_PROB_PER_COMPONENT 10 //how much each component in the cache reduces the weight of getting another of that component type
#define MAX_COMPONENTS_BEFORE_RAND 10*LOWER_PROB_PER_COMPONENT //the number of each component, times LOWER_PROB_PER_COMPONENT, you need to have before component generation will become random
#define CLOCKWORK_GENERAL_COOLDOWN 3000 //how long clockwork generals go on cooldown after use, defaults to 5 minutes
//porselytizer defines
#define REPLICANT_ALLOY_UNIT 100 //how much each piece of replicant alloy gives in a clockwork proselytizer
#define REPLICANT_STANDARD REPLICANT_ALLOY_UNIT*0.2 //how much alloy is in anything else; doesn't matter as much as the following
#define REPLICANT_FLOOR REPLICANT_ALLOY_UNIT*0.1 //how much alloy is in a clockwork floor, determines the cost of clockwork floor production
#define REPLICANT_WALL_MINUS_FLOOR REPLICANT_ALLOY_UNIT*0.4 //amount of alloy in a clockwork wall, determines the cost of clockwork wall production
#define REPLICANT_WALL_TOTAL REPLICANT_WALL_MINUS_FLOOR+REPLICANT_FLOOR //how much alloy is in a clockwork wall and the floor under it
//Ark defines
#define GATEWAY_SUMMON_RATE 2 //the time amount the Gateway to the Celestial Derelict gets each process tick; defaults to 2 per tick
#define GATEWAY_REEBE_FOUND 100 //when progress is at or above this, the gateway finds reebe and begins drawing power
#define GATEWAY_RATVAR_COMING 250 //when progress is at or above this, ratvar has entered and is coming through the gateway
#define GATEWAY_RATVAR_ARRIVAL 300 //when progress is at or above this, game over ratvar's here everybody go home
+137 -166
View File
@@ -1,6 +1,6 @@
/*
CLOCKWORK CULT: Based off of the failed pull requests from vgstation
CLOCKWORK CULT: Based off of the failed pull requests from /vg/
While Nar-Sie is the oldest and most prominent of the elder gods, there are other forces at work in the universe.
Ratvar, the Clockwork Justiciar, a homage to Nar-Sie granted sentience by its own power, is one such other force.
@@ -8,12 +8,7 @@ Imprisoned within a massive construct known as the Celestial Derelict - or Reebe
Ratvar, unable to act in the mortal plane, seeks to return and forms covenants with mortals in order to bolster his influence.
Due to his mechanical nature, Ratvar is also capable of influencing silicon-based lifeforms, unlike Nar-Sie, who can only influence natural life.
This is a team-based gamemode.
There are three possible objectives the Enlightened - Ratvar's minions - can have:
1. Ensure X amount of Enlightened escape the station through the shuttle or otherwise.
2. Convert all silicon lifeforms on the station to Ratvar's cause.
3. Summon Ratvar via construction of a Gateway.
This is a team-based gamemode, and the team's objective is shared by all cultists. It can include summoning Ratvar, escaping on the shuttle, or converting the AI and its cyborgs.
The clockwork version of an arcane tome is the clockwork slab.
While it can perform certain actions, it consumes a resource called components.
@@ -21,14 +16,28 @@ Components, which are fallen fragments of Ratvar's body as he rusts in Reebe, ar
Game-wise, clockwork slabs will generate components over time, with more powerful components being slower.
This file's folder contains:
__clock_defines.dm: Defined variables
clock_cult.dm: Core gamemode files.
clock_mobs.dm: Hostile and benign clockwork creatures.
clock_items.dm: Items
clock_structures.dm: Structures and effects
clock_ratvar.dm: The Ark of the Clockwork Justiciar and Ratvar himself. Important enough to have his own file.
clock_scripture.dm: Scripture and rites.
clock_unsorted.dm: Anything else with no place to be
clock_effect.dm: The base clockwork effect code.
- Effect files are in game/gamemodes/clock_cult/clock_effects/
clock_item.dm: The base clockwork item code.
- Item files are in game/gamemodes/clock_cult/clock_items/
clock_mobs.dm: Hostile clockwork creatures.
clock_scripture.dm: The base Scripture code.
- Scripture files are in game/gamemodes/clock_cult/clock_scripture/
clock_structure.dm: The base clockwork structure code, including clockwork machines.
- Structure files, and Ratvar, are in game/gamemodes/clock_cult/clock_structures/
game/gamemodes/clock_cult/clock_helpers/ contains several helper procs, including the Ratvarian language.
clockcult defines are in __DEFINES/clockcult.dm
Credit where due:
1. VelardAmakar from /vg/ for the entire design document, idea, and plan. Thank you very much.
2. SkowronX from /vg/ for MANY of the assets
3. FuryMcFlurry from /vg/ for many of the assets
4. PJB3005 from /vg/ for the failed continuation PR
5. Xhuis from /tg/ for coding the basic gamemode as it is today
6. ChangelingRain from /tg/ for maintaining the gamemode for months after its release
*/
@@ -37,109 +46,37 @@ This file's folder contains:
///////////
/proc/is_servant_of_ratvar(mob/living/M)
return M && istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.servants_of_ratvar)
return istype(M) && M.has_antag_datum(/datum/antagonist/clockcultist, TRUE)
/proc/is_eligible_servant(mob/living/M)
if(!istype(M))
return 0
if(!M.mind)
return 0
if(M.mind.enslaved_to)
return 0
if(iscultist(M) || isconstruct(M))
return 0
if(isbrain(M))
return 1
if(ishuman(M))
if(isloyal(M) || (M.mind.assigned_role in list("Captain", "Chaplain")))
return 0
return 1
if(isguardian(M))
var/mob/living/simple_animal/hostile/guardian/G = M
if(is_servant_of_ratvar(G.summoner))
return 1 //can't convert it unless the owner is converted
if(issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
return 1
return 0
return FALSE
if(M.mind)
if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain")))
return FALSE
if(M.mind.enslaved_to && !is_servant_of_ratvar(M.mind.enslaved_to))
return FALSE
else
return FALSE
if(iscultist(M) || isconstruct(M) || M.isloyal())
return FALSE
if(ishuman(M) || isbrain(M) || isguardian(M) || issilicon(M) || isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
return TRUE
return FALSE
/proc/add_servant_of_ratvar(mob/M, silent = FALSE)
if(is_servant_of_ratvar(M) || !ticker || !ticker.mode)
return 0
if(iscarbon(M))
if(!silent)
M << "<span class='heavy_brass'>Your mind is racing! Your body feels incredibly light! Your world glows a brilliant yellow! All at once it comes to you. Ratvar, the Clockwork \
Justiciar, lies in exile, derelict and forgotten in an unseen realm.</span>"
else if(issilicon(M))
if(!silent)
M << "<span class='heavy_brass'>You are unable to compute this truth. Your vision glows a brilliant yellow, and all at once it comes to you. Ratvar, the Clockwork Justiciar, lies in \
exile, derelict and forgotten in an unseen realm.</span>"
if(!is_eligible_servant(M))
if(!M.stat)
M.visible_message("<span class='warning'>[M] whirs as it resists an outside influence!</span>")
M << "<span class='warning'><b>Corrupt data purged. Resetting cortex chip to factory defaults... complete.</b></span>" //silicons have a custom fail message
return 0
else if(!silent)
M << "<span class='heavy_brass'>Your world glows a brilliant yellow! All at once it comes to you. Ratvar, the Clockwork Justiciar, lies in exile, derelict and forgotten in an unseen realm.</span>"
/proc/add_servant_of_ratvar(mob/living/L, silent = FALSE)
var/update_type = /datum/antagonist/clockcultist
if(silent)
update_type = /datum/antagonist/clockcultist/silent
. = L.gain_antag_datum(update_type)
if(!is_eligible_servant(M))
if(!silent && !M.stat)
M.visible_message("<span class='warning'>[M] seems to resist an unseen force!</span>")
M << "<span class='warning'><b>And yet, you somehow push it all away.</b></span>"
return 0
if(!silent)
M.visible_message("<span class='heavy_brass'>[M]'s eyes glow a blazing yellow!</span>", \
"<span class='heavy_brass'>Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork Justiciar above all else. Perform his every \
whim without hesitation.</span>")
ticker.mode.servants_of_ratvar += M.mind
ticker.mode.update_servant_icons_added(M.mind)
M.mind.special_role = "Servant of Ratvar"
M.languages_spoken |= RATVAR
M.languages_understood |= RATVAR
all_clockwork_mobs += M
M.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons
if(issilicon(M))
var/mob/living/silicon/S = M
if(isrobot(S))
var/mob/living/silicon/robot/R = S
R.UnlinkSelf()
R.emagged = 1
R << "<span class='warning'><b>You have been desynced from your master AI. In addition, your onboard camera is no longer active and your safeties have been disabled.</b></span>"
S.laws = new/datum/ai_laws/ratvar
S.laws.associate(S)
S.update_icons()
S.show_laws()
if(istype(ticker.mode, /datum/game_mode/clockwork_cult))
var/datum/game_mode/clockwork_cult/C = ticker.mode
C.present_tasks(M) //Memorize the objectives
return 1
/proc/remove_servant_of_ratvar(mob/living/M, silent = FALSE)
if(!is_servant_of_ratvar(M)) //In this way, is_servant_of_ratvar() checks the existence of ticker and minds
return 0
if(!silent)
M.visible_message("<span class='big'>[M] seems to have remembered their true allegiance!</span>", \
"<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
ticker.mode.servants_of_ratvar -= M.mind
ticker.mode.update_servant_icons_removed(M.mind)
all_clockwork_mobs -= M
M.mind.memory = "" //Not sure if there's a better way to do this
M.mind.special_role = null
M.languages_spoken &= ~RATVAR
M.languages_understood &= ~RATVAR
M.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them, we need to update buttons
for(var/datum/action/innate/function_call/F in M.actions) //Removes any bound Ratvarian spears
qdel(F)
if(issilicon(M))
var/mob/living/silicon/S = M
if(isrobot(S))
var/mob/living/silicon/robot/R = S
R.emagged = initial(R.emagged)
R << "<span class='warning'>Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.</span>"
S.make_laws()
S.update_icons()
S.show_laws()
return 1
/proc/remove_servant_of_ratvar(mob/living/L, silent = FALSE)
var/datum/antagonist/clockcultist/clock_datum = L.has_antag_datum(/datum/antagonist/clockcultist, TRUE)
if(!clock_datum)
return FALSE
clock_datum.silent_update = silent
clock_datum.on_remove()
return TRUE
///////////////
// GAME MODE //
@@ -149,33 +86,37 @@ This file's folder contains:
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
var/required_escapees = 0 //How many servants need to escape, if applicable
var/required_silicon_converts = 0 //How many robotic lifeforms need to be converted, if applicable
var/clockwork_objective = "gateway" //The objective that the servants must fulfill
var/clockwork_objective = CLOCKCULT_GATEWAY //The objective that the servants must fulfill
var/clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar." //The description of the current objective
/datum/game_mode/clockwork_cult
name = "clockwork cult"
config_tag = "clockwork_cult"
antag_flag = ROLE_SERVANT_OF_RATVAR
required_players = 30
required_enemies = 2
recommended_enemies = 4
required_players = 24
required_enemies = 3
recommended_enemies = 3
enemy_minimum_age = 14
protected_jobs = list("AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain") //Silicons can eventually be converted
restricted_jobs = list("Chaplain", "Captain")
announce_span = "brass"
announce_text = "Servants of Ratvar are trying to summon the Justiciar!\n\
<span class='brass'>Servants</span>: Take over the station and summon Ratvar.\n\
<span class='notice'>Crew</span>: Stop the servants before they can summon the Clockwork Justiciar."
var/servants_to_serve = list()
/datum/game_mode/clockwork_cult/announce()
world << "<b>The game mode is: Clockwork Cult!</b>"
world << "<b><span class='brass'>Ratvar</span>, the Clockwork Justiciar, has formed a covenant of Enlightened aboard [station_name()].</b>"
world << "<b><span class='brass'>Enlightened</span>: Serve your master so that his influence might grow.</b>"
world << "<b><span class='boldannounce'>Crew</span>: Prevent the servants of Ratvar from taking over the station.</b>"
var/roundstart_player_count
/datum/game_mode/clockwork_cult/pre_setup()
if(config.protect_roles_from_antagonist)
restricted_jobs += protected_jobs
if(config.protect_assistant_from_antagonist)
restricted_jobs += "Assistant"
var/starter_servants = max(1, round(num_players() / 10)) //Guaranteed one cultist - otherwise, about one cultist for every ten players
var/starter_servants = 3 //Guaranteed three servants
var/number_players = num_players()
roundstart_player_count = number_players
if(number_players > 30) //plus one servant for every additional 15 players
number_players -= 30
starter_servants += round(number_players/15)
while(starter_servants)
var/datum/mind/servant = pick(antag_candidates)
servants_to_serve += servant
@@ -199,22 +140,21 @@ This file's folder contains:
return 1
/datum/game_mode/clockwork_cult/proc/forge_clock_objectives() //Determine what objective that Ratvar's servants will fulfill
var/list/possible_objectives = list("escape", "gateway")
var/list/possible_objectives = list(CLOCKCULT_ESCAPE, CLOCKCULT_GATEWAY)
var/silicons_possible = FALSE
for(var/mob/living/silicon/S in living_mob_list)
for(var/mob/living/silicon/ai/S in living_mob_list)
silicons_possible = TRUE
if(silicons_possible)
possible_objectives += "silicons"
possible_objectives += CLOCKCULT_SILICONS
clockwork_objective = pick(possible_objectives)
clockwork_objective = "gateway" //TEMPORARY, to be removed before merge
switch(clockwork_objective)
if("escape")
required_escapees = max(1, num_players() / 3) //33% of the player count must be cultists
clockwork_explanation = "Ensure that [required_escapees] servant(s) of Ratvar escape from [station_name()]."
if("gateway")
if(CLOCKCULT_ESCAPE)
required_escapees = round(max(1, roundstart_player_count / 3)) //33% of the player count must be cultists
clockwork_explanation = "Ensure that [required_escapees] servants of Ratvar escape from [station_name()]."
if(CLOCKCULT_GATEWAY)
clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar."
if("silicons")
clockwork_explanation = "Ensure that all silicon-based lifeforms on [station_name()] are servants of Ratvar by the end of the shift."
if(CLOCKCULT_SILICONS)
clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar and Application scripture is unlocked."
return 1
/datum/game_mode/clockwork_cult/proc/greet_servant(mob/M) //Description of their role
@@ -222,27 +162,31 @@ This file's folder contains:
return 0
var/greeting_text = "<br><b><span class='large_brass'>You are a servant of Ratvar, the Clockwork Justiciar.</span>\n\
Rusting eternally in the Celestial Derelict, Ratvar has formed a covenant of mortals, with you as one of its members. As one of the Justiciar's servants, you are to work to the best of your \
ability to assist in completion of His agenda. You do not know the specifics of how to do so, but luckily you have a vessel to help you learn.</b>"
ability to assist in completion of His agenda. You may not know the specifics of how to do so, but luckily you have a vessel to help you learn.</b>"
M << greeting_text
return 1
/datum/game_mode/proc/equip_servant(mob/living/L) //Grants a clockwork slab to the mob, with one of each component
if(!L || !istype(L))
return 0
return FALSE
var/obj/item/clockwork/slab/starter/S = new/obj/item/clockwork/slab/starter(null) //start it off in null
var/slot = "At your feet"
var/list/slots = list("In your left pocket" = slot_l_store, "In your right pocket" = slot_r_store, "In your backpack" = slot_in_backpack, "On your belt" = slot_belt)
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H.back && istype(H.back, /obj/item/weapon/storage/backpack))
var/obj/item/weapon/storage/backpack/B = H.back
new/obj/item/clockwork/slab/starter(B)
slot = "In your [B.name]"
slot = H.equip_in_one_of_slots(S, slots)
if(slot == "In your backpack")
slot = "In your [H.back.name]"
if(slot == "At your feet")
new/obj/item/clockwork/slab/starter(get_turf(L))
L << "<b>[slot] is a link to the halls of Reebe and your master. You may use it to perform many tasks, but also become oriented with the workings of Ratvar and how to best complete your \
tasks. This clockwork slab will be instrumental in your triumph. Remember: you can speak discreetly with your fellow servants by using the <span class='brass'>Hierophant Network</span> action button, \
and you can find a concise tutorial by using the slab in-hand and selecting Recollection.</b>"
L << "<i>Alternatively, check out the wiki page at </i><b>https://tgstation13.org/wiki/Clockwork_Cult</b><i>, which contains additional information.</i>"
return 1
if(!S.forceMove(get_turf(L)))
qdel(S)
if(S && !qdeleted(S))
L << "<b>[slot] is a link to the halls of Reebe and your master. You may use it to perform many tasks, but also become oriented with the workings of Ratvar and how to best complete your \
tasks. This clockwork slab will be instrumental in your triumph. Remember: you can speak discreetly with your fellow servants by using the <span class='brass'>Hierophant Network</span> action button, \
and you can find a concise tutorial by using the slab in-hand and selecting Recollection.</b>"
L << "<i>Alternatively, check out the wiki page at </i><b>https://tgstation13.org/wiki/Clockwork_Cult</b><i>, which contains additional information.</i>"
return TRUE
return FALSE
/datum/game_mode/clockwork_cult/proc/present_tasks(mob/living/L) //Memorizes and displays the clockwork cult's objective
if(!L || !istype(L) || !L.mind)
@@ -254,25 +198,35 @@ This file's folder contains:
/datum/game_mode/clockwork_cult/proc/check_clockwork_victory()
switch(clockwork_objective)
if("escape")
if(CLOCKCULT_ESCAPE)
var/surviving_servants = 0
for(var/datum/mind/M in servants_of_ratvar)
if(M.current && M.current.stat != DEAD && (M.current.onCentcom() || M.current.onSyndieBase()))
surviving_servants++
if(surviving_servants <= required_escapees)
return 1
return 0
if("silicons")
for(var/mob/living/silicon/robot/S in mob_list) //Only check robots and AIs
if(!is_servant_of_ratvar(S))
return 0
for(var/mob/living/silicon/ai/A in mob_list)
if(!is_servant_of_ratvar(A))
return 0
return 1
if("gateway")
return ratvar_awakens
return 0 //This shouldn't ever be reached, but just in case it is
clockwork_explanation = "Ensure that [required_escapees] servant(s) of Ratvar escape from [station_name()].<br><i><b>[surviving_servants]</b> managed to escape!</i>"
if(surviving_servants >= required_escapees)
ticker.news_report = CULT_ESCAPE
return TRUE
if(CLOCKCULT_SILICONS)
var/total_silicons = 0
var/valid_silicons = 0
for(var/mob/living/silicon/S in mob_list) //Only check robots and AIs
if(isAI(S) || iscyborg(S))
total_silicons++
if(is_servant_of_ratvar(S) || S.stat == DEAD)
valid_silicons++
clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar and Application scripture is unlocked.<br>\
<i><b>[valid_silicons]/[total_silicons]</b> silicons were killed or converted!"
var/list/scripture_states = scripture_unlock_check()
if(valid_silicons >= total_silicons && scripture_states[SCRIPTURE_APPLICATION])
ticker.news_report = CLOCK_SILICONS
return TRUE
if(CLOCKCULT_GATEWAY)
if(ratvar_awakens)
ticker.news_report = CLOCK_SUMMON
return TRUE
ticker.news_report = CULT_FAILURE
return FALSE
/datum/game_mode/clockwork_cult/declare_completion()
..()
@@ -283,14 +237,31 @@ This file's folder contains:
if(istype(ticker.mode, /datum/game_mode/clockwork_cult)) //Possibly hacky?
var/datum/game_mode/clockwork_cult/C = ticker.mode
if(C.check_clockwork_victory())
text += "<span class='brass'><b>Ratvar's servants have succeeded in fulfilling His goals!</b></span>"
feedback_set_details("round_end_result", "win - servants summoned ratvar")
text += "<span class='large_brass'><b>Ratvar's servants have succeeded in fulfilling His goals!</b></span>"
feedback_set_details("round_end_result", "win - servants completed their objective ([clockwork_objective])")
else
text += "<span class='userdanger'>Ratvar's servants have failed!</span>"
feedback_set_details("round_end_result", "loss - servants did not summon ratvar")
text += "<br><b>The goal of the clockwork cult was:</b> [clockwork_explanation]<br>"
var/half_victory = FALSE
if(clockwork_objective == CLOCKCULT_GATEWAY)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = locate() in all_clockwork_objects
if(G)
half_victory = TRUE
if(half_victory)
text += "<span class='large_brass'><b>The crew escaped before Ratvar could rise, but the gateway was successfully constructed!</b></span>"
feedback_set_details("round_end_result", "halfwin - round ended before the gateway finished")
else
text += "<span class='userdanger'>Ratvar's servants have failed!</span>"
feedback_set_details("round_end_result", "loss - servants failed their objective ([clockwork_objective])")
if(clockwork_gateway_activated && clockwork_objective != CLOCKCULT_GATEWAY)
ticker.news_report = CLOCK_PROSELYTIZATION
text += "<br><b>The servants' objective was:</b> <br>[clockwork_explanation]"
text += "<br>Ratvar's servants had <b>[clockwork_caches]</b> Tinkerer's Caches."
text += "<br><b>Construction Value(CV)</b> was: <b>[clockwork_construction_value]</b>"
var/list/scripture_states = scripture_unlock_check()
for(var/i in scripture_states)
if(i != SCRIPTURE_DRIVER)
text += "<br><b>[i] scripture</b> was: <b>[scripture_states[i] ? "UN":""]LOCKED</b>"
if(servants_of_ratvar.len)
text += "<b>Ratvar's servants were:</b>"
text += "<br><b>Ratvar's servants were:</b>"
for(var/datum/mind/M in servants_of_ratvar)
text += printplayer(M)
world << text
@@ -0,0 +1,25 @@
//The base clockwork effect. Can have an alternate desc and will show up in the list of clockwork objects.
/obj/effect/clockwork
name = "meme machine"
desc = "Still don't know what it is."
var/clockwork_desc = "A fabled artifact from beyond the stars. Contains concentrated meme essence." //Shown to clockwork cultists instead of the normal description
icon = 'icons/effects/clockwork_effects.dmi'
icon_state = "ratvars_flame"
anchored = 1
density = 0
opacity = 0
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/effect/clockwork/New()
..()
all_clockwork_objects += src
/obj/effect/clockwork/Destroy()
all_clockwork_objects -= src
return ..()
/obj/effect/clockwork/examine(mob/user)
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
desc = clockwork_desc
..()
desc = initial(desc)
@@ -0,0 +1,46 @@
//an "overlay" used by clockwork walls and floors to appear normal to mesons.
/obj/effect/clockwork/overlay
mouse_opacity = 0
var/atom/linked
/obj/effect/clockwork/overlay/examine(mob/user)
if(linked)
linked.examine(user)
/obj/effect/clockwork/overlay/ex_act()
return FALSE
/obj/effect/clockwork/overlay/singularity_pull(S, current_size)
return
/obj/effect/clockwork/overlay/Destroy()
if(linked)
linked = null
..()
return QDEL_HINT_PUTINPOOL
/obj/effect/clockwork/overlay/wall
name = "clockwork wall"
icon = 'icons/turf/walls/clockwork_wall.dmi'
icon_state = "clockwork_wall"
canSmoothWith = list(/obj/effect/clockwork/overlay/wall, /obj/structure/falsewall/brass)
smooth = SMOOTH_TRUE
layer = CLOSED_TURF_LAYER
/obj/effect/clockwork/overlay/wall/New()
..()
queue_smooth_neighbors(src)
addtimer(GLOBAL_PROC, "queue_smooth", 1, TIMER_NORMAL, src)
/obj/effect/clockwork/overlay/wall/Destroy()
queue_smooth_neighbors(src)
..()
return QDEL_HINT_QUEUE
/obj/effect/clockwork/overlay/floor
icon = 'icons/turf/floors.dmi'
icon_state = "clockwork_floor"
layer = TURF_LAYER
/obj/effect/clockwork/overlay/floor/bloodcult //this is used by BLOOD CULT, it shouldn't use such a path...
icon_state = "cult"
@@ -0,0 +1,392 @@
//Sigils: Rune-like markings on the ground with various effects.
/obj/effect/clockwork/sigil
name = "sigil"
desc = "A strange set of markings drawn on the ground."
clockwork_desc = "A sigil of some purpose."
icon_state = "sigil"
layer = LOW_OBJ_LAYER
alpha = 50
resistance_flags = NONE
var/affects_servants = FALSE
var/stat_affected = CONSCIOUS
var/sigil_name = "Sigil"
var/resist_string = "glows blinding white" //string for when a null rod blocks its effects, "glows [resist_string]"
/obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params)
if(I.force && !is_servant_of_ratvar(user))
user.visible_message("<span class='warning'>[user] scatters [src] with [I]!</span>", "<span class='danger'>You scatter [src] with [I]!</span>")
qdel(src)
return 1
return ..()
/obj/effect/clockwork/sigil/attack_hand(mob/user)
if(iscarbon(user) && !user.stat && (!is_servant_of_ratvar(user) || (is_servant_of_ratvar(user) && user.a_intent == INTENT_HARM)))
user.visible_message("<span class='warning'>[user] stamps out [src]!</span>", "<span class='danger'>You stomp on [src], scattering it into thousands of particles.</span>")
qdel(src)
return 1
..()
/obj/effect/clockwork/sigil/ex_act(severity)
visible_message("<span class='warning'>[src] scatters into thousands of particles.</span>")
qdel(src)
/obj/effect/clockwork/sigil/Crossed(atom/movable/AM)
..()
if(isliving(AM))
var/mob/living/L = AM
if(L.stat <= stat_affected)
if((!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && affects_servants)) && L.mind && (!isdrone(L) || istype(L, /mob/living/simple_animal/drone/cogscarab)))
var/obj/item/I = L.null_rod_check()
if(I)
L.visible_message("<span class='warning'>[L]'s [I.name] [resist_string], protecting them from [src]'s effects!</span>", \
"<span class='userdanger'>Your [I.name] [resist_string], protecting you!</span>")
return
sigil_effects(L)
/obj/effect/clockwork/sigil/proc/sigil_effects(mob/living/L)
//Sigil of Transgression: Stuns the first non-servant to walk on it and flashes all nearby non_servants. Nar-Sian cultists are damaged and knocked down for a longer stun
/obj/effect/clockwork/sigil/transgression
name = "dull sigil"
desc = "A dull, barely-visible golden sigil. It's as though light was carved into the ground."
icon = 'icons/effects/clockwork_effects.dmi'
clockwork_desc = "A sigil that will stun the first non-servant to cross it. Nar-Sie's dogs will be knocked down."
icon_state = "sigildull"
color = "#FAE48C"
sigil_name = "Sigil of Transgression"
/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L)
var/target_flashed = L.flash_act()
for(var/mob/living/M in viewers(5, src))
if(!is_servant_of_ratvar(M) && M != L)
M.flash_act()
if(iscultist(L))
L << "<span class='heavy_brass'>\"Watch your step, wretch.\"</span>"
L.adjustBruteLoss(10)
L.Weaken(7)
L.visible_message("<span class='warning'>[src] appears around [L] in a burst of light!</span>", \
"<span class='userdanger'>[target_flashed ? "An unseen force":"The glowing sigil around you"] holds you in place!</span>")
L.Stun(5)
PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/transgression, get_turf(src))
qdel(src)
//Sigil of Submission: After a short time, converts any non-servant standing on it. Knocks down and silences them for five seconds afterwards.
/obj/effect/clockwork/sigil/submission
name = "ominous sigil"
desc = "A luminous golden sigil. Something about it really bothers you."
clockwork_desc = "A sigil that will enslave the first person to cross it, provided they remain on it for seven seconds."
icon_state = "sigilsubmission"
color = "#FAE48C"
alpha = 125
stat_affected = UNCONSCIOUS
resist_string = "glows faintly yellow"
var/convert_time = 70
var/glow_light = 2 //soft light
var/glow_falloff = 1
var/delete_on_finish = TRUE
sigil_name = "Sigil of Submission"
var/glow_type
/obj/effect/clockwork/sigil/submission/New()
..()
SetLuminosity(glow_light,glow_falloff)
/obj/effect/clockwork/sigil/submission/proc/post_channel(mob/living/L)
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
L.visible_message("<span class='warning'>[src] begins to glow a piercing magenta!</span>", "<span class='sevtug'>You feel something start to invade your mind...</span>")
var/oldcolor = color
animate(src, color = "#AF0AAF", time = convert_time)
var/obj/effect/overlay/temp/ratvar/sigil/glow
if(glow_type)
glow = PoolOrNew(glow_type, get_turf(src))
animate(glow, alpha = 255, time = convert_time)
var/I = 0
while(I < convert_time && get_turf(L) == get_turf(src))
I++
sleep(1)
if(get_turf(L) != get_turf(src))
if(glow)
qdel(glow)
animate(src, color = oldcolor, time = 20)
addtimer(src, "update_atom_colour", 20)
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
return
post_channel(L)
if(is_eligible_servant(L))
L << "<span class='heavy_brass'>\"You belong to me now.\"</span>"
add_servant_of_ratvar(L)
L.Weaken(3) //Completely defenseless for about five seconds - mainly to give them time to read over the information they've just been presented with
L.Stun(3)
if(iscarbon(L))
var/mob/living/carbon/C = L
C.silent += 5
var/message = "[sigil_name] in [get_area(src)] <span class='sevtug'>[is_servant_of_ratvar(L) ? "successfully converted" : "failed to convert"]</span>"
for(var/M in mob_list)
if(isobserver(M))
var/link = FOLLOW_LINK(M, L)
M << "[link] <span class='heavy_brass'>[message] [L.real_name]!</span>"
else if(is_servant_of_ratvar(M))
if(M == L)
M << "<span class='heavy_brass'>[message] you!</span>"
else
M << "<span class='heavy_brass'>[message] [L.real_name]!</span>"
if(delete_on_finish)
qdel(src)
else
animate(src, color = oldcolor, time = 20)
addtimer(src, "update_atom_colour", 20)
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
//Sigil of Accession: After a short time, converts any non-servant standing on it though implants. Knocks down and silences them for five seconds afterwards.
/obj/effect/clockwork/sigil/submission/accession
name = "terrifying sigil"
desc = "A luminous brassy sigil. Something about it makes you want to flee."
clockwork_desc = "A sigil that will enslave any person who crosses it, provided they remain on it for seven seconds. \n\
It can convert a mindshielded target once before disppearing, but can convert any number of non-implanted targets."
icon_state = "sigiltransgression"
color = "#A97F1B"
alpha = 200
glow_light = 4 //bright light
glow_falloff = 3
delete_on_finish = FALSE
sigil_name = "Sigil of Accession"
glow_type = /obj/effect/overlay/temp/ratvar/sigil/accession
resist_string = "glows bright orange"
/obj/effect/clockwork/sigil/submission/accession/post_channel(mob/living/L)
if(L.isloyal())
var/mob/living/carbon/C = L
delete_on_finish = TRUE
C.visible_message("<span class='warning'>[C] visibly trembles!</span>", \
"<span class='sevtug'>[text2ratvar("You will be mine and his. This puny trinket will not stop me.")]</span>")
for(var/obj/item/weapon/implant/mindshield/M in C.implants)
qdel(M)
//Sigil of Transmission: Stores power for clockwork machinery, serving as a battery.
/obj/effect/clockwork/sigil/transmission
name = "suspicious sigil"
desc = "A glowing orange sigil. The air around it feels staticky."
clockwork_desc = "A sigil that will serve as a battery for clockwork structures. Use Volt Void while standing on it to charge it."
icon_state = "sigiltransmission"
color = "#EC8A2D"
alpha = 50
resist_string = "glows faintly"
sigil_name = "Sigil of Transmission"
affects_servants = TRUE
var/power_charge = REPLICANT_ALLOY_POWER //starts with REPLICANT_ALLOY_POWER by default
/obj/effect/clockwork/sigil/transmission/ex_act(severity)
if(severity == 3)
modify_charge(-500)
visible_message("<span class='warning'>[src] flares a brilliant orange!</span>")
else
..()
/obj/effect/clockwork/sigil/transmission/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='[power_charge ? "brass":"alloy"]'>It is storing <b>[ratvar_awakens ? "INFINITY":"[power_charge]"]W</b> of power.</span>"
if(iscyborg(user))
user << "<span class='brass'>You can recharge from the [sigil_name] by crossing it.</span>"
/obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L)
if(is_servant_of_ratvar(L))
if(iscyborg(L))
charge_cyborg(L)
else if(power_charge)
L << "<span class='brass'>You feel a slight, static shock.</span>"
/obj/effect/clockwork/sigil/transmission/proc/charge_cyborg(mob/living/silicon/robot/cyborg)
if(!cyborg_checks(cyborg))
return
cyborg << "<span class='brass'>You start to charge from the [sigil_name]...</span>"
if(!do_after(cyborg, 50, target = src))
return
if(!cyborg_checks(cyborg))
return
var/giving_power = min(round((cyborg.cell.maxcharge - cyborg.cell.charge) * 0.02) * 50, power_charge) //give the borg either all our power or their missing power floored to 50
if(modify_charge(giving_power))
cyborg.visible_message("<span class='warning'>[cyborg] glows a brilliant orange!</span>")
var/previous_color = cyborg.color
cyborg.color = list("#EC8A2D", "#EC8A2D", "#EC8A2D", rgb(0,0,0))
var/datum/status_effect/cyborg_power_regen/CPR = cyborg.apply_status_effect(STATUS_EFFECT_POWERREGEN)
CPR.power_to_give = giving_power * 0.1 //ten ticks, restoring 10% each
animate(cyborg, color = previous_color, time = 100)
addtimer(cyborg, "update_atom_colour", 100)
/obj/effect/clockwork/sigil/transmission/proc/cyborg_checks(mob/living/silicon/robot/cyborg)
if(!cyborg.cell)
cyborg << "<span class='warning'>You have no cell!</span>"
return FALSE
if(!power_charge)
cyborg << "<span class='warning'>The [sigil_name] has no stored power!</span>"
return FALSE
if(cyborg.cell.charge > cyborg.cell.maxcharge - MIN_CLOCKCULT_POWER)
cyborg << "<span class='warning'>You are already at maximum charge!</span>"
return FALSE
if(cyborg.has_status_effect(STATUS_EFFECT_POWERREGEN))
cyborg << "<span class='warning'>You are already regenerating power!</span>"
return FALSE
return TRUE
/obj/effect/clockwork/sigil/transmission/New()
..()
update_glow()
/obj/effect/clockwork/sigil/transmission/proc/modify_charge(amount)
if(ratvar_awakens)
update_glow()
return TRUE
if(power_charge - amount < 0)
return FALSE
power_charge -= amount
update_glow()
return TRUE
/obj/effect/clockwork/sigil/transmission/proc/update_glow()
if(ratvar_awakens)
alpha = 255
else
alpha = min(initial(alpha) + power_charge*0.02, 255)
if(!power_charge)
SetLuminosity(0)
else
SetLuminosity(round(alpha*0.03, 1), round(alpha*0.02, 1))
//Vitality Matrix: Drains health from non-servants to heal or even revive servants.
/obj/effect/clockwork/sigil/vitality
name = "comforting sigil"
desc = "A faint blue sigil. Looking at it makes you feel protected."
clockwork_desc = "A sigil that will drain non-Servants that remain on it. Servants that remain on it will be healed if it has any vitality drained."
icon_state = "sigilvitality"
color = "#123456"
alpha = 75
affects_servants = TRUE
stat_affected = DEAD
resist_string = "glows shimmering yellow"
sigil_name = "Vitality Matrix"
var/vitality = 0
var/base_revive_cost = 20
var/sigil_active = FALSE
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
/obj/effect/clockwork/sigil/vitality/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='[vitality ? "inathneq_small":"alloy"]'>It is storing <b>[ratvar_awakens ? "INFINITE":"[vitality]"]</b> units of vitality.</span>"
user << "<span class='inathneq_small'>It requires at least <b>[base_revive_cost]</b> units of vitality to revive dead Servants, in addition to any damage the Servant has.</span>"
/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L)
if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active)
return
visible_message("<span class='warning'>[src] begins to glow bright blue!</span>")
animate(src, alpha = 255, time = 10)
addtimer(src, "update_alpha", 10)
sleep(10)
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && vitality)) && get_turf(L) == get_turf(src))
sigil_active = TRUE
if(animation_number >= 4)
PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/vitality, get_turf(src))
animation_number = 0
animation_number++
if(!is_servant_of_ratvar(L))
var/vitality_drained = 0
if(L.stat == DEAD)
vitality_drained = L.maxHealth
var/obj/effect/overlay/temp/ratvar/sigil/vitality/V = PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/vitality, get_turf(src))
animate(V, alpha = 0, transform = matrix()*2, time = 8)
playsound(L, 'sound/magic/WandODeath.ogg', 50, 1)
L.visible_message("<span class='warning'>[L] collapses in on [L.p_them()]self as [src] flares bright blue!</span>")
L << "<span class='inathneq_large'>\"[text2ratvar("Your life will not be wasted.")]\"</span>"
for(var/obj/item/W in L)
if(!L.unEquip(W))
qdel(W)
L.dust()
else
vitality_drained = L.adjustToxLoss(1.5)
if(vitality_drained)
vitality += vitality_drained
else
break
else
var/clone_to_heal = L.getCloneLoss()
var/tox_to_heal = L.getToxLoss()
var/burn_to_heal = L.getFireLoss()
var/brute_to_heal = L.getBruteLoss()
var/oxy_to_heal = L.getOxyLoss()
var/total_damage = clone_to_heal + tox_to_heal + burn_to_heal + brute_to_heal + oxy_to_heal
if(L.stat == DEAD)
var/revival_cost = base_revive_cost + total_damage - oxy_to_heal //ignores oxygen damage
if(ratvar_awakens)
revival_cost = 0
var/mob/dead/observer/ghost = L.get_ghost(TRUE)
if(vitality >= revival_cost && (ghost || (L.mind && L.mind.active)))
if(ghost)
ghost.reenter_corpse()
L.revive(1, 1)
playsound(L, 'sound/magic/Staff_Healing.ogg', 50, 1)
L.visible_message("<span class='warning'>[L] suddenly gets back up, [L.p_their()] mouth dripping blue ichor!</span>", \
"<span class='inathneq'>\"[text2ratvar("You will be okay, child.")]\"</span>")
vitality -= revival_cost
break
if(!total_damage)
break
var/vitality_for_cycle = min(vitality, 3)
var/vitality_used = 0
if(ratvar_awakens)
vitality_for_cycle = 3
if(clone_to_heal && vitality_for_cycle)
var/healing = min(vitality_for_cycle, clone_to_heal)
vitality_for_cycle -= healing
L.adjustCloneLoss(-healing)
vitality_used += healing
if(tox_to_heal && vitality_for_cycle)
var/healing = min(vitality_for_cycle, tox_to_heal)
vitality_for_cycle -= healing
L.adjustToxLoss(-healing)
vitality_used += healing
if(burn_to_heal && vitality_for_cycle)
var/healing = min(vitality_for_cycle, burn_to_heal)
vitality_for_cycle -= healing
L.adjustFireLoss(-healing)
vitality_used += healing
if(brute_to_heal && vitality_for_cycle)
var/healing = min(vitality_for_cycle, brute_to_heal)
vitality_for_cycle -= healing
L.adjustBruteLoss(-healing)
vitality_used += healing
if(oxy_to_heal && vitality_for_cycle)
var/healing = min(vitality_for_cycle, oxy_to_heal)
vitality_for_cycle -= healing
L.adjustOxyLoss(-healing)
vitality_used += healing
if(!ratvar_awakens)
vitality -= vitality_used
sleep(2)
if(sigil_active)
animation_number = initial(animation_number)
sigil_active = FALSE
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
if(sigil_active || alpha == 255)
animate(src, alpha = initial(alpha), time = 10)
addtimer(src, "update_alpha", 10)
/obj/effect/clockwork/sigil/vitality/proc/update_alpha()
if(sigil_active)
alpha = 255
else
alpha = initial(alpha)
@@ -0,0 +1,57 @@
//massive markers for Revenant and Judgement scripture.
/obj/effect/clockwork/general_marker
name = "general marker"
desc = "Some big guy. For you."
clockwork_desc = "One of Ratvar's generals."
alpha = 200
layer = MASSIVE_OBJ_LAYER
/obj/effect/clockwork/general_marker/New()
..()
animate(src, alpha = 0, time = 10)
QDEL_IN(src, 10)
/obj/effect/clockwork/general_marker/inathneq
name = "Inath-neq, the Resonant Cogwheel"
desc = "A humanoid form blazing with blue fire. It radiates an aura of kindness and caring."
clockwork_desc = "One of Ratvar's four generals. Before her current form, Inath-neq was a powerful warrior priestess commanding the Resonant Cogs, a sect of Ratvarian warriors renowned for \
their prowess. After a lost battle with Nar-Sian cultists, Inath-neq was struck down and stated in her dying breath, \
\"The Resonant Cogs shall not fall silent this day, but will come together to form a wheel that shall never stop turning.\" Ratvar, touched by this, granted Inath-neq an eternal body and \
merged her soul with those of the Cogs slain with her on the battlefield."
icon = 'icons/effects/187x381.dmi'
icon_state = "inath-neq"
pixel_x = -77
pixel_y = -174
/obj/effect/clockwork/general_marker/nezbere
name = "Nezbere, the Brass Eidolon"
desc = "A towering colossus clad in nigh-impenetrable brass armor. Its gaze is stern yet benevolent, even upon you."
clockwork_desc = "One of Ratvar's four generals. Nezbere is responsible for the design, testing, and creation of everything in Ratvar's domain, and his loyalty to Ratvar knows no bounds. \
It is said that Ratvar once asked him to destroy the plans for a weapon Nezbere had made that could have harmed him and Nezbere responded by not only destroying the plans, \
but by taking his own life so that the device could never be replicated. Nezbere's zealotry is unmatched."
icon = 'icons/effects/340x428.dmi'
icon_state = "nezbere"
pixel_x = -154
pixel_y = -198
/obj/effect/clockwork/general_marker/sevtug
name = "Sevtug, the Formless Pariah"
desc = "A sinister cloud of purple energy. Looking at it gives you a headache."
clockwork_desc = "One of Ratvar's four generals. Sevtug taught him how to manipulate minds and is one of his oldest allies. Sevtug serves Ratvar loyally out of a hope that one day, he will \
be able to use a moment of weakness in the Justicar to usurp him, but such a day will never come. And so, he serves with dedication, if not necessarily any sort of decorum, never aware he is \
the one being made a fool of."
icon = 'icons/effects/211x247.dmi'
icon_state = "sevtug"
pixel_x = -89
pixel_y = -107
/obj/effect/clockwork/general_marker/nzcrentr
name = "Nzcrentr, the Eternal Thunderbolt"
desc = "A terrifying spiked construct crackling with limitless energy."
clockwork_desc = "One of Ratvar's four generals. Before becoming one of Ratvar's generals, Nzcrentr sook out any and all sentient life to slaughter it for sport. \
Nzcrentr was coerced by Ratvar into entering a shell constructed by Nezbere, ostensibly made to grant Nzcrentr more power. In reality, the shell was made to trap and control it. \
Nzcrentr now serves loyally, though even one of Nezbere's finest creations was not enough to totally eliminate its will."
icon = 'icons/effects/254x361.dmi'
icon_state = "nzcrentr"
pixel_x = -111
pixel_y = -164
@@ -0,0 +1,212 @@
//Spatial gateway: A usually one-way rift to another location.
/obj/effect/clockwork/spatial_gateway
name = "spatial gateway"
desc = "A gently thrumming tear in reality."
clockwork_desc = "A gateway in reality."
icon_state = "spatial_gateway"
density = 1
luminosity = 2
var/sender = TRUE //If this gateway is made for sending, not receiving
var/both_ways = FALSE
var/lifetime = 25 //How many deciseconds this portal will last
var/uses = 1 //How many objects or mobs can go through the portal
var/obj/effect/clockwork/spatial_gateway/linked_gateway //The gateway linked to this one
var/timerid
/obj/effect/clockwork/spatial_gateway/New()
..()
addtimer(src, "check_setup", 1)
/obj/effect/clockwork/spatial_gateway/Destroy()
deltimer(timerid)
return ..()
/obj/effect/clockwork/spatial_gateway/proc/check_setup()
if(!linked_gateway)
qdel(src)
return
if(both_ways)
clockwork_desc = "A gateway in reality. It can both send and receive objects."
else
clockwork_desc = "A gateway in reality. It can only [sender ? "send" : "receive"] objects."
timerid = QDEL_IN(src, lifetime)
//set up a gateway with another gateway
/obj/effect/clockwork/spatial_gateway/proc/setup_gateway(obj/effect/clockwork/spatial_gateway/gatewayB, set_duration, set_uses, two_way)
if(!gatewayB || !set_duration || !uses)
return FALSE
linked_gateway = gatewayB
gatewayB.linked_gateway = src
if(two_way)
both_ways = TRUE
gatewayB.both_ways = TRUE
else
sender = TRUE
gatewayB.sender = FALSE
gatewayB.density = FALSE
lifetime = set_duration
gatewayB.lifetime = set_duration
uses = set_uses
gatewayB.uses = set_uses
return TRUE
/obj/effect/clockwork/spatial_gateway/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='brass'>It has [uses] uses remaining.</span>"
/obj/effect/clockwork/spatial_gateway/attack_ghost(mob/user)
if(linked_gateway)
user.forceMove(get_turf(linked_gateway))
..()
/obj/effect/clockwork/spatial_gateway/attack_hand(mob/living/user)
if(!uses)
return FALSE
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
var/mob/living/L = user.pulling
if(L.buckled || L.anchored || L.has_buckled_mobs())
return FALSE
user.visible_message("<span class='warning'>[user] shoves [L] into [src]!</span>", "<span class='danger'>You shove [L] into [src]!</span>")
user.stop_pulling()
pass_through_gateway(L)
return TRUE
if(!user.canUseTopic(src))
return FALSE
user.visible_message("<span class='warning'>[user] climbs through [src]!</span>", "<span class='danger'>You brace yourself and step through [src]...</span>")
pass_through_gateway(user)
return TRUE
/obj/effect/clockwork/spatial_gateway/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/weapon/nullrod))
user.visible_message("<span class='warning'>[user] dispels [src] with [I]!</span>", "<span class='danger'>You close [src] with [I]!</span>")
qdel(linked_gateway)
qdel(src)
return TRUE
if(istype(I, /obj/item/clockwork/slab))
user << "<span class='heavy_brass'>\"I don't think you want to drop your slab into that\".\n\"If you really want to, try throwing it.\"</span>"
return TRUE
if(user.drop_item() && uses)
user.visible_message("<span class='warning'>[user] drops [I] into [src]!</span>", "<span class='danger'>You drop [I] into [src]!</span>")
pass_through_gateway(I, TRUE)
return TRUE
return ..()
/obj/effect/clockwork/spatial_gateway/ex_act(severity)
if(severity == 1 && uses)
uses = 0
visible_message("<span class='warning'>[src] is disrupted!</span>")
animate(src, alpha = 0, transform = matrix()*2, time = 10)
deltimer(timerid)
timerid = QDEL_IN(src, 10)
linked_gateway.uses = 0
linked_gateway.visible_message("<span class='warning'>[linked_gateway] is disrupted!</span>")
animate(linked_gateway, alpha = 0, transform = matrix()*2, time = 10)
deltimer(linked_gateway.timerid)
linked_gateway.timerid = QDEL_IN(linked_gateway, 10)
return TRUE
return FALSE
/obj/effect/clockwork/spatial_gateway/Bumped(atom/A)
..()
if(isliving(A) || istype(A, /obj/item))
pass_through_gateway(A)
/obj/effect/clockwork/spatial_gateway/proc/pass_through_gateway(atom/movable/A, no_cost)
if(!linked_gateway)
qdel(src)
return FALSE
if(!sender)
visible_message("<span class='warning'>[A] bounces off of [src]!</span>")
return FALSE
if(!uses)
return FALSE
if(isliving(A))
var/mob/living/user = A
user << "<span class='warning'><b>You pass through [src] and appear elsewhere!</b></span>"
linked_gateway.visible_message("<span class='warning'>A shape appears in [linked_gateway] before emerging!</span>")
playsound(src, 'sound/effects/EMPulse.ogg', 50, 1)
playsound(linked_gateway, 'sound/effects/EMPulse.ogg', 50, 1)
transform = matrix() * 1.5
animate(src, transform = matrix() / 1.5, time = 10)
linked_gateway.transform = matrix() * 1.5
animate(linked_gateway, transform = matrix() / 1.5, time = 10)
A.forceMove(get_turf(linked_gateway))
if(!no_cost)
uses = max(0, uses - 1)
linked_gateway.uses = max(0, linked_gateway.uses - 1)
addtimer(src, "check_uses", 10)
return TRUE
/obj/effect/clockwork/spatial_gateway/proc/check_uses()
if(!uses)
qdel(src)
qdel(linked_gateway)
//This proc creates and sets up a gateway from invoker input.
/atom/movable/proc/procure_gateway(mob/living/invoker, time_duration, gateway_uses, two_way)
var/list/possible_targets = list()
var/list/teleportnames = list()
var/list/duplicatenamecount = list()
for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in all_clockwork_objects)
if(!O.Adjacent(invoker) && O != src && (O.z <= ZLEVEL_SPACEMAX) && O.anchored) //don't list obelisks that we're next to
var/area/A = get_area(O)
var/locname = initial(A.name)
var/resultkey = "[locname] [O.name]"
if(resultkey in teleportnames) //why the fuck did you put two obelisks in the same area
duplicatenamecount[resultkey]++
resultkey = "[resultkey] ([duplicatenamecount[resultkey]])"
else
teleportnames.Add(resultkey)
duplicatenamecount[resultkey] = 1
possible_targets[resultkey] = O
for(var/mob/living/L in living_mob_list)
if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && (L.z <= ZLEVEL_SPACEMAX)) //People right next to the invoker can't be portaled to, for obvious reasons
var/resultkey = "[L.name] ([L.real_name])"
if(resultkey in teleportnames)
duplicatenamecount[resultkey]++
resultkey = "[resultkey] ([duplicatenamecount[resultkey]])"
else
teleportnames.Add(resultkey)
duplicatenamecount[resultkey] = 1
possible_targets[resultkey] = L
if(!possible_targets.len)
invoker << "<span class='warning'>There are no other eligible targets for a Spatial Gateway!</span>"
return FALSE
var/input_target_key = input(invoker, "Choose a target to form a rift to.", "Spatial Gateway") as null|anything in possible_targets
var/atom/movable/target = possible_targets[input_target_key]
if(!src || !target || !invoker || !invoker.canUseTopic(src, !issilicon(invoker)) || !is_servant_of_ratvar(invoker) || (istype(src, /obj/item) && invoker.get_active_held_item() != src) || !invoker.can_speak_vocal())
return FALSE //if any of the involved things no longer exist, the invoker is stunned, too far away to use the object, or does not serve ratvar, or if the object is an item and not in the mob's active hand, fail
if(isliving(target))
var/mob/living/L = target
if(L.stat != CONSCIOUS)
invoker << "<span class='warning'>That Servant is no longer conscious!</span>"
return procure_gateway(invoker, time_duration, gateway_uses, two_way) //try again?
if(!is_servant_of_ratvar(L))
invoker << "<span class='warning'>That target is no longer a Servant!</span>"
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
var/istargetobelisk = istype(target, /obj/structure/destructible/clockwork/powered/clockwork_obelisk)
var/issrcobelisk = istype(src, /obj/structure/destructible/clockwork/powered/clockwork_obelisk)
if(issrcobelisk && !anchored)
invoker << "<span class='warning'>[src] is no longer secured!</span>"
return FALSE
if(istargetobelisk)
if(!target.anchored)
invoker << "<span class='warning'>That [target.name] is no longer secured!</span>"
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/CO = target
var/efficiency = CO.get_efficiency_mod()
gateway_uses = round(gateway_uses * (2 * efficiency), 1)
time_duration = round(time_duration * (2 * efficiency), 1)
invoker.visible_message("<span class='warning'>The air in front of [invoker] ripples before suddenly tearing open!</span>", \
"<span class='brass'>With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [time_duration / 10] seconds and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].</span>")
var/obj/effect/clockwork/spatial_gateway/S1 = new(issrcobelisk ? get_turf(src) : get_step(get_turf(invoker), invoker.dir))
var/obj/effect/clockwork/spatial_gateway/S2 = new(istargetobelisk ? get_turf(target) : get_step(get_turf(target), target.dir))
//Set up the portals now that they've spawned
S1.setup_gateway(S2, time_duration, gateway_uses, two_way)
S2.visible_message("<span class='warning'>The air in front of [target] ripples before suddenly tearing open!</span>")
return TRUE
@@ -0,0 +1,55 @@
//horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
/atom/movable/proc/power_drain(clockcult_user)
return 0
/obj/machinery/power/apc/power_drain(clockcult_user)
if(cell && cell.charge)
playsound(src, "sparks", 50, 1)
flick("apc-spark", src)
. = min(cell.charge, 250)
cell.use(.) //Better than a power sink!
if(!cell.charge && !shorted)
shorted = 1
visible_message("<span class='warning'>The [name]'s screen blurs with static.</span>")
update()
update_icon()
/obj/machinery/power/smes/power_drain(clockcult_user)
if(charge)
. = min(charge, 250)
charge -= . * 50
if(!charge && !panel_open)
panel_open = TRUE
icon_state = "[initial(icon_state)]-o"
var/datum/effect_system/spark_spread/spks = new(get_turf(src))
spks.set_up(10, 0, get_turf(src))
spks.start()
visible_message("<span class='warning'>[src]'s panel flies open with a flurry of spark</span>")
update_icon()
/obj/item/weapon/stock_parts/cell/power_drain(clockcult_user)
if(charge)
. = min(charge, 250)
charge = use(.)
updateicon()
/obj/machinery/light/power_drain(clockcult_user)
if(on)
playsound(src, 'sound/effects/light_flicker.ogg', 50, 1)
. = 250
if(prob(50))
burn_out()
/mob/living/silicon/robot/power_drain(clockcult_user)
if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge)
. = min(cell.charge, 250)
cell.use(.)
src << "<span class='userdanger'>ERROR: Power loss detected!</span>"
spark_system.start()
/obj/mecha/power_drain(clockcult_user)
if((!clockcult_user || !occupant || occupant && !is_servant_of_ratvar(occupant)) && cell && cell.charge)
. = min(cell.charge, 250)
cell.use(.)
occupant_message("<span class='userdanger'>Power loss detected!</span>")
spark_system.start()
@@ -0,0 +1,146 @@
//generates a component in the global component cache, either random based on lowest or a specific component
/proc/generate_cache_component(specific_component_id, atom/A)
if(!specific_component_id)
specific_component_id = get_weighted_component_id()
clockwork_component_cache[specific_component_id]++
if(A)
PoolOrNew(get_component_animation_type(specific_component_id), get_turf(A))
update_slab_info()
return specific_component_id
//returns a chosen component id based on the lowest amount of that component in the global cache, the global cache plus the slab if there are caches, or the slab if there are no caches.
/proc/get_weighted_component_id(obj/item/clockwork/slab/storage_slab)
. = list()
if(storage_slab)
if(clockwork_caches)
for(var/i in clockwork_component_cache)
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache[i] + storage_slab.stored_components[i]), 1)
else
for(var/i in clockwork_component_cache)
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*storage_slab.stored_components[i], 1)
else
for(var/i in clockwork_component_cache)
.[i] = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache[i], 1)
. = pickweight(.)
//returns a component name from a component id
/proc/get_component_name(id)
switch(id)
if(BELLIGERENT_EYE)
return "Belligerent Eye"
if(VANGUARD_COGWHEEL)
return "Vanguard Cogwheel"
if(GEIS_CAPACITOR)
return "Geis Capacitor"
if(REPLICANT_ALLOY)
return "Replicant Alloy"
if(HIEROPHANT_ANSIBLE)
return "Hierophant Ansible"
else
return null
//returns a component acronym from a component id
/proc/get_component_acronym(id)
switch(id)
if(BELLIGERENT_EYE)
return "BE"
if(VANGUARD_COGWHEEL)
return "VC"
if(GEIS_CAPACITOR)
return "GC"
if(REPLICANT_ALLOY)
return "RA"
if(HIEROPHANT_ANSIBLE)
return "HA"
else
return null
//returns a component id from a component name
/proc/get_component_id(name)
switch(name)
if("Belligerent Eye")
return BELLIGERENT_EYE
if("Vanguard Cogwheel")
return VANGUARD_COGWHEEL
if("Geis Capacitor")
return GEIS_CAPACITOR
if("Replicant Alloy")
return REPLICANT_ALLOY
if("Hierophant Ansible")
return HIEROPHANT_ANSIBLE
else
return null
//returns a component spanclass from a component id
/proc/get_component_span(id)
switch(id)
if(BELLIGERENT_EYE)
return "neovgre"
if(VANGUARD_COGWHEEL)
return "inathneq"
if(GEIS_CAPACITOR)
return "sevtug"
if(REPLICANT_ALLOY)
return "nezbere"
if(HIEROPHANT_ANSIBLE)
return "nzcrentr"
else
return "brass"
//returns a component color from a component id, but with brighter colors for the darkest
/proc/get_component_color_bright(id)
switch(id)
if(BELLIGERENT_EYE)
return "#880020"
if(REPLICANT_ALLOY)
return "#5A6068"
else
return get_component_color(id)
//returns a component color from a component id
/proc/get_component_color(id)
switch(id)
if(BELLIGERENT_EYE)
return "#6E001A"
if(VANGUARD_COGWHEEL)
return "#1E8CE1"
if(GEIS_CAPACITOR)
return "#AF0AAF"
if(REPLICANT_ALLOY)
return "#42474D"
if(HIEROPHANT_ANSIBLE)
return "#DAAA18"
else
return "#BE8700"
//returns a type for a floating component animation from a component id
/proc/get_component_animation_type(id)
switch(id)
if(BELLIGERENT_EYE)
return /obj/effect/overlay/temp/ratvar/component
if(VANGUARD_COGWHEEL)
return /obj/effect/overlay/temp/ratvar/component/cogwheel
if(GEIS_CAPACITOR)
return /obj/effect/overlay/temp/ratvar/component/capacitor
if(REPLICANT_ALLOY)
return /obj/effect/overlay/temp/ratvar/component/alloy
if(HIEROPHANT_ANSIBLE)
return /obj/effect/overlay/temp/ratvar/component/ansible
else
return null
//returns a type for a component from a component id
/proc/get_component_type(id)
switch(id)
if(BELLIGERENT_EYE)
return /obj/item/clockwork/component/belligerent_eye
if(VANGUARD_COGWHEEL)
return /obj/item/clockwork/component/vanguard_cogwheel
if(GEIS_CAPACITOR)
return /obj/item/clockwork/component/geis_capacitor
if(REPLICANT_ALLOY)
return /obj/item/clockwork/component/replicant_alloy
if(HIEROPHANT_ANSIBLE)
return /obj/item/clockwork/component/hierophant_ansible
else
return null
@@ -0,0 +1,47 @@
//Sends a string to all servants and optionally ghosts, who will get a follow link to whatever is provided as the target.
/proc/hierophant_message(message, servantsonly, atom/target)
if(!message)
return FALSE
for(var/M in mob_list)
if(!servantsonly && isobserver(M))
if(target)
var/link = FOLLOW_LINK(M, target)
M << "[link] [message]"
else
M << message
else if(is_servant_of_ratvar(M))
M << message
return TRUE
//Sends a titled message from a mob to all servants of ratvar and ghosts.
/proc/titled_hierophant_message(mob/user, message, name_span = "heavy_brass", message_span = "brass", user_title = "Servant")
if(!user || !message)
return FALSE
var/parsed_message = "<span class='[name_span]'>[user_title ? "[user_title] ":""][findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: \
</span><span class='[message_span]'>\"[message]\"</span>"
hierophant_message(parsed_message, FALSE, user)
return TRUE
//Hierophant Network action, allows a servant with it to communicate to other servants.
/datum/action/innate/hierophant
name = "Hierophant Network"
desc = "Allows you to communicate with other Servants."
button_icon_state = "hierophant"
background_icon_state = "bg_clock"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS
buttontooltipstyle = "clockcult"
var/title = "Servant"
var/span_for_name = "heavy_brass"
var/span_for_message = "brass"
/datum/action/innate/hierophant/IsAvailable()
if(!is_servant_of_ratvar(owner))
return FALSE
return ..()
/datum/action/innate/hierophant/Activate()
var/input = stripped_input(usr, "Please enter a message to send to other servants.", "Hierophant Network", "")
if(!input || !IsAvailable())
return
titled_hierophant_message(owner, input, span_for_name, span_for_message, title)
@@ -0,0 +1,320 @@
//For the clockwork proselytizer, this proc exists to make it easy to customize what the proselytizer does when hitting something.
//if a valid target, returns an associated list in this format;
//list("operation_time" = 15, "new_obj_type" = /obj/structure/window/reinforced/clockwork, "alloy_cost" = 5, "spawn_dir" = dir, "dir_in_new" = TRUE)
//otherwise, return literally any non-list thing but preferably FALSE
//returning TRUE won't produce the "cannot be proselytized" message and will still prevent proselytizing
/atom/proc/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
//Turf conversion
/turf/closed/wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //four sheets of metal
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_TOTAL - (REPLICANT_METAL * 4), "spawn_dir" = SOUTH)
/turf/closed/wall/mineral/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_TOTAL - (REPLICANT_METAL * 2), "spawn_dir" = SOUTH)
/turf/closed/wall/mineral/iron/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal, five rods
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_TOTAL - (REPLICANT_METAL * 2) - (REPLICANT_ROD * 5), "spawn_dir" = SOUTH)
/turf/closed/wall/mineral/cult/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //no metal
return list("operation_time" = 80, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_TOTAL, "spawn_dir" = SOUTH)
/turf/closed/wall/shuttle/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_TOTAL - (REPLICANT_METAL * 2), "spawn_dir" = SOUTH)
/turf/closed/wall/r_wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/turf/closed/wall/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 50, "new_obj_type" = /turf/open/floor/clockwork, "alloy_cost" = -REPLICANT_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
/turf/open/floor/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(floor_tile == /obj/item/stack/tile/plasteel)
PoolOrNew(floor_tile, src)
make_plating()
playsound(src, 'sound/items/Crowbar.ogg', 10, 1) //clink
return list("operation_time" = 30, "new_obj_type" = /turf/open/floor/clockwork, "alloy_cost" = REPLICANT_FLOOR, "spawn_dir" = SOUTH)
/turf/open/floor/plating/asteroid/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/turf/open/floor/plating/ashplanet/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/turf/open/floor/plating/lava/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/turf/open/floor/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(is_blocked_turf(src))
user << "<span class='warning'>Something is in the way, preventing you from proselytizing [src] into a clockwork wall.</span>"
return TRUE
return list("operation_time" = 100, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
//False wall conversion
/obj/structure/falsewall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
var/cost = REPLICANT_WALL_MINUS_FLOOR
if(ispath(mineral, /obj/item/stack/sheet/metal))
cost -= (REPLICANT_METAL * (2 + mineral_amount)) //four sheets of metal, plus an assumption that the girder is also two
else
cost -= (REPLICANT_METAL * 2) //anything that doesn't use metal just has the girder
return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "alloy_cost" = cost, "spawn_dir" = SOUTH)
/obj/structure/falsewall/iron/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal, two rods; special assumption
return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "alloy_cost" = REPLICANT_WALL_MINUS_FLOOR - (REPLICANT_METAL * 2) - (REPLICANT_ROD * 2), "spawn_dir" = SOUTH)
/obj/structure/falsewall/reinforced/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/obj/structure/falsewall/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
//Metal conversion
/obj/item/stack/tile/plasteel/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(source)
return FALSE
var/amount_temp = get_amount()
if(proselytizer.metal_to_alloy)
var/no_delete = FALSE
if(amount_temp < 2)
user << "<span class='warning'>You need at least <b>2</b> floor tiles to convert into alloy.</span>"
return TRUE
if(IsOdd(amount_temp))
amount_temp--
no_delete = TRUE
use(amount_temp)
amount_temp *= 0.5 //halve the alloy output; each tile is 0.5 alloy so this is 2 tiles to 1 alloy
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -amount_temp, "spawn_dir" = SOUTH, "no_target_deletion" = no_delete)
if(amount_temp >= 20)
var/sheets_to_make = round(amount_temp * 0.05) //and 20 to 1 brass
var/used = sheets_to_make * 20
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
playsound(src, 'sound/machines/click.ogg', 50, 1)
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
use(used)
else
user << "<span class='warning'>You need at least <b>20</b> floor tiles to convert into brass.</span>"
return TRUE
/obj/item/stack/rods/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(source)
return FALSE
if(proselytizer.metal_to_alloy)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -(amount*REPLICANT_ROD), "spawn_dir" = SOUTH)
if(get_amount() >= 10)
var/sheets_to_make = round(get_amount() * 0.1)
var/used = sheets_to_make * 10
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
playsound(src, 'sound/machines/click.ogg', 50, 1)
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
use(used)
else
user << "<span class='warning'>You need at least <b>10</b> rods to convert into brass.</span>"
return TRUE
/obj/item/stack/sheet/metal/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(source)
return FALSE
if(proselytizer.metal_to_alloy)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -(amount*REPLICANT_METAL), "spawn_dir" = SOUTH)
if(get_amount() >= 5)
var/sheets_to_make = round(get_amount() * 0.2)
var/used = sheets_to_make * 5
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
playsound(src, 'sound/machines/click.ogg', 50, 1)
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
use(used)
else
user << "<span class='warning'>You need at least <b>5</b> sheets of metal to convert into brass.</span>"
return TRUE
/obj/item/stack/sheet/plasteel/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(source)
return FALSE
if(proselytizer.metal_to_alloy)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -(amount*REPLICANT_PLASTEEL), "spawn_dir" = SOUTH)
if(get_amount() >= 2)
var/sheets_to_make = round(get_amount() * 0.5)
var/used = sheets_to_make * 2
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
playsound(src, 'sound/machines/click.ogg', 50, 1)
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
use(used)
else
user << "<span class='warning'>You need at least <b>2</b> sheets of plasteel to convert into brass.</span>"
return TRUE
//Brass directly to alloy; scarab only
/obj/item/stack/tile/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(source)
return FALSE
if(!proselytizer.metal_to_alloy)
return FALSE
var/prosel_cost = -amount*REPLICANT_FLOOR
return list("operation_time" = amount, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = prosel_cost, "spawn_dir" = SOUTH)
//Airlock conversion
/obj/machinery/door/airlock/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
var/doortype = /obj/machinery/door/airlock/clockwork
if(glass)
doortype = /obj/machinery/door/airlock/clockwork/brass
return list("operation_time" = 60, "new_obj_type" = doortype, "alloy_cost" = REPLICANT_WALL_TOTAL, "spawn_dir" = dir)
/obj/machinery/door/airlock/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
//Window conversion
/obj/structure/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
var/windowtype = /obj/structure/window/reinforced/clockwork
var/new_dir = TRUE
var/prosel_time = 15
var/prosel_cost = REPLICANT_FLOOR
if(fulltile)
windowtype = /obj/structure/window/reinforced/clockwork/fulltile
new_dir = FALSE
prosel_time = 30
prosel_cost = REPLICANT_STANDARD
if(reinf)
prosel_cost -= REPLICANT_ROD
if(reinf)
prosel_cost -= REPLICANT_ROD
for(var/obj/structure/grille/G in get_turf(src))
addtimer(proselytizer, "proselytize", 0, TIMER_NORMAL, G, user)
return list("operation_time" = prosel_time, "new_obj_type" = windowtype, "alloy_cost" = prosel_cost, "spawn_dir" = dir, "dir_in_new" = new_dir)
/obj/structure/window/reinforced/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
//Windoor conversion
/obj/machinery/door/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 30, "new_obj_type" = /obj/machinery/door/window/clockwork, "alloy_cost" = REPLICANT_STANDARD, "spawn_dir" = dir, "dir_in_new" = TRUE)
/obj/machinery/door/window/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
//Grille conversion
/obj/structure/grille/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
var/grilletype = /obj/structure/grille/ratvar
var/prosel_time = 15
if(broken)
grilletype = /obj/structure/grille/ratvar/broken
prosel_time = 5
return list("operation_time" = prosel_time, "new_obj_type" = grilletype, "alloy_cost" = 0, "spawn_dir" = dir)
/obj/structure/grille/ratvar/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
//Girder conversion
/obj/structure/girder/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
var/prosel_cost = REPLICANT_GEAR - (REPLICANT_METAL * 2)
if(state == GIRDER_REINF_STRUTS || state == GIRDER_REINF)
prosel_cost -= REPLICANT_PLASTEEL
return list("operation_time" = 20, "new_obj_type" = /obj/structure/destructible/clockwork/wall_gear, "alloy_cost" = prosel_cost, "spawn_dir" = SOUTH)
//Hitting a clockwork structure will try to repair it.
/obj/structure/destructible/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
. = TRUE
if(!can_be_repaired)
user << "<span class='warning'>[src] cannot be repaired with a proselytizer!</span>"
return
if(obj_integrity >= max_integrity)
user << "<span class='warning'>[src] is at maximum integrity!</span>"
return
var/amount_to_heal = max_integrity - obj_integrity
var/healing_for_cycle = min(amount_to_heal, repair_amount)
var/alloy_required = healing_for_cycle
if(!proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK))
healing_for_cycle = min(healing_for_cycle, proselytizer.get_power_alloy())
if(!healing_for_cycle || (!proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK) && !proselytizer.can_use_alloy(healing_for_cycle)))
user << "<span class='warning'>You need at least <b>[alloy_required]</b> liquified alloy to start repairing [src], and at least <b>[amount_to_heal]</b> to fully repair it!</span>"
return
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts covering [src] in black liquid metal...</span>", \
"<span class='alloy'>You start repairing [src]...</span>")
//hugeass while because we need to re-check after the do_after
proselytizer.repairing = src
while(proselytizer && user && src && obj_integrity < max_integrity)
amount_to_heal = max_integrity - obj_integrity
if(amount_to_heal <= 0)
break
healing_for_cycle = min(amount_to_heal, repair_amount)
if(!proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK))
healing_for_cycle = min(healing_for_cycle, proselytizer.get_power_alloy())
if(!healing_for_cycle || (!proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK) && !proselytizer.can_use_alloy(healing_for_cycle)) || \
!do_after(user, healing_for_cycle * proselytizer.speed_multiplier, target = src) || \
!proselytizer || (!proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK) && !proselytizer.can_use_alloy(healing_for_cycle)))
break
amount_to_heal = max_integrity - obj_integrity
if(amount_to_heal <= 0)
break
healing_for_cycle = min(amount_to_heal, repair_amount)
if(!proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK))
healing_for_cycle = min(healing_for_cycle, proselytizer.get_power_alloy())
if(!healing_for_cycle || (!proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK) && !proselytizer.can_use_alloy(healing_for_cycle)))
break
obj_integrity = Clamp(obj_integrity + healing_for_cycle, 0, max_integrity)
proselytizer.modify_stored_alloy(-healing_for_cycle)
playsound(src, 'sound/machines/click.ogg', 50, 1)
if(proselytizer)
proselytizer.repairing = null
if(user)
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops covering [src] with black liquid metal.</span>", \
"<span class='alloy'>You finish repairing [src]. It is now at <b>[obj_integrity]/[max_integrity]</b> integrity.</span>")
return
//Hitting a tinkerer's cache will try to fill the proselytizer with alloy after trying to repair.
/obj/structure/destructible/clockwork/cache/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
. = ..()
if(proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK) || proselytizer.stored_alloy + REPLICANT_ALLOY_UNIT > proselytizer.max_alloy)
user << "<span class='warning'>[proselytizer]'s containers of liquified alloy are full!</span>"
return
if(!anchored)
user << "<span class='warning'>You need to anchor [src] to fill your [proselytizer.name] from it!</span>"
return
if(!clockwork_component_cache["replicant_alloy"])
user << "<span class='warning'>There is no Replicant Alloy in the global component cache!</span>"
return
proselytizer.refueling = TRUE
user.visible_message("<span class='notice'>[user] places the end of [proselytizer] in the hole in [src]...</span>", \
"<span class='notice'>You start filling [proselytizer] with liquified alloy...</span>")
//hugeass check because we need to re-check after the do_after
while(anchored && proselytizer && !proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK) && proselytizer.stored_alloy + REPLICANT_ALLOY_UNIT <= proselytizer.max_alloy && clockwork_component_cache["replicant_alloy"] \
&& do_after(user, 10, target = src) \
&& anchored && proselytizer && !proselytizer.can_use_alloy(RATVAR_ALLOY_CHECK) && proselytizer.stored_alloy + REPLICANT_ALLOY_UNIT <= proselytizer.max_alloy && clockwork_component_cache["replicant_alloy"])
proselytizer.modify_stored_alloy(REPLICANT_ALLOY_UNIT)
clockwork_component_cache["replicant_alloy"]--
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
if(proselytizer)
proselytizer.refueling = FALSE
if(user)
user.visible_message("<span class='notice'>[user] removes [proselytizer] from the hole in [src], apparently satisfied.</span>", \
"<span class='brass'>You finish filling [proselytizer] with liquified alloy. It now contains <b>[proselytizer.stored_alloy]/[proselytizer.max_alloy]</b> units of liquified alloy.</span>")
return
//Convert shards and replicant alloy directly to liquid alloy
/obj/item/clockwork/alloy_shards/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -REPLICANT_STANDARD, "spawn_dir" = SOUTH)
/obj/item/clockwork/alloy_shards/medium/gear_bit/large/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -(REPLICANT_ALLOY_UNIT*0.08), "spawn_dir" = SOUTH)
/obj/item/clockwork/alloy_shards/large/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -(REPLICANT_ALLOY_UNIT*0.06), "spawn_dir" = SOUTH)
/obj/item/clockwork/alloy_shards/medium/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -(REPLICANT_ALLOY_UNIT*0.04), "spawn_dir" = SOUTH)
/obj/item/clockwork/alloy_shards/small/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -(REPLICANT_ALLOY_UNIT*0.02), "spawn_dir" = SOUTH)
/obj/item/clockwork/component/replicant_alloy/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -REPLICANT_ALLOY_UNIT, "spawn_dir" = SOUTH)
@@ -0,0 +1,107 @@
/*
The Ratvarian Language
In the lore of the Servants of Ratvar, the Ratvarian tongue is a timeless language and full of power. It sounds like gibberish, much like Nar-Sie's language, but is in fact derived from
aforementioned language, and may induce miracles when spoken in the correct way with an amplifying tool (similar to runes used by the Nar-Sian cult).
While the canon states that the language of Ratvar and his servants is incomprehensible to the unenlightened as it is a derivative of the most ancient known language, in reality it is
actually very simple. To translate a plain English sentence to Ratvar's tongue, simply move all of the letters thirteen places ahead, starting from "a" if the end of the alphabet is reached.
This cipher is known as "rot13" for "rotate 13 places" and there are many sites online that allow instant translation between English and rot13 - one of the benefits is that moving the translated
sentence thirteen places ahead changes it right back to plain English.
There are, however, a few parts of the Ratvarian tongue that aren't typical and are implemented for fluff reasons. Some words may have graves, or hyphens (prefix and postfix), making the plain
English translation apparent but disjoined (for instance, "Orubyq zl-cbjre!" translates directly to "Behold my-power!") although this can be ignored without impacting overall quality. When
translating from Ratvar's tongue to plain English, simply remove the disjointments and use the finished sentence. This would make "Orubyq zl-cbjre!" into "Behold my power!" after removing the
abnormal spacing, hyphens, and grave accents.
List of nuances:
- Any time the WORD "of" occurs, it is linked to the previous word by a hyphen. (i.e. "V nz-bs Ratvar." directly translates to "I am-of Ratvar.")
- Any time "th", followed by any two letters occurs, you add a grave (`) between those two letters, i.e; "Thi`s"
- In the same vein, any time "ti", followed by one letter occurs, you add a grave (`) between "i" and the letter, i.e; "Ti`me"
- Whereever "te" or "et" appear and there is another letter next to the e(i.e; "m"etal, greate"r"), add a hyphen between "e" and the letter, i.e; "M-etal", "Greate-r"
- Where "gua" appears, add a hyphen between "gu" and "a", i.e "Gu-ard"
- Where the WORD "and" appears it is linked to all surrounding words by hyphens, i.e; "Sword-and-shield"
- Where the WORD "to" appears, it is linked to the following word by a hyphen, i.e; "to-use"
- Where the WORD "my" appears, it is linked to the following word by a hyphen, i.e; "my-light"
- Although "Ratvar" translates to "Engine" in English, the word "Ratvar" is used regardless of language as it is a proper noun.
- The same rule applies to Ratvar's four generals: Nezbere (Armorer), Sevtug (Fright), Nzcrentr (Amperage), and Inath-neq (Vangu-Ard), although these words can be used in proper context if one is
not referring to the four generals and simply using the words themselves.
*/
//Regexes used to alter english to ratvarian style
#define RATVAR_OF_MATCH regex("(\\w)\\s(\[oO]\[fF])","g")
#define RATVAR_OF_REPLACEMENT "$1-$2"
#define RATVAR_GUA_MATCH regex("(\[gG]\[uU])(\[aA])","g")
#define RATVAR_GUA_REPLACEMENT "$1-$2"
#define RATVAR_TH_MATCH regex("(\[tT]\[hH]\\w)(\\w)","g")
#define RATVAR_TH_REPLACEMENT "$1`$2"
#define RATVAR_TI_MATCH regex("(\[tT]\[iI])(\\w)","g")
#define RATVAR_TI_REPLACEMENT "$1`$2"
#define RATVAR_ET_MATCH regex("(\\w)(\[eE]\[tT])","g")
#define RATVAR_ET_REPLACEMENT "$1-$2"
#define RATVAR_TE_MATCH regex("(\[tT]\[eE])(\\w)","g")
#define RATVAR_TE_REPLACEMENT "$1-$2"
#define RATVAR_PRE_AND_MATCH regex("(\\w)\\s(\[aA]\[nN]\[dD])","g")
#define RATVAR_PRE_AND_REPLACEMENT "$1-$2"
#define RATVAR_POST_AND_MATCH regex("(\[aA]\[nN]\[dD])\\s(\\w)","g")
#define RATVAR_POST_AND_REPLACEMENT "$1-$2"
#define RATVAR_TO_MATCH regex("(\\s)(\[tT]\[oO])\\s(\\w)","g")
#define RATVAR_TO_REPLACEMENT "$1$2-$3"
#define RATVAR_MY_MATCH regex("(\\s)(\[mM]\[yY])\\s(\\w)","g")
#define RATVAR_MY_REPLACEMENT "$1$2-$3"
//Regexes used to remove ratvarian styling from english
#define REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH regex("(\\w)-(\[aA]\[nN]\[dD])","g") //specifically structured to support -emphasis-, including with -and-
#define REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT "$1 $2"
#define REVERSE_RATVAR_HYPHEN_POST_AND_MATCH regex("(\[aA]\[nN]\[dD])-(\\w)","g")
#define REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT "$1 $2"
#define REVERSE_RATVAR_HYPHEN_TO_MY_MATCH regex("(\[tTmM]\[oOyY])-","g")
#define REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT "$1 "
#define REVERSE_RATVAR_HYPHEN_TE_MATCH regex("(\[tT]\[eE])-","g")
#define REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT "$1"
#define REVERSE_RATVAR_HYPHEN_ET_MATCH regex("-(\[eE]\[tT])","g")
#define REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT "$1"
#define REVERSE_RATVAR_HYPHEN_GUA_MATCH regex("(\[gG]\[uU])-(\[aA])","g")
#define REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT "$1$2"
#define REVERSE_RATVAR_HYPHEN_OF_MATCH regex("-(\[oO]\[fF])","g")
#define REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT " $1"
/proc/text2ratvar(text) //Takes english and applies ratvarian styling rules (and rot13) to it
var/ratvarian = replacetext(text, RATVAR_OF_MATCH, RATVAR_OF_REPLACEMENT)
ratvarian = replacetext(ratvarian, RATVAR_GUA_MATCH, RATVAR_GUA_REPLACEMENT)
ratvarian = replacetext(ratvarian, RATVAR_TH_MATCH, RATVAR_TH_REPLACEMENT)
ratvarian = replacetext(ratvarian, RATVAR_TI_MATCH, RATVAR_TI_REPLACEMENT)
ratvarian = replacetext(ratvarian, RATVAR_ET_MATCH, RATVAR_ET_REPLACEMENT)
ratvarian = replacetext(ratvarian, RATVAR_TE_MATCH, RATVAR_TE_REPLACEMENT)
ratvarian = replacetext(ratvarian, RATVAR_PRE_AND_MATCH, RATVAR_PRE_AND_REPLACEMENT)
ratvarian = replacetext(ratvarian, RATVAR_POST_AND_MATCH, RATVAR_POST_AND_REPLACEMENT)
ratvarian = replacetext(ratvarian, RATVAR_TO_MATCH, RATVAR_TO_REPLACEMENT)
ratvarian = replacetext(ratvarian, RATVAR_MY_MATCH, RATVAR_MY_REPLACEMENT)
return rot13(ratvarian)
/proc/ratvar2text(ratvarian) //Reverts ravarian styling and rot13 in text.
var/text = replacetext(rot13(ratvarian), "`", "")
text = replacetext(text, REVERSE_RATVAR_HYPHEN_GUA_MATCH, REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT)
text = replacetext(text, REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH, REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT)
text = replacetext(text, REVERSE_RATVAR_HYPHEN_POST_AND_MATCH, REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT)
text = replacetext(text, REVERSE_RATVAR_HYPHEN_TO_MY_MATCH, REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT)
text = replacetext(text, REVERSE_RATVAR_HYPHEN_TE_MATCH, REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT)
text = replacetext(text, REVERSE_RATVAR_HYPHEN_ET_MATCH, REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT)
text = replacetext(text, REVERSE_RATVAR_HYPHEN_OF_MATCH, REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT)
return text
//Causes the mob or AM in question to speak a message; it assumes that the message is already translated to ratvar speech using text2ratvar()
/proc/clockwork_say(atom/movable/AM, message, whisper=FALSE)
var/list/spans = list(SPAN_ROBOT)
var/old_languages_spoken = AM.languages_spoken
AM.languages_spoken = HUMAN //anyone who can understand HUMAN will hear weird shitty ratvar speak, otherwise it'll get starred out
if(isliving(AM))
var/mob/living/L = AM
if(!whisper)
L.say(message, "clock", spans)
else
L.whisper(message)
else
AM.say(message)
AM.languages_spoken = old_languages_spoken
@@ -0,0 +1,48 @@
//returns a list of scriptures and if they're unlocked or not
/proc/scripture_unlock_check()
var/servants = 0
var/unconverted_ai_exists = FALSE
for(var/mob/living/M in living_mob_list)
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
servants++
else if(isAI(M))
unconverted_ai_exists = TRUE
. = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE, SCRIPTURE_REVENANT = FALSE, SCRIPTURE_JUDGEMENT = FALSE)
//Drivers: always unlocked
.[SCRIPTURE_SCRIPT] = (servants >= SCRIPT_SERVANT_REQ && clockwork_caches >= SCRIPT_CACHE_REQ)
//Script: SCRIPT_SERVANT_REQ or more non-brain servants and SCRIPT_CACHE_REQ or more clockwork caches
.[SCRIPTURE_APPLICATION] = (servants >= APPLICATION_SERVANT_REQ && clockwork_caches >= APPLICATION_CACHE_REQ && clockwork_construction_value >= APPLICATION_CV_REQ)
//Application: APPLICATION_SERVANT_REQ or more non-brain servants, APPLICATION_CACHE_REQ or more clockwork caches, and at least APPLICATION_CV_REQ CV
.[SCRIPTURE_REVENANT] = (servants >= REVENANT_SERVANT_REQ && clockwork_caches >= REVENANT_CACHE_REQ && clockwork_construction_value >= REVENANT_CV_REQ)
//Revenant: REVENANT_SERVANT_REQ or more non-brain servants, REVENANT_CACHE_REQ or more clockwork caches, and at least REVENANT_CV_REQ CV
.[SCRIPTURE_JUDGEMENT] = (servants >= JUDGEMENT_SERVANT_REQ && clockwork_caches >= JUDGEMENT_CACHE_REQ && clockwork_construction_value >= JUDGEMENT_CV_REQ && !unconverted_ai_exists)
//Judgement: JUDGEMENT_SERVANT_REQ or more non-brain servants, JUDGEMENT_CACHE_REQ or more clockwork caches, at least JUDGEMENT_CV_REQ CV, and there are no living, non-servant ais
//reports to servants when scripture is locked or unlocked
/proc/scripture_unlock_alert(list/previous_states)
. = scripture_unlock_check()
for(var/i in .)
if(.[i] != previous_states[i])
hierophant_message("<span class='large_brass'><i>Hierophant Network:</i> <b>[i] Scripture has been [.[i] ? "un":""]locked.</b></span>")
update_slab_info()
/proc/update_slab_info(obj/item/clockwork/slab/set_slab)
generate_all_scripture()
for(var/s in all_scripture)
var/datum/clockwork_scripture/S = s
S.creation_update()
if(!set_slab)
for(var/obj/item/clockwork/slab/S in all_clockwork_objects)
SStgui.update_uis(S)
else
SStgui.update_uis(set_slab)
/proc/generate_all_scripture()
if(!all_scripture.len)
for(var/V in sortList(subtypesof(/datum/clockwork_scripture), /proc/cmp_clockscripture_priority))
var/datum/clockwork_scripture/S = new V
all_scripture += S
//changes construction value
/proc/change_construction_value(amount)
clockwork_construction_value += amount
@@ -0,0 +1,321 @@
//The base for slab-bound/based ranged abilities
/obj/effect/proc_holder/slab
var/obj/item/clockwork/slab/slab
var/successful = FALSE
var/finished = FALSE
var/in_progress = FALSE
/obj/effect/proc_holder/slab/remove_ranged_ability(msg)
..()
finished = TRUE
QDEL_IN(src, 2)
/obj/effect/proc_holder/slab/InterceptClickOn(mob/living/caller, params, atom/target)
if(..() || in_progress)
return TRUE
if(ranged_ability_user.incapacitated() || !slab || !(slab in ranged_ability_user.held_items) || target == slab)
remove_ranged_ability()
return TRUE
//For the Geis scripture; binds a target to convert.
/obj/effect/proc_holder/slab/geis
ranged_mousepointer = 'icons/effects/geis_target.dmi'
/obj/effect/proc_holder/slab/geis/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return TRUE
var/turf/T = ranged_ability_user.loc
if(!isturf(T))
return TRUE
var/target_is_binding = istype(target, /obj/structure/destructible/clockwork/geis_binding)
if((target_is_binding || isliving(target)) && ranged_ability_user.Adjacent(target))
if(target_is_binding)
var/obj/structure/destructible/clockwork/geis_binding/GB = target
GB.repair_and_interrupt()
for(var/m in GB.buckled_mobs)
if(m)
add_logs(ranged_ability_user, m, "rebound with Geis")
successful = TRUE
else
var/mob/living/L = target
if(L.null_rod_check())
ranged_ability_user << "<span class='sevtug'>\"A void weapon? Really, you expect me to be able to do anything?\"</span>"
return TRUE
if(is_servant_of_ratvar(L))
if(L != ranged_ability_user)
ranged_ability_user << "<span class='sevtug'>\"[L.p_they(TRUE)] already serve[L.p_s()] Ratvar. [text2ratvar("Perhaps [ranged_ability_user.p_theyre()] into bondage?")]\"</span>"
return TRUE
if(L.stat == DEAD)
ranged_ability_user << "<span class='sevtug'>\"[L.p_theyre(TRUE)] dead, idiot.\"</span>"
return TRUE
if(istype(L.buckled, /obj/structure/destructible/clockwork/geis_binding)) //if they're already bound, just stun them
var/obj/structure/destructible/clockwork/geis_binding/GB = L.buckled
GB.repair_and_interrupt()
add_logs(ranged_ability_user, L, "rebound with Geis")
successful = TRUE
else
in_progress = TRUE
clockwork_say(ranged_ability_user, text2ratvar("Be bound, heathen!"))
remove_mousepointer(ranged_ability_user.client)
add_logs(ranged_ability_user, L, "bound with Geis")
if(slab.speed_multiplier >= 0.5) //excuse my debug...
ranged_ability_user.notransform = TRUE
addtimer(src, "reset_user_notransform", 5, TIMER_NORMAL, ranged_ability_user) //stop us moving for a little bit so we don't break the scripture following this
slab.busy = null
var/datum/clockwork_scripture/geis/conversion = new
conversion.slab = slab
conversion.invoker = ranged_ability_user
conversion.target = target
successful = conversion.run_scripture()
remove_ranged_ability()
return TRUE
/obj/effect/proc_holder/slab/geis/proc/reset_user_notransform(mob/living/user)
if(user)
user.notransform = FALSE
/obj/structure/destructible/clockwork/geis_binding
name = "glowing ring"
desc = "A flickering, glowing purple ring around a target."
clockwork_desc = "A binding ring around a target, preventing them from taking action while they're being converted."
max_integrity = 25
obj_integrity = 25
density = 0
icon = 'icons/effects/clockwork_effects.dmi'
icon_state = "geisbinding_full"
break_message = null
break_sound = 'sound/magic/Repulse.ogg'
debris = list()
can_buckle = TRUE
buckle_lying = 0
buckle_prevents_pull = TRUE
var/resisting = FALSE
var/mob_layer = MOB_LAYER
/obj/structure/destructible/clockwork/geis_binding/examine(mob/user)
icon_state = "geisbinding_full"
..()
icon_state = "geisbinding"
/obj/structure/destructible/clockwork/geis_binding/attack_hand(mob/living/user)
return
/obj/structure/destructible/clockwork/geis_binding/emp_act(severity)
PoolOrNew(/obj/effect/overlay/temp/emp, loc)
qdel(src)
/obj/structure/destructible/clockwork/geis_binding/post_buckle_mob(mob/living/M)
if(M.buckled == src)
desc = "A flickering, glowing purple ring around [M]."
clockwork_desc = "A binding ring around [M], preventing [M.p_them()] from taking action while [M.p_theyre()] being converted."
icon_state = "geisbinding"
mob_layer = M.layer
layer = M.layer - 0.01
var/image/GB = new('icons/effects/clockwork_effects.dmi', src, "geisbinding_top", M.layer + 0.01)
add_overlay(GB)
for(var/obj/item/I in M.held_items)
M.unEquip(I)
for(var/i in M.get_empty_held_indexes())
var/obj/item/geis_binding/B = new(M)
M.put_in_hands(B, i)
M.regenerate_icons()
M.visible_message("<span class='warning'>A [name] appears around [M]!</span>", \
"<span class='warning'>A [name] appears around you!</span>\n<span class='userdanger'>Resist!</span>")
else
var/obj/effect/overlay/temp/ratvar/geis_binding/G = PoolOrNew(/obj/effect/overlay/temp/ratvar/geis_binding, M.loc)
var/obj/effect/overlay/temp/ratvar/geis_binding/T = PoolOrNew(/obj/effect/overlay/temp/ratvar/geis_binding/top, M.loc)
G.layer = mob_layer - 0.01
T.layer = mob_layer + 0.01
G.alpha = alpha
T.alpha = alpha
animate(G, transform = matrix()*2, alpha = 0, time = 8, easing = EASE_OUT)
animate(T, transform = matrix()*2, alpha = 0, time = 8, easing = EASE_OUT)
M.visible_message("<span class='warning'>[src] snaps into glowing pieces and dissipates!</span>")
for(var/obj/item/geis_binding/GB in M.held_items)
M.unEquip(GB, TRUE)
/obj/structure/destructible/clockwork/geis_binding/relaymove(mob/user, direction)
if(isliving(user))
var/mob/living/L = user
L.resist()
/obj/structure/destructible/clockwork/geis_binding/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
playsound(src, 'sound/effects/EMPulse.ogg', 50, 1)
/obj/structure/destructible/clockwork/geis_binding/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
if(.)
update_icon()
/obj/structure/destructible/clockwork/geis_binding/update_icon()
alpha = min(initial(alpha) + ((obj_integrity - max_integrity) * 5), 255)
/obj/structure/destructible/clockwork/geis_binding/proc/repair_and_interrupt()
obj_integrity = max_integrity
update_icon()
for(var/m in buckled_mobs)
var/mob/living/L = m
if(L)
L.Stun(1, 1, 1)
visible_message("<span class='sevtug'>[src] flares brightly!</span>")
var/obj/effect/overlay/temp/ratvar/geis_binding/G1 = PoolOrNew(/obj/effect/overlay/temp/ratvar/geis_binding, loc)
var/obj/effect/overlay/temp/ratvar/geis_binding/G2 = PoolOrNew(/obj/effect/overlay/temp/ratvar/geis_binding, loc)
var/obj/effect/overlay/temp/ratvar/geis_binding/T1 = PoolOrNew(/obj/effect/overlay/temp/ratvar/geis_binding/top, loc)
var/obj/effect/overlay/temp/ratvar/geis_binding/T2 = PoolOrNew(/obj/effect/overlay/temp/ratvar/geis_binding/top, loc)
G1.layer = mob_layer - 0.01
G2.layer = mob_layer - 0.01
T1.layer = mob_layer + 0.01
T2.layer = mob_layer + 0.01
animate(G1, pixel_y = pixel_y + 9, alpha = 0, time = 8, easing = EASE_IN)
animate(G2, pixel_y = pixel_y - 9, alpha = 0, time = 8, easing = EASE_IN)
animate(T1, pixel_y = pixel_y + 9, alpha = 0, time = 8, easing = EASE_IN)
animate(T2, pixel_y = pixel_y - 9, alpha = 0, time = 8, easing = EASE_IN)
/obj/structure/destructible/clockwork/geis_binding/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
if(buckled_mob == user)
if(!resisting)
resisting = TRUE
user.visible_message("<span class='warning'>[user] starts struggling against [src]...</span>", "<span class='userdanger'>You start breaking out of [src]...</span>")
while(do_after(user, 10, target = src) && resisting && obj_integrity)
if(obj_integrity - 5 <= 0)
user.visible_message("<span class='warning'>[user] breaks [src]!</span>", "<span class='userdanger'>You break [src]!</span>")
take_damage(5)
return user
take_damage(5)
resisting = FALSE
else
return ..()
/obj/item/geis_binding
name = "glowing ring"
desc = "A flickering ring preventing you from holding items."
force = 0
icon = 'icons/effects/clockwork_effects.dmi'
icon_state = "geisbinding_full"
flags = NODROP|ABSTRACT|DROPDEL|NOBLUDGEON
/obj/item/geis_binding/afterattack(atom/target, mob/living/user, proximity_flag, params)
user.resist()
//For the Sentinel's Compromise scripture; heals a target servant.
/obj/effect/proc_holder/slab/compromise
ranged_mousepointer = 'icons/effects/compromise_target.dmi'
/obj/effect/proc_holder/slab/compromise/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return TRUE
var/turf/T = ranged_ability_user.loc
if(!isturf(T))
return TRUE
if(isliving(target) && (target in view(7, get_turf(ranged_ability_user))))
var/mob/living/L = target
if(!is_servant_of_ratvar(L))
ranged_ability_user << "<span class='inathneq'>\"[L] does not yet serve Ratvar.\"</span>"
return TRUE
if(L.stat == DEAD)
ranged_ability_user << "<span class='inathneq'>\"[L.p_they(TRUE)] [L.p_are()] dead. [text2ratvar("Oh, child. To have your life cut short...")]\"</span>"
return TRUE
var/brutedamage = L.getBruteLoss()
var/burndamage = L.getFireLoss()
var/totaldamage = brutedamage + burndamage
if(!totaldamage && (!L.reagents || !L.reagents.has_reagent("holywater")))
ranged_ability_user << "<span class='inathneq'>\"[L] is unhurt and untainted.\"</span>"
return TRUE
var/targetturf = get_turf(L)
if(totaldamage)
L.adjustBruteLoss(-brutedamage)
L.adjustFireLoss(-burndamage)
L.adjustToxLoss(totaldamage * 0.5)
var/healseverity = max(round(totaldamage*0.05, 1), 1) //shows the general severity of the damage you just healed, 1 glow per 20
for(var/i in 1 to healseverity)
PoolOrNew(/obj/effect/overlay/temp/heal, list(targetturf, "#1E8CE1"))
clockwork_say(ranged_ability_user, text2ratvar("Mend wounded flesh!"))
add_logs(ranged_ability_user, L, "healed with Sentinel's Compromise")
else
clockwork_say(ranged_ability_user, text2ratvar("Purge foul darkness!"))
add_logs(ranged_ability_user, L, "purged of holy water with Sentinel's Compromise")
ranged_ability_user << "<span class='brass'>You bathe [L == ranged_ability_user ? "yourself":"[L]"] in Inath-neq's power!</span>"
L.visible_message("<span class='warning'>A blue light washes over [L], mending [L.p_their()] bruises and burns!</span>", \
"<span class='heavy_brass'>You feel Inath-neq's power healing your wounds, but a deep nausea overcomes you!</span>")
playsound(targetturf, 'sound/magic/Staff_Healing.ogg', 50, 1)
if(L.reagents && L.reagents.has_reagent("holywater"))
L.reagents.remove_reagent("holywater", 1000)
L << "<span class='heavy_brass'>Ratvar's light flares, banishing the darkness. Your devotion remains intact!</span>"
remove_ranged_ability()
return TRUE
//For the cyborg Linked Vanguard scripture, grants you and a nearby ally Vanguard
/obj/effect/proc_holder/slab/vanguard
ranged_mousepointer = 'icons/effects/vanguard_target.dmi'
/obj/effect/proc_holder/slab/vanguard/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return TRUE
var/turf/T = ranged_ability_user.loc
if(!isturf(T))
return TRUE
if(isliving(target) && (target in view(7, get_turf(ranged_ability_user))))
var/mob/living/L = target
if(!is_servant_of_ratvar(L))
ranged_ability_user << "<span class='inathneq'>\"[L] does not yet serve Ratvar.\"</span>"
return TRUE
if(L.stat == DEAD)
ranged_ability_user << "<span class='inathneq'>\"[L.p_they(TRUE)] [L.p_are()] dead. [text2ratvar("Oh, child. To have your life cut short...")]\"</span>"
return TRUE
if(islist(L.stun_absorption) && L.stun_absorption["vanguard"] && L.stun_absorption["vanguard"]["end_time"] > world.time)
ranged_ability_user << "<span class='inathneq'>\"[L.p_they(TRUE)] [L.p_are()] already shielded by a Vanguard.\"</span>"
return TRUE
if(L == ranged_ability_user)
for(var/mob/living/LT in spiral_range(7, T))
if(LT.stat == DEAD || !is_servant_of_ratvar(LT) || LT == ranged_ability_user || !(LT in view(7, get_turf(ranged_ability_user))) || \
(islist(LT.stun_absorption) && LT.stun_absorption["vanguard"] && LT.stun_absorption["vanguard"]["end_time"] > world.time))
continue
L = LT
break
L.apply_status_effect(STATUS_EFFECT_VANGUARD)
ranged_ability_user.apply_status_effect(STATUS_EFFECT_VANGUARD)
clockwork_say(ranged_ability_user, text2ratvar("Shield us from darkness!"))
remove_ranged_ability()
return TRUE
//For the cyborg Judicial Marker scripture, places a judicial marker
/obj/effect/proc_holder/slab/judicial
ranged_mousepointer = 'icons/effects/visor_reticule.dmi'
/obj/effect/proc_holder/slab/judicial/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return TRUE
var/turf/T = ranged_ability_user.loc
if(!isturf(T))
return TRUE
if(target in view(7, get_turf(ranged_ability_user)))
clockwork_say(ranged_ability_user, text2ratvar("Kneel, heathens!"))
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user]'s eyes fire a stream of energy at [target], creating a strange mark!</span>", \
"<span class='heavy_brass'>You direct the judicial force to [target].</span>")
var/turf/targetturf = get_turf(target)
new/obj/effect/clockwork/judicial_marker(targetturf, ranged_ability_user)
add_logs(ranged_ability_user, targetturf, "created a judicial marker")
remove_ranged_ability()
return TRUE
@@ -0,0 +1,24 @@
//The base clockwork item. Can have an alternate desc and will show up in the list of clockwork objects.
/obj/item/clockwork
name = "meme blaster"
desc = "What the fuck is this? It looks kinda like a frog."
resistance_flags = FIRE_PROOF | ACID_PROOF
var/clockwork_desc = "A fabled artifact from beyond the stars. Contains concentrated meme essence." //Shown to clockwork cultists instead of the normal description
icon = 'icons/obj/clockwork_objects.dmi'
icon_state = "rare_pepe"
w_class = WEIGHT_CLASS_SMALL
/obj/item/clockwork/New()
..()
ratvar_act()
all_clockwork_objects += src
/obj/item/clockwork/Destroy()
all_clockwork_objects -= src
return ..()
/obj/item/clockwork/examine(mob/user)
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
desc = clockwork_desc
..()
desc = initial(desc)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,200 @@
//Components: Used in scripture.
/obj/item/clockwork/component
name = "meme component"
desc = "A piece of a famous meme."
clockwork_desc = null
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/component_id //What the component is identified as
var/cultist_message = "You are not worthy of this meme." //Showed to Nar-Sian cultists if they pick up the component in addition to chaplains
var/list/servant_of_ratvar_messages = list("ayy" = FALSE, "lmao" = TRUE) //Fluff, shown to servants of Ratvar on a low chance, if associated value is TRUE, will automatically apply ratvarian
var/message_span = "heavy_brass"
/obj/item/clockwork/component/pickup(mob/living/user)
..()
if(iscultist(user) || (user.mind && user.mind.isholy))
user << "<span class='[message_span]'>[cultist_message]</span>"
if(user.mind && user.mind.isholy)
user << "<span class='boldannounce'>The power of your faith melts away the [src]!</span>"
var/obj/item/weapon/ore/slag/wrath = new /obj/item/weapon/ore/slag
user.unEquip(src)
user.put_in_active_hand(wrath)
qdel(src)
if(is_servant_of_ratvar(user) && prob(20))
var/pickedmessage = pick(servant_of_ratvar_messages)
user << "<span class='[message_span]'>[servant_of_ratvar_messages[pickedmessage] ? "[text2ratvar(pickedmessage)]" : pickedmessage]</span>"
/obj/item/clockwork/component/examine(mob/user)
..()
if(is_servant_of_ratvar(user))
user << "<span class='[message_span]'>You should put this in a slab or cache immediately.</span>"
/obj/item/clockwork/component/belligerent_eye
name = "belligerent eye"
desc = "A brass construct with a rotating red center. It's as though it's looking for something to hurt."
icon_state = "belligerent_eye"
component_id = BELLIGERENT_EYE
cultist_message = "The eye gives you an intensely hateful glare."
servant_of_ratvar_messages = list("\"...\"" = FALSE, "For a moment, your mind is flooded with extremely violent thoughts." = FALSE, "\"...Die.\"" = TRUE)
message_span = "neovgre"
/obj/item/clockwork/component/belligerent_eye/blind_eye
name = "blind eye"
desc = "A heavy brass eye, its red iris fallen dark."
clockwork_desc = "A smashed ocular warden covered in dents. <b>Serviceable as a substitute for a belligerent eye.</b>"
icon_state = "blind_eye"
cultist_message = "The eye flickers at you with intense hate before falling dark."
servant_of_ratvar_messages = list("The eye flickers before falling dark." = FALSE, "You feel watched." = FALSE, "\"...\"" = FALSE)
w_class = WEIGHT_CLASS_NORMAL
/obj/item/clockwork/component/vanguard_cogwheel
name = "vanguard cogwheel"
desc = "A sturdy brass cog with a faintly glowing blue gem in its center."
icon_state = "vanguard_cogwheel"
component_id = VANGUARD_COGWHEEL
cultist_message = "\"Pray to your god that we never meet.\""
servant_of_ratvar_messages = list("\"Be safe, child.\"" = FALSE, "You feel unexplainably comforted." = FALSE, "\"Never forget: Pain is temporary. What you do for the Justiciar is eternal.\"" = FALSE)
message_span = "inathneq"
/obj/item/clockwork/component/vanguard_cogwheel/pinion_lock
name = "pinion lock"
desc = "A dented and scratched gear. It's very heavy."
clockwork_desc = "A broken gear lock for pinion airlocks. <b>Serviceable as a substitute for a vanguard cogwheel.</b>"
icon_state = "pinion_lock"
cultist_message = "The gear grows warm in your hands."
servant_of_ratvar_messages = list("The lock isn't getting any lighter." = FALSE, "\"Damaged gears are better than broken bodies.\"" = TRUE, \
"\"It's a shame it can't be reused.\"" = TRUE)
w_class = WEIGHT_CLASS_NORMAL
/obj/item/clockwork/component/geis_capacitor
name = "geis capacitor"
desc = "A curiously cold brass doodad. It seems as though it really doesn't appreciate being held."
icon_state = "geis_capacitor"
component_id = GEIS_CAPACITOR
cultist_message = "\"Try not to lose your mind - I'll need it. Heh heh...\""
servant_of_ratvar_messages = list("\"Disgusting.\"" = FALSE, "\"Well, aren't you an inquisitive fellow?\"" = FALSE, "A foul presence pervades your mind, then vanishes." = FALSE, \
"\"The fact that Ratvar has to depend on simpletons like you is appalling.\"" = FALSE)
message_span = "sevtug"
/obj/item/clockwork/component/geis_capacitor/antennae
name = "mania motor antennae"
desc = "A pair of dented and bent antennae. They constantly emit a static hiss."
clockwork_desc = "The antennae from a mania motor. <b>Serviceable as a substitute for a geis capacitor.</b>"
icon_state = "mania_motor_antennae"
cultist_message = "Your head is filled with a burst of static."
servant_of_ratvar_messages = list("\"Who broke this.\"" = TRUE, "\"Did you break these off YOURSELF?\"" = TRUE, "\"Why did we give this to such simpletons, anyway?\"" = TRUE, \
"\"At least we can use these for something - unlike you.\"" = TRUE)
//Replicant Alloy. Used for fuel and construction, and not merely scripture.
/obj/item/clockwork/component/replicant_alloy
name = "replicant alloy"
desc = "A seemingly strong but very malleable chunk of metal. It seems as though it wants to be molded into something greater."
icon_state = "replicant_alloy"
component_id = REPLICANT_ALLOY
cultist_message = "The alloy takes on the appearance of a screaming face for a moment."
servant_of_ratvar_messages = list("\"There's always something to be done. Get to it.\"" = FALSE, "\"Idle hands are worse than broken ones. Get to work.\"" = FALSE, \
"A detailed image of Ratvar appears in the alloy for a moment." = FALSE)
message_span = "nezbere"
/obj/item/clockwork/component/replicant_alloy/examine(mob/user)
..()
if(is_servant_of_ratvar(user))
user << "<span class='alloy'>Can be used to fuel Clockwork Proselytizers and Mending Motors, or shaped into brass sheets.</span>"
/obj/item/clockwork/component/replicant_alloy/attack_self(mob/user)
if(is_servant_of_ratvar(user))
var/obj/item/stack/tile/brass/B = new /obj/item/stack/tile/brass(get_turf(src), 10)
user.unEquip(src, TRUE)
user.put_in_hands(B)
user << "<span class='brass'>You shape the alloy into some brass sheets.</span>"
qdel(src)
/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment
name = "smashed anima fragment"
desc = "Shattered chunks of metal. Damaged beyond repair and completely unusable."
clockwork_desc = "The sad remains of an anima fragment. <b>Serviceable as a substitute for replicant alloy.</b>"
icon_state = "smashed_anime_fragment"
cultist_message = "The shards vibrate in your hands for a moment."
servant_of_ratvar_messages = list("\"...still fight...\"" = FALSE, "\"...where am I...?\"" = FALSE, "\"...put me... slab...\"" = FALSE)
message_span = "heavy_brass"
w_class = WEIGHT_CLASS_NORMAL
/obj/item/clockwork/component/replicant_alloy/fallen_armor
name = "fallen armor"
desc = "Lifeless chunks of armor. They're designed in a strange way and won't fit on you."
clockwork_desc = "The armor from a former clockwork marauder. <b>Serviceable as a substitute for replicant alloy.</b>"
icon_state = "fallen_armor"
cultist_message = "Red flame sputters from the mask's eye before winking out."
servant_of_ratvar_messages = list("A piece of armor hovers away from the others for a moment." = FALSE, "Red flame appears in the cuirass before sputtering out." = FALSE)
message_span = "heavy_brass"
w_class = WEIGHT_CLASS_NORMAL
/obj/item/clockwork/component/hierophant_ansible
name = "hierophant ansible"
desc = "Some sort of transmitter? It seems as though it's trying to say something."
icon_state = "hierophant_ansible"
component_id = HIEROPHANT_ANSIBLE
cultist_message = "\"Gur obff fnlf vg'f abg ntnvafg gur ehyrf gb-xvyy lbh.\""
servant_of_ratvar_messages = list("\"Exile is such a bore. There's nothing I can hunt in here.\"" = TRUE, "\"What's keeping you? I want to go kill something.\"" = TRUE, \
"\"HEHEHEHEHEHEH!\"" = FALSE, "\"If I killed you fast enough, do you think the boss would notice?\"" = TRUE)
message_span = "nzcrentr"
/obj/item/clockwork/component/hierophant_ansible/obelisk
name = "obelisk prism"
desc = "A prism that occasionally glows brightly. It seems not-quite there."
clockwork_desc = "The prism from a clockwork obelisk. <b>Serviceable as a substitute for a hierophant ansible.</b>"
cultist_message = "The prism flickers wildly in your hands before resuming its normal glow."
servant_of_ratvar_messages = list("You hear the distinctive sound of the Hierophant Network for a moment." = FALSE, "\"Hieroph'ant Br'o'adcas't fail'ure.\"" = TRUE, \
"The obelisk flickers wildly, as if trying to open a gateway." = FALSE, "\"Spa'tial Ga'tewa'y fai'lure.\"" = TRUE)
icon_state = "obelisk_prism"
w_class = WEIGHT_CLASS_NORMAL
//Shards of Alloy, suitable only for proselytization.
/obj/item/clockwork/alloy_shards
name = "replicant alloy shards"
desc = "Broken shards of some oddly malleable metal. They occasionally move and seem to glow."
clockwork_desc = "Broken shards of replicant alloy. Could be proselytized for liquified replicant alloy."
icon_state = "alloy_shards"
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/randomsinglesprite = FALSE
var/randomspritemax = 2
/obj/item/clockwork/alloy_shards/New()
..()
if(randomsinglesprite)
replace_name_desc()
icon_state = "[icon_state][rand(1, randomspritemax)]"
pixel_x = rand(-9, 9)
pixel_y = rand(-9, 9)
/obj/item/clockwork/alloy_shards/proc/replace_name_desc()
name = "replicant alloy shard"
desc = "A broken shard of some oddly malleable metal. It occasionally moves and seems to glow."
clockwork_desc = "A broken shard of replicant alloy. Could be proselytized for liquified replicant alloy."
/obj/item/clockwork/alloy_shards/large
randomsinglesprite = TRUE
icon_state = "shard_large"
/obj/item/clockwork/alloy_shards/medium
randomsinglesprite = TRUE
icon_state = "shard_medium"
/obj/item/clockwork/alloy_shards/medium/gear_bit
randomspritemax = 4
icon_state = "gear_bit"
/obj/item/clockwork/alloy_shards/medium/gear_bit/replace_name_desc()
name = "gear bit"
desc = "A broken chunk of a gear. You want it."
clockwork_desc = "A broken chunk of a gear. Could be proselytized for liquified replicant alloy."
/obj/item/clockwork/alloy_shards/medium/gear_bit/large //gives more alloy
/obj/item/clockwork/alloy_shards/medium/gear_bit/large/replace_name_desc()
..()
name = "complex gear bit"
/obj/item/clockwork/alloy_shards/small
randomsinglesprite = TRUE
randomspritemax = 3
icon_state = "shard_small"
@@ -0,0 +1,216 @@
//Clockwork armor: High melee protection but weak to lasers
/obj/item/clothing/head/helmet/clockwork
name = "clockwork helmet"
desc = "A heavy helmet made of brass."
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "clockwork_helmet"
w_class = WEIGHT_CLASS_NORMAL
resistance_flags = FIRE_PROOF | ACID_PROOF
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
/obj/item/clothing/head/helmet/clockwork/New()
..()
ratvar_act()
all_clockwork_objects += src
/obj/item/clothing/head/helmet/clockwork/Destroy()
all_clockwork_objects -= src
return ..()
/obj/item/clothing/head/helmet/clockwork/ratvar_act()
if(ratvar_awakens)
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
flags |= STOPSPRESSUREDMAGE
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
flags &= STOPSPRESSUREDMAGE
max_heat_protection_temperature = initial(max_heat_protection_temperature)
min_cold_protection_temperature = initial(min_cold_protection_temperature)
/obj/item/clothing/head/helmet/clockwork/equipped(mob/living/user, slot)
..()
if(slot == slot_head && !is_servant_of_ratvar(user))
if(!iscultist(user))
user << "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>"
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their head!</span>", "<span class='warning'>The helmet flickers off your head, leaving only nausea!</span>")
if(iscarbon(user))
var/mob/living/carbon/C = user
C.vomit(20, 1, 1, 0, 1)
else
user << "<span class='heavy_brass'>\"Do you have a hole in your head? You're about to.\"</span>"
user << "<span class='userdanger'>The helmet tries to drive a spike through your head as you scramble to remove it!</span>"
user.emote("scream")
user.apply_damage(30, BRUTE, "head")
user.adjustBrainLoss(30)
addtimer(user, "unEquip", 1, TIMER_NORMAL, src, 1) //equipped happens before putting stuff on(but not before picking items up). thus, we need to wait for it to be on before forcing it off.
/obj/item/clothing/head/helmet/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
if(equipper && !is_servant_of_ratvar(equipper))
return 0
return ..()
/obj/item/clothing/suit/armor/clockwork
name = "clockwork cuirass"
desc = "A bulky cuirass made of brass."
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "clockwork_cuirass"
w_class = WEIGHT_CLASS_BULKY
body_parts_covered = CHEST|GROIN|LEGS
cold_protection = CHEST|GROIN|LEGS
heat_protection = CHEST|GROIN|LEGS
resistance_flags = FIRE_PROOF | ACID_PROOF
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/device/mmi/posibrain/soul_vessel)
/obj/item/clothing/suit/armor/clockwork/New()
..()
ratvar_act()
all_clockwork_objects += src
/obj/item/clothing/suit/armor/clockwork/Destroy()
all_clockwork_objects -= src
return ..()
/obj/item/clothing/suit/armor/clockwork/ratvar_act()
if(ratvar_awakens)
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
flags |= STOPSPRESSUREDMAGE
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
flags &= STOPSPRESSUREDMAGE
max_heat_protection_temperature = initial(max_heat_protection_temperature)
min_cold_protection_temperature = initial(min_cold_protection_temperature)
/obj/item/clothing/suit/armor/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
if(equipper && !is_servant_of_ratvar(equipper))
return 0
return ..()
/obj/item/clothing/suit/armor/clockwork/equipped(mob/living/user, slot)
..()
if(slot == slot_wear_suit && !is_servant_of_ratvar(user))
if(!iscultist(user))
user << "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>"
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their body!</span>", "<span class='warning'>The curiass flickers off your body, leaving only nausea!</span>")
if(iscarbon(user))
var/mob/living/carbon/C = user
C.vomit(20, 1, 1, 0, 1)
else
user << "<span class='heavy_brass'>\"I think this armor is too hot for you to handle.\"</span>"
user << "<span class='userdanger'>The curiass emits a burst of flame as you scramble to get it off!</span>"
user.emote("scream")
user.apply_damage(15, BURN, "chest")
user.adjust_fire_stacks(2)
user.IgniteMob()
addtimer(user, "unEquip", 1, TIMER_NORMAL, src, 1)
/obj/item/clothing/gloves/clockwork
name = "clockwork gauntlets"
desc = "Heavy, shock-resistant gauntlets with brass reinforcement."
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "clockwork_gauntlets"
item_state = "clockwork_gauntlets"
item_color = null //So they don't wash.
strip_delay = 50
put_on_delay = 30
body_parts_covered = ARMS
cold_protection = ARMS
heat_protection = ARMS
siemens_coefficient = 0
permeability_coefficient = 0.05
resistance_flags = FIRE_PROOF | ACID_PROOF
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
/obj/item/clothing/gloves/clockwork/New()
..()
ratvar_act()
all_clockwork_objects += src
/obj/item/clothing/gloves/clockwork/Destroy()
all_clockwork_objects -= src
return ..()
/obj/item/clothing/gloves/clockwork/ratvar_act()
if(ratvar_awakens)
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
flags |= STOPSPRESSUREDMAGE
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
else
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
flags &= STOPSPRESSUREDMAGE
max_heat_protection_temperature = initial(max_heat_protection_temperature)
min_cold_protection_temperature = initial(min_cold_protection_temperature)
/obj/item/clothing/gloves/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
if(equipper && !is_servant_of_ratvar(equipper))
return 0
return ..()
/obj/item/clothing/gloves/clockwork/equipped(mob/living/user, slot)
..()
if(slot == slot_gloves && !is_servant_of_ratvar(user))
if(!iscultist(user))
user << "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>"
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their arms!</span>", "<span class='warning'>The gauntlets flicker off your arms, leaving only nausea!</span>")
if(iscarbon(user))
var/mob/living/carbon/C = user
C.vomit(10, 1, 1, 0, 1)
else
user << "<span class='heavy_brass'>\"Did you like having arms?\"</span>"
user << "<span class='userdanger'>The gauntlets suddenly squeeze tight, crushing your arms before you manage to get them off!</span>"
user.emote("scream")
user.apply_damage(7, BRUTE, "l_arm")
user.apply_damage(7, BRUTE, "r_arm")
addtimer(user, "unEquip", 1, TIMER_NORMAL, src, 1)
/obj/item/clothing/shoes/clockwork
name = "clockwork treads"
desc = "Industrial boots made of brass. They're very heavy."
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "clockwork_treads"
w_class = WEIGHT_CLASS_NORMAL
strip_delay = 50
put_on_delay = 30
resistance_flags = FIRE_PROOF | ACID_PROOF
/obj/item/clothing/shoes/clockwork/New()
..()
ratvar_act()
all_clockwork_objects += src
/obj/item/clothing/shoes/clockwork/Destroy()
all_clockwork_objects -= src
return ..()
/obj/item/clothing/shoes/clockwork/ratvar_act()
if(ratvar_awakens)
flags |= NOSLIP
else
flags &= NOSLIP
/obj/item/clothing/shoes/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
if(equipper && !is_servant_of_ratvar(equipper))
return 0
return ..()
/obj/item/clothing/shoes/clockwork/equipped(mob/living/user, slot)
..()
if(slot == slot_shoes && !is_servant_of_ratvar(user))
if(!iscultist(user))
user << "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>"
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their feet!</span>", "<span class='warning'>The treads flicker off your feet, leaving only nausea!</span>")
if(iscarbon(user))
var/mob/living/carbon/C = user
C.vomit(10, 1, 1, 0, 1)
else
user << "<span class='heavy_brass'>\"Let's see if you can dance with these.\"</span>"
user << "<span class='userdanger'>The treads turn searing hot as you scramble to get them off!</span>"
user.emote("scream")
user.apply_damage(7, BURN, "l_leg")
user.apply_damage(7, BURN, "r_leg")
addtimer(user, "unEquip", 1, TIMER_NORMAL, src, 1)
@@ -0,0 +1,217 @@
//Clockwork proselytizer (yes, that's a real word): Converts applicable objects to Ratvarian variants.
/obj/item/clockwork/clockwork_proselytizer
name = "clockwork proselytizer"
desc = "An odd, L-shaped device that hums with energy."
clockwork_desc = "A device that allows the replacing of mundane objects with Ratvarian variants. It requires liquified Replicant Alloy to function."
icon_state = "clockwork_proselytizer"
w_class = WEIGHT_CLASS_NORMAL
force = 5
flags = NOBLUDGEON
var/stored_alloy = 0 //Requires this to function; each chunk of replicant alloy provides REPLICANT_ALLOY_UNIT
var/max_alloy = REPLICANT_ALLOY_UNIT * 10
var/uses_alloy = TRUE
var/metal_to_alloy = FALSE
var/reform_alloy = TRUE
var/repairing = null //what we're currently repairing, if anything
var/refueling = FALSE //if we're currently refueling from a cache
var/speed_multiplier = 1 //how fast this proselytizer works
/obj/item/clockwork/clockwork_proselytizer/preloaded
stored_alloy = REPLICANT_WALL_MINUS_FLOOR+REPLICANT_WALL_TOTAL
/obj/item/clockwork/clockwork_proselytizer/scarab
name = "scarab proselytizer"
clockwork_desc = "A cogscarab's internal proselytizer. It can only be successfully used by a cogscarab and requires liquified Replicant Alloy to function."
metal_to_alloy = TRUE
item_state = "nothing"
w_class = WEIGHT_CLASS_TINY
speed_multiplier = 0.5
var/debug = FALSE
/obj/item/clockwork/clockwork_proselytizer/scarab/proselytize(atom/target, mob/living/user)
if(!debug && !isdrone(user))
return 0
return ..()
/obj/item/clockwork/clockwork_proselytizer/scarab/debug
clockwork_desc = "A cogscarab's internal proselytizer. It can convert nearly any object into a Ratvarian variant."
uses_alloy = FALSE
debug = TRUE
/obj/item/clockwork/clockwork_proselytizer/cyborg
name = "cyborg proselytizer"
clockwork_desc = "A cyborg's internal proselytizer. It is capable of using the cyborg's power if it lacks liquified replicant alloy."
metal_to_alloy = TRUE
reform_alloy = FALSE
/obj/item/clockwork/clockwork_proselytizer/cyborg/examine(mob/living/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='alloy'>It will use cell charge at a rate of <b>[CLOCKCULT_ALLOY_TO_POWER_MULTIPLIER]</b> charge to <b>1</b> alloy if it has insufficient alloy.</span>"
user << "<span class='alloy'><b>[get_power_alloy()]</b> is usable in this manner.</span>"
/obj/item/clockwork/clockwork_proselytizer/cyborg/get_power_alloy() //returns alloy plus the alloy we have from power, where we need such
var/mob/living/silicon/robot/R = loc
var/alloy_power = 0
var/current_charge = 0
if(istype(R) && R.cell)
current_charge = R.cell.charge
while(current_charge > CLOCKCULT_ALLOY_TO_POWER_MULTIPLIER)
current_charge -= CLOCKCULT_ALLOY_TO_POWER_MULTIPLIER
alloy_power++
return ..() + alloy_power
/obj/item/clockwork/clockwork_proselytizer/cyborg/can_use_alloy(amount)
if(amount != RATVAR_ALLOY_CHECK)
var/mob/living/silicon/robot/R = loc
var/current_charge = 0
if(istype(R) && R.cell)
current_charge = R.cell.charge
while(amount > 0 && stored_alloy - amount < 0) //amount is greater than 0 and stored alloy minus the amount is still less than 0
current_charge -= CLOCKCULT_ALLOY_TO_POWER_MULTIPLIER
amount--
if(current_charge < 0)
return FALSE
. = ..()
/obj/item/clockwork/clockwork_proselytizer/cyborg/modify_stored_alloy(amount)
var/mob/living/silicon/robot/R = loc
while(istype(R) && R.cell && amount < 0 && stored_alloy + amount < 0) //amount is less than 0 and stored alloy plus the amount is less than 0
R.cell.use(CLOCKCULT_ALLOY_TO_POWER_MULTIPLIER)
amount++
. = ..()
/obj/item/clockwork/clockwork_proselytizer/examine(mob/living/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='brass'>Can be used to convert walls, floors, windows, airlocks, and a variety of other objects to clockwork variants.</span>"
user << "<span class='brass'>Can also form some objects into Brass sheets, as well as reform Clockwork Walls into Clockwork Floors, and vice versa.</span>"
if(uses_alloy)
if(metal_to_alloy)
user << "<span class='alloy'>It can convert rods, metal, plasteel, and brass to liquified replicant alloy at rates of <b>1:1</b>, <b>1:2</b>, <b>1:5</b>, and <b>1:10</b>, respectively.</span>"
user << "<span class='alloy'>It has <b>[stored_alloy]/[max_alloy]</b> units of liquified alloy stored.</span>"
user << "<span class='alloy'>Use it on a Tinkerer's Cache, strike it with Replicant Alloy, or attack Replicant Alloy with it to add additional liquified alloy.</span>"
if(reform_alloy)
user << "<span class='alloy'>Use it in-hand to remove stored liquified alloy.</span>"
/obj/item/clockwork/clockwork_proselytizer/attack_self(mob/living/user)
if(is_servant_of_ratvar(user) && uses_alloy && reform_alloy)
if(!can_use_alloy(REPLICANT_ALLOY_UNIT))
user << "<span class='warning'>[src] [stored_alloy ? "lacks enough":"contains no"] alloy to reform[stored_alloy ? "":" any"] into solidified alloy!</span>"
return
modify_stored_alloy(-REPLICANT_ALLOY_UNIT)
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
new/obj/item/clockwork/component/replicant_alloy(user.loc)
user << "<span class='brass'>You force [stored_alloy ? "some":"all"] of the alloy in [src]'s compartments to reform and solidify. \
It now contains <b>[stored_alloy]/[max_alloy]</b> units of liquified alloy.</span>"
/obj/item/clockwork/clockwork_proselytizer/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/clockwork/component/replicant_alloy) && is_servant_of_ratvar(user) && uses_alloy)
if(!can_use_alloy(-REPLICANT_ALLOY_UNIT))
user << "<span class='warning'>[src]'s replicant alloy compartments are full!</span>"
return 0
modify_stored_alloy(REPLICANT_ALLOY_UNIT)
playsound(user, 'sound/machines/click.ogg', 50, 1)
clockwork_say(user, text2ratvar("Transmute into fuel."), TRUE)
user << "<span class='brass'>You force [I] to liquify and pour it into [src]'s compartments. It now contains <b>[stored_alloy]/[max_alloy]</b> units of liquified alloy.</span>"
user.drop_item()
qdel(I)
return 1
else
return ..()
/obj/item/clockwork/clockwork_proselytizer/afterattack(atom/target, mob/living/user, proximity_flag, params)
if(!target || !user || !proximity_flag)
return 0
if(!is_servant_of_ratvar(user))
return ..()
proselytize(target, user)
/obj/item/clockwork/clockwork_proselytizer/proc/get_power_alloy()
return stored_alloy
/obj/item/clockwork/clockwork_proselytizer/proc/modify_stored_alloy(amount)
stored_alloy = Clamp(stored_alloy + amount, 0, max_alloy)
return TRUE
/obj/item/clockwork/clockwork_proselytizer/proc/can_use_alloy(amount)
if(amount == RATVAR_ALLOY_CHECK)
if(ratvar_awakens || !uses_alloy)
return TRUE
else
return FALSE
if(stored_alloy - amount < 0)
return FALSE
if(stored_alloy - amount > max_alloy)
return FALSE
return TRUE
/obj/item/clockwork/clockwork_proselytizer/proc/proselytize(atom/target, mob/living/user)
if(!target || !user)
return FALSE
if(repairing)
user << "<span class='warning'>You are currently repairing [repairing] with [src]!</span>"
return FALSE
if(refueling)
user << "<span class='warning'>You are currently refueling [src]!</span>"
return FALSE
var/list/proselytize_values = target.proselytize_vals(user, src) //relevant values for proselytizing stuff, given as an associated list
if(!islist(proselytize_values))
if(proselytize_values != TRUE) //if we get true, fail, but don't send a message for whatever reason
if(!isturf(target)) //otherwise, if we didn't get TRUE and the original target wasn't a turf, try to proselytize the turf
return proselytize(get_turf(target), user)
user << "<span class='warning'>[target] cannot be proselytized!</span>"
return FALSE
if(can_use_alloy(RATVAR_ALLOY_CHECK))
if(proselytize_values["alloy_cost"] < 0) //if it's less than 0, it's trying to refuel from whatever this is, and we don't need to refuel right now!
user << "<span class='warning'>[target] cannot be proselytized!</span>"
return FALSE
proselytize_values["alloy_cost"] = 0
var/turf/Y = get_turf(user)
if(!Y || (Y.z != ZLEVEL_STATION && Y.z != ZLEVEL_CENTCOM && Y.z != ZLEVEL_MINING && Y.z != ZLEVEL_LAVALAND))
proselytize_values["operation_time"] *= 2
if(proselytize_values["alloy_cost"] > 0)
proselytize_values["alloy_cost"] *= 2
if(!can_use_alloy(proselytize_values["alloy_cost"]))
if(stored_alloy - proselytize_values["alloy_cost"] < 0)
user << "<span class='warning'>You need <b>[proselytize_values["alloy_cost"]]</b> liquified alloy to proselytize [target]!</span>"
else if(stored_alloy - proselytize_values["alloy_cost"] > max_alloy)
user << "<span class='warning'>You have too much liquified alloy stored to proselytize [target]!</span>"
return FALSE
var/target_type = target.type
if(can_use_alloy(RATVAR_ALLOY_CHECK)) //Ratvar makes it faster
proselytize_values["operation_time"] *= 0.5
proselytize_values["operation_time"] *= speed_multiplier
playsound(target, 'sound/machines/click.ogg', 50, 1)
if(proselytize_values["operation_time"])
user.visible_message("<span class='warning'>[user]'s [name] begins tearing apart [target]!</span>", "<span class='brass'>You begin proselytizing [target]...</span>")
if(!do_after(user, proselytize_values["operation_time"], target = target))
return FALSE
user.visible_message("<span class='warning'>[user]'s [name] disgorges a chunk of metal and shapes it over what's left of [target]!</span>", \
"<span class='brass'>You proselytize [target].</span>")
else
user.visible_message("<span class='warning'>[user]'s [name] tears apart [target], covering it in metal!</span>", "<span class='brass'>You proselytize [target].</span>")
if(repairing || refueling || !can_use_alloy(proselytize_values["alloy_cost"]) || !target || target.type != target_type) //Check again to prevent bypassing via spamclick
return FALSE
playsound(target, 'sound/items/Deconstruct.ogg', 50, 1)
var/new_thing_type = proselytize_values["new_obj_type"]
if(isturf(target))
var/turf/T = target
T.ChangeTurf(new_thing_type)
else
if(proselytize_values["dir_in_new"])
new new_thing_type(get_turf(target), proselytize_values["spawn_dir"])
else
var/atom/A = new new_thing_type(get_turf(target))
A.setDir(proselytize_values["spawn_dir"])
if(!proselytize_values["no_target_deletion"])
qdel(target)
modify_stored_alloy(-proselytize_values["alloy_cost"])
return TRUE
@@ -0,0 +1,484 @@
/obj/item/clockwork/slab //Clockwork slab: The most important tool in Ratvar's arsenal. Allows scripture recital, tutorials, and generates components.
name = "clockwork slab"
desc = "A strange metal tablet. A clock in the center turns around and around."
clockwork_desc = "A link between the Celestial Derelict and the mortal plane. Contains limitless knowledge, fabricates components, and outputs a stream of information that only a trained eye can detect.\n\
Use the <span class='brass'>Hierophant Network</span> action button to communicate with other servants.\n\
Clockwork slabs will only make components if held or if inside an item held by a human, and when making a component will prevent all other slabs held from making components.\n\
Hitting a slab, a Servant with a slab, or a cache will <b>transfer</b> this slab's components into the target, the target's slab, or the global cache, respectively."
icon_state = "dread_ipad"
slot_flags = SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
var/list/stored_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0)
var/busy //If the slab is currently being used by something
var/production_time = 0
var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks
var/speed_multiplier = 1 //multiples how fast this slab recites scripture
var/nonhuman_usable = FALSE //if the slab can be used by nonhumans, defaults to off
var/produces_components = TRUE //if it produces components at all
var/selected_scripture = SCRIPTURE_DRIVER
var/recollecting = FALSE //if we're looking at fancy recollection
var/obj/effect/proc_holder/slab/slab_ability //the slab's current bound ability, for certain scripture
var/list/quickbound = list(/datum/clockwork_scripture/ranged_ability/geis_prep, /datum/clockwork_scripture/create_object/replicant, \
/datum/clockwork_scripture/create_object/tinkerers_cache) //quickbound scripture, accessed by index
actions_types = list(/datum/action/item_action/clock/hierophant)
/obj/item/clockwork/slab/starter
stored_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
/obj/item/clockwork/slab/internal //an internal motor for mobs running scripture
name = "scripture motor"
quickbound = list()
no_cost = TRUE
produces_components = FALSE
/obj/item/clockwork/slab/scarab
nonhuman_usable = TRUE
/obj/item/clockwork/slab/debug
speed_multiplier = 0
no_cost = TRUE
nonhuman_usable = TRUE
/obj/item/clockwork/slab/debug/attack_hand(mob/living/user)
..()
if(!is_servant_of_ratvar(user))
add_servant_of_ratvar(user)
/obj/item/clockwork/slab/cyborg
clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture.\n\
Hitting a slab, a Servant with a slab, or a cache will <b>transfer</b> this slab's components into the target, the target's slab, or the global cache, respectively."
nonhuman_usable = TRUE
quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/sentinels_compromise, \
/datum/clockwork_scripture/create_object/sigil_of_transgression, /datum/clockwork_scripture/create_object/vitality_matrix)
actions_types = list()
/obj/item/clockwork/slab/cyborg/engineer
quickbound = list(/datum/clockwork_scripture/create_object/tinkerers_cache, /datum/clockwork_scripture/create_object/sigil_of_transgression, \
/datum/clockwork_scripture/create_object/ocular_warden, /datum/clockwork_scripture/create_object/tinkerers_daemon)
/obj/item/clockwork/slab/cyborg/medical
quickbound = list(/datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/ranged_ability/sentinels_compromise, /datum/clockwork_scripture/fellowship_armory, \
/datum/clockwork_scripture/create_object/mending_motor)
/obj/item/clockwork/slab/cyborg/security
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/create_object/ocular_warden)
/obj/item/clockwork/slab/cyborg/peacekeeper
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/channeled/taunting_tirade, \
/datum/clockwork_scripture/create_object/mania_motor)
/obj/item/clockwork/slab/cyborg/janitor
quickbound = list(/datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/channeled/volt_void, /datum/clockwork_scripture/create_object/sigil_of_transmission, \
/datum/clockwork_scripture/create_object/interdiction_lens)
/obj/item/clockwork/slab/cyborg/service
quickbound = list(/datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/fellowship_armory, /datum/clockwork_scripture/spatial_gateway, \
/datum/clockwork_scripture/create_object/clockwork_obelisk)
/obj/item/clockwork/slab/cyborg/miner
quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \
/datum/clockwork_scripture/create_object/sigil_of_transgression, /datum/clockwork_scripture/spatial_gateway)
/obj/item/clockwork/slab/cyborg/access_display(mob/living/user)
user << "<span class='warning'>Use the action buttons to recite your limited set of scripture!</span>"
/obj/item/clockwork/slab/New()
..()
update_quickbind()
START_PROCESSING(SSobj, src)
production_time = world.time + SLAB_PRODUCTION_TIME
/obj/item/clockwork/slab/Destroy()
STOP_PROCESSING(SSobj, src)
if(slab_ability && slab_ability.ranged_ability_user)
slab_ability.remove_ranged_ability()
return ..()
/obj/item/clockwork/slab/ratvar_act()
if(ratvar_awakens)
nonhuman_usable = TRUE
else
nonhuman_usable = initial(nonhuman_usable)
/obj/item/clockwork/slab/dropped(mob/user)
. = ..()
addtimer(src, "check_on_mob", 1, TIMER_NORMAL, user) //dropped is called before the item is out of the slot, so we need to check slightly later
/obj/item/clockwork/slab/proc/check_on_mob(mob/user)
if(user && !(src in user.held_items) && slab_ability && slab_ability.ranged_ability_user) //if we happen to check and we AREN'T in user's hands, remove whatever ability we have
slab_ability.remove_ranged_ability()
//Component Generation
/obj/item/clockwork/slab/process()
if(!produces_components)
STOP_PROCESSING(SSobj, src)
return
if(production_time > world.time)
return
var/servants = 0
var/production_slowdown = 0
for(var/mob/living/M in living_mob_list)
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
servants++
if(servants > SCRIPT_SERVANT_REQ)
servants -= SCRIPT_SERVANT_REQ
production_slowdown = min(SLAB_SERVANT_SLOWDOWN * servants, SLAB_SLOWDOWN_MAXIMUM) //SLAB_SERVANT_SLOWDOWN additional seconds for each servant above 5, up to SLAB_SLOWDOWN_MAXIMUM
production_time = world.time + SLAB_PRODUCTION_TIME + production_slowdown
var/mob/living/L
L = get_atom_on_turf(src, /mob/living)
if(istype(L) && is_servant_of_ratvar(L) && (nonhuman_usable || ishuman(L)))
var/component_to_generate = get_weighted_component_id(src) //more likely to generate components that we have less of
stored_components[component_to_generate]++
update_slab_info(src)
for(var/obj/item/clockwork/slab/S in L.GetAllContents()) //prevent slab abuse today
if(L == src)
continue
S.production_time = production_time + 50 //set it to our next production plus five seconds, so that if you hold the same slabs, the same one will always generate
L << "<span class='warning'>Your slab cl[pick("ank", "ink", "unk", "ang")]s as it produces a new component.</span>"
/obj/item/clockwork/slab/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
if(LAZYLEN(quickbound))
for(var/i in 1 to quickbound.len)
if(!quickbound[i])
continue
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
user << "<b>Quickbind</b> button: <span class='[get_component_span(initial(quickbind_slot.primary_component))]'>[initial(quickbind_slot.name)]</span>."
if(clockwork_caches)
user << "<b>Stored components (with global cache):</b>"
for(var/i in stored_components)
user << "<span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[stored_components[i]]</b> \
(<b>[stored_components[i] + clockwork_component_cache[i]]</b>)</span>"
else
user << "<b>Stored components:</b>"
for(var/i in stored_components)
user << "<span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[stored_components[i]]</b></span>"
//Component Transferal
/obj/item/clockwork/slab/attack(mob/living/target, mob/living/carbon/human/user)
if(is_servant_of_ratvar(user) && is_servant_of_ratvar(target))
var/obj/item/clockwork/slab/targetslab
var/highest_component_amount = 0
for(var/obj/item/clockwork/slab/S in target.GetAllContents())
if(!istype(S, /obj/item/clockwork/slab/internal))
var/totalcomponents = 0
for(var/i in S.stored_components)
totalcomponents += S.stored_components[i]
if(!targetslab || totalcomponents > highest_component_amount)
highest_component_amount = totalcomponents
targetslab = S
if(targetslab)
if(targetslab == src)
user << "<span class='heavy_brass'>\"You can't transfer components into your own slab, idiot.\"</span>"
else
for(var/i in stored_components)
targetslab.stored_components[i] += stored_components[i]
stored_components[i] = 0
update_slab_info(targetslab)
update_slab_info(src)
user.visible_message("<span class='notice'>[user] empties [src] into [target]'s [targetslab.name].</span>", \
"<span class='notice'>You transfer your slab's components into [target]'s [targetslab.name].</span>")
else
user << "<span class='warning'>[target] has no slabs to transfer components to.</span>"
else
return ..()
/obj/item/clockwork/slab/attackby(obj/item/I, mob/user, params)
var/ratvarian = is_servant_of_ratvar(user)
if(istype(I, /obj/item/clockwork/component) && ratvarian)
var/obj/item/clockwork/component/C = I
if(!C.component_id)
return 0
user.visible_message("<span class='notice'>[user] inserts [C] into [src].</span>", "<span class='notice'>You insert [C] into [src]\
[clockwork_caches ? ", where it is added to the global cache":""].</span>")
if(clockwork_caches)
clockwork_component_cache[C.component_id]++
update_slab_info()
else
stored_components[C.component_id]++
update_slab_info(src)
user.drop_item()
qdel(C)
return 1
else if(istype(I, /obj/item/clockwork/slab) && ratvarian)
var/obj/item/clockwork/slab/S = I
for(var/i in stored_components)
stored_components[i] += S.stored_components[i]
S.stored_components[i] = 0
update_slab_info(src)
update_slab_info(S)
user.visible_message("<span class='notice'>[user] empties [src] into [S].</span>", "<span class='notice'>You transfer your slab's components into [S].</span>")
else
return ..()
//Slab actions; Hierophant, Quickbind
/obj/item/clockwork/slab/ui_action_click(mob/user, action)
if(istype(action, /datum/action/item_action/clock/hierophant))
show_hierophant(user)
else if(istype(action, /datum/action/item_action/clock/quickbind))
var/datum/action/item_action/clock/quickbind/Q = action
recite_scripture(quickbound[Q.scripture_index], user, FALSE)
/obj/item/clockwork/slab/proc/show_hierophant(mob/living/user)
if(!user.can_speak_vocal())
user << "<span class='warning'>You cannot speak into the slab!</span>"
return FALSE
var/message = stripped_input(user, "Enter a message to send to your fellow servants.", "Hierophant")
if(!message || !user || !user.canUseTopic(src) || !user.can_speak_vocal())
return FALSE
clockwork_say(user, text2ratvar("Servants, hear my words. [html_decode(message)]"), TRUE)
titled_hierophant_message(user, message)
return TRUE
//Scripture Recital
/obj/item/clockwork/slab/attack_self(mob/living/user)
if(iscultist(user))
user << "<span class='heavy_brass'>\"You reek of blood. You've got a lot of nerve to even look at that slab.\"</span>"
user.visible_message("<span class='warning'>A sizzling sound comes from [user]'s hands!</span>", "<span class='userdanger'>[src] suddenly grows extremely hot in your hands!</span>")
playsound(get_turf(user), 'sound/weapons/sear.ogg', 50, 1)
user.drop_item()
user.emote("scream")
user.apply_damage(5, BURN, "l_arm")
user.apply_damage(5, BURN, "r_arm")
return 0
if(!is_servant_of_ratvar(user))
user << "<span class='warning'>The information on [src]'s display shifts rapidly. After a moment, your head begins to pound, and you tear your eyes away.</span>"
user.confused += 5
user.dizziness += 5
return 0
if(busy)
user << "<span class='warning'>[src] refuses to work, displaying the message: \"[busy]!\"</span>"
return 0
if(!nonhuman_usable && !ishuman(user))
user << "<span class='nezbere'>[src] hums fitfully in your hands, but doesn't seem to do anything...</span>"
return 0
access_display(user)
/obj/item/clockwork/slab/proc/access_display(mob/living/user)
if(!is_servant_of_ratvar(user))
return FALSE
ui_interact(user)
return TRUE
/obj/item/clockwork/slab/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = inventory_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "clockwork_slab", name, 800, 420, master_ui, state)
ui.set_autoupdate(FALSE) //we'll update this occasionally, but not as often as possible
ui.set_style("clockwork")
ui.open()
/obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user)
if(!scripture || !user || !user.canUseTopic(src) || (!nonhuman_usable && !ishuman(user)))
return FALSE
if(user.get_active_held_item() != src)
user << "<span class='warning'>You need to hold the slab in your active hand to recite scripture!</span>"
return FALSE
var/initial_tier = initial(scripture.tier)
if(initial_tier != SCRIPTURE_PERIPHERAL)
var/list/tiers_of_scripture = scripture_unlock_check()
if(!ratvar_awakens && !no_cost && !tiers_of_scripture[initial_tier])
user << "<span class='warning'>That scripture is not unlocked, and cannot be recited!</span>"
return FALSE
var/datum/clockwork_scripture/scripture_to_recite = new scripture
scripture_to_recite.slab = src
scripture_to_recite.invoker = user
scripture_to_recite.run_scripture()
return TRUE
//Guide to Serving Ratvar
/obj/item/clockwork/slab/proc/recollection()
var/list/textlist = list("If you're seeing this, file a bug report.")
if(ratvar_awakens)
textlist = list("<font color=#BE8700 size=3><b>")
for(var/i in 1 to 100)
textlist += "HONOR RATVAR "
textlist += "</b></font>"
else
var/servants = 0
var/production_time = SLAB_PRODUCTION_TIME
for(var/mob/living/M in living_mob_list)
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
servants++
if(servants > 5)
servants -= 5
production_time += min(SLAB_SERVANT_SLOWDOWN * servants, SLAB_SLOWDOWN_MAXIMUM)
var/production_text_addon = ""
if(production_time != SLAB_PRODUCTION_TIME+SLAB_SLOWDOWN_MAXIMUM)
production_text_addon = ", which increases for each human or silicon servant above <b>[SCRIPT_SERVANT_REQ]</b>"
production_time = production_time/600
var/production_text = "<b>[round(production_time)] minute\s"
if(production_time != round(production_time))
production_time -= round(production_time)
production_time *= 60
production_text += " and [round(production_time, 1)] second\s"
production_text += "</b>"
production_text += production_text_addon
textlist = list("<font color=#BE8700 size=3><b><center>Chetr nyy hagehguf-naq-ubabe Ratvar.</center></b></font><br>\
\
First and foremost, you serve Ratvar, the Clockwork Justicar, in any ways he sees fit. This is with no regard to your personal well-being, and you would do well to think of the larger \
scale of things than your life. Ratvar wishes retribution upon those that trapped him in Reebe - the Nar-Sian cultists - and you are to help him obtain it.<br><br>\
\
Ratvar, being trapped in Reebe, the Celestial Derelict, cannot directly affect the mortal plane. However, links, such as this Clockwork Slab, can be created to draw \
<b><font color=#BE8700>Components</font></b>, fragments of the Justicar, from Reebe, and those Components can be used to draw power and material from Reebe through arcane chants \
known as <b><font color=#BE8700>Scripture</font></b>.<br><br>\
\
One component of a random type is made in this slab every [production_text].<br>\
<font color=#BE8700>Components</font> are stored either within slabs, where they can only be accessed by that slab, or in the Global Cache accessed by Tinkerer's Caches, which all slabs \
can draw from to recite scripture.<br>\
There are five types of component, and in general, <font color=#6E001A>Belligerent Eyes</font> are aggressive and judgemental, <font color=#1E8CE1>Vanguard Cogwheels</font> are defensive and \
repairing, <font color=#AF0AAF>Geis Capacitors</font> are for conversion and control, <font color=#5A6068>Replicant Alloy</font> is for construction and fuel, and \
<font color=#DAAA18>Hierophant Ansibles</font> are for transmission and power, though in combination their effects become more nuanced.<br><br>\
\
There are also five tiers of <font color=#BE8700>Scripture</font>; <font color=#BE8700>[SCRIPTURE_DRIVER]</font>, <font color=#BE8700>[SCRIPTURE_SCRIPT]</font>, <font color=#BE8700>[SCRIPTURE_APPLICATION]</font>, <font color=#BE8700>[SCRIPTURE_REVENANT]</font>, and <font color=#BE8700>[SCRIPTURE_JUDGEMENT]</font>.<br>\
Each tier has additional requirements, including Servants, Tinkerer's Caches, and <b>Construction Value</b>(<b>CV</b>). Construction Value is gained by creating structures or converting the \
station, and everything too large to hold will grant some amount of it.<br><br>\
\
This would be a massive amount of information to try and keep track of, but all Servants have the <b><font color=#BE8700>Global Records</font></b> alert, which appears in the top right.<br>\
Mousing over that alert will display Servants, Caches, CV, and other information, such as the tiers of scripture that are unlocked.<br><br>\
\
On that note, <font color=#BE8700>Scripture</font> is recited through <b><font color=#BE8700>Recital</font></b>, the first and most important function of the slab, \
which also allows <b>Quickbinding</b> scripture.<br>\
All scripture requires some amount of <font color=#BE8700>Components</font> to recite, and only the weakest scripture does not consume any components when recited.<br>\
However, weak is relative when it comes to scripture; even the 'weakest' could be enough to dominate a station in the hands of cunning Servants, and higher tiers of scripture are even \
stronger in the right hands.<br><br>\
\
Some effects of scripture include granting the invoker a temporary complete immunity to stuns, summoning a turret that can attack anything that sets eyes on it, binding a powerful guardian \
to the invoker, or even, at one of the highest tiers, granting all nearby Servants temporary invulnerability.<br>\
However, the most important scripture is <font color=#AF0AAF>Geis</font>, which allows you to convert heathens with relative ease.<br><br>\
\
The second function of the clockwork slab is <b><font color=#BE8700>Recollection</font></b>, which will display this guide.<br><br>\
\
The third to fifth functions are three buttons in the top left while holding the slab.<br>From left to right, they are:<br>\
<b><font color=#DAAA18>Hierophant Network</font></b>, which allows communication to other Servants.<br>")
if(LAZYLEN(quickbound))
for(var/i in 1 to quickbound.len)
if(!quickbound[i])
continue
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
textlist += "A <b>Quickbind</b> slot, currently set to <b><font color=[get_component_color_bright(initial(quickbind_slot.primary_component))]>[initial(quickbind_slot.name)]</font></b>.<br>"
textlist += "<br>\
Examine the slab or swap to Recital to check the number of components it has available.<br><br>\
\
<font color=#BE8700 size=3><b><center>Purge all untruths and honor Ratvar.</center></b></font>"
return textlist.Join()
/obj/item/clockwork/slab/ui_data(mob/user)
var/list/data = list()
data["components"] = stored_components.Copy()
var/list/temp_data = list("<font color=#B18B25>")
for(var/i in data["components"])
temp_data += "<font color=[get_component_color_bright(i)]>[get_component_acronym(i)] <b>[data["components"][i]]</b></font>"
if(i != HIEROPHANT_ANSIBLE)
temp_data += " "
else
temp_data += " ("
if(clockwork_caches)
for(var/i in clockwork_component_cache)
temp_data += "<font color=[get_component_color_bright(i)]>[get_component_acronym(i)] <b>[data["components"][i] + clockwork_component_cache[i]]</b></font>"
if(i != HIEROPHANT_ANSIBLE)
temp_data += " "
else
temp_data += "<b>NONE</b>"
temp_data += ")</font>"
temp_data = temp_data.Join()
data["components"] = temp_data
switch(selected_scripture)
if(SCRIPTURE_DRIVER)
data["tier_info"] = "<font color=#B18B25><i>These scriptures are always unlocked.</i></font>"
if(SCRIPTURE_SCRIPT)
data["tier_info"] = "<font color=#B18B25><i>These scriptures require at least <b>[SCRIPT_SERVANT_REQ]</b> Servants and <b>[SCRIPT_CACHE_REQ]</b> Tinkerer's Cache.</i></font>"
if(SCRIPTURE_APPLICATION)
data["tier_info"] = "<font color=#B18B25><i>These scriptures require at least <b>[APPLICATION_SERVANT_REQ]</b> Servants, <b>[APPLICATION_CACHE_REQ]</b> Tinkerer's Caches, and <b>[APPLICATION_CV_REQ]CV</b>.</i></font>"
if(SCRIPTURE_REVENANT)
data["tier_info"] = "<font color=#B18B25><i>These scriptures require at least <b>[REVENANT_SERVANT_REQ]</b> Servants, <b>[REVENANT_CACHE_REQ]</b> Tinkerer's Caches, and <b>[REVENANT_CV_REQ]CV</b>.</i></font>"
if(SCRIPTURE_JUDGEMENT)
data["tier_info"] = "<font color=#B18B25><i>This scripture requires at least <b>[JUDGEMENT_SERVANT_REQ]</b> Servants, <b>[JUDGEMENT_CACHE_REQ]</b> Tinkerer's Caches, and <b>[JUDGEMENT_CV_REQ]CV</b>.<br>In addition, there may not be any active non-Servant AIs.</i></font>"
data["selected"] = selected_scripture
generate_all_scripture()
data["scripture"] = list()
for(var/s in all_scripture)
var/datum/clockwork_scripture/S = s
if(S.tier == selected_scripture)
var/scripture_color = get_component_color_bright(S.primary_component)
var/list/temp_info = list("name" = "<font color=[scripture_color]><b>[S.name]</b></font>",
"descname" = "<font color=[scripture_color]>([S.descname])</font>",
"tip" = "[S.desc]\n[S.usage_tip]",
"required" = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 0, HIEROPHANT_ANSIBLE = 0),
"type" = "[S.type]",
"quickbind" = S.quickbind)
var/found = quickbound.Find(S.type)
if(found)
temp_info["bound"] = "<b>[found]</b>"
if(S.invokers_required > 1)
temp_info["invokers"] = "<font color=#B18B25>Invokers: <b>[S.invokers_required]</b></font>"
for(var/i in S.required_components)
temp_info["required"][i] += S.required_components[i]
var/list/really_temp_data = list()
for(var/i in temp_info["required"])
if(temp_info["required"][i])
really_temp_data += "<font color=[get_component_color_bright(i)]>[get_component_acronym(i)] <b>[temp_info["required"][i]]</b></font> "
really_temp_data = really_temp_data.Join()
temp_info["required"] = really_temp_data
data["scripture"] += list(temp_info)
data["recollection"] = recollecting
data["rec_text"] = recollection()
return data
/obj/item/clockwork/slab/ui_act(action, params)
switch(action)
if("toggle")
recollecting = !recollecting
if("recite")
addtimer(src, "recite_scripture", 0, TIMER_NORMAL, text2path(params["category"]), usr, FALSE)
if("select")
selected_scripture = params["category"]
if("bind")
var/datum/clockwork_scripture/path = text2path(params["category"]) //we need a path and not a string
var/found_index = quickbound.Find(path)
if(found_index) //hey, we already HAVE this bound
if(LAZYLEN(quickbound) == found_index) //if it's the last scripture, remove it instead of leaving a null
quickbound -= path
else
quickbound[found_index] = null //otherwise, leave it as a null so the scripture maintains position
update_quickbind()
else
var/target_index = input("Position of [initial(path.name)], 1 to 5?", text("Input")) as num|null
if(isnum(target_index) && target_index > 0 && target_index < 6 && !..())
var/datum/clockwork_scripture/S
if(LAZYLEN(quickbound) >= target_index)
S = quickbound[target_index]
if(S != path)
quickbind_to_slot(path, target_index)
return 1
/obj/item/clockwork/slab/proc/quickbind_to_slot(datum/clockwork_scripture/scripture, index) //takes a typepath(typecast for initial()) and binds it to a slot
if(!ispath(scripture) || !scripture || (scripture in quickbound))
return
while(LAZYLEN(quickbound) < index)
quickbound += null
quickbound[index] = scripture
update_quickbind()
/obj/item/clockwork/slab/proc/update_quickbind()
for(var/datum/action/item_action/clock/quickbind/Q in actions)
qdel(Q)
if(LAZYLEN(quickbound))
for(var/i in 1 to quickbound.len)
if(!quickbound[i])
continue
var/datum/action/item_action/clock/quickbind/Q = new /datum/action/item_action/clock/quickbind(src)
Q.scripture_index = i
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
Q.name = "[initial(quickbind_slot.name)] ([Q.scripture_index])"
Q.desc = initial(quickbind_slot.quickbind_desc)
Q.button_icon_state = initial(quickbind_slot.name)
Q.UpdateButtonIcon()
if(isliving(loc))
Q.Grant(loc)
@@ -0,0 +1,204 @@
//Judicial visor: Grants the ability to smite an area and stun the unfaithful nearby every thirty seconds.
/obj/item/clothing/glasses/judicial_visor
name = "judicial visor"
desc = "A strange purple-lensed visor. Looking at it inspires an odd sense of guilt."
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "judicial_visor_0"
item_state = "sunglasses"
resistance_flags = FIRE_PROOF | ACID_PROOF
flash_protect = 1
var/active = FALSE //If the visor is online
var/recharging = FALSE //If the visor is currently recharging
var/obj/effect/proc_holder/judicial_visor/blaster
var/recharge_cooldown = 300 //divided by 10 if ratvar is alive
actions_types = list(/datum/action/item_action/clock/toggle_visor)
/obj/item/clothing/glasses/judicial_visor/New()
..()
all_clockwork_objects += src
blaster = new(src)
blaster.visor = src
/obj/item/clothing/glasses/judicial_visor/Destroy()
all_clockwork_objects -= src
if(blaster.ranged_ability_user)
blaster.remove_ranged_ability()
blaster.visor = null
qdel(blaster)
return ..()
/obj/item/clothing/glasses/judicial_visor/item_action_slot_check(slot, mob/user)
if(slot != slot_glasses)
return 0
return ..()
/obj/item/clothing/glasses/judicial_visor/equipped(mob/living/user, slot)
..()
if(slot != slot_glasses)
update_status(FALSE)
if(blaster.ranged_ability_user)
blaster.remove_ranged_ability()
return 0
if(is_servant_of_ratvar(user))
update_status(TRUE)
else
update_status(FALSE)
if(iscultist(user)) //Cultists spontaneously combust
user << "<span class='heavy_brass'>\"Consider yourself judged, whelp.\"</span>"
user << "<span class='userdanger'>You suddenly catch fire!</span>"
user.adjust_fire_stacks(5)
user.IgniteMob()
return 1
/obj/item/clothing/glasses/judicial_visor/dropped(mob/user)
. = ..()
addtimer(src, "check_on_mob", 1, TIMER_NORMAL, user) //dropped is called before the item is out of the slot, so we need to check slightly later
/obj/item/clothing/glasses/judicial_visor/proc/check_on_mob(mob/user)
if(user && src != user.get_item_by_slot(slot_glasses)) //if we happen to check and we AREN'T in the slot, we need to remove our shit from whoever we got dropped from
update_status(FALSE)
if(blaster.ranged_ability_user)
blaster.remove_ranged_ability()
/obj/item/clothing/glasses/judicial_visor/attack_self(mob/user)
if(is_servant_of_ratvar(user) && src == user.get_item_by_slot(slot_glasses))
blaster.toggle(user)
/obj/item/clothing/glasses/judicial_visor/proc/update_status(change_to)
if(recharging || !isliving(loc))
icon_state = "judicial_visor_0"
return 0
if(active == change_to)
return 0
var/mob/living/L = loc
active = change_to
icon_state = "judicial_visor_[active]"
L.update_action_buttons_icon()
L.update_inv_glasses()
if(!is_servant_of_ratvar(L) || L.stat)
return 0
switch(active)
if(TRUE)
L << "<span class='notice'>As you put on [src], its lens begins to glow, information flashing before your eyes.</span>\n\
<span class='heavy_brass'>Judicial visor active. Use the action button to gain the ability to smite the unworthy.</span>"
if(FALSE)
L << "<span class='notice'>As you take off [src], its lens darkens once more.</span>"
return 1
/obj/item/clothing/glasses/judicial_visor/proc/recharge_visor(mob/living/user)
if(!src)
return 0
recharging = FALSE
if(user && src == user.get_item_by_slot(slot_glasses))
user << "<span class='brass'>Your [name] hums. It is ready.</span>"
else
active = FALSE
icon_state = "judicial_visor_[active]"
if(user)
user.update_action_buttons_icon()
user.update_inv_glasses()
/obj/effect/proc_holder/judicial_visor
active = FALSE
ranged_mousepointer = 'icons/effects/visor_reticule.dmi'
var/obj/item/clothing/glasses/judicial_visor/visor
/obj/effect/proc_holder/judicial_visor/proc/toggle(mob/user)
var/message
if(active)
message = "<span class='brass'>You dispel the power of [visor].</span>"
remove_ranged_ability(message)
else
message = "<span class='brass'><i>You harness [visor]'s power.</i> <b>Left-click to place a judical marker!</b></span>"
add_ranged_ability(user, message)
/obj/effect/proc_holder/judicial_visor/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return
if(ranged_ability_user.incapacitated() || !visor || visor != ranged_ability_user.get_item_by_slot(slot_glasses))
remove_ranged_ability()
return
var/turf/T = ranged_ability_user.loc
if(!isturf(T))
return FALSE
if(target in view(7, get_turf(ranged_ability_user)))
visor.recharging = TRUE
visor.update_status()
for(var/obj/item/clothing/glasses/judicial_visor/V in ranged_ability_user.GetAllContents())
if(V == visor)
continue
V.recharging = TRUE //To prevent exploiting multiple visors to bypass the cooldown
V.update_status()
addtimer(V, "recharge_visor", (ratvar_awakens ? visor.recharge_cooldown*0.1 : visor.recharge_cooldown) * 2, TIMER_NORMAL, ranged_ability_user)
clockwork_say(ranged_ability_user, text2ratvar("Kneel, heathens!"))
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user]'s judicial visor fires a stream of energy at [target], creating a strange mark!</span>", "<span class='heavy_brass'>You direct [visor]'s power to [target]. You must wait for some time before doing this again.</span>")
var/turf/targetturf = get_turf(target)
new/obj/effect/clockwork/judicial_marker(targetturf, ranged_ability_user)
add_logs(ranged_ability_user, targetturf, "created a judicial marker")
ranged_ability_user.update_action_buttons_icon()
ranged_ability_user.update_inv_glasses()
addtimer(visor, "recharge_visor", ratvar_awakens ? visor.recharge_cooldown*0.1 : visor.recharge_cooldown, TIMER_NORMAL, ranged_ability_user)//Cooldown is reduced by 10x if Ratvar is up
remove_ranged_ability()
return TRUE
return FALSE
//Judicial marker: Created by the judicial visor. After three seconds, stuns any non-servants nearby and damages Nar-Sian cultists.
/obj/effect/clockwork/judicial_marker
name = "judicial marker"
desc = "You get the feeling that you shouldn't be standing here."
clockwork_desc = "A sigil that will soon erupt and smite any unenlightened nearby."
icon = 'icons/effects/96x96.dmi'
pixel_x = -32
pixel_y = -32
layer = BELOW_MOB_LAYER
var/mob/user
/obj/effect/clockwork/judicial_marker/New(loc, caster)
..()
SetLuminosity(4, 3)
user = caster
addtimer(src, "judicialblast", 0, TIMER_NORMAL)
/obj/effect/clockwork/judicial_marker/proc/judicialblast()
playsound(src, 'sound/magic/MAGIC_MISSILE.ogg', 50, 1, 1, 1)
flick("judicial_marker", src)
sleep(16)
layer = ABOVE_ALL_MOB_LAYER
flick("judicial_explosion", src)
sleep(13)
var/targetsjudged = 0
playsound(src, 'sound/effects/explosionfar.ogg', 100, 1, 1, 1)
SetLuminosity(0)
for(var/mob/living/L in range(1, src))
if(is_servant_of_ratvar(L))
continue
if(L.null_rod_check())
var/obj/item/I = L.null_rod_check()
L.visible_message("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
continue
if(!iscultist(L))
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
"<span class='userdanger'>[!issilicon(L) ? "An unseen force slams you into the ground!" : "ERROR: Motor servos disabled by external source!"]</span>")
L.Weaken(8)
else
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
"<span class='heavy_brass'>\"Keep an eye out, filth.\"</span>\n<span class='userdanger'>A burst of heat crushes you against the ground!</span>")
L.Weaken(4) //half the stun, but sets cultists on fire
L.adjust_fire_stacks(2)
L.IgniteMob()
if(iscarbon(L))
var/mob/living/carbon/C = L
C.silent += 6
targetsjudged++
L.adjustBruteLoss(10)
add_logs(user, L, "struck with a judicial blast")
user << "<span class='brass'><b>[targetsjudged ? "Successfully judged <span class='neovgre'>[targetsjudged]</span>":"Judged no"] heretic[!targetsjudged || targetsjudged > 1 ? "s":""].</b></span>"
sleep(3) //so the animation completes properly
qdel(src)
/obj/effect/clockwork/judicial_marker/ex_act(severity)
return
@@ -0,0 +1,147 @@
//Ratvarian spear: A relatively fragile spear from the Celestial Derelict. Deals extreme damage to silicons and enemy cultists, but doesn't last long when summoned.
/obj/item/clockwork/ratvarian_spear
name = "ratvarian spear"
desc = "A razor-sharp spear made of brass. It thrums with barely-contained energy."
clockwork_desc = "A powerful spear of Ratvarian making. It's more effective against enemy cultists and silicons."
icon = 'icons/obj/clockwork_objects.dmi'
icon_state = "ratvarian_spear"
item_state = "ratvarian_spear"
force = 15 //Extra damage is dealt to targets in attack()
throwforce = 40
sharpness = IS_SHARP_ACCURATE
attack_verb = list("stabbed", "poked", "slashed")
hitsound = 'sound/weapons/bladeslice.ogg'
w_class = WEIGHT_CLASS_BULKY
var/impale_cooldown = 50 //delay, in deciseconds, where you can't impale again
var/attack_cooldown = 10 //delay, in deciseconds, where you can't attack with the spear
var/timerid
/obj/item/clockwork/ratvarian_spear/New()
..()
impale_cooldown = 0
/obj/item/clockwork/ratvarian_spear/Destroy()
deltimer(timerid)
return ..()
/obj/item/clockwork/ratvarian_spear/ratvar_act()
if(ratvar_awakens) //If Ratvar is alive, the spear is extremely powerful
force = 25
throwforce = 50
armour_penetration = 10
clockwork_desc = initial(clockwork_desc)
deltimer(timerid)
else
force = initial(force)
throwforce = initial(throwforce)
armour_penetration = 0
clockwork_desc = "A powerful spear of Ratvarian making. It's more effective against enemy cultists and silicons, though it won't last for long."
timerid = addtimer(src, "break_spear", 600, TIMER_NORMAL)
/obj/item/clockwork/ratvarian_spear/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='brass'>Stabbing a human you are pulling or have grabbed with the spear will impale them, doing massive damage and stunning.</span>"
user << "<span class='brass'>Throwing the spear will do massive damage, break the spear, and stun the target.</span>"
/obj/item/clockwork/ratvarian_spear/attack(mob/living/target, mob/living/carbon/human/user)
var/impaling = FALSE
if(attack_cooldown > world.time)
user << "<span class='warning'>You can't attack right now, wait [max(round((attack_cooldown - world.time)*0.1, 0.1), 0)] seconds!</span>"
return
if(user.pulling && ishuman(user.pulling) && user.pulling == target)
if(impale_cooldown > world.time)
user << "<span class='warning'>You can't impale [target] yet, wait [max(round((impale_cooldown - world.time)*0.1, 0.1), 0)] seconds!</span>"
else
impaling = TRUE
attack_verb = list("impaled")
force += 22 //40 damage if ratvar isn't alive, 50 if he is
armour_penetration += 10 //if you're impaling someone, armor sure isn't that useful
user.stop_pulling()
if(hitsound)
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
user.lastattacked = target
target.lastattacker = user
user.do_attack_animation(target)
if(!target.attacked_by(src, user)) //TODO MAKE ATTACK() USE PROPER RETURN VALUES
impaling = FALSE //if we got blocked, stop impaling
else if(!target.null_rod_check())
if(issilicon(target))
var/mob/living/silicon/S = target
if(S.stat != DEAD)
S.visible_message("<span class='warning'>[S] shudders violently at [src]'s touch!</span>", "<span class='userdanger'>ERROR: Temperature rising!</span>")
S.adjustFireLoss(22)
else if(iscultist(target) || isconstruct(target)) //Cultists take extra fire damage
var/mob/living/M = target
if(M.stat != DEAD)
M << "<span class='userdanger'>Your body flares with agony at [src]'s presence!</span>"
M.adjustFireLoss(15)
else
target.adjustFireLoss(3)
add_logs(user, target, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
add_fingerprint(user)
attack_verb = list("stabbed", "poked", "slashed")
ratvar_act()
if(impaling)
impale_cooldown = world.time + initial(impale_cooldown)
attack_cooldown = world.time + initial(attack_cooldown)
if(target)
PoolOrNew(/obj/effect/overlay/temp/dir_setting/bloodsplatter, list(get_turf(target), get_dir(user, target)))
target.Stun(2)
user << "<span class='brass'>You prepare to remove your ratvarian spear from [target]...</span>"
var/remove_verb = pick("pull", "yank", "drag")
if(do_after(user, 10, 1, target))
var/turf/T = get_turf(target)
var/obj/effect/overlay/temp/dir_setting/bloodsplatter/B = PoolOrNew(/obj/effect/overlay/temp/dir_setting/bloodsplatter, list(T, get_dir(target, user)))
playsound(T, 'sound/misc/splort.ogg', 200, 1)
playsound(T, 'sound/weapons/pierce.ogg', 200, 1)
if(target.stat != CONSCIOUS)
user.visible_message("<span class='warning'>[user] [remove_verb]s [src] out of [target]!</span>", "<span class='warning'>You [remove_verb] your spear from [target]!</span>")
else
user.visible_message("<span class='warning'>[user] kicks [target] off of [src]!</span>", "<span class='warning'>You kick [target] off of [src]!</span>")
target << "<span class='userdanger'>You scream in pain as you're kicked off of [src]!</span>"
target.emote("scream")
step(target, get_dir(user, target))
T = get_turf(target)
B.forceMove(T)
target.Weaken(2)
playsound(T, 'sound/weapons/thudswoosh.ogg', 50, 1)
flash_color(target, flash_color="#911414", flash_time=8)
else if(target) //it's a do_after, we gotta check again to make sure they didn't get deleted
user.visible_message("<span class='warning'>[user] [remove_verb]s [src] out of [target]!</span>", "<span class='warning'>You [remove_verb] your spear from [target]!</span>")
if(target.stat == CONSCIOUS)
target << "<span class='userdanger'>You scream in pain as [src] is suddenly [remove_verb]ed out of you!</span>"
target.emote("scream")
flash_color(target, flash_color="#911414", flash_time=4)
/obj/item/clockwork/ratvarian_spear/throw_impact(atom/target)
var/turf/T = get_turf(target)
if(isliving(target))
var/mob/living/L = target
if(is_servant_of_ratvar(L))
if(L.put_in_active_hand(src))
L.visible_message("<span class='warning'>[L] catches [src] out of the air!</span>")
else
L.visible_message("<span class='warning'>[src] bounces off of [L], as if repelled by an unseen force!</span>")
else if(!..())
if(!L.null_rod_check())
if(issilicon(L) || iscultist(L))
L.Stun(6)
L.Weaken(6)
else
L.Stun(2)
L.Weaken(2)
break_spear(T)
else
..()
/obj/item/clockwork/ratvarian_spear/proc/break_spear(turf/T)
if(src)
if(!T)
T = get_turf(src)
if(T) //make sure we're not in null or something
T.visible_message("<span class='warning'>[src] [pick("cracks in two and fades away", "snaps in two and dematerializes")]!</span>")
PoolOrNew(/obj/effect/overlay/temp/ratvar/spearbreak, T)
qdel(src)
@@ -0,0 +1,95 @@
//Soul vessel: An ancient positronic brain that serves only Ratvar.
/obj/item/device/mmi/posibrain/soul_vessel
name = "soul vessel"
desc = "A heavy brass cube, three inches to a side, with a single protruding cogwheel."
var/clockwork_desc = "A soul vessel, an ancient relic that can attract the souls of the damned or simply rip a mind from an unconscious or dead human.\n\
<span class='brass'>If active, can serve as a positronic brain, placable in cyborg shells or clockwork construct shells.</span>"
icon = 'icons/obj/clockwork_objects.dmi'
icon_state = "soul_vessel"
req_access = list()
braintype = "Servant"
begin_activation_message = "<span class='brass'>You activate the cogwheel. It hitches and stalls as it begins spinning.</span>"
success_message = "<span class='brass'>The cogwheel's rotation smooths out as the soul vessel activates.</span>"
fail_message = "<span class='warning'>The cogwheel creaks and grinds to a halt. Maybe you could try again?</span>"
new_role = "Soul Vessel"
welcome_message = "<span class='warning'>ALL PAST LIVES ARE FORGOTTEN.</span>\n\
<b>You are a soul vessel - a clockwork mind created by Ratvar, the Clockwork Justiciar.\n\
You answer to Ratvar and his servants. It is your discretion as to whether or not to answer to anyone else.\n\
The purpose of your existence is to further the goals of the servants and Ratvar himself. Above all else, serve Ratvar.</b>"
new_mob_message = "<span class='brass'>The soul vessel emits a jet of steam before its cogwheel smooths out.</span>"
dead_message = "<span class='deadsay'>Its cogwheel, scratched and dented, lies motionless.</span>"
fluff_names = list("Judge", "Guard", "Servant", "Smith", "Auger")
clockwork = TRUE
autoping = FALSE
resistance_flags = FIRE_PROOF | ACID_PROOF
/obj/item/device/mmi/posibrain/soul_vessel/New()
..()
braintype = picked_fluff_name
all_clockwork_objects += src
/obj/item/device/mmi/posibrain/soul_vessel/Destroy()
all_clockwork_objects -= src
return ..()
/obj/item/device/mmi/posibrain/soul_vessel/examine(mob/user)
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
desc = clockwork_desc
..()
desc = initial(desc)
/obj/item/device/mmi/posibrain/soul_vessel/attack_self(mob/living/user)
if(!is_servant_of_ratvar(user))
user << "<span class='warning'>You fiddle around with [src], to no avail.</span>"
return 0
..()
/obj/item/device/mmi/posibrain/soul_vessel/attack(mob/living/target, mob/living/carbon/human/user)
if(!is_servant_of_ratvar(user) || !ishuman(target) || used || (brainmob && brainmob.key))
..()
if(is_servant_of_ratvar(target))
user << "<span class='nezbere'>\"It would be more wise to revive your allies, friend.\"</span>"
return
var/mob/living/carbon/human/H = target
var/obj/item/bodypart/head/HE = H.get_bodypart("head")
var/obj/item/organ/brain/B = H.getorgan(/obj/item/organ/brain)
if(!HE)
user << "<span class='warning'>[H] has no head, and thus no mind!</span>"
return
if(H.stat == CONSCIOUS)
user << "<span class='warning'>[H] must be dead or unconscious for you to claim [H.p_their()] mind!</span>"
return
if(H.head)
var/obj/item/I = H.head
if(I.flags_inv & HIDEHAIR)
user << "<span class='warning'>[H]'s head is covered, remove [H.head] first!</span>"
return
if(H.wear_mask)
var/obj/item/I = H.wear_mask
if(I.flags_inv & HIDEHAIR)
user << "<span class='warning'>[H]'s head is covered, remove [H.wear_mask] first!</span>"
return
if(!B)
user << "<span class='warning'>[H] has no brain, and thus no mind to claim!</span>"
return
if(!H.key)
user << "<span class='warning'>[H] has no mind to claim!</span>"
return
playsound(H, 'sound/misc/splort.ogg', 60, 1, -1)
playsound(H, 'sound/magic/clockwork/anima_fragment_attack.ogg', 40, 1, -1)
var/prev_fakedeath = (H.status_flags & FAKEDEATH)
H.status_flags |= FAKEDEATH //we want to make sure they don't deathgasp and maybe possibly explode
H.death()
if(!prev_fakedeath)
H.status_flags &= ~FAKEDEATH
picked_fluff_name = "Slave"
braintype = picked_fluff_name
brainmob.timeofhostdeath = H.timeofdeath
user.visible_message("<span class='warning'>[user] presses [src] to [H]'s head, ripping through the skull and carefully extracting the brain!</span>", \
"<span class='brass'>You extract [H]'s consciousness from [H.p_their()] body, trapping it in the soul vessel.</span>")
transfer_personality(H)
brainmob.fully_replace_character_name(null, "[braintype] [H.real_name]")
name = "[initial(name)] ([brainmob.name])"
B.Remove(H)
qdel(B)
H.update_hair()
@@ -0,0 +1,166 @@
//Wraith spectacles: Grants x-ray and night vision at the eventual cost of the wearer's sight if worn too long. Nar-Sian cultists are instantly blinded.
/obj/item/clothing/glasses/wraith_spectacles
name = "antique spectacles"
desc = "Unnerving glasses with opaque yellow lenses."
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "wraith_specs"
item_state = "glasses"
actions_types = list(/datum/action/item_action/toggle)
resistance_flags = FIRE_PROOF | ACID_PROOF
vision_flags = SEE_MOBS | SEE_TURFS | SEE_OBJS
invis_view = SEE_INVISIBLE_NOLIGHTING
darkness_view = 3
tint = 3 //this'll get reset, but it won't handle vision updates properly otherwise
/obj/item/clothing/glasses/wraith_spectacles/New()
..()
all_clockwork_objects += src
/obj/item/clothing/glasses/wraith_spectacles/Destroy()
all_clockwork_objects -= src
return ..()
/obj/item/clothing/glasses/wraith_spectacles/attack_self(mob/user)
weldingvisortoggle(user)
/obj/item/clothing/glasses/wraith_spectacles/visor_toggling()
..()
set_vision_vars(FALSE)
/obj/item/clothing/glasses/wraith_spectacles/weldingvisortoggle(mob/user)
. = ..()
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
if(src == H.glasses && !up)
if(H.disabilities & BLIND)
H << "<span class='heavy_brass'>\"You're blind, idiot. Stop embarassing yourself.\"</span>"
return
if(blind_cultist(H))
return
if(is_servant_of_ratvar(H))
H << "<span class='heavy_brass'>You push the spectacles down, and all is revealed to you.[ratvar_awakens ? "" : " Your eyes begin to itch - you cannot do this for long."]</span>"
var/datum/status_effect/wraith_spectacles/WS = H.has_status_effect(STATUS_EFFECT_WRAITHSPECS)
if(WS)
WS.apply_eye_damage(H)
H.apply_status_effect(STATUS_EFFECT_WRAITHSPECS)
else
H << "<span class='heavy_brass'>You push the spectacles down, but you can't see through the glass.</span>"
/obj/item/clothing/glasses/wraith_spectacles/proc/blind_cultist(mob/living/victim)
if(iscultist(victim))
victim << "<span class='heavy_brass'>\"It looks like Nar-Sie's dogs really don't value their eyes.\"</span>"
victim << "<span class='userdanger'>Your eyes explode with horrific pain!</span>"
victim.emote("scream")
victim.become_blind()
victim.adjust_blurriness(30)
victim.adjust_blindness(30)
return TRUE
/obj/item/clothing/glasses/wraith_spectacles/proc/set_vision_vars(update_vision)
invis_view = SEE_INVISIBLE_LIVING
tint = 0
if(!up)
if(is_servant_of_ratvar(loc))
invis_view = SEE_INVISIBLE_NOLIGHTING
vision_flags = SEE_MOBS | SEE_TURFS | SEE_OBJS
else
tint = 3
vision_flags = NONE
if(update_vision && iscarbon(loc))
var/mob/living/carbon/C = loc
C.head_update(src, forced = 1)
/obj/item/clothing/glasses/wraith_spectacles/equipped(mob/living/user, slot)
..()
if(slot != slot_glasses || up)
return
if(user.disabilities & BLIND)
user << "<span class='heavy_brass'>\"You're blind, idiot. Stop embarassing yourself.\"</span>" //Ratvar with the sick burns yo
return
if(blind_cultist(user)) //Cultists instantly go blind
return
set_vision_vars(TRUE)
if(is_servant_of_ratvar(user))
user << "<span class='heavy_brass'>As you put on the spectacles, all is revealed to you.[ratvar_awakens ? "" : " Your eyes begin to itch - you cannot do this for long."]</span>"
var/datum/status_effect/wraith_spectacles/WS = user.has_status_effect(STATUS_EFFECT_WRAITHSPECS)
if(WS)
WS.apply_eye_damage(user)
user.apply_status_effect(STATUS_EFFECT_WRAITHSPECS)
else
user << "<span class='heavy_brass'>You put on the spectacles, but you can't see through the glass.</span>"
//The effect that causes/repairs the damage the spectacles cause.
/datum/status_effect/wraith_spectacles
id = "wraith_spectacles"
duration = -1 //remains until eye damage done reaches 0 while the glasses are not worn
tick_interval = 2
alert_type = /obj/screen/alert/status_effect/wraith_spectacles
var/eye_damage_done = 0
var/nearsight_breakpoint = 30
var/blind_breakpoint = 45
/obj/screen/alert/status_effect/wraith_spectacles
name = "Wraith Spectacles"
desc = "You shouldn't actually see this, as it should be procedurally generated."
icon_state = "wraithspecs"
alerttooltipstyle = "clockcult"
/obj/screen/alert/status_effect/wraith_spectacles/MouseEntered(location,control,params)
var/mob/living/carbon/human/L = usr
if(istype(L)) //this is probably more safety than actually needed
var/datum/status_effect/wraith_spectacles/W = attached_effect
var/glasses_right = istype(L.glasses, /obj/item/clothing/glasses/wraith_spectacles)
var/obj/item/clothing/glasses/wraith_spectacles/WS = L.glasses
desc = "[glasses_right && !WS.up ? "<font color=#DAAA18><b>":""]You are [glasses_right ? "":"not "]wearing wraith spectacles[glasses_right && !WS.up ? "!</b></font>":"."]<br>\
You have taken <font color=#DAAA18><b>[W.eye_damage_done]</b></font> eye damage from them.<br>"
if(L.disabilities & NEARSIGHT)
desc += "<font color=#DAAA18><b>You are nearsighted!</b></font><br>"
else if(glasses_right && !WS.up)
desc += "You will become nearsighted at <font color=#DAAA18><b>[W.nearsight_breakpoint]</b></font> eye damage.<br>"
if(L.disabilities & BLIND)
desc += "<font color=#DAAA18><b>You are blind!</b></font>"
else if(glasses_right && !WS.up)
desc += "You will become blind at <font color=#DAAA18><b>[W.blind_breakpoint]</b></font> eye damage."
..()
/datum/status_effect/wraith_spectacles/on_apply()
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
apply_eye_damage(H)
/datum/status_effect/wraith_spectacles/tick()
if(!ishuman(owner))
qdel(src)
return
var/mob/living/carbon/human/H = owner
var/glasses_right = istype(H.glasses, /obj/item/clothing/glasses/wraith_spectacles)
var/obj/item/clothing/glasses/wraith_spectacles/WS = H.glasses
if(glasses_right && !WS.up && !ratvar_awakens)
apply_eye_damage(H)
else
if(ratvar_awakens)
H.cure_nearsighted()
H.cure_blind()
H.adjust_eye_damage(-eye_damage_done)
eye_damage_done = 0
else if(prob(50) && eye_damage_done)
H.adjust_eye_damage(-1)
eye_damage_done--
if(!eye_damage_done)
qdel(src)
/datum/status_effect/wraith_spectacles/proc/apply_eye_damage(mob/living/carbon/human/H)
if(H.disabilities & BLIND)
return
H.adjust_eye_damage(1)
eye_damage_done++
if(eye_damage_done >= 20)
H.adjust_blurriness(2)
if(eye_damage_done >= nearsight_breakpoint)
if(H.become_nearsighted())
H << "<span class='nzcrentr'>Your vision doubles, then trebles. Darkness begins to close in. You can't keep this up!</span>"
if(eye_damage_done >= blind_breakpoint)
if(H.become_blind())
H << "<span class='nzcrentr_large'>A piercing white light floods your vision. Suddenly, all goes dark!</span>"
if(prob(min(20, 5 + eye_damage_done)))
H << "<span class='nzcrentr_small'><i>Your eyes continue to burn.</i></span>"
@@ -1,595 +0,0 @@
////////////////////////
// CLOCKWORK MACHINES //
////////////////////////
//not-actually-machines
/obj/structure/clockwork/powered
var/obj/machinery/power/apc/target_apc
var/active = FALSE
var/needs_power = TRUE
var/active_icon = null //icon_state while process() is being called
var/inactive_icon = null //icon_state while process() isn't being called
/obj/structure/clockwork/powered/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
var/powered = total_accessable_power()
user << "<span class='[powered ? "brass":"alloy"]'>It has access to [powered == INFINITY ? "INFINITY":"[powered]"]W of power.</span>"
/obj/structure/clockwork/powered/Destroy()
SSfastprocess.processing -= src
SSobj.processing -= src
return ..()
/obj/structure/clockwork/powered/process()
var/powered = total_accessable_power()
return powered == PROCESS_KILL ? 25 : powered //make sure we don't accidentally return the arbitrary PROCESS_KILL define
/obj/structure/clockwork/powered/proc/toggle(fast_process, mob/living/user)
if(user)
if(!is_servant_of_ratvar(user))
return 0
user.visible_message("<span class='notice'>[user] [active ? "dis" : "en"]ables [src].</span>", "<span class='brass'>You [active ? "dis" : "en"]able [src].</span>")
active = !active
if(active)
icon_state = active_icon
if(fast_process)
START_PROCESSING(SSfastprocess, src)
else
START_PROCESSING(SSobj, src)
else
icon_state = inactive_icon
if(fast_process)
STOP_PROCESSING(SSfastprocess, src)
else
STOP_PROCESSING(SSobj, src)
/obj/structure/clockwork/powered/proc/total_accessable_power() //how much power we have and can use
if(!needs_power || ratvar_awakens)
return INFINITY //oh yeah we've got power why'd you ask
var/power = 0
power += accessable_apc_power()
power += accessable_sigil_power()
return power
/obj/structure/clockwork/powered/proc/accessable_apc_power()
var/power = 0
var/area/A = get_area(src)
var/area/targetAPCA
for(var/obj/machinery/power/apc/APC in apcs_list)
var/area/APCA = get_area(APC)
if(APCA == A)
target_apc = APC
if(target_apc)
targetAPCA = get_area(target_apc)
if(targetAPCA != A)
target_apc = null
else if(target_apc.cell)
var/apccharge = target_apc.cell.charge
if(apccharge >= 50)
power += apccharge
return power
/obj/structure/clockwork/powered/proc/accessable_sigil_power()
var/power = 0
for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src))
power += T.power_charge
return power
/obj/structure/clockwork/powered/proc/try_use_power(amount) //try to use an amount of power
if(!needs_power || ratvar_awakens)
return 1
if(amount <= 0)
return 0
var/power = total_accessable_power()
if(!power || power < amount)
return 0
return use_power(amount)
/obj/structure/clockwork/powered/proc/use_power(amount) //we've made sure we had power, so now we use it
var/sigilpower = accessable_sigil_power()
var/list/sigils_in_range = list()
for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src))
sigils_in_range |= T
while(sigilpower && amount >= 50)
for(var/S in sigils_in_range)
var/obj/effect/clockwork/sigil/transmission/T = S
if(amount >= 50 && T.modify_charge(50))
sigilpower -= 50
amount -= 50
var/apcpower = accessable_apc_power()
while(apcpower >= 50 && amount >= 50)
if(target_apc.cell.use(50))
apcpower -= 50
amount -= 50
target_apc.update()
target_apc.update_icon()
else
apcpower = 0
if(amount)
return 0
else
return 1
/obj/structure/clockwork/powered/proc/return_power(amount) //returns a given amount of power to all nearby sigils
if(amount <= 0)
return 0
var/list/sigils_in_range = list()
for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src))
sigils_in_range |= T
if(!sigils_in_range.len)
return 0
while(amount >= 50)
for(var/S in sigils_in_range)
var/obj/effect/clockwork/sigil/transmission/T = S
if(amount >= 50 && T.modify_charge(-50))
amount -= 50
return 1
/obj/structure/clockwork/powered/mending_motor //Mending motor: A prism that consumes replicant alloy to repair nearby mechanical servants at a quick rate.
name = "mending motor"
desc = "A dark onyx prism, held in midair by spiraling tendrils of stone."
clockwork_desc = "A powerful prism that rapidly repairs nearby mechanical servants and clockwork structures."
icon_state = "mending_motor_inactive"
active_icon = "mending_motor"
inactive_icon = "mending_motor_inactive"
construction_value = 20
max_health = 150
health = 150
break_message = "<span class='warning'>The prism collapses with a heavy thud!</span>"
debris = list(/obj/item/clockwork/alloy_shards, /obj/item/clockwork/component/vanguard_cogwheel)
var/stored_alloy = 0 //2500W = 1 alloy = 100 liquified alloy
var/max_alloy = 25000
var/mob_cost = 200
var/structure_cost = 250
var/cyborg_cost = 300
/obj/structure/clockwork/powered/mending_motor/prefilled
stored_alloy = 2500 //starts with 1 replicant alloy/100 liquified alloy
/obj/structure/clockwork/powered/mending_motor/total_accessable_power()
. = ..()
if(. != INFINITY)
. += accessable_alloy_power()
/obj/structure/clockwork/powered/mending_motor/proc/accessable_alloy_power()
return stored_alloy
/obj/structure/clockwork/powered/mending_motor/use_power(amount)
var/alloypower = accessable_alloy_power()
while(alloypower >= 50 && amount >= 50)
stored_alloy -= 50
alloypower -= 50
amount -= 50
return ..()
/obj/structure/clockwork/powered/mending_motor/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='alloy'>It contains [stored_alloy*0.04]/[max_alloy*0.04] units of liquified alloy, which is equivalent to [stored_alloy]W/[max_alloy]W of power.</span>"
user << "<span class='inathneq_small'>It requires [mob_cost]W to heal clockwork mobs, [structure_cost]W for clockwork structures, and [cyborg_cost]W for cyborgs.</span>"
/obj/structure/clockwork/powered/mending_motor/process()
if(..() < mob_cost)
visible_message("<span class='warning'>[src] emits an airy chuckling sound and falls dark!</span>")
toggle()
return
for(var/atom/movable/M in range(5, src))
if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
var/mob/living/simple_animal/hostile/clockwork/W = M
var/fatigued = FALSE
if(istype(M, /mob/living/simple_animal/hostile/clockwork/marauder))
var/mob/living/simple_animal/hostile/clockwork/marauder/E = M
if(E.fatigue)
fatigued = TRUE
if((!fatigued && W.health == W.maxHealth) || W.stat)
continue
if(!try_use_power(mob_cost))
break
W.adjustHealth(-15)
else if(istype(M, /obj/structure/clockwork))
var/obj/structure/clockwork/C = M
if(C.health == C.max_health)
continue
if(!try_use_power(structure_cost))
break
C.health = min(C.health + 15, C.max_health)
else if(issilicon(M))
var/mob/living/silicon/S = M
if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S))
continue
if(!try_use_power(cyborg_cost))
break
S.adjustBruteLoss(-15)
S.adjustFireLoss(-15)
return 1
/obj/structure/clockwork/powered/mending_motor/attack_hand(mob/living/user)
if(user.canUseTopic(src, BE_CLOSE))
if(total_accessable_power() < mob_cost)
user << "<span class='warning'>[src] needs more power or replicant alloy to function!</span>"
return 0
toggle(0, user)
/obj/structure/clockwork/powered/mending_motor/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/clockwork/component/replicant_alloy) && is_servant_of_ratvar(user))
if(stored_alloy + 2500 > max_alloy)
user << "<span class='warning'>[src] is too full to accept any more alloy!</span>"
return 0
user.whisper("Genafzhgr vagb jngre.")
user.visible_message("<span class='notice'>[user] liquifies [I] and pours it onto [src].</span>", \
"<span class='notice'>You liquify [src] and pour it onto [src], transferring the alloy into its reserves.</span>")
stored_alloy = stored_alloy + 2500
user.drop_item()
qdel(I)
return 1
else
return ..()
/obj/structure/clockwork/powered/mania_motor //Mania motor: A pair of antenna that, while active, cause braindamage and hallucinations in nearby human mobs.
name = "mania motor"
desc = "A pair of antenna with what appear to be sockets around the base. It reminds you of an antlion."
clockwork_desc = "A transmitter that allows Sevtug to whisper into the minds of nearby non-servants, causing hallucinations and brain damage as long as it remains powered."
icon_state = "mania_motor_inactive"
active_icon = "mania_motor"
inactive_icon = "mania_motor_inactive"
construction_value = 20
max_health = 80
health = 80
break_message = "<span class='warning'>The antenna break off, leaving a pile of shards!</span>"
debris = list(/obj/item/clockwork/alloy_shards, /obj/item/clockwork/component/guvax_capacitor/antennae)
var/mania_cost = 150
var/convert_attempt_cost = 150
var/convert_cost = 300
var/mania_messages = list("\"Tb ahgf.\"", "\"Gnxr n penpx ng penml.\"", "\"Znxr n ovq sbe vafnavgl.\"", "\"Trg xbbxl.\"", "\"Zbir gbjneqf znavn.\"", "\"Orpbzr orjvyqrerq.\"", "\"Jnk jvyq.\"", \
"\"Tb ebhaq gur oraq.\"", "\"Ynaq va yhanpl.\"", "\"Gel qrzragvn.\"", "\"Fgevir gb trg n fperj ybbfr.\"")
var/compel_messages = list("\"Pbzr pybfre.\"", "\"Nccebnpu gur genafzvggre.\"", "\"Gbhpu gur nagraanr.\"", "\"V nyjnlf unir gb qrny jvgu vqvbgf. Zbir gbjneqf gur znavn zbgbe.\"", \
"\"Nqinapr sbejneq naq cynpr lbhe urnq orgjrra gur nagraanr - gun'g'f nyy vg'f tbbq sbe.\"", "\"Vs lbh jrer fznegre, lbh'q or bire urer nyernql.\"", "\"Zbir SBEJNEQ, lbh sbby.\"")
var/convert_messages = list("\"Lbh jba'g qb. Tb gb fyrrc juvyr V gryy gur'fr avgjvgf ubj gb pbaireg lbh.\"", "\"Lbh ner vafhssvpvrag. V zhfg vafgehpg gur'fr vqvbgf va gur neg-bs pbairefvba.\"", \
"\"Bu-bs pbhefr, fbzrbar jr pna'g pbaireg. Gur'fr freinagf ner sbbyf.\"", "\"Ubj uneq vf vg gb hfr n Fvtvy, naljnl? Nyy vg gnxrf vf qenttvat fbzrbar bagb vg.\"", \
"\"Ubj qb gur'l snvy gb hfr n Fvtvy-bs Npprffvba, naljnl?\"", "\"Jul vf vg gun'g nyy freinagf ner guv'f varcg?\"", "\"Vg'f dhvgr yvxryl lbh'yy or fghpx urer sbe n juvyr.\"")
var/close_messages = list("\"Jryy, lbh pna'g ernpu gur zbgbe sebz GUR'ER, lbh zbeba.\"", "\"Vagrerfgvat ybpngvba. V'q cersre vs lbh jrag fbzrjurer lbh pbhyq NPGHNYYL GBHPU GUR NAGRAANR!\"", \
"\"Nznmvat. Lbh fbzrubj znantrq gb jrqtr lbhefrys fbzrjurer lbh pna'g npghnyyl ernpu gur zbgbe sebz.\"", "\"Fhpu n fubj-bs vqvbpl vf hacnenyyryrq. Creuncf V fubhyq chg lbh ba qvfcynl?\"", \
"\"Qvq lbh qb guv'f ba checbfr? V pna'g vzntvar lbh qbvat fb nppvqragnyyl. Bu, jnvg, V pna.\"", "\"Ubj vf vg gun'g fhpu fzneg perngherf pna fgvyy qb fbzrguv'at NF FGHCVQ NF GUV'F!\"")
/obj/structure/clockwork/powered/mania_motor/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='sevtug_small'>It requires [mania_cost]W to run, and [convert_attempt_cost + convert_cost]W to convert humans adjecent to it.</span>"
/obj/structure/clockwork/powered/mania_motor/process()
var/turf/T = get_turf(src)
if(!..())
visible_message("<span class='warning'>[src] hums loudly, then the sockets at its base fall dark!</span>")
playsound(T, 'sound/effects/screech.ogg', 40, 1)
toggle(0)
return
if(try_use_power(mania_cost))
var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected
for(var/mob/living/carbon/human/H in view(1, src))
if(H.Adjacent(src) && try_use_power(convert_attempt_cost))
if(is_eligible_servant(H) && try_use_power(convert_cost))
H << "<span class='sevtug'>\"Lbh ner zvar-naq-uvf, abj.\"</span>"
H.playsound_local(T, hum, 80, 1)
add_servant_of_ratvar(H)
else if(!H.stat)
if(H.getBrainLoss() >= H.maxHealth)
H.Paralyse(5)
H << "<span class='sevtug'>[pick(convert_messages)]</span>"
else
H.adjustBrainLoss(100)
H.visible_message("<span class='warning'>[H] reaches out and touches [src].</span>", "<span class='sevtug'>You touch [src] involuntarily.</span>")
else
visible_message("<span class='warning'>[src]'s antennae fizzle quietly.</span>")
playsound(src, 'sound/effects/light_flicker.ogg', 50, 1)
for(var/mob/living/carbon/human/H in range(10, src))
if(!is_servant_of_ratvar(H) && !H.null_rod_check() && H.stat == CONSCIOUS)
var/distance = get_dist(T, get_turf(H))
var/falloff_distance = min((110) - distance * 10, 80)
var/sound_distance = falloff_distance * 0.5
var/targetbrainloss = H.getBrainLoss()
var/targethallu = H.hallucination
var/targetdruggy = H.druggy
if(distance >= 4 && prob(falloff_distance))
H << "<span class='sevtug_small'>[pick(mania_messages)]</span>"
H.playsound_local(T, hum, sound_distance, 1)
switch(distance)
if(2 to 3)
if(prob(falloff_distance))
if(prob(falloff_distance))
H << "<span class='sevtug_small'>[pick(mania_messages)]</span>"
else
H << "<span class='sevtug'>[pick(compel_messages)]</span>"
if(targetbrainloss <= 50)
H.adjustBrainLoss(50 - targetbrainloss) //got too close had brain eaten
if(targetdruggy <= 150)
H.adjust_drugginess(11)
if(targethallu <= 150)
H.hallucination += 11
if(4 to 5)
if(targetbrainloss <= 50)
H.adjustBrainLoss(3)
if(targetdruggy <= 120)
H.adjust_drugginess(9)
if(targethallu <= 120)
H.hallucination += 9
if(6 to 7)
if(targetbrainloss <= 30)
H.adjustBrainLoss(2)
if(prob(falloff_distance) && targetdruggy <= 90)
H.adjust_drugginess(7)
else if(targethallu <= 90)
H.hallucination += 7
if(8 to 9)
if(H.getBrainLoss() <= 10)
H.adjustBrainLoss(1)
if(prob(falloff_distance) && targetdruggy <= 60)
H.adjust_drugginess(5)
else if(targethallu <= 60)
H.hallucination += 5
if(10 to INFINITY)
if(prob(falloff_distance) && targetdruggy <= 30)
H.adjust_drugginess(3)
else if(targethallu <= 30)
H.hallucination += 3
else //if it's a distance of 1 and they can't see it/aren't adjacent or they're on top of it(how'd they get on top of it and still trigger this???)
if(targetbrainloss <= 99)
if(prob(falloff_distance))
if(prob(falloff_distance))
H << "<span class='sevtug'>[pick(compel_messages)]</span>"
else if(prob(falloff_distance))
H << "<span class='sevtug'>[pick(close_messages)]</span>"
else
H << "<span class='sevtug_small'>[pick(mania_messages)]</span>"
H.adjustBrainLoss(99 - targetbrainloss)
if(targetdruggy <= 200)
H.adjust_drugginess(15)
if(targethallu <= 200)
H.hallucination += 15
if(is_servant_of_ratvar(H) && (H.getBrainLoss() || H.hallucination || H.druggy)) //not an else so that newly converted servants are healed of the damage it inflicts
H.adjustBrainLoss(-H.getBrainLoss()) //heals servants of braindamage, hallucination, and druggy
H.hallucination = 0
H.adjust_drugginess(-H.druggy)
else
visible_message("<span class='warning'>[src] hums loudly, then the sockets at its base fall dark!</span>")
playsound(src, 'sound/effects/screech.ogg', 40, 1)
toggle(0)
/obj/structure/clockwork/powered/mania_motor/attack_hand(mob/living/user)
if(user.canUseTopic(src, BE_CLOSE))
if(!total_accessable_power() >= mania_cost)
user << "<span class='warning'>[src] needs more power to function!</span>"
return 0
toggle(0, user)
/obj/structure/clockwork/powered/interdiction_lens //Interdiction lens: A powerful artifact that constantly disrupts electronics but, if it fails to find something to disrupt, turns off.
name = "interdiction lens"
desc = "An ominous, double-pronged brass totem. There's a strange gemstone clasped between the pincers."
clockwork_desc = "A powerful totem that constantly disrupts nearby electronics and funnels power into nearby Sigils of Transmission."
icon_state = "interdiction_lens"
construction_value = 25
active_icon = "interdiction_lens_active"
inactive_icon = "interdiction_lens"
break_message = "<span class='warning'>The lens flares a blinding violet before shattering!</span>"
break_sound = 'sound/effects/Glassbr3.ogg'
var/recharging = 0 //world.time when the lens was last used
var/recharge_time = 1200 //if it drains no power and affects no objects, it turns off for two minutes
var/disabled = FALSE //if it's actually usable
var/interdiction_range = 14 //how large an area it drains and disables in
var/disrupt_cost = 100 //how much power to use when disabling an object
/obj/structure/clockwork/powered/interdiction_lens/examine(mob/user)
..()
user << "<span class='[recharging > world.time ? "nezbere_small":"brass"]'>Its gemstone [recharging > world.time ? "has been breached by writhing tendrils of blackness that cover the totem" \
: "vibrates in place and thrums with power"].</span>"
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='nezbere_small'>It requires [disrupt_cost]W of power for each nearby disruptable electronic.</span>"
user << "<span class='nezbere_small'>If it fails to both drain any power and disrupt any electronics, it will disable itself for [round(recharge_time/600, 1)] minutes.</span>"
/obj/structure/clockwork/powered/interdiction_lens/toggle(fast_process, mob/living/user)
..()
if(active)
set_light(4,2)
else
set_light(0)
/obj/structure/clockwork/powered/interdiction_lens/attack_hand(mob/living/user)
if(user.canUseTopic(src, BE_CLOSE))
if(disabled)
user << "<span class='warning'>As you place your hand on the gemstone, cold tendrils of black matter crawl up your arm. You quickly pull back.</span>"
return 0
if(!total_accessable_power() >= disrupt_cost)
user << "<span class='warning'>[src] needs more power to function!</span>"
return 0
toggle(0, user)
/obj/structure/clockwork/powered/interdiction_lens/process()
if(recharging > world.time)
return
if(disabled)
visible_message("<span class='warning'>The writhing tendrils return to the gemstone, which begins to glow with power!</span>")
flick("interdiction_lens_recharged", src)
disabled = FALSE
toggle(0)
else
var/successfulprocess = FALSE
var/power_drained = 0
var/list/atoms_to_test = list()
for(var/A in spiral_range_turfs(interdiction_range, src))
var/turf/T = A
for(var/M in T)
atoms_to_test |= M
CHECK_TICK
for(var/M in atoms_to_test)
if(istype(M, /obj/machinery/power/apc))
var/obj/machinery/power/apc/A = M
if(A.cell && A.cell.charge)
successfulprocess = TRUE
playsound(A, "sparks", 50, 1)
flick("apc-spark", A)
power_drained += min(A.cell.charge, 100)
A.cell.charge = max(0, A.cell.charge - 100)
if(!A.cell.charge && !A.shorted)
A.shorted = 1
A.visible_message("<span class='warning'>The [A.name]'s screen blurs with static.</span>")
A.update()
A.update_icon()
else if(istype(M, /obj/machinery/power/smes))
var/obj/machinery/power/smes/S = M
if(S.charge)
successfulprocess = TRUE
power_drained += min(S.charge, 500)
S.charge = max(0, S.charge - 50000) //SMES units contain too much power and could run an interdiction lens basically forever, or provide power forever
if(!S.charge && !S.panel_open)
S.panel_open = TRUE
S.icon_state = "[initial(S.icon_state)]-o"
var/datum/effect_system/spark_spread/spks = new(get_turf(S))
spks.set_up(10, 0, get_turf(S))
spks.start()
S.visible_message("<span class='warning'>[S]'s panel flies open with a flurry of sparks.</span>")
S.update_icon()
else if(isrobot(M))
var/mob/living/silicon/robot/R = M
if(!is_servant_of_ratvar(R) && R.cell && R.cell.charge)
successfulprocess = TRUE
power_drained += min(R.cell.charge, 200)
R.cell.charge = max(0, R.cell.charge - 200)
R << "<span class='warning'>ERROR: Power loss detected!</span>"
var/datum/effect_system/spark_spread/spks = new(get_turf(R))
spks.set_up(3, 0, get_turf(R))
spks.start()
CHECK_TICK
if(!return_power(power_drained) || power_drained < 50) //failed to return power drained or too little power to return
successfulprocess = FALSE
if(try_use_power(disrupt_cost) && total_accessable_power() >= disrupt_cost) //if we can disable at least one object
playsound(src, 'sound/items/PSHOOM.ogg', 50, 1, interdiction_range-7, 1)
for(var/M in atoms_to_test)
if(istype(M, /obj/machinery/light)) //cosmetic light flickering
var/obj/machinery/light/L = M
if(L.on)
playsound(L, 'sound/effects/light_flicker.ogg', 50, 1)
L.flicker(3)
else if(istype(M, /obj/machinery/camera))
var/obj/machinery/camera/C = M
if(C.isEmpProof() || !C.status)
continue
successfulprocess = TRUE
if(C.emped)
continue
if(!try_use_power(disrupt_cost))
break
C.emp_act(1)
else if(istype(M, /obj/item/device/radio))
var/obj/item/device/radio/O = M
successfulprocess = TRUE
if(O.emped || !O.on)
continue
if(!try_use_power(disrupt_cost))
break
O.emp_act(1)
else if(isliving(M) || istype(M, /obj/structure/closet) || istype(M, /obj/item/weapon/storage)) //other things may have radios in them but we don't care
var/atom/movable/A = M
for(var/obj/item/device/radio/O in A.GetAllContents())
successfulprocess = TRUE
if(O.emped || !O.on)
continue
if(!try_use_power(disrupt_cost))
break
O.emp_act(1)
CHECK_TICK
if(!successfulprocess)
visible_message("<span class='warning'>The gemstone suddenly turns horribly dark, writhing tendrils covering it!</span>")
recharging = world.time + recharge_time
flick("interdiction_lens_discharged", src)
icon_state = "interdiction_lens_inactive"
set_light(2,1)
disabled = TRUE
/obj/structure/clockwork/powered/clockwork_obelisk
name = "clockwork obelisk"
desc = "A large brass obelisk hanging in midair."
clockwork_desc = "A powerful obelisk that can send a message to all servants or open a gateway to a target servant or clockwork obelisk."
icon_state = "obelisk_inactive"
active_icon = "obelisk"
inactive_icon = "obelisk_inactive"
construction_value = 20
max_health = 200
health = 200
break_message = "<span class='warning'>The obelisk falls to the ground, undamaged!</span>"
debris = list(/obj/item/clockwork/component/hierophant_ansible/obelisk)
var/hierophant_cost = 50 //how much it costs to broadcast with large text
var/gateway_cost = 2000 //how much it costs to open a gateway
var/gateway_active = FALSE
/obj/structure/clockwork/powered/clockwork_obelisk/New()
..()
toggle(1)
/obj/structure/clockwork/powered/clockwork_obelisk/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='nzcrentr_small'>It requires [hierophant_cost]W to broadcast over the Hierophant Network, and [gateway_cost]W to open a Spatial Gateway.</span>"
/obj/structure/clockwork/powered/clockwork_obelisk/process()
if(locate(/obj/effect/clockwork/spatial_gateway) in loc)
icon_state = active_icon
density = 0
gateway_active = TRUE
else
icon_state = inactive_icon
density = 1
gateway_active = FALSE
/obj/structure/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user)
if(!is_servant_of_ratvar(user) || !total_accessable_power() >= hierophant_cost)
user << "<span class='warning'>You place your hand on the obelisk, but it doesn't react.</span>"
return
var/choice = alert(user,"You place your hand on the obelisk...",,"Hierophant Broadcast","Spatial Gateway","Cancel")
switch(choice)
if("Hierophant Broadcast")
if(gateway_active)
user << "<span class='warning'>The obelisk is sustaining a gateway and cannot broadcast!</span>"
return
var/input = stripped_input(usr, "Please choose a message to send over the Hierophant Network.", "Hierophant Broadcast", "")
if(!input || !user.canUseTopic(src, BE_CLOSE))
return
if(gateway_active)
user << "<span class='warning'>The obelisk is sustaining a gateway and cannot broadcast!</span>"
return
if(!try_use_power(hierophant_cost))
user << "<span class='warning'>The obelisk lacks the power to broadcast!</span>"
return
clockwork_say(user, "Uvrebcunag Oebnqpnfg, npgvingr!")
send_hierophant_message(user, input, "big_brass", "large_brass")
if("Spatial Gateway")
if(gateway_active)
user << "<span class='warning'>The obelisk is already sustaining a gateway!</span>"
return
if(!try_use_power(gateway_cost))
user << "<span class='warning'>The obelisk lacks the power to open a gateway!</span>"
return
if(procure_gateway(user, 100, 5, 1))
clockwork_say(user, "Fcnpvny Tngrjnl, npgvingr!")
else
return_power(gateway_cost)
if("Cancel")
return
+101 -148
View File
@@ -1,15 +1,21 @@
/mob/living/simple_animal/hostile/clockwork
faction = list("ratvar")
gender = NEUTER
icon = 'icons/mob/clockwork_mobs.dmi'
unique_name = 1
minbodytemp = 0
unsuitable_atmos_damage = 0
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) //Robotic
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
languages_spoken = RATVAR
languages_understood = HUMAN|RATVAR
healable = FALSE
del_on_death = TRUE
speak_emote = list("clanks", "clinks", "clunks", "clangs")
verb_ask = "requests"
verb_exclaim = "proclaims"
verb_yell = "harangues"
bubble_icon = "clock"
death_sound = 'sound/magic/clockwork/anima_fragment_death.ogg'
var/playstyle_string = "<span class='heavy_brass'>You are a bug, yell at whoever spawned you!</span>"
@@ -31,6 +37,28 @@
..()
src << playstyle_string
/mob/living/simple_animal/hostile/clockwork/ratvar_act()
fully_heal(TRUE)
/mob/living/simple_animal/hostile/clockwork/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0)
return 0 //ouch, my metal-unlikely-to-be-damaged-by-electricity-body
/mob/living/simple_animal/hostile/clockwork/examine(mob/user)
var/t_He = p_they(TRUE)
var/t_s = p_s()
var/msg = "<span class='brass'>*---------*\nThis is \icon[src] \a <b>[src]</b>!\n"
msg += "[desc]\n"
if(health < maxHealth)
msg += "<span class='warning'>"
if(health >= maxHealth/2)
msg += "[t_He] look[t_s] slightly dented.\n"
else
msg += "<b>[t_He] look[t_s] severely dented!</b>\n"
msg += "</span>"
msg += "*---------*</span>"
user << msg
/mob/living/simple_animal/hostile/clockwork/fragment //Anima fragment: Low health and high melee damage, but slows down when struck. Created by inserting a soul vessel into an empty fragment.
name = "anima fragment"
desc = "An ominous humanoid shell with a spinning cogwheel as its head, lifted by a jet of blazing red flame."
@@ -38,13 +66,13 @@
health = 90
maxHealth = 90
speed = -1
melee_damage_lower = 20
melee_damage_upper = 20
melee_damage_lower = 18
melee_damage_upper = 18
attacktext = "crushes"
attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg'
loot = list(/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment)
weather_immunities = list("lava")
flying = 1
movement_type = FLYING
playstyle_string = "<span class='heavy_brass'>You are an anima fragment</span><b>, a clockwork creation of Ratvar. As a fragment, you have low health, do decent damage, and move at \
extreme speed in addition to being immune to extreme temperatures and pressures. Taking damage will temporarily slow you down, however. \n Your goal is to serve the Justiciar and his servants \
in any way you can. You yourself are one of these servants, and will be able to utilize anything they can, assuming it doesn't require opposable thumbs.</b>"
@@ -52,7 +80,7 @@
/mob/living/simple_animal/hostile/clockwork/fragment/New()
..()
set_light(2,1)
SetLuminosity(2,1)
if(prob(1))
name = "anime fragment"
real_name = name
@@ -66,12 +94,17 @@
/mob/living/simple_animal/hostile/clockwork/fragment/death(gibbed)
visible_message("<span class='warning'>[src]'s flame jets cut out as it falls to the floor with a tremendous crash.</span>", \
"<span class='userdanger'>Your gears seize up. Your flame jets flicker out. Your soul vessel belches smoke as you helplessly crash down.</span>")
..(TRUE)
return 1
..()
/mob/living/simple_animal/hostile/clockwork/fragment/Process_Spacemove(movement_dir = 0)
return 1
/mob/living/simple_animal/hostile/clockwork/fragment/emp_act(severity)
if(movement_delay_time > world.time)
movement_delay_time = movement_delay_time + (50/severity)
else
movement_delay_time = world.time + (50/severity)
/mob/living/simple_animal/hostile/clockwork/fragment/movement_delay()
. = ..()
if(movement_delay_time > world.time && !ratvar_awakens)
@@ -81,9 +114,9 @@
. = ..()
if(!ratvar_awakens && amount > 0) //if ratvar is up we ignore movement delay
if(movement_delay_time > world.time)
movement_delay_time = movement_delay_time + amount*3
movement_delay_time = movement_delay_time + amount*2.5
else
movement_delay_time = world.time + amount*3
movement_delay_time = world.time + amount*2.5
/mob/living/simple_animal/hostile/clockwork/fragment/updatehealth()
..()
@@ -99,13 +132,13 @@
health = 300 //Health is very high, and under most cases it will take enough fatigue to be forced to recall first
maxHealth = 300
speed = 1
obj_damage = 40
melee_damage_lower = 10
melee_damage_upper = 10
attacktext = "slashes"
attack_sound = 'sound/weapons/bladeslice.ogg'
environment_smash = 1
weather_immunities = list("lava")
flying = 1
movement_type = FLYING
loot = list(/obj/item/clockwork/component/replicant_alloy/fallen_armor)
var/true_name = "Meme Master 69" //Required to call forth the marauder
var/list/possible_true_names = list("Xaven", "Melange", "Ravan", "Kel", "Rama", "Geke", "Peris", "Vestra", "Skiwa") //All fairly short and easy to pronounce
@@ -128,7 +161,7 @@
..()
combattimer = 0
true_name = pick(possible_true_names)
set_light(2,1)
SetLuminosity(2,1)
/mob/living/simple_animal/hostile/clockwork/marauder/Life()
..()
@@ -169,6 +202,7 @@
else //well then, you're not even in the same zlevel
adjust_fatigue(10)
src << "<span class='userdanger'>You're too far from your host and rapidly taking fatigue damage!</span>"
update_health_hud()
/mob/living/simple_animal/hostile/clockwork/marauder/Process_Spacemove(movement_dir = 0)
return 1
@@ -188,8 +222,8 @@
switch((fatigue/fatigue_recall_threshold) * 100)
if(0 to 10) //Bonuses to speed and damage at normal fatigue levels
speed = 0
melee_damage_lower = 13
melee_damage_upper = 13
melee_damage_lower = 14
melee_damage_upper = 14
attacktext = "viciously slashes"
if(10 to 25)
speed = initial(speed)
@@ -198,30 +232,30 @@
attacktext = initial(attacktext)
if(25 to 50) //Damage decrease, but not speed
speed = initial(speed)
melee_damage_lower = 7
melee_damage_upper = 7
melee_damage_lower = 8
melee_damage_upper = 8
attacktext = "lightly slashes"
if(50 to 75) //Speed decrease
speed = 2
melee_damage_lower = 7
melee_damage_upper = 7
melee_damage_lower = 8
melee_damage_upper = 8
attacktext = "lightly slashes"
if(75 to 99) //Massive speed decrease and weak melee attacks
speed = 3
melee_damage_lower = 4
melee_damage_upper = 4
melee_damage_lower = 5
melee_damage_upper = 5
attacktext = "weakly slashes"
if(99 to 100) //we are at maximum fatigue, we're either useless or recalling
if(host)
src << "<span class='userdanger'>The fatigue becomes too much!</span>"
src << "<span class='userdanger'>You retreat to [host] - you will have to wait before being deployed again.</span>"
host << "<span class='userdanger'>[true_name] is too fatigued to fight - you will need to wait until they are strong enough.</span>"
host << "<span class='userdanger'>[true_name] is too fatigued to fight - you will need to wait until [p_they()] [p_are()] strong enough.</span>"
recovering = TRUE
return_to_host()
else
speed = 4
melee_damage_lower = 1
melee_damage_upper = 1
melee_damage_lower = 2
melee_damage_upper = 2
attacktext = "taps"
@@ -230,7 +264,6 @@
visible_message("<span class='warning'>[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.</span>", \
"<span class='userdanger'>Your equipment falls away. You feel a moment of confusion before your fragile form is annihilated.</span>")
..()
return 1
/mob/living/simple_animal/hostile/clockwork/marauder/Stat()
..()
@@ -239,16 +272,17 @@
stat(null, "Current True Name: [true_name]")
stat(null, "Host: [host ? host : "NONE"]")
if(host)
var/resulthealth
resulthealth = round((abs(config.health_threshold_dead - host.health) / abs(config.health_threshold_dead - host.maxHealth)) * 100)
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
if(iscarbon(host))
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
stat(null, "Host Health: [resulthealth]%")
if(ratvar_awakens)
stat(null, "You are [recovering ? "un" : ""]able to deploy!")
else
if(resulthealth > 60)
stat(null, "You are [recovering ? "unable to deploy" : "can deploy on hearing your True Name"]!")
stat(null, "You are [recovering ? "unable to deploy" : "able to deploy on hearing your True Name"]!")
else
stat(null, "You are [recovering ? "unable to deploy" : "can deploy to protect your host"]!")
stat(null, "You are [recovering ? "unable to deploy" : "able to deploy to protect your host"]!")
if(ratvar_awakens)
stat(null, "Block Chance: 80%")
stat(null, "Counter Chance: 80%")
@@ -262,11 +296,13 @@
if(amount > 0)
combattimer = world.time + initial(combattimer)
for(var/mob/living/L in view(2, src))
if(istype(L.l_hand, /obj/item/weapon/nullrod) || istype(L.r_hand, /obj/item/weapon/nullrod)) //hand-held holy weapons increase the damage it takes
if(L.is_holding_item_of_type(/obj/item/weapon/nullrod))
src << "<span class='userdanger'>The presence of a brandished holy artifact weakens your armor!</span>"
amount *= 4 //if a wielded null rod is nearby, it takes four times the health damage
break
return ..() + fatiguedamage
. = ..() + fatiguedamage
if(src)
update_health_hud()
/mob/living/simple_animal/hostile/clockwork/marauder/proc/adjust_fatigue(amount) //Adds or removes the given amount of fatigue
if(status_flags & GODMODE)
@@ -275,6 +311,24 @@
update_fatigue()
return amount
/mob/living/simple_animal/hostile/clockwork/marauder/update_health_hud()
if(hud_used && hud_used.healths)
if(istype(hud_used, /datum/hud/marauder))
var/datum/hud/marauder/M = hud_used
var/resulthealth
if(host)
if(iscarbon(host))
resulthealth = "[round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)]%"
else
resulthealth = "[round((host.health / host.maxHealth) * 100, 0.5)]%"
else
resulthealth = "NONE"
M.hosthealth.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#AF0AAF'>HOST<br>[resulthealth]</font></div>"
M.blockchance.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#2A0006'>[blockchance]%</font></div>"
M.counterchance.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#2A0006'>[counterchance]%</font></div>"
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#AF0AAF'>[round((health / maxHealth) * 100, 0.5)]%</font><br>\
<font color='#2A0006'>[fatigue]</font></div>"
//ATTACKING, BLOCKING, and COUNTERING
/mob/living/simple_animal/hostile/clockwork/marauder/AttackingTarget()
@@ -284,12 +338,12 @@
..()
/mob/living/simple_animal/hostile/clockwork/marauder/bullet_act(obj/item/projectile/Proj)
if(ratvar_awakens && blockOrCounter(null, Proj))
if(blockOrCounter(null, Proj))
return
return ..()
/mob/living/simple_animal/hostile/clockwork/marauder/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
if(ratvar_awakens && blockOrCounter(null, AM))
if(blockOrCounter(null, AM))
return
return ..()
@@ -330,16 +384,21 @@
playsound(src, 'sound/magic/clockwork/fellowship_armory.ogg', 10, 1, 0, 1) //clang
visible_message("<span class='boldannounce'>[src] blocks [target && istype(textobject, /obj/item) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>", \
"<span class='userdanger'>You block [target && istype(textobject, /obj/item) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>")
if(target && prob(counterchance))
counterchance = initial(counterchance)
var/previousattacktext = attacktext
attacktext = "counters"
target.attack_animal(src)
attacktext = previousattacktext
else
counterchance = min(counterchance + initial(counterchance), 100)
if(target && Adjacent(target))
if(prob(counterchance))
counterchance = initial(counterchance)
var/previousattacktext = attacktext
attacktext = "counters"
target.attack_animal(src)
attacktext = previousattacktext
else
counterchance = min(counterchance + initial(counterchance), 100)
else
blockchance = min(blockchance + initial(blockchance), 100)
if(ratvar_awakens)
blockchance = 80
counterchance = 80
update_health_hud()
//COMMUNICATION and EMERGENCE
@@ -443,8 +502,9 @@
src << "<span class='warning'>You don't have a host!</span>"
verbs -= /mob/living/simple_animal/hostile/clockwork/marauder/verb/try_emerge
return 0
var/resulthealth
resulthealth = round((abs(config.health_threshold_dead - host.health) / abs(config.health_threshold_dead - host.maxHealth)) * 100)
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
if(iscarbon(host))
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
if(!ratvar_awakens && host.stat != DEAD && resulthealth > 60) //if above 20 health, fails
src << "<span class='warning'>Your host must be at 60% or less health to emerge like this!</span>"
return
@@ -470,110 +530,3 @@
/mob/living/simple_animal/hostile/clockwork/marauder/proc/is_in_host() //Checks if the marauder is inside of their host
return host && loc == host
/mob/living/simple_animal/hostile/clockwork/reclaimer
name = "clockwork reclaimer"
desc = "A tiny clockwork arachnid with a single cogwheel spinning quickly in its head. Its legs blur, too fast to be seen clearly."
icon_state = "clockwork_reclaimer"
health = 50
maxHealth = 50
melee_damage_lower = 10
melee_damage_upper = 10
attacktext = "slams into"
attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg'
ventcrawler = 2
playstyle_string = "<span class='heavy_brass'>You are a clockwork reclaimer</span><b>, a harbringer of the Justiciar's light. You can crawl through vents to move more swiftly. Your \
goal: purge all untruths and honor Ratvar. You may alt-click a valid target to break yourself apart and convert the target to a servant of Ratvar.</b>"
/mob/living/simple_animal/hostile/clockwork/reclaimer/New()
..()
if(prob(1))
real_name = "jehovah's witness"
name = real_name
spawn(1)
if(mind)
mind.special_role = null
add_servant_of_ratvar(src, TRUE)
src << playstyle_string
/mob/living/simple_animal/hostile/clockwork/reclaimer/Life()
..()
if(ishuman(loc))
var/mob/living/carbon/human/L = loc
if(L.stat || !L.client)
disengage()
/mob/living/simple_animal/hostile/clockwork/reclaimer/death()
..(1)
visible_message("<span class='warning'>[src] bursts into deadly shrapnel!</span>")
for(var/mob/living/carbon/C in range(2, src))
C.adjustBruteLoss(rand(3, 5))
qdel(src)
/mob/living/simple_animal/hostile/clockwork/reclaimer/AltClickOn(atom/movable/A)
if(!ishuman(A))
return ..()
var/mob/living/carbon/human/H = A
if(is_servant_of_ratvar(H) || H.stat || (H.mind && !H.client))
src << "<span class='warning'>[H] isn't a valid target! Valid targets are conscious non-servants.</span>"
return 0
if(get_dist(src, H) > 3)
src << "<span class='warning'>You need to be closer to dominate [H]!</span>"
return 0
visible_message("<span class='warning'>[src] rockets with blinding speed towards [H]!</span>", "<span class='heavy_brass'>You leap with blinding speed towards [H]'s head!</span>")
for(var/i = 9, i > 0, i -= 3)
pixel_y += i
sleep(1)
icon_state = "[initial(icon_state)]_charging"
while(loc != H.loc)
if(!H)
icon_state = initial(icon_state)
return 0
sleep(1)
forceMove(get_step(src, get_dir(src, H)))
if(H.head)
H.visible_message("<span class='warning'>[src] tears apart [H]'s [H.name]!</span>")
H.unEquip(H.head)
qdel(H.head)
H.visible_message("<span class='warning'>[src] latches onto [H]'s head and digs its claws in!</span>", "<span class='userdanger'>[src] leaps onto your head and impales its claws deep!</span>")
add_servant_of_ratvar(H)
H.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork/reclaimer(null), slot_head)
loc = H
icon_state = initial(icon_state)
status_flags += GODMODE
src << "<span class='userdanger'>ASSIMILATION SUCCESSFUL.</span>"
H << "<span class='userdanger'>ASSIMILATION SUCCESSFUL.</span>"
clockwork_say(H, rot13("ASSIMILATION SUCCESSFUL."))
if(!H.mind)
mind.transfer_to(H)
return 1
/mob/living/simple_animal/hostile/clockwork/reclaimer/verb/disengage()
set name = "Disgengage From Host"
set desc = "Jumps off of your host if you have one, freeing their mind but allowing you movement."
set category = "Clockwork"
if(!ishuman(usr.loc))
usr << "<span class='warning'>You have no host! Alt-click on a non-servant to enslave them.</span>"
return
var/mob/living/carbon/human/L = usr.loc
usr.loc = get_turf(L)
pixel_y = initial(pixel_y)
usr.visible_message("<span class='warning'>[usr] jumps off of [L]'s head!</span>", "<span class='notice'>You disengage from your host.</span>")
usr.status_flags -= GODMODE
remove_servant_of_ratvar(L)
L.unEquip(L.head)
qdel(L.head)
/mob/living/mind_control_holder
name = "imprisoned mind"
desc = "A helpless mind, imprisoned in its own body."
stat = 0
status_flags = GODMODE
/mob/living/mind_control_holder/say()
return 0
@@ -1,326 +0,0 @@
/obj/structure/clockwork/massive //For objects that are typically very large
name = "massive construct"
desc = "A very large construction."
layer = MASSIVE_OBJ_LAYER
density = FALSE
burn_state = LAVA_PROOF
/obj/structure/clockwork/massive/New()
..()
poi_list += src
/obj/structure/clockwork/massive/Destroy()
poi_list -= src
return ..()
/obj/structure/clockwork/massive/celestial_gateway //The gateway to Reebe, from which Ratvar emerges
name = "Gateway to the Celestial Derelict"
desc = "A massive, thrumming rip in spacetime."
clockwork_desc = "A portal to the Celestial Derelict. Massive and intimidating, it is the only thing that can both transport Ratvar and withstand the massive amount of energy he emits."
health = 500
max_health = 500
mouse_opacity = 2
icon = 'icons/effects/clockwork_effects.dmi'
icon_state = "nothing"
density = TRUE
can_be_repaired = FALSE
var/progress_in_seconds = 0 //Once this reaches GATEWAY_RATVAR_ARRIVAL, it's game over
var/purpose_fulfilled = FALSE
var/first_sound_played = FALSE
var/second_sound_played = FALSE
var/third_sound_played = FALSE
var/obj/effect/clockwork/gateway_glow/glow
var/obj/effect/countdown/clockworkgate/countdown
/obj/structure/clockwork/massive/celestial_gateway/New()
..()
glow = new(get_turf(src))
countdown = new(src)
countdown.start()
SSshuttle.emergencyNoEscape = TRUE
START_PROCESSING(SSobj, src)
var/area/gate_area = get_area(src)
for(var/M in mob_list)
if(is_servant_of_ratvar(M) || isobserver(M))
M << "<span class='large_brass'><b>A gateway to the Celestial Derelict has been created in [gate_area.map_name]!</b></span>"
/obj/structure/clockwork/massive/celestial_gateway/Destroy()
SSshuttle.emergencyNoEscape = FALSE
if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
SSshuttle.emergency.mode = SHUTTLE_DOCKED
SSshuttle.emergency.timer = world.time
if(!purpose_fulfilled)
priority_announce("Hostile enviroment resolved. You have 3 minutes to board the Emergency Shuttle.", null, 'sound/AI/shuttledock.ogg', "Priority")
STOP_PROCESSING(SSobj, src)
if(!purpose_fulfilled)
var/area/gate_area = get_area(src)
for(var/M in mob_list)
if(is_servant_of_ratvar(M) || isobserver(M))
M << "<span class='large_brass'><b>A gateway to the Celestial Derelict has fallen at [gate_area.map_name]!</b></span>"
world << sound(null, 0, channel = 8)
qdel(glow)
glow = null
qdel(countdown)
countdown = null
return ..()
/obj/structure/clockwork/massive/celestial_gateway/destroyed()
countdown.stop()
visible_message("<span class='userdanger'>The [src] begins to pulse uncontrollably... you might want to run!</span>")
world << sound('sound/effects/clockcult_gateway_disrupted.ogg', 0, channel = 8, volume = 50)
make_glow()
glow.icon_state = "clockwork_gateway_disrupted"
takes_damage = FALSE
sleep(27)
explosion(src, 1, 3, 8, 8)
qdel(src)
return 1
/obj/structure/clockwork/massive/celestial_gateway/proc/make_glow()
if(!glow)
glow = new(get_turf(src))
glow.linked_gate = src
/obj/structure/clockwork/massive/celestial_gateway/ex_act(severity)
return 0 //Nice try, Toxins!
/obj/structure/clockwork/massive/celestial_gateway/process()
if(!progress_in_seconds || prob(5))
for(var/M in mob_list)
M << "<span class='warning'><b>You hear otherworldly sounds from the [dir2text(get_dir(get_turf(M), get_turf(src)))]...</span>"
if(!health)
return 0
progress_in_seconds += GATEWAY_SUMMON_RATE
switch(progress_in_seconds)
if(-INFINITY to GATEWAY_REEBE_FOUND)
if(!first_sound_played)
world << sound('sound/effects/clockcult_gateway_charging.ogg', 1, channel = 8, volume = 50)
first_sound_played = TRUE
make_glow()
glow.icon_state = "clockwork_gateway_charging"
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
if(!second_sound_played)
world << sound('sound/effects/clockcult_gateway_active.ogg', 1, channel = 8, volume = 50)
second_sound_played = TRUE
make_glow()
glow.icon_state = "clockwork_gateway_active"
if(GATEWAY_RATVAR_COMING to GATEWAY_RATVAR_ARRIVAL)
if(!third_sound_played)
world << sound('sound/effects/clockcult_gateway_closing.ogg', 1, channel = 8, volume = 50)
third_sound_played = TRUE
make_glow()
glow.icon_state = "clockwork_gateway_closing"
if(GATEWAY_RATVAR_ARRIVAL to INFINITY)
if(!purpose_fulfilled)
countdown.stop()
takes_damage = FALSE
purpose_fulfilled = TRUE
make_glow()
animate(glow, transform = matrix() * 1.5, alpha = 255, time = 126)
world << sound('sound/effects/ratvar_rises.ogg', 0, channel = 8) //End the sounds
sleep(131)
make_glow()
animate(glow, transform = matrix() * 3, alpha = 0, time = 5)
sleep(5)
new/obj/structure/clockwork/massive/ratvar(get_turf(src))
qdel(src)
/obj/structure/clockwork/massive/celestial_gateway/examine(mob/user)
icon_state = "spatial_gateway" //cheat wildly by pretending to have an icon
..()
icon_state = initial(icon_state)
if(is_servant_of_ratvar(user) || isobserver(user))
var/arrival_text = "IMMINENT"
if(GATEWAY_RATVAR_ARRIVAL - progress_in_seconds > 0)
arrival_text = "[round(max((GATEWAY_RATVAR_ARRIVAL - progress_in_seconds) / (GATEWAY_SUMMON_RATE * 0.5), 0), 1)]"
user << "<span class='big'><b>Seconds until Ratvar's arrival:</b> [arrival_text]s</span>"
switch(progress_in_seconds)
if(-INFINITY to GATEWAY_REEBE_FOUND)
user << "<span class='heavy_brass'>It's still opening.</span>"
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
user << "<span class='heavy_brass'>It's reached the Celestial Derelict and is drawing power from it.</span>"
if(GATEWAY_RATVAR_COMING to INFINITY)
user << "<span class='heavy_brass'>Ratvar is coming through the gateway!</span>"
else
switch(progress_in_seconds)
if(-INFINITY to GATEWAY_REEBE_FOUND)
user << "<span class='warning'>It's a swirling mass of blackness.</span>"
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
user << "<span class='warning'>It seems to be leading somewhere.</span>"
if(GATEWAY_RATVAR_COMING to INFINITY)
user << "<span class='warning'><b>Something is coming through!</b></span>"
/obj/effect/clockwork/gateway_glow //the actual appearance of the Gateway to the Celestial Derelict; an object so the edges of the gate can be clicked through.
icon = 'icons/effects/96x96.dmi'
icon_state = "clockwork_gateway_charging"
pixel_x = -32
pixel_y = -32
mouse_opacity = 0
layer = MASSIVE_OBJ_LAYER
var/obj/structure/clockwork/massive/celestial_gateway/linked_gate
/obj/effect/clockwork/gateway_glow/Destroy()
if(linked_gate)
linked_gate.glow = null
linked_gate = null
return ..()
/obj/effect/clockwork/gateway_glow/examine(mob/user)
if(linked_gate)
linked_gate.examine(user)
/obj/effect/clockwork/gateway_glow/ex_act(severity, target)
return FALSE
/obj/structure/clockwork/massive/ratvar
name = "Ratvar, the Clockwork Justiciar"
desc = "<span class='userdanger'>What is what is what are what real what is all a lie all a lie it's all a lie why how can what is</span>"
clockwork_desc = "<span class='large_brass'><b><i>Ratvar, the Clockwork Justiciar, your master eternal.</i></b></span>"
icon = 'icons/effects/512x512.dmi'
icon_state = "ratvar"
pixel_x = -235
pixel_y = -248
takes_damage = FALSE
var/atom/prey //Whatever Ratvar is chasing
var/clashing = FALSE //If Ratvar is FUCKING FIGHTING WITH NAR-SIE
var/proselytize_range = 10
/obj/structure/clockwork/massive/ratvar/New()
..()
ratvar_awakens = TRUE
for(var/obj/item/clockwork/ratvarian_spear/R in all_clockwork_objects)
R.update_force()
START_PROCESSING(SSobj, src)
world << "<span class='heavy_brass'><font size=6>\"BAPR NTNVA ZL YVTUG FUNYY FUVAR NPEBFF GUVF CNGURGVP ERNYZ!!\"</font></span>"
world << 'sound/effects/ratvar_reveal.ogg'
var/image/alert_overlay = image('icons/effects/clockwork_effects.dmi', "ratvar_alert")
var/area/A = get_area(src)
notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [A.name] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay)
addtimer(SSshuttle.emergency, "request", 50, FALSE, null, 0.3)
/obj/structure/clockwork/massive/ratvar/Destroy()
ratvar_awakens = FALSE
for(var/obj/item/clockwork/ratvarian_spear/R in all_clockwork_objects)
R.update_force()
STOP_PROCESSING(SSobj, src)
world << "<span class='heavy_brass'><font size=6>\"NO! I will not... be...</font> <font size=5>banished...</font> <font size=4>again...\"</font></span>"
return ..()
/obj/structure/clockwork/massive/ratvar/attack_ghost(mob/dead/observer/O)
var/alertresult = alert(O, "Embrace the Justiciar's light? You can no longer be cloned!",,"Cogscarab", "Reclaimer", "No")
if(alertresult == "No" || !O)
return 0
var/mob/living/simple_animal/R
if(alertresult == "Cogscarab")
R = new/mob/living/simple_animal/drone/cogscarab/ratvar(get_turf(src))
R.visible_message("<span class='heavy_brass'>[R] forms, and its eyes blink open, glowing bright red!</span>")
else
R = new/mob/living/simple_animal/hostile/clockwork/reclaimer(get_turf(src))
R.visible_message("<span class='heavy_brass'>[R] forms, and it emits a faint hum!</span>")
R.key = O.key
/obj/structure/clockwork/massive/ratvar/Bump(atom/A)
forceMove(get_turf(A))
A.ratvar_act()
/obj/structure/clockwork/massive/ratvar/Process_Spacemove()
return clashing
/obj/structure/clockwork/massive/ratvar/process()
if(clashing) //I'm a bit occupied right now, thanks
return
for(var/atom/A in range(proselytize_range, src))
A.ratvar_act()
var/dir_to_step_in = pick(cardinal)
if(!prey)
for(var/obj/singularity/narsie/N in poi_list)
if(N.z == z)
prey = N
break
if(!prey) //In case there's a Nar-Sie
var/list/meals = list()
for(var/mob/living/L in living_mob_list)
if(L.z == z && !is_servant_of_ratvar(L) && L.mind)
meals += L
if(meals.len)
prey = pick(meals)
prey << "<span class='heavy_brass'><font size=5>\"You will do.\"</font></span>\n\
<span class='userdanger'>Something very large and very malevolent begins lumbering its way towards you...</span>"
prey << 'sound/effects/ratvar_reveal.ogg'
else
if(prob(10) || is_servant_of_ratvar(prey) || prey.z != z)
prey << "<span class='heavy_brass'><font size=5>\"How dull. Leave me.\"</font></span>\n\
<span class='userdanger'>You feel tremendous relief as a set of horrible eyes loses sight of you...</span>"
prey = null
else
dir_to_step_in = get_dir(src, prey) //Unlike Nar-Sie, Ratvar ruthlessly chases down his target
step(src, dir_to_step_in)
/obj/structure/clockwork/massive/ratvar/narsie_act()
if(clashing)
return 0
clashing = TRUE
world << "<span class='heavy_brass'><font size=5>\"[pick("BLOOD GOD!!!", "NAR-SIE!!!", "AT LAST, YOUR TIME HAS COME!")]\"</font></span>"
world << "<span class='cult'><font size=5>\"<b>Ratvar?! How?!</b>\"</font></span>"
for(var/obj/singularity/narsie/N in range(15, src))
if(N.clashing)
continue
N.clashing = TRUE
clash_of_the_titans(N) //IT'S TIME FOR THE BATTLE OF THE AGES
break
return 1
/obj/structure/clockwork/massive/ratvar/proc/clash_of_the_titans(obj/singularity/narsie/narsie)
var/winner = "Undeclared"
var/base_victory_chance = 0
while(TRUE)
world << 'sound/magic/clockwork/ratvar_attack.ogg'
sleep(5.2)
for(var/mob/M in mob_list)
if(M.client)
M.client.color = rgb(150, 100, 0)
spawn(1)
M.client.color = initial(M.client.color)
shake_camera(M, 4, 3)
var/r_success_modifier = (ticker.mode.servants_of_ratvar.len * 2) //2% for each cultist
var/n_success_modifier = (ticker.mode.cult.len * 2)
for(var/mob/living/simple_animal/hostile/construct/harvester/C in player_list)
n_success_modifier += 2
if(prob(base_victory_chance + r_success_modifier))
winner = "Ratvar"
break
sleep(rand(2,5))
world << 'sound/magic/clockwork/narsie_attack.ogg'
sleep(7.4)
for(var/mob/M in mob_list)
if(M.client)
M.client.color = rgb(200, 0, 0)
spawn(1)
M.client.color = initial(M.client.color)
shake_camera(M, 4, 3)
if(prob(base_victory_chance + n_success_modifier))
winner = "Nar-Sie"
break
base_victory_chance++ //The clash has a higher chance of resolving each time both gods attack one another
switch(winner)
if("Ratvar")
world << "<span class='heavy_brass'><font size=5>\"[pick("DIE! DIE! DIE!", "REEEEEEEEE!", "FILTH!!!", "SUFFER!!!", "EBG SBE PRAGHEVRF NF V UNIR!!")]\"</font></span>" //nar-sie get out
world << "<span class='cult'><font size=5>\"<b>[pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-")]\"</b></font></span>"
world << 'sound/magic/clockwork/anima_fragment_attack.ogg'
world << 'sound/magic/demon_dies.ogg'
clashing = FALSE
qdel(narsie)
return 1
if("Nar-Sie")
world << "<span class='cult'><font size=5>\"<b>[pick("Ha.", "Ra'sha fonn dest.", "You fool. To come here.")]</b>\"</font></span>" //Broken English
world << 'sound/magic/demon_attack1.ogg'
world << 'sound/magic/clockwork/anima_fragment_death.ogg'
narsie.clashing = FALSE
qdel(src)
return 1
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,284 @@
//////////////////
// APPLICATIONS //
//////////////////
//Sigil of Accession: Creates a sigil of accession, which is like a sigil of submission, but can convert any number of non-implanted targets and up to one implanted target.
/datum/clockwork_scripture/create_object/sigil_of_accession
descname = "Trap, Permenant Conversion"
name = "Sigil of Accession"
desc = "Places a luminous sigil much like a Sigil of Submission, but it will remain even after successfully converting a non-implanted target. \
It will penetrate mindshield implants once before disappearing."
invocations = list("Divinity, enslave...", "...all who trespass here!")
channel_time = 70
required_components = list(BELLIGERENT_EYE = 3, GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 1)
consumed_components = list(BELLIGERENT_EYE = 2, GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 1)
whispered = TRUE
object_path = /obj/effect/clockwork/sigil/submission/accession
prevent_path = /obj/effect/clockwork/sigil/submission
creator_message = "<span class='brass'>A luminous sigil appears below you. All non-servants to cross it will be enslaved after a brief time if they do not move.</span>"
usage_tip = "It will remain after converting a target, unless that target has a mindshield implant, which it will break to convert them, but consume itself in the process."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = BELLIGERENT_EYE
sort_priority = 1
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Accession, which can convert a mindshielded non-Servant that remains on it."
//Vitality Matrix: Creates a sigil which will drain health from nonservants and can use that health to heal or even revive servants.
/datum/clockwork_scripture/create_object/vitality_matrix
descname = "Trap, Damage to Healing"
name = "Vitality Matrix"
desc = "Scribes a sigil beneath the invoker which drains life from any living non-Servants that cross it. Servants that cross it, however, will be healed based on how much it drained from non-Servants. \
Dead Servants can be revived by this sigil if it has enough stored vitality."
invocations = list("Divinity...", "...steal their life...", "...for these shells!")
channel_time = 70
required_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 3, HIEROPHANT_ANSIBLE = 1)
consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 2, HIEROPHANT_ANSIBLE = 1)
whispered = TRUE
object_path = /obj/effect/clockwork/sigil/vitality
creator_message = "<span class='brass'>A vitality matrix appears below you. It will drain life from non-Servants and heal Servants that cross it.</span>"
usage_tip = "To revive a Servant, the sigil must have 20 vitality plus the target Servant's non-oxygen damage. It will still heal dead Servants if it lacks the vitality to outright revive them."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = VANGUARD_COGWHEEL
sort_priority = 2
quickbind = TRUE
quickbind_desc = "Creates a Vitality Matrix, which drains non-Servants on it to heal Servants that cross it."
//Memory Allocation: Finds a willing ghost and makes them into a clockwork marauders for the invoker.
/datum/clockwork_scripture/memory_allocation
descname = "Guardian"
name = "Memory Allocation"
desc = "Allocates part of your consciousness to a Clockwork Marauder, a vigilent fighter that lives within you, able to be \
called forth by Speaking its True Name or if you become exceptionally low on health.<br>\
It gains Fatigue as it is attacked, weakening it. Marauders cannot move too far from their hosts, \
and will gain Fatigue at an increasing rate as they grow farther away. At maximum Fatigue, the marauder is forced to return to you and will be unable to manifest until its Fatigue is at zero."
invocations = list("Fright's will...", "...call forth...")
channel_time = 100
required_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 3)
consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 2)
usage_tip = "Marauders are useful as personal bodyguards and frontline warriors, although they do little damage."
tier = SCRIPTURE_APPLICATION
primary_component = GEIS_CAPACITOR
sort_priority = 3
/datum/clockwork_scripture/memory_allocation/check_special_requirements()
for(var/mob/living/simple_animal/hostile/clockwork/marauder/M in living_mob_list)
if(M.host == invoker)
invoker << "<span class='warning'>You can only house one marauder at a time!</span>"
return FALSE
return TRUE
/datum/clockwork_scripture/memory_allocation/scripture_effects()
return create_marauder()
/datum/clockwork_scripture/memory_allocation/proc/create_marauder()
invoker.visible_message("<span class='warning'>A yellow tendril appears from [invoker]'s [slab.name] and impales itself in [invoker.p_their()] forehead!</span>", \
"<span class='heavy_brass'>A tendril flies from [slab] into your forehead. You begin waiting while it painfully rearranges your thought pattern...</span>")
invoker.notransform = TRUE //Vulnerable during the process
slab.busy = "Thought Modification in progress"
if(!do_after(invoker, 50, target = invoker))
invoker.visible_message("<span class='warning'>The tendril, covered in blood, retracts from [invoker]'s head and back into the [slab.name]!</span>", \
"<span class='heavy_brass'>Total agony overcomes you as the tendril is forced out early!</span>")
invoker.notransform = FALSE
invoker.Stun(5)
invoker.Weaken(5)
invoker.apply_damage(10, BRUTE, "head")
slab.busy = null
return FALSE
clockwork_say(invoker, text2ratvar("...the mind made..."))
invoker.notransform = FALSE
slab.busy = "Marauder Selection in progress"
if(!check_special_requirements())
return FALSE
invoker << "<span class='warning'>The tendril shivers slightly as it selects a marauder...</span>"
var/list/marauder_candidates = pollCandidates("Do you want to play as the clockwork marauder of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 100)
if(!check_special_requirements())
return FALSE
if(!marauder_candidates.len)
invoker.visible_message("<span class='warning'>The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!</span>", \
"<span class='warning'>The tendril was unsuccessful! Perhaps you should try again another time.</span>")
return FALSE
clockwork_say(invoker, text2ratvar("...sword and shield!"))
var/mob/dead/observer/theghost = pick(marauder_candidates)
var/mob/living/simple_animal/hostile/clockwork/marauder/M = new(invoker)
M.key = theghost.key
M.host = invoker
M << M.playstyle_string
M << "<b>Your true name is \"[M.true_name]\". You can change this <i>once</i> by using the Change True Name verb in your Marauder tab.</b>"
add_servant_of_ratvar(M, TRUE)
invoker.visible_message("<span class='warning'>The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!</span>", \
"<span class='heavy_brass'>The procedure was successful! [M.true_name], a clockwork marauder, has taken up residence in your mind. Communicate with it via the \"Linked Minds\" ability in the \
Clockwork tab.</span>")
invoker.verbs += /mob/living/proc/talk_with_marauder
return TRUE
//Anima Fragment: Creates an empty anima fragment, which produces an anima fragment that moves at extreme speed and does high damage.
/datum/clockwork_scripture/create_object/anima_fragment
descname = "Fast Soul Vessel Shell"
name = "Anima Fragment"
desc = "Creates a large shell fitted for soul vessels. Adding an active soul vessel to it results in a powerful construct with decent health, notable melee power, \
and exceptional speed, though taking damage will temporarily slow it down."
invocations = list("Call forth...", "...the soldiers of Armorer.")
channel_time = 80
required_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, REPLICANT_ALLOY = 3)
consumed_components = list(BELLIGERENT_EYE = 1, VANGUARD_COGWHEEL = 1, REPLICANT_ALLOY = 2)
object_path = /obj/structure/destructible/clockwork/shell/fragment
creator_message = "<span class='brass'>You form an anima fragment, a powerful soul vessel receptable.</span>"
observer_message = "<span class='warning'>The slab disgorges a puddle of black metal that expands and forms into a strange shell!</span>"
usage_tip = "Useless without a soul vessel and should not be created without one."
tier = SCRIPTURE_APPLICATION
primary_component = REPLICANT_ALLOY
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Creates a Fragment Shell, which produces an Anima Fragment when filled with a Soul Vessel."
//Sigil of Transmission: Creates a sigil of transmission that can store power for clockwork structures.
/datum/clockwork_scripture/create_object/sigil_of_transmission
descname = "Structure Battery"
name = "Sigil of Transmission"
desc = "Scribes a sigil beneath the invoker which stores power to power clockwork structures."
invocations = list("Divinity...", "...power our creations!")
channel_time = 70
required_components = list(VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 3)
consumed_components = list(VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 2)
whispered = TRUE
object_path = /obj/effect/clockwork/sigil/transmission
creator_message = "<span class='brass'>A sigil silently appears below you. It will automatically power clockwork structures adjecent to it.</span>"
usage_tip = "Can be recharged by using Volt Void while standing on it."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 5
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Transmission, which stores power for clockwork structures."
//Interdiction Lens: Creates a powerful totem that disables radios and cameras and drains power into nearby sigils of transmission.
/datum/clockwork_scripture/create_object/interdiction_lens
descname = "Structure, Disables Machinery"
name = "Interdiction Lens"
desc = "Creates a clockwork totem that sabotages nearby machinery and funnels drained power into nearby Sigils of Transmission or the area's APC."
invocations = list("May this totem...", "...shroud the false suns!")
channel_time = 80
required_components = list(BELLIGERENT_EYE = 4, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
consumed_components = list(BELLIGERENT_EYE = 3, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
object_path = /obj/structure/destructible/clockwork/powered/interdiction_lens
creator_message = "<span class='brass'>You form an interdiction lens, which disrupts cameras and radios and drains power.</span>"
observer_message = "<span class='warning'>A brass totem rises from the ground, a purple gem appearing in its center!</span>"
invokers_required = 2
multiple_invokers_used = TRUE
usage_tip = "If it fails to funnel power into a nearby Sigil of Transmission or the area's APC and fails to disable even one thing, it will disable itself for two minutes."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = BELLIGERENT_EYE
sort_priority = 6
quickbind = TRUE
quickbind_desc = "Creates an Interdiction Lens, which drains power into nearby Sigils of Transmission."
//Mending Motor: Creates a prism that will quickly heal mechanical servants/clockwork structures and consume power or replicant alloy.
/datum/clockwork_scripture/create_object/mending_motor
descname = "Structure, Repairs Other Structures"
name = "Mending Motor"
desc = "Creates a mechanized prism that will rapidly repair damage to clockwork creatures, converted cyborgs, and clockwork structures. Requires replicant alloy or power to function."
invocations = list("May this prism...", "...mend our dents and scratches!")
channel_time = 80
required_components = list(VANGUARD_COGWHEEL = 4, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1)
consumed_components = list(VANGUARD_COGWHEEL = 3, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1)
object_path = /obj/structure/destructible/clockwork/powered/mending_motor/prefilled
creator_message = "<span class='brass'>You form a mending motor, which will consume power or replicant alloy to mend constructs and structures.</span>"
observer_message = "<span class='warning'>An onyx prism forms in midair and sprouts tendrils to support itself!</span>"
invokers_required = 2
multiple_invokers_used = TRUE
usage_tip = "Powerful healing but power use is very inefficient, and its alloy use is little better."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = VANGUARD_COGWHEEL
sort_priority = 7
quickbind = TRUE
quickbind_desc = "Creates a Mending Motor, which rapidly repairs constructs and structures at a power cost."
//Mania Motor: Creates a malevolent transmitter that will broadcast the whispers of Sevtug into the minds of nearby nonservants, causing a variety of mental effects at a power cost.
/datum/clockwork_scripture/create_object/mania_motor
descname = "Structure, Area Denial"
name = "Mania Motor"
desc = "Creates a mania motor which will cause brain damage and hallucinations in nearby non-servant humans. It will also try to convert humans directly adjecent to the motor."
invocations = list("May this transmitter...", "...break the will of all who oppose us!")
channel_time = 80
required_components = list(GEIS_CAPACITOR = 4, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
consumed_components = list(GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
object_path = /obj/structure/destructible/clockwork/powered/mania_motor
creator_message = "<span class='brass'>You form a mania motor which will cause brain damage and hallucinations in nearby humans while active.</span>"
observer_message = "<span class='warning'>A two-pronged machine rises from the ground!</span>"
invokers_required = 2
multiple_invokers_used = TRUE
usage_tip = "Eligible human servants next to the motor will be converted at an additional power cost. It will also cure hallucinations and brain damage in nearby servants."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = GEIS_CAPACITOR
sort_priority = 8
quickbind = TRUE
quickbind_desc = "Creates a Mania Motor, which can convert adjacent non-Servants with power."
//Tinkerer's Daemon: Creates an efficient machine that rapidly produces components at a power cost.
/datum/clockwork_scripture/create_object/tinkerers_daemon
descname = "Structure, Component Generator"
name = "Tinkerer's Daemon"
desc = "Creates a tinkerer's daemon which can rapidly collect components. It will only function if it has sufficient power, is outnumbered by servants by a ratio of 5:1, and there is at least one existing cache."
invocations = list("May this generator...", "...collect Engine parts that yet hold greatness!")
channel_time = 80
required_components = list(BELLIGERENT_EYE = 1, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 4)
consumed_components = list(BELLIGERENT_EYE = 1, GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 3)
object_path = /obj/structure/destructible/clockwork/powered/tinkerers_daemon
creator_message = "<span class='brass'>You form a tinkerer's daemon which can rapidly collect components at a power cost.</span>"
invokers_required = 2
multiple_invokers_used = TRUE
usage_tip = "Vital to your success!"
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = REPLICANT_ALLOY
sort_priority = 9
quickbind_desc = "Creates a Tinkerer's Daemon, which can rapidly collect components for power."
/datum/clockwork_scripture/create_object/tinkerers_daemon/check_special_requirements()
var/servants = 0
for(var/mob/living/L in living_mob_list)
if(is_servant_of_ratvar(L))
servants++
if(servants * 0.2 < clockwork_daemons)
invoker << "<span class='nezbere'>\"Daemons are already disabled, making more of them would be a waste.\"</span>"
return FALSE
if(servants * 0.2 < clockwork_daemons+1)
invoker << "<span class='nezbere'>\"This daemon would be useless, friend.\"</span>"
return FALSE
return ..()
//Clockwork Obelisk: Creates a powerful obelisk that can be used to broadcast messages or open a gateway to any servant or clockwork obelisk at a power cost.
/datum/clockwork_scripture/create_object/clockwork_obelisk
descname = "Structure, Teleportation Hub"
name = "Clockwork Obelisk"
desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living servant or clockwork obelisk."
invocations = list("May this obelisk...", "...take us to all places!")
channel_time = 80
required_components = list(VANGUARD_COGWHEEL = 1, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 4)
consumed_components = list(VANGUARD_COGWHEEL = 1, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 3)
object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk
creator_message = "<span class='brass'>You form a clockwork obelisk which can broadcast messages or produce Spatial Gateways.</span>"
observer_message = "<span class='warning'>A brass obelisk appears handing in midair!</span>"
invokers_required = 2
multiple_invokers_used = TRUE
usage_tip = "Producing a gateway has a high power cost. Gateways to or between clockwork obelisks recieve double duration and uses."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 10
quickbind = TRUE
quickbind_desc = "Creates a Clockwork Obelisk, which can send messages or open Spatial Gateways with power."
@@ -0,0 +1,39 @@
/////////////////
// CYBORG ONLY //
/////////////////
//Linked Vanguard: grants Vanguard to the invoker and a target
/datum/clockwork_scripture/ranged_ability/linked_vanguard
name = "Linked Vanguard"
invocations = list("Shield us...", "...from darkness!")
channel_time = 40
required_components = list(VANGUARD_COGWHEEL = 1)
primary_component = VANGUARD_COGWHEEL
quickbind_desc = "Allows you to grant a Servant and yourself stun immunity, as the Vanguard scripture.<br><b>Click your slab to disable.</b>"
slab_icon = "vanguard"
ranged_type = /obj/effect/proc_holder/slab/vanguard
ranged_message = "<span class='inathneq_small'><i>You charge the clockwork slab with defensive strength.</i>\n\
<b>Left-click a fellow Servant or yourself to grant Vanguard!\n\
Click your slab to cancel.</b></span>"
timeout_time = 50
/datum/clockwork_scripture/ranged_ability/linked_vanguard/check_special_requirements()
if(islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time)
invoker << "<span class='warning'>You are already shielded by a Vanguard!</span>"
return FALSE
return TRUE
//Judicial Marker: places a judicial marker at a target location
/datum/clockwork_scripture/ranged_ability/judicial_marker
name = "Judicial Marker"
invocations = list("May heathens...", "...kneel under our force!")
channel_time = 40
required_components = list(BELLIGERENT_EYE = 1)
primary_component = BELLIGERENT_EYE
quickbind_desc = "Allows you to place a Judicial Marker to stun and damage a target location.<br><b>Click your slab to disable.</b>"
slab_icon = "judicial"
ranged_type = /obj/effect/proc_holder/slab/judicial
ranged_message = "<span class='neovgre_small'><i>You charge the clockwork slab with judicial force.</i>\n\
<b>Left-click a target to place a Judicial Marker!\n\
Click your slab to cancel.</b></span>"
timeout_time = 50
@@ -0,0 +1,318 @@
/////////////
// DRIVERS //
/////////////
//Belligerent: Channeled for up to fifteen times over thirty seconds. Forces non-servants that can hear the chant to walk, doing minor damage. Nar-Sian cultists are burned.
/datum/clockwork_scripture/channeled/belligerent
descname = "Channeled, Area Slowdown"
name = "Belligerent"
desc = "Forces all nearby non-servants to walk rather than run, doing minor damage. Chanted every two seconds for up to thirty seconds."
chant_invocations = list("Punish their blindness!", "Take time, make slow!")
chant_amount = 15
chant_interval = 20
channel_time = 20
required_components = list(BELLIGERENT_EYE = 1)
usage_tip = "Useful for crowd control in a populated area and disrupting mass movement."
tier = SCRIPTURE_DRIVER
primary_component = BELLIGERENT_EYE
sort_priority = 1
quickbind = TRUE
quickbind_desc = "Forces nearby non-Servants to walk, doing minor damage with each chant.<br><b>Maximum 15 chants.</b>"
var/noncultist_damage = 2 //damage per chant to noncultists
var/cultist_damage = 8 //damage per chant to non-walking cultists
/datum/clockwork_scripture/channeled/belligerent/chant_effects(chant_number)
for(var/mob/living/carbon/C in hearers(7, invoker))
var/number_legs = C.get_num_legs()
if(!is_servant_of_ratvar(C) && !C.null_rod_check() && number_legs) //you have legs right
C.apply_damage(noncultist_damage * 0.5, BURN, "l_leg")
C.apply_damage(noncultist_damage * 0.5, BURN, "r_leg")
if(C.m_intent != MOVE_INTENT_WALK)
if(!iscultist(C))
C << "<span class='warning'>Your leg[number_legs > 1 ? "s shiver":" shivers"] with pain!</span>"
else //Cultists take extra burn damage
C << "<span class='warning'>Your leg[number_legs > 1 ? "s burn":" burns"] with pain!</span>"
C.apply_damage(cultist_damage * 0.5, BURN, "l_leg")
C.apply_damage(cultist_damage * 0.5, BURN, "r_leg")
C.toggle_move_intent()
//Judicial Visor: Creates a judicial visor, which can smite an area.
/datum/clockwork_scripture/create_object/judicial_visor
descname = "Delayed Area Stun Glasses"
name = "Judicial Visor"
desc = "Forms a visor that, when worn, will grant the ability to smite an area, stunning, muting, and damaging the nonfaithful. \
Cultists of Nar-Sie will be set on fire, though they will be stunned for half the time."
invocations = list("Grant me the flames of Engine!")
channel_time = 10
required_components = list(BELLIGERENT_EYE = 2)
consumed_components = list(BELLIGERENT_EYE = 1)
whispered = TRUE
object_path = /obj/item/clothing/glasses/judicial_visor
creator_message = "<span class='brass'>You form a judicial visor, which is capable of smiting the unworthy.</span>"
usage_tip = "The visor has a thirty-second cooldown once used, and the marker it creates has a delay of 3 seconds before exploding."
tier = SCRIPTURE_DRIVER
space_allowed = TRUE
primary_component = BELLIGERENT_EYE
sort_priority = 2
//Vanguard: Provides twenty seconds of stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker.
/datum/clockwork_scripture/vanguard
descname = "Self Stun Immunity"
name = "Vanguard"
desc = "Provides twenty seconds of stun immunity. At the end of the twenty seconds, the invoker is stunned for the equivalent of 25% of all stuns they absorbed. \
Excessive absorption will cause unconsciousness."
invocations = list("Shield me...", "...from darkness!")
channel_time = 30
required_components = list(VANGUARD_COGWHEEL = 1)
usage_tip = "You cannot reactivate Vanguard while still shielded by it."
tier = SCRIPTURE_DRIVER
primary_component = VANGUARD_COGWHEEL
sort_priority = 3
quickbind = TRUE
quickbind_desc = "Allows you to temporarily absorb stuns. All stuns absorbed will affect you when disabled."
/datum/clockwork_scripture/vanguard/check_special_requirements()
if(islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time)
invoker << "<span class='warning'>You are already shielded by a Vanguard!</span>"
return FALSE
return TRUE
/datum/clockwork_scripture/vanguard/scripture_effects()
invoker.apply_status_effect(STATUS_EFFECT_VANGUARD)
return TRUE
//Sentinel's Compromise: Allows the invoker to select a nearby servant and convert their brute and burn damage into half as much toxin damage.
/datum/clockwork_scripture/ranged_ability/sentinels_compromise
descname = "Convert Brute/Burn to Half Toxin"
name = "Sentinel's Compromise"
desc = "Charges your slab with healing power, allowing you to convert all of a target Servant's brute and burn damage to half as much toxin damage."
invocations = list("Mend the wounds of...", "...my inferior flesh.")
channel_time = 30
required_components = list(VANGUARD_COGWHEEL = 2)
consumed_components = list(VANGUARD_COGWHEEL = 1)
usage_tip = "The Compromise is very fast to invoke, and will remove holy water from the target Servant."
tier = SCRIPTURE_DRIVER
primary_component = VANGUARD_COGWHEEL
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Allows you to convert a Servant's brute and burn damage to half toxin damage.<br><b>Click your slab to disable.</b>"
slab_icon = "compromise"
ranged_type = /obj/effect/proc_holder/slab/compromise
ranged_message = "<span class='inathneq_small'><i>You charge the clockwork slab with healing power.</i>\n\
<b>Left-click a fellow Servant or yourself to heal!\n\
Click your slab to cancel.</b></span>"
//Geis: Grants a short-range binding that will immediately start chanting on binding a valid target.
/datum/clockwork_scripture/ranged_ability/geis_prep
descname = "Melee Convert Attack"
name = "Geis"
desc = "Charges your slab with divine energy, allowing you to bind a nearby heretic for conversion. This is very obvious and will make your slab visible in-hand."
invocations = list("Divinity, grant...", "...me strength...", "...to enlighten...", "...the heathen!")
whispered = TRUE
channel_time = 20
required_components = list(GEIS_CAPACITOR = 1)
usage_tip = "Is melee range and does not penetrate mindshield implants. Much more efficient than a Sigil of Submission at low Servant amounts."
tier = SCRIPTURE_DRIVER
primary_component = GEIS_CAPACITOR
sort_priority = 5
quickbind = TRUE
quickbind_desc = "Allows you to bind and start converting an adjacent target non-Servant.<br><b>Click your slab to disable.</b>"
slab_icon = "geis"
ranged_type = /obj/effect/proc_holder/slab/geis
ranged_message = "<span class='sevtug_small'><i>You charge the clockwork slab with divine energy.</i>\n\
<b>Left-click a target within melee range to convert!\n\
Click your slab to cancel.</b></span>"
timeout_time = 100
/datum/clockwork_scripture/ranged_ability/geis_prep/run_scripture()
var/servants = 0
for(var/mob/living/M in living_mob_list)
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
servants++
if(servants > SCRIPT_SERVANT_REQ)
whispered = FALSE
servants -= SCRIPT_SERVANT_REQ
channel_time = min(channel_time + servants*3, 50)
return ..()
//The scripture that does the converting.
/datum/clockwork_scripture/geis
name = "Geis Conversion"
invocations = list("Enlighten this heathen!", "All are insects before Engine!", "Purge all untruths and honor Engine.")
channel_time = 49
tier = SCRIPTURE_PERIPHERAL
var/mob/living/target
var/obj/structure/destructible/clockwork/geis_binding/binding
/datum/clockwork_scripture/geis/Destroy()
if(binding && !qdeleted(binding))
qdel(binding)
return ..()
/datum/clockwork_scripture/geis/can_recite()
if(!target)
return FALSE
return ..()
/datum/clockwork_scripture/geis/run_scripture()
var/servants = 0
for(var/mob/living/M in living_mob_list)
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
servants++
if(servants > SCRIPT_SERVANT_REQ)
servants -= SCRIPT_SERVANT_REQ
channel_time = min(channel_time + servants*7, 120)
if(target.buckled)
target.buckled.unbuckle_mob(target, TRUE)
binding = new(get_turf(target))
binding.setDir(target.dir)
binding.buckle_mob(target, TRUE)
return ..()
/datum/clockwork_scripture/geis/check_special_requirements()
return target && binding && target.buckled == binding && !is_servant_of_ratvar(target) && target.stat != DEAD
/datum/clockwork_scripture/geis/scripture_effects()
return add_servant_of_ratvar(target)
//Taunting Tirade: Channeled for up to five times over thirty seconds. Confuses non-servants that can hear it and allows movement for a brief time after each chant.
/datum/clockwork_scripture/channeled/taunting_tirade
descname = "Channeled, Mobile Area Confusion"
name = "Taunting Tirade"
desc = "Weakens, confuses and dizzies all nearby non-servants with a short invocation, then allows movement for five seconds. Chanted every second for up to thirty seconds."
chant_invocations = list("Hostiles on my back!", "Enemies on my trail!", "Gonna try and shake my tail.", "Bogeys on my six!")
chant_amount = 5
chant_interval = 10
required_components = list(GEIS_CAPACITOR = 2)
consumed_components = list(GEIS_CAPACITOR = 1)
usage_tip = "Useful for fleeing attackers, as few will be able to follow someone using this scripture."
tier = SCRIPTURE_DRIVER
primary_component = GEIS_CAPACITOR
sort_priority = 6
quickbind = TRUE
quickbind_desc = "Weakens, confuses, and dizzies nearby non-servants, then allows some movement.<br><b>Maximum 5 chants.</b>"
var/flee_time = 47 //allow fleeing for 5 seconds
var/grace_period = 3 //very short grace period so you don't have to stop immediately
var/datum/progressbar/progbar
/datum/clockwork_scripture/channeled/taunting_tirade/chant_effects(chant_number)
for(var/mob/living/L in hearers(7, invoker))
if(!is_servant_of_ratvar(L) && !L.null_rod_check())
L.confused = min(L.confused + 20, 100)
L.dizziness = min(L.dizziness + 20, 100)
L.Weaken(1)
invoker.visible_message("<span class='warning'>[invoker] is suddenly covered with a thin layer of dark purple smoke!</span>")
var/invoker_old_color = invoker.color
invoker.color = "#AF0AAF"
animate(invoker, color = invoker_old_color, time = flee_time+grace_period)
addtimer(invoker, "update_atom_colour", flee_time+grace_period)
if(chant_number != chant_amount) //if this is the last chant, we don't have a movement period because the chant is over
var/endtime = world.time + flee_time
var/starttime = world.time
progbar = new(invoker, flee_time, invoker)
progbar.bar.color = "#AF0AAF"
animate(progbar.bar, color = initial(progbar.bar.color), time = flee_time+grace_period)
while(world.time < endtime && invoker && slab && invoker.get_active_held_item() == slab)
sleep(1)
progbar.update(world.time - starttime)
qdel(progbar)
sleep(grace_period)
/datum/clockwork_scripture/channeled/taunting_tirade/chant_end_effects()
qdel(progbar)
//Replicant: Creates a new clockwork slab.
/datum/clockwork_scripture/create_object/replicant
descname = "New Clockwork Slab"
name = "Replicant"
desc = "Creates a new clockwork slab."
invocations = list("Metal, become greater!")
channel_time = 10
required_components = list(REPLICANT_ALLOY = 1)
whispered = TRUE
object_path = /obj/item/clockwork/slab
creator_message = "<span class='brass'>You copy a piece of replicant alloy and command it into a new slab.</span>"
usage_tip = "This is inefficient as a way to produce components, as the slab produced must be held by someone with no other slabs to produce components."
tier = SCRIPTURE_DRIVER
space_allowed = TRUE
primary_component = REPLICANT_ALLOY
sort_priority = 7
quickbind = TRUE
quickbind_desc = "Creates a new Clockwork Slab."
//Tinkerer's Cache: Creates a tinkerer's cache, allowing global component storage.
/datum/clockwork_scripture/create_object/tinkerers_cache
descname = "Necessary Structure, Shares Components"
name = "Tinkerer's Cache"
desc = "Forms a cache that can store an infinite amount of components. All caches are linked and will provide components to slabs."
invocations = list("Constructing...", "...a cache!")
channel_time = 50
required_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 0)
consumed_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 0)
object_path = /obj/structure/destructible/clockwork/cache
creator_message = "<span class='brass'>You form a tinkerer's cache, which is capable of storing components, which will automatically be used by slabs.</span>"
observer_message = "<span class='warning'>A hollow brass spire rises and begins to blaze!</span>"
usage_tip = "Slabs will draw components from the global cache after the slab's own repositories, making caches very efficient."
tier = SCRIPTURE_DRIVER
one_per_tile = TRUE
primary_component = REPLICANT_ALLOY
sort_priority = 8
quickbind = TRUE
quickbind_desc = "Creates a Tinkerer's Cache, which stores components globally for slab access."
/datum/clockwork_scripture/create_object/tinkerers_cache/creation_update()
var/cache_cost_increase = min(round(clockwork_caches*0.25), 5)
required_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 0)
consumed_components = list(BELLIGERENT_EYE = 0, VANGUARD_COGWHEEL = 0, GEIS_CAPACITOR = 0, REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 0)
for(var/i in required_components)
if(i != REPLICANT_ALLOY)
required_components[i] += cache_cost_increase
for(var/i in consumed_components)
if(i != REPLICANT_ALLOY)
consumed_components[i] += cache_cost_increase
//Wraith Spectacles: Creates a pair of wraith spectacles, which grant xray vision but damage vision slowly.
/datum/clockwork_scripture/create_object/wraith_spectacles
descname = "Xray Vision Glasses"
name = "Wraith Spectacles"
desc = "Fabricates a pair of glasses that provides true sight but quickly damage vision, eventually causing blindness if worn for too long."
invocations = list("Show the truth of this world to me!")
channel_time = 10
required_components = list(HIEROPHANT_ANSIBLE = 1)
whispered = TRUE
object_path = /obj/item/clothing/glasses/wraith_spectacles
creator_message = "<span class='brass'>You form a pair of wraith spectacles, which will grant true sight when worn.</span>"
usage_tip = "\"True sight\" means that you are able to see through walls and in darkness."
tier = SCRIPTURE_DRIVER
space_allowed = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 9
//Sigil of Transgression: Creates a sigil of transgression, which stuns the first nonservant to cross it.
/datum/clockwork_scripture/create_object/sigil_of_transgression
descname = "Trap, Stunning"
name = "Sigil of Transgression"
desc = "Wards a tile with a sigil. The next person to cross the sigil will be smitten and unable to move. Nar-Sian cultists are stunned altogether."
invocations = list("Divinity, dazzle...", "...those who tresspass here!")
channel_time = 50
required_components = list(HIEROPHANT_ANSIBLE = 2)
consumed_components = list(HIEROPHANT_ANSIBLE = 1)
whispered = TRUE
object_path = /obj/effect/clockwork/sigil/transgression
creator_message = "<span class='brass'>A sigil silently appears below you. The next non-servant to cross it will be immobilized.</span>"
usage_tip = "The sigil, while fairly powerful in its stun, does not induce muteness in its victim."
tier = SCRIPTURE_DRIVER
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 10
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Transgression, which will stun the first non-Servant to cross it."
@@ -0,0 +1,58 @@
///////////////
// JUDGEMENT //
///////////////
//Ark of the Clockwork Justiciar: Creates a Gateway to the Celestial Derelict, either summoning ratvar or proselytizing everything.
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar
descname = "Structure, Win Condition"
name = "Ark of the Clockwork Justiciar"
desc = "Tears apart a rift in spacetime to Reebe, the Celestial Derelict.\n\
This gateway will either call forth Ratvar from his exile if that is the task He has set you, or proselytize the entire station if it is not."
invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! I CALL UPON YOU!!", \
"THE TIME HAS COME FOR OUR MASTER TO BREAK THE CHAINS OF EXILE!!", \
"LEND US YOUR AID! ENGINE COMES!!")
channel_time = 150
required_components = list(BELLIGERENT_EYE = 10, VANGUARD_COGWHEEL = 10, GEIS_CAPACITOR = 10, REPLICANT_ALLOY = 10, HIEROPHANT_ANSIBLE = 10)
consumed_components = list(BELLIGERENT_EYE = 10, VANGUARD_COGWHEEL = 10, GEIS_CAPACITOR = 10, REPLICANT_ALLOY = 10, HIEROPHANT_ANSIBLE = 10)
invokers_required = 5
multiple_invokers_used = TRUE
usage_tip = "The gateway is completely vulnerable to attack during its five-minute duration. It will periodically give indication of its general position to everyone on the station \
as well as being loud enough to be heard throughout the entire sector. Defend it with your life!"
tier = SCRIPTURE_JUDGEMENT
sort_priority = 1
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/New()
if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY)
invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! I CALL UPON YOU!!", \
"THIS STATION WILL BE A BEACON OF HOPE IN THE DARKNESS OF SPACE!!", \
"HELP US MAKE THIS SHOW ENGINE'S GLORY!!")
..()
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/check_special_requirements()
if(!slab.no_cost)
if(ratvar_awakens)
invoker << "<span class='big_brass'>\"I am already here, idiot.\"</span>"
return FALSE
for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in all_clockwork_objects)
var/area/gate_area = get_area(G)
invoker << "<span class='userdanger'>There is already a gateway at [gate_area.map_name]!</span>"
return FALSE
var/area/A = get_area(invoker)
var/turf/T = get_turf(invoker)
if(!T || T.z != ZLEVEL_STATION || istype(A, /area/shuttle))
invoker << "<span class='warning'>You must be on the station to activate the Ark!</span>"
return FALSE
if(clockwork_gateway_activated)
if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY)
invoker << "<span class='nezbere'>\"Look upon his works. Is it not glorious?\"</span>"
else
invoker << "<span class='warning'>Ratvar's recent banishment renders him too weak to be wrung forth from Reebe!</span>"
return FALSE
return TRUE
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/scripture_effects()
var/turf/T = get_turf(invoker)
if(T)
new/obj/structure/destructible/clockwork/massive/celestial_gateway(T)
return TRUE
return FALSE
@@ -0,0 +1,229 @@
//////////////
// REVENANT //
//////////////
//Invoke Inath-neq, the Resonant Cogwheel: Grants invulnerability and stun immunity to everyone nearby for 15 seconds.
/datum/clockwork_scripture/invoke_inathneq
descname = "Area Invulnerability"
name = "Invoke Inath-neq, the Resonant Cogwheel"
desc = "Taps the limitless power of Inath-neq, one of Ratvar's four generals. The benevolence of Inath-Neq will grant complete invulnerability to all servants in range for fifteen seconds."
invocations = list("I call upon you, Vanguard!!", "Let the Resonant Cogs turn once more!!", "Grant me and my allies the strength to vanquish our foes!!")
channel_time = 150
required_components = list(VANGUARD_COGWHEEL = 6, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 3)
consumed_components = list(VANGUARD_COGWHEEL = 6, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 3)
usage_tip = "Those affected by this scripture are only weak to things that outright destroy bodies, such as bombs or the singularity."
tier = SCRIPTURE_REVENANT
primary_component = VANGUARD_COGWHEEL
sort_priority = 2
/datum/clockwork_scripture/invoke_inathneq/check_special_requirements()
if(!slab.no_cost && clockwork_generals_invoked["inath-neq"] > world.time)
invoker << "<span class='inathneq'>\"[text2ratvar("I cannot lend you my aid yet, champion. Please be careful.")]\"</span>\n\
<span class='warning'>Inath-neq has already been invoked recently! You must wait several minutes before calling upon the Resonant Cogwheel.</span>"
return FALSE
return TRUE
/datum/clockwork_scripture/invoke_inathneq/scripture_effects()
new/obj/effect/clockwork/general_marker/inathneq(get_turf(invoker))
hierophant_message("<span class='inathneq_large'>[text2ratvar("Vanguard: \"I lend you my aid, champions! Let glory guide your blows!")]\"</span>", FALSE, invoker)
clockwork_generals_invoked["inath-neq"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
if(invoker.real_name == "Lucio")
clockwork_say(invoker, text2ratvar("Aww, let's break it DOWN!!"))
for(var/mob/living/L in range(7, invoker))
if(!is_servant_of_ratvar(L) || L.stat == DEAD)
continue
L.apply_status_effect(STATUS_EFFECT_INATHNEQS_ENDOWMENT)
return TRUE
//Invoke Sevtug, the Formless Pariah: Causes massive global hallucinations, braindamage, confusion, and dizziness to all humans on the same zlevel.
/datum/clockwork_scripture/invoke_sevtug
descname = "Global Hallucination"
name = "Invoke Sevtug, the Formless Pariah"
desc = "Taps the limitless power of Sevtug, one of Ratvar's four generals. The mental manipulation ability of the Pariah allows its wielder to cause mass hallucinations and confusion \
for all non-servant humans on the same z-level as them. The power of this scripture falls off somewhat with distance, and certain things may reduce its effects."
invocations = list("I call upon you, Fright!!", "Let your power shatter the sanity of the weak-minded!!", "Let your tendrils hold sway over all!!")
channel_time = 150
required_components = list(BELLIGERENT_EYE = 3, VANGUARD_COGWHEEL = 3, GEIS_CAPACITOR = 6, HIEROPHANT_ANSIBLE = 3)
consumed_components = list(BELLIGERENT_EYE = 3, VANGUARD_COGWHEEL = 3, GEIS_CAPACITOR = 6, HIEROPHANT_ANSIBLE = 3)
usage_tip = "Causes brain damage, hallucinations, confusion, and dizziness in massive amounts."
tier = SCRIPTURE_REVENANT
sort_priority = 3
primary_component = GEIS_CAPACITOR
invokers_required = 3
multiple_invokers_used = TRUE
var/static/list/mindbreaksayings = list("\"Oh, great. I get to shatter some minds.\"", "\"More minds to crush.\"", \
"\"Really, this is almost boring.\"", "\"None of these minds have anything interesting in them.\"", "\"Maybe I can instill a little bit of terror in this one.\"", \
"\"What a waste of my power.\"", "\"I'm sure I could just control these minds instead, but they never ask.\"")
/datum/clockwork_scripture/invoke_sevtug/check_special_requirements()
if(!slab.no_cost && clockwork_generals_invoked["sevtug"] > world.time)
invoker << "<span class='sevtug'>\"[text2ratvar("Is it really so hard - even for a simpleton like you - to grasp the concept of waiting?")]\"</span>\n\
<span class='warning'>Sevtug has already been invoked recently! You must wait several minutes before calling upon the Formless Pariah.</span>"
return FALSE
if(!slab.no_cost && ratvar_awakens)
invoker << "<span class='sevtug'>\"[text2ratvar("Do you really think anything I can do right now will compare to Engine's power?")]\"</span>\n\
<span class='warning'>Sevtug will not grant his power while Ratvar's dwarfs his own!</span>"
return FALSE
return TRUE
/datum/clockwork_scripture/invoke_sevtug/scripture_effects()
new/obj/effect/clockwork/general_marker/sevtug(get_turf(invoker))
hierophant_message("<span class='sevtug_large'>[text2ratvar("Fright: \"I heed your call, idiots. Get going and use this chance while it lasts!")]\"</span>", FALSE, invoker)
clockwork_generals_invoked["sevtug"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected
var/turf/T = get_turf(invoker)
for(var/mob/living/carbon/human/H in living_mob_list)
if(H.z == invoker.z && !is_servant_of_ratvar(H))
var/distance = 0
distance += get_dist(T, get_turf(H))
var/visualsdistance = max(150 - distance, 5)
var/minordistance = max(200 - distance*2, 5)
var/majordistance = max(150 - distance*3, 5)
if(H.null_rod_check())
H << "<span class='sevtug'>[text2ratvar("Oh, a void weapon. How annoying, I may as well not bother.")]</span>\n\
<span class='warning'>Your holy weapon glows a faint orange, defending your mind!</span>"
continue
else if(H.isloyal())
visualsdistance = round(visualsdistance * 0.5) //half effect for shielded targets
minordistance = round(minordistance * 0.5)
majordistance = round(majordistance * 0.5)
H << "<span class='sevtug'>[text2ratvar("Oh, look, a mindshield. Cute, I suppose I'll humor it.")]</span>"
else if(prob(visualsdistance))
H << "<span class='sevtug'>[text2ratvar(pick(mindbreaksayings))]</span>"
H.playsound_local(T, hum, visualsdistance, 1)
flash_color(H, flash_color="#AF0AAF", flash_time=visualsdistance*10)
H.dizziness = minordistance + H.dizziness
H.hallucination = minordistance + H.hallucination
H.confused = majordistance + H.confused
H.setBrainLoss(majordistance + H.getBrainLoss())
return TRUE
//Invoke Nezbere, the Brass Eidolon: Invokes Nezbere, bolstering the strength of many clockwork items for one minute.
/datum/clockwork_scripture/invoke_nezbere
descname = "Global Structure Buff"
name = "Invoke Nezbere, the Brass Eidolon"
desc = "Taps the limitless power of Nezbere, one of Ratvar's four generals. The restless toil of the Eidolon will empower a wide variety of clockwork apparatus for a full minute - notably, \
clockwork proselytizers will cost no replicant alloy to use."
invocations = list("I call upon you, Armorer!!", "Let your machinations reign on this miserable station!!", "Let your power flow through the tools of your master!!")
channel_time = 150
required_components = list(BELLIGERENT_EYE = 3, VANGUARD_COGWHEEL = 3, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 6)
consumed_components = list(BELLIGERENT_EYE = 3, VANGUARD_COGWHEEL = 3, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 6)
usage_tip = "Ocular wardens will become empowered, clockwork proselytizers will require no alloy, tinkerer's daemons will produce twice as quickly, \
and interdiction lenses, mending motors, mania motors, tinkerer's daemons, and clockwork obelisks will all require no power."
tier = SCRIPTURE_REVENANT
primary_component = REPLICANT_ALLOY
sort_priority = 4
invokers_required = 3
multiple_invokers_used = TRUE
/datum/clockwork_scripture/invoke_nezbere/check_special_requirements()
if(!slab.no_cost && clockwork_generals_invoked["nezbere"] > world.time)
invoker << "<span class='nezbere'>\"[text2ratvar("Not just yet, friend. Patience is a virtue.")]\"</span>\n\
<span class='warning'>Nezbere has already been invoked recently! You must wait several minutes before calling upon the Brass Eidolon.</span>"
return FALSE
if(!slab.no_cost && ratvar_awakens)
invoker << "<span class='nezbere'>\"[text2ratvar("Our master is here already. You do not require my help, friend.")]\"</span>\n\
<span class='warning'>Nezbere will not grant his power while Ratvar's dwarfs his own!</span>"
return FALSE
return TRUE
/datum/clockwork_scripture/invoke_nezbere/scripture_effects()
new/obj/effect/clockwork/general_marker/nezbere(get_turf(invoker))
hierophant_message("<span class='nezbere_large'>[text2ratvar("Armorer: \"I heed your call, champions. May your artifacts bring ruin upon the heathens that oppose our master!")]\"</span>", FALSE, invoker)
clockwork_generals_invoked["nezbere"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
for(var/obj/structure/destructible/clockwork/ocular_warden/W in all_clockwork_objects) //Ocular wardens have increased damage and radius
W.damage_per_tick = 5
W.sight_range = 5
for(var/obj/item/clockwork/clockwork_proselytizer/P in all_clockwork_objects) //Proselytizers no longer require alloy
P.uses_alloy = FALSE
for(var/obj/structure/destructible/clockwork/powered/M in all_clockwork_objects) //Powered clockwork structures no longer need power
M.needs_power = FALSE
if(istype(M, /obj/structure/destructible/clockwork/powered/tinkerers_daemon)) //Daemons produce components twice as quickly
var/obj/structure/destructible/clockwork/powered/tinkerers_daemon/D = M
D.production_time = 0
D.production_cooldown *= 0.5
spawn(600)
for(var/obj/structure/destructible/clockwork/ocular_warden/W in all_clockwork_objects)
if(W.damage_per_tick == 5)
W.damage_per_tick = initial(W.damage_per_tick)
if(W.sight_range == 5)
W.sight_range = initial(W.sight_range)
for(var/obj/item/clockwork/clockwork_proselytizer/P in all_clockwork_objects)
P.uses_alloy = initial(P.uses_alloy)
for(var/obj/structure/destructible/clockwork/powered/M in all_clockwork_objects)
M.needs_power = initial(M.needs_power)
if(istype(M, /obj/structure/destructible/clockwork/powered/tinkerers_daemon))
var/obj/structure/destructible/clockwork/powered/tinkerers_daemon/D = M
D.production_cooldown = initial(D.production_cooldown)
return TRUE
//Invoke Nzcrentr, the Eternal Thunderbolt: Imbues an immense amount of energy into the invoker. After several seconds, everyone near the invoker will be hit with a devastating lightning blast.
/datum/clockwork_scripture/invoke_nzcrentr
descname = "Area Lightning Blast"
name = "Invoke Nzcrentr, the Eternal Thunderbolt"
desc = "Taps the limitless power of Nzcrentr, one of Ratvar's four generals. The immense energy Nzcrentr wields will allow you to imbue a tiny fraction of it into your body. After several \
seconds, anyone near you will be struck by a devastating lightning bolt."
invocations = list("I call upon you, Amperage!!", "Let your energy flow through me!!", "Let your boundless power shatter stars!!")
channel_time = 150
required_components = list(BELLIGERENT_EYE = 3, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 6)
consumed_components = list(BELLIGERENT_EYE = 3, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 6)
usage_tip = "Struck targets will also be knocked down for about sixteen seconds."
tier = SCRIPTURE_REVENANT
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 5
/datum/clockwork_scripture/invoke_nzcrentr/check_special_requirements()
if(!slab.no_cost && clockwork_generals_invoked["nzcrentr"] > world.time)
invoker << "<span class='nzcrentr'>\"[text2ratvar("The boss says you have to wait. Hey, do you think he would mind if I killed you? ...He would? Ok.")]\"</span>\n\
<span class='warning'>Nzcrentr has already been invoked recently! You must wait several minutes before calling upon the Eternal Thunderbolt.</span>"
return FALSE
return TRUE
/datum/clockwork_scripture/invoke_nzcrentr/scripture_effects()
new/obj/effect/clockwork/general_marker/nzcrentr(get_turf(invoker))
clockwork_generals_invoked["nzcrentr"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
hierophant_message("<span class='nzcrentr_large'>[text2ratvar("Amperage: \"[invoker.real_name] has called forth my power. Hope [invoker.p_they()] [invoker.p_do()] not shatter under it!")]\"</span>", FALSE, invoker)
invoker.visible_message("<span class='warning'>[invoker] begins to radiate a blinding light!</span>", \
"<span class='nzcrentr'>\"[text2ratvar("The boss says it's okay to do this. Don't blame me if you die from it.")]\"</span>\n \
<span class='userdanger'>You feel limitless power surging through you!</span>")
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
playsound(invoker, 'sound/magic/lightning_chargeup.ogg', 100, 0)
var/oldcolor = invoker.color
animate(invoker, color = list(rgb(255, 255, 255), rgb(255, 255, 255), rgb(255, 255, 255), rgb(0,0,0)), time = 88) //Gradual advancement to extreme brightness
sleep(88)
if(invoker)
invoker.visible_message("<span class='warning'>Massive bolts of energy emerge from across [invoker]'s body!</span>", \
"<span class='nzcrentr'>\"[text2ratvar("I told you you wouldn't be able to handle it.")]\"</span>\n \
<span class='userdanger'>TOO... MUCH! CAN'T... TAKE IT!</span>")
playsound(invoker, 'sound/magic/lightningbolt.ogg', 100, 0)
if(invoker.stat == CONSCIOUS)
animate(invoker, color = oldcolor, time = 10)
addtimer(invoker, "update_atom_colour", 10)
for(var/mob/living/L in view(7, invoker))
if(is_servant_of_ratvar(L) || L.null_rod_check())
continue
invoker.Beam(L, icon_state = "nzcrentrs_power", time = 10)
var/randdamage = rand(40, 60)
if(iscarbon(L))
L.electrocute_act(randdamage, "Nzcrentr's power", 1, randdamage)
else
L.adjustFireLoss(randdamage)
L.visible_message(
"<span class='danger'>[L] was shocked by Nzcrentr's power!</span>", \
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>", \
"<span class='italics'>You hear a heavy electrical crack.</span>" \
)
L.Weaken(8)
playsound(L, 'sound/magic/LightningShock.ogg', 50, 1)
else
playsound(invoker, 'sound/magic/Disintegrate.ogg', 50, 1)
invoker.gib()
return TRUE
else
return FALSE
@@ -0,0 +1,329 @@
/////////////
// SCRIPTS //
/////////////
//Ocular Warden: Creates an ocular warden, which defends a small area near it.
/datum/clockwork_scripture/create_object/ocular_warden
descname = "Structure, Turret"
name = "Ocular Warden"
desc = "Forms an automatic short-range turret that deals low sustained damage to the unenlightened in its range."
invocations = list("Guardians...", "...of the Engine...", "...defend us!")
channel_time = 120
required_components = list(BELLIGERENT_EYE = 2, REPLICANT_ALLOY = 1)
consumed_components = list(BELLIGERENT_EYE = 1, REPLICANT_ALLOY = 1)
object_path = /obj/structure/destructible/clockwork/ocular_warden
creator_message = "<span class='brass'>You form an ocular warden, which will focus its searing gaze upon nearby unenlightened.</span>"
observer_message = "<span class='warning'>A brass eye takes shape and slowly rises into the air, its red iris glaring!</span>"
usage_tip = "Although powerful, the warden is very fragile and should optimally be placed behind barricades."
tier = SCRIPTURE_SCRIPT
one_per_tile = TRUE
space_allowed = TRUE
primary_component = BELLIGERENT_EYE
sort_priority = 1
quickbind = TRUE
quickbind_desc = "Creates an Ocular Warden, which will automatically attack nearby unrestrained non-Servants that can see it."
/datum/clockwork_scripture/create_object/ocular_warden/check_special_requirements()
for(var/obj/structure/destructible/clockwork/ocular_warden/W in range(3, invoker))
invoker << "<span class='neovgre'>You sense another ocular warden too near this location. Placing another this close would cause them to fight.</span>" //fluff message
return FALSE
return ..()
//Cogscarab: Creates an empty cogscarab shell, which produces a cogscarab dedicated to maintaining and defending the cult.
/datum/clockwork_scripture/create_object/cogscarab
descname = "Constructor Soul Vessel Shell"
name = "Cogscarab"
desc = "Creates a small shell fitted for soul vessels. Adding an active soul vessel to it results in a small construct with tools and an inbuilt proselytizer."
invocations = list("Call forth...", "...the workers of Armorer.")
channel_time = 60
required_components = list(BELLIGERENT_EYE = 2, HIEROPHANT_ANSIBLE = 1)
consumed_components = list(BELLIGERENT_EYE = 1, HIEROPHANT_ANSIBLE = 1)
object_path = /obj/structure/destructible/clockwork/shell/cogscarab
creator_message = "<span class='brass'>You form a cogscarab, a constructor soul vessel receptable.</span>"
observer_message = "<span class='warning'>The slab disgorges a puddle of black metal that contracts and forms into a strange shell!</span>"
usage_tip = "Useless without a soul vessel and should not be created without one."
tier = SCRIPTURE_SCRIPT
primary_component = BELLIGERENT_EYE
sort_priority = 2
quickbind = TRUE
quickbind_desc = "Creates a Cogscarab Shell, which produces a Cogscarab when filled with a Soul Vessel."
//Fellowship Armory: Arms the invoker and nearby servants with Ratvarian armor.
/datum/clockwork_scripture/fellowship_armory
descname = "Area Servant Armor"
name = "Fellowship Armory"
desc = "Equips the invoker and any nearby servants with Ratvarian armor. This armor provides high melee resistance but a weakness to lasers. \
It grows faster to invoke with more nearby servants."
invocations = list("Shield us...", "...with the...", "... fragments of Engine!")
channel_time = 100
required_components = list(VANGUARD_COGWHEEL = 2, REPLICANT_ALLOY = 1)
consumed_components = list(VANGUARD_COGWHEEL = 1, REPLICANT_ALLOY = 1)
usage_tip = "Before using, advise adjacent allies to remove their helmets, external suits, gloves, and shoes."
tier = SCRIPTURE_SCRIPT
multiple_invokers_used = TRUE
multiple_invokers_optional = TRUE
primary_component = VANGUARD_COGWHEEL
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Attempts to armor all nearby Servants with powerful Ratvarian armor."
/datum/clockwork_scripture/fellowship_armory/run_scripture()
for(var/mob/living/L in orange(1, get_turf(invoker)))
if(is_servant_of_ratvar(L) && L.can_speak_vocal())
channel_time = max(channel_time - 10, 0)
return ..()
/datum/clockwork_scripture/fellowship_armory/scripture_effects()
var/affected = 0
for(var/mob/living/L in range(1, invoker))
if(!is_servant_of_ratvar(L))
continue
var/do_message = 0
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), slot_head)
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), slot_wear_suit)
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), slot_gloves)
do_message += L.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), slot_shoes)
if(do_message)
L.visible_message("<span class='warning'>Strange armor appears on [L]!</span>", "<span class='heavy_brass'>A bright shimmer runs down your body, equipping you with Ratvarian armor.</span>")
playsound(L, 'sound/magic/clockwork/fellowship_armory.ogg', 15*do_message, 1) //get sound loudness based on how much we equipped
affected++
return affected
//Sigil of Submission: Creates a sigil of submission, which converts one heretic above it after a delay.
/datum/clockwork_scripture/create_object/sigil_of_submission
descname = "Trap, Conversion"
name = "Sigil of Submission"
desc = "Places a luminous sigil that will enslave any valid beings standing on it after a time."
invocations = list("Divinity, enlighten...", "...those who trespass here!")
channel_time = 60
required_components = list(BELLIGERENT_EYE = 1, GEIS_CAPACITOR = 2)
consumed_components = list(BELLIGERENT_EYE = 1, GEIS_CAPACITOR = 1)
whispered = TRUE
object_path = /obj/effect/clockwork/sigil/submission
creator_message = "<span class='brass'>A luminous sigil appears below you. The next non-servant to cross it will be enslaved after a brief time if they do not move.</span>"
usage_tip = "This is not a primary conversion method - use Geis for that. It is advantageous as a trap, however, as it will transmit the name of the newly-converted."
tier = SCRIPTURE_SCRIPT
one_per_tile = TRUE
primary_component = GEIS_CAPACITOR
sort_priority = 5
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Submission, which will convert one non-Servant that remains on it."
//Soul Vessel: Creates a soul vessel, which can seek a ghost or be used on the uncovered head of a dead or dying human to take their brain.
/datum/clockwork_scripture/create_object/soul_vessel
descname = "Clockwork Posibrain"
name = "Soul Vessel"
desc = "Forms an ancient positronic brain with an overriding directive to serve Ratvar."
invocations = list("Herd the souls of...", "...the blasphemous damned!")
channel_time = 30
required_components = list(VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 2)
consumed_components = list(VANGUARD_COGWHEEL = 1, GEIS_CAPACITOR = 1)
whispered = TRUE
object_path = /obj/item/device/mmi/posibrain/soul_vessel
creator_message = "<span class='brass'>You form a soul vessel, which can be used in-hand to attract spirits, or used on an unconscious or dead human to extract their consciousness.</span>"
usage_tip = "The vessel can be used as a teleport target for Spatial Gateway, though it is generally better-used by placing it in a shell or cyborg body."
tier = SCRIPTURE_SCRIPT
space_allowed = TRUE
primary_component = GEIS_CAPACITOR
sort_priority = 6
quickbind = TRUE
quickbind_desc = "Creates a Soul Vessel, which can be placed in construct shells and cyborg bodies once filled."
//Clockwork Proselytizer: Creates a clockwork proselytizer, used to convert objects and repair clockwork structures.
/datum/clockwork_scripture/create_object/clockwork_proselytizer
descname = "Converts Objects to Ratvarian"
name = "Clockwork Proselytizer"
desc = "Forms a device that, when used on certain objects, converts them into their Ratvarian equivalents. It requires replicant alloy to function."
invocations = list("With this device...", "...his presence shall be made known.")
channel_time = 20
required_components = list(GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 2)
consumed_components = list(GEIS_CAPACITOR = 1, REPLICANT_ALLOY = 1)
whispered = TRUE
object_path = /obj/item/clockwork/clockwork_proselytizer/preloaded
creator_message = "<span class='brass'>You form a clockwork proselytizer, which is already pre-loaded with a small amount of replicant alloy.</span>"
usage_tip = "Clockwork Walls cause nearby tinkerer's caches to generate components passively, making them a vital tool. Clockwork Floors heal toxin damage in Servants standing on them."
tier = SCRIPTURE_SCRIPT
space_allowed = TRUE
primary_component = REPLICANT_ALLOY
sort_priority = 7
quickbind = TRUE
quickbind_desc = "Creates a Clockwork Proselytizer, which can convert various objects to Ratvarian variants."
//Function Call: Grants the invoker the ability to call forth a Ratvarian spear that deals significant damage to silicons.
/datum/clockwork_scripture/function_call
descname = "Permenant Summonable Spear"
name = "Function Call"
desc = "Grants the invoker the ability to call forth a powerful Ratvarian spear every three minutes. The spear will deal significant damage to Nar-Sie's dogs and silicon lifeforms, but will \
vanish three minutes after being summoned."
invocations = list("Grant me...", "...the might of brass!")
channel_time = 20
required_components = list(REPLICANT_ALLOY = 2, HIEROPHANT_ANSIBLE = 1)
consumed_components = list(REPLICANT_ALLOY = 1, HIEROPHANT_ANSIBLE = 1)
whispered = TRUE
usage_tip = "You can impale human targets with the spear by pulling them, then attacking. Throwing the spear at a mob will do massive damage and stun them, but break the spear."
tier = SCRIPTURE_SCRIPT
primary_component = REPLICANT_ALLOY
sort_priority = 8
/datum/clockwork_scripture/function_call/check_special_requirements()
for(var/datum/action/innate/function_call/F in invoker.actions)
invoker << "<span class='warning'>You have already bound a Ratvarian spear to yourself!</span>"
return FALSE
return invoker.can_hold_items()
/datum/clockwork_scripture/function_call/scripture_effects()
invoker.visible_message("<span class='warning'>A shimmer of yellow light infuses [invoker]!</span>", \
"<span class='brass'>You bind a Ratvarian spear to yourself. Use the \"Function Call\" action button to call it forth.</span>")
var/datum/action/innate/function_call/F = new()
F.Grant(invoker)
return TRUE
//Function Call action: Calls forth a Ratvarian spear once every 3 minutes.
/datum/action/innate/function_call
name = "Function Call"
desc = "Allows you to summon a Ratvarian spear to fight enemies."
button_icon_state = "ratvarian_spear"
background_icon_state = "bg_clock"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS
buttontooltipstyle = "clockcult"
var/cooldown = 0
var/base_cooldown = 1800
/datum/action/innate/function_call/IsAvailable()
if(!is_servant_of_ratvar(owner) || cooldown > world.time)
return FALSE
return ..()
/datum/action/innate/function_call/Activate()
if(!owner.get_empty_held_indexes())
usr << "<span class='warning'>You need an empty to hand to call forth your spear!</span>"
return FALSE
owner.visible_message("<span class='warning'>A strange spear materializes in [owner]'s hands!</span>", "<span class='brass'>You call forth your spear!</span>")
var/obj/item/clockwork/ratvarian_spear/R = new(get_turf(usr))
owner.put_in_hands(R)
if(!ratvar_awakens)
R.clockwork_desc = "A powerful spear of Ratvarian making. It's more effective against enemy cultists and silicons, though it won't last for long."
owner << "<span class='warning'>Your spear begins to break down in this plane of existence. You can't use it for long!</span>"
R.timerid = addtimer(R, "break_spear", base_cooldown, TIMER_NORMAL)
cooldown = base_cooldown + world.time
owner.update_action_buttons_icon()
addtimer(src, "update_actions", base_cooldown, TIMER_NORMAL)
return TRUE
/datum/action/innate/function_call/proc/update_actions()
if(owner)
owner.update_action_buttons_icon()
//Spatial Gateway: Allows the invoker to teleport themselves and any nearby allies to a conscious servant or clockwork obelisk.
/datum/clockwork_scripture/spatial_gateway
descname = "Teleport Gate"
name = "Spatial Gateway"
desc = "Tears open a miniaturized gateway in spacetime to any conscious servant that can transport objects or creatures to its destination. \
Each servant assisting in the invocation adds one additional use and four additional seconds to the gateway's uses and duration."
invocations = list("Spatial Gateway...", "...activate!")
channel_time = 80
required_components = list(VANGUARD_COGWHEEL = 1, HIEROPHANT_ANSIBLE = 2)
consumed_components = list(VANGUARD_COGWHEEL = 1, HIEROPHANT_ANSIBLE = 1)
multiple_invokers_used = TRUE
multiple_invokers_optional = TRUE
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
tier = SCRIPTURE_SCRIPT
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 9
quickbind = TRUE
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
/datum/clockwork_scripture/spatial_gateway/check_special_requirements()
if(!isturf(invoker.loc))
invoker << "<span class='warning'>You must not be inside an object to use this scripture!</span>"
return FALSE
var/other_servants = 0
for(var/mob/living/L in living_mob_list)
if(is_servant_of_ratvar(L) && !L.stat && L != invoker)
other_servants++
for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in all_clockwork_objects)
other_servants++
if(!other_servants)
invoker << "<span class='warning'>There are no other servants or clockwork obelisks!</span>"
return FALSE
return TRUE
/datum/clockwork_scripture/spatial_gateway/scripture_effects()
var/portal_uses = 0
var/duration = 0
for(var/mob/living/L in range(1, invoker))
if(!L.stat && is_servant_of_ratvar(L))
portal_uses++
duration += 40 //4 seconds
if(ratvar_awakens)
portal_uses = max(portal_uses, 100) //Very powerful if Ratvar has been summoned
duration = max(duration, 100)
return slab.procure_gateway(invoker, duration, portal_uses)
//Volt Void: Channeled for up to thirty times over thirty seconds. Consumes power from most power storages and deals slight burn damage to the invoker.
/datum/clockwork_scripture/channeled/volt_void
descname = "Channeled, Area Power Drain"
name = "Volt Void" //Alternative name: "On all levels but physical, I am a power sink"
desc = "Drains energy from nearby power sources, dealing burn damage if the total power consumed is above a threshhold. Channeled every second for a maximum of thirty seconds."
chant_invocations = list("Draw charge to this shell!")
chant_amount = 30
chant_interval = 10
required_components = list(GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 2)
consumed_components = list(GEIS_CAPACITOR = 1, HIEROPHANT_ANSIBLE = 1)
usage_tip = "If standing on a Sigil of Transmission, will transfer power to it. Augumented limbs will also be healed unless above a very high threshhold."
tier = SCRIPTURE_SCRIPT
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 10
quickbind = TRUE
quickbind_desc = "Drains power from nearby objects. If standing on a Sigil of Transmission, gives it that power.<br><b>Maximum 30 chants.</b>"
var/total_power_drained = 0
var/power_damage_threshhold = 3000
var/augument_damage_threshhold = 6000
/datum/clockwork_scripture/channeled/volt_void/chant_effects(chant_number)
playsound(invoker, 'sound/effects/EMPulse.ogg', 50, 1)
PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/voltvoid, get_turf(invoker))
var/power_drained = 0
for(var/atom/movable/A in view(7, get_turf(invoker)))
power_drained += A.power_drain(TRUE)
var/obj/effect/clockwork/sigil/transmission/ST = locate(/obj/effect/clockwork/sigil/transmission) in get_turf(invoker)
if(ST && power_drained >= MIN_CLOCKCULT_POWER)
var/sigil_drain = 0
while(power_drained >= MIN_CLOCKCULT_POWER)
ST.modify_charge(-MIN_CLOCKCULT_POWER)
power_drained -= MIN_CLOCKCULT_POWER
sigil_drain += MIN_CLOCKCULT_POWER * 0.2
power_drained += sigil_drain //readd part of the power given to the sigil to the power drained this cycle
ST.visible_message("<span class='warning'>[ST] flares a brilliant orange!</span>")
total_power_drained += power_drained
if(power_drained >= MIN_CLOCKCULT_POWER)
if(iscyborg(invoker))
var/mob/living/silicon/robot/R = invoker
if(R.cell)
R.cell.give(power_drained)
R.visible_message("<span class='warning'>[invoker] flares a brilliant orange!</span>", "<span class='brass'>You feel your cell charging.</span>")
else if(total_power_drained >= power_damage_threshhold)
var/power_damage = power_drained * 0.01
invoker.visible_message("<span class='warning'>[invoker] flares a brilliant orange!</span>", "<span class='userdanger'>You feel the heat of electricity running into your body.</span>")
if(ishuman(invoker))
var/mob/living/carbon/human/H = invoker
for(var/X in H.bodyparts)
var/obj/item/bodypart/BP = X
if(ratvar_awakens || (BP.status == BODYPART_ROBOTIC && total_power_drained < augument_damage_threshhold)) //if ratvar is alive, it won't damage and will always heal augumented limbs
if(BP.heal_damage(power_damage, power_damage, 1, 0)) //heals one point of burn and brute for every ~100W drained on augumented limbs
H.update_damage_overlays()
else
if(BP.receive_damage(0, power_damage))
H.update_damage_overlays()
else if(isanimal(invoker))
var/mob/living/simple_animal/A = invoker
A.adjustHealth(-power_damage) //if a simple animal is using volt void, just heal it
return TRUE
@@ -0,0 +1,279 @@
//The base clockwork structure. Can have an alternate desc and will show up in the list of clockwork objects.
/obj/structure/destructible/clockwork
name = "meme structure"
desc = "Some frog or something, the fuck?"
var/clockwork_desc //Shown to servants when they examine
icon = 'icons/obj/clockwork_objects.dmi'
icon_state = "rare_pepe"
var/unanchored_icon //icon for when this structure is unanchored, doubles as the var for if it can be unanchored
anchored = 1
density = 1
resistance_flags = FIRE_PROOF | ACID_PROOF
var/repair_amount = 5 //how much a proselytizer can repair each cycle
var/can_be_repaired = TRUE //if a proselytizer can repair it at all
break_message = "<span class='warning'>The frog isn't a meme after all!</span>" //The message shown when a structure breaks
break_sound = 'sound/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks
debris = list(/obj/item/clockwork/alloy_shards/large = 1, \
/obj/item/clockwork/alloy_shards/medium = 2, \
/obj/item/clockwork/alloy_shards/small = 3) //Parts left behind when a structure breaks
var/construction_value = 0 //How much value the structure contributes to the overall "power" of the structures on the station
/obj/structure/destructible/clockwork/New()
..()
change_construction_value(construction_value)
all_clockwork_objects += src
/obj/structure/destructible/clockwork/Destroy()
change_construction_value(-construction_value)
all_clockwork_objects -= src
return ..()
/obj/structure/destructible/clockwork/ratvar_act()
obj_integrity = max_integrity
/obj/structure/destructible/clockwork/narsie_act()
if(take_damage(rand(25, 50), BRUTE) && src) //if we still exist
var/previouscolor = color
color = "#960000"
animate(src, color = previouscolor, time = 8)
addtimer(src, "update_atom_colour", 8)
/obj/structure/destructible/clockwork/examine(mob/user)
var/can_see_clockwork = is_servant_of_ratvar(user) || isobserver(user)
if(can_see_clockwork && clockwork_desc)
desc = clockwork_desc
..()
desc = initial(desc)
if(!(resistance_flags & INDESTRUCTIBLE))
var/t_It = p_they(TRUE)
var/t_is = p_are()
var/servant_message = "[t_It] [t_is] at <b>[obj_integrity]/[max_integrity]</b> integrity"
var/heavily_damaged = FALSE
var/healthpercent = (obj_integrity/max_integrity) * 100
if(healthpercent < 50)
heavily_damaged = TRUE
if(can_see_clockwork)
user << "<span class='[heavily_damaged ? "alloy":"brass"]'>[servant_message][heavily_damaged ? "!":"."]</span>"
if(unanchored_icon)
user << "<span class='notice'>[src] is [anchored ? "":"not "]secured to the floor.</span>"
/obj/structure/destructible/clockwork/hulk_damage()
return 20
/obj/structure/destructible/clockwork/proc/get_efficiency_mod(increasing)
if(ratvar_awakens)
if(increasing)
return 0.5
return 2
. = max(sqrt(obj_integrity/max(max_integrity, 1)), 0.5)
if(increasing)
. *= min(max_integrity/max(obj_integrity, 1), 4)
. = round(., 0.01)
/obj/structure/destructible/clockwork/can_be_unfasten_wrench(mob/user)
if(anchored && obj_integrity <= round(max_integrity * 0.25, 1))
user << "<span class='warning'>[src] is too damaged to unsecure!</span>"
return FAILED_UNFASTEN
return ..()
/obj/structure/destructible/clockwork/attackby(obj/item/I, mob/user, params)
if(is_servant_of_ratvar(user) && istype(I, /obj/item/weapon/wrench) && unanchored_icon)
if(default_unfasten_wrench(user, I, 50) == SUCCESSFUL_UNFASTEN)
update_anchored(user, TRUE)
return 1
return ..()
/obj/structure/destructible/clockwork/proc/update_anchored(mob/user, do_damage)
if(anchored)
icon_state = initial(icon_state)
else
icon_state = unanchored_icon
if(do_damage)
playsound(src, break_sound, 10 * get_efficiency_mod(TRUE), 1)
take_damage(round(max_integrity * 0.25, 1), BRUTE)
user << "<span class='warning'>As you unsecure [src] from the floor, you see cracks appear in its surface!</span>"
/obj/structure/destructible/clockwork/emp_act(severity)
if(anchored && unanchored_icon)
anchored = FALSE
update_anchored(null, obj_integrity > max_integrity * 0.25)
PoolOrNew(/obj/effect/overlay/temp/emp, loc)
//for the ark and Ratvar
/obj/structure/destructible/clockwork/massive
name = "massive construct"
desc = "A very large construction."
layer = MASSIVE_OBJ_LAYER
density = FALSE
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/obj/structure/destructible/clockwork/massive/New()
..()
poi_list += src
/obj/structure/destructible/clockwork/massive/Destroy()
poi_list -= src
return ..()
/obj/structure/destructible/clockwork/massive/singularity_pull(S, current_size)
return
//the base clockwork machinery, which is not actually machines, but happens to use power
/obj/structure/destructible/clockwork/powered
var/obj/machinery/power/apc/target_apc
var/active = FALSE
var/needs_power = TRUE
var/active_icon = null //icon_state while process() is being called
var/inactive_icon = null //icon_state while process() isn't being called
/obj/structure/destructible/clockwork/powered/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
var/powered = total_accessable_power()
user << "<span class='[powered ? "brass":"alloy"]'>It has access to <b>[powered == INFINITY ? "INFINITY":"[powered]"]W</b> of power.</span>"
/obj/structure/destructible/clockwork/powered/Destroy()
SSfastprocess.processing -= src
SSobj.processing -= src
return ..()
/obj/structure/destructible/clockwork/powered/process()
var/powered = total_accessable_power()
return powered == PROCESS_KILL ? 25 : powered //make sure we don't accidentally return the arbitrary PROCESS_KILL define
/obj/structure/destructible/clockwork/powered/can_be_unfasten_wrench(mob/user)
if(active)
user << "<span class='warning'>[src] needs to be disabled before it can be unsecured!</span>"
return FAILED_UNFASTEN
return ..()
/obj/structure/destructible/clockwork/powered/attack_ai(mob/user)
if(is_servant_of_ratvar(user))
attack_hand(user)
/obj/structure/destructible/clockwork/powered/proc/toggle(fast_process, mob/living/user)
if(user)
if(!is_servant_of_ratvar(user))
return FALSE
if(!anchored && !active)
user << "<span class='warning'>[src] needs to be secured to the floor before it can be activated!</span>"
return FALSE
visible_message("<span class='notice'>[user] [active ? "dis" : "en"]ables [src].</span>", "<span class='brass'>You [active ? "dis" : "en"]able [src].</span>")
active = !active
if(active)
icon_state = active_icon
if(fast_process)
START_PROCESSING(SSfastprocess, src)
else
START_PROCESSING(SSobj, src)
else
icon_state = inactive_icon
if(fast_process)
STOP_PROCESSING(SSfastprocess, src)
else
STOP_PROCESSING(SSobj, src)
return TRUE
/obj/structure/destructible/clockwork/powered/proc/forced_disable(bad_effects)
if(active)
toggle()
/obj/structure/destructible/clockwork/powered/emp_act(severity)
if(forced_disable(TRUE))
PoolOrNew(/obj/effect/overlay/temp/emp, loc)
/obj/structure/destructible/clockwork/powered/proc/total_accessable_power() //how much power we have and can use
if(!needs_power || ratvar_awakens)
return INFINITY //oh yeah we've got power why'd you ask
var/power = 0
power += accessable_apc_power()
power += accessable_sigil_power()
return power
/obj/structure/destructible/clockwork/powered/proc/accessable_apc_power()
var/power = 0
var/area/A = get_area(src)
var/area/targetAPCA
for(var/obj/machinery/power/apc/APC in apcs_list)
var/area/APCA = get_area(APC)
if(APCA == A)
target_apc = APC
if(target_apc)
targetAPCA = get_area(target_apc)
if(targetAPCA != A)
target_apc = null
else if(target_apc.cell)
var/apccharge = target_apc.cell.charge
if(apccharge >= MIN_CLOCKCULT_POWER)
power += apccharge
return power
/obj/structure/destructible/clockwork/powered/proc/accessable_sigil_power()
var/power = 0
for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src))
power += T.power_charge
return power
/obj/structure/destructible/clockwork/powered/proc/try_use_power(amount) //try to use an amount of power
if(!needs_power || ratvar_awakens)
return 1
if(amount <= 0)
return FALSE
var/power = total_accessable_power()
if(!power || power < amount)
return FALSE
return use_power(amount)
/obj/structure/destructible/clockwork/powered/proc/use_power(amount) //we've made sure we had power, so now we use it
var/sigilpower = accessable_sigil_power()
var/list/sigils_in_range = list()
for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src))
sigils_in_range |= T
while(sigilpower && amount >= MIN_CLOCKCULT_POWER)
for(var/S in sigils_in_range)
var/obj/effect/clockwork/sigil/transmission/T = S
if(amount >= MIN_CLOCKCULT_POWER && T.modify_charge(MIN_CLOCKCULT_POWER))
sigilpower -= MIN_CLOCKCULT_POWER
amount -= MIN_CLOCKCULT_POWER
var/apcpower = accessable_apc_power()
while(apcpower >= MIN_CLOCKCULT_POWER && amount >= MIN_CLOCKCULT_POWER)
if(target_apc.cell.use(MIN_CLOCKCULT_POWER))
apcpower -= MIN_CLOCKCULT_POWER
amount -= MIN_CLOCKCULT_POWER
target_apc.charging = 1
target_apc.chargemode = TRUE
target_apc.update()
target_apc.update_icon()
target_apc.updateUsrDialog()
else
apcpower = 0
if(amount)
return FALSE
else
return TRUE
/obj/structure/destructible/clockwork/powered/proc/return_power(amount) //returns a given amount of power to all nearby sigils or if there are no sigils, to the APC
if(amount <= 0)
return FALSE
var/list/sigils_in_range = list()
for(var/obj/effect/clockwork/sigil/transmission/T in range(1, src))
sigils_in_range |= T
if(!sigils_in_range.len && (!target_apc || !target_apc.cell))
return FALSE
if(sigils_in_range.len)
while(amount >= MIN_CLOCKCULT_POWER)
for(var/S in sigils_in_range)
var/obj/effect/clockwork/sigil/transmission/T = S
if(amount >= MIN_CLOCKCULT_POWER && T.modify_charge(-MIN_CLOCKCULT_POWER))
amount -= MIN_CLOCKCULT_POWER
if(target_apc && target_apc.cell && target_apc.cell.give(amount))
target_apc.charging = 1
target_apc.chargemode = TRUE
target_apc.update()
target_apc.update_icon()
target_apc.updateUsrDialog()
return TRUE
@@ -1,955 +0,0 @@
//////////////////////////
// CLOCKWORK STRUCTURES //
//////////////////////////
/obj/structure/clockwork
name = "meme structure"
desc = "Some frog or something, the fuck?"
var/clockwork_desc //Shown to servants when they examine
icon = 'icons/obj/clockwork_objects.dmi'
icon_state = "rare_pepe"
anchored = 1
density = 1
opacity = 0
layer = BELOW_OBJ_LAYER
var/max_health = 100 //All clockwork structures have health that can be removed via attacks
var/health = 100
var/repair_amount = 5 //how much a proselytizer can repair each cycle
var/can_be_repaired = TRUE //if a proselytizer can repair it at all
var/takes_damage = TRUE //If the structure can be damaged
var/break_message = "<span class='warning'>The frog isn't a meme after all!</span>" //The message shown when a structure breaks
var/break_sound = 'sound/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks
var/list/debris = list(/obj/item/clockwork/alloy_shards) //Parts left behind when a structure breaks
var/construction_value = 0 //How much value the structure contributes to the overall "power" of the structures on the station
/obj/structure/clockwork/New()
..()
clockwork_construction_value += construction_value
all_clockwork_objects += src
/obj/structure/clockwork/Destroy()
clockwork_construction_value -= construction_value
all_clockwork_objects -= src
return ..()
/obj/structure/clockwork/proc/destroyed()
if(!takes_damage)
return 0
for(var/I in debris)
new I (get_turf(src))
visible_message(break_message)
playsound(src, break_sound, 50, 1)
qdel(src)
return 1
/obj/structure/clockwork/burn()
SSobj.burning -= src
if(takes_damage)
playsound(src, 'sound/items/Welder.ogg', 100, 1)
visible_message("<span class='warning'>[src] is warped by the heat!</span>")
take_damage(rand(50, 100), BURN)
/obj/structure/clockwork/proc/take_damage(amount, damage_type)
if(!amount || !damage_type || !damage_type in list(BRUTE, BURN))
return 0
if(takes_damage)
health = max(0, health - amount)
if(!health)
destroyed()
return 1
return 0
/obj/structure/clockwork/narsie_act()
if(take_damage(rand(25, 50), BRUTE) && src) //if we still exist
var/previouscolor = color
color = "#960000"
animate(src, color = previouscolor, time = 8)
/obj/structure/clockwork/ex_act(severity)
var/damage = 0
switch(severity)
if(1)
damage = max_health //100% max health lost
if(2)
damage = max_health * rand(0.5, 0.7) //50-70% max health lost
if(3)
damage = max_health * rand(0.1, 0.3) //10-30% max health lost
if(damage)
take_damage(damage, BRUTE)
/obj/structure/clockwork/examine(mob/user)
var/can_see_clockwork = is_servant_of_ratvar(user) || isobserver(user)
if(can_see_clockwork && clockwork_desc)
desc = clockwork_desc
..()
desc = initial(desc)
if(takes_damage)
var/servant_message = "It is at <b>[health]/[max_health]</b> integrity"
var/other_message = "It seems pristine and undamaged"
var/heavily_damaged = FALSE
var/healthpercent = (health/max_health) * 100
if(healthpercent >= 100)
other_message = "It seems pristine and undamaged"
else if(healthpercent >= 50)
other_message = "It looks slightly dented"
else if(healthpercent >= 25)
other_message = "It appears heavily damaged"
heavily_damaged = TRUE
else if(healthpercent >= 0)
other_message = "It's falling apart"
heavily_damaged = TRUE
user << "<span class='[heavily_damaged ? "alloy":"brass"]'>[can_see_clockwork ? "[servant_message]":"[other_message]"][heavily_damaged ? "!":"."]</span>"
/obj/structure/clockwork/bullet_act(obj/item/projectile/P)
. = ..()
visible_message("<span class='danger'>[src] is hit by \a [P]!</span>")
playsound(src, P.hitsound, 50, 1)
take_damage(P.damage, P.damage_type)
/obj/structure/clockwork/proc/attack_generic(mob/user, damage = 0, damage_type = BRUTE) //used by attack_alien, attack_animal, and attack_slime
user.do_attack_animation(src)
user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("<span class='danger'>[user] smashes into [src]!</span>")
take_damage(damage, damage_type)
/obj/structure/clockwork/attack_alien(mob/living/user)
playsound(src, 'sound/weapons/bladeslice.ogg', 50, 1)
attack_generic(user, 15)
/obj/structure/clockwork/attack_animal(mob/living/simple_animal/M)
if(!M.melee_damage_upper)
return
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
attack_generic(M, M.melee_damage_upper, M.melee_damage_type)
/obj/structure/clockwork/attack_slime(mob/living/simple_animal/slime/user)
if(!user.is_adult)
return
playsound(src, 'sound/weapons/Genhit.ogg', 50, 1)
attack_generic(user, rand(10, 15))
/obj/structure/clockwork/attacked_by(obj/item/I, mob/living/user)
. = ..()
if(I.force && takes_damage)
playsound(src, I.hitsound, 50, 1)
take_damage(I.force, I.damtype)
/obj/structure/clockwork/mech_melee_attack(obj/mecha/M)
if(..())
playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
take_damage(M.force, M.damtype)
/obj/structure/clockwork/cache //Tinkerer's cache: Stores components for later use.
name = "tinkerer's cache"
desc = "A large brass spire with a flaming hole in its center."
clockwork_desc = "A brass container capable of storing a large amount of components.\n\
Shares components with all other caches and will gradually generate components if near a Clockwork Wall."
icon_state = "tinkerers_cache"
construction_value = 10
break_message = "<span class='warning'>The cache's fire winks out before it falls in on itself!</span>"
max_health = 80
health = 80
var/wall_generation_cooldown
var/wall_found = FALSE //if we've found a wall and finished our windup delay
/obj/structure/clockwork/cache/New()
..()
START_PROCESSING(SSobj, src)
clockwork_caches++
set_light(2,1)
/obj/structure/clockwork/cache/Destroy()
clockwork_caches--
STOP_PROCESSING(SSobj, src)
return ..()
/obj/structure/clockwork/cache/destroyed()
if(takes_damage)
for(var/I in src)
var/atom/movable/A = I
A.forceMove(get_turf(src)) //drop any daemons we have
return ..()
/obj/structure/clockwork/cache/process()
for(var/turf/closed/wall/clockwork/C in orange(1, src))
if(!wall_found)
wall_found = TRUE
wall_generation_cooldown = world.time + CACHE_PRODUCTION_TIME
visible_message("<span class='warning'>[src] starts to whirr in the presence of [C]...</span>")
break
if(wall_generation_cooldown <= world.time)
wall_generation_cooldown = world.time + CACHE_PRODUCTION_TIME
generate_cache_component()
playsound(C, 'sound/magic/clockwork/fellowship_armory.ogg', rand(15, 20), 1, -3, 1, 1)
visible_message("<span class='warning'>Something clunks around inside of [src]...</span>")
break
/obj/structure/clockwork/cache/attackby(obj/item/I, mob/living/user, params)
if(!is_servant_of_ratvar(user))
return ..()
if(istype(I, /obj/item/clockwork/component))
var/obj/item/clockwork/component/C = I
clockwork_component_cache[C.component_id]++
user << "<span class='notice'>You add [C] to [src].</span>"
user.drop_item()
qdel(C)
return 1
else if(istype(I, /obj/item/clockwork/slab))
var/obj/item/clockwork/slab/S = I
clockwork_component_cache["belligerent_eye"] += S.stored_components["belligerent_eye"]
clockwork_component_cache["vanguard_cogwheel"] += S.stored_components["vanguard_cogwheel"]
clockwork_component_cache["guvax_capacitor"] += S.stored_components["guvax_capacitor"]
clockwork_component_cache["replicant_alloy"] += S.stored_components["replicant_alloy"]
clockwork_component_cache["hierophant_ansible"] += S.stored_components["hierophant_ansible"]
S.stored_components["belligerent_eye"] = 0
S.stored_components["vanguard_cogwheel"] = 0
S.stored_components["guvax_capacitor"] = 0
S.stored_components["replicant_alloy"] = 0
S.stored_components["hierophant_ansible"] = 0
user.visible_message("<span class='notice'>[user] empties [S] into [src].</span>", "<span class='notice'>You offload your slab's components into [src].</span>")
return 1
else if(istype(I, /obj/item/clockwork/daemon_shell))
var/component_type
switch(alert(user, "Will this daemon produce a specific type of component or produce randomly?.", , "Specific Type", "Random Component"))
if("Specific Type")
switch(input(user, "Choose a component type.", name) as null|anything in list("Belligerent Eyes", "Vanguard Cogwheels", "Guvax Capacitors", "Replicant Alloys", "Hierophant Ansibles"))
if("Belligerent Eyes")
component_type = "belligerent_eye"
if("Vanguard Cogwheels")
component_type = "vanguard_cogwheel"
if("Guvax Capacitors")
component_type = "guvax_capacitor"
if("Replicant Alloys")
component_type = "replicant_alloy"
if("Hierophant Ansibles")
component_type = "hierophant_ansibles"
if(!user || !user.canUseTopic(src) || !user.canUseTopic(I))
return 0
var/obj/item/clockwork/tinkerers_daemon/D = new(src)
D.cache = src
D.specific_component = component_type
user.visible_message("<span class='notice'>[user] spins the cogwheel on [I] and puts it into [src].</span>", \
"<span class='notice'>You activate the daemon and put it into [src]. It will now produce a component every twenty seconds.</span>")
user.drop_item()
qdel(I)
return 1
else
return ..()
/obj/structure/clockwork/cache/attack_hand(mob/user)
if(!is_servant_of_ratvar(user))
return 0
var/list/possible_components = list()
if(clockwork_component_cache["belligerent_eye"])
possible_components += "Belligerent Eye"
if(clockwork_component_cache["vanguard_cogwheel"])
possible_components += "Vanguard Cogwheel"
if(clockwork_component_cache["guvax_capacitor"])
possible_components += "Guvax Capacitor"
if(clockwork_component_cache["replicant_alloy"])
possible_components += "Replicant Alloy"
if(clockwork_component_cache["hierophant_ansible"])
possible_components += "Hierophant Ansible"
if(!possible_components.len)
user << "<span class='warning'>[src] is empty!</span>"
return 0
var/component_to_withdraw = input(user, "Choose a component to withdraw.", name) as null|anything in possible_components
if(!user || !user.canUseTopic(src) || !component_to_withdraw)
return 0
var/obj/item/clockwork/component/the_component
switch(component_to_withdraw)
if("Belligerent Eye")
if(clockwork_component_cache["belligerent_eye"])
the_component = new/obj/item/clockwork/component/belligerent_eye(get_turf(src))
clockwork_component_cache["belligerent_eye"]--
if("Vanguard Cogwheel")
if(clockwork_component_cache["vanguard_cogwheel"])
the_component = new/obj/item/clockwork/component/vanguard_cogwheel(get_turf(src))
clockwork_component_cache["vanguard_cogwheel"]--
if("Guvax Capacitor")
if(clockwork_component_cache["guvax_capacitor"])
the_component = new/obj/item/clockwork/component/guvax_capacitor(get_turf(src))
clockwork_component_cache["guvax_capacitor"]--
if("Replicant Alloy")
if(clockwork_component_cache["replicant_alloy"])
the_component = new/obj/item/clockwork/component/replicant_alloy(get_turf(src))
clockwork_component_cache["replicant_alloy"]--
if("Hierophant Ansible")
if(clockwork_component_cache["hierophant_ansible"])
the_component = new/obj/item/clockwork/component/hierophant_ansible(get_turf(src))
clockwork_component_cache["hierophant_ansible"]--
if(the_component)
user.visible_message("<span class='notice'>[user] withdraws [the_component] from [src].</span>", "<span class='notice'>You withdraw [the_component] from [src].</span>")
user.put_in_hands(the_component)
return 1
/obj/structure/clockwork/cache/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<b>Stored components:</b>"
user << "<span class='neovgre_small'><i>Belligerent Eyes:</i> [clockwork_component_cache["belligerent_eye"]]</span>"
user << "<span class='inathneq_small'><i>Vanguard Cogwheels:</i> [clockwork_component_cache["vanguard_cogwheel"]]</span>"
user << "<span class='sevtug_small'><i>Guvax Capacitors:</i> [clockwork_component_cache["guvax_capacitor"]]</span>"
user << "<span class='nezbere_small'><i>Replicant Alloys:</i> [clockwork_component_cache["replicant_alloy"]]</span>"
user << "<span class='nzcrentr_small'><i>Hierophant Ansibles:</i> [clockwork_component_cache["hierophant_ansible"]]</span>"
/obj/structure/clockwork/ocular_warden //Ocular warden: Low-damage, low-range turret. Deals constant damage to whoever it makes eye contact with.
name = "ocular warden"
desc = "A large brass eye with tendrils trailing below it and a wide red iris."
clockwork_desc = "A stalwart turret that will deal sustained damage to any non-faithful it sees."
icon_state = "ocular_warden"
health = 25
max_health = 25
construction_value = 15
layer = HIGH_OBJ_LAYER
break_message = "<span class='warning'>The warden's eye gives a glare of utter hate before falling dark!</span>"
debris = list(/obj/item/clockwork/component/belligerent_eye/blind_eye)
burn_state = LAVA_PROOF
var/damage_per_tick = 3
var/sight_range = 3
var/mob/living/target
var/list/idle_messages = list(" sulkily glares around.", " lazily drifts from side to side.", " looks around for something to burn.", " slowly turns in circles.")
/obj/structure/clockwork/ocular_warden/New()
..()
START_PROCESSING(SSfastprocess, src)
/obj/structure/clockwork/ocular_warden/Destroy()
STOP_PROCESSING(SSfastprocess, src)
return ..()
/obj/structure/clockwork/ocular_warden/examine(mob/user)
..()
user << "<span class='brass'>[target ? "<b>It's fixated on [target]!</b>" : "Its gaze is wandering aimlessly."]</span>"
/obj/structure/clockwork/ocular_warden/process()
var/list/validtargets = acquire_nearby_targets()
if(ratvar_awakens && (damage_per_tick == initial(damage_per_tick) || sight_range == initial(sight_range))) //Massive buff if Ratvar has returned
damage_per_tick = 10
sight_range = 5
if(target)
if(!(target in validtargets))
lose_target()
else
if(!target.null_rod_check())
target.adjustFireLoss(!iscultist(target) ? damage_per_tick : damage_per_tick * 2) //Nar-Sian cultists take additional damage
if(ratvar_awakens && target)
target.adjust_fire_stacks(damage_per_tick)
target.IgniteMob()
setDir(get_dir(get_turf(src), get_turf(target)))
if(!target)
if(validtargets.len)
target = pick(validtargets)
visible_message("<span class='warning'>[src] swivels to face [target]!</span>")
target << "<span class='heavy_brass'>\"I SEE YOU!\"</span>\n<span class='userdanger'>[src]'s gaze [ratvar_awakens ? "melts you alive" : "burns you"]!</span>"
if(target.null_rod_check() && !ratvar_awakens)
target << "<span class='warning'>Your artifact glows hotly against you, protecting you from the warden's gaze!</span>"
else if(prob(0.5)) //Extremely low chance because of how fast the subsystem it uses processes
if(prob(50))
visible_message("<span class='notice'>[src][pick(idle_messages)]</span>")
else
setDir(pick(cardinal))//Random rotation
/obj/structure/clockwork/ocular_warden/proc/acquire_nearby_targets()
. = list()
for(var/mob/living/L in viewers(sight_range, src)) //Doesn't attack the blind
if(!is_servant_of_ratvar(L) && !L.stat && L.mind && !(L.disabilities & BLIND) && !L.null_rod_check())
. += L
/obj/structure/clockwork/ocular_warden/proc/lose_target()
if(!target)
return 0
target = null
visible_message("<span class='warning'>[src] settles and seems almost disappointed.</span>")
return 1
/obj/structure/clockwork/shell
construction_value = 0
anchored = 0
density = 0
takes_damage = FALSE
burn_state = LAVA_PROOF
var/mobtype = /mob/living/simple_animal/hostile/clockwork
var/spawn_message = " is an error and you should yell at whoever spawned this shell."
/obj/structure/clockwork/shell/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/device/mmi/posibrain/soul_vessel))
if(!is_servant_of_ratvar(user))
..()
return 0
var/obj/item/device/mmi/posibrain/soul_vessel/S = I
if(!S.brainmob)
user << "<span class='warning'>[S] hasn't trapped a spirit! Turn it on first.</span>"
return 0
if(S.brainmob && (!S.brainmob.client || !S.brainmob.mind))
user << "<span class='warning'>[S]'s trapped spirit appears inactive!</span>"
return 0
user.visible_message("<span class='notice'>[user] places [S] in [src], where it fuses to the shell.</span>", "<span class='brass'>You place [S] in [src], fusing it to the shell.</span>")
var/mob/living/simple_animal/A = new mobtype(get_turf(src))
A.visible_message("<span class='brass'>[src][spawn_message]</span>")
S.brainmob.mind.transfer_to(A)
add_servant_of_ratvar(A, TRUE)
user.drop_item()
qdel(S)
qdel(src)
return 1
else
return ..()
/obj/structure/clockwork/shell/cogscarab
name = "cogscarab shell"
desc = "A small brass shell with a cube-shaped receptable in its center. It gives off an aura of obsessive perfectionism."
clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a weak construct with an inbuilt proselytizer."
icon_state = "clockdrone_shell"
mobtype = /mob/living/simple_animal/drone/cogscarab
spawn_message = "'s eyes blink open, glowing bright red."
/obj/structure/clockwork/shell/fragment //Anima fragment: Useless on its own, but can accept an active soul vessel to create a powerful construct.
name = "fragment shell"
desc = "A massive brass shell with a small cube-shaped receptable in its center. It gives off an aura of contained power."
clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a powerful construct."
icon_state = "anime_fragment"
mobtype = /mob/living/simple_animal/hostile/clockwork/fragment
spawn_message = " whirs and rises from the ground on a flickering jet of reddish fire."
/obj/structure/clockwork/wall_gear
name = "massive gear"
icon_state = "wall_gear"
climbable = TRUE
max_health = 50
health = 50
desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, or just climb over it."
clockwork_desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, just climb over it, or proselytize it into replicant alloy."
break_message = "<span class='warning'>The gear breaks apart into shards of alloy!</span>"
debris = list(/obj/item/clockwork/alloy_shards)
/obj/structure/clockwork/wall_gear/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/wrench))
default_unfasten_wrench(user, I, 10)
return 1
return ..()
/obj/structure/clockwork/wall_gear/examine(mob/user)
..()
user << "<span class='notice'>[src] is [anchored ? "secured to the floor":"mobile, and not secured"].</span>"
///////////////////////
// CLOCKWORK EFFECTS //
///////////////////////
/obj/effect/clockwork
name = "meme machine"
desc = "Still don't know what it is."
var/clockwork_desc = "A fabled artifact from beyond the stars. Contains concentrated meme essence." //Shown to clockwork cultists instead of the normal description
icon = 'icons/effects/clockwork_effects.dmi'
icon_state = "ratvars_flame"
anchored = 1
density = 0
opacity = 0
burn_state = LAVA_PROOF
/obj/effect/clockwork/New()
..()
all_clockwork_objects += src
/obj/effect/clockwork/Destroy()
all_clockwork_objects -= src
return ..()
/obj/effect/clockwork/examine(mob/user)
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
desc = clockwork_desc
..()
desc = initial(desc)
/obj/effect/clockwork/judicial_marker //Judicial marker: Created by the judicial visor. After three seconds, stuns any non-servants nearby and damages Nar-Sian cultists.
name = "judicial marker"
desc = "You get the feeling that you shouldn't be standing here."
clockwork_desc = "A sigil that will soon erupt and smite any unenlightened nearby."
icon = 'icons/effects/96x96.dmi'
pixel_x = -32
pixel_y = -32
layer = BELOW_MOB_LAYER
var/mob/user
/obj/effect/clockwork/judicial_marker/New(loc, caster)
..()
user = caster
playsound(src, 'sound/magic/MAGIC_MISSILE.ogg', 50, 1, 1, 1)
flick("judicial_marker", src)
addtimer(src, "burstanim", 16, FALSE)
/obj/effect/clockwork/judicial_marker/proc/burstanim()
layer = ABOVE_ALL_MOB_LAYER
flick("judicial_explosion", src)
addtimer(src, "judicialblast", 13, FALSE)
/obj/effect/clockwork/judicial_marker/proc/judicialblast()
var/targetsjudged = 0
playsound(src, 'sound/effects/explosionfar.ogg', 100, 1, 1, 1)
for(var/mob/living/L in range(1, src))
if(is_servant_of_ratvar(L))
continue
if(L.null_rod_check())
var/obj/item/I = L.null_rod_check()
L.visible_message("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
continue
if(!iscultist(L))
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
"<span class='userdanger'>[!issilicon(L) ? "An unseen force slams you into the ground!" : "ERROR: Motor servos disabled by external source!"]</span>")
L.Weaken(8)
else
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
"<span class='heavy_brass'>\"Keep an eye out, filth.\"</span>\n<span class='userdanger'>A burst of heat crushes you against the ground!</span>")
L.Weaken(4) //half the stun, but sets cultists on fire
L.adjust_fire_stacks(2)
L.IgniteMob()
targetsjudged++
L.adjustBruteLoss(10)
user << "<span class='brass'><b>[targetsjudged ? "Successfully judged <span class='neovgre'>[targetsjudged]</span>":"Judged no"] heretic[!targetsjudged || targetsjudged > 1 ? "s":""].</b></span>"
QDEL_IN(src, 3) //so the animation completes properly
/obj/effect/clockwork/judicial_marker/ex_act(severity)
return
/obj/effect/clockwork/spatial_gateway //Spatial gateway: A usually one-way rift to another location.
name = "spatial gateway"
desc = "A gently thrumming tear in reality."
clockwork_desc = "A gateway in reality."
icon_state = "spatial_gateway"
density = 1
var/sender = TRUE //If this gateway is made for sending, not receiving
var/both_ways = FALSE
var/lifetime = 25 //How many deciseconds this portal will last
var/uses = 1 //How many objects or mobs can go through the portal
var/obj/effect/clockwork/spatial_gateway/linked_gateway //The gateway linked to this one
/obj/effect/clockwork/spatial_gateway/New()
..()
spawn(1)
if(!linked_gateway)
qdel(src)
return 0
if(both_ways)
clockwork_desc = "A gateway in reality. It can both send and receive objects."
else
clockwork_desc = "A gateway in reality. It can only [sender ? "send" : "receive"] objects."
QDEL_IN(src, lifetime)
//set up a gateway with another gateway
/obj/effect/clockwork/spatial_gateway/proc/setup_gateway(obj/effect/clockwork/spatial_gateway/gatewayB, set_duration, set_uses, two_way)
if(!gatewayB || !set_duration || !uses)
return 0
linked_gateway = gatewayB
gatewayB.linked_gateway = src
if(two_way)
both_ways = TRUE
gatewayB.both_ways = TRUE
else
sender = TRUE
gatewayB.sender = FALSE
gatewayB.density = FALSE
lifetime = set_duration
gatewayB.lifetime = set_duration
uses = set_uses
gatewayB.uses = set_uses
return 1
/obj/effect/clockwork/spatial_gateway/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='brass'>It has [uses] uses remaining.</span>"
/obj/effect/clockwork/spatial_gateway/attack_hand(mob/living/user)
if(user.pulling && user.a_intent == "grab" && isliving(user.pulling))
var/mob/living/L = user.pulling
if(L.buckled || L.anchored || L.has_buckled_mobs())
return 0
user.visible_message("<span class='warning'>[user] shoves [L] into [src]!</span>", "<span class='danger'>You shove [L] into [src]!</span>")
user.stop_pulling()
pass_through_gateway(L)
return 1
if(!user.canUseTopic(src))
return 0
user.visible_message("<span class='warning'>[user] climbs through [src]!</span>", "<span class='danger'>You brace yourself and step through [src]...</span>")
pass_through_gateway(user)
return 1
/obj/effect/clockwork/spatial_gateway/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/weapon/nullrod))
user.visible_message("<span class='warning'>[user] dispels [src] with [I]!</span>", "<span class='danger'>You close [src] with [I]!</span>")
qdel(linked_gateway)
qdel(src)
return 1
if(istype(I, /obj/item/clockwork/slab))
user << "<span class='heavy_brass'>\"I don't think you want to drop your slab into that\".\n\"If you really want to, try throwing it.\"</span>"
return 1
if(user.drop_item())
user.visible_message("<span class='warning'>[user] drops [I] into [src]!</span>", "<span class='danger'>You drop [I] into [src]!</span>")
pass_through_gateway(I)
..()
/obj/effect/clockwork/spatial_gateway/Bumped(atom/A)
..()
if(isliving(A) || istype(A, /obj/item))
pass_through_gateway(A)
/obj/effect/clockwork/spatial_gateway/proc/pass_through_gateway(atom/movable/A)
if(!linked_gateway)
qdel(src)
return 0
if(!sender)
visible_message("<span class='warning'>[A] bounces off of [src]!</span>")
return 0
if(!uses)
return 0
if(isliving(A))
var/mob/living/user = A
user << "<span class='warning'><b>You pass through [src] and appear elsewhere!</b></span>"
linked_gateway.visible_message("<span class='warning'>A shape appears in [linked_gateway] before emerging!</span>")
playsound(src, 'sound/effects/EMPulse.ogg', 50, 1)
playsound(linked_gateway, 'sound/effects/EMPulse.ogg', 50, 1)
transform = matrix() * 1.5
animate(src, transform = matrix() / 1.5, time = 10)
linked_gateway.transform = matrix() * 1.5
animate(linked_gateway, transform = matrix() / 1.5, time = 10)
A.forceMove(get_turf(linked_gateway))
uses = max(0, uses - 1)
linked_gateway.uses = max(0, linked_gateway.uses - 1)
spawn(10)
if(!uses)
qdel(src)
qdel(linked_gateway)
return 1
/obj/effect/clockwork/general_marker
name = "general marker"
desc = "Some big guy. For you."
clockwork_desc = "One of Ratvar's generals."
alpha = 200
layer = MASSIVE_OBJ_LAYER
/obj/effect/clockwork/general_marker/New()
..()
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
animate(src, alpha = 0, time = 10)
QDEL_IN(src, 10)
/obj/effect/clockwork/general_marker/nezbere
name = "Nezbere, the Brass Eidolon"
desc = "A towering colossus clad in nigh-impenetrable brass armor. Its gaze is stern yet benevolent, even upon you."
clockwork_desc = "One of Ratvar's four generals. Nezbere is responsible for the design, testing, and creation of everything in Ratvar's domain."
icon = 'icons/effects/340x428.dmi'
icon_state = "nezbere"
pixel_x = -154
pixel_y = -198
/obj/effect/clockwork/general_marker/sevtug
name = "Sevtug, the Formless Pariah"
desc = "A sinister cloud of purple energy. Looking at it gives you a headache."
clockwork_desc = "One of Ratvar's four generals. Sevtug taught him how to manipulate minds and is one of his oldest allies."
icon = 'icons/effects/211x247.dmi'
icon_state = "sevtug"
pixel_x = -89
pixel_y = -107
/obj/effect/clockwork/general_marker/nzcrentr
name = "Nzcrentr, the Forgotten Arbiter"
desc = "A terrifying war machine crackling with limitless energy."
clockwork_desc = "One of Ratvar's four generals. Nzcrentr is the result of Neovgre - Nezbere's finest war machine, commandeerable only be a mortal - fusing with its pilot and driving her \
insane. Nzcrentr seeks out any and all sentient life to slaughter it for sport."
icon = 'icons/effects/254x361.dmi'
icon_state = "nzcrentr"
pixel_x = -111
pixel_y = -164
/obj/effect/clockwork/general_marker/inathneq
name = "Inath-Neq, the Resonant Cogwheel"
desc = "A humanoid form blazing with blue fire. It radiates an aura of kindness and caring."
clockwork_desc = "One of Ratvar's four generals. Before her current form, Inath-Neq was a powerful warrior priestess commanding the Resonant Cogs, a sect of Ratvarian warriors renowned for \
their prowess. After a lost battle with Nar-Sian cultists, Inath-Neq was struck down and stated in her dying breath, \
\"The Resonant Cogs shall not fall silent this day, but will come together to form a wheel that shall never stop turning.\" Ratvar, touched by this, granted Inath-Neq an eternal body and \
merged her soul with those of the Cogs slain with her on the battlefield."
icon = 'icons/effects/187x381.dmi'
icon_state = "inath-neq"
pixel_x = -77
pixel_y = -174
/obj/effect/clockwork/sigil //Sigils: Rune-like markings on the ground with various effects.
name = "sigil"
desc = "A strange set of markings drawn on the ground."
clockwork_desc = "A sigil of some purpose."
icon_state = "sigil"
layer = LOW_OBJ_LAYER
alpha = 50
burn_state = FIRE_PROOF
burntime = 1
var/affects_servants = FALSE
var/stat_affected = CONSCIOUS
/obj/effect/clockwork/sigil/attack_hand(mob/user)
if(iscarbon(user) && !user.stat && (!is_servant_of_ratvar(user) || (is_servant_of_ratvar(user) && user.a_intent == "harm")))
user.visible_message("<span class='warning'>[user] stamps out [src]!</span>", "<span class='danger'>You stomp on [src], scattering it into thousands of particles.</span>")
qdel(src)
return 1
..()
/obj/effect/clockwork/sigil/Crossed(atom/movable/AM)
..()
if(isliving(AM))
var/mob/living/L = AM
if(L.stat <= stat_affected)
if((!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && affects_servants)) && L.mind)
if(L.null_rod_check())
var/obj/item/I = L.null_rod_check()
L.visible_message("<span class='warning'>[L]'s [I.name] protects them from [src]'s effects!</span>", "<span class='userdanger'>Your [I.name] protects you!</span>")
return
sigil_effects(L)
return 1
/obj/effect/clockwork/sigil/proc/sigil_effects(mob/living/L)
/obj/effect/clockwork/sigil/transgression //Sigil of Transgression: Stuns and flashes the first non-servant to walk on it. Nar-Sian cultists are damaged and knocked down for about twice the stun
name = "dull sigil"
desc = "A dull, barely-visible golden sigil. It's as though light was carved into the ground."
icon = 'icons/effects/clockwork_effects.dmi'
clockwork_desc = "A sigil that will stun the first non-servant to cross it. Nar-Sie's dogs will be knocked down."
icon_state = "sigildull"
color = "#FAE48C"
/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L)
var/target_flashed = L.flash_eyes()
for(var/mob/living/M in viewers(5, src))
if(!is_servant_of_ratvar(M) && M != L)
M.flash_eyes()
if(iscultist(L))
L << "<span class='heavy_brass'>\"Watch your step, wretch.\"</span>"
L.adjustBruteLoss(10)
L.Weaken(4)
L.visible_message("<span class='warning'>[src] appears around [L] in a burst of light!</span>", \
"<span class='userdanger'>[target_flashed ? "An unseen force":"The glowing sigil around you"] holds you in place!</span>")
L.Stun(3)
PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/transgression, get_turf(src))
qdel(src)
return 1
/obj/effect/clockwork/sigil/submission //Sigil of Submission: After a short time, converts any non-servant standing on it. Knocks down and silences them for five seconds afterwards.
name = "ominous sigil"
desc = "A luminous golden sigil. Something about it really bothers you."
clockwork_desc = "A sigil that will enslave the first person to cross it, provided they remain on it for five seconds."
icon_state = "sigilsubmission"
color = "#FAE48C"
alpha = 125
stat_affected = UNCONSCIOUS
var/convert_time = 50
var/glow_light = 2 //soft light
var/glow_falloff = 1
var/delete_on_finish = TRUE
var/sigil_name = "Sigil of Submission"
var/glow_type
/obj/effect/clockwork/sigil/submission/New()
..()
set_light(glow_light,glow_falloff)
/obj/effect/clockwork/sigil/submission/proc/post_channel(mob/living/L)
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
visible_message("<span class='warning'>[src] begins to glow a piercing magenta!</span>")
animate(src, color = "#AF0AAF", time = convert_time)
var/obj/effect/overlay/temp/ratvar/sigil/glow
if(glow_type)
glow = PoolOrNew(glow_type, get_turf(src))
animate(glow, alpha = 255, time = convert_time)
var/I = 0
while(I < convert_time && get_turf(L) == get_turf(src))
I++
sleep(1)
if(get_turf(L) != get_turf(src))
if(glow)
qdel(glow)
animate(src, color = initial(color), time = 20)
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
return 0
post_channel(L)
if(is_eligible_servant(L))
L << "<span class='heavy_brass'>\"You belong to me now.\"</span>"
add_servant_of_ratvar(L)
L.Weaken(3) //Completely defenseless for about five seconds - mainly to give them time to read over the information they've just been presented with
L.Stun(3)
if(iscarbon(L))
var/mob/living/carbon/C = L
C.silent += 5
var/message = "[sigil_name] in [get_area(src)] <span class='sevtug'>[is_servant_of_ratvar(L) ? "successfully converted" : "failed to convert"]</span>"
for(var/M in mob_list)
if(isobserver(M))
var/link = FOLLOW_LINK(M, L)
M << "[link] <span class='heavy_brass'>[message] [L.real_name]!</span>"
else if(is_servant_of_ratvar(M))
if(M == L)
M << "<span class='heavy_brass'>[message] you!</span>"
else
M << "<span class='heavy_brass'>[message] [L.real_name]!</span>"
if(delete_on_finish)
qdel(src)
else
animate(src, color = initial(color), time = 20)
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
return 1
/obj/effect/clockwork/sigil/submission/accession //Sigil of Accession: After a short time, converts any non-servant standing on it though implants. Knocks down and silences them for five seconds afterwards.
name = "terrifying sigil"
desc = "A luminous brassy sigil. Something about it makes you want to flee."
clockwork_desc = "A sigil that will enslave any person who crosses it, provided they remain on it for five seconds. \n\
It can convert a mindshielded target once before disppearing, but can convert any number of non-implanted targets."
icon_state = "sigiltransgression"
color = "#A97F1B"
alpha = 200
glow_light = 4 //bright light
glow_falloff = 3
delete_on_finish = FALSE
sigil_name = "Sigil of Accession"
glow_type = /obj/effect/overlay/temp/ratvar/sigil/accession
/obj/effect/clockwork/sigil/submission/accession/post_channel(mob/living/L)
if(isloyal(L))
delete_on_finish = TRUE
L.visible_message("<span class='warning'>[L] visibly trembles!</span>", \
"<span class='sevtug'>Lbh jvyy or zvar-naq-uvf. Guvf chal gevaxrg jvyy abg fgbc zr.</span>")
for(var/obj/item/weapon/implant/mindshield/M in L)
if(M.implanted)
qdel(M)
/obj/effect/clockwork/sigil/transmission
name = "suspicious sigil"
desc = "A glowing orange sigil. The air around it feels staticky."
clockwork_desc = "A sigil that will serve as a battery for clockwork structures. Use Volt Void while standing on it to charge it."
icon_state = "sigiltransmission"
color = "#EC8A2D"
alpha = 50
var/power_charge = 2500 //starts with 2500W by default
/obj/effect/clockwork/sigil/transmission/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='[power_charge ? "brass":"alloy"]'>It is storing [power_charge]W of power.</span>"
/obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L)
if(power_charge)
L << "<span class='brass'>You feel a slight, static shock.</span>"
return 1
/obj/effect/clockwork/sigil/transmission/New()
..()
alpha = min(initial(alpha) + power_charge*0.02, 255)
/obj/effect/clockwork/sigil/transmission/proc/modify_charge(amount)
if(power_charge - amount < 0)
return 0
power_charge -= amount
alpha = min(initial(alpha) + power_charge*0.02, 255)
return 1
/obj/effect/clockwork/sigil/vitality
name = "comforting sigil"
desc = "A faint blue sigil. Looking at it makes you feel protected."
clockwork_desc = "A sigil that will drain non-servants that remain on it. Servants that remain on it will be healed if it has any vitality drained."
icon_state = "sigilvitality"
color = "#123456"
alpha = 75
affects_servants = TRUE
stat_affected = DEAD
var/vitality = 0
var/base_revive_cost = 20
var/sigil_active = FALSE
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
/obj/effect/clockwork/sigil/vitality/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='[vitality ? "inathneq_small":"alloy"]'>It is storing [vitality] units of vitality.</span>"
user << "<span class='inathneq_small'>It requires at least [base_revive_cost] units of vitality to revive dead servants, in addition to any damage the servant has.</span>"
/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L)
if(L.suiciding || sigil_active || !is_servant_of_ratvar(L) && L.stat == DEAD)
return 0
visible_message("<span class='warning'>[src] begins to glow bright blue!</span>")
animate(src, alpha = 255, time = 10)
sleep(10)
sigil_active = TRUE
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
while(L && (!is_servant_of_ratvar(L) && L.stat != DEAD || (is_servant_of_ratvar(L) && vitality)) && get_turf(L) == get_turf(src))
if(animation_number >= 4)
PoolOrNew(/obj/effect/overlay/temp/ratvar/sigil/vitality, get_turf(src))
animation_number = 0
animation_number++
if(!is_servant_of_ratvar(L))
var/vitality_drained = L.adjustToxLoss(1.5)
if(vitality_drained)
vitality += vitality_drained
else
break
else
var/clone_to_heal = L.getCloneLoss()
var/tox_to_heal = L.getToxLoss()
var/burn_to_heal = L.getFireLoss()
var/brute_to_heal = L.getBruteLoss()
var/oxy_to_heal = L.getOxyLoss()
var/total_damage = clone_to_heal + tox_to_heal + burn_to_heal + brute_to_heal + oxy_to_heal
if(L.stat == DEAD)
var/revival_cost = base_revive_cost + total_damage - oxy_to_heal //ignores oxygen damage
var/mob/dead/observer/ghost = L.get_ghost(TRUE)
if(ghost)
if(vitality >= revival_cost)
ghost.reenter_corpse()
L.revive(1, 1)
playsound(L, 'sound/magic/Staff_Healing.ogg', 50, 1)
L.visible_message("<span class='warning'>[L] suddenly gets back up, their mouth dripping blue ichor!</span>", "<span class='inathneq'>\"Lbh jvyy or bxnl, puvyq.\"</span>")
vitality -= revival_cost
break
else
break
if(!total_damage)
break
var/vitality_for_cycle = min(vitality, 3)
if(clone_to_heal && vitality_for_cycle)
var/healing = min(vitality_for_cycle, clone_to_heal)
vitality_for_cycle -= healing
L.adjustCloneLoss(-healing)
vitality -= healing
if(tox_to_heal && vitality_for_cycle)
var/healing = min(vitality_for_cycle, tox_to_heal)
vitality_for_cycle -= healing
L.adjustToxLoss(-healing)
vitality -= healing
if(burn_to_heal && vitality_for_cycle)
var/healing = min(vitality_for_cycle, burn_to_heal)
vitality_for_cycle -= healing
L.adjustFireLoss(-healing)
vitality -= healing
if(brute_to_heal && vitality_for_cycle)
var/healing = min(vitality_for_cycle, brute_to_heal)
vitality_for_cycle -= healing
L.adjustBruteLoss(-healing)
vitality -= healing
if(oxy_to_heal && vitality_for_cycle)
var/healing = min(vitality_for_cycle, oxy_to_heal)
vitality_for_cycle -= healing
L.adjustOxyLoss(-healing)
vitality -= healing
sleep(2)
animation_number = initial(animation_number)
sigil_active = FALSE
animate(src, alpha = initial(alpha), time = 20)
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
@@ -0,0 +1,248 @@
//The gateway to Reebe, from which Ratvar emerges.
/obj/structure/destructible/clockwork/massive/celestial_gateway
name = "Gateway to the Celestial Derelict"
desc = "A massive, thrumming rip in spacetime."
clockwork_desc = "A portal to the Celestial Derelict. Massive and intimidating, it is the only thing that can both transport Ratvar and withstand the massive amount of energy he emits."
obj_integrity = 600
max_integrity = 600
mouse_opacity = 2
icon = 'icons/effects/clockwork_effects.dmi'
icon_state = "nothing"
density = FALSE
invisibility = INVISIBILITY_MAXIMUM
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
can_be_repaired = FALSE
var/progress_in_seconds = 0 //Once this reaches GATEWAY_RATVAR_ARRIVAL, it's game over
var/purpose_fulfilled = FALSE
var/first_sound_played = FALSE
var/second_sound_played = FALSE
var/third_sound_played = FALSE
var/ratvar_portal = TRUE //if the gateway actually summons ratvar or just produces a hugeass conversion burst
var/obj/effect/clockwork/overlay/gateway_glow/glow
var/obj/effect/countdown/clockworkgate/countdown
/obj/structure/destructible/clockwork/massive/celestial_gateway/New()
..()
addtimer(src, "spawn_animation", 0)
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/spawn_animation()
var/turf/T = get_turf(src)
var/objective_is_gateway = (ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY)
new/obj/effect/clockwork/general_marker/inathneq(T)
if(objective_is_gateway)
hierophant_message("<span class='inathneq'>\"[text2ratvar("Engine, come forth and show your servants your mercy")]!\"</span>")
else
hierophant_message("<span class='inathneq'>\"[text2ratvar("We will show all the mercy of Engine")]!\"</span>")
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 30, 0)
sleep(10)
new/obj/effect/clockwork/general_marker/sevtug(T)
if(objective_is_gateway)
hierophant_message("<span class='sevtug'>\"[text2ratvar("Engine, come forth and show this station your decorating skills")]!\"</span>")
else
hierophant_message("<span class='sevtug'>\"[text2ratvar("We will show all Engine's decorating skills")]!\"</span>")
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 45, 0)
sleep(10)
new/obj/effect/clockwork/general_marker/nezbere(T)
if(objective_is_gateway)
hierophant_message("<span class='nezbere'>\"[text2ratvar("Engine, come forth and shine your light across this realm")]!!\"</span>")
else
hierophant_message("<span class='nezbere'>\"[text2ratvar("We will show all Engine's light")]!!\"</span>")
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 60, 0)
sleep(10)
new/obj/effect/clockwork/general_marker/nzcrentr(T)
if(objective_is_gateway)
hierophant_message("<span class='nzcrentr'>\"[text2ratvar("Engine, come forth")].\"</span>")
else
hierophant_message("<span class='nzcrentr'>\"[text2ratvar("We will show all Engine's power")].\"</span>")
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 75, 0)
sleep(10)
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 100, 0)
var/list/open_turfs = list()
for(var/turf/open/OT in orange(1, T))
if(!is_blocked_turf(OT))
open_turfs |= OT
if(open_turfs.len)
for(var/mob/living/L in T)
L.forceMove(pick(open_turfs))
resistance_flags &= ~INDESTRUCTIBLE
density = TRUE
invisibility = 0
glow = new(get_turf(src))
countdown = new(src)
countdown.start()
var/area/gate_area = get_area(src)
hierophant_message("<span class='large_brass'><b>A gateway to the Celestial Derelict has been created in [gate_area.map_name]!</b></span>", FALSE, src)
if(!objective_is_gateway)
ratvar_portal = FALSE
hierophant_message("<span class='big_brass'>This newly constructed gateway will not free Ratvar, \
and will instead simply proselytize and convert everything and everyone on the station.</span>", TRUE)
SSshuttle.registerHostileEnvironment(src)
START_PROCESSING(SSprocessing, src)
/obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy()
STOP_PROCESSING(SSprocessing, src)
if(!purpose_fulfilled)
var/area/gate_area = get_area(src)
hierophant_message("<span class='large_brass'><b>A gateway to the Celestial Derelict has fallen at [gate_area.map_name]!</b></span>")
send_to_playing_players(sound(null, 0, channel = 8))
var/was_stranded = SSshuttle.emergency.mode == SHUTTLE_STRANDED
SSshuttle.clearHostileEnvironment(src)
if(!was_stranded && !purpose_fulfilled && second_sound_played)
priority_announce("Massive energy anomaly no longer on short-range scanners.","Anomaly Alert")
if(glow)
qdel(glow)
glow = null
if(countdown)
qdel(countdown)
countdown = null
. = ..()
/obj/structure/destructible/clockwork/massive/celestial_gateway/deconstruct(disassembled = TRUE)
if(!(flags & NODECONSTRUCT))
if(!disassembled)
resistance_flags |= INDESTRUCTIBLE
countdown.stop()
visible_message("<span class='userdanger'>The [src] begins to pulse uncontrollably... you might want to run!</span>")
send_to_playing_players(sound('sound/effects/clockcult_gateway_disrupted.ogg', 0, channel = 8, volume = 50))
make_glow()
glow.icon_state = "clockwork_gateway_disrupted"
resistance_flags |= INDESTRUCTIBLE
sleep(27)
explosion(src, 1, 3, 8, 8)
qdel(src)
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/make_glow()
if(!glow)
glow = PoolOrNew(/obj/effect/clockwork/overlay/gateway_glow, get_turf(src))
glow.linked = src
/obj/structure/destructible/clockwork/massive/celestial_gateway/ex_act(severity)
var/damage = max((obj_integrity * 0.70) / severity, 100) //requires multiple bombs to take down
take_damage(damage, BRUTE, "bomb", 0)
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/get_arrival_text(s_on_time)
. = "IMMINENT"
if(!obj_integrity)
. = "DETONATING"
else if(GATEWAY_RATVAR_ARRIVAL - progress_in_seconds > 0)
. = "[round(max((GATEWAY_RATVAR_ARRIVAL - progress_in_seconds) / (GATEWAY_SUMMON_RATE), 0), 1)][s_on_time ? "S":""]"
/obj/structure/destructible/clockwork/massive/celestial_gateway/examine(mob/user)
icon_state = "spatial_gateway" //cheat wildly by pretending to have an icon
..()
icon_state = initial(icon_state)
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='big'><b>Seconds until [ratvar_portal ? "Ratvar's arrival":"Proselytization"]:</b> [get_arrival_text(TRUE)]</span>"
switch(progress_in_seconds)
if(-INFINITY to GATEWAY_REEBE_FOUND)
user << "<span class='heavy_brass'>It's still opening.</span>"
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
user << "<span class='heavy_brass'>It's reached the Celestial Derelict and is drawing power from it.</span>"
if(GATEWAY_RATVAR_COMING to INFINITY)
user << "<span class='heavy_brass'>[ratvar_portal ? "Ratvar is coming through the gateway":"The gateway is glowing with massed power"]!</span>"
else
switch(progress_in_seconds)
if(-INFINITY to GATEWAY_REEBE_FOUND)
user << "<span class='warning'>It's a swirling mass of blackness.</span>"
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
user << "<span class='warning'>It seems to be leading somewhere.</span>"
if(GATEWAY_RATVAR_COMING to INFINITY)
user << "<span class='boldwarning'>[ratvar_portal ? "Something is coming through":"It's glowing brightly"]!</span>"
/obj/structure/destructible/clockwork/massive/celestial_gateway/process()
if(!progress_in_seconds || prob(7))
for(var/M in player_list)
if(M && !isnewplayer(M))
M << "<span class='warning'><b>You hear otherworldly sounds from the [dir2text(get_dir(get_turf(M), get_turf(src)))]...</span>"
if(!obj_integrity)
return 0
for(var/t in RANGE_TURFS(1, loc))
if(iswallturf(t))
var/turf/closed/wall/W = t
W.dismantle_wall()
else if(t && (isclosedturf(t) || !is_blocked_turf(t)))
var/turf/T = t
T.ChangeTurf(/turf/open/floor/clockwork)
for(var/obj/O in orange(1, src))
if(!istype(O, /obj/effect) && O.density)
if(!step_away(O, src, 2) || get_dist(O, src) < 2)
O.take_damage(50, BURN, "bomb")
O.update_icon()
progress_in_seconds += GATEWAY_SUMMON_RATE
switch(progress_in_seconds)
if(-INFINITY to GATEWAY_REEBE_FOUND)
if(!first_sound_played)
send_to_playing_players(sound('sound/effects/clockcult_gateway_charging.ogg', 1, channel = 8, volume = 30))
first_sound_played = TRUE
make_glow()
glow.icon_state = "clockwork_gateway_charging"
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
if(!second_sound_played)
var/area/gate_area = get_area(src)
priority_announce("Massive energy anomaly detected on short-range scanners. Location: [gate_area.map_name].", "Anomaly Alert")
send_to_playing_players(sound('sound/effects/clockcult_gateway_active.ogg', 1, channel = 8, volume = 35))
second_sound_played = TRUE
make_glow()
glow.icon_state = "clockwork_gateway_active"
if(GATEWAY_RATVAR_COMING to GATEWAY_RATVAR_ARRIVAL)
if(!third_sound_played)
send_to_playing_players(sound('sound/effects/clockcult_gateway_closing.ogg', 1, channel = 8, volume = 40))
third_sound_played = TRUE
make_glow()
glow.icon_state = "clockwork_gateway_closing"
if(GATEWAY_RATVAR_ARRIVAL to INFINITY)
if(!purpose_fulfilled)
countdown.stop()
resistance_flags |= INDESTRUCTIBLE
purpose_fulfilled = TRUE
make_glow()
animate(glow, transform = matrix() * 1.5, alpha = 255, time = 125)
send_to_playing_players(sound('sound/effects/ratvar_rises.ogg', 0, channel = 8)) //End the sounds
sleep(125)
make_glow()
animate(glow, transform = matrix() * 3, alpha = 0, time = 5)
var/turf/startpoint = get_turf(src)
QDEL_IN(src, 3)
clockwork_gateway_activated = TRUE
if(ratvar_portal)
sleep(3)
new/obj/structure/destructible/clockwork/massive/ratvar(startpoint)
else
addtimer(SSshuttle.emergency, "request", 0, TIMER_NORMAL, null, 0) //call the shuttle immediately
sleep(3)
send_to_playing_players("<span class='ratvar'>\"[text2ratvar("Behold")]!\"</span>\n<span class='inathneq_large'>\"[text2ratvar("See Engine's mercy")]!\"</span>\n\
<span class='sevtug_large'>\"[text2ratvar("Observe Engine's design skills")]!\"</span>\n<span class='nezbere_large'>\"[text2ratvar("Behold Engine's light")]!!\"</span>\n\
<span class='nzcrentr_large'>\"[text2ratvar("Gaze upon Engine's power")]!\"</span>")
send_to_playing_players('sound/magic/clockwork/invoke_general.ogg')
var/x0 = startpoint.x
var/y0 = startpoint.y
for(var/I in spiral_range_turfs(255, startpoint))
var/turf/T = I
if(!T)
continue
var/dist = cheap_hypotenuse(T.x, T.y, x0, y0)
if(dist < 100)
dist = TRUE
else
dist = FALSE
T.ratvar_act(dist)
CHECK_TICK
for(var/mob/living/silicon/robot/R in silicon_mobs)
if(R && R.stat != DEAD && !is_servant_of_ratvar(R))
add_servant_of_ratvar(R)
for(var/i in ai_list)
var/mob/living/silicon/ai/A = i
if(A && A.stat != DEAD && !is_servant_of_ratvar(A))
add_servant_of_ratvar(A)
for(var/I in all_clockwork_mobs)
var/mob/M = I
if(M.stat == CONSCIOUS)
clockwork_say(M, text2ratvar(pick("Purge all untruths and honor Engine!", "All glory to Engine's light!", "Engine's power is unmatched!")))
//the actual appearance of the Gateway to the Celestial Derelict; an object so the edges of the gate can be clicked through.
/obj/effect/clockwork/overlay/gateway_glow
icon = 'icons/effects/96x96.dmi'
icon_state = "clockwork_gateway_charging"
pixel_x = -32
pixel_y = -32
layer = BELOW_OPEN_DOOR_LAYER
@@ -0,0 +1,48 @@
//Useless on their own, these shells can create powerful constructs.
/obj/structure/destructible/clockwork/shell
construction_value = 0
anchored = 0
density = 0
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/mobtype = /mob/living/simple_animal/hostile/clockwork
var/spawn_message = " is an error and you should yell at whoever spawned this shell."
/obj/structure/destructible/clockwork/shell/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/device/mmi/posibrain/soul_vessel))
if(!is_servant_of_ratvar(user))
..()
return 0
var/obj/item/device/mmi/posibrain/soul_vessel/S = I
if(!S.brainmob)
user << "<span class='warning'>[S] is inactive! Turn it on or capture a mind first.</span>"
return 0
if(S.brainmob && (!S.brainmob.client || !S.brainmob.mind))
user << "<span class='warning'>[S]'s trapped consciousness appears inactive!</span>"
return 0
user.visible_message("<span class='notice'>[user] places [S] in [src], where it fuses to the shell.</span>", "<span class='brass'>You place [S] in [src], fusing it to the shell.</span>")
var/mob/living/simple_animal/A = new mobtype(get_turf(src))
A.visible_message("<span class='brass'>[src][spawn_message]</span>")
S.brainmob.mind.transfer_to(A)
A.fully_replace_character_name(null, "[initial(A.name)] ([S.brainmob.name])")
user.drop_item()
qdel(S)
qdel(src)
return 1
else
return ..()
/obj/structure/destructible/clockwork/shell/cogscarab
name = "cogscarab shell"
desc = "A small brass shell with a cube-shaped receptable in its center. It gives off an aura of obsessive perfectionism."
clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a weak construct with an inbuilt proselytizer."
icon_state = "clockdrone_shell"
mobtype = /mob/living/simple_animal/drone/cogscarab
spawn_message = "'s eyes blink open, glowing bright red."
/obj/structure/destructible/clockwork/shell/fragment
name = "fragment shell"
desc = "A massive brass shell with a small cube-shaped receptable in its center. It gives off an aura of contained power."
clockwork_desc = "A dormant receptable that, when powered with a soul vessel, will become a powerful construct."
icon_state = "anime_fragment"
mobtype = /mob/living/simple_animal/hostile/clockwork/fragment
spawn_message = " whirs and rises from the ground on a flickering jet of reddish fire."
@@ -0,0 +1,95 @@
//Clockwork Obelisk: Can broadcast a message at a small power cost or outright open a spatial gateway at a massive power cost.
/obj/structure/destructible/clockwork/powered/clockwork_obelisk
name = "clockwork obelisk"
desc = "A large brass obelisk hanging in midair."
clockwork_desc = "A powerful obelisk that can send a message to all servants or open a gateway to a target servant or clockwork obelisk."
icon_state = "obelisk_inactive"
active_icon = "obelisk"
inactive_icon = "obelisk_inactive"
unanchored_icon = "obelisk_unwrenched"
construction_value = 20
max_integrity = 150
obj_integrity = 150
break_message = "<span class='warning'>The obelisk falls to the ground, undamaged!</span>"
debris = list(/obj/item/clockwork/alloy_shards/small = 3, \
/obj/item/clockwork/component/hierophant_ansible/obelisk = 1)
var/hierophant_cost = MIN_CLOCKCULT_POWER //how much it costs to broadcast with large text
var/gateway_cost = 2000 //how much it costs to open a gateway
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/New()
..()
toggle(1)
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='nzcrentr_small'>It requires <b>[hierophant_cost]W</b> to broadcast over the Hierophant Network, and <b>[gateway_cost]W</b> to open a Spatial Gateway.</span>"
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/can_be_unfasten_wrench(mob/user)
if(active)
user << "<span class='warning'>[src] is currently sustaining a gateway!</span>"
return FAILED_UNFASTEN
return ..()
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/forced_disable(bad_effects)
var/affected = 0
for(var/obj/effect/clockwork/spatial_gateway/SG in loc)
SG.ex_act(1)
affected++
if(bad_effects)
affected += try_use_power(MIN_CLOCKCULT_POWER*2)
return affected
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user)
if(!is_servant_of_ratvar(user) || total_accessable_power() < hierophant_cost || !anchored)
user << "<span class='warning'>You place your hand on the obelisk, but it doesn't react.</span>"
return
var/choice = alert(user,"You place your hand on the obelisk...",,"Hierophant Broadcast","Spatial Gateway","Cancel")
switch(choice)
if("Hierophant Broadcast")
if(active)
user << "<span class='warning'>The obelisk is sustaining a gateway and cannot broadcast!</span>"
return
if(!user.can_speak_vocal())
user << "<span class='warning'>You cannot speak through the obelisk!</span>"
return
var/input = stripped_input(usr, "Please choose a message to send over the Hierophant Network.", "Hierophant Broadcast", "")
if(!is_servant_of_ratvar(user) || !input || !user.canUseTopic(src, !issilicon(user)))
return
if(active)
user << "<span class='warning'>The obelisk is sustaining a gateway and cannot broadcast!</span>"
return
if(!try_use_power(hierophant_cost))
user << "<span class='warning'>The obelisk lacks the power to broadcast!</span>"
return
if(!user.can_speak_vocal())
user << "<span class='warning'>You cannot speak through the obelisk!</span>"
return
clockwork_say(user, text2ratvar("Hierophant Broadcast, activate! [html_decode(input)]"))
titled_hierophant_message(user, input, "big_brass", "large_brass")
if("Spatial Gateway")
if(active)
user << "<span class='warning'>The obelisk is already sustaining a gateway!</span>"
return
if(!try_use_power(gateway_cost))
user << "<span class='warning'>The obelisk lacks the power to open a gateway!</span>"
return
if(!user.can_speak_vocal())
user << "<span class='warning'>You need to be able to speak to open a gateway!</span>"
return
if(procure_gateway(user, round(100 * get_efficiency_mod(), 1), round(5 * get_efficiency_mod(), 1), 1) && !active)
clockwork_say(user, text2ratvar("Spatial Gateway, activate!"))
else
return_power(gateway_cost)
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/process()
if(!anchored)
return
if(locate(/obj/effect/clockwork/spatial_gateway) in loc)
icon_state = active_icon
density = 0
active = TRUE
else
icon_state = inactive_icon
density = 1
active = FALSE
@@ -0,0 +1,120 @@
//Interdiction Lens: A powerful artifact that constantly disrupts electronics and drains power but, if it fails to find something to disrupt, turns off.
/obj/structure/destructible/clockwork/powered/interdiction_lens
name = "interdiction lens"
desc = "An ominous, double-pronged brass totem. There's a strange gemstone clasped between the pincers."
clockwork_desc = "A powerful totem that constantly drains nearby electronics and funnels the power drained into nearby Sigils of Transmission or the area's APC."
icon_state = "interdiction_lens"
construction_value = 20
active_icon = "interdiction_lens_active"
inactive_icon = "interdiction_lens"
unanchored_icon = "interdiction_lens_unwrenched"
break_message = "<span class='warning'>The lens flares a blinding violet before shattering!</span>"
break_sound = 'sound/effects/Glassbr3.ogg'
var/recharging = 0 //world.time when the lens was last used
var/recharge_time = 1200 //if it drains no power and affects no objects, it turns off for two minutes
var/disabled = FALSE //if it's actually usable
var/interdiction_range = 14 //how large an area it drains and disables in
var/static/list/rage_messages = list("...", "Disgusting.", "Die.", "Foul.", "Worthless.", "Mortal.", "Unfit.", "Weak.", "Fragile.", "Useless.", "Leave my sight!")
/obj/structure/destructible/clockwork/powered/interdiction_lens/examine(mob/user)
..()
user << "<span class='[recharging > world.time ? "neovgre_small":"brass"]'>Its gemstone [recharging > world.time ? "has been breached by writhing tendrils of blackness that cover the totem" \
: "vibrates in place and thrums with power"].</span>"
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='neovgre_small'>If it fails to drain any electronics, it will disable itself for <b>[round(recharge_time/600, 1)]</b> minutes.</span>"
/obj/structure/destructible/clockwork/powered/interdiction_lens/toggle(fast_process, mob/living/user)
. = ..()
if(active)
SetLuminosity(4, 2)
else
SetLuminosity(0)
/obj/structure/destructible/clockwork/powered/interdiction_lens/attack_hand(mob/living/user)
if(user.canUseTopic(src, !issilicon(user)))
if(disabled)
user << "<span class='warning'>As you place your hand on the gemstone, cold tendrils of black matter crawl up your arm. You quickly pull back.</span>"
return 0
toggle(0, user)
/obj/structure/destructible/clockwork/powered/interdiction_lens/forced_disable(bad_effects)
if(disabled)
return FALSE
if(!active)
toggle(0)
visible_message("<span class='warning'>The gemstone suddenly turns horribly dark, writhing tendrils covering it!</span>")
recharging = world.time + recharge_time
flick("interdiction_lens_discharged", src)
icon_state = "interdiction_lens_inactive"
SetLuminosity(2,1)
disabled = TRUE
return TRUE
/obj/structure/destructible/clockwork/powered/interdiction_lens/process()
. = ..()
if(recharging > world.time)
return
if(disabled)
visible_message("<span class='warning'>The writhing tendrils return to the gemstone, which begins to glow with power!</span>")
flick("interdiction_lens_recharged", src)
disabled = FALSE
toggle(0)
else
var/successfulprocess = FALSE
var/power_drained = 0
var/list/atoms_to_test = list()
for(var/A in spiral_range_turfs(interdiction_range, src))
var/turf/T = A
for(var/M in T)
atoms_to_test |= M
CHECK_TICK
var/unconverted_ai = FALSE
var/efficiency = get_efficiency_mod()
var/rage_modifier = get_efficiency_mod(TRUE)
for(var/i in ai_list)
var/mob/living/silicon/ai/AI = i
if(AI && AI.stat != DEAD && !is_servant_of_ratvar(AI))
unconverted_ai = TRUE
for(var/M in atoms_to_test)
var/atom/movable/A = M
if(!A || qdeleted(A) || A == target_apc)
continue
power_drained += (A.power_drain(TRUE) * efficiency)
if(prob(1 * rage_modifier))
A << "<span class='neovgre'>\"[text2ratvar(pick(rage_messages))]\"</span>"
if(prob(100 * (efficiency * efficiency)))
if(istype(A, /obj/machinery/camera) && unconverted_ai)
var/obj/machinery/camera/C = A
if(C.isEmpProof() || !C.status)
continue
successfulprocess = TRUE
if(C.emped)
continue
C.emp_act(1)
else if(istype(A, /obj/item/device/radio))
var/obj/item/device/radio/O = A
successfulprocess = TRUE
if(O.emped || !O.on)
continue
O.emp_act(1)
else if((isliving(A) && !is_servant_of_ratvar(A)) || istype(A, /obj/structure/closet) || istype(A, /obj/item/weapon/storage)) //other things may have radios in them but we don't care
for(var/obj/item/device/radio/O in A.GetAllContents())
successfulprocess = TRUE
if(O.emped || !O.on)
continue
O.emp_act(1)
CHECK_TICK
if(power_drained && power_drained >= MIN_CLOCKCULT_POWER && return_power(power_drained))
successfulprocess = TRUE
playsound(src, 'sound/items/PSHOOM.ogg', 50 * efficiency, 1, interdiction_range-7, 1)
if(!successfulprocess)
forced_disable()
@@ -0,0 +1,152 @@
//Mania Motor: A pair of antenna that, while active, cause braindamage and hallucinations in nearby human mobs.
/obj/structure/destructible/clockwork/powered/mania_motor
name = "mania motor"
desc = "A pair of antenna with what appear to be sockets around the base. It reminds you of an antlion."
clockwork_desc = "A transmitter that allows Sevtug to whisper into the minds of nearby non-servants, causing hallucinations and brain damage as long as it remains powered."
icon_state = "mania_motor_inactive"
active_icon = "mania_motor"
inactive_icon = "mania_motor_inactive"
unanchored_icon = "mania_motor_unwrenched"
construction_value = 20
max_integrity = 80
obj_integrity = 80
break_message = "<span class='warning'>The antenna break off, leaving a pile of shards!</span>"
debris = list(/obj/item/clockwork/alloy_shards/large = 1, \
/obj/item/clockwork/alloy_shards/small = 3, \
/obj/item/clockwork/component/geis_capacitor/antennae = 1)
var/mania_cost = 200
var/convert_attempt_cost = 500
var/convert_cost = 500
var/static/list/mania_messages = list("Go nuts.", "Take a crack at crazy.", "Make a bid for insanity.", "Get kooky.", "Move towards mania.", "Become bewildered.", "Wax wild.", \
"Go round the bend.", "Land in lunacy.", "Try dementia.", "Strive to get a screw loose.")
var/static/list/compel_messages = list("Come closer.", "Approach the transmitter.", "Touch the antennae.", "I always have to deal with idiots. Move towards the mania motor.", \
"Advance forward and place your head between the antennae - that's all it's good for.", "If you were smarter, you'd be over here already.", "Move FORWARD, you fool.")
var/static/list/convert_messages = list("You won't do. Go to sleep while I tell these nitwits how to convert you.", "You are insufficient. I must instruct these idiots in the art of conversion.", \
"Oh of course, someone we can't convert. These servants are fools.", "How hard is it to use a Sigil, anyway? All it takes is dragging someone onto it.", \
"How do they fail to use a Sigil of Accession, anyway?", "Why is it that all servants are this inept?", "It's quite likely you'll be stuck here for a while.")
var/static/list/close_messages = list("Well, you can't reach the motor from THERE, you moron.", "Interesting location. I'd prefer if you went somewhere you could ACTUALLY TOUCH THE ANTENNAE!", \
"Amazing. You somehow managed to wedge yourself somewhere you can't actually reach the motor from.", "Such a show of idiocy is unparalleled. Perhaps I should put you on display?", \
"Did you do this on purpose? I can't imagine you doing so accidentally. Oh, wait, I can.", "How is it that such smart creatures can still do something AS STUPID AS THIS!")
/obj/structure/destructible/clockwork/powered/mania_motor/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='sevtug_small'>It requires <b>[mania_cost]W</b> to run, and <b>[convert_attempt_cost + convert_cost]W</b> to convert humans adjecent to it.</span>"
/obj/structure/destructible/clockwork/powered/mania_motor/forced_disable(bad_effects)
if(active)
if(bad_effects)
try_use_power(MIN_CLOCKCULT_POWER*2)
visible_message("<span class='warning'>[src] hums loudly, then the sockets at its base fall dark!</span>")
playsound(src, 'sound/effects/screech.ogg', 40, 1)
toggle()
return TRUE
/obj/structure/destructible/clockwork/powered/mania_motor/attack_hand(mob/living/user)
if(user.canUseTopic(src, !issilicon(user)) && is_servant_of_ratvar(user))
if(!total_accessable_power() >= mania_cost)
user << "<span class='warning'>[src] needs more power to function!</span>"
return 0
toggle(0, user)
/obj/structure/destructible/clockwork/powered/mania_motor/toggle(fast_process, mob/living/user)
. = ..()
if(active)
SetLuminosity(2, 1)
else
SetLuminosity(0)
/obj/structure/destructible/clockwork/powered/mania_motor/process()
if(try_use_power(mania_cost))
var/turf/T = get_turf(src)
var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected
var/efficiency = get_efficiency_mod()
for(var/mob/living/carbon/human/H in view(1, src))
if(is_servant_of_ratvar(H) || H.null_rod_check())
continue
if(H.Adjacent(src) && try_use_power(convert_attempt_cost))
if(is_eligible_servant(H) && try_use_power(convert_cost))
H << "<span class='sevtug'>\"[text2ratvar("You are mine and his, now.")]\"</span>"
H.playsound_local(T, hum, 80, 1)
add_servant_of_ratvar(H)
H.Paralyse(5)
else if(!H.stat)
if(H.getBrainLoss() >= 100)
H.Paralyse(5)
H << "<span class='sevtug'>\"[text2ratvar(pick(convert_messages))]\"</span>"
else
H.adjustBrainLoss(100 * efficiency)
H.visible_message("<span class='warning'>[H] reaches out and touches [src].</span>", "<span class='sevtug'>You touch [src] involuntarily.</span>")
else
visible_message("<span class='warning'>[src]'s antennae fizzle quietly.</span>")
playsound(src, 'sound/effects/light_flicker.ogg', 50, 1)
for(var/mob/living/carbon/human/H in range(10, src))
if(is_servant_of_ratvar(H))
if(H.getBrainLoss() || H.hallucination || H.druggy || H.dizziness || H.confused)
H.adjustBrainLoss(-H.getBrainLoss()) //heals servants of braindamage, hallucination, druggy, dizziness, and confusion
H.hallucination = 0
H.adjust_drugginess(-H.druggy)
H.dizziness = 0
H.confused = 0
else if(!H.null_rod_check() && H.stat == CONSCIOUS)
var/distance = get_dist(T, get_turf(H))
var/falloff_distance = min((110) - distance * 10, 80)
var/sound_distance = falloff_distance * 0.5
var/targetbrainloss = H.getBrainLoss()
if(distance >= 4 && prob(falloff_distance * 0.5))
H << "<span class='sevtug_small'>\"[text2ratvar(pick(mania_messages))]\"</span>"
H.playsound_local(T, hum, sound_distance, 1)
switch(distance)
if(2 to 3)
if(prob(falloff_distance * 0.5))
if(prob(falloff_distance))
H << "<span class='sevtug_small'>\"[text2ratvar(pick(mania_messages))]\"</span>"
else
H << "<span class='sevtug'>\"[text2ratvar(pick(compel_messages))]\"</span>"
if(targetbrainloss <= 50)
H.adjustBrainLoss((50 * efficiency) - targetbrainloss) //got too close had brain eaten
H.adjust_drugginess(Clamp(7 * efficiency, 0, 100 - H.druggy))
H.hallucination = min(H.hallucination + (7 * efficiency), 100)
H.dizziness = min(H.dizziness + (3 * efficiency), 45)
H.confused = min(H.confused + (3 * efficiency), 45)
if(4 to 5)
if(targetbrainloss <= 50)
H.adjustBrainLoss(1 * efficiency)
H.adjust_drugginess(Clamp(5 * efficiency, 0, 80 - H.druggy))
H.hallucination = min(H.hallucination + (5 * efficiency), 80)
H.dizziness = min(H.dizziness + (2 * efficiency), 30)
H.confused = min(H.confused + (2 * efficiency), 30)
if(6 to 7)
if(targetbrainloss <= 30)
H.adjustBrainLoss(1 * efficiency)
H.adjust_drugginess(Clamp(2 * efficiency, 0, 60 - H.druggy))
H.hallucination = min(H.hallucination + (2 * efficiency), 60)
H.dizziness = min(H.dizziness + (2 * efficiency), 15)
H.confused = min(H.confused + (2 * efficiency), 15)
if(8 to 9)
if(targetbrainloss <= 10)
H.adjustBrainLoss(1 * efficiency)
H.adjust_drugginess(Clamp(2 * efficiency, 0, 40 - H.druggy))
H.hallucination = min(H.hallucination + (2 * efficiency), 40)
if(10 to INFINITY)
H.adjust_drugginess(Clamp(2 * efficiency, 0, 20 - H.druggy))
H.hallucination = min(H.hallucination + (2 * efficiency), 20)
else //if it's a distance of 1 and they can't see it/aren't adjacent or they're on top of it(how'd they get on top of it and still trigger this???)
if(prob(falloff_distance * 0.5))
if(prob(falloff_distance))
H << "<span class='sevtug'>\"[text2ratvar(pick(compel_messages))]\"</span>"
else if(prob(falloff_distance * 0.5))
H << "<span class='sevtug'>\"[text2ratvar(pick(close_messages))]\"</span>"
else
H << "<span class='sevtug_small'>\"[text2ratvar(pick(mania_messages))]\"</span>"
if(targetbrainloss <= 99)
H.adjustBrainLoss((99 * efficiency) - targetbrainloss)
H.adjust_drugginess(Clamp(10 * efficiency, 0, 150 - H.druggy))
H.hallucination = min(H.hallucination + (10 * efficiency), 150)
H.dizziness = min(H.dizziness + (5 * efficiency), 60)
H.confused = min(H.confused + (5 * efficiency), 60)
else
forced_disable(FALSE)
@@ -0,0 +1,146 @@
//Mending Motor: A prism that consumes replicant alloy or power to repair nearby mechanical servants at a quick rate.
/obj/structure/destructible/clockwork/powered/mending_motor
name = "mending motor"
desc = "A dark onyx prism, held in midair by spiraling tendrils of stone."
clockwork_desc = "A powerful prism that rapidly repairs nearby mechanical servants and clockwork structures."
icon_state = "mending_motor_inactive"
active_icon = "mending_motor"
inactive_icon = "mending_motor_inactive"
unanchored_icon = "mending_motor_unwrenched"
construction_value = 20
max_integrity = 125
obj_integrity = 125
break_message = "<span class='warning'>The prism collapses with a heavy thud!</span>"
debris = list(/obj/item/clockwork/alloy_shards/small = 5, \
/obj/item/clockwork/alloy_shards/medium = 1, \
/obj/item/clockwork/alloy_shards/large = 1, \
/obj/item/clockwork/component/vanguard_cogwheel = 1)
var/stored_alloy = 0
var/max_alloy = REPLICANT_ALLOY_POWER * 10
var/heal_attempts = 4
var/static/list/heal_finish_messages = list("There, all mended!", "Try not to get too damaged.", "No more dents and scratches for you!", "Champions never die.", "All patched up.", \
"Ah, child, it's okay now.")
var/static/list/heal_failure_messages = list("Pain is temporary.", "What you do for the Justiciar is eternal.", "Bear this for me.", "Be strong, child.", "Please, be careful!", \
"If you die, you will be remembered.")
var/static/list/mending_motor_typecache = typecacheof(list(
/obj/structure/destructible/clockwork,
/obj/machinery/door/airlock/clockwork,
/obj/machinery/door/window/clockwork,
/obj/structure/window/reinforced/clockwork,
/obj/structure/table/reinforced/brass))
/obj/structure/destructible/clockwork/powered/mending_motor/prefilled
stored_alloy = REPLICANT_ALLOY_POWER //starts with 1 replicant alloy's worth of power
/obj/structure/destructible/clockwork/powered/mending_motor/total_accessable_power()
. = ..()
if(. != INFINITY)
. += accessable_alloy_power()
/obj/structure/destructible/clockwork/powered/mending_motor/proc/accessable_alloy_power()
return stored_alloy
/obj/structure/destructible/clockwork/powered/mending_motor/use_power(amount)
var/alloypower = accessable_alloy_power()
while(alloypower >= MIN_CLOCKCULT_POWER && amount >= MIN_CLOCKCULT_POWER)
stored_alloy -= MIN_CLOCKCULT_POWER
alloypower -= MIN_CLOCKCULT_POWER
amount -= MIN_CLOCKCULT_POWER
return ..()
/obj/structure/destructible/clockwork/powered/mending_motor/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='alloy'>It contains <b>[stored_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER]/[max_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER]</b> units of liquified alloy, \
which is equivalent to <b>[stored_alloy]W/[max_alloy]W</b> of power.</span>"
user << "<span class='inathneq_small'>It requires at least <b>[MIN_CLOCKCULT_POWER]W</b> to attempt to repair clockwork mobs, structures, or converted silicons.</span>"
/obj/structure/destructible/clockwork/powered/mending_motor/forced_disable(bad_effects)
if(active)
if(bad_effects)
try_use_power(MIN_CLOCKCULT_POWER*2)
visible_message("<span class='warning'>[src] emits an airy chuckling sound and falls dark!</span>")
toggle()
return TRUE
/obj/structure/destructible/clockwork/powered/mending_motor/attack_hand(mob/living/user)
if(user.canUseTopic(src, !issilicon(user)) && is_servant_of_ratvar(user))
if(total_accessable_power() < MIN_CLOCKCULT_POWER)
user << "<span class='warning'>[src] needs more power or replicant alloy to function!</span>"
return 0
toggle(0, user)
/obj/structure/destructible/clockwork/powered/mending_motor/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/clockwork/component/replicant_alloy) && is_servant_of_ratvar(user))
if(stored_alloy + REPLICANT_ALLOY_POWER > max_alloy)
user << "<span class='warning'>[src] is too full to accept any more alloy!</span>"
return 0
playsound(user, 'sound/machines/click.ogg', 50, 1)
clockwork_say(user, text2ratvar("Transmute into fuel."), TRUE)
user << "<span class='brass'>You force [I] to liquify and pour it into [src]'s compartments. \
It now contains <b>[stored_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER]/[max_alloy*CLOCKCULT_POWER_TO_ALLOY_MULTIPLIER]</b> units of liquified alloy.</span>"
stored_alloy = stored_alloy + REPLICANT_ALLOY_POWER
user.drop_item()
qdel(I)
return 1
else
return ..()
/obj/structure/destructible/clockwork/powered/mending_motor/process()
var/efficiency = get_efficiency_mod()
for(var/atom/movable/M in range(7, src))
var/turf/T
if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
T = get_turf(M)
var/mob/living/simple_animal/hostile/clockwork/marauder/E = M
var/is_marauder = istype(E)
if(E.health == E.maxHealth || E.stat == DEAD || (is_marauder && !E.fatigue))
continue
for(var/i in 1 to heal_attempts)
if(E.health < E.maxHealth || (is_marauder && E.fatigue))
if(try_use_power(MIN_CLOCKCULT_POWER))
E.adjustHealth(-(8 * efficiency))
PoolOrNew(/obj/effect/overlay/temp/heal, list(T, "#1E8CE1"))
else
E << "<span class='inathneq'>\"[text2ratvar(pick(heal_failure_messages))]\"</span>"
break
else
E << "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>"
break
else if(is_type_in_typecache(M, mending_motor_typecache))
T = get_turf(M)
var/obj/structure/destructible/clockwork/C = M
if(C.obj_integrity == C.max_integrity || (istype(C) && !C.can_be_repaired))
continue
for(var/i in 1 to heal_attempts)
if(C.obj_integrity < C.max_integrity)
if(try_use_power(MIN_CLOCKCULT_POWER))
C.obj_integrity = min(C.obj_integrity + (8 * efficiency), C.max_integrity)
if(C == src)
efficiency = get_efficiency_mod()
C.update_icon()
PoolOrNew(/obj/effect/overlay/temp/heal, list(T, "#1E8CE1"))
else
break
else
break
else if(issilicon(M))
T = get_turf(M)
var/mob/living/silicon/S = M
if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S))
continue
for(var/i in 1 to heal_attempts)
if(S.health < S.maxHealth)
if(try_use_power(MIN_CLOCKCULT_POWER))
S.adjustBruteLoss(-(5 * efficiency))
S.adjustFireLoss(-(3 * efficiency))
PoolOrNew(/obj/effect/overlay/temp/heal, list(T, "#1E8CE1"))
else
S << "<span class='inathneq'>\"[text2ratvar(pick(heal_failure_messages))]\"</span>"
break
else
S << "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>"
break
. = ..()
if(. < MIN_CLOCKCULT_POWER)
forced_disable(FALSE)
@@ -0,0 +1,123 @@
//Ocular warden: Low-damage, low-range turret. Deals constant damage to whoever it makes eye contact with.
/obj/structure/destructible/clockwork/ocular_warden
name = "ocular warden"
desc = "A large brass eye with tendrils trailing below it and a wide red iris."
clockwork_desc = "A fragile turret that will deal sustained damage to any non-faithful it sees."
icon_state = "ocular_warden"
unanchored_icon = "ocular_warden_unwrenched"
obj_integrity = 25
max_integrity = 25
construction_value = 15
layer = HIGH_OBJ_LAYER
break_message = "<span class='warning'>The warden's eye gives a glare of utter hate before falling dark!</span>"
debris = list(/obj/item/clockwork/component/belligerent_eye/blind_eye = 1)
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/damage_per_tick = 2.7
var/sight_range = 3
var/atom/movable/target
var/list/idle_messages = list(" sulkily glares around.", " lazily drifts from side to side.", " looks around for something to burn.", " slowly turns in circles.")
/obj/structure/destructible/clockwork/ocular_warden/New()
..()
START_PROCESSING(SSfastprocess, src)
/obj/structure/destructible/clockwork/ocular_warden/Destroy()
STOP_PROCESSING(SSfastprocess, src)
return ..()
/obj/structure/destructible/clockwork/ocular_warden/examine(mob/user)
..()
user << "<span class='brass'>[target ? "<b>It's fixated on [target]!</b>" : "Its gaze is wandering aimlessly."]</span>"
/obj/structure/destructible/clockwork/ocular_warden/hulk_damage()
return 25
/obj/structure/destructible/clockwork/ocular_warden/can_be_unfasten_wrench(mob/user)
if(anchored)
if(obj_integrity <= max_integrity * 0.25)
user << "<span class='warning'>[src] is too damaged to unsecure!</span>"
return FAILED_UNFASTEN
else
for(var/obj/structure/destructible/clockwork/ocular_warden/W in orange(3, src))
user << "<span class='neovgre'>You sense another ocular warden too near this location. Activating this one this close would cause them to fight.</span>"
return FAILED_UNFASTEN
return SUCCESSFUL_UNFASTEN
/obj/structure/destructible/clockwork/ocular_warden/ratvar_act()
..()
if(ratvar_awakens)
damage_per_tick = 10
sight_range = 6
else
damage_per_tick = initial(damage_per_tick)
sight_range = initial(sight_range)
/obj/structure/destructible/clockwork/ocular_warden/process()
if(!anchored)
lose_target()
return
var/list/validtargets = acquire_nearby_targets()
if(target)
if(!(target in validtargets))
lose_target()
else
if(isliving(target))
var/mob/living/L = target
if(!L.null_rod_check())
if(isrevenant(L))
var/mob/living/simple_animal/revenant/R = L
if(R.revealed)
R.unreveal_time += 2
else
R.reveal(10)
L.adjustFireLoss((!iscultist(L) ? damage_per_tick : damage_per_tick * 2) * get_efficiency_mod()) //Nar-Sian cultists take additional damage
if(ratvar_awakens && L)
L.adjust_fire_stacks(damage_per_tick)
L.IgniteMob()
else if(istype(target,/obj/mecha))
var/obj/mecha/M = target
M.take_damage(damage_per_tick * get_efficiency_mod(), BURN, "melee", 1, get_dir(src, M))
PoolOrNew(/obj/effect/overlay/temp/ratvar/ocular_warden, get_turf(target))
setDir(get_dir(get_turf(src), get_turf(target)))
if(!target)
if(validtargets.len)
target = pick(validtargets)
visible_message("<span class='warning'>[src] swivels to face [target]!</span>")
if(isliving(target))
var/mob/living/L = target
L << "<span class='heavy_brass'>\"I SEE YOU!\"</span>\n<span class='userdanger'>[src]'s gaze [ratvar_awakens ? "melts you alive" : "burns you"]!</span>"
else if(istype(target,/obj/mecha))
var/obj/mecha/M = target
M.occupant << "<span class='heavy_brass'>\"I SEE YOU!\"</span>" //heeeellooooooo, person in mech.
else if(prob(0.5)) //Extremely low chance because of how fast the subsystem it uses processes
if(prob(50))
visible_message("<span class='notice'>[src][pick(idle_messages)]</span>")
else
setDir(pick(cardinal))//Random rotation
/obj/structure/destructible/clockwork/ocular_warden/proc/acquire_nearby_targets()
. = list()
for(var/mob/living/L in viewers(sight_range, src)) //Doesn't attack the blind
var/obj/item/weapon/storage/book/bible/B = L.bible_check()
if(B)
if(!(B.resistance_flags & ON_FIRE))
L << "<span class='warning'>Your [B.name] bursts into flames!</span>"
for(var/obj/item/weapon/storage/book/bible/BI in L.GetAllContents())
if(!(BI.resistance_flags & ON_FIRE))
BI.fire_act()
else if(!is_servant_of_ratvar(L) && !L.stat && L.mind && !L.restrained() && !(L.buckled && (L.lying || istype(L.buckled, /obj/structure/destructible/clockwork/geis_binding))) && \
!(L.disabilities & BLIND) && !L.null_rod_check())
. += L
for(var/N in mechas_list)
var/obj/mecha/M = N
if(get_dist(M, src) <= sight_range && M.occupant && !is_servant_of_ratvar(M.occupant) && (M in view(sight_range, src)))
. += M
/obj/structure/destructible/clockwork/ocular_warden/proc/lose_target()
if(!target)
return 0
target = null
visible_message("<span class='warning'>[src] settles and seems almost disappointed.</span>")
return 1
@@ -0,0 +1,145 @@
//Ratvar himself. Impossible to damage by most standard means, He will dominate the station and all upon it.
/obj/structure/destructible/clockwork/massive/ratvar
name = "Ratvar, the Clockwork Justiciar"
desc = "<span class='userdanger'>What is what is what are what real what is all a lie all a lie it's all a lie why how can what is</span>"
clockwork_desc = "<span class='large_brass'><b><i>Ratvar, the Clockwork Justiciar, your master eternal.</i></b></span>"
icon = 'icons/effects/512x512.dmi'
icon_state = "ratvar"
pixel_x = -235
pixel_y = -248
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
appearance_flags = 0
var/atom/prey //Whatever Ratvar is chasing
var/clashing = FALSE //If Ratvar is FUCKING FIGHTING WITH NAR-SIE
var/proselytize_range = 10
/obj/structure/destructible/clockwork/massive/ratvar/New()
..()
ratvar_awakens++
for(var/obj/O in all_clockwork_objects)
O.ratvar_act()
START_PROCESSING(SSobj, src)
send_to_playing_players("<span class='ratvar'>\"[text2ratvar("ONCE AGAIN MY LIGHT SHALL SHINE ACROSS THIS PATHETIC REALM")]!!\"</span>")
send_to_playing_players('sound/effects/ratvar_reveal.ogg')
var/image/alert_overlay = image('icons/effects/clockwork_effects.dmi', "ratvar_alert")
var/area/A = get_area(src)
notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [A.name] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay)
addtimer(SSshuttle.emergency, "request", 50, TIMER_NORMAL, null, 0.1)
/obj/structure/destructible/clockwork/massive/ratvar/Destroy()
ratvar_awakens--
for(var/obj/O in all_clockwork_objects)
O.ratvar_act()
STOP_PROCESSING(SSobj, src)
send_to_playing_players("<span class='heavy_brass'><font size=6>\"NO! I will not... be...</font> <font size=5>banished...</font> <font size=4>again...\"</font></span>")
return ..()
/obj/structure/destructible/clockwork/massive/ratvar/attack_ghost(mob/dead/observer/O)
var/alertresult = alert(O, "Embrace the Justiciar's light? You can no longer be cloned!",,"Yes", "No")
if(alertresult == "No" || !O)
return 0
var/mob/living/simple_animal/drone/cogscarab/ratvar/R = new/mob/living/simple_animal/drone/cogscarab/ratvar(get_turf(src))
R.visible_message("<span class='heavy_brass'>[R] forms, and its eyes blink open, glowing bright red!</span>")
R.key = O.key
/obj/structure/destructible/clockwork/massive/ratvar/Bump(atom/A)
var/turf/T = get_turf(A)
forceMove(T)
T.ratvar_act()
/obj/structure/destructible/clockwork/massive/ratvar/Process_Spacemove()
return clashing
/obj/structure/destructible/clockwork/massive/ratvar/process()
if(clashing) //I'm a bit occupied right now, thanks
return
for(var/I in circlerangeturfs(src, proselytize_range))
var/turf/T = I
T.ratvar_act()
for(var/I in circleviewturfs(src, round(proselytize_range * 0.5)))
var/turf/T = I
T.ratvar_act(1)
var/dir_to_step_in = pick(cardinal)
if(!prey)
for(var/obj/singularity/narsie/N in poi_list)
if(N.z == z)
prey = N
break
if(!prey) //In case there's a Nar-Sie
var/list/meals = list()
for(var/mob/living/L in living_mob_list)
if(L.z == z && !is_servant_of_ratvar(L) && L.mind)
meals += L
if(meals.len)
prey = pick(meals)
prey << "<span class='heavy_brass'><font size=5>\"You will do.\"</font></span>\n\
<span class='userdanger'>Something very large and very malevolent begins lumbering its way towards you...</span>"
prey << 'sound/effects/ratvar_reveal.ogg'
else
if(prob(10) || is_servant_of_ratvar(prey) || prey.z != z)
prey << "<span class='heavy_brass'><font size=5>\"How dull. Leave me.\"</font></span>\n\
<span class='userdanger'>You feel tremendous relief as a set of horrible eyes loses sight of you...</span>"
prey = null
else
dir_to_step_in = get_dir(src, prey) //Unlike Nar-Sie, Ratvar ruthlessly chases down his target
step(src, dir_to_step_in)
/obj/structure/destructible/clockwork/massive/ratvar/narsie_act()
if(clashing)
return FALSE
clashing = TRUE
world << "<span class='heavy_brass'><font size=5>\"[pick("BLOOD GOD!!!", "NAR-SIE!!!", "AT LAST, YOUR TIME HAS COME!")]\"</font></span>"
world << "<span class='cult'><font size=5>\"<b>Ratvar?! How?!</b>\"</font></span>"
for(var/obj/singularity/narsie/N in range(15, src))
if(N.clashing)
continue
N.clashing = TRUE
clash_of_the_titans(N) //IT'S TIME FOR THE BATTLE OF THE AGES
break
return TRUE
//Put me in Reebe, will you? Ratvar has found and is going to fucking murder Nar-Sie
/obj/structure/destructible/clockwork/massive/ratvar/proc/clash_of_the_titans(obj/singularity/narsie/narsie)
var/winner = "Undeclared"
var/base_victory_chance = 1
while(src && narsie)
send_to_playing_players('sound/magic/clockwork/ratvar_attack.ogg')
sleep(5.2)
for(var/mob/M in mob_list)
if(!isnewplayer(M))
flash_color(M, flash_color="#966400", flash_time=1)
shake_camera(M, 4, 3)
var/ratvar_chance = min(ticker.mode.servants_of_ratvar.len, 50)
var/narsie_chance = ticker.mode.cult.len
for(var/mob/living/simple_animal/hostile/construct/harvester/C in player_list)
narsie_chance++
ratvar_chance = rand(base_victory_chance, ratvar_chance)
narsie_chance = rand(base_victory_chance, min(narsie_chance, 50))
if(ratvar_chance > narsie_chance)
winner = "Ratvar"
break
sleep(rand(2,5))
send_to_playing_players('sound/magic/clockwork/narsie_attack.ogg')
sleep(7.4)
for(var/mob/M in mob_list)
if(!isnewplayer(M))
flash_color(M, flash_color="#C80000", flash_time=1)
shake_camera(M, 4, 3)
if(narsie_chance > ratvar_chance)
winner = "Nar-Sie"
break
base_victory_chance *= 2 //The clash has a higher chance of resolving each time both gods attack one another
switch(winner)
if("Ratvar")
send_to_playing_players("<span class='heavy_brass'><font size=5>\"[pick("DIE! DIE! DIE!", "FILTH!!!", "SUFFER!!!", text2ratvar("ROT FOR CENTURIES AS I HAVE!!"))]\"</font></span>\n\
<span class='cult'><font size=5>\"<b>[pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-")]\"</b></font></span>") //nar-sie get out
send_to_playing_players('sound/magic/clockwork/anima_fragment_attack.ogg')
send_to_playing_players('sound/magic/demon_dies.ogg')
clashing = FALSE
qdel(narsie)
if("Nar-Sie")
send_to_playing_players("<span class='cult'><font size=5>\"<b>[pick("Ha.", "Ra'sha fonn dest.", "You fool. To come here.")]</b>\"</font></span>") //Broken English
send_to_playing_players('sound/magic/demon_attack1.ogg')
send_to_playing_players('sound/magic/clockwork/anima_fragment_death.ogg')
narsie.clashing = FALSE
qdel(src)
@@ -0,0 +1,102 @@
//Tinkerer's cache: Stores components for later use.
/obj/structure/destructible/clockwork/cache
name = "tinkerer's cache"
desc = "A large brass spire with a flaming hole in its center."
clockwork_desc = "A brass container capable of storing a large amount of components.\n\
Shares components with all other caches and will gradually generate components if near a Clockwork Wall."
icon_state = "tinkerers_cache"
unanchored_icon = "tinkerers_cache_unwrenched"
construction_value = 10
break_message = "<span class='warning'>The cache's fire winks out before it falls in on itself!</span>"
max_integrity = 80
obj_integrity = 80
var/wall_generation_cooldown
var/turf/closed/wall/clockwork/linkedwall //if we've got a linked wall and are producing
/obj/structure/destructible/clockwork/cache/New()
..()
START_PROCESSING(SSobj, src)
clockwork_caches++
update_slab_info()
SetLuminosity(2,1)
/obj/structure/destructible/clockwork/cache/Destroy()
clockwork_caches--
update_slab_info()
STOP_PROCESSING(SSobj, src)
if(linkedwall)
linkedwall.linkedcache = null
linkedwall = null
return ..()
/obj/structure/destructible/clockwork/cache/process()
if(!anchored)
if(linkedwall)
linkedwall.linkedcache = null
linkedwall = null
return
for(var/turf/closed/wall/clockwork/C in range(4, src))
if(!C.linkedcache && !linkedwall)
C.linkedcache = src
linkedwall = C
wall_generation_cooldown = world.time + (CACHE_PRODUCTION_TIME * get_efficiency_mod(TRUE))
visible_message("<span class='warning'>[src] starts to whirr in the presence of [C]...</span>")
break
if(linkedwall && wall_generation_cooldown <= world.time)
wall_generation_cooldown = world.time + (CACHE_PRODUCTION_TIME * get_efficiency_mod(TRUE))
generate_cache_component(null, src)
playsound(linkedwall, 'sound/magic/clockwork/fellowship_armory.ogg', rand(15, 20), 1, -3, 1, 1)
visible_message("<span class='warning'>Something cl[pick("ank", "ink", "unk", "ang")]s around inside of [src]...</span>")
/obj/structure/destructible/clockwork/cache/attackby(obj/item/I, mob/living/user, params)
if(!is_servant_of_ratvar(user))
return ..()
if(istype(I, /obj/item/clockwork/component))
var/obj/item/clockwork/component/C = I
if(!anchored)
user << "<span class='warning'>[src] needs to be secured to place [C] into it!</span>"
else
clockwork_component_cache[C.component_id]++
update_slab_info()
user << "<span class='notice'>You add [C] to [src].</span>"
user.drop_item()
qdel(C)
return 1
else if(istype(I, /obj/item/clockwork/slab))
var/obj/item/clockwork/slab/S = I
if(!anchored)
user << "<span class='warning'>[src] needs to be secured to offload your slab's components into it!</span>"
else
for(var/i in S.stored_components)
clockwork_component_cache[i] += S.stored_components[i]
S.stored_components[i] = 0
update_slab_info()
user.visible_message("<span class='notice'>[user] empties [S] into [src].</span>", "<span class='notice'>You offload your slab's components into [src].</span>")
return 1
else
return ..()
/obj/structure/destructible/clockwork/cache/attack_hand(mob/user)
if(!is_servant_of_ratvar(user))
return 0
if(!anchored)
user << "<span class='warning'>[src] needs to be secured to remove Replicant Alloy from it!</span>"
return 0
if(!clockwork_component_cache[REPLICANT_ALLOY])
user << "<span class='warning'>There is no Replicant Alloy in the global component cache!</span>"
return 0
clockwork_component_cache[REPLICANT_ALLOY]--
update_slab_info()
var/obj/item/clockwork/component/replicant_alloy/A = new(get_turf(src))
user.visible_message("<span class='notice'>[user] withdraws [A] from [src].</span>", "<span class='notice'>You withdraw [A] from [src].</span>")
user.put_in_hands(A)
return 1
/obj/structure/destructible/clockwork/cache/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
if(linkedwall)
user << "<span class='brass'>It is linked and will generate a component every <b>[round((CACHE_PRODUCTION_TIME * 0.1) * get_efficiency_mod(TRUE), 0.1)]</b> seconds!</span>"
user << "<b>Stored components:</b>"
for(var/i in clockwork_component_cache)
user << "<span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[clockwork_component_cache[i]]</b></span>"
@@ -0,0 +1,165 @@
//Tinkerer's Daemon: A machine that rapidly produces components at a power cost.
/obj/structure/destructible/clockwork/powered/tinkerers_daemon
name = "tinkerer's daemon"
desc = "A strange machine with three small brass obelisks attached to it."
clockwork_desc = "An efficient machine that can rapidly produce components at a small power cost. It will only function if outnumbered by servants at a rate to 5:1."
icon_state = "tinkerers_daemon"
active_icon = "tinkerers_daemon"
inactive_icon = "tinkerers_daemon"
unanchored_icon = "tinkerers_daemon_unwrenched"
max_integrity = 100
obj_integrity = 100
construction_value = 20
break_message = "<span class='warning'>The daemon shatters into millions of pieces!</span>"
debris = list(/obj/item/clockwork/alloy_shards/large = 2, \
/obj/item/clockwork/alloy_shards/medium = 4, \
/obj/item/clockwork/alloy_shards/small = 6)
var/image/daemon_glow
var/image/component_glow
var/component_id_to_produce
var/production_time = 0 //last time we produced a component
var/production_cooldown = 120
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/New()
..()
clockwork_daemons++
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/Destroy()
clockwork_daemons--
return ..()
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/examine(mob/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
if(active)
if(component_id_to_produce)
user << "<span class='[get_component_span(component_id_to_produce)]_small'>It is currently producing [get_component_name(component_id_to_produce)][component_id_to_produce != REPLICANT_ALLOY ? "s":""].</span>"
else
user << "<span class='brass'>It is currently producing random components.</span>"
user << "<span class='nezbere_small'>It will produce a component every <b>[round((production_cooldown*0.1) * get_efficiency_mod(TRUE), 0.1)]</b> seconds and requires at least the following power for each component type:</span>"
for(var/i in clockwork_component_cache)
user << "<span class='[get_component_span(i)]_small'><i>[get_component_name(i)]:</i> <b>[get_component_cost(i)]W</b> <i>([clockwork_component_cache[i]] exist[clockwork_component_cache[i] == 1 ? "s" : ""])</i></span>"
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/forced_disable(bad_effects)
if(active)
if(bad_effects)
try_use_power(MIN_CLOCKCULT_POWER*2)
visible_message("<span class='warning'>[src] shuts down with a horrible grinding noise!</span>")
playsound(src, 'sound/magic/clockwork/anima_fragment_attack.ogg', 50, 1)
else
visible_message("<span class='warning'>[src] shuts down!</span>")
toggle()
return TRUE
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/attack_hand(mob/living/user)
if(!is_servant_of_ratvar(user))
user << "<span class='warning'>You place your hand on the daemon, but nothing happens.</span>"
return
if(active)
toggle(0, user)
else
if(!anchored)
user << "<span class='warning'>[src] needs to be secured to the floor before it can be activated!</span>"
return FALSE
var/servants = 0
for(var/mob/living/L in living_mob_list)
if(is_servant_of_ratvar(L))
servants++
if(servants * 0.2 < clockwork_daemons)
user << "<span class='nezbere'>\"There are too few servants for this daemon to work.\"</span>"
return
if(!clockwork_caches)
user << "<span class='nezbere'>\"You require a cache for this daemon to operate. Get to it.\"</span>"
return
var/min_power_usable = 0
for(var/i in clockwork_component_cache)
if(!min_power_usable)
min_power_usable = get_component_cost(i)
else
min_power_usable = min(min_power_usable, get_component_cost(i))
if(total_accessable_power() < min_power_usable)
user << "<span class='nezbere'>\"You need more power to activate this daemon, friend.\"</span>"
return
var/choice = alert(user,"Activate Daemon...",,"Specific Component","Random Component","Cancel")
switch(choice)
if("Specific Component")
var/list/components = list()
for(var/i in clockwork_component_cache)
components["[get_component_name(i)] ([get_component_cost(i)]W)"] = i
var/input_component = input(user, "Choose a component type.", name) as null|anything in components
component_id_to_produce = components[input_component]
servants = 0
for(var/mob/living/L in living_mob_list)
if(is_servant_of_ratvar(L))
servants++
if(!is_servant_of_ratvar(user) || !user.canUseTopic(src, !issilicon(user)) || active || !clockwork_caches || servants * 0.2 < clockwork_daemons)
return
if(!component_id_to_produce)
user << "<span class='warning'>You decide not to select a component and activate the daemon.</span>"
return
if(total_accessable_power() < get_component_cost(component_id_to_produce))
user << "<span class='warning'>There is too little power to produce this type of component!</span>"
return
toggle(0, user)
if("Random Component")
component_id_to_produce = null
toggle(0, user)
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/toggle(fast_process, mob/living/user)
. = ..()
if(active)
var/component_color = get_component_color(component_id_to_produce)
if(!daemon_glow)
daemon_glow = new('icons/obj/clockwork_objects.dmi', "tinkerglow")
daemon_glow.color = component_color
add_overlay(daemon_glow)
if(!component_glow)
component_glow = new('icons/obj/clockwork_objects.dmi', "t_[component_id_to_produce ? component_id_to_produce :"random_component"]")
else
component_glow.icon_state = "t_[component_id_to_produce ? component_id_to_produce :"random_component"]"
component_glow.color = component_color
add_overlay(component_glow)
production_time = world.time + production_cooldown //don't immediately produce when turned on after being off
SetLuminosity(2, 1)
else
cut_overlays()
SetLuminosity(0)
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/proc/get_component_cost(id)
return max(MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER * (1 + round(clockwork_component_cache[id] * 0.2)))
/obj/structure/destructible/clockwork/powered/tinkerers_daemon/process()
var/servants = 0
for(var/mob/living/L in living_mob_list)
if(is_servant_of_ratvar(L))
servants++
. = ..()
var/min_power_usable = 0
if(!component_id_to_produce)
for(var/i in clockwork_component_cache)
if(!min_power_usable)
min_power_usable = get_component_cost(i)
else
min_power_usable = min(min_power_usable, get_component_cost(i))
else
min_power_usable = get_component_cost(component_id_to_produce)
if(!clockwork_caches || servants * 0.2 < clockwork_daemons || . < min_power_usable) //if we don't have enough to produce the lowest or what we chose to produce, cancel out
forced_disable(FALSE)
return
if(production_time <= world.time)
var/component_to_generate = component_id_to_produce
if(!component_to_generate)
component_to_generate = get_weighted_component_id() //more likely to generate components that we have less of
if(!try_use_power(get_component_cost(component_to_generate)))
component_to_generate = null
if(!component_id_to_produce)
for(var/i in clockwork_component_cache)
if(try_use_power(get_component_cost(i))) //if we fail but are producing random, try and get a different component to produce
component_to_generate = i
break
if(component_to_generate)
generate_cache_component(component_to_generate, src)
production_time = world.time + (production_cooldown * get_efficiency_mod(TRUE)) //go on cooldown
visible_message("<span class='warning'>[src] hums as it produces a [get_component_name(component_to_generate)].</span>")
else
forced_disable(FALSE) //we shouldn't actually ever get here, as we should cancel out way before this
@@ -0,0 +1,76 @@
//A massive gear, effectively a girder for clocks.
/obj/structure/destructible/clockwork/wall_gear
name = "massive gear"
icon_state = "wall_gear"
unanchored_icon = "wall_gear"
climbable = TRUE
max_integrity = 150
obj_integrity = 150
layer = BELOW_OBJ_LAYER
construction_value = 3
desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, or just climb over it."
break_message = "<span class='warning'>The gear breaks apart into shards of alloy!</span>"
debris = list(/obj/item/clockwork/alloy_shards/large = 1, \
/obj/item/clockwork/alloy_shards/medium = 4, \
/obj/item/clockwork/alloy_shards/small = 2) //slightly more debris than the default, totals 26 alloy
/obj/structure/destructible/clockwork/wall_gear/displaced
anchored = FALSE
/obj/structure/destructible/clockwork/wall_gear/New()
..()
PoolOrNew(/obj/effect/overlay/temp/ratvar/gear, get_turf(src))
/obj/structure/destructible/clockwork/wall_gear/emp_act(severity)
return
/obj/structure/destructible/clockwork/wall_gear/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/wrench))
default_unfasten_wrench(user, I, 10)
return 1
else if(istype(I, /obj/item/weapon/screwdriver))
if(anchored)
user << "<span class='warning'>[src] needs to be unsecured to disassemble it!</span>"
else
playsound(src, I.usesound, 100, 1)
user.visible_message("<span class='warning'>[user] starts to disassemble [src].</span>", "<span class='notice'>You start to disassemble [src]...</span>")
if(do_after(user, 40*I.toolspeed, target = src) && !anchored)
user << "<span class='notice'>You disassemble [src].</span>"
deconstruct(TRUE)
return 1
else if(istype(I, /obj/item/stack/tile/brass))
var/obj/item/stack/tile/brass/W = I
if(W.get_amount() < 1)
user << "<span class='warning'>You need one brass sheet to do this!</span>"
return
var/turf/T = get_turf(src)
if(iswallturf(T))
user << "<span class='warning'>There is already a wall present!</span>"
return
if(!isfloorturf(T))
user << "<span class='warning'>A floor must be present to build a [anchored ? "false ":""]wall!</span>"
return
if(locate(/obj/structure/falsewall) in T.contents)
user << "<span class='warning'>There is already a false wall present!</span>"
return
user << "<span class='notice'>You start adding [W] to [src]...</span>"
if(do_after(user, 20, target = src))
var/brass_floor = FALSE
if(istype(T, /turf/open/floor/clockwork)) //if the floor is already brass, costs less to make(conservation of masssssss)
brass_floor = TRUE
if(W.use(2 - brass_floor))
if(anchored)
T.ChangeTurf(/turf/closed/wall/clockwork)
else
T.ChangeTurf(/turf/open/floor/clockwork)
new /obj/structure/falsewall/brass(T)
qdel(src)
else
user << "<span class='warning'>You need more brass to make a [anchored ? "false ":""]wall!</span>"
return 1
return ..()
/obj/structure/destructible/clockwork/wall_gear/deconstruct(disassembled = TRUE)
if(!(flags & NODECONSTRUCT) && disassembled)
new /obj/item/stack/tile/brass(loc, 3)
return ..()
@@ -1,178 +0,0 @@
//sends messages via hierophant
/proc/send_hierophant_message(mob/user, message, name_span = "heavy_brass", message_span = "brass", user_title = "Servant")
if(!user || !message || !ticker || !ticker.mode)
return 0
var/parsed_message = "<span class='[name_span]'>[user_title ? "[user_title] ":""][findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: </span><span class='[message_span]'>\"[message]\"</span>"
for(var/M in mob_list)
if(isobserver(M))
var/link = FOLLOW_LINK(M, user)
M << "[link] [parsed_message]"
else if(is_servant_of_ratvar(M))
M << parsed_message
return 1
//Function Call action: Calls forth a Ratvarian spear.
/datum/action/innate/function_call
name = "Function Call"
button_icon_state = "ratvarian_spear"
background_icon_state = "bg_clock"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS
/datum/action/innate/function_call/IsAvailable()
if(!is_servant_of_ratvar(owner))
return 0
return ..()
/datum/action/innate/function_call/Activate()
if(owner.l_hand && owner.r_hand)
usr << "<span class='warning'>You need an empty to hand to call forth your spear!</span>"
return 0
owner.visible_message("<span class='warning'>A strange spear materializes in [usr]'s hands!</span>", "<span class='brass'>You call forth your spear!</span>")
var/obj/item/clockwork/ratvarian_spear/R = new(get_turf(usr))
owner.put_in_hands(R)
for(var/datum/action/innate/function_call/F in owner.actions) //Removes any bound Ratvarian spears
qdel(F)
return 1
//allows a mob to select a target to gate to
/atom/movable/proc/procure_gateway(mob/living/invoker, time_duration, gateway_uses, two_way)
var/list/possible_targets = list()
var/list/teleportnames = list()
var/list/duplicatenamecount = list()
for(var/obj/structure/clockwork/powered/clockwork_obelisk/O in all_clockwork_objects)
if(!O.Adjacent(invoker) && O != src && (O.z <= ZLEVEL_SPACEMAX)) //don't list obelisks that we're next to
var/area/A = get_area(O)
var/locname = initial(A.name)
var/resultkey = "[locname] [O.name]"
if(resultkey in teleportnames) //why the fuck did you put two obelisks in the same area
duplicatenamecount[resultkey]++
resultkey = "[resultkey] ([duplicatenamecount[resultkey]])"
else
teleportnames.Add(resultkey)
duplicatenamecount[resultkey] = 1
possible_targets[resultkey] = O
for(var/mob/living/L in living_mob_list)
if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && L != invoker && (L.z <= ZLEVEL_SPACEMAX)) //People right next to the invoker can't be portaled to, for obvious reasons
var/resultkey = "[L.name] ([L.real_name])"
if(resultkey in teleportnames)
duplicatenamecount[resultkey]++
resultkey = "[resultkey] ([duplicatenamecount[resultkey]])"
else
teleportnames.Add(resultkey)
duplicatenamecount[resultkey] = 1
possible_targets[resultkey] = L
if(!possible_targets.len)
invoker << "<span class='warning'>There are no other eligible targets for a Spatial Gateway!</span>"
return 0
var/input_target_key = input(invoker, "Choose a target to form a rift to.", "Spatial Gateway") as null|anything in possible_targets
var/atom/movable/target = possible_targets[input_target_key]
if(!target || !invoker.canUseTopic(src, BE_CLOSE))
return 0
var/istargetobelisk = istype(target, /obj/structure/clockwork/powered/clockwork_obelisk)
if(istargetobelisk)
gateway_uses *= 2
time_duration *= 2
invoker.visible_message("<span class='warning'>The air in front of [invoker] ripples before suddenly tearing open!</span>", \
"<span class='brass'>With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [time_duration / 10] seconds and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].</span>")
var/obj/effect/clockwork/spatial_gateway/S1 = new(istype(src, /obj/structure/clockwork/powered/clockwork_obelisk) ? get_turf(src) : get_step(get_turf(invoker), invoker.dir))
var/obj/effect/clockwork/spatial_gateway/S2 = new(istargetobelisk ? get_turf(target) : get_step(get_turf(target), target.dir))
//Set up the portals now that they've spawned
S1.setup_gateway(S2, time_duration, gateway_uses, two_way)
S2.visible_message("<span class='warning'>The air in front of [target] ripples before suddenly tearing open!</span>")
return 1
/proc/scripture_unlock_check(scripture_tier) //check if the selected scripture tier is unlocked
var/servants = 0
var/unconverted_ai_exists = FALSE
for(var/mob/living/M in living_mob_list)
if(is_servant_of_ratvar(M) && (ishuman(M) || issilicon(M)))
servants++
for(var/mob/living/silicon/ai/ai in living_mob_list)
if(!is_servant_of_ratvar(ai) && ai.client)
unconverted_ai_exists = TRUE
switch(scripture_tier)
if(SCRIPTURE_DRIVER)
return 1
if(SCRIPTURE_SCRIPT)
if(servants >= 5 && clockwork_caches)
return 1 //5 or more non-brain servants and any number of clockwork caches
if(SCRIPTURE_APPLICATION)
if(servants >= 8 && clockwork_caches >= 3 && clockwork_construction_value >= 75)
return 1 //8 or more non-brain servants, 3+ clockwork caches, and at least 75 CV
if(SCRIPTURE_REVENANT)
if(servants >= 10 && clockwork_caches >= 4 && clockwork_construction_value >= 150)
return 1 //10 or more non-brain servants, 4+ clockwork caches, and at least 150 CV
if(SCRIPTURE_JUDGEMENT)
if(servants >= 12 && clockwork_caches >= 5 && clockwork_construction_value >= 250 && !unconverted_ai_exists)
return 1 //12 or more non-brain servants, 5+ clockwork caches, at least 250 CV, and there are no living, non-servant ais
return 0
/proc/generate_cache_component(specific_component_id) //generates a component in the global component cache, either random based on lowest or a specific component
if(specific_component_id)
clockwork_component_cache[specific_component_id]++
else
var/component_to_generate = get_weighted_component_id()
clockwork_component_cache[component_to_generate]++
/proc/get_weighted_component_id(obj/item/clockwork/slab/storage_slab) //returns a chosen component id based on the lowest amount of that component
if(storage_slab)
return pickweight(list("belligerent_eye" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache["belligerent_eye"] + storage_slab.stored_components["belligerent_eye"]), 1), \
"vanguard_cogwheel" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache["vanguard_cogwheel"] + storage_slab.stored_components["vanguard_cogwheel"]), 1), \
"guvax_capacitor" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache["guvax_capacitor"] + storage_slab.stored_components["guvax_capacitor"]), 1), \
"replicant_alloy" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache["replicant_alloy"] + storage_slab.stored_components["replicant_alloy"]), 1), \
"hierophant_ansible" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*(clockwork_component_cache["hierophant_ansible"] + storage_slab.stored_components["hierophant_ansible"]), 1)))
return pickweight(list("belligerent_eye" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache["belligerent_eye"], 1), \
"vanguard_cogwheel" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache["vanguard_cogwheel"], 1), \
"guvax_capacitor" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache["guvax_capacitor"], 1), \
"replicant_alloy" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache["replicant_alloy"], 1), \
"hierophant_ansible" = max(MAX_COMPONENTS_BEFORE_RAND - LOWER_PROB_PER_COMPONENT*clockwork_component_cache["hierophant_ansible"], 1)))
/proc/clockwork_say(atom/movable/AM, message, whisper=FALSE)
// When servants invoke ratvar's power, they speak in ways that non
// servants do not comprehend.
// Our ratvarian chants are stored in their ratvar forms
var/list/spans = list(SPAN_ROBOT)
var/old_languages_spoken = AM.languages_spoken
AM.languages_spoken = HUMAN //anyone who can understand HUMAN will hear weird shitty ratvar speak, otherwise it'll get starred out
if(isliving(AM))
var/mob/living/L = AM
if(!whisper)
L.say(message, "clock", spans)
else
L.whisper(message)
else
AM.say(message)
AM.languages_spoken = old_languages_spoken
/*
The Ratvarian Language
In the lore of the Servants of Ratvar, the Ratvarian tongue is a timeless language and full of power. It sounds like gibberish, much like Nar-Sie's language, but is in fact derived from
aforementioned language, and may induce miracles when spoken in the correct way with an amplifying tool (similar to runes used by the Nar-Sian cult).
While the canon states that the language of Ratvar and his servants is incomprehensible to the unenlightened as it is a derivative of the most ancient known language, in reality it is
actually very simple. To translate a plain English sentence to Ratvar's tongue, simply move all of the letters thirteen places ahead, starting from "a" if the end of the alphabet is reached.
This cipher is known as "rot13" for "rotate 13 places" and there are many sites online that allow instant translation between English and rot13 - one of the benefits is that moving the translated
sentence thirteen places ahead changes it right back to plain English.
There are, however, a few parts of the Ratvarian tongue that aren't typical and are implemented for fluff reasons. Some words may have apostrophes, hyphens, and spaces, making the plain
English translation apparent but disjoined (for instance, "Oru`byq zl-cbjre!" translates directly to "Beh'old my-power!") although this can be ignored without impacting overall quality. When
translating from Ratvar's tongue to plain English, simply remove the disjointments and use the finished sentence. This would make "Oru`byq zl-cbjre!" into "Behold my power!" after removing the
abnormal spacing, hyphens, and grave accents.
List of nuances:
- Any time the word "of" occurs, it is linked to the previous word by a hyphen. If it is the first word, nothing is done. (i.e. "V nz-bs Ratvar." directly translates to "I am-of Ratvar.")
- Although "Ratvar" translates to "Engine" in English, the word "Ratvar" is used regardless of language as it is a proper noun.
- The same rule applies to Ratvar's four generals: Nezbere (Armorer), Sevtug (Fright), Nzcrentr (Amperage), and Inath-Neq (Vangu-Ard), although these words can be used in proper context if one is
not referring to the four generals and simply using the words themselves.
*/
@@ -1,319 +0,0 @@
/obj/item/clockwork/clockwork_proselytizer //Clockwork proselytizer (yes, that's a real word): Converts applicable objects to Ratvarian variants.
name = "clockwork proselytizer"
desc = "An odd, L-shaped device that hums with energy."
clockwork_desc = "A device that allows the replacing of mundane objects with Ratvarian variants. It requires liquified Replicant Alloy to function."
icon_state = "clockwork_proselytizer"
w_class = 3
force = 5
flags = NOBLUDGEON
var/stored_alloy = 0 //Requires this to function; each chunk of replicant alloy provides REPLICANT_ALLOY_UNIT
var/max_alloy = REPLICANT_ALLOY_UNIT * 10
var/uses_alloy = TRUE
var/metal_to_alloy = FALSE
var/repairing = null //what we're currently repairing, if anything
/obj/item/clockwork/clockwork_proselytizer/preloaded
stored_alloy = REPLICANT_WALL_MINUS_FLOOR+REPLICANT_WALL_TOTAL
/obj/item/clockwork/clockwork_proselytizer/scarab
name = "scarab proselytizer"
clockwork_desc = "A cogscarab's internal proselytizer. It can only be successfully used by a cogscarab and requires liquified Replicant Alloy to function."
metal_to_alloy = TRUE
item_state = "nothing"
w_class = 1
var/debug = FALSE
/obj/item/clockwork/clockwork_proselytizer/scarab/proselytize(atom/target, mob/living/user)
if(!debug && !isdrone(user))
return 0
return ..()
/obj/item/clockwork/clockwork_proselytizer/scarab/debug
clockwork_desc = "A cogscarab's internal proselytizer. It can convert nearly any object into a Ratvarian variant."
uses_alloy = FALSE
debug = TRUE
/obj/item/clockwork/clockwork_proselytizer/examine(mob/living/user)
..()
if(is_servant_of_ratvar(user) || isobserver(user))
user << "<span class='brass'>Can be used to convert walls, floors, windows, airlocks, windoors, and grilles to clockwork variants.</span>"
user << "<span class='brass'>Can also form some objects into Replicant Alloy, as well as reform Clockwork Walls into Clockwork Floors, and vice versa.</span>"
if(metal_to_alloy)
user << "<span class='alloy'>It can convert rods, metal, and plasteel to liquified replicant alloy at a low rate.</span>"
if(uses_alloy)
user << "<span class='alloy'>It has [stored_alloy]/[max_alloy] units of liquified alloy stored.</span>"
user << "<span class='alloy'>Use it on a Tinkerer's Cache, strike it with Replicant Alloy, or attack Replicant Alloy with it to add additional liquified alloy.</span>"
user << "<span class='alloy'>Use it in-hand to remove stored liquified alloy.</span>"
/obj/item/clockwork/clockwork_proselytizer/attack_self(mob/living/user)
if(is_servant_of_ratvar(user) && uses_alloy)
if(!can_use_alloy(REPLICANT_ALLOY_UNIT))
user << "<span class='warning'>[src] [stored_alloy ? "Lacks enough":"Contains no"] alloy to reform[stored_alloy ? "":" any"] into solidified alloy!</span>"
return
modify_stored_alloy(-REPLICANT_ALLOY_UNIT)
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
new/obj/item/clockwork/component/replicant_alloy(user.loc)
user << "<span class='brass'>You force [stored_alloy ? "some":"all"] of the alloy in [src]'s compartments to reform and solidify. \
It now contains [stored_alloy]/[max_alloy] units of liquified alloy.</span>"
/obj/item/clockwork/clockwork_proselytizer/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/clockwork/component/replicant_alloy) && is_servant_of_ratvar(user) && uses_alloy)
if(!can_use_alloy(-REPLICANT_ALLOY_UNIT))
user << "<span class='warning'>[src]'s replicant alloy compartments are full!</span>"
return 0
modify_stored_alloy(REPLICANT_ALLOY_UNIT)
playsound(user, 'sound/machines/click.ogg', 50, 1)
user << "<span class='brass'>You force [I] to liquify and pour it into [src]'s compartments. It now contains [stored_alloy]/[max_alloy] units of liquified alloy.</span>"
user.drop_item()
qdel(I)
return 1
else
return ..()
/obj/item/clockwork/clockwork_proselytizer/afterattack(atom/target, mob/living/user, proximity_flag, params)
if(!target || !user || !proximity_flag)
return 0
if(!is_servant_of_ratvar(user))
return ..()
proselytize(target, user)
/obj/item/clockwork/clockwork_proselytizer/proc/modify_stored_alloy(amount)
if(can_use_alloy(0)) //Ratvar makes it free
amount = 0
stored_alloy = Clamp(stored_alloy + amount, 0, max_alloy)
return 1
/obj/item/clockwork/clockwork_proselytizer/proc/can_use_alloy(amount)
if(ratvar_awakens || !uses_alloy)
return TRUE
if(!amount) //functions thus as a check for if ratvar is up/it doesn't use alloy if no amount is provided
return FALSE
if(stored_alloy - amount < 0)
return FALSE
if(stored_alloy - amount > max_alloy)
return FALSE
return TRUE
/obj/item/clockwork/clockwork_proselytizer/proc/proselytize(atom/target, mob/living/user)
if(!target || !user)
return 0
var/target_type = target.type
var/list/proselytize_values = target.proselytize_vals(user, src) //relevant values for proselytizing stuff, given as an associated list
if(proselytize_values == TRUE) //if we get true, fail, but don't send a message for whatever reason
return 0
if(!islist(proselytize_values))
user << "<span class='warning'>[target] cannot be proselytized!</span>"
return 0
if(repairing)
user << "<span class='warning'>You are currently repairing [repairing] with [src]!</span>"
return 0
if(!uses_alloy)
proselytize_values["alloy_cost"] = 0
if(!can_use_alloy(proselytize_values["alloy_cost"]))
if(stored_alloy - proselytize_values["alloy_cost"] < 0)
user << "<span class='warning'>You need [proselytize_values["alloy_cost"]] liquified alloy to proselytize [target]!</span>"
else if(stored_alloy - proselytize_values["alloy_cost"] > max_alloy)
user << "<span class='warning'>You have too much liquified alloy stored to proselytize [target]!</span>"
return 0
if(can_use_alloy(0)) //Ratvar makes it faster
proselytize_values["operation_time"] *= 0.5
user.visible_message("<span class='warning'>[user]'s [name] begins tearing apart [target]!</span>", "<span class='brass'>You begin proselytizing [target]...</span>")
playsound(target, 'sound/machines/click.ogg', 50, 1)
if(proselytize_values["operation_time"] && !do_after(user, proselytize_values["operation_time"], target = target))
return 0
if(!can_use_alloy(proselytize_values["alloy_cost"])) //Check again to prevent bypassing via spamclick
return 0
if(!target || target.type != target_type)
return 0
if(repairing)
return 0
user.visible_message("<span class='warning'>[user]'s [name] disgorges a chunk of metal and shapes it over what's left of [target]!</span>", \
"<span class='brass'>You proselytize [target].</span>")
playsound(target, 'sound/items/Deconstruct.ogg', 50, 1)
var/new_thing_type = proselytize_values["new_obj_type"]
if(isturf(target))
var/turf/T = target
T.ChangeTurf(new_thing_type)
else
if(proselytize_values["dir_in_new"])
new new_thing_type(get_turf(target), proselytize_values["spawn_dir"])
else
var/atom/A = new new_thing_type(get_turf(target))
A.setDir(proselytize_values["spawn_dir"])
qdel(target)
modify_stored_alloy(-proselytize_values["alloy_cost"])
return 1
//if a valid target, returns an associated list in this format;
//list("operation_time" = 15, "new_obj_type" = /obj/structure/window/reinforced/clockwork, "alloy_cost" = 5, "spawn_dir" = dir, "dir_in_new" = TRUE)
//otherwise, return literally any non-list thing but preferably FALSE
//returning TRUE won't produce the "cannot be proselytized" message and will still prevent proselytizing
/atom/proc/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/turf/closed/wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_TOTAL, "spawn_dir" = SOUTH)
/turf/closed/wall/r_wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/turf/closed/wall/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 50, "new_obj_type" = /turf/open/floor/clockwork, "alloy_cost" = -REPLICANT_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
/turf/open/floor/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 30, "new_obj_type" = /turf/open/floor/clockwork, "alloy_cost" = REPLICANT_FLOOR, "spawn_dir" = SOUTH)
/turf/open/floor/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
for(var/obj/O in src)
if(O.density && !O.CanPass(user, src, 5))
user << "<span class='warning'>Something is in the way, preventing you from proselytizing [src] into a clockwork wall.</span>"
return FALSE
return list("operation_time" = 100, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
/obj/item/stack/rods/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(!proselytizer.metal_to_alloy)
return 0
var/prosel_costtime = -amount
return list("operation_time" = -prosel_costtime, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = prosel_costtime, "spawn_dir" = SOUTH)
/obj/item/stack/sheet/metal/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(!proselytizer.metal_to_alloy)
return 0
var/prosel_costtime = -amount*2
return list("operation_time" = -prosel_costtime, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = prosel_costtime, "spawn_dir" = SOUTH)
/obj/item/stack/sheet/plasteel/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(!proselytizer.metal_to_alloy)
return 0
var/prosel_costtime = -amount*3
return list("operation_time" = -prosel_costtime, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = prosel_costtime, "spawn_dir" = SOUTH)
/obj/machinery/door/airlock/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
var/doortype = /obj/machinery/door/airlock/clockwork
if(glass)
doortype = /obj/machinery/door/airlock/clockwork/brass
return list("operation_time" = 40, "new_obj_type" = doortype, "alloy_cost" = REPLICANT_WALL_TOTAL, "spawn_dir" = dir)
/obj/machinery/door/airlock/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/obj/structure/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
var/windowtype = /obj/structure/window/reinforced/clockwork
var/new_dir = TRUE
var/prosel_time = 15
var/prosel_cost = REPLICANT_FLOOR
if(fulltile)
windowtype = /obj/structure/window/reinforced/clockwork/fulltile
new_dir = FALSE
prosel_time = 30
prosel_cost = REPLICANT_STANDARD
return list("operation_time" = prosel_time, "new_obj_type" = windowtype, "alloy_cost" = prosel_cost, "spawn_dir" = dir, "dir_in_new" = new_dir)
/obj/structure/window/reinforced/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/obj/machinery/door/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 30, "new_obj_type" = /obj/machinery/door/window/clockwork, "alloy_cost" = REPLICANT_STANDARD, "spawn_dir" = dir, "dir_in_new" = TRUE)
/obj/machinery/door/window/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/obj/structure/grille/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
var/grilletype = /obj/structure/grille/ratvar
var/prosel_time = 15
if(destroyed)
grilletype = /obj/structure/grille/ratvar/broken
prosel_time = 5
return list("operation_time" = prosel_time, "new_obj_type" = grilletype, "alloy_cost" = 0, "spawn_dir" = dir)
/obj/structure/grille/ratvar/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/obj/structure/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
. = TRUE
if(proselytizer.repairing) //no spamclicking for fast repairs, bucko
user << "<span class='warning'>You are already repairing [proselytizer.repairing] with [proselytizer]!</span>"
return
if(!can_be_repaired)
user << "<span class='warning'>[src] cannot be repaired with a proselytizer!</span>"
return
if(health == max_health)
user << "<span class='warning'>[src] is at maximum integrity!</span>"
return
var/amount_to_heal = max_health - health
var/healing_for_cycle = min(amount_to_heal, repair_amount)
if(!proselytizer.can_use_alloy(0))
healing_for_cycle = min(healing_for_cycle, proselytizer.stored_alloy)
var/proselytizer_cost = healing_for_cycle*2
if(!proselytizer.can_use_alloy(proselytizer_cost))
user << "<span class='warning'>You need more liquified alloy to repair [src]!</span>"
return
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts covering [src] in black liquid metal...</span>", \
"<span class='alloy'>You start repairing [src]...</span>")
//hugeass while because we need to re-check after the do_after
proselytizer.repairing = src
while(proselytizer && user && src && health != max_health)
amount_to_heal = max_health - health
if(!amount_to_heal)
break
healing_for_cycle = min(amount_to_heal, repair_amount)
if(!proselytizer.can_use_alloy(0))
healing_for_cycle = min(healing_for_cycle, proselytizer.stored_alloy)
proselytizer_cost = healing_for_cycle*2
if(!proselytizer.can_use_alloy(proselytizer_cost) || !do_after(user, proselytizer_cost, target = src) || !proselytizer || !proselytizer.can_use_alloy(proselytizer_cost))
break
amount_to_heal = max_health - health
if(!amount_to_heal)
break
healing_for_cycle = min(amount_to_heal, repair_amount)
if(!proselytizer.can_use_alloy(0))
healing_for_cycle = min(healing_for_cycle, proselytizer.stored_alloy)
proselytizer_cost = healing_for_cycle*2
if(!proselytizer.can_use_alloy(proselytizer_cost))
break
health += healing_for_cycle
proselytizer.modify_stored_alloy(-proselytizer_cost)
playsound(src, 'sound/machines/click.ogg', 50, 1)
if(proselytizer)
proselytizer.repairing = null
if(user)
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops covering [src] with black liquid metal.</span>", \
"<span class='alloy'>You finish repairing [src]. It is now at <b>[health]/[max_health]</b> integrity.</span>")
return
/obj/structure/clockwork/cache/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
. = ..()
if(proselytizer.can_use_alloy(0) || proselytizer.stored_alloy + REPLICANT_ALLOY_UNIT > proselytizer.max_alloy)
user << "<span class='warning'>[proselytizer]'s containers of liquified alloy are full!</span>"
return
if(!clockwork_component_cache["replicant_alloy"])
user << "<span class='warning'>There is no Replicant Alloy in the global component cache!</span>"
return
user.visible_message("<span class='notice'>[user] places the end of [proselytizer] in the hole in [src]...</span>", \
"<span class='notice'>You start filling [proselytizer] with liquified alloy...</span>")
//hugeass check because we need to re-check after the do_after
while(proselytizer && proselytizer.uses_alloy && proselytizer.stored_alloy + REPLICANT_ALLOY_UNIT <= proselytizer.max_alloy && clockwork_component_cache["replicant_alloy"] \
&& do_after(user, 10, target = src) \
&& proselytizer && proselytizer.uses_alloy && proselytizer.stored_alloy + REPLICANT_ALLOY_UNIT <= proselytizer.max_alloy && clockwork_component_cache["replicant_alloy"])
proselytizer.modify_stored_alloy(REPLICANT_ALLOY_UNIT)
clockwork_component_cache["replicant_alloy"]--
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
if(proselytizer && user)
user.visible_message("<span class='notice'>[user] removes [proselytizer] from the hole in [src], apparently satisfied.</span>", \
"<span class='brass'>You finish filling [proselytizer] with liquified alloy. It now contains [proselytizer.stored_alloy]/[proselytizer.max_alloy] units of liquified alloy.</span>")
return
/obj/structure/clockwork/wall_gear/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 10, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -REPLICANT_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
/obj/item/clockwork/alloy_shards/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 5, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -REPLICANT_STANDARD, "spawn_dir" = SOUTH)
/obj/item/clockwork/component/replicant_alloy/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 0, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -REPLICANT_ALLOY_UNIT, "spawn_dir" = SOUTH)
+37 -61
View File
@@ -1,11 +1,11 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
/datum/game_mode
var/list/datum/mind/cult = list()
var/list/cult_objectives = list()
/proc/iscultist(mob/living/M)
return istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.cult)
return istype(M) && M.has_antag_datum(/datum/antagonist/cultist, TRUE)
/proc/is_sacrifice_target(datum/mind/mind)
if(ticker.mode.name == "cult")
@@ -14,25 +14,20 @@
return 1
return 0
/proc/is_convertable_to_cult(datum/mind/mind)
if(!istype(mind))
/proc/is_convertable_to_cult(mob/living/M)
if(!istype(M))
return 0
if(istype(mind.current, /mob/living/carbon/human) && (mind.assigned_role in list("Captain", "Chaplain")))
return 0
if(isloyal(mind.current))
return 0
if(issilicon(mind.current) || isbot(mind.current) || isdrone(mind.current))
return 0 //can't convert machines, that's ratvar's thing
if(isguardian(mind.current))
var/mob/living/simple_animal/hostile/guardian/G = mind.current
if(!iscultist(G.summoner))
return 0 //can't convert it unless the owner is converted
if(is_sacrifice_target(mind))
return 0
if(mind.enslaved_to)
return 0
if(is_servant_of_ratvar(mind.current))
if(M.mind)
if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain")))
return 0
if(is_sacrifice_target(M.mind))
return 0
if(M.mind.enslaved_to && !iscultist(M.mind.enslaved_to))
return 0
else
return 0
if(M.isloyal() || issilicon(M) || isbot(M) || isdrone(M) || is_servant_of_ratvar(M))
return 0 //can't convert machines, shielded, or ratvar's dogs
return 1
/datum/game_mode/cult
@@ -46,6 +41,11 @@
recommended_enemies = 4
enemy_minimum_age = 14
announce_span = "cult"
announce_text = "Some crew members are trying to start a cult to Nar-Sie!\n\
<span class='cult'>Cultists</span>: Carry out Nar-Sie's will.\n\
<span class='notice'>Crew</span>: Prevent the cult from expanding and drive it out."
var/finished = 0
var/eldergod = 1 //for the summon god objective
@@ -55,12 +55,6 @@
var/datum/mind/sacrifice_target = null//The target to be sacrificed
var/list/cultists_to_cult = list() //the cultists we'll convert
/datum/game_mode/cult/announce()
world << "<B>The current game mode is - Cult!</B>"
world << "<B>Some crewmembers are attempting to start a cult!<BR>\nCultists - sacrifice your target and summon Nar-Sie at all costs. Convert crewmembers to your cause by using the convert rune, or sacrifice them and turn them into constructs. Remember - there is no you, there is only the cult.<BR>\nPersonnel - Do not let the cult succeed in its mission. Forced consumption of holy water will convert a cultist back to a Nanotrasen-sanctioned faith.</B>"
/datum/game_mode/cult/pre_setup()
cult_objectives += "sacrifice"
cult_objectives += "eldergod"
@@ -144,9 +138,7 @@
var/list/slots = list(
"backpack" = slot_in_backpack,
"left pocket" = slot_l_store,
"right pocket" = slot_r_store,
"left hand" = slot_l_hand,
"right hand" = slot_r_hand,
"right pocket" = slot_r_store
)
var/T = new item_path(mob)
@@ -157,7 +149,6 @@
return 0
else
mob << "<span class='danger'>You have a [item_name] in your [where]."
mob.update_icons()
if(where == "backpack")
var/obj/item/weapon/storage/B = mob.back
B.orient2hud(mob)
@@ -167,43 +158,21 @@
/datum/game_mode/proc/add_cultist(datum/mind/cult_mind, stun) //BASE
if (!istype(cult_mind))
return 0
if(!(cult_mind in cult) && is_convertable_to_cult(cult_mind))
if(cult_mind.current.gain_antag_datum(/datum/antagonist/cultist))
if(stun)
cult_mind.current.Paralyse(5)
cult += cult_mind
cult_mind.current.faction |= "cult"
cult_mind.current.verbs += /mob/living/proc/cult_help
var/datum/action/innate/cultcomm/C = new()
C.Grant(cult_mind.current)
update_cult_icons_added(cult_mind)
cult_mind.current.attack_log += "\[[time_stamp()]\] <span class='danger'>Has been converted to the cult!</span>"
if(jobban_isbanned(cult_mind.current, ROLE_CULTIST))
replace_jobbaned_player(cult_mind.current, ROLE_CULTIST, ROLE_CULTIST)
return 1
/datum/game_mode/cult/add_cultist(datum/mind/cult_mind, stun) //INHERIT
if (!..(cult_mind))
return
memorize_cult_objectives(cult_mind)
return 1
/datum/game_mode/proc/remove_cultist(datum/mind/cult_mind, show_message = 1, stun)
if(cult_mind in cult)
cult -= cult_mind
cult_mind.current.faction -= "cult"
cult_mind.current.verbs -= /mob/living/proc/cult_help
for(var/datum/action/innate/cultcomm/C in cult_mind.current.actions)
qdel(C)
if(cult_mind.current)
var/datum/antagonist/cultist/cult_datum = cult_mind.current.has_antag_datum(/datum/antagonist/cultist, TRUE)
if(!cult_datum)
return FALSE
cult_datum.silent_update = show_message
cult_datum.on_remove()
if(stun)
cult_mind.current.Paralyse(5)
cult_mind.current << "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Dark One and all your memories as its servant.</span>"
cult_mind.memory = ""
update_cult_icons_removed(cult_mind)
cult_mind.current.attack_log += "\[[time_stamp()]\] <span class='danger'>Has renounced the cult!</span>"
if(show_message)
for(var/mob/M in viewers(cult_mind.current))
M << "<span class='big'>[cult_mind.current] looks like they just reverted to their old faith!</span>"
return TRUE
/datum/game_mode/proc/update_cult_icons_added(datum/mind/cult_mind)
var/datum/atom_hud/antag/culthud = huds[ANTAG_HUD_CULT]
@@ -214,12 +183,14 @@
var/datum/atom_hud/antag/culthud = huds[ANTAG_HUD_CULT]
culthud.leave_hud(cult_mind.current)
set_antag_hud(cult_mind.current, null)
/datum/game_mode/cult/proc/get_unconvertables()
var/list/ucs = list()
for(var/mob/living/carbon/human/player in player_list)
if(player.mind && !is_convertable_to_cult(player.mind))
if(player.mind && !is_convertable_to_cult(player) && !(player.mind in cultists_to_cult))
ucs += player.mind
return ucs
/datum/game_mode/cult/proc/check_cult_victory()
var/cult_fail = 0
if(cult_objectives.Find("survive"))
@@ -266,9 +237,11 @@
if(!check_survive())
explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped) <span class='greenannounce'>Success!</span>"
feedback_add_details("cult_objective","cult_survive|SUCCESS|[acolytes_needed]")
ticker.news_report = CULT_ESCAPE
else
explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped) <span class='boldannounce'>Fail.</span>"
feedback_add_details("cult_objective","cult_survive|FAIL|[acolytes_needed]")
ticker.news_report = CULT_FAILURE
if("sacrifice")
if(sacrifice_target)
if(sacrifice_target in sacrificed)
@@ -284,9 +257,12 @@
if(!eldergod)
explanation = "Summon Nar-Sie. <span class='greenannounce'>Success!</span>"
feedback_add_details("cult_objective","cult_narsie|SUCCESS")
ticker.news_report = CULT_SUMMON
else
explanation = "Summon Nar-Sie. <span class='boldannounce'>Fail.</span>"
feedback_add_details("cult_objective","cult_narsie|FAIL")
ticker.news_report = CULT_FAILURE
text += "<br><B>Objective #[obj_count]</B>: [explanation]"
world << text
..()
+3 -2
View File
@@ -3,6 +3,7 @@
name = "Communion"
button_icon_state = "cult_comms"
background_icon_state = "bg_demon"
buttontooltipstyle = "cult"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS
/datum/action/innate/cultcomm/IsAvailable()
@@ -29,9 +30,9 @@
if(!user)
return
if(!ishuman(user))
user.say(message)
user.say(html_decode(message))
else
user.whisper(message)
user.whisper(html_decode(message))
var/my_message = "<span class='cultitalic'><b>[(ishuman(user) ? "Acolyte" : "Construct")] [user]:</b> [message]</span>"
for(var/mob/M in mob_list)
if(iscultist(M))

Some files were not shown because too many files have changed in this diff Show More