Merge branch 'master' into punch-bundle

This commit is contained in:
kiwedespars
2020-04-19 16:50:01 -07:00
committed by GitHub
1014 changed files with 182479 additions and 42577 deletions
+1
View File
@@ -74,6 +74,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
/client/proc/addbunkerbypass,
/client/proc/revokebunkerbypass,
/client/proc/stop_sounds,
/client/proc/mark_datum_mapview,
/client/proc/hide_verbs, /*hides all our adminverbs*/
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
/datum/admins/proc/open_borgopanel
+208
View File
@@ -0,0 +1,208 @@
/client/proc/callproc()
set category = "Debug"
set name = "Advanced ProcCall"
set waitfor = FALSE
callproc_blocking()
/client/proc/callproc_blocking(list/get_retval)
if(!check_rights(R_DEBUG))
return
var/datum/target
var/targetselected = FALSE
var/returnval
switch(alert("Proc owned by something?",,"Yes","No"))
if("Yes")
targetselected = TRUE
var/list/value = vv_get_value(default_class = VV_ATOM_REFERENCE, classes = list(VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, VV_CLIENT, VV_MARKED_DATUM, VV_TEXT_LOCATE, VV_PROCCALL_RETVAL))
if (!value["class"] || !value["value"])
return
target = value["value"]
if(!istype(target))
to_chat(usr, "<span class='danger'>Invalid target.</span>")
return
if("No")
target = null
targetselected = FALSE
var/procpath = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null
if(!procpath)
return
//strip away everything but the proc name
var/list/proclist = splittext(procpath, "/")
if (!length(proclist))
return
var/procname = proclist[proclist.len]
var/proctype = ("verb" in proclist) ? "verb" :"proc"
if(targetselected)
if(!hascall(target, procname))
to_chat(usr, "<span class='warning'>Error: callproc(): type [target.type] has no [proctype] named [procpath].</span>")
return
else
procpath = "/[proctype]/[procname]"
if(!text2path(procpath))
to_chat(usr, "<span class='warning'>Error: callproc(): [procpath] does not exist.</span>")
return
var/list/lst = get_callproc_args()
if(!lst)
return
if(targetselected)
if(!target)
to_chat(usr, "<font color='red'>Error: callproc(): owner of proc no longer exists.</font>")
return
var/msg = "[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
log_admin(msg)
message_admins(msg) //Proccall announce removed.
admin_ticket_log(target, msg)
returnval = WrapAdminProcCall(target, procname, lst) // Pass the lst as an argument list to the proc
else
//this currently has no hascall protection. wasn't able to get it working.
log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed.
returnval = WrapAdminProcCall(GLOBAL_PROC, procname, lst) // Pass the lst as an argument list to the proc
SSblackbox.record_feedback("tally", "admin_verb", 1, "Advanced ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(get_retval)
get_retval += returnval
. = get_callproc_returnval(returnval, procname)
if(.)
to_chat(usr, .)
GLOBAL_VAR(AdminProcCaller)
GLOBAL_PROTECT(AdminProcCaller)
GLOBAL_VAR_INIT(AdminProcCallCount, 0)
GLOBAL_PROTECT(AdminProcCallCount)
GLOBAL_VAR(LastAdminCalledTargetRef)
GLOBAL_PROTECT(LastAdminCalledTargetRef)
GLOBAL_VAR(LastAdminCalledTarget)
GLOBAL_PROTECT(LastAdminCalledTarget)
GLOBAL_VAR(LastAdminCalledProc)
GLOBAL_PROTECT(LastAdminCalledProc)
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target != GLOBAL_PROC && procname == "Del")
to_chat(usr, "<span class='warning'>Calling Del() is not allowed</span>")
return
if(target != GLOBAL_PROC && !target.CanProcCall(procname))
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
return
var/current_caller = GLOB.AdminProcCaller
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
if(!ckey)
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
if(current_caller && current_caller != ckey)
if(!GLOB.AdminProcCallSpamPrevention[ckey])
to_chat(usr, "<span class='adminnotice'>Another set of admin called procs are still running, your proc will be run after theirs finish.</span>")
GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
UNTIL(!GLOB.AdminProcCaller)
to_chat(usr, "<span class='adminnotice'>Running your proc</span>")
GLOB.AdminProcCallSpamPrevention -= ckey
else
UNTIL(!GLOB.AdminProcCaller)
GLOB.LastAdminCalledProc = procname
if(target != GLOBAL_PROC)
GLOB.LastAdminCalledTargetRef = "[REF(target)]"
GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
++GLOB.AdminProcCallCount
. = world.WrapAdminProcCall(target, procname, arguments)
if(--GLOB.AdminProcCallCount == 0)
GLOB.AdminProcCaller = null
//adv proc call this, ya nerds
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target == GLOBAL_PROC)
return call(procname)(arglist(arguments))
else if(target != world)
return call(target, procname)(arglist(arguments))
else
log_admin_private("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
/proc/IsAdminAdvancedProcCall()
#ifdef TESTING
return FALSE
#else
return usr && usr.client && GLOB.AdminProcCaller == usr.client.ckey
#endif
/client/proc/callproc_datum(datum/A as null|area|mob|obj|turf)
set category = "Debug"
set name = "Atom ProcCall"
set waitfor = FALSE
if(!check_rights(R_DEBUG))
return
var/procname = input("Proc name, eg: fake_blood","Proc:", null) as text|null
if(!procname)
return
if(!hascall(A,procname))
to_chat(usr, "<span class='warning'>Error: callproc_datum(): type [A.type] has no proc named [procname].</span>")
return
var/list/lst = get_callproc_args()
if(!lst)
return
if(!A || !IsValidSrc(A))
to_chat(usr, "<span class='warning'>Error: callproc_datum(): owner of proc no longer exists.</span>")
return
var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
log_admin(msg)
message_admins(msg)
admin_ticket_log(A, msg)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Atom ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
. = get_callproc_returnval(returnval,procname)
if(.)
to_chat(usr, .)
/client/proc/get_callproc_args()
var/argnum = input("Number of arguments","Number:",0) as num|null
if(isnull(argnum))
return
. = list()
var/list/named_args = list()
while(argnum--)
var/named_arg = input("Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument") as text|null
var/value = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
if (!value["class"])
return
if(named_arg)
named_args[named_arg] = value["value"]
else
. += value["value"]
if(LAZYLEN(named_args))
. += named_args
/client/proc/get_callproc_returnval(returnval,procname)
. = ""
if(islist(returnval))
var/list/returnedlist = returnval
. = "<span class='notice'>"
if(returnedlist.len)
var/assoc_check = returnedlist[1]
if(istext(assoc_check) && (returnedlist[assoc_check] != null))
. += "[procname] returned an associative list:"
for(var/key in returnedlist)
. += "\n[key] = [returnedlist[key]]"
else
. += "[procname] returned a list:"
for(var/elem in returnedlist)
. += "\n[elem]"
else
. = "[procname] returned an empty list"
. += "</span>"
else
. = "<span class='notice'>[procname] returned: [!isnull(returnval) ? returnval : "null"]</span>"
+1
View File
@@ -18,6 +18,7 @@
H.undie_color = random_short_color()
H.undershirt = random_undershirt(H.gender)
H.shirt_color = random_short_color()
H.dna.skin_tone_override = null
H.skin_tone = random_skin_tone()
H.hair_style = random_hair_style(H.gender)
H.facial_hair_style = random_facial_hair_style(H.gender)
+3 -3
View File
@@ -61,7 +61,7 @@
<A href='?src=[REF(src)];[HrefToken()];secrets=events'>Summon Events (Toggle)</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=onlyone'>There can only be one!</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=delayed_onlyone'>There can only be one! (40-second delay)</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=retardify'>Make all players retarded</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=stupify'>Make all players stupid</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=eagles'>Egalitarian Station Mode</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=blackout'>Break all lights</A><BR>
<A href='?src=[REF(src)];[HrefToken()];secrets=whiteout'>Fix all lights</A><BR>
@@ -452,14 +452,14 @@
var/datum/round_event/disease_outbreak/DO = E
DO.virus_type = virus
if("retardify")
if("stupify")
if(!check_rights(R_FUN))
return
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Mass Braindamage"))
for(var/mob/living/carbon/human/H in GLOB.player_list)
to_chat(H, "<span class='boldannounce'>You suddenly feel stupid.</span>")
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 60, 80)
message_admins("[key_name_admin(usr)] made everybody retarded")
message_admins("[key_name_admin(usr)] made everybody stupid")
if("eagles")//SCRAW
if(!check_rights(R_FUN))
+2 -3
View File
@@ -1732,9 +1732,8 @@
var/mob/M = locate(href_list["makeeligible"])
if(!ismob(M))
to_chat(usr, "this can only be used on instances of type /mob.")
var/datum/element/ghost_role_eligibility/eli = SSdcs.GetElement(list(/datum/element/ghost_role_eligibility))
if(M.ckey in eli.timeouts)
eli.timeouts -= M.ckey
if(M.ckey in GLOB.client_ghost_timeouts)
GLOB.client_ghost_timeouts -= M.ckey
else if(href_list["sendtoprison"])
if(!check_rights(R_ADMIN))
+1 -1
View File
@@ -23,8 +23,8 @@
/datum/borgpanel/New(to_user, mob/living/silicon/robot/to_borg)
if(!istype(to_borg))
CRASH("Borg panel is only available for borgs")
qdel(src)
CRASH("Borg panel is only available for borgs")
user = CLIENT_FROM_VAR(to_user)
-268
View File
@@ -15,214 +15,6 @@
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Debug Two") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/* 21st Sept 2010
Updated by Skie -- Still not perfect but better!
Stuff you can't do:
Call proc /mob/proc/Dizzy() for some player
Because if you select a player mob as owner it tries to do the proc for
/mob/living/carbon/human/ instead. And that gives a run-time error.
But you can call procs that are of type /mob/living/carbon/human/proc/ for that player.
*/
/client/proc/callproc()
set category = "Debug"
set name = "Advanced ProcCall"
set waitfor = FALSE
if(!check_rights(R_DEBUG))
return
var/datum/target = null
var/targetselected = FALSE
var/returnval = null
if(alert("Proc owned by something?",,"Yes","No") == "Yes")
targetselected = TRUE
var/list/value = vv_get_value(default_class = VV_ATOM_REFERENCE, classes = list(VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, VV_CLIENT))
if (!value["class"] || !value["value"])
return
target = value["value"]
var/procpath = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null
if(!procpath)
return
//strip away everything but the proc name
var/list/proclist = splittext(procpath, "/")
if (!length(proclist))
return
var/procname = proclist[proclist.len]
var/proctype = ("verb" in proclist) ? "verb" :"proc"
if(targetselected)
if(!hascall(target, procname))
to_chat(usr, "<span class='warning'>Error: callproc(): type [target.type] has no [proctype] named [procpath].</span>")
return
else
procpath = "/[proctype]/[procname]"
if(!text2path(procpath))
to_chat(usr, "<span class='warning'>Error: callproc(): [procpath] does not exist.</span>")
return
var/list/lst = get_callproc_args()
if(!lst)
return
if(targetselected)
if(!target)
to_chat(usr, "<span class='warning'>Error: callproc(): owner of proc no longer exists.</span>")
return
var/msg = "[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no argument"]."
log_admin(msg)
message_admins(msg)
admin_ticket_log(target, msg)
returnval = WrapAdminProcCall(target, procname, lst)
else
var/msg = "[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no argument"]."
log_admin(msg)
message_admins(msg)
returnval = WrapAdminProcCall(GLOBAL_PROC, procpath, lst) //calling globals needs full qualified name (e.g /proc/foo)
. = get_callproc_returnval(returnval, procname)
if(.)
to_chat(usr, .)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Advanced ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
GLOBAL_VAR(AdminProcCaller)
GLOBAL_PROTECT(AdminProcCaller)
GLOBAL_VAR_INIT(AdminProcCallCount, 0)
GLOBAL_PROTECT(AdminProcCallCount)
GLOBAL_VAR(LastAdminCalledTargetRef)
GLOBAL_PROTECT(LastAdminCalledTargetRef)
GLOBAL_VAR(LastAdminCalledTarget)
GLOBAL_PROTECT(LastAdminCalledTarget)
GLOBAL_VAR(LastAdminCalledProc)
GLOBAL_PROTECT(LastAdminCalledProc)
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target != GLOBAL_PROC && procname == "Del")
to_chat(usr, "<span class='warning'>Calling Del() is not allowed</span>")
return
if(target != GLOBAL_PROC && !target.CanProcCall(procname))
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
return
var/current_caller = GLOB.AdminProcCaller
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
if(!ckey)
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
if(current_caller && current_caller != ckey)
if(!GLOB.AdminProcCallSpamPrevention[ckey])
to_chat(usr, "<span class='adminnotice'>Another set of admin called procs are still running, your proc will be run after theirs finish.</span>")
GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
UNTIL(!GLOB.AdminProcCaller)
to_chat(usr, "<span class='adminnotice'>Running your proc</span>")
GLOB.AdminProcCallSpamPrevention -= ckey
else
UNTIL(!GLOB.AdminProcCaller)
GLOB.LastAdminCalledProc = procname
if(target != GLOBAL_PROC)
GLOB.LastAdminCalledTargetRef = "[REF(target)]"
GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
++GLOB.AdminProcCallCount
. = world.WrapAdminProcCall(target, procname, arguments)
if(--GLOB.AdminProcCallCount == 0)
GLOB.AdminProcCaller = null
//adv proc call this, ya nerds
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target == GLOBAL_PROC)
return call(procname)(arglist(arguments))
else if(target != world)
return call(target, procname)(arglist(arguments))
else
log_admin_private("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
/proc/IsAdminAdvancedProcCall()
#ifdef TESTING
return FALSE
#else
return usr && usr.client && GLOB.AdminProcCaller == usr.client.ckey
#endif
/client/proc/callproc_datum(datum/A as null|area|mob|obj|turf)
set category = "Debug"
set name = "Atom ProcCall"
set waitfor = FALSE
if(!check_rights(R_DEBUG))
return
var/procname = input("Proc name, eg: fake_blood","Proc:", null) as text|null
if(!procname)
return
if(!hascall(A,procname))
to_chat(usr, "<span class='warning'>Error: callproc_datum(): type [A.type] has no proc named [procname].</span>")
return
var/list/lst = get_callproc_args()
if(!lst)
return
if(!A || !IsValidSrc(A))
to_chat(usr, "<span class='warning'>Error: callproc_datum(): owner of proc no longer exists.</span>")
return
var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
log_admin(msg)
message_admins(msg)
admin_ticket_log(A, msg)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Atom ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
. = get_callproc_returnval(returnval,procname)
if(.)
to_chat(usr, .)
/client/proc/get_callproc_args()
var/argnum = input("Number of arguments","Number:",0) as num|null
if(isnull(argnum))
return
. = list()
var/list/named_args = list()
while(argnum--)
var/named_arg = input("Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument") as text|null
var/value = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
if (!value["class"])
return
if(named_arg)
named_args[named_arg] = value["value"]
else
. += value["value"]
if(LAZYLEN(named_args))
. += named_args
/client/proc/get_callproc_returnval(returnval,procname)
. = ""
if(islist(returnval))
var/list/returnedlist = returnval
. = "<span class='notice'>"
if(returnedlist.len)
var/assoc_check = returnedlist[1]
if(istext(assoc_check) && (returnedlist[assoc_check] != null))
. += "[procname] returned an associative list:"
for(var/key in returnedlist)
. += "\n[key] = [returnedlist[key]]"
else
. += "[procname] returned a list:"
for(var/elem in returnedlist)
. += "\n[elem]"
else
. = "[procname] returned an empty list"
. += "</span>"
else
. = "<span class='notice'>[procname] returned: [!isnull(returnval) ? returnval : "null"]</span>"
/client/proc/Cell()
set category = "Debug"
set name = "Air Status in Location"
@@ -343,66 +135,6 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
else
alert("Invalid mob")
/proc/make_types_fancy(var/list/types)
if (ispath(types))
types = list(types)
. = list()
for(var/type in types)
var/typename = "[type]"
var/static/list/TYPES_SHORTCUTS = list(
/obj/effect/decal/cleanable = "CLEANABLE",
/obj/item/radio/headset = "HEADSET",
/obj/item/clothing/head/helmet/space = "SPESSHELMET",
/obj/item/book/manual = "MANUAL",
/obj/item/reagent_containers/food/drinks = "DRINK", //longest paths comes first
/obj/item/reagent_containers/food = "FOOD",
/obj/item/reagent_containers = "REAGENT_CONTAINERS",
/obj/machinery/atmospherics = "ATMOS_MECH",
/obj/machinery/portable_atmospherics = "PORT_ATMOS",
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK",
/obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP",
/obj/item/organ = "ORGAN",
/obj/item = "ITEM",
/obj/machinery = "MACHINERY",
/obj/effect = "EFFECT",
/obj = "O",
/datum = "D",
/turf/open = "OPEN",
/turf/closed = "CLOSED",
/turf = "T",
/mob/living/carbon = "CARBON",
/mob/living/simple_animal = "SIMPLE",
/mob/living = "LIVING",
/mob = "M"
)
for (var/tn in TYPES_SHORTCUTS)
if (copytext(typename,1, length("[tn]/")+1)=="[tn]/" /*findtextEx(typename,"[tn]/",1,2)*/ )
typename = TYPES_SHORTCUTS[tn]+copytext(typename,length("[tn]/"))
break
.[typename] = type
/proc/get_fancy_list_of_atom_types()
var/static/list/pre_generated_list
if (!pre_generated_list) //init
pre_generated_list = make_types_fancy(typesof(/atom))
return pre_generated_list
/proc/get_fancy_list_of_datum_types()
var/static/list/pre_generated_list
if (!pre_generated_list) //init
pre_generated_list = make_types_fancy(sortList(typesof(/datum) - typesof(/atom)))
return pre_generated_list
/proc/filter_fancy_list(list/L, filter as text)
var/list/matches = new
for(var/key in L)
var/value = L[key]
if(findtext("[key]", filter) || findtext("[value]", filter))
matches[key] = value
return matches
//TODO: merge the vievars version into this or something maybe mayhaps
/client/proc/cmd_debug_del_all(object as text)
set category = "Debug"
-25
View File
@@ -594,31 +594,6 @@ Traitors and the like can also be revived with the previous role mostly intact.
admin_delete(A)
/client/proc/admin_delete(datum/D)
var/atom/A = D
var/coords = ""
var/jmp_coords = ""
if(istype(A))
var/turf/T = get_turf(A)
if(T)
coords = "at [COORD(T)]"
jmp_coords = "at [ADMIN_COORDJMP(T)]"
else
jmp_coords = coords = "in nullspace"
if (alert(src, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", "Yes", "No") == "Yes")
log_admin("[key_name(usr)] deleted [D] [coords]")
message_admins("[key_name_admin(usr)] deleted [D] [jmp_coords]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delete") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(isturf(D))
var/turf/T = D
T.ScrapeAway()
else
vv_update_display(D, "deleted", VV_MSG_DELETED)
qdel(D)
if(!QDELETED(D))
vv_update_display(D, "deleted", "")
/client/proc/cmd_admin_list_open_jobs()
set category = "Admin"
set name = "Manage Job Slots"
@@ -0,0 +1,24 @@
/client/proc/admin_delete(datum/D)
var/atom/A = D
var/coords = ""
var/jmp_coords = ""
if(istype(A))
var/turf/T = get_turf(A)
if(T)
coords = "at [COORD(T)]"
jmp_coords = "at [ADMIN_COORDJMP(T)]"
else
jmp_coords = coords = "in nullspace"
if (alert(src, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", "Yes", "No") == "Yes")
log_admin("[key_name(usr)] deleted [D] [coords]")
message_admins("[key_name_admin(usr)] deleted [D] [jmp_coords]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delete") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(isturf(D))
var/turf/T = D
T.ScrapeAway()
else
vv_update_display(D, "deleted", VV_MSG_DELETED)
qdel(D)
if(!QDELETED(D))
vv_update_display(D, "deleted", "")
@@ -0,0 +1,76 @@
#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
/proc/debug_variable(name, value, level, datum/D, sanitize = TRUE) //if D is a list, name will be index, and value will be assoc value.
var/header
if(D)
if(islist(D))
var/index = name
if (value)
name = D[name] //name is really the index until this line
else
value = D[name]
header = "<li style='backgroundColor:white'>([VV_HREF_TARGET_1V(D, VV_HK_LIST_EDIT, "E", index)]) ([VV_HREF_TARGET_1V(D, VV_HK_LIST_CHANGE, "C", index)]) ([VV_HREF_TARGET_1V(D, VV_HK_LIST_REMOVE, "-", index)]) "
else
header = "<li style='backgroundColor:white'>([VV_HREF_TARGET_1V(D, VV_HK_BASIC_EDIT, "E", name)]) ([VV_HREF_TARGET_1V(D, VV_HK_BASIC_CHANGE, "C", name)]) ([VV_HREF_TARGET_1V(D, VV_HK_BASIC_MASSEDIT, "M", name)]) "
else
header = "<li>"
var/item
if (isnull(value))
item = "[VV_HTML_ENCODE(name)] = <span class='value'>null</span>"
else if (istext(value))
item = "[VV_HTML_ENCODE(name)] = <span class='value'>\"[VV_HTML_ENCODE(value)]\"</span>"
else if (isicon(value))
#ifdef VARSICON
var/icon/I = icon(value)
var/rnd = rand(1,10000)
var/rname = "tmp[REF(I)][rnd].png"
usr << browse_rsc(I, rname)
item = "[VV_HTML_ENCODE(name)] = (<span class='value'>[value]</span>) <img class=icon src=\"[rname]\">"
#else
item = "[VV_HTML_ENCODE(name)] = /icon (<span class='value'>[value]</span>)"
#endif
else if (isfile(value))
item = "[VV_HTML_ENCODE(name)] = <span class='value'>'[value]'</span>"
else if (istype(value, /datum))
var/datum/DV = value
if ("[DV]" != "[DV.type]") //if the thing as a name var, lets use it.
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] [REF(value)]</a> = [DV] [DV.type]"
else
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] [REF(value)]</a> = [DV.type]"
else if (islist(value))
var/list/L = value
var/list/items = list()
if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? VV_NORMAL_LIST_NO_EXPAND_THRESHOLD : VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD)))
for (var/i in 1 to L.len)
var/key = L[i]
var/val
if (IS_NORMAL_LIST(L) && !isnum(key))
val = L[key]
if (isnull(val)) // we still want to display non-null false values, such as 0 or ""
val = key
key = i
items += debug_variable(key, val, level + 1, sanitize = sanitize)
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a><ul>[items.Join()]</ul>"
else
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a>"
else if (name in GLOB.bitfields)
var/list/flags = list()
for (var/i in GLOB.bitfields[name])
if (value & GLOB.bitfields[name][i])
flags += i
item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(jointext(flags, ", "))]"
else
item = "[VV_HTML_ENCODE(name)] = <span class='value'>[VV_HTML_ENCODE(value)]</span>"
return "[header][item]</li>"
#undef VV_HTML_ENCODE
@@ -0,0 +1,271 @@
/client/proc/vv_get_class(var_name, var_value)
if(isnull(var_value))
. = VV_NULL
else if(isnum(var_value))
if(var_name in GLOB.bitfields)
. = VV_BITFIELD
else
. = VV_NUM
else if(istext(var_value))
if(findtext(var_value, "\n"))
. = VV_MESSAGE
else
. = VV_TEXT
else if(isicon(var_value))
. = VV_ICON
else if(ismob(var_value))
. = VV_MOB_REFERENCE
else if(isloc(var_value))
. = VV_ATOM_REFERENCE
else if(istype(var_value, /client))
. = VV_CLIENT
else if(istype(var_value, /datum))
. = VV_DATUM_REFERENCE
else if(ispath(var_value))
if(ispath(var_value, /atom))
. = VV_ATOM_TYPE
else if(ispath(var_value, /datum))
. = VV_DATUM_TYPE
else
. = VV_TYPE
else if(islist(var_value))
. = VV_LIST
else if(isfile(var_value))
. = VV_FILE
else
. = VV_NULL
/client/proc/vv_get_value(class, default_class, current_value, list/restricted_classes, list/extra_classes, list/classes, var_name)
. = list("class" = class, "value" = null)
if(!class)
if(!classes)
classes = list (
VV_NUM,
VV_TEXT,
VV_MESSAGE,
VV_ICON,
VV_ATOM_REFERENCE,
VV_DATUM_REFERENCE,
VV_MOB_REFERENCE,
VV_CLIENT,
VV_ATOM_TYPE,
VV_DATUM_TYPE,
VV_TYPE,
VV_FILE,
VV_NEW_ATOM,
VV_NEW_DATUM,
VV_NEW_TYPE,
VV_NEW_LIST,
VV_NULL,
VV_RESTORE_DEFAULT,
VV_TEXT_LOCATE,
VV_PROCCALL_RETVAL,
)
var/markstring
if(!(VV_MARKED_DATUM in restricted_classes))
markstring = "[VV_MARKED_DATUM] (CURRENT: [(istype(holder) && istype(holder.marked_datum))? holder.marked_datum.type : "NULL"])"
classes += markstring
if(restricted_classes)
classes -= restricted_classes
if(extra_classes)
classes += extra_classes
.["class"] = input(src, "What kind of data?", "Variable Type", default_class) as null|anything in classes
if(holder && holder.marked_datum && .["class"] == markstring)
.["class"] = VV_MARKED_DATUM
switch(.["class"])
if(VV_TEXT)
.["value"] = input("Enter new text:", "Text", current_value) as null|text
if(.["value"] == null)
.["class"] = null
return
if(VV_MESSAGE)
.["value"] = input("Enter new text:", "Text", current_value) as null|message
if(.["value"] == null)
.["class"] = null
return
if(VV_NUM)
.["value"] = input("Enter new number:", "Num", current_value) as null|num
if(.["value"] == null)
.["class"] = null
return
if(VV_BITFIELD)
.["value"] = input_bitfield(usr, "Editing bitfield: [var_name]", var_name, current_value)
if(.["value"] == null)
.["class"] = null
return
if(VV_ATOM_TYPE)
.["value"] = pick_closest_path(FALSE)
if(.["value"] == null)
.["class"] = null
return
if(VV_DATUM_TYPE)
.["value"] = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
if(.["value"] == null)
.["class"] = null
return
if(VV_TYPE)
var/type = current_value
var/error = ""
do
type = input("Enter type:[error]", "Type", type) as null|text
if(!type)
break
type = text2path(type)
error = "\nType not found, Please try again"
while(!type)
if(!type)
.["class"] = null
return
.["value"] = type
if(VV_ATOM_REFERENCE)
var/type = pick_closest_path(FALSE)
var/subtypes = vv_subtype_prompt(type)
if(subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if(!value)
.["class"] = null
return
.["value"] = things[value]
if(VV_DATUM_REFERENCE)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
var/subtypes = vv_subtype_prompt(type)
if(subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if(!value)
.["class"] = null
return
.["value"] = things[value]
if(VV_MOB_REFERENCE)
var/type = pick_closest_path(FALSE, make_types_fancy(typesof(/mob)))
var/subtypes = vv_subtype_prompt(type)
if(subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if(!value)
.["class"] = null
return
.["value"] = things[value]
if(VV_CLIENT)
.["value"] = input("Select reference:", "Reference", current_value) as null|anything in GLOB.clients
if(.["value"] == null)
.["class"] = null
return
if(VV_FILE)
.["value"] = input("Pick file:", "File") as null|file
if(.["value"] == null)
.["class"] = null
return
if(VV_ICON)
.["value"] = input("Pick icon:", "Icon") as null|icon
if(.["value"] == null)
.["class"] = null
return
if(VV_MARKED_DATUM)
.["value"] = holder.marked_datum
if(.["value"] == null)
.["class"] = null
return
if(VV_PROCCALL_RETVAL)
var/list/get_retval = list()
callproc_blocking(get_retval)
.["value"] = get_retval[1] //should have been set in proccall!
if(.["value"] == null)
.["class"] = null
return
if(VV_NEW_ATOM)
var/type = pick_closest_path(FALSE)
if(!type)
.["class"] = null
return
.["type"] = type
var/atom/newguy = new type()
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if(VV_NEW_DATUM)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
if(!type)
.["class"] = null
return
.["type"] = type
var/datum/newguy = new type()
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if(VV_NEW_TYPE)
var/type = current_value
var/error = ""
do
type = input("Enter type:[error]", "Type", type) as null|text
if(!type)
break
type = text2path(type)
error = "\nType not found, Please try again"
while(!type)
if(!type)
.["class"] = null
return
.["type"] = type
var/datum/newguy = new type()
if(istype(newguy))
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if(VV_NEW_LIST)
.["value"] = list()
.["type"] = /list
if(VV_TEXT_LOCATE)
var/datum/D
do
var/ref = input("Enter reference:", "Reference") as null|text
if(!ref)
break
D = locate(ref)
if(!D)
alert("Invalid ref!")
continue
if(!D.can_vv_mark())
alert("Datum can not be marked!")
continue
while(!D)
.["type"] = D.type
.["value"] = D
@@ -0,0 +1,12 @@
/client/proc/mark_datum(datum/D)
if(!holder)
return
if(holder.marked_datum)
vv_update_display(holder.marked_datum, "marked", "")
holder.marked_datum = D
vv_update_display(D, "marked", VV_MSG_MARKED)
/client/proc/mark_datum_mapview(datum/D as mob|obj|turf|area in view(view))
set category = "Debug"
set name = "Mark Object"
mark_datum(D)
@@ -197,7 +197,7 @@
log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
//not using global lists as vv is a debug function and debug functions should rely on as less things as possible.
/proc/get_all_of_type(var/T, subtypes = TRUE)
var/list/typecache = list()
typecache[T] = 1
@@ -205,19 +205,25 @@
typecache = typecacheof(typecache)
. = list()
if (ispath(T, /mob))
for(var/mob/thing in GLOB.mob_list)
for(var/mob/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
else if (ispath(T, /obj/machinery/door))
for(var/obj/machinery/door/thing in GLOB.airlocks)
for(var/obj/machinery/door/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
else if (ispath(T, /obj/machinery))
for(var/obj/machinery/thing in GLOB.machines)
for(var/obj/machinery/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
else if (ispath(T, /obj/item))
for(var/obj/item/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
@@ -247,7 +253,7 @@
CHECK_TICK
else if (ispath(T, /client))
for(var/client/thing in GLOB.clients)
for(var/client/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
@@ -1,264 +1,12 @@
GLOBAL_LIST_INIT(VVlocked, list("vars", "datum_flags", "client", "virus", "viruses", "cuffed", "last_eaten", "unlock_content", "force_ending"))
GLOBAL_LIST_INIT(VVlocked, list("vars", "datum_flags", "client", "mob")) //Requires DEBUG
GLOBAL_PROTECT(VVlocked)
GLOBAL_LIST_INIT(VVicon_edit_lock, list("icon", "icon_state", "overlays", "underlays", "resize"))
GLOBAL_LIST_INIT(VVicon_edit_lock, list("icon", "icon_state", "overlays", "underlays")) //Requires DEBUG or FUN
GLOBAL_PROTECT(VVicon_edit_lock)
GLOBAL_LIST_INIT(VVckey_edit, list("key", "ckey"))
GLOBAL_LIST_INIT(VVckey_edit, list("key", "ckey")) //Requires DEBUG or SPAWN
GLOBAL_PROTECT(VVckey_edit)
GLOBAL_LIST_INIT(VVpixelmovement, list("step_x", "step_y", "bound_height", "bound_width", "bound_x", "bound_y"))
GLOBAL_LIST_INIT(VVpixelmovement, list("bound_x", "bound_y", "step_x", "step_y", "step_size", "bound_height", "bound_width", "bounds")) //No editing ever.
GLOBAL_PROTECT(VVpixelmovement)
/client/proc/vv_get_class(var/var_name, var/var_value)
if(isnull(var_value))
. = VV_NULL
else if (isnum(var_value))
if (var_name in GLOB.bitfields)
. = VV_BITFIELD
else
. = VV_NUM
else if (istext(var_value))
if (findtext(var_value, "\n"))
. = VV_MESSAGE
else
. = VV_TEXT
else if (isicon(var_value))
. = VV_ICON
else if (ismob(var_value))
. = VV_MOB_REFERENCE
else if (isloc(var_value))
. = VV_ATOM_REFERENCE
else if (istype(var_value, /client))
. = VV_CLIENT
else if (istype(var_value, /datum))
. = VV_DATUM_REFERENCE
else if (ispath(var_value))
if (ispath(var_value, /atom))
. = VV_ATOM_TYPE
else if (ispath(var_value, /datum))
. = VV_DATUM_TYPE
else
. = VV_TYPE
else if (islist(var_value))
. = VV_LIST
else if (isfile(var_value))
. = VV_FILE
else
. = VV_NULL
/client/proc/vv_get_value(class, default_class, current_value, list/restricted_classes, list/extra_classes, list/classes, var_name)
. = list("class" = class, "value" = null)
if (!class)
if (!classes)
classes = list (
VV_NUM,
VV_TEXT,
VV_MESSAGE,
VV_ICON,
VV_ATOM_REFERENCE,
VV_DATUM_REFERENCE,
VV_MOB_REFERENCE,
VV_CLIENT,
VV_ATOM_TYPE,
VV_DATUM_TYPE,
VV_TYPE,
VV_FILE,
VV_NEW_ATOM,
VV_NEW_DATUM,
VV_NEW_TYPE,
VV_NEW_LIST,
VV_NULL,
VV_RESTORE_DEFAULT
)
if(holder && holder.marked_datum && !(VV_MARKED_DATUM in restricted_classes))
classes += "[VV_MARKED_DATUM] ([holder.marked_datum.type])"
if (restricted_classes)
classes -= restricted_classes
if (extra_classes)
classes += extra_classes
.["class"] = input(src, "What kind of data?", "Variable Type", default_class) as null|anything in classes
if (holder && holder.marked_datum && .["class"] == "[VV_MARKED_DATUM] ([holder.marked_datum.type])")
.["class"] = VV_MARKED_DATUM
switch(.["class"])
if (VV_TEXT)
.["value"] = input("Enter new text:", "Text", current_value) as null|text
if (.["value"] == null)
.["class"] = null
return
if (VV_MESSAGE)
.["value"] = input("Enter new text:", "Text", current_value) as null|message
if (.["value"] == null)
.["class"] = null
return
if (VV_NUM)
.["value"] = input("Enter new number:", "Num", current_value) as null|num
if (.["value"] == null)
.["class"] = null
return
if (VV_BITFIELD)
.["value"] = input_bitfield(usr, "Editing bitfield: [var_name]", var_name, current_value)
if (.["value"] == null)
.["class"] = null
return
if (VV_ATOM_TYPE)
.["value"] = pick_closest_path(FALSE)
if (.["value"] == null)
.["class"] = null
return
if (VV_DATUM_TYPE)
.["value"] = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
if (.["value"] == null)
.["class"] = null
return
if (VV_TYPE)
var/type = current_value
var/error = ""
do
type = input("Enter type:[error]", "Type", type) as null|text
if (!type)
break
type = text2path(type)
error = "\nType not found, Please try again"
while(!type)
if (!type)
.["class"] = null
return
.["value"] = type
if (VV_ATOM_REFERENCE)
var/type = pick_closest_path(FALSE)
var/subtypes = vv_subtype_prompt(type)
if (subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if (!value)
.["class"] = null
return
.["value"] = things[value]
if (VV_DATUM_REFERENCE)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
var/subtypes = vv_subtype_prompt(type)
if (subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if (!value)
.["class"] = null
return
.["value"] = things[value]
if (VV_MOB_REFERENCE)
var/type = pick_closest_path(FALSE, make_types_fancy(typesof(/mob)))
var/subtypes = vv_subtype_prompt(type)
if (subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if (!value)
.["class"] = null
return
.["value"] = things[value]
if (VV_CLIENT)
.["value"] = input("Select reference:", "Reference", current_value) as null|anything in GLOB.clients
if (.["value"] == null)
.["class"] = null
return
if (VV_FILE)
.["value"] = input("Pick file:", "File") as null|file
if (.["value"] == null)
.["class"] = null
return
if (VV_ICON)
.["value"] = input("Pick icon:", "Icon") as null|icon
if (.["value"] == null)
.["class"] = null
return
if (VV_MARKED_DATUM)
.["value"] = holder.marked_datum
if (.["value"] == null)
.["class"] = null
return
if (VV_NEW_ATOM)
var/type = pick_closest_path(FALSE)
if (!type)
.["class"] = null
return
.["type"] = type
var/atom/newguy = new type()
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if (VV_NEW_DATUM)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
if (!type)
.["class"] = null
return
.["type"] = type
var/datum/newguy = new type()
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if (VV_NEW_TYPE)
var/type = current_value
var/error = ""
do
type = input("Enter type:[error]", "Type", type) as null|text
if (!type)
break
type = text2path(type)
error = "\nType not found, Please try again"
while(!type)
if (!type)
.["class"] = null
return
.["type"] = type
var/datum/newguy = new type()
if(istype(newguy))
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if (VV_NEW_LIST)
.["value"] = list()
.["type"] = /list
/client/proc/vv_parse_text(O, new_var)
if(O && findtext(new_var,"\["))
var/process_vars = alert(usr,"\[] detected in string, process as variables?","Process Variables?","Yes","No")
@@ -372,13 +120,13 @@ GLOBAL_PROTECT(VVpixelmovement)
if(confirm != "Continue")
return
var/is_normal_list = IS_NORMAL_LIST(L)
var/list/names = list()
for (var/i in 1 to L.len)
var/key = L[i]
var/value
if (IS_NORMAL_LIST(L) && !isnum(key))
if (is_normal_list && !isnum(key))
value = L[key]
if (value == null)
value = "null"
@@ -439,10 +187,17 @@ GLOBAL_PROTECT(VVpixelmovement)
assoc_key = L[index]
var/default
var/variable
if (assoc)
variable = L[assoc_key]
else
variable = L[index]
var/old_assoc_value //EXPERIMENTAL - Keep old associated value while modifying key, if any
if(is_normal_list)
if (assoc)
variable = L[assoc_key]
else
variable = L[index]
//EXPERIMENTAL - Keep old associated value while modifying key, if any
var/found = L[variable]
if(!isnull(found))
old_assoc_value = found
//
default = vv_get_class(objectvar, variable)
@@ -504,11 +259,13 @@ GLOBAL_PROTECT(VVpixelmovement)
for(var/V in varsvars)
new_var = replacetext(new_var,"\[[V]]","[O.vars[V]]")
if(assoc)
L[assoc_key] = new_var
else
L[index] = new_var
if(is_normal_list)
if(assoc)
L[assoc_key] = new_var
else
L[index] = new_var
if(!isnull(old_assoc_value) && IS_VALID_ASSOC_KEY(new_var))
L[new_var] = old_assoc_value
if (O)
if (O.vv_edit_var(objectvar, L) == FALSE)
to_chat(src, "Your edit was rejected by the object.")
@@ -527,15 +284,8 @@ GLOBAL_PROTECT(VVpixelmovement)
if(param_var_name in GLOB.VVicon_edit_lock)
if(!check_rights(R_FUN|R_DEBUG))
return FALSE
if(param_var_name in GLOB.VVpixelmovement)
if(!check_rights(R_DEBUG))
return FALSE
var/prompt = alert(usr, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", "ABORT ", "Continue", " ABORT")
if (prompt != "Continue")
return FALSE
return TRUE
/client/proc/modify_variables(atom/O, param_var_name = null, autodetect_class = 0)
if(!check_rights(R_VAREDIT))
return
@@ -567,11 +317,6 @@ GLOBAL_PROTECT(VVpixelmovement)
var_value = O.vars[variable]
if(!vv_varname_lockcheck(variable))
return
if(istype(O, /datum/armor))
var/prompt = alert(src, "Editing this var changes this value on potentially thousands of items that share the same combination of armor values. If you want to edit the armor of just one item, use the \"Modify armor values\" dropdown item", "DANGER", "ABORT ", "Continue", " ABORT")
if (prompt != "Continue")
return
var/default = vv_get_class(variable, var_value)
@@ -635,10 +380,9 @@ GLOBAL_PROTECT(VVpixelmovement)
to_chat(src, "Your edit was rejected by the object.")
return
vv_update_display(O, "varedited", VV_MSG_EDITED)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_VAR_EDIT, args)
log_world("### VarEdit by [key_name(src)]: [O.type] [variable]=[var_value] => [var_new]")
log_admin("[key_name(src)] modified [original_name]'s [variable] from [html_encode("[var_value]")] to [html_encode("[var_new]")]")
var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] from [var_value] to [var_new]"
message_admins(msg)
admin_ticket_log(O, msg)
return TRUE
return TRUE
+128
View File
@@ -0,0 +1,128 @@
//DO NOT ADD MORE TO THIS FILE.
//Use vv_do_topic() for datums!
/client/proc/view_var_Topic(href, href_list, hsrc)
if( (usr.client != src) || !src.holder || !holder.CheckAdminHref(href, href_list))
return
var/target = GET_VV_TARGET
vv_do_basic(target, href_list, href)
if(istype(target, /datum))
var/datum/D = target
D.vv_do_topic(href_list)
else if(islist(target))
vv_do_list(target, href_list)
if(href_list["Vars"])
debug_variables(locate(href_list["Vars"]))
//Stuff below aren't in dropdowns/etc.
if(check_rights(R_VAREDIT))
//~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records).
if(href_list["rename"])
if(!check_rights(NONE))
return
var/mob/M = locate(href_list["rename"]) in GLOB.mob_list
if(!istype(M))
to_chat(usr, "This can only be used on instances of type /mob")
return
var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN)
if( !new_name || !M )
return
message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].")
M.fully_replace_character_name(M.real_name,new_name)
vv_update_display(M, "name", new_name)
vv_update_display(M, "real_name", M.real_name || "No real name")
else if(href_list["rotatedatum"])
if(!check_rights(NONE))
return
var/atom/A = locate(href_list["rotatedatum"])
if(!istype(A))
to_chat(usr, "This can only be done to instances of type /atom")
return
switch(href_list["rotatedir"])
if("right")
A.setDir(turn(A.dir, -45))
if("left")
A.setDir(turn(A.dir, 45))
vv_update_display(A, "dir", dir2text(A.dir))
else if(href_list["makehuman"])
if(!check_rights(R_SPAWN))
return
var/mob/living/carbon/monkey/Mo = locate(href_list["makehuman"]) in GLOB.mob_list
if(!istype(Mo))
to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey")
return
if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
return
if(!Mo)
to_chat(usr, "Mob doesn't exist anymore")
return
holder.Topic(href, list("humanone"=href_list["makehuman"]))
else if(href_list["adjustDamage"] && href_list["mobToDamage"])
if(!check_rights(NONE))
return
var/mob/living/L = locate(href_list["mobToDamage"]) in GLOB.mob_list
if(!istype(L))
return
var/Text = href_list["adjustDamage"]
var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num
if(!L)
to_chat(usr, "Mob doesn't exist anymore")
return
var/newamt
switch(Text)
if("brute")
L.adjustBruteLoss(amount)
newamt = L.getBruteLoss()
if("fire")
L.adjustFireLoss(amount)
newamt = L.getFireLoss()
if("toxin")
L.adjustToxLoss(amount)
newamt = L.getToxLoss()
if("oxygen")
L.adjustOxyLoss(amount)
newamt = L.getOxyLoss()
if("brain")
L.adjustOrganLoss(ORGAN_SLOT_BRAIN, amount)
newamt = L.getOrganLoss(ORGAN_SLOT_BRAIN)
if("clone")
L.adjustCloneLoss(amount)
newamt = L.getCloneLoss()
if("stamina")
L.adjustStaminaLoss(amount)
newamt = L.getStaminaLoss()
else
to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]")
return
if(amount != 0)
var/log_msg = "[key_name(usr)] dealt [amount] amount of [Text] damage to [key_name(L)]"
message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [ADMIN_LOOKUPFLW(L)]")
log_admin(log_msg)
admin_ticket_log(L, "<font color='blue'>[log_msg]</font>")
vv_update_display(L, Text, "[newamt]")
//Finally, refresh if something modified the list.
if(href_list["datumrefresh"])
var/datum/DAT = locate(href_list["datumrefresh"])
if(istype(DAT, /datum) || istype(DAT, /client))
debug_variables(DAT)
@@ -0,0 +1,51 @@
//Not using datum.vv_do_topic for very basic/low level debug things, incase the datum's vv_do_topic is runtiming/whatnot.
/client/proc/vv_do_basic(datum/target, href_list)
var/target_var = GET_VV_VAR_TARGET
if(check_rights(R_VAREDIT))
if(target_var)
if(href_list[VV_HK_BASIC_EDIT])
if(!modify_variables(target, target_var, 1))
return
switch(target_var)
if("name")
vv_update_display(target, "name", "[target]")
if("dir")
var/atom/A = target
if(istype(A))
vv_update_display(target, "dir", dir2text(A.dir) || A.dir)
if("ckey")
var/mob/living/L = target
if(istype(L))
vv_update_display(target, "ckey", L.ckey || "No ckey")
if("real_name")
var/mob/living/L = target
if(istype(L))
vv_update_display(target, "real_name", L.real_name || "No real name")
if(href_list[VV_HK_BASIC_CHANGE])
modify_variables(target, target_var, 0)
if(href_list[VV_HK_BASIC_MASSEDIT])
cmd_mass_modify_object_variables(target, target_var)
if(check_rights(R_ADMIN, FALSE))
if(href_list[VV_HK_EXPOSE])
var/value = vv_get_value(VV_CLIENT)
if (value["class"] != VV_CLIENT)
return
var/client/C = value["value"]
if (!C)
return
if(!target)
to_chat(usr, "<span class='warning'>The object you tried to expose to [C] no longer exists (nulled or hard-deled)</span>")
return
message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a <a href='?_src_=vars;datumrefresh=[REF(target)]'>VV window</a>")
log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [target]")
to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window")
C.debug_variables(target)
if(check_rights(R_DEBUG))
if(href_list[VV_HK_DELETE])
usr.client.admin_delete(target)
if (isturf(src)) // show the turf that took its place
usr.client.debug_variables(src)
if(href_list[VV_HK_MARK])
usr.client.mark_datum(target)
if(href_list[VV_HK_CALLPROC])
usr.client.callproc_datum(target)
@@ -0,0 +1,43 @@
//LISTS - CAN NOT DO VV_DO_TOPIC BECAUSE LISTS AREN'T DATUMS :(
/client/proc/vv_do_list(list/target, href_list)
var/target_index = text2num(GET_VV_VAR_TARGET)
if(check_rights(R_VAREDIT))
if(target_index)
if(href_list[VV_HK_LIST_EDIT])
mod_list(target, null, "list", "contents", target_index, autodetect_class = TRUE)
if(href_list[VV_HK_LIST_CHANGE])
mod_list(target, null, "list", "contents", target_index, autodetect_class = FALSE)
if(href_list[VV_HK_LIST_REMOVE])
var/variable = target[target_index]
var/prompt = alert("Do you want to remove item number [target_index] from list?", "Confirm", "Yes", "No")
if (prompt != "Yes")
return
target.Cut(target_index, target_index+1)
log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]")
log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]")
message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]")
if(href_list[VV_HK_LIST_ADD])
mod_list_add(target, null, "list", "contents")
if(href_list[VV_HK_LIST_ERASE_DUPES])
uniqueList_inplace(target)
log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES")
log_admin("[key_name(src)] modified list's contents: CLEAR DUPES")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES")
if(href_list[VV_HK_LIST_ERASE_NULLS])
listclearnulls(target)
log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS")
log_admin("[key_name(src)] modified list's contents: CLEAR NULLS")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS")
if(href_list[VV_HK_LIST_SET_LENGTH])
var/value = vv_get_value(VV_NUM)
if (value["class"] != VV_NUM || value["value"] > max(50000, target.len)) //safety - would rather someone not put an extra 0 and erase the server's memory lmao.
return
target.len = value["value"]
log_world("### ListVarEdit by [src]: /list len: [target.len]")
log_admin("[key_name(src)] modified list's len: [target.len]")
message_admins("[key_name_admin(src)] modified list's len: [target.len]")
if(href_list[VV_HK_LIST_SHUFFLE])
shuffle_inplace(target)
log_world("### ListVarEdit by [src]: /list contents: SHUFFLE")
log_admin("[key_name(src)] modified list's contents: SHUFFLE")
message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE")
@@ -0,0 +1,269 @@
/client/proc/debug_variables(datum/D in world)
set category = "Debug"
set name = "View Variables"
//set src in world
var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round.
if(!usr.client || !usr.client.holder) //This is usr because admins can call the proc on other clients, even if they're not admins, to show them VVs.
to_chat(usr, "<span class='danger'>You need to be an administrator to access this.</span>")
return
if(!D)
return
var/islist = islist(D)
if(!islist && !istype(D))
return
var/title = ""
var/refid = REF(D)
var/icon/sprite
var/hash
var/type = islist? /list : D.type
var/no_icon = FALSE
if(istype(D, /atom))
sprite = getFlatIcon(D)
hash = md5(sprite)
if(sprite)
hash = md5(sprite)
src << browse_rsc(sprite, "vv[hash].png")
else
no_icon = TRUE
title = "[D] ([REF(D)]) = [type]"
var/formatted_type = replacetext("[type]", "/", "<wbr>/")
var/sprite_text
if(sprite)
sprite_text = no_icon? "\[NO ICON\]" : "<img src='vv[hash].png'></td><td>"
var/list/header = islist(D)? list("<b>/list</b>") : D.vv_get_header()
var/marked_line
if(holder && holder.marked_datum && holder.marked_datum == D)
marked_line = VV_MSG_MARKED
var/varedited_line
if(!islist && (D.datum_flags & DF_VAR_EDITED))
varedited_line = VV_MSG_EDITED
var/deleted_line
if(!islist && D.gc_destroyed)
deleted_line = VV_MSG_DELETED
var/list/dropdownoptions
if (islist)
dropdownoptions = list(
"---",
"Add Item" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ADD),
"Remove Nulls" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_NULLS),
"Remove Dupes" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_DUPES),
"Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH),
"Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE),
"Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE),
"---"
)
for(var/i in 1 to length(dropdownoptions))
var/name = dropdownoptions[i]
var/link = dropdownoptions[name]
dropdownoptions[i] = "<option value[link? "='[link]'":""]>[name]</option>"
else
dropdownoptions = D.vv_get_dropdown()
var/list/names = list()
if(!islist)
for(var/V in D.vars)
names += V
sleep(1)
var/list/variable_html = list()
if(islist)
var/list/L = D
for(var/i in 1 to L.len)
var/key = L[i]
var/value
if(IS_NORMAL_LIST(L) && IS_VALID_ASSOC_KEY(key))
value = L[key]
variable_html += debug_variable(i, value, 0, L)
else
names = sortList(names)
for(var/V in names)
if(D.can_vv_get(V))
variable_html += D.vv_get_var(V)
var/html = {"
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>[title]</title>
<style>
body {
font-family: Verdana, sans-serif;
font-size: 9pt;
}
.value {
font-family: "Courier New", monospace;
font-size: 8pt;
}
</style>
</head>
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
<script type="text/javascript">
// onload
function selectTextField() {
var filter_text = document.getElementById('filter');
filter_text.focus();
filter_text.select();
var lastsearch = getCookie("[refid][cookieoffset]search");
if (lastsearch) {
filter_text.value = lastsearch;
updateSearch();
}
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca\[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
}
// main search functionality
var last_filter = "";
function updateSearch() {
var filter = document.getElementById('filter').value.toLowerCase();
var vars_ol = document.getElementById("vars");
if (filter === last_filter) {
// An event triggered an update but nothing has changed.
return;
} else if (filter.indexOf(last_filter) === 0) {
// The new filter starts with the old filter, fast path by removing only.
var children = vars_ol.childNodes;
for (var i = children.length - 1; i >= 0; --i) {
try {
var li = children\[i];
if (li.innerText.toLowerCase().indexOf(filter) == -1) {
vars_ol.removeChild(li);
}
} catch(err) {}
}
} else {
// Remove everything and put back what matches.
while (vars_ol.hasChildNodes()) {
vars_ol.removeChild(vars_ol.lastChild);
}
for (var i = 0; i < complete_list.length; ++i) {
try {
var li = complete_list\[i];
if (!filter || li.innerText.toLowerCase().indexOf(filter) != -1) {
vars_ol.appendChild(li);
}
} catch(err) {}
}
}
last_filter = filter;
document.cookie="[refid][cookieoffset]search="+encodeURIComponent(filter);
}
// onkeydown
function handle_keydown() {
if(event.keyCode == 116) { //F5 (to refresh properly)
document.getElementById("refresh_link").click();
event.preventDefault ? event.preventDefault() : (event.returnValue = false);
return false;
}
return true;
}
// onkeyup
function handle_keyup() {
updateSearch();
}
// onchange
function handle_dropdown(list) {
var value = list.options\[list.selectedIndex].value;
if (value !== "") {
location.href = value;
}
list.selectedIndex = 0;
document.getElementById('filter').focus();
}
// byjax
function replace_span(what) {
var idx = what.indexOf(':');
document.getElementById(what.substr(0, idx)).innerHTML = what.substr(idx + 1);
}
</script>
<div align='center'>
<table width='100%'>
<tr>
<td width='50%'>
<table align='center' width='100%'>
<tr>
<td>
[sprite_text]
<div align='center'>
[header.Join()]
</div>
</td>
</tr>
</table>
<div align='center'>
<b><font size='1'>[formatted_type]</font></b>
<span id='marked'>[marked_line]</span>
<span id='varedited'>[varedited_line]</span>
<span id='deleted'>[deleted_line]</span>
</div>
</td>
<td width='50%'>
<div align='center'>
<a id='refresh_link' href='?_src_=vars;
datumrefresh=[refid];[HrefToken()]'>Refresh</a>
<form>
<select name="file" size="1"
onchange="handle_dropdown(this)"
onmouseclick="this.focus()">
<option value selected>Select option</option>
[dropdownoptions.Join()]
</select>
</form>
</div>
</td>
</tr>
</table>
</div>
<hr>
<font size='1'>
<b>E</b> - Edit, tries to determine the variable type by itself.<br>
<b>C</b> - Change, asks you for the var type first.<br>
<b>M</b> - Mass modify: changes this variable for all objects of this type.<br>
</font>
<hr>
<table width='100%'>
<tr>
<td width='20%'>
<div align='center'>
<b>Search:</b>
</div>
</td>
<td width='80%'>
<input type='text' id='filter' name='filter_text' value='' style='width:100%;'>
</td>
</tr>
</table>
<hr>
<ol id='vars'>
[variable_html.Join()]
</ol>
<script type='text/javascript'>
var complete_list = \[\];
var lis = document.getElementById("vars").children;
for(var i = lis.length; i--;) complete_list\[i\] = lis\[i\];
</script>
</body>
</html>
"}
src << browse(html, "window=variables[refid];size=475x650")
/client/proc/vv_update_display(datum/D, span, content)
src << output("[span]:[content]", "variables[REF(D)].browser:replace_span")
@@ -31,4 +31,5 @@
/datum/antagonist/abductee/remove_innate_effects(mob/living/mob_override)
update_abductor_icons_removed(mob_override ? mob_override.mind : owner)
qdel(brain_trauma)
if(!QDELETED(brain_trauma))
qdel(brain_trauma)
@@ -22,6 +22,7 @@
/obj/item/gun/energy,
/obj/item/restraints/handcuffs
)
mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON
var/mode = VEST_STEALTH
var/stealth_active = 0
var/combat_cooldown = 10
@@ -92,10 +93,8 @@
M.cut_overlays()
M.regenerate_icons()
/obj/item/clothing/suit/armor/abductor/vest/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
DeactivateStealth()
/obj/item/clothing/suit/armor/abductor/vest/IsReflect()
/obj/item/clothing/suit/armor/abductor/vest/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
. = ..()
DeactivateStealth()
/obj/item/clothing/suit/armor/abductor/vest/ui_action_click()
@@ -493,7 +492,7 @@
user.do_attack_animation(L)
if(L.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
if(L.run_block(src, 0, "[user]'s [src]", ATTACK_TYPE_MELEE, 0, user, check_zone(user.zone_selected)) & BLOCK_SUCCESS)
playsound(L, 'sound/weapons/genhit.ogg', 50, TRUE)
return FALSE
@@ -209,7 +209,6 @@
open_machine()
SendBack(H)
return "<span class='bad'>Specimen braindead - disposed.</span>"
return "<span class='bad'>ERROR</span>"
/obj/machinery/abductor/experiment/proc/SendBack(mob/living/carbon/human/H)
@@ -1,12 +1,6 @@
// INTEGRATION: Adding Procs and Datums to existing "classes"
/mob/living/proc/AmBloodsucker(falseIfInDisguise=FALSE)
// No Datum
if(!mind || !mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER))
return FALSE
return TRUE
/mob/living/proc/HaveBloodsuckerBodyparts(var/displaymessage="") // displaymessage can be something such as "rising from death" for Torpid Sleep. givewarningto is the person receiving messages.
/mob/living/proc/HaveBloodsuckerBodyparts(displaymessage = "") // displaymessage can be something such as "rising from death" for Torpid Sleep. givewarningto is the person receiving messages.
if(!getorganslot(ORGAN_SLOT_HEART))
if(displaymessage != "")
to_chat(src, "<span class='warning'>Without a heart, you are incapable of [displaymessage].</span>")
@@ -21,33 +15,6 @@
return FALSE
return TRUE
// GET DAMAGE
// Do NOT count the damage on prosthetics for this.
/mob/living/proc/getBruteLoss_nonProsthetic()
return getBruteLoss()
/mob/living/proc/getFireLoss_nonProsthetic()
return getFireLoss()
/mob/living/carbon/getBruteLoss_nonProsthetic()
var/amount = 0
for(var/obj/item/bodypart/BP in bodyparts)
if(BP.status < 2)
amount += BP.brute_dam
return amount
/mob/living/carbon/getFireLoss_nonProsthetic()
var/amount = 0
for(var/obj/item/bodypart/BP in bodyparts)
if(BP.status < 2)
amount += BP.burn_dam
return amount
/mob/living/carbon
// EXAMINING
/mob/living/carbon/human/proc/ReturnVampExamine(var/mob/viewer)
if(!mind || !viewer.mind)
@@ -12,10 +12,10 @@
/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 = FALSE
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_DEATHCOMA)) // Deduct Blood
AddBloodVolume(-0.1) // -.15 (before tick went from 10 to 30, but we also charge more for faking life now)
AddBloodVolume(passive_blood_drain) // -.1 currently
if(HandleHealing(1)) // Heal
if(notice_healing == FALSE && owner.current.blood_volume > 0)
to_chat(owner, "<span class='notice'>The power of your blood begins knitting your wounds...</span>")
@@ -25,7 +25,7 @@
HandleStarving() // Death
HandleDeath() // Standard Update
update_hud()// Daytime Sleep in Coffin
if (SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker"))
if(SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker"))
if(istype(owner.current.loc, /obj/structure/closet/crate/coffin))
Torpor_Begin()
// Wait before next pass
@@ -39,12 +39,12 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/datum/antagonist/bloodsucker/proc/AddBloodVolume(value)
owner.current.blood_volume = CLAMP(owner.current.blood_volume + value, 0, maxBloodVolume)
owner.current.blood_volume = CLAMP(owner.current.blood_volume + value, 0, max_blood_volume)
update_hud()
/datum/antagonist/bloodsucker/proc/HandleFeeding(mob/living/carbon/target, mult=1)
// mult: SILENT feed is 1/3 the amount
var/blood_taken = min(feedAmount, target.blood_volume) * mult // Starts at 15 (now 8 since we doubled the Feed time)
var/blood_taken = min(feed_amount, target.blood_volume) * mult // Starts at 15 (now 8 since we doubled the Feed time)
target.blood_volume -= blood_taken
// Simple Animals lose a LOT of blood, and take damage. This is to keep cats, cows, and so forth from giving you insane amounts of blood.
if(!ishuman(target))
@@ -82,38 +82,40 @@
/datum/antagonist/bloodsucker/proc/HandleHealing(mult = 1)
// NOTE: Mult of 0 is just a TEST to see if we are injured and need to go into Torpor!
//It is called from your coffin on close (by you only)
var/actual_regen = regen_rate + additional_regen
if(poweron_masquerade == TRUE || owner.current.AmStaked())
return FALSE
owner.current.adjustStaminaLoss(-1.5 + (regenRate * -7) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more.
owner.current.adjustCloneLoss(-0.1 * (regenRate * 2) * mult, 0)
owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (regenRate * 4) * mult) //adjustBrainLoss(-1 * (regenRate * 4) * mult, 0)
if(owner.current.reagents.has_reagent(/datum/reagent/consumable/garlic))
return FALSE
if(istype(owner.current.get_item_by_slot(SLOT_NECK), /obj/item/clothing/neck/garlic_necklace))
return FALSE
owner.current.adjustStaminaLoss(-1.5 + (actual_regen * -7) * mult, 0) // Humans lose stamina damage really quickly. Vamps should heal more.
owner.current.adjustCloneLoss(-0.1 * (actual_regen * 2) * mult, 0)
owner.current.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1 * (actual_regen * 4) * mult)
// No Bleeding
if(ishuman(owner.current)) //NOTE Current bleeding is horrible, not to count the amount of blood ballistics delete.
/*if(ishuman(owner.current)) //NOTE Current bleeding is horrible, not to count the amount of blood ballistics delete.
var/mob/living/carbon/human/H = owner.current
H.bleed_rate = 0
if(H.bleed_rate > 0) //Only heal bleeding if we are actually bleeding
H.bleed_rate =- 0.5 + actual_regen * 0.2 */
if(iscarbon(owner.current)) // Damage Heal: Do I have damage to ANY bodypart?
var/mob/living/carbon/C = owner.current
var/costMult = 1 // Coffin makes it cheaper
var/fireheal = 0 // BURN: Heal in Coffin while Fakedeath, or when damage above maxhealth (you can never fully heal fire)
var/amInCoffinWhileTorpor = istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_DEATHCOMA)) // Check for mult 0 OR death coma. (mult 0 means we're testing from coffin)
var/amInCoffinWhileTorpor = istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_FAKEDEATH)) // Check for mult 0 OR death coma. (mult 0 means we're testing from coffin)
if(amInCoffinWhileTorpor)
mult *= 4 // Increase multiplier if we're sleeping in a coffin.
fireheal = min(C.getFireLoss_nonProsthetic(), regenRate) // NOTE: Burn damage ONLY heals in torpor.
costMult = 0.25
fireheal = min(C.getFireLoss(), regen_rate) // NOTE: Burn damage ONLY heals in torpor.
C.ExtinguishMob()
CureDisabilities() // Extinguish Fire
C.remove_all_embedded_objects() // Remove Embedded!
owner.current.regenerate_organs() // Heal Organs (will respawn original eyes etc. but we replace right away, next)
CheckVampOrgans() // Heart, Eyes
else
if(owner.current.blood_volume <= 0) // No Blood? Lower Mult
mult = 0.25
// Crit from burn? Lower damage to maximum allowed.
//if (C.getFireLoss() > owner.current.getMaxHealth())
// fireheal = regenRate / 2
if(check_limbs(costMult))
return TRUE
// BRUTE: Always Heal
var/bruteheal = min(C.getBruteLoss_nonProsthetic(), regenRate)
var/toxinheal = min(C.getToxLoss(), regenRate)
var/bruteheal = min(C.getBruteLoss(), actual_regen)
var/toxinheal = min(C.getToxLoss(), actual_regen)
// Heal if Damaged
if(bruteheal + fireheal + toxinheal > 0) // Just a check? Don't heal/spend, and return.
if(mult == 0)
@@ -127,28 +129,29 @@
//C.heal_overall_damage(bruteheal * mult, fireheal * mult) // REMOVED: We need to FORCE this, because otherwise, vamps won't heal EVER. Swapped to above.
AddBloodVolume((bruteheal * -0.5 + fireheal * -1 + toxinheal * -0.2) / mult * costMult) // Costs blood to heal
return TRUE // Healed! Done for this tick.
if(amInCoffinWhileTorpor) // Limbs? (And I have no other healing)
var/list/missing = owner.current.get_missing_limbs() // Heal Missing
if (missing.len) // Cycle through ALL limbs and regen them!
for (var/targetLimbZone in missing) // 1) Find ONE Limb and regenerate it.
owner.current.regenerate_limb(targetLimbZone, 0) // regenerate_limbs() <--- If you want to EXCLUDE certain parts, do it like this ----> regenerate_limbs(0, list("head"))
var/obj/item/bodypart/L = owner.current.get_bodypart( targetLimbZone ) // 2) Limb returns Damaged
AddBloodVolume(50 * costMult) // Costs blood to heal
L.brute_dam = 60
to_chat(owner.current, "<span class='notice'>Your flesh knits as it regrows [L]!</span>")
playsound(owner.current, 'sound/magic/demon_consume.ogg', 50, 1)
// DONE! After regenerating ANY number of limbs, we stop here.
return TRUE
/*else // REMOVED: For now, let's just leave prosthetics on. Maybe you WANT to be a robovamp.
// Remove Prosthetic/False Limb
for(var/obj/item/bodypart/BP in C.bodyparts)
message_admins("T1: [BP] ")
if (istype(BP) && BP.status == 2)
message_admins("T2: [BP] ")
BP.drop_limb()
return TRUE */
// NOTE: Limbs have a "status", like their hosts "stat". 2 is dead (aka Prosthetic). 1 seems to be idle/alive.*/
return FALSE
/datum/antagonist/bloodsucker/proc/check_limbs(costMult)
var/limb_regen_cost = 50 * costMult
var/mob/living/carbon/C = owner.current
var/list/missing = C.get_missing_limbs()
if(missing.len && C.blood_volume < limb_regen_cost + 5)
return FALSE
for(var/targetLimbZone in missing) // 1) Find ONE Limb and regenerate it.
C.regenerate_limb(targetLimbZone, FALSE) // regenerate_limbs() <--- If you want to EXCLUDE certain parts, do it like this ----> regenerate_limbs(0, list("head"))
AddBloodVolume(50)
var/obj/item/bodypart/L = C.get_bodypart(targetLimbZone) // 2) Limb returns Damaged
L.brute_dam = 60
to_chat(C, "<span class='notice'>Your flesh knits as it regrows your [L]!</span>")
playsound(C, 'sound/magic/demon_consume.ogg', 50, TRUE)
return TRUE
/*for(var/obj/item/bodypart/BP in C.bodyparts)
if(!istype(BP) && !BP.status == 2)
return FALSE
to_chat(C, "<span class='notice'>Your body expels the [BP]!</span>")
BP.drop_limb()
return TRUE */
/datum/antagonist/bloodsucker/proc/CureDisabilities()
var/mob/living/carbon/C = owner.current
@@ -179,7 +182,16 @@
if(owner.current.blood_volume < BLOOD_VOLUME_BAD / 2)
owner.current.blur_eyes(8 - 8 * (owner.current.blood_volume / BLOOD_VOLUME_BAD))
// Nutrition
owner.current.nutrition = min(owner.current.blood_volume, NUTRITION_LEVEL_FED) // <-- 350 //NUTRITION_LEVEL_FULL
owner.current.nutrition = clamp(owner.current.blood_volume, 545, 0) //The amount of blood is how full we are.
//A bit higher regeneration based on blood volume
if(owner.current.blood_volume < 700)
additional_regen = 0.4
else if(owner.current.blood_volume < BLOOD_VOLUME_NORMAL)
additional_regen = 0.3
else if(owner.current.blood_volume < BLOOD_VOLUME_OKAY)
additional_regen = 0.2
else if(owner.current.blood_volume < BLOOD_VOLUME_BAD)
additional_regen = 0.1
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DEATH
@@ -189,7 +201,7 @@
/datum/antagonist/bloodsucker/proc/HandleDeath()
// FINAL DEATH
// Fire Damage? (above double health)
if(owner.current.getFireLoss_nonProsthetic() >= owner.current.maxHealth * 2.5)
if(owner.current.getFireLoss() >= owner.current.maxHealth * 3)
FinalDeath()
return
// Staked while "Temp Death" or Asleep
@@ -209,8 +221,8 @@
// for (var/datum/action/bloodsucker/masquerade/P in powers)
// P.Deactivate()
// TEMP DEATH
var/total_brute = owner.current.getBruteLoss_nonProsthetic()
var/total_burn = owner.current.getFireLoss_nonProsthetic()
var/total_brute = owner.current.getBruteLoss()
var/total_burn = owner.current.getFireLoss()
var/total_toxloss = owner.current.getToxLoss() //This is neater than just putting it in total_damage
var/total_damage = total_brute + total_burn + total_toxloss
// Died? Convert to Torpor (fake death)
@@ -218,27 +230,25 @@
Torpor_Begin()
to_chat(owner, "<span class='danger'>Your immortal body will not yet relinquish your soul to the abyss. You enter Torpor.</span>")
sleep(30) //To avoid spam
if (poweron_masquerade == TRUE)
if(poweron_masquerade == TRUE)
to_chat(owner, "<span class='warning'>Your wounds will not heal until you disable the <span class='boldnotice'>Masquerade</span> power.</span>")
// End Torpor:
else // No damage, OR toxin healed AND brute healed and NOT in coffin (since you cannot heal burn)
if(total_damage <= 0 || total_toxloss <= 0 && total_brute <= 0 && !istype(owner.current.loc, /obj/structure/closet/crate/coffin))
// Not Daytime, Not in Torpor
if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker"))
if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker"))
Torpor_End()
// Fake Unconscious
if(poweron_masquerade == TRUE && total_damage >= owner.current.getMaxHealth() - HEALTH_THRESHOLD_FULLCRIT)
owner.current.Unconscious(20,1)
//HEALTH_THRESHOLD_CRIT 0
//HEALTH_THRESHOLD_FULLCRIT -30
//HEALTH_THRESHOLD_DEAD -100
owner.current.Unconscious(20, 1)
/datum/antagonist/bloodsucker/proc/Torpor_Begin(amInCoffin=FALSE)
/datum/antagonist/bloodsucker/proc/Torpor_Begin(amInCoffin = FALSE)
owner.current.stat = UNCONSCIOUS
owner.current.fakedeath("bloodsucker") // Come after UNCONSCIOUS or else it fails
owner.current.apply_status_effect(STATUS_EFFECT_UNCONSCIOUS)
ADD_TRAIT(owner.current, TRAIT_FAKEDEATH, "bloodsucker") // Come after UNCONSCIOUS or else it fails
ADD_TRAIT(owner.current, TRAIT_NODEATH, "bloodsucker") // Without this, you'll just keep dying while you recover.
ADD_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker") // So you can heal in 0 G. otherwise you just...heal forever.
ADD_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker") // So you can heal in 0 G. otherwise you just...heal forever.
ADD_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker") // So you can heal in space. Otherwise you just...heal forever.
ADD_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker")
// Visuals
owner.current.update_sight()
owner.current.reload_fullscreen()
@@ -247,10 +257,10 @@
if(power.active && !power.can_use_in_torpor)
power.DeactivatePower()
/datum/antagonist/bloodsucker/proc/Torpor_End()
owner.current.stat = SOFT_CRIT
owner.current.cure_fakedeath("bloodsucker") // Come after SOFT_CRIT or else it fails
owner.current.remove_status_effect(STATUS_EFFECT_UNCONSCIOUS)
REMOVE_TRAIT(owner.current, TRAIT_FAKEDEATH, "bloodsucker")
REMOVE_TRAIT(owner.current, TRAIT_NODEATH, "bloodsucker")
REMOVE_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker")
REMOVE_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker")
@@ -283,18 +293,19 @@
// Free my Vassals!
FreeAllVassals()
// Elders get Dusted
if(vamplevel >= 4) // (vamptitle)
if(bloodsucker_level >= 4) // (bloodsucker_title)
owner.current.visible_message("<span class='warning'>[owner.current]'s skin crackles and dries, their skin and bones withering to dust. A hollow cry whips from what is now a sandy pile of remains.</span>", \
"<span class='userdanger'>Your soul escapes your withering body as the abyss welcomes you to your Final Death.</span>", \
"<span class='italics'>You hear a dry, crackling sound.</span>")
sleep(50)
owner.current.dust()
// Fledglings get Gibbed
else
owner.current.visible_message("<span class='warning'>[owner.current]'s skin bursts forth in a spray of gore and detritus. A horrible cry echoes from what is now a wet pile of decaying meat.</span>", \
"<span class='userdanger'>Your soul escapes your withering body as the abyss welcomes you to your Final Death.</span>", \
"<span class='italics'>You hear a wet, bursting sound.</span>")
owner.current.gib(TRUE, FALSE, FALSE)//Brain cloning is wierd and allows hellbounds. Lets destroy the brain for safety.
playsound(owner.current.loc, 'sound/effects/tendril_destroyed.ogg', 40, 1)
owner.current.gib(TRUE, FALSE, FALSE) //Brain cloning is wierd and allows hellbounds. Lets destroy the brain for safety.
playsound(owner.current, 'sound/effects/tendril_destroyed.ogg', 40, TRUE)
@@ -304,15 +315,15 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/mob/proc/CheckBloodsuckerEatFood(var/food_nutrition)
if (!isliving(src))
/mob/proc/CheckBloodsuckerEatFood(food_nutrition)
if(!isliving(src))
return
var/mob/living/L = src
if(!L.AmBloodsucker())
if(!AmBloodsucker(L))
return
// We're a vamp? Try to eat food...
var/datum/antagonist/bloodsucker/bloodsuckerdatum = mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
bloodsuckerdatum.handle_eat_human_food(food_nutrition)
// We're a bloodsucker? Try to eat food...
var/datum/antagonist/bloodsucker/B = L.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
B.handle_eat_human_food(food_nutrition)
/datum/antagonist/bloodsucker/proc/handle_eat_human_food(food_nutrition, puke_blood = TRUE, masquerade_override) // Called from snacks.dm and drinks.dm
@@ -93,6 +93,14 @@
if(display_error)
to_chat(owner, "<span class='warning'>You have a stake in your chest! Your powers are useless.</span>")
return FALSE
if(istype(owner.get_item_by_slot(SLOT_NECK), /obj/item/clothing/neck/garlic_necklace))
if(display_error)
to_chat(owner, "<span class='warning'The necklace on your neck is interfering with your powers!</span>")
return FALSE
if(owner.reagents?.has_reagent(/datum/reagent/consumable/garlic))
if(display_error)
to_chat(owner, "<span class='warning'>Garlic in your blood is interfering with your powers!</span>")
return FALSE
// Incap?
if(must_be_capacitated)
var/mob/living/L = owner
@@ -141,23 +141,23 @@
if(!bloodsuckerdatum.warn_sun_locker)
to_chat(M, "<span class='warning'>Your skin sizzles. The [M.current.loc] doesn't protect well against UV bombardment.</span>")
bloodsuckerdatum.warn_sun_locker = TRUE
M.current.adjustFireLoss(0.5 + bloodsuckerdatum.vamplevel / 2) // M.current.fireloss += 0.5 + bloodsuckerdatum.vamplevel / 2 // Do DIRECT damage. Being spaced was causing this to not occur. setFireLoss(bloodsuckerdatum.vamplevel)
M.current.adjustFireLoss(0.5 + bloodsuckerdatum.bloodsucker_level / 2) // M.current.fireloss += 0.5 + bloodsuckerdatum.bloodsucker_level / 2 // Do DIRECT damage. Being spaced was causing this to not occur. setFireLoss(bloodsuckerdatum.bloodsucker_level)
M.current.updatehealth()
SEND_SIGNAL(M.current, COMSIG_ADD_MOOD_EVENT, "vampsleep", /datum/mood_event/daylight_1)
// Out in the Open? Buh Bye
else
if(!bloodsuckerdatum.warn_sun_burn)
if(bloodsuckerdatum.vamplevel > 0)
if(bloodsuckerdatum.bloodsucker_level > 0)
to_chat(M, "<span class='userdanger'>The solar flare sets your skin ablaze!</span>")
else
to_chat(M, "<span class='userdanger'>The solar flare scalds your neophyte skin!</span>")
bloodsuckerdatum.warn_sun_burn = TRUE
if(M.current.fire_stacks <= 0)
M.current.fire_stacks = 0
if(bloodsuckerdatum.vamplevel > 0)
M.current.adjust_fire_stacks(0.2 + bloodsuckerdatum.vamplevel / 10)
if(bloodsuckerdatum.bloodsucker_level > 0)
M.current.adjust_fire_stacks(0.2 + bloodsuckerdatum.bloodsucker_level / 10)
M.current.IgniteMob()
M.current.adjustFireLoss(2 + bloodsuckerdatum.vamplevel) // M.current.fireloss += 2 + bloodsuckerdatum.vamplevel // Do DIRECT damage. Being spaced was causing this to not occur. //setFireLoss(2 + bloodsuckerdatum.vamplevel)
M.current.adjustFireLoss(2 + bloodsuckerdatum.bloodsucker_level) // M.current.fireloss += 2 + bloodsuckerdatum.bloodsucker_level // Do DIRECT damage. Being spaced was causing this to not occur. //setFireLoss(2 + bloodsuckerdatum.bloodsucker_level)
M.current.updatehealth()
SEND_SIGNAL(M.current, COMSIG_ADD_MOOD_EVENT, "vampsleep", /datum/mood_event/daylight_2)
@@ -8,9 +8,9 @@
job_rank = ROLE_BLOODSUCKER
threat = 5
// NAME
var/vampname // My Dracula name
var/vamptitle // My Dracula title
var/vampreputation // My "Surname" or description of my deeds
var/bloodsucker_name // My Dracula style name
var/bloodsucker_title // My Dracula style title
var/bloodsucker_reputation // My "Surname" or description of my deeds
// CLAN
var/datum/team/vampireclan/clan
var/list/datum/antagonist/vassal/vassals = list()// Vassals under my control. Periodically remove the dead ones.
@@ -20,35 +20,33 @@
var/poweron_feed = FALSE // Am I feeding?
var/poweron_masquerade = FALSE
// STATS
var/vamplevel = 0
var/vamplevel_unspent = 1
var/regenRate = 0.4 // How many points of Brute do I heal per tick?
var/feedAmount = 15 // Amount of blood drawn from a target per tick.
var/maxBloodVolume = 600 // Maximum blood a Vamp can hold via feeding. // BLOOD_VOLUME_NORMAL 550 // BLOOD_VOLUME_SAFE 475 //BLOOD_VOLUME_OKAY 336 //BLOOD_VOLUME_BAD 224 // BLOOD_VOLUME_SURVIVE 122
var/bloodsucker_level
var/bloodsucker_level_unspent = 1
var/regen_rate = 0.3 // How fast do I regenerate?
var/additional_regen // How much additional blood regen we gain from bonuses such as high blood.
var/feed_amount = 15 // Amount of blood drawn from a target per tick.
var/max_blood_volume = 600 // Maximum blood a Vamp can hold via feeding.
// OBJECTIVES
var/list/datum/objective/objectives_given = list() // For removal if needed.
var/area/lair
var/obj/structure/closet/crate/coffin
// TRACKING
var/foodInGut = 0 // How much food to throw up later. You shouldn't have eaten that.
var/warn_sun_locker = FALSE // So we only get the locker burn message once per day.
var/warn_sun_burn = FALSE // So we only get the sun burn message once per day.
var/had_toxlover = FALSE
var/foodInGut // How much food to throw up later. You shouldn't have eaten that.
var/warn_sun_locker // So we only get the locker burn message once per day.
var/warn_sun_burn // So we only get the sun burn message once per day.
var/had_toxlover
var/level_bloodcost
var/passive_blood_drain = -0.1 //The amount of blood we loose each bloodsucker life() tick
// 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)
// NOTES: TRAIT_AGEUSIA <-- Doesn't like flavors.
// REMOVED: TRAIT_NODEATH
// TO ADD:
//var/static/list/defaultOrgans = list (/obj/item/organ/heart/vampheart,/obj/item/organ/heart/vampeyes)
/datum/antagonist/bloodsucker/on_gain()
SSticker.mode.bloodsuckers |= owner // Add if not already in here (and you might be, if you were picked at round start)
SSticker.mode.check_start_sunlight()// Start Sunlight? (if first Vamp)
SelectFirstName()// Name & Title
SelectTitle(am_fledgling=TRUE) // If I have a creator, then set as Fledgling.
SelectReputation(am_fledgling=TRUE)
SelectTitle(am_fledgling = TRUE) // If I have a creator, then set as Fledgling.
SelectReputation(am_fledgling = TRUE)
AssignStarterPowersAndStats()// Give Powers & Stats
forge_bloodsucker_objectives()// Objectives & Team
update_bloodsucker_icons_added(owner.current, "bloodsucker") // Add Antag HUD
@@ -68,18 +66,18 @@
/datum/antagonist/bloodsucker/greet()
var/fullname = ReturnFullName(TRUE)
to_chat(owner, "<span class='userdanger'>You are [fullname], a bloodsucking vampire!</span><br>")
to_chat(owner, "<span class='userdanger'>You are [fullname], a strain of vampire dubbed bloodsucker!</span><br>")
owner.announce_objectives()
to_chat(owner, "<span class='boldannounce'>* You regenerate your health slowly, you're weak to fire, and you depend on blood to survive. Allow your stolen blood to run too low, and you will find yourself at \
risk of being discovered!</span><br>")
//to_chat(owner, "<span class='boldannounce'>As an immortal, your power is linked to your age. The older you grow, the more abilities you will have access to.<span>")
var/vamp_greet
vamp_greet += "<span class='boldannounce'>* Other Bloodsuckers are not necessarily your friends, but your survival may depend on cooperation. Betray them at your own discretion and peril.</span><br>"
vamp_greet += "<span class='boldannounce'><i>* Use \",b\" to speak your ancient Bloodsucker language.</span><br>"
vamp_greet += "<span class='announce'>Bloodsucker Tip: Rest in a <i>Coffin</i> to claim it, and that area, as your lair.</span><br>"
vamp_greet += "<span class='announce'>Bloodsucker Tip: Fear the daylight! Solar flares will bombard the station periodically, and only your coffin can guarantee your safety.</span><br>"
vamp_greet += "<span class='announce'>Bloodsucker Tip: You wont loose blood if you are unconcious or sleeping. Use this to your advantage to conserve blood.</span><br>"
to_chat(owner, vamp_greet)
var/bloodsucker_greet
bloodsucker_greet += "<span class='boldannounce'>* Other Bloodsuckers are not necessarily your friends, but your survival may depend on cooperation. Betray them at your own discretion and peril.</span><br>"
bloodsucker_greet += "<span class='boldannounce'><i>* Use \",b\" to speak your ancient Bloodsucker language.</span><br>"
bloodsucker_greet += "<span class='announce'>Bloodsucker Tip: Rest in a <i>Coffin</i> to claim it, and that area, as your lair.</span><br>"
bloodsucker_greet += "<span class='announce'>Bloodsucker Tip: Fear the daylight! Solar flares will bombard the station periodically, and only your coffin can guarantee your safety.</span><br>"
bloodsucker_greet += "<span class='announce'>Bloodsucker Tip: You wont loose blood if you are unconcious or sleeping. Use this to your advantage to conserve blood.</span><br>"
to_chat(owner, bloodsucker_greet)
owner.current.playsound_local(null, 'sound/bloodsucker/BloodsuckerAlert.ogg', 100, FALSE, pressure_affected = FALSE)
antag_memory += "Although you were born a mortal, in un-death you earned the name <b>[fullname]</b>.<br>"
@@ -92,13 +90,13 @@
owner.current.blood_volume = max(owner.current.blood_volume,BLOOD_VOLUME_SAFE)
/datum/antagonist/bloodsucker/threat()
return ..()+3*vamplevel
return ..() + 3 * bloodsucker_level
/datum/antagonist/bloodsucker/proc/SelectFirstName()
// Names (EVERYONE gets one))
if(owner.current.gender == MALE)
vampname = pick("Desmond","Rudolph","Dracul","Vlad","Pyotr","Gregor","Cristian","Christoff","Marcu","Andrei","Constantin","Gheorghe","Grigore","Ilie","Iacob","Luca","Mihail","Pavel","Vasile","Octavian","Sorin", \
bloodsucker_name = pick("Desmond","Rudolph","Dracul","Vlad","Pyotr","Gregor","Cristian","Christoff","Marcu","Andrei","Constantin","Gheorghe","Grigore","Ilie","Iacob","Luca","Mihail","Pavel","Vasile","Octavian","Sorin", \
"Sveyn","Aurel","Alexe","Iustin","Theodor","Dimitrie","Octav","Damien","Magnus","Caine","Abel", // Romanian/Ancient
"Lucius","Gaius","Otho","Balbinus","Arcadius","Romanos","Alexios","Vitellius", // Latin
"Melanthus","Teuthras","Orchamus","Amyntor","Axion", // Greek
@@ -106,7 +104,7 @@
"Dio")
else
vampname = pick("Islana","Tyrra","Greganna","Pytra","Hilda","Andra","Crina","Viorela","Viorica","Anemona","Camelia","Narcisa","Sorina","Alessia","Sophia","Gladda","Arcana","Morgan","Lasarra","Ioana","Elena", \
bloodsucker_name = pick("Islana","Tyrra","Greganna","Pytra","Hilda","Andra","Crina","Viorela","Viorica","Anemona","Camelia","Narcisa","Sorina","Alessia","Sophia","Gladda","Arcana","Morgan","Lasarra","Ioana","Elena", \
"Alina","Rodica","Teodora","Denisa","Mihaela","Svetla","Stefania","Diyana","Kelssa","Lilith", // Romanian/Ancient
"Alexia","Athanasia","Callista","Karena","Nephele","Scylla","Ursa", // Latin
"Alcestis","Damaris","Elisavet","Khthonia","Teodora", // Greek
@@ -114,57 +112,57 @@
/datum/antagonist/bloodsucker/proc/SelectTitle(am_fledgling = 0, forced = FALSE)
// Already have Title
if (!forced && vamptitle != null)
if(!forced && bloodsucker_title != null)
return
// Titles [Master]
if (!am_fledgling)
if(!am_fledgling)
if(owner.current.gender == MALE)
vamptitle = pick ("Count","Baron","Viscount","Prince","Duke","Tzar","Dreadlord","Lord","Master")
bloodsucker_title = pick ("Count","Baron","Viscount","Prince","Duke","Tzar","Dreadlord","Lord","Master")
else
vamptitle = pick ("Countess","Baroness","Viscountess","Princess","Duchess","Tzarina","Dreadlady","Lady","Mistress")
bloodsucker_title = pick ("Countess","Baroness","Viscountess","Princess","Duchess","Tzarina","Dreadlady","Lady","Mistress")
to_chat(owner, "<span class='announce'>You have earned a title! You are now known as <i>[ReturnFullName(TRUE)]</i>!</span>")
// Titles [Fledgling]
else
vamptitle = null
bloodsucker_title = null
/datum/antagonist/bloodsucker/proc/SelectReputation(am_fledgling = 0, forced=FALSE)
// Already have Reputation
if(!forced && vampreputation != null)
if(!forced && bloodsucker_reputation != null)
return
// Reputations [Master]
if(!am_fledgling)
vampreputation = pick("Butcher","Blood Fiend","Crimson","Red","Black","Terror","Nightman","Feared","Ravenous","Fiend","Malevolent","Wicked","Ancient","Plaguebringer","Sinister","Forgotten","Wretched","Baleful", \
bloodsucker_reputation = pick("Butcher","Blood Fiend","Crimson","Red","Black","Terror","Nightman","Feared","Ravenous","Fiend","Malevolent","Wicked","Ancient","Plaguebringer","Sinister","Forgotten","Wretched","Baleful", \
"Inqisitor","Harvester","Reviled","Robust","Betrayer","Destructor","Damned","Accursed","Terrible","Vicious","Profane","Vile","Depraved","Foul","Slayer","Manslayer","Sovereign","Slaughterer", \
"Forsaken","Mad","Dragon","Savage","Villainous","Nefarious","Inquisitor","Marauder","Horrible","Immortal","Undying","Overlord","Corrupt","Hellspawn","Tyrant","Sanguineous")
if(owner.current.gender == MALE)
if(prob(10)) // Gender override
vampreputation = pick("King of the Damned", "Blood King", "Emperor of Blades", "Sinlord", "God-King")
bloodsucker_reputation = pick("King of the Damned", "Blood King", "Emperor of Blades", "Sinlord", "God-King")
else
if(prob(10)) // Gender override
vampreputation = pick("Queen of the Damned", "Blood Queen", "Empress of Blades", "Sinlady", "God-Queen")
bloodsucker_reputation = pick("Queen of the Damned", "Blood Queen", "Empress of Blades", "Sinlady", "God-Queen")
to_chat(owner, "<span class='announce'>You have earned a reputation! You are now known as <i>[ReturnFullName(TRUE)]</i>!</span>")
// Reputations [Fledgling]
else
vampreputation = pick ("Crude","Callow","Unlearned","Neophyte","Novice","Unseasoned","Fledgling","Young","Neonate","Scrapling","Untested","Unproven","Unknown","Newly Risen","Born","Scavenger","Unknowing",\
bloodsucker_reputation = pick ("Crude","Callow","Unlearned","Neophyte","Novice","Unseasoned","Fledgling","Young","Neonate","Scrapling","Untested","Unproven","Unknown","Newly Risen","Born","Scavenger","Unknowing",\
"Unspoiled","Disgraced","Defrocked","Shamed","Meek","Timid","Broken")//,"Fresh")
/datum/antagonist/bloodsucker/proc/AmFledgling()
return !vamptitle
return !bloodsucker_title
/datum/antagonist/bloodsucker/proc/ReturnFullName(var/include_rep=0)
var/fullname
// Name First
fullname = (vampname ? vampname : owner.current.name)
fullname = (bloodsucker_name ? bloodsucker_name : owner.current.name)
// Title
if(vamptitle)
fullname = vamptitle + " " + fullname
if(bloodsucker_title)
fullname = bloodsucker_title + " " + fullname
// Rep
if(include_rep && vampreputation)
fullname = fullname + " the " + vampreputation
if(include_rep && bloodsucker_reputation)
fullname = fullname + " the " + bloodsucker_reputation
return fullname
@@ -199,15 +197,12 @@
var/mob/living/carbon/human/H = owner.current
var/datum/species/S = H.dna.species
// Make Changes
H.physiology.brute_mod *= 0.8 // <-------------------- Start small, but burn mod increases based on rank!
H.physiology.brute_mod *= 0.8
H.physiology.cold_mod = 0
H.physiology.stun_mod *= 0.5
H.physiology.siemens_coeff *= 0.75 //base electrocution coefficient 1
//S.heatmod += 0.5 // Heat shouldn't affect. Only Fire.
//S.punchstunthreshold = 8 //damage at which punches from this race will stun 9
S.punchdamagelow += 1 //lowest possible punch damage 0
S.punchdamagehigh += 1 //highest possible punch damage 9
// Clown
if(istype(H) && owner.assigned_role == "Clown")
H.dna.remove_mutation(CLOWNMUT)
to_chat(H, "As a vampiric clown, you are no longer a danger to yourself. Your nature is subdued.")
@@ -215,8 +210,6 @@
CheckVampOrgans() // Heart, Eyes
// Language
owner.current.grant_language(/datum/language/vampiric)
// Soul
//owner.current.hellbound = TRUE Causes wierd stuff
owner.hasSoul = FALSE // If false, renders the character unable to sell their soul.
owner.isholy = FALSE // is this person a chaplain or admin role allowed to use bibles
// Disabilities
@@ -248,7 +241,6 @@
// Clown
if(istype(H) && owner.assigned_role == "Clown")
H.dna.add_mutation(CLOWNMUT)
// NOTE: Use initial() to return things to default!
// Physiology
owner.current.regenerate_organs()
// Update Health
@@ -264,13 +256,13 @@
set waitfor = FALSE
if(!owner || !owner.current)
return
vamplevel_unspent ++
bloodsucker_level_unspent ++
// Spend Rank Immediately?
if(istype(owner.current.loc, /obj/structure/closet/crate/coffin))
SpendRank()
else
to_chat(owner, "<EM><span class='notice'>You have grown more ancient! Sleep in a coffin that you have claimed to thicken your blood and become more powerful.</span></EM>")
if(vamplevel_unspent >= 2)
if(bloodsucker_level_unspent >= 2)
to_chat(owner, "<span class='announce'>Bloodsucker Tip: If you cannot find or steal a coffin to use, you can build one from wooden planks.</span><br>")
/datum/antagonist/bloodsucker/proc/LevelUpPowers()
@@ -279,10 +271,10 @@
/datum/antagonist/bloodsucker/proc/SpendRank()
set waitfor = FALSE
if(vamplevel_unspent <= 0 || !owner || !owner.current || !owner.current.client || !isliving(owner.current))
if(bloodsucker_level_unspent <= 0 || !owner || !owner.current || !owner.current.client || !isliving(owner.current))
return
var/mob/living/L = owner.current
level_bloodcost = maxBloodVolume * 0.2
level_bloodcost = max_blood_volume * 0.2
//If the blood volume of the bloodsucker is lower than the cost to level up, return and inform the bloodsucker
//TODO: Make this into a radial, or perhaps a tgui next UI
@@ -298,7 +290,7 @@
if(options.len > 1)
var/choice = input(owner.current, "You have the opportunity to grow more ancient at the cost of [level_bloodcost] units of blood. Select a power to advance your Rank.", "Your Blood Thickens...") in options
// Cheat-Safety: Can't keep opening/closing coffin to spam levels
if(vamplevel_unspent <= 0) // Already spent all your points, and tried opening/closing your coffin, pal.
if(bloodsucker_level_unspent <= 0) // Already spent all your points, and tried opening/closing your coffin, pal.
return
if(!istype(owner.current.loc, /obj/structure/closet/crate/coffin))
to_chat(owner.current, "<span class='warning'>Return to your coffin to advance your Rank.</span>")
@@ -329,20 +321,20 @@
// More Health
owner.current.setMaxHealth(owner.current.maxHealth + 10)
// Vamp Stats
regenRate += 0.05 // Points of brute healed (starts at 0.3)
feedAmount += 2 // Increase how quickly I munch down vics (15)
maxBloodVolume += 100 // Increase my max blood (600)
regen_rate += 0.05 // Points of brute healed (starts at 0.3)
feed_amount += 2 // Increase how quickly I munch down vics (15)
max_blood_volume += 100 // Increase my max blood (600)
/////////
vamplevel ++
vamplevel_unspent --
bloodsucker_level ++
bloodsucker_level_unspent --
// Assign True Reputation
if(vamplevel == 4)
if(bloodsucker_level == 4)
SelectReputation(am_fledgling = FALSE, forced = TRUE)
to_chat(owner.current, "<span class='notice'>You are now a rank [vamplevel] Bloodsucker. Your strength, health, feed rate, regen rate, and maximum blood have all increased!</span>")
to_chat(owner.current, "<span class='notice'>You are now a rank [bloodsucker_level] Bloodsucker. Your strength, health, feed rate, regen rate, can have up to [bloodsucker_level - count_vassals(owner.current.mind)] vassals, and maximum blood have all increased!</span>")
to_chat(owner.current, "<span class='notice'>Your existing powers have all ranked up as well!</span>")
update_hud(TRUE)
owner.current.playsound_local(null, 'sound/effects/pope_entry.ogg', 25, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
owner.current.playsound_local(null, 'sound/effects/pope_entry.ogg', 25, TRUE, pressure_affected = FALSE)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -654,13 +646,13 @@
var/datum/antagonist/vassal/mob_V = M.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
// Check 2) If they are a BLOODSUCKER, then are they my Master?
if (mob_V && atom_B == mob_V.master)
return TRUE // SUCCESS!
return TRUE
// Check 3) If I am a BLOODSUCKER, then are they my Vassal?
if (mob_B && atom_V && (atom_V in mob_B.vassals))
return TRUE // SUCCESS!
return TRUE
// Check 4) If we are both VASSAL, then do we have the same master?
if (atom_V && mob_V && atom_V.master == mob_V.master)
return TRUE // SUCCESS!
return TRUE
return FALSE
@@ -705,10 +697,10 @@
// Update Rank Counter
if(owner.current.hud_used.vamprank_display)
var/valuecolor = vamplevel_unspent ? "#FFFF00" : "#FF0000"
owner.current.hud_used.vamprank_display.update_counter(vamplevel, valuecolor)
var/valuecolor = bloodsucker_level_unspent ? "#FFFF00" : "#FF0000"
owner.current.hud_used.vamprank_display.update_counter(bloodsucker_level, valuecolor)
if(updateRank) // Only change icon on special request.
owner.current.hud_used.vamprank_display.icon_state = (vamplevel_unspent > 0) ? "rank_up" : "rank"
owner.current.hud_used.vamprank_display.icon_state = (bloodsucker_level_unspent > 0) ? "rank_up" : "rank"
/obj/screen/bloodsucker
@@ -718,12 +710,12 @@
invisibility = INVISIBILITY_ABSTRACT
/obj/screen/bloodsucker/proc/update_counter(value, valuecolor)
invisibility = 0 // Make Visible
invisibility = 0
/obj/screen/bloodsucker/blood_counter // NOTE: Look up /obj/screen/devil/soul_counter in _onclick / hud / human.dm
icon = 'icons/mob/actions/bloodsucker.dmi'//'icons/mob/screen_gen.dmi'
/obj/screen/bloodsucker/blood_counter
icon = 'icons/mob/actions/bloodsucker.dmi'
name = "Blood Consumed"
icon_state = "blood_display"//"power_display"
icon_state = "blood_display"
screen_loc = ui_blood_display
/obj/screen/bloodsucker/blood_counter/update_counter(value, valuecolor)
@@ -748,22 +740,27 @@
/datum/antagonist/bloodsucker/proc/update_sunlight(value, amDay = FALSE)
// No Hud? Get out.
if (!owner.current.hud_used)
if(!owner.current.hud_used)
return
// Update Sun Time
if (owner.current.hud_used.sunlight_display)
if(owner.current.hud_used.sunlight_display)
var/valuecolor = "#BBBBFF"
if (amDay)
if(amDay)
valuecolor = "#FF5555"
else if(value <= 25)
valuecolor = "#FFCCCC"
else if(value < 10)
valuecolor = "#FF5555"
var/value_string = (value >= 60) ? "[round(value / 60, 1)] m" : "[round(value,1)] s"
var/value_string = (value >= 60) ? "[round(value / 60, 1)] m" : "[round(value, 1)] s"
owner.current.hud_used.sunlight_display.update_counter( value_string, valuecolor )
owner.current.hud_used.sunlight_display.icon_state = "sunlight_" + (amDay ? "day":"night")
/obj/screen/bloodsucker/sunlight_counter/update_counter(value, valuecolor)
..()
maptext = "<div align='center' valign='bottom' style='position:relative; top:0px; left:6px'><font color='[valuecolor]'>[value]</font></div>"
maptext = "<div align='center' valign='bottom' style='position:relative; top:0px; left:6px'><font color='[valuecolor]'>[value]</font></div>"
/datum/antagonist/bloodsucker/proc/count_vassals(datum/mind/master)
var/datum/antagonist/bloodsucker/B = master.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
var/vassal_amount = B.vassals.len
return vassal_amount
@@ -5,7 +5,8 @@
var/obj/item/organ/O
// Heart
O = owner.current.getorganslot(ORGAN_SLOT_HEART)
if(!istype(O, /obj/item/organ/heart/vampheart))
if(!istype(O, /obj/item/organ/heart/vampheart) && !istype(O, /obj/item/organ/heart/demon))
qdel(O)
var/obj/item/organ/heart/vampheart/H = new
H.Insert(owner.current)
@@ -115,13 +115,15 @@
qdel(src)
/obj/structure/bloodsucker/vassalrack/examine(mob/user)
var/datum/antagonist/bloodsucker/B = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
. = ..()
if(isvamp(user) || isobserver(user))
if(B || isobserver(user))
. += {"<span class='cult'>This is the vassal rack, which allows you to thrall crewmembers into loyal minions in your service.</span>"}
. += {"<span class='cult'>You need to first secure the vassal rack by clicking on it while it is in your lair.</span>"}
. += {"<span class='cult'>Simply click and hold on a victim, and then drag their sprite on the vassal rack. Alt click on the vassal rack to unbuckle them.</span>"}
. += {"<span class='cult'>Make sure that the victim is handcuffed, or else they can simply run away or resist, as the process is not instant.</span>"}
. += {"<span class='cult'>To convert the victim, simply click on the vassal rack itself. Sharp weapons work faster than other tools.</span>"}
. += {"<span class='cult'> You have only the power for [B.bloodsucker_level - B.count_vassals(user.mind)] vassals</span>"}
/* if(user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
. += {"<span class='cult'>This is the vassal rack, which allows your master to thrall crewmembers into his minions.\n
Aid your master in bringing their victims here and keeping them secure.\n
@@ -130,7 +132,7 @@
/obj/structure/bloodsucker/vassalrack/MouseDrop_T(atom/movable/O, mob/user)
if(!O.Adjacent(src) || O == user || !isliving(O) || !isliving(user) || useLock || has_buckled_mobs() || user.incapacitated())
return
if(!anchored && isvamp(user))
if(!anchored && AmBloodsucker(user))
to_chat(user, "<span class='danger'>Until this rack is secured in place, it cannot serve its purpose.</span>")
return
// PULL TARGET: Remember if I was pullin this guy, so we can restore this
@@ -183,7 +185,7 @@
/obj/structure/bloodsucker/vassalrack/user_unbuckle_mob(mob/living/M, mob/user)
// Attempt Unbuckle
if(!isvamp(user))
if(!AmBloodsucker(user))
if(M == user)
M.visible_message("<span class='danger'>[user] tries to release themself from the rack!</span>",\
"<span class='danger'>You attempt to release yourself from the rack!</span>") // For sound if not seen --> "<span class='italics'>You hear a squishy wet noise.</span>")
@@ -222,15 +224,15 @@
// Go away. Torturing.
if(useLock)
return
var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
var/datum/antagonist/bloodsucker/B = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
// CHECK ONE: Am I claiming this? Is it in the right place?
if(istype(bloodsuckerdatum) && !owner)
if(!bloodsuckerdatum.lair)
if(istype(B) && !owner)
if(!B.lair)
to_chat(user, "<span class='danger'>You don't have a lair. Claim a coffin to make that location your lair.</span>")
if(bloodsuckerdatum.lair != get_area(src))
to_chat(user, "<span class='danger'>You may only activate this structure in your lair: [bloodsuckerdatum.lair].</span>")
if(B.lair != get_area(src))
to_chat(user, "<span class='danger'>You may only activate this structure in your lair: [B.lair].</span>")
return
switch(alert(user,"Do you wish to afix this structure here? Be aware you wont be able to unsecure it anymore","Secure [src]","Yes", "No"))
switch(alert(user,"Do you wish to afix this structure here? Be aware you wont be able to unsecure it anymore", "Secure [src]", "Yes", "No"))
if("Yes")
owner = user
density = FALSE
@@ -241,27 +243,31 @@
return
// CHECK TWO: Am I a non-bloodsucker?
var/mob/living/carbon/C = pick(buckled_mobs)
if(!istype(bloodsuckerdatum))
if(!istype(B))
// Try to release this guy
user_unbuckle_mob(C, user)
return
// Bloodsucker Owner! Let the boy go.
if(C.mind)
var/datum/antagonist/vassal/vassaldatum = C.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if(istype(vassaldatum) && vassaldatum.master == bloodsuckerdatum || C.stat >= DEAD)
var/datum/antagonist/vassal/V = C.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if(istype(V) && V.master == B || C.stat >= DEAD)
unbuckle_mob(C)
useLock = FALSE // Failsafe
return
// Just torture the boy
torture_victim(user, C)
#define CONVERT_COST 150
/obj/structure/bloodsucker/vassalrack/proc/torture_victim(mob/living/user, mob/living/target)
var/datum/antagonist/bloodsucker/bloodsuckerdatum = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
var/datum/antagonist/bloodsucker/B = user.mind.has_antag_datum(ANTAG_DATUM_BLOODSUCKER)
// Check Bloodmob/living/M, force = FALSE, check_loc = TRUE
var/convert_cost = 200 + 200 * bloodsuckerdatum.vassals
if(user.blood_volume < convert_cost + 5)
if(user.blood_volume < CONVERT_COST + 5)
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target].</span>")
return
if(B.count_vassals(user.mind) > B.bloodsucker_level)
to_chat(user, "<span class='notice'>Your power is yet too weak to bring more vassals under your control....</span>")
return
// Prep...
useLock = TRUE
// Step One: Tick Down Conversion from 3 to 0
@@ -302,12 +308,13 @@
useLock = FALSE
return
// Check: Blood
if(user.blood_volume < convert_cost)
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target], you need [convert_cost - user.blood_volume] units more!</span>")
if(user.blood_volume < CONVERT_COST)
to_chat(user, "<span class='notice'>You don't have enough blood to initiate the Dark Communion with [target], you need [CONVERT_COST - user.blood_volume] units more!</span>")
useLock = FALSE
return
bloodsuckerdatum.AddBloodVolume(-convert_cost)
target.add_mob_blood(user)
B.AddBloodVolume(-CONVERT_COST)
target.add_mob_blood(user, "<span class='danger'>Youve used [CONVERT_COST] amount of blood to gain a new vassal!</span>")
to_chat(user, )
user.visible_message("<span class='notice'>[user] marks a bloody smear on [target]'s forehead and puts a wrist up to [target.p_their()] mouth!</span>", \
"<span class='notice'>You paint a bloody marking across [target]'s forehead, place your wrist to [target.p_their()] mouth, and subject [target.p_them()] to the Dark Communion.</span>")
if(!do_mob(user, src, 50))
@@ -315,21 +322,22 @@
useLock = FALSE
return
// Convert to Vassal!
if(bloodsuckerdatum && bloodsuckerdatum.attempt_turn_vassal(target))
if(B && B.attempt_turn_vassal(target))
//remove_loyalties(target) // In case of Mindshield, or appropriate Antag (Traitor, Internal, etc)
//if (!target.buckled)
// to_chat(user, "<span class='danger'><i>The ritual has been interrupted!</i></span>")
// useLock = FALSE
// return
user.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
target.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
user.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, TRUE)
target.playsound_local(null, 'sound/effects/explosion_distant.ogg', 40, TRUE)
target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE)
target.Jitter(25)
target.emote("laugh")
//remove_victim(target) // Remove on CLICK ONLY!
useLock = FALSE
/obj/structure/bloodsucker/vassalrack/proc/do_torture(mob/living/user, mob/living/target, mult=1)
#undef CONVERT_COST
/obj/structure/bloodsucker/vassalrack/proc/do_torture(mob/living/user, mob/living/target, mult = 1)
var/torture_time = 15 // Fifteen seconds if you aren't using anything. Shorter with weapons and such.
var/torture_dmg_brute = 2
var/torture_dmg_burn = 0
@@ -454,7 +462,7 @@
/obj/structure/bloodsucker/candelabrum/examine(mob/user)
. = ..()
if((isvamp()) || isobserver(user))
if((AmBloodsucker(user)) || isobserver(user))
. += {"<span class='cult'>This is a magical candle which drains at the sanity of mortals who are not under your command while it is active.</span>"}
. += {"<span class='cult'>You can alt click on it from any range to turn it on remotely, or simply be next to it and click on it to turn it on and off normally.</span>"}
/* if(user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
@@ -463,12 +471,12 @@
/obj/structure/bloodsucker/candelabrum/attack_hand(mob/user)
var/datum/antagonist/vassal/T = user.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if(isvamp(user) || istype(T))
if(AmBloodsucker(user) || istype(T))
toggle()
/obj/structure/bloodsucker/candelabrum/AltClick(mob/user)
// Bloodsuckers can turn their candles on from a distance. SPOOOOKY.
if(isvamp(user))
if(AmBloodsucker(user))
toggle()
/obj/structure/bloodsucker/candelabrum/proc/toggle(mob/user)
@@ -485,7 +493,7 @@
if(lit)
for(var/mob/living/carbon/human/H in viewers(7, src))
var/datum/antagonist/vassal/T = H.mind.has_antag_datum(ANTAG_DATUM_VASSAL)
if(isvamp(H) || T) //We dont want vassals or vampires affected by this
if(AmBloodsucker(H) || T) //We dont want vassals or vampires affected by this
return
H.hallucination = 20
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "vampcandle", /datum/mood_event/vampcandle)
@@ -2,7 +2,7 @@
/datum/action/bloodsucker/cloak
name = "Cloak of Darkness"
desc = "Blend into the shadows and become invisible to the untrained eye. Movement is slowed in brightly lit areas."
desc = "Blend into the shadows and become invisible to the untrained eye. Movement is slowed in brightly lit areas, and you cannot dissapear while mortals watch you."
button_icon_state = "power_cloak"
bloodcost = 5
cooldown = 50
@@ -140,7 +140,7 @@
to_chat(user, "<span class='notice'>You lean quietly toward [target] and secretly draw out your fangs...</span>")
else
to_chat(user, "<span class='warning'>You pull [target] close to you and draw out your fangs...</span>")
if(!do_mob(user, target, feed_time,0,1,extra_checks=CALLBACK(src, .proc/ContinueActive, user, target)))//sleep(10)
if(!do_mob(user, target, feed_time, 0, 1, extra_checks = CALLBACK(src, .proc/ContinueActive, user, target)))//sleep(10)
to_chat(user, "<span class='warning'>Your feeding was interrupted.</span>")
//DeactivatePower(user,target)
return
@@ -166,7 +166,7 @@
var/deadmessage = target.stat == DEAD ? "" : " <i>[target.p_they(TRUE)] looks dazed, and will not remember this.</i>"
user.visible_message("<span class='notice'>[user] puts [target]'s wrist up to [user.p_their()] mouth.</span>", \
"<span class='notice'>You secretly slip your fangs into [target]'s wrist.[deadmessage]</span>", \
vision_distance = notice_range, ignored_mobs=target) // Only people who AREN'T the target will notice this action.
vision_distance = notice_range, ignored_mobs = target) // Only people who AREN'T the target will notice this action.
// Warn Feeder about Witnesses...
var/was_unnoticed = TRUE
for(var/mob/living/M in viewers(notice_range, owner))
@@ -257,11 +257,11 @@
to_chat(user, "<span class='notice'>Your victim is dead. [target.p_their(TRUE)] blood barely nourishes you.</span>")
warning_target_dead = TRUE
// Full?
if(!warning_full && user.blood_volume >= bloodsuckerdatum.maxBloodVolume)
if(!warning_full && user.blood_volume >= bloodsuckerdatum.max_blood_volume)
to_chat(user, "<span class='notice'>You are full. Further blood will be wasted.</span>")
warning_full = TRUE
// Blood Remaining? (Carbons/Humans only)
if(iscarbon(target) && !target.AmBloodsucker(1))
if(iscarbon(target) && !AmBloodsucker(target, TRUE))
if(target.blood_volume <= BLOOD_VOLUME_BAD && warning_target_bloodvol > BLOOD_VOLUME_BAD)
to_chat(user, "<span class='warning'>Your victim's blood volume is fatally low!</span>")
else if(target.blood_volume <= BLOOD_VOLUME_OKAY && warning_target_bloodvol > BLOOD_VOLUME_OKAY)
@@ -275,8 +275,9 @@
break
// Blood Gulp Sound
owner.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, 1) // Play THIS sound for user only. The "null" is where turf would go if a location was needed. Null puts it right in their head.
owner.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE)
if(!amSilent)
target.playsound_local(null, 'sound/effects/singlebeat.ogg', 40, TRUE)
// DONE!
//DeactivatePower(user,target)
if(amSilent)
@@ -294,12 +295,12 @@
/datum/action/bloodsucker/feed/proc/CheckKilledTarget(mob/living/user, mob/living/target)
// Bad Vampire. You shouldn't do that.
// Bad Bloodsucker. You shouldn't do that.
if(target && target.stat >= DEAD && ishuman(target))
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "drankkilled", /datum/mood_event/drankkilled) // BAD // in bloodsucker_life.dm
/datum/action/bloodsucker/feed/ContinueActive(mob/living/user, mob/living/target)
return ..() && target && (!target_grappled || user.pulling == target)// Active, and still Antag,
return ..() && target && (!target_grappled || user.pulling == target) && blood_sucking_checks(target, TRUE, TRUE) // Active, and still antag,
// NOTE: We only care about pulling if target started off that way. Mostly only important for Aggressive feed.
/datum/action/bloodsucker/feed/proc/ApplyVictimEffects(mob/living/target)
@@ -33,6 +33,15 @@
if(was_running)
user.toggle_move_intent()
while(bloodsuckerdatum && ContinueActive(user) || user.m_intent == MOVE_INTENT_RUN)
if(istype(user.buckled, /obj/vehicle)) //We dont want people using fortitude being able to use vehicles
var/obj/vehicle/V = user.buckled
var/datum/component/riding/VRD = V.GetComponent(/datum/component/riding)
if(VRD)
VRD.force_dismount(user)
to_chat(user, "<span class='notice'>You trip off the [V], your muscles too heavy for it to support you.</span>")
else
V.unbuckle_mob(user, force = TRUE)
to_chat(user, "<span class='notice'>You fall off the [V], your weight making you too heavy to be supported by it.</span>")
// Pay Blood Toll (if awake)
if(user.stat == CONSCIOUS)
bloodsuckerdatum.AddBloodVolume(-0.5) // Used to be 0.3 blood per 2 seconds, but we're making it more expensive to keep on.
@@ -8,7 +8,7 @@
desc = "Dash somewhere with supernatural speed. Those nearby may be knocked away, stunned, or left empty-handed."
button_icon_state = "power_speed"
bloodcost = 6
cooldown = 50
cooldown = 120
target_range = 15
power_activates_immediately = TRUE
message_Trigger = ""//"Whom will you subvert to your will?"
@@ -64,7 +64,7 @@
to_chat(owner, "<span class='warning'>Your victim's eyes are glazed over. They cannot perceive you.</span>")
return FALSE
// Check: Target See Me? (behind wall)
if(!(target in view(target_range, get_turf(owner))))
if(!(target in viewers(target_range, get_turf(owner))))
// Sub-Check: GET CLOSER
//if (!(owner in range(target_range, get_turf(target)))
// if (display_error)
@@ -90,48 +90,56 @@
/datum/action/bloodsucker/targeted/mesmerize/proc/ContinueTarget(atom/A)
var/mob/living/carbon/target = A
var/mob/living/user = owner
var/mob/living/L = owner
var/cancontinue=CheckCanTarget(target)
var/cancontinue = CheckCanTarget(target)
if(!cancontinue)
success = FALSE
target.remove_status_effect(STATUS_EFFECT_MESMERIZE)
user.remove_status_effect(STATUS_EFFECT_MESMERIZE)
L.remove_status_effect(STATUS_EFFECT_MESMERIZE)
DeactivatePower()
DeactivateRangedAbility()
StartCooldown()
to_chat(user, "<span class='warning'>[target] has escaped your gaze!</span>")
to_chat(L, "<span class='warning'>[target] has escaped your gaze!</span>")
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
/datum/action/bloodsucker/targeted/mesmerize/FireTargetedPower(atom/A)
// set waitfor = FALSE <---- DONT DO THIS!We WANT this power to hold up ClickWithPower(), so that we can unlock the power when it's done.
var/mob/living/carbon/target = A
var/mob/living/user = owner
var/mob/living/L = owner
L.face_atom(A)
if(!istype(target))
return
success = TRUE
var/power_time = 138 + level_current * 12
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
L.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/ContinueTarget)
// 5 second windup
addtimer(CALLBACK(src, .proc/apply_effects, L, target, power_time), 6 SECONDS)
ADD_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src)
ADD_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src)
if(istype(target))
success = TRUE
var/power_time = 138 + level_current * 12
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
user.apply_status_effect(STATUS_EFFECT_MESMERIZE, 30)
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/ContinueTarget)
/datum/action/bloodsucker/targeted/mesmerize/proc/apply_effects(aggressor, victim, power_time)
var/mob/living/carbon/target = victim
var/mob/living/L = aggressor
if(!success)
return
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time)
REMOVE_TRAIT(L, TRAIT_COMBAT_MODE_LOCKED, src)
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.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
spawn(power_time)
if(istype(target) && success)
target.notransform = FALSE
REMOVE_TRAIT(target, TRAIT_COMBAT_MODE_LOCKED, src)
if(istype(L) && target.stat == CONSCIOUS && (target in view(10, get_turf(L)))) // They Woke Up! (Notice if within view)
to_chat(L, "<span class='warning'>[target] has snapped out of their trance.</span>")
// 3 second windup
sleep(30)
if(success)
PowerActivatedSuccessfully() // blood & cooldown only altered if power activated successfully - less "fuck you"-y
target.face_atom(user)
target.apply_status_effect(STATUS_EFFECT_MESMERIZE, power_time) // pretty much purely cosmetic
target.Stun(power_time)
to_chat(user, "<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.notransform = TRUE // <--- Fuck it. We tried using next_move, but they could STILL resist. We're just doing a hard freeze.
spawn(power_time)
if(istype(target) && success)
target.notransform = FALSE
// They Woke Up! (Notice if within view)
if(istype(user) && target.stat == CONSCIOUS && (target in view(10, get_turf(user))) )
to_chat(user, "<span class='warning'>[target] has snapped out of their trance.</span>")
/datum/action/bloodsucker/targeted/mesmerize/ContinueActive(mob/living/user, mob/living/target)
return ..() && CheckCanUse() && CheckCanTarget(target)
@@ -82,6 +82,7 @@
// Change Appearance, not randomizing clothes colour, itll just be janky
H.gender = pick(MALE, FEMALE)
H.dna.skin_tone_override = null
H.skin_tone = random_skin_tone()
H.hair_style = random_hair_style(H.gender)
H.facial_hair_style = pick(random_facial_hair_style(H.gender),"Shaved")
@@ -124,6 +125,8 @@
// Revert Appearance
H.gender = prev_gender
H.skin_tone = prev_skin_tone
if(!GLOB.skin_tones[H.skin_tone])
H.dna.skin_tone_override = H.skin_tone
H.hair_style = prev_hair_style
H.facial_hair_style = prev_facial_hair_style
H.hair_color = prev_hair_color
@@ -31,6 +31,7 @@
var/isabsorbing = 0
var/islinking = 0
var/geneticpoints = 10
var/maxgeneticpoints = 10
var/purchasedpowers = list()
var/mimicing = ""
var/canrespec = 0
@@ -98,17 +99,24 @@
to_chat(H, "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
/datum/antagonist/changeling/proc/reset_properties()
/datum/antagonist/changeling/proc/reset_properties(hardReset = FALSE)
changeling_speak = 0
chosen_sting = null
geneticpoints = initial(geneticpoints)
geneticpoints = maxgeneticpoints
sting_range = initial(sting_range)
chem_storage = initial(chem_storage)
chem_recharge_rate = initial(chem_recharge_rate)
chem_charges = min(chem_charges, chem_storage)
chem_recharge_slowdown = initial(chem_recharge_slowdown)
mimicing = ""
if (hardReset)
chem_storage = initial(chem_storage)
chem_recharge_rate = initial(chem_recharge_rate)
geneticpoints = initial(geneticpoints)
maxgeneticpoints = initial(maxgeneticpoints)
chem_charges = min(chem_charges, chem_storage)
/datum/antagonist/changeling/proc/remove_changeling_powers()
if(ishuman(owner.current) || ismonkey(owner.current))
reset_properties()
@@ -287,7 +295,6 @@
prof.name_list[slot] = I.name
prof.appearance_list[slot] = I.appearance
prof.flags_cover_list[slot] = I.flags_cover
prof.item_color_list[slot] = I.item_color
prof.item_state_list[slot] = I.item_state
prof.exists_list[slot] = 1
else
@@ -503,7 +510,6 @@
var/list/appearance_list = list()
var/list/flags_cover_list = list()
var/list/exists_list = list()
var/list/item_color_list = list()
var/list/item_state_list = list()
var/underwear
@@ -526,7 +532,6 @@
newprofile.appearance_list = appearance_list.Copy()
newprofile.flags_cover_list = flags_cover_list.Copy()
newprofile.exists_list = exists_list.Copy()
newprofile.item_color_list = item_color_list.Copy()
newprofile.item_state_list = item_state_list.Copy()
newprofile.underwear = underwear
newprofile.undershirt = undershirt
@@ -28,8 +28,7 @@
action.Remove(user)
return
/obj/effect/proc_holder/changeling/Click()
var/mob/user = usr
/obj/effect/proc_holder/changeling/Trigger(mob/user)
if(!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist/changeling))
return
try_to_sting(user)
@@ -96,6 +96,7 @@
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)
changeling.maxgeneticpoints += round(target_ling.geneticpoints/2)
target_ling.geneticpoints = 0
target_ling.canrespec = 0
changeling.chem_storage += round(target_ling.chem_storage/2)
@@ -441,23 +441,23 @@
var/remaining_uses //Set by the changeling ability.
/obj/item/shield/changeling/Initialize()
/obj/item/shield/changeling/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
if(ismob(loc))
loc.visible_message("<span class='warning'>The end of [loc.name]\'s hand inflates rapidly, forming a huge shield-like mass!</span>", "<span class='warning'>We inflate our hand into a strong shield.</span>", "<span class='italics'>You hear organic matter ripping and tearing!</span>")
/obj/item/shield/changeling/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(remaining_uses < 1)
/obj/item/shield/changeling/check_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
block_return[BLOCK_RETURN_BLOCK_CAPACITY] = (block_return[BLOCK_RETURN_BLOCK_CAPACITY] || 0) + remaining_uses
return ..()
/obj/item/shield/changeling/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
. = ..()
if(--remaining_uses < 1)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
H.visible_message("<span class='warning'>With a sickening crunch, [H] reforms [H.p_their()] shield into an arm!</span>", "<span class='notice'>We assimilate our shield into our body</span>", "<span class='italics>You hear organic matter ripping and tearing!</span>")
qdel(src)
return 0
else
remaining_uses--
return ..()
/***************************************\
|*********SPACE SUIT + HELMET***********|
@@ -489,6 +489,7 @@
clothing_flags = STOPSPRESSUREDAMAGE //Not THICKMATERIAL because it's organic tissue, so if somebody tries to inject something into it, it still ends up in your blood. (also balance but muh fluff)
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/oxygen)
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90) //No armor at all.
mutantrace_variation = NONE
/obj/item/clothing/suit/space/changeling/Initialize()
. = ..()
@@ -3,8 +3,7 @@
desc = "Stabby stabby."
var/sting_icon = null
/obj/effect/proc_holder/changeling/sting/Click()
var/mob/user = usr
/obj/effect/proc_holder/changeling/sting/Trigger(mob/user)
if(!user || !user.mind)
return
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
@@ -74,8 +73,7 @@
action_icon_state = "ling_sting_transform"
action_background_icon_state = "bg_ling"
/obj/effect/proc_holder/changeling/sting/transformation/Click()
var/mob/user = usr
/obj/effect/proc_holder/changeling/sting/transformation/Trigger(mob/user)
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.chosen_sting)
unset_sting(user)
@@ -279,9 +279,15 @@
sigil_name = "Vitality Matrix"
var/revive_cost = 150
var/sigil_active = FALSE
var/min_drain_health = -INFINITY
var/can_dust = TRUE
var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets
var/static/list/damage_heal_order = list(CLONE, TOX, BURN, BRUTE, OXY) //we heal damage in this order
/obj/effect/clockwork/sigil/vitality/neutered
min_drain_health = 20
can_dust = FALSE
/obj/effect/clockwork/sigil/vitality/examine(mob/user)
. = ..()
if(is_servant_of_ratvar(user) || isobserver(user))
@@ -306,7 +312,7 @@
animation_number++
if(!is_servant_of_ratvar(L))
var/vitality_drained = 0
if(L.stat == DEAD && !consumed_vitality)
if(L.stat == DEAD && !consumed_vitality && can_dust)
consumed_vitality = TRUE //Prevent the target from being consumed multiple times
vitality_drained = L.maxHealth
var/obj/effect/temp_visual/ratvar/sigil/vitality/V = new /obj/effect/temp_visual/ratvar/sigil/vitality(get_turf(src))
@@ -318,7 +324,7 @@
if(!L.dropItemToGround(W))
qdel(W)
L.dust()
else
else if(L.health > min_drain_health)
if(!GLOB.ratvar_awakens && L.stat == CONSCIOUS)
vitality_drained = L.adjustToxLoss(1, forced = TRUE)
else
@@ -35,7 +35,7 @@
var/span_for_name = "heavy_brass"
var/span_for_message = "brass"
/datum/action/innate/hierophant/IsAvailable()
/datum/action/innate/hierophant/IsAvailable(silent = FALSE)
if(!is_servant_of_ratvar(owner))
return FALSE
return ..()
@@ -12,7 +12,7 @@
var/obj/item/clockwork/weapon/weapon_type //The type of weapon to create
var/obj/item/clockwork/weapon/weapon
/datum/action/innate/call_weapon/IsAvailable()
/datum/action/innate/call_weapon/IsAvailable(silent = FALSE)
if(!is_servant_of_ratvar(owner))
qdel(src)
return
@@ -127,7 +127,6 @@
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "clockwork_gauntlets"
item_state = "clockwork_gauntlets"
item_color = null //So they don't wash.
strip_delay = 50
equip_delay_other = 30
body_parts_covered = ARMS
@@ -36,6 +36,24 @@
speed_multiplier = 0
no_cost = TRUE
/obj/item/clockwork/slab/traitor
var/spent = FALSE
/obj/item/clockwork/slab/traitor/check_uplink_validity()
return !spent
/obj/item/clockwork/slab/traitor/attack_self(mob/living/user)
if(!is_servant_of_ratvar(user) && !spent)
to_chat(user, "<span class='userdanger'>You press your hand onto [src], golden tendrils of light latching onto you. Was this the best of ideas?</span>")
if(add_servant_of_ratvar(user, FALSE, FALSE, /datum/antagonist/clockcult/neutered/traitor))
spent = TRUE
// Add some (5 KW) power so they don't suffer for 100 ticks
GLOB.clockwork_power += 5000
// This intentionally does not use adjust_clockwork_power.
else
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))
@@ -103,8 +121,8 @@
. = ..()
addtimer(CALLBACK(src, .proc/check_on_mob, user), 1) //dropped is called before the item is out of the slot, so we need to check slightly later
/obj/item/clockwork/slab/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE)
. = list()
/obj/item/clockwork/slab/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
. = ..()
if(isinhands && item_state && inhand_overlay)
var/mutable_appearance/M = mutable_appearance(icon_file, "slab_[inhand_overlay]")
. += M
@@ -232,7 +232,7 @@
background_icon_state = "bg_clock"
buttontooltipstyle = "clockcult"
/datum/action/innate/eminence/IsAvailable()
/datum/action/innate/eminence/IsAvailable(silent = FALSE)
if(!iseminence(owner))
qdel(src)
return
@@ -283,7 +283,7 @@
desc = "Initiates a mass recall, warping all servants to the Ark after a short delay. This can only be used once."
button_icon_state = "Spatial Gateway"
/datum/action/innate/eminence/mass_recall/IsAvailable()
/datum/action/innate/eminence/mass_recall/IsAvailable(silent = FALSE)
. = ..()
if(.)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
@@ -30,6 +30,7 @@ Applications: 8 servants, 3 caches, and 100 CV
var/primary_component
var/important = FALSE //important scripture will be italicized in the slab's interface
var/sort_priority = 1 //what position the scripture should have in a list of scripture. Should be based off of component costs/reqs, but you can't initial() lists.
var/requires_full_power = FALSE //requires the user to be a full, non neutered servant of ratvar
//messages for offstation scripture recital, courtesy ratvar's generals(and neovgre)
var/static/list/neovgre_penalty = list("Go to the station.", "Useless.", "Don't waste time.", "Pathetic.", "Wasteful.")
@@ -77,6 +78,9 @@ Applications: 8 servants, 3 caches, and 100 CV
/datum/clockwork_scripture/proc/can_recite() //If the words can be spoken
if(!invoker || !slab || invoker.get_active_held_item() != slab)
return FALSE
if(!is_servant_of_ratvar(invoker, requires_full_power))
to_chat(invoker, "<span class='warning'>You aren't strongly connected enough to Ratvar to invoke this!</span>")
return FALSE
if(!invoker.can_speak_vocal())
to_chat(invoker, "<span class='warning'>You are unable to speak the words of the scripture!</span>")
return FALSE
@@ -236,18 +240,21 @@ Applications: 8 servants, 3 caches, and 100 CV
return FALSE
return TRUE
/datum/clockwork_scripture/create_object/proc/get_spawn_path(mob/user)
return object_path
/datum/clockwork_scripture/create_object/scripture_effects()
if(creator_message && observer_message)
invoker.visible_message(observer_message, creator_message)
else if(creator_message)
to_chat(invoker, creator_message)
var/obj/O = new object_path (get_turf(invoker))
var/to_spawn = get_spawn_path(invoker)
var/obj/O = new to_spawn(get_turf(invoker))
O.ratvar_act() //update the new object so it gets buffed if ratvar is alive
if(isitem(O) && put_object_in_hands)
invoker.put_in_hands(O)
return TRUE
//Used specifically to create construct shells.
/datum/clockwork_scripture/create_object/construct
put_object_in_hands = FALSE
@@ -88,7 +88,7 @@
sort_priority = 4
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Submission, which will convert non-Servants that remain on it."
requires_full_power = TRUE
//Kindle: Charges the slab with blazing energy. It can be released to stun and silence a target.
/datum/clockwork_scripture/ranged_ability/kindle
@@ -211,6 +211,7 @@
quickbind = TRUE
quickbind_desc = "Returns you to Reebe."
var/client_color
requires_full_power = TRUE
/datum/clockwork_scripture/abscond/check_special_requirements()
if(is_reebe(invoker.z))
@@ -50,7 +50,6 @@
return FALSE
return ..()
//Vitality Matrix: Creates a sigil which will drain health from nonservants and can use that health to heal or even revive servants.
/datum/clockwork_scripture/create_object/vitality_matrix
descname = "Trap, Damage to Healing"
@@ -77,6 +76,10 @@
return FALSE
return ..()
/datum/clockwork_scripture/create_object/vitality_matrix/get_spawn_path(mob/user)
if(!is_servant_of_ratvar(user, TRUE))
return /obj/effect/clockwork/sigil/vitality/neutered
return ..()
//Judicial Visor: Creates a judicial visor, which can smite an area.
/datum/clockwork_scripture/create_object/judicial_visor
@@ -150,7 +153,7 @@
/obj/item/clothing/head/helmet/space,
/obj/item/clothing/shoes/magboots)) //replace this only if ratvar is up
/datum/action/innate/clockwork_armaments/IsAvailable()
/datum/action/innate/clockwork_armaments/IsAvailable(silent = FALSE)
if(!is_servant_of_ratvar(owner))
qdel(src)
return
@@ -5,15 +5,27 @@
antagpanel_category = "Clockcult"
job_rank = ROLE_SERVANT_OF_RATVAR
antag_moodlet = /datum/mood_event/cult
var/datum/action/innate/hierophant/hierophant_network = new
threat = 3
var/datum/action/innate/hierophant/hierophant_network = new()
var/datum/team/clockcult/clock_team
var/make_team = TRUE //This should be only false for tutorial scarabs
var/neutered = FALSE //can not use round ending, gibbing, converting, or similar things with unmatched round impact
var/ignore_eligibility_check = FALSE
var/ignore_holy_water = FALSE
/datum/antagonist/clockcult/silent
silent = TRUE
show_in_antagpanel = FALSE //internal
/datum/antagonist/clockcult/neutered
neutered = TRUE
/datum/antagonist/clockcult/neutered/traitor
ignore_eligibility_check = TRUE
ignore_holy_water = TRUE
show_in_roundend = FALSE
make_team = FALSE
/datum/antagonist/clockcult/Destroy()
qdel(hierophant_network)
return ..()
@@ -38,7 +50,7 @@
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
if(. && !ignore_eligibility_check)
. = is_eligible_servant(new_owner.current)
/datum/antagonist/clockcult/greet()
+12 -5
View File
@@ -17,7 +17,7 @@
qdel(X)
..()
/datum/action/innate/cult/blood_magic/IsAvailable()
/datum/action/innate/cult/blood_magic/IsAvailable(silent = FALSE)
if(!iscultist(owner))
return FALSE
return ..()
@@ -118,7 +118,7 @@
hand_magic = null
..()
/datum/action/innate/cult/blood_spell/IsAvailable()
/datum/action/innate/cult/blood_spell/IsAvailable(silent = FALSE)
if(!iscultist(owner) || owner.incapacitated() || !charges)
return FALSE
return ..()
@@ -439,7 +439,7 @@
"<span class='userdanger'>A feeling of warmth washes over you, rays of holy light surround your body and protect you from the flash of light!</span>")
else // cult doesn't stun any longer when halos are out, instead it does burn damage + knockback!
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(user_antag.cult_team.cult_ascendent)
if(user_antag.cult_team?.cult_ascendent)
if(!iscultist(L))
L.adjustFireLoss(20)
if(L.move_resist < MOVE_FORCE_STRONG)
@@ -577,7 +577,9 @@
var/turf/T = get_turf(target)
if(istype(target, /obj/item/stack/sheet/metal))
var/obj/item/stack/sheet/candidate = target
if(candidate.use(50))
if(!iscultist(user, TRUE))
to_chat(user, "<span class='warning'>You are not strongly connected enough to Nar'sie to use make constructs...</span>")
else if(candidate.use(50))
uses--
to_chat(user, "<span class='warning'>A dark cloud emanates from your hand and swirls around the metal, twisting it into a construct shell!</span>")
new /obj/structure/constructshell(T)
@@ -600,7 +602,9 @@
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else if(istype(target,/mob/living/silicon/robot))
var/mob/living/silicon/robot/candidate = target
if(candidate.mmi)
if(!iscultist(user, TRUE))
to_chat(user, "<span class='warning'>You are not strongly connected enough to Nar'sie to use make constructs...</span>")
else if(candidate.mmi)
user.visible_message("<span class='danger'>A dark cloud emanates from [user]'s hand and swirls around [candidate]!</span>")
playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
var/prev_color = candidate.color
@@ -656,6 +660,7 @@
C.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), SLOT_WEAR_SUIT)
C.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), SLOT_SHOES)
C.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), SLOT_BACK)
C.equip_to_slot_or_del(new /obj/item/clothing/gloves/fingerless/pugilist/hungryghost(user), SLOT_GLOVES)
if(C == user)
qdel(src) //Clears the hands
C.put_in_hands(new /obj/item/melee/cultblade(user))
@@ -819,6 +824,8 @@
if("Blood Beam (500)")
if(uses < 500)
to_chat(user, "<span class='cultitalic'>You need 500 charges to perform this rite.</span>")
else if(!iscultist(user, TRUE))
to_chat(user, "<span class='warning'>You are not strongly connected to Nar'sie enough to use something of this power.</span>")
else
var/obj/rite = new /obj/item/blood_beam()
uses -= 500
+21 -9
View File
@@ -11,15 +11,27 @@
var/datum/action/innate/cult/blood_magic/magic = new
job_rank = ROLE_CULTIST
var/ignore_implant = FALSE
var/make_team = TRUE
var/give_equipment = FALSE
var/datum/team/cult/cult_team
var/neutered = FALSE //can not use round ending, gibbing, converting, or similar things with unmatched round impact
var/ignore_eligibility_checks = FALSE
var/ignore_holy_water = FALSE
/datum/antagonist/cult/neutered
neutered = TRUE
/datum/antagonist/cult/neutered/traitor
ignore_eligibility_checks = TRUE
ignore_holy_water = TRUE
show_in_roundend = FALSE
make_team = FALSE
/datum/antagonist/cult/get_team()
return cult_team
/datum/antagonist/cult/create_team(datum/team/cult/new_team)
if(!new_team)
if(!new_team && make_team)
//todo remove this and allow admin buttons to create more than one cult
for(var/datum/antagonist/cult/H in GLOB.antagonists)
if(!H.owner)
@@ -30,12 +42,12 @@
cult_team = new /datum/team/cult
cult_team.setup_objectives()
return
if(!istype(new_team))
if(make_team && !istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
cult_team = new_team
/datum/antagonist/cult/proc/add_objectives()
objectives |= cult_team.objectives
objectives |= cult_team?.objectives
/datum/antagonist/cult/Destroy()
QDEL_NULL(communion)
@@ -44,7 +56,7 @@
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
. = ..()
if(. && !ignore_implant)
if(. && !ignore_implant && !ignore_eligibility_checks)
. = is_convertable_to_cult(new_owner.current,cult_team)
/datum/antagonist/cult/greet()
@@ -62,7 +74,7 @@
SSticker.mode.update_cult_icons_added(owner)
current.log_message("has been converted to the cult of Nar'Sie!", LOG_ATTACK, color="#960000")
if(cult_team.blood_target && cult_team.blood_target_image && current.client)
if(cult_team?.blood_target && cult_team.blood_target_image && current.client)
current.client.images += cult_team.blood_target_image
@@ -105,13 +117,13 @@
current = mob_override
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
if(!cult_team.cult_master)
if(!cult_team?.cult_master)
vote.Grant(current)
communion.Grant(current)
if(ishuman(current))
magic.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
if(cult_team.cult_risen)
if(cult_team?.cult_risen)
cult_team.rise(current)
if(cult_team.cult_ascendent)
cult_team.ascend(current)
@@ -144,7 +156,7 @@
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_theyve()] just reverted to [owner.current.p_their()] old faith!</span>", null, null, null, owner.current)
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
owner.current.log_message("has renounced the cult of Nar'Sie!", LOG_ATTACK, color="#960000")
if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
if(cult_team?.blood_target && cult_team.blood_target_image && owner.current.client)
owner.current.client.images -= cult_team.blood_target_image
. = ..()
@@ -206,7 +218,7 @@
throwing.Grant(current)
current.update_action_buttons_icon()
current.apply_status_effect(/datum/status_effect/cult_master)
if(cult_team.cult_risen)
if(cult_team?.cult_risen)
cult_team.rise(current)
if(cult_team.cult_ascendent)
cult_team.ascend(current)
+26 -14
View File
@@ -6,7 +6,7 @@
buttontooltipstyle = "cult"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
/datum/action/innate/cult/IsAvailable()
/datum/action/innate/cult/IsAvailable(silent = FALSE)
if(!iscultist(owner))
return FALSE
return ..()
@@ -51,7 +51,7 @@
name = "Spiritual Communion"
desc = "Conveys a message from the spirit realm that all cultists can hear."
/datum/action/innate/cult/comm/spirit/IsAvailable()
/datum/action/innate/cult/comm/spirit/IsAvailable(silent = FALSE)
if(iscultist(owner.mind.current))
return TRUE
@@ -72,9 +72,9 @@
name = "Assert Leadership"
button_icon_state = "cultvote"
/datum/action/innate/cult/mastervote/IsAvailable()
/datum/action/innate/cult/mastervote/IsAvailable(silent = FALSE)
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C || C.cult_team.cult_vote_called || !ishuman(owner))
if(!C?.cult_team || C.cult_team.cult_vote_called || !ishuman(owner))
return FALSE
return ..()
@@ -82,6 +82,9 @@
var/choice = alert(owner, "The mantle of leadership is heavy. Success in this role requires an expert level of communication and experience. Are you sure?",, "Yes", "No")
if(choice == "Yes" && IsAvailable())
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C.cult_team)
to_chat(owner, "<span class='cult bold'>Do you not alreaady lead yourself?</span>")
return
pollCultists(owner,C.cult_team)
/proc/pollCultists(var/mob/living/Nominee,datum/team/cult/team) //Cult Master Poll
@@ -137,7 +140,7 @@
to_chat(B.current,"<span class='cultlarge'>[Nominee] has won the cult's support and is now their master. Follow [Nominee.p_their()] orders to the best of your ability!</span>")
return TRUE
/datum/action/innate/cult/master/IsAvailable()
/datum/action/innate/cult/master/IsAvailable(silent = FALSE)
if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master) || GLOB.cult_narsie)
return 0
return ..()
@@ -151,6 +154,9 @@
var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!antag)
return
if(!antag.cult_team)
to_chat(owner, "<span class='cult bold'>You have no team. You are alone.</span>")
return
for(var/i in 1 to 4)
chant(i)
var/list/destinations = list()
@@ -220,9 +226,9 @@
CM.attached_action = src
..()
/datum/action/innate/cult/master/cultmark/IsAvailable()
/datum/action/innate/cult/master/cultmark/IsAvailable(silent = FALSE)
if(cooldown > world.time)
if(!CM.active)
if(!CM.active && !silent)
to_chat(owner, "<span class='cultlarge'><b>You need to wait [DisplayTimeText(cooldown - world.time)] before you can mark another target!</b></span>")
return FALSE
return ..()
@@ -261,7 +267,10 @@
return FALSE
var/datum/antagonist/cult/C = caller.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C.cult_team)
to_chat(ranged_ability_user, "<span class='cultlarge'>What is the point of marking a target for yourself?</span>")
remove_ranged_ability()
return
if(target in view(7, get_turf(ranged_ability_user)))
if(C.cult_team.blood_target)
to_chat(ranged_ability_user, "<span class='cult'>The cult has already designated a target!</span>")
@@ -299,7 +308,7 @@
name = "Mark a Blood Target for the Cult"
desc = "Marks a target for the entire cult to track."
/datum/action/innate/cult/master/cultmark/ghost/IsAvailable()
/datum/action/innate/cult/master/cultmark/ghost/IsAvailable(silent = FALSE)
if(istype(owner, /mob/dead/observer) && iscultist(owner.mind.current))
return TRUE
else
@@ -313,7 +322,7 @@
var/cooldown = 0
var/base_cooldown = 600
/datum/action/innate/cult/ghostmark/IsAvailable()
/datum/action/innate/cult/ghostmark/IsAvailable(silent = FALSE)
if(istype(owner, /mob/dead/observer) && iscultist(owner.mind.current))
return TRUE
else
@@ -330,8 +339,11 @@
/datum/action/innate/cult/ghostmark/Activate()
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C.cult_team)
to_chat(owner, "<span class='cultbold'>You are alone. You do not have a team.</span>")
return
if(C.cult_team.blood_target)
if(cooldown>world.time)
if(cooldown > world.time)
reset_blood_target(C.cult_team)
to_chat(owner, "<span class='cultbold'>You have cleared the cult's blood target!</span>")
deltimer(C.cult_team.blood_target_reset_timer)
@@ -339,7 +351,7 @@
else
to_chat(owner, "<span class='cultbold'>The cult has already designated a target!</span>")
return
if(cooldown>world.time)
if(cooldown > world.time)
to_chat(owner, "<span class='cultbold'>You aren't ready to place another blood mark yet!</span>")
return
target = owner.orbiting?.parent || get_turf(owner)
@@ -389,11 +401,11 @@
PM.attached_action = src
..()
/datum/action/innate/cult/master/pulse/IsAvailable()
/datum/action/innate/cult/master/pulse/IsAvailable(silent = FALSE)
if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master))
return FALSE
if(cooldown > world.time)
if(!PM.active)
if(!PM.active && !silent)
to_chat(owner, "<span class='cultlarge'><b>You need to wait [DisplayTimeText(cooldown - world.time)] before you can pulse again!</b></span>")
return FALSE
return ..()
+65 -38
View File
@@ -6,6 +6,21 @@
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
/obj/item/tome/traitor
var/spent = FALSE
/obj/item/tome/traitor/check_uplink_validity()
return !spent
/obj/item/tome/traitor/attack_self(mob/living/user)
if(!iscultist(user) && !spent)
to_chat(user, "<span class='userdanger'>You press your hand onto [src], sinister tendrils of corrupted magic swirling around you. Was this the best of ideas?</span>")
if(user.mind.add_antag_datum(/datum/antagonist/cult/neutered/traitor))
spent = TRUE
else
to_chat(user, "<span class='userdanger'>[src] falls dark. It appears you weren't worthy.</span>")
return ..()
/obj/item/melee/cultblade/dagger
name = "ritual dagger"
desc = "A strange dagger said to be used by sinister groups for \"preparing\" a corpse before sacrificing it to their dark gods."
@@ -162,24 +177,20 @@
jaunt.Remove(user)
user.update_icons()
/obj/item/twohanded/required/cult_bastard/IsReflect()
if(spinning)
/obj/item/twohanded/required/cult_bastard/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(spinning && is_energy_reflectable_projectile(object) && (attack_type & ATTACK_TYPE_PROJECTILE))
playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, 1)
return TRUE
else
..()
/obj/item/twohanded/required/cult_bastard/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT
if(prob(final_block_chance))
if(attack_type == PROJECTILE_ATTACK)
if(attack_type & ATTACK_TYPE_PROJECTILE)
owner.visible_message("<span class='danger'>[owner] deflects [attack_text] with [src]!</span>")
playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, 1)
return TRUE
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL | BLOCK_REDIRECTED | BLOCK_SHOULD_REDIRECT
else
playsound(src, 'sound/weapons/parry.ogg', 75, 1)
owner.visible_message("<span class='danger'>[owner] parries [attack_text] with [src]!</span>")
return TRUE
return FALSE
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL
return BLOCK_NONE
/obj/item/twohanded/required/cult_bastard/afterattack(atom/target, mob/user, proximity, click_parameters)
. = ..()
@@ -211,7 +222,7 @@
phasein = /obj/effect/temp_visual/dir_setting/cult/phase
phaseout = /obj/effect/temp_visual/dir_setting/cult/phase/out
/datum/action/innate/dash/cult/IsAvailable()
/datum/action/innate/dash/cult/IsAvailable(silent = FALSE)
if(iscultist(holder) && current_charges)
return TRUE
else
@@ -231,7 +242,7 @@
sword = bastard
holder = user
/datum/action/innate/cult/spin2win/IsAvailable()
/datum/action/innate/cult/spin2win/IsAvailable(silent = FALSE)
if(iscultist(holder) && cooldown <= world.time)
return TRUE
else
@@ -353,6 +364,11 @@
brightness_on = 0
actions_types = list()
/obj/item/clothing/head/helmet/space/hardsuit/cult/ComponentInitialize()
. = ..()
AddElement(/datum/element/spellcasting, SPELL_CULT_HELMET, ITEM_SLOT_HEAD)
/obj/item/clothing/suit/space/hardsuit/cult
name = "\improper Nar'Sien hardened armor"
icon_state = "cult_armor"
@@ -363,6 +379,10 @@
armor = list("melee" = 70, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 40, "acid" = 75)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/cult
/obj/item/clothing/suit/space/hardsuit/cult/ComponentInitialize()
. = ..()
AddElement(/datum/element/spellcasting, SPELL_CULT_ARMOR, ITEM_SLOT_OCLOTHING)
/obj/item/sharpener/cult
name = "eldritch whetstone"
desc = "A block, empowered by dark magic. Sharp weapons will be enhanced when used on the stone."
@@ -414,7 +434,13 @@
user.adjustBruteLoss(25)
user.dropItemToGround(src, TRUE)
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/check_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(current_charges)
block_return[BLOCK_RETURN_NORMAL_BLOCK_CHANCE] = 100
block_return[BLOCK_RETURN_BLOCK_CAPACITY] = (block_return[BLOCK_RETURN_BLOCK_CAPACITY] || 0) + current_charges
return ..()
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(current_charges)
owner.visible_message("<span class='danger'>\The [attack_text] is deflected in a burst of blood-red sparks!</span>")
current_charges--
@@ -422,11 +448,11 @@
if(!current_charges)
owner.visible_message("<span class='danger'>The runed shield around [owner] suddenly disappears!</span>")
owner.update_inv_wear_suit()
return 1
return 0
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL
return BLOCK_NONE
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands, icon_file, style_flags = NONE)
. = list()
/obj/item/clothing/suit/hooded/cultrobes/cult_shield/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE)
. = ..()
if(!isinhands && current_charges)
. += mutable_appearance('icons/effects/cult_effects.dmi', "shield-cult", MOB_LAYER + 0.01)
@@ -498,7 +524,7 @@
var/static/curselimit = 0
/obj/item/shuttle_curse/attack_self(mob/living/user)
if(!iscultist(user))
if(!iscultist(user, TRUE))
user.dropItemToGround(src, TRUE)
user.DefaultCombatKnockdown(100)
to_chat(user, "<span class='warning'>A powerful force shoves you away from [src]!</span>")
@@ -725,19 +751,19 @@
playsound(T, 'sound/effects/glassbr3.ogg', 100)
qdel(src)
/obj/item/twohanded/cult_spear/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
/obj/item/twohanded/cult_spear/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(wielded)
final_block_chance *= 2
if(prob(final_block_chance))
if(attack_type == PROJECTILE_ATTACK)
if(attack_type & ATTACK_TYPE_PROJECTILE)
owner.visible_message("<span class='danger'>[owner] deflects [attack_text] with [src]!</span>")
playsound(src, pick('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg', 'sound/weapons/effects/ric3.ogg', 'sound/weapons/effects/ric4.ogg', 'sound/weapons/effects/ric5.ogg'), 100, 1)
return TRUE
return BLOCK_SUCCESS | BLOCK_SHOULD_REDIRECT | BLOCK_REDIRECTED | BLOCK_PHYSICAL_EXTERNAL
else
playsound(src, 'sound/weapons/parry.ogg', 100, 1)
owner.visible_message("<span class='danger'>[owner] parries [attack_text] with [src]!</span>")
return TRUE
return FALSE
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL
return BLOCK_NONE
/datum/action/innate/cult/spear
name = "Bloody Bond"
@@ -936,10 +962,18 @@
hitsound = 'sound/weapons/smash.ogg'
var/illusions = 2
/obj/item/shield/mirror/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
/obj/item/shield/mirror/check_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
block_return[BLOCK_RETURN_REFLECT_PROJECTILE_CHANCE] = max(block_return[BLOCK_RETURN_REFLECT_PROJECTILE_CHANCE] || null, final_block_chance)
return ..()
/obj/item/shield/mirror/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(iscultist(owner))
if(istype(hitby, /obj/item/projectile))
var/obj/item/projectile/P = hitby
if(istype(object, /obj/item/projectile) && (attack_type == ATTACK_TYPE_PROJECTILE))
if(is_energy_reflectable_projectile(object))
if(prob(final_block_chance))
return BLOCK_SUCCESS | BLOCK_SHOULD_REDIRECT | BLOCK_PHYSICAL_EXTERNAL | BLOCK_REDIRECTED
return BLOCK_NONE //To avoid reflection chance double-dipping with block chance
var/obj/item/projectile/P = object
if(P.damage >= 30)
var/turf/T = get_turf(owner)
T.visible_message("<span class='warning'>The sheer force from [P] shatters the mirror shield!</span>")
@@ -947,11 +981,9 @@
playsound(T, 'sound/effects/glassbr3.ogg', 100)
owner.DefaultCombatKnockdown(25)
qdel(src)
return FALSE
if(P.is_reflectable)
return FALSE //To avoid reflection chance double-dipping with block chance
return BLOCK_NONE
. = ..()
if(.)
if(. & BLOCK_SUCCESS)
playsound(src, 'sound/weapons/parry.ogg', 100, 1)
if(illusions > 0)
illusions--
@@ -966,7 +998,7 @@
E.Copy_Parent(owner, 70, 10)
E.GiveTarget(owner)
E.Goto(owner, owner.movement_delay(), E.minimum_distance)
return TRUE
return
else
if(prob(50))
var/mob/living/simple_animal/hostile/illusion/H = new(owner.loc)
@@ -975,7 +1007,7 @@
H.GiveTarget(owner)
H.move_to_delay = owner.movement_delay()
to_chat(owner, "<span class='danger'><b>[src] betrays you!</b></span>")
return FALSE
return BLOCK_NONE
/obj/item/shield/mirror/proc/readd()
illusions++
@@ -983,11 +1015,6 @@
var/mob/living/holder = loc
to_chat(holder, "<span class='cult italic'>The shield's illusions are back at full strength!</span>")
/obj/item/shield/mirror/IsReflect()
if(prob(block_chance))
return TRUE
return FALSE
/obj/item/shield/mirror/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
var/turf/T = get_turf(hit_atom)
var/datum/thrownthing/D = throwingdatum
+5 -2
View File
@@ -59,6 +59,9 @@ This file contains the cult dagger and rune list code
rune_to_scribe = GLOB.rune_types[entered_rune_name]
if(!rune_to_scribe)
return
if(!iscultist(user, initial(rune_to_scribe.requires_full_power)))
to_chat(user, "<span class='warning'>You aren't strongly connected enough to Nar'sie to do draw this.</span>")
return
if(initial(rune_to_scribe.req_keyword))
chosen_keyword = stripped_input(user, "Enter a keyword for the new rune.", "Words of Power")
if(!chosen_keyword)
@@ -84,8 +87,8 @@ This file contains the cult dagger and rune list code
to_chat(user, "<span class='cultlarge'>Only one ritual site remains - it must be reserved for the final summoning!</span>")
return
if(ispath(rune_to_scribe, /obj/effect/rune/narsie))
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team.objectives
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team?.objectives
var/datum/objective/sacrifice/sac_objective = locate() in user_antag.cult_team?.objectives
if(!summon_objective)
to_chat(user, "<span class='warning'>Nar'Sie does not wish to be summoned!</span>")
return
@@ -14,7 +14,7 @@
var/obj/effect/temp_visual/cult/rune_spawn/rune_center_type
var/rune_color
/datum/action/innate/cult/create_rune/IsAvailable()
/datum/action/innate/cult/create_rune/IsAvailable(silent = FALSE)
if(!rune_type || cooldown > world.time)
return FALSE
return ..()
+11
View File
@@ -32,6 +32,7 @@ Runes can either be invoked by one's self or with many different cultists. Each
var/scribe_delay = 40 //how long the rune takes to create
var/scribe_damage = 0.1 //how much damage you take doing it
var/requires_full_power = FALSE //requires full power to draw or invoke
var/invoke_damage = 0 //how much damage invokers take when invoking it
var/construct_invoke = TRUE //if constructs can invoke it
@@ -185,6 +186,7 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_OFFER
req_cultists = 1
rune_in_use = FALSE
requires_full_power = TRUE
/obj/effect/rune/convert/do_invoke_glow()
return
@@ -458,6 +460,7 @@ structure_check() searches for nearby cultist structures required for the invoca
pixel_y = -32
scribe_delay = 500 //how long the rune takes to create
scribe_damage = 40.1 //how much damage you take doing it
requires_full_power = TRUE
var/used = FALSE
/obj/effect/rune/narsie/Initialize(mapload, set_keyword)
@@ -482,6 +485,9 @@ structure_check() searches for nearby cultist structures required for the invoca
fail_invoke()
return
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!user_antag.cult_team)
to_chat(user, "<span class='cultlarge'>You can't seem to make the arcane links to your fellows that you'd need to use this.</span>")
return
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/area/place = get_area(src)
if(!(place in summon_objective.summon_spots))
@@ -812,6 +818,7 @@ structure_check() searches for nearby cultist structures required for the invoca
invoke_damage = 10
construct_invoke = FALSE
color = RUNE_COLOR_DARKRED
requires_full_power = TRUE
var/mob/living/affecting = null
var/ghost_limit = 3
var/ghosts = 0
@@ -942,6 +949,7 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_DARKRED
req_cultists = 3
scribe_delay = 100
requires_full_power = TRUE
/obj/effect/rune/apocalypse/invoke(var/list/invokers)
if(rune_in_use)
@@ -950,6 +958,9 @@ structure_check() searches for nearby cultist structures required for the invoca
var/area/place = get_area(src)
var/mob/living/user = invokers[1]
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!user_antag.cult_team)
to_chat(user, "<span class='cultlarge'>You can't seem to make the arcane links to your fellows that you'd need to use this.</span>")
return
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
if(summon_objective.summon_spots.len <= 1)
to_chat(user, "<span class='cultlarge'>Only one ritual site remains - it must be reserved for the final summoning!</span>")
@@ -12,12 +12,7 @@
var/obj/item/r_hand = get_item_for_held_index(2)
if(r_hand)
var/r_state = r_hand.item_state
if(!r_state)
r_state = r_hand.icon_state
var/mutable_appearance/r_hand_overlay = r_hand.build_worn_icon(state = r_state, default_layer = DEVIL_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE)
var/mutable_appearance/r_hand_overlay = r_hand.build_worn_icon(default_layer = DEVIL_HANDS_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE)
hands_overlays += r_hand_overlay
@@ -28,12 +23,7 @@
client.screen |= r_hand
if(l_hand)
var/l_state = l_hand.item_state
if(!l_state)
l_state = l_hand.icon_state
var/mutable_appearance/l_hand_overlay = l_hand.build_worn_icon(state = l_state, default_layer = DEVIL_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE)
var/mutable_appearance/l_hand_overlay = l_hand.build_worn_icon(default_layer = DEVIL_HANDS_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE)
hands_overlays += l_hand_overlay
@@ -74,12 +74,6 @@ GLOBAL_VAR_INIT(war_declared, FALSE)
new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS - tc_malus + CEILING(PLAYER_SCALING * actual_players, 1))
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
if(istype(SSticker.mode, /datum/game_mode/dynamic))
var/datum/game_mode/dynamic/mode = SSticker.mode
if(!(mode.storyteller.flags & WAROPS_ALWAYS_ALLOWED))
var/threat_spent = CONFIG_GET(number/dynamic_warops_cost)
mode.spend_threat(threat_spent)
mode.log_threat("Nuke ops spent [threat_spent] on war ops.")
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
qdel(src)
@@ -414,11 +414,11 @@
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)
if(nuclear_cooldown > world.time)
to_chat(usr, "<span class='danger'>[src]'s timer protocols are currently on cooldown, please stand by.</span>")
return
previous_level = get_security_level()
detonation_timer = world.time + (timer_set * 10)
for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
@@ -117,7 +117,7 @@
tinfoil_check = FALSE
/obj/effect/proc_holder/spell/aoe_turf/revenant
clothes_req = 0
clothes_req = NONE
action_icon = 'icons/mob/actions/actions_revenant.dmi'
action_background_icon_state = "bg_revenant"
panel = "Revenant Abilities (Locked)"
@@ -135,7 +135,7 @@
else
name = "[initial(name)] ([cast_amount]E)"
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr)
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr, skipcharge = FALSE, silent = FALSE)
if(charge_counter < charge_max)
return FALSE
if(!istype(user)) //Badmins, no. Badmins, don't do it.
+1 -1
View File
@@ -18,7 +18,7 @@
owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/presents)
var/obj/effect/proc_holder/spell/targeted/area_teleport/teleport/telespell = new
telespell.clothes_req = 0 //santa robes aren't actually magical.
telespell.clothes_req = NONE //santa robes aren't actually magical.
owner.AddSpell(telespell) //does the station have chimneys? WHO KNOWS!
/datum/antagonist/santa/proc/give_objective()
+61 -2
View File
@@ -179,8 +179,8 @@
/obj/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
if(resistance_flags & INDESTRUCTIBLE)
return FALSE
for(var/mob/living/L in contents)
if(!issilicon(L) && !isbrain(L))
for(var/mob/living/L in GetAllContents())
if(!ispAI(L) && !isbrain(L))
to_chat(S, "<span class='warning'>An organism has been detected inside this object. Aborting.</span>")
return FALSE
return ..()
@@ -416,6 +416,57 @@
to_chat(S, "<span class='warning'>Destroying this object would cause a catastrophic chain reaction. Aborting.</span>")
return FALSE
/obj/machinery/ore_silo/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>Destroying this object, however tempting it's, will disrupt the research development that may serve for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/rnd/server/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>Destroying this object, will disrupt the research development that may serve for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/pool/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) //pool's closed, but not.
to_chat(S, "<span class='warning'>The pool must not be closed, it will provide healthy fun for our masters in the future. Aborting.</span>")
return FALSE
/obj/structure/pool/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>The pool must not be closed, it will provide healthy fun for our masters in the future. Aborting.</span>")
return FALSE
/obj/structure/holosign/barrier/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
var/static/list/lazy_typecache = typecacheof(list(/obj/structure/holosign/barrier/engineering, /obj/structure/holosign/barrier/firelock, /obj/structure/holosign/barrier/atmos, /obj/structure/holosign/barrier/combifan))
if(lazy_typecache[type])
to_chat(S, "<span class='warning'>Destroying this holographic barrier may not benefit us. Aborting.</span>")
return FALSE
return ..()
/obj/machinery/dominator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/computer/bsa_control/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/bsa/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/dna_vault/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
return FALSE
/obj/structure/filler/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>This advanced piece of technology may be of use for our masters in the future. Aborting.</span>")
return FALSE
/obj/machinery/computer/sat_control/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>Destroying this object will lower the station shielding against space debris. Aborting.</span>")
return FALSE
/obj/machinery/satellite/meteor_shield/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
to_chat(S, "<span class='warning'>Destroying this object will lower the station shielding against space debris. Aborting.</span>")
return FALSE
////END CTRL CLICK FOR SWARMERS////
/mob/living/simple_animal/hostile/swarmer/proc/Fabricate(atom/fabrication_object,fabrication_cost = 0)
@@ -429,6 +480,14 @@
return new fabrication_object(loc)
/mob/living/simple_animal/hostile/swarmer/proc/Integrate(atom/movable/target)
if(isobj(target))
var/obj/O = target
if(O.resistance_flags & INDESTRUCTIBLE)
return FALSE
for(var/mob/living/L in GetAllContents())
if(!ispAI(L) && !isbrain(L))
to_chat(src, "<span class='warning'>An organism has been detected inside this object. Aborting.</span>")
return FALSE
var/resource_gain = target.IntegrateAmount()
if(resources + resource_gain > max_resources)
to_chat(src, "<span class='warning'>We cannot hold more materials!</span>")
@@ -1,10 +1,10 @@
/datum/round_event_control/spawn_swarmer
name = "Spawn Swarmer Shell"
typepath = /datum/round_event/spawn_swarmer
weight = 0
max_occurrences = 0
weight = 7
max_occurrences = 1 //Only once okay fam
earliest_start = 30 MINUTES
min_players = 15
min_players = 35
gamemode_blacklist = list("dynamic")
@@ -34,7 +34,7 @@
if(is_dynamic)
var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost)
mode.spend_threat(threat_spent)
mode.log_threat("[T.owner.name] spent [threat_spent] on an assassination target.")
mode.log_threat("[T.owner.name] added [threat_spent] on an assassination target.")
var/list/active_ais = active_ais()
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
var/datum/objective/destroy/destroy_objective = new
@@ -38,8 +38,8 @@
weights[C] = weight
var/choice = pickweightAllowZero(weights)
if(!choice)
choice = GLOB.traitor_classes[TRAITOR_HUMAN]
set_traitor_kind(pickweightAllowZero(weights))
choice = GLOB.traitor_classes[TRAITOR_HUMAN] // it's an "easter egg"
set_traitor_kind(choice)
traitor_kind.weight *= 0.8 // less likely this round
SSticker.mode.traitors += owner
owner.special_role = special_role
@@ -43,7 +43,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
else
owner_AI = owner
/datum/action/innate/ai/IsAvailable()
/datum/action/innate/ai/IsAvailable(silent = FALSE)
. = ..()
if(owner_AI && owner_AI.malf_cooldown > world.time)
return FALSE
@@ -89,7 +89,7 @@
/datum/syndicate_contract/proc/handleVictimExperience(var/mob/living/M) // They're off to holding - handle the return timer and give some text about what's going on.
addtimer(CALLBACK(src, .proc/returnVictim, M), 4 MINUTES) // Ship 'em back - dead or alive... 4 minutes wait.
if(M.stat != DEAD) //Even if they weren't the target, we're still treating them the same.
M.reagents.add_reagent(/datum/reagent/medicine/omnizine, 20) // Heal them up - gets them out of crit/soft crit.
M.reagents.add_reagent(/datum/reagent/medicine/regen_jelly, 20) // Heal them up - gets them out of crit/soft crit. -- now 100% toxinlover friendly!!
M.flash_act()
M.confused += 10
M.blur_eyes(5)
@@ -31,12 +31,12 @@
/obj/item/soulstone/pickup(mob/living/user)
..()
if(!iscultist(user) && !iswizard(user) && !usability)
if(!iscultist(user, TRUE) && !iswizard(user) && !usability)
to_chat(user, "<span class='danger'>An overwhelming feeling of dread comes over you as you pick up the soulstone. It would be wise to be rid of this quickly.</span>")
/obj/item/soulstone/examine(mob/user)
. = ..()
if(usability || iscultist(user) || iswizard(user) || isobserver(user))
if(usability || iscultist(user, TRUE) || iswizard(user) || isobserver(user))
if (old_shard)
. += "<span class='cult'>A soulstone, used to capture a soul, either from dead humans or from freed shades.</span>"
else
@@ -53,7 +53,7 @@
//////////////////////////////Capturing////////////////////////////////////////////////////////
/obj/item/soulstone/attack(mob/living/carbon/human/M, mob/living/user)
if(!iscultist(user) && !iswizard(user) && !usability)
if(!iscultist(user, TRUE) && !iswizard(user) && !usability)
user.Unconscious(100)
to_chat(user, "<span class='userdanger'>Your body is wracked with debilitating pain!</span>")
return
@@ -74,7 +74,7 @@
/obj/item/soulstone/attack_self(mob/living/user)
if(!in_range(src, user))
return
if(!iscultist(user) && !iswizard(user) && !usability)
if(!iscultist(user, TRUE) && !iswizard(user) && !usability)
user.Unconscious(100)
to_chat(user, "<span class='userdanger'>Your body is wracked with debilitating pain!</span>")
return
@@ -103,7 +103,7 @@
/obj/structure/constructshell/examine(mob/user)
. = ..()
if(iscultist(user) || iswizard(user) || user.stat == DEAD)
if(iscultist(user, TRUE) || iswizard(user) || user.stat == DEAD)
. += "<span class='cult'>A construct shell, used to house bound souls from a soulstone.</span>"
. += "<span class='cult'>Placing a soulstone with a soul into this shell allows you to produce your choice of the following:</span>"
. += "<span class='cult'>An <b>Artificer</b>, which can produce <b>more shells and soulstones</b>, as well as fortifications.</span>"
@@ -113,7 +113,7 @@
/obj/structure/constructshell/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/soulstone))
var/obj/item/soulstone/SS = O
if(!iscultist(user) && !iswizard(user) && !SS.usability)
if(!iscultist(user, TRUE) && !iswizard(user) && !SS.usability)
to_chat(user, "<span class='danger'>An overwhelming feeling of dread comes over you as you attempt to place the soulstone into the shell. It would be wise to be rid of this quickly.</span>")
user.Dizzy(30)
return
@@ -145,7 +145,7 @@
if("VICTIM")
var/mob/living/carbon/human/T = target
var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(C && C.cult_team.is_sacrifice_target(T.mind))
if(C && C.cult_team?.is_sacrifice_target(T.mind))
if(iscultist(user))
to_chat(user, "<span class='cult'><b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\"</span>")
else
@@ -104,7 +104,7 @@
dat += " Cooldown:[S.charge_max/10]"
dat += " Cost:[cost]<br>"
dat += "<i>[S.desc][desc]</i><br>"
dat += "[S.clothes_req?"Needs wizard garb":"Can be cast without wizard garb"]<br>"
dat += "[S.clothes_req & SPELL_WIZARD_GARB ? "Needs wizard garb" : "Can be cast without wizard garb"]<br>"
return dat
/datum/spellbook_entry/fireball
+1 -1
View File
@@ -312,7 +312,7 @@
if(holder)
holder.update_icon()
/obj/item/assembly/flash/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
/obj/item/assembly/flash/shield/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
activate()
return ..()
@@ -179,7 +179,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
/datum/gas/miasma
id = "miasma"
specific_heat = 0.00001
specific_heat = 20
fusion_power = 50
name = "Miasma"
gas_overlay = "miasma"
@@ -84,7 +84,6 @@
/obj/machinery/atmospherics/components/proc/nullifyPipenet(datum/pipeline/reference)
if(!reference)
CRASH("nullifyPipenet(null) called by [type] on [COORD(src)]")
return
var/i = parents.Find(reference)
reference.other_airs -= airs[i]
reference.other_atmosmch -= src
@@ -168,4 +167,4 @@
/obj/machinery/atmospherics/components/analyzer_act(mob/living/user, obj/item/I)
atmosanalyzer_scan(airs, user, src)
atmosanalyzer_scan(airs, user, src)
@@ -131,7 +131,6 @@
var/datum/pipeline/P = returnPipenet(A)
if(!P)
CRASH("null.addMember() called by [type] on [COORD(src)]")
return
P.addMember(A, src)
@@ -208,7 +207,7 @@
/datum/pipeline/proc/return_air()
. = other_airs + air
if(null in .)
stack_trace("[src] has one or more null gas mixtures, which may cause bugs. Null mixtures will not be considered in reconcile_air().")
stack_trace("[src]([REF(src)]) has one or more null gas mixtures, which may cause bugs. Null mixtures will not be considered in reconcile_air().")
return removeNullsFromList(.)
/datum/pipeline/proc/reconcile_air()
+2
View File
@@ -205,6 +205,8 @@
H.facial_hair_style = random_facial_hair_style(gender)
if(skin_tone)
H.skin_tone = skin_tone
if(!GLOB.skin_tones[H.skin_tone])
H.dna.skin_tone_override = H.skin_tone
else
H.skin_tone = random_skin_tone()
H.update_hair()
@@ -309,7 +309,7 @@
name = "Summon Servant"
desc = "This spell can be used to call your servant, whenever you need it."
charge_max = 100
clothes_req = 0
clothes_req = NONE
invocation = "JE VES"
invocation_type = "whisper"
range = -1
+47
View File
@@ -116,3 +116,50 @@
exclude_types = list(/obj/item/stack/ore/bluespace_crystal,
/obj/item/stack/sheet/bluespace_crystal,
/obj/item/stack/ore/bluespace_crystal/refined)
/datum/bounty/item/science/noneactive_reactivearmor
name = "Reactive Armor Shells"
description = "Do to the breakthroughs in anomalies, we can not keep up in making reactive armor shells, can you send us a few?"
reward = 2000
required_count = 5
wanted_types = list(/obj/item/reactive_armour_shell, /obj/item/clothing/suit/armor/reactive)
exclude_types = list(/obj/item/clothing/suit/armor/reactive/repulse,
/obj/item/clothing/suit/armor/reactive/tesla,
/obj/item/clothing/suit/armor/reactive/teleport,
/obj/item/clothing/suit/armor/reactive/stealth,
/obj/item/clothing/suit/armor/reactive/fire)
/datum/bounty/item/science/anomaly_core
name = "Anomaly Core"
description = "A new theory has begun that each sector of space has different anomalies, this all started when a local station tried to make a fire based reactive suit and failed making a stealth version, please send us a core so we may study it more."
reward = 2500
required_count = 1
wanted_types = list(/obj/item/assembly/signaler/anomaly)
/datum/bounty/item/science/anomaly_neutralizer
name = "Anomaly Neutralizers"
description = "An idea for a long time was to use an unstable Supermatter Shard to help create the breeding grounds for an unstable part of space to harvest any anomalies we want. It worked a little too well and now were out of anomaly neutralizers please send us a baker's dozen."
reward = 2500
required_count = 13
wanted_types = list(/obj/item/anomaly_neutralizer)
/datum/bounty/item/science/integrated_circuit_printer
name = "Integrated Circuit Printer"
description = "due to a paperwork error, a newly made integrated circuit manufacturer line is missing three of its printers needed to operate. Until the paper work is corrected we are outsourcing this problem, so please send us three integrated circuit printers."
reward = 2000
required_count = 3
wanted_types = list(/obj/item/integrated_circuit_printer)
/datum/bounty/item/science/integrated_circuit_disks
name = "Integrated Circuit Printer Upgrade Disks"
description = "HR has requested ten more integrated circuit printer upgrade disks, please send them to CC as soon as possible."
reward = 2000
required_count = 10 //Its just metal
wanted_types = list(/obj/item/disk/integrated_circuit/upgrade)
/datum/bounty/item/science/nanite_trash
name = "Nanite Based Gear"
description = "CC wants to make nanite based gear available to a new wing of devolvement but lacks the hand held tools to get it full up and running. Please send us any you have."
reward = 2500
required_count = 20 //Its just metal
wanted_types = list( /obj/item/nanite_remote, /obj/item/nanite_remote/comm, /obj/item/nanite_scanner)
@@ -488,7 +488,6 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
if (isnull(A)) //If theres no supplypod bay mapped into centcom, throw an error
to_chat(holder.mob, "No /area/centcom/supplypod/loading/one (or /two or /three or /four) in the world! You can make one yourself (then refresh) for now, but yell at a mapper to fix this, today!")
CRASH("No /area/centcom/supplypod/loading/one (or /two or /three or /four) has been mapped into the centcom z-level!")
return
orderedArea = list()
if (!isemptylist(A.contents)) //Go through the area passed into the proc, and figure out the top left and bottom right corners by calculating max and min values
var/startX = A.contents[1].x //Create the four values (we do it off a.contents[1] so they have some sort of arbitrary initial value. They should be overwritten in a few moments)
+1 -1
View File
@@ -309,7 +309,7 @@
/datum/export/gear/combatgloves
cost = 80
unit_name = "combat gloves"
export_types = list(/obj/item/clothing/gloves/combat, /obj/item/clothing/gloves/rapid, /obj/item/clothing/gloves/krav_maga)
export_types = list(/obj/item/clothing/gloves/combat, /obj/item/clothing/gloves/fingerless/pugilist/rapid, /obj/item/clothing/gloves/krav_maga)
include_subtypes = TRUE
/datum/export/gear/bonegloves
+25 -1
View File
@@ -112,7 +112,7 @@
/datum/export/glasswork_lens
cost = 1800
unit_name = "small glass lens"
export_types = list(/obj/item/lens)
export_types = list(/obj/item/glasswork/glass_base/lens)
/datum/export/glasswork_spouty
cost = 1200
@@ -131,3 +131,27 @@
unit_name = "large flask"
export_types = list(/obj/item/reagent_containers/glass/beaker/flask/large)
include_subtypes = FALSE
/datum/export/glasswork_teaplate
cost = 1200
unit_name = "tea gear"
export_types = list(/obj/item/tea_plate)
include_subtypes = FALSE
/datum/export/glasswork_teacup
cost = 1800
unit_name = "tea gear"
export_types = list(/obj/item/tea_cup)
include_subtypes = FALSE
/datum/export/glasswork_laserpointer
cost = 2600
unit_name = "hand made laserpointer"
export_types = list(/obj/item/laser_pointer/blue/handmade)
include_subtypes = FALSE
/datum/export/glasswork_glasses
cost = 5000
unit_name = "hand made glasses"
export_types = list(/obj/item/glasswork/glasses)
include_subtypes = FALSE
+1 -1
View File
@@ -287,7 +287,7 @@
/datum/export/weapon/gloves
cost = 90
unit_name = "star struck gloves"
export_types = list(/obj/item/clothing/gloves/rapid)
export_types = list(/obj/item/clothing/gloves/fingerless/pugilist/rapid)
/datum/export/weapon/l6
cost = 500
+1 -1
View File
@@ -287,7 +287,7 @@
/datum/supply_pack/emergency/specialops
name = "Special Ops Supplies"
desc = "(*!&@#TOO CHEAP FOR THAT NULL_ENTRY, HUH OPERATIVE? WELL, THIS LITTLE ORDER CAN STILL HELP YOU OUT IN A PINCH. CONTAINS A BOX OF FIVE EMP GRENADES, THREE SMOKEBOMBS, AN INCENDIARY GRENADE, AND A \"SLEEPY PEN\" FULL OF NICE TOXINS!#@*$"
desc = "(*!&@#NEED SOMETHING TO DEAL WITH THE GREYTIDE, HUH OPERATIVE? WELL, THIS LITTLE ORDER CAN HELP YOU OUT IN A PINCH. CONTAINS A BOX OF FIVE EMP GRENADES, THREE SMOKEBOMBS, AN INCENDIARY GRENADE, AND A \"SLEEPY PEN\" FULL OF NICE TOXINS!#@*$"
hidden = TRUE
cost = 2200
contains = list(/obj/item/storage/box/emps,
+2 -2
View File
@@ -152,7 +152,7 @@
/obj/item/instrument/trombone,
/obj/item/instrument/recorder,
/obj/item/instrument/harmonica,
/obj/structure/piano/unanchored)
/obj/structure/musician/piano/unanchored)
crate_type = /obj/structure/closet/crate/wooden
/datum/supply_pack/misc/casinocrate
@@ -330,7 +330,7 @@
/datum/supply_pack/misc/religious_supplies
name = "Religious Supplies Crate"
desc = "Keep your local chaplain happy and well-supplied, lest they call down judgement upon your cargo bay. Contains two bottles of holywater, bibles, chaplain robes, and burial garmets."
cost = 4000 // it costs so much because the Space Church is ran by Space Jews
cost = 4000 // it costs so much because the Space Church needs funding to build a cathedral
contains = list(/obj/item/reagent_containers/food/drinks/bottle/holywater,
/obj/item/reagent_containers/food/drinks/bottle/holywater,
/obj/item/storage/book/bible/booze,
+36 -2
View File
@@ -529,7 +529,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
"pill21" = 'icons/UI_Icons/Pills/pill21.png',
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
)
/datum/asset/simple/IRV
assets = list(
"jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
@@ -704,9 +704,43 @@ GLOBAL_LIST_EMPTY(asset_datums)
Insert(initial(D.id), I)
return ..()
/datum/asset/spritesheet/vending
name = "vending"
/datum/asset/spritesheet/vending/register()
for(var/k in GLOB.vending_products)
var/atom/item = k
if(!ispath(item, /atom))
continue
var/icon_file = initial(item.icon)
var/icon_state = initial(item.icon_state)
var/icon/I
var/icon_states_list = icon_states(icon_file)
if(icon_state in icon_states_list)
I = icon(icon_file, icon_state, SOUTH)
var/c = initial(item.color)
if(!isnull(c) && c != "#FFFFFF")
I.Blend(c, ICON_MULTIPLY)
else
var/icon_states_string
for(var/an_icon_state in icon_states_list)
if(!icon_states_string)
icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
else
icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
I = icon('icons/turf/floors.dmi', "", SOUTH)
var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
Insert(imgid, I)
return ..()
/datum/asset/simple/genetics
assets = list(
"dna_discovered.gif" = 'html/dna_discovered.gif',
"dna_undiscovered.gif" = 'html/dna_undiscovered.gif',
"dna_extra.gif" = 'html/dna_extra.gif'
)
)
+105 -47
View File
@@ -89,11 +89,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/facial_hair_style = "Shaved" //Face hair type
var/facial_hair_color = "000" //Facial hair color
var/skin_tone = "caucasian1" //Skin color
var/use_custom_skin_tone = FALSE
var/eye_color = "000" //Eye color
var/horn_color = "85615a" //Horn color
var/wing_color = "fff" //Wing color
var/datum/species/pref_species = new /datum/species/human() //Mutant race
var/list/features = list("mcolor" = "FFF",
"mcolor2" = "FFF",
"mcolor3" = "FFF",
"tail_lizard" = "Smooth",
"tail_human" = "None",
"snout" = "Round",
@@ -108,8 +111,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"insect_wings" = "Plain",
"insect_fluff" = "None",
"insect_markings" = "None",
"mcolor2" = "FFF",
"mcolor3" = "FFF",
"mam_body_markings" = "Plain",
"mam_ears" = "None",
"mam_snouts" = "None",
@@ -125,6 +126,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"cock_length" = COCK_SIZE_DEF,
"cock_diameter_ratio" = COCK_DIAMETER_RATIO_DEF,
"cock_color" = "fff",
"cock_taur" = FALSE,
"has_balls" = FALSE,
"balls_color" = "fff",
"balls_shape" = DEF_BALLS_SHAPE,
@@ -149,7 +151,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"ipc_antenna" = "None",
"flavor_text" = "",
"meat_type" = "Mammalian",
"body_model" = MALE
"body_model" = MALE,
"body_size" = RESIZE_DEFAULT_SIZE
)
var/list/custom_names = list()
@@ -194,10 +197,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/action_buttons_screen_locs = list()
//bad stuff
var/digestable = FALSE
var/devourable = FALSE
var/feeding = FALSE
var/lickable = FALSE
var/vore_flags = 0
var/list/belly_prefs = list()
var/vore_taste = "nothing in particular"
@@ -293,7 +293,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<a href='?_src_=prefs;preference=name;task=input'>[real_name]</a><BR>"
dat += "<a href='?_src_=prefs;preference=nameless'>Be nameless: [nameless ? "Yes" : "No"]</a><BR>"
dat += "<b>Gender:</b> <a href='?_src_=prefs;preference=gender'>[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]</a><BR>"
dat += "<b>Gender:</b> <a href='?_src_=prefs;preference=gender;task=input'>[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]</a><BR>"
dat += "<b>Age:</b> <a style='display:block;width:30px' href='?_src_=prefs;preference=age;task=input'>[age]</a><BR>"
dat += "<b>Special Names:</b><BR>"
@@ -344,7 +344,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
else
dat += "[TextPreview(features["flavor_text"])]...<BR>"
dat += "<h2>Body</h2>"
dat += "<b>Gender:</b><a style='display:block;width:100px' href='?_src_=prefs;preference=gender'>[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]</a><BR>"
dat += "<b>Gender:</b><a style='display:block;width:100px' href='?_src_=prefs;preference=gender;task=input'>[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]</a><BR>"
if(gender != NEUTER && pref_species.sexes)
dat += "<b>Body Model:</b><a style='display:block;width:100px' href='?_src_=prefs;preference=body_model'>[features["body_model"] == MALE ? "Masculine" : "Feminine"]</a><BR>"
dat += "<b>Species:</b><a style='display:block;width:100px' href='?_src_=prefs;preference=species;task=input'>[pref_species.name]</a><BR>"
@@ -359,7 +359,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<h3>Skin Tone</h3>"
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=s_tone;task=input'>[skin_tone]</a><BR>"
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=s_tone;task=input'>[use_custom_skin_tone ? "custom: <span style='border:1px solid #161616; background-color: [skin_tone];'>&nbsp;&nbsp;&nbsp;</span>" : skin_tone]</a><BR>"
var/mutant_colors
if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits))
@@ -378,6 +378,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<span style='border: 1px solid #161616; background-color: #[features["mcolor3"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=mutant_color3;task=input'>Change</a><BR>"
mutant_colors = TRUE
if (CONFIG_GET(number/body_size_min) != CONFIG_GET(number/body_size_max))
dat += "<b>Sprite Size:</b> <a href='?_src_=prefs;preference=body_size;task=input'>[features["body_size"]]%</a><br>"
if((EYECOLOR in pref_species.species_traits) && !(NOEYES in pref_species.species_traits))
if(!use_skintones && !mutant_colors)
@@ -758,18 +761,25 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(features["has_cock"])
if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
dat += "<b>Penis Color:</b></a><BR>"
dat += "<span style='border: 1px solid #161616; background-color: #[skintone2hex(skin_tone)];'>&nbsp;&nbsp;&nbsp;</span>(Skin tone overriding)</a><br>"
dat += "<span style='border: 1px solid #161616; background-color: [SKINTONE2HEX(skin_tone)];'>&nbsp;&nbsp;&nbsp;</span>(Skin tone overriding)</a><br>"
else
dat += "<b>Penis Color:</b></a><BR>"
dat += "<span style='border: 1px solid #161616; background-color: #[features["cock_color"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=cock_color;task=input'>Change</a><br>"
dat += "<b>Penis Shape:</b> <a style='display:block;width:120px' href='?_src_=prefs;preference=cock_shape;task=input'>[features["cock_shape"]]</a>"
var/tauric_shape = FALSE
if(features["cock_taur"])
var/datum/sprite_accessory/penis/P = GLOB.cock_shapes_list[features["cock_shape"]]
if(P.taur_icon && pref_species.mutant_bodyparts["taur"])
var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]]
if(T.taur_mode & P.accepted_taurs)
tauric_shape = TRUE
dat += "<b>Penis Shape:</b> <a style='display:block;width:120px' href='?_src_=prefs;preference=cock_shape;task=input'>[features["cock_shape"]][tauric_shape ? " (Taur)" : ""]</a>"
dat += "<b>Penis Length:</b> <a style='display:block;width:120px' href='?_src_=prefs;preference=cock_length;task=input'>[features["cock_length"]] inch(es)</a>"
dat += "<b>Penis Visibility:</b><a style='display:block;width:100px' href='?_src_=prefs;preference=cock_visibility;task=input'>[features["cock_visibility"]]</a>"
dat += "<b>Has Testicles:</b><a style='display:block;width:50px' href='?_src_=prefs;preference=has_balls'>[features["has_balls"] == TRUE ? "Yes" : "No"]</a>"
if(features["has_balls"])
if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
dat += "<b>Testicles Color:</b></a><BR>"
dat += "<span style='border: 1px solid #161616; background-color: #[skintone2hex(skin_tone)];'>&nbsp;&nbsp;&nbsp;</span>(Skin tone overriding)<br>"
dat += "<span style='border: 1px solid #161616; background-color: [SKINTONE2HEX(skin_tone)];'>&nbsp;&nbsp;&nbsp;</span>(Skin tone overriding)<br>"
else
dat += "<b>Testicles Color:</b></a><BR>"
dat += "<span style='border: 1px solid #161616; background-color: #[features["balls_color"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=balls_color;task=input'>Change</a><br>"
@@ -781,7 +791,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Vagina Type:</b> <a style='display:block;width:100px' href='?_src_=prefs;preference=vag_shape;task=input'>[features["vag_shape"]]</a>"
if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
dat += "<b>Vagina Color:</b></a><BR>"
dat += "<span style='border: 1px solid #161616; background-color: #[skintone2hex(skin_tone)];'>&nbsp;&nbsp;&nbsp;</span>(Skin tone overriding)<br>"
dat += "<span style='border: 1px solid #161616; background-color: [SKINTONE2HEX(skin_tone)];'>&nbsp;&nbsp;&nbsp;</span>(Skin tone overriding)<br>"
else
dat += "<b>Vagina Color:</b></a><BR>"
dat += "<span style='border: 1px solid #161616; background-color: #[features["vag_color"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=vag_color;task=input'>Change</a><br>"
@@ -794,7 +804,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(features["has_breasts"])
if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE)
dat += "<b>Color:</b></a><BR>"
dat += "<span style='border: 1px solid #161616; background-color: #[skintone2hex(skin_tone)];'>&nbsp;&nbsp;&nbsp;</span>(Skin tone overriding)<br>"
dat += "<span style='border: 1px solid #161616; background-color: [SKINTONE2HEX(skin_tone)];'>&nbsp;&nbsp;&nbsp;</span>(Skin tone overriding)<br>"
else
dat += "<b>Color:</b></a><BR>"
dat += "<span style='border: 1px solid #161616; background-color: #[features["breasts_color"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=breasts_color;task=input'>Change</a><br>"
@@ -1426,6 +1436,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
eye_color = random_eye_color()
if("s_tone")
skin_tone = random_skin_tone()
use_custom_skin_tone = null
if("bag")
backbag = pick(GLOB.backbaglist)
if("suit")
@@ -1533,7 +1544,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
underwear = new_underwear
if("undie_color")
var/n_undie_color = input(user, "Choose your underwear's color.", "Character Preference", undie_color) as color|null
var/n_undie_color = input(user, "Choose your underwear's color.", "Character Preference", "#[undie_color]") as color|null
if(n_undie_color)
undie_color = sanitize_hexcolor(n_undie_color)
@@ -1543,7 +1554,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
undershirt = new_undershirt
if("shirt_color")
var/n_shirt_color = input(user, "Choose your undershirt's color.", "Character Preference", shirt_color) as color|null
var/n_shirt_color = input(user, "Choose your undershirt's color.", "Character Preference", "#[shirt_color]") as color|null
if(n_shirt_color)
shirt_color = sanitize_hexcolor(n_shirt_color)
@@ -1553,7 +1564,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
socks = new_socks
if("socks_color")
var/n_socks_color = input(user, "Choose your socks' color.", "Character Preference", socks_color) as color|null
var/n_socks_color = input(user, "Choose your socks' color.", "Character Preference", "#[socks_color]") as color|null
if(n_socks_color)
socks_color = sanitize_hexcolor(n_socks_color)
@@ -1610,7 +1621,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
to_chat(user, "<span class='danger'>Invalid color. Your color is not bright enough.</span>")
if("mutant_color2")
var/new_mutantcolor = input(user, "Choose your character's secondary alien/mutant color:", "Character Preference") as color|null
var/new_mutantcolor = input(user, "Choose your character's secondary alien/mutant color:", "Character Preference","#"+features["mcolor2"]) as color|null
if(new_mutantcolor)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
if(new_mutantcolor == "#000000")
@@ -1621,7 +1632,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
to_chat(user, "<span class='danger'>Invalid color. Your color is not bright enough.</span>")
if("mutant_color3")
var/new_mutantcolor = input(user, "Choose your character's tertiary alien/mutant color:", "Character Preference") as color|null
var/new_mutantcolor = input(user, "Choose your character's tertiary alien/mutant color:", "Character Preference","#"+features["mcolor3"]) as color|null
if(new_mutantcolor)
var/temp_hsv = RGBtoHSV(new_mutantcolor)
if(new_mutantcolor == "#000000")
@@ -1822,9 +1833,24 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["insect_markings"] = new_insect_markings
if("s_tone")
var/new_s_tone = input(user, "Choose your character's skin-tone:", "Character Preference") as null|anything in GLOB.skin_tones
var/list/choices = GLOB.skin_tones - GLOB.nonstandard_skin_tones
if(CONFIG_GET(number/allow_custom_skintones))
choices += "custom"
var/new_s_tone = input(user, "Choose your character's skin tone:", "Character Preference") as null|anything in choices
if(new_s_tone)
skin_tone = new_s_tone
if(new_s_tone == "custom")
var/default = use_custom_skin_tone ? skin_tone : null
var/custom_tone = input(user, "Choose your custom skin tone:", "Character Preference", default) as color|null
if(custom_tone)
var/temp_hsv = RGBtoHSV(custom_tone)
if(ReadHSV(temp_hsv)[3] < ReadHSV("#333333")[3]) // rgb(50,50,50)
to_chat(user,"<span class='danger'>Invalid color. Your color is not bright enough.</span>")
else
use_custom_skin_tone = TRUE
skin_tone = custom_tone
else
use_custom_skin_tone = FALSE
skin_tone = new_s_tone
if("taur")
var/list/snowflake_taur_list = list()
@@ -1922,12 +1948,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
//Genital code
if("cock_color")
var/new_cockcolor = input(user, "Penis color:", "Character Preference") as color|null
var/new_cockcolor = input(user, "Penis color:", "Character Preference","#"+features["cock_color"]) as color|null
if(new_cockcolor)
var/temp_hsv = RGBtoHSV(new_cockcolor)
if(new_cockcolor == "#000000")
features["cock_color"] = pref_species.default_color
else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
features["cock_color"] = sanitize_hexcolor(new_cockcolor)
else
to_chat(user,"<span class='danger'>Invalid color. Your color is not bright enough.</span>")
@@ -1941,8 +1967,19 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("cock_shape")
var/new_shape
new_shape = input(user, "Penis shape:", "Character Preference") as null|anything in GLOB.cock_shapes_list
var/list/hockeys = list()
if(pref_species.mutant_bodyparts["taur"])
var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]]
for(var/A in GLOB.cock_shapes_list)
var/datum/sprite_accessory/penis/P = GLOB.cock_shapes_list[A]
if(P.taur_icon && T.taur_mode & P.accepted_taurs)
LAZYSET(hockeys, "[A] (Taur)", A)
new_shape = input(user, "Penis shape:", "Character Preference") as null|anything in (GLOB.cock_shapes_list + hockeys)
if(new_shape)
features["cock_taur"] = FALSE
if(hockeys[new_shape])
new_shape = hockeys[new_shape]
features["cock_taur"] = TRUE
features["cock_shape"] = new_shape
if("cock_visibility")
@@ -1951,12 +1988,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["cock_visibility"] = n_vis
if("balls_color")
var/new_ballscolor = input(user, "Testicles Color:", "Character Preference") as color|null
var/new_ballscolor = input(user, "Testicles Color:", "Character Preference","#"+features["balls_color"]) as color|null
if(new_ballscolor)
var/temp_hsv = RGBtoHSV(new_ballscolor)
if(new_ballscolor == "#000000")
features["balls_color"] = pref_species.default_color
else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
features["balls_color"] = sanitize_hexcolor(new_ballscolor)
else
to_chat(user,"<span class='danger'>Invalid color. Your color is not bright enough.</span>")
@@ -1978,12 +2015,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["breasts_shape"] = new_shape
if("breasts_color")
var/new_breasts_color = input(user, "Breast Color:", "Character Preference") as color|null
var/new_breasts_color = input(user, "Breast Color:", "Character Preference","#"+features["breasts_color"]) as color|null
if(new_breasts_color)
var/temp_hsv = RGBtoHSV(new_breasts_color)
if(new_breasts_color == "#000000")
features["breasts_color"] = pref_species.default_color
else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
features["breasts_color"] = sanitize_hexcolor(new_breasts_color)
else
to_chat(user,"<span class='danger'>Invalid color. Your color is not bright enough.</span>")
@@ -2000,12 +2037,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["vag_shape"] = new_shape
if("vag_color")
var/new_vagcolor = input(user, "Vagina color:", "Character Preference") as color|null
var/new_vagcolor = input(user, "Vagina color:", "Character Preference","#"+features["vag_color"]) as color|null
if(new_vagcolor)
var/temp_hsv = RGBtoHSV(new_vagcolor)
if(new_vagcolor == "#000000")
features["vag_color"] = pref_species.default_color
else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
else if(ReadHSV(temp_hsv)[3] >= ReadHSV("#202020")[3])
features["vag_color"] = sanitize_hexcolor(new_vagcolor)
else
to_chat(user,"<span class='danger'>Invalid color. Your color is not bright enough.</span>")
@@ -2100,6 +2137,38 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(new_toggle_color)
hud_toggle_color = new_toggle_color
if("gender")
var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) as null|anything in list(MALE,FEMALE,"nonbinary","object")
if(!chosengender)
return
switch(chosengender)
if("nonbinary")
chosengender = PLURAL
features["body_model"] = pick(MALE, FEMALE)
if("object")
chosengender = NEUTER
features["body_model"] = MALE
else
features["body_model"] = chosengender
gender = chosengender
facial_hair_style = random_facial_hair_style(gender)
hair_style = random_hair_style(gender)
if("body_size")
var/min = CONFIG_GET(number/body_size_min)
var/max = CONFIG_GET(number/body_size_max)
var/danger = CONFIG_GET(number/threshold_body_size_slowdown)
var/new_body_size = input(user, "Choose your desired sprite size:\n([min*100]%-[max*100]%), Warning: May make your character look distorted[danger > min ? ", and an exponential slowdown will occur for those smaller than [danger*100]%!" : "!"]", "Character Preference", features["body_size"]*100) as num|null
if (new_body_size)
new_body_size = CLAMP(new_body_size * 0.01, min, max)
var/dorfy
if(danger > new_body_size)
dorfy = alert(user, "The chosen size appears to be smaller than the threshold of [danger*100]%, which will lead to an added exponential slowdown. Are you sure about that?", "Dwarfism Alert", "Yes", "Move it to the threshold", "No")
if(!dorfy || dorfy == "Move it above the threshold")
new_body_size = danger
if(dorfy != "No")
features["body_size"] = new_body_size
else
switch(href_list["preference"])
//CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj
@@ -2152,22 +2221,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("publicity")
if(unlock_content)
toggles ^= MEMBER_PUBLIC
if("gender")
var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) as null|anything in list(MALE,FEMALE,"nonbinary","object")
if(!chosengender)
return
switch(chosengender)
if("nonbinary")
chosengender = PLURAL
features["body_model"] = pick(MALE, FEMALE)
if("object")
chosengender = NEUTER
features["body_model"] = MALE
else
features["body_model"] = chosengender
gender = chosengender
facial_hair_style = random_facial_hair_style(gender)
hair_style = random_hair_style(gender)
if("body_model")
features["body_model"] = features["body_model"] == MALE ? FEMALE : MALE
@@ -2391,6 +2444,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.wing_color = wing_color
character.skin_tone = skin_tone
character.dna.skin_tone_override = use_custom_skin_tone ? skin_tone : null
character.hair_style = hair_style
character.facial_hair_style = facial_hair_style
character.underwear = underwear
@@ -2412,6 +2466,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
pref_species = new /datum/species/human
save_character()
var/old_size = character.dna.features["body_size"]
character.dna.features = features.Copy()
character.set_species(chosen_species, icon_update = FALSE, pref_load = TRUE)
character.dna.real_name = character.real_name
@@ -2433,6 +2489,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.give_genitals(TRUE) //character.update_genitals() is already called on genital.update_appearance()
character.dna.update_body_size(old_size)
SEND_SIGNAL(character, COMSIG_HUMAN_PREFS_COPIED_TO, src, icon_updates, roundstart_checks)
//let's be sure the character updates
+57 -18
View File
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
#define SAVEFILE_VERSION_MAX 27
#define SAVEFILE_VERSION_MAX 29
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -120,10 +120,14 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(fexists(vr_path))
var/list/json_from_file = json_decode(file2text(vr_path))
if(json_from_file)
digestable = json_from_file["digestable"]
devourable = json_from_file["devourable"]
feeding = json_from_file["feeding"]
lickable = json_from_file["lickable"]
if(json_from_file["digestable"])
ENABLE_BITFIELD(vore_flags,DIGESTABLE)
if(json_from_file["devourable"])
ENABLE_BITFIELD(vore_flags,DEVOURABLE)
if(json_from_file["feeding"])
ENABLE_BITFIELD(vore_flags,FEEDING)
if(json_from_file["lickable"])
ENABLE_BITFIELD(vore_flags,LICKABLE)
belly_prefs = json_from_file["belly_prefs"]
vore_taste = json_from_file["vore_taste"]
@@ -151,6 +155,32 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(tennis == "Hidden")
features["balls_visibility"] = GEN_VISIBLE_NEVER
if(current_version < 28)
var/hockey
S["feature_cock_shape"] >> hockey
var/list/malformed_hockeys = list("Taur, Flared" = "Flared", "Taur, Knotted" = "Knotted", "Taur, Tapered" = "Tapered")
if(malformed_hockeys[hockey])
features["cock_shape"] = malformed_hockeys[hockey]
features["cock_taur"] = TRUE
if(current_version < 29)
var/digestable
var/devourable
var/feeding
var/lickable
S["digestable"] >> digestable
S["devourable"] >> devourable
S["feeding"] >> feeding
S["lickable"] >> lickable
if(digestable)
ENABLE_BITFIELD(vore_flags,DIGESTABLE)
if(devourable)
ENABLE_BITFIELD(vore_flags,DEVOURABLE)
if(feeding)
ENABLE_BITFIELD(vore_flags,FEEDING)
if(lickable)
ENABLE_BITFIELD(vore_flags,LICKABLE)
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey)
return
@@ -387,10 +417,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["body_is_always_random"] >> be_random_body
S["gender"] >> gender
S["body_model"] >> features["body_model"]
S["body_size"] >> features["body_size"]
S["age"] >> age
S["hair_color"] >> hair_color
S["facial_hair_color"] >> facial_hair_color
S["eye_color"] >> eye_color
S["use_custom_skin_tone"] >> use_custom_skin_tone
S["skin_tone"] >> skin_tone
S["hair_style_name"] >> hair_style
S["facial_style_name"] >> facial_hair_style
@@ -457,6 +489,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_cock_color"] >> features["cock_color"]
S["feature_cock_length"] >> features["cock_length"]
S["feature_cock_diameter"] >> features["cock_diameter"]
S["feature_cock_taur"] >> features["cock_taur"]
S["feature_cock_visibility"] >> features["cock_visibility"]
//balls features
S["feature_has_balls"] >> features["has_balls"]
@@ -488,11 +521,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
else //We have no old flavortext, default to new
S["feature_flavor_text"] >> features["flavor_text"]
S["digestable"] >> digestable
S["devourable"] >> devourable
S["feeding"] >> feeding
S["vore_flags"] >> vore_flags
S["vore_taste"] >> vore_taste
S["lickable"] >> lickable
S["belly_prefs"] >> belly_prefs
//try to fix any outdated data if necessary
@@ -538,7 +568,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
hair_color = sanitize_hexcolor(hair_color, 3, 0)
facial_hair_color = sanitize_hexcolor(facial_hair_color, 3, 0)
eye_color = sanitize_hexcolor(eye_color, 3, 0)
skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones)
use_custom_skin_tone = sanitize_integer(use_custom_skin_tone, FALSE, TRUE, initial(use_custom_skin_tone))
if(use_custom_skin_tone && CONFIG_GET(number/allow_custom_skintones))
skin_tone = sanitize_hexcolor(skin_tone, 6, TRUE, "#FFFFFF")
else
skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones - GLOB.nonstandard_skin_tones, initial(skin_tone))
horn_color = sanitize_hexcolor(horn_color, 3, FALSE)
wing_color = sanitize_hexcolor(wing_color, 3, FALSE, "#FFFFFF")
backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag))
@@ -559,6 +593,14 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
features["insect_markings"] = sanitize_inlist(features["insect_markings"], GLOB.insect_markings_list, "None")
features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list)
var/static/size_min
if(!size_min)
size_min = CONFIG_GET(number/body_size_min)
var/static/size_max
if(!size_max)
size_max = CONFIG_GET(number/body_size_max)
features["body_size"] = sanitize_integer(features["body_size"], size_min, size_max, RESIZE_DEFAULT_SIZE)
var/static/list/B_sizes
if(!B_sizes)
var/list/L = CONFIG_GET(keyed_list/breasts_cups_prefs)
@@ -600,10 +642,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
all_quirks = SANITIZE_LIST(all_quirks)
lickable = sanitize_integer(lickable, FALSE, TRUE, initial(lickable))
devourable = sanitize_integer(devourable, FALSE, TRUE, initial(devourable))
digestable = sanitize_integer(digestable, FALSE, TRUE, initial(digestable))
feeding = sanitize_integer(feeding, FALSE, TRUE, initial(feeding))
vore_flags = sanitize_integer(vore_flags, 0, MAX_VORE_FLAG, 0)
vore_taste = copytext(vore_taste, 1, MAX_TASTE_LEN)
belly_prefs = SANITIZE_LIST(belly_prefs)
@@ -634,10 +673,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["body_is_always_random"] , be_random_body)
WRITE_FILE(S["gender"] , gender)
WRITE_FILE(S["body_model"] , features["body_model"])
WRITE_FILE(S["body_size"] , features["body_size"])
WRITE_FILE(S["age"] , age)
WRITE_FILE(S["hair_color"] , hair_color)
WRITE_FILE(S["facial_hair_color"] , facial_hair_color)
WRITE_FILE(S["eye_color"] , eye_color)
WRITE_FILE(S["use_custom_skin_tone"] , use_custom_skin_tone)
WRITE_FILE(S["skin_tone"] , skin_tone)
WRITE_FILE(S["hair_style_name"] , hair_style)
WRITE_FILE(S["facial_style_name"] , facial_hair_style)
@@ -673,6 +714,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["feature_cock_shape"], features["cock_shape"])
WRITE_FILE(S["feature_cock_color"], features["cock_color"])
WRITE_FILE(S["feature_cock_length"], features["cock_length"])
WRITE_FILE(S["feature_cock_taur"], features["cock_taur"])
WRITE_FILE(S["feature_cock_visibility"], features["cock_visibility"])
WRITE_FILE(S["feature_has_balls"], features["has_balls"])
@@ -710,11 +752,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Quirks
WRITE_FILE(S["all_quirks"] , all_quirks)
WRITE_FILE(S["digestable"] , digestable)
WRITE_FILE(S["devourable"] , devourable)
WRITE_FILE(S["feeding"] , feeding)
WRITE_FILE(S["vore_flags"] , vore_flags)
WRITE_FILE(S["vore_taste"] , vore_taste)
WRITE_FILE(S["lickable"] , lickable)
WRITE_FILE(S["belly_prefs"] , belly_prefs)
cit_character_pref_save(S)
+1 -9
View File
@@ -219,14 +219,13 @@
if(isitem(target))
var/obj/item/I = target
I.item_state = initial(picked_item.item_state)
I.item_color = initial(picked_item.item_color)
var/obj/item/clothing/CL = target
var/obj/item/clothing/PCL = new picked_item
if(istype(CL) && istype(PCL))
CL.flags_cover = PCL.flags_cover
CL.flags_inv = PCL.flags_inv
CL.mutantrace_variation = PCL.mutantrace_variation
CL.alternate_worn_icon = PCL.alternate_worn_icon
CL.mob_overlay_icon = PCL.mob_overlay_icon
qdel(PCL)
target.icon = initial(picked_item.icon)
@@ -238,7 +237,6 @@
P.desc = initial(picked_item.desc)
P.icon_state = initial(picked_item.icon_state)
P.item_state = initial(picked_item.item_state)
P.item_color = initial(picked_item.item_color)
P.overlays_offsets = initial(picked_item.overlays_offsets)
P.set_new_overlays()
P.update_icon()
@@ -269,7 +267,6 @@
name = "black jumpsuit"
icon_state = "black"
item_state = "bl_suit"
item_color = "black"
desc = "It's a plain jumpsuit. It has a small dial on the wrist."
sensor_mode = SENSOR_OFF //Hey who's this guy on the Syndicate Shuttle??
random_sensor = FALSE
@@ -284,7 +281,6 @@
desc = "A tough jumpsuit woven from alloy threads. It can take on the appearance of other jumpsuits."
icon_state = "engine"
item_state = "engi_suit"
item_color = "engine"
/obj/item/clothing/under/chameleon/Initialize()
. = ..()
@@ -394,7 +390,6 @@
name = "grey cap"
desc = "It's a baseball hat in a tasteful grey colour."
icon_state = "greysoft"
item_color = "grey"
resistance_flags = NONE
armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
@@ -494,7 +489,6 @@
/obj/item/clothing/shoes/chameleon
name = "black shoes"
icon_state = "black"
item_color = "black"
desc = "A pair of black shoes."
permeability_coefficient = 0.05
resistance_flags = NONE
@@ -520,7 +514,6 @@
/obj/item/clothing/shoes/chameleon/noslip
name = "black shoes"
icon_state = "black"
item_color = "black"
desc = "A pair of black shoes."
clothing_flags = NOSLIP
@@ -639,7 +632,6 @@
desc = "A neosilk clip-on tie."
icon = 'icons/obj/clothing/neck.dmi'
icon_state = "blacktie"
item_color = "blacktie"
resistance_flags = NONE
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
+2 -195
View File
@@ -3,6 +3,7 @@
resistance_flags = FLAMMABLE
max_integrity = 200
integrity_failure = 0.4
block_priority = BLOCK_PRIORITY_CLOTHING
var/damaged_clothes = 0 //similar to machine's BROKEN stat and structure's broken var
var/flash_protect = 0 //What level of bright light protection item has. 1 = Flashers, Flashes, & Flashbangs | 2 = Welding | -1 = OH GOD WELDING BURNT OUT MY RETINAS
var/tint = 0 //Sets the item's level of visual impairment tint, normally set to the same as flash_protect
@@ -46,25 +47,12 @@
//Add a "exclude" string to do the opposite, making it only only species listed that can't wear it.
//You append this to clothing objects.
//Polychrome stuff:
var/hasprimary = FALSE //These vars allow you to choose which overlays a clothing has
var/hassecondary = FALSE
var/hastertiary = FALSE
var/primary_color = "#FFFFFF" //RGB in hexcode
var/secondary_color = "#FFFFFF"
var/tertiary_color = "#808080"
//No idea what this is but eh -tori
var/force_alternate_icon = FALSE
/obj/item/clothing/Initialize()
. = ..()
if(CHECK_BITFIELD(clothing_flags, VOICEBOX_TOGGLABLE))
actions_types += /datum/action/item_action/toggle_voice_box
if(ispath(pocket_storage_component_path))
LoadComponent(pocket_storage_component_path)
if(hasprimary | hassecondary | hastertiary) //Checks if polychrome is enabled
update_icon() //Applies the overlays and default colors onto the clothes on spawn.
/obj/item/clothing/MouseDrop(atom/over_object)
. = ..()
@@ -149,8 +137,6 @@
how_cool_are_your_threads += "Adding or removing items from [src] makes no noise.\n"
how_cool_are_your_threads += "</span>"
. += how_cool_are_your_threads.Join()
if(hasprimary | hassecondary | hastertiary) //Checks if polychrome is enabled
. += "<span class='notice'>Alt-click to recolor it.</span>"
/obj/item/clothing/obj_break(damage_flag)
if(!damaged_clothes)
@@ -189,178 +175,11 @@ BLIND // can't see anything
/proc/generate_female_clothing(index,t_color,icon,type)
var/icon/female_clothing_icon = icon("icon"=icon, "icon_state"=t_color)
var/icon/female_s = icon("icon"='icons/mob/uniform.dmi', "icon_state"="[(type == FEMALE_UNIFORM_FULL) ? "female_full" : "female_top"]")
var/icon/female_s = icon("icon"='icons/mob/clothing/uniform.dmi', "icon_state"="[(type == FEMALE_UNIFORM_FULL) ? "female_full" : "female_top"]")
female_clothing_icon.Blend(female_s, ICON_MULTIPLY)
female_clothing_icon = fcopy_rsc(female_clothing_icon)
GLOB.female_clothing_icons[index] = female_clothing_icon
/obj/item/clothing/under/verb/toggle()
set name = "Adjust Suit Sensors"
set category = "Object"
set src in usr
var/mob/M = usr
if (istype(M, /mob/dead/))
return
if (!can_use(M))
return
if(src.has_sensor == LOCKED_SENSORS)
to_chat(usr, "The controls are locked.")
return 0
if(src.has_sensor == BROKEN_SENSORS)
to_chat(usr, "The sensors have shorted out!")
return 0
if(src.has_sensor <= NO_SENSORS)
to_chat(usr, "This suit does not have any sensors.")
return 0
var/list/modes = list("Off", "Binary vitals", "Exact vitals", "Tracking beacon")
var/switchMode = input("Select a sensor mode:", "Suit Sensor Mode", modes[sensor_mode + 1]) in modes
if(get_dist(usr, src) > 1)
to_chat(usr, "<span class='warning'>You have moved too far away!</span>")
return
sensor_mode = modes.Find(switchMode) - 1
if (src.loc == usr)
switch(sensor_mode)
if(0)
to_chat(usr, "<span class='notice'>You disable your suit's remote sensing equipment.</span>")
if(1)
to_chat(usr, "<span class='notice'>Your suit will now only report whether you are alive or dead.</span>")
if(2)
to_chat(usr, "<span class='notice'>Your suit will now only report your exact vital lifesigns.</span>")
if(3)
to_chat(usr, "<span class='notice'>Your suit will now report your exact vital lifesigns as well as your coordinate position.</span>")
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
if(H.w_uniform == src)
H.update_suit_sensors()
/obj/item/clothing/under/CtrlClick(mob/user)
. = ..()
if (!(item_flags & IN_INVENTORY))
return
if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
if(has_sensor == LOCKED_SENSORS)
to_chat(user, "The controls are locked.")
return
if(has_sensor == BROKEN_SENSORS)
to_chat(user, "The sensors have shorted out!")
return
if(has_sensor <= NO_SENSORS)
to_chat(user, "This suit does not have any sensors.")
return
sensor_mode = SENSOR_COORDS
to_chat(user, "<span class='notice'>Your suit will now report your exact vital lifesigns as well as your coordinate position.</span>")
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.w_uniform == src)
H.update_suit_sensors()
/obj/item/clothing/under/AltClick(mob/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
if(attached_accessory)
remove_accessory(user)
else
rolldown()
// Polychrome stuff:
if(hasprimary | hassecondary | hastertiary)
var/choice = input(user,"polychromic thread options", "Clothing Recolor") as null|anything in list("[hasprimary ? "Primary Color" : ""]", "[hassecondary ? "Secondary Color" : ""]", "[hastertiary ? "Tertiary Color" : ""]") //generates a list depending on the enabled overlays
switch(choice) //Lets the list's options actually lead to something
if("Primary Color")
var/primary_color_input = input(usr,"","Choose Primary Color",primary_color) as color|null //color input menu, the "|null" adds a cancel button to it.
if(primary_color_input) //Checks if the color selected is NULL, rejects it if it is NULL.
primary_color = sanitize_hexcolor(primary_color_input, desired_format=6, include_crunch=1) //formats the selected color properly
update_icon() //updates the item icon
user.regenerate_icons() //updates the worn icon. Probably a bad idea, but it works.
if("Secondary Color")
var/secondary_color_input = input(usr,"","Choose Secondary Color",secondary_color) as color|null
if(secondary_color_input)
secondary_color = sanitize_hexcolor(secondary_color_input, desired_format=6, include_crunch=1)
update_icon()
user.regenerate_icons()
if("Tertiary Color")
var/tertiary_color_input = input(usr,"","Choose Tertiary Color",tertiary_color) as color|null
if(tertiary_color_input)
tertiary_color = sanitize_hexcolor(tertiary_color_input, desired_format=6, include_crunch=1)
update_icon()
user.regenerate_icons()
return TRUE
/obj/item/clothing/neck/AltClick(mob/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
// Polychrome stuff:
if(hasprimary | hassecondary | hastertiary)
var/choice = input(user,"polychromic thread options", "Clothing Recolor") as null|anything in list("[hasprimary ? "Primary Color" : ""]", "[hassecondary ? "Secondary Color" : ""]", "[hastertiary ? "Tertiary Color" : ""]") //generates a list depending on the enabled overlays
switch(choice) //Lets the list's options actually lead to something
if("Primary Color")
var/primary_color_input = input(usr,"","Choose Primary Color",primary_color) as color|null //color input menu, the "|null" adds a cancel button to it.
if(primary_color_input) //Checks if the color selected is NULL, rejects it if it is NULL.
primary_color = sanitize_hexcolor(primary_color_input, desired_format=6, include_crunch=1) //formats the selected color properly
update_icon() //updates the item icon
user.regenerate_icons() //updates the worn icon. Probably a bad idea, but it works.
if("Secondary Color")
var/secondary_color_input = input(usr,"","Choose Secondary Color",secondary_color) as color|null
if(secondary_color_input)
secondary_color = sanitize_hexcolor(secondary_color_input, desired_format=6, include_crunch=1)
update_icon()
user.regenerate_icons()
if("Tertiary Color")
var/tertiary_color_input = input(usr,"","Choose Tertiary Color",tertiary_color) as color|null
if(tertiary_color_input)
tertiary_color = sanitize_hexcolor(tertiary_color_input, desired_format=6, include_crunch=1)
update_icon()
user.regenerate_icons()
return TRUE
/obj/item/clothing/under/verb/jumpsuit_adjust()
set name = "Adjust Jumpsuit Style"
set category = null
set src in usr
rolldown()
/obj/item/clothing/under/proc/rolldown()
if(!can_use(usr))
return
if(!can_adjust)
to_chat(usr, "<span class='warning'>You cannot wear this suit any differently!</span>")
return
if(toggle_jumpsuit_adjust())
to_chat(usr, "<span class='notice'>You adjust the suit to wear it more casually.</span>")
else
to_chat(usr, "<span class='notice'>You adjust the suit back to normal.</span>")
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
H.update_inv_w_uniform()
H.update_body()
/obj/item/clothing/under/proc/toggle_jumpsuit_adjust()
adjusted = !adjusted
if(adjusted)
if(fitted != FEMALE_UNIFORM_TOP)
fitted = NO_FEMALE_UNIFORM
if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted
body_parts_covered &= ~CHEST
else
fitted = initial(fitted)
if(!alt_covers_chest)
body_parts_covered |= CHEST
return adjusted
/obj/item/clothing/proc/weldingvisortoggle(mob/user) //proc to toggle welding visors on helmets, masks, goggles, etc.
if(!can_use(user))
return FALSE
@@ -440,15 +259,3 @@ BLIND // can't see anything
return FALSE
return TRUE
/obj/item/clothing/update_overlays() // Polychrome stuff
. = ..()
if(hasprimary) //Checks if the overlay is enabled
var/mutable_appearance/primary_overlay = mutable_appearance(icon, "[item_color]-primary", color = primary_color) //Automagically picks overlays
. += primary_overlay //Applies the coloured overlay onto the item sprite. but NOT the mob sprite.
if(hassecondary)
var/mutable_appearance/secondary_overlay = mutable_appearance(icon, "[item_color]-secondary", color = secondary_color)
. += secondary_overlay
if(hastertiary)
var/mutable_appearance/tertiary_overlay = mutable_appearance(icon, "[item_color]-tertiary", color = tertiary_color)
. += tertiary_overlay
+4 -4
View File
@@ -132,7 +132,7 @@
name = "prescription night vision goggles"
desc = "NVGs but for those with nearsightedness."
vision_correction = 1
/obj/item/clothing/glasses/night/syndicate
name = "combat night vision goggles"
desc = "See everything, without fear."
@@ -346,11 +346,11 @@
add_atom_colour("#[user.eye_color]", FIXED_COLOUR_PRIORITY)
colored_before = TRUE
/obj/item/clothing/glasses/sunglasses/blindfold/white/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE)
. = list()
/obj/item/clothing/glasses/sunglasses/blindfold/white/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
. = ..()
if(!isinhands && ishuman(loc) && !colored_before)
var/mob/living/carbon/human/H = loc
var/mutable_appearance/M = mutable_appearance('icons/mob/eyes.dmi', "blindfoldwhite")
var/mutable_appearance/M = mutable_appearance('icons/mob/clothing/eyes.dmi', "blindfoldwhite")
M.appearance_flags |= RESET_COLOR
M.color = "#[H.eye_color]"
. += M
@@ -1,7 +1,7 @@
/obj/item/clothing/glasses/phantomthief
name = "suspicious paper mask"
desc = "A cheap, Syndicate-branded paper face mask. They'll never see it coming."
alternate_worn_icon = 'icons/mob/mask.dmi'
mob_overlay_icon = 'icons/mob/clothing/mask.dmi'
icon = 'icons/obj/clothing/masks.dmi'
icon_state = "s-ninja"
item_state = "s-ninja"
@@ -23,8 +23,8 @@
else
. += "<span class='notice'>[DisplayTimeText(nextadrenalinepop - world.time)] left before the adrenaline injector can be used again."
/obj/item/clothing/glasses/phantomthief/syndicate/proc/injectadrenaline(mob/user, combatmodestate)
if(istype(user) && combatmodestate && world.time >= nextadrenalinepop)
/obj/item/clothing/glasses/phantomthief/syndicate/proc/injectadrenaline(mob/living/user, was_forced = FALSE)
if(user.combat_flags & COMBAT_FLAG_COMBAT_TOGGLED && world.time >= nextadrenalinepop)
nextadrenalinepop = world.time + 5 MINUTES
user.reagents.add_reagent(/datum/reagent/syndicateadrenals, 5)
user.playsound_local(user, 'sound/misc/adrenalinject.ogg', 100, 0, pressure_affected = FALSE)
+2 -2
View File
@@ -26,8 +26,8 @@
user.visible_message("<span class='suicide'>\the [src] are forcing [user]'s hands around [user.p_their()] neck! It looks like the gloves are possessed!</span>")
return OXYLOSS
/obj/item/clothing/gloves/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE)
. = list()
/obj/item/clothing/gloves/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
. = ..()
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves")
+6 -41
View File
@@ -1,3 +1,6 @@
/obj/item/clothing/gloves/color
dying_key = DYE_REGISTRY_GLOVES
/obj/item/clothing/gloves/color/yellow
desc = "These gloves will protect the wearer from electric shock."
name = "insulated gloves"
@@ -5,7 +8,6 @@
item_state = "ygloves"
siemens_coefficient = 0
permeability_coefficient = 0.05
item_color="yellow"
resistance_flags = NONE
var/can_be_cut = 1
@@ -16,7 +18,6 @@
item_state = "ygloves"
siemens_coefficient = 1 //Set to a default of 1, gets overridden in New()
permeability_coefficient = 0.05
item_color="yellow"
resistance_flags = NONE
var/can_be_cut = 1
@@ -70,21 +71,14 @@
name = "black gloves"
icon_state = "black"
item_state = "blackgloves"
item_color="black"
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
resistance_flags = NONE
var/can_be_cut = 1
var/can_be_cut = TRUE
strip_mod = 1.2
/obj/item/clothing/gloves/color/black/hos
item_color = "hosred" //Exists for washing machines. Is not different from black gloves in any way.
/obj/item/clothing/gloves/color/black/ce
item_color = "chief" //Exists for washing machines. Is not different from black gloves in any way.
/obj/item/clothing/gloves/color/black/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/wirecutters))
if(can_be_cut && icon_state == initial(icon_state))//only if not dyed
@@ -99,15 +93,12 @@
desc = "A pair of gloves, they don't look special in any way."
icon_state = "orange"
item_state = "orangegloves"
item_color="orange"
/obj/item/clothing/gloves/color/red
name = "red gloves"
desc = "A pair of gloves, they don't look special in any way."
icon_state = "red"
item_state = "redgloves"
item_color = "red"
/obj/item/clothing/gloves/color/red/insulated
name = "insulated gloves"
@@ -121,68 +112,48 @@
desc = "A pair of gloves, they don't look special in any way."
icon_state = "rainbow"
item_state = "rainbowgloves"
item_color = "rainbow"
/obj/item/clothing/gloves/color/rainbow/clown
item_color = "clown"
/obj/item/clothing/gloves/color/blue
name = "blue gloves"
desc = "A pair of gloves, they don't look special in any way."
icon_state = "blue"
item_state = "bluegloves"
item_color="blue"
/obj/item/clothing/gloves/color/purple
name = "purple gloves"
desc = "A pair of gloves, they don't look special in any way."
icon_state = "purple"
item_state = "purplegloves"
item_color="purple"
/obj/item/clothing/gloves/color/green
name = "green gloves"
desc = "A pair of gloves, they don't look special in any way."
icon_state = "green"
item_state = "greengloves"
item_color="green"
/obj/item/clothing/gloves/color/grey
name = "grey gloves"
desc = "A pair of gloves, they don't look special in any way."
icon_state = "gray"
item_state = "graygloves"
item_color="grey"
/obj/item/clothing/gloves/color/grey/rd
item_color = "director" //Exists for washing machines. Is not different from gray gloves in any way.
/obj/item/clothing/gloves/color/grey/hop
item_color = "hop" //Exists for washing machines. Is not different from gray gloves in any way.
/obj/item/clothing/gloves/color/light_brown
name = "light brown gloves"
desc = "A pair of gloves, they don't look special in any way."
icon_state = "lightbrown"
item_state = "lightbrowngloves"
item_color="light brown"
/obj/item/clothing/gloves/color/brown
name = "brown gloves"
desc = "A pair of gloves, they don't look special in any way."
icon_state = "brown"
item_state = "browngloves"
item_color="brown"
/obj/item/clothing/gloves/color/brown/cargo
item_color = "cargo" //Exists for washing machines. Is not different from brown gloves in any way.
/obj/item/clothing/gloves/color/captain
desc = "Regal blue gloves, with a nice gold trim, a diamond anti-shock coating, and an integrated thermal barrier. Swanky."
name = "captain's gloves"
icon_state = "captain"
item_state = "egloves"
item_color = "captain"
siemens_coefficient = 0
permeability_coefficient = 0.05
cold_protection = HANDS
@@ -199,7 +170,6 @@
item_state = "lgloves"
siemens_coefficient = 0.3
permeability_coefficient = 0.01
item_color="mime"
transfer_prints = TRUE
resistance_flags = NONE
var/carrytrait = TRAIT_QUICK_CARRY
@@ -207,18 +177,17 @@
/obj/item/clothing/gloves/color/latex/equipped(mob/user, slot)
..()
if(slot == SLOT_GLOVES)
ADD_TRAIT(user, carrytrait, CLOTHING_TRAIT)
ADD_TRAIT(user, carrytrait, GLOVE_TRAIT)
/obj/item/clothing/gloves/color/latex/dropped(mob/user)
..()
REMOVE_TRAIT(user, carrytrait, CLOTHING_TRAIT)
REMOVE_TRAIT(user, carrytrait, GLOVE_TRAIT)
/obj/item/clothing/gloves/color/latex/nitrile
name = "nitrile gloves"
desc = "Pricy sterile gloves that are stronger than latex. Transfers advanced paramedical knowledge to the wearer via the use of nanochips."
icon_state = "nitrile"
item_state = "nitrilegloves"
item_color = "cmo"
transfer_prints = FALSE
carrytrait = TRAIT_QUICKER_CARRY
@@ -236,7 +205,3 @@
desc = "These look pretty fancy."
icon_state = "white"
item_state = "wgloves"
item_color="white"
/obj/item/clothing/gloves/color/white/redcoat
item_color = "redcoat" //Exists for washing machines. Is not different from white gloves in any way.
+128 -51
View File
@@ -4,7 +4,6 @@
desc = "Plain black gloves without fingertips for the hard working."
icon_state = "fingerless"
item_state = "fingerless"
item_color = null //So they don't wash.
transfer_prints = TRUE
strip_delay = 40
equip_delay_other = 20
@@ -12,6 +11,133 @@
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
strip_mod = 0.9
/obj/item/clothing/gloves/fingerless/pugilist
name = "armwraps"
desc = "A series of armwraps. Makes you pretty keen to start punching people."
icon_state = "armwraps"
item_state = "armwraps"
body_parts_covered = ARMS
cold_protection = ARMS
strip_delay = 300 //you can't just yank them off
///Extra damage through the punch.
var/enhancement = 0 //it's a +0 to your punches because it isn't magical
///Main trait added by the gloves to the user on wear.
var/inherited_trait = TRAIT_NOGUNS //what are you, dishonoroable?
///Secondary trait added by the gloves to the user on wear.
var/secondary_trait = TRAIT_FEARLESS //what are you, a coward?
/obj/item/clothing/gloves/fingerless/pugilist/equipped(mob/user, slot)
. = ..()
if(slot == SLOT_GLOVES)
if(ishuman(user))
var/mob/living/carbon/human/H = user
ADD_TRAIT(H, TRAIT_PUGILIST, GLOVE_TRAIT)
ADD_TRAIT(H, inherited_trait, GLOVE_TRAIT)
ADD_TRAIT(H, secondary_trait, GLOVE_TRAIT)
H.dna.species.punchdamagehigh += enhancement
H.dna.species.punchdamagelow += enhancement
/obj/item/clothing/gloves/fingerless/pugilist/dropped(mob/user)
REMOVE_TRAIT(user, TRAIT_PUGILIST, GLOVE_TRAIT)
REMOVE_TRAIT(user, inherited_trait, GLOVE_TRAIT)
REMOVE_TRAIT(user, secondary_trait, GLOVE_TRAIT)
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.dna.species.punchdamagehigh = initial(H.dna.species.punchdamagehigh)
H.dna.species.punchdamagelow = initial(H.dna.species.punchdamagelow)
return ..()
/obj/item/clothing/gloves/fingerless/pugilist/chaplain
name = "armwraps of unyielding resolve"
desc = "A series of armwraps, soaked in holy water. Makes you pretty keen to smite evil magic users."
resistance_flags = FIRE_PROOF | ACID_PROOF
enhancement = 2 //It is not magic that makes you punch harder, but force of will. Trust me.
secondary_trait = TRAIT_ANTIMAGIC
var/chaplain_spawnable = TRUE
/obj/item/clothing/gloves/fingerless/pugilist/chaplain/Initialize()
. = ..()
AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, null, FALSE)
/obj/item/clothing/gloves/fingerless/pugilist/magic
name = "armwraps of mighty fists"
desc = "A series of armwraps. Makes you pretty keen to go adventuring and punch dragons."
resistance_flags = FIRE_PROOF | ACID_PROOF //magic items are harder to damage with energy this is a dnd joke okay?
enhancement = 1 //They're +1!
/obj/item/clothing/gloves/fingerless/pugilist/hungryghost
name = "armwraps of the hungry ghost"
desc = "A series of blackened, bloodstained armwraps stitched with strange geometric symbols. Makes you pretty keen to commit horrible acts against the living through bloody carnage."
icon_state = "narsiearmwraps"
item_state = "narsiearmwraps"
resistance_flags = FIRE_PROOF | ACID_PROOF
armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 35, "rad" = 0, "fire" = 50, "acid" = 50)
enhancement = 3
secondary_trait = TRAIT_KI_VAMPIRE
/obj/item/clothing/gloves/fingerless/pugilist/brassmountain
name = "armbands of the brass mountain"
desc = "A series of scolding hot brass armbands. Makes you pretty keen to bring the light to the unenlightened through unmitigated violence."
icon_state = "ratvararmwraps"
item_state = "ratvararmwraps"
resistance_flags = FIRE_PROOF | ACID_PROOF
armor = list("melee" = 10, "bullet" = 0, "laser" = -10, "energy" = 0, "bomb" = 0, "bio" = 35, "rad" = 0, "fire" = 50, "acid" = 50)
enhancement = 4 //The artifice of Ratvar is unmatched except when it is.
secondary_trait = TRAIT_STRONG_GRABBER
/obj/item/clothing/gloves/fingerless/pugilist/rapid
name = "Bands of the North Star"
desc = "The armbands of a deadly martial artist. Makes you pretty keen to put an end to evil in an extremely violent manner."
icon_state = "rapid"
item_state = "rapid"
enhancement = 10 //omae wa mou shindeiru
var/warcry = "AT"
secondary_trait = TRAIT_NOSOFTCRIT //basically extra health
/obj/item/clothing/gloves/fingerless/pugilist/rapid/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, GLOVE_TRAIT)
/obj/item/clothing/gloves/fingerless/pugilist/rapid/Touch(atom/target, proximity = TRUE)
if(!isliving(target))
return
var/mob/living/M = loc
M.changeNext_move(CLICK_CD_RAPID)
if(warcry)
M.say("[warcry]", ignore_spam = TRUE, forced = TRUE)
return FALSE
/obj/item/clothing/gloves/fingerless/pugilist/rapid/AltClick(mob/user)
var/input = stripped_input(user,"What do you want your battlecry to be? Max length of 6 characters.", ,"", 7)
if(input)
warcry = input
/obj/item/clothing/gloves/fingerless/pugilist/hug
name = "Hugs of the North Star"
desc = "The armbands of a humble friend. Makes you pretty keen to go let everyone know how much you appreciate them!"
icon_state = "rapid"
item_state = "rapid"
enhancement = 0
secondary_trait = TRAIT_PACIFISM //You are only here to hug and be friends!
/obj/item/clothing/gloves/fingerless/pugilist/hug/Touch(mob/target, proximity = TRUE)
if(!isliving(target))
return
var/mob/living/M = loc
if(M.a_intent != INTENT_HELP)
return FALSE
if(target.stat != CONSCIOUS) //Can't hug people who are dying/dead
return FALSE
else
M.changeNext_move(CLICK_CD_RAPID)
return FALSE
/obj/item/clothing/gloves/botanic_leather
name = "botanist's leather gloves"
desc = "These leather gloves protect against thorns, barbs, prickles, spikes and other harmful objects of floral origin. They're also quite warm."
@@ -48,7 +174,6 @@
desc = "For when you're expecting to get slapped on the wrist. Offers modest protection to your arms."
icon_state = "bracers"
item_state = "bracers"
item_color = null //So they don't wash.
transfer_prints = TRUE
strip_delay = 40
equip_delay_other = 20
@@ -59,54 +184,6 @@
resistance_flags = NONE
armor = list("melee" = 15, "bullet" = 35, "laser" = 35, "energy" = 20, "bomb" = 35, "bio" = 35, "rad" = 35, "fire" = 0, "acid" = 0)
/obj/item/clothing/gloves/rapid
name = "Gloves of the North Star"
desc = "Just looking at these fills you with an urge to beat the shit out of people. Violently."
icon_state = "rapid"
item_state = "rapid"
transfer_prints = TRUE
var/warcry = "AT"
/obj/item/clothing/gloves/rapid/Touch(mob/living/target,proximity = TRUE)
if(!istype(target))
return
var/mob/living/M = loc
M.changeNext_move(CLICK_CD_RAPID)
M.adjustStaminaLoss(-3.5) // used to be -2 with some comment about stamina buffer management but *shrug -hatterhat
if(warcry)
M.say("[warcry]", ignore_spam = TRUE, forced = "north star warcry")
.= FALSE
/obj/item/clothing/gloves/rapid/attack_self(mob/user)
var/input = stripped_input(user,"What do you want your battlecry to be? Max length of 6 characters.", ,"", 7)
if(input)
warcry = input
/obj/item/clothing/gloves/rapid/hug
name = "Hugs of the North Star"
desc = "Just looking at these fills you with an urge to hug the shit out of people. In a very friendly manner."
warcry = "owo" //Shouldn't ever come into play
/obj/item/clothing/gloves/rapid/hug/Touch(mob/living/target,proximity = TRUE)
if(!istype(target))
return
var/mob/living/M = loc
if(M.a_intent == INTENT_HELP)
if(target.health >= 0 && !HAS_TRAIT(target, TRAIT_FAKEDEATH)) //Can't hug people who are dying/dead
if(target.on_fire || target.lying) //No spamming extinguishing, helping them up, or other non-hugging/patting help interactions
return
else
M.changeNext_move(CLICK_CD_RAPID)
. = FALSE
/obj/item/clothing/gloves/rapid/hug/attack_self(mob/user)
return FALSE
/obj/item/clothing/gloves/thief
name = "black gloves"
desc = "Gloves made with completely frictionless, insulated cloth, easier to steal from people with."
@@ -117,4 +194,4 @@
strip_delay = 80
transfer_prints = FALSE
strip_mod = 5
strip_silence = TRUE
strip_silence = TRUE
+2 -2
View File
@@ -48,8 +48,8 @@
/obj/item/clothing/head/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE)
. = list()
/obj/item/clothing/head/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
. = ..()
if(!isinhands)
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet")
-7
View File
@@ -5,7 +5,6 @@
name = "white beanie"
desc = "A stylish beanie. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their heads."
icon_state = "beanie" //Default white
item_color = "beanie"
/obj/item/clothing/head/beanie/black
name = "black beanie"
@@ -52,33 +51,27 @@
/obj/item/clothing/head/beanie/christmas
name = "christmas beanie"
icon_state = "beaniechristmas"
item_color = "beaniechristmas"
/obj/item/clothing/head/beanie/striped
name = "striped beanie"
icon_state = "beaniestriped"
item_color = "beaniestriped"
/obj/item/clothing/head/beanie/stripedred
name = "red striped beanie"
icon_state = "beaniestripedred"
item_color = "beaniestripedred"
/obj/item/clothing/head/beanie/stripedblue
name = "blue striped beanie"
icon_state = "beaniestripedblue"
item_color = "beaniestripedblue"
/obj/item/clothing/head/beanie/stripedgreen
name = "green striped beanie"
icon_state = "beaniestripedgreen"
item_color = "beaniestripedgreen"
/obj/item/clothing/head/beanie/durathread
name = "durathread beanie"
desc = "A beanie made from durathread, its resilient fibres provide some protection to the wearer."
icon_state = "beaniedurathread"
item_color = null
armor = list("melee" = 25, "bullet" = 10, "laser" = 20,"energy" = 10, "bomb" = 30, "bio" = 15, "rad" = 20, "fire" = 100, "acid" = 50)
+14 -14
View File
@@ -7,7 +7,7 @@
light_color = "#FFCC66"
var/power_on = 0.8
var/on = FALSE
item_color = "yellow" //Determines used sprites: hardhat[on]_[item_color] and hardhat[on]_[item_color]2 (lying down sprite)
var/hat_type = "yellow" //Determines used sprites: hardhat[on]_[hat_type] and hardhat[on]_[hat_type]2 (lying down sprite)
armor = list("melee" = 15, "bullet" = 5, "laser" = 20,"energy" = 10, "bomb" = 20, "bio" = 10, "rad" = 20, "fire" = 100, "acid" = 50)
flags_inv = 0
actions_types = list(/datum/action/item_action/toggle_helmet_light)
@@ -33,8 +33,8 @@
update_icon()
/obj/item/clothing/head/hardhat/update_icon_state()
icon_state = "hardhat[on]_[item_color]"
item_state = "hardhat[on]_[item_color]"
icon_state = "hardhat[on]_[hat_type]"
item_state = "hardhat[on]_[hat_type]"
/obj/item/clothing/head/hardhat/proc/turn_on(mob/user)
set_light(brightness_on, power_on)
@@ -45,13 +45,13 @@
/obj/item/clothing/head/hardhat/orange
icon_state = "hardhat0_orange"
item_state = "hardhat0_orange"
item_color = "orange"
hat_type = "orange"
dog_fashion = null
/obj/item/clothing/head/hardhat/red
icon_state = "hardhat0_red"
item_state = "hardhat0_red"
item_color = "red"
hat_type = "red"
dog_fashion = null
name = "firefighter helmet"
clothing_flags = STOPSPRESSUREDAMAGE
@@ -63,7 +63,7 @@
/obj/item/clothing/head/hardhat/white
icon_state = "hardhat0_white"
item_state = "hardhat0_white"
item_color = "white"
hat_type = "white"
clothing_flags = STOPSPRESSUREDAMAGE
heat_protection = HEAD
max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT
@@ -74,13 +74,13 @@
/obj/item/clothing/head/hardhat/dblue
icon_state = "hardhat0_dblue"
item_state = "hardhat0_dblue"
item_color = "dblue"
hat_type = "dblue"
dog_fashion = null
/obj/item/clothing/head/hardhat/atmos
icon_state = "hardhat0_atmos"
item_state = "hardhat0_atmos"
item_color = "atmos"
hat_type = "atmos"
dog_fashion = null
name = "atmospheric technician's firefighting helmet"
desc = "A firefighter's helmet, able to keep the user cool in any situation."
@@ -124,12 +124,12 @@
playsound(src, 'sound/mecha/mechmove03.ogg', 50, TRUE) //Visors don't just come from nothing
update_icon()
/obj/item/clothing/head/hardhat/weldhat/worn_overlays(isinhands, icon_file, style_flags = NONE)
/obj/item/clothing/head/hardhat/weldhat/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE)
. = ..()
if(!isinhands)
. += mutable_appearance('icons/mob/head.dmi', "weldhelmet")
. += mutable_appearance('icons/mob/clothing/head.dmi', "weldhelmet")
if(!up)
. += mutable_appearance('icons/mob/head.dmi', "weldvisor")
. += mutable_appearance('icons/mob/clothing/head.dmi', "weldvisor")
/obj/item/clothing/head/hardhat/weldhat/update_overlays()
. = ..()
@@ -139,14 +139,14 @@
/obj/item/clothing/head/hardhat/weldhat/orange
icon_state = "hardhat0_orange"
item_state = "hardhat0_orange"
item_color = "orange"
hat_type = "orange"
/obj/item/clothing/head/hardhat/weldhat/white
desc = "A piece of headgear used in dangerous working conditions to protect the head. Comes with a built-in flashlight AND welding shield!" //This bulb is not smaller
icon_state = "hardhat0_white"
item_state = "hardhat0_white"
brightness_on = 4 //Boss always takes the best stuff
item_color = "white"
hat_type = "white"
clothing_flags = STOPSPRESSUREDAMAGE
heat_protection = HEAD
max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT
@@ -156,4 +156,4 @@
/obj/item/clothing/head/hardhat/weldhat/dblue
icon_state = "hardhat0_dblue"
item_state = "hardhat0_dblue"
item_color = "dblue"
hat_type = "dblue"
-1
View File
@@ -364,7 +364,6 @@
name = "durathread beret"
desc = "A beret made from durathread, its resilient fibres provide some protection to the wearer."
icon_state = "beretdurathread"
item_color = null
armor = list("melee" = 25, "bullet" = 10, "laser" = 20,"energy" = 10, "bomb" = 30, "bio" = 15, "rad" = 20, "fire" = 100, "acid" = 50)
#undef DRILL_DEFAULT
-2
View File
@@ -372,14 +372,12 @@
name = "Telegram cap"
desc = "A bright red cap warn by hotel staff. Or people who want to be a singing telegram"
icon_state = "telegram"
item_color = "telegram"
dog_fashion = /datum/dog_fashion/head/telegram
/obj/item/clothing/head/colour
name = "Singer cap"
desc = "A light white hat that has bands of color. Just makes you want to sing and dance!"
icon_state = "colour"
item_color = "colour"
dog_fashion = /datum/dog_fashion/head/colour
/obj/item/clothing/head/christmashat
+10 -17
View File
@@ -42,7 +42,6 @@
desc = "You put the cake on your head. Brilliant."
icon_state = "hardhat0_cakehat"
item_state = "hardhat0_cakehat"
item_color = "cakehat"
hitsound = 'sound/weapons/tap.ogg'
flags_inv = HIDEEARS|HIDEHAIR
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
@@ -114,7 +113,6 @@
desc = "A jack o' lantern! Believed to ward off evil spirits."
icon_state = "hardhat0_pumpkin"
item_state = "hardhat0_pumpkin"
item_color = "pumpkin"
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
brightness_on = 2 //luminosity when on
@@ -151,7 +149,6 @@
desc = "Some fake antlers and a very fake red nose."
icon_state = "hardhat0_reindeer"
item_state = "hardhat0_reindeer"
item_color = "reindeer"
flags_inv = 0
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
brightness_on = 1 //luminosity when on
@@ -187,14 +184,15 @@
/obj/item/clothing/head/wig
name = "wig"
desc = "A bunch of hair without a head attached."
icon_state = ""
item_state = "pwig"
icon = 'icons/mob/human_face.dmi' // default icon for all hairs
icon_state = "hair_vlong"
flags_inv = HIDEHAIR
color = "#000"
var/hair_style = "Very Long Hair"
var/hair_color = "#000"
/obj/item/clothing/head/wig/Initialize(mapload)
. = ..()
icon_state = "" //Shitty hack that i dont know if it is even neccesary to deal with the vendor stack exception
update_icon()
/obj/item/clothing/head/wig/update_icon_state()
@@ -202,29 +200,24 @@
if(!S)
icon = 'icons/obj/clothing/hats.dmi'
icon_state = "pwig"
else
icon = S.icon
icon_state = S.icon_state
/obj/item/clothing/head/wig/update_overlays()
/obj/item/clothing/head/wig/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
. = ..()
var/datum/sprite_accessory/S = GLOB.hair_styles_list[hair_style]
if(S)
var/mutable_appearance/M = mutable_appearance(S.icon, S.icon_state, color = hair_color)
M.appearance_flags |= RESET_COLOR
. += M
/obj/item/clothing/head/wig/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE)
. = list()
if(!isinhands)
var/datum/sprite_accessory/S = GLOB.hair_styles_list[hair_style]
if(!S)
return
var/mutable_appearance/M = mutable_appearance(S.icon, S.icon_state,layer = -HAIR_LAYER)
M.appearance_flags |= RESET_COLOR
M.color = hair_color
M.color = color
. += M
/obj/item/clothing/head/wig/random/Initialize(mapload)
hair_style = pick(GLOB.hair_styles_list - "Bald") //Don't want invisible wig
hair_color = "#[random_short_color()]"
color = "#[random_short_color()]"
. = ..()
/obj/item/clothing/head/bronze
+17 -17
View File
@@ -3,14 +3,14 @@
desc = "It's a baseball hat in a tasteless yellow colour."
icon_state = "cargosoft"
item_state = "helmet"
item_color = "cargo"
var/soft_type = "cargo"
dog_fashion = /datum/dog_fashion/head/cargo_tech
var/flipped = 0
/obj/item/clothing/head/soft/dropped(mob/user)
icon_state = "[item_color]soft"
icon_state = "[soft_type]soft"
flipped = FALSE
return ..()
@@ -33,10 +33,10 @@
if(!user.incapacitated())
src.flipped = !src.flipped
if(src.flipped)
icon_state = "[item_color]soft_flipped"
icon_state = "[soft_type]soft_flipped"
to_chat(user, "<span class='notice'>You flip the hat backwards.</span>")
else
icon_state = "[item_color]soft"
icon_state = "[soft_type]soft"
to_chat(user, "<span class='notice'>You flip the hat back in normal position.</span>")
usr.update_inv_head() //so our mob-overlays update
@@ -48,77 +48,77 @@
name = "red cap"
desc = "It's a baseball hat in a tasteless red colour."
icon_state = "redsoft"
item_color = "red"
soft_type = "red"
dog_fashion = null
/obj/item/clothing/head/soft/blue
name = "blue cap"
desc = "It's a baseball hat in a tasteless blue colour."
icon_state = "bluesoft"
item_color = "blue"
soft_type = "blue"
dog_fashion = null
/obj/item/clothing/head/soft/green
name = "green cap"
desc = "It's a baseball hat in a tasteless green colour."
icon_state = "greensoft"
item_color = "green"
soft_type = "green"
dog_fashion = null
/obj/item/clothing/head/soft/yellow
name = "yellow cap"
desc = "It's a baseball hat in a tasteless yellow colour."
icon_state = "yellowsoft"
item_color = "yellow"
soft_type = "yellow"
dog_fashion = null
/obj/item/clothing/head/soft/grey
name = "grey cap"
desc = "It's a baseball hat in a tasteful grey colour."
icon_state = "greysoft"
item_color = "grey"
soft_type = "grey"
dog_fashion = null
/obj/item/clothing/head/soft/orange
name = "orange cap"
desc = "It's a baseball hat in a tasteless orange colour."
icon_state = "orangesoft"
item_color = "orange"
soft_type = "orange"
dog_fashion = null
/obj/item/clothing/head/soft/mime
name = "white cap"
desc = "It's a baseball hat in a tasteless white colour."
icon_state = "mimesoft"
item_color = "mime"
soft_type = "mime"
dog_fashion = null
/obj/item/clothing/head/soft/purple
name = "purple cap"
desc = "It's a baseball hat in a tasteless purple colour."
icon_state = "purplesoft"
item_color = "purple"
soft_type = "purple"
dog_fashion = null
/obj/item/clothing/head/soft/black
name = "black cap"
desc = "It's a baseball hat in a tasteless black colour."
icon_state = "blacksoft"
item_color = "black"
soft_type = "black"
dog_fashion = null
/obj/item/clothing/head/soft/rainbow
name = "rainbow cap"
desc = "It's a baseball hat in a bright rainbow of colors."
icon_state = "rainbowsoft"
item_color = "rainbow"
soft_type = "rainbow"
dog_fashion = null
/obj/item/clothing/head/soft/sec
name = "security cap"
desc = "It's a robust baseball hat in tasteful red colour."
icon_state = "secsoft"
item_color = "sec"
soft_type = "sec"
armor = list("melee" = 30, "bullet" = 25, "laser" = 25, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 50)
strip_delay = 60
dog_fashion = null
@@ -127,14 +127,14 @@
name = "EMT cap"
desc = "It's a baseball hat with a dark turquoise color and a reflective cross on the top."
icon_state = "emtsoft"
item_color = "emt"
soft_type = "emt"
dog_fashion = null
/obj/item/clothing/head/soft/baseball
name = "baseball cap"
desc = "It's a robust baseball hat, this one belongs to syndicate major league team."
icon_state = "baseballsoft"
item_color = "baseballsoft"
soft_type = "baseballsoft"
item_state = "baseballsoft"
flags_inv = HIDEEYES|HIDEFACE
armor = list("melee" = 35, "bullet" = 35, "laser" = 25, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 90)
+2 -2
View File
@@ -28,8 +28,8 @@
/obj/item/clothing/mask/proc/handle_speech()
/obj/item/clothing/mask/worn_overlays(isinhands = FALSE, icon_file, style_flags = NONE)
. = list()
/obj/item/clothing/mask/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
. = ..()
if(!isinhands)
if(body_parts_covered & HEAD)
if(damaged_clothes)

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