Merge branch 'master' into upstream-merge-33601

This commit is contained in:
LetterJay
2018-01-02 18:26:18 -06:00
committed by GitHub
1130 changed files with 16375 additions and 27705 deletions
+3 -1
View File
@@ -62,6 +62,7 @@
var/list/firealarms
var/firedoors_last_closed_on = 0
var/xenobiology_compatible = FALSE //Can the Xenobio management console transverse this area by default?
var/list/canSmoothWithAreas //typecache to limit the areas that atoms in this area can smooth with
/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
@@ -75,7 +76,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(GLOB.teleportlocs[AR.name])
continue
var/turf/picked = safepick(get_area_turfs(AR.type))
if (picked && (picked.z in GLOB.station_z_levels))
if (picked && is_station_level(picked.z))
GLOB.teleportlocs[AR.name] = AR
sortTim(GLOB.teleportlocs, /proc/cmp_text_dsc)
@@ -105,6 +106,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
uid = ++global_uid
related = list(src)
map_name = name // Save the initial (the name set in the map) name of the area.
canSmoothWithAreas = typecacheof(canSmoothWithAreas)
if(requires_power)
luminosity = 0
+21 -9
View File
@@ -11,6 +11,11 @@
valid_territory = FALSE
icon_state = "shuttle"
/area/shuttle/Initialize()
if(!canSmoothWithAreas)
canSmoothWithAreas = type
. = ..()
////////////////////////////Multi-area shuttles////////////////////////////
////////////////////////////Syndicate infiltrator////////////////////////////
@@ -19,6 +24,7 @@
name = "Syndicate Infiltrator"
blob_allowed = FALSE
ambientsounds = HIGHSEC
canSmoothWithAreas = /area/shuttle/syndicate
/area/shuttle/syndicate/bridge
name = "Syndicate Infiltrator Control"
@@ -37,6 +43,18 @@
/area/shuttle/syndicate/airlock
name = "Syndicate Infiltrator Airlock"
////////////////////////////Pirate Shuttle////////////////////////////
/area/shuttle/pirate
name = "Pirate Shuttle"
blob_allowed = FALSE
requires_power = TRUE
canSmoothWithAreas = /area/shuttle/pirate
/area/shuttle/pirate/vault
name = "Pirate Shuttle Vault"
requires_power = FALSE
////////////////////////////Single-area shuttles////////////////////////////
/area/shuttle/transit
@@ -76,6 +94,9 @@
/area/shuttle/escape
name = "Emergency Shuttle"
/area/shuttle/escape/backup
name = "Backup Emergency Shuttle"
/area/shuttle/escape/luxury
name = "Luxurious Emergency Shuttle"
noteleport = TRUE
@@ -111,12 +132,3 @@
/area/shuttle/syndicate_scout
name = "Syndicate Scout"
blob_allowed = FALSE
/area/shuttle/pirate
name = "Pirate Shuttle"
blob_allowed = FALSE
requires_power = TRUE
/area/shuttle/pirate/vault
name = "Pirate Shuttle Vault"
requires_power = FALSE
+63 -141
View File
@@ -5,10 +5,6 @@
var/flags_1 = 0
var/flags_2 = 0
var/list/fingerprints
var/list/fingerprintshidden
var/list/blood_DNA
var/container_type = NONE
var/admin_spawned = 0 //was this spawned by an admin? used for stat tracking stuff.
var/datum/reagents/reagents = null
@@ -113,7 +109,7 @@
if(!T)
return FALSE
if(T.z == ZLEVEL_TRANSIT)
if(is_transit_level(T.z))
for(var/A in SSshuttle.mobile)
var/obj/docking_port/mobile/M = A
if(M.launch_status == ENDGAME_TRANSIT)
@@ -122,7 +118,7 @@
if(T in shuttle_area)
return TRUE
if(T.z != ZLEVEL_CENTCOM)//if not, don't bother
if(!is_centcom_level(T.z))//if not, don't bother
return FALSE
//Check for centcom itself
@@ -141,15 +137,15 @@
/atom/proc/onSyndieBase()
var/turf/T = get_turf(src)
if(!T)
return 0
return FALSE
if(T.z != ZLEVEL_CENTCOM)//if not, don't bother
return 0
if(!is_centcom_level(T.z))//if not, don't bother
return FALSE
if(istype(T.loc, /area/shuttle/syndicate) || istype(T.loc, /area/syndicate_mothership))
return 1
if(istype(T.loc, /area/shuttle/syndicate) || istype(T.loc, /area/syndicate_mothership) || istype(T.loc, /area/shuttle/assault_pod))
return TRUE
return 0
return FALSE
/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
SendSignal(COMSIG_ATOM_HULK_ATTACK, user)
@@ -194,27 +190,22 @@
set waitfor = FALSE
return
// Convenience proc to see if a container is open for chemistry handling
// returns true if open
// false if closed
// Convenience procs to see if a container is open for chemistry handling
/atom/proc/is_open_container()
return container_type & OPENCONTAINER_1
/atom/proc/is_transparent()
return container_type & TRANSPARENT_1
return is_refillable() && is_drainable()
/atom/proc/is_injectable(allowmobs = TRUE)
if(isliving(src) && allowmobs)
var/mob/living/L = src
return L.can_inject()
if(container_type & OPENCONTAINER_1)
return TRUE
return container_type & INJECTABLE_1
return reagents && (container_type & (INJECTABLE | REFILLABLE))
/atom/proc/is_drawable(allowmobs = TRUE)
if(is_injectable(allowmobs)) //Everything that can be injected can also be drawn from, but not vice versa
return TRUE
return container_type & DRAWABLE_1
return reagents && (container_type & (DRAWABLE | DRAINABLE))
/atom/proc/is_refillable()
return reagents && (container_type & REFILLABLE)
/atom/proc/is_drainable()
return reagents && (container_type & DRAINABLE)
/atom/proc/AllowDrop()
return FALSE
@@ -237,38 +228,46 @@
/atom/proc/in_contents_of(container)//can take class or object instance as argument
if(ispath(container))
if(istype(src.loc, container))
return 1
return TRUE
else if(src in container)
return 1
return TRUE
return FALSE
/atom/proc/get_examine_name(mob/user)
. = "\a [src]"
var/list/override = list(gender == PLURAL? "some" : "a" , " ", "[name]")
if(SendSignal(COMSIG_ATOM_GET_EXAMINE_NAME, user, override) & COMPONENT_EXNAME_CHANGED)
. = override.Join("")
/atom/proc/get_examine_string(mob/user, thats = FALSE)
. = "[icon2html(src, user)] [thats? "That's ":""][get_examine_name(user)]"
/atom/proc/examine(mob/user)
//This reformat names to get a/an properly working on item descriptions when they are bloody
var/f_name = "\a [src]."
if(src.blood_DNA && !istype(src, /obj/effect/decal))
if(gender == PLURAL)
f_name = "some "
else
f_name = "a "
f_name += "<span class='danger'>blood-stained</span> [name]!"
to_chat(user, "[icon2html(src, user)] That's [f_name]")
to_chat(user, get_examine_string(user, TRUE))
if(desc)
to_chat(user, desc)
if(reagents && (is_open_container() || is_transparent())) //is_open_container() isn't really the right proc for this, but w/e
to_chat(user, "It contains:")
if(reagents.reagent_list.len)
if(user.can_see_reagents()) //Show each individual reagent
for(var/datum/reagent/R in reagents.reagent_list)
to_chat(user, "[R.volume] units of [R.name]")
else //Otherwise, just show the total volume
var/total_volume = 0
for(var/datum/reagent/R in reagents.reagent_list)
total_volume += R.volume
to_chat(user, "[total_volume] units of various reagents")
else
to_chat(user, "Nothing.")
if(reagents)
if(container_type & TRANSPARENT)
to_chat(user, "It contains:")
if(reagents.reagent_list.len)
if(user.can_see_reagents()) //Show each individual reagent
for(var/datum/reagent/R in reagents.reagent_list)
to_chat(user, "[R.volume] units of [R.name]")
else //Otherwise, just show the total volume
var/total_volume = 0
for(var/datum/reagent/R in reagents.reagent_list)
total_volume += R.volume
to_chat(user, "[total_volume] units of various reagents")
else
to_chat(user, "Nothing.")
else if(container_type & AMOUNT_VISIBLE)
if(reagents.total_volume)
to_chat(user, "<span class='notice'>It has [reagents.total_volume] unit\s left.</span>")
else
to_chat(user, "<span class='danger'>It's empty.</span>")
SendSignal(COMSIG_PARENT_EXAMINE, user)
/atom/proc/relaymove(mob/user)
@@ -301,11 +300,6 @@
if(AM && isturf(AM.loc))
step(AM, turn(AM.dir, 180))
GLOBAL_LIST_EMPTY(blood_splatter_icons)
/atom/proc/blood_splatter_index()
return "[REF(initial(icon))]-[initial(icon_state)]"
//returns the mob's dna info as a list, to be inserted in an object's blood_DNA list
/mob/living/proc/get_blood_dna_list()
if(get_blood_id() != "blood")
@@ -330,100 +324,28 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons)
// Returns 0 if we have that blood already
var/new_blood_dna = L.get_blood_dna_list()
if(!new_blood_dna)
return 0
if(!blood_DNA) //if our list of DNA doesn't exist yet, initialise it.
blood_DNA = list()
var/old_length = blood_DNA.len
blood_DNA |= new_blood_dna
if(blood_DNA.len == old_length)
return 0
return 1
//to add blood dna info to the object's blood_DNA list
/atom/proc/transfer_blood_dna(list/blood_dna)
if(!blood_DNA)
blood_DNA = list()
var/old_length = blood_DNA.len
blood_DNA |= blood_dna
if(blood_DNA.len > old_length)
return 1//some new blood DNA was added
return FALSE
var/old_length = blood_DNA_length()
add_blood_DNA(new_blood_dna)
if(blood_DNA_length() == old_length)
return FALSE
return TRUE
//to add blood from a mob onto something, and transfer their dna info
/atom/proc/add_mob_blood(mob/living/M)
var/list/blood_dna = M.get_blood_dna_list()
if(!blood_dna)
return 0
return add_blood(blood_dna)
//to add blood onto something, with blood dna info to include.
/atom/proc/add_blood(list/blood_dna)
return 0
/obj/add_blood(list/blood_dna)
return transfer_blood_dna(blood_dna)
/obj/item/add_blood(list/blood_dna)
var/blood_count = !blood_DNA ? 0 : blood_DNA.len
if(!..())
return 0
if(!blood_count)//apply the blood-splatter overlay if it isn't already in there
add_blood_overlay()
return 1 //we applied blood to the item
/obj/item/proc/add_blood_overlay()
if(initial(icon) && initial(icon_state))
//try to find a pre-processed blood-splatter. otherwise, make a new one
var/index = blood_splatter_index()
var/icon/blood_splatter_icon = GLOB.blood_splatter_icons[index]
if(!blood_splatter_icon)
blood_splatter_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply blood-splatters to the initial icon_state for each object
blood_splatter_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent)
blood_splatter_icon.Blend(icon('icons/effects/blood.dmi', "itemblood"), ICON_MULTIPLY) //adds blood and the remaining white areas become transparant
blood_splatter_icon = fcopy_rsc(blood_splatter_icon)
GLOB.blood_splatter_icons[index] = blood_splatter_icon
add_overlay(blood_splatter_icon)
/obj/item/clothing/gloves/add_blood(list/blood_dna)
. = ..()
transfer_blood = rand(2, 4)
/turf/add_blood(list/blood_dna, list/datum/disease/diseases)
var/obj/effect/decal/cleanable/blood/splatter/B = locate() in src
if(!B)
B = new /obj/effect/decal/cleanable/blood/splatter(src, diseases)
B.transfer_blood_dna(blood_dna) //give blood info to the blood decal.
return 1 //we bloodied the floor
/mob/living/carbon/human/add_blood(list/blood_dna)
if(wear_suit)
wear_suit.add_blood(blood_dna)
update_inv_wear_suit()
else if(w_uniform)
w_uniform.add_blood(blood_dna)
update_inv_w_uniform()
if(gloves)
var/obj/item/clothing/gloves/G = gloves
G.add_blood(blood_dna)
else
transfer_blood_dna(blood_dna)
bloody_hands = rand(2, 4)
update_inv_gloves() //handles bloody hands overlays and updating
return 1
/atom/proc/clean_blood()
if(islist(blood_DNA))
blood_DNA = null
return 1
return FALSE
return add_blood_DNA(blood_dna)
/atom/proc/wash_cream()
return 1
return TRUE
/atom/proc/isinspace()
if(isspaceturf(get_turf(src)))
return 1
return TRUE
else
return 0
return FALSE
/atom/proc/handle_fall()
return
+10 -10
View File
@@ -144,27 +144,27 @@
/atom/movable/proc/clean_on_move()
var/turf/tile = loc
if(isturf(tile))
tile.clean_blood()
tile.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
for(var/A in tile)
if(is_cleanable(A))
qdel(A)
else if(istype(A, /obj/item))
var/obj/item/cleaned_item = A
cleaned_item.clean_blood()
cleaned_item.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
else if(ishuman(A))
var/mob/living/carbon/human/cleaned_human = A
if(cleaned_human.lying)
if(cleaned_human.head)
cleaned_human.head.clean_blood()
cleaned_human.head.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
cleaned_human.update_inv_head()
if(cleaned_human.wear_suit)
cleaned_human.wear_suit.clean_blood()
cleaned_human.wear_suit.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
cleaned_human.update_inv_wear_suit()
else if(cleaned_human.w_uniform)
cleaned_human.w_uniform.clean_blood()
cleaned_human.w_uniform.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
cleaned_human.update_inv_w_uniform()
if(cleaned_human.shoes)
cleaned_human.shoes.clean_blood()
cleaned_human.shoes.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
cleaned_human.update_inv_shoes()
cleaned_human.clean_blood()
cleaned_human.wash_cream()
@@ -414,7 +414,7 @@
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
if(!buckled_mob.Move(newloc, direct))
loc = buckled_mob.loc
forceMove(buckled_mob.loc)
last_move = buckled_mob.last_move
inertia_dir = last_move
buckled_mob.inertia_dir = last_move
@@ -516,7 +516,7 @@
. = ..()
. -= "Jump to"
.["Follow"] = "?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(src)]"
.["Get"] = "?_src=holder;[HrefToken()];admingetmovable=[REF(src)]"
.["Get"] = "?_src_=holder;[HrefToken()];admingetmovable=[REF(src)]"
/atom/movable/proc/ex_check(ex_id)
if(!ex_id)
@@ -611,8 +611,8 @@
/atom/movable/proc/in_bounds()
. = FALSE
var/turf/currentturf = get_turf(src)
if(currentturf && (currentturf.z == ZLEVEL_CENTCOM || (currentturf.z in GLOB.station_z_levels) || currentturf.z == ZLEVEL_TRANSIT))
var/turf/T = get_turf(src)
if (T && (is_centcom_level(T.z) || is_station_level(T.z) || is_transit_level(T.z)))
. = TRUE
+3
View File
@@ -60,6 +60,9 @@
/datum/atom_hud/data/bot_path
hud_icons = list(DIAG_PATH_HUD)
/datum/atom_hud/abductor
hud_icons = list(GLAND_HUD)
/* MED/SEC/DIAG HUD HOOKS */
/*
+37 -31
View File
@@ -4,7 +4,7 @@
w_class = WEIGHT_CLASS_TINY
var/used = 0
/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, type = "")
/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
return
/obj/item/antag_spawner/proc/equip_antag(mob/target)
@@ -67,18 +67,16 @@
else
to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.")
/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, school,datum/mind/user)
/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind ,datum/mind/user)
new /obj/effect/particle_effect/smoke(T)
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
C.prefs.copy_to(M)
M.key = C.key
var/datum/mind/app_mind = M.mind
var/datum/antagonist/wizard/apprentice/app = new(app_mind)
app.master = user
app.school = school
app.school = kind
var/datum/antagonist/wizard/master_wizard = user.has_antag_datum(/datum/antagonist/wizard)
if(master_wizard)
@@ -107,10 +105,10 @@
if(used)
to_chat(user, "<span class='warning'>[src] is out of power!</span>")
return FALSE
if(!(user.mind in SSticker.mode.syndicates))
if(!user.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE))
to_chat(user, "<span class='danger'>AUTHENTICATION FAILURE. ACCESS DENIED.</span>")
return FALSE
if(user.z != ZLEVEL_CENTCOM)
if(!user.onSyndieBase())
to_chat(user, "<span class='warning'>[src] is out of range! It can only be used at your base!</span>")
return FALSE
return TRUE
@@ -127,25 +125,25 @@
return
used = TRUE
var/mob/dead/observer/theghost = pick(nuke_candidates)
spawn_antag(theghost.client, get_turf(src), "syndieborg", user.mind)
spawn_antag(theghost.client, get_turf(src), "syndieborg")
do_sparks(4, TRUE, src)
qdel(src)
else
to_chat(user, "<span class='warning'>Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.</span>")
/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T)
/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T, kind, datum/mind/user)
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
C.prefs.copy_to(M)
M.key = C.key
var/code = "BOMB-NOT-FOUND"
var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
if(nuke)
code = nuke.r_code
M.mind.make_Nuke(null, code, 0, FALSE)
var/newname = M.dna.species.random_name(M.gender,0,SSticker.mode.nukeops_lastname)
M.mind.name = newname
M.real_name = newname
M.name = newname
var/datum/antagonist/nukeop/new_op = new(M.mind)
new_op.send_to_spawnpoint = FALSE
new_op.nukeop_outfit = /datum/outfit/syndicate/no_crystals
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
if(creator_op)
M.mind.add_antag_datum(new_op,creator_op.nuke_team)
M.mind.special_role = "Nuclear Operative"
//////SYNDICATE BORG
/obj/item/antag_spawner/nuke_ops/borg_tele
@@ -162,8 +160,12 @@
name = "syndicate medical teleporter"
borg_to_spawn = "Medical"
/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T)
/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T, kind, datum/mind/user)
var/mob/living/silicon/robot/R
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
if(!creator_op)
return
switch(borg_to_spawn)
if("Medical")
R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
@@ -174,8 +176,8 @@
if(prob(50))
brainfirstname = pick(GLOB.first_names_female)
var/brainopslastname = pick(GLOB.last_names)
if(SSticker.mode.nukeops_lastname) //the brain inside the syndiborg has the same last name as the other ops.
brainopslastname = SSticker.mode.nukeops_lastname
if(creator_op.nuke_team.syndicate_name) //the brain inside the syndiborg has the same last name as the other ops.
brainopslastname = creator_op.nuke_team.syndicate_name
var/brainopsname = "[brainfirstname] [brainopslastname]"
R.mmi.name = "Man-Machine Interface: [brainopsname]"
@@ -185,7 +187,11 @@
R.real_name = R.name
R.key = C.key
R.mind.make_Nuke(null, nuke_code = null,leader=0, telecrystals = TRUE)
var/datum/antagonist/nukeop/new_borg = new(R.mind)
new_borg.send_to_spawnpoint = FALSE
R.mind.add_antag_datum(new_borg,creator_op.nuke_team)
R.mind.special_role = "Syndicate Cyborg"
///////////SLAUGHTER DEMON
@@ -202,7 +208,7 @@
/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user)
if(!(user.z in GLOB.station_z_levels))
if(!is_station_level(user.z))
to_chat(user, "<span class='notice'>You should probably wait until you reach the station.</span>")
return
if(used)
@@ -213,7 +219,7 @@
return
used = 1
var/mob/dead/observer/theghost = pick(demon_candidates)
spawn_antag(theghost.client, get_turf(src), initial(demon_type.name),user.mind)
spawn_antag(theghost.client, get_turf(src), initial(demon_type.name))
to_chat(user, shatter_msg)
to_chat(user, veil_msg)
playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, 1)
@@ -222,8 +228,7 @@
to_chat(user, "<span class='notice'>You can't seem to work up the nerve to shatter the bottle. Perhaps you should try again later.</span>")
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, type = "", datum/mind/user)
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
S.holder = holder
@@ -232,16 +237,17 @@
S.mind.special_role = S.name
SSticker.mode.traitors += S.mind
var/datum/objective/assassinate/new_objective
if(user)
if(usr)
new_objective = new /datum/objective/assassinate
new_objective.owner = S.mind
new_objective.target = user
new_objective.explanation_text = "[objective_verb] [user.name], the one who summoned you."
new_objective.target = usr.mind
new_objective.explanation_text = "[objective_verb] [usr.real_name], the one who summoned you."
S.mind.objectives += new_objective
var/datum/objective/new_objective2 = new /datum/objective
new_objective2.owner = S.mind
new_objective2.explanation_text = "[objective_verb] everyone[user ? " else while you're at it":""]."
new_objective2.explanation_text = "[objective_verb] everyone[usr ? " else while you're at it":""]."
S.mind.objectives += new_objective2
S.mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
to_chat(S, "<B>You are currently not currently in the same plane of existence as the station. \
Ctrl+Click a blood pool to manifest.</B>")
+34
View File
@@ -0,0 +1,34 @@
//A barebones antagonist team.
/datum/team
var/list/datum/mind/members = list()
var/name = "team"
var/member_name = "member"
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
/datum/team/New(starting_members)
. = ..()
if(starting_members)
if(islist(starting_members))
for(var/datum/mind/M in starting_members)
add_member(M)
else
add_member(starting_members)
/datum/team/proc/is_solo()
return members.len == 1
/datum/team/proc/add_member(datum/mind/new_member)
members |= new_member
/datum/team/proc/remove_member(datum/mind/member)
members -= member
//Display members/victory/failure/objectives for the team
/datum/team/proc/roundend_report()
var/list/report = list()
report += "<b>[name]:</b>"
report += "The [member_name]s were:"
report += printplayerlist(members)
return report.Join("<br>")
+1 -1
View File
@@ -42,7 +42,7 @@
/mob/living/simple_animal/hostile/blob/fire_act(exposed_temperature, exposed_volume)
..()
if(exposed_temperature)
adjustFireLoss(Clamp(0.01 * exposed_temperature, 1, 5))
adjustFireLoss(CLAMP(0.01 * exposed_temperature, 1, 5))
else
adjustFireLoss(5)
+29 -6
View File
@@ -4,6 +4,7 @@ GLOBAL_LIST_EMPTY(blob_cores)
GLOBAL_LIST_EMPTY(overminds)
GLOBAL_LIST_EMPTY(blob_nodes)
/mob/camera/blob
name = "Blob Overmind"
real_name = "Blob Overmind"
@@ -33,10 +34,12 @@ GLOBAL_LIST_EMPTY(blob_nodes)
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
var/list/blobs_legit = list()
var/max_count = 0 //The biggest it got before death
var/blobwincount = 400
var/victory_in_progress = FALSE
/mob/camera/blob/Initialize(mapload, starting_points = 60)
validate_location()
blob_points = starting_points
manualplace_min_time += world.time
autoplace_max_time += world.time
@@ -50,11 +53,18 @@ GLOBAL_LIST_EMPTY(blob_nodes)
color = blob_reagent_datum.complementary_color
if(blob_core)
blob_core.update_icon()
SSshuttle.registerHostileEnvironment(src)
.= ..()
/mob/camera/blob/proc/validate_location()
var/turf/T = get_turf(src)
var/area/A = get_area(T)
if(((A && !A.blob_allowed) || !T || !(T.z in GLOB.station_z_levels)) && LAZYLEN(GLOB.blobstart))
T = get_turf(pick(GLOB.blobstart))
if(!T)
CRASH("No blobspawnpoints and blob spawned in nullspace.")
forceMove(T)
/mob/camera/blob/Life()
if(!blob_core)
if(!placed)
@@ -73,6 +83,9 @@ GLOBAL_LIST_EMPTY(blob_nodes)
max_blob_points = INFINITY
blob_points = INFINITY
addtimer(CALLBACK(src, .proc/victory), 450)
if(!victory_in_progress && max_count < blobs_legit.len)
max_count = blobs_legit.len
..()
@@ -111,6 +124,11 @@ GLOBAL_LIST_EMPTY(blob_nodes)
A.layer = BELOW_MOB_LAYER
A.invisibility = 0
A.blend_mode = 0
var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
if(B)
var/datum/objective/blob_takeover/main_objective = locate() in B.objectives
if(main_objective)
main_objective.completed = TRUE
to_chat(world, "<B>[real_name] consumed the station in an unstoppable tide!</B>")
SSticker.news_report = BLOB_WIN
SSticker.force_ending = 1
@@ -134,7 +152,6 @@ GLOBAL_LIST_EMPTY(blob_nodes)
/mob/camera/blob/Login()
..()
sync_mind()
to_chat(src, "<span class='notice'>You are the overmind!</span>")
blob_help()
update_health_hud()
@@ -153,7 +170,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
B.hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_core.obj_integrity)]</font></div>"
/mob/camera/blob/proc/add_points(points)
blob_points = Clamp(blob_points + points, 0, max_blob_points)
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)
@@ -215,12 +232,18 @@ GLOBAL_LIST_EMPTY(blob_nodes)
if(placed)
var/obj/structure/blob/B = locate() in range("3x3", NewLoc)
if(B)
loc = NewLoc
forceMove(NewLoc)
else
return 0
else
var/area/A = get_area(NewLoc)
if(isspaceturf(NewLoc) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
return 0
loc = NewLoc
forceMove(NewLoc)
return 1
/mob/camera/blob/mind_initialize()
. = ..()
var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
if(!B)
mind.add_antag_datum(/datum/antagonist/blob)
+17 -16
View File
@@ -7,22 +7,23 @@
// Power verbs
/mob/camera/blob/proc/place_blob_core(point_rate, placement_override)
/mob/camera/blob/proc/place_blob_core(point_rate, placement_override , pop_override = FALSE)
if(placed && placement_override != -1)
return 1
if(!placement_override)
for(var/mob/living/M in range(7, src))
if("blob" in M.faction)
continue
if(M.client)
to_chat(src, "<span class='warning'>There is someone too close to place your blob core!</span>")
return 0
for(var/mob/living/M in view(13, src))
if("blob" in M.faction)
continue
if(M.client)
to_chat(src, "<span class='warning'>Someone could see your blob core from here!</span>")
return 0
if(!pop_override)
for(var/mob/living/M in range(7, src))
if("blob" in M.faction)
continue
if(M.client)
to_chat(src, "<span class='warning'>There is someone too close to place your blob core!</span>")
return 0
for(var/mob/living/M in view(13, src))
if("blob" in M.faction)
continue
if(M.client)
to_chat(src, "<span class='warning'>Someone could see your blob core from here!</span>")
return 0
var/turf/T = get_turf(src)
if(T.density)
to_chat(src, "<span class='warning'>This spot is too dense to place a blob core on!</span>")
@@ -37,12 +38,12 @@
else if(O.density)
to_chat(src, "<span class='warning'>This spot is too dense to place a blob core on!</span>")
return 0
if(world.time <= manualplace_min_time && world.time <= autoplace_max_time)
if(!pop_override && world.time <= manualplace_min_time && world.time <= autoplace_max_time)
to_chat(src, "<span class='warning'>It is too early to place your blob core!</span>")
return 0
else if(placement_override == 1)
var/turf/T = pick(GLOB.blobstart)
loc = T //got overrided? you're somewhere random, motherfucker
forceMove(T) //got overrided? you're somewhere random, motherfucker
if(placed && blob_core)
blob_core.forceMove(loc)
else
@@ -74,7 +75,7 @@
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
var/obj/structure/blob/node/chosen_node = nodes[node_name]
if(chosen_node)
loc = chosen_node.loc
forceMove(chosen_node.loc)
/mob/camera/blob/proc/createSpecial(price, blobType, nearEquals, needsNode, turf/T)
if(!T)
+6 -74
View File
@@ -1,44 +1,6 @@
/datum/objective_team/brother_team
name = "brotherhood"
member_name = "blood brother"
var/list/objectives = list()
var/meeting_area
/datum/objective_team/brother_team/is_solo()
return FALSE
/datum/objective_team/brother_team/proc/add_objective(datum/objective/O, needs_target = FALSE)
O.team = src
if(needs_target)
O.find_target()
O.update_explanation_text()
objectives += O
/datum/objective_team/brother_team/proc/forge_brother_objectives()
objectives = list()
var/is_hijacker = prob(10)
for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
forge_single_objective()
if(is_hijacker)
if(!locate(/datum/objective/hijack) in objectives)
add_objective(new/datum/objective/hijack)
else if(!locate(/datum/objective/escape) in objectives)
add_objective(new/datum/objective/escape)
/datum/objective_team/brother_team/proc/forge_single_objective()
if(prob(50))
if(LAZYLEN(active_ais()) && prob(100/GLOB.joined_player_list.len))
add_objective(new/datum/objective/destroy, TRUE)
else if(prob(30))
add_objective(new/datum/objective/maroon, TRUE)
else
add_objective(new/datum/objective/assassinate, TRUE)
else
add_objective(new/datum/objective/steal, TRUE)
/datum/game_mode
var/list/datum/mind/brothers = list()
var/list/datum/objective_team/brother_team/brother_teams = list()
var/list/datum/team/brother_team/brother_teams = list()
/datum/game_mode/traitor/bros
name = "traitor+brothers"
@@ -51,9 +13,10 @@
<span class='danger'>Blood Brothers</span>: Accomplish your objectives.\n\
<span class='notice'>Crew</span>: Do not let the traitors or brothers succeed!"
var/list/datum/objective_team/brother_team/pre_brother_teams = list()
var/list/datum/team/brother_team/pre_brother_teams = list()
var/const/team_amount = 2 //hard limit on brother teams if scaling is turned off
var/const/min_team_size = 2
traitors_required = FALSE //Only teams are possible
var/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
@@ -73,7 +36,7 @@
for(var/j = 1 to num_teams)
if(possible_brothers.len < min_team_size || antag_candidates.len <= required_enemies)
break
var/datum/objective_team/brother_team/team = new
var/datum/team/brother_team/team = new
var/team_size = prob(10) ? min(3, possible_brothers.len) : 2
for(var/k = 1 to team_size)
var/datum/mind/bro = pick(possible_brothers)
@@ -86,50 +49,19 @@
return ..()
/datum/game_mode/traitor/bros/post_setup()
for(var/datum/objective_team/brother_team/team in pre_brother_teams)
for(var/datum/team/brother_team/team in pre_brother_teams)
team.meeting_area = pick(meeting_areas)
meeting_areas -= team.meeting_area
team.forge_brother_objectives()
for(var/datum/mind/M in team.members)
M.add_antag_datum(ANTAG_DATUM_BROTHER, team)
team.update_name()
brother_teams += pre_brother_teams
return ..()
/datum/game_mode/traitor/bros/generate_report()
return "It's Syndicate recruiting season. Be alert for potential Syndicate infiltrators, but also watch out for disgruntled employees trying to defect. Unlike Nanotrasen, the Syndicate prides itself in teamwork and will only recruit pairs that share a brotherly trust."
/datum/game_mode/proc/auto_declare_completion_brother()
if(!LAZYLEN(brother_teams))
return
var/text = "<br><font size=4><b>The blood brothers were:</b></font>"
var/teamnumber = 1
for(var/datum/objective_team/brother_team/team in brother_teams)
if(!team.members.len)
continue
text += "<br><font size=3><b>Team #[teamnumber++]</b></font>"
for(var/datum/mind/M in team.members)
text += printplayer(M)
var/win = TRUE
var/objective_count = 1
for(var/datum/objective/objective in team.objectives)
if(objective.check_completion())
text += "<br><B>Objective #[objective_count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
else
text += "<br><B>Objective #[objective_count]</B>: [objective.explanation_text] <font color='red'>Fail.</font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
if(!(istype(objective, /datum/objective/crew)))
win = FALSE
objective_count++
if(win)
text += "<br><font color='green'><B>The blood brothers were successful!</B></font>"
SSblackbox.record_feedback("tally", "brother_success", 1, "SUCCESS")
else
text += "<br><font color='red'><B>The blood brothers have failed!</B></font>"
SSblackbox.record_feedback("tally", "brother_success", 1, "FAIL")
text += "<br>"
to_chat(world, text)
/datum/game_mode/proc/update_brother_icons_added(datum/mind/brother_mind)
var/datum/atom_hud/antag/brotherhud = GLOB.huds[ANTAG_HUD_BROTHER]
brotherhud.join_hud(brother_mind.current)
@@ -94,47 +94,6 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
of the Thing being sent to a station in this sector is highly likely. It may be in the guise of any crew member. Trust nobody - suspect everybody. Do not announce this to the crew, \
as paranoia may spread and inhibit workplace efficiency."
/datum/game_mode/proc/auto_declare_completion_changeling()
var/list/changelings = get_antagonists(/datum/antagonist/changeling,TRUE) //Only real lings get a mention
if(changelings.len)
var/text = "<br><font size=3><b>The changelings were:</b></font>"
for(var/datum/mind/changeling in changelings)
var/datum/antagonist/changeling/ling = changeling.has_antag_datum(/datum/antagonist/changeling)
var/changelingwin = 1
if(!changeling.current)
changelingwin = 0
text += printplayer(changeling)
//Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
text += "<br><b>Changeling ID:</b> [ling.changelingID]."
text += "<br><b>Genomes Extracted:</b> [ling.absorbedcount]"
if(changeling.objectives.len)
var/count = 1
for(var/datum/objective/objective in changeling.objectives)
if(objective.check_completion())
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <font color='green'><b>Success!</b></font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "changeling_objective", 1, list("[objective.type]", "SUCCESS"))
else
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='danger'>Fail.</span> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "changeling_objective", 1, list("[objective.type]", "FAIL"))
if(!(istype(objective, /datum/objective/crew)))
changelingwin = 0
count++
if(changelingwin)
text += "<br><font color='green'><b>The changeling was successful!</b></font>"
SSblackbox.record_feedback("tally", "changeling_success", 1, "SUCCESS")
else
text += "<br><span class='boldannounce'>The changeling has failed.</span>"
SSblackbox.record_feedback("tally", "changeling_success", 1, "FAIL")
text += "<br>"
to_chat(world, text)
return 1
/proc/changeling_transform(mob/living/carbon/human/user, datum/changelingprofile/chosen_prof)
var/datum/dna/chosen_dna = chosen_prof.dna
user.real_name = chosen_prof.name
@@ -58,6 +58,8 @@
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
if(target.mind)//if the victim has got a mind
// Absorb a lizard, speak Draconic.
user.copy_known_languages_from(target)
target.mind.show_memory(user, 0) //I can read your mind, kekeke. Output all their notes.
@@ -8,6 +8,8 @@
/obj/effect/proc_holder/changeling/headcrab/sting_action(mob/user)
set waitfor = FALSE
if(alert("Are we sure we wish to kill ourself and create a headslug?",,"Yes", "No") == "No")
return
var/datum/mind/M = user.mind
var/list/organs = user.getorganszone("head", 1)
@@ -35,4 +37,4 @@
if(crab.origin)
crab.origin.active = 1
crab.origin.transfer_to(crab)
to_chat(crab, "<span class='warning'>You burst out of the remains of your former body in a shower of gore!</span>")
to_chat(crab, "<span class='warning'>You burst out of the remains of your former body in a shower of gore!</span>")
@@ -20,7 +20,7 @@
to_chat(user, "<span class='notice'>We prepare our sting, use alt+click or middle mouse button on target to sting them.</span>")
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chosen_sting = src
user.hud_used.lingstingdisplay.icon_state = sting_icon
user.hud_used.lingstingdisplay.invisibility = 0
@@ -28,7 +28,7 @@
to_chat(user, "<span class='warning'>We retract our sting, we can't sting anyone for now.</span>")
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chosen_sting = null
user.hud_used.lingstingdisplay.icon_state = null
user.hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
@@ -90,7 +90,7 @@
/obj/effect/proc_holder/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target)
if(!..())
return
if((target.disabilities & HUSK) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
if((target.has_disability(DISABILITY_HUSK)) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
to_chat(user, "<span class='warning'>Our sting appears ineffective against its DNA.</span>")
return 0
return 1
@@ -129,9 +129,11 @@
/obj/effect/proc_holder/changeling/sting/false_armblade/can_sting(mob/user, mob/target)
if(!..())
return
if((target.disabilities & HUSK) || !target.has_dna())
to_chat(user, "<span class='warning'>Our sting appears ineffective against its DNA.</span>")
return 0
if(isliving(target))
var/mob/living/L = target
if((L.has_disability(DISABILITY_HUSK)) || !L.has_dna())
to_chat(user, "<span class='warning'>Our sting appears ineffective against its DNA.</span>")
return 0
return 1
/obj/effect/proc_holder/changeling/sting/false_armblade/sting_action(mob/user, mob/target)
+15 -36
View File
@@ -65,13 +65,16 @@ Credit where due:
return TRUE
return FALSE
/proc/add_servant_of_ratvar(mob/L, silent = FALSE)
/proc/add_servant_of_ratvar(mob/L, silent = FALSE, create_team = TRUE)
if(!L || !L.mind)
return
var/update_type = ANTAG_DATUM_CLOCKCULT
if(silent)
update_type = ANTAG_DATUM_CLOCKCULT_SILENT
. = L.mind.add_antag_datum(update_type)
var/datum/antagonist/clockcult/C = new update_type(L.mind)
C.make_team = create_team
C.show_in_roundend = create_team //tutorial scarabs begone
. = L.mind.add_antag_datum(C)
/proc/remove_servant_of_ratvar(mob/L, silent = FALSE)
if(!L || !L.mind)
@@ -88,7 +91,6 @@ Credit where due:
///////////////
/datum/game_mode
var/datum/mind/eminence //The clockwork Eminence
var/list/servants_of_ratvar = list() //The Enlightened servants of Ratvar
var/clockwork_explanation = "Defend the Ark of the Clockwork Justiciar and free Ratvar." //The description of the current objective
@@ -111,6 +113,8 @@ Credit where due:
var/roundstart_player_count
var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
var/datum/team/clockcult/main_clockcult
/datum/game_mode/clockwork_cult/pre_setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
@@ -185,22 +189,21 @@ Credit where due:
return FALSE
/datum/game_mode/clockwork_cult/check_finished()
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G && !GLOB.ratvar_awakens) // Doesn't end until the Ark is destroyed or completed
if(GLOB.ark_of_the_clockwork_justiciar && !GLOB.ratvar_awakens) // Doesn't end until the Ark is destroyed or completed
return FALSE
. = ..()
return ..()
/datum/game_mode/clockwork_cult/proc/check_clockwork_victory()
return main_clockcult.check_clockwork_victory()
/datum/game_mode/clock_cult/set_round_result()
..()
if(GLOB.clockwork_gateway_activated)
SSticker.news_report = CLOCK_SUMMON
return TRUE
SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
else
SSticker.news_report = CULT_FAILURE
return FALSE
/datum/game_mode/clockwork_cult/declare_completion()
..()
return //Doesn't end until the round does
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
/datum/game_mode/clockwork_cult/generate_report()
return "Bluespace monitors near your sector have detected a continuous stream of patterned fluctuations since the station was completed. It is most probable that a powerful entity \
@@ -210,30 +213,6 @@ Credit where due:
working for this entity and utilizing highly-advanced technology to cross the great distance at will. If they should turn out to be a credible threat, the task falls on you and \
your crew to dispatch it in a timely manner."
/datum/game_mode/proc/auto_declare_completion_clockwork_cult()
var/text = ""
if(istype(SSticker.mode, /datum/game_mode/clockwork_cult)) //Possibly hacky?
var/datum/game_mode/clockwork_cult/C = SSticker.mode
if(C.check_clockwork_victory())
text += "<span class='bold large_brass'>Ratvar's servants defended the Ark until its activation!</span>"
SSticker.mode_result = "win - servants completed their objective (summon ratvar)"
else
text += "<span class='userdanger'>The Ark was destroyed! Ratvar will rust away for all eternity!</span>"
SSticker.mode_result = "loss - servants failed their objective (summon ratvar)"
text += "<br><b>The servants' objective was:</b> [CLOCKCULT_OBJECTIVE]."
text += "<br>Ratvar's servants had <b>[GLOB.clockwork_caches]</b> Tinkerer's Caches."
text += "<br><b>Construction Value(CV)</b> was: <b>[GLOB.clockwork_construction_value]</b>"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER)
text += "<br><b>[i] scripture</b> was: <b>[SSticker.scripture_states[i] ? "UN":""]LOCKED</b>"
if(SSticker.mode.eminence)
text += "<br><b>The Eminence was:</b> [printplayer(SSticker.mode.eminence)]"
if(servants_of_ratvar.len)
text += "<br><b>Ratvar's servants were:</b>"
for(var/datum/mind/M in servants_of_ratvar - SSticker.mode.eminence)
text += printplayer(M)
to_chat(world, text)
/datum/game_mode/proc/update_servant_icons_added(datum/mind/M)
var/datum/atom_hud/antag/A = GLOB.huds[ANTAG_HUD_CLOCKWORK]
A.join_hud(M.current)
@@ -207,7 +207,7 @@
to_chat(cyborg, "<span class='brass'>You start to charge from the [sigil_name]...</span>")
if(!do_after(cyborg, 50, target = src, extra_checks = CALLBACK(src, .proc/cyborg_checks, cyborg, TRUE)))
return
var/giving_power = min(Floor(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
var/giving_power = min(FLOOR(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
if(adjust_clockwork_power(-giving_power))
cyborg.visible_message("<span class='warning'>[cyborg] glows a brilliant orange!</span>")
var/previous_color = cyborg.color
@@ -275,11 +275,10 @@
/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L)
if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active)
return
visible_message("<span class='warning'>[src] begins to glow bright blue!</span>")
animate(src, alpha = 255, time = 10, flags = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay.
sleep(10)
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && (GLOB.ratvar_awakens || GLOB.clockwork_vitality))) && get_turf(L) == get_turf(src))
while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && (GLOB.ratvar_awakens || GLOB.clockwork_vitality))) && get_turf(L) == get_turf(src) && !L.buckled)
sigil_active = TRUE
if(animation_number >= 4)
new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
@@ -314,21 +313,28 @@
revival_cost = 0
var/mob/dead/observer/ghost = L.get_ghost(TRUE)
if(GLOB.clockwork_vitality >= revival_cost && (ghost || (L.mind && L.mind.active)))
if(ghost)
ghost.reenter_corpse()
L.revive(1, 1)
var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
animate(V, alpha = 0, transform = matrix()*2, time = 8)
playsound(L, 'sound/magic/staff_healing.ogg', 50, 1)
L.visible_message("<span class='warning'>[L] suddenly gets back up, [L.p_their()] body dripping blue ichor!</span>", "<span class='inathneq'>\"[text2ratvar("You will be okay, child.")]\"</span>")
GLOB.clockwork_vitality -= revival_cost
if(L.has_status_effect(STATUS_EFFECT_ICHORIAL_STAIN))
visible_message("<span class='boldwarning'>[src] strains, but nothing happens...</span>")
if(L.pulledby)
to_chat(L.pulledby, "<span class='userdanger'>[L] was already revived recently by a vitality matrix! Wait a bit longer!</span>")
break
else
if(ghost)
ghost.reenter_corpse()
L.revive(1, 1)
var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
animate(V, alpha = 0, transform = matrix()*2, time = 8)
playsound(L, 'sound/magic/staff_healing.ogg', 50, 1)
to_chat(L, "<span class='inathneq'>\"[text2ratvar("You will be okay, child.")]\"</span>")
L.apply_status_effect(STATUS_EFFECT_ICHORIAL_STAIN)
GLOB.clockwork_vitality -= revival_cost
break
if(!L.client || L.client.is_afk())
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [L.name], an inactive clock cultist?", "[name]", null, "Clock Cultist", 50, L)
var/mob/dead/observer/theghost = null
if(candidates.len)
to_chat(L, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form!")
to_chat(L, "<span class='userdanger'>Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form!</span>")
message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(L)]) to replace an inactive clock cultist.")
L.ghostize(0)
L.key = theghost.key
@@ -355,5 +361,4 @@
if(sigil_active)
animation_number = initial(animation_number)
sigil_active = FALSE
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
animate(src, alpha = initial(alpha), time = 10, flags = ANIMATION_END_NOW)
@@ -14,7 +14,7 @@
/obj/effect/clockwork/servant_blocker/CanPass(atom/movable/M, turf/target)
var/list/target_contents = M.GetAllContents() + M
for(var/mob/living/L in target_contents)
if(is_servant_of_ratvar(L) && get_dir(M, src) != dir) //Unless we're on the side the arrow is pointing directly away from, no-go
if(is_servant_of_ratvar(L) && get_dir(M, src) != dir && L.stat != DEAD) //Unless we're on the side the arrow is pointing directly away from, no-go
to_chat(L, "<span class='danger'>The space beyond here can't be accessed by you or other servants.</span>")
return
return TRUE
@@ -165,13 +165,13 @@
var/list/teleportnames = list()
for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in GLOB.all_clockwork_objects)
if(!O.Adjacent(invoker) && O != src && (O.z <= ZLEVEL_SPACEMAX) && O.anchored) //don't list obelisks that we're next to
if(!O.Adjacent(invoker) && O != src && !is_away_level(O.z) && O.anchored) //don't list obelisks that we're next to
var/area/A = get_area(O)
var/locname = initial(A.name)
possible_targets[avoid_assoc_duplicate_keys("[locname] [O.name]", teleportnames)] = O
for(var/mob/living/L in GLOB.alive_mob_list)
if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && (L.z <= ZLEVEL_SPACEMAX)) //People right next to the invoker can't be portaled to, for obvious reasons
if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && !is_away_level(L.z)) //People right next to the invoker can't be portaled to, for obvious reasons
possible_targets[avoid_assoc_duplicate_keys("[L.name] ([L.real_name])", teleportnames)] = L
if(!possible_targets.len)
@@ -90,7 +90,7 @@
if(amount_temp < 2)
to_chat(user, "<span class='warning'>You need at least <b>2</b> floor tiles to convert into power.</span>")
return TRUE
if(IsOdd(amount_temp))
if(ISODD(amount_temp))
amount_temp--
no_delete = TRUE
use(amount_temp)
@@ -239,7 +239,7 @@
if(!do_after(user, repair_values["healing_for_cycle"] * fabricator.speed_multiplier, target = src, \
extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE)))
break
obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
obj_integrity = CLAMP(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
adjust_clockwork_power(-repair_values["power_required"])
playsound(src, 'sound/machines/click.ogg', 50, 1)
@@ -10,12 +10,15 @@
for(var/obj/effect/clockwork/sigil/transmission/T in GLOB.all_clockwork_objects)
T.update_icon()
var/power_overwhelming = GLOB.clockwork_power
var/unlock_message
if(power_overwhelming >= SCRIPT_UNLOCK_THRESHOLD && !GLOB.script_scripture_unlocked)
GLOB.script_scripture_unlocked = TRUE
hierophant_message("<span class='large_brass bold'>The Ark swells as a key power threshold is reached. Script scriptures are now available.</span>")
unlock_message = "<span class='large_brass bold'>The Ark swells as a key power threshold is reached. Script scriptures are now available.</span>"
if(power_overwhelming >= APPLICATION_UNLOCK_THRESHOLD && !GLOB.application_scripture_unlocked)
GLOB.application_scripture_unlocked = TRUE
hierophant_message("<span class='large_brass bold'>The Ark surges as a key power threshold is reached. Application scriptures are now available.</span>")
unlock_message = "<span class='large_brass bold'>The Ark surges as a key power threshold is reached. Application scriptures are now available.</span>"
if(GLOB.servants_active)
hierophant_message(unlock_message)
return TRUE
/proc/can_access_clockwork_power(atom/movable/access_point, amount) //Returns true if the access point has access to clockwork power (and optionally, a number of watts for it)
@@ -11,6 +11,8 @@
//reports to servants when scripture is locked or unlocked
/proc/scripture_unlock_alert(list/previous_states)
if(!GLOB.servants_active)
return
. = scripture_unlock_check()
for(var/i in .)
if(.[i] != previous_states[i])
@@ -91,7 +91,8 @@
/obj/item/clockwork/construct_chassis/cogscarab/pre_spawn()
if(infinite_resources)
construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar //During rounds where they can't interact with the station, let them experiment with builds
//During rounds where they can't interact with the station, let them experiment with builds
construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar
/obj/item/clockwork/construct_chassis/cogscarab/post_spawn(mob/living/construct)
if(infinite_resources) //Allow them to build stuff and recite scripture
@@ -94,7 +94,7 @@
fabrication_values["power_cost"] = 0
var/turf/Y = get_turf(user)
if(!Y || (!(Y.z in GLOB.station_z_levels) && Y.z != ZLEVEL_CENTCOM && Y.z != ZLEVEL_MINING && Y.z != ZLEVEL_LAVALAND))
if(!Y || (!is_centcom_level(Y.z) && !is_station_level(Y.z) && !is_mining_level(Y.z)))
fabrication_values["operation_time"] *= 2
if(fabrication_values["power_cost"] > 0)
fabrication_values["power_cost"] *= 2
@@ -32,7 +32,7 @@
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
if(src == H.glasses && !up)
if(H.disabilities & BLIND)
if(H.has_disability(DISABILITY_BLIND))
to_chat(H, "<span class='heavy_brass'>\"You're blind, idiot. Stop embarrassing yourself.\"</span>")
return
if(blind_cultist(H))
@@ -76,7 +76,7 @@
..()
if(slot != slot_glasses || up)
return
if(user.disabilities & BLIND)
if(user.has_disability(DISABILITY_BLIND))
to_chat(user, "<span class='heavy_brass'>\"You're blind, idiot. Stop embarrassing yourself.\"</span>" )
return
if(blind_cultist(user)) //Cultists instantly go blind
@@ -115,11 +115,11 @@
var/obj/item/clothing/glasses/wraith_spectacles/WS = L.glasses
desc = "[glasses_right && !WS.up ? "<font color=#DAAA18><b>":""]You are [glasses_right ? "":"not "]wearing wraith spectacles[glasses_right && !WS.up ? "!</b></font>":"."]<br>\
You have taken <font color=#DAAA18><b>[W.eye_damage_done]</b></font> eye damage from them.<br>"
if(L.disabilities & NEARSIGHT)
if(L.has_disability(DISABILITY_NEARSIGHT))
desc += "<font color=#DAAA18><b>You are nearsighted!</b></font><br>"
else if(glasses_right && !WS.up)
desc += "You will become nearsighted at <font color=#DAAA18><b>[W.nearsight_breakpoint]</b></font> eye damage.<br>"
if(L.disabilities & BLIND)
if(L.has_disability(DISABILITY_BLIND))
desc += "<font color=#DAAA18><b>You are blind!</b></font>"
else if(glasses_right && !WS.up)
desc += "You will become blind at <font color=#DAAA18><b>[W.blind_breakpoint]</b></font> eye damage."
@@ -153,17 +153,18 @@
qdel(src)
/datum/status_effect/wraith_spectacles/proc/apply_eye_damage(mob/living/carbon/human/H)
if(H.disabilities & BLIND)
if(H.has_disability(DISABILITY_BLIND))
return
H.adjust_eye_damage(0.5)
eye_damage_done += 0.5
if(eye_damage_done >= 20)
H.adjust_blurriness(2)
if(eye_damage_done >= nearsight_breakpoint)
if(H.become_nearsighted())
to_chat(H, "<span class='nzcrentr'>Your vision doubles, then trebles. Darkness begins to close in. You can't keep this up!</span>")
if(!H.has_disability(DISABILITY_NEARSIGHT))
to_chat(H, "<span class='nzcrentr'>Your vision doubles, then trembles. Darkness begins to close in. You can't keep this up!</span>")
H.become_nearsighted(EYE_DAMAGE)
if(eye_damage_done >= blind_breakpoint)
if(H.become_blind())
if(!H.has_disability(DISABILITY_BLIND))
to_chat(H, "<span class='nzcrentr_large'>A piercing white light floods your vision. Suddenly, all goes dark!</span>")
if(prob(min(20, 5 + eye_damage_done)))
to_chat(H, "<span class='nzcrentr_small'><i>Your eyes continue to burn.</i></span>")
@@ -14,16 +14,6 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
var/static/superheated_walls = 0
/mob/camera/eminence/Initialize()
if(SSticker.mode.eminence)
return INITIALIZE_HINT_QDEL
. = ..()
/mob/camera/eminence/Destroy(force)
if(!force && mind && SSticker.mode.eminence == mind)
return QDEL_HINT_LETMELIVE
return ..()
/mob/camera/eminence/CanPass(atom/movable/mover, turf/target)
return TRUE
@@ -39,12 +29,20 @@
/mob/camera/eminence/Login()
..()
add_servant_of_ratvar(src, TRUE)
var/datum/antagonist/clockcult/C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
if(!C)
add_servant_of_ratvar(src, TRUE)
C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
if(C && C.clock_team)
if(C.clock_team.eminence)
remove_servant_of_ratvar(src,TRUE)
qdel(src)
else
C.clock_team.eminence = src
to_chat(src, "<span class='bold large_brass'>You have been selected as the Eminence!</span>")
to_chat(src, "<span class='brass'>As the Eminence, you lead the servants. Anything you say will be heard by the entire cult.</span>")
to_chat(src, "<span class='brass'>Though you can move through walls, you're also incorporeal, and largely can't interact with the world except for a few ways.</span>")
to_chat(src, "<span class='brass'>Additionally, unless the herald's beacon is activated, you can't understand any speech while away from Reebe.</span>")
SSticker.mode.eminence = mind
eminence_help()
for(var/V in actions)
var/datum/action/A = V
@@ -65,7 +63,7 @@
hierophant_message("<span class='large_brass'><b>The Eminence:</b> \"[message]\"</span>")
/mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
if(z == ZLEVEL_CITYOFCOGS || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything
if(is_reebe(z) || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything
to_chat(src, message)
return
to_chat(src, "<i>[speaker] says something, but you can't understand any of it...</i>")
@@ -235,7 +233,7 @@
button_icon_state = "warp_down"
/datum/action/innate/eminence/station_jump/Activate()
if(owner.z == ZLEVEL_CITYOFCOGS)
if(is_reebe(owner.z))
owner.forceMove(get_turf(pick(GLOB.generic_event_spawns)))
owner.playsound_local(owner, 'sound/magic/magic_missile.ogg', 50, TRUE)
flash_color(owner, flash_color = "#AF0AAF", flash_time = 25)
@@ -1,13 +1,13 @@
#define MARAUDER_SLOWDOWN_PERCENTAGE 0.40 //Below this percentage of health, marauders will become slower
#define MARAUDER_SHIELD_REGEN_TIME 100 //In deciseconds, how long it takes for shields to regenerate after breaking
#define MARAUDER_SHIELD_REGEN_TIME 200 //In deciseconds, how long it takes for shields to regenerate after breaking
//Clockwork marauder: A well-rounded frontline construct. Only one can exist for every two human servants.
/mob/living/simple_animal/hostile/clockwork/marauder
name = "clockwork marauder"
desc = "The stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield."
icon_state = "clockwork_marauder"
health = 150
maxHealth = 150
health = 120
maxHealth = 120
force_threshold = 8
speed = 0
obj_damage = 40
@@ -39,10 +39,11 @@
speed = initial(speed) + 1 //Yes, this slows them down
else
speed = initial(speed)
if(shield_health != max_shield_health && world.time >= shield_health_regen)
to_chat(src, "<span class='neovgre'>Your shield has recovered. <b>[max_shield_health]</b> blocks remaining!</span>")
if(shield_health < max_shield_health && world.time >= shield_health_regen)
shield_health_regen = world.time + MARAUDER_SHIELD_REGEN_TIME
to_chat(src, "<span class='neovgre'>Your shield has recovered, <b>[shield_health]</b> blocks remaining!</span>")
playsound_local(src, "shatter", 75, TRUE, frequency = -1)
shield_health = max_shield_health
shield_health++
/mob/living/simple_animal/hostile/clockwork/marauder/update_values()
if(GLOB.ratvar_awakens) //Massive attack damage bonuses and health increase, because Ratvar
@@ -126,7 +126,7 @@ Applications: 8 servants, 3 caches, and 100 CV
/datum/clockwork_scripture/proc/check_offstation_penalty()
var/turf/T = get_turf(invoker)
if(!T || (!(T.z in GLOB.station_z_levels) && T.z != ZLEVEL_CENTCOM && T.z != ZLEVEL_MINING && T.z != ZLEVEL_LAVALAND && T.z != ZLEVEL_CITYOFCOGS))
if(!T || (!is_centcom_level(T.z) && !is_station_level(T.z) && !is_mining_level(T.z) && !is_reebe(T.z)))
channel_time *= 2
power_cost *= 2
return TRUE
@@ -262,7 +262,7 @@ Applications: 8 servants, 3 caches, and 100 CV
to_chat(invoker, "<span class='warning'>There are too many constructs of this type ([constructs])! You may only have [round(construct_limit)] at once.</span>")
return
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G && !G.active && combat_construct && invoker.z == ZLEVEL_CITYOFCOGS && !confirmed) //Putting marauders on the base during the prep phase is a bad idea mmkay
if(G && !G.active && combat_construct && is_reebe(invoker.z) && !confirmed) //Putting marauders on the base during the prep phase is a bad idea mmkay
if(alert(invoker, "This is a combat construct, and you cannot easily get it to the station. Are you sure you want to make one here?", "Construct Alert", "Yes", "Cancel") == "Cancel")
return
if(!is_servant_of_ratvar(invoker) || !invoker.canUseTopic(slab))
@@ -97,7 +97,7 @@
if(ishuman(M.current))
human_servants++
construct_limit = human_servants / 4 //1 per 4 human servants, and a maximum of 3 marauders
construct_limit = Clamp(construct_limit, 1, 3)
construct_limit = CLAMP(construct_limit, 1, 3)
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/pre_recital()
channel_time = initial(channel_time)
@@ -209,7 +209,7 @@
quickbind_desc = "Returns you to Reebe."
/datum/clockwork_scripture/abscond/check_special_requirements()
if(invoker.z == ZLEVEL_CITYOFCOGS)
if(is_reebe(invoker.z))
to_chat(invoker, "<span class='danger'>You're already at Reebe.</span>")
return
return TRUE
@@ -70,6 +70,12 @@
quickbind = TRUE
quickbind_desc = "Creates a Vitality Matrix, which drains non-Servants on it to heal Servants that cross it."
/datum/clockwork_scripture/create_object/vitality_matrix/check_special_requirements()
if(locate(object_path) in range(1, invoker))
to_chat(invoker, "<span class='danger'>Vitality matrices placed next to each other could interfere and cause a feedback loop! Move away from the other ones!</span>")
return FALSE
return ..()
//Judicial Visor: Creates a judicial visor, which can smite an area.
/datum/clockwork_scripture/create_object/judicial_visor
@@ -17,7 +17,11 @@
return
if(kingmaking)
return
if(SSticker.mode.eminence)
var/datum/antagonist/clockcult/C = user.mind.has_antag_datum(/datum/antagonist/clockcult)
if(!C || !C.clock_team)
return
if(C.clock_team.eminence)
to_chat(user, "<span class='warning'>There's already an Eminence!</span>")
return
if(!GLOB.servants_active)
@@ -34,7 +38,9 @@
/obj/structure/destructible/clockwork/eminence_spire/attack_ghost(mob/user)
if(!IsAdminGhost(user))
return
if(SSticker.mode.eminence)
var/datum/antagonist/clockcult/random_cultist = locate() in GLOB.antagonists //if theres no cultists new team without eminence will be created anyway.
if(random_cultist && random_cultist.clock_team && random_cultist.clock_team.eminence)
to_chat(user, "<span class='warning'>There's already an Eminence - too late!</span>")
return
if(!GLOB.servants_active)
@@ -60,4 +60,4 @@
break
if(!M)
M = H.apply_status_effect(STATUS_EFFECT_MANIAMOTOR, src)
M.severity = Clamp(M.severity + ((11 - get_dist(src, H)) * efficiency * efficiency), 0, MAX_MANIA_SEVERITY)
M.severity = CLAMP(M.severity + ((11 - get_dist(src, H)) * efficiency * efficiency), 0, MAX_MANIA_SEVERITY)
@@ -110,7 +110,7 @@
if(!(BI.resistance_flags & ON_FIRE))
BI.fire_act()
continue
if(is_servant_of_ratvar(L) || (L.disabilities & BLIND) || L.null_rod_check())
if(is_servant_of_ratvar(L) || (L.has_disability(DISABILITY_BLIND)) || L.null_rod_check())
continue
if(L.stat || L.restrained() || L.buckled || L.lying)
continue
@@ -57,5 +57,5 @@
L.confused = min(L.confused + 15, 50)
L.dizziness = min(L.dizziness + 15, 50)
if(L.confused >= 25)
L.Knockdown(Floor(L.confused * 0.8))
L.Knockdown(FLOOR(L.confused * 0.8, 1))
take_damage(max_integrity)
@@ -3,7 +3,7 @@
name = "pressure sensor"
desc = "A thin plate of brass, barely visible but clearly distinct."
clockwork_desc = "A trigger that will activate when a non-servant runs across it."
max_integrity = 25
max_integrity = 5
icon_state = "pressure_sensor"
alpha = 80
layer = LOW_ITEM_LAYER
@@ -21,9 +21,10 @@
STOP_PROCESSING(SSfastprocess, src)
if(buckled_mobs && buckled_mobs.len)
var/mob/living/L = buckled_mobs[1]
L.Knockdown(100)
L.visible_message("<span class='warning'>[L] is maimed as the skewer shatters while still in their body!</span>")
L.adjustBruteLoss(15)
if(iscarbon(L))
L.Knockdown(100)
L.visible_message("<span class='warning'>[L] is maimed as the skewer shatters while still in their body!</span>")
L.adjustBruteLoss(15)
unbuckle_mob(L)
return ..()
@@ -48,14 +49,22 @@
/obj/structure/destructible/clockwork/trap/brass_skewer/activate()
if(density)
return
var/mob/living/carbon/squirrel = locate() in get_turf(src)
var/mob/living/squirrel = locate() in get_turf(src)
if(squirrel)
squirrel.visible_message("<span class='boldwarning'>A massive brass spike erupts from the ground, impaling [squirrel]!</span>", \
"<span class='userdanger'>A massive brass spike rams through your chest, hoisting you into the air!</span>")
squirrel.emote("scream")
playsound(squirrel, 'sound/effects/splat.ogg', 50, TRUE)
playsound(squirrel, 'sound/misc/desceration-03.ogg', 50, TRUE)
squirrel.apply_damage(20, BRUTE, "chest")
if(iscyborg(squirrel))
if(!squirrel.stat)
squirrel.visible_message("<span class='boldwarning'>A massive brass spike erupts from the ground, rending [squirrel]'s chassis but shattering into pieces!</span>", \
"<span class='userdanger'>A massive brass spike rips through your chassis and bursts into shrapnel in your casing!</span>")
squirrel.adjustBruteLoss(50)
squirrel.Stun(20)
addtimer(CALLBACK(src, .proc/take_damage, max_integrity), 1)
else
squirrel.visible_message("<span class='boldwarning'>A massive brass spike erupts from the ground, impaling [squirrel]!</span>", \
"<span class='userdanger'>A massive brass spike rams through your chest, hoisting you into the air!</span>")
squirrel.emote("scream")
playsound(squirrel, 'sound/effects/splat.ogg', 50, TRUE)
playsound(squirrel, 'sound/misc/desceration-03.ogg', 50, TRUE)
squirrel.apply_damage(20, BRUTE, "chest")
mouse_opacity = MOUSE_OPACITY_OPAQUE //So players can interact with the tile it's on to pull them off
buckle_mob(squirrel, TRUE)
else
@@ -59,9 +59,9 @@
brass_floor = TRUE
if(W.use(2 - brass_floor))
if(anchored)
T.ChangeTurf(/turf/closed/wall/clockwork)
T.PlaceOnTop(/turf/closed/wall/clockwork)
else
T.ChangeTurf(/turf/open/floor/clockwork)
T.PlaceOnTop(/turf/open/floor/clockwork)
new /obj/structure/falsewall/brass(T)
qdel(src)
else
+25 -183
View File
@@ -2,24 +2,23 @@
/datum/game_mode
var/list/datum/mind/cult = list()
var/list/cult_objectives = list()
var/eldergod = 1 //for the summon god objective
/proc/iscultist(mob/living/M)
return istype(M) && M.mind && M.mind.has_antag_datum(ANTAG_DATUM_CULT)
/proc/is_sacrifice_target(datum/mind/mind)
if(mind == GLOB.sac_mind)
return TRUE
/datum/team/cult/proc/is_sacrifice_target(datum/mind/mind)
for(var/datum/objective/sacrifice/sac_objective in objectives)
if(mind == sac_objective.target)
return TRUE
return FALSE
/proc/is_convertable_to_cult(mob/living/M)
/proc/is_convertable_to_cult(mob/living/M,datum/team/cult/specific_cult)
if(!istype(M))
return FALSE
if(M.mind)
if(ishuman(M) && (M.mind.assigned_role in list("Captain", "Chaplain")))
return FALSE
if(is_sacrifice_target(M.mind))
if(specific_cult && specific_cult.is_sacrifice_target(M.mind))
return FALSE
if(M.mind.enslaved_to && !iscultist(M.mind.enslaved_to))
return FALSE
@@ -55,10 +54,10 @@
var/list/cultists_to_cult = list() //the cultists we'll convert
var/datum/team/cult/main_cult
/datum/game_mode/cult/pre_setup()
cult_objectives += "sacrifice"
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
@@ -86,82 +85,19 @@
/datum/game_mode/cult/post_setup()
if("sacrifice" in cult_objectives)
var/list/possible_targets = get_unconvertables()
if(!possible_targets.len)
message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !(player.mind in cultists_to_cult))
possible_targets += player.mind
if(possible_targets.len > 0)
GLOB.sac_mind = pick(possible_targets)
if(!GLOB.sac_mind)
message_admins("Cult Sacrifice: ERROR - Null target chosen!")
else
var/datum/job/sacjob = SSjob.GetJob(GLOB.sac_mind.assigned_role)
var/datum/preferences/sacface = GLOB.sac_mind.current.client.prefs
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
reshape.Shift(SOUTH, 4)
reshape.Shift(EAST, 1)
reshape.Crop(7,4,26,31)
reshape.Crop(-5,-3,26,30)
GLOB.sac_image = reshape
else
message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
if(!GLOB.summon_spots.len)
while(GLOB.summon_spots.len < SUMMON_POSSIBILITIES)
var/area/summon = pick(GLOB.sortedAreas - GLOB.summon_spots)
if((summon.z in GLOB.station_z_levels) && summon.valid_territory)
GLOB.summon_spots += summon
cult_objectives += "eldergod"
for(var/datum/mind/cult_mind in cultists_to_cult)
equip_cultist(cult_mind.current)
update_cult_icons_added(cult_mind)
to_chat(cult_mind.current, "<span class='userdanger'>You are a member of the cult!</span>")
cult_mind.current.playsound_local(get_turf(cult_mind.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
add_cultist(cult_mind, 0)
add_cultist(cult_mind, 0, equip=TRUE)
..()
/datum/game_mode/proc/equip_cultist(mob/living/carbon/human/mob,tome = 0)
if(!istype(mob))
return
if (mob.mind)
if (mob.mind.assigned_role == "Clown")
to_chat(mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
mob.dna.remove_mutation(CLOWNMUT)
if(tome)
. += cult_give_item(/obj/item/tome, mob)
else
. += cult_give_item(/obj/item/paper/talisman/supply, mob)
to_chat(mob, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.</span>")
/datum/game_mode/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
var/list/slots = list(
"backpack" = slot_in_backpack,
"left pocket" = slot_l_store,
"right pocket" = slot_r_store
)
var/T = new item_path(mob)
var/item_name = initial(item_path.name)
var/where = mob.equip_in_one_of_slots(T, slots)
if(!where)
to_chat(mob, "<span class='userdanger'>Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).</span>")
return 0
else
to_chat(mob, "<span class='danger'>You have a [item_name] in your [where].</span>")
if(where == "backpack")
var/obj/item/storage/B = mob.back
B.orient2hud(mob)
B.show_to(mob)
return 1
/datum/game_mode/proc/add_cultist(datum/mind/cult_mind, stun) //BASE
/datum/game_mode/proc/add_cultist(datum/mind/cult_mind, stun , equip = FALSE) //BASE
if (!istype(cult_mind))
return 0
if(cult_mind.add_antag_datum(ANTAG_DATUM_CULT))
var/datum/antagonist/cult/new_cultist = new(cult_mind)
new_cultist.give_equipment = equip
if(cult_mind.add_antag_datum(new_cultist))
if(stun)
cult_mind.current.Unconscious(100)
return 1
@@ -187,25 +123,19 @@
culthud.leave_hud(cult_mind.current)
set_antag_hud(cult_mind.current, null)
/datum/game_mode/cult/proc/get_unconvertables()
var/list/ucs = list()
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !is_convertable_to_cult(player) && !(player.mind in cultists_to_cult))
ucs += player.mind
return ucs
/datum/game_mode/cult/proc/check_cult_victory()
var/cult_fail = 0
if(cult_objectives.Find("survive"))
cult_fail += check_survive() //the proc returns 1 if there are not enough cultists on the shuttle, 0 otherwise
if(cult_objectives.Find("eldergod"))
cult_fail += eldergod //1 by default, 0 if the elder god has been summoned at least once
if(cult_objectives.Find("sacrifice"))
if(GLOB.sac_mind && !GLOB.sac_complete) //if the target has been GLOB.sacrificed, ignore this step. otherwise, add 1 to cult_fail
cult_fail++
return cult_fail //if any objectives aren't met, failure
return main_cult.check_cult_victory()
/datum/game_mode/cult/set_round_result()
..()
if(check_cult_victory())
SSticker.mode_result = "win - cult win"
SSticker.news_report = CULT_SUMMON
else
SSticker.mode_result = "loss - staff stopped the cult"
SSticker.news_report = CULT_FAILURE
/datum/game_mode/cult/proc/check_survive()
var/acolytes_survived = 0
for(var/datum/mind/cult_mind in cult)
@@ -218,57 +148,6 @@
return 1
/datum/game_mode/cult/declare_completion()
if(!check_cult_victory())
SSticker.mode_result = "win - cult win"
to_chat(world, "<span class='greentext'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>")
else
SSticker.mode_result = "loss - staff stopped the cult"
to_chat(world, "<span class='redtext'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>")
var/text = ""
if(cult_objectives.len)
text += "<br><b>The cultists' objectives were:</b>"
for(var/obj_count=1, obj_count <= cult_objectives.len, obj_count++)
var/explanation
switch(cult_objectives[obj_count])
if("survive")
if(!check_survive())
explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped) <span class='greenannounce'>Success!</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_survive", "SUCCESS"))
SSticker.news_report = CULT_ESCAPE
else
explanation = "Make sure at least [acolytes_needed] acolytes escape on the shuttle. ([acolytes_survived] escaped) <span class='boldannounce'>Fail.</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_survive", "FAIL"))
SSticker.news_report = CULT_FAILURE
if("sacrifice")
if(GLOB.sac_complete)
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='greenannounce'>Success!</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "SUCCESS"))
else
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='boldannounce'>Fail.</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "FAIL"))
if("eldergod")
if(!eldergod)
explanation = "Summon Nar-Sie. The summoning can only be accomplished in [english_list(GLOB.summon_spots)].<span class='greenannounce'>Success!</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "SUCCESS"))
SSticker.news_report = CULT_SUMMON
else
explanation = "Summon Nar-Sie. The summoning can only be accomplished in [english_list(GLOB.summon_spots)]<span class='boldannounce'>Fail.</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "FAIL"))
SSticker.news_report = CULT_FAILURE
text += "<br><B>Objective #[obj_count]</B>: [explanation]"
if(cult.len)
text += "<br><b>The cultists were:</b>"
for(var/datum/mind/M in cult)
text += printplayer(M)
to_chat(world, text)
..()
return 1
/datum/game_mode/cult/generate_report()
return "Some stations in your sector have reported evidence of blood sacrifice and strange magic. Ties to the Wizards' Federation have been proven not to exist, and many employees \
have disappeared; even Central Command employees light-years away have felt strange presences and at times hysterical compulsions. Interrogations point towards this being the work of \
@@ -276,41 +155,4 @@
devoted to stopping this cult. Note that holy water seems to weaken and eventually return the minds of cultists that ingest it, and mindshield implants will prevent conversion \
altogether."
/datum/game_mode/proc/datum_cult_completion()
var/text = ""
var/cult_fail = 0
cult_fail += eldergod
if(!GLOB.sac_complete)
cult_fail++
if(!cult_fail)
SSticker.mode_result = "win - cult win"
to_chat(world, "<span class='greentext'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>")
else
SSticker.mode_result = "loss - staff stopped the cult"
to_chat(world, "<span class='redtext'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>")
if(cult_objectives.len)
text += "<br><b>The cultists' objectives were:</b>"
for(var/obj_count in 1 to 2)
var/explanation
switch(cult_objectives[obj_count])
if("sacrifice")
if(GLOB.sac_mind)
if(GLOB.sac_complete)
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='greenannounce'>Success!</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "SUCCESS"))
else
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='boldannounce'>Fail.</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_sacrifice", "FAIL"))
if("eldergod")
if(!eldergod)
explanation = "Summon Nar-Sie. <span class='greenannounce'>Success!</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "SUCCESS"))
SSticker.news_report = CULT_SUMMON
else
explanation = "Summon Nar-Sie. <span class='boldannounce'>Fail.</span>"
SSblackbox.record_feedback("nested tally", "cult_objective", 1, list("cult_narsie", "FAIL"))
SSticker.news_report = CULT_FAILURE
text += "<br><B>Objective #[obj_count]</B>: [explanation]"
to_chat(world, text)
#undef CULT_SCALING_COEFFICIENT
+39 -31
View File
@@ -30,7 +30,7 @@
user.whisper("O bidai nabora se[pick("'","`")]sma!", language = /datum/language/common)
user.whisper(html_decode(message))
var/title = "Acolyte"
var/span = "cultitalic"
var/span = "cult italic"
if(user.mind && user.mind.has_antag_datum(ANTAG_DATUM_CULT_MASTER))
span = "cultlarge"
if(ishuman(user))
@@ -88,19 +88,21 @@
button_icon_state = "cultvote"
/datum/action/innate/cult/mastervote/IsAvailable()
if(GLOB.cult_vote_called || !ishuman(owner))
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C || C.cult_team.cult_vote_called || !ishuman(owner))
return FALSE
return ..()
/datum/action/innate/cult/mastervote/Activate()
pollCultists(owner)
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
pollCultists(owner,C.cult_team)
/proc/pollCultists(var/mob/living/Nominee) //Cult Master Poll
/proc/pollCultists(var/mob/living/Nominee,datum/team/cult/team) //Cult Master Poll
if(world.time < CULT_POLL_WAIT)
to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [DisplayTimeText(CULT_POLL_WAIT-world.time)].")
return
GLOB.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
for(var/datum/mind/B in SSticker.mode.cult)
team.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
@@ -108,39 +110,39 @@
to_chat(B.current, "<span class='cultlarge'>Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.</span>")
sleep(100)
var/list/asked_cultists = list()
for(var/datum/mind/B in SSticker.mode.cult)
for(var/datum/mind/B in team.members)
if(B.current && B.current != Nominee && !B.current.incapacitated())
SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg')
asked_cultists += B.current
var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 300, group = asked_cultists)
if(QDELETED(Nominee) || Nominee.incapacitated())
GLOB.cult_vote_called = FALSE
for(var/datum/mind/B in SSticker.mode.cult)
team.cult_vote_called = FALSE
for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current,"<span class='cultlarge'>[Nominee] has died in the process of attempting to win the cult's support!</span>")
return FALSE
if(!Nominee.mind)
GLOB.cult_vote_called = FALSE
for(var/datum/mind/B in SSticker.mode.cult)
team.cult_vote_called = FALSE
for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current,"<span class='cultlarge'>[Nominee] has gone catatonic in the process of attempting to win the cult's support!</span>")
return FALSE
if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5)
GLOB.cult_vote_called = FALSE
for(var/datum/mind/B in SSticker.mode.cult)
team.cult_vote_called = FALSE
for(var/datum/mind/B in team.members)
if(B.current)
B.current.update_action_buttons_icon()
if(!B.current.incapacitated())
to_chat(B.current, "<span class='cultlarge'>[Nominee] could not win the cult's support and shall continue to serve as an acolyte.</span>")
return FALSE
GLOB.cult_mastered = TRUE
team.cult_mastered = TRUE
SSticker.mode.remove_cultist(Nominee.mind, TRUE)
Nominee.mind.add_antag_datum(ANTAG_DATUM_CULT_MASTER)
for(var/datum/mind/B in SSticker.mode.cult)
for(var/datum/mind/B in team.members)
if(B.current)
for(var/datum/action/innate/cult/mastervote/vote in B.current.actions)
vote.Remove(B.current)
@@ -159,6 +161,9 @@
button_icon_state = "sintouch"
/datum/action/innate/cult/master/finalreck/Activate()
var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!antag)
return
for(var/i in 1 to 4)
chant(i)
var/list/destinations = list()
@@ -169,7 +174,7 @@
to_chat(owner, "<span class='warning'>You need more space to summon the cult!</span>")
return
if(do_after(owner, 30, target = owner))
for(var/datum/mind/B in SSticker.mode.cult)
for(var/datum/mind/B in antag.cult_team.members)
if(B.current && B.current.stat != DEAD)
var/turf/mobloc = get_turf(B.current)
switch(i)
@@ -194,7 +199,7 @@
addtimer(CALLBACK(B.current, /mob/.proc/reckon, final), 10)
else
return
GLOB.reckoning_complete = TRUE
antag.cult_team.reckoning_complete = TRUE
Remove(owner)
/mob/proc/reckon(turf/final)
@@ -269,34 +274,37 @@
var/turf/T = get_turf(ranged_ability_user)
if(!isturf(T))
return FALSE
var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(target in view(7, get_turf(ranged_ability_user)))
GLOB.blood_target = target
C.cult_team.blood_target = target
var/area/A = get_area(target)
attached_action.cooldown = world.time + attached_action.base_cooldown
addtimer(CALLBACK(attached_action.owner, /mob.proc/update_action_buttons_icon), attached_action.base_cooldown)
GLOB.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
GLOB.blood_target_image.appearance_flags = RESET_COLOR
GLOB.blood_target_image.pixel_x = -target.pixel_x
GLOB.blood_target_image.pixel_y = -target.pixel_y
C.cult_team.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
C.cult_team.blood_target_image.appearance_flags = RESET_COLOR
C.cult_team.blood_target_image.pixel_x = -target.pixel_x
C.cult_team.blood_target_image.pixel_y = -target.pixel_y
for(var/datum/mind/B in SSticker.mode.cult)
if(B.current && B.current.stat != DEAD && B.current.client)
to_chat(B.current, "<span class='cultlarge'><b>Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!</b></span>")
to_chat(B.current, "<span class='cultlarge'><b>Master [ranged_ability_user] has marked [C.cult_team.blood_target] in the [A.name] as the cult's top priority, get there immediately!</b></span>")
SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75))
B.current.client.images += GLOB.blood_target_image
B.current.client.images += C.cult_team.blood_target_image
attached_action.owner.update_action_buttons_icon()
remove_ranged_ability("<span class='cult'>The marking rite is complete! It will last for 90 seconds.</span>")
GLOB.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target), 900, TIMER_STOPPABLE)
C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target,C.cult_team), 900, TIMER_STOPPABLE)
return TRUE
return FALSE
/proc/reset_blood_target()
for(var/datum/mind/B in SSticker.mode.cult)
/proc/reset_blood_target(datum/team/cult/team)
for(var/datum/mind/B in team.members)
if(B.current && B.current.stat != DEAD && B.current.client)
if(GLOB.blood_target)
if(team.blood_target)
to_chat(B.current,"<span class='cultlarge'><b>The blood mark has expired!</b></span>")
B.current.client.images -= GLOB.blood_target_image
QDEL_NULL(GLOB.blood_target_image)
GLOB.blood_target = null
B.current.client.images -= team.blood_target_image
QDEL_NULL(team.blood_target_image)
team.blood_target = null
+17 -9
View File
@@ -179,6 +179,13 @@ This file contains the arcane tome files.
var/list/shields = list()
var/area/A = get_area(src)
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!user_antag)
return
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives
if(!check_rune_turf(Turf, user))
return
entered_rune_name = input(user, "Choose a rite to scribe.", "Sigils of Power") as null|anything in GLOB.rune_types
@@ -196,18 +203,20 @@ This file contains the arcane tome files.
A = get_area(src)
if(!src || QDELETED(src) || !Adjacent(user) || user.incapacitated() || !check_rune_turf(Turf, user))
return
//AAAAAAAAAAAAAAAH, i'm rewriting enough for now so TODO: remove this shit
if(ispath(rune_to_scribe, /obj/effect/rune/narsie))
if(!("eldergod" in SSticker.mode.cult_objectives))
if(!summon_objective)
to_chat(user, "<span class='warning'>Nar-Sie does not wish to be summoned!</span>")
return
if(!GLOB.sac_complete)
if(sac_objective && !sac_objective.check_completion())
to_chat(user, "<span class='warning'>The sacrifice is not complete. The portal would lack the power to open if you tried!</span>")
return
if(!SSticker.mode.eldergod)
if(summon_objective.check_completion())
to_chat(user, "<span class='cultlarge'>\"I am already here. There is no need to try to summon me now.\"</span>")
return
if(!(A in GLOB.summon_spots))
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!</span>")
if(!(A in summon_objective.summon_spots))
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!</span>")
return
var/confirm_final = alert(user, "This is the FINAL step to summon Nar-Sie; it is a long, painful ritual and the crew will be alerted to your presence", "Are you prepared for the final battle?", "My life for Nar-Sie!", "No")
if(confirm_final == "No")
@@ -215,8 +224,8 @@ This file contains the arcane tome files.
return
Turf = get_turf(user)
A = get_area(src)
if(!(A in GLOB.summon_spots)) // Check again to make sure they didn't move
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(GLOB.summon_spots)]!</span>")
if(!(A in summon_objective.summon_spots)) // Check again to make sure they didn't move
to_chat(user, "<span class='cultlarge'>The Geometer can only be summoned where the veil is weak - in [english_list(summon_objective.summon_spots)]!</span>")
return
priority_announce("Figments from an eldritch god are being summoned by [user] into [A.map_name] from an unknown dimension. Disrupt the ritual at all costs!","Central Command Higher Dimensional Affairs", 'sound/ai/spanomalies.ogg')
for(var/B in spiral_range_turfs(1, user, 1))
@@ -256,8 +265,7 @@ This file contains the arcane tome files.
if(locate(/obj/effect/rune) in T)
to_chat(user, "<span class='cult'>There is already a rune here.</span>")
return FALSE
if(!(T.z in GLOB.station_z_levels) && T.z != ZLEVEL_MINING)
if(!is_station_level(T.z) && !is_mining_level(T.z))
to_chat(user, "<span class='warning'>The veil is not weak enough here.</span>")
return FALSE
+40 -38
View File
@@ -115,7 +115,7 @@ structure_check() searches for nearby cultist structures required for the invoca
continue
if(ishuman(L))
var/mob/living/carbon/human/H = L
if((H.disabilities & MUTE) || H.silent)
if((H.has_disability(DISABILITY_MUTE)) || H.silent)
continue
if(L.stat)
continue
@@ -268,7 +268,7 @@ structure_check() searches for nearby cultist structures required for the invoca
var/list/teleportnames = list()
for(var/R in GLOB.teleport_runes)
var/obj/effect/rune/teleport/T = R
if(T != src && (T.z <= ZLEVEL_SPACEMAX))
if(T != src && !is_away_level(T.z))
potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T
if(!potential_runes.len)
@@ -277,8 +277,9 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
return
if(user.z > ZLEVEL_SPACEMAX)
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
var/turf/T = get_turf(src)
if(is_away_level(T.z))
to_chat(user, "<span class='cult italic'>You are not in the right dimension!</span>")
log_game("Teleport rune failed - user in away mission")
fail_invoke()
return
@@ -289,7 +290,6 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
return
var/turf/T = get_turf(src)
var/turf/target = get_turf(actual_selected_rune)
if(is_blocked_turf(target, TRUE))
to_chat(user, "<span class='warning'>The target rune is blocked. Attempting to teleport to it would be massively unwise.</span>")
@@ -349,7 +349,11 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_DARKRED
var/mob/living/L = pick(myriad_targets)
var/is_clock = is_servant_of_ratvar(L)
var/is_convertable = is_convertable_to_cult(L)
var/mob/living/F = invokers[1]
var/datum/antagonist/cult/C = F.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
var/is_convertable = is_convertable_to_cult(L,C.cult_team)
if(L.stat != DEAD && (is_clock || is_convertable))
invocation = "Mah'weyh pleggh at e'ntrath!"
..()
@@ -397,17 +401,27 @@ structure_check() searches for nearby cultist structures required for the invoca
return 1
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
var/mob/living/first_invoker = invokers[1]
if(!first_invoker)
return FALSE
var/datum/antagonist/cult/C = first_invoker.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C)
return
var/big_sac = FALSE
if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
for(var/M in invokers)
to_chat(M, "<span class='cultitalic'>[sacrificial] is too greatly linked to the world! You need three acolytes!</span>")
log_game("Offer rune failed - not enough acolytes and target is living or sac target")
return FALSE
if(sacrificial.mind)
GLOB.sacrificed += sacrificial.mind
if(is_sacrifice_target(sacrificial.mind))
GLOB.sac_complete = TRUE
big_sac = TRUE
for(var/datum/objective/sacrifice/sac_objective in C.cult_team.objectives)
if(sac_objective.target == sacrificial.mind)
sac_objective.sacced = TRUE
sac_objective.update_explanation_text()
big_sac = TRUE
else
GLOB.sacrificed += sacrificial
@@ -465,7 +479,7 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/narsie/invoke(var/list/invokers)
if(used)
return
if(!(z in GLOB.station_z_levels))
if(!is_station_level(z))
return
if(locate(/obj/singularity/narsie) in GLOB.poi_list)
@@ -481,7 +495,6 @@ structure_check() searches for nearby cultist structures required for the invoca
sleep(40)
if(src)
color = RUNE_COLOR_RED
SSticker.mode.eldergod = FALSE
new /obj/singularity/narsie/large/cult(T) //Causes Nar-Sie to spawn even if the rune has been removed
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
@@ -497,10 +510,10 @@ structure_check() searches for nearby cultist structures required for the invoca
message_admins("[key_name_admin(user)] erased a Narsie rune with a null rod")
..()
//Rite of Resurrection: Requires a dead or inactive cultist. When reviving the dead, you can only perform one revival for every sacrifice your cult has carried out.
//Rite of Resurrection: Requires the corpse of a cultist and that there have been less revives than the number of people GLOB.sacrificed
/obj/effect/rune/raise_dead
cultist_name = "Revive Cultist"
cultist_desc = "requires a dead, mindless, or inactive cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be given a new life."
cultist_name = "Resurrect Cultist"
cultist_desc = "requires the corpse of a cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be revived."
invocation = "Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!" //Depends on the name of the user - see below
icon_state = "1"
color = RUNE_COLOR_MEDIUMRED
@@ -521,11 +534,16 @@ structure_check() searches for nearby cultist structures required for the invoca
return
rune_in_use = TRUE
for(var/mob/living/M in T.contents)
if(iscultist(M) && (M.stat == DEAD || !M.client || M.client.is_afk()))
if(iscultist(M) && M.stat == DEAD)
potential_revive_mobs |= M
if(!potential_revive_mobs.len)
to_chat(user, "<span class='cultitalic'>There are no dead cultists on the rune!</span>")
log_game("Raise Dead rune failed - no cultists to revive")
log_game("Raise Dead rune failed - no corpses to revive")
fail_invoke()
rune_in_use = FALSE
return
if(LAZYLEN(GLOB.sacrificed) <= revives_used)
to_chat(user, "<span class='warning'>You have sacrificed too few people to revive a cultist!</span>")
fail_invoke()
rune_in_use = FALSE
return
@@ -541,25 +559,9 @@ structure_check() searches for nearby cultist structures required for the invoca
else
invocation = initial(invocation)
..()
if(mob_to_revive.stat == DEAD)
if(LAZYLEN(GLOB.sacrificed) <= revives_used)
to_chat(user, "<span class='warning'>Your cult must carry out another sacrifice before it can revive a cultist!</span>")
fail_invoke()
rune_in_use = FALSE
return
revives_used++
mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
mob_to_revive.grab_ghost()
else if(!mob_to_revive.client || mob_to_revive.client.is_afk())
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", "[name]", null, "Blood Cultist", 50, mob_to_revive)
var/mob/dead/observer/theghost = null
if(candidates.len)
theghost = pick(candidates)
to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.")
mob_to_revive.ghostize(0)
mob_to_revive.key = theghost.key
revives_used++
mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
mob_to_revive.grab_ghost()
to_chat(mob_to_revive, "<span class='cultlarge'>\"PASNAR SAVRAE YAM'TOTH. Arise.\"</span>")
mob_to_revive.visible_message("<span class='warning'>[mob_to_revive] draws in a huge breath, red light shining from [mob_to_revive.p_their()] eyes.</span>", \
"<span class='cultlarge'>You awaken suddenly from the void. You're alive!</span>")
@@ -813,8 +815,8 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
log_game("Summon Cultist rune failed - target was deconverted")
return
if(cultist_to_summon.z > ZLEVEL_SPACEMAX)
to_chat(user, "<span class='cultitalic'>[cultist_to_summon] is not in our dimension!</span>")
if(is_away_level(cultist_to_summon.z))
to_chat(user, "<span class='cult italic'>[cultist_to_summon] is not in our dimension!</span>")
fail_invoke()
log_game("Summon Cultist rune failed - target in away mission")
return
+2 -2
View File
@@ -65,8 +65,8 @@
log_game("Teleport talisman failed - no other teleport runes")
return ..(user, 0)
if(user.z > ZLEVEL_SPACEMAX)
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
if(is_away_level(user.z))
to_chat(user, "<span class='cult italic'>You are not in the right dimension!</span>")
log_game("Teleport talisman failed - user in away mission")
return ..(user, 0)
-38
View File
@@ -3,32 +3,6 @@
var/list/datum/mind/devils = list()
var/devil_ascended = 0 // Number of arch devils on station
/datum/game_mode/proc/auto_declare_completion_sintouched()
var/text = ""
if(sintouched.len)
text += "<br><span class='big'><b>The sintouched were:</b></span>"
var/list/sintouchedUnique = uniqueList(sintouched)
for(var/S in sintouchedUnique)
var/datum/mind/sintouched_mind = S
text += printplayer(sintouched_mind)
text += printobjectives(sintouched_mind)
text += "<br>"
text += "<br>"
to_chat(world, text)
/datum/game_mode/proc/auto_declare_completion_devils()
/var/text = ""
if(devils.len)
text += "<br><span class='big'><b>The devils were:</b></span>"
for(var/D in devils)
var/datum/mind/devil = D
text += printplayer(devil)
text += printdevilinfo(devil.current)
text += printobjectives(devil)
text += "<br>"
text += "<br>"
to_chat(world, text)
/datum/game_mode/proc/add_devil_objectives(datum/mind/devil_mind, quantity)
var/list/validtypes = list(/datum/objective/devil/soulquantity, /datum/objective/devil/soulquality, /datum/objective/devil/sintouch, /datum/objective/devil/buy_target)
for(var/i = 1 to quantity)
@@ -41,18 +15,6 @@
else
objective.find_target()
/datum/game_mode/proc/printdevilinfo(mob/living/ply)
var/datum/antagonist/devil/devilinfo = is_devil(ply)
if(!devilinfo)
return "Target is not a devil."
var/text = "</br>The devil's true name is: [devilinfo.truename]</br>"
text += "The devil's bans were:</br>"
text += " [GLOB.lawlorify[LORE][devilinfo.ban]]</br>"
text += " [GLOB.lawlorify[LORE][devilinfo.bane]]</br>"
text += " [GLOB.lawlorify[LORE][devilinfo.obligation]]</br>"
text += " [GLOB.lawlorify[LORE][devilinfo.banish]]</br></br>"
return text
/datum/game_mode/proc/update_devil_icons_added(datum/mind/devil_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_DEVIL]
hud.join_hud(devil_mind.current)
@@ -67,10 +67,7 @@
//Left hand items
for(var/obj/item/I in held_items)
if(!(I.flags_1 & ABSTRACT_1))
if(I.blood_DNA)
msg += "<span class='warning'>It is holding [icon2html(I, user)] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!</span>\n"
else
msg += "It is holding [icon2html(I, user)] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n"
msg += "It is holding [I.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(I))].\n"
//Braindead
if(!client && stat != DEAD)
+6 -6
View File
@@ -1,7 +1,7 @@
/proc/power_failure()
priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", 'sound/ai/poweroff.ogg')
for(var/obj/machinery/power/smes/S in GLOB.machines)
if(istype(get_area(S), /area/ai_monitored/turret_protected) || !(S.z in GLOB.station_z_levels))
if(istype(get_area(S), /area/ai_monitored/turret_protected) || !is_station_level(S.z))
continue
S.charge = 0
S.output_level = 0
@@ -22,7 +22,7 @@
break
if(A.contents)
for(var/atom/AT in A.contents)
if(!(AT.z in GLOB.station_z_levels)) //Only check one, it's enough.
if(!is_station_level(AT.z)) //Only check one, it's enough.
skip = 1
break
if(skip)
@@ -33,7 +33,7 @@
A.power_change()
for(var/obj/machinery/power/apc/C in GLOB.apcs_list)
if(C.cell && (C.z in GLOB.station_z_levels))
if(C.cell && is_station_level(C.z))
var/area/A = C.area
var/skip = 0
@@ -50,11 +50,11 @@
priority_announce("Power has been restored to [station_name()]. We apologize for the inconvenience.", "Power Systems Nominal", 'sound/ai/poweron.ogg')
for(var/obj/machinery/power/apc/C in GLOB.machines)
if(C.cell && (C.z in GLOB.station_z_levels))
if(C.cell && is_station_level(C.z))
C.cell.charge = C.cell.maxcharge
C.failure_timer = 0
for(var/obj/machinery/power/smes/S in GLOB.machines)
if(!(S.z in GLOB.station_z_levels))
if(!is_station_level(S.z))
continue
S.charge = S.capacity
S.output_level = S.output_level_max
@@ -72,7 +72,7 @@
priority_announce("All SMESs on [station_name()] have been recharged. We apologize for the inconvenience.", "Power Systems Nominal", 'sound/ai/poweron.ogg')
for(var/obj/machinery/power/smes/S in GLOB.machines)
if(!(S.z in GLOB.station_z_levels))
if(!is_station_level(S.z))
continue
S.charge = S.capacity
S.output_level = S.output_level_max
+16 -80
View File
@@ -19,6 +19,7 @@
var/probability = 0
var/false_report_weight = 0 //How often will this show up incorrectly in a centcom report?
var/station_was_nuked = 0 //see nuclearbomb.dm and malfunction.dm
var/nuke_off_station = 0 //Used for tracking where the nuke hit
var/round_ends_with_antag_death = 0 //flags the "one verse the station" antags as such
var/list/datum/mind/antag_candidates = list() // List of possible starting antags goes here
var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist
@@ -73,7 +74,6 @@
/datum/game_mode/proc/pre_setup()
return 1
///Everyone should now be on the station and have their normal gear. This is the place to give the special roles extra things
/datum/game_mode/proc/post_setup(report) //Gamemodes can override the intercept report. Passing TRUE as the argument will force a report.
if(!report)
@@ -241,55 +241,9 @@
return 0
/datum/game_mode/proc/declare_completion()
var/clients = 0
var/surviving_humans = 0
var/surviving_total = 0
var/ghosts = 0
var/escaped_humans = 0
var/escaped_total = 0
for(var/mob/M in GLOB.player_list)
if(M.client)
clients++
if(ishuman(M))
if(!M.stat)
surviving_humans++
if(M.z == ZLEVEL_CENTCOM)
escaped_humans++
if(!M.stat)
surviving_total++
if(M.z == ZLEVEL_CENTCOM)
escaped_total++
if(isobserver(M))
ghosts++
if(clients)
SSblackbox.record_feedback("nested tally", "round_end_stats", clients, list("clients"))
if(ghosts)
SSblackbox.record_feedback("nested tally", "round_end_stats", ghosts, list("ghosts"))
if(surviving_humans)
SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_humans, list("survivors", "human"))
if(surviving_total)
SSblackbox.record_feedback("nested tally", "round_end_stats", surviving_total, list("survivors", "total"))
if(escaped_humans)
SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_humans, list("escapees", "human"))
if(escaped_total)
SSblackbox.record_feedback("nested tally", "round_end_stats", escaped_total, list("escapees", "total"))
send2irc("Server", "Round just ended.")
if(cult.len && !istype(SSticker.mode, /datum/game_mode/cult))
datum_cult_completion()
return 0
/datum/game_mode/proc/check_win() //universal trigger to be called at mob death, nuke explosion, etc. To be called from everywhere.
return 0
/datum/game_mode/proc/send_intercept()
var/intercepttext = "<b><i>Central Command Status Summary</i></b><hr>"
intercepttext += "<b>Central Command has intercepted and partially decoded a Syndicate transmission with vital information regarding their movements. The following report outlines the most \
@@ -451,34 +405,6 @@
for (var/C in GLOB.admins)
to_chat(C, msg)
/datum/game_mode/proc/printplayer(datum/mind/ply, fleecheck)
var/text = "<br><b>[ply.key]</b> was <b>[ply.name]</b> the <b>[ply.assigned_role]</b> and"
if(ply.current)
if(ply.current.stat == DEAD)
text += " <span class='boldannounce'>died</span>"
else
text += " <span class='greenannounce'>survived</span>"
if(fleecheck)
var/turf/T = get_turf(ply.current)
if(!T || !(T.z in GLOB.station_z_levels))
text += " while <span class='boldannounce'>fleeing the station</span>"
if(ply.current.real_name != ply.name)
text += " as <b>[ply.current.real_name]</b>"
else
text += " <span class='boldannounce'>had their body destroyed</span>"
return text
/datum/game_mode/proc/printobjectives(datum/mind/ply)
var/text = ""
var/count = 1
for(var/datum/objective/objective in ply.objectives)
if(objective.check_completion())
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='greenannounce'>Success!</span>"
else
text += "<br><b>Objective #[count]</b>: [objective.explanation_text] <span class='boldannounce'>Fail.</span>"
count++
return text
//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
/datum/game_mode/proc/age_check(client/C)
if(get_remaining_days(C) == 0)
@@ -518,15 +444,25 @@
station_goals += new picked
/datum/game_mode/proc/declare_station_goal_completion()
for(var/V in station_goals)
var/datum/station_goal/G = V
G.print_result()
/datum/game_mode/proc/generate_report() //Generates a small text blurb for the gamemode in centcom report
return "Gamemode report for [name] not set. Contact a coder."
//By default nuke just ends the round
/datum/game_mode/proc/OnNukeExplosion(off_station)
nuke_off_station = off_station
if(off_station < 2)
station_was_nuked = TRUE //Will end the round on next check.
//Additional report section in roundend report
/datum/game_mode/proc/special_report()
return
//Set result and news report here
/datum/game_mode/proc/set_round_result()
SSticker.mode_result = "undefined"
if(station_was_nuked)
SSticker.news_report = STATION_DESTROYED_NUKE
if(EMERGENCY_ESCAPED_OR_ENDGAMED)
SSticker.news_report = STATION_EVACUATED
if(SSshuttle.emergency.is_hijacked())
SSticker.news_report = SHUTTLE_HIJACK
@@ -233,7 +233,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/datum/action/innate/ai/nuke_station/Activate()
var/turf/T = get_turf(owner)
if(!istype(T) || !(T.z in GLOB.station_z_levels))
if(!istype(T) || !is_station_level(T.z))
to_chat(owner, "<span class='warning'>You cannot activate the doomsday device while off-station!</span>")
return
if(alert(owner, "Send arming signal? (true = arm, false = cancel)", "purge_all_life()", "confirm = TRUE;", "confirm = FALSE;") != "confirm = TRUE;")
@@ -356,7 +356,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/obj/machinery/doomsday_device/process()
var/turf/T = get_turf(src)
if(!T || !(T.z in GLOB.station_z_levels))
if(!T || !is_station_level(T.z))
minor_announce("DOOMSDAY DEVICE OUT OF STATION RANGE, ABORTING", "ERROR ER0RR $R0RRO$!R41.%%!!(%$^^__+ @#F0E4", TRUE)
SSshuttle.clearHostileEnvironment(src)
qdel(src)
@@ -378,7 +378,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
for(var/i in GLOB.mob_living_list)
var/mob/living/L = i
var/turf/T = get_turf(L)
if(!T || !(T.z in GLOB.station_z_levels))
if(!T || !is_station_level(T.z))
continue
if(issilicon(L))
continue
@@ -425,7 +425,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/datum/action/innate/ai/lockdown/Activate()
for(var/obj/machinery/door/D in GLOB.airlocks)
if(!(D.z in GLOB.station_z_levels))
if(!is_station_level(D.z))
continue
INVOKE_ASYNC(D, /obj/machinery/door.proc/hostile_lockdown, owner)
addtimer(CALLBACK(D, /obj/machinery/door.proc/disable_lockdown), 900)
@@ -503,7 +503,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/datum/action/innate/ai/break_fire_alarms/Activate()
for(var/obj/machinery/firealarm/F in GLOB.machines)
if(!(F.z in GLOB.station_z_levels))
if(!is_station_level(F.z))
continue
F.emagged = TRUE
to_chat(owner, "<span class='notice'>All thermal sensors on the station have been disabled. Fire alerts will no longer be recognized.</span>")
@@ -530,7 +530,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/datum/action/innate/ai/break_air_alarms/Activate()
for(var/obj/machinery/airalarm/AA in GLOB.machines)
if(!(AA.z in GLOB.station_z_levels))
if(!is_station_level(AA.z))
continue
AA.emagged = TRUE
to_chat(owner, "<span class='notice'>All air alarm safeties on the station have been overriden. Air alarms may now use the Flood environmental mode.</span>")
@@ -753,7 +753,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/datum/action/innate/ai/emergency_lights/Activate()
for(var/obj/machinery/light/L in GLOB.machines)
if(L.z in GLOB.station_z_levels)
if(is_station_level(L.z))
L.no_emergency = TRUE
INVOKE_ASYNC(L, /obj/machinery/light/.proc/update, FALSE)
CHECK_TICK
+10 -11
View File
@@ -25,35 +25,34 @@
if (prob(meteorminutes/2))
wavetype = GLOB.meteors_catastrophic
var/ramp_up_final = Clamp(round(meteorminutes/rampupdelta), 1, 10)
var/ramp_up_final = CLAMP(round(meteorminutes/rampupdelta), 1, 10)
spawn_meteors(ramp_up_final, wavetype)
/datum/game_mode/meteor/declare_completion()
var/text
/datum/game_mode/meteor/special_report()
var/survivors = 0
var/list/survivor_list = list()
for(var/mob/living/player in GLOB.player_list)
if(player.stat != DEAD)
++survivors
if(player.onCentCom())
text += "<br><b><font size=2>[player.real_name] escaped to the safety of CentCom.</font></b>"
survivor_list += "<span class='greentext'>[player.real_name] escaped to the safety of CentCom.</span>"
else if(player.onSyndieBase())
text += "<br><b><font size=2>[player.real_name] escaped to the (relative) safety of Syndicate Space.</font></b>"
survivor_list += "<span class='greentext'>[player.real_name] escaped to the (relative) safety of Syndicate Space.</span>"
else
text += "<br><font size=1>[player.real_name] survived but is stranded without any hope of rescue.</font>"
survivor_list += "<span class='neutraltext'>[player.real_name] survived but is stranded without any hope of rescue.</span>"
if(survivors)
to_chat(world, "<span class='boldnotice'>The following survived the meteor storm</span>:[text]")
return "<span class='header'>The following survived the meteor storm:</span><br>[survivor_list.Join("<br>")]"
else
to_chat(world, "<span class='boldnotice'>Nobody survived the meteor storm!</span>")
return "<span class='redtext big'>Nobody survived the meteor storm!</span>"
SSticker.mode_result = "end - evacuation"
/datum/game_mode/meteor/set_round_result()
..()
return 1
SSticker.mode_result = "end - evacuation"
/datum/game_mode/meteor/generate_report()
return "[pick("Asteroids have", "Meteors have", "Large rocks have", "Stellar minerals have", "Space hail has", "Debris has")] been detected near your station, and a collision is possible, \
@@ -1,19 +1,5 @@
/datum/objective_team/abductor_team
member_name = "abductor"
var/list/objectives = list()
var/team_number
/datum/objective_team/abductor_team/is_solo()
return FALSE
/datum/objective_team/abductor_team/proc/add_objective(datum/objective/O)
O.team = src
O.update_explanation_text()
objectives += O
/datum/game_mode
var/list/datum/mind/abductors = list()
var/list/datum/mind/abductees = list()
/datum/game_mode/abduction
name = "abduction"
@@ -24,7 +10,7 @@
required_players = 15
maximum_players = 50
var/max_teams = 4
var/list/datum/objective_team/abductor_team/abductor_teams = list()
var/list/datum/team/abductor_team/abductor_teams = list()
var/finished = FALSE
var/static/team_count = 0
@@ -51,7 +37,7 @@
if(team_number > max_teams)
return //or should it try to stuff them in anway ?
var/datum/objective_team/abductor_team/team = new
var/datum/team/abductor_team/team = new
team.team_number = team_number
team.name = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
team.add_objective(new/datum/objective/experiment)
@@ -64,6 +50,7 @@
antag_candidates -= scientist
team.members |= scientist
scientist.assigned_role = "Abductor Scientist"
scientist.special_role = "Abductor Scientist"
log_game("[scientist.key] (ckey) has been selected as [team.name] abductor scientist.")
if(!agent)
@@ -71,18 +58,19 @@
antag_candidates -= agent
team.members |= agent
agent.assigned_role = "Abductor Agent"
agent.special_role = "Abductor Agent"
log_game("[agent.key] (ckey) has been selected as [team.name] abductor agent.")
abductor_teams += team
return team
/datum/game_mode/abduction/post_setup()
for(var/datum/objective_team/abductor_team/team in abductor_teams)
for(var/datum/team/abductor_team/team in abductor_teams)
post_setup_team(team)
return ..()
//Used for create antag buttons
/datum/game_mode/abduction/proc/post_setup_team(datum/objective_team/abductor_team/team)
/datum/game_mode/abduction/proc/post_setup_team(datum/team/abductor_team/team)
for(var/datum/mind/M in team.members)
if(M.assigned_role == "Abductor Scientist")
M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_SCIENTIST, team)
@@ -91,7 +79,7 @@
/datum/game_mode/abduction/check_finished()
if(!finished)
for(var/datum/objective_team/abductor_team/team in abductor_teams)
for(var/datum/team/abductor_team/team in abductor_teams)
for(var/datum/objective/O in team.objectives)
if(O.check_completion())
SSshuttle.emergency.request(null, set_coefficient = 0.5)
@@ -99,35 +87,6 @@
return ..()
return ..()
/datum/game_mode/abduction/declare_completion()
for(var/datum/objective_team/abductor_team/team in abductor_teams)
var/won = TRUE
for(var/datum/objective/O in team.objectives)
if(!O.check_completion())
won = FALSE
if(won)
to_chat(world, "<span class='greenannounce'>[team.name] team fulfilled its mission!</span>")
else
to_chat(world, "<span class='boldannounce'>[team.name] team failed its mission.</span>")
..()
return TRUE
/datum/game_mode/proc/auto_declare_completion_abduction()
var/text = ""
if(abductors.len)
text += "<br><span class='big'><b>The abductors were:</b></span>"
for(var/datum/mind/abductor_mind in abductors)
text += printplayer(abductor_mind)
text += printobjectives(abductor_mind)
text += "<br>"
if(abductees.len)
text += "<br><span class='big'><b>The abductees were:</b></span>"
for(var/datum/mind/abductee_mind in abductees)
text += printplayer(abductee_mind)
text += printobjectives(abductee_mind)
text += "<br>"
to_chat(world, text)
// LANDMARKS
/obj/effect/landmark/abductor
var/team_number = 1
@@ -144,9 +103,9 @@
/datum/objective/experiment/check_completion()
for(var/obj/machinery/abductor/experiment/E in GLOB.machines)
if(!istype(team, /datum/objective_team/abductor_team))
if(!istype(team, /datum/team/abductor_team))
return FALSE
var/datum/objective_team/abductor_team/T = team
var/datum/team/abductor_team/T = team
if(E.team_number == T.team_number)
return E.points >= target_amount
return FALSE
@@ -2,6 +2,8 @@
#define VEST_COMBAT 2
#define GIZMO_SCAN 1
#define GIZMO_MARK 2
#define MIND_DEVICE_MESSAGE 1
#define MIND_DEVICE_CONTROL 2
//AGENT VEST
/obj/item/clothing/suit/armor/abductor/vest
@@ -278,6 +280,84 @@
if(!istype(I, /obj/item/device/radio/headset))
r.broadcasting = 0 //goddamned headset hacks
/obj/item/device/abductor/mind_device
name = "mental interface device"
desc = "A dual-mode tool for directly communicating with sentient brains. It can be used to send a direct message to a target, \
or to send a command to a test subject with a charged gland."
icon_state = "mind_device_message"
item_state = "silencer"
lefthand_file = 'icons/mob/inhands/antag/abductor_lefthand.dmi'
righthand_file = 'icons/mob/inhands/antag/abductor_righthand.dmi'
var/mode = MIND_DEVICE_MESSAGE
/obj/item/device/abductor/mind_device/attack_self(mob/user)
if(!ScientistCheck(user))
return
if(mode == MIND_DEVICE_MESSAGE)
mode = MIND_DEVICE_CONTROL
icon_state = "mind_device_control"
else
mode = MIND_DEVICE_MESSAGE
icon_state = "mind_device_message"
to_chat(user, "<span class='notice'>You switch the device to [mode==MIND_DEVICE_MESSAGE? "TRANSMISSION": "COMMAND"] MODE</span>")
/obj/item/device/abductor/mind_device/afterattack(atom/target, mob/living/user, flag, params)
if(!ScientistCheck(user))
return
switch(mode)
if(MIND_DEVICE_CONTROL)
mind_control(target, user)
if(MIND_DEVICE_MESSAGE)
mind_message(target, user)
/obj/item/device/abductor/mind_device/proc/mind_control(atom/target, mob/living/user)
if(iscarbon(target))
var/mob/living/carbon/C = target
var/obj/item/organ/heart/gland/G = C.getorganslot("heart")
if(!istype(G))
to_chat(user, "<span class='warning'>Your target does not have an experimental gland!</span>")
return
if(!G.mind_control_uses)
to_chat(user, "<span class='warning'>Your target's gland is spent!</span>")
return
if(G.active_mind_control)
to_chat(user, "<span class='warning'>Your target is already under a mind-controlling influence!</span>")
return
var/command = stripped_input(user, "Enter the command for your target to follow.\
Uses Left: [G.mind_control_uses], Duration: [G.mind_control_duration / 10] seconds","Enter command")
if(!command)
return
if(QDELETED(user) || user.get_active_held_item() != src || loc != user)
return
if(QDELETED(G))
return
G.mind_control(command, user)
to_chat(user, "<span class='notice'>You send the command to your target.</span>")
/obj/item/device/abductor/mind_device/proc/mind_message(atom/target, mob/living/user)
if(isliving(target))
var/mob/living/L = target
if(L.stat == DEAD)
to_chat(user, "<span class='warning'>Your target is dead!</span>")
return
var/message = stripped_input(user, "Write a message to send to your target's brain.","Enter message")
if(!message)
return
if(QDELETED(L) || L.stat == DEAD)
return
to_chat(L, "<span class='italics'>You hear a voice in your head saying: </span><span class='abductor'>[message]</span>")
to_chat(user, "<span class='notice'>You send the message to your target.</span>")
log_talk(user,"[key_name(user)] sent an abductor mind message to [L]/[L.ckey]: '[message]'", LOGSAY)
/obj/item/device/firing_pin/abductor
name = "alien firing pin"
icon_state = "firing_pin_ayy"
@@ -496,8 +576,8 @@ Congratulations! You are now trained for invasive xenobiology research!"}
flags_1 = DROPDEL_1
/obj/item/restraints/handcuffs/energy/used/dropped(mob/user)
user.visible_message("<span class='danger'>[user]'s [src] break in a discharge of energy!</span>", \
"<span class='userdanger'>[user]'s [src] break in a discharge of energy!</span>")
user.visible_message("<span class='danger'>[user]'s [name] breaks in a discharge of energy!</span>", \
"<span class='userdanger'>[user]'s [name] breaks in a discharge of energy!</span>")
var/datum/effect_system/spark_spread/S = new
S.set_up(4,0,user.loc)
S.start()
@@ -12,28 +12,68 @@
var/human_only = 0
var/active = 0
var/mind_control_uses = 1
var/mind_control_duration = 1800
var/active_mind_control = FALSE
/obj/item/organ/heart/gland/proc/ownerCheck()
if(ishuman(owner))
return 1
return TRUE
if(!human_only && iscarbon(owner))
return 1
return 0
return TRUE
return FALSE
/obj/item/organ/heart/gland/proc/Start()
active = 1
next_activation = world.time + rand(cooldown_low,cooldown_high)
/obj/item/organ/heart/gland/proc/update_gland_hud()
if(!owner)
return
var/image/holder = owner.hud_list[GLAND_HUD]
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
holder.pixel_y = I.Height() - world.icon_size
if(active_mind_control)
holder.icon_state = "hudgland_active"
else if(mind_control_uses)
holder.icon_state = "hudgland_ready"
else
holder.icon_state = "hudgland_spent"
/obj/item/organ/heart/gland/Remove(var/mob/living/carbon/M, special = 0)
/obj/item/organ/heart/gland/proc/mind_control(command, mob/living/user)
if(!ownerCheck() || !mind_control_uses || active_mind_control)
return
mind_control_uses--
to_chat(owner, "<span class='userdanger'>You suddenly feel an irresistible compulsion to follow an order...</span>")
to_chat(owner, "<span class='mind_control'>[command]</span>")
active_mind_control = TRUE
log_admin("[key_name(user)] sent an abductor mind control message to [key_name(owner)]: [command]")
update_gland_hud()
addtimer(CALLBACK(src, .proc/clear_mind_control), mind_control_duration)
/obj/item/organ/heart/gland/proc/clear_mind_control()
if(!ownerCheck() || !active_mind_control)
return
to_chat(owner, "<span class='userdanger'>You feel the compulsion fade, and you completely forget about your previous orders.</span>")
active_mind_control = FALSE
/obj/item/organ/heart/gland/Remove(mob/living/carbon/M, special = 0)
active = 0
if(initial(uses) == 1)
uses = initial(uses)
var/datum/atom_hud/abductor/hud = GLOB.huds[DATA_HUD_ABDUCTOR]
hud.remove_from_hud(owner)
clear_mind_control()
..()
/obj/item/organ/heart/gland/Insert(var/mob/living/carbon/M, special = 0)
/obj/item/organ/heart/gland/Insert(mob/living/carbon/M, special = 0)
..()
if(special != 2 && uses) // Special 2 means abductor surgery
Start()
var/datum/atom_hud/abductor/hud = GLOB.huds[DATA_HUD_ABDUCTOR]
hud.add_to_hud(owner)
update_gland_hud()
/obj/item/organ/heart/gland/on_life()
if(!beating)
@@ -59,6 +99,8 @@
cooldown_high = 400
uses = -1
icon_state = "health"
mind_control_uses = 3
mind_control_duration = 3000
/obj/item/organ/heart/gland/heals/activate()
to_chat(owner, "<span class='notice'>You feel curiously revitalized.</span>")
@@ -71,6 +113,8 @@
cooldown_high = 1200
uses = -1
icon_state = "slime"
mind_control_uses = 1
mind_control_duration = 2400
/obj/item/organ/heart/gland/slime/activate()
to_chat(owner, "<span class='warning'>You feel nauseous!</span>")
@@ -86,6 +130,8 @@
cooldown_high = 300
uses = -1
icon_state = "mindshock"
mind_control_uses = 1
mind_control_duration = 6000
/obj/item/organ/heart/gland/mindshock/activate()
to_chat(owner, "<span class='notice'>You get a headache.</span>")
@@ -103,6 +149,8 @@
uses = -1
human_only = 1
icon_state = "species"
mind_control_uses = 5
mind_control_duration = 300
/obj/item/organ/heart/gland/pop/activate()
to_chat(owner, "<span class='notice'>You feel unlike yourself.</span>")
@@ -114,6 +162,8 @@
cooldown_high = 2400
uses = 1
icon_state = "vent"
mind_control_uses = 4
mind_control_duration = 1800
/obj/item/organ/heart/gland/ventcrawling/activate()
to_chat(owner, "<span class='notice'>You feel very stretchy.</span>")
@@ -125,6 +175,8 @@
cooldown_high = 2400
uses = 1
icon_state = "viral"
mind_control_uses = 1
mind_control_duration = 1800
/obj/item/organ/heart/gland/viral/activate()
to_chat(owner, "<span class='warning'>You feel sick.</span>")
@@ -141,6 +193,8 @@
cooldown_high = 1600
uses = 10
icon_state = "emp"
mind_control_uses = 1
mind_control_duration = 1800
/obj/item/organ/heart/gland/emp/activate()
to_chat(owner, "<span class='warning'>You feel a spike of pain in your head.</span>")
@@ -151,6 +205,8 @@
cooldown_high = 900
uses = 10
icon_state = "spider"
mind_control_uses = 2
mind_control_duration = 2400
/obj/item/organ/heart/gland/spiderman/activate()
to_chat(owner, "<span class='warning'>You feel something crawling in your skin.</span>")
@@ -164,6 +220,8 @@
icon_state = "egg"
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
mind_control_uses = 2
mind_control_duration = 1800
/obj/item/organ/heart/gland/egg/activate()
to_chat(owner, "<span class='boldannounce'>You lay an egg!</span>")
@@ -175,6 +233,8 @@
cooldown_low = 200
cooldown_high = 400
uses = -1
mind_control_uses = 1
mind_control_duration = 450
/obj/item/organ/heart/gland/bloody/activate()
owner.blood_volume -= 20
@@ -192,6 +252,8 @@
cooldown_high = 600
human_only = 1
uses = 1
mind_control_uses = 1
mind_control_duration = 600
/obj/item/organ/heart/gland/bodysnatch/activate()
to_chat(owner, "<span class='warning'>You feel something moving around inside you...</span>")
@@ -233,6 +295,8 @@
cooldown_low = 1200
cooldown_high = 1800
uses = -1
mind_control_uses = 1
mind_control_duration = 800
/obj/item/organ/heart/gland/plasma/activate()
to_chat(owner, "<span class='warning'>You feel bloated.</span>")
@@ -48,6 +48,7 @@
dat += "<a href='?src=[REF(src)];dispense=vest'>Agent Vest</A><br>"
dat += "<a href='?src=[REF(src)];dispense=silencer'>Radio Silencer</A><br>"
dat += "<a href='?src=[REF(src)];dispense=tool'>Science Tool</A><br>"
dat += "<a href='?src=[REF(src)];dispense=mind_device'>Mental Interface Device</A><br>"
else
dat += "<span class='bad'>NO EXPERIMENT MACHINE DETECTED</span> <br>"
@@ -109,6 +110,8 @@
Dispense(/obj/item/device/abductor/gizmo)
if("vest")
Dispense(/obj/item/clothing/suit/armor/abductor/vest)
if("mind_device")
Dispense(/obj/item/device/abductor/mind_device,cost=2)
updateUsrDialog()
/obj/machinery/abductor/console/proc/TeleporterRetrieve()
@@ -151,13 +151,18 @@
var/mob/living/mob_occupant = occupant
if(mob_occupant.stat != DEAD)
if(href_list["experiment"])
flash = Experiment(occupant,href_list["experiment"])
flash = Experiment(occupant,href_list["experiment"],usr)
updateUsrDialog()
add_fingerprint(usr)
/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type)
/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type,mob/user)
LAZYINITLIST(history)
var/mob/living/carbon/human/H = occupant
var/datum/antagonist/abductor/user_abductor = user.mind.has_antag_datum(/datum/antagonist/abductor)
if(!user_abductor)
return "<span class='bad'>Authorization failure. Contact mothership immidiately.</span>"
var/point_reward = 0
if(H in history)
return "<span class='bad'>Specimen already in database.</span>"
@@ -182,15 +187,8 @@
if(3)
to_chat(H, "<span class='warning'>You feel intensely watched.</span>")
sleep(5)
to_chat(H, "<span class='warning'><b>Your mind snaps!</b></span>")
H.gain_trauma_type(BRAIN_TRAUMA_MILD)
to_chat(H, "<big><span class='warning'><b>You can't remember how you got here...</b></span></big>")
var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
var/datum/objective/abductee/O = new objtype()
SSticker.mode.abductees += H.mind
H.mind.objectives += O
H.mind.announce_objectives()
SSticker.mode.update_abductor_icons_added(H.mind)
user_abductor.team.abductees += H.mind
H.mind.add_antag_datum(/datum/antagonist/abductee)
for(var/obj/item/organ/heart/gland/G in H.internal_organs)
G.Start()
@@ -27,7 +27,7 @@
if(QDELETED(temp_vent))
continue
if(temp_vent.loc.z == ZLEVEL_STATION_PRIMARY && !temp_vent.welded)
var/datum/pipeline/temp_vent_parent = temp_vent.PARENT1
var/datum/pipeline/temp_vent_parent = temp_vent.parents[1]
if(temp_vent_parent.other_atmosmch.len > 20)
vents += temp_vent
@@ -454,7 +454,7 @@
if(target == src)
return
if(!(z in GLOB.station_z_levels) && z != ZLEVEL_LAVALAND)
if(!is_station_level(z) && !is_mining_level(z))
to_chat(src, "<span class='warning'>Our bluespace transceiver cannot locate a viable bluespace link, our teleportation abilities are useless in this area.</span>")
return
+56 -41
View File
@@ -1,5 +1,6 @@
/datum/game_mode
var/list/ape_infectees = list()
var/list/ape_leaders = list()
/datum/game_mode/monkey
name = "monkey"
@@ -21,6 +22,9 @@
var/players_per_carrier = 30
var/datum/team/monkey/monkey_team
/datum/game_mode/monkey/pre_setup()
carriers_to_make = max(round(num_players()/players_per_carrier, 1), 1)
@@ -30,88 +34,99 @@
break
var/datum/mind/carrier = pick(antag_candidates)
carriers += carrier
carrier.special_role = "monkey"
carrier.special_role = "Monkey Leader"
carrier.restricted_roles = restricted_jobs
log_game("[carrier.key] (ckey) has been selected as a Jungle Fever carrier")
antag_candidates -= carrier
if(!carriers.len)
return 0
return 1
return FALSE
return TRUE
/datum/game_mode/monkey/announce()
to_chat(world, "<B>The current game mode is - Monkey!</B>")
to_chat(world, "<B>One or more crewmembers have been infected with Jungle Fever! Crew: Contain the outbreak. None of the infected monkeys may escape alive to CentCom. Monkeys: Ensure that your kind lives on! Rise up against your captors!</B>")
/datum/game_mode/monkey/proc/greet_carrier(datum/mind/carrier)
to_chat(carrier.current, "<B><span class='notice'>You are the Jungle Fever patient zero!!</B></span>")
to_chat(carrier.current, "<b>You have been planted onto this station by the Animal Rights Consortium.</b>")
to_chat(carrier.current, "<b>Soon the disease will transform you into an ape. Afterwards, you will be able spread the infection to others with a bite.</b>")
to_chat(carrier.current, "<b>While your infection strain is undetectable by scanners, any other infectees will show up on medical equipment.</b>")
to_chat(carrier.current, "<b>Your mission will be deemed a success if any of the live infected monkeys reach CentCom.</b>")
carrier.current.playsound_local(get_turf(carrier.current), 'sound/ambience/antag/monkey.ogg', 100, FALSE, pressure_affected = FALSE)
return
/datum/game_mode/monkey/post_setup()
for(var/datum/mind/carriermind in carriers)
greet_carrier(carriermind)
ape_infectees += carriermind
var/datum/disease/D = new /datum/disease/transformation/jungle_fever
D.visibility_flags = HIDDEN_SCANNER|HIDDEN_PANDEMIC
D.affected_mob = carriermind.current
carriermind.current.viruses += D
..()
var/datum/antagonist/monkey/M = add_monkey_leader(carriermind, monkey_team)
if(M)
monkey_team = M.monkey_team
return ..()
/datum/game_mode/monkey/check_finished()
if((SSshuttle.emergency.mode == SHUTTLE_ENDGAME) || station_was_nuked)
return 1
return TRUE
if(!round_converted)
for(var/datum/mind/monkey_mind in ape_infectees)
continuous_sanity_checked = 1
continuous_sanity_checked = TRUE
if(monkey_mind.current && monkey_mind.current.stat != DEAD)
return 0
return FALSE
var/datum/disease/D = new /datum/disease/transformation/jungle_fever() //ugly but unfortunately needed
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
if(H.mind && H.stat != DEAD)
if(!is_station_level(H.z))
continue
if(H.mind && H.client && H.stat != DEAD)
if(H.HasDisease(D))
return 0
return FALSE
..()
return ..()
/datum/game_mode/monkey/proc/check_monkey_victory()
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
return 0
return FALSE
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if (M.HasDisease(D))
if(M.onCentCom() || M.onSyndieBase())
escaped_monkeys++
if(escaped_monkeys >= monkeys_to_win)
return 1
return TRUE
else
return 0
/datum/game_mode/proc/add_monkey(datum/mind/monkey_mind)
ape_infectees |= monkey_mind
monkey_mind.special_role = "Infected Monkey"
/datum/game_mode/proc/remove_monkey(datum/mind/monkey_mind)
ape_infectees.Remove(monkey_mind)
monkey_mind.special_role = null
return FALSE
/datum/game_mode/monkey/declare_completion()
/datum/game_mode/monkey/set_round_result()
..()
if(check_monkey_victory())
SSticker.mode_result = "win - monkey win"
to_chat(world, "<span class='userdanger'>The monkeys have overthrown their captors! Eeek eeeek!!</span>")
else
SSticker.mode_result = "loss - staff stopped the monkeys"
to_chat(world, "<span class='userdanger'>The staff managed to contain the monkey infestation!</span>")
/datum/game_mode/monkey/special_report()
if(check_monkey_victory())
return "<span class='redtext big'>The monkeys have overthrown their captors! Eeek eeeek!!</span>"
else
return "<span class='redtext big'>The staff managed to contain the monkey infestation!</span>"
/datum/game_mode/monkey/generate_report()
return "Reports of an ancient [pick("retrovirus", "flesh eating bacteria", "disease", "magical curse blamed on viruses", "banana blight")] outbreak that turn humans into monkeys has been reported in your quadrant. Any such infections may be treated with banana juice. If an outbreak occurs, ensure the station is quarantined to prevent a largescale outbreak at CentCom."
/proc/add_monkey_leader(datum/mind/monkey_mind)
if(is_monkey_leader(monkey_mind))
return FALSE
var/datum/antagonist/monkey/leader/M = monkey_mind.add_antag_datum(ANTAG_DATUM_MONKEY_LEADER)
return M
/proc/add_monkey(datum/mind/monkey_mind)
if(is_monkey(monkey_mind))
return FALSE
var/datum/antagonist/monkey/M = monkey_mind.add_antag_datum(ANTAG_DATUM_MONKEY)
return M
/proc/remove_monkey(datum/mind/monkey_mind)
if(!is_monkey(monkey_mind))
return FALSE
var/datum/antagonist/monkey/M = monkey_mind.has_antag_datum(ANTAG_DATUM_MONKEY)
M.on_removal()
return TRUE
/proc/is_monkey_leader(datum/mind/monkey_mind)
return monkey_mind && monkey_mind.has_antag_datum(ANTAG_DATUM_MONKEY_LEADER)
/proc/is_monkey(datum/mind/monkey_mind)
return monkey_mind && (monkey_mind.has_antag_datum(ANTAG_DATUM_MONKEY) || is_monkey_leader(monkey_mind))
@@ -227,6 +227,7 @@
player_mind.assigned_role = "Morph"
player_mind.special_role = "Morph"
SSticker.mode.traitors |= player_mind
player_mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
SEND_SOUND(S, sound('sound/magic/mutate.ogg'))
message_admins("[key_name_admin(S)] has been made into a morph by an event.")
@@ -87,6 +87,7 @@
mind.assigned_role = "revenant"
mind.special_role = "Revenant"
SSticker.mode.traitors |= mind //Necessary for announcing
mind.add_antag_datum(/datum/antagonist/auto_custom)
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))
@@ -374,7 +375,7 @@
return
var/key_of_revenant
message_admins("Revenant ectoplasm was left undestroyed for 1 minute and is reforming into a new revenant.")
loc = get_turf(src) //In case it's in a backpack or someone's hand
forceMove(drop_location()) //In case it's in a backpack or someone's hand
revenant.forceMove(loc)
if(client_to_revive)
for(var/mob/M in GLOB.dead_mob_list)
@@ -38,6 +38,7 @@
player_mind.assigned_role = "Slaughter Demon"
player_mind.special_role = "Slaughter Demon"
SSticker.mode.traitors |= player_mind
player_mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
to_chat(S, "<B>You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.</B>")
SEND_SOUND(S, 'sound/magic/demon_dies.ogg')
+61 -239
View File
@@ -1,7 +1,3 @@
/datum/game_mode
var/list/datum/mind/syndicates = list()
var/nukeops_lastname = ""
/datum/game_mode/nuclear
name = "nuclear emergency"
config_tag = "nuclear"
@@ -18,12 +14,11 @@
<span class='notice'>Crew</span>: Defend the nuclear authentication disk and ensure that it leaves with you on the emergency shuttle."
var/const/agents_possible = 5 //If we ever need more syndicate agents.
var/nukes_left = 1 // Call 3714-PRAY right now and order more nukes! Limited offer!
var/nuke_off_station = 0 //Used for tracking if the syndies actually haul the nuke to the station
var/syndies_didnt_escape = 0 //Used for tracking if the syndies got the shuttle off of the z-level
var/list/pre_nukeops = list()
var/datum/team/nuclear/nuke_team
/datum/game_mode/nuclear/pre_setup()
var/n_agents = min(round(num_players() / 10), antag_candidates.len, agents_possible)
for(var/i = 0, i < n_agents, ++i)
@@ -33,120 +28,23 @@
new_op.special_role = "Nuclear Operative"
log_game("[new_op.key] (ckey) has been selected as a nuclear operative")
return TRUE
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
/datum/game_mode/proc/update_synd_icons_added(datum/mind/synd_mind)
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
opshud.join_hud(synd_mind.current)
set_antag_hud(synd_mind.current, "synd")
/datum/game_mode/proc/update_synd_icons_removed(datum/mind/synd_mind)
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
opshud.leave_hud(synd_mind.current)
set_antag_hud(synd_mind.current, null)
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
/datum/game_mode/nuclear/post_setup()
var/nuke_code = random_nukecode()
var/agent_number = 1
var/datum/mind/leader = pick(pre_nukeops)
syndicates += pre_nukeops
for(var/i = 1 to pre_nukeops.len)
var/datum/mind/op = pre_nukeops[i]
forge_syndicate_objectives(op)
greet_syndicate(op)
equip_syndicate(op.current)
if(nuke_code)
op.store_memory("<B>Syndicate Nuclear Bomb Code</B>: [nuke_code]", 0, 0)
to_chat(op.current, "The nuclear authorization code is: <B>[nuke_code]</B>")
if(op == leader)
op.current.forceMove(pick(GLOB.nukeop_leader_start))
prepare_syndicate_leader(op, nuke_code)
else
op.current.forceMove(GLOB.nukeop_start[((i - 1) % GLOB.nukeop_start.len) + 1])
op.current.real_name = "[syndicate_name()] Operative #[agent_number++]"
update_synd_icons_added(op)
op.current.playsound_local(get_turf(op.current), 'sound/ambience/antag/ops.ogg',100,0)
var/obj/machinery/nuclearbomb/nuke = locate("syndienuke") in GLOB.nuke_list
if(nuke)
nuke.r_code = nuke_code
//Assign leader
var/datum/mind/leader_mind = pre_nukeops[1]
var/datum/antagonist/nukeop/L = leader_mind.add_antag_datum(/datum/antagonist/nukeop/leader)
nuke_team = L.nuke_team
//Assign the remaining operatives
for(var/i = 2 to pre_nukeops.len)
var/datum/mind/nuke_mind = pre_nukeops[i]
nuke_mind.add_antag_datum(/datum/antagonist/nukeop,nuke_team)
return ..()
/datum/game_mode/proc/prepare_syndicate_leader(datum/mind/synd_mind, nuke_code)
var/leader_title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
addtimer(CALLBACK(src, .proc/nuketeam_name_assign, synd_mind), 1)
synd_mind.current.real_name = "[syndicate_name()] [leader_title]"
to_chat(synd_mind.current, "<B>You are the Syndicate [leader_title] for this mission. You are responsible for the distribution of telecrystals and your ID is the only one who can open the launch bay doors.</B>")
to_chat(synd_mind.current, "<B>If you feel you are not up to this task, give your ID to another operative.</B>")
to_chat(synd_mind.current, "<B>In your hand you will find a special item capable of triggering a greater challenge for your team. Examine it carefully and consult with your fellow operatives before activating it.</B>")
var/obj/item/device/nuclear_challenge/challenge = new /obj/item/device/nuclear_challenge
synd_mind.current.put_in_hands(challenge, TRUE)
var/static/id_cache = typecacheof(/obj/item/card/id)
var/list/foundIDs = typecache_filter_list(synd_mind.current.GetAllContents(), id_cache)
if(foundIDs.len)
for(var/i in 1 to foundIDs.len)
var/obj/item/card/id/ID = foundIDs[i]
ID.name = "lead agent card"
ID.access += ACCESS_SYNDICATE_LEADER
else
message_admins("Warning: Nuke Ops spawned without access to leave their spawn area!")
var/obj/item/device/radio/headset/syndicate/alt/A = locate() in synd_mind.current
if(A)
A.command = TRUE
if(nuke_code)
var/obj/item/paper/P = new
P.info = "The nuclear authorization code is: <b>[nuke_code]</b>"
P.name = "nuclear bomb code"
var/mob/living/carbon/human/H = synd_mind.current
H.put_in_hands(P, TRUE)
H.update_icons()
else
nuke_code = "code will be provided later"
return
/datum/game_mode/proc/nuketeam_name_assign(datum/mind/synd_mind)
nukeops_lastname = nukelastname(synd_mind.current)
NukeNameAssign(nukeops_lastname, syndicates)
/datum/game_mode/proc/forge_syndicate_objectives(datum/mind/syndicate)
var/datum/objective/nuclear/syndobj = new
syndobj.owner = syndicate
syndicate.objectives += syndobj
/datum/game_mode/proc/greet_syndicate(datum/mind/syndicate, you_are=1)
if(you_are)
to_chat(syndicate.current, "<span class='notice'>You are a [syndicate_name()] agent!</span>")
syndicate.announce_objectives()
/datum/game_mode/proc/equip_syndicate(mob/living/carbon/human/synd_mob, telecrystals = TRUE)
synd_mob.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs
if(telecrystals)
synd_mob.equipOutfit(/datum/outfit/syndicate)
else
synd_mob.equipOutfit(/datum/outfit/syndicate/no_crystals)
return TRUE
/datum/game_mode/nuclear/OnNukeExplosion(off_station)
..()
nukes_left--
var/obj/docking_port/mobile/Shuttle = SSshuttle.getShuttle("syndicate")
syndies_didnt_escape = (Shuttle && (Shuttle.z == ZLEVEL_CENTCOM || Shuttle.z == ZLEVEL_TRANSIT)) ? 0 : 1
nuke_off_station = off_station
/datum/game_mode/nuclear/check_win()
if (nukes_left == 0)
@@ -154,8 +52,8 @@
return ..()
/datum/game_mode/proc/are_operatives_dead()
for(var/datum/mind/operative_mind in syndicates)
if(ishuman(operative_mind.current) && (operative_mind.current.stat!=2))
for(var/datum/mind/operative_mind in get_antagonists(/datum/antagonist/nukeop))
if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD))
return FALSE
return TRUE
@@ -164,142 +62,55 @@
return replacementmode.check_finished()
if((SSshuttle.emergency.mode == SHUTTLE_ENDGAME) || station_was_nuked)
return TRUE
if(are_operatives_dead())
if(nuke_team.operatives_dead())
var/obj/machinery/nuclearbomb/N
pass(N) //suppress unused warning
if(N.bomb_set) //snaaaaaaaaaake! It's not over yet!
return FALSE //its a static var btw
..()
/datum/game_mode/nuclear/declare_completion()
var/disk_rescued = 1
for(var/obj/item/disk/nuclear/D in GLOB.poi_list)
if(!D.onCentCom())
disk_rescued = 0
break
var/crew_evacuated = (SSshuttle.emergency.mode == SHUTTLE_ENDGAME)
if(nuke_off_station == NUKE_SYNDICATE_BASE)
SSticker.mode_result = "loss - syndicate nuked - disk secured"
to_chat(world, "<FONT size = 3><B>Humiliating Syndicate Defeat</B></FONT>")
to_chat(world, "<B>The crew of [station_name()] gave [syndicate_name()] operatives back their bomb! The syndicate base was destroyed!</B> Next time, don't lose the nuke!")
SSticker.news_report = NUKE_SYNDICATE_BASE
else if(!disk_rescued && station_was_nuked && !syndies_didnt_escape)
SSticker.mode_result = "win - syndicate nuke"
to_chat(world, "<FONT size = 3><B>Syndicate Major Victory!</B></FONT>")
to_chat(world, "<B>[syndicate_name()] operatives have destroyed [station_name()]!</B>")
SSticker.news_report = STATION_NUKED
else if (!disk_rescued && station_was_nuked && syndies_didnt_escape)
SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time"
to_chat(world, "<FONT size = 3><B>Total Annihilation</B></FONT>")
to_chat(world, "<B>[syndicate_name()] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion.</B> Next time, don't lose the disk!")
SSticker.news_report = STATION_NUKED
else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape)
SSticker.mode_result = "halfwin - blew wrong station"
to_chat(world, "<FONT size = 3><B>Crew Minor Victory</B></FONT>")
to_chat(world, "<B>[syndicate_name()] operatives secured the authentication disk but blew up something that wasn't [station_name()].</B> Next time, don't do that!")
SSticker.news_report = NUKE_MISS
else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape)
SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time"
to_chat(world, "<FONT size = 3><B>[syndicate_name()] operatives have earned Darwin Award!</B></FONT>")
to_chat(world, "<B>[syndicate_name()] operatives blew up something that wasn't [station_name()] and got caught in the explosion.</B> Next time, don't do that!")
SSticker.news_report = NUKE_MISS
else if ((disk_rescued || SSshuttle.emergency.mode != SHUTTLE_ENDGAME) && are_operatives_dead())
SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead"
to_chat(world, "<FONT size = 3><B>Crew Major Victory!</B></FONT>")
to_chat(world, "<B>The Research Staff has saved the disk and killed the [syndicate_name()] Operatives</B>")
SSticker.news_report = OPERATIVES_KILLED
else if (disk_rescued)
SSticker.mode_result = "loss - evacuation - disk secured"
to_chat(world, "<FONT size = 3><B>Crew Major Victory</B></FONT>")
to_chat(world, "<B>The Research Staff has saved the disk and stopped the [syndicate_name()] Operatives!</B>")
SSticker.news_report = OPERATIVES_KILLED
else if (!disk_rescued && are_operatives_dead())
SSticker.mode_result = "halfwin - evacuation - disk not secured"
to_chat(world, "<FONT size = 3><B>Neutral Victory!</B></FONT>")
to_chat(world, "<B>The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name()] Operatives!</B>")
SSticker.news_report = OPERATIVE_SKIRMISH
else if (!disk_rescued && crew_evacuated)
SSticker.mode_result = "halfwin - detonation averted"
to_chat(world, "<FONT size = 3><B>Syndicate Minor Victory!</B></FONT>")
to_chat(world, "<B>[syndicate_name()] operatives survived the assault but did not achieve the destruction of [station_name()].</B> Next time, don't lose the disk!")
SSticker.news_report = OPERATIVE_SKIRMISH
else if (!disk_rescued && !crew_evacuated)
SSticker.mode_result = "halfwin - interrupted"
to_chat(world, "<FONT size = 3><B>Neutral Victory</B></FONT>")
to_chat(world, "<B>Round was mysteriously interrupted!</B>")
SSticker.news_report = OPERATIVE_SKIRMISH
/datum/game_mode/nuclear/set_round_result()
..()
return
var result = nuke_team.get_result()
switch(result)
if(NUKE_RESULT_FLUKE)
SSticker.mode_result = "loss - syndicate nuked - disk secured"
SSticker.news_report = NUKE_SYNDICATE_BASE
if(NUKE_RESULT_NUKE_WIN)
SSticker.mode_result = "win - syndicate nuke"
SSticker.news_report = STATION_NUKED
if(NUKE_RESULT_NOSURVIVORS)
SSticker.mode_result = "halfwin - syndicate nuke - did not evacuate in time"
SSticker.news_report = STATION_NUKED
if(NUKE_RESULT_WRONG_STATION)
SSticker.mode_result = "halfwin - blew wrong station"
SSticker.news_report = NUKE_MISS
if(NUKE_RESULT_WRONG_STATION_DEAD)
SSticker.mode_result = "halfwin - blew wrong station - did not evacuate in time"
SSticker.news_report = NUKE_MISS
if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD)
SSticker.mode_result = "loss - evacuation - disk secured - syndi team dead"
SSticker.news_report = OPERATIVES_KILLED
if(NUKE_RESULT_CREW_WIN)
SSticker.mode_result = "loss - evacuation - disk secured"
SSticker.news_report = OPERATIVES_KILLED
if(NUKE_RESULT_DISK_LOST)
SSticker.mode_result = "halfwin - evacuation - disk not secured"
SSticker.news_report = OPERATIVE_SKIRMISH
if(NUKE_RESULT_DISK_STOLEN)
SSticker.mode_result = "halfwin - detonation averted"
SSticker.news_report = OPERATIVE_SKIRMISH
else
SSticker.mode_result = "halfwin - interrupted"
SSticker.news_report = OPERATIVE_SKIRMISH
/datum/game_mode/nuclear/generate_report()
return "One of Central Command's trading routes was recently disrupted by a raid carried out by the Gorlex Marauders. They seemed to only be after one ship - a highly-sensitive \
transport containing a nuclear fission explosive, although it is useless without the proper code and authorization disk. While the code was likely found in minutes, the only disk that \
can activate this explosive is on your station. Ensure that it is protected at all times, and remain alert for possible intruders."
/datum/game_mode/proc/auto_declare_completion_nuclear()
if( syndicates.len || (SSticker && istype(SSticker.mode, /datum/game_mode/nuclear)) )
var/text = "<br><FONT size=3><B>The syndicate operatives were:</B></FONT>"
var/purchases = ""
var/TC_uses = 0
for(var/datum/mind/syndicate in syndicates)
text += printplayer(syndicate)
for(var/datum/component/uplink/H in GLOB.uplinks)
if(H.purchase_log)
purchases += H.purchase_log.generate_render()
else
stack_trace("WARNING: Uplink with no purchase_log in nuclear mode! Owner: [H.owner]")
text += "<br>"
text += "(Syndicates used [TC_uses] TC) [purchases]"
if(TC_uses == 0 && station_was_nuked && !are_operatives_dead())
text += "<BIG>[icon2html('icons/badass.dmi', world, "badass")]</BIG>"
to_chat(world, text)
return TRUE
/proc/nukelastname(mob/M) //--All praise goes to NEO|Phyte, all blame goes to DH, and it was Cindi-Kate's idea. Also praise Urist for copypasta ho.
var/randomname = pick(GLOB.last_names)
var/newname = copytext(sanitize(input(M,"You are the nuke operative [pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")]. Please choose a last name for your family.", "Name change",randomname)),1,MAX_NAME_LEN)
if (!newname)
newname = randomname
else
if (newname == "Unknown" || newname == "floor" || newname == "wall" || newname == "rwall" || newname == "_")
to_chat(M, "That name is reserved.")
return nukelastname(M)
return capitalize(newname)
/proc/NukeNameAssign(lastname,list/syndicates)
for(var/datum/mind/synd_mind in syndicates)
var/mob/living/carbon/human/H = synd_mind.current
synd_mind.name = H.dna.species.random_name(H.gender,0,lastname)
synd_mind.current.real_name = synd_mind.name
return
/proc/is_nuclear_operative(mob/M)
return M && istype(M) && M.mind && SSticker && SSticker.mode && M.mind in SSticker.mode.syndicates
return M && istype(M) && M.mind && M.mind.has_antag_datum(/datum/antagonist/nukeop)
/datum/outfit/syndicate
name = "Syndicate Operative - Basic"
@@ -312,18 +123,28 @@
l_pocket = /obj/item/pinpointer/nuke/syndicate
id = /obj/item/card/id/syndicate
belt = /obj/item/gun/ballistic/automatic/pistol
backpack_contents = list(/obj/item/storage/box/syndie=1)
backpack_contents = list(/obj/item/storage/box/syndie=1,\
/obj/item/kitchen/knife/combat/survival)
var/tc = 25
var/command_radio = FALSE
/datum/outfit/syndicate/leader
name = "Syndicate Leader - Basic"
id = /obj/item/card/id/syndicate/nuke_leader
r_hand = /obj/item/device/nuclear_challenge
command_radio = TRUE
/datum/outfit/syndicate/no_crystals
tc = 0
/datum/outfit/syndicate/post_equip(mob/living/carbon/human/H)
var/obj/item/device/radio/R = H.ears
R.set_frequency(GLOB.SYND_FREQ)
R.freqlock = 1
if(command_radio)
R.command = TRUE
if(tc)
var/obj/item/device/radio/uplink/nuclear/U = new(H, H.key, tc)
@@ -348,4 +169,5 @@
r_hand = /obj/item/gun/ballistic/automatic/shotgun/bulldog
backpack_contents = list(/obj/item/storage/box/syndie=1,\
/obj/item/tank/jetpack/oxygen/harness=1,\
/obj/item/gun/ballistic/automatic/pistol=1)
/obj/item/gun/ballistic/automatic/pistol=1,\
/obj/item/kitchen/knife/combat/survival)
@@ -67,7 +67,7 @@
if(GLOB.player_list.len < CHALLENGE_MIN_PLAYERS)
to_chat(user, "The enemy crew is too small to be worth declaring war on.")
return FALSE
if(user.z != ZLEVEL_CENTCOM)
if(!user.onSyndieBase())
to_chat(user, "You have to be at your base to use this.")
return FALSE
if(world.time-SSticker.round_start_time > CHALLENGE_TIME_LIMIT)
+7 -7
View File
@@ -77,16 +77,16 @@
icon = 'icons/obj/machines/nuke_terminal.dmi'
icon_state = "nuclearbomb_base"
anchored = TRUE //stops it being moved
use_tag = TRUE
/obj/machinery/nuclearbomb/syndicate
use_tag = TRUE
//ui_style = "syndicate" // actually the nuke op bomb is a stole nt bomb
/obj/machinery/nuclearbomb/syndicate/get_cinematic_type(off_station)
var/datum/game_mode/nuclear/NM = SSticker.mode
switch(off_station)
if(0)
if(istype(NM) && NM.syndies_didnt_escape)
if(istype(NM) && !NM.nuke_team.syndies_escaped())
return CINEMATIC_ANNIHILATION
else
return CINEMATIC_NUKE_WIN
@@ -353,7 +353,7 @@
var/N = text2num(user_input)
if(!N)
return
timer_set = Clamp(N,minimum_timer_set,maximum_timer_set)
timer_set = CLAMP(N,minimum_timer_set,maximum_timer_set)
. = TRUE
if("safety")
if(auth && yes_code)
@@ -451,12 +451,12 @@
var/off_station = 0
var/turf/bomb_location = get_turf(src)
var/area/A = get_area(bomb_location)
if(bomb_location && (bomb_location.z in GLOB.station_z_levels))
if(bomb_location && is_station_level(bomb_location.z))
if(istype(A, /area/space))
off_station = NUKE_NEAR_MISS
if((bomb_location.x < (128-NUKERANGE)) || (bomb_location.x > (128+NUKERANGE)) || (bomb_location.y < (128-NUKERANGE)) || (bomb_location.y > (128+NUKERANGE)))
off_station = NUKE_NEAR_MISS
else if((istype(A, /area/syndicate_mothership) || (istype(A, /area/shuttle/syndicate)) && bomb_location.z == ZLEVEL_CENTCOM))
else if(bomb_location.onSyndieBase())
off_station = NUKE_SYNDICATE_BASE
else
off_station = NUKE_MISS_STATION
@@ -556,7 +556,7 @@ This is here to make the tiles around the station mininuke change when it's arme
addtimer(CALLBACK(user, /atom/proc/add_atom_colour, (i % 2)? "#00FF00" : "#FF0000", ADMIN_COLOUR_PRIORITY), i)
addtimer(CALLBACK(src, .proc/manual_suicide, user), 101)
return MANUAL_SUICIDE
/obj/item/disk/proc/manual_suicide(mob/living/user)
user.remove_atom_colour(ADMIN_COLOUR_PRIORITY)
user.visible_message("<span class='suicide'>[user] was destroyed by the nuclear blast!</span>")
@@ -572,4 +572,4 @@ This is here to make the tiles around the station mininuke change when it's arme
user.visible_message("<span class='suicide'>[user] is pretending to go delta! It looks like [user.p_theyre()] trying to commit suicide!</span>")
playsound(src, 'sound/machines/alarm.ogg', 30, -1, 1)
addtimer(CALLBACK(src, .proc/manual_suicide, user), 101)
return MANUAL_SUICIDE
return MANUAL_SUICIDE
+2 -2
View File
@@ -71,9 +71,9 @@
target = null
var/list/possible_targets = list()
var/turf/here = get_turf(src)
for(var/V in SSticker.mode.syndicates)
for(var/V in get_antagonists(/datum/antagonist/nukeop))
var/datum/mind/M = V
if(M.current && M.current.stat != DEAD)
if(ishuman(M.current) && M.current.stat != DEAD)
possible_targets |= M.current
var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here)
if(closest_operative)
+1 -1
View File
@@ -154,7 +154,7 @@
if(!target || !considered_alive(target) || considered_afk(target))
return TRUE
var/turf/T = get_turf(target.current)
return T && !(T.z in GLOB.station_z_levels)
return T && !is_station_level(T.z)
/datum/objective/mutiny/update_explanation_text()
..()
+12 -2
View File
@@ -3,6 +3,7 @@
var/list/datum/mind/members = list()
var/name = "team"
var/member_name = "member"
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
/datum/objective_team/New(starting_members)
. = ..()
@@ -12,7 +13,6 @@
add_member(M)
else
add_member(starting_members)
members += starting_members
/datum/objective_team/proc/is_solo()
return members.len == 1
@@ -21,4 +21,14 @@
members |= new_member
/datum/objective_team/proc/remove_member(datum/mind/member)
members -= member
members -= member
//Display members/victory/failure/objectives for the team
/datum/objective_team/proc/roundend_report()
var/list/report = list()
report += "<b>[name]:</b>"
report += "The [member_name]s were:"
report += printplayerlist(members)
return report.Join("<br>")
+11 -51
View File
@@ -26,7 +26,7 @@
var/finished = 0
var/check_counter = 0
var/max_headrevs = 3
var/datum/objective_team/revolution/revolution
var/datum/team/revolution/revolution
var/list/datum/mind/headrev_candidates = list()
///////////////////////////
@@ -164,67 +164,27 @@
/datum/game_mode/revolution/proc/check_heads_victory()
for(var/datum/mind/rev_mind in revolution.head_revolutionaries())
var/turf/T = get_turf(rev_mind.current)
if(!considered_afk(rev_mind) && considered_alive(rev_mind) && (T.z in GLOB.station_z_levels))
if(!considered_afk(rev_mind) && considered_alive(rev_mind) && is_station_level(T.z))
if(ishuman(rev_mind.current))
return FALSE
return TRUE
//////////////////////////////////////////////////////////////////////
//Announces the end of the game with all relavent information stated//
//////////////////////////////////////////////////////////////////////
/datum/game_mode/revolution/declare_completion()
/datum/game_mode/revolution/set_round_result()
..()
if(finished == 1)
SSticker.mode_result = "win - heads killed"
to_chat(world, "<span class='redtext'>The heads of staff were killed or exiled! The revolutionaries win!</span>")
SSticker.news_report = REVS_WIN
else if(finished == 2)
SSticker.mode_result = "loss - rev heads killed"
to_chat(world, "<span class='redtext'>The heads of staff managed to stop the revolution!</span>")
SSticker.news_report = REVS_LOSE
..()
return TRUE
/datum/game_mode/proc/auto_declare_completion_revolution()
var/list/targets = list()
var/list/datum/mind/headrevs = get_antagonists(/datum/antagonist/rev/head)
var/list/datum/mind/revs = get_antagonists(/datum/antagonist/rev,TRUE)
if(headrevs.len)
var/num_revs = 0
var/num_survivors = 0
for(var/mob/living/carbon/survivor in GLOB.alive_mob_list)
if(survivor.ckey)
num_survivors++
if(survivor.mind)
if(is_revolutionary(survivor))
num_revs++
if(num_survivors)
to_chat(world, "[GLOB.TAB]Command's Approval Rating: <B>[100 - round((num_revs/num_survivors)*100, 0.1)]%</B>" )
var/text = "<br><font size=3><b>The head revolutionaries were:</b></font>"
for(var/datum/mind/headrev in headrevs)
text += printplayer(headrev, 1)
text += "<br>"
to_chat(world, text)
if(revs.len)
var/text = "<br><font size=3><b>The revolutionaries were:</b></font>"
for(var/datum/mind/rev in revs)
text += printplayer(rev, 1)
text += "<br>"
to_chat(world, text)
if(revs.len || headrevs.len)
var/text = "<br><font size=3><b>The heads of staff were:</b></font>"
var/list/heads = SSjob.get_all_heads()
for(var/datum/mind/head in heads)
var/target = (head in targets)
if(target)
text += "<span class='boldannounce'>Target</span>"
text += printplayer(head, 1)
text += "<br>"
to_chat(world, text)
//TODO What should be displayed for revs in non-rev rounds
/datum/game_mode/revolution/special_report()
if(finished == 1)
return "<span class='redtext big'>The heads of staff were killed or exiled! The revolutionaries win!</span>"
else if(finished == 2)
return "<span class='redtext big'>The heads of staff managed to stop the revolution!</span>"
/datum/game_mode/revolution/generate_report()
return "Employee unrest has spiked in recent weeks, with several attempted mutinies on heads of staff. Some crew have been observed using flashbulb devices to blind their colleagues, \
+2 -71
View File
@@ -27,6 +27,7 @@
var/traitors_possible = 4 //hard limit on traitors if scaling is turned off
var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual.
var/antag_datum = ANTAG_DATUM_TRAITOR //what type of antag to create
var/traitors_required = TRUE //Will allow no traitors
/datum/game_mode/traitor/pre_setup()
@@ -55,7 +56,7 @@
log_game("[traitor.key] (ckey) has been selected as a [traitor_name]")
antag_candidates.Remove(traitor)
return pre_traitors.len > 0
return !traitors_required || pre_traitors.len > 0
/datum/game_mode/traitor/post_setup()
@@ -85,80 +86,10 @@
new_antag.should_specialise = TRUE
character.add_antag_datum(new_antag)
/datum/game_mode/traitor/declare_completion()
..()
return//Traitors will be checked as part of check_extra_completion. Leaving this here as a reminder.
/datum/game_mode/proc/auto_declare_completion_traitor()
if(traitors.len)
var/text = "<br><font size=3><b>The [traitor_name]s were:</b></font>"
for(var/datum/mind/traitor in traitors)
var/traitorwin = TRUE
text += printplayer(traitor)
var/TC_uses = 0
var/uplink_true = FALSE
var/purchases = ""
for(var/datum/component/uplink/H in GLOB.uplinks)
if(H && H.owner && H.owner == traitor.key)
TC_uses += H.spent_telecrystals
uplink_true = TRUE
purchases += H.purchase_log.generate_render(FALSE)
var/objectives = ""
if(traitor.objectives.len)//If the traitor had no objectives, don't need to process this.
var/count = 1
for(var/datum/objective/objective in traitor.objectives)
if(objective.check_completion())
objectives += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "SUCCESS"))
else
objectives += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='red'>Fail.</font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "traitor_objective", 1, list("[objective.type]", "FAIL"))
if(!(istype(objective, /datum/objective/crew)))
traitorwin = FALSE
count++
if(uplink_true)
text += " (used [TC_uses] TC) [purchases]"
if(TC_uses==0 && traitorwin)
var/static/icon/badass = icon('icons/badass.dmi', "badass")
text += "<BIG>[icon2html(badass, world)]</BIG>"
text += objectives
var/special_role_text
if(traitor.special_role)
special_role_text = lowertext(traitor.special_role)
else
special_role_text = "antagonist"
if(traitorwin)
text += "<br><font color='green'><B>The [special_role_text] was successful!</B></font>"
SSblackbox.record_feedback("tally", "traitor_success", 1, "SUCCESS")
else
text += "<br><font color='red'><B>The [special_role_text] has failed!</B></font>"
SSblackbox.record_feedback("tally", "traitor_success", 1, "FAIL")
SEND_SOUND(traitor.current, 'sound/ambience/ambifailure.ogg')
text += "<br>"
text += "<br><b>The code phrases were:</b> <font color='red'>[GLOB.syndicate_code_phrase]</font><br>\
<b>The code responses were:</b> <font color='red'>[GLOB.syndicate_code_response]</font><br>"
to_chat(world, text)
return TRUE
/datum/game_mode/traitor/generate_report()
return "Although more specific threats are commonplace, you should always remain vigilant for Syndicate agents aboard your station. Syndicate communications have implied that many \
Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions."
/datum/game_mode/proc/update_traitor_icons_added(datum/mind/traitor_mind)
var/datum/atom_hud/antag/traitorhud = GLOB.huds[ANTAG_HUD_TRAITOR]
traitorhud.join_hud(traitor_mind.current)
+12 -9
View File
@@ -213,7 +213,7 @@
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
var/mob/living/carbon/human/target = null
var/list/mob/living/carbon/human/possible = list()
var/obj/item/link = null
var/obj/item/voodoo_link = null
var/cooldown_time = 30 //3s
var/cooldown = 0
max_integrity = 10
@@ -237,10 +237,10 @@
cooldown = world.time +cooldown_time
return
if(!link)
if(!voodoo_link)
if(I.loc == user && istype(I) && I.w_class <= WEIGHT_CLASS_SMALL)
if (user.transferItemToLoc(I,src))
link = I
voodoo_link = I
to_chat(user, "You attach [I] to the doll.")
update_targets()
@@ -255,11 +255,11 @@
return
if(user.zone_selected == "chest")
if(link)
if(voodoo_link)
target = null
link.loc = get_turf(src)
to_chat(user, "<span class='notice'>You remove the [link] from the doll.</span>")
link = null
voodoo_link.forceMove(drop_location())
to_chat(user, "<span class='notice'>You remove the [voodoo_link] from the doll.</span>")
voodoo_link = null
update_targets()
return
@@ -291,10 +291,13 @@
/obj/item/voodoo/proc/update_targets()
possible = list()
if(!link)
if(!voodoo_link)
return
var/list/prints = voodoo_link.return_fingerprints()
if(!length(prints))
return FALSE
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
if(md5(H.dna.uni_identity) in link.fingerprints)
if(prints[md5(H.dna.uni_identity)])
possible |= H
/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
+2 -2
View File
@@ -64,7 +64,6 @@
to_chat(user, "<span class='cultlarge'>\"Come now, do not capture your bretheren's soul.\"</span>")
return
add_logs(user, M, "captured [M.name]'s soul", src)
transfer_soul("VICTIM", M, user)
///////////////////Options for using captured souls///////////////////////////////////////
@@ -142,7 +141,8 @@
if("VICTIM")
var/mob/living/carbon/human/T = target
if(is_sacrifice_target(T.mind))
var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(C && C.cult_team.is_sacrifice_target(T.mind))
if(iscultist(user))
to_chat(user, "<span class='cult'><b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\"</span>")
else
+5 -54
View File
@@ -58,65 +58,16 @@
return TRUE
/datum/game_mode/wizard/declare_completion()
/datum/game_mode/wizard/set_round_result()
..()
if(finished)
SSticker.mode_result = "loss - wizard killed"
to_chat(world, "<span class='userdanger'>The wizard[(wizards.len>1)?"s":""] has been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!</span>")
SSticker.news_report = WIZARD_KILLED
..()
return 1
/datum/game_mode/wizard/special_report()
if(finished)
return "<span class='redtext big'>The wizard[(wizards.len>1)?"s":""] has been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!</span>"
/datum/game_mode/proc/auto_declare_completion_wizard()
if(wizards.len)
var/text = "<br><font size=3><b>the wizards/witches were:</b></font>"
for(var/datum/mind/wizard in wizards)
text += "<br><b>[wizard.key]</b> was <b>[wizard.name]</b> ("
if(wizard.current)
if(wizard.current.stat == DEAD)
text += "died"
else
text += "survived"
if(wizard.current.real_name != wizard.name)
text += " as <b>[wizard.current.real_name]</b>"
else
text += "body destroyed"
text += ")"
var/count = 1
var/wizardwin = 1
for(var/datum/objective/objective in wizard.objectives)
if(objective.check_completion())
text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='green'><B>Success!</B></font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "SUCCESS"))
else
text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <font color='red'>Fail.</font> [istype(objective, /datum/objective/crew) ? "<font color='grey'>(Optional)</font>" : ""]"
SSblackbox.record_feedback("nested tally", "wizard_objective", 1, list("[objective.type]", "FAIL"))
if(!(istype(objective, /datum/objective/crew)))
wizardwin = 0
count++
if(wizard.current && wizardwin)
text += "<br><font color='green'><B>The wizard was successful!</B></font>"
SSblackbox.record_feedback("tally", "wizard_success", 1, "SUCCESS")
else
text += "<br><font color='red'><B>The wizard has failed!</B></font>"
SSblackbox.record_feedback("tally", "wizard_success", 1, "FAIL")
if(wizard.spell_list.len>0)
text += "<br><B>[wizard.name] used the following spells: </B>"
var/i = 1
for(var/obj/effect/proc_holder/spell/S in wizard.spell_list)
text += "[S.name]"
if(wizard.spell_list.len > i)
text += ", "
i++
text += "<br>"
to_chat(world, text)
return 1
//returns whether the mob is a wizard (or apprentice)
/proc/iswizard(mob/living/M)
return M.mind && M.mind.has_antag_datum(/datum/antagonist/wizard,TRUE)
+1 -1
View File
@@ -134,7 +134,7 @@
return
if(storedpda)
storedpda.loc = get_turf(src.loc)
storedpda.forceMove(drop_location())
storedpda = null
update_icon()
else
+26 -30
View File
@@ -149,8 +149,6 @@
if(href_list["make"])
var/turf/T = loc
/////////////////
//href protection
being_built = stored_research.isDesignResearchedID(href_list["make"])
@@ -174,34 +172,8 @@
use_power(power)
icon_state = "autolathe"
flick("autolathe_n",src)
if(is_stack)
spawn(32*coeff)
use_power(power)
var/list/materials_used = list(MAT_METAL=metal_cost*multiplier, MAT_GLASS=glass_cost*multiplier)
materials.use_amount(materials_used)
var/obj/item/stack/N = new being_built.build_path(T, multiplier)
N.update_icon()
N.autolathe_crafted(src)
for(var/obj/item/stack/S in T.contents - N)
if(istype(S, N.merge_type))
N.merge(S)
busy = FALSE
updateUsrDialog()
else
spawn(32*coeff*multiplier)
use_power(power)
var/list/materials_used = list(MAT_METAL=metal_cost*coeff*multiplier, MAT_GLASS=glass_cost*coeff*multiplier)
materials.use_amount(materials_used)
for(var/i=1, i<=multiplier, i++)
var/obj/item/new_item = new being_built.build_path(T)
for(var/mat in materials_used)
new_item.materials[mat] = materials_used[mat] / multiplier
new_item.autolathe_crafted(src)
busy = FALSE
updateUsrDialog()
var/time = is_stack ? 32 : 32*coeff*multiplier
addtimer(CALLBACK(src, .proc/make_item, power, metal_cost, glass_cost, multiplier, coeff, is_stack), time)
if(href_list["search"])
matching_designs.Cut()
@@ -218,6 +190,30 @@
return
/obj/machinery/autolathe/proc/make_item(power, metal_cost, glass_cost, multiplier, coeff, is_stack)
GET_COMPONENT(materials, /datum/component/material_container)
var/atom/A = drop_location()
use_power(power)
var/list/materials_used = list(MAT_METAL=metal_cost*coeff*multiplier, MAT_GLASS=glass_cost*coeff*multiplier)
materials.use_amount(materials_used)
if(is_stack)
var/obj/item/stack/N = new being_built.build_path(A, multiplier)
N.update_icon()
N.autolathe_crafted(src)
for(var/obj/item/stack/S in (A.contents - N))
if(istype(S, N.merge_type))
N.merge(S)
else
for(var/i=1, i<=multiplier, i++)
var/obj/item/new_item = new being_built.build_path(A)
for(var/mat in materials_used)
new_item.materials[mat] = materials_used[mat] / multiplier
new_item.autolathe_crafted(src)
busy = FALSE
updateDialog()
/obj/machinery/autolathe/RefreshParts()
var/T = 0
for(var/obj/item/stock_parts/matter_bin/MB in component_parts)
+1 -1
View File
@@ -59,7 +59,7 @@
if(..())
return
src.add_fingerprint(usr)
var/dat = "[world.name] secure vault. Authorized personnel only.<br>"
var/dat = "[station_name()] secure vault. Authorized personnel only.<br>"
dat += "Current Balance: [SSshuttle.points] credits.<br>"
if(!siphoning)
dat += "<A href='?src=[REF(src)];siphon=1'>Siphon Credits</A><br>"
+5 -7
View File
@@ -53,23 +53,21 @@
LAZYADD(myarea.cameras, src)
proximity_monitor = new(src, 1)
if(mapload && (z in GLOB.station_z_levels) && prob(3) && !start_active)
if(mapload && is_station_level(z) && prob(3) && !start_active)
toggle_cam()
/obj/machinery/camera/Destroy()
toggle_cam(null, 0) //kick anyone viewing out
if(can_use())
toggle_cam(null, 0) //kick anyone viewing out and remove from the camera chunks
GLOB.cameranet.cameras -= src
if(isarea(myarea))
LAZYREMOVE(myarea.cameras, src)
if(assembly)
qdel(assembly)
assembly = null
QDEL_NULL(assembly)
if(bug)
bug.bugged_cameras -= src.c_tag
if(bug.current == src)
bug.current = null
bug = null
GLOB.cameranet.removeCamera(src) //Will handle removal from the camera network and the chunks, so we don't need to worry about that
GLOB.cameranet.cameras -= src
return ..()
/obj/machinery/camera/emp_act(severity)
+6 -23
View File
@@ -1,10 +1,4 @@
/mob/living/silicon/ai/proc/get_camera_list()
track.cameras.Cut()
if(src.stat == DEAD)
return
var/list/L = list()
for (var/obj/machinery/camera/C in GLOB.cameranet.cameras)
L.Add(C)
@@ -18,25 +12,18 @@
if (tempnetwork.len)
T[text("[][]", C.c_tag, (C.can_use() ? null : " (Deactivated)"))] = C
track.cameras = T
return T
/mob/living/silicon/ai/proc/ai_camera_list(camera)
if (!camera)
return 0
var/obj/machinery/camera/C = track.cameras[camera]
src.eyeobj.setLoc(C)
return
/mob/living/silicon/ai/proc/show_camera_list()
var/list/cameras = get_camera_list()
var/camera = input(src, "Choose which camera you want to view", "Cameras") as null|anything in cameras
switchCamera(cameras[camera])
/datum/trackable
var/list/names = list()
var/list/namecounts = list()
var/list/humans = list()
var/list/others = list()
var/list/cameras = list()
/mob/living/silicon/ai/proc/trackable_mobs()
@@ -143,13 +130,9 @@
/obj/machinery/camera/attack_ai(mob/living/silicon/ai/user)
if (!istype(user))
return
if (!src.can_use())
if (!can_use())
return
user.eyeobj.setLoc(get_turf(src))
/mob/living/silicon/ai/attack_ai(mob/user)
ai_camera_list()
user.switchCamera(src)
/proc/camera_sort(list/L)
var/obj/machinery/camera/a
+2 -2
View File
@@ -161,7 +161,7 @@
return
log_activity("changed greater than charge filter to \"[new_filter]\"")
if(new_filter)
new_filter = Clamp(new_filter, 0, 100)
new_filter = CLAMP(new_filter, 0, 100)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Charge Above"] = new_filter
if(href_list["below_filter"])
@@ -171,7 +171,7 @@
return
log_activity("changed lesser than charge filter to \"[new_filter]\"")
if(new_filter)
new_filter = Clamp(new_filter, 0, 100)
new_filter = CLAMP(new_filter, 0, 100)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Charge Below"] = new_filter
if(href_list["access_filter"])
+1 -1
View File
@@ -528,7 +528,7 @@
playsound(loc, 'sound/effects/bang.ogg', 100, 1)
var/turf/open/floor/F
for(F in orange(1, src))
F.ChangeTurf(F.baseturf)
F.ScrapeAway()
say("Something slams into the floor around [src], exposing it to space!")
if(hull)
sleep(10)
@@ -211,7 +211,7 @@
if("pressure")
var/target = input("New target pressure:", name, output_info ? output_info["internal"] : 0) as num|null
if(!isnull(target) && !..())
target = Clamp(target, 0, 50 * ONE_ATMOSPHERE)
target = CLAMP(target, 0, 50 * ONE_ATMOSPHERE)
signal.data += list("tag" = output_tag, "set_internal_pressure" = target)
. = TRUE
radio_connection.post_signal(src, signal, filter = GLOB.RADIO_ATMOSIA)
@@ -121,7 +121,7 @@
to_chat(user, "<span class='notice'>You remove the glass panel.</span>")
state = 3
icon_state = "3"
var/obj/item/stack/sheet/glass/G = new (drop_location(), 2)
var/obj/item/stack/sheet/glass/G = new(drop_location(), 2)
G.add_fingerprint(user)
return
if(istype(P, /obj/item/screwdriver))
+1 -1
View File
@@ -124,7 +124,7 @@
/obj/machinery/computer/security/proc/get_available_cameras()
var/list/L = list()
for (var/obj/machinery/camera/C in GLOB.cameranet.cameras)
if((z > ZLEVEL_SPACEMAX || C.z > ZLEVEL_SPACEMAX) && (C.z != z))//if on away mission, can only recieve feed from same z_level cameras
if((is_away_level(z) || is_away_level(C.z)) && (C.z != z))//if on away mission, can only recieve feed from same z_level cameras
continue
L.Add(C)
@@ -83,12 +83,23 @@
if(!eyeobj.eye_initialized)
var/camera_location
for(var/obj/machinery/camera/C in GLOB.cameranet.cameras)
if(!C.can_use() || z_lock.len && !(C.z in z_lock))
continue
if(C.network & networks)
camera_location = get_turf(C)
break
var/turf/myturf = get_turf(src)
if(eyeobj.use_static)
if((!z_lock.len || (myturf.z in z_lock)) && GLOB.cameranet.checkTurfVis(myturf))
camera_location = myturf
else
for(var/obj/machinery/camera/C in GLOB.cameranet.cameras)
if(!C.can_use() || z_lock.len && !(C.z in z_lock))
continue
var/list/network_overlap = networks & C.network
if(network_overlap.len)
camera_location = get_turf(C)
break
else
camera_location = myturf
if(z_lock.len && !(myturf.z in z_lock))
camera_location = locate(round(world.maxx/2), round(world.maxy/2), z_lock[1])
if(camera_location)
eyeobj.eye_initialized = TRUE
give_eye_control(L)
@@ -292,7 +303,7 @@
var/mob/camera/aiEye/remote/remote_eye = user.remote_control
var/obj/machinery/computer/camera_advanced/ratvar/R = target
var/turf/T = get_turf(remote_eye)
if(user.z != ZLEVEL_CITYOFCOGS || !(T.z in GLOB.station_z_levels))
if(!is_reebe(user.z) || !is_station_level(T.z))
return
if(isclosedturf(T))
to_chat(user, "<span class='sevtug_small'>You can't teleport into a wall.</span>")
+1 -1
View File
@@ -449,7 +449,7 @@
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((mob_occupant.disabilities & NOCLONE) && (src.scanner.scan_level < 2))
if((mob_occupant.has_disability(DISABILITY_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
@@ -9,7 +9,7 @@
var/authenticated = 0
var/auth_id = "Unknown" //Who is currently logged in?
var/list/datum/comm_message/messages = list()
var/datum/comm_message/currmsg
var/datum/comm_message/currmsg
var/datum/comm_message/aicurrmsg
var/state = STATE_DEFAULT
var/aistate = STATE_DEFAULT
@@ -53,7 +53,7 @@
/obj/machinery/computer/communications/Topic(href, href_list)
if(..())
return
if(!(z in GLOB.station_z_levels) && z != ZLEVEL_CENTCOM) //Can only use on centcom and SS13
if(!is_station_level(z) && !is_centcom_level(z)) //Can only use on centcom and SS13
to_chat(usr, "<span class='boldannounce'>Unable to establish a connection</span>: \black You're too far away from the station!")
return
usr.set_machine(src)
@@ -136,7 +136,6 @@
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
var/input = stripped_multiline_input(usr, "Please choose a message to transmit to allied stations. Please be aware that this process is very expensive, and abuse will lead to... termination.", "Send a message to an allied station.", "")
if(!input || !(usr in view(1,src)))
return
+19 -18
View File
@@ -81,7 +81,7 @@
if(connected && connected.is_operational())
if(connected.occupant) //set occupant_status message
viable_occupant = connected.occupant
if(viable_occupant.has_dna() && (!(RADIMMUNE in viable_occupant.dna.species.species_traits)) && (!(viable_occupant.disabilities & NOCLONE) || (connected.scan_level == 3))) //occupant is viable for dna modification
if(viable_occupant.has_dna() && (!(RADIMMUNE in viable_occupant.dna.species.species_traits)) && (!(viable_occupant.has_disability(DISABILITY_NOCLONE)) || (connected.scan_level == 3))) //occupant is viable for dna modification
occupant_status += "[viable_occupant.name] => "
switch(viable_occupant.stat)
if(CONSCIOUS)
@@ -337,12 +337,12 @@
if(!num)
num = round(input(usr, "Choose pulse duration:", "Input an Integer", null) as num|null)
if(num)
radduration = Wrap(num, 1, RADIATION_DURATION_MAX+1)
radduration = WRAP(num, 1, RADIATION_DURATION_MAX+1)
if("setstrength")
if(!num)
num = round(input(usr, "Choose pulse strength:", "Input an Integer", null) as num|null)
if(num)
radstrength = Wrap(num, 1, RADIATION_STRENGTH_MAX+1)
radstrength = WRAP(num, 1, RADIATION_STRENGTH_MAX+1)
if("screen")
current_screen = href_list["text"]
if("rejuv")
@@ -353,13 +353,13 @@
if("setbufferlabel")
var/text = sanitize(input(usr, "Input a new label:", "Input an Text", null) as text|null)
if(num && text)
num = Clamp(num, 1, NUMBER_OF_BUFFERS)
num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
buffer_slot["label"] = text
if("setbuffer")
if(num && viable_occupant)
num = Clamp(num, 1, NUMBER_OF_BUFFERS)
num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
buffer[num] = list(
"label"="Buffer[num]:[viable_occupant.real_name]",
"UI"=viable_occupant.dna.uni_identity,
@@ -370,7 +370,7 @@
)
if("clearbuffer")
if(num)
num = Clamp(num, 1, NUMBER_OF_BUFFERS)
num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
buffer_slot.Cut()
@@ -387,7 +387,7 @@
apply_buffer(SCANNER_ACTION_MIXED,num)
if("injector")
if(num && injectorready < world.time)
num = Clamp(num, 1, NUMBER_OF_BUFFERS)
num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
var/obj/item/dnainjector/timed/I
@@ -436,11 +436,11 @@
injectorready = world.time + INJECTOR_TIMEOUT
if("loaddisk")
if(num && diskette && diskette.fields)
num = Clamp(num, 1, NUMBER_OF_BUFFERS)
num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
buffer[num] = diskette.fields.Copy()
if("savedisk")
if(num && diskette && !diskette.read_only)
num = Clamp(num, 1, NUMBER_OF_BUFFERS)
num = CLAMP(num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[num]
if(istype(buffer_slot))
diskette.name = "data disk \[[buffer_slot["label"]]\]"
@@ -454,8 +454,8 @@
delayed_action = list("action"=text2num(href_list["delayaction"]),"buffer"=num)
if("pulseui","pulsese")
if(num && viable_occupant && connected)
radduration = Wrap(radduration, 1, RADIATION_DURATION_MAX+1)
radstrength = Wrap(radstrength, 1, RADIATION_STRENGTH_MAX+1)
radduration = WRAP(radduration, 1, RADIATION_DURATION_MAX+1)
radstrength = WRAP(radstrength, 1, RADIATION_STRENGTH_MAX+1)
var/locked_state = connected.locked
connected.locked = TRUE
@@ -471,7 +471,7 @@
switch(href_list["task"]) //Same thing as there but values are even lower, on best part they are about 0.0*, effectively no damage
if("pulseui")
var/len = length(viable_occupant.dna.uni_identity)
num = Wrap(num, 1, len+1)
num = WRAP(num, 1, len+1)
num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len) //Each manipulator level above 1 makes randomization as accurate as selected time + manipulator lvl^2
//Value is this high for the same reason as with laser - not worth the hassle of upgrading if the bonus is low
var/block = round((num-1)/DNA_BLOCK_SIZE)+1
@@ -487,7 +487,7 @@
viable_occupant.updateappearance(mutations_overlay_update=1)
if("pulsese")
var/len = length(viable_occupant.dna.struc_enzymes)
num = Wrap(num, 1, len+1)
num = WRAP(num, 1, len+1)
num = randomize_radiation_accuracy(num, radduration + (connected.precision_coeff ** 2), len)
var/block = round((num-1)/DNA_BLOCK_SIZE)+1
@@ -518,21 +518,22 @@
ran = round(ran) //negative, so floor it
else
ran = -round(-ran) //positive, so ceiling it
return num2hex(Wrap(hex2num(input)+ran, 0, 16**length), length)
return num2hex(WRAP(hex2num(input)+ran, 0, 16**length), length)
/obj/machinery/computer/scan_consolenew/proc/randomize_radiation_accuracy(position_we_were_supposed_to_hit, radduration, number_of_blocks)
return Wrap(round(position_we_were_supposed_to_hit + gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration), 1), 1, number_of_blocks+1)
/obj/machinery/computer/scan_consolenew/proc/randomize_radiation_accuracy(position, radduration, number_of_blocks)
var/val = round(gaussian(0, RADIATION_ACCURACY_MULTIPLIER/radduration) + position, 1)
return WRAP(val, 1, number_of_blocks+1)
/obj/machinery/computer/scan_consolenew/proc/get_viable_occupant()
var/mob/living/carbon/viable_occupant = null
if(connected)
viable_occupant = connected.occupant
if(!istype(viable_occupant) || !viable_occupant.dna || (viable_occupant.disabilities & NOCLONE))
if(!istype(viable_occupant) || !viable_occupant.dna || (viable_occupant.has_disability(DISABILITY_NOCLONE)))
viable_occupant = null
return viable_occupant
/obj/machinery/computer/scan_consolenew/proc/apply_buffer(action,buffer_num)
buffer_num = Clamp(buffer_num, 1, NUMBER_OF_BUFFERS)
buffer_num = CLAMP(buffer_num, 1, NUMBER_OF_BUFFERS)
var/list/buffer_slot = buffer[buffer_num]
var/mob/living/carbon/viable_occupant = get_viable_occupant()
if(istype(buffer_slot))
@@ -106,7 +106,7 @@
return
if(!new_goal)
new_goal = default_goal
id.goal = Clamp(new_goal, 0, 1000) //maximum 1000 points
id.goal = CLAMP(new_goal, 0, 1000) //maximum 1000 points
if("toggle_open")
if(teleporter.locked)
to_chat(usr, "The teleporter is locked")
+1 -1
View File
@@ -56,7 +56,7 @@
var/loc_display = "Unknown"
var/mob/living/M = T.imp_in
if((Tr.z in GLOB.station_z_levels) && !isspaceturf(M.loc))
if(is_station_level(Tr.z) && !isspaceturf(M.loc))
var/turf/mob_loc = get_turf(M)
loc_display = mob_loc.loc
@@ -51,7 +51,7 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
/obj/machinery/computer/telecrystals/uplinker/proc/ejectuplink()
if(uplinkholder)
uplinkholder.loc = get_turf(src.loc)
uplinkholder.forceMove(drop_location())
uplinkholder = null
update_icon()
@@ -154,8 +154,11 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
/obj/machinery/computer/telecrystals/boss/proc/getDangerous()//This scales the TC assigned with the round population.
..()
var/danger = GLOB.joined_player_list.len - SSticker.mode.syndicates.len
danger = Ceiling(danger, 10)
var/list/nukeops = get_antagonists(/datum/antagonist/nukeop)
var/danger = GLOB.joined_player_list.len - nukeops.len
// var/list/nukeops = get_antagonists(/datum/antagonist/nukeop)
// var/danger = GLOB.joined_player_list.len - nukeops.len
danger = CEILING(danger, 10)
scaleTC(danger)
/obj/machinery/computer/telecrystals/boss/proc/scaleTC(amt)//Its own proc, since it'll probably need a lot of tweaks for balance, use a fancier algorhithm, etc.
@@ -223,4 +226,4 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
src.updateUsrDialog()
return
#undef NUKESCALINGMODIFIER
#undef NUKESCALINGMODIFIER
+12 -1
View File
@@ -209,4 +209,15 @@
trg.teleporter_hub.update_icon()
if(trg.teleporter_console)
trg.teleporter_console.stat &= ~NOPOWER
trg.teleporter_console.update_icon()
trg.teleporter_console.update_icon()
/obj/machinery/computer/teleporter/proc/is_eligible(atom/movable/AM)
var/turf/T = get_turf(AM)
if(!T)
return FALSE
if(is_centcom_level(T.z) || is_away_level(T.z))
return FALSE
var/area/A = get_area(T)
if(!A || A.noteleport)
return FALSE
return TRUE
+5 -5
View File
@@ -157,15 +157,15 @@
if(istype(P, /obj/item/crowbar))
playsound(src.loc, P.usesound, 50, 1)
state = 2
circuit.loc = src.loc
circuit.forceMove(drop_location())
components.Remove(circuit)
circuit = null
if(components.len == 0)
to_chat(user, "<span class='notice'>You remove the circuit board.</span>")
else
to_chat(user, "<span class='notice'>You remove the circuit board and other components.</span>")
for(var/atom/movable/A in components)
A.loc = src.loc
for(var/atom/movable/AM in components)
AM.forceMove(drop_location())
desc = initial(desc)
req_components = null
components = null
@@ -186,9 +186,9 @@
qdel(O)
new_machine.component_parts = list()
for(var/obj/O in src)
O.loc = null
O.moveToNullspace()
new_machine.component_parts += O
circuit.loc = null
circuit.moveToNullspace()
new_machine.RefreshParts()
qdel(src)
return
+2
View File
@@ -459,6 +459,8 @@
var/sound/song_played = sound(selection.song_path)
for(var/mob/M in range(10,src))
if(!M.client || !(M.client.prefs.toggles & SOUND_INSTRUMENTS))
continue
if(!(M in rangers))
rangers[M] = TRUE
M.playsound_local(get_turf(M), null, 100, channel = CHANNEL_JUKEBOX, S = song_played)
+1 -1
View File
@@ -33,7 +33,7 @@
to_chat(user, "<span class='notice'>You begin repairing [src]...</span>")
playsound(loc, WT.usesound, 40, 1)
if(do_after(user, 40*I.toolspeed, target = src))
obj_integrity = Clamp(obj_integrity + 20, 0, max_integrity)
obj_integrity = CLAMP(obj_integrity + 20, 0, max_integrity)
else
return ..()
+1 -1
View File
@@ -100,7 +100,7 @@
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
if(istype(mob_occupant))
if(locate_computer(/obj/machinery/computer/cloning))
if(!mob_occupant.suiciding && !(mob_occupant.disabilities & NOCLONE) && !mob_occupant.hellbound)
if(!mob_occupant.suiciding && !(mob_occupant.has_disability(DISABILITY_NOCLONE)) && !mob_occupant.hellbound)
mob_occupant.notify_ghost_cloning("Your corpse has been placed into a cloning scanner. Re-enter your corpse if you want to be cloned!", source = src)
// DNA manipulators cannot operate on severed heads or brains
+4 -4
View File
@@ -135,7 +135,7 @@
for(var/turf/closed/T in range(2, src))
here.ChangeTurf(T.type)
return INITIALIZE_HINT_QDEL
here.ChangeTurf(/turf/closed/wall)
here.PlaceOnTop(/turf/closed/wall)
if(9 to 11)
lights = FALSE
locked = TRUE
@@ -680,7 +680,7 @@
if(ishuman(user) && prob(40) && src.density)
var/mob/living/carbon/human/H = user
if((H.disabilities & DUMB) && Adjacent(user))
if((H.has_disability(DISABILITY_DUMB)) && Adjacent(user))
playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
if(!istype(H.head, /obj/item/clothing/head/helmet))
H.visible_message("<span class='danger'>[user] headbutts the airlock.</span>", \
@@ -1036,7 +1036,7 @@
panel_open = TRUE
update_icon(AIRLOCK_OPENING)
visible_message("<span class='warning'>[src]'s panel is blown off in a spray of deadly shrapnel!</span>")
charge.loc = get_turf(src)
charge.forceMove(drop_location())
charge.ex_act(EXPLODE_DEVASTATE)
detonated = 1
charge = null
@@ -1340,7 +1340,7 @@
else
ae = electronics
electronics = null
ae.loc = src.loc
ae.forceMove(drop_location())
qdel(src)
/obj/machinery/door/airlock/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
+1 -1
View File
@@ -142,7 +142,7 @@
. /= 10
/obj/machinery/door_timer/proc/set_timer(value)
var/new_time = Clamp(value,0,MAX_TIMER)
var/new_time = CLAMP(value,0,MAX_TIMER)
. = new_time == timer_duration //return 1 on no change
timer_duration = new_time
+63 -61
View File
@@ -1,66 +1,68 @@
/obj/machinery/door/poddoor
name = "blast door"
desc = "A heavy duty blast door that opens mechanically."
icon = 'icons/obj/doors/blastdoor.dmi'
icon_state = "closed"
var/id = 1
/obj/machinery/door/poddoor
name = "blast door"
desc = "A heavy duty blast door that opens mechanically."
icon = 'icons/obj/doors/blastdoor.dmi'
icon_state = "closed"
var/id = 1
sub_door = TRUE
explosion_block = 3
explosion_block = 3
heat_proof = TRUE
safe = FALSE
max_integrity = 600
armor = list(melee = 50, bullet = 100, laser = 100, energy = 100, bomb = 50, bio = 100, rad = 100, fire = 100, acid = 70)
resistance_flags = FIRE_PROOF
damage_deflection = 70
/obj/machinery/door/poddoor/preopen
icon_state = "open"
max_integrity = 600
armor = list(melee = 50, bullet = 100, laser = 100, energy = 100, bomb = 50, bio = 100, rad = 100, fire = 100, acid = 70)
resistance_flags = FIRE_PROOF
damage_deflection = 70
/obj/machinery/door/poddoor/preopen
icon_state = "open"
density = FALSE
opacity = 0
/obj/machinery/door/poddoor/ert
desc = "A heavy duty blast door that only opens for dire emergencies."
//special poddoors that open when emergency shuttle docks at centcom
/obj/machinery/door/poddoor/shuttledock
var/checkdir = 4 //door won't open if turf in this dir is `turftype`
var/turftype = /turf/open/space
/obj/machinery/door/poddoor/shuttledock/proc/check()
var/turf/T = get_step(src, checkdir)
if(!istype(T, turftype))
INVOKE_ASYNC(src, .proc/open)
else
INVOKE_ASYNC(src, .proc/close)
opacity = 0
/obj/machinery/door/poddoor/ert
desc = "A heavy duty blast door that only opens for dire emergencies."
//special poddoors that open when emergency shuttle docks at centcom
/obj/machinery/door/poddoor/shuttledock
var/checkdir = 4 //door won't open if turf in this dir is `turftype`
var/turftype = /turf/open/space
/obj/machinery/door/poddoor/shuttledock/proc/check()
var/turf/T = get_step(src, checkdir)
if(!istype(T, turftype))
INVOKE_ASYNC(src, .proc/open)
else
INVOKE_ASYNC(src, .proc/close)
/obj/machinery/door/poddoor/CollidedWith(atom/movable/AM)
if(density)
return 0
else
return ..()
//"BLAST" doors are obviously stronger than regular doors when it comes to BLASTS.
/obj/machinery/door/poddoor/ex_act(severity, target)
if(severity == 3)
return
..()
/obj/machinery/door/poddoor/do_animate(animation)
switch(animation)
if("opening")
flick("opening", src)
if("closing")
flick("closing", src)
/obj/machinery/door/poddoor/update_icon()
if(density)
icon_state = "closed"
else
icon_state = "open"
/obj/machinery/door/poddoor/try_to_activate_door(mob/user)
return
/obj/machinery/door/poddoor/try_to_crowbar(obj/item/I, mob/user)
if(stat & NOPOWER)
open(1)
if(density)
return 0
else
return ..()
//"BLAST" doors are obviously stronger than regular doors when it comes to BLASTS.
/obj/machinery/door/poddoor/ex_act(severity, target)
if(severity == 3)
return
..()
/obj/machinery/door/poddoor/do_animate(animation)
switch(animation)
if("opening")
flick("opening", src)
playsound(src, 'sound/machines/blastdoor.ogg', 30, 1)
if("closing")
flick("closing", src)
playsound(src, 'sound/machines/blastdoor.ogg', 30, 1)
/obj/machinery/door/poddoor/update_icon()
if(density)
icon_state = "closed"
else
icon_state = "open"
/obj/machinery/door/poddoor/try_to_activate_door(mob/user)
return
/obj/machinery/door/poddoor/try_to_crowbar(obj/item/I, mob/user)
if(stat & NOPOWER)
open(1)
+2 -2
View File
@@ -275,7 +275,7 @@
else
ae = electronics
electronics = null
ae.loc = src.loc
ae.forceMove(drop_location())
qdel(src)
return
@@ -495,4 +495,4 @@
/obj/machinery/door/window/brigdoor/security/holding/southright
dir = SOUTH
icon_state = "rightsecure"
base_state = "rightsecure"
base_state = "rightsecure"
+2 -2
View File
@@ -70,7 +70,7 @@
if(stat & NOPOWER)
return
if(src.z in GLOB.station_z_levels)
if(is_station_level(z))
add_overlay("overlay_[GLOB.security_level]")
else
add_overlay("overlay_[SEC_LEVEL_GREEN]")
@@ -124,7 +124,7 @@
var/list/data = list()
data["emagged"] = emagged
if(src.z in GLOB.station_z_levels)
if(is_station_level(z))
data["seclevel"] = get_security_level()
else
data["seclevel"] = "green"
+5 -5
View File
@@ -75,7 +75,7 @@ Possible to do for anyone motivated enough:
replay_stop()
if(record_mode)
record_stop()
QDEL_NULL(disk)
holopads -= src
@@ -256,12 +256,12 @@ Possible to do for anyone motivated enough:
temp = ""
if(outgoing_call)
outgoing_call.Disconnect()
else if(href_list["disk_eject"])
if(disk && !replay_mode)
disk.forceMove(drop_location())
disk = null
else if(href_list["replay_stop"])
replay_stop()
else if(href_list["replay_start"])
@@ -424,7 +424,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(masters[user])
var/obj/effect/overlay/holo_pad_hologram/H = masters[user]
step_to(H, new_turf)
H.loc = new_turf
H.forceMove(new_turf)
var/area/holo_area = get_area(src)
var/area/eye_area = new_turf.loc
@@ -505,7 +505,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
current_delay += entry[2]
var/time_delta = world.time - record_start - current_delay
if(time_delta >= 1)
disk.record.entries += list(list(HOLORECORD_DELAY,time_delta))
disk.record.entries += list(list(HOLORECORD_SAY,message))
+1 -1
View File
@@ -10,7 +10,7 @@
icon = 'icons/obj/machines/limbgrower.dmi'
icon_state = "limbgrower_idleoff"
density = TRUE
container_type = OPENCONTAINER_1
container_type = OPENCONTAINER
anchored = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 10

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