[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:
CitadelStationBot
2017-05-18 09:37:30 -05:00
committed by Poojawa
parent 30279b7f55
commit a317d23a51
27 changed files with 8007 additions and 7963 deletions
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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)
File diff suppressed because it is too large Load Diff
+5
View File
@@ -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
+11
View File
@@ -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"
+24 -13
View File
@@ -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()
+1 -1
View File
@@ -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
View File
@@ -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
+259 -259
View File
@@ -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"
+1 -1
View File
@@ -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
+21 -21
View File
@@ -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")
+134 -134
View File
@@ -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)]&deg;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)]&deg;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
+309 -309
View File
@@ -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
File diff suppressed because it is too large Load Diff
+161 -161
View File
@@ -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
View File
@@ -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
+3
View File
@@ -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."
+201 -201
View File
@@ -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
+1 -1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff