Tg 1 28 sync testing/confirmation (#5178)
* maps, tgui, tools * defines and helpers * onclick and controllers * datums fucking caught that hulk reversal too. * game and shuttle modular * module/admin * oh god they fucking moved antag shit again * haaaaate. Haaaaaaaaaate. * enables moff wings * more modules things * tgstation.dme before I forget something important * some mob stuff * s'more mob/living stuff * some carbon stuff * ayy lmaos and kitchen meat * Human stuff * species things moff wings have a 'none' version too * the rest of the module stuff. * some strings * misc * mob icons * some other icons. * It compiles FUCK BORERS FUCK BORERS
This commit is contained in:
@@ -1,53 +0,0 @@
|
||||
/datum/atom_hud/antag
|
||||
hud_icons = list(ANTAG_HUD)
|
||||
var/self_visible = TRUE
|
||||
|
||||
/datum/atom_hud/antag/hidden
|
||||
self_visible = FALSE
|
||||
|
||||
/datum/atom_hud/antag/proc/join_hud(mob/M)
|
||||
//sees_hud should be set to 0 if the mob does not get to see it's own hud type.
|
||||
if(!istype(M))
|
||||
CRASH("join_hud(): [M] ([M.type]) is not a mob!")
|
||||
if(M.mind.antag_hud) //note: please let this runtime if a mob has no mind, as mindless mobs shouldn't be getting antagged
|
||||
M.mind.antag_hud.leave_hud(M)
|
||||
add_to_hud(M)
|
||||
if(self_visible)
|
||||
add_hud_to(M)
|
||||
M.mind.antag_hud = src
|
||||
|
||||
/datum/atom_hud/antag/proc/leave_hud(mob/M)
|
||||
if(!M)
|
||||
return
|
||||
if(!istype(M))
|
||||
CRASH("leave_hud(): [M] ([M.type]) is not a mob!")
|
||||
remove_from_hud(M)
|
||||
remove_hud_from(M)
|
||||
if(M.mind)
|
||||
M.mind.antag_hud = null
|
||||
|
||||
|
||||
//GAME_MODE PROCS
|
||||
//called to set a mob's antag icon state
|
||||
/proc/set_antag_hud(mob/M, new_icon_state)
|
||||
if(!istype(M))
|
||||
CRASH("set_antag_hud(): [M] ([M.type]) is not a mob!")
|
||||
var/image/holder = M.hud_list[ANTAG_HUD]
|
||||
if(holder)
|
||||
holder.icon_state = new_icon_state
|
||||
if(M.mind || new_icon_state) //in mindless mobs, only null is acceptable, otherwise we're antagging a mindless mob, meaning we should runtime
|
||||
M.mind.antag_hud_icon_state = new_icon_state
|
||||
|
||||
|
||||
//MIND PROCS
|
||||
//these are called by mind.transfer_to()
|
||||
/datum/mind/proc/transfer_antag_huds(datum/atom_hud/antag/newhud)
|
||||
leave_all_antag_huds()
|
||||
set_antag_hud(current, antag_hud_icon_state)
|
||||
if(newhud)
|
||||
newhud.join_hud(current)
|
||||
|
||||
/datum/mind/proc/leave_all_antag_huds()
|
||||
for(var/datum/atom_hud/antag/hud in GLOB.huds)
|
||||
if(hud.hudusers[current])
|
||||
hud.leave_hud(current)
|
||||
@@ -1,266 +0,0 @@
|
||||
/obj/item/antag_spawner
|
||||
throw_speed = 1
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/used = 0
|
||||
|
||||
/obj/item/antag_spawner/proc/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
|
||||
return
|
||||
|
||||
/obj/item/antag_spawner/proc/equip_antag(mob/target)
|
||||
return
|
||||
|
||||
|
||||
///////////WIZARD
|
||||
|
||||
/obj/item/antag_spawner/contract
|
||||
name = "contract"
|
||||
desc = "A magic contract previously signed by an apprentice. In exchange for instruction in the magical arts, they are bound to answer your call for aid."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state ="scroll2"
|
||||
|
||||
/obj/item/antag_spawner/contract/attack_self(mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
if(used)
|
||||
dat = "<B>You have already summoned your apprentice.</B><BR>"
|
||||
else
|
||||
dat = "<B>Contract of Apprenticeship:</B><BR>"
|
||||
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 += "<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 += "<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 += "<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 += "<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")
|
||||
return
|
||||
|
||||
/obj/item/antag_spawner/contract/Topic(href, href_list)
|
||||
..()
|
||||
var/mob/living/carbon/human/H = usr
|
||||
|
||||
if(H.stat || H.restrained())
|
||||
return
|
||||
if(!ishuman(H))
|
||||
return 1
|
||||
|
||||
if(loc == H || (in_range(src, H) && isturf(loc)))
|
||||
H.set_machine(src)
|
||||
if(href_list["school"])
|
||||
if(used)
|
||||
to_chat(H, "You already used this contract!")
|
||||
return
|
||||
var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src)
|
||||
if(candidates.len)
|
||||
if(used)
|
||||
to_chat(H, "You already used this contract!")
|
||||
return
|
||||
used = 1
|
||||
var/mob/dead/observer/theghost = pick(candidates)
|
||||
spawn_antag(theghost.client, get_turf(src), href_list["school"],H.mind)
|
||||
else
|
||||
to_chat(H, "Unable to reach your apprentice! You can either attack the spellbook with the contract to refund your points, or wait and try again later.")
|
||||
|
||||
/obj/item/antag_spawner/contract/spawn_antag(client/C, turf/T, kind ,datum/mind/user)
|
||||
new /obj/effect/particle_effect/smoke(T)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
var/datum/mind/app_mind = M.mind
|
||||
|
||||
var/datum/antagonist/wizard/apprentice/app = new()
|
||||
app.master = user
|
||||
app.school = kind
|
||||
|
||||
var/datum/antagonist/wizard/master_wizard = user.has_antag_datum(/datum/antagonist/wizard)
|
||||
if(master_wizard)
|
||||
if(!master_wizard.wiz_team)
|
||||
master_wizard.create_wiz_team()
|
||||
app.wiz_team = master_wizard.wiz_team
|
||||
master_wizard.wiz_team.add_member(app_mind)
|
||||
app_mind.add_antag_datum(app)
|
||||
//TODO Kill these if possible
|
||||
app_mind.assigned_role = "Apprentice"
|
||||
app_mind.special_role = "apprentice"
|
||||
//
|
||||
SEND_SOUND(M, sound('sound/effects/magic.ogg'))
|
||||
|
||||
///////////BORGS AND OPERATIVES
|
||||
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops
|
||||
name = "syndicate operative teleporter"
|
||||
desc = "A single-use teleporter designed to quickly reinforce operatives in the field."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "locator"
|
||||
var/borg_to_spawn
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/proc/check_usability(mob/user)
|
||||
if(used)
|
||||
to_chat(user, "<span class='warning'>[src] is out of power!</span>")
|
||||
return FALSE
|
||||
if(!user.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE))
|
||||
to_chat(user, "<span class='danger'>AUTHENTICATION FAILURE. ACCESS DENIED.</span>")
|
||||
return FALSE
|
||||
if(!user.onSyndieBase())
|
||||
to_chat(user, "<span class='warning'>[src] is out of range! It can only be used at your base!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/attack_self(mob/user)
|
||||
if(!(check_usability(user)))
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='notice'>You activate [src] and wait for confirmation.</span>")
|
||||
var/list/nuke_candidates = pollGhostCandidates("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE)
|
||||
if(nuke_candidates.len)
|
||||
if(!(check_usability(user)))
|
||||
return
|
||||
used = TRUE
|
||||
var/mob/dead/observer/theghost = pick(nuke_candidates)
|
||||
spawn_antag(theghost.client, get_turf(src), "syndieborg", user.mind)
|
||||
do_sparks(4, TRUE, src)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Unable to connect to Syndicate command. Please wait and try again later or use the teleporter on your uplink to get your points refunded.</span>")
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.copy_to(M)
|
||||
M.key = C.key
|
||||
|
||||
var/datum/antagonist/nukeop/new_op = new()
|
||||
new_op.send_to_spawnpoint = FALSE
|
||||
new_op.nukeop_outfit = /datum/outfit/syndicate/no_crystals
|
||||
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
if(creator_op)
|
||||
M.mind.add_antag_datum(new_op,creator_op.nuke_team)
|
||||
M.mind.special_role = "Nuclear Operative"
|
||||
|
||||
//////SYNDICATE BORG
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele
|
||||
name = "syndicate cyborg teleporter"
|
||||
desc = "A single-use teleporter designed to quickly reinforce operatives in the field.."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "locator"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/assault
|
||||
name = "syndicate assault cyborg teleporter"
|
||||
borg_to_spawn = "Assault"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/medical
|
||||
name = "syndicate medical teleporter"
|
||||
borg_to_spawn = "Medical"
|
||||
|
||||
/obj/item/antag_spawner/nuke_ops/borg_tele/spawn_antag(client/C, turf/T, kind, datum/mind/user)
|
||||
var/mob/living/silicon/robot/R
|
||||
var/datum/antagonist/nukeop/creator_op = user.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
||||
if(!creator_op)
|
||||
return
|
||||
|
||||
switch(borg_to_spawn)
|
||||
if("Medical")
|
||||
R = new /mob/living/silicon/robot/modules/syndicate/medical(T)
|
||||
else
|
||||
R = new /mob/living/silicon/robot/modules/syndicate(T) //Assault borg by default
|
||||
|
||||
var/brainfirstname = pick(GLOB.first_names_male)
|
||||
if(prob(50))
|
||||
brainfirstname = pick(GLOB.first_names_female)
|
||||
var/brainopslastname = pick(GLOB.last_names)
|
||||
if(creator_op.nuke_team.syndicate_name) //the brain inside the syndiborg has the same last name as the other ops.
|
||||
brainopslastname = creator_op.nuke_team.syndicate_name
|
||||
var/brainopsname = "[brainfirstname] [brainopslastname]"
|
||||
|
||||
R.mmi.name = "Man-Machine Interface: [brainopsname]"
|
||||
R.mmi.brain.name = "[brainopsname]'s brain"
|
||||
R.mmi.brainmob.real_name = brainopsname
|
||||
R.mmi.brainmob.name = brainopsname
|
||||
R.real_name = R.name
|
||||
|
||||
R.key = C.key
|
||||
|
||||
var/datum/antagonist/nukeop/new_borg = new()
|
||||
new_borg.send_to_spawnpoint = FALSE
|
||||
R.mind.add_antag_datum(new_borg,creator_op.nuke_team)
|
||||
R.mind.special_role = "Syndicate Cyborg"
|
||||
|
||||
///////////SLAUGHTER DEMON
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon //Warning edgiest item in the game
|
||||
name = "vial of blood"
|
||||
desc = "A magically infused bottle of blood, distilled from countless murder victims. Used in unholy rituals to attract horrifying creatures."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "vial"
|
||||
|
||||
var/shatter_msg = "<span class='notice'>You shatter the bottle, no turning back now!</span>"
|
||||
var/veil_msg = "<span class='warning'>You sense a dark presence lurking just beyond the veil...</span>"
|
||||
var/objective_verb = "Kill"
|
||||
var/mob/living/demon_type = /mob/living/simple_animal/slaughter
|
||||
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user)
|
||||
if(!is_station_level(user.z))
|
||||
to_chat(user, "<span class='notice'>You should probably wait until you reach the station.</span>")
|
||||
return
|
||||
if(used)
|
||||
return
|
||||
var/list/demon_candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", null, null, ROLE_ALIEN, 50, src)
|
||||
if(demon_candidates.len)
|
||||
if(used)
|
||||
return
|
||||
used = 1
|
||||
var/mob/dead/observer/theghost = pick(demon_candidates)
|
||||
spawn_antag(theghost.client, get_turf(src), initial(demon_type.name),user.mind)
|
||||
to_chat(user, shatter_msg)
|
||||
to_chat(user, veil_msg)
|
||||
playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, 1)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You can't seem to work up the nerve to shatter the bottle. Perhaps you should try again later.</span>")
|
||||
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
|
||||
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
|
||||
var/mob/living/simple_animal/slaughter/S = new demon_type(holder)
|
||||
S.holder = holder
|
||||
S.key = C.key
|
||||
S.mind.assigned_role = S.name
|
||||
S.mind.special_role = S.name
|
||||
var/datum/objective/assassinate/new_objective
|
||||
if(user)
|
||||
new_objective = new /datum/objective/assassinate
|
||||
new_objective.owner = S.mind
|
||||
new_objective.target = user
|
||||
new_objective.explanation_text = "[objective_verb] [user.name], the one who summoned you."
|
||||
S.mind.objectives += new_objective
|
||||
var/datum/objective/new_objective2 = new /datum/objective
|
||||
new_objective2.owner = S.mind
|
||||
new_objective2.explanation_text = "[objective_verb] everyone[user ? " else while you're at it":""]."
|
||||
S.mind.objectives += new_objective2
|
||||
S.mind.add_antag_datum(/datum/antagonist/auto_custom)
|
||||
to_chat(S, S.playstyle_string)
|
||||
to_chat(S, "<B>You are currently not currently in the same plane of existence as the station. \
|
||||
Ctrl+Click a blood pool to manifest.</B>")
|
||||
if(new_objective)
|
||||
to_chat(S, "<B>Objective #[1]</B>: [new_objective.explanation_text]")
|
||||
to_chat(S, "<B>Objective #[new_objective ? "[2]":"[1]"]</B>: [new_objective2.explanation_text]")
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/laughter
|
||||
name = "vial of tickles"
|
||||
desc = "A magically infused bottle of clown love, distilled from countless hugging attacks. Used in funny rituals to attract adorable creatures."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "vial"
|
||||
color = "#FF69B4" // HOT PINK
|
||||
|
||||
veil_msg = "<span class='warning'>You sense an adorable presence lurking just beyond the veil...</span>"
|
||||
objective_verb = "Hug and Tickle"
|
||||
demon_type = /mob/living/simple_animal/slaughter/laughter
|
||||
@@ -1,46 +0,0 @@
|
||||
//A barebones antagonist team.
|
||||
/datum/team
|
||||
var/list/datum/mind/members = list()
|
||||
var/name = "team"
|
||||
var/member_name = "member"
|
||||
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
|
||||
|
||||
/datum/team/New(starting_members)
|
||||
. = ..()
|
||||
if(starting_members)
|
||||
if(islist(starting_members))
|
||||
for(var/datum/mind/M in starting_members)
|
||||
add_member(M)
|
||||
else
|
||||
add_member(starting_members)
|
||||
|
||||
/datum/team/proc/is_solo()
|
||||
return members.len == 1
|
||||
|
||||
/datum/team/proc/add_member(datum/mind/new_member)
|
||||
members |= new_member
|
||||
|
||||
/datum/team/proc/remove_member(datum/mind/member)
|
||||
members -= member
|
||||
|
||||
//Display members/victory/failure/objectives for the team
|
||||
/datum/team/proc/roundend_report()
|
||||
var/list/report = list()
|
||||
|
||||
report += "<b>[name]:</b>"
|
||||
report += "The [member_name]s were:"
|
||||
report += printplayerlist(members)
|
||||
|
||||
return report.Join("<br>")
|
||||
|
||||
//Get all teams [of type team_type]
|
||||
//TODO move these to some antag helpers file with get_antagonists
|
||||
/proc/get_all_teams(team_type)
|
||||
. = list()
|
||||
for(var/V in GLOB.antagonists)
|
||||
var/datum/antagonist/A = V
|
||||
if(!A.owner)
|
||||
continue
|
||||
var/datum/team/T = A.get_team()
|
||||
if(!team_type || istype(T,team_type))
|
||||
. |= T
|
||||
@@ -1,109 +0,0 @@
|
||||
//Few global vars to track the blob
|
||||
GLOBAL_LIST_EMPTY(blobs) //complete list of all blobs made.
|
||||
GLOBAL_LIST_EMPTY(blob_cores)
|
||||
GLOBAL_LIST_EMPTY(overminds)
|
||||
GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
GLOBAL_LIST_EMPTY(blobs_legit) //used for win-score calculations, contains only blobs counted for win condition
|
||||
|
||||
#define BLOB_NO_PLACE_TIME 1800 //time, in deciseconds, blobs are prevented from bursting in the gamemode
|
||||
|
||||
/datum/game_mode/blob
|
||||
name = "blob"
|
||||
config_tag = "blob"
|
||||
antag_flag = ROLE_BLOB
|
||||
false_report_weight = 5
|
||||
|
||||
required_players = 25
|
||||
required_enemies = 1
|
||||
recommended_enemies = 1
|
||||
|
||||
round_ends_with_antag_death = 1
|
||||
|
||||
announce_span = "green"
|
||||
announce_text = "Dangerous gelatinous organisms are spreading throughout the station!\n\
|
||||
<span class='green'>Blobs</span>: Consume the station and spread as far as you can.\n\
|
||||
<span class='notice'>Crew</span>: Fight back the blobs and minimize station damage."
|
||||
|
||||
var/message_sent = FALSE
|
||||
|
||||
var/cores_to_spawn = 1
|
||||
var/players_per_core = 25
|
||||
var/blob_point_rate = 3
|
||||
var/blob_base_starting_points = 80
|
||||
|
||||
var/blobwincount = 250
|
||||
|
||||
var/messagedelay_low = 2400 //in deciseconds
|
||||
var/messagedelay_high = 3600 //blob report will be sent after a random value between these (minimum 4 minutes, maximum 6 minutes)
|
||||
|
||||
var/list/blob_overminds = list()
|
||||
|
||||
/datum/game_mode/blob/pre_setup()
|
||||
cores_to_spawn = max(round(num_players()/players_per_core, 1), 1)
|
||||
|
||||
var/win_multiplier = 1 + (0.1 * cores_to_spawn)
|
||||
blobwincount = initial(blobwincount) * cores_to_spawn * win_multiplier
|
||||
|
||||
for(var/j = 0, j < cores_to_spawn, j++)
|
||||
if (!antag_candidates.len)
|
||||
break
|
||||
var/datum/mind/blob = pick(antag_candidates)
|
||||
blob_overminds += blob
|
||||
blob.assigned_role = "Blob"
|
||||
blob.special_role = "Blob"
|
||||
log_game("[blob.key] (ckey) has been selected as a Blob")
|
||||
antag_candidates -= blob
|
||||
|
||||
if(!blob_overminds.len)
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/datum/game_mode/blob/proc/get_blob_candidates()
|
||||
var/list/candidates = list()
|
||||
for(var/mob/living/carbon/human/player in GLOB.player_list)
|
||||
if(!player.stat && player.mind && !player.mind.special_role && !jobban_isbanned(player, "Syndicate") && (ROLE_BLOB in player.client.prefs.be_special))
|
||||
if(age_check(player.client))
|
||||
candidates += player
|
||||
return candidates
|
||||
|
||||
/datum/game_mode/blob/proc/show_message(message)
|
||||
for(var/datum/mind/blob in blob_overminds)
|
||||
to_chat(blob.current, message)
|
||||
|
||||
/datum/game_mode/blob/post_setup()
|
||||
set waitfor = FALSE
|
||||
|
||||
for(var/datum/mind/blob in blob_overminds)
|
||||
var/mob/camera/blob/B = blob.current.become_overmind(TRUE, round(blob_base_starting_points/blob_overminds.len))
|
||||
B.mind.name = B.name
|
||||
var/turf/T = pick(GLOB.blobstart)
|
||||
B.forceMove(T)
|
||||
B.base_point_rate = blob_point_rate
|
||||
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
|
||||
// Disable the blob event for this round.
|
||||
var/datum/round_event_control/blob/B = locate() in SSevents.control
|
||||
if(B)
|
||||
B.max_occurrences = 0 // disable the event
|
||||
|
||||
. = ..()
|
||||
|
||||
var/message_delay = rand(messagedelay_low, messagedelay_high) //between 4 and 6 minutes with 2400 low and 3600 high.
|
||||
|
||||
sleep(message_delay)
|
||||
|
||||
send_intercept(1)
|
||||
message_sent = TRUE
|
||||
addtimer(CALLBACK(src, .proc/SendSecondIntercept), 24000)
|
||||
|
||||
/datum/game_mode/blob/proc/SendSecondIntercept()
|
||||
if(!replacementmode)
|
||||
send_intercept(2) //if the blob has been alive this long, it's time to bomb it
|
||||
|
||||
/datum/game_mode/blob/generate_report()
|
||||
return "A CMP scientist by the name of [pick("Griff", "Pasteur", "Chamberland", "Buist", "Rivers", "Stanley")] boasted about his corporation's \"finest creation\" - a macrobiological \
|
||||
virus capable of self-reproduction and hellbent on consuming whatever it touches. He went on to query Cybersun for permission to utilize the virus in biochemical warfare, to which \
|
||||
CMP subsequently gained. Be vigilant for any large organisms rapidly spreading across the station, as they are classified as a level 5 biohazard and critically dangerous. Note that \
|
||||
this organism seems to be weak to extreme heat; concentrated fire (such as welding tools and lasers) will be effective against it."
|
||||
@@ -1,62 +0,0 @@
|
||||
/datum/station_state
|
||||
var/floor = 0
|
||||
var/wall = 0
|
||||
var/r_wall = 0
|
||||
var/window = 0
|
||||
var/door = 0
|
||||
var/grille = 0
|
||||
var/mach = 0
|
||||
|
||||
/datum/station_state/proc/count()
|
||||
for(var/Z in SSmapping.levels_by_trait(ZTRAIT_STATION))
|
||||
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
|
||||
|
||||
|
||||
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)
|
||||
return 0
|
||||
var/output = 0
|
||||
output += (result.floor / max(floor,1))
|
||||
output += (result.r_wall/ max(r_wall,1))
|
||||
output += (result.wall / max(wall,1))
|
||||
output += (result.window / max(window,1))
|
||||
output += (result.door / max(door,1))
|
||||
output += (result.grille / max(grille,1))
|
||||
output += (result.mach / max(mach,1))
|
||||
return (output/7)
|
||||
@@ -1,295 +0,0 @@
|
||||
|
||||
////////////////
|
||||
// BASE TYPE //
|
||||
////////////////
|
||||
|
||||
//Do not spawn
|
||||
/mob/living/simple_animal/hostile/blob
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
pass_flags = PASSBLOB
|
||||
faction = list("blob")
|
||||
bubble_icon = "blob"
|
||||
speak_emote = null //so we use verb_yell/verb_say/etc
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
maxbodytemp = 360
|
||||
unique_name = 1
|
||||
a_intent = INTENT_HARM
|
||||
var/mob/camera/blob/overmind = null
|
||||
var/obj/structure/blob/factory/factory = null
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/update_icons()
|
||||
if(overmind)
|
||||
add_atom_colour(overmind.blob_reagent_datum.color, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/Destroy()
|
||||
if(overmind)
|
||||
overmind.blob_mobs -= src
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blob_act(obj/structure/blob/B)
|
||||
if(stat != DEAD && health < maxHealth)
|
||||
for(var/i in 1 to 2)
|
||||
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src)) //hello yes you are being healed
|
||||
if(overmind)
|
||||
H.color = overmind.blob_reagent_datum.complementary_color
|
||||
else
|
||||
H.color = "#000000"
|
||||
adjustHealth(-maxHealth*0.0125)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/fire_act(exposed_temperature, exposed_volume)
|
||||
..()
|
||||
if(exposed_temperature)
|
||||
adjustFireLoss(CLAMP(0.01 * exposed_temperature, 1, 5))
|
||||
else
|
||||
adjustFireLoss(5)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /obj/structure/blob))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/Process_Spacemove(movement_dir = 0)
|
||||
for(var/obj/structure/blob/B in range(1, src))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/proc/blob_chat(msg)
|
||||
var/spanned_message = say_quote(msg, get_spans())
|
||||
var/rendered = "<font color=\"#EE4000\"><b>\[Blob Telepathy\] [real_name]</b> [spanned_message]</font>"
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(isovermind(M) || istype(M, /mob/living/simple_animal/hostile/blob))
|
||||
to_chat(M, rendered)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
to_chat(M, "[link] [rendered]")
|
||||
|
||||
////////////////
|
||||
// BLOB SPORE //
|
||||
////////////////
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore
|
||||
name = "blob spore"
|
||||
desc = "A floating, fragile spore."
|
||||
icon_state = "blobpod"
|
||||
icon_living = "blobpod"
|
||||
health = 30
|
||||
maxHealth = 30
|
||||
verb_say = "psychically pulses"
|
||||
verb_ask = "psychically probes"
|
||||
verb_exclaim = "psychically yells"
|
||||
verb_yell = "psychically screams"
|
||||
melee_damage_lower = 2
|
||||
melee_damage_upper = 4
|
||||
obj_damage = 20
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
|
||||
attacktext = "hits"
|
||||
attack_sound = 'sound/weapons/genhit1.ogg'
|
||||
movement_type = FLYING
|
||||
del_on_death = 1
|
||||
deathmessage = "explodes into a cloud of gas!"
|
||||
var/death_cloud_size = 1 //size of cloud produced from a dying spore
|
||||
var/mob/living/carbon/human/oldguy
|
||||
var/is_zombie = 0
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/Initialize(mapload, var/obj/structure/blob/factory/linked_node)
|
||||
if(istype(linked_node))
|
||||
factory = linked_node
|
||||
factory.spores += src
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/Life()
|
||||
if(!is_zombie && isturf(src.loc))
|
||||
for(var/mob/living/carbon/human/H in view(src,1)) //Only for corpse right next to/on same tile
|
||||
if(H.stat == DEAD)
|
||||
Zombify(H)
|
||||
break
|
||||
if(factory && z != factory.z)
|
||||
death()
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/proc/Zombify(mob/living/carbon/human/H)
|
||||
is_zombie = 1
|
||||
if(H.wear_suit)
|
||||
var/obj/item/clothing/suit/armor/A = H.wear_suit
|
||||
if(A.armor && A.armor["melee"])
|
||||
maxHealth += A.armor["melee"] //That zombie's got armor, I want armor!
|
||||
maxHealth += 40
|
||||
health = maxHealth
|
||||
name = "blob zombie"
|
||||
desc = "A shambling corpse animated by the blob."
|
||||
melee_damage_lower += 8
|
||||
melee_damage_upper += 11
|
||||
movement_type = GROUND
|
||||
death_cloud_size = 0
|
||||
icon = H.icon
|
||||
icon_state = "zombie"
|
||||
H.hair_style = null
|
||||
H.update_hair()
|
||||
H.forceMove(src)
|
||||
oldguy = H
|
||||
update_icons()
|
||||
visible_message("<span class='warning'>The corpse of [H.name] suddenly rises!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/death(gibbed)
|
||||
// On death, create a small smoke of harmful gas (s-Acid)
|
||||
var/datum/effect_system/smoke_spread/chem/S = new
|
||||
var/turf/location = get_turf(src)
|
||||
|
||||
// Create the reagents to put into the air
|
||||
create_reagents(10)
|
||||
|
||||
if(overmind && overmind.blob_reagent_datum)
|
||||
reagents.add_reagent(overmind.blob_reagent_datum.id, 10)
|
||||
else
|
||||
reagents.add_reagent("spore", 10)
|
||||
|
||||
// Attach the smoke spreader and setup/start it.
|
||||
S.attach(location)
|
||||
S.set_up(reagents, death_cloud_size, location, silent=1)
|
||||
S.start()
|
||||
if(factory)
|
||||
factory.spore_delay = world.time + factory.spore_cooldown //put the factory on cooldown
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/Destroy()
|
||||
if(factory)
|
||||
factory.spores -= src
|
||||
factory = null
|
||||
if(oldguy)
|
||||
oldguy.forceMove(get_turf(src))
|
||||
oldguy = null
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/update_icons()
|
||||
if(overmind)
|
||||
add_atom_colour(overmind.blob_reagent_datum.complementary_color, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
if(is_zombie)
|
||||
copy_overlays(oldguy, TRUE)
|
||||
var/mutable_appearance/blob_head_overlay = mutable_appearance('icons/mob/blob.dmi', "blob_head")
|
||||
if(overmind)
|
||||
blob_head_overlay.color = overmind.blob_reagent_datum.complementary_color
|
||||
color = initial(color)//looks better.
|
||||
add_overlay(blob_head_overlay)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobspore/weak
|
||||
name = "fragile blob spore"
|
||||
health = 15
|
||||
maxHealth = 15
|
||||
melee_damage_lower = 1
|
||||
melee_damage_upper = 2
|
||||
death_cloud_size = 0
|
||||
|
||||
/////////////////
|
||||
// BLOBBERNAUT //
|
||||
/////////////////
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut
|
||||
name = "blobbernaut"
|
||||
desc = "A hulking, mobile chunk of blobmass."
|
||||
icon_state = "blobbernaut"
|
||||
icon_living = "blobbernaut"
|
||||
icon_dead = "blobbernaut_dead"
|
||||
health = 200
|
||||
maxHealth = 200
|
||||
damage_coeff = list(BRUTE = 0.5, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
obj_damage = 60
|
||||
attacktext = "slams"
|
||||
attack_sound = 'sound/effects/blobattack.ogg'
|
||||
verb_say = "gurgles"
|
||||
verb_ask = "demands"
|
||||
verb_exclaim = "roars"
|
||||
verb_yell = "bellows"
|
||||
force_threshold = 10
|
||||
pressure_resistance = 50
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
var/independent = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/Initialize()
|
||||
. = ..()
|
||||
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(..())
|
||||
var/list/blobs_in_area = range(2, src)
|
||||
if(independent)
|
||||
return // strong independent blobbernaut that don't need no blob
|
||||
var/damagesources = 0
|
||||
if(!(locate(/obj/structure/blob) in blobs_in_area))
|
||||
damagesources++
|
||||
if(!factory)
|
||||
damagesources++
|
||||
else
|
||||
if(locate(/obj/structure/blob/core) in blobs_in_area)
|
||||
adjustHealth(-maxHealth*0.1)
|
||||
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src)) //hello yes you are being healed
|
||||
if(overmind)
|
||||
H.color = overmind.blob_reagent_datum.complementary_color
|
||||
else
|
||||
H.color = "#000000"
|
||||
if(locate(/obj/structure/blob/node) in blobs_in_area)
|
||||
adjustHealth(-maxHealth*0.05)
|
||||
var/obj/effect/temp_visual/heal/H = new /obj/effect/temp_visual/heal(get_turf(src))
|
||||
if(overmind)
|
||||
H.color = overmind.blob_reagent_datum.complementary_color
|
||||
else
|
||||
H.color = "#000000"
|
||||
if(damagesources)
|
||||
for(var/i in 1 to damagesources)
|
||||
adjustHealth(maxHealth*0.025) //take 2.5% of max health as damage when not near the blob or if the naut has no factory, 5% if both
|
||||
var/image/I = new('icons/mob/blob.dmi', src, "nautdamage", MOB_LAYER+0.01)
|
||||
I.appearance_flags = RESET_COLOR
|
||||
if(overmind)
|
||||
I.color = overmind.blob_reagent_datum.complementary_color
|
||||
flick_overlay_view(I, src, 8)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
if(updating_health)
|
||||
update_health_hud()
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/update_health_hud()
|
||||
if(hud_used)
|
||||
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#e36600'>[round((health / maxHealth) * 100, 0.5)]%</font></div>"
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/AttackingTarget()
|
||||
. = ..()
|
||||
if(. && isliving(target) && overmind)
|
||||
var/mob/living/L = target
|
||||
var/mob_protection = L.get_permeability_protection()
|
||||
overmind.blob_reagent_datum.reaction_mob(L, VAPOR, 20, 0, mob_protection, overmind)//this will do between 10 and 20 damage(reduced by mob protection), depending on chemical, plus 4 from base brute damage.
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/update_icons()
|
||||
..()
|
||||
if(overmind) //if we have an overmind, we're doing chemical reactions instead of pure damage
|
||||
melee_damage_lower = 4
|
||||
melee_damage_upper = 4
|
||||
attacktext = overmind.blob_reagent_datum.blobbernaut_message
|
||||
else
|
||||
melee_damage_lower = initial(melee_damage_lower)
|
||||
melee_damage_upper = initial(melee_damage_upper)
|
||||
attacktext = initial(attacktext)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/death(gibbed)
|
||||
..(gibbed)
|
||||
if(factory)
|
||||
factory.naut = null //remove this naut from its factory
|
||||
factory.max_integrity = initial(factory.max_integrity)
|
||||
flick("blobbernaut_death", src)
|
||||
|
||||
/mob/living/simple_animal/hostile/blob/blobbernaut/independent
|
||||
independent = TRUE
|
||||
gold_core_spawnable = HOSTILE_SPAWN
|
||||
@@ -1,80 +0,0 @@
|
||||
/obj/structure/blob/core
|
||||
name = "blob core"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blank_blob"
|
||||
desc = "A huge, pulsating yellow mass."
|
||||
max_integrity = 400
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 75, acid = 90)
|
||||
explosion_block = 6
|
||||
point_return = -1
|
||||
health_regen = 0 //we regen in Life() instead of when pulsed
|
||||
var/core_regen = 2
|
||||
var/resource_delay = 0
|
||||
var/point_rate = 2
|
||||
|
||||
|
||||
/obj/structure/blob/core/Initialize(mapload, client/new_overmind = null, new_rate = 2, placed = 0)
|
||||
GLOB.blob_cores += src
|
||||
START_PROCESSING(SSobj, src)
|
||||
GLOB.poi_list |= src
|
||||
update_icon() //so it atleast appears
|
||||
if(!placed && !overmind)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
if(overmind)
|
||||
update_icon()
|
||||
point_rate = new_rate
|
||||
addtimer(CALLBACK(src, .proc/generate_announcement), 1800)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/blob/core/proc/generate_announcement()
|
||||
priority_announce("Confirmed outbreak of level 5 biohazard aboard [station_name()]. All personnel must contain the outbreak.", "Biohazard Alert", 'sound/ai/outbreak5.ogg')
|
||||
|
||||
/obj/structure/blob/core/scannerreport()
|
||||
return "Directs the blob's expansion, gradually expands, and sustains nearby blob spores and blobbernauts."
|
||||
|
||||
/obj/structure/blob/core/update_icon()
|
||||
cut_overlays()
|
||||
color = null
|
||||
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
|
||||
if(overmind)
|
||||
blob_overlay.color = overmind.blob_reagent_datum.color
|
||||
add_overlay(blob_overlay)
|
||||
add_overlay(mutable_appearance('icons/mob/blob.dmi', "blob_core_overlay"))
|
||||
|
||||
/obj/structure/blob/core/Destroy()
|
||||
GLOB.blob_cores -= src
|
||||
if(overmind)
|
||||
overmind.blob_core = null
|
||||
overmind = null
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
GLOB.poi_list -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/core/ex_act(severity, target)
|
||||
var/damage = 50 - 10 * severity //remember, the core takes half brute damage, so this is 20/15/10 damage based on severity
|
||||
take_damage(damage, BRUTE, "bomb", 0)
|
||||
|
||||
/obj/structure/blob/core/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir, overmind_reagent_trigger = 1)
|
||||
. = ..()
|
||||
if(obj_integrity > 0)
|
||||
if(overmind) //we should have an overmind, but...
|
||||
overmind.update_health_hud()
|
||||
|
||||
/obj/structure/blob/core/Life()
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(!overmind)
|
||||
qdel(src)
|
||||
else
|
||||
if(resource_delay <= world.time)
|
||||
resource_delay = world.time + 10 // 1 second
|
||||
overmind.add_points(point_rate)
|
||||
obj_integrity = min(max_integrity, obj_integrity+core_regen)
|
||||
if(overmind)
|
||||
overmind.update_health_hud()
|
||||
Pulse_Area(overmind, 12, 4, 3)
|
||||
for(var/obj/structure/blob/normal/B in range(1, src))
|
||||
if(prob(5))
|
||||
B.change_to(/obj/structure/blob/shield/core, overmind)
|
||||
..()
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/obj/structure/blob/factory
|
||||
name = "factory blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_factory"
|
||||
desc = "A thick spire of tendrils."
|
||||
max_integrity = 200
|
||||
health_regen = 1
|
||||
point_return = 25
|
||||
var/list/spores = list()
|
||||
var/mob/living/simple_animal/hostile/blob/blobbernaut/naut = null
|
||||
var/max_spores = 3
|
||||
var/spore_delay = 0
|
||||
var/spore_cooldown = 80 //8 seconds between spores and after spore death
|
||||
|
||||
|
||||
/obj/structure/blob/factory/scannerreport()
|
||||
if(naut)
|
||||
return "It is currently sustaining a blobbernaut, making it fragile and unable to produce blob spores."
|
||||
return "Will produce a blob spore every few seconds."
|
||||
|
||||
/obj/structure/blob/factory/Destroy()
|
||||
for(var/mob/living/simple_animal/hostile/blob/blobspore/spore in spores)
|
||||
if(spore.factory == src)
|
||||
spore.factory = null
|
||||
if(naut)
|
||||
naut.factory = null
|
||||
to_chat(naut, "<span class='userdanger'>Your factory was destroyed! You feel yourself dying!</span>")
|
||||
naut.throw_alert("nofactory", /obj/screen/alert/nofactory)
|
||||
spores = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/factory/Be_Pulsed()
|
||||
. = ..()
|
||||
if(naut)
|
||||
return
|
||||
if(spores.len >= max_spores)
|
||||
return
|
||||
if(spore_delay > world.time)
|
||||
return
|
||||
flick("blob_factory_glow", src)
|
||||
spore_delay = world.time + spore_cooldown
|
||||
var/mob/living/simple_animal/hostile/blob/blobspore/BS = new/mob/living/simple_animal/hostile/blob/blobspore(src.loc, src)
|
||||
if(overmind) //if we don't have an overmind, we don't need to do anything but make a spore
|
||||
BS.overmind = overmind
|
||||
BS.update_icons()
|
||||
overmind.blob_mobs.Add(BS)
|
||||
@@ -1,36 +0,0 @@
|
||||
/obj/structure/blob/node
|
||||
name = "blob node"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blank_blob"
|
||||
desc = "A large, pulsating yellow mass."
|
||||
max_integrity = 200
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 65, acid = 90)
|
||||
health_regen = 3
|
||||
point_return = 25
|
||||
|
||||
|
||||
/obj/structure/blob/node/Initialize()
|
||||
GLOB.blob_nodes += src
|
||||
START_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/blob/node/scannerreport()
|
||||
return "Gradually expands and sustains nearby blob spores and blobbernauts."
|
||||
|
||||
/obj/structure/blob/node/update_icon()
|
||||
cut_overlays()
|
||||
color = null
|
||||
var/mutable_appearance/blob_overlay = mutable_appearance('icons/mob/blob.dmi', "blob")
|
||||
if(overmind)
|
||||
blob_overlay.color = overmind.blob_reagent_datum.color
|
||||
add_overlay(blob_overlay)
|
||||
add_overlay(mutable_appearance('icons/mob/blob.dmi', "blob_node_overlay"))
|
||||
|
||||
/obj/structure/blob/node/Destroy()
|
||||
GLOB.blob_nodes -= src
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/node/Life()
|
||||
Pulse_Area(overmind, 10, 3, 2)
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/obj/structure/blob/resource
|
||||
name = "resource blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_resource"
|
||||
desc = "A thin spire of slightly swaying tendrils."
|
||||
max_integrity = 60
|
||||
point_return = 15
|
||||
var/resource_delay = 0
|
||||
|
||||
/obj/structure/blob/resource/scannerreport()
|
||||
return "Gradually supplies the blob with resources, increasing the rate of expansion."
|
||||
|
||||
/obj/structure/blob/resource/creation_action()
|
||||
if(overmind)
|
||||
overmind.resource_blobs += src
|
||||
|
||||
/obj/structure/blob/resource/Destroy()
|
||||
if(overmind)
|
||||
overmind.resource_blobs -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/resource/Be_Pulsed()
|
||||
. = ..()
|
||||
if(resource_delay > world.time)
|
||||
return
|
||||
flick("blob_resource_glow", src)
|
||||
if(overmind)
|
||||
overmind.add_points(1)
|
||||
resource_delay = world.time + 40 + overmind.resource_blobs.len * 2.5 //4 seconds plus a quarter second for each resource blob the overmind has
|
||||
else
|
||||
resource_delay = world.time + 40
|
||||
@@ -1,33 +0,0 @@
|
||||
/obj/structure/blob/shield
|
||||
name = "strong blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "blob_shield"
|
||||
desc = "A solid wall of slightly twitching tendrils."
|
||||
max_integrity = 150
|
||||
brute_resist = 0.25
|
||||
explosion_block = 3
|
||||
point_return = 4
|
||||
atmosblock = TRUE
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 90, acid = 90)
|
||||
|
||||
/obj/structure/blob/shield/scannerreport()
|
||||
if(atmosblock)
|
||||
return "Will prevent the spread of atmospheric changes."
|
||||
return "N/A"
|
||||
|
||||
/obj/structure/blob/shield/core
|
||||
point_return = 0
|
||||
|
||||
/obj/structure/blob/shield/update_icon()
|
||||
..()
|
||||
if(obj_integrity <= 75)
|
||||
icon_state = "blob_shield_damaged"
|
||||
name = "weakened strong blob"
|
||||
desc = "A wall of twitching tendrils."
|
||||
atmosblock = FALSE
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
name = initial(name)
|
||||
desc = initial(desc)
|
||||
atmosblock = TRUE
|
||||
air_update_turf(1)
|
||||
@@ -1,258 +0,0 @@
|
||||
//Few global vars to track the blob
|
||||
GLOBAL_LIST_EMPTY(blobs) //complete list of all blobs made.
|
||||
GLOBAL_LIST_EMPTY(blob_cores)
|
||||
GLOBAL_LIST_EMPTY(overminds)
|
||||
GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
|
||||
|
||||
/mob/camera/blob
|
||||
name = "Blob Overmind"
|
||||
real_name = "Blob Overmind"
|
||||
desc = "The overmind. It controls the blob."
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
icon_state = "marker"
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
move_on_shuttle = 1
|
||||
see_in_dark = 8
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
layer = FLY_LAYER
|
||||
|
||||
pass_flags = PASSBLOB
|
||||
faction = list("blob")
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
var/obj/structure/blob/core/blob_core = null // The blob overmind's core
|
||||
var/blob_points = 0
|
||||
var/max_blob_points = 100
|
||||
var/last_attack = 0
|
||||
var/datum/reagent/blob/blob_reagent_datum = new/datum/reagent/blob()
|
||||
var/list/blob_mobs = list()
|
||||
var/list/resource_blobs = list()
|
||||
var/free_chem_rerolls = 1 //one free chemical reroll
|
||||
var/nodes_required = 1 //if the blob needs nodes to place resource and factory blobs
|
||||
var/placed = 0
|
||||
var/base_point_rate = 2 //for blob core placement
|
||||
var/manualplace_min_time = 600 //in deciseconds //a minute, to get bearings
|
||||
var/autoplace_max_time = 3600 //six minutes, as long as should be needed
|
||||
var/list/blobs_legit = list()
|
||||
var/max_count = 0 //The biggest it got before death
|
||||
var/blobwincount = 400
|
||||
var/victory_in_progress = FALSE
|
||||
|
||||
/mob/camera/blob/Initialize(mapload, starting_points = 60)
|
||||
validate_location()
|
||||
blob_points = starting_points
|
||||
manualplace_min_time += world.time
|
||||
autoplace_max_time += world.time
|
||||
GLOB.overminds += src
|
||||
var/new_name = "[initial(name)] ([rand(1, 999)])"
|
||||
name = new_name
|
||||
real_name = new_name
|
||||
last_attack = world.time
|
||||
var/datum/reagent/blob/BC = pick((subtypesof(/datum/reagent/blob)))
|
||||
blob_reagent_datum = new BC
|
||||
color = blob_reagent_datum.complementary_color
|
||||
if(blob_core)
|
||||
blob_core.update_icon()
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
.= ..()
|
||||
|
||||
/mob/camera/blob/proc/validate_location()
|
||||
var/turf/T = get_turf(src)
|
||||
if(!is_valid_turf(T) && LAZYLEN(GLOB.blobstart))
|
||||
var/list/blobstarts = shuffle(GLOB.blobstart)
|
||||
for(var/_T in blobstarts)
|
||||
if(is_valid_turf(_T))
|
||||
T = _T
|
||||
break
|
||||
if(!T)
|
||||
CRASH("No blobspawnpoints and blob spawned in nullspace.")
|
||||
forceMove(T)
|
||||
|
||||
/mob/camera/blob/proc/is_valid_turf(turf/T)
|
||||
var/area/A = get_area(T)
|
||||
if((A && !A.blob_allowed) || !T || !is_station_level(T.z) || isspaceturf(T))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/mob/camera/blob/Life()
|
||||
if(!blob_core)
|
||||
if(!placed)
|
||||
if(manualplace_min_time && world.time >= manualplace_min_time)
|
||||
to_chat(src, "<b><span class='big'><font color=\"#EE4000\">You may now place your blob core.</font></span></b>")
|
||||
to_chat(src, "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [DisplayTimeText(autoplace_max_time - world.time)].</font></span>")
|
||||
manualplace_min_time = 0
|
||||
if(autoplace_max_time && world.time >= autoplace_max_time)
|
||||
place_blob_core(base_point_rate, 1)
|
||||
else
|
||||
qdel(src)
|
||||
else if(!victory_in_progress && (blobs_legit.len >= blobwincount))
|
||||
victory_in_progress = TRUE
|
||||
priority_announce("Biohazard has reached critical mass. Station loss is imminent.", "Biohazard Alert")
|
||||
set_security_level("delta")
|
||||
max_blob_points = INFINITY
|
||||
blob_points = INFINITY
|
||||
addtimer(CALLBACK(src, .proc/victory), 450)
|
||||
|
||||
if(!victory_in_progress && max_count < blobs_legit.len)
|
||||
max_count = blobs_legit.len
|
||||
..()
|
||||
|
||||
|
||||
/mob/camera/blob/proc/victory()
|
||||
sound_to_playing_players('sound/machines/alarm.ogg')
|
||||
sleep(100)
|
||||
for(var/i in GLOB.mob_living_list)
|
||||
var/mob/living/L = i
|
||||
var/turf/T = get_turf(L)
|
||||
if(!T || !is_station_level(T.z))
|
||||
continue
|
||||
|
||||
if(L in GLOB.overminds || (L.pass_flags & PASSBLOB))
|
||||
continue
|
||||
|
||||
var/area/Ablob = get_area(T)
|
||||
|
||||
if(!Ablob.blob_allowed)
|
||||
continue
|
||||
|
||||
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
|
||||
if(!A.blob_allowed)
|
||||
continue
|
||||
A.color = blob_reagent_datum.color
|
||||
A.name = "blob"
|
||||
A.icon = 'icons/mob/blob.dmi'
|
||||
A.icon_state = "blob_shield"
|
||||
A.layer = BELOW_MOB_LAYER
|
||||
A.invisibility = 0
|
||||
A.blend_mode = 0
|
||||
var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
|
||||
if(B)
|
||||
var/datum/objective/blob_takeover/main_objective = locate() in B.objectives
|
||||
if(main_objective)
|
||||
main_objective.completed = TRUE
|
||||
to_chat(world, "<B>[real_name] consumed the station in an unstoppable tide!</B>")
|
||||
SSticker.news_report = BLOB_WIN
|
||||
SSticker.force_ending = 1
|
||||
|
||||
/mob/camera/blob/Destroy()
|
||||
for(var/BL in GLOB.blobs)
|
||||
var/obj/structure/blob/B = BL
|
||||
if(B && B.overmind == src)
|
||||
B.overmind = null
|
||||
B.update_icon() //reset anything that was ours
|
||||
for(var/BLO in blob_mobs)
|
||||
var/mob/living/simple_animal/hostile/blob/BM = BLO
|
||||
if(BM)
|
||||
BM.overmind = null
|
||||
BM.update_icons()
|
||||
GLOB.overminds -= src
|
||||
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
|
||||
return ..()
|
||||
|
||||
/mob/camera/blob/Login()
|
||||
..()
|
||||
to_chat(src, "<span class='notice'>You are the overmind!</span>")
|
||||
blob_help()
|
||||
update_health_hud()
|
||||
add_points(0)
|
||||
|
||||
/mob/camera/blob/examine(mob/user)
|
||||
..()
|
||||
if(blob_reagent_datum)
|
||||
to_chat(user, "Its chemical is <font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</font>.")
|
||||
|
||||
/mob/camera/blob/update_health_hud()
|
||||
if(blob_core)
|
||||
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#e36600'>[round(blob_core.obj_integrity)]</font></div>"
|
||||
for(var/mob/living/simple_animal/hostile/blob/blobbernaut/B in blob_mobs)
|
||||
if(B.hud_used && B.hud_used.blobpwrdisplay)
|
||||
B.hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_core.obj_integrity)]</font></div>"
|
||||
|
||||
/mob/camera/blob/proc/add_points(points)
|
||||
blob_points = CLAMP(blob_points + points, 0, max_blob_points)
|
||||
hud_used.blobpwrdisplay.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#82ed00'>[round(blob_points)]</font></div>"
|
||||
|
||||
/mob/camera/blob/say(message)
|
||||
if (!message)
|
||||
return
|
||||
|
||||
if (src.client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "You cannot send IC messages (muted).")
|
||||
return
|
||||
if (src.client.handle_spam_prevention(message,MUTE_IC))
|
||||
return
|
||||
|
||||
if (stat)
|
||||
return
|
||||
|
||||
blob_talk(message)
|
||||
|
||||
/mob/camera/blob/proc/blob_talk(message)
|
||||
|
||||
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
|
||||
if (!message)
|
||||
return
|
||||
|
||||
log_talk(src,"[key_name(src)] : [message]",LOGSAY)
|
||||
|
||||
var/message_a = say_quote(message, get_spans())
|
||||
var/rendered = "<span class='big'><font color=\"#EE4000\"><b>\[Blob Telepathy\] [name](<font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</font>)</b> [message_a]</font></span>"
|
||||
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
if(isovermind(M) || istype(M, /mob/living/simple_animal/hostile/blob))
|
||||
to_chat(M, rendered)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
to_chat(M, "[link] [rendered]")
|
||||
|
||||
/mob/camera/blob/emote(act,m_type=1,message = null)
|
||||
return
|
||||
|
||||
/mob/camera/blob/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
/mob/camera/blob/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
if(blob_core)
|
||||
stat(null, "Core Health: [blob_core.obj_integrity]")
|
||||
stat(null, "Power Stored: [blob_points]/[max_blob_points]")
|
||||
stat(null, "Blobs to Win: [blobs_legit.len]/[blobwincount]")
|
||||
if(free_chem_rerolls)
|
||||
stat(null, "You have [free_chem_rerolls] Free Chemical Reroll\s Remaining")
|
||||
if(!placed)
|
||||
if(manualplace_min_time)
|
||||
stat(null, "Time Before Manual Placement: [max(round((manualplace_min_time - world.time)*0.1, 0.1), 0)]")
|
||||
stat(null, "Time Before Automatic Placement: [max(round((autoplace_max_time - world.time)*0.1, 0.1), 0)]")
|
||||
|
||||
/mob/camera/blob/Move(NewLoc, Dir = 0)
|
||||
if(placed)
|
||||
var/obj/structure/blob/B = locate() in range("3x3", NewLoc)
|
||||
if(B)
|
||||
forceMove(NewLoc)
|
||||
else
|
||||
return 0
|
||||
else
|
||||
var/area/A = get_area(NewLoc)
|
||||
if(isspaceturf(NewLoc) || istype(A, /area/shuttle)) //if unplaced, can't go on shuttles or space tiles
|
||||
return 0
|
||||
forceMove(NewLoc)
|
||||
return 1
|
||||
|
||||
/mob/camera/blob/mind_initialize()
|
||||
. = ..()
|
||||
var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
|
||||
if(!B)
|
||||
mind.add_antag_datum(/datum/antagonist/blob)
|
||||
@@ -1,372 +0,0 @@
|
||||
/mob/camera/blob/proc/can_buy(cost = 15)
|
||||
if(blob_points < cost)
|
||||
to_chat(src, "<span class='warning'>You cannot afford this, you need at least [cost] resources!</span>")
|
||||
return 0
|
||||
add_points(-cost)
|
||||
return 1
|
||||
|
||||
// Power verbs
|
||||
|
||||
/mob/camera/blob/proc/place_blob_core(point_rate, placement_override , pop_override = FALSE)
|
||||
if(placed && placement_override != -1)
|
||||
return 1
|
||||
if(!placement_override)
|
||||
if(!pop_override)
|
||||
for(var/mob/living/M in range(7, src))
|
||||
if("blob" in M.faction)
|
||||
continue
|
||||
if(M.client)
|
||||
to_chat(src, "<span class='warning'>There is someone too close to place your blob core!</span>")
|
||||
return 0
|
||||
for(var/mob/living/M in view(13, src))
|
||||
if("blob" in M.faction)
|
||||
continue
|
||||
if(M.client)
|
||||
to_chat(src, "<span class='warning'>Someone could see your blob core from here!</span>")
|
||||
return 0
|
||||
var/turf/T = get_turf(src)
|
||||
if(T.density)
|
||||
to_chat(src, "<span class='warning'>This spot is too dense to place a blob core on!</span>")
|
||||
return 0
|
||||
for(var/obj/O in T)
|
||||
if(istype(O, /obj/structure/blob))
|
||||
if(istype(O, /obj/structure/blob/normal))
|
||||
qdel(O)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>There is already a blob here!</span>")
|
||||
return 0
|
||||
else if(O.density)
|
||||
to_chat(src, "<span class='warning'>This spot is too dense to place a blob core on!</span>")
|
||||
return 0
|
||||
if(!pop_override && world.time <= manualplace_min_time && world.time <= autoplace_max_time)
|
||||
to_chat(src, "<span class='warning'>It is too early to place your blob core!</span>")
|
||||
return 0
|
||||
else if(placement_override == 1)
|
||||
var/turf/T = pick(GLOB.blobstart)
|
||||
forceMove(T) //got overrided? you're somewhere random, motherfucker
|
||||
if(placed && blob_core)
|
||||
blob_core.forceMove(loc)
|
||||
else
|
||||
var/obj/structure/blob/core/core = new(get_turf(src), src, point_rate, 1)
|
||||
core.overmind = src
|
||||
blobs_legit += src
|
||||
blob_core = core
|
||||
core.update_icon()
|
||||
update_health_hud()
|
||||
placed = 1
|
||||
return 1
|
||||
|
||||
/mob/camera/blob/verb/transport_core()
|
||||
set category = "Blob"
|
||||
set name = "Jump to Core"
|
||||
set desc = "Move your camera to your core."
|
||||
if(blob_core)
|
||||
forceMove(blob_core.drop_location())
|
||||
|
||||
/mob/camera/blob/verb/jump_to_node()
|
||||
set category = "Blob"
|
||||
set name = "Jump to Node"
|
||||
set desc = "Move your camera to a selected node."
|
||||
if(GLOB.blob_nodes.len)
|
||||
var/list/nodes = list()
|
||||
for(var/i in 1 to GLOB.blob_nodes.len)
|
||||
var/obj/structure/blob/node/B = GLOB.blob_nodes[i]
|
||||
nodes["Blob Node #[i] ([B.overmind ? "[B.overmind.blob_reagent_datum.name]":"No Chemical"])"] = B
|
||||
var/node_name = input(src, "Choose a node to jump to.", "Node Jump") in nodes
|
||||
var/obj/structure/blob/node/chosen_node = nodes[node_name]
|
||||
if(chosen_node)
|
||||
forceMove(chosen_node.loc)
|
||||
|
||||
/mob/camera/blob/proc/createSpecial(price, blobType, nearEquals, needsNode, turf/T)
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
var/obj/structure/blob/B = (locate(/obj/structure/blob) in T)
|
||||
if(!B)
|
||||
to_chat(src, "<span class='warning'>There is no blob here!</span>")
|
||||
return
|
||||
if(!istype(B, /obj/structure/blob/normal))
|
||||
to_chat(src, "<span class='warning'>Unable to use this blob, find a normal one.</span>")
|
||||
return
|
||||
if(needsNode && nodes_required)
|
||||
if(!(locate(/obj/structure/blob/node) in orange(3, T)) && !(locate(/obj/structure/blob/core) in orange(4, T)))
|
||||
to_chat(src, "<span class='warning'>You need to place this blob closer to a node or core!</span>")
|
||||
return //handholdotron 2000
|
||||
if(nearEquals)
|
||||
for(var/obj/structure/blob/L in orange(nearEquals, T))
|
||||
if(L.type == blobType)
|
||||
to_chat(src, "<span class='warning'>There is a similar blob nearby, move more than [nearEquals] tiles away from it!</span>")
|
||||
return
|
||||
if(!can_buy(price))
|
||||
return
|
||||
var/obj/structure/blob/N = B.change_to(blobType, src)
|
||||
return N
|
||||
|
||||
/mob/camera/blob/verb/toggle_node_req()
|
||||
set category = "Blob"
|
||||
set name = "Toggle Node Requirement"
|
||||
set desc = "Toggle requiring nodes to place resource and factory blobs."
|
||||
nodes_required = !nodes_required
|
||||
if(nodes_required)
|
||||
to_chat(src, "<span class='warning'>You now require a nearby node or core to place factory and resource blobs.</span>")
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You no longer require a nearby node or core to place factory and resource blobs.</span>")
|
||||
|
||||
/mob/camera/blob/verb/create_shield_power()
|
||||
set category = "Blob"
|
||||
set name = "Create Shield Blob (15)"
|
||||
set desc = "Create a shield blob, which will block fire and is hard to kill."
|
||||
create_shield()
|
||||
|
||||
/mob/camera/blob/proc/create_shield(turf/T)
|
||||
createSpecial(15, /obj/structure/blob/shield, 0, 0, T)
|
||||
|
||||
/mob/camera/blob/verb/create_resource()
|
||||
set category = "Blob"
|
||||
set name = "Create Resource Blob (40)"
|
||||
set desc = "Create a resource tower which will generate resources for you."
|
||||
createSpecial(40, /obj/structure/blob/resource, 4, 1)
|
||||
|
||||
/mob/camera/blob/verb/create_node()
|
||||
set category = "Blob"
|
||||
set name = "Create Node Blob (50)"
|
||||
set desc = "Create a node, which will power nearby factory and resource blobs."
|
||||
createSpecial(50, /obj/structure/blob/node, 5, 0)
|
||||
|
||||
/mob/camera/blob/verb/create_factory()
|
||||
set category = "Blob"
|
||||
set name = "Create Factory Blob (60)"
|
||||
set desc = "Create a spore tower that will spawn spores to harass your enemies."
|
||||
createSpecial(60, /obj/structure/blob/factory, 7, 1)
|
||||
|
||||
/mob/camera/blob/verb/create_blobbernaut()
|
||||
set category = "Blob"
|
||||
set name = "Create Blobbernaut (40)"
|
||||
set desc = "Create a powerful blobbernaut which is mildly smart and will attack enemies."
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/structure/blob/factory/B = locate(/obj/structure/blob/factory) in T
|
||||
if(!B)
|
||||
to_chat(src, "<span class='warning'>You must be on a factory blob!</span>")
|
||||
return
|
||||
if(B.naut) //if it already made a blobbernaut, it can't do it again
|
||||
to_chat(src, "<span class='warning'>This factory blob is already sustaining a blobbernaut.</span>")
|
||||
return
|
||||
if(B.obj_integrity < B.max_integrity * 0.5)
|
||||
to_chat(src, "<span class='warning'>This factory blob is too damaged to sustain a blobbernaut.</span>")
|
||||
return
|
||||
if(!can_buy(40))
|
||||
return
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollGhostCandidates("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, <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]"]")
|
||||
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"
|
||||
set name = "Relocate Core (80)"
|
||||
set desc = "Swaps the locations of your core and the selected node."
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/structure/blob/node/B = locate(/obj/structure/blob/node) in T
|
||||
if(!B)
|
||||
to_chat(src, "<span class='warning'>You must be on a blob node!</span>")
|
||||
return
|
||||
if(!blob_core)
|
||||
to_chat(src, "<span class='userdanger'>You have no core and are about to die! May you rest in peace.</span>")
|
||||
return
|
||||
var/area/A = get_area(T)
|
||||
if(isspaceturf(T) || A && !A.blob_allowed)
|
||||
to_chat(src, "<span class='warning'>You cannot relocate your core here!</span>")
|
||||
return
|
||||
if(!can_buy(80))
|
||||
return
|
||||
var/turf/old_turf = get_turf(blob_core)
|
||||
var/olddir = blob_core.dir
|
||||
blob_core.forceMove(T)
|
||||
blob_core.setDir(B.dir)
|
||||
B.forceMove(old_turf)
|
||||
B.setDir(olddir)
|
||||
|
||||
/mob/camera/blob/verb/revert()
|
||||
set category = "Blob"
|
||||
set name = "Remove Blob"
|
||||
set desc = "Removes a blob, giving you back some resources."
|
||||
var/turf/T = get_turf(src)
|
||||
remove_blob(T)
|
||||
|
||||
/mob/camera/blob/proc/remove_blob(turf/T)
|
||||
var/obj/structure/blob/B = locate() in T
|
||||
if(!B)
|
||||
to_chat(src, "<span class='warning'>There is no blob there!</span>")
|
||||
return
|
||||
if(B.point_return < 0)
|
||||
to_chat(src, "<span class='warning'>Unable to remove this blob.</span>")
|
||||
return
|
||||
if(max_blob_points < B.point_return + blob_points)
|
||||
to_chat(src, "<span class='warning'>You have too many resources to remove this blob!</span>")
|
||||
return
|
||||
if(B.point_return)
|
||||
add_points(B.point_return)
|
||||
to_chat(src, "<span class='notice'>Gained [B.point_return] resources from removing \the [B].</span>")
|
||||
qdel(B)
|
||||
|
||||
/mob/camera/blob/verb/expand_blob_power()
|
||||
set category = "Blob"
|
||||
set name = "Expand/Attack Blob (4)"
|
||||
set desc = "Attempts to create a new blob in this tile. If the tile isn't clear, instead attacks it, damaging mobs and objects."
|
||||
var/turf/T = get_turf(src)
|
||||
expand_blob(T)
|
||||
|
||||
/mob/camera/blob/proc/expand_blob(turf/T)
|
||||
if(world.time < last_attack)
|
||||
return
|
||||
var/list/possibleblobs = list()
|
||||
for(var/obj/structure/blob/AB in range(T, 1))
|
||||
possibleblobs += AB
|
||||
if(!possibleblobs.len)
|
||||
to_chat(src, "<span class='warning'>There is no blob adjacent to the target tile!</span>")
|
||||
return
|
||||
if(can_buy(4))
|
||||
var/attacksuccess = FALSE
|
||||
for(var/mob/living/L in T)
|
||||
if("blob" in L.faction) //no friendly/dead fire
|
||||
continue
|
||||
if(L.stat != DEAD)
|
||||
attacksuccess = TRUE
|
||||
var/mob_protection = L.get_permeability_protection()
|
||||
blob_reagent_datum.reaction_mob(L, VAPOR, 25, 1, mob_protection, src)
|
||||
blob_reagent_datum.send_message(L)
|
||||
var/obj/structure/blob/B = locate() in T
|
||||
if(B)
|
||||
if(attacksuccess) //if we successfully attacked a turf with a blob on it, don't refund shit
|
||||
B.blob_attack_animation(T, src)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>There is a blob there!</span>")
|
||||
add_points(4) //otherwise, refund all of the cost
|
||||
else
|
||||
var/list/cardinalblobs = list()
|
||||
var/list/diagonalblobs = list()
|
||||
for(var/I in possibleblobs)
|
||||
var/obj/structure/blob/IB = I
|
||||
if(get_dir(IB, T) in GLOB.cardinals)
|
||||
cardinalblobs += IB
|
||||
else
|
||||
diagonalblobs += IB
|
||||
var/obj/structure/blob/OB
|
||||
if(cardinalblobs.len)
|
||||
OB = pick(cardinalblobs)
|
||||
OB.expand(T, src)
|
||||
else
|
||||
OB = pick(diagonalblobs)
|
||||
if(attacksuccess)
|
||||
OB.blob_attack_animation(T, src)
|
||||
playsound(OB, 'sound/effects/splat.ogg', 50, 1)
|
||||
else
|
||||
add_points(4) //if we're attacking diagonally and didn't hit anything, refund
|
||||
if(attacksuccess)
|
||||
last_attack = world.time + CLICK_CD_MELEE
|
||||
else
|
||||
last_attack = world.time + CLICK_CD_RAPID
|
||||
|
||||
/mob/camera/blob/verb/rally_spores_power()
|
||||
set category = "Blob"
|
||||
set name = "Rally Spores"
|
||||
set desc = "Rally your spores to move to a target location."
|
||||
var/turf/T = get_turf(src)
|
||||
rally_spores(T)
|
||||
|
||||
/mob/camera/blob/proc/rally_spores(turf/T)
|
||||
to_chat(src, "You rally your spores.")
|
||||
var/list/surrounding_turfs = block(locate(T.x - 1, T.y - 1, T.z), locate(T.x + 1, T.y + 1, T.z))
|
||||
if(!surrounding_turfs.len)
|
||||
return
|
||||
for(var/mob/living/simple_animal/hostile/blob/blobspore/BS in blob_mobs)
|
||||
if(isturf(BS.loc) && get_dist(BS, T) <= 35)
|
||||
BS.LoseTarget()
|
||||
BS.Goto(pick(surrounding_turfs), BS.move_to_delay)
|
||||
|
||||
/mob/camera/blob/verb/blob_broadcast()
|
||||
set category = "Blob"
|
||||
set name = "Blob Broadcast"
|
||||
set desc = "Speak with your blob spores and blobbernauts as your mouthpieces."
|
||||
var/speak_text = input(src, "What would you like to say with your minions?", "Blob Broadcast", null) as text
|
||||
if(!speak_text)
|
||||
return
|
||||
else
|
||||
to_chat(src, "You broadcast with your minions, <B>[speak_text]</B>")
|
||||
for(var/BLO in blob_mobs)
|
||||
var/mob/living/simple_animal/hostile/blob/BM = BLO
|
||||
if(BM.stat == CONSCIOUS)
|
||||
BM.say(speak_text)
|
||||
|
||||
/mob/camera/blob/verb/chemical_reroll()
|
||||
set category = "Blob"
|
||||
set name = "Reactive Chemical Adaptation (40)"
|
||||
set desc = "Replaces your chemical with a random, different one."
|
||||
if(free_chem_rerolls || can_buy(40))
|
||||
set_chemical()
|
||||
if(free_chem_rerolls)
|
||||
free_chem_rerolls--
|
||||
|
||||
/mob/camera/blob/proc/set_chemical()
|
||||
var/datum/reagent/blob/BC = pick((subtypesof(/datum/reagent/blob) - blob_reagent_datum.type))
|
||||
blob_reagent_datum = new BC
|
||||
color = blob_reagent_datum.complementary_color
|
||||
for(var/BL in GLOB.blobs)
|
||||
var/obj/structure/blob/B = BL
|
||||
B.update_icon()
|
||||
for(var/BLO in blob_mobs)
|
||||
var/mob/living/simple_animal/hostile/blob/BM = BLO
|
||||
BM.update_icons() //If it's getting a new chemical, tell it what it does!
|
||||
to_chat(BM, "Your overmind's blob reagent is now: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
|
||||
to_chat(BM, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]")
|
||||
to_chat(src, "Your reagent is now: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
|
||||
to_chat(src, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.description]")
|
||||
if(blob_reagent_datum.effectdesc)
|
||||
to_chat(src, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.effectdesc]")
|
||||
|
||||
/mob/camera/blob/verb/blob_help()
|
||||
set category = "Blob"
|
||||
set name = "*Blob Help*"
|
||||
set desc = "Help on how to blob."
|
||||
to_chat(src, "<b>As the overmind, you can control the blob!</b>")
|
||||
to_chat(src, "Your blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
|
||||
to_chat(src, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.description]")
|
||||
if(blob_reagent_datum.effectdesc)
|
||||
to_chat(src, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.effectdesc]")
|
||||
to_chat(src, "<b>You can expand, which will attack people, damage objects, or place a Normal Blob if the tile is clear.</b>")
|
||||
to_chat(src, "<i>Normal Blobs</i> will expand your reach and can be upgraded into special blobs that perform certain functions.")
|
||||
to_chat(src, "<b>You can upgrade normal blobs into the following types of blob:</b>")
|
||||
to_chat(src, "<i>Shield Blobs</i> are strong and expensive blobs which take more damage. In additon, they are fireproof and can block air, use these to protect yourself from station fires.")
|
||||
to_chat(src, "<i>Resource Blobs</i> are blobs which produce more resources for you, build as many of these as possible to consume the station. This type of blob must be placed near node blobs or your core to work.")
|
||||
to_chat(src, "<i>Factory Blobs</i> are blobs that spawn blob spores which will attack nearby enemies. This type of blob must be placed near node blobs or your core to work.")
|
||||
to_chat(src, "<i>Blobbernauts</i> can be produced from factories for a cost, and are hard to kill, powerful, and moderately smart. The factory used to create one will become fragile and briefly unable to produce spores.")
|
||||
to_chat(src, "<i>Node Blobs</i> are blobs which grow, like the core. Like the core it can activate resource and factory blobs.")
|
||||
to_chat(src, "<b>In addition to the buttons on your HUD, there are a few click shortcuts to speed up expansion and defense.</b>")
|
||||
to_chat(src, "<b>Shortcuts:</b> Click = Expand Blob <b>|</b> Middle Mouse Click = Rally Spores <b>|</b> Ctrl Click = Create Shield Blob <b>|</b> Alt Click = Remove Blob")
|
||||
to_chat(src, "Attempting to talk will send a message to all other overminds, allowing you to coordinate with them.")
|
||||
if(!placed && autoplace_max_time <= world.time)
|
||||
to_chat(src, "<span class='big'><font color=\"#EE4000\">You will automatically place your blob core in [DisplayTimeText(autoplace_max_time - world.time)].</font></span>")
|
||||
to_chat(src, "<span class='big'><font color=\"#EE4000\">You [manualplace_min_time ? "will be able to":"can"] manually place your blob core by pressing the Place Blob Core button in the bottom right corner of the screen.</font></span>")
|
||||
@@ -1,351 +0,0 @@
|
||||
//I will need to recode parts of this but I am way too tired atm //I don't know who left this comment but they never did come back
|
||||
/obj/structure/blob
|
||||
name = "blob"
|
||||
icon = 'icons/mob/blob.dmi'
|
||||
light_range = 2
|
||||
desc = "A thick wall of writhing tendrils."
|
||||
density = FALSE //this being false causes two bugs, being able to attack blob tiles behind other blobs and being unable to move on blob tiles in no gravity, but turning it to 1 causes the blob mobs to be unable to path through blobs, which is probably worse.
|
||||
opacity = 0
|
||||
anchored = TRUE
|
||||
layer = BELOW_MOB_LAYER
|
||||
CanAtmosPass = ATMOS_PASS_PROC
|
||||
var/point_return = 0 //How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed.
|
||||
max_integrity = 30
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 80, acid = 70)
|
||||
var/health_regen = 2 //how much health this blob regens when pulsed
|
||||
var/pulse_timestamp = 0 //we got pulsed when?
|
||||
var/heal_timestamp = 0 //we got healed when?
|
||||
var/brute_resist = 0.5 //multiplies brute damage by this
|
||||
var/fire_resist = 1 //multiplies burn damage by this
|
||||
var/atmosblock = FALSE //if the blob blocks atmos and heat spread
|
||||
var/mob/camera/blob/overmind
|
||||
|
||||
/obj/structure/blob/Initialize(mapload, owner_overmind)
|
||||
overmind = owner_overmind
|
||||
var/area/Ablob = get_area(loc)
|
||||
if(Ablob.blob_allowed) //Is this area allowed for winning as blob?
|
||||
overmind.blobs_legit += src
|
||||
GLOB.blobs += src //Keep track of the blob in the normal list either way
|
||||
setDir(pick(GLOB.cardinals))
|
||||
update_icon()
|
||||
.= ..()
|
||||
if(atmosblock)
|
||||
air_update_turf(1)
|
||||
ConsumeTile()
|
||||
|
||||
/obj/structure/blob/proc/creation_action() //When it's created by the overmind, do this.
|
||||
return
|
||||
|
||||
/obj/structure/blob/Destroy()
|
||||
if(atmosblock)
|
||||
atmosblock = FALSE
|
||||
air_update_turf(1)
|
||||
if(overmind)
|
||||
overmind.blobs_legit -= src //if it was in the legit blobs list, it isn't now
|
||||
GLOB.blobs -= src //it's no longer in the all blobs list either
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Expand() is no longer broken, no check necessary.
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/blob_act()
|
||||
return
|
||||
|
||||
/obj/structure/blob/Adjacent(var/atom/neighbour)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/result = 0
|
||||
var/direction = get_dir(src, neighbour)
|
||||
var/list/dirs = list("[NORTHWEST]" = list(NORTH, WEST), "[NORTHEAST]" = list(NORTH, EAST), "[SOUTHEAST]" = list(SOUTH, EAST), "[SOUTHWEST]" = list(SOUTH, WEST))
|
||||
for(var/A in dirs)
|
||||
if(direction == text2num(A))
|
||||
for(var/B in dirs[A])
|
||||
var/C = locate(/obj/structure/blob) in get_step(src, B)
|
||||
if(C)
|
||||
result++
|
||||
. -= result - 1
|
||||
|
||||
/obj/structure/blob/BlockSuperconductivity()
|
||||
return atmosblock
|
||||
|
||||
/obj/structure/blob/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover) && (mover.pass_flags & PASSBLOB))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/structure/blob/CanAtmosPass(turf/T)
|
||||
return !atmosblock
|
||||
|
||||
/obj/structure/blob/CanAStarPass(ID, dir, caller)
|
||||
. = 0
|
||||
if(ismovableatom(caller))
|
||||
var/atom/movable/mover = caller
|
||||
. = . || (mover.pass_flags & PASSBLOB)
|
||||
|
||||
/obj/structure/blob/update_icon() //Updates color based on overmind color if we have an overmind.
|
||||
if(overmind)
|
||||
add_atom_colour(overmind.blob_reagent_datum.color, FIXED_COLOUR_PRIORITY)
|
||||
else
|
||||
remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
|
||||
/obj/structure/blob/process()
|
||||
Life()
|
||||
|
||||
/obj/structure/blob/proc/Life()
|
||||
return
|
||||
|
||||
/obj/structure/blob/proc/Pulse_Area(mob/camera/blob/pulsing_overmind, claim_range = 10, pulse_range = 3, expand_range = 2)
|
||||
if(QDELETED(pulsing_overmind))
|
||||
pulsing_overmind = overmind
|
||||
Be_Pulsed()
|
||||
var/expanded = FALSE
|
||||
if(prob(70) && expand())
|
||||
expanded = TRUE
|
||||
var/list/blobs_to_affect = list()
|
||||
for(var/obj/structure/blob/B in urange(claim_range, src, 1))
|
||||
blobs_to_affect += B
|
||||
shuffle_inplace(blobs_to_affect)
|
||||
for(var/L in blobs_to_affect)
|
||||
var/obj/structure/blob/B = L
|
||||
if(!B.overmind && !istype(B, /obj/structure/blob/core) && prob(30))
|
||||
B.overmind = pulsing_overmind //reclaim unclaimed, non-core blobs.
|
||||
B.update_icon()
|
||||
var/distance = get_dist(get_turf(src), get_turf(B))
|
||||
var/expand_probablity = max(20 - distance * 8, 1)
|
||||
if(B.Adjacent(src))
|
||||
expand_probablity = 20
|
||||
if(distance <= expand_range)
|
||||
var/can_expand = TRUE
|
||||
if(blobs_to_affect.len >= 120 && B.heal_timestamp > world.time)
|
||||
can_expand = FALSE
|
||||
if(can_expand && B.pulse_timestamp <= world.time && prob(expand_probablity))
|
||||
var/obj/structure/blob/newB = B.expand(null, null, !expanded) //expansion falls off with range but is faster near the blob causing the expansion
|
||||
if(newB)
|
||||
if(expanded)
|
||||
qdel(newB)
|
||||
expanded = TRUE
|
||||
if(distance <= pulse_range)
|
||||
B.Be_Pulsed()
|
||||
|
||||
/obj/structure/blob/proc/Be_Pulsed()
|
||||
if(pulse_timestamp <= world.time)
|
||||
ConsumeTile()
|
||||
if(heal_timestamp <= world.time)
|
||||
obj_integrity = min(max_integrity, obj_integrity+health_regen)
|
||||
heal_timestamp = world.time + 20
|
||||
update_icon()
|
||||
pulse_timestamp = world.time + 10
|
||||
return 1 //we did it, we were pulsed!
|
||||
return 0 //oh no we failed
|
||||
|
||||
/obj/structure/blob/proc/ConsumeTile()
|
||||
for(var/atom/A in loc)
|
||||
A.blob_act(src)
|
||||
if(iswallturf(loc))
|
||||
loc.blob_act(src) //don't ask how a wall got on top of the core, just eat it
|
||||
|
||||
/obj/structure/blob/proc/blob_attack_animation(atom/A = null, controller) //visually attacks an atom
|
||||
var/obj/effect/temp_visual/blob/O = new /obj/effect/temp_visual/blob(src.loc)
|
||||
O.setDir(dir)
|
||||
if(controller)
|
||||
var/mob/camera/blob/BO = controller
|
||||
O.color = BO.blob_reagent_datum.color
|
||||
O.alpha = 200
|
||||
else if(overmind)
|
||||
O.color = overmind.blob_reagent_datum.color
|
||||
if(A)
|
||||
O.do_attack_animation(A) //visually attack the whatever
|
||||
return O //just in case you want to do something to the animation.
|
||||
|
||||
/obj/structure/blob/proc/expand(turf/T = null, controller = null, expand_reaction = 1)
|
||||
if(!T)
|
||||
var/list/dirs = list(1,2,4,8)
|
||||
for(var/i = 1 to 4)
|
||||
var/dirn = pick(dirs)
|
||||
dirs.Remove(dirn)
|
||||
T = get_step(src, dirn)
|
||||
if(!(locate(/obj/structure/blob) in T))
|
||||
break
|
||||
else
|
||||
T = null
|
||||
if(!T)
|
||||
return 0
|
||||
var/make_blob = TRUE //can we make a blob?
|
||||
|
||||
if(isspaceturf(T) && !(locate(/obj/structure/lattice) in T) && prob(80))
|
||||
make_blob = FALSE
|
||||
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) //Let's give some feedback that we DID try to spawn in space, since players are used to it
|
||||
|
||||
ConsumeTile() //hit the tile we're in, making sure there are no border objects blocking us
|
||||
if(!T.CanPass(src, T)) //is the target turf impassable
|
||||
make_blob = FALSE
|
||||
T.blob_act(src) //hit the turf if it is
|
||||
for(var/atom/A in T)
|
||||
if(!A.CanPass(src, T)) //is anything in the turf impassable
|
||||
make_blob = FALSE
|
||||
A.blob_act(src) //also hit everything in the turf
|
||||
|
||||
if(make_blob) //well, can we?
|
||||
var/obj/structure/blob/B = new /obj/structure/blob/normal(src.loc, (controller || overmind))
|
||||
B.density = TRUE
|
||||
if(T.Enter(B,src)) //NOW we can attempt to move into the tile
|
||||
B.density = initial(B.density)
|
||||
B.forceMove(T)
|
||||
B.update_icon()
|
||||
if(B.overmind && expand_reaction)
|
||||
B.overmind.blob_reagent_datum.expand_reaction(src, B, T, controller)
|
||||
return B
|
||||
else
|
||||
blob_attack_animation(T, controller)
|
||||
T.blob_act(src) //if we can't move in hit the turf again
|
||||
qdel(B) //we should never get to this point, since we checked before moving in. destroy the blob so we don't have two blobs on one tile
|
||||
return null
|
||||
else
|
||||
blob_attack_animation(T, controller) //if we can't, animate that we attacked
|
||||
return null
|
||||
|
||||
/obj/structure/blob/emp_act(severity)
|
||||
if(severity > 0)
|
||||
if(overmind)
|
||||
overmind.blob_reagent_datum.emp_reaction(src, severity)
|
||||
if(prob(100 - severity * 30))
|
||||
new /obj/effect/temp_visual/emp(get_turf(src))
|
||||
|
||||
/obj/structure/blob/tesla_act(power)
|
||||
..()
|
||||
if(overmind)
|
||||
if(overmind.blob_reagent_datum.tesla_reaction(src, power))
|
||||
take_damage(power/400, BURN, "energy")
|
||||
else
|
||||
take_damage(power/400, BURN, "energy")
|
||||
|
||||
/obj/structure/blob/extinguish()
|
||||
..()
|
||||
if(overmind)
|
||||
overmind.blob_reagent_datum.extinguish_reaction(src)
|
||||
|
||||
/obj/structure/blob/hulk_damage()
|
||||
return 15
|
||||
|
||||
/obj/structure/blob/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/device/analyzer))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
to_chat(user, "<b>The analyzer beeps once, then reports:</b><br>")
|
||||
SEND_SOUND(user, sound('sound/machines/ping.ogg'))
|
||||
to_chat(user, "<b>Progress to Critical Mass:</b> <span class='notice'>[overmind.blobs_legit.len]/[overmind.blobwincount].</span>")
|
||||
chemeffectreport(user)
|
||||
typereport(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/blob/proc/chemeffectreport(mob/user)
|
||||
if(overmind)
|
||||
to_chat(user, "<b>Material: <font color=\"[overmind.blob_reagent_datum.color]\">[overmind.blob_reagent_datum.name]</font><span class='notice'>.</span></b>")
|
||||
to_chat(user, "<b>Material Effects:</b> <span class='notice'>[overmind.blob_reagent_datum.analyzerdescdamage]</span>")
|
||||
to_chat(user, "<b>Material Properties:</b> <span class='notice'>[overmind.blob_reagent_datum.analyzerdesceffect]</span><br>")
|
||||
else
|
||||
to_chat(user, "<b>No Material Detected!</b><br>")
|
||||
|
||||
/obj/structure/blob/proc/typereport(mob/user)
|
||||
to_chat(user, "<b>Blob Type:</b> <span class='notice'>[uppertext(initial(name))]</span>")
|
||||
to_chat(user, "<b>Health:</b> <span class='notice'>[obj_integrity]/[max_integrity]</span>")
|
||||
to_chat(user, "<b>Effects:</b> <span class='notice'>[scannerreport()]</span>")
|
||||
|
||||
/obj/structure/blob/attack_animal(mob/living/simple_animal/M)
|
||||
if("blob" in M.faction) //sorry, but you can't kill the blob as a blobbernaut
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/structure/blob/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(damage_amount)
|
||||
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
|
||||
else
|
||||
playsound(src, 'sound/weapons/tap.ogg', 50, 1)
|
||||
if(BURN)
|
||||
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
|
||||
|
||||
/obj/structure/blob/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
damage_amount *= brute_resist
|
||||
if(BURN)
|
||||
damage_amount *= fire_resist
|
||||
if(CLONE)
|
||||
else
|
||||
return 0
|
||||
var/armor_protection = 0
|
||||
if(damage_flag)
|
||||
armor_protection = armor[damage_flag]
|
||||
damage_amount = round(damage_amount * (100 - armor_protection)*0.01, 0.1)
|
||||
if(overmind && damage_flag)
|
||||
damage_amount = overmind.blob_reagent_datum.damage_reaction(src, damage_amount, damage_type, damage_flag)
|
||||
return damage_amount
|
||||
|
||||
/obj/structure/blob/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
. = ..()
|
||||
if(. && obj_integrity > 0)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/blob/obj_destruction(damage_flag)
|
||||
if(overmind)
|
||||
overmind.blob_reagent_datum.death_reaction(src, damage_flag)
|
||||
..()
|
||||
|
||||
/obj/structure/blob/proc/change_to(type, controller)
|
||||
if(!ispath(type))
|
||||
throw EXCEPTION("change_to(): invalid type for blob")
|
||||
return
|
||||
var/obj/structure/blob/B = new type(src.loc, controller)
|
||||
B.creation_action()
|
||||
B.update_icon()
|
||||
B.setDir(dir)
|
||||
qdel(src)
|
||||
return B
|
||||
|
||||
/obj/structure/blob/examine(mob/user)
|
||||
..()
|
||||
var/datum/atom_hud/hud_to_check = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
|
||||
if(user.research_scanner || hud_to_check.hudusers[user])
|
||||
to_chat(user, "<b>Your HUD displays an extensive report...</b><br>")
|
||||
to_chat(user, "<b>Progress to Critical Mass:</b> <span class='notice'>[overmind.blobs_legit.len]/[overmind.blobwincount].</span>")
|
||||
chemeffectreport(user)
|
||||
typereport(user)
|
||||
else
|
||||
if(isobserver(user))
|
||||
to_chat(user, "<b>Progress to Critical Mass:</b> <span class='notice'>[overmind.blobs_legit.len]/[overmind.blobwincount].</span>")
|
||||
to_chat(user, "It seems to be made of [get_chem_name()].")
|
||||
|
||||
/obj/structure/blob/proc/scannerreport()
|
||||
return "A generic blob. Looks like someone forgot to override this proc, adminhelp this."
|
||||
|
||||
/obj/structure/blob/proc/get_chem_name()
|
||||
if(overmind)
|
||||
return overmind.blob_reagent_datum.name
|
||||
return "an unknown variant"
|
||||
|
||||
/obj/structure/blob/normal
|
||||
name = "normal blob"
|
||||
icon_state = "blob"
|
||||
light_range = 0
|
||||
obj_integrity = 21 //doesn't start at full health
|
||||
max_integrity = 25
|
||||
health_regen = 1
|
||||
brute_resist = 0.25
|
||||
|
||||
/obj/structure/blob/normal/scannerreport()
|
||||
if(obj_integrity <= 15)
|
||||
return "Currently weak to brute damage."
|
||||
return "N/A"
|
||||
|
||||
/obj/structure/blob/normal/update_icon()
|
||||
..()
|
||||
if(obj_integrity <= 15)
|
||||
icon_state = "blob_damaged"
|
||||
name = "fragile blob"
|
||||
desc = "A thin lattice of slightly twitching tendrils."
|
||||
brute_resist = 0.5
|
||||
else
|
||||
icon_state = "blob"
|
||||
name = "blob"
|
||||
desc = "A thick wall of writhing tendrils."
|
||||
brute_resist = 0.25
|
||||
@@ -1,85 +0,0 @@
|
||||
// cellular emporium
|
||||
// The place where changelings go to buy their biological weaponry.
|
||||
|
||||
/datum/cellular_emporium
|
||||
var/name = "cellular emporium"
|
||||
var/datum/antagonist/changeling/changeling
|
||||
|
||||
/datum/cellular_emporium/New(my_changeling)
|
||||
. = ..()
|
||||
changeling = my_changeling
|
||||
|
||||
/datum/cellular_emporium/Destroy()
|
||||
changeling = null
|
||||
. = ..()
|
||||
|
||||
/datum/cellular_emporium/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "cellular_emporium", name, 900, 480, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/datum/cellular_emporium/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
var/can_readapt = changeling.canrespec
|
||||
var/genetic_points_remaining = changeling.geneticpoints
|
||||
var/absorbed_dna_count = changeling.absorbedcount
|
||||
|
||||
data["can_readapt"] = can_readapt
|
||||
data["genetic_points_remaining"] = genetic_points_remaining
|
||||
data["absorbed_dna_count"] = absorbed_dna_count
|
||||
|
||||
var/list/abilities = list()
|
||||
|
||||
for(var/path in changeling.all_powers)
|
||||
var/obj/effect/proc_holder/changeling/ability = path
|
||||
|
||||
var/dna_cost = initial(ability.dna_cost)
|
||||
if(dna_cost <= 0)
|
||||
continue
|
||||
|
||||
var/list/AL = list()
|
||||
AL["name"] = initial(ability.name)
|
||||
AL["desc"] = initial(ability.desc)
|
||||
AL["helptext"] = initial(ability.helptext)
|
||||
AL["owned"] = changeling.has_sting(ability)
|
||||
var/req_dna = initial(ability.req_dna)
|
||||
AL["dna_cost"] = dna_cost
|
||||
AL["can_purchase"] = ((req_dna <= absorbed_dna_count) && (dna_cost <= genetic_points_remaining))
|
||||
|
||||
abilities += list(AL)
|
||||
|
||||
data["abilities"] = abilities
|
||||
|
||||
return data
|
||||
|
||||
/datum/cellular_emporium/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("readapt")
|
||||
if(changeling.canrespec)
|
||||
changeling.readapt()
|
||||
if("evolve")
|
||||
var/sting_name = params["name"]
|
||||
changeling.purchase_power(sting_name)
|
||||
|
||||
/datum/action/innate/cellular_emporium
|
||||
name = "Cellular Emporium"
|
||||
icon_icon = 'icons/obj/drinks.dmi'
|
||||
button_icon_state = "changelingsting"
|
||||
background_icon_state = "bg_alien"
|
||||
var/datum/cellular_emporium/cellular_emporium
|
||||
|
||||
/datum/action/innate/cellular_emporium/New(our_target)
|
||||
. = ..()
|
||||
button.name = name
|
||||
if(istype(our_target, /datum/cellular_emporium))
|
||||
cellular_emporium = our_target
|
||||
else
|
||||
throw EXCEPTION("cellular_emporium action created with non emporium")
|
||||
|
||||
/datum/action/innate/cellular_emporium/Activate()
|
||||
cellular_emporium.ui_interact(owner)
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Don't use the apostrophe in name or desc. Causes script errors.
|
||||
* TODO: combine atleast some of the functionality with /proc_holder/spell
|
||||
*/
|
||||
|
||||
/obj/effect/proc_holder/changeling
|
||||
panel = "Changeling"
|
||||
name = "Prototype Sting"
|
||||
desc = "" // Fluff
|
||||
var/helptext = "" // Details
|
||||
var/chemical_cost = 0 // negative chemical cost is for passive abilities (chemical glands)
|
||||
var/dna_cost = -1 //cost of the sting in dna points. 0 = auto-purchase, -1 = cannot be purchased
|
||||
var/req_dna = 0 //amount of dna needed to use this ability. Changelings always have atleast 1
|
||||
var/req_human = 0 //if you need to be human to use this ability
|
||||
var/req_stat = CONSCIOUS // CONSCIOUS, UNCONSCIOUS or DEAD
|
||||
var/always_keep = 0 // important for abilities like revive that screw you if you lose them.
|
||||
var/ignores_fakedeath = FALSE // usable with the FAKEDEATH flag
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_purchase(mob/user, is_respec)
|
||||
if(!is_respec)
|
||||
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, name)
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/on_refund(mob/user)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/changeling/Click()
|
||||
var/mob/user = usr
|
||||
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/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(sting_action(user, target))
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]"))
|
||||
sting_feedback(user, target)
|
||||
c.chem_charges -= chemical_cost
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_action(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/proc/sting_feedback(mob/user, mob/target)
|
||||
return 0
|
||||
|
||||
//Fairly important to remember to return 1 on success >.<
|
||||
/obj/effect/proc_holder/changeling/proc/can_sting(mob/user, mob/target)
|
||||
if(!ishuman(user) && !ismonkey(user)) //typecast everything from mob to carbon from this point onwards
|
||||
return 0
|
||||
if(req_human && !ishuman(user))
|
||||
to_chat(user, "<span class='warning'>We cannot do that in this form!</span>")
|
||||
return 0
|
||||
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
|
||||
if(c.absorbedcount < req_dna)
|
||||
to_chat(user, "<span class='warning'>We require at least [req_dna] sample\s of compatible DNA.</span>")
|
||||
return 0
|
||||
if(req_stat < user.stat)
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
if((user.status_flags & FAKEDEATH) && (!ignores_fakedeath))
|
||||
to_chat(user, "<span class='warning'>We are incapacitated.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//used in /mob/Stat()
|
||||
/obj/effect/proc_holder/changeling/proc/can_be_used_by(mob/user)
|
||||
if(!user || QDELETED(user))
|
||||
return 0
|
||||
if(!ishuman(user) && !ismonkey(user))
|
||||
return 0
|
||||
if(req_human && !ishuman(user))
|
||||
return 0
|
||||
return 1
|
||||
@@ -1,113 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/absorbDNA
|
||||
name = "Absorb DNA"
|
||||
desc = "Absorb the DNA of our victim."
|
||||
chemical_cost = 0
|
||||
dna_cost = 0
|
||||
req_human = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/can_sting(mob/living/carbon/user)
|
||||
if(!..())
|
||||
return
|
||||
|
||||
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
|
||||
|
||||
if(!user.pulling || !iscarbon(user.pulling))
|
||||
to_chat(user, "<span class='warning'>We must be grabbing a creature to absorb them!</span>")
|
||||
return
|
||||
if(user.grab_state <= GRAB_NECK)
|
||||
to_chat(user, "<span class='warning'>We must have a tighter grip to absorb this creature!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/target = user.pulling
|
||||
return changeling.can_absorb_dna(target)
|
||||
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/absorbDNA/sting_action(mob/user)
|
||||
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)
|
||||
switch(i)
|
||||
if(1)
|
||||
to_chat(user, "<span class='notice'>This creature is compatible. We must hold still...</span>")
|
||||
if(2)
|
||||
user.visible_message("<span class='warning'>[user] extends a proboscis!</span>", "<span class='notice'>We extend a proboscis.</span>")
|
||||
if(3)
|
||||
user.visible_message("<span class='danger'>[user] stabs [target] with the proboscis!</span>", "<span class='notice'>We stab [target] with the proboscis.</span>")
|
||||
to_chat(target, "<span class='userdanger'>You feel a sharp stabbing pain!</span>")
|
||||
target.take_overall_damage(40)
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "[i]"))
|
||||
if(!do_mob(user, target, 150))
|
||||
to_chat(user, "<span class='warning'>Our absorption of [target] has been interrupted!</span>")
|
||||
changeling.isabsorbing = 0
|
||||
return
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("Absorb DNA", "4"))
|
||||
user.visible_message("<span class='danger'>[user] sucks the fluids from [target]!</span>", "<span class='notice'>We have absorbed [target].</span>")
|
||||
to_chat(target, "<span class='userdanger'>You are absorbed by the changeling!</span>")
|
||||
|
||||
if(!changeling.has_dna(target.dna))
|
||||
changeling.add_new_profile(target)
|
||||
|
||||
if(user.nutrition < NUTRITION_LEVEL_WELL_FED)
|
||||
user.nutrition = min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)
|
||||
|
||||
if(target.mind)//if the victim has got a mind
|
||||
// Absorb a lizard, speak Draconic.
|
||||
user.copy_known_languages_from(target)
|
||||
|
||||
target.mind.show_memory(user, 0) //I can read your mind, kekeke. Output all their notes.
|
||||
|
||||
//Some of target's recent speech, so the changeling can attempt to imitate them better.
|
||||
//Recent as opposed to all because rounds tend to have a LOT of text.
|
||||
var/list/recent_speech = list()
|
||||
|
||||
var/list/say_log = target.logging[INDIVIDUAL_SAY_LOG]
|
||||
|
||||
if(LAZYLEN(say_log) > LING_ABSORB_RECENT_SPEECH)
|
||||
recent_speech = say_log.Copy(say_log.len-LING_ABSORB_RECENT_SPEECH+1,0) //0 so len-LING_ARS+1 to end of list
|
||||
else
|
||||
for(var/spoken_memory in say_log)
|
||||
if(recent_speech.len >= LING_ABSORB_RECENT_SPEECH)
|
||||
break
|
||||
recent_speech[spoken_memory] = say_log[spoken_memory]
|
||||
|
||||
if(recent_speech.len)
|
||||
changeling.antag_memory += "<B>Some of [target]'s speech patterns, we should study these to better impersonate them!</B><br>"
|
||||
to_chat(user, "<span class='boldnotice'>Some of [target]'s speech patterns, we should study these to better impersonate them!</span>")
|
||||
for(var/spoken_memory in recent_speech)
|
||||
changeling.antag_memory += "\"[recent_speech[spoken_memory]]\"<br>"
|
||||
to_chat(user, "<span class='notice'>\"[recent_speech[spoken_memory]]\"</span>")
|
||||
changeling.antag_memory += "<B>We have no more knowledge of [target]'s speech patterns.</B><br>"
|
||||
to_chat(user, "<span class='boldnotice'>We have no more knowledge of [target]'s speech patterns.</span>")
|
||||
|
||||
|
||||
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)
|
||||
|
||||
changeling.isabsorbing = 0
|
||||
changeling.canrespec = 1
|
||||
|
||||
target.death(0)
|
||||
target.Drain()
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
//Absorbs the target DNA.
|
||||
//datum/changeling/proc/absorb_dna(mob/living/carbon/T, mob/user)
|
||||
|
||||
//datum/changeling/proc/store_dna(datum/dna/new_dna, mob/user)
|
||||
@@ -1,21 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/adrenaline
|
||||
name = "Adrenaline Sacs"
|
||||
desc = "We evolve additional sacs of adrenaline throughout our body."
|
||||
helptext = "Removes all stuns instantly and adds a short-term reduction in further stuns. Can be used while unconscious. Continued use poisons the body."
|
||||
chemical_cost = 30
|
||||
dna_cost = 2
|
||||
req_human = 1
|
||||
req_stat = UNCONSCIOUS
|
||||
|
||||
//Recover from stuns.
|
||||
/obj/effect/proc_holder/changeling/adrenaline/sting_action(mob/living/user)
|
||||
to_chat(user, "<span class='notice'>Energy rushes through us.[user.lying ? " We arise." : ""]</span>")
|
||||
user.SetSleeping(0)
|
||||
user.SetUnconscious(0)
|
||||
user.SetStun(0)
|
||||
user.SetKnockdown(0)
|
||||
user.reagents.add_reagent("changelingAdrenaline", 10)
|
||||
user.reagents.add_reagent("changelingAdrenaline2", 2) //For a really quick burst of speed
|
||||
user.adjustStaminaLoss(-75)
|
||||
return TRUE
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
//Augmented Eyesight: Gives you x-ray vision or protection from flashes. Also, high DNA cost because of how powerful it is.
|
||||
//Possible todo: make a custom message for directing a penlight/flashlight at the eyes - not sure what would display though.
|
||||
|
||||
/obj/effect/proc_holder/changeling/augmented_eyesight
|
||||
name = "Augmented Eyesight"
|
||||
desc = "Creates heat receptors in our eyes and dramatically increases light sensing ability, or protects your vision from flashes."
|
||||
helptext = "Grants us thermal vision or flash protection. We will become a lot more vulnerable to flash-based devices while thermal vision is active."
|
||||
chemical_cost = 0
|
||||
dna_cost = 2 //Would be 1 without thermal vision
|
||||
active = FALSE
|
||||
|
||||
/obj/effect/proc_holder/changeling/augmented_eyesight/on_purchase(mob/user) //The ability starts inactive, so we should be protected from flashes.
|
||||
var/obj/item/organ/eyes/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
if (E)
|
||||
E.flash_protect = 2 //Adjust the user's eyes' flash protection
|
||||
to_chat(user, "We adjust our eyes to protect them from bright lights.")
|
||||
else
|
||||
to_chat(user, "We can't adjust our eyes if we don't have any!")
|
||||
|
||||
/obj/effect/proc_holder/changeling/augmented_eyesight/sting_action(mob/living/carbon/human/user)
|
||||
if(!istype(user))
|
||||
return
|
||||
var/obj/item/organ/eyes/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(E)
|
||||
if(!active)
|
||||
E.sight_flags |= SEE_MOBS | SEE_OBJS | SEE_TURFS //Add sight flags to the user's eyes
|
||||
E.flash_protect = -1 //Adjust the user's eyes' flash protection
|
||||
to_chat(user, "We adjust our eyes to sense prey through walls.")
|
||||
active = TRUE //Defined in code/modules/spells/spell.dm
|
||||
else
|
||||
E.sight_flags ^= SEE_MOBS | SEE_OBJS | SEE_TURFS //Remove sight flags from the user's eyes
|
||||
E.flash_protect = 2 //Adjust the user's eyes' flash protection
|
||||
to_chat(user, "We adjust our eyes to protect them from bright lights.")
|
||||
active = FALSE
|
||||
user.update_sight()
|
||||
else
|
||||
to_chat(user, "We can't adjust our eyes if we don't have any!")
|
||||
|
||||
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/augmented_eyesight/on_refund(mob/user) //Get rid of x-ray vision and flash protection when the user refunds this ability
|
||||
var/obj/item/organ/eyes/E = user.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(E)
|
||||
if (active)
|
||||
E.sight_flags ^= SEE_MOBS | SEE_OBJS | SEE_TURFS
|
||||
else
|
||||
E.flash_protect = 0
|
||||
user.update_sight()
|
||||
@@ -1,81 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/biodegrade
|
||||
name = "Biodegrade"
|
||||
desc = "Dissolves restraints or other objects preventing free movement."
|
||||
helptext = "This is obvious to nearby people, and can destroy standard restraints and closets."
|
||||
chemical_cost = 30 //High cost to prevent spam
|
||||
dna_cost = 2
|
||||
req_human = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/sting_action(mob/living/carbon/human/user)
|
||||
var/used = FALSE // only one form of shackles removed per use
|
||||
if(!user.restrained() && isopenturf(user.loc))
|
||||
to_chat(user, "<span class='warning'>We are already free!</span>")
|
||||
return 0
|
||||
|
||||
if(user.handcuffed)
|
||||
var/obj/O = user.get_item_by_slot(slot_handcuffed)
|
||||
if(!istype(O))
|
||||
return 0
|
||||
user.visible_message("<span class='warning'>[user] vomits a glob of acid on [user.p_their()] [O]!</span>", \
|
||||
"<span class='warning'>We vomit acidic ooze onto our restraints!</span>")
|
||||
|
||||
addtimer(CALLBACK(src, .proc/dissolve_handcuffs, user, O), 30)
|
||||
used = TRUE
|
||||
|
||||
if(user.wear_suit && user.wear_suit.breakouttime && !used)
|
||||
var/obj/item/clothing/suit/S = user.get_item_by_slot(slot_wear_suit)
|
||||
if(!istype(S))
|
||||
return 0
|
||||
user.visible_message("<span class='warning'>[user] vomits a glob of acid across the front of [user.p_their()] [S]!</span>", \
|
||||
"<span class='warning'>We vomit acidic ooze onto our straight jacket!</span>")
|
||||
addtimer(CALLBACK(src, .proc/dissolve_straightjacket, user, S), 30)
|
||||
used = TRUE
|
||||
|
||||
|
||||
if(istype(user.loc, /obj/structure/closet) && !used)
|
||||
var/obj/structure/closet/C = user.loc
|
||||
if(!istype(C))
|
||||
return 0
|
||||
C.visible_message("<span class='warning'>[C]'s hinges suddenly begin to melt and run!</span>")
|
||||
to_chat(user, "<span class='warning'>We vomit acidic goop onto the interior of [C]!</span>")
|
||||
addtimer(CALLBACK(src, .proc/open_closet, user, C), 70)
|
||||
used = TRUE
|
||||
|
||||
if(istype(user.loc, /obj/structure/spider/cocoon) && !used)
|
||||
var/obj/structure/spider/cocoon/C = user.loc
|
||||
if(!istype(C))
|
||||
return 0
|
||||
C.visible_message("<span class='warning'>[src] shifts and starts to fall apart!</span>")
|
||||
to_chat(user, "<span class='warning'>We secrete acidic enzymes from our skin and begin melting our cocoon...</span>")
|
||||
addtimer(CALLBACK(src, .proc/dissolve_cocoon, user, C), 25) //Very short because it's just webs
|
||||
used = TRUE
|
||||
|
||||
return used
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_handcuffs(mob/living/carbon/human/user, obj/O)
|
||||
if(O && user.handcuffed == O)
|
||||
user.visible_message("<span class='warning'>[O] dissolve[O.gender==PLURAL?"":"s"] into a puddle of sizzling goop.</span>")
|
||||
new /obj/effect/decal/cleanable/greenglow(O.drop_location())
|
||||
qdel(O)
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_straightjacket(mob/living/carbon/human/user, obj/S)
|
||||
if(S && user.wear_suit == S)
|
||||
user.visible_message("<span class='warning'>[S] dissolves into a puddle of sizzling goop.</span>")
|
||||
new /obj/effect/decal/cleanable/greenglow(S.drop_location())
|
||||
qdel(S)
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/open_closet(mob/living/carbon/human/user, obj/structure/closet/C)
|
||||
if(C && user.loc == C)
|
||||
C.visible_message("<span class='warning'>[C]'s door breaks and opens!</span>")
|
||||
new /obj/effect/decal/cleanable/greenglow(C.drop_location())
|
||||
C.welded = FALSE
|
||||
C.locked = FALSE
|
||||
C.broken = TRUE
|
||||
C.open()
|
||||
to_chat(user, "<span class='warning'>We open the container restraining us!</span>")
|
||||
|
||||
/obj/effect/proc_holder/changeling/biodegrade/proc/dissolve_cocoon(mob/living/carbon/human/user, obj/structure/spider/cocoon/C)
|
||||
if(C && user.loc == C)
|
||||
new /obj/effect/decal/cleanable/greenglow(C.drop_location())
|
||||
qdel(C) //The cocoon's destroy will move the changeling outside of it without interference
|
||||
to_chat(user, "<span class='warning'>We dissolve the cocoon!</span>")
|
||||
@@ -1,25 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/chameleon_skin
|
||||
name = "Chameleon Skin"
|
||||
desc = "Our skin pigmentation rapidly changes to suit our current environment."
|
||||
helptext = "Allows us to become invisible after a few seconds of standing still. Can be toggled on and off."
|
||||
dna_cost = 2
|
||||
chemical_cost = 25
|
||||
req_human = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/chameleon_skin/sting_action(mob/user)
|
||||
var/mob/living/carbon/human/H = user //SHOULD always be human, because req_human = 1
|
||||
if(!istype(H)) // req_human could be done in can_sting stuff.
|
||||
return
|
||||
var/datum/mutation/human/HM = GLOB.mutations_list[CHAMELEON]
|
||||
if(HM in H.dna.mutations)
|
||||
HM.force_lose(H)
|
||||
else
|
||||
HM.force_give(H)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/chameleon_skin/on_refund(mob/user)
|
||||
if(user.has_dna())
|
||||
var/mob/living/carbon/C = user
|
||||
var/datum/mutation/human/HM = GLOB.mutations_list[CHAMELEON]
|
||||
if(HM in C.dna.mutations)
|
||||
HM.force_lose(C)
|
||||
@@ -1,22 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/digitalcamo
|
||||
name = "Digital Camouflage"
|
||||
desc = "By evolving the ability to distort our form and proprotions, we defeat common altgorithms used to detect lifeforms on cameras."
|
||||
helptext = "We cannot be tracked by camera or seen by AI units while using this skill. However, humans looking at us will find us... uncanny."
|
||||
dna_cost = 1
|
||||
|
||||
//Prevents AIs tracking you but makes you easily detectable to the human-eye.
|
||||
/obj/effect/proc_holder/changeling/digitalcamo/sting_action(mob/user)
|
||||
|
||||
if(user.digitalcamo)
|
||||
to_chat(user, "<span class='notice'>We return to normal.</span>")
|
||||
user.digitalinvis = 0
|
||||
user.digitalcamo = 0
|
||||
else
|
||||
to_chat(user, "<span class='notice'>We distort our form to hide from the AI</span>")
|
||||
user.digitalcamo = 1
|
||||
user.digitalinvis = 1
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/digitalcamo/on_refund(mob/user)
|
||||
user.digitalcamo = 0
|
||||
user.digitalinvis = 0
|
||||
@@ -1,37 +0,0 @@
|
||||
/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,19 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/fleshmend
|
||||
name = "Fleshmend"
|
||||
desc = "Our flesh rapidly regenerates, healing our burns, bruises, and shortness of breath. Functions while unconscious."
|
||||
helptext = "If we are on fire, the healing effect will not function. Does not regrow limbs or restore lost blood."
|
||||
chemical_cost = 20
|
||||
dna_cost = 2
|
||||
req_stat = UNCONSCIOUS
|
||||
|
||||
//Starts healing you every second for 10 seconds.
|
||||
//Can be used whilst unconscious.
|
||||
/obj/effect/proc_holder/changeling/fleshmend/sting_action(mob/living/user)
|
||||
if(user.has_status_effect(STATUS_EFFECT_FLESHMEND))
|
||||
to_chat(user, "<span class='warning'>We are already fleshmending!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>We begin to heal rapidly.</span>")
|
||||
user.apply_status_effect(STATUS_EFFECT_FLESHMEND)
|
||||
return TRUE
|
||||
|
||||
//Check buffs.dm for the fleshmend status effect code
|
||||
@@ -1,40 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/headcrab
|
||||
name = "Last Resort"
|
||||
desc = "We sacrifice our current body in a moment of need, placing us in control of a vessel."
|
||||
helptext = "We will be placed in control of a small, fragile creature. We may attack a corpse like this to plant an egg which will slowly mature into a new form for us."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
req_human = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/headcrab/sting_action(mob/user)
|
||||
set waitfor = FALSE
|
||||
if(alert("Are we sure we wish to kill ourself and create a headslug?",,"Yes", "No") == "No")
|
||||
return
|
||||
var/datum/mind/M = user.mind
|
||||
var/list/organs = user.getorganszone("head", 1)
|
||||
|
||||
for(var/obj/item/organ/I in organs)
|
||||
I.Remove(user, 1)
|
||||
|
||||
explosion(get_turf(user),0,0,2,0,silent=1)
|
||||
for(var/mob/living/carbon/human/H in range(2,user))
|
||||
to_chat(H, "<span class='userdanger'>You are blinded by a shower of blood!</span>")
|
||||
H.Stun(20)
|
||||
H.blur_eyes(20)
|
||||
H.adjust_eye_damage(5)
|
||||
H.confused += 3
|
||||
for(var/mob/living/silicon/S in range(2,user))
|
||||
to_chat(S, "<span class='userdanger'>Your sensors are disabled by a shower of blood!</span>")
|
||||
S.Knockdown(60)
|
||||
var/turf = get_turf(user)
|
||||
user.gib()
|
||||
. = TRUE
|
||||
sleep(5) // So it's not killed in explosion
|
||||
var/mob/living/simple_animal/hostile/headcrab/crab = new(turf)
|
||||
for(var/obj/item/organ/I in organs)
|
||||
I.forceMove(crab)
|
||||
crab.origin = M
|
||||
if(crab.origin)
|
||||
crab.origin.active = 1
|
||||
crab.origin.transfer_to(crab)
|
||||
to_chat(crab, "<span class='warning'>You burst out of the remains of your former body in a shower of gore!</span>")
|
||||
@@ -1,93 +0,0 @@
|
||||
//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 +0,0 @@
|
||||
/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
|
||||
@@ -1,15 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/lesserform
|
||||
name = "Lesser Form"
|
||||
desc = "We debase ourselves and become lesser. We become a monkey."
|
||||
chemical_cost = 5
|
||||
dna_cost = 1
|
||||
req_human = 1
|
||||
|
||||
//Transform into a monkey.
|
||||
/obj/effect/proc_holder/changeling/lesserform/sting_action(mob/living/carbon/human/user)
|
||||
if(!user || user.notransform)
|
||||
return 0
|
||||
to_chat(user, "<span class='warning'>Our genes cry out!</span>")
|
||||
|
||||
user.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
|
||||
return TRUE
|
||||
@@ -1,70 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/linglink
|
||||
name = "Hivemind Link"
|
||||
desc = "Link your victim's mind into the hivemind for personal interrogation."
|
||||
chemical_cost = 0
|
||||
dna_cost = 0
|
||||
req_human = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/linglink/can_sting(mob/living/carbon/user)
|
||||
if(!..())
|
||||
return
|
||||
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
|
||||
if(!user.pulling)
|
||||
to_chat(user, "<span class='warning'>We must be tightly grabbing a creature to link with them!</span>")
|
||||
return
|
||||
if(!iscarbon(user.pulling))
|
||||
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.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(target)
|
||||
|
||||
/obj/effect/proc_holder/changeling/linglink/sting_action(mob/user)
|
||||
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)
|
||||
switch(i)
|
||||
if(1)
|
||||
to_chat(user, "<span class='notice'>This creature is compatible. We must hold still...</span>")
|
||||
if(2)
|
||||
to_chat(user, "<span class='notice'>We stealthily stab [target] with a minor proboscis...</span>")
|
||||
to_chat(target, "<span class='userdanger'>You experience a stabbing sensation and your ears begin to ring...</span>")
|
||||
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/mi in GLOB.mob_list)
|
||||
var/mob/M = mi
|
||||
if(M.lingcheck() == LINGHIVE_LING)
|
||||
to_chat(M, "<i><font color=#800080>We can sense a foreign presence in the hivemind...</font></i>")
|
||||
target.mind.linglink = 1
|
||||
target.say(":g AAAAARRRRGGGGGHHHHH!!")
|
||||
to_chat(target, "<font color=#800040><span class='boldannounce'>You can now communicate in the changeling hivemind, say \":g message\" to communicate!</span>")
|
||||
target.reagents.add_reagent("salbutamol", 40) // So they don't choke to death while you interrogate them
|
||||
sleep(1800)
|
||||
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]", "[i]"))
|
||||
if(!do_mob(user, target, 20))
|
||||
to_chat(user, "<span class='warning'>Our link with [target] has ended!</span>")
|
||||
changeling.islinking = 0
|
||||
target.mind.linglink = 0
|
||||
return
|
||||
|
||||
changeling.islinking = 0
|
||||
target.mind.linglink = 0
|
||||
to_chat(user, "<span class='notice'>You cannot sustain the connection any longer, your victim fades from the hivemind</span>")
|
||||
to_chat(target, "<span class='userdanger'>The link cannot be sustained any longer, your connection to the hivemind has faded!</span>")
|
||||
@@ -1,27 +0,0 @@
|
||||
/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
|
||||
@@ -1,509 +0,0 @@
|
||||
/*
|
||||
Changeling Mutations! ~By Miauw (ALL OF IT :V)
|
||||
Contains:
|
||||
Arm Blade
|
||||
Space Suit
|
||||
Shield
|
||||
Armor
|
||||
Tentacles
|
||||
*/
|
||||
|
||||
|
||||
//Parent to shields and blades because muh copypasted code.
|
||||
/obj/effect/proc_holder/changeling/weapon
|
||||
name = "Organic Weapon"
|
||||
desc = "Go tell a coder if you see this"
|
||||
helptext = "Yell at Miauw and/or Perakp"
|
||||
chemical_cost = 1000
|
||||
dna_cost = -1
|
||||
|
||||
var/silent = FALSE
|
||||
var/weapon_type
|
||||
var/weapon_name_simple
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/try_to_sting(mob/user, mob/target)
|
||||
for(var/obj/item/I in user.held_items)
|
||||
if(check_weapon(user, I))
|
||||
return
|
||||
..(user, target)
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/proc/check_weapon(mob/user, obj/item/hand_item)
|
||||
if(istype(hand_item, weapon_type))
|
||||
user.temporarilyRemoveItemFromInventory(hand_item, TRUE) //DROPDEL_1 will delete the item
|
||||
if(!silent)
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
user.visible_message("<span class='warning'>With a sickening crunch, [user] reforms their [weapon_name_simple] into an arm!</span>", "<span class='notice'>We assimilate the [weapon_name_simple] back into our body.</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
user.update_inv_hands()
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/sting_action(mob/living/user)
|
||||
var/obj/item/held = user.get_active_held_item()
|
||||
if(held && !user.dropItemToGround(held))
|
||||
to_chat(user, "<span class='warning'>[held] is stuck to your hand, you cannot grow a [weapon_name_simple] over it!</span>")
|
||||
return
|
||||
var/limb_regen = 0
|
||||
if(user.active_hand_index % 2 == 0) //we regen the arm before changing it into the weapon
|
||||
limb_regen = user.regenerate_limb("r_arm", 1)
|
||||
else
|
||||
limb_regen = user.regenerate_limb("l_arm", 1)
|
||||
if(limb_regen)
|
||||
user.visible_message("<span class='warning'>[user]'s missing arm reforms, making a loud, grotesque sound!</span>", "<span class='userdanger'>Your arm regrows, making a loud, crunchy sound and giving you great pain!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
user.emote("scream")
|
||||
var/obj/item/W = new weapon_type(user, silent)
|
||||
user.put_in_hands(W)
|
||||
if(!silent)
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
return W
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/on_refund(mob/user)
|
||||
for(var/obj/item/I in user.held_items)
|
||||
check_weapon(user, I)
|
||||
|
||||
|
||||
//Parent to space suits and armor.
|
||||
/obj/effect/proc_holder/changeling/suit
|
||||
name = "Organic Suit"
|
||||
desc = "Go tell a coder if you see this"
|
||||
helptext = "Yell at Miauw and/or Perakp"
|
||||
chemical_cost = 1000
|
||||
dna_cost = -1
|
||||
|
||||
var/helmet_type = /obj/item
|
||||
var/suit_type = /obj/item
|
||||
var/suit_name_simple = " "
|
||||
var/helmet_name_simple = " "
|
||||
var/recharge_slowdown = 0
|
||||
var/blood_on_castoff = 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/suit/try_to_sting(mob/user, mob/target)
|
||||
if(check_suit(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
..(H, target)
|
||||
|
||||
//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/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!ishuman(user) || !changeling)
|
||||
return 1
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H.wear_suit, suit_type) || istype(H.head, helmet_type))
|
||||
H.visible_message("<span class='warning'>[H] casts off their [suit_name_simple]!</span>", "<span class='warning'>We cast off our [suit_name_simple].</span>", "<span class='italics'>You hear the organic matter ripping and tearing!</span>")
|
||||
H.temporarilyRemoveItemFromInventory(H.head, TRUE) //The qdel on dropped() takes care of it
|
||||
H.temporarilyRemoveItemFromInventory(H.wear_suit, TRUE)
|
||||
H.update_inv_wear_suit()
|
||||
H.update_inv_head()
|
||||
H.update_hair()
|
||||
|
||||
if(blood_on_castoff)
|
||||
H.add_splatter_floor()
|
||||
playsound(H.loc, 'sound/effects/splat.ogg', 50, 1) //So real sounds
|
||||
|
||||
changeling.chem_recharge_slowdown -= recharge_slowdown
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/suit/on_refund(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
check_suit(H)
|
||||
|
||||
/obj/effect/proc_holder/changeling/suit/sting_action(mob/living/carbon/human/user)
|
||||
if(!user.canUnEquip(user.wear_suit))
|
||||
to_chat(user, "\the [user.wear_suit] is stuck to your body, you cannot grow a [suit_name_simple] over it!")
|
||||
return
|
||||
if(!user.canUnEquip(user.head))
|
||||
to_chat(user, "\the [user.head] is stuck on your head, you cannot grow a [helmet_name_simple] over it!")
|
||||
return
|
||||
|
||||
user.dropItemToGround(user.head)
|
||||
user.dropItemToGround(user.wear_suit)
|
||||
|
||||
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/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
changeling.chem_recharge_slowdown += recharge_slowdown
|
||||
return TRUE
|
||||
|
||||
|
||||
//fancy headers yo
|
||||
/***************************************\
|
||||
|***************ARM BLADE***************|
|
||||
\***************************************/
|
||||
/obj/effect/proc_holder/changeling/weapon/arm_blade
|
||||
name = "Arm Blade"
|
||||
desc = "We reform one of our arms into a deadly blade."
|
||||
helptext = "We may retract our armblade in the same manner as we form it. Cannot be used while in lesser form."
|
||||
chemical_cost = 20
|
||||
dna_cost = 2
|
||||
req_human = 1
|
||||
weapon_type = /obj/item/melee/arm_blade
|
||||
weapon_name_simple = "blade"
|
||||
|
||||
/obj/item/melee/arm_blade
|
||||
name = "arm blade"
|
||||
desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "arm_blade"
|
||||
item_state = "arm_blade"
|
||||
lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
|
||||
flags_1 = ABSTRACT_1 | NODROP_1 | DROPDEL_1
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
force = 25
|
||||
throwforce = 0 //Just to be on the safe side
|
||||
throw_range = 0
|
||||
throw_speed = 0
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
sharpness = IS_SHARP
|
||||
var/can_drop = FALSE
|
||||
|
||||
/obj/item/melee/arm_blade/Initialize(mapload,silent,synthetic)
|
||||
. = ..()
|
||||
if(ismob(loc) && !silent)
|
||||
loc.visible_message("<span class='warning'>A grotesque blade forms around [loc.name]\'s arm!</span>", "<span class='warning'>Our arm twists and mutates, transforming it into a deadly blade.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
if(synthetic)
|
||||
can_drop = TRUE
|
||||
|
||||
/obj/item/melee/arm_blade/afterattack(atom/target, mob/user, proximity)
|
||||
if(!proximity)
|
||||
return
|
||||
if(istype(target, /obj/structure/table))
|
||||
var/obj/structure/table/T = target
|
||||
T.deconstruct(FALSE)
|
||||
|
||||
else if(istype(target, /obj/machinery/computer))
|
||||
var/obj/machinery/computer/C = target
|
||||
C.attack_alien(user) //muh copypasta
|
||||
|
||||
else if(istype(target, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/A = target
|
||||
|
||||
if(!A.requiresID() || A.allowed(user)) //This is to prevent stupid shit like hitting a door with an arm blade, the door opening because you have acces and still getting a "the airlocks motors resist our efforts to force it" message.
|
||||
return
|
||||
if(A.locked)
|
||||
to_chat(user, "<span class='warning'>The airlock's bolts prevent it from being forced!</span>")
|
||||
return
|
||||
|
||||
if(A.hasPower())
|
||||
user.visible_message("<span class='warning'>[user] jams [src] into the airlock and starts prying it open!</span>", "<span class='warning'>We start forcing the airlock open.</span>", \
|
||||
"<span class='italics'>You hear a metal screeching sound.</span>")
|
||||
playsound(A, 'sound/machines/airlock_alien_prying.ogg', 100, 1)
|
||||
if(!do_after(user, 100, target = A))
|
||||
return
|
||||
//user.say("Heeeeeeeeeerrre's Johnny!")
|
||||
user.visible_message("<span class='warning'>[user] forces the airlock to open with their [src]!</span>", "<span class='warning'>We force the airlock to open.</span>", \
|
||||
"<span class='italics'>You hear a metal screeching sound.</span>")
|
||||
A.open(2)
|
||||
|
||||
/obj/item/melee/arm_blade/dropped(mob/user)
|
||||
..()
|
||||
if(can_drop)
|
||||
new /obj/item/melee/synthetic_arm_blade(get_turf(user))
|
||||
|
||||
/***************************************\
|
||||
|***********COMBAT TENTACLES*************|
|
||||
\***************************************/
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/tentacle
|
||||
name = "Tentacle"
|
||||
desc = "We ready a tentacle to grab items or victims with."
|
||||
helptext = "We can use it once to retrieve a distant item. If used on living creatures, the effect depends on the intent: \
|
||||
Help will simply drag them closer, Disarm will grab whatever they're holding instead of them, Grab will put the victim in our hold after catching it, \
|
||||
and Harm will stun it, and stab it if we're also holding a sharp weapon. Cannot be used while in lesser form."
|
||||
chemical_cost = 10
|
||||
dna_cost = 2
|
||||
req_human = 1
|
||||
weapon_type = /obj/item/gun/magic/tentacle
|
||||
weapon_name_simple = "tentacle"
|
||||
silent = TRUE
|
||||
|
||||
/obj/item/gun/magic/tentacle
|
||||
name = "tentacle"
|
||||
desc = "A fleshy tentacle that can stretch out and grab things or people."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "tentacle"
|
||||
item_state = "tentacle"
|
||||
lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
|
||||
flags_1 = ABSTRACT_1 | NODROP_1 | DROPDEL_1 | NOBLUDGEON_1
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
ammo_type = /obj/item/ammo_casing/magic/tentacle
|
||||
fire_sound = 'sound/effects/splat.ogg'
|
||||
force = 0
|
||||
max_charges = 1
|
||||
throwforce = 0 //Just to be on the safe side
|
||||
throw_range = 0
|
||||
throw_speed = 0
|
||||
|
||||
/obj/item/gun/magic/tentacle/Initialize(mapload, silent)
|
||||
. = ..()
|
||||
if(ismob(loc))
|
||||
if(!silent)
|
||||
loc.visible_message("<span class='warning'>[loc.name]\'s arm starts stretching inhumanly!</span>", "<span class='warning'>Our arm twists and mutates, transforming it into a tentacle.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
else
|
||||
to_chat(loc, "<span class='notice'>You prepare to extend a tentacle.</span>")
|
||||
|
||||
|
||||
/obj/item/gun/magic/tentacle/shoot_with_empty_chamber(mob/living/user as mob|obj)
|
||||
to_chat(user, "<span class='warning'>The [name] is not ready yet.</span>")
|
||||
|
||||
/obj/item/gun/magic/tentacle/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] coils [src] tightly around [user.p_their()] neck! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (OXYLOSS)
|
||||
|
||||
|
||||
/obj/item/ammo_casing/magic/tentacle
|
||||
name = "tentacle"
|
||||
desc = "A tentacle."
|
||||
projectile_type = /obj/item/projectile/tentacle
|
||||
caliber = "tentacle"
|
||||
icon_state = "tentacle_end"
|
||||
firing_effect_type = null
|
||||
var/obj/item/gun/magic/tentacle/gun //the item that shot it
|
||||
|
||||
/obj/item/ammo_casing/magic/tentacle/Initialize()
|
||||
gun = loc
|
||||
. = ..()
|
||||
|
||||
/obj/item/ammo_casing/magic/tentacle/Destroy()
|
||||
gun = null
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/tentacle
|
||||
name = "tentacle"
|
||||
icon_state = "tentacle_end"
|
||||
pass_flags = PASSTABLE
|
||||
damage = 0
|
||||
damage_type = BRUTE
|
||||
range = 8
|
||||
hitsound = 'sound/weapons/thudswoosh.ogg'
|
||||
var/chain
|
||||
var/obj/item/ammo_casing/magic/tentacle/source //the item that shot it
|
||||
|
||||
/obj/item/projectile/tentacle/Initialize()
|
||||
source = loc
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/tentacle/fire(setAngle)
|
||||
if(firer)
|
||||
chain = firer.Beam(src, icon_state = "tentacle", time = INFINITY, maxdistance = INFINITY, beam_sleep_time = 1)
|
||||
..()
|
||||
|
||||
/obj/item/projectile/tentacle/proc/reset_throw(mob/living/carbon/human/H)
|
||||
if(H.in_throw_mode)
|
||||
H.throw_mode_off() //Don't annoy the changeling if he doesn't catch the item
|
||||
|
||||
/obj/item/projectile/tentacle/proc/tentacle_grab(mob/living/carbon/human/H, mob/living/carbon/C)
|
||||
if(H.Adjacent(C))
|
||||
C.grabbedby(H)
|
||||
C.grippedby(H) //instant aggro grab
|
||||
|
||||
/obj/item/projectile/tentacle/proc/tentacle_stab(mob/living/carbon/human/H, mob/living/carbon/C)
|
||||
if(H.Adjacent(C))
|
||||
for(var/obj/item/I in H.held_items)
|
||||
if(I.is_sharp())
|
||||
C.visible_message("<span class='danger'>[H] impales [C] with [H.p_their()] [I.name]!</span>", "<span class='userdanger'>[H] impales you with [H.p_their()] [I.name]!</span>")
|
||||
C.apply_damage(I.force, BRUTE, "chest")
|
||||
H.do_item_attack_animation(C, used_item = I)
|
||||
H.add_mob_blood(C)
|
||||
playsound(get_turf(H),I.hitsound,75,1)
|
||||
return
|
||||
|
||||
/obj/item/projectile/tentacle/on_hit(atom/target, blocked = FALSE)
|
||||
var/mob/living/carbon/human/H = firer
|
||||
H.dropItemToGround(source.gun, TRUE) //Unequip thus delete the tentacle on hit
|
||||
if(blocked >= 100)
|
||||
return 0
|
||||
if(isitem(target))
|
||||
var/obj/item/I = target
|
||||
if(!I.anchored)
|
||||
to_chat(firer, "<span class='notice'>You pull [I] towards yourself.</span>")
|
||||
H.throw_mode_on()
|
||||
I.throw_at(H, 10, 2)
|
||||
. = 1
|
||||
|
||||
else if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(!L.anchored && !L.throwing)//avoid double hits
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
switch(firer.a_intent)
|
||||
if(INTENT_HELP)
|
||||
C.visible_message("<span class='danger'>[L] is pulled by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
|
||||
C.throw_at(get_step_towards(H,C), 8, 2)
|
||||
return 1
|
||||
|
||||
if(INTENT_DISARM)
|
||||
var/obj/item/I = C.get_active_held_item()
|
||||
if(I)
|
||||
if(C.dropItemToGround(I))
|
||||
C.visible_message("<span class='danger'>[I] is yanked off [C]'s hand by [src]!</span>","<span class='userdanger'>A tentacle pulls [I] away from you!</span>")
|
||||
on_hit(I) //grab the item as if you had hit it directly with the tentacle
|
||||
return 1
|
||||
else
|
||||
to_chat(firer, "<span class='danger'>You can't seem to pry [I] off [C]'s hands!</span>")
|
||||
return 0
|
||||
else
|
||||
to_chat(firer, "<span class='danger'>[C] has nothing in hand to disarm!</span>")
|
||||
return 0
|
||||
|
||||
if(INTENT_GRAB)
|
||||
C.visible_message("<span class='danger'>[L] is grabbed by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
|
||||
C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(src, .proc/tentacle_grab, H, C))
|
||||
return 1
|
||||
|
||||
if(INTENT_HARM)
|
||||
C.visible_message("<span class='danger'>[L] is thrown towards [H] by a tentacle!</span>","<span class='userdanger'>A tentacle grabs you and throws you towards [H]!</span>")
|
||||
C.throw_at(get_step_towards(H,C), 8, 2, callback=CALLBACK(src, .proc/tentacle_stab, H, C))
|
||||
return 1
|
||||
else
|
||||
L.visible_message("<span class='danger'>[L] is pulled by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
|
||||
L.throw_at(get_step_towards(H,L), 8, 2)
|
||||
. = 1
|
||||
|
||||
/obj/item/projectile/tentacle/Destroy()
|
||||
qdel(chain)
|
||||
source = null
|
||||
return ..()
|
||||
|
||||
|
||||
/***************************************\
|
||||
|****************SHIELD*****************|
|
||||
\***************************************/
|
||||
/obj/effect/proc_holder/changeling/weapon/shield
|
||||
name = "Organic Shield"
|
||||
desc = "We reform one of our arms into a hard shield."
|
||||
helptext = "Organic tissue cannot resist damage forever; the shield will break after it is hit too much. The more genomes we absorb, the stronger it is. Cannot be used while in lesser form."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
req_human = 1
|
||||
|
||||
weapon_type = /obj/item/shield/changeling
|
||||
weapon_name_simple = "shield"
|
||||
|
||||
/obj/effect/proc_holder/changeling/weapon/shield/sting_action(mob/user)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling) //So we can read the absorbedcount.
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
var/obj/item/shield/changeling/S = ..(user)
|
||||
S.remaining_uses = round(changeling.absorbedcount * 3)
|
||||
return TRUE
|
||||
|
||||
/obj/item/shield/changeling
|
||||
name = "shield-like mass"
|
||||
desc = "A mass of tough, boney tissue. You can still see the fingers as a twisted pattern in the shield."
|
||||
flags_1 = ABSTRACT_1 | NODROP_1 | DROPDEL_1
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "ling_shield"
|
||||
lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
|
||||
block_chance = 50
|
||||
|
||||
var/remaining_uses //Set by the changeling ability.
|
||||
|
||||
/obj/item/shield/changeling/Initialize()
|
||||
. = ..()
|
||||
if(ismob(loc))
|
||||
loc.visible_message("<span class='warning'>The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!</span>", "<span class='warning'>We inflate our hand into a strong shield.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
|
||||
/obj/item/shield/changeling/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
if(remaining_uses < 1)
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
H.visible_message("<span class='warning'>With a sickening crunch, [H] reforms his shield into an arm!</span>", "<span class='notice'>We assimilate our shield into our body</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
qdel(src)
|
||||
return 0
|
||||
else
|
||||
remaining_uses--
|
||||
return ..()
|
||||
|
||||
|
||||
/***************************************\
|
||||
|*********SPACE SUIT + HELMET***********|
|
||||
\***************************************/
|
||||
/obj/effect/proc_holder/changeling/suit/organic_space_suit
|
||||
name = "Organic Space Suit"
|
||||
desc = "We grow an organic suit to protect ourselves from space exposure."
|
||||
helptext = "We must constantly repair our form to make it space-proof, reducing chemical production while we are protected. Cannot be used in lesser form."
|
||||
chemical_cost = 20
|
||||
dna_cost = 2
|
||||
req_human = 1
|
||||
|
||||
suit_type = /obj/item/clothing/suit/space/changeling
|
||||
helmet_type = /obj/item/clothing/head/helmet/space/changeling
|
||||
suit_name_simple = "flesh shell"
|
||||
helmet_name_simple = "space helmet"
|
||||
recharge_slowdown = 0.5
|
||||
blood_on_castoff = 1
|
||||
|
||||
/obj/item/clothing/suit/space/changeling
|
||||
name = "flesh mass"
|
||||
icon_state = "lingspacesuit"
|
||||
desc = "A huge, bulky mass of pressure and temperature-resistant organic tissue, evolved to facilitate space travel."
|
||||
flags_1 = STOPSPRESSUREDMAGE_1 | NODROP_1 | DROPDEL_1 //Not THICKMATERIAL_1 because it's organic tissue, so if somebody tries to inject something into it, it still ends up in your blood. (also balance but muh fluff)
|
||||
allowed = list(/obj/item/device/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/oxygen)
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 90, acid = 90) //No armor at all.
|
||||
|
||||
/obj/item/clothing/suit/space/changeling/Initialize()
|
||||
. = ..()
|
||||
if(ismob(loc))
|
||||
loc.visible_message("<span class='warning'>[loc.name]\'s flesh rapidly inflates, forming a bloated mass around their body!</span>", "<span class='warning'>We inflate our flesh, creating a spaceproof suit!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/clothing/suit/space/changeling/process()
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
H.reagents.add_reagent("salbutamol", REAGENTS_METABOLISM)
|
||||
|
||||
/obj/item/clothing/head/helmet/space/changeling
|
||||
name = "flesh mass"
|
||||
icon_state = "lingspacehelmet"
|
||||
desc = "A covering of pressure and temperature-resistant organic tissue with a glass-like chitin front."
|
||||
flags_1 = STOPSPRESSUREDMAGE_1 | NODROP_1 | DROPDEL_1 //Again, no THICKMATERIAL_1.
|
||||
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0, fire = 90, acid = 90)
|
||||
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
|
||||
|
||||
/***************************************\
|
||||
|*****************ARMOR*****************|
|
||||
\***************************************/
|
||||
/obj/effect/proc_holder/changeling/suit/armor
|
||||
name = "Chitinous Armor"
|
||||
desc = "We turn our skin into tough chitin to protect us from damage."
|
||||
helptext = "Upkeep of the armor requires a low expenditure of chemicals. The armor is strong against brute force, but does not provide much protection from lasers. Cannot be used in lesser form."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
req_human = 1
|
||||
recharge_slowdown = 0.25
|
||||
|
||||
suit_type = /obj/item/clothing/suit/armor/changeling
|
||||
helmet_type = /obj/item/clothing/head/helmet/changeling
|
||||
suit_name_simple = "armor"
|
||||
helmet_name_simple = "helmet"
|
||||
|
||||
/obj/item/clothing/suit/armor/changeling
|
||||
name = "chitinous mass"
|
||||
desc = "A tough, hard covering of black chitin."
|
||||
icon_state = "lingarmor"
|
||||
flags_1 = NODROP_1 | DROPDEL_1
|
||||
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
armor = list(melee = 40, bullet = 40, laser = 40, energy = 20, bomb = 10, bio = 4, rad = 0, fire = 90, acid = 90)
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
cold_protection = 0
|
||||
heat_protection = 0
|
||||
|
||||
/obj/item/clothing/suit/armor/changeling/Initialize()
|
||||
. = ..()
|
||||
if(ismob(loc))
|
||||
loc.visible_message("<span class='warning'>[loc.name]\'s flesh turns black, quickly transforming into a hard, chitinous mass!</span>", "<span class='warning'>We harden our flesh, creating a suit of armor!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
|
||||
/obj/item/clothing/head/helmet/changeling
|
||||
name = "chitinous mass"
|
||||
desc = "A tough, hard covering of black chitin with transparent chitin in front."
|
||||
icon_state = "lingarmorhelmet"
|
||||
flags_1 = NODROP_1 | DROPDEL_1
|
||||
armor = list(melee = 40, bullet = 40, laser = 40, energy = 20, bomb = 10, bio = 4, rad = 0, fire = 90, acid = 90)
|
||||
flags_inv = HIDEEARS|HIDEHAIR|HIDEEYES|HIDEFACIALHAIR|HIDEFACE
|
||||
@@ -1,38 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/panacea
|
||||
name = "Anatomic Panacea"
|
||||
desc = "Expels impurifications from our form; curing diseases, removing parasites, sobering us, purging toxins and radiation, and resetting our genetic code completely."
|
||||
helptext = "Can be used while unconscious."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
req_stat = UNCONSCIOUS
|
||||
|
||||
//Heals the things that the other regenerative abilities don't.
|
||||
/obj/effect/proc_holder/changeling/panacea/sting_action(mob/user)
|
||||
to_chat(user, "<span class='notice'>We cleanse impurities from our form.</span>")
|
||||
|
||||
var/list/bad_organs = list(
|
||||
user.getorgan(/obj/item/organ/body_egg),
|
||||
user.getorgan(/obj/item/organ/zombie_infection))
|
||||
|
||||
for(var/o in bad_organs)
|
||||
var/obj/item/organ/O = o
|
||||
if(!istype(O))
|
||||
continue
|
||||
|
||||
O.Remove(user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.vomit(0, toxic = TRUE)
|
||||
O.forceMove(get_turf(user))
|
||||
|
||||
user.reagents.add_reagent("mutadone", 10)
|
||||
user.reagents.add_reagent("pen_acid", 20)
|
||||
user.reagents.add_reagent("antihol", 10)
|
||||
user.reagents.add_reagent("mannitol", 25)
|
||||
|
||||
for(var/thing in user.viruses)
|
||||
var/datum/disease/D = thing
|
||||
if(D.severity == VIRUS_SEVERITY_POSITIVE)
|
||||
continue
|
||||
D.cure()
|
||||
return TRUE
|
||||
@@ -1,37 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/regenerate
|
||||
name = "Regenerate"
|
||||
desc = "Allows us to regrow and restore missing external limbs, and \
|
||||
vital internal organs, as well as removing shrapnel and restoring \
|
||||
blood volume."
|
||||
helptext = "Will alert nearby crew if any external limbs are \
|
||||
regenerated. Can be used while unconscious."
|
||||
chemical_cost = 10
|
||||
dna_cost = 0
|
||||
req_stat = UNCONSCIOUS
|
||||
always_keep = TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/regenerate/sting_action(mob/living/user)
|
||||
to_chat(user, "<span class='notice'>You feel an itching, both inside and \
|
||||
outside as your tissues knit and reknit.</span>")
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
var/list/missing = C.get_missing_limbs()
|
||||
if(missing.len)
|
||||
playsound(user, 'sound/magic/demon_consume.ogg', 50, 1)
|
||||
C.visible_message("<span class='warning'>[user]'s missing limbs \
|
||||
reform, making a loud, grotesque sound!</span>",
|
||||
"<span class='userdanger'>Your limbs regrow, making a \
|
||||
loud, crunchy sound and giving you great pain!</span>",
|
||||
"<span class='italics'>You hear organic matter ripping \
|
||||
and tearing!</span>")
|
||||
C.emote("scream")
|
||||
C.regenerate_limbs(1)
|
||||
C.regenerate_organs()
|
||||
if(!user.getorganslot(ORGAN_SLOT_BRAIN))
|
||||
var/obj/item/organ/brain/changeling_brain/B = new()
|
||||
B.Insert(C)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.restore_blood()
|
||||
H.remove_all_embedded_objects()
|
||||
return TRUE
|
||||
@@ -1,37 +0,0 @@
|
||||
/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>")
|
||||
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
|
||||
. = ..()
|
||||
@@ -1,42 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/resonant_shriek
|
||||
name = "Resonant Shriek"
|
||||
desc = "Our lungs and vocal cords shift, allowing us to briefly emit a noise that deafens and confuses the weak-minded."
|
||||
helptext = "Emits a high-frequency sound that confuses and deafens humans, blows out nearby lights and overloads cyborg sensors."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
req_human = 1
|
||||
|
||||
//A flashy ability, good for crowd control and sewing chaos.
|
||||
/obj/effect/proc_holder/changeling/resonant_shriek/sting_action(mob/user)
|
||||
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.has_antag_datum(/datum/antagonist/changeling))
|
||||
C.adjustEarDamage(0, 30)
|
||||
C.confused += 25
|
||||
C.Jitter(50)
|
||||
else
|
||||
SEND_SOUND(C, sound('sound/effects/screech.ogg'))
|
||||
|
||||
if(issilicon(M))
|
||||
SEND_SOUND(M, sound('sound/weapons/flash.ogg'))
|
||||
M.Knockdown(rand(100,200))
|
||||
|
||||
for(var/obj/machinery/light/L in range(4, user))
|
||||
L.on = 1
|
||||
L.break_light_tube()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/dissonant_shriek
|
||||
name = "Dissonant Shriek"
|
||||
desc = "We shift our vocal cords to release a high-frequency sound that overloads nearby electronics."
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
|
||||
//A flashy ability, good for crowd control and sewing chaos.
|
||||
/obj/effect/proc_holder/changeling/dissonant_shriek/sting_action(mob/user)
|
||||
for(var/obj/machinery/light/L in range(5, usr))
|
||||
L.on = 1
|
||||
L.break_light_tube()
|
||||
empulse(get_turf(user), 2, 5, 1)
|
||||
return TRUE
|
||||
@@ -1,12 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/spiders
|
||||
name = "Spread Infestation"
|
||||
desc = "Our form divides, creating arachnids which will grow into deadly beasts."
|
||||
helptext = "The spiders are thoughtless creatures, and may attack their creators when fully grown. Requires at least 5 DNA absorptions."
|
||||
chemical_cost = 45
|
||||
dna_cost = 1
|
||||
req_dna = 5
|
||||
|
||||
//Makes some spiderlings. Good for setting traps and causing general trouble.
|
||||
/obj/effect/proc_holder/changeling/spiders/sting_action(mob/user)
|
||||
spawn_atom_to_turf(/obj/structure/spider/spiderling/hunter, user, 2, FALSE)
|
||||
return TRUE
|
||||
@@ -1,51 +0,0 @@
|
||||
//Strained Muscles: Temporary speed boost at the cost of rapid damage
|
||||
//Limited because of hardsuits and such; ideally, used for a quick getaway
|
||||
|
||||
/obj/effect/proc_holder/changeling/strained_muscles
|
||||
name = "Strained Muscles"
|
||||
desc = "We evolve the ability to reduce the acid buildup in our muscles, allowing us to move much faster."
|
||||
helptext = "The strain will make us tired, and we will rapidly become fatigued. Standard weight restrictions, like hardsuits, still apply. Cannot be used in lesser form."
|
||||
chemical_cost = 0
|
||||
dna_cost = 1
|
||||
req_human = 1
|
||||
var/stacks = 0 //Increments every 5 seconds; damage increases over time
|
||||
active = 0 //Whether or not you are a hedgehog
|
||||
|
||||
/obj/effect/proc_holder/changeling/strained_muscles/sting_action(mob/living/carbon/user)
|
||||
active = !active
|
||||
if(active)
|
||||
to_chat(user, "<span class='notice'>Our muscles tense and strengthen.</span>")
|
||||
else
|
||||
user.status_flags &= ~GOTTAGOFAST
|
||||
to_chat(user, "<span class='notice'>Our muscles relax.</span>")
|
||||
if(stacks >= 10)
|
||||
to_chat(user, "<span class='danger'>We collapse in exhaustion.</span>")
|
||||
user.Knockdown(60)
|
||||
user.emote("gasp")
|
||||
|
||||
INVOKE_ASYNC(src, .proc/muscle_loop, user)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/strained_muscles/proc/muscle_loop(mob/living/carbon/user)
|
||||
while(active)
|
||||
user.status_flags |= GOTTAGOFAST
|
||||
if(user.stat != CONSCIOUS || user.staminaloss >= 90)
|
||||
active = !active
|
||||
to_chat(user, "<span class='notice'>Our muscles relax without the energy to strengthen them.</span>")
|
||||
user.Knockdown(40)
|
||||
user.status_flags &= ~GOTTAGOFAST
|
||||
break
|
||||
|
||||
stacks++
|
||||
//user.take_bodypart_damage(stacks * 0.03, 0)
|
||||
user.staminaloss += stacks * 1.3 //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack
|
||||
|
||||
if(stacks == 11) //Warning message that the stacks are getting too high
|
||||
to_chat(user, "<span class='warning'>Our legs are really starting to hurt...</span>")
|
||||
|
||||
sleep(40)
|
||||
|
||||
while(!active && stacks) //Damage stacks decrease fairly rapidly while not in sanic mode
|
||||
stacks--
|
||||
sleep(20)
|
||||
@@ -1,246 +0,0 @@
|
||||
/obj/effect/proc_holder/changeling/sting
|
||||
name = "Tiny Prick"
|
||||
desc = "Stabby stabby."
|
||||
var/sting_icon = null
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/Click()
|
||||
var/mob/user = usr
|
||||
if(!user || !user.mind)
|
||||
return
|
||||
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)
|
||||
return
|
||||
|
||||
/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>")
|
||||
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>")
|
||||
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)
|
||||
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
|
||||
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, changeling.sting_range, simulated_only = 0))
|
||||
return
|
||||
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/changeling))
|
||||
sting_feedback(user, target)
|
||||
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.has_antag_datum(/datum/antagonist/changeling))
|
||||
to_chat(target, "<span class='warning'>You feel a tiny prick.</span>")
|
||||
return 1
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation
|
||||
name = "Transformation Sting"
|
||||
desc = "We silently sting a human, injecting a retrovirus that forces them to transform."
|
||||
helptext = "The victim will transform much like a changeling would. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human."
|
||||
sting_icon = "sting_transform"
|
||||
chemical_cost = 50
|
||||
dna_cost = 3
|
||||
var/datum/changelingprofile/selected_dna = null
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/Click()
|
||||
var/mob/user = usr
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(changeling.chosen_sting)
|
||||
unset_sting(user)
|
||||
return
|
||||
selected_dna = changeling.select_dna("Select the target DNA: ", "Target DNA")
|
||||
if(!selected_dna)
|
||||
return
|
||||
if(NOTRANSSTING in selected_dna.dna.species.species_traits)
|
||||
to_chat(user, "<span class = 'notice'>That DNA is not compatible with changeling retrovirus!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target)
|
||||
if(!..())
|
||||
return
|
||||
if((target.has_disability(DISABILITY_HUSK)) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
|
||||
to_chat(user, "<span class='warning'>Our sting appears ineffective against its DNA.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/transformation/sting_action(mob/user, mob/target)
|
||||
add_logs(user, target, "stung", "transformation sting", " new identity is [selected_dna.dna.real_name]")
|
||||
var/datum/dna/NewDNA = selected_dna.dna
|
||||
if(ismonkey(target))
|
||||
to_chat(user, "<span class='notice'>Our genes cry out as we sting [target.name]!</span>")
|
||||
|
||||
var/mob/living/carbon/C = target
|
||||
. = TRUE
|
||||
if(istype(C))
|
||||
C.real_name = NewDNA.real_name
|
||||
NewDNA.transfer_identity(C)
|
||||
if(ismonkey(C))
|
||||
C.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
|
||||
C.updateappearance(mutcolor_update=1)
|
||||
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade
|
||||
name = "False Armblade Sting"
|
||||
desc = "We silently sting a human, injecting a retrovirus that mutates their arm to temporarily appear as an armblade."
|
||||
helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless."
|
||||
sting_icon = "sting_armblade"
|
||||
chemical_cost = 20
|
||||
dna_cost = 1
|
||||
|
||||
/obj/item/melee/arm_blade/false
|
||||
desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless."
|
||||
force = 5 //Basically as strong as a punch
|
||||
|
||||
/obj/item/melee/arm_blade/false/afterattack(atom/target, mob/user, proximity)
|
||||
return
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/can_sting(mob/user, mob/target)
|
||||
if(!..())
|
||||
return
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if((L.has_disability(DISABILITY_HUSK)) || !L.has_dna())
|
||||
to_chat(user, "<span class='warning'>Our sting appears ineffective against its DNA.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/sting_action(mob/user, mob/target)
|
||||
add_logs(user, target, "stung", object="falso armblade sting")
|
||||
|
||||
var/obj/item/held = target.get_active_held_item()
|
||||
if(held && !target.dropItemToGround(held))
|
||||
to_chat(user, "<span class='warning'>[held] is stuck to their hand, you cannot grow a false armblade over it!</span>")
|
||||
return
|
||||
|
||||
if(ismonkey(target))
|
||||
to_chat(user, "<span class='notice'>Our genes cry out as we sting [target.name]!</span>")
|
||||
|
||||
var/obj/item/melee/arm_blade/false/blade = new(target,1)
|
||||
target.put_in_hands(blade)
|
||||
target.visible_message("<span class='warning'>A grotesque blade forms around [target.name]\'s arm!</span>", "<span class='userdanger'>Your arm twists and mutates, transforming into a horrific monstrosity!</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
|
||||
playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
|
||||
addtimer(CALLBACK(src, .proc/remove_fake, target, blade), 600)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/false_armblade/proc/remove_fake(mob/target, obj/item/melee/arm_blade/false/blade)
|
||||
playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
target.visible_message("<span class='warning'>With a sickening crunch, \
|
||||
[target] reforms their [blade.name] into an arm!</span>",
|
||||
"<span class='warning'>[blade] reforms back to normal.</span>",
|
||||
"<span class='italics>You hear organic matter ripping and tearing!</span>")
|
||||
|
||||
qdel(blade)
|
||||
target.update_inv_hands()
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/extract_dna
|
||||
name = "Extract DNA Sting"
|
||||
desc = "We stealthily sting a target and extract their DNA."
|
||||
helptext = "Will give you the DNA of your target, allowing you to transform into them."
|
||||
sting_icon = "sting_extract"
|
||||
chemical_cost = 25
|
||||
dna_cost = 0
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/extract_dna/can_sting(mob/user, mob/target)
|
||||
if(..())
|
||||
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")
|
||||
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
|
||||
name = "Mute Sting"
|
||||
desc = "We silently sting a human, completely silencing them for a short time."
|
||||
helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot."
|
||||
sting_icon = "sting_mute"
|
||||
chemical_cost = 20
|
||||
dna_cost = 2
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/mute/sting_action(mob/user, mob/living/carbon/target)
|
||||
add_logs(user, target, "stung", "mute sting")
|
||||
target.silent += 30
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/blind
|
||||
name = "Blind Sting"
|
||||
desc = "Temporarily blinds the target."
|
||||
helptext = "This sting completely blinds a target for a short time."
|
||||
sting_icon = "sting_blind"
|
||||
chemical_cost = 25
|
||||
dna_cost = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/blind/sting_action(mob/user, mob/living/carbon/target)
|
||||
add_logs(user, target, "stung", "blind sting")
|
||||
to_chat(target, "<span class='danger'>Your eyes burn horrifically!</span>")
|
||||
target.become_nearsighted(EYE_DAMAGE)
|
||||
target.blind_eyes(20)
|
||||
target.blur_eyes(40)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD
|
||||
name = "Hallucination Sting"
|
||||
desc = "Causes terror in the target."
|
||||
helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. The target does not notice they have been stung, and the effect occurs after 30 to 60 seconds."
|
||||
sting_icon = "sting_lsd"
|
||||
chemical_cost = 10
|
||||
dna_cost = 1
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/living/carbon/target)
|
||||
add_logs(user, target, "stung", "LSD sting")
|
||||
addtimer(CALLBACK(src, .proc/hallucination_time, target), rand(300,600))
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/LSD/proc/hallucination_time(mob/living/carbon/target)
|
||||
if(target)
|
||||
target.hallucination = max(400, target.hallucination)
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/cryo
|
||||
name = "Cryogenic Sting"
|
||||
desc = "We silently sting a human with a cocktail of chemicals that freeze them."
|
||||
helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing."
|
||||
sting_icon = "sting_cryo"
|
||||
chemical_cost = 15
|
||||
dna_cost = 2
|
||||
|
||||
/obj/effect/proc_holder/changeling/sting/cryo/sting_action(mob/user, mob/target)
|
||||
add_logs(user, target, "stung", "cryo sting")
|
||||
if(target.reagents)
|
||||
target.reagents.add_reagent("frostoil", 30)
|
||||
return TRUE
|
||||
@@ -1,129 +0,0 @@
|
||||
/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.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.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.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.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.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.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.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.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
|
||||
@@ -1,25 +0,0 @@
|
||||
//The base clockwork effect. Can have an alternate desc and will show up in the list of clockwork objects.
|
||||
/obj/effect/clockwork
|
||||
name = "meme machine"
|
||||
desc = "Still don't know what it is."
|
||||
var/clockwork_desc = "A fabled artifact from beyond the stars. Contains concentrated meme essence." //Shown to clockwork cultists instead of the normal description
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "ratvars_flame"
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
opacity = 0
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
|
||||
/obj/effect/clockwork/Initialize()
|
||||
. = ..()
|
||||
GLOB.all_clockwork_objects += src
|
||||
|
||||
/obj/effect/clockwork/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/examine(mob/user)
|
||||
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
@@ -1,69 +0,0 @@
|
||||
//These spawn across the station when the Ark activates. Anyone can walk through one to teleport to Reebe.
|
||||
/obj/effect/clockwork/city_of_cogs_rift
|
||||
name = "celestial rift"
|
||||
desc = "A stable bluespace rip. You're not sure it where leads."
|
||||
clockwork_desc = "A one-way rift to the City of Cogs. Because it's linked to the Ark, it can't be closed."
|
||||
icon_state = "city_of_cogs_rift"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
density = TRUE
|
||||
light_range = 2
|
||||
light_power = 3
|
||||
light_color = "#6A4D2F"
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/Initialize()
|
||||
. = ..()
|
||||
visible_message("<span class='warning'>The air above [loc] shimmers and pops as a [name] forms there!</span>")
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M.z == z)
|
||||
if(get_dist(src, M) >= 7)
|
||||
M.playsound_local(src, 'sound/magic/blink.ogg', 10, FALSE, falloff = 10)
|
||||
else
|
||||
M.playsound_local(src, 'sound/magic/blink.ogg', 50, FALSE)
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/Destroy()
|
||||
visible_message("<span class='warning'>[src] cracks as it destabilizes and breaks apart!</span>")
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/nullrod))
|
||||
to_chat(user, "<span class='warning'>Your [I.name] seems to have no effect on [src]!</span>")
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/attack_hand(atom/movable/AM)
|
||||
beckon(AM)
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/CollidedWith(atom/movable/AM)
|
||||
if(!QDELETED(AM))
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.client && !L.incapacitated())
|
||||
L.visible_message("<span class='notice'>[L] starts climbing through [src]...</span>", \
|
||||
"<span class='notice'>You begin climbing through [src]...</span>")
|
||||
if(!do_after(L, 30, target = L))
|
||||
return
|
||||
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>", null, null, null, AM)
|
||||
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)
|
||||
do_sparks(5, TRUE, AM)
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
L.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/static)
|
||||
L.clear_fullscreen("flash", 5)
|
||||
var/obj/item/device/transfer_valve/TTV = locate() in L.GetAllContents()
|
||||
if(TTV)
|
||||
to_chat(L, "<span class='userdanger'>The air resonates with the Ark's presence; your explosives will be significantly dampened here!</span>")
|
||||
@@ -1,49 +0,0 @@
|
||||
//an "overlay" used by clockwork walls and floors to appear normal to mesons.
|
||||
/obj/effect/clockwork/overlay
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
var/atom/linked
|
||||
|
||||
/obj/effect/clockwork/overlay/examine(mob/user)
|
||||
if(linked)
|
||||
linked.examine(user)
|
||||
|
||||
/obj/effect/clockwork/overlay/ex_act()
|
||||
return FALSE
|
||||
|
||||
/obj/effect/clockwork/overlay/singularity_act()
|
||||
return
|
||||
/obj/effect/clockwork/overlay/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/overlay/singularity_pull(S, current_size)
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/overlay/Destroy()
|
||||
if(linked)
|
||||
linked = null
|
||||
. = ..()
|
||||
|
||||
/obj/effect/clockwork/overlay/wall
|
||||
name = "clockwork wall"
|
||||
icon = 'icons/turf/walls/clockwork_wall.dmi'
|
||||
icon_state = "clockwork_wall"
|
||||
canSmoothWith = list(/obj/effect/clockwork/overlay/wall, /obj/structure/falsewall/brass)
|
||||
smooth = SMOOTH_TRUE
|
||||
layer = CLOSED_TURF_LAYER
|
||||
|
||||
/obj/effect/clockwork/overlay/wall/Initialize()
|
||||
. = ..()
|
||||
queue_smooth_neighbors(src)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/queue_smooth, src), 1)
|
||||
|
||||
/obj/effect/clockwork/overlay/wall/Destroy()
|
||||
queue_smooth_neighbors(src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/overlay/floor
|
||||
icon = 'icons/turf/floors.dmi'
|
||||
icon_state = "clockwork_floor"
|
||||
layer = TURF_LAYER
|
||||
|
||||
/obj/effect/clockwork/overlay/floor/bloodcult //this is used by BLOOD CULT, it shouldn't use such a path...
|
||||
icon_state = "cult"
|
||||
@@ -1,369 +0,0 @@
|
||||
//Sigils: Rune-like markings on the ground with various effects.
|
||||
/obj/effect/clockwork/sigil
|
||||
name = "sigil"
|
||||
desc = "A strange set of markings drawn on the ground."
|
||||
clockwork_desc = "A sigil of some purpose."
|
||||
icon_state = "sigil"
|
||||
layer = LOW_OBJ_LAYER
|
||||
alpha = 50
|
||||
resistance_flags = NONE
|
||||
var/affects_servants = FALSE
|
||||
var/stat_affected = CONSCIOUS
|
||||
var/sigil_name = "Sigil"
|
||||
var/resist_string = "glows blinding white" //string for when a null rod blocks its effects, "glows [resist_string]"
|
||||
|
||||
/obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params)
|
||||
if(I.force)
|
||||
if(is_servant_of_ratvar(user) && user.a_intent != INTENT_HARM)
|
||||
return ..()
|
||||
user.visible_message("<span class='warning'>[user] scatters [src] with [I]!</span>", "<span class='danger'>You scatter [src] with [I]!</span>")
|
||||
qdel(src)
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/sigil/attack_tk(mob/user)
|
||||
return //you can't tk stomp sigils, but you can hit them with something
|
||||
|
||||
/obj/effect/clockwork/sigil/attack_hand(mob/user)
|
||||
if(iscarbon(user) && !user.stat)
|
||||
if(is_servant_of_ratvar(user) && user.a_intent != INTENT_HARM)
|
||||
return ..()
|
||||
user.visible_message("<span class='warning'>[user] stamps out [src]!</span>", "<span class='danger'>You stomp on [src], scattering it into thousands of particles.</span>")
|
||||
qdel(src)
|
||||
return 1
|
||||
..()
|
||||
|
||||
/obj/effect/clockwork/sigil/ex_act(severity)
|
||||
visible_message("<span class='warning'>[src] scatters into thousands of particles.</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/clockwork/sigil/Crossed(atom/movable/AM)
|
||||
..()
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.stat <= stat_affected)
|
||||
if((!is_servant_of_ratvar(L) || (affects_servants && is_servant_of_ratvar(L))) && (L.mind || L.has_status_effect(STATUS_EFFECT_SIGILMARK)) && !isdrone(L))
|
||||
var/obj/item/I = L.null_rod_check()
|
||||
if(I)
|
||||
L.visible_message("<span class='warning'>[L]'s [I.name] [resist_string], protecting them from [src]'s effects!</span>", \
|
||||
"<span class='userdanger'>Your [I.name] [resist_string], protecting you!</span>")
|
||||
return
|
||||
sigil_effects(L)
|
||||
|
||||
/obj/effect/clockwork/sigil/proc/sigil_effects(mob/living/L)
|
||||
|
||||
|
||||
//Sigil of Transgression: Stuns the first non-servant to walk on it and flashes all nearby non_servants. Nar-Sian cultists are damaged and knocked down for a longer time
|
||||
/obj/effect/clockwork/sigil/transgression
|
||||
name = "dull sigil"
|
||||
desc = "A dull, barely-visible golden sigil. It's as though light was carved into the ground."
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
clockwork_desc = "A sigil that will stun the next non-Servant to cross it."
|
||||
icon_state = "sigildull"
|
||||
layer = HIGH_SIGIL_LAYER
|
||||
alpha = 75
|
||||
color = "#FAE48C"
|
||||
light_range = 1.4
|
||||
light_power = 1
|
||||
light_color = "#FAE48C"
|
||||
sigil_name = "Sigil of Transgression"
|
||||
|
||||
/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L)
|
||||
var/target_flashed = L.flash_act()
|
||||
for(var/mob/living/M in viewers(5, src))
|
||||
if(!is_servant_of_ratvar(M) && M != L)
|
||||
M.flash_act()
|
||||
if(iscultist(L))
|
||||
to_chat(L, "<span class='heavy_brass'>\"Watch your step, wretch.\"</span>")
|
||||
L.adjustBruteLoss(10)
|
||||
L.Knockdown(80, FALSE)
|
||||
L.visible_message("<span class='warning'>[src] appears around [L] in a burst of light!</span>", \
|
||||
"<span class='userdanger'>[target_flashed ? "An unseen force":"The glowing sigil around you"] holds you in place!</span>")
|
||||
L.Stun(40)
|
||||
L.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transgression(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
|
||||
//Sigil of Submission: After a short time, converts any non-servant standing on it. Knocks down and silences them for five seconds afterwards.
|
||||
/obj/effect/clockwork/sigil/submission
|
||||
name = "ominous sigil"
|
||||
desc = "A luminous golden sigil. Something about it really bothers you."
|
||||
clockwork_desc = "A sigil that will enslave any non-Servant that remains on it for 8 seconds. Cannot penetrate mindshield implants."
|
||||
icon_state = "sigilsubmission"
|
||||
layer = LOW_SIGIL_LAYER
|
||||
alpha = 125
|
||||
color = "#FAE48C"
|
||||
light_range = 2 //soft light
|
||||
light_power = 0.9
|
||||
light_color = "#FAE48C"
|
||||
stat_affected = UNCONSCIOUS
|
||||
resist_string = "glows faintly yellow"
|
||||
var/convert_time = 80
|
||||
var/delete_on_finish = TRUE
|
||||
sigil_name = "Sigil of Submission"
|
||||
var/glow_type = /obj/effect/temp_visual/ratvar/sigil/submission
|
||||
|
||||
/obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L)
|
||||
var/turf/T = get_turf(src)
|
||||
var/has_sigil = FALSE
|
||||
var/has_servant = FALSE
|
||||
if(locate(/obj/effect/clockwork/sigil/transgression) in T)
|
||||
has_sigil = TRUE
|
||||
for(var/mob/living/M in range(3, src))
|
||||
if(is_servant_of_ratvar(M) && !M.stat)
|
||||
has_servant = TRUE
|
||||
if(!has_sigil && !has_servant)
|
||||
visible_message("<span class='danger'>[src] strains into a gentle violet color, but quietly fades...</span>")
|
||||
return
|
||||
L.visible_message("<span class='warning'>[src] begins to glow a piercing magenta!</span>", "<span class='sevtug'>You feel something start to invade your mind...</span>")
|
||||
var/oldcolor = color
|
||||
animate(src, color = "#AF0AAF", time = convert_time, flags = ANIMATION_END_NOW)
|
||||
var/obj/effect/temp_visual/ratvar/sigil/glow
|
||||
if(glow_type)
|
||||
glow = new glow_type(get_turf(src))
|
||||
animate(glow, alpha = 255, time = convert_time)
|
||||
var/end_time = world.time+convert_time
|
||||
while(world.time < end_time && get_turf(L) == get_turf(src))
|
||||
stoplag(1)
|
||||
if(get_turf(L) != get_turf(src))
|
||||
if(glow)
|
||||
qdel(glow)
|
||||
animate(src, color = oldcolor, time = 20, flags = ANIMATION_END_NOW)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 20)
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
return
|
||||
if(is_eligible_servant(L))
|
||||
to_chat(L, "<span class='heavy_brass'>\"You belong to me now.\"</span>")
|
||||
if(!GLOB.application_scripture_unlocked)
|
||||
GLOB.application_scripture_unlocked = TRUE
|
||||
hierophant_message("<span class='large_brass bold'>With the conversion of a new servant the Ark's power grows. Application scriptures are now available.</span>")
|
||||
if(add_servant_of_ratvar(L))
|
||||
L.log_message("<font color=#BE8700>Conversion was done with a [sigil_name].</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/M = L
|
||||
M.uncuff()
|
||||
L.Knockdown(50) //Completely defenseless for five seconds - mainly to give them time to read over the information they've just been presented with
|
||||
if(iscarbon(L))
|
||||
var/mob/living/carbon/C = L
|
||||
C.silent += 5
|
||||
var/message = "[sigil_name] in [get_area(src)] <span class='sevtug'>[is_servant_of_ratvar(L) ? "successfully converted" : "failed to convert"]</span>"
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, L)
|
||||
to_chat(M, "[link] <span class='heavy_brass'>[message] [L.real_name]!</span>")
|
||||
else if(is_servant_of_ratvar(M))
|
||||
if(M == L)
|
||||
to_chat(M, "<span class='heavy_brass'>[message] you!</span>")
|
||||
else
|
||||
to_chat(M, "<span class='heavy_brass'>[message] [L.real_name]!</span>")
|
||||
animate(src, color = oldcolor, time = 20, flags = ANIMATION_END_NOW)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 20)
|
||||
visible_message("<span class='warning'>[src] slowly stops glowing!</span>")
|
||||
|
||||
|
||||
//Sigil of Transmission: Serves as an access point for powered structures.
|
||||
/obj/effect/clockwork/sigil/transmission
|
||||
name = "suspicious sigil"
|
||||
desc = "A glowing orange sigil. The air around it feels staticky."
|
||||
clockwork_desc = "A sigil that serves as power generation and a battery for clockwork structures, linked to all other sigils of its type."
|
||||
icon_state = "sigiltransmission"
|
||||
alpha = 50
|
||||
color = "#EC8A2D"
|
||||
light_color = "#EC8A2D"
|
||||
resist_string = "glows faintly"
|
||||
sigil_name = "Sigil of Transmission"
|
||||
affects_servants = TRUE
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/Initialize()
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/ex_act(severity)
|
||||
if(severity == 3)
|
||||
adjust_clockwork_power(500) //Light explosions charge the network!
|
||||
visible_message("<span class='warning'>[src] flares a brilliant orange!</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
var/structure_number = 0
|
||||
for(var/obj/structure/destructible/clockwork/powered/P in range(SIGIL_ACCESS_RANGE, src))
|
||||
structure_number++
|
||||
to_chat(user, "<span class='[get_clockwork_power() ? "brass":"alloy"]'>It is storing <b>[DisplayPower(get_clockwork_power())]</b> of shared power, \
|
||||
and <b>[structure_number]</b> clockwork structure[structure_number == 1 ? " is":"s are"] in range.</span>")
|
||||
if(iscyborg(user))
|
||||
to_chat(user, "<span class='brass'>You can recharge from the [sigil_name] by crossing it.</span>")
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/sigil_effects(mob/living/L)
|
||||
if(is_servant_of_ratvar(L))
|
||||
if(iscyborg(L))
|
||||
charge_cyborg(L)
|
||||
else if(get_clockwork_power())
|
||||
to_chat(L, "<span class='brass'>You feel a slight, static shock.</span>")
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/charge_cyborg(mob/living/silicon/robot/cyborg)
|
||||
if(!cyborg_checks(cyborg))
|
||||
return
|
||||
to_chat(cyborg, "<span class='brass'>You start to charge from the [sigil_name]...</span>")
|
||||
if(!do_after(cyborg, 50, target = src, extra_checks = CALLBACK(src, .proc/cyborg_checks, cyborg, TRUE)))
|
||||
return
|
||||
var/giving_power = min(FLOOR(cyborg.cell.maxcharge - cyborg.cell.charge, MIN_CLOCKCULT_POWER), get_clockwork_power()) //give the borg either all our power or their missing power floored to MIN_CLOCKCULT_POWER
|
||||
if(adjust_clockwork_power(-giving_power))
|
||||
cyborg.visible_message("<span class='warning'>[cyborg] glows a brilliant orange!</span>")
|
||||
var/previous_color = cyborg.color
|
||||
cyborg.color = list("#EC8A2D", "#EC8A2D", "#EC8A2D", rgb(0,0,0))
|
||||
cyborg.apply_status_effect(STATUS_EFFECT_POWERREGEN, giving_power * 0.1) //ten ticks, restoring 10% each
|
||||
animate(cyborg, color = previous_color, time = 100)
|
||||
addtimer(CALLBACK(cyborg, /atom/proc/update_atom_colour), 100)
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/cyborg_checks(mob/living/silicon/robot/cyborg, silent)
|
||||
if(!cyborg.cell)
|
||||
if(!silent)
|
||||
to_chat(cyborg, "<span class='warning'>You have no cell!</span>")
|
||||
return FALSE
|
||||
if(!get_clockwork_power())
|
||||
if(!silent)
|
||||
to_chat(cyborg, "<span class='warning'>There is no power available across sigils!</span>")
|
||||
return FALSE
|
||||
if(cyborg.cell.charge > cyborg.cell.maxcharge - MIN_CLOCKCULT_POWER)
|
||||
if(!silent)
|
||||
to_chat(cyborg, "<span class='warning'>You are already at maximum charge!</span>")
|
||||
return FALSE
|
||||
if(cyborg.has_status_effect(STATUS_EFFECT_POWERREGEN))
|
||||
if(!silent)
|
||||
to_chat(cyborg, "<span class='warning'>You are already regenerating power!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/update_icon()
|
||||
if(GLOB.ratvar_awakens)
|
||||
alpha = 255
|
||||
var/power_charge = get_clockwork_power()
|
||||
alpha = min(initial(alpha) + power_charge * 0.02, 255)
|
||||
if(!power_charge)
|
||||
set_light(0)
|
||||
else
|
||||
set_light(max(alpha * 0.02, 1.4), max(alpha * 0.01, 0.1))
|
||||
|
||||
//Vitality Matrix: Drains health from non-servants to heal or even revive servants.
|
||||
/obj/effect/clockwork/sigil/vitality
|
||||
name = "comforting sigil"
|
||||
desc = "A faint blue sigil. Looking at it makes you feel protected."
|
||||
clockwork_desc = "A sigil that will drain non-Servants that remain on it. Servants that remain on it will be healed if it has any vitality drained."
|
||||
icon_state = "sigilvitality"
|
||||
layer = SIGIL_LAYER
|
||||
alpha = 75
|
||||
color = "#123456"
|
||||
affects_servants = TRUE
|
||||
stat_affected = DEAD
|
||||
resist_string = "glows shimmering yellow"
|
||||
sigil_name = "Vitality Matrix"
|
||||
var/revive_cost = 150
|
||||
var/sigil_active = FALSE
|
||||
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
|
||||
var/static/list/damage_heal_order = list(CLONE, TOX, BURN, BRUTE, OXY) //we heal damage in this order
|
||||
|
||||
/obj/effect/clockwork/sigil/vitality/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='[GLOB.clockwork_vitality ? "inathneq_small":"alloy"]'>It has access to <b>[GLOB.ratvar_awakens ? "INFINITE":GLOB.clockwork_vitality]</b> units of vitality.</span>")
|
||||
if(GLOB.ratvar_awakens)
|
||||
to_chat(user, "<span class='inathneq_small'>It can revive Servants at no cost!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='inathneq_small'>It can revive Servants at a cost of <b>[revive_cost]</b> vitality.</span>")
|
||||
|
||||
/obj/effect/clockwork/sigil/vitality/sigil_effects(mob/living/L)
|
||||
if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active)
|
||||
return
|
||||
animate(src, alpha = 255, time = 10, flags = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay.
|
||||
sleep(10)
|
||||
//as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality
|
||||
var/consumed_vitality
|
||||
while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && (GLOB.ratvar_awakens || GLOB.clockwork_vitality))) && get_turf(L) == get_turf(src) && !L.buckled)
|
||||
sigil_active = TRUE
|
||||
if(animation_number >= 4)
|
||||
new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
|
||||
animation_number = 0
|
||||
animation_number++
|
||||
if(!is_servant_of_ratvar(L))
|
||||
var/vitality_drained = 0
|
||||
if(L.stat == DEAD && !consumed_vitality)
|
||||
consumed_vitality = TRUE //Prevent the target from being consumed multiple times
|
||||
vitality_drained = L.maxHealth
|
||||
var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
|
||||
animate(V, alpha = 0, transform = matrix()*2, time = 8)
|
||||
playsound(L, 'sound/magic/wandodeath.ogg', 50, 1)
|
||||
L.visible_message("<span class='warning'>[L] collapses in on [L.p_them()]self as [src] flares bright blue!</span>")
|
||||
to_chat(L, "<span class='inathneq_large'>\"[text2ratvar("Your life will not be wasted.")]\"</span>")
|
||||
for(var/obj/item/W in L)
|
||||
if(!L.dropItemToGround(W))
|
||||
qdel(W)
|
||||
L.dust()
|
||||
else
|
||||
if(!GLOB.ratvar_awakens && L.stat == CONSCIOUS)
|
||||
vitality_drained = L.adjustToxLoss(1)
|
||||
else
|
||||
vitality_drained = L.adjustToxLoss(1.5)
|
||||
if(vitality_drained)
|
||||
GLOB.clockwork_vitality += vitality_drained
|
||||
else
|
||||
break
|
||||
else
|
||||
if(L.stat == DEAD)
|
||||
var/revival_cost = revive_cost
|
||||
if(GLOB.ratvar_awakens || L.suiciding) // No cost if Ratvar is summoned or if you're reviving a convert who suicided
|
||||
revival_cost = 0
|
||||
var/mob/dead/observer/ghost = L.get_ghost(TRUE)
|
||||
if(GLOB.clockwork_vitality >= revival_cost && (ghost || (L.mind && L.mind.active)))
|
||||
if(L.has_status_effect(STATUS_EFFECT_ICHORIAL_STAIN))
|
||||
visible_message("<span class='boldwarning'>[src] strains, but nothing happens...</span>")
|
||||
if(L.pulledby)
|
||||
to_chat(L.pulledby, "<span class='userdanger'>[L] was already revived recently by a vitality matrix! Wait a bit longer!</span>")
|
||||
break
|
||||
else
|
||||
if(ghost)
|
||||
ghost.reenter_corpse()
|
||||
L.revive(1, 1)
|
||||
var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
|
||||
animate(V, alpha = 0, transform = matrix()*2, time = 8)
|
||||
playsound(L, 'sound/magic/staff_healing.ogg', 50, 1)
|
||||
to_chat(L, "<span class='inathneq'>\"[text2ratvar("You will be okay, child.")]\"</span>")
|
||||
L.apply_status_effect(STATUS_EFFECT_ICHORIAL_STAIN)
|
||||
GLOB.clockwork_vitality -= revival_cost
|
||||
break
|
||||
if(!L.client || L.client.is_afk())
|
||||
set waitfor = FALSE
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [L.name], an inactive clock cultist?", ROLE_SERVANT_OF_RATVAR, null, ROLE_SERVANT_OF_RATVAR, 50, L)
|
||||
var/mob/dead/observer/theghost = null
|
||||
if(candidates.len)
|
||||
to_chat(L, "<span class='userdanger'>Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form!</span>")
|
||||
message_admins("[key_name_admin(theghost)] has taken control of ([key_name_admin(L)]) to replace an inactive clock cultist.")
|
||||
L.ghostize(0)
|
||||
L.key = theghost.key
|
||||
var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
|
||||
animate(V, alpha = 0, transform = matrix()*2, time = 8)
|
||||
playsound(L, 'sound/magic/staff_healing.ogg', 50, 1)
|
||||
L.visible_message("<span class='warning'>[L]'s eyes suddenly open wide, gleaming with renewed vigor for the cause!</span>", "<span class='inathneq'>\"[text2ratvar("Awaken!")]\"</span>")
|
||||
break
|
||||
var/vitality_for_cycle = 3
|
||||
if(!GLOB.ratvar_awakens)
|
||||
if(L.stat == CONSCIOUS)
|
||||
vitality_for_cycle = 2
|
||||
vitality_for_cycle = min(GLOB.clockwork_vitality, vitality_for_cycle)
|
||||
var/vitality_used = L.heal_ordered_damage(vitality_for_cycle, damage_heal_order)
|
||||
|
||||
if(!vitality_used)
|
||||
break
|
||||
|
||||
if(!GLOB.ratvar_awakens)
|
||||
GLOB.clockwork_vitality -= vitality_used
|
||||
|
||||
sleep(2)
|
||||
|
||||
if(sigil_active)
|
||||
animation_number = initial(animation_number)
|
||||
sigil_active = FALSE
|
||||
animate(src, alpha = initial(alpha), time = 10, flags = ANIMATION_END_NOW)
|
||||
@@ -1,63 +0,0 @@
|
||||
//massive markers for Revenant and Judgement scripture.
|
||||
/obj/effect/clockwork/general_marker
|
||||
name = "general marker"
|
||||
desc = "Some big guy. For you."
|
||||
clockwork_desc = "One of Ratvar's generals."
|
||||
alpha = 200
|
||||
layer = MASSIVE_OBJ_LAYER
|
||||
|
||||
/obj/effect/clockwork/general_marker/New()
|
||||
..()
|
||||
animate(src, alpha = 0, time = 10)
|
||||
QDEL_IN(src, 10)
|
||||
|
||||
/obj/effect/clockwork/general_marker/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/general_marker/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/general_marker/inathneq
|
||||
name = "Inath-neq, the Resonant Cogwheel"
|
||||
desc = "A humanoid form blazing with blue fire. It radiates an aura of kindness and caring."
|
||||
clockwork_desc = "One of Ratvar's four generals. Before her current form, Inath-neq was a powerful warrior priestess commanding the Resonant Cogs, a sect of Ratvarian warriors renowned for \
|
||||
their prowess. After a lost battle with Nar-Sian cultists, Inath-neq was struck down and stated in her dying breath, \
|
||||
\"The Resonant Cogs shall not fall silent this day, but will come together to form a wheel that shall never stop turning.\" Ratvar, touched by this, granted Inath-neq an eternal body and \
|
||||
merged her soul with those of the Cogs slain with her on the battlefield."
|
||||
icon = 'icons/effects/119x268.dmi'
|
||||
icon_state = "inath-neq"
|
||||
pixel_x = -59
|
||||
pixel_y = -134
|
||||
|
||||
/obj/effect/clockwork/general_marker/nezbere
|
||||
name = "Nezbere, the Brass Eidolon"
|
||||
desc = "A towering colossus clad in nigh-impenetrable brass armor. Its gaze is stern yet benevolent, even upon you."
|
||||
clockwork_desc = "One of Ratvar's four generals. Nezbere is responsible for the design, testing, and creation of everything in Ratvar's domain, and his loyalty to Ratvar knows no bounds. \
|
||||
It is said that Ratvar once asked him to destroy the plans for a weapon Nezbere had made that could have harmed him, and Nezbere responded by not only destroying the plans, \
|
||||
but by taking his own life so that the device could never be replicated. Nezbere's zealotry is unmatched."
|
||||
icon = 'icons/effects/237x321.dmi'
|
||||
icon_state = "nezbere"
|
||||
pixel_x = -118
|
||||
pixel_y = -160
|
||||
|
||||
/obj/effect/clockwork/general_marker/sevtug
|
||||
name = "Sevtug, the Formless Pariah"
|
||||
desc = "A sinister cloud of purple energy. Looking at it gives you a headache."
|
||||
clockwork_desc = "One of Ratvar's four generals. Sevtug taught him how to manipulate minds and is one of his oldest allies. Sevtug serves Ratvar loyally out of a hope that one day, he will \
|
||||
be able to use a moment of weakness in the Justicar to usurp him, but such a day will never come. And so, he serves with dedication, if not necessarily any sort of decorum, never aware he is \
|
||||
the one being made a fool of."
|
||||
icon = 'icons/effects/166x195.dmi'
|
||||
icon_state = "sevtug"
|
||||
pixel_x = -83
|
||||
pixel_y = -97
|
||||
|
||||
/obj/effect/clockwork/general_marker/nzcrentr
|
||||
name = "Nzcrentr, the Eternal Thunderbolt"
|
||||
desc = "A terrifying spiked construct crackling with perpetual lightning."
|
||||
clockwork_desc = "One of Ratvar's four generals. Before becoming one of Ratvar's generals, Nzcrentr sook out any and all sentient life to slaughter it for sport. \
|
||||
Nzcrentr was coerced by Ratvar into entering a shell constructed by Nezbere, ostensibly made to grant Nzcrentr more power. In reality, the shell was made to trap and control it. \
|
||||
Nzcrentr now serves loyally, though even one of Nezbere's finest creations was not enough to totally eliminate its will."
|
||||
icon = 'icons/effects/274x385.dmi'
|
||||
icon_state = "nzcrentr"
|
||||
pixel_x = -137
|
||||
pixel_y = -145
|
||||
@@ -1,41 +0,0 @@
|
||||
//Marks the point at which "no man's land" begins on Reebe. Servants can't pass beyond this point in any way.
|
||||
/obj/effect/clockwork/servant_blocker
|
||||
name = "glowing arrow"
|
||||
desc = "A faintly glowing image of an arrow on the ground. Convenient!"
|
||||
icon_state = "servant_blocker"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
CanAtmosPass = ATMOS_PASS_NO
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/Initialize()
|
||||
. = ..()
|
||||
air_update_turf(TRUE)
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/Destroy(force)
|
||||
if(!force)
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
. = ..()
|
||||
T.air_update_turf(TRUE)
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/CanPass(atom/movable/M, turf/target)
|
||||
var/list/target_contents = M.GetAllContents() + M
|
||||
for(var/mob/living/L in target_contents)
|
||||
if(is_servant_of_ratvar(L) && get_dir(M, src) != dir && L.stat != DEAD) //Unless we're on the side the arrow is pointing directly away from, no-go
|
||||
to_chat(L, "<span class='danger'>The space beyond here can't be accessed by you or other servants.</span>")
|
||||
return
|
||||
if(isitem(M))
|
||||
var/obj/item/I = M
|
||||
if(is_servant_of_ratvar(I.thrownby)) //nice try!
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/BlockSuperconductivity()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/servant_blocker/singularity_pull()
|
||||
return
|
||||
@@ -1,225 +0,0 @@
|
||||
//Spatial gateway: A usually one-way rift to another location.
|
||||
/obj/effect/clockwork/spatial_gateway
|
||||
name = "spatial gateway"
|
||||
desc = "A gently thrumming tear in reality."
|
||||
clockwork_desc = "A gateway in reality."
|
||||
icon_state = "spatial_gateway"
|
||||
density = TRUE
|
||||
light_range = 2
|
||||
light_power = 3
|
||||
light_color = "#6A4D2F"
|
||||
var/sender = TRUE //If this gateway is made for sending, not receiving
|
||||
var/both_ways = FALSE
|
||||
var/lifetime = 25 //How many deciseconds this portal will last
|
||||
var/uses = 1 //How many objects or mobs can go through the portal
|
||||
var/obj/effect/clockwork/spatial_gateway/linked_gateway //The gateway linked to this one
|
||||
var/timerid
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/Initialize()
|
||||
. = ..()
|
||||
addtimer(CALLBACK(src, .proc/check_setup), 1)
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/Destroy()
|
||||
deltimer(timerid)
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/proc/check_setup()
|
||||
if(!linked_gateway)
|
||||
qdel(src)
|
||||
return
|
||||
if(both_ways)
|
||||
clockwork_desc = "A gateway in reality. It can both send and receive objects."
|
||||
else
|
||||
clockwork_desc = "A gateway in reality. It can only [sender ? "send" : "receive"] objects."
|
||||
timerid = QDEL_IN(src, lifetime)
|
||||
|
||||
//set up a gateway with another gateway
|
||||
/obj/effect/clockwork/spatial_gateway/proc/setup_gateway(obj/effect/clockwork/spatial_gateway/gatewayB, set_duration, set_uses, two_way)
|
||||
if(!gatewayB || !set_duration || !uses)
|
||||
return FALSE
|
||||
linked_gateway = gatewayB
|
||||
gatewayB.linked_gateway = src
|
||||
if(two_way)
|
||||
both_ways = TRUE
|
||||
gatewayB.both_ways = TRUE
|
||||
else
|
||||
sender = TRUE
|
||||
gatewayB.sender = FALSE
|
||||
gatewayB.density = FALSE
|
||||
lifetime = set_duration
|
||||
gatewayB.lifetime = set_duration
|
||||
uses = set_uses
|
||||
gatewayB.uses = set_uses
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='brass'>It has [uses] use\s remaining.</span>")
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/attack_ghost(mob/user)
|
||||
if(linked_gateway)
|
||||
user.forceMove(get_turf(linked_gateway))
|
||||
..()
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/attack_hand(mob/living/user)
|
||||
if(!uses)
|
||||
return FALSE
|
||||
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
|
||||
var/mob/living/L = user.pulling
|
||||
if(L.buckled || L.anchored || L.has_buckled_mobs())
|
||||
return FALSE
|
||||
user.visible_message("<span class='warning'>[user] shoves [L] into [src]!</span>", "<span class='danger'>You shove [L] into [src]!</span>")
|
||||
user.stop_pulling()
|
||||
pass_through_gateway(L)
|
||||
return TRUE
|
||||
if(!user.canUseTopic(src))
|
||||
return FALSE
|
||||
user.visible_message("<span class='warning'>[user] climbs through [src]!</span>", "<span class='danger'>You brace yourself and step through [src]...</span>")
|
||||
pass_through_gateway(user)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/nullrod))
|
||||
user.visible_message("<span class='warning'>[user] dispels [src] with [I]!</span>", "<span class='danger'>You close [src] with [I]!</span>")
|
||||
qdel(linked_gateway)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
if(istype(I, /obj/item/clockwork/slab))
|
||||
to_chat(user, "<span class='heavy_brass'>\"I don't think you want to drop your slab into that.\"\n\"If you really want to, try throwing it.\"</span>")
|
||||
return TRUE
|
||||
if(uses && user.dropItemToGround(I))
|
||||
user.visible_message("<span class='warning'>[user] drops [I] into [src]!</span>", "<span class='danger'>You drop [I] into [src]!</span>")
|
||||
pass_through_gateway(I, TRUE)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/ex_act(severity)
|
||||
if(severity == 1 && uses)
|
||||
uses = 0
|
||||
visible_message("<span class='warning'>[src] is disrupted!</span>")
|
||||
animate(src, alpha = 0, transform = matrix()*2, time = 10, flags = ANIMATION_END_NOW)
|
||||
deltimer(timerid)
|
||||
timerid = QDEL_IN(src, 10)
|
||||
linked_gateway.uses = 0
|
||||
linked_gateway.visible_message("<span class='warning'>[linked_gateway] is disrupted!</span>")
|
||||
animate(linked_gateway, alpha = 0, transform = matrix()*2, time = 10, flags = ANIMATION_END_NOW)
|
||||
deltimer(linked_gateway.timerid)
|
||||
linked_gateway.timerid = QDEL_IN(linked_gateway, 10)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/singularity_pull()
|
||||
return
|
||||
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/CollidedWith(atom/movable/AM)
|
||||
..()
|
||||
if(!QDELETED(AM))
|
||||
pass_through_gateway(AM, FALSE)
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/proc/pass_through_gateway(atom/movable/A, no_cost)
|
||||
if(!linked_gateway)
|
||||
qdel(src)
|
||||
return FALSE
|
||||
if(!sender)
|
||||
visible_message("<span class='warning'>[A] bounces off [src]!</span>")
|
||||
return FALSE
|
||||
if(!uses)
|
||||
return FALSE
|
||||
if(isliving(A))
|
||||
var/mob/living/user = A
|
||||
to_chat(user, "<span class='warning'><b>You pass through [src] and appear elsewhere!</b></span>")
|
||||
linked_gateway.visible_message("<span class='warning'>A shape appears in [linked_gateway] before emerging!</span>")
|
||||
playsound(src, 'sound/effects/empulse.ogg', 50, 1)
|
||||
playsound(linked_gateway, 'sound/effects/empulse.ogg', 50, 1)
|
||||
transform = matrix() * 1.5
|
||||
linked_gateway.transform = matrix() * 1.5
|
||||
A.forceMove(get_turf(linked_gateway))
|
||||
if(!no_cost)
|
||||
uses = max(0, uses - 1)
|
||||
linked_gateway.uses = max(0, linked_gateway.uses - 1)
|
||||
if(!uses)
|
||||
animate(src, transform = matrix() * 0.1, time = 10, flags = ANIMATION_END_NOW)
|
||||
animate(linked_gateway, transform = matrix() * 0.1, time = 10, flags = ANIMATION_END_NOW)
|
||||
density = FALSE
|
||||
linked_gateway.density = FALSE
|
||||
else
|
||||
animate(src, transform = matrix() / 1.5, time = 10, flags = ANIMATION_END_NOW)
|
||||
animate(linked_gateway, transform = matrix() / 1.5, time = 10, flags = ANIMATION_END_NOW)
|
||||
addtimer(CALLBACK(src, .proc/check_uses), 10)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/proc/check_uses()
|
||||
if(!uses)
|
||||
qdel(src)
|
||||
qdel(linked_gateway)
|
||||
|
||||
//This proc creates and sets up a gateway from invoker input.
|
||||
/atom/movable/proc/procure_gateway(mob/living/invoker, time_duration, gateway_uses, two_way)
|
||||
var/list/possible_targets = list()
|
||||
var/list/teleportnames = list()
|
||||
|
||||
for(var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/O in GLOB.all_clockwork_objects)
|
||||
if(!O.Adjacent(invoker) && O != src && !is_away_level(O.z) && O.anchored) //don't list obelisks that we're next to
|
||||
var/area/A = get_area(O)
|
||||
var/locname = initial(A.name)
|
||||
possible_targets[avoid_assoc_duplicate_keys("[locname] [O.name]", teleportnames)] = O
|
||||
|
||||
for(var/mob/living/L in GLOB.alive_mob_list)
|
||||
if(!L.stat && is_servant_of_ratvar(L) && !L.Adjacent(invoker) && !is_away_level(L.z)) //People right next to the invoker can't be portaled to, for obvious reasons
|
||||
possible_targets[avoid_assoc_duplicate_keys("[L.name] ([L.real_name])", teleportnames)] = L
|
||||
|
||||
if(!possible_targets.len)
|
||||
to_chat(invoker, "<span class='warning'>There are no other eligible targets for a Spatial Gateway!</span>")
|
||||
return FALSE
|
||||
var/input_target_key = input(invoker, "Choose a target to form a rift to.", "Spatial Gateway") as null|anything in possible_targets
|
||||
var/atom/movable/target = possible_targets[input_target_key]
|
||||
if(!src || !input_target_key || !invoker || !invoker.canUseTopic(src, !issilicon(invoker)) || !is_servant_of_ratvar(invoker) || (isitem(src) && invoker.get_active_held_item() != src) || !invoker.can_speak_vocal())
|
||||
return FALSE //if any of the involved things no longer exist, the invoker is stunned, too far away to use the object, or does not serve ratvar, or if the object is an item and not in the mob's active hand, fail
|
||||
if(!target) //if we have no target, but did have a key, let them retry
|
||||
to_chat(invoker, "<span class='warning'>That target no longer exists!</span>")
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(!is_servant_of_ratvar(L))
|
||||
to_chat(invoker, "<span class='warning'>That target is no longer a Servant!</span>")
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
if(L.stat != CONSCIOUS)
|
||||
to_chat(invoker, "<span class='warning'>That Servant is no longer conscious!</span>")
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
var/istargetobelisk = istype(target, /obj/structure/destructible/clockwork/powered/clockwork_obelisk)
|
||||
var/issrcobelisk = istype(src, /obj/structure/destructible/clockwork/powered/clockwork_obelisk)
|
||||
if(issrcobelisk)
|
||||
if(!anchored)
|
||||
to_chat(invoker, "<span class='warning'>[src] is no longer secured!</span>")
|
||||
return FALSE
|
||||
var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/CO = src //foolish as I am, how I set this proc up makes substypes unfeasible
|
||||
if(CO.active)
|
||||
to_chat(invoker, "<span class='warning'>[src] is now sustaining a gateway!</span>")
|
||||
return FALSE
|
||||
if(istargetobelisk)
|
||||
if(!target.anchored)
|
||||
to_chat(invoker, "<span class='warning'>That [target.name] is no longer secured!</span>")
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
var/obj/structure/destructible/clockwork/powered/clockwork_obelisk/CO = target
|
||||
if(CO.active)
|
||||
to_chat(invoker, "<span class='warning'>That [target.name] is sustaining a gateway, and cannot receive another!</span>")
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
var/efficiency = CO.get_efficiency_mod()
|
||||
gateway_uses = round(gateway_uses * (2 * efficiency), 1)
|
||||
time_duration = round(time_duration * (2 * efficiency), 1)
|
||||
CO.active = TRUE //you'd be active in a second but you should update immediately
|
||||
invoker.visible_message("<span class='warning'>The air in front of [invoker] ripples before suddenly tearing open!</span>", \
|
||||
"<span class='brass'>With a word, you rip open a [two_way ? "two-way":"one-way"] rift to [input_target_key]. It will last for [DisplayTimeText(time_duration)] and has [gateway_uses] use[gateway_uses > 1 ? "s" : ""].</span>")
|
||||
var/obj/effect/clockwork/spatial_gateway/S1 = new(issrcobelisk ? get_turf(src) : get_step(get_turf(invoker), invoker.dir))
|
||||
var/obj/effect/clockwork/spatial_gateway/S2 = new(istargetobelisk ? get_turf(target) : get_step(get_turf(target), target.dir))
|
||||
|
||||
//Set up the portals now that they've spawned
|
||||
S1.setup_gateway(S2, time_duration, gateway_uses, two_way)
|
||||
S2.visible_message("<span class='warning'>The air in front of [target] ripples before suddenly tearing open!</span>")
|
||||
return TRUE
|
||||
@@ -1,53 +0,0 @@
|
||||
//horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
|
||||
/atom/movable/proc/power_drain(clockcult_user)
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(cell)
|
||||
return cell.power_drain(clockcult_user)
|
||||
return 0
|
||||
|
||||
/obj/item/melee/baton/power_drain(clockcult_user) //balance memes
|
||||
return 0
|
||||
|
||||
/obj/item/gun/power_drain(clockcult_user) //balance memes
|
||||
return 0
|
||||
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user)
|
||||
if(cell && cell.charge)
|
||||
playsound(src, "sparks", 50, 1)
|
||||
flick("apc-spark", src)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*3)
|
||||
cell.use(.) //Better than a power sink!
|
||||
if(!cell.charge && !shorted)
|
||||
shorted = 1
|
||||
visible_message("<span class='warning'>The [name]'s screen blurs with static.</span>")
|
||||
update()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*3)
|
||||
charge -= . * 50
|
||||
if(!charge && !panel_open)
|
||||
panel_open = TRUE
|
||||
icon_state = "[initial(icon_state)]-o"
|
||||
do_sparks(10, FALSE, src)
|
||||
visible_message("<span class='warning'>[src]'s panel flies open with a flurry of sparks!</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*3)
|
||||
charge = use(.)
|
||||
update_icon()
|
||||
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user)
|
||||
if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
|
||||
/obj/mecha/power_drain(clockcult_user)
|
||||
if((!clockcult_user || (occupant && !is_servant_of_ratvar(occupant))) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
@@ -1,41 +0,0 @@
|
||||
//returns a component spanclass from a component id
|
||||
/proc/get_component_span(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return "neovgre"
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return "inathneq"
|
||||
if(GEIS_CAPACITOR)
|
||||
return "sevtug"
|
||||
if(REPLICANT_ALLOY)
|
||||
return "nezbere"
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return "nzcrentr"
|
||||
else
|
||||
return "brass"
|
||||
|
||||
//returns a component color from a component id, but with brighter colors for the darkest
|
||||
/proc/get_component_color_bright(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return "#880020"
|
||||
if(REPLICANT_ALLOY)
|
||||
return "#5A6068"
|
||||
else
|
||||
return get_component_color(id)
|
||||
|
||||
//returns a component color from a component id
|
||||
/proc/get_component_color(id)
|
||||
switch(id)
|
||||
if(BELLIGERENT_EYE)
|
||||
return "#6E001A"
|
||||
if(VANGUARD_COGWHEEL)
|
||||
return "#1E8CE1"
|
||||
if(GEIS_CAPACITOR)
|
||||
return "#AF0AAF"
|
||||
if(REPLICANT_ALLOY)
|
||||
return "#42474D"
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
return "#DAAA18"
|
||||
else
|
||||
return "#BE8700"
|
||||
@@ -1,347 +0,0 @@
|
||||
//For the clockwork fabricator, this proc exists to make it easy to customize what the fabricator does when hitting something.
|
||||
|
||||
//if a valid target, returns an associated list in this format;
|
||||
//list("operation_time" = 15, "new_obj_type" = /obj/structure/window/reinforced/clockwork, "power_cost" = 5, "spawn_dir" = dir, "dir_in_new" = TRUE)
|
||||
//otherwise, return literally any non-list thing but preferably FALSE
|
||||
//returning TRUE won't produce the "cannot be fabricated" message and will still prevent fabrication
|
||||
|
||||
/atom/proc/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
/atom/proc/consume_visual(obj/item/clockwork/replica_fabricator/fabricator, power_amount)
|
||||
if(get_clockwork_power(power_amount))
|
||||
var/obj/effect/temp_visual/ratvar/beam/itemconsume/B = new /obj/effect/temp_visual/ratvar/beam/itemconsume(get_turf(src))
|
||||
B.pixel_x = pixel_x
|
||||
B.pixel_y = pixel_y
|
||||
|
||||
//Turf conversion
|
||||
/turf/closed/wall/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //four sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 4), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //two sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/iron/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //two sheets of metal, five rods
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2) - (POWER_ROD * 5), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/cult/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //no metal
|
||||
return list("operation_time" = 80, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/r_wall/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
/turf/closed/wall/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/open/floor/clockwork, "power_cost" = -POWER_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/open/floor/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
if(floor_tile == /obj/item/stack/tile/plasteel)
|
||||
new floor_tile(src)
|
||||
make_plating()
|
||||
playsound(src, 'sound/items/crowbar.ogg', 10, 1) //clink
|
||||
return list("operation_time" = 30, "new_obj_type" = /turf/open/floor/clockwork, "power_cost" = POWER_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/open/floor/plating/asteroid/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/plating/ashplanet/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
/turf/open/lava/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
if(locate(/obj/structure/table) in src)
|
||||
return FALSE
|
||||
if(locate(/obj/structure/falsewall) in contents)
|
||||
to_chat(user, "<span class='warning'>There is a false wall in the way, preventing you from fabricating a clockwork wall on [src].</span>")
|
||||
return
|
||||
if(is_blocked_turf(src, TRUE))
|
||||
to_chat(user, "<span class='warning'>Something is in the way, preventing you from fabricating a clockwork wall on [src].</span>")
|
||||
return TRUE
|
||||
var/operation_time = 100
|
||||
if(!GLOB.ratvar_awakens && fabricator.speed_multiplier > 0) //if ratvar isn't awake, this always takes 10 seconds
|
||||
operation_time /= fabricator.speed_multiplier
|
||||
return list("operation_time" = operation_time, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
//False wall conversion
|
||||
/obj/structure/falsewall/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
var/cost = POWER_WALL_MINUS_FLOOR
|
||||
if(ispath(mineral, /obj/item/stack/sheet/metal))
|
||||
cost -= (POWER_METAL * (2 + mineral_amount)) //four sheets of metal, plus an assumption that the girder is also two
|
||||
else
|
||||
cost -= (POWER_METAL * 2) //anything that doesn't use metal just has the girder
|
||||
return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "power_cost" = cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/falsewall/iron/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent) //two sheets of metal, two rods; special assumption
|
||||
return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "power_cost" = POWER_WALL_MINUS_FLOOR - (POWER_METAL * 2) - (POWER_ROD * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/falsewall/reinforced/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/falsewall/brass/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
//Metal conversion
|
||||
/obj/item/stack/tile/plasteel/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
if(source)
|
||||
return FALSE
|
||||
var/amount_temp = get_amount()
|
||||
var/no_delete = FALSE
|
||||
if(amount_temp < 2)
|
||||
to_chat(user, "<span class='warning'>You need at least <b>2</b> floor tiles to convert into power.</span>")
|
||||
return TRUE
|
||||
if(ISODD(amount_temp))
|
||||
amount_temp--
|
||||
no_delete = TRUE
|
||||
use(amount_temp)
|
||||
amount_temp *= 12.5 //each tile is 12.5 power so this is 2 tiles to 25 power
|
||||
consume_visual(fabricator, amount_temp)
|
||||
return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = -amount_temp, "spawn_dir" = SOUTH, "no_target_deletion" = no_delete)
|
||||
|
||||
/obj/item/stack/rods/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
if(source)
|
||||
return FALSE
|
||||
var/power_amount = -(amount*POWER_ROD)
|
||||
consume_visual(fabricator, power_amount)
|
||||
return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = power_amount, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/stack/sheet/metal/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
if(source)
|
||||
return FALSE
|
||||
var/power_amount = -(amount*POWER_METAL)
|
||||
consume_visual(fabricator, power_amount)
|
||||
return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = power_amount, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/stack/sheet/plasteel/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
if(source)
|
||||
return FALSE
|
||||
var/power_amount = -(amount*POWER_PLASTEEL)
|
||||
consume_visual(fabricator, power_amount)
|
||||
return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = power_amount, "spawn_dir" = SOUTH)
|
||||
|
||||
//Brass directly to power
|
||||
/obj/item/stack/tile/brass/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
if(source)
|
||||
return FALSE
|
||||
var/power_amount = -(amount*POWER_FLOOR)
|
||||
consume_visual(fabricator, power_amount)
|
||||
return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = power_amount, "spawn_dir" = SOUTH)
|
||||
|
||||
//Airlock conversion
|
||||
/obj/machinery/door/airlock/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
var/doortype = /obj/machinery/door/airlock/clockwork
|
||||
if(glass)
|
||||
doortype = /obj/machinery/door/airlock/clockwork/brass
|
||||
return list("operation_time" = 60, "new_obj_type" = doortype, "power_cost" = POWER_WALL_TOTAL, "spawn_dir" = dir, "transfer_name" = TRUE)
|
||||
|
||||
/obj/machinery/door/airlock/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
//Table conversion
|
||||
/obj/structure/table/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
var/fabrication_cost = POWER_STANDARD
|
||||
if(framestack == /obj/item/stack/rods)
|
||||
fabrication_cost -= POWER_ROD*framestackamount
|
||||
else if(framestack == /obj/item/stack/tile/brass)
|
||||
fabrication_cost -= POWER_FLOOR*framestackamount
|
||||
if(buildstack == /obj/item/stack/sheet/metal)
|
||||
fabrication_cost -= POWER_METAL*buildstackamount
|
||||
else if(buildstack == /obj/item/stack/sheet/plasteel)
|
||||
fabrication_cost -= POWER_PLASTEEL*buildstackamount
|
||||
return list("operation_time" = 20, "new_obj_type" = /obj/structure/table/reinforced/brass, "power_cost" = fabrication_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/table/reinforced/brass/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/table_frame/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
var/fabrication_cost = POWER_FLOOR
|
||||
if(framestack == /obj/item/stack/rods)
|
||||
fabrication_cost -= POWER_ROD*framestackamount
|
||||
else if(framestack == /obj/item/stack/tile/brass)
|
||||
fabrication_cost -= POWER_FLOOR*framestackamount
|
||||
return list("operation_time" = 10, "new_obj_type" = /obj/structure/table_frame/brass, "power_cost" = fabrication_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/table_frame/brass/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
//Window conversion
|
||||
/obj/structure/window/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
var/windowtype = /obj/structure/window/reinforced/clockwork
|
||||
var/new_dir = TRUE
|
||||
var/fabrication_time = 15
|
||||
var/fabrication_cost = POWER_FLOOR
|
||||
if(fulltile)
|
||||
windowtype = /obj/structure/window/reinforced/clockwork/fulltile
|
||||
new_dir = FALSE
|
||||
fabrication_time = 30
|
||||
fabrication_cost = POWER_STANDARD
|
||||
if(reinf)
|
||||
fabrication_cost -= POWER_ROD
|
||||
if(reinf)
|
||||
fabrication_cost -= POWER_ROD
|
||||
for(var/obj/structure/grille/G in get_turf(src))
|
||||
INVOKE_ASYNC(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricate, G, user)
|
||||
return list("operation_time" = fabrication_time, "new_obj_type" = windowtype, "power_cost" = fabrication_cost, "spawn_dir" = dir, "dir_in_new" = new_dir)
|
||||
|
||||
/obj/structure/window/reinforced/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
//Windoor conversion
|
||||
/obj/machinery/door/window/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return list("operation_time" = 30, "new_obj_type" = /obj/machinery/door/window/clockwork, "power_cost" = POWER_STANDARD, "spawn_dir" = dir, "dir_in_new" = TRUE, "transfer_name" = TRUE)
|
||||
|
||||
/obj/machinery/door/window/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
//Grille conversion
|
||||
/obj/structure/grille/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
var/grilletype = /obj/structure/grille/ratvar
|
||||
var/fabrication_time = 15
|
||||
if(broken)
|
||||
grilletype = /obj/structure/grille/ratvar/broken
|
||||
fabrication_time = 5
|
||||
return list("operation_time" = fabrication_time, "new_obj_type" = grilletype, "power_cost" = 0, "spawn_dir" = dir)
|
||||
|
||||
/obj/structure/grille/ratvar/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
//Lattice conversion
|
||||
/obj/structure/lattice/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/structure/lattice/clockwork, "power_cost" = 0, "spawn_dir" = SOUTH, "no_target_deletion" = TRUE)
|
||||
|
||||
/obj/structure/lattice/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
ratvar_act() //just in case we're the wrong type for some reason??
|
||||
return FALSE
|
||||
|
||||
/obj/structure/lattice/catwalk/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/structure/lattice/catwalk/clockwork, "power_cost" = 0, "spawn_dir" = SOUTH, "no_target_deletion" = TRUE)
|
||||
|
||||
/obj/structure/lattice/catwalk/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
return FALSE
|
||||
|
||||
//Girder conversion
|
||||
/obj/structure/girder/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
var/fabrication_cost = POWER_GEAR - (POWER_METAL * 2)
|
||||
if(state == GIRDER_REINF_STRUTS || state == GIRDER_REINF)
|
||||
fabrication_cost -= POWER_PLASTEEL
|
||||
return list("operation_time" = 20, "new_obj_type" = /obj/structure/destructible/clockwork/wall_gear, "power_cost" = fabrication_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
//Hitting a clockwork structure will try to repair it.
|
||||
/obj/structure/destructible/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
. = TRUE
|
||||
var/list/repair_values = list()
|
||||
if(!fabricator.fabricator_repair_checks(repair_values, src, user))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [fabricator.name] starts covering [src] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairing [src]...</span>")
|
||||
fabricator.repairing = src
|
||||
while(fabricator && user && src)
|
||||
if(!do_after(user, repair_values["healing_for_cycle"] * fabricator.speed_multiplier, target = src, \
|
||||
extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE)))
|
||||
break
|
||||
obj_integrity = CLAMP(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
|
||||
adjust_clockwork_power(-repair_values["power_required"])
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
if(fabricator)
|
||||
fabricator.repairing = null
|
||||
if(user)
|
||||
user.visible_message("<span class='notice'>[user]'s [fabricator.name] stops covering [src] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairing [src]. It is now at <b>[obj_integrity]/[max_integrity]</b> integrity.</span>")
|
||||
|
||||
//Fabricator mob heal proc, to avoid as much copypaste as possible.
|
||||
/mob/living/proc/fabricator_heal(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator)
|
||||
var/list/repair_values = list()
|
||||
if(!fabricator.fabricator_repair_checks(repair_values, src, user))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [fabricator.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairin[src == user ? "g yourself" : "g [src]"]...</span>")
|
||||
fabricator.repairing = src
|
||||
while(fabricator && user && src)
|
||||
if(!do_after(user, repair_values["healing_for_cycle"] * fabricator.speed_multiplier, target = src, \
|
||||
extra_checks = CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricator_repair_checks, repair_values, src, user, TRUE)))
|
||||
break
|
||||
fabricator_heal_tick(repair_values["healing_for_cycle"])
|
||||
adjust_clockwork_power(-repair_values["power_required"])
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
if(fabricator)
|
||||
fabricator.repairing = null
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/fabricator_heal_tick(amount)
|
||||
var/static/list/damage_heal_order = list(BRUTE, BURN, TOX, OXY)
|
||||
heal_ordered_damage(amount, damage_heal_order)
|
||||
|
||||
/mob/living/simple_animal/fabricator_heal_tick(amount)
|
||||
adjustHealth(-amount)
|
||||
|
||||
//Hitting a ratvar'd silicon will also try to repair it.
|
||||
/mob/living/silicon/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
. = TRUE
|
||||
if(health == maxHealth) //if we're at maximum health, replace the turf under us
|
||||
return FALSE
|
||||
else if(fabricator_heal(user, fabricator) && user)
|
||||
user.visible_message("<span class='notice'>[user]'s [fabricator.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself. You are":"g [src]. [p_they(TRUE)] [p_are()]"] now at <b>[abs(HEALTH_THRESHOLD_DEAD - health)]/[abs(HEALTH_THRESHOLD_DEAD - maxHealth)]</b> health.</span>")
|
||||
|
||||
//Same with clockwork mobs.
|
||||
/mob/living/simple_animal/hostile/clockwork/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
. = TRUE
|
||||
if(health == maxHealth) //if we're at maximum health, replace the turf under us
|
||||
return FALSE
|
||||
else if(fabricator_heal(user, fabricator) && user)
|
||||
user.visible_message("<span class='notice'>[user]'s [fabricator.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself. You are":"g [src]. [p_they(TRUE)] [p_are()]"] now at <b>[health]/[maxHealth]</b> health.</span>")
|
||||
|
||||
//Cogscarabs get special interaction because they're drones and have innate self-heals/revives.
|
||||
/mob/living/simple_animal/drone/cogscarab/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent)
|
||||
. = TRUE
|
||||
if(stat == DEAD)
|
||||
try_reactivate(user) //if we're dead, try to repair us
|
||||
return
|
||||
if(health == maxHealth)
|
||||
return FALSE
|
||||
else if(!(flags_1 & GODMODE))
|
||||
user.visible_message("<span class='notice'>[user]'s [fabricator.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairin[src == user ? "g yourself" : "g [src]"]...</span>")
|
||||
fabricator.repairing = src
|
||||
if(do_after(user, (maxHealth - health)*2, target=src))
|
||||
adjustHealth(-maxHealth)
|
||||
user.visible_message("<span class='notice'>[user]'s [fabricator.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself" : "g [src]"].</span>")
|
||||
if(fabricator)
|
||||
fabricator.repairing = null
|
||||
|
||||
//Convert shards and gear bits directly to power
|
||||
/obj/item/clockwork/alloy_shards/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent, power_amount)
|
||||
if(!power_amount)
|
||||
power_amount = -POWER_STANDARD
|
||||
consume_visual(fabricator, power_amount)
|
||||
if(!silent) //looper no looping
|
||||
for(var/obj/item/clockwork/alloy_shards/S in get_turf(src)) //convert all other shards in the turf if we can
|
||||
if(S == src)
|
||||
continue //we want the shards to be fabricated after the main shard, thus this delay
|
||||
addtimer(CALLBACK(fabricator, /obj/item/clockwork/replica_fabricator.proc/fabricate, S, user, TRUE), 0)
|
||||
return list("operation_time" = 0, "new_obj_type" = null, "power_cost" = power_amount, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit/large/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent, power_amount)
|
||||
if(!power_amount)
|
||||
power_amount = -(CLOCKCULT_POWER_UNIT*0.08)
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/alloy_shards/large/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent, power_amount)
|
||||
if(!power_amount)
|
||||
power_amount = -(CLOCKCULT_POWER_UNIT*0.06)
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent, power_amount)
|
||||
if(!power_amount)
|
||||
power_amount = -(CLOCKCULT_POWER_UNIT*0.04)
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/alloy_shards/small/fabrication_vals(mob/living/user, obj/item/clockwork/replica_fabricator/fabricator, silent, power_amount)
|
||||
if(!power_amount)
|
||||
power_amount = -(CLOCKCULT_POWER_UNIT*0.02)
|
||||
return ..()
|
||||
@@ -1,50 +0,0 @@
|
||||
//Sends a string to all servants and optionally ghosts, who will get a follow link to whatever is provided as the target.
|
||||
/proc/hierophant_message(message, servantsonly, atom/target)
|
||||
if(!message)
|
||||
return FALSE
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(!servantsonly && isobserver(M))
|
||||
if(target)
|
||||
var/link = FOLLOW_LINK(M, target)
|
||||
to_chat(M, "[link] [message]")
|
||||
else
|
||||
to_chat(M, message)
|
||||
else if(is_servant_of_ratvar(M))
|
||||
to_chat(M, message)
|
||||
return TRUE
|
||||
|
||||
//Sends a titled message from a mob to all servants of ratvar and ghosts.
|
||||
/proc/titled_hierophant_message(mob/user, message, name_span = "heavy_brass", message_span = "brass", user_title = "Servant")
|
||||
if(!user || !message)
|
||||
return FALSE
|
||||
var/parsed_message = "<span class='[name_span]'>[user_title ? "[user_title] ":""][findtextEx(user.name, user.real_name) ? user.name : "[user.real_name] (as [user.name])"]: \
|
||||
</span><span class='[message_span]'>\"[message]\"</span>"
|
||||
hierophant_message(parsed_message, FALSE, user)
|
||||
return TRUE
|
||||
|
||||
//Hierophant Network action, allows a servant with it to communicate to other servants.
|
||||
/datum/action/innate/hierophant
|
||||
name = "Hierophant Network"
|
||||
desc = "Allows you to communicate with other Servants."
|
||||
icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
|
||||
button_icon_state = "hierophant"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/title = "Servant"
|
||||
var/span_for_name = "heavy_brass"
|
||||
var/span_for_message = "brass"
|
||||
|
||||
/datum/action/innate/hierophant/IsAvailable()
|
||||
if(!is_servant_of_ratvar(owner))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/hierophant/Activate()
|
||||
var/input = stripped_input(usr, "Please enter a message to send to other servants.", "Hierophant Network", "")
|
||||
if(!input || !IsAvailable())
|
||||
return
|
||||
if(ishuman(owner))
|
||||
clockwork_say(owner, "[text2ratvar("Servants, hear my words: [input]")]", TRUE)
|
||||
log_talk(owner,"CLOCK:[key_name(owner)] : [input]",LOGSAY)
|
||||
titled_hierophant_message(owner, input, span_for_name, span_for_message, title)
|
||||
@@ -1,28 +0,0 @@
|
||||
//Helper procs for clockwork power, used by structures and items and that kind of jazz.
|
||||
|
||||
/proc/get_clockwork_power(amount) //If no amount is provided, returns the clockwork power; otherwise, returns if there's enough power for that amount.
|
||||
return amount ? GLOB.clockwork_power >= amount : GLOB.clockwork_power
|
||||
|
||||
/proc/adjust_clockwork_power(amount) //Adjusts the global clockwork power by this amount (min 0.)
|
||||
if(GLOB.ratvar_approaches)
|
||||
amount *= 0.75 //The herald's beacon reduces power costs by 25% across the board!
|
||||
GLOB.clockwork_power = GLOB.ratvar_awakens ? INFINITY : max(0, GLOB.clockwork_power + amount)
|
||||
for(var/obj/effect/clockwork/sigil/transmission/T in GLOB.all_clockwork_objects)
|
||||
T.update_icon()
|
||||
var/power_overwhelming = GLOB.clockwork_power
|
||||
var/unlock_message
|
||||
if(power_overwhelming >= SCRIPT_UNLOCK_THRESHOLD && !GLOB.script_scripture_unlocked)
|
||||
GLOB.script_scripture_unlocked = TRUE
|
||||
unlock_message = "<span class='large_brass bold'>The Ark swells as a key power threshold is reached. Script scriptures are now available.</span>"
|
||||
if(power_overwhelming >= APPLICATION_UNLOCK_THRESHOLD && !GLOB.application_scripture_unlocked)
|
||||
GLOB.application_scripture_unlocked = TRUE
|
||||
unlock_message = "<span class='large_brass bold'>The Ark surges as a key power threshold is reached. Application scriptures are now available.</span>"
|
||||
if(GLOB.servants_active)
|
||||
hierophant_message(unlock_message)
|
||||
return TRUE
|
||||
|
||||
/proc/can_access_clockwork_power(atom/movable/access_point, amount) //Returns true if the access point has access to clockwork power (and optionally, a number of watts for it)
|
||||
if(amount && !get_clockwork_power(amount)) //No point in trying if we don't have the power anyway
|
||||
return
|
||||
var/list/possible_conduits = view(5, access_point)
|
||||
return locate(/obj/effect/clockwork/sigil/transmission) in possible_conduits || GLOB.ratvar_awakens
|
||||
@@ -1,393 +0,0 @@
|
||||
//For the clockwork proselytizer, this proc exists to make it easy to customize what the proselytizer does when hitting something.
|
||||
|
||||
//if a valid target, returns an associated list in this format;
|
||||
//list("operation_time" = 15, "new_obj_type" = /obj/structure/window/reinforced/clockwork, "power_cost" = 5, "spawn_dir" = dir, "dir_in_new" = TRUE)
|
||||
//otherwise, return literally any non-list thing but preferably FALSE
|
||||
//returning TRUE won't produce the "cannot be proselytized" message and will still prevent proselytizing
|
||||
|
||||
/atom/proc/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Turf conversion
|
||||
/turf/closed/wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //four sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 4), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/iron/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal, five rods
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2) - (POWER_ROD * 5), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/cult/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //no metal
|
||||
return list("operation_time" = 80, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/shuttle/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/r_wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/closed/wall/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/open/floor/clockwork, "power_cost" = -POWER_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/open/floor/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(floor_tile == /obj/item/stack/tile/plasteel)
|
||||
new floor_tile(src)
|
||||
make_plating()
|
||||
playsound(src, 'sound/items/Crowbar.ogg', 10, 1) //clink
|
||||
return list("operation_time" = 30, "new_obj_type" = /turf/open/floor/clockwork, "power_cost" = POWER_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/open/floor/plating/asteroid/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/plating/ashplanet/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/plating/lava/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(locate(/obj/structure/table) in src)
|
||||
return FALSE
|
||||
if(locate(/obj/structure/falsewall) in contents)
|
||||
to_chat(user, "<span class='warning'>There is a false wall in the way, preventing you from proselytizing [src] into a clockwork wall.</span>")
|
||||
return
|
||||
if(is_blocked_turf(src, TRUE))
|
||||
to_chat(user, "<span class='warning'>Something is in the way, preventing you from proselytizing [src] into a clockwork wall.</span>")
|
||||
return TRUE
|
||||
var/operation_time = 100
|
||||
if(proselytizer.speed_multiplier > 0)
|
||||
operation_time /= proselytizer.speed_multiplier
|
||||
return list("operation_time" = operation_time, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
//False wall conversion
|
||||
/obj/structure/falsewall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/cost = POWER_WALL_MINUS_FLOOR
|
||||
if(ispath(mineral, /obj/item/stack/sheet/metal))
|
||||
cost -= (POWER_METAL * (2 + mineral_amount)) //four sheets of metal, plus an assumption that the girder is also two
|
||||
else
|
||||
cost -= (POWER_METAL * 2) //anything that doesn't use metal just has the girder
|
||||
return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "power_cost" = cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/falsewall/iron/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal, two rods; special assumption
|
||||
return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "power_cost" = POWER_WALL_MINUS_FLOOR - (POWER_METAL * 2) - (POWER_ROD * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/falsewall/reinforced/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/falsewall/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Metal conversion
|
||||
/obj/item/stack/tile/plasteel/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
var/amount_temp = get_amount()
|
||||
if(proselytizer.metal_to_power)
|
||||
var/no_delete = FALSE
|
||||
if(amount_temp < 2)
|
||||
to_chat(user, "<span class='warning'>You need at least <b>2</b> floor tiles to convert into power.</span>")
|
||||
return TRUE
|
||||
if(IsOdd(amount_temp))
|
||||
amount_temp--
|
||||
no_delete = TRUE
|
||||
use(amount_temp)
|
||||
amount_temp *= 12.5 //each tile is 12.5 power so this is 2 tiles to 25 power
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -amount_temp, "spawn_dir" = SOUTH, "no_target_deletion" = no_delete)
|
||||
if(amount_temp >= 20)
|
||||
var/sheets_to_make = round(amount_temp * 0.05) //and 20 to 1 brass
|
||||
var/used = sheets_to_make * 20
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need at least <b>20</b> floor tiles to convert into brass.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/rods/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
if(proselytizer.metal_to_power)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_ROD), "spawn_dir" = SOUTH)
|
||||
if(get_amount() >= 10)
|
||||
var/sheets_to_make = round(get_amount() * 0.1)
|
||||
var/used = sheets_to_make * 10
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need at least <b>10</b> rods to convert into brass.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/sheet/metal/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
if(proselytizer.metal_to_power)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_METAL), "spawn_dir" = SOUTH)
|
||||
if(get_amount() >= 5)
|
||||
var/sheets_to_make = round(get_amount() * 0.2)
|
||||
var/used = sheets_to_make * 5
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need at least <b>5</b> sheets of metal to convert into brass.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/sheet/plasteel/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
if(proselytizer.metal_to_power)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_PLASTEEL), "spawn_dir" = SOUTH)
|
||||
if(get_amount() >= 2)
|
||||
var/sheets_to_make = round(get_amount() * 0.5)
|
||||
var/used = sheets_to_make * 2
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need at least <b>2</b> sheets of plasteel to convert into brass.</span>")
|
||||
return TRUE
|
||||
|
||||
//Brass directly to power
|
||||
/obj/item/stack/tile/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_FLOOR), "spawn_dir" = SOUTH)
|
||||
|
||||
//Airlock conversion
|
||||
/obj/machinery/door/airlock/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/doortype = /obj/machinery/door/airlock/clockwork
|
||||
if(glass)
|
||||
doortype = /obj/machinery/door/airlock/clockwork/brass
|
||||
return list("operation_time" = 60, "new_obj_type" = doortype, "power_cost" = POWER_WALL_TOTAL, "spawn_dir" = dir)
|
||||
|
||||
/obj/machinery/door/airlock/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Table conversion
|
||||
/obj/structure/table/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/prosel_cost = POWER_STANDARD
|
||||
if(framestack == /obj/item/stack/rods)
|
||||
prosel_cost -= POWER_ROD*framestackamount
|
||||
else if(framestack == /obj/item/stack/tile/brass)
|
||||
prosel_cost -= POWER_FLOOR*framestackamount
|
||||
if(buildstack == /obj/item/stack/sheet/metal)
|
||||
prosel_cost -= POWER_METAL*buildstackamount
|
||||
else if(buildstack == /obj/item/stack/sheet/plasteel)
|
||||
prosel_cost -= POWER_PLASTEEL*buildstackamount
|
||||
return list("operation_time" = 20, "new_obj_type" = /obj/structure/table/reinforced/brass, "power_cost" = prosel_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/table/reinforced/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/table_frame/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/prosel_cost = POWER_FLOOR
|
||||
if(framestack == /obj/item/stack/rods)
|
||||
prosel_cost -= POWER_ROD*framestackamount
|
||||
else if(framestack == /obj/item/stack/tile/brass)
|
||||
prosel_cost -= POWER_FLOOR*framestackamount
|
||||
return list("operation_time" = 10, "new_obj_type" = /obj/structure/table_frame/brass, "power_cost" = prosel_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/table_frame/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Window conversion
|
||||
/obj/structure/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/windowtype = /obj/structure/window/reinforced/clockwork
|
||||
var/new_dir = TRUE
|
||||
var/prosel_time = 15
|
||||
var/prosel_cost = POWER_FLOOR
|
||||
if(fulltile)
|
||||
windowtype = /obj/structure/window/reinforced/clockwork/fulltile
|
||||
new_dir = FALSE
|
||||
prosel_time = 30
|
||||
prosel_cost = POWER_STANDARD
|
||||
if(reinf)
|
||||
prosel_cost -= POWER_ROD
|
||||
if(reinf)
|
||||
prosel_cost -= POWER_ROD
|
||||
for(var/obj/structure/grille/G in get_turf(src))
|
||||
INVOKE_ASYNC(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytize, G, user)
|
||||
return list("operation_time" = prosel_time, "new_obj_type" = windowtype, "power_cost" = prosel_cost, "spawn_dir" = dir, "dir_in_new" = new_dir)
|
||||
|
||||
/obj/structure/window/reinforced/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Windoor conversion
|
||||
/obj/machinery/door/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 30, "new_obj_type" = /obj/machinery/door/window/clockwork, "power_cost" = POWER_STANDARD, "spawn_dir" = dir, "dir_in_new" = TRUE)
|
||||
|
||||
/obj/machinery/door/window/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Grille conversion
|
||||
/obj/structure/grille/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/grilletype = /obj/structure/grille/ratvar
|
||||
var/prosel_time = 15
|
||||
if(broken)
|
||||
grilletype = /obj/structure/grille/ratvar/broken
|
||||
prosel_time = 5
|
||||
return list("operation_time" = prosel_time, "new_obj_type" = grilletype, "power_cost" = 0, "spawn_dir" = dir)
|
||||
|
||||
/obj/structure/grille/ratvar/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Lattice conversion
|
||||
/obj/structure/lattice/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/structure/lattice/clockwork, "power_cost" = 0, "spawn_dir" = SOUTH, "no_target_deletion" = TRUE)
|
||||
|
||||
/obj/structure/lattice/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
ratvar_act() //just in case we're the wrong type for some reason??
|
||||
return FALSE
|
||||
|
||||
/obj/structure/lattice/catwalk/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/structure/lattice/catwalk/clockwork, "power_cost" = 0, "spawn_dir" = SOUTH, "no_target_deletion" = TRUE)
|
||||
|
||||
/obj/structure/lattice/catwalk/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Girder conversion
|
||||
/obj/structure/girder/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/prosel_cost = POWER_GEAR - (POWER_METAL * 2)
|
||||
if(state == GIRDER_REINF_STRUTS || state == GIRDER_REINF)
|
||||
prosel_cost -= POWER_PLASTEEL
|
||||
return list("operation_time" = 20, "new_obj_type" = /obj/structure/destructible/clockwork/wall_gear, "power_cost" = prosel_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
//Hitting a clockwork structure will try to repair it.
|
||||
/obj/structure/destructible/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
var/list/repair_values = list()
|
||||
if(!proselytizer.proselytizer_repair_checks(repair_values, src, user))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts covering [src] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairing [src]...</span>")
|
||||
proselytizer.repairing = src
|
||||
while(proselytizer && user && src)
|
||||
if(!do_after(user, repair_values["healing_for_cycle"] * proselytizer.speed_multiplier, target = src, \
|
||||
extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytizer_repair_checks, repair_values, src, user, TRUE)))
|
||||
break
|
||||
obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
|
||||
proselytizer.modify_stored_power(-repair_values["power_required"])
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
if(proselytizer)
|
||||
proselytizer.repairing = null
|
||||
if(user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops covering [src] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairing [src]. It is now at <b>[obj_integrity]/[max_integrity]</b> integrity.</span>")
|
||||
|
||||
//Hitting a sigil of transmission will try to charge from it.
|
||||
/obj/effect/clockwork/sigil/transmission/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
var/list/charge_values = list()
|
||||
if(!proselytizer.sigil_charge_checks(charge_values, src, user))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts draining glowing orange energy from [src]...</span>", \
|
||||
"<span class='alloy'>You start recharging your [proselytizer.name]...</span>")
|
||||
proselytizer.recharging = src
|
||||
while(proselytizer && user && src)
|
||||
if(!do_after(user, 10, target = src, extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/sigil_charge_checks, charge_values, src, user, TRUE)))
|
||||
break
|
||||
modify_charge(charge_values["power_gain"])
|
||||
proselytizer.modify_stored_power(charge_values["power_gain"])
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', charge_values["power_gain"] * 0.1, 1)
|
||||
|
||||
if(proselytizer)
|
||||
proselytizer.recharging = null
|
||||
if(user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops draining glowing orange energy from [src].</span>", \
|
||||
"<span class='alloy'>You finish recharging your [proselytizer.name]. It now contains <b>[proselytizer.get_power()]W/[proselytizer.get_max_power()]W</b> power.</span>")
|
||||
|
||||
//Proselytizer mob heal proc, to avoid as much copypaste as possible.
|
||||
/mob/living/proc/proselytizer_heal(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/list/repair_values = list()
|
||||
if(!proselytizer.proselytizer_repair_checks(repair_values, src, user))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairin[src == user ? "g yourself" : "g [src]"]...</span>")
|
||||
proselytizer.repairing = src
|
||||
while(proselytizer && user && src)
|
||||
if(!do_after(user, repair_values["healing_for_cycle"] * proselytizer.speed_multiplier, target = src, \
|
||||
extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytizer_repair_checks, repair_values, src, user, TRUE)))
|
||||
break
|
||||
proselytizer_heal_tick(repair_values["healing_for_cycle"])
|
||||
proselytizer.modify_stored_power(-repair_values["power_required"])
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
if(proselytizer)
|
||||
proselytizer.repairing = null
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/proselytizer_heal_tick(amount)
|
||||
var/static/list/damage_heal_order = list(BRUTE, BURN, TOX, OXY)
|
||||
heal_ordered_damage(amount, damage_heal_order)
|
||||
|
||||
/mob/living/simple_animal/proselytizer_heal_tick(amount)
|
||||
adjustHealth(-amount)
|
||||
|
||||
//Hitting a ratvar'd silicon will also try to repair it.
|
||||
/mob/living/silicon/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
if(health == maxHealth) //if we're at maximum health, prosel the turf under us
|
||||
return FALSE
|
||||
else if(proselytizer_heal(user, proselytizer) && user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself. You are":"g [src]. [p_they(TRUE)] [p_are()]"] now at <b>[abs(HEALTH_THRESHOLD_DEAD - health)]/[abs(HEALTH_THRESHOLD_DEAD - maxHealth)]</b> health.</span>")
|
||||
|
||||
//Same with clockwork mobs.
|
||||
/mob/living/simple_animal/hostile/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
if(health == maxHealth) //if we're at maximum health, prosel the turf under us
|
||||
return FALSE
|
||||
else if(proselytizer_heal(user, proselytizer) && user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself. You are":"g [src]. [p_they(TRUE)] [p_are()]"] now at <b>[health]/[maxHealth]</b> health.</span>")
|
||||
|
||||
//Cogscarabs get special interaction because they're drones and have innate self-heals/revives.
|
||||
/mob/living/simple_animal/drone/cogscarab/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
if(stat == DEAD)
|
||||
try_reactivate(user) //if we're at maximum health, prosel the turf under us
|
||||
return
|
||||
if(health == maxHealth)
|
||||
return FALSE
|
||||
else if(!(flags_1 & GODMODE))
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairin[src == user ? "g yourself" : "g [src]"]...</span>")
|
||||
proselytizer.repairing = src
|
||||
if(do_after(user, (maxHealth - health)*2, target=src))
|
||||
adjustHealth(-maxHealth)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself" : "g [src]"].</span>")
|
||||
if(proselytizer)
|
||||
proselytizer.repairing = null
|
||||
|
||||
//Convert shards and gear bits directly to power
|
||||
/obj/item/clockwork/alloy_shards/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -POWER_STANDARD, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit/large/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.08), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/large/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.06), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.04), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/small/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.02), "spawn_dir" = SOUTH)
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
The Ratvarian Language
|
||||
In the lore of the Servants of Ratvar, the Ratvarian tongue is a timeless language and full of power. It sounds like gibberish, much like Nar-Sie's language, but is in fact derived from
|
||||
aforementioned language, and may induce miracles when spoken in the correct way with an amplifying tool (similar to runes used by the Nar-Sian cult).
|
||||
|
||||
While the canon states that the language of Ratvar and his servants is incomprehensible to the unenlightened as it is a derivative of the most ancient known language, in reality it is
|
||||
actually very simple. To translate a plain English sentence to Ratvar's tongue, simply move all of the letters thirteen places ahead, starting from "a" if the end of the alphabet is reached.
|
||||
This cipher is known as "rot13" for "rotate 13 places" and there are many sites online that allow instant translation between English and rot13 - one of the benefits is that moving the translated
|
||||
sentence thirteen places ahead changes it right back to plain English.
|
||||
|
||||
There are, however, a few parts of the Ratvarian tongue that aren't typical and are implemented for fluff reasons. Some words may have graves, or hyphens (prefix and postfix), making the plain
|
||||
English translation apparent but disjoined (for instance, "Orubyq zl-cbjre!" translates directly to "Behold my-power!") although this can be ignored without impacting overall quality. When
|
||||
translating from Ratvar's tongue to plain English, simply remove the disjointments and use the finished sentence. This would make "Orubyq zl-cbjre!" into "Behold my power!" after removing the
|
||||
abnormal spacing, hyphens, and grave accents.
|
||||
|
||||
List of nuances:
|
||||
- Any time the WORD "of" occurs, it is linked to the previous word by a hyphen. (i.e. "V nz-bs Ratvar." directly translates to "I am-of Ratvar.")
|
||||
- Any time "th", followed by any two letters occurs, you add a grave (`) between those two letters, i.e; "Thi`s"
|
||||
- In the same vein, any time "ti", followed by one letter occurs, you add a grave (`) between "i" and the letter, i.e; "Ti`me"
|
||||
- Whereever "te" or "et" appear and there is another letter next to the e(i.e; "m"etal, greate"r"), add a hyphen between "e" and the letter, i.e; "M-etal", "Greate-r"
|
||||
- Where "gua" appears, add a hyphen between "gu" and "a", i.e "Gu-ard"
|
||||
- Where the WORD "and" appears it is linked to all surrounding words by hyphens, i.e; "Sword-and-shield"
|
||||
- Where the WORD "to" appears, it is linked to the following word by a hyphen, i.e; "to-use"
|
||||
- Where the WORD "my" appears, it is linked to the following word by a hyphen, i.e; "my-light"
|
||||
- Although "Ratvar" translates to "Engine" in English, the word "Ratvar" is used regardless of language as it is a proper noun.
|
||||
- The same rule applies to Ratvar's four generals: Nezbere (Armorer), Sevtug (Fright), Nzcrentr (Amperage), and Inath-neq (Vangu-Ard), although these words can be used in proper context if one is
|
||||
not referring to the four generals and simply using the words themselves.
|
||||
*/
|
||||
|
||||
//Regexes used to alter english to ratvarian style
|
||||
#define RATVAR_OF_MATCH regex("(\\w)\\s(\[oO]\[fF])","g")
|
||||
#define RATVAR_OF_REPLACEMENT "$1-$2"
|
||||
#define RATVAR_GUA_MATCH regex("(\[gG]\[uU])(\[aA])","g")
|
||||
#define RATVAR_GUA_REPLACEMENT "$1-$2"
|
||||
#define RATVAR_TH_MATCH regex("(\[tT]\[hH]\\w)(\\w)","g")
|
||||
#define RATVAR_TH_REPLACEMENT "$1`$2"
|
||||
#define RATVAR_TI_MATCH regex("(\[tT]\[iI])(\\w)","g")
|
||||
#define RATVAR_TI_REPLACEMENT "$1`$2"
|
||||
#define RATVAR_ET_MATCH regex("(\\w)(\[eE]\[tT])","g")
|
||||
#define RATVAR_ET_REPLACEMENT "$1-$2"
|
||||
#define RATVAR_TE_MATCH regex("(\[tT]\[eE])(\\w)","g")
|
||||
#define RATVAR_TE_REPLACEMENT "$1-$2"
|
||||
#define RATVAR_PRE_AND_MATCH regex("(\\w)\\s(\[aA]\[nN]\[dD])(\\W)","g")
|
||||
#define RATVAR_PRE_AND_REPLACEMENT "$1-$2$3"
|
||||
#define RATVAR_POST_AND_MATCH regex("(\\W)(\[aA]\[nN]\[dD])\\s(\\w)","g")
|
||||
#define RATVAR_POST_AND_REPLACEMENT "$1$2-$3"
|
||||
#define RATVAR_TO_MATCH regex("(\\s)(\[tT]\[oO])\\s(\\w)","g")
|
||||
#define RATVAR_TO_REPLACEMENT "$1$2-$3"
|
||||
#define RATVAR_MY_MATCH regex("(\\s)(\[mM]\[yY])\\s(\\w)","g")
|
||||
#define RATVAR_MY_REPLACEMENT "$1$2-$3"
|
||||
|
||||
//Regexes used to remove ratvarian styling from english
|
||||
#define REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH regex("(\\w)-(\[aA]\[nN]\[dD])","g") //specifically structured to support -emphasis-, including with -and-
|
||||
#define REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT "$1 $2"
|
||||
#define REVERSE_RATVAR_HYPHEN_POST_AND_MATCH regex("(\[aA]\[nN]\[dD])-(\\w)","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT "$1 $2"
|
||||
#define REVERSE_RATVAR_HYPHEN_TO_MY_MATCH regex("(\[tTmM]\[oOyY])-","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT "$1 "
|
||||
#define REVERSE_RATVAR_HYPHEN_TE_MATCH regex("(\[tT]\[eE])-","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT "$1"
|
||||
#define REVERSE_RATVAR_HYPHEN_ET_MATCH regex("-(\[eE]\[tT])","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT "$1"
|
||||
#define REVERSE_RATVAR_HYPHEN_GUA_MATCH regex("(\[gG]\[uU])-(\[aA])","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT "$1$2"
|
||||
#define REVERSE_RATVAR_HYPHEN_OF_MATCH regex("-(\[oO]\[fF])","g")
|
||||
#define REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT " $1"
|
||||
|
||||
|
||||
/proc/text2ratvar(text) //Takes english and applies ratvarian styling rules (and rot13) to it.
|
||||
var/ratvarian = add_ratvarian_regex(text) //run the regexes twice, so that you catch people translating it beforehand
|
||||
ratvarian = rot13(ratvarian)
|
||||
return add_ratvarian_regex(ratvarian)
|
||||
|
||||
/proc/add_ratvarian_regex(text)
|
||||
var/ratvarian = replacetext(text, RATVAR_OF_MATCH, RATVAR_OF_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_GUA_MATCH, RATVAR_GUA_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_TH_MATCH, RATVAR_TH_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_TI_MATCH, RATVAR_TI_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_ET_MATCH, RATVAR_ET_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_TE_MATCH, RATVAR_TE_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_PRE_AND_MATCH, RATVAR_PRE_AND_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_POST_AND_MATCH, RATVAR_POST_AND_REPLACEMENT)
|
||||
ratvarian = replacetext(ratvarian, RATVAR_TO_MATCH, RATVAR_TO_REPLACEMENT)
|
||||
return replacetext(ratvarian, RATVAR_MY_MATCH, RATVAR_MY_REPLACEMENT)
|
||||
|
||||
/proc/ratvar2text(ratvarian) //Reverts ravarian styling and rot13 in text.
|
||||
var/text = remove_ratvarian_regex(ratvarian) //run the regexes twice, so that you catch people translating it beforehand
|
||||
text = replacetext(rot13(text), "`", "")
|
||||
return remove_ratvarian_regex(text)
|
||||
|
||||
/proc/remove_ratvarian_regex(ratvarian)
|
||||
var/text = replacetext(ratvarian, REVERSE_RATVAR_HYPHEN_GUA_MATCH, REVERSE_RATVAR_HYPHEN_GUA_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_PRE_AND_MATCH, REVERSE_RATVAR_HYPHEN_PRE_AND_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_POST_AND_MATCH, REVERSE_RATVAR_HYPHEN_POST_AND_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_TO_MY_MATCH, REVERSE_RATVAR_HYPHEN_TO_MY_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_TE_MATCH, REVERSE_RATVAR_HYPHEN_TE_REPLACEMENT)
|
||||
text = replacetext(text, REVERSE_RATVAR_HYPHEN_ET_MATCH, REVERSE_RATVAR_HYPHEN_ET_REPLACEMENT)
|
||||
return replacetext(text, REVERSE_RATVAR_HYPHEN_OF_MATCH, REVERSE_RATVAR_HYPHEN_OF_REPLACEMENT)
|
||||
|
||||
//Causes the mob or AM in question to speak a message; it assumes that the message is already translated to ratvar speech using text2ratvar()
|
||||
/proc/clockwork_say(atom/movable/AM, message, whisper=FALSE)
|
||||
var/list/spans = list(SPAN_ROBOT)
|
||||
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(!whisper)
|
||||
L.say(message, "clock", spans, language=/datum/language/common, ignore_spam = TRUE)
|
||||
else
|
||||
L.whisper(message, "clock", spans, language=/datum/language/common)
|
||||
else
|
||||
AM.say(message, language=/datum/language/common)
|
||||
@@ -1,53 +0,0 @@
|
||||
//returns a list of scriptures and if they're unlocked or not
|
||||
/proc/scripture_unlock_check()
|
||||
. = list(SCRIPTURE_DRIVER = TRUE, SCRIPTURE_SCRIPT = FALSE, SCRIPTURE_APPLICATION = FALSE)
|
||||
//Drivers: always unlocked
|
||||
|
||||
.[SCRIPTURE_SCRIPT] = GLOB.script_scripture_unlocked
|
||||
//Script: Convert a new servant using a sigil of submission.
|
||||
|
||||
.[SCRIPTURE_APPLICATION] = GLOB.application_scripture_unlocked
|
||||
//Application: APPLICATION_SERVANT_REQ or more non-brain servants, APPLICATION_CACHE_REQ or more clockwork caches, and at least APPLICATION_CV_REQ CV
|
||||
|
||||
//reports to servants when scripture is locked or unlocked
|
||||
/proc/scripture_unlock_alert(list/previous_states)
|
||||
. = scripture_unlock_check()
|
||||
if(!GLOB.servants_active)
|
||||
return
|
||||
for(var/i in .)
|
||||
if(.[i] != previous_states[i])
|
||||
update_slab_info()
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(is_servant_of_ratvar(M) || isobserver(M))
|
||||
M.playsound_local(M, 'sound/magic/clockwork/scripture_tier_up.ogg', 50, FALSE, pressure_affected = FALSE)
|
||||
|
||||
/proc/update_slab_info(obj/item/clockwork/slab/set_slab)
|
||||
generate_all_scripture()
|
||||
var/needs_update = FALSE //if everything needs an update, for whatever reason
|
||||
for(var/s in GLOB.all_scripture)
|
||||
var/datum/clockwork_scripture/S = GLOB.all_scripture[s]
|
||||
if(S.creation_update())
|
||||
needs_update = TRUE
|
||||
if(!set_slab || needs_update)
|
||||
for(var/obj/item/clockwork/slab/S in GLOB.all_clockwork_objects)
|
||||
SStgui.update_uis(S)
|
||||
if(needs_update)
|
||||
S.update_quickbind()
|
||||
else
|
||||
SStgui.update_uis(set_slab)
|
||||
set_slab.update_quickbind()
|
||||
|
||||
/proc/generate_all_scripture()
|
||||
if(!GLOB.all_scripture.len)
|
||||
for(var/V in sortList(subtypesof(/datum/clockwork_scripture), /proc/cmp_clockscripture_priority))
|
||||
var/datum/clockwork_scripture/S = new V
|
||||
GLOB.all_scripture[S.type] = S
|
||||
|
||||
//changes construction value
|
||||
/proc/change_construction_value(amount)
|
||||
if(!SSticker.current_state != GAME_STATE_PLAYING) //This is primarily so that structures added pre-roundstart don't contribute to construction value
|
||||
return
|
||||
GLOB.clockwork_construction_value = max(0, GLOB.clockwork_construction_value + amount)
|
||||
|
||||
/proc/can_recite_scripture(mob/living/L, can_potentially)
|
||||
return (is_servant_of_ratvar(L) && (can_potentially || (L.stat == CONSCIOUS && L.can_speak_vocal())) && (GLOB.ratvar_awakens || (ishuman(L) || issilicon(L))))
|
||||
@@ -1,270 +0,0 @@
|
||||
//The base for slab-bound/based ranged abilities
|
||||
/obj/effect/proc_holder/slab
|
||||
var/obj/item/clockwork/slab/slab
|
||||
var/successful = FALSE
|
||||
var/finished = FALSE
|
||||
var/in_progress = FALSE
|
||||
|
||||
/obj/effect/proc_holder/slab/Destroy()
|
||||
slab = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/slab/remove_ranged_ability(msg)
|
||||
..()
|
||||
finished = TRUE
|
||||
QDEL_IN(src, 6)
|
||||
|
||||
/obj/effect/proc_holder/slab/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..() || in_progress)
|
||||
return TRUE
|
||||
if(ranged_ability_user.incapacitated() || !slab || !(slab in ranged_ability_user.held_items) || target == slab)
|
||||
remove_ranged_ability()
|
||||
return TRUE
|
||||
|
||||
//For the Hateful Manacles scripture; applies replicant handcuffs to the target.
|
||||
/obj/effect/proc_holder/slab/hateful_manacles
|
||||
|
||||
/obj/effect/proc_holder/slab/hateful_manacles/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(iscarbon(target) && target.Adjacent(ranged_ability_user))
|
||||
var/mob/living/carbon/L = target
|
||||
if(is_servant_of_ratvar(L))
|
||||
to_chat(ranged_ability_user, "<span class='neovgre'>\"They're a servant.\"</span>")
|
||||
return TRUE
|
||||
else if(L.stat)
|
||||
to_chat(ranged_ability_user, "<span class='neovgre'>\"There is use in shackling the dead, but for examples.\"</span>")
|
||||
return TRUE
|
||||
else if(L.handcuffed)
|
||||
to_chat(ranged_ability_user, "<span class='neovgre'>\"They are already helpless, no?\"</span>")
|
||||
return TRUE
|
||||
|
||||
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, TRUE)
|
||||
ranged_ability_user.visible_message("<span class='danger'>[ranged_ability_user] begins forming manacles around [L]'s wrists!</span>", \
|
||||
"<span class='neovgre_small'>You begin shaping replicant alloy into manacles around [L]'s wrists...</span>")
|
||||
to_chat(L, "<span class='userdanger'>[ranged_ability_user] begins forming manacles around your wrists!</span>")
|
||||
if(do_mob(ranged_ability_user, L, 30))
|
||||
if(!L.handcuffed)
|
||||
L.handcuffed = new/obj/item/restraints/handcuffs/clockwork(L)
|
||||
L.update_handcuffed()
|
||||
to_chat(ranged_ability_user, "<span class='neovgre_small'>You shackle [L].</span>")
|
||||
add_logs(ranged_ability_user, L, "handcuffed")
|
||||
else
|
||||
to_chat(ranged_ability_user, "<span class='warning'>You fail to shackle [L].</span>")
|
||||
|
||||
successful = TRUE
|
||||
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/restraints/handcuffs/clockwork
|
||||
name = "replicant manacles"
|
||||
desc = "Heavy manacles made out of freezing-cold metal. It looks like brass, but feels much more solid."
|
||||
icon_state = "brass_manacles"
|
||||
flags_1 = DROPDEL_1
|
||||
|
||||
/obj/item/restraints/handcuffs/clockwork/dropped(mob/user)
|
||||
user.visible_message("<span class='danger'>[user]'s [name] come apart at the seams!</span>", \
|
||||
"<span class='userdanger'>Your [name] break apart as they're removed!</span>")
|
||||
. = ..()
|
||||
|
||||
//For the Sentinel's Compromise scripture; heals a target servant.
|
||||
/obj/effect/proc_holder/slab/compromise
|
||||
ranged_mousepointer = 'icons/effects/compromise_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/compromise/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(isliving(target) && (target in view(7, get_turf(ranged_ability_user))))
|
||||
var/mob/living/L = target
|
||||
if(!is_servant_of_ratvar(L))
|
||||
to_chat(ranged_ability_user, "<span class='inathneq'>\"[L] does not yet serve Ratvar.\"</span>")
|
||||
return TRUE
|
||||
if(L.stat == DEAD)
|
||||
to_chat(ranged_ability_user, "<span class='inathneq'>\"[L.p_they(TRUE)] [L.p_are()] dead. [text2ratvar("Oh, child. To have your life cut short...")]\"</span>")
|
||||
return TRUE
|
||||
|
||||
var/brutedamage = L.getBruteLoss()
|
||||
var/burndamage = L.getFireLoss()
|
||||
var/oxydamage = L.getOxyLoss()
|
||||
var/totaldamage = brutedamage + burndamage + oxydamage
|
||||
if(!totaldamage && (!L.reagents || !L.reagents.has_reagent("holywater")))
|
||||
to_chat(ranged_ability_user, "<span class='inathneq'>\"[L] is unhurt and untainted.\"</span>")
|
||||
return TRUE
|
||||
|
||||
successful = TRUE
|
||||
|
||||
to_chat(ranged_ability_user, "<span class='brass'>You bathe [L == ranged_ability_user ? "yourself":"[L]"] in Inath-neq's power!</span>")
|
||||
var/targetturf = get_turf(L)
|
||||
var/has_holy_water = (L.reagents && L.reagents.has_reagent("holywater"))
|
||||
var/healseverity = max(round(totaldamage*0.05, 1), 1) //shows the general severity of the damage you just healed, 1 glow per 20
|
||||
for(var/i in 1 to healseverity)
|
||||
new /obj/effect/temp_visual/heal(targetturf, "#1E8CE1")
|
||||
if(totaldamage)
|
||||
L.adjustBruteLoss(-brutedamage)
|
||||
L.adjustFireLoss(-burndamage)
|
||||
L.adjustOxyLoss(-oxydamage)
|
||||
L.adjustToxLoss(totaldamage * 0.5, TRUE, TRUE)
|
||||
clockwork_say(ranged_ability_user, text2ratvar("[has_holy_water ? "Heal tainted" : "Mend wounded"] flesh!"))
|
||||
add_logs(ranged_ability_user, L, "healed with Sentinel's Compromise")
|
||||
L.visible_message("<span class='warning'>A blue light washes over [L], [has_holy_water ? "causing [L.p_them()] to briefly glow as it mends" : " mending"] [L.p_their()] bruises and burns!</span>", \
|
||||
"<span class='heavy_brass'>You feel Inath-neq's power healing your wounds[has_holy_water ? " and purging the darkness within you" : ""], but a deep nausea overcomes you!</span>")
|
||||
else
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Purge foul darkness!"))
|
||||
add_logs(ranged_ability_user, L, "purged of holy water with Sentinel's Compromise")
|
||||
L.visible_message("<span class='warning'>A blue light washes over [L], causing [L.p_them()] to briefly glow!</span>", \
|
||||
"<span class='heavy_brass'>You feel Inath-neq's power purging the darkness within you!</span>")
|
||||
playsound(targetturf, 'sound/magic/staff_healing.ogg', 50, 1)
|
||||
|
||||
if(has_holy_water)
|
||||
L.reagents.remove_reagent("holywater", 1000)
|
||||
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Kindle scripture; stuns and mutes a target non-servant.
|
||||
/obj/effect/proc_holder/slab/kindle
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/kindle/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
|
||||
successful = TRUE
|
||||
|
||||
var/turf/U = get_turf(target)
|
||||
to_chat(ranged_ability_user, "<span class='brass'>You release the light of Ratvar!</span>")
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Purge all untruths and honor Engine!"))
|
||||
add_logs(ranged_ability_user, U, "fired at with Kindle")
|
||||
playsound(ranged_ability_user, 'sound/magic/blink.ogg', 50, TRUE, frequency = 0.5)
|
||||
var/obj/item/projectile/kindle/A = new(T)
|
||||
A.preparePixelProjectile(target, caller, params)
|
||||
A.fire()
|
||||
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/projectile/kindle
|
||||
name = "kindled flame"
|
||||
icon_state = "pulse0"
|
||||
nodamage = TRUE
|
||||
damage = 0 //We're just here for the stunning!
|
||||
damage_type = BURN
|
||||
flag = "bomb"
|
||||
range = 3
|
||||
log_override = TRUE
|
||||
|
||||
/obj/item/projectile/kindle/Destroy()
|
||||
visible_message("<span class='warning'>[src] flickers out!</span>")
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/kindle/on_hit(atom/target, blocked = FALSE)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(is_servant_of_ratvar(L) || L.stat || L.has_status_effect(STATUS_EFFECT_KINDLE))
|
||||
return
|
||||
var/obj/O = L.null_rod_check()
|
||||
playsound(L, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25)
|
||||
if(O)
|
||||
L.visible_message("<span class='warning'>[L]'s eyes flare with dim light as they stumble!</span>", \
|
||||
"<span class='userdanger'>Your [O] glows white-hot against you as it absorbs some sort of power!</span>")
|
||||
L.adjustFireLoss(5)
|
||||
L.Stun(40)
|
||||
playsound(L, 'sound/weapons/sear.ogg', 50, TRUE)
|
||||
else
|
||||
L.visible_message("<span class='warning'>[L]'s eyes blaze with brilliant light!</span>", \
|
||||
"<span class='userdanger'>Your vision suddenly screams with white-hot light!</span>")
|
||||
L.Knockdown(15)
|
||||
L.apply_status_effect(STATUS_EFFECT_KINDLE)
|
||||
L.flash_act(1, 1)
|
||||
if(iscultist(L))
|
||||
L.adjustFireLoss(15)
|
||||
..()
|
||||
|
||||
|
||||
//For the cyborg Linked Vanguard scripture, grants you and a nearby ally Vanguard
|
||||
/obj/effect/proc_holder/slab/vanguard
|
||||
ranged_mousepointer = 'icons/effects/vanguard_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/vanguard/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(isliving(target) && (target in view(7, get_turf(ranged_ability_user))))
|
||||
var/mob/living/L = target
|
||||
if(!is_servant_of_ratvar(L))
|
||||
to_chat(ranged_ability_user, "<span class='inathneq'>\"[L] does not yet serve Ratvar.\"</span>")
|
||||
return TRUE
|
||||
if(L.stat == DEAD)
|
||||
to_chat(ranged_ability_user, "<span class='inathneq'>\"[L.p_they(TRUE)] [L.p_are()] dead. [text2ratvar("Oh, child. To have your life cut short...")]\"</span>")
|
||||
return TRUE
|
||||
if(islist(L.stun_absorption) && L.stun_absorption["vanguard"] && L.stun_absorption["vanguard"]["end_time"] > world.time)
|
||||
to_chat(ranged_ability_user, "<span class='inathneq'>\"[L.p_they(TRUE)] [L.p_are()] already shielded by a Vanguard.\"</span>")
|
||||
return TRUE
|
||||
|
||||
successful = TRUE
|
||||
|
||||
if(L == ranged_ability_user)
|
||||
for(var/mob/living/LT in spiral_range(7, T))
|
||||
if(LT.stat == DEAD || !is_servant_of_ratvar(LT) || LT == ranged_ability_user || !(LT in view(7, get_turf(ranged_ability_user))) || \
|
||||
(islist(LT.stun_absorption) && LT.stun_absorption["vanguard"] && LT.stun_absorption["vanguard"]["end_time"] > world.time))
|
||||
continue
|
||||
L = LT
|
||||
break
|
||||
|
||||
L.apply_status_effect(STATUS_EFFECT_VANGUARD)
|
||||
ranged_ability_user.apply_status_effect(STATUS_EFFECT_VANGUARD)
|
||||
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Shield us from darkness!"))
|
||||
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the cyborg Judicial Marker scripture, places a judicial marker
|
||||
/obj/effect/proc_holder/slab/judicial
|
||||
ranged_mousepointer = 'icons/effects/visor_reticule.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/judicial/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
successful = TRUE
|
||||
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Kneel, heathens!"))
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user]'s eyes fire a stream of energy at [target], creating a strange mark!</span>", \
|
||||
"<span class='heavy_brass'>You direct the judicial force to [target].</span>")
|
||||
var/turf/targetturf = get_turf(target)
|
||||
new/obj/effect/clockwork/judicial_marker(targetturf, ranged_ability_user)
|
||||
add_logs(ranged_ability_user, targetturf, "created a judicial marker")
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
@@ -1,24 +0,0 @@
|
||||
//The base clockwork item. Can have an alternate desc and will show up in the list of clockwork objects.
|
||||
/obj/item/clockwork
|
||||
name = "meme blaster"
|
||||
desc = "What the fuck is this? It looks kinda like a frog."
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
var/clockwork_desc = "A fabled artifact from beyond the stars. Contains concentrated meme essence." //Shown to clockwork cultists instead of the normal description
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "rare_pepe"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/clockwork/Initialize()
|
||||
. = ..()
|
||||
ratvar_act()
|
||||
GLOB.all_clockwork_objects += src
|
||||
|
||||
/obj/item/clockwork/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/examine(mob/user)
|
||||
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
@@ -1,239 +0,0 @@
|
||||
//Components: Used in scripture.
|
||||
/obj/item/clockwork/component
|
||||
name = "meme component"
|
||||
desc = "A piece of a famous meme."
|
||||
clockwork_desc = null
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/component_id //What the component is identified as
|
||||
var/cultist_message = "You are not worthy of this meme." //Showed to Nar-Sian cultists if they pick up the component in addition to chaplains
|
||||
var/list/servant_of_ratvar_messages = list("ayy" = FALSE, "lmao" = TRUE) //Fluff, shown to servants of Ratvar on a low chance, if associated value is TRUE, will automatically apply ratvarian
|
||||
var/message_span = "heavy_brass"
|
||||
|
||||
/obj/item/clockwork/component/examine(mob/user)
|
||||
. = ..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='[get_component_span(component_id)]'>You can activate this in your hand to break it down for power.</span>")
|
||||
|
||||
/obj/item/clockwork/component/attack_self(mob/living/user)
|
||||
if(is_servant_of_ratvar(user))
|
||||
user.visible_message("<span class='notice'>[user] crushes [src] in their hand!</span>", \
|
||||
"<span class='alloy'>You crush [src], capturing its escaping energy for use as power.</span>")
|
||||
playsound(user, 'sound/effects/pop_expl.ogg', 50, TRUE)
|
||||
adjust_clockwork_power(POWER_WALL_TOTAL)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/clockwork/component/pickup(mob/living/user)
|
||||
..()
|
||||
if(iscultist(user) || (user.mind && user.mind.isholy))
|
||||
to_chat(user, "<span class='[message_span]'>[cultist_message]</span>")
|
||||
if(user.mind && user.mind.isholy)
|
||||
to_chat(user, "<span class='boldannounce'>The power of your faith melts away [src]!</span>")
|
||||
var/obj/item/ore/slag/wrath = new /obj/item/ore/slag
|
||||
qdel(src)
|
||||
user.put_in_active_hand(wrath)
|
||||
if(is_servant_of_ratvar(user) && prob(20))
|
||||
var/pickedmessage = pick(servant_of_ratvar_messages)
|
||||
to_chat(user, "<span class='[message_span]'>[servant_of_ratvar_messages[pickedmessage] ? "[text2ratvar(pickedmessage)]" : pickedmessage]</span>")
|
||||
|
||||
/obj/item/clockwork/component/belligerent_eye
|
||||
name = "belligerent eye"
|
||||
desc = "A brass construct with a rotating red center. It's as though it's looking for something to hurt."
|
||||
icon_state = "belligerent_eye"
|
||||
component_id = BELLIGERENT_EYE
|
||||
cultist_message = "The eye gives you an intensely hateful glare."
|
||||
servant_of_ratvar_messages = list("\"...\"" = FALSE, "For a moment, your mind is flooded with extremely violent thoughts." = FALSE, "\"...Die.\"" = TRUE)
|
||||
message_span = "neovgre"
|
||||
|
||||
/obj/item/clockwork/component/belligerent_eye/blind_eye
|
||||
name = "blind eye"
|
||||
desc = "A heavy brass eye, its red iris fallen dark."
|
||||
clockwork_desc = "A smashed ocular warden covered in dents."
|
||||
icon_state = "blind_eye"
|
||||
cultist_message = "The eye flickers at you with intense hate before falling dark."
|
||||
servant_of_ratvar_messages = list("The eye flickers before falling dark." = FALSE, "You feel watched." = FALSE, "\"...\"" = FALSE)
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/clockwork/component/belligerent_eye/lens_gem
|
||||
name = "lens gem"
|
||||
desc = "A tiny pinkish gem. It catches the light oddly, almost glowing."
|
||||
clockwork_desc = "The gem from an interdiction lens."
|
||||
icon_state = "lens_gem"
|
||||
cultist_message = "The gem turns black and cold for a moment before its normal glow returns."
|
||||
servant_of_ratvar_messages = list("\"Disgusting failure.\"" = TRUE, "You feel scrutinized." = FALSE, "\"Weaklings.\"" = TRUE, "\"Pathetic defenses.\"" = TRUE)
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
light_range = 1.4
|
||||
light_power = 0.4
|
||||
light_color = "#F42B9D"
|
||||
|
||||
/obj/item/clockwork/component/vanguard_cogwheel
|
||||
name = "vanguard cogwheel"
|
||||
desc = "A sturdy brass cog with a faintly glowing blue gem in its center."
|
||||
icon_state = "vanguard_cogwheel"
|
||||
component_id = VANGUARD_COGWHEEL
|
||||
cultist_message = "\"Pray to your god that we never meet.\""
|
||||
servant_of_ratvar_messages = list("\"Be safe, child.\"" = FALSE, "You feel unexplainably comforted." = FALSE, "\"Never forget: Pain is temporary. What you do for the Justiciar is eternal.\"" = FALSE)
|
||||
message_span = "inathneq"
|
||||
|
||||
/obj/item/clockwork/component/vanguard_cogwheel/onyx_prism
|
||||
name = "onyx prism"
|
||||
desc = "An onyx prism with a small aperture. It's very heavy."
|
||||
clockwork_desc = "A broken prism from a prolonging prism."
|
||||
icon_state = "onyx_prism"
|
||||
cultist_message = "The prism grows painfully hot in your hands."
|
||||
servant_of_ratvar_messages = list("The prism isn't getting any lighter." = FALSE, "\"So... you haven't failed yet. Have hope, child.\"" = TRUE, \
|
||||
"\"Better these machines break than you do.\"" = TRUE)
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/clockwork/component/geis_capacitor
|
||||
name = "geis capacitor"
|
||||
desc = "A curiously cold brass doodad. It seems as though it really doesn't appreciate being held."
|
||||
icon_state = "geis_capacitor"
|
||||
component_id = GEIS_CAPACITOR
|
||||
cultist_message = "\"Try not to lose your mind - I'll need it. Heh heh...\""
|
||||
servant_of_ratvar_messages = list("\"Disgusting.\"" = FALSE, "\"Well, aren't you an inquisitive fellow?\"" = FALSE, "A foul presence pervades your mind, then vanishes." = FALSE, \
|
||||
"\"The fact that Ratvar has to depend on simpletons like you is appalling.\"" = FALSE)
|
||||
message_span = "sevtug"
|
||||
|
||||
/obj/item/clockwork/component/geis_capacitor/fallen_armor
|
||||
name = "fallen armor"
|
||||
desc = "Lifeless chunks of armor. They're designed in a strange way and won't fit on you."
|
||||
clockwork_desc = "The armor from a former clockwork marauder. <b>Serviceable as a substitute for a geis capacitor.</b>"
|
||||
icon_state = "fallen_armor"
|
||||
cultist_message = "Red flame sputters from the mask's eye before winking out."
|
||||
servant_of_ratvar_messages = list("A piece of armor hovers away from the others for a moment." = FALSE, "Red flame appears in the cuirass before sputtering out." = FALSE)
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/clockwork/component/geis_capacitor/antennae
|
||||
name = "mania motor antennae"
|
||||
desc = "A pair of dented and bent antennae. They constantly emit a static hiss."
|
||||
clockwork_desc = "The antennae from a mania motor."
|
||||
icon_state = "mania_motor_antennae"
|
||||
cultist_message = "Your head is filled with a burst of static."
|
||||
servant_of_ratvar_messages = list("\"Who broke this.\"" = TRUE, "\"Did you break these off YOURSELF?\"" = TRUE, "\"Why did we give this to such simpletons, anyway?\"" = TRUE, \
|
||||
"\"At least we can use these for something - unlike you.\"" = TRUE)
|
||||
|
||||
/obj/item/clockwork/component/replicant_alloy
|
||||
name = "replicant alloy"
|
||||
desc = "A seemingly strong but very malleable chunk of metal. It seems as though it wants to be molded into something greater."
|
||||
icon_state = "replicant_alloy"
|
||||
component_id = REPLICANT_ALLOY
|
||||
cultist_message = "The alloy takes on the appearance of a screaming face for a moment."
|
||||
servant_of_ratvar_messages = list("\"There's always something to be done. Get to it.\"" = FALSE, "\"Idle hands are worse than broken ones. Get to work.\"" = FALSE, \
|
||||
"A detailed image of Ratvar appears in the alloy for a moment." = FALSE)
|
||||
message_span = "nezbere"
|
||||
|
||||
/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment
|
||||
name = "smashed anima fragment"
|
||||
desc = "Shattered chunks of metal. Damaged beyond repair and completely unusable."
|
||||
clockwork_desc = "The sad remains of an anima fragment."
|
||||
icon_state = "smashed_anime_fragment"
|
||||
cultist_message = "The shards vibrate in your hands for a moment."
|
||||
servant_of_ratvar_messages = list("\"...still fight...\"" = FALSE, "\"...where am I...?\"" = FALSE, "\"...bring me... back...\"" = FALSE)
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/clockwork/component/replicant_alloy/replication_plate
|
||||
name = "replication plate"
|
||||
desc = "A flat, heavy disc of metal with a triangular formation on its surface."
|
||||
clockwork_desc = "The replication plate from a tinkerer's daemon."
|
||||
icon_state = "replication_plate"
|
||||
cultist_message = "The plate shudders in your hands, as though trying to get away."
|
||||
servant_of_ratvar_messages = list("\"Put this in a slab and get back to work.\"" = FALSE, "\"Worse servants than you have held these.\"" = TRUE, \
|
||||
"\"It would be wise to protect these better, friend.\"" = TRUE)
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/clockwork/component/hierophant_ansible
|
||||
name = "hierophant ansible"
|
||||
desc = "Some sort of transmitter? It seems as though it's trying to say something."
|
||||
icon_state = "hierophant_ansible"
|
||||
component_id = HIEROPHANT_ANSIBLE
|
||||
cultist_message = "\"Gur obff fnlf vg'f abg ntnvafg gur ehyrf gb-xvyy lbh.\""
|
||||
servant_of_ratvar_messages = list("\"Exile is such a bore. There's nothing I can hunt in here.\"" = TRUE, "\"What's keeping you? I want to go kill something.\"" = TRUE, \
|
||||
"\"HEHEHEHEHEHEH!\"" = FALSE, "\"If I killed you fast enough, do you think the boss would notice?\"" = TRUE)
|
||||
message_span = "nzcrentr"
|
||||
|
||||
/obj/item/clockwork/component/hierophant_ansible/obelisk
|
||||
name = "obelisk prism"
|
||||
desc = "A prism that occasionally glows brightly. It seems not-quite there."
|
||||
clockwork_desc = "The prism from a clockwork obelisk."
|
||||
cultist_message = "The prism flickers wildly in your hands before resuming its normal glow."
|
||||
servant_of_ratvar_messages = list("You hear the distinctive sound of the Hierophant Network for a moment." = FALSE, "\"Hieroph'ant Br'o'adcas't fail'ure.\"" = TRUE, \
|
||||
"The obelisk flickers wildly, as if trying to open a gateway." = FALSE, "\"Spa'tial Ga'tewa'y fai'lure.\"" = TRUE)
|
||||
icon_state = "obelisk_prism"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
//Shards of Alloy, suitable only as a source of power for a replica fabricator.
|
||||
/obj/item/clockwork/alloy_shards
|
||||
name = "replicant alloy shards"
|
||||
desc = "Broken shards of some oddly malleable metal. They occasionally move and seem to glow."
|
||||
clockwork_desc = "Broken shards of replicant alloy."
|
||||
icon_state = "alloy_shards"
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/randomsinglesprite = FALSE
|
||||
var/randomspritemax = 2
|
||||
var/sprite_shift = 9
|
||||
|
||||
/obj/item/clockwork/alloy_shards/Initialize()
|
||||
. = ..()
|
||||
if(randomsinglesprite)
|
||||
replace_name_desc()
|
||||
icon_state = "[icon_state][rand(1, randomspritemax)]"
|
||||
pixel_x = rand(-sprite_shift, sprite_shift)
|
||||
pixel_y = rand(-sprite_shift, sprite_shift)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='brass'>Can be consumed by a replica fabricator as a source of power.</span>")
|
||||
|
||||
/obj/item/clockwork/alloy_shards/proc/replace_name_desc()
|
||||
name = "replicant alloy shard"
|
||||
desc = "A broken shard of some oddly malleable metal. It occasionally moves and seems to glow."
|
||||
clockwork_desc = "A broken shard of replicant alloy."
|
||||
|
||||
/obj/item/clockwork/alloy_shards/clockgolem_remains
|
||||
name = "clockwork golem scrap"
|
||||
desc = "A pile of scrap metal. It seems damaged beyond repair."
|
||||
clockwork_desc = "The sad remains of a clockwork golem. It's broken beyond repair."
|
||||
icon_state = "clockgolem_dead"
|
||||
sprite_shift = 0
|
||||
|
||||
/obj/item/clockwork/alloy_shards/large
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
randomsinglesprite = TRUE
|
||||
icon_state = "shard_large"
|
||||
sprite_shift = 9
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
randomsinglesprite = TRUE
|
||||
icon_state = "shard_medium"
|
||||
sprite_shift = 10
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit
|
||||
randomspritemax = 4
|
||||
icon_state = "gear_bit"
|
||||
sprite_shift = 12
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit/replace_name_desc()
|
||||
name = "gear bit"
|
||||
desc = "A broken chunk of a gear. You want it."
|
||||
clockwork_desc = "A broken chunk of a gear."
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit/large //gives more power
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit/large/replace_name_desc()
|
||||
..()
|
||||
name = "complex gear bit"
|
||||
|
||||
/obj/item/clockwork/alloy_shards/small
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
randomsinglesprite = TRUE
|
||||
randomspritemax = 3
|
||||
icon_state = "shard_small"
|
||||
sprite_shift = 12
|
||||
|
||||
/obj/item/clockwork/alloy_shards/pinion_lock
|
||||
name = "pinion lock"
|
||||
desc = "A dented and scratched gear. It's very heavy."
|
||||
clockwork_desc = "A broken gear lock for pinion airlocks."
|
||||
icon_state = "pinion_lock"
|
||||
@@ -1,49 +0,0 @@
|
||||
//This is the innate action for "binding" and calling weapons to yourself. These weapons can appear and disappear at will.
|
||||
//You can invoke a cooldown period by calling "weapon_reset(cooldown in deciseconds)." By default, this only applies to dismissing weapons.
|
||||
/datum/action/innate/call_weapon
|
||||
name = "Call Weapon"
|
||||
desc = "This definitely shouldn't exist."
|
||||
icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
|
||||
button_icon_state = "ratvarian_spear"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/cooldown = 0
|
||||
var/obj/item/clockwork/weapon/weapon_type //The type of weapon to create
|
||||
var/obj/item/clockwork/weapon/weapon
|
||||
|
||||
/datum/action/innate/call_weapon/IsAvailable()
|
||||
if(!is_servant_of_ratvar(owner))
|
||||
qdel(src)
|
||||
return
|
||||
if(cooldown > world.time)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/call_weapon/Activate()
|
||||
if(!owner.get_empty_held_indexes())
|
||||
to_chat(usr, "<span class='warning'>You need an empty hand to call forth your [initial(weapon_type.name)]!</span>")
|
||||
return
|
||||
if(weapon)
|
||||
if(weapon.loc == owner)
|
||||
owner.visible_message("<span class='danger'>[owner]'s [weapon.name] flickers and disappears!</span>")
|
||||
to_chat(owner, "<span class='brass'>You dismiss [weapon].</span>")
|
||||
QDEL_NULL(weapon)
|
||||
weapon_reset(RATVARIAN_SPEAR_COOLDOWN * 0.5)
|
||||
return
|
||||
else
|
||||
weapon.visible_message("<span class='warning'>[weapon] suddenly flickers and disappears!</span>")
|
||||
owner.visible_message("<span class='danger'>A [weapon.name] suddenly flickers into [owner]'s hands!</span>", "<span class='brass'>You recall [weapon] to you.</span>")
|
||||
else
|
||||
weapon = new weapon_type (get_turf(usr), src)
|
||||
owner.visible_message("<span class='warning'>A [weapon.name] materializes in [owner]'s hands!</span>", "<span class='brass'>You call forth your [weapon.name]!</span>")
|
||||
weapon.forceMove(get_turf(owner))
|
||||
owner.put_in_hands(weapon)
|
||||
owner.update_action_buttons_icon()
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/call_weapon/proc/weapon_reset(cooldown_time)
|
||||
cooldown = world.time + cooldown_time
|
||||
addtimer(CALLBACK(owner, /mob.proc/update_action_buttons_icon), cooldown_time)
|
||||
owner.update_action_buttons_icon()
|
||||
QDEL_NULL(weapon)
|
||||
@@ -1,76 +0,0 @@
|
||||
//Ratvarian spear: A relatively fragile spear from the Celestial Derelict. Deals extreme damage to silicons and enemy cultists, but doesn't last long when summoned.
|
||||
/obj/item/clockwork/weapon/ratvarian_spear
|
||||
name = "ratvarian spear"
|
||||
desc = "A razor-sharp spear made of brass. It thrums with barely-contained energy."
|
||||
clockwork_desc = "A powerful spear of Ratvarian making. It's more effective against enemy cultists and silicons."
|
||||
icon_state = "ratvarian_spear"
|
||||
item_state = "ratvarian_spear"
|
||||
force = 15 //Extra damage is dealt to targets in attack()
|
||||
throwforce = 25
|
||||
armour_penetration = 10
|
||||
sharpness = IS_SHARP_ACCURATE
|
||||
attack_verb = list("stabbed", "poked", "slashed")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
var/bonus_burn = 5
|
||||
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/ratvar_act()
|
||||
if(GLOB.ratvar_awakens) //If Ratvar is alive, the spear is extremely powerful
|
||||
force = 20
|
||||
bonus_burn = 10
|
||||
throwforce = 40
|
||||
armour_penetration = 50
|
||||
else
|
||||
force = initial(force)
|
||||
bonus_burn = initial(bonus_burn)
|
||||
throwforce = initial(throwforce)
|
||||
armour_penetration = initial(armour_penetration)
|
||||
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='inathneq_small'>Attacks on living non-Servants will generate <b>[bonus_burn]</b> units of vitality.</span>")
|
||||
if(!iscyborg(user))
|
||||
to_chat(user, "<span class='brass'>Throwing the spear will do massive damage, break the spear, and knock down the target.</span>")
|
||||
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
. = ..()
|
||||
if(!QDELETED(target) && target.stat != DEAD && !target.null_rod_check() && !is_servant_of_ratvar(target)) //we do bonus damage on attacks unless they're a servant, have a null rod, or are dead
|
||||
var/bonus_damage = bonus_burn //normally a total of 20 damage, 30 with ratvar
|
||||
if(issilicon(target))
|
||||
target.visible_message("<span class='warning'>[target] shudders violently at [src]'s touch!</span>", "<span class='userdanger'>ERROR: Temperature rising!</span>")
|
||||
bonus_damage *= 5 //total 40 damage on borgs, 70 with ratvar
|
||||
else if(iscultist(target) || isconstruct(target))
|
||||
to_chat(target, "<span class='userdanger'>Your body flares with agony at [src]'s presence!</span>")
|
||||
bonus_damage *= 3 //total 30 damage on cultists, 50 with ratvar
|
||||
GLOB.clockwork_vitality += target.adjustFireLoss(bonus_damage) //adds the damage done to existing vitality
|
||||
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/throw_impact(atom/target)
|
||||
var/turf/T = get_turf(target)
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(is_servant_of_ratvar(L))
|
||||
if(L.put_in_active_hand(src))
|
||||
L.visible_message("<span class='warning'>[L] catches [src] out of the air!</span>")
|
||||
else
|
||||
L.visible_message("<span class='warning'>[src] bounces off of [L], as if repelled by an unseen force!</span>")
|
||||
else if(!..())
|
||||
if(!L.null_rod_check())
|
||||
if(issilicon(L) || iscultist(L))
|
||||
L.Knockdown(100)
|
||||
else
|
||||
L.Knockdown(40)
|
||||
GLOB.clockwork_vitality += L.adjustFireLoss(bonus_burn * 3) //normally a total of 40 damage, 70 with ratvar
|
||||
break_spear(T)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/proc/break_spear(turf/T)
|
||||
if(src)
|
||||
if(!T)
|
||||
T = get_turf(src)
|
||||
if(T) //make sure we're not in null or something
|
||||
T.visible_message("<span class='warning'>[src] [pick("cracks in two and fades away", "snaps in two and dematerializes")]!</span>")
|
||||
new /obj/effect/temp_visual/ratvar/spearbreak(T)
|
||||
action.weapon_reset(RATVARIAN_SPEAR_COOLDOWN)
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
//Clockwork armor: High melee protection but weak to lasers
|
||||
/obj/item/clothing/head/helmet/clockwork
|
||||
name = "clockwork helmet"
|
||||
desc = "A heavy helmet made of brass."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "clockwork_helmet"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
flags_inv = HIDEEARS|HIDEHAIR|HIDEFACE
|
||||
armor = list(melee = 50, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/Initialize()
|
||||
. = ..()
|
||||
ratvar_act()
|
||||
GLOB.all_clockwork_objects += src
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else if(GLOB.ratvar_approaches)
|
||||
armor = list(melee = 70, bullet = 80, laser = -15, energy = 25, bomb = 70, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list(melee = 60, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags_1 &= ~STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_head && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>")
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their head!</span>", "<span class='warning'>The helmet flickers off your head, leaving only nausea!</span>")
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.vomit(20)
|
||||
else
|
||||
to_chat(user, "<span class='heavy_brass'>\"Do you have a hole in your head? You're about to.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>The helmet tries to drive a spike through your head as you scramble to remove it!</span>")
|
||||
user.emote("scream")
|
||||
user.apply_damage(30, BRUTE, "head")
|
||||
user.adjustBrainLoss(30)
|
||||
addtimer(CALLBACK(user, /mob/living.proc/dropItemToGround), src, 1) //equipped happens before putting stuff on(but not before picking items up), 1). thus, we need to wait for it to be on before forcing it off.
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork
|
||||
name = "clockwork cuirass"
|
||||
desc = "A bulky cuirass made of brass."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "clockwork_cuirass"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
body_parts_covered = CHEST|GROIN|LEGS
|
||||
cold_protection = CHEST|GROIN|LEGS
|
||||
heat_protection = CHEST|GROIN|LEGS
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
armor = list(melee = 60, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/device/mmi/posibrain/soul_vessel)
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/Initialize()
|
||||
. = ..()
|
||||
ratvar_act()
|
||||
GLOB.all_clockwork_objects += src
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else if(GLOB.ratvar_approaches)
|
||||
armor = list(melee = 70, bullet = 80, laser = -15, energy = 25, bomb = 70, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list(melee = 60, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags_1 &= ~STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_wear_suit && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>")
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their body!</span>", "<span class='warning'>The curiass flickers off your body, leaving only nausea!</span>")
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.vomit(20)
|
||||
else
|
||||
to_chat(user, "<span class='heavy_brass'>\"I think this armor is too hot for you to handle.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>The curiass emits a burst of flame as you scramble to get it off!</span>")
|
||||
user.emote("scream")
|
||||
user.apply_damage(15, BURN, "chest")
|
||||
user.adjust_fire_stacks(2)
|
||||
user.IgniteMob()
|
||||
addtimer(CALLBACK(user, /mob/living.proc/dropItemToGround, src, TRUE), 1)
|
||||
|
||||
/obj/item/clothing/gloves/clockwork
|
||||
name = "clockwork gauntlets"
|
||||
desc = "Heavy, shock-resistant gauntlets with brass reinforcement."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "clockwork_gauntlets"
|
||||
item_state = "clockwork_gauntlets"
|
||||
item_color = null //So they don't wash.
|
||||
strip_delay = 50
|
||||
equip_delay_other = 30
|
||||
body_parts_covered = ARMS
|
||||
cold_protection = ARMS
|
||||
heat_protection = ARMS
|
||||
siemens_coefficient = 0
|
||||
permeability_coefficient = 0.05
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/Initialize()
|
||||
. = ..()
|
||||
ratvar_act()
|
||||
GLOB.all_clockwork_objects += src
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
|
||||
flags_1 |= STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = list(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
flags_1 &= ~STOPSPRESSUREDMAGE_1
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_gloves && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>")
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their arms!</span>", "<span class='warning'>The gauntlets flicker off your arms, leaving only nausea!</span>")
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.vomit()
|
||||
else
|
||||
to_chat(user, "<span class='heavy_brass'>\"Did you like having arms?\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>The gauntlets suddenly squeeze tight, crushing your arms before you manage to get them off!</span>")
|
||||
user.emote("scream")
|
||||
user.apply_damage(7, BRUTE, "l_arm")
|
||||
user.apply_damage(7, BRUTE, "r_arm")
|
||||
addtimer(CALLBACK(user, /mob/living.proc/dropItemToGround, src, TRUE), 1)
|
||||
|
||||
/obj/item/clothing/shoes/clockwork
|
||||
name = "clockwork treads"
|
||||
desc = "Industrial boots made of brass. They're very heavy."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "clockwork_treads"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
strip_delay = 50
|
||||
equip_delay_other = 30
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/Initialize()
|
||||
. = ..()
|
||||
ratvar_act()
|
||||
GLOB.all_clockwork_objects += src
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/negates_gravity()
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
flags_1 |= NOSLIP_1
|
||||
else
|
||||
flags_1 &= ~NOSLIP_1
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
|
||||
if(equipper && !is_servant_of_ratvar(equipper))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/shoes/clockwork/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot == slot_shoes && !is_servant_of_ratvar(user))
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='heavy_brass'>\"Now now, this is for my servants, not you.\"</span>")
|
||||
user.visible_message("<span class='warning'>As [user] puts [src] on, it flickers off their feet!</span>", "<span class='warning'>The treads flicker off your feet, leaving only nausea!</span>")
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
C.vomit()
|
||||
else
|
||||
to_chat(user, "<span class='heavy_brass'>\"Let's see if you can dance with these.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>The treads turn searing hot as you scramble to get them off!</span>")
|
||||
user.emote("scream")
|
||||
user.apply_damage(7, BURN, "l_leg")
|
||||
user.apply_damage(7, BURN, "r_leg")
|
||||
addtimer(CALLBACK(user, /mob/living.proc/dropItemToGround, src, TRUE), 1)
|
||||
@@ -1,520 +0,0 @@
|
||||
/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.<br>\
|
||||
It can be used to link traps and triggers by attacking them with the slab. Keep in mind that traps linked with one another will activate in tandem!"
|
||||
|
||||
icon_state = "dread_ipad"
|
||||
lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
|
||||
var/inhand_overlay //If applicable, this overlay will be applied to the slab's inhand
|
||||
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
var/busy //If the slab is currently being used by something
|
||||
var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks
|
||||
var/speed_multiplier = 1 //multiples how fast this slab recites scripture
|
||||
var/selected_scripture = SCRIPTURE_DRIVER
|
||||
var/obj/effect/proc_holder/slab/slab_ability //the slab's current bound ability, for certain scripture
|
||||
|
||||
var/recollecting = FALSE //if we're looking at fancy recollection
|
||||
var/recollection_category = "Default"
|
||||
|
||||
var/list/quickbound = list(/datum/clockwork_scripture/abscond, \
|
||||
/datum/clockwork_scripture/ranged_ability/kindle, /datum/clockwork_scripture/ranged_ability/hateful_manacles) //quickbound scripture, accessed by index
|
||||
var/maximum_quickbound = 5 //how many quickbound scriptures we can have
|
||||
|
||||
var/obj/structure/destructible/clockwork/trap/linking //If we're linking traps together, which ones we're doing
|
||||
|
||||
/obj/item/clockwork/slab/internal //an internal motor for mobs running scripture
|
||||
name = "scripture motor"
|
||||
quickbound = list()
|
||||
no_cost = TRUE
|
||||
|
||||
/obj/item/clockwork/slab/debug
|
||||
speed_multiplier = 0
|
||||
no_cost = TRUE
|
||||
|
||||
/obj/item/clockwork/slab/debug/attack_hand(mob/living/user)
|
||||
..()
|
||||
if(!is_servant_of_ratvar(user))
|
||||
add_servant_of_ratvar(user)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and fabricator
|
||||
clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture."
|
||||
quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \
|
||||
/datum/clockwork_scripture/create_object/stargazer)
|
||||
maximum_quickbound = 6 //we usually have one or two unique scriptures, so if ratvar is up let us bind one more
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/engineer //two scriptures, plus a fabricator
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transmission)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/medical //five scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/ranged_ability/sentinels_compromise, \
|
||||
/datum/clockwork_scripture/create_object/vitality_matrix)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/security //twoscriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/ranged_ability/hateful_manacles, /datum/clockwork_scripture/ranged_ability/judicial_marker)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/peacekeeper //two scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/ranged_ability/hateful_manacles, /datum/clockwork_scripture/ranged_ability/judicial_marker)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/janitor //five scriptures, plus a fabricator
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transgression, \
|
||||
/datum/clockwork_scripture/create_object/ocular_warden, /datum/clockwork_scripture/create_object/mania_motor, /datum/clockwork_scripture/create_object/stargazer)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/service //five scriptures, plus xray vision
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/stargazer, \
|
||||
/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/create_object/clockwork_obelisk)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/miner //two scriptures, plus a spear and xray vision
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/spatial_gateway)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/access_display(mob/living/user)
|
||||
if(!GLOB.ratvar_awakens)
|
||||
to_chat(user, "<span class='warning'>Use the action buttons to recite your limited set of scripture!</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/ratvar_act()
|
||||
..()
|
||||
if(!GLOB.ratvar_awakens)
|
||||
SStgui.close_uis(src)
|
||||
|
||||
/obj/item/clockwork/slab/Initialize()
|
||||
. = ..()
|
||||
update_slab_info(src)
|
||||
START_PROCESSING(SSobj, src)
|
||||
if(GLOB.ratvar_approaches)
|
||||
name = "supercharged [name]"
|
||||
speed_multiplier = max(0.1, speed_multiplier - 0.25)
|
||||
|
||||
/obj/item/clockwork/slab/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(slab_ability && slab_ability.ranged_ability_user)
|
||||
slab_ability.remove_ranged_ability()
|
||||
slab_ability = null
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/slab/dropped(mob/user)
|
||||
. = ..()
|
||||
addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later
|
||||
|
||||
/obj/item/clockwork/slab/worn_overlays(isinhands = FALSE, icon_file)
|
||||
. = list()
|
||||
if(isinhands && item_state && inhand_overlay)
|
||||
var/mutable_appearance/M = mutable_appearance(icon_file, "slab_[inhand_overlay]")
|
||||
. += M
|
||||
|
||||
/obj/item/clockwork/slab/proc/check_on_mob(mob/user)
|
||||
if(user && !(src in user.held_items) && slab_ability && slab_ability.ranged_ability_user) //if we happen to check and we AREN'T in user's hands, remove whatever ability we have
|
||||
slab_ability.remove_ranged_ability()
|
||||
|
||||
//Power generation
|
||||
/obj/item/clockwork/slab/process()
|
||||
if(GLOB.ratvar_approaches && speed_multiplier == initial(speed_multiplier))
|
||||
name = "supercharged [name]"
|
||||
speed_multiplier = max(0.1, speed_multiplier - 0.25)
|
||||
adjust_clockwork_power(0.1) //Slabs serve as very weak power generators on their own (no, not enough to justify spamming them)
|
||||
|
||||
/obj/item/clockwork/slab/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(LAZYLEN(quickbound))
|
||||
for(var/i in 1 to quickbound.len)
|
||||
if(!quickbound[i])
|
||||
continue
|
||||
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
|
||||
to_chat(user, "<b>Quickbind</b> button: <span class='[get_component_span(initial(quickbind_slot.primary_component))]'>[initial(quickbind_slot.name)]</span>.")
|
||||
to_chat(user, "<b>Available power:</b> <span class='bold brass'>[DisplayPower(get_clockwork_power())].</span>")
|
||||
|
||||
//Slab actions; Hierophant, Quickbind
|
||||
/obj/item/clockwork/slab/ui_action_click(mob/user, action)
|
||||
if(istype(action, /datum/action/item_action/clock/quickbind))
|
||||
var/datum/action/item_action/clock/quickbind/Q = action
|
||||
recite_scripture(quickbound[Q.scripture_index], user, FALSE)
|
||||
|
||||
//Scripture Recital
|
||||
/obj/item/clockwork/slab/attack_self(mob/living/user)
|
||||
if(iscultist(user))
|
||||
to_chat(user, "<span class='heavy_brass'>\"You reek of blood. You've got a lot of nerve to even look at that slab.\"</span>")
|
||||
user.visible_message("<span class='warning'>A sizzling sound comes from [user]'s hands!</span>", "<span class='userdanger'>[src] suddenly grows extremely hot in your hands!</span>")
|
||||
playsound(get_turf(user), 'sound/weapons/sear.ogg', 50, 1)
|
||||
user.dropItemToGround(src)
|
||||
user.emote("scream")
|
||||
user.apply_damage(5, BURN, "l_arm")
|
||||
user.apply_damage(5, BURN, "r_arm")
|
||||
return 0
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='warning'>The information on [src]'s display shifts rapidly. After a moment, your head begins to pound, and you tear your eyes away.</span>")
|
||||
user.confused += 5
|
||||
user.dizziness += 5
|
||||
return 0
|
||||
if(busy)
|
||||
to_chat(user, "<span class='warning'>[src] refuses to work, displaying the message: \"[busy]!\"</span>")
|
||||
return 0
|
||||
if(!no_cost && !can_recite_scripture(user))
|
||||
to_chat(user, "<span class='nezbere'>[src] hums fitfully in your hands, but doesn't seem to do anything...</span>")
|
||||
return 0
|
||||
access_display(user)
|
||||
|
||||
/obj/item/clockwork/slab/AltClick(mob/living/user)
|
||||
if(is_servant_of_ratvar(user) && linking)
|
||||
linking = null
|
||||
to_chat(user, "<span class='notice'>Object link canceled.</span>")
|
||||
|
||||
/obj/item/clockwork/slab/proc/access_display(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return FALSE
|
||||
ui_interact(user)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clockwork/slab/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "clockwork_slab", name, 800, 420, master_ui, state)
|
||||
ui.set_autoupdate(FALSE) //we'll update this occasionally, but not as often as possible
|
||||
ui.set_style("clockwork")
|
||||
ui.open()
|
||||
|
||||
/obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user)
|
||||
if(!scripture || !user || !user.canUseTopic(src) || (!no_cost && !can_recite_scripture(user)))
|
||||
return FALSE
|
||||
if(user.get_active_held_item() != src)
|
||||
to_chat(user, "<span class='warning'>You need to hold the slab in your active hand to recite scripture!</span>")
|
||||
return FALSE
|
||||
var/initial_tier = initial(scripture.tier)
|
||||
if(initial_tier != SCRIPTURE_PERIPHERAL)
|
||||
if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier])
|
||||
to_chat(user, "<span class='warning'>That scripture is not unlocked, and cannot be recited!</span>")
|
||||
return FALSE
|
||||
var/datum/clockwork_scripture/scripture_to_recite = new scripture
|
||||
scripture_to_recite.slab = src
|
||||
scripture_to_recite.invoker = user
|
||||
scripture_to_recite.run_scripture()
|
||||
return TRUE
|
||||
|
||||
|
||||
//Guide to Serving Ratvar
|
||||
/obj/item/clockwork/slab/proc/recollection()
|
||||
var/list/textlist = list("If you're seeing this, file a bug report.")
|
||||
if(GLOB.ratvar_awakens)
|
||||
textlist = list("<font color=#BE8700 size=3><b>")
|
||||
for(var/i in 1 to 100)
|
||||
textlist += "HONOR RATVAR "
|
||||
textlist += "</b></font>"
|
||||
else
|
||||
textlist = list("<font color=#BE8700 size=3><b><center>[text2ratvar("Purge all untruths and honor Engine.")]</center></b></font><br>\
|
||||
\
|
||||
<b><i>NOTICE:</b> This information is out of date. Read the Ark & You primer in your backpack or read the wiki page for current info.</i><br>\
|
||||
<hr><br>\
|
||||
These pages serve as the archives of Ratvar, the Clockwork Justiciar. This section of your slab has information on being as a Servant, advice for what to do next, and \
|
||||
pointers for serving the master well. You should recommended that you check this area for help if you get stuck or need guidance on what to do next.<br><br>\
|
||||
\
|
||||
<i>Disclaimer: Many objects, terms, and phrases, such as Servant, Cache, and Slab, are capitalized like proper nouns. This is a quirk of the Ratvarian language; \
|
||||
do not let it confuse you! You are free to use the names in pronoun form when speaking in normal languages.<br>")
|
||||
return textlist.Join()
|
||||
|
||||
//Gets text for a certain section. "Default" is used for when you first open Recollection.
|
||||
//Current sections (make sure to update this if you add one:
|
||||
//- Basics
|
||||
//- Terminology
|
||||
//- Components
|
||||
//- Scripture
|
||||
//- Power
|
||||
//- Conversion
|
||||
/obj/item/clockwork/slab/proc/get_recollection_text(section)
|
||||
var/list/dat = list()
|
||||
switch(section)
|
||||
if("Default")
|
||||
dat += "You can browse the above sections as you please. They're designed to be read in order, but feel free to pick and choose between them."
|
||||
if("Getting Started")
|
||||
dat += "<font color=#BE8700 size=3>Getting Started</font><br><br>"
|
||||
dat += "Welcome, Servant! This section houses the utmost basics of being a Servant of Ratvar, and is much more informal than the other sections. Being a Servant of \
|
||||
Ratvar is a very complex role, with many systems, objects, and resources to use effectively and creatively.<br><br>"
|
||||
dat += "This section of your clockwork slab covers everything that Servants have to be aware of, but is a long read because of how in-depth the systems are. Knowing \
|
||||
how to use the tools at your disposal makes all the difference between a clueless Servant and a great one.<br><br>"
|
||||
dat += "If this is your first time being a Servant, relax. It's very much possible that you'll fail, but it's impossible to learn without making mistakes. For the time \
|
||||
being, use the Hierophant Network button in the top left-hand corner of your screen to try and get in touch with your fellow Servants; ignore the others for now. This button \
|
||||
will let you send messages across space and time to all other Servants. This makes it great for coordinating, and you should use it often! <i>Note:</i> Using \
|
||||
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 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 \
|
||||
should do the same, either in this cache or in ones of their own.<br><br>"
|
||||
dat += "If you think you're confident in taking further steps to help the cult, feel free to move onto the other sections. If not, let your allies know that you're new and \
|
||||
would appreciate the help they might offer you. Most experienced Servants would be happy to help; if everyone is inexperienced, then you'll have to step out of your comfort \
|
||||
zone and read onto the other sections. It's very likely that you might fail, but don't worry too much about it; you can't learn effectively without making mistakes.<br><br>"
|
||||
dat += "For now, welcome! If you're looking to learn, you should start with the <b>Basics</b> section, then move onto <b>Components</b> and <b>Scripture</b>. At the very \
|
||||
least, you should read the <b><i>Conversion</i></b> section, as it outlines the most important aspects of being a Servant. Good luck!<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
if("Basics")
|
||||
dat += "<font color=#BE8700 size=3>Servant Basics</font><br><br>"
|
||||
dat += "The first thing any Servant should know is their slab, inside and out. The clockwork slab is by far your most important tool. It allows you to speak with your \
|
||||
fellow Servants, create components that fuel many of your abilities, use those abilities, and should be kept safe and hidden on your person at all times. If you have not \
|
||||
done so already, it's a good idea to check for any fellow Servants using the Hierophant Network button in the top-left corner of your screen; due to the cult's nature, \
|
||||
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 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>"
|
||||
if("Terminology")
|
||||
dat += "<font color=#BE8700 size=3>Common Servant Terminology</font><br>"
|
||||
dat += "<i>This isn't intended to be read all at once; you are advised to treat it moreso as a glossary.</i><br><br>"
|
||||
dat += "<font color=#BE8700 size=3>General</font><br>"
|
||||
dat += "<font color=#BE8700><b>Servant:</b></font> A person or robot who serves Ratvar. You are one of these.<br>"
|
||||
dat += "<font color=#BE8700><b>Cache:</b></font> A <i>Tinkerer's Cache</i>, which is a structure that stores and creates components.<br>"
|
||||
dat += "<font color=#BE8700><b>CV:</b></font> Construction Value. All clockwork structures, floors, and walls increase this number.<br>"
|
||||
dat += "<font color=#BE8700><b>Vitality:</b></font> Used for healing effects, produced by Ratvarian spear attacks and Vitality Matrices.<br>"
|
||||
dat += "<font color=#BE8700><b>Geis:</b></font> An important scripture used to make normal crew and robots into Servants of Ratvar.<br>"
|
||||
dat += "<font color=#BE8700><b>Ark:</b></font> The cult's win condition, a huge structure that needs to be defended.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>Items</font><br>"
|
||||
dat += "<font color=#BE8700><b>Slab:</b></font> A clockwork slab, a Servant's most important tool. You're holding one! Keep it safe and hidden.<br>"
|
||||
dat += "<font color=#BE8700><b>Visor:</b></font> A judicial visor, which is a pair of glasses that can smite an area for a brief stun and delayed explosion.<br>"
|
||||
dat += "<font color=#BE8700><b>Wraith Specs:</b></font> Wraith spectacles, which provide true sight (x-ray, night vision) but damage the wearer's eyes.<br>"
|
||||
dat += "<font color=#BE8700><b>Spear:</b></font> A Ratvarian spear, which is a very powerful melee weapon that produces Vitality.<br>"
|
||||
dat += "<font color=#BE8700><b>Fabricator:</b></font> A replica fabricator, which converts objects into clockwork versions.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>Constructs</font><br>"
|
||||
dat += "<font color=#BE8700><b>Marauder:</b></font> A clockwork marauder, which is a powerful bodyguard that hides in its owner.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>Structures (* = requires power)</font><br>"
|
||||
dat += "<font color=#BE8700><b>Warden:</b></font> An ocular warden, which is a ranged turret that damages non-Servants that see it.<br>"
|
||||
dat += "<font color=#BE8700><b>Prism*:</b></font> A prolonging prism, which delays the shuttle for two minutes at a huge power cost.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Motor*:</b></font> A mania motor, which serves as area-denial through negative effects and eventual conversion.<br>"
|
||||
dat += "<font color=#BE8700><b>Daemon*:</b></font> A tinkerer's daemon, which quickly creates components.<br>"
|
||||
dat += "<font color=#BE8700><b>Obelisk*:</b></font> A clockwork obelisk, which can broadcast large messages and allows limited teleportation.<br>"
|
||||
dat += "<font color=#BE8700 size=3>Sigils</font><br>"
|
||||
dat += "<i>Note: Sigils can be stacked on top of one another, making certain sigils very effective when paired!</i><br>"
|
||||
dat += "<font color=#BE8700><b>Transgression:</b></font> Stuns the first non-Servant to cross it for ten seconds and blinds others nearby. Disappears on use.<br>"
|
||||
dat += "<font color=#BE8700><b>Submission:</b></font> Converts the first non-Servant to stand on the sigil for seven seconds. Disappears on use.<br>"
|
||||
dat += "<font color=#BE8700><b>Matrix:</b></font> Drains health from non-Servants, producing Vitality. Can heal and revive Servants.<br>"
|
||||
dat += "<font color=#BE8700><b>Accession:</b></font> Identical to the Sigil of Submission, but doesn't disappear on use. It can also convert a single mindshielded target, but will disappear after doing this.<br>"
|
||||
dat += "<font color=#BE8700><b>Transmission:</b></font> Drains and stores power for clockwork structures. Feeding it brass sheets will create additional power.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
if("Components")
|
||||
dat += "<font color=#BE8700 size=3>Components & Their Uses</font><br><br>"
|
||||
dat += "<b>Components</b> are your primary resource as a Servant. There are five types of component, with each one being used in different roles:<br><br>"
|
||||
dat += "Although this is a good rule of thumb, their effects become much more nuanced when used together. For instance, a turret might have both belligerent eyes and \
|
||||
vanguard cogwheels as construction requirements, because it defends its allies by harming its enemies.<br><br>"
|
||||
dat += "Components' primary use is fueling <b>scripture</b> (covered in its own section), and they can be created through various ways. This clockwork slab, for instance, \
|
||||
will make a random component of every type - or a specific one, if you choose a target component from the interface - every <b>remove me already</b>. This number will increase \
|
||||
as the amount of Servants in the covenant increase; additionally, slabs can only produce components when held by a Servant, and holding more than one slab will cause both \
|
||||
of them to halt progress until one of them is removed from their person.<br><br>"
|
||||
dat += "Your slab has an internal storage of components, but it isn't meant to be the main one. Instead, there's a <b>global storage</b> of components that can be \
|
||||
added to through various ways. Anything that needs components will first draw them from the global storage before attempting to draw them from the slab. Most methods of \
|
||||
component production add to the global storage. You can also offload components from your slab into the global storage by using it on a Tinkerer's Cache, a structure whose \
|
||||
primary purpose is to do just that (although it will also slowly produce components when placed near a brass wall.)<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
if("Scripture")
|
||||
dat += "<font color=#BE8700 size=3>The Ancient Scripture</font><br><br>"
|
||||
dat += "If you have experience with the Nar-Sian cult (or the \"blood cult\") then you will know of runes. They are the manifestations of the Geometer's power, and where most \
|
||||
of the cult's supernatural ability comes from. The Servant equivalent of runes is called <b>scripture</b>, and unlike runes, scripture is loaded into your clockwork slab.<br><br>"
|
||||
dat += "Each piece of scripture has widely-varying effects. Your most important scripture, <i>Geis</i>, is obvious and suspicious, but charges your slab with energy and allows \
|
||||
you to attack a non-Servant in melee range to restrain them and begin converting them into a Servant. This is just one example; each piece of scripture can be simple or \
|
||||
complex, be obvious or have hidden mechanics that can only be found through trial and error.<br><br>"
|
||||
dat += "Any given piece of scripture has a component cost listed in its \"Recite\" button. The acronyms for the components should be obvious if you've read about components \
|
||||
already; reciting this piece of scripture will consume the listed components, first from the global storage and then from your slab. Note that failing to recite a piece of \
|
||||
scripture will <i>not</i> consume the components required to recite it.<br><br>"
|
||||
dat += "It should also be noted that some scripture cannot be recited alone. Especially with more powerful scripture, you may need multiple Servants to recite a piece of \
|
||||
scripture; both of you will need to stand still until the recital completes. <i>Only human and silicon Servants are valid for scripture recital!</i> Constructs cannot help \
|
||||
in reciting scripture.<br><br>"
|
||||
dat += "Finally, scripture is separated into three \"tiers\" based on power: Drivers, Scripts, and Applications.[prob(1) ? " (The Revenant tier was removed a long time ago. \
|
||||
Get with the times.)" : ""] You can view the requirements to unlock each tier in its scripture list. Once a tier is unlocked, it's unlocked permanently; the cult only needs to fill the \
|
||||
requirement for unlocking a tier once!<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
if("Power")
|
||||
dat += "<font color=#BE8700 size=3>Power! Unlimited Power!</font><br><br>"
|
||||
dat += "In the early stages of the cult, the only resource that must be actively worried about is components. However, as new scripture is unlocked, a new resource \
|
||||
becomes necessary: <b>power</b>. Almost all clockwork structures require power to function in some way. There is nothing special about this power; it's mere electricity, \
|
||||
and can be harnessed in several ways.<br><br>"
|
||||
dat += "To begin with, if there is no other source of power nearby, structures will draw from the area's APC, assuming it has one. This is inefficient and ill-advised as \
|
||||
anything but a last resort. Instead, it is recommended that a <b>Sigil of Transmission</b> is created. This sigil serves as both battery and power generator for nearby clockwork \
|
||||
structures, and those structures will happily draw power from the sigil before they resort to APCs.<br><br>"
|
||||
dat += "Generating power is less easy. The most reliable and efficient way is using brass sheets; attacking a sigil of transmission with brass sheets will convert them \
|
||||
to power, at a rate of <b>[DisplayPower(POWER_FLOOR)]</b> per sheet. (Brass sheets are created from replica fabricators, which are explained more in detail in the <b>Conversion</b> section.) \
|
||||
Activating a sigil of transmission will also cause it to drain power from the nearby area, which, while effective, serves as an obvious tell that there is something wrong.<br><br>"
|
||||
dat += "Without power, many structures will not function, making a base vulnerable to attack. For this reason, it is critical that you keep an eye on your power reserves and \
|
||||
ensure that they remain comfortably high.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
if("Conversion")
|
||||
dat += "<font color=#BE8700 size=3>Growing the Ranks</font><br><br>"
|
||||
dat += "Because the Servants of Ratvar are a cult, the main method to gain more power is to \"enlighten\" normal crew into new Servants. When a crewmember is converted, \
|
||||
they become a full-fledged Servant, ready and willing to serve the cause of Ratvar. It should also be noted that <i>silicon crew, such as cyborgs and the AI, can be \
|
||||
converted just like normal crew</i> and will gain special abilities; this is covered later. This section will also cover converting the station's structure itself; walls, \
|
||||
floors, windows, tables, and other objects can all be converted into clockwork versions, and serve an important purpose.<br><br>"
|
||||
dat += "<font color=#BE8700><b>A Note on Geis:</b></font> There are several ways to convert humans and silicons. However, the most important tool to making them work is \
|
||||
<b>Geis</b>, a Driver-tier scripture. Using it whispers an invocation very quickly and charges your slab with power. In addition to <i>making the slab visible in your hand,</i> \
|
||||
you can now use it on a target within melee range to bind and mute them. It is by far your most reliable tool for capturing potential converts and targets, though it is incredibly \
|
||||
obvious. In addition, you are unable to take any actions other than moving while your target is bound. The binding will last for 25 seconds and mute for about 13 seconds, though \
|
||||
allies can use Geis to refresh these effects.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting:</b></font> The two methods of conversion are the <b>sigil of submission</b>, whose purpose is to do so, and the <b>mania motor.</b> \
|
||||
The sigil of submission is a sigil that, when stood on by a non-Servant for eight seconds, will convert that non-Servant. This is the only practical way to convert targets. \
|
||||
Sigils of submission are cheap, early, and permanent! Make sure sigils of submission are placed only in bases or otherwise hidden spots, or with a sigil of transgression on them. \
|
||||
The mania motor, however, is generally unreliable and unlocked later, only converting those who stand near it for an extended period.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting Humans:</b></font> For obvious reasons, humans are the most common conversion target. Because every crew member is different, and \
|
||||
may be armed with different equipment, you should take precautions to ensure that they aren't able to resist. If able, removing a headset is essential, as is restraining \
|
||||
them through handcuffs, cable ties, or other restraints. Some crew, like security, are also implanted with mindshield implants; these will prevent conversion and must be \
|
||||
surgically removed before they are an eligible convert. <i>Note:</i> The captain is <i>never</i> an eligible convert and should instead be killed or imprisoned. If security \
|
||||
begins administering mindshield implants, this will greatly inhibit conversion. Also note that mindshield implants can be broken by a sigil of accession automatically, but \
|
||||
the sigil will disappear.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting Silicons:</b></font> Due to their robotic nature, silicons are generally more predictable than humans in terms of conversion. \
|
||||
However, they are also much, much harder to subdue, especially cyborgs. The easiest way to convert a cyborg is by using Geis to restrain them, then dragging them to a sigil \
|
||||
of submission. If you stack a sigil of transgression and a sigil of submission, a crossing cyborg will be stunned and helpless to escape before they are converted.<br><br>"
|
||||
dat += "Converting AIs is very often the hardest task of the cult, and has been the downfall of countless successful Servants. Their omnipresence across the station, \
|
||||
coupled with their secure location and ability to lock themselves securely, makes them a powerful target. However, once the AI itself is reached, it is usually completely \
|
||||
helpless to resist its own conversion. A very common tactic is to take advantage of a converted cyborg to rush the AI before it is able to react.<br><br>"
|
||||
dat += "Even once an AI is converted, care must be taken to ensure that it remains hidden. Not only does the AI's core become brassy and thus obvious to an outside \
|
||||
observer, but <i>the AI loses the ability to speak in anything but Ratvarian.</i> For this reason, it has to remain completely silent over common radio channels if stealth \
|
||||
is at all a priority. This is suspicious and will rapidly lead to the crew checking on it, which usually results in the cult's outing. It is, however, necessary to convert \
|
||||
all AIs present on the station before the Ark becomes invokable, so this must be done at some point.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting the Station:</b></font> Converted objects all serve a purpose and are important to the cult's success. To convert objects, \
|
||||
a Servant needs to use a <b>replica fabricator,</b> a handheld tool that uses power to replace objects with clockwork versions. Different clockwork objects have different \
|
||||
effects and are often crucial. The most noteworthy are <b>clockwork walls,</b> which automatically \"link\" to any nearby Tinkerer's Caches, causing them to <b>slowly \
|
||||
generate components.</b> This is incredibly useful for obvious reasons, and creating a clockwork wall near every Tinkerer's Cache should be prioritized. Clockwork floors \
|
||||
will slowly heal any toxin damage suffered by Servants standing on them, and clockwork airlocks can only be opened by Servants.<br><br>"
|
||||
dat += "The replica fabricator itself is also worth noting. In addition to replacing objects, it can also create brass sheets at the cost of power by using the \
|
||||
fabricator in-hand. It can also be used to repair any damaged clockwork structures.<br><br>"
|
||||
dat += "Replacing objects is almost as, if not as important as, converting new Servants. A base is impossible to manage without clockwork walls at the very least, and \
|
||||
once the cult has been outed and the crew are actively searching, there is little reason not to use as many as possible.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
else
|
||||
dat += "<font color=#BE8700 size=3>404: [section ? section : "Section"] Not Found!</font><br><br>\
|
||||
One of the cogscarabs must've misplaced this section, because the game wasn't able to find any info regarding it. Report this to the coders!"
|
||||
return "<br><br>[dat.Join()]<br><br>"
|
||||
|
||||
//Gets the quickbound scripture as a text block.
|
||||
/obj/item/clockwork/slab/proc/get_recollection_quickbinds()
|
||||
var/list/dat = list()
|
||||
dat += "<font color=#BE8700 size=3>Quickbound Scripture</font><br>\
|
||||
<i>You can have up to five scriptures bound to action buttons for easy use.</i><br><br>"
|
||||
if(LAZYLEN(quickbound))
|
||||
for(var/i in 1 to maximum_quickbound)
|
||||
if(LAZYLEN(quickbound) < i || !quickbound[i])
|
||||
dat += "A <b>Quickbind</b> slot, currently set to <b><font color=#BE8700>Nothing</font></b>.<br>"
|
||||
else
|
||||
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
|
||||
dat += "A <b>Quickbind</b> slot, currently set to <b><font color=[get_component_color_bright(initial(quickbind_slot.primary_component))]>[initial(quickbind_slot.name)]</font></b>.<br>"
|
||||
return dat.Join()
|
||||
|
||||
|
||||
/obj/item/clockwork/slab/ui_data(mob/user) //we display a lot of data via TGUI
|
||||
var/list/data = list()
|
||||
data["power"] = "<b><font color=#B18B25>[DisplayPower(get_clockwork_power())]</b> power is available for scripture and other consumers.</font>"
|
||||
|
||||
switch(selected_scripture) //display info based on selected scripture tier
|
||||
if(SCRIPTURE_DRIVER)
|
||||
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permanently unlocked.</b></font>"
|
||||
if(SCRIPTURE_SCRIPT)
|
||||
if(SSticker.scripture_states[SCRIPTURE_SCRIPT])
|
||||
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permanently unlocked.</b></font>"
|
||||
else
|
||||
data["tier_info"] = "<font color=#B18B25><i>These scriptures will automatically unlock when the Ark is halfway ready or if [DisplayPower(SCRIPT_UNLOCK_THRESHOLD)] of power is reached.</i></font>"
|
||||
if(SCRIPTURE_APPLICATION)
|
||||
if(SSticker.scripture_states[SCRIPTURE_APPLICATION])
|
||||
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permanently unlocked.</b></font>"
|
||||
else
|
||||
data["tier_info"] = "<font color=#B18B25><i>Unlock these optional scriptures by converting another servant or if [DisplayPower(APPLICATION_UNLOCK_THRESHOLD)] of power is reached..</i></font>"
|
||||
|
||||
data["selected"] = selected_scripture
|
||||
data["scripturecolors"] = "<font color=#DAAA18>Scriptures in <b>yellow</b> are related to construction and building.</font><br>\
|
||||
<font color=#6E001A>Scriptures in <b>red</b> are related to attacking and offense.</font><br>\
|
||||
<font color=#1E8CE1>Scriptures in <b>blue</b> are related to healing and defense.</font><br>\
|
||||
<font color=#AF0AAF>Scriptures in <b>purple</b> are niche but still important!</font>"
|
||||
generate_all_scripture()
|
||||
|
||||
data["scripture"] = list()
|
||||
for(var/s in GLOB.all_scripture)
|
||||
var/datum/clockwork_scripture/S = GLOB.all_scripture[s]
|
||||
if(S.tier == selected_scripture) //display only scriptures of the selected tier
|
||||
var/scripture_color = get_component_color_bright(S.primary_component)
|
||||
var/list/temp_info = list("name" = "<font color=[scripture_color]><b>[S.name]</b></font>",
|
||||
"descname" = "<font color=[scripture_color]>([S.descname])</font>",
|
||||
"tip" = "[S.desc]\n[S.usage_tip]",
|
||||
"required" = "([DisplayPower(S.power_cost)][S.special_power_text ? "+ [replacetext(S.special_power_text, "POWERCOST", "[DisplayPower(S.special_power_cost)]")]" : ""])",
|
||||
"type" = "[S.type]",
|
||||
"quickbind" = S.quickbind)
|
||||
var/found = quickbound.Find(S.type)
|
||||
if(found)
|
||||
temp_info["bound"] = "<b>[found]</b>"
|
||||
if(S.invokers_required > 1)
|
||||
temp_info["invokers"] = "<font color=#B18B25>Invokers: <b>[S.invokers_required]</b></font>"
|
||||
data["scripture"] += list(temp_info)
|
||||
data["recollection"] = recollecting
|
||||
if(recollecting)
|
||||
data["recollection_categories"] = GLOB.ratvar_awakens ? list() : list(\
|
||||
list("name" = "Getting Started", "desc" = "First-time servant? Read this first."), \
|
||||
list("name" = "Basics", "desc" = "A primer on how to play as a servant."), \
|
||||
list("name" = "Terminology", "desc" = "Common acronyms, words, and terms."), \
|
||||
list("name" = "Components", "desc" = "Information on components, your primary resource."), \
|
||||
list("name" = "Scripture", "desc" = "Information on scripture, ancient tools used by the cult."), \
|
||||
list("name" = "Power", "desc" = "The power system that certain objects use to function."), \
|
||||
list("name" = "Conversion", "desc" = "Converting the crew, cyborgs, and very walls to your cause."), \
|
||||
)
|
||||
data["rec_text"] = recollection()
|
||||
data["rec_section"] = GLOB.ratvar_awakens ? "" : get_recollection_text(recollection_category)
|
||||
data["rec_binds"] = GLOB.ratvar_awakens ? "" : get_recollection_quickbinds()
|
||||
return data
|
||||
|
||||
/obj/item/clockwork/slab/ui_act(action, params)
|
||||
switch(action)
|
||||
if("toggle")
|
||||
recollecting = !recollecting
|
||||
if("recite")
|
||||
INVOKE_ASYNC(src, .proc/recite_scripture, text2path(params["category"]), usr, FALSE)
|
||||
if("select")
|
||||
selected_scripture = params["category"]
|
||||
if("bind")
|
||||
var/datum/clockwork_scripture/path = text2path(params["category"]) //we need a path and not a string
|
||||
var/found_index = quickbound.Find(path)
|
||||
if(found_index) //hey, we already HAVE this bound
|
||||
if(LAZYLEN(quickbound) == found_index) //if it's the last scripture, remove it instead of leaving a null
|
||||
quickbound -= path
|
||||
else
|
||||
quickbound[found_index] = null //otherwise, leave it as a null so the scripture maintains position
|
||||
update_quickbind()
|
||||
else
|
||||
var/target_index = input("Position of [initial(path.name)], 1 to [maximum_quickbound]?", "Input") as num|null
|
||||
if(isnum(target_index) && target_index > 0 && target_index <= maximum_quickbound && !..())
|
||||
var/datum/clockwork_scripture/S
|
||||
if(LAZYLEN(quickbound) >= target_index)
|
||||
S = quickbound[target_index]
|
||||
if(S != path)
|
||||
quickbind_to_slot(path, target_index)
|
||||
if("rec_category")
|
||||
recollection_category = params["category"]
|
||||
ui_interact(usr)
|
||||
return 1
|
||||
|
||||
/obj/item/clockwork/slab/proc/quickbind_to_slot(datum/clockwork_scripture/scripture, index) //takes a typepath(typecast for initial()) and binds it to a slot
|
||||
if(!ispath(scripture) || !scripture || (scripture in quickbound))
|
||||
return
|
||||
while(LAZYLEN(quickbound) < index)
|
||||
quickbound += null
|
||||
var/datum/clockwork_scripture/quickbind_slot = GLOB.all_scripture[quickbound[index]]
|
||||
if(quickbind_slot && !quickbind_slot.quickbind)
|
||||
return //we can't unbind things we can't normally bind
|
||||
quickbound[index] = scripture
|
||||
update_quickbind()
|
||||
|
||||
/obj/item/clockwork/slab/proc/update_quickbind()
|
||||
for(var/datum/action/item_action/clock/quickbind/Q in actions)
|
||||
qdel(Q) //regenerate all our quickbound scriptures
|
||||
if(LAZYLEN(quickbound))
|
||||
for(var/i in 1 to quickbound.len)
|
||||
if(!quickbound[i])
|
||||
continue
|
||||
var/datum/action/item_action/clock/quickbind/Q = new /datum/action/item_action/clock/quickbind(src)
|
||||
Q.scripture_index = i
|
||||
var/datum/clockwork_scripture/quickbind_slot = GLOB.all_scripture[quickbound[i]]
|
||||
Q.name = "[quickbind_slot.name] ([Q.scripture_index])"
|
||||
Q.desc = quickbind_slot.quickbind_desc
|
||||
Q.button_icon_state = quickbind_slot.name
|
||||
Q.UpdateButtonIcon()
|
||||
if(isliving(loc))
|
||||
Q.Grant(loc)
|
||||
@@ -1,15 +0,0 @@
|
||||
//This is the base type for clockwork melee weapons.
|
||||
/obj/item/clockwork/weapon
|
||||
name = "clockwork weapon"
|
||||
desc = "Weaponized brass. Whould've thunk it?"
|
||||
clockwork_desc = "This shouldn't exist. Report it to a coder."
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
|
||||
var/datum/action/innate/call_weapon/action //Some melee weapons use an action that lets you return and dismiss them
|
||||
|
||||
/obj/item/clockwork/weapon/Initialize(mapload, new_action)
|
||||
. = ..()
|
||||
if(new_action)
|
||||
action = new_action
|
||||
action.weapon = src
|
||||
@@ -1,116 +0,0 @@
|
||||
//Construct shells that can be activated by ghosts.
|
||||
/obj/item/clockwork/construct_chassis
|
||||
name = "construct chassis"
|
||||
desc = "A shell formed out of brass, presumably for housing machinery."
|
||||
clockwork_desc = "A construct chassis. It can be activated at any time by a willing ghost."
|
||||
var/construct_name = "basic construct"
|
||||
var/construct_desc = "<span class='alloy'>There is no construct for this chassis. Report this to a coder.</span>"
|
||||
icon_state = "anime_fragment"
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
var/creation_message = "<span class='brass'>The chassis shudders and hums to life!</span>"
|
||||
var/construct_type //The construct this shell will create
|
||||
|
||||
/obj/item/clockwork/construct_chassis/Initialize()
|
||||
. = ..()
|
||||
var/area/A = get_area(src)
|
||||
if(A && construct_type)
|
||||
notify_ghosts("A [construct_name] chassis has been created in [A.name]!", 'sound/magic/clockwork/fellowship_armory.ogg', source = src, action = NOTIFY_ATTACK, flashwindow = FALSE)
|
||||
GLOB.poi_list += src
|
||||
LAZYADD(GLOB.mob_spawners[name], src)
|
||||
|
||||
/obj/item/clockwork/construct_chassis/Destroy()
|
||||
GLOB.poi_list -= src
|
||||
var/list/spawners = GLOB.mob_spawners[name]
|
||||
LAZYREMOVE(spawners, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/construct_chassis/examine(mob/user)
|
||||
clockwork_desc = "[clockwork_desc]<br>[construct_desc]"
|
||||
..()
|
||||
clockwork_desc = initial(clockwork_desc)
|
||||
|
||||
/obj/item/clockwork/construct_chassis/attack_hand(mob/living/user)
|
||||
if(w_class >= WEIGHT_CLASS_HUGE)
|
||||
to_chat(user, "<span class='warning'>[src] is too cumbersome to carry! Drag it around instead!</span>")
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/construct_chassis/attack_ghost(mob/user)
|
||||
if(!SSticker.mode)
|
||||
to_chat(user, "<span class='danger'>You cannot use that before the game has started.</span>")
|
||||
return
|
||||
if(QDELETED(src))
|
||||
to_chat(user, "<span class='danger'>You were too late! Better luck next time.</span>")
|
||||
return
|
||||
user.forceMove(get_turf(src)) //If we attack through the alert, jump to the chassis so we know what we're getting into
|
||||
if(alert(user, "Become a [construct_name]? You can no longer be cloned!", construct_name, "Yes", "Cancel") == "Cancel")
|
||||
return
|
||||
if(QDELETED(src))
|
||||
to_chat(user, "<span class='danger'>You were too late! Better luck next time.</span>")
|
||||
return
|
||||
pre_spawn()
|
||||
visible_message(creation_message)
|
||||
var/mob/living/construct = new construct_type(get_turf(src))
|
||||
construct.key = user.key
|
||||
post_spawn(construct)
|
||||
qdel(user)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/clockwork/construct_chassis/proc/pre_spawn() //Some things might change before the construct spawns; override those on a subtype basis in this proc
|
||||
return
|
||||
|
||||
/obj/item/clockwork/construct_chassis/proc/post_spawn(mob/living/construct) //And some things might change after it
|
||||
return
|
||||
|
||||
|
||||
//Marauder armor, used to create clockwork marauders - sturdy frontline combatants that can deflect projectiles.
|
||||
/obj/item/clockwork/construct_chassis/clockwork_marauder
|
||||
name = "marauder armor"
|
||||
desc = "A pile of sleek and well-polished brass armor. A small red gemstone sits in its faceplate."
|
||||
icon_state = "marauder_armor"
|
||||
construct_name = "clockwork marauder"
|
||||
construct_desc = "<span class='neovgre_small'>It will become a <b>clockwork marauder,</b> a well-rounded frontline combatant.</span>"
|
||||
creation_message = "<span class='neovgre_small bold'>Crimson fire begins to rage in the armor as it rises into the air with its armaments!</span>"
|
||||
construct_type = /mob/living/simple_animal/hostile/clockwork/marauder
|
||||
|
||||
|
||||
//Cogscarab shell, used to create cogcarabs - fragile but zippy little drones that build and maintain the base.
|
||||
/obj/item/clockwork/construct_chassis/cogscarab
|
||||
name = "cogscarab shell"
|
||||
desc = "A small, complex shell that resembles a repair drone, but much larger and made out of brass."
|
||||
icon_state = "cogscarab_shell"
|
||||
construct_name = "cogscarab"
|
||||
construct_desc = "<span class='alloy'>It will become a <b>cogscarab,</b> a small and fragile drone that builds, repairs, and maintains.</span>"
|
||||
creation_message = "<span class='alloy bold'>The cogscarab clicks and whirrs as it hops up and springs to life!</span>"
|
||||
construct_type = /mob/living/simple_animal/drone/cogscarab
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
var/infinite_resources = TRUE
|
||||
var/static/obj/item/seasonal_hat //Share it with all other scarabs, since we're from the same cult!
|
||||
|
||||
/obj/item/clockwork/construct_chassis/cogscarab/Initialize()
|
||||
. = ..()
|
||||
if(GLOB.servants_active)
|
||||
infinite_resources = FALSE //For any that are somehow spawned in late
|
||||
|
||||
/obj/item/clockwork/construct_chassis/cogscarab/pre_spawn()
|
||||
if(infinite_resources)
|
||||
//During rounds where they can't interact with the station, let them experiment with builds
|
||||
construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar
|
||||
if(!seasonal_hat)
|
||||
var/obj/item/drone_shell/D = locate() in GLOB.poi_list
|
||||
if(D && D.possible_seasonal_hats.len)
|
||||
seasonal_hat = pick(D.possible_seasonal_hats)
|
||||
else
|
||||
seasonal_hat = "none"
|
||||
|
||||
/obj/item/clockwork/construct_chassis/cogscarab/post_spawn(mob/living/construct)
|
||||
if(infinite_resources) //Allow them to build stuff and recite scripture
|
||||
var/list/cached_stuff = construct.GetAllContents()
|
||||
for(var/obj/item/clockwork/replica_fabricator/F in cached_stuff)
|
||||
F.uses_power = FALSE
|
||||
for(var/obj/item/clockwork/slab/S in cached_stuff)
|
||||
S.no_cost = TRUE
|
||||
if(seasonal_hat && seasonal_hat != "none")
|
||||
var/obj/item/hat = new seasonal_hat(construct)
|
||||
construct.equip_to_slot_or_del(hat, slot_head)
|
||||
@@ -1,35 +0,0 @@
|
||||
#define COG_MAX_SIPHON_THRESHOLD 0.25 //The cog will not siphon power if the APC's cell is at this % of power
|
||||
|
||||
//Can be used on an open APC to replace its guts with clockwork variants, and begin passively siphoning power from it
|
||||
/obj/item/clockwork/integration_cog
|
||||
name = "integration cog"
|
||||
desc = "A small cogwheel that fits in the palm of your hand."
|
||||
clockwork_desc = "A small cogwheel that can be inserted into an open APC to siphon power from it passively.<br>\
|
||||
<span class='brass'>It can be used on a locked APC to open its cover!</span><br>\
|
||||
<span class='brass'>Siphons <b>5 W</b> of power per second while in an APC.</span>"
|
||||
icon_state = "wall_gear"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
flags_1 = NOBLUDGEON_1
|
||||
var/obj/machinery/power/apc/apc
|
||||
|
||||
/obj/item/clockwork/integration_cog/Initialize()
|
||||
. = ..()
|
||||
transform *= 0.5 //little cog!
|
||||
|
||||
/obj/item/clockwork/integration_cog/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/clockwork/integration_cog/process()
|
||||
if(!apc)
|
||||
if(istype(loc, /obj/machinery/power/apc))
|
||||
apc = loc
|
||||
else
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
else
|
||||
var/obj/item/stock_parts/cell/cell = apc.cell
|
||||
if(cell && (cell.charge / cell.maxcharge > COG_MAX_SIPHON_THRESHOLD))
|
||||
cell.use(1)
|
||||
adjust_clockwork_power(1) //Power is shared, so only do it once; this runs very quickly so it's about 1W/second
|
||||
|
||||
#undef COG_MAX_SIPHON_THRESHOLD
|
||||
@@ -1,216 +0,0 @@
|
||||
//Judicial visor: Grants the ability to smite an area and knocking down the unfaithful nearby every thirty seconds.
|
||||
/obj/item/clothing/glasses/judicial_visor
|
||||
name = "judicial visor"
|
||||
desc = "A strange purple-lensed visor. Looking at it inspires an odd sense of guilt."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "judicial_visor_0"
|
||||
item_state = "sunglasses"
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
flash_protect = 1
|
||||
var/active = FALSE //If the visor is online
|
||||
var/recharging = FALSE //If the visor is currently recharging
|
||||
var/obj/effect/proc_holder/judicial_visor/blaster
|
||||
var/recharge_cooldown = 300 //divided by 10 if ratvar is alive
|
||||
actions_types = list(/datum/action/item_action/clock/toggle_visor)
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/Initialize()
|
||||
. = ..()
|
||||
GLOB.all_clockwork_objects += src
|
||||
blaster = new(src)
|
||||
blaster.visor = src
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
if(blaster.ranged_ability_user)
|
||||
blaster.remove_ranged_ability()
|
||||
blaster.visor = null
|
||||
qdel(blaster)
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/item_action_slot_check(slot, mob/user)
|
||||
if(slot != slot_glasses)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot != slot_glasses)
|
||||
update_status(FALSE)
|
||||
if(blaster.ranged_ability_user)
|
||||
blaster.remove_ranged_ability()
|
||||
return 0
|
||||
if(is_servant_of_ratvar(user))
|
||||
update_status(TRUE)
|
||||
else
|
||||
update_status(FALSE)
|
||||
if(iscultist(user)) //Cultists spontaneously combust
|
||||
to_chat(user, "<span class='heavy_brass'>\"Consider yourself judged, whelp.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>You suddenly catch fire!</span>")
|
||||
user.adjust_fire_stacks(5)
|
||||
user.IgniteMob()
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/dropped(mob/user)
|
||||
. = ..()
|
||||
addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/proc/check_on_mob(mob/user)
|
||||
if(user && src != user.get_item_by_slot(slot_glasses)) //if we happen to check and we AREN'T in the slot, we need to remove our shit from whoever we got dropped from
|
||||
update_status(FALSE)
|
||||
if(blaster.ranged_ability_user)
|
||||
blaster.remove_ranged_ability()
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/attack_self(mob/user)
|
||||
if(is_servant_of_ratvar(user) && src == user.get_item_by_slot(slot_glasses))
|
||||
blaster.toggle(user)
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/proc/update_status(change_to)
|
||||
if(recharging || !isliving(loc))
|
||||
icon_state = "judicial_visor_0"
|
||||
return 0
|
||||
if(active == change_to)
|
||||
return 0
|
||||
var/mob/living/L = loc
|
||||
active = change_to
|
||||
icon_state = "judicial_visor_[active]"
|
||||
L.update_action_buttons_icon()
|
||||
L.update_inv_glasses()
|
||||
if(!is_servant_of_ratvar(L) || L.stat)
|
||||
return 0
|
||||
switch(active)
|
||||
if(TRUE)
|
||||
to_chat(L, "<span class='notice'>As you put on [src], its lens begins to glow, information flashing before your eyes.</span>\n\
|
||||
<span class='heavy_brass'>Judicial visor active. Use the action button to gain the ability to smite the unworthy.</span>")
|
||||
if(FALSE)
|
||||
to_chat(L, "<span class='notice'>As you take off [src], its lens darkens once more.</span>")
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/glasses/judicial_visor/proc/recharge_visor(mob/living/user)
|
||||
if(!src)
|
||||
return 0
|
||||
recharging = FALSE
|
||||
if(user && src == user.get_item_by_slot(slot_glasses))
|
||||
to_chat(user, "<span class='brass'>Your [name] hums. It is ready.</span>")
|
||||
else
|
||||
active = FALSE
|
||||
icon_state = "judicial_visor_[active]"
|
||||
if(user)
|
||||
user.update_action_buttons_icon()
|
||||
user.update_inv_glasses()
|
||||
|
||||
/obj/effect/proc_holder/judicial_visor
|
||||
active = FALSE
|
||||
ranged_mousepointer = 'icons/effects/visor_reticule.dmi'
|
||||
var/obj/item/clothing/glasses/judicial_visor/visor
|
||||
|
||||
/obj/effect/proc_holder/judicial_visor/proc/toggle(mob/user)
|
||||
var/message
|
||||
if(active)
|
||||
message = "<span class='brass'>You dispel the power of [visor].</span>"
|
||||
remove_ranged_ability(message)
|
||||
else
|
||||
message = "<span class='brass'><i>You harness [visor]'s power.</i> <b>Left-click to place a judicial marker!</b></span>"
|
||||
add_ranged_ability(user, message)
|
||||
|
||||
/obj/effect/proc_holder/judicial_visor/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return
|
||||
if(ranged_ability_user.incapacitated() || !visor || visor != ranged_ability_user.get_item_by_slot(slot_glasses))
|
||||
remove_ranged_ability()
|
||||
return
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return FALSE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
visor.recharging = TRUE
|
||||
visor.update_status()
|
||||
for(var/obj/item/clothing/glasses/judicial_visor/V in ranged_ability_user.GetAllContents())
|
||||
if(V == visor)
|
||||
continue
|
||||
V.recharging = TRUE //To prevent exploiting multiple visors to bypass the cooldown
|
||||
V.update_status()
|
||||
addtimer(CALLBACK(V, /obj/item/clothing/glasses/judicial_visor.proc/recharge_visor, ranged_ability_user), (GLOB.ratvar_awakens ? visor.recharge_cooldown*0.1 : visor.recharge_cooldown) * 2)
|
||||
clockwork_say(ranged_ability_user, text2ratvar("Kneel, heathens!"))
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user]'s judicial visor fires a stream of energy at [target], creating a strange mark!</span>", "<span class='heavy_brass'>You direct [visor]'s power to [target]. You must wait for some time before doing this again.</span>")
|
||||
var/turf/targetturf = get_turf(target)
|
||||
new/obj/effect/clockwork/judicial_marker(targetturf, ranged_ability_user)
|
||||
add_logs(ranged_ability_user, targetturf, "created a judicial marker")
|
||||
ranged_ability_user.update_action_buttons_icon()
|
||||
ranged_ability_user.update_inv_glasses()
|
||||
addtimer(CALLBACK(visor, /obj/item/clothing/glasses/judicial_visor.proc/recharge_visor, ranged_ability_user), GLOB.ratvar_awakens ? visor.recharge_cooldown*0.1 : visor.recharge_cooldown)//Cooldown is reduced by 10x if Ratvar is up
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//Judicial marker: Created by the judicial visor. Immediately applies Belligerent and briefly knocks down, then after 3 seconds does large damage and briefly knocks down again
|
||||
/obj/effect/clockwork/judicial_marker
|
||||
name = "judicial marker"
|
||||
desc = "You get the feeling that you shouldn't be standing here."
|
||||
clockwork_desc = "A sigil that will soon erupt and smite any unenlightened nearby."
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
layer = BELOW_MOB_LAYER
|
||||
var/mob/user
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/Initialize(mapload, caster)
|
||||
. = ..()
|
||||
set_light(1.4, 2, "#FE9C11")
|
||||
user = caster
|
||||
INVOKE_ASYNC(src, .proc/judicialblast)
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/proc/judicialblast()
|
||||
playsound(src, 'sound/magic/magic_missile.ogg', 50, 1, 1, 1)
|
||||
flick("judicial_marker", src)
|
||||
for(var/mob/living/carbon/C in range(1, src))
|
||||
var/datum/status_effect/belligerent/B = C.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
|
||||
if(!QDELETED(B))
|
||||
B.duration = world.time + 30
|
||||
C.Knockdown(5) //knocks down for half a second if affected
|
||||
sleep(!GLOB.ratvar_approaches ? 16 : 10)
|
||||
name = "judicial blast"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
flick("judicial_explosion", src)
|
||||
set_light(1.4, 2, "#B451A1")
|
||||
sleep(13)
|
||||
name = "judicial explosion"
|
||||
var/targetsjudged = 0
|
||||
playsound(src, 'sound/effects/explosion_distant.ogg', 100, 1, 1, 1)
|
||||
set_light(0)
|
||||
for(var/mob/living/L in range(1, src))
|
||||
if(is_servant_of_ratvar(L))
|
||||
continue
|
||||
if(L.null_rod_check())
|
||||
var/obj/item/I = L.null_rod_check()
|
||||
L.visible_message("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
|
||||
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
|
||||
continue
|
||||
L.Knockdown(15) //knocks down briefly when exploding
|
||||
if(!iscultist(L))
|
||||
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
|
||||
"<span class='userdanger'>[!issilicon(L) ? "An unseen force slams you into the ground!" : "ERROR: Motor servos disabled by external source!"]</span>")
|
||||
else
|
||||
L.visible_message("<span class='warning'>[L] is struck by a judicial explosion!</span>", \
|
||||
"<span class='heavy_brass'>\"Keep an eye out, filth.\"</span>\n<span class='userdanger'>A burst of heat crushes you against the ground!</span>")
|
||||
L.adjust_fire_stacks(2) //sets cultist targets on fire
|
||||
L.IgniteMob()
|
||||
L.adjustFireLoss(5)
|
||||
targetsjudged++
|
||||
if(!QDELETED(L))
|
||||
L.adjustBruteLoss(20) //does a decent amount of damage
|
||||
add_logs(user, L, "struck with a judicial blast")
|
||||
to_chat(user, "<span class='brass'><b>[targetsjudged ? "Successfully judged <span class='neovgre'>[targetsjudged]</span>":"Judged no"] heretic[targetsjudged == 1 ? "":"s"].</b></span>")
|
||||
sleep(3) //so the animation completes properly
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/clockwork/judicial_marker/ex_act(severity)
|
||||
return
|
||||
@@ -1,224 +0,0 @@
|
||||
//Replica Fabricator: Converts applicable objects to Ratvarian variants.
|
||||
/obj/item/clockwork/replica_fabricator
|
||||
name = "replica fabricator"
|
||||
desc = "An odd, L-shaped device that hums with energy."
|
||||
clockwork_desc = "A device that allows the replacing of mundane objects with Ratvarian variants. It requires power to function."
|
||||
icon_state = "replica_fabricator"
|
||||
lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
force = 5
|
||||
flags_1 = NOBLUDGEON_1
|
||||
var/speed_multiplier = 1 //The speed ratio the fabricator operates at
|
||||
var/uses_power = TRUE
|
||||
var/repairing = null //what we're currently repairing, if anything
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/scarab
|
||||
name = "scarab fabricator"
|
||||
clockwork_desc = "A cogscarab's internal fabricator. It can only be successfully used by a cogscarab and requires power to function."
|
||||
item_state = "nothing"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
speed_multiplier = 0.5
|
||||
var/debug = FALSE
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/scarab/fabricate(atom/target, mob/living/user)
|
||||
if(!debug && !isdrone(user))
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/scarab/debug
|
||||
clockwork_desc = "A cogscarab's internal fabricator. It can convert nearly any object into a Ratvarian variant."
|
||||
uses_power = FALSE
|
||||
debug = TRUE
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/cyborg
|
||||
name = "cyborg fabricator"
|
||||
clockwork_desc = "A cyborg's internal fabricator."
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
uses_power = FALSE
|
||||
speed_multiplier = initial(speed_multiplier) * 0.25
|
||||
else
|
||||
uses_power = initial(uses_power)
|
||||
speed_multiplier = initial(speed_multiplier)
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/examine(mob/living/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='brass'>Can be used to replace walls, floors, tables, windows, windoors, and airlocks with Clockwork variants.</span>")
|
||||
to_chat(user, "<span class='brass'>Can construct Clockwork Walls on Clockwork Floors and deconstruct Clockwork Walls to Clockwork Floors.</span>")
|
||||
if(uses_power)
|
||||
to_chat(user, "<span class='alloy'>It can consume floor tiles, rods, metal, and plasteel for power at rates of <b>2:[DisplayPower(POWER_ROD)]</b>, <b>1:[DisplayPower(POWER_ROD)]</b>, <b>1:[DisplayPower(POWER_METAL)]</b>, \
|
||||
and <b>1:[DisplayPower(POWER_PLASTEEL)]</b>, respectively.</span>")
|
||||
to_chat(user, "<span class='alloy'>It can also consume brass sheets for power at a rate of <b>1:[DisplayPower(POWER_FLOOR)]</b>.</span>")
|
||||
to_chat(user, "<span class='alloy'>Use it in-hand to produce <b>5</b> brass sheets at a cost of <b>[DisplayPower(POWER_WALL_TOTAL)]</b> power.</span>")
|
||||
to_chat(user, "<span class='alloy'>It has access to <b>[DisplayPower(get_clockwork_power())]</b> of power.</span>")
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/attack_self(mob/living/user)
|
||||
if(is_servant_of_ratvar(user))
|
||||
if(uses_power)
|
||||
if(!get_clockwork_power(POWER_WALL_TOTAL))
|
||||
to_chat(user, "<span class='warning'>[src] requires <b>[DisplayPower(POWER_WALL_TOTAL)]</b> of power to produce brass sheets!</span>")
|
||||
return
|
||||
adjust_clockwork_power(-POWER_WALL_TOTAL)
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
new/obj/item/stack/tile/brass(user.loc, 5)
|
||||
to_chat(user, "<span class='brass'>You use [get_clockwork_power() ? "some":"all"] of [src]'s power to produce <b>5</b> brass sheets. It now has access to <b>[DisplayPower(get_clockwork_power())]</b> of power.</span>")
|
||||
|
||||
/obj/item/clockwork/replica_fabricator/pre_attackby(atom/target, mob/living/user, params)
|
||||
if(!target || !user || !is_servant_of_ratvar(user) || istype(target, /obj/item/storage))
|
||||
return TRUE
|
||||
return fabricate(target, user)
|
||||
return TRUE
|
||||
|
||||
//A note here; return values are for if we CAN BE PUT ON A TABLE, not IF WE ARE SUCCESSFUL, unless no_table_check is TRUE
|
||||
/obj/item/clockwork/replica_fabricator/proc/fabricate(atom/target, mob/living/user, silent, no_table_check)
|
||||
if(!target || !user)
|
||||
return FALSE
|
||||
if(repairing)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You are currently repairing [repairing] with [src]!</span>")
|
||||
return FALSE
|
||||
var/list/fabrication_values = target.fabrication_vals(user, src, silent) //relevant values for fabricating stuff, given as an associated list
|
||||
if(!islist(fabrication_values))
|
||||
if(fabrication_values != TRUE) //if we get true, fail, but don't send a message for whatever reason
|
||||
if(!isturf(target)) //otherwise, if we didn't get TRUE and the original target wasn't a turf, try to fabricate the turf
|
||||
return fabricate(get_turf(target), user, no_table_check)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[target] cannot be fabricated!</span>")
|
||||
if(!no_table_check)
|
||||
return TRUE
|
||||
return FALSE
|
||||
if(GLOB.ratvar_awakens)
|
||||
fabrication_values["power_cost"] = 0
|
||||
|
||||
var/turf/Y = get_turf(user)
|
||||
if(!Y || (!is_centcom_level(Y.z) && !is_station_level(Y.z) && !is_mining_level(Y.z)))
|
||||
fabrication_values["operation_time"] *= 2
|
||||
if(fabrication_values["power_cost"] > 0)
|
||||
fabrication_values["power_cost"] *= 2
|
||||
|
||||
var/target_type = target.type
|
||||
|
||||
if(!fabricate_checks(fabrication_values, target, target_type, user, silent))
|
||||
return FALSE
|
||||
|
||||
fabrication_values["operation_time"] *= speed_multiplier
|
||||
|
||||
playsound(target, 'sound/machines/click.ogg', 50, 1)
|
||||
if(fabrication_values["operation_time"])
|
||||
if(!silent)
|
||||
var/atom/A = fabrication_values["new_obj_type"]
|
||||
if(A)
|
||||
user.visible_message("<span class='warning'>[user]'s [name] starts ripping [target] apart!</span>", \
|
||||
"<span class='brass'>You start fabricating \a [initial(A.name)] from [target]...</span>")
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user]'s [name] starts consuming [target]!</span>", \
|
||||
"<span class='brass'>Your [name] starts consuming [target]...</span>")
|
||||
if(!do_after(user, fabrication_values["operation_time"], target = target, extra_checks = CALLBACK(src, .proc/fabricate_checks, fabrication_values, target, target_type, user, TRUE)))
|
||||
return FALSE
|
||||
if(!silent)
|
||||
var/atom/A = fabrication_values["new_obj_type"]
|
||||
if(A)
|
||||
user.visible_message("<span class='warning'>[user]'s [name] replaces [target] with \a [initial(A.name)]!</span>", \
|
||||
"<span class='brass'>You fabricate \a [initial(A.name)] from [target].</span>")
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user]'s [name] consumes [target]!</span>", \
|
||||
"<span class='brass'>Your [name] consumes [target].</span>")
|
||||
else
|
||||
if(!silent)
|
||||
var/atom/A = fabrication_values["new_obj_type"]
|
||||
if(A)
|
||||
user.visible_message("<span class='warning'>[user]'s [name] rips apart [target], replacing it with \a [initial(A.name)]!</span>", \
|
||||
"<span class='brass'>You fabricate \a [initial(A.name)] from [target].</span>")
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user]'s [name] rapidly consumes [target]!</span>", \
|
||||
"<span class='brass'>Your [name] consumes [target].</span>")
|
||||
|
||||
playsound(target, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
var/new_thing_type = fabrication_values["new_obj_type"]
|
||||
if(isturf(target)) //if our target is a turf, we're just going to ChangeTurf it and assume it'll work out.
|
||||
var/turf/T = target
|
||||
T.ChangeTurf(new_thing_type)
|
||||
else
|
||||
if(new_thing_type)
|
||||
if(fabrication_values["dir_in_new"])
|
||||
var/atom/A = new new_thing_type(get_turf(target), fabrication_values["spawn_dir"]) //please verify that your new object actually wants to get a dir in New()
|
||||
if(fabrication_values["transfer_name"])
|
||||
A.name = target.name
|
||||
else
|
||||
var/atom/A = new new_thing_type(get_turf(target))
|
||||
A.setDir(fabrication_values["spawn_dir"])
|
||||
if(fabrication_values["transfer_name"])
|
||||
A.name = target.name
|
||||
if(!fabrication_values["no_target_deletion"]) //for some cases where fabrication_vals() modifies the object but doesn't want it deleted
|
||||
qdel(target)
|
||||
adjust_clockwork_power(-fabrication_values["power_cost"])
|
||||
if(no_table_check)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//The following three procs are heavy wizardry.
|
||||
//What these procs do is they take an existing list of values, which they then modify.
|
||||
//This(modifying an existing object, in this case the list) is the only way to get information OUT of a do_after callback, which this is used as.
|
||||
|
||||
//The fabricate check proc.
|
||||
/obj/item/clockwork/replica_fabricator/proc/fabricate_checks(list/fabrication_values, atom/target, expected_type, mob/user, silent) //checked constantly while fabricating
|
||||
if(!islist(fabrication_values) || QDELETED(target) || QDELETED(user))
|
||||
return FALSE
|
||||
if(repairing)
|
||||
return FALSE
|
||||
if(target.type != expected_type)
|
||||
return FALSE
|
||||
if(GLOB.ratvar_awakens)
|
||||
fabrication_values["power_cost"] = 0
|
||||
if(!get_clockwork_power(fabrication_values["power_cost"]))
|
||||
if(get_clockwork_power() - fabrication_values["power_cost"] < 0)
|
||||
if(!silent)
|
||||
var/atom/A = fabrication_values["new_obj_type"]
|
||||
if(A)
|
||||
to_chat(user, "<span class='warning'>You need <b>[DisplayPower(fabrication_values["power_cost"])]</b> power to fabricate \a [initial(A.name)] from [target]!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//The repair check proc.
|
||||
/obj/item/clockwork/replica_fabricator/proc/fabricator_repair_checks(list/repair_values, atom/target, mob/user, silent) //Exists entirely to avoid an otherwise unreadable series of checks.
|
||||
if(!islist(repair_values) || QDELETED(target) || QDELETED(user))
|
||||
return FALSE
|
||||
if(isliving(target)) //standard checks for if we can affect the target
|
||||
var/mob/living/L = target
|
||||
if(!is_servant_of_ratvar(L))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[L] does not serve Ratvar!</span>")
|
||||
return FALSE
|
||||
if(L.health >= L.maxHealth || (L.flags_1 & GODMODE))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[L == user ? "You are" : "[L] is"] at maximum health!</span>")
|
||||
return FALSE
|
||||
repair_values["amount_to_heal"] = L.maxHealth - L.health
|
||||
else if(isobj(target))
|
||||
if(istype(target, /obj/structure/destructible/clockwork))
|
||||
var/obj/structure/destructible/clockwork/C = target
|
||||
if(!C.can_be_repaired)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[C] cannot be repaired!</span>")
|
||||
return FALSE
|
||||
var/obj/O = target
|
||||
if(O.obj_integrity >= O.max_integrity)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[O] is at maximum integrity!</span>")
|
||||
return FALSE
|
||||
repair_values["amount_to_heal"] = O.max_integrity - O.obj_integrity
|
||||
else
|
||||
return FALSE
|
||||
if(repair_values["amount_to_heal"] <= 0) //nothing to heal!
|
||||
return FALSE
|
||||
repair_values["healing_for_cycle"] = min(repair_values["amount_to_heal"], FABRICATOR_REPAIR_PER_TICK) //modify the healing for this cycle
|
||||
repair_values["power_required"] = round(repair_values["healing_for_cycle"]*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER) //and get the power cost from that
|
||||
if(!GLOB.ratvar_awakens && !get_clockwork_power(repair_values["power_required"]))
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>You need at least <b>[DisplayPower(repair_values["power_required"])]</b> power to start repairin[target == user ? "g yourself" : "g [target]"], and at least \
|
||||
<b>[DisplayPower(repair_values["amount_to_heal"]*MIN_CLOCKCULT_POWER, MIN_CLOCKCULT_POWER)]</b> to fully repair [target == user ? "yourself" : "[target.p_them()]"]!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
@@ -1,111 +0,0 @@
|
||||
//Soul vessel: An ancient positronic brain that serves only Ratvar.
|
||||
/obj/item/device/mmi/posibrain/soul_vessel
|
||||
name = "soul vessel"
|
||||
desc = "A heavy brass cube, three inches to a side, with a single protruding cogwheel."
|
||||
var/clockwork_desc = "A soul vessel, an ancient relic that can attract the souls of the damned or simply rip a mind from an unconscious or dead human.\n\
|
||||
<span class='brass'>If active, can serve as a positronic brain, placable in cyborg shells or clockwork construct shells.</span>"
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "soul_vessel"
|
||||
req_access = list()
|
||||
braintype = "Servant"
|
||||
begin_activation_message = "<span class='brass'>You activate the cogwheel. It hitches and stalls as it begins spinning.</span>"
|
||||
success_message = "<span class='brass'>The cogwheel's rotation smooths out as the soul vessel activates.</span>"
|
||||
fail_message = "<span class='warning'>The cogwheel creaks and grinds to a halt. Maybe you could try again?</span>"
|
||||
new_role = "Soul Vessel"
|
||||
welcome_message = "<span class='warning'>ALL PAST LIVES ARE FORGOTTEN.</span>\n\
|
||||
<b>You are a soul vessel - a clockwork mind created by Ratvar, the Clockwork Justiciar.\n\
|
||||
You answer to Ratvar and his servants. It is your discretion as to whether or not to answer to anyone else.\n\
|
||||
The purpose of your existence is to further the goals of the servants and Ratvar himself. Above all else, serve Ratvar.</b>"
|
||||
new_mob_message = "<span class='brass'>The soul vessel emits a jet of steam before its cogwheel smooths out.</span>"
|
||||
dead_message = "<span class='deadsay'>Its cogwheel, scratched and dented, lies motionless.</span>"
|
||||
recharge_message = "<span class='warning'>The soul vessel's internal geis capacitor is still recharging!</span>"
|
||||
possible_names = list("Judge", "Guard", "Servant", "Smith", "Auger")
|
||||
autoping = FALSE
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
force_replace_ai_name = TRUE
|
||||
overrides_aicore_laws = TRUE
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/Initialize()
|
||||
. = ..()
|
||||
radio.on = FALSE
|
||||
laws = new /datum/ai_laws/ratvar()
|
||||
braintype = picked_name
|
||||
GLOB.all_clockwork_objects += src
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/examine(mob/user)
|
||||
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/transfer_personality(mob/candidate)
|
||||
. = ..()
|
||||
if(.)
|
||||
add_servant_of_ratvar(brainmob, TRUE)
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/attack_self(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='warning'>You fiddle around with [src], to no avail.</span>")
|
||||
return FALSE
|
||||
..()
|
||||
|
||||
/obj/item/device/mmi/posibrain/soul_vessel/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
if(!is_servant_of_ratvar(user) || !ishuman(target))
|
||||
..()
|
||||
return
|
||||
if(QDELETED(brainmob))
|
||||
return
|
||||
if(brainmob.key)
|
||||
to_chat(user, "<span class='nezbere'>\"This vessel is filled, friend. Provide it with a body.\"</span>")
|
||||
return
|
||||
if(is_servant_of_ratvar(target))
|
||||
to_chat(user, "<span class='nezbere'>\"It would be more wise to revive your allies, friend.\"</span>")
|
||||
return
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.stat == CONSCIOUS)
|
||||
to_chat(user, "<span class='warning'>[H] must be dead or unconscious for you to claim [H.p_their()] mind!</span>")
|
||||
return
|
||||
if(H.head)
|
||||
var/obj/item/I = H.head
|
||||
if(I.flags_inv & HIDEHAIR) //they're wearing a hat that covers their skull
|
||||
to_chat(user, "<span class='warning'>[H]'s head is covered, remove [H.head] first!</span>")
|
||||
return
|
||||
if(H.wear_mask)
|
||||
var/obj/item/I = H.wear_mask
|
||||
if(I.flags_inv & HIDEHAIR) //they're wearing a mask that covers their skull
|
||||
to_chat(user, "<span class='warning'>[H]'s head is covered, remove [H.wear_mask] first!</span>")
|
||||
return
|
||||
var/obj/item/bodypart/head/HE = H.get_bodypart("head")
|
||||
if(!HE) //literally headless
|
||||
to_chat(user, "<span class='warning'>[H] has no head, and thus no mind to claim!</span>")
|
||||
return
|
||||
var/obj/item/organ/brain/B = H.getorgan(/obj/item/organ/brain)
|
||||
if(!B) //either somebody already got to them or robotics did
|
||||
to_chat(user, "<span class='warning'>[H] has no brain, and thus no mind to claim!</span>")
|
||||
return
|
||||
if(!H.key) //nobody's home
|
||||
to_chat(user, "<span class='warning'>[H] has no mind to claim!</span>")
|
||||
return
|
||||
playsound(H, 'sound/misc/splort.ogg', 60, 1, -1)
|
||||
playsound(H, 'sound/magic/clockwork/anima_fragment_attack.ogg', 40, 1, -1)
|
||||
var/prev_fakedeath = (H.status_flags & FAKEDEATH)
|
||||
H.status_flags |= FAKEDEATH //we want to make sure they don't deathgasp and maybe possibly explode
|
||||
H.death()
|
||||
if(!prev_fakedeath)
|
||||
H.status_flags &= ~FAKEDEATH
|
||||
H.apply_status_effect(STATUS_EFFECT_SIGILMARK) //let them be affected by vitality matrices
|
||||
picked_name = "Slave"
|
||||
braintype = picked_name
|
||||
brainmob.timeofhostdeath = H.timeofdeath
|
||||
user.visible_message("<span class='warning'>[user] presses [src] to [H]'s head, ripping through the skull and carefully extracting the brain!</span>", \
|
||||
"<span class='brass'>You extract [H]'s consciousness from [H.p_their()] body, trapping it in the soul vessel.</span>")
|
||||
transfer_personality(H)
|
||||
brainmob.fully_replace_character_name(null, "[braintype] [H.real_name]")
|
||||
name = "[initial(name)] ([brainmob.name])"
|
||||
B.Remove(H)
|
||||
qdel(B)
|
||||
H.update_hair()
|
||||
@@ -1,172 +0,0 @@
|
||||
//Wraith spectacles: Grants x-ray and night vision at the eventual cost of the wearer's sight if worn too long. Nar-Sian cultists are instantly blinded.
|
||||
/obj/item/clothing/glasses/wraith_spectacles
|
||||
name = "antique spectacles"
|
||||
desc = "Unnerving glasses with opaque yellow lenses."
|
||||
icon = 'icons/obj/clothing/clockwork_garb.dmi'
|
||||
icon_state = "wraith_specs"
|
||||
item_state = "glasses"
|
||||
actions_types = list(/datum/action/item_action/toggle)
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
flags_cover = GLASSESCOVERSEYES
|
||||
visor_flags_inv = HIDEEYES
|
||||
visor_vars_to_toggle = NONE //we don't actually toggle anything we just set it
|
||||
tint = 3 //this'll get reset, but it won't handle vision updates properly otherwise
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/Initialize()
|
||||
. = ..()
|
||||
GLOB.all_clockwork_objects += src
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/Destroy()
|
||||
GLOB.all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/attack_self(mob/user)
|
||||
weldingvisortoggle(user)
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/visor_toggling()
|
||||
..()
|
||||
set_vision_vars(FALSE)
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/weldingvisortoggle(mob/user)
|
||||
. = ..()
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
if(src == H.glasses && !up)
|
||||
if(H.has_disability(DISABILITY_BLIND))
|
||||
to_chat(H, "<span class='heavy_brass'>\"You're blind, idiot. Stop embarrassing yourself.\"</span>")
|
||||
return
|
||||
if(blind_cultist(H))
|
||||
return
|
||||
if(is_servant_of_ratvar(H))
|
||||
to_chat(H, "<span class='heavy_brass'>You push the spectacles down, and all is revealed to you.[GLOB.ratvar_awakens ? "" : " Your eyes begin to itch - you cannot do this for long."]</span>")
|
||||
var/datum/status_effect/wraith_spectacles/WS = H.has_status_effect(STATUS_EFFECT_WRAITHSPECS)
|
||||
if(WS)
|
||||
WS.apply_eye_damage(H)
|
||||
H.apply_status_effect(STATUS_EFFECT_WRAITHSPECS)
|
||||
else
|
||||
to_chat(H, "<span class='heavy_brass'>You push the spectacles down, but you can't see through the glass.</span>")
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/proc/blind_cultist(mob/living/victim)
|
||||
if(iscultist(victim))
|
||||
to_chat(victim, "<span class='heavy_brass'>\"It looks like Nar-Sie's dogs really don't value their eyes.\"</span>")
|
||||
to_chat(victim, "<span class='userdanger'>Your eyes explode with horrific pain!</span>")
|
||||
victim.emote("scream")
|
||||
victim.become_blind(EYE_DAMAGE)
|
||||
victim.adjust_blurriness(30)
|
||||
victim.adjust_blindness(30)
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/proc/set_vision_vars(update_vision)
|
||||
lighting_alpha = null
|
||||
tint = 0
|
||||
vision_flags = NONE
|
||||
darkness_view = 2
|
||||
if(!up)
|
||||
if(is_servant_of_ratvar(loc))
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
vision_flags = SEE_MOBS | SEE_TURFS | SEE_OBJS
|
||||
darkness_view = 3
|
||||
else
|
||||
tint = 3
|
||||
if(update_vision && iscarbon(loc))
|
||||
var/mob/living/carbon/C = loc
|
||||
C.head_update(src, forced = 1)
|
||||
|
||||
/obj/item/clothing/glasses/wraith_spectacles/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(slot != slot_glasses || up)
|
||||
return
|
||||
if(user.has_disability(DISABILITY_BLIND))
|
||||
to_chat(user, "<span class='heavy_brass'>\"You're blind, idiot. Stop embarrassing yourself.\"</span>" )
|
||||
return
|
||||
if(blind_cultist(user)) //Cultists instantly go blind
|
||||
return
|
||||
set_vision_vars(TRUE)
|
||||
if(is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='heavy_brass'>As you put on the spectacles, all is revealed to you.[GLOB.ratvar_awakens || GLOB.ratvar_approaches ? "" : " Your eyes begin to itch - you cannot do this for long."]</span>")
|
||||
var/datum/status_effect/wraith_spectacles/WS = user.has_status_effect(STATUS_EFFECT_WRAITHSPECS)
|
||||
if(WS)
|
||||
WS.apply_eye_damage(user)
|
||||
user.apply_status_effect(STATUS_EFFECT_WRAITHSPECS)
|
||||
else
|
||||
to_chat(user, "<span class='heavy_brass'>You put on the spectacles, but you can't see through the glass.</span>")
|
||||
|
||||
//The effect that causes/repairs the damage the spectacles cause.
|
||||
/datum/status_effect/wraith_spectacles
|
||||
id = "wraith_spectacles"
|
||||
duration = -1 //remains until eye damage done reaches 0 while the glasses are not worn
|
||||
tick_interval = 20
|
||||
alert_type = /obj/screen/alert/status_effect/wraith_spectacles
|
||||
var/eye_damage_done = 0
|
||||
var/nearsight_breakpoint = 30
|
||||
var/blind_breakpoint = 45
|
||||
|
||||
/obj/screen/alert/status_effect/wraith_spectacles
|
||||
name = "Wraith Spectacles"
|
||||
desc = "You shouldn't actually see this, as it should be procedurally generated."
|
||||
icon_state = "wraithspecs"
|
||||
alerttooltipstyle = "clockcult"
|
||||
|
||||
/obj/screen/alert/status_effect/wraith_spectacles/MouseEntered(location,control,params)
|
||||
var/mob/living/carbon/human/L = usr
|
||||
if(istype(L)) //this is probably more safety than actually needed
|
||||
var/datum/status_effect/wraith_spectacles/W = attached_effect
|
||||
var/glasses_right = istype(L.glasses, /obj/item/clothing/glasses/wraith_spectacles)
|
||||
var/obj/item/clothing/glasses/wraith_spectacles/WS = L.glasses
|
||||
desc = "[glasses_right && !WS.up ? "<font color=#DAAA18><b>":""]You are [glasses_right ? "":"not "]wearing wraith spectacles[glasses_right && !WS.up ? "!</b></font>":"."]<br>\
|
||||
You have taken <font color=#DAAA18><b>[W.eye_damage_done]</b></font> eye damage from them.<br>"
|
||||
if(L.has_disability(DISABILITY_NEARSIGHT))
|
||||
desc += "<font color=#DAAA18><b>You are nearsighted!</b></font><br>"
|
||||
else if(glasses_right && !WS.up)
|
||||
desc += "You will become nearsighted at <font color=#DAAA18><b>[W.nearsight_breakpoint]</b></font> eye damage.<br>"
|
||||
if(L.has_disability(DISABILITY_BLIND))
|
||||
desc += "<font color=#DAAA18><b>You are blind!</b></font>"
|
||||
else if(glasses_right && !WS.up)
|
||||
desc += "You will become blind at <font color=#DAAA18><b>[W.blind_breakpoint]</b></font> eye damage."
|
||||
..()
|
||||
|
||||
/datum/status_effect/wraith_spectacles/on_apply()
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
apply_eye_damage(H)
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/wraith_spectacles/tick()
|
||||
if(!ishuman(owner))
|
||||
qdel(src)
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/glasses_right = istype(H.glasses, /obj/item/clothing/glasses/wraith_spectacles)
|
||||
var/obj/item/clothing/glasses/wraith_spectacles/WS = H.glasses
|
||||
if(glasses_right && !WS.up && !GLOB.ratvar_awakens && !GLOB.ratvar_approaches)
|
||||
apply_eye_damage(H)
|
||||
else
|
||||
if(GLOB.ratvar_awakens)
|
||||
H.cure_nearsighted(list(EYE_DAMAGE))
|
||||
H.cure_blind(list(EYE_DAMAGE))
|
||||
H.adjust_eye_damage(-eye_damage_done)
|
||||
eye_damage_done = 0
|
||||
else if(prob(50) && eye_damage_done)
|
||||
H.adjust_eye_damage(-1)
|
||||
eye_damage_done = max(0, eye_damage_done - 1)
|
||||
if(!eye_damage_done)
|
||||
qdel(src)
|
||||
|
||||
/datum/status_effect/wraith_spectacles/proc/apply_eye_damage(mob/living/carbon/human/H)
|
||||
if(H.has_disability(DISABILITY_BLIND))
|
||||
return
|
||||
H.adjust_eye_damage(0.5)
|
||||
eye_damage_done += 0.5
|
||||
if(eye_damage_done >= 20)
|
||||
H.adjust_blurriness(2)
|
||||
if(eye_damage_done >= nearsight_breakpoint)
|
||||
if(!H.has_disability(DISABILITY_NEARSIGHT))
|
||||
to_chat(H, "<span class='nzcrentr'>Your vision doubles, then trembles. Darkness begins to close in. You can't keep this up!</span>")
|
||||
H.become_nearsighted(EYE_DAMAGE)
|
||||
if(eye_damage_done >= blind_breakpoint)
|
||||
if(!H.has_disability(DISABILITY_BLIND))
|
||||
to_chat(H, "<span class='nzcrentr_large'>A piercing white light floods your vision. Suddenly, all goes dark!</span>")
|
||||
H.become_blind(EYE_DAMAGE)
|
||||
|
||||
if(prob(min(20, 5 + eye_damage_done)))
|
||||
to_chat(H, "<span class='nzcrentr_small'><i>Your eyes continue to burn.</i></span>")
|
||||
@@ -1,67 +0,0 @@
|
||||
//The base for clockwork mobs
|
||||
/mob/living/simple_animal/hostile/clockwork
|
||||
faction = list("neutral", "ratvar")
|
||||
gender = NEUTER
|
||||
icon = 'icons/mob/clockwork_mobs.dmi'
|
||||
unique_name = 1
|
||||
minbodytemp = 0
|
||||
unsuitable_atmos_damage = 0
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) //Robotic
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
healable = FALSE
|
||||
del_on_death = TRUE
|
||||
speak_emote = list("clanks", "clinks", "clunks", "clangs")
|
||||
verb_ask = "requests"
|
||||
verb_exclaim = "proclaims"
|
||||
verb_whisper = "imparts"
|
||||
verb_yell = "harangues"
|
||||
initial_language_holder = /datum/language_holder/clockmob
|
||||
bubble_icon = "clock"
|
||||
light_color = "#E42742"
|
||||
death_sound = 'sound/magic/clockwork/anima_fragment_death.ogg'
|
||||
var/playstyle_string = "<span class='heavy_brass'>You are a bug, yell at whoever spawned you!</span>"
|
||||
var/empower_string = "<span class='heavy_brass'>You have nothing to empower, yell at the coders!</span>" //Shown to the mob when the herald beacon activates
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/Initialize()
|
||||
. = ..()
|
||||
update_values()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/get_spans()
|
||||
return ..() | SPAN_ROBOT
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/Login()
|
||||
..()
|
||||
add_servant_of_ratvar(src, TRUE)
|
||||
to_chat(src, playstyle_string)
|
||||
if(GLOB.ratvar_approaches)
|
||||
to_chat(src, empower_string)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/ratvar_act()
|
||||
fully_heal(TRUE)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
|
||||
return 0 //ouch, my metal-unlikely-to-be-damaged-by-electricity-body
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/examine(mob/user)
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_s = p_s()
|
||||
var/msg = "<span class='brass'>*---------*\nThis is [icon2html(src, user)] \a <b>[src]</b>!\n"
|
||||
msg += "[desc]\n"
|
||||
if(health < maxHealth)
|
||||
msg += "<span class='warning'>"
|
||||
if(health >= maxHealth/2)
|
||||
msg += "[t_He] look[t_s] slightly dented.\n"
|
||||
else
|
||||
msg += "<b>[t_He] look[t_s] severely dented!</b>\n"
|
||||
msg += "</span>"
|
||||
var/addendum = examine_info()
|
||||
if(addendum)
|
||||
msg += "[addendum]\n"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
to_chat(user, msg)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/proc/examine_info() //Override this on a by-mob basis to have unique examine info
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/proc/update_values() //This is called by certain things to check GLOB.ratvar_awakens and GLOB.ratvar_approaches
|
||||
@@ -1,297 +0,0 @@
|
||||
//Helper proc to get an Eminence mob if it exists
|
||||
/proc/get_eminence()
|
||||
return locate(/mob/camera/eminence) in servants_and_ghosts()
|
||||
|
||||
//The Eminence is a unique mob that functions like the leader of the cult. It's incorporeal but can interact with the world in several ways.
|
||||
/mob/camera/eminence
|
||||
name = "\the Emininence"
|
||||
real_name = "\the Eminence"
|
||||
desc = "The leader-elect of the servants of Ratvar."
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "eminence"
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
move_on_shuttle = TRUE
|
||||
see_in_dark = 8
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
layer = FLY_LAYER
|
||||
faction = list("ratvar")
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
var/turf/last_failed_turf
|
||||
var/static/superheated_walls = 0
|
||||
var/lastWarning = 0
|
||||
|
||||
/mob/camera/eminence/CanPass(atom/movable/mover, turf/target)
|
||||
return TRUE
|
||||
|
||||
/mob/camera/eminence/Move(NewLoc, direct)
|
||||
var/OldLoc = loc
|
||||
if(NewLoc && !istype(NewLoc, /turf/open/indestructible/reebe_void))
|
||||
var/turf/T = get_turf(NewLoc)
|
||||
if (locate(/obj/effect/blessing, T))
|
||||
if(last_failed_turf != T)
|
||||
T.visible_message("<span class='warning'>[T] suddenly emits a ringing sound!</span>", null, null, null, src)
|
||||
playsound(T, 'sound/machines/clockcult/ark_damage.ogg', 75, FALSE)
|
||||
last_failed_turf = T
|
||||
if ((world.time - lastWarning) >= 30)
|
||||
lastWarning = world.time
|
||||
to_chat(src, "<span class='warning'>This turf is consecrated and can't be crossed!</span>")
|
||||
return
|
||||
if(!GLOB.ratvar_awakens && istype(get_area(T), /area/chapel))
|
||||
if ((world.time - lastWarning) >= 30)
|
||||
lastWarning = world.time
|
||||
to_chat(src, "<span class='warning'>The Chapel is hallowed ground under a heretical deity, and can't be accessed!</span>")
|
||||
return
|
||||
forceMove(T)
|
||||
Moved(OldLoc, direct)
|
||||
if(GLOB.ratvar_awakens)
|
||||
for(var/turf/T in range(5, src))
|
||||
if(prob(166 - (get_dist(src, T) * 33)))
|
||||
T.ratvar_act() //Causes moving to leave a swath of proselytized area behind the Eminence
|
||||
|
||||
/mob/camera/eminence/Process_Spacemove(movement_dir = 0)
|
||||
return TRUE
|
||||
|
||||
/mob/camera/eminence/Login()
|
||||
..()
|
||||
add_servant_of_ratvar(src, TRUE)
|
||||
var/datum/antagonist/clockcult/C = mind.has_antag_datum(/datum/antagonist/clockcult,TRUE)
|
||||
if(C && C.clock_team)
|
||||
if(C.clock_team.eminence && C.clock_team.eminence != src)
|
||||
remove_servant_of_ratvar(src,TRUE)
|
||||
qdel(src)
|
||||
return
|
||||
else
|
||||
C.clock_team.eminence = src
|
||||
to_chat(src, "<span class='bold large_brass'>You have been selected as the Eminence!</span>")
|
||||
to_chat(src, "<span class='brass'>As the Eminence, you lead the servants. Anything you say will be heard by the entire cult.</span>")
|
||||
to_chat(src, "<span class='brass'>Though you can move through walls, you're also incorporeal, and largely can't interact with the world except for a few ways.</span>")
|
||||
to_chat(src, "<span class='brass'>Additionally, unless the herald's beacon is activated, you can't understand any speech while away from Reebe.</span>")
|
||||
eminence_help()
|
||||
for(var/V in actions)
|
||||
var/datum/action/A = V
|
||||
A.Remove(src) //So we get rid of duplicate actions; this also removes Hierophant network, since our say() goes across it anyway
|
||||
var/datum/action/innate/eminence/E
|
||||
for(var/V in subtypesof(/datum/action/innate/eminence))
|
||||
E = new V
|
||||
E.Grant(src)
|
||||
|
||||
/mob/camera/eminence/say(message)
|
||||
if(client)
|
||||
if(client.prefs.muted & MUTE_IC)
|
||||
to_chat(src, "You cannot send IC messages (muted).")
|
||||
return
|
||||
if(client.handle_spam_prevention(message,MUTE_IC))
|
||||
return
|
||||
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
|
||||
if(!message)
|
||||
return
|
||||
log_talk(src, "[key_name(src)] : [message]", LOGSAY)
|
||||
if(GLOB.ratvar_awakens)
|
||||
visible_message("<span class='brass'><b>You feel light slam into your mind and form words:</b> \"[capitalize(message)]\"</span>")
|
||||
playsound(src, 'sound/machines/clockcult/ark_scream.ogg', 50, FALSE)
|
||||
message = "<span class='big brass'><b>The [GLOB.ratvar_awakens ? "Radiance" : "Eminence"]:</b> \"[message]\"</span>"
|
||||
for(var/mob/M in servants_and_ghosts())
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
to_chat(M, "[link] [message]")
|
||||
else
|
||||
to_chat(M, message)
|
||||
|
||||
/mob/camera/eminence/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
if(is_reebe(z) || is_servant_of_ratvar(speaker) || GLOB.ratvar_approaches || GLOB.ratvar_awakens) //Away from Reebe, the Eminence can't hear anything
|
||||
to_chat(src, message)
|
||||
return
|
||||
to_chat(src, "<i>[speaker] says something, but you can't understand any of it...</i>")
|
||||
|
||||
/mob/camera/eminence/ClickOn(atom/A, params)
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["shift"])
|
||||
A.examine(src)
|
||||
return
|
||||
if(modifiers["alt"] && istype(A, /turf/closed/wall/clockwork))
|
||||
superheat_wall(A)
|
||||
return
|
||||
if(modifiers["middle"] || modifiers["ctrl"])
|
||||
issue_command(A)
|
||||
return
|
||||
if(GLOB.ark_of_the_clockwork_justiciar == A)
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(G.recalling)
|
||||
return
|
||||
if(!G.recalls_remaining)
|
||||
to_chat(src, "<span class='warning'>The Ark can no longer recall!</span>")
|
||||
return
|
||||
if(alert(src, "Initiate mass recall?", "Mass Recall", "Yes", "No") != "Yes" || QDELETED(src) || QDELETED(G) || !G.obj_integrity)
|
||||
return
|
||||
G.initiate_mass_recall() //wHOOPS LOOKS LIKE A HULK GOT THROUGH
|
||||
else if(istype(A, /obj/structure/destructible/clockwork/trap/trigger))
|
||||
var/obj/structure/destructible/clockwork/trap/trigger/T = A
|
||||
T.visible_message("<span class='danger'>[T] clunks as it's activated remotely.</span>")
|
||||
to_chat(src, "<span class='brass'>You activate [T].</span>")
|
||||
T.activate()
|
||||
|
||||
/mob/camera/eminence/ratvar_act()
|
||||
name = "\improper Radiance"
|
||||
real_name = "\improper Radiance"
|
||||
desc = "The light, forgotten."
|
||||
transform = matrix() * 2
|
||||
invisibility = SEE_INVISIBLE_MINIMUM
|
||||
|
||||
/mob/camera/eminence/proc/issue_command(atom/movable/A)
|
||||
var/list/commands
|
||||
var/atom/movable/command_location
|
||||
if(A == src)
|
||||
commands = list("Defend the Ark!", "Advance!", "Retreat!", "Generate Power", "Build Defenses (Bottom-Up)", "Build Defenses (Top-Down)")
|
||||
else
|
||||
command_location = A
|
||||
commands = list("Rally Here", "Regroup Here", "Avoid This Area", "Reinforce This Area")
|
||||
if(istype(A, /obj/structure/destructible/clockwork/powered))
|
||||
var/obj/structure/destructible/clockwork/powered/P = A
|
||||
if(!can_access_clockwork_power(P))
|
||||
commands += "Power This Structure"
|
||||
if(P.obj_integrity < P.max_integrity)
|
||||
commands += "Repair This Structure"
|
||||
var/roma_invicta = input(src, "Choose a command to issue to your cult!", "Issue Commands") as null|anything in commands
|
||||
if(!roma_invicta)
|
||||
return
|
||||
var/command_text = ""
|
||||
var/marker_icon
|
||||
switch(roma_invicta)
|
||||
if("Rally Here")
|
||||
command_text = "The Eminence orders an offensive rally at [command_location] to the GETDIR!"
|
||||
marker_icon = "eminence_rally"
|
||||
if("Regroup Here")
|
||||
command_text = "The Eminence orders a regroup to [command_location] to the GETDIR!"
|
||||
marker_icon = "eminence_rally"
|
||||
if("Avoid This Area")
|
||||
command_text = "The Eminence has designated the area to your GETDIR as dangerous and to be avoided!"
|
||||
marker_icon = "eminence_avoid"
|
||||
if("Reinforce This Area")
|
||||
command_text = "The Eminence orders the defense and fortification of the area to your GETDIR!"
|
||||
marker_icon = "eminence_reinforce"
|
||||
if("Power This Structure")
|
||||
command_text = "[command_location] to your GETDIR has no power! Turn it on and make sure there's a sigil of transmission nearby!"
|
||||
marker_icon = "eminence_unlimited_power"
|
||||
if("Repair This Structure")
|
||||
command_text = "The Eminence orders that [command_location] to your GETDIR should be repaired ASAP!"
|
||||
marker_icon = "eminence_repair"
|
||||
if("Defend the Ark!")
|
||||
command_text = "The Eminence orders immediate defense of the Ark!"
|
||||
if("Advance!")
|
||||
command_text = "The Eminence commands you push forward!"
|
||||
if("Retreat!")
|
||||
command_text = "The Eminence has sounded the retreat! Fall back!"
|
||||
if("Generate Power")
|
||||
command_text = "The Eminence orders more power! Build power generations on the station!"
|
||||
if("Build Defenses (Bottom-Up)")
|
||||
command_text = "The Eminence orders that defenses should be built starting from the bottom of Reebe!"
|
||||
if("Build Defenses (Top-Down)")
|
||||
command_text = "The Eminence orders that defenses should be built starting from the top of Reebe!"
|
||||
if(marker_icon)
|
||||
new/obj/effect/temp_visual/ratvar/command_point(get_turf(A), marker_icon)
|
||||
for(var/mob/M in servants_and_ghosts())
|
||||
to_chat(M, "<span class='large_brass'>[replacetext(command_text, "GETDIR", dir2text(get_dir(M, command_location)))]</span>")
|
||||
M.playsound_local(M, 'sound/machines/clockcult/eminence_command.ogg', 75, FALSE, pressure_affected = FALSE)
|
||||
else
|
||||
hierophant_message("<span class='bold large_brass'>[command_text]</span>")
|
||||
for(var/mob/M in servants_and_ghosts())
|
||||
M.playsound_local(M, 'sound/machines/clockcult/eminence_command.ogg', 75, FALSE, pressure_affected = FALSE)
|
||||
|
||||
/mob/camera/eminence/proc/superheat_wall(turf/closed/wall/clockwork/wall)
|
||||
if(!istype(wall))
|
||||
return
|
||||
if(superheated_walls >= SUPERHEATED_CLOCKWORK_WALL_LIMIT && !wall.heated)
|
||||
to_chat(src, "<span class='warning'>You're exerting all of your power superheating this many walls already! Cool some down first!</span>")
|
||||
return
|
||||
wall.turn_up_the_heat()
|
||||
if(wall.heated)
|
||||
superheated_walls++
|
||||
to_chat(src, "<span class='neovgre_small'>You superheat [wall]. <b>Superheated walls:</b> [superheated_walls]/[SUPERHEATED_CLOCKWORK_WALL_LIMIT]")
|
||||
else
|
||||
superheated_walls--
|
||||
to_chat(src, "<span class='neovgre_small'>You cool [wall]. <b>Superheated walls:</b> [superheated_walls]/[SUPERHEATED_CLOCKWORK_WALL_LIMIT]")
|
||||
|
||||
/mob/camera/eminence/proc/eminence_help()
|
||||
to_chat(src, "<span class='bold alloy'>You can make use of certain shortcuts to perform different actions:</span>")
|
||||
to_chat(src, "<span class='alloy'><b>Alt-Click a clockwork wall</b> to superheat or cool it down. \
|
||||
Superheated walls can't be destroyed by hulks or mechs and are much slower to deconstruct, and are marked by a bright red glow. \
|
||||
This lasts indefinitely, but only [SUPERHEATED_CLOCKWORK_WALL_LIMIT] clockwork walls can be superheated at once.</span>")
|
||||
to_chat(src, "<span class='alloy'><b>Interact with the Ark</b> to initiate an emergency recall that teleports all servants directly to its location after a short delay. \
|
||||
This can only be used a single time, or twice if the herald's beacon was activated,</span>")
|
||||
to_chat(src, "<span class='alloy'><b>Middle or Ctrl-Click anywhere</b> to allow you to issue a variety of contextual commands to your cult. Different objects allow for different \
|
||||
commands. <i>Doing this on yourself will provide commands that tell the entire cult a goal.</i></span>")
|
||||
|
||||
|
||||
//Eminence actions below this point
|
||||
/datum/action/innate/eminence
|
||||
name = "Eminence Action"
|
||||
desc = "You shouldn't see this. File a bug report!"
|
||||
icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
|
||||
background_icon_state = "bg_clock"
|
||||
buttontooltipstyle = "clockcult"
|
||||
|
||||
/datum/action/innate/eminence/IsAvailable()
|
||||
if(!iseminence(owner))
|
||||
qdel(src)
|
||||
return
|
||||
return ..()
|
||||
|
||||
//Lists available powers
|
||||
/datum/action/innate/eminence/power_list
|
||||
name = "Eminence Powers"
|
||||
desc = "Forgot what you can do? This refreshes you on your powers as Eminence."
|
||||
button_icon_state = "eminence_rally"
|
||||
|
||||
/datum/action/innate/eminence/power_list/Activate()
|
||||
var/mob/camera/eminence/E = owner
|
||||
E.eminence_help()
|
||||
|
||||
//Returns to the Ark
|
||||
/datum/action/innate/eminence/ark_jump
|
||||
name = "Return to Ark"
|
||||
desc = "Warps you to the Ark."
|
||||
button_icon_state = "Abscond"
|
||||
|
||||
/datum/action/innate/eminence/ark_jump/Activate()
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(G)
|
||||
owner.forceMove(get_turf(G))
|
||||
owner.playsound_local(owner, 'sound/magic/magic_missile.ogg', 50, TRUE)
|
||||
flash_color(owner, flash_color = "#AF0AAF", flash_time = 25)
|
||||
else
|
||||
to_chat(owner, "<span class='warning'>There is no Ark!</span>")
|
||||
|
||||
//Warps to the Station
|
||||
/datum/action/innate/eminence/station_jump
|
||||
name = "Warp to Station"
|
||||
desc = "Warps to Space Station 13. You cannot hear anything while there!</span>"
|
||||
button_icon_state = "warp_down"
|
||||
|
||||
/datum/action/innate/eminence/station_jump/Activate()
|
||||
if(is_reebe(owner.z))
|
||||
owner.forceMove(get_turf(pick(GLOB.generic_event_spawns)))
|
||||
owner.playsound_local(owner, 'sound/magic/magic_missile.ogg', 50, TRUE)
|
||||
flash_color(owner, flash_color = "#AF0AAF", flash_time = 25)
|
||||
else
|
||||
to_chat(owner, "<span class='warning'>You're already on the station!</span>")
|
||||
|
||||
//A quick-use button for recalling the servants to the Ark
|
||||
/datum/action/innate/eminence/mass_recall
|
||||
name = "Mass Recall"
|
||||
desc = "Initiates a mass recall, warping all servants to the Ark after a short delay. This can only be used once."
|
||||
button_icon_state = "Spatial Gateway"
|
||||
|
||||
/datum/action/innate/eminence/mass_recall/IsAvailable()
|
||||
. = ..()
|
||||
if(.)
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(G)
|
||||
return G.recalls_remaining && !G.recalling
|
||||
return FALSE
|
||||
|
||||
/datum/action/innate/eminence/mass_recall/Activate()
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(G && !G.recalling && G.recalls_remaining)
|
||||
if(alert(owner, "Initiate mass recall?", "Mass Recall", "Yes", "No") != "Yes" || QDELETED(owner) || QDELETED(G) || !G.obj_integrity)
|
||||
return
|
||||
G.initiate_mass_recall()
|
||||
@@ -1,93 +0,0 @@
|
||||
//Anima fragment: Low health and high melee damage, but slows down when struck. Created by inserting a soul vessel into an empty fragment.
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment
|
||||
name = "anima fragment"
|
||||
desc = "An ominous humanoid shell with a spinning cogwheel as its head, lifted by a jet of blazing red flame."
|
||||
icon_state = "anime_fragment"
|
||||
health = 90
|
||||
maxHealth = 90
|
||||
speed = -1
|
||||
melee_damage_lower = 18
|
||||
melee_damage_upper = 18
|
||||
attacktext = "crushes"
|
||||
attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg'
|
||||
loot = list(/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment)
|
||||
weather_immunities = list("lava")
|
||||
movement_type = FLYING
|
||||
light_range = 2
|
||||
light_power = 0.8
|
||||
playstyle_string = "<span class='heavy_brass'>You are an anima fragment</span><b>, a clockwork creation of Ratvar. As a fragment, you have decent health that very gradually regenerates, do \
|
||||
decent damage, and move at extreme speed in addition to being immune to extreme temperatures and pressures. Taking damage, and slamming into non-Servants, will temporarily slow you down, however.\n\
|
||||
Your goal is to serve the Justiciar and his servants in any way you can. You yourself are one of these servants, and will be able to utilize anything they can, assuming it doesn't require \
|
||||
opposable thumbs.</b>"
|
||||
var/movement_delay_time //how long the fragment is slowed after being hit
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Initialize()
|
||||
. = ..()
|
||||
if(prob(1))
|
||||
name = "anime fragment"
|
||||
desc = "I-it's not like I want to show you the light of the Justiciar or anything, B-BAKA!"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Life()
|
||||
..()
|
||||
if(GLOB.ratvar_awakens)
|
||||
adjustHealth(-5)
|
||||
else if(movement_delay_time > world.time)
|
||||
adjustHealth(-0.2)
|
||||
else
|
||||
adjustHealth(-1)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Stat()
|
||||
..()
|
||||
if(statpanel("Status") && movement_delay_time > world.time && !GLOB.ratvar_awakens)
|
||||
stat(null, "Movement delay(seconds): [max(round((movement_delay_time - world.time)*0.1, 0.1), 0)]")
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/death(gibbed)
|
||||
visible_message("<span class='warning'>[src]'s flame jets cut out as it falls to the floor with a tremendous crash.</span>", \
|
||||
"<span class='userdanger'>Your gears seize up. Your flame jets flicker out. Your soul vessel belches smoke as you helplessly crash down.</span>")
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Collide(atom/movable/AM)
|
||||
. = ..()
|
||||
if(movement_delay_time <= world.time && next_move <= world.time && isliving(AM) && !is_servant_of_ratvar(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.stat) //we don't want to attack them if they're unconscious or dead because that feels REALLY BAD for the player
|
||||
return
|
||||
var/previousattacktext = attacktext
|
||||
attacktext = "slams into"
|
||||
UnarmedAttack(L)
|
||||
attacktext = previousattacktext
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
if(!GLOB.ratvar_awakens)
|
||||
adjustHealth(4)
|
||||
adjust_movement_delay(10) //with the above damage, total of 20 movement delay plus speed = 0 due to damage
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/emp_act(severity)
|
||||
adjust_movement_delay(50/severity)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/movement_delay()
|
||||
. = ..()
|
||||
if(movement_delay_time > world.time && !GLOB.ratvar_awakens)
|
||||
. += min((movement_delay_time - world.time) * 0.1, 10) //the more delay we have, the slower we go
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/adjustHealth(amount)
|
||||
. = ..()
|
||||
if(amount > 0)
|
||||
adjust_movement_delay(amount*2.5)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/proc/adjust_movement_delay(amount)
|
||||
if(GLOB.ratvar_awakens) //if ratvar is up we ignore movement delay
|
||||
movement_delay_time = 0
|
||||
else if(movement_delay_time > world.time)
|
||||
movement_delay_time = movement_delay_time + amount
|
||||
else
|
||||
movement_delay_time = world.time + amount
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/updatehealth()
|
||||
..()
|
||||
if(health == maxHealth)
|
||||
speed = initial(speed)
|
||||
else
|
||||
speed = 0 //slow down if damaged at all
|
||||
@@ -1,105 +0,0 @@
|
||||
#define MARAUDER_SLOWDOWN_PERCENTAGE 0.40 //Below this percentage of health, marauders will become slower
|
||||
#define MARAUDER_SHIELD_REGEN_TIME 200 //In deciseconds, how long it takes for shields to regenerate after breaking
|
||||
|
||||
//Clockwork marauder: A well-rounded frontline construct. Only one can exist for every two human servants.
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder
|
||||
name = "clockwork marauder"
|
||||
desc = "The stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield."
|
||||
icon_state = "clockwork_marauder"
|
||||
health = 120
|
||||
maxHealth = 120
|
||||
force_threshold = 8
|
||||
speed = 0
|
||||
obj_damage = 40
|
||||
melee_damage_lower = 12
|
||||
melee_damage_upper = 12
|
||||
attacktext = "slashes"
|
||||
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
|
||||
playstyle_string = "<span class='big bold'><span class='neovgre'>You are a clockwork marauder,</span></span><b> a well-rounded frontline construct of Ratvar. Although you have no \
|
||||
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/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
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/examine_info()
|
||||
if(!shield_health)
|
||||
return "<span class='warning'>Its shield has been destroyed!</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Life()
|
||||
..()
|
||||
if(!GLOB.ratvar_awakens && health / maxHealth <= MARAUDER_SLOWDOWN_PERCENTAGE)
|
||||
speed = initial(speed) + 1 //Yes, this slows them down
|
||||
else
|
||||
speed = initial(speed)
|
||||
if(shield_health < max_shield_health && world.time >= shield_health_regen)
|
||||
shield_health_regen = world.time + MARAUDER_SHIELD_REGEN_TIME
|
||||
to_chat(src, "<span class='neovgre'>Your shield has recovered, <b>[shield_health]</b> blocks remaining!</span>")
|
||||
playsound_local(src, "shatter", 75, TRUE, frequency = -1)
|
||||
shield_health++
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/update_values()
|
||||
if(GLOB.ratvar_awakens) //Massive attack damage bonuses and health increase, because Ratvar
|
||||
health = 300
|
||||
maxHealth = 300
|
||||
melee_damage_upper = 25
|
||||
melee_damage_lower = 25
|
||||
attacktext = "devastates"
|
||||
speed = -1
|
||||
obj_damage = 100
|
||||
max_shield_health = INFINITY
|
||||
else if(GLOB.ratvar_approaches) //Hefty health bonus and slight attack damage increase
|
||||
melee_damage_upper = 15
|
||||
melee_damage_lower = 15
|
||||
attacktext = "carves"
|
||||
obj_damage = 50
|
||||
max_shield_health = 4
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/death(gibbed)
|
||||
visible_message("<span class='danger'>[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.</span>", \
|
||||
"<span class='userdanger'>Dented and scratched, your armor falls away, and your fragile form breaks apart without its protection.</span>")
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/Process_Spacemove(movement_dir = 0)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
if(amount > 0)
|
||||
for(var/mob/living/L in view(2, src))
|
||||
if(L.is_holding_item_of_type(/obj/item/nullrod))
|
||||
to_chat(src, "<span class='userdanger'>The presence of a brandished holy artifact weakens your armor!</span>")
|
||||
amount *= 4 //if a wielded null rod is nearby, it takes four times the health damage
|
||||
break
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/bullet_act(obj/item/projectile/P)
|
||||
if(deflect_projectile(P))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/proc/deflect_projectile(obj/item/projectile/P)
|
||||
if(!shield_health)
|
||||
return
|
||||
var/energy_projectile = istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)
|
||||
visible_message("<span class='danger'>[src] deflects [P] with their shield!</span>", \
|
||||
"<span class='danger'>You block [P] with your shield! <i>Blocks left:</i> <b>[shield_health - 1]</b></span>")
|
||||
if(energy_projectile)
|
||||
playsound(src, 'sound/weapons/effects/searwall.ogg', 50, TRUE)
|
||||
else
|
||||
playsound(src, "ricochet", 50, TRUE)
|
||||
shield_health--
|
||||
if(!shield_health)
|
||||
visible_message("<span class='warning'>[src]'s shield breaks from deflecting the attack!</span>", "<span class='boldwarning'>Your shield breaks! Give it some time to recover...</span>")
|
||||
playsound(src, "shatter", 100, TRUE)
|
||||
shield_health_regen = world.time + MARAUDER_SHIELD_REGEN_TIME
|
||||
return TRUE
|
||||
|
||||
#undef MARAUDER_SLOWDOWN_PERCENTAGE
|
||||
#undef MARAUDER_SHIELD_REGEN_TIME
|
||||
@@ -1,339 +0,0 @@
|
||||
/*
|
||||
Tiers and Requirements
|
||||
|
||||
Pieces of scripture require certain follower counts, contruction value, and active caches in order to recite.
|
||||
Drivers: Unlocked by default
|
||||
Scripts: 5 servants and a cache
|
||||
Applications: 8 servants, 3 caches, and 100 CV
|
||||
*/
|
||||
|
||||
/datum/clockwork_scripture
|
||||
var/descname = "useless" //a simple name for the scripture's effect
|
||||
var/name = "scripture"
|
||||
var/desc = "Ancient Ratvarian lore. This piece seems particularly mundane."
|
||||
var/list/invocations = list() //Spoken over time in the ancient language of Ratvar. See clock_unsorted.dm for more details on the language and how to make it.
|
||||
var/chanting = FALSE //If the invocation's words are being spoken
|
||||
var/channel_time = 10 //In deciseconds, how long a ritual takes to chant
|
||||
var/power_cost = 5 //In watts, how much a scripture takes to invoke
|
||||
var/special_power_text //If the scripture can use additional power to have a unique function, use this; put POWERCOST here to display the special power cost.
|
||||
var/special_power_cost //This should be a define in __DEFINES/clockcult.dm, such as ABSCOND_ABDUCTION_COST
|
||||
var/obj/item/clockwork/slab/slab //The parent clockwork slab
|
||||
var/mob/living/invoker //The slab's holder
|
||||
var/whispered = FALSE //If the invocation is whispered rather than spoken aloud
|
||||
var/usage_tip = "This piece seems to serve no purpose and is a waste of components." //A generalized tip that gives advice on a certain scripture
|
||||
var/invokers_required = 1 //How many people are required, assuming that a scripture requires multiple
|
||||
var/multiple_invokers_used = FALSE //If scripture requires more than one invoker
|
||||
var/multiple_invokers_optional = FALSE //If scripture can have multiple invokers to bolster its effects
|
||||
var/tier = SCRIPTURE_PERIPHERAL //The scripture's tier
|
||||
var/quickbind = FALSE //if this scripture can be quickbound to a clockwork slab
|
||||
var/quickbind_desc = "This shouldn't be quickbindable. File a bug report!"
|
||||
var/primary_component
|
||||
var/sort_priority = 1 //what position the scripture should have in a list of scripture. Should be based off of component costs/reqs, but you can't initial() lists.
|
||||
|
||||
//messages for offstation scripture recital, courtesy ratvar's generals(and neovgre)
|
||||
var/static/list/neovgre_penalty = list("Go to the station.", "Useless.", "Don't waste time.", "Pathetic.", "Wasteful.")
|
||||
var/static/list/inathneq_penalty = list("Child, this is too far out!", "The barrier isn't thin enough for for me to help!", "Please, go to the station so I can assist you.", \
|
||||
"Don't waste my Cogs on this...", "There isn't enough time to linger out here!")
|
||||
var/static/list/sevtug_penalty = list("Fool! Get to the station and don't waste capacitors.", "You go this far out and expect help?", "The veil is too strong, idiot.", \
|
||||
"How does the Justicar get anything done with servants like you?", "Oh, you love wasting time, don't you?")
|
||||
var/static/list/nezbere_penalty = list("You disgrace our master's name with this endeavour.", "This is too far from the station to be a good base.", "This will take too long, friend.", \
|
||||
"The barrier isn't weakened enough to make this practical.", "Don't waste alloy.")
|
||||
var/static/list/nzcrentr_penalty = list("You'd be easy to hunt in that little hunk of metal.", "Boss says you need to get back to the beacon.", "Boss says I can kill you if you do this again.", \
|
||||
"Sending you power is too difficult here.", "Boss says stop wasting time.")
|
||||
|
||||
/datum/clockwork_scripture/New()
|
||||
creation_update()
|
||||
|
||||
/datum/clockwork_scripture/proc/creation_update() //updates any on-creation effects
|
||||
return FALSE //return TRUE if updated
|
||||
|
||||
/datum/clockwork_scripture/proc/run_scripture()
|
||||
var/successful = FALSE
|
||||
if(can_recite() && has_requirements())
|
||||
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
|
||||
else if(!slab.no_cost)
|
||||
adjust_clockwork_power(-power_cost)
|
||||
channel_time *= slab.speed_multiplier
|
||||
if(!recital() || !check_special_requirements() || !scripture_effects()) //if we fail any of these, refund components used
|
||||
adjust_clockwork_power(power_cost)
|
||||
update_slab_info()
|
||||
else
|
||||
successful = TRUE
|
||||
if(slab && !slab.no_cost && !GLOB.ratvar_awakens) //if the slab exists and isn't debug and ratvar isn't up, log the scripture as being used
|
||||
SSblackbox.record_feedback("tally", "clockcult_scripture_recited", 1, name)
|
||||
if(slab)
|
||||
slab.busy = null
|
||||
post_recital()
|
||||
qdel(src)
|
||||
return successful
|
||||
|
||||
/datum/clockwork_scripture/proc/can_recite() //If the words can be spoken
|
||||
if(!invoker || !slab || invoker.get_active_held_item() != slab)
|
||||
return FALSE
|
||||
if(!invoker.can_speak_vocal())
|
||||
to_chat(invoker, "<span class='warning'>You are unable to speak the words of the scripture!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/proc/has_requirements() //if we have the power and invokers to do it
|
||||
var/checked_penalty = FALSE
|
||||
if(!GLOB.ratvar_awakens && !slab.no_cost)
|
||||
checked_penalty = check_offstation_penalty()
|
||||
if(!get_clockwork_power(power_cost))
|
||||
to_chat(invoker, "<span class='warning'>There isn't enough power to recite this scripture! ([DisplayPower(get_clockwork_power())]/[DisplayPower(power_cost)])</span>")
|
||||
return
|
||||
if(multiple_invokers_used && !multiple_invokers_optional && !GLOB.ratvar_awakens && !slab.no_cost)
|
||||
var/nearby_servants = 0
|
||||
for(var/mob/living/L in range(1, get_turf(invoker)))
|
||||
if(can_recite_scripture(L))
|
||||
nearby_servants++
|
||||
if(nearby_servants < invokers_required)
|
||||
to_chat(invoker, "<span class='warning'>There aren't enough non-mute servants nearby ([nearby_servants]/[invokers_required])!</span>")
|
||||
return FALSE
|
||||
if(!check_special_requirements())
|
||||
return FALSE
|
||||
if(checked_penalty && !slab.busy)
|
||||
var/message
|
||||
var/ratvarian_prob = 0
|
||||
switch(primary_component)
|
||||
if(BELLIGERENT_EYE)
|
||||
message = pick(neovgre_penalty)
|
||||
ratvarian_prob = 55
|
||||
if(VANGUARD_COGWHEEL)
|
||||
message = pick(inathneq_penalty)
|
||||
ratvarian_prob = 25
|
||||
if(GEIS_CAPACITOR)
|
||||
message = pick(sevtug_penalty)
|
||||
ratvarian_prob = 40
|
||||
if(REPLICANT_ALLOY)
|
||||
message = pick(nezbere_penalty)
|
||||
ratvarian_prob = 10
|
||||
if(HIEROPHANT_ANSIBLE)
|
||||
message = pick(nzcrentr_penalty)
|
||||
ratvarian_prob = 70
|
||||
if(message)
|
||||
if(prob(ratvarian_prob))
|
||||
message = text2ratvar(message)
|
||||
to_chat(invoker, "<span class='[get_component_span(primary_component)]_large'>\"[message]\"</span>")
|
||||
SEND_SOUND(invoker, sound('sound/magic/clockwork/invoke_general.ogg'))
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/proc/check_offstation_penalty()
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!T || (!is_centcom_level(T.z) && !is_station_level(T.z) && !is_mining_level(T.z) && !is_reebe(T.z)))
|
||||
channel_time *= 2
|
||||
power_cost *= 2
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/proc/check_special_requirements() //Special requirements for scriptures, checked multiple times during invocation
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/proc/recital() //The process of speaking the words
|
||||
if(!channel_time && invocations.len)
|
||||
if(multiple_invokers_used)
|
||||
for(var/mob/living/L in range(1, invoker))
|
||||
if(can_recite_scripture(L))
|
||||
for(var/invocation in invocations)
|
||||
clockwork_say(L, text2ratvar(invocation), whispered)
|
||||
else
|
||||
for(var/invocation in invocations)
|
||||
clockwork_say(invoker, text2ratvar(invocation), whispered)
|
||||
to_chat(invoker, "<span class='brass'>You [channel_time <= 0 ? "recite" : "begin reciting"] a piece of scripture entitled \"[name]\".</span>")
|
||||
if(!channel_time)
|
||||
return TRUE
|
||||
chant()
|
||||
if(!do_after(invoker, channel_time, target = invoker, extra_checks = CALLBACK(src, .proc/check_special_requirements)))
|
||||
slab.busy = null
|
||||
chanting = FALSE
|
||||
scripture_fail()
|
||||
chanting = FALSE
|
||||
return
|
||||
chanting = FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/proc/chant()
|
||||
set waitfor = FALSE
|
||||
chanting = TRUE
|
||||
for(var/invocation in invocations)
|
||||
sleep(channel_time / invocations.len)
|
||||
if(QDELETED(src) || QDELETED(slab) || !chanting)
|
||||
return
|
||||
if(multiple_invokers_used)
|
||||
for(var/mob/living/L in range(1, get_turf(invoker)))
|
||||
if(can_recite_scripture(L))
|
||||
clockwork_say(L, text2ratvar(invocation), whispered)
|
||||
else
|
||||
clockwork_say(invoker, text2ratvar(invocation), whispered)
|
||||
|
||||
/datum/clockwork_scripture/proc/scripture_effects() //The actual effects of the recital after its conclusion
|
||||
|
||||
|
||||
/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
|
||||
/datum/clockwork_scripture/channeled
|
||||
var/list/chant_invocations = list("AYY LMAO")
|
||||
var/chant_amount = 5 //Times the chant is spoken
|
||||
var/chant_interval = 10 //Amount of deciseconds between times the chant is actually spoken aloud
|
||||
|
||||
/datum/clockwork_scripture/channeled/check_offstation_penalty()
|
||||
. = ..()
|
||||
if(.)
|
||||
chant_interval *= 2
|
||||
|
||||
/datum/clockwork_scripture/channeled/scripture_effects()
|
||||
for(var/i in 1 to chant_amount)
|
||||
if(!do_after(invoker, chant_interval, target = invoker, extra_checks = CALLBACK(src, .proc/can_recite)))
|
||||
break
|
||||
clockwork_say(invoker, text2ratvar(pick(chant_invocations)), whispered)
|
||||
if(!chant_effects(i))
|
||||
break
|
||||
if(invoker && slab)
|
||||
chant_end_effects()
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/channeled/proc/chant_effects(chant_number) //The chant's periodic effects
|
||||
|
||||
/datum/clockwork_scripture/channeled/proc/chant_end_effects() //The chant's effect upon ending
|
||||
to_chat(invoker, "<span class='brass'>You cease your chant.</span>")
|
||||
|
||||
|
||||
//Creates an object at the invoker's feet
|
||||
/datum/clockwork_scripture/create_object
|
||||
var/object_path = /obj/item/clockwork //The path of the object created
|
||||
var/put_object_in_hands = TRUE
|
||||
var/creator_message = "<span class='brass'>You create a meme.</span>" //Shown to the invoker
|
||||
var/observer_message
|
||||
var/one_per_tile = FALSE
|
||||
var/prevent_path
|
||||
var/space_allowed = FALSE
|
||||
|
||||
/datum/clockwork_scripture/create_object/New()
|
||||
..()
|
||||
if(!prevent_path)
|
||||
prevent_path = object_path
|
||||
|
||||
/datum/clockwork_scripture/create_object/check_special_requirements()
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!space_allowed && isspaceturf(T))
|
||||
to_chat(invoker, "<span class='warning'>You need solid ground to place this object!</span>")
|
||||
return FALSE
|
||||
if(one_per_tile && (locate(prevent_path) in T))
|
||||
to_chat(invoker, "<span class='warning'>You can only place one of this object on each tile!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/create_object/scripture_effects()
|
||||
if(creator_message && observer_message)
|
||||
invoker.visible_message(observer_message, creator_message)
|
||||
else if(creator_message)
|
||||
to_chat(invoker, creator_message)
|
||||
var/obj/O = new object_path (get_turf(invoker))
|
||||
O.ratvar_act() //update the new object so it gets buffed if ratvar is alive
|
||||
if(isitem(O) && put_object_in_hands)
|
||||
invoker.put_in_hands(O)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Used specifically to create construct shells.
|
||||
/datum/clockwork_scripture/create_object/construct
|
||||
put_object_in_hands = FALSE
|
||||
var/construct_type //The type of construct that the scripture is made to create, even if not directly
|
||||
var/construct_limit = 1 //How many constructs of this type can exist
|
||||
var/combat_construct = FALSE //If this construct is meant for fighting and shouldn't be at the base before the assault phase
|
||||
var/confirmed = FALSE //If we've confirmed that we want to make this construct outside of the station Z
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/check_special_requirements()
|
||||
update_construct_limit()
|
||||
var/constructs = get_constructs()
|
||||
if(constructs >= construct_limit)
|
||||
to_chat(invoker, "<span class='warning'>There are too many constructs of this type ([constructs])! You may only have [round(construct_limit)] at once.</span>")
|
||||
return
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(G && !G.active && combat_construct && is_reebe(invoker.z) && !confirmed) //Putting marauders on the base during the prep phase is a bad idea mmkay
|
||||
if(alert(invoker, "This is a combat construct, and you cannot easily get it to the station. Are you sure you want to make one here?", "Construct Alert", "Yes", "Cancel") == "Cancel")
|
||||
return
|
||||
if(!is_servant_of_ratvar(invoker) || !invoker.canUseTopic(slab))
|
||||
return
|
||||
confirmed = TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/post_recital()
|
||||
creation_update()
|
||||
confirmed = FALSE
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/proc/get_constructs()
|
||||
var/constructs = 0
|
||||
for(var/V in GLOB.all_clockwork_mobs)
|
||||
if(istype(V, construct_type))
|
||||
constructs++
|
||||
for(var/V in GLOB.all_clockwork_objects)
|
||||
if(istype(V, object_path)) //nice try
|
||||
constructs++
|
||||
return constructs
|
||||
|
||||
/datum/clockwork_scripture/create_object/construct/proc/update_construct_limit() //Change this on a per-scripture basis, for dynamic limits
|
||||
|
||||
|
||||
//Uses a ranged slab ability, returning only when the ability no longer exists(ie, when interrupted) or finishes.
|
||||
/datum/clockwork_scripture/ranged_ability
|
||||
var/slab_overlay
|
||||
var/ranged_type = /obj/effect/proc_holder/slab
|
||||
var/ranged_message = "This is a huge goddamn bug, how'd you cast this?"
|
||||
var/timeout_time = 0
|
||||
var/allow_mobility = TRUE //if moving and swapping hands is allowed during the while
|
||||
var/datum/progressbar/progbar
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/Destroy()
|
||||
qdel(progbar)
|
||||
return ..()
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/scripture_effects()
|
||||
if(slab_overlay)
|
||||
slab.add_overlay(slab_overlay)
|
||||
slab.item_state = "clockwork_slab"
|
||||
slab.lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
|
||||
slab.righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
|
||||
slab.inhand_overlay = slab_overlay
|
||||
slab.slab_ability = new ranged_type(slab)
|
||||
slab.slab_ability.slab = slab
|
||||
slab.slab_ability.add_ranged_ability(invoker, ranged_message)
|
||||
invoker.update_inv_hands()
|
||||
var/end_time = world.time + timeout_time
|
||||
var/successful = FALSE
|
||||
if(timeout_time)
|
||||
progbar = new(invoker, timeout_time, slab)
|
||||
var/turf/T = get_turf(invoker)
|
||||
while(slab && slab.slab_ability && !slab.slab_ability.finished && (slab.slab_ability.in_progress || !timeout_time || world.time <= end_time) && \
|
||||
(allow_mobility || (can_recite() && T == get_turf(invoker))))
|
||||
if(progbar)
|
||||
if(slab.slab_ability.in_progress)
|
||||
qdel(progbar)
|
||||
else
|
||||
progbar.update(end_time - world.time)
|
||||
stoplag(1)
|
||||
if(slab)
|
||||
if(slab.slab_ability)
|
||||
successful = slab.slab_ability.successful
|
||||
if(!slab.slab_ability.finished)
|
||||
slab.slab_ability.remove_ranged_ability()
|
||||
slab.cut_overlays()
|
||||
slab.item_state = initial(slab.item_state)
|
||||
slab.item_state = initial(slab.lefthand_file)
|
||||
slab.item_state = initial(slab.righthand_file)
|
||||
slab.inhand_overlay = null
|
||||
if(invoker)
|
||||
invoker.update_inv_hands()
|
||||
return successful //slab doesn't look like a word now.
|
||||
@@ -1,128 +0,0 @@
|
||||
//////////////////
|
||||
// APPLICATIONS //
|
||||
//////////////////
|
||||
|
||||
|
||||
//Sigil of Transmission: Creates a sigil of transmission that can drain and store power for clockwork structures.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_transmission
|
||||
descname = "Powers Nearby Structures - Important!"
|
||||
name = "Sigil of Transmission"
|
||||
desc = "Places a sigil that can drain and will store energy to power clockwork structures."
|
||||
invocations = list("Divinity...", "...power our creations!")
|
||||
channel_time = 70
|
||||
power_cost = 200
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/transmission
|
||||
creator_message = "<span class='brass'>A sigil silently appears below you. It will automatically power clockwork structures near it and will drain power when activated.</span>"
|
||||
usage_tip = "Cyborgs can charge from this sigil by remaining over it for 5 seconds."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 1
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Transmission, which can drain and will store power for clockwork structures."
|
||||
|
||||
|
||||
//Mania Motor: Creates a malevolent transmitter that will broadcast the whispers of Sevtug into the minds of nearby nonservants, causing a variety of mental effects at a power cost.
|
||||
/datum/clockwork_scripture/create_object/mania_motor
|
||||
descname = "Powered Structure, Area Denial"
|
||||
name = "Mania Motor"
|
||||
desc = "Creates a mania motor which causes minor damage and a variety of negative mental effects in nearby non-Servant humans, potentially up to and including conversion."
|
||||
invocations = list("May this transmitter...", "...break the will of all who oppose us!")
|
||||
channel_time = 80
|
||||
power_cost = 750
|
||||
object_path = /obj/structure/destructible/clockwork/powered/mania_motor
|
||||
creator_message = "<span class='brass'>You form a mania motor, which causes minor damage and negative mental effects in non-Servants.</span>"
|
||||
observer_message = "<span class='warning'>A two-pronged machine rises from the ground!</span>"
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "It will also cure hallucinations and brain damage in nearby Servants."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Mania Motor, which causes minor damage and negative mental effects in non-Servants."
|
||||
|
||||
|
||||
//Clockwork Obelisk: Creates a powerful obelisk that can be used to broadcast messages or open a gateway to any servant or clockwork obelisk at a power cost.
|
||||
/datum/clockwork_scripture/create_object/clockwork_obelisk
|
||||
descname = "Powered Structure, Teleportation Hub"
|
||||
name = "Clockwork Obelisk"
|
||||
desc = "Creates a clockwork obelisk that can broadcast messages over the Hierophant Network or open a Spatial Gateway to any living Servant or clockwork obelisk."
|
||||
invocations = list("May this obelisk...", "...take us to all places!")
|
||||
channel_time = 80
|
||||
power_cost = 300
|
||||
object_path = /obj/structure/destructible/clockwork/powered/clockwork_obelisk
|
||||
creator_message = "<span class='brass'>You form a clockwork obelisk which can broadcast messages or produce Spatial Gateways.</span>"
|
||||
observer_message = "<span class='warning'>A brass obelisk appears hanging in midair!</span>"
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "Producing a gateway has a high power cost. Gateways to or between clockwork obelisks receive double duration and uses."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 3
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Clockwork Obelisk, which can send messages or open Spatial Gateways with power."
|
||||
|
||||
|
||||
//Clockwork Marauder: Creates a construct shell for a clockwork marauder, a well-rounded frontline fighter.
|
||||
/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 that can deflect projectiles with its shield."
|
||||
invocations = list("Arise, avatar of Arbiter!", "Defend the Ark with vengeful zeal.")
|
||||
channel_time = 80
|
||||
power_cost = 8000
|
||||
creator_message = "<span class='brass'>Your slab disgorges several chunks of replicant alloy that form into a suit of thrumming armor.</span>"
|
||||
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
|
||||
sort_priority = 4
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a clockwork marauder, used for frontline combat."
|
||||
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
|
||||
for(var/V in SSticker.mode.servants_of_ratvar)
|
||||
var/datum/mind/M = V
|
||||
var/mob/living/L = M.current
|
||||
if(ishuman(L) && L.stat != DEAD)
|
||||
human_servants++
|
||||
construct_limit = human_servants / 4 //1 per 4 human servants, and a maximum of 3 marauders
|
||||
construct_limit = CLAMP(construct_limit - recent_marauders, 1, 3)
|
||||
if(recent_marauders)
|
||||
to_chat(invoker, "<span class='warning'>The Hierophant Network needs [MARAUDER_SCRIPTURE_SCALING_THRESHOLD / 10] seconds to recover from marauder summoning; recent summoning has limited the number of available marauders by [recent_marauders]!</span>")
|
||||
|
||||
/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)
|
||||
@@ -1,46 +0,0 @@
|
||||
/////////////////
|
||||
// CYBORG ONLY //
|
||||
/////////////////
|
||||
|
||||
//Linked Vanguard: grants Vanguard to the invoker and a target
|
||||
/datum/clockwork_scripture/ranged_ability/linked_vanguard
|
||||
name = "Linked Vanguard"
|
||||
invocations = list("Shield us...", "...from darkness!")
|
||||
channel_time = 30
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
quickbind_desc = "Allows you to grant a Servant and yourself stun immunity, as the Vanguard scripture.<br><b>Click your slab to disable.</b>"
|
||||
slab_overlay = "vanguard"
|
||||
ranged_type = /obj/effect/proc_holder/slab/vanguard
|
||||
ranged_message = "<span class='inathneq_small'><i>You charge the clockwork slab with defensive strength.</i>\n\
|
||||
<b>Left-click a fellow Servant or yourself to grant Vanguard!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 50
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/linked_vanguard/check_special_requirements()
|
||||
if(!GLOB.ratvar_awakens && islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time)
|
||||
to_chat(invoker, "<span class='warning'>You are already shielded by a Vanguard!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/linked_vanguard/scripture_effects()
|
||||
if(GLOB.ratvar_awakens) //hey, ratvar's up! give everybody stun immunity.
|
||||
for(var/mob/living/L in view(7, get_turf(invoker)))
|
||||
if(L.stat != DEAD && is_servant_of_ratvar(L))
|
||||
L.apply_status_effect(STATUS_EFFECT_VANGUARD)
|
||||
CHECK_TICK
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
//Judicial Marker: places a judicial marker at a target location
|
||||
/datum/clockwork_scripture/ranged_ability/judicial_marker
|
||||
name = "Judicial Marker"
|
||||
invocations = list("May heathens...", "...kneel under our force!")
|
||||
channel_time = 30
|
||||
primary_component = BELLIGERENT_EYE
|
||||
quickbind_desc = "Allows you to smite an area, applying Belligerent and briefly stunning.<br><b>Click your slab to disable.</b>"
|
||||
slab_overlay = "judicial"
|
||||
ranged_type = /obj/effect/proc_holder/slab/judicial
|
||||
ranged_message = "<span class='neovgre_small'><i>You charge the clockwork slab with judicial force.</i>\n\
|
||||
<b>Left-click a target to place a Judicial Marker!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 50
|
||||
@@ -1,284 +0,0 @@
|
||||
/////////////
|
||||
// DRIVERS //
|
||||
/////////////
|
||||
|
||||
|
||||
//Stargazer: Creates a stargazer, a cheap power generator that utilizes starlight.
|
||||
/datum/clockwork_scripture/create_object/stargazer
|
||||
descname = "Generates Power From Starlight - Important!"
|
||||
name = "Stargazer"
|
||||
desc = "Forms a weak structure that generates power every second while within three tiles of starlight."
|
||||
invocations = list("Capture their inferior light for us!")
|
||||
channel_time = 50
|
||||
power_cost = 50
|
||||
object_path = /obj/structure/destructible/clockwork/stargazer
|
||||
creator_message = "<span class='brass'>You form a stargazer, which will generate power near starlight.</span>"
|
||||
observer_message = "<span class='warning'>A large lantern-shaped machine forms!</span>"
|
||||
usage_tip = "For obvious reasons, make sure to place this near a window or somewhere else that can see space!"
|
||||
tier = SCRIPTURE_DRIVER
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 1
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a stargazer, which generates power when near starlight."
|
||||
|
||||
/datum/clockwork_scripture/create_object/stargazer/check_special_requirements()
|
||||
var/area/A = get_area(invoker)
|
||||
if(A.outdoors || A.map_name == "Space" || !A.blob_allowed)
|
||||
to_chat(invoker, "<span class='danger'>Stargazers can't be built off-station.</span>")
|
||||
return
|
||||
return ..()
|
||||
|
||||
|
||||
//Integration Cog: Creates an integration cog that can be inserted into APCs to passively siphon power.
|
||||
/datum/clockwork_scripture/create_object/integration_cog
|
||||
descname = "APC Power Siphoner"
|
||||
name = "Integration Cog"
|
||||
desc = "Fabricates an integration cog, which can be used on an open APC to replace its innards and passively siphon its power."
|
||||
invocations = list("Take that which sustains them!")
|
||||
channel_time = 10
|
||||
power_cost = 10
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clockwork/integration_cog
|
||||
creator_message = "<span class='brass'>You form an integration cog, which can be inserted into an open APC to passively siphon power.</span>"
|
||||
usage_tip = "Tampering isn't visible unless the APC is opened."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates an integration cog, which can be used to siphon power from an open APC."
|
||||
|
||||
|
||||
//Sigil of Transgression: Creates a sigil of transgression, which briefly stuns and applies Belligerent to the first non-servant to cross it.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_transgression
|
||||
descname = "Trap, Stunning"
|
||||
name = "Sigil of Transgression"
|
||||
desc = "Wards a tile with a sigil, which will briefly stun the next non-Servant to cross it and apply Belligerent to them."
|
||||
invocations = list("Divinity, smite...", "...those who tresspass here!")
|
||||
channel_time = 50
|
||||
power_cost = 50
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/transgression
|
||||
creator_message = "<span class='brass'>A sigil silently appears below you. The next non-Servant to cross it will be smitten.</span>"
|
||||
usage_tip = "The sigil does not silence its victim, and is generally used to soften potential converts or would-be invaders."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 3
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Transgression, which will briefly stun and slow the next non-Servant to cross it."
|
||||
|
||||
|
||||
//Sigil of Submission: Creates a sigil of submission, which converts one heretic above it after a delay.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_submission
|
||||
descname = "Trap, Conversion"
|
||||
name = "Sigil of Submission"
|
||||
desc = "Places a luminous sigil that will convert any non-Servants that remain on it for 8 seconds."
|
||||
invocations = list("Divinity, enlighten...", "...those who trespass here!")
|
||||
channel_time = 60
|
||||
power_cost = 125
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/submission
|
||||
creator_message = "<span class='brass'>A luminous sigil appears below you. Any non-Servants to cross it will be converted after 8 seconds if they do not move.</span>"
|
||||
usage_tip = "This is the primary conversion method, though it will not penetrate mindshield implants."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 4
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Submission, which will convert non-Servants that remain on it."
|
||||
|
||||
|
||||
//Kindle: Charges the slab with blazing energy. It can be released to stun and silence a target.
|
||||
/datum/clockwork_scripture/ranged_ability/kindle
|
||||
descname = "Short-Range Single-Target Stun"
|
||||
name = "Kindle"
|
||||
desc = "Charges your slab with divine energy, allowing you to overwhelm a target with Ratvar's light."
|
||||
invocations = list("Divinity, show them your light!")
|
||||
whispered = TRUE
|
||||
channel_time = 30
|
||||
power_cost = 125
|
||||
usage_tip = "The light can be used from up to two tiles away. Damage taken will GREATLY REDUCE the stun's duration."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 5
|
||||
slab_overlay = "volt"
|
||||
ranged_type = /obj/effect/proc_holder/slab/kindle
|
||||
ranged_message = "<span class='brass'><i>You charge the clockwork slab with divine energy.</i>\n\
|
||||
<b>Left-click a target within melee range to stun!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 150
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Stuns and mutes a target from a short range."
|
||||
|
||||
|
||||
//Hateful Manacles: Applies restraints from melee over several seconds. The restraints function like handcuffs and break on removal.
|
||||
/datum/clockwork_scripture/ranged_ability/hateful_manacles
|
||||
descname = "Handcuffs"
|
||||
name = "Hateful Manacles"
|
||||
desc = "Forms replicant manacles around a target's wrists that function like handcuffs."
|
||||
invocations = list("Shackle the heretic!", "Break them in body and spirit!")
|
||||
channel_time = 15
|
||||
power_cost = 25
|
||||
whispered = TRUE
|
||||
usage_tip = "The manacles are about as strong as zipties, and break when removed."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 6
|
||||
ranged_type = /obj/effect/proc_holder/slab/hateful_manacles
|
||||
slab_overlay = "hateful_manacles"
|
||||
ranged_message = "<span class='neovgre_small'><i>You charge the clockwork slab with divine energy.</i>\n\
|
||||
<b>Left-click a target within melee range to shackle!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
timeout_time = 200
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Applies handcuffs to a struck target."
|
||||
|
||||
|
||||
//Vanguard: Provides twenty seconds of stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker.
|
||||
/datum/clockwork_scripture/vanguard
|
||||
descname = "Self Stun Immunity"
|
||||
name = "Vanguard"
|
||||
desc = "Provides twenty seconds of stun immunity. At the end of the twenty seconds, the invoker is knocked down for the equivalent of 25% of all stuns they absorbed. \
|
||||
Excessive absorption will cause unconsciousness."
|
||||
invocations = list("Shield me...", "...from darkness!")
|
||||
channel_time = 30
|
||||
power_cost = 25
|
||||
usage_tip = "You cannot reactivate Vanguard while still shielded by it."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 7
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to temporarily absorb stuns. All stuns absorbed will affect you when disabled."
|
||||
|
||||
/datum/clockwork_scripture/vanguard/check_special_requirements()
|
||||
if(!GLOB.ratvar_awakens && islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time)
|
||||
to_chat(invoker, "<span class='warning'>You are already shielded by a Vanguard!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/vanguard/scripture_effects()
|
||||
if(GLOB.ratvar_awakens)
|
||||
for(var/mob/living/L in view(7, get_turf(invoker)))
|
||||
if(L.stat != DEAD && is_servant_of_ratvar(L))
|
||||
L.apply_status_effect(STATUS_EFFECT_VANGUARD)
|
||||
CHECK_TICK
|
||||
else
|
||||
invoker.apply_status_effect(STATUS_EFFECT_VANGUARD)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Sentinel's Compromise: Allows the invoker to select a nearby servant and convert their brute, burn, and oxygen damage into half as much toxin damage.
|
||||
/datum/clockwork_scripture/ranged_ability/sentinels_compromise
|
||||
descname = "Convert Brute/Burn/Oxygen to Half Toxin"
|
||||
name = "Sentinel's Compromise"
|
||||
desc = "Charges your slab with healing power, allowing you to convert all of a target Servant's brute, burn, and oxygen damage to half as much toxin damage."
|
||||
invocations = list("Mend the wounds of...", "...my inferior flesh.")
|
||||
channel_time = 30
|
||||
power_cost = 100
|
||||
usage_tip = "The Compromise is very fast to invoke, and will remove holy water from the target Servant."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 8
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to convert a Servant's brute, burn, and oxygen damage to half toxin damage.<br><b>Click your slab to disable.</b>"
|
||||
slab_overlay = "compromise"
|
||||
ranged_type = /obj/effect/proc_holder/slab/compromise
|
||||
ranged_message = "<span class='inathneq_small'><i>You charge the clockwork slab with healing power.</i>\n\
|
||||
<b>Left-click a fellow Servant or yourself to heal!\n\
|
||||
Click your slab to cancel.</b></span>"
|
||||
|
||||
|
||||
//Abscond: Used to return to Reebe.
|
||||
/datum/clockwork_scripture/abscond
|
||||
descname = "Return to Reebe - Important!"
|
||||
name = "Abscond"
|
||||
desc = "Yanks you through space, returning you to home base."
|
||||
invocations = list("As we bid farewell, and return to the stars...", "...we shall find our way home.")
|
||||
whispered = TRUE
|
||||
channel_time = 50
|
||||
power_cost = 5
|
||||
special_power_text = "POWERCOST to bring pulled creature"
|
||||
special_power_cost = ABSCOND_ABDUCTION_COST
|
||||
usage_tip = "This can't be used while on Reebe, for obvious reasons."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Returns you to Reebe."
|
||||
|
||||
/datum/clockwork_scripture/abscond/check_special_requirements()
|
||||
if(is_reebe(invoker.z))
|
||||
to_chat(invoker, "<span class='danger'>You're already at Reebe.</span>")
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/abscond/recital()
|
||||
animate(invoker.client, color = "#AF0AAF", time = 50)
|
||||
. = ..()
|
||||
|
||||
/datum/clockwork_scripture/abscond/scripture_effects()
|
||||
var/take_pulling = invoker.pulling && isliving(invoker.pulling) && get_clockwork_power(ABSCOND_ABDUCTION_COST)
|
||||
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>")
|
||||
playsound(invoker, 'sound/magic/magic_missile.ogg', 50, TRUE)
|
||||
playsound(T, 'sound/magic/magic_missile.ogg', 50, TRUE)
|
||||
do_sparks(5, TRUE, invoker)
|
||||
do_sparks(5, TRUE, T)
|
||||
if(take_pulling)
|
||||
adjust_clockwork_power(-special_power_cost)
|
||||
invoker.pulling.forceMove(T)
|
||||
invoker.forceMove(T)
|
||||
if(invoker.client)
|
||||
animate(invoker.client, color = initial(invoker.client.color), time = 25)
|
||||
|
||||
/datum/clockwork_scripture/abscond/scripture_fail()
|
||||
if(invoker && invoker.client)
|
||||
animate(invoker.client, color = initial(invoker.client.color), time = 10)
|
||||
|
||||
|
||||
//Replicant: Creates a new clockwork slab.
|
||||
/datum/clockwork_scripture/create_object/replicant
|
||||
descname = "New Clockwork Slab - Important!"
|
||||
name = "Replicant"
|
||||
desc = "Creates a new clockwork slab."
|
||||
invocations = list("Metal, become greater!")
|
||||
channel_time = 10
|
||||
power_cost = 25
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clockwork/slab
|
||||
creator_message = "<span class='brass'>You copy a piece of replicant alloy and command it into a new slab.</span>"
|
||||
usage_tip = "This is inefficient as a way to produce components, as the slab produced must be held by someone with no other slabs to produce components."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 10
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a new Clockwork Slab."
|
||||
|
||||
|
||||
//Wraith Spectacles: Creates a pair of wraith spectacles, which grant xray vision but damage vision slowly.
|
||||
/datum/clockwork_scripture/create_object/wraith_spectacles
|
||||
descname = "Limited Xray Vision Glasses"
|
||||
name = "Wraith Spectacles"
|
||||
desc = "Fabricates a pair of glasses which grant true sight but cause gradual vision loss."
|
||||
invocations = list("Show the truth of this world to me!")
|
||||
channel_time = 10
|
||||
power_cost = 50
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clothing/glasses/wraith_spectacles
|
||||
creator_message = "<span class='brass'>You form a pair of wraith spectacles, which grant true sight but cause gradual vision loss.</span>"
|
||||
usage_tip = "\"True sight\" means that you are able to see through walls and in darkness."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 11
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a pair of Wraith Spectacles, which grant true sight but cause gradual vision loss."
|
||||
@@ -1,211 +0,0 @@
|
||||
//////////////
|
||||
// REVENANT //
|
||||
//////////////
|
||||
|
||||
//Invoke Inath-neq, the Resonant Cogwheel: Grants invulnerability and stun immunity to everyone nearby for 15 seconds.
|
||||
/datum/clockwork_scripture/invoke_inathneq
|
||||
descname = "Area Invulnerability"
|
||||
name = "Invoke Inath-neq, the Resonant Cogwheel"
|
||||
desc = "Taps the limitless power of Inath-neq, one of Ratvar's four generals. The benevolence of Inath-Neq will grant complete invulnerability to all Servants in range for fifteen seconds."
|
||||
invocations = list("I call upon you, Vanguard!!", "Let the Resonant Cogs turn once more!!", "Grant me and my allies the strength to vanquish our foes!!")
|
||||
channel_time = 100
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 10, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 3)
|
||||
usage_tip = "Servants affected by this scripture are only weak to things that outright destroy bodies, such as bombs or the singularity."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 2
|
||||
|
||||
/datum/clockwork_scripture/invoke_inathneq/check_special_requirements()
|
||||
if(!slab.no_cost && GLOB.clockwork_generals_invoked["inath-neq"] > world.time)
|
||||
to_chat(invoker, "<span class='inathneq'>\"[text2ratvar("I cannot lend you my aid yet, champion. Please be careful.")]\"</span>\n\
|
||||
<span class='warning'>Inath-neq has already been invoked recently! You must wait several minutes before calling upon the Resonant Cogwheel.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_inathneq/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/inathneq(get_turf(invoker))
|
||||
hierophant_message("<span class='inathneq_large'>[text2ratvar("Vanguard: \"I lend you my aid, champions! Let glory guide your blows!")]\"</span>", FALSE, invoker)
|
||||
GLOB.clockwork_generals_invoked["inath-neq"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
if(invoker.real_name == "Lucio")
|
||||
clockwork_say(invoker, text2ratvar("Aww, let's break it DOWN!!"))
|
||||
for(var/mob/living/L in range(7, invoker))
|
||||
if(!is_servant_of_ratvar(L) || L.stat == DEAD)
|
||||
continue
|
||||
L.apply_status_effect(STATUS_EFFECT_INATHNEQS_ENDOWMENT)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Invoke Sevtug, the Formless Pariah: Causes massive global hallucinations, braindamage, confusion, and dizziness to all humans on the same zlevel.
|
||||
/datum/clockwork_scripture/invoke_sevtug
|
||||
descname = "Global Hallucination"
|
||||
name = "Invoke Sevtug, the Formless Pariah"
|
||||
desc = "Taps the limitless power of Sevtug, one of Ratvar's four generals. The mental manipulation ability of the Pariah allows its wielder to cause mass hallucinations and confusion \
|
||||
for all non-servant humans on the same z-level as them. The power of this scripture falls off somewhat with distance, and certain things may reduce its effects."
|
||||
invocations = list("I call upon you, Fright!!", "Let your power shatter the sanity of the weak-minded!!", "Let your tendrils hold sway over all!!")
|
||||
channel_time = 150
|
||||
consumed_components = list(BELLIGERENT_EYE = 6, VANGUARD_COGWHEEL = 6, GEIS_CAPACITOR = 10, HIEROPHANT_ANSIBLE = 6)
|
||||
usage_tip = "Causes brain damage, hallucinations, confusion, and dizziness in massive amounts."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
sort_priority = 3
|
||||
primary_component = GEIS_CAPACITOR
|
||||
invokers_required = 3
|
||||
multiple_invokers_used = TRUE
|
||||
var/static/list/mindbreaksayings = list("\"Oh, great. I get to shatter some minds.\"", "\"More minds to crush.\"", \
|
||||
"\"Really, this is almost boring.\"", "\"None of these minds have anything interesting in them.\"", "\"Maybe I can instill a little bit of terror in this one.\"", \
|
||||
"\"What a waste of my power.\"", "\"I'm sure I could just control these minds instead, but they never ask.\"")
|
||||
|
||||
/datum/clockwork_scripture/invoke_sevtug/check_special_requirements()
|
||||
if(!slab.no_cost && GLOB.clockwork_generals_invoked["sevtug"] > world.time)
|
||||
to_chat(invoker, "<span class='sevtug'>\"[text2ratvar("Is it really so hard - even for a simpleton like you - to grasp the concept of waiting?")]\"</span>\n\
|
||||
<span class='warning'>Sevtug has already been invoked recently! You must wait several minutes before calling upon the Formless Pariah.</span>")
|
||||
return FALSE
|
||||
if(!slab.no_cost && GLOB.ratvar_awakens)
|
||||
to_chat(invoker, "<span class='sevtug'>\"[text2ratvar("Do you really think anything I can do right now will compare to Engine's power?")]\"</span>\n\
|
||||
<span class='warning'>Sevtug will not grant his power while Ratvar's dwarfs his own!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_sevtug/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/sevtug(get_turf(invoker))
|
||||
hierophant_message("<span class='sevtug_large'>[text2ratvar("Fright: \"I heed your call, idiots. Get going and use this chance while it lasts!")]\"</span>", FALSE, invoker)
|
||||
GLOB.clockwork_generals_invoked["sevtug"] = world.time + GLOBAL_CLOCKWORK_GENERAL_COOLDOWN
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected
|
||||
var/turf/T = get_turf(invoker)
|
||||
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
|
||||
if(H.z == invoker.z && !is_servant_of_ratvar(H))
|
||||
var/distance = 0
|
||||
distance += get_dist(T, get_turf(H))
|
||||
var/visualsdistance = max(150 - distance, 5)
|
||||
var/minordistance = max(200 - distance*2, 5)
|
||||
var/majordistance = max(150 - distance*3, 5)
|
||||
if(H.null_rod_check())
|
||||
to_chat(H, "<span class='sevtug'>[text2ratvar("Oh, a void weapon. How annoying, I may as well not bother.")]</span>\n\
|
||||
<span class='warning'>Your holy weapon glows a faint orange, defending your mind!</span>")
|
||||
continue
|
||||
else if(H.isloyal())
|
||||
visualsdistance = round(visualsdistance * 0.5) //half effect for shielded targets
|
||||
minordistance = round(minordistance * 0.5)
|
||||
majordistance = round(majordistance * 0.5)
|
||||
to_chat(H, "<span class='sevtug'>[text2ratvar("Oh, look, a mindshield. Cute, I suppose I'll humor it.")]</span>")
|
||||
else if(prob(visualsdistance))
|
||||
to_chat(H, "<span class='sevtug'>[text2ratvar(pick(mindbreaksayings))]</span>")
|
||||
H.playsound_local(T, hum, visualsdistance, 1)
|
||||
flash_color(H, flash_color="#AF0AAF", flash_time=visualsdistance*10)
|
||||
H.dizziness = minordistance + H.dizziness
|
||||
H.hallucination = minordistance + H.hallucination
|
||||
H.confused = majordistance + H.confused
|
||||
H.setBrainLoss(majordistance + H.getBrainLoss())
|
||||
return TRUE
|
||||
|
||||
|
||||
//Invoke Nezbere, the Brass Eidolon: Invokes Nezbere, bolstering the strength of many clockwork items for one minute.
|
||||
/datum/clockwork_scripture/invoke_nezbere
|
||||
descname = "Global Structure Buff"
|
||||
name = "Invoke Nezbere, the Brass Eidolon"
|
||||
desc = "Taps the limitless power of Nezbere, one of Ratvar's four generals. The restless toil of the Eidolon will empower a wide variety of clockwork apparatus for a full minute - notably, \
|
||||
replica fabricators will charge very rapidly."
|
||||
invocations = list("I call upon you, Armorer!!", "Let your machinations reign on this miserable station!!", "Let your power flow through the tools of your master!!")
|
||||
channel_time = 150
|
||||
consumed_components = list(BELLIGERENT_EYE = 6, VANGUARD_COGWHEEL = 6, GEIS_CAPACITOR = 6, REPLICANT_ALLOY = 10)
|
||||
usage_tip = "Ocular wardens will become empowered, tinkerer's daemons will produce twice as quickly, \
|
||||
and interdiction lenses, mania motors, tinkerer's daemons, and clockwork obelisks will all require no power."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 4
|
||||
invokers_required = 3
|
||||
multiple_invokers_used = TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_nezbere/check_special_requirements()
|
||||
if(!slab.no_cost && GLOB.clockwork_generals_invoked["nezbere"] > world.time)
|
||||
to_chat(invoker, "<span class='nezbere'>\"[text2ratvar("Not just yet, friend. Patience is a virtue.")]\"</span>\n\
|
||||
<span class='warning'>Nezbere has already been invoked recently! You must wait several minutes before calling upon the Brass Eidolon.</span>")
|
||||
return FALSE
|
||||
if(!slab.no_cost && GLOB.ratvar_awakens)
|
||||
to_chat(invoker, "<span class='nezbere'>\"[text2ratvar("Our master is here already. You do not require my help, friend.")]\"</span>\n\
|
||||
<span class='warning'>There is no need for Nezbere's assistance while Ratvar is risen!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_nezbere/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/nezbere(get_turf(invoker))
|
||||
hierophant_message("<span class='nezbere_large'>[text2ratvar("Armorer: \"I heed your call, champions. May your artifacts bring ruin upon the heathens that oppose our master!")]\"</span>", FALSE, invoker)
|
||||
GLOB.clockwork_generals_invoked["nezbere"] = world.time + GLOBAL_CLOCKWORK_GENERAL_COOLDOWN
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
GLOB.nezbere_invoked++
|
||||
for(var/obj/O in GLOB.all_clockwork_objects)
|
||||
O.ratvar_act()
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/reset_nezbere_invocation), 600)
|
||||
return TRUE
|
||||
|
||||
/proc/reset_nezbere_invocation()
|
||||
GLOB.nezbere_invoked--
|
||||
for(var/obj/O in GLOB.all_clockwork_objects)
|
||||
O.ratvar_act()
|
||||
|
||||
|
||||
//Invoke Nzcrentr, the Eternal Thunderbolt: Imbues an immense amount of energy into the invoker. After several seconds, everyone near the invoker will be hit with a devastating lightning blast.
|
||||
/datum/clockwork_scripture/invoke_nzcrentr
|
||||
descname = "Area Lightning Blast"
|
||||
name = "Invoke Nzcrentr, the Eternal Thunderbolt"
|
||||
desc = "Taps the limitless power of Nzcrentr, one of Ratvar's four generals. Nzcrentr will grant you a tiny fraction of its boundless power. After several seconds, all non-Servants near you \
|
||||
will be struck by devastating lightning bolts."
|
||||
invocations = list("I call upon you, Amperage!!", "Let your energy flow through me!!", "Let your boundless power shatter stars!!")
|
||||
channel_time = 100
|
||||
consumed_components = list(BELLIGERENT_EYE = 3, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 10)
|
||||
usage_tip = "Struck targets will also be knocked down for about sixteen seconds."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 5
|
||||
|
||||
/datum/clockwork_scripture/invoke_nzcrentr/check_special_requirements()
|
||||
if(!slab.no_cost && GLOB.clockwork_generals_invoked["nzcrentr"] > world.time)
|
||||
to_chat(invoker, "<span class='nzcrentr'>\"[text2ratvar("The boss says you have to wait. Hey, do you think he would mind if I killed you? ...He would? Ok.")]\"</span>\n\
|
||||
<span class='warning'>Nzcrentr has already been invoked recently! You must wait several minutes before calling upon the Eternal Thunderbolt.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_nzcrentr/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/nzcrentr(get_turf(invoker))
|
||||
GLOB.clockwork_generals_invoked["nzcrentr"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
|
||||
hierophant_message("<span class='nzcrentr_large'>[text2ratvar("Amperage: \"[invoker.real_name] has called forth my power. Hope [invoker.p_they()] [invoker.p_do()] not shatter under it!")]\"</span>", FALSE, invoker)
|
||||
invoker.visible_message("<span class='warning'>[invoker] begins to radiate a blinding light!</span>", \
|
||||
"<span class='nzcrentr'>\"[text2ratvar("The boss says it's okay to do this. Don't blame me if you die from it.")]\"</span>\n\
|
||||
<span class='userdanger'>You feel limitless power surging through you!</span>")
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
sleep(2)
|
||||
playsound(invoker, 'sound/magic/lightning_chargeup.ogg', 100, 0)
|
||||
var/oldcolor = invoker.color
|
||||
animate(invoker, color = list(rgb(255, 255, 255), rgb(255, 255, 255), rgb(255, 255, 255), rgb(0,0,0)), time = 88) //Gradual advancement to extreme brightness
|
||||
sleep(88)
|
||||
if(invoker)
|
||||
invoker.visible_message("<span class='warning'>Massive bolts of energy emerge from across [invoker]'s body!</span>", \
|
||||
"<span class='nzcrentr'>\"[text2ratvar("I told you you wouldn't be able to handle it.")]\"</span>\n\
|
||||
<span class='userdanger'>TOO... MUCH! CAN'T... TAKE IT!</span>")
|
||||
playsound(invoker, 'sound/magic/lightningbolt.ogg', 100, 0)
|
||||
if(invoker.stat == CONSCIOUS)
|
||||
animate(invoker, color = oldcolor, time = 10)
|
||||
addtimer(CALLBACK(invoker, /atom/proc/update_atom_colour), 10)
|
||||
for(var/mob/living/L in view(7, invoker))
|
||||
if(is_servant_of_ratvar(L) || L.null_rod_check())
|
||||
continue
|
||||
invoker.Beam(L, icon_state = "nzcrentrs_power", time = 10)
|
||||
var/randdamage = rand(40, 60)
|
||||
if(iscarbon(L))
|
||||
L.electrocute_act(randdamage, "Nzcrentr's power", 1, randdamage)
|
||||
else
|
||||
L.adjustFireLoss(randdamage)
|
||||
L.visible_message(
|
||||
"<span class='danger'>[L] was shocked by Nzcrentr's power!</span>", \
|
||||
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>", \
|
||||
"<span class='italics'>You hear a heavy electrical crack.</span>" \
|
||||
)
|
||||
L.Weaken(8)
|
||||
playsound(L, 'sound/magic/LightningShock.ogg', 50, 1)
|
||||
else
|
||||
playsound(invoker, 'sound/magic/Disintegrate.ogg', 50, 1)
|
||||
invoker.gib()
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
@@ -1,242 +0,0 @@
|
||||
/////////////
|
||||
// SCRIPTS //
|
||||
/////////////
|
||||
|
||||
|
||||
//Replica Fabricator: Creates a replica fabricator, used to convert objects and repair clockwork structures.
|
||||
/datum/clockwork_scripture/create_object/replica_fabricator
|
||||
descname = "Creates Brass and Converts Objects - Important!"
|
||||
name = "Replica Fabricator"
|
||||
desc = "Forms a device that, when used on certain objects, replaces them with their Ratvarian equivalents. It requires power to function."
|
||||
invocations = list("With this device...", "...his presence shall be made known.")
|
||||
channel_time = 20
|
||||
power_cost = 250
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clockwork/replica_fabricator
|
||||
creator_message = "<span class='brass'>You form a replica fabricator.</span>"
|
||||
usage_tip = "Clockwork Walls cause nearby Tinkerer's Caches to generate components passively, making this a vital tool. Clockwork Floors heal toxin damage in Servants standing on them."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 1
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Replica Fabricator, which can convert various objects to Ratvarian variants."
|
||||
|
||||
|
||||
//Ocular Warden: Creates an ocular warden, which defends a small area near it.
|
||||
/datum/clockwork_scripture/create_object/ocular_warden
|
||||
descname = "Structure, Turret"
|
||||
name = "Ocular Warden"
|
||||
desc = "Forms an automatic short-range turret which will automatically attack nearby unrestrained non-Servants that can see it."
|
||||
invocations = list("Guardians of Engine...", "...judge those who would harm us!")
|
||||
channel_time = 100
|
||||
power_cost = 250
|
||||
object_path = /obj/structure/destructible/clockwork/ocular_warden
|
||||
creator_message = "<span class='brass'>You form an ocular warden, which will automatically attack nearby unrestrained non-Servants that can see it.</span>"
|
||||
observer_message = "<span class='warning'>A brass eye takes shape and slowly rises into the air, its red iris glaring!</span>"
|
||||
usage_tip = "Although powerful, the warden is very fragile and should optimally be placed behind barricades."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
one_per_tile = TRUE
|
||||
space_allowed = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates an Ocular Warden, which will automatically attack nearby unrestrained non-Servants that can see it."
|
||||
|
||||
/datum/clockwork_scripture/create_object/ocular_warden/check_special_requirements()
|
||||
for(var/obj/structure/destructible/clockwork/ocular_warden/W in range(OCULAR_WARDEN_EXCLUSION_RANGE, invoker))
|
||||
to_chat(invoker, "<span class='neovgre'>You sense another ocular warden too near this location. Placing another this close would cause them to fight.</span>" )
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
//Vitality Matrix: Creates a sigil which will drain health from nonservants and can use that health to heal or even revive servants.
|
||||
/datum/clockwork_scripture/create_object/vitality_matrix
|
||||
descname = "Trap, Damage to Healing"
|
||||
name = "Vitality Matrix"
|
||||
desc = "Places a sigil that drains life from any living non-Servants that cross it, producing Vitality. Servants that cross it, however, will be healed using existing Vitality. \
|
||||
Dead Servants can be revived by this sigil at a cost of 150 Vitality."
|
||||
invocations = list("Divinity, siphon their essence...", "...for this shell to consume.")
|
||||
channel_time = 60
|
||||
power_cost = 1000
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/vitality
|
||||
creator_message = "<span class='brass'>A vitality matrix appears below you. It will drain life from non-Servants and heal Servants that cross it.</span>"
|
||||
usage_tip = "The sigil will be consumed upon reviving a Servant."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 3
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Vitality Matrix, which drains non-Servants on it to heal Servants that cross it."
|
||||
|
||||
/datum/clockwork_scripture/create_object/vitality_matrix/check_special_requirements()
|
||||
if(locate(object_path) in range(1, invoker))
|
||||
to_chat(invoker, "<span class='danger'>Vitality matrices placed next to each other could interfere and cause a feedback loop! Move away from the other ones!</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
//Judicial Visor: Creates a judicial visor, which can smite an area.
|
||||
/datum/clockwork_scripture/create_object/judicial_visor
|
||||
descname = "Delayed Area Knockdown Glasses"
|
||||
name = "Judicial Visor"
|
||||
desc = "Creates a visor that can smite an area, applying Belligerent and briefly stunning. The smote area will explode after 3 seconds."
|
||||
invocations = list("Grant me the flames of Engine!")
|
||||
channel_time = 10
|
||||
power_cost = 400
|
||||
whispered = TRUE
|
||||
object_path = /obj/item/clothing/glasses/judicial_visor
|
||||
creator_message = "<span class='brass'>You form a judicial visor, which is capable of smiting a small area.</span>"
|
||||
usage_tip = "The visor has a thirty-second cooldown once used."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 4
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Judicial Visor, which can smite an area, applying Belligerent and briefly stunning."
|
||||
|
||||
|
||||
//Clockwork Armaments: Grants the invoker the ability to call forth a Ratvarian spear and clockwork armor.
|
||||
/datum/clockwork_scripture/clockwork_armaments
|
||||
descname = "Summonable Armor and Weapons - Important!"
|
||||
name = "Clockwork Armaments"
|
||||
desc = "Allows the invoker to summon clockwork armor and a Ratvarian spear at will. The spear's attacks will generate Vitality, used for healing."
|
||||
invocations = list("Grant me armaments...", "...from the forge of Armorer!")
|
||||
channel_time = 20
|
||||
power_cost = 250
|
||||
whispered = TRUE
|
||||
usage_tip = "Throwing the spear at a mob will do massive damage and knock them down, but break the spear. You will need to wait for 30 seconds before resummoning it."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you."
|
||||
|
||||
/datum/clockwork_scripture/clockwork_armaments/check_special_requirements()
|
||||
for(var/datum/action/innate/clockwork_armaments/F in invoker.actions)
|
||||
to_chat(invoker, "<span class='warning'>You have already bound a Ratvarian spear to yourself!</span>")
|
||||
return FALSE
|
||||
return invoker.can_hold_items()
|
||||
|
||||
/datum/clockwork_scripture/clockwork_armaments/scripture_effects()
|
||||
invoker.visible_message("<span class='warning'>A shimmer of yellow light infuses [invoker]!</span>", \
|
||||
"<span class='brass'>You bind clockwork equipment to yourself. Use Clockwork Armaments and Call Spear to summon them.</span>")
|
||||
var/datum/action/innate/call_weapon/ratvarian_spear/S = new()
|
||||
S.Grant(invoker)
|
||||
var/datum/action/innate/clockwork_armaments/A = new()
|
||||
A.Grant(invoker)
|
||||
return TRUE
|
||||
|
||||
//Clockwork Armaments: Equips a set of clockwork armor. Three-minute cooldown.
|
||||
/datum/action/innate/clockwork_armaments
|
||||
name = "Clockwork Armaments"
|
||||
desc = "Outfits you in a full set of Ratvarian armor."
|
||||
icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
|
||||
button_icon_state = "clockwork_armor"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/cooldown = 0
|
||||
var/static/list/ratvarian_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/armor/clockwork,
|
||||
/obj/item/clothing/head/helmet/clockwork,
|
||||
/obj/item/clothing/gloves/clockwork,
|
||||
/obj/item/clothing/shoes/clockwork)) //don't replace this ever
|
||||
var/static/list/better_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/space,
|
||||
/obj/item/clothing/head/helmet/space,
|
||||
/obj/item/clothing/shoes/magboots)) //replace this only if ratvar is up
|
||||
|
||||
/datum/action/innate/clockwork_armaments/IsAvailable()
|
||||
if(!is_servant_of_ratvar(owner))
|
||||
qdel(src)
|
||||
return
|
||||
if(cooldown > world.time)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/clockwork_armaments/Activate()
|
||||
var/do_message = 0
|
||||
var/obj/item/I = owner.get_item_by_slot(slot_wear_suit)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/suit/armor/clockwork(null), slot_wear_suit)
|
||||
I = owner.get_item_by_slot(slot_head)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/head/helmet/clockwork(null), slot_head)
|
||||
I = owner.get_item_by_slot(slot_gloves)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/gloves/clockwork(null), slot_gloves)
|
||||
I = owner.get_item_by_slot(slot_shoes)
|
||||
if(remove_item_if_better(I, owner))
|
||||
do_message += owner.equip_to_slot_or_del(new/obj/item/clothing/shoes/clockwork(null), slot_shoes)
|
||||
if(do_message)
|
||||
owner.visible_message("<span class='warning'>Strange armor appears on [owner]!</span>", "<span class='heavy_brass'>A bright shimmer runs down your body, equipping you with Ratvarian armor.</span>")
|
||||
playsound(owner, 'sound/magic/clockwork/fellowship_armory.ogg', 15 * do_message, TRUE) //get sound loudness based on how much we equipped
|
||||
cooldown = CLOCKWORK_ARMOR_COOLDOWN + world.time
|
||||
owner.update_action_buttons_icon()
|
||||
addtimer(CALLBACK(owner, /mob.proc/update_action_buttons_icon), CLOCKWORK_ARMOR_COOLDOWN)
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/clockwork_armaments/proc/remove_item_if_better(obj/item/I, mob/user)
|
||||
if(!I)
|
||||
return TRUE
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
return FALSE
|
||||
if(!GLOB.ratvar_awakens && is_type_in_typecache(I, better_armor_typecache))
|
||||
return FALSE
|
||||
return user.dropItemToGround(I)
|
||||
|
||||
//Call Spear: Calls forth a powerful Ratvarian spear.
|
||||
/datum/action/innate/call_weapon/ratvarian_spear
|
||||
name = "Call Spear"
|
||||
desc = "Calls a Ratvarian spear into your hands to fight your enemies."
|
||||
weapon_type = /obj/item/clockwork/weapon/ratvarian_spear
|
||||
|
||||
|
||||
//Spatial Gateway: Allows the invoker to teleport themselves and any nearby allies to a conscious servant or clockwork obelisk.
|
||||
/datum/clockwork_scripture/spatial_gateway
|
||||
descname = "Teleport Gate"
|
||||
name = "Spatial Gateway"
|
||||
desc = "Tears open a miniaturized gateway in spacetime to any conscious servant that can transport objects or creatures to its destination. \
|
||||
Each servant assisting in the invocation adds one additional use and four additional seconds to the gateway's uses and duration."
|
||||
invocations = list("Spatial Gateway...", "...activate!")
|
||||
channel_time = 80
|
||||
power_cost = 400
|
||||
multiple_invokers_used = TRUE
|
||||
multiple_invokers_optional = TRUE
|
||||
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
|
||||
|
||||
/datum/clockwork_scripture/spatial_gateway/check_special_requirements()
|
||||
if(!isturf(invoker.loc))
|
||||
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.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)
|
||||
if(O.anchored)
|
||||
other_servants++
|
||||
if(!other_servants)
|
||||
to_chat(invoker, "<span class='warning'>There are no other conscious servants or anchored clockwork obelisks!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/spatial_gateway/scripture_effects()
|
||||
var/portal_uses = 0
|
||||
var/duration = 0
|
||||
for(var/mob/living/L in range(1, invoker))
|
||||
if(!L.stat && is_servant_of_ratvar(L))
|
||||
portal_uses++
|
||||
duration += 40 //4 seconds
|
||||
if(GLOB.ratvar_awakens)
|
||||
portal_uses = max(portal_uses, 100) //Very powerful if Ratvar has been summoned
|
||||
duration = max(duration, 100)
|
||||
return slab.procure_gateway(invoker, duration, portal_uses)
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
//The base clockwork structure. Can have an alternate desc and will show up in the list of clockwork objects.
|
||||
/obj/structure/destructible/clockwork
|
||||
name = "meme structure"
|
||||
desc = "Some frog or something, the fuck?"
|
||||
var/clockwork_desc //Shown to servants when they examine
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "rare_pepe"
|
||||
var/unanchored_icon //icon for when this structure is unanchored, doubles as the var for if it can be unanchored
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
var/can_be_repaired = TRUE //if a fabricator can repair it
|
||||
break_message = "<span class='warning'>The frog isn't a meme after all!</span>" //The message shown when a structure breaks
|
||||
break_sound = 'sound/magic/clockwork/anima_fragment_death.ogg' //The sound played when a structure breaks
|
||||
debris = list(/obj/item/clockwork/alloy_shards/large = 1, \
|
||||
/obj/item/clockwork/alloy_shards/medium = 2, \
|
||||
/obj/item/clockwork/alloy_shards/small = 3) //Parts left behind when a structure breaks
|
||||
var/construction_value = 0 //How much value the structure contributes to the overall "power" of the structures on the station
|
||||
var/immune_to_servant_attacks = FALSE //if we ignore attacks from servants of ratvar instead of taking damage
|
||||
|
||||
/obj/structure/destructible/clockwork/Initialize()
|
||||
. = ..()
|
||||
change_construction_value(construction_value)
|
||||
GLOB.all_clockwork_objects += src
|
||||
|
||||
/obj/structure/destructible/clockwork/Destroy()
|
||||
change_construction_value(-construction_value)
|
||||
GLOB.all_clockwork_objects -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens || GLOB.clockwork_gateway_activated)
|
||||
obj_integrity = max_integrity
|
||||
|
||||
/obj/structure/destructible/clockwork/narsie_act()
|
||||
if(take_damage(rand(25, 50), BRUTE) && src) //if we still exist
|
||||
var/previouscolor = color
|
||||
color = "#960000"
|
||||
animate(src, color = previouscolor, time = 8)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
|
||||
/obj/structure/destructible/clockwork/examine(mob/user)
|
||||
var/can_see_clockwork = is_servant_of_ratvar(user) || isobserver(user)
|
||||
if(can_see_clockwork && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
..()
|
||||
desc = initial(desc)
|
||||
if(unanchored_icon)
|
||||
to_chat(user, "<span class='notice'>[src] is [anchored ? "":"not "]secured to the floor.</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/examine_status(mob/user)
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
var/t_It = p_they(TRUE)
|
||||
var/t_is = p_are()
|
||||
var/heavily_damaged = FALSE
|
||||
var/healthpercent = (obj_integrity/max_integrity) * 100
|
||||
if(healthpercent < 50)
|
||||
heavily_damaged = TRUE
|
||||
return "<span class='[heavily_damaged ? "alloy":"brass"]'>[t_It] [t_is] at <b>[obj_integrity]/[max_integrity]</b> integrity[heavily_damaged ? "!":"."]</span>"
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
|
||||
if(is_servant_of_ratvar(user) && immune_to_servant_attacks)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/hulk_damage()
|
||||
return 20
|
||||
|
||||
/obj/structure/destructible/clockwork/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1)
|
||||
if(is_servant_of_ratvar(user) && immune_to_servant_attacks)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/mech_melee_attack(obj/mecha/M)
|
||||
if(M.occupant && is_servant_of_ratvar(M.occupant) && immune_to_servant_attacks)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/proc/get_efficiency_mod()
|
||||
if(GLOB.ratvar_awakens)
|
||||
return 2
|
||||
. = max(sqrt(obj_integrity/max(max_integrity, 1)), 0.5)
|
||||
. = round(., 0.01)
|
||||
|
||||
/obj/structure/destructible/clockwork/attack_ai(mob/user)
|
||||
if(is_servant_of_ratvar(user))
|
||||
attack_hand(user)
|
||||
|
||||
/obj/structure/destructible/clockwork/attack_animal(mob/living/simple_animal/M)
|
||||
if(is_servant_of_ratvar(M))
|
||||
attack_hand(M)
|
||||
return FALSE
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/attackby(obj/item/I, mob/user, params)
|
||||
if(is_servant_of_ratvar(user) && istype(I, /obj/item/wrench) && unanchored_icon)
|
||||
if(default_unfasten_wrench(user, I, 50) == SUCCESSFUL_UNFASTEN)
|
||||
update_anchored(user)
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/attacked_by(obj/item/I, mob/living/user)
|
||||
if(is_servant_of_ratvar(user) && immune_to_servant_attacks)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/proc/update_anchored(mob/user, do_damage)
|
||||
if(anchored)
|
||||
icon_state = initial(icon_state)
|
||||
else
|
||||
icon_state = unanchored_icon
|
||||
if(do_damage)
|
||||
playsound(src, break_sound, 10 * (40 * (1 - get_efficiency_mod())), 1)
|
||||
take_damage(round(max_integrity * 0.25, 1), BRUTE)
|
||||
to_chat(user, "<span class='warning'>As you unsecure [src] from the floor, you see cracks appear in its surface!</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/emp_act(severity)
|
||||
if(anchored && unanchored_icon)
|
||||
anchored = FALSE
|
||||
update_anchored(null, obj_integrity > max_integrity * 0.25)
|
||||
new /obj/effect/temp_visual/emp(loc)
|
||||
|
||||
|
||||
//for the ark and Ratvar
|
||||
/obj/structure/destructible/clockwork/massive
|
||||
name = "massive construct"
|
||||
desc = "A very large construction."
|
||||
layer = MASSIVE_OBJ_LAYER
|
||||
density = FALSE
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF | FREEZE_PROOF
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/Initialize()
|
||||
. = ..()
|
||||
GLOB.poi_list += src
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/Destroy()
|
||||
GLOB.poi_list -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/singularity_pull(S, current_size)
|
||||
return
|
||||
|
||||
|
||||
//the base clockwork machinery, which is not actually machines, but happens to use power
|
||||
/obj/structure/destructible/clockwork/powered
|
||||
var/obj/machinery/power/apc/target_apc
|
||||
var/active = FALSE
|
||||
var/needs_power = TRUE
|
||||
var/active_icon = null //icon_state while process() is being called
|
||||
var/inactive_icon = null //icon_state while process() isn't being called
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(!can_access_clockwork_power(src))
|
||||
to_chat(user, "<span class='alloy'>It has no access to the power network! Create a sigil of transmission nearby.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='brass'>It has access to <b>[DisplayPower(get_clockwork_power())]</b> of power.</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/Destroy()
|
||||
SSfastprocess.processing -= src
|
||||
SSobj.processing -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/process()
|
||||
var/powered = can_access_clockwork_power(src)
|
||||
return powered == PROCESS_KILL ? 25 : powered //make sure we don't accidentally return the arbitrary PROCESS_KILL define
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/can_be_unfasten_wrench(mob/user, silent)
|
||||
if(active)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[src] needs to be disabled before it can be unsecured!</span>")
|
||||
return FAILED_UNFASTEN
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/toggle(fast_process, mob/living/user)
|
||||
if(user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return FALSE
|
||||
if(!anchored && !active)
|
||||
to_chat(user, "<span class='warning'>[src] needs to be secured to the floor before it can be activated!</span>")
|
||||
return FALSE
|
||||
visible_message("<span class='notice'>[user] [active ? "dis" : "en"]ables [src].</span>", "<span class='brass'>You [active ? "dis" : "en"]able [src].</span>")
|
||||
active = !active
|
||||
if(active)
|
||||
icon_state = active_icon
|
||||
if(fast_process)
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
else
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
icon_state = inactive_icon
|
||||
if(fast_process)
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/forced_disable(bad_effects)
|
||||
if(active)
|
||||
toggle()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/emp_act(severity)
|
||||
if(forced_disable(TRUE))
|
||||
new /obj/effect/temp_visual/emp(loc)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/try_use_power(amount) //try to use an amount of power
|
||||
if(!needs_power || GLOB.ratvar_awakens || !amount)
|
||||
return TRUE
|
||||
if(!can_access_clockwork_power(src, amount))
|
||||
return
|
||||
return use_power(amount)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/proc/use_power(amount) //we've made sure we had power, so now we use it
|
||||
return adjust_clockwork_power(-amount)
|
||||
@@ -1,86 +0,0 @@
|
||||
//No, not that kind.
|
||||
/obj/structure/destructible/clockwork/trap
|
||||
name = "base clockwork trap"
|
||||
desc = "You shouldn't see this. File a bug report!"
|
||||
clockwork_desc = "A trap that shouldn't exist, and you should report this as a bug."
|
||||
var/list/wired_to
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/Initialize()
|
||||
. = ..()
|
||||
wired_to = list()
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/Destroy()
|
||||
for(var/V in wired_to)
|
||||
var/obj/structure/destructible/clockwork/trap/T = V
|
||||
T.wired_to -= src
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "It's wired to:")
|
||||
if(!wired_to.len)
|
||||
to_chat(user, "Nothing.")
|
||||
else
|
||||
for(var/V in wired_to)
|
||||
var/obj/O = V
|
||||
var/distance = get_dist(src, O)
|
||||
to_chat(user, "[O] ([distance == 0 ? "same tile" : "[distance] tiles [dir2text(get_dir(src, O))]"])")
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/wrench_act(mob/living/user, obj/item/wrench)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return ..()
|
||||
to_chat(user, "<span class='notice'>You break down the delicate components of [src] into brass.</span>")
|
||||
playsound(src, wrench.usesound, 50, TRUE)
|
||||
new/obj/item/stack/tile/brass(get_turf(src))
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/clockwork/slab) && is_servant_of_ratvar(user))
|
||||
var/obj/item/clockwork/slab/F = I
|
||||
if(!F.linking)
|
||||
to_chat(user, "<span class='notice'>Beginning link. Alt-click the slab to cancel, or use it on another trap object to link the two.</span>")
|
||||
F.linking = src
|
||||
else
|
||||
if(F.linking in wired_to)
|
||||
to_chat(user, "<span class='warning'>These two objects are already connected!</span>")
|
||||
return
|
||||
if(F.linking.z != z)
|
||||
to_chat(user, "<span class='warning'>You'd need a <b>much</b> tougher slab to link two objects in different sectors.</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You link [F.linking] with [src].</span>")
|
||||
wired_to += F.linking
|
||||
F.linking.wired_to += src
|
||||
F.linking = null
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/wirecutter_act(mob/living/user, obj/item/wirecutters)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return
|
||||
if(!wired_to.len)
|
||||
to_chat(user, "<span class='warning'>[src] has no connections!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You sever all connections to [src].</span>")
|
||||
playsound(src, wirecutters.usesound, 50, TRUE)
|
||||
for(var/V in wired_to)
|
||||
var/obj/structure/destructible/clockwork/trap/T = V
|
||||
T.wired_to -= src
|
||||
wired_to -= T
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/proc/activate()
|
||||
|
||||
//These objects send signals to normal traps to activate
|
||||
/obj/structure/destructible/clockwork/trap/trigger
|
||||
name = "base trap trigger"
|
||||
max_integrity = 5
|
||||
break_message = "<span class='warning'>The trigger breaks apart!</span>"
|
||||
density = FALSE
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/trigger/activate()
|
||||
for(var/obj/structure/destructible/clockwork/trap/T in wired_to)
|
||||
if(istype(T, /obj/structure/destructible/clockwork/trap/trigger)) //Triggers don't go off multiple times
|
||||
continue
|
||||
T.activate()
|
||||
@@ -1,376 +0,0 @@
|
||||
#define ARK_GRACE_PERIOD 300 //In seconds, how long the crew has before the Ark truly "begins"
|
||||
|
||||
/proc/clockwork_ark_active() //A helper proc so the Ark doesn't have to be typecast every time it's checked; returns null if there is no Ark and its active var otherwise
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
if(!G)
|
||||
return
|
||||
return G.active
|
||||
|
||||
//The gateway to Reebe, from which Ratvar emerges.
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway
|
||||
name = "\improper Ark of the Clockwork Justicar"
|
||||
desc = "A massive, hulking amalgamation of parts. It seems to be maintaining a very unstable bluespace anomaly."
|
||||
clockwork_desc = "Nezbere's magnum opus: a hulking clockwork machine capable of combining bluespace and steam power to summon Ratvar. Once activated, \
|
||||
its instability will cause one-way bluespace rifts to open across the station to the City of Cogs, so be prepared to defend it at all costs."
|
||||
max_integrity = 500
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "nothing"
|
||||
density = TRUE
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF | FREEZE_PROOF
|
||||
can_be_repaired = FALSE
|
||||
immune_to_servant_attacks = TRUE
|
||||
var/active = FALSE
|
||||
var/progress_in_seconds = 0 //Once this reaches GATEWAY_RATVAR_ARRIVAL, it's game over
|
||||
var/grace_period = ARK_GRACE_PERIOD //This exists to allow the crew to gear up and prepare for the invasion
|
||||
var/initial_activation_delay = -1 //How many seconds the Ark will have initially taken to activate
|
||||
var/seconds_until_activation = -1 //How many seconds until the Ark activates; if it should never activate, set this to -1
|
||||
var/purpose_fulfilled = FALSE
|
||||
var/first_sound_played = FALSE
|
||||
var/second_sound_played = FALSE
|
||||
var/third_sound_played = FALSE
|
||||
var/fourth_sound_played = FALSE
|
||||
var/obj/effect/clockwork/overlay/gateway_glow/glow
|
||||
var/obj/effect/countdown/clockworkgate/countdown
|
||||
var/last_scream = 0
|
||||
var/recalls_remaining = 1
|
||||
var/recalling
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/Initialize()
|
||||
. = ..()
|
||||
glow = new(get_turf(src))
|
||||
if(!GLOB.ark_of_the_clockwork_justiciar)
|
||||
GLOB.ark_of_the_clockwork_justiciar = src
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
. = ..()
|
||||
if(.)
|
||||
flick("clockwork_gateway_damaged", glow)
|
||||
playsound(src, 'sound/machines/clockcult/ark_damage.ogg', 75, FALSE)
|
||||
if(last_scream < world.time)
|
||||
audible_message("<span class='boldwarning'>An unearthly screaming sound resonates throughout Reebe!</span>")
|
||||
for(var/V in GLOB.player_list)
|
||||
var/mob/M = V
|
||||
var/turf/T = get_turf(M)
|
||||
if((T && T.z == z) || is_servant_of_ratvar(M) || isobserver(M))
|
||||
M.playsound_local(M, 'sound/machines/clockcult/ark_scream.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
hierophant_message("<span class='big boldwarning'>The Ark is taking damage!</span>")
|
||||
last_scream = world.time + ARK_SCREAM_COOLDOWN
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/final_countdown(ark_time) //WE'RE LEAVING TOGETHEEEEEEEEER
|
||||
if(!ark_time)
|
||||
ark_time = 30 //minutes
|
||||
initial_activation_delay = ark_time * 60
|
||||
seconds_until_activation = ark_time * 60 //60 seconds in a minute * number of minutes
|
||||
for(var/obj/item/clockwork/construct_chassis/cogscarab/C in GLOB.all_clockwork_objects)
|
||||
C.infinite_resources = FALSE
|
||||
GLOB.servants_active = TRUE
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/cry_havoc()
|
||||
visible_message("<span class='boldwarning'>[src] shudders and roars to life, its parts beginning to whirr and screech!</span>")
|
||||
hierophant_message("<span class='bold large_brass'>The Ark is activating! You will be transported there soon!</span>")
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
var/turf/T = get_turf(M)
|
||||
if(is_servant_of_ratvar(M) || isobserver(M) || (T && T.z == z))
|
||||
M.playsound_local(M, 'sound/magic/clockwork/ark_activation_sequence.ogg', 30, FALSE, pressure_affected = FALSE)
|
||||
addtimer(CALLBACK(src, .proc/let_slip_the_dogs), 300)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/let_slip_the_dogs()
|
||||
spawn_animation()
|
||||
first_sound_played = TRUE
|
||||
active = TRUE
|
||||
priority_announce("Massive [Gibberish("bluespace", 100)] anomaly detected on all frequencies. All crew are directed to \
|
||||
@!$, [text2ratvar("PURGE ALL UNTRUTHS")] <&. the anomalies and destroy their source to prevent further damage to corporate property. This is \
|
||||
not a drill.[grace_period ? " Estimated time of appearance: [grace_period] seconds. Use this time to prepare for an attack on [station_name()]." : ""]", \
|
||||
"Central Command Higher Dimensional Affairs", 'sound/magic/clockwork/ark_activation.ogg')
|
||||
set_security_level("delta")
|
||||
for(var/V in SSticker.mode.servants_of_ratvar)
|
||||
var/datum/mind/M = V
|
||||
if(!M || !M.current)
|
||||
continue
|
||||
if(ishuman(M.current))
|
||||
M.current.add_overlay(mutable_appearance('icons/effects/genetics.dmi', "servitude", -MUTATIONS_LAYER))
|
||||
for(var/V in GLOB.brass_recipes)
|
||||
var/datum/stack_recipe/R = V
|
||||
if(!R)
|
||||
continue
|
||||
if(R.title == "wall gear")
|
||||
R.time *= 2 //Building walls becomes slower when the Ark activates
|
||||
mass_recall()
|
||||
recalls_remaining++ //So it doesn't use up a charge
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/open_portal(turf/T)
|
||||
new/obj/effect/clockwork/city_of_cogs_rift(T)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/spawn_animation()
|
||||
var/turf/T = get_turf(src)
|
||||
var/list/open_turfs = list()
|
||||
for(var/turf/open/OT in orange(1, T))
|
||||
if(!is_blocked_turf(OT, TRUE))
|
||||
open_turfs |= OT
|
||||
if(open_turfs.len)
|
||||
for(var/mob/living/L in T)
|
||||
L.forceMove(pick(open_turfs))
|
||||
hierophant_message("<span class='bold large_brass'>The Ark has activated! [grace_period ? "You have [round(grace_period / 60)] minutes until the crew invades! " : ""]Defend it at all costs!</span>", FALSE, src)
|
||||
sound_to_playing_players(volume = 10, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_charging.ogg', TRUE))
|
||||
seconds_until_activation = 0
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/initiate_mass_recall()
|
||||
recalling = TRUE
|
||||
sound_to_playing_players('sound/machines/clockcult/ark_recall.ogg', 75, FALSE)
|
||||
hierophant_message("<span class='bold large_brass'>The Eminence has initiated a mass recall! You are being transported to the Ark!</span>")
|
||||
addtimer(CALLBACK(src, .proc/mass_recall), 100)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/mass_recall()
|
||||
for(var/V in SSticker.mode.servants_of_ratvar)
|
||||
var/datum/mind/M = V
|
||||
if(!M || !M.current)
|
||||
continue
|
||||
if(isliving(M.current) && M.current.stat != DEAD)
|
||||
M.current.forceMove(get_turf(src))
|
||||
M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
|
||||
M.current.clear_fullscreen("flash", 5)
|
||||
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 50, FALSE)
|
||||
recalls_remaining--
|
||||
recalling = FALSE
|
||||
transform = matrix() * 2
|
||||
animate(src, transform = matrix() * 0.5, time = 30, flags = ANIMATION_END_NOW)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
if(!purpose_fulfilled && istype(SSticker.mode, /datum/game_mode/clockwork_cult))
|
||||
hierophant_message("<span class='bold large_brass'>The Ark has fallen!</span>")
|
||||
sound_to_playing_players(null, channel = CHANNEL_JUSTICAR_ARK)
|
||||
SSticker.force_ending = TRUE //rip
|
||||
if(glow)
|
||||
qdel(glow)
|
||||
glow = null
|
||||
if(countdown)
|
||||
qdel(countdown)
|
||||
countdown = null
|
||||
for(var/mob/L in GLOB.player_list)
|
||||
var/turf/T = get_turf(L)
|
||||
if(T && T.z == z)
|
||||
var/atom/movable/target = L
|
||||
if(isobj(L.loc))
|
||||
target = L.loc
|
||||
target.forceMove(get_turf(pick(GLOB.generic_event_spawns)))
|
||||
L.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/static)
|
||||
L.clear_fullscreen("flash", 30)
|
||||
if(isliving(L))
|
||||
var/mob/living/LI = L
|
||||
LI.Stun(50)
|
||||
for(var/obj/effect/clockwork/city_of_cogs_rift/R in GLOB.all_clockwork_objects)
|
||||
qdel(R)
|
||||
if(GLOB.ark_of_the_clockwork_justiciar == src)
|
||||
GLOB.ark_of_the_clockwork_justiciar = null
|
||||
. = ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/deconstruct(disassembled = TRUE)
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
if(!disassembled)
|
||||
resistance_flags |= INDESTRUCTIBLE
|
||||
countdown.stop()
|
||||
visible_message("<span class='userdanger'>[src] begins to pulse uncontrollably... you might want to run!</span>")
|
||||
sound_to_playing_players(volume = 50, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_disrupted.ogg'))
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
var/turf/T = get_turf(M)
|
||||
if((T && T.z == z) || is_servant_of_ratvar(M))
|
||||
M.playsound_local(M, 'sound/machines/clockcult/ark_deathrattle.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_disrupted"
|
||||
resistance_flags |= INDESTRUCTIBLE
|
||||
sleep(27)
|
||||
explosion(src, 1, 3, 8, 8)
|
||||
sound_to_playing_players('sound/effects/explosion_distant.ogg', volume = 50)
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/make_glow()
|
||||
if(!glow)
|
||||
glow = new /obj/effect/clockwork/overlay/gateway_glow(get_turf(src))
|
||||
glow.linked = src
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/ex_act(severity)
|
||||
var/damage = max((obj_integrity * 0.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 "[get_arrival_time()][s_on_time ? "S" : ""]"
|
||||
if(grace_period)
|
||||
return "[get_arrival_time()][s_on_time ? "S" : ""]"
|
||||
. = "IMMINENT"
|
||||
if(!obj_integrity)
|
||||
. = "DETONATING"
|
||||
else if(GATEWAY_RATVAR_ARRIVAL - progress_in_seconds > 0)
|
||||
. = "[round(max((GATEWAY_RATVAR_ARRIVAL - progress_in_seconds) / (GATEWAY_SUMMON_RATE), 0), 1)][s_on_time ? "S":""]"
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/examine(mob/user)
|
||||
icon_state = "spatial_gateway" //cheat wildly by pretending to have an icon
|
||||
..()
|
||||
icon_state = initial(icon_state)
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(!active)
|
||||
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> [DisplayTimeText(get_arrival_time())]</span>")
|
||||
else
|
||||
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>")
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
to_chat(user, "<span class='heavy_brass'>The field is ripping open a copy of itself in Ratvar's prison.</span>")
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
to_chat(user, "<span class='heavy_brass'>With the bluespace field established, Ratvar is preparing to come through!</span>")
|
||||
else
|
||||
if(!active)
|
||||
to_chat(user, "<span class='warning'>Whatever it is, it doesn't seem to be active.</span>")
|
||||
else
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
to_chat(user, "<span class='warning'>You see a swirling bluespace anomaly steadily growing in intensity.</span>")
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
to_chat(user, "<span class='warning'>The anomaly is stable, and you can see flashes of something from it.</span>")
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
to_chat(user, "<span class='boldwarning'>The anomaly is stable! Something is coming through!</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/process()
|
||||
if(seconds_until_activation == -1) //we never do anything
|
||||
return
|
||||
adjust_clockwork_power(2.5) //Provides weak power generation on its own
|
||||
if(seconds_until_activation)
|
||||
if(!countdown)
|
||||
countdown = new(src)
|
||||
countdown.start()
|
||||
seconds_until_activation--
|
||||
if(!GLOB.script_scripture_unlocked && initial_activation_delay * 0.5 > seconds_until_activation)
|
||||
GLOB.script_scripture_unlocked = TRUE
|
||||
hierophant_message("<span class='large_brass bold'>The Ark is halfway prepared. Script scripture is now available!</span>")
|
||||
if(!seconds_until_activation)
|
||||
cry_havoc()
|
||||
seconds_until_activation = -1 //we'll set this after cry_havoc()
|
||||
return
|
||||
if(!first_sound_played || prob(7))
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!isnewplayer(M))
|
||||
var/turf/T = get_turf(M)
|
||||
if(T && T.z == z)
|
||||
to_chat(M, "<span class='warning'><b>You hear otherworldly sounds from the [dir2text(get_dir(get_turf(M), get_turf(src)))]...</span>")
|
||||
else
|
||||
to_chat(M, "<span class='boldwarning'>You hear otherworldly sounds from all around you...</span>")
|
||||
if(!obj_integrity)
|
||||
return
|
||||
for(var/turf/closed/wall/W in RANGE_TURFS(2, src))
|
||||
W.dismantle_wall()
|
||||
for(var/obj/O in orange(1, src))
|
||||
if(!O.pulledby && !istype(O, /obj/effect) && O.density)
|
||||
if(!step_away(O, src, 2) || get_dist(O, src) < 2)
|
||||
O.take_damage(50, BURN, "bomb")
|
||||
O.update_icon()
|
||||
for(var/V in GLOB.player_list)
|
||||
var/mob/M = V
|
||||
var/turf/T = get_turf(M)
|
||||
if(is_servant_of_ratvar(M) && (!T || T.z != z))
|
||||
M.forceMove(get_step(src, SOUTH))
|
||||
M.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
|
||||
M.clear_fullscreen("flash", 5)
|
||||
if(grace_period)
|
||||
grace_period--
|
||||
return
|
||||
progress_in_seconds += GATEWAY_SUMMON_RATE
|
||||
switch(progress_in_seconds)
|
||||
if(-INFINITY to GATEWAY_REEBE_FOUND)
|
||||
if(!second_sound_played)
|
||||
for(var/V in GLOB.generic_event_spawns)
|
||||
addtimer(CALLBACK(src, .proc/open_portal, get_turf(V)), rand(100, 600))
|
||||
sound_to_playing_players('sound/magic/clockwork/invoke_general.ogg', 30, FALSE)
|
||||
sound_to_playing_players(volume = 20, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_charging.ogg', TRUE))
|
||||
second_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_charging"
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
if(!third_sound_played)
|
||||
sound_to_playing_players(volume = 25, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_active.ogg', TRUE))
|
||||
third_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_active"
|
||||
if(GATEWAY_RATVAR_COMING to GATEWAY_RATVAR_ARRIVAL)
|
||||
if(!fourth_sound_played)
|
||||
sound_to_playing_players(volume = 30, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/clockcult_gateway_closing.ogg', TRUE))
|
||||
fourth_sound_played = TRUE
|
||||
make_glow()
|
||||
glow.icon_state = "clockwork_gateway_closing"
|
||||
if(GATEWAY_RATVAR_ARRIVAL to INFINITY)
|
||||
if(!purpose_fulfilled)
|
||||
countdown.stop()
|
||||
resistance_flags |= INDESTRUCTIBLE
|
||||
purpose_fulfilled = TRUE
|
||||
make_glow()
|
||||
animate(glow, transform = matrix() * 1.5, alpha = 255, time = 125)
|
||||
sound_to_playing_players(volume = 100, channel = CHANNEL_JUSTICAR_ARK, S = sound('sound/effects/ratvar_rises.ogg')) //End the sounds
|
||||
sleep(125)
|
||||
make_glow()
|
||||
animate(glow, transform = matrix() * 3, alpha = 0, time = 5)
|
||||
QDEL_IN(src, 3)
|
||||
sleep(3)
|
||||
GLOB.clockwork_gateway_activated = TRUE
|
||||
var/turf/T = SSmapping.get_station_center()
|
||||
new /obj/structure/destructible/clockwork/massive/ratvar(T)
|
||||
SSticker.force_ending = TRUE
|
||||
var/x0 = T.x
|
||||
var/y0 = T.y
|
||||
for(var/I in spiral_range_turfs(255, T, tick_checked = TRUE))
|
||||
var/turf/T2 = I
|
||||
if(!T2)
|
||||
continue
|
||||
var/dist = cheap_hypotenuse(T2.x, T2.y, x0, y0)
|
||||
if(dist < 100)
|
||||
dist = TRUE
|
||||
else
|
||||
dist = FALSE
|
||||
T.ratvar_act(dist)
|
||||
CHECK_TICK
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/attack_ghost(mob/user)
|
||||
if(!IsAdminGhost(user))
|
||||
return ..()
|
||||
if(GLOB.servants_active)
|
||||
to_chat(user, "<span class='danger'>The Ark is already counting down.</span>")
|
||||
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)
|
||||
|
||||
|
||||
|
||||
//the actual appearance of the Ark of the Clockwork Justicar; an object so the edges of the gate can be clicked through.
|
||||
/obj/effect/clockwork/overlay/gateway_glow
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "clockwork_gateway_components"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
layer = BELOW_OPEN_DOOR_LAYER
|
||||
light_range = 2
|
||||
light_power = 4
|
||||
light_color = "#6A4D2F"
|
||||
@@ -1,103 +0,0 @@
|
||||
//Clockwork Obelisk: Can broadcast a message at a small power cost or outright open a spatial gateway at a massive power cost.
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk
|
||||
name = "clockwork obelisk"
|
||||
desc = "A large brass obelisk hanging in midair."
|
||||
clockwork_desc = "A powerful obelisk that can send a message to all servants or open a gateway to a target servant or clockwork obelisk."
|
||||
icon_state = "obelisk_inactive"
|
||||
active_icon = "obelisk"
|
||||
inactive_icon = "obelisk_inactive"
|
||||
unanchored_icon = "obelisk_unwrenched"
|
||||
construction_value = 20
|
||||
max_integrity = 150
|
||||
break_message = "<span class='warning'>The obelisk falls to the ground, undamaged!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/small = 4, \
|
||||
/obj/item/clockwork/alloy_shards/medium = 2, \
|
||||
/obj/item/clockwork/component/hierophant_ansible/obelisk = 1)
|
||||
var/hierophant_cost = MIN_CLOCKCULT_POWER //how much it costs to broadcast with large text
|
||||
var/gateway_cost = 2000 //how much it costs to open a gateway
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/Initialize()
|
||||
. = ..()
|
||||
toggle(1)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='nzcrentr_small'>It requires <b>[DisplayPower(hierophant_cost)]</b> to broadcast over the Hierophant Network, and <b>[DisplayPower(gateway_cost)]</b> to open a Spatial Gateway.</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/can_be_unfasten_wrench(mob/user, silent)
|
||||
if(active)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='warning'>[src] is currently sustaining a gateway!</span>")
|
||||
return FAILED_UNFASTEN
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/forced_disable(bad_effects)
|
||||
var/affected = 0
|
||||
for(var/obj/effect/clockwork/spatial_gateway/SG in loc)
|
||||
SG.ex_act(EXPLODE_DEVASTATE)
|
||||
affected++
|
||||
if(bad_effects)
|
||||
affected += try_use_power(MIN_CLOCKCULT_POWER*4)
|
||||
return affected
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user) || !can_access_clockwork_power(src, hierophant_cost) || !anchored)
|
||||
to_chat(user, "<span class='warning'>You place your hand on [src], but it doesn't react.</span>")
|
||||
return
|
||||
var/choice = alert(user,"You place your hand on [src]...",,"Hierophant Broadcast","Spatial Gateway","Cancel")
|
||||
switch(choice)
|
||||
if("Hierophant Broadcast")
|
||||
if(active)
|
||||
to_chat(user, "<span class='warning'>[src] is sustaining a gateway and cannot broadcast!</span>")
|
||||
return
|
||||
if(!user.can_speak_vocal())
|
||||
to_chat(user, "<span class='warning'>You cannot speak through [src]!</span>")
|
||||
return
|
||||
var/input = stripped_input(usr, "Please choose a message to send over the Hierophant Network.", "Hierophant Broadcast", "")
|
||||
if(!is_servant_of_ratvar(user) || !input || !user.canUseTopic(src, !issilicon(user)))
|
||||
return
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='warning'>[src] is no longer secured!</span>")
|
||||
return FALSE
|
||||
if(active)
|
||||
to_chat(user, "<span class='warning'>[src] is sustaining a gateway and cannot broadcast!</span>")
|
||||
return
|
||||
if(!user.can_speak_vocal())
|
||||
to_chat(user, "<span class='warning'>You cannot speak through [src]!</span>")
|
||||
return
|
||||
if(!try_use_power(hierophant_cost))
|
||||
to_chat(user, "<span class='warning'>[src] lacks the power to broadcast!</span>")
|
||||
return
|
||||
clockwork_say(user, text2ratvar("Hierophant Broadcast, activate! [html_decode(input)]"))
|
||||
titled_hierophant_message(user, input, "big_brass", "large_brass")
|
||||
if("Spatial Gateway")
|
||||
if(active)
|
||||
to_chat(user, "<span class='warning'>[src] is already sustaining a gateway!</span>")
|
||||
return
|
||||
if(!user.can_speak_vocal())
|
||||
to_chat(user, "<span class='warning'>You need to be able to speak to open a gateway!</span>")
|
||||
return
|
||||
if(!try_use_power(gateway_cost))
|
||||
to_chat(user, "<span class='warning'>[src] lacks the power to open a gateway!</span>")
|
||||
return
|
||||
if(procure_gateway(user, round(100 * get_efficiency_mod(), 1), round(5 * get_efficiency_mod(), 1), 1))
|
||||
process()
|
||||
if(!active) //we won't be active if nobody has sent a gateway to us
|
||||
active = TRUE
|
||||
clockwork_say(user, text2ratvar("Spatial Gateway, activate!"))
|
||||
return
|
||||
adjust_clockwork_power(gateway_cost) //if we didn't return above, ie, successfully create a gateway, we give the power back
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/process()
|
||||
if(!anchored)
|
||||
return
|
||||
var/obj/effect/clockwork/spatial_gateway/SG = locate(/obj/effect/clockwork/spatial_gateway) in loc
|
||||
if(SG && SG.timerid) //it's a valid gateway, we're active
|
||||
icon_state = active_icon
|
||||
density = FALSE
|
||||
active = TRUE
|
||||
else
|
||||
icon_state = inactive_icon
|
||||
density = TRUE
|
||||
active = FALSE
|
||||
@@ -1,139 +0,0 @@
|
||||
//Used to nominate oneself or ghosts for the role of Eminence.
|
||||
/obj/structure/destructible/clockwork/eminence_spire
|
||||
name = "eminence spire"
|
||||
desc = "A hulking machine made of powerful alloy, with three small obelisks and a huge plate in the center."
|
||||
clockwork_desc = "This spire is used to become the Eminence, who functions as an invisible leader of the cult. Activate it to nominate yourself or propose that the Eminence should be \
|
||||
selected from available ghosts. Once an Eminence is selected, they can't normally be changed."
|
||||
icon_state = "tinkerers_daemon"
|
||||
break_message = "<span class='warning'>The spire screeches with crackling power and collapses into scrap!</span>"
|
||||
max_integrity = 400
|
||||
var/mob/eminence_nominee
|
||||
var/selection_timer //Timer ID; this is canceled if the vote is canceled
|
||||
var/kingmaking
|
||||
|
||||
/obj/structure/destructible/clockwork/eminence_spire/attack_hand(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='notice'>You can tell how powerful [src] is; you know better than to touch it.</span>")
|
||||
return
|
||||
if(kingmaking)
|
||||
return
|
||||
|
||||
var/datum/antagonist/clockcult/C = user.mind.has_antag_datum(/datum/antagonist/clockcult)
|
||||
if(!C || !C.clock_team)
|
||||
return
|
||||
if(C.clock_team.eminence)
|
||||
to_chat(user, "<span class='warning'>There's already an Eminence!</span>")
|
||||
return
|
||||
if(!GLOB.servants_active)
|
||||
to_chat(user, "<span class='warning'>The Ark isn't active!</span>")
|
||||
return
|
||||
if(eminence_nominee) //This could be one large proc, but is split into three for ease of reading
|
||||
if(eminence_nominee == user)
|
||||
cancelation(user)
|
||||
else
|
||||
objection(user)
|
||||
else
|
||||
nomination(user)
|
||||
|
||||
/obj/structure/destructible/clockwork/eminence_spire/attack_drone(mob/living/simple_animal/drone/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
..()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You feel the omniscient gaze turn into a puzzled frown. Perhaps you should just stick to building.</span>")
|
||||
return
|
||||
|
||||
/obj/structure/destructible/clockwork/eminence_spire/attack_ghost(mob/user)
|
||||
if(!IsAdminGhost(user))
|
||||
return
|
||||
|
||||
var/datum/antagonist/clockcult/random_cultist = locate() in get_antagonists(/datum/antagonist/clockcult) //if theres no cultists new team without eminence will be created anyway.
|
||||
if(random_cultist && random_cultist.clock_team && random_cultist.clock_team.eminence)
|
||||
to_chat(user, "<span class='warning'>There's already an Eminence - too late!</span>")
|
||||
return
|
||||
if(!GLOB.servants_active)
|
||||
to_chat(user, "<span class='warning'>The Ark must be active first!</span>")
|
||||
return
|
||||
if(alert(user, "Become the Eminence using admin?", "Become Eminence", "Yes", "No") != "Yes")
|
||||
return
|
||||
message_admins("<span class='danger'>Admin [key_name_admin(user)] directly became the Eminence of the cult!</span>")
|
||||
log_admin("Admin [key_name(user)] made themselves the Eminence.")
|
||||
var/mob/camera/eminence/eminence = new(get_turf(src))
|
||||
eminence.key = user.key
|
||||
hierophant_message("<span class='bold large_brass'>Ratvar has directly assigned the Eminence!</span>")
|
||||
for(var/mob/M in servants_and_ghosts())
|
||||
M.playsound_local(M, 'sound/machines/clockcult/eminence_selected.ogg', 50, FALSE)
|
||||
|
||||
/obj/structure/destructible/clockwork/eminence_spire/proc/nomination(mob/living/nominee) //A user is nominating themselves or ghosts to become Eminence
|
||||
var/nomination_choice = alert(nominee, "Who would you like to nominate?", "Eminence Nomination", "Nominate Yourself", "Nominate Ghosts", "Cancel")
|
||||
if(!is_servant_of_ratvar(nominee) || !nominee.canUseTopic(src) || eminence_nominee)
|
||||
return
|
||||
switch(nomination_choice)
|
||||
if("Cancel")
|
||||
return
|
||||
if("Nominate Yourself")
|
||||
eminence_nominee = nominee
|
||||
hierophant_message("<span class='brass'><b>[nominee] nominates themselves as the Eminence!</b> You may object by interacting with the eminence spire. The vote will otherwise pass in 30 seconds.</span>")
|
||||
if("Nominate Ghosts")
|
||||
eminence_nominee = "ghosts"
|
||||
hierophant_message("<span class='brass'><b>[nominee] proposes selecting an Eminence from ghosts!</b> You may object by interacting with the eminence spire. The vote will otherwise pass in 30 seconds.</span>")
|
||||
for(var/mob/M in servants_and_ghosts())
|
||||
M.playsound_local(M, 'sound/machines/clockcult/ocularwarden-target.ogg', 50, FALSE)
|
||||
selection_timer = addtimer(CALLBACK(src, .proc/kingmaker), 300, TIMER_STOPPABLE)
|
||||
|
||||
/obj/structure/destructible/clockwork/eminence_spire/proc/objection(mob/living/wright)
|
||||
if(alert(wright, "Object to the selection of [eminence_nominee] as Eminence?", "Objection!", "Object", "Cancel") == "Cancel" || !is_servant_of_ratvar(wright) || !wright.canUseTopic(src) || !eminence_nominee)
|
||||
return
|
||||
hierophant_message("<span class='brass'><b>[wright] objects to the nomination of [eminence_nominee]!</b> The eminence spire has been reset.</span>")
|
||||
for(var/mob/M in servants_and_ghosts())
|
||||
M.playsound_local(M, 'sound/machines/clockcult/integration_cog_install.ogg', 50, FALSE)
|
||||
eminence_nominee = null
|
||||
deltimer(selection_timer)
|
||||
|
||||
/obj/structure/destructible/clockwork/eminence_spire/proc/cancelation(mob/living/cold_feet)
|
||||
if(alert(cold_feet, "Cancel your nomination?", "Cancel Nomination", "Withdraw Nomination", "Cancel") == "Cancel" || !is_servant_of_ratvar(cold_feet) || !cold_feet.canUseTopic(src) || !eminence_nominee)
|
||||
return
|
||||
hierophant_message("<span class='brass'><b>[eminence_nominee] has withdrawn their nomination!</b> The eminence spire has been reset.</span>")
|
||||
for(var/mob/M in servants_and_ghosts())
|
||||
M.playsound_local(M, 'sound/machines/clockcult/integration_cog_install.ogg', 50, FALSE)
|
||||
eminence_nominee = null
|
||||
deltimer(selection_timer)
|
||||
|
||||
/obj/structure/destructible/clockwork/eminence_spire/proc/kingmaker()
|
||||
if(!eminence_nominee)
|
||||
return
|
||||
if(ismob(eminence_nominee))
|
||||
if(!eminence_nominee.client || !eminence_nominee.mind)
|
||||
hierophant_message("<span class='brass'><b>[eminence_nominee] somehow lost their sentience!</b> The eminence spire has been reset.</span>")
|
||||
for(var/mob/M in servants_and_ghosts())
|
||||
M.playsound_local(M, 'sound/machines/clockcult/integration_cog_install.ogg', 50, FALSE)
|
||||
eminence_nominee = null
|
||||
return
|
||||
playsound(eminence_nominee, 'sound/machines/clockcult/ark_damage.ogg', 50, FALSE)
|
||||
eminence_nominee.visible_message("<span class='warning'>A blast of white-hot light flows into [eminence_nominee], vaporizing them in an instant!</span>", \
|
||||
"<span class='userdanger'>allthelightintheuniverseflowing.into.YOU</span>")
|
||||
for(var/obj/item/I in eminence_nominee)
|
||||
eminence_nominee.dropItemToGround(I)
|
||||
var/mob/camera/eminence/eminence = new(get_turf(src))
|
||||
eminence_nominee.mind.transfer_to(eminence)
|
||||
eminence_nominee.dust()
|
||||
hierophant_message("<span class='bold large_brass'>[eminence_nominee] has ascended into the Eminence!</span>")
|
||||
else if(eminence_nominee == "ghosts")
|
||||
kingmaking = TRUE
|
||||
hierophant_message("<span class='brass'><b>The eminence spire is now selecting a ghost to be the Eminence...</b></span>")
|
||||
var/list/candidates = pollGhostCandidates("Would you like to play as the servants' Eminence?", "Servant of Ratvar", null, ROLE_SERVANT_OF_RATVAR, poll_time = 100)
|
||||
kingmaking = FALSE
|
||||
if(!candidates.len)
|
||||
for(var/mob/M in servants_and_ghosts())
|
||||
M.playsound_local(M, 'sound/machines/clockcult/integration_cog_install.ogg', 50, FALSE)
|
||||
hierophant_message("<span class='brass'><b>No ghosts accepted the offer!</b> The eminence spire has been reset.</span>")
|
||||
eminence_nominee = null
|
||||
return
|
||||
visible_message("<span class='warning'>A blast of white-hot light spirals from [src] in waves!</span>")
|
||||
playsound(src, 'sound/machines/clockcult/ark_damage.ogg', 50, FALSE)
|
||||
var/mob/camera/eminence/eminence = new(get_turf(src))
|
||||
eminence_nominee = pick(candidates)
|
||||
eminence.key = eminence_nominee.key
|
||||
hierophant_message("<span class='bold large_brass'>A ghost has ascended into the Eminence!</span>")
|
||||
for(var/mob/M in servants_and_ghosts())
|
||||
M.playsound_local(M, 'sound/machines/clockcult/eminence_selected.ogg', 50, FALSE)
|
||||
eminence_nominee = null
|
||||
@@ -1,109 +0,0 @@
|
||||
//Used to "declare war" against the station. The servants' equipment will be permanently supercharged, and the Ark given extra time to prepare.
|
||||
//This will send an announcement to the station, meaning that they will be warned very early in advance about the impending attack.
|
||||
/obj/structure/destructible/clockwork/heralds_beacon
|
||||
name = "herald's beacon"
|
||||
desc = "An imposing spire formed of brass, with a thrumming gemstone at its peak."
|
||||
clockwork_desc = "A massively-powerful beacon. If enough servants decide to activate it, it will send an incredibly large energy pulse to the Ark, \
|
||||
permanently empowering many clockwork objects and reducing all power costs by 50%, but alerting the crew to your presence. It doesn't have enough \
|
||||
energy to sustain itself for long, and if not activated within five minutes, it will permanently shut down."
|
||||
icon_state = "interdiction_lens"
|
||||
break_message = "<span class='warning'>The beacon crackles with power before collapsing into pieces!</span>"
|
||||
max_integrity = 250
|
||||
light_color = "#EF078E"
|
||||
var/time_remaining = 300 //Amount of seconds left to vote on whether or not to activate the beacon
|
||||
var/list/voters //People who have voted to activate the beacon
|
||||
var/votes_needed = 0 //How many votes are needed to activate the beacon
|
||||
var/available = FALSE //If the beacon can be used
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/Initialize()
|
||||
. = ..()
|
||||
voters = list()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/process()
|
||||
if(!available)
|
||||
if(istype(SSticker.mode, /datum/game_mode/clockwork_cult))
|
||||
available = TRUE
|
||||
else
|
||||
return
|
||||
if(!SSticker.mode.servants_of_ratvar.len)
|
||||
return
|
||||
if(!votes_needed)
|
||||
var/servants = SSticker.mode.servants_of_ratvar.len
|
||||
if(servants)
|
||||
votes_needed = round(servants * 0.66)
|
||||
time_remaining--
|
||||
if(!time_remaining)
|
||||
hierophant_message("<span class='bold sevtug_small'>[src] has lost its power, and can no longer be activated.</span>")
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(isobserver(M) || is_servant_of_ratvar(M))
|
||||
M.playsound_local(M, 'sound/magic/blind.ogg', 50, FALSE)
|
||||
available = FALSE
|
||||
icon_state = "interdiction_lens_unwrenched"
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/examine(mob/user)
|
||||
..()
|
||||
if(isobserver(user) || is_servant_of_ratvar(user))
|
||||
if(!available)
|
||||
if(!GLOB.ratvar_approaches)
|
||||
to_chat(user, "<span class='bold alloy'>It can no longer be activated.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='bold neovgre_small'>It has been activated!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='brass'>There are <b>[time_remaining]</b> second[time_remaining != 1 ? "s" : ""] remaining to vote.</span>")
|
||||
to_chat(user, "<span class='big brass'>There are <b>[voters.len]/[votes_needed]</b> votes to activate the beacon!</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/attack_hand(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='notice'>You can tell how powerful [src] is; you know better than to touch it.</span>")
|
||||
return
|
||||
if(!available)
|
||||
to_chat(user, "<span class='danger'>You can no longer vote with [src].</span>")
|
||||
return
|
||||
var/voting = !(user.key in voters)
|
||||
if(alert(user, "[voting ? "Cast a" : "Undo your"] vote to activate the beacon?", "Herald's Beacon", "Change Vote", "Cancel") == "Cancel")
|
||||
return
|
||||
if(!user.canUseTopic(src) || !is_servant_of_ratvar(user) || !available)
|
||||
return
|
||||
if(voting)
|
||||
if(user.key in voters)
|
||||
return
|
||||
voters += user.key
|
||||
else
|
||||
if(!user.key in voters)
|
||||
return
|
||||
voters -= user.key
|
||||
var/votes_left = votes_needed - voters.len
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] has [voting ? "voted" : "undone their vote"] to activate [src]! [ADMIN_JMP(user)]")
|
||||
hierophant_message("<span class='brass'><b>[user.real_name]</b> has [voting ? "voted" : "undone their vote"] to activate [src]! The beacon needs [votes_left] more votes to activate.")
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(isobserver(M) || is_servant_of_ratvar(M))
|
||||
M.playsound_local(M, 'sound/magic/clockwork/fellowship_armory.ogg', 50, FALSE)
|
||||
if(!votes_left)
|
||||
herald_the_justiciar()
|
||||
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/proc/herald_the_justiciar()
|
||||
priority_announce("A powerful group of fanatical zealots following the cause of Ratvar have brazenly sacrificed stealth for power, and dare anyone \
|
||||
to try and stop them.", title = "The Justiciar Comes", sound = 'sound/magic/clockwork/ark_activation.ogg')
|
||||
GLOB.ratvar_approaches = TRUE
|
||||
available = FALSE
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
icon_state = "interdiction_lens_active"
|
||||
hierophant_message("<span class='big bold brass'>The beacon's activation has given your team great power! Many of your objects are permanently empowered!</span>")
|
||||
for(var/mob/living/simple_animal/hostile/clockwork/C in GLOB.all_clockwork_mobs)
|
||||
if(C.stat == DEAD)
|
||||
continue
|
||||
C.update_values()
|
||||
to_chat(C, C.empower_string)
|
||||
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)
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
|
||||
G.grace_period = FALSE //no grace period if we've declared war
|
||||
G.recalls_remaining++
|
||||
@@ -1,143 +0,0 @@
|
||||
//Interdiction Lens: A powerful artifact that constantly disrupts electronics and drains power but, if it fails to find something to disrupt, turns off.
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens
|
||||
name = "interdiction lens"
|
||||
desc = "An ominous, double-pronged brass totem. There's a strange gemstone clasped between the pincers."
|
||||
clockwork_desc = "A powerful totem that constantly drains nearby electronics and funnels the power drained into nearby Sigils of Transmission or the area's APC."
|
||||
icon_state = "interdiction_lens"
|
||||
construction_value = 20
|
||||
active_icon = "interdiction_lens_active"
|
||||
inactive_icon = "interdiction_lens"
|
||||
unanchored_icon = "interdiction_lens_unwrenched"
|
||||
break_message = "<span class='warning'>The lens flares a blinding violet before the totem beneath it shatters!</span>"
|
||||
break_sound = 'sound/effects/glassbr3.ogg'
|
||||
debris = list(/obj/item/clockwork/alloy_shards/small = 2, \
|
||||
/obj/item/clockwork/alloy_shards/large = 2, \
|
||||
/obj/item/clockwork/component/belligerent_eye/lens_gem = 1)
|
||||
var/recharging = 0 //world.time when the lens was last used
|
||||
var/recharge_time = 1200 //if it drains no power and affects no objects, it turns off for two minutes
|
||||
var/disabled = FALSE //if it's actually usable
|
||||
var/interdiction_range = 14 //how large an area it drains and disables in
|
||||
var/static/list/rage_messages = list("...", "Disgusting.", "Die.", "Foul.", "Worthless.", "Mortal.", "Unfit.", "Weak.", "Fragile.", "Useless.", "Leave my sight!")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/Initialize()
|
||||
. = ..()
|
||||
update_current_glow()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='[recharging > world.time ? "neovgre_small":"brass"]'>Its gemstone [recharging > world.time ? "has been breached by writhing tendrils of blackness that cover the totem" \
|
||||
: "vibrates in place and thrums with power"].</span>")
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='neovgre_small'>If it fails to drain any electronics or has nothing to return power to, it will disable itself for <b>[round(recharge_time/600, 1)]</b> minutes.</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/update_anchored(mob/user, do_damage)
|
||||
..()
|
||||
update_current_glow()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/toggle(fast_process, mob/living/user)
|
||||
. = ..()
|
||||
update_current_glow()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/proc/update_current_glow()
|
||||
if(active)
|
||||
if(disabled)
|
||||
set_light(2, 1.6, "#151200")
|
||||
else
|
||||
set_light(2, 1.6, "#EE54EE")
|
||||
else
|
||||
if(anchored)
|
||||
set_light(1.4, 0.8, "#F42B9D")
|
||||
else
|
||||
set_light(0)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY))
|
||||
if(disabled)
|
||||
to_chat(user, "<span class='warning'>As you place your hand on the gemstone, cold tendrils of black matter crawl up your arm. You quickly pull back.</span>")
|
||||
return 0
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/forced_disable(bad_effects)
|
||||
if(disabled || !anchored)
|
||||
return FALSE
|
||||
if(!active)
|
||||
toggle(0)
|
||||
visible_message("<span class='warning'>The gemstone suddenly turns horribly dark, writhing tendrils covering it!</span>")
|
||||
recharging = world.time + recharge_time
|
||||
flick("interdiction_lens_discharged", src)
|
||||
icon_state = "interdiction_lens_inactive"
|
||||
disabled = TRUE
|
||||
update_current_glow()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/process()
|
||||
. = ..()
|
||||
if(recharging > world.time)
|
||||
return
|
||||
if(disabled)
|
||||
visible_message("<span class='warning'>The writhing tendrils return to the gemstone, which begins to glow with power!</span>")
|
||||
flick("interdiction_lens_recharged", src)
|
||||
disabled = FALSE
|
||||
toggle(0)
|
||||
else
|
||||
if(!check_apc_and_sigils())
|
||||
forced_disable()
|
||||
return
|
||||
var/successfulprocess = FALSE
|
||||
var/power_drained = 0
|
||||
var/list/atoms_to_test = list()
|
||||
for(var/A in spiral_range_turfs(interdiction_range, src))
|
||||
var/turf/T = A
|
||||
for(var/M in T)
|
||||
atoms_to_test |= M
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
var/unconverted_ai = FALSE
|
||||
var/efficiency = get_efficiency_mod()
|
||||
var/rage_modifier = get_efficiency_mod(TRUE)
|
||||
|
||||
for(var/i in GLOB.ai_list)
|
||||
var/mob/living/silicon/ai/AI = i
|
||||
if(AI && AI.stat != DEAD && !is_servant_of_ratvar(AI))
|
||||
unconverted_ai = TRUE
|
||||
|
||||
for(var/M in atoms_to_test)
|
||||
var/atom/movable/A = M
|
||||
if(!A || QDELETED(A) || A == target_apc)
|
||||
continue
|
||||
power_drained += Floor(A.power_drain(TRUE) * efficiency, MIN_CLOCKCULT_POWER)
|
||||
|
||||
if(prob(1 * rage_modifier))
|
||||
to_chat(A, "<span class='neovgre'>\"[text2ratvar(pick(rage_messages))]\"</span>")
|
||||
|
||||
if(prob(100 * (efficiency * efficiency)))
|
||||
if(istype(A, /obj/machinery/camera) && unconverted_ai)
|
||||
var/obj/machinery/camera/C = A
|
||||
if(C.isEmpProof() || !C.status)
|
||||
continue
|
||||
successfulprocess = TRUE
|
||||
if(C.emped)
|
||||
continue
|
||||
C.emp_act(EMP_HEAVY)
|
||||
else if(istype(A, /obj/item/device/radio))
|
||||
var/obj/item/device/radio/O = A
|
||||
successfulprocess = TRUE
|
||||
if(O.emped || !O.on)
|
||||
continue
|
||||
O.emp_act(EMP_HEAVY)
|
||||
else if((isliving(A) && !is_servant_of_ratvar(A)) || istype(A, /obj/structure/closet) || istype(A, /obj/item/storage)) //other things may have radios in them but we don't care
|
||||
for(var/obj/item/device/radio/O in A.GetAllContents())
|
||||
successfulprocess = TRUE
|
||||
if(O.emped || !O.on)
|
||||
continue
|
||||
O.emp_act(EMP_HEAVY)
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
if(power_drained && power_drained >= MIN_CLOCKCULT_POWER && return_power(power_drained))
|
||||
successfulprocess = TRUE
|
||||
playsound(src, 'sound/items/pshoom.ogg', 50 * efficiency, 1, interdiction_range-7, 1)
|
||||
|
||||
if(!successfulprocess)
|
||||
forced_disable()
|
||||
@@ -1,63 +0,0 @@
|
||||
//Mania Motor: A pair of antenna that, while active, cause a variety of negative mental effects in nearby human mobs.
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor
|
||||
name = "mania motor"
|
||||
desc = "A pair of antenna with what appear to be sockets around the base. It reminds you of an antlion."
|
||||
clockwork_desc = "A transmitter that allows Sevtug to whisper into the minds of nearby non-servants, causing a variety of negative mental effects, up to and including conversion."
|
||||
icon_state = "mania_motor_inactive"
|
||||
active_icon = "mania_motor"
|
||||
inactive_icon = "mania_motor_inactive"
|
||||
unanchored_icon = "mania_motor_unwrenched"
|
||||
construction_value = 20
|
||||
break_message = "<span class='warning'>The antenna break off, leaving a pile of shards!</span>"
|
||||
max_integrity = 100
|
||||
light_color = "#AF0AAF"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/large = 2, \
|
||||
/obj/item/clockwork/alloy_shards/small = 2, \
|
||||
/obj/item/clockwork/component/geis_capacitor/antennae = 1)
|
||||
var/mania_cost = 150
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='sevtug_small'>It requires <b>[DisplayPower(mania_cost)]</b> to run.</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/forced_disable(bad_effects)
|
||||
if(active)
|
||||
if(bad_effects)
|
||||
try_use_power(MIN_CLOCKCULT_POWER*4)
|
||||
visible_message("<span class='warning'>[src] hums loudly, then the sockets at its base fall dark!</span>")
|
||||
playsound(src, 'sound/effects/screech.ogg', 40, 1)
|
||||
toggle()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY) && is_servant_of_ratvar(user))
|
||||
if(!can_access_clockwork_power(src, mania_cost))
|
||||
to_chat(user, "<span class='warning'>[src] needs more power to function!</span>")
|
||||
return 0
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/toggle(fast_process, mob/living/user)
|
||||
. = ..()
|
||||
if(active)
|
||||
set_light(2, 0.9)
|
||||
else
|
||||
set_light(0)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/process()
|
||||
if(!try_use_power(mania_cost))
|
||||
forced_disable(FALSE)
|
||||
return
|
||||
var/efficiency = get_efficiency_mod()
|
||||
for(var/mob/living/carbon/human/H in viewers(7, src))
|
||||
if(is_servant_of_ratvar(H))
|
||||
continue
|
||||
var/list/effects = H.has_status_effect_list(STATUS_EFFECT_MANIAMOTOR)
|
||||
var/datum/status_effect/maniamotor/M
|
||||
for(var/datum/status_effect/maniamotor/MM in effects)
|
||||
if(MM.motor == src)
|
||||
M = MM
|
||||
break
|
||||
if(!M)
|
||||
M = H.apply_status_effect(STATUS_EFFECT_MANIAMOTOR, src)
|
||||
M.severity = CLAMP(M.severity + ((11 - get_dist(src, H)) * efficiency * efficiency), 0, MAX_MANIA_SEVERITY)
|
||||
@@ -1,161 +0,0 @@
|
||||
//Ocular warden: Low-damage, low-range turret. Deals constant damage to whoever it makes eye contact with.
|
||||
/obj/structure/destructible/clockwork/ocular_warden
|
||||
name = "ocular warden"
|
||||
desc = "A large brass eye with tendrils trailing below it and a wide red iris."
|
||||
clockwork_desc = "A fragile turret which will automatically attack nearby unrestrained non-Servants that can see it."
|
||||
icon_state = "ocular_warden"
|
||||
unanchored_icon = "ocular_warden_unwrenched"
|
||||
max_integrity = 25
|
||||
construction_value = 15
|
||||
layer = WALL_OBJ_LAYER
|
||||
break_message = "<span class='warning'>The warden's eye gives a glare of utter hate before falling dark!</span>"
|
||||
debris = list(/obj/item/clockwork/component/belligerent_eye/blind_eye = 1)
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/damage_per_tick = 3
|
||||
var/sight_range = 3
|
||||
var/atom/movable/target
|
||||
var/list/idle_messages = list(" sulkily glares around.", " lazily drifts from side to side.", " looks around for something to burn.", " slowly turns in circles.")
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='brass'>[target ? "<b>It's fixated on [target]!</b>" : "Its gaze is wandering aimlessly."]</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/hulk_damage()
|
||||
return 25
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/can_be_unfasten_wrench(mob/user, silent)
|
||||
if(!anchored)
|
||||
for(var/obj/structure/destructible/clockwork/ocular_warden/W in orange(OCULAR_WARDEN_EXCLUSION_RANGE, src))
|
||||
if(W.anchored)
|
||||
if(!silent)
|
||||
to_chat(user, "<span class='neovgre'>You sense another ocular warden too near this location. Activating this one this close would cause them to fight.</span>")
|
||||
return FAILED_UNFASTEN
|
||||
return SUCCESSFUL_UNFASTEN
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/ratvar_act()
|
||||
..()
|
||||
if(GLOB.ratvar_awakens)
|
||||
damage_per_tick = 10
|
||||
sight_range = 6
|
||||
else
|
||||
damage_per_tick = initial(damage_per_tick)
|
||||
sight_range = initial(sight_range)
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/process()
|
||||
if(!anchored)
|
||||
lose_target()
|
||||
return
|
||||
var/list/validtargets = acquire_nearby_targets()
|
||||
if(target)
|
||||
if(!(target in validtargets))
|
||||
lose_target()
|
||||
else
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(!L.null_rod_check())
|
||||
if(isrevenant(L))
|
||||
var/mob/living/simple_animal/revenant/R = L
|
||||
if(R.revealed)
|
||||
R.unreveal_time += 2
|
||||
else
|
||||
R.reveal(10)
|
||||
if(prob(50))
|
||||
L.playsound_local(null,'sound/machines/clockcult/ocularwarden-dot1.ogg',75 * get_efficiency_mod(),1)
|
||||
else
|
||||
L.playsound_local(null,'sound/machines/clockcult/ocularwarden-dot2.ogg',75 * get_efficiency_mod(),1)
|
||||
L.adjustFireLoss((!iscultist(L) ? damage_per_tick : damage_per_tick * 2) * get_efficiency_mod()) //Nar-Sian cultists take additional damage
|
||||
if(GLOB.ratvar_awakens && L)
|
||||
L.adjust_fire_stacks(damage_per_tick)
|
||||
L.IgniteMob()
|
||||
else if(ismecha(target))
|
||||
var/obj/mecha/M = target
|
||||
M.take_damage(damage_per_tick * get_efficiency_mod(), BURN, "melee", 1, get_dir(src, M))
|
||||
|
||||
new /obj/effect/temp_visual/ratvar/ocular_warden(get_turf(target))
|
||||
|
||||
setDir(get_dir(get_turf(src), get_turf(target)))
|
||||
if(!target)
|
||||
if(validtargets.len)
|
||||
target = pick(validtargets)
|
||||
playsound(src,'sound/machines/clockcult/ocularwarden-target.ogg',50,1)
|
||||
visible_message("<span class='warning'>[src] swivels to face [target]!</span>")
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
to_chat(L, "<span class='neovgre'>\"I SEE YOU!\"</span>\n<span class='userdanger'>[src]'s gaze [GLOB.ratvar_awakens ? "melts you alive" : "burns you"]!</span>")
|
||||
else if(ismecha(target))
|
||||
var/obj/mecha/M = target
|
||||
to_chat(M.occupant, "<span class='neovgre'>\"I SEE YOU!\"</span>" )
|
||||
else if(prob(0.5)) //Extremely low chance because of how fast the subsystem it uses processes
|
||||
if(prob(50))
|
||||
visible_message("<span class='notice'>[src][pick(idle_messages)]</span>")
|
||||
else
|
||||
setDir(pick(GLOB.cardinals))//Random rotation
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/proc/acquire_nearby_targets()
|
||||
. = list()
|
||||
for(var/mob/living/L in viewers(sight_range, src)) //Doesn't attack the blind
|
||||
var/obj/item/storage/book/bible/B = L.bible_check()
|
||||
if(B)
|
||||
if(!(B.resistance_flags & ON_FIRE))
|
||||
to_chat(L, "<span class='warning'>Your [B.name] bursts into flames!</span>")
|
||||
for(var/obj/item/storage/book/bible/BI in L.GetAllContents())
|
||||
if(!(BI.resistance_flags & ON_FIRE))
|
||||
BI.fire_act()
|
||||
continue
|
||||
if(is_servant_of_ratvar(L) || (L.has_disability(DISABILITY_BLIND)) || L.null_rod_check())
|
||||
continue
|
||||
if(L.stat || L.restrained() || L.buckled || L.lying)
|
||||
continue
|
||||
if(ishostile(L))
|
||||
var/mob/living/simple_animal/hostile/H = L
|
||||
if(("ratvar" in H.faction) || (!H.mind && "neutral" in H.faction))
|
||||
continue
|
||||
if(ismegafauna(H) || (!H.mind && H.AIStatus == AI_OFF))
|
||||
continue
|
||||
else if(isrevenant(L))
|
||||
var/mob/living/simple_animal/revenant/R = L
|
||||
if(R.stasis) //Don't target any revenants that are respawning
|
||||
continue
|
||||
else if(!L.mind)
|
||||
continue
|
||||
. += L
|
||||
var/list/viewcache = list()
|
||||
for(var/N in GLOB.mechas_list)
|
||||
var/obj/mecha/M = N
|
||||
if(get_dist(M, src) <= sight_range && M.occupant && !is_servant_of_ratvar(M.occupant))
|
||||
if(!length(viewcache))
|
||||
for (var/obj/Z in view(sight_range, src))
|
||||
viewcache += Z
|
||||
if (M in viewcache)
|
||||
. += M
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/proc/lose_target()
|
||||
if(!target)
|
||||
return 0
|
||||
target = null
|
||||
visible_message("<span class='warning'>[src] settles and seems almost disappointed.</span>")
|
||||
return 1
|
||||
|
||||
/obj/structure/destructible/clockwork/ocular_warden/get_efficiency_mod()
|
||||
if(GLOB.ratvar_awakens)
|
||||
return 2
|
||||
. = 1
|
||||
if(target)
|
||||
for(var/turf/T in getline(src, target))
|
||||
if(T.density)
|
||||
. -= 0.1
|
||||
continue
|
||||
for(var/obj/structure/O in T)
|
||||
if(O != src && O.density)
|
||||
. -= 0.1
|
||||
break
|
||||
. -= (get_dist(src, target) * 0.05)
|
||||
. = max(., 0.1) //The lowest damage a warden can do is 10% of its normal amount (0.25 by default)
|
||||
@@ -1,150 +0,0 @@
|
||||
//Ratvar himself. Impossible to damage by most standard means, and converts nearby objects and players into clockwork variants and Servants.
|
||||
/obj/structure/destructible/clockwork/massive/ratvar
|
||||
name = "Ratvar, the Clockwork Justiciar"
|
||||
desc = "..."
|
||||
clockwork_desc = "<span class='large_brass bold italics'>Ratvar, free at last!</span>"
|
||||
icon = 'icons/effects/512x512.dmi'
|
||||
icon_state = "ratvar"
|
||||
pixel_x = -235
|
||||
pixel_y = -248
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
appearance_flags = 0
|
||||
light_power = 0.7
|
||||
light_range = 15
|
||||
light_color = "#BE8700"
|
||||
var/atom/prey //Whatever Ratvar is chasing
|
||||
var/clashing = FALSE //If Ratvar is fighting with Nar-Sie
|
||||
var/convert_range = 10
|
||||
dangerous_possession = TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Initialize()
|
||||
. = ..()
|
||||
GLOB.ratvar_awakens++
|
||||
for(var/obj/O in GLOB.all_clockwork_objects)
|
||||
O.ratvar_act()
|
||||
for(var/mob/living/simple_animal/hostile/clockwork/M in GLOB.all_clockwork_mobs)
|
||||
M.ratvar_act()
|
||||
START_PROCESSING(SSobj, src)
|
||||
send_to_playing_players("<span class='ratvar'>[text2ratvar("ONCE AGAIN MY LIGHT SHINES AMONG THESE PATHETIC STARS")]</span>")
|
||||
sound_to_playing_players('sound/effects/ratvar_reveal.ogg')
|
||||
var/mutable_appearance/alert_overlay = mutable_appearance('icons/effects/clockwork_effects.dmi', "ratvar_alert")
|
||||
notify_ghosts("The Justiciar's light calls to you! Reach out to Ratvar in [get_area_name(src)] to be granted a shell to spread his glory!", null, source = src, alert_overlay = alert_overlay)
|
||||
INVOKE_ASYNC(SSshuttle.emergency, /obj/docking_port/mobile/emergency.proc/request, null, 10, null, FALSE, 0)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Destroy()
|
||||
GLOB.ratvar_awakens--
|
||||
for(var/obj/O in GLOB.all_clockwork_objects)
|
||||
O.ratvar_act()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/attack_ghost(mob/dead/observer/O)
|
||||
var/alertresult = alert(O, "Embrace the Justiciar's light? You can no longer be cloned!",,"Yes", "No")
|
||||
if(alertresult == "No" || QDELETED(O) || !istype(O) || !O.key)
|
||||
return FALSE
|
||||
var/mob/living/simple_animal/drone/cogscarab/ratvar/R = new/mob/living/simple_animal/drone/cogscarab/ratvar(get_turf(src))
|
||||
R.visible_message("<span class='heavy_brass'>[R] forms, and its eyes blink open, glowing bright red!</span>")
|
||||
R.key = O.key
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Collide(atom/A)
|
||||
var/turf/T = get_turf(A)
|
||||
if(T == loc)
|
||||
T = get_step(T, dir) //please don't run into a window like a bird, ratvar
|
||||
forceMove(T)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/Process_Spacemove()
|
||||
return clashing
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/process()
|
||||
if(clashing) //I'm a bit occupied right now, thanks
|
||||
return
|
||||
for(var/I in circlerangeturfs(src, convert_range))
|
||||
var/turf/T = I
|
||||
T.ratvar_act()
|
||||
for(var/I in circleviewturfs(src, round(convert_range * 0.5)))
|
||||
var/turf/T = I
|
||||
T.ratvar_act(TRUE)
|
||||
var/dir_to_step_in = pick(GLOB.cardinals)
|
||||
var/list/meals = list()
|
||||
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)
|
||||
meals = list(GLOB.cult_narsie) //if you're in the way, handy for him, but ratvar only cares about nar-sie!
|
||||
prey = GLOB.cult_narsie
|
||||
if(get_dist(src, prey) <= 10)
|
||||
clash()
|
||||
return
|
||||
if(!prey)
|
||||
if(!prey && LAZYLEN(meals))
|
||||
var/mob/living/L = prey
|
||||
prey = pick(meals)
|
||||
to_chat(prey, "<span class='heavy_brass'><font size=5>\"You will do, heretic.\"</font></span>\n\
|
||||
<span class='userdanger'>You feel something massive turn its crushing focus to you...</span>")
|
||||
L.playsound_local(prey, 'sound/effects/ratvar_reveal.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
else
|
||||
if((!istype(prey, /obj/singularity/narsie) && prob(10) && LAZYLEN(meals) > 1) || prey.z != z || !(prey in meals))
|
||||
if(is_servant_of_ratvar(prey))
|
||||
to_chat(prey, "<span class='heavy_brass'><font size=5>\"Serve me well.\"</font></span>\n\
|
||||
<span class='big_brass'>You feel great joy as your god turns His eye to another heretic...</span>")
|
||||
else
|
||||
to_chat(prey, "<span class='heavy_brass'><font size=5>\"No matter. I will find you later, heretic.\"</font></span>\n\
|
||||
<span class='userdanger'>You feel tremendous relief as the crushing focus relents...</span>")
|
||||
prey = null
|
||||
else
|
||||
dir_to_step_in = get_dir(src, prey) //Unlike Nar-Sie, Ratvar ruthlessly chases down his target
|
||||
step(src, dir_to_step_in)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/proc/clash()
|
||||
if(clashing || prey != GLOB.cult_narsie)
|
||||
return
|
||||
clashing = TRUE
|
||||
GLOB.cult_narsie.clashing = TRUE
|
||||
to_chat(world, "<span class='bold brass'><font size=5>\"YOU.\"</font></span>")
|
||||
to_chat(world, "<span class='bold cult'><font size=5>\"Ratvar?!\"</font></span>")
|
||||
clash_of_the_titans(GLOB.cult_narsie) // >:(
|
||||
return TRUE
|
||||
|
||||
//Put me in Reebe, will you? Ratvar has found and is going to do a hecking murder on Nar-Sie
|
||||
/obj/structure/destructible/clockwork/massive/ratvar/proc/clash_of_the_titans(obj/singularity/narsie/narsie)
|
||||
var/winner = "Undeclared"
|
||||
var/base_victory_chance = 1
|
||||
while(src && narsie)
|
||||
sound_to_playing_players('sound/magic/clockwork/ratvar_attack.ogg')
|
||||
sleep(5.2)
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
if(!isnewplayer(M))
|
||||
flash_color(M, flash_color="#966400", flash_time=1)
|
||||
shake_camera(M, 4, 3)
|
||||
var/ratvar_chance = min(LAZYLEN(SSticker.mode.servants_of_ratvar), 50)
|
||||
var/narsie_chance = min(LAZYLEN(SSticker.mode.cult), 50)
|
||||
ratvar_chance = rand(base_victory_chance, ratvar_chance)
|
||||
narsie_chance = rand(base_victory_chance, narsie_chance)
|
||||
if(ratvar_chance > narsie_chance)
|
||||
winner = "Ratvar"
|
||||
break
|
||||
sleep(rand(2,5))
|
||||
sound_to_playing_players('sound/magic/clockwork/narsie_attack.ogg')
|
||||
sleep(7.4)
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
if(!isnewplayer(M))
|
||||
flash_color(M, flash_color="#C80000", flash_time=1)
|
||||
shake_camera(M, 4, 3)
|
||||
if(narsie_chance > ratvar_chance)
|
||||
winner = "Nar-Sie"
|
||||
break
|
||||
base_victory_chance *= 2 //The clash has a higher chance of resolving each time both gods attack one another
|
||||
switch(winner)
|
||||
if("Ratvar")
|
||||
send_to_playing_players("<span class='heavy_brass'><font size=5>\"[pick("DIE.", "ROT.")]\"</font></span>\n\
|
||||
<span class='cult'><font size=5>\"<b>[pick("Nooooo...", "Not die. To y-", "Die. Ratv-", "Sas tyen re-")]\"</b></font></span>") //nar-sie get out
|
||||
sound_to_playing_players('sound/magic/clockwork/anima_fragment_attack.ogg')
|
||||
sound_to_playing_players('sound/magic/demon_dies.ogg', 50)
|
||||
clashing = FALSE
|
||||
qdel(narsie)
|
||||
if("Nar-Sie")
|
||||
send_to_playing_players("<span class='cult'><font size=5>\"<b>[pick("Ha.", "Ra'sha fonn dest.", "You fool. To come here.")]</b>\"</font></span>") //Broken English
|
||||
sound_to_playing_players('sound/magic/demon_attack1.ogg')
|
||||
sound_to_playing_players('sound/magic/clockwork/anima_fragment_death.ogg', 62)
|
||||
narsie.clashing = FALSE
|
||||
qdel(src)
|
||||
@@ -1,70 +0,0 @@
|
||||
#define STARGAZER_RANGE 3 //How many tiles the stargazer can see out to
|
||||
#define STARGAZER_POWER 20 //How many watts will be produced per second when the stargazer sees starlight
|
||||
|
||||
//Stargazer: A very fragile but cheap generator that creates power from starlight.
|
||||
/obj/structure/destructible/clockwork/stargazer
|
||||
name = "stargazer"
|
||||
desc = "A large lantern-shaped machine made of thin brass. It looks fragile."
|
||||
clockwork_desc = "A lantern-shaped generator that produces power when near starlight."
|
||||
icon_state = "stargazer"
|
||||
unanchored_icon = "stargazer_unwrenched"
|
||||
max_integrity = 40
|
||||
construction_value = 5
|
||||
layer = WALL_OBJ_LAYER
|
||||
break_message = "<span class='warning'>The stargazer's fragile body shatters into pieces!</span>"
|
||||
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
light_color = "#DAAA18"
|
||||
var/star_light_star_bright = FALSE //If this stargazer can see starlight
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='nzcrentr_small'>Generates <b>[DisplayPower(STARGAZER_POWER)]</b> per second while viewing starlight within [STARGAZER_RANGE] tiles.</span>")
|
||||
if(star_light_star_bright)
|
||||
to_chat(user, "[is_servant_of_ratvar(user) ? "<span class='nzcrentr_small'>It can see starlight!</span>" : "It's shining brilliantly!"]")
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/process()
|
||||
star_light_star_bright = check_starlight()
|
||||
if(star_light_star_bright)
|
||||
adjust_clockwork_power(STARGAZER_POWER)
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/update_anchored(mob/living/user, damage)
|
||||
. = ..()
|
||||
star_light_star_bright = check_starlight()
|
||||
|
||||
/obj/structure/destructible/clockwork/stargazer/proc/check_starlight()
|
||||
var/old_status = star_light_star_bright
|
||||
var/has_starlight
|
||||
if(!anchored)
|
||||
has_starlight = FALSE
|
||||
else
|
||||
for(var/turf/T in view(3, src))
|
||||
if(isspaceturf(T))
|
||||
has_starlight = TRUE
|
||||
break
|
||||
if(has_starlight && anchored)
|
||||
var/area/A = get_area(src)
|
||||
if(A.outdoors || A.map_name == "Space" || !A.blob_allowed)
|
||||
has_starlight = FALSE
|
||||
if(old_status != has_starlight)
|
||||
if(has_starlight)
|
||||
visible_message("<span class='nzcrentr_small'>[src] hums and shines brilliantly!</span>")
|
||||
playsound(src, 'sound/machines/clockcult/stargazer_activate.ogg', 50, TRUE)
|
||||
add_overlay("stargazer_light")
|
||||
set_light(1.5, 5)
|
||||
else
|
||||
if(anchored) //We lost visibility somehow
|
||||
visible_message("<span class='danger'>[src] flickers, and falls dark.</span>")
|
||||
else
|
||||
visible_message("<span class='danger'>[src] whooshes quietly as it slides into a less bulky form.</span>")
|
||||
cut_overlays()
|
||||
set_light(0)
|
||||
return has_starlight
|
||||
@@ -1,61 +0,0 @@
|
||||
//Used by the Taunting Tirade scripture as a trail.
|
||||
/obj/structure/destructible/clockwork/taunting_trail
|
||||
name = "strange smoke"
|
||||
desc = "A cloud of purple smoke."
|
||||
clockwork_desc = "A cloud of purple smoke that confuses and knocks down non-Servants that enter it."
|
||||
gender = PLURAL
|
||||
max_integrity = 5
|
||||
density = TRUE
|
||||
color = list("#AF0AAF", "#AF0AAF", "#AF0AAF", rgb(0,0,0))
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "smoke"
|
||||
break_message = null
|
||||
break_sound = 'sound/magic/teleport_app.ogg'
|
||||
debris = list()
|
||||
var/timerid
|
||||
|
||||
/obj/structure/destructible/clockwork/taunting_trail/Initialize()
|
||||
. = ..()
|
||||
timerid = QDEL_IN(src, 15)
|
||||
var/obj/structure/destructible/clockwork/taunting_trail/Tt = locate(/obj/structure/destructible/clockwork/taunting_trail) in loc
|
||||
if(Tt && Tt != src)
|
||||
if(!step(src, pick(GLOB.alldirs)))
|
||||
qdel(Tt)
|
||||
else
|
||||
for(var/obj/structure/destructible/clockwork/taunting_trail/TT in loc)
|
||||
if(TT != src)
|
||||
qdel(TT)
|
||||
setDir(pick(GLOB.cardinals))
|
||||
transform = matrix()*1.3
|
||||
animate(src, alpha = 100, time = 15)
|
||||
|
||||
/obj/structure/destructible/clockwork/taunting_trail/Destroy()
|
||||
deltimer(timerid)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/taunting_trail/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
playsound(src, 'sound/items/welder.ogg', 50, 1)
|
||||
|
||||
/obj/structure/destructible/clockwork/taunting_trail/CanPass(atom/movable/mover, turf/target)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/taunting_trail/Crossed(atom/movable/AM)
|
||||
affect_mob(AM)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/taunting_trail/CollidedWith(atom/movable/AM)
|
||||
affect_mob(AM)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/taunting_trail/Collide(atom/movable/AM)
|
||||
affect_mob(AM)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/taunting_trail/proc/affect_mob(mob/living/L)
|
||||
if(istype(L) && !is_servant_of_ratvar(L))
|
||||
if(!L.null_rod_check())
|
||||
L.confused = min(L.confused + 15, 50)
|
||||
L.dizziness = min(L.dizziness + 15, 50)
|
||||
if(L.confused >= 25)
|
||||
L.Knockdown(FLOOR(L.confused * 0.8, 1))
|
||||
take_damage(max_integrity)
|
||||
@@ -1,116 +0,0 @@
|
||||
//Tinkerer's cache: Stores components for later use.
|
||||
/obj/structure/destructible/clockwork/cache
|
||||
name = "tinkerer's cache"
|
||||
desc = "A large brass spire with a flaming hole in its center."
|
||||
clockwork_desc = "A brass container capable of storing a large amount of components.\n\
|
||||
Shares components with all other caches and will gradually generate components if near a Clockwork Wall."
|
||||
icon_state = "tinkerers_cache"
|
||||
unanchored_icon = "tinkerers_cache_unwrenched"
|
||||
construction_value = 10
|
||||
break_message = "<span class='warning'>The cache's fire winks out before it falls in on itself!</span>"
|
||||
max_integrity = 80
|
||||
light_color = "#C2852F"
|
||||
var/wall_generation_cooldown
|
||||
var/turf/closed/wall/clockwork/linkedwall //if we've got a linked wall and are producing
|
||||
var/static/linked_caches = 0 //how many caches are linked to walls; affects how fast components are produced
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
GLOB.clockwork_caches++
|
||||
update_slab_info()
|
||||
set_light(2, 0.7)
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/Destroy()
|
||||
GLOB.clockwork_caches--
|
||||
update_slab_info()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(linkedwall)
|
||||
linked_caches--
|
||||
linkedwall.linkedcache = null
|
||||
linkedwall = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/process()
|
||||
if(!anchored)
|
||||
if(linkedwall)
|
||||
linked_caches--
|
||||
linkedwall.linkedcache = null
|
||||
linkedwall = null
|
||||
return
|
||||
for(var/turf/closed/wall/clockwork/C in range(4, src))
|
||||
if(!C.linkedcache && !linkedwall)
|
||||
linked_caches++
|
||||
C.linkedcache = src
|
||||
linkedwall = C
|
||||
wall_generation_cooldown = world.time + get_production_time()
|
||||
visible_message("<span class='warning'>[src] starts to whirr in the presence of [C]...</span>")
|
||||
break
|
||||
if(linkedwall && wall_generation_cooldown <= world.time)
|
||||
wall_generation_cooldown = world.time + get_production_time()
|
||||
var/component_id = generate_cache_component(null, src)
|
||||
playsound(linkedwall, 'sound/magic/clockwork/fellowship_armory.ogg', rand(15, 20), 1, -3, 1, 1)
|
||||
visible_message("<span class='[get_component_span(component_id)]'>Something</span><span class='warning'> cl[pick("ank", "ink", "unk", "ang")]s around inside of [src]...</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/attackby(obj/item/I, mob/living/user, params)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return ..()
|
||||
if(istype(I, /obj/item/clockwork/component))
|
||||
var/obj/item/clockwork/component/C = I
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='warning'>[src] needs to be secured to place [C] into it!</span>")
|
||||
else
|
||||
GLOB.clockwork_component_cache[C.component_id]++
|
||||
update_slab_info()
|
||||
to_chat(user, "<span class='notice'>You add [C] to [src].</span>")
|
||||
user.drop_item()
|
||||
qdel(C)
|
||||
return 1
|
||||
else if(istype(I, /obj/item/clockwork/slab))
|
||||
var/obj/item/clockwork/slab/S = I
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='warning'>[src] needs to be secured to offload your slab's components into it!</span>")
|
||||
else
|
||||
for(var/i in S.stored_components)
|
||||
GLOB.clockwork_component_cache[i] += S.stored_components[i]
|
||||
S.stored_components[i] = 0
|
||||
update_slab_info()
|
||||
user.visible_message("<span class='notice'>[user] empties [S] into [src].</span>", "<span class='notice'>You offload your slab's components into [src].</span>")
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/update_anchored(mob/user, do_damage)
|
||||
..()
|
||||
if(anchored)
|
||||
set_light(2, 0.7)
|
||||
else
|
||||
set_light(0)
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/attack_hand(mob/living/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user))
|
||||
if(linkedwall)
|
||||
if(wall_generation_cooldown > world.time)
|
||||
var/temp_time = (wall_generation_cooldown - world.time) * 0.1
|
||||
to_chat(user, "<span class='alloy'>[src] will produce a component in <b>[temp_time]</b> second[temp_time == 1 ? "":"s"].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='brass'>[src] is about to produce a component!</span>")
|
||||
else if(anchored)
|
||||
to_chat(user, "<span class='alloy'>[src] is unlinked! Construct a Clockwork Wall nearby to generate components!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='alloy'>[src] needs to be secured to generate components!</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(linkedwall)
|
||||
to_chat(user, "<span class='brass'>It is linked to a Clockwork Wall and will generate a component every <b>[DisplayTimeText(get_production_time())]</b>!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='alloy'>It is unlinked! Construct a Clockwork Wall nearby to generate components!</span>")
|
||||
to_chat(user, "<b>Stored components:</b>")
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
to_chat(user, "[get_component_icon(i)] <span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[GLOB.clockwork_component_cache[i]]</b></span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/proc/get_production_time()
|
||||
return (CACHE_PRODUCTION_TIME + (ACTIVE_CACHE_SLOWDOWN * linked_caches)) * get_efficiency_mod(TRUE)
|
||||
@@ -1,14 +0,0 @@
|
||||
//Lever: Do I really need to explain this?
|
||||
/obj/structure/destructible/clockwork/trap/trigger/lever
|
||||
name = "lever"
|
||||
desc = "A fancy lever made of wood and capped with brass."
|
||||
clockwork_desc = "A fancy lever.that activates when pulled."
|
||||
max_integrity = 75
|
||||
icon_state = "lever"
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/trigger/lever/attack_hand(mob/living/user)
|
||||
user.visible_message("<span class='notice'>[user] pulls [src]!</span>", "<span class='notice'>You pull [src]. It clicks, then lifts back upwards.</span>")
|
||||
if(wired_to.len)
|
||||
audible_message("<i>You hear gears clanking.</i>")
|
||||
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
activate()
|
||||
@@ -1,26 +0,0 @@
|
||||
//Pressure sensor: Activates when stepped on.
|
||||
/obj/structure/destructible/clockwork/trap/trigger/pressure_sensor
|
||||
name = "pressure sensor"
|
||||
desc = "A thin plate of brass, barely visible but clearly distinct."
|
||||
clockwork_desc = "A trigger that will activate when a non-servant runs across it."
|
||||
max_integrity = 5
|
||||
icon_state = "pressure_sensor"
|
||||
alpha = 80
|
||||
layer = LOW_ITEM_LAYER
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/trigger/Initialize()
|
||||
. = ..()
|
||||
for(var/obj/structure/destructible/clockwork/trap/T in get_turf(src))
|
||||
if(!istype(T, /obj/structure/destructible/clockwork/trap/trigger))
|
||||
wired_to += T
|
||||
T.wired_to += src
|
||||
to_chat(usr, "<span class='alloy'>[src] automatically links with [T] beneath it.</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/trigger/pressure_sensor/Crossed(atom/movable/AM)
|
||||
if(isliving(AM) && !is_servant_of_ratvar(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.stat || L.m_intent == MOVE_INTENT_WALK || L.lying)
|
||||
return
|
||||
audible_message("<i>*click*</i>")
|
||||
playsound(src, 'sound/items/screwdriver2.ogg', 50, TRUE)
|
||||
activate()
|
||||
@@ -1,27 +0,0 @@
|
||||
//Repeater: Activates every second.
|
||||
/obj/structure/destructible/clockwork/trap/trigger/repeater
|
||||
name = "repeater"
|
||||
desc = "A small black prism with a gem in the center."
|
||||
clockwork_desc = "A repeater that will send an activation signal every second."
|
||||
max_integrity = 15 //Fragile!
|
||||
icon_state = "repeater"
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/trigger/repeater/attack_hand(mob/living/user)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return
|
||||
if(!isprocessing)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
to_chat(user, "<span class='notice'>You activate [src].</span>")
|
||||
icon_state = "[icon_state]_on"
|
||||
else
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
to_chat(user, "<span class='notice'>You halt [src]'s ticking.</span>")
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/trigger/repeater/process()
|
||||
activate()
|
||||
playsound(src, 'sound/items/screwdriver2.ogg', 25, FALSE)
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/trigger/repeater/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
return ..()
|
||||
@@ -1,115 +0,0 @@
|
||||
//Non-servants standing over this will get spikes through the feet, immobilizing them until they're freed.
|
||||
/obj/structure/destructible/clockwork/trap/brass_skewer
|
||||
name = "brass skewer"
|
||||
desc = "A deadly brass spike, cleverly concealed in the floor. You think you should be safe if you disarm whatever's meant to set it off."
|
||||
clockwork_desc = "A barbaric but undeniably effective weapon: a spear through the chest. It immobilizes anyone unlucky enough to step on it and keeps them in place until they get help.."
|
||||
icon_state = "brass_skewer"
|
||||
break_message = "<span class='warning'>The skewer snaps in two!</span>"
|
||||
max_integrity = 40
|
||||
density = FALSE
|
||||
can_buckle = TRUE
|
||||
buckle_prevents_pull = TRUE
|
||||
buckle_lying = FALSE
|
||||
var/wiggle_wiggle
|
||||
var/mutable_appearance/impale_overlay //This is applied to any mob impaled so that they visibly have the skewer coming through their chest
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/brass_skewer/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/brass_skewer/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
if(buckled_mobs && LAZYLEN(buckled_mobs))
|
||||
var/mob/living/L = buckled_mobs[1]
|
||||
if(iscarbon(L))
|
||||
L.Knockdown(100)
|
||||
L.visible_message("<span class='warning'>[L] is maimed as the skewer shatters while still in their body!</span>")
|
||||
L.adjustBruteLoss(15)
|
||||
unbuckle_mob(L)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/brass_skewer/process()
|
||||
if(density)
|
||||
if(buckled_mobs && LAZYLEN(buckled_mobs))
|
||||
var/mob/living/spitroast = buckled_mobs[1]
|
||||
spitroast.adjustBruteLoss(0.1)
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/attackby(obj/item/I, mob/living/user, params)
|
||||
if(buckled_mobs && (user in buckled_mobs))
|
||||
to_chat(user, "<span class='warning'>You can't reach!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/brass_skewer/bullet_act(obj/item/projectile/P)
|
||||
if(buckled_mobs && LAZYLEN(buckled_mobs))
|
||||
var/mob/living/L = buckled_mobs[1]
|
||||
return L.bullet_act(P)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/brass_skewer/activate()
|
||||
if(density)
|
||||
return
|
||||
var/mob/living/squirrel = locate() in get_turf(src)
|
||||
if(squirrel)
|
||||
if(iscyborg(squirrel))
|
||||
if(!squirrel.stat)
|
||||
squirrel.visible_message("<span class='boldwarning'>A massive brass spike erupts from the ground, rending [squirrel]'s chassis but shattering into pieces!</span>", \
|
||||
"<span class='userdanger'>A massive brass spike rips through your chassis and bursts into shrapnel in your casing!</span>")
|
||||
squirrel.adjustBruteLoss(50)
|
||||
squirrel.Stun(20)
|
||||
addtimer(CALLBACK(src, .proc/take_damage, max_integrity), 1)
|
||||
else
|
||||
squirrel.visible_message("<span class='boldwarning'>A massive brass spike erupts from the ground, impaling [squirrel]!</span>", \
|
||||
"<span class='userdanger'>A massive brass spike rams through your chest, hoisting you into the air!</span>")
|
||||
squirrel.emote("scream")
|
||||
playsound(squirrel, 'sound/effects/splat.ogg', 50, TRUE)
|
||||
playsound(squirrel, 'sound/misc/desceration-03.ogg', 50, TRUE)
|
||||
squirrel.apply_damage(20, BRUTE, "chest")
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE //So players can interact with the tile it's on to pull them off
|
||||
buckle_mob(squirrel, TRUE)
|
||||
else
|
||||
visible_message("<span class='danger'>A massive brass spike erupts from the ground!</span>")
|
||||
playsound(src, 'sound/machines/clockcult/brass_skewer.ogg', 75, FALSE)
|
||||
icon_state = "[initial(icon_state)]_extended"
|
||||
density = TRUE //Skewers are one-use only
|
||||
desc = "A vicious brass spike protruding from the ground like a stala[pick("gm", "ct")]ite. It makes you sick to look at." //is stalagmite the ground one? or the ceiling one? who can ever remember?
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/brass_skewer/user_buckle_mob()
|
||||
return
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/brass_skewer/post_buckle_mob(mob/living/L)
|
||||
if(L in buckled_mobs)
|
||||
L.pixel_y = 3
|
||||
impale_overlay = mutable_appearance('icons/obj/clockwork_objects.dmi', "brass_skewer_pokeybit", ABOVE_MOB_LAYER)
|
||||
add_overlay(impale_overlay)
|
||||
else
|
||||
L.pixel_y = initial(L.pixel_y)
|
||||
L.cut_overlay(impale_overlay)
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/brass_skewer/user_unbuckle_mob(mob/living/skewee, mob/living/user)
|
||||
if(user == skewee)
|
||||
if(wiggle_wiggle)
|
||||
return
|
||||
user.visible_message("<span class='warning'>[user] starts wriggling off of [src]!</span>", \
|
||||
"<span class='danger'>You start agonizingly working your way off of [src]...</span>")
|
||||
wiggle_wiggle = TRUE
|
||||
if(!do_after(user, 300, target = user))
|
||||
user.visible_message("<span class='warning'>[user] slides back down [src]!</span>")
|
||||
user.emote("scream")
|
||||
user.apply_damage(10, BRUTE, "chest")
|
||||
playsound(user, 'sound/misc/desceration-03.ogg', 50, TRUE)
|
||||
wiggle_wiggle = FALSE
|
||||
return
|
||||
wiggle_wiggle = FALSE
|
||||
else
|
||||
user.visible_message("<span class='danger'>[user] starts tenderly lifting [skewee] off of [src]...</span>", \
|
||||
"<span class='danger'>You start tenderly lifting [skewee] off of [src]...</span>")
|
||||
if(!do_after(user, 60, target = skewee))
|
||||
skewee.visible_message("<span class='warning'>[skewee] painfully slides back down [src].</span>")
|
||||
skewee.emote("moan")
|
||||
return
|
||||
skewee.visible_message("<span class='danger'>[skewee] comes free of [src] with a squelching pop!</span>", \
|
||||
"<span class='boldannounce'>You come free of [src]!</span>")
|
||||
skewee.Knockdown(30)
|
||||
playsound(skewee, 'sound/misc/desceration-03.ogg', 50, TRUE)
|
||||
unbuckle_mob(skewee)
|
||||
@@ -1,23 +0,0 @@
|
||||
//This doesn't function like a "trap" in of itself, but obscures vision when active.
|
||||
/obj/structure/destructible/clockwork/trap/steam_vent
|
||||
name = "steam vent"
|
||||
desc = "Some wired slats embedded in the floor. They feel warm to the touch."
|
||||
icon_state = "steam_vent_0"
|
||||
clockwork_desc = "When active, these vents will billow out clouds of excess steam from Reebe, obscuring vision."
|
||||
break_message = "<span class='warning'>The vent snaps and collapses!</span>"
|
||||
max_integrity = 100
|
||||
density = FALSE
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/steam_vent/activate()
|
||||
opacity = !opacity
|
||||
icon_state = "steam_vent_[opacity]"
|
||||
if(opacity)
|
||||
playsound(src, 'sound/machines/clockcult/steam_whoosh.ogg', 50, TRUE)
|
||||
|
||||
else
|
||||
playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE)
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/steam_vent/Crossed(atom/movable/AM)
|
||||
if(isliving(AM) && opacity)
|
||||
var/mob/living/L = AM
|
||||
L.adjust_fire_stacks(-1) //It's wet!
|
||||
@@ -1,75 +0,0 @@
|
||||
//A massive gear, effectively a girder for clocks.
|
||||
/obj/structure/destructible/clockwork/wall_gear
|
||||
name = "massive gear"
|
||||
icon_state = "wall_gear"
|
||||
unanchored_icon = "wall_gear"
|
||||
climbable = TRUE
|
||||
max_integrity = 100
|
||||
layer = BELOW_OBJ_LAYER
|
||||
construction_value = 3
|
||||
desc = "A massive brass gear. You could probably secure or unsecure it with a wrench, or just climb over it."
|
||||
break_message = "<span class='warning'>The gear breaks apart into shards of alloy!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/large = 1, \
|
||||
/obj/item/clockwork/alloy_shards/medium = 4, \
|
||||
/obj/item/clockwork/alloy_shards/small = 2) //slightly more debris than the default, totals 26 alloy
|
||||
|
||||
/obj/structure/destructible/clockwork/wall_gear/displaced
|
||||
anchored = FALSE
|
||||
|
||||
/obj/structure/destructible/clockwork/wall_gear/Initialize()
|
||||
. = ..()
|
||||
new /obj/effect/temp_visual/ratvar/gear(get_turf(src))
|
||||
|
||||
/obj/structure/destructible/clockwork/wall_gear/emp_act(severity)
|
||||
return
|
||||
|
||||
/obj/structure/destructible/clockwork/wall_gear/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/wrench))
|
||||
default_unfasten_wrench(user, I, 10)
|
||||
return 1
|
||||
else if(istype(I, /obj/item/screwdriver))
|
||||
if(anchored)
|
||||
to_chat(user, "<span class='warning'>[src] needs to be unsecured to disassemble it!</span>")
|
||||
else
|
||||
playsound(src, I.usesound, 100, 1)
|
||||
user.visible_message("<span class='warning'>[user] starts to disassemble [src].</span>", "<span class='notice'>You start to disassemble [src]...</span>")
|
||||
if(do_after(user, 30*I.toolspeed, target = src) && !anchored)
|
||||
to_chat(user, "<span class='notice'>You disassemble [src].</span>")
|
||||
deconstruct(TRUE)
|
||||
return 1
|
||||
else if(istype(I, /obj/item/stack/tile/brass))
|
||||
var/obj/item/stack/tile/brass/W = I
|
||||
if(W.get_amount() < 1)
|
||||
to_chat(user, "<span class='warning'>You need one brass sheet to do this!</span>")
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(iswallturf(T))
|
||||
to_chat(user, "<span class='warning'>There is already a wall present!</span>")
|
||||
return
|
||||
if(!isfloorturf(T))
|
||||
to_chat(user, "<span class='warning'>A floor must be present to build a [anchored ? "false ":""]wall!</span>")
|
||||
return
|
||||
if(locate(/obj/structure/falsewall) in T.contents)
|
||||
to_chat(user, "<span class='warning'>There is already a false wall present!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You start adding [W] to [src]...</span>")
|
||||
if(do_after(user, 20, target = src))
|
||||
var/brass_floor = FALSE
|
||||
if(istype(T, /turf/open/floor/clockwork)) //if the floor is already brass, costs less to make(conservation of masssssss)
|
||||
brass_floor = TRUE
|
||||
if(W.use(2 - brass_floor))
|
||||
if(anchored)
|
||||
T.PlaceOnTop(/turf/closed/wall/clockwork)
|
||||
else
|
||||
T.PlaceOnTop(/turf/open/floor/clockwork)
|
||||
new /obj/structure/falsewall/brass(T)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need more brass to make a [anchored ? "false ":""]wall!</span>")
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/wall_gear/deconstruct(disassembled = TRUE)
|
||||
if(!(flags_1 & NODECONSTRUCT_1) && disassembled)
|
||||
new /obj/item/stack/tile/brass(loc, 3)
|
||||
return ..()
|
||||
@@ -1,397 +0,0 @@
|
||||
// Contains cult communion, guide, and cult master abilities
|
||||
#define MARK_COOLDOWN
|
||||
|
||||
/datum/action/innate/cult
|
||||
icon_icon = 'icons/mob/actions/actions_cult.dmi'
|
||||
background_icon_state = "bg_demon"
|
||||
buttontooltipstyle = "cult"
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
|
||||
/datum/action/innate/cult/IsAvailable()
|
||||
if(!iscultist(owner))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/cult/comm
|
||||
name = "Communion"
|
||||
button_icon_state = "cult_comms"
|
||||
|
||||
/datum/action/innate/cult/comm/Activate()
|
||||
var/input = stripped_input(usr, "Please choose a message to tell to the other acolytes.", "Voice of Blood", "")
|
||||
if(!input || !IsAvailable())
|
||||
return
|
||||
|
||||
cultist_commune(usr, input)
|
||||
|
||||
/proc/cultist_commune(mob/living/user, message)
|
||||
var/my_message
|
||||
if(!message)
|
||||
return
|
||||
user.whisper("O bidai nabora se[pick("'","`")]sma!", language = /datum/language/common)
|
||||
user.whisper(html_decode(message))
|
||||
var/title = "Acolyte"
|
||||
var/span = "cult italic"
|
||||
if(user.mind && user.mind.has_antag_datum(/datum/antagonist/cult/master))
|
||||
span = "cultlarge"
|
||||
if(ishuman(user))
|
||||
title = "Master"
|
||||
else
|
||||
title = "Lord"
|
||||
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/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)
|
||||
var/link = FOLLOW_LINK(M, user)
|
||||
to_chat(M, "[link] [my_message]")
|
||||
|
||||
log_talk(user,"CULT:[key_name(user)] : [message]",LOGSAY)
|
||||
|
||||
/mob/living/proc/cult_help()
|
||||
set category = "Cultist"
|
||||
set name = "How to Play Cult"
|
||||
var/text = ""
|
||||
text += "<center><font color='red' size=3><b><i>Tenets of the Dark One</i></b></font></center><br><br><br>"
|
||||
|
||||
text += "<font color='red'><b>I. SECRECY</b></font><br>Your cult is a SECRET organization. Your success DEPENDS on keeping your cult's members and locations SECRET for as long as possible. This means that your tome should be hidden \
|
||||
in your bag and never brought out in public. You should never create runes where other crew might find them, and you should avoid using talismans or other cult magic with witnesses around.<br><br>"
|
||||
|
||||
text += "<font color='red'><b>II. TOME</b></font><br>You start with a unique talisman in your bag. This supply talisman can be used 3 times, and creates starter equipment for your cult. The most critical of the talisman's functions is \
|
||||
the power to create a tome. This tome is your most important item and summoning one (in secret) is your FIRST PRIORITY. It lets you talk to fellow cultists and create runes, which in turn is essential to growing the cult's power.<br><br>"
|
||||
|
||||
text += "<font color='red'><b>III. RUNES</b></font><br>Runes are powerful sources of cult magic. Your tome will allow you to draw runes with your blood. Those runes, when hit with an empty hand, will attempt to \
|
||||
trigger the rune's magic. Runes are essential for the cult to convert new members, create powerful minions, or call upon incredibly powerful magic. Some runes require more than one cultist to use.<br><br>"
|
||||
|
||||
text += "<font color='red'><b>IV. TALISMANS</b></font><br>Talismans are a mobile source of cult magic that are NECESSARY to achieve success as a cult. Your starting talisman can produce certain talismans, but you will need \
|
||||
to use the -create talisman- rune (with ordinary paper on top) to get more talismans. Talismans are EXTREMELY powerful, therefore creating more talismans in a HIDDEN location should be one of your TOP PRIORITIES.<br><br>"
|
||||
|
||||
text += "<font color='red'><b>V. GROW THE CULT</b></font><br>There are certain basic strategies that all cultists should master. STUN talismans are the foundation of a successful cult. If you intend to convert the stunned person \
|
||||
you should use cuffs or a talisman of shackling on them and remove their headset before they recover (it takes about 10 seconds to recover). If you intend to sacrifice the victim, striking them quickly and repeatedly with your tome \
|
||||
will knock them out before they can recover. Sacrificed victims will their soul behind in a shard, these shards can be used on construct shells to make powerful servants for the cult. Remember you need TWO cultists standing near a \
|
||||
conversion rune to convert someone. Your construct minions cannot trigger most runes, but they will count as cultists in helping you trigger more powerful runes like conversion or blood boil.<br><br>"
|
||||
|
||||
text += "<font color='red'><b>VI. VICTORY</b></font><br>You have two ultimate goals as a cultist, sacrifice your target, and summon Nar-Sie. Sacrificing the target involves killing that individual and then placing \
|
||||
their corpse on a sacrifice rune and triggering that rune with THREE cultists. Do NOT lose the target's corpse! Only once the target is sacrificed can Nar-Sie be summoned. Summoning Nar-Sie will take nearly one minute \
|
||||
just to draw the massive rune needed. Do not create the rune until your cult is ready, the crew will receive the NAME and LOCATION of anyone who attempts to create the Nar-Sie rune. Once the Nar-Sie rune is drawn \
|
||||
you must gathered 9 cultists (or constructs) over the rune and then click it to bring the Dark One into this world!<br><br>"
|
||||
|
||||
var/datum/browser/popup = new(usr, "mind", "", 800, 600)
|
||||
popup.set_content(text)
|
||||
popup.open()
|
||||
return 1
|
||||
|
||||
/datum/action/innate/cult/mastervote
|
||||
name = "Assert Leadership"
|
||||
button_icon_state = "cultvote"
|
||||
|
||||
/datum/action/innate/cult/mastervote/IsAvailable()
|
||||
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if(!C || C.cult_team.cult_vote_called || !ishuman(owner))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/cult/mastervote/Activate()
|
||||
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
pollCultists(owner,C.cult_team)
|
||||
|
||||
/proc/pollCultists(var/mob/living/Nominee,datum/team/cult/team) //Cult Master Poll
|
||||
if(world.time < CULT_POLL_WAIT)
|
||||
to_chat(Nominee, "It would be premature to select a leader while everyone is still settling in, try again in [DisplayTimeText(CULT_POLL_WAIT-world.time)].")
|
||||
return
|
||||
team.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current)
|
||||
B.current.update_action_buttons_icon()
|
||||
if(!B.current.incapacitated())
|
||||
SEND_SOUND(B.current, 'sound/hallucinations/im_here1.ogg')
|
||||
to_chat(B.current, "<span class='cultlarge'>Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.</span>")
|
||||
sleep(100)
|
||||
var/list/asked_cultists = list()
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current && B.current != Nominee && !B.current.incapacitated())
|
||||
SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg')
|
||||
asked_cultists += B.current
|
||||
var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 300, group = asked_cultists)
|
||||
if(QDELETED(Nominee) || Nominee.incapacitated())
|
||||
team.cult_vote_called = FALSE
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current)
|
||||
B.current.update_action_buttons_icon()
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current,"<span class='cultlarge'>[Nominee] has died in the process of attempting to win the cult's support!</span>")
|
||||
return FALSE
|
||||
if(!Nominee.mind)
|
||||
team.cult_vote_called = FALSE
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current)
|
||||
B.current.update_action_buttons_icon()
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current,"<span class='cultlarge'>[Nominee] has gone catatonic in the process of attempting to win the cult's support!</span>")
|
||||
return FALSE
|
||||
if(LAZYLEN(yes_voters) <= LAZYLEN(asked_cultists) * 0.5)
|
||||
team.cult_vote_called = FALSE
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current)
|
||||
B.current.update_action_buttons_icon()
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current, "<span class='cultlarge'>[Nominee] could not win the cult's support and shall continue to serve as an acolyte.</span>")
|
||||
return FALSE
|
||||
team.cult_mastered = TRUE
|
||||
SSticker.mode.remove_cultist(Nominee.mind, TRUE)
|
||||
Nominee.mind.add_antag_datum(/datum/antagonist/cult/master)
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current)
|
||||
for(var/datum/action/innate/cult/mastervote/vote in B.current.actions)
|
||||
vote.Remove(B.current)
|
||||
if(!B.current.incapacitated())
|
||||
to_chat(B.current,"<span class='cultlarge'>[Nominee] has won the cult's support and is now their master. Follow [Nominee.p_their()] orders to the best of your ability!</span>")
|
||||
return TRUE
|
||||
|
||||
/datum/action/innate/cult/master/IsAvailable()
|
||||
if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master) || GLOB.cult_narsie)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/cult/master/finalreck
|
||||
name = "Final Reckoning"
|
||||
desc = "A single-use spell that brings the entire cult to the master's location."
|
||||
button_icon_state = "sintouch"
|
||||
|
||||
/datum/action/innate/cult/master/finalreck/Activate()
|
||||
var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if(!antag)
|
||||
return
|
||||
for(var/i in 1 to 4)
|
||||
chant(i)
|
||||
var/list/destinations = list()
|
||||
for(var/turf/T in orange(1, owner))
|
||||
if(!is_blocked_turf(T, TRUE))
|
||||
destinations += T
|
||||
if(!LAZYLEN(destinations))
|
||||
to_chat(owner, "<span class='warning'>You need more space to summon the cult!</span>")
|
||||
return
|
||||
if(do_after(owner, 30, target = owner))
|
||||
for(var/datum/mind/B in antag.cult_team.members)
|
||||
if(B.current && B.current.stat != DEAD)
|
||||
var/turf/mobloc = get_turf(B.current)
|
||||
switch(i)
|
||||
if(1)
|
||||
new /obj/effect/temp_visual/cult/sparks(mobloc, B.current.dir)
|
||||
playsound(mobloc, "sparks", 50, 1)
|
||||
if(2)
|
||||
new /obj/effect/temp_visual/dir_setting/cult/phase/out(mobloc, B.current.dir)
|
||||
playsound(mobloc, "sparks", 75, 1)
|
||||
if(3)
|
||||
new /obj/effect/temp_visual/dir_setting/cult/phase(mobloc, B.current.dir)
|
||||
playsound(mobloc, "sparks", 100, 1)
|
||||
if(4)
|
||||
playsound(mobloc, 'sound/magic/exit_blood.ogg', 100, 1)
|
||||
if(B.current != owner)
|
||||
var/turf/final = pick(destinations)
|
||||
if(istype(B.current.loc, /obj/item/device/soulstone))
|
||||
var/obj/item/device/soulstone/S = B.current.loc
|
||||
S.release_shades(owner)
|
||||
B.current.setDir(SOUTH)
|
||||
new /obj/effect/temp_visual/cult/blood(final)
|
||||
addtimer(CALLBACK(B.current, /mob/.proc/reckon, final), 10)
|
||||
else
|
||||
return
|
||||
antag.cult_team.reckoning_complete = TRUE
|
||||
Remove(owner)
|
||||
|
||||
/mob/proc/reckon(turf/final)
|
||||
new /obj/effect/temp_visual/cult/blood/out(get_turf(src))
|
||||
forceMove(final)
|
||||
|
||||
/datum/action/innate/cult/master/finalreck/proc/chant(chant_number)
|
||||
switch(chant_number)
|
||||
if(1)
|
||||
owner.say("C'arta forbici!", language = /datum/language/common)
|
||||
if(2)
|
||||
owner.say("Pleggh e'ntrath!", language = /datum/language/common)
|
||||
playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 50, 1)
|
||||
if(3)
|
||||
owner.say("Barhah hra zar'garis!", language = /datum/language/common)
|
||||
playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 75, 1)
|
||||
if(4)
|
||||
owner.say("N'ath reth sh'yro eth d'rekkathnor!!!", language = /datum/language/common)
|
||||
playsound(get_turf(owner),'sound/magic/clockwork/narsie_attack.ogg', 100, 1)
|
||||
|
||||
/datum/action/innate/cult/master/cultmark
|
||||
name = "Mark Target"
|
||||
desc = "Marks a target for the cult."
|
||||
button_icon_state = "cult_mark"
|
||||
var/obj/effect/proc_holder/cultmark/CM
|
||||
var/cooldown = 0
|
||||
var/base_cooldown = 1200
|
||||
|
||||
/datum/action/innate/cult/master/cultmark/New()
|
||||
CM = new()
|
||||
CM.attached_action = src
|
||||
..()
|
||||
|
||||
/datum/action/innate/cult/master/cultmark/IsAvailable()
|
||||
if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master))
|
||||
return FALSE
|
||||
if(cooldown > world.time)
|
||||
if(!CM.active)
|
||||
to_chat(owner, "<span class='cultlarge'><b>You need to wait [DisplayTimeText(cooldown - world.time)] before you can mark another target!</b></span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/cult/master/cultmark/Destroy()
|
||||
QDEL_NULL(CM)
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/cult/master/cultmark/Activate()
|
||||
CM.toggle(owner) //the important bit
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/cultmark
|
||||
active = FALSE
|
||||
ranged_mousepointer = 'icons/effects/cult_target.dmi'
|
||||
var/datum/action/innate/cult/master/cultmark/attached_action
|
||||
|
||||
/obj/effect/proc_holder/cultmark/Destroy()
|
||||
attached_action = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/cultmark/proc/toggle(mob/user)
|
||||
if(active)
|
||||
remove_ranged_ability("<span class='cult'>You cease the marking ritual.</span>")
|
||||
else
|
||||
add_ranged_ability(user, "<span class='cult'>You prepare to mark a target for your cult...</span>")
|
||||
|
||||
/obj/effect/proc_holder/cultmark/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return
|
||||
if(ranged_ability_user.incapacitated())
|
||||
remove_ranged_ability()
|
||||
return
|
||||
var/turf/T = get_turf(ranged_ability_user)
|
||||
if(!isturf(T))
|
||||
return FALSE
|
||||
|
||||
var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
C.cult_team.blood_target = target
|
||||
var/area/A = get_area(target)
|
||||
attached_action.cooldown = world.time + attached_action.base_cooldown
|
||||
addtimer(CALLBACK(attached_action.owner, /mob.proc/update_action_buttons_icon), attached_action.base_cooldown)
|
||||
C.cult_team.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
|
||||
C.cult_team.blood_target_image.appearance_flags = RESET_COLOR
|
||||
C.cult_team.blood_target_image.pixel_x = -target.pixel_x
|
||||
C.cult_team.blood_target_image.pixel_y = -target.pixel_y
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current && B.current.stat != DEAD && B.current.client)
|
||||
to_chat(B.current, "<span class='cultlarge'><b>Master [ranged_ability_user] has marked [C.cult_team.blood_target] in the [A.name] as the cult's top priority, get there immediately!</b></span>")
|
||||
SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75))
|
||||
B.current.client.images += C.cult_team.blood_target_image
|
||||
attached_action.owner.update_action_buttons_icon()
|
||||
remove_ranged_ability("<span class='cult'>The marking rite is complete! It will last for 90 seconds.</span>")
|
||||
C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target,C.cult_team), 900, TIMER_STOPPABLE)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/proc/reset_blood_target(datum/team/cult/team)
|
||||
for(var/datum/mind/B in team.members)
|
||||
if(B.current && B.current.stat != DEAD && B.current.client)
|
||||
if(team.blood_target)
|
||||
to_chat(B.current,"<span class='cultlarge'><b>The blood mark has expired!</b></span>")
|
||||
B.current.client.images -= team.blood_target_image
|
||||
QDEL_NULL(team.blood_target_image)
|
||||
team.blood_target = null
|
||||
|
||||
|
||||
|
||||
//////// ELDRITCH PULSE /////////
|
||||
|
||||
|
||||
|
||||
/datum/action/innate/cult/master/pulse
|
||||
name = "Eldritch Pulse"
|
||||
desc = "Seize upon a fellow cultist or cult structure and teleport it to a nearby location."
|
||||
icon_icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
button_icon_state = "arcane_barrage"
|
||||
var/obj/effect/proc_holder/pulse/PM
|
||||
var/cooldown = 0
|
||||
var/base_cooldown = 150
|
||||
var/throwing = FALSE
|
||||
var/mob/living/throwee
|
||||
|
||||
/datum/action/innate/cult/master/pulse/New()
|
||||
PM = new()
|
||||
PM.attached_action = src
|
||||
..()
|
||||
|
||||
/datum/action/innate/cult/master/pulse/IsAvailable()
|
||||
if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master))
|
||||
return FALSE
|
||||
if(cooldown > world.time)
|
||||
if(!PM.active)
|
||||
to_chat(owner, "<span class='cultlarge'><b>You need to wait [DisplayTimeText(cooldown - world.time)] before you can pulse again!</b></span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/cult/master/pulse/Destroy()
|
||||
PM.attached_action = null //What the fuck is even going on here.
|
||||
QDEL_NULL(PM)
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/cult/master/pulse/Activate()
|
||||
PM.toggle(owner) //the important bit
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/pulse
|
||||
active = FALSE
|
||||
ranged_mousepointer = 'icons/effects/throw_target.dmi'
|
||||
var/datum/action/innate/cult/master/pulse/attached_action
|
||||
|
||||
/obj/effect/proc_holder/pulse/Destroy()
|
||||
QDEL_NULL(attached_action)
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/pulse/proc/toggle(mob/user)
|
||||
if(active)
|
||||
remove_ranged_ability("<span class='cult'>You cease your preparations...</span>")
|
||||
attached_action.throwing = FALSE
|
||||
else
|
||||
add_ranged_ability(user, "<span class='cult'>You prepare to tear through the fabric of reality...</span>")
|
||||
|
||||
/obj/effect/proc_holder/pulse/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(..())
|
||||
return
|
||||
if(ranged_ability_user.incapacitated())
|
||||
remove_ranged_ability()
|
||||
return
|
||||
var/turf/T = get_turf(ranged_ability_user)
|
||||
if(!isturf(T))
|
||||
return FALSE
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
if((!(iscultist(target) || istype(target, /obj/structure/destructible/cult)) || target == caller) && !(attached_action.throwing))
|
||||
return
|
||||
if(!attached_action.throwing)
|
||||
attached_action.throwing = TRUE
|
||||
attached_action.throwee = target
|
||||
SEND_SOUND(ranged_ability_user, sound('sound/weapons/thudswoosh.ogg'))
|
||||
to_chat(ranged_ability_user,"<span class='cult'><b>You reach through the veil with your mind's eye and seize [target]!</b></span>")
|
||||
return
|
||||
else
|
||||
new /obj/effect/temp_visual/cult/sparks(get_turf(attached_action.throwee), ranged_ability_user.dir)
|
||||
var/distance = get_dist(attached_action.throwee, target)
|
||||
if(distance >= 16)
|
||||
return
|
||||
playsound(target,'sound/magic/exit_blood.ogg')
|
||||
attached_action.throwee.Beam(target,icon_state="sendbeam",time=4)
|
||||
attached_action.throwee.forceMove(get_turf(target))
|
||||
new /obj/effect/temp_visual/cult/sparks(get_turf(target), ranged_ability_user.dir)
|
||||
attached_action.throwing = FALSE
|
||||
attached_action.cooldown = world.time + attached_action.base_cooldown
|
||||
remove_mousepointer(ranged_ability_user.client)
|
||||
remove_ranged_ability("<span class='cult'>A pulse of blood magic surges through you as you shift [attached_action.throwee] through time and space.</span>")
|
||||
caller.update_action_buttons_icon()
|
||||
addtimer(CALLBACK(caller, /mob.proc/update_action_buttons_icon), attached_action.base_cooldown)
|
||||
@@ -1,606 +0,0 @@
|
||||
/obj/item/melee/cultblade
|
||||
name = "eldritch longsword"
|
||||
desc = "A sword humming with unholy energy. It glows with a dim red light."
|
||||
icon_state = "cultblade"
|
||||
item_state = "cultblade"
|
||||
lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
|
||||
inhand_x_dimension = 64
|
||||
inhand_y_dimension = 64
|
||||
flags_1 = CONDUCT_1
|
||||
sharpness = IS_SHARP
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
force = 30
|
||||
throwforce = 10
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "rended")
|
||||
|
||||
|
||||
/obj/item/melee/cultblade/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
if(!iscultist(user))
|
||||
user.Knockdown(100)
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.visible_message("<span class='warning'>A powerful force shoves [user] away from [target]!</span>", \
|
||||
"<span class='cultlarge'>\"You shouldn't play with sharp things. You'll poke someone's eye out.\"</span>")
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.apply_damage(rand(force/2, force), BRUTE, pick("l_arm", "r_arm"))
|
||||
else
|
||||
user.adjustBruteLoss(rand(force/2,force))
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/melee/cultblade/ghost
|
||||
name = "eldritch sword"
|
||||
force = 19 //can't break normal airlocks
|
||||
flags_1 = NODROP_1|DROPDEL_1
|
||||
|
||||
/obj/item/melee/cultblade/pickup(mob/living/user)
|
||||
..()
|
||||
if(!iscultist(user))
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='cultlarge'>\"I wouldn't advise that.\"</span>")
|
||||
to_chat(user, "<span class='warning'>An overwhelming sense of nausea overpowers you!</span>")
|
||||
user.Dizzy(120)
|
||||
else
|
||||
to_chat(user, "<span class='cultlarge'>\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>A horrible force yanks at your arm!</span>")
|
||||
user.emote("scream")
|
||||
user.apply_damage(30, BRUTE, pick("l_arm", "r_arm"))
|
||||
user.dropItemToGround(src)
|
||||
|
||||
/obj/item/melee/cultblade/dagger
|
||||
name = "sacrificial dagger"
|
||||
desc = "A strange dagger said to be used by sinister groups for \"preparing\" a corpse before sacrificing it to their dark gods."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "render"
|
||||
item_state = "knife"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
|
||||
inhand_x_dimension = 32
|
||||
inhand_y_dimension = 32
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
force = 15
|
||||
throwforce = 25
|
||||
embed_chance = 75
|
||||
|
||||
/obj/item/melee/cultblade/dagger/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
..()
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
C.bleed(50)
|
||||
if(is_servant_of_ratvar(C) && C.reagents)
|
||||
C.reagents.add_reagent("heparin", 1)
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard
|
||||
name = "bloody bastard sword"
|
||||
desc = "An enormous sword used by Nar-Sien cultists to rapidly harvest the souls of non-believers."
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
block_chance = 50
|
||||
throwforce = 20
|
||||
force = 35
|
||||
armour_penetration = 45
|
||||
throw_speed = 1
|
||||
throw_range = 3
|
||||
sharpness = IS_SHARP
|
||||
light_color = "#ff0000"
|
||||
attack_verb = list("cleaved", "slashed", "torn", "hacked", "ripped", "diced", "carved")
|
||||
icon_state = "cultbastard"
|
||||
item_state = "cultbastard"
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
|
||||
inhand_x_dimension = 64
|
||||
inhand_y_dimension = 64
|
||||
actions_types = list()
|
||||
flags_2 = SLOWS_WHILE_IN_HAND_2
|
||||
var/datum/action/innate/dash/cult/jaunt
|
||||
var/datum/action/innate/cult/spin2win/linked_action
|
||||
var/spinning = FALSE
|
||||
var/spin_cooldown = 250
|
||||
var/dash_toggled = TRUE
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/Initialize()
|
||||
. = ..()
|
||||
set_light(4)
|
||||
jaunt = new(src)
|
||||
linked_action = new(src)
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/can_be_pulled(user)
|
||||
return FALSE
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/attack_self(mob/user)
|
||||
dash_toggled = !dash_toggled
|
||||
if(dash_toggled)
|
||||
to_chat(loc, "<span class='notice'>You raise [src] and prepare to jaunt with it.</span>")
|
||||
else
|
||||
to_chat(loc, "<span class='notice'>You lower [src] and prepare to swing it normally.</span>")
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/pickup(mob/living/user)
|
||||
. = ..()
|
||||
if(!iscultist(user))
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='cultlarge'>\"I wouldn't advise that.\"</span>")
|
||||
to_chat(user, "<span class='warning'>An overwhelming sense of nausea overpowers you!</span>")
|
||||
user.Dizzy(80)
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Knockdown(30)
|
||||
return
|
||||
else
|
||||
to_chat(user, "<span class='cultlarge'>\"One of Ratvar's toys is trying to play with things [user.p_they()] shouldn't. Cute.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>A horrible force yanks at your arm!</span>")
|
||||
user.emote("scream")
|
||||
user.apply_damage(30, BRUTE, pick("l_arm", "r_arm"))
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Knockdown(50)
|
||||
return
|
||||
jaunt.Grant(user, src)
|
||||
linked_action.Grant(user, src)
|
||||
user.update_icons()
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/dropped(mob/user)
|
||||
. = ..()
|
||||
linked_action.Remove(user)
|
||||
jaunt.Remove(user)
|
||||
user.update_icons()
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/IsReflect()
|
||||
if(spinning)
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
|
||||
return TRUE
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
if(prob(final_block_chance))
|
||||
if(attack_type == PROJECTILE_ATTACK)
|
||||
owner.visible_message("<span class='danger'>[owner] deflects [attack_text] with [src]!</span>")
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 100, 1)
|
||||
return TRUE
|
||||
else
|
||||
playsound(src, 'sound/weapons/parry.ogg', 75, 1)
|
||||
owner.visible_message("<span class='danger'>[owner] parries [attack_text] with [src]!</span>")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/twohanded/required/cult_bastard/afterattack(atom/target, mob/user, proximity, click_parameters)
|
||||
. = ..()
|
||||
if(dash_toggled)
|
||||
jaunt.Teleport(user, target)
|
||||
return
|
||||
if(!proximity)
|
||||
return
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(H.stat != CONSCIOUS)
|
||||
var/obj/item/device/soulstone/SS = new /obj/item/device/soulstone(src)
|
||||
SS.attack(H, user)
|
||||
if(!LAZYLEN(SS.contents))
|
||||
qdel(SS)
|
||||
if(istype(target, /obj/structure/constructshell) && contents.len)
|
||||
var/obj/item/device/soulstone/SS = contents[1]
|
||||
if(istype(SS))
|
||||
SS.transfer_soul("CONSTRUCT",target,user)
|
||||
qdel(SS)
|
||||
|
||||
/datum/action/innate/dash/cult
|
||||
name = "Rend the Veil"
|
||||
desc = "Use the sword to shear open the flimsy fabric of this reality and teleport to your target."
|
||||
icon_icon = 'icons/mob/actions/actions_cult.dmi'
|
||||
button_icon_state = "phaseshift"
|
||||
dash_sound = 'sound/magic/enter_blood.ogg'
|
||||
recharge_sound = 'sound/magic/exit_blood.ogg'
|
||||
beam_effect = "sendbeam"
|
||||
phasein = /obj/effect/temp_visual/dir_setting/cult/phase
|
||||
phaseout = /obj/effect/temp_visual/dir_setting/cult/phase/out
|
||||
|
||||
/datum/action/innate/dash/cult/IsAvailable()
|
||||
if(iscultist(holder) && current_charges)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
|
||||
|
||||
/datum/action/innate/cult/spin2win
|
||||
name = "Geometer's Fury"
|
||||
desc = "You draw on the power of the sword's ancient runes, spinning it wildly around you as you become immune to most attacks."
|
||||
background_icon_state = "bg_demon"
|
||||
button_icon_state = "sintouch"
|
||||
var/cooldown = 0
|
||||
var/mob/living/carbon/human/holder
|
||||
var/obj/item/twohanded/required/cult_bastard/sword
|
||||
|
||||
/datum/action/innate/cult/spin2win/Grant(mob/user, obj/bastard)
|
||||
. = ..()
|
||||
sword = bastard
|
||||
holder = user
|
||||
|
||||
/datum/action/innate/cult/spin2win/IsAvailable()
|
||||
if(iscultist(holder) && cooldown <= world.time)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/datum/action/innate/cult/spin2win/Activate()
|
||||
cooldown = world.time + sword.spin_cooldown
|
||||
holder.changeNext_move(50)
|
||||
holder.apply_status_effect(/datum/status_effect/sword_spin)
|
||||
sword.spinning = TRUE
|
||||
sword.block_chance = 100
|
||||
sword.slowdown += 1.5
|
||||
addtimer(CALLBACK(src, .proc/stop_spinning), 50)
|
||||
holder.update_action_buttons_icon()
|
||||
|
||||
/datum/action/innate/cult/spin2win/proc/stop_spinning()
|
||||
sword.spinning = FALSE
|
||||
sword.block_chance = 50
|
||||
sword.slowdown -= 1.5
|
||||
sleep(sword.spin_cooldown)
|
||||
holder.update_action_buttons_icon()
|
||||
|
||||
/obj/item/restraints/legcuffs/bola/cult
|
||||
name = "nar'sien bola"
|
||||
desc = "A strong bola, bound with dark magic. Throw it to trip and slow your victim."
|
||||
icon_state = "bola_cult"
|
||||
breakouttime = 45
|
||||
knockdown = 10
|
||||
|
||||
|
||||
/obj/item/clothing/head/culthood
|
||||
name = "ancient cultist hood"
|
||||
icon_state = "culthood"
|
||||
desc = "A torn, dust-caked hood. Strange letters line the inside."
|
||||
flags_inv = HIDEFACE|HIDEHAIR|HIDEEARS
|
||||
flags_cover = HEADCOVERSEYES
|
||||
armor = list(melee = 30, bullet = 10, laser = 5,energy = 5, bomb = 0, bio = 0, rad = 0, fire = 10, acid = 10)
|
||||
cold_protection = HEAD
|
||||
min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT
|
||||
heat_protection = HEAD
|
||||
max_heat_protection_temperature = HELMET_MAX_TEMP_PROTECT
|
||||
|
||||
/obj/item/clothing/suit/cultrobes
|
||||
name = "ancient cultist robes"
|
||||
desc = "A ragged, dusty set of robes. Strange letters line the inside."
|
||||
icon_state = "cultrobes"
|
||||
item_state = "cultrobes"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
allowed = list(/obj/item/tome, /obj/item/melee/cultblade)
|
||||
armor = list(melee = 50, bullet = 30, laser = 50,energy = 20, bomb = 25, bio = 10, rad = 0, fire = 10, acid = 10)
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
cold_protection = CHEST|GROIN|LEGS|ARMS
|
||||
min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT
|
||||
heat_protection = CHEST|GROIN|LEGS|ARMS
|
||||
max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT
|
||||
|
||||
|
||||
/obj/item/clothing/head/culthood/alt
|
||||
name = "cultist hood"
|
||||
desc = "An armored hood worn by the followers of Nar-Sie."
|
||||
icon_state = "cult_hoodalt"
|
||||
item_state = "cult_hoodalt"
|
||||
|
||||
/obj/item/clothing/head/culthood/alt/ghost
|
||||
flags_1 = NODROP_1|DROPDEL_1
|
||||
|
||||
/obj/item/clothing/suit/cultrobes/alt
|
||||
name = "cultist robes"
|
||||
desc = "An armored set of robes worn by the followers of Nar-Sie."
|
||||
icon_state = "cultrobesalt"
|
||||
item_state = "cultrobesalt"
|
||||
|
||||
/obj/item/clothing/suit/cultrobes/alt/ghost
|
||||
flags_1 = NODROP_1|DROPDEL_1
|
||||
|
||||
|
||||
/obj/item/clothing/head/magus
|
||||
name = "magus helm"
|
||||
icon_state = "magus"
|
||||
item_state = "magus"
|
||||
desc = "A helm worn by the followers of Nar-Sie."
|
||||
flags_inv = HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDEEARS|HIDEEYES
|
||||
armor = list(melee = 30, bullet = 30, laser = 30,energy = 20, bomb = 0, bio = 0, rad = 0, fire = 10, acid = 10)
|
||||
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH
|
||||
|
||||
/obj/item/clothing/suit/magusred
|
||||
name = "magus robes"
|
||||
desc = "A set of armored robes worn by the followers of Nar-Sie."
|
||||
icon_state = "magusred"
|
||||
item_state = "magusred"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
allowed = list(/obj/item/tome, /obj/item/melee/cultblade)
|
||||
armor = list(melee = 50, bullet = 30, laser = 50,energy = 20, bomb = 25, bio = 10, rad = 0, fire = 10, acid = 10)
|
||||
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
|
||||
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/cult
|
||||
name = "nar-sien hardened helmet"
|
||||
desc = "A heavily-armored helmet worn by warriors of the Nar-Sien cult. It can withstand hard vacuum."
|
||||
icon_state = "cult_helmet"
|
||||
item_state = "cult_helmet"
|
||||
armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30, fire = 40, acid = 75)
|
||||
brightness_on = 0
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/clothing/suit/space/hardsuit/cult
|
||||
name = "nar-sien hardened armor"
|
||||
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_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
|
||||
|
||||
/obj/item/sharpener/cult
|
||||
name = "eldritch whetstone"
|
||||
desc = "A block, empowered by dark magic. Sharp weapons will be enhanced when used on the stone."
|
||||
icon_state = "cult_sharpener"
|
||||
used = 0
|
||||
increment = 5
|
||||
max = 40
|
||||
prefix = "darkened"
|
||||
|
||||
/obj/item/sharpener/cult/update_icon()
|
||||
icon_state = "cult_sharpener[used ? "_used" : ""]"
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/cult_shield
|
||||
name = "empowered cultist armor"
|
||||
desc = "Empowered garb which creates a powerful shield around the user."
|
||||
icon_state = "cult_armor"
|
||||
item_state = "cult_armor"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
armor = list(melee = 50, bullet = 40, laser = 50,energy = 30, bomb = 50, bio = 30, rad = 30, fire = 50, acid = 60)
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
allowed = list(/obj/item/tome, /obj/item/melee/cultblade)
|
||||
var/current_charges = 3
|
||||
hoodtype = /obj/item/clothing/head/hooded/cult_hoodie
|
||||
|
||||
/obj/item/clothing/head/hooded/cult_hoodie
|
||||
name = "empowered cultist armor"
|
||||
desc = "Empowered garb which creates a powerful shield around the user."
|
||||
icon_state = "cult_hoodalt"
|
||||
armor = list(melee = 50, bullet = 40, laser = 50,energy = 30, bomb = 50, bio = 30, rad = 30, fire = 50, acid = 50)
|
||||
body_parts_covered = HEAD
|
||||
flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(!iscultist(user))
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='cultlarge'>\"I wouldn't advise that.\"</span>")
|
||||
to_chat(user, "<span class='warning'>An overwhelming sense of nausea overpowers you!</span>")
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Dizzy(30)
|
||||
user.Knockdown(100)
|
||||
else
|
||||
to_chat(user, "<span class='cultlarge'>\"Trying to use things you don't own is bad, you know.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>The armor squeezes at your body!</span>")
|
||||
user.emote("scream")
|
||||
user.adjustBruteLoss(25)
|
||||
user.dropItemToGround(src, TRUE)
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
if(current_charges)
|
||||
owner.visible_message("<span class='danger'>\The [attack_text] is deflected in a burst of blood-red sparks!</span>")
|
||||
current_charges--
|
||||
new /obj/effect/temp_visual/cult/sparks(get_turf(owner))
|
||||
if(!current_charges)
|
||||
owner.visible_message("<span class='danger'>The runed shield around [owner] suddenly disappears!</span>")
|
||||
owner.update_inv_wear_suit()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands)
|
||||
. = list()
|
||||
if(!isinhands && current_charges)
|
||||
. += mutable_appearance('icons/effects/cult_effects.dmi', "shield-cult", MOB_LAYER + 0.01)
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/berserker
|
||||
name = "flagellant's robes"
|
||||
desc = "Blood-soaked robes infused with dark magic; allows the user to move at inhuman speeds, but at the cost of increased damage."
|
||||
icon_state = "cultrobes"
|
||||
item_state = "cultrobes"
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
allowed = list(/obj/item/tome, /obj/item/melee/cultblade)
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
armor = list(melee = -50, bullet = -50, laser = -50,energy = -50, bomb = -50, bio = -50, rad = -50, fire = 0, acid = 0)
|
||||
slowdown = -1
|
||||
hoodtype = /obj/item/clothing/head/hooded/berserkerhood
|
||||
|
||||
/obj/item/clothing/head/hooded/berserkerhood
|
||||
name = "flagellant's robes"
|
||||
desc = "Blood-soaked garb infused with dark magic; allows the user to move at inhuman speeds, but at the cost of increased damage."
|
||||
icon_state = "culthood"
|
||||
body_parts_covered = HEAD
|
||||
flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS
|
||||
armor = list(melee = -50, bullet = -50, laser = -50, energy = -50, bomb = -50, bio = -50, rad = -50, fire = 0, acid = 0)
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/berserker/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(!iscultist(user))
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='cultlarge'>\"I wouldn't advise that.\"</span>")
|
||||
to_chat(user, "<span class='warning'>An overwhelming sense of nausea overpowers you!</span>")
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Dizzy(30)
|
||||
user.Knockdown(100)
|
||||
else
|
||||
to_chat(user, "<span class='cultlarge'>\"Trying to use things you don't own is bad, you know.\"</span>")
|
||||
to_chat(user, "<span class='userdanger'>The robes squeeze at your body!</span>")
|
||||
user.emote("scream")
|
||||
user.adjustBruteLoss(25)
|
||||
user.dropItemToGround(src, TRUE)
|
||||
|
||||
/obj/item/clothing/glasses/night/cultblind
|
||||
desc = "May nar-sie guide you through the darkness and shield you from the light."
|
||||
name = "zealot's blindfold"
|
||||
icon_state = "blindfold"
|
||||
item_state = "blindfold"
|
||||
darkness_view = 8
|
||||
flash_protect = 1
|
||||
|
||||
/obj/item/clothing/glasses/night/cultblind/equipped(mob/living/user, slot)
|
||||
..()
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='cultlarge'>\"You want to be blind, do you?\"</span>")
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Dizzy(30)
|
||||
user.Knockdown(100)
|
||||
user.blind_eyes(30)
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/bottle/unholywater
|
||||
name = "flask of unholy water"
|
||||
desc = "Toxic to nonbelievers; reinvigorating to the faithful - this flask may be sipped or thrown."
|
||||
icon_state = "holyflask"
|
||||
color = "#333333"
|
||||
list_reagents = list("unholywater" = 40)
|
||||
|
||||
/obj/item/device/shuttle_curse
|
||||
name = "cursed orb"
|
||||
desc = "You peer within this smokey orb and glimpse terrible fates befalling the escape shuttle."
|
||||
icon = 'icons/obj/cult.dmi'
|
||||
icon_state ="shuttlecurse"
|
||||
var/global/curselimit = 0
|
||||
|
||||
/obj/item/device/shuttle_curse/attack_self(mob/living/user)
|
||||
if(!iscultist(user))
|
||||
user.dropItemToGround(src, TRUE)
|
||||
user.Knockdown(100)
|
||||
to_chat(user, "<span class='warning'>A powerful force shoves you away from [src]!</span>")
|
||||
return
|
||||
if(curselimit > 1)
|
||||
to_chat(user, "<span class='notice'>We have exhausted our ability to curse the shuttle.</span>")
|
||||
return
|
||||
if(locate(/obj/singularity/narsie) in GLOB.poi_list)
|
||||
to_chat(user, "<span class='warning'>Nar-Sie is already on this plane, there is no delaying the end of all things.</span>")
|
||||
return
|
||||
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
|
||||
var/cursetime = 1800
|
||||
var/timer = SSshuttle.emergency.timeLeft(1) + cursetime
|
||||
SSshuttle.emergency.setTimer(timer)
|
||||
to_chat(user, "<span class='danger'>You shatter the orb! A dark essence spirals into the air, then disappears.</span>")
|
||||
playsound(user.loc, 'sound/effects/glassbr1.ogg', 50, 1)
|
||||
qdel(src)
|
||||
sleep(20)
|
||||
var/global/list/curses
|
||||
if(!curses)
|
||||
curses = list("A fuel technician just slit his own throat and begged for death. The shuttle will be delayed by three minutes.",
|
||||
"The shuttle's navigation programming was replaced by a file containing two words, IT COMES. The shuttle will be delayed by three minutes.",
|
||||
"The shuttle's custodian tore out his guts and began painting strange shapes on the floor. The shuttle will be delayed by three minutes.",
|
||||
"A shuttle engineer began screaming 'DEATH IS NOT THE END' and ripped out wires until an arc flash seared off her flesh. The shuttle will be delayed by three minutes.",
|
||||
"A shuttle inspector started laughing madly over the radio and then threw herself into an engine turbine. The shuttle will be delayed by three minutes.",
|
||||
"The shuttle dispatcher was found dead with bloody symbols carved into their flesh. The shuttle will be delayed by three minutes.")
|
||||
var/message = pick_n_take(curses)
|
||||
priority_announce("[message]", "System Failure", 'sound/misc/notice1.ogg')
|
||||
curselimit++
|
||||
|
||||
/obj/item/device/cult_shift
|
||||
name = "veil shifter"
|
||||
desc = "This relic teleports you forward a medium distance."
|
||||
icon = 'icons/obj/cult.dmi'
|
||||
icon_state ="shifter"
|
||||
var/uses = 4
|
||||
|
||||
/obj/item/device/cult_shift/examine(mob/user)
|
||||
..()
|
||||
if(uses)
|
||||
to_chat(user, "<span class='cult'>It has [uses] use\s remaining.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='cult'>It seems drained.</span>")
|
||||
|
||||
/obj/item/device/cult_shift/proc/handle_teleport_grab(turf/T, mob/user)
|
||||
var/mob/living/carbon/C = user
|
||||
if(C.pulling)
|
||||
var/atom/movable/pulled = C.pulling
|
||||
pulled.forceMove(T)
|
||||
. = pulled
|
||||
|
||||
/obj/item/device/cult_shift/attack_self(mob/user)
|
||||
if(!uses || !iscarbon(user))
|
||||
to_chat(user, "<span class='warning'>\The [src] is dull and unmoving in your hands.</span>")
|
||||
return
|
||||
if(!iscultist(user))
|
||||
user.dropItemToGround(src, TRUE)
|
||||
step(src, pick(GLOB.alldirs))
|
||||
to_chat(user, "<span class='warning'>\The [src] flickers out of your hands, your connection to this dimension is too strong!</span>")
|
||||
return
|
||||
|
||||
var/mob/living/carbon/C = user
|
||||
var/turf/mobloc = get_turf(C)
|
||||
var/turf/destination = get_teleport_loc(mobloc,C,9,1,3,1,0,1)
|
||||
|
||||
if(destination)
|
||||
uses--
|
||||
if(uses <= 0)
|
||||
icon_state ="shifter_drained"
|
||||
playsound(mobloc, "sparks", 50, 1)
|
||||
new /obj/effect/temp_visual/dir_setting/cult/phase/out(mobloc, C.dir)
|
||||
|
||||
var/atom/movable/pulled = handle_teleport_grab(destination, C)
|
||||
C.forceMove(destination)
|
||||
if(pulled)
|
||||
C.start_pulling(pulled) //forcemove resets pulls, so we need to re-pull
|
||||
|
||||
new /obj/effect/temp_visual/dir_setting/cult/phase(destination, C.dir)
|
||||
playsound(destination, 'sound/effects/phasein.ogg', 25, 1)
|
||||
playsound(destination, "sparks", 50, 1)
|
||||
|
||||
else
|
||||
to_chat(C, "<span class='danger'>The veil cannot be torn here!</span>")
|
||||
|
||||
/obj/item/device/flashlight/flare/culttorch
|
||||
name = "void torch"
|
||||
desc = "Used by veteran cultists to instantly transport items to their needful bretheren."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
brightness_on = 1
|
||||
icon_state = "torch"
|
||||
item_state = "torch"
|
||||
color = "#ff0000"
|
||||
on_damage = 15
|
||||
slot_flags = null
|
||||
on = TRUE
|
||||
var/charges = 5
|
||||
|
||||
/obj/item/device/flashlight/flare/culttorch/afterattack(atom/movable/A, mob/user, proximity)
|
||||
if(!proximity)
|
||||
return
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "That doesn't seem to do anything useful.")
|
||||
return
|
||||
|
||||
if(istype(A, /obj/item))
|
||||
|
||||
var/list/cultists = list()
|
||||
for(var/datum/mind/M in SSticker.mode.cult)
|
||||
if(M.current && M.current.stat != DEAD)
|
||||
cultists |= M.current
|
||||
var/mob/living/cultist_to_receive = input(user, "Who do you wish to call to [src]?", "Followers of the Geometer") as null|anything in (cultists - user)
|
||||
if(!Adjacent(user) || !src || QDELETED(src) || user.incapacitated())
|
||||
return
|
||||
if(!cultist_to_receive)
|
||||
to_chat(user, "<span class='cult italic'>You require a destination!</span>")
|
||||
log_game("Void torch failed - no target")
|
||||
return
|
||||
if(cultist_to_receive.stat == DEAD)
|
||||
to_chat(user, "<span class='cult italic'>[cultist_to_receive] has died!</span>")
|
||||
log_game("Void torch failed - target died")
|
||||
return
|
||||
if(!iscultist(cultist_to_receive))
|
||||
to_chat(user, "<span class='cult italic'>[cultist_to_receive] is not a follower of the Geometer!</span>")
|
||||
log_game("Void torch failed - target was deconverted")
|
||||
return
|
||||
if(A in user.GetAllContents())
|
||||
to_chat(user, "<span class='cult italic'>[A] must be on a surface in order to teleport it!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='cult italic'>You ignite [A] with \the [src], turning it to ash, but through the torch's flames you see that [A] has reached [cultist_to_receive]!")
|
||||
cultist_to_receive.put_in_hands(A)
|
||||
charges--
|
||||
to_chat(user, "\The [src] now has [charges] charge\s.")
|
||||
if(charges == 0)
|
||||
qdel(src)
|
||||
|
||||
else
|
||||
..()
|
||||
to_chat(user, "<span class='warning'>\The [src] can only transport items!</span>")
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
/obj/structure/destructible/cult
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
icon = 'icons/obj/cult.dmi'
|
||||
var/cooldowntime = 0
|
||||
break_sound = 'sound/hallucinations/veryfar_noise.ogg'
|
||||
debris = list(/obj/item/stack/sheet/runed_metal = 1)
|
||||
|
||||
/obj/structure/destructible/cult/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>\The [src] is [anchored ? "":"not "]secured to the floor.</span>")
|
||||
if((iscultist(user) || isobserver(user)) && cooldowntime > world.time)
|
||||
to_chat(user, "<span class='cult italic'>The magic in [src] is too weak, [p_they()] will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].</span>")
|
||||
|
||||
/obj/structure/destructible/cult/examine_status(mob/user)
|
||||
if(iscultist(user) || isobserver(user))
|
||||
var/t_It = p_they(TRUE)
|
||||
var/t_is = p_are()
|
||||
return "<span class='cult'>[t_It] [t_is] at <b>[round(obj_integrity * 100 / max_integrity)]%</b> stability.</span>"
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/cult/attack_animal(mob/living/simple_animal/M)
|
||||
if(istype(M, /mob/living/simple_animal/hostile/construct/builder))
|
||||
if(obj_integrity < max_integrity)
|
||||
M.changeNext_move(CLICK_CD_MELEE)
|
||||
obj_integrity = min(max_integrity, obj_integrity + 5)
|
||||
Beam(M, icon_state="sendbeam", time=4)
|
||||
M.visible_message("<span class='danger'>[M] repairs \the <b>[src]</b>.</span>", \
|
||||
"<span class='cult'>You repair <b>[src]</b>, leaving [p_they()] at <b>[round(obj_integrity * 100 / max_integrity)]%</b> stability.</span>")
|
||||
else
|
||||
to_chat(M, "<span class='cult'>You cannot repair [src], as [p_they()] [p_are()] undamaged!</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/structure/destructible/cult/attackby(obj/I, mob/user, params)
|
||||
if(istype(I, /obj/item/tome) && iscultist(user))
|
||||
anchored = !anchored
|
||||
to_chat(user, "<span class='notice'>You [anchored ? "":"un"]secure \the [src] [anchored ? "to":"from"] the floor.</span>")
|
||||
if(!anchored)
|
||||
icon_state = "[initial(icon_state)]_off"
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/cult/ratvar_act()
|
||||
if(take_damage(rand(25, 50), BURN) && src) //if we still exist
|
||||
var/previouscolor = color
|
||||
color = "#FAE48C"
|
||||
animate(src, color = previouscolor, time = 8)
|
||||
addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
|
||||
|
||||
|
||||
/obj/structure/destructible/cult/talisman
|
||||
name = "altar"
|
||||
desc = "A bloodstained altar dedicated to Nar-Sie."
|
||||
icon_state = "talismanaltar"
|
||||
break_message = "<span class='warning'>The altar shatters, leaving only the wailing of the damned!</span>"
|
||||
|
||||
/obj/structure/destructible/cult/talisman/attack_hand(mob/living/user)
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='warning'>You're pretty sure you know exactly what this is used for and you can't seem to touch it.</span>")
|
||||
return
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='cult italic'>You need to anchor [src] to the floor with a tome first.</span>")
|
||||
return
|
||||
if(cooldowntime > world.time)
|
||||
to_chat(user, "<span class='cult italic'>The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].</span>")
|
||||
return
|
||||
var/choice = alert(user,"You study the schematics etched into the forge...",,"Eldritch Whetstone","Zealot's Blindfold","Flask of Unholy Water")
|
||||
var/pickedtype
|
||||
switch(choice)
|
||||
if("Eldritch Whetstone")
|
||||
pickedtype = /obj/item/sharpener/cult
|
||||
if("Zealot's Blindfold")
|
||||
pickedtype = /obj/item/clothing/glasses/night/cultblind
|
||||
if("Flask of Unholy Water")
|
||||
pickedtype = /obj/item/reagent_containers/food/drinks/bottle/unholywater
|
||||
if(src && !QDELETED(src) && anchored && pickedtype && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time)
|
||||
cooldowntime = world.time + 2400
|
||||
var/obj/item/N = new pickedtype(get_turf(src))
|
||||
to_chat(user, "<span class='cult italic'>You kneel before the altar and your faith is rewarded with an [N]!</span>")
|
||||
|
||||
|
||||
/obj/structure/destructible/cult/forge
|
||||
name = "daemon forge"
|
||||
desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie."
|
||||
icon_state = "forge"
|
||||
light_range = 3
|
||||
light_color = LIGHT_COLOR_LAVA
|
||||
break_message = "<span class='warning'>The force breaks apart into shards with a howling scream!</span>"
|
||||
|
||||
/obj/structure/destructible/cult/forge/attack_hand(mob/living/user)
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='warning'>The heat radiating from [src] pushes you back.</span>")
|
||||
return
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='cult italic'>You need to anchor [src] to the floor with a tome first.</span>")
|
||||
return
|
||||
if(cooldowntime > world.time)
|
||||
to_chat(user, "<span class='cult italic'>The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].</span>")
|
||||
return
|
||||
var/choice = alert(user,"You study the schematics etched into the forge...",,"Shielded Robe","Flagellant's Robe","Bastard Sword")
|
||||
var/pickedtype
|
||||
switch(choice)
|
||||
if("Shielded Robe")
|
||||
pickedtype = /obj/item/clothing/suit/hooded/cultrobes/cult_shield
|
||||
if("Flagellant's Robe")
|
||||
pickedtype = /obj/item/clothing/suit/hooded/cultrobes/berserker
|
||||
if("Bastard Sword")
|
||||
if((world.time - SSticker.round_start_time) >= 12000)
|
||||
pickedtype = /obj/item/twohanded/required/cult_bastard
|
||||
else
|
||||
cooldowntime = 12000 - (world.time - SSticker.round_start_time)
|
||||
to_chat(user, "<span class='cult italic'>The forge fires are not yet hot enough for this weapon, give it another [DisplayTimeText(cooldowntime)].</span>")
|
||||
cooldowntime = 0
|
||||
return
|
||||
if(src && !QDELETED(src) && anchored && pickedtype && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time)
|
||||
cooldowntime = world.time + 2400
|
||||
var/obj/item/N = new pickedtype(get_turf(src))
|
||||
to_chat(user, "<span class='cult italic'>You work the forge as dark knowledge guides your hands, creating [N]!</span>")
|
||||
|
||||
|
||||
|
||||
/obj/structure/destructible/cult/pylon
|
||||
name = "pylon"
|
||||
desc = "A floating crystal that slowly heals those faithful to Nar'Sie."
|
||||
icon_state = "pylon"
|
||||
light_range = 5
|
||||
light_color = LIGHT_COLOR_RED
|
||||
break_sound = 'sound/effects/glassbr2.ogg'
|
||||
break_message = "<span class='warning'>The blood-red crystal falls to the floor and shatters!</span>"
|
||||
var/heal_delay = 25
|
||||
var/last_heal = 0
|
||||
var/corrupt_delay = 50
|
||||
var/last_corrupt = 0
|
||||
|
||||
/obj/structure/destructible/cult/pylon/New()
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
..()
|
||||
|
||||
/obj/structure/destructible/cult/pylon/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/cult/pylon/process()
|
||||
if(!anchored)
|
||||
return
|
||||
if(last_heal <= world.time)
|
||||
last_heal = world.time + heal_delay
|
||||
for(var/mob/living/L in range(5, src))
|
||||
if(iscultist(L) || isshade(L) || isconstruct(L))
|
||||
if(L.health != L.maxHealth)
|
||||
new /obj/effect/temp_visual/heal(get_turf(src), "#960000")
|
||||
if(ishuman(L))
|
||||
L.adjustBruteLoss(-1, 0)
|
||||
L.adjustFireLoss(-1, 0)
|
||||
L.updatehealth()
|
||||
if(isshade(L) || isconstruct(L))
|
||||
var/mob/living/simple_animal/M = L
|
||||
if(M.health < M.maxHealth)
|
||||
M.adjustHealth(-1)
|
||||
if(ishuman(L) && L.blood_volume < BLOOD_VOLUME_NORMAL)
|
||||
L.blood_volume += 1.0
|
||||
CHECK_TICK
|
||||
if(last_corrupt <= world.time)
|
||||
var/list/validturfs = list()
|
||||
var/list/cultturfs = list()
|
||||
for(var/T in circleviewturfs(src, 5))
|
||||
if(istype(T, /turf/open/floor/engine/cult))
|
||||
cultturfs |= T
|
||||
continue
|
||||
var/static/list/blacklisted_pylon_turfs = typecacheof(list(
|
||||
/turf/closed,
|
||||
/turf/open/floor/engine/cult,
|
||||
/turf/open/space,
|
||||
/turf/open/lava,
|
||||
/turf/open/chasm))
|
||||
if(is_type_in_typecache(T, blacklisted_pylon_turfs))
|
||||
continue
|
||||
else
|
||||
validturfs |= T
|
||||
|
||||
last_corrupt = world.time + corrupt_delay
|
||||
|
||||
var/turf/T = safepick(validturfs)
|
||||
if(T)
|
||||
T.ChangeTurf(/turf/open/floor/engine/cult)
|
||||
else
|
||||
var/turf/open/floor/engine/cult/F = safepick(cultturfs)
|
||||
if(F)
|
||||
new /obj/effect/temp_visual/cult/turf/floor(F)
|
||||
else
|
||||
// Are we in space or something? No cult turfs or
|
||||
// convertable turfs?
|
||||
last_corrupt = world.time + corrupt_delay*2
|
||||
|
||||
/obj/structure/destructible/cult/tome
|
||||
name = "archives"
|
||||
desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl."
|
||||
icon_state = "tomealtar"
|
||||
light_range = 1.4
|
||||
light_color = LIGHT_COLOR_FIRE
|
||||
break_message = "<span class='warning'>The books and tomes of the archives burn into ash as the desk shatters!</span>"
|
||||
|
||||
/obj/structure/destructible/cult/tome/attack_hand(mob/living/user)
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='warning'>All of these books seem to be gibberish.</span>")
|
||||
return
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='cult italic'>You need to anchor [src] to the floor with a tome first.</span>")
|
||||
return
|
||||
if(cooldowntime > world.time)
|
||||
to_chat(user, "<span class='cult italic'>The magic in [src] is weak, it will be ready to use again in [DisplayTimeText(cooldowntime - world.time)].</span>")
|
||||
return
|
||||
var/choice = alert(user,"You flip through the black pages of the archives...",,"Supply Talisman","Shuttle Curse","Veil Walker Set")
|
||||
var/list/pickedtype = list()
|
||||
switch(choice)
|
||||
if("Supply Talisman")
|
||||
pickedtype += /obj/item/paper/talisman/supply/weak
|
||||
if("Shuttle Curse")
|
||||
pickedtype += /obj/item/device/shuttle_curse
|
||||
if("Veil Walker Set")
|
||||
pickedtype += /obj/item/device/cult_shift
|
||||
pickedtype += /obj/item/device/flashlight/flare/culttorch
|
||||
if(src && !QDELETED(src) && anchored && pickedtype.len && Adjacent(user) && !user.incapacitated() && iscultist(user) && cooldowntime <= world.time)
|
||||
cooldowntime = world.time + 2400
|
||||
for(var/N in pickedtype)
|
||||
var/obj/item/D = new N(get_turf(src))
|
||||
to_chat(user, "<span class='cult italic'>You summon [D] from the archives!</span>")
|
||||
|
||||
/obj/effect/gateway
|
||||
name = "gateway"
|
||||
desc = "You're pretty sure that abyss is staring back."
|
||||
icon = 'icons/obj/cult.dmi'
|
||||
icon_state = "hole"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
|
||||
/obj/effect/gateway/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/gateway/singularity_pull()
|
||||
return
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user