[MIRROR] Manifest Spirit is better for summoning cannon fodder but slightly worse for instantly summoning Nar-Sie (#916)
* Manifest Spirit is better for summoning cannon fodder but slightly worse for instantly summoning Nar-Sie * fixes .rej
This commit is contained in:
committed by
Poojawa
parent
30279b7f55
commit
a317d23a51
@@ -38,3 +38,5 @@
|
||||
#define MANIA_DAMAGE_TO_CONVERT 90 //how much damage is required before it'll convert affected targets
|
||||
|
||||
#define STATUS_EFFECT_HISWRATH /datum/status_effect/his_wrath //His Wrath.
|
||||
|
||||
#define STATUS_EFFECT_SUMMONEDGHOST /datum/status_effect/cultghost //is a cult ghost and can't use manifest runes
|
||||
+491
-491
@@ -1,491 +1,491 @@
|
||||
/*
|
||||
* Holds procs to help with list operations
|
||||
* Contains groups:
|
||||
* Misc
|
||||
* Sorting
|
||||
*/
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
|
||||
//Returns a list in plain english as a string
|
||||
/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
|
||||
var/total = input.len
|
||||
if (!total)
|
||||
return "[nothing_text]"
|
||||
else if (total == 1)
|
||||
return "[input[1]]"
|
||||
else if (total == 2)
|
||||
return "[input[1]][and_text][input[2]]"
|
||||
else
|
||||
var/output = ""
|
||||
var/index = 1
|
||||
while (index < total)
|
||||
if (index == total - 1)
|
||||
comma_text = final_comma_text
|
||||
|
||||
output += "[input[index]][comma_text]"
|
||||
index++
|
||||
|
||||
return "[output][and_text][input[index]]"
|
||||
|
||||
//Returns list element or null. Should prevent "index out of bounds" error.
|
||||
/proc/listgetindex(list/L, index)
|
||||
if(istype(L))
|
||||
if(isnum(index) && IsInteger(index))
|
||||
if(IsInRange(index,1,L.len))
|
||||
return L[index]
|
||||
else if(index in L)
|
||||
return L[index]
|
||||
return
|
||||
|
||||
//Return either pick(list) or null if list is not of type /list or is empty
|
||||
/proc/safepick(list/L)
|
||||
if(istype(L) && L.len)
|
||||
return pick(L)
|
||||
|
||||
//Checks if the list is empty
|
||||
/proc/isemptylist(list/L)
|
||||
if(!L.len)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Checks for specific types in a list
|
||||
/proc/is_type_in_list(atom/A, list/L)
|
||||
if(!L || !L.len || !A)
|
||||
return 0
|
||||
for(var/type in L)
|
||||
if(istype(A, type))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Checks for specific types in specifically structured (Assoc "type" = TRUE) lists ('typecaches')
|
||||
/proc/is_type_in_typecache(atom/A, list/L)
|
||||
if(!L || !L.len || !A)
|
||||
|
||||
return 0
|
||||
if(ispath(A))
|
||||
. = L[A]
|
||||
else
|
||||
. = L[A.type]
|
||||
|
||||
//Checks for a string in a list
|
||||
/proc/is_string_in_list(string, list/L)
|
||||
if(!L || !L.len || !string)
|
||||
return
|
||||
for(var/V in L)
|
||||
if(string == V)
|
||||
return 1
|
||||
return
|
||||
|
||||
//Removes a string from a list
|
||||
/proc/remove_strings_from_list(string, list/L)
|
||||
if(!L || !L.len || !string)
|
||||
return
|
||||
for(var/V in L)
|
||||
if(V == string)
|
||||
L -= V //No return here so that it removes all strings of that type
|
||||
return
|
||||
|
||||
//returns a new list with only atoms that are in typecache L
|
||||
/proc/typecache_filter_list(list/atoms, list/typecache)
|
||||
. = list()
|
||||
for (var/thing in atoms)
|
||||
var/atom/A = thing
|
||||
if (typecache[A.type])
|
||||
. += A
|
||||
|
||||
//Like typesof() or subtypesof(), but returns a typecache instead of a list
|
||||
/proc/typecacheof(path, ignore_root_path, only_root_path = FALSE)
|
||||
if(ispath(path))
|
||||
var/list/types = list()
|
||||
if(only_root_path)
|
||||
types = list(path)
|
||||
else
|
||||
types = ignore_root_path ? subtypesof(path) : typesof(path)
|
||||
var/list/L = list()
|
||||
for(var/T in types)
|
||||
L[T] = TRUE
|
||||
return L
|
||||
else if(islist(path))
|
||||
var/list/pathlist = path
|
||||
var/list/L = list()
|
||||
if(ignore_root_path)
|
||||
for(var/P in pathlist)
|
||||
for(var/T in subtypesof(P))
|
||||
L[T] = TRUE
|
||||
else
|
||||
for(var/P in pathlist)
|
||||
if(only_root_path)
|
||||
L[P] = TRUE
|
||||
else
|
||||
for(var/T in typesof(P))
|
||||
L[T] = TRUE
|
||||
return L
|
||||
|
||||
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected
|
||||
/proc/clearlist(list/list)
|
||||
if(istype(list))
|
||||
list.len = 0
|
||||
return
|
||||
|
||||
//Removes any null entries from the list
|
||||
/proc/listclearnulls(list/L)
|
||||
var/list/N = new(L.len)
|
||||
L -= N
|
||||
|
||||
/*
|
||||
* Returns list containing all the entries from first list that are not present in second.
|
||||
* If skiprep = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/difflist(list/first, list/second, skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
for(var/e in first)
|
||||
if(!(e in result) && !(e in second))
|
||||
result += e
|
||||
else
|
||||
result = first - second
|
||||
return result
|
||||
|
||||
/*
|
||||
* Returns list containing entries that are in either list but not both.
|
||||
* If skipref = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/uniquemergelist(list/first, list/second, skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
result = difflist(first, second, skiprep)+difflist(second, first, skiprep)
|
||||
else
|
||||
result = first ^ second
|
||||
return result
|
||||
|
||||
//Pretends to pick an element based on its weight but really just seems to pick a random element.
|
||||
/proc/pickweight(list/L)
|
||||
var/total = 0
|
||||
var/item
|
||||
for (item in L)
|
||||
if (!L[item])
|
||||
L[item] = 1
|
||||
total += L[item]
|
||||
|
||||
total = rand(1, total)
|
||||
for (item in L)
|
||||
total -=L [item]
|
||||
if (total <= 0)
|
||||
return item
|
||||
|
||||
return null
|
||||
|
||||
//Pick a random element from the list and remove it from the list.
|
||||
/proc/pick_n_take(list/L)
|
||||
if(L.len)
|
||||
var/picked = rand(1,L.len)
|
||||
. = L[picked]
|
||||
L.Cut(picked,picked+1) //Cut is far more efficient that Remove()
|
||||
|
||||
//Returns the top(last) element from the list and removes it from the list (typical stack function)
|
||||
/proc/pop(list/L)
|
||||
if(L.len)
|
||||
. = L[L.len]
|
||||
L.len--
|
||||
|
||||
/proc/popleft(list/L)
|
||||
if(L.len)
|
||||
. = L[1]
|
||||
L.Cut(1,2)
|
||||
|
||||
/proc/sorted_insert(list/L, thing, comparator)
|
||||
var/pos = L.len
|
||||
while(pos > 0 && call(comparator)(thing, L[pos]) > 0)
|
||||
pos--
|
||||
L.Insert(pos+1, thing)
|
||||
|
||||
// Returns the next item in a list
|
||||
/proc/next_list_item(item, list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == L.len)
|
||||
i = 1
|
||||
else
|
||||
i++
|
||||
return L[i]
|
||||
|
||||
// Returns the previous item in a list
|
||||
/proc/previous_list_item(item, list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == 1)
|
||||
i = L.len
|
||||
else
|
||||
i--
|
||||
return L[i]
|
||||
|
||||
//Randomize: Return the list in a random order
|
||||
/proc/shuffle(list/L)
|
||||
if(!L)
|
||||
return
|
||||
L = L.Copy()
|
||||
|
||||
for(var/i=1, i<L.len, ++i)
|
||||
L.Swap(i,rand(i,L.len))
|
||||
|
||||
return L
|
||||
|
||||
//same, but returns nothing and acts on list in place
|
||||
/proc/shuffle_inplace(list/L)
|
||||
if(!L)
|
||||
return
|
||||
|
||||
for(var/i=1, i<L.len, ++i)
|
||||
L.Swap(i,rand(i,L.len))
|
||||
|
||||
//Return a list with no duplicate entries
|
||||
/proc/uniqueList(list/L)
|
||||
. = list()
|
||||
for(var/i in L)
|
||||
. |= i
|
||||
|
||||
//same, but returns nothing and acts on list in place (also handles associated values properly)
|
||||
/proc/uniqueList_inplace(list/L)
|
||||
var/temp = L.Copy()
|
||||
L.len = 0
|
||||
for(var/key in temp)
|
||||
if (isnum(key))
|
||||
L |= key
|
||||
else
|
||||
L[key] = temp[key]
|
||||
|
||||
//for sorting clients or mobs by ckey
|
||||
/proc/sortKey(list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_ckey_asc : /proc/cmp_ckey_dsc)
|
||||
|
||||
//Specifically for record datums in a list.
|
||||
/proc/sortRecord(list/L, field = "name", order = 1)
|
||||
GLOB.cmp_field = field
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_records_asc : /proc/cmp_records_dsc)
|
||||
|
||||
//any value in a list
|
||||
/proc/sortList(list/L, cmp=/proc/cmp_text_asc)
|
||||
return sortTim(L.Copy(), cmp)
|
||||
|
||||
//uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead
|
||||
/proc/sortNames(list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc)
|
||||
|
||||
|
||||
//Converts a bitfield to a list of numbers (or words if a wordlist is provided)
|
||||
/proc/bitfield2list(bitfield = 0, list/wordlist)
|
||||
var/list/r = list()
|
||||
if(istype(wordlist,/list))
|
||||
var/max = min(wordlist.len,16)
|
||||
var/bit = 1
|
||||
for(var/i=1, i<=max, i++)
|
||||
if(bitfield & bit)
|
||||
r += wordlist[i]
|
||||
bit = bit << 1
|
||||
else
|
||||
for(var/bit=1, bit<=65535, bit = bit << 1)
|
||||
if(bitfield & bit)
|
||||
r += bit
|
||||
|
||||
return r
|
||||
|
||||
// Returns the key based on the index
|
||||
#define KEYBYINDEX(L, index) (((index <= L:len) && (index > 0)) ? L[index] : null)
|
||||
|
||||
/proc/count_by_type(list/L, type)
|
||||
var/i = 0
|
||||
for(var/T in L)
|
||||
if(istype(T, type))
|
||||
i++
|
||||
return i
|
||||
|
||||
/proc/find_record(field, value, list/L)
|
||||
for(var/datum/data/record/R in L)
|
||||
if(R.fields[field] == value)
|
||||
return R
|
||||
|
||||
|
||||
//Move a single element from position fromIndex within a list, to position toIndex
|
||||
//All elements in the range [1,toIndex) before the move will be before the pivot afterwards
|
||||
//All elements in the range [toIndex, L.len+1) before the move will be after the pivot afterwards
|
||||
//In other words, it's as if the range [fromIndex,toIndex) have been rotated using a <<< operation common to other languages.
|
||||
//fromIndex and toIndex must be in the range [1,L.len+1]
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveElement(list/L, fromIndex, toIndex)
|
||||
if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move
|
||||
return
|
||||
if(fromIndex > toIndex)
|
||||
++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one
|
||||
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
|
||||
//Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex)
|
||||
//Same as moveElement but for ranges of elements
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements
|
||||
if(fromIndex <= toIndex)
|
||||
return //no need to move
|
||||
fromIndex += len //we want to shift left instead of right
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(fromIndex > toIndex)
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
//Move elements from [fromIndex, fromIndex+len) to [toIndex, toIndex+len)
|
||||
//Move any elements being overwritten by the move to the now-empty elements, preserving order
|
||||
//Note: if the two ranges overlap, only the destination order will be preserved fully, since some elements will be within both ranges ~Carnie
|
||||
/proc/swapRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len > distance) //there is an overlap, therefore swapping each element will require more swaps than inserting new elements
|
||||
if(fromIndex < toIndex)
|
||||
toIndex += len
|
||||
else
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(toIndex > fromIndex)
|
||||
var/a = toIndex
|
||||
toIndex = fromIndex
|
||||
fromIndex = a
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Swap(fromIndex++, toIndex++)
|
||||
|
||||
//replaces reverseList ~Carnie
|
||||
/proc/reverseRange(list/L, start=1, end=0)
|
||||
if(L.len)
|
||||
start = start % L.len
|
||||
end = end % (L.len+1)
|
||||
if(start <= 0)
|
||||
start += L.len
|
||||
if(end <= 0)
|
||||
end += L.len + 1
|
||||
|
||||
--end
|
||||
while(start < end)
|
||||
L.Swap(start++,end--)
|
||||
|
||||
return L
|
||||
|
||||
|
||||
//return first thing in L which has var/varname == value
|
||||
//this is typecaste as list/L, but you could actually feed it an atom instead.
|
||||
//completely safe to use
|
||||
/proc/getElementByVar(list/L, varname, value)
|
||||
varname = "[varname]"
|
||||
for(var/datum/D in L)
|
||||
if(D.vars.Find(varname))
|
||||
if(D.vars[varname] == value)
|
||||
return D
|
||||
|
||||
//remove all nulls from a list
|
||||
/proc/removeNullsFromList(list/L)
|
||||
while(L.Remove(null))
|
||||
continue
|
||||
return L
|
||||
|
||||
//Copies a list, and all lists inside it recusively
|
||||
//Does not copy any other reference type
|
||||
/proc/deepCopyList(list/l)
|
||||
if(!islist(l))
|
||||
return l
|
||||
. = l.Copy()
|
||||
for(var/i = 1 to l.len)
|
||||
if(islist(.[i]))
|
||||
.[i] = .(.[i])
|
||||
|
||||
//takes an input_key, as text, and the list of keys already used, outputting a replacement key in the format of "[input_key] ([number_of_duplicates])" if it finds a duplicate
|
||||
//use this for lists of things that might have the same name, like mobs or objects, that you plan on giving to a player as input
|
||||
/proc/avoid_assoc_duplicate_keys(input_key, list/used_key_list)
|
||||
if(!input_key || !istype(used_key_list))
|
||||
return
|
||||
if(used_key_list[input_key])
|
||||
used_key_list[input_key]++
|
||||
input_key = "[input_key] ([used_key_list[input_key]])"
|
||||
else
|
||||
used_key_list[input_key] = 1
|
||||
return input_key
|
||||
|
||||
#if DM_VERSION > 512
|
||||
#error Remie said that lummox was adding a way to get a lists
|
||||
#error contents via list.values, if that is true remove this
|
||||
#error otherwise, update the version and bug lummox
|
||||
#elseif
|
||||
//Flattens a keyed list into a list of it's contents
|
||||
/proc/flatten_list(list/key_list)
|
||||
if(!islist(key_list))
|
||||
return null
|
||||
. = list()
|
||||
for(var/key in key_list)
|
||||
. |= key_list[key]
|
||||
|
||||
//Picks from the list, with some safeties, and returns the "default" arg if it fails
|
||||
#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)
|
||||
|
||||
#define LAZYINITLIST(L) if (!L) L = list()
|
||||
|
||||
#define UNSETEMPTY(L) if (L && !L.len) L = null
|
||||
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
|
||||
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
|
||||
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
|
||||
#define LAZYLEN(L) length(L)
|
||||
#define LAZYCLEARLIST(L) if(L) L.Cut()
|
||||
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
|
||||
|
||||
/* Definining a counter as a series of key -> numeric value entries
|
||||
|
||||
* All these procs modify in place.
|
||||
*/
|
||||
|
||||
/proc/counterlist_scale(list/L, scalar)
|
||||
var/list/out = list()
|
||||
for(var/key in L)
|
||||
out[key] = L[key] * scalar
|
||||
. = out
|
||||
|
||||
/proc/counterlist_sum(list/L)
|
||||
. = 0
|
||||
for(var/key in L)
|
||||
. += L[key]
|
||||
|
||||
/proc/counterlist_normalise(list/L)
|
||||
var/avg = counterlist_sum(L)
|
||||
if(avg != 0)
|
||||
. = counterlist_scale(L, 1 / avg)
|
||||
else
|
||||
. = L
|
||||
|
||||
/proc/counterlist_combine(list/L1, list/L2)
|
||||
for(var/key in L2)
|
||||
var/other_value = L2[key]
|
||||
if(key in L1)
|
||||
L1[key] += other_value
|
||||
else
|
||||
L1[key] = other_value
|
||||
/*
|
||||
* Holds procs to help with list operations
|
||||
* Contains groups:
|
||||
* Misc
|
||||
* Sorting
|
||||
*/
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
|
||||
//Returns a list in plain english as a string
|
||||
/proc/english_list(list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
|
||||
var/total = input.len
|
||||
if (!total)
|
||||
return "[nothing_text]"
|
||||
else if (total == 1)
|
||||
return "[input[1]]"
|
||||
else if (total == 2)
|
||||
return "[input[1]][and_text][input[2]]"
|
||||
else
|
||||
var/output = ""
|
||||
var/index = 1
|
||||
while (index < total)
|
||||
if (index == total - 1)
|
||||
comma_text = final_comma_text
|
||||
|
||||
output += "[input[index]][comma_text]"
|
||||
index++
|
||||
|
||||
return "[output][and_text][input[index]]"
|
||||
|
||||
//Returns list element or null. Should prevent "index out of bounds" error.
|
||||
/proc/listgetindex(list/L, index)
|
||||
if(istype(L))
|
||||
if(isnum(index) && IsInteger(index))
|
||||
if(IsInRange(index,1,L.len))
|
||||
return L[index]
|
||||
else if(index in L)
|
||||
return L[index]
|
||||
return
|
||||
|
||||
//Return either pick(list) or null if list is not of type /list or is empty
|
||||
/proc/safepick(list/L)
|
||||
if(istype(L) && L.len)
|
||||
return pick(L)
|
||||
|
||||
//Checks if the list is empty
|
||||
/proc/isemptylist(list/L)
|
||||
if(!L.len)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Checks for specific types in a list
|
||||
/proc/is_type_in_list(atom/A, list/L)
|
||||
if(!L || !L.len || !A)
|
||||
return 0
|
||||
for(var/type in L)
|
||||
if(istype(A, type))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
//Checks for specific types in specifically structured (Assoc "type" = TRUE) lists ('typecaches')
|
||||
/proc/is_type_in_typecache(atom/A, list/L)
|
||||
if(!L || !L.len || !A)
|
||||
|
||||
return 0
|
||||
if(ispath(A))
|
||||
. = L[A]
|
||||
else
|
||||
. = L[A.type]
|
||||
|
||||
//Checks for a string in a list
|
||||
/proc/is_string_in_list(string, list/L)
|
||||
if(!L || !L.len || !string)
|
||||
return
|
||||
for(var/V in L)
|
||||
if(string == V)
|
||||
return 1
|
||||
return
|
||||
|
||||
//Removes a string from a list
|
||||
/proc/remove_strings_from_list(string, list/L)
|
||||
if(!L || !L.len || !string)
|
||||
return
|
||||
for(var/V in L)
|
||||
if(V == string)
|
||||
L -= V //No return here so that it removes all strings of that type
|
||||
return
|
||||
|
||||
//returns a new list with only atoms that are in typecache L
|
||||
/proc/typecache_filter_list(list/atoms, list/typecache)
|
||||
. = list()
|
||||
for (var/thing in atoms)
|
||||
var/atom/A = thing
|
||||
if (typecache[A.type])
|
||||
. += A
|
||||
|
||||
//Like typesof() or subtypesof(), but returns a typecache instead of a list
|
||||
/proc/typecacheof(path, ignore_root_path, only_root_path = FALSE)
|
||||
if(ispath(path))
|
||||
var/list/types = list()
|
||||
if(only_root_path)
|
||||
types = list(path)
|
||||
else
|
||||
types = ignore_root_path ? subtypesof(path) : typesof(path)
|
||||
var/list/L = list()
|
||||
for(var/T in types)
|
||||
L[T] = TRUE
|
||||
return L
|
||||
else if(islist(path))
|
||||
var/list/pathlist = path
|
||||
var/list/L = list()
|
||||
if(ignore_root_path)
|
||||
for(var/P in pathlist)
|
||||
for(var/T in subtypesof(P))
|
||||
L[T] = TRUE
|
||||
else
|
||||
for(var/P in pathlist)
|
||||
if(only_root_path)
|
||||
L[P] = TRUE
|
||||
else
|
||||
for(var/T in typesof(P))
|
||||
L[T] = TRUE
|
||||
return L
|
||||
|
||||
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected
|
||||
/proc/clearlist(list/list)
|
||||
if(istype(list))
|
||||
list.len = 0
|
||||
return
|
||||
|
||||
//Removes any null entries from the list
|
||||
/proc/listclearnulls(list/L)
|
||||
var/list/N = new(L.len)
|
||||
L -= N
|
||||
|
||||
/*
|
||||
* Returns list containing all the entries from first list that are not present in second.
|
||||
* If skiprep = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/difflist(list/first, list/second, skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
for(var/e in first)
|
||||
if(!(e in result) && !(e in second))
|
||||
result += e
|
||||
else
|
||||
result = first - second
|
||||
return result
|
||||
|
||||
/*
|
||||
* Returns list containing entries that are in either list but not both.
|
||||
* If skipref = 1, repeated elements are treated as one.
|
||||
* If either of arguments is not a list, returns null
|
||||
*/
|
||||
/proc/uniquemergelist(list/first, list/second, skiprep=0)
|
||||
if(!islist(first) || !islist(second))
|
||||
return
|
||||
var/list/result = new
|
||||
if(skiprep)
|
||||
result = difflist(first, second, skiprep)+difflist(second, first, skiprep)
|
||||
else
|
||||
result = first ^ second
|
||||
return result
|
||||
|
||||
//Pretends to pick an element based on its weight but really just seems to pick a random element.
|
||||
/proc/pickweight(list/L)
|
||||
var/total = 0
|
||||
var/item
|
||||
for (item in L)
|
||||
if (!L[item])
|
||||
L[item] = 1
|
||||
total += L[item]
|
||||
|
||||
total = rand(1, total)
|
||||
for (item in L)
|
||||
total -=L [item]
|
||||
if (total <= 0)
|
||||
return item
|
||||
|
||||
return null
|
||||
|
||||
//Pick a random element from the list and remove it from the list.
|
||||
/proc/pick_n_take(list/L)
|
||||
if(L.len)
|
||||
var/picked = rand(1,L.len)
|
||||
. = L[picked]
|
||||
L.Cut(picked,picked+1) //Cut is far more efficient that Remove()
|
||||
|
||||
//Returns the top(last) element from the list and removes it from the list (typical stack function)
|
||||
/proc/pop(list/L)
|
||||
if(L.len)
|
||||
. = L[L.len]
|
||||
L.len--
|
||||
|
||||
/proc/popleft(list/L)
|
||||
if(L.len)
|
||||
. = L[1]
|
||||
L.Cut(1,2)
|
||||
|
||||
/proc/sorted_insert(list/L, thing, comparator)
|
||||
var/pos = L.len
|
||||
while(pos > 0 && call(comparator)(thing, L[pos]) > 0)
|
||||
pos--
|
||||
L.Insert(pos+1, thing)
|
||||
|
||||
// Returns the next item in a list
|
||||
/proc/next_list_item(item, list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == L.len)
|
||||
i = 1
|
||||
else
|
||||
i++
|
||||
return L[i]
|
||||
|
||||
// Returns the previous item in a list
|
||||
/proc/previous_list_item(item, list/L)
|
||||
var/i
|
||||
i = L.Find(item)
|
||||
if(i == 1)
|
||||
i = L.len
|
||||
else
|
||||
i--
|
||||
return L[i]
|
||||
|
||||
//Randomize: Return the list in a random order
|
||||
/proc/shuffle(list/L)
|
||||
if(!L)
|
||||
return
|
||||
L = L.Copy()
|
||||
|
||||
for(var/i=1, i<L.len, ++i)
|
||||
L.Swap(i,rand(i,L.len))
|
||||
|
||||
return L
|
||||
|
||||
//same, but returns nothing and acts on list in place
|
||||
/proc/shuffle_inplace(list/L)
|
||||
if(!L)
|
||||
return
|
||||
|
||||
for(var/i=1, i<L.len, ++i)
|
||||
L.Swap(i,rand(i,L.len))
|
||||
|
||||
//Return a list with no duplicate entries
|
||||
/proc/uniqueList(list/L)
|
||||
. = list()
|
||||
for(var/i in L)
|
||||
. |= i
|
||||
|
||||
//same, but returns nothing and acts on list in place (also handles associated values properly)
|
||||
/proc/uniqueList_inplace(list/L)
|
||||
var/temp = L.Copy()
|
||||
L.len = 0
|
||||
for(var/key in temp)
|
||||
if (isnum(key))
|
||||
L |= key
|
||||
else
|
||||
L[key] = temp[key]
|
||||
|
||||
//for sorting clients or mobs by ckey
|
||||
/proc/sortKey(list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_ckey_asc : /proc/cmp_ckey_dsc)
|
||||
|
||||
//Specifically for record datums in a list.
|
||||
/proc/sortRecord(list/L, field = "name", order = 1)
|
||||
GLOB.cmp_field = field
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_records_asc : /proc/cmp_records_dsc)
|
||||
|
||||
//any value in a list
|
||||
/proc/sortList(list/L, cmp=/proc/cmp_text_asc)
|
||||
return sortTim(L.Copy(), cmp)
|
||||
|
||||
//uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead
|
||||
/proc/sortNames(list/L, order=1)
|
||||
return sortTim(L, order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc)
|
||||
|
||||
|
||||
//Converts a bitfield to a list of numbers (or words if a wordlist is provided)
|
||||
/proc/bitfield2list(bitfield = 0, list/wordlist)
|
||||
var/list/r = list()
|
||||
if(istype(wordlist,/list))
|
||||
var/max = min(wordlist.len,16)
|
||||
var/bit = 1
|
||||
for(var/i=1, i<=max, i++)
|
||||
if(bitfield & bit)
|
||||
r += wordlist[i]
|
||||
bit = bit << 1
|
||||
else
|
||||
for(var/bit=1, bit<=65535, bit = bit << 1)
|
||||
if(bitfield & bit)
|
||||
r += bit
|
||||
|
||||
return r
|
||||
|
||||
// Returns the key based on the index
|
||||
#define KEYBYINDEX(L, index) (((index <= L:len) && (index > 0)) ? L[index] : null)
|
||||
|
||||
/proc/count_by_type(list/L, type)
|
||||
var/i = 0
|
||||
for(var/T in L)
|
||||
if(istype(T, type))
|
||||
i++
|
||||
return i
|
||||
|
||||
/proc/find_record(field, value, list/L)
|
||||
for(var/datum/data/record/R in L)
|
||||
if(R.fields[field] == value)
|
||||
return R
|
||||
|
||||
|
||||
//Move a single element from position fromIndex within a list, to position toIndex
|
||||
//All elements in the range [1,toIndex) before the move will be before the pivot afterwards
|
||||
//All elements in the range [toIndex, L.len+1) before the move will be after the pivot afterwards
|
||||
//In other words, it's as if the range [fromIndex,toIndex) have been rotated using a <<< operation common to other languages.
|
||||
//fromIndex and toIndex must be in the range [1,L.len+1]
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveElement(list/L, fromIndex, toIndex)
|
||||
if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move
|
||||
return
|
||||
if(fromIndex > toIndex)
|
||||
++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one
|
||||
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
|
||||
//Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex)
|
||||
//Same as moveElement but for ranges of elements
|
||||
//This will preserve associations ~Carnie
|
||||
/proc/moveRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements
|
||||
if(fromIndex <= toIndex)
|
||||
return //no need to move
|
||||
fromIndex += len //we want to shift left instead of right
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(fromIndex > toIndex)
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Insert(toIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(fromIndex, fromIndex+1)
|
||||
|
||||
//Move elements from [fromIndex, fromIndex+len) to [toIndex, toIndex+len)
|
||||
//Move any elements being overwritten by the move to the now-empty elements, preserving order
|
||||
//Note: if the two ranges overlap, only the destination order will be preserved fully, since some elements will be within both ranges ~Carnie
|
||||
/proc/swapRange(list/L, fromIndex, toIndex, len=1)
|
||||
var/distance = abs(toIndex - fromIndex)
|
||||
if(len > distance) //there is an overlap, therefore swapping each element will require more swaps than inserting new elements
|
||||
if(fromIndex < toIndex)
|
||||
toIndex += len
|
||||
else
|
||||
fromIndex += len
|
||||
|
||||
for(var/i=0, i<distance, ++i)
|
||||
L.Insert(fromIndex, null)
|
||||
L.Swap(fromIndex, toIndex)
|
||||
L.Cut(toIndex, toIndex+1)
|
||||
else
|
||||
if(toIndex > fromIndex)
|
||||
var/a = toIndex
|
||||
toIndex = fromIndex
|
||||
fromIndex = a
|
||||
|
||||
for(var/i=0, i<len, ++i)
|
||||
L.Swap(fromIndex++, toIndex++)
|
||||
|
||||
//replaces reverseList ~Carnie
|
||||
/proc/reverseRange(list/L, start=1, end=0)
|
||||
if(L.len)
|
||||
start = start % L.len
|
||||
end = end % (L.len+1)
|
||||
if(start <= 0)
|
||||
start += L.len
|
||||
if(end <= 0)
|
||||
end += L.len + 1
|
||||
|
||||
--end
|
||||
while(start < end)
|
||||
L.Swap(start++,end--)
|
||||
|
||||
return L
|
||||
|
||||
|
||||
//return first thing in L which has var/varname == value
|
||||
//this is typecaste as list/L, but you could actually feed it an atom instead.
|
||||
//completely safe to use
|
||||
/proc/getElementByVar(list/L, varname, value)
|
||||
varname = "[varname]"
|
||||
for(var/datum/D in L)
|
||||
if(D.vars.Find(varname))
|
||||
if(D.vars[varname] == value)
|
||||
return D
|
||||
|
||||
//remove all nulls from a list
|
||||
/proc/removeNullsFromList(list/L)
|
||||
while(L.Remove(null))
|
||||
continue
|
||||
return L
|
||||
|
||||
//Copies a list, and all lists inside it recusively
|
||||
//Does not copy any other reference type
|
||||
/proc/deepCopyList(list/l)
|
||||
if(!islist(l))
|
||||
return l
|
||||
. = l.Copy()
|
||||
for(var/i = 1 to l.len)
|
||||
if(islist(.[i]))
|
||||
.[i] = .(.[i])
|
||||
|
||||
//takes an input_key, as text, and the list of keys already used, outputting a replacement key in the format of "[input_key] ([number_of_duplicates])" if it finds a duplicate
|
||||
//use this for lists of things that might have the same name, like mobs or objects, that you plan on giving to a player as input
|
||||
/proc/avoid_assoc_duplicate_keys(input_key, list/used_key_list)
|
||||
if(!input_key || !istype(used_key_list))
|
||||
return
|
||||
if(used_key_list[input_key])
|
||||
used_key_list[input_key]++
|
||||
input_key = "[input_key] ([used_key_list[input_key]])"
|
||||
else
|
||||
used_key_list[input_key] = 1
|
||||
return input_key
|
||||
|
||||
#if DM_VERSION > 512
|
||||
#error Remie said that lummox was adding a way to get a lists
|
||||
#error contents via list.values, if that is true remove this
|
||||
#error otherwise, update the version and bug lummox
|
||||
#elseif
|
||||
//Flattens a keyed list into a list of it's contents
|
||||
/proc/flatten_list(list/key_list)
|
||||
if(!islist(key_list))
|
||||
return null
|
||||
. = list()
|
||||
for(var/key in key_list)
|
||||
. |= key_list[key]
|
||||
|
||||
//Picks from the list, with some safeties, and returns the "default" arg if it fails
|
||||
#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default)
|
||||
|
||||
#define LAZYINITLIST(L) if (!L) L = list()
|
||||
|
||||
#define UNSETEMPTY(L) if (L && !L.len) L = null
|
||||
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
|
||||
#define LAZYADD(L, I) if(!L) { L = list(); } L += I;
|
||||
#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null)
|
||||
#define LAZYLEN(L) length(L)
|
||||
#define LAZYCLEARLIST(L) if(L) L.Cut()
|
||||
#define SANITIZE_LIST(L) ( islist(L) ? L : list() )
|
||||
|
||||
/* Definining a counter as a series of key -> numeric value entries
|
||||
|
||||
* All these procs modify in place.
|
||||
*/
|
||||
|
||||
/proc/counterlist_scale(list/L, scalar)
|
||||
var/list/out = list()
|
||||
for(var/key in L)
|
||||
out[key] = L[key] * scalar
|
||||
. = out
|
||||
|
||||
/proc/counterlist_sum(list/L)
|
||||
. = 0
|
||||
for(var/key in L)
|
||||
. += L[key]
|
||||
|
||||
/proc/counterlist_normalise(list/L)
|
||||
var/avg = counterlist_sum(L)
|
||||
if(avg != 0)
|
||||
. = counterlist_scale(L, 1 / avg)
|
||||
else
|
||||
. = L
|
||||
|
||||
/proc/counterlist_combine(list/L1, list/L2)
|
||||
for(var/key in L2)
|
||||
var/other_value = L2[key]
|
||||
if(key in L1)
|
||||
L1[key] += other_value
|
||||
else
|
||||
L1[key] = other_value
|
||||
|
||||
+33
-33
@@ -1,34 +1,34 @@
|
||||
GLOBAL_VAR(log_directory)
|
||||
GLOBAL_PROTECT(log_directory)
|
||||
GLOBAL_VAR(world_game_log)
|
||||
GLOBAL_PROTECT(world_game_log)
|
||||
GLOBAL_VAR(world_runtime_log)
|
||||
GLOBAL_PROTECT(world_runtime_log)
|
||||
GLOBAL_VAR(world_attack_log)
|
||||
GLOBAL_PROTECT(world_attack_log)
|
||||
GLOBAL_VAR(world_href_log)
|
||||
GLOBAL_PROTECT(world_href_log)
|
||||
GLOBAL_VAR(round_id)
|
||||
GLOBAL_PROTECT(round_id)
|
||||
GLOBAL_VAR(config_error_log)
|
||||
GLOBAL_PROTECT(config_error_log)
|
||||
|
||||
GLOBAL_LIST_EMPTY(bombers)
|
||||
GLOBAL_PROTECT(bombers)
|
||||
GLOBAL_LIST_EMPTY(admin_log)
|
||||
GLOBAL_PROTECT(admin_log)
|
||||
GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
|
||||
GLOBAL_PROTECT(lastsignalers)
|
||||
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
|
||||
GLOBAL_PROTECT(lawchanges)
|
||||
|
||||
GLOBAL_LIST_EMPTY(combatlog)
|
||||
GLOBAL_PROTECT(combatlog)
|
||||
GLOBAL_LIST_EMPTY(IClog)
|
||||
GLOBAL_PROTECT(IClog)
|
||||
GLOBAL_LIST_EMPTY(OOClog)
|
||||
GLOBAL_PROTECT(OOClog)
|
||||
GLOBAL_LIST_EMPTY(adminlog)
|
||||
GLOBAL_PROTECT(adminlog)
|
||||
|
||||
GLOBAL_VAR(log_directory)
|
||||
GLOBAL_PROTECT(log_directory)
|
||||
GLOBAL_VAR(world_game_log)
|
||||
GLOBAL_PROTECT(world_game_log)
|
||||
GLOBAL_VAR(world_runtime_log)
|
||||
GLOBAL_PROTECT(world_runtime_log)
|
||||
GLOBAL_VAR(world_attack_log)
|
||||
GLOBAL_PROTECT(world_attack_log)
|
||||
GLOBAL_VAR(world_href_log)
|
||||
GLOBAL_PROTECT(world_href_log)
|
||||
GLOBAL_VAR(round_id)
|
||||
GLOBAL_PROTECT(round_id)
|
||||
GLOBAL_VAR(config_error_log)
|
||||
GLOBAL_PROTECT(config_error_log)
|
||||
|
||||
GLOBAL_LIST_EMPTY(bombers)
|
||||
GLOBAL_PROTECT(bombers)
|
||||
GLOBAL_LIST_EMPTY(admin_log)
|
||||
GLOBAL_PROTECT(admin_log)
|
||||
GLOBAL_LIST_EMPTY(lastsignalers) //keeps last 100 signals here in format: "[src] used \ref[src] @ location [src.loc]: [freq]/[code]"
|
||||
GLOBAL_PROTECT(lastsignalers)
|
||||
GLOBAL_LIST_EMPTY(lawchanges) //Stores who uploaded laws to which silicon-based lifeform, and what the law was
|
||||
GLOBAL_PROTECT(lawchanges)
|
||||
|
||||
GLOBAL_LIST_EMPTY(combatlog)
|
||||
GLOBAL_PROTECT(combatlog)
|
||||
GLOBAL_LIST_EMPTY(IClog)
|
||||
GLOBAL_PROTECT(IClog)
|
||||
GLOBAL_LIST_EMPTY(OOClog)
|
||||
GLOBAL_PROTECT(OOClog)
|
||||
GLOBAL_LIST_EMPTY(adminlog)
|
||||
GLOBAL_PROTECT(adminlog)
|
||||
|
||||
GLOBAL_LIST_EMPTY(active_turfs_startlist)
|
||||
+931
-931
File diff suppressed because it is too large
Load Diff
@@ -162,3 +162,8 @@
|
||||
owner.confused = min(owner.confused + round(severity * 0.025, 1), 25) //2.5% of severity per second above 20 severity
|
||||
owner.adjustToxLoss(severity * 0.02, TRUE, TRUE) //2% of severity per second
|
||||
severity--
|
||||
|
||||
/datum/status_effect/cultghost //is a cult ghost and can't use manifest runes
|
||||
id = "cult_ghost"
|
||||
duration = -1
|
||||
alert_type = null
|
||||
@@ -26,6 +26,11 @@
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/weapon/melee/cultblade/ghost
|
||||
name = "eldritch sword"
|
||||
force = 20
|
||||
flags = NODROP|DROPDEL
|
||||
|
||||
/obj/item/weapon/melee/cultblade/pickup(mob/living/user)
|
||||
..()
|
||||
if(!iscultist(user))
|
||||
@@ -100,12 +105,18 @@
|
||||
icon_state = "cult_hoodalt"
|
||||
item_state = "cult_hoodalt"
|
||||
|
||||
/obj/item/clothing/head/culthood/alt/ghost
|
||||
flags = NODROP|DROPDEL
|
||||
|
||||
/obj/item/clothing/suit/cultrobes/alt
|
||||
name = "cultist robes"
|
||||
desc = "An armored set of robes worn by the followers of Nar-Sie."
|
||||
icon_state = "cultrobesalt"
|
||||
item_state = "cultrobesalt"
|
||||
|
||||
/obj/item/clothing/suit/cultrobes/alt/ghost
|
||||
flags = NODROP|DROPDEL
|
||||
|
||||
|
||||
/obj/item/clothing/head/magus
|
||||
name = "magus helm"
|
||||
|
||||
@@ -481,12 +481,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
if(src)
|
||||
color = "#FF0000"
|
||||
SSticker.mode.eldergod = FALSE
|
||||
deltimer(GLOB.blood_target_reset_timer)
|
||||
GLOB.blood_target = new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed
|
||||
for(var/datum/mind/cult_mind in SSticker.mode.cult)
|
||||
if(isliving(cult_mind.current))
|
||||
var/mob/living/L = cult_mind.current
|
||||
L.narsie_act()
|
||||
new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed
|
||||
|
||||
/obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal.
|
||||
if((istype(I, /obj/item/weapon/tome) && iscultist(user)))
|
||||
@@ -895,9 +890,11 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
icon_state = "6"
|
||||
construct_invoke = 0
|
||||
color = "#C80000"
|
||||
var/ghost_limit = 5
|
||||
var/ghosts = 0
|
||||
|
||||
/obj/effect/rune/manifest/New(loc)
|
||||
..()
|
||||
/obj/effect/rune/manifest/Initialize()
|
||||
. = ..()
|
||||
notify_ghosts("Manifest rune created in [get_area(src)].", 'sound/effects/ghost2.ogg', source = src)
|
||||
|
||||
/obj/effect/rune/manifest/can_invoke(mob/living/user)
|
||||
@@ -906,6 +903,16 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
fail_invoke()
|
||||
log_game("Manifest rune failed - user not standing on rune")
|
||||
return list()
|
||||
if(user.has_status_effect(STATUS_EFFECT_SUMMONEDGHOST))
|
||||
to_chat(user, "<span class='cultitalic'>Ghosts can't summon more ghosts!</span>")
|
||||
fail_invoke()
|
||||
log_game("Manifest rune failed - user is a ghost")
|
||||
return list()
|
||||
if(ghosts >= ghost_limit)
|
||||
to_chat(user, "<span class='cultitalic'>You are sustaining too many ghosts to summon more!</span>")
|
||||
fail_invoke()
|
||||
log_game("Manifest rune failed - too many summoned ghosts")
|
||||
return list()
|
||||
var/list/ghosts_on_rune = list()
|
||||
for(var/mob/dead/observer/O in get_turf(src))
|
||||
if(O.client && !jobban_isbanned(O, ROLE_CULTIST))
|
||||
@@ -927,8 +934,11 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
var/mob/living/carbon/human/new_human = new(get_turf(src))
|
||||
new_human.real_name = ghost_to_spawn.real_name
|
||||
new_human.alpha = 150 //Makes them translucent
|
||||
new_human.equipOutfit(/datum/outfit/ghost_cultist) //give them armor
|
||||
new_human.apply_status_effect(STATUS_EFFECT_SUMMONEDGHOST) //ghosts can't summon more ghosts
|
||||
..()
|
||||
visible_message("<span class='warning'>A cloud of red mist forms above [src], and from within steps... a man.</span>")
|
||||
ghosts++
|
||||
visible_message("<span class='warning'>A cloud of red mist forms above [src], and from within steps... a [new_human.gender == FEMALE ? "wo":""]man.</span>")
|
||||
to_chat(user, "<span class='cultitalic'>Your blood begins flowing into [src]. You must remain in place and conscious to maintain the forms of those summoned. This will hurt you slowly but surely...</span>")
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/structure/emergency_shield/invoker/N = new(T)
|
||||
@@ -937,16 +947,17 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
SSticker.mode.add_cultist(new_human.mind, 0)
|
||||
to_chat(new_human, "<span class='cultitalic'><b>You are a servant of the Geometer. You have been made semi-corporeal by the cult of Nar-Sie, and you are to serve them at all costs.</b></span>")
|
||||
|
||||
while(user in T)
|
||||
if(user.stat)
|
||||
while(!QDELETED(src) && !QDELETED(user) && !QDELETED(new_human) && (user in T))
|
||||
if(user.stat || new_human.InCritical())
|
||||
break
|
||||
user.apply_damage(0.1, BRUTE)
|
||||
sleep(3)
|
||||
sleep(1)
|
||||
|
||||
qdel(N)
|
||||
ghosts--
|
||||
if(new_human)
|
||||
new_human.visible_message("<span class='warning'>[new_human] suddenly dissolves into bones and ashes.</span>", \
|
||||
"<span class='cultlarge'>Your link to the world fades. Your form breaks apart.</span>")
|
||||
for(var/obj/I in new_human)
|
||||
new_human.dropItemToGround(I)
|
||||
new_human.dropItemToGround(I, TRUE)
|
||||
new_human.dust()
|
||||
@@ -52,7 +52,7 @@
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/computer/narsie_act()
|
||||
if(clockwork && clockwork != initial(clockwork)) //if it's clockwork but isn't normally clockwork
|
||||
if(clockwork && clockwork != initial(clockwork)) //if it's clockwork but isn't normally clockwork
|
||||
clockwork = FALSE
|
||||
icon_screen = initial(icon_screen)
|
||||
icon_keyboard = initial(icon_keyboard)
|
||||
|
||||
+396
-396
@@ -1,397 +1,397 @@
|
||||
/* Holograms!
|
||||
* Contains:
|
||||
* Holopad
|
||||
* Hologram
|
||||
* Other stuff
|
||||
*/
|
||||
|
||||
/*
|
||||
Revised. Original based on space ninja hologram code. Which is also mine. /N
|
||||
How it works:
|
||||
AI clicks on holopad in camera view. View centers on holopad.
|
||||
AI clicks again on the holopad to display a hologram. Hologram stays as long as AI is looking at the pad and it (the hologram) is in range of the pad.
|
||||
AI can use the directional keys to move the hologram around, provided the above conditions are met and the AI in question is the holopad's master.
|
||||
Any number of AIs can use a holopad. /Lo6
|
||||
AI may cancel the hologram at any time by clicking on the holopad once more.
|
||||
|
||||
Possible to do for anyone motivated enough:
|
||||
Give an AI variable for different hologram icons.
|
||||
Itegrate EMP effect to disable the unit.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Holopad
|
||||
*/
|
||||
|
||||
#define HOLOPAD_PASSIVE_POWER_USAGE 1
|
||||
#define HOLOGRAM_POWER_USAGE 2
|
||||
|
||||
GLOBAL_LIST_EMPTY(holopads)
|
||||
#define HOLOPAD_MODE RANGE_BASED
|
||||
|
||||
/obj/machinery/holopad
|
||||
name = "Holopad"
|
||||
desc = "It's a floor-mounted device for projecting holographic images."
|
||||
icon_state = "holopad0"
|
||||
layer = LOW_OBJ_LAYER
|
||||
flags = HEAR
|
||||
anchored = 1
|
||||
use_power = 1
|
||||
idle_power_usage = 5
|
||||
active_power_usage = 100
|
||||
obj_integrity = 300
|
||||
max_integrity = 300
|
||||
armor = list(melee = 50, bullet = 20, laser = 20, energy = 20, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 0)
|
||||
var/list/masters = list()//List of living mobs that use the holopad
|
||||
var/last_request = 0 //to prevent request spam. ~Carn
|
||||
var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating.
|
||||
var/temp = ""
|
||||
var/list/holo_calls //array of /datum/holocalls
|
||||
var/datum/holocall/outgoing_call //do not modify the datums only check and call the public procs
|
||||
var/static/force_answer_call = FALSE //Calls will be automatically answered after a couple rings, here for debugging
|
||||
var/static/list/holopads = list()
|
||||
|
||||
/obj/machinery/holopad/Initialize()
|
||||
..()
|
||||
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/holopad(null)
|
||||
B.apply_default_parts(src)
|
||||
holopads += src
|
||||
|
||||
/obj/machinery/holopad/Destroy()
|
||||
if(outgoing_call)
|
||||
LAZYADD(holo_calls, outgoing_call)
|
||||
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
HC.ConnectionFailure(src)
|
||||
LAZYCLEARLIST(holo_calls)
|
||||
|
||||
for (var/I in masters)
|
||||
clear_holo(I)
|
||||
holopads -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/holopad/power_change()
|
||||
if (powered())
|
||||
stat &= ~NOPOWER
|
||||
else
|
||||
stat |= ~NOPOWER
|
||||
|
||||
/obj/machinery/holopad/RefreshParts()
|
||||
var/holograph_range = 4
|
||||
for(var/obj/item/weapon/stock_parts/capacitor/B in component_parts)
|
||||
holograph_range += 1 * B.rating
|
||||
holo_range = holograph_range
|
||||
|
||||
/obj/machinery/holopad/attackby(obj/item/P, mob/user, params)
|
||||
if(default_deconstruction_screwdriver(user, "holopad_open", "holopad0", P))
|
||||
return
|
||||
|
||||
if(exchange_parts(user, P))
|
||||
return
|
||||
|
||||
if(default_pry_open(P))
|
||||
return
|
||||
|
||||
if(default_unfasten_wrench(user, P))
|
||||
return
|
||||
|
||||
if(default_deconstruction_crowbar(P))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/holopad/proc/CheckCallClose()
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(usr == HC.eye)
|
||||
HC.Disconnect(HC.calling_holopad) //disconnect via clicking the called holopad
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/holopad/Click(location,control,params)
|
||||
if(!CheckCallClose())
|
||||
return ..()
|
||||
|
||||
/obj/machinery/holopad/AltClick(mob/living/carbon/human/user)
|
||||
if(!CheckCallClose())
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/holopad/interact(mob/living/carbon/human/user) //Carn: Hologram requests.
|
||||
if(!istype(user))
|
||||
return
|
||||
|
||||
if(outgoing_call || user.incapacitated() || !is_operational())
|
||||
return
|
||||
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
if(temp)
|
||||
dat = temp
|
||||
else
|
||||
dat = "<a href='?src=\ref[src];AIrequest=1'>Request an AI's presence.</a><br>"
|
||||
dat += "<a href='?src=\ref[src];Holocall=1'>Call another holopad.</a><br>"
|
||||
|
||||
if(LAZYLEN(holo_calls))
|
||||
dat += "=====================================================<br>"
|
||||
|
||||
var/one_answered_call = FALSE
|
||||
var/one_unanswered_call = FALSE
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(HC.connected_holopad != src)
|
||||
dat += "<a href='?src=\ref[src];connectcall=\ref[HC]'>Answer call from [get_area(HC.calling_holopad)].</a><br>"
|
||||
one_unanswered_call = TRUE
|
||||
else
|
||||
one_answered_call = TRUE
|
||||
|
||||
if(one_answered_call && one_unanswered_call)
|
||||
dat += "=====================================================<br>"
|
||||
//we loop twice for formatting
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(HC.connected_holopad == src)
|
||||
dat += "<a href='?src=\ref[src];disconnectcall=\ref[HC]'>Disconnect call from [HC.user].</a><br>"
|
||||
|
||||
|
||||
var/datum/browser/popup = new(user, "holopad", name, 300, 130)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/holopad/Topic(href, href_list)
|
||||
if(..() || isAI(usr))
|
||||
return
|
||||
add_fingerprint(usr)
|
||||
if(!is_operational())
|
||||
return
|
||||
if (href_list["AIrequest"])
|
||||
if(last_request + 200 < world.time)
|
||||
last_request = world.time
|
||||
temp = "You requested an AI's presence.<BR>"
|
||||
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
|
||||
var/area/area = get_area(src)
|
||||
for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs)
|
||||
if(!AI.client)
|
||||
continue
|
||||
to_chat(AI, "<span class='info'>Your presence is requested at <a href='?src=\ref[AI];jumptoholopad=\ref[src]'>\the [area]</a>.</span>")
|
||||
else
|
||||
temp = "A request for AI presence was already sent recently.<BR>"
|
||||
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
|
||||
|
||||
else if(href_list["Holocall"])
|
||||
if(outgoing_call)
|
||||
return
|
||||
|
||||
temp = "You must stand on the holopad to make a call!<br>"
|
||||
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
|
||||
if(usr.loc == loc)
|
||||
var/list/callnames = list()
|
||||
for(var/I in holopads)
|
||||
var/area/A = get_area(I)
|
||||
if(A)
|
||||
LAZYADD(callnames[A], I)
|
||||
callnames -= get_area(src)
|
||||
|
||||
var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in callnames
|
||||
if(QDELETED(usr) || !result || outgoing_call)
|
||||
return
|
||||
|
||||
if(usr.loc == loc)
|
||||
temp = "Dialing...<br>"
|
||||
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
|
||||
new /datum/holocall(usr, src, callnames[result])
|
||||
|
||||
else if(href_list["connectcall"])
|
||||
var/datum/holocall/call_to_connect = locate(href_list["connectcall"])
|
||||
if(!QDELETED(call_to_connect))
|
||||
call_to_connect.Answer(src)
|
||||
temp = ""
|
||||
|
||||
else if(href_list["disconnectcall"])
|
||||
var/datum/holocall/call_to_disconnect = locate(href_list["disconnectcall"])
|
||||
if(!QDELETED(call_to_disconnect))
|
||||
call_to_disconnect.Disconnect(src)
|
||||
temp = ""
|
||||
|
||||
else if(href_list["mainmenu"])
|
||||
temp = ""
|
||||
if(outgoing_call)
|
||||
outgoing_call.Disconnect()
|
||||
|
||||
updateDialog()
|
||||
|
||||
//do not allow AIs to answer calls or people will use it to meta the AI sattelite
|
||||
/obj/machinery/holopad/attack_ai(mob/living/silicon/ai/user)
|
||||
if (!istype(user))
|
||||
return
|
||||
/*There are pretty much only three ways to interact here.
|
||||
I don't need to check for client since they're clicking on an object.
|
||||
This may change in the future but for now will suffice.*/
|
||||
if(user.eyeobj.loc != src.loc)//Set client eye on the object if it's not already.
|
||||
user.eyeobj.setLoc(get_turf(src))
|
||||
else if(!masters[user])//If there is no hologram, possibly make one.
|
||||
activate_holo(user)
|
||||
else//If there is a hologram, remove it.
|
||||
clear_holo(user)
|
||||
|
||||
/obj/machinery/holopad/process()
|
||||
for(var/I in masters)
|
||||
var/mob/living/master = I
|
||||
var/mob/living/silicon/ai/AI = master
|
||||
if(!istype(AI))
|
||||
AI = null
|
||||
|
||||
if(!QDELETED(master) && !master.incapacitated() && master.client && (!AI || AI.eyeobj))//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector.
|
||||
if(is_operational())//If the machine has power.
|
||||
if(AI) //ais are range based
|
||||
if(get_dist(AI.eyeobj, src) <= holo_range)
|
||||
continue
|
||||
else
|
||||
var/obj/machinery/holopad/pad_close = get_closest_atom(/obj/machinery/holopad, holopads, AI.eyeobj)
|
||||
if(get_dist(pad_close, AI.eyeobj) <= holo_range)
|
||||
var/obj/effect/overlay/holo_pad_hologram/h = masters[master]
|
||||
unset_holo(master)
|
||||
pad_close.set_holo(master, h)
|
||||
continue
|
||||
else
|
||||
continue
|
||||
clear_holo(master)//If not, we want to get rid of the hologram.
|
||||
|
||||
if(outgoing_call)
|
||||
outgoing_call.Check()
|
||||
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(HC.connected_holopad != src)
|
||||
if(force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2)))
|
||||
HC.Answer(src)
|
||||
break
|
||||
if(outgoing_call)
|
||||
HC.Disconnect(src)//can't answer calls while calling
|
||||
else
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring!
|
||||
|
||||
/obj/machinery/holopad/proc/activate_holo(mob/living/user)
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
if(!istype(AI))
|
||||
AI = null
|
||||
|
||||
if(is_operational() && (!AI || AI.eyeobj.loc == loc))//If the projector has power and client eye is on it
|
||||
if (AI && istype(AI.current, /obj/machinery/holopad))
|
||||
to_chat(user, "<span class='danger'>ERROR:</span> \black Image feed in progress.")
|
||||
return
|
||||
|
||||
var/obj/effect/overlay/holo_pad_hologram/Hologram = new(loc)//Spawn a blank effect at the location.
|
||||
if(AI)
|
||||
Hologram.icon = AI.holo_icon
|
||||
else //make it like real life
|
||||
Hologram.icon = user.icon
|
||||
Hologram.icon_state = user.icon_state
|
||||
Hologram.copy_overlays(user, TRUE)
|
||||
//codersprite some holo effects here
|
||||
Hologram.alpha = 100
|
||||
Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
|
||||
Hologram.Impersonation = user
|
||||
|
||||
|
||||
Hologram.language_holder = user.get_language_holder()
|
||||
|
||||
Hologram.mouse_opacity = 0//So you can't click on it.
|
||||
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
|
||||
Hologram.anchored = 1//So space wind cannot drag it.
|
||||
Hologram.name = "[user.name] (Hologram)"//If someone decides to right click.
|
||||
Hologram.set_light(2) //hologram lighting
|
||||
|
||||
set_holo(user, Hologram)
|
||||
visible_message("A holographic image of [user] flicks to life right before your eyes!")
|
||||
|
||||
return Hologram
|
||||
else
|
||||
to_chat(user, "<span class='danger'>ERROR:</span> \black Unable to project hologram.")
|
||||
|
||||
/*This is the proc for special two-way communication between AI and holopad/people talking near holopad.
|
||||
For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
if(speaker && masters.len && !radio_freq)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios.
|
||||
for(var/mob/living/silicon/ai/master in masters)
|
||||
if(masters[master] && speaker != master)
|
||||
master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(HC.connected_holopad == src && speaker != HC.hologram)
|
||||
HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans)
|
||||
|
||||
if(outgoing_call && speaker == outgoing_call.user)
|
||||
outgoing_call.hologram.say(raw_message)
|
||||
|
||||
/obj/machinery/holopad/proc/SetLightsAndPower()
|
||||
var/total_users = masters.len + LAZYLEN(holo_calls)
|
||||
use_power = HOLOPAD_PASSIVE_POWER_USAGE + HOLOGRAM_POWER_USAGE * total_users
|
||||
if(total_users)
|
||||
set_light(2)
|
||||
icon_state = "holopad1"
|
||||
else
|
||||
set_light(0)
|
||||
icon_state = "holopad0"
|
||||
|
||||
/obj/machinery/holopad/proc/set_holo(mob/living/user, var/obj/effect/overlay/holo_pad_hologram/h)
|
||||
masters[user] = h
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
if(istype(AI))
|
||||
AI.current = src
|
||||
SetLightsAndPower()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/holopad/proc/clear_holo(mob/living/user)
|
||||
qdel(masters[user]) // Get rid of user's hologram
|
||||
unset_holo(user)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/holopad/proc/unset_holo(mob/living/user)
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
if(istype(AI) && AI.current == src)
|
||||
AI.current = null
|
||||
masters -= user // Discard AI from the list of those who use holopad
|
||||
SetLightsAndPower()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf)
|
||||
if(masters[user])
|
||||
var/obj/effect/overlay/holo_pad_hologram/H = masters[user]
|
||||
step_to(H, new_turf)
|
||||
H.loc = new_turf
|
||||
var/area/holo_area = get_area(src)
|
||||
var/area/eye_area = new_turf.loc
|
||||
|
||||
if(!(eye_area in holo_area.related))
|
||||
clear_holo(user)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram
|
||||
var/mob/living/Impersonation
|
||||
var/datum/holocall/HC
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram/Destroy()
|
||||
Impersonation = null
|
||||
if(HC)
|
||||
HC.Disconnect(HC.calling_holopad)
|
||||
return ..()
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram/examine(mob/user)
|
||||
if(Impersonation)
|
||||
return Impersonation.examine(user)
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/holopad
|
||||
name = "AI Holopad (Machine Board)"
|
||||
build_path = /obj/machinery/holopad
|
||||
origin_tech = "programming=1"
|
||||
req_components = list(/obj/item/weapon/stock_parts/capacitor = 1)
|
||||
|
||||
#undef HOLOPAD_PASSIVE_POWER_USAGE
|
||||
/* Holograms!
|
||||
* Contains:
|
||||
* Holopad
|
||||
* Hologram
|
||||
* Other stuff
|
||||
*/
|
||||
|
||||
/*
|
||||
Revised. Original based on space ninja hologram code. Which is also mine. /N
|
||||
How it works:
|
||||
AI clicks on holopad in camera view. View centers on holopad.
|
||||
AI clicks again on the holopad to display a hologram. Hologram stays as long as AI is looking at the pad and it (the hologram) is in range of the pad.
|
||||
AI can use the directional keys to move the hologram around, provided the above conditions are met and the AI in question is the holopad's master.
|
||||
Any number of AIs can use a holopad. /Lo6
|
||||
AI may cancel the hologram at any time by clicking on the holopad once more.
|
||||
|
||||
Possible to do for anyone motivated enough:
|
||||
Give an AI variable for different hologram icons.
|
||||
Itegrate EMP effect to disable the unit.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Holopad
|
||||
*/
|
||||
|
||||
#define HOLOPAD_PASSIVE_POWER_USAGE 1
|
||||
#define HOLOGRAM_POWER_USAGE 2
|
||||
|
||||
GLOBAL_LIST_EMPTY(holopads)
|
||||
#define HOLOPAD_MODE RANGE_BASED
|
||||
|
||||
/obj/machinery/holopad
|
||||
name = "Holopad"
|
||||
desc = "It's a floor-mounted device for projecting holographic images."
|
||||
icon_state = "holopad0"
|
||||
layer = LOW_OBJ_LAYER
|
||||
flags = HEAR
|
||||
anchored = 1
|
||||
use_power = 1
|
||||
idle_power_usage = 5
|
||||
active_power_usage = 100
|
||||
obj_integrity = 300
|
||||
max_integrity = 300
|
||||
armor = list(melee = 50, bullet = 20, laser = 20, energy = 20, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 0)
|
||||
var/list/masters = list()//List of living mobs that use the holopad
|
||||
var/last_request = 0 //to prevent request spam. ~Carn
|
||||
var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating.
|
||||
var/temp = ""
|
||||
var/list/holo_calls //array of /datum/holocalls
|
||||
var/datum/holocall/outgoing_call //do not modify the datums only check and call the public procs
|
||||
var/static/force_answer_call = FALSE //Calls will be automatically answered after a couple rings, here for debugging
|
||||
var/static/list/holopads = list()
|
||||
|
||||
/obj/machinery/holopad/Initialize()
|
||||
..()
|
||||
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/holopad(null)
|
||||
B.apply_default_parts(src)
|
||||
holopads += src
|
||||
|
||||
/obj/machinery/holopad/Destroy()
|
||||
if(outgoing_call)
|
||||
LAZYADD(holo_calls, outgoing_call)
|
||||
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
HC.ConnectionFailure(src)
|
||||
LAZYCLEARLIST(holo_calls)
|
||||
|
||||
for (var/I in masters)
|
||||
clear_holo(I)
|
||||
holopads -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/holopad/power_change()
|
||||
if (powered())
|
||||
stat &= ~NOPOWER
|
||||
else
|
||||
stat |= ~NOPOWER
|
||||
|
||||
/obj/machinery/holopad/RefreshParts()
|
||||
var/holograph_range = 4
|
||||
for(var/obj/item/weapon/stock_parts/capacitor/B in component_parts)
|
||||
holograph_range += 1 * B.rating
|
||||
holo_range = holograph_range
|
||||
|
||||
/obj/machinery/holopad/attackby(obj/item/P, mob/user, params)
|
||||
if(default_deconstruction_screwdriver(user, "holopad_open", "holopad0", P))
|
||||
return
|
||||
|
||||
if(exchange_parts(user, P))
|
||||
return
|
||||
|
||||
if(default_pry_open(P))
|
||||
return
|
||||
|
||||
if(default_unfasten_wrench(user, P))
|
||||
return
|
||||
|
||||
if(default_deconstruction_crowbar(P))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/holopad/proc/CheckCallClose()
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(usr == HC.eye)
|
||||
HC.Disconnect(HC.calling_holopad) //disconnect via clicking the called holopad
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/holopad/Click(location,control,params)
|
||||
if(!CheckCallClose())
|
||||
return ..()
|
||||
|
||||
/obj/machinery/holopad/AltClick(mob/living/carbon/human/user)
|
||||
if(!CheckCallClose())
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/holopad/interact(mob/living/carbon/human/user) //Carn: Hologram requests.
|
||||
if(!istype(user))
|
||||
return
|
||||
|
||||
if(outgoing_call || user.incapacitated() || !is_operational())
|
||||
return
|
||||
|
||||
user.set_machine(src)
|
||||
var/dat
|
||||
if(temp)
|
||||
dat = temp
|
||||
else
|
||||
dat = "<a href='?src=\ref[src];AIrequest=1'>Request an AI's presence.</a><br>"
|
||||
dat += "<a href='?src=\ref[src];Holocall=1'>Call another holopad.</a><br>"
|
||||
|
||||
if(LAZYLEN(holo_calls))
|
||||
dat += "=====================================================<br>"
|
||||
|
||||
var/one_answered_call = FALSE
|
||||
var/one_unanswered_call = FALSE
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(HC.connected_holopad != src)
|
||||
dat += "<a href='?src=\ref[src];connectcall=\ref[HC]'>Answer call from [get_area(HC.calling_holopad)].</a><br>"
|
||||
one_unanswered_call = TRUE
|
||||
else
|
||||
one_answered_call = TRUE
|
||||
|
||||
if(one_answered_call && one_unanswered_call)
|
||||
dat += "=====================================================<br>"
|
||||
//we loop twice for formatting
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(HC.connected_holopad == src)
|
||||
dat += "<a href='?src=\ref[src];disconnectcall=\ref[HC]'>Disconnect call from [HC.user].</a><br>"
|
||||
|
||||
|
||||
var/datum/browser/popup = new(user, "holopad", name, 300, 130)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/holopad/Topic(href, href_list)
|
||||
if(..() || isAI(usr))
|
||||
return
|
||||
add_fingerprint(usr)
|
||||
if(!is_operational())
|
||||
return
|
||||
if (href_list["AIrequest"])
|
||||
if(last_request + 200 < world.time)
|
||||
last_request = world.time
|
||||
temp = "You requested an AI's presence.<BR>"
|
||||
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
|
||||
var/area/area = get_area(src)
|
||||
for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs)
|
||||
if(!AI.client)
|
||||
continue
|
||||
to_chat(AI, "<span class='info'>Your presence is requested at <a href='?src=\ref[AI];jumptoholopad=\ref[src]'>\the [area]</a>.</span>")
|
||||
else
|
||||
temp = "A request for AI presence was already sent recently.<BR>"
|
||||
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
|
||||
|
||||
else if(href_list["Holocall"])
|
||||
if(outgoing_call)
|
||||
return
|
||||
|
||||
temp = "You must stand on the holopad to make a call!<br>"
|
||||
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
|
||||
if(usr.loc == loc)
|
||||
var/list/callnames = list()
|
||||
for(var/I in holopads)
|
||||
var/area/A = get_area(I)
|
||||
if(A)
|
||||
LAZYADD(callnames[A], I)
|
||||
callnames -= get_area(src)
|
||||
|
||||
var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in callnames
|
||||
if(QDELETED(usr) || !result || outgoing_call)
|
||||
return
|
||||
|
||||
if(usr.loc == loc)
|
||||
temp = "Dialing...<br>"
|
||||
temp += "<A href='?src=\ref[src];mainmenu=1'>Main Menu</A>"
|
||||
new /datum/holocall(usr, src, callnames[result])
|
||||
|
||||
else if(href_list["connectcall"])
|
||||
var/datum/holocall/call_to_connect = locate(href_list["connectcall"])
|
||||
if(!QDELETED(call_to_connect))
|
||||
call_to_connect.Answer(src)
|
||||
temp = ""
|
||||
|
||||
else if(href_list["disconnectcall"])
|
||||
var/datum/holocall/call_to_disconnect = locate(href_list["disconnectcall"])
|
||||
if(!QDELETED(call_to_disconnect))
|
||||
call_to_disconnect.Disconnect(src)
|
||||
temp = ""
|
||||
|
||||
else if(href_list["mainmenu"])
|
||||
temp = ""
|
||||
if(outgoing_call)
|
||||
outgoing_call.Disconnect()
|
||||
|
||||
updateDialog()
|
||||
|
||||
//do not allow AIs to answer calls or people will use it to meta the AI sattelite
|
||||
/obj/machinery/holopad/attack_ai(mob/living/silicon/ai/user)
|
||||
if (!istype(user))
|
||||
return
|
||||
/*There are pretty much only three ways to interact here.
|
||||
I don't need to check for client since they're clicking on an object.
|
||||
This may change in the future but for now will suffice.*/
|
||||
if(user.eyeobj.loc != src.loc)//Set client eye on the object if it's not already.
|
||||
user.eyeobj.setLoc(get_turf(src))
|
||||
else if(!masters[user])//If there is no hologram, possibly make one.
|
||||
activate_holo(user)
|
||||
else//If there is a hologram, remove it.
|
||||
clear_holo(user)
|
||||
|
||||
/obj/machinery/holopad/process()
|
||||
for(var/I in masters)
|
||||
var/mob/living/master = I
|
||||
var/mob/living/silicon/ai/AI = master
|
||||
if(!istype(AI))
|
||||
AI = null
|
||||
|
||||
if(!QDELETED(master) && !master.incapacitated() && master.client && (!AI || AI.eyeobj))//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector.
|
||||
if(is_operational())//If the machine has power.
|
||||
if(AI) //ais are range based
|
||||
if(get_dist(AI.eyeobj, src) <= holo_range)
|
||||
continue
|
||||
else
|
||||
var/obj/machinery/holopad/pad_close = get_closest_atom(/obj/machinery/holopad, holopads, AI.eyeobj)
|
||||
if(get_dist(pad_close, AI.eyeobj) <= holo_range)
|
||||
var/obj/effect/overlay/holo_pad_hologram/h = masters[master]
|
||||
unset_holo(master)
|
||||
pad_close.set_holo(master, h)
|
||||
continue
|
||||
else
|
||||
continue
|
||||
clear_holo(master)//If not, we want to get rid of the hologram.
|
||||
|
||||
if(outgoing_call)
|
||||
outgoing_call.Check()
|
||||
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(HC.connected_holopad != src)
|
||||
if(force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2)))
|
||||
HC.Answer(src)
|
||||
break
|
||||
if(outgoing_call)
|
||||
HC.Disconnect(src)//can't answer calls while calling
|
||||
else
|
||||
playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring!
|
||||
|
||||
/obj/machinery/holopad/proc/activate_holo(mob/living/user)
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
if(!istype(AI))
|
||||
AI = null
|
||||
|
||||
if(is_operational() && (!AI || AI.eyeobj.loc == loc))//If the projector has power and client eye is on it
|
||||
if (AI && istype(AI.current, /obj/machinery/holopad))
|
||||
to_chat(user, "<span class='danger'>ERROR:</span> \black Image feed in progress.")
|
||||
return
|
||||
|
||||
var/obj/effect/overlay/holo_pad_hologram/Hologram = new(loc)//Spawn a blank effect at the location.
|
||||
if(AI)
|
||||
Hologram.icon = AI.holo_icon
|
||||
else //make it like real life
|
||||
Hologram.icon = user.icon
|
||||
Hologram.icon_state = user.icon_state
|
||||
Hologram.copy_overlays(user, TRUE)
|
||||
//codersprite some holo effects here
|
||||
Hologram.alpha = 100
|
||||
Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
|
||||
Hologram.Impersonation = user
|
||||
|
||||
|
||||
Hologram.language_holder = user.get_language_holder()
|
||||
|
||||
Hologram.mouse_opacity = 0//So you can't click on it.
|
||||
Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
|
||||
Hologram.anchored = 1//So space wind cannot drag it.
|
||||
Hologram.name = "[user.name] (Hologram)"//If someone decides to right click.
|
||||
Hologram.set_light(2) //hologram lighting
|
||||
|
||||
set_holo(user, Hologram)
|
||||
visible_message("A holographic image of [user] flicks to life right before your eyes!")
|
||||
|
||||
return Hologram
|
||||
else
|
||||
to_chat(user, "<span class='danger'>ERROR:</span> \black Unable to project hologram.")
|
||||
|
||||
/*This is the proc for special two-way communication between AI and holopad/people talking near holopad.
|
||||
For the other part of the code, check silicon say.dm. Particularly robot talk.*/
|
||||
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode)
|
||||
if(speaker && masters.len && !radio_freq)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios.
|
||||
for(var/mob/living/silicon/ai/master in masters)
|
||||
if(masters[master] && speaker != master)
|
||||
master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
|
||||
|
||||
for(var/I in holo_calls)
|
||||
var/datum/holocall/HC = I
|
||||
if(HC.connected_holopad == src && speaker != HC.hologram)
|
||||
HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans)
|
||||
|
||||
if(outgoing_call && speaker == outgoing_call.user)
|
||||
outgoing_call.hologram.say(raw_message)
|
||||
|
||||
/obj/machinery/holopad/proc/SetLightsAndPower()
|
||||
var/total_users = masters.len + LAZYLEN(holo_calls)
|
||||
use_power = HOLOPAD_PASSIVE_POWER_USAGE + HOLOGRAM_POWER_USAGE * total_users
|
||||
if(total_users)
|
||||
set_light(2)
|
||||
icon_state = "holopad1"
|
||||
else
|
||||
set_light(0)
|
||||
icon_state = "holopad0"
|
||||
|
||||
/obj/machinery/holopad/proc/set_holo(mob/living/user, var/obj/effect/overlay/holo_pad_hologram/h)
|
||||
masters[user] = h
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
if(istype(AI))
|
||||
AI.current = src
|
||||
SetLightsAndPower()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/holopad/proc/clear_holo(mob/living/user)
|
||||
qdel(masters[user]) // Get rid of user's hologram
|
||||
unset_holo(user)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/holopad/proc/unset_holo(mob/living/user)
|
||||
var/mob/living/silicon/ai/AI = user
|
||||
if(istype(AI) && AI.current == src)
|
||||
AI.current = null
|
||||
masters -= user // Discard AI from the list of those who use holopad
|
||||
SetLightsAndPower()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf)
|
||||
if(masters[user])
|
||||
var/obj/effect/overlay/holo_pad_hologram/H = masters[user]
|
||||
step_to(H, new_turf)
|
||||
H.loc = new_turf
|
||||
var/area/holo_area = get_area(src)
|
||||
var/area/eye_area = new_turf.loc
|
||||
|
||||
if(!(eye_area in holo_area.related))
|
||||
clear_holo(user)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram
|
||||
var/mob/living/Impersonation
|
||||
var/datum/holocall/HC
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram/Destroy()
|
||||
Impersonation = null
|
||||
if(HC)
|
||||
HC.Disconnect(HC.calling_holopad)
|
||||
return ..()
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/obj/effect/overlay/holo_pad_hologram/examine(mob/user)
|
||||
if(Impersonation)
|
||||
return Impersonation.examine(user)
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/holopad
|
||||
name = "AI Holopad (Machine Board)"
|
||||
build_path = /obj/machinery/holopad
|
||||
origin_tech = "programming=1"
|
||||
req_components = list(/obj/item/weapon/stock_parts/capacitor = 1)
|
||||
|
||||
#undef HOLOPAD_PASSIVE_POWER_USAGE
|
||||
#undef HOLOGRAM_POWER_USAGE
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,259 +1,259 @@
|
||||
/obj/item/weapon/melee/energy
|
||||
var/active = 0
|
||||
var/force_on = 30 //force when active
|
||||
var/throwforce_on = 20
|
||||
var/icon_state_on = "axe1"
|
||||
var/list/attack_verb_on = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
var/list/possible_colors
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
sharpness = IS_SHARP
|
||||
var/w_class_on = WEIGHT_CLASS_BULKY
|
||||
heat = 3500
|
||||
obj_integrity = 200
|
||||
max_integrity = 200
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30)
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/brightness_on = 3
|
||||
|
||||
/obj/item/weapon/melee/energy/Initialize()
|
||||
. = ..()
|
||||
if(LAZYLEN(possible_colors))
|
||||
item_color = pick(possible_colors)
|
||||
switch(item_color)//Only run this check if the color was picked randomly, so that colors can be manually set for non-random colored energy weapons.
|
||||
if("red")
|
||||
light_color = LIGHT_COLOR_RED
|
||||
if("green")
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
if("blue")
|
||||
light_color = LIGHT_COLOR_LIGHT_CYAN
|
||||
if("purple")
|
||||
light_color = LIGHT_COLOR_LAVENDER
|
||||
if(active)
|
||||
set_light(brightness_on)
|
||||
|
||||
/obj/item/weapon/melee/energy/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is [pick("slitting [user.p_their()] stomach open with", "falling on")] [src]! It looks like [user.p_theyre()] trying to commit seppuku!</span>")
|
||||
return (BRUTELOSS|FIRELOSS)
|
||||
|
||||
/obj/item/weapon/melee/energy/add_blood(list/blood_dna)
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/melee/energy/is_sharp()
|
||||
return active * sharpness
|
||||
|
||||
/obj/item/weapon/melee/energy/axe
|
||||
name = "energy axe"
|
||||
desc = "An energized battle axe."
|
||||
icon_state = "axe0"
|
||||
force = 40
|
||||
force_on = 150
|
||||
throwforce = 25
|
||||
throwforce_on = 30
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
w_class_on = WEIGHT_CLASS_HUGE
|
||||
flags = CONDUCT
|
||||
armour_penetration = 100
|
||||
origin_tech = "combat=4;magnets=3"
|
||||
attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut")
|
||||
attack_verb_on = list()
|
||||
light_color = "#40ceff"
|
||||
|
||||
/obj/item/weapon/melee/energy/axe/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] swings [src] towards [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (BRUTELOSS|FIRELOSS)
|
||||
|
||||
/obj/item/weapon/melee/energy/sword
|
||||
name = "energy sword"
|
||||
desc = "May the force be within you."
|
||||
icon_state = "sword0"
|
||||
force = 3
|
||||
throwforce = 5
|
||||
hitsound = "swing_hit" //it starts deactivated
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
sharpness = IS_SHARP
|
||||
embed_chance = 75
|
||||
embedded_impact_pain_multiplier = 10
|
||||
armour_penetration = 35
|
||||
origin_tech = "combat=3;magnets=4;syndicate=4"
|
||||
block_chance = 50
|
||||
possible_colors = list("red", "blue", "green", "purple")
|
||||
var/hacked = 0
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/process()
|
||||
if(active)
|
||||
if(hacked)
|
||||
light_color = pick(LIGHT_COLOR_RED, LIGHT_COLOR_GREEN, LIGHT_COLOR_LIGHT_CYAN, LIGHT_COLOR_LAVENDER)
|
||||
open_flame()
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
|
||||
if(active)
|
||||
return ..()
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/melee/energy/attack_self(mob/living/carbon/user)
|
||||
if(user.disabilities & CLUMSY && prob(50))
|
||||
to_chat(user, "<span class='warning'>You accidentally cut yourself with [src], like a doofus!</span>")
|
||||
user.take_bodypart_damage(5,5)
|
||||
active = !active
|
||||
if (active)
|
||||
force = force_on
|
||||
throwforce = throwforce_on
|
||||
hitsound = 'sound/weapons/blade1.ogg'
|
||||
throw_speed = 4
|
||||
if(attack_verb_on.len)
|
||||
attack_verb = attack_verb_on
|
||||
if(!item_color)
|
||||
icon_state = icon_state_on
|
||||
else
|
||||
icon_state = "sword[item_color]"
|
||||
w_class = w_class_on
|
||||
playsound(user, 'sound/weapons/saberon.ogg', 35, 1) //changed it from 50% volume to 35% because deafness
|
||||
to_chat(user, "<span class='notice'>[src] is now active.</span>")
|
||||
START_PROCESSING(SSobj, src)
|
||||
set_light(brightness_on)
|
||||
else
|
||||
force = initial(force)
|
||||
throwforce = initial(throwforce)
|
||||
hitsound = initial(hitsound)
|
||||
throw_speed = initial(throw_speed)
|
||||
if(attack_verb_on.len)
|
||||
attack_verb = list()
|
||||
icon_state = initial(icon_state)
|
||||
w_class = initial(w_class)
|
||||
playsound(user, 'sound/weapons/saberoff.ogg', 35, 1) //changed it from 50% volume to 35% because deafness
|
||||
to_chat(user, "<span class='notice'>[src] can now be concealed.</span>")
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
set_light(0)
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/item/weapon/melee/energy/is_hot()
|
||||
return active * heat
|
||||
|
||||
/obj/item/weapon/melee/energy/ignition_effect(atom/A, mob/user)
|
||||
if(!active)
|
||||
return ""
|
||||
|
||||
var/in_mouth = ""
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(C.wear_mask == src)
|
||||
in_mouth = ", barely missing their nose"
|
||||
. = "<span class='warning'>[user] swings their \
|
||||
[src][in_mouth]. They light [A] in the process.</span>"
|
||||
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/cyborg
|
||||
var/hitcost = 50
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/cyborg/attack(mob/M, var/mob/living/silicon/robot/R)
|
||||
if(R.cell)
|
||||
var/obj/item/weapon/stock_parts/cell/C = R.cell
|
||||
if(active && !(C.use(hitcost)))
|
||||
attack_self(R)
|
||||
to_chat(R, "<span class='notice'>It's out of charge!</span>")
|
||||
return
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/cyborg/saw //Used by medical Syndicate cyborgs
|
||||
name = "energy saw"
|
||||
desc = "For heavy duty cutting. It has a carbon-fiber blade in addition to a toggleable hard-light edge to dramatically increase sharpness."
|
||||
icon_state = "esaw"
|
||||
force_on = 30
|
||||
force = 18 //About as much as a spear
|
||||
hitsound = 'sound/weapons/circsawhit.ogg'
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "esaw_0"
|
||||
icon_state_on = "esaw_1"
|
||||
hitcost = 75 //Costs more than a standard cyborg esword
|
||||
item_color = null
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
sharpness = IS_SHARP
|
||||
light_color = "#40ceff"
|
||||
possible_colors = null
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/cyborg/saw/Initialize()
|
||||
. = ..()
|
||||
icon_state = "esaw_0"
|
||||
item_color = null
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/cyborg/saw/hit_reaction()
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber/blue
|
||||
possible_colors = list("blue")
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber/purple
|
||||
possible_colors = list("purple")
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber/green
|
||||
possible_colors = list("green")
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber/red
|
||||
possible_colors = list("red")
|
||||
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber/attackby(obj/item/weapon/W, mob/living/user, params)
|
||||
if(istype(W, /obj/item/device/multitool))
|
||||
if(!hacked)
|
||||
hacked = TRUE
|
||||
item_color = "rainbow"
|
||||
to_chat(user, "<span class='warning'>RNBW_ENGAGE</span>")
|
||||
|
||||
if(active)
|
||||
icon_state = "swordrainbow"
|
||||
user.update_inv_hands()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>It's already fabulous!</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/pirate
|
||||
name = "energy cutlass"
|
||||
desc = "Arrrr matey."
|
||||
icon_state = "cutlass0"
|
||||
icon_state_on = "cutlass1"
|
||||
light_color = "#ff0000"
|
||||
|
||||
/obj/item/weapon/melee/energy/blade
|
||||
name = "energy blade"
|
||||
desc = "A concentrated beam of energy in the shape of a blade. Very stylish... and lethal."
|
||||
icon_state = "blade"
|
||||
force = 30 //Normal attacks deal esword damage
|
||||
hitsound = 'sound/weapons/blade1.ogg'
|
||||
active = 1
|
||||
throwforce = 1//Throwing or dropping the item deletes it.
|
||||
throw_speed = 3
|
||||
throw_range = 1
|
||||
w_class = WEIGHT_CLASS_BULKY//So you can't hide it in your pocket or some such.
|
||||
var/datum/effect_system/spark_spread/spark_system
|
||||
sharpness = IS_SHARP
|
||||
|
||||
//Most of the other special functions are handled in their own files. aka special snowflake code so kewl
|
||||
/obj/item/weapon/melee/energy/blade/Initialize()
|
||||
. = ..()
|
||||
spark_system = new /datum/effect_system/spark_spread()
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
|
||||
/obj/item/weapon/melee/energy/blade/attack_self(mob/user)
|
||||
return
|
||||
|
||||
/obj/item/weapon/melee/energy/blade/hardlight
|
||||
name = "hardlight blade"
|
||||
desc = "An extremely sharp blade made out of hard light. Packs quite a punch."
|
||||
icon_state = "lightblade"
|
||||
item_state = "lightblade"
|
||||
/obj/item/weapon/melee/energy
|
||||
var/active = 0
|
||||
var/force_on = 30 //force when active
|
||||
var/throwforce_on = 20
|
||||
var/icon_state_on = "axe1"
|
||||
var/list/attack_verb_on = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
var/list/possible_colors
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
sharpness = IS_SHARP
|
||||
var/w_class_on = WEIGHT_CLASS_BULKY
|
||||
heat = 3500
|
||||
obj_integrity = 200
|
||||
max_integrity = 200
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 30)
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/brightness_on = 3
|
||||
|
||||
/obj/item/weapon/melee/energy/Initialize()
|
||||
. = ..()
|
||||
if(LAZYLEN(possible_colors))
|
||||
item_color = pick(possible_colors)
|
||||
switch(item_color)//Only run this check if the color was picked randomly, so that colors can be manually set for non-random colored energy weapons.
|
||||
if("red")
|
||||
light_color = LIGHT_COLOR_RED
|
||||
if("green")
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
if("blue")
|
||||
light_color = LIGHT_COLOR_LIGHT_CYAN
|
||||
if("purple")
|
||||
light_color = LIGHT_COLOR_LAVENDER
|
||||
if(active)
|
||||
set_light(brightness_on)
|
||||
|
||||
/obj/item/weapon/melee/energy/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is [pick("slitting [user.p_their()] stomach open with", "falling on")] [src]! It looks like [user.p_theyre()] trying to commit seppuku!</span>")
|
||||
return (BRUTELOSS|FIRELOSS)
|
||||
|
||||
/obj/item/weapon/melee/energy/add_blood(list/blood_dna)
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/melee/energy/is_sharp()
|
||||
return active * sharpness
|
||||
|
||||
/obj/item/weapon/melee/energy/axe
|
||||
name = "energy axe"
|
||||
desc = "An energized battle axe."
|
||||
icon_state = "axe0"
|
||||
force = 40
|
||||
force_on = 150
|
||||
throwforce = 25
|
||||
throwforce_on = 30
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
w_class_on = WEIGHT_CLASS_HUGE
|
||||
flags = CONDUCT
|
||||
armour_penetration = 100
|
||||
origin_tech = "combat=4;magnets=3"
|
||||
attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut")
|
||||
attack_verb_on = list()
|
||||
light_color = "#40ceff"
|
||||
|
||||
/obj/item/weapon/melee/energy/axe/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] swings [src] towards [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (BRUTELOSS|FIRELOSS)
|
||||
|
||||
/obj/item/weapon/melee/energy/sword
|
||||
name = "energy sword"
|
||||
desc = "May the force be within you."
|
||||
icon_state = "sword0"
|
||||
force = 3
|
||||
throwforce = 5
|
||||
hitsound = "swing_hit" //it starts deactivated
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
sharpness = IS_SHARP
|
||||
embed_chance = 75
|
||||
embedded_impact_pain_multiplier = 10
|
||||
armour_penetration = 35
|
||||
origin_tech = "combat=3;magnets=4;syndicate=4"
|
||||
block_chance = 50
|
||||
possible_colors = list("red", "blue", "green", "purple")
|
||||
var/hacked = 0
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/process()
|
||||
if(active)
|
||||
if(hacked)
|
||||
light_color = pick(LIGHT_COLOR_RED, LIGHT_COLOR_GREEN, LIGHT_COLOR_LIGHT_CYAN, LIGHT_COLOR_LAVENDER)
|
||||
open_flame()
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
|
||||
if(active)
|
||||
return ..()
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/melee/energy/attack_self(mob/living/carbon/user)
|
||||
if(user.disabilities & CLUMSY && prob(50))
|
||||
to_chat(user, "<span class='warning'>You accidentally cut yourself with [src], like a doofus!</span>")
|
||||
user.take_bodypart_damage(5,5)
|
||||
active = !active
|
||||
if (active)
|
||||
force = force_on
|
||||
throwforce = throwforce_on
|
||||
hitsound = 'sound/weapons/blade1.ogg'
|
||||
throw_speed = 4
|
||||
if(attack_verb_on.len)
|
||||
attack_verb = attack_verb_on
|
||||
if(!item_color)
|
||||
icon_state = icon_state_on
|
||||
else
|
||||
icon_state = "sword[item_color]"
|
||||
w_class = w_class_on
|
||||
playsound(user, 'sound/weapons/saberon.ogg', 35, 1) //changed it from 50% volume to 35% because deafness
|
||||
to_chat(user, "<span class='notice'>[src] is now active.</span>")
|
||||
START_PROCESSING(SSobj, src)
|
||||
set_light(brightness_on)
|
||||
else
|
||||
force = initial(force)
|
||||
throwforce = initial(throwforce)
|
||||
hitsound = initial(hitsound)
|
||||
throw_speed = initial(throw_speed)
|
||||
if(attack_verb_on.len)
|
||||
attack_verb = list()
|
||||
icon_state = initial(icon_state)
|
||||
w_class = initial(w_class)
|
||||
playsound(user, 'sound/weapons/saberoff.ogg', 35, 1) //changed it from 50% volume to 35% because deafness
|
||||
to_chat(user, "<span class='notice'>[src] can now be concealed.</span>")
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
set_light(0)
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/item/weapon/melee/energy/is_hot()
|
||||
return active * heat
|
||||
|
||||
/obj/item/weapon/melee/energy/ignition_effect(atom/A, mob/user)
|
||||
if(!active)
|
||||
return ""
|
||||
|
||||
var/in_mouth = ""
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(C.wear_mask == src)
|
||||
in_mouth = ", barely missing their nose"
|
||||
. = "<span class='warning'>[user] swings their \
|
||||
[src][in_mouth]. They light [A] in the process.</span>"
|
||||
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/cyborg
|
||||
var/hitcost = 50
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/cyborg/attack(mob/M, var/mob/living/silicon/robot/R)
|
||||
if(R.cell)
|
||||
var/obj/item/weapon/stock_parts/cell/C = R.cell
|
||||
if(active && !(C.use(hitcost)))
|
||||
attack_self(R)
|
||||
to_chat(R, "<span class='notice'>It's out of charge!</span>")
|
||||
return
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/cyborg/saw //Used by medical Syndicate cyborgs
|
||||
name = "energy saw"
|
||||
desc = "For heavy duty cutting. It has a carbon-fiber blade in addition to a toggleable hard-light edge to dramatically increase sharpness."
|
||||
icon_state = "esaw"
|
||||
force_on = 30
|
||||
force = 18 //About as much as a spear
|
||||
hitsound = 'sound/weapons/circsawhit.ogg'
|
||||
icon = 'icons/obj/surgery.dmi'
|
||||
icon_state = "esaw_0"
|
||||
icon_state_on = "esaw_1"
|
||||
hitcost = 75 //Costs more than a standard cyborg esword
|
||||
item_color = null
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
sharpness = IS_SHARP
|
||||
light_color = "#40ceff"
|
||||
possible_colors = null
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/cyborg/saw/Initialize()
|
||||
. = ..()
|
||||
icon_state = "esaw_0"
|
||||
item_color = null
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/cyborg/saw/hit_reaction()
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber/blue
|
||||
possible_colors = list("blue")
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber/purple
|
||||
possible_colors = list("purple")
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber/green
|
||||
possible_colors = list("green")
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber/red
|
||||
possible_colors = list("red")
|
||||
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/saber/attackby(obj/item/weapon/W, mob/living/user, params)
|
||||
if(istype(W, /obj/item/device/multitool))
|
||||
if(!hacked)
|
||||
hacked = TRUE
|
||||
item_color = "rainbow"
|
||||
to_chat(user, "<span class='warning'>RNBW_ENGAGE</span>")
|
||||
|
||||
if(active)
|
||||
icon_state = "swordrainbow"
|
||||
user.update_inv_hands()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>It's already fabulous!</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/melee/energy/sword/pirate
|
||||
name = "energy cutlass"
|
||||
desc = "Arrrr matey."
|
||||
icon_state = "cutlass0"
|
||||
icon_state_on = "cutlass1"
|
||||
light_color = "#ff0000"
|
||||
|
||||
/obj/item/weapon/melee/energy/blade
|
||||
name = "energy blade"
|
||||
desc = "A concentrated beam of energy in the shape of a blade. Very stylish... and lethal."
|
||||
icon_state = "blade"
|
||||
force = 30 //Normal attacks deal esword damage
|
||||
hitsound = 'sound/weapons/blade1.ogg'
|
||||
active = 1
|
||||
throwforce = 1//Throwing or dropping the item deletes it.
|
||||
throw_speed = 3
|
||||
throw_range = 1
|
||||
w_class = WEIGHT_CLASS_BULKY//So you can't hide it in your pocket or some such.
|
||||
var/datum/effect_system/spark_spread/spark_system
|
||||
sharpness = IS_SHARP
|
||||
|
||||
//Most of the other special functions are handled in their own files. aka special snowflake code so kewl
|
||||
/obj/item/weapon/melee/energy/blade/Initialize()
|
||||
. = ..()
|
||||
spark_system = new /datum/effect_system/spark_spread()
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
|
||||
/obj/item/weapon/melee/energy/blade/attack_self(mob/user)
|
||||
return
|
||||
|
||||
/obj/item/weapon/melee/energy/blade/hardlight
|
||||
name = "hardlight blade"
|
||||
desc = "An extremely sharp blade made out of hard light. Packs quite a punch."
|
||||
icon_state = "lightblade"
|
||||
item_state = "lightblade"
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
queue_smooth_neighbors(src)
|
||||
|
||||
/obj/structure/table/narsie_act()
|
||||
new /obj/structure/table/wood(src.loc)
|
||||
new /obj/structure/table/wood(src.loc)
|
||||
|
||||
/obj/structure/table/ratvar_act()
|
||||
new /obj/structure/table/reinforced/brass(src.loc)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,21 @@
|
||||
/atom/proc/investigate_log(message, subject)
|
||||
if(!message || !subject)
|
||||
return
|
||||
var/F = file("[GLOB.log_directory]/[subject].html")
|
||||
F << "<small>[time_stamp()] \ref[src] ([x],[y],[z])</small> || [src] [message]<br>"
|
||||
|
||||
|
||||
/client/proc/investigate_show( subject in list("hrefs","notes, memos, watchlist","singulo","wires","telesci", "gravity", "records", "cargo", "supermatter", "atmos", "experimentor", "botany") )
|
||||
set name = "Investigate"
|
||||
set category = "Admin"
|
||||
if(!holder)
|
||||
return
|
||||
switch(subject)
|
||||
if("notes, memos, watchlist")
|
||||
browse_messages()
|
||||
else
|
||||
var/F = file("[GLOB.log_directory]/[subject].html")
|
||||
if(!fexists(F))
|
||||
to_chat(src, "<span class='danger'>No [subject] logfile was found.</span>")
|
||||
return
|
||||
src << browse(F,"window=investigate[subject];size=800x300")
|
||||
/atom/proc/investigate_log(message, subject)
|
||||
if(!message || !subject)
|
||||
return
|
||||
var/F = file("[GLOB.log_directory]/[subject].html")
|
||||
F << "<small>[time_stamp()] \ref[src] ([x],[y],[z])</small> || [src] [message]<br>"
|
||||
|
||||
|
||||
/client/proc/investigate_show( subject in list("hrefs","notes, memos, watchlist","singulo","wires","telesci", "gravity", "records", "cargo", "supermatter", "atmos", "experimentor", "botany") )
|
||||
set name = "Investigate"
|
||||
set category = "Admin"
|
||||
if(!holder)
|
||||
return
|
||||
switch(subject)
|
||||
if("notes, memos, watchlist")
|
||||
browse_messages()
|
||||
else
|
||||
var/F = file("[GLOB.log_directory]/[subject].html")
|
||||
if(!fexists(F))
|
||||
to_chat(src, "<span class='danger'>No [subject] logfile was found.</span>")
|
||||
return
|
||||
src << browse(F,"window=investigate[subject];size=800x300")
|
||||
|
||||
@@ -1,134 +1,134 @@
|
||||
/obj/machinery/meter
|
||||
name = "gas flow meter"
|
||||
desc = "It measures something."
|
||||
icon = 'icons/obj/meter.dmi'
|
||||
icon_state = "meterX"
|
||||
var/atom/target = null
|
||||
anchored = 1
|
||||
power_channel = ENVIRON
|
||||
var/frequency = 0
|
||||
var/id_tag
|
||||
use_power = 1
|
||||
idle_power_usage = 2
|
||||
active_power_usage = 4
|
||||
obj_integrity = 150
|
||||
max_integrity = 150
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 100, bomb = 0, bio = 100, rad = 100, fire = 40, acid = 0)
|
||||
|
||||
|
||||
/obj/machinery/meter/Initialize(mapload)
|
||||
. = ..()
|
||||
SSair.atmos_machinery += src
|
||||
if (mapload && !target)
|
||||
target = locate(/obj/machinery/atmospherics/pipe) in loc
|
||||
|
||||
/obj/machinery/meter/Destroy()
|
||||
SSair.atmos_machinery -= src
|
||||
src.target = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/meter/process_atmos()
|
||||
if(!target)
|
||||
icon_state = "meterX"
|
||||
return 0
|
||||
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
icon_state = "meter0"
|
||||
return 0
|
||||
|
||||
use_power(5)
|
||||
|
||||
var/datum/gas_mixture/environment = target.return_air()
|
||||
if(!environment)
|
||||
icon_state = "meterX"
|
||||
return 0
|
||||
|
||||
var/env_pressure = environment.return_pressure()
|
||||
if(env_pressure <= 0.15*ONE_ATMOSPHERE)
|
||||
icon_state = "meter0"
|
||||
else if(env_pressure <= 1.8*ONE_ATMOSPHERE)
|
||||
var/val = round(env_pressure/(ONE_ATMOSPHERE*0.3) + 0.5)
|
||||
icon_state = "meter1_[val]"
|
||||
else if(env_pressure <= 30*ONE_ATMOSPHERE)
|
||||
var/val = round(env_pressure/(ONE_ATMOSPHERE*5)-0.35) + 1
|
||||
icon_state = "meter2_[val]"
|
||||
else if(env_pressure <= 59*ONE_ATMOSPHERE)
|
||||
var/val = round(env_pressure/(ONE_ATMOSPHERE*5) - 6) + 1
|
||||
icon_state = "meter3_[val]"
|
||||
else
|
||||
icon_state = "meter4"
|
||||
|
||||
if(frequency)
|
||||
var/datum/radio_frequency/radio_connection = SSradio.return_frequency(frequency)
|
||||
|
||||
if(!radio_connection)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = new
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
signal.data = list(
|
||||
"id_tag" = id_tag,
|
||||
"device" = "AM",
|
||||
"pressure" = round(env_pressure),
|
||||
"sigtype" = "status"
|
||||
)
|
||||
radio_connection.post_signal(src, signal)
|
||||
|
||||
/obj/machinery/meter/proc/status()
|
||||
var/t = ""
|
||||
if (src.target)
|
||||
var/datum/gas_mixture/environment = target.return_air()
|
||||
if(environment)
|
||||
t += "The pressure gauge reads [round(environment.return_pressure(), 0.01)] kPa; [round(environment.temperature,0.01)] K ([round(environment.temperature-T0C,0.01)]°C)"
|
||||
else
|
||||
t += "The sensor error light is blinking."
|
||||
else
|
||||
t += "The connect error light is blinking."
|
||||
return t
|
||||
|
||||
/obj/machinery/meter/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, status())
|
||||
|
||||
|
||||
/obj/machinery/meter/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if (istype(W, /obj/item/weapon/wrench))
|
||||
playsound(src.loc, W.usesound, 50, 1)
|
||||
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
|
||||
if (do_after(user, 40*W.toolspeed, target = src))
|
||||
user.visible_message( \
|
||||
"[user] unfastens \the [src].", \
|
||||
"<span class='notice'>You unfasten \the [src].</span>", \
|
||||
"<span class='italics'>You hear ratchet.</span>")
|
||||
new /obj/item/pipe_meter(src.loc)
|
||||
qdel(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/meter/attack_ai(mob/user)
|
||||
return src.attack_hand(user)
|
||||
|
||||
/obj/machinery/meter/attack_paw(mob/user)
|
||||
return src.attack_hand(user)
|
||||
|
||||
/obj/machinery/meter/attack_hand(mob/user)
|
||||
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return 1
|
||||
else
|
||||
to_chat(usr, status())
|
||||
return 1
|
||||
|
||||
/obj/machinery/meter/singularity_pull(S, current_size)
|
||||
if(current_size >= STAGE_FIVE)
|
||||
new /obj/item/pipe_meter(loc)
|
||||
qdel(src)
|
||||
|
||||
// TURF METER - REPORTS A TILE'S AIR CONTENTS
|
||||
// why are you yelling?
|
||||
/obj/machinery/meter/turf
|
||||
|
||||
/obj/machinery/meter/turf/Initialize()
|
||||
..()
|
||||
src.target = loc
|
||||
/obj/machinery/meter
|
||||
name = "gas flow meter"
|
||||
desc = "It measures something."
|
||||
icon = 'icons/obj/meter.dmi'
|
||||
icon_state = "meterX"
|
||||
var/atom/target = null
|
||||
anchored = 1
|
||||
power_channel = ENVIRON
|
||||
var/frequency = 0
|
||||
var/id_tag
|
||||
use_power = 1
|
||||
idle_power_usage = 2
|
||||
active_power_usage = 4
|
||||
obj_integrity = 150
|
||||
max_integrity = 150
|
||||
armor = list(melee = 0, bullet = 0, laser = 0, energy = 100, bomb = 0, bio = 100, rad = 100, fire = 40, acid = 0)
|
||||
|
||||
|
||||
/obj/machinery/meter/Initialize(mapload)
|
||||
. = ..()
|
||||
SSair.atmos_machinery += src
|
||||
if (mapload && !target)
|
||||
target = locate(/obj/machinery/atmospherics/pipe) in loc
|
||||
|
||||
/obj/machinery/meter/Destroy()
|
||||
SSair.atmos_machinery -= src
|
||||
src.target = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/meter/process_atmos()
|
||||
if(!target)
|
||||
icon_state = "meterX"
|
||||
return 0
|
||||
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
icon_state = "meter0"
|
||||
return 0
|
||||
|
||||
use_power(5)
|
||||
|
||||
var/datum/gas_mixture/environment = target.return_air()
|
||||
if(!environment)
|
||||
icon_state = "meterX"
|
||||
return 0
|
||||
|
||||
var/env_pressure = environment.return_pressure()
|
||||
if(env_pressure <= 0.15*ONE_ATMOSPHERE)
|
||||
icon_state = "meter0"
|
||||
else if(env_pressure <= 1.8*ONE_ATMOSPHERE)
|
||||
var/val = round(env_pressure/(ONE_ATMOSPHERE*0.3) + 0.5)
|
||||
icon_state = "meter1_[val]"
|
||||
else if(env_pressure <= 30*ONE_ATMOSPHERE)
|
||||
var/val = round(env_pressure/(ONE_ATMOSPHERE*5)-0.35) + 1
|
||||
icon_state = "meter2_[val]"
|
||||
else if(env_pressure <= 59*ONE_ATMOSPHERE)
|
||||
var/val = round(env_pressure/(ONE_ATMOSPHERE*5) - 6) + 1
|
||||
icon_state = "meter3_[val]"
|
||||
else
|
||||
icon_state = "meter4"
|
||||
|
||||
if(frequency)
|
||||
var/datum/radio_frequency/radio_connection = SSradio.return_frequency(frequency)
|
||||
|
||||
if(!radio_connection)
|
||||
return
|
||||
|
||||
var/datum/signal/signal = new
|
||||
signal.source = src
|
||||
signal.transmission_method = 1
|
||||
signal.data = list(
|
||||
"id_tag" = id_tag,
|
||||
"device" = "AM",
|
||||
"pressure" = round(env_pressure),
|
||||
"sigtype" = "status"
|
||||
)
|
||||
radio_connection.post_signal(src, signal)
|
||||
|
||||
/obj/machinery/meter/proc/status()
|
||||
var/t = ""
|
||||
if (src.target)
|
||||
var/datum/gas_mixture/environment = target.return_air()
|
||||
if(environment)
|
||||
t += "The pressure gauge reads [round(environment.return_pressure(), 0.01)] kPa; [round(environment.temperature,0.01)] K ([round(environment.temperature-T0C,0.01)]°C)"
|
||||
else
|
||||
t += "The sensor error light is blinking."
|
||||
else
|
||||
t += "The connect error light is blinking."
|
||||
return t
|
||||
|
||||
/obj/machinery/meter/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, status())
|
||||
|
||||
|
||||
/obj/machinery/meter/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if (istype(W, /obj/item/weapon/wrench))
|
||||
playsound(src.loc, W.usesound, 50, 1)
|
||||
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
|
||||
if (do_after(user, 40*W.toolspeed, target = src))
|
||||
user.visible_message( \
|
||||
"[user] unfastens \the [src].", \
|
||||
"<span class='notice'>You unfasten \the [src].</span>", \
|
||||
"<span class='italics'>You hear ratchet.</span>")
|
||||
new /obj/item/pipe_meter(src.loc)
|
||||
qdel(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/meter/attack_ai(mob/user)
|
||||
return src.attack_hand(user)
|
||||
|
||||
/obj/machinery/meter/attack_paw(mob/user)
|
||||
return src.attack_hand(user)
|
||||
|
||||
/obj/machinery/meter/attack_hand(mob/user)
|
||||
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return 1
|
||||
else
|
||||
to_chat(usr, status())
|
||||
return 1
|
||||
|
||||
/obj/machinery/meter/singularity_pull(S, current_size)
|
||||
if(current_size >= STAGE_FIVE)
|
||||
new /obj/item/pipe_meter(loc)
|
||||
qdel(src)
|
||||
|
||||
// TURF METER - REPORTS A TILE'S AIR CONTENTS
|
||||
// why are you yelling?
|
||||
/obj/machinery/meter/turf
|
||||
|
||||
/obj/machinery/meter/turf/Initialize()
|
||||
..()
|
||||
src.target = loc
|
||||
|
||||
@@ -1,309 +1,309 @@
|
||||
|
||||
//Academy Items
|
||||
|
||||
/obj/singularity/academy
|
||||
dissipate = 0
|
||||
move_self = 0
|
||||
grav_pull = 1
|
||||
|
||||
/obj/singularity/academy/admin_investigate_setup()
|
||||
return
|
||||
|
||||
/obj/singularity/academy/process()
|
||||
eat()
|
||||
if(prob(1))
|
||||
mezzer()
|
||||
|
||||
|
||||
/obj/item/clothing/glasses/meson/truesight
|
||||
name = "The Lens of Truesight"
|
||||
desc = "I can see forever!"
|
||||
icon_state = "monocle"
|
||||
item_state = "headset"
|
||||
|
||||
|
||||
/obj/structure/academy_wizard_spawner
|
||||
name = "Academy Defensive System"
|
||||
desc = "Made by Abjuration Inc"
|
||||
icon = 'icons/obj/cult.dmi'
|
||||
icon_state = "forge"
|
||||
anchored = 1
|
||||
obj_integrity = 200
|
||||
max_integrity = 200
|
||||
var/mob/living/current_wizard = null
|
||||
var/next_check = 0
|
||||
var/cooldown = 600
|
||||
var/faction = "wizard"
|
||||
var/braindead_check = 0
|
||||
|
||||
/obj/structure/academy_wizard_spawner/New()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/structure/academy_wizard_spawner/Destroy()
|
||||
if(!broken)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/academy_wizard_spawner/process()
|
||||
if(next_check < world.time)
|
||||
if(!current_wizard)
|
||||
for(var/mob/living/L in GLOB.player_list)
|
||||
if(L.z == src.z && L.stat != DEAD && !(faction in L.faction))
|
||||
summon_wizard()
|
||||
break
|
||||
else
|
||||
if(current_wizard.stat == DEAD)
|
||||
current_wizard = null
|
||||
summon_wizard()
|
||||
if(!current_wizard.client)
|
||||
if(!braindead_check)
|
||||
braindead_check = 1
|
||||
else
|
||||
braindead_check = 0
|
||||
give_control()
|
||||
next_check = world.time + cooldown
|
||||
|
||||
/obj/structure/academy_wizard_spawner/proc/give_control()
|
||||
set waitfor = FALSE
|
||||
|
||||
if(!current_wizard)
|
||||
return
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as Wizard Academy Defender?", "wizard", null, be_special_flag = ROLE_WIZARD, M = current_wizard)
|
||||
var/mob/dead/observer/chosen = null
|
||||
|
||||
if(candidates.len)
|
||||
chosen = pick(candidates)
|
||||
message_admins("[key_name_admin(chosen)] was spawned as Wizard Academy Defender")
|
||||
current_wizard.ghostize() // on the off chance braindead defender gets back in
|
||||
current_wizard.key = chosen.key
|
||||
|
||||
/obj/structure/academy_wizard_spawner/proc/summon_wizard()
|
||||
var/turf/T = src.loc
|
||||
|
||||
var/mob/living/carbon/human/wizbody = new(T)
|
||||
wizbody.equipOutfit(/datum/outfit/wizard/academy)
|
||||
var/obj/item/weapon/implant/exile/Implant = new/obj/item/weapon/implant/exile(wizbody)
|
||||
Implant.implant(wizbody)
|
||||
wizbody.faction |= "wizard"
|
||||
wizbody.real_name = "Academy Teacher"
|
||||
wizbody.name = "Academy Teacher"
|
||||
|
||||
var/datum/mind/wizmind = new /datum/mind()
|
||||
wizmind.name = "Wizard Defender"
|
||||
wizmind.special_role = "Academy Defender"
|
||||
var/datum/objective/O = new("Protect Wizard Academy from the intruders")
|
||||
wizmind.objectives += O
|
||||
wizmind.transfer_to(wizbody)
|
||||
SSticker.mode.wizards |= wizmind
|
||||
|
||||
wizmind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt)
|
||||
wizmind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile)
|
||||
wizmind.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball)
|
||||
|
||||
current_wizard = wizbody
|
||||
|
||||
give_control()
|
||||
|
||||
/obj/structure/academy_wizard_spawner/deconstruct(disassembled = TRUE)
|
||||
if(!broken)
|
||||
broken = 1
|
||||
visible_message("<span class='warning'>[src] breaks down!</span>")
|
||||
icon_state = "forge_off"
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/outfit/wizard/academy
|
||||
name = "Academy Wizard"
|
||||
r_pocket = null
|
||||
r_hand = null
|
||||
suit = /obj/item/clothing/suit/wizrobe/red
|
||||
head = /obj/item/clothing/head/wizard/red
|
||||
backpack_contents = list(/obj/item/weapon/storage/box/survival = 1)
|
||||
|
||||
/obj/item/weapon/dice/d20/fate
|
||||
name = "Die of Fate"
|
||||
desc = "A die with twenty sides. You can feel unearthly energies radiating from it. Using this might be VERY risky."
|
||||
icon_state = "d20"
|
||||
sides = 20
|
||||
can_be_rigged = FALSE
|
||||
var/reusable = 1
|
||||
var/used = 0
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/one_use
|
||||
reusable = 0
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/diceroll(mob/user)
|
||||
..()
|
||||
if(!used)
|
||||
if(!ishuman(user) || !user.mind || (user.mind in SSticker.mode.wizards))
|
||||
to_chat(user, "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans!</span>")
|
||||
return
|
||||
if(rigged)
|
||||
effect(user,rigged)
|
||||
else
|
||||
effect(user,result)
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/equipped(mob/user, slot)
|
||||
if(!ishuman(user) || !user.mind || (user.mind in SSticker.mode.wizards))
|
||||
to_chat(user, "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans! You should leave it alone.</span>")
|
||||
user.drop_item()
|
||||
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/proc/effect(var/mob/living/carbon/human/user,roll)
|
||||
if(!reusable)
|
||||
used = 1
|
||||
visible_message("<span class='userdanger'>The die flare briefly.</span>")
|
||||
switch(roll)
|
||||
if(1)
|
||||
//Dust
|
||||
user.dust()
|
||||
if(2)
|
||||
//Death
|
||||
user.death()
|
||||
if(3)
|
||||
//Swarm of creatures
|
||||
for(var/direction in GLOB.alldirs)
|
||||
var/turf/T = get_turf(src)
|
||||
new /mob/living/simple_animal/hostile/creature(get_step(T,direction))
|
||||
if(4)
|
||||
//Destroy Equipment
|
||||
for (var/obj/item/I in user)
|
||||
if (istype(I, /obj/item/weapon/implant))
|
||||
continue
|
||||
qdel(I)
|
||||
if(5)
|
||||
//Monkeying
|
||||
user.monkeyize()
|
||||
if(6)
|
||||
//Cut speed
|
||||
var/datum/species/S = user.dna.species
|
||||
S.speedmod += 1
|
||||
if(7)
|
||||
//Throw
|
||||
user.Stun(3)
|
||||
user.adjustBruteLoss(50)
|
||||
var/throw_dir = pick(GLOB.cardinal)
|
||||
var/atom/throw_target = get_edge_target_turf(user, throw_dir)
|
||||
user.throw_at(throw_target, 200, 4)
|
||||
if(8)
|
||||
//Fueltank Explosion
|
||||
explosion(src.loc,-1,0,2, flame_range = 2)
|
||||
if(9)
|
||||
//Cold
|
||||
var/datum/disease/D = new /datum/disease/cold
|
||||
user.ForceContractDisease(D)
|
||||
if(10)
|
||||
//Nothing
|
||||
visible_message("<span class='notice'>[src] roll perfectly.</span>")
|
||||
if(11)
|
||||
//Cookie
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/cookie/C = new(get_turf(src))
|
||||
C.name = "Cookie of Fate"
|
||||
if(12)
|
||||
//Healing
|
||||
user.revive(full_heal = 1, admin_revive = 1)
|
||||
if(13)
|
||||
//Mad Dosh
|
||||
var/turf/Start = get_turf(src)
|
||||
for(var/direction in GLOB.alldirs)
|
||||
var/turf/T = get_step(Start,direction)
|
||||
if(rand(0,1))
|
||||
new /obj/item/stack/spacecash/c1000(T)
|
||||
else
|
||||
var/obj/item/weapon/storage/bag/money/M = new(T)
|
||||
for(var/i in 1 to rand(5,50))
|
||||
new /obj/item/weapon/coin/gold(M)
|
||||
if(14)
|
||||
//Free Gun
|
||||
new /obj/item/weapon/gun/ballistic/revolver/mateba(get_turf(src))
|
||||
if(15)
|
||||
//Random One-use spellbook
|
||||
new /obj/item/weapon/spellbook/oneuse/random(get_turf(src))
|
||||
if(16)
|
||||
//Servant & Servant Summon
|
||||
var/mob/living/carbon/human/H = new(get_turf(src))
|
||||
H.equipOutfit(/datum/outfit/butler)
|
||||
var/datum/mind/servant_mind = new /datum/mind()
|
||||
var/datum/objective/O = new("Serve [user.real_name].")
|
||||
servant_mind.objectives += O
|
||||
servant_mind.transfer_to(H)
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [user.real_name] Servant?", "wizard", mob = H)
|
||||
var/mob/dead/observer/chosen = null
|
||||
|
||||
if(candidates.len)
|
||||
chosen = pick(candidates)
|
||||
message_admins("[key_name_admin(chosen)] was spawned as Dice Servant")
|
||||
H.key = chosen.key
|
||||
|
||||
var/obj/effect/proc_holder/spell/targeted/summonmob/S = new
|
||||
S.target_mob = H
|
||||
user.mind.AddSpell(S)
|
||||
|
||||
if(17)
|
||||
//Tator Kit
|
||||
new /obj/item/weapon/storage/box/syndicate/(get_turf(src))
|
||||
if(18)
|
||||
//Captain ID
|
||||
new /obj/item/weapon/card/id/captains_spare(get_turf(src))
|
||||
if(19)
|
||||
//Instrinct Resistance
|
||||
to_chat(user, "<span class='notice'>You feel robust.</span>")
|
||||
var/datum/species/S = user.dna.species
|
||||
S.brutemod *= 0.5
|
||||
S.burnmod *= 0.5
|
||||
S.coldmod *= 0.5
|
||||
if(20)
|
||||
//Free wizard!
|
||||
user.mind.make_Wizard()
|
||||
|
||||
|
||||
/datum/outfit/butler
|
||||
name = "Butler"
|
||||
uniform = /obj/item/clothing/under/suit_jacket/really_black
|
||||
shoes = /obj/item/clothing/shoes/laceup
|
||||
head = /obj/item/clothing/head/bowler
|
||||
glasses = /obj/item/clothing/glasses/monocle
|
||||
gloves = /obj/item/clothing/gloves/color/white
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/summonmob
|
||||
name = "Summon Servant"
|
||||
desc = "This spell can be used to call your servant, whenever you need it."
|
||||
charge_max = 100
|
||||
clothes_req = 0
|
||||
invocation = "JE VES"
|
||||
invocation_type = "whisper"
|
||||
range = -1
|
||||
level_max = 0 //cannot be improved
|
||||
cooldown_min = 100
|
||||
include_user = 1
|
||||
|
||||
var/mob/living/target_mob
|
||||
|
||||
action_icon_state = "summons"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/summonmob/cast(list/targets,mob/user = usr)
|
||||
if(!target_mob)
|
||||
return
|
||||
var/turf/Start = get_turf(user)
|
||||
for(var/direction in GLOB.alldirs)
|
||||
var/turf/T = get_step(Start,direction)
|
||||
if(!T.density)
|
||||
target_mob.Move(T)
|
||||
|
||||
/obj/structure/ladder/unbreakable/rune
|
||||
name = "Teleportation Rune"
|
||||
desc = "Could lead anywhere."
|
||||
icon = 'icons/obj/rune.dmi'
|
||||
icon_state = "1"
|
||||
color = rgb(0,0,255)
|
||||
|
||||
/obj/structure/ladder/unbreakable/rune/update_icon()
|
||||
return
|
||||
|
||||
/obj/structure/ladder/unbreakable/rune/show_fluff_message(up,mob/user)
|
||||
user.visible_message("[user] activates \the [src].","<span class='notice'>You activate \the [src].</span>")
|
||||
|
||||
/obj/structure/ladder/can_use(mob/user)
|
||||
if(user.mind in SSticker.mode.wizards)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
//Academy Items
|
||||
|
||||
/obj/singularity/academy
|
||||
dissipate = 0
|
||||
move_self = 0
|
||||
grav_pull = 1
|
||||
|
||||
/obj/singularity/academy/admin_investigate_setup()
|
||||
return
|
||||
|
||||
/obj/singularity/academy/process()
|
||||
eat()
|
||||
if(prob(1))
|
||||
mezzer()
|
||||
|
||||
|
||||
/obj/item/clothing/glasses/meson/truesight
|
||||
name = "The Lens of Truesight"
|
||||
desc = "I can see forever!"
|
||||
icon_state = "monocle"
|
||||
item_state = "headset"
|
||||
|
||||
|
||||
/obj/structure/academy_wizard_spawner
|
||||
name = "Academy Defensive System"
|
||||
desc = "Made by Abjuration Inc"
|
||||
icon = 'icons/obj/cult.dmi'
|
||||
icon_state = "forge"
|
||||
anchored = 1
|
||||
obj_integrity = 200
|
||||
max_integrity = 200
|
||||
var/mob/living/current_wizard = null
|
||||
var/next_check = 0
|
||||
var/cooldown = 600
|
||||
var/faction = "wizard"
|
||||
var/braindead_check = 0
|
||||
|
||||
/obj/structure/academy_wizard_spawner/New()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/structure/academy_wizard_spawner/Destroy()
|
||||
if(!broken)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/academy_wizard_spawner/process()
|
||||
if(next_check < world.time)
|
||||
if(!current_wizard)
|
||||
for(var/mob/living/L in GLOB.player_list)
|
||||
if(L.z == src.z && L.stat != DEAD && !(faction in L.faction))
|
||||
summon_wizard()
|
||||
break
|
||||
else
|
||||
if(current_wizard.stat == DEAD)
|
||||
current_wizard = null
|
||||
summon_wizard()
|
||||
if(!current_wizard.client)
|
||||
if(!braindead_check)
|
||||
braindead_check = 1
|
||||
else
|
||||
braindead_check = 0
|
||||
give_control()
|
||||
next_check = world.time + cooldown
|
||||
|
||||
/obj/structure/academy_wizard_spawner/proc/give_control()
|
||||
set waitfor = FALSE
|
||||
|
||||
if(!current_wizard)
|
||||
return
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as Wizard Academy Defender?", "wizard", null, be_special_flag = ROLE_WIZARD, M = current_wizard)
|
||||
var/mob/dead/observer/chosen = null
|
||||
|
||||
if(candidates.len)
|
||||
chosen = pick(candidates)
|
||||
message_admins("[key_name_admin(chosen)] was spawned as Wizard Academy Defender")
|
||||
current_wizard.ghostize() // on the off chance braindead defender gets back in
|
||||
current_wizard.key = chosen.key
|
||||
|
||||
/obj/structure/academy_wizard_spawner/proc/summon_wizard()
|
||||
var/turf/T = src.loc
|
||||
|
||||
var/mob/living/carbon/human/wizbody = new(T)
|
||||
wizbody.equipOutfit(/datum/outfit/wizard/academy)
|
||||
var/obj/item/weapon/implant/exile/Implant = new/obj/item/weapon/implant/exile(wizbody)
|
||||
Implant.implant(wizbody)
|
||||
wizbody.faction |= "wizard"
|
||||
wizbody.real_name = "Academy Teacher"
|
||||
wizbody.name = "Academy Teacher"
|
||||
|
||||
var/datum/mind/wizmind = new /datum/mind()
|
||||
wizmind.name = "Wizard Defender"
|
||||
wizmind.special_role = "Academy Defender"
|
||||
var/datum/objective/O = new("Protect Wizard Academy from the intruders")
|
||||
wizmind.objectives += O
|
||||
wizmind.transfer_to(wizbody)
|
||||
SSticker.mode.wizards |= wizmind
|
||||
|
||||
wizmind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt)
|
||||
wizmind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile)
|
||||
wizmind.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball)
|
||||
|
||||
current_wizard = wizbody
|
||||
|
||||
give_control()
|
||||
|
||||
/obj/structure/academy_wizard_spawner/deconstruct(disassembled = TRUE)
|
||||
if(!broken)
|
||||
broken = 1
|
||||
visible_message("<span class='warning'>[src] breaks down!</span>")
|
||||
icon_state = "forge_off"
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/outfit/wizard/academy
|
||||
name = "Academy Wizard"
|
||||
r_pocket = null
|
||||
r_hand = null
|
||||
suit = /obj/item/clothing/suit/wizrobe/red
|
||||
head = /obj/item/clothing/head/wizard/red
|
||||
backpack_contents = list(/obj/item/weapon/storage/box/survival = 1)
|
||||
|
||||
/obj/item/weapon/dice/d20/fate
|
||||
name = "Die of Fate"
|
||||
desc = "A die with twenty sides. You can feel unearthly energies radiating from it. Using this might be VERY risky."
|
||||
icon_state = "d20"
|
||||
sides = 20
|
||||
can_be_rigged = FALSE
|
||||
var/reusable = 1
|
||||
var/used = 0
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/one_use
|
||||
reusable = 0
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/diceroll(mob/user)
|
||||
..()
|
||||
if(!used)
|
||||
if(!ishuman(user) || !user.mind || (user.mind in SSticker.mode.wizards))
|
||||
to_chat(user, "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans!</span>")
|
||||
return
|
||||
if(rigged)
|
||||
effect(user,rigged)
|
||||
else
|
||||
effect(user,result)
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/equipped(mob/user, slot)
|
||||
if(!ishuman(user) || !user.mind || (user.mind in SSticker.mode.wizards))
|
||||
to_chat(user, "<span class='warning'>You feel the magic of the dice is restricted to ordinary humans! You should leave it alone.</span>")
|
||||
user.drop_item()
|
||||
|
||||
|
||||
/obj/item/weapon/dice/d20/fate/proc/effect(var/mob/living/carbon/human/user,roll)
|
||||
if(!reusable)
|
||||
used = 1
|
||||
visible_message("<span class='userdanger'>The die flare briefly.</span>")
|
||||
switch(roll)
|
||||
if(1)
|
||||
//Dust
|
||||
user.dust()
|
||||
if(2)
|
||||
//Death
|
||||
user.death()
|
||||
if(3)
|
||||
//Swarm of creatures
|
||||
for(var/direction in GLOB.alldirs)
|
||||
var/turf/T = get_turf(src)
|
||||
new /mob/living/simple_animal/hostile/creature(get_step(T,direction))
|
||||
if(4)
|
||||
//Destroy Equipment
|
||||
for (var/obj/item/I in user)
|
||||
if (istype(I, /obj/item/weapon/implant))
|
||||
continue
|
||||
qdel(I)
|
||||
if(5)
|
||||
//Monkeying
|
||||
user.monkeyize()
|
||||
if(6)
|
||||
//Cut speed
|
||||
var/datum/species/S = user.dna.species
|
||||
S.speedmod += 1
|
||||
if(7)
|
||||
//Throw
|
||||
user.Stun(3)
|
||||
user.adjustBruteLoss(50)
|
||||
var/throw_dir = pick(GLOB.cardinal)
|
||||
var/atom/throw_target = get_edge_target_turf(user, throw_dir)
|
||||
user.throw_at(throw_target, 200, 4)
|
||||
if(8)
|
||||
//Fueltank Explosion
|
||||
explosion(src.loc,-1,0,2, flame_range = 2)
|
||||
if(9)
|
||||
//Cold
|
||||
var/datum/disease/D = new /datum/disease/cold
|
||||
user.ForceContractDisease(D)
|
||||
if(10)
|
||||
//Nothing
|
||||
visible_message("<span class='notice'>[src] roll perfectly.</span>")
|
||||
if(11)
|
||||
//Cookie
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/cookie/C = new(get_turf(src))
|
||||
C.name = "Cookie of Fate"
|
||||
if(12)
|
||||
//Healing
|
||||
user.revive(full_heal = 1, admin_revive = 1)
|
||||
if(13)
|
||||
//Mad Dosh
|
||||
var/turf/Start = get_turf(src)
|
||||
for(var/direction in GLOB.alldirs)
|
||||
var/turf/T = get_step(Start,direction)
|
||||
if(rand(0,1))
|
||||
new /obj/item/stack/spacecash/c1000(T)
|
||||
else
|
||||
var/obj/item/weapon/storage/bag/money/M = new(T)
|
||||
for(var/i in 1 to rand(5,50))
|
||||
new /obj/item/weapon/coin/gold(M)
|
||||
if(14)
|
||||
//Free Gun
|
||||
new /obj/item/weapon/gun/ballistic/revolver/mateba(get_turf(src))
|
||||
if(15)
|
||||
//Random One-use spellbook
|
||||
new /obj/item/weapon/spellbook/oneuse/random(get_turf(src))
|
||||
if(16)
|
||||
//Servant & Servant Summon
|
||||
var/mob/living/carbon/human/H = new(get_turf(src))
|
||||
H.equipOutfit(/datum/outfit/butler)
|
||||
var/datum/mind/servant_mind = new /datum/mind()
|
||||
var/datum/objective/O = new("Serve [user.real_name].")
|
||||
servant_mind.objectives += O
|
||||
servant_mind.transfer_to(H)
|
||||
|
||||
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [user.real_name] Servant?", "wizard", mob = H)
|
||||
var/mob/dead/observer/chosen = null
|
||||
|
||||
if(candidates.len)
|
||||
chosen = pick(candidates)
|
||||
message_admins("[key_name_admin(chosen)] was spawned as Dice Servant")
|
||||
H.key = chosen.key
|
||||
|
||||
var/obj/effect/proc_holder/spell/targeted/summonmob/S = new
|
||||
S.target_mob = H
|
||||
user.mind.AddSpell(S)
|
||||
|
||||
if(17)
|
||||
//Tator Kit
|
||||
new /obj/item/weapon/storage/box/syndicate/(get_turf(src))
|
||||
if(18)
|
||||
//Captain ID
|
||||
new /obj/item/weapon/card/id/captains_spare(get_turf(src))
|
||||
if(19)
|
||||
//Instrinct Resistance
|
||||
to_chat(user, "<span class='notice'>You feel robust.</span>")
|
||||
var/datum/species/S = user.dna.species
|
||||
S.brutemod *= 0.5
|
||||
S.burnmod *= 0.5
|
||||
S.coldmod *= 0.5
|
||||
if(20)
|
||||
//Free wizard!
|
||||
user.mind.make_Wizard()
|
||||
|
||||
|
||||
/datum/outfit/butler
|
||||
name = "Butler"
|
||||
uniform = /obj/item/clothing/under/suit_jacket/really_black
|
||||
shoes = /obj/item/clothing/shoes/laceup
|
||||
head = /obj/item/clothing/head/bowler
|
||||
glasses = /obj/item/clothing/glasses/monocle
|
||||
gloves = /obj/item/clothing/gloves/color/white
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/summonmob
|
||||
name = "Summon Servant"
|
||||
desc = "This spell can be used to call your servant, whenever you need it."
|
||||
charge_max = 100
|
||||
clothes_req = 0
|
||||
invocation = "JE VES"
|
||||
invocation_type = "whisper"
|
||||
range = -1
|
||||
level_max = 0 //cannot be improved
|
||||
cooldown_min = 100
|
||||
include_user = 1
|
||||
|
||||
var/mob/living/target_mob
|
||||
|
||||
action_icon_state = "summons"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/summonmob/cast(list/targets,mob/user = usr)
|
||||
if(!target_mob)
|
||||
return
|
||||
var/turf/Start = get_turf(user)
|
||||
for(var/direction in GLOB.alldirs)
|
||||
var/turf/T = get_step(Start,direction)
|
||||
if(!T.density)
|
||||
target_mob.Move(T)
|
||||
|
||||
/obj/structure/ladder/unbreakable/rune
|
||||
name = "Teleportation Rune"
|
||||
desc = "Could lead anywhere."
|
||||
icon = 'icons/obj/rune.dmi'
|
||||
icon_state = "1"
|
||||
color = rgb(0,0,255)
|
||||
|
||||
/obj/structure/ladder/unbreakable/rune/update_icon()
|
||||
return
|
||||
|
||||
/obj/structure/ladder/unbreakable/rune/show_fluff_message(up,mob/user)
|
||||
user.visible_message("[user] activates \the [src].","<span class='notice'>You activate \the [src].</span>")
|
||||
|
||||
/obj/structure/ladder/can_use(mob/user)
|
||||
if(user.mind in SSticker.mode.wizards)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
+1643
-1643
File diff suppressed because it is too large
Load Diff
+161
-161
@@ -1,162 +1,162 @@
|
||||
|
||||
//Chef
|
||||
/obj/item/clothing/head/chefhat
|
||||
name = "chef's hat"
|
||||
item_state = "chef"
|
||||
icon_state = "chef"
|
||||
desc = "The commander in chef's head wear."
|
||||
strip_delay = 10
|
||||
put_on_delay = 10
|
||||
dog_fashion = /datum/dog_fashion/head/chef
|
||||
|
||||
/obj/item/clothing/head/chefhat/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is donning [src]! It looks like [user.p_theyre()] trying to become a chef.</span>")
|
||||
user.say("Bork Bork Bork!")
|
||||
sleep(20)
|
||||
user.visible_message("<span class='suicide'>[user] climbs into an imaginary oven!</span>")
|
||||
user.say("BOOORK!")
|
||||
playsound(user, 'sound/machines/ding.ogg', 50, 1)
|
||||
return(FIRELOSS)
|
||||
|
||||
//Captain
|
||||
/obj/item/clothing/head/caphat
|
||||
name = "captain's hat"
|
||||
desc = "It's good being the king."
|
||||
icon_state = "captain"
|
||||
item_state = "that"
|
||||
flags_inv = 0
|
||||
armor = list(melee = 25, bullet = 15, laser = 25, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 50, acid = 50)
|
||||
strip_delay = 60
|
||||
dog_fashion = /datum/dog_fashion/head/captain
|
||||
|
||||
//Captain: This is no longer space-worthy
|
||||
/obj/item/clothing/head/caphat/parade
|
||||
name = "captain's parade cap"
|
||||
desc = "Worn only by Captains with an abundance of class."
|
||||
icon_state = "capcap"
|
||||
|
||||
dog_fashion = null
|
||||
|
||||
|
||||
//Head of Personnel
|
||||
/obj/item/clothing/head/hopcap
|
||||
name = "head of personnel's cap"
|
||||
icon_state = "hopcap"
|
||||
desc = "The symbol of true bureaucratic micromanagement."
|
||||
armor = list(melee = 25, bullet = 15, laser = 25, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 50, acid = 50)
|
||||
dog_fashion = /datum/dog_fashion/head/hop
|
||||
|
||||
//Chaplain
|
||||
/obj/item/clothing/head/nun_hood
|
||||
name = "nun hood"
|
||||
desc = "Maximum piety in this star system."
|
||||
icon_state = "nun_hood"
|
||||
flags_inv = HIDEHAIR
|
||||
flags_cover = HEADCOVERSEYES
|
||||
|
||||
/obj/item/clothing/head/cage
|
||||
name = "cage"
|
||||
desc = "A cage that restrains the will of the self, allowing one to see the profane world for what it is."
|
||||
alternate_worn_icon = 'icons/mob/large-worn-icons/64x64/head.dmi'
|
||||
icon_state = "cage"
|
||||
item_state = "cage"
|
||||
worn_x_dimension = 64
|
||||
worn_y_dimension = 64
|
||||
|
||||
|
||||
/obj/item/clothing/head/witchunter_hat
|
||||
name = "witchunter hat"
|
||||
desc = "This hat saw much use back in the day."
|
||||
icon_state = "witchhunterhat"
|
||||
item_state = "witchhunterhat"
|
||||
flags_cover = HEADCOVERSEYES
|
||||
|
||||
//Detective
|
||||
/obj/item/clothing/head/det_hat
|
||||
name = "detective's fedora"
|
||||
desc = "There's only one man who can sniff out the dirty stench of crime, and he's likely wearing this hat."
|
||||
icon_state = "detective"
|
||||
armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50)
|
||||
var/candy_cooldown = 0
|
||||
pockets = /obj/item/weapon/storage/internal/pocket/small/detective
|
||||
dog_fashion = /datum/dog_fashion/head/detective
|
||||
|
||||
/obj/item/clothing/head/det_hat/AltClick()
|
||||
..()
|
||||
if(ismob(loc))
|
||||
var/mob/M = loc
|
||||
if(candy_cooldown < world.time)
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/candy_corn/CC = new /obj/item/weapon/reagent_containers/food/snacks/candy_corn(src)
|
||||
M.put_in_hands(CC)
|
||||
to_chat(M, "You slip a candy corn from your hat.")
|
||||
candy_cooldown = world.time+1200
|
||||
else
|
||||
to_chat(M, "You just took a candy corn! You should wait a couple minutes, lest you burn through your stash.")
|
||||
|
||||
|
||||
//Mime
|
||||
/obj/item/clothing/head/beret
|
||||
name = "beret"
|
||||
desc = "A beret, a mime's favorite headwear."
|
||||
icon_state = "beret"
|
||||
|
||||
dog_fashion = /datum/dog_fashion/head/beret
|
||||
|
||||
/obj/item/clothing/head/beret/highlander
|
||||
desc = "That was white fabric. <i>Was.</i>"
|
||||
flags = NODROP
|
||||
dog_fashion = null //THIS IS FOR SLAUGHTER, NOT PUPPIES
|
||||
|
||||
//Security
|
||||
|
||||
/obj/item/clothing/head/HoS
|
||||
name = "head of security cap"
|
||||
desc = "The robust standard-issue cap of the Head of Security. For showing the officers who's in charge."
|
||||
icon_state = "hoscap"
|
||||
armor = list(melee = 40, bullet = 30, laser = 25, energy = 10, bomb = 25, bio = 10, rad = 0, fire = 50, acid = 60)
|
||||
strip_delay = 80
|
||||
|
||||
/obj/item/clothing/head/HoS/beret
|
||||
name = "head of security beret"
|
||||
desc = "A robust beret for the Head of Security, for looking stylish while not sacrificing protection."
|
||||
icon_state = "hosberetblack"
|
||||
|
||||
/obj/item/clothing/head/warden
|
||||
name = "warden's police hat"
|
||||
desc = "It's a special armored hat issued to the Warden of a security force. Protects the head from impacts."
|
||||
icon_state = "policehelm"
|
||||
armor = list(melee = 40, bullet = 30, laser = 30, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 30, acid = 60)
|
||||
strip_delay = 60
|
||||
dog_fashion = /datum/dog_fashion/head/warden
|
||||
|
||||
/obj/item/clothing/head/beret/sec
|
||||
name = "security beret"
|
||||
desc = "A robust beret with the security insignia emblazoned on it. Uses reinforced fabric to offer sufficent protection."
|
||||
icon_state = "beret_badge"
|
||||
armor = list(melee = 40, bullet = 30, laser = 30,energy = 10, bomb = 25, bio = 0, rad = 0, fire = 20, acid = 50)
|
||||
strip_delay = 60
|
||||
dog_fashion = null
|
||||
|
||||
/obj/item/clothing/head/beret/sec/navyhos
|
||||
name = "head of security's beret"
|
||||
desc = "A special beret with the Head of Security's insignia emblazoned on it. A symbol of excellence, a badge of courage, a mark of distinction."
|
||||
icon_state = "hosberet"
|
||||
|
||||
/obj/item/clothing/head/beret/sec/navywarden
|
||||
name = "warden's beret"
|
||||
desc = "A special beret with the Warden's insignia emblazoned on it. For wardens with class."
|
||||
icon_state = "wardenberet"
|
||||
armor = list(melee = 40, bullet = 30, laser = 30, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 30, acid = 50)
|
||||
strip_delay = 60
|
||||
|
||||
/obj/item/clothing/head/beret/sec/navyofficer
|
||||
desc = "A special beret with the security insignia emblazoned on it. For officers with class."
|
||||
icon_state = "officerberet"
|
||||
|
||||
//Curator
|
||||
/obj/item/clothing/head/curator
|
||||
name = "treasure hunter's fedora"
|
||||
desc = "You got red text today kid, but it doesn't mean you have to like it."
|
||||
icon_state = "curator"
|
||||
armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50)
|
||||
|
||||
//Chef
|
||||
/obj/item/clothing/head/chefhat
|
||||
name = "chef's hat"
|
||||
item_state = "chef"
|
||||
icon_state = "chef"
|
||||
desc = "The commander in chef's head wear."
|
||||
strip_delay = 10
|
||||
put_on_delay = 10
|
||||
dog_fashion = /datum/dog_fashion/head/chef
|
||||
|
||||
/obj/item/clothing/head/chefhat/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is donning [src]! It looks like [user.p_theyre()] trying to become a chef.</span>")
|
||||
user.say("Bork Bork Bork!")
|
||||
sleep(20)
|
||||
user.visible_message("<span class='suicide'>[user] climbs into an imaginary oven!</span>")
|
||||
user.say("BOOORK!")
|
||||
playsound(user, 'sound/machines/ding.ogg', 50, 1)
|
||||
return(FIRELOSS)
|
||||
|
||||
//Captain
|
||||
/obj/item/clothing/head/caphat
|
||||
name = "captain's hat"
|
||||
desc = "It's good being the king."
|
||||
icon_state = "captain"
|
||||
item_state = "that"
|
||||
flags_inv = 0
|
||||
armor = list(melee = 25, bullet = 15, laser = 25, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 50, acid = 50)
|
||||
strip_delay = 60
|
||||
dog_fashion = /datum/dog_fashion/head/captain
|
||||
|
||||
//Captain: This is no longer space-worthy
|
||||
/obj/item/clothing/head/caphat/parade
|
||||
name = "captain's parade cap"
|
||||
desc = "Worn only by Captains with an abundance of class."
|
||||
icon_state = "capcap"
|
||||
|
||||
dog_fashion = null
|
||||
|
||||
|
||||
//Head of Personnel
|
||||
/obj/item/clothing/head/hopcap
|
||||
name = "head of personnel's cap"
|
||||
icon_state = "hopcap"
|
||||
desc = "The symbol of true bureaucratic micromanagement."
|
||||
armor = list(melee = 25, bullet = 15, laser = 25, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 50, acid = 50)
|
||||
dog_fashion = /datum/dog_fashion/head/hop
|
||||
|
||||
//Chaplain
|
||||
/obj/item/clothing/head/nun_hood
|
||||
name = "nun hood"
|
||||
desc = "Maximum piety in this star system."
|
||||
icon_state = "nun_hood"
|
||||
flags_inv = HIDEHAIR
|
||||
flags_cover = HEADCOVERSEYES
|
||||
|
||||
/obj/item/clothing/head/cage
|
||||
name = "cage"
|
||||
desc = "A cage that restrains the will of the self, allowing one to see the profane world for what it is."
|
||||
alternate_worn_icon = 'icons/mob/large-worn-icons/64x64/head.dmi'
|
||||
icon_state = "cage"
|
||||
item_state = "cage"
|
||||
worn_x_dimension = 64
|
||||
worn_y_dimension = 64
|
||||
|
||||
|
||||
/obj/item/clothing/head/witchunter_hat
|
||||
name = "witchunter hat"
|
||||
desc = "This hat saw much use back in the day."
|
||||
icon_state = "witchhunterhat"
|
||||
item_state = "witchhunterhat"
|
||||
flags_cover = HEADCOVERSEYES
|
||||
|
||||
//Detective
|
||||
/obj/item/clothing/head/det_hat
|
||||
name = "detective's fedora"
|
||||
desc = "There's only one man who can sniff out the dirty stench of crime, and he's likely wearing this hat."
|
||||
icon_state = "detective"
|
||||
armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50)
|
||||
var/candy_cooldown = 0
|
||||
pockets = /obj/item/weapon/storage/internal/pocket/small/detective
|
||||
dog_fashion = /datum/dog_fashion/head/detective
|
||||
|
||||
/obj/item/clothing/head/det_hat/AltClick()
|
||||
..()
|
||||
if(ismob(loc))
|
||||
var/mob/M = loc
|
||||
if(candy_cooldown < world.time)
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/candy_corn/CC = new /obj/item/weapon/reagent_containers/food/snacks/candy_corn(src)
|
||||
M.put_in_hands(CC)
|
||||
to_chat(M, "You slip a candy corn from your hat.")
|
||||
candy_cooldown = world.time+1200
|
||||
else
|
||||
to_chat(M, "You just took a candy corn! You should wait a couple minutes, lest you burn through your stash.")
|
||||
|
||||
|
||||
//Mime
|
||||
/obj/item/clothing/head/beret
|
||||
name = "beret"
|
||||
desc = "A beret, a mime's favorite headwear."
|
||||
icon_state = "beret"
|
||||
|
||||
dog_fashion = /datum/dog_fashion/head/beret
|
||||
|
||||
/obj/item/clothing/head/beret/highlander
|
||||
desc = "That was white fabric. <i>Was.</i>"
|
||||
flags = NODROP
|
||||
dog_fashion = null //THIS IS FOR SLAUGHTER, NOT PUPPIES
|
||||
|
||||
//Security
|
||||
|
||||
/obj/item/clothing/head/HoS
|
||||
name = "head of security cap"
|
||||
desc = "The robust standard-issue cap of the Head of Security. For showing the officers who's in charge."
|
||||
icon_state = "hoscap"
|
||||
armor = list(melee = 40, bullet = 30, laser = 25, energy = 10, bomb = 25, bio = 10, rad = 0, fire = 50, acid = 60)
|
||||
strip_delay = 80
|
||||
|
||||
/obj/item/clothing/head/HoS/beret
|
||||
name = "head of security beret"
|
||||
desc = "A robust beret for the Head of Security, for looking stylish while not sacrificing protection."
|
||||
icon_state = "hosberetblack"
|
||||
|
||||
/obj/item/clothing/head/warden
|
||||
name = "warden's police hat"
|
||||
desc = "It's a special armored hat issued to the Warden of a security force. Protects the head from impacts."
|
||||
icon_state = "policehelm"
|
||||
armor = list(melee = 40, bullet = 30, laser = 30, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 30, acid = 60)
|
||||
strip_delay = 60
|
||||
dog_fashion = /datum/dog_fashion/head/warden
|
||||
|
||||
/obj/item/clothing/head/beret/sec
|
||||
name = "security beret"
|
||||
desc = "A robust beret with the security insignia emblazoned on it. Uses reinforced fabric to offer sufficent protection."
|
||||
icon_state = "beret_badge"
|
||||
armor = list(melee = 40, bullet = 30, laser = 30,energy = 10, bomb = 25, bio = 0, rad = 0, fire = 20, acid = 50)
|
||||
strip_delay = 60
|
||||
dog_fashion = null
|
||||
|
||||
/obj/item/clothing/head/beret/sec/navyhos
|
||||
name = "head of security's beret"
|
||||
desc = "A special beret with the Head of Security's insignia emblazoned on it. A symbol of excellence, a badge of courage, a mark of distinction."
|
||||
icon_state = "hosberet"
|
||||
|
||||
/obj/item/clothing/head/beret/sec/navywarden
|
||||
name = "warden's beret"
|
||||
desc = "A special beret with the Warden's insignia emblazoned on it. For wardens with class."
|
||||
icon_state = "wardenberet"
|
||||
armor = list(melee = 40, bullet = 30, laser = 30, energy = 10, bomb = 25, bio = 0, rad = 0, fire = 30, acid = 50)
|
||||
strip_delay = 60
|
||||
|
||||
/obj/item/clothing/head/beret/sec/navyofficer
|
||||
desc = "A special beret with the security insignia emblazoned on it. For officers with class."
|
||||
icon_state = "officerberet"
|
||||
|
||||
//Curator
|
||||
/obj/item/clothing/head/curator
|
||||
name = "treasure hunter's fedora"
|
||||
desc = "You got red text today kid, but it doesn't mean you have to like it."
|
||||
icon_state = "curator"
|
||||
armor = list(melee = 25, bullet = 5, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 30, acid = 50)
|
||||
pockets = /obj/item/weapon/storage/internal/pocket/small
|
||||
@@ -242,6 +242,15 @@
|
||||
R.set_frequency(GLOB.CENTCOM_FREQ)
|
||||
R.freqlock = 1
|
||||
|
||||
/datum/outfit/ghost_cultist
|
||||
name = "Cultist Ghost"
|
||||
|
||||
uniform = /obj/item/clothing/under/color/black/ghost
|
||||
suit = /obj/item/clothing/suit/cultrobes/alt/ghost
|
||||
shoes = /obj/item/clothing/shoes/cult/alt/ghost
|
||||
head = /obj/item/clothing/head/culthood/alt/ghost
|
||||
r_hand = /obj/item/weapon/melee/cultblade/ghost
|
||||
|
||||
/datum/outfit/wizard
|
||||
name = "Blue Wizard"
|
||||
|
||||
|
||||
@@ -142,6 +142,9 @@
|
||||
name = "cultist boots"
|
||||
icon_state = "cultalt"
|
||||
|
||||
/obj/item/clothing/shoes/cult/alt/ghost
|
||||
flags = NODROP|DROPDEL
|
||||
|
||||
/obj/item/clothing/shoes/cyborg
|
||||
name = "cyborg boots"
|
||||
desc = "Shoes for a cyborg costume."
|
||||
|
||||
+188
-188
@@ -1,188 +1,188 @@
|
||||
/*
|
||||
* Job related
|
||||
*/
|
||||
|
||||
//Botanist
|
||||
/obj/item/clothing/suit/apron
|
||||
name = "apron"
|
||||
desc = "A basic blue apron."
|
||||
icon_state = "apron"
|
||||
item_state = "apron"
|
||||
blood_overlay_type = "armor"
|
||||
body_parts_covered = CHEST|GROIN
|
||||
allowed = list(/obj/item/weapon/reagent_containers/spray/plantbgone,/obj/item/device/plant_analyzer,/obj/item/seeds,/obj/item/weapon/reagent_containers/glass/bottle, /obj/item/weapon/reagent_containers/glass/beaker, /obj/item/weapon/cultivator,/obj/item/weapon/reagent_containers/spray/pestspray,/obj/item/weapon/hatchet,/obj/item/weapon/storage/bag/plants)
|
||||
|
||||
//Captain
|
||||
/obj/item/clothing/suit/captunic
|
||||
name = "captain's parade tunic"
|
||||
desc = "Worn by a Captain to show their class."
|
||||
icon_state = "captunic"
|
||||
item_state = "bio_suit"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
allowed = list(/obj/item/weapon/disk, /obj/item/weapon/stamp, /obj/item/weapon/reagent_containers/food/drinks/flask, /obj/item/weapon/melee, /obj/item/weapon/storage/lockbox/medal, /obj/item/device/assembly/flash/handheld, /obj/item/weapon/storage/box/matches, /obj/item/weapon/lighter, /obj/item/clothing/mask/cigarette, /obj/item/weapon/storage/fancy/cigarettes, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
|
||||
//Chaplain
|
||||
/obj/item/clothing/suit/hooded/chaplain_hoodie
|
||||
name = "chaplain hoodie"
|
||||
desc = "This suit says to you 'hush'!"
|
||||
icon_state = "chaplain_hoodie"
|
||||
item_state = "chaplain_hoodie"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
allowed = list(/obj/item/weapon/storage/book/bible, /obj/item/weapon/nullrod, /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater, /obj/item/weapon/storage/fancy/candle_box, /obj/item/candle, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
hoodtype = /obj/item/clothing/head/hooded/chaplain_hood
|
||||
|
||||
/obj/item/clothing/head/hooded/chaplain_hood
|
||||
name = "chaplain hood"
|
||||
desc = "For protecting your identity when immolating demons."
|
||||
icon_state = "chaplain_hood"
|
||||
body_parts_covered = HEAD
|
||||
flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS
|
||||
|
||||
/obj/item/clothing/suit/nun
|
||||
name = "nun robe"
|
||||
desc = "Maximum piety in this star system."
|
||||
icon_state = "nun"
|
||||
item_state = "nun"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS|HANDS
|
||||
flags_inv = HIDESHOES|HIDEJUMPSUIT
|
||||
allowed = list(/obj/item/weapon/storage/book/bible, /obj/item/weapon/nullrod, /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater, /obj/item/weapon/storage/fancy/candle_box, /obj/item/candle, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
|
||||
/obj/item/clothing/suit/studentuni
|
||||
name = "student robe"
|
||||
desc = "The uniform of a bygone institute of learning."
|
||||
icon_state = "studentuni"
|
||||
item_state = "studentuni"
|
||||
body_parts_covered = ARMS|CHEST
|
||||
allowed = list(/obj/item/weapon/storage/book/bible, /obj/item/weapon/nullrod, /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater, /obj/item/weapon/storage/fancy/candle_box, /obj/item/candle, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
|
||||
/obj/item/clothing/suit/witchhunter
|
||||
name = "witchunter garb"
|
||||
desc = "This worn outfit saw much use back in the day."
|
||||
icon_state = "witchhunter"
|
||||
item_state = "witchhunter"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
allowed = list(/obj/item/weapon/storage/book/bible, /obj/item/weapon/nullrod, /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater, /obj/item/weapon/storage/fancy/candle_box, /obj/item/candle, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
|
||||
//Chef
|
||||
/obj/item/clothing/suit/toggle/chef
|
||||
name = "chef's apron"
|
||||
desc = "An apron-jacket used by a high class chef."
|
||||
icon_state = "chef"
|
||||
item_state = "chef"
|
||||
gas_transfer_coefficient = 0.90
|
||||
permeability_coefficient = 0.50
|
||||
body_parts_covered = CHEST|GROIN|ARMS
|
||||
allowed = list(/obj/item/weapon/kitchen)
|
||||
togglename = "sleeves"
|
||||
|
||||
//Cook
|
||||
/obj/item/clothing/suit/apron/chef
|
||||
name = "cook's apron"
|
||||
desc = "A basic, dull, white chef's apron."
|
||||
icon_state = "apronchef"
|
||||
item_state = "apronchef"
|
||||
blood_overlay_type = "armor"
|
||||
body_parts_covered = CHEST|GROIN
|
||||
allowed = list(/obj/item/weapon/kitchen)
|
||||
|
||||
//Detective
|
||||
/obj/item/clothing/suit/det_suit
|
||||
name = "trenchcoat"
|
||||
desc = "An 18th-century multi-purpose trenchcoat. Someone who wears this means serious business."
|
||||
icon_state = "detective"
|
||||
item_state = "det_suit"
|
||||
blood_overlay_type = "coat"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
allowed = list(/obj/item/weapon/tank/internals/emergency_oxygen,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/ballistic,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/lighter,/obj/item/device/detective_scanner,/obj/item/device/taperecorder,/obj/item/weapon/melee/classic_baton)
|
||||
armor = list(melee = 25, bullet = 10, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 45)
|
||||
cold_protection = CHEST|GROIN|LEGS|ARMS
|
||||
heat_protection = CHEST|GROIN|LEGS|ARMS
|
||||
|
||||
/obj/item/clothing/suit/det_suit/grey
|
||||
name = "noir trenchcoat"
|
||||
desc = "A hard-boiled private investigator's grey trenchcoat."
|
||||
icon_state = "greydet"
|
||||
item_state = "greydet"
|
||||
|
||||
//Engineering
|
||||
/obj/item/clothing/suit/hazardvest
|
||||
name = "hazard vest"
|
||||
desc = "A high-visibility vest used in work zones."
|
||||
icon_state = "hazard"
|
||||
item_state = "hazard"
|
||||
blood_overlay_type = "armor"
|
||||
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/internals/emergency_oxygen,/obj/item/device/t_scanner,/obj/item/device/radio)
|
||||
resistance_flags = 0
|
||||
//Lawyer
|
||||
/obj/item/clothing/suit/toggle/lawyer
|
||||
name = "blue suit jacket"
|
||||
desc = "A snappy dress jacket."
|
||||
icon_state = "suitjacket_blue"
|
||||
item_state = "suitjacket_blue"
|
||||
blood_overlay_type = "coat"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
togglename = "buttons"
|
||||
|
||||
/obj/item/clothing/suit/toggle/lawyer/purple
|
||||
name = "purple suit jacket"
|
||||
desc = "A foppish dress jacket."
|
||||
icon_state = "suitjacket_purp"
|
||||
item_state = "suitjacket_purp"
|
||||
|
||||
/obj/item/clothing/suit/toggle/lawyer/black
|
||||
name = "black suit jacket"
|
||||
desc = "A professional suit jacket."
|
||||
icon_state = "suitjacket_black"
|
||||
item_state = "ro_suit"
|
||||
|
||||
|
||||
//Mime
|
||||
/obj/item/clothing/suit/suspenders
|
||||
name = "suspenders"
|
||||
desc = "They suspend the illusion of the mime's play."
|
||||
icon = 'icons/obj/clothing/belts.dmi'
|
||||
icon_state = "suspenders"
|
||||
blood_overlay_type = "armor" //it's the less thing that I can put here
|
||||
|
||||
//Security
|
||||
/obj/item/clothing/suit/security/officer
|
||||
name = "security officer's jacket"
|
||||
desc = "This jacket is for those special occasions when a security officer isn't required to wear their armor."
|
||||
icon_state = "officerbluejacket"
|
||||
item_state = "officerbluejacket"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
|
||||
/obj/item/clothing/suit/security/warden
|
||||
name = "warden's jacket"
|
||||
desc = "Perfectly suited for the warden that wants to leave an impression of style on those who visit the brig."
|
||||
icon_state = "wardenbluejacket"
|
||||
item_state = "wardenbluejacket"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
|
||||
/obj/item/clothing/suit/security/hos
|
||||
name = "head of security's jacket"
|
||||
desc = "This piece of clothing was specifically designed for asserting superior authority."
|
||||
icon_state = "hosbluejacket"
|
||||
item_state = "hosbluejacket"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
|
||||
//Surgeon
|
||||
/obj/item/clothing/suit/apron/surgical
|
||||
name = "surgical apron"
|
||||
desc = "A sterile blue surgical apron."
|
||||
icon_state = "surgical"
|
||||
allowed = list(/obj/item/weapon/scalpel, /obj/item/weapon/surgical_drapes, /obj/item/weapon/cautery, /obj/item/weapon/hemostat, /obj/item/weapon/retractor)
|
||||
|
||||
//Curator
|
||||
/obj/item/clothing/suit/curator
|
||||
name = "treasure hunter's coat"
|
||||
desc = "Both fashionable and lightly armoured, this jacket is favoured by treasure hunters the galaxy over."
|
||||
icon_state = "curator"
|
||||
item_state = "curator"
|
||||
blood_overlay_type = "coat"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
allowed = list(/obj/item/weapon/tank/internals, /obj/item/weapon/melee/curator_whip)
|
||||
armor = list(melee = 25, bullet = 10, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 45)
|
||||
cold_protection = CHEST|ARMS
|
||||
heat_protection = CHEST|ARMS
|
||||
/*
|
||||
* Job related
|
||||
*/
|
||||
|
||||
//Botanist
|
||||
/obj/item/clothing/suit/apron
|
||||
name = "apron"
|
||||
desc = "A basic blue apron."
|
||||
icon_state = "apron"
|
||||
item_state = "apron"
|
||||
blood_overlay_type = "armor"
|
||||
body_parts_covered = CHEST|GROIN
|
||||
allowed = list(/obj/item/weapon/reagent_containers/spray/plantbgone,/obj/item/device/plant_analyzer,/obj/item/seeds,/obj/item/weapon/reagent_containers/glass/bottle, /obj/item/weapon/reagent_containers/glass/beaker, /obj/item/weapon/cultivator,/obj/item/weapon/reagent_containers/spray/pestspray,/obj/item/weapon/hatchet,/obj/item/weapon/storage/bag/plants)
|
||||
|
||||
//Captain
|
||||
/obj/item/clothing/suit/captunic
|
||||
name = "captain's parade tunic"
|
||||
desc = "Worn by a Captain to show their class."
|
||||
icon_state = "captunic"
|
||||
item_state = "bio_suit"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
flags_inv = HIDEJUMPSUIT
|
||||
allowed = list(/obj/item/weapon/disk, /obj/item/weapon/stamp, /obj/item/weapon/reagent_containers/food/drinks/flask, /obj/item/weapon/melee, /obj/item/weapon/storage/lockbox/medal, /obj/item/device/assembly/flash/handheld, /obj/item/weapon/storage/box/matches, /obj/item/weapon/lighter, /obj/item/clothing/mask/cigarette, /obj/item/weapon/storage/fancy/cigarettes, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
|
||||
//Chaplain
|
||||
/obj/item/clothing/suit/hooded/chaplain_hoodie
|
||||
name = "chaplain hoodie"
|
||||
desc = "This suit says to you 'hush'!"
|
||||
icon_state = "chaplain_hoodie"
|
||||
item_state = "chaplain_hoodie"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
allowed = list(/obj/item/weapon/storage/book/bible, /obj/item/weapon/nullrod, /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater, /obj/item/weapon/storage/fancy/candle_box, /obj/item/candle, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
hoodtype = /obj/item/clothing/head/hooded/chaplain_hood
|
||||
|
||||
/obj/item/clothing/head/hooded/chaplain_hood
|
||||
name = "chaplain hood"
|
||||
desc = "For protecting your identity when immolating demons."
|
||||
icon_state = "chaplain_hood"
|
||||
body_parts_covered = HEAD
|
||||
flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS
|
||||
|
||||
/obj/item/clothing/suit/nun
|
||||
name = "nun robe"
|
||||
desc = "Maximum piety in this star system."
|
||||
icon_state = "nun"
|
||||
item_state = "nun"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS|HANDS
|
||||
flags_inv = HIDESHOES|HIDEJUMPSUIT
|
||||
allowed = list(/obj/item/weapon/storage/book/bible, /obj/item/weapon/nullrod, /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater, /obj/item/weapon/storage/fancy/candle_box, /obj/item/candle, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
|
||||
/obj/item/clothing/suit/studentuni
|
||||
name = "student robe"
|
||||
desc = "The uniform of a bygone institute of learning."
|
||||
icon_state = "studentuni"
|
||||
item_state = "studentuni"
|
||||
body_parts_covered = ARMS|CHEST
|
||||
allowed = list(/obj/item/weapon/storage/book/bible, /obj/item/weapon/nullrod, /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater, /obj/item/weapon/storage/fancy/candle_box, /obj/item/candle, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
|
||||
/obj/item/clothing/suit/witchhunter
|
||||
name = "witchunter garb"
|
||||
desc = "This worn outfit saw much use back in the day."
|
||||
icon_state = "witchhunter"
|
||||
item_state = "witchhunter"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
allowed = list(/obj/item/weapon/storage/book/bible, /obj/item/weapon/nullrod, /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater, /obj/item/weapon/storage/fancy/candle_box, /obj/item/candle, /obj/item/weapon/tank/internals/emergency_oxygen)
|
||||
|
||||
//Chef
|
||||
/obj/item/clothing/suit/toggle/chef
|
||||
name = "chef's apron"
|
||||
desc = "An apron-jacket used by a high class chef."
|
||||
icon_state = "chef"
|
||||
item_state = "chef"
|
||||
gas_transfer_coefficient = 0.90
|
||||
permeability_coefficient = 0.50
|
||||
body_parts_covered = CHEST|GROIN|ARMS
|
||||
allowed = list(/obj/item/weapon/kitchen)
|
||||
togglename = "sleeves"
|
||||
|
||||
//Cook
|
||||
/obj/item/clothing/suit/apron/chef
|
||||
name = "cook's apron"
|
||||
desc = "A basic, dull, white chef's apron."
|
||||
icon_state = "apronchef"
|
||||
item_state = "apronchef"
|
||||
blood_overlay_type = "armor"
|
||||
body_parts_covered = CHEST|GROIN
|
||||
allowed = list(/obj/item/weapon/kitchen)
|
||||
|
||||
//Detective
|
||||
/obj/item/clothing/suit/det_suit
|
||||
name = "trenchcoat"
|
||||
desc = "An 18th-century multi-purpose trenchcoat. Someone who wears this means serious business."
|
||||
icon_state = "detective"
|
||||
item_state = "det_suit"
|
||||
blood_overlay_type = "coat"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|ARMS
|
||||
allowed = list(/obj/item/weapon/tank/internals/emergency_oxygen,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/device/flashlight,/obj/item/weapon/gun/energy,/obj/item/weapon/gun/ballistic,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs,/obj/item/weapon/storage/fancy/cigarettes,/obj/item/weapon/lighter,/obj/item/device/detective_scanner,/obj/item/device/taperecorder,/obj/item/weapon/melee/classic_baton)
|
||||
armor = list(melee = 25, bullet = 10, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 45)
|
||||
cold_protection = CHEST|GROIN|LEGS|ARMS
|
||||
heat_protection = CHEST|GROIN|LEGS|ARMS
|
||||
|
||||
/obj/item/clothing/suit/det_suit/grey
|
||||
name = "noir trenchcoat"
|
||||
desc = "A hard-boiled private investigator's grey trenchcoat."
|
||||
icon_state = "greydet"
|
||||
item_state = "greydet"
|
||||
|
||||
//Engineering
|
||||
/obj/item/clothing/suit/hazardvest
|
||||
name = "hazard vest"
|
||||
desc = "A high-visibility vest used in work zones."
|
||||
icon_state = "hazard"
|
||||
item_state = "hazard"
|
||||
blood_overlay_type = "armor"
|
||||
allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/internals/emergency_oxygen,/obj/item/device/t_scanner,/obj/item/device/radio)
|
||||
resistance_flags = 0
|
||||
//Lawyer
|
||||
/obj/item/clothing/suit/toggle/lawyer
|
||||
name = "blue suit jacket"
|
||||
desc = "A snappy dress jacket."
|
||||
icon_state = "suitjacket_blue"
|
||||
item_state = "suitjacket_blue"
|
||||
blood_overlay_type = "coat"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
togglename = "buttons"
|
||||
|
||||
/obj/item/clothing/suit/toggle/lawyer/purple
|
||||
name = "purple suit jacket"
|
||||
desc = "A foppish dress jacket."
|
||||
icon_state = "suitjacket_purp"
|
||||
item_state = "suitjacket_purp"
|
||||
|
||||
/obj/item/clothing/suit/toggle/lawyer/black
|
||||
name = "black suit jacket"
|
||||
desc = "A professional suit jacket."
|
||||
icon_state = "suitjacket_black"
|
||||
item_state = "ro_suit"
|
||||
|
||||
|
||||
//Mime
|
||||
/obj/item/clothing/suit/suspenders
|
||||
name = "suspenders"
|
||||
desc = "They suspend the illusion of the mime's play."
|
||||
icon = 'icons/obj/clothing/belts.dmi'
|
||||
icon_state = "suspenders"
|
||||
blood_overlay_type = "armor" //it's the less thing that I can put here
|
||||
|
||||
//Security
|
||||
/obj/item/clothing/suit/security/officer
|
||||
name = "security officer's jacket"
|
||||
desc = "This jacket is for those special occasions when a security officer isn't required to wear their armor."
|
||||
icon_state = "officerbluejacket"
|
||||
item_state = "officerbluejacket"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
|
||||
/obj/item/clothing/suit/security/warden
|
||||
name = "warden's jacket"
|
||||
desc = "Perfectly suited for the warden that wants to leave an impression of style on those who visit the brig."
|
||||
icon_state = "wardenbluejacket"
|
||||
item_state = "wardenbluejacket"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
|
||||
/obj/item/clothing/suit/security/hos
|
||||
name = "head of security's jacket"
|
||||
desc = "This piece of clothing was specifically designed for asserting superior authority."
|
||||
icon_state = "hosbluejacket"
|
||||
item_state = "hosbluejacket"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
|
||||
//Surgeon
|
||||
/obj/item/clothing/suit/apron/surgical
|
||||
name = "surgical apron"
|
||||
desc = "A sterile blue surgical apron."
|
||||
icon_state = "surgical"
|
||||
allowed = list(/obj/item/weapon/scalpel, /obj/item/weapon/surgical_drapes, /obj/item/weapon/cautery, /obj/item/weapon/hemostat, /obj/item/weapon/retractor)
|
||||
|
||||
//Curator
|
||||
/obj/item/clothing/suit/curator
|
||||
name = "treasure hunter's coat"
|
||||
desc = "Both fashionable and lightly armoured, this jacket is favoured by treasure hunters the galaxy over."
|
||||
icon_state = "curator"
|
||||
item_state = "curator"
|
||||
blood_overlay_type = "coat"
|
||||
body_parts_covered = CHEST|ARMS
|
||||
allowed = list(/obj/item/weapon/tank/internals, /obj/item/weapon/melee/curator_whip)
|
||||
armor = list(melee = 25, bullet = 10, laser = 25, energy = 10, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 45)
|
||||
cold_protection = CHEST|ARMS
|
||||
heat_protection = CHEST|ARMS
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
item_color = "black"
|
||||
resistance_flags = 0
|
||||
|
||||
/obj/item/clothing/under/color/black/ghost
|
||||
flags = NODROP|DROPDEL
|
||||
|
||||
/obj/item/clothing/under/color/grey
|
||||
name = "grey jumpsuit"
|
||||
desc = "A tasteful grey jumpsuit that reminds you of the good old days."
|
||||
|
||||
@@ -1,201 +1,201 @@
|
||||
/*
|
||||
Clown
|
||||
*/
|
||||
/datum/job/clown
|
||||
title = "Clown"
|
||||
flag = CLOWN
|
||||
department_head = list("Head of Personnel")
|
||||
department_flag = CIVILIAN
|
||||
faction = "Station"
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "the head of personnel"
|
||||
selection_color = "#dddddd"
|
||||
|
||||
outfit = /datum/outfit/job/clown
|
||||
|
||||
access = list(GLOB.access_theatre)
|
||||
minimal_access = list(GLOB.access_theatre)
|
||||
|
||||
/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M)
|
||||
H.rename_self("clown", M.client)
|
||||
|
||||
/datum/outfit/job/clown
|
||||
name = "Clown"
|
||||
jobtype = /datum/job/clown
|
||||
|
||||
belt = /obj/item/device/pda/clown
|
||||
uniform = /obj/item/clothing/under/rank/clown
|
||||
shoes = /obj/item/clothing/shoes/clown_shoes
|
||||
mask = /obj/item/clothing/mask/gas/clown_hat
|
||||
l_pocket = /obj/item/weapon/bikehorn
|
||||
r_pocket = /obj/item/toy/crayon/rainbow
|
||||
backpack_contents = list(
|
||||
/obj/item/weapon/stamp/clown = 1,
|
||||
/obj/item/weapon/reagent_containers/spray/waterflower = 1,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/banana = 1,
|
||||
/obj/item/device/megaphone/clown = 1,
|
||||
/obj/item/weapon/reagent_containers/food/drinks/soda_cans/canned_laughter = 1,
|
||||
/obj/item/weapon/pneumatic_cannon/pie = 1
|
||||
)
|
||||
|
||||
implants = list(/obj/item/weapon/implant/sad_trombone)
|
||||
|
||||
backpack = /obj/item/weapon/storage/backpack/clown
|
||||
satchel = /obj/item/weapon/storage/backpack/clown
|
||||
dufflebag = /obj/item/weapon/storage/backpack/dufflebag/clown //strangely has a duffle
|
||||
|
||||
box = /obj/item/weapon/storage/box/hug/survival
|
||||
|
||||
|
||||
/datum/outfit/job/clown/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names))
|
||||
|
||||
/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
H.dna.add_mutation(CLOWNMUT)
|
||||
|
||||
/*
|
||||
Mime
|
||||
*/
|
||||
/datum/job/mime
|
||||
title = "Mime"
|
||||
flag = MIME
|
||||
department_head = list("Head of Personnel")
|
||||
department_flag = CIVILIAN
|
||||
faction = "Station"
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "the head of personnel"
|
||||
selection_color = "#dddddd"
|
||||
|
||||
outfit = /datum/outfit/job/mime
|
||||
|
||||
access = list(GLOB.access_theatre)
|
||||
minimal_access = list(GLOB.access_theatre)
|
||||
|
||||
/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M)
|
||||
H.rename_self("mime", M.client)
|
||||
|
||||
/datum/outfit/job/mime
|
||||
name = "Mime"
|
||||
jobtype = /datum/job/mime
|
||||
|
||||
belt = /obj/item/device/pda/mime
|
||||
uniform = /obj/item/clothing/under/rank/mime
|
||||
mask = /obj/item/clothing/mask/gas/mime
|
||||
gloves = /obj/item/clothing/gloves/color/white
|
||||
head = /obj/item/clothing/head/beret
|
||||
suit = /obj/item/clothing/suit/suspenders
|
||||
backpack_contents = list(/obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing=1,\
|
||||
/obj/item/toy/crayon/mime=1)
|
||||
|
||||
backpack = /obj/item/weapon/storage/backpack/mime
|
||||
satchel = /obj/item/weapon/storage/backpack/mime
|
||||
|
||||
|
||||
/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
if(H.mind)
|
||||
H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null))
|
||||
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null))
|
||||
H.mind.miming = 1
|
||||
|
||||
/*
|
||||
Curator
|
||||
*/
|
||||
/datum/job/curator
|
||||
title = "Curator"
|
||||
flag = CURATOR
|
||||
department_head = list("Head of Personnel")
|
||||
department_flag = CIVILIAN
|
||||
faction = "Station"
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "the head of personnel"
|
||||
selection_color = "#dddddd"
|
||||
|
||||
outfit = /datum/outfit/job/curator
|
||||
|
||||
access = list(GLOB.access_library)
|
||||
minimal_access = list(GLOB.access_library, GLOB.access_construction,GLOB.access_mining_station)
|
||||
|
||||
/datum/outfit/job/curator
|
||||
name = "Curator"
|
||||
jobtype = /datum/job/curator
|
||||
|
||||
belt = /obj/item/device/pda/curator
|
||||
uniform = /obj/item/clothing/under/rank/curator
|
||||
l_hand = /obj/item/weapon/storage/bag/books
|
||||
r_pocket = /obj/item/key/displaycase
|
||||
l_pocket = /obj/item/device/laser_pointer
|
||||
backpack_contents = list(
|
||||
/obj/item/weapon/melee/curator_whip = 1,
|
||||
/obj/item/soapstone = 1,
|
||||
/obj/item/weapon/barcodescanner = 1
|
||||
)
|
||||
|
||||
|
||||
/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
H.grant_all_languages(omnitongue=TRUE)
|
||||
|
||||
/*
|
||||
Lawyer
|
||||
*/
|
||||
/datum/job/lawyer
|
||||
title = "Lawyer"
|
||||
flag = LAWYER
|
||||
department_head = list("Head of Personnel")
|
||||
department_flag = CIVILIAN
|
||||
faction = "Station"
|
||||
total_positions = 2
|
||||
spawn_positions = 2
|
||||
supervisors = "the head of personnel"
|
||||
selection_color = "#dddddd"
|
||||
var/lawyers = 0 //Counts lawyer amount
|
||||
|
||||
outfit = /datum/outfit/job/lawyer
|
||||
|
||||
access = list(GLOB.access_lawyer, GLOB.access_court, GLOB.access_sec_doors)
|
||||
minimal_access = list(GLOB.access_lawyer, GLOB.access_court, GLOB.access_sec_doors)
|
||||
|
||||
/datum/outfit/job/lawyer
|
||||
name = "Lawyer"
|
||||
jobtype = /datum/job/lawyer
|
||||
|
||||
belt = /obj/item/device/pda/lawyer
|
||||
ears = /obj/item/device/radio/headset/headset_sec
|
||||
uniform = /obj/item/clothing/under/lawyer/bluesuit
|
||||
suit = /obj/item/clothing/suit/toggle/lawyer
|
||||
shoes = /obj/item/clothing/shoes/laceup
|
||||
l_hand = /obj/item/weapon/storage/briefcase/lawyer
|
||||
l_pocket = /obj/item/device/laser_pointer
|
||||
r_pocket = /obj/item/clothing/tie/lawyers_badge
|
||||
|
||||
|
||||
/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/datum/job/lawyer/J = SSjob.GetJobType(jobtype)
|
||||
J.lawyers++
|
||||
if(J.lawyers>1)
|
||||
uniform = /obj/item/clothing/under/lawyer/purpsuit
|
||||
suit = /obj/item/clothing/suit/toggle/lawyer/purple
|
||||
/*
|
||||
Clown
|
||||
*/
|
||||
/datum/job/clown
|
||||
title = "Clown"
|
||||
flag = CLOWN
|
||||
department_head = list("Head of Personnel")
|
||||
department_flag = CIVILIAN
|
||||
faction = "Station"
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "the head of personnel"
|
||||
selection_color = "#dddddd"
|
||||
|
||||
outfit = /datum/outfit/job/clown
|
||||
|
||||
access = list(GLOB.access_theatre)
|
||||
minimal_access = list(GLOB.access_theatre)
|
||||
|
||||
/datum/job/clown/after_spawn(mob/living/carbon/human/H, mob/M)
|
||||
H.rename_self("clown", M.client)
|
||||
|
||||
/datum/outfit/job/clown
|
||||
name = "Clown"
|
||||
jobtype = /datum/job/clown
|
||||
|
||||
belt = /obj/item/device/pda/clown
|
||||
uniform = /obj/item/clothing/under/rank/clown
|
||||
shoes = /obj/item/clothing/shoes/clown_shoes
|
||||
mask = /obj/item/clothing/mask/gas/clown_hat
|
||||
l_pocket = /obj/item/weapon/bikehorn
|
||||
r_pocket = /obj/item/toy/crayon/rainbow
|
||||
backpack_contents = list(
|
||||
/obj/item/weapon/stamp/clown = 1,
|
||||
/obj/item/weapon/reagent_containers/spray/waterflower = 1,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/banana = 1,
|
||||
/obj/item/device/megaphone/clown = 1,
|
||||
/obj/item/weapon/reagent_containers/food/drinks/soda_cans/canned_laughter = 1,
|
||||
/obj/item/weapon/pneumatic_cannon/pie = 1
|
||||
)
|
||||
|
||||
implants = list(/obj/item/weapon/implant/sad_trombone)
|
||||
|
||||
backpack = /obj/item/weapon/storage/backpack/clown
|
||||
satchel = /obj/item/weapon/storage/backpack/clown
|
||||
dufflebag = /obj/item/weapon/storage/backpack/dufflebag/clown //strangely has a duffle
|
||||
|
||||
box = /obj/item/weapon/storage/box/hug/survival
|
||||
|
||||
|
||||
/datum/outfit/job/clown/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
H.fully_replace_character_name(H.real_name, pick(GLOB.clown_names))
|
||||
|
||||
/datum/outfit/job/clown/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
H.dna.add_mutation(CLOWNMUT)
|
||||
|
||||
/*
|
||||
Mime
|
||||
*/
|
||||
/datum/job/mime
|
||||
title = "Mime"
|
||||
flag = MIME
|
||||
department_head = list("Head of Personnel")
|
||||
department_flag = CIVILIAN
|
||||
faction = "Station"
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "the head of personnel"
|
||||
selection_color = "#dddddd"
|
||||
|
||||
outfit = /datum/outfit/job/mime
|
||||
|
||||
access = list(GLOB.access_theatre)
|
||||
minimal_access = list(GLOB.access_theatre)
|
||||
|
||||
/datum/job/mime/after_spawn(mob/living/carbon/human/H, mob/M)
|
||||
H.rename_self("mime", M.client)
|
||||
|
||||
/datum/outfit/job/mime
|
||||
name = "Mime"
|
||||
jobtype = /datum/job/mime
|
||||
|
||||
belt = /obj/item/device/pda/mime
|
||||
uniform = /obj/item/clothing/under/rank/mime
|
||||
mask = /obj/item/clothing/mask/gas/mime
|
||||
gloves = /obj/item/clothing/gloves/color/white
|
||||
head = /obj/item/clothing/head/beret
|
||||
suit = /obj/item/clothing/suit/suspenders
|
||||
backpack_contents = list(/obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing=1,\
|
||||
/obj/item/toy/crayon/mime=1)
|
||||
|
||||
backpack = /obj/item/weapon/storage/backpack/mime
|
||||
satchel = /obj/item/weapon/storage/backpack/mime
|
||||
|
||||
|
||||
/datum/outfit/job/mime/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
if(H.mind)
|
||||
H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall(null))
|
||||
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mime/speak(null))
|
||||
H.mind.miming = 1
|
||||
|
||||
/*
|
||||
Curator
|
||||
*/
|
||||
/datum/job/curator
|
||||
title = "Curator"
|
||||
flag = CURATOR
|
||||
department_head = list("Head of Personnel")
|
||||
department_flag = CIVILIAN
|
||||
faction = "Station"
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "the head of personnel"
|
||||
selection_color = "#dddddd"
|
||||
|
||||
outfit = /datum/outfit/job/curator
|
||||
|
||||
access = list(GLOB.access_library)
|
||||
minimal_access = list(GLOB.access_library, GLOB.access_construction,GLOB.access_mining_station)
|
||||
|
||||
/datum/outfit/job/curator
|
||||
name = "Curator"
|
||||
jobtype = /datum/job/curator
|
||||
|
||||
belt = /obj/item/device/pda/curator
|
||||
uniform = /obj/item/clothing/under/rank/curator
|
||||
l_hand = /obj/item/weapon/storage/bag/books
|
||||
r_pocket = /obj/item/key/displaycase
|
||||
l_pocket = /obj/item/device/laser_pointer
|
||||
backpack_contents = list(
|
||||
/obj/item/weapon/melee/curator_whip = 1,
|
||||
/obj/item/soapstone = 1,
|
||||
/obj/item/weapon/barcodescanner = 1
|
||||
)
|
||||
|
||||
|
||||
/datum/outfit/job/curator/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
H.grant_all_languages(omnitongue=TRUE)
|
||||
|
||||
/*
|
||||
Lawyer
|
||||
*/
|
||||
/datum/job/lawyer
|
||||
title = "Lawyer"
|
||||
flag = LAWYER
|
||||
department_head = list("Head of Personnel")
|
||||
department_flag = CIVILIAN
|
||||
faction = "Station"
|
||||
total_positions = 2
|
||||
spawn_positions = 2
|
||||
supervisors = "the head of personnel"
|
||||
selection_color = "#dddddd"
|
||||
var/lawyers = 0 //Counts lawyer amount
|
||||
|
||||
outfit = /datum/outfit/job/lawyer
|
||||
|
||||
access = list(GLOB.access_lawyer, GLOB.access_court, GLOB.access_sec_doors)
|
||||
minimal_access = list(GLOB.access_lawyer, GLOB.access_court, GLOB.access_sec_doors)
|
||||
|
||||
/datum/outfit/job/lawyer
|
||||
name = "Lawyer"
|
||||
jobtype = /datum/job/lawyer
|
||||
|
||||
belt = /obj/item/device/pda/lawyer
|
||||
ears = /obj/item/device/radio/headset/headset_sec
|
||||
uniform = /obj/item/clothing/under/lawyer/bluesuit
|
||||
suit = /obj/item/clothing/suit/toggle/lawyer
|
||||
shoes = /obj/item/clothing/shoes/laceup
|
||||
l_hand = /obj/item/weapon/storage/briefcase/lawyer
|
||||
l_pocket = /obj/item/device/laser_pointer
|
||||
r_pocket = /obj/item/clothing/tie/lawyers_badge
|
||||
|
||||
|
||||
/datum/outfit/job/lawyer/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
|
||||
..()
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
var/datum/job/lawyer/J = SSjob.GetJobType(jobtype)
|
||||
J.lawyers++
|
||||
if(J.lawyers>1)
|
||||
uniform = /obj/item/clothing/under/lawyer/purpsuit
|
||||
suit = /obj/item/clothing/suit/toggle/lawyer/purple
|
||||
|
||||
@@ -241,7 +241,7 @@
|
||||
return 1
|
||||
|
||||
/mob/living/proc/InCritical()
|
||||
return (src.health < 0 && src.health > -95 && stat == UNCONSCIOUS)
|
||||
return (health < 0 && health > -100 && stat == UNCONSCIOUS)
|
||||
|
||||
//This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually
|
||||
//affects them once clothing is factored in. ~Errorage
|
||||
|
||||
@@ -1,364 +1,364 @@
|
||||
/mob/living/simple_animal/hostile/construct
|
||||
name = "Construct"
|
||||
real_name = "Construct"
|
||||
desc = ""
|
||||
gender = NEUTER
|
||||
speak_emote = list("hisses")
|
||||
response_help = "thinks better of touching"
|
||||
response_disarm = "flails at"
|
||||
response_harm = "punches"
|
||||
speak_chance = 1
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
speed = 0
|
||||
a_intent = INTENT_HARM
|
||||
stop_automated_movement = 1
|
||||
status_flags = CANPUSH
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
see_in_dark = 7
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
healable = 0
|
||||
faction = list("cult")
|
||||
movement_type = FLYING
|
||||
pressure_resistance = 100
|
||||
unique_name = 1
|
||||
AIStatus = AI_OFF //normal constructs don't have AI
|
||||
loot = list(/obj/item/weapon/ectoplasm)
|
||||
del_on_death = TRUE
|
||||
initial_language_holder = /datum/language_holder/construct
|
||||
deathmessage = "collapses in a shattered heap."
|
||||
var/list/construct_spells = list()
|
||||
var/playstyle_string = "<b>You are a generic construct! Your job is to not exist, and you should probably adminhelp this.</b>"
|
||||
var/master = null
|
||||
var/seeking = FALSE
|
||||
var/can_repair_constructs = FALSE
|
||||
var/can_repair_self = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Initialize()
|
||||
. = ..()
|
||||
update_health_hud()
|
||||
for(var/spell in construct_spells)
|
||||
AddSpell(new spell(null))
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Login()
|
||||
..()
|
||||
to_chat(src, playstyle_string)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/examine(mob/user)
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_s = p_s()
|
||||
var/msg = "<span class='cult'>*---------*\nThis is \icon[src] \a <b>[src]</b>!\n"
|
||||
msg += "[desc]\n"
|
||||
if(health < maxHealth)
|
||||
msg += "<span class='warning'>"
|
||||
if(health >= maxHealth/2)
|
||||
msg += "[t_He] look[t_s] slightly dented.\n"
|
||||
else
|
||||
msg += "<b>[t_He] look[t_s] severely dented!</b>\n"
|
||||
msg += "</span>"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
to_chat(user, msg)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/attack_animal(mob/living/simple_animal/M)
|
||||
if(isconstruct(M)) //is it a construct?
|
||||
var/mob/living/simple_animal/hostile/construct/C = M
|
||||
if(!C.can_repair_constructs || (C == src && !C.can_repair_self))
|
||||
return
|
||||
if(health < maxHealth)
|
||||
adjustHealth(-5)
|
||||
if(src != M)
|
||||
Beam(M,icon_state="sendbeam",time=4)
|
||||
M.visible_message("<span class='danger'>[M] repairs some of \the <b>[src]'s</b> dents.</span>", \
|
||||
"<span class='cult'>You repair some of <b>[src]'s</b> dents, leaving <b>[src]</b> at <b>[health]/[maxHealth]</b> health.</span>")
|
||||
else
|
||||
M.visible_message("<span class='danger'>[M] repairs some of [p_their()] own dents.</span>", \
|
||||
"<span class='cult'>You repair some of your own dents, leaving you at <b>[M.health]/[M.maxHealth]</b> health.</span>")
|
||||
else
|
||||
if(src != M)
|
||||
to_chat(M, "<span class='cult'>You cannot repair <b>[src]'s</b> dents, as [p_they()] [p_have()] none!</span>")
|
||||
else
|
||||
to_chat(M, "<span class='cult'>You cannot repair your own dents, as you have none!</span>")
|
||||
else if(src != M)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/narsie_act()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
if(updating_health)
|
||||
update_health_hud()
|
||||
|
||||
/////////////////Juggernaut///////////////
|
||||
/mob/living/simple_animal/hostile/construct/armored
|
||||
name = "Juggernaut"
|
||||
real_name = "Juggernaut"
|
||||
desc = "A massive, armored construct built to spearhead attacks and soak up enemy fire."
|
||||
icon_state = "behemoth"
|
||||
icon_living = "behemoth"
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
response_harm = "harmlessly punches"
|
||||
harm_intent_damage = 0
|
||||
obj_damage = 90
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 30
|
||||
attacktext = "smashes their armored gauntlet into"
|
||||
speed = 3
|
||||
environment_smash = 2
|
||||
attack_sound = 'sound/weapons/punch3.ogg'
|
||||
status_flags = 0
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
force_threshold = 11
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall)
|
||||
playstyle_string = "<b>You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \
|
||||
create shield walls, rip apart enemies and walls alike, and even deflect energy weapons.</b>"
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/armored/hostile //actually hostile, will move around, hit things
|
||||
AIStatus = AI_ON
|
||||
environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/armored/bullet_act(obj/item/projectile/P)
|
||||
if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam))
|
||||
var/reflectchance = 80 - round(P.damage/3)
|
||||
if(prob(reflectchance))
|
||||
apply_damage(P.damage * 0.5, P.damage_type)
|
||||
visible_message("<span class='danger'>The [P.name] is reflected by [src]'s armored shell!</span>", \
|
||||
"<span class='userdanger'>The [P.name] is reflected by your armored shell!</span>")
|
||||
|
||||
// Find a turf near or on the original location to bounce to
|
||||
if(P.starting)
|
||||
var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
|
||||
var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
|
||||
var/turf/curloc = get_turf(src)
|
||||
|
||||
// redirect the projectile
|
||||
P.original = locate(new_x, new_y, P.z)
|
||||
P.starting = curloc
|
||||
P.current = curloc
|
||||
P.firer = src
|
||||
P.yo = new_y - curloc.y
|
||||
P.xo = new_x - curloc.x
|
||||
|
||||
return -1 // complete projectile permutation
|
||||
|
||||
return (..(P))
|
||||
|
||||
|
||||
|
||||
////////////////////////Wraith/////////////////////////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/wraith
|
||||
name = "Wraith"
|
||||
real_name = "Wraith"
|
||||
desc = "A wicked, clawed shell constructed to assassinate enemies and sow chaos behind enemy lines."
|
||||
icon_state = "floating"
|
||||
icon_living = "floating"
|
||||
maxHealth = 75
|
||||
health = 75
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
retreat_distance = 2 //AI wraiths will move in and out of combat
|
||||
attacktext = "slashes"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift)
|
||||
playstyle_string = "<b>You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls.</b>"
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/wraith/hostile //actually hostile, will move around, hit things
|
||||
AIStatus = AI_ON
|
||||
|
||||
|
||||
|
||||
/////////////////////////////Artificer/////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/builder
|
||||
name = "Artificer"
|
||||
real_name = "Artificer"
|
||||
desc = "A bulbous construct dedicated to building and maintaining the Cult of Nar-Sie's armies."
|
||||
icon_state = "artificer"
|
||||
icon_living = "artificer"
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
response_harm = "viciously beats"
|
||||
harm_intent_damage = 5
|
||||
obj_damage = 60
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 5
|
||||
retreat_distance = 10
|
||||
minimum_distance = 10 //AI artificers will flee like fuck
|
||||
attacktext = "rams"
|
||||
environment_smash = 2
|
||||
attack_sound = 'sound/weapons/punch2.ogg'
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/wall,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/floor,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser,
|
||||
/obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser)
|
||||
playstyle_string = "<b>You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \
|
||||
use magic missile, repair allied constructs, shades, and yourself (by clicking on them), \
|
||||
<i>and, most important of all,</i> create new constructs by producing soulstones to capture souls, \
|
||||
and shells to place those soulstones into.</b>"
|
||||
can_repair_constructs = TRUE
|
||||
can_repair_self = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/Found(atom/A) //what have we found here?
|
||||
if(isconstruct(A)) //is it a construct?
|
||||
var/mob/living/simple_animal/hostile/construct/C = A
|
||||
if(C.health < C.maxHealth) //is it hurt? let's go heal it if it is
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
else
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/CanAttack(atom/the_target)
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
return 0
|
||||
if(Found(the_target) || ..()) //If we Found it or Can_Attack it normally, we Can_Attack it as long as it wasn't invisible
|
||||
return 1 //as a note this shouldn't be added to base hostile mobs because it'll mess up retaliate hostile mobs
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/MoveToTarget(var/list/possible_targets)
|
||||
..()
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(isconstruct(L) && L.health >= L.maxHealth) //is this target an unhurt construct? stop trying to heal it
|
||||
LoseTarget()
|
||||
return 0
|
||||
if(L.health <= melee_damage_lower+melee_damage_upper) //ey bucko you're hurt as fuck let's go hit you
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/Aggro()
|
||||
..()
|
||||
if(isconstruct(target)) //oh the target is a construct no need to flee
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/LoseAggro()
|
||||
..()
|
||||
retreat_distance = initial(retreat_distance)
|
||||
minimum_distance = initial(minimum_distance)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/hostile //actually hostile, will move around, hit things, heal other constructs
|
||||
AIStatus = AI_ON
|
||||
environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP
|
||||
|
||||
/////////////////////////////Non-cult Artificer/////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/builder/noncult
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/wall,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/floor,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/noncult,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser,
|
||||
/obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser)
|
||||
|
||||
|
||||
/////////////////////////////Harvester/////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/harvester
|
||||
name = "Harvester"
|
||||
real_name = "Harvester"
|
||||
desc = "A long, thin construct built to herald Nar-Sie's rise. It'll be all over soon."
|
||||
icon_state = "harvester"
|
||||
icon_living = "harvester"
|
||||
maxHealth = 60
|
||||
health = 60
|
||||
sight = SEE_MOBS
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
attacktext = "butchers"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/area_conversion,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall)
|
||||
playstyle_string = "<B>You are a Harvester. You are incapable of directly killing humans, but your attacks will remove their limbs: \
|
||||
Bring those who still cling to this world of illusion back to the Geometer so they may know Truth.</B>"
|
||||
can_repair_constructs = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/harvester/Bump(atom/AM)
|
||||
. = ..()
|
||||
if(istype(AM, /turf/closed/wall/mineral/cult) && AM != loc) //we can go through cult walls
|
||||
var/atom/movable/stored_pulling = pulling
|
||||
if(stored_pulling)
|
||||
stored_pulling.setDir(get_dir(stored_pulling.loc, loc))
|
||||
stored_pulling.forceMove(loc)
|
||||
forceMove(AM)
|
||||
if(stored_pulling)
|
||||
start_pulling(stored_pulling, TRUE) //drag anything we're pulling through the wall with us by magic
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/harvester/AttackingTarget()
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
var/list/parts = list()
|
||||
var/undismembermerable_limbs = 0
|
||||
for(var/X in C.bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(BP.body_part != HEAD && BP.body_part != CHEST)
|
||||
if(BP.dismemberable)
|
||||
parts += BP
|
||||
else
|
||||
undismembermerable_limbs++
|
||||
if(!LAZYLEN(parts))
|
||||
if(undismembermerable_limbs) //they have limbs we can't remove, and no parts we can, attack!
|
||||
return ..()
|
||||
to_chat(src, "<span class='cultlarge'>\"Bring [C.p_them()] to me.\"</span>")
|
||||
return FALSE
|
||||
do_attack_animation(C)
|
||||
var/obj/item/bodypart/BP = pick(parts)
|
||||
BP.dismember()
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
|
||||
///////////////////////Master-Tracker///////////////////////
|
||||
|
||||
/datum/action/innate/seek_master
|
||||
name = "Seek your Master"
|
||||
desc = "You and your master share a soul-link that informs you of their location"
|
||||
background_icon_state = "bg_demon"
|
||||
buttontooltipstyle = "cult"
|
||||
button_icon_state = "cult_mark"
|
||||
var/tracking = FALSE
|
||||
var/mob/living/simple_animal/hostile/construct/the_construct
|
||||
|
||||
/datum/action/innate/seek_master/Grant(var/mob/living/C)
|
||||
the_construct = C
|
||||
..()
|
||||
|
||||
/datum/action/innate/seek_master/Activate()
|
||||
if(!the_construct.master)
|
||||
to_chat(the_construct, "<span class='cultitalic'>You have no master to seek!</span>")
|
||||
the_construct.seeking = FALSE
|
||||
return
|
||||
if(tracking)
|
||||
tracking = FALSE
|
||||
the_construct.seeking = FALSE
|
||||
to_chat(the_construct, "<span class='cultitalic'>You are no longer tracking your master.</span>")
|
||||
return
|
||||
else
|
||||
tracking = TRUE
|
||||
the_construct.seeking = TRUE
|
||||
to_chat(the_construct, "<span class='cultitalic'>You are now tracking your master.</span>")
|
||||
|
||||
|
||||
/////////////////////////////ui stuff/////////////////////////////
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/update_health_hud()
|
||||
if(hud_used)
|
||||
if(health >= maxHealth)
|
||||
hud_used.healths.icon_state = "[icon_state]_health0"
|
||||
else if(health > maxHealth*0.8)
|
||||
hud_used.healths.icon_state = "[icon_state]_health2"
|
||||
else if(health > maxHealth*0.6)
|
||||
hud_used.healths.icon_state = "[icon_state]_health3"
|
||||
else if(health > maxHealth*0.4)
|
||||
hud_used.healths.icon_state = "[icon_state]_health4"
|
||||
else if(health > maxHealth*0.2)
|
||||
hud_used.healths.icon_state = "[icon_state]_health5"
|
||||
else
|
||||
hud_used.healths.icon_state = "[icon_state]_health6"
|
||||
/mob/living/simple_animal/hostile/construct
|
||||
name = "Construct"
|
||||
real_name = "Construct"
|
||||
desc = ""
|
||||
gender = NEUTER
|
||||
speak_emote = list("hisses")
|
||||
response_help = "thinks better of touching"
|
||||
response_disarm = "flails at"
|
||||
response_harm = "punches"
|
||||
speak_chance = 1
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
speed = 0
|
||||
a_intent = INTENT_HARM
|
||||
stop_automated_movement = 1
|
||||
status_flags = CANPUSH
|
||||
attack_sound = 'sound/weapons/punch1.ogg'
|
||||
see_in_dark = 7
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
minbodytemp = 0
|
||||
maxbodytemp = INFINITY
|
||||
healable = 0
|
||||
faction = list("cult")
|
||||
movement_type = FLYING
|
||||
pressure_resistance = 100
|
||||
unique_name = 1
|
||||
AIStatus = AI_OFF //normal constructs don't have AI
|
||||
loot = list(/obj/item/weapon/ectoplasm)
|
||||
del_on_death = TRUE
|
||||
initial_language_holder = /datum/language_holder/construct
|
||||
deathmessage = "collapses in a shattered heap."
|
||||
var/list/construct_spells = list()
|
||||
var/playstyle_string = "<b>You are a generic construct! Your job is to not exist, and you should probably adminhelp this.</b>"
|
||||
var/master = null
|
||||
var/seeking = FALSE
|
||||
var/can_repair_constructs = FALSE
|
||||
var/can_repair_self = FALSE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Initialize()
|
||||
. = ..()
|
||||
update_health_hud()
|
||||
for(var/spell in construct_spells)
|
||||
AddSpell(new spell(null))
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Login()
|
||||
..()
|
||||
to_chat(src, playstyle_string)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/examine(mob/user)
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_s = p_s()
|
||||
var/msg = "<span class='cult'>*---------*\nThis is \icon[src] \a <b>[src]</b>!\n"
|
||||
msg += "[desc]\n"
|
||||
if(health < maxHealth)
|
||||
msg += "<span class='warning'>"
|
||||
if(health >= maxHealth/2)
|
||||
msg += "[t_He] look[t_s] slightly dented.\n"
|
||||
else
|
||||
msg += "<b>[t_He] look[t_s] severely dented!</b>\n"
|
||||
msg += "</span>"
|
||||
msg += "*---------*</span>"
|
||||
|
||||
to_chat(user, msg)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/attack_animal(mob/living/simple_animal/M)
|
||||
if(isconstruct(M)) //is it a construct?
|
||||
var/mob/living/simple_animal/hostile/construct/C = M
|
||||
if(!C.can_repair_constructs || (C == src && !C.can_repair_self))
|
||||
return
|
||||
if(health < maxHealth)
|
||||
adjustHealth(-5)
|
||||
if(src != M)
|
||||
Beam(M,icon_state="sendbeam",time=4)
|
||||
M.visible_message("<span class='danger'>[M] repairs some of \the <b>[src]'s</b> dents.</span>", \
|
||||
"<span class='cult'>You repair some of <b>[src]'s</b> dents, leaving <b>[src]</b> at <b>[health]/[maxHealth]</b> health.</span>")
|
||||
else
|
||||
M.visible_message("<span class='danger'>[M] repairs some of [p_their()] own dents.</span>", \
|
||||
"<span class='cult'>You repair some of your own dents, leaving you at <b>[M.health]/[M.maxHealth]</b> health.</span>")
|
||||
else
|
||||
if(src != M)
|
||||
to_chat(M, "<span class='cult'>You cannot repair <b>[src]'s</b> dents, as [p_they()] [p_have()] none!</span>")
|
||||
else
|
||||
to_chat(M, "<span class='cult'>You cannot repair your own dents, as you have none!</span>")
|
||||
else if(src != M)
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/narsie_act()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
|
||||
. = ..()
|
||||
if(updating_health)
|
||||
update_health_hud()
|
||||
|
||||
/////////////////Juggernaut///////////////
|
||||
/mob/living/simple_animal/hostile/construct/armored
|
||||
name = "Juggernaut"
|
||||
real_name = "Juggernaut"
|
||||
desc = "A massive, armored construct built to spearhead attacks and soak up enemy fire."
|
||||
icon_state = "behemoth"
|
||||
icon_living = "behemoth"
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
response_harm = "harmlessly punches"
|
||||
harm_intent_damage = 0
|
||||
obj_damage = 90
|
||||
melee_damage_lower = 30
|
||||
melee_damage_upper = 30
|
||||
attacktext = "smashes their armored gauntlet into"
|
||||
speed = 3
|
||||
environment_smash = 2
|
||||
attack_sound = 'sound/weapons/punch3.ogg'
|
||||
status_flags = 0
|
||||
mob_size = MOB_SIZE_LARGE
|
||||
force_threshold = 11
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall)
|
||||
playstyle_string = "<b>You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \
|
||||
create shield walls, rip apart enemies and walls alike, and even deflect energy weapons.</b>"
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/armored/hostile //actually hostile, will move around, hit things
|
||||
AIStatus = AI_ON
|
||||
environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/armored/bullet_act(obj/item/projectile/P)
|
||||
if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam))
|
||||
var/reflectchance = 80 - round(P.damage/3)
|
||||
if(prob(reflectchance))
|
||||
apply_damage(P.damage * 0.5, P.damage_type)
|
||||
visible_message("<span class='danger'>The [P.name] is reflected by [src]'s armored shell!</span>", \
|
||||
"<span class='userdanger'>The [P.name] is reflected by your armored shell!</span>")
|
||||
|
||||
// Find a turf near or on the original location to bounce to
|
||||
if(P.starting)
|
||||
var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
|
||||
var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
|
||||
var/turf/curloc = get_turf(src)
|
||||
|
||||
// redirect the projectile
|
||||
P.original = locate(new_x, new_y, P.z)
|
||||
P.starting = curloc
|
||||
P.current = curloc
|
||||
P.firer = src
|
||||
P.yo = new_y - curloc.y
|
||||
P.xo = new_x - curloc.x
|
||||
|
||||
return -1 // complete projectile permutation
|
||||
|
||||
return (..(P))
|
||||
|
||||
|
||||
|
||||
////////////////////////Wraith/////////////////////////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/wraith
|
||||
name = "Wraith"
|
||||
real_name = "Wraith"
|
||||
desc = "A wicked, clawed shell constructed to assassinate enemies and sow chaos behind enemy lines."
|
||||
icon_state = "floating"
|
||||
icon_living = "floating"
|
||||
maxHealth = 75
|
||||
health = 75
|
||||
melee_damage_lower = 25
|
||||
melee_damage_upper = 25
|
||||
retreat_distance = 2 //AI wraiths will move in and out of combat
|
||||
attacktext = "slashes"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift)
|
||||
playstyle_string = "<b>You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls.</b>"
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/wraith/hostile //actually hostile, will move around, hit things
|
||||
AIStatus = AI_ON
|
||||
|
||||
|
||||
|
||||
/////////////////////////////Artificer/////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/builder
|
||||
name = "Artificer"
|
||||
real_name = "Artificer"
|
||||
desc = "A bulbous construct dedicated to building and maintaining the Cult of Nar-Sie's armies."
|
||||
icon_state = "artificer"
|
||||
icon_living = "artificer"
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
response_harm = "viciously beats"
|
||||
harm_intent_damage = 5
|
||||
obj_damage = 60
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 5
|
||||
retreat_distance = 10
|
||||
minimum_distance = 10 //AI artificers will flee like fuck
|
||||
attacktext = "rams"
|
||||
environment_smash = 2
|
||||
attack_sound = 'sound/weapons/punch2.ogg'
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/wall,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/floor,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser,
|
||||
/obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser)
|
||||
playstyle_string = "<b>You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \
|
||||
use magic missile, repair allied constructs, shades, and yourself (by clicking on them), \
|
||||
<i>and, most important of all,</i> create new constructs by producing soulstones to capture souls, \
|
||||
and shells to place those soulstones into.</b>"
|
||||
can_repair_constructs = TRUE
|
||||
can_repair_self = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/Found(atom/A) //what have we found here?
|
||||
if(isconstruct(A)) //is it a construct?
|
||||
var/mob/living/simple_animal/hostile/construct/C = A
|
||||
if(C.health < C.maxHealth) //is it hurt? let's go heal it if it is
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
else
|
||||
return 0
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/CanAttack(atom/the_target)
|
||||
if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
|
||||
return 0
|
||||
if(Found(the_target) || ..()) //If we Found it or Can_Attack it normally, we Can_Attack it as long as it wasn't invisible
|
||||
return 1 //as a note this shouldn't be added to base hostile mobs because it'll mess up retaliate hostile mobs
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/MoveToTarget(var/list/possible_targets)
|
||||
..()
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
if(isconstruct(L) && L.health >= L.maxHealth) //is this target an unhurt construct? stop trying to heal it
|
||||
LoseTarget()
|
||||
return 0
|
||||
if(L.health <= melee_damage_lower+melee_damage_upper) //ey bucko you're hurt as fuck let's go hit you
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/Aggro()
|
||||
..()
|
||||
if(isconstruct(target)) //oh the target is a construct no need to flee
|
||||
retreat_distance = null
|
||||
minimum_distance = 1
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/LoseAggro()
|
||||
..()
|
||||
retreat_distance = initial(retreat_distance)
|
||||
minimum_distance = initial(minimum_distance)
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/builder/hostile //actually hostile, will move around, hit things, heal other constructs
|
||||
AIStatus = AI_ON
|
||||
environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP
|
||||
|
||||
/////////////////////////////Non-cult Artificer/////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/builder/noncult
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/wall,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/floor,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/noncult,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser,
|
||||
/obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser)
|
||||
|
||||
|
||||
/////////////////////////////Harvester/////////////////////////
|
||||
/mob/living/simple_animal/hostile/construct/harvester
|
||||
name = "Harvester"
|
||||
real_name = "Harvester"
|
||||
desc = "A long, thin construct built to herald Nar-Sie's rise. It'll be all over soon."
|
||||
icon_state = "harvester"
|
||||
icon_living = "harvester"
|
||||
maxHealth = 60
|
||||
health = 60
|
||||
sight = SEE_MOBS
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
attacktext = "butchers"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/area_conversion,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall)
|
||||
playstyle_string = "<B>You are a Harvester. You are incapable of directly killing humans, but your attacks will remove their limbs: \
|
||||
Bring those who still cling to this world of illusion back to the Geometer so they may know Truth.</B>"
|
||||
can_repair_constructs = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/harvester/Bump(atom/AM)
|
||||
. = ..()
|
||||
if(istype(AM, /turf/closed/wall/mineral/cult) && AM != loc) //we can go through cult walls
|
||||
var/atom/movable/stored_pulling = pulling
|
||||
if(stored_pulling)
|
||||
stored_pulling.setDir(get_dir(stored_pulling.loc, loc))
|
||||
stored_pulling.forceMove(loc)
|
||||
forceMove(AM)
|
||||
if(stored_pulling)
|
||||
start_pulling(stored_pulling, TRUE) //drag anything we're pulling through the wall with us by magic
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/harvester/AttackingTarget()
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
var/list/parts = list()
|
||||
var/undismembermerable_limbs = 0
|
||||
for(var/X in C.bodyparts)
|
||||
var/obj/item/bodypart/BP = X
|
||||
if(BP.body_part != HEAD && BP.body_part != CHEST)
|
||||
if(BP.dismemberable)
|
||||
parts += BP
|
||||
else
|
||||
undismembermerable_limbs++
|
||||
if(!LAZYLEN(parts))
|
||||
if(undismembermerable_limbs) //they have limbs we can't remove, and no parts we can, attack!
|
||||
return ..()
|
||||
to_chat(src, "<span class='cultlarge'>\"Bring [C.p_them()] to me.\"</span>")
|
||||
return FALSE
|
||||
do_attack_animation(C)
|
||||
var/obj/item/bodypart/BP = pick(parts)
|
||||
BP.dismember()
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
|
||||
///////////////////////Master-Tracker///////////////////////
|
||||
|
||||
/datum/action/innate/seek_master
|
||||
name = "Seek your Master"
|
||||
desc = "You and your master share a soul-link that informs you of their location"
|
||||
background_icon_state = "bg_demon"
|
||||
buttontooltipstyle = "cult"
|
||||
button_icon_state = "cult_mark"
|
||||
var/tracking = FALSE
|
||||
var/mob/living/simple_animal/hostile/construct/the_construct
|
||||
|
||||
/datum/action/innate/seek_master/Grant(var/mob/living/C)
|
||||
the_construct = C
|
||||
..()
|
||||
|
||||
/datum/action/innate/seek_master/Activate()
|
||||
if(!the_construct.master)
|
||||
to_chat(the_construct, "<span class='cultitalic'>You have no master to seek!</span>")
|
||||
the_construct.seeking = FALSE
|
||||
return
|
||||
if(tracking)
|
||||
tracking = FALSE
|
||||
the_construct.seeking = FALSE
|
||||
to_chat(the_construct, "<span class='cultitalic'>You are no longer tracking your master.</span>")
|
||||
return
|
||||
else
|
||||
tracking = TRUE
|
||||
the_construct.seeking = TRUE
|
||||
to_chat(the_construct, "<span class='cultitalic'>You are now tracking your master.</span>")
|
||||
|
||||
|
||||
/////////////////////////////ui stuff/////////////////////////////
|
||||
|
||||
/mob/living/simple_animal/hostile/construct/update_health_hud()
|
||||
if(hud_used)
|
||||
if(health >= maxHealth)
|
||||
hud_used.healths.icon_state = "[icon_state]_health0"
|
||||
else if(health > maxHealth*0.8)
|
||||
hud_used.healths.icon_state = "[icon_state]_health2"
|
||||
else if(health > maxHealth*0.6)
|
||||
hud_used.healths.icon_state = "[icon_state]_health3"
|
||||
else if(health > maxHealth*0.4)
|
||||
hud_used.healths.icon_state = "[icon_state]_health4"
|
||||
else if(health > maxHealth*0.2)
|
||||
hud_used.healths.icon_state = "[icon_state]_health5"
|
||||
else
|
||||
hud_used.healths.icon_state = "[icon_state]_health6"
|
||||
|
||||
@@ -44,10 +44,10 @@
|
||||
return TRUE //this doesn't make much sense; you'd thing TRUE would mean it'd process spacemove but it means it doesn't
|
||||
|
||||
/mob/living/simple_animal/shade/attack_animal(mob/living/simple_animal/M)
|
||||
if(isconstruct(M))
|
||||
var/mob/living/simple_animal/hostile/construct/C = M
|
||||
if(!C.can_repair_constructs)
|
||||
return
|
||||
if(isconstruct(M))
|
||||
var/mob/living/simple_animal/hostile/construct/C = M
|
||||
if(!C.can_repair_constructs)
|
||||
return
|
||||
if(health < maxHealth)
|
||||
adjustHealth(-25)
|
||||
Beam(M,icon_state="sendbeam",time=4)
|
||||
|
||||
+1709
-1709
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user