Merge remote-tracking branch 'refs/remotes/Citadel-Station-13/master' into IHAVENOIDEAWHATTHEFUCKIMDOING

This commit is contained in:
deathride58
2017-11-20 00:21:38 -05:00
1218 changed files with 80559 additions and 76738 deletions
+4 -4
View File
@@ -29,13 +29,13 @@
dat += "<I>Using this contract, you may summon an apprentice to aid you on your mission.</I><BR>"
dat += "<I>If you are unable to establish contact with your apprentice, you can feed the contract back to the spellbook to refund your points.</I><BR>"
dat += "<B>Which school of magic is your apprentice studying?:</B><BR>"
dat += "<A href='byond://?src=\ref[src];school=[APPRENTICE_DESTRUCTION]'>Destruction</A><BR>"
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_DESTRUCTION]'>Destruction</A><BR>"
dat += "<I>Your apprentice is skilled in offensive magic. They know Magic Missile and Fireball.</I><BR>"
dat += "<A href='byond://?src=\ref[src];school=[APPRENTICE_BLUESPACE]'>Bluespace Manipulation</A><BR>"
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_BLUESPACE]'>Bluespace Manipulation</A><BR>"
dat += "<I>Your apprentice is able to defy physics, melting through solid objects and travelling great distances in the blink of an eye. They know Teleport and Ethereal Jaunt.</I><BR>"
dat += "<A href='byond://?src=\ref[src];school=[APPRENTICE_HEALING]'>Healing</A><BR>"
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_HEALING]'>Healing</A><BR>"
dat += "<I>Your apprentice is training to cast spells that will aid your survival. They know Forcewall and Charge and come with a Staff of Healing.</I><BR>"
dat += "<A href='byond://?src=\ref[src];school=[APPRENTICE_ROBELESS]'>Robeless</A><BR>"
dat += "<A href='byond://?src=[REF(src)];school=[APPRENTICE_ROBELESS]'>Robeless</A><BR>"
dat += "<I>Your apprentice is training to cast spells without their robes. They know Knock and Mindswap.</I><BR>"
user << browse(dat, "window=radio")
onclose(user, "radio")
+39 -48
View File
@@ -6,56 +6,47 @@
var/door = 0
var/grille = 0
var/mach = 0
var/num_territories = 1//Number of total valid territories for gang mode
/datum/station_state/proc/count()
for(var/Z in GLOB.station_z_levels)
for(var/turf/T in block(locate(1,1,Z), locate(world.maxx,world.maxy,Z)))
// don't count shuttles since they may have just left
if(istype(T.loc, /area/shuttle))
continue
if(isfloorturf(T))
var/turf/open/floor/TF = T
if(!(TF.burnt))
floor += 12
else
floor += 1
if(iswallturf(T))
var/turf/closed/wall/TW = T
if(TW.intact)
wall += 2
else
wall += 1
if(istype(T, /turf/closed/wall/r_wall))
var/turf/closed/wall/r_wall/TRW = T
if(TRW.intact)
r_wall += 2
else
r_wall += 1
/datum/station_state/proc/count(count_territories)
for(var/turf/T in block(locate(1,1,1), locate(world.maxx,world.maxy,1)))
if(isfloorturf(T))
var/turf/open/floor/TF = T
if(!(TF.burnt))
src.floor += 12
else
src.floor += 1
if(iswallturf(T))
var/turf/closed/wall/TW = T
if(TW.intact)
src.wall += 2
else
src.wall += 1
if(istype(T, /turf/closed/wall/r_wall))
var/turf/closed/wall/r_wall/TRW = T
if(TRW.intact)
src.r_wall += 2
else
src.r_wall += 1
for(var/obj/O in T.contents)
if(istype(O, /obj/structure/window))
src.window += 1
else if(istype(O, /obj/structure/grille))
var/obj/structure/grille/GR = O
if(!GR.broken)
src.grille += 1
else if(istype(O, /obj/machinery/door))
src.door += 1
else if(ismachinery(O))
src.mach += 1
if(count_territories)
var/list/valid_territories = list()
for(var/area/A in world) //First, collect all area types on the station zlevel
if(A.z in GLOB.station_z_levels)
if(!(A.type in valid_territories) && A.valid_territory)
valid_territories |= A.type
if(valid_territories.len)
num_territories = valid_territories.len //Add them all up to make the total number of area types
else
to_chat(world, "ERROR: NO VALID TERRITORIES")
for(var/obj/O in T.contents)
if(istype(O, /obj/structure/window))
window += 1
else if(istype(O, /obj/structure/grille))
var/obj/structure/grille/GR = O
if(!GR.broken)
grille += 1
else if(istype(O, /obj/machinery/door))
door += 1
else if(ismachinery(O))
mach += 1
/datum/station_state/proc/score(datum/station_state/result)
if(!result)
@@ -226,6 +226,8 @@
. = ..()
if(!independent) //no pulling people deep into the blob
verbs -= /mob/living/verb/pulled
else
pass_flags &= ~PASSBLOB
/mob/living/simple_animal/hostile/blob/blobbernaut/Life()
if(..())
+9 -5
View File
@@ -79,12 +79,13 @@ GLOBAL_LIST_EMPTY(blob_nodes)
/mob/camera/blob/proc/victory()
sound_to_playing_players('sound/machines/alarm.ogg')
sleep(100)
for(var/mob/living/L in GLOB.mob_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))
continue
if(L in GLOB.overminds || L.checkpass(PASSBLOB))
if(L in GLOB.overminds || (L.pass_flags & PASSBLOB))
continue
var/area/Ablob = get_area(T)
@@ -92,9 +93,12 @@ GLOBAL_LIST_EMPTY(blob_nodes)
if(!Ablob.blob_allowed)
continue
playsound(L, 'sound/effects/splat.ogg', 50, 1)
L.death()
new/mob/living/simple_animal/hostile/blob/blobspore(T)
if(!("blob" in L.faction))
playsound(L, 'sound/effects/splat.ogg', 50, 1)
L.death()
new/mob/living/simple_animal/hostile/blob/blobspore(T)
else
L.fully_heal()
for(var/V in GLOB.sortedAreas)
var/area/A = V
+19 -18
View File
@@ -154,33 +154,34 @@
return
if(!can_buy(40))
return
B.max_integrity = initial(B.max_integrity) * 0.25 //factories that produced a blobbernaut have much lower health
B.obj_integrity = min(B.obj_integrity, B.max_integrity)
B.update_icon()
B.visible_message("<span class='warning'><b>The blobbernaut [pick("rips", "tears", "shreds")] its way out of the factory blob!</b></span>")
playsound(B.loc, 'sound/effects/splat.ogg', 50, 1)
var/mob/living/simple_animal/hostile/blob/blobbernaut/blobber = new /mob/living/simple_animal/hostile/blob/blobbernaut(get_turf(B))
flick("blobbernaut_produce", blobber)
B.naut = blobber
blobber.factory = B
blobber.overmind = src
blobber.update_icons()
blobber.notransform = 1 //stop the naut from moving around
blobber.adjustHealth(blobber.maxHealth * 0.5)
blob_mobs += blobber
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50, blobber) //players must answer rapidly
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [blob_reagent_datum.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50) //players must answer rapidly
if(candidates.len) //if we got at least one candidate, they're a blobbernaut now.
B.max_integrity = initial(B.max_integrity) * 0.25 //factories that produced a blobbernaut have much lower health
B.obj_integrity = min(B.obj_integrity, B.max_integrity)
B.update_icon()
B.visible_message("<span class='warning'><b>The blobbernaut [pick("rips", "tears", "shreds")] its way out of the factory blob!</b></span>")
playsound(B.loc, 'sound/effects/splat.ogg', 50, 1)
var/mob/living/simple_animal/hostile/blob/blobbernaut/blobber = new /mob/living/simple_animal/hostile/blob/blobbernaut(get_turf(B))
flick("blobbernaut_produce", blobber)
B.naut = blobber
blobber.factory = B
blobber.overmind = src
blobber.update_icons()
blobber.adjustHealth(blobber.maxHealth * 0.5)
blob_mobs += blobber
var/client/C = pick(candidates)
blobber.key = C.key
SEND_SOUND(blobber, sound('sound/effects/blobattack.ogg'))
SEND_SOUND(blobber, sound('sound/effects/attackblob.ogg'))
to_chat(blobber, "<b>You are a blobbernaut!</b>")
to_chat(blobber, "You are powerful, hard to kill, and slowly regenerate near nodes and cores, but will slowly die if not near the blob or if the factory that made you is killed.")
to_chat(blobber, "You are powerful, hard to kill, and slowly regenerate near nodes and cores, <span class='cultlarge'>but will slowly die if not near the blob</span> or if the factory that made you is killed.")
to_chat(blobber, "You can communicate with other blobbernauts and overminds via <b>:b</b>")
to_chat(blobber, "Your overmind's blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
to_chat(blobber, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]")
if(blobber)
blobber.notransform = 0
else
to_chat(src, "<span class='warning'>You could not conjure a sentience for your blobbernaut. Your points have been refunded. Try again later.</span>")
add_points(40)
/mob/camera/blob/verb/relocate_core()
set category = "Blob"
+2 -2
View File
@@ -67,7 +67,7 @@
return atmosblock
/obj/structure/blob/CanPass(atom/movable/mover, turf/target)
if(istype(mover) && mover.checkpass(PASSBLOB))
if(istype(mover) && (mover.pass_flags & PASSBLOB))
return 1
return 0
@@ -78,7 +78,7 @@
. = 0
if(ismovableatom(caller))
var/atom/movable/mover = caller
. = . || mover.checkpass(PASSBLOB)
. = . || (mover.pass_flags & PASSBLOB)
/obj/structure/blob/update_icon() //Updates color based on overmind color if we have an overmind.
if(overmind)
@@ -3,7 +3,7 @@
/datum/cellular_emporium
var/name = "cellular emporium"
var/datum/changeling/changeling
var/datum/antagonist/changeling/changeling
/datum/cellular_emporium/New(my_changeling)
. = ..()
@@ -32,7 +32,7 @@
var/list/abilities = list()
for(var/path in subtypesof(/obj/effect/proc_holder/changeling))
for(var/path in changeling.all_powers)
var/obj/effect/proc_holder/changeling/ability = path
var/dna_cost = initial(ability.dna_cost)
@@ -61,10 +61,10 @@
switch(action)
if("readapt")
if(changeling.canrespec)
changeling.lingRespec(usr)
changeling.readapt()
if("evolve")
var/sting_name = params["name"]
changeling.purchasePower(usr, sting_name)
changeling.purchase_power(sting_name)
/datum/action/innate/cellular_emporium
name = "Cellular Emporium"
+14 -360
View File
@@ -1,15 +1,8 @@
#define LING_FAKEDEATH_TIME 400 //40 seconds
#define LING_DEAD_GENETICDAMAGE_HEAL_CAP 50 //The lowest value of geneticdamage handle_changeling() can take it to while dead.
#define LING_ABSORB_RECENT_SPEECH 8 //The amount of recent spoken lines to gain on absorbing a mob
GLOBAL_LIST_INIT(possible_changeling_IDs, list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega"))
GLOBAL_LIST_INIT(slots, list("head", "wear_mask", "back", "wear_suit", "w_uniform", "shoes", "belt", "gloves", "glasses", "ears", "wear_id", "s_store"))
GLOBAL_LIST_INIT(slot2slot, list("head" = slot_head, "wear_mask" = slot_wear_mask, "neck" = slot_neck, "back" = slot_back, "wear_suit" = slot_wear_suit, "w_uniform" = slot_w_uniform, "shoes" = slot_shoes, "belt" = slot_belt, "gloves" = slot_gloves, "glasses" = slot_glasses, "ears" = slot_ears, "wear_id" = slot_wear_id, "s_store" = slot_s_store))
GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "wear_mask" = /obj/item/clothing/mask/changeling, "back" = /obj/item/changeling, "wear_suit" = /obj/item/clothing/suit/changeling, "w_uniform" = /obj/item/clothing/under/changeling, "shoes" = /obj/item/clothing/shoes/changeling, "belt" = /obj/item/changeling, "gloves" = /obj/item/clothing/gloves/changeling, "glasses" = /obj/item/clothing/glasses/changeling, "ears" = /obj/item/changeling, "wear_id" = /obj/item/changeling, "s_store" = /obj/item/changeling))
/datum/game_mode
var/list/datum/mind/changelings = list()
GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our this objective to all lings
/datum/game_mode/changeling
@@ -29,26 +22,8 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
<span class='green'>Changelings</span>: Accomplish the objectives assigned to you.\n\
<span class='notice'>Crew</span>: Root out and eliminate the changeling menace."
var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time
var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target
var/const/prob_right_murder_target_h = 50 // upper bound on probability of naimg the right assassination target
var/const/prob_int_item = 50 // intercept names the theft target half the time
var/const/prob_right_item_l = 25 // lower bound on probability of naming right theft target
var/const/prob_right_item_h = 50 // upper bound on probability of naming the right theft target
var/const/prob_int_sab_target = 50 // intercept names the sabotage target half the time
var/const/prob_right_sab_target_l = 25 // lower bound on probability of naming right sabotage target
var/const/prob_right_sab_target_h = 50 // upper bound on probability of naming right sabotage target
var/const/prob_right_killer_l = 25 //lower bound on probability of naming the right operative
var/const/prob_right_killer_h = 50 //upper bound on probability of naming the right operative
var/const/prob_right_objective_l = 25 //lower bound on probability of determining the objective correctly
var/const/prob_right_objective_h = 50 //upper bound on probability of determining the objective correctly
var/const/changeling_amount = 4 //hard limit on changelings if scaling is turned off
var/changeling_team_objective_type = null //If this is not null, we hand our this objective to all lings
var/list/changelings = list()
/datum/game_mode/changeling/pre_setup()
@@ -80,7 +55,6 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
return 0
/datum/game_mode/changeling/post_setup()
//Decide if it's ok for the lings to have a team objective
//And then set it up to be handed out in forge_changeling_objectives
var/list/team_objectives = subtypesof(/datum/objective/changeling_team_objective)
@@ -92,116 +66,27 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
possible_team_objectives += T
if(possible_team_objectives.len && prob(20*changelings.len))
changeling_team_objective_type = pick(possible_team_objectives)
GLOB.changeling_team_objective_type = pick(possible_team_objectives)
for(var/datum/mind/changeling in changelings)
log_game("[changeling.key] (ckey) has been selected as a changeling")
changeling.current.make_changeling()
forge_changeling_objectives(changeling)
greet_changeling(changeling)
SSticker.mode.update_changeling_icons_added(changeling)
var/datum/antagonist/changeling/new_antag = new(changeling)
new_antag.team_mode = TRUE
changeling.add_antag_datum(new_antag)
..()
/datum/game_mode/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
var/changelingcap = min(round(GLOB.joined_player_list.len / (csc * 2)) + 2, round(GLOB.joined_player_list.len / csc))
if(SSticker.mode.changelings.len >= changelingcap) //Caps number of latejoin antagonists
if(changelings.len >= changelingcap) //Caps number of latejoin antagonists
return
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2)))
if(changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
if(!(character.job in restricted_jobs))
character.mind.make_Changling()
/datum/game_mode/proc/forge_changeling_objectives(datum/mind/changeling, var/team_mode = 0)
//OBJECTIVES - random traitor objectives. Unique objectives "steal brain" and "identity theft".
//No escape alone because changelings aren't suited for it and it'd probably just lead to rampant robusting
//If it seems like they'd be able to do it in play, add a 10% chance to have to escape alone
var/escape_objective_possible = TRUE
//if there's a team objective, check if it's compatible with escape objectives
for(var/datum/objective/changeling_team_objective/CTO in changeling.objectives)
if(!CTO.escape_objective_compatible)
escape_objective_possible = FALSE
break
var/datum/objective/absorb/absorb_objective = new
absorb_objective.owner = changeling
absorb_objective.gen_amount_goal(6, 8)
changeling.objectives += absorb_objective
if(prob(60))
if(prob(85))
var/datum/objective/steal/steal_objective = new
steal_objective.owner = changeling
steal_objective.find_target()
changeling.objectives += steal_objective
else
var/datum/objective/download/download_objective = new
download_objective.owner = changeling
download_objective.gen_amount_goal()
changeling.objectives += download_objective
var/list/active_ais = active_ais()
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
var/datum/objective/destroy/destroy_objective = new
destroy_objective.owner = changeling
destroy_objective.find_target()
changeling.objectives += destroy_objective
else
if(prob(70))
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = changeling
if(team_mode) //No backstabbing while in a team
kill_objective.find_target_by_role(role = "Changeling", role_type = 1, invert = 1)
else
kill_objective.find_target()
changeling.objectives += kill_objective
else
var/datum/objective/maroon/maroon_objective = new
maroon_objective.owner = changeling
if(team_mode)
maroon_objective.find_target_by_role(role = "Changeling", role_type = 1, invert = 1)
else
maroon_objective.find_target()
changeling.objectives += maroon_objective
if (!(locate(/datum/objective/escape) in changeling.objectives) && escape_objective_possible)
var/datum/objective/escape/escape_with_identity/identity_theft = new
identity_theft.owner = changeling
identity_theft.target = maroon_objective.target
identity_theft.update_explanation_text()
changeling.objectives += identity_theft
escape_objective_possible = FALSE
if (!(locate(/datum/objective/escape) in changeling.objectives) && escape_objective_possible)
if(prob(50))
var/datum/objective/escape/escape_objective = new
escape_objective.owner = changeling
changeling.objectives += escape_objective
else
var/datum/objective/escape/escape_with_identity/identity_theft = new
identity_theft.owner = changeling
if(team_mode)
identity_theft.find_target_by_role(role = "Changeling", role_type = 1, invert = 1)
else
identity_theft.find_target()
changeling.objectives += identity_theft
escape_objective_possible = FALSE
/datum/game_mode/changeling/forge_changeling_objectives(datum/mind/changeling)
if(changeling_team_objective_type)
var/datum/objective/changeling_team_objective/team_objective = new changeling_team_objective_type
team_objective.owner = changeling
changeling.objectives += team_objective
..(changeling,1)
else
..(changeling,0)
changelings += character.mind
/datum/game_mode/changeling/generate_report()
return "The Gorlex Marauders have announced the successful raid and destruction of Central Command containment ship #S-[rand(1111, 9999)]. This ship housed only a single prisoner - \
@@ -209,29 +94,12 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
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/greet_changeling(datum/mind/changeling, you_are=1)
if (you_are)
to_chat(changeling.current, "<span class='boldannounce'>You are [changeling.changeling.changelingID], a changeling! You have absorbed and taken the form of a human.</span>")
to_chat(changeling.current, "<span class='boldannounce'>Use say \":g message\" to communicate with your fellow changelings.</span>")
to_chat(changeling.current, "<b>You must complete the following tasks:</b>")
changeling.current.playsound_local(get_turf(changeling.current), 'sound/ambience/antag/ling_aler.ogg', 100, FALSE, pressure_affected = FALSE)
if (changeling.current.mind)
var/mob/living/carbon/human/H = changeling.current
if(H.mind.assigned_role == "Clown")
to_chat(H, "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
var/obj_count = 1
for(var/datum/objective/objective in changeling.objectives)
to_chat(changeling.current, "<b>Objective #[obj_count]</b>: [objective.explanation_text]")
obj_count++
return
/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
@@ -239,8 +107,8 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
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> [changeling.changeling.changelingID]."
text += "<br><b>Genomes Extracted:</b> [changeling.changeling.absorbedcount]"
text += "<br><b>Changeling ID:</b> [ling.changelingID]."
text += "<br><b>Genomes Extracted:</b> [ling.absorbedcount]"
if(changeling.objectives.len)
var/count = 1
@@ -265,176 +133,8 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
to_chat(world, text)
return 1
/datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind)
var/list/stored_profiles = list() //list of datum/changelingprofile
var/datum/changelingprofile/first_prof = null
//var/list/absorbed_dna = list()
//var/list/protected_dna = list() //dna that is not lost when capacity is otherwise full
var/dna_max = 6 //How many extra DNA strands the changeling can store for transformation.
var/absorbedcount = 0
var/chem_charges = 20
var/chem_storage = 75
var/chem_recharge_rate = 1
var/chem_recharge_slowdown = 0
var/sting_range = 2
var/changelingID = "Changeling"
var/geneticdamage = 0
var/isabsorbing = 0
var/islinking = 0
var/geneticpoints = 10
var/purchasedpowers = list()
var/mimicing = ""
var/canrespec = 0
var/changeling_speak = 0
var/datum/dna/chosen_dna
var/obj/effect/proc_holder/changeling/sting/chosen_sting
var/datum/cellular_emporium/cellular_emporium
var/datum/action/innate/cellular_emporium/emporium_action
/datum/changeling/New(var/gender=FEMALE)
..()
var/honorific
if(gender == FEMALE)
honorific = "Ms."
else
honorific = "Mr."
if(GLOB.possible_changeling_IDs.len)
changelingID = pick(GLOB.possible_changeling_IDs)
GLOB.possible_changeling_IDs -= changelingID
changelingID = "[honorific] [changelingID]"
else
changelingID = "[honorific] [rand(1,999)]"
cellular_emporium = new(src)
emporium_action = new(cellular_emporium)
/datum/changeling/Destroy()
qdel(cellular_emporium)
cellular_emporium = null
qdel(emporium_action)
emporium_action = null
. = ..()
/datum/changeling/proc/regenerate(var/mob/living/carbon/the_ling)
if(istype(the_ling))
emporium_action.Grant(the_ling)
if(the_ling.stat == DEAD)
chem_charges = min(max(0, chem_charges + chem_recharge_rate - chem_recharge_slowdown), (chem_storage*0.5))
geneticdamage = max(LING_DEAD_GENETICDAMAGE_HEAL_CAP,geneticdamage-1)
else //not dead? no chem/geneticdamage caps.
chem_charges = min(max(0, chem_charges + chem_recharge_rate - chem_recharge_slowdown), chem_storage)
geneticdamage = max(0, geneticdamage-1)
/datum/changeling/proc/get_dna(dna_owner)
for(var/datum/changelingprofile/prof in stored_profiles)
if(dna_owner == prof.name)
return prof
/datum/changeling/proc/has_dna(datum/dna/tDNA)
for(var/datum/changelingprofile/prof in stored_profiles)
if(tDNA.is_same_as(prof.dna))
return 1
return 0
/datum/changeling/proc/can_absorb_dna(mob/living/carbon/user, mob/living/carbon/human/target, var/verbose=1)
if(stored_profiles.len)
var/datum/changelingprofile/prof = stored_profiles[1]
if(prof.dna == user.dna && stored_profiles.len >= dna_max)//If our current DNA is the stalest, we gotta ditch it.
if(verbose)
to_chat(user, "<span class='warning'>We have reached our capacity to store genetic information! We must transform before absorbing more.</span>")
return
if(!target)
return
if(NO_DNA_COPY in target.dna.species.species_traits)
if(verbose)
to_chat(user, "<span class='warning'>[target] is not compatible with our biology.</span>")
return
if((target.disabilities & NOCLONE) || (target.disabilities & HUSK))
if(verbose)
to_chat(user, "<span class='warning'>DNA of [target] is ruined beyond usability!</span>")
return
if(!ishuman(target))//Absorbing monkeys is entirely possible, but it can cause issues with transforming. That's what lesser form is for anyway!
if(verbose)
to_chat(user, "<span class='warning'>We could gain no benefit from absorbing a lesser creature.</span>")
return
if(has_dna(target.dna))
if(verbose)
to_chat(user, "<span class='warning'>We already have this DNA in storage!</span>")
return
if(!target.has_dna())
if(verbose)
to_chat(user, "<span class='warning'>[target] is not compatible with our biology.</span>")
return
return 1
/datum/changeling/proc/create_profile(mob/living/carbon/human/H, mob/living/carbon/human/user, protect = 0)
var/datum/changelingprofile/prof = new
H.dna.real_name = H.real_name //Set this again, just to be sure that it's properly set.
var/datum/dna/new_dna = new H.dna.type
H.dna.copy_dna(new_dna)
prof.dna = new_dna
prof.name = H.real_name
prof.protected = protect
prof.underwear = H.underwear
prof.undershirt = H.undershirt
prof.socks = H.socks
var/list/slots = list("head", "wear_mask", "back", "wear_suit", "w_uniform", "shoes", "belt", "gloves", "glasses", "ears", "wear_id", "s_store")
for(var/slot in slots)
if(slot in H.vars)
var/obj/item/I = H.vars[slot]
if(!I)
continue
prof.name_list[slot] = I.name
prof.appearance_list[slot] = I.appearance
prof.flags_cover_list[slot] = I.flags_cover
prof.item_color_list[slot] = I.item_color
prof.item_state_list[slot] = I.item_state
prof.exists_list[slot] = 1
else
continue
return prof
/datum/changeling/proc/add_profile(datum/changelingprofile/prof)
if(stored_profiles.len > dna_max)
if(!push_out_profile())
return
stored_profiles += prof
absorbedcount++
/datum/changeling/proc/add_new_profile(mob/living/carbon/human/H, mob/living/carbon/human/user, protect = 0)
var/datum/changelingprofile/prof = create_profile(H, protect)
add_profile(prof)
return prof
/datum/changeling/proc/remove_profile(mob/living/carbon/human/H, force = 0)
for(var/datum/changelingprofile/prof in stored_profiles)
if(H.real_name == prof.name)
if(prof.protected && !force)
continue
stored_profiles -= prof
qdel(prof)
/datum/changeling/proc/get_profile_to_remove()
for(var/datum/changelingprofile/prof in stored_profiles)
if(!prof.protected)
return prof
/datum/changeling/proc/push_out_profile()
var/datum/changelingprofile/removeprofile = get_profile_to_remove()
if(removeprofile)
stored_profiles -= removeprofile
return 1
return 0
/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
@@ -474,50 +174,4 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
if(equip)
user.equip_to_slot_or_del(C, GLOB.slot2slot[slot])
user.regenerate_icons()
/datum/changelingprofile
var/name = "a bug"
var/protected = 0
var/datum/dna/dna = null
var/list/name_list = list() //associative list of slotname = itemname
var/list/appearance_list = list()
var/list/flags_cover_list = list()
var/list/exists_list = list()
var/list/item_color_list = list()
var/list/item_state_list = list()
var/underwear
var/undershirt
var/socks
/datum/changelingprofile/Destroy()
qdel(dna)
. = ..()
/datum/changelingprofile/proc/copy_profile(datum/changelingprofile/newprofile)
newprofile.name = name
newprofile.protected = protected
newprofile.dna = new dna.type
dna.copy_dna(newprofile.dna)
newprofile.name_list = name_list.Copy()
newprofile.appearance_list = appearance_list.Copy()
newprofile.flags_cover_list = flags_cover_list.Copy()
newprofile.exists_list = exists_list.Copy()
newprofile.item_color_list = item_color_list.Copy()
newprofile.item_state_list = item_state_list.Copy()
newprofile.underwear = underwear
newprofile.undershirt = undershirt
newprofile.socks = socks
/datum/game_mode/proc/update_changeling_icons_added(datum/mind/changling_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_CHANGELING]
hud.join_hud(changling_mind.current)
set_antag_hud(changling_mind.current, "changling")
/datum/game_mode/proc/update_changeling_icons_removed(datum/mind/changling_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_CHANGELING]
hud.leave_hud(changling_mind.current)
set_antag_hud(changling_mind.current, null)
user.regenerate_icons()
@@ -26,14 +26,14 @@
/obj/effect/proc_holder/changeling/Click()
var/mob/user = usr
if(!user || !user.mind || !user.mind.changeling)
if(!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist/changeling))
return
try_to_sting(user)
/obj/effect/proc_holder/changeling/proc/try_to_sting(mob/user, mob/target)
if(!can_sting(user, target))
return
var/datum/changeling/c = user.mind.changeling
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(sting_action(user, target))
SSblackbox.add_details("changeling_powers",name)
sting_feedback(user, target)
@@ -52,7 +52,7 @@
if(req_human && !ishuman(user))
to_chat(user, "<span class='warning'>We cannot do that in this form!</span>")
return 0
var/datum/changeling/c = user.mind.changeling
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(c.chem_charges < chemical_cost)
to_chat(user, "<span class='warning'>We require at least [chemical_cost] unit\s of chemicals to do that!</span>")
return 0
@@ -1,112 +0,0 @@
/datum/changeling/proc/purchasePower(mob/living/carbon/user, sting_name)
var/obj/effect/proc_holder/changeling/thepower = null
for(var/path in subtypesof(/obj/effect/proc_holder/changeling))
var/obj/effect/proc_holder/changeling/S = path
if(initial(S.name) == sting_name)
thepower = new path()
break
if(!thepower)
to_chat(user, "This is awkward. Changeling power purchase failed, please report this bug to a coder!")
return
if(absorbedcount < thepower.req_dna)
to_chat(user, "We lack the energy to evolve this ability!")
return
if(has_sting(thepower))
to_chat(user, "We have already evolved this ability!")
return
if(thepower.dna_cost < 0)
to_chat(user, "We cannot evolve this ability.")
return
if(geneticpoints < thepower.dna_cost)
to_chat(user, "We have reached our capacity for abilities.")
return
if(user.status_flags & FAKEDEATH)//To avoid potential exploits by buying new powers while in stasis, which clears your verblist.
to_chat(user, "We lack the energy to evolve new abilities right now.")
return
geneticpoints -= thepower.dna_cost
purchasedpowers += thepower
thepower.on_purchase(user)
//Reselect powers
/datum/changeling/proc/lingRespec(mob/user)
if(!ishuman(user))
to_chat(user, "<span class='danger'>We can't remove our evolutions in this form!</span>")
return
if(canrespec)
to_chat(user, "<span class='notice'>We have removed our evolutions from this form, and are now ready to readapt.</span>")
user.remove_changeling_powers(1)
canrespec = 0
user.make_changeling(TRUE)
return 1
else
to_chat(user, "<span class='danger'>You lack the power to readapt your evolutions!</span>")
return 0
/mob/proc/make_changeling(is_respec)
if(!mind)
return
if(!ishuman(src) && !ismonkey(src))
return
if(!mind.changeling)
mind.changeling = new /datum/changeling(gender)
if(mind.changeling.purchasedpowers)
remove_changeling_powers(1)
// purchase free powers.
for(var/path in subtypesof(/obj/effect/proc_holder/changeling))
var/obj/effect/proc_holder/changeling/S = new path()
if(!S.dna_cost)
if(!mind.changeling.has_sting(S))
mind.changeling.purchasedpowers+=S
S.on_purchase(src, is_respec)
if(is_respec)
SSblackbox.add_details("changeling_power_purchase","Readapt")
var/mob/living/carbon/C = src //only carbons have dna now, so we have to typecaste
if(ishuman(C))
var/datum/changelingprofile/prof = mind.changeling.add_new_profile(C, src)
mind.changeling.first_prof = prof
var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN)
if(B)
B.vital = FALSE
B.decoy_override = TRUE
return 1
/datum/changeling/proc/reset()
chosen_sting = null
geneticpoints = initial(geneticpoints)
sting_range = initial(sting_range)
chem_storage = initial(chem_storage)
chem_recharge_rate = initial(chem_recharge_rate)
chem_charges = min(chem_charges, chem_storage)
chem_recharge_slowdown = initial(chem_recharge_slowdown)
mimicing = ""
/mob/proc/remove_changeling_powers(keep_free_powers=0)
if(ishuman(src) || ismonkey(src))
if(mind && mind.changeling)
mind.changeling.changeling_speak = 0
mind.changeling.reset()
for(var/obj/effect/proc_holder/changeling/p in mind.changeling.purchasedpowers)
if((p.dna_cost == 0 && keep_free_powers) || p.always_keep)
continue
mind.changeling.purchasedpowers -= p
p.on_refund(src)
if(hud_used)
hud_used.lingstingdisplay.icon_state = null
hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
/datum/changeling/proc/has_sting(obj/effect/proc_holder/changeling/power)
for(var/obj/effect/proc_holder/changeling/P in purchasedpowers)
if(initial(power.name) == P.name)
return 1
return 0
@@ -9,7 +9,7 @@
if(!..())
return
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.isabsorbing)
to_chat(user, "<span class='warning'>We are already absorbing!</span>")
return
@@ -22,12 +22,12 @@
return
var/mob/living/carbon/target = user.pulling
return changeling.can_absorb_dna(user,target)
return changeling.can_absorb_dna(target)
/obj/effect/proc_holder/changeling/absorbDNA/sting_action(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/mob/living/carbon/human/target = user.pulling
changeling.isabsorbing = 1
for(var/i in 1 to 3)
@@ -52,7 +52,7 @@
to_chat(target, "<span class='userdanger'>You are absorbed by the changeling!</span>")
if(!changeling.has_dna(target.dna))
changeling.add_new_profile(target, user)
changeling.add_new_profile(target)
if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
@@ -84,12 +84,14 @@
user.mind.store_memory("<B>We have no more knowledge of [target]'s speech patterns.</B>")
to_chat(user, "<span class='boldnotice'>We have no more knowledge of [target]'s speech patterns.</span>")
if(target.mind.changeling)//If the target was a changeling, suck out their extra juice and objective points!
changeling.chem_charges += min(target.mind.changeling.chem_charges, changeling.chem_storage)
changeling.absorbedcount += (target.mind.changeling.absorbedcount)
target.mind.changeling.stored_profiles.len = 1
target.mind.changeling.absorbedcount = 0
var/datum/antagonist/changeling/target_ling = target.mind.has_antag_datum(/datum/antagonist/changeling)
if(target_ling)//If the target was a changeling, suck out their extra juice and objective points!
changeling.chem_charges += min(target_ling.chem_charges, changeling.chem_storage)
changeling.absorbedcount += (target_ling.absorbedcount)
target_ling.stored_profiles.len = 1
target_ling.absorbedcount = 0
changeling.chem_charges=min(changeling.chem_charges+10, changeling.chem_storage)
@@ -1,35 +1,37 @@
/obj/effect/proc_holder/changeling/fakedeath
name = "Reviving Stasis"
desc = "We fall into a stasis, allowing us to regenerate and trick our enemies."
chemical_cost = 15
dna_cost = 0
req_dna = 1
req_stat = DEAD
//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay.
/obj/effect/proc_holder/changeling/fakedeath/sting_action(mob/living/user)
to_chat(user, "<span class='notice'>We begin our stasis, preparing energy to arise once more.</span>")
if(user.stat != DEAD)
user.emote("deathgasp")
user.tod = worldtime2text()
user.status_flags |= FAKEDEATH //play dead
user.update_stat()
user.update_canmove()
addtimer(CALLBACK(src, .proc/ready_to_regenerate, user), LING_FAKEDEATH_TIME, TIMER_UNIQUE)
return TRUE
/obj/effect/proc_holder/changeling/fakedeath/proc/ready_to_regenerate(mob/user)
if(user && user.mind && user.mind.changeling && user.mind.changeling.purchasedpowers)
to_chat(user, "<span class='notice'>We are ready to revive.</span>")
user.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/revive(null)
/obj/effect/proc_holder/changeling/fakedeath/can_sting(mob/user)
if(user.status_flags & FAKEDEATH)
to_chat(user, "<span class='warning'>We are already reviving.</span>")
return
if(!user.stat) //Confirmation for living changelings if they want to fake their death
switch(alert("Are we sure we wish to fake our own death?",,"Yes", "No"))
if("No")
return
return ..()
/obj/effect/proc_holder/changeling/fakedeath
name = "Reviving Stasis"
desc = "We fall into a stasis, allowing us to regenerate and trick our enemies."
chemical_cost = 15
dna_cost = 0
req_dna = 1
req_stat = DEAD
//Fake our own death and fully heal. You will appear to be dead but regenerate fully after a short delay.
/obj/effect/proc_holder/changeling/fakedeath/sting_action(mob/living/user)
to_chat(user, "<span class='notice'>We begin our stasis, preparing energy to arise once more.</span>")
if(user.stat != DEAD)
user.emote("deathgasp")
user.tod = worldtime2text()
user.status_flags |= FAKEDEATH //play dead
user.update_stat()
user.update_canmove()
addtimer(CALLBACK(src, .proc/ready_to_regenerate, user), LING_FAKEDEATH_TIME, TIMER_UNIQUE)
return TRUE
/obj/effect/proc_holder/changeling/fakedeath/proc/ready_to_regenerate(mob/user)
if(user && user.mind)
var/datum/antagonist/changeling/C = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(C && C.purchasedpowers)
to_chat(user, "<span class='notice'>We are ready to revive.</span>")
C.purchasedpowers += new /obj/effect/proc_holder/changeling/revive(null)
/obj/effect/proc_holder/changeling/fakedeath/can_sting(mob/user)
if(user.status_flags & FAKEDEATH)
to_chat(user, "<span class='warning'>We are already reviving.</span>")
return
if(!user.stat) //Confirmation for living changelings if they want to fake their death
switch(alert("Are we sure we wish to fake our own death?",,"Yes", "No"))
if("No")
return
return ..()
@@ -1,93 +1,93 @@
//HIVEMIND COMMUNICATION (:g)
/obj/effect/proc_holder/changeling/hivemind_comms
name = "Hivemind Communication"
desc = "We tune our senses to the airwaves to allow us to discreetly communicate and exchange DNA with other changelings."
helptext = "We will be able to talk with other changelings with :g. Exchanged DNA do not count towards absorb objectives."
dna_cost = 0
chemical_cost = -1
/obj/effect/proc_holder/changeling/hivemind_comms/on_purchase(mob/user, is_respec)
..()
var/datum/changeling/changeling=user.mind.changeling
changeling.changeling_speak = 1
to_chat(user, "<i><font color=#800080>Use say \":g message\" to communicate with the other changelings.</font></i>")
var/obj/effect/proc_holder/changeling/hivemind_upload/S1 = new
if(!changeling.has_sting(S1))
changeling.purchasedpowers+=S1
var/obj/effect/proc_holder/changeling/hivemind_download/S2 = new
if(!changeling.has_sting(S2))
changeling.purchasedpowers+=S2
// HIVE MIND UPLOAD/DOWNLOAD DNA
GLOBAL_LIST_EMPTY(hivemind_bank)
/obj/effect/proc_holder/changeling/hivemind_upload
name = "Hive Channel DNA"
desc = "Allows us to channel DNA in the airwaves to allow other changelings to absorb it."
chemical_cost = 10
dna_cost = -1
/obj/effect/proc_holder/changeling/hivemind_upload/sting_action(var/mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/list/names = list()
for(var/datum/changelingprofile/prof in changeling.stored_profiles)
if(!(prof in GLOB.hivemind_bank))
names += prof.name
if(names.len <= 0)
to_chat(user, "<span class='notice'>The airwaves already have all of our DNA.</span>")
return
var/chosen_name = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names
if(!chosen_name)
return
var/datum/changelingprofile/chosen_dna = changeling.get_dna(chosen_name)
if(!chosen_dna)
return
var/datum/changelingprofile/uploaded_dna = new chosen_dna.type
chosen_dna.copy_profile(uploaded_dna)
GLOB.hivemind_bank += uploaded_dna
to_chat(user, "<span class='notice'>We channel the DNA of [chosen_name] to the air.</span>")
return TRUE
/obj/effect/proc_holder/changeling/hivemind_download
name = "Hive Absorb DNA"
desc = "Allows us to absorb DNA that has been channeled to the airwaves. Does not count towards absorb objectives."
chemical_cost = 10
dna_cost = -1
/obj/effect/proc_holder/changeling/hivemind_download/can_sting(mob/living/carbon/user)
if(!..())
return
var/datum/changeling/changeling = user.mind.changeling
var/datum/changelingprofile/first_prof = changeling.stored_profiles[1]
if(first_prof.name == user.real_name)//If our current DNA is the stalest, we gotta ditch it.
to_chat(user, "<span class='warning'>We have reached our capacity to store genetic information! We must transform before absorbing more.</span>")
return
return 1
/obj/effect/proc_holder/changeling/hivemind_download/sting_action(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/list/names = list()
for(var/datum/changelingprofile/prof in GLOB.hivemind_bank)
if(!(prof in changeling.stored_profiles))
names[prof.name] = prof
if(names.len <= 0)
to_chat(user, "<span class='notice'>There's no new DNA to absorb from the air.</span>")
return
var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names
if(!S)
return
var/datum/changelingprofile/chosen_prof = names[S]
if(!chosen_prof)
return
var/datum/changelingprofile/downloaded_prof = new chosen_prof.type
chosen_prof.copy_profile(downloaded_prof)
changeling.add_profile(downloaded_prof)
to_chat(user, "<span class='notice'>We absorb the DNA of [S] from the air.</span>")
return TRUE
//HIVEMIND COMMUNICATION (:g)
/obj/effect/proc_holder/changeling/hivemind_comms
name = "Hivemind Communication"
desc = "We tune our senses to the airwaves to allow us to discreetly communicate and exchange DNA with other changelings."
helptext = "We will be able to talk with other changelings with :g. Exchanged DNA do not count towards absorb objectives."
dna_cost = 0
chemical_cost = -1
/obj/effect/proc_holder/changeling/hivemind_comms/on_purchase(mob/user, is_respec)
..()
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.changeling_speak = 1
to_chat(user, "<i><font color=#800080>Use say \":g message\" to communicate with the other changelings.</font></i>")
var/obj/effect/proc_holder/changeling/hivemind_upload/S1 = new
if(!changeling.has_sting(S1))
changeling.purchasedpowers+=S1
var/obj/effect/proc_holder/changeling/hivemind_download/S2 = new
if(!changeling.has_sting(S2))
changeling.purchasedpowers+=S2
// HIVE MIND UPLOAD/DOWNLOAD DNA
GLOBAL_LIST_EMPTY(hivemind_bank)
/obj/effect/proc_holder/changeling/hivemind_upload
name = "Hive Channel DNA"
desc = "Allows us to channel DNA in the airwaves to allow other changelings to absorb it."
chemical_cost = 10
dna_cost = -1
/obj/effect/proc_holder/changeling/hivemind_upload/sting_action(var/mob/user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/list/names = list()
for(var/datum/changelingprofile/prof in changeling.stored_profiles)
if(!(prof in GLOB.hivemind_bank))
names += prof.name
if(names.len <= 0)
to_chat(user, "<span class='notice'>The airwaves already have all of our DNA.</span>")
return
var/chosen_name = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names
if(!chosen_name)
return
var/datum/changelingprofile/chosen_dna = changeling.get_dna(chosen_name)
if(!chosen_dna)
return
var/datum/changelingprofile/uploaded_dna = new chosen_dna.type
chosen_dna.copy_profile(uploaded_dna)
GLOB.hivemind_bank += uploaded_dna
to_chat(user, "<span class='notice'>We channel the DNA of [chosen_name] to the air.</span>")
return TRUE
/obj/effect/proc_holder/changeling/hivemind_download
name = "Hive Absorb DNA"
desc = "Allows us to absorb DNA that has been channeled to the airwaves. Does not count towards absorb objectives."
chemical_cost = 10
dna_cost = -1
/obj/effect/proc_holder/changeling/hivemind_download/can_sting(mob/living/carbon/user)
if(!..())
return
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/datum/changelingprofile/first_prof = changeling.stored_profiles[1]
if(first_prof.name == user.real_name)//If our current DNA is the stalest, we gotta ditch it.
to_chat(user, "<span class='warning'>We have reached our capacity to store genetic information! We must transform before absorbing more.</span>")
return
return 1
/obj/effect/proc_holder/changeling/hivemind_download/sting_action(mob/user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/list/names = list()
for(var/datum/changelingprofile/prof in GLOB.hivemind_bank)
if(!(prof in changeling.stored_profiles))
names[prof.name] = prof
if(names.len <= 0)
to_chat(user, "<span class='notice'>There's no new DNA to absorb from the air.</span>")
return
var/S = input("Select a DNA absorb from the air: ", "Absorb DNA", null) as null|anything in names
if(!S)
return
var/datum/changelingprofile/chosen_prof = names[S]
if(!chosen_prof)
return
var/datum/changelingprofile/downloaded_prof = new chosen_prof.type
chosen_prof.copy_profile(downloaded_prof)
changeling.add_profile(downloaded_prof)
to_chat(user, "<span class='notice'>We absorb the DNA of [S] from the air.</span>")
return TRUE
@@ -1,30 +1,30 @@
/obj/effect/proc_holder/changeling/humanform
name = "Human Form"
desc = "We change into a human."
chemical_cost = 5
req_dna = 1
//Transform into a human.
/obj/effect/proc_holder/changeling/humanform/sting_action(mob/living/carbon/user)
var/datum/changeling/changeling = user.mind.changeling
var/list/names = list()
for(var/datum/changelingprofile/prof in changeling.stored_profiles)
names += "[prof.name]"
var/chosen_name = input("Select the target DNA: ", "Target DNA", null) as null|anything in names
if(!chosen_name)
return
var/datum/changelingprofile/chosen_prof = changeling.get_dna(chosen_name)
if(!chosen_prof)
return
if(!user || user.notransform)
return 0
to_chat(user, "<span class='notice'>We transform our appearance.</span>")
changeling.purchasedpowers -= src
var/newmob = user.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS)
changeling_transform(newmob, chosen_prof)
return TRUE
/obj/effect/proc_holder/changeling/humanform
name = "Human Form"
desc = "We change into a human."
chemical_cost = 5
req_dna = 1
//Transform into a human.
/obj/effect/proc_holder/changeling/humanform/sting_action(mob/living/carbon/user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/list/names = list()
for(var/datum/changelingprofile/prof in changeling.stored_profiles)
names += "[prof.name]"
var/chosen_name = input("Select the target DNA: ", "Target DNA", null) as null|anything in names
if(!chosen_name)
return
var/datum/changelingprofile/chosen_prof = changeling.get_dna(chosen_name)
if(!chosen_prof)
return
if(!user || user.notransform)
return 0
to_chat(user, "<span class='notice'>We transform our appearance.</span>")
changeling.purchasedpowers -= src
var/newmob = user.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS)
changeling_transform(newmob, chosen_prof)
return TRUE
@@ -8,7 +8,7 @@
/obj/effect/proc_holder/changeling/linglink/can_sting(mob/living/carbon/user)
if(!..())
return
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.islinking)
to_chat(user, "<span class='warning'>We have already formed a link with the victim!</span>")
return
@@ -19,22 +19,23 @@
to_chat(user, "<span class='warning'>We cannot link with this creature!</span>")
return
var/mob/living/carbon/target = user.pulling
if(!target.mind)
to_chat(user, "<span class='warning'>The victim has no mind to link to!</span>")
return
if(target.stat == DEAD)
to_chat(user, "<span class='warning'>The victim is dead, you cannot link to a dead mind!</span>")
return
if(target.mind.changeling)
if(target.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='warning'>The victim is already a part of the hivemind!</span>")
return
if(user.grab_state <= GRAB_AGGRESSIVE)
to_chat(user, "<span class='warning'>We must have a tighter grip to link with this creature!</span>")
return
return changeling.can_absorb_dna(user,target)
return changeling.can_absorb_dna(target)
/obj/effect/proc_holder/changeling/linglink/sting_action(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/mob/living/carbon/human/target = user.pulling
changeling.islinking = 1
for(var/i in 1 to 3)
@@ -47,7 +48,8 @@
if(3)
to_chat(user, "<span class='notice'>We mold the [target]'s mind like clay, granting [target.p_them()] the ability to speak in the hivemind!</span>")
to_chat(target, "<span class='userdanger'>A migraine throbs behind your eyes, you hear yourself screaming - but your mouth has not opened!</span>")
for(var/mob/M in GLOB.mob_list)
for(var/mi in GLOB.mob_list)
var/mob/M = mi
if(M.lingcheck() == 2)
to_chat(M, "<i><font color=#800080>We can sense a foreign presence in the hivemind...</font></i>")
target.mind.linglink = 1
@@ -1,27 +1,27 @@
/obj/effect/proc_holder/changeling/mimicvoice
name = "Mimic Voice"
desc = "We shape our vocal glands to sound like a desired voice."
helptext = "Will turn your voice into the name that you enter. We must constantly expend chemicals to maintain our form like this."
chemical_cost = 0 //constant chemical drain hardcoded
dna_cost = 1
req_human = 1
// Fake Voice
/obj/effect/proc_holder/changeling/mimicvoice/sting_action(mob/user)
var/datum/changeling/changeling=user.mind.changeling
if(changeling.mimicing)
changeling.mimicing = ""
changeling.chem_recharge_slowdown -= 0.5
to_chat(user, "<span class='notice'>We return our vocal glands to their original position.</span>")
return
var/mimic_voice = stripped_input(user, "Enter a name to mimic.", "Mimic Voice", null, MAX_NAME_LEN)
if(!mimic_voice)
return
changeling.mimicing = mimic_voice
changeling.chem_recharge_slowdown += 0.5
to_chat(user, "<span class='notice'>We shape our glands to take the voice of <b>[mimic_voice]</b>, this will slow down regenerating chemicals while active.</span>")
to_chat(user, "<span class='notice'>Use this power again to return to our original voice and return chemical production to normal levels.</span>")
return TRUE
/obj/effect/proc_holder/changeling/mimicvoice
name = "Mimic Voice"
desc = "We shape our vocal glands to sound like a desired voice."
helptext = "Will turn your voice into the name that you enter. We must constantly expend chemicals to maintain our form like this."
chemical_cost = 0 //constant chemical drain hardcoded
dna_cost = 1
req_human = 1
// Fake Voice
/obj/effect/proc_holder/changeling/mimicvoice/sting_action(mob/user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.mimicing)
changeling.mimicing = ""
changeling.chem_recharge_slowdown -= 0.5
to_chat(user, "<span class='notice'>We return our vocal glands to their original position.</span>")
return
var/mimic_voice = stripped_input(user, "Enter a name to mimic.", "Mimic Voice", null, MAX_NAME_LEN)
if(!mimic_voice)
return
changeling.mimicing = mimic_voice
changeling.chem_recharge_slowdown += 0.5
to_chat(user, "<span class='notice'>We shape our glands to take the voice of <b>[mimic_voice]</b>, this will slow down regenerating chemicals while active.</span>")
to_chat(user, "<span class='notice'>Use this power again to return to our original voice and return chemical production to normal levels.</span>")
return TRUE
@@ -83,7 +83,7 @@
//checks if we already have an organic suit and casts it off.
/obj/effect/proc_holder/changeling/suit/proc/check_suit(mob/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(!ishuman(user) || !changeling)
return 1
var/mob/living/carbon/human/H = user
@@ -122,7 +122,7 @@
user.equip_to_slot_if_possible(new suit_type(user), slot_wear_suit, 1, 1, 1)
user.equip_to_slot_if_possible(new helmet_type(user), slot_head, 1, 1, 1)
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chem_recharge_slowdown += recharge_slowdown
return TRUE
@@ -385,7 +385,7 @@
weapon_name_simple = "shield"
/obj/effect/proc_holder/changeling/weapon/shield/sting_action(mob/user)
var/datum/changeling/changeling = user.mind.changeling //So we can read the absorbedcount.
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) //So we can read the absorbedcount.
if(!changeling)
return
+36 -34
View File
@@ -1,35 +1,37 @@
/obj/effect/proc_holder/changeling/revive
name = "Revive"
desc = "We regenerate, healing all damage from our form."
helptext = "Does not regrow lost organs or a missing head."
req_stat = DEAD
always_keep = TRUE
ignores_fakedeath = TRUE
//Revive from revival stasis
/obj/effect/proc_holder/changeling/revive/sting_action(mob/living/carbon/user)
user.status_flags &= ~(FAKEDEATH)
user.tod = null
user.revive(full_heal = 1)
var/list/missing = user.get_missing_limbs()
missing -= "head" // headless changelings are funny
if(missing.len)
playsound(user, 'sound/magic/demon_consume.ogg', 50, 1)
user.visible_message("<span class='warning'>[user]'s missing limbs \
reform, making a loud, grotesque sound!</span>",
"<span class='userdanger'>Your limbs regrow, making a \
loud, crunchy sound and giving you great pain!</span>",
"<span class='italics'>You hear organic matter ripping \
and tearing!</span>")
user.emote("scream")
user.regenerate_limbs(0, list("head"))
/obj/effect/proc_holder/changeling/revive
name = "Revive"
desc = "We regenerate, healing all damage from our form."
helptext = "Does not regrow lost organs or a missing head."
req_stat = DEAD
always_keep = TRUE
ignores_fakedeath = TRUE
//Revive from revival stasis
/obj/effect/proc_holder/changeling/revive/sting_action(mob/living/carbon/user)
user.status_flags &= ~(FAKEDEATH)
user.tod = null
user.revive(full_heal = 1)
var/list/missing = user.get_missing_limbs()
missing -= "head" // headless changelings are funny
if(missing.len)
playsound(user, 'sound/magic/demon_consume.ogg', 50, 1)
user.visible_message("<span class='warning'>[user]'s missing limbs \
reform, making a loud, grotesque sound!</span>",
"<span class='userdanger'>Your limbs regrow, making a \
loud, crunchy sound and giving you great pain!</span>",
"<span class='italics'>You hear organic matter ripping \
and tearing!</span>")
user.emote("scream")
user.regenerate_limbs(0, list("head"))
user.regenerate_organs()
to_chat(user, "<span class='notice'>We have revived ourselves.</span>")
user.mind.changeling.purchasedpowers -= src
return TRUE
/obj/effect/proc_holder/changeling/revive/can_be_used_by(mob/user)
if((user.stat != DEAD) && !(user.status_flags & FAKEDEATH))
user.mind.changeling.purchasedpowers -= src
return 0
. = ..()
to_chat(user, "<span class='notice'>We have revived ourselves.</span>")
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.purchasedpowers -= src
return TRUE
/obj/effect/proc_holder/changeling/revive/can_be_used_by(mob/user)
if((user.stat != DEAD) && !(user.status_flags & FAKEDEATH))
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.purchasedpowers -= src
return 0
. = ..()
@@ -11,7 +11,7 @@
for(var/mob/living/M in get_hearers_in_view(4, user))
if(iscarbon(M))
var/mob/living/carbon/C = M
if(!C.mind || !C.mind.changeling)
if(!C.mind || !C.mind.has_antag_datum(/datum/antagonist/changeling))
C.adjustEarDamage(0, 30)
C.confused += 25
C.Jitter(50)
@@ -5,9 +5,12 @@
/obj/effect/proc_holder/changeling/sting/Click()
var/mob/user = usr
if(!user || !user.mind || !user.mind.changeling)
if(!user || !user.mind)
return
if(!(user.mind.changeling.chosen_sting))
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(!changeling)
return
if(!changeling.chosen_sting)
set_sting(user)
else
unset_sting(user)
@@ -15,41 +18,48 @@
/obj/effect/proc_holder/changeling/sting/proc/set_sting(mob/user)
to_chat(user, "<span class='notice'>We prepare our sting, use alt+click or middle mouse button on target to sting them.</span>")
user.mind.changeling.chosen_sting = src
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
/obj/effect/proc_holder/changeling/sting/proc/unset_sting(mob/user)
to_chat(user, "<span class='warning'>We retract our sting, we can't sting anyone for now.</span>")
user.mind.changeling.chosen_sting = null
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
/mob/living/carbon/proc/unset_sting()
if(mind && mind.changeling && mind.changeling.chosen_sting)
src.mind.changeling.chosen_sting.unset_sting(src)
if(mind)
var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling && changeling.chosen_sting)
changeling.chosen_sting.unset_sting(src)
/obj/effect/proc_holder/changeling/sting/can_sting(mob/user, mob/target)
if(!..())
return
if(!user.mind.changeling.chosen_sting)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(!changeling.chosen_sting)
to_chat(user, "We haven't prepared our sting yet!")
if(!iscarbon(target))
return
if(!isturf(user.loc))
return
if(!AStar(user, target.loc, /turf/proc/Distance, user.mind.changeling.sting_range, simulated_only = 0))
if(!AStar(user, target.loc, /turf/proc/Distance, changeling.sting_range, simulated_only = 0))
return
if(target.mind && target.mind.changeling)
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/changeling))
sting_feedback(user, target)
user.mind.changeling.chem_charges -= chemical_cost
changeling.chem_charges -= chemical_cost //??
return 1
/obj/effect/proc_holder/changeling/sting/sting_feedback(mob/user, mob/target)
if(!target)
return
to_chat(user, "<span class='notice'>We stealthily sting [target.name].</span>")
if(target.mind && target.mind.changeling)
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(target, "<span class='warning'>You feel a tiny prick.</span>")
return 1
@@ -65,7 +75,7 @@
/obj/effect/proc_holder/changeling/sting/transformation/Click()
var/mob/user = usr
var/datum/changeling/changeling = user.mind.changeling
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.chosen_sting)
unset_sting(user)
return
@@ -163,12 +173,14 @@
/obj/effect/proc_holder/changeling/sting/extract_dna/can_sting(mob/user, mob/target)
if(..())
return user.mind.changeling.can_absorb_dna(user, target)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
return changeling.can_absorb_dna(target)
/obj/effect/proc_holder/changeling/sting/extract_dna/sting_action(mob/user, mob/living/carbon/human/target)
add_logs(user, target, "stung", "extraction sting")
if(!(user.mind.changeling.has_dna(target.dna)))
user.mind.changeling.add_new_profile(target, user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(!(changeling.has_dna(target.dna)))
changeling.add_new_profile(target)
return TRUE
/obj/effect/proc_holder/changeling/sting/mute
+121 -118
View File
@@ -1,126 +1,129 @@
/obj/effect/proc_holder/changeling/transform
name = "Transform"
desc = "We take on the appearance and voice of one we have absorbed."
chemical_cost = 5
dna_cost = 0
req_dna = 1
req_human = 1
/obj/item/clothing/glasses/changeling
name = "flesh"
/obj/effect/proc_holder/changeling/transform
name = "Transform"
desc = "We take on the appearance and voice of one we have absorbed."
chemical_cost = 5
dna_cost = 0
req_dna = 1
req_human = 1
/obj/item/clothing/glasses/changeling
name = "flesh"
flags_1 = NODROP_1
/obj/item/clothing/glasses/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/under/changeling
name = "flesh"
/obj/item/clothing/glasses/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/under/changeling
name = "flesh"
flags_1 = NODROP_1
/obj/item/clothing/under/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/suit/changeling
name = "flesh"
/obj/item/clothing/under/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/suit/changeling
name = "flesh"
flags_1 = NODROP_1
allowed = list(/obj/item/changeling)
/obj/item/clothing/suit/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/head/changeling
name = "flesh"
allowed = list(/obj/item/changeling)
/obj/item/clothing/suit/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/head/changeling
name = "flesh"
flags_1 = NODROP_1
/obj/item/clothing/head/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/shoes/changeling
name = "flesh"
/obj/item/clothing/head/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/shoes/changeling
name = "flesh"
flags_1 = NODROP_1
/obj/item/clothing/shoes/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/gloves/changeling
name = "flesh"
/obj/item/clothing/shoes/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/gloves/changeling
name = "flesh"
flags_1 = NODROP_1
/obj/item/clothing/gloves/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/mask/changeling
name = "flesh"
/obj/item/clothing/gloves/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/clothing/mask/changeling
name = "flesh"
flags_1 = NODROP_1
/obj/item/clothing/mask/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/changeling
name = "flesh"
/obj/item/clothing/mask/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
/obj/item/changeling
name = "flesh"
flags_1 = NODROP_1
slot_flags = ALL
allowed = list(/obj/item/changeling)
/obj/item/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.changeling)
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
//Change our DNA to that of somebody we've absorbed.
/obj/effect/proc_holder/changeling/transform/sting_action(mob/living/carbon/human/user)
var/datum/changeling/changeling = user.mind.changeling
var/datum/changelingprofile/chosen_prof = changeling.select_dna("Select the target DNA: ", "Target DNA", user)
if(!chosen_prof)
return
changeling_transform(user, chosen_prof)
return TRUE
/datum/changeling/proc/select_dna(var/prompt, var/title, var/mob/living/carbon/user)
var/list/names = list("Drop Flesh Disguise")
for(var/datum/changelingprofile/prof in stored_profiles)
names += "[prof.name]"
var/chosen_name = input(prompt, title, null) as null|anything in names
if(!chosen_name)
return
if(chosen_name == "Drop Flesh Disguise")
for(var/slot in GLOB.slots)
if(istype(user.vars[slot], GLOB.slot2type[slot]))
qdel(user.vars[slot])
var/datum/changelingprofile/prof = get_dna(chosen_name)
return prof
slot_flags = ALL
allowed = list(/obj/item/changeling)
/obj/item/changeling/attack_hand(mob/user)
if(loc == user && user.mind && user.mind.has_antag_datum(/datum/antagonist/changeling))
to_chat(user, "<span class='notice'>You reabsorb [src] into your body.</span>")
qdel(src)
return
..()
//Change our DNA to that of somebody we've absorbed.
/obj/effect/proc_holder/changeling/transform/sting_action(mob/living/carbon/human/user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/datum/changelingprofile/chosen_prof = changeling.select_dna("Select the target DNA: ", "Target DNA")
if(!chosen_prof)
return
changeling_transform(user, chosen_prof)
return TRUE
/datum/antagonist/changeling/proc/select_dna(var/prompt, var/title)
var/mob/living/carbon/user = owner.current
if(!istype(user))
return
var/list/names = list("Drop Flesh Disguise")
for(var/datum/changelingprofile/prof in stored_profiles)
names += "[prof.name]"
var/chosen_name = input(prompt, title, null) as null|anything in names
if(!chosen_name)
return
if(chosen_name == "Drop Flesh Disguise")
for(var/slot in GLOB.slots)
if(istype(user.vars[slot], GLOB.slot2type[slot]))
qdel(user.vars[slot])
var/datum/changelingprofile/prof = get_dna(chosen_name)
return prof
@@ -10,6 +10,7 @@
reroll_friendly = 1
var/list/possible_changelings = list()
var/list/changelings = list()
var/const/changeling_amount = 1 //hard limit on changelings if scaling is turned off
/datum/game_mode/traitor/changeling/announce()
@@ -57,25 +58,22 @@
/datum/game_mode/traitor/changeling/post_setup()
for(var/datum/mind/changeling in changelings)
changeling.current.make_changeling()
forge_changeling_objectives(changeling)
greet_changeling(changeling)
SSticker.mode.update_changeling_icons_added(changeling)
..()
return
changeling.add_antag_datum(/datum/antagonist/changeling)
return ..()
/datum/game_mode/traitor/changeling/make_antag_chance(mob/living/carbon/human/character) //Assigns changeling to latejoiners
var/csc = CONFIG_GET(number/changeling_scaling_coeff)
var/changelingcap = min( round(GLOB.joined_player_list.len / (csc * 4)) + 2, round(GLOB.joined_player_list.len / (csc * 2)))
if(SSticker.mode.changelings.len >= changelingcap) //Caps number of latejoin antagonists
if(changelings.len >= changelingcap) //Caps number of latejoin antagonists
..()
return
if(SSticker.mode.changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4)))
if(changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4)))
if(ROLE_CHANGELING in character.client.prefs.be_special)
if(!jobban_isbanned(character, ROLE_CHANGELING) && !jobban_isbanned(character, "Syndicate"))
if(age_check(character.client))
if(!(character.job in restricted_jobs))
character.mind.make_Changling()
changelings += character.mind
..()
/datum/game_mode/traitor/changeling/generate_report()
@@ -273,6 +273,7 @@ Credit where due:
if(plasmaman && !visualsOnly) //If we need to breathe from the plasma tank, we should probably start doing that
H.internal = H.get_item_for_held_index(2)
H.update_internals_hud_icon(1)
H.sec_hud_set_ID()
/obj/item/paper/servant_primer
name = "The Ark And You: A Primer On Servitude"
@@ -38,8 +38,11 @@
beckon(AM)
/obj/effect/clockwork/city_of_cogs_rift/proc/beckon(atom/movable/AM)
var/turf/T = get_turf(pick(GLOB.city_of_cogs_spawns))
if(is_servant_of_ratvar(AM))
T = GLOB.ark_of_the_clockwork_justiciar ? get_step(GLOB.ark_of_the_clockwork_justiciar, SOUTH) : get_turf(pick(GLOB.servant_spawns))
AM.visible_message("<span class='danger'>[AM] passes through [src]!</span>", ignored_mob = AM)
AM.forceMove(pick(!is_servant_of_ratvar(AM) ? GLOB.city_of_cogs_spawns : GLOB.servant_spawns))
AM.forceMove(T)
AM.visible_message("<span class='danger'>[AM] materializes from the air!</span>", \
"<span class='boldannounce'>You pass through [src] and appear [is_servant_of_ratvar(AM) ? "back at the City of Cogs" : "somewhere unfamiliar. Looks like it was a one-way trip.."].</span>")
do_sparks(5, TRUE, src)
@@ -162,7 +162,7 @@
var/locname = initial(A.name)
possible_targets[avoid_assoc_duplicate_keys("[locname] [O.name]", teleportnames)] = O
for(var/mob/living/L in GLOB.living_mob_list)
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
possible_targets[avoid_assoc_duplicate_keys("[L.name] ([L.real_name])", teleportnames)] = L
@@ -104,7 +104,7 @@ List of nuances:
if(isliving(AM))
var/mob/living/L = AM
if(!whisper)
L.say(message, "clock", spans, language=/datum/language/common)
L.say(message, "clock", spans, language=/datum/language/common, ignore_spam = TRUE)
else
L.whisper(message, "clock", spans, language=/datum/language/common)
else
@@ -1,8 +1,7 @@
/obj/item/clockwork/slab //Clockwork slab: The most important tool in Ratvar's arsenal. Allows scripture recital, tutorials, and generates components.
name = "clockwork slab"
desc = "A strange metal tablet. A clock in the center turns around and around."
clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant.\n\
Hitting a slab, a Servant with a slab, or a cache will <b>transfer</b> this slab's components into the target, the target's slab, or the global cache, respectively."
clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant."
icon_state = "dread_ipad"
lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
@@ -231,7 +230,7 @@
this will cause you to whisper your message aloud, so doing so in a public place is very suspicious and you should try to restrict it to private use.<br><br>"
dat += "If you aren't willing or don't have the time to read through every section, you can still help your teammates! Ask if they've set up a base. If they have, head there \
and ask however you can help; chances are there's always something. If not, it's your job as a Servant to get one up and running! Try to find a secluded, low-traffic area, \
like the auxilary base or somewhere deep in maintenance. You'll want to go into the Drivers section of the slab and look for <i>Tinkerer's Cache.</i> Find a nice spot and \
like the auxiliary base or somewhere deep in maintenance. You'll want to go into the Drivers section of the slab and look for <i>Tinkerer's Cache.</i> Find a nice spot and \
create one. This serves as a storage for <i>components,</i> the cult's primary resource. (Your slab's probably produced a few by now.) By attacking that cache with this \
slab, you'll offload all your components into it, and all Servants will be able to use those components from any distance - all Tinkerer's Caches are linked!<br><br>"
dat += "Once you have a base up and running, contact your fellows and let them know. You should come back here often to drop off the slab's components, and your fellows \
@@ -250,7 +249,7 @@
teamwork is an instrumental component of your success.<br><br>" //get it? component? ha!
dat += "As a Servant of Ratvar, the tools you are given focus around building and maintaining bases and outposts. A great deal of your power comes from stationary \
structures, and without constructing a base somewhere, it's essentially impossible to succeed. Finding a good spot to build a base can be difficult, and it's recommended \
that you choose an area in low-traffic part of the station (such as the auxilary base). Make sure to disconnect any cameras in the area beforehand.<br><br>"
that you choose an area in low-traffic part of the station (such as the auxiliary base). Make sure to disconnect any cameras in the area beforehand.<br><br>"
dat += "Because of how complex being a Servant is, it isn't possible to fit much information into this section. It's highly recommended that you read the <b>Components</b> \
and <b>Scripture</b> sections next. Not knowing how these two systems work will cripple both you and your fellows, and lead to a frustrating experience for everyone.<br><br>"
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
@@ -17,6 +17,7 @@
attack_sound = 'sound/weapons/bladeslice.ogg'
weather_immunities = list("lava")
movement_type = FLYING
a_intent = INTENT_HARM
loot = list(/obj/item/clockwork/component/geis_capacitor/fallen_armor)
light_range = 2
light_power = 1.1
@@ -24,7 +25,6 @@
unique abilities, you're a fearsome fighter in one-on-one combat, and your shield protects from projectiles!<br><br>Obey the Servants and do as they \
tell you. Your primary goal is to defend the Ark from destruction; they are your allies in this, and should be protected from harm.</b>"
empower_string = "<span class='neovgre'>The Anima Bulwark's power flows through you! Your weapon will strike harder, your armor is sturdier, and your shield is more durable.</span>"
var/deflect_chance = 40 //Chance to deflect any given projectile (non-damaging energy projectiles are always deflected)
var/max_shield_health = 3
var/shield_health = 3 //Amount of projectiles that can be deflected within
var/shield_health_regen = 0 //When world.time equals this, shield health will regenerate
@@ -55,8 +55,6 @@
obj_damage = 100
max_shield_health = INFINITY
else if(GLOB.ratvar_approaches) //Hefty health bonus and slight attack damage increase
health = 200
maxHealth = 200
melee_damage_upper = 15
melee_damage_lower = 15
attacktext = "carves"
@@ -53,6 +53,7 @@ Applications: 8 servants, 3 caches, and 100 CV
if(slab.busy)
to_chat(invoker, "<span class='warning'>[slab] refuses to work, displaying the message: \"[slab.busy]!\"</span>")
return FALSE
pre_recital()
slab.busy = "Invocation ([name]) in progress"
if(GLOB.ratvar_awakens)
channel_time *= 0.5 //if ratvar has awoken, half channel time and no cost
@@ -176,6 +177,9 @@ Applications: 8 servants, 3 caches, and 100 CV
/datum/clockwork_scripture/proc/scripture_fail() //Called if the scripture fails to invoke.
/datum/clockwork_scripture/proc/pre_recital() //Called before the scripture is recited
/datum/clockwork_scripture/proc/post_recital() //Called after the scripture is recited
//Channeled scripture begins instantly but runs constantly
@@ -7,12 +7,12 @@
/datum/clockwork_scripture/create_object/construct/clockwork_marauder
descname = "Well-Rounded Combat Construct"
name = "Clockwork Marauder"
desc = "Creates a shell for a clockwork marauder, a balanced frontline construct."
desc = "Creates a shell for a clockwork marauder, a balanced frontline construct that can deflect projectiles with its shield."
invocations = list("Arise, avatar of Arbiter!", "Defend the Ark with vengeful zeal.")
channel_time = 50
power_cost = 1000
creator_message = "<span class='brass'>Your slab disgorges several chunks of replicant alloy that form into a suit of thrumming armor.</span>"
usage_tip = "The marauder's shield can effectively deflect energy-based projectiles."
usage_tip = "Reciting this scripture multiple times in a short period will cause it to take longer!"
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
primary_component = BELLIGERENT_EYE
@@ -22,6 +22,9 @@
object_path = /obj/item/clockwork/construct_chassis/clockwork_marauder
construct_type = /mob/living/simple_animal/hostile/clockwork/marauder
combat_construct = TRUE
var/static/recent_marauders = 0
var/static/time_since_last_marauder = 0
var/static/scaled_recital_time = 0
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/update_construct_limit()
var/human_servants = 0
@@ -32,15 +35,30 @@
construct_limit = human_servants / 4 //1 per 4 human servants, and a maximum of 3 marauders
construct_limit = Clamp(construct_limit, 1, 3)
/datum/clockwork_scripture/create_object/prolonging_prism/check_special_requirements()
if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
to_chat(invoker, "<span class='inathneq'>\"It is too late to construct one of these, champion.\"</span>")
return FALSE
var/turf/T = get_turf(invoker)
if(!T || !(T.z in GLOB.station_z_levels))
to_chat(invoker, "<span class='inathneq'>\"You must be on the station to construct one of these, champion.\"</span>")
return FALSE
return ..()
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/pre_recital()
channel_time = initial(channel_time)
calculate_scaling()
if(scaled_recital_time)
to_chat(invoker, "<span class='warning'>The Hierophant Network is under strain from repeated summoning, making this scripture [scaled_recital_time / 10] seconds slower!</span>")
channel_time += scaled_recital_time
return TRUE
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/scripture_effects()
. = ..()
time_since_last_marauder = world.time
recent_marauders++
calculate_scaling()
/datum/clockwork_scripture/create_object/construct/clockwork_marauder/proc/calculate_scaling()
var/WT = world.time
var/MT = time_since_last_marauder //Cast it for quicker reference
var/marauders_to_exclude = 0
if(world.time >= time_since_last_marauder + MARAUDER_SCRIPTURE_SCALING_THRESHOLD)
marauders_to_exclude = round(WT - MT) / MARAUDER_SCRIPTURE_SCALING_THRESHOLD //If at least 20 seconds have passed, lose one marauder for each 20 seconds
//i.e. world.time = 10000, last marauder = 9000, so we lose 5 marauders from the recent count since 10k - 9k = 1k, 1k / 200 = 5
time_since_last_marauder = world.time //So that it can't be spammed to make the marauder exclusion plummet; this emulates "ticking"
recent_marauders = max(0, recent_marauders - marauders_to_exclude)
scaled_recital_time = min(recent_marauders * MARAUDER_SCRIPTURE_SCALING_TIME, MARAUDER_SCRIPTURE_SCALING_MAX)
//Mania Motor: Creates a malevolent transmitter that will broadcast the whispers of Sevtug into the minds of nearby nonservants, causing a variety of mental effects at a power cost.
@@ -129,7 +129,11 @@
/datum/clockwork_scripture/abscond/scripture_effects()
var/take_pulling = invoker.pulling && isliving(invoker.pulling) && get_clockwork_power(ABSCOND_ABDUCTION_COST)
var/turf/T = get_turf(pick(GLOB.servant_spawns))
var/turf/T
if(GLOB.ark_of_the_clockwork_justiciar)
T = get_step(GLOB.ark_of_the_clockwork_justiciar, SOUTH)
else
T = get_turf(pick(GLOB.servant_spawns))
invoker.visible_message("<span class='warning'>[invoker] flickers and phases out of existence!</span>", \
"<span class='bold sevtug_small'>You feel a dizzying sense of vertigo as you're yanked back to Reebe!</span>")
T.visible_message("<span class='warning'>[invoker] flickers and phases into existence!</span>")
@@ -322,7 +322,7 @@
to_chat(invoker, "<span class='warning'>You must not be inside an object to use this scripture!</span>")
return FALSE
var/other_servants = 0
for(var/mob/living/L in GLOB.living_mob_list)
for(var/mob/living/L in GLOB.alive_mob_list)
if(is_servant_of_ratvar(L) && !L.stat && L != invoker)
other_servants++
for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in GLOB.all_clockwork_objects)
@@ -134,11 +134,21 @@
var/damage = max((obj_integrity * 0.7) / severity, 100) //requires multiple bombs to take down
take_damage(damage, BRUTE, "bomb", 0)
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/get_arrival_time(var/deciseconds = TRUE)
if(seconds_until_activation)
. = seconds_until_activation
else if(grace_period)
. = grace_period
else if(GATEWAY_RATVAR_ARRIVAL - progress_in_seconds > 0)
. = round(max((GATEWAY_RATVAR_ARRIVAL - progress_in_seconds) / (GATEWAY_SUMMON_RATE), 0), 1)
if(deciseconds)
. *= 10
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/get_arrival_text(s_on_time)
if(seconds_until_activation)
return "[seconds_until_activation][s_on_time ? "S" : ""]"
return "[get_arrival_time()][s_on_time ? "S" : ""]"
if(grace_period)
return "[grace_period][s_on_time ? "S" : ""]"
return "[get_arrival_time()][s_on_time ? "S" : ""]"
. = "IMMINENT"
if(!obj_integrity)
. = "DETONATING"
@@ -151,12 +161,12 @@
icon_state = initial(icon_state)
if(is_servant_of_ratvar(user) || isobserver(user))
if(!active)
to_chat(user, "<span class='big'><b>Seconds until the Ark's activation:</b> [get_arrival_text(TRUE)]</span>")
to_chat(user, "<span class='big'><b>Time until the Ark's activation:</b> [DisplayTimeText(get_arrival_time())]</span>")
else
if(grace_period)
to_chat(user, "<span class='big'><b>Crew grace period time remaining:</b> [get_arrival_text(TRUE)]</span>")
to_chat(user, "<span class='big'><b>Crew grace period time remaining:</b> [DisplayTimeText(get_arrival_time())]</span>")
else
to_chat(user, "<span class='big'><b>Seconds until Ratvar's arrival:</b> [get_arrival_text(TRUE)]</span>")
to_chat(user, "<span class='big'><b>Time until Ratvar's arrival:</b> [DisplayTimeText(get_arrival_time())]</span>")
switch(progress_in_seconds)
if(-INFINITY to GATEWAY_REEBE_FOUND)
to_chat(user, "<span class='heavy_brass'>The Ark is feeding power into the bluespace field.</span>")
@@ -266,15 +276,16 @@
CHECK_TICK
/obj/structure/destructible/clockwork/massive/celestial_gateway/attack_ghost(mob/user)
if(!user.client || !user.client.holder)
return
if(!IsAdminGhost(user))
return ..()
if(GLOB.servants_active)
to_chat(user, "<span class='danger'>The Ark is already counting down.</span>")
return
return ..()
if(alert(user, "Activate the Ark's countdown?", name, "Yes", "No") == "Yes")
if(alert(user, "REALLY activate the Ark's countdown?", name, "Yes", "No") == "Yes")
if(alert(user, "You're REALLY SURE? This cannot be undone.", name, "Yes - Activate the Ark", "No") == "Yes - Activate the Ark")
message_admins("<span class='danger'>Admin [key_name_admin(user)] started the Ark's countdown!</span>")
log_admin("Admin [key_name(user)] started the Ark's countdown on a non-clockcult mode!")
to_chat(user, "<span class='userdanger'>The gamemode is now being treated as clockwork cult, and the Ark is counting down from 30 \
minutes. You will need to create servant players yourself.</span>")
final_countdown(35)
@@ -100,7 +100,7 @@
continue
C.update_values()
to_chat(C, C.empower_string)
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
if(is_servant_of_ratvar(H))
to_chat(H, "<span class='bold alloy'>The beacon's power warps your body into a clockwork form! You are now immune to many hazards, and your body is more robust against damage!</span>")
H.set_species(/datum/species/golem/clockwork/no_scrap)
@@ -67,7 +67,7 @@
T.ratvar_act(TRUE)
var/dir_to_step_in = pick(GLOB.cardinals)
var/list/meals = list()
for(var/mob/living/L in GLOB.living_mob_list) //we want to know who's alive so we don't lose and retarget a single person
for(var/mob/living/L in GLOB.alive_mob_list) //we want to know who's alive so we don't lose and retarget a single person
if(L.z == z && !is_servant_of_ratvar(L) && L.mind)
meals += L
if(GLOB.cult_narsie && GLOB.cult_narsie.z == z)
+12 -1
View File
@@ -1,3 +1,5 @@
#define CULT_SCALING_COEFFICIENT 9.3 //Roughly one new cultist at roundstart per this many players
/datum/game_mode
var/list/datum/mind/cult = list()
var/list/cult_objectives = list()
@@ -64,7 +66,10 @@
restricted_jobs += "Assistant"
//cult scaling goes here
recommended_enemies = 3 + round(num_players()/15)
recommended_enemies = 1 + round(num_players()/CULT_SCALING_COEFFICIENT)
var/remaining = (num_players() % CULT_SCALING_COEFFICIENT) * 10 //Basically the % of how close the population is toward adding another cultis
if(prob(remaining))
recommended_enemies++
for(var/cultists_number = 1 to recommended_enemies)
@@ -256,6 +261,10 @@
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
@@ -303,3 +312,5 @@
SSticker.news_report = CULT_FAILURE
text += "<br><B>Objective #[obj_count]</B>: [explanation]"
to_chat(world, text)
#undef CULT_SCALING_COEFFICIENT
+2 -1
View File
@@ -40,7 +40,8 @@
else if(!ishuman(user))
title = "Construct"
my_message = "<span class='[span]'><b>[title] [findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]:</b> [message]</span>"
for(var/mob/M in GLOB.mob_list)
for(var/i in GLOB.player_list)
var/mob/M = i
if(iscultist(M))
to_chat(M, my_message)
else if(M in GLOB.dead_mob_list)
+1 -1
View File
@@ -324,7 +324,7 @@
icon_state = "cult_armor"
item_state = "cult_armor"
desc = "A heavily-armored exosuit worn by warriors of the Nar-Sien cult. It can withstand hard vacuum."
w_class = WEIGHT_CLASS_SMALL
w_class = WEIGHT_CLASS_BULKY
allowed = list(/obj/item/tome, /obj/item/melee/cultblade, /obj/item/tank/internals/)
armor = list(melee = 70, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30, fire = 40, acid = 75)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/cult
+1 -1
View File
@@ -137,7 +137,7 @@ structure_check() searches for nearby cultist structures required for the invoca
for(var/M in invokers)
var/mob/living/L = M
if(invocation)
L.say(invocation, language = /datum/language/common)
L.say(invocation, language = /datum/language/common, ignore_spam = TRUE)
if(invoke_damage)
L.apply_damage(invoke_damage, BRUTE)
to_chat(L, "<span class='cultitalic'>[src] saps your strength!</span>")
+1 -1
View File
@@ -22,7 +22,7 @@
dat += "<HR>"
for(var/s in possible_summons)
var/datum/cult_supply/S = s
dat += "<a href='?src=\ref[src];id=[initial(S.id)]'>[initial(S.invocation)]</a> - [initial(S.desc)]<br>"
dat += "<a href='?src=[REF(src)];id=[initial(S.id)]'>[initial(S.invocation)]</a> - [initial(S.desc)]<br>"
var/datum/browser/popup = new(user, "talisman", "", 400, 400)
popup.set_content(dat.Join(""))
popup.open()
+2 -3
View File
@@ -225,8 +225,8 @@
/obj/item/paper/talisman/horror/afterattack(mob/living/target, mob/living/user)
if(iscultist(user) && (get_dist(user, target) < 7))
to_chat(user, "<span class='cultitalic'>You disturb [target] with visions of madness!</span>")
if(iscarbon(target))
to_chat(user, "<span class='cultitalic'>You disturb [target] with visions of madness!</span>")
var/mob/living/carbon/H = target
H.reagents.add_reagent("mindbreaker", 12)
if(is_servant_of_ratvar(target))
@@ -234,8 +234,7 @@
target.emote("scream")
target.confused = max(0, target.confused + 3)
target.flash_act()
qdel(src)
qdel(src)
//Talisman of Fabrication: Creates a construct shell out of 25 metal sheets, or converts plasteel into runed metal up to 25 times
/obj/item/paper/talisman/construction
@@ -17,6 +17,7 @@
var/ascended = FALSE
sight = (SEE_TURFS | SEE_OBJS)
status_flags = CANPUSH
spacewalk = TRUE
mob_size = MOB_SIZE_LARGE
var/mob/living/oldform
var/list/devil_overlays[DEVIL_TOTAL_LAYERS]
@@ -135,9 +136,6 @@
"<span class='userdanger'>[attack_message]</span>", null, COMBAT_MESSAGE_RANGE)
return TRUE
/mob/living/carbon/true_devil/Process_Spacemove(movement_dir = 0)
return 1
/mob/living/carbon/true_devil/singularity_act()
if(ascended)
return 0
+13 -18
View File
@@ -160,7 +160,7 @@
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
replacementmode.restricted_jobs += "Assistant"
message_admins("The roundtype will be converted. If you have other plans for the station or feel the station is too messed up to inhabit <A HREF='?_src_=holder;[HrefToken()];toggle_midround_antag=\ref[usr]'>stop the creation of antags</A> or <A HREF='?_src_=holder;[HrefToken()];end_round=\ref[usr]'>end the round now</A>.")
message_admins("The roundtype will be converted. If you have other plans for the station or feel the station is too messed up to inhabit <A HREF='?_src_=holder;[HrefToken()];toggle_midround_antag=[REF(usr)]'>stop the creation of antags</A> or <A HREF='?_src_=holder;[HrefToken()];end_round=[REF(usr)]'>end the round now</A>.")
. = 1
sleep(rand(600,1800))
@@ -217,7 +217,7 @@
if(living_antag_player && living_antag_player.mind && isliving(living_antag_player) && living_antag_player.stat != DEAD && !isnewplayer(living_antag_player) &&!isbrain(living_antag_player))
return 0 //A resource saver: once we find someone who has to die for all antags to be dead, we can just keep checking them, cycling over everyone only when we lose our mark.
for(var/mob/Player in GLOB.living_mob_list)
for(var/mob/Player in GLOB.alive_mob_list)
if(Player.mind && Player.stat != DEAD && !isnewplayer(Player) &&!isbrain(Player) && Player.client)
if(Player.mind.special_role || LAZYLEN(Player.mind.antag_datums)) //Someone's still antaging!
living_antag_player = Player
@@ -407,16 +407,11 @@
//////////////////////////
/proc/display_roundstart_logout_report()
var/msg = "<span class='boldnotice'>Roundstart logout report\n\n</span>"
for(var/mob/living/L in GLOB.mob_list)
for(var/i in GLOB.mob_living_list)
var/mob/living/L = i
if(L.ckey)
var/found = 0
for(var/client/C in GLOB.clients)
if(C.ckey == L.ckey)
found = 1
break
if(!found)
msg += "<b>[L.name]</b> ([L.ckey]), the [L.job] (<font color='#ffcc00'><b>Disconnected</b></font>)\n"
if(L.ckey && !GLOB.directory[L.ckey])
msg += "<b>[L.name]</b> ([L.ckey]), the [L.job] (<font color='#ffcc00'><b>Disconnected</b></font>)\n"
if(L.ckey && L.client)
@@ -452,10 +447,8 @@
continue //Ghosted while alive
for(var/mob/M in GLOB.mob_list)
if(M.client && M.client.holder)
to_chat(M, msg)
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"
@@ -464,8 +457,10 @@
text += " <span class='boldannounce'>died</span>"
else
text += " <span class='greenannounce'>survived</span>"
if(fleecheck && (!(ply.current.z in GLOB.station_z_levels)))
text += " while <span class='boldannounce'>fleeing the station</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
@@ -533,4 +528,4 @@
//By default nuke just ends the round
/datum/game_mode/proc/OnNukeExplosion(off_station)
if(off_station < 2)
station_was_nuked = TRUE //Will end the round on next check.
station_was_nuked = TRUE //Will end the round on next check.
@@ -133,9 +133,9 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
dat += "<B>Install Module:</B><BR>"
dat += "<I>The number afterwards is the amount of processing time it consumes.</I><BR>"
for(var/datum/AI_Module/large/module in possible_modules)
dat += "<A href='byond://?src=\ref[src];[module.mod_pick_name]=1'>[module.module_name]</A><A href='byond://?src=\ref[src];showdesc=[module.mod_pick_name]'>\[?\]</A> ([module.cost])<BR>"
dat += "<A href='byond://?src=[REF(src)];[module.mod_pick_name]=1'>[module.module_name]</A><A href='byond://?src=[REF(src)];showdesc=[module.mod_pick_name]'>\[?\]</A> ([module.cost])<BR>"
for(var/datum/AI_Module/small/module in possible_modules)
dat += "<A href='byond://?src=\ref[src];[module.mod_pick_name]=1'>[module.module_name]</A><A href='byond://?src=\ref[src];showdesc=[module.mod_pick_name]'>\[?\]</A> ([module.cost])<BR>"
dat += "<A href='byond://?src=[REF(src)];[module.mod_pick_name]=1'>[module.module_name]</A><A href='byond://?src=[REF(src)];showdesc=[module.mod_pick_name]'>\[?\]</A> ([module.cost])<BR>"
dat += "<HR>"
if(temp)
dat += "[temp]"
@@ -375,7 +375,8 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/obj/machinery/doomsday_device/proc/detonate(z_level = ZLEVEL_STATION_PRIMARY)
sound_to_playing_players('sound/machines/alarm.ogg')
sleep(100)
for(var/mob/living/L in GLOB.mob_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))
continue
@@ -679,7 +680,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
C.images -= I
/mob/living/silicon/ai/proc/can_place_transformer(datum/action/innate/ai/place_transformer/action)
if(!eyeobj || !isturf(loc) || !canUseTopic() || !action)
if(!eyeobj || !isturf(loc) || incapacitated() || !action)
return
var/turf/middle = get_turf(eyeobj)
var/list/turfs = list(middle, locate(middle.x - 1, middle.y, middle.z), locate(middle.x + 1, middle.y, middle.z))
@@ -477,7 +477,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
if(ishuman(L))
var/mob/living/carbon/human/H = L
species = "<span class='notice'>[H.dna.species.name]</span>"
if(L.mind && L.mind.changeling)
if(L.mind && L.mind.has_antag_datum(/datum/antagonist/changeling))
species = "<span class='warning'>Changeling lifeform</span>"
var/obj/item/organ/heart/gland/temp = locate() in H.internal_organs
if(temp)
@@ -43,20 +43,20 @@
dat += "Collected Samples : [points] <br>"
dat += "Gear Credits: [credits] <br>"
dat += "<b>Transfer data in exchange for supplies:</b><br>"
dat += "<a href='?src=\ref[src];dispense=baton'>Advanced Baton</A><br>"
dat += "<a href='?src=\ref[src];dispense=helmet'>Agent Helmet</A><br>"
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=baton'>Advanced Baton</A><br>"
dat += "<a href='?src=[REF(src)];dispense=helmet'>Agent Helmet</A><br>"
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>"
else
dat += "<span class='bad'>NO EXPERIMENT MACHINE DETECTED</span> <br>"
if(pad)
dat += "<span class='bad'>Emergency Teleporter System.</span>"
dat += "<span class='bad'>Consider using primary observation console first.</span>"
dat += "<a href='?src=\ref[src];teleporter_send=1'>Activate Teleporter</A><br>"
dat += "<a href='?src=[REF(src)];teleporter_send=1'>Activate Teleporter</A><br>"
if(gizmo && gizmo.marked)
dat += "<a href='?src=\ref[src];teleporter_retrieve=1'>Retrieve Mark</A><br>"
dat += "<a href='?src=[REF(src)];teleporter_retrieve=1'>Retrieve Mark</A><br>"
else
dat += "<span class='linkOff'>Retrieve Mark</span><br>"
else
@@ -66,15 +66,15 @@
dat += "<h4> Agent Vest Mode </h4><br>"
var/mode = vest.mode
if(mode == VEST_STEALTH)
dat += "<a href='?src=\ref[src];flip_vest=1'>Combat</A>"
dat += "<a href='?src=[REF(src)];flip_vest=1'>Combat</A>"
dat += "<span class='linkOff'>Stealth</span>"
else
dat += "<span class='linkOff'>Combat</span>"
dat += "<a href='?src=\ref[src];flip_vest=1'>Stealth</A>"
dat += "<a href='?src=[REF(src)];flip_vest=1'>Stealth</A>"
dat+="<br>"
dat += "<a href='?src=\ref[src];select_disguise=1'>Select Agent Vest Disguise</a><br>"
dat += "<a href='?src=\ref[src];toggle_vest=1'>[vest.flags_1 & NODROP_1 ? "Unlock" : "Lock"] Vest</a><br>"
dat += "<a href='?src=[REF(src)];select_disguise=1'>Select Agent Vest Disguise</a><br>"
dat += "<a href='?src=[REF(src)];toggle_vest=1'>[vest.flags_1 & NODROP_1 ? "Unlock" : "Lock"] Vest</a><br>"
else
dat += "<span class='bad'>NO AGENT VEST DETECTED</span>"
var/datum/browser/popup = new(user, "computer", "Abductor Console", 400, 500)
@@ -48,7 +48,7 @@
item_count++
var/g_color = gland_colors[i]
var/amount = amounts[i]
dat += "<a class='box gland' style='background-color:[g_color]' href='?src=\ref[src];dispense=[i]'>[amount]</a>"
dat += "<a class='box gland' style='background-color:[g_color]' href='?src=[REF(src)];dispense=[i]'>[amount]</a>"
if(item_count == 4) // Four boxes per line
dat +="</br></br>"
item_count = 0
@@ -104,9 +104,9 @@
dat += "<table><tr><td>"
dat += "<img src=dissection_img height=80 width=80>" //Avert your eyes
dat += "</td><td>"
dat += "<a href='?src=\ref[src];experiment=1'>Probe</a><br>"
dat += "<a href='?src=\ref[src];experiment=2'>Dissect</a><br>"
dat += "<a href='?src=\ref[src];experiment=3'>Analyze</a><br>"
dat += "<a href='?src=[REF(src)];experiment=1'>Probe</a><br>"
dat += "<a href='?src=[REF(src)];experiment=2'>Dissect</a><br>"
dat += "<a href='?src=[REF(src)];experiment=3'>Analyze</a><br>"
dat += "</td></tr></table>"
else
dat += "<span class='linkOff'>Experiment </span>"
@@ -127,8 +127,8 @@
dat += "<br>"
dat += "[flash]"
dat += "<br>"
dat += "<a href='?src=\ref[src];refresh=1'>Scan</a>"
dat += "<a href='?src=\ref[src];[state_open ? "close=1'>Close</a>" : "open=1'>Open</a>"]"
dat += "<a href='?src=[REF(src)];refresh=1'>Scan</a>"
dat += "<a href='?src=[REF(src)];[state_open ? "close=1'>Close</a>" : "open=1'>Open</a>"]"
var/datum/browser/popup = new(user, "experiment", "Probing Console", 300, 300)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.set_content(dat)
@@ -654,7 +654,8 @@
/mob/living/simple_animal/hostile/swarmer/proc/swarmer_chat(msg)
var/rendered = "<B>Swarm communication - [src]</b> [say_quote(msg, get_spans())]"
for(var/mob/M in GLOB.mob_list)
for(var/i in GLOB.mob_list)
var/mob/M = i
if(isswarmer(M))
to_chat(M, rendered)
if(isobserver(M))
@@ -21,7 +21,8 @@
print_command_report(swarmer_report, announce=TRUE)
/datum/round_event/spawn_swarmer/proc/find_swarmer()
for(var/mob/living/M in GLOB.mob_list)
if(istype(M, /mob/living/simple_animal/hostile/swarmer) && M.client) //If there is a swarmer with an active client, we've found our swarmer
for(var/i in GLOB.mob_living_list)
var/mob/living/L = i
if(istype(L, /mob/living/simple_animal/hostile/swarmer) && L.client) //If there is a swarmer with an active client, we've found our swarmer
return 1
return 0
@@ -76,7 +76,7 @@
return 0
var/datum/disease/D = new /datum/disease/transformation/jungle_fever() //ugly but unfortunately needed
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
if(H.mind && H.stat != DEAD)
if(H.HasDisease(D))
return 0
@@ -87,7 +87,7 @@
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
return 0
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.living_mob_list)
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if (M.HasDisease(D))
if(M.onCentCom() || M.onSyndieBase())
escaped_monkeys++
@@ -21,6 +21,7 @@
maxHealth = INFINITY
layer = GHOST_LAYER
healable = FALSE
spacewalk = TRUE
sight = SEE_SELF
see_in_dark = 8
@@ -153,8 +154,6 @@
//Immunities
/mob/living/simple_animal/revenant/Process_Spacemove(movement_dir = 0)
return 1
/mob/living/simple_animal/revenant/ex_act(severity, target)
return 1 //Immune to the effects of explosions.
+4 -2
View File
@@ -91,9 +91,11 @@
var/obj/item/device/nuclear_challenge/challenge = new /obj/item/device/nuclear_challenge
synd_mind.current.put_in_hands(challenge, TRUE)
var/list/foundIDs = synd_mind.current.search_contents_for(/obj/item/card/id)
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/obj/item/card/id/ID in foundIDs)
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
+23 -19
View File
@@ -77,6 +77,7 @@
icon = 'icons/obj/machines/nuke_terminal.dmi'
icon_state = "nuclearbomb_base"
anchored = TRUE //stops it being moved
use_tag = TRUE
/obj/machinery/nuclearbomb/syndicate
//ui_style = "syndicate" // actually the nuke op bomb is a stole nt bomb
@@ -121,15 +122,7 @@
to_chat(user, "<span class='notice'>You remove the screws from [src]'s front panel.</span>")
update_icon()
return
if(NUKESTATE_UNSCREWED)
if(istype(I, /obj/item/crowbar))
to_chat(user, "<span class='notice'>You start removing [src]'s front panel...</span>")
playsound(loc, I.usesound, 100, 1)
if(do_after(user,30*I.toolspeed,target=src))
to_chat(user, "<span class='notice'>You remove [src]'s front panel.</span>")
deconstruction_state = NUKESTATE_PANEL_REMOVED
update_icon()
return
if(NUKESTATE_PANEL_REMOVED)
if(istype(I, /obj/item/weldingtool))
var/obj/item/weldingtool/welder = I
@@ -141,16 +134,6 @@
deconstruction_state = NUKESTATE_WELDED
update_icon()
return
if(NUKESTATE_WELDED)
if(istype(I, /obj/item/crowbar))
to_chat(user, "<span class='notice'>You start prying off [src]'s inner plate...</span>")
playsound(loc, I.usesound, 100, 1)
if(do_after(user,50*I.toolspeed,target=src))
to_chat(user, "<span class='notice'>You pry off [src]'s inner plate. You can see the core's green glow!</span>")
deconstruction_state = NUKESTATE_CORE_EXPOSED
update_icon()
START_PROCESSING(SSobj, core)
return
if(NUKESTATE_CORE_EXPOSED)
if(istype(I, /obj/item/nuke_core_container))
var/obj/item/nuke_core_container/core_box = I
@@ -181,6 +164,27 @@
return
. = ..()
/obj/machinery/nuclearbomb/crowbar_act(mob/user, obj/item/tool)
. = FALSE
switch(deconstruction_state)
if(NUKESTATE_UNSCREWED)
to_chat(user, "<span class='notice'>You start removing [src]'s front panel...</span>")
playsound(loc, tool.usesound, 100, 1)
if(do_after(user, 30 * tool.toolspeed, target = src))
to_chat(user, "<span class='notice'>You remove [src]'s front panel.</span>")
deconstruction_state = NUKESTATE_PANEL_REMOVED
update_icon()
return TRUE
if(NUKESTATE_WELDED)
to_chat(user, "<span class='notice'>You start prying off [src]'s inner plate...</span>")
playsound(loc, tool.usesound, 100, 1)
if(do_after(user, 50 * tool.toolspeed, target = src))
to_chat(user, "<span class='notice'>You pry off [src]'s inner plate. You can see the core's green glow!</span>")
deconstruction_state = NUKESTATE_CORE_EXPOSED
update_icon()
START_PROCESSING(SSobj, core)
return TRUE
/obj/machinery/nuclearbomb/proc/get_nuke_state()
if(exploding)
return NUKE_ON_EXPLODING
+14 -10
View File
@@ -586,7 +586,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
n_p ++
else if (SSticker.IsRoundInProgress())
for(var/mob/living/carbon/human/P in GLOB.player_list)
if(P.client && !(P.mind in SSticker.mode.changelings) && !(P.mind in owners))
if(P.client && !(P.mind.has_antag_datum(/datum/antagonist/changeling)) && !(P.mind in owners))
n_p ++
target_amount = min(target_amount, n_p)
@@ -597,9 +597,12 @@ GLOBAL_LIST_EMPTY(possible_items_special)
var/list/datum/mind/owners = get_owners()
var/absorbedcount = 0
for(var/datum/mind/M in owners)
if(!owner || !owner.changeling || !owner.changeling.stored_profiles)
if(!M)
continue
absorbedcount += M.changeling.absorbedcount
var/datum/antagonist/changeling/changeling = M.has_antag_datum(/datum/antagonist/changeling)
if(!changeling || !changeling.stored_profiles)
continue
absorbedcount += changeling.absorbedcount
return absorbedcount >= target_amount
@@ -696,10 +699,11 @@ GLOBAL_LIST_EMPTY(possible_items_special)
if("Chief Medical Officer")
department_string = "medical"
var/ling_count = SSticker.mode.changelings
var/list/lings = get_antagonists(/datum/antagonist/changeling,TRUE)
var/ling_count = lings.len
for(var/datum/mind/M in SSticker.minds)
if(M in SSticker.mode.changelings)
if(M in lings)
continue
if(department_head in get_department_heads(M.assigned_role))
if(ling_count)
@@ -723,13 +727,13 @@ GLOBAL_LIST_EMPTY(possible_items_special)
//Needed heads is between min_lings and the maximum possible amount of command roles
//So at the time of writing, rand(3,6), it's also capped by the amount of lings there are
//Because you can't fill 6 head roles with 3 lings
var/list/lings = get_antagonists(/datum/antagonist/changeling,TRUE)
var/needed_heads = rand(min_lings,GLOB.command_positions.len)
needed_heads = min(SSticker.mode.changelings.len,needed_heads)
needed_heads = min(lings.len,needed_heads)
var/list/heads = SSjob.get_living_heads()
for(var/datum/mind/head in heads)
if(head in SSticker.mode.changelings) //Looking at you HoP.
if(head in lings) //Looking at you HoP.
continue
if(needed_heads)
department_minds += head
@@ -789,7 +793,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
//Check each department member's mind to see if any of them made it to centcom alive, if they did it's an automatic fail
for(var/datum/mind/M in department_minds)
if(M in SSticker.mode.changelings) //Lings aren't picked for this, but let's be safe
if(M.has_antag_datum(/datum/antagonist/changeling)) //Lings aren't picked for this, but let's be safe
continue
if(M.current)
@@ -800,7 +804,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
//Check each staff member has been replaced, by cross referencing changeling minds, changeling current dna, the staff minds and their original DNA names
var/success = 0
changelings:
for(var/datum/mind/changeling in SSticker.mode.changelings)
for(var/datum/mind/changeling in get_antagonists(/datum/antagonist/changeling,TRUE))
if(success >= department_minds.len) //We did it, stop here!
return 1
if(ishuman(changeling.current))
+1 -1
View File
@@ -194,7 +194,7 @@
if(headrevs.len)
var/num_revs = 0
var/num_survivors = 0
for(var/mob/living/carbon/survivor in GLOB.living_mob_list)
for(var/mob/living/carbon/survivor in GLOB.alive_mob_list)
if(survivor.ckey)
num_survivors++
if(survivor.mind)
+139 -139
View File
@@ -1,139 +1,139 @@
/*
This is for the sandbox for now,
maybe useful later for an actual thing?
-Sayu
*/
/obj/structure/door_assembly
var/datum/airlock_maker/maker = null
/obj/structure/door_assembly/attack_hand()
..()
if(maker)
maker.interact()
/datum/airlock_maker
var/obj/structure/door_assembly/linked = null
var/list/access_used = null
var/require_all = 1
var/paintjob = "none"
var/glassdoor = 0
var/doorname = "airlock"
/datum/airlock_maker/New(var/atom/target_loc)
linked = new(target_loc)
linked.maker = src
linked.anchored = FALSE
access_used = list()
interact()
/datum/airlock_maker/proc/linkpretty(href,desc,active)
if(!desc)
var/static/list/defaults = list("No","Yes")
desc = defaults[active+1]
if(active)
return "<a href='?src=\ref[src];[href]'><b>[desc]</b></a>"
return "<a href='?src=\ref[src];[href]'><i>[desc]</i></a>"
/datum/airlock_maker/proc/interact()
var/list/leftcolumn = list()
var/list/rightcolumn = list()
leftcolumn += "<u><b>Required Access</b></u>"
for(var/access in get_all_accesses())
leftcolumn += linkpretty("access=[access]",get_access_desc(access),access in access_used)
leftcolumn += "Require all listed accesses: [linkpretty("reqall",null,require_all)]"
rightcolumn += "<u><b>Paintjob</b></u>"
for(var/option in list("none","engineering","atmos","security","command","medical","research","mining","maintenance","external","highsecurity"))
rightcolumn += linkpretty("paint=[option]",option,option == paintjob)
rightcolumn += "Glass door: " + linkpretty("glass",null,glassdoor) + "<br><br>"
var/length = max(leftcolumn.len,rightcolumn.len)
var/dat = "You may move the model airlock around. A new airlock will be built in its space when you click done, below.<hr><br>"
dat += "<a href='?src=\ref[src];rename'>Door name</a>: \"[doorname]\""
dat += "<table>"
for(var/i=1; i<=length; i++)
dat += "<tr><td>"
if(i<=leftcolumn.len)
dat += leftcolumn[i]
dat += "</td><td>"
if(i<=rightcolumn.len)
dat += rightcolumn[i]
dat += "</td></tr>"
dat += "</table><hr><a href='?src=\ref[src];done'>Finalize Airlock Construction</a> | <a href='?src=\ref[src];cancel'>Cancel and Destroy Airlock</a>"
usr << browse(dat,"window=airlockmaker")
/datum/airlock_maker/Topic(var/href,var/list/href_list)
if(!usr)
return
if(!src || !linked || !linked.loc)
usr << browse(null,"window=airlockmaker")
return
if("rename" in href_list)
var/newname = stripped_input(usr,"New airlock name:","Name the airlock",doorname)
if(newname)
doorname = newname
if("access" in href_list)
var/value = text2num(href_list["access"])
access_used ^= value
if("reqall" in href_list)
require_all = !require_all
if("paint" in href_list)
paintjob = href_list["paint"]
if("glass" in href_list)
glassdoor = !glassdoor
if("cancel" in href_list)
usr << browse(null,"window=airlockmaker")
qdel(linked)
qdel(src)
return
if("done" in href_list)
usr << browse(null,"window=airlockmaker")
var/turf/t_loc = linked.loc
qdel(linked)
if(!istype(t_loc))
return
var/target_type = "/obj/machinery/door/airlock"
if(glassdoor)
if(paintjob != "none")
if(paintjob in list("external","highsecurity","maintenance")) // no glass version
target_type += "/[paintjob]"
else
target_type += "/glass_[paintjob]"
else
target_type += "/glass"
else if(paintjob != "none")
target_type += "/[paintjob]"
var/final = target_type
target_type = text2path(final)
if(!target_type)
to_chat(usr, "Didn't work, contact Sayu with this: [final]")
usr << browse(null,"window=airlockmaker")
return
var/obj/machinery/door/D = new target_type(t_loc)
D.name = doorname
if(access_used.len == 0)
D.req_access = null
D.req_one_access = null
else if(require_all)
D.req_access = access_used.Copy()
D.req_one_access = null
else
D.req_access = null
D.req_one_access = access_used.Copy()
return
interact()
/*
This is for the sandbox for now,
maybe useful later for an actual thing?
-Sayu
*/
/obj/structure/door_assembly
var/datum/airlock_maker/maker = null
/obj/structure/door_assembly/attack_hand()
..()
if(maker)
maker.interact()
/datum/airlock_maker
var/obj/structure/door_assembly/linked = null
var/list/access_used = null
var/require_all = 1
var/paintjob = "none"
var/glassdoor = 0
var/doorname = "airlock"
/datum/airlock_maker/New(var/atom/target_loc)
linked = new(target_loc)
linked.maker = src
linked.anchored = FALSE
access_used = list()
interact()
/datum/airlock_maker/proc/linkpretty(href,desc,active)
if(!desc)
var/static/list/defaults = list("No","Yes")
desc = defaults[active+1]
if(active)
return "<a href='?src=[REF(src)];[href]'><b>[desc]</b></a>"
return "<a href='?src=[REF(src)];[href]'><i>[desc]</i></a>"
/datum/airlock_maker/proc/interact()
var/list/leftcolumn = list()
var/list/rightcolumn = list()
leftcolumn += "<u><b>Required Access</b></u>"
for(var/access in get_all_accesses())
leftcolumn += linkpretty("access=[access]",get_access_desc(access),access in access_used)
leftcolumn += "Require all listed accesses: [linkpretty("reqall",null,require_all)]"
rightcolumn += "<u><b>Paintjob</b></u>"
for(var/option in list("none","engineering","atmos","security","command","medical","research","mining","maintenance","external","highsecurity"))
rightcolumn += linkpretty("paint=[option]",option,option == paintjob)
rightcolumn += "Glass door: " + linkpretty("glass",null,glassdoor) + "<br><br>"
var/length = max(leftcolumn.len,rightcolumn.len)
var/dat = "You may move the model airlock around. A new airlock will be built in its space when you click done, below.<hr><br>"
dat += "<a href='?src=[REF(src)];rename'>Door name</a>: \"[doorname]\""
dat += "<table>"
for(var/i=1; i<=length; i++)
dat += "<tr><td>"
if(i<=leftcolumn.len)
dat += leftcolumn[i]
dat += "</td><td>"
if(i<=rightcolumn.len)
dat += rightcolumn[i]
dat += "</td></tr>"
dat += "</table><hr><a href='?src=[REF(src)];done'>Finalize Airlock Construction</a> | <a href='?src=[REF(src)];cancel'>Cancel and Destroy Airlock</a>"
usr << browse(dat,"window=airlockmaker")
/datum/airlock_maker/Topic(var/href,var/list/href_list)
if(!usr)
return
if(!src || !linked || !linked.loc)
usr << browse(null,"window=airlockmaker")
return
if("rename" in href_list)
var/newname = stripped_input(usr,"New airlock name:","Name the airlock",doorname)
if(newname)
doorname = newname
if("access" in href_list)
var/value = text2num(href_list["access"])
access_used ^= value
if("reqall" in href_list)
require_all = !require_all
if("paint" in href_list)
paintjob = href_list["paint"]
if("glass" in href_list)
glassdoor = !glassdoor
if("cancel" in href_list)
usr << browse(null,"window=airlockmaker")
qdel(linked)
qdel(src)
return
if("done" in href_list)
usr << browse(null,"window=airlockmaker")
var/turf/t_loc = linked.loc
qdel(linked)
if(!istype(t_loc))
return
var/target_type = "/obj/machinery/door/airlock"
if(glassdoor)
if(paintjob != "none")
if(paintjob in list("external","highsecurity","maintenance")) // no glass version
target_type += "/[paintjob]"
else
target_type += "/glass_[paintjob]"
else
target_type += "/glass"
else if(paintjob != "none")
target_type += "/[paintjob]"
var/final = target_type
target_type = text2path(final)
if(!target_type)
to_chat(usr, "Didn't work, contact Sayu with this: [final]")
usr << browse(null,"window=airlockmaker")
return
var/obj/machinery/door/D = new target_type(t_loc)
D.name = doorname
if(access_used.len == 0)
D.req_access = null
D.req_one_access = null
else if(require_all)
D.req_access = access_used.Copy()
D.req_one_access = null
else
D.req_access = null
D.req_one_access = access_used.Copy()
return
interact()
+16 -16
View File
@@ -77,26 +77,26 @@ GLOBAL_VAR_INIT(hsboxspawn, TRUE)
hsbinfo = "<center><b>Sandbox Panel</b></center><hr>"
if(admin)
hsbinfo += "<b>Administration</b><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbtobj'>Toggle Object Spawning</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbtac'>Toggle Item Spawn Panel Auto-close</a><br>"
hsbinfo += "- <a href='?src=[REF(src)];hsb=hsbtobj'>Toggle Object Spawning</a><br>"
hsbinfo += "- <a href='?src=[REF(src)];hsb=hsbtac'>Toggle Item Spawn Panel Auto-close</a><br>"
hsbinfo += "<b>Canister Spawning</b><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/toxins]'>Spawn Plasma Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/carbon_dioxide]'>Spawn CO2 Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrogen]'>Spawn Nitrogen Canister</a><br>"
hsbinfo += "- <a href='?src=\ref[src];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrous_oxide]'>Spawn N2O Canister</a><hr>"
hsbinfo += "- <a href='?src=[REF(src)];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/toxins]'>Spawn Plasma Canister</a><br>"
hsbinfo += "- <a href='?src=[REF(src)];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/carbon_dioxide]'>Spawn CO2 Canister</a><br>"
hsbinfo += "- <a href='?src=[REF(src)];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrogen]'>Spawn Nitrogen Canister</a><br>"
hsbinfo += "- <a href='?src=[REF(src)];hsb=hsbspawn&path=[/obj/machinery/portable_atmospherics/canister/nitrous_oxide]'>Spawn N2O Canister</a><hr>"
else
hsbinfo += "<i>Some item spawning may be disabled by the administrators.</i><br>"
hsbinfo += "<i>Only administrators may spawn dangerous canisters.</i><br>"
for(var/T in hrefs)
var/href = hrefs[T]
if(href)
hsbinfo += "- <a href='?\ref[src];hsb=[hrefs[T]]'>[T]</a><br>"
hsbinfo += "- <a href='?[REF(src)];hsb=[hrefs[T]]'>[T]</a><br>"
else
hsbinfo += "<br><b>[T]</b><br>"
hsbinfo += "<hr>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbcloth'>Spawn Clothing...</a><br>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbreag'>Spawn Reagent Container...</a><br>"
hsbinfo += "- <a href='?\ref[src];hsb=hsbobj'>Spawn Other Item...</a><br><br>"
hsbinfo += "- <a href='?[REF(src)];hsb=hsbcloth'>Spawn Clothing...</a><br>"
hsbinfo += "- <a href='?[REF(src)];hsb=hsbreag'>Spawn Reagent Container...</a><br>"
hsbinfo += "- <a href='?[REF(src)];hsb=hsbobj'>Spawn Other Item...</a><br><br>"
usr << browse(hsbinfo, "window=hsbpanel")
@@ -235,12 +235,12 @@ GLOBAL_VAR_INIT(hsboxspawn, TRUE)
if(!GLOB.hsboxspawn) return
if(!clothinfo)
clothinfo = "<b>Clothing</b> <a href='?\ref[src];hsb=hsbreag'>(Reagent Containers)</a> <a href='?\ref[src];hsb=hsbobj'>(Other Items)</a><hr><br>"
clothinfo = "<b>Clothing</b> <a href='?[REF(src)];hsb=hsbreag'>(Reagent Containers)</a> <a href='?[REF(src)];hsb=hsbobj'>(Other Items)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/clothing)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
clothinfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
clothinfo += "<a href='?src=[REF(src)];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(clothinfo,"window=sandbox")
@@ -249,12 +249,12 @@ GLOBAL_VAR_INIT(hsboxspawn, TRUE)
if(!GLOB.hsboxspawn) return
if(!reaginfo)
reaginfo = "<b>Reagent Containers</b> <a href='?\ref[src];hsb=hsbcloth'>(Clothing)</a> <a href='?\ref[src];hsb=hsbobj'>(Other Items)</a><hr><br>"
reaginfo = "<b>Reagent Containers</b> <a href='?[REF(src)];hsb=hsbcloth'>(Clothing)</a> <a href='?[REF(src)];hsb=hsbobj'>(Other Items)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/reagent_containers)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
reaginfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
reaginfo += "<a href='?src=[REF(src)];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(reaginfo,"window=sandbox")
@@ -263,13 +263,13 @@ GLOBAL_VAR_INIT(hsboxspawn, TRUE)
if(!GLOB.hsboxspawn) return
if(!objinfo)
objinfo = "<b>Other Items</b> <a href='?\ref[src];hsb=hsbcloth'>(Clothing)</a> <a href='?\ref[src];hsb=hsbreag'>(Reagent Containers)</a><hr><br>"
objinfo = "<b>Other Items</b> <a href='?[REF(src)];hsb=hsbcloth'>(Clothing)</a> <a href='?[REF(src)];hsb=hsbreag'>(Reagent Containers)</a><hr><br>"
var/list/all_items = subtypesof(/obj/item/) - typesof(/obj/item/clothing) - typesof(/obj/item/reagent_containers)
for(var/typekey in spawn_forbidden)
all_items -= typesof(typekey)
for(var/O in reverseRange(all_items))
objinfo += "<a href='?src=\ref[src];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
objinfo += "<a href='?src=[REF(src)];hsb=hsb_safespawn&path=[O]'>[O]</a><br>"
usr << browse(objinfo,"window=sandbox")
+2 -1
View File
@@ -83,7 +83,7 @@
/datum/game_mode/traitor/proc/add_latejoin_traitor(datum/mind/character)
var/datum/antagonist/traitor/new_antag = new antag_datum(character)
new_antag.should_specialise = TRUE
character.add_antag_datum(antag_datum)
character.add_antag_datum(new_antag)
@@ -144,6 +144,7 @@
else
text += "<br><font color='red'><B>The [special_role_text] has failed!</B></font>"
SSblackbox.add_details("traitor_success","FAIL")
SEND_SOUND(traitor.current, 'sound/ambience/ambifailure.ogg')
text += "<br>"
+1 -1
View File
@@ -288,7 +288,7 @@
possible = list()
if(!link)
return
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
if(md5(H.dna.uni_identity) in link.fingerprints)
possible |= H
+2 -2
View File
@@ -212,7 +212,7 @@
/proc/makeNewConstruct(mob/living/simple_animal/hostile/construct/ctype, mob/target, mob/stoner = null, cultoverride = 0, loc_override = null)
var/mob/living/simple_animal/hostile/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target)))
if(stoner)
newstruct.faction |= "\ref[stoner]"
newstruct.faction |= "[REF(stoner)]"
newstruct.master = stoner
var/datum/action/innate/seek_master/SM = new()
SM.Grant(newstruct)
@@ -244,7 +244,7 @@
S.key = T.key
S.language_holder = U.language_holder.copy(S)
if(U)
S.faction |= "\ref[U]" //Add the master as a faction, allowing inter-mob cooperation
S.faction |= "[REF(U)]" //Add the master as a faction, allowing inter-mob cooperation
if(U && iscultist(U))
SSticker.mode.add_cultist(S.mind, 0)
S.cancel_camera()
+4 -4
View File
@@ -425,7 +425,7 @@
/datum/spellbook_entry/item/warpwhistle
name = "Warp Whistle"
desc = "A strange whistle that will transport you to a distant safe place on the station. There is a window of vulnerability at the begining of every use."
desc = "A strange whistle that will transport you to a distant safe place on the station. There is a window of vulnerability at the beginning of every use."
item_path = /obj/item/warpwhistle
category = "Mobility"
cost = 1
@@ -652,7 +652,7 @@
var/list/cat_dat = list()
for(var/category in categories)
cat_dat[category] = "<hr>"
dat += "<li><a [tab==category?"class=selected":""] href='byond://?src=\ref[src];page=[category]'>[category]</a></li>"
dat += "<li><a [tab==category?"class=selected":""] href='byond://?src=[REF(src)];page=[category]'>[category]</a></li>"
dat += "<li><a><b>Points remaining : [uses]</b></a></li>"
dat += "</ul>"
@@ -663,11 +663,11 @@
E = entries[i]
spell_info += E.GetInfo()
if(E.CanBuy(user,src))
spell_info+= "<a href='byond://?src=\ref[src];buy=[i]'>[E.buy_word]</A><br>"
spell_info+= "<a href='byond://?src=[REF(src)];buy=[i]'>[E.buy_word]</A><br>"
else
spell_info+= "<span>Can't [E.buy_word]</span><br>"
if(E.CanRefund(user,src))
spell_info+= "<a href='byond://?src=\ref[src];refund=[i]'>Refund</A><br>"
spell_info+= "<a href='byond://?src=[REF(src)];refund=[i]'>Refund</A><br>"
spell_info += "<hr>"
if(cat_dat[E.category])
cat_dat[E.category] += spell_info