Merge branch 'master' into punch-bundle
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>"
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
+11
-5
@@ -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
|
||||
+25
-281
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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];'> </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"]];'> </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)];'> </span>(Skin tone overriding)</a><br>"
|
||||
dat += "<span style='border: 1px solid #161616; background-color: [SKINTONE2HEX(skin_tone)];'> </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"]];'> </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)];'> </span>(Skin tone overriding)<br>"
|
||||
dat += "<span style='border: 1px solid #161616; background-color: [SKINTONE2HEX(skin_tone)];'> </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"]];'> </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)];'> </span>(Skin tone overriding)<br>"
|
||||
dat += "<span style='border: 1px solid #161616; background-color: [SKINTONE2HEX(skin_tone)];'> </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"]];'> </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)];'> </span>(Skin tone overriding)<br>"
|
||||
dat += "<span style='border: 1px solid #161616; background-color: [SKINTONE2HEX(skin_tone)];'> </span>(Skin tone overriding)<br>"
|
||||
else
|
||||
dat += "<b>Color:</b></a><BR>"
|
||||
dat += "<span style='border: 1px solid #161616; background-color: #[features["breasts_color"]];'> </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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user