Merge remote-tracking branch 'Citadel-Station-13/master' into kills_the_shitty_fix

This commit is contained in:
Artur
2020-04-05 18:21:50 +03:00
194 changed files with 141945 additions and 4075 deletions
+1
View File
@@ -74,6 +74,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
/client/proc/addbunkerbypass,
/client/proc/revokebunkerbypass,
/client/proc/stop_sounds,
/client/proc/mark_datum_mapview,
/client/proc/hide_verbs, /*hides all our adminverbs*/
/client/proc/hide_most_verbs, /*hides all our hideable adminverbs*/
/datum/admins/proc/open_borgopanel
+208
View File
@@ -0,0 +1,208 @@
/client/proc/callproc()
set category = "Debug"
set name = "Advanced ProcCall"
set waitfor = FALSE
callproc_blocking()
/client/proc/callproc_blocking(list/get_retval)
if(!check_rights(R_DEBUG))
return
var/datum/target
var/targetselected = FALSE
var/returnval
switch(alert("Proc owned by something?",,"Yes","No"))
if("Yes")
targetselected = TRUE
var/list/value = vv_get_value(default_class = VV_ATOM_REFERENCE, classes = list(VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, VV_CLIENT, VV_MARKED_DATUM, VV_TEXT_LOCATE, VV_PROCCALL_RETVAL))
if (!value["class"] || !value["value"])
return
target = value["value"]
if(!istype(target))
to_chat(usr, "<span class='danger'>Invalid target.</span>")
return
if("No")
target = null
targetselected = FALSE
var/procpath = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null
if(!procpath)
return
//strip away everything but the proc name
var/list/proclist = splittext(procpath, "/")
if (!length(proclist))
return
var/procname = proclist[proclist.len]
var/proctype = ("verb" in proclist) ? "verb" :"proc"
if(targetselected)
if(!hascall(target, procname))
to_chat(usr, "<span class='warning'>Error: callproc(): type [target.type] has no [proctype] named [procpath].</span>")
return
else
procpath = "/[proctype]/[procname]"
if(!text2path(procpath))
to_chat(usr, "<span class='warning'>Error: callproc(): [procpath] does not exist.</span>")
return
var/list/lst = get_callproc_args()
if(!lst)
return
if(targetselected)
if(!target)
to_chat(usr, "<font color='red'>Error: callproc(): owner of proc no longer exists.</font>")
return
var/msg = "[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
log_admin(msg)
message_admins(msg) //Proccall announce removed.
admin_ticket_log(target, msg)
returnval = WrapAdminProcCall(target, procname, lst) // Pass the lst as an argument list to the proc
else
//this currently has no hascall protection. wasn't able to get it working.
log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].")
message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed.
returnval = WrapAdminProcCall(GLOBAL_PROC, procname, lst) // Pass the lst as an argument list to the proc
SSblackbox.record_feedback("tally", "admin_verb", 1, "Advanced ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(get_retval)
get_retval += returnval
. = get_callproc_returnval(returnval, procname)
if(.)
to_chat(usr, .)
GLOBAL_VAR(AdminProcCaller)
GLOBAL_PROTECT(AdminProcCaller)
GLOBAL_VAR_INIT(AdminProcCallCount, 0)
GLOBAL_PROTECT(AdminProcCallCount)
GLOBAL_VAR(LastAdminCalledTargetRef)
GLOBAL_PROTECT(LastAdminCalledTargetRef)
GLOBAL_VAR(LastAdminCalledTarget)
GLOBAL_PROTECT(LastAdminCalledTarget)
GLOBAL_VAR(LastAdminCalledProc)
GLOBAL_PROTECT(LastAdminCalledProc)
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target != GLOBAL_PROC && procname == "Del")
to_chat(usr, "<span class='warning'>Calling Del() is not allowed</span>")
return
if(target != GLOBAL_PROC && !target.CanProcCall(procname))
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
return
var/current_caller = GLOB.AdminProcCaller
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
if(!ckey)
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
if(current_caller && current_caller != ckey)
if(!GLOB.AdminProcCallSpamPrevention[ckey])
to_chat(usr, "<span class='adminnotice'>Another set of admin called procs are still running, your proc will be run after theirs finish.</span>")
GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
UNTIL(!GLOB.AdminProcCaller)
to_chat(usr, "<span class='adminnotice'>Running your proc</span>")
GLOB.AdminProcCallSpamPrevention -= ckey
else
UNTIL(!GLOB.AdminProcCaller)
GLOB.LastAdminCalledProc = procname
if(target != GLOBAL_PROC)
GLOB.LastAdminCalledTargetRef = "[REF(target)]"
GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
++GLOB.AdminProcCallCount
. = world.WrapAdminProcCall(target, procname, arguments)
if(--GLOB.AdminProcCallCount == 0)
GLOB.AdminProcCaller = null
//adv proc call this, ya nerds
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target == GLOBAL_PROC)
return call(procname)(arglist(arguments))
else if(target != world)
return call(target, procname)(arglist(arguments))
else
log_admin_private("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
/proc/IsAdminAdvancedProcCall()
#ifdef TESTING
return FALSE
#else
return usr && usr.client && GLOB.AdminProcCaller == usr.client.ckey
#endif
/client/proc/callproc_datum(datum/A as null|area|mob|obj|turf)
set category = "Debug"
set name = "Atom ProcCall"
set waitfor = FALSE
if(!check_rights(R_DEBUG))
return
var/procname = input("Proc name, eg: fake_blood","Proc:", null) as text|null
if(!procname)
return
if(!hascall(A,procname))
to_chat(usr, "<span class='warning'>Error: callproc_datum(): type [A.type] has no proc named [procname].</span>")
return
var/list/lst = get_callproc_args()
if(!lst)
return
if(!A || !IsValidSrc(A))
to_chat(usr, "<span class='warning'>Error: callproc_datum(): owner of proc no longer exists.</span>")
return
var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
log_admin(msg)
message_admins(msg)
admin_ticket_log(A, msg)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Atom ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
. = get_callproc_returnval(returnval,procname)
if(.)
to_chat(usr, .)
/client/proc/get_callproc_args()
var/argnum = input("Number of arguments","Number:",0) as num|null
if(isnull(argnum))
return
. = list()
var/list/named_args = list()
while(argnum--)
var/named_arg = input("Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument") as text|null
var/value = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
if (!value["class"])
return
if(named_arg)
named_args[named_arg] = value["value"]
else
. += value["value"]
if(LAZYLEN(named_args))
. += named_args
/client/proc/get_callproc_returnval(returnval,procname)
. = ""
if(islist(returnval))
var/list/returnedlist = returnval
. = "<span class='notice'>"
if(returnedlist.len)
var/assoc_check = returnedlist[1]
if(istext(assoc_check) && (returnedlist[assoc_check] != null))
. += "[procname] returned an associative list:"
for(var/key in returnedlist)
. += "\n[key] = [returnedlist[key]]"
else
. += "[procname] returned a list:"
for(var/elem in returnedlist)
. += "\n[elem]"
else
. = "[procname] returned an empty list"
. += "</span>"
else
. = "<span class='notice'>[procname] returned: [!isnull(returnval) ? returnval : "null"]</span>"
-268
View File
@@ -15,214 +15,6 @@
SSblackbox.record_feedback("tally", "admin_verb", 1, "Toggle Debug Two") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/* 21st Sept 2010
Updated by Skie -- Still not perfect but better!
Stuff you can't do:
Call proc /mob/proc/Dizzy() for some player
Because if you select a player mob as owner it tries to do the proc for
/mob/living/carbon/human/ instead. And that gives a run-time error.
But you can call procs that are of type /mob/living/carbon/human/proc/ for that player.
*/
/client/proc/callproc()
set category = "Debug"
set name = "Advanced ProcCall"
set waitfor = FALSE
if(!check_rights(R_DEBUG))
return
var/datum/target = null
var/targetselected = FALSE
var/returnval = null
if(alert("Proc owned by something?",,"Yes","No") == "Yes")
targetselected = TRUE
var/list/value = vv_get_value(default_class = VV_ATOM_REFERENCE, classes = list(VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, VV_CLIENT))
if (!value["class"] || !value["value"])
return
target = value["value"]
var/procpath = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null
if(!procpath)
return
//strip away everything but the proc name
var/list/proclist = splittext(procpath, "/")
if (!length(proclist))
return
var/procname = proclist[proclist.len]
var/proctype = ("verb" in proclist) ? "verb" :"proc"
if(targetselected)
if(!hascall(target, procname))
to_chat(usr, "<span class='warning'>Error: callproc(): type [target.type] has no [proctype] named [procpath].</span>")
return
else
procpath = "/[proctype]/[procname]"
if(!text2path(procpath))
to_chat(usr, "<span class='warning'>Error: callproc(): [procpath] does not exist.</span>")
return
var/list/lst = get_callproc_args()
if(!lst)
return
if(targetselected)
if(!target)
to_chat(usr, "<span class='warning'>Error: callproc(): owner of proc no longer exists.</span>")
return
var/msg = "[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no argument"]."
log_admin(msg)
message_admins(msg)
admin_ticket_log(target, msg)
returnval = WrapAdminProcCall(target, procname, lst)
else
var/msg = "[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no argument"]."
log_admin(msg)
message_admins(msg)
returnval = WrapAdminProcCall(GLOBAL_PROC, procpath, lst) //calling globals needs full qualified name (e.g /proc/foo)
. = get_callproc_returnval(returnval, procname)
if(.)
to_chat(usr, .)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Advanced ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
GLOBAL_VAR(AdminProcCaller)
GLOBAL_PROTECT(AdminProcCaller)
GLOBAL_VAR_INIT(AdminProcCallCount, 0)
GLOBAL_PROTECT(AdminProcCallCount)
GLOBAL_VAR(LastAdminCalledTargetRef)
GLOBAL_PROTECT(LastAdminCalledTargetRef)
GLOBAL_VAR(LastAdminCalledTarget)
GLOBAL_PROTECT(LastAdminCalledTarget)
GLOBAL_VAR(LastAdminCalledProc)
GLOBAL_PROTECT(LastAdminCalledProc)
GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention)
GLOBAL_PROTECT(AdminProcCallSpamPrevention)
/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target != GLOBAL_PROC && procname == "Del")
to_chat(usr, "<span class='warning'>Calling Del() is not allowed</span>")
return
if(target != GLOBAL_PROC && !target.CanProcCall(procname))
to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!")
return
var/current_caller = GLOB.AdminProcCaller
var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller
if(!ckey)
CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]")
if(current_caller && current_caller != ckey)
if(!GLOB.AdminProcCallSpamPrevention[ckey])
to_chat(usr, "<span class='adminnotice'>Another set of admin called procs are still running, your proc will be run after theirs finish.</span>")
GLOB.AdminProcCallSpamPrevention[ckey] = TRUE
UNTIL(!GLOB.AdminProcCaller)
to_chat(usr, "<span class='adminnotice'>Running your proc</span>")
GLOB.AdminProcCallSpamPrevention -= ckey
else
UNTIL(!GLOB.AdminProcCaller)
GLOB.LastAdminCalledProc = procname
if(target != GLOBAL_PROC)
GLOB.LastAdminCalledTargetRef = "[REF(target)]"
GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you
++GLOB.AdminProcCallCount
. = world.WrapAdminProcCall(target, procname, arguments)
if(--GLOB.AdminProcCallCount == 0)
GLOB.AdminProcCaller = null
//adv proc call this, ya nerds
/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments)
if(target == GLOBAL_PROC)
return call(procname)(arglist(arguments))
else if(target != world)
return call(target, procname)(arglist(arguments))
else
log_admin_private("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]")
/proc/IsAdminAdvancedProcCall()
#ifdef TESTING
return FALSE
#else
return usr && usr.client && GLOB.AdminProcCaller == usr.client.ckey
#endif
/client/proc/callproc_datum(datum/A as null|area|mob|obj|turf)
set category = "Debug"
set name = "Atom ProcCall"
set waitfor = FALSE
if(!check_rights(R_DEBUG))
return
var/procname = input("Proc name, eg: fake_blood","Proc:", null) as text|null
if(!procname)
return
if(!hascall(A,procname))
to_chat(usr, "<span class='warning'>Error: callproc_datum(): type [A.type] has no proc named [procname].</span>")
return
var/list/lst = get_callproc_args()
if(!lst)
return
if(!A || !IsValidSrc(A))
to_chat(usr, "<span class='warning'>Error: callproc_datum(): owner of proc no longer exists.</span>")
return
var/msg = "[key_name(src)] called [A]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]."
log_admin(msg)
message_admins(msg)
admin_ticket_log(A, msg)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Atom ProcCall") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
var/returnval = WrapAdminProcCall(A, procname, lst) // Pass the lst as an argument list to the proc
. = get_callproc_returnval(returnval,procname)
if(.)
to_chat(usr, .)
/client/proc/get_callproc_args()
var/argnum = input("Number of arguments","Number:",0) as num|null
if(isnull(argnum))
return
. = list()
var/list/named_args = list()
while(argnum--)
var/named_arg = input("Leave blank for positional argument. Positional arguments will be considered as if they were added first.", "Named argument") as text|null
var/value = vv_get_value(restricted_classes = list(VV_RESTORE_DEFAULT))
if (!value["class"])
return
if(named_arg)
named_args[named_arg] = value["value"]
else
. += value["value"]
if(LAZYLEN(named_args))
. += named_args
/client/proc/get_callproc_returnval(returnval,procname)
. = ""
if(islist(returnval))
var/list/returnedlist = returnval
. = "<span class='notice'>"
if(returnedlist.len)
var/assoc_check = returnedlist[1]
if(istext(assoc_check) && (returnedlist[assoc_check] != null))
. += "[procname] returned an associative list:"
for(var/key in returnedlist)
. += "\n[key] = [returnedlist[key]]"
else
. += "[procname] returned a list:"
for(var/elem in returnedlist)
. += "\n[elem]"
else
. = "[procname] returned an empty list"
. += "</span>"
else
. = "<span class='notice'>[procname] returned: [!isnull(returnval) ? returnval : "null"]</span>"
/client/proc/Cell()
set category = "Debug"
set name = "Air Status in Location"
@@ -343,66 +135,6 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
else
alert("Invalid mob")
/proc/make_types_fancy(var/list/types)
if (ispath(types))
types = list(types)
. = list()
for(var/type in types)
var/typename = "[type]"
var/static/list/TYPES_SHORTCUTS = list(
/obj/effect/decal/cleanable = "CLEANABLE",
/obj/item/radio/headset = "HEADSET",
/obj/item/clothing/head/helmet/space = "SPESSHELMET",
/obj/item/book/manual = "MANUAL",
/obj/item/reagent_containers/food/drinks = "DRINK", //longest paths comes first
/obj/item/reagent_containers/food = "FOOD",
/obj/item/reagent_containers = "REAGENT_CONTAINERS",
/obj/machinery/atmospherics = "ATMOS_MECH",
/obj/machinery/portable_atmospherics = "PORT_ATMOS",
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack = "MECHA_MISSILE_RACK",
/obj/item/mecha_parts/mecha_equipment = "MECHA_EQUIP",
/obj/item/organ = "ORGAN",
/obj/item = "ITEM",
/obj/machinery = "MACHINERY",
/obj/effect = "EFFECT",
/obj = "O",
/datum = "D",
/turf/open = "OPEN",
/turf/closed = "CLOSED",
/turf = "T",
/mob/living/carbon = "CARBON",
/mob/living/simple_animal = "SIMPLE",
/mob/living = "LIVING",
/mob = "M"
)
for (var/tn in TYPES_SHORTCUTS)
if (copytext(typename,1, length("[tn]/")+1)=="[tn]/" /*findtextEx(typename,"[tn]/",1,2)*/ )
typename = TYPES_SHORTCUTS[tn]+copytext(typename,length("[tn]/"))
break
.[typename] = type
/proc/get_fancy_list_of_atom_types()
var/static/list/pre_generated_list
if (!pre_generated_list) //init
pre_generated_list = make_types_fancy(typesof(/atom))
return pre_generated_list
/proc/get_fancy_list_of_datum_types()
var/static/list/pre_generated_list
if (!pre_generated_list) //init
pre_generated_list = make_types_fancy(sortList(typesof(/datum) - typesof(/atom)))
return pre_generated_list
/proc/filter_fancy_list(list/L, filter as text)
var/list/matches = new
for(var/key in L)
var/value = L[key]
if(findtext("[key]", filter) || findtext("[value]", filter))
matches[key] = value
return matches
//TODO: merge the vievars version into this or something maybe mayhaps
/client/proc/cmd_debug_del_all(object as text)
set category = "Debug"
-25
View File
@@ -594,31 +594,6 @@ Traitors and the like can also be revived with the previous role mostly intact.
admin_delete(A)
/client/proc/admin_delete(datum/D)
var/atom/A = D
var/coords = ""
var/jmp_coords = ""
if(istype(A))
var/turf/T = get_turf(A)
if(T)
coords = "at [COORD(T)]"
jmp_coords = "at [ADMIN_COORDJMP(T)]"
else
jmp_coords = coords = "in nullspace"
if (alert(src, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", "Yes", "No") == "Yes")
log_admin("[key_name(usr)] deleted [D] [coords]")
message_admins("[key_name_admin(usr)] deleted [D] [jmp_coords]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delete") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(isturf(D))
var/turf/T = D
T.ScrapeAway()
else
vv_update_display(D, "deleted", VV_MSG_DELETED)
qdel(D)
if(!QDELETED(D))
vv_update_display(D, "deleted", "")
/client/proc/cmd_admin_list_open_jobs()
set category = "Admin"
set name = "Manage Job Slots"
@@ -0,0 +1,24 @@
/client/proc/admin_delete(datum/D)
var/atom/A = D
var/coords = ""
var/jmp_coords = ""
if(istype(A))
var/turf/T = get_turf(A)
if(T)
coords = "at [COORD(T)]"
jmp_coords = "at [ADMIN_COORDJMP(T)]"
else
jmp_coords = coords = "in nullspace"
if (alert(src, "Are you sure you want to delete:\n[D]\n[coords]?", "Confirmation", "Yes", "No") == "Yes")
log_admin("[key_name(usr)] deleted [D] [coords]")
message_admins("[key_name_admin(usr)] deleted [D] [jmp_coords]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Delete") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
if(isturf(D))
var/turf/T = D
T.ScrapeAway()
else
vv_update_display(D, "deleted", VV_MSG_DELETED)
qdel(D)
if(!QDELETED(D))
vv_update_display(D, "deleted", "")
@@ -0,0 +1,76 @@
#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
/proc/debug_variable(name, value, level, datum/D, sanitize = TRUE) //if D is a list, name will be index, and value will be assoc value.
var/header
if(D)
if(islist(D))
var/index = name
if (value)
name = D[name] //name is really the index until this line
else
value = D[name]
header = "<li style='backgroundColor:white'>([VV_HREF_TARGET_1V(D, VV_HK_LIST_EDIT, "E", index)]) ([VV_HREF_TARGET_1V(D, VV_HK_LIST_CHANGE, "C", index)]) ([VV_HREF_TARGET_1V(D, VV_HK_LIST_REMOVE, "-", index)]) "
else
header = "<li style='backgroundColor:white'>([VV_HREF_TARGET_1V(D, VV_HK_BASIC_EDIT, "E", name)]) ([VV_HREF_TARGET_1V(D, VV_HK_BASIC_CHANGE, "C", name)]) ([VV_HREF_TARGET_1V(D, VV_HK_BASIC_MASSEDIT, "M", name)]) "
else
header = "<li>"
var/item
if (isnull(value))
item = "[VV_HTML_ENCODE(name)] = <span class='value'>null</span>"
else if (istext(value))
item = "[VV_HTML_ENCODE(name)] = <span class='value'>\"[VV_HTML_ENCODE(value)]\"</span>"
else if (isicon(value))
#ifdef VARSICON
var/icon/I = icon(value)
var/rnd = rand(1,10000)
var/rname = "tmp[REF(I)][rnd].png"
usr << browse_rsc(I, rname)
item = "[VV_HTML_ENCODE(name)] = (<span class='value'>[value]</span>) <img class=icon src=\"[rname]\">"
#else
item = "[VV_HTML_ENCODE(name)] = /icon (<span class='value'>[value]</span>)"
#endif
else if (isfile(value))
item = "[VV_HTML_ENCODE(name)] = <span class='value'>'[value]'</span>"
else if (istype(value, /datum))
var/datum/DV = value
if ("[DV]" != "[DV.type]") //if the thing as a name var, lets use it.
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] [REF(value)]</a> = [DV] [DV.type]"
else
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] [REF(value)]</a> = [DV.type]"
else if (islist(value))
var/list/L = value
var/list/items = list()
if (L.len > 0 && !(name == "underlays" || name == "overlays" || L.len > (IS_NORMAL_LIST(L) ? VV_NORMAL_LIST_NO_EXPAND_THRESHOLD : VV_SPECIAL_LIST_NO_EXPAND_THRESHOLD)))
for (var/i in 1 to L.len)
var/key = L[i]
var/val
if (IS_NORMAL_LIST(L) && !isnum(key))
val = L[key]
if (isnull(val)) // we still want to display non-null false values, such as 0 or ""
val = key
key = i
items += debug_variable(key, val, level + 1, sanitize = sanitize)
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a><ul>[items.Join()]</ul>"
else
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a>"
else if (name in GLOB.bitfields)
var/list/flags = list()
for (var/i in GLOB.bitfields[name])
if (value & GLOB.bitfields[name][i])
flags += i
item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(jointext(flags, ", "))]"
else
item = "[VV_HTML_ENCODE(name)] = <span class='value'>[VV_HTML_ENCODE(value)]</span>"
return "[header][item]</li>"
#undef VV_HTML_ENCODE
@@ -0,0 +1,271 @@
/client/proc/vv_get_class(var_name, var_value)
if(isnull(var_value))
. = VV_NULL
else if(isnum(var_value))
if(var_name in GLOB.bitfields)
. = VV_BITFIELD
else
. = VV_NUM
else if(istext(var_value))
if(findtext(var_value, "\n"))
. = VV_MESSAGE
else
. = VV_TEXT
else if(isicon(var_value))
. = VV_ICON
else if(ismob(var_value))
. = VV_MOB_REFERENCE
else if(isloc(var_value))
. = VV_ATOM_REFERENCE
else if(istype(var_value, /client))
. = VV_CLIENT
else if(istype(var_value, /datum))
. = VV_DATUM_REFERENCE
else if(ispath(var_value))
if(ispath(var_value, /atom))
. = VV_ATOM_TYPE
else if(ispath(var_value, /datum))
. = VV_DATUM_TYPE
else
. = VV_TYPE
else if(islist(var_value))
. = VV_LIST
else if(isfile(var_value))
. = VV_FILE
else
. = VV_NULL
/client/proc/vv_get_value(class, default_class, current_value, list/restricted_classes, list/extra_classes, list/classes, var_name)
. = list("class" = class, "value" = null)
if(!class)
if(!classes)
classes = list (
VV_NUM,
VV_TEXT,
VV_MESSAGE,
VV_ICON,
VV_ATOM_REFERENCE,
VV_DATUM_REFERENCE,
VV_MOB_REFERENCE,
VV_CLIENT,
VV_ATOM_TYPE,
VV_DATUM_TYPE,
VV_TYPE,
VV_FILE,
VV_NEW_ATOM,
VV_NEW_DATUM,
VV_NEW_TYPE,
VV_NEW_LIST,
VV_NULL,
VV_RESTORE_DEFAULT,
VV_TEXT_LOCATE,
VV_PROCCALL_RETVAL,
)
var/markstring
if(!(VV_MARKED_DATUM in restricted_classes))
markstring = "[VV_MARKED_DATUM] (CURRENT: [(istype(holder) && istype(holder.marked_datum))? holder.marked_datum.type : "NULL"])"
classes += markstring
if(restricted_classes)
classes -= restricted_classes
if(extra_classes)
classes += extra_classes
.["class"] = input(src, "What kind of data?", "Variable Type", default_class) as null|anything in classes
if(holder && holder.marked_datum && .["class"] == markstring)
.["class"] = VV_MARKED_DATUM
switch(.["class"])
if(VV_TEXT)
.["value"] = input("Enter new text:", "Text", current_value) as null|text
if(.["value"] == null)
.["class"] = null
return
if(VV_MESSAGE)
.["value"] = input("Enter new text:", "Text", current_value) as null|message
if(.["value"] == null)
.["class"] = null
return
if(VV_NUM)
.["value"] = input("Enter new number:", "Num", current_value) as null|num
if(.["value"] == null)
.["class"] = null
return
if(VV_BITFIELD)
.["value"] = input_bitfield(usr, "Editing bitfield: [var_name]", var_name, current_value)
if(.["value"] == null)
.["class"] = null
return
if(VV_ATOM_TYPE)
.["value"] = pick_closest_path(FALSE)
if(.["value"] == null)
.["class"] = null
return
if(VV_DATUM_TYPE)
.["value"] = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
if(.["value"] == null)
.["class"] = null
return
if(VV_TYPE)
var/type = current_value
var/error = ""
do
type = input("Enter type:[error]", "Type", type) as null|text
if(!type)
break
type = text2path(type)
error = "\nType not found, Please try again"
while(!type)
if(!type)
.["class"] = null
return
.["value"] = type
if(VV_ATOM_REFERENCE)
var/type = pick_closest_path(FALSE)
var/subtypes = vv_subtype_prompt(type)
if(subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if(!value)
.["class"] = null
return
.["value"] = things[value]
if(VV_DATUM_REFERENCE)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
var/subtypes = vv_subtype_prompt(type)
if(subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if(!value)
.["class"] = null
return
.["value"] = things[value]
if(VV_MOB_REFERENCE)
var/type = pick_closest_path(FALSE, make_types_fancy(typesof(/mob)))
var/subtypes = vv_subtype_prompt(type)
if(subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if(!value)
.["class"] = null
return
.["value"] = things[value]
if(VV_CLIENT)
.["value"] = input("Select reference:", "Reference", current_value) as null|anything in GLOB.clients
if(.["value"] == null)
.["class"] = null
return
if(VV_FILE)
.["value"] = input("Pick file:", "File") as null|file
if(.["value"] == null)
.["class"] = null
return
if(VV_ICON)
.["value"] = input("Pick icon:", "Icon") as null|icon
if(.["value"] == null)
.["class"] = null
return
if(VV_MARKED_DATUM)
.["value"] = holder.marked_datum
if(.["value"] == null)
.["class"] = null
return
if(VV_PROCCALL_RETVAL)
var/list/get_retval = list()
callproc_blocking(get_retval)
.["value"] = get_retval[1] //should have been set in proccall!
if(.["value"] == null)
.["class"] = null
return
if(VV_NEW_ATOM)
var/type = pick_closest_path(FALSE)
if(!type)
.["class"] = null
return
.["type"] = type
var/atom/newguy = new type()
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if(VV_NEW_DATUM)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
if(!type)
.["class"] = null
return
.["type"] = type
var/datum/newguy = new type()
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if(VV_NEW_TYPE)
var/type = current_value
var/error = ""
do
type = input("Enter type:[error]", "Type", type) as null|text
if(!type)
break
type = text2path(type)
error = "\nType not found, Please try again"
while(!type)
if(!type)
.["class"] = null
return
.["type"] = type
var/datum/newguy = new type()
if(istype(newguy))
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if(VV_NEW_LIST)
.["value"] = list()
.["type"] = /list
if(VV_TEXT_LOCATE)
var/datum/D
do
var/ref = input("Enter reference:", "Reference") as null|text
if(!ref)
break
D = locate(ref)
if(!D)
alert("Invalid ref!")
continue
if(!D.can_vv_mark())
alert("Datum can not be marked!")
continue
while(!D)
.["type"] = D.type
.["value"] = D
@@ -0,0 +1,12 @@
/client/proc/mark_datum(datum/D)
if(!holder)
return
if(holder.marked_datum)
vv_update_display(holder.marked_datum, "marked", "")
holder.marked_datum = D
vv_update_display(D, "marked", VV_MSG_MARKED)
/client/proc/mark_datum_mapview(datum/D as mob|obj|turf|area in view(view))
set category = "Debug"
set name = "Mark Object"
mark_datum(D)
@@ -197,7 +197,7 @@
log_admin("[key_name(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
message_admins("[key_name_admin(src)] mass modified [original_name]'s [variable] to [O.vars[variable]] ([accepted] objects modified)")
//not using global lists as vv is a debug function and debug functions should rely on as less things as possible.
/proc/get_all_of_type(var/T, subtypes = TRUE)
var/list/typecache = list()
typecache[T] = 1
@@ -205,19 +205,25 @@
typecache = typecacheof(typecache)
. = list()
if (ispath(T, /mob))
for(var/mob/thing in GLOB.mob_list)
for(var/mob/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
else if (ispath(T, /obj/machinery/door))
for(var/obj/machinery/door/thing in GLOB.airlocks)
for(var/obj/machinery/door/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
else if (ispath(T, /obj/machinery))
for(var/obj/machinery/thing in GLOB.machines)
for(var/obj/machinery/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
else if (ispath(T, /obj/item))
for(var/obj/item/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
@@ -247,7 +253,7 @@
CHECK_TICK
else if (ispath(T, /client))
for(var/client/thing in GLOB.clients)
for(var/client/thing in world)
if (typecache[thing.type])
. += thing
CHECK_TICK
@@ -1,264 +1,12 @@
GLOBAL_LIST_INIT(VVlocked, list("vars", "datum_flags", "client", "virus", "viruses", "cuffed", "last_eaten", "unlock_content", "force_ending"))
GLOBAL_LIST_INIT(VVlocked, list("vars", "datum_flags", "client", "mob")) //Requires DEBUG
GLOBAL_PROTECT(VVlocked)
GLOBAL_LIST_INIT(VVicon_edit_lock, list("icon", "icon_state", "overlays", "underlays", "resize"))
GLOBAL_LIST_INIT(VVicon_edit_lock, list("icon", "icon_state", "overlays", "underlays")) //Requires DEBUG or FUN
GLOBAL_PROTECT(VVicon_edit_lock)
GLOBAL_LIST_INIT(VVckey_edit, list("key", "ckey"))
GLOBAL_LIST_INIT(VVckey_edit, list("key", "ckey")) //Requires DEBUG or SPAWN
GLOBAL_PROTECT(VVckey_edit)
GLOBAL_LIST_INIT(VVpixelmovement, list("step_x", "step_y", "bound_height", "bound_width", "bound_x", "bound_y"))
GLOBAL_LIST_INIT(VVpixelmovement, list("bound_x", "bound_y", "step_x", "step_y", "step_size", "bound_height", "bound_width", "bounds")) //No editing ever.
GLOBAL_PROTECT(VVpixelmovement)
/client/proc/vv_get_class(var/var_name, var/var_value)
if(isnull(var_value))
. = VV_NULL
else if (isnum(var_value))
if (var_name in GLOB.bitfields)
. = VV_BITFIELD
else
. = VV_NUM
else if (istext(var_value))
if (findtext(var_value, "\n"))
. = VV_MESSAGE
else
. = VV_TEXT
else if (isicon(var_value))
. = VV_ICON
else if (ismob(var_value))
. = VV_MOB_REFERENCE
else if (isloc(var_value))
. = VV_ATOM_REFERENCE
else if (istype(var_value, /client))
. = VV_CLIENT
else if (istype(var_value, /datum))
. = VV_DATUM_REFERENCE
else if (ispath(var_value))
if (ispath(var_value, /atom))
. = VV_ATOM_TYPE
else if (ispath(var_value, /datum))
. = VV_DATUM_TYPE
else
. = VV_TYPE
else if (islist(var_value))
. = VV_LIST
else if (isfile(var_value))
. = VV_FILE
else
. = VV_NULL
/client/proc/vv_get_value(class, default_class, current_value, list/restricted_classes, list/extra_classes, list/classes, var_name)
. = list("class" = class, "value" = null)
if (!class)
if (!classes)
classes = list (
VV_NUM,
VV_TEXT,
VV_MESSAGE,
VV_ICON,
VV_ATOM_REFERENCE,
VV_DATUM_REFERENCE,
VV_MOB_REFERENCE,
VV_CLIENT,
VV_ATOM_TYPE,
VV_DATUM_TYPE,
VV_TYPE,
VV_FILE,
VV_NEW_ATOM,
VV_NEW_DATUM,
VV_NEW_TYPE,
VV_NEW_LIST,
VV_NULL,
VV_RESTORE_DEFAULT
)
if(holder && holder.marked_datum && !(VV_MARKED_DATUM in restricted_classes))
classes += "[VV_MARKED_DATUM] ([holder.marked_datum.type])"
if (restricted_classes)
classes -= restricted_classes
if (extra_classes)
classes += extra_classes
.["class"] = input(src, "What kind of data?", "Variable Type", default_class) as null|anything in classes
if (holder && holder.marked_datum && .["class"] == "[VV_MARKED_DATUM] ([holder.marked_datum.type])")
.["class"] = VV_MARKED_DATUM
switch(.["class"])
if (VV_TEXT)
.["value"] = input("Enter new text:", "Text", current_value) as null|text
if (.["value"] == null)
.["class"] = null
return
if (VV_MESSAGE)
.["value"] = input("Enter new text:", "Text", current_value) as null|message
if (.["value"] == null)
.["class"] = null
return
if (VV_NUM)
.["value"] = input("Enter new number:", "Num", current_value) as null|num
if (.["value"] == null)
.["class"] = null
return
if (VV_BITFIELD)
.["value"] = input_bitfield(usr, "Editing bitfield: [var_name]", var_name, current_value)
if (.["value"] == null)
.["class"] = null
return
if (VV_ATOM_TYPE)
.["value"] = pick_closest_path(FALSE)
if (.["value"] == null)
.["class"] = null
return
if (VV_DATUM_TYPE)
.["value"] = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
if (.["value"] == null)
.["class"] = null
return
if (VV_TYPE)
var/type = current_value
var/error = ""
do
type = input("Enter type:[error]", "Type", type) as null|text
if (!type)
break
type = text2path(type)
error = "\nType not found, Please try again"
while(!type)
if (!type)
.["class"] = null
return
.["value"] = type
if (VV_ATOM_REFERENCE)
var/type = pick_closest_path(FALSE)
var/subtypes = vv_subtype_prompt(type)
if (subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if (!value)
.["class"] = null
return
.["value"] = things[value]
if (VV_DATUM_REFERENCE)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
var/subtypes = vv_subtype_prompt(type)
if (subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if (!value)
.["class"] = null
return
.["value"] = things[value]
if (VV_MOB_REFERENCE)
var/type = pick_closest_path(FALSE, make_types_fancy(typesof(/mob)))
var/subtypes = vv_subtype_prompt(type)
if (subtypes == null)
.["class"] = null
return
var/list/things = vv_reference_list(type, subtypes)
var/value = input("Select reference:", "Reference", current_value) as null|anything in things
if (!value)
.["class"] = null
return
.["value"] = things[value]
if (VV_CLIENT)
.["value"] = input("Select reference:", "Reference", current_value) as null|anything in GLOB.clients
if (.["value"] == null)
.["class"] = null
return
if (VV_FILE)
.["value"] = input("Pick file:", "File") as null|file
if (.["value"] == null)
.["class"] = null
return
if (VV_ICON)
.["value"] = input("Pick icon:", "Icon") as null|icon
if (.["value"] == null)
.["class"] = null
return
if (VV_MARKED_DATUM)
.["value"] = holder.marked_datum
if (.["value"] == null)
.["class"] = null
return
if (VV_NEW_ATOM)
var/type = pick_closest_path(FALSE)
if (!type)
.["class"] = null
return
.["type"] = type
var/atom/newguy = new type()
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if (VV_NEW_DATUM)
var/type = pick_closest_path(FALSE, get_fancy_list_of_datum_types())
if (!type)
.["class"] = null
return
.["type"] = type
var/datum/newguy = new type()
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if (VV_NEW_TYPE)
var/type = current_value
var/error = ""
do
type = input("Enter type:[error]", "Type", type) as null|text
if (!type)
break
type = text2path(type)
error = "\nType not found, Please try again"
while(!type)
if (!type)
.["class"] = null
return
.["type"] = type
var/datum/newguy = new type()
if(istype(newguy))
newguy.datum_flags |= DF_VAR_EDITED
.["value"] = newguy
if (VV_NEW_LIST)
.["value"] = list()
.["type"] = /list
/client/proc/vv_parse_text(O, new_var)
if(O && findtext(new_var,"\["))
var/process_vars = alert(usr,"\[] detected in string, process as variables?","Process Variables?","Yes","No")
@@ -372,13 +120,13 @@ GLOBAL_PROTECT(VVpixelmovement)
if(confirm != "Continue")
return
var/is_normal_list = IS_NORMAL_LIST(L)
var/list/names = list()
for (var/i in 1 to L.len)
var/key = L[i]
var/value
if (IS_NORMAL_LIST(L) && !isnum(key))
if (is_normal_list && !isnum(key))
value = L[key]
if (value == null)
value = "null"
@@ -439,10 +187,17 @@ GLOBAL_PROTECT(VVpixelmovement)
assoc_key = L[index]
var/default
var/variable
if (assoc)
variable = L[assoc_key]
else
variable = L[index]
var/old_assoc_value //EXPERIMENTAL - Keep old associated value while modifying key, if any
if(is_normal_list)
if (assoc)
variable = L[assoc_key]
else
variable = L[index]
//EXPERIMENTAL - Keep old associated value while modifying key, if any
var/found = L[variable]
if(!isnull(found))
old_assoc_value = found
//
default = vv_get_class(objectvar, variable)
@@ -504,11 +259,13 @@ GLOBAL_PROTECT(VVpixelmovement)
for(var/V in varsvars)
new_var = replacetext(new_var,"\[[V]]","[O.vars[V]]")
if(assoc)
L[assoc_key] = new_var
else
L[index] = new_var
if(is_normal_list)
if(assoc)
L[assoc_key] = new_var
else
L[index] = new_var
if(!isnull(old_assoc_value) && IS_VALID_ASSOC_KEY(new_var))
L[new_var] = old_assoc_value
if (O)
if (O.vv_edit_var(objectvar, L) == FALSE)
to_chat(src, "Your edit was rejected by the object.")
@@ -527,15 +284,8 @@ GLOBAL_PROTECT(VVpixelmovement)
if(param_var_name in GLOB.VVicon_edit_lock)
if(!check_rights(R_FUN|R_DEBUG))
return FALSE
if(param_var_name in GLOB.VVpixelmovement)
if(!check_rights(R_DEBUG))
return FALSE
var/prompt = alert(usr, "Editing this var may irreparably break tile gliding for the rest of the round. THIS CAN'T BE UNDONE", "DANGER", "ABORT ", "Continue", " ABORT")
if (prompt != "Continue")
return FALSE
return TRUE
/client/proc/modify_variables(atom/O, param_var_name = null, autodetect_class = 0)
if(!check_rights(R_VAREDIT))
return
@@ -567,11 +317,6 @@ GLOBAL_PROTECT(VVpixelmovement)
var_value = O.vars[variable]
if(!vv_varname_lockcheck(variable))
return
if(istype(O, /datum/armor))
var/prompt = alert(src, "Editing this var changes this value on potentially thousands of items that share the same combination of armor values. If you want to edit the armor of just one item, use the \"Modify armor values\" dropdown item", "DANGER", "ABORT ", "Continue", " ABORT")
if (prompt != "Continue")
return
var/default = vv_get_class(variable, var_value)
@@ -635,10 +380,9 @@ GLOBAL_PROTECT(VVpixelmovement)
to_chat(src, "Your edit was rejected by the object.")
return
vv_update_display(O, "varedited", VV_MSG_EDITED)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_VAR_EDIT, args)
log_world("### VarEdit by [key_name(src)]: [O.type] [variable]=[var_value] => [var_new]")
log_admin("[key_name(src)] modified [original_name]'s [variable] from [html_encode("[var_value]")] to [html_encode("[var_new]")]")
var/msg = "[key_name_admin(src)] modified [original_name]'s [variable] from [var_value] to [var_new]"
message_admins(msg)
admin_ticket_log(O, msg)
return TRUE
return TRUE
+128
View File
@@ -0,0 +1,128 @@
//DO NOT ADD MORE TO THIS FILE.
//Use vv_do_topic() for datums!
/client/proc/view_var_Topic(href, href_list, hsrc)
if( (usr.client != src) || !src.holder || !holder.CheckAdminHref(href, href_list))
return
var/target = GET_VV_TARGET
vv_do_basic(target, href_list, href)
if(istype(target, /datum))
var/datum/D = target
D.vv_do_topic(href_list)
else if(islist(target))
vv_do_list(target, href_list)
if(href_list["Vars"])
debug_variables(locate(href_list["Vars"]))
//Stuff below aren't in dropdowns/etc.
if(check_rights(R_VAREDIT))
//~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records).
if(href_list["rename"])
if(!check_rights(NONE))
return
var/mob/M = locate(href_list["rename"]) in GLOB.mob_list
if(!istype(M))
to_chat(usr, "This can only be used on instances of type /mob")
return
var/new_name = stripped_input(usr,"What would you like to name this mob?","Input a name",M.real_name,MAX_NAME_LEN)
if( !new_name || !M )
return
message_admins("Admin [key_name_admin(usr)] renamed [key_name_admin(M)] to [new_name].")
M.fully_replace_character_name(M.real_name,new_name)
vv_update_display(M, "name", new_name)
vv_update_display(M, "real_name", M.real_name || "No real name")
else if(href_list["rotatedatum"])
if(!check_rights(NONE))
return
var/atom/A = locate(href_list["rotatedatum"])
if(!istype(A))
to_chat(usr, "This can only be done to instances of type /atom")
return
switch(href_list["rotatedir"])
if("right")
A.setDir(turn(A.dir, -45))
if("left")
A.setDir(turn(A.dir, 45))
vv_update_display(A, "dir", dir2text(A.dir))
else if(href_list["makehuman"])
if(!check_rights(R_SPAWN))
return
var/mob/living/carbon/monkey/Mo = locate(href_list["makehuman"]) in GLOB.mob_list
if(!istype(Mo))
to_chat(usr, "This can only be done to instances of type /mob/living/carbon/monkey")
return
if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
return
if(!Mo)
to_chat(usr, "Mob doesn't exist anymore")
return
holder.Topic(href, list("humanone"=href_list["makehuman"]))
else if(href_list["adjustDamage"] && href_list["mobToDamage"])
if(!check_rights(NONE))
return
var/mob/living/L = locate(href_list["mobToDamage"]) in GLOB.mob_list
if(!istype(L))
return
var/Text = href_list["adjustDamage"]
var/amount = input("Deal how much damage to mob? (Negative values here heal)","Adjust [Text]loss",0) as num
if(!L)
to_chat(usr, "Mob doesn't exist anymore")
return
var/newamt
switch(Text)
if("brute")
L.adjustBruteLoss(amount)
newamt = L.getBruteLoss()
if("fire")
L.adjustFireLoss(amount)
newamt = L.getFireLoss()
if("toxin")
L.adjustToxLoss(amount)
newamt = L.getToxLoss()
if("oxygen")
L.adjustOxyLoss(amount)
newamt = L.getOxyLoss()
if("brain")
L.adjustOrganLoss(ORGAN_SLOT_BRAIN, amount)
newamt = L.getOrganLoss(ORGAN_SLOT_BRAIN)
if("clone")
L.adjustCloneLoss(amount)
newamt = L.getCloneLoss()
if("stamina")
L.adjustStaminaLoss(amount)
newamt = L.getStaminaLoss()
else
to_chat(usr, "You caused an error. DEBUG: Text:[Text] Mob:[L]")
return
if(amount != 0)
var/log_msg = "[key_name(usr)] dealt [amount] amount of [Text] damage to [key_name(L)]"
message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [ADMIN_LOOKUPFLW(L)]")
log_admin(log_msg)
admin_ticket_log(L, "<font color='blue'>[log_msg]</font>")
vv_update_display(L, Text, "[newamt]")
//Finally, refresh if something modified the list.
if(href_list["datumrefresh"])
var/datum/DAT = locate(href_list["datumrefresh"])
if(istype(DAT, /datum) || istype(DAT, /client))
debug_variables(DAT)
@@ -0,0 +1,51 @@
//Not using datum.vv_do_topic for very basic/low level debug things, incase the datum's vv_do_topic is runtiming/whatnot.
/client/proc/vv_do_basic(datum/target, href_list)
var/target_var = GET_VV_VAR_TARGET
if(check_rights(R_VAREDIT))
if(target_var)
if(href_list[VV_HK_BASIC_EDIT])
if(!modify_variables(target, target_var, 1))
return
switch(target_var)
if("name")
vv_update_display(target, "name", "[target]")
if("dir")
var/atom/A = target
if(istype(A))
vv_update_display(target, "dir", dir2text(A.dir) || A.dir)
if("ckey")
var/mob/living/L = target
if(istype(L))
vv_update_display(target, "ckey", L.ckey || "No ckey")
if("real_name")
var/mob/living/L = target
if(istype(L))
vv_update_display(target, "real_name", L.real_name || "No real name")
if(href_list[VV_HK_BASIC_CHANGE])
modify_variables(target, target_var, 0)
if(href_list[VV_HK_BASIC_MASSEDIT])
cmd_mass_modify_object_variables(target, target_var)
if(check_rights(R_ADMIN, FALSE))
if(href_list[VV_HK_EXPOSE])
var/value = vv_get_value(VV_CLIENT)
if (value["class"] != VV_CLIENT)
return
var/client/C = value["value"]
if (!C)
return
if(!target)
to_chat(usr, "<span class='warning'>The object you tried to expose to [C] no longer exists (nulled or hard-deled)</span>")
return
message_admins("[key_name_admin(usr)] Showed [key_name_admin(C)] a <a href='?_src_=vars;datumrefresh=[REF(target)]'>VV window</a>")
log_admin("Admin [key_name(usr)] Showed [key_name(C)] a VV window of a [target]")
to_chat(C, "[holder.fakekey ? "an Administrator" : "[usr.client.key]"] has granted you access to view a View Variables window")
C.debug_variables(target)
if(check_rights(R_DEBUG))
if(href_list[VV_HK_DELETE])
usr.client.admin_delete(target)
if (isturf(src)) // show the turf that took its place
usr.client.debug_variables(src)
if(href_list[VV_HK_MARK])
usr.client.mark_datum(target)
if(href_list[VV_HK_CALLPROC])
usr.client.callproc_datum(target)
@@ -0,0 +1,43 @@
//LISTS - CAN NOT DO VV_DO_TOPIC BECAUSE LISTS AREN'T DATUMS :(
/client/proc/vv_do_list(list/target, href_list)
var/target_index = text2num(GET_VV_VAR_TARGET)
if(check_rights(R_VAREDIT))
if(target_index)
if(href_list[VV_HK_LIST_EDIT])
mod_list(target, null, "list", "contents", target_index, autodetect_class = TRUE)
if(href_list[VV_HK_LIST_CHANGE])
mod_list(target, null, "list", "contents", target_index, autodetect_class = FALSE)
if(href_list[VV_HK_LIST_REMOVE])
var/variable = target[target_index]
var/prompt = alert("Do you want to remove item number [target_index] from list?", "Confirm", "Yes", "No")
if (prompt != "Yes")
return
target.Cut(target_index, target_index+1)
log_world("### ListVarEdit by [src]: /list's contents: REMOVED=[html_encode("[variable]")]")
log_admin("[key_name(src)] modified list's contents: REMOVED=[variable]")
message_admins("[key_name_admin(src)] modified list's contents: REMOVED=[variable]")
if(href_list[VV_HK_LIST_ADD])
mod_list_add(target, null, "list", "contents")
if(href_list[VV_HK_LIST_ERASE_DUPES])
uniqueList_inplace(target)
log_world("### ListVarEdit by [src]: /list contents: CLEAR DUPES")
log_admin("[key_name(src)] modified list's contents: CLEAR DUPES")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR DUPES")
if(href_list[VV_HK_LIST_ERASE_NULLS])
listclearnulls(target)
log_world("### ListVarEdit by [src]: /list contents: CLEAR NULLS")
log_admin("[key_name(src)] modified list's contents: CLEAR NULLS")
message_admins("[key_name_admin(src)] modified list's contents: CLEAR NULLS")
if(href_list[VV_HK_LIST_SET_LENGTH])
var/value = vv_get_value(VV_NUM)
if (value["class"] != VV_NUM || value["value"] > max(50000, target.len)) //safety - would rather someone not put an extra 0 and erase the server's memory lmao.
return
target.len = value["value"]
log_world("### ListVarEdit by [src]: /list len: [target.len]")
log_admin("[key_name(src)] modified list's len: [target.len]")
message_admins("[key_name_admin(src)] modified list's len: [target.len]")
if(href_list[VV_HK_LIST_SHUFFLE])
shuffle_inplace(target)
log_world("### ListVarEdit by [src]: /list contents: SHUFFLE")
log_admin("[key_name(src)] modified list's contents: SHUFFLE")
message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE")
@@ -0,0 +1,269 @@
/client/proc/debug_variables(datum/D in world)
set category = "Debug"
set name = "View Variables"
//set src in world
var/static/cookieoffset = rand(1, 9999) //to force cookies to reset after the round.
if(!usr.client || !usr.client.holder) //This is usr because admins can call the proc on other clients, even if they're not admins, to show them VVs.
to_chat(usr, "<span class='danger'>You need to be an administrator to access this.</span>")
return
if(!D)
return
var/islist = islist(D)
if(!islist && !istype(D))
return
var/title = ""
var/refid = REF(D)
var/icon/sprite
var/hash
var/type = islist? /list : D.type
var/no_icon = FALSE
if(istype(D, /atom))
sprite = getFlatIcon(D)
hash = md5(sprite)
if(sprite)
hash = md5(sprite)
src << browse_rsc(sprite, "vv[hash].png")
else
no_icon = TRUE
title = "[D] ([REF(D)]) = [type]"
var/formatted_type = replacetext("[type]", "/", "<wbr>/")
var/sprite_text
if(sprite)
sprite_text = no_icon? "\[NO ICON\]" : "<img src='vv[hash].png'></td><td>"
var/list/header = islist(D)? list("<b>/list</b>") : D.vv_get_header()
var/marked_line
if(holder && holder.marked_datum && holder.marked_datum == D)
marked_line = VV_MSG_MARKED
var/varedited_line
if(!islist && (D.datum_flags & DF_VAR_EDITED))
varedited_line = VV_MSG_EDITED
var/deleted_line
if(!islist && D.gc_destroyed)
deleted_line = VV_MSG_DELETED
var/list/dropdownoptions
if (islist)
dropdownoptions = list(
"---",
"Add Item" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ADD),
"Remove Nulls" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_NULLS),
"Remove Dupes" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_ERASE_DUPES),
"Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH),
"Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE),
"Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE),
"---"
)
for(var/i in 1 to length(dropdownoptions))
var/name = dropdownoptions[i]
var/link = dropdownoptions[name]
dropdownoptions[i] = "<option value[link? "='[link]'":""]>[name]</option>"
else
dropdownoptions = D.vv_get_dropdown()
var/list/names = list()
if(!islist)
for(var/V in D.vars)
names += V
sleep(1)
var/list/variable_html = list()
if(islist)
var/list/L = D
for(var/i in 1 to L.len)
var/key = L[i]
var/value
if(IS_NORMAL_LIST(L) && IS_VALID_ASSOC_KEY(key))
value = L[key]
variable_html += debug_variable(i, value, 0, L)
else
names = sortList(names)
for(var/V in names)
if(D.can_vv_get(V))
variable_html += D.vv_get_var(V)
var/html = {"
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>[title]</title>
<style>
body {
font-family: Verdana, sans-serif;
font-size: 9pt;
}
.value {
font-family: "Courier New", monospace;
font-size: 8pt;
}
</style>
</head>
<body onload='selectTextField()' onkeydown='return handle_keydown()' onkeyup='handle_keyup()'>
<script type="text/javascript">
// onload
function selectTextField() {
var filter_text = document.getElementById('filter');
filter_text.focus();
filter_text.select();
var lastsearch = getCookie("[refid][cookieoffset]search");
if (lastsearch) {
filter_text.value = lastsearch;
updateSearch();
}
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca\[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
}
// main search functionality
var last_filter = "";
function updateSearch() {
var filter = document.getElementById('filter').value.toLowerCase();
var vars_ol = document.getElementById("vars");
if (filter === last_filter) {
// An event triggered an update but nothing has changed.
return;
} else if (filter.indexOf(last_filter) === 0) {
// The new filter starts with the old filter, fast path by removing only.
var children = vars_ol.childNodes;
for (var i = children.length - 1; i >= 0; --i) {
try {
var li = children\[i];
if (li.innerText.toLowerCase().indexOf(filter) == -1) {
vars_ol.removeChild(li);
}
} catch(err) {}
}
} else {
// Remove everything and put back what matches.
while (vars_ol.hasChildNodes()) {
vars_ol.removeChild(vars_ol.lastChild);
}
for (var i = 0; i < complete_list.length; ++i) {
try {
var li = complete_list\[i];
if (!filter || li.innerText.toLowerCase().indexOf(filter) != -1) {
vars_ol.appendChild(li);
}
} catch(err) {}
}
}
last_filter = filter;
document.cookie="[refid][cookieoffset]search="+encodeURIComponent(filter);
}
// onkeydown
function handle_keydown() {
if(event.keyCode == 116) { //F5 (to refresh properly)
document.getElementById("refresh_link").click();
event.preventDefault ? event.preventDefault() : (event.returnValue = false);
return false;
}
return true;
}
// onkeyup
function handle_keyup() {
updateSearch();
}
// onchange
function handle_dropdown(list) {
var value = list.options\[list.selectedIndex].value;
if (value !== "") {
location.href = value;
}
list.selectedIndex = 0;
document.getElementById('filter').focus();
}
// byjax
function replace_span(what) {
var idx = what.indexOf(':');
document.getElementById(what.substr(0, idx)).innerHTML = what.substr(idx + 1);
}
</script>
<div align='center'>
<table width='100%'>
<tr>
<td width='50%'>
<table align='center' width='100%'>
<tr>
<td>
[sprite_text]
<div align='center'>
[header.Join()]
</div>
</td>
</tr>
</table>
<div align='center'>
<b><font size='1'>[formatted_type]</font></b>
<span id='marked'>[marked_line]</span>
<span id='varedited'>[varedited_line]</span>
<span id='deleted'>[deleted_line]</span>
</div>
</td>
<td width='50%'>
<div align='center'>
<a id='refresh_link' href='?_src_=vars;
datumrefresh=[refid];[HrefToken()]'>Refresh</a>
<form>
<select name="file" size="1"
onchange="handle_dropdown(this)"
onmouseclick="this.focus()">
<option value selected>Select option</option>
[dropdownoptions.Join()]
</select>
</form>
</div>
</td>
</tr>
</table>
</div>
<hr>
<font size='1'>
<b>E</b> - Edit, tries to determine the variable type by itself.<br>
<b>C</b> - Change, asks you for the var type first.<br>
<b>M</b> - Mass modify: changes this variable for all objects of this type.<br>
</font>
<hr>
<table width='100%'>
<tr>
<td width='20%'>
<div align='center'>
<b>Search:</b>
</div>
</td>
<td width='80%'>
<input type='text' id='filter' name='filter_text' value='' style='width:100%;'>
</td>
</tr>
</table>
<hr>
<ol id='vars'>
[variable_html.Join()]
</ol>
<script type='text/javascript'>
var complete_list = \[\];
var lis = document.getElementById("vars").children;
for(var i = lis.length; i--;) complete_list\[i\] = lis\[i\];
</script>
</body>
</html>
"}
src << browse(html, "window=variables[refid];size=475x650")
/client/proc/vv_update_display(datum/D, span, content)
src << output("[span]:[content]", "variables[REF(D)].browser:replace_span")
@@ -31,4 +31,5 @@
/datum/antagonist/abductee/remove_innate_effects(mob/living/mob_override)
update_abductor_icons_removed(mob_override ? mob_override.mind : owner)
qdel(brain_trauma)
if(!QDELETED(brain_trauma))
qdel(brain_trauma)
@@ -353,6 +353,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 +368,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."
@@ -117,7 +117,7 @@
tinfoil_check = FALSE
/obj/effect/proc_holder/spell/aoe_turf/revenant
clothes_req = 0
clothes_req = NONE
action_icon = 'icons/mob/actions/actions_revenant.dmi'
action_background_icon_state = "bg_revenant"
panel = "Revenant Abilities (Locked)"
@@ -135,7 +135,7 @@
else
name = "[initial(name)] ([cast_amount]E)"
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr)
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr, skipcharge = FALSE, silent = FALSE)
if(charge_counter < charge_max)
return FALSE
if(!istype(user)) //Badmins, no. Badmins, don't do it.
+1 -1
View File
@@ -18,7 +18,7 @@
owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/presents)
var/obj/effect/proc_holder/spell/targeted/area_teleport/teleport/telespell = new
telespell.clothes_req = 0 //santa robes aren't actually magical.
telespell.clothes_req = NONE //santa robes aren't actually magical.
owner.AddSpell(telespell) //does the station have chimneys? WHO KNOWS!
/datum/antagonist/santa/proc/give_objective()
@@ -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
@@ -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
+1 -1
View File
@@ -287,7 +287,7 @@
/datum/supply_pack/emergency/specialops
name = "Special Ops Supplies"
desc = "(*!&@#TOO CHEAP FOR THAT NULL_ENTRY, HUH OPERATIVE? WELL, THIS LITTLE ORDER CAN STILL HELP YOU OUT IN A PINCH. CONTAINS A BOX OF FIVE EMP GRENADES, THREE SMOKEBOMBS, AN INCENDIARY GRENADE, AND A \"SLEEPY PEN\" FULL OF NICE TOXINS!#@*$"
desc = "(*!&@#NEED SOMETHING TO DEAL WITH THE GREYTIDE, HUH OPERATIVE? WELL, THIS LITTLE ORDER CAN HELP YOU OUT IN A PINCH. CONTAINS A BOX OF FIVE EMP GRENADES, THREE SMOKEBOMBS, AN INCENDIARY GRENADE, AND A \"SLEEPY PEN\" FULL OF NICE TOXINS!#@*$"
hidden = TRUE
cost = 2200
contains = list(/obj/item/storage/box/emps,
+27 -8
View File
@@ -125,6 +125,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,
@@ -762,7 +763,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
else
dat += "<b>Penis Color:</b></a><BR>"
dat += "<span style='border: 1px solid #161616; background-color: #[features["cock_color"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=cock_color;task=input'>Change</a><br>"
dat += "<b>Penis Shape:</b> <a style='display:block;width:120px' href='?_src_=prefs;preference=cock_shape;task=input'>[features["cock_shape"]]</a>"
var/tauric_shape = FALSE
if(features["cock_taur"])
var/datum/sprite_accessory/penis/P = GLOB.cock_shapes_list[features["cock_shape"]]
if(P.taur_icon && pref_species.mutant_bodyparts["taur"])
var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]]
if(T.taur_mode & P.accepted_taurs)
tauric_shape = TRUE
dat += "<b>Penis Shape:</b> <a style='display:block;width:120px' href='?_src_=prefs;preference=cock_shape;task=input'>[features["cock_shape"]][tauric_shape ? " (Taur)" : ""]</a>"
dat += "<b>Penis Length:</b> <a style='display:block;width:120px' href='?_src_=prefs;preference=cock_length;task=input'>[features["cock_length"]] inch(es)</a>"
dat += "<b>Penis Visibility:</b><a style='display:block;width:100px' href='?_src_=prefs;preference=cock_visibility;task=input'>[features["cock_visibility"]]</a>"
dat += "<b>Has Testicles:</b><a style='display:block;width:50px' href='?_src_=prefs;preference=has_balls'>[features["has_balls"] == TRUE ? "Yes" : "No"]</a>"
@@ -1610,7 +1618,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 +1629,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")
@@ -1922,7 +1930,7 @@ 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")
@@ -1941,8 +1949,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,7 +1970,7 @@ 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")
@@ -1978,7 +1997,7 @@ 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")
@@ -2000,7 +2019,7 @@ 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")
+11 -1
View File
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
#define SAVEFILE_VERSION_MAX 27
#define SAVEFILE_VERSION_MAX 28
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -151,6 +151,14 @@ 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
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey)
return
@@ -457,6 +465,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"]
@@ -673,6 +682,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"])
@@ -343,3 +343,45 @@
desc = "A bandana made from durathread, you wish it would provide some protection to its wearer, but it's far too thin..."
icon_state = "banddurathread"
/obj/item/clothing/mask/paper
name = "paper mask"
desc = "A neat, circular mask made out of paper."
icon_state = "plainmask"
item_state = "plainmask"
flags_inv = HIDEFACE|HIDEFACIALHAIR
resistance_flags = FLAMMABLE
max_integrity = 100
actions_types = list(/datum/action/item_action/adjust)
/obj/item/clothing/mask/paper/ui_action_click(mob/user)
if(!istype(user) || user.incapacitated())
return
var/list/options = list()
options["Blank"] = "plainmask"
options["Neutral"] = "neutralmask"
options["Eyes"] = "eyemask"
options["Sleeping"] ="sleepingmask"
options["Heart"] = "heartmask"
options["Core"] = "coremask"
options["Plus"] = "plusmask"
options["Square"] ="squaremask"
options["Bullseye"] = "bullseyemask"
options["Vertical"] = "verticalmask"
options["Horizontal"] = "horizontalmask"
options["X"] ="xmask"
options["Bugeyes"] = "bugmask"
options["Double"] = "doublemask"
options["Mark"] = "markmask"
var/choice = input(user,"What symbol would you want on this mask?","Morph Mask") in options
if(src && choice && !user.incapacitated() && in_range(user,src))
icon_state = options[choice]
user.update_inv_wear_mask()
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
to_chat(user, "<span class='notice'>Your paper mask now has a [choice] symbol!</span>")
return 1
+6 -1
View File
@@ -422,6 +422,10 @@
heat_protection = HEAD //Uncomment to enable firesuit protection
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
/obj/item/clothing/head/helmet/space/hardsuit/wizard/ComponentInitialize()
. = ..()
AddElement(/datum/element/spellcasting, SPELL_WIZARD_HAT, ITEM_SLOT_HEAD)
/obj/item/clothing/suit/space/hardsuit/wizard
icon_state = "hardsuit-wiz"
name = "gem-encrusted hardsuit"
@@ -436,9 +440,10 @@
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/wizard
mutantrace_variation = STYLE_DIGITIGRADE
/obj/item/clothing/suit/space/hardsuit/wizard/Initialize()
/obj/item/clothing/suit/space/hardsuit/wizard/ComponentInitialize()
. = ..()
AddComponent(/datum/component/anti_magic, TRUE, FALSE, FALSE, ITEM_SLOT_OCLOTHING, INFINITY, FALSE)
AddElement(/datum/element/spellcasting, SPELL_WIZARD_ROBE, ITEM_SLOT_OCLOTHING)
//Medical hardsuit
/obj/item/clothing/head/helmet/space/hardsuit/medical
+27 -11
View File
@@ -9,6 +9,12 @@
equip_delay_other = 50
resistance_flags = FIRE_PROOF | ACID_PROOF
dog_fashion = /datum/dog_fashion/head/blue_wizard
var/magic_flags = SPELL_WIZARD_HAT
/obj/item/clothing/head/wizard/ComponentInitialize()
. = ..()
if(magic_flags)
AddElement(/datum/element/spellcasting, magic_flags, ITEM_SLOT_HEAD)
/obj/item/clothing/head/wizard/red
name = "red wizard hat"
@@ -36,7 +42,7 @@
permeability_coefficient = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
resistance_flags = FLAMMABLE
dog_fashion = /datum/dog_fashion/head/blue_wizard
magic_flags = NONE
/obj/item/clothing/head/wizard/marisa
name = "witch hat"
@@ -50,6 +56,7 @@
icon_state = "magus"
item_state = "magus"
dog_fashion = null
magic_flags = SPELL_WIZARD_HAT|SPELL_CULT_HELMET
/obj/item/clothing/head/wizard/santa
name = "Santa's hat"
@@ -72,6 +79,12 @@
strip_delay = 50
equip_delay_other = 50
resistance_flags = FIRE_PROOF | ACID_PROOF
var/magic_flags = SPELL_WIZARD_ROBE
/obj/item/clothing/suit/wizrobe/ComponentInitialize()
. = ..()
if(magic_flags)
AddElement(/datum/element/spellcasting, magic_flags, ITEM_SLOT_OCLOTHING)
/obj/item/clothing/suit/wizrobe/red
name = "red wizard robe"
@@ -102,13 +115,14 @@
desc = "A set of armored robes that seem to radiate a dark power."
icon_state = "magusblue"
item_state = "magusblue"
magic_flags = SPELL_WIZARD_ROBE|SPELL_CULT_ARMOR
/obj/item/clothing/suit/wizrobe/magusred
name = "\improper Magus robe"
desc = "A set of armored robes that seem to radiate a dark power."
icon_state = "magusred"
item_state = "magusred"
magic_flags = SPELL_WIZARD_ROBE|SPELL_CULT_ARMOR
/obj/item/clothing/suit/wizrobe/santa
name = "Santa's suit"
@@ -117,33 +131,27 @@
item_state = "santa"
/obj/item/clothing/suit/wizrobe/fake
name = "wizard robe"
desc = "A rather dull blue robe meant to mimick real wizard robes."
icon_state = "wizard-fake"
item_state = "wizrobe"
gas_transfer_coefficient = 1
permeability_coefficient = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
resistance_flags = FLAMMABLE
magic_flags = NONE
/obj/item/clothing/head/wizard/marisa/fake
name = "witch hat"
desc = "Strange-looking hat-wear, makes you want to cast fireballs."
icon_state = "marisa"
gas_transfer_coefficient = 1
permeability_coefficient = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
resistance_flags = FLAMMABLE
magic_flags = NONE
/obj/item/clothing/suit/wizrobe/marisa/fake
name = "witch robe"
desc = "Magic is all about the spell power, ZE!"
icon_state = "marisa"
item_state = "marisarobe"
gas_transfer_coefficient = 1
permeability_coefficient = 1
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
resistance_flags = FLAMMABLE
magic_flags = NONE
/obj/item/clothing/suit/wizrobe/paper
name = "papier-mache robe" // no non-latin characters!
@@ -198,6 +206,10 @@
slowdown = 0
resistance_flags = FIRE_PROOF | ACID_PROOF
/obj/item/clothing/suit/space/hardsuit/shielded/wizard/ComponentInitialize()
. = ..()
AddElement(/datum/element/spellcasting, SPELL_WIZARD_HAT, ITEM_SLOT_HEAD)
/obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard
name = "battlemage helmet"
desc = "A suitably impressive helmet.."
@@ -209,6 +221,10 @@
actions_types = null //No inbuilt light
resistance_flags = FIRE_PROOF | ACID_PROOF
/obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard/ComponentInitialize()
. = ..()
AddElement(/datum/element/spellcasting, SPELL_WIZARD_ROBE, ITEM_SLOT_OCLOTHING)
/obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard/attack_self(mob/user)
return
+1 -1
View File
@@ -59,7 +59,7 @@
SA.del_on_death = FALSE
spawned_mobs += SA
SA.AddElement(/datum/element/ghost_role_eligibility)
SA.AddElement(/datum/element/ghost_role_eligibility, penalize_on_ghost = TRUE)
to_chat(SA, "<span class='userdanger'>Hello world!</span>")
to_chat(SA, "<span class='warning'>Due to freak radiation and/or chemicals \
and/or lucky chance, you have gained human level intelligence \
+6 -10
View File
@@ -393,17 +393,13 @@
/datum/spacevine_controller/vv_get_dropdown()
. = ..()
. += "---"
.["Delete Vines"] = "?_src_=[REF(src)];[HrefToken()];purge_vines=1"
VV_DROPDOWN_OPTION(VV_HK_SPACEVINE_PURGE, "Delete Vines")
/datum/spacevine_controller/Topic(href, href_list)
if(..() || !check_rights(R_ADMIN, FALSE) || !usr.client.holder.CheckAdminHref(href, href_list))
return
if(href_list["purge_vines"])
if(alert(usr, "Are you sure you want to delete this spacevine cluster?", "Delete Vines", "Yes", "No") != "Yes")
return
DeleteVines()
/datum/spacevine_controller/vv_do_topic(href_list)
. = ..()
if(href_list[VV_HK_SPACEVINE_PURGE])
if(alert(usr, "Are you sure you want to delete this spacevine cluster?", "Delete Vines", "Yes", "No") == "Yes")
DeleteVines()
/datum/spacevine_controller/proc/DeleteVines() //this is kill
QDEL_LIST(vines) //this will also qdel us
+1 -1
View File
@@ -15,7 +15,7 @@
var/spell_improved = FALSE
for(var/obj/effect/proc_holder/spell/S in L.mind.spell_list)
if(S.clothes_req)
S.clothes_req = 0
S.clothes_req = NONE
spell_improved = TRUE
if(spell_improved)
to_chat(L, "<span class='notice'>You suddenly feel like you never needed those garish robes in the first place...</span>")
+3
View File
@@ -301,6 +301,9 @@
rate = 0.04
glow_color = "#AAD84B"
/datum/plant_gene/trait/glow/shadow/glow_power(obj/item/seeds/S)
return -max(S.potency*(rate*0.2), 0.2)
/datum/plant_gene/trait/glow/white
name = "White Bioluminescence"
glow_color = "#FFFFFF"
-8
View File
@@ -87,14 +87,6 @@
return
. = ..()
/obj/machinery/computer/shuttle/mining/common
name = "lavaland shuttle console"
desc = "Used to call and send the lavaland shuttle."
req_access = list()
circuit = /obj/item/circuitboard/computer/mining_shuttle/common
shuttleId = "mining_common"
possible_destinations = "lavaland_common_away;commonmining_home"
/**********************Mining car (Crate like thing, not the rail car)**************************/
/obj/structure/closet/crate/miningcar
+25 -11
View File
@@ -263,14 +263,15 @@ Works together with spawning an observer, noted above.
*/
/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE, penalize = FALSE, voluntary = FALSE)
penalize = suiciding || penalize // suicide squad.
var/sig_flags = SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special, penalize)
penalize = !(sig_flags & COMPONENT_DO_NOT_PENALIZE_GHOSTING) && (suiciding || penalize) // suicide squad.
voluntary_ghosted = voluntary
if(!key || key[1] == "@" || (SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special, penalize) & COMPONENT_BLOCK_GHOSTING))
if(!key || key[1] == "@" || (sig_flags & COMPONENT_BLOCK_GHOSTING))
return //mob has no key, is an aghost or some component hijacked.
stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now
var/mob/dead/observer/ghost = new(get_turf(src), src) // Transfer safety to observer spawning proc.
SStgui.on_transfer(src, ghost) // Transfer NanoUIs.
ghost.can_reenter_corpse = can_reenter_corpse
ghost.can_reenter_corpse = can_reenter_corpse || (sig_flags & COMPONENT_FREE_GHOSTING)
if (client && client.prefs && client.prefs.auto_ooc)
if (!(client.prefs.chat_toggles & CHAT_OOC))
client.prefs.chat_toggles ^= CHAT_OOC
@@ -297,12 +298,17 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
penalty = CANT_REENTER_ROUND
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE, (stat == DEAD)? penalty : 0, (stat == DEAD)? TRUE : FALSE) & COMPONENT_BLOCK_GHOSTING)
var/sig_flags = SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE, (stat == DEAD)? penalty : 0, (stat == DEAD)? TRUE : FALSE)
if(sig_flags & COMPONENT_BLOCK_GHOSTING)
return
if(sig_flags & COMPONENT_DO_NOT_PENALIZE_GHOSTING)
penalty = 0
if(stat != DEAD)
succumb()
if(stat == DEAD)
if(stat == DEAD || sig_flags & COMPONENT_FREE_GHOSTING)
ghostize(1)
else
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty == CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
@@ -321,7 +327,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Ghost"
set desc = "Relinquish your life and enter the land of the dead."
if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING)
var/sig_flags = SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, FALSE, FALSE)
if(sig_flags & COMPONENT_BLOCK_GHOSTING)
return
var/penalty = CONFIG_GET(number/suicide_reenter_round_timer) MINUTES
@@ -333,10 +341,16 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
penalty = CANT_REENTER_ROUND
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty == CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return
ghostize(0, penalize = TRUE)
if(sig_flags & COMPONENT_DO_NOT_PENALIZE_GHOSTING)
penalty = 0
if(sig_flags & COMPONENT_FREE_GHOSTING)
ghostize(1)
else
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst alive you won't be able to re-enter this round [penalty ? "or play ghost roles [penalty == CANT_REENTER_ROUND ? "until the round is over" : "for the next [DisplayTimeText(penalty)]"]" : ""]! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return
ghostize(0, penalize = TRUE)
@@ -670,7 +684,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return 0
transfer_ckey(target, FALSE)
target.AddElement(/datum/element/ghost_role_eligibility)
target.AddElement(/datum/element/ghost_role_eligibility, penalize_on_ghost = FALSE, free_ghosting = TRUE)
target.faction = list("neutral")
return 1
+115 -8
View File
@@ -984,14 +984,121 @@
/mob/living/carbon/vv_get_dropdown()
. = ..()
. += "---"
.["Make AI"] = "?_src_=vars;[HrefToken()];makeai=[REF(src)]"
.["Modify bodypart"] = "?_src_=vars;[HrefToken()];editbodypart=[REF(src)]"
.["Modify organs"] = "?_src_=vars;[HrefToken()];editorgans=[REF(src)]"
.["Hallucinate"] = "?_src_=vars;[HrefToken()];hallucinate=[REF(src)]"
.["Give martial arts"] = "?_src_=vars;[HrefToken()];givemartialart=[REF(src)]"
.["Give brain trauma"] = "?_src_=vars;[HrefToken()];givetrauma=[REF(src)]"
.["Cure brain traumas"] = "?_src_=vars;[HrefToken()];curetraumas=[REF(src)]"
VV_DROPDOWN_OPTION("", "---------")
VV_DROPDOWN_OPTION(VV_HK_MAKE_AI, "Make AI")
VV_DROPDOWN_OPTION(VV_HK_MODIFY_BODYPART, "Modify bodypart")
VV_DROPDOWN_OPTION(VV_HK_MODIFY_ORGANS, "Modify organs")
VV_DROPDOWN_OPTION(VV_HK_HALLUCINATION, "Hallucinate")
VV_DROPDOWN_OPTION(VV_HK_MARTIAL_ART, "Give Martial Arts")
VV_DROPDOWN_OPTION(VV_HK_GIVE_TRAUMA, "Give Brain Trauma")
VV_DROPDOWN_OPTION(VV_HK_CURE_TRAUMA, "Cure Brain Traumas")
/mob/living/carbon/vv_do_topic(list/href_list)
. = ..()
if(href_list[VV_HK_MODIFY_BODYPART])
if(!check_rights(R_SPAWN))
return
var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment")
if(!edit_action)
return
var/list/limb_list = list()
if(edit_action == "remove" || edit_action == "augment")
for(var/obj/item/bodypart/B in bodyparts)
limb_list += B.body_zone
if(edit_action == "remove")
limb_list -= BODY_ZONE_CHEST
else
limb_list = list(BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
for(var/obj/item/bodypart/B in bodyparts)
limb_list -= B.body_zone
var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in limb_list
if(result)
var/obj/item/bodypart/BP = get_bodypart(result)
switch(edit_action)
if("remove")
if(BP)
BP.drop_limb()
else
to_chat(usr, "[src] doesn't have such bodypart.")
if("add")
if(BP)
to_chat(usr, "[src] already has such bodypart.")
else
if(!regenerate_limb(result))
to_chat(usr, "[src] cannot have such bodypart.")
if("augment")
if(ishuman(src))
if(BP)
BP.change_bodypart_status(BODYPART_ROBOTIC, TRUE, TRUE)
else
to_chat(usr, "[src] doesn't have such bodypart.")
else
to_chat(usr, "Only humans can be augmented.")
admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src]")
if(href_list[VV_HK_MAKE_AI])
if(!check_rights(R_SPAWN))
return
if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
return
usr.client.holder.Topic("vv_override", list("makeai"=href_list[VV_HK_TARGET]))
if(href_list[VV_HK_MODIFY_ORGANS])
if(!check_rights(NONE))
return
usr.client.manipulate_organs(src)
if(href_list[VV_HK_MARTIAL_ART])
if(!check_rights(NONE))
return
var/list/artpaths = subtypesof(/datum/martial_art)
var/list/artnames = list()
for(var/i in artpaths)
var/datum/martial_art/M = i
artnames[initial(M.name)] = M
var/result = input(usr, "Choose the martial art to teach","JUDO CHOP") as null|anything in artnames
if(!usr)
return
if(QDELETED(src))
to_chat(usr, "Mob doesn't exist anymore")
return
if(result)
var/chosenart = artnames[result]
var/datum/martial_art/MA = new chosenart
MA.teach(src)
log_admin("[key_name(usr)] has taught [MA] to [key_name(src)].")
message_admins("<span class='notice'>[key_name_admin(usr)] has taught [MA] to [key_name_admin(src)].</span>")
if(href_list[VV_HK_GIVE_TRAUMA])
if(!check_rights(NONE))
return
var/list/traumas = subtypesof(/datum/brain_trauma)
var/result = input(usr, "Choose the brain trauma to apply","Traumatize") as null|anything in traumas
if(!usr)
return
if(QDELETED(src))
to_chat(usr, "Mob doesn't exist anymore")
return
if(!result)
return
var/datum/brain_trauma/BT = gain_trauma(result)
if(BT)
log_admin("[key_name(usr)] has traumatized [key_name(src)] with [BT.name]")
message_admins("<span class='notice'>[key_name_admin(usr)] has traumatized [key_name_admin(src)] with [BT.name].</span>")
if(href_list[VV_HK_CURE_TRAUMA])
if(!check_rights(NONE))
return
cure_all_traumas(TRAUMA_RESILIENCE_ABSOLUTE)
log_admin("[key_name(usr)] has cured all traumas from [key_name(src)].")
message_admins("<span class='notice'>[key_name_admin(usr)] has cured all traumas from [key_name_admin(src)].</span>")
if(href_list[VV_HK_HALLUCINATION])
if(!check_rights(NONE))
return
var/list/hallucinations = subtypesof(/datum/hallucination)
var/result = input(usr, "Choose the hallucination to apply","Send Hallucination") as null|anything in hallucinations
if(!usr)
return
if(QDELETED(src))
to_chat(usr, "Mob doesn't exist anymore")
return
if(result)
new result(src, TRUE)
/mob/living/carbon/can_resist()
return bodyparts.len > 2 && ..()
+89 -9
View File
@@ -849,15 +849,95 @@
/mob/living/carbon/human/vv_get_dropdown()
. = ..()
. += "---"
.["Make monkey"] = "?_src_=vars;[HrefToken()];makemonkey=[REF(src)]"
.["Set Species"] = "?_src_=vars;[HrefToken()];setspecies=[REF(src)]"
.["Make cyborg"] = "?_src_=vars;[HrefToken()];makerobot=[REF(src)]"
.["Make alien"] = "?_src_=vars;[HrefToken()];makealien=[REF(src)]"
.["Make slime"] = "?_src_=vars;[HrefToken()];makeslime=[REF(src)]"
.["Toggle Purrbation"] = "?_src_=vars;[HrefToken()];purrbation=[REF(src)]"
.["Copy outfit"] = "?_src_=vars;[HrefToken()];copyoutfit=[REF(src)]"
.["Add/Remove Quirks"] = "?_src_=vars;[HrefToken()];modquirks=[REF(src)]"
VV_DROPDOWN_OPTION("", "---------")
VV_DROPDOWN_OPTION(VV_HK_COPY_OUTFIT, "Copy Outfit")
VV_DROPDOWN_OPTION(VV_HK_MOD_QUIRKS, "Add/Remove Quirks")
VV_DROPDOWN_OPTION(VV_HK_MAKE_MONKEY, "Make Monkey")
VV_DROPDOWN_OPTION(VV_HK_MAKE_CYBORG, "Make Cyborg")
VV_DROPDOWN_OPTION(VV_HK_MAKE_SLIME, "Make Slime")
VV_DROPDOWN_OPTION(VV_HK_MAKE_ALIEN, "Make Alien")
VV_DROPDOWN_OPTION(VV_HK_SET_SPECIES, "Set Species")
VV_DROPDOWN_OPTION(VV_HK_PURRBATION, "Toggle Purrbation")
/mob/living/carbon/human/vv_do_topic(list/href_list)
. = ..()
if(href_list[VV_HK_COPY_OUTFIT])
if(!check_rights(R_SPAWN))
return
copy_outfit()
if(href_list[VV_HK_MOD_QUIRKS])
if(!check_rights(R_SPAWN))
return
var/list/options = list("Clear"="Clear")
for(var/x in subtypesof(/datum/quirk))
var/datum/quirk/T = x
var/qname = initial(T.name)
options[has_quirk(T) ? "[qname] (Remove)" : "[qname] (Add)"] = T
var/result = input(usr, "Choose quirk to add/remove","Quirk Mod") as null|anything in options
if(result)
if(result == "Clear")
for(var/datum/quirk/q in roundstart_quirks)
remove_quirk(q.type)
else
var/T = options[result]
if(has_quirk(T))
remove_quirk(T)
else
add_quirk(T,TRUE)
if(href_list[VV_HK_MAKE_MONKEY])
if(!check_rights(R_SPAWN))
return
if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
return
usr.client.holder.Topic("vv_override", list("monkeyone"=href_list[VV_HK_TARGET]))
if(href_list[VV_HK_MAKE_CYBORG])
if(!check_rights(R_SPAWN))
return
if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
return
usr.client.holder.Topic("vv_override", list("makerobot"=href_list[VV_HK_TARGET]))
if(href_list[VV_HK_MAKE_ALIEN])
if(!check_rights(R_SPAWN))
return
if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
return
usr.client.holder.Topic("vv_override", list("makealien"=href_list[VV_HK_TARGET]))
if(href_list[VV_HK_MAKE_SLIME])
if(!check_rights(R_SPAWN))
return
if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform")
return
usr.client.holder.Topic("vv_override", list("makeslime"=href_list[VV_HK_TARGET]))
if(href_list[VV_HK_SET_SPECIES])
if(!check_rights(R_SPAWN))
return
var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list
if(result)
var/newtype = GLOB.species_list[result]
admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src] to [result]")
set_species(newtype)
if(href_list[VV_HK_PURRBATION])
if(!check_rights(R_SPAWN))
return
if(!ishumanbasic(src))
to_chat(usr, "This can only be done to the basic human species at the moment.")
return
var/success = purrbation_toggle(src)
if(success)
to_chat(usr, "Put [src] on purrbation.")
log_admin("[key_name(usr)] has put [key_name(src)] on purrbation.")
var/msg = "<span class='notice'>[key_name_admin(usr)] has put [key_name(src)] on purrbation.</span>"
message_admins(msg)
admin_ticket_log(src, msg)
else
to_chat(usr, "Removed [src] from purrbation.")
log_admin("[key_name(usr)] has removed [key_name(src)] from purrbation.")
var/msg = "<span class='notice'>[key_name_admin(usr)] has removed [key_name(src)] from purrbation.</span>"
message_admins(msg)
admin_ticket_log(src, msg)
/mob/living/carbon/human/MouseDrop_T(mob/living/target, mob/living/user)
if(pulling == target && grab_state >= GRAB_AGGRESSIVE && stat == CONSCIOUS)
+16 -11
View File
@@ -1474,13 +1474,17 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
else
user.do_attack_animation(target, ATTACK_EFFECT_PUNCH)
user.adjustStaminaLossBuffered(5) //CITADEL CHANGE - makes punching cause staminaloss
user.adjustStaminaLossBuffered(3.5) //CITADEL CHANGE - makes punching cause staminaloss
var/damage = rand(user.dna.species.punchdamagelow, user.dna.species.punchdamagehigh)
var/puncherstam = user.getStaminaLoss()
var/puncherbrute = user.getBruteLoss()
var/punchedstam = target.getStaminaLoss()
var/punchedbrute = target.getBruteLoss()
//CITADEL CHANGES - makes resting and disabled combat mode reduce punch damage, makes being out of combat mode result in you taking more damage
if(!(target.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && damage < user.dna.species.punchstunthreshold)
damage = user.dna.species.punchstunthreshold - 1
if(!(target.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
damage *= 1.5
if(!CHECK_MOBILITY(user, MOBILITY_STAND))
damage *= 0.5
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
@@ -1494,7 +1498,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(atk_verb == ATTACK_EFFECT_KICK) //kicks never miss (provided your species deals more than 0 damage)
miss_chance = 0
else
miss_chance = min((user.dna.species.punchdamagehigh/user.dna.species.punchdamagelow) + user.getStaminaLoss() + (user.getBruteLoss()*0.5), 100) //old base chance for a miss + various damage. capped at 100 to prevent weirdness in prob()
miss_chance = min(10 + ((puncherstam + puncherbrute)*0.5), 100) //probability of miss has a base of 10, and modified based on half your stamina and brute total. Capped at max 100 and min 0 to prevent weirdness in prob()
if(!damage || !affecting || prob(miss_chance))//future-proofing for species that have 0 damage/weird cases where no zone is targeted
playsound(target.loc, user.dna.species.miss_sound, 25, TRUE, -1)
@@ -1529,13 +1533,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
log_combat(user, target, "punched")
if((target.stat != DEAD) && damage >= user.dna.species.punchstunthreshold)
target.visible_message("<span class='danger'>[user] knocks [target] down!</span>", \
"<span class='userdanger'>You're knocked down by [user]!</span>", "<span class='hear'>You hear aggressive shuffling followed by a loud thud!</span>", COMBAT_MESSAGE_RANGE, user)
to_chat(user, "<span class='danger'>You knock [target] down!</span>")
var/knockdown_duration = 40 + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 - armor_block
target.DefaultCombatKnockdown(knockdown_duration)
target.forcesay(GLOB.hit_appends)
log_combat(user, target, "got a stun punch with their previous punch")
if((punchedstam > 50) && prob(punchedstam*0.5)) //If our punch victim has been hit above the threshold, and they have more than 50 stamina damage, roll for stun, probability of 1% per 2 stamina damage
target.visible_message("<span class='danger'>[user] knocks [target] down!</span>", \
"<span class='userdanger'>You're knocked down by [user]!</span>", "<span class='hear'>You hear aggressive shuffling followed by a loud thud!</span>", COMBAT_MESSAGE_RANGE, user)
to_chat(user, "<span class='danger'>You knock [target] down!</span>")
var/knockdown_duration = 40 + (punchedstam + (punchedbrute*0.5))*0.8 - armor_block
target.DefaultCombatKnockdown(knockdown_duration)
target.forcesay(GLOB.hit_appends)
log_combat(user, target, "got a stun punch with their previous punch")
else if(!(target.mobility_flags & MOBILITY_STAND))
target.forcesay(GLOB.hit_appends)
@@ -92,6 +92,8 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
//These count in on_life ticks which should be 2 seconds per every increment of 1 in a perfect world.
var/dwarf_filth_ticker = 0 //Currently set =< 4, that means this will fire the proc around every 4-8 seconds.
var/dwarf_eth_ticker = 0 //Currently set =< 1, that means this will fire the proc around every 2 seconds
var/last_filth_spam
var/last_alcohol_spam
/obj/item/organ/dwarfgland/prepare_eat()
var/obj/S = ..()
@@ -136,40 +138,39 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
filth_counter += 10 //Dwarves could technically chainstun each other in a vomit tantrum spiral.
switch(filth_counter)
if(11 to 25)
if(prob(25))
to_chat(owner, "<span class = 'danger'>Someone should really clean up in here!</span>")
if(last_filth_spam + 40 SECONDS < world.time)
to_chat(owner, "<span class = 'warning'>Someone should really clean up in here!</span>")
last_filth_spam = world.time
if(26 to 50)
if(prob(30)) //Probability the message appears
if(prob(6)) //And then the probability they vomit along with it.
to_chat(owner, "<span class = 'danger'>The stench makes you queasy.</span>")
if(prob(20)) //And then the probability they vomit along with it.
owner.vomit(20) //I think vomit should stay over a disgust adjustment.
owner.vomit(10) //I think vomit should stay over a disgust adjustment.
if(51 to 75)
if(prob(35))
if(prob(9))
to_chat(owner, "<span class = 'danger'>By Armok! You won't be able to keep alcohol down at all!</span>")
if(prob(25))
owner.vomit(20) //Its more funny
owner.vomit(20) //Its more funny
if(76 to 100)
if(prob(40))
if(prob(11))
to_chat(owner, "<span class = 'userdanger'>You can't live in such FILTH!</span>")
if(prob(25))
owner.adjustToxLoss(10) //Now they start dying.
owner.vomit(20)
owner.adjustToxLoss(10) //Now they start dying.
owner.vomit(20)
if(101 to INFINITY) //Now they will really start dying
if(prob(40))
if(last_filth_spam + 12 SECONDS < world.time)
to_chat(owner, "<span class = 'userdanger'> THERES TOO MUCH FILTH, OH GODS THE FILTH!</span>")
last_filth_spam = world.time
if(prob(40))
owner.adjustToxLoss(15)
owner.vomit(40)
owner.vomit(30)
CHECK_TICK //Check_tick right here, its motherfuckin magic. (To me at least)
//Handles the dwarf alcohol cycle tied to on_life, it ticks in dwarf_cycle_ticker.
/obj/item/organ/dwarfgland/proc/dwarf_eth_cycle()
//BOOZE POWER
var/init_stored_alcohol = stored_alcohol
for(var/datum/reagent/R in owner.reagents.reagent_list)
if(istype(R, /datum/reagent/consumable/ethanol))
var/datum/reagent/consumable/ethanol/E = R
stored_alcohol += (E.boozepwr / 50)
if(stored_alcohol > max_alcohol) //Dwarves technically start at 250 alcohol stored.
stored_alcohol = max_alcohol
stored_alcohol = CLAMP(stored_alcohol + E.boozepwr / 50, 0, max_alcohol)
var/heal_amt = heal_rate
stored_alcohol -= alcohol_rate //Subtracts alcohol_Rate from stored alcohol so EX: 250 - 0.25 per each loop that occurs.
if(stored_alcohol > 400) //If they are over 400 they start regenerating
@@ -177,16 +178,27 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
owner.adjustFireLoss(-heal_amt) //Unless they drink casually all the time.
owner.adjustOxyLoss(-heal_amt)
owner.adjustCloneLoss(-heal_amt) //Also they will probably get brain damage if thats a thing here.
if(prob(25))
switch(stored_alcohol)
if(0 to 24)
if(init_stored_alcohol + 0.5 < stored_alcohol) //recovering stored alcohol at a steady rate of +0.75, no spam.
return
switch(stored_alcohol)
if(0 to 24)
if(last_alcohol_spam + 8 SECONDS < world.time)
to_chat(owner, "<span class='userdanger'>DAMNATION INCARNATE, WHY AM I CURSED WITH THIS DRY-SPELL? I MUST DRINK.</span>")
owner.adjustToxLoss(35)
if(25 to 50)
last_alcohol_spam = world.time
owner.adjustToxLoss(10)
if(25 to 50)
if(last_alcohol_spam + 20 SECONDS < world.time)
to_chat(owner, "<span class='danger'>Oh DAMN, I need some brew!</span>")
if(51 to 75)
last_alcohol_spam = world.time
if(51 to 75)
if(last_alcohol_spam + 35 SECONDS < world.time)
to_chat(owner, "<span class='warning'>Your body aches, you need to get ahold of some booze...</span>")
if(76 to 100)
last_alcohol_spam = world.time
if(76 to 100)
if(last_alcohol_spam + 40 SECONDS < world.time)
to_chat(owner, "<span class='notice'>A pint of anything would really hit the spot right now.</span>")
if(101 to 150)
last_alcohol_spam = world.time
if(101 to 150)
if(last_alcohol_spam + 50 SECONDS < world.time)
to_chat(owner, "<span class='notice'>You feel like you could use a good brew.</span>")
last_alcohol_spam = world.time
@@ -146,5 +146,7 @@
if(transfer_name)
H.name = caster.name
clothes_req = 0
human_req = 0
clothes_req = NONE
mobs_whitelist = null
mobs_blacklist = null
+16
View File
@@ -1198,3 +1198,19 @@
gender = ngender
return TRUE
return FALSE
/mob/living/vv_get_header()
. = ..()
var/refid = REF(src)
. += {"
<br><font size='1'>[VV_HREF_TARGETREF_1V(refid, VV_HK_BASIC_EDIT, "[ckey || "no ckey"]", NAMEOF(src, ckey))] / [VV_HREF_TARGETREF_1V(refid, VV_HK_BASIC_EDIT, "[real_name || "no real name"]", NAMEOF(src, real_name))]</font>
<br><font size='1'>
BRUTE:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=brute' id='brute'>[getBruteLoss()]</a>
FIRE:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=fire' id='fire'>[getFireLoss()]</a>
TOXIN:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=toxin' id='toxin'>[getToxLoss()]</a>
OXY:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=oxygen' id='oxygen'>[getOxyLoss()]</a>
CLONE:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=clone' id='clone'>[getCloneLoss()]</a>
BRAIN:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=brain' id='brain'>[getOrganLoss(ORGAN_SLOT_BRAIN)]</a>
STAMINA:<font size='1'><a href='?_src_=vars;[HrefToken()];mobToDamage=[refid];adjustDamage=stamina' id='stamina'>[getStaminaLoss()]</a>
</font>
"}
-11
View File
@@ -193,17 +193,6 @@
if(user == anchored || !isturf(user.loc))
return FALSE
//pacifist vore check.
if(user.pulling && HAS_TRAIT(user, TRAIT_PACIFISM) && user.voremode) //they can only do heals, noisy guts, absorbing (technically not harm)
if(ismob(user.pulling))
var/mob/P = user.pulling
if(src != user)
to_chat(user, "<span class='notice'>You can't risk digestion!</span>")
return FALSE
else
user.vore_attack(user, P, user)
return
//normal vore check.
if(user.pulling && user.grab_state == GRAB_AGGRESSIVE && user.voremode)
if(ismob(user.pulling))
@@ -33,6 +33,10 @@
if (!(istype(src, /mob/living/simple_animal/pet/gondola/gondolapod)))
CreateGondola()
/mob/living/simple_animal/pet/gondola/ComponentInitialize()
. = ..()
AddElement(/datum/element/spellcasting, SPELL_SKIP_VOCAL) // so they can cast spells despite being silent.
/mob/living/simple_animal/pet/gondola/proc/CreateGondola()
icon_state = null
icon_living = null
@@ -112,6 +112,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
attacktext = "bites"
attack_sound = 'sound/weapons/bite.ogg'
recolorentiresprite = TRUE
if(!recolorentiresprite) //we want this to proc before stand logs in, so the overlay isnt gone for some reason
cooloverlay = mutable_appearance(icon, theme)
add_overlay(cooloverlay)
/mob/living/simple_animal/hostile/guardian/Login() //if we have a mind, set its name to ours when it logs in
..()
@@ -762,7 +762,7 @@ Difficulty: Very Hard
name = "Exit Possession"
desc = "Exits the body you are possessing."
charge_max = 60
clothes_req = 0
clothes_req = NONE
invocation_type = "none"
max_targets = 1
range = -1
@@ -26,7 +26,6 @@
pull_force = MOVE_FORCE_OVERPOWERING
mob_size = MOB_SIZE_LARGE
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway
flags_1 = PREVENT_CONTENTS_EXPLOSION_1 | HEAR_1
var/list/crusher_loot
var/medal_type
@@ -169,7 +169,7 @@
desc = "You will trigger a large amount of lights around you to flicker."
charge_max = 300
clothes_req = 0
clothes_req = NONE
range = 14
/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/cast(list/targets,mob/user = usr)
@@ -185,7 +185,7 @@
message = "<span class='notice'>You glare your eyes.</span>"
charge_max = 600
clothes_req = 0
clothes_req = NONE
range = 10
/obj/effect/proc_holder/spell/aoe_turf/blindness/cast(list/targets,mob/user = usr)
@@ -201,7 +201,7 @@
desc = "Toggle your nightvision mode."
charge_max = 10
clothes_req = 0
clothes_req = NONE
message = "<span class='notice'>You toggle your night vision!</span>"
range = -1
@@ -43,23 +43,23 @@
/mob/living/simple_animal/hostile/wizard/Initialize()
. = ..()
fireball = new /obj/effect/proc_holder/spell/aimed/fireball
fireball.clothes_req = 0
fireball.human_req = 0
fireball.player_lock = 0
fireball.clothes_req = NONE
fireball.mobs_whitelist = null
fireball.player_lock = FALSE
AddSpell(fireball)
var/obj/item/implant/exile/I = new
I.implant(src, null, TRUE)
mm = new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile
mm.clothes_req = 0
mm.human_req = 0
mm.player_lock = 0
mm.clothes_req = NONE
mm.mobs_whitelist = null
mm.player_lock = FALSE
AddSpell(mm)
blink = new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink
blink.clothes_req = 0
blink.human_req = 0
blink.player_lock = 0
blink.clothes_req = NONE
blink.mobs_whitelist = null
blink.player_lock = FALSE
blink.outer_tele_radius = 3
AddSpell(blink)
+64 -13
View File
@@ -632,7 +632,7 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
/mob/proc/add_spells_to_statpanel(list/spells)
for(var/obj/effect/proc_holder/spell/S in spells)
if(S.can_be_cast_by(src))
if((!S.mobs_blacklist || !S.mobs_blacklist[src]) && (!S.mobs_whitelist || S.mobs_whitelist[src]))
switch(S.charge_type)
if("recharge")
statpanel("[S.panel]","[S.charge_counter/10.0]/[S.charge_max/10]",S)
@@ -946,18 +946,65 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
/mob/vv_get_dropdown()
. = ..()
. += "---"
.["Gib"] = "?_src_=vars;[HrefToken()];gib=[REF(src)]"
.["Give Spell"] = "?_src_=vars;[HrefToken()];give_spell=[REF(src)]"
.["Remove Spell"] = "?_src_=vars;[HrefToken()];remove_spell=[REF(src)]"
.["Give Disease"] = "?_src_=vars;[HrefToken()];give_disease=[REF(src)]"
.["Toggle Godmode"] = "?_src_=vars;[HrefToken()];godmode=[REF(src)]"
.["Drop Everything"] = "?_src_=vars;[HrefToken()];drop_everything=[REF(src)]"
.["Regenerate Icons"] = "?_src_=vars;[HrefToken()];regenerateicons=[REF(src)]"
.["Show player panel"] = "?_src_=vars;[HrefToken()];mob_player_panel=[REF(src)]"
.["Toggle Build Mode"] = "?_src_=vars;[HrefToken()];build_mode=[REF(src)]"
.["Assume Direct Control"] = "?_src_=vars;[HrefToken()];direct_control=[REF(src)]"
.["Offer Control to Ghosts"] = "?_src_=vars;[HrefToken()];offer_control=[REF(src)]"
VV_DROPDOWN_OPTION("", "---------")
VV_DROPDOWN_OPTION(VV_HK_GIB, "Gib")
VV_DROPDOWN_OPTION(VV_HK_GIVE_SPELL, "Give Spell")
VV_DROPDOWN_OPTION(VV_HK_REMOVE_SPELL, "Remove Spell")
VV_DROPDOWN_OPTION(VV_HK_GIVE_DISEASE, "Give Disease")
VV_DROPDOWN_OPTION(VV_HK_GODMODE, "Toggle Godmode")
VV_DROPDOWN_OPTION(VV_HK_DROP_ALL, "Drop Everything")
VV_DROPDOWN_OPTION(VV_HK_REGEN_ICONS, "Regenerate Icons")
VV_DROPDOWN_OPTION(VV_HK_PLAYER_PANEL, "Show player panel")
VV_DROPDOWN_OPTION(VV_HK_BUILDMODE, "Toggle Buildmode")
VV_DROPDOWN_OPTION(VV_HK_DIRECT_CONTROL, "Assume Direct Control")
VV_DROPDOWN_OPTION(VV_HK_OFFER_GHOSTS, "Offer Control to Ghosts")
/mob/vv_do_topic(list/href_list)
. = ..()
if(href_list[VV_HK_REGEN_ICONS])
if(!check_rights(NONE))
return
regenerate_icons()
if(href_list[VV_HK_PLAYER_PANEL])
if(!check_rights(NONE))
return
usr.client.holder.show_player_panel(src)
if(href_list[VV_HK_GODMODE])
if(!check_rights(R_ADMIN))
return
usr.client.cmd_admin_godmode(src)
if(href_list[VV_HK_GIVE_SPELL])
if(!check_rights(NONE))
return
usr.client.give_spell(src)
if(href_list[VV_HK_REMOVE_SPELL])
if(!check_rights(NONE))
return
usr.client.remove_spell(src)
if(href_list[VV_HK_GIVE_DISEASE])
if(!check_rights(NONE))
return
usr.client.give_disease(src)
if(href_list[VV_HK_GIB])
if(!check_rights(R_FUN))
return
usr.client.cmd_admin_gib(src)
if(href_list[VV_HK_BUILDMODE])
if(!check_rights(R_BUILDMODE))
return
togglebuildmode(src)
if(href_list[VV_HK_DROP_ALL])
if(!check_rights(NONE))
return
usr.client.cmd_admin_drop_everything(src)
if(href_list[VV_HK_DIRECT_CONTROL])
if(!check_rights(NONE))
return
usr.client.cmd_assume_direct_control(src)
if(href_list[VV_HK_OFFER_GHOSTS])
if(!check_rights(NONE))
return
offer_control(src)
/mob/vv_get_var(var_name)
switch(var_name)
@@ -965,6 +1012,10 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
return debug_variable(var_name, logging, 0, src, FALSE)
. = ..()
/mob/vv_auto_rename(new_name)
//Do not do parent's actions, as we *usually* do this differently.
fully_replace_character_name(real_name, new_name)
/mob/verb/open_language_menu()
set name = "Open Language Menu"
set category = "IC"
@@ -57,12 +57,12 @@ It is possible to destroy the net by the occupant or someone else.
continue//So all they're left with are shoes and uniform.
H.dropItemToGround(W)
H.dna.species.give_important_for_life(H) // After we remove items, at least give them what they need to live.
/*
var/datum/antagonist/antag_datum
for(var/datum/antagonist/ninja/AD in GLOB.antagonists) //Because only ninjas get capture objectives; They're not doable without the suit.
if(AD.owner == master)
antag_datum = AD
break
for(var/datum/objective/capture/capture in antag_datum)
if(istype(affecting, /mob/living/carbon/human)) //Humans.
if(affecting.stat == DEAD)//Dead folks are worth less.
@@ -87,7 +87,7 @@ It is possible to destroy the net by the occupant or someone else.
capture.captured_amount+=1
continue
capture.captured_amount+=2
*/
affecting.revive(1, 1) //Basically a revive and full heal, including limbs/organs
//In case people who have been captured dead want to hang out at the holding area
+1 -4
View File
@@ -22,7 +22,7 @@ Contents:
armor = list("melee" = 60, "bullet" = 50, "laser" = 30,"energy" = 15, "bomb" = 30, "bio" = 30, "rad" = 30, "fire" = 100, "acid" = 100)
strip_delay = 12
actions_types = list(/datum/action/item_action/initialize_ninja_suit, /datum/action/item_action/ninjasmoke, /datum/action/item_action/ninjaboost, /datum/action/item_action/ninjapulse, /datum/action/item_action/ninjastar, /datum/action/item_action/ninjanet, /datum/action/item_action/ninja_sword_recall, /datum/action/item_action/ninja_stealth, /datum/action/item_action/toggle_glove)
actions_types = list(/datum/action/item_action/initialize_ninja_suit, /datum/action/item_action/ninjasmoke, /datum/action/item_action/ninjaboost, /datum/action/item_action/ninjapulse, /datum/action/item_action/ninjastar, /datum/action/item_action/ninja_sword_recall, /datum/action/item_action/ninja_stealth, /datum/action/item_action/toggle_glove)
//Important parts of the suit.
var/mob/living/carbon/human/affecting = null
@@ -175,9 +175,6 @@ Contents:
if(istype(action, /datum/action/item_action/ninjastar))
ninjastar()
return TRUE
if(istype(action, /datum/action/item_action/ninjanet))
ninjanet()
return TRUE
if(istype(action, /datum/action/item_action/ninja_sword_recall))
ninja_sword_recall()
return TRUE
+103 -1
View File
@@ -48,11 +48,113 @@
name = "paper- 'Chemical Information'"
info = "Known Onboard Toxins:<BR>\n\tGrade A Semi-Liquid Plasma:<BR>\n\t\tHighly poisonous. You cannot sustain concentrations above 15 units.<BR>\n\t\tA gas mask fails to filter plasma after 50 units.<BR>\n\t\tWill attempt to diffuse like a gas.<BR>\n\t\tFiltered by scrubbers.<BR>\n\t\tThere is a bottled version which is very different<BR>\n\t\t\tfrom the version found in canisters!<BR>\n<BR>\n\t\tWARNING: Highly Flammable. Keep away from heat sources<BR>\n\t\texcept in an enclosed fire area!<BR>\n\t\tWARNING: It is a crime to use this without authorization.<BR>\nKnown Onboard Anti-Toxin:<BR>\n\tAnti-Toxin Type 01P: Works against Grade A Plasma.<BR>\n\t\tBest if injected directly into bloodstream.<BR>\n\t\tA full injection is in every regular Med-Kit.<BR>\n\t\tSpecial toxin Kits hold around 7.<BR>\n<BR>\nKnown Onboard Chemicals (other):<BR>\n\tRejuvenation T#001:<BR>\n\t\tEven 1 unit injected directly into the bloodstream<BR>\n\t\t\twill cure unconscious and sleep toxins.<BR>\n\t\tIf administered to a dying patient it will prevent<BR>\n\t\t\tfurther damage for about units*3 seconds.<BR>\n\t\t\tit will not cure them or allow them to be cured.<BR>\n\t\tIt can be administered to a non-dying patient<BR>\n\t\t\tbut the chemicals disappear just as fast.<BR>\n\tMorphine T#054:<BR>\n\t\t5 units will induce precisely 1 minute of sleep.<BR>\n\t\t\tThe effect are cumulative.<BR>\n\t\tWARNING: It is a crime to use this without authorization"
/*
* Stations
*/
/obj/item/paper/guides/cogstation/job_changes
name = "MEMO: Job Changes"
info = "To ensure minimal employee downtime, please take note of the following changes to select professions that Cogstation specifically requires:<BR>\n<BR>\n- Chemists are to have <B>basic Research access</B>and an encryption key for the Science channel. <BR>\n- Roboticists are to have <B>basic Medical and Morgue access</B>. <BR>\n- Engineers and Atmospheric Technicians <I>are</I> to have Warehouse and Mining access.<BR>\n- The Cook should <I>not</I> have Morgue access <BR>\n- The Clown and Mime <I>are</I> to have Maintenance access. This is necessary due to the location of their offices.<BR>\n<BR>\n<I>Generated by Organic Resources Bot #2053</I>"
/obj/item/paper/guides/cogstation/letter_sec
name = "To future Security personnel"
info = "As this station's Head of Security prior to it being translocated to your sector, my hope is that Central Command will properly brief you on the ins and outs of this particular layout. I'm writing this in case they don't. 'CogStation' as it's called may be worlds different than other stations in your sector, so I wanted to mention a few things: <BR>\n<BR>\nFirst of all, <B>the brig uses a 'genpop' prison system.</B> While I'm sure books exist on the subject, the main thing to know is prisoners share a common area regardless of sentence length. There is a single solitary cell, but it should be reserved only for the particularly dangerous. <BR>\n<BR>\nYour auxiliary posts can be found in the <B>fore</B> and <B>starboard quarter</B> parts of the station; near arrivals and cargo, respectively. I've heard about stations with a post in each department - unfortunately, this isn't one of them. If it's any consolation, the security wing is rather centrally located. <BR>\n<BR>\nAfter a perp's done their time, you can let them out via the disposal unit right outside the prison wing. It'll plop them right outside your front desk without the potential hassle of escorting them through your office. <BR>\n<BR>\nHave a secure day! <BR>\n<I>- Louis Cannon</I>"
/obj/item/paper/guides/cogstation/disposals
name = "Regarding the disposal system:"
info = "As you might have noticed, this station has far more disposal pipes than you may expect from your average Nanotrasen research facility. Part of the reason for this is specialization - mail, trash, even corpses have their own disposal systems. Unfortunately, the convenient color-coding was lost in translocation and we've had to compensate by marking the area around each bin. <BR>\n<BR>\n- <B>WHITE/GRAY STRIPES is for DELIVERIES. <BR>\n- RED STRIPES is for CORPSES. <BR>\n- EVERYTHING ELSE is for TRASH,</B> barring a few exceptions that should be labeled as such. <BR>\n<BR>\nIdeally the station won't sustain any heavy structural damage during your time here but if it does, or someone decides to tamper with/sabotage this system, you'll be forgiven if you can't put it back together perfectly. <BR>\n<BR>\n<I>-C. Donnelly</I> <BR>Architectural Analyst"
/obj/item/paper/guides/cogstation/janitor
name = "a quick tip"
info = "I'm gonna tell you something I wish I knew my first day here: there's an auxiliary custodial closet on the other end of the station. Just head straight through maintenance behind the bathrooms next to engineering and you'll find it. <BR>\n<BR>\nNow this sounds great until you realize there's no quick way to the other end of the station without a spacesuit - then it sounds like a gift from the gods! <BR>\n<BR>\n<I>- 'Squeaky' Kleiner</I>"
/obj/item/paper/guides/cogstation/cooks
name = "MEMO: Cooks"
info = "Please be aware that while a smartfridge has recently been installed in your kitchen, botanists may choose to use the produce delivery system instead. You'll find the outlet, in addition to your freezer in the adjacent service hall. You can also send food directly to the bar and prison inmates via the disposal bins marked with <B>dark red</B> and <B>bright red</B> tiling, respectively. <BR>\n<BR>\n<I>Generated by Organic Resources Bot #7004</I>"
/obj/item/paper/guides/cogstation/cdn_chap
name = "About the corpse disposal network"
info = "One of the medical staff has insisted I leave a message regarding the 'corpse disposal network' and its significance. From what I have been told, it has been designed so medical staff can deliver the deceased directly to you. However, bodies from the medical booth or detective's office next door will be sent your way first. <BR>\nThe delivery chute will allow you to send these bodies to the medical department so that they can attempt to revive them, if possible. I would recommend periodically checking the morgue for any unannounced arrivals, but make sure bodies are devoid of a soul <I>before</I> 'burying' or cremating them! <BR>\n<BR>\n<I>Soulstone Obelisk</I> <BR>\n<BR>\nDepartment of Higher-Dimensional Affairs"
/obj/item/paper/guides/cogstation/letter_cmo
name = "To the future Medical Director..."
info = "From one Medical Director to another, I'm happy to say you won't have to rethink how you do things here, since saving lives is universal! That being said, you might want to consider the following: <BR>\n<BR>\n There's a medical booth over in the civilian wing, so ideally folks with minor cuts and bruises will head there first. While it can operate on a self-serve basis, you might want to send one of your doctors there to make sure it's run proper. <BR>\n<BR>\n The Geneticists and Virologists share the same pool of test subjects, so make sure they don't reintroduce them to the control group! A group of regular monkeys is dangerous enough, so do NOT attack one in view of the others! <BR>\n<BR>\nLastly, you might want to check the morgue regularly - it's one of the two main endpoints for the corpse disposal network. At the very least, make sure robotics gets your approval BEFORE borging someone! Robert hasn't been the same since he became Rob-Bot... <BR>\n<BR>\n<I>Earl. E. Greaves</I>"
/obj/item/paper/guides/cogstation/cdn_med
name = "Corpse Disposal Network"
info = "It's come to my attention that this station has been outfitted with a Corpse Disposal Network (CDN), and disposal units incorporated into this network are marked with RED STRIPES surrounding them. This morgue is one of the network's major endpoints, the other being the chapel morgue. <BR>\n<BR>\nAs such, it should be checked routinely for any bodies that may have arrived unannounced. Cloned corpses or personnel that have proven unrevivable can be shipped to the chapel morgue via your delivery chute. The same can be done for bodies that arrived brainless, although if you want botany to have at them you should tag them accordingly. <BR>\n<BR>\nLiving persons who treat the CDN like a theme park ride are to be swiftly removed from the medical department, short of them being on the verge of death. In such cases, treatment is advised. <BR>\n<BR>\n<I>-Dr. Halley</I>"
/obj/item/paper/guides/cogstation/letter_eng
name = "To future Engineering staff:"
info = "I'm not gonna sugarcoat this. Compared to other departments, you might have your work cut out for you. CogStation is an entirely different beast than your standard Box, but everyone's still gonna expect you to keep the place running. <BR>\n<BR>\n If there's any good news, it's your time to shine if you know how to run a thermo-electric generator. That's what this station runs on, and CentCom isn't planning on changing that. If it's absolutely critical you might be able to run a singularity or tesla engine east of mining, but it won't have any sort of shielding out there. <BR>\n<BR>\nThe air system's different too. It's multiple small networks instead of a single big one, with air hookups across the station. Fortunately it's not that complicated, but it comes at the expense of being able to filter out and reuse specific gases. Besides, you'll probably be busy enough with the engine and general upkeep anyway. <BR>\n<BR>\nThe disposal network in contrast is significantly more complicated, yet more capable. I've already elaborated on it, so I'll let you find and read my write-up for that. As for the routing system, it's just begging to get hit by a stray meteor so consider other utilities a higher priority. <BR>\n<BR>\nGood luck. You're gonna need it. <BR>\n<BR>\n<I>-C. Donnelly</I> <BR>Architectural Analyst"
/obj/item/paper/guides/cogstation/letter_chief
name = "To the future Chief Engineer:"
info = "Considering some of the other heads are writing letters to their successors, I reckon I might as well do the same. If this place is heading where I think it is, I sure as hell hope they made sure you know how to run a TEG. <I>Oh who am I kidding, of course they won't.</I> Well, the good news is unlike that newfangled supermatter that can kill everyone from radiation before you know anything is wrong, <B>you'll know if a Thermo-Electric Generator is failing,</B> since you'll either have no power or be on fire. <BR>\n<BR>\nThere's two main ways to set it up, with the 'proper way' being to run plasma through the pipes. You hook them up on the hot side (the one with the red pipes), then use the heaters and freezers to keep the hot side hot and the cold side cold. Just keep an eye on pressures - too much on the hot side or too little on the cold side and you'll get reduced or even no power. Of course, the fun way is to get something cooking in the burn chamber for the hot side and use space itself for the cold side. You might want to throw a monkey into the burn chamber for good luck and an indication whether your gas is suitably hot or not. Just make sure that <BR>\n<BR>\n<I>I found this on the CE's desk. My guess is he was going to finish it, but was interrupted at some point in his last shift and ultimately met his untimely demise. I just hope whatever he was going to warn you about wasn't critical...<BR>\n<BR>\n-C. Donnelly</I>"
/obj/item/paper/guides/cogstation/letter_hos
name = "To the future HoS"
info = "I'm gonna be rather disappointed if CentCom doesn't brief you about this station, but if they don't <B>I wrote up another letter for your department that should cover it pretty well.</B> Make sure your officers read it if they aren't up to speed. <BR>\n<BR>\nSomething you in particular should know is that if someone's getting to be too much to handle, the boys and I have constructed a 'discount transfer centre' just behind the router. <B>Use it only as a last resort</B> - the walls may be reinforced but they're still thin, and you'll have big trouble on your hands if the AI or any cyborgs find out about it. <BR>\n<BR><I>-LC</I>"
/obj/item/paper/guides/cogstation/letter_supp
name = "To future Supply Staff:"
info = "Cargo, move freight. Miners, don't die. Your jobs are pretty straightforward, which is likely why they originally fell under Engineering on this station as opposed to their own department. Although we've considerably readjusted this part of the station to accommodate you, there are potential differences you should be aware of.<BR>\n<BR>\nEngineering<I>will</I> have access to some of your department, namely the warehouse and mining dock. Mining operations on this station were originally asteroid-based, hence the catwalk into the great beyond. Although you won't need to worry about being space-worthy due to a newly installed shuttle dock, they might need to get out there. <BR>\n<BR>\nYou'll have all your usual means of shipping out goods, but the disposal network is more complex with a separate line for mail and trash. I've left another note that explains this in detail, but know trash is the janitor's responsibility, not yours. <BR>\n<BR>\nThe biggest difference has to be this station's router system, which allows departments to ship goods between themselves. Even if the belts aren't working properly they'll still have their own request consoles, so you'll want to check for orders regularly. <BR>\n<BR>\n<I>-C. Donnelly</I> <BR>\nArchitectural Analyst"
/obj/item/paper/fluff/cogstation/sleepers
name = "Re: Sleepers?"
info = "Yes, the sleepers are meant to be publicly accessible. Policies in this station's original location encouraged crew to visit the clinic or treat themselves when it came to minor injuries. <BR>\n<BR>\n<B>This is no excuse for you not to do your jobs.</B> You may wish to keep an eye on the sleepers as to ensure they're being used responsibly. Remember, allowing an overdose to happen under your watch isn't much different from administering that overdose yourself. <BR>\n<BR>\n<I>- Dr. Halley</I>"
/obj/item/paper/fluff/cogstation/cloner
name = "Re: Issue with the cloner?"
info = "I've yet to see any <I>sentient</I> small primates working in this sector, but if they aren't carrying the Devo gene they should be fine. The document was likely referring to the nonsapient ones you can get out of a monkey cube. <BR>\n<BR>\n<I>- Dr. Halley</I>"
/obj/item/paper/fluff/cogstation/letter_rd
name = "To the future Research Director"
info = "Apologies if you were expecting a letter from the station's Research Director, but just prior to translocation we found out they were a BLF operative. I wouldn't trust a single word they wrote and while I'm not a scientist, something tells me your department will have the easiest time adjusting to this station. <BR>\n<BR>\nYou should have everything you need - this is a research facility after all. It's just a matter of finding it, which shouldn't be too hard. Folks like you are why we're out in deep space, after all! <BR>\n<I>-Louis Cannon</I> <BR>\nFormer Head of Security"
/obj/item/paper/fluff/cogstation/letter_cap
name = "Captain's Log"
info = "So I guess some of the other heads have decided to leave little notes for future employees here. Heartwarming, but the most important thing I figure I can leave you is the truth. Nevermind the Syndicate, the xenomorphs, the apocalyptic death cults I hear are a thing way out there - I'm convinced we are our own worst enemy. <BR>\n<BR>\nDon't believe me? Maybe you can ask Chief Engineer Earp. Oh right, he vaporized himself trying to produce enough power to keep the lights on in Space China for a week, despite only needing a sliver of that to run this place as intended. Or maybe you can ask Head of Security Cannon, who executed our Research Director in plain sight of everyone. Even if he was in the right, the final frontier isn't the goddamn wild west! Hell, maybe you can ask one of your 'staff assistants', although in my experience the only ones they seem to want to help is themselves. <BR>\n<BR>\nOf course, the REAL problems are with the higher-ups that stationed us on this deathtrap before deciding to send it your way, but there's only so much I can say and get away with it, for instance that they only sent this station since they could care less if it was a total loss. By the time you read this, I'll already be long gone. Maybe it'll be a different story with your crew, but between you and me, I wouldn't hold my breath...<I>unless they fuck up the air system.</I> <BR>\n<BR>\n<I>Dom Kahn</I> <BR>Former Captain of Nanotrasen CogStation"
/obj/item/paper/fluff/cogstation/letter_qm
name = "To the future Quartermaster:"
info = "Sorry if this office seems like an afterthought - as I mentioned in my letter to your department at large, you used to be a sub-department of Engineering on this station. Fortunately that's not the case here and you have cargo techs as opposed to other quartermasters, but you should keep the following in mind: <BR>\n<BR>\n- Keep your miners focused on where they're supposed to mine. I get the allure of deep space can be tempting, but we want them somewhere we can be fairly confident they'll come back alive and with ores. <BR>\n<BR>\n- Anyone with maintenance access can enter the Routing Depot at the heart of the station, but you'll need a space suit to safely reach it. You've been given one for this very reason, but your techs will need to source their own. <BR>\n<BR>\n- The fact that you've been given an office and had a good portion of your department refurbished as opposed to being told to make do should be seen as an indication that there <I>are</I> people in this company that care about you, even if it doesn't feel that way sometimes. Remember that before trying to 'declare independence' as 'Cargonia'. <BR>\n<BR>\n<I>-C. Donnelly</I> <BR>\nArchitectural Analyst"
/obj/item/paper/fluff/cogstation/letter_chap
name = "A message from the DHDA"
info = "Regardless of what the name leads you to believe, CogStation is neither Ratvarian in origin nor designed by members of this so-called 'clock cult'. Despite a potential common enemy and instances of exhibiting peaceful behavior, their beliefs have been labeled 'Heretical' by the Department of Higher-Dimensional Affairs and following them is grounds for immediate termination. <BR>\nAs the station's designated Chaplain, it is advised you correct anyone who claims this station and/or its designers are Ratvarian. While they are most likely misinformed or 'joking around', untruths gain credibility the more they are repeated. <BR>\n<BR>\n<I>Soulstone Obelisk</I> <BR>\n<BR>\nDepartment of Higher-Dimensional Affairs"
/obj/item/paper/fluff/cogstation/cluwne
name = "Mysterious Note"
info = "<B>ThE rInGmAsTeR dOeSn'T rUn ThE cIrCus... HONK!!!</B>"
/obj/item/paper/fluff/cogstation/mime
name = "Au futur Mime"
info = "Toutes mes excuses pour toute mauvaise grammaire, je ne suis pas un haut-parleur naturel Français et a dû utiliser NanoTranslate. Bien que vous puissiez être mécontent de lemplacement de votre bureau, sil vous plaît comprendre que c’était le seul endroit où nous pourrions le mettre sans problèmes de sécurité et/ou CentClown se plaindre à ce sujet. Nous nous excusons également pour labsence dune zone de performance dédiée, mais nous espérons que vous accorder un accès à lentretien compensera. <BR>\n<BR>\n<I>-C. Donnelly<I> <BR>\n<BR>\nAnalyste Architectural"
/obj/item/paper/fluff/cogstation/bsrb
name = "Message from the NTBSRB"
info = "Congratulations, (sector name here)! You've been chosen as a candidate to receive a Nanotrasen icon via bluespace translocation! 'CogStation' as it's commonly known has a rich history and a unique layout. Our hope is that you'll be able to retrofit this station to serve your needs, ideally as one of your primary research hubs.<br><br>We look forward to seeing what you can accomplish here!<BR>\n<BR>\n<I>-The Nanotrasen Bluespace Research Board</I>"
/obj/item/paper/fluff/cogstation/survey
name = "Fwd: Survey Report"
info = "After a thorough investigation, I'm happy to say that this translocation and its consequences weren't for naught. CogStation appears to have made it in one piece, with the only exception being a 'drone factory' satellite. I suspect it met a fate similar to parts of the station's original home, which means there's the possibility it's not terribly far from here. <BR>\n<BR>\nI can see some of CogStation's components being alien to local crews, but fortunately some of the station's previous staff appear to have anticipated this and left some advice. The assessment team and I have decided to do the same where appropriate, although I can see some areas that might be worth redesigning to better suit area protocol. I've brought them up to the Chief Architect, you should hear from them in a couple of hours. <BR>\n<BR>\n<I>-C. Donnelly</I> <BR>\n<BR>\nArchitectural Analyst"
/obj/item/paper/fluff/cogstation/router_off
name = "ROUTER STATUS: INACTIVE"
info = "This router line has been closed while we determine possible solutions. While you are free to use the request and supply consoles, you should plan on receiving your deliveries elsewhere. <BR>\n<BR>\n<I>-C. Donnelly</I> <BR>\n<BR>\nArchitectural Analyst"
/obj/item/paper/fluff/cogstation/router_verylimited
name = "ROUTER STATUS: VERY LIMITED"
info = "Currently, this router is only capable of making deliveries to Engineering, Cargo and the recycler, via manual input from the Routing Depot. It is not yet capable of receiving deliveries, meaning you should expect to receive any orders elsewhere. <BR>\n<BR>\n<I>-C. Donnelly</I> <BR>\n<BR>\nArchitectural Analyst"
/obj/item/paper/fluff/cogstation/router_limited
name = "ROUTER STATUS: LIMITED"
info = "Currently, this router cannot receive deliveries from the Airbridge, MedSci, Security, or Service Routers. Cargo and the recycler are the only points currently accepting deliveries from here, although manual input from the routing depot is currently required. <BR>\n<BR>\n<I>-C. Donnelly</I> <BR>\n<BR>\nArchitectural Analyst"
/obj/item/paper/fluff/cogstation/router_cargo
name = "ROUTER STATUS: VERY LIMITED"
info = "Currently, this router cannot receive deliveries from the Airbridge, MedSci, Security, or Service Routers. It is not yet capable of making deliveries, beyond sending items to the recycler. <BR>\n<BR>\n<I>-C. Donnelly</I> <BR>\n<BR>\nArchitectural Analyst"
/////////// CentCom
+50 -48
View File
@@ -196,7 +196,7 @@ By design, d1 is the smallest direction and d2 is the highest
/obj/structure/cable/proc/update_stored(length = 1, colorC = "red")
stored.amount = length
stored.item_color = colorC
stored.color = colorC
stored.update_icon()
////////////////////////////////////////////
@@ -469,7 +469,6 @@ By design, d1 is the smallest direction and d2 is the highest
// Definitions
////////////////////////////////
GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restraints", /obj/item/restraints/handcuffs/cable, 15)))
/obj/item/stack/cable_coil
name = "cable coil"
@@ -482,7 +481,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
max_amount = MAXCOIL
amount = MAXCOIL
merge_type = /obj/item/stack/cable_coil // This is here to let its children merge between themselves
item_color = "red"
color = "red"
desc = "A coil of insulated power cable."
throwforce = 0
w_class = WEIGHT_CLASS_SMALL
@@ -504,7 +503,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/obj/item/stack/cable_coil/cyborg/attack_self(mob/user)
var/cable_color = input(user,"Pick a cable color.","Cable Color") in list("red","yellow","green","blue","pink","orange","cyan","white")
item_color = cable_color
color = cable_color
update_icon()
/obj/item/stack/cable_coil/suicide_act(mob/user)
@@ -514,18 +513,11 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
user.visible_message("<span class='suicide'>[user] is strangling [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
return(OXYLOSS)
/obj/item/stack/cable_coil/Initialize(mapload, new_amount = null, param_color = null)
/obj/item/stack/cable_coil/Initialize(mapload, new_amount = null)
. = ..()
var/list/cable_colors = GLOB.cable_colors
item_color = param_color || item_color || pick(cable_colors)
if(cable_colors[item_color])
item_color = cable_colors[item_color]
pixel_x = rand(-2,2)
pixel_y = rand(-2,2)
update_icon()
recipes = GLOB.cable_coil_recipes
///////////////////////////////////
// General procedures
@@ -541,7 +533,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
if(affecting && affecting.status == BODYPART_ROBOTIC)
if(user == H)
user.visible_message("<span class='notice'>[user] starts to fix some of the wires in [H]'s [affecting.name].</span>", "<span class='notice'>You start fixing some of the wires in [H]'s [affecting.name].</span>")
if(!do_mob(user, H, 50))
if(!do_after(user, H, 50))
return
if(item_heal_robotic(H, user, 0, 15))
use(1)
@@ -553,8 +545,6 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/obj/item/stack/cable_coil/update_icon()
icon_state = "[initial(item_state)][amount < 3 ? amount : ""]"
name = "cable [amount < 3 ? "piece" : "coil"]"
color = null
add_atom_colour(item_color, FIXED_COLOUR_PRIORITY)
/obj/item/stack/cable_coil/attack_hand(mob/user)
. = ..()
@@ -562,9 +552,28 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
return
var/obj/item/stack/cable_coil/new_cable = ..()
if(istype(new_cable))
new_cable.item_color = item_color
new_cable.color = color
new_cable.update_icon()
/obj/item/stack/cable_coil/attack_self(mob/user)
if(!check_cable_amount(user))
return
to_chat(user, "<span class='notice'>You start making some cable restraints.</span>")
if(do_after(user, 30, TRUE, user) && check_cable_amount(user))
amount -= 15
var/obj/item/restraints/handcuffs/cable/result = new(get_turf(user))
user.put_in_hands(result)
result.color = color
to_chat(user, "<span class='notice'>You make some restraints out of cable</span>")
return
to_chat(user, "<span class='notice'>You fail to make cable restraints, you need to stand still while doing so.</span>")
/obj/item/stack/cable_coil/proc/check_cable_amount(user)
if(amount < 15) //We dont care about cyborgs here, so we dont use get_amount()
to_chat(user, "<span class='notice'>You dont have enough cable coil to make restraints out of them</span>")
return FALSE
return TRUE
//add cables to the stack
/obj/item/stack/cable_coil/proc/give(extra)
if(amount + extra > max_amount)
@@ -581,7 +590,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/obj/item/stack/cable_coil/proc/get_new_cable(location)
var/path = /obj/structure/cable
return new path(location, item_color)
return new path(location, color)
// called when cable_coil is clicked on a turf
/obj/item/stack/cable_coil/proc/place_turf(turf/T, mob/user, dirnew)
@@ -738,7 +747,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
C.d2 = nd2
//updates the stored cable coil
C.update_stored(2, item_color)
C.update_stored(2, color)
C.add_fingerprint(user)
C.update_icon()
@@ -769,40 +778,36 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/////////////////////////////
/obj/item/stack/cable_coil/red
item_color = "red"
color = "#ff0000"
color = "red"
/obj/item/stack/cable_coil/yellow
item_color = "yellow"
color = "#ffff00"
color = "yellow"
/obj/item/stack/cable_coil/blue
item_color = "blue"
color = "#1919c8"
color = "blue"
/obj/item/stack/cable_coil/green
item_color = "green"
color = "#00aa00"
color = "green"
/obj/item/stack/cable_coil/pink
item_color = "pink"
color = "#ff3ccd"
/obj/item/stack/cable_coil/orange
item_color = "orange"
color = "#ff8000"
/obj/item/stack/cable_coil/cyan
item_color = "cyan"
color = "#00ffff"
color = "cyan"
/obj/item/stack/cable_coil/white
item_color = "white"
color = "white"
/obj/item/stack/cable_coil/random
item_color = null
color = "#ffffff"
/obj/item/stack/cable_coil/random/Initialize(mapload, new_amount = null, param_color = null)
. = ..()
var/list/cable_colors = GLOB.cable_colors
color = pick(cable_colors)
/obj/item/stack/cable_coil/random/five
amount = 5
@@ -820,36 +825,33 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
update_icon()
/obj/item/stack/cable_coil/cut/red
item_color = "red"
color = "#ff0000"
color = "red"
/obj/item/stack/cable_coil/cut/yellow
item_color = "yellow"
color = "#ffff00"
color = "yellow"
/obj/item/stack/cable_coil/cut/blue
item_color = "blue"
color = "#1919c8"
color = "blue"
/obj/item/stack/cable_coil/cut/green
item_color = "green"
color = "#00aa00"
color = "green"
/obj/item/stack/cable_coil/cut/pink
item_color = "pink"
color = "#ff3ccd"
/obj/item/stack/cable_coil/cut/orange
item_color = "orange"
color = "#ff8000"
/obj/item/stack/cable_coil/cut/cyan
item_color = "cyan"
color = "#00ffff"
color = "cyan"
/obj/item/stack/cable_coil/cut/white
item_color = "white"
color = "white"
/obj/item/stack/cable_coil/cut/random
item_color = null
color = "#ffffff"
color = "#ffffff"
/obj/item/stack/cable_coil/cut/random/Initialize(mapload, new_amount = null, param_color = null)
. = ..()
var/list/cable_colors = GLOB.cable_colors
color = pick(cable_colors)
+1 -1
View File
@@ -41,7 +41,7 @@
var/firing = FALSE
/// Used in gun-in-mouth execution/suicide and similar, while TRUE nothing should work on this like firing or modification and so on and so forth.
var/busy_action = FALSE
var/weapon_weight = WEAPON_LIGHT //currently only used for inaccuracy
var/weapon_weight = WEAPON_LIGHT //used for inaccuracy and wielding requirements/penalties
var/spread = 0 //Spread induced by the gun itself.
var/burst_spread = 0 //Spread induced by the gun itself during burst fire per iteration. Only checked if spread is 0.
var/randomspread = 1 //Set to 0 for shotguns. This is used for weapons that don't fire all their bullets at once.
@@ -1,10 +1,10 @@
/obj/item/gun/ballistic/automatic/magrifle
name = "\improper Magnetic Rifle"
name = "magnetic rifle"
desc = "A simple upscalling of the technologies used in the magpistol, the magrifle is capable of firing slightly larger slugs in bursts. Compatible with the magpistol's slugs."
icon_state = "magrifle"
item_state = "arg"
force = 10
slot_flags = NONE
slot_flags = ITEM_SLOT_BACK
mag_type = /obj/item/ammo_box/magazine/mmag
fire_sound = 'sound/weapons/magrifle.ogg'
can_suppress = FALSE
@@ -17,6 +17,7 @@
inaccuracy_modifier = 0
dualwield_spread_mult = 1.4
weapon_weight = WEAPON_MEDIUM
w_class = WEIGHT_CLASS_BULKY
var/obj/item/stock_parts/cell/cell
var/cell_type = /obj/item/stock_parts/cell/magnetic
@@ -63,12 +64,13 @@
spawnwithmagazine = FALSE
/obj/item/gun/ballistic/automatic/magrifle/hyperburst
name = "\improper Hyper-Burst Rifle"
name = "\improper Hyper-Burst rifle"
desc = "An extremely beefed up version of a stolen Nanotrasen weapon prototype, this 'rifle' is more like a cannon, with an extremely large bore barrel capable of generating several smaller magnetic 'barrels' to simultaneously launch multiple projectiles at once."
icon_state = "hyperburst"
item_state = "arg"
slot_flags = NONE //too lazy for the sprites rn and it's pretty stronk anyway.
mag_type = /obj/item/ammo_box/magazine/mhyper
fire_sound = 'sound/weapons/magburst.ogg'
w_class = WEIGHT_CLASS_HUGE
fire_delay = 40
recoil = 2
weapon_weight = WEAPON_HEAVY
@@ -83,6 +85,8 @@
name = "magpistol"
desc = "A handgun utilizing maglev technologies to propel a ferromagnetic slug to extreme velocities."
icon_state = "magpistol"
w_class = WEIGHT_CLASS_NORMAL
slot_flags = ITEM_SLOT_BELT
fire_sound = 'sound/weapons/magpistol.ogg'
mag_type = /obj/item/ammo_box/magazine/mmag/small
fire_delay = 2
@@ -24,6 +24,7 @@
icon_state = "toyburst"
obj_flags = NONE
fire_delay = 40
w_class = WEIGHT_CLASS_HUGE
weapon_weight = WEAPON_HEAVY
selfcharge = EGUN_SELFCHARGE
charge_delay = 2
@@ -56,12 +57,14 @@
/obj/item/gun/energy/laser/carbine
name = "laser carbine"
desc = "A ruggedized laser carbine featuring much higher capacity and improved handling when compared to a normal laser gun."
icon = 'icons/obj/guns/energy.dmi'
icon_state = "lasernew"
item_state = "laser"
item_state = "lasernew"
slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
weapon_weight = WEAPON_MEDIUM
inaccuracy_modifier = 0.5
force = 10
throwforce = 10
ammo_type = list(/obj/item/ammo_casing/energy/lasergun)
cell_type = /obj/item/stock_parts/cell/lascarbine
resistance_flags = FIRE_PROOF | ACID_PROOF
@@ -189,96 +189,139 @@
if(beaker)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
beakerContents.Add(list(list("name" = R.name, "id" = ckey(R.name), "volume" = R.volume))) // list in a list because Byond merges the first list...
data["beakerContents"] = beakerContents
data["beakerContents"] = beakerContents
var/bufferContents[0]
if(reagents.total_volume)
for(var/datum/reagent/N in reagents.reagent_list)
bufferContents.Add(list(list("name" = N.name, "id" = ckey(N.name), "volume" = N.volume))) // ^
data["bufferContents"] = bufferContents
data["bufferContents"] = bufferContents
//Calculated at init time as it never changes
data["pillStyles"] = pillStyles
return data
/obj/machinery/chem_master/ui_act(action, params)
if(..())
return
switch(action)
if("eject")
replace_beaker(usr)
. = TRUE
if("ejectp")
if("ejectPillBottle")
replace_pillbottle(usr)
. = TRUE
if("transferToBuffer")
if(beaker)
var/reagent = GLOB.name2reagent[params["id"]]
var/amount = text2num(params["amount"])
if (amount > 0)
end_fermi_reaction()
beaker.reagents.trans_id_to(src, reagent, amount)
. = TRUE
else if (amount == -1) // -1 means custom amount
useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null
if (useramount > 0)
end_fermi_reaction()
beaker.reagents.trans_id_to(src, reagent, useramount)
. = TRUE
if("transferFromBuffer")
if("transfer")
if(!beaker)
return FALSE
var/reagent = GLOB.name2reagent[params["id"]]
var/amount = text2num(params["amount"])
if (amount > 0)
if(mode)
reagents.trans_id_to(beaker, reagent, amount)
. = TRUE
else
reagents.remove_reagent(reagent, amount)
. = TRUE
else if (amount == -1) // -1 means custom amount
useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null
if (useramount > 0)
end_fermi_reaction()
reagents.trans_id_to(beaker, reagent, useramount)
. = TRUE
var/to_container = params["to"]
// Custom amount
if (amount == -1)
amount = text2num(input(
"Enter the amount you want to transfer:",
name, ""))
if (amount == null || amount <= 0)
return FALSE
if (to_container == "buffer")
end_fermi_reaction()
beaker.reagents.trans_id_to(src, reagent, amount)
return TRUE
if (to_container == "beaker" && mode)
end_fermi_reaction()
reagents.trans_id_to(beaker, reagent, amount)
return TRUE
if (to_container == "beaker" && !mode)
end_fermi_reaction()
reagents.remove_reagent(reagent, amount)
return TRUE
return FALSE
if("toggleMode")
mode = !mode
. = TRUE
if("createPill")
var/many = params["many"]
if("pillStyle")
var/id = text2num(params["id"])
chosenPillStyle = id
return TRUE
if("create")
if(reagents.total_volume == 0)
return
if(!condi)
var/amount = 1
var/vol_each = min(reagents.total_volume, 50)
if(text2num(many))
amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many pills?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 50)
var/name = html_decode(stripped_input(usr,"Name:","Name your pill!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
return
return FALSE
var/item_type = params["type"]
// Get amount of items
var/amount = text2num(params["amount"])
if(amount == null)
amount = text2num(input(usr,
"Max 10. Buffer content will be split evenly.",
"How many to make?", 1))
amount = clamp(round(amount), 0, 10)
if (amount <= 0)
return FALSE
// Get units per item
var/vol_each = text2num(params["volume"])
var/vol_each_text = params["volume"]
var/vol_each_max = reagents.total_volume / amount
if (item_type == "pill")
vol_each_max = min(50, vol_each_max)
else if (item_type == "patch")
vol_each_max = min(40, vol_each_max)
else if (item_type == "bottle")
vol_each_max = min(30, vol_each_max)
else if (item_type == "condimentPack")
vol_each_max = min(10, vol_each_max)
else if (item_type == "condimentBottle")
vol_each_max = min(50, vol_each_max)
else if (item_type == "hypoVial")
vol_each_max = min(60, vol_each_max)
else if (item_type == "smartDart")
vol_each_max = min(20, vol_each_max)
else
return FALSE
if(vol_each_text == "auto")
vol_each = vol_each_max
if(vol_each == null)
vol_each = text2num(input(usr,
"Maximum [vol_each_max] units per item.",
"How many units to fill?",
vol_each_max))
vol_each = clamp(vol_each, 0, vol_each_max)
if(vol_each <= 0)
return FALSE
// Get item name
var/name = params["name"]
var/name_has_units = item_type == "pill" || item_type == "patch"
if(!name)
var/name_default = reagents.get_master_reagent_name()
if (name_has_units)
name_default += " ([vol_each]u)"
name = stripped_input(usr,
"Name:",
"Give it a name!",
name_default,
MAX_NAME_LEN)
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return FALSE
// Start filling
if(item_type == "pill")
var/obj/item/reagent_containers/pill/P
var/target_loc = drop_location()
var/drop_threshold = INFINITY
if(bottle)
var/datum/component/storage/STRB = bottle.GetComponent(/datum/component/storage)
var/datum/component/storage/STRB = bottle.GetComponent(
/datum/component/storage)
if(STRB)
drop_threshold = STRB.max_items - bottle.contents.len
target_loc = bottle
for(var/i in 1 to amount)
if(i <= drop_threshold)
P = new(target_loc)
for(var/i = 0; i < amount; i++)
if(i < drop_threshold)
P = new/obj/item/reagent_containers/pill(target_loc)
else
P = new(drop_location())
P = new/obj/item/reagent_containers/pill(drop_location())
P.name = trim("[name] pill")
if(chosenPillStyle == RANDOM_PILL_STYLE)
P.icon_state ="pill[rand(1,21)]"
@@ -287,171 +330,62 @@
if(P.icon_state == "pill4")
P.desc = "A tablet or capsule, but not just any, a red one, one taken by the ones not scared of knowledge, freedom, uncertainty and the brutal truths of reality."
adjust_item_drop_location(P)
reagents.trans_to(P,vol_each)
else
var/name = html_decode(stripped_input(usr, "Name:", "Name your pack!", reagents.get_master_reagent_name(), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
return
var/obj/item/reagent_containers/food/condiment/pack/P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
P.originalname = name
P.name = trim("[name] pack")
P.desc = "A small condiment pack. The label says it contains [name]."
reagents.trans_to(P,10)
. = TRUE
if("pillStyle")
var/id = text2num(params["id"])
chosenPillStyle = id
if("createPatch")
var/many = params["many"]
if(reagents.total_volume == 0)
return
var/amount = 1
var/vol_each = min(reagents.total_volume, 40)
if(text2num(many))
amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many patches?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 40)
var/name = html_decode(stripped_input(usr,"Name:","Name your patch!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
return
var/obj/item/reagent_containers/pill/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/pill/patch(drop_location())
P.name = trim("[name] patch")
adjust_item_drop_location(P)
reagents.trans_to(P,vol_each)
. = TRUE
if("createBottle")
var/many = params["many"]
if(reagents.total_volume == 0)
return
if(condi)
var/name = html_decode(stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
return
var/obj/item/reagent_containers/food/condiment/P = new(drop_location())
P.originalname = name
P.name = trim("[name] bottle")
reagents.trans_to(P, P.volume)
else
var/amount_full = 0
var/vol_part = min(reagents.total_volume, 30)
if(text2num(many))
amount_full = round(reagents.total_volume / 30)
vol_part = ((reagents.total_volume*1000) % 30000) / 1000 //% operator doesn't support decimals.
var/name = html_decode(stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
return
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "patch")
var/obj/item/reagent_containers/pill/patch/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/pill/patch(drop_location())
P.name = trim("[name] patch")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "bottle")
var/obj/item/reagent_containers/glass/bottle/P
for(var/i = 0; i < amount_full; i++)
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/glass/bottle(drop_location())
P.name = trim("[name] bottle")
adjust_item_drop_location(P)
reagents.trans_to(P, 30)
if(vol_part)
P = new/obj/item/reagent_containers/glass/bottle(drop_location())
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "condimentPack")
var/obj/item/reagent_containers/food/condiment/pack/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
P.originalname = name
P.name = trim("[name] pack")
P.desc = "A small condiment pack. The label says it contains [name]."
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "condimentBottle")
var/obj/item/reagent_containers/food/condiment/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/food/condiment(drop_location())
P.originalname = name
P.name = trim("[name] bottle")
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "hypoVial")
var/obj/item/reagent_containers/glass/bottle/vial/small/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
P.name = trim("[name] hypovial")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_part)
. = TRUE
//CITADEL ADD Hypospray Vials
if("createVial")
var/many = params["many"]
if(reagents.total_volume == 0)
return
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "smartDart")
var/obj/item/reagent_containers/syringe/dart/P
for(var/i = 0; i < amount; i++)
P = new /obj/item/reagent_containers/syringe/dart(drop_location())
P.name = trim("[name] SmartDart")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_each)
P.mode=!mode
P.update_icon()
return TRUE
return FALSE
var/amount_full = 0
var/vol_part = min(reagents.total_volume, 60)
if(text2num(many))
amount_full = round(reagents.total_volume / 60)
vol_part = reagents.total_volume % 60
var/name = html_decode(stripped_input(usr, "Name:","Name your hypovial!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
return
var/obj/item/reagent_containers/glass/bottle/vial/small/P
for(var/i = 0; i < amount_full; i++)
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
P.name = trim("[name] hypovial")
adjust_item_drop_location(P)
reagents.trans_to(P, 60)
if(vol_part)
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
P.name = trim("[name] hypovial")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_part)
. = TRUE
if("createDart")
for(var/datum/reagent/R in reagents.reagent_list)
if(!(istype(R, /datum/reagent/medicine)))
visible_message("<b>The [src]</b> beeps, \"<span class='warning'>SmartDarts are insoluble with non-medicinal compounds.\"</span>")
return
var/many = params["many"]
if(reagents.total_volume == 0)
return
var/amount = 1
var/vol_each = min(reagents.total_volume, 20)
if(text2num(many))
amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many darts?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 20)
var/name = html_decode(stripped_input(usr,"Name:","Name your SmartDart!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
return
var/obj/item/reagent_containers/syringe/dart/D
for(var/i = 0; i < amount; i++)
D = new /obj/item/reagent_containers/syringe/dart(drop_location())
D.name = trim("[name] SmartDart")
adjust_item_drop_location(D)
reagents.trans_to(D, vol_each)
D.mode=!mode
D.update_icon()
. = TRUE
//END CITADEL ADDITIONS
if("analyzeBeak")
var/datum/reagent/R = GLOB.name2reagent[params["id"]]
if(R)
var/state = "Unknown"
if(initial(R.reagent_state) == 1)
state = "Solid"
else if(initial(R.reagent_state) == 2)
state = "Liquid"
else if(initial(R.reagent_state) == 3)
state = "Gas"
var/const/P = 3 //The number of seconds between life ticks
var/T = initial(R.metabolization_rate) * (60 / P)
var/datum/chemical_reaction/Rcr = get_chemical_reaction(R)
if(Rcr && Rcr.FermiChem)
fermianalyze = TRUE
var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
var/datum/reagent/targetReagent = beaker.reagents.has_reagent(R)
if(!targetReagent)
CRASH("Tried to find a reagent that doesn't exist in the chem_master!")
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = targetReagent.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
else
fermianalyze = FALSE
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
screen = "analyze"
return
if("analyzeBuff")
if("analyze")
var/datum/reagent/R = GLOB.name2reagent[params["id"]]
if(R)
var/state = "Unknown"
@@ -476,7 +410,7 @@
fermianalyze = FALSE
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
screen = "analyze"
return
return TRUE
if("goScreen")
screen = params["screen"]
@@ -527,4 +461,4 @@
condi = TRUE
#undef PILL_STYLE_COUNT
#undef RANDOM_PILL_STYLE
#undef RANDOM_PILL_STYLE
@@ -864,12 +864,13 @@
glass_icon_state = "red_queen"
glass_name = "Red Queen"
glass_desc = "DRINK ME."
var/current_size = 1
var/current_size = RESIZE_DEFAULT_SIZE
/datum/reagent/consumable/red_queen/on_mob_life(mob/living/carbon/H)
if(prob(75))
return ..()
var/newsize = pick(0.5, 0.75, 1, 1.50, 2)
newsize *= RESIZE_DEFAULT_SIZE
H.resize = newsize/current_size
current_size = newsize
H.update_transform()
@@ -878,7 +879,8 @@
..()
/datum/reagent/consumable/red_queen/on_mob_end_metabolize(mob/living/M)
M.resize = 1/current_size
M.resize = RESIZE_DEFAULT_SIZE/current_size
current_size = RESIZE_DEFAULT_SIZE
M.update_transform()
..()
@@ -1917,22 +1917,22 @@
name = "Growth Serum"
description = "A commercial chemical designed to help older men in the bedroom."//not really it just makes you a giant
color = "#ff0000"//strong red. rgb 255, 0, 0
var/current_size = 1
var/current_size = RESIZE_DEFAULT_SIZE
taste_description = "bitterness" // apparently what viagra tastes like
/datum/reagent/growthserum/on_mob_life(mob/living/carbon/H)
var/newsize = current_size
switch(volume)
if(0 to 19)
newsize = 1.25
newsize = 1.25*RESIZE_DEFAULT_SIZE
if(20 to 49)
newsize = 1.5
newsize = 1.5*RESIZE_DEFAULT_SIZE
if(50 to 99)
newsize = 2
newsize = 2*RESIZE_DEFAULT_SIZE
if(100 to 199)
newsize = 2.5
newsize = 2.5*RESIZE_DEFAULT_SIZE
if(200 to INFINITY)
newsize = 3.5
newsize = 3.5*RESIZE_DEFAULT_SIZE
H.resize = newsize/current_size
current_size = newsize
@@ -1940,7 +1940,8 @@
..()
/datum/reagent/growthserum/on_mob_end_metabolize(mob/living/M)
M.resize = 1/current_size
M.resize = RESIZE_DEFAULT_SIZE/current_size
current_size = RESIZE_DEFAULT_SIZE
M.update_transform()
..()
+2 -2
View File
@@ -235,7 +235,7 @@
/obj/structure/reagent_dispensers/keg/milk
name = "keg of milk"
desc = "It's not quite what you were hoping for."
desc = "A keg of pasteurised, homogenised, filtered and semi-skimmed space milk."
icon_state = "whitekeg"
reagent_id = /datum/reagent/consumable/milk
@@ -250,4 +250,4 @@
desc = "A keg of... wow that's a long name."
icon_state = "bluekeg"
reagent_id = /datum/reagent/consumable/ethanol/gargle_blaster
tank_volume = 100
tank_volume = 100
@@ -45,7 +45,7 @@
/datum/design/board/vendor
name = "Machine Design (Vendor Board)"
desc = "The circuit board for a Vendor."
desc = "The circuit board for a Vendor. Use a screwdriver to turn the \"brand selection\" dial."
id = "vendor"
build_path = /obj/item/circuitboard/machine/vendor
category = list ("Misc. Machinery")
+1 -1
View File
@@ -237,7 +237,7 @@
display_name = "Games and Toys"
description = "For the slackers on the station."
prereq_ids = list("comptech")
design_ids = list("arcade_battle", "arcade_orion", "slotmachine", "autoylathe")
design_ids = list("arcade_battle", "arcade_orion", "arcade_minesweeper", "slotmachine", "autoylathe")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000)
/////////////////////////Bluespace tech/////////////////////////
@@ -505,13 +505,13 @@ datum/status_effect/rebreathing/tick()
/datum/status_effect/stabilized/purple/tick()
var/is_healing = FALSE
if(owner.getBruteLoss() > 0)
owner.adjustBruteLoss(-0.2)
owner.adjustBruteLoss(-0.4)
is_healing = TRUE
if(owner.getFireLoss() > 0)
owner.adjustFireLoss(-0.2)
owner.adjustFireLoss(-0.4)
is_healing = TRUE
if(owner.getToxLoss() > 0)
owner.adjustToxLoss(-0.2, forced = TRUE) //Slimepeople should also get healed.
owner.adjustToxLoss(-0.4, forced = TRUE) //Slimepeople should also get healed.
is_healing = TRUE
if(is_healing)
examine_text = "<span class='warning'>SUBJECTPRONOUN is regenerating slowly, purplish goo filling in small injuries!</span>"
@@ -933,7 +933,6 @@ datum/status_effect/stabilized/blue/on_remove()
return ..()
/datum/status_effect/stabilized/lightpink/tick()
owner.adjustStaminaLoss(-4.5)
for(var/mob/living/carbon/human/H in range(1, get_turf(owner)))
if(H != owner && H.stat != DEAD && H.health <= 0 && !H.reagents.has_reagent(/datum/reagent/medicine/epinephrine))
to_chat(owner, "[linked_extract] pulses in sync with [H]'s heartbeat, trying to keep [H.p_them()] alive.")
+67 -94
View File
@@ -109,10 +109,9 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
var/holder_var_type = "bruteloss" //only used if charge_type equals to "holder_var"
var/holder_var_amount = 20 //same. The amount adjusted with the mob's var when the spell is used
var/clothes_req = 1 //see if it requires clothes
var/cult_req = 0 //SPECIAL SNOWFLAKE clothes required for cult only spells
var/human_req = 0 //spell can only be cast by humans
var/nonabstract_req = 0 //spell can only be cast by mobs that are physical entities
var/clothes_req = SPELL_WIZARD_GARB //see if it requires clothes
var/list/mobs_whitelist //spell can only be casted by mobs in this typecache.
var/list/mobs_blacklist //The opposite of the above.
var/stat_allowed = 0 //see if it requires being conscious/alive, need to set to 1 for ghostpells
var/phase_allowed = 0 // If true, the spell can be cast while phased, eg. blood crawling, ethereal jaunting
var/antimagic_allowed = TRUE // If false, the spell cannot be cast while under the effect of antimagic
@@ -144,79 +143,17 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
action_background_icon_state = "bg_spell"
base_action = /datum/action/spell_action/spell
/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
if(player_lock)
if(!user.mind || !(src in user.mind.spell_list) && !(src in user.mob_spell_list))
to_chat(user, "<span class='warning'>You shouldn't have this spell! Something's wrong.</span>")
return FALSE
else
if(!(src in user.mob_spell_list))
return FALSE
/obj/effect/proc_holder/spell/Initialize()
. = ..()
if(mobs_whitelist)
mobs_whitelist = typecacheof(mobs_whitelist)
if(mobs_blacklist)
mobs_blacklist = typecacheof(mobs_blacklist)
var/turf/T = get_turf(user)
if(is_centcom_level(T.z) && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel
to_chat(user, "<span class='notice'>You can't cast this spell here.</span>")
/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = FALSE, mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
if(!can_cast(user, skipcharge))
return FALSE
if(!skipcharge)
if(!charge_check(user))
return FALSE
if(user.stat && !stat_allowed)
to_chat(user, "<span class='notice'>Not when you're incapacitated.</span>")
return FALSE
if(!antimagic_allowed)
var/antimagic = user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE)
if(antimagic)
if(isitem(antimagic))
to_chat(user, "<span class='notice'>[antimagic] is interfering with your magic.</span>")
else
to_chat(user, "<span class='notice'>Magic seems to flee from you, you can't gather enough power to cast this spell.</span>")
return FALSE
if(!phase_allowed && istype(user.loc, /obj/effect/dummy))
to_chat(user, "<span class='notice'>[name] cannot be cast unless you are completely manifested in the material plane.</span>")
return FALSE
if(ishuman(user))
var/mob/living/carbon/human/H = user
if((invocation_type == "whisper" || invocation_type == "shout") && !H.can_speak_vocal())
to_chat(user, "<span class='notice'>You can't get the words out!</span>")
return FALSE
var/list/casting_clothes = typecacheof(list(/obj/item/clothing/suit/wizrobe,
/obj/item/clothing/suit/space/hardsuit/wizard,
/obj/item/clothing/head/wizard,
/obj/item/clothing/head/helmet/space/hardsuit/wizard,
/obj/item/clothing/suit/space/hardsuit/shielded/wizard,
/obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard))
if(clothes_req) //clothes check
if(!is_type_in_typecache(H.wear_suit, casting_clothes))
to_chat(H, "<span class='notice'>I don't feel strong enough without my robe.</span>")
return FALSE
if(!is_type_in_typecache(H.head, casting_clothes))
to_chat(H, "<span class='notice'>I don't feel strong enough without my hat.</span>")
return FALSE
if(cult_req) //CULT_REQ CLOTHES CHECK
if(!istype(H.wear_suit, /obj/item/clothing/suit/magusred) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/cult))
to_chat(H, "<span class='notice'>I don't feel strong enough without my armor.</span>")
return FALSE
if(!istype(H.head, /obj/item/clothing/head/magus) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/cult))
to_chat(H, "<span class='notice'>I don't feel strong enough without my helmet.</span>")
return FALSE
else
if(clothes_req || human_req)
to_chat(user, "<span class='notice'>This spell can only be cast by humans!</span>")
return FALSE
if(nonabstract_req && (isbrain(user) || ispAI(user)))
to_chat(user, "<span class='notice'>This spell can only be cast by physical beings!</span>")
return FALSE
if(!skipcharge)
switch(charge_type)
if("recharge")
@@ -227,7 +164,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
adjust_var(user, holder_var_type, holder_var_amount)
if(action)
action.UpdateButtonIcon()
return 1
return TRUE
/obj/effect/proc_holder/spell/proc/charge_check(mob/user, silent = FALSE)
switch(charge_type)
@@ -482,11 +419,6 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
/obj/effect/proc_holder/spell/proc/updateButtonIcon(status_only, force)
action.UpdateButtonIcon(status_only, force)
/obj/effect/proc_holder/spell/proc/can_be_cast_by(mob/caster)
if((human_req || clothes_req) && !ishuman(caster))
return 0
return 1
/obj/effect/proc_holder/spell/targeted/proc/los_check(mob/A,mob/B)
//Checks for obstacles from A to B
var/obj/dummy = new(A.loc)
@@ -499,24 +431,65 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
qdel(dummy)
return 1
/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr)
if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list))
/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr, skipcharge = FALSE, silent = FALSE)
var/magic_flags = SEND_SIGNAL(user, COMSIG_MOB_SPELL_CAST_CHECK, src)
if(magic_flags & SPELL_SKIP_ALL_REQS)
return TRUE
if(player_lock && (!user.mind || !(src in user.mind.spell_list)))
if(!silent)
to_chat(user, "<span class='warning'>You shouldn't have this spell! Something's wrong.</span>")
return FALSE
if(!charge_check(user,TRUE))
if(!(src in user.mob_spell_list))
return FALSE
if(user.stat && !stat_allowed)
return FALSE
if(!antimagic_allowed && user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE))
return FALSE
if(!ishuman(user))
if(clothes_req || human_req)
if(!centcom_cancast && !(magic_flags & SPELL_SKIP_CENTCOM)) //Certain spells are not allowed on the centcom zlevel
var/turf/T = get_turf(user)
if(is_centcom_level(T.z))
if(!silent)
to_chat(user, "<span class='notice'>You can't cast this spell here.</span>")
return FALSE
if(nonabstract_req && (isbrain(user) || ispAI(user)))
if(!skipcharge)
if(!charge_check(user))
return FALSE
if(user.stat && !stat_allowed && !(magic_flags & SPELL_SKIP_STAT))
if(!silent)
to_chat(user, "<span class='notice'>Not when you're incapacitated.</span>")
return FALSE
if(!phase_allowed && istype(user.loc, /obj/effect/dummy))
if(!silent)
to_chat(user, "<span class='notice'>[name] cannot be cast unless you are completely manifested in the material plane.</span>")
return FALSE
if(clothes_req && !(magic_flags & SPELL_SKIP_CLOTHES))
var/met_requirements = magic_flags & (clothes_req)
if(met_requirements != clothes_req)
if(!silent)
var/the_many_hats = met_requirements & (clothes_req & (SPELL_WIZARD_HAT|SPELL_CULT_HELMET))
var/the_many_suits = met_requirements & (clothes_req & (SPELL_WIZARD_ROBE|SPELL_CULT_ARMOR))
var/without_hat_robe = the_many_suits ? "a proper headwear" : the_many_hats ? "a proper suit" : "proper garments"
to_chat(user, "<span class='notice'>I don't feel strong enough to cast this spell without [without_hat_robe].</span>")
return FALSE
if(!antimagic_allowed && !(magic_flags & SPELL_SKIP_ANTIMAGIC) && user.anti_magic_check(TRUE, FALSE, chargecost = 0, self = TRUE))
return FALSE
if(!(magic_flags & SPELL_SKIP_VOCAL) && (invocation_type in list("whisper", "shout")) && isliving(user))
var/mob/living/L = user
if(!L.can_speak_vocal())
if(!silent)
to_chat(L, "<span class='notice'>You can't get the words out!</span>")
return FALSE
if(!(magic_flags & SPELL_SKIP_MOBTYPE) && ((mobs_whitelist && !mobs_whitelist[user]) || (mobs_blacklist && mobs_blacklist[user])))
if(!silent)
to_chat(user, "<span class='notice'>This spell can't be casted in this current form!</span>")
return FALSE
return TRUE
/obj/effect/proc_holder/spell/self //Targets only the caster. Good for buffs and heals, but probably not wise for fireballs (although they usually fireball themselves anyway, honke)
@@ -531,8 +504,8 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
/obj/effect/proc_holder/spell/self/basic_heal //This spell exists mainly for debugging purposes, and also to show how casting works
name = "Lesser Heal"
desc = "Heals a small amount of brute and burn damage."
human_req = 1
clothes_req = 0
mobs_whitelist = list(/mob/living/carbon/human)
clothes_req = NONE
charge_max = 100
cooldown_min = 50
invocation = "Victus sano!"
+3 -4
View File
@@ -16,7 +16,7 @@
if(!istype(user))
return
var/msg
if(!can_cast(user))
if(!can_cast(user, FALSE, TRUE))
msg = "<span class='warning'>You can no longer cast [name]!</span>"
remove_ranged_ability(msg)
return
@@ -95,7 +95,6 @@
desc = "Fire a high powered lightning bolt at your foes!"
school = "evocation"
charge_max = 150
clothes_req = 1
invocation = "ZAP MUTHA'FUCKA"
invocation_type = "shout"
cooldown_min = 30
@@ -113,7 +112,7 @@
desc = "This spell fires a fireball at a target and does not require wizard garb."
school = "evocation"
charge_max = 100
clothes_req = 0
clothes_req = NONE
invocation = "ONI SOMA"
invocation_type = "shout"
range = 20
@@ -131,7 +130,7 @@
desc = "Blazing hot rapid-fire homing cards. Banish your foes with its mystical power!"
school = "evocation"
charge_max = 50
clothes_req = 0
clothes_req = NONE
invocation = "Sigi'lu M'Fan 'Tasia"
invocation_type = "shout"
range = 40
@@ -1,7 +1,7 @@
/obj/effect/proc_holder/spell/targeted/area_teleport
name = "Area teleport"
desc = "This spell teleports you to a type of area of your selection."
nonabstract_req = 1
mobs_blacklist = list(/mob/living/brain, /mob/living/silicon/pai)
var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list
var/invocation_area = 1 //if the invocation appends the selected area
+1 -1
View File
@@ -5,7 +5,7 @@
charge_type = "recharge"
charge_max = 150
charge_counter = 0
clothes_req = 0
clothes_req = NONE
stat_allowed = 0
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
invocation_type = "shout"
@@ -2,7 +2,7 @@
name = "Blood Crawl"
desc = "Use pools of blood to phase out of existence."
charge_max = 0
clothes_req = 0
clothes_req = NONE
//If you couldn't cast this while phased, you'd have a problem
phase_allowed = 1
selection_type = "range"
+1 -1
View File
@@ -4,7 +4,7 @@
school = "transmutation"
charge_max = 600
clothes_req = 0
clothes_req = NONE
invocation = "DIRI CEL"
invocation_type = "whisper"
range = -1
+2 -2
View File
@@ -60,7 +60,7 @@
name = "Link Worlds"
desc = "A whole new dimension for you to play with! They won't be happy about it, though."
invocation = "WTF"
clothes_req = FALSE
clothes_req = NONE
charge_max = 600
cooldown_min = 200
summon_type = list(/obj/structure/spawner/nether)
@@ -74,7 +74,7 @@
invocation_type = "none"
include_user = 1
range = -1
clothes_req = 0
clothes_req = NONE
var/obj/item/item
var/item_type = /obj/item/banhammer
school = "conjuration"
@@ -7,7 +7,7 @@
action_background_icon_state = "bg_demon"
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser/cult
cult_req = 1
clothes_req = SPELL_CULT_GARB
charge_max = 2500
@@ -17,7 +17,7 @@
school = "transmutation"
charge_max = 50
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 2
@@ -37,7 +37,7 @@
school = "conjuration"
charge_max = 20
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 0
@@ -53,7 +53,7 @@
school = "conjuration"
charge_max = 100
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 0
@@ -70,7 +70,7 @@
school = "conjuration"
charge_max = 300
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 0
@@ -83,7 +83,7 @@
school = "conjuration"
charge_max = 2400
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 0
@@ -94,7 +94,7 @@
summon_type = list(/obj/item/soulstone)
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/cult
cult_req = 1
clothes_req = SPELL_CULT_GARB
charge_max = 3600
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/noncult
@@ -105,7 +105,7 @@
desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire."
school = "transmutation"
charge_max = 400
clothes_req = FALSE
clothes_req = NONE
invocation = "none"
invocation_type = "none"
wall_type = /obj/effect/forcefield/cult
@@ -121,7 +121,7 @@
school = "transmutation"
charge_max = 250
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = -1
@@ -143,7 +143,7 @@
school = "evocation"
charge_max = 400
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
proj_type = "/obj/effect/proc_holder/spell/targeted/inflict_handler/magic_missile/lesser"
@@ -161,7 +161,7 @@
school = "conjuration"
charge_max = 200
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = -1
@@ -185,7 +185,7 @@
stat_allowed = FALSE
school = "evocation"
clothes_req = FALSE
clothes_req = NONE
invocation = "none"
invocation_type = "none"
action_icon = 'icons/mob/actions/actions_cult.dmi'
@@ -232,7 +232,7 @@
stat_allowed = FALSE
school = "evocation"
clothes_req = FALSE
clothes_req = NONE
invocation = "none"
invocation_type = "none"
action_icon = 'icons/mob/actions/actions_cult.dmi'
@@ -294,7 +294,7 @@
proj_lifespan = 15
proj_step_delay = 7
charge_max = 350
clothes_req = FALSE
clothes_req = NONE
action_icon = 'icons/mob/actions/actions_cult.dmi'
action_icon_state = "cultfist"
action_background_icon_state = "bg_demon"
+6 -6
View File
@@ -4,7 +4,7 @@
invocation_type = "none"
include_user = 1
range = -1
clothes_req = 0
clothes_req = NONE
item_type = /obj/item/twohanded/pitchfork/demonic
school = "conjuration"
@@ -37,7 +37,7 @@
invocation = "Just sign on the dotted line."
include_user = 0
range = 5
clothes_req = 0
clothes_req = NONE
school = "conjuration"
charge_max = 150
@@ -79,7 +79,7 @@
school = "evocation"
charge_max = 80
clothes_req = 0
clothes_req = NONE
invocation = "Your very soul will catch fire!"
invocation_type = "shout"
range = 2
@@ -92,7 +92,7 @@
name = "Infernal Jaunt"
desc = "Use hellfire to phase out of existence."
charge_max = 200
clothes_req = 0
clothes_req = NONE
selection_type = "range"
range = -1
cooldown_min = 0
@@ -167,7 +167,7 @@
name = "Sin Touch"
desc = "Subtly encourage someone to sin."
charge_max = 1800
clothes_req = 0
clothes_req = NONE
selection_type = "range"
range = 2
cooldown_min = 0
@@ -206,7 +206,7 @@
desc = "When what a Devil really needs is funk."
include_user = 1
range = -1
clothes_req = 0
clothes_req = NONE
school = "conjuration"
charge_max = 10
@@ -4,7 +4,7 @@
invocation_type = "none"
include_user = 1
range = -1
clothes_req = 0
clothes_req = NONE
school = "conjuration"
charge_max = 100
cooldown_min = 10
@@ -32,7 +32,7 @@
invocation_type = "none"
include_user = 1
range = -1
clothes_req = 0
clothes_req = NONE
charge_max = 50
cooldown_min = 10
action_icon = 'icons/mob/actions/actions_silicon.dmi'
@@ -51,7 +51,7 @@
invocation_type = "none"
include_user = 1
range = -1
clothes_req = 0
clothes_req = NONE
charge_max = 50
cooldown_min = 10
action_icon = 'icons/mob/actions/actions_spells.dmi'
@@ -73,4 +73,4 @@
friendShell = new /obj/effect/mob_spawn/human/demonic_friend(L.loc, L.mind, src)
/obj/effect/proc_holder/spell/targeted/conjure_item/spellpacket/robeless
clothes_req = FALSE
clothes_req = NONE
@@ -4,13 +4,12 @@
school = "transmutation"
charge_max = 300
clothes_req = 1
invocation = "none"
invocation_type = "none"
range = -1
cooldown_min = 100 //50 deciseconds reduction per rank
include_user = 1
nonabstract_req = 1
mobs_blacklist = list(/mob/living/brain, /mob/living/silicon/pai)
var/jaunt_duration = 50 //in deciseconds
var/jaunt_in_time = 5
var/jaunt_in_type = /obj/effect/temp_visual/wizard
+1 -1
View File
@@ -3,7 +3,7 @@
desc = "Create a magical barrier that only you can pass through. Does not require wizard garb."
school = "transmutation"
charge_max = 80
clothes_req = 0
clothes_req = NONE
invocation = "TARCOL MINTI ZHERI"
invocation_type = "shout"
sound = 'sound/magic/forcewall.ogg'
@@ -7,7 +7,6 @@
school = "conjuration"
charge_max = 750
clothes_req = 1
cooldown_min = 10 //Gun wizard
action_icon_state = "bolt_action"
var/summon_path = /obj/item/gun/ballistic/shotgun/boltaction/enchanted
+1 -1
View File
@@ -4,7 +4,7 @@
school = "transmutation"
charge_max = 100
clothes_req = 0
clothes_req = NONE
invocation = "AULIE OXIN FIERA"
invocation_type = "whisper"
range = 3
+1 -1
View File
@@ -8,7 +8,7 @@
becoming a lich destroys all internal organs except the brain."
school = "necromancy"
charge_max = 10
clothes_req = 0
clothes_req = NONE
centcom_cancast = 0
invocation = "NECREM IMORTIUM!"
invocation_type = "shout"
@@ -3,7 +3,6 @@
desc = "Blast lightning at your foes!"
charge_type = "recharge"
charge_max = 270
clothes_req = 1
invocation = "UN'LTD P'WAH!"
invocation_type = "shout"
range = 7
+6 -6
View File
@@ -8,10 +8,10 @@
invocation_emote_self = "<span class='notice'>You form a wall in front of yourself.</span>"
summon_lifespan = 300
charge_max = 300
clothes_req = 0
clothes_req = NONE
range = 0
cast_sound = null
human_req = 1
mobs_whitelist = list(/mob/living/carbon/human)
action_icon_state = "mime"
action_background_icon_state = "bg_mime"
@@ -32,8 +32,8 @@
desc = "Make or break a vow of silence."
school = "mime"
panel = "Mime"
clothes_req = 0
human_req = 1
clothes_req = NONE
mobs_whitelist = list(/mob/living/carbon/human)
charge_max = 3000
range = -1
include_user = 1
@@ -75,7 +75,7 @@
invocation_emote_self = "<span class='notice'>You form a blockade in front of yourself.</span>"
charge_max = 600
sound = null
clothes_req = 0
clothes_req = NONE
range = -1
include_user = 1
@@ -98,7 +98,7 @@
school = "mime"
panel = "Mime"
charge_max = 300
clothes_req = 0
clothes_req = NONE
invocation_type = "emote"
invocation_emote_self = "<span class='dangers'>You fire your finger gun!</span>"
range = 20
@@ -4,7 +4,7 @@
school = "transmutation"
charge_max = 600
clothes_req = 0
clothes_req = NONE
invocation = "GIN'YU CAPAN"
invocation_type = "whisper"
range = 1
@@ -1,8 +1,6 @@
/obj/effect/proc_holder/spell/targeted/rod_form
name = "Rod Form"
desc = "Take on the form of an immovable rod, destroying all in your path."
clothes_req = 1
human_req = 0
charge_max = 250
cooldown_min = 100
range = -1
+1 -1
View File
@@ -4,7 +4,7 @@
desc = "This spell lets you reach into S-space and retrieve presents! Yay!"
school = "santa"
charge_max = 600
clothes_req = 0
clothes_req = NONE
invocation = "HO HO HO"
invocation_type = "shout"
range = 3
@@ -2,7 +2,7 @@
name = "Shadow Walk"
desc = "Grants unlimited movement in darkness."
charge_max = 0
clothes_req = 0
clothes_req = NONE
phase_allowed = 1
selection_type = "range"
range = -1
@@ -1,8 +1,7 @@
/obj/effect/proc_holder/spell/targeted/shapeshift
name = "Shapechange"
desc = "Take on the shape of another for a time to use their natural abilities. Once you've made your choice it cannot be changed."
clothes_req = 0
human_req = 0
clothes_req = NONE
charge_max = 200
cooldown_min = 50
range = -1
@@ -59,8 +58,9 @@
var/mob/living/shape = new shapeshift_type(caster.loc)
H = new(shape,src,caster)
clothes_req = 0
human_req = 0
clothes_req = NONE
mobs_whitelist = null
mobs_blacklist = null
/obj/effect/proc_holder/spell/targeted/shapeshift/proc/Restore(mob/living/shape)
var/obj/shapeshift_holder/H = locate() in shape
@@ -70,7 +70,8 @@
H.restore()
clothes_req = initial(clothes_req)
human_req = initial(human_req)
mobs_whitelist = typecacheof(initial(mobs_whitelist))
mobs_blacklist = typecacheof(initial(mobs_blacklist))
/obj/effect/proc_holder/spell/targeted/shapeshift/dragon
name = "Dragon Form"
@@ -11,7 +11,7 @@
cooldown_min = 300
level_max = 0
/obj/effect/proc_holder/spell/spacetime_dist/can_cast(mob/user = usr)
/obj/effect/proc_holder/spell/spacetime_dist/can_cast(mob/user = usr, skipcharge = FALSE, silent = FALSE)
if(ready)
return ..()
return FALSE
@@ -3,7 +3,7 @@
desc = "This spell can be used to recall a previously marked item to your hand from anywhere in the universe."
school = "transmutation"
charge_max = 100
clothes_req = 0
clothes_req = NONE
invocation = "GAR YOK"
invocation_type = "whisper"
range = -1
@@ -105,7 +105,7 @@
if(item_to_retrieve.loc)
item_to_retrieve.loc.visible_message("<span class='warning'>The [item_to_retrieve.name] suddenly disappears!</span>")
if(!L.put_in_hands(item_to_retrieve))
if(!isitem(item_to_retrieve) || !L.put_in_hands(item_to_retrieve))
item_to_retrieve.forceMove(L.drop_location())
item_to_retrieve.loc.visible_message("<span class='caution'>The [item_to_retrieve.name] suddenly appears!</span>")
playsound(get_turf(L), 'sound/magic/summonitems_generic.ogg', 50, 1)
@@ -4,7 +4,6 @@
invocation_type = "none"
include_user = 1
range = -1
clothes_req = 0
item_type = /obj/item/reagent_containers/food/snacks/pie/cream
charge_max = 30
@@ -20,7 +19,7 @@
charge_type = "recharge"
charge_max = 100
cooldown_min = 100
clothes_req = 0
clothes_req = NONE
invocation_type = "none"
range = 7
selection_type = "view"
@@ -61,7 +60,7 @@
hand_path = /obj/item/melee/touch_attack/megahonk
charge_max = 100
clothes_req = 0
clothes_req = NONE
cooldown_min = 100
action_icon = 'icons/mecha/mecha_equipment.dmi'
@@ -75,7 +74,7 @@
hand_path = /obj/item/melee/touch_attack/bspie
charge_max = 450
clothes_req = 0
clothes_req = NONE
cooldown_min = 450
action_icon = 'icons/obj/food/piecake.dmi'
+1 -1
View File
@@ -2,7 +2,7 @@
name = "Telepathy"
desc = "Telepathically transmits a message to the target."
charge_max = 0
clothes_req = 0
clothes_req = NONE
range = 7
include_user = 0
action_icon = 'icons/mob/actions/actions_revenant.dmi'
@@ -5,7 +5,6 @@
charge_max = 250
cooldown_min = 50
clothes_req = 1
invocation = "CAVERE INSIDIAS"
invocation_type = "shout"
range = 3
@@ -56,7 +56,6 @@
school = "evocation"
charge_max = 600
clothes_req = 1
cooldown_min = 200 //100 deciseconds reduction per rank
action_icon_state = "gib"
@@ -68,7 +67,6 @@
school = "transmutation"
charge_max = 600
clothes_req = 1
cooldown_min = 200 //100 deciseconds reduction per rank
action_icon_state = "statue"
@@ -81,7 +79,7 @@
school = "evocation"
charge_max = 100
clothes_req = 0
clothes_req = NONE
cooldown_min = 20
action_icon_state = "nuclearfist"
@@ -1,7 +1,7 @@
/obj/effect/proc_holder/spell/targeted/turf_teleport
name = "Turf Teleport"
desc = "This spell teleports the target to the turf in range."
nonabstract_req = 1
mobs_blacklist = list(/mob/living/brain, /mob/living/silicon/pai)
var/inner_tele_radius = 1
var/outer_tele_radius = 2
@@ -4,7 +4,7 @@
charge_max = 1200 //variable
cooldown_min = 0
level_max = 1
clothes_req = 0
clothes_req = NONE
action_icon = 'icons/mob/actions/actions_items.dmi'
action_icon_state = "voice_of_god"
var/command
@@ -13,9 +13,10 @@
var/list/spans = list("colossus","yell")
var/speech_sound = 'sound/magic/clockwork/invoke_general.ogg'
/obj/effect/proc_holder/spell/voice_of_god/can_cast(mob/user = usr)
/obj/effect/proc_holder/spell/voice_of_god/can_cast(mob/user = usr, skipcharge = FALSE, silent = TRUE)
if(!user.can_speak())
to_chat(user, "<span class='warning'>You are unable to speak!</span>")
if(!silent)
to_chat(user, "<span class='warning'>You are unable to speak!</span>")
return FALSE
return TRUE
+10 -19
View File
@@ -4,7 +4,6 @@
school = "evocation"
charge_max = 200
clothes_req = 1
invocation = "FORTI GY AMA"
invocation_type = "shout"
range = 7
@@ -38,7 +37,6 @@
school = "transmutation"
charge_max = 400
clothes_req = 1
invocation = "BIRUZ BENNAR"
invocation_type = "shout"
range = -1
@@ -58,7 +56,7 @@
school = "conjuration"
charge_max = 120
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = -1
@@ -77,7 +75,7 @@
school = "conjuration"
charge_max = 360
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = -1
@@ -92,7 +90,6 @@
name = "Disable Tech"
desc = "This spell disables all weapons, cameras and most other technology in range."
charge_max = 400
clothes_req = 1
invocation = "NEC CANTIO"
invocation_type = "shout"
range = -1
@@ -109,7 +106,6 @@
school = "abjuration"
charge_max = 20
clothes_req = 1
invocation = "none"
invocation_type = "none"
range = -1
@@ -131,8 +127,7 @@
name = "quickstep"
charge_max = 100
clothes_req = 0
cult_req = 1
clothes_req = SPELL_CULT_GARB
/obj/effect/proc_holder/spell/targeted/area_teleport/teleport
name = "Teleport"
@@ -140,7 +135,6 @@
school = "abjuration"
charge_max = 600
clothes_req = 1
invocation = "SCYAR NILA"
invocation_type = "shout"
range = -1
@@ -156,7 +150,6 @@
name = "Stop Time"
desc = "This spell stops time for everyone except for you, allowing you to move freely while your enemies and even projectiles are frozen."
charge_max = 500
clothes_req = 1
invocation = "TOKI YO TOMARE"
invocation_type = "shout"
range = 0
@@ -174,7 +167,6 @@
school = "conjuration"
charge_max = 1200
clothes_req = 1
invocation = "NOUK FHUNMM SACP RISSKA"
invocation_type = "shout"
range = 1
@@ -189,7 +181,7 @@
school = "conjuration"
charge_max = 600
clothes_req = 0
clothes_req = NONE
invocation = "none"
invocation_type = "none"
range = 0
@@ -206,7 +198,7 @@
school = "conjuration"
charge_max = 1200
clothes_req = 0
clothes_req = NONE
invocation = "IA IA"
invocation_type = "shout"
summon_amt = 10
@@ -221,7 +213,7 @@
school = "transmutation"
charge_max = 300
clothes_req = 0
clothes_req = NONE
invocation = "STI KALY"
invocation_type = "whisper"
message = "<span class='notice'>Your eyes cry out in pain!</span>"
@@ -233,7 +225,7 @@
/obj/effect/proc_holder/spell/aoe_turf/conjure/creature/cult
name = "Summon Creatures (DANGEROUS)"
cult_req = 1
clothes_req = SPELL_CULT_GARB
charge_max = 5000
summon_amt = 2
@@ -253,7 +245,6 @@
name = "Repulse"
desc = "This spell throws everything around the user away."
charge_max = 400
clothes_req = 1
invocation = "GITTAH WEIGH"
invocation_type = "shout"
range = 5
@@ -314,7 +305,7 @@
desc = "Throw back attackers with a sweep of your tail."
sound = 'sound/magic/tail_swing.ogg'
charge_max = 150
clothes_req = 0
clothes_req = NONE
range = 2
cooldown_min = 150
invocation_type = "none"
@@ -335,7 +326,7 @@
name = "Sacred Flame"
desc = "Makes everyone around you more flammable, and lights yourself on fire."
charge_max = 60
clothes_req = 0
clothes_req = NONE
invocation = "FI'RAN DADISKO"
invocation_type = "shout"
max_targets = 0
@@ -358,7 +349,7 @@
/obj/effect/proc_holder/spell/targeted/conjure_item/spellpacket
name = "Thrown Lightning"
desc = "Forged from eldrich energies, a packet of pure power, known as a spell packet will appear in your hand, that when thrown will stun the target."
clothes_req = 1
clothes_req = SPELL_WIZARD_GARB
item_type = /obj/item/spellpacket/lightningbolt
charge_max = 10
+109 -26
View File
@@ -40,11 +40,22 @@
. = ..()
/obj/vehicle/ridden/scooter/skateboard
name = "skateboard"
desc = "An unfinished scooter which can only barely be called a skateboard. It's still rideable, but probably unsafe. Looks like you'll need to add a few rods to make handlebars. Alt-click to adjust speed."
name = "improvised skateboard"
desc = "An unfinished scooter which can only barely be called a skateboard. It's still rideable, but probably unsafe. Looks like you'll need to add a few rods to make handlebars."
icon_state = "skateboard"
density = FALSE
var/adjusted_speed = FALSE
arms_required = 0
var/datum/effect_system/spark_spread/sparks
///Whether the board is currently grinding
var/grinding = FALSE
///Stores the time of the last crash plus a short cooldown, affects availability and outcome of certain actions
var/next_crash
///Stores the default icon state
var/board_icon = "skateboard"
///The handheld item counterpart for the board
var/board_item_type = /obj/item/melee/skateboard
///Stamina drain multiplier
var/instability = 10
/obj/vehicle/ridden/scooter/skateboard/Initialize()
. = ..()
@@ -54,6 +65,23 @@
D.set_vehicle_dir_layer(NORTH, OBJ_LAYER)
D.set_vehicle_dir_layer(EAST, OBJ_LAYER)
D.set_vehicle_dir_layer(WEST, OBJ_LAYER)
sparks = new
sparks.set_up(1, 0, src)
sparks.attach(src)
/obj/vehicle/ridden/scooter/skateboard/Destroy()
if(sparks)
QDEL_NULL(sparks)
. = ..()
/obj/vehicle/ridden/scooter/skateboard/relaymove()
if (grinding || world.time < next_crash)
return FALSE
return ..()
/obj/vehicle/ridden/scooter/skateboard/generate_actions()
. = ..()
initialize_controller_action_type(/datum/action/vehicle/ridden/scooter/skateboard/ollie, VEHICLE_CONTROL_DRIVE)
/obj/vehicle/ridden/scooter/skateboard/post_buckle_mob(mob/living/M)//allows skateboards to be non-dense but still allows 2 skateboarders to collide with each other
density = TRUE
@@ -68,17 +96,52 @@
. = ..()
if(A.density && has_buckled_mobs())
var/mob/living/H = buckled_mobs[1]
var/atom/throw_target = get_edge_target_turf(H, pick(GLOB.cardinals))
unbuckle_mob(H)
H.throw_at(throw_target, 4, 3)
H.DefaultCombatKnockdown(100)
H.adjustStaminaLoss(40)
var/head_slot = H.get_item_by_slot(SLOT_HEAD)
if(!head_slot || !(istype(head_slot,/obj/item/clothing/head/helmet) || istype(head_slot,/obj/item/clothing/head/hardhat)))
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3)
H.updatehealth()
visible_message("<span class='danger'>[src] crashes into [A], sending [H] flying!</span>")
playsound(src, 'sound/effects/bang.ogg', 50, 1)
H.adjustStaminaLoss(instability*6)
playsound(src, 'sound/effects/bang.ogg', 40, TRUE)
if(!iscarbon(H) || H.getStaminaLoss() >= 100 || grinding || world.time < next_crash)
var/atom/throw_target = get_edge_target_turf(H, pick(GLOB.cardinals))
unbuckle_mob(H)
H.throw_at(throw_target, 3, 2)
var/head_slot = H.get_item_by_slot(SLOT_HEAD)
if(!head_slot || !(istype(head_slot,/obj/item/clothing/head/helmet) || istype(head_slot,/obj/item/clothing/head/hardhat)))
H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5)
H.updatehealth()
visible_message("<span class='danger'>[src] crashes into [A], sending [H] flying!</span>")
H.Knockdown(80)
else
var/backdir = turn(dir, 180)
vehicle_move(backdir)
H.spin(4, 1)
next_crash = world.time + 10
///Moves the vehicle forward and if it lands on a table, repeats
/obj/vehicle/ridden/scooter/skateboard/proc/grind()
vehicle_move(dir)
if(has_buckled_mobs() && locate(/obj/structure/table) in loc.contents)
var/mob/living/L = buckled_mobs[1]
L.adjustStaminaLoss(instability*0.5)
if (L.getStaminaLoss() >= 100)
playsound(src, 'sound/effects/bang.ogg', 20, TRUE)
unbuckle_mob(L)
var/atom/throw_target = get_edge_target_turf(src, pick(GLOB.cardinals))
L.throw_at(throw_target, 2, 2)
visible_message("<span class='danger'>[L] loses [L.p_their()] footing and slams on the ground!</span>")
L.Knockdown(40)
grinding = FALSE
icon_state = board_icon
return
else
playsound(src, 'sound/vehicles/skateboard_roll.ogg', 50, TRUE)
if(prob (25))
var/turf/location = get_turf(loc)
if(location)
location.hotspot_expose(1000,1000)
sparks.start() //the most radical way to start plasma fires
addtimer(CALLBACK(src, .proc/grind), 2)
return
else
grinding = FALSE
icon_state = board_icon
/obj/vehicle/ridden/scooter/skateboard/MouseDrop(atom/over_object)
. = ..()
@@ -89,22 +152,42 @@
to_chat(M, "<span class='warning'>You can't lift this up when somebody's on it.</span>")
return
if(over_object == M)
var/obj/item/melee/skateboard/board = new /obj/item/melee/skateboard()
var/board = new board_item_type(get_turf(M))
M.put_in_hands(board)
qdel(src)
/obj/vehicle/ridden/scooter/skateboard/AltClick(mob/user)
. = ..()
var/datum/component/riding/R = src.GetComponent(/datum/component/riding)
if (!adjusted_speed)
R.vehicle_move_delay = 0
to_chat(user, "<span class='notice'>You adjust the wheels on [src] to make it go faster.</span>")
adjusted_speed = TRUE
/obj/vehicle/ridden/scooter/skateboard/pro
name = "skateboard"
desc = "A RaDSTORMz brand professional skateboard. Looks a lot more stable than the average board."
icon_state = "skateboard2"
board_icon = "skateboard2"
board_item_type = /obj/item/melee/skateboard/pro
instability = 6
/obj/vehicle/ridden/scooter/skateboard/hoverboard/
name = "hoverboard"
desc = "A blast from the past, so retro!"
board_item_type = /obj/item/melee/skateboard/hoverboard
instability = 3
icon_state = "hoverboard_red"
board_icon = "hoverboard_red"
/obj/vehicle/ridden/scooter/skateboard/hoverboard/screwdriver_act(mob/living/user, obj/item/I)
return FALSE
/obj/vehicle/ridden/scooter/skateboard/hoverboard/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/stack/rods))
return
else
R.vehicle_move_delay = 1
to_chat(user, "<span class='notice'>You adjust the wheels on [src] to make it go slower.</span>")
adjusted_speed = FALSE
return TRUE
return ..()
/obj/vehicle/ridden/scooter/skateboard/hoverboard/admin
name = "\improper Board Of Directors"
desc = "The engineering complexity of a spaceship concentrated inside of a board. Just as expensive, too."
board_item_type = /obj/item/melee/skateboard/hoverboard/admin
instability = 0
icon_state = "hoverboard_nt"
board_icon = "hoverboard_nt"
//CONSTRUCTION
/obj/item/scooter_frame
+38
View File
@@ -164,3 +164,41 @@
if(istype(vehicle_entered_target, /obj/vehicle/sealed/car/clowncar))
var/obj/vehicle/sealed/car/clowncar/C = vehicle_entered_target
C.RollTheDice(owner)
/datum/action/vehicle/ridden/scooter/skateboard/ollie
name = "Ollie"
desc = "Get some air! Land on a table to do a gnarly grind."
button_icon_state = "skateboard_ollie"
///Cooldown to next jump
var/next_ollie
/datum/action/vehicle/ridden/scooter/skateboard/ollie/Trigger()
if(world.time > next_ollie)
var/obj/vehicle/ridden/scooter/skateboard/V = vehicle_target
if (V.grinding)
return
var/mob/living/L = owner
var/turf/landing_turf = get_step(V.loc, V.dir)
L.adjustStaminaLoss(V.instability*2)
if (L.getStaminaLoss() >= 100)
playsound(src, 'sound/effects/bang.ogg', 20, TRUE)
V.unbuckle_mob(L)
L.throw_at(landing_turf, 2, 2)
L.Knockdown(40)
V.visible_message("<span class='danger'>[L] misses the landing and falls on [L.p_their()] face!</span>")
else
L.spin(4, 1)
animate(L, pixel_y = -6, time = 4)
animate(V, pixel_y = -6, time = 3)
playsound(V, 'sound/vehicles/skateboard_ollie.ogg', 50, TRUE)
passtable_on(L, VEHICLE_TRAIT)
V.pass_flags |= PASSTABLE
L.Move(landing_turf, vehicle_target.dir)
passtable_off(L, VEHICLE_TRAIT)
V.pass_flags &= ~PASSTABLE
if(locate(/obj/structure/table) in V.loc.contents)
V.grinding = TRUE
V.icon_state = "[V.board_icon]-grind"
addtimer(CALLBACK(V, /obj/vehicle/ridden/scooter/skateboard/.proc/grind), 2)
next_ollie = world.time + 5
+2
View File
@@ -8,6 +8,8 @@
/obj/item/toy/cards/deck/cas = 3,
/obj/item/toy/cards/deck/cas/black = 3)
contraband = list(/obj/item/dice/fudge = 9)
premium = list(/obj/item/melee/skateboard/pro = 3,
/obj/item/melee/skateboard/hoverboard = 1)
refill_canister = /obj/item/vending_refill/games
/obj/item/vending_refill/games
+166 -172
View File
@@ -60,187 +60,181 @@
var/sound/pred_digest = sound(get_sfx("digest_pred"))
var/sound/pred_death = sound(get_sfx("death_pred"))
///////////////////////////// DM_HOLD /////////////////////////////
if(digest_mode == DM_HOLD)
return SSBELLIES_PROCESSED
switch(digest_mode)
if(DM_HOLD)
return SSBELLIES_PROCESSED
//////////////////////////// DM_DIGEST ////////////////////////////
else if(digest_mode == DM_DIGEST)
if(HAS_TRAIT(owner, TRAIT_PACIFISM)) //obvious.
digest_mode = DM_NOISY
return
if(DM_DIGEST)
if(HAS_TRAIT(owner, TRAIT_PACIFISM)) //obvious.
digest_mode = DM_NOISY
return
for (var/mob/living/M in contents)
if(prob(25))
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_digest)
play_sound = pick(pred_digest)
for (var/mob/living/M in contents)
if(prob(25))
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_digest)
play_sound = pick(pred_digest)
//Pref protection!
if (!M.digestable || M.absorbed)
continue
//Pref protection!
if (!M.digestable || M.absorbed)
continue
//Person just died in guts!
if(M.stat == DEAD)
var/digest_alert_owner = pick(digest_messages_owner)
var/digest_alert_prey = pick(digest_messages_prey)
//Replace placeholder vars
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
//Send messages
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
M.visible_message("<span class='notice'>You watch as [owner]'s form loses its additions.</span>")
owner.nutrition += 400 // so eating dead mobs gives you *something*.
play_sound = pick(pred_death)
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_death)
M.stop_sound_channel(CHANNEL_PREYLOOP)
digestion_death(M)
owner.update_icons()
to_update = TRUE
continue
// Deal digestion damage (and feed the pred)
if(!(M.status_flags & GODMODE))
M.adjustFireLoss(digest_burn)
owner.nutrition += 1
//Contaminate or gurgle items
var/obj/item/T = pick(touchable_items)
if(istype(T))
if(istype(T,/obj/item/reagent_containers/food) || istype(T,/obj/item/organ))
digest_item(T)
if(DM_HEAL)
for (var/mob/living/M in contents)
if(prob(25))
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_digest)
play_sound = pick(pred_digest)
if(M.stat != DEAD)
if(owner.nutrition >= NUTRITION_LEVEL_STARVING && (M.health < M.maxHealth))
M.adjustBruteLoss(-3)
M.adjustFireLoss(-3)
owner.nutrition -= 5
//for when you just want people to squelch around
if(DM_NOISY)
if(prob(35))
for(var/mob/M in contents)
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_digest)
play_sound = pick(pred_digest)
if(DM_ABSORB)
for (var/mob/living/M in contents)
if(prob(10))//Less often than gurgles. People might leave this on forever.
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_digest)
play_sound = pick(pred_digest)
if(M.absorbed)
continue
if(M.nutrition >= 100) //Drain them until there's no nutrients left. Slowly "absorb" them.
var/oldnutrition = (M.nutrition * 0.05)
M.nutrition = (M.nutrition * 0.95)
owner.nutrition += oldnutrition
else if(M.nutrition < 100) //When they're finally drained.
absorb_living(M)
to_update = TRUE
if(DM_UNABSORB)
for (var/mob/living/M in contents)
if(M.absorbed && owner.nutrition >= 100)
M.absorbed = FALSE
to_chat(M,"<span class='notice'>You suddenly feel solid again </span>")
to_chat(owner,"<span class='notice'>You feel like a part of you is missing.</span>")
owner.nutrition -= 100
to_update = TRUE
//because dragons need snowflake guts
if(DM_DRAGON)
if(HAS_TRAIT(owner, TRAIT_PACIFISM)) //imagine var editing this when you're a pacifist. smh
digest_mode = DM_NOISY
return
for (var/mob/living/M in contents)
if(prob(55)) //if you're hearing this, you're a vore ho anyway.
if((world.time + NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
for(var/mob/living/H in get_hearers_in_view(3, owner))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
for(var/mob/living/H in hearing_mobs)
if(H && H.client && (isturf(H.loc) || (H.loc != src.contents)))
SEND_SOUND(H,pred_digest)
else if(H?.client && (H in contents))
SEND_SOUND(H,prey_digest)
//No digestion protection for megafauna.
//Person just died in guts!
if(M.stat == DEAD)
var/digest_alert_owner = pick(digest_messages_owner)
var/digest_alert_prey = pick(digest_messages_prey)
if(M.stat == DEAD)
var/digest_alert_owner = pick(digest_messages_owner)
var/digest_alert_prey = pick(digest_messages_prey)
//Replace placeholder vars
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
//Replace placeholder vars
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
//Send messages
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
M.visible_message("<span class='notice'>You watch as [owner]'s form loses its additions.</span>")
owner.nutrition += 400 // so eating dead mobs gives you *something*.
play_sound = pick(pred_death)
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_death)
M.stop_sound_channel(CHANNEL_PREYLOOP)
digestion_death(M)
owner.update_icons()
to_update = TRUE
continue
//Send messages
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
M.visible_message("<span class='notice'>You watch as [owner]'s guts loudly rumble as it finishes off a meal.</span>")
play_sound = pick(pred_death)
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_death)
M.spill_organs(FALSE,TRUE,TRUE)
M.stop_sound_channel(CHANNEL_PREYLOOP)
digestion_death(M)
owner.update_icons()
to_update = TRUE
continue
// Deal digestion damage (and feed the pred)
if(!(M.status_flags & GODMODE))
M.adjustFireLoss(digest_burn)
owner.nutrition += 1
// Deal digestion damage (and feed the pred)
if(!(M.status_flags & GODMODE))
M.adjustFireLoss(digest_burn)
M.adjustToxLoss(2) // something something plasma based acids
M.adjustCloneLoss(1) // eventually this'll kill you if you're healing everything else, you nerds.
//Contaminate or gurgle items
var/obj/item/T = pick(touchable_items)
if(istype(T))
if(istype(T,/obj/item/reagent_containers/food) || istype(T,/obj/item/organ))
digest_item(T)
//Contaminate or gurgle items
var/obj/item/T = pick(touchable_items)
if(istype(T))
if(istype(T,/obj/item/reagent_containers/food) || istype(T,/obj/item/organ))
digest_item(T)
///////////////////////////// DM_HEAL /////////////////////////////
if(digest_mode == DM_HEAL)
for (var/mob/living/M in contents)
if(prob(25))
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_digest)
play_sound = pick(pred_digest)
if(M.stat != DEAD)
if(owner.nutrition >= NUTRITION_LEVEL_STARVING && (M.health < M.maxHealth))
M.adjustBruteLoss(-3)
M.adjustFireLoss(-3)
owner.nutrition -= 5
////////////////////////// DM_NOISY /////////////////////////////////
//for when you just want people to squelch around
if(digest_mode == DM_NOISY)
if(prob(35))
for(var/mob/M in contents)
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_digest)
play_sound = pick(pred_digest)
//////////////////////////// DM_ABSORB ////////////////////////////
else if(digest_mode == DM_ABSORB)
for (var/mob/living/M in contents)
if(prob(10))//Less often than gurgles. People might leave this on forever.
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_digest)
play_sound = pick(pred_digest)
if(M.absorbed)
continue
if(M.nutrition >= 100) //Drain them until there's no nutrients left. Slowly "absorb" them.
var/oldnutrition = (M.nutrition * 0.05)
M.nutrition = (M.nutrition * 0.95)
owner.nutrition += oldnutrition
else if(M.nutrition < 100) //When they're finally drained.
absorb_living(M)
to_update = TRUE
//////////////////////////// DM_UNABSORB ////////////////////////////
else if(digest_mode == DM_UNABSORB)
for (var/mob/living/M in contents)
if(M.absorbed && owner.nutrition >= 100)
M.absorbed = FALSE
to_chat(M,"<span class='notice'>You suddenly feel solid again </span>")
to_chat(owner,"<span class='notice'>You feel like a part of you is missing.</span>")
owner.nutrition -= 100
to_update = TRUE
//////////////////////////DM_DRAGON /////////////////////////////////////
//because dragons need snowflake guts
if(digest_mode == DM_DRAGON)
if(HAS_TRAIT(owner, TRAIT_PACIFISM)) //imagine var editing this when you're a pacifist. smh
digest_mode = DM_NOISY
return
for (var/mob/living/M in contents)
if(prob(55)) //if you're hearing this, you're a vore ho anyway.
if((world.time + NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
for(var/mob/living/H in get_hearers_in_view(3, owner))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
for(var/mob/living/H in hearing_mobs)
if(H && H.client && (isturf(H.loc) || (H.loc != src.contents)))
SEND_SOUND(H,pred_digest)
else if(H?.client && (H in contents))
SEND_SOUND(H,prey_digest)
//No digestion protection for megafauna.
//Person just died in guts!
if(M.stat == DEAD)
var/digest_alert_owner = pick(digest_messages_owner)
var/digest_alert_prey = pick(digest_messages_prey)
//Replace placeholder vars
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
//Send messages
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
M.visible_message("<span class='notice'>You watch as [owner]'s guts loudly rumble as it finishes off a meal.</span>")
play_sound = pick(pred_death)
if(M && M.client && M.client.prefs.cit_toggles & DIGESTION_NOISES)
SEND_SOUND(M,prey_death)
M.spill_organs(FALSE,TRUE,TRUE)
M.stop_sound_channel(CHANNEL_PREYLOOP)
digestion_death(M)
owner.update_icons()
to_update = TRUE
continue
// Deal digestion damage (and feed the pred)
if(!(M.status_flags & GODMODE))
M.adjustFireLoss(digest_burn)
M.adjustToxLoss(2) // something something plasma based acids
M.adjustCloneLoss(1) // eventually this'll kill you if you're healing everything else, you nerds.
//Contaminate or gurgle items
var/obj/item/T = pick(touchable_items)
if(istype(T))
if(istype(T,/obj/item/reagent_containers/food) || istype(T,/obj/item/organ))
digest_item(T)
/////////////////////////// Make any noise ///////////////////////////
/////////////////////////// Make any noise ///////////////////////////
if(play_sound)
if((world.time + NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
@@ -252,7 +246,7 @@
for(var/mob/M in hearing_mobs) //so we don't fill the whole room with the sound effect
if(M && M.client && (isturf(M.loc) || (M.loc != src.contents))) //to avoid people on the inside getting the outside sounds and their direct sounds + built in sound pref check
M.playsound_local(owner.loc, play_sound, vol = 75, vary = 1, falloff = VORE_SOUND_FALLOFF)
//these are all external sound triggers now, so it's ok.
//these are all external sound triggers now, so it's ok.
if(to_update)
for(var/mob/living/M in contents)
if(M.client)
@@ -260,4 +254,4 @@
if(owner.client)
owner.updateVRPanel()
return SSBELLIES_PROCESSED
return SSBELLIES_PROCESSED