Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into DRAKEBORG
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, "ntnet_relay", "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 ..()
|
||||
|
||||
@@ -71,22 +71,22 @@
|
||||
/obj/machinery/vr_sleeper/update_icon_state()
|
||||
icon_state = "[initial(icon_state)][state_open ? "-open" : ""]"
|
||||
|
||||
/obj/machinery/vr_sleeper/open_machine()
|
||||
if(state_open)
|
||||
return
|
||||
if(occupant)
|
||||
SStgui.close_user_uis(occupant, src)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/vr_sleeper/MouseDrop_T(mob/target, mob/user)
|
||||
if(user.lying || !iscarbon(target) || !Adjacent(target) || !user.canUseTopic(src, BE_CLOSE, TRUE, NO_TK))
|
||||
return
|
||||
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_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, "vr_sleeper", "VR Sleeper", 475, 340, master_ui, state)
|
||||
ui = new(user, src, "VrSleeper", "VR Sleeper")
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/vr_sleeper/ui_act(action, params)
|
||||
@@ -130,11 +130,13 @@
|
||||
|
||||
/obj/machinery/vr_sleeper/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
var/is_living
|
||||
if(vr_mob && !QDELETED(vr_mob))
|
||||
is_living = isliving(vr_mob)
|
||||
data["can_delete_avatar"] = TRUE
|
||||
data["vr_avatar"] = list("name" = vr_mob.name)
|
||||
data["isliving"] = istype(vr_mob)
|
||||
if(data["isliving"])
|
||||
data["isliving"] = is_living
|
||||
if(is_living)
|
||||
var/status
|
||||
switch(vr_mob.stat)
|
||||
if(CONSCIOUS)
|
||||
@@ -146,6 +148,11 @@
|
||||
if(SOFT_CRIT)
|
||||
status = "Barely Conscious"
|
||||
data["vr_avatar"] += list("status" = status, "health" = vr_mob.health, "maxhealth" = vr_mob.maxHealth)
|
||||
else
|
||||
data["can_delete_avatar"] = FALSE
|
||||
data["vr_avatar"] = FALSE
|
||||
data["isliving"] = FALSE
|
||||
|
||||
data["toggle_open"] = state_open
|
||||
data["emagged"] = you_die_in_the_game_you_die_for_real
|
||||
data["isoccupant"] = (user == occupant)
|
||||
|
||||
@@ -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> \]"
|
||||
|
||||
@@ -62,7 +62,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
|
||||
/client/proc/cmd_admin_check_player_exp, /* shows players by playtime */
|
||||
/client/proc/toggle_combo_hud, // toggle display of the combination pizza antag and taco sci/med/eng hud
|
||||
/client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/
|
||||
/client/proc/open_shuttle_manipulator, /* Opens shuttle manipulator UI */
|
||||
/datum/admins/proc/open_shuttlepanel, /* Opens shuttle manipulator UI */
|
||||
/client/proc/respawn_character,
|
||||
/client/proc/secrets,
|
||||
/client/proc/toggle_hear_radio, /*allows admins to hide all radio output*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -666,8 +666,8 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
obj_count_finished = select_refs
|
||||
var/n = 0
|
||||
for(var/i in found)
|
||||
if(++n == 20000)
|
||||
text_list += "<br><font color='red'><b>TRUNCATED - 20000 OBJECT LIMIT HIT</b></font>"
|
||||
if(++n == 2500)
|
||||
text_list += "<br><font color='red'><b>TRUNCATED - 2500 OBJECT LIMIT HIT</b></font>"
|
||||
SDQL_print(i, text_list, print_nulls)
|
||||
select_refs[REF(i)] = TRUE
|
||||
SDQL2_TICK_CHECK
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
if(AH)
|
||||
message_admins("[key_name_admin(src)] has started replying to [key_name(C, 0, 0)]'s admin help.")
|
||||
var/msg = input(src,"Message:", "Private message to [key_name(C, 0, 0)]") as message|null
|
||||
var/msg = stripped_multiline_input(src,"Message:", "Private message to [key_name(C, 0, 0)]")
|
||||
if (!msg)
|
||||
message_admins("[key_name_admin(src)] has cancelled their reply to [key_name(C, 0, 0)]'s admin help.")
|
||||
return
|
||||
@@ -87,10 +87,10 @@
|
||||
|
||||
|
||||
if(irc)
|
||||
if(!ircreplyamount) //to prevent people from spamming irc
|
||||
if(!ircreplyamount) //to prevent people from spamming irc/discord
|
||||
return
|
||||
if(!msg)
|
||||
msg = input(src,"Message:", "Private message to Administrator") as text|null
|
||||
msg = stripped_multiline_input(src,"Message:", "Private message to Administrator")
|
||||
|
||||
if(!msg)
|
||||
return
|
||||
@@ -112,7 +112,7 @@
|
||||
|
||||
//get message text, limit it's length.and clean/escape html
|
||||
if(!msg)
|
||||
msg = input(src,"Message:", "Private message to [key_name(recipient, 0, 0)]") as message|null
|
||||
msg = stripped_multiline_input(src,"Message:", "Private message to [key_name(recipient, 0, 0)]")
|
||||
msg = trim(msg)
|
||||
if(!msg)
|
||||
return
|
||||
@@ -191,7 +191,7 @@
|
||||
spawn() //so we don't hold the caller proc up
|
||||
var/sender = src
|
||||
var/sendername = key
|
||||
var/reply = input(recipient, msg,"Admin PM from-[sendername]", "") as text|null //show message and await a reply
|
||||
var/reply = stripped_multiline_input(recipient, msg,"Admin PM from-[sendername]", "") //show message and await a reply
|
||||
if(recipient && reply)
|
||||
if(sender)
|
||||
recipient.cmd_admin_pm(sender,reply) //sender is still about, let's reply to them
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
/datum/borgpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "borgopanel", "Borg Panel", 700, 700, master_ui, state)
|
||||
ui = new(user, src, ui_key, "BorgPanel", "Borg Panel", 700, 700, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/datum/borgpanel/ui_data(mob/user)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -421,7 +421,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
new_character.real_name = record_found.fields["name"]
|
||||
new_character.gender = record_found.fields["gender"]
|
||||
new_character.age = record_found.fields["age"]
|
||||
new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], record_found.fields["name"], record_found.fields["blood_type"], new record_found.fields["species"], record_found.fields["features"])
|
||||
new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], null, record_found.fields["name"], record_found.fields["blood_type"], new record_found.fields["species"], record_found.fields["features"])
|
||||
else
|
||||
var/datum/preferences/A = new()
|
||||
A.copy_to(new_character)
|
||||
@@ -1058,13 +1058,6 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
var/datum/atom_hud/A = GLOB.huds[ANTAG_HUD_TRAITOR]
|
||||
return A.hudusers[mob]
|
||||
|
||||
/client/proc/open_shuttle_manipulator()
|
||||
set category = "Admin"
|
||||
set name = "Shuttle Manipulator"
|
||||
set desc = "Opens the shuttle manipulator UI."
|
||||
|
||||
for(var/obj/machinery/shuttle_manipulator/M in GLOB.machines)
|
||||
M.ui_interact(usr)
|
||||
|
||||
/client/proc/run_weather()
|
||||
set category = "Fun"
|
||||
@@ -1276,7 +1269,23 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
if(!check_rights(R_ADMIN) || !check_rights(R_FUN))
|
||||
return
|
||||
|
||||
var/list/punishment_list = list(ADMIN_PUNISHMENT_PIE, ADMIN_PUNISHMENT_CUSTOM_PIE, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_SUPPLYPOD_QUICK, ADMIN_PUNISHMENT_SUPPLYPOD, ADMIN_PUNISHMENT_MAZING, ADMIN_PUNISHMENT_ROD)
|
||||
var/list/punishment_list = list(ADMIN_PUNISHMENT_PIE,
|
||||
ADMIN_PUNISHMENT_CUSTOM_PIE,
|
||||
ADMIN_PUNISHMENT_FIREBALL,
|
||||
ADMIN_PUNISHMENT_LIGHTNING,
|
||||
ADMIN_PUNISHMENT_BRAINDAMAGE,
|
||||
ADMIN_PUNISHMENT_BSA,
|
||||
ADMIN_PUNISHMENT_GIB,
|
||||
ADMIN_PUNISHMENT_SUPPLYPOD_QUICK,
|
||||
ADMIN_PUNISHMENT_SUPPLYPOD,
|
||||
ADMIN_PUNISHMENT_MAZING,
|
||||
ADMIN_PUNISHMENT_ROD,
|
||||
ADMIN_PUNISHMENT_SHOES,
|
||||
ADMIN_PUNISHMENT_PICKLE,
|
||||
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
|
||||
|
||||
@@ -1341,7 +1350,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
if(ADMIN_PUNISHMENT_PIE)
|
||||
var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/creamy = new(get_turf(target))
|
||||
creamy.splat(target)
|
||||
if (ADMIN_PUNISHMENT_CUSTOM_PIE)
|
||||
if(ADMIN_PUNISHMENT_CUSTOM_PIE)
|
||||
var/obj/item/reagent_containers/food/snacks/pie/cream/nostun/A = new()
|
||||
if(!A.reagents)
|
||||
var/amount = input(usr, "Specify the reagent size of [A]", "Set Reagent Size", 50) as num|null
|
||||
@@ -1354,9 +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)
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/datum/admins/proc/open_shuttlepanel()
|
||||
set category = "Admin"
|
||||
set name = "Shuttle Manipulator"
|
||||
set desc = "Opens the shuttle manipulator UI."
|
||||
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
SSshuttle.ui_interact(usr)
|
||||
|
||||
|
||||
/obj/docking_port/mobile/proc/admin_fly_shuttle(mob/user)
|
||||
var/list/options = list()
|
||||
|
||||
for(var/port in SSshuttle.stationary)
|
||||
if (istype(port, /obj/docking_port/stationary/transit))
|
||||
continue // please don't do this
|
||||
var/obj/docking_port/stationary/S = port
|
||||
if (canDock(S) == SHUTTLE_CAN_DOCK)
|
||||
options[S.name || S.id] = S
|
||||
|
||||
options += "--------"
|
||||
options += "Infinite Transit"
|
||||
options += "Delete Shuttle"
|
||||
options += "Into The Sunset (delete & greentext 'escape')"
|
||||
|
||||
var/selection = input(user, "Select where to fly [name || id]:", "Fly Shuttle") as null|anything in options
|
||||
if(!selection)
|
||||
return
|
||||
|
||||
switch(selection)
|
||||
if("Infinite Transit")
|
||||
destination = null
|
||||
mode = SHUTTLE_IGNITING
|
||||
setTimer(ignitionTime)
|
||||
|
||||
if("Delete Shuttle")
|
||||
if(alert(user, "Really delete [name || id]?", "Delete Shuttle", "Cancel", "Really!") != "Really!")
|
||||
return
|
||||
jumpToNullSpace()
|
||||
|
||||
if("Into The Sunset (delete & greentext 'escape')")
|
||||
if(alert(user, "Really delete [name || id] and greentext escape objectives?", "Delete Shuttle", "Cancel", "Really!") != "Really!")
|
||||
return
|
||||
intoTheSunset()
|
||||
|
||||
else
|
||||
if(options[selection])
|
||||
request(options[selection])
|
||||
|
||||
/obj/docking_port/mobile/emergency/admin_fly_shuttle(mob/user)
|
||||
return // use the existing verbs for this
|
||||
|
||||
/obj/docking_port/mobile/arrivals/admin_fly_shuttle(mob/user)
|
||||
switch(alert(user, "Would you like to fly the arrivals shuttle once or change its destination?", "Fly Shuttle", "Fly", "Retarget", "Cancel"))
|
||||
if("Cancel")
|
||||
return
|
||||
if("Fly")
|
||||
return ..()
|
||||
|
||||
var/list/options = list()
|
||||
|
||||
for(var/port in SSshuttle.stationary)
|
||||
if (istype(port, /obj/docking_port/stationary/transit))
|
||||
continue // please don't do this
|
||||
var/obj/docking_port/stationary/S = port
|
||||
if (canDock(S) == SHUTTLE_CAN_DOCK)
|
||||
options[S.name || S.id] = S
|
||||
|
||||
var/selection = input(user, "Select the new arrivals destination:", "Fly Shuttle") as null|anything in options
|
||||
if(!selection)
|
||||
return
|
||||
target_dock = options[selection]
|
||||
if(!QDELETED(target_dock))
|
||||
destination = target_dock
|
||||
|
||||
@@ -23,6 +23,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/show_name_in_check_antagonists = FALSE //Will append antagonist name in admin listings - use for categories that share more than one antag type
|
||||
var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default.
|
||||
var/threat = 0 // Amount of threat this antag poses, for dynamic mode
|
||||
var/show_to_ghosts = FALSE // Should this antagonist be shown as antag to ghosts? Shouldn't be used for stealthy antagonists like traitors
|
||||
|
||||
var/list/skill_modifiers
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
job_rank = ROLE_ABDUCTOR
|
||||
show_in_antagpanel = FALSE //should only show subtypes
|
||||
threat = 5
|
||||
show_to_ghosts = TRUE
|
||||
var/datum/team/abductor_team/team
|
||||
var/sub_role
|
||||
var/outfit
|
||||
@@ -59,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/abductor/baton //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,121 @@
|
||||
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)
|
||||
/obj/machinery/abductor/console/Initialize(mapload)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
possible_gear = get_abductor_gear()
|
||||
|
||||
/**
|
||||
* get_abductor_gear: Returns a list of a filtered abductor gear sorted by categories
|
||||
*/
|
||||
/obj/machinery/abductor/console/proc/get_abductor_gear()
|
||||
var/list/filtered_modules = list()
|
||||
for(var/path in GLOB.abductor_gear)
|
||||
var/datum/abductor_gear/AG = new path
|
||||
if(!filtered_modules[AG.category])
|
||||
filtered_modules[AG.category] = list()
|
||||
filtered_modules[AG.category][AG] = AG
|
||||
return filtered_modules
|
||||
|
||||
/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 +178,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)
|
||||
/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)
|
||||
. = ..()
|
||||
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"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "Blob"
|
||||
roundend_category = "blobs"
|
||||
antagpanel_category = "Blob"
|
||||
show_to_ghosts = TRUE
|
||||
job_rank = ROLE_BLOB
|
||||
threat = 20
|
||||
var/datum/action/innate/blobpop/pop_action
|
||||
|
||||
@@ -45,11 +45,8 @@
|
||||
desc = "A solid wall of slightly twitching tendrils with a reflective glow."
|
||||
damaged_desc = "A wall of twitching tendrils with a reflective glow."
|
||||
icon_state = "blob_glow"
|
||||
flags_ricochet = RICOCHET_SHINY
|
||||
point_return = 8
|
||||
max_integrity = 100
|
||||
brute_resist = 1
|
||||
explosion_block = 2
|
||||
|
||||
/obj/structure/blob/shield/reflective/check_projectile_ricochet(obj/item/projectile/P)
|
||||
return PROJECTILE_RICOCHET_FORCE
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
if (bloodsuckerdatum && bloodsuckerdatum.coffin == src)
|
||||
bloodsuckerdatum.coffin = null
|
||||
bloodsuckerdatum.lair = null
|
||||
to_chat(resident, "<span class='danger'><span class='italics'>You sense that the link with your coffin, your sacred place of rest, has been brokem! You will need to seek another.</span></span>")
|
||||
to_chat(resident, "<span class='danger'><span class='italics'>You sense that the link with your coffin, your sacred place of rest, has been broken! You will need to seek another.</span></span>")
|
||||
resident = null // Remove resident. Because this object isnt removed from the game immediately (GC?) we need to give them a way to see they don't have a home anymore.
|
||||
|
||||
/obj/structure/closet/crate/coffin/can_open(mob/living/user)
|
||||
|
||||
@@ -217,7 +217,7 @@
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/structure/bloodsucker/vassalrack/attack_hand(mob/user)
|
||||
/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)
|
||||
/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, "cellular_emporium", 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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/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
|
||||
@@ -38,10 +38,11 @@
|
||||
set_slab.update_quickbind()
|
||||
|
||||
/proc/generate_all_scripture()
|
||||
if(!GLOB.all_scripture.len)
|
||||
for(var/V in sortList(subtypesof(/datum/clockwork_scripture), /proc/cmp_clockscripture_priority))
|
||||
var/datum/clockwork_scripture/S = new V
|
||||
GLOB.all_scripture[S.type] = S
|
||||
if(GLOB.all_scripture.len)
|
||||
return
|
||||
for(var/V in sortList(subtypesof(/datum/clockwork_scripture) - list(/datum/clockwork_scripture/channeled, /datum/clockwork_scripture/create_object, /datum/clockwork_scripture/create_object/construct), /proc/cmp_clockscripture_priority))
|
||||
var/datum/clockwork_scripture/S = new V
|
||||
GLOB.all_scripture[S.type] = S
|
||||
|
||||
//changes construction value
|
||||
/proc/change_construction_value(amount)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/obj/item/clockwork/slab //Clockwork slab: The most important tool in Ratvar's arsenal. Allows scripture recital, tutorials, and generates components.
|
||||
name = "clockwork slab"
|
||||
desc = "A strange metal tablet. A clock in the center turns around and around."
|
||||
clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant.<br>\
|
||||
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
|
||||
@@ -15,13 +15,13 @@
|
||||
var/busy //If the slab is currently being used by something
|
||||
var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks
|
||||
var/speed_multiplier = 1 //multiples how fast this slab recites scripture
|
||||
var/selected_scripture = SCRIPTURE_DRIVER
|
||||
// var/selected_scripture = SCRIPTURE_DRIVER //handled UI side
|
||||
var/obj/effect/proc_holder/slab/slab_ability //the slab's current bound ability, for certain scripture
|
||||
|
||||
var/recollecting = FALSE //if we're looking at fancy recollection
|
||||
var/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
|
||||
|
||||
@@ -36,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
|
||||
|
||||
@@ -54,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)
|
||||
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, \
|
||||
@@ -67,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)
|
||||
@@ -140,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]
|
||||
. += "<b>Quickbind</b> button: <span class='[get_component_span(initial(quickbind_slot.primary_component))]'>[initial(quickbind_slot.name)]</span>."
|
||||
. += "<b>Available power:</b> <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)
|
||||
@@ -165,18 +168,19 @@
|
||||
user.emote("scream")
|
||||
user.apply_damage(5, BURN, BODY_ZONE_L_ARM)
|
||||
user.apply_damage(5, BURN, BODY_ZONE_R_ARM)
|
||||
return 0
|
||||
return FALSE
|
||||
if(!is_servant_of_ratvar(user))
|
||||
to_chat(user, "<span class='warning'>The information on [src]'s display shifts rapidly. After a moment, your head begins to pound, and you tear your eyes away.</span>")
|
||||
user.confused += 5
|
||||
user.dizziness += 5
|
||||
return 0
|
||||
if(user.confused || user.dizziness)
|
||||
user.confused += 5
|
||||
user.dizziness += 5
|
||||
return FALSE
|
||||
if(busy)
|
||||
to_chat(user, "<span class='warning'>[src] refuses to work, displaying the message: \"[busy]!\"</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
if(!no_cost && !can_recite_scripture(user))
|
||||
to_chat(user, "<span class='nezbere'>[src] hums fitfully in your hands, but doesn't seem to do anything...</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
access_display(user)
|
||||
|
||||
/obj/item/clockwork/slab/AltClick(mob/living/user)
|
||||
@@ -192,14 +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, "clockwork_slab", name, 800, 420, master_ui, state)
|
||||
ui.set_autoupdate(FALSE) //we'll update this occasionally, but not as often as possible
|
||||
ui.set_style("clockwork")
|
||||
ui.open()
|
||||
|
||||
/obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user)
|
||||
if(!scripture || !user || !user.canUseTopic(src) || (!no_cost && !can_recite_scripture(user)))
|
||||
return FALSE
|
||||
@@ -207,294 +203,156 @@
|
||||
to_chat(user, "<span class='warning'>You need to hold the slab in your active hand to recite scripture!</span>")
|
||||
return FALSE
|
||||
var/initial_tier = initial(scripture.tier)
|
||||
if(initial_tier != SCRIPTURE_PERIPHERAL)
|
||||
if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier])
|
||||
to_chat(user, "<span class='warning'>That scripture is not unlocked, and cannot be recited!</span>")
|
||||
return FALSE
|
||||
if(initial_tier == SCRIPTURE_PERIPHERAL)
|
||||
to_chat(user, "<span class='warning'>Nice try using href exploits</span>")
|
||||
return
|
||||
if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier])
|
||||
to_chat(user, "<span class='warning'>That scripture is not unlocked, and cannot be recited!</span>")
|
||||
return FALSE
|
||||
var/datum/clockwork_scripture/scripture_to_recite = new scripture
|
||||
scripture_to_recite.slab = src
|
||||
scripture_to_recite.invoker = user
|
||||
scripture_to_recite.run_scripture()
|
||||
return TRUE
|
||||
|
||||
|
||||
//Guide to Serving Ratvar
|
||||
/obj/item/clockwork/slab/proc/recollection()
|
||||
var/list/textlist = list("If you're seeing this, file a bug report.")
|
||||
if(GLOB.ratvar_awakens)
|
||||
textlist = list("<font color=#BE8700 size=3><b>")
|
||||
for(var/i in 1 to 100)
|
||||
textlist += "HONOR RATVAR "
|
||||
textlist += "</b></font>"
|
||||
else
|
||||
textlist = list("<font color=#BE8700 size=3><b><center>[text2ratvar("Purge all untruths and honor Engine.")]</center></b></font><br>\
|
||||
\
|
||||
<b><i>NOTICE:</b> This information is out of date. Read the Ark & You primer in your backpack or read the wiki page for current info.</i><br>\
|
||||
<hr><br>\
|
||||
These pages serve as the archives of Ratvar, the Clockwork Justiciar. This section of your slab has information on being as a Servant, advice for what to do next, and \
|
||||
pointers for serving the master well. You should recommended that you check this area for help if you get stuck or need guidance on what to do next.<br><br>\
|
||||
\
|
||||
<i>Disclaimer: Many objects, terms, and phrases, such as Servant, Cache, and Slab, are capitalized like proper nouns. This is a quirk of the Ratvarian language; \
|
||||
do not let it confuse you! You are free to use the names in pronoun form when speaking in normal languages.<br>")
|
||||
return textlist.Join()
|
||||
|
||||
//Gets text for a certain section. "Default" is used for when you first open Recollection.
|
||||
//Current sections (make sure to update this if you add one:
|
||||
//- Basics
|
||||
//- Terminology
|
||||
//- Components
|
||||
//- Scripture
|
||||
//- Power
|
||||
//- Conversion
|
||||
/obj/item/clockwork/slab/proc/get_recollection_text(section)
|
||||
var/list/dat = list()
|
||||
switch(section)
|
||||
/*
|
||||
* 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")
|
||||
dat += "You can browse the above sections as you please. They're designed to be read in order, but feel free to pick and choose between them."
|
||||
if("Getting Started")
|
||||
dat += "<font color=#BE8700 size=3>Getting Started</font><br><br>"
|
||||
dat += "Welcome, Servant! This section houses the utmost basics of being a Servant of Ratvar, and is much more informal than the other sections. Being a Servant of \
|
||||
Ratvar is a very complex role, with many systems, objects, and resources to use effectively and creatively.<br><br>"
|
||||
dat += "This section of your clockwork slab covers everything that Servants have to be aware of, but is a long read because of how in-depth the systems are. Knowing \
|
||||
how to use the tools at your disposal makes all the difference between a clueless Servant and a great one.<br><br>"
|
||||
dat += "If this is your first time being a Servant, relax. It's very much possible that you'll fail, but it's impossible to learn without making mistakes. For the time \
|
||||
being, use the Hierophant Network button in the top left-hand corner of your screen to try and get in touch with your fellow Servants; ignore the others for now. This button \
|
||||
will let you send messages across space and time to all other Servants. This makes it great for coordinating, and you should use it often! <i>Note:</i> Using \
|
||||
this will cause you to whisper your message aloud, so doing so in a public place is very suspicious and you should try to restrict it to private use.<br><br>"
|
||||
dat += "If you aren't willing or don't have the time to read through every section, you can still help your teammates! Ask if they've set up a base. If they have, head there \
|
||||
and ask however you can help; chances are there's always something. If not, it's your job as a Servant to get one up and running! Try to find a secluded, low-traffic area, \
|
||||
like the auxiliary base or somewhere deep in maintenance. You'll want to go into the Drivers section of the slab and look for <i>Tinkerer's Cache.</i> Find a nice spot and \
|
||||
create one. This serves as a storage for <i>components,</i> the cult's primary resource. (Your slab's probably produced a few by now.) By attacking that cache with this \
|
||||
slab, you'll offload all your components into it, and all Servants will be able to use those components from any distance - all Tinkerer's Caches are linked!<br><br>"
|
||||
dat += "Once you have a base up and running, contact your fellows and let them know. You should come back here often to drop off the slab's components, and your fellows \
|
||||
should do the same, either in this cache or in ones of their own.<br><br>"
|
||||
dat += "If you think you're confident in taking further steps to help the cult, feel free to move onto the other sections. If not, let your allies know that you're new and \
|
||||
would appreciate the help they might offer you. Most experienced Servants would be happy to help; if everyone is inexperienced, then you'll have to step out of your comfort \
|
||||
zone and read onto the other sections. It's very likely that you might fail, but don't worry too much about it; you can't learn effectively without making mistakes.<br><br>"
|
||||
dat += "For now, welcome! If you're looking to learn, you should start with the <b>Basics</b> section, then move onto <b>Components</b> and <b>Scripture</b>. At the very \
|
||||
least, you should read the <b><i>Conversion</i></b> section, as it outlines the most important aspects of being a Servant. Good luck!<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
.["title"] = "Default"
|
||||
.["info"] = "Hello servant! Currently these categories dosen't work!"
|
||||
/*
|
||||
if("Basics")
|
||||
dat += "<font color=#BE8700 size=3>Servant Basics</font><br><br>"
|
||||
dat += "The first thing any Servant should know is their slab, inside and out. The clockwork slab is by far your most important tool. It allows you to speak with your \
|
||||
fellow Servants, create components that fuel many of your abilities, use those abilities, and should be kept safe and hidden on your person at all times. If you have not \
|
||||
done so already, it's a good idea to check for any fellow Servants using the Hierophant Network button in the top-left corner of your screen; due to the cult's nature, \
|
||||
teamwork is an instrumental component of your success.<br><br>" //get it? component? ha!
|
||||
dat += "As a Servant of Ratvar, the tools you are given focus around building and maintaining bases and outposts. A great deal of your power comes from stationary \
|
||||
structures, and without constructing a base somewhere, it's essentially impossible to succeed. Finding a good spot to build a base can be difficult, and it's recommended \
|
||||
that you choose an area in low-traffic part of the station (such as the auxiliary base). Make sure to disconnect any cameras in the area beforehand.<br><br>"
|
||||
dat += "Because of how complex being a Servant is, it isn't possible to fit much information into this section. It's highly recommended that you read the <b>Components</b> \
|
||||
and <b>Scripture</b> sections next. Not knowing how these two systems work will cripple both you and your fellows, and lead to a frustrating experience for everyone.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
.["title"] = "Basics"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
if("Terminology")
|
||||
dat += "<font color=#BE8700 size=3>Common Servant Terminology</font><br>"
|
||||
dat += "<i>This isn't intended to be read all at once; you are advised to treat it moreso as a glossary.</i><br><br>"
|
||||
dat += "<font color=#BE8700 size=3>General</font><br>"
|
||||
dat += "<font color=#BE8700><b>Servant:</b></font> A person or robot who serves Ratvar. You are one of these.<br>"
|
||||
dat += "<font color=#BE8700><b>Cache:</b></font> A <i>Tinkerer's Cache</i>, which is a structure that stores and creates components.<br>"
|
||||
dat += "<font color=#BE8700><b>CV:</b></font> Construction Value. All clockwork structures, floors, and walls increase this number.<br>"
|
||||
dat += "<font color=#BE8700><b>Vitality:</b></font> Used for healing effects, produced by Ratvarian spear attacks and Vitality Matrices.<br>"
|
||||
dat += "<font color=#BE8700><b>Geis:</b></font> An important scripture used to make normal crew and robots into Servants of Ratvar.<br>"
|
||||
dat += "<font color=#BE8700><b>Ark:</b></font> The cult's win condition, a huge structure that needs to be defended.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>Items</font><br>"
|
||||
dat += "<font color=#BE8700><b>Slab:</b></font> A clockwork slab, a Servant's most important tool. You're holding one! Keep it safe and hidden.<br>"
|
||||
dat += "<font color=#BE8700><b>Visor:</b></font> A judicial visor, which is a pair of glasses that can smite an area for a brief stun and delayed explosion.<br>"
|
||||
dat += "<font color=#BE8700><b>Wraith Specs:</b></font> Wraith spectacles, which provide true sight (X-ray, night vision) but damage the wearer's eyes.<br>"
|
||||
dat += "<font color=#BE8700><b>Spear:</b></font> A Ratvarian spear, which is a very powerful melee weapon that produces Vitality.<br>"
|
||||
dat += "<font color=#BE8700><b>Fabricator:</b></font> A replica fabricator, which converts objects into clockwork versions.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>Constructs</font><br>"
|
||||
dat += "<font color=#BE8700><b>Marauder:</b></font> A clockwork marauder, which is a powerful bodyguard that hides in its owner.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>Structures (* = requires power)</font><br>"
|
||||
dat += "<font color=#BE8700><b>Warden:</b></font> An ocular warden, which is a ranged turret that damages non-Servants that see it.<br>"
|
||||
dat += "<font color=#BE8700><b>Prism*:</b></font> A prolonging prism, which delays the shuttle for two minutes at a huge power cost.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Motor*:</b></font> A mania motor, which serves as area-denial through negative effects and eventual conversion.<br>"
|
||||
dat += "<font color=#BE8700><b>Daemon*:</b></font> A tinkerer's daemon, which quickly creates components.<br>"
|
||||
dat += "<font color=#BE8700><b>Obelisk*:</b></font> A clockwork obelisk, which can broadcast large messages and allows limited teleportation.<br>"
|
||||
dat += "<font color=#BE8700 size=3>Sigils</font><br>"
|
||||
dat += "<i>Note: Sigils can be stacked on top of one another, making certain sigils very effective when paired!</i><br>"
|
||||
dat += "<font color=#BE8700><b>Transgression:</b></font> Stuns the first non-Servant to cross it for ten seconds and blinds others nearby. Disappears on use.<br>"
|
||||
dat += "<font color=#BE8700><b>Submission:</b></font> Converts the first non-Servant to stand on the sigil for seven seconds. Disappears on use.<br>"
|
||||
dat += "<font color=#BE8700><b>Matrix:</b></font> Drains health from non-Servants, producing Vitality. Can heal and revive Servants.<br>"
|
||||
dat += "<font color=#BE8700><b>Accession:</b></font> Identical to the Sigil of Submission, but doesn't disappear on use. It can also convert a single mindshielded target, but will disappear after doing this.<br>"
|
||||
dat += "<font color=#BE8700><b>Transmission:</b></font> Drains and stores power for clockwork structures. Feeding it brass sheets will create additional power.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
.["title"] = "Terminology"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
if("Components")
|
||||
dat += "<font color=#BE8700 size=3>Components & Their Uses</font><br><br>"
|
||||
dat += "<b>Components</b> are your primary resource as a Servant. There are five types of component, with each one being used in different roles:<br><br>"
|
||||
dat += "Although this is a good rule of thumb, their effects become much more nuanced when used together. For instance, a turret might have both belligerent eyes and \
|
||||
vanguard cogwheels as construction requirements, because it defends its allies by harming its enemies.<br><br>"
|
||||
dat += "Components' primary use is fueling <b>scripture</b> (covered in its own section), and they can be created through various ways. This clockwork slab, for instance, \
|
||||
will make a random component of every type - or a specific one, if you choose a target component from the interface - every <b>remove me already</b>. This number will increase \
|
||||
as the amount of Servants in the covenant increase; additionally, slabs can only produce components when held by a Servant, and holding more than one slab will cause both \
|
||||
of them to halt progress until one of them is removed from their person.<br><br>"
|
||||
dat += "Your slab has an internal storage of components, but it isn't meant to be the main one. Instead, there's a <b>global storage</b> of components that can be \
|
||||
added to through various ways. Anything that needs components will first draw them from the global storage before attempting to draw them from the slab. Most methods of \
|
||||
component production add to the global storage. You can also offload components from your slab into the global storage by using it on a Tinkerer's Cache, a structure whose \
|
||||
primary purpose is to do just that (although it will also slowly produce components when placed near a brass wall.)<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
.["title"] = "Default"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
if("Scripture")
|
||||
dat += "<font color=#BE8700 size=3>The Ancient Scripture</font><br><br>"
|
||||
dat += "If you have experience with the Nar'Sian cult (or the \"blood cult\") then you will know of runes. They are the manifestations of the Geometer's power, and where most \
|
||||
of the cult's supernatural ability comes from. The Servant equivalent of runes is called <b>scripture</b>, and unlike runes, scripture is loaded into your clockwork slab.<br><br>"
|
||||
dat += "Each piece of scripture has widely-varying effects. Your most important scripture, <i>Geis</i>, is obvious and suspicious, but charges your slab with energy and allows \
|
||||
you to attack a non-Servant in melee range to restrain them and begin converting them into a Servant. This is just one example; each piece of scripture can be simple or \
|
||||
complex, be obvious or have hidden mechanics that can only be found through trial and error.<br><br>"
|
||||
dat += "Any given piece of scripture has a component cost listed in its \"Recite\" button. The acronyms for the components should be obvious if you've read about components \
|
||||
already; reciting this piece of scripture will consume the listed components, first from the global storage and then from your slab. Note that failing to recite a piece of \
|
||||
scripture will <i>not</i> consume the components required to recite it.<br><br>"
|
||||
dat += "It should also be noted that some scripture cannot be recited alone. Especially with more powerful scripture, you may need multiple Servants to recite a piece of \
|
||||
scripture; both of you will need to stand still until the recital completes. <i>Only human and silicon Servants are valid for scripture recital!</i> Constructs cannot help \
|
||||
in reciting scripture.<br><br>"
|
||||
dat += "Finally, scripture is separated into three \"tiers\" based on power: Drivers, Scripts, and Applications.[prob(1) ? " (The Revenant tier was removed a long time ago. \
|
||||
Get with the times.)" : ""] You can view the requirements to unlock each tier in its scripture list. Once a tier is unlocked, it's unlocked permanently; the cult only needs to fill the \
|
||||
requirement for unlocking a tier once!<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
.["title"] = "Default"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
if("Power")
|
||||
dat += "<font color=#BE8700 size=3>Power! Unlimited Power!</font><br><br>"
|
||||
dat += "In the early stages of the cult, the only resource that must be actively worried about is components. However, as new scripture is unlocked, a new resource \
|
||||
becomes necessary: <b>power</b>. Almost all clockwork structures require power to function in some way. There is nothing special about this power; it's mere electricity, \
|
||||
and can be harnessed in several ways.<br><br>"
|
||||
dat += "To begin with, if there is no other source of power nearby, structures will draw from the area's APC, assuming it has one. This is inefficient and ill-advised as \
|
||||
anything but a last resort. Instead, it is recommended that a <b>Sigil of Transmission</b> is created. This sigil serves as both battery and power generator for nearby clockwork \
|
||||
structures, and those structures will happily draw power from the sigil before they resort to APCs.<br><br>"
|
||||
dat += "Generating power is less easy. The most reliable and efficient way is using brass sheets; attacking a sigil of transmission with brass sheets will convert them \
|
||||
to power, at a rate of <b>[DisplayPower(POWER_FLOOR)]</b> per sheet. (Brass sheets are created from replica fabricators, which are explained more in detail in the <b>Conversion</b> section.) \
|
||||
Activating a sigil of transmission will also cause it to drain power from the nearby area, which, while effective, serves as an obvious tell that there is something wrong.<br><br>"
|
||||
dat += "Without power, many structures will not function, making a base vulnerable to attack. For this reason, it is critical that you keep an eye on your power reserves and \
|
||||
ensure that they remain comfortably high.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
.["title"] = "Power"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
if("Conversion")
|
||||
dat += "<font color=#BE8700 size=3>Growing the Ranks</font><br><br>"
|
||||
dat += "Because the Servants of Ratvar are a cult, the main method to gain more power is to \"enlighten\" normal crew into new Servants. When a crewmember is converted, \
|
||||
they become a full-fledged Servant, ready and willing to serve the cause of Ratvar. It should also be noted that <i>silicon crew, such as cyborgs and the AI, can be \
|
||||
converted just like normal crew</i> and will gain special abilities; this is covered later. This section will also cover converting the station's structure itself; walls, \
|
||||
floors, windows, tables, and other objects can all be converted into clockwork versions, and serve an important purpose.<br><br>"
|
||||
dat += "<font color=#BE8700><b>A Note on Geis:</b></font> There are several ways to convert humans and silicons. However, the most important tool to making them work is \
|
||||
<b>Geis</b>, a Driver-tier scripture. Using it whispers an invocation very quickly and charges your slab with power. In addition to <i>making the slab visible in your hand,</i> \
|
||||
you can now use it on a target within melee range to bind and mute them. It is by far your most reliable tool for capturing potential converts and targets, though it is incredibly \
|
||||
obvious. In addition, you are unable to take any actions other than moving while your target is bound. The binding will last for 25 seconds and mute for about 13 seconds, though \
|
||||
allies can use Geis to refresh these effects.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting:</b></font> The two methods of conversion are the <b>sigil of submission</b>, whose purpose is to do so, and the <b>mania motor.</b> \
|
||||
The sigil of submission is a sigil that, when stood on by a non-Servant for eight seconds, will convert that non-Servant. This is the only practical way to convert targets. \
|
||||
Sigils of submission are cheap, early, and permanent! Make sure sigils of submission are placed only in bases or otherwise hidden spots, or with a sigil of transgression on them. \
|
||||
The mania motor, however, is generally unreliable and unlocked later, only converting those who stand near it for an extended period.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting Humans:</b></font> For obvious reasons, humans are the most common conversion target. Because every crew member is different, and \
|
||||
may be armed with different equipment, you should take precautions to ensure that they aren't able to resist. If able, removing a headset is essential, as is restraining \
|
||||
them through handcuffs, cable ties, or other restraints. Some crew, like security, are also implanted with mindshield implants; these will prevent conversion and must be \
|
||||
surgically removed before they are an eligible convert. <i>Note:</i> The captain is <i>never</i> an eligible convert and should instead be killed or imprisoned. If security \
|
||||
begins administering mindshield implants, this will greatly inhibit conversion. Also note that mindshield implants can be broken by a sigil of accession automatically, but \
|
||||
the sigil will disappear.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting Silicons:</b></font> Due to their robotic nature, silicons are generally more predictable than humans in terms of conversion. \
|
||||
However, they are also much, much harder to subdue, especially cyborgs. The easiest way to convert a cyborg is by using Geis to restrain them, then dragging them to a sigil \
|
||||
of submission. If you stack a sigil of transgression and a sigil of submission, a crossing cyborg will be stunned and helpless to escape before they are converted.<br><br>"
|
||||
dat += "Converting AIs is very often the hardest task of the cult, and has been the downfall of countless successful Servants. Their omnipresence across the station, \
|
||||
coupled with their secure location and ability to lock themselves securely, makes them a powerful target. However, once the AI itself is reached, it is usually completely \
|
||||
helpless to resist its own conversion. A very common tactic is to take advantage of a converted cyborg to rush the AI before it is able to react.<br><br>"
|
||||
dat += "Even once an AI is converted, care must be taken to ensure that it remains hidden. Not only does the AI's core become brassy and thus obvious to an outside \
|
||||
observer, but <i>the AI loses the ability to speak in anything but Ratvarian.</i> For this reason, it has to remain completely silent over common radio channels if stealth \
|
||||
is at all a priority. This is suspicious and will rapidly lead to the crew checking on it, which usually results in the cult's outing. It is, however, necessary to convert \
|
||||
all AIs present on the station before the Ark becomes invokable, so this must be done at some point.<br><br>"
|
||||
dat += "<font color=#BE8700><b>Converting the Station:</b></font> Converted objects all serve a purpose and are important to the cult's success. To convert objects, \
|
||||
a Servant needs to use a <b>replica fabricator,</b> a handheld tool that uses power to replace objects with clockwork versions. Different clockwork objects have different \
|
||||
effects and are often crucial. The most noteworthy are <b>clockwork walls,</b> which automatically \"link\" to any nearby Tinkerer's Caches, causing them to <b>slowly \
|
||||
generate components.</b> This is incredibly useful for obvious reasons, and creating a clockwork wall near every Tinkerer's Cache should be prioritized. Clockwork floors \
|
||||
will slowly heal any toxin damage suffered by Servants standing on them, and clockwork airlocks can only be opened by Servants.<br><br>"
|
||||
dat += "The replica fabricator itself is also worth noting. In addition to replacing objects, it can also create brass sheets at the cost of power by using the \
|
||||
fabricator in-hand. It can also be used to repair any damaged clockwork structures.<br><br>"
|
||||
dat += "Replacing objects is almost as, if not as important as, converting new Servants. A base is impossible to manage without clockwork walls at the very least, and \
|
||||
once the cult has been outed and the crew are actively searching, there is little reason not to use as many as possible.<br><br>"
|
||||
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
|
||||
.["title"] = "Conversion"
|
||||
.["info"] = "# MARKDOWN WITH HTML?"
|
||||
*/
|
||||
else
|
||||
dat += "<font color=#BE8700 size=3>404: [section ? section : "Section"] Not Found!</font><br><br>\
|
||||
One of the cogscarabs must've misplaced this section, because the game wasn't able to find any info regarding it. Report this to the coders!"
|
||||
return "<br><br>[dat.Join()]<br><br>"
|
||||
|
||||
//Gets the quickbound scripture as a text block.
|
||||
/obj/item/clockwork/slab/proc/get_recollection_quickbinds()
|
||||
var/list/dat = list()
|
||||
dat += "<font color=#BE8700 size=3>Quickbound Scripture</font><br>\
|
||||
<i>You can have up to five scriptures bound to action buttons for easy use.</i><br><br>"
|
||||
if(LAZYLEN(quickbound))
|
||||
for(var/i in 1 to maximum_quickbound)
|
||||
if(LAZYLEN(quickbound) < i || !quickbound[i])
|
||||
dat += "A <b>Quickbind</b> slot, currently set to <b><font color=#BE8700>Nothing</font></b>.<br>"
|
||||
else
|
||||
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
|
||||
dat += "A <b>Quickbind</b> slot, currently set to <b><font color=[get_component_color_bright(initial(quickbind_slot.primary_component))]>[initial(quickbind_slot.name)]</font></b>.<br>"
|
||||
return dat.Join()
|
||||
return null //error text handled tgui side. should not cause BSOD
|
||||
|
||||
/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
|
||||
var/list/data = list()
|
||||
data["power"] = "<b><font color=#B18B25>[DisplayPower(get_clockwork_power())]</b> power is available for scripture and other consumers.</font>"
|
||||
|
||||
switch(selected_scripture) //display info based on selected scripture tier
|
||||
if(SCRIPTURE_DRIVER)
|
||||
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permanently unlocked.</b></font>"
|
||||
if(SCRIPTURE_SCRIPT)
|
||||
if(SSticker.scripture_states[SCRIPTURE_SCRIPT])
|
||||
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permanently unlocked.</b></font>"
|
||||
else
|
||||
data["tier_info"] = "<font color=#B18B25><i>These scriptures will automatically unlock when the Ark is halfway ready or if [DisplayPower(SCRIPT_UNLOCK_THRESHOLD)] of power is reached.</i></font>"
|
||||
if(SCRIPTURE_APPLICATION)
|
||||
if(SSticker.scripture_states[SCRIPTURE_APPLICATION])
|
||||
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permanently unlocked.</b></font>"
|
||||
else
|
||||
data["tier_info"] = "<font color=#B18B25><i>Unlock these optional scriptures by converting another servant or if [DisplayPower(APPLICATION_UNLOCK_THRESHOLD)] of power is reached..</i></font>"
|
||||
|
||||
data["selected"] = selected_scripture
|
||||
data["scripturecolors"] = "<font color=#DAAA18>Scriptures in <b>yellow</b> are related to construction and building.</font><br>\
|
||||
<font color=#6E001A>Scriptures in <b>red</b> are related to attacking and offense.</font><br>\
|
||||
<font color=#1E8CE1>Scriptures in <b>blue</b> are related to healing and defense.</font><br>\
|
||||
<font color=#AF0AAF>Scriptures in <b>purple</b> are niche but still important!</font><br>\
|
||||
<font color=#DAAA18><i>Scriptures with italicized names are important to success.</i></font>"
|
||||
generate_all_scripture()
|
||||
|
||||
data["scripture"] = list()
|
||||
for(var/s in GLOB.all_scripture)
|
||||
. = list()
|
||||
.["recollection"] = recollecting
|
||||
.["power"] = DisplayPower(get_clockwork_power())
|
||||
.["power_unformatted"] = get_clockwork_power()
|
||||
.["HONOR_RATVAR"] = GLOB.ratvar_awakens
|
||||
.["scripture"] = list()
|
||||
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 == selected_scripture) //display only scriptures of the selected tier
|
||||
var/scripture_color = get_component_color_bright(S.primary_component)
|
||||
var/list/temp_info = list("name" = "<font color=[scripture_color]><b>[S.name]</b></font>",
|
||||
"descname" = "<font color=[scripture_color]>([S.descname])</font>",
|
||||
"tip" = "[S.desc]\n[S.usage_tip]",
|
||||
"required" = "([DisplayPower(S.power_cost)][S.special_power_text ? "+ [replacetext(S.special_power_text, "POWERCOST", "[DisplayPower(S.special_power_cost)]")]" : ""])",
|
||||
"type" = "[S.type]",
|
||||
"quickbind" = S.quickbind)
|
||||
if(S.important)
|
||||
temp_info["name"] = "<i>[temp_info["name"]]</i>"
|
||||
var/found = quickbound.Find(S.type)
|
||||
if(found)
|
||||
temp_info["bound"] = "<b>[found]</b>"
|
||||
if(S.invokers_required > 1)
|
||||
temp_info["invokers"] = "<font color=#B18B25>Invokers: <b>[S.invokers_required]</b></font>"
|
||||
data["scripture"] += list(temp_info)
|
||||
data["recollection"] = recollecting
|
||||
if(recollecting)
|
||||
data["recollection_categories"] = GLOB.ratvar_awakens ? list() : list(\
|
||||
list("name" = "Getting Started", "desc" = "First-time servant? Read this first."), \
|
||||
list("name" = "Basics", "desc" = "A primer on how to play as a servant."), \
|
||||
list("name" = "Terminology", "desc" = "Common acronyms, words, and terms."), \
|
||||
list("name" = "Components", "desc" = "Information on components, your primary resource."), \
|
||||
list("name" = "Scripture", "desc" = "Information on scripture, ancient tools used by the cult."), \
|
||||
list("name" = "Power", "desc" = "The power system that certain objects use to function."), \
|
||||
list("name" = "Conversion", "desc" = "Converting the crew, cyborgs, and very walls to your cause."), \
|
||||
)
|
||||
data["rec_text"] = recollection()
|
||||
data["rec_section"] = GLOB.ratvar_awakens ? "" : get_recollection_text(recollection_category)
|
||||
data["rec_binds"] = GLOB.ratvar_awakens ? "" : get_recollection_quickbinds()
|
||||
return data
|
||||
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
|
||||
data["tip"] = "[S.desc]\n[S.usage_tip]"
|
||||
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 (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(LAZYLEN(quickbound) < i || !quickbound[i])
|
||||
.["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),
|
||||
"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() //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."
|
||||
)
|
||||
.["tier_infos"][SCRIPTURE_SCRIPT] = list(
|
||||
"requirement" = "These scriptures will automatically unlock when the Ark is halfway ready or if [DisplayPower(SCRIPT_UNLOCK_THRESHOLD)] of power is reached.",
|
||||
"ready" = SSticker.scripture_states[SCRIPTURE_SCRIPT] //huh, on the gamemode ticker? okay...
|
||||
)
|
||||
.["tier_infos"][SCRIPTURE_APPLICATION] = list(
|
||||
"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]
|
||||
)
|
||||
.["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."),
|
||||
list("name" = "Components", "desc" = "Information on components, your primary resource."),
|
||||
list("name" = "Scripture", "desc" = "Information on scripture, ancient tools used by the cult."),
|
||||
list("name" = "Power", "desc" = "The power system that certain objects use to function."),
|
||||
list("name" = "Conversion", "desc" = "Converting the crew, cyborgs, and very walls to your cause.")
|
||||
)
|
||||
.["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)
|
||||
if("toggle")
|
||||
recollecting = !recollecting
|
||||
if("recite")
|
||||
INVOKE_ASYNC(src, .proc/recite_scripture, text2path(params["category"]), usr, FALSE)
|
||||
if("select")
|
||||
selected_scripture = params["category"]
|
||||
INVOKE_ASYNC(src, .proc/recite_scripture, text2path(params["script"]), usr, FALSE)
|
||||
if("bind")
|
||||
var/datum/clockwork_scripture/path = text2path(params["category"]) //we need a path and not a string
|
||||
var/datum/clockwork_scripture/path = text2path(params["script"]) //we need a path and not a string
|
||||
if(!ispath(path, /datum/clockwork_scripture) || !initial(path.quickbind) || initial(path.tier) == SCRIPTURE_PERIPHERAL) //fuck you href bus
|
||||
to_chat(usr, "<span class='warning'>Nice try using href exploits</span>")
|
||||
return
|
||||
var/found_index = quickbound.Find(path)
|
||||
if(found_index) //hey, we already HAVE this bound
|
||||
if(LAZYLEN(quickbound) == found_index) //if it's the last scripture, remove it instead of leaving a null
|
||||
@@ -512,8 +370,8 @@
|
||||
quickbind_to_slot(path, target_index)
|
||||
if("rec_category")
|
||||
recollection_category = params["category"]
|
||||
ui_interact(usr)
|
||||
return 1
|
||||
update_static_data()
|
||||
return TRUE
|
||||
|
||||
/obj/item/clockwork/slab/proc/quickbind_to_slot(datum/clockwork_scripture/scripture, index) //takes a typepath(typecast for initial()) and binds it to a slot
|
||||
if(!ispath(scripture) || !scripture || (scripture in quickbound))
|
||||
|
||||
@@ -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)
|
||||
/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
|
||||
@@ -90,17 +89,17 @@
|
||||
creation_message = "<span class='alloy bold'>The cogscarab clicks and whirrs as it hops up and springs to life!</span>"
|
||||
construct_type = /mob/living/simple_animal/drone/cogscarab
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
var/infinite_resources = TRUE
|
||||
var/infinite_resources = FALSE //No.
|
||||
var/static/obj/item/seasonal_hat //Share it with all other scarabs, since we're from the same cult!
|
||||
|
||||
/obj/item/clockwork/construct_chassis/cogscarab/Initialize()
|
||||
. = ..()
|
||||
if(GLOB.servants_active)
|
||||
infinite_resources = FALSE //For any that are somehow spawned in late
|
||||
infinite_resources = FALSE //This check is relatively irrelevant until *someone* makes the infinite resources var default to true again, so, leaving it in.
|
||||
|
||||
/obj/item/clockwork/construct_chassis/cogscarab/pre_spawn()
|
||||
if(infinite_resources)
|
||||
//During rounds where they can't interact with the station, let them experiment with builds
|
||||
//During rounds where they can't interact with the station, let them experiment with builds, if an admin allows them to.
|
||||
construct_type = /mob/living/simple_animal/drone/cogscarab/ratvar
|
||||
if(!seasonal_hat)
|
||||
var/obj/item/drone_shell/D = locate() in GLOB.poi_list
|
||||
|
||||
@@ -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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/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)
|
||||
/obj/effect/rune/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
@@ -92,6 +92,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
|
||||
//Don't delete upon mind destruction, otherwise soul re-selling will break.
|
||||
delete_on_mind_deletion = FALSE
|
||||
threat = 5
|
||||
show_to_ghosts = TRUE
|
||||
var/obligation
|
||||
var/ban
|
||||
var/bane
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "Sentient Disease"
|
||||
roundend_category = "diseases"
|
||||
antagpanel_category = "Disease"
|
||||
show_to_ghosts = TRUE
|
||||
var/disease_name = ""
|
||||
|
||||
/datum/antagonist/disease/on_gain()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
var/list/name_source
|
||||
threat = -5
|
||||
show_in_antagpanel = FALSE
|
||||
show_to_ghosts = TRUE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
|
||||
/datum/antagonist/ert/on_gain()
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
roundend_category = "monkeys"
|
||||
antagpanel_category = "Monkey"
|
||||
threat = 3
|
||||
show_to_ghosts = TRUE
|
||||
var/datum/team/monkey/monkey_team
|
||||
var/monkey_only = TRUE
|
||||
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
threat = 5
|
||||
show_to_ghosts = TRUE
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
antagpanel_category = "Ninja"
|
||||
job_rank = ROLE_NINJA
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
threat = 8
|
||||
var/helping_station = FALSE
|
||||
|
||||
@@ -8,13 +8,12 @@
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
|
||||
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
|
||||
@@ -31,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()
|
||||
. = ..()
|
||||
@@ -74,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)
|
||||
@@ -191,7 +190,7 @@
|
||||
icon_state = "nuclearbomb_exploding"
|
||||
|
||||
/obj/machinery/nuclearbomb/update_overlays()
|
||||
. = ..()
|
||||
. += ..()
|
||||
update_icon_interior()
|
||||
update_icon_lights()
|
||||
|
||||
@@ -233,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)
|
||||
@@ -258,18 +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, "nuclear_bomb", name, 350, 442, master_ui, state)
|
||||
ui.set_style(ui_style)
|
||||
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))
|
||||
@@ -386,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
|
||||
|
||||
@@ -414,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)
|
||||
@@ -425,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)
|
||||
@@ -481,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
|
||||
|
||||
@@ -500,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
|
||||
@@ -519,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())
|
||||
@@ -533,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()
|
||||
@@ -581,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()
|
||||
@@ -639,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].")
|
||||
|
||||
@@ -659,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
|
||||
@@ -684,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)
|
||||
@@ -692,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)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
antag_moodlet = /datum/mood_event/focused
|
||||
threat = 10
|
||||
skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
|
||||
show_to_ghosts = TRUE
|
||||
var/datum/team/nuclear/nuke_team
|
||||
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
|
||||
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
show_in_antagpanel = FALSE
|
||||
var/datum/objective/mission
|
||||
var/datum/team/ert/ert_team
|
||||
show_to_ghosts = TRUE
|
||||
|
||||
/datum/antagonist/official/greet()
|
||||
to_chat(owner, "<B><font size=3 color=red>You are a CentCom Official.</font></B>")
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
roundend_category = "space pirates"
|
||||
antagpanel_category = "Pirate"
|
||||
threat = 5
|
||||
show_to_ghosts = TRUE
|
||||
var/datum/team/pirate/crew
|
||||
|
||||
/datum/antagonist/pirate/greet()
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
throwforce = 0
|
||||
blood_volume = 0
|
||||
has_field_of_vision = FALSE //we are a spoopy ghost
|
||||
rad_flags = RAD_NO_CONTAMINATE | RAD_PROTECT_CONTENTS
|
||||
|
||||
see_in_dark = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
@@ -112,7 +113,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)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
threat = 5
|
||||
show_to_ghosts = TRUE
|
||||
|
||||
/datum/antagonist/revenant/greet()
|
||||
owner.announce_objectives()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/datum/antagonist/santa
|
||||
name = "Santa"
|
||||
show_in_antagpanel = FALSE
|
||||
show_name_in_check_antagonists = TRUE
|
||||
show_to_ghosts = TRUE
|
||||
|
||||
/datum/antagonist/santa/on_gain()
|
||||
. = ..()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
threat = 10
|
||||
job_rank = ROLE_ALIEN
|
||||
show_in_antagpanel = FALSE
|
||||
show_to_ghosts = TRUE
|
||||
|
||||
/datum/antagonist/slaughter/on_gain()
|
||||
forge_objectives()
|
||||
@@ -14,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)
|
||||
|
||||
@@ -23,6 +23,18 @@
|
||||
/datum/antagonist/survivalist/guns
|
||||
greet_message = "Your own safety matters above all else, and the only way to ensure your safety is to stockpile weapons! Grab as many guns as possible, and don't let anyone take them!"
|
||||
|
||||
/datum/antagonist/survivalist/guns/forge_objectives()
|
||||
var/datum/objective/steal_five_of_type/summon_guns/guns = new
|
||||
guns.owner = owner
|
||||
objectives += guns
|
||||
..()
|
||||
|
||||
/datum/antagonist/survivalist/magic
|
||||
name = "Amateur Magician"
|
||||
greet_message = "This magic stuff is... so powerful. You want more. More! They want your power. They can't have it! Don't let them have it!"
|
||||
|
||||
/datum/antagonist/survivalist/magic/forge_objectives()
|
||||
var/datum/objective/steal_five_of_type/summon_magic/magic = new
|
||||
magic.owner = owner
|
||||
objectives += magic
|
||||
..()
|
||||
|
||||
@@ -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)
|
||||
/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)
|
||||
@@ -399,13 +400,13 @@
|
||||
return FALSE
|
||||
|
||||
/obj/structure/lattice/catwalk/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
|
||||
. = ..()
|
||||
var/turf/here = get_turf(src)
|
||||
for(var/A in here.contents)
|
||||
var/obj/structure/cable/C = A
|
||||
if(istype(C))
|
||||
to_chat(S, "<span class='warning'>Disrupting the power grid would bring no benefit to us. Aborting.</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/item/deactivated_swarmer/IntegrateAmount()
|
||||
return 50
|
||||
@@ -486,7 +487,7 @@
|
||||
var/obj/O = target
|
||||
if(O.resistance_flags & INDESTRUCTIBLE)
|
||||
return FALSE
|
||||
for(var/mob/living/L in GetAllContents())
|
||||
for(var/mob/living/L in target.GetAllContents())
|
||||
if(!ispAI(L) && !isbrain(L))
|
||||
to_chat(src, "<span class='warning'>An organism has been detected inside this object. Aborting.</span>")
|
||||
return FALSE
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user