Merge branch 'master' into plumb
This commit is contained in:
@@ -9,8 +9,6 @@
|
||||
icon_state = "bus"
|
||||
density = TRUE
|
||||
circuit = /obj/item/circuitboard/machine/ntnet_relay
|
||||
ui_x = 400
|
||||
ui_y = 300
|
||||
|
||||
var/datum/ntnet/NTNet = null // This is mostly for backwards reference and to allow varedit modifications from ingame.
|
||||
var/enabled = 1 // Set to 0 if the relay was turned off
|
||||
@@ -64,15 +62,12 @@
|
||||
SSnetworks.station_network.add_log("Quantum relay switched from overload recovery mode to normal operation mode.")
|
||||
..()
|
||||
|
||||
/obj/machinery/ntnet_relay/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
|
||||
/obj/machinery/ntnet_relay/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "NtnetRelay", "NTNet Quantum Relay", ui_x, ui_y, master_ui, state)
|
||||
ui = new(user, src, "NtnetRelay")
|
||||
ui.open()
|
||||
|
||||
|
||||
/obj/machinery/ntnet_relay/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["enabled"] = enabled
|
||||
@@ -81,7 +76,6 @@
|
||||
data["dos_crashed"] = dos_failure
|
||||
return data
|
||||
|
||||
|
||||
/obj/machinery/ntnet_relay/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
@@ -118,4 +112,4 @@
|
||||
D.target = null
|
||||
D.error = "Connection to quantum relay severed"
|
||||
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -78,10 +78,15 @@
|
||||
close_machine(target)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/machinery/vr_sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_contained_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/vr_sleeper/ui_state(mob/user)
|
||||
if(user == occupant)
|
||||
return GLOB.contained_state
|
||||
return GLOB.default_state
|
||||
|
||||
/obj/machinery/vr_sleeper/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "VrSleeper", "VR Sleeper", 475, 340, master_ui, state)
|
||||
ui = new(user, src, "VrSleeper", "VR Sleeper")
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/vr_sleeper/ui_act(action, params)
|
||||
|
||||
@@ -40,6 +40,11 @@
|
||||
|
||||
if(M.client)
|
||||
body += "<br>\[<b>First Seen:</b> [M.client.player_join_date]\]\[<b>Byond account registered on:</b> [M.client.account_join_date]\]"
|
||||
body += "<br><br><b>CentCom Galactic Ban DB: </b> "
|
||||
if(CONFIG_GET(string/centcom_ban_db))
|
||||
body += "<a href='?_src_=holder;[HrefToken()];centcomlookup=[M.client.ckey]'>Search</a>"
|
||||
else
|
||||
body += "<i>Disabled</i>"
|
||||
body += "<br><br><b>Show related accounts by:</b> "
|
||||
body += "\[ <a href='?_src_=holder;[HrefToken()];showrelatedacc=cid;client=[REF(M.client)]'>CID</a> | "
|
||||
body += "<a href='?_src_=holder;[HrefToken()];showrelatedacc=ip;client=[REF(M.client)]'>IP</a> \]"
|
||||
|
||||
@@ -150,7 +150,7 @@ GLOBAL_LIST(round_end_notifiees)
|
||||
|
||||
/datum/tgs_chat_command/wheelofsalt/Run(datum/tgs_chat_user/sender, params)
|
||||
var/saltresult = "The wheel of salt [pick("clatters","screams","vibrates","clanks","resonates","groans","moans","squeaks","emits a[pick(" god-forsaken"," lewd"," creepy"," generic","n orgasmic"," demonic")] [pick("airhorn","bike horn","trumpet","clown","latex","vore","dog","laughing")] noise")] as it spins violently... And it seems the salt of the day is the "
|
||||
var/saltprimarysubject = "[pick("combat","medical","grab","furry","wall","orgasm","cat","ERP","lizard","dog","latex","vision cone","atmospherics","table","chem","vore","dogborg","Skylar Lineman","Mekhi Anderson","Peppermint","rework","cum","dick","cockvore","Medihound","sleeper","belly sleeper","door wires","flightsuit","coder privilege","Developer abuse","ban reason","github self merge","red panda","beret","male catgirl","powergame","hexacrocin","Discord server","Clitadel","Cargonia","Solarian Republic","Main and RP merger","bluespace","salt","chem dispenser theft","Botany","moth","BWOINK","anal vore","stamina","Mason Jakops","mining","noodle","milf","Lavaland","Necropolis","Ashwalker","Chase Redtail","Drew Mint","Pavel Marsk","Joker Amari","Durgit","chaplain","Antag","nanite","Syndicate","Nar-Sie","Ratvar","Cult","maint","Foam-Force","AI","cyborg","ghost","clockwork","cyberpunk","vaporwave","Clown","Leon Beech","Mime","security","research","Megafauna","Bubblegum","Ash Drake","Legion","Colossus","White Shuttle","Changeling","Cowboy","Space Ninja","Poly","Revolutionary","Skyrim","forbidden fruits","xenomorph","blob","Nuclear Operative","crossdressing")]"
|
||||
var/saltprimarysubject = "[pick("combat","medical","grab","furry","wall","orgasm","cat","ERP","lizard","dog","latex","vision cone","atmospherics","table","chem","vore","dogborg","Skylar Lineman","Mekhi Anderson","Peppermint","rework","cum","dick","cockvore","Medihound","sleeper","belly sleeper","door wires","flightsuit","coder privilege","Developer abuse","ban reason","github self merge","red panda","beret","male catgirl","powergame","hexacrocin removal","Discord server","Clitadel","Cargonia","Solarian Republic","Main and RP merger","bluespace","salt","chem dispenser theft","Botany","moth","BWOINK","anal vore","stamina","Mason Jakops","mining","noodle","milf","Lavaland","Necropolis","Ashwalker","Chase Redtail","Drew Mint","Pavel Marsk","Joker Amari","Durgit","chaplain","Antag","nanite","Syndicate","Nar-Sie","Ratvar","Cult","maint","Foam-Force","AI","cyborg","ghost","clockwork","cyberpunk","vaporwave","Clown","Leon Beech","Mime","security","research","Megafauna","Bubblegum","Ash Drake","Legion","Colossus","White Shuttle","Changeling","Cowboy","Space Ninja","Poly","Revolutionary","Skyrim","forbidden fruits","xenomorph","blob","Nuclear Operative","crossdressing")]"
|
||||
var/saltsecondarysubject = "[pick("rework","changes","r34","ban","removal","addition","leak","proposal","fanart","introduction","tabling","ERP","bikeshedding","crossdressing","sprites","semen keg","argument","theft","nerf","screeching","salt","creampie","lewding","murder","kissing","marriage","replacement","fucking","ship","netflix adaptation","dance","remaster","system","voyeur","decoration","pre-order","bukkake","seduction","worship","gangbang","handholding")]"
|
||||
if(prob(10))
|
||||
saltresult += "@here for your salt, all day every day"
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
if(jobban_isbanned(M, ROLE_TRAITOR) || isbanned_dept)
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=traitor;jobban4=[REF(M)]'><font color=red>Traitor</font></a></td>"
|
||||
else
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];jobban3=traitor;jobban4=[REF(M)]'>Traitor</a></td>"
|
||||
dat += "<td width='20%'><a href='?src=[REF(src)];[HrefToken()];jobban3=traitor;jobban4=[REF(M)]'>Traitor</a></td>"
|
||||
|
||||
//Changeling
|
||||
if(jobban_isbanned(M, ROLE_CHANGELING) || isbanned_dept)
|
||||
@@ -2184,8 +2184,18 @@
|
||||
if(!ishuman(H))
|
||||
to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human.")
|
||||
return
|
||||
|
||||
var/obj/item/reagent_containers/food/snacks/cookie/cookie = new(H)
|
||||
//let's keep it simple
|
||||
//milk to plasmemes and skeletons, meat to lizards, electricity bars to ethereals, cookies to everyone else
|
||||
var/cookiealt = /obj/item/reagent_containers/food/snacks/cookie
|
||||
if(isskeleton(H))
|
||||
cookiealt = /obj/item/reagent_containers/food/condiment/milk
|
||||
else if(isplasmaman(H))
|
||||
cookiealt = /obj/item/reagent_containers/food/condiment/milk
|
||||
else if(isethereal(H))
|
||||
cookiealt = /obj/item/reagent_containers/food/snacks/energybar
|
||||
else if(islizard(H))
|
||||
cookiealt = /obj/item/reagent_containers/food/snacks/meat/slab
|
||||
var/obj/item/cookie = new cookiealt(H)
|
||||
if(H.put_in_hands(cookie))
|
||||
H.update_inv_hands()
|
||||
else
|
||||
@@ -2834,6 +2844,60 @@
|
||||
|
||||
usr << browse(dat.Join("<br>"), "window=related_[C];size=420x300")
|
||||
|
||||
else if(href_list["centcomlookup"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
if(!CONFIG_GET(string/centcom_ban_db))
|
||||
to_chat(usr, "<span class='warning'>Centcom Galactic Ban DB is disabled!</span>")
|
||||
return
|
||||
|
||||
var/ckey = href_list["centcomlookup"]
|
||||
|
||||
// Make the request
|
||||
var/datum/http_request/request = new()
|
||||
request.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/centcom_ban_db)]/[ckey]", "", "")
|
||||
request.begin_async()
|
||||
UNTIL(request.is_complete() || !usr)
|
||||
if (!usr)
|
||||
return
|
||||
var/datum/http_response/response = request.into_response()
|
||||
|
||||
var/list/bans
|
||||
|
||||
var/list/dat = list("<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><body>")
|
||||
|
||||
if(response.errored)
|
||||
dat += "<br>Failed to connect to CentCom."
|
||||
else if(response.status_code != 200)
|
||||
dat += "<br>Failed to connect to CentCom. Status code: [response.status_code]"
|
||||
else
|
||||
if(response.body == "[]")
|
||||
dat += "<center><b>0 bans detected for [ckey]</b></center>"
|
||||
else
|
||||
bans = json_decode(response["body"])
|
||||
dat += "<center><b>[bans.len] ban\s detected for [ckey]</b></center>"
|
||||
for(var/list/ban in bans)
|
||||
dat += "<b>Server: </b> [sanitize(ban["sourceName"])]<br>"
|
||||
dat += "<b>RP Level: </b> [sanitize(ban["sourceRoleplayLevel"])]<br>"
|
||||
dat += "<b>Type: </b> [sanitize(ban["type"])]<br>"
|
||||
dat += "<b>Banned By: </b> [sanitize(ban["bannedBy"])]<br>"
|
||||
dat += "<b>Reason: </b> [sanitize(ban["reason"])]<br>"
|
||||
dat += "<b>Datetime: </b> [sanitize(ban["bannedOn"])]<br>"
|
||||
var/expiration = ban["expires"]
|
||||
dat += "<b>Expires: </b> [expiration ? "[sanitize(expiration)]" : "Permanent"]<br>"
|
||||
if(ban["type"] == "job")
|
||||
dat += "<b>Jobs: </b> "
|
||||
var/list/jobs = ban["jobs"]
|
||||
dat += sanitize(jobs.Join(", "))
|
||||
dat += "<br>"
|
||||
dat += "<hr>"
|
||||
|
||||
dat += "<br></body>"
|
||||
var/datum/browser/popup = new(usr, "centcomlookup-[ckey]", "<div align='center'>Central Command Galactic Ban Database</div>", 700, 600)
|
||||
popup.set_content(dat.Join())
|
||||
popup.open(0)
|
||||
|
||||
else if(href_list["modantagrep"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
@@ -371,8 +371,7 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
return
|
||||
|
||||
var/msg = "<font color='red' size='4'><b>- AdminHelp marked as IC issue by [usr?.client?.holder?.fakekey? usr.client.holder.fakekey : "an administrator"]! -</b></font><br>"
|
||||
msg += "<font color='red'><b>Losing is part of the game!</b></font><br>"
|
||||
msg += "<font color='red'>It is also possible that your ahelp is unable to be answered properly, due to events occurring in the round.</font>"
|
||||
msg += "<font color='red'>Your ahelp is unable to be answered properly due to events occurring in the round. Your question probably has an IC answer, which means you should deal with it IC!</font>"
|
||||
if(initiator)
|
||||
to_chat(initiator, msg)
|
||||
|
||||
|
||||
@@ -22,37 +22,6 @@
|
||||
show_air_status_to(target, usr)
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Air Status") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
/client/proc/fix_next_move()
|
||||
set category = "Debug"
|
||||
set name = "Unfreeze Everyone"
|
||||
var/largest_move_time = 0
|
||||
var/largest_click_time = 0
|
||||
var/mob/largest_move_mob = null
|
||||
var/mob/largest_click_mob = null
|
||||
for(var/mob/M in world)
|
||||
if(!M.client)
|
||||
continue
|
||||
if(M.next_move >= largest_move_time)
|
||||
largest_move_mob = M
|
||||
if(M.next_move > world.time)
|
||||
largest_move_time = M.next_move - world.time
|
||||
else
|
||||
largest_move_time = 1
|
||||
if(M.next_click >= largest_click_time)
|
||||
largest_click_mob = M
|
||||
if(M.next_click > world.time)
|
||||
largest_click_time = M.next_click - world.time
|
||||
else
|
||||
largest_click_time = 0
|
||||
log_admin("DEBUG: [key_name(M)] next_move = [M.next_move] lastDblClick = [M.next_click] world.time = [world.time]")
|
||||
M.next_move = 1
|
||||
M.next_click = 0
|
||||
message_admins("[ADMIN_LOOKUPFLW(largest_move_mob)] had the largest move delay with [largest_move_time] frames / [DisplayTimeText(largest_move_time)]!")
|
||||
message_admins("[ADMIN_LOOKUPFLW(largest_click_mob)] had the largest click delay with [largest_click_time] frames / [DisplayTimeText(largest_click_time)]!")
|
||||
message_admins("world.time = [world.time]")
|
||||
SSblackbox.record_feedback("tally", "admin_verb", 1, "Unfreeze Everyone") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
return
|
||||
|
||||
/client/proc/radio_report()
|
||||
set category = "Debug"
|
||||
set name = "Radio report"
|
||||
|
||||
@@ -1280,8 +1280,12 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
ADMIN_PUNISHMENT_SUPPLYPOD,
|
||||
ADMIN_PUNISHMENT_MAZING,
|
||||
ADMIN_PUNISHMENT_ROD,
|
||||
ADMIN_PUNISHMENT_SHOES,
|
||||
ADMIN_PUNISHMENT_PICKLE,
|
||||
ADMIN_PUNISHMENT_FRY)
|
||||
ADMIN_PUNISHMENT_FRY,
|
||||
ADMIN_PUNISHMENT_CRACK,
|
||||
ADMIN_PUNISHMENT_BLEED,
|
||||
ADMIN_PUNISHMENT_SCARIFY)
|
||||
|
||||
var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list
|
||||
|
||||
@@ -1359,13 +1363,122 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
if(amount)
|
||||
A.reagents.add_reagent(chosen_id, amount)
|
||||
A.splat(target)
|
||||
if(ADMIN_PUNISHMENT_CRACK)
|
||||
if(!iscarbon(target))
|
||||
to_chat(usr,"<span class='warning'>This must be used on a carbon mob.</span>", confidential = TRUE)
|
||||
return
|
||||
var/mob/living/carbon/C = target
|
||||
for(var/i in C.bodyparts)
|
||||
var/obj/item/bodypart/squish_part = i
|
||||
var/type_wound = pick(list(/datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/critical, /datum/wound/blunt/severe, /datum/wound/blunt/moderate))
|
||||
squish_part.force_wound_upwards(type_wound, smited=TRUE)
|
||||
if(ADMIN_PUNISHMENT_BLEED)
|
||||
if(!iscarbon(target))
|
||||
to_chat(usr,"<span class='warning'>This must be used on a carbon mob.</span>", confidential = TRUE)
|
||||
return
|
||||
var/mob/living/carbon/C = target
|
||||
for(var/i in C.bodyparts)
|
||||
var/obj/item/bodypart/slice_part = i
|
||||
var/type_wound = pick(list(/datum/wound/slash/severe, /datum/wound/slash/moderate))
|
||||
slice_part.force_wound_upwards(type_wound, smited=TRUE)
|
||||
type_wound = pick(list(/datum/wound/slash/critical, /datum/wound/slash/severe, /datum/wound/slash/moderate))
|
||||
slice_part.force_wound_upwards(type_wound, smited=TRUE)
|
||||
type_wound = pick(list(/datum/wound/slash/critical, /datum/wound/slash/severe))
|
||||
slice_part.force_wound_upwards(type_wound, smited=TRUE)
|
||||
if(ADMIN_PUNISHMENT_SCARIFY)
|
||||
if(!iscarbon(target))
|
||||
to_chat(usr,"<span class='warning'>This must be used on a carbon mob.</span>", confidential = TRUE)
|
||||
return
|
||||
var/mob/living/carbon/dude = target
|
||||
dude.generate_fake_scars(rand(1, 4))
|
||||
to_chat(dude, "<span class='warning'>You feel your body grow jaded and torn...</span>")
|
||||
if(ADMIN_PUNISHMENT_PERFORATE)
|
||||
if(!iscarbon(target))
|
||||
to_chat(usr,"<span class='warning'>This must be used on a carbon mob.</span>", confidential = TRUE)
|
||||
return
|
||||
|
||||
var/list/how_fucked_is_this_dude = list("A little", "A lot", "So fucking much", "FUCK THIS DUDE")
|
||||
var/hatred = input("How much do you hate this guy?") in how_fucked_is_this_dude
|
||||
var/repetitions
|
||||
var/shots_per_limb_per_rep = 2
|
||||
var/damage
|
||||
switch(hatred)
|
||||
if("A little")
|
||||
repetitions = 1
|
||||
damage = 5
|
||||
if("A lot")
|
||||
repetitions = 2
|
||||
|
||||
damage = 8
|
||||
if("So fucking much")
|
||||
repetitions = 3
|
||||
damage = 10
|
||||
if("FUCK THIS DUDE")
|
||||
repetitions = 4
|
||||
damage = 10
|
||||
|
||||
var/mob/living/carbon/dude = target
|
||||
var/list/open_adj_turfs = get_adjacent_open_turfs(dude)
|
||||
var/list/wound_bonuses = list(15, 70, 110, 250)
|
||||
|
||||
var/delay_per_shot = 1
|
||||
var/delay_counter = 1
|
||||
|
||||
dude.Immobilize(5 SECONDS)
|
||||
for(var/wound_bonus_rep in 1 to repetitions)
|
||||
for(var/i in dude.bodyparts)
|
||||
var/obj/item/bodypart/slice_part = i
|
||||
var/shots_this_limb = 0
|
||||
for(var/t in shuffle(open_adj_turfs))
|
||||
var/turf/iter_turf = t
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/firing_squad, dude, iter_turf, slice_part.body_zone, wound_bonuses[wound_bonus_rep], damage), delay_counter)
|
||||
delay_counter += delay_per_shot
|
||||
shots_this_limb++
|
||||
if(shots_this_limb > shots_per_limb_per_rep)
|
||||
break
|
||||
if(ADMIN_PUNISHMENT_PICKLE)
|
||||
target.turn_into_pickle()
|
||||
if(ADMIN_PUNISHMENT_FRY)
|
||||
target.fry()
|
||||
|
||||
if(ADMIN_PUNISHMENT_SHOES)
|
||||
if(!iscarbon(target))
|
||||
to_chat(usr,"<span class='warning'>This must be used on a carbon mob.</span>")
|
||||
return
|
||||
var/mob/living/carbon/C = target
|
||||
var/obj/item/clothing/shoes/sick_kicks = C.shoes
|
||||
if(!sick_kicks?.can_be_tied)
|
||||
to_chat(usr,"<span class='warning'>[C] does not have knottable shoes!</span>")
|
||||
return
|
||||
sick_kicks.adjust_laces(SHOES_KNOTTED)
|
||||
|
||||
punish_log(target, punishment)
|
||||
|
||||
/**
|
||||
* firing_squad is a proc for the :B:erforate smite to shoot each individual bullet at them, so that we can add actual delays without sleep() nonsense
|
||||
*
|
||||
* Hilariously, if you drag someone away mid smite, the bullets will still chase after them from the original spot, possibly hitting other people. Too funny to fix imo
|
||||
*
|
||||
* Arguments:
|
||||
* * target- guy we're shooting obviously
|
||||
* * source_turf- where the bullet begins, preferably on a turf next to the target
|
||||
* * body_zone- which bodypart we're aiming for, if there is one there
|
||||
* * wound_bonus- the wounding power we're assigning to the bullet, since we don't care about the base one
|
||||
* * damage- the damage we're assigning to the bullet, since we don't care about the base one
|
||||
*/
|
||||
/proc/firing_squad(mob/living/carbon/target, turf/source_turf, body_zone, wound_bonus, damage)
|
||||
if(!target.get_bodypart(body_zone))
|
||||
return
|
||||
playsound(target, 'sound/weapons/shot.ogg', 100)
|
||||
var/obj/item/projectile/bullet/smite/divine_wrath = new(source_turf)
|
||||
divine_wrath.damage = damage
|
||||
divine_wrath.wound_bonus = wound_bonus
|
||||
divine_wrath.original = target
|
||||
divine_wrath.def_zone = body_zone
|
||||
divine_wrath.spread = 0
|
||||
divine_wrath.preparePixelProjectile(target, source_turf)
|
||||
divine_wrath.fire()
|
||||
|
||||
/client/proc/punish_log(var/whom, var/punishment)
|
||||
var/msg = "[key_name_admin(usr)] punished [key_name_admin(whom)] with [punishment]."
|
||||
message_admins(msg)
|
||||
|
||||
@@ -60,8 +60,10 @@
|
||||
|
||||
/datum/antagonist/abductor/greet()
|
||||
to_chat(owner.current, "<span class='notice'>You are the [owner.special_role]!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>With the help of your teammate, kidnap and experiment on station crew members!</span>")
|
||||
to_chat(owner.current, "<span class='notice'>Try not to disturb the habitat, it could lead to dead specimens.</span>")
|
||||
to_chat(owner.current, "<span class='notice'>You are an operative for your home planet's government. Your mission is to detain, experiment, and observe.</span>")
|
||||
to_chat(owner.current, "<span class='notice'>Work together with your teammate to bring live subjects from the space station nearby onto your ship for experimentation.</span>")
|
||||
to_chat(owner.current, "<span class='notice'>For the sake of the mission, do not damage the integrity of the station, do not kill anyone unless in self defense, always capture specimens first if you can, and do not steal equipment or belongings from abducted specimens.</span>")
|
||||
to_chat(owner.current, "<span class='notice'>Your task is to observe and take notes of the effects of your experiments.</span>")
|
||||
to_chat(owner.current, "<span class='notice'>[greet_text]</span>")
|
||||
owner.announce_objectives()
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
GLOBAL_LIST_INIT(abductor_gear, subtypesof(/datum/abductor_gear))
|
||||
|
||||
/datum/abductor_gear
|
||||
/// Name of the gear
|
||||
var/name = "Generic Abductor Gear"
|
||||
/// Description of the gear
|
||||
var/description = "Generic description."
|
||||
/// Unique ID of the gear
|
||||
var/id = "abductor_generic"
|
||||
/// Credit cost of the gear
|
||||
var/cost = 1
|
||||
/// Build path of the gear itself
|
||||
var/build_path = null
|
||||
/// Category of the gear
|
||||
var/category = "Basic Gear"
|
||||
|
||||
/datum/abductor_gear/agent_helmet
|
||||
name = "Agent Helmet"
|
||||
description = "Abduct with style - spiky style. Prevents digital tracking."
|
||||
id = "agent_helmet"
|
||||
build_path = /obj/item/clothing/head/helmet/abductor
|
||||
|
||||
/datum/abductor_gear/agent_vest
|
||||
name = "Agent Vest"
|
||||
description = "A vest outfitted with advanced stealth technology. It has two modes - combat and stealth."
|
||||
id = "agent_vest"
|
||||
build_path = /obj/item/clothing/suit/armor/abductor/vest
|
||||
|
||||
/datum/abductor_gear/radio_silencer
|
||||
name = "Radio Silencer"
|
||||
description = "A compact device used to shut down communications equipment."
|
||||
id = "radio_silencer"
|
||||
build_path = /obj/item/abductor/silencer
|
||||
|
||||
/datum/abductor_gear/science_tool
|
||||
name = "Science Tool"
|
||||
description = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras."
|
||||
id = "science_tool"
|
||||
build_path = /obj/item/abductor/gizmo
|
||||
/*
|
||||
/datum/abductor_gear/advanced_baton
|
||||
name = "Advanced Baton"
|
||||
description = "A quad-mode baton used for incapacitation and restraining of specimens."
|
||||
id = "advanced_baton"
|
||||
cost = 2
|
||||
build_path = /obj/item/melee/baton/abductor //does not exist?
|
||||
*/
|
||||
/datum/abductor_gear/superlingual_matrix
|
||||
name = "Superlingual Matrix"
|
||||
description = "A mysterious structure that allows for instant communication between users. Pretty impressive until you need to eat something."
|
||||
id = "superlingual_matrix"
|
||||
build_path = /obj/item/organ/tongue/abductor
|
||||
category = "Advanced Gear"
|
||||
|
||||
/datum/abductor_gear/mental_interface
|
||||
name = "Mental Interface Device"
|
||||
description = "A dual-mode tool for directly communicating with sentient brains. It can be used to send a direct message to a target, \
|
||||
or to send a command to a test subject with a charged gland."
|
||||
id = "mental_interface"
|
||||
cost = 2
|
||||
build_path = /obj/item/abductor/mind_device
|
||||
category = "Advanced Gear"
|
||||
|
||||
/datum/abductor_gear/reagent_synthesizer
|
||||
name = "Reagent Synthesizer"
|
||||
description = "Synthesizes a variety of reagents using proto-matter."
|
||||
id = "reagent_synthesizer"
|
||||
cost = 2
|
||||
build_path = /obj/item/abductor_machine_beacon/chem_dispenser
|
||||
category = "Advanced Gear"
|
||||
|
||||
/datum/abductor_gear/shrink_ray
|
||||
name = "Shrink Ray Blaster"
|
||||
description = "This is a piece of frightening alien tech that enhances the magnetic pull of atoms in a localized space to temporarily make an object shrink. \
|
||||
That or it's just space magic. Either way, it shrinks stuff."
|
||||
id = "shrink_ray"
|
||||
cost = 2
|
||||
build_path = /obj/item/gun/energy/shrink_ray
|
||||
category = "Advanced Gear"
|
||||
@@ -23,102 +23,105 @@
|
||||
var/obj/machinery/abductor/pad/pad
|
||||
var/obj/machinery/computer/camera_advanced/abductor/camera
|
||||
var/list/datum/icon_snapshot/disguises = list()
|
||||
/// Currently selected gear category
|
||||
var/selected_cat
|
||||
/// Dictates if the compact mode of the interface is on or off
|
||||
var/compact_mode = FALSE
|
||||
/// Possible gear to be dispensed
|
||||
var/list/possible_gear
|
||||
|
||||
/obj/machinery/abductor/console/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
/obj/machinery/abductor/console/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(!HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING) && !HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING))
|
||||
to_chat(user, "<span class='warning'>You start mashing alien buttons at random!</span>")
|
||||
if(do_after(user,100, target = src))
|
||||
TeleporterSend()
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat = ""
|
||||
dat += "<H3> Abductsoft 3000 </H3>"
|
||||
|
||||
/obj/machinery/abductor/console/ui_status(mob/user)
|
||||
if(!isabductor(user) && !isobserver(user))
|
||||
return UI_CLOSE
|
||||
return ..()
|
||||
|
||||
/obj/machinery/abductor/console/ui_state(mob/user)
|
||||
return GLOB.physical_state
|
||||
|
||||
/obj/machinery/abductor/console/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "AbductorConsole", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/abductor/console/ui_static_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["categories"] = list()
|
||||
for(var/category in possible_gear)
|
||||
var/list/cat = list(
|
||||
"name" = category,
|
||||
"items" = (category == selected_cat ? list() : null))
|
||||
for(var/gear in possible_gear[category])
|
||||
var/datum/abductor_gear/AG = possible_gear[category][gear]
|
||||
cat["items"] += list(list(
|
||||
"name" = AG.name,
|
||||
"cost" = AG.cost,
|
||||
"desc" = AG.description,
|
||||
))
|
||||
data["categories"] += list(cat)
|
||||
return data
|
||||
|
||||
/obj/machinery/abductor/console/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["compactMode"] = compact_mode
|
||||
data["experiment"] = experiment ? TRUE : FALSE
|
||||
if(experiment)
|
||||
var/points = experiment.points
|
||||
var/credits = experiment.credits
|
||||
dat += "Collected Samples : [points] <br>"
|
||||
dat += "Gear Credits: [credits] <br>"
|
||||
dat += "<b>Transfer data in exchange for supplies:</b><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=baton'>Advanced Baton (2 Credits)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=mind_device'>Mental Interface Device (2 Credits)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=chem_dispenser'>Reagent Synthesizer (2 Credits)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=helmet'>Agent Helmet (1 Credit)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=vest'>Agent Vest (1 Credit)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=silencer'>Radio Silencer (1 Credit)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=tool'>Science Tool (1 Credit)</A><br>"
|
||||
dat += "<a href='?src=[REF(src)];dispense=tongue'>Superlingual Matrix (1 Credit)</a><br>"
|
||||
else
|
||||
dat += "<span class='bad'>NO EXPERIMENT MACHINE DETECTED</span> <br>"
|
||||
|
||||
data["points"] = experiment.points
|
||||
data["credits"] = experiment.credits
|
||||
data["pad"] = pad ? TRUE : FALSE
|
||||
if(pad)
|
||||
dat += "<span class='bad'>Emergency Teleporter System.</span>"
|
||||
dat += "<span class='bad'>Consider using primary observation console first.</span>"
|
||||
dat += "<a href='?src=[REF(src)];teleporter_send=1'>Activate Teleporter</A><br>"
|
||||
if(gizmo && gizmo.marked)
|
||||
dat += "<a href='?src=[REF(src)];teleporter_retrieve=1'>Retrieve Mark</A><br>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Retrieve Mark</span><br>"
|
||||
else
|
||||
dat += "<span class='bad'>NO TELEPAD DETECTED</span></br>"
|
||||
|
||||
data["gizmo"] = gizmo && gizmo.marked ? TRUE : FALSE
|
||||
data["vest"] = vest ? TRUE : FALSE
|
||||
if(vest)
|
||||
dat += "<h4> Agent Vest Mode </h4><br>"
|
||||
var/mode = vest.mode
|
||||
if(mode == VEST_STEALTH)
|
||||
dat += "<a href='?src=[REF(src)];flip_vest=1'>Combat</A>"
|
||||
dat += "<span class='linkOff'>Stealth</span>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Combat</span>"
|
||||
dat += "<a href='?src=[REF(src)];flip_vest=1'>Stealth</A>"
|
||||
data["vest_mode"] = vest.mode
|
||||
data["vest_lock"] = HAS_TRAIT_FROM(vest, TRAIT_NODROP, ABDUCTOR_VEST_TRAIT)
|
||||
return data
|
||||
|
||||
dat+="<br>"
|
||||
dat += "<a href='?src=[REF(src)];select_disguise=1'>Select Agent Vest Disguise</a><br>"
|
||||
dat += "<a href='?src=[REF(src)];toggle_vest=1'>[HAS_TRAIT_FROM(vest, TRAIT_NODROP, ABDUCTOR_VEST_TRAIT) ? "Unlock" : "Lock"] Vest</a><br>"
|
||||
else
|
||||
dat += "<span class='bad'>NO AGENT VEST DETECTED</span>"
|
||||
var/datum/browser/popup = new(user, "computer", "Abductor Console", 400, 500)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/abductor/console/Topic(href, href_list)
|
||||
if(..())
|
||||
/obj/machinery/abductor/console/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
usr.set_machine(src)
|
||||
if(href_list["teleporter_send"])
|
||||
TeleporterSend()
|
||||
else if(href_list["teleporter_retrieve"])
|
||||
TeleporterRetrieve()
|
||||
else if(href_list["flip_vest"])
|
||||
FlipVest()
|
||||
else if(href_list["toggle_vest"])
|
||||
if(vest)
|
||||
switch(action)
|
||||
if("buy")
|
||||
var/item_name = params["name"]
|
||||
var/list/buyable_items = list()
|
||||
for(var/category in possible_gear)
|
||||
buyable_items += possible_gear[category]
|
||||
for(var/key in buyable_items)
|
||||
var/datum/abductor_gear/AG = buyable_items[key]
|
||||
if(AG.name == item_name)
|
||||
Dispense(AG.build_path, AG.cost)
|
||||
return TRUE
|
||||
if("teleporter_send")
|
||||
TeleporterSend()
|
||||
return TRUE
|
||||
if("teleporter_retrieve")
|
||||
TeleporterRetrieve()
|
||||
return TRUE
|
||||
if("flip_vest")
|
||||
FlipVest()
|
||||
return TRUE
|
||||
if("toggle_vest")
|
||||
if(!vest)
|
||||
return
|
||||
vest.toggle_nodrop()
|
||||
else if(href_list["select_disguise"])
|
||||
SelectDisguise()
|
||||
else if(href_list["dispense"])
|
||||
switch(href_list["dispense"])
|
||||
if("baton")
|
||||
Dispense(/obj/item/abductor/baton,cost=2)
|
||||
if("helmet")
|
||||
Dispense(/obj/item/clothing/head/helmet/abductor)
|
||||
if("silencer")
|
||||
Dispense(/obj/item/abductor/silencer)
|
||||
if("tool")
|
||||
Dispense(/obj/item/abductor/gizmo)
|
||||
if("vest")
|
||||
Dispense(/obj/item/clothing/suit/armor/abductor/vest)
|
||||
if("mind_device")
|
||||
Dispense(/obj/item/abductor/mind_device,cost=2)
|
||||
if("chem_dispenser")
|
||||
Dispense(/obj/item/abductor_machine_beacon/chem_dispenser,cost=2)
|
||||
if("tongue")
|
||||
Dispense(/obj/item/organ/tongue/abductor)
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
if("select_disguise")
|
||||
SelectDisguise()
|
||||
return TRUE
|
||||
if("select")
|
||||
selected_cat = params["category"]
|
||||
return TRUE
|
||||
if("compact_toggle")
|
||||
compact_mode = !compact_mode
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/abductor/console/proc/TeleporterRetrieve()
|
||||
if(pad && gizmo && gizmo.marked)
|
||||
@@ -159,7 +162,6 @@
|
||||
pad.teleport_target = location
|
||||
to_chat(user, "<span class='notice'>Location marked as test subject release point.</span>")
|
||||
|
||||
|
||||
/obj/machinery/abductor/console/Initialize(mapload)
|
||||
..()
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
@@ -22,41 +22,44 @@
|
||||
gland_colors[i] = random_color()
|
||||
amounts[i] = rand(1,5)
|
||||
|
||||
/obj/machinery/abductor/gland_dispenser/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/machinery/abductor/gland_dispenser/ui_status(mob/user)
|
||||
if(!isabductor(user) && !isobserver(user))
|
||||
return UI_CLOSE
|
||||
return ..()
|
||||
|
||||
/obj/machinery/abductor/gland_dispenser/ui_state(mob/user)
|
||||
return GLOB.physical_state
|
||||
|
||||
/obj/machinery/abductor/gland_dispenser/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "GlandDispenser", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/abductor/gland_dispenser/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["glands"] = list()
|
||||
for(var/gland_number=1,gland_number<=gland_colors.len,gland_number++)
|
||||
var/list/gland_information = list(
|
||||
"color" = gland_colors[gland_number],
|
||||
"amount" = amounts[gland_number],
|
||||
"id" = gland_number,
|
||||
)
|
||||
data["glands"] += list(gland_information)
|
||||
return data
|
||||
|
||||
/obj/machinery/abductor/gland_dispenser/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!isabductor(user))
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/box_css = {"
|
||||
<style>
|
||||
a.box.gland {
|
||||
float: left;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 5px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: rgba(0,0,0,.2);
|
||||
text-align: center;
|
||||
}
|
||||
</style>"}
|
||||
var/dat = ""
|
||||
var/item_count = 0
|
||||
for(var/i=1,i<=gland_colors.len,i++)
|
||||
item_count++
|
||||
var/g_color = gland_colors[i]
|
||||
var/amount = amounts[i]
|
||||
dat += "<a class='box gland' style='background-color:[g_color]' href='?src=[REF(src)];dispense=[i]'>[amount]</a>"
|
||||
if(item_count == 4) // Four boxes per line
|
||||
dat +="</br></br>"
|
||||
item_count = 0
|
||||
var/datum/browser/popup = new(user, "glands", "Gland Dispenser", 200, 200)
|
||||
popup.add_head_content(box_css)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("dispense")
|
||||
var/gland_id = text2num(params["gland_id"])
|
||||
if(!gland_id)
|
||||
return
|
||||
Dispense(gland_id)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/abductor/gland_dispenser/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/organ/heart/gland))
|
||||
@@ -68,15 +71,6 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/abductor/gland_dispenser/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["dispense"])
|
||||
Dispense(text2num(href_list["dispense"]))
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/abductor/gland_dispenser/proc/Dispense(count)
|
||||
if(amounts[count]>0)
|
||||
amounts[count]--
|
||||
|
||||
@@ -15,19 +15,13 @@
|
||||
var/breakout_time = 450
|
||||
|
||||
/obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
|
||||
var/mob/living/L = user
|
||||
if(user.stat || (isliving(user) && (!(L.mobility_flags & MOBILITY_STAND) || !(L.mobility_flags & MOBILITY_UI))) || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
|
||||
return
|
||||
if(isabductor(target))
|
||||
return
|
||||
close_machine(target)
|
||||
|
||||
/obj/machinery/abductor/experiment/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
experimentUI(user)
|
||||
|
||||
/obj/machinery/abductor/experiment/open_machine()
|
||||
if(!state_open && !panel_open)
|
||||
..()
|
||||
@@ -47,11 +41,9 @@
|
||||
to_chat(user, "<span class='warning'>[src]'s door won't budge!</span>")
|
||||
|
||||
/obj/machinery/abductor/experiment/container_resist(mob/living/user)
|
||||
user.changeNext_move(CLICK_CD_BREAKOUT)
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
|
||||
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a metallic creaking from [src].</span>")
|
||||
"<span class='hear'>You hear a metallic creaking from [src].</span>")
|
||||
if(do_after(user,(breakout_time), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open)
|
||||
return
|
||||
@@ -59,122 +51,84 @@
|
||||
"<span class='notice'>You successfully break out of [src]!</span>")
|
||||
open_machine()
|
||||
|
||||
/obj/machinery/abductor/experiment/proc/dissection_icon(mob/living/carbon/human/H)
|
||||
var/icon/photo = null
|
||||
var/g = (H.dna.features["body_model"] == FEMALE) ? "f" : "m"
|
||||
if(H.dna.species.use_skintones)
|
||||
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.skin_tone]_[g]")
|
||||
else
|
||||
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.dna.species.id]_[g]")
|
||||
photo.Blend("#[H.dna.features["mcolor"]]", ICON_MULTIPLY)
|
||||
/obj/machinery/abductor/experiment/ui_status(mob/user)
|
||||
if(user == occupant)
|
||||
return UI_CLOSE
|
||||
return ..()
|
||||
|
||||
var/icon/eyes
|
||||
if(EYECOLOR in H.dna.species.species_traits)
|
||||
eyes = icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "eyes")
|
||||
eyes.Blend("#[H.eye_color]", ICON_MULTIPLY)
|
||||
/obj/machinery/abductor/experiment/ui_state(mob/user)
|
||||
return GLOB.physical_state
|
||||
|
||||
var/datum/sprite_accessory/S
|
||||
S = GLOB.hair_styles_list[H.hair_style]
|
||||
if(S && (HAIR in H.dna.species.species_traits))
|
||||
var/icon/hair = icon("icon" = S.icon, "icon_state" = "[S.icon_state]")
|
||||
hair.Blend("#[H.hair_color]", ICON_MULTIPLY)
|
||||
eyes.Blend(hair, ICON_OVERLAY)
|
||||
/obj/machinery/abductor/experiment/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ProbingConsole", name)
|
||||
ui.open()
|
||||
|
||||
S = GLOB.facial_hair_styles_list[H.facial_hair_style]
|
||||
if(S && (FACEHAIR in H.dna.species.species_traits))
|
||||
var/icon/facial = icon("icon" = S.icon, "icon_state" = "[S.icon_state]")
|
||||
facial.Blend("#[H.facial_hair_color]", ICON_MULTIPLY)
|
||||
eyes.Blend(facial, ICON_OVERLAY)
|
||||
|
||||
if(eyes)
|
||||
photo.Blend(eyes, ICON_OVERLAY)
|
||||
|
||||
var/icon/splat = icon("icon" = 'icons/mob/dam_mob.dmi',"icon_state" = "chest30")
|
||||
photo.Blend(splat,ICON_OVERLAY)
|
||||
|
||||
return photo
|
||||
|
||||
/obj/machinery/abductor/experiment/proc/experimentUI(mob/user)
|
||||
var/dat
|
||||
dat += "<h3> Experiment </h3>"
|
||||
if(occupant)
|
||||
var/obj/item/photo/P = new
|
||||
P.picture = new
|
||||
P.picture.picture_image = icon(dissection_icon(occupant), dir = SOUTH)
|
||||
user << browse_rsc(P.picture.picture_image, "dissection_img")
|
||||
dat += "<table><tr><td>"
|
||||
dat += "<img src=dissection_img height=80 width=80>" //Avert your eyes
|
||||
dat += "</td><td>"
|
||||
dat += "<a href='?src=[REF(src)];experiment=1'>Probe</a><br>"
|
||||
dat += "<a href='?src=[REF(src)];experiment=2'>Dissect</a><br>"
|
||||
dat += "<a href='?src=[REF(src)];experiment=3'>Analyze</a><br>"
|
||||
dat += "</td></tr></table>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Experiment </span>"
|
||||
|
||||
if(!occupant)
|
||||
dat += "<h3>Machine Unoccupied</h3>"
|
||||
else
|
||||
dat += "<h3>Subject Status : </h3>"
|
||||
dat += "[occupant.name] => "
|
||||
var/mob/living/mob_occupant = occupant
|
||||
switch(mob_occupant.stat)
|
||||
if(CONSCIOUS)
|
||||
dat += "<span class='good'>Conscious</span>"
|
||||
if(UNCONSCIOUS)
|
||||
dat += "<span class='average'>Unconscious</span>"
|
||||
else // DEAD
|
||||
dat += "<span class='bad'>Deceased</span>"
|
||||
dat += "<br>"
|
||||
dat += "[flash]"
|
||||
dat += "<br>"
|
||||
dat += "<a href='?src=[REF(src)];refresh=1'>Scan</a>"
|
||||
dat += "<a href='?src=[REF(src)];[state_open ? "close=1'>Close</a>" : "open=1'>Open</a>"]"
|
||||
var/datum/browser/popup = new(user, "experiment", "Probing Console", 300, 300)
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/abductor/experiment/Topic(href, href_list)
|
||||
if(..() || usr == occupant)
|
||||
return
|
||||
usr.set_machine(src)
|
||||
if(href_list["refresh"])
|
||||
updateUsrDialog()
|
||||
return
|
||||
if(href_list["open"])
|
||||
open_machine()
|
||||
return
|
||||
if(href_list["close"])
|
||||
close_machine()
|
||||
return
|
||||
/obj/machinery/abductor/experiment/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["open"] = state_open
|
||||
data["feedback"] = flash
|
||||
data["occupant"] = occupant ? TRUE : FALSE
|
||||
data["occupant_name"] = null
|
||||
data["occupant_status"] = null
|
||||
if(occupant)
|
||||
var/mob/living/mob_occupant = occupant
|
||||
if(mob_occupant.stat != DEAD)
|
||||
if(href_list["experiment"])
|
||||
flash = Experiment(occupant,href_list["experiment"],usr)
|
||||
updateUsrDialog()
|
||||
add_fingerprint(usr)
|
||||
data["occupant_name"] = mob_occupant.name
|
||||
data["occupant_status"] = mob_occupant.stat
|
||||
return data
|
||||
|
||||
/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type,mob/user)
|
||||
/obj/machinery/abductor/experiment/ui_act(action, list/params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("door")
|
||||
if(state_open)
|
||||
close_machine()
|
||||
return TRUE
|
||||
else
|
||||
open_machine()
|
||||
return TRUE
|
||||
if("experiment")
|
||||
if(!occupant)
|
||||
return
|
||||
var/mob/living/mob_occupant = occupant
|
||||
if(mob_occupant.stat == DEAD)
|
||||
return
|
||||
flash = experiment(occupant, params["experiment_type"], usr)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* experiment: Performs selected experiment on occupant mob, resulting in a point reward on success
|
||||
*
|
||||
* Arguments:
|
||||
* * occupant The mob inside the machine
|
||||
* * type The type of experiment to be performed
|
||||
* * user The mob starting the experiment
|
||||
*/
|
||||
/obj/machinery/abductor/experiment/proc/experiment(mob/occupant, type, mob/user)
|
||||
LAZYINITLIST(history)
|
||||
var/mob/living/carbon/human/H = occupant
|
||||
|
||||
var/datum/antagonist/abductor/user_abductor = user.mind.has_antag_datum(/datum/antagonist/abductor)
|
||||
if(!user_abductor)
|
||||
return "<span class='bad'>Authorization failure. Contact mothership immidiately.</span>"
|
||||
return "Authorization failure. Contact mothership immediately."
|
||||
|
||||
var/point_reward = 0
|
||||
if(!H)
|
||||
return "Invalid or missing specimen."
|
||||
if(H in history)
|
||||
return "<span class='bad'>Specimen already in database.</span>"
|
||||
return "Specimen already in database."
|
||||
if(H.stat == DEAD)
|
||||
say("Specimen deceased - please provide fresh sample.")
|
||||
return "<span class='bad'>Specimen deceased.</span>"
|
||||
return "Specimen deceased."
|
||||
var/obj/item/organ/heart/gland/GlandTest = locate() in H.internal_organs
|
||||
if(!GlandTest)
|
||||
say("Experimental dissection not detected!")
|
||||
return "<span class='bad'>No glands detected!</span>"
|
||||
if(H.mind != null && (H.voluntary_ghosted || (H.ckey != null)))
|
||||
return "No glands detected!"
|
||||
if(H.mind != null && H.ckey != null)
|
||||
LAZYINITLIST(abductee_minds)
|
||||
LAZYADD(history, H)
|
||||
LAZYADD(abductee_minds, H.mind)
|
||||
@@ -196,22 +150,27 @@
|
||||
point_reward++
|
||||
if(point_reward > 0)
|
||||
open_machine()
|
||||
SendBack(H)
|
||||
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
|
||||
send_back(H)
|
||||
playsound(src.loc, 'sound/machines/ding.ogg', 50, TRUE)
|
||||
points += point_reward
|
||||
credits += point_reward
|
||||
return "<span class='good'>Experiment successful! [point_reward] new data-points collected.</span>"
|
||||
return "Experiment successful! [point_reward] new data-points collected."
|
||||
else
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
|
||||
return "<span class='bad'>Experiment failed! No replacement organ detected.</span>"
|
||||
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
|
||||
return "Experiment failed! No replacement organ detected."
|
||||
else
|
||||
say("Brain activity nonexistent - disposing sample...")
|
||||
open_machine()
|
||||
SendBack(H)
|
||||
return "<span class='bad'>Specimen braindead - disposed.</span>"
|
||||
send_back(H)
|
||||
return "Specimen braindead - disposed."
|
||||
|
||||
|
||||
/obj/machinery/abductor/experiment/proc/SendBack(mob/living/carbon/human/H)
|
||||
/**
|
||||
* send_back: Sends a mob back to a selected teleport location if safe
|
||||
*
|
||||
* Arguments:
|
||||
* * H The human mob to be sent back
|
||||
*/
|
||||
/obj/machinery/abductor/experiment/proc/send_back(mob/living/carbon/human/H)
|
||||
H.Sleeping(160)
|
||||
H.uncuff()
|
||||
if(console && console.pad && console.pad.teleport_target)
|
||||
@@ -221,7 +180,6 @@
|
||||
SSjob.SendToLateJoin(H, FALSE)
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/abductor/experiment/update_icon_state()
|
||||
if(state_open)
|
||||
icon_state = "experiment-open"
|
||||
|
||||
@@ -36,6 +36,6 @@
|
||||
M.adjust_fire_stacks(round(reac_volume/10))
|
||||
M.IgniteMob()
|
||||
if(M)
|
||||
M.apply_damage(0.8*reac_volume, BURN)
|
||||
M.apply_damage(0.8*reac_volume, BURN, wound_bonus=CANT_WOUND)
|
||||
if(iscarbon(M))
|
||||
M.emote("scream")
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
M.reagents.add_reagent("frostoil", 0.3*reac_volume)
|
||||
M.reagents.add_reagent("ice", 0.3*reac_volume)
|
||||
M.reagents.add_reagent("cryogenic_poison", 0.3*reac_volume)
|
||||
M.apply_damage(0.2*reac_volume, BRUTE)
|
||||
M.apply_damage(0.2*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
|
||||
|
||||
/datum/reagent/blob/cryogenic_poison/on_mob_life(mob/living/carbon/M)
|
||||
M.adjustBruteLoss(0.3*REAGENTS_EFFECT_MULTIPLIER, 0)
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
if(prob(reac_volume*2))
|
||||
M.emp_act(EMP_LIGHT)
|
||||
if(M)
|
||||
M.apply_damage(reac_volume, BURN)
|
||||
M.apply_damage(reac_volume, BURN, wound_bonus=CANT_WOUND)
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
if(ROLE_BLOB in L.faction) //no friendly fire
|
||||
continue
|
||||
var/aoe_volume = ..(L, TOUCH, initial_volume, 0, L.get_permeability_protection(), O)
|
||||
L.apply_damage(0.4*aoe_volume, BRUTE)
|
||||
L.apply_damage(0.4*aoe_volume, BRUTE, wound_bonus=CANT_WOUND)
|
||||
if(M)
|
||||
M.apply_damage(0.6*reac_volume, BRUTE)
|
||||
M.apply_damage(0.6*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
|
||||
else
|
||||
M.apply_damage(0.6*reac_volume, BRUTE)
|
||||
M.apply_damage(0.6*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
|
||||
|
||||
@@ -33,6 +33,6 @@
|
||||
|
||||
/datum/reagent/blob/networked_fibers/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
|
||||
reac_volume = ..()
|
||||
M.apply_damage(0.6*reac_volume, BRUTE)
|
||||
M.apply_damage(0.6*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
|
||||
if(M)
|
||||
M.apply_damage(0.6*reac_volume, BURN)
|
||||
M.apply_damage(0.6*reac_volume, BURN, wound_bonus=CANT_WOUND)
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
T.MakeSlippery(TURF_WET_LUBE, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
|
||||
M.adjust_fire_stacks(-(reac_volume / 10))
|
||||
M.ExtinguishMob()
|
||||
M.apply_damage(0.4*reac_volume, BRUTE)
|
||||
M.apply_damage(0.4*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
|
||||
if(M)
|
||||
M.apply_damage(0.4*reac_volume, OXY)
|
||||
if(M)
|
||||
|
||||
@@ -31,4 +31,4 @@
|
||||
|
||||
/datum/reagent/blob/replicating_foam/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
|
||||
reac_volume = ..()
|
||||
M.apply_damage(0.7*reac_volume, BRUTE)
|
||||
M.apply_damage(0.7*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
|
||||
|
||||
@@ -32,4 +32,4 @@
|
||||
|
||||
/datum/reagent/blob/shifting_fragments/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
|
||||
reac_volume = ..()
|
||||
M.apply_damage(0.7*reac_volume, BRUTE)
|
||||
M.apply_damage(0.7*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
|
||||
/datum/reagent/blob/synchronous_mesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/O)
|
||||
reac_volume = ..()
|
||||
M.apply_damage(0.2*reac_volume, BRUTE)
|
||||
M.apply_damage(0.2*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
|
||||
if(M && reac_volume)
|
||||
for(var/obj/structure/blob/B in range(1, M)) //if the target is completely surrounded, this is 2.4*reac_volume bonus damage, total of 2.6*reac_volume
|
||||
if(M)
|
||||
B.blob_attack_animation(M) //show them they're getting a bad time
|
||||
M.apply_damage(0.3*reac_volume, BRUTE)
|
||||
M.apply_damage(0.3*reac_volume, BRUTE, wound_bonus=CANT_WOUND)
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
|
||||
/obj/structure/blob/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/analyzer))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.DelayNextAction(CLICK_CD_MELEE)
|
||||
to_chat(user, "<b>The analyzer beeps once, then reports:</b><br>")
|
||||
SEND_SOUND(user, sound('sound/machines/ping.ogg'))
|
||||
if(overmind)
|
||||
|
||||
@@ -10,26 +10,24 @@
|
||||
//
|
||||
// Show as dead when...
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/LifeTick()// Should probably run from life.dm, same as handle_changeling, but will be an utter pain to move
|
||||
set waitfor = FALSE // Don't make on_gain() wait for this function to finish. This lets this code run on the side.
|
||||
var/notice_healing
|
||||
while(owner && !AmFinalDeath()) // owner.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) == src
|
||||
if(owner.current.stat == CONSCIOUS && !poweron_feed && !HAS_TRAIT(owner.current, TRAIT_FAKEDEATH)) // Deduct Blood
|
||||
AddBloodVolume(passive_blood_drain) // -.1 currently
|
||||
if(HandleHealing(1)) // Heal
|
||||
if(!notice_healing && owner.current.blood_volume > 0)
|
||||
to_chat(owner, "<span class='notice'>The power of your blood begins knitting your wounds...</span>")
|
||||
notice_healing = TRUE
|
||||
else if(notice_healing == TRUE)
|
||||
notice_healing = FALSE // Apply Low Blood Effects
|
||||
HandleStarving() // Death
|
||||
HandleDeath() // Standard Update
|
||||
update_hud()// Daytime Sleep in Coffin
|
||||
if(SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker"))
|
||||
if(istype(owner.current.loc, /obj/structure/closet/crate/coffin))
|
||||
Torpor_Begin()
|
||||
// Wait before next pass
|
||||
sleep(10)
|
||||
/datum/antagonist/bloodsucker/proc/LifeTick() //Runs from BiologicalLife, handles all the bloodsucker constant proccesses
|
||||
if(!owner || AmFinalDeath())
|
||||
return
|
||||
if(owner.current.stat == CONSCIOUS && !poweron_feed && !HAS_TRAIT(owner.current, TRAIT_FAKEDEATH)) // Deduct Blood
|
||||
AddBloodVolume(passive_blood_drain) // -.1 currently
|
||||
if(HandleHealing(1)) // Heal
|
||||
if(!notice_healing && owner.current.blood_volume > 0)
|
||||
to_chat(owner, "<span class='notice'>The power of your blood begins knitting your wounds...</span>")
|
||||
notice_healing = TRUE
|
||||
else if(notice_healing)
|
||||
notice_healing = FALSE // Apply Low Blood Effects
|
||||
HandleStarving() // Death
|
||||
HandleDeath() // Standard Update
|
||||
update_hud()// Daytime Sleep in Coffin
|
||||
if(SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker"))
|
||||
if(istype(owner.current.loc, /obj/structure/closet/crate/coffin))
|
||||
Torpor_Begin()
|
||||
// Wait before next pass
|
||||
FreeAllVassals() // Free my Vassals! (if I haven't yet)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -272,13 +270,15 @@
|
||||
|
||||
/datum/antagonist/bloodsucker/AmFinalDeath()
|
||||
return owner && owner.AmFinalDeath()
|
||||
/datum/antagonist/changeling/AmFinalDeath()
|
||||
return owner && owner.AmFinalDeath()
|
||||
|
||||
/datum/mind/proc/AmFinalDeath()
|
||||
return !current || QDELETED(current) || !isliving(current) || isbrain(current) || !get_turf(current) // NOTE: "isliving()" is not the same as STAT == CONSCIOUS. This is to make sure you're not a BORG (aka silicon)
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/FinalDeath()
|
||||
//Dont bother if we are already supposed to be dead
|
||||
if(FinalDeath)
|
||||
return
|
||||
FinalDeath = TRUE //We are now supposed to die. Lets not spam it.
|
||||
if(!iscarbon(owner.current)) //Check for non carbons.
|
||||
owner.current.gib()
|
||||
return
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
var/had_toxlover
|
||||
var/level_bloodcost
|
||||
var/passive_blood_drain = -0.1 //The amount of blood we loose each bloodsucker life() tick
|
||||
var/notice_healing //Var to see if you are healing for preventing spam of the chat message inform the user of such
|
||||
var/FinalDeath //Have we reached final death? Used to prevent spam.
|
||||
// LISTS
|
||||
var/static/list/defaultTraits = list (TRAIT_STABLEHEART, TRAIT_NOBREATH, TRAIT_SLEEPIMMUNE, TRAIT_NOCRITDAMAGE, TRAIT_RESISTCOLD, TRAIT_RADIMMUNE, TRAIT_NIGHT_VISION, \
|
||||
TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_AGEUSIA, TRAIT_COLDBLOODED, TRAIT_NONATURALHEAL, TRAIT_NOMARROW, TRAIT_NOPULSE, TRAIT_VIRUSIMMUNE, TRAIT_NODECAP, TRAIT_NOGUT)
|
||||
@@ -50,7 +52,6 @@
|
||||
AssignStarterPowersAndStats()// Give Powers & Stats
|
||||
forge_bloodsucker_objectives()// Objectives & Team
|
||||
update_bloodsucker_icons_added(owner.current, "bloodsucker") // Add Antag HUD
|
||||
LifeTick() // Run Life Function
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -683,6 +684,8 @@
|
||||
owner.current.hud_used.sunlight_display.invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/datum/antagonist/bloodsucker/proc/update_hud(updateRank=FALSE)
|
||||
if(FinalDeath)
|
||||
return
|
||||
// No Hud? Get out.
|
||||
if(!owner.current.hud_used)
|
||||
return
|
||||
|
||||
@@ -217,7 +217,7 @@
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/structure/bloodsucker/vassalrack/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/structure/bloodsucker/vassalrack/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
//. = ..() // Taken from sacrificial altar in divine.dm
|
||||
//if(.)
|
||||
// return
|
||||
@@ -361,9 +361,9 @@
|
||||
torture_time -= I.force / 4
|
||||
torture_dmg_brute += I.force / 4
|
||||
//torture_dmg_burn += I.
|
||||
if(I.sharpness == IS_SHARP)
|
||||
if(I.sharpness == SHARP_EDGED)
|
||||
torture_time -= 1
|
||||
else if(I.sharpness == IS_SHARP_ACCURATE)
|
||||
else if(I.sharpness == SHARP_POINTY)
|
||||
torture_time -= 2
|
||||
if(istype(I, /obj/item/weldingtool))
|
||||
var/obj/item/weldingtool/welder = I
|
||||
@@ -469,7 +469,7 @@
|
||||
. += {"<span class='cult'>This is a magical candle which drains at the sanity of the fools who havent yet accepted your master, as long as it is active.\n
|
||||
You can turn it on and off by clicking on it while you are next to it</span>"} */
|
||||
|
||||
/obj/structure/bloodsucker/candelabrum/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/structure/bloodsucker/candelabrum/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
var/datum/antagonist/vassal/T = user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
|
||||
if(AmBloodsucker(user) || istype(T))
|
||||
toggle()
|
||||
|
||||
@@ -226,7 +226,9 @@
|
||||
playsound(get_turf(target), 'sound/effects/splat.ogg', 40, 1)
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.bleed_rate += 5
|
||||
var/obj/item/bodypart/head_part = H.get_bodypart(BODY_ZONE_HEAD)
|
||||
if(head_part)
|
||||
head_part.generic_bleedstacks += 5
|
||||
target.add_splatter_floor(get_turf(target))
|
||||
user.add_mob_blood(target) // Put target's blood on us. The donor goes in the ( )
|
||||
target.add_mob_blood(target)
|
||||
|
||||
@@ -128,11 +128,9 @@
|
||||
target.face_atom(L)
|
||||
target.Stun(power_time)
|
||||
to_chat(L, "<span class='notice'>[target] is fixed in place by your hypnotic gaze.</span>")
|
||||
target.next_move = world.time + power_time // <--- Use direct change instead. We want an unmodified delay to their next move // target.changeNext_move(power_time) // check click.dm
|
||||
target.mob_transforming = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
|
||||
target.DelayNextAction(power_time)
|
||||
spawn(power_time)
|
||||
if(istype(target) && success)
|
||||
target.mob_transforming = FALSE
|
||||
if(istype(L) && target.stat == CONSCIOUS && (target in L.fov_view(10))) // They Woke Up! (Notice if within view)
|
||||
to_chat(L, "<span class='warning'>[target] has snapped out of their trance.</span>")
|
||||
|
||||
|
||||
@@ -27,8 +27,9 @@
|
||||
C.blood_volume -= 0.2
|
||||
C.adjustStaminaLoss(-15)
|
||||
// Stop Bleeding
|
||||
if(istype(H) && H.bleed_rate > 0 && rand(20) == 0)
|
||||
H.bleed_rate --
|
||||
if(istype(H) && H.is_bleeding() && rand(20) == 0)
|
||||
for(var/obj/item/bodypart/part in H.bodyparts)
|
||||
part.generic_bleedstacks --
|
||||
C.Jitter(5)
|
||||
sleep(10)
|
||||
// DONE!
|
||||
|
||||
@@ -81,9 +81,7 @@
|
||||
var/mist_delay = max(5, 20 - level_current * 2.5) // Level up and do this faster.
|
||||
|
||||
// Freeze Me
|
||||
user.next_move = world.time + mist_delay
|
||||
user.Stun(mist_delay, ignore_canstun = TRUE)
|
||||
user.mob_transforming = TRUE
|
||||
user.density = FALSE
|
||||
var/invis_was = user.invisibility
|
||||
user.invisibility = INVISIBILITY_MAXIMUM
|
||||
@@ -96,7 +94,6 @@
|
||||
// Move & Freeze
|
||||
if(isturf(target_turf))
|
||||
do_teleport(owner, target_turf, no_effects=TRUE, channel = TELEPORT_CHANNEL_QUANTUM) // in teleport.dm?
|
||||
user.next_move = world.time + mist_delay / 2
|
||||
user.Stun(mist_delay / 2, ignore_canstun = TRUE)
|
||||
|
||||
// Wait...
|
||||
@@ -104,9 +101,7 @@
|
||||
|
||||
// Un-Hide & Freeze
|
||||
user.dir = get_dir(my_turf, target_turf)
|
||||
user.next_move = world.time + mist_delay / 2
|
||||
user.Stun(mist_delay / 2, ignore_canstun = TRUE)
|
||||
user.mob_transforming = FALSE
|
||||
user.density = 1
|
||||
user.invisibility = invis_was
|
||||
|
||||
|
||||
@@ -13,10 +13,13 @@
|
||||
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)
|
||||
/datum/cellular_emporium/ui_state(mob/user)
|
||||
return GLOB.always_state
|
||||
|
||||
/datum/cellular_emporium/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "CellularEmporium", name, 900, 480, master_ui, state)
|
||||
ui = new(user, src, "CellularEmporium", name)
|
||||
ui.open()
|
||||
|
||||
/datum/cellular_emporium/ui_data(mob/user)
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
var/datum/changelingprofile/first_prof = null
|
||||
var/dna_max = 6 //How many extra DNA strands the changeling can store for transformation.
|
||||
var/absorbedcount = 0
|
||||
/// did we get succed by another changeling
|
||||
var/hostile_absorbed = FALSE
|
||||
var/trueabsorbs = 0//dna gained using absorb, not dna sting
|
||||
var/chem_charges = 20
|
||||
var/chem_storage = 75
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
|
||||
|
||||
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!
|
||||
if(target_ling && !target_ling.hostile_absorbed)//If the target was a changeling, suck out their extra juice and objective points!
|
||||
to_chat(user, "<span class='boldnotice'>[target] was one of us. We have absorbed their power.</span>")
|
||||
target_ling.remove_changeling_powers()
|
||||
changeling.geneticpoints += round(target_ling.geneticpoints/2)
|
||||
@@ -102,6 +102,7 @@
|
||||
changeling.chem_storage += round(target_ling.chem_storage/2)
|
||||
changeling.chem_charges += min(target_ling.chem_charges, changeling.chem_storage)
|
||||
target_ling.chem_charges = 0
|
||||
target_ling.hostile_absorbed = TRUE
|
||||
target_ling.chem_storage = 0
|
||||
changeling.absorbedcount += (target_ling.absorbedcount)
|
||||
target_ling.stored_profiles.len = 1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/obj/effect/proc_holder/changeling/fleshmend
|
||||
name = "Fleshmend"
|
||||
desc = "Our flesh rapidly regenerates, healing our burns, bruises, and shortness of breath. Functions while unconscious. This ability is loud, and might cause our blood to react violently to heat."
|
||||
desc = "Our flesh rapidly regenerates, healing our burns, bruises, and shortness of breath, as well as hiding all of our scars. Costs 20 chemicals."
|
||||
helptext = "If we are on fire, the healing effect will not function. Does not regrow limbs or restore lost blood."
|
||||
chemical_cost = 20
|
||||
loudness = 2
|
||||
|
||||
@@ -164,7 +164,9 @@
|
||||
armour_penetration = 20
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
sharpness = IS_SHARP
|
||||
sharpness = SHARP_EDGED
|
||||
wound_bonus = -60
|
||||
bare_wound_bonus = 20
|
||||
var/can_drop = FALSE
|
||||
var/fake = FALSE
|
||||
total_mass = TOTAL_MASS_HAND_REPLACEMENT
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
C.emote("scream")
|
||||
C.regenerate_limbs(1)
|
||||
C.regenerate_organs()
|
||||
for(var/i in C.all_wounds)
|
||||
var/datum/wound/iter_wound = i
|
||||
iter_wound.remove_wound()
|
||||
if(!user.getorganslot(ORGAN_SLOT_BRAIN))
|
||||
var/obj/item/organ/brain/B
|
||||
if(C.has_dna() && C.dna.species.mutant_brain)
|
||||
|
||||
@@ -36,9 +36,10 @@
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
if(HAS_TRAIT(user, CHANGELING_DRAIN) || ((user.stat != DEAD) && !(HAS_TRAIT(user, TRAIT_DEATHCOMA))))
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
if(changeling.hostile_absorbed || ((user.stat != DEAD) && !(HAS_TRAIT(user, TRAIT_DEATHCOMA))))
|
||||
changeling.purchasedpowers -= src
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clothing/glasses/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/item/clothing/glasses/changeling/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
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)
|
||||
@@ -33,8 +32,7 @@
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clothing/under/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/item/clothing/under/changeling/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
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)
|
||||
@@ -50,8 +48,7 @@
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clothing/suit/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/item/clothing/suit/changeling/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
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)
|
||||
@@ -65,8 +62,7 @@
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clothing/head/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/item/clothing/head/changeling/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
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)
|
||||
@@ -81,8 +77,7 @@
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clothing/shoes/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/item/clothing/shoes/changeling/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
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)
|
||||
@@ -97,8 +92,7 @@
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clothing/gloves/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/item/clothing/gloves/changeling/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
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)
|
||||
@@ -113,8 +107,7 @@
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clothing/mask/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/item/clothing/mask/changeling/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
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)
|
||||
@@ -131,8 +124,7 @@
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/changeling/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/item/changeling/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
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)
|
||||
|
||||
@@ -36,8 +36,7 @@
|
||||
return
|
||||
. = ..()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/effect/clockwork/city_of_cogs_rift/attack_hand(atom/movable/AM)
|
||||
/obj/effect/clockwork/city_of_cogs_rift/on_attack_hand(atom/movable/AM)
|
||||
beckon(AM)
|
||||
|
||||
/obj/effect/clockwork/city_of_cogs_rift/Bumped(atom/movable/AM)
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
/obj/effect/clockwork/sigil/attack_tk(mob/user)
|
||||
return //you can't tk stomp sigils, but you can hit them with something
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/effect/clockwork/sigil/attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/effect/clockwork/sigil/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(iscarbon(user) && !user.stat)
|
||||
if(is_servant_of_ratvar(user) && user.a_intent != INTENT_HARM)
|
||||
return ..()
|
||||
@@ -217,6 +216,20 @@
|
||||
else if(get_clockwork_power())
|
||||
to_chat(L, "<span class='brass'>You feel a slight, static shock.</span>")
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/process()
|
||||
var/power_drained = 0
|
||||
var/power_mod = 0.005
|
||||
for(var/t in spiral_range_turfs(SIGIL_ACCESS_RANGE, src))
|
||||
var/turf/T = t
|
||||
for(var/M in T)
|
||||
var/atom/movable/A = M
|
||||
power_drained += A.power_drain(TRUE)
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
adjust_clockwork_power(power_drained * power_mod * 15)
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transmission(loc, 1 + (power_drained * 0.0035))
|
||||
|
||||
/obj/effect/clockwork/sigil/transmission/proc/charge_cyborg(mob/living/silicon/robot/cyborg)
|
||||
if(!cyborg_checks(cyborg))
|
||||
return
|
||||
@@ -392,3 +405,49 @@
|
||||
animation_number = initial(animation_number)
|
||||
sigil_active = FALSE
|
||||
animate(src, alpha = initial(alpha), time = 10, flags = ANIMATION_END_NOW)
|
||||
|
||||
/obj/effect/clockwork/sigil/rite
|
||||
name = "radiant sigil"
|
||||
desc = "A glowing sigil glowing with barely-contained power."
|
||||
clockwork_desc = "A sigil that will allow you to perform certain rites on it, provided you have access to sufficient power and materials."
|
||||
icon_state = "sigiltransmission" //am big lazy - recolored transmission sigil
|
||||
sigil_name = "Sigil of Rites"
|
||||
alpha = 255
|
||||
var/performing_rite = FALSE
|
||||
color = "#ffe63a"
|
||||
light_color = "#ffe63a"
|
||||
light_range = 1
|
||||
light_power = 2
|
||||
|
||||
/obj/effect/clockwork/sigil/rite/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return
|
||||
if(!GLOB.all_clockwork_rites.len) //Did we already generate the list?
|
||||
generate_all_rites()
|
||||
if(performing_rite)
|
||||
to_chat(user, "<span class='warning'>Someone is already performing a rite here!")
|
||||
return
|
||||
var/list/possible_rites = list()
|
||||
for(var/datum/clockwork_rite/R in GLOB.all_clockwork_rites)
|
||||
possible_rites[R] = R
|
||||
var/input_key = input(user, "Choose a rite", "Choosing a rite") as null|anything in possible_rites
|
||||
if(!input_key)
|
||||
return
|
||||
var/datum/clockwork_rite/CR = possible_rites[input_key]
|
||||
if(!CR)
|
||||
return
|
||||
var/choice = alert(user, "What to do with this rite?", "What to do?", "Cast", "Show Info", "Cancel")
|
||||
switch(choice)
|
||||
if("Cast")
|
||||
CR.try_cast(src, user)
|
||||
if("Show Info")
|
||||
var/infotext = CR.build_info()
|
||||
to_chat(user, infotext)
|
||||
|
||||
/obj/effect/clockwork/sigil/rite/proc/generate_all_rites() //The first time someone uses a sigil of rites, all the rites are actually generated. No need to have a bunch of random datums laying around all the time.
|
||||
for(var/V in subtypesof(/datum/clockwork_rite))
|
||||
var/datum/clockwork_rite/R = new V
|
||||
GLOB.all_clockwork_rites += R
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
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
|
||||
var/is_stable = FALSE
|
||||
var/busy = FALSE //If someone is already working on closing the gateway, only needed for stable gateways but in the parent to not need typecasting
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/Initialize()
|
||||
. = ..()
|
||||
@@ -31,11 +33,16 @@
|
||||
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)
|
||||
if(is_stable)
|
||||
return
|
||||
timerid = QDEL_IN(src, lifetime) //We only need this if the gateway is not stable
|
||||
|
||||
//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)
|
||||
if(!gatewayB)
|
||||
return FALSE
|
||||
|
||||
if((!set_duration || !uses) && !is_stable)
|
||||
return FALSE
|
||||
linked_gateway = gatewayB
|
||||
gatewayB.linked_gateway = src
|
||||
@@ -55,7 +62,7 @@
|
||||
/obj/effect/clockwork/spatial_gateway/examine(mob/user)
|
||||
. = ..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
. += "<span class='brass'>It has [uses] use\s remaining.</span>"
|
||||
. += "<span class='brass'> [is_stable ? "It is stabilised and can be used as much as is neccessary." : "It has [uses] use\s remaining."]</span>"
|
||||
|
||||
//ATTACK GHOST IGNORING PARENT RETURN VALUE
|
||||
/obj/effect/clockwork/spatial_gateway/attack_ghost(mob/user)
|
||||
@@ -63,8 +70,7 @@
|
||||
user.forceMove(get_turf(linked_gateway))
|
||||
..()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/effect/clockwork/spatial_gateway/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/effect/clockwork/spatial_gateway/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(!uses)
|
||||
return FALSE
|
||||
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
|
||||
@@ -122,9 +128,9 @@
|
||||
/obj/effect/clockwork/spatial_gateway/Bumped(atom/movable/AM)
|
||||
..()
|
||||
if(!QDELETED(AM))
|
||||
pass_through_gateway(AM, FALSE)
|
||||
pass_through_gateway(AM)
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/proc/pass_through_gateway(atom/movable/A, no_cost)
|
||||
/obj/effect/clockwork/spatial_gateway/proc/pass_through_gateway(atom/movable/A, no_cost = FALSE)
|
||||
if(!linked_gateway)
|
||||
qdel(src)
|
||||
return FALSE
|
||||
@@ -198,6 +204,10 @@
|
||||
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 && target.z != invoker.z && (is_reebe(invoker.z) || is_reebe(target.z)) && !GLOB.ratvar_awakens) //You need obilisks to get from and to reebe. Costs alot of power, unless you use stable gateways.
|
||||
to_chat(invoker, "<span class='heavy brass'>The distance between reebe and the mortal realm is far too vast to bridge with a gateway your slab can create, my child. \
|
||||
Use an obilisk instead!</span>")
|
||||
return procure_gateway(invoker, time_duration, gateway_uses, two_way)
|
||||
if(issrcobelisk)
|
||||
if(!anchored)
|
||||
to_chat(invoker, "<span class='warning'>[src] is no longer secured!</span>")
|
||||
@@ -218,12 +228,63 @@
|
||||
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))
|
||||
if(issrcobelisk && istargetobelisk && src.z != target.z && (is_reebe(src.z) || is_reebe(target.z)))
|
||||
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 stable two-way rift between reebe and the mortal realm.</span>")
|
||||
var/obj/effect/clockwork/spatial_gateway/stable/stable_S1 = new(get_turf(src))
|
||||
var/obj/effect/clockwork/spatial_gateway/stable/stable_S2 = new(get_turf(target))
|
||||
stable_S1.setup_gateway(stable_S2)
|
||||
stable_S2.visible_message("<span class='warning'>The air in front of [target] ripples before suddenly tearing open!</span>")
|
||||
else
|
||||
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>")
|
||||
//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
|
||||
|
||||
//Stable Gateway: Used to travel to and from reebe without any further powercost. Needs a clockwork obilisk to keep active, but stays active as long as it is not deactivated via an null rod or a slab, or the obilisk is destroyed
|
||||
/obj/effect/clockwork/spatial_gateway/stable
|
||||
name = "stable gateway"
|
||||
is_stable = TRUE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/stable/ex_act(severity)
|
||||
if(severity == 1)
|
||||
start_shutdown() //Yes, you can chain devastation-level explosions to delay a gateway shutdown, if you somehow manage to do it without breaking the obelisk. Is it worth it? Probably not.
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/stable/setup_gateway(obj/effect/clockwork/spatial_gateway/stable/gatewayB) //Reduced setup call due to some things being irrelevant for stable gateways
|
||||
return ..(gatewayB, 1, 1, TRUE) //Uses and time irrelevant due to is_stable
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/stable/attackby(obj/item/I, mob/living/user, params)
|
||||
if(!istype(I, /obj/item/clockwork/slab) || !is_servant_of_ratvar(user) || busy)
|
||||
return ..()
|
||||
busy = TRUE
|
||||
linked_gateway.busy = TRUE
|
||||
user.visible_message("<span class='warning'>The rift begins to ripple as [user] points [user.p_their()] slab at it!</span>", "<span class='brass'> You begin to shutdown the stabilised gateway with your slab.</span>")
|
||||
linked_gateway.visible_message("<span class='warning'[linked_gateway] begins to ripple, but nothing comes through...</span>")
|
||||
var/datum/beam/B = user.Beam(src, icon_state = "nzcrentrs_power", maxdistance = 50, time = 80) //Not too fancy, but this'll do.. for now.
|
||||
if(do_after(user, 80, target = src)) //Eight seconds to initiate the closing, then another two before is closes.
|
||||
to_chat(user, "<span class='brass'>You successfully set the gateway to shutdown in another two seconds.</span>")
|
||||
start_shutdown()
|
||||
qdel(B)
|
||||
busy = FALSE
|
||||
linked_gateway.busy = FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/stable/proc/start_shutdown()
|
||||
deltimer(timerid)
|
||||
deltimer(linked_gateway.timerid)
|
||||
timerid = QDEL_IN(src, 20)
|
||||
linked_gateway.timerid = QDEL_IN(linked_gateway, 20)
|
||||
animate(src, alpha = 0, transform = matrix()*2, time = 20, flags = ANIMATION_END_NOW)
|
||||
animate(linked_gateway, alpha = 0, transform = matrix()*2, time = 20, flags = ANIMATION_END_NOW)
|
||||
src.visible_message("<span class='warning'>[src] begins to destabilise!</span>")
|
||||
linked_gateway.visible_message("<span class='warning'>[linked_gateway] begins to destabilise!</span>")
|
||||
|
||||
/obj/effect/clockwork/spatial_gateway/stable/pass_through_gateway(atom/movable/A, no_cost = TRUE)
|
||||
return ..()
|
||||
@@ -0,0 +1,196 @@
|
||||
//This file is for clock rites, mainly used by the Sigil of Rites in clock_sigils.dm
|
||||
//The rites themselves are in this file to prevent bloating the other file too much, aswell as for easier access
|
||||
|
||||
#define INFINITE -1
|
||||
|
||||
//The base clockwork rite. This should never be visible
|
||||
/datum/clockwork_rite
|
||||
var/name = "Rite of THE frog" //The name of the rite
|
||||
var/desc = "This rite is used to summon the legendary frog whose-name-shall-not-be-spoken, ender of many worlds." //What does this rite do? Shown to cultists if they choose 'Show Info' after selecting the rite.
|
||||
var/list/required_ingredients = list(/obj/item/clockwork) //What does this rite require?
|
||||
var/power_cost = 0 //How much power does this rite cost.. or does it even add power?
|
||||
var/requires_human = FALSE //Does the rite require a ../carbon/human on the rune?
|
||||
var/must_be_servant = TRUE //If the above is true, does the human need to be a servant?
|
||||
var/target_can_be_invoker = TRUE //Does this rite work if the invoker is also the target?
|
||||
var/cast_time = 0 //How long does the rite take to cast?
|
||||
var/limit = INFINITE //How often can this rite be used per round? Set this to INFINITE for unlimited, 0 for disallowed, anything above 0 for a limit
|
||||
var/times_used = 0 //How often has the rite already been used this shift?
|
||||
var/rite_cast_sound = 'sound/items/bikehorn.ogg' //The sound played when successfully casting the rite. If it honks, the one adding the rite forgot to set one (or was just lazy).
|
||||
|
||||
/datum/clockwork_rite/proc/try_cast(var/obj/effect/clockwork/sigil/rite/R, var/mob/living/invoker) //Performs a ton of checks to see if the invoker can cast the rite
|
||||
if(!istype(R))
|
||||
return FALSE
|
||||
if(!R || !R.loc)
|
||||
return FALSE
|
||||
var/turf/T = R.loc
|
||||
if(!T) //Uh oh something is fucky
|
||||
return FALSE
|
||||
|
||||
if(limit != INFINITE && times_used >= limit) //Is the limit on casts exceeded?
|
||||
to_chat(invoker, "<span class='brass'>There are no more uses left for this rite!</span>")
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/human/H //This is only used if requires_human is TRUE
|
||||
if(requires_human) //In case this requires a target
|
||||
for(var/mob/living/carbon/human/possible_H in T)
|
||||
if((!must_be_servant || is_servant_of_ratvar(possible_H)) && (target_can_be_invoker || invoker != possible_H))
|
||||
H = possible_H
|
||||
break
|
||||
if(!H)
|
||||
to_chat(invoker, "<span class='brass'>There is no target for the rite on the sigil!</span>")
|
||||
return FALSE
|
||||
|
||||
if(required_ingredients.len) //In case this requires materials
|
||||
var/is_missing_materials = FALSE
|
||||
for(var/I in required_ingredients)
|
||||
var/obj/item/Material = locate(I) in T
|
||||
if(!Material)
|
||||
is_missing_materials = TRUE
|
||||
break
|
||||
if(is_missing_materials)
|
||||
var/still_required_string = ""
|
||||
for(var/i = 1 to required_ingredients.len)
|
||||
var/obj/O = required_ingredients[i]
|
||||
if(i != 1)
|
||||
still_required_string += ", "
|
||||
still_required_string += "a [initial(O.name)]"
|
||||
to_chat(invoker, "<span class='brass'>There are still materials missing for this rite. You require [still_required_string].</span>")
|
||||
return FALSE
|
||||
|
||||
if(power_cost) //If this costs power
|
||||
if(!get_clockwork_power(power_cost))
|
||||
to_chat(invoker, "<span class='brass'>There is not enough power for this rite!</span>")
|
||||
return FALSE
|
||||
R.performing_rite = TRUE
|
||||
if(!do_after(invoker, cast_time, target = R))
|
||||
to_chat(invoker, "<span class='warning'>Your rite is disrupted.</span>")
|
||||
R.performing_rite = FALSE
|
||||
return FALSE
|
||||
. = cast(invoker, T, H)
|
||||
if(!.)
|
||||
to_chat(invoker, "<span class='warning'> You fail casting [name]</span>")
|
||||
post_cast(FALSE)
|
||||
else
|
||||
to_chat(invoker, "<span class='warning'>You successfully cast [name]</span>")
|
||||
post_cast(TRUE)
|
||||
R.performing_rite = FALSE
|
||||
return
|
||||
|
||||
/datum/clockwork_rite/proc/cast(var/mob/living/invoker, var/turf/T, var/mob/living/carbon/human/target) //Casts the rite and uses up ingredients. Doublechecks some things to prevent bypassing some restrictions via funky timing or badminnery.
|
||||
if(!T || !invoker)
|
||||
return FALSE
|
||||
if(requires_human && !target)
|
||||
return FALSE
|
||||
if(power_cost && !get_clockwork_power(power_cost))
|
||||
return FALSE
|
||||
adjust_clockwork_power(-power_cost)
|
||||
if(limit != INFINITE && times_used >= limit)
|
||||
return FALSE
|
||||
if(required_ingredients.len)
|
||||
var/is_missing_materials = FALSE
|
||||
for(var/I in required_ingredients)
|
||||
var/obj/item/Material = locate(I) in T
|
||||
if(!Material)
|
||||
is_missing_materials = TRUE
|
||||
break
|
||||
qdel(Material)
|
||||
if(is_missing_materials)
|
||||
return FALSE
|
||||
playsound(T, rite_cast_sound, 50, 2)
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_rite/proc/post_cast(var/cast_succeeded)
|
||||
if(cast_succeeded)
|
||||
times_used++
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_rite/proc/build_info() //Constructs the info text of a given rite, based on the vars of the rite
|
||||
. = ""
|
||||
. += "<span class='brass'>This is the <b>[name]</b>.\n"
|
||||
. += "[desc]\n"
|
||||
. += "It requires: "
|
||||
if(required_ingredients.len)
|
||||
var/material_string = ""
|
||||
for(var/i = 1 to required_ingredients.len)
|
||||
var/obj/O = required_ingredients[i]
|
||||
if(i != 1)
|
||||
material_string += ", "
|
||||
material_string += "a [initial(O.name)]"
|
||||
. += "[material_string].\n"
|
||||
else
|
||||
. += "</span><span class='inathneq_small'><b>no</b><span class='brass'> materials.\n"
|
||||
. += "It [power_cost >= 0 ? "costs" : "generates"]<span class='inathneq_small'><b> [power_cost ? "[power_cost]" : "no"] </b><span class='brass'>power.\n"
|
||||
. += "It requires <span class='inathneq_small'><b>[requires_human ? " a human" : " no"]</b><span class='brass'> target.\n"
|
||||
if(requires_human)
|
||||
. += "The target <span class='inathneq_small'><b>[must_be_servant ? "cannot be" : "can be"] </b><span class='brass'> a nonservant.\n"
|
||||
. += "The target <span class='inathneq_small'><b>[target_can_be_invoker ? "can be" : "cannot be"]</b><span class='brass'> the invoker.\n"
|
||||
. += "It requires <span class='inathneq_small'><b>[cast_time/10]</b><span class='brass'> seconds to cast.\n"
|
||||
. += "It has been used <span class='inathneq_small'><b>[times_used]</b><span class='brass'> time[times_used != 1 ? "s" : ""], out of <span class='inathneq_small'><b>[limit != INFINITE ? "[limit]" : "infinite"]</b><span class='brass'> available uses.</span>"
|
||||
|
||||
//Adds a organ or cybernetic implant to a servant without the need for surgery. Cannot be used with brains for.. reasons.
|
||||
/datum/clockwork_rite/advancement
|
||||
name = "Rite of Advancement"
|
||||
desc = "This rite is used to augment a servant with organs or cybernetic implants. The organ of choice, aswell as the servant and the required ingredients must be placed on the sigil for this rite to take place."
|
||||
required_ingredients = list(/obj/item/assembly/prox_sensor, /obj/item/stock_parts/cell)
|
||||
power_cost = 500
|
||||
requires_human = TRUE
|
||||
cast_time = 40
|
||||
rite_cast_sound = 'sound/magic/blind.ogg'
|
||||
|
||||
/datum/clockwork_rite/advancement/cast(var/mob/living/invoker, var/turf/T, var/mob/living/carbon/human/target)
|
||||
var/obj/item/organ/O = locate(/obj/item/organ) in T
|
||||
if(!O)
|
||||
return FALSE
|
||||
if(istype(O, /obj/item/organ/brain)) //NOPE
|
||||
return FALSE
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
O.Insert(target)
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transgression(T)
|
||||
|
||||
//Heals all wounds (not damage) on the target, causing toxloss proportional to amount of wounds healed. 10 damage per wound.
|
||||
/datum/clockwork_rite/treat_wounds
|
||||
name = "Rite of Woundmending"
|
||||
desc = "This rite is used to heal wounds of the servant on the rune. It causes toxins damage proportional to the amount of wounds healed. This can be lethal if performed on an critically injured target."
|
||||
required_ingredients = list(/obj/item/stock_parts/cell, /obj/item/healthanalyzer, /obj/item/reagent_containers/food/drinks/bottle/holyoil)
|
||||
power_cost = 300
|
||||
requires_human = TRUE
|
||||
must_be_servant = FALSE
|
||||
target_can_be_invoker = FALSE
|
||||
cast_time = 80
|
||||
rite_cast_sound = 'sound/magic/staff_healing.ogg'
|
||||
|
||||
/datum/clockwork_rite/treat_wounds/cast(var/mob/living/invoker, var/turf/T, var/mob/living/carbon/human/target)
|
||||
if(!target)
|
||||
return FALSE
|
||||
if(!target.all_wounds.len)
|
||||
to_chat(invoker, "<span class='inathneq_small'>This one does not require mending.</span>")
|
||||
return FALSE
|
||||
.= ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
target.adjustToxLoss(10 * target.all_wounds.len)
|
||||
QDEL_LIST(target.all_wounds)
|
||||
to_chat(target, "<span class='warning'>You feel your wounds heal, but are overcome with deep nausea.</span>")
|
||||
new /obj/effect/temp_visual/ratvar/sigil/vitality(T)
|
||||
|
||||
//Summons a brass claw implant on the sigil, which can extend a claw that benefits from repeatedly attacking a single target. Can only be cast a limited amount of times.
|
||||
/datum/clockwork_rite/summon_claw
|
||||
name = "Rite of the Claw"
|
||||
desc = "Summons a special arm implant that, when added to a servant's limb, will allow them to extend and retract a claw at will. Don't leave any implants you want to keep on this rune when casting the rite."
|
||||
required_ingredients = list(/obj/item/stock_parts/cell, /obj/item/organ/cyberimp, /obj/item/assembly/flash)
|
||||
power_cost = 1000
|
||||
cast_time = 60
|
||||
limit = 4
|
||||
rite_cast_sound = 'sound/magic/clockwork/fellowship_armory.ogg'
|
||||
|
||||
/datum/clockwork_rite/summon_claw/cast(var/mob/living/invoker, var/turf/T, var/mob/living/carbon/human/target)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
var/obj/item/organ/cyberimp/arm/clockwork/claw/CL = new /obj/item/organ/cyberimp/arm/clockwork/claw(T)
|
||||
CL.visible_message("<span class='warning'>[CL] materialises out of thin air!")
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transmission(T,2)
|
||||
|
||||
#undef INFINITE
|
||||
@@ -0,0 +1,32 @@
|
||||
//This file is for snowflakey clock augmentations and clock-themed cybernetic implants.
|
||||
|
||||
//The base clockie arm implant, which only clock cultist can use unless it is emagged. THIS SHOULD NEVER ACTUALLY EXIST
|
||||
/obj/item/organ/cyberimp/arm/clockwork
|
||||
name = "clock-themed arm-mounted implant"
|
||||
var/clockwork_desc = "According to Ratvar, this really shouldn't exist. Tell Him about this immediately."
|
||||
syndicate_implant = TRUE
|
||||
icon_state = "clock_arm_implant"
|
||||
|
||||
/obj/item/organ/cyberimp/arm/clockwork/ui_action_click()
|
||||
if(is_servant_of_ratvar(owner) || (obj_flags & EMAGGED)) //If you somehow manage to steal a clockie's implant AND have an emag AND manage to get it implanted for yourself, good on ya!
|
||||
return ..()
|
||||
to_chat(owner, "<span class='warning'>The implant refuses to activate..</span>")
|
||||
|
||||
/obj/item/organ/cyberimp/arm/clockwork/examine(mob/user)
|
||||
if((is_servant_of_ratvar(user) || isobserver(user)) && clockwork_desc)
|
||||
desc = clockwork_desc
|
||||
. = ..()
|
||||
desc = initial(desc)
|
||||
|
||||
/obj/item/organ/cyberimp/arm/clockwork/emag_act()
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(usr, "<span class='notice'>You emag [src], hoping it'll achieve something..</span>")
|
||||
|
||||
//Brass claw implant. Holds the brass claw from brass_claw.dm and can extend / retract it at will.
|
||||
/obj/item/organ/cyberimp/arm/clockwork/claw
|
||||
name = "brass claw implant"
|
||||
desc = "Yikes, the claw attached to this looks pretty darn sharp."
|
||||
clockwork_desc = "This implant, when added to a servant's arm, allows them to extend and retract a claw at will, though this is mildly painful to do. It will refuse to work for any non-servants."
|
||||
contents = newlist(/obj/item/clockwork/brass_claw)
|
||||
@@ -29,7 +29,7 @@
|
||||
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)
|
||||
weapon_reset(RATVARIAN_WEAPON_COOLDOWN * 0.5)
|
||||
return
|
||||
else
|
||||
weapon.visible_message("<span class='warning'>[weapon] suddenly flickers and disappears!</span>")
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
//Brass claw, an armblade-like weapon used by a clock implant. Stealthy if retracted, very obvious if active.
|
||||
//Bit weaker than an armblade strength-wise but gains combo on consecutive attacks against the same target, which causes bonus damage
|
||||
|
||||
/obj/item/clockwork/brass_claw
|
||||
name = "brass claw"
|
||||
desc = "A very sharp claw made out of brass."
|
||||
clockwork_desc = "A incredibly sharp claw made out of brass. It is quite effective at crippling enemies, though very obvious when extended.\nGains combo on consecutive attacks against a target, causing bonus damage."
|
||||
icon_state = "brass_claw" //Codersprite moment
|
||||
item_state = "brass_claw"
|
||||
lefthand_file = 'icons/mob/inhands/antag/clockwork_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/clockwork_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
force = 15 //Doesn't generate vitality like the spear does / has somewhat less damage, but quite good at wounding and gets through armor pretty well. Also gains 2 bonus damage per consecutive attack on the same target
|
||||
throwforce = 0 //haha yes lets be safe about this
|
||||
throw_range = 0
|
||||
throw_speed = 0
|
||||
armour_penetration = 20
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
sharpness = SHARP_EDGED
|
||||
wound_bonus = 5
|
||||
bare_wound_bonus = 15
|
||||
total_mass = TOTAL_MASS_HAND_REPLACEMENT
|
||||
var/mob/living/last_attacked
|
||||
var/combo = 0
|
||||
var/damage_per_combo = 2
|
||||
var/maximum_combo_damage = 18 //33 damage on max stacks. Usually the target will already be dead by then but if they somehow aren't, better to have this capped
|
||||
|
||||
/obj/item/clockwork/brass_claw/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/butchering, 60, 80)
|
||||
|
||||
/obj/item/clockwork/brass_claw/examine(mob/user)
|
||||
if(is_servant_of_ratvar(user))
|
||||
clockwork_desc += "\n<span class='brass'>It has </span><span class='inathneq_small'><b>[combo]</span></b><span class='brass'> combo stacks built up against the current target, causing </span><span class='inathneq_small'><b>[min(maximum_combo_damage, combo * damage_per_combo)]</span></b><span class='brass'> bonus damage.</span>"
|
||||
. = ..()
|
||||
clockwork_desc = initial(clockwork_desc)
|
||||
|
||||
/obj/item/clockwork/brass_claw/attack(mob/living/target, mob/living/carbon/human/user)
|
||||
. = ..()
|
||||
if(QDELETED(target) || target.anti_magic_check(chargecost = 0) || is_servant_of_ratvar(target))
|
||||
return
|
||||
if(target != last_attacked) //Loses all combat on switching targets
|
||||
last_attacked = target
|
||||
combo = 0
|
||||
else
|
||||
if(!iscultist(target)) //Hostile cultists being hit stacks up combo far faster than usual
|
||||
combo++
|
||||
else
|
||||
combo += 3
|
||||
target.adjustBruteLoss(min(maximum_combo_damage, combo * damage_per_combo))
|
||||
@@ -8,10 +8,12 @@
|
||||
force = 15 //Extra damage is dealt to targets in attack()
|
||||
throwforce = 25
|
||||
armour_penetration = 10
|
||||
sharpness = IS_SHARP_ACCURATE
|
||||
sharpness = SHARP_POINTY
|
||||
attack_verb = list("stabbed", "poked", "slashed")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
block_parry_data = /datum/block_parry_data/ratvarian_spear
|
||||
item_flags = ITEM_CAN_PARRY
|
||||
var/bonus_burn = 5
|
||||
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/ratvar_act()
|
||||
@@ -43,7 +45,7 @@
|
||||
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
|
||||
GLOB.clockwork_vitality += max(0, target.adjustFireLoss(bonus_damage)) //adds the damage done to existing vitality
|
||||
|
||||
/obj/item/clockwork/weapon/ratvarian_spear/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
var/turf/T = get_turf(hit_atom)
|
||||
@@ -78,5 +80,17 @@
|
||||
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)
|
||||
action.weapon_reset(RATVARIAN_WEAPON_COOLDOWN)
|
||||
|
||||
//A very short, very effective parry that counts on you predicting when the enemy will attack.
|
||||
/datum/block_parry_data/ratvarian_spear
|
||||
parry_time_windup = 0 //Very good for predicting
|
||||
parry_time_active = 3 //Very short
|
||||
parry_time_spindown = 1
|
||||
parry_time_perfect = 2
|
||||
parry_efficiency_perfect = 110 //Very low leeway for counterattacks...
|
||||
parry_efficiency_considered_successful = 0.8
|
||||
parry_efficiency_to_counterattack = 1
|
||||
parry_cooldown = 15 //But also very low cooldown..
|
||||
parry_failed_stagger_duration = 2 SECONDS //And relatively small penalties for failing.
|
||||
parry_failed_clickcd_duration = 1 SECONDS
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
flags_inv = HIDEEARS|HIDEHAIR|HIDEFACE|HIDESNOUT
|
||||
mutantrace_variation = STYLE_MUZZLE
|
||||
armor = list("melee" = 50, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
armor = list("melee" = 50, "bullet" = 70, "laser" = 0, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100, "magic" = 60, "wound" = 65)
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/Initialize()
|
||||
. = ..()
|
||||
@@ -21,17 +21,17 @@
|
||||
|
||||
/obj/item/clothing/head/helmet/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = getArmor(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
|
||||
armor = getArmor(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100, magic = 100, wound = 100)
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else if(GLOB.ratvar_approaches)
|
||||
armor = getArmor(melee = 70, bullet = 80, laser = -15, energy = 25, bomb = 70, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
armor = getArmor(melee = 70, bullet = 80, laser = 10, energy = 25, bomb = 70, bio = 0, rad = 0, fire = 100, acid = 100,, magic = 70, wound = 75)
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = getArmor(melee = 60, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
armor = getArmor(melee = 60, bullet = 70, laser = 0, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100, magic = 60, wound = 65)
|
||||
clothing_flags &= ~STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
@@ -68,7 +68,7 @@
|
||||
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)
|
||||
armor = list("melee" = 60, "bullet" = 70, "laser" = 0, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100, "magic" = 60, "wound" = 65)
|
||||
allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/mmi/posibrain/soul_vessel, /obj/item/reagent_containers/food/drinks/bottle/holyoil)
|
||||
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_SNEK_TAURIC
|
||||
|
||||
@@ -83,17 +83,17 @@
|
||||
|
||||
/obj/item/clothing/suit/armor/clockwork/ratvar_act()
|
||||
if(GLOB.ratvar_awakens)
|
||||
armor = getArmor(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100)
|
||||
armor = getArmor(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100, magic = 100, wound = 100)
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else if(GLOB.ratvar_approaches)
|
||||
armor = getArmor(melee = 70, bullet = 80, laser = -15, energy = 25, bomb = 70, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
armor = getArmor(melee = 70, bullet = 80, laser = 10, energy = 25, bomb = 70, bio = 0, rad = 0, fire = 100, acid = 100, magic = 70, wound = 75)
|
||||
clothing_flags |= STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = getArmor(melee = 60, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
armor = getArmor(melee = 60, bullet = 70, laser = 0, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100, magic = 60, wound = 65)
|
||||
clothing_flags &= ~STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
@@ -135,7 +135,7 @@
|
||||
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)
|
||||
armor = list("melee" = 80, "bullet" = 70, "laser" = 0, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100, "magic" = 70, "wound" = 85)
|
||||
|
||||
/obj/item/clothing/gloves/clockwork/Initialize()
|
||||
. = ..()
|
||||
@@ -153,7 +153,7 @@
|
||||
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
|
||||
min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT
|
||||
else
|
||||
armor = getArmor(melee = 80, bullet = 70, laser = -25, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100)
|
||||
armor = getArmor(melee = 80, bullet = 70, laser = 0, energy = 0, bomb = 60, bio = 0, rad = 0, fire = 100, acid = 100, magic = 70, wound = 85)
|
||||
clothing_flags &= ~STOPSPRESSUREDAMAGE
|
||||
max_heat_protection_temperature = initial(max_heat_protection_temperature)
|
||||
min_cold_protection_temperature = initial(min_cold_protection_temperature)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant.\
|
||||
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"
|
||||
icon_state = "clockwork_slab"
|
||||
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
|
||||
@@ -21,13 +21,10 @@
|
||||
var/recollecting = TRUE //if we're looking at fancy recollection. tutorial enabled by default
|
||||
var/recollection_category = "Default"
|
||||
|
||||
var/list/quickbound = list(/datum/clockwork_scripture/abscond, \
|
||||
var/list/quickbound = list(/datum/clockwork_scripture/spatial_gateway, \
|
||||
/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/ui_x = 800
|
||||
var/ui_z = 420
|
||||
|
||||
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
|
||||
@@ -39,6 +36,11 @@
|
||||
speed_multiplier = 0
|
||||
no_cost = TRUE
|
||||
|
||||
/obj/item/clockwork/slab/debug/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
add_servant_of_ratvar(user)
|
||||
return ..()
|
||||
|
||||
/obj/item/clockwork/slab/traitor
|
||||
var/spent = FALSE
|
||||
|
||||
@@ -57,12 +59,6 @@
|
||||
to_chat(user, "<span class='userdanger'>[src] falls dark. It appears you weren't worthy.</span>")
|
||||
return ..()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clockwork/slab/debug/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
add_servant_of_ratvar(user)
|
||||
return ..()
|
||||
|
||||
/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, \
|
||||
@@ -70,29 +66,32 @@
|
||||
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 //three scriptures, plus a fabricator
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transmission, /datum/clockwork_scripture/create_object/stargazer)
|
||||
/obj/item/clockwork/slab/cyborg/engineer //six scriptures, plus a fabricator. Might revert this if its too OP, I just thought that engineering borgs should get the all the structures
|
||||
quickbound = list(/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transmission, /datum/clockwork_scripture/create_object/stargazer, \
|
||||
/datum/clockwork_scripture/create_object/ocular_warden, /datum/clockwork_scripture/create_object/clockwork_obelisk, /datum/clockwork_scripture/create_object/mania_motor)
|
||||
|
||||
/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/medical //six scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/ranged_ability/sentinels_compromise, \
|
||||
/datum/clockwork_scripture/create_object/vitality_matrix, /datum/clockwork_scripture/channeled/mending_mantra)
|
||||
|
||||
/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/security //four scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/channeled/volt_blaster, /datum/clockwork_scripture/ranged_ability/hateful_manacles, \
|
||||
/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/channeled/belligerent)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/peacekeeper //four scriptures, plus a spear
|
||||
quickbound = list(/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/channeled/volt_blaster, /datum/clockwork_scripture/ranged_ability/hateful_manacles, \
|
||||
/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/channeled/belligerent)
|
||||
/*//this module was commented out so why wasn't this?
|
||||
/obj/item/clockwork/slab/cyborg/janitor //six scriptures, plus a fabricator
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transgression, \
|
||||
quickbound = list(/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transgression, \
|
||||
/datum/clockwork_scripture/create_object/stargazer, /datum/clockwork_scripture/create_object/ocular_warden, /datum/clockwork_scripture/create_object/mania_motor)
|
||||
|
||||
*/
|
||||
/obj/item/clockwork/slab/cyborg/service //six scriptures, plus xray vision
|
||||
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant,/datum/clockwork_scripture/create_object/stargazer, \
|
||||
quickbound = list(/datum/clockwork_scripture/spatial_gateway, /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/miner //three scriptures, plus a spear and xray vision
|
||||
quickbound = list(/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/ranged_ability/linked_vanguard, /datum/clockwork_scripture/channeled/belligerent, /datum/clockwork_scripture/channeled/volt_blaster)
|
||||
|
||||
/obj/item/clockwork/slab/cyborg/access_display(mob/living/user)
|
||||
if(!GLOB.ratvar_awakens)
|
||||
@@ -143,14 +142,15 @@
|
||||
|
||||
/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]
|
||||
. += "Quickbind button: <span class='[get_component_span(initial(quickbind_slot.primary_component))]'>[initial(quickbind_slot.name)]</span>."
|
||||
. += "Available power: <span class='bold brass'>[DisplayPower(get_clockwork_power())].</span>"
|
||||
if(!is_servant_of_ratvar(user) || !isobserver(user))
|
||||
return
|
||||
if(LAZYLEN(quickbound))
|
||||
for(var/i in 1 to quickbound.len)
|
||||
if(!quickbound[i])
|
||||
continue
|
||||
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
|
||||
. += "Quickbind button: <span class='[get_component_span(initial(quickbind_slot.primary_component))]'>[initial(quickbind_slot.name)]</span>."
|
||||
. += "Available power: <span class='bold brass'>[DisplayPower(get_clockwork_power())].</span>"
|
||||
|
||||
//Slab actions; Hierophant, Quickbind
|
||||
/obj/item/clockwork/slab/ui_action_click(mob/user, action)
|
||||
@@ -196,12 +196,6 @@
|
||||
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, "ClockworkSlab", name, ui_x, ui_z, master_ui, state)
|
||||
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
|
||||
@@ -221,29 +215,64 @@
|
||||
scripture_to_recite.run_scripture()
|
||||
return TRUE
|
||||
|
||||
/*
|
||||
* 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
|
||||
* * what - What section?
|
||||
*/
|
||||
/obj/item/clockwork/slab/proc/get_recollection(what) //Now DMDOC compliant!*
|
||||
. = list()
|
||||
switch(what) //need someone to rewrite info for this.
|
||||
if("Default")
|
||||
.["title"] = "Default"
|
||||
.["info"] = "Hello servant! Currently these categories dosen't work!"
|
||||
/*
|
||||
if("Basics")
|
||||
.["title"] = "Basics"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
if("Terminology")
|
||||
.["title"] = "Terminology"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
if("Components")
|
||||
.["title"] = "Default"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
if("Scripture")
|
||||
.["title"] = "Default"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
if("Power")
|
||||
.["title"] = "Power"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
if("Conversion")
|
||||
.["title"] = "Conversion"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
*/
|
||||
else
|
||||
return null //error text handled tgui side. should not cause BSOD
|
||||
|
||||
//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/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ClockworkSlab", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/clockwork/slab/ui_data(mob/user) //we display a lot of data via TGUI
|
||||
. = list()
|
||||
.["recollection"] = recollecting
|
||||
.["power"] = DisplayPower(get_clockwork_power())
|
||||
.["power_unformatted"] = get_clockwork_power()
|
||||
// .["rec_text"] = recollection() handled TGUI side
|
||||
.["HONOR_RATVAR"] = GLOB.ratvar_awakens
|
||||
.["scripture"] = list()
|
||||
for(var/s in GLOB.all_scripture)
|
||||
for(var/s in GLOB.all_scripture) //don't block this, even when ratvar spawns for roundend griff.
|
||||
var/datum/clockwork_scripture/S = GLOB.all_scripture[s]
|
||||
if(S.tier == SCRIPTURE_PERIPHERAL) //yes, tiers are the tabs.
|
||||
if(S.tier == SCRIPTURE_PERIPHERAL) // This tier is skiped because this contains basetype stuff
|
||||
continue
|
||||
|
||||
|
||||
var/list/data = list()
|
||||
data["name"] = S.name
|
||||
data["descname"] = S.descname
|
||||
@@ -251,34 +280,36 @@
|
||||
data["required"] = "([DisplayPower(S.power_cost)][S.special_power_text ? "+ [replacetext(S.special_power_text, "POWERCOST", "[DisplayPower(S.special_power_cost)]")]" : ""])"
|
||||
data["required_unformatted"] = S.power_cost
|
||||
data["type"] = "[S.type]"
|
||||
data["quickbind"] = S.quickbind //this is if it cant quickbind
|
||||
data["quickbind"] = S.quickbind //this is if it cant quickbind (bool)
|
||||
data["fontcolor"] = get_component_color_bright(S.primary_component)
|
||||
data["important"] = S.important //italic!
|
||||
|
||||
|
||||
var/found = quickbound.Find(S.type)
|
||||
if(found)
|
||||
data["bound"] = found //number (pos) on where is it on the list
|
||||
if(S.invokers_required > 1)
|
||||
data["invokers"] = "Invokers: [S.invokers_required]"
|
||||
|
||||
|
||||
.["rec_binds"] = list()
|
||||
for(var/i in 1 to maximum_quickbound)
|
||||
if(GLOB.ratvar_awakens)
|
||||
return
|
||||
if(LAZYLEN(quickbound) < i || !quickbound[i])
|
||||
.["rec_binds"] += list(list())
|
||||
.["rec_binds"] += list(list()) //a blank json.
|
||||
else
|
||||
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
|
||||
.["rec_binds"] += list(list(
|
||||
"name" = initial(quickbind_slot.name),
|
||||
"name" = initial(quickbind_slot.name),
|
||||
"color" = get_component_color_bright(initial(quickbind_slot.primary_component))
|
||||
))
|
||||
|
||||
|
||||
.["scripture"][S.tier] += list(data)
|
||||
|
||||
/obj/item/clockwork/slab/ui_static_data(mob/user)
|
||||
. = list()
|
||||
.["tier_infos"] = list()
|
||||
.["tier_infos"] = list() //HEY!! WHEN ADDING NEW TIER, ADD IT HERE
|
||||
.["tier_infos"][SCRIPTURE_PERIPHERAL] = list(
|
||||
"requirement" = "Breaking the code DM side. Report to coggerbus if this appears!!",
|
||||
"ready" = FALSE //just in case. Should NOT exist at all
|
||||
)
|
||||
.["tier_infos"][SCRIPTURE_DRIVER] = list(
|
||||
"requirement" = "None, this is already unlocked",
|
||||
"ready" = TRUE //to bold it on JS side, and to say "These scriptures are permanently unlocked."
|
||||
@@ -291,10 +322,14 @@
|
||||
"requirement" = "Unlock these optional scriptures by converting another servant or if [DisplayPower(APPLICATION_UNLOCK_THRESHOLD)] of power is reached..",
|
||||
"ready" = SSticker.scripture_states[SCRIPTURE_APPLICATION]
|
||||
)
|
||||
|
||||
// .["selected"] = selected_scripture
|
||||
generate_all_scripture()
|
||||
.["recollection_categories"] = GLOB.ratvar_awakens ? list() : list(
|
||||
.["tier_infos"][SCRIPTURE_JUDGEMENT] = list(
|
||||
"requirement" = "Unlock powerful equipment and structures by converting five servants or if [DisplayPower(JUDGEMENT_UNLOCK_THRESHOLD)] of power is reached..",
|
||||
"ready" = SSticker.scripture_states[SCRIPTURE_JUDGEMENT]
|
||||
)
|
||||
.["recollection_categories"] = list()
|
||||
if(GLOB.ratvar_awakens)
|
||||
return
|
||||
.["recollection_categories"] = 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."),
|
||||
@@ -303,8 +338,9 @@
|
||||
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.")
|
||||
)
|
||||
// .["rec_section"]["title"] //this is here if ever we decided to return these back.
|
||||
// .["rec_section"]["info"]// wall of info for the thing
|
||||
.["rec_section"] = get_recollection(recollection_category)
|
||||
generate_all_scripture()
|
||||
//needs a new place to live, preferably when clockcult unlocks/downgrades a tier. Smart enough to earlyreturn.
|
||||
|
||||
/obj/item/clockwork/slab/ui_act(action, params)
|
||||
switch(action)
|
||||
|
||||
@@ -31,8 +31,7 @@
|
||||
. = ..()
|
||||
clockwork_desc = initial(clockwork_desc)
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/clockwork/construct_chassis/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/item/clockwork/construct_chassis/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
if(w_class >= WEIGHT_CLASS_HUGE)
|
||||
to_chat(user, "<span class='warning'>[src] is too cumbersome to carry! Drag it around instead!</span>")
|
||||
return
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
var/obj/item/stock_parts/cell/cell = apc.cell
|
||||
if(cell && (cell.charge / cell.maxcharge > COG_MAX_SIPHON_THRESHOLD))
|
||||
cell.use(1)
|
||||
apc.cog_drained++
|
||||
adjust_clockwork_power(2) //Power is shared, so only do it once; this runs very quickly so it's about 10 W/second
|
||||
else
|
||||
adjust_clockwork_power(1) //Continue generating power when the cell has run dry; 5 W/second
|
||||
|
||||
@@ -114,24 +114,27 @@
|
||||
superheat_wall(A)
|
||||
return
|
||||
if(modifiers["middle"] || modifiers["ctrl"])
|
||||
issue_command(A)
|
||||
INVOKE_ASYNC(src, .proc/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
|
||||
INVOKE_ASYNC(src, .proc/attempt_recall, G)
|
||||
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/proc/attempt_recall(obj/structure/destructible/clockwork/massive/celestial_gateway/G)
|
||||
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
|
||||
|
||||
/mob/camera/eminence/ratvar_act()
|
||||
name = "\improper Radiance"
|
||||
real_name = "\improper Radiance"
|
||||
|
||||
@@ -124,3 +124,437 @@
|
||||
|
||||
#undef MARAUDER_SLOWDOWN_PERCENTAGE
|
||||
#undef MARAUDER_SHIELD_REGEN_TIME
|
||||
|
||||
//Clockwork guardian: Slow but with high damage, resides inside of a servant. Created via the Memory Allocation scripture.
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian
|
||||
name = "clockwork guardian"
|
||||
desc = "A stalwart apparition of a soldier, blazing with crimson flames. It's armed with a gladius and shield and stands ready by its master."
|
||||
icon_state = "clockwork_marauder"
|
||||
health = 300
|
||||
maxHealth = 300
|
||||
speed = 1
|
||||
obj_damage = 40
|
||||
melee_damage_lower = 12
|
||||
melee_damage_upper = 12
|
||||
attack_verb_continuous = "slashes"
|
||||
attack_verb_simple = "slash"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
weather_immunities = list("lava")
|
||||
movement_type = FLYING
|
||||
AIStatus = AI_OFF //this has to be manually set so that the guardian doesn't start bashing the host, how annoying -_-
|
||||
loot = list(/obj/item/clockwork/component/geis_capacitor/fallen_armor)
|
||||
max_shield_health = 0
|
||||
shield_health = 0
|
||||
var/true_name = "Meme Master 69" //Required to call forth the guardian
|
||||
var/global/list/possible_true_names = list("Servant", "Warden", "Serf", "Page", "Usher", "Knave", "Vassal", "Escort")
|
||||
var/mob/living/host //The mob that the guardian is living inside of
|
||||
var/recovering = FALSE //If the guardian is recovering from recalling
|
||||
var/blockchance = 17 //chance to block attacks entirely
|
||||
var/counterchance = 30 //chance to counterattack after blocking
|
||||
var/static/list/damage_heal_order = list(OXY, BURN, BRUTE, TOX) //we heal our host's damage in this order
|
||||
light_range = 2
|
||||
light_power = 1.1
|
||||
playstyle_string = "<span class='sevtug'>You are a clockwork guardian</span><b>, a living extension of Sevtug's will. As a guardian, you are somewhat slow, but may block attacks, \
|
||||
and have a chance to also counter blocked melee attacks for extra damage, in addition to being immune to extreme temperatures and pressures. \
|
||||
Your primary goal is to serve the creature that you are now a part of, as well as The Clockwork Justiciar, Ratvar. You can use <span class='sevtug_small'><i>The Hierophant Network</i></span> to communicate silently with your master and their allies, \
|
||||
but can only exit if your master calls your true name or if they are exceptionally damaged. \
|
||||
\n\n\
|
||||
Stay near your host to protect and heal them; being too far from your host will rapidly cause you massive damage. Recall to your host if you are too weak and believe you cannot continue \
|
||||
fighting safely. As a final note, you should probably avoid harming any fellow servants of Ratvar.</span>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/Initialize()
|
||||
. = ..()
|
||||
true_name = pick(possible_true_names)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/BiologicalLife(seconds, times_fired)
|
||||
..()
|
||||
if(is_in_host())
|
||||
if(!is_servant_of_ratvar(host))
|
||||
emerge_from_host(FALSE, TRUE)
|
||||
unbind_from_host()
|
||||
return
|
||||
if(!GLOB.ratvar_awakens && host.stat == DEAD)
|
||||
death()
|
||||
return
|
||||
if(GLOB.ratvar_awakens)
|
||||
adjustHealth(-50)
|
||||
else
|
||||
adjustHealth(-10)
|
||||
if(!recovering)
|
||||
heal_host() //also heal our host if inside of them and we aren't recovering
|
||||
else if(health == maxHealth)
|
||||
to_chat(src, "<span class='userdanger'>Your strength has returned. You can once again come forward!</span>")
|
||||
to_chat(host, "<span class='userdanger'>Your guardian is now strong enough to come forward again!</span>")
|
||||
recovering = FALSE
|
||||
else
|
||||
if(GLOB.ratvar_awakens) //If Ratvar is alive, guardians don't need a host and are downright impossible to kill
|
||||
adjustHealth(-5)
|
||||
heal_host()
|
||||
else if(host)
|
||||
if(!is_servant_of_ratvar(host))
|
||||
unbind_from_host()
|
||||
return
|
||||
if(host.stat == DEAD)
|
||||
adjustHealth(50)
|
||||
to_chat(src, "<span class='userdanger'>Your host is dead!</span>")
|
||||
return
|
||||
if(z && host.z && z == host.z)
|
||||
switch(get_dist(get_turf(src), get_turf(host)))
|
||||
if(2)
|
||||
adjustHealth(-1)
|
||||
if(3)
|
||||
//EQUILIBRIUM
|
||||
if(4)
|
||||
adjustHealth(1)
|
||||
if(5)
|
||||
adjustHealth(3)
|
||||
if(6)
|
||||
adjustHealth(6)
|
||||
if(7)
|
||||
adjustHealth(9)
|
||||
if(8 to INFINITY)
|
||||
adjustHealth(15)
|
||||
to_chat(src, "<span class='userdanger'>You're too far from your host and rapidly taking damage!</span>")
|
||||
else //right next to or on top of host
|
||||
adjustHealth(-2)
|
||||
heal_host() //gradually heal host if nearby and host is very weak
|
||||
else //well then, you're not even in the same zlevel
|
||||
adjustHealth(15)
|
||||
to_chat(src, "<span class='userdanger'>You're too far from your host and rapidly taking damage!</span>")
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/death(gibbed)
|
||||
emerge_from_host(FALSE, TRUE)
|
||||
unbind_from_host()
|
||||
visible_message("<span class='warning'>[src]'s equipment clatters lifelessly to the ground as the red flames within dissipate.</span>", \
|
||||
"<span class='userdanger'>Your equipment falls away. You feel a moment of confusion before your fragile form is annihilated.</span>")
|
||||
. = ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/Stat()
|
||||
..()
|
||||
if(statpanel("Status"))
|
||||
stat(null, "Current True Name: [true_name]")
|
||||
stat(null, "Host: [host ? host : "NONE"]")
|
||||
if(host)
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
stat(null, "Host Health: [resulthealth]%")
|
||||
if(GLOB.ratvar_awakens)
|
||||
stat(null, "You are [recovering ? "un" : ""]able to deploy!")
|
||||
else
|
||||
if(resulthealth > GUARDIAN_EMERGE_THRESHOLD)
|
||||
stat(null, "You are [recovering ? "unable to deploy" : "able to deploy on hearing your True Name"]!")
|
||||
else
|
||||
stat(null, "You are [recovering ? "unable to deploy" : "able to deploy to protect your host"]!")
|
||||
stat(null, "You do [melee_damage_upper] damage on melee attacks.")
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/bind_to_host(mob/living/new_host)
|
||||
if(!new_host)
|
||||
return FALSE
|
||||
host = new_host
|
||||
var/datum/action/innate/summon_guardian/SG = new()
|
||||
SG.linked_guardian = src
|
||||
SG.Grant(host)
|
||||
var/datum/action/innate/linked_minds/LM = new()
|
||||
LM.linked_guardian = src
|
||||
LM.Grant(host)
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/unbind_from_host()
|
||||
if(host)
|
||||
for(var/datum/action/innate/summon_guardian/SG in host.actions)
|
||||
qdel(SG)
|
||||
for(var/datum/action/innate/linked_minds/LM in host.actions)
|
||||
qdel(LM)
|
||||
host = null
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//DAMAGE and FATIGUE
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/heal_host()
|
||||
if(!host)
|
||||
return
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
if(GLOB.ratvar_awakens || resulthealth <= GUARDIAN_EMERGE_THRESHOLD)
|
||||
new /obj/effect/temp_visual/heal(host.loc, "#AF0AAF")
|
||||
host.heal_ordered_damage(4, damage_heal_order)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/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
|
||||
. = ..()
|
||||
if(src && updating_health)
|
||||
update_health_hud()
|
||||
update_stats()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/update_health_hud()
|
||||
if(hud_used && hud_used.healths)
|
||||
if(istype(hud_used, /datum/hud/marauder))
|
||||
var/datum/hud/marauder/G = hud_used
|
||||
var/resulthealth
|
||||
if(host)
|
||||
if(iscarbon(host))
|
||||
resulthealth = "[round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)]%"
|
||||
else
|
||||
resulthealth = "[round((host.health / host.maxHealth) * 100, 0.5)]%"
|
||||
else
|
||||
resulthealth = "NONE"
|
||||
G.hosthealth.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#AF0AAF'>HOST<br>[resulthealth]</font></div>"
|
||||
hud_used.healths.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font color='#AF0AAF'>[round((health / maxHealth) * 100, 0.5)]%</font>"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/update_stats()
|
||||
if(GLOB.ratvar_awakens)
|
||||
speed = 0
|
||||
melee_damage_lower = 20
|
||||
melee_damage_upper = 20
|
||||
attack_verb_continuous = "devastates"
|
||||
else
|
||||
var/healthpercent = (health/maxHealth) * 100
|
||||
switch(healthpercent)
|
||||
if(100 to 70) //Bonuses to speed and damage at high health
|
||||
speed = 0
|
||||
melee_damage_lower = 16
|
||||
melee_damage_upper = 16
|
||||
attack_verb_continuous = "viciously slashes"
|
||||
if(70 to 40)
|
||||
speed = initial(speed)
|
||||
melee_damage_lower = initial(melee_damage_lower)
|
||||
melee_damage_upper = initial(melee_damage_upper)
|
||||
attack_verb_continuous = initial(attack_verb_continuous)
|
||||
if(40 to 30) //Damage decrease, but not speed
|
||||
speed = initial(speed)
|
||||
melee_damage_lower = 10
|
||||
melee_damage_upper = 10
|
||||
attack_verb_continuous = "lightly slashes"
|
||||
if(30 to 20) //Speed decrease
|
||||
speed = 2
|
||||
melee_damage_lower = 8
|
||||
melee_damage_upper = 8
|
||||
attack_verb_continuous = "lightly slashes"
|
||||
if(20 to 10) //Massive speed decrease and weak melee attacks
|
||||
speed = 3
|
||||
melee_damage_lower = 6
|
||||
melee_damage_upper = 6
|
||||
attack_verb_continuous = "weakly slashes"
|
||||
if(10 to 0) //We are super weak and going to die
|
||||
speed = 4
|
||||
melee_damage_lower = 4
|
||||
melee_damage_upper = 4
|
||||
attack_verb_continuous = "taps"
|
||||
|
||||
//ATTACKING, BLOCKING, and COUNTERING
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/AttackingTarget()
|
||||
if(is_in_host())
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/bullet_act(obj/item/projectile/Proj)
|
||||
if(blockOrCounter(null, Proj))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/hitby(atom/movable/AM, skipcatch, hitpush, blocked, atom/movable/AM, datum/thrownthing/throwingdatum)
|
||||
if(blockOrCounter(null, AM))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attack_animal(mob/living/simple_animal/M)
|
||||
if(istype(M, /mob/living/simple_animal/hostile/clockwork/marauder/guardian) || !blockOrCounter(M, M)) //we don't want infinite blockcounter loops if fighting another guardian
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attack_paw(mob/living/carbon/monkey/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attack_alien(mob/living/carbon/alien/humanoid/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attack_slime(mob/living/simple_animal/slime/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attack_hand(mob/living/carbon/human/M)
|
||||
if(!blockOrCounter(M, M))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/nullrod) || !blockOrCounter(user, I))
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/blockOrCounter(mob/target, atom/textobject)
|
||||
if(GLOB.ratvar_awakens) //if ratvar has woken, we block nearly everything at a very high chance
|
||||
blockchance = 90
|
||||
counterchance = 90
|
||||
if(prob(blockchance))
|
||||
. = TRUE
|
||||
if(target)
|
||||
target.do_attack_animation(src)
|
||||
target.DelayNextAction(CLICK_CD_MELEE)
|
||||
blockchance = initial(blockchance)
|
||||
playsound(src, 'sound/magic/clockwork/fellowship_armory.ogg', 30, 1, 0, 1) //clang
|
||||
visible_message("<span class='boldannounce'>[src] blocks [target && isitem(textobject) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>", \
|
||||
"<span class='userdanger'>You block [target && isitem(textobject) ? "[target]'s [textobject.name]":"\the [textobject]"]!</span>")
|
||||
if(target && Adjacent(target))
|
||||
if(prob(counterchance))
|
||||
counterchance = initial(counterchance)
|
||||
var/previousattack_verb_continuous = attack_verb_continuous
|
||||
attack_verb_continuous = "counters"
|
||||
UnarmedAttack(target)
|
||||
attack_verb_continuous = previousattack_verb_continuous
|
||||
else
|
||||
counterchance = min(counterchance + initial(counterchance), 100)
|
||||
else
|
||||
blockchance = min(blockchance + initial(blockchance), 100)
|
||||
if(GLOB.ratvar_awakens)
|
||||
blockchance = 90
|
||||
counterchance = 90
|
||||
|
||||
//COMMUNICATION and EMERGENCE
|
||||
/*
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/handle_inherent_channels(message, message_mode)
|
||||
if(host && (is_in_host() || message_mode == MODE_BINARY))
|
||||
guardian_comms(message)
|
||||
return TRUE
|
||||
return ..()
|
||||
*/
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/guardian_comms(message)
|
||||
var/name_part = "<span class='sevtug'>[src] ([true_name])</span>"
|
||||
message = "<span class='sevtug_small'>\"[message]\"</span>" //Processed output
|
||||
to_chat(src, "[name_part]<span class='sevtug_small'>:</span> [message]")
|
||||
to_chat(host, "[name_part]<span class='sevtug_small'>:</span> [message]")
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
to_chat(M, "[link] [name_part] <span class='sevtug_small'>(to</span> <span class='sevtug'>[findtextEx(host.name, host.real_name) ? "[host.name]" : "[host.real_name] (as [host.name])"]</span><span class='sevtug_small'>):</span> [message] ")
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/return_to_host()
|
||||
if(is_in_host())
|
||||
return FALSE
|
||||
if(!host)
|
||||
to_chat(src, "<span class='warning'>You don't have a host!</span>")
|
||||
return FALSE
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
host.visible_message("<span class='warning'>[host]'s skin flashes crimson!</span>", "<span class='sevtug'>You feel [true_name]'s consciousness settle in your mind.</span>")
|
||||
visible_message("<span class='warning'>[src] suddenly disappears!</span>", "<span class='sevtug'>You return to [host].</span>")
|
||||
forceMove(host)
|
||||
if(resulthealth > GUARDIAN_EMERGE_THRESHOLD && health != maxHealth)
|
||||
recovering = TRUE
|
||||
to_chat(src, "<span class='userdanger'>You have weakened and will need to recover before manifesting again!</span>")
|
||||
to_chat(host, "<span class='sevtug'>[true_name] has weakened and will need to recover before manifesting again!</span>")
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/try_emerge()
|
||||
if(!host)
|
||||
to_chat(src, "<span class='warning'>You don't have a host!</span>")
|
||||
return FALSE
|
||||
if(!GLOB.ratvar_awakens)
|
||||
var/resulthealth = round((host.health / host.maxHealth) * 100, 0.5)
|
||||
if(iscarbon(host))
|
||||
resulthealth = round((abs(HEALTH_THRESHOLD_DEAD - host.health) / abs(HEALTH_THRESHOLD_DEAD - host.maxHealth)) * 100)
|
||||
if(host.stat != DEAD && resulthealth > GUARDIAN_EMERGE_THRESHOLD) //if above 20 health, fails
|
||||
to_chat(src, "<span class='warning'>Your host must be at [GUARDIAN_EMERGE_THRESHOLD]% or less health to emerge like this!</span>")
|
||||
return FALSE
|
||||
return emerge_from_host(FALSE)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/emerge_from_host(hostchosen, force) //Notice that this is a proc rather than a verb - guardians can NOT exit at will, but they CAN return
|
||||
if(!is_in_host())
|
||||
return FALSE
|
||||
if(!force && recovering)
|
||||
if(hostchosen)
|
||||
to_chat(host, "<span class='sevtug'>[true_name] is too weak to come forth!</span>")
|
||||
else
|
||||
to_chat(host, "<span class='sevtug'>[true_name] tries to emerge to protect you, but it's too weak!</span>")
|
||||
to_chat(src, "<span class='userdanger'>You try to come forth, but you're too weak!</span>")
|
||||
return FALSE
|
||||
if(!force)
|
||||
if(hostchosen) //guardian approved
|
||||
to_chat(host, "<span class='sevtug'>Your words echo with power as [true_name] emerges from your body!</span>")
|
||||
else
|
||||
to_chat(host, "<span class='sevtug'>[true_name] emerges from your body to protect you!</span>")
|
||||
forceMove(host.loc)
|
||||
visible_message("<span class='warning'>[host]'s skin glows red as [name] emerges from their body!</span>", "<span class='sevtug_small'>You exit the safety of [host]'s body!</span>")
|
||||
return TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/get_alt_name()
|
||||
return " ([text2ratvar(true_name)])"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/marauder/guardian/proc/is_in_host() //Checks if the guardian is inside of their host
|
||||
return host && loc == host
|
||||
|
||||
//HOST ACTIONS
|
||||
|
||||
//Summon guardian action: Calls forth or recalls your guardian
|
||||
/datum/action/innate/summon_guardian
|
||||
name = "Force Guardian to Emerge/Recall"
|
||||
desc = "Allows you to force your clockwork guardian to emerge or recall as required."
|
||||
button_icon_state = "clockwork_marauder"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/guardian/linked_guardian
|
||||
var/list/defend_phrases = list("Defend me", "Come forth", "Assist me", "Protect me", "Give aid", "Help me")
|
||||
var/list/return_phrases = list("Return", "Return to me", "Your job is done", "You have served", "Come back", "Retreat")
|
||||
|
||||
/datum/action/innate/summon_guardian/IsAvailable()
|
||||
if(!linked_guardian)
|
||||
return FALSE
|
||||
if(isliving(owner))
|
||||
var/mob/living/L = owner
|
||||
if(!L.can_speak_vocal() || L.stat)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/summon_guardian/Activate()
|
||||
if(linked_guardian.is_in_host())
|
||||
clockwork_say(owner, text2ratvar("[pick(defend_phrases)], [linked_guardian.true_name]!"))
|
||||
linked_guardian.emerge_from_host(TRUE)
|
||||
else
|
||||
clockwork_say(owner, text2ratvar("[pick(return_phrases)], [linked_guardian.true_name]!"))
|
||||
linked_guardian.return_to_host()
|
||||
return TRUE
|
||||
|
||||
//Linked Minds action: talks to your guardian
|
||||
/datum/action/innate/linked_minds
|
||||
name = "Linked Minds"
|
||||
desc = "Allows you to silently communicate with your guardian."
|
||||
button_icon_state = "linked_minds"
|
||||
background_icon_state = "bg_clock"
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
buttontooltipstyle = "clockcult"
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/guardian/linked_guardian
|
||||
|
||||
/datum/action/innate/linked_minds/IsAvailable()
|
||||
if(!linked_guardian)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/linked_minds/Activate()
|
||||
var/message = stripped_input(owner, "Enter a message to tell your guardian.", "Telepathy")
|
||||
if(!owner || !message)
|
||||
return FALSE
|
||||
if(!linked_guardian)
|
||||
to_chat(owner, "<span class='warning'>Your guardian seems to have been destroyed!</span>")
|
||||
return FALSE
|
||||
var/name_part = "<span class='sevtug'>Servant [findtextEx(owner.name, owner.real_name) ? "[owner.name]" : "[owner.real_name] (as [owner.name])"]</span>"
|
||||
message = "<span class='sevtug_small'>\"[message]\"</span>" //Processed output
|
||||
to_chat(owner, "[name_part]<span class='sevtug_small'>:</span> [message]")
|
||||
to_chat(linked_guardian, "[name_part]<span class='sevtug_small'>:</span> [message]")
|
||||
for(var/M in GLOB.mob_list)
|
||||
if(isobserver(M))
|
||||
var/link = FOLLOW_LINK(M, src)
|
||||
to_chat(M, "[link] [name_part] <span class='sevtug_small'>(to</span> <span class='sevtug'>[linked_guardian] ([linked_guardian.true_name])</span><span class='sevtug_small'>):</span> [message]")
|
||||
return TRUE
|
||||
|
||||
@@ -3,8 +3,9 @@ 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
|
||||
Scripts: 35k power or one convert
|
||||
Applications: 50k or three converts
|
||||
Judgement 5 converts
|
||||
*/
|
||||
|
||||
/datum/clockwork_scripture
|
||||
@@ -129,11 +130,11 @@ Applications: 8 servants, 3 caches, and 100 CV
|
||||
SEND_SOUND(invoker, sound('sound/magic/clockwork/invoke_general.ogg'))
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/proc/check_offstation_penalty()
|
||||
/datum/clockwork_scripture/proc/check_offstation_penalty()//don't cast spells away from the station
|
||||
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
|
||||
channel_time *= 3
|
||||
power_cost *= 3
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/proc/check_special_requirements() //Special requirements for scriptures, checked multiple times during invocation
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//////////////////
|
||||
// APPLICATIONS //
|
||||
// APPLICATIONS // For various structures and base building, as well as advanced power generation.
|
||||
//////////////////
|
||||
|
||||
|
||||
@@ -23,6 +23,37 @@
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Sigil of Transmission, which can drain and will store power for clockwork structures."
|
||||
|
||||
//Prolonging Prism: Creates a prism that will delay the shuttle at a power cost
|
||||
/datum/clockwork_scripture/create_object/prolonging_prism
|
||||
descname = "Powered Structure, Delay Emergency Shuttles"
|
||||
name = "Prolonging Prism"
|
||||
desc = "Creates a mechanized prism which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost."
|
||||
invocations = list("May this prism...", "...grant us time to enact his will!")
|
||||
channel_time = 80
|
||||
power_cost = 300
|
||||
object_path = /obj/structure/destructible/clockwork/powered/prolonging_prism
|
||||
creator_message = "<span class='brass'>You form a prolonging prism, which will delay the arrival of an emergency shuttle at a massive power cost.</span>"
|
||||
observer_message = "<span class='warning'>An onyx prism forms in midair and sprouts tendrils to support itself!</span>"
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
usage_tip = "The power cost to delay a shuttle increases based on the number of times activated."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 4
|
||||
important = TRUE
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Prolonging Prism, which will delay the arrival of an emergency shuttle by 2 minutes at a massive power cost."
|
||||
|
||||
/datum/clockwork_scripture/create_object/prolonging_prism/check_special_requirements()
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
|
||||
to_chat(invoker, "<span class='inathneq'>\"It is too late to construct one of these, champion.\"</span>")
|
||||
return FALSE
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!T || !is_station_level(T.z))
|
||||
to_chat(invoker, "<span class='inathneq'>\"You must be on the station to construct one of these, champion.\"</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
//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
|
||||
@@ -44,6 +75,7 @@
|
||||
sort_priority = 2
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Mania Motor, which causes minor damage and negative mental effects in non-Servants."
|
||||
requires_full_power = TRUE
|
||||
|
||||
|
||||
//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.
|
||||
@@ -67,6 +99,64 @@
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Clockwork Obelisk, which can send messages or open Spatial Gateways with power."
|
||||
|
||||
//Memory Allocation: Finds a willing ghost and makes them into a clockwork guardian for the invoker.
|
||||
/datum/clockwork_scripture/memory_allocation
|
||||
descname = "Personal Guardian, A Peice Of Your Mind."
|
||||
name = "Memory Allocation"
|
||||
desc = "Allocates part of your consciousness to a Clockwork Guardian, a variant of Marauder that lives within you, able to be \
|
||||
called forth by Speaking its True Name or if you become exceptionally low on health.<br>\
|
||||
If it remains close to you, you will gradually regain health up to a low amount, but it will die if it goes too far from you."
|
||||
invocations = list("Fright's will...", "...call forth...")
|
||||
channel_time = 100
|
||||
power_cost = 8000
|
||||
usage_tip = "guardians are useful as personal bodyguards and frontline warriors."
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 5
|
||||
|
||||
/datum/clockwork_scripture/memory_allocation/check_special_requirements()
|
||||
for(var/mob/living/simple_animal/hostile/clockwork/marauder/guardian/M in GLOB.all_clockwork_mobs)
|
||||
if(M.host == invoker)
|
||||
to_chat(invoker, "<span class='warning'>You can only house one guardian at a time!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/memory_allocation/scripture_effects()
|
||||
return create_guardian()
|
||||
|
||||
/datum/clockwork_scripture/memory_allocation/proc/create_guardian()
|
||||
invoker.visible_message("<span class='warning'>A purple tendril appears from [invoker]'s [slab.name] and impales itself in [invoker.p_their()] forehead!</span>", \
|
||||
"<span class='sevtug'>A tendril flies from [slab] into your forehead. You begin waiting while it painfully rearranges your thought pattern...</span>")
|
||||
//invoker.notransform = TRUE //Vulnerable during the process
|
||||
slab.busy = "Thought Modification in progress"
|
||||
if(!do_after(invoker, 50, target = invoker))
|
||||
invoker.visible_message("<span class='warning'>The tendril, covered in blood, retracts from [invoker]'s head and back into the [slab.name]!</span>", \
|
||||
"<span class='userdanger'>Total agony overcomes you as the tendril is forced out early!</span>")
|
||||
invoker.Knockdown(100)
|
||||
invoker.apply_damage(50, BRUTE, "head")//Sevtug leaves a gaping hole in your face if interrupted.
|
||||
slab.busy = null
|
||||
return FALSE
|
||||
clockwork_say(invoker, text2ratvar("...the mind made..."))
|
||||
//invoker.notransform = FALSE
|
||||
slab.busy = "Guardian Selection in progress"
|
||||
if(!check_special_requirements())
|
||||
return FALSE
|
||||
to_chat(invoker, "<span class='warning'>The tendril shivers slightly as it selects a guardian...</span>")
|
||||
var/list/marauder_candidates = pollGhostCandidates("Do you want to play as the clockwork guardian of [invoker.real_name]?", ROLE_SERVANT_OF_RATVAR, null, FALSE, 50, POLL_IGNORE_HOLOPARASITE)
|
||||
if(!check_special_requirements())
|
||||
return FALSE
|
||||
if(!marauder_candidates.len)
|
||||
invoker.visible_message("<span class='warning'>The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!</span>", \
|
||||
"<span class='warning'>The tendril was unsuccessful! Perhaps you should try again another time.</span>")
|
||||
return FALSE
|
||||
clockwork_say(invoker, text2ratvar("...sword and shield!"))
|
||||
var/mob/dead/observer/theghost = pick(marauder_candidates)
|
||||
var/mob/living/simple_animal/hostile/clockwork/marauder/guardian/M = new(invoker)
|
||||
M.key = theghost.key
|
||||
M.bind_to_host(invoker)
|
||||
invoker.visible_message("<span class='warning'>The tendril retracts from [invoker]'s head, sealing the entry wound as it does so!</span>", \
|
||||
"<span class='sevtug'>[M.true_name], a clockwork guardian, has taken up residence in your mind. Communicate with it via the \"Linked Minds\" action button.</span>")
|
||||
return TRUE
|
||||
|
||||
//Clockwork Marauder: Creates a construct shell for a clockwork marauder, a well-rounded frontline fighter.
|
||||
/datum/clockwork_scripture/create_object/construct/clockwork_marauder
|
||||
@@ -81,7 +171,7 @@
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
one_per_tile = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 4
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a clockwork marauder, used for frontline combat."
|
||||
object_path = /obj/item/clockwork/construct_chassis/clockwork_marauder
|
||||
@@ -117,14 +207,13 @@
|
||||
/datum/clockwork_scripture/create_object/summon_arbiter
|
||||
descname = "Powerful Assault Mech"
|
||||
name = "Summon Neovgre, the Anima Bulwark"
|
||||
desc = "Calls forth the mighty Anima Bulwark, a weapon of unmatched power,\
|
||||
mech with superior defensive and offensive capabilities. It will \
|
||||
desc = "Calls forth the mighty Anima Bulwark, a mech with superior defensive and offensive capabilities. It will \
|
||||
steadily regenerate HP and triple its regeneration speed while standing \
|
||||
on a clockwork tile. It will automatically draw power from nearby sigils of \
|
||||
transmission should the need arise. Its Arbiter laser cannon can decimate foes \
|
||||
from a range and is capable of smashing through any barrier presented to it. \
|
||||
Be warned, choosing to pilot Neovgre is a lifetime commitment, once you are \
|
||||
in you cannot leave and when it is destroyed it will explode catastrophically with you inside."
|
||||
Be warned however, choosing to pilot Neovgre is a lifetime commitment, once you are \
|
||||
in you cannot leave and when it is destroyed it will explode catastrophically, with you inside."
|
||||
invocations = list("By the strength of the alloy...!!", "...call forth the Arbiter!!")
|
||||
channel_time = 200 // This is a strong fucking weapon, 20 seconds channel time is getting off light I tell ya.
|
||||
power_cost = 75000 //75 KW
|
||||
@@ -134,7 +223,7 @@
|
||||
object_path = /obj/mecha/combat/neovgre
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 2
|
||||
sort_priority = 7
|
||||
creator_message = "<span class='brass'>Neovgre, the Anima Bulwark towers over you... your enemies reckoning has come.</span>"
|
||||
|
||||
/datum/clockwork_scripture/create_object/summon_arbiter/check_special_requirements()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/////////////////
|
||||
// CYBORG ONLY //
|
||||
// CYBORG ONLY // Cyborgs only, fleshed ones.
|
||||
/////////////////
|
||||
|
||||
//Linked Vanguard: grants Vanguard to the invoker and a target
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/////////////
|
||||
// DRIVERS //
|
||||
// DRIVERS // Starter spells
|
||||
/////////////
|
||||
|
||||
//Stargazer: Creates a stargazer, a cheap power generator that utilizes starlight.
|
||||
@@ -97,7 +97,7 @@
|
||||
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 = 20 // I think making kindle channel a third of the time less is a good make up for the fact that it silences people for such a little amount of time.
|
||||
channel_time = 15 // I think making kindle channel a third of the time less is a good make up for the fact that it silences people for such a little amount of time.
|
||||
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
|
||||
@@ -113,7 +113,6 @@
|
||||
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"
|
||||
@@ -192,43 +191,39 @@
|
||||
Click your slab to cancel.</b></span>"
|
||||
|
||||
|
||||
/*//commenting this out until its reworked to actually do random teleports
|
||||
//Abscond: Used to return to Reebe.
|
||||
/datum/clockwork_scripture/abscond
|
||||
descname = "Return to Reebe"
|
||||
descname = "Safety warp, teleports you somewhere random. moderately high power cost to use."
|
||||
name = "Abscond"
|
||||
desc = "Yanks you through space, returning you to home base."
|
||||
desc = "Yanks you through space, putting you in hopefully a safe location."
|
||||
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
|
||||
channel_time = 3.5
|
||||
power_cost = 10000
|
||||
usage_tip = "This can't be used while on Reebe, for obvious reasons."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 9
|
||||
important = TRUE
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Returns you to Reebe."
|
||||
quickbind_desc = "Teleports you somewhere random, or to an active Ark if one exists. Use in emergencies."
|
||||
var/client_color
|
||||
requires_full_power = TRUE
|
||||
|
||||
/datum/clockwork_scripture/abscond/check_special_requirements()
|
||||
if(is_reebe(invoker.z))
|
||||
to_chat(invoker, "<span class='danger'>You're already at Reebe.</span>")
|
||||
to_chat(invoker, "<span class='danger'>You're at Reebe, attempting to warp in the void could cause you to share your masters fate of banishment!.</span>")
|
||||
return
|
||||
if(!isturf(invoker.loc))
|
||||
to_chat(invoker, "<span class='danger'>You must be visible to return!</span>")
|
||||
to_chat(invoker, "<span class='danger'>You must be visible to warp!</span>")
|
||||
return
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/abscond/recital()
|
||||
client_color = invoker.client.color
|
||||
animate(invoker.client, color = "#AF0AAF", time = 50)
|
||||
. = ..()
|
||||
|
||||
/datum/clockwork_scripture/abscond/scripture_effects()
|
||||
var/mob/living/pulled_mob = (invoker.pulling && isliving(invoker.pulling) && get_clockwork_power(ABSCOND_ABDUCTION_COST)) ? invoker.pulling : null
|
||||
var/turf/T
|
||||
if(GLOB.ark_of_the_clockwork_justiciar)
|
||||
T = get_step(GLOB.ark_of_the_clockwork_justiciar, SOUTH)
|
||||
@@ -237,21 +232,12 @@
|
||||
if(!do_teleport(invoker, T, channel = TELEPORT_CHANNEL_CULT, forced = TRUE))
|
||||
return
|
||||
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>")
|
||||
"<span class='bold sevtug_small'>You feel a dizzying sense of vertigo as you're yanked through the fabric of reality!</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(pulled_mob && do_teleport(pulled_mob, T, channel = TELEPORT_CHANNEL_CULT, forced = TRUE))
|
||||
adjust_clockwork_power(-special_power_cost)
|
||||
invoker.start_pulling(pulled_mob) //forcemove resets pulls, so we need to re-pull
|
||||
if(invoker.client)
|
||||
animate(invoker.client, color = client_color, time = 25)
|
||||
|
||||
/datum/clockwork_scripture/abscond/scripture_fail()
|
||||
if(invoker && invoker.client)
|
||||
animate(invoker.client, color = client_color, time = 10)
|
||||
do_sparks(5, TRUE, T)*/
|
||||
|
||||
|
||||
//Replicant: Creates a new clockwork slab.
|
||||
@@ -265,7 +251,7 @@
|
||||
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."
|
||||
usage_tip = "This is inefficient as a way to produce power, as the slab produced must be held by someone with no other slabs to produce any."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
space_allowed = TRUE
|
||||
primary_component = GEIS_CAPACITOR
|
||||
@@ -293,3 +279,50 @@
|
||||
sort_priority = 11
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a pair of Wraith Spectacles, which grant true sight but cause gradual vision loss."
|
||||
|
||||
//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 = 30
|
||||
power_cost = 400
|
||||
whispered = TRUE
|
||||
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_DRIVER
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
|
||||
|
||||
/datum/clockwork_scripture/spatial_gateway/check_special_requirements()
|
||||
if(!isturf(invoker.loc))
|
||||
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)
|
||||
@@ -0,0 +1,44 @@
|
||||
///////////////
|
||||
// JUDGEMENT // For the big game changing things. TODO: Summonable generals, just need mob sprites for them.
|
||||
///////////////
|
||||
|
||||
//Ark of the Clockwork Justiciar: Creates a Gateway to the Celestial Derelict, summoning ratvar.
|
||||
/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar
|
||||
descname = "Structure, Win Condition"
|
||||
name = "Ark of the Clockwork Justiciar"
|
||||
desc = "Tears apart a rift in spacetime to Reebe, the Celestial Derelict, using a massive amount of power.\n\
|
||||
This gateway will, after some time, call forth Ratvar from his exile and massively empower all scriptures and tools."
|
||||
invocations = list("ARMORER! FRIGHT! AMPERAGE! VANGUARD! WE CALL UPON YOU!!", \
|
||||
"THE TIME HAS COME FOR OUR MASTER TO BREAK THE CHAINS OF EXILE!!", \
|
||||
"LEND US YOUR AID! ENGINE COMES!!")
|
||||
channel_time = 150
|
||||
power_cost = 70000 //70 KW. It's literally the thing wrenching the god out of another dimension why wouldn't it be costly.
|
||||
invokers_required = 6
|
||||
multiple_invokers_used = TRUE
|
||||
object_path = /obj/structure/destructible/clockwork/massive/celestial_gateway
|
||||
creator_message = "<span class='heavy_brass'>The Ark swirls into existance before you with the help of the Generals. After all this time, he shall, finally, be free</span>"
|
||||
usage_tip = "The gateway is completely vulnerable to attack during its five-minute duration. It will periodically give indication of its general position to everyone on the station \
|
||||
as well as being loud enough to be heard throughout the entire sector. Defend it with your life!"
|
||||
tier = SCRIPTURE_APPLICATION
|
||||
sort_priority = 8
|
||||
requires_full_power = TRUE
|
||||
|
||||
/datum/clockwork_scripture/create_object/ark_of_the_clockwork_justiciar/check_special_requirements()
|
||||
if(!slab.no_cost)
|
||||
if(GLOB.ratvar_awakens)
|
||||
to_chat(invoker, "<span class='big_brass'>\"I am already here, there is no point in that.\"</span>")
|
||||
return FALSE
|
||||
for(var/obj/structure/destructible/clockwork/massive/celestial_gateway/G in GLOB.all_clockwork_objects)
|
||||
var/area/gate_area = get_area(G)
|
||||
to_chat(invoker, "<span class='userdanger'>There is already an Ark at [gate_area.map_name]!</span>")
|
||||
return FALSE
|
||||
var/area/A = get_area(invoker)
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!T || !is_station_level(T.z) || istype(A, /area/shuttle) || !A.blob_allowed)
|
||||
to_chat(invoker, "<span class='warning'>You must be on the station to activate the Ark!</span>")
|
||||
return FALSE
|
||||
if(GLOB.clockwork_gateway_activated)
|
||||
to_chat(invoker, "<span class='warning'>Ratvar's recent banishment renders him too weak to be wrung forth from Reebe!</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/////////////
|
||||
// SCRIPTS //
|
||||
// SCRIPTS // Various miscellanious spells for offense/defense/construction.
|
||||
/////////////
|
||||
|
||||
|
||||
@@ -81,6 +81,25 @@
|
||||
return /obj/effect/clockwork/sigil/vitality/neutered
|
||||
return ..()
|
||||
|
||||
//Sigil of Rites: Creates a sigil that allows to perform certain rites on it. More information on these can be found in clock_rites.dm, they usually require power, materials and sometimes a target.
|
||||
/datum/clockwork_scripture/create_object/sigil_of_rites
|
||||
descname = "Sigil, Access to rites"
|
||||
name = "Sigil of Rites"
|
||||
desc = "Places a sigil that, when interacted with, will allow for a variety of rites to be performed on the sigil. These usually require power cells, clockwork power, and some other components."
|
||||
invocations = list("Engine, allow us..", ".. to be blessed with your rites.")
|
||||
channel_time = 80
|
||||
power_cost = 1400
|
||||
invokers_required = 2
|
||||
multiple_invokers_used = TRUE
|
||||
whispered = TRUE
|
||||
object_path = /obj/effect/clockwork/sigil/rite
|
||||
creator_message = "<span class='brass'>A sigil of Rites appears beneath you. It will allow you to perform certain rites, given sufficient materials and power.</span>"
|
||||
usage_tip = "It may be useful to coordinate to acquire needed materials quickly."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
one_per_tile = TRUE
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 4
|
||||
|
||||
//Judicial Visor: Creates a judicial visor, which can smite an area.
|
||||
/datum/clockwork_scripture/create_object/judicial_visor
|
||||
descname = "Delayed Area Knockdown Glasses"
|
||||
@@ -96,7 +115,7 @@
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 4
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Judicial Visor, which can smite an area, applying Belligerent and briefly stunning."
|
||||
|
||||
@@ -115,7 +134,7 @@
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 6
|
||||
sort_priority = 7
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Ratvarian shield, which can absorb energy from attacks for use in powerful bashes."
|
||||
|
||||
@@ -131,7 +150,7 @@
|
||||
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 = 7
|
||||
sort_priority = 8
|
||||
important = TRUE
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you."
|
||||
@@ -217,53 +236,6 @@
|
||||
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 = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
|
||||
|
||||
/datum/clockwork_scripture/spatial_gateway/check_special_requirements()
|
||||
if(!isturf(invoker.loc))
|
||||
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)
|
||||
|
||||
|
||||
//Mending Mantra: Channeled for up to ten times over twenty seconds to repair structures and heal allies
|
||||
/datum/clockwork_scripture/channeled/mending_mantra
|
||||
descname = "Channeled, Area Healing and Repair"
|
||||
@@ -276,7 +248,7 @@
|
||||
usage_tip = "This is a very effective way to rapidly reinforce a base after an attack."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 8
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed.<br><b>Maximum 10 chants.</b>"
|
||||
var/heal_attempts = 4
|
||||
@@ -389,7 +361,7 @@
|
||||
usage_tip = "Though it requires you to stand still, this scripture can do massive damage."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 5
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to fire energy rays at target locations.<br><b>Maximum 5 chants.</b>"
|
||||
var/static/list/nzcrentr_insults = list("You're not very good at aiming.", "You hunt badly.", "What a waste of energy.", "Almost funny to watch.",
|
||||
@@ -438,7 +410,7 @@
|
||||
usage_tip = "It may be useful to end channelling early if the burning becomes too much to handle.."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 10
|
||||
sort_priority = 11
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Quickly drains power in an area around the invoker, causing burns proportional to the amount of energy drained.<br><b>Maximum of 20 chants.</b>"
|
||||
|
||||
@@ -487,3 +459,26 @@
|
||||
invoker.light_range = 0
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
|
||||
//Belligerent: Channeled for up to fifteen times over thirty seconds. Forces non-servants that can hear the chant to walk, doing minor damage. Nar-Sian cultists are burned.
|
||||
/datum/clockwork_scripture/channeled/belligerent
|
||||
descname = "Channeled, Area Slowdown"
|
||||
name = "Belligerent"
|
||||
desc = "Forces all nearby non-servants to walk rather than run, doing minor damage. Chanted every two seconds for up to thirty seconds."
|
||||
chant_invocations = list("Punish their blindness!", "Take time, make slow!", "Kneel before The Justiciar!", "Halt their charges!", "Cease the tides!")
|
||||
chant_amount = 15
|
||||
chant_interval = 20
|
||||
channel_time = 20
|
||||
power_cost = 300
|
||||
usage_tip = "Useful for crowd control in a populated area and disrupting mass movement."
|
||||
tier = SCRIPTURE_DRIVER
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 1
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Forces nearby non-Servants to walk, doing minor damage with each chant.<br><b>Maximum 15 chants.</b>"
|
||||
|
||||
/datum/clockwork_scripture/channeled/belligerent/chant_effects(chant_number)
|
||||
for(var/mob/living/carbon/C in hearers(7, invoker))
|
||||
C.apply_status_effect(STATUS_EFFECT_BELLIGERENT)
|
||||
new /obj/effect/temp_visual/ratvar/belligerent(get_turf(invoker))
|
||||
return TRUE
|
||||
|
||||
+83
-93
@@ -1,5 +1,3 @@
|
||||
#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)
|
||||
@@ -11,7 +9,7 @@
|
||||
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."
|
||||
its instability will alert the entire area, so be prepared to defend it at all costs."
|
||||
max_integrity = 500
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
@@ -22,9 +20,8 @@
|
||||
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/initial_activation_delay = 5 //How many seconds the Ark will have initially taken to activate
|
||||
var/seconds_until_activation = 5 //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
|
||||
@@ -38,10 +35,21 @@
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/Initialize()
|
||||
. = ..()
|
||||
INVOKE_ASYNC(src, .proc/spawn_animation)
|
||||
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/on_attack_hand(mob/user, act_intent, unarmed_attack_flags)
|
||||
if(!active && is_servant_of_ratvar(user) && user.canUseTopic(src, !issilicon(user), NO_DEXTERY))
|
||||
if(alert(user, "Are you sure you want to activate the ark? Once enabled, there will be no turning back.", "Enabling the ark", "Activate!", "Cancel") == "Activate!")
|
||||
if(active)
|
||||
return
|
||||
log_game("[key_name(user)] has activated an Ark of the Clockwork Justicar at [COORD(src)].")
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
else
|
||||
to_chat(user, "<span class='brass'>You decide against activating the ark.. for now.</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
. = ..()
|
||||
@@ -49,7 +57,7 @@
|
||||
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>")
|
||||
audible_message("<span class='boldwarning'>An unearthly screaming sound resonates throughout the area!</span>")
|
||||
for(var/V in GLOB.player_list)
|
||||
var/mob/M = V
|
||||
var/turf/T = get_turf(M)
|
||||
@@ -60,31 +68,19 @@
|
||||
|
||||
/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
|
||||
ark_time = 5 //5 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
|
||||
visible_message("<span class='boldwarning'>[src] shudders and roars to life, its parts beginning to whirr and screech!</span>")
|
||||
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')
|
||||
not a drill.", "Central Command Higher Dimensional Affairs", 'sound/magic/clockwork/ark_activation_sequence.ogg')
|
||||
set_security_level("delta")
|
||||
for(var/V in SSticker.mode.servants_of_ratvar)
|
||||
var/datum/mind/M = V
|
||||
@@ -92,15 +88,6 @@
|
||||
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
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
var/list/open_turfs = list()
|
||||
for(var/turf/open/OT in orange(1, T))
|
||||
@@ -110,14 +97,35 @@
|
||||
for(var/mob/living/L in T)
|
||||
L.forceMove(pick(open_turfs))
|
||||
|
||||
/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()
|
||||
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)
|
||||
var/turf/T = get_turf(src)
|
||||
new/obj/effect/clockwork/general_marker/inathneq(T)
|
||||
hierophant_message("<span class='inathneq'>\"[text2ratvar("Engine, come forth and show your servants your mercy")]!\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 30, 0)
|
||||
sleep(10)
|
||||
new/obj/effect/clockwork/general_marker/sevtug(T)
|
||||
hierophant_message("<span class='sevtug'>\"[text2ratvar("Engine, come forth and show this station your decorating skills")]!\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 45, 0)
|
||||
sleep(10)
|
||||
new/obj/effect/clockwork/general_marker/nezbere(T)
|
||||
hierophant_message("<span class='nezbere'>\"[text2ratvar("Engine, come forth and shine your light across this realm")]!!\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 60, 0)
|
||||
sleep(10)
|
||||
new/obj/effect/clockwork/general_marker/nzcrentr(T)
|
||||
hierophant_message("<span class='nzcrentr'>\"[text2ratvar("Engine, come forth")].\"</span>")
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 75, 0)
|
||||
sleep(10)
|
||||
playsound(T, 'sound/magic/clockwork/invoke_general.ogg', 100, 0)
|
||||
var/list/open_turfs = list()
|
||||
for(var/turf/open/OT in orange(1, T))
|
||||
if(!is_blocked_turf(OT, TRUE))
|
||||
open_turfs |= OT
|
||||
if(open_turfs.len)
|
||||
for(var/mob/living/L in T)
|
||||
L.forceMove(pick(open_turfs))
|
||||
glow = new(get_turf(src))
|
||||
var/area/gate_area = get_area(src)
|
||||
hierophant_message("<span class='large_brass'><b>An Ark of the Clockwork Justicar has been created in [gate_area.map_name]!</b></span>", FALSE, src)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/initiate_mass_recall()
|
||||
recalling = TRUE
|
||||
@@ -141,35 +149,22 @@
|
||||
transform = matrix() * 2
|
||||
animate(src, transform = matrix() * 0.5, time = 30, flags = ANIMATION_END_NOW)
|
||||
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy()
|
||||
obj/structure/destructible/clockwork/massive/celestial_gateway/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
if(!purpose_fulfilled)
|
||||
var/area/gate_area = get_area(src)
|
||||
hierophant_message("<span class='large_brass'><b>An Ark of the Clockwork Justicar has fallen at [gate_area.map_name]!</b></span>")
|
||||
send_to_playing_players(sound(null, 0, channel = CHANNEL_JUSTICAR_ARK))
|
||||
var/was_stranded = SSshuttle.emergency.mode == SHUTTLE_STRANDED
|
||||
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(!was_stranded && !purpose_fulfilled)
|
||||
priority_announce("Massive energy anomaly no longer on short-range scanners, bluespace distortions still detected.","Central Command Higher Dimensional Affairs")
|
||||
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)
|
||||
@@ -203,8 +198,6 @@
|
||||
/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)
|
||||
@@ -213,8 +206,6 @@
|
||||
/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"
|
||||
@@ -229,17 +220,14 @@
|
||||
if(!active)
|
||||
. += "<span class='big'><b>Time until the Ark's activation:</b> [DisplayTimeText(get_arrival_time())]</span>"
|
||||
else
|
||||
if(grace_period)
|
||||
. += "<span class='big'><b>Crew grace period time remaining:</b> [DisplayTimeText(get_arrival_time())]</span>"
|
||||
else
|
||||
. += "<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)
|
||||
. += "<span class='heavy_brass'>The Ark is feeding power into the bluespace field.</span>"
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
. += "<span class='heavy_brass'>The field is ripping open a copy of itself in Ratvar's prison.</span>"
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
. += "<span class='heavy_brass'>With the bluespace field established, Ratvar is preparing to come through!</span>"
|
||||
. += "<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)
|
||||
. += "<span class='heavy_brass'>The Ark is feeding power into the bluespace field.</span>"
|
||||
if(GATEWAY_REEBE_FOUND to GATEWAY_RATVAR_COMING)
|
||||
. += "<span class='heavy_brass'>The field is ripping open a copy of itself in Ratvar's prison.</span>"
|
||||
if(GATEWAY_RATVAR_COMING to INFINITY)
|
||||
. += "<span class='heavy_brass'>With the bluespace field established, Ratvar is preparing to come through!</span>"
|
||||
else
|
||||
if(!active)
|
||||
. += "<span class='warning'>Whatever it is, it doesn't seem to be active.</span>"
|
||||
@@ -253,20 +241,14 @@
|
||||
. += "<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()
|
||||
let_slip_the_dogs()
|
||||
return
|
||||
if(!first_sound_played || prob(7))
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
@@ -285,6 +267,9 @@
|
||||
if(!step_away(O, src, 2) || get_dist(O, src) < 2)
|
||||
O.take_damage(50, BURN, "bomb")
|
||||
O.update_icon()
|
||||
|
||||
conversion_pulse() //Converts the nearby area into clockcult-style
|
||||
|
||||
for(var/V in GLOB.player_list)
|
||||
var/mob/M = V
|
||||
var/turf/T = get_turf(M)
|
||||
@@ -292,29 +277,24 @@
|
||||
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))
|
||||
sound_to_playing_players(volume = 10, 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))
|
||||
sound_to_playing_players(volume = 30, 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))
|
||||
sound_to_playing_players(volume = 70, 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"
|
||||
@@ -334,7 +314,6 @@
|
||||
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))
|
||||
@@ -349,6 +328,17 @@
|
||||
T.ratvar_act(dist)
|
||||
CHECK_TICK
|
||||
|
||||
//Converts nearby turfs into their clockwork equivalent, with ever-increasing range the closer the ark is to summoning Ratvar
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/conversion_pulse()
|
||||
var/convert_dist = 1 + (round(FLOOR(progress_in_seconds, 15) * 0.067))
|
||||
for(var/t in RANGE_TURFS(convert_dist, loc))
|
||||
var/turf/T = t
|
||||
if(!T)
|
||||
continue
|
||||
var/dist = cheap_hypotenuse(T.x, T.y, x, y)
|
||||
if(dist < convert_dist)
|
||||
T.ratvar_act(FALSE, TRUE, 3)
|
||||
|
||||
//ATTACK GHOST IGNORING PARENT RETURN VALUE
|
||||
/obj/structure/destructible/clockwork/massive/celestial_gateway/attack_ghost(mob/user)
|
||||
if(!IsAdminGhost(user))
|
||||
@@ -361,9 +351,9 @@
|
||||
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 \
|
||||
to_chat(user, "<span class='userdanger'>The gamemode is now being treated as clockwork cult, and the Ark is counting down from 5 \
|
||||
minutes. You will need to create servant players yourself.</span>")
|
||||
final_countdown(35)
|
||||
final_countdown(5)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -41,14 +41,19 @@
|
||||
affected += try_use_power(MIN_CLOCKCULT_POWER*4)
|
||||
return affected
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/Destroy()
|
||||
for(var/obj/effect/clockwork/spatial_gateway/SG in loc)
|
||||
SG.ex_act(EXPLODE_DEVASTATE)
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/clockwork_obelisk/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
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")
|
||||
var/choice = alert(user,"You place your hand on [src]...",,"Hierophant Broadcast","Spatial Gateway","Cancel") //Will create a stable gateway instead if between two obelisks one of which is onstation and the other on reebe
|
||||
switch(choice)
|
||||
if("Hierophant Broadcast")
|
||||
if(active)
|
||||
@@ -96,7 +101,7 @@
|
||||
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
|
||||
if(SG && (SG.timerid || SG.is_stable)) //it's a valid gateway, we're active
|
||||
icon_state = active_icon
|
||||
density = FALSE
|
||||
active = TRUE
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
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, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/structure/destructible/clockwork/eminence_spire/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
@@ -27,9 +27,6 @@
|
||||
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)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
|
||||
|
||||
//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
|
||||
@@ -58,7 +60,7 @@
|
||||
. += "<span class='brass'>There are <b>[time_remaining]</b> second[time_remaining != 1 ? "s" : ""] remaining to vote.</span>"
|
||||
. += "<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, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/structure/destructible/clockwork/heralds_beacon/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
@@ -108,5 +110,4 @@
|
||||
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++
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
toggle()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/structure/destructible/clockwork/powered/mania_motor/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
//Prolonging Prism: A prism that consumes power to delay the shuttle
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism
|
||||
name = "prolonging prism"
|
||||
desc = "A dark onyx prism, held in midair by spiraling tendrils of stone."
|
||||
clockwork_desc = "A powerful prism that will delay the arrival of an emergency shuttle."
|
||||
icon_state = "prolonging_prism_inactive"
|
||||
active_icon = "prolonging_prism"
|
||||
inactive_icon = "prolonging_prism_inactive"
|
||||
unanchored_icon = "prolonging_prism_unwrenched"
|
||||
construction_value = 20
|
||||
max_integrity = 125
|
||||
break_message = "<span class='warning'>The prism falls to the ground with a heavy thud!</span>"
|
||||
debris = list(/obj/item/clockwork/alloy_shards/small = 3, \
|
||||
/obj/item/clockwork/alloy_shards/medium = 1, \
|
||||
/obj/item/clockwork/alloy_shards/large = 1, \
|
||||
/obj/item/clockwork/component/vanguard_cogwheel/onyx_prism = 1)
|
||||
var/static/power_refund = 250
|
||||
var/static/delay_cost = 2000 //Updated power values for new-newclock. Easier to activate and sustain, you are quite literally pointing the entire station towards you as opposed to blood-delay after all.
|
||||
var/static/delay_cost_increase = 1000
|
||||
var/static/delay_remaining = 0
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/examine(mob/user)
|
||||
. = ..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
|
||||
. += "<span class='inathneq'>An emergency shuttle has arrived and this prism is no longer useful; attempt to activate it to gain a partial refund of components used.</span>"
|
||||
else
|
||||
var/efficiency = get_efficiency_mod(TRUE)
|
||||
. += "<span class='inathneq_small'>It requires at least <b>[DisplayPower(get_delay_cost())]</b> of power to attempt to delay the arrival of an emergency shuttle by <b>[2 * efficiency]</b> minutes.</span>"
|
||||
. += "<span class='inathneq_small'>This cost increases by <b>[DisplayPower(delay_cost_increase)]</b> for every previous activation.</span>"
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/forced_disable(bad_effects)
|
||||
if(active)
|
||||
if(bad_effects)
|
||||
try_use_power(MIN_CLOCKCULT_POWER*4)
|
||||
visible_message("<span class='warning'>[src] emits an airy chuckling sound and falls dark!</span>")
|
||||
toggle()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/on_attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY) && is_servant_of_ratvar(user))
|
||||
if(SSshuttle.emergency.mode == SHUTTLE_DOCKED || SSshuttle.emergency.mode == SHUTTLE_IGNITING || SSshuttle.emergency.mode == SHUTTLE_STRANDED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE)
|
||||
to_chat(user, "<span class='brass'>You break [src] apart, refunding some of the power used.</span>")
|
||||
adjust_clockwork_power(power_refund)
|
||||
take_damage(max_integrity)
|
||||
return 0
|
||||
if(active)
|
||||
return 0
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T || !is_station_level(T.z))
|
||||
to_chat(user, "<span class='warning'>[src] must be on the station to function!</span>")
|
||||
return 0
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_CALL)
|
||||
to_chat(user, "<span class='warning'>No emergency shuttles are attempting to arrive at the station!</span>")
|
||||
return 0
|
||||
if(!try_use_power(get_delay_cost()))
|
||||
to_chat(user, "<span class='warning'>[src] needs more power to function!</span>")
|
||||
return 0
|
||||
delay_cost += delay_cost_increase
|
||||
delay_remaining += PRISM_DELAY_DURATION
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/process()
|
||||
var/turf/own_turf = get_turf(src)
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_CALL || delay_remaining <= 0 || !own_turf || !is_station_level(own_turf.z))
|
||||
forced_disable(FALSE)
|
||||
return
|
||||
. = ..()
|
||||
var/delay_amount = 40
|
||||
delay_remaining -= delay_amount
|
||||
var/efficiency = get_efficiency_mod()
|
||||
SSshuttle.emergency.setTimer(SSshuttle.emergency.timeLeft(1) + (delay_amount * efficiency))
|
||||
var/highest_y
|
||||
var/highest_x
|
||||
var/lowest_y
|
||||
var/lowest_x
|
||||
var/list/prism_turfs = list()
|
||||
for(var/t in SSshuttle.emergency.ripple_area(SSshuttle.getDock("emergency_home")))
|
||||
prism_turfs[t] = TRUE
|
||||
var/turf/T = t
|
||||
if(!highest_y || T.y > highest_y)
|
||||
highest_y = T.y
|
||||
if(!highest_x || T.x > highest_x)
|
||||
highest_x = T.x
|
||||
if(!lowest_y || T.y < lowest_y)
|
||||
lowest_y = T.y
|
||||
if(!lowest_x || T.x < lowest_x)
|
||||
lowest_x = T.x
|
||||
var/mean_y = LERP(lowest_y, highest_y, 0.5)
|
||||
var/mean_x = LERP(lowest_x, highest_x, 0.5)
|
||||
if(prob(50))
|
||||
mean_y = CEILING(mean_y, 1)
|
||||
else
|
||||
mean_y = FLOOR(mean_y, 1) //Yes, I know round(mean_y) does the same, just left as FLOOR for consistancy sake
|
||||
if(prob(50))
|
||||
mean_x = CEILING(mean_x, 1)
|
||||
else
|
||||
mean_x = FLOOR(mean_x, 1)
|
||||
var/turf/semi_random_center_turf = locate(mean_x, mean_y, z)
|
||||
for(var/t in getline(src, semi_random_center_turf))
|
||||
prism_turfs[t] = TRUE
|
||||
var/placement_style = prob(50)
|
||||
for(var/t in prism_turfs)
|
||||
var/turf/T = t
|
||||
if(placement_style)
|
||||
if(ISODD(T.x + T.y))
|
||||
seven_random_hexes(T, efficiency)
|
||||
else if(prob(50 * efficiency))
|
||||
new /obj/effect/temp_visual/ratvar/prolonging_prism(T)
|
||||
else
|
||||
if(ISEVEN(T.x + T.y))
|
||||
seven_random_hexes(T, efficiency)
|
||||
else if(prob(50 * efficiency))
|
||||
new /obj/effect/temp_visual/ratvar/prolonging_prism(T)
|
||||
CHECK_TICK //we may be going over a hell of a lot of turfs
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/get_delay_cost()
|
||||
return FLOOR(delay_cost, MIN_CLOCKCULT_POWER)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/prolonging_prism/proc/seven_random_hexes(turf/T, efficiency)
|
||||
var/static/list/hex_states = list("prismhex1", "prismhex2", "prismhex3", "prismhex4", "prismhex5", "prismhex6", "prismhex7")
|
||||
var/mutable_appearance/hex_combo
|
||||
for(var/n in hex_states) //BUILD ME A HEXAGON
|
||||
if(prob(50 * efficiency))
|
||||
if(!hex_combo)
|
||||
hex_combo = mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER)
|
||||
else
|
||||
hex_combo.add_overlay(mutable_appearance('icons/effects/64x64.dmi', n, RIPPLE_LAYER))
|
||||
if(hex_combo) //YOU BUILT A HEXAGON
|
||||
hex_combo.pixel_x = -16
|
||||
hex_combo.pixel_y = -16
|
||||
hex_combo.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
hex_combo.plane = GAME_PLANE
|
||||
new /obj/effect/temp_visual/ratvar/prolonging_prism(T, hex_combo)
|
||||
+8
-7
@@ -101,8 +101,8 @@
|
||||
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>")
|
||||
to_chat(world, "<span class='bold brass'><font size=5>\"[pick("YOU.", "BLOOD GOD!!", "FACE ME, COWARD!")]\"</font></span>")
|
||||
to_chat(world, "<span class='bold cult'><font size=5>\"[pick("Ratvar?! How?!", "YOU. BANISHED ONCE. KILLED NOW.", "SCRAP HEAP!!")]\"</font></span>")
|
||||
clash_of_the_titans(GLOB.cult_narsie) // >:(
|
||||
return TRUE
|
||||
|
||||
@@ -137,15 +137,16 @@
|
||||
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\
|
||||
send_to_playing_players("<span class='heavy_brass'><font size=5>\"[pick("DIE.", "ROT FOR CENTURIES, AS I HAVE!.","PERISH, HEATHEN.", "DIE, MONSTER, YOU DON'T BELONG IN THIS WORLD.")]\"</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)
|
||||
sound_to_playing_players('sound/magic/abomscream.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)
|
||||
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>\n\
|
||||
<span class='heavy_brass'><font size=5>\"[pick("NO, YOUR SHADOWS SHALL NO-", "ZNL GUR FGERNZF BS GVZR PNEEL ZL RKVFG-", "MY LIGHT CANNO-")]\"</font></span>")
|
||||
sound_to_playing_players('sound/magic/demon_attack1.ogg', 50)
|
||||
sound_to_playing_players('sound/machines/clockcult/ratvar_scream.ogg', 80)
|
||||
narsie.clashing = FALSE
|
||||
qdel(src)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
max_integrity = 75
|
||||
icon_state = "lever"
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/trigger/lever/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/structure/destructible/clockwork/trap/trigger/lever/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
max_integrity = 15 //Fragile!
|
||||
icon_state = "repeater"
|
||||
|
||||
/obj/structure/destructible/clockwork/trap/trigger/repeater/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/structure/destructible/clockwork/trap/trigger/repeater/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
force = 15
|
||||
throwforce = 25
|
||||
wound_bonus = -30
|
||||
bare_wound_bonus = 30
|
||||
armour_penetration = 35
|
||||
actions_types = list(/datum/action/item_action/cult_dagger)
|
||||
|
||||
@@ -51,10 +53,12 @@
|
||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||
flags_1 = CONDUCT_1
|
||||
sharpness = IS_SHARP
|
||||
sharpness = SHARP_EDGED
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
force = 30
|
||||
force = 30 // whoever balanced this got beat in the head by a bible too many times good lord
|
||||
throwforce = 10
|
||||
wound_bonus = -80
|
||||
bare_wound_bonus = 30
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "rended")
|
||||
|
||||
@@ -110,7 +114,7 @@
|
||||
armour_penetration = 45
|
||||
throw_speed = 1
|
||||
throw_range = 3
|
||||
sharpness = IS_SHARP
|
||||
sharpness = SHARP_EDGED
|
||||
light_color = "#ff0000"
|
||||
attack_verb = list("cleaved", "slashed", "torn", "hacked", "ripped", "diced", "carved")
|
||||
icon_state = "cultbastard"
|
||||
@@ -254,7 +258,7 @@
|
||||
|
||||
/datum/action/innate/cult/spin2win/Activate()
|
||||
cooldown = world.time + sword.spin_cooldown
|
||||
holder.changeNext_move(50)
|
||||
holder.DelayNextAction(50)
|
||||
holder.apply_status_effect(/datum/status_effect/sword_spin)
|
||||
sword.spinning = TRUE
|
||||
sword.block_chance = 100
|
||||
@@ -704,7 +708,7 @@
|
||||
armour_penetration = 30
|
||||
block_chance = 30
|
||||
attack_verb = list("attacked", "impaled", "stabbed", "torn", "gored")
|
||||
sharpness = IS_SHARP
|
||||
sharpness = SHARP_EDGED
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
var/datum/action/innate/cult/spear/spear_act
|
||||
var/wielded = FALSE // track wielded status on item
|
||||
|
||||
@@ -44,15 +44,16 @@
|
||||
/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)
|
||||
M.DelayNextAction(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>")
|
||||
return TRUE
|
||||
else
|
||||
to_chat(M, "<span class='cult'>You cannot repair [src], as [p_theyre()] undamaged!</span>")
|
||||
else
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/cult/attackby(obj/I, mob/user, params)
|
||||
if(istype(I, /obj/item/melee/cultblade/dagger) && iscultist(user))
|
||||
|
||||
@@ -67,7 +67,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
|
||||
to_chat(user, "<span class='danger'>You disrupt the magic of [src] with [I].</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/rune/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/effect/rune/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
/mob/living/carbon/true_devil/resist_fire()
|
||||
//They're immune to fire.
|
||||
|
||||
/mob/living/carbon/true_devil/attack_hand(mob/living/carbon/human/M)
|
||||
/mob/living/carbon/true_devil/on_attack_hand(mob/living/carbon/human/M)
|
||||
. = ..()
|
||||
if(.)
|
||||
switch(M.a_intent)
|
||||
|
||||
@@ -291,16 +291,19 @@ the new instance inside the host to be updated to the template's stats.
|
||||
|
||||
/mob/camera/disease/ClickOn(var/atom/A, params)
|
||||
if(freemove && ishuman(A))
|
||||
var/mob/living/carbon/human/H = A
|
||||
if(alert(src, "Select [H.name] as your initial host?", "Select Host", "Yes", "No") != "Yes")
|
||||
return
|
||||
if(!freemove)
|
||||
return
|
||||
if(QDELETED(H) || !force_infect(H))
|
||||
to_chat(src, "<span class='warning'>[H ? H.name : "Host"] cannot be infected.</span>")
|
||||
confirm_initial_infection(A)
|
||||
else
|
||||
..()
|
||||
|
||||
/mob/camera/disease/proc/confirm_initial_infection(mob/living/carbon/human/H)
|
||||
set waitfor = FALSE
|
||||
if(alert(src, "Select [H.name] as your initial host?", "Select Host", "Yes", "No") != "Yes")
|
||||
return
|
||||
if(!freemove)
|
||||
return
|
||||
if(QDELETED(H) || !force_infect(H))
|
||||
to_chat(src, "<span class='warning'>[H ? H.name : "Host"] cannot be infected.</span>")
|
||||
|
||||
/mob/camera/disease/proc/adapt_cooldown()
|
||||
to_chat(src, "<span class='notice'>You have altered your genetic structure. You will be unable to adapt again for [DisplayTimeText(adaptation_cooldown)].</span>")
|
||||
next_adaptation_time = world.time + adaptation_cooldown
|
||||
|
||||
@@ -7,17 +7,13 @@
|
||||
density = TRUE
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
|
||||
ui_x = 350
|
||||
ui_y = 442
|
||||
|
||||
var/timer_set = 90
|
||||
var/default_timer_set = 90
|
||||
var/minimum_timer_set = 90
|
||||
var/maximum_timer_set = 3600
|
||||
ui_style = "nanotrasen"
|
||||
|
||||
var/numeric_input = ""
|
||||
var/ui_mode = NUKEUI_AWAIT_DISK
|
||||
|
||||
var/timing = FALSE
|
||||
var/exploding = FALSE
|
||||
var/exploded = FALSE
|
||||
@@ -34,7 +30,6 @@
|
||||
var/interior = ""
|
||||
var/proper_bomb = TRUE //Please
|
||||
var/obj/effect/countdown/nuclearbomb/countdown
|
||||
var/nuclear_cooldown //used to stop global spam.
|
||||
|
||||
/obj/machinery/nuclearbomb/Initialize()
|
||||
. = ..()
|
||||
@@ -77,15 +72,16 @@
|
||||
/obj/machinery/nuclearbomb/syndicate/get_cinematic_type(off_station)
|
||||
var/datum/game_mode/nuclear/NM = SSticker.mode
|
||||
switch(off_station)
|
||||
if(FALSE)
|
||||
if(0)
|
||||
if(istype(NM) && !NM.nuke_team.syndies_escaped())
|
||||
return CINEMATIC_ANNIHILATION
|
||||
else
|
||||
return CINEMATIC_NUKE_WIN
|
||||
if(NUKE_MISS_STATION)
|
||||
if(1)
|
||||
return CINEMATIC_NUKE_MISS
|
||||
else
|
||||
if(2)
|
||||
return CINEMATIC_NUKE_FAR
|
||||
return CINEMATIC_NUKE_FAR
|
||||
|
||||
/obj/machinery/nuclearbomb/proc/disk_check(obj/item/disk/nuclear/D)
|
||||
if(D.fake)
|
||||
@@ -194,7 +190,7 @@
|
||||
icon_state = "nuclearbomb_exploding"
|
||||
|
||||
/obj/machinery/nuclearbomb/update_overlays()
|
||||
. = ..()
|
||||
. += ..()
|
||||
update_icon_interior()
|
||||
update_icon_lights()
|
||||
|
||||
@@ -236,7 +232,7 @@
|
||||
explode()
|
||||
else
|
||||
var/volume = (get_time_left() <= 20 ? 30 : 5)
|
||||
playsound(loc, 'sound/items/timer.ogg', volume, 0)
|
||||
playsound(loc, 'sound/items/timer.ogg', volume, FALSE)
|
||||
|
||||
/obj/machinery/nuclearbomb/proc/update_ui_mode()
|
||||
if(exploded)
|
||||
@@ -261,17 +257,18 @@
|
||||
|
||||
ui_mode = NUKEUI_AWAIT_TIMER
|
||||
|
||||
|
||||
/obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key="main", datum/tgui/ui=null, force_open=0, datum/tgui/master_ui=null, datum/ui_state/state=GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/nuclearbomb/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "NuclearBomb", name, ui_x, ui_y, master_ui, state)
|
||||
ui = new(user, src, "NuclearBomb", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/nuclearbomb/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["disk_present"] = auth
|
||||
|
||||
var/hidden_code = (ui_mode == NUKEUI_AWAIT_CODE && numeric_input != "ERROR")
|
||||
|
||||
var/current_code = ""
|
||||
if(hidden_code)
|
||||
while(length(current_code) < length(numeric_input))
|
||||
@@ -388,14 +385,13 @@
|
||||
if("anchor")
|
||||
if(auth && yes_code)
|
||||
playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE)
|
||||
set_anchor(usr)
|
||||
set_anchor()
|
||||
else
|
||||
playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE)
|
||||
|
||||
|
||||
/obj/machinery/nuclearbomb/proc/set_anchor(mob/user)
|
||||
if((istype(get_area(src), /area/space) || isinspace()) && !anchored)
|
||||
to_chat(user, "<span class='warning'>This is not a suitable platform for anchoring [src]!</span>")
|
||||
/obj/machinery/nuclearbomb/proc/set_anchor()
|
||||
if(isinspace() && !anchored)
|
||||
to_chat(usr, "<span class='warning'>There is nothing to anchor to!</span>")
|
||||
else
|
||||
anchored = !anchored
|
||||
|
||||
@@ -416,9 +412,6 @@
|
||||
if(safety)
|
||||
to_chat(usr, "<span class='danger'>The safety is still on.</span>")
|
||||
return
|
||||
if(!timing && nuclear_cooldown > world.time)
|
||||
to_chat(usr, "<span class='danger'>[src]'s timer protocols are currently on cooldown, please stand by.</span>")
|
||||
return
|
||||
timing = !timing
|
||||
if(timing)
|
||||
previous_level = NUM2SECLEVEL(GLOB.security_level)
|
||||
@@ -427,12 +420,6 @@
|
||||
S.switch_mode_to(TRACK_INFILTRATOR)
|
||||
countdown.start()
|
||||
set_security_level("delta")
|
||||
nuclear_cooldown = world.time + 15 SECONDS
|
||||
|
||||
if(GLOB.war_declared)
|
||||
var/area/A = get_area(src)
|
||||
priority_announce("Alert: Unexpected increase in radiation levels near [A.name] ([src.x],[src.y],[src.z]). Please send an authorized radiation specialist to investigate.", "Sensory Nuclear Indexer Telemetry Calculation Helper")
|
||||
|
||||
else
|
||||
detonation_timer = null
|
||||
set_security_level(previous_level)
|
||||
@@ -483,12 +470,19 @@
|
||||
|
||||
var/off_station = FALSE
|
||||
var/turf/bomb_location = get_turf(src)
|
||||
if(!bomb_location || !is_station_level(bomb_location.z))
|
||||
off_station = NUKE_MISS_STATION
|
||||
var/area/A = get_area(bomb_location)
|
||||
|
||||
if(bomb_location && is_station_level(bomb_location.z))
|
||||
if(istype(A, /area/space))
|
||||
off_station = NUKE_NEAR_MISS
|
||||
if((bomb_location.x < (128-NUKERANGE)) || (bomb_location.x > (128+NUKERANGE)) || (bomb_location.y < (128-NUKERANGE)) || (bomb_location.y > (128+NUKERANGE)))
|
||||
off_station = NUKE_NEAR_MISS
|
||||
else if(bomb_location.onSyndieBase())
|
||||
off_station = NUKE_SYNDICATE_BASE
|
||||
else
|
||||
off_station = NUKE_MISS_STATION
|
||||
|
||||
if(!off_station)
|
||||
if(off_station < 2) //can only launch when nuke is on syndie base or space
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
SSshuttle.lockdown = TRUE
|
||||
|
||||
@@ -502,13 +496,13 @@
|
||||
INVOKE_ASYNC(GLOBAL_PROC,.proc/KillEveryoneOnZLevel, z)
|
||||
|
||||
/obj/machinery/nuclearbomb/proc/get_cinematic_type(off_station)
|
||||
if(!off_station)
|
||||
if(off_station < 2)
|
||||
return CINEMATIC_SELFDESTRUCT
|
||||
else
|
||||
return CINEMATIC_SELFDESTRUCT_MISS
|
||||
|
||||
/obj/machinery/nuclearbomb/beer
|
||||
name = "Nanotrasen-brand nuclear fission explosive"
|
||||
name = "\improper Nanotrasen-brand nuclear fission explosive"
|
||||
desc = "One of the more successful achievements of the Nanotrasen Corporate Warfare Division, their nuclear fission explosives are renowned for being cheap to produce and devastatingly effective. Signs explain that though this particular device has been decommissioned, every Nanotrasen station is equipped with an equivalent one, just in case. All Captains carefully guard the disk needed to detonate them - at least, the sign says they do. There seems to be a tap on the back."
|
||||
proper_bomb = FALSE
|
||||
var/obj/structure/reagent_dispensers/beerkeg/keg
|
||||
@@ -521,9 +515,9 @@
|
||||
/obj/machinery/nuclearbomb/beer/examine(mob/user)
|
||||
. = ..()
|
||||
if(keg.reagents.total_volume)
|
||||
. += "<span class='notice'>It has [keg.reagents.total_volume] unit\s left.</span>"
|
||||
to_chat(user, "<span class='notice'>It has [keg.reagents.total_volume] unit\s left.</span>")
|
||||
else
|
||||
. += "<span class='danger'>It's empty.</span>"
|
||||
to_chat(user, "<span class='danger'>It's empty.</span>")
|
||||
|
||||
/obj/machinery/nuclearbomb/beer/attackby(obj/item/W, mob/user, params)
|
||||
if(W.is_refillable())
|
||||
@@ -535,6 +529,8 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/nuclearbomb/beer/actually_explode()
|
||||
//Unblock roundend, we're not actually exploding.
|
||||
SSticker.roundend_check_paused = FALSE
|
||||
var/turf/bomb_location = get_turf(src)
|
||||
if(!bomb_location)
|
||||
disarm()
|
||||
@@ -583,7 +579,7 @@
|
||||
This is here to make the tiles around the station mininuke change when it's armed.
|
||||
*/
|
||||
|
||||
/obj/machinery/nuclearbomb/selfdestruct/set_anchor(mob/user)
|
||||
/obj/machinery/nuclearbomb/selfdestruct/set_anchor()
|
||||
return
|
||||
|
||||
/obj/machinery/nuclearbomb/selfdestruct/set_active()
|
||||
@@ -641,18 +637,19 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
if(newturf && lastlocation == newturf)
|
||||
if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.0001))
|
||||
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
|
||||
if(istype(loneop))
|
||||
if(istype(loneop) && loneop.occurrences < loneop.max_occurrences)
|
||||
loneop.weight += 1
|
||||
if(loneop.weight % 5 == 0)
|
||||
if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1) //players count now
|
||||
message_admins("[src] is stationary in [ADMIN_VERBOSEJMP(newturf)]. The weight of Lone Operative is now [loneop.weight].")
|
||||
log_game("[src] is stationary for too long in [loc_name(newturf)], and has increased the weight of the Lone Operative event to [loneop.weight].")
|
||||
|
||||
else
|
||||
lastlocation = newturf
|
||||
last_disk_move = world.time
|
||||
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
|
||||
if(istype(loneop) && prob(loneop.weight))
|
||||
if(istype(loneop) && loneop.occurrences < loneop.max_occurrences && prob(loneop.weight))
|
||||
loneop.weight = max(loneop.weight - 1, 0)
|
||||
if(loneop.weight % 5 == 0)
|
||||
if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1)
|
||||
message_admins("[src] is on the move (currently in [ADMIN_VERBOSEJMP(newturf)]). The weight of Lone Operative is now [loneop.weight].")
|
||||
log_game("[src] being on the move has reduced the weight of the Lone Operative event to [loneop.weight].")
|
||||
|
||||
@@ -661,9 +658,19 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
if(!fake)
|
||||
return
|
||||
|
||||
if(isobserver(user) || HAS_TRAIT(user, TRAIT_DISK_VERIFIER) || (user.mind && HAS_TRAIT(user.mind, TRAIT_DISK_VERIFIER)))
|
||||
if(isobserver(user) || HAS_TRAIT(user.mind, TRAIT_DISK_VERIFIER))
|
||||
. += "<span class='warning'>The serial numbers on [src] are incorrect.</span>"
|
||||
|
||||
/*
|
||||
* You can't accidentally eat the nuke disk, bro
|
||||
*/
|
||||
/*
|
||||
/obj/item/disk/nuclear/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
|
||||
M.visible_message("<span class='warning'>[M] looks like [M.p_theyve()] just bitten into something important.</span>", \
|
||||
"<span class='warning'>Wait, is this the nuke disk?</span>")
|
||||
|
||||
return discover_after
|
||||
*/
|
||||
/obj/item/disk/nuclear/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/claymore/highlander) && !fake)
|
||||
var/obj/item/claymore/highlander/H = I
|
||||
@@ -686,7 +693,7 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
|
||||
/obj/item/disk/nuclear/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is going delta! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
playsound(src, 'sound/machines/alarm.ogg', 50, -1, 1)
|
||||
playsound(src, 'sound/machines/alarm.ogg', 50, -1, TRUE)
|
||||
for(var/i in 1 to 100)
|
||||
addtimer(CALLBACK(user, /atom/proc/add_atom_colour, (i % 2)? "#00FF00" : "#FF0000", ADMIN_COLOUR_PRIORITY), i)
|
||||
addtimer(CALLBACK(src, .proc/manual_suicide, user), 101)
|
||||
@@ -694,7 +701,7 @@ This is here to make the tiles around the station mininuke change when it's arme
|
||||
|
||||
/obj/item/disk/nuclear/proc/manual_suicide(mob/living/user)
|
||||
user.remove_atom_colour(ADMIN_COLOUR_PRIORITY)
|
||||
user.visible_message("<span class='suicide'>[user] was destroyed by the nuclear blast!</span>")
|
||||
user.visible_message("<span class='suicide'>[user] is destroyed by the nuclear blast!</span>")
|
||||
user.adjustOxyLoss(200)
|
||||
user.death(0)
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
if(stasis)
|
||||
return
|
||||
if(revealed && essence <= 0)
|
||||
death()
|
||||
INVOKE_ASYNC(src, .proc/death)
|
||||
if(unreveal_time && world.time >= unreveal_time)
|
||||
unreveal_time = 0
|
||||
revealed = FALSE
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
//Harvest; activated ly clicking the target, will try to drain their essence.
|
||||
/mob/living/simple_animal/revenant/proc/Harvest(mob/living/carbon/human/target)
|
||||
set waitfor = FALSE
|
||||
if(!castcheck(0))
|
||||
return
|
||||
if(draining)
|
||||
|
||||
@@ -34,8 +34,11 @@
|
||||
healable = 0
|
||||
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
|
||||
obj_damage = 50
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 30
|
||||
melee_damage_lower = 22.5 // reduced from 30 to 22.5 with wounds since they get big buffs to slicing wounds
|
||||
melee_damage_upper = 22.5
|
||||
wound_bonus = -10
|
||||
bare_wound_bonus = 0
|
||||
sharpness = SHARP_EDGED
|
||||
see_in_dark = 8
|
||||
blood_volume = 0 //No bleeding on getting shot, for skeddadles
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
@@ -43,13 +46,25 @@
|
||||
var/playstyle_string = "<span class='big bold'>You are a slaughter demon,</span><B> a terrible creature from another realm. You have a single desire: To kill. \
|
||||
You may use the \"Blood Crawl\" ability near blood pools to travel through them, appearing and disappearing from the station at will. \
|
||||
Pulling a dead or unconscious mob while you enter a pool will pull them in with you, allowing you to feast and regain your health. \
|
||||
You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. </B>"
|
||||
You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. \
|
||||
You gain strength the more attacks you land on live humanoids, though this resets when you return to the blood zone. You can also \
|
||||
launch a devastating slam attack with ctrl+shift+click, capable of smashing bones in one strike.</B>"
|
||||
|
||||
loot = list(/obj/effect/decal/cleanable/blood, \
|
||||
/obj/effect/decal/cleanable/blood/innards, \
|
||||
/obj/item/organ/heart/demon)
|
||||
del_on_death = 1
|
||||
deathmessage = "screams in anger as it collapses into a puddle of viscera!"
|
||||
// How long it takes for the alt-click slam attack to come off cooldown
|
||||
var/slam_cooldown_time = 45 SECONDS
|
||||
// The actual instance var for the cooldown
|
||||
var/slam_cooldown = 0
|
||||
// How many times we have hit humanoid targets since we last bloodcrawled, scaling wounding power
|
||||
var/current_hitstreak = 0
|
||||
// How much both our wound_bonus and bare_wound_bonus go up per hitstreak hit
|
||||
var/wound_bonus_per_hit = 5
|
||||
// How much our wound_bonus hitstreak bonus caps at (peak demonry)
|
||||
var/wound_bonus_hitstreak_max = 12
|
||||
|
||||
/mob/living/simple_animal/slaughter/Initialize()
|
||||
..()
|
||||
@@ -58,6 +73,33 @@
|
||||
if(istype(loc, /obj/effect/dummy/phased_mob/slaughter))
|
||||
bloodspell.phased = TRUE
|
||||
|
||||
/mob/living/simple_animal/slaughter/CtrlShiftClickOn(atom/A)
|
||||
if(!isliving(A))
|
||||
return ..()
|
||||
if(slam_cooldown + slam_cooldown_time > world.time)
|
||||
to_chat(src, "<span class='warning'>Your slam ability is still on cooldown!</span>")
|
||||
return
|
||||
|
||||
face_atom(A)
|
||||
var/mob/living/victim = A
|
||||
victim.take_bodypart_damage(brute=20, wound_bonus=wound_bonus) // don't worry, there's more punishment when they hit something
|
||||
visible_message("<span class='danger'>[src] slams into [victim] with monstrous strength!</span>", "<span class='danger'>You slam into [victim] with monstrous strength!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[src] slams into you with monstrous strength, sending you flying like a ragdoll!</span>")
|
||||
var/turf/yeet_target = get_edge_target_turf(victim, dir)
|
||||
victim.throw_at(yeet_target, 10, 5, src)
|
||||
slam_cooldown = world.time
|
||||
log_combat(src, victim, "slaughter slammed")
|
||||
|
||||
/mob/living/simple_animal/slaughter/UnarmedAttack(atom/A, proximity)
|
||||
if(iscarbon(A))
|
||||
var/mob/living/carbon/target = A
|
||||
if(target.stat != DEAD && target.mind && current_hitstreak < wound_bonus_hitstreak_max)
|
||||
current_hitstreak++
|
||||
wound_bonus += wound_bonus_per_hit
|
||||
bare_wound_bonus += wound_bonus_per_hit
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/innards
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
name = "pile of viscera"
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
/datum/antagonist/slaughter/greet()
|
||||
. = ..()
|
||||
owner.announce_objectives()
|
||||
to_chat(owner, "<span class='warning'>You have a powerful alt-attack that slams people backwards that you can activate by shift+ctrl+clicking your target!</span>")
|
||||
|
||||
/datum/antagonist/slaughter/proc/forge_objectives()
|
||||
if(summoner)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
if(A)
|
||||
notify_ghosts("A swarmer shell has been created in [A.name].", 'sound/effects/bin_close.ogg', source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_dnr_observers = TRUE)
|
||||
|
||||
/obj/effect/mob_spawn/swarmer/attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
/obj/effect/mob_spawn/swarmer/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
@@ -158,10 +158,11 @@
|
||||
face_atom(A)
|
||||
if(!isturf(loc))
|
||||
return
|
||||
if(next_move > world.time)
|
||||
if(!CheckActionCooldown())
|
||||
return
|
||||
if(!A.Adjacent(src))
|
||||
return
|
||||
DelayNextAction()
|
||||
A.swarmer_act(src)
|
||||
|
||||
/atom/proc/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
@@ -497,7 +498,7 @@
|
||||
if(resource_gain)
|
||||
resources += resource_gain
|
||||
do_attack_animation(target)
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
DelayNextAction(CLICK_CD_MELEE)
|
||||
var/obj/effect/temp_visual/swarmer/integrate/I = new /obj/effect/temp_visual/swarmer/integrate(get_turf(target))
|
||||
I.pixel_x = target.pixel_x
|
||||
I.pixel_y = target.pixel_y
|
||||
@@ -517,10 +518,9 @@
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/DisIntegrate(atom/movable/target)
|
||||
new /obj/effect/temp_visual/swarmer/disintegration(get_turf(target))
|
||||
do_attack_animation(target)
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
DelayNextAction(CLICK_CD_MELEE)
|
||||
target.ex_act(EXPLODE_LIGHT)
|
||||
|
||||
|
||||
/mob/living/simple_animal/hostile/swarmer/proc/DisperseTarget(mob/living/target)
|
||||
if(target == src)
|
||||
return
|
||||
|
||||
@@ -167,10 +167,10 @@
|
||||
return
|
||||
if(last_man_standing)
|
||||
if(syndicate)
|
||||
to_chat(owner.current,"<span class='userdanger'> All the loyalist agents are dead, and no more is required of you. Die a glorious death, agent. </span>")
|
||||
to_chat(owner.current,"<span class='userdanger'>All the suspected agents are dead, and no more is required of you. Die a glorious death, agent.</span>")
|
||||
replace_escape_objective(owner)
|
||||
else
|
||||
to_chat(owner.current,"<span class='userdanger'> All the other agents are dead, and you're the last loose end. Stage a Syndicate terrorist attack to cover up for today's events. You no longer have any limits on collateral damage.</span>")
|
||||
replace_escape_objective(owner)
|
||||
to_chat(owner.current,"<span class='userdanger'>All the other agents are dead. You have done us all a great service and shall be honorably exiled upon returning to base.</span>")
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/proc/iaa_process()
|
||||
if(owner&&owner.current&&owner.current.stat!=DEAD)
|
||||
@@ -193,7 +193,7 @@
|
||||
if(syndicate)
|
||||
fail_msg += "<span class='userdanger'> You no longer have permission to die. </span>"
|
||||
else
|
||||
fail_msg += "<span class='userdanger'> The truth could still slip out!</font><B><font size=5 color=red> Cease any terrorist actions as soon as possible, unneeded property damage or loss of employee life will lead to your contract being terminated.</span>"
|
||||
fail_msg += "<span class='userdanger'> The truth could still slip out!</font><B><font size=5 color=red> Cease any terrorist actions as soon as possible, unneeded property damage or loss of employee life will lead to great shame.</span>"
|
||||
reinstate_escape_objective(owner)
|
||||
last_man_standing = FALSE
|
||||
to_chat(owner.current, fail_msg)
|
||||
@@ -226,18 +226,20 @@
|
||||
add_objective(escape_objective)
|
||||
|
||||
/datum/antagonist/traitor/internal_affairs/proc/greet_iaa()
|
||||
var/crime = pick("distribution of contraband" , "unauthorized erotic action on duty", "embezzlement", "piloting under the influence", "dereliction of duty", "syndicate collaboration", "mutiny", "multiple homicides", "corporate espionage", "receiving bribes", "malpractice", "worship of prohibited life forms", "possession of profane texts", "murder", "arson", "insulting their manager", "grand theft", "conspiracy", "attempting to unionize", "vandalism", "gross incompetence")
|
||||
var/crime = pick("distribution of contraband" , "embezzlement", "piloting under the influence", "dereliction of duty", "syndicate collaboration", "mutiny", "multiple homicides", "corporate espionage", "receiving bribes", "malpractice", "worship of prohibited life forms", "possession of profane texts", "murder", "arson", "insulting their manager", "grand theft", "conspiracy", "attempting to unionize", "vandalism", "gross incompetence")
|
||||
|
||||
to_chat(owner.current, "<span class='userdanger'>You are the [special_role].</span>")
|
||||
if(syndicate)
|
||||
to_chat(owner.current, "<span class='userdanger'>Your target has been framed for [crime], and you have been tasked with eliminating them to prevent them defending themselves in court.</span>")
|
||||
to_chat(owner.current, "<B><font size=5 color=red>Any damage you cause will be a further embarrassment to Nanotrasen, so you have no limits on collateral damage.</font></B>")
|
||||
to_chat(owner.current, "<span class='userdanger'> You have been provided with a standard uplink to accomplish your task. </span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>By no means reveal that you, or any other NT employees, are undercover agents.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>GREAT LEADER IS DEAD. NANOTRASEN MUST FALL.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>Your have infiltrated this vessel to cause chaos and assassinate targets known to have conspired against the Syndicate.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>Any damage you cause will be a further embarrassment to Nanotrasen, so you have no limits on collateral damage.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>You have been provided with a standard uplink to accomplish your task. </span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>By no means reveal that you are a Syndicate agent. By no means reveal that your targets are being hunted.</span>")
|
||||
else
|
||||
to_chat(owner.current, "<span class='userdanger'>Your target is suspected of [crime], and you have been tasked with eliminating them by any means necessary to avoid a costly and embarrassing public trial.</span>")
|
||||
to_chat(owner.current, "<B><font size=5 color=red>While you have a license to kill, unneeded property damage or loss of employee life will lead to your contract being terminated.</font></B>")
|
||||
to_chat(owner.current, "<span class='userdanger'>For the sake of plausible deniability, you have been equipped with an array of captured Syndicate weaponry available via uplink.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>CAUTION: Your legal status as a citizen of NanoTrasen will be permanently revoked upon completion of your first contract.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>Your target has been suspected of [crime], and must be removed from this plane.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>While you have a license to kill, you are to eliminate your targets with no collateral or unrelated deaths.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>For the sake of plausable deniability, you have been equipped with captured Syndicate equipment via uplink.</span>")
|
||||
to_chat(owner.current, "<span class='userdanger'>By no means reveal that you, or any other NT employees, are undercover agents.</span>")
|
||||
|
||||
to_chat(owner.current, "<span class='userdanger'>Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them.</span>")
|
||||
|
||||
@@ -259,7 +259,7 @@
|
||||
to_chat(target, "<span class='userdanger'>You suddenly feel very hot</span>")
|
||||
target.adjust_bodytemperature(50)
|
||||
GiveHint(target)
|
||||
else if(is_pointed(I))
|
||||
else if(I.get_sharpness() == SHARP_POINTY)
|
||||
to_chat(target, "<span class='userdanger'>You feel a stabbing pain in [parse_zone(user.zone_selected)]!</span>")
|
||||
target.DefaultCombatKnockdown(40)
|
||||
GiveHint(target)
|
||||
|
||||
@@ -294,6 +294,11 @@
|
||||
dat += "[surplus] left.<br>"
|
||||
return dat
|
||||
|
||||
/datum/spellbook_entry/item/timestop_katana
|
||||
name = "Temporal Katana"
|
||||
desc = "An oddly-weighted katana, reinforced to allow parrying, with a temporal anomaly magically shoved into it. Successful ripostes prove devastating to those unprepared."
|
||||
item_path = /obj/item/katana/timestop
|
||||
|
||||
/datum/spellbook_entry/item/staffchange
|
||||
name = "Staff of Change"
|
||||
desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself."
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
|
||||
/obj/item/onetankbomb/analyzer_act(mob/living/user, obj/item/I)
|
||||
bombtank.analyzer_act(user, I)
|
||||
return TRUE
|
||||
|
||||
/obj/item/onetankbomb/attack_self(mob/user) //pressing the bomb accesses its assembly
|
||||
bombassembly.attack_self(user, TRUE)
|
||||
@@ -90,7 +91,7 @@
|
||||
if(bombassembly)
|
||||
bombassembly.on_found(finder)
|
||||
|
||||
/obj/item/onetankbomb/attack_hand() //also for mousetraps
|
||||
/obj/item/onetankbomb/on_attack_hand() //also for mousetraps
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
if(a_right)
|
||||
a_right.dropped(user)
|
||||
|
||||
/obj/item/assembly_holder/attack_hand()//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess
|
||||
/obj/item/assembly_holder/on_attack_hand()//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
icon_state = "infrared"
|
||||
custom_materials = list(/datum/material/iron=1000, /datum/material/glass=500)
|
||||
is_position_sensitive = TRUE
|
||||
var/ui_x = 225
|
||||
var/ui_y = 110
|
||||
var/on = FALSE
|
||||
var/visible = FALSE
|
||||
var/maxlength = 8
|
||||
@@ -125,7 +123,7 @@
|
||||
return
|
||||
refreshBeam()
|
||||
|
||||
/obj/item/assembly/infra/attack_hand()
|
||||
/obj/item/assembly/infra/on_attack_hand()
|
||||
. = ..()
|
||||
refreshBeam()
|
||||
|
||||
@@ -134,7 +132,7 @@
|
||||
. = ..()
|
||||
setDir(t)
|
||||
|
||||
/obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE)
|
||||
/obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE, quickstart = TRUE)
|
||||
. = ..()
|
||||
olddir = dir
|
||||
|
||||
@@ -186,11 +184,10 @@
|
||||
return ..()
|
||||
return UI_CLOSE
|
||||
|
||||
/obj/item/assembly/infra/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/item/assembly/infra/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "InfraredEmitter", name, ui_x, ui_y, master_ui, state)
|
||||
ui = new(user, src, "InfraredEmitter", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/assembly/infra/ui_data(mob/user)
|
||||
|
||||
@@ -84,8 +84,7 @@
|
||||
playsound(src, 'sound/weapons/handcuffs.ogg', 30, TRUE, -3)
|
||||
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/assembly/mousetrap/attack_hand(mob/living/carbon/human/user)
|
||||
/obj/item/assembly/mousetrap/on_attack_hand(mob/living/carbon/human/user)
|
||||
if(armed)
|
||||
if((HAS_TRAIT(user, TRAIT_DUMB) || HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
|
||||
var/which_hand = BODY_ZONE_PRECISE_L_HAND
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
icon_state = "prox"
|
||||
custom_materials = list(/datum/material/iron=800, /datum/material/glass=200)
|
||||
attachable = TRUE
|
||||
var/ui_x = 250
|
||||
var/ui_y = 185
|
||||
var/scanning = FALSE
|
||||
var/timing = FALSE
|
||||
var/time = 10
|
||||
@@ -113,11 +111,10 @@
|
||||
return ..()
|
||||
return UI_CLOSE
|
||||
|
||||
/obj/item/assembly/prox_sensor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/item/assembly/prox_sensor/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "ProximitySensor", name, ui_x, ui_y, master_ui, state)
|
||||
ui = new(user, src, "ProximitySensor", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/assembly/prox_sensor/ui_data(mob/user)
|
||||
|
||||
@@ -8,33 +8,46 @@
|
||||
custom_materials = list(/datum/material/iron=400, /datum/material/glass=120)
|
||||
wires = WIRE_RECEIVE | WIRE_PULSE | WIRE_RADIO_PULSE | WIRE_RADIO_RECEIVE
|
||||
attachable = TRUE
|
||||
var/ui_x = 280
|
||||
var/ui_y = 132
|
||||
|
||||
var/code = DEFAULT_SIGNALER_CODE
|
||||
var/frequency = FREQ_SIGNALER
|
||||
var/datum/radio_frequency/radio_connection
|
||||
var/suicider = null
|
||||
///Holds the mind that commited suicide.
|
||||
var/datum/mind/suicider
|
||||
///Holds a reference string to the mob, decides how much of a gamer you are.
|
||||
var/suicide_mob
|
||||
var/hearing_range = 1
|
||||
|
||||
/obj/item/assembly/signaler/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] eats \the [src]! If it is signaled, [user.p_they()] will die!</span>")
|
||||
playsound(src, 'sound/items/eatfood.ogg', 50, TRUE)
|
||||
user.transferItemToLoc(src, user, TRUE)
|
||||
suicider = user
|
||||
moveToNullspace()
|
||||
suicider = user.mind
|
||||
suicide_mob = REF(user)
|
||||
return MANUAL_SUICIDE
|
||||
|
||||
/obj/item/assembly/signaler/proc/manual_suicide(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user]'s \the [src] receives a signal, killing [user.p_them()] instantly!</span>")
|
||||
/obj/item/assembly/signaler/proc/manual_suicide(datum/mind/suicidee)
|
||||
var/mob/living/user = suicidee.current
|
||||
if(!istype(user))
|
||||
return
|
||||
if(suicide_mob == REF(user))
|
||||
user.visible_message("<span class='suicide'>[user]'s [src] receives a signal, killing [user.p_them()] instantly!</span>")
|
||||
else
|
||||
user.visible_message("<span class='suicide'>[user]'s [src] receives a signal and [user.p_they()] die[user.p_s()] like a gamer!</span>")
|
||||
user.adjustOxyLoss(200)//it sends an electrical pulse to their heart, killing them. or something.
|
||||
user.death(0)
|
||||
//user.set_suicide(TRUE)
|
||||
user.suicide_log()
|
||||
playsound(user, 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/assembly/signaler/Initialize()
|
||||
. = ..()
|
||||
set_frequency(frequency)
|
||||
|
||||
|
||||
/obj/item/assembly/signaler/Destroy()
|
||||
SSradio.remove_object(src,frequency)
|
||||
suicider = null
|
||||
. = ..()
|
||||
|
||||
/obj/item/assembly/signaler/activate()
|
||||
@@ -53,11 +66,10 @@
|
||||
return ..()
|
||||
return UI_CLOSE
|
||||
|
||||
/obj/item/assembly/signaler/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/item/assembly/signaler/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "Signaler", name, ui_x, ui_y, master_ui, state)
|
||||
ui = new(user, src, "Signaler", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/assembly/signaler/ui_data(mob/user)
|
||||
@@ -66,12 +78,12 @@
|
||||
data["code"] = code
|
||||
data["minFrequency"] = MIN_FREE_FREQ
|
||||
data["maxFrequency"] = MAX_FREE_FREQ
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/assembly/signaler/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("signal")
|
||||
INVOKE_ASYNC(src, .proc/signal)
|
||||
@@ -115,9 +127,6 @@
|
||||
if(usr)
|
||||
GLOB.lastsignalers.Add("[time] <B>:</B> [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) <B>:</B> [format_frequency(frequency)]/[code]")
|
||||
|
||||
|
||||
return
|
||||
|
||||
/obj/item/assembly/signaler/receive_signal(datum/signal/signal)
|
||||
. = FALSE
|
||||
if(!signal)
|
||||
@@ -128,6 +137,7 @@
|
||||
return
|
||||
if(suicider)
|
||||
manual_suicide(suicider)
|
||||
return
|
||||
pulse(TRUE)
|
||||
audible_message("[icon2html(src, hearers(src))] *beep* *beep* *beep*", null, hearing_range)
|
||||
for(var/CHM in get_hearers_in_view(hearing_range, src))
|
||||
@@ -136,7 +146,6 @@
|
||||
LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE)
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/assembly/signaler/proc/set_frequency(new_frequency)
|
||||
SSradio.remove_object(src, frequency)
|
||||
frequency = new_frequency
|
||||
@@ -165,69 +174,8 @@
|
||||
return
|
||||
return ..(signal)
|
||||
|
||||
// Embedded signaller used in anomalies.
|
||||
/obj/item/assembly/signaler/anomaly
|
||||
name = "anomaly core"
|
||||
desc = "The neutralized core of an anomaly. It'd probably be valuable for research."
|
||||
icon_state = "anomaly core"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/anomaly_type = /obj/effect/anomaly
|
||||
|
||||
/obj/item/assembly/signaler/anomaly/receive_signal(datum/signal/signal)
|
||||
if(!signal)
|
||||
return FALSE
|
||||
if(signal.data["code"] != code)
|
||||
return FALSE
|
||||
if(suicider)
|
||||
manual_suicide(suicider)
|
||||
for(var/obj/effect/anomaly/A in get_turf(src))
|
||||
A.anomalyNeutralize()
|
||||
return TRUE
|
||||
|
||||
/obj/item/assembly/signaler/anomaly/manual_suicide(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user]'s [src] is reacting to the radio signal, warping [user.p_their()] body!</span>")
|
||||
user.suiciding = TRUE
|
||||
user.suicide_log()
|
||||
user.gib()
|
||||
|
||||
/obj/item/assembly/signaler/anomaly/attackby(obj/item/I, mob/user, params)
|
||||
if(I.tool_behaviour == TOOL_ANALYZER)
|
||||
to_chat(user, "<span class='notice'>Analyzing... [src]'s stabilized field is fluctuating along frequency [format_frequency(frequency)], code [code].</span>")
|
||||
..()
|
||||
|
||||
//Anomaly cores
|
||||
/obj/item/assembly/signaler/anomaly/pyro
|
||||
name = "\improper pyroclastic anomaly core"
|
||||
desc = "The neutralized core of a pyroclastic anomaly. It feels warm to the touch. It'd probably be valuable for research."
|
||||
icon_state = "pyro core"
|
||||
anomaly_type = /obj/effect/anomaly/pyro
|
||||
|
||||
/obj/item/assembly/signaler/anomaly/grav
|
||||
name = "\improper gravitational anomaly core"
|
||||
desc = "The neutralized core of a gravitational anomaly. It feels much heavier than it looks. It'd probably be valuable for research."
|
||||
icon_state = "grav core"
|
||||
anomaly_type = /obj/effect/anomaly/grav
|
||||
|
||||
/obj/item/assembly/signaler/anomaly/flux
|
||||
name = "\improper flux anomaly core"
|
||||
desc = "The neutralized core of a flux anomaly. Touching it makes your skin tingle. It'd probably be valuable for research."
|
||||
icon_state = "flux core"
|
||||
anomaly_type = /obj/effect/anomaly/flux
|
||||
|
||||
/obj/item/assembly/signaler/anomaly/bluespace
|
||||
name = "\improper bluespace anomaly core"
|
||||
desc = "The neutralized core of a bluespace anomaly. It keeps phasing in and out of view. It'd probably be valuable for research."
|
||||
icon_state = "anomaly core"
|
||||
anomaly_type = /obj/effect/anomaly/bluespace
|
||||
|
||||
/obj/item/assembly/signaler/anomaly/vortex
|
||||
name = "\improper vortex anomaly core"
|
||||
desc = "The neutralized core of a vortex anomaly. It won't sit still, as if some invisible force is acting on it. It'd probably be valuable for research."
|
||||
icon_state = "vortex core"
|
||||
anomaly_type = /obj/effect/anomaly/bhole
|
||||
/obj/item/assembly/signaler/anomaly/attack_self()
|
||||
return
|
||||
|
||||
/obj/item/assembly/signaler/cyborg
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
icon_state = "timer"
|
||||
custom_materials = list(/datum/material/iron=500, /datum/material/glass=50)
|
||||
attachable = TRUE
|
||||
var/ui_x = 275
|
||||
var/ui_y = 115
|
||||
|
||||
var/timing = FALSE
|
||||
var/time = 5
|
||||
var/saved_time = 5
|
||||
@@ -88,11 +87,10 @@
|
||||
return ..()
|
||||
return UI_CLOSE
|
||||
|
||||
/obj/item/assembly/timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/item/assembly/timer/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "Timer", name, ui_x, ui_y, master_ui, state)
|
||||
ui = new(user, src, "Timer", name)
|
||||
ui.open()
|
||||
|
||||
/obj/item/assembly/timer/ui_data(mob/user)
|
||||
|
||||
@@ -94,6 +94,13 @@ Note: If your code uses output() with assets you will need to call asset_flush o
|
||||
var/list/stacktrace = gib_stack_trace()
|
||||
log_asset("WARNING: dupe asset added to the asset cache: [asset_name] existing asset md5: [OACI.md5] new asset md5:[ACI.md5]\n[stacktrace.Join("\n")]")
|
||||
SSassets.cache[asset_name] = ACI
|
||||
return ACI
|
||||
|
||||
/// Returns the url of the asset, currently this is just its name, here to allow further work cdn'ing assets.
|
||||
/// Can be given an asset as well, this is just a work around for buggy edge cases where two assets may have the same name, doesn't matter now, but it will when the cdn comes.
|
||||
/proc/get_asset_url(asset_name, asset = null)
|
||||
var/datum/asset_cache_item/ACI = SSassets.cache[asset_name]
|
||||
return ACI?.url
|
||||
|
||||
//Generated names do not include file extention.
|
||||
//Used mainly for code that deals with assets in a generic way
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
**/
|
||||
/datum/asset_cache_item
|
||||
var/name
|
||||
var/url
|
||||
var/md5
|
||||
var/resource
|
||||
|
||||
@@ -18,4 +19,5 @@
|
||||
CRASH("invalid asset sent to asset cache")
|
||||
debug_world_log("asset cache unexpected success of second fcopy_rsc")
|
||||
src.name = name
|
||||
url = name
|
||||
resource = file
|
||||
|
||||
@@ -16,6 +16,9 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
GLOB.asset_datums[type] = src
|
||||
register()
|
||||
|
||||
/datum/asset/proc/get_url_mappings()
|
||||
return list()
|
||||
|
||||
/datum/asset/proc/register()
|
||||
return
|
||||
|
||||
@@ -30,11 +33,19 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
/datum/asset/simple/register()
|
||||
for(var/asset_name in assets)
|
||||
register_asset(asset_name, assets[asset_name])
|
||||
assets[asset_name] = register_asset(asset_name, assets[asset_name])
|
||||
|
||||
/datum/asset/simple/send(client)
|
||||
. = send_asset_list(client, assets)
|
||||
|
||||
/datum/asset/simple/get_url_mappings()
|
||||
. = list()
|
||||
for (var/asset_name in assets)
|
||||
var/datum/asset_cache_item/ACI = assets[asset_name]
|
||||
if (!ACI)
|
||||
continue
|
||||
.[asset_name] = ACI.url
|
||||
|
||||
|
||||
// For registering or sending multiple others at once
|
||||
/datum/asset/group
|
||||
@@ -50,6 +61,11 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
var/datum/asset/A = get_asset_datum(type)
|
||||
. = A.send(C) || .
|
||||
|
||||
/datum/asset/group/get_url_mappings()
|
||||
. = list()
|
||||
for(var/type in children)
|
||||
var/datum/asset/A = get_asset_datum(type)
|
||||
. += A.get_url_mappings()
|
||||
|
||||
// spritesheet implementation - coalesces various icons into a single .png file
|
||||
// and uses CSS to select icons out of that file - saves on transferring some
|
||||
@@ -70,7 +86,9 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
if (!name)
|
||||
CRASH("spritesheet [type] cannot register without a name")
|
||||
ensure_stripped()
|
||||
|
||||
for(var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
|
||||
var/res_name = "spritesheet_[name].css"
|
||||
var/fname = "data/spritesheets/[res_name]"
|
||||
fdel(fname)
|
||||
@@ -78,10 +96,6 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
register_asset(res_name, fcopy_rsc(fname))
|
||||
fdel(fname)
|
||||
|
||||
for(var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
register_asset("[name]_[size_id].png", size[SPRSZ_STRIPPED])
|
||||
|
||||
/datum/asset/spritesheet/send(client/C)
|
||||
if (!name)
|
||||
return
|
||||
@@ -90,6 +104,15 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
all += "[name]_[size_id].png"
|
||||
. = send_asset_list(C, all)
|
||||
|
||||
/datum/asset/spritesheet/get_url_mappings()
|
||||
if (!name)
|
||||
return
|
||||
. = list("spritesheet_[name].css" = get_asset_url("spritesheet_[name].css"))
|
||||
for(var/size_id in sizes)
|
||||
.["[name]_[size_id].png"] = get_asset_url("[name]_[size_id].png")
|
||||
|
||||
|
||||
|
||||
/datum/asset/spritesheet/proc/ensure_stripped(sizes_to_strip = sizes)
|
||||
for(var/size_id in sizes_to_strip)
|
||||
var/size = sizes[size_id]
|
||||
@@ -111,7 +134,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
for (var/size_id in sizes)
|
||||
var/size = sizes[size_id]
|
||||
var/icon/tiny = size[SPRSZ_ICON]
|
||||
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[name]_[size_id].png') no-repeat;}"
|
||||
out += ".[name][size_id]{display:inline-block;width:[tiny.Width()]px;height:[tiny.Height()]px;background:url('[get_asset_url("[name]_[size_id].png")]') no-repeat;}"
|
||||
|
||||
for (var/sprite_id in sprites)
|
||||
var/sprite = sprites[sprite_id]
|
||||
@@ -162,7 +185,10 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
Insert("[prefix][prefix2][icon_state_name]", I, icon_state=icon_state_name, dir=direction)
|
||||
|
||||
/datum/asset/spritesheet/proc/css_tag()
|
||||
return {"<link rel="stylesheet" href="spritesheet_[name].css" />"}
|
||||
return {"<link rel="stylesheet" href="[css_filename()]" />"}
|
||||
|
||||
/datum/asset/spritesheet/proc/css_filename()
|
||||
return get_asset_url("spritesheet_[name].css")
|
||||
|
||||
/datum/asset/spritesheet/proc/icon_tag(sprite_name)
|
||||
var/sprite = sprites[sprite_name]
|
||||
|
||||
@@ -6,12 +6,6 @@
|
||||
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css',
|
||||
)
|
||||
|
||||
/datum/asset/group/tgui
|
||||
children = list(
|
||||
/datum/asset/simple/tgui,
|
||||
/datum/asset/simple/fontawesome
|
||||
)
|
||||
|
||||
/datum/asset/simple/headers
|
||||
assets = list(
|
||||
"alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
|
||||
@@ -78,6 +72,7 @@
|
||||
"refresh" = 'icons/pda_icons/pda_refresh.png',
|
||||
"scanner" = 'icons/pda_icons/pda_scanner.png',
|
||||
"signaler" = 'icons/pda_icons/pda_signaler.png',
|
||||
// "skills" = 'icons/pda_icons/pda_skills.png',
|
||||
"status" = 'icons/pda_icons/pda_status.png',
|
||||
"dronephone" = 'icons/pda_icons/pda_dronephone.png',
|
||||
"emoji" = 'icons/pda_icons/pda_emoji.png'
|
||||
@@ -97,6 +92,10 @@
|
||||
"stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
|
||||
"stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
|
||||
"stamp-law" = 'icons/stamp_icons/large_stamp-law.png'
|
||||
// "stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png'
|
||||
// "stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png',
|
||||
// "stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png',
|
||||
// "stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png'
|
||||
)
|
||||
|
||||
|
||||
@@ -147,7 +146,6 @@
|
||||
"jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
|
||||
)
|
||||
|
||||
|
||||
/datum/asset/simple/goonchat
|
||||
assets = list(
|
||||
"json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
|
||||
@@ -375,6 +373,19 @@
|
||||
"ghost.png" = 'html/ghost.png'
|
||||
)
|
||||
|
||||
/datum/asset/simple/vv
|
||||
assets = list(
|
||||
"ghost.png" = 'html/ghost.png'
|
||||
"view_variables.css" = 'html/admin/view_variables.css'
|
||||
)
|
||||
|
||||
/datum/asset/spritesheet/sheetmaterials
|
||||
name = "sheetmaterials"
|
||||
|
||||
/datum/asset/spritesheet/sheetmaterials/register()
|
||||
InsertAll("", 'icons/obj/stack_objects.dmi')
|
||||
|
||||
// Special case to handle Bluespace Crystals
|
||||
Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal")
|
||||
..()
|
||||
|
||||
|
||||
|
||||
@@ -198,24 +198,27 @@
|
||||
//////////////////////////SPACEWIND/////////////////////////////
|
||||
|
||||
/turf/open/proc/consider_pressure_difference(turf/T, difference)
|
||||
SSair.high_pressure_delta[src] = TRUE
|
||||
if(difference > pressure_difference)
|
||||
pressure_direction = get_dir(src, T)
|
||||
pressure_difference = difference
|
||||
SSair.high_pressure_delta[src] = TRUE
|
||||
|
||||
/turf/open/proc/high_pressure_movements()
|
||||
var/atom/movable/M
|
||||
var/multiplier = 1
|
||||
var/diff = pressure_difference
|
||||
if(locate(/obj/structure/rack) in src)
|
||||
multiplier *= 0.1
|
||||
diff *= 0.1
|
||||
else if(locate(/obj/structure/table) in src)
|
||||
multiplier *= 0.2
|
||||
for(var/thing in src)
|
||||
M = thing
|
||||
if (!M.anchored && !M.pulledby && M.last_high_pressure_movement_air_cycle < SSair.times_fired)
|
||||
M.experience_pressure_difference(pressure_difference * multiplier, pressure_direction, 0, pressure_specific_target)
|
||||
diff *= 0.2
|
||||
for(var/obj/M in src)
|
||||
if(!M.anchored && !M.pulledby && M.last_high_pressure_movement_air_cycle < SSair.times_fired)
|
||||
M.experience_pressure_difference(diff, pressure_direction, 0, pressure_specific_target)
|
||||
for(var/mob/M in src)
|
||||
if(!M.anchored && !M.pulledby && M.last_high_pressure_movement_air_cycle < SSair.times_fired)
|
||||
M.experience_pressure_difference(diff, pressure_direction, 0, pressure_specific_target)
|
||||
/*
|
||||
if(pressure_difference > 100)
|
||||
new /obj/effect/temp_visual/dir_setting/space_wind(src, pressure_direction, clamp(round(sqrt(pressure_difference) * 2), 10, 255))
|
||||
*/
|
||||
|
||||
/atom/movable/var/pressure_resistance = 10
|
||||
/atom/movable/var/last_high_pressure_movement_air_cycle = 0
|
||||
|
||||
@@ -43,6 +43,12 @@ GLOBAL_LIST_INIT(meta_gas_fusions, meta_gas_fusion_list())
|
||||
var/list/dummy = get_gases()
|
||||
for(var/gas in dummy)
|
||||
dummy[gas] = get_moles(gas)
|
||||
dummy["TEMP"] = return_temperature()
|
||||
dummy["PRESSURE"] = return_pressure()
|
||||
dummy["HEAT CAPACITY"] = heat_capacity()
|
||||
dummy["TOTAL MOLES"] = total_moles()
|
||||
dummy["VOLUME"] = return_volume()
|
||||
dummy["THERMAL ENERGY"] = thermal_energy()
|
||||
return debug_variable("gases (READ ONLY)", dummy, 0, src)
|
||||
|
||||
/datum/gas_mixture/vv_get_dropdown()
|
||||
|
||||
@@ -237,11 +237,10 @@
|
||||
return ..()
|
||||
return UI_CLOSE
|
||||
|
||||
/obj/machinery/airalarm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/airalarm/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "AirAlarm", name, 440, 650, master_ui, state)
|
||||
ui = new(user, src, "AirAlarm", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/airalarm/ui_data(mob/user)
|
||||
|
||||
@@ -26,9 +26,6 @@ Passive gate is similar to the regular pump except:
|
||||
construction_type = /obj/item/pipe/directional
|
||||
pipe_state = "passivegate"
|
||||
|
||||
ui_x = 335
|
||||
ui_y = 115
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/passive_gate/CtrlClick(mob/user)
|
||||
if(can_interact(user))
|
||||
on = !on
|
||||
@@ -102,11 +99,10 @@ Passive gate is similar to the regular pump except:
|
||||
))
|
||||
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/passive_gate/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/atmospherics/components/binary/passive_gate/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "AtmosPump", name, ui_x, ui_y, master_ui, state)
|
||||
ui = new(user, src, "AtmosPump", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/passive_gate/ui_data()
|
||||
|
||||
@@ -107,11 +107,10 @@
|
||||
))
|
||||
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/pump/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/atmospherics/components/binary/pump/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "AtmosPump", name, 335, 115, master_ui, state)
|
||||
ui = new(user, src, "AtmosPump", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/pump/ui_data()
|
||||
|
||||
@@ -60,15 +60,14 @@
|
||||
else if(!opened && our_pressure >= open_pressure)
|
||||
open()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/relief_valve/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/atmospherics/components/binary/relief_valve/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "atmos_relief", name, 335, 115, master_ui, state)
|
||||
ui = new(user, src, "AtmosRelief", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/relief_valve/ui_data()
|
||||
var/data = list()
|
||||
var/list/data = list()
|
||||
data["open_pressure"] = round(open_pressure)
|
||||
data["close_pressure"] = round(close_pressure)
|
||||
data["max_pressure"] = round(50*ONE_ATMOSPHERE)
|
||||
@@ -79,11 +78,11 @@
|
||||
return
|
||||
switch(action)
|
||||
if("open_pressure")
|
||||
var/pressure = params["open_pressure"]
|
||||
var/pressure = params["pressure"]
|
||||
if(pressure == "max")
|
||||
pressure = 50*ONE_ATMOSPHERE
|
||||
. = TRUE
|
||||
else if(pressure == "input")
|
||||
else if(pressure == "input") // The manual expirience.
|
||||
pressure = input("New output pressure ([close_pressure]-[50*ONE_ATMOSPHERE] kPa):", name, open_pressure) as num|null
|
||||
if(!isnull(pressure) && !..())
|
||||
. = TRUE
|
||||
@@ -94,7 +93,7 @@
|
||||
open_pressure = clamp(pressure, close_pressure, 50*ONE_ATMOSPHERE)
|
||||
investigate_log("open pressure was set to [open_pressure] kPa by [key_name(usr)]", INVESTIGATE_ATMOS)
|
||||
if("close_pressure")
|
||||
var/pressure = params["close_pressure"]
|
||||
var/pressure = params["pressure"]
|
||||
if(pressure == "max")
|
||||
pressure = open_pressure
|
||||
. = TRUE
|
||||
|
||||
@@ -92,11 +92,10 @@
|
||||
))
|
||||
radio_connection.post_signal(src, signal)
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/volume_pump/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/atmospherics/components/binary/volume_pump/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "AtmosPump", name, 310, 115, master_ui, state)
|
||||
ui = new(user, src, "AtmosPump", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/atmospherics/components/binary/volume_pump/ui_data()
|
||||
|
||||
@@ -170,3 +170,4 @@
|
||||
|
||||
/obj/machinery/atmospherics/components/analyzer_act(mob/living/user, obj/item/I)
|
||||
atmosanalyzer_scan(airs, user, src)
|
||||
return TRUE
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user