Merge remote-tracking branch 'remotes/tgstation/master' into The_Alien_Queen_Bends_Down_And_Plants_A_Kiss_On_WJ_With_Her_Long_Wet_Tongue-mouth

# Conflicts:
#	icons/mob/actions.dmi
This commit is contained in:
GunHog
2016-08-17 09:33:10 -05:00
212 changed files with 7582 additions and 1196 deletions
+9
View File
@@ -6,6 +6,7 @@ var/global/list/all_clockwork_objects = list() //All clockwork items, structures
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
var/global/clockwork_gateway_activated = FALSE //if a gateway to the celestial derelict has ever been successfully activated
#define SCRIPTURE_PERIPHERAL "Peripheral" //Scripture tiers; peripherals should never be used
#define SCRIPTURE_DRIVER "Driver"
@@ -47,3 +48,11 @@ var/global/ratvar_awakens = FALSE //If Ratvar has been summoned
#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
//Objective defines
#define CLOCKCULT_GATEWAY "gateway"
#define CLOCKCULT_ESCAPE "escape"
#define CLOCKCULT_SILICONS "silicons"
+30 -1
View File
@@ -152,6 +152,7 @@
#define CLICK_CD_MELEE 8
#define CLICK_CD_RANGE 4
#define CLICK_CD_RAPID 2
#define CLICK_CD_CLICK_ABILITY 6
#define CLICK_CD_BREAKOUT 100
#define CLICK_CD_HANDCUFFED 10
@@ -498,4 +499,32 @@ var/global/list/ghost_others_options = list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define BUBBLEGUM_SCORE "Bubblegum Killed"
#define DRAKE_SCORE "Drakes Killed"
#define BOSS_SCORE "Bosses Killed"
#define TENDRIL_CLEAR_SCORE "Tendrils Killed"
#define TENDRIL_CLEAR_SCORE "Tendrils Killed"
// NTNet module-configuration values. Do not change these. If you need to add another use larger number (5..6..7 etc)
#define NTNET_SOFTWAREDOWNLOAD 1 // Downloads of software from NTNet
#define NTNET_PEERTOPEER 2 // P2P transfers of files between devices
#define NTNET_COMMUNICATION 3 // Communication (messaging)
#define NTNET_SYSTEMCONTROL 4 // Control of various systems, RCon, air alarm control, etc.
// NTNet transfer speeds, used when downloading/uploading a file/program.
#define NTNETSPEED_LOWSIGNAL 0.5 // GQ/s transfer speed when the device is wirelessly connected and on Low signal
#define NTNETSPEED_HIGHSIGNAL 1 // GQ/s transfer speed when the device is wirelessly connected and on High signal
#define NTNETSPEED_ETHERNET 2 // GQ/s transfer speed when the device is using wired connection
// Program bitflags
#define PROGRAM_ALL 7
#define PROGRAM_CONSOLE 1
#define PROGRAM_LAPTOP 2
#define PROGRAM_TABLET 4
#define PROGRAM_STATE_KILLED 0
#define PROGRAM_STATE_BACKGROUND 1
#define PROGRAM_STATE_ACTIVE 2
// Caps for NTNet logging. Less than 10 would make logging useless anyway, more than 500 may make the log browser too laggy. Defaults to 100 unless user changes it.
#define MAX_NTNET_LOGS 300
#define MIN_NTNET_LOGS 10
+4 -4
View File
@@ -1,7 +1,7 @@
#define TICK_LIMIT_RUNNING 85
#define TICK_LIMIT_TO_RUN 80
#define TICK_LIMIT_MC 84
#define TICK_LIMIT_MC_INIT 100
#define TICK_LIMIT_RUNNING 80
#define TICK_LIMIT_TO_RUN 78
#define TICK_LIMIT_MC 70
#define TICK_LIMIT_MC_INIT 98
#define TICK_CHECK ( world.tick_usage > CURRENT_TICKLIMIT ? stoplag() : 0 )
#define CHECK_TICK if (world.tick_usage > CURRENT_TICKLIMIT) stoplag()
+4 -1
View File
@@ -22,7 +22,7 @@
/proc/log_adminsay(text)
if (config.log_adminchat)
log_admin("ASAY: [text]")
/proc/log_dsay(text)
if (config.log_adminchat)
log_admin("DSAY: [text]")
@@ -76,3 +76,6 @@
//reusing the PDA option because I really don't think news comments are worth a config option
diary << "\[[time_stamp()]]COMMENT: [text]"
/proc/log_chat(text)
if (config.log_pda)
diary << "\[[time_stamp()]]CHAT: [text]"
+1
View File
@@ -10,6 +10,7 @@ var/global/list/deliverybeacons = list() //list of all MULEbot delivery beacon
var/global/list/deliverybeacontags = list() //list of all tags associated with delivery beacons.
var/global/list/nuke_list = list()
var/global/list/nuke_tiles = list() //list of all turfs that turn to animated red grids when a nuke is triggered
var/global/list/alarmdisplay = list() //list of all machines or programs that can display station alerts
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
var/global/list/chemical_reagents_list //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
+4 -1
View File
@@ -287,7 +287,10 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
for(var/obj/structure/clockwork/massive/celestial_gateway/G in all_clockwork_objects)
var/area/gate_area = get_area(G)
desc += "Ark Location: <b>[uppertext(gate_area.map_name)]</b><br>"
desc += "Seconds until Ratvar's arrival: <b>[G.get_arrival_text(TRUE)]</b><br>"
if(G.ratvar_portal)
desc += "Seconds until Ratvar's arrival: <b>[G.get_arrival_text(TRUE)]</b><br>"
else
desc += "Seconds until Proselytization: <b>[G.get_arrival_text(TRUE)]</b><br>"
if(unconverted_ai_exists)
desc += "<b>An unconverted AI exists!</b><br>"
if(scripture_states[SCRIPTURE_REVENANT])
+9 -9
View File
@@ -54,7 +54,7 @@
/obj/screen/blob/Blobbernaut
icon_state = "ui_blobbernaut"
name = "Produce Blobbernaut (40)"
desc = "Produces a strong, smart blobbernaut from a factory blob for 40 points.<br>The factory blob used will become fragile and unable to produce spores."
desc = "Produces a strong, smart blobbernaut from a factory blob for 40 resources.<br>The factory blob used will become fragile and unable to produce spores."
/obj/screen/blob/Blobbernaut/Click()
if(isovermind(usr))
@@ -64,7 +64,7 @@
/obj/screen/blob/ResourceBlob
icon_state = "ui_resource"
name = "Produce Resource Blob (40)"
desc = "Produces a resource blob for 40 points.<br>Resource blobs will give you points every few seconds."
desc = "Produces a resource blob for 40 resources.<br>Resource blobs will give you resources every few seconds."
/obj/screen/blob/ResourceBlob/Click()
if(isovermind(usr))
@@ -73,8 +73,8 @@
/obj/screen/blob/NodeBlob
icon_state = "ui_node"
name = "Produce Node Blob (60)"
desc = "Produces a node blob for 60 points.<br>Node blobs will expand and activate nearby resource and factory blobs."
name = "Produce Node Blob (50)"
desc = "Produces a node blob for 50 resources.<br>Node blobs will expand and activate nearby resource and factory blobs."
/obj/screen/blob/NodeBlob/Click()
if(isovermind(usr))
@@ -84,7 +84,7 @@
/obj/screen/blob/FactoryBlob
icon_state = "ui_factory"
name = "Produce Factory Blob (60)"
desc = "Produces a factory blob for 60 points.<br>Factory blobs will produce spores every few seconds."
desc = "Produces a factory blob for 60 resources.<br>Factory blobs will produce spores every few seconds."
/obj/screen/blob/FactoryBlob/Click()
if(isovermind(usr))
@@ -94,7 +94,7 @@
/obj/screen/blob/ReadaptChemical
icon_state = "ui_chemswap"
name = "Readapt Chemical (40)"
desc = "Randomly rerolls your chemical for 40 points."
desc = "Randomly rerolls your chemical for 40 resources."
/obj/screen/blob/ReadaptChemical/MouseEntered(location,control,params)
if(hud && hud.mymob && isovermind(hud.mymob))
@@ -115,7 +115,7 @@
/obj/screen/blob/RelocateCore
icon_state = "ui_swap"
name = "Relocate Core (80)"
desc = "Swaps a node and your core for 80 points."
desc = "Swaps a node and your core for 80 resources."
/obj/screen/blob/RelocateCore/Click()
if(isovermind(usr))
@@ -159,11 +159,11 @@
static_inventory += using
using = new /obj/screen/blob/NodeBlob()
using.screen_loc = ui_lhand
using.screen_loc = ui_rhand
static_inventory += using
using = new /obj/screen/blob/FactoryBlob()
using.screen_loc = ui_rhand
using.screen_loc = ui_lhand
static_inventory += using
using = new /obj/screen/blob/ReadaptChemical()
+108 -110
View File
@@ -208,7 +208,8 @@
ticker.mode.update_wiz_icons_removed(src)
ticker.mode.update_cult_icons_removed(src)
ticker.mode.update_rev_icons_removed(src)
gang_datum.remove_gang_hud(src)
if(gang_datum)
gang_datum.remove_gang_hud(src)
//Link a new mobs mind to the creator of said mob. They will join any team they are currently on, and will only switch teams when their creator does.
@@ -283,7 +284,7 @@
)
var/text = ""
if (istype(current, /mob/living/carbon/human) || istype(current, /mob/living/carbon/monkey))
if(ishuman(current))
/** REVOLUTION ***/
text = "revolution"
if (ticker.mode.config_tag=="revolution")
@@ -362,100 +363,23 @@
sections["gang"] = text
/** CULT ***/
text = "cult"
if (ticker.mode.config_tag=="cult")
/** Abductors **/
text = "Abductor"
if(ticker.mode.config_tag == "abductor")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if (src in ticker.mode.cult)
text += "loyal|<a href='?src=\ref[src];cult=clear'>employee</a>|<b>CULTIST</b>"
text += "<br>Give <a href='?src=\ref[src];cult=tome'>tome</a>|<a href='?src=\ref[src];cult=amulet'>amulet</a>."
/*
if (objectives.len==0)
text += "<br>Objectives are empty! Set to sacrifice and <a href='?src=\ref[src];cult=escape'>escape</a> or <a href='?src=\ref[src];cult=summon'>summon</a>."
*/
else if(isloyal(current))
text += "<b>LOYAL</b>|employee|<a href='?src=\ref[src];cult=cultist'>cultist</a>"
if(src in ticker.mode.abductors)
text += "<b>Abductor</b>|<a href='?src=\ref[src];abductor=clear'>human</a>"
text += "|<a href='?src=\ref[src];common=undress'>undress</a>|<a href='?src=\ref[src];abductor=equip'>equip</a>"
else
text += "loyal|<b>EMPLOYEE</b>|<a href='?src=\ref[src];cult=cultist'>cultist</a>"
text += "<a href='?src=\ref[src];abductor=abductor'>Abductor</a>|<b>human</b>"
if(current && current.client && (ROLE_CULTIST in current.client.prefs.be_special))
if(current && current.client && (ROLE_ABDUCTOR in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["cult"] = text
/** CLOCKWORK CULT **/
text = "clockwork cult"
if(ticker.mode.config_tag == "clockwork cult")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(src in ticker.mode.servants_of_ratvar)
text += "loyal|<a href='?src=\ref[src];clockcult=clear'>employee</a>|<b>SERVANT</b>"
text += "<br><a href='?src=\ref[src];clockcult=slab'>Give slab</a>"
else if(isloyal(current))
text += "<b>LOYAL</b>|employee|<a href='?src=\ref[src];clockcult=servant'>servant</a>"
else
text += "loyal|<b>EMPLOYEE</b>|<a href='?src=\ref[src];clockcult=servant'>servant</a>"
if(current && current.client && (ROLE_SERVANT_OF_RATVAR in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["clockcult"] = text
/** WIZARD ***/
text = "wizard"
if (ticker.mode.config_tag=="wizard")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if ((src in ticker.mode.wizards) || (src in ticker.mode.apprentices))
text += "<b>YES</b>|<a href='?src=\ref[src];wizard=clear'>no</a>"
text += "<br><a href='?src=\ref[src];wizard=lair'>To lair</a>, <a href='?src=\ref[src];common=undress'>undress</a>, <a href='?src=\ref[src];wizard=dressup'>dress up</a>, <a href='?src=\ref[src];wizard=name'>let choose name</a>."
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];wizard=autoobjectives'>Randomize!</a>"
else
text += "<a href='?src=\ref[src];wizard=wizard'>yes</a>|<b>NO</b>"
if(current && current.client && (ROLE_WIZARD in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["wizard"] = text
/** CHANGELING ***/
text = "changeling"
if (ticker.mode.config_tag=="changeling" || ticker.mode.config_tag=="traitorchan")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if ((src in ticker.mode.changelings) && special_role)
text += "<b>YES</b>|<a href='?src=\ref[src];changeling=clear'>no</a>"
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];changeling=autoobjectives'>Randomize!</a>"
if(changeling && changeling.stored_profiles.len && (current.real_name != changeling.first_prof.name) )
text += "<br><a href='?src=\ref[src];changeling=initialdna'>Transform to initial appearance.</a>"
else if(src in ticker.mode.changelings) //Station Aligned Changeling
text += "<b>YES (but not an antag)</b>|<a href='?src=\ref[src];changeling=clear'>no</a>"
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];changeling=autoobjectives'>Randomize!</a>"
if(changeling && changeling.stored_profiles.len && (current.real_name != changeling.first_prof.name) )
text += "<br><a href='?src=\ref[src];changeling=initialdna'>Transform to initial appearance.</a>"
else
text += "<a href='?src=\ref[src];changeling=changeling'>yes</a>|<b>NO</b>"
// var/datum/game_mode/changeling/changeling = ticker.mode
// if (istype(changeling) && changeling.changelingdeath)
// text += "<br>All the changelings are dead! Restart in [round((changeling.TIME_TO_GET_REVIVED-(world.time-changeling.changelingdeathtime))/10)] seconds."
if(current && current.client && (ROLE_CHANGELING in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["changeling"] = text
sections["abductor"] = text
/** NUCLEAR ***/
text = "nuclear"
@@ -482,6 +406,71 @@
sections["nuclear"] = text
/** WIZARD ***/
text = "wizard"
if (ticker.mode.config_tag=="wizard")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if ((src in ticker.mode.wizards) || (src in ticker.mode.apprentices))
text += "<b>YES</b>|<a href='?src=\ref[src];wizard=clear'>no</a>"
text += "<br><a href='?src=\ref[src];wizard=lair'>To lair</a>, <a href='?src=\ref[src];common=undress'>undress</a>, <a href='?src=\ref[src];wizard=dressup'>dress up</a>, <a href='?src=\ref[src];wizard=name'>let choose name</a>."
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];wizard=autoobjectives'>Randomize!</a>"
else
text += "<a href='?src=\ref[src];wizard=wizard'>yes</a>|<b>NO</b>"
if(current && current.client && (ROLE_WIZARD in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["wizard"] = text
/** CULT ***/
text = "cult"
if (ticker.mode.config_tag=="cult")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if (src in ticker.mode.cult)
text += "loyal|<a href='?src=\ref[src];cult=clear'>employee</a>|<b>CULTIST</b>"
text += "<br>Give <a href='?src=\ref[src];cult=tome'>tome</a>|<a href='?src=\ref[src];cult=amulet'>amulet</a>."
else if(isloyal(current))
text += "<b>LOYAL</b>|employee|<a href='?src=\ref[src];cult=cultist'>cultist</a>"
else if(is_convertable_to_cult(src))
text += "loyal|<b>EMPLOYEE</b>|<a href='?src=\ref[src];cult=cultist'>cultist</a>"
else
text += "loyal|<b>EMPLOYEE</b>|<i>cannot serve Nar-Sie</i>"
if(current && current.client && (ROLE_CULTIST in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["cult"] = text
/** CLOCKWORK CULT **/
text = "clockwork cult"
if(ticker.mode.config_tag == "clockwork cult")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(src in ticker.mode.servants_of_ratvar)
text += "loyal|<a href='?src=\ref[src];clockcult=clear'>employee</a>|<b>SERVANT</b>"
text += "<br><a href='?src=\ref[src];clockcult=slab'>Give slab</a>"
else if(isloyal(current))
text += "<b>LOYAL</b>|employee|<a href='?src=\ref[src];clockcult=servant'>servant</a>"
else if(is_eligible_servant(current))
text += "loyal|<b>EMPLOYEE</b>|<a href='?src=\ref[src];clockcult=servant'>servant</a>"
else
text += "loyal|<b>EMPLOYEE</b>|<i>cannot serve Ratvar</i>"
if(current && current.client && (ROLE_SERVANT_OF_RATVAR in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["clockcult"] = text
/** TRAITOR ***/
text = "traitor"
if (ticker.mode.config_tag=="traitor" || ticker.mode.config_tag=="traitorchan")
@@ -501,25 +490,6 @@
sections["traitor"] = text
/** Abductors **/
text = "Abductor"
if(ticker.mode.config_tag == "abductor")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if(src in ticker.mode.abductors)
text += "<b>Abductor</b>|<a href='?src=\ref[src];abductor=clear'>human</a>"
text += "|<a href='?src=\ref[src];common=undress'>undress</a>|<a href='?src=\ref[src];abductor=equip'>equip</a>"
else
text += "<a href='?src=\ref[src];abductor=abductor'>Abductor</a>|<b>human</b>"
if(current && current.client && (ROLE_ABDUCTOR in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["abductor"] = text
/** HAND OF GOD **/
text = "hand of god"
if(ticker.mode.config_tag == "handofgod")
@@ -552,8 +522,36 @@
sections["follower"] = text
/** MONKEY ***/
if (istype(current, /mob/living/carbon))
if(ishuman(current) || ismonkey(current))
/** CHANGELING ***/
text = "changeling"
if (ticker.mode.config_tag=="changeling" || ticker.mode.config_tag=="traitorchan")
text = uppertext(text)
text = "<i><b>[text]</b></i>: "
if ((src in ticker.mode.changelings) && special_role)
text += "<b>YES</b>|<a href='?src=\ref[src];changeling=clear'>no</a>"
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];changeling=autoobjectives'>Randomize!</a>"
if(changeling && changeling.stored_profiles.len && (current.real_name != changeling.first_prof.name) )
text += "<br><a href='?src=\ref[src];changeling=initialdna'>Transform to initial appearance.</a>"
else if(src in ticker.mode.changelings) //Station Aligned Changeling
text += "<b>YES (but not an antag)</b>|<a href='?src=\ref[src];changeling=clear'>no</a>"
if (objectives.len==0)
text += "<br>Objectives are empty! <a href='?src=\ref[src];changeling=autoobjectives'>Randomize!</a>"
if(changeling && changeling.stored_profiles.len && (current.real_name != changeling.first_prof.name) )
text += "<br><a href='?src=\ref[src];changeling=initialdna'>Transform to initial appearance.</a>"
else
text += "<a href='?src=\ref[src];changeling=changeling'>yes</a>|<b>NO</b>"
if(current && current.client && (ROLE_CHANGELING in current.client.prefs.be_special))
text += "|Enabled in Prefs"
else
text += "|Disabled in Prefs"
sections["changeling"] = text
/** MONKEY ***/
text = "monkey"
if (ticker.mode.config_tag=="monkey")
text = uppertext(text)
@@ -1227,7 +1225,7 @@
log_admin("[key_name(usr)] has de-sintouch'ed [current].")
if("devil")
if(!ishuman(current) && !iscyborg(current))
usr << "<span class='warning'>This only works on humans!</span>"
usr << "<span class='warning'>This only works on humans and cyborgs!</span>"
return
ticker.mode.devils += src
special_role = "devil"
+8
View File
@@ -139,27 +139,34 @@ var/list/teleportlocs = list()
/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
/area/start
name = "start area"
@@ -658,6 +665,7 @@ var/list/teleportlocs = list()
luminosity = 1
lighting_use_dynamic = DYNAMIC_LIGHTING_IFSTARLIGHT
valid_territory = 0
blob_allowed = FALSE
/area/solar/auxport
name = "Fore Port Solar Array"
+13
View File
@@ -74,6 +74,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 +94,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 +104,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 +137,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 +161,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
+5 -2
View File
@@ -25,11 +25,12 @@ var/list/blobs_legit = list() //used for win-score calculations, contains only b
<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/burst = 0
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
@@ -73,7 +74,8 @@ 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
@@ -91,6 +93,7 @@ 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)
+24 -5
View File
@@ -1,10 +1,14 @@
/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.clearHostileEnvironment(src)
return ..()
@@ -18,23 +22,38 @@
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.")
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).")
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.")
..()
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
+7 -5
View File
@@ -168,20 +168,23 @@
return ..()
/mob/living/simple_animal/hostile/blob/blobspore/update_icons()
..()
if(overmind)
color = overmind.blob_reagent_datum.complementary_color
else
color = initial(color)
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,7 +202,6 @@
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 = 20
+2 -2
View File
@@ -7,7 +7,6 @@
maxhealth = 400
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
@@ -50,7 +49,8 @@
return ..()
/obj/effect/blob/core/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return
exposed_temperature *= 0.5
..()
/obj/effect/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
+6 -6
View File
@@ -7,13 +7,12 @@
maxhealth = 200
health_regen = 3
point_return = 25
atmosblock = 1
/obj/effect/blob/node/New(loc, var/h = 100)
/obj/effect/blob/node/New(loc)
blob_nodes += src
START_PROCESSING(SSobj, src)
..(loc, h)
..(loc)
/obj/effect/blob/node/scannerreport()
return "Gradually expands and sustains nearby blob spores and blobbernauts."
@@ -28,14 +27,15 @@
var/image/C = new('icons/mob/blob.dmi', "blob_node_overlay")
src.add_overlay(C)
/obj/effect/blob/node/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return
/obj/effect/blob/node/Destroy()
blob_nodes -= src
STOP_PROCESSING(SSobj, src)
return ..()
/obj/effect/blob/node/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
exposed_temperature *= 0.75
..()
/obj/effect/blob/node/Life()
Pulse_Area(overmind, 10, 3, 2)
color = null
+19 -3
View File
@@ -1,21 +1,37 @@
/obj/effect/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
brute_resist = 0.25
explosion_block = 3
point_return = 4
atmosblock = 1
/obj/effect/blob/shield/scannerreport()
return "Will prevent the spread of atmospheric changes."
if(atmosblock)
return "Will prevent the spread of atmospheric changes."
return "N/A"
/obj/effect/blob/shield/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
return
/obj/effect/blob/shield/core
point_return = 0
/obj/effect/blob/shield/update_icon()
..()
if(health <= 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)
+27 -16
View File
@@ -1,12 +1,15 @@
/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")
@@ -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()
@@ -70,18 +73,19 @@
/mob/camera/blob/Destroy()
for(var/BL in blobs)
var/obj/effect/blob/B = BL
if(B.overmind == src)
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,6 +95,12 @@
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)
@@ -100,9 +110,8 @@
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>"
/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)
@@ -150,6 +159,11 @@
if(blob_core)
stat(null, "Core Health: [blob_core.health]")
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)
@@ -170,6 +184,3 @@
return 0
loc = NewLoc
return 1
/mob/camera/blob/proc/can_attack()
return (world.time > (last_attack + CLICK_CD_RANGE))
+59 -22
View File
@@ -67,12 +67,13 @@
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/effect/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]
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)
@@ -110,12 +111,12 @@
/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/effect/blob/shield, 0, 0, T)
/mob/camera/blob/verb/create_resource()
set category = "Blob"
@@ -125,9 +126,9 @@
/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/effect/blob/node, 5, 0)
/mob/camera/blob/verb/create_factory()
set category = "Blob"
@@ -166,9 +167,8 @@
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
if(candidates.len) //if we got at least one candidate, they're a blobbernaut now.
C = pick(candidates)
var/client/C = pick(candidates)
blobber.notransform = 0
blobber.key = C.key
blobber << 'sound/effects/blobattack.ogg'
@@ -190,11 +190,21 @@
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(istype(T, /turf/open/space) || 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"
@@ -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/effect/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
@@ -250,10 +261,31 @@
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/effect/blob/IB = I
if(get_dir(IB, T) in cardinal)
cardinalblobs += IB
else
diagonalblobs += IB
var/obj/effect/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,6 +330,7 @@
/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
B.update_icon()
@@ -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>"
+39 -26
View File
@@ -7,12 +7,13 @@
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
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
@@ -24,8 +25,8 @@
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()
setDir(pick(cardinal))
update_icon()
..(loc)
ConsumeTile()
if(atmosblock)
@@ -84,46 +85,56 @@
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.
if(overmind)
color = overmind.blob_reagent_datum.color
else
color = null
return
/obj/effect/blob/process()
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)
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/effect/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/effect/blob/B = L
if(!B.overmind && !istype(B, /obj/effect/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/effect/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()
if(pulse_timestamp <= world.time)
ConsumeTile()
health = min(maxhealth, health+health_regen)
if(heal_timestamp <= world.time)
health = min(maxhealth, health+health_regen)
heal_timestamp = world.time + 20
update_icon()
pulse_timestamp = world.time + 10
return 1 //we did it, we were pulsed!
@@ -137,6 +148,7 @@
/obj/effect/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
@@ -311,6 +323,7 @@
B.overmind = controller
B.creation_action()
B.update_icon()
B.setDir(dir)
qdel(src)
return B
@@ -342,13 +355,13 @@
brute_resist = 0.25
/obj/effect/blob/normal/scannerreport()
if(health <= 10)
if(health <= 15)
return "Currently weak to brute damage."
return "N/A"
/obj/effect/blob/normal/update_icon()
..()
if(health <= 10)
if(health <= 15)
icon_state = "blob_damaged"
name = "fragile blob"
desc = "A thin lattice of slightly twitching tendrils."
+13 -13
View File
@@ -16,7 +16,6 @@ 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_items.dm: Items (excluding the proselytizer).
clock_machines.dm: Machinery like the mending motor.
@@ -27,6 +26,7 @@ This file's folder contains:
clock_structures.dm: Structures and effects
clock_unsorted.dm: Anything else with no place to be
clockcult defines are in __DEFINES/clockcult.dm
*/
///////////
@@ -183,7 +183,7 @@ 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
@@ -237,20 +237,20 @@ 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)
silicons_possible = TRUE
if(silicons_possible)
possible_objectives += "silicons"
possible_objectives += CLOCKCULT_SILICONS
clockwork_objective = pick(possible_objectives)
switch(clockwork_objective)
if("escape")
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("gateway")
if(CLOCKCULT_GATEWAY)
clockwork_explanation = "Construct a Gateway to the Celestial Derelict and free Ratvar."
if("silicons")
if(CLOCKCULT_SILICONS)
clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar by the end of the shift."
return 1
@@ -291,16 +291,16 @@ 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++
clockwork_explanation = "Ensure that [required_escapees] servant(s) of Ratvar escape from [station_name()]. <i><b>[surviving_servants]</b> managed to escape!</i>"
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)
return TRUE
return FALSE
if("silicons")
if(CLOCKCULT_SILICONS)
var/total_silicons = 0
var/valid_silicons = 0
var/successful = TRUE
@@ -314,10 +314,10 @@ This file's folder contains:
valid_silicons++
if(valid_silicons < total_silicons)
successful = FALSE
clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar by the end of the shift. \
clockwork_explanation = "Ensure that all active silicon-based lifeforms on [station_name()] are servants of Ratvar by the end of the shift.<br>\
<i><b>[valid_silicons]/[total_silicons]</b> silicons were killed or converted!</i>"
return successful
if("gateway")
if(CLOCKCULT_GATEWAY)
return ratvar_awakens
return FALSE //This shouldn't ever be reached, but just in case it is
@@ -334,7 +334,7 @@ This file's folder contains:
feedback_set_details("round_end_result", "win - servants completed their objective ([clockwork_objective])")
else
var/half_victory = FALSE
if(clockwork_objective == "gateway")
if(clockwork_objective == CLOCKCULT_GATEWAY)
var/obj/structure/clockwork/massive/celestial_gateway/G = locate() in all_clockwork_objects
if(G)
half_victory = TRUE
+47 -13
View File
@@ -13,6 +13,9 @@
poi_list -= src
return ..()
/obj/structure/clockwork/massive/singularity_pull(S, current_size)
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."
@@ -29,6 +32,7 @@
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
@@ -120,23 +124,48 @@
sleep(125)
make_glow()
animate(glow, transform = matrix() * 3, alpha = 0, time = 5)
sleep(5)
new/obj/structure/clockwork/massive/ratvar(get_turf(src))
qdel(src)
var/turf/startpoint = get_turf(src)
sleep(3)
QDEL_IN(src, 3)
clockwork_gateway_activated = TRUE
if(ratvar_portal)
new/obj/structure/clockwork/massive/ratvar(startpoint)
else
world << "<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>"
world << '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 < 60)
dist = TRUE
else
dist = FALSE
T.ratvar_act(dist)
CHECK_TICK
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!")))
/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))
user << "<span class='big'><b>Seconds until Ratvar's arrival:</b> [get_arrival_text(TRUE)]</span>"
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 is coming through the gateway!</span>"
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)
@@ -144,7 +173,7 @@
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>"
user << "<span class='boldwarning'>[ratvar_portal ? "Something is coming through":"It's glowing brightly"]!</span>"
/obj/effect/clockwork/overlay/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'
@@ -170,11 +199,11 @@
/obj/structure/clockwork/massive/ratvar/New()
..()
ratvar_awakens = TRUE
ratvar_awakens++
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>\"[text2ratvar("ONCE AGAIN MY LIGHT SHALL SHINE ACROSS THIS PATHETIC REALM")]!!\"</font></span>"
world << "<span class='ratvar'>\"[text2ratvar("ONCE AGAIN MY LIGHT SHALL SHINE ACROSS THIS PATHETIC REALM")]!!\"</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)
@@ -183,7 +212,7 @@
/obj/structure/clockwork/massive/ratvar/Destroy()
ratvar_awakens = FALSE
ratvar_awakens--
for(var/obj/item/clockwork/ratvarian_spear/R in all_clockwork_objects)
R.update_force()
STOP_PROCESSING(SSobj, src)
@@ -201,8 +230,9 @@
/obj/structure/clockwork/massive/ratvar/Bump(atom/A)
forceMove(get_turf(A))
A.ratvar_act()
var/turf/T = get_turf(A)
forceMove(T)
T.ratvar_act()
/obj/structure/clockwork/massive/ratvar/Process_Spacemove()
@@ -212,8 +242,12 @@
/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()
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)
@@ -1226,7 +1226,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar //Ark of the Clockwork Justiciar: Creates a Gateway to the Celestial Derelict.
descname = "Summon Ratvar"
descname = "Win Condition"
name = "Ark of the Clockwork Justiciar"
desc = "Pulls from the power of all of Ratvar's servants and generals to construct a massive machine used to tear apart a rift in spacetime to the Celestial Derelict. This gateway will \
call forth Ratvar from his exile after some time."
@@ -1236,55 +1236,83 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
channel_time = 150
required_components = list("belligerent_eye" = 10, "vanguard_cogwheel" = 10, "guvax_capacitor" = 10, "replicant_alloy" = 10, "hierophant_ansible" = 10)
consumed_components = list("belligerent_eye" = 10, "vanguard_cogwheel" = 10, "guvax_capacitor" = 10, "replicant_alloy" = 10, "hierophant_ansible" = 10)
invokers_required = 4
invokers_required = 5
multiple_invokers_used = TRUE
usage_tip = "The gateway is completely vulnerable to attack during its five-minute duration. In addition to preventing shuttle departure, 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!"
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
/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 && ratvar_awakens)
invoker << "<span class='big_brass'>\"I am already here, idiot.\"</span>"
return 0
for(var/obj/structure/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 0
var/area/A = get_area(invoker)
if(!slab.no_cost && (invoker.z != ZLEVEL_STATION || istype(A, /area/shuttle)))
invoker << "<span class='warning'>You must be on the station to activate the Ark!</span>"
return 0
if(!slab.no_cost && ticker.mode.clockwork_objective != "gateway")
invoker << "<span class='warning'>As painful as it is, Ratvar's will is not to be freed!</span>"
return 0
if(!slab.no_cost)
if(ratvar_awakens)
invoker << "<span class='big_brass'>\"I am already here, idiot.\"</span>"
return 0
for(var/obj/structure/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 0
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 0
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 0
return 1
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/scripture_effects()
var/turf/T = get_turf(invoker)
new/obj/effect/clockwork/general_marker/inathneq(T)
T.visible_message("<span class='inathneq'>\"[text2ratvar("Engine, come forth and show your servants your mercy!")]\"</span>")
if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY)
T.visible_message("<span class='inathneq'>\"[text2ratvar("Engine, come forth and show your servants your mercy!")]\"</span>")
else
T.visible_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)
if(!check_special_requirements())
return 0
new/obj/effect/clockwork/general_marker/sevtug(T)
T.visible_message("<span class='sevtug'>\"[text2ratvar("Engine, come forth and show this station your decorating skills!")]\"</span>")
if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY)
T.visible_message("<span class='sevtug'>\"[text2ratvar("Engine, come forth and show this station your decorating skills!")]\"</span>")
else
T.visible_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)
if(!check_special_requirements())
return 0
new/obj/effect/clockwork/general_marker/nezbere(T)
T.visible_message("<span class='nezbere'>\"[text2ratvar("Engine, come forth and shine your light across this realm!")]\"</span>")
if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY)
T.visible_message("<span class='nezbere'>\"[text2ratvar("Engine, come forth and shine your light across this realm!!")]\"</span>")
else
T.visible_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)
if(!check_special_requirements())
return 0
new/obj/effect/clockwork/general_marker/nzcrentr(T)
T.visible_message("<span class='nzcrentr'>\"[text2ratvar("Engine, come forth.")]\"</span>")
if(ticker && ticker.mode && ticker.mode.clockwork_objective == CLOCKCULT_GATEWAY)
T.visible_message("<span class='nzcrentr'>\"[text2ratvar("Engine, come forth.")]\"</span>")
else
T.visible_message("<span class='nezbere'>\"[text2ratvar("We will show all Engine's power!")]\"</span>")
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 75, 0)
sleep(10)
if(check_special_requirements())
new/obj/structure/clockwork/massive/celestial_gateway(T)
var/obj/structure/clockwork/massive/celestial_gateway/CG = new/obj/structure/clockwork/massive/celestial_gateway(T)
if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY)
CG.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)
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 100, 0)
var/list/open_turfs = list()
for(var/turf/open/OT in orange(1, T))
@@ -653,6 +653,9 @@
/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
@@ -212,7 +212,7 @@
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
var/mob/dead/selected = popleft(candidates)
var/mob/dead/selected = pick_n_take(candidates)
var/datum/mind/player_mind = new /datum/mind(selected.key)
player_mind.active = 1
@@ -60,6 +60,7 @@
var/list/drained_mobs = list() //Cannot harvest the same mob twice
var/perfectsouls = 0 //How many perfect, regen-cap increasing souls the revenant has. //TODO, add objective for getting a perfect soul(s?)
var/image/ghostimage = null //Visible to ghost with darkness off
var/generated_objectives_and_spells = FALSE
/mob/living/simple_animal/revenant/New()
..()
@@ -68,28 +69,31 @@
ghost_darkness_images |= ghostimage
updateallghostimages()
spawn(5)
if(src.mind)
src.mind.remove_all_antag()
src.mind.wipe_memory()
src << 'sound/effects/ghost.ogg'
src << "<br>"
src << "<span class='deadsay'><font size=3><b>You are a revenant.</b></font></span>"
src << "<b>Your formerly mundane spirit has been infused with alien energies and empowered into a revenant.</b>"
src << "<b>You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds.</b>"
src << "<b>You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.</b>"
src << "<b>To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities.</b>"
src << "<b><i>You do not remember anything of your past lives, nor will you remember anything about this one after your death.</i></b>"
src << "<b>Be sure to read the wiki page at https://tgstation13.org/wiki/Revenant to learn more.</b>"
var/datum/objective/revenant/objective = new
objective.owner = src.mind
src.mind.objectives += objective
src << "<b>Objective #1</b>: [objective.explanation_text]"
var/datum/objective/revenantFluff/objective2 = new
objective2.owner = src.mind
src.mind.objectives += objective2
src << "<b>Objective #2</b>: [objective2.explanation_text]"
ticker.mode.traitors |= src.mind //Necessary for announcing
/mob/living/simple_animal/revenant/Login()
..()
src << "<span class='deadsay'><font size=3><b>You are a revenant.</b></font></span>"
src << "<b>Your formerly mundane spirit has been infused with alien energies and empowered into a revenant.</b>"
src << "<b>You are not dead, not alive, but somewhere in between. You are capable of limited interaction with both worlds.</b>"
src << "<b>You are invincible and invisible to everyone but other ghosts. Most abilities will reveal you, rendering you vulnerable.</b>"
src << "<b>To function, you are to drain the life essence from humans. This essence is a resource, as well as your health, and will power all of your abilities.</b>"
src << "<b><i>You do not remember anything of your past lives, nor will you remember anything about this one after your death.</i></b>"
src << "<b>Be sure to read the wiki page at https://tgstation13.org/wiki/Revenant to learn more.</b>"
if(!generated_objectives_and_spells)
generated_objectives_and_spells = TRUE
mind.remove_all_antag()
mind.wipe_memory()
src << 'sound/effects/ghost.ogg'
var/datum/objective/revenant/objective = new
objective.owner = mind
mind.objectives += objective
src << "<b>Objective #1</b>: [objective.explanation_text]"
var/datum/objective/revenantFluff/objective2 = new
objective2.owner = mind
mind.objectives += objective2
src << "<b>Objective #2</b>: [objective2.explanation_text]"
mind.assigned_role = "revenant"
mind.special_role = "Revenant"
ticker.mode.traitors |= mind //Necessary for announcing
AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null))
AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/defile(null))
@@ -97,7 +101,6 @@
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/blight(null))
AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction(null))
//Life, Stat, Hud Updates, and Say
/mob/living/simple_animal/revenant/Life()
if(revealed && essence <= 0)
@@ -10,15 +10,15 @@
/datum/round_event/ghost_role/revenant
var/force_spawn
var/ignore_mobcheck = FALSE
role_name = "revenant"
/datum/round_event/ghost_role/revenant/New(my_force_spawn = FALSE)
/datum/round_event/ghost_role/revenant/New(my_processing = TRUE, new_ignore_mobcheck = FALSE)
..()
force_spawn = my_force_spawn
ignore_mobcheck = new_ignore_mobcheck
/datum/round_event/ghost_role/revenant/spawn_role()
if(!force_spawn)
if(!ignore_mobcheck)
var/deadMobs = 0
for(var/mob/M in dead_mob_list)
deadMobs++
@@ -26,14 +26,12 @@
message_admins("Event attempted to spawn a revenant, but there were only [deadMobs]/[REVENANT_SPAWN_THRESHOLD] dead mobs.")
return WAITING_FOR_SOMETHING
var/list/mob/dead/observer/candidates = get_candidates("revenant", null, ROLE_REVENANT)
var/list/candidates = get_candidates("revenant", null, ROLE_REVENANT)
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
var/mob/dead/observer/selected = popleft(candidates)
var/mob/dead/observer/selected = pick_n_take(candidates)
var/datum/mind/player_mind = new /datum/mind(selected.key)
player_mind.active = 1
var/list/spawn_locs = list()
for(var/obj/effect/landmark/L in landmarks_list)
@@ -48,16 +46,13 @@
if("carpspawn")
spawn_locs += L.loc
if(!spawn_locs) //If we can't find either, just spawn the revenant at the player's location
spawn_locs += get_turf(player_mind.current)
spawn_locs += get_turf(selected)
if(!spawn_locs) //If we can't find THAT, then just give up and cry
return MAP_ERROR
var/mob/living/simple_animal/revenant/revvie = new /mob/living/simple_animal/revenant/(pick(spawn_locs))
player_mind.transfer_to(revvie)
player_mind.assigned_role = "revenant"
player_mind.special_role = "Revenant"
ticker.mode.traitors |= player_mind
message_admins("[player_mind.key] has been made into a revenant by an event.")
log_game("[player_mind.key] was spawned as a revenant by an event.")
revvie.key = selected.key
message_admins("[revvie.key] has been made into a revenant by an event.")
log_game("[revvie.key] was spawned as a revenant by an event.")
spawned_mobs += revvie
return SUCCESSFUL_SPAWN
@@ -17,7 +17,7 @@
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
var/mob/dead/selected = popleft(candidates)
var/mob/dead/selected = pick_n_take(candidates)
var/datum/mind/player_mind = new /datum/mind(selected.key)
player_mind.active = 1
-8
View File
@@ -89,14 +89,6 @@
open_machine()
..(severity)
/obj/machinery/sleeper/blob_act(obj/effect/blob/B)
if(prob(75))
var/turf/T = get_turf(src)
for(var/atom/movable/A in src)
A.forceMove(T)
A.blob_act(B)
qdel(src)
/obj/machinery/sleeper/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
return
+4
View File
@@ -106,6 +106,10 @@
..()
/obj/machinery/camera/blob_act(obj/effect/blob/B)
if(B && B.loc == loc)
take_damage(health, BRUTE, 0)
/obj/machinery/camera/ex_act(severity, target)
if(src.invuln)
return
+1 -1
View File
@@ -55,7 +55,7 @@
take_damage(rand(10,30), BRUTE, 0)
/obj/machinery/computer/ratvar_act()
if(!clockwork && prob(20))
if(!clockwork)
clockwork = TRUE
icon_screen = "ratvar[rand(1, 4)]"
icon_keyboard = "ratvar_key[rand(1, 6)]"
+5 -6
View File
@@ -156,12 +156,11 @@ var/list/airlock_overlays = list()
qdel(src)
/obj/machinery/door/airlock/ratvar_act() //Airlocks become pinion airlocks that only allow servants
if(prob(20))
if(glass)
new/obj/machinery/door/airlock/clockwork/brass(get_turf(src))
else
new/obj/machinery/door/airlock/clockwork(get_turf(src))
qdel(src)
if(glass)
new/obj/machinery/door/airlock/clockwork/brass(get_turf(src))
else
new/obj/machinery/door/airlock/clockwork(get_turf(src))
qdel(src)
/obj/machinery/door/airlock/Destroy()
qdel(wires)
@@ -352,13 +352,6 @@
/obj/machinery/door/airlock/cult/narsie_act()
return
/obj/machinery/door/airlock/cult/ratvar_act()
..()
if(src)
var/previouscolor = color
color = "#FAE48C"
animate(src, color = previouscolor, time = 8)
/obj/machinery/door/airlock/cult/friendly
friendly = TRUE
+1 -1
View File
@@ -182,7 +182,7 @@ obj/machinery/door/proc/try_to_crowbar(obj/item/I, mob/user)
/obj/machinery/door/blob_act(obj/effect/blob/B)
if(prob(40))
if(prob(60))
qdel(src)
/obj/machinery/door/emp_act(severity)
+2 -3
View File
@@ -196,9 +196,8 @@
color = "#7D1919"
/obj/machinery/door/window/ratvar_act()
if(prob(20))
new/obj/machinery/door/window/clockwork(src.loc, dir)
qdel(src)
new/obj/machinery/door/window/clockwork(src.loc, dir)
qdel(src)
/obj/machinery/door/window/bullet_act(obj/item/projectile/P)
. = ..()
+1 -3
View File
@@ -189,9 +189,7 @@ Class Procs:
update_icon()
/obj/machinery/blob_act(obj/effect/blob/B)
if(!density)
qdel(src)
if(prob(75))
if(density && prob(75))
qdel(src)
/obj/machinery/proc/auto_use_power()
+34 -1
View File
@@ -8,6 +8,7 @@
idle_power_usage = 4
active_power_usage = 250
var/obj/item/weapon/charging = null
var/list/allowed_devices = list(/obj/item/weapon/gun/energy,/obj/item/weapon/melee/baton,/obj/item/ammo_box/magazine/recharge,/obj/item/weapon/computer_hardware/battery_module,/obj/item/laptop,/obj/item/modular_computer/)
var/recharge_coeff = 1
/obj/machinery/recharger/New()
@@ -36,7 +37,11 @@
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
return
if(istype(G, /obj/item/weapon/gun/energy) || istype(G, /obj/item/weapon/melee/baton) || istype(G, /obj/item/ammo_box/magazine/recharge))
var/allowed = 0
for (var/allowed_type in allowed_devices)
if (istype(G, allowed_type)) allowed = 1
if(allowed)
if(anchored)
if(charging || panel_open)
return 1
@@ -127,6 +132,34 @@
use_power(200 * recharge_coeff)
using_power = 1
if(istype(charging, /obj/item/laptop))
var/obj/item/laptop/L = charging
if(L.stored_computer.cpu.battery_module)
var/obj/item/weapon/computer_hardware/battery_module/B = L.stored_computer.cpu.battery_module
if(B.battery)
if(B.battery.charge < B.battery.maxcharge)
B.battery.give(B.battery.chargerate * recharge_coeff)
use_power(200 * recharge_coeff)
using_power = 1
if(istype(charging, /obj/item/weapon/computer_hardware/battery_module))
var/obj/item/weapon/computer_hardware/battery_module/B = charging
if(B.battery)
if(B.battery.charge < B.battery.maxcharge)
B.battery.give(B.battery.chargerate * recharge_coeff)
use_power(200 * recharge_coeff)
using_power = 1
if(istype(charging, /obj/item/modular_computer))
var/obj/item/modular_computer/C = charging
if(C.battery_module)
var/obj/item/weapon/computer_hardware/battery_module/B = C.battery_module
if(B.battery)
if(B.battery.charge < B.battery.maxcharge)
B.battery.give(B.battery.chargerate * recharge_coeff)
use_power(200 * recharge_coeff)
using_power = 1
update_icon(using_power)
/obj/machinery/recharger/power_change()
+2 -1
View File
@@ -118,7 +118,8 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s
return ..()
/obj/item/blob_act(obj/effect/blob/B)
qdel(src)
if(B && B.loc == loc)
qdel(src)
/obj/item/ex_act(severity, target)
if(severity == 1 || target == src)
@@ -1,35 +0,0 @@
/obj/item/modkit
name = "modification kit"
desc = "A one-use kit, which enables kinetic accelerators to retain their \
charge when away from a bioelectric source, renders them immune to \
interference with other accelerators, as well as allowing less \
dextrous races to use the tool."
icon = 'icons/obj/objects.dmi'
icon_state = "modkit"
origin_tech = "programming=2;materials=2;magnets=4"
var/uses = 1
/obj/item/modkit/afterattack(obj/item/weapon/gun/energy/kinetic_accelerator/C, mob/user)
..()
if(!uses)
qdel(src)
return
if(!istype(C))
user << "<span class='warning'>This kit can only modify kinetic \
accelerators!</span>"
return ..()
// RIP the 'improved improved improved improved kinetic accelerator
if(C.holds_charge && C.unique_frequency)
user << "<span class='warning'>This kinetic accelerator already has \
these upgrades.</span>"
return ..()
user <<"<span class='notice'>You modify the [C], adjusting the trigger \
guard and internal capacitor.</span>"
C.name = "improved [C.name]"
C.holds_charge = TRUE
C.unique_frequency = TRUE
C.trigger_guard = TRIGGER_GUARD_ALLOW_ALL
uses--
if(!uses)
qdel(src)
@@ -30,6 +30,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \
new/datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 40, one_per_turf = 1, on_floor = 1), \
null, \
new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 25, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("modular console", /obj/machinery/modular_computer/console/buildable/, 10, time = 25, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("machine frame", /obj/structure/frame/machine, 5, time = 25, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("airlock assembly", /obj/structure/door_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1), \
new/datum/stack_recipe("firelock frame", /obj/structure/firelock_frame, 3, time = 50, one_per_turf = 1, on_floor = 1), \
@@ -152,7 +152,7 @@
add_mutations_static = list(CLOWNMUT)
/obj/item/weapon/dnainjector/anticlumsy
name = "\improper DNA injector (Anti-Clumy)"
name = "\improper DNA injector (Anti-Clumsy)"
desc = "Apply this for Security Clown."
remove_mutations_static = list(CLOWNMUT)
@@ -13,7 +13,8 @@
bang(get_turf(M), M)
for(var/obj/effect/blob/B in get_hear(8,flashbang_turf)) //Blob damage here
var/damage = round(40/(get_dist(B,get_turf(src))+1))
var/distance = get_dist(B, get_turf(src))
var/damage = round(100/(distance*distance)+1)
B.take_damage(damage, BURN)
qdel(src)
@@ -108,8 +108,8 @@
name = "plant bag"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "plantbag"
storage_slots = 50; //the number of plant pieces it can carry.
max_combined_w_class = 200 //Doesn't matter what this is, so long as it's more or equal to storage_slots * plants.w_class
storage_slots = 100; //the number of plant pieces it can carry.
max_combined_w_class = 100 //Doesn't matter what this is, so long as it's more or equal to storage_slots * plants.w_class
max_w_class = 3
w_class = 1
can_hold = list(/obj/item/weapon/reagent_containers/food/snacks/grown,/obj/item/seeds,/obj/item/weapon/grown)
@@ -183,7 +183,10 @@
/obj/item/weapon/reagent_containers/pill,
/obj/item/weapon/storage/pill_bottle,
/obj/item/weapon/ore,
/obj/item/weapon/reagent_containers/food/drinks
/obj/item/weapon/reagent_containers/food/drinks,
/obj/item/organ/hivelord_core,
/obj/item/device/wormhole_jaunter
)
@@ -70,7 +70,7 @@
/obj/item/weapon/storage/box/survival_mining/New()
..()
new /obj/item/clothing/mask/breath(src)
new /obj/item/clothing/mask/gas/explorer(src)
new /obj/item/weapon/tank/internals/emergency_oxygen/engi(src)
new /obj/item/weapon/crowbar/red(src)
new /obj/item/weapon/reagent_containers/hypospray/medipen(src)
@@ -92,12 +92,12 @@
user << "<span class='notice'>It feels [descriptive].</span>"
/obj/item/weapon/tank/blob_act(obj/effect/blob/B)
if(prob(50))
var/turf/location = src.loc
if (!( istype(location, /turf) ))
if(B && B.loc == loc)
var/turf/location = get_turf(src)
if(!location)
qdel(src)
if(src.air_contents)
if(air_contents)
location.assume_air(air_contents)
qdel(src)
+2 -6
View File
@@ -218,7 +218,6 @@
w_class = 2
materials = list(MAT_METAL=70, MAT_GLASS=30)
origin_tech = "engineering=1;plasmatech=1"
var/welding = 0 //Whether or not the welding tool is off(0), on(1) or currently welding(2)
@@ -332,8 +331,6 @@
if(welding)
SetLuminosity(0)
user.AddLuminosity(light_intensity)
else
user.AddLuminosity(-light_intensity)
update_icon()
@@ -396,9 +393,8 @@ obj/item/weapon/weldingtool/proc/switched_on(mob/user)
//Switches the welder off
obj/item/weapon/weldingtool/proc/switched_off(mob/user)
welding = 0
var/mob/Player = loc
if(ismob(loc)) //If player is holding the welder
Player.AddLuminosity(-light_intensity)
if(user == loc) //If player is holding the welder
user.AddLuminosity(-light_intensity)
SetLuminosity(0)
else
SetLuminosity(0)
+15 -9
View File
@@ -83,13 +83,6 @@
user.put_in_inactive_hand(O)
return
/obj/item/weapon/twohanded/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
//Cannot equip wielded items.
if(wielded)
M << "<span class='warning'>Unwield the [name] first!</span>"
return 0
return ..()
/obj/item/weapon/twohanded/dropped(mob/user)
..()
//handles unwielding a twohanded weapon when dropped as well as clearing up the offhand
@@ -109,6 +102,11 @@
else //Trying to wield it
wield(user)
/obj/item/weapon/twohanded/equip_to_best_slot(mob/M)
if(..())
unwield(M)
return
///////////OFFHAND///////////////
/obj/item/weapon/twohanded/offhand
name = "offhand"
@@ -131,7 +129,7 @@
return
/obj/item/weapon/twohanded/required/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
if(wielded)
if(wielded && !slot_flags)
M << "<span class='warning'>\The [src] is too cumbersome to carry with anything but your hands!</span>"
return 0
return ..()
@@ -143,9 +141,17 @@
if(H != null)
user << "<span class='notice'>\The [src] is too cumbersome to carry in one hand!</span>"
return
wield(user)
if(src.loc != user)
wield(user)
..()
/obj/item/weapon/twohanded/required/equipped(mob/user, slot)
..()
if(slot == slot_l_hand || slot == slot_r_hand)
wield(user)
else
unwield(user)
/obj/item/weapon/twohanded/
+1 -3
View File
@@ -16,9 +16,7 @@
cameranet.updateVisibility(src)
/obj/structure/blob_act(obj/effect/blob/B)
if(!density)
qdel(src)
if(prob(50))
if(density && prob(50))
qdel(src)
/obj/structure/Destroy()
@@ -208,10 +208,6 @@
visible_message("<span class='danger'>[user] destroys \the [src].</span>")
qdel(src)
/obj/structure/closet/blob_act(obj/effect/blob/B)
if(prob(75))
qdel(src)
/obj/structure/closet/attackby(obj/item/weapon/W, mob/user, params)
if(user in src)
return
+1 -4
View File
@@ -49,10 +49,7 @@
showpiece = null
/obj/structure/displaycase/blob_act(obj/effect/blob/B)
if (prob(75))
new /obj/item/weapon/shard( src.loc )
dump()
qdel(src)
take_damage(30)
/obj/structure/displaycase/hitby(atom/movable/AM)
..()
+1 -1
View File
@@ -84,7 +84,7 @@
/obj/structure/fireaxecabinet/blob_act(obj/effect/blob/B)
if(fireaxe)
fireaxe.loc = src.loc
fireaxe.forceMove(loc)
qdel(src)
/obj/structure/fireaxecabinet/attack_hand(mob/user)
+7 -7
View File
@@ -25,15 +25,15 @@
take_damage(rand(5,10), BRUTE, 0)
/obj/structure/grille/ratvar_act()
if(prob(20))
if(destroyed)
new /obj/structure/grille/ratvar/broken(src.loc)
else
new /obj/structure/grille/ratvar(src.loc)
qdel(src)
if(destroyed)
new /obj/structure/grille/ratvar/broken(src.loc)
else
new /obj/structure/grille/ratvar(src.loc)
qdel(src)
/obj/structure/grille/blob_act(obj/effect/blob/B)
qdel(src)
if(!destroyed)
Break()
/obj/structure/grille/Bumped(atom/user)
if(ismob(user))
-1
View File
@@ -15,7 +15,6 @@
/obj/structure/sign/blob_act(obj/effect/blob/B)
qdel(src)
return
/obj/structure/sign/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/weapon/wrench))
+2 -3
View File
@@ -79,9 +79,8 @@
qdel(src)
/obj/structure/table_frame/ratvar_act()
if(prob(20))
new /obj/structure/table_frame/brass(src.loc)
qdel(src)
new /obj/structure/table_frame/brass(src.loc)
qdel(src)
/*
* Wooden Frames
+3 -8
View File
@@ -54,16 +54,14 @@
take_damage(rand(40,80), BRUTE, 0)
/obj/structure/table/blob_act(obj/effect/blob/B)
if(prob(75))
qdel(src)
take_damage(rand(75,150), BRUTE, 0)
/obj/structure/table/narsie_act()
if(prob(20))
new /obj/structure/table/wood(src.loc)
/obj/structure/table/ratvar_act()
if(prob(20))
new /obj/structure/table/reinforced/brass(src.loc)
new /obj/structure/table/reinforced/brass(src.loc)
/obj/structure/table/mech_melee_attack(obj/mecha/M)
playsound(src.loc, 'sound/weapons/punch4.ogg', 50, 1)
@@ -463,10 +461,7 @@
take_damage(rand(5,25), BRUTE, 0)
/obj/structure/rack/blob_act(obj/effect/blob/B)
if(prob(75))
qdel(src)
else
rack_destroy()
rack_destroy()
/obj/structure/rack/mech_melee_attack(obj/mecha/M)
+6 -7
View File
@@ -66,7 +66,7 @@
take_damage(rand(25,75), BRUTE, 0)
/obj/structure/window/blob_act(obj/effect/blob/B)
shatter()
take_damage(rand(75,150), BRUTE, 0)
/obj/structure/window/narsie_act()
color = NARSIE_WINDOW_COLOUR
@@ -74,12 +74,11 @@
shard.color = NARSIE_WINDOW_COLOUR
/obj/structure/window/ratvar_act()
if(prob(20))
if(!fulltile)
new/obj/structure/window/reinforced/clockwork(get_turf(src), dir)
else
new/obj/structure/window/reinforced/clockwork/fulltile(get_turf(src))
qdel(src)
if(!fulltile)
new/obj/structure/window/reinforced/clockwork(get_turf(src), dir)
else
new/obj/structure/window/reinforced/clockwork/fulltile(get_turf(src))
qdel(src)
/obj/structure/window/singularity_pull(S, current_size)
if(current_size >= STAGE_FIVE)
+7 -2
View File
@@ -170,9 +170,14 @@ var/list/icons_to_ignore_at_floor_init = list("damaged1","damaged2","damaged3","
if(prob(20))
ChangeTurf(/turf/open/floor/engine/cult)
/turf/open/floor/ratvar_act()
if(prob(20))
/turf/open/floor/ratvar_act(force)
var/converted = (prob(40) || force)
if(converted)
ChangeTurf(/turf/open/floor/clockwork)
for(var/I in src)
var/atom/A = I
if(ismob(A) || converted)
A.ratvar_act()
/turf/open/floor/initialize()
..()
@@ -187,7 +187,8 @@
return ..()
/turf/open/floor/clockwork/ratvar_act()
return 0
for(var/mob/M in src)
M.ratvar_act()
/turf/open/floor/clockwork/narsie_act()
..()
+7 -2
View File
@@ -256,9 +256,14 @@
if(prob(20))
ChangeTurf(/turf/closed/wall/mineral/cult)
/turf/closed/wall/ratvar_act()
if(prob(20))
/turf/closed/wall/ratvar_act(force)
var/converted = (prob(40) || force)
if(converted)
ChangeTurf(/turf/closed/wall/clockwork)
for(var/I in src)
var/atom/A = I
if(ismob(A) || converted)
A.ratvar_act()
/turf/closed/wall/storage_contents_dump_act(obj/item/weapon/storage/src_object, mob/user)
return 0
+2 -1
View File
@@ -94,7 +94,8 @@
return ..()
/turf/closed/wall/clockwork/ratvar_act()
return 0
for(var/mob/M in src)
M.ratvar_act()
/turf/closed/wall/clockwork/narsie_act()
..()
+1 -1
View File
@@ -22,7 +22,7 @@
throw_atom(AM)
/turf/open/space/transit/proc/throw_atom(atom/movable/AM)
if(!AM)
if(!AM || istype(AM, /obj/docking_port))
return
var/max = world.maxx-TRANSITIONEDGE
var/min = 1+TRANSITIONEDGE
+3
View File
@@ -284,6 +284,9 @@
if(A.level >= affecting_level)
A.ex_act(severity, target)
/turf/ratvar_act()
for(var/mob/M in src)
M.ratvar_act()
/turf/proc/add_blueprints(atom/movable/AM)
var/image/I = new
+8 -1
View File
@@ -161,6 +161,9 @@ var/list/admin_ranks = list() //list of all admin_rank datums
C.holder = null
admins.Cut()
load_admin_ranks()
//Clear profile access
for(var/A in world.GetConfig("admin"))
world.SetConfig("APP/admin", A, null)
var/list/rank_names = list()
for(var/datum/admin_rank/R in admin_ranks)
@@ -189,6 +192,8 @@ var/list/admin_ranks = list() //list of all admin_rank datums
var/datum/admins/D = new(rank_names[rank], ckey) //create the admin datum and store it for later use
if(!D)
continue //will occur if an invalid rank is provided
if(D.rank.rights & R_DEBUG) //grant profile access
world.SetConfig("APP/admin", ckey, "role=admin")
D.associate(directory[ckey]) //find the client for a ckey if they are connected and associate them with the new admin datum
else
establish_db_connection()
@@ -214,6 +219,8 @@ var/list/admin_ranks = list() //list of all admin_rank datums
var/datum/admins/D = new(rank_names[rank], ckey) //create the admin datum and store it for later use
if(!D)
continue //will occur if an invalid rank is provided
if(D.rank.rights & R_DEBUG) //grant profile access
world.SetConfig("APP/admin", ckey, "role=admin")
D.associate(directory[ckey]) //find the client for a ckey if they are connected and associate them with the new admin datum
#ifdef TESTING
@@ -369,4 +376,4 @@ var/list/admin_ranks = list() //list of all admin_rank datums
var/sql_admin_rank = sanitizeSQL(newrank)
var/DBQuery/query_update = dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastadminrank = '[sql_admin_rank]' WHERE ckey = '[sql_ckey]'")
query_update.Execute()
query_update.Execute()
+4 -4
View File
@@ -92,10 +92,10 @@
message_admins("[key_name_admin(usr)] tried to create a death squad. Unfortunately, there were not enough candidates available.")
log_admin("[key_name(usr)] failed to create a death squad.")
if("blob")
var/strength = input("Set Blob Strength (1=Weak, 2=Strong, 3=Full)","Set Strength",1) as num
message_admins("[key_name(usr)] spawned a blob with strength [strength].")
log_admin("[key_name(usr)] spawned a blob with strength [strength].")
new/datum/round_event/blob(strength)
var/strength = input("Set Blob Resource Gain Rate","Set Resource Rate",1) as num
message_admins("[key_name(usr)] spawned a blob with base resource gain [strength].")
log_admin("[key_name(usr)] spawned a blob with base resource gain [strength].")
new/datum/round_event/ghost_role/blob(TRUE, strength)
if("gangs")
if(src.makeGangsters())
message_admins("[key_name(usr)] created gangs.")
+1 -1
View File
@@ -261,7 +261,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
log_admin("[key_name(src)] has blobized [M.key].")
var/mob/living/carbon/human/H = M
spawn(0)
var/mob/camera/blob/B = H.become_overmind()
var/mob/camera/blob/B = H.become_overmind(FALSE)
B.place_blob_core(B.base_point_rate, -1) //place them wherever they are
else
+2 -2
View File
@@ -134,7 +134,7 @@
var/list/mob/dead/observer/candidates = pollCandidates("Do you wish to be considered for the position of a Wizard Foundation 'diplomat'?", "wizard", null)
var/mob/dead/observer/selected = popleft(candidates)
var/mob/dead/observer/selected = pick_n_take(candidates)
var/mob/living/carbon/human/new_character = makeBody(selected)
new_character.mind.make_Wizard()
@@ -552,5 +552,5 @@
return 1
/datum/admins/proc/makeRevenant()
new /datum/round_event/ghost_role/revenant
new /datum/round_event/ghost_role/revenant(TRUE, TRUE)
return 1
+5 -3
View File
@@ -31,6 +31,8 @@
if(!cost)
return 0
var/potDiff = max(S.potency - discoveredPlants[S.type], 0)
return round(..() * potDiff)
var/potDiff = (S.potency - discoveredPlants[S.type])
if(potDiff < 1)
return round(S.rarity * S.potency / 10)
else
return round(..() * potDiff)
+30
View File
@@ -179,6 +179,36 @@ You can set verify to TRUE if you want send() to sleep until the client has the
"tgui.js" = 'tgui/assets/tgui.js'
)
/datum/asset/simple/headers
assets = list(
"alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
"alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
"batt_5.gif" = 'icons/program_icons/batt_5.gif',
"batt_20.gif" = 'icons/program_icons/batt_20.gif',
"batt_40.gif" = 'icons/program_icons/batt_40.gif',
"batt_60.gif" = 'icons/program_icons/batt_60.gif',
"batt_80.gif" = 'icons/program_icons/batt_80.gif',
"batt_100.gif" = 'icons/program_icons/batt_100.gif',
"charging.gif" = 'icons/program_icons/charging.gif',
"downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
"downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
"ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
"ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
"power_norm.gif" = 'icons/program_icons/power_norm.gif',
"power_warn.gif" = 'icons/program_icons/power_warn.gif',
"sig_high.gif" = 'icons/program_icons/sig_high.gif',
"sig_low.gif" = 'icons/program_icons/sig_low.gif',
"sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
"sig_none.gif" = 'icons/program_icons/sig_none.gif',
)
/datum/asset/simple/pda
assets = list(
"pda_atmos.png" = 'icons/pda_icons/pda_atmos.png',
+7 -2
View File
@@ -77,7 +77,12 @@
chameleon_blacklist += target.type
var/list/temp_list = typesof(chameleon_type)
for(var/V in temp_list - (chameleon_blacklist))
chameleon_list += V
if(istype(V, /obj/item))
var/obj/item/I = V
if(initial(I.flags) & ABSTRACT)
continue
else
chameleon_list += I
/datum/action/item_action/chameleon/change/proc/select_look(mob/user)
var/list/item_names = list()
@@ -86,7 +91,7 @@
var/obj/item/I = U
item_names += initial(I.name)
var/picked_name
picked_name = input("Select [chameleon_name] to change it to", "Chameleon [chameleon_name]", picked_name) in item_names
picked_name = input("Select [chameleon_name] to change into", "Chameleon [chameleon_name]", picked_name) in item_names
if(!picked_name)
return
for(var/V in chameleon_list)
@@ -494,6 +494,32 @@
armor = list(melee = 45, bullet = 25, laser = 30, energy = 10, bomb = 25, bio = 100, rad = 50)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/security/hos
//Clown
/obj/item/clothing/head/helmet/space/hardsuit/clown
name = "cosmohonk hardsuit helmet"
desc = "A special helmet designed for work in a hazardous, low-humor environment. Has radiation shielding."
icon_state = "hardsuit0-clown"
item_state = "hardsuit0-clown"
armor = list(melee = 30, bullet = 5, laser = 10, energy = 5, bomb = 10, bio = 100, rad = 75)
item_color = "clown"
/obj/item/clothing/suit/space/hardsuit/clown
name = "cosmohonk hardsuit"
desc = "A special suit that protects against hazardous, low humor environments. Has radiation shielding. Only a true clown can wear it."
icon_state = "hardsuit-clown"
item_state = "clown_hardsuit"
armor = list(melee = 30, bullet = 5, laser = 10, energy = 5, bomb = 10, bio = 100, rad = 75)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/clown
pockets = /obj/item/weapon/storage/internal/pocket
/obj/item/clothing/suit/space/hardsuit/clown/mob_can_equip(mob/M, slot)
if(!..() || !ishuman(M))
return FALSE
var/mob/living/carbon/human/H = M
if(H.mind.assigned_role == "Clown")
return TRUE
else
return FALSE
/////////////SHIELDED//////////////////////////////////
+2 -2
View File
@@ -28,8 +28,8 @@
else
temp = new
var/agent_mind = popleft(candidates)
var/scientist_mind = popleft(candidates)
var/agent_mind = pick_n_take(candidates)
var/scientist_mind = pick_n_take(candidates)
var/mob/living/carbon/human/agent = makeBody(agent_mind)
var/mob/living/carbon/human/scientist = makeBody(scientist_mind)
+1 -1
View File
@@ -57,7 +57,7 @@
while(spawncount > 0 && vents.len && candidates.len)
var/obj/vent = pick_n_take(vents)
var/client/C = popleft(candidates)
var/client/C = pick_n_take(candidates)
var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc)
new_xeno.key = C.key
+19 -12
View File
@@ -1,6 +1,6 @@
/datum/round_event_control/blob
name = "Blob"
typepath = /datum/round_event/blob
typepath = /datum/round_event/ghost_role/blob
weight = 5
max_occurrences = 1
@@ -9,22 +9,29 @@
gamemode_blacklist = list("blob") //Just in case a blob survives that long
/datum/round_event/blob
/datum/round_event/ghost_role/blob
announceWhen = 12
endWhen = 120
var/new_rate = 2
/datum/round_event/blob/New(var/strength)
/datum/round_event/ghost_role/blob/New(my_processing = TRUE, set_point_rate)
..()
if(strength)
new_rate = strength
if(set_point_rate)
new_rate = set_point_rate
/datum/round_event/blob/announce()
/datum/round_event/ghost_role/blob/announce()
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/AI/outbreak5.ogg')
/datum/round_event/blob/start()
var/turf/T = pick(blobstart)
if(!T)
return kill()
new/obj/effect/blob/core(T, null, new_rate)
/datum/round_event/ghost_role/blob/spawn_role()
if(!blobstart.len)
return MAP_ERROR
var/list/candidates = get_candidates("blob", null, ROLE_BLOB)
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
var/mob/dead/observer/new_blob = pick(candidates)
var/obj/effect/blob/core/BC = new/obj/effect/blob/core(pick(blobstart), new_blob.client, new_rate)
BC.overmind.blob_points = min(20 + player_list.len, BC.overmind.max_blob_points)
spawned_mobs += BC.overmind
message_admins("[BC.overmind.key] has been made into a blob overmind by an event.")
log_game("[BC.overmind.key] was spawned as a blob overmind by an event.")
return SUCCESSFUL_SPAWN
+1 -1
View File
@@ -24,7 +24,7 @@
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
var/mob/dead/selected_candidate = popleft(candidates)
var/mob/dead/selected_candidate = pick_n_take(candidates)
var/key = selected_candidate.key
var/datum/mind/Mind = create_devil_mind(key)
+1 -1
View File
@@ -13,7 +13,7 @@
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
var/mob/dead/selected = popleft(candidates)
var/mob/dead/selected = pick_n_take(candidates)
var/list/spawn_locs = list()
for(var/obj/effect/landmark/L in landmarks_list)
+5 -2
View File
@@ -64,6 +64,7 @@
/var/const/access_mineral_storeroom = 64
/var/const/access_minisat = 65
/var/const/access_weapons = 66 //Weapon authorization for secbots
/var/const/access_network = 67
//BEGIN CENTCOM ACCESS
/*Should leave plenty of room if we need to add more access levels.
@@ -237,7 +238,7 @@
access_hydroponics, access_library, access_lawyer, access_virology, access_cmo, access_qm, access_surgery,
access_theatre, access_research, access_mining, access_mailsorting, access_weapons,
access_heads_vault, access_mining_station, access_xenobiology, access_ce, access_hop, access_hos, access_RC_announce,
access_keycard_auth, access_tcomsat, access_gateway, access_mineral_storeroom, access_minisat)
access_keycard_auth, access_tcomsat, access_gateway, access_mineral_storeroom, access_minisat, access_network)
/proc/get_all_centcom_access()
return list(access_cent_general, access_cent_thunder, access_cent_specops, access_cent_medical, access_cent_living, access_cent_storage, access_cent_teleporter, access_cent_captain)
@@ -267,7 +268,7 @@
if(3) //medbay
return list(access_medical, access_genetics, access_morgue, access_chemistry, access_virology, access_surgery, access_cmo)
if(4) //research
return list(access_research, access_tox, access_tox_storage, access_genetics, access_robotics, access_xenobiology, access_minisat, access_rd)
return list(access_research, access_tox, access_tox_storage, access_genetics, access_robotics, access_xenobiology, access_minisat, access_rd, access_network)
if(5) //engineering and maintenance
return list(access_construction, access_maint_tunnels, access_engine, access_engine_equip, access_external_airlocks, access_tech_storage, access_atmospherics, access_tcomsat, access_minisat, access_ce)
if(6) //supply
@@ -424,6 +425,8 @@
return "AI Satellite"
if(access_weapons)
return "Weapon Permit"
if(access_network)
return "Network Access"
/proc/get_centcom_access_desc(A)
switch(A)
+1
View File
@@ -14,6 +14,7 @@ Assistant
minimal_access = list() //See /datum/job/assistant/get_access()
outfit = /datum/outfit/job/assistant
/datum/job/assistant/get_access()
if((config.jobs_have_maint_access & ASSISTANTS_HAVE_MAINT_ACCESS) || !config.jobs_have_minimal_access) //Config has assistant maint access set
. = ..()
+1 -1
View File
@@ -99,7 +99,7 @@ Head of Personnel
shoes = /obj/item/clothing/shoes/sneakers/brown
head = /obj/item/clothing/head/hopcap
backpack_contents = list(/obj/item/weapon/storage/box/ids=1,\
/obj/item/weapon/melee/classic_baton/telescopic=1)
/obj/item/weapon/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced = 1)
/datum/outfit/job/hop/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()
+6 -2
View File
@@ -52,6 +52,7 @@ Cargo Technician
belt = /obj/item/device/pda/cargo
ears = /obj/item/device/radio/headset/headset_cargo
uniform = /obj/item/clothing/under/rank/cargotech
backpack_contents = list(/obj/item/modular_computer/tablet/preset/cheap=1)
/*
@@ -86,7 +87,7 @@ Shaft Miner
backpack_contents = list(
/obj/item/weapon/storage/bag/ore=1,\
/obj/item/weapon/kitchen/knife/combat/survival=1,\
/obj/item/weapon/mining_voucher=1)
/obj/item/weapon/mining_voucher=1,/obj/item/modular_computer/tablet/preset/cheap=1)
backpack = /obj/item/weapon/storage/backpack/explorer
satchel = /obj/item/weapon/storage/backpack/satchel/explorer
@@ -121,7 +122,7 @@ Bartender
ears = /obj/item/device/radio/headset/headset_srv
uniform = /obj/item/clothing/under/rank/bartender
suit = /obj/item/clothing/suit/armor/vest
backpack_contents = list(/obj/item/weapon/storage/box/beanbag=1)
backpack_contents = list(/obj/item/weapon/storage/box/beanbag=1,/obj/item/modular_computer/tablet/preset/cheap=1)
shoes = /obj/item/clothing/shoes/laceup
/*
@@ -152,6 +153,7 @@ Cook
uniform = /obj/item/clothing/under/rank/chef
suit = /obj/item/clothing/suit/toggle/chef
head = /obj/item/clothing/head/chefhat
backpack_contents = list(/obj/item/modular_computer/tablet/preset/cheap=1)
/datum/outfit/job/cook/pre_equip(mob/living/carbon/human/H)
..()
@@ -200,6 +202,7 @@ Botanist
backpack = /obj/item/weapon/storage/backpack/botany
satchel = /obj/item/weapon/storage/backpack/satchel/hyd
backpack_contents = list(/obj/item/modular_computer/tablet/preset/cheap=1)
/*
@@ -228,3 +231,4 @@ Janitor
belt = /obj/item/device/pda/janitor
ears = /obj/item/device/radio/headset/headset_srv
uniform = /obj/item/clothing/under/rank/janitor
backpack_contents = list(/obj/item/modular_computer/tablet/preset/cheap=1)
+3 -3
View File
@@ -20,12 +20,12 @@ Research Director
access_tox_storage, access_teleporter, access_sec_doors,
access_research, access_robotics, access_xenobiology, access_ai_upload,
access_RC_announce, access_keycard_auth, access_gateway, access_mineral_storeroom,
access_tech_storage, access_minisat, access_maint_tunnels)
access_tech_storage, access_minisat, access_maint_tunnels, access_network)
minimal_access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue,
access_tox_storage, access_teleporter, access_sec_doors,
access_research, access_robotics, access_xenobiology, access_ai_upload,
access_RC_announce, access_keycard_auth, access_gateway, access_mineral_storeroom,
access_tech_storage, access_minisat, access_maint_tunnels)
access_tech_storage, access_minisat, access_maint_tunnels, access_network)
/datum/outfit/job/rd
name = "Research Director"
@@ -38,7 +38,7 @@ Research Director
suit = /obj/item/clothing/suit/toggle/labcoat
l_hand = /obj/item/weapon/clipboard
l_pocket = /obj/item/device/laser_pointer
backpack_contents = list(/obj/item/weapon/melee/classic_baton/telescopic=1)
backpack_contents = list(/obj/item/weapon/melee/classic_baton/telescopic=1,/obj/item/modular_computer/tablet/preset/advanced=1)
backpack = /obj/item/weapon/storage/backpack/science
satchel = /obj/item/weapon/storage/backpack/satchel/tox
+1 -1
View File
@@ -158,7 +158,7 @@ Detective
backpack_contents = list(/obj/item/weapon/storage/box/evidence=1,\
/obj/item/device/detective_scanner=1,\
/obj/item/weapon/melee/classic_baton=1,\
/obj/item/weapon/reagent_containers/food/drinks/flask/det)
/obj/item/weapon/reagent_containers/food/drinks/flask/det=1)
mask = /obj/item/clothing/mask/cigarette
/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+108 -1
View File
@@ -459,4 +459,111 @@
C.preserved()
user << "<span class='notice'>You inject the [M] with the stabilizer. It will no longer go inert.</span>"
qdel(src)
qdel(src)
/*********************Mining Hammer****************/
/obj/item/weapon/twohanded/required/mining_hammer
icon = 'icons/obj/mining.dmi'
icon_state = "mining_hammer1"
item_state = "mining_hammer1"
name = "proto-kinetic crusher"
desc = "An early design of the proto-kinetic accelerator, it is little more than an combination of various mining tools cobbled together, forming a high-tech club.\
While it is an effective mining tool, it did little to aid any but the most skilled and/or suicidal miners against local fauna. \
\n<span class='info'>Mark a mob with the destabilizing force, then hit them in melee to activate it for extra damage. Extra damage if backstabbed in this fashion. \
This weapon is only particularly effective against large creatures.</span>"
force = 20 //As much as a bone spear, but this is significantly more annoying to carry around due to requiring the use of both hands at all times
w_class = 4
slot_flags = SLOT_BACK
force_unwielded = 20 //It's never not wielded so these are the same
force_wielded = 20
throwforce = 5
throw_speed = 4
luminosity = 4
armour_penetration = 10
materials = list(MAT_METAL=1150, MAT_GLASS=2075)
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("smashes", "crushes", "cleaves", "chops", "pulps")
sharpness = IS_SHARP
var/charged = 1
var/charge_time = 16
var/atom/mark = null
var/marked_image = null
/obj/item/projectile/destabilizer
name = "destabilizing force"
icon_state = "pulse1"
damage = 0 //We're just here to mark people. This is still a melee weapon.
damage_type = BRUTE
flag = "bomb"
range = 6
var/obj/item/weapon/twohanded/required/mining_hammer/hammer_synced = null
/obj/item/projectile/destabilizer/on_hit(atom/target, blocked = 0, hit_zone)
if(hammer_synced)
if(hammer_synced.mark == target)
return ..()
if(isliving(target))
if(hammer_synced.mark && hammer_synced.marked_image)
hammer_synced.mark.underlays -= hammer_synced.marked_image
hammer_synced.marked_image = null
var/mob/living/L = target
if(L.mob_size >= MOB_SIZE_LARGE)
hammer_synced.mark = L
var/image/I = image('icons/effects/effects.dmi', loc = L, icon_state = "shield2",pixel_y = (-L.pixel_y),pixel_x = (-L.pixel_x))
L.underlays += I
hammer_synced.marked_image = I
var/target_turf = get_turf(target)
if(istype(target_turf, /turf/closed/mineral))
var/turf/closed/mineral/M = target_turf
PoolOrNew(/obj/effect/overlay/temp/kinetic_blast, M)
M.gets_drilled(firer)
..()
/obj/item/weapon/twohanded/required/mining_hammer/afterattack(atom/target, mob/user, proximity_flag)
if(!proximity_flag && charged)//Mark a target, or mine a tile.
var/turf/proj_turf = get_turf(src)
if(!istype(proj_turf, /turf))
return
var/datum/gas_mixture/environment = proj_turf.return_air()
var/pressure = environment.return_pressure()
if(pressure > 50)
playsound(user, 'sound/weapons/empty.ogg', 100, 1)
return
var/obj/item/projectile/destabilizer/D = new /obj/item/projectile/destabilizer(user.loc)
D.preparePixelProjectile(target,get_turf(target), user)
D.hammer_synced = src
playsound(user, 'sound/weapons/plasma_cutter.ogg', 100, 1)
D.fire()
charged = 0
icon_state = "mining_hammer1_uncharged"
addtimer(src, "Recharge", charge_time)
return
if(proximity_flag && target == mark && isliving(target))
var/mob/living/L = target
PoolOrNew(/obj/effect/overlay/temp/kinetic_blast, get_turf(L))
mark = 0
if(L.mob_size >= MOB_SIZE_LARGE)
L.underlays -= marked_image
qdel(marked_image)
marked_image = null
var/backstab = check_target_facings(user, L)
var/def_check = L.getarmor(type = "bomb")
if(backstab == FACING_INIT_FACING_TARGET_TARGET_FACING_PERPENDICULAR || backstab == FACING_SAME_DIR)
L.apply_damage(80, BRUTE, blocked = def_check)
playsound(user, 'sound/weapons/Kenetic_accel.ogg', 100, 1) //Seriously who spelled it wrong
else
L.apply_damage(50, BRUTE, blocked = def_check)
/obj/item/weapon/twohanded/required/mining_hammer/proc/Recharge()
if(!charged)
charged = 1
icon_state = "mining_hammer1"
playsound(src.loc, 'sound/weapons/kenetic_reload.ogg', 60, 1)
/obj/item/weapon/twohanded/required/mining_hammer/pickup(mob/user)
..()
user.AddLuminosity(luminosity)
/obj/item/weapon/twohanded/required/mining_hammer/dropped(mob/user)
..()
user.AddLuminosity(-luminosity)
+6 -2
View File
@@ -27,6 +27,7 @@
new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/weapon/storage/firstaid/brute, 600),
new /datum/data/mining_equipment("Tracking Implant Kit",/obj/item/weapon/storage/box/minertracker, 600),
new /datum/data/mining_equipment("Jaunter", /obj/item/device/wormhole_jaunter, 750),
new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/weapon/twohanded/required/mining_hammer, 750),
new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/weapon/gun/energy/kinetic_accelerator, 750),
new /datum/data/mining_equipment("Resonator", /obj/item/weapon/resonator, 800),
new /datum/data/mining_equipment("Medivac Balloon", /obj/item/weapon/extraction_pack/medivac, 800),
@@ -38,7 +39,6 @@
new /datum/data/mining_equipment("Mining Hardsuit", /obj/item/clothing/suit/space/hardsuit/mining, 2000),
new /datum/data/mining_equipment("Diamond Pickaxe", /obj/item/weapon/pickaxe/diamond, 2000),
new /datum/data/mining_equipment("Super Resonator", /obj/item/weapon/resonator/upgraded, 2500),
new /datum/data/mining_equipment("Super Accelerator", /obj/item/weapon/gun/energy/kinetic_accelerator/super, 3000),
new /datum/data/mining_equipment("Point Transfer Card", /obj/item/weapon/card/mining_point_card, 500),
new /datum/data/mining_equipment("Mining Drone", /mob/living/simple_animal/hostile/mining_drone, 800),
new /datum/data/mining_equipment("Drone Melee Upgrade", /obj/item/device/mine_bot_ugprade, 400),
@@ -159,7 +159,7 @@
return ..()
/obj/machinery/mineral/equipment_vendor/proc/RedeemVoucher(obj/item/weapon/mining_voucher/voucher, mob/redeemer)
var/items = list("Survival Capsule and Explorer's Webbing", "Resonator and Advanced Scanner", "Mining Drone", "Medivac Kit", "Extraction Kit")
var/items = list("Survival Capsule and Explorer's Webbing", "Resonator and Advanced Scanner", "Mining Drone", "Medivac Kit", "Extraction Kit", "Crusher Kit")
var/selection = input(redeemer, "Pick your equipment", "Mining Voucher Redemption") as null|anything in items
if(!selection || !Adjacent(redeemer) || qdeleted(voucher) || voucher.loc != redeemer)
@@ -182,6 +182,10 @@
new /obj/item/stack/sheet/metal/five(loc)
new /obj/item/weapon/extraction_pack(loc)
new /obj/item/fulton_core(loc)
if("Crusher Kit")
new /obj/item/weapon/twohanded/required/mining_hammer(loc)
new /obj/item/weapon/storage/belt/mining/alt(loc)
new /obj/item/weapon/extinguisher/mini(loc)
feedback_add_details("mining_voucher_redeemed", selection)
qdel(voucher)
+1 -1
View File
@@ -270,7 +270,7 @@
/turf/open/floor/plating/asteroid/airless/cave/volcanic
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/goldgrub = 10, /mob/living/simple_animal/hostile/asteroid/goliath/beast = 50, /mob/living/simple_animal/hostile/asteroid/basilisk/watcher = 40, /mob/living/simple_animal/hostile/asteroid/hivelord/legion = 30,
/mob/living/simple_animal/hostile/spawner/lavaland = 2, /mob/living/simple_animal/hostile/spawner/lavaland/goliath = 3, /mob/living/simple_animal/hostile/spawner/lavaland/legion = 3, \
/mob/living/simple_animal/hostile/megafauna/dragon = 2, /mob/living/simple_animal/hostile/megafauna/bubblegum = 2, /mob/living/simple_animal/hostile/megafauna/colossus = 2)
/mob/living/simple_animal/hostile/megafauna/dragon = 2, /mob/living/simple_animal/hostile/megafauna/bubblegum = 2)
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = "o2=14;n2=23;TEMP=300"
+8 -5
View File
@@ -297,11 +297,14 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
..()
if(statpanel("Status"))
stat(null, "Station Time: [worldtime2text()]")
if(ticker)
if(ticker.mode)
for(var/datum/gang/G in ticker.mode.gangs)
if(G.is_dominating)
stat(null, "[G.name] Gang Takeover: [max(G.domination_time_remaining(), 0)]")
if(ticker && ticker.mode)
for(var/datum/gang/G in ticker.mode.gangs)
if(G.is_dominating)
stat(null, "[G.name] Gang Takeover: [max(G.domination_time_remaining(), 0)]")
if(istype(ticker.mode, /datum/game_mode/blob))
var/datum/game_mode/blob/B = ticker.mode
if(B.message_sent)
stat(null, "Blobs to Blob Win: [blobs_legit.len]/[B.blobwincount]")
/mob/dead/observer/verb/reenter_corpse()
set category = "Ghost"
@@ -203,12 +203,19 @@
for(var/obj/item/I in BP.embedded_objects)
msg += "<B>[t_He] [t_has] \a \icon[I] [I] embedded in [t_his] [BP.name]!</B>\n"
//stores how many left limbs are missing
var/l_limbs_missing = 0
for(var/t in missing)
if(t=="head")
msg += "<span class='deadsay'><B>[capitalize(t_his)] [parse_zone(t)] is missing!</B><span class='warning'>\n"
continue
if(t == "l_arm" || t == "l_leg")
l_limbs_missing++
msg += "<B>[capitalize(t_his)] [parse_zone(t)] is missing!</B>\n"
if(l_limbs_missing >= 2)
msg += "[t_He] looks all right now.\n"
if(temp)
if(temp < 30)
msg += "[t_He] [t_has] minor bruising.\n"
@@ -345,7 +352,6 @@
msg += "<a href='?src=\ref[src];hud=s;add_crime=1'>\[Add crime\]</a> "
msg += "<a href='?src=\ref[src];hud=s;view_comment=1'>\[View comment log\]</a> "
msg += "<a href='?src=\ref[src];hud=s;add_comment=1'>\[Add comment\]</a>\n"
msg += "*---------*</span>"
user << msg
+9 -5
View File
@@ -953,12 +953,16 @@ Sorry Giacom. Please don't be mad :(
/mob/living/Stat()
..()
if(statpanel("Status"))
if(ticker)
if(ticker.mode)
for(var/datum/gang/G in ticker.mode.gangs)
if(G.is_dominating)
stat(null, "[G.name] Gang Takeover: [max(G.domination_time_remaining(), 0)]")
if(ticker && ticker.mode)
for(var/datum/gang/G in ticker.mode.gangs)
if(G.is_dominating)
stat(null, "[G.name] Gang Takeover: [max(G.domination_time_remaining(), 0)]")
if(istype(ticker.mode, /datum/game_mode/blob))
var/datum/game_mode/blob/B = ticker.mode
if(B.message_sent)
stat(null, "Blobs to Blob Win: [blobs_legit.len]/[B.blobwincount]")
/mob/living/cancel_camera()
..()
@@ -10,6 +10,7 @@
healable = 0
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 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)
maxbodytemp = INFINITY
minbodytemp = 0
has_unlimited_silicon_privilege = 1
sentience_type = SENTIENCE_ARTIFICIAL
@@ -313,6 +313,7 @@ Difficulty: Very Hard
return
current = src
ReadMemory()
. = ..()
/obj/machinery/smartfridge/black_box/process()
..()
@@ -51,6 +51,7 @@ Difficulty: Medium
aggro_vision_range = 18
idle_vision_range = 13
appearance_flags = 0
mouse_opacity = 1
/mob/living/simple_animal/hostile/megafauna/legion/New()
..()
@@ -22,6 +22,7 @@
var/elimination = 0
anchored = TRUE
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
mouse_opacity = 2 // Easier to click on in melee, they're giant targets anyway
/mob/living/simple_animal/hostile/megafauna/death(gibbed)
if(health > 0)
@@ -15,6 +15,7 @@
var/icon_aggro = null // for swapping to when we get aggressive
see_in_dark = 8
see_invisible = SEE_INVISIBLE_MINIMUM
mob_size = MOB_SIZE_LARGE
/mob/living/simple_animal/hostile/asteroid/Aggro()
..()
@@ -452,7 +453,6 @@
aggro_vision_range = 9
idle_vision_range = 5
anchored = 1 //Stays anchored until death as to be unpullable
mob_size = MOB_SIZE_LARGE
var/pre_attack = 0
var/pre_attack_icon = "Goliath_preattack"
loot = list(/obj/item/stack/sheet/animalhide/goliath_hide)
+2 -1
View File
@@ -2,6 +2,7 @@
mob_list -= src
dead_mob_list -= src
living_mob_list -= src
all_clockwork_mobs -= src
if(observers && observers.len)
for(var/M in observers)
var/mob/dead/observe = M
@@ -593,7 +594,7 @@ var/next_mob_id = 0
if(statpanel("Status"))
stat(null, "Map: [MAP_NAME]")
if (nextmap && istype(nextmap))
if(nextmap && istype(nextmap))
stat(null, "Next Map: [nextmap.friendlyname]")
stat(null, "Server Time: [time2text(world.realtime, "YYYY-MM-DD hh:mm")]")
if(SSshuttle.emergency)
+22 -2
View File
@@ -12,7 +12,26 @@
return 1
return (!mover.density || !density || lying)
//there are bugs with byond's default versions of these verbs
/client/verb/moveup()
set name = ".moveup"
set instant = 1
Move(get_step(mob, NORTH), NORTH)
/client/verb/movedown()
set name = ".movedown"
set instant = 1
Move(get_step(mob, SOUTH), SOUTH)
/client/verb/moveright()
set name = ".moveright"
set instant = 1
Move(get_step(mob, EAST), EAST)
/client/verb/moveleft()
set name = ".moveleft"
set instant = 1
Move(get_step(mob, WEST), WEST)
/client/Northeast()
swap_hand()
@@ -90,14 +109,15 @@
/client/Move(n, direct)
if(world.time < move_delay)
return 0
move_delay = world.time+world.tick_lag //this is here because Move() can now be called mutiple times per tick
if(!mob || !mob.loc)
return 0
if(mob.notransform)
return 0 //This is sota the goto stop mobs from moving var
if(mob.control_object)
return Move_object(direct)
if(world.time < move_delay)
return 0
if(!isliving(mob))
return mob.Move(n,direct)
if(mob.stat == DEAD)
+2 -2
View File
@@ -422,8 +422,8 @@
. = new_slime
qdel(src)
/mob/proc/become_overmind(mode_made = 0)
var/mob/camera/blob/B = new /mob/camera/blob(loc, 0, mode_made)
/mob/proc/become_overmind(mode_made, starting_points = 60)
var/mob/camera/blob/B = new /mob/camera/blob(loc, 0, mode_made, starting_points)
if(mind)
mind.transfer_to(B)
else
@@ -0,0 +1,65 @@
var/global/static/ntnrc_uid = 0
/datum/ntnet_conversation/
var/id = null
var/title = "Untitled Conversation"
var/datum/computer_file/program/chatclient/operator // "Administrator" of this channel. Creator starts as channel's operator,
var/list/messages = list()
var/list/clients = list()
var/password
/datum/ntnet_conversation/New()
id = ntnrc_uid
ntnrc_uid++
if(ntnet_global)
ntnet_global.chat_channels.Add(src)
..()
/datum/ntnet_conversation/proc/add_message(message, username)
message = "[worldtime2text()] [username]: [message]"
messages.Add(message)
trim_message_list()
/datum/ntnet_conversation/proc/add_status_message(message)
messages.Add("[worldtime2text()] -!- [message]")
trim_message_list()
/datum/ntnet_conversation/proc/trim_message_list()
if(messages.len <= 50)
return
messages = messages.Copy(messages.len-50 ,0)
/datum/ntnet_conversation/proc/add_client(datum/computer_file/program/chatclient/C)
if(!istype(C))
return
clients.Add(C)
add_status_message("[C.username] has joined the channel.")
// No operator, so we assume the channel was empty. Assign this user as operator.
if(!operator)
changeop(C)
/datum/ntnet_conversation/proc/remove_client(datum/computer_file/program/chatclient/C)
if(!istype(C) || !(C in clients))
return
clients.Remove(C)
add_status_message("[C.username] has left the channel.")
// Channel operator left, pick new operator
if(C == operator)
operator = null
if(clients.len)
var/datum/computer_file/program/chatclient/newop = pick(clients)
changeop(newop)
/datum/ntnet_conversation/proc/changeop(datum/computer_file/program/chatclient/newop)
if(istype(newop))
operator = newop
add_status_message("Channel operator status transferred to [newop.username].")
/datum/ntnet_conversation/proc/change_title(newtitle, datum/computer_file/program/chatclient/client)
if(operator != client)
return 0 // Not Authorised
add_status_message("[client.username] has changed channel title from [title] to [newtitle]")
title = newtitle
@@ -0,0 +1,145 @@
var/global/datum/ntnet/ntnet_global = new()
// This is the NTNet datum. There can be only one NTNet datum in game at once. Modular computers read data from this.
/datum/ntnet/
var/list/relays = list()
var/list/logs = list()
var/list/available_station_software = list()
var/list/available_antag_software = list()
var/list/chat_channels = list()
var/list/fileservers = list()
// Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly.
// High values make displaying logs much laggier.
var/setting_maxlogcount = 100
// These only affect wireless. LAN (consoles) are unaffected since it would be possible to create scenario where someone turns off NTNet, and is unable to turn it back on since it refuses connections
var/setting_softwaredownload = 1
var/setting_peertopeer = 1
var/setting_communication = 1
var/setting_systemcontrol = 1
var/setting_disabled = 0 // Setting to 1 will disable all wireless, independently on relays status.
var/intrusion_detection_enabled = 1 // Whether the IDS warning system is enabled
var/intrusion_detection_alarm = 0 // Set when there is an IDS warning due to malicious (antag) software.
// If new NTNet datum is spawned, it replaces the old one.
/datum/ntnet/New()
if(ntnet_global && (ntnet_global != src))
ntnet_global = src // There can be only one.
for(var/obj/machinery/ntnet_relay/R in machines)
relays.Add(R)
R.NTNet = src
build_software_lists()
add_log("NTNet logging system activated.")
// Simplified logging: Adds a log. log_string is mandatory parameter, source is optional.
/datum/ntnet/proc/add_log(log_string, obj/item/weapon/computer_hardware/network_card/source = null)
var/log_text = "[worldtime2text()] - "
if(source)
log_text += "[source.get_network_tag()] - "
else
log_text += "*SYSTEM* - "
log_text += log_string
logs.Add(log_text)
// We have too many logs, remove the oldest entries until we get into the limit
if(logs.len > setting_maxlogcount)
logs = logs.Copy(logs.len-setting_maxlogcount,0)
// Checks whether NTNet operates. If parameter is passed checks whether specific function is enabled.
/datum/ntnet/proc/check_function(specific_action = 0)
if(!relays || !relays.len) // No relays found. NTNet is down
return 0
var/operating = 0
// Check all relays. If we have at least one working relay, network is up.
for(var/M in relays)
var/obj/machinery/ntnet_relay/R = M
if(R.is_operational())
operating = 1
break
if(setting_disabled)
return 0
switch(specific_action)
if(NTNET_SOFTWAREDOWNLOAD)
return (operating && setting_softwaredownload)
if(NTNET_PEERTOPEER)
return (operating && setting_peertopeer)
if(NTNET_COMMUNICATION)
return (operating && setting_communication)
if(NTNET_SYSTEMCONTROL)
return (operating && setting_systemcontrol)
return operating
// Builds lists that contain downloadable software.
/datum/ntnet/proc/build_software_lists()
available_station_software = list()
available_antag_software = list()
for(var/F in typesof(/datum/computer_file/program))
var/datum/computer_file/program/prog = new F
// Invalid type (shouldn't be possible but just in case), invalid filetype (not executable program) or invalid filename (unset program)
if(!prog || prog.filename == "UnknownProgram" || prog.filetype != "PRG")
continue
// Check whether the program should be available for station/antag download, if yes, add it to lists.
if(prog.available_on_ntnet)
available_station_software.Add(prog)
if(prog.available_on_syndinet)
available_antag_software.Add(prog)
// Attempts to find a downloadable file according to filename var
/datum/ntnet/proc/find_ntnet_file_by_name(filename)
for(var/N in available_station_software)
var/datum/computer_file/program/P = N
if(filename == P.filename)
return P
for(var/N in available_antag_software)
var/datum/computer_file/program/P = N
if(filename == P.filename)
return P
// Resets the IDS alarm
/datum/ntnet/proc/resetIDS()
intrusion_detection_alarm = 0
/datum/ntnet/proc/toggleIDS()
resetIDS()
intrusion_detection_enabled = !intrusion_detection_enabled
// Removes all logs
/datum/ntnet/proc/purge_logs()
logs = list()
add_log("-!- LOGS DELETED BY SYSTEM OPERATOR -!-")
// Updates maximal amount of stored logs. Use this instead of setting the number, it performs required checks.
/datum/ntnet/proc/update_max_log_count(lognumber)
if(!lognumber)
return 0
// Trim the value if necessary
lognumber = max(MIN_NTNET_LOGS, min(lognumber, MAX_NTNET_LOGS))
setting_maxlogcount = lognumber
add_log("Configuration Updated. Now keeping [setting_maxlogcount] logs in system memory.")
/datum/ntnet/proc/toggle_function(function)
if(!function)
return
function = text2num(function)
switch(function)
if(NTNET_SOFTWAREDOWNLOAD)
setting_softwaredownload = !setting_softwaredownload
add_log("Configuration Updated. Wireless network firewall now [setting_softwaredownload ? "allows" : "disallows"] connection to software repositories.")
if(NTNET_PEERTOPEER)
setting_peertopeer = !setting_peertopeer
add_log("Configuration Updated. Wireless network firewall now [setting_peertopeer ? "allows" : "disallows"] peer to peer network traffic.")
if(NTNET_COMMUNICATION)
setting_communication = !setting_communication
add_log("Configuration Updated. Wireless network firewall now [setting_communication ? "allows" : "disallows"] instant messaging and similar communication services.")
if(NTNET_SYSTEMCONTROL)
setting_systemcontrol = !setting_systemcontrol
add_log("Configuration Updated. Wireless network firewall now [setting_systemcontrol ? "allows" : "disallows"] remote control of station's systems.")
@@ -0,0 +1,127 @@
// Relays don't handle any actual communication. Global NTNet datum does that, relays only tell the datum if it should or shouldn't work.
/obj/machinery/ntnet_relay
name = "NTNet Quantum Relay"
desc = "A very complex router and transmitter capable of connecting electronic devices together. Looks fragile."
use_power = 2
active_power_usage = 20000 //20kW, apropriate for machine that keeps massive cross-Zlevel wireless network operational.
idle_power_usage = 100
icon = 'icons/obj/machines/telecomms.dmi'
icon_state = "bus"
anchored = 1
density = 1
var/datum/ntnet/NTNet = null // This is mostly for backwards reference and to allow varedit modifications from ingame.
var/enabled = 1 // Set to 0 if the relay was turned off
var/dos_failure = 0 // Set to 1 if the relay failed due to (D)DoS attack
var/list/dos_sources = list() // Backwards reference for qdel() stuff
// Denial of Service attack variables
var/dos_overload = 0 // Amount of DoS "packets" in this relay's buffer
var/dos_capacity = 500 // Amount of DoS "packets" in buffer required to crash the relay
var/dos_dissipate = 1 // Amount of DoS "packets" dissipated over time.
// TODO: Implement more logic here. For now it's only a placeholder.
/obj/machinery/ntnet_relay/is_operational()
if(stat & (BROKEN | NOPOWER | EMPED))
return 0
if(dos_failure)
return 0
if(!enabled)
return 0
return 1
/obj/machinery/ntnet_relay/update_icon()
if(is_operational())
icon_state = "bus"
else
icon_state = "bus_off"
/obj/machinery/ntnet_relay/process()
if(is_operational())
use_power = 2
else
use_power = 1
if(dos_overload)
dos_overload = max(0, dos_overload - dos_dissipate)
// If DoS traffic exceeded capacity, crash.
if((dos_overload > dos_capacity) && !dos_failure)
dos_failure = 1
update_icon()
ntnet_global.add_log("Quantum relay switched from normal operation mode to overload recovery mode.")
// If the DoS buffer reaches 0 again, restart.
if((dos_overload == 0) && dos_failure)
dos_failure = 0
update_icon()
ntnet_global.add_log("Quantum relay switched from overload recovery mode to normal operation mode.")
..()
/obj/machinery/ntnet_relay/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "ntnet_relay", "NTNet Quantum Relay", 500, 300, master_ui, state)
ui.open()
/obj/machinery/ntnet_relay/ui_data(mob/user)
var/list/data = list()
data["enabled"] = enabled
data["dos_capacity"] = dos_capacity
data["dos_overload"] = dos_overload
data["dos_crashed"] = dos_failure
return data
/obj/machinery/ntnet_relay/ui_act(action, params)
if(..())
return
switch(action)
if("restart")
dos_overload = 0
dos_failure = 0
update_icon()
ntnet_global.add_log("Quantum relay manually restarted from overload recovery mode to normal operation mode.")
if("toggle")
enabled = !enabled
ntnet_global.add_log("Quantum relay manually [enabled ? "enabled" : "disabled"].")
update_icon()
/obj/machinery/ntnet_relay/attack_hand(mob/living/user)
ui_interact(user)
/obj/machinery/ntnet_relay/New()
uid = gl_uid
gl_uid++
component_parts = list()
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/ntnet_relay(null)
B.apply_default_parts(src)
if(ntnet_global)
ntnet_global.relays.Add(src)
NTNet = ntnet_global
ntnet_global.add_log("New quantum relay activated. Current amount of linked relays: [NTNet.relays.len]")
..()
/obj/machinery/ntnet_relay/Destroy()
if(ntnet_global)
ntnet_global.relays.Remove(src)
ntnet_global.add_log("Quantum relay connection severed. Current amount of linked relays: [NTNet.relays.len]")
NTNet = null
for(var/datum/computer_file/program/ntnet_dos/D in dos_sources)
D.target = null
D.error = "Connection to quantum relay severed"
..()
/obj/item/weapon/circuitboard/machine/ntnet_relay
name = "circuit board (NTNet Relay)"
build_path = /obj/machinery/ntnet_relay
origin_tech = "programming=3;bluespace=3;magnets=2"
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/weapon/stock_parts/subspace/filter = 1)
@@ -0,0 +1,704 @@
// This is the base type that does all the hardware stuff.
// Other types expand it - tablets use a direct subtypes, and
// consoles and laptops use "procssor" item that is held inside machinery piece
/obj/item/modular_computer
name = "Modular Microcomputer"
desc = "A small portable microcomputer."
var/enabled = 0 // Whether the computer is turned on.
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
var/hardware_flag = 0 // A flag that describes this device type
var/last_power_usage = 0
var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged
var/last_world_time = "00:00"
var/list/last_header_icons
var/computer_emagged = 0 // Whether the computer is emagged.
var/base_active_power_usage = 50 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too.
var/base_idle_power_usage = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops)
// Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..)
// must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently
// If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example.
icon = 'icons/obj/computer.dmi'
icon_state = "laptop-open"
var/icon_state_unpowered = null // Icon state when the computer is turned off
var/icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen.
var/max_hardware_size = 0 // Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed.
var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer.
// Damage of the chassis. If the chassis takes too much damage it will break apart.
var/damage = 0 // Current damage level
var/broken_damage = 50 // Damage level at which the computer ceases to operate
var/max_damage = 100 // Damage level at which the computer breaks apart.
// Important hardware (must be installed for computer to work)
var/obj/item/weapon/computer_hardware/processor_unit/processor_unit // CPU. Without it the computer won't run. Better CPUs can run more programs at once.
var/obj/item/weapon/computer_hardware/network_card/network_card // Network Card component of this computer. Allows connection to NTNet
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive // Hard Drive component of this computer. Stores programs and files.
var/obj/item/weapon/computer_hardware/battery_module/battery_module // An internal power source for this computer. Can be recharged.
// Optional hardware (improves functionality, but is not critical for computer to work)
var/obj/item/weapon/computer_hardware/card_slot/card_slot // ID Card slot component of this computer. Mostly for HoP modification console that needs ID slot for modification.
var/obj/item/weapon/computer_hardware/card_slot/card_slot2 // second slot. popular demand requested the hop need to insert 2 ids.
var/obj/item/weapon/computer_hardware/nano_printer/nano_printer // Nano Printer component of this computer, for your everyday paperwork needs.
var/obj/item/weapon/computer_hardware/hard_drive/portable/portable_drive // Portable data storage
var/list/idle_threads = list() // Idle programs on background. They still receive process calls but can't be interacted with.
var/obj/physical = null
// Eject ID card from computer, if it has ID slot with card inside.
/obj/item/modular_computer/verb/eject_id()
set name = "Eject ID"
set category = "Object"
set src in view(1)
if(usr.incapacitated() || !istype(usr, /mob/living))
usr << "<span class='warning'>You can't do that.</span>"
return
if(!Adjacent(usr))
usr << "<span class='warning'>You can't reach it.</span>"
return
proc_eject_id(usr)
// Eject ID card from computer, if it has ID slot with card inside.
/obj/item/modular_computer/verb/eject_usb()
set name = "Eject Portable Device"
set category = "Object"
set src in view(1)
if(usr.incapacitated() || !istype(usr, /mob/living))
usr << "<span class='warning'>You can't do that.</span>"
return
if(!Adjacent(usr))
usr << "<span class='warning'>You can't reach it.</span>"
return
proc_eject_usb(usr)
/obj/item/modular_computer/proc/proc_eject_id(mob/user, slot)
if(!user)
user = usr
if(!card_slot)
user << "\The [src] does not have an ID card slot"
return
if(!card_slot.stored_card && !card_slot.stored_card2)
user << "There is no card in \the [src]"
return
if(active_program)
active_program.event_idremoved(0, slot)
for(var/I in idle_threads)
var/datum/computer_file/program/P = I
P.event_idremoved(1, slot)
if(card_slot.stored_card && (!slot || slot == 1))
card_slot.stored_card.forceMove(get_turf(src))
card_slot.stored_card = null
if(card_slot.stored_card2 && (!slot || slot == 2))
card_slot.stored_card2.forceMove(get_turf(src))
card_slot.stored_card2 = null
user << "You remove the card[card_slot.stored_card && card_slot.stored_card2 && !slot ? "s" : ""] from \the [src]"
/obj/item/modular_computer/proc/proc_eject_usb(mob/user)
if(!user)
user = usr
if(!portable_drive)
user << "There is no portable device connected to \the [src]."
return
uninstall_component(user, portable_drive)
/obj/item/modular_computer/attack_ghost(mob/dead/observer/user)
if(enabled)
ui_interact(user)
else if(check_rights_for(user.client, R_ADMIN))
var/response = alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", "Yes", "No")
if(response == "Yes")
turn_on(user)
/obj/item/modular_computer/emag_act(mob/user)
if(computer_emagged)
user << "\The [src] was already emagged."
return 0
else
computer_emagged = 1
user << "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message."
return 1
/obj/item/modular_computer/examine(mob/user)
..()
if(damage > broken_damage)
user << "<span class='danger'>It is heavily damaged!</span>"
else if(damage)
user << "It is damaged."
/obj/item/modular_computer/New()
START_PROCESSING(SSmachine, src)
update_icon()
if(!physical)
physical = src
..()
/obj/item/modular_computer/Destroy()
kill_program(1)
STOP_PROCESSING(SSmachine, src)
for(var/H in get_all_components())
var/obj/item/weapon/computer_hardware/CH = H
uninstall_component(null, CH)
qdel(CH)
return ..()
/obj/item/modular_computer/update_icon()
icon_state = icon_state_unpowered
cut_overlays()
if(!enabled)
return
if(active_program)
add_overlay(active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu)
else
add_overlay(icon_state_menu)
// Used by child types if they have other power source than battery
/obj/item/modular_computer/proc/check_power_override()
return 0
// Operates NanoUI
/obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
if(!screen_on || !enabled)
if(ui)
ui.close()
return 0
if((!battery_module || !battery_module.battery.charge) && !check_power_override())
if(ui)
ui.close()
return 0
// If we have an active program switch to it now.
if(active_program)
if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now.
ui.close()
active_program.ui_interact(user)
return
// We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it.
// This screen simply lists available programs and user may select them.
if(!hard_drive || !hard_drive.stored_files || !hard_drive.stored_files.len)
physical.visible_message("\The [src] beeps three times, it's screen displaying \"DISK ERROR\" warning.")
return // No HDD, No HDD files list or no stored files. Something is very broken.
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "computer_main", "NTOS Main menu", 400, 500, master_ui, state)
ui.open()
ui.set_autoupdate(state = 1)
/obj/item/modular_computer/ui_data(mob/user)
var/list/data = get_header_data()
data["programs"] = list()
for(var/datum/computer_file/program/P in hard_drive.stored_files)
var/running = 0
if(P in idle_threads)
running = 1
data["programs"] += list(list("name" = P.filename, "desc" = P.filedesc, "running" = running))
return data
// On-click handling. Turns on the computer if it's off and opens the GUI.
/obj/item/modular_computer/attack_self(mob/user)
if(enabled)
ui_interact(user)
else
turn_on(user)
/obj/item/modular_computer/proc/break_apart()
physical.visible_message("\The [src] breaks apart!")
var/turf/newloc = get_turf(src)
new /obj/item/stack/sheet/metal(newloc, round(steel_sheet_cost/2))
for(var/C in get_all_components())
var/obj/item/weapon/computer_hardware/H = C
uninstall_component(null, H)
H.forceMove(newloc)
if(prob(25))
H.take_damage(rand(10,30))
relay_qdel()
qdel()
/obj/item/modular_computer/proc/turn_on(mob/user)
var/issynth = issilicon(user) // Robots and AIs get different activation messages.
if(damage > broken_damage)
if(issynth)
user << "You send an activation signal to \the [src], but it responds with an error code. It must be damaged."
else
user << "You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again."
return
if(processor_unit && ((battery_module && battery_module.battery.charge && battery_module.check_functionality()) || check_power_override())) // Battery-run and charged or non-battery but powered by APC.
if(issynth)
user << "You send an activation signal to \the [src], turning it on"
else
user << "You press the power button and start up \the [src]"
enabled = 1
update_icon()
ui_interact(user)
else // Unpowered
if(issynth)
user << "You send an activation signal to \the [src] but it does not respond"
else
user << "You press the power button but \the [src] does not respond"
// Process currently calls handle_power(), may be expanded in future if more things are added.
/obj/item/modular_computer/process()
if(!enabled) // The computer is turned off
last_power_usage = 0
return 0
if(damage > broken_damage)
shutdown_computer()
return 0
if(active_program && active_program.requires_ntnet && !get_ntnet_status(active_program.requires_ntnet_feature)) // Active program requires NTNet to run but we've just lost connection. Crash.
active_program.event_networkfailure(0)
for(var/I in idle_threads)
var/datum/computer_file/program/P = I
if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature))
P.event_networkfailure(1)
if(active_program)
if(active_program.program_state != PROGRAM_STATE_KILLED)
active_program.process_tick()
active_program.ntnet_status = get_ntnet_status()
active_program.computer_emagged = computer_emagged
else
active_program = null
for(var/I in idle_threads)
var/datum/computer_file/program/P = I
if(P.program_state != PROGRAM_STATE_KILLED)
P.process_tick()
P.ntnet_status = get_ntnet_status()
P.computer_emagged = computer_emagged
else
idle_threads.Remove(P)
handle_power() // Handles all computer power interaction
//check_update_ui_need()
// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_"
/obj/item/modular_computer/proc/get_header_data()
var/list/data = list()
if(battery_module)
switch(battery_module.battery.percent())
if(80 to 200) // 100 should be maximal but just in case..
data["PC_batteryicon"] = "batt_100.gif"
if(60 to 80)
data["PC_batteryicon"] = "batt_80.gif"
if(40 to 60)
data["PC_batteryicon"] = "batt_60.gif"
if(20 to 40)
data["PC_batteryicon"] = "batt_40.gif"
if(5 to 20)
data["PC_batteryicon"] = "batt_20.gif"
else
data["PC_batteryicon"] = "batt_5.gif"
data["PC_batterypercent"] = "[round(battery_module.battery.percent())] %"
data["PC_showbatteryicon"] = 1
else
data["PC_batteryicon"] = "batt_5.gif"
data["PC_batterypercent"] = "N/C"
data["PC_showbatteryicon"] = battery_module ? 1 : 0
switch(get_ntnet_status())
if(0)
data["PC_ntneticon"] = "sig_none.gif"
if(1)
data["PC_ntneticon"] = "sig_low.gif"
if(2)
data["PC_ntneticon"] = "sig_high.gif"
if(3)
data["PC_ntneticon"] = "sig_lan.gif"
if(idle_threads.len)
var/list/program_headers = list()
for(var/I in idle_threads)
var/datum/computer_file/program/P = I
if(!P.ui_header)
continue
program_headers.Add(list(list(
"icon" = P.ui_header
)))
data["PC_programheaders"] = program_headers
data["PC_stationtime"] = worldtime2text()
data["PC_hasheader"] = 1
data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen
return data
// Relays kill program request to currently active program. Use this to quit current program.
/obj/item/modular_computer/proc/kill_program(forced = 0)
if(active_program)
active_program.kill_program(forced)
active_program = null
var/mob/user = usr
if(user && istype(user))
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
update_icon()
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
/obj/item/modular_computer/proc/get_ntnet_status(specific_action = 0)
if(network_card)
return network_card.get_signal(specific_action)
else
return 0
/obj/item/modular_computer/proc/add_log(text)
if(!get_ntnet_status())
return 0
return ntnet_global.add_log(text, network_card)
/obj/item/modular_computer/proc/shutdown_computer(loud = 1)
kill_program(1)
for(var/datum/computer_file/program/P in idle_threads)
P.kill_program(1)
idle_threads.Remove(P)
if(loud)
physical.visible_message("\The [src] shuts down.")
enabled = 0
update_icon()
return
// Handles user's GUI input
/obj/item/modular_computer/ui_act(action, params)
if(..())
return
switch(action)
if("PC_exit")
kill_program()
return 1
if("PC_shutdown")
shutdown_computer()
return 1
if("PC_minimize")
var/mob/user = usr
if(!active_program || !processor_unit)
return
idle_threads.Add(active_program)
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
active_program = null
update_icon()
if(user && istype(user))
ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
if("PC_killprogram")
var/prog = params["name"]
var/datum/computer_file/program/P = null
var/mob/user = usr
if(hard_drive)
P = hard_drive.find_file_by_name(prog)
if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
return
P.kill_program(1)
user << "<span class='notice'>Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.</span>"
if("PC_runprogram")
var/prog = params["name"]
var/datum/computer_file/program/P = null
var/mob/user = usr
if(hard_drive)
P = hard_drive.find_file_by_name(prog)
if(!P || !istype(P)) // Program not found or it's not executable program.
user << "<span class='danger'>\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning.</span>"
return
P.computer = src
if(!P.is_supported_by_hardware(hardware_flag, 1, user))
return
// The program is already running. Resume it.
if(P in idle_threads)
P.program_state = PROGRAM_STATE_ACTIVE
active_program = P
idle_threads.Remove(P)
update_icon()
return
if(idle_threads.len >= processor_unit.max_idle_programs+1)
user << "<span class='notice'>\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error</span>"
return
if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature)) // The program requires NTNet connection, but we are not connected to NTNet.
user << "<span class='danger'>\The [src]'s screen shows \"NETWORK ERROR - Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning.</span>"
return
P.computer_emagged = computer_emagged
if(P.run_program(user))
active_program = P
update_icon()
return 1
else
return
// Used in following function to reduce copypaste
/obj/item/modular_computer/proc/power_failure(malfunction = 0)
if(enabled) // Shut down the computer
physical.visible_message("<span class='danger'>\The [src]'s screen flickers \"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\" warning as it shuts down unexpectedly.</span>")
if(active_program)
active_program.event_powerfailure(0)
for(var/I in idle_threads)
var/datum/computer_file/program/PRG = I
PRG.event_powerfailure(1)
shutdown_computer(0)
// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged
/obj/item/modular_computer/proc/handle_power()
if(!battery_module || battery_module.battery.charge <= 0) // Battery-run but battery is depleted.
power_failure()
return 0
var/power_usage = screen_on ? base_active_power_usage : base_idle_power_usage
for(var/obj/item/weapon/computer_hardware/H in get_all_components())
if(H.enabled)
power_usage += H.power_usage
if(battery_module)
if(!battery_module.check_functionality())
power_failure(1)
return
if(!battery_module.battery.use(power_usage * CELLRATE))
battery_module.battery.charge = 0
power_failure()
return 0
last_power_usage = power_usage
/obj/item/modular_computer/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/card/id)) // ID Card, try to insert it.
var/obj/item/weapon/card/id/I = W
if(!card_slot)
user << "You try to insert \the [I] into \the [src], but it does not have an ID card slot installed."
return
if(card_slot.stored_card && card_slot.stored_card2)
user << "You try to insert \the [I] into \the [src], but it's ID card slots are occupied."
return
if(!user.drop_item(I))
return
if(!card_slot.stored_card)
card_slot.stored_card = I
else
card_slot.stored_card2 = I
I.forceMove(src)
// update_uis()
user << "You insert \the [I] into \the [src]."
return
if(istype(W, /obj/item/weapon/paper))
if(!nano_printer)
return
nano_printer.attackby(W, user)
if(istype(W, /obj/item/weapon/computer_hardware))
var/obj/item/weapon/computer_hardware/C = W
if(C.hardware_size <= max_hardware_size)
C.try_install_component(user, src)
else
user << "This component is too large for \the [src]."
if(istype(W, /obj/item/weapon/wrench))
var/list/components = get_all_components()
if(components.len)
user << "Remove all components from \the [src] before disassembling it."
return
new /obj/item/stack/sheet/metal( get_turf(src.loc), steel_sheet_cost )
physical.visible_message("\The [src] has been disassembled by [user].")
relay_qdel()
qdel(src)
return
if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(!WT.isOn())
user << "\The [W] is off."
return
if(!damage)
user << "\The [src] does not require repairs."
return
user << "You begin repairing damage to \the [src]..."
if(WT.remove_fuel(round(damage/75)) && do_after(usr, damage/10))
damage = 0
user << "You repair \the [src]."
return
if(istype(W, /obj/item/weapon/screwdriver))
var/list/all_components = get_all_components()
if(!all_components.len)
user << "This device doesn't have any components installed."
return
var/list/component_names = list()
for(var/obj/item/weapon/computer_hardware/H in all_components)
component_names.Add(H.name)
var/choice = input(usr, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in component_names
if(!choice)
return
if(!Adjacent(usr))
return
var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(choice)
if(!H)
return
uninstall_component(user, H)
return
..()
// Used by processor to relay qdel() to machinery type.
/obj/item/modular_computer/proc/relay_qdel()
return
// Uninstalls component. Found and Critical vars may be passed by parent types, if they have additional hardware.
/obj/item/modular_computer/proc/uninstall_component(mob/living/user, obj/item/weapon/computer_hardware/H, found = 0, critical = 0)
if(portable_drive == H)
portable_drive = null
found = 1
if(hard_drive == H)
hard_drive = null
found = 1
critical = 1
if(network_card == H)
network_card = null
found = 1
if(nano_printer == H)
nano_printer = null
found = 1
if(card_slot == H)
card_slot = null
found = 1
if(battery_module == H)
battery_module = null
found = 1
if(processor_unit == H)
processor_unit = null
found = 1
critical = 1
if(found)
if(user)
user << "You remove \the [H] from \the [src]."
H.forceMove(get_turf(src))
H.holder2 = null
if(critical && enabled)
if(user)
user << "<span class='danger'>\The [src]'s screen freezes for few seconds and then displays an \"HARDWARE ERROR: Critical component disconnected. Please verify component connection and reboot the device. If the problem persists contact technical support for assistance.\" warning.</span>"
shutdown_computer()
update_icon()
// Checks all hardware pieces to determine if name matches, if yes, returns the hardware piece, otherwise returns null
/obj/item/modular_computer/proc/find_hardware_by_name(name)
if(portable_drive && (portable_drive.name == name))
return portable_drive
if(hard_drive && (hard_drive.name == name))
return hard_drive
if(network_card && (network_card.name == name))
return network_card
if(nano_printer && (nano_printer.name == name))
return nano_printer
if(card_slot && (card_slot.name == name))
return card_slot
if(battery_module && (battery_module.name == name))
return battery_module
if(processor_unit && (processor_unit.name == name))
return processor_unit
return null
// Returns list of all components
/obj/item/modular_computer/proc/get_all_components()
var/list/all_components = list()
if(hard_drive)
all_components.Add(hard_drive)
if(network_card)
all_components.Add(network_card)
if(portable_drive)
all_components.Add(portable_drive)
if(nano_printer)
all_components.Add(nano_printer)
if(card_slot)
all_components.Add(card_slot)
if(battery_module)
all_components.Add(battery_module)
if(processor_unit)
all_components.Add(processor_unit)
return all_components
/obj/item/modular_computer/proc/take_damage(amount, component_probability, damage_casing = 1, randomize = 1)
if(randomize)
// 75%-125%, rand() works with integers, apparently.
amount *= (rand(75, 125) / 100.0)
amount = round(amount)
if(damage_casing)
damage += amount
damage = max(0,min(max_damage,damage))
if(component_probability)
for(var/I in get_all_components())
var/obj/item/weapon/computer_hardware/H = I
if(prob(component_probability))
H.take_damage(round(amount / 2))
if(damage >= max_damage)
break_apart()
// Stronger explosions cause serious damage to internal components
// Minor explosions are mostly mitigitated by casing.
/obj/item/modular_computer/ex_act(severity)
take_damage(rand(100,200) / severity, 30 / severity)
// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components
/obj/item/modular_computer/emp_act(severity)
take_damage(rand(100,200) / severity, 50 / severity, 0)
// "Stun" weapons can cause minor damage to components (short-circuits?)
// "Burn" damage is equally strong against internal components and exterior casing
// "Brute" damage mostly damages the casing.
/obj/item/modular_computer/bullet_act(obj/item/projectile/Proj)
switch(Proj.damage_type)
if(BRUTE)
take_damage(Proj.damage, Proj.damage / 2)
if(BURN)
take_damage(Proj.damage, Proj.damage / 1.5)
/obj/item/modular_computer/ui_host()
if(physical)
return physical
else
return src
@@ -0,0 +1,119 @@
// Held by /obj/machinery/modular_computer to reduce amount of copy-pasted code.
/obj/item/modular_computer/processor
name = "processing unit"
desc = "You shouldn't see this. If you do, report it."
icon = null
icon_state = null
icon_state_unpowered = null
icon_state_menu = null
hardware_flag = 0
var/obj/machinery/modular_computer/machinery_computer = null
/obj/item/modular_computer/processor/Destroy()
. = ..()
if(machinery_computer && (machinery_computer.cpu == src))
machinery_computer.cpu = null
machinery_computer = null
// Due to how processes work, we'd receive two process calls - one from machinery type and one from our own type.
// Since we want this to be in-sync with machinery (as it's hidden type for machinery-based computers) we'll ignore
// non-relayed process calls.
/obj/item/modular_computer/processor/process(relayed = 0)
if(relayed)
..()
else
return
/obj/item/modular_computer/processor/examine(var/mob/user)
if(damage > broken_damage)
user << "<span class='danger'>It is heavily damaged!</span>"
else if(damage)
user << "It is damaged."
// Power interaction is handled by our machinery part, due to machinery having APC connection.
/obj/item/modular_computer/processor/handle_power()
if(machinery_computer)
machinery_computer.handle_power()
/obj/item/modular_computer/processor/New(comp)
if(!comp || !istype(comp, /obj/machinery/modular_computer))
CRASH("Inapropriate type passed to obj/item/modular_computer/processor/New()! Aborting.")
return
// Obtain reference to machinery computer
machinery_computer = comp
machinery_computer.cpu = src
hardware_flag = machinery_computer.hardware_flag
max_hardware_size = machinery_computer.max_hardware_size
steel_sheet_cost = machinery_computer.steel_sheet_cost
max_damage = machinery_computer._max_damage
broken_damage = machinery_computer._break_damage
/obj/item/modular_computer/processor/relay_qdel()
qdel(machinery_computer)
/obj/item/modular_computer/processor/find_hardware_by_name(N)
var/obj/item/weapon/computer_hardware/H = machinery_computer.find_hardware_by_name(N)
if(H)
return H
else
return ..()
/obj/item/modular_computer/processor/update_icon()
if(machinery_computer)
return machinery_computer.update_icon()
/obj/item/modular_computer/processor/get_header_data()
var/list/L = ..()
if(machinery_computer.tesla_link && machinery_computer.tesla_link.enabled && machinery_computer.powered())
L["PC_apclinkicon"] = "charging.gif"
return L
// Checks whether the machinery computer doesn't take power from APC network
/obj/item/modular_computer/processor/check_power_override()
if(!machinery_computer)
return 0
if(!machinery_computer.tesla_link || !machinery_computer.tesla_link.enabled)
return 0
return machinery_computer.powered()
// This thing is not meant to be used on it's own, get topic data from our machinery owner.
//obj/item/modular_computer/processor/canUseTopic(user, state)
// if(!machinery_computer)
// return 0
// return machinery_computer.canUseTopic(user, state)
/obj/item/modular_computer/processor/shutdown_computer()
if(!machinery_computer)
return
..()
machinery_computer.update_icon()
machinery_computer.use_power = 0
return
/obj/item/modular_computer/processor/uninstall_component(mob/living/user, obj/item/weapon/computer_hardware/H, found = 0, critical = 0)
if(machinery_computer.tesla_link == H)
machinery_computer.tesla_link = null
var/obj/item/weapon/computer_hardware/tesla_link/L = H
L.holder = null
found = 1
..(user, H, found, critical)
/obj/item/modular_computer/processor/get_all_components()
var/list/all_components = ..()
if(machinery_computer && machinery_computer.tesla_link)
all_components.Add(machinery_computer.tesla_link)
return all_components
// Perform adjacency checks on our machinery counterpart, rather than on ourselves.
/obj/item/modular_computer/processor/Adjacent(atom/neighbor)
if(!machinery_computer)
return 0
return machinery_computer.Adjacent(neighbor)
/obj/item/modular_computer/processor/turn_on(mob/user)
// If we have a tesla link on our machinery counterpart, enable it automatically. Lets computer without a battery work.
if(machinery_computer && machinery_computer.tesla_link)
machinery_computer.tesla_link.enabled = 1
..()

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