Tg 1 28 sync testing/confirmation (#5178)
* maps, tgui, tools * defines and helpers * onclick and controllers * datums fucking caught that hulk reversal too. * game and shuttle modular * module/admin * oh god they fucking moved antag shit again * haaaaate. Haaaaaaaaaate. * enables moff wings * more modules things * tgstation.dme before I forget something important * some mob stuff * s'more mob/living stuff * some carbon stuff * ayy lmaos and kitchen meat * Human stuff * species things moff wings have a 'none' version too * the rest of the module stuff. * some strings * misc * mob icons * some other icons. * It compiles FUCK BORERS FUCK BORERS
This commit is contained in:
@@ -1,191 +0,0 @@
|
||||
|
||||
//Ok so it's technically a double linked list, bite me.
|
||||
|
||||
/datum/linked_list
|
||||
var/datum/linked_node/head
|
||||
var/datum/linked_node/tail
|
||||
var/node_amt = 0
|
||||
|
||||
|
||||
/datum/linked_node
|
||||
var/value = null
|
||||
var/datum/linked_list/linked_list = null
|
||||
var/datum/linked_node/next_node = null
|
||||
var/datum/linked_node/previous_node = null
|
||||
|
||||
|
||||
/datum/linked_list/proc/IsEmpty()
|
||||
. = (node_amt <= 0)
|
||||
|
||||
|
||||
//Add a linked_node (or value, creating a linked_node) at position
|
||||
//the added node BECOMES the position-th element,
|
||||
//eg: add("Test",5), the 5th node is now "Test", the previous 5th moves up to become the 6th
|
||||
/datum/linked_list/proc/Add(node, position)
|
||||
var/datum/linked_node/adding
|
||||
if(istype(node, /datum/linked_node))
|
||||
adding = node
|
||||
else
|
||||
adding = new()
|
||||
adding.value = node
|
||||
|
||||
if(!adding.linked_list || (adding.linked_list && (adding.linked_list != src)))
|
||||
node_amt++
|
||||
|
||||
adding.linked_list = src
|
||||
|
||||
if(position && position < node_amt)
|
||||
//Replacing head
|
||||
if(position == 1)
|
||||
if(head)
|
||||
head.previous_node = adding
|
||||
adding.next_node = head
|
||||
head = adding
|
||||
|
||||
//Replacing any middle node
|
||||
else
|
||||
var/location = 0
|
||||
var/datum/linked_node/at
|
||||
while((location != position) && (location <= node_amt))
|
||||
if(at)
|
||||
if(at.next_node)
|
||||
at = at.next_node
|
||||
else
|
||||
break
|
||||
else
|
||||
at = head
|
||||
location++
|
||||
|
||||
//Push at up and assume it's place as the position-th element
|
||||
if(at && at.previous_node)
|
||||
at.previous_node.next_node = adding
|
||||
adding.previous_node = at.previous_node
|
||||
at.previous_node = adding
|
||||
adding.next_node = at
|
||||
return
|
||||
|
||||
//Replacing tail
|
||||
if(tail)
|
||||
tail.next_node = adding
|
||||
adding.previous_node = tail
|
||||
if(!tail.previous_node)
|
||||
head = tail
|
||||
tail = adding
|
||||
|
||||
|
||||
|
||||
//Remove a linked_node or the linked_node of a value
|
||||
//If you specify a value the FIRST ONE is removed
|
||||
/datum/linked_list/proc/Remove(node)
|
||||
var/datum/linked_node/removing
|
||||
if(istype(node, /datum/linked_node))
|
||||
removing = node
|
||||
else
|
||||
//optimise removing head and tail, no point looping for them, especially the tail
|
||||
if(removing == head)
|
||||
removing = head
|
||||
else if(removing == tail)
|
||||
removing = tail
|
||||
else
|
||||
var/location = 1
|
||||
var/current_value = null
|
||||
var/datum/linked_node/at = null
|
||||
while((current_value != node) && (location <= node_amt))
|
||||
if(at)
|
||||
if(at.next_node)
|
||||
at = at.next_node
|
||||
else
|
||||
at = head
|
||||
location++
|
||||
if(at)
|
||||
current_value = at.value
|
||||
if(current_value == node)
|
||||
removing = at
|
||||
break
|
||||
|
||||
//Adjust pointers of where removing -was- in the chain.
|
||||
if(removing)
|
||||
if(removing.previous_node)
|
||||
if(removing == tail)
|
||||
tail = removing.previous_node
|
||||
if(removing.next_node)
|
||||
if(removing == head)
|
||||
head = removing.next_node
|
||||
removing.next_node.previous_node = removing.previous_node
|
||||
removing.previous_node.next_node = removing.next_node
|
||||
else
|
||||
removing.previous_node.next_node = null
|
||||
else
|
||||
if(removing.next_node)
|
||||
if(removing == head)
|
||||
head = removing.next_node
|
||||
removing.next_node.previous_node = null
|
||||
|
||||
//if this is still true at this point, there's no more nodes to replace them with
|
||||
if(removing == head)
|
||||
head = null
|
||||
if(removing == tail)
|
||||
tail = null
|
||||
|
||||
removing.next_node = null
|
||||
removing.previous_node = null
|
||||
if(removing.linked_list == src)
|
||||
node_amt--
|
||||
removing.linked_list = null
|
||||
|
||||
return removing
|
||||
return 0
|
||||
|
||||
|
||||
//Removes and deletes a node or value
|
||||
/datum/linked_list/proc/RemoveDelete(node)
|
||||
var/datum/linked_node/dead = Remove(node)
|
||||
if(dead)
|
||||
qdel(dead)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
//Empty the linked_list, deleting all nodes
|
||||
/datum/linked_list/proc/Empty()
|
||||
var/datum/linked_node/n = head
|
||||
while(n)
|
||||
var/next = n.next_node
|
||||
Remove(n)
|
||||
qdel(n)
|
||||
n = next
|
||||
node_amt = 0
|
||||
|
||||
|
||||
//Some debugging tools
|
||||
/datum/linked_list/proc/CheckNodeLinks()
|
||||
var/datum/linked_node/n = head
|
||||
while(n)
|
||||
. = "|[n.value]|"
|
||||
if(n.previous_node)
|
||||
. = "[n.previous_node.value]<-" + .
|
||||
if(n.next_node)
|
||||
. += "->[n.next_node.value]"
|
||||
n = n.next_node
|
||||
. += "<BR>"
|
||||
|
||||
|
||||
/datum/linked_list/proc/DrawNodeLinks()
|
||||
. = "|<-"
|
||||
var/datum/linked_node/n = head
|
||||
while(n)
|
||||
if(n.previous_node)
|
||||
. += "<-"
|
||||
. += "[n.value]"
|
||||
if(n.next_node)
|
||||
. += "->"
|
||||
n = n.next_node
|
||||
. += "->|"
|
||||
|
||||
|
||||
/datum/linked_list/proc/ToList()
|
||||
. = list()
|
||||
var/datum/linked_node/n = head
|
||||
while(n)
|
||||
. += n
|
||||
n = n.next_node
|
||||
@@ -1,83 +0,0 @@
|
||||
|
||||
//////////////////////
|
||||
//PriorityQueue object
|
||||
//////////////////////
|
||||
|
||||
//an ordered list, using the cmp proc to weight the list elements
|
||||
/PriorityQueue
|
||||
var/list/L //the actual queue
|
||||
var/cmp //the weight function used to order the queue
|
||||
|
||||
/PriorityQueue/New(compare)
|
||||
L = new()
|
||||
cmp = compare
|
||||
|
||||
/PriorityQueue/proc/IsEmpty()
|
||||
return !L.len
|
||||
|
||||
//return the index the element should be in the priority queue using dichotomic search
|
||||
/PriorityQueue/proc/FindElementIndex(atom/A)
|
||||
var/i = 1
|
||||
var/j = L.len
|
||||
var/mid
|
||||
|
||||
while(i < j)
|
||||
mid = round((i+j)/2)
|
||||
|
||||
if(call(cmp)(L[mid],A) < 0)
|
||||
i = mid + 1
|
||||
else
|
||||
j = mid
|
||||
|
||||
if(i == 1 || i == L.len) //edge cases
|
||||
return (call(cmp)(L[i],A) > 0) ? i : i+1
|
||||
else
|
||||
return i
|
||||
|
||||
|
||||
//add an element in the list,
|
||||
//immediatly ordering it to its position using dichotomic search
|
||||
/PriorityQueue/proc/Enqueue(atom/A)
|
||||
if(!L.len)
|
||||
L.Add(A)
|
||||
return
|
||||
|
||||
L.Insert(FindElementIndex(A),A)
|
||||
|
||||
//removes and returns the first element in the queue
|
||||
/PriorityQueue/proc/Dequeue()
|
||||
if(!L.len)
|
||||
return 0
|
||||
. = L[1]
|
||||
|
||||
Remove(.)
|
||||
|
||||
//removes an element
|
||||
/PriorityQueue/proc/Remove(atom/A)
|
||||
return L.Remove(A)
|
||||
|
||||
//returns a copy of the elements list
|
||||
/PriorityQueue/proc/List()
|
||||
. = L.Copy()
|
||||
|
||||
//return the position of an element or 0 if not found
|
||||
/PriorityQueue/proc/Seek(atom/A)
|
||||
. = L.Find(A)
|
||||
|
||||
//return the element at the i_th position
|
||||
/PriorityQueue/proc/Get(i)
|
||||
if(i > L.len || i < 1)
|
||||
return 0
|
||||
return L[i]
|
||||
|
||||
//replace the passed element at it's right position using the cmp proc
|
||||
/PriorityQueue/proc/ReSort(atom/A)
|
||||
var/i = Seek(A)
|
||||
if(i == 0)
|
||||
return
|
||||
while(i < L.len && call(cmp)(L[i],L[i+1]) > 0)
|
||||
L.Swap(i,i+1)
|
||||
i++
|
||||
while(i > 1 && call(cmp)(L[i],L[i-1]) <= 0) //last inserted element being first in case of ties (optimization)
|
||||
L.Swap(i,i-1)
|
||||
i--
|
||||
@@ -1,56 +0,0 @@
|
||||
/datum/stack
|
||||
var/list/stack = list()
|
||||
var/max_elements = 0
|
||||
|
||||
/datum/stack/New(list/elements,max)
|
||||
..()
|
||||
if(elements)
|
||||
stack = elements.Copy()
|
||||
if(max)
|
||||
max_elements = max
|
||||
|
||||
/datum/stack/proc/Pop()
|
||||
if(is_empty())
|
||||
return null
|
||||
. = stack[stack.len]
|
||||
stack.Cut(stack.len,0)
|
||||
|
||||
/datum/stack/proc/Push(element)
|
||||
if(max_elements && (stack.len+1 > max_elements))
|
||||
return null
|
||||
stack += element
|
||||
|
||||
/datum/stack/proc/Top()
|
||||
if(is_empty())
|
||||
return null
|
||||
. = stack[stack.len]
|
||||
|
||||
/datum/stack/proc/is_empty()
|
||||
. = stack.len ? 0 : 1
|
||||
|
||||
//Rotate entire stack left with the leftmost looping around to the right
|
||||
/datum/stack/proc/RotateLeft()
|
||||
if(is_empty())
|
||||
return 0
|
||||
. = stack[1]
|
||||
stack.Cut(1,2)
|
||||
Push(.)
|
||||
|
||||
//Rotate entire stack to the right with the rightmost looping around to the left
|
||||
/datum/stack/proc/RotateRight()
|
||||
if(is_empty())
|
||||
return 0
|
||||
. = stack[stack.len]
|
||||
stack.Cut(stack.len,0)
|
||||
stack.Insert(1,.)
|
||||
|
||||
|
||||
/datum/stack/proc/Copy()
|
||||
var/datum/stack/S=new()
|
||||
S.stack = stack.Copy()
|
||||
S.max_elements = max_elements
|
||||
return S
|
||||
|
||||
|
||||
/datum/stack/proc/Clear()
|
||||
stack.Cut()
|
||||
@@ -123,6 +123,7 @@
|
||||
#define SPECIES_INORGANIC 32
|
||||
#define SPECIES_UNDEAD 33
|
||||
#define SPECIES_ROBOTIC 34
|
||||
#define NOEYES 35
|
||||
|
||||
#define ORGAN_SLOT_BRAIN "brain"
|
||||
#define ORGAN_SLOT_APPENDIX "appendix"
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
//See controllers/globals.dm
|
||||
#define GLOBAL_MANAGED(X, InitValue)\
|
||||
/datum/controller/global_vars/proc/InitGlobal##X(){\
|
||||
##X = ##InitValue;\
|
||||
gvars_datum_init_order += #X;\
|
||||
}
|
||||
#define GLOBAL_UNMANAGED(X) /datum/controller/global_vars/proc/InitGlobal##X() { return; }
|
||||
|
||||
#ifndef TESTING
|
||||
#define GLOBAL_PROTECT(X)\
|
||||
/datum/controller/global_vars/InitGlobal##X(){\
|
||||
..();\
|
||||
gvars_datum_protected_varlist[#X] = TRUE;\
|
||||
}
|
||||
#else
|
||||
#define GLOBAL_PROTECT(X)
|
||||
#endif
|
||||
|
||||
#define GLOBAL_REAL_VAR(X) var/global/##X
|
||||
#define GLOBAL_REAL(X, Typepath) var/global##Typepath/##X
|
||||
|
||||
#define GLOBAL_RAW(X) /datum/controller/global_vars/var/global##X
|
||||
|
||||
#define GLOBAL_VAR_INIT(X, InitValue) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_VAR_CONST(X, InitValue) GLOBAL_RAW(/const/##X) = InitValue; GLOBAL_UNMANAGED(X)
|
||||
|
||||
#define GLOBAL_LIST_INIT(X, InitValue) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_LIST_EMPTY(X) GLOBAL_LIST_INIT(X, list())
|
||||
|
||||
#define GLOBAL_DATUM_INIT(X, Typepath, InitValue) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_VAR(X) GLOBAL_RAW(/##X); GLOBAL_UNMANAGED(X)
|
||||
|
||||
#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_UNMANAGED(X)
|
||||
|
||||
#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_UNMANAGED(X)
|
||||
//See controllers/globals.dm
|
||||
#define GLOBAL_MANAGED(X, InitValue)\
|
||||
/datum/controller/global_vars/proc/InitGlobal##X(){\
|
||||
##X = ##InitValue;\
|
||||
gvars_datum_init_order += #X;\
|
||||
}
|
||||
#define GLOBAL_UNMANAGED(X) /datum/controller/global_vars/proc/InitGlobal##X() { return; }
|
||||
|
||||
#ifndef TESTING
|
||||
#define GLOBAL_PROTECT(X)\
|
||||
/datum/controller/global_vars/InitGlobal##X(){\
|
||||
..();\
|
||||
gvars_datum_protected_varlist[#X] = TRUE;\
|
||||
}
|
||||
#else
|
||||
#define GLOBAL_PROTECT(X)
|
||||
#endif
|
||||
|
||||
#define GLOBAL_REAL_VAR(X) var/global/##X
|
||||
#define GLOBAL_REAL(X, Typepath) var/global##Typepath/##X
|
||||
|
||||
#define GLOBAL_RAW(X) /datum/controller/global_vars/var/global##X
|
||||
|
||||
#define GLOBAL_VAR_INIT(X, InitValue) GLOBAL_RAW(/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_VAR_CONST(X, InitValue) GLOBAL_RAW(/const/##X) = InitValue; GLOBAL_UNMANAGED(X)
|
||||
|
||||
#define GLOBAL_LIST_INIT(X, InitValue) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_LIST_EMPTY(X) GLOBAL_LIST_INIT(X, list())
|
||||
|
||||
#define GLOBAL_DATUM_INIT(X, Typepath, InitValue) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, InitValue)
|
||||
|
||||
#define GLOBAL_VAR(X) GLOBAL_RAW(/##X); GLOBAL_UNMANAGED(X)
|
||||
|
||||
#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_UNMANAGED(X)
|
||||
|
||||
#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_UNMANAGED(X)
|
||||
@@ -76,3 +76,8 @@
|
||||
#define AHELP_ACTIVE 1
|
||||
#define AHELP_CLOSED 2
|
||||
#define AHELP_RESOLVED 3
|
||||
|
||||
#define ROUNDSTART_LOGOUT_REPORT_TIME 6000 //Amount of time (in deciseconds) after the rounds starts, that the player disconnect report is issued.
|
||||
|
||||
#define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu
|
||||
#define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#define NUKE_RESULT_FLUKE 0
|
||||
#define NUKE_RESULT_NUKE_WIN 1
|
||||
#define NUKE_RESULT_CREW_WIN 2
|
||||
#define NUKE_RESULT_CREW_WIN_SYNDIES_DEAD 3
|
||||
#define NUKE_RESULT_DISK_LOST 4
|
||||
#define NUKE_RESULT_DISK_STOLEN 5
|
||||
#define NUKE_RESULT_NOSURVIVORS 6
|
||||
#define NUKE_RESULT_WRONG_STATION 7
|
||||
#define NUKE_RESULT_WRONG_STATION_DEAD 8
|
||||
|
||||
#define APPRENTICE_DESTRUCTION "destruction"
|
||||
#define APPRENTICE_BLUESPACE "bluespace"
|
||||
#define APPRENTICE_ROBELESS "robeless"
|
||||
#define APPRENTICE_HEALING "healing"
|
||||
@@ -34,13 +34,7 @@
|
||||
#define CANKNOCKDOWN 2
|
||||
#define CANUNCONSCIOUS 4
|
||||
#define CANPUSH 8
|
||||
#define IGNORESLOWDOWN 16
|
||||
#define GOTTAGOFAST 32
|
||||
#define GOTTAGOREALLYFAST 64
|
||||
#define GODMODE 4096
|
||||
#define FAKEDEATH 8192 //Replaces stuff like changeling.changeling_fakedeath
|
||||
#define DISFIGURED 16384 //I'll probably move this elsewhere if I ever get wround to writing a bitflag mob-damage system
|
||||
#define XENO_HOST 32768 //Tracks whether we're gonna be a baby alien's mummy.
|
||||
#define GODMODE 16
|
||||
|
||||
//Health Defines
|
||||
#define HEALTH_THRESHOLD_CRIT 0
|
||||
|
||||
@@ -61,7 +61,9 @@
|
||||
#define isplasmaman(A) (is_species(A, /datum/species/plasmaman))
|
||||
#define ispodperson(A) (is_species(A, /datum/species/podperson))
|
||||
#define isflyperson(A) (is_species(A, /datum/species/fly))
|
||||
#define isjellyperson(A) (is_species(A, /datum/species/jelly))
|
||||
#define isslimeperson(A) (is_species(A, /datum/species/jelly/slime))
|
||||
#define isluminescent(A) (is_species(A, /datum/species/jelly/luminescent))
|
||||
#define isshadowperson(A) (is_species(A, /datum/species/shadow))
|
||||
#define iszombie(A) (is_species(A, /datum/species/zombie))
|
||||
#define ishumanbasic(A) (is_species(A, /datum/species/human))
|
||||
|
||||
@@ -70,3 +70,9 @@ Last space-z level = empty
|
||||
DECLARE_LEVEL("Lavaland", UNAFFECTED, list(ZTRAIT_MINING = TRUE, ZTRAIT_LAVA_RUINS = TRUE, ZTRAIT_BOMBCAP_MULTIPLIER = 3)),\
|
||||
DECLARE_LEVEL("Reebe", UNAFFECTED, list(ZTRAIT_REEBE = TRUE, ZTRAIT_BOMBCAP_MULTIPLIER = 0.5)),\
|
||||
)
|
||||
|
||||
//Camera lock flags
|
||||
#define CAMERA_LOCK_STATION 1
|
||||
#define CAMERA_LOCK_MINING 2
|
||||
#define CAMERA_LOCK_CENTCOM 4
|
||||
#define CAMERA_LOCK_REEBE 8
|
||||
|
||||
+31
-15
@@ -50,18 +50,19 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
|
||||
//Human Overlays Indexes/////////
|
||||
//LOTS OF CIT CHANGES HERE. BE CAREFUL WHEN UPSTREAM ADDS MORE LAYERS
|
||||
#define MUTATIONS_LAYER 30 //mutations. Tk headglows, cold resistance glow, etc
|
||||
#define GENITALS_BEHIND_LAYER 29 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer
|
||||
#define BODY_BEHIND_LAYER 28 //certain mutantrace features (tail when looking south) that must appear behind the body parts
|
||||
#define BODYPARTS_LAYER 27 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
|
||||
#define BODY_ADJ_LAYER 26 //certain mutantrace features (snout, body markings) that must appear above the body parts
|
||||
#define GENITALS_ADJ_LAYER 25
|
||||
#define BODY_LAYER 24 //underwear, undershirts, socks, eyes, lips(makeup)
|
||||
#define FRONT_MUTATIONS_LAYER 23 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes)
|
||||
#define DAMAGE_LAYER 22 //damage indicators (cuts and burns)
|
||||
#define UNIFORM_LAYER 21
|
||||
#define ID_LAYER 20
|
||||
#define SHOES_LAYER 19
|
||||
#define MUTATIONS_LAYER 31 //mutations. Tk headglows, cold resistance glow, etc
|
||||
#define GENITALS_BEHIND_LAYER 30 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer
|
||||
#define BODY_BEHIND_LAYER 29 //certain mutantrace features (tail when looking south) that must appear behind the body parts
|
||||
#define BODYPARTS_LAYER 28 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
|
||||
#define BODY_ADJ_LAYER 27 //certain mutantrace features (snout, body markings) that must appear above the body parts
|
||||
#define GENITALS_ADJ_LAYER 26
|
||||
#define BODY_LAYER 25 //underwear, undershirts, socks, eyes, lips(makeup)
|
||||
#define FRONT_MUTATIONS_LAYER 24 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes)
|
||||
#define DAMAGE_LAYER 23 //damage indicators (cuts and burns)
|
||||
#define UNIFORM_LAYER 22
|
||||
#define ID_LAYER 21
|
||||
#define SHOES_LAYER 20
|
||||
#define HANDS_PART_LAYER 19
|
||||
#define GLOVES_LAYER 18
|
||||
#define EARS_LAYER 17
|
||||
#define SUIT_LAYER 16
|
||||
@@ -80,7 +81,7 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
#define HANDS_LAYER 3
|
||||
#define BODY_FRONT_LAYER 2
|
||||
#define FIRE_LAYER 1 //If you're on fire
|
||||
#define TOTAL_LAYERS 30 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_;
|
||||
#define TOTAL_LAYERS 31 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_;
|
||||
|
||||
//Human Overlay Index Shortcuts for alternate_worn_layer, layers
|
||||
//Because I *KNOW* somebody will think layer+1 means "above"
|
||||
@@ -93,8 +94,9 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
#define UNDER_DAMAGE_LAYER DAMAGE_LAYER+1
|
||||
#define UNDER_UNIFORM_LAYER UNIFORM_LAYER+1
|
||||
#define UNDER_ID_LAYER ID_LAYER+1
|
||||
#define UNDER_SHOES_LAYER SHOES_LAYER+1
|
||||
#define UNDER_HANDS_PART_LAYER HANDS_PART_LAYER+1
|
||||
#define UNDER_GLOVES_LAYER GLOVES_LAYER+1
|
||||
#define UNDER_SHOES_LAYER SHOES_LAYER+1
|
||||
#define UNDER_EARS_LAYER EARS_LAYER+1
|
||||
#define UNDER_SUIT_LAYER SUIT_LAYER+1
|
||||
#define UNDER_GLASSES_LAYER GLASSES_LAYER+1
|
||||
@@ -119,8 +121,9 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
#define ABOVE_DAMAGE_LAYER DAMAGE_LAYER-1
|
||||
#define ABOVE_UNIFORM_LAYER UNIFORM_LAYER-1
|
||||
#define ABOVE_ID_LAYER ID_LAYER-1
|
||||
#define ABOVE_SHOES_LAYER SHOES_LAYER-1
|
||||
#define ABOVE_HANDS_PART_LAYER HANDS_PART_LAYER-1
|
||||
#define ABOVE_GLOVES_LAYER GLOVES_LAYER-1
|
||||
#define ABOVE_SHOES_LAYER SHOES_LAYER-1
|
||||
#define ABOVE_EARS_LAYER EARS_LAYER-1
|
||||
#define ABOVE_SUIT_LAYER SUIT_LAYER-1
|
||||
#define ABOVE_GLASSES_LAYER GLASSES_LAYER-1
|
||||
@@ -488,6 +491,12 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
|
||||
#define HOSTILE_SPAWN 1
|
||||
#define FRIENDLY_SPAWN 2
|
||||
|
||||
//slime core activation type
|
||||
#define SLIME_ACTIVATE_MINOR 1
|
||||
#define SLIME_ACTIVATE_MAJOR 2
|
||||
|
||||
#define LUMINESCENT_DEFAULT_GLOW 2
|
||||
|
||||
#define RIDING_OFFSET_ALL "ALL"
|
||||
|
||||
//text files
|
||||
@@ -499,3 +508,10 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
|
||||
|
||||
#define SUMMON_GUNS "guns"
|
||||
#define SUMMON_MAGIC "magic"
|
||||
|
||||
//Run the world with this parameter to enable a single run though of the game setup and tear down process with unit tests in between
|
||||
#define TEST_RUN_PARAMETER "test-run"
|
||||
//Force the log directory to be something specific in the data/logs folder
|
||||
#define OVERRIDE_LOG_DIRECTORY_PARAMETER "log-directory"
|
||||
//Prevent the master controller from starting automatically, overrides TEST_RUN_PARAMETER
|
||||
#define NO_INIT_PARAMETER "no-init"
|
||||
|
||||
+18
-1
@@ -188,4 +188,21 @@
|
||||
#define OFFSET_BELT "belt"
|
||||
#define OFFSET_BACK "back"
|
||||
#define OFFSET_SUIT "suit"
|
||||
#define OFFSET_NECK "neck"
|
||||
#define OFFSET_NECK "neck"
|
||||
|
||||
//MINOR TWEAKS/MISC
|
||||
#define AGE_MIN 17 //youngest a character can be
|
||||
#define AGE_MAX 85 //oldest a character can be
|
||||
#define WIZARD_AGE_MIN 30 //youngest a wizard can be
|
||||
#define APPRENTICE_AGE_MIN 29 //youngest an apprentice can be
|
||||
#define SHOES_SLOWDOWN 0 //How much shoes slow you down by default. Negative values speed you up
|
||||
#define POCKET_STRIP_DELAY 40 //time taken (in deciseconds) to search somebody's pockets
|
||||
#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you
|
||||
|
||||
#define HUNGER_FACTOR 0.1 //factor at which mob nutrition decreases
|
||||
#define REAGENTS_METABOLISM 0.4 //How many units of reagent are consumed per tick, by default.
|
||||
#define REAGENTS_EFFECT_MULTIPLIER (REAGENTS_METABOLISM / 0.4) // By defining the effect multiplier this way, it'll exactly adjust all effects according to how they originally were with the 0.4 metabolism
|
||||
|
||||
// AI Toggles
|
||||
#define AI_CAMERA_LUMINOSITY 5
|
||||
#define AI_VOX // Comment out if you don't want VOX to be enabled and have players download the voice sounds.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Flags for the obj_flags var on /obj
|
||||
|
||||
|
||||
#define EMAGGED 1
|
||||
#define IN_USE 2 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
|
||||
#define CAN_BE_HIT 4 //can this be bludgeoned by items?
|
||||
#define BEING_SHOCKED 8 // Whether this thing is currently (already) being shocked by a tesla
|
||||
#define DANGEROUS_POSSESSION 16 //Admin possession yes/no
|
||||
#define ON_BLUEPRINTS 32 //Are we visible on the station blueprints at roundstart?
|
||||
#define UNIQUE_RENAME 64 // can you customize the description/name of the thing?
|
||||
|
||||
// If you add new ones, be sure to add them to /obj/Initialize as well for complete mapping support
|
||||
|
||||
// Flags for the item_flags var on /obj/item
|
||||
|
||||
#define BEING_REMOVED 1
|
||||
#define IN_INVENTORY 2 //is this item equipped into an inventory slot or hand of a mob? used for tooltips
|
||||
#define FORCE_STRING_OVERRIDE 4 // used for tooltips
|
||||
#define NEEDS_PERMIT 8 //Used by security bots to determine if this item is safe for public use.
|
||||
@@ -56,4 +56,10 @@
|
||||
#define LINGHIVE_NONE 0
|
||||
#define LINGHIVE_OUTSIDER 1
|
||||
#define LINGHIVE_LING 2
|
||||
#define LINGHIVE_LINK 3
|
||||
#define LINGHIVE_LINK 3
|
||||
|
||||
//Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam
|
||||
#define MAX_MESSAGE_LEN 1024
|
||||
#define MAX_NAME_LEN 42
|
||||
#define MAX_BROADCAST_LEN 512
|
||||
#define MAX_CHARTER_LEN 80
|
||||
|
||||
@@ -8,35 +8,6 @@
|
||||
#define UNCONSCIOUS 2
|
||||
#define DEAD 3
|
||||
|
||||
//mob disabilities stat
|
||||
|
||||
#define DISABILITY_BLIND "blind"
|
||||
#define DISABILITY_MUTE "mute"
|
||||
#define DISABILITY_DEAF "deaf"
|
||||
#define DISABILITY_NEARSIGHT "nearsighted"
|
||||
#define DISABILITY_FAT "fat"
|
||||
#define DISABILITY_HUSK "husk"
|
||||
#define DISABILITY_NOCLONE "noclone"
|
||||
#define DISABILITY_CLUMSY "clumsy"
|
||||
#define DISABILITY_DUMB "dumb"
|
||||
#define DISABILITY_MONKEYLIKE "monkeylike" //sets IsAdvancedToolUser to FALSE
|
||||
#define DISABILITY_PACIFISM "pacifism"
|
||||
|
||||
// common disability sources
|
||||
#define EYE_DAMAGE "eye_damage"
|
||||
#define GENETIC_MUTATION "genetic"
|
||||
#define OBESITY "obesity"
|
||||
#define MAGIC_DISABILITY "magic"
|
||||
#define STASIS_MUTE "stasis"
|
||||
#define GENETICS_SPELL "genetics_spell"
|
||||
#define TRAUMA_DISABILITY "trauma"
|
||||
#define CHEMICAL_DISABILITY "chemical"
|
||||
|
||||
// unique disability sources, still defines
|
||||
#define STATUE_MUTE "statue"
|
||||
#define CHANGELING_DRAIN "drain"
|
||||
#define ABYSSAL_GAZE_BLIND "abyssal_gaze"
|
||||
|
||||
// bitflags for machine stat variable
|
||||
#define BROKEN 1
|
||||
#define NOPOWER 2
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
//Update this whenever the db schema changes
|
||||
//make sure you add an update to the schema_version stable in the db changelog
|
||||
#define DB_MAJOR_VERSION 4
|
||||
#define DB_MINOR_VERSION 0
|
||||
|
||||
//Timing subsystem
|
||||
//Don't run if there is an identical unique timer active
|
||||
|
||||
@@ -22,6 +22,6 @@ When using time2text(), please use "DDD" to find the weekday. Refrain from using
|
||||
|
||||
#define TICKS *world.tick_lag
|
||||
|
||||
#define DS2TICKS(DS) (DS/world.tick_lag)
|
||||
#define DS2TICKS(DS) ((DS)/world.tick_lag)
|
||||
|
||||
#define TICKS2DS(T) (T TICKS)
|
||||
#define TICKS2DS(T) ((T) TICKS)
|
||||
@@ -1,6 +1,7 @@
|
||||
#define TOOL_NONE 0
|
||||
#define TOOL_CROWBAR 1
|
||||
#define TOOL_MULTITOOL 2
|
||||
#define TOOL_SCREWDRIVER 3
|
||||
#define TOOL_WIRECUTTER 4
|
||||
#define TOOL_WRENCH 5
|
||||
// Tool types
|
||||
#define TOOL_CROWBAR "crowbar"
|
||||
#define TOOL_MULTITOOL "multitool"
|
||||
#define TOOL_SCREWDRIVER "screwdriver"
|
||||
#define TOOL_WIRECUTTER "wirecutter"
|
||||
#define TOOL_WRENCH "wrench"
|
||||
#define TOOL_WELDER "welder"
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
//mob traits
|
||||
#define TRAIT_BLIND "blind"
|
||||
#define TRAIT_MUTE "mute"
|
||||
#define TRAIT_DEAF "deaf"
|
||||
#define TRAIT_NEARSIGHT "nearsighted"
|
||||
#define TRAIT_FAT "fat"
|
||||
#define TRAIT_HUSK "husk"
|
||||
#define TRAIT_NOCLONE "noclone"
|
||||
#define TRAIT_CLUMSY "clumsy"
|
||||
#define TRAIT_DUMB "dumb"
|
||||
#define TRAIT_MONKEYLIKE "monkeylike" //sets IsAdvancedToolUser to FALSE
|
||||
#define TRAIT_PACIFISM "pacifism"
|
||||
#define TRAIT_IGNORESLOWDOWN "ignoreslow"
|
||||
#define TRAIT_GOTTAGOFAST "fast"
|
||||
#define TRAIT_GOTTAGOREALLYFAST "2fast"
|
||||
#define TRAIT_FAKEDEATH "fakedeath"
|
||||
#define TRAIT_DISFIGURED "disfigured"
|
||||
#define TRAIT_XENO_HOST "xeno_host" //Tracks whether we're gonna be a baby alien's mummy.
|
||||
#define TRAIT_STUNIMMUNE "stun_immunity"
|
||||
#define TRAIT_PUSHIMMUNE "push_immunity"
|
||||
|
||||
// common trait sources
|
||||
#define TRAIT_GENERIC "generic"
|
||||
#define EYE_DAMAGE "eye_damage"
|
||||
#define GENETIC_MUTATION "genetic"
|
||||
#define OBESITY "obesity"
|
||||
#define MAGIC_TRAIT "magic"
|
||||
#define STASIS_MUTE "stasis"
|
||||
#define GENETICS_SPELL "genetics_spell"
|
||||
#define TRAUMA_TRAIT "trauma"
|
||||
|
||||
// unique trait sources, still defines
|
||||
#define STATUE_MUTE "statue"
|
||||
#define CHANGELING_DRAIN "drain"
|
||||
#define ABYSSAL_GAZE_BLIND "abyssal_gaze"
|
||||
#define HIGHLANDER "highlander"
|
||||
#define TRAIT_HULK "hulk"
|
||||
@@ -18,4 +18,4 @@
|
||||
#define VV_NULL "NULL"
|
||||
#define VV_RESTORE_DEFAULT "Restore to Default"
|
||||
#define VV_MARKED_DATUM "Marked Datum"
|
||||
|
||||
#define VV_BITFIELD "Bitfield"
|
||||
|
||||
@@ -24,6 +24,12 @@
|
||||
#define testing(msg)
|
||||
#endif
|
||||
|
||||
#ifdef UNIT_TESTS
|
||||
/proc/log_test(text)
|
||||
WRITE_FILE(GLOB.test_log, "\[[time_stamp()]]: [text]")
|
||||
SEND_TEXT(world.log, text)
|
||||
#endif
|
||||
|
||||
/proc/log_admin(text)
|
||||
GLOB.admin_log.Add(text)
|
||||
if (CONFIG_GET(flag/log_admin))
|
||||
|
||||
@@ -241,9 +241,6 @@
|
||||
processing_list += A.contents
|
||||
|
||||
/proc/get_mobs_in_radio_ranges(list/obj/item/device/radio/radios)
|
||||
|
||||
set background = BACKGROUND_ENABLED
|
||||
|
||||
. = list()
|
||||
// Returns a list of mobs who can hear any of the radios given in @radios
|
||||
for(var/obj/item/device/radio/R in radios)
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/spines_animated, GLOB.animated_spines_list)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/legs, GLOB.legs_list)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.r_wings_list,roundstart = TRUE)
|
||||
|
||||
//moffs
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list)
|
||||
|
||||
//CIT CHANGES START HERE, ADDS SNOWFLAKE BODYPARTS AND MORE
|
||||
//mammal bodyparts (fucking furries)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/mam_body_markings, GLOB.mam_body_markings_list)
|
||||
|
||||
+39
-9
@@ -32,7 +32,7 @@
|
||||
else
|
||||
return pick(GLOB.underwear_list)*/
|
||||
|
||||
/proc/random_undershirt(gender)//Cit change - makes random underwear always return nude
|
||||
/proc/random_undershirt(gender)//Cit change - makes random undershirts always return nude
|
||||
if(!GLOB.undershirt_list.len)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/undershirt, GLOB.undershirt_list, GLOB.undershirt_m, GLOB.undershirt_f)
|
||||
return "Nude"
|
||||
@@ -44,7 +44,7 @@
|
||||
else
|
||||
return pick(GLOB.undershirt_list)*/
|
||||
|
||||
/proc/random_socks()//Cit change - makes random underwear always return nude
|
||||
/proc/random_socks()//Cit change - makes random socks always return nude
|
||||
if(!GLOB.socks_list.len)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/socks, GLOB.socks_list)
|
||||
return "Nude"
|
||||
@@ -71,6 +71,8 @@
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/body_markings, GLOB.body_markings_list)
|
||||
if(!GLOB.wings_list.len)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/wings, GLOB.wings_list)
|
||||
if(!GLOB.moth_wings_list.len)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_wings, GLOB.moth_wings_list)
|
||||
|
||||
//CIT CHANGES - genitals and such
|
||||
if(!GLOB.cock_shapes_list.len)
|
||||
@@ -109,6 +111,7 @@
|
||||
"spines" = pick(GLOB.spines_list),
|
||||
"body_markings" = pick(GLOB.body_markings_list),
|
||||
"legs" = "Normal Legs",
|
||||
"moth_wings" = pick(GLOB.moth_wings_list),
|
||||
"taur" = "None",
|
||||
"mam_body_markings" = "None",
|
||||
"mam_ears" = "None",
|
||||
@@ -163,7 +166,6 @@
|
||||
"womb_efficiency" = CUM_EFFICIENCY,
|
||||
"womb_fluid" = "femcum",
|
||||
"flavor_text" = ""))
|
||||
|
||||
/proc/random_hair_style(gender)
|
||||
switch(gender)
|
||||
if(MALE)
|
||||
@@ -183,27 +185,34 @@
|
||||
return pick(GLOB.facial_hair_styles_list)
|
||||
|
||||
/proc/random_unique_name(gender, attempts_to_find_unique_name=10)
|
||||
for(var/i=1, i<=attempts_to_find_unique_name, i++)
|
||||
for(var/i in 1 to attempts_to_find_unique_name)
|
||||
if(gender==FEMALE)
|
||||
. = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
|
||||
else
|
||||
. = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
|
||||
|
||||
if(i != attempts_to_find_unique_name && !findname(.))
|
||||
if(!findname(.))
|
||||
break
|
||||
|
||||
/proc/random_unique_lizard_name(gender, attempts_to_find_unique_name=10)
|
||||
for(var/i=1, i<=attempts_to_find_unique_name, i++)
|
||||
for(var/i in 1 to attempts_to_find_unique_name)
|
||||
. = capitalize(lizard_name(gender))
|
||||
|
||||
if(i != attempts_to_find_unique_name && !findname(.))
|
||||
if(!findname(.))
|
||||
break
|
||||
|
||||
/proc/random_unique_plasmaman_name(attempts_to_find_unique_name=10)
|
||||
for(var/i=1, i<=attempts_to_find_unique_name, i++)
|
||||
for(var/i in 1 to attempts_to_find_unique_name)
|
||||
. = capitalize(plasmaman_name())
|
||||
|
||||
if(i != attempts_to_find_unique_name && !findname(.))
|
||||
if(!findname(.))
|
||||
break
|
||||
|
||||
/proc/random_unique_moth_name(attempts_to_find_unique_name=10)
|
||||
for(var/i in 1 to attempts_to_find_unique_name)
|
||||
. = capitalize(moth_name())
|
||||
|
||||
if(!findname(.))
|
||||
break
|
||||
|
||||
/proc/random_skin_tone()
|
||||
@@ -580,3 +589,24 @@ Proc for attack log creation, because really why not
|
||||
warning("Invalid speech logging type detected. [logtype]. Defaulting to say")
|
||||
log_say(logmessage)
|
||||
|
||||
//Used in chemical_mob_spawn. Generates a random mob based on a given gold_core_spawnable value.
|
||||
/proc/create_random_mob(spawn_location, mob_class = HOSTILE_SPAWN)
|
||||
var/static/list/mob_spawn_meancritters = list() // list of possible hostile mobs
|
||||
var/static/list/mob_spawn_nicecritters = list() // and possible friendly mobs
|
||||
|
||||
if(mob_spawn_meancritters.len <= 0 || mob_spawn_nicecritters.len <= 0)
|
||||
for(var/T in typesof(/mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/SA = T
|
||||
switch(initial(SA.gold_core_spawnable))
|
||||
if(HOSTILE_SPAWN)
|
||||
mob_spawn_meancritters += T
|
||||
if(FRIENDLY_SPAWN)
|
||||
mob_spawn_nicecritters += T
|
||||
|
||||
var/chosen
|
||||
if(mob_class == FRIENDLY_SPAWN)
|
||||
chosen = pick(mob_spawn_nicecritters)
|
||||
else
|
||||
chosen = pick(mob_spawn_meancritters)
|
||||
var/mob/living/simple_animal/C = new chosen(spawn_location)
|
||||
return C
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
/proc/plasmaman_name()
|
||||
return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"
|
||||
|
||||
/proc/moth_name()
|
||||
return "[pick(GLOB.moth_names)]"
|
||||
|
||||
/proc/church_name()
|
||||
var/static/church_name
|
||||
if (church_name)
|
||||
|
||||
@@ -391,6 +391,7 @@
|
||||
if(X.get_team() == T)
|
||||
all_antagonists -= X
|
||||
result += " "//newline between teams
|
||||
CHECK_TICK
|
||||
|
||||
var/currrent_category
|
||||
var/datum/antagonist/previous_category
|
||||
@@ -410,6 +411,7 @@
|
||||
previous_category = A
|
||||
result += A.roundend_report()
|
||||
result += "<br><br>"
|
||||
CHECK_TICK
|
||||
|
||||
if(all_antagonists.len)
|
||||
var/datum/antagonist/last = all_antagonists[all_antagonists.len]
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
if(toIndex <= 0)
|
||||
toIndex += L.len + 1
|
||||
|
||||
GLOB.sortInstance.L = L
|
||||
GLOB.sortInstance.cmp = cmp
|
||||
GLOB.sortInstance.associative = associative
|
||||
var/datum/sortInstance/SI = GLOB.sortInstance
|
||||
if(!SI)
|
||||
SI = new
|
||||
SI.L = L
|
||||
SI.cmp = cmp
|
||||
SI.associative = associative
|
||||
|
||||
GLOB.sortInstance.binarySort(fromIndex, toIndex, fromIndex)
|
||||
SI.binarySort(fromIndex, toIndex, fromIndex)
|
||||
return L
|
||||
@@ -8,9 +8,12 @@
|
||||
if(toIndex <= 0)
|
||||
toIndex += L.len + 1
|
||||
|
||||
GLOB.sortInstance.L = L
|
||||
GLOB.sortInstance.cmp = cmp
|
||||
GLOB.sortInstance.associative = associative
|
||||
GLOB.sortInstance.mergeSort(fromIndex, toIndex)
|
||||
var/datum/sortInstance/SI = GLOB.sortInstance
|
||||
if(!SI)
|
||||
SI = new
|
||||
SI.L = L
|
||||
SI.cmp = cmp
|
||||
SI.associative = associative
|
||||
|
||||
SI.mergeSort(fromIndex, toIndex)
|
||||
return L
|
||||
@@ -8,10 +8,13 @@
|
||||
if(toIndex <= 0)
|
||||
toIndex += L.len + 1
|
||||
|
||||
GLOB.sortInstance.L = L
|
||||
GLOB.sortInstance.cmp = cmp
|
||||
GLOB.sortInstance.associative = associative
|
||||
var/datum/sortInstance/SI = GLOB.sortInstance
|
||||
if(!SI)
|
||||
SI = new
|
||||
|
||||
GLOB.sortInstance.timSort(fromIndex, toIndex)
|
||||
SI.L = L
|
||||
SI.cmp = cmp
|
||||
SI.associative = associative
|
||||
|
||||
SI.timSort(fromIndex, toIndex)
|
||||
return L
|
||||
@@ -65,6 +65,7 @@
|
||||
return .
|
||||
|
||||
//Splits the text of a file at seperator and returns them in a list.
|
||||
//returns an empty list if the file doesn't exist
|
||||
/world/proc/file2list(filename, seperator="\n", trim = TRUE)
|
||||
if (trim)
|
||||
return splittext(trim(file2text(filename)),seperator)
|
||||
@@ -589,4 +590,4 @@
|
||||
for(var/i = 1 to length(str)/2)
|
||||
c= hex2num(copytext(str,i*2-1,i*2+1))
|
||||
r+= ascii2text(c)
|
||||
return r
|
||||
return r
|
||||
|
||||
@@ -1511,7 +1511,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
usr = M
|
||||
. = CB.Invoke()
|
||||
usr = temp
|
||||
|
||||
|
||||
//Returns a list of all servants of Ratvar and observers.
|
||||
/proc/servants_and_ghosts()
|
||||
. = list()
|
||||
|
||||
@@ -34,6 +34,7 @@ GLOBAL_LIST_EMPTY(ears_list)
|
||||
GLOBAL_LIST_EMPTY(wings_list)
|
||||
GLOBAL_LIST_EMPTY(wings_open_list)
|
||||
GLOBAL_LIST_EMPTY(r_wings_list)
|
||||
GLOBAL_LIST_EMPTY(moth_wings_list)
|
||||
|
||||
GLOBAL_LIST_INIT(ghost_forms_with_directions_list, list("ghost")) //stores the ghost forms that support directional sprites
|
||||
GLOBAL_LIST_INIT(ghost_forms_with_accessories_list, list("ghost")) //stores the ghost forms that support hair and other such things
|
||||
|
||||
@@ -13,6 +13,7 @@ GLOBAL_LIST_INIT(clown_names, world.file2list("strings/names/clown.txt"))
|
||||
GLOBAL_LIST_INIT(mime_names, world.file2list("strings/names/mime.txt"))
|
||||
GLOBAL_LIST_INIT(carp_names, world.file2list("strings/names/carp.txt"))
|
||||
GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt"))
|
||||
GLOBAL_LIST_INIT(moth_names, world.file2list("strings/names/moth.txt"))
|
||||
GLOBAL_LIST_INIT(plasmaman_names, world.file2list("strings/names/plasmaman.txt"))
|
||||
GLOBAL_LIST_INIT(posibrain_names, world.file2list("strings/names/posibrain.txt"))
|
||||
GLOBAL_LIST_INIT(nightmare_names, world.file2list("strings/names/nightmare.txt"))
|
||||
|
||||
@@ -17,4 +17,10 @@ GLOBAL_LIST_EMPTY(powernets)
|
||||
|
||||
GLOBAL_VAR_INIT(bsa_unlock, FALSE) //BSA unlocked by head ID swipes
|
||||
|
||||
GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details
|
||||
GLOBAL_LIST_EMPTY(player_details) // ckey -> /datum/player_details
|
||||
|
||||
GLOBAL_LIST_INIT(bitfields, list(
|
||||
"obj_flags" = list("EMAGGED" = EMAGGED, "IN_USE" = IN_USE, "CAN_BE_HIT" = CAN_BE_HIT, "BEING_SHOCKED" = BEING_SHOCKED, "DANGEROUS_POSSESSION" = DANGEROUS_POSSESSION, "ON_BLUEPRINTS" = ON_BLUEPRINTS, "UNIQUE_RENAME" = UNIQUE_RENAME),
|
||||
"datum_flags" = list("DF_USE_TAG" = DF_USE_TAG, "DF_VAR_EDITED" = DF_VAR_EDITED),
|
||||
"item_flags" = list("BEING_REMOVED" = BEING_REMOVED, "IN_INVENTORY" = IN_INVENTORY, "FORCE_STRING_OVERRIDE" = FORCE_STRING_OVERRIDE, "NEEDS_PERMIT" = NEEDS_PERMIT)
|
||||
))
|
||||
|
||||
+6
-6
@@ -130,16 +130,16 @@
|
||||
|
||||
/* Airlocks */
|
||||
/obj/machinery/door/airlock/AICtrlClick() // Bolts doors
|
||||
if(emagged)
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
|
||||
|
||||
if(locked)
|
||||
bolt_raise(usr)
|
||||
else
|
||||
bolt_drop(usr)
|
||||
|
||||
/obj/machinery/door/airlock/AIAltClick() // Eletrifies doors.
|
||||
if(emagged)
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
|
||||
if(!secondsElectrified)
|
||||
@@ -148,15 +148,15 @@
|
||||
shock_restore(usr)
|
||||
|
||||
/obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors!
|
||||
if(emagged)
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
|
||||
user_toggle_open(usr)
|
||||
|
||||
/obj/machinery/door/airlock/AICtrlShiftClick() // Sets/Unsets Emergency Access Override
|
||||
if(emagged)
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
|
||||
|
||||
if(!emergency)
|
||||
emergency_on(usr)
|
||||
else
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
/obj/item/proc/melee_attack_chain(mob/user, atom/target, params)
|
||||
if(!tool_check(user, target) && pre_attackby(target, user, params))
|
||||
if(!tool_attack_chain(user, target) && pre_attackby(target, user, params))
|
||||
// Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example)
|
||||
var/resolved = target.attackby(src, user, params)
|
||||
if(!resolved && target && !QDELETED(src))
|
||||
@@ -8,20 +8,11 @@
|
||||
|
||||
|
||||
//Checks if the item can work as a tool, calling the appropriate tool behavior on the target
|
||||
/obj/item/proc/tool_check(mob/user, atom/target)
|
||||
switch(tool_behaviour)
|
||||
if(TOOL_NONE)
|
||||
return FALSE
|
||||
if(TOOL_CROWBAR)
|
||||
return target.crowbar_act(user, src)
|
||||
if(TOOL_MULTITOOL)
|
||||
return target.multitool_act(user, src)
|
||||
if(TOOL_SCREWDRIVER)
|
||||
return target.screwdriver_act(user, src)
|
||||
if(TOOL_WRENCH)
|
||||
return target.wrench_act(user, src)
|
||||
if(TOOL_WIRECUTTER)
|
||||
return target.wirecutter_act(user, src)
|
||||
/obj/item/proc/tool_attack_chain(mob/user, atom/target)
|
||||
if(!tool_behaviour)
|
||||
return FALSE
|
||||
|
||||
return target.tool_act(user, src, tool_behaviour)
|
||||
|
||||
|
||||
// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
|
||||
@@ -39,7 +30,7 @@
|
||||
return FALSE
|
||||
|
||||
/obj/attackby(obj/item/I, mob/living/user, params)
|
||||
return ..() || (can_be_hit && I.attack_obj(src, user))
|
||||
return ..() || ((obj_flags & CAN_BE_HIT) && I.attack_obj(src, user))
|
||||
|
||||
/mob/living/attackby(obj/item/I, mob/living/user, params)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
@@ -59,10 +50,10 @@
|
||||
if(flags_1 & NOBLUDGEON_1)
|
||||
return
|
||||
|
||||
if(force && user.has_disability(DISABILITY_PACIFISM))
|
||||
if(force && user.has_trait(TRAIT_PACIFISM))
|
||||
to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
|
||||
return
|
||||
|
||||
|
||||
if(!force)
|
||||
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1)
|
||||
else if(hitsound)
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "toy9"
|
||||
can_suppress = 0
|
||||
needs_permit = 0
|
||||
obj_flags = 0
|
||||
mag_type = /obj/item/ammo_box/magazine/toy/x9
|
||||
casing_ejector = 0
|
||||
spread = 90 //MAXIMUM XCOM MEMES (actually that'd be 180 spread)
|
||||
@@ -489,7 +489,7 @@
|
||||
name = "foamag rifle"
|
||||
desc = "A foam launching magnetic rifle. Ages 8 and up."
|
||||
icon_state = "foamagrifle"
|
||||
needs_permit = FALSE
|
||||
obj_flags = 0
|
||||
mag_type = /obj/item/ammo_box/magazine/toy/foamag
|
||||
casing_ejector = FALSE
|
||||
spread = 60
|
||||
@@ -617,7 +617,7 @@
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "toyburst"
|
||||
clumsy_check = FALSE
|
||||
needs_permit = FALSE
|
||||
obj_flags = 0
|
||||
fire_delay = 40
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
selfcharge = TRUE
|
||||
@@ -772,7 +772,7 @@ obj/item/projectile/bullet/c10mm/soporific
|
||||
caliber = "flechette"
|
||||
throwforce = 2
|
||||
throw_speed = 3
|
||||
embed_chance = 75
|
||||
embedding = list("embedded_pain_multiplier" = 0, "embed_chance" = 40, "embedded_fall_chance" = 10)
|
||||
|
||||
///magazine///
|
||||
|
||||
@@ -858,7 +858,7 @@ obj/item/projectile/bullet/c10mm/soporific
|
||||
icon = 'icons/obj/guns/cit_guns.dmi'
|
||||
icon_state = "cde"
|
||||
can_unsuppress = TRUE
|
||||
unique_rename = TRUE
|
||||
obj_flags = UNIQUE_RENAME
|
||||
unique_reskin = list("Default" = "cde",
|
||||
"NT-99" = "n99",
|
||||
"Stealth" = "stealthpistol",
|
||||
@@ -1154,7 +1154,7 @@ obj/item/projectile/bullet/c10mm/soporific
|
||||
icon_state = "p37_foam"
|
||||
pin = /obj/item/device/firing_pin
|
||||
spawnwithmagazine = TRUE
|
||||
needs_permit = FALSE
|
||||
obj_flags = 0
|
||||
mag_type = /obj/item/ammo_box/magazine/toy/pistol
|
||||
can_suppress = FALSE
|
||||
actions_types = list(/datum/action/item_action/pick_color)
|
||||
|
||||
@@ -31,32 +31,30 @@
|
||||
/obj/item/dogborg/jaws/small/attack_self(mob/user)
|
||||
var/mob/living/silicon/robot.R = user
|
||||
if(R.emagged)
|
||||
emagged = !emagged
|
||||
if(emagged)
|
||||
name = "combat jaws"
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "jaws"
|
||||
desc = "The jaws of the law."
|
||||
flags_1 = CONDUCT_1
|
||||
force = 12
|
||||
throwforce = 0
|
||||
hitsound = 'sound/weapons/bite.ogg'
|
||||
attack_verb = list("chomped", "bit", "ripped", "mauled", "enforced")
|
||||
w_class = 3
|
||||
sharpness = IS_SHARP
|
||||
else
|
||||
name = "puppy jaws"
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "smalljaws"
|
||||
desc = "The jaws of a small dog."
|
||||
flags_1 = CONDUCT_1
|
||||
force = 5
|
||||
throwforce = 0
|
||||
hitsound = 'sound/weapons/bite.ogg'
|
||||
attack_verb = list("nibbled", "bit", "gnawed", "chomped", "nommed")
|
||||
w_class = 3
|
||||
sharpness = IS_SHARP
|
||||
update_icon()
|
||||
name = "combat jaws"
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "jaws"
|
||||
desc = "The jaws of the law."
|
||||
flags_1 = CONDUCT_1
|
||||
force = 12
|
||||
throwforce = 0
|
||||
hitsound = 'sound/weapons/bite.ogg'
|
||||
attack_verb = list("chomped", "bit", "ripped", "mauled", "enforced")
|
||||
w_class = 3
|
||||
sharpness = IS_SHARP
|
||||
else
|
||||
name = "puppy jaws"
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "smalljaws"
|
||||
desc = "The jaws of a small dog."
|
||||
flags_1 = CONDUCT_1
|
||||
force = 5
|
||||
throwforce = 0
|
||||
hitsound = 'sound/weapons/bite.ogg'
|
||||
attack_verb = list("nibbled", "bit", "gnawed", "chomped", "nommed")
|
||||
w_class = 3
|
||||
sharpness = IS_SHARP
|
||||
update_icon()
|
||||
|
||||
|
||||
//Cuffs
|
||||
@@ -189,107 +187,101 @@
|
||||
/obj/item/soap/tongue/attack_self(mob/user)
|
||||
var/mob/living/silicon/robot.R = user
|
||||
if(R.emagged)
|
||||
emagged = !emagged
|
||||
if(emagged)
|
||||
name = "hacked tongue of doom"
|
||||
desc = "Your tongue has been upgraded successfully. Congratulations."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "syndietongue"
|
||||
cleanspeed = 10 //(nerf'd)tator soap stat
|
||||
else
|
||||
name = "synthetic tongue"
|
||||
desc = "Useful for slurping mess off the floor before affectionally licking the crew members in the face."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "synthtongue"
|
||||
cleanspeed = initial(cleanspeed)
|
||||
update_icon()
|
||||
name = "hacked tongue of doom"
|
||||
desc = "Your tongue has been upgraded successfully. Congratulations."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "syndietongue"
|
||||
cleanspeed = 10 //(nerf'd)tator soap stat
|
||||
else
|
||||
name = "synthetic tongue"
|
||||
desc = "Useful for slurping mess off the floor before affectionally licking the crew members in the face."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "synthtongue"
|
||||
cleanspeed = initial(cleanspeed)
|
||||
update_icon()
|
||||
|
||||
/obj/item/soap/tongue/afterattack(atom/target, mob/user, proximity)
|
||||
var/mob/living/silicon/robot.R = user
|
||||
if(!proximity || !check_allowed_items(target))
|
||||
return
|
||||
if(user.client && (target in user.client.screen))
|
||||
to_chat(user, "<span class='warning'>You need to take that [target.name] off before cleaning it!</span>")
|
||||
if(R.client && (target in R.client.screen))
|
||||
to_chat(R, "<span class='warning'>You need to take that [target.name] off before cleaning it!</span>")
|
||||
else if(istype(target,/obj/effect/decal/cleanable))
|
||||
user.visible_message("[user] begins to lick off \the [target.name].", "<span class='warning'>You begin to lick off \the [target.name]...</span>")
|
||||
if(do_after(user, src.cleanspeed, target = target))
|
||||
R.visible_message("[R] begins to lick off \the [target.name].", "<span class='warning'>You begin to lick off \the [target.name]...</span>")
|
||||
if(do_after(R, src.cleanspeed, target = target))
|
||||
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
|
||||
return //If they moved away, you can't eat them.
|
||||
to_chat(user, "<span class='notice'>You finish licking off \the [target.name].</span>")
|
||||
to_chat(R, "<span class='notice'>You finish licking off \the [target.name].</span>")
|
||||
qdel(target)
|
||||
var/mob/living/silicon/robot.R = user
|
||||
R.cell.give(50)
|
||||
else if(istype(target,/obj/item)) //hoo boy. danger zone man
|
||||
if(istype(target,/obj/item/trash))
|
||||
user.visible_message("[user] nibbles away at \the [target.name].", "<span class='warning'>You begin to nibble away at \the [target.name]...</span>")
|
||||
if(do_after(user, src.cleanspeed, target = target))
|
||||
R.visible_message("[R] nibbles away at \the [target.name].", "<span class='warning'>You begin to nibble away at \the [target.name]...</span>")
|
||||
if(do_after(R, src.cleanspeed, target = target))
|
||||
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
|
||||
return //If they moved away, you can't eat them.
|
||||
to_chat(user, "<span class='notice'>You finish off \the [target.name].</span>")
|
||||
to_chat(R, "<span class='notice'>You finish off \the [target.name].</span>")
|
||||
qdel(target)
|
||||
var/mob/living/silicon/robot.R = user
|
||||
R.cell.give(250)
|
||||
return
|
||||
if(istype(target,/obj/item/stock_parts/cell))
|
||||
user.visible_message("[user] begins cramming \the [target.name] down its throat.", "<span class='warning'>You begin cramming \the [target.name] down your throat...</span>")
|
||||
if(do_after(user, 50, target = target))
|
||||
R.visible_message("[R] begins cramming \the [target.name] down its throat.", "<span class='warning'>You begin cramming \the [target.name] down your throat...</span>")
|
||||
if(do_after(R, 50, target = target))
|
||||
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
|
||||
return //If they moved away, you can't eat them.
|
||||
to_chat(user, "<span class='notice'>You finish off \the [target.name].</span>")
|
||||
var/mob/living/silicon/robot.R = user
|
||||
to_chat(R, "<span class='notice'>You finish off \the [target.name].</span>")
|
||||
var/obj/item/stock_parts/cell.C = target
|
||||
R.cell.charge = R.cell.charge + (C.charge / 3) //Instant full cell upgrades op idgaf
|
||||
qdel(target)
|
||||
return
|
||||
var/obj/item/I = target //HAHA FUCK IT, NOT LIKE WE ALREADY HAVE A SHITTON OF WAYS TO REMOVE SHIT
|
||||
if(!I.anchored && src.emagged)
|
||||
user.visible_message("[user] begins chewing up \the [target.name]. Looks like it's trying to loophole around its diet restriction!", "<span class='warning'>You begin chewing up \the [target.name]...</span>")
|
||||
if(do_after(user, 100, target = I)) //Nerf dat time yo
|
||||
if(!I.anchored && R.emagged)
|
||||
R.visible_message("[R] begins chewing up \the [target.name]. Looks like it's trying to loophole around its diet restriction!", "<span class='warning'>You begin chewing up \the [target.name]...</span>")
|
||||
if(do_after(R, 100, target = I)) //Nerf dat time yo
|
||||
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check. Even emags don't make you magically eat things at range.
|
||||
return //If they moved away, you can't eat them.
|
||||
visible_message("<span class='warning'>[user] chews up \the [target.name] and cleans off the debris!</span>")
|
||||
to_chat(user, "<span class='notice'>You finish off \the [target.name].</span>")
|
||||
visible_message("<span class='warning'>[R] chews up \the [target.name] and cleans off the debris!</span>")
|
||||
to_chat(R, "<span class='notice'>You finish off \the [target.name].</span>")
|
||||
qdel(I)
|
||||
var/mob/living/silicon/robot.R = user
|
||||
R.cell.give(500)
|
||||
return
|
||||
user.visible_message("[user] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
|
||||
if(do_after(user, src.cleanspeed, target = target))
|
||||
R.visible_message("[R] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
|
||||
if(do_after(R, src.cleanspeed, target = target))
|
||||
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
|
||||
return //If they moved away, you can't clean them.
|
||||
to_chat(user,"<span class='notice'>You clean \the [target.name].</span>")
|
||||
to_chat(R,"<span class='notice'>You clean \the [target.name].</span>")
|
||||
var/obj/effect/decal/cleanable/C = locate() in target
|
||||
qdel(C)
|
||||
SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
|
||||
else if(ishuman(target))
|
||||
if(src.emagged)
|
||||
var/mob/living/silicon/robot.R = user
|
||||
if(R.emagged)
|
||||
var/mob/living/L = target
|
||||
if(R.cell.charge <= 666)
|
||||
return
|
||||
L.Stun(4) // normal stunbaton is force 7 gimme a break good sir!
|
||||
L.Knockdown(80)
|
||||
L.apply_effect(STUTTER, 4)
|
||||
L.visible_message("<span class='danger'>[user] has shocked [L] with its tongue!</span>", \
|
||||
"<span class='userdanger'>[user] has shocked you with its tongue! You can feel the betrayal.</span>")
|
||||
L.visible_message("<span class='danger'>[R] has shocked [L] with its tongue!</span>", \
|
||||
"<span class='userdanger'>[R] has shocked you with its tongue! You can feel the betrayal.</span>")
|
||||
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
|
||||
R.cell.use(666)
|
||||
else
|
||||
user.visible_message("<span class='warning'>\the [user] affectionally licks \the [target]'s face!</span>", "<span class='notice'>You affectionally lick \the [target]'s face!</span>")
|
||||
R.visible_message("<span class='warning'>\the [R] affectionally licks \the [target]'s face!</span>", "<span class='notice'>You affectionally lick \the [target]'s face!</span>")
|
||||
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
|
||||
return
|
||||
else if(istype(target, /obj/structure/window))
|
||||
user.visible_message("[user] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
|
||||
if(do_after(user, src.cleanspeed, target = target))
|
||||
R.visible_message("[R] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
|
||||
if(do_after(R, src.cleanspeed, target = target))
|
||||
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
|
||||
return //If they moved away, you can't clean them.
|
||||
to_chat(user, "<span class='notice'>You clean \the [target.name].</span>")
|
||||
to_chat(R, "<span class='notice'>You clean \the [target.name].</span>")
|
||||
target.color = initial(target.color)
|
||||
else
|
||||
user.visible_message("[user] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
|
||||
if(do_after(user, src.cleanspeed, target = target))
|
||||
R.visible_message("[R] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
|
||||
if(do_after(R, src.cleanspeed, target = target))
|
||||
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
|
||||
return //If they moved away, you can't clean them.
|
||||
to_chat(user, "<span class='notice'>You clean \the [target.name].</span>")
|
||||
to_chat(R, "<span class='notice'>You clean \the [target.name].</span>")
|
||||
var/obj/effect/decal/cleanable/C = locate() in target
|
||||
qdel(C)
|
||||
SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
|
||||
|
||||
@@ -260,7 +260,7 @@
|
||||
for(var/L in relevant_layers) //Less hardcode
|
||||
H.remove_overlay(L)
|
||||
|
||||
if(H.has_disability(DISABILITY_HUSK))
|
||||
if(H.has_trait(TRAIT_HUSK))
|
||||
return
|
||||
//start scanning for genitals
|
||||
//var/list/worn_stuff = H.get_equipped_items()//cache this list so it's not built again
|
||||
|
||||
@@ -49,6 +49,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
var/map_loading = FALSE //Are we loading in a new map?
|
||||
|
||||
var/current_runlevel //for scheduling different subsystems for different stages of the round
|
||||
var/sleep_offline_after_initializations = TRUE
|
||||
|
||||
var/static/restart_clear = 0
|
||||
var/static/restart_timeout = 0
|
||||
@@ -65,7 +66,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
|
||||
|
||||
if(!random_seed)
|
||||
random_seed = rand(1, 1e9)
|
||||
random_seed = (TEST_RUN_PARAMETER in world.params) ? 29051994 : rand(1, 1e9)
|
||||
rand_seed(random_seed)
|
||||
|
||||
var/list/_subsystems = list()
|
||||
@@ -197,11 +198,12 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
// Sort subsystems by display setting for easy access.
|
||||
sortTim(subsystems, /proc/cmp_subsystem_display)
|
||||
// Set world options.
|
||||
world.sleep_offline = TRUE
|
||||
if(sleep_offline_after_initializations)
|
||||
world.sleep_offline = TRUE
|
||||
world.fps = CONFIG_GET(number/fps)
|
||||
var/initialized_tod = REALTIMEOFDAY
|
||||
sleep(1)
|
||||
if(CONFIG_GET(flag/resume_after_initializations))
|
||||
if(sleep_offline_after_initializations && CONFIG_GET(flag/resume_after_initializations))
|
||||
world.sleep_offline = FALSE
|
||||
initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10
|
||||
// Loop.
|
||||
|
||||
@@ -76,7 +76,7 @@ SUBSYSTEM_DEF(augury)
|
||||
active = FALSE
|
||||
UpdateButtonIcon()
|
||||
|
||||
/datum/action/innate/augury/UpdateButtonIcon(status_only = FALSE)
|
||||
/datum/action/innate/augury/UpdateButtonIcon(status_only = FALSE, force)
|
||||
..()
|
||||
if(active)
|
||||
button.icon_state = "template_active"
|
||||
|
||||
@@ -332,7 +332,6 @@ SUBSYSTEM_DEF(garbage)
|
||||
/datum/verb/find_refs()
|
||||
set category = "Debug"
|
||||
set name = "Find References"
|
||||
set background = 1
|
||||
set src in world
|
||||
|
||||
find_references(FALSE)
|
||||
@@ -385,7 +384,6 @@ SUBSYSTEM_DEF(garbage)
|
||||
/datum/verb/qdel_then_find_references()
|
||||
set category = "Debug"
|
||||
set name = "qdel() then Find References"
|
||||
set background = 1
|
||||
set src in world
|
||||
|
||||
qdel(src)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
SUBSYSTEM_DEF(idlenpcpool)
|
||||
name = "Idling NPC Pool"
|
||||
flags = SS_POST_FIRE_TIMING|SS_BACKGROUND
|
||||
flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
|
||||
priority = FIRE_PRIORITY_IDLE_NPC
|
||||
wait = 60
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
@@ -13,9 +13,12 @@ SUBSYSTEM_DEF(idlenpcpool)
|
||||
var/list/zlist = GLOB.simple_animals[AI_Z_OFF]
|
||||
..("IdleNPCS:[idlelist.len]|Z:[zlist.len]")
|
||||
|
||||
/datum/controller/subsystem/idlenpcpool/Initialize(start_timeofday)
|
||||
idle_mobs_by_zlevel = new /list(world.maxz,0)
|
||||
return ..()
|
||||
/datum/controller/subsystem/idlenpcpool/proc/MaxZChanged()
|
||||
if (!islist(idle_mobs_by_zlevel))
|
||||
idle_mobs_by_zlevel = new /list(world.maxz,0)
|
||||
while (SSidlenpcpool.idle_mobs_by_zlevel.len < world.maxz)
|
||||
SSidlenpcpool.idle_mobs_by_zlevel.len++
|
||||
SSidlenpcpool.idle_mobs_by_zlevel[idle_mobs_by_zlevel.len] = list()
|
||||
|
||||
/datum/controller/subsystem/idlenpcpool/fire(resumed = FALSE)
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ SUBSYSTEM_DEF(input)
|
||||
"North", "East", "South", "West",
|
||||
"Northeast", "Southeast", "Northwest", "Southwest",
|
||||
"Insert", "Delete", "Ctrl", "Alt",
|
||||
"F1", "F2", "F5", "F6", "F7", "F8", "F12",
|
||||
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
|
||||
)
|
||||
|
||||
for(var/i in 1 to oldmode_keys.len)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
SUBSYSTEM_DEF(mobs)
|
||||
name = "Mobs"
|
||||
priority = FIRE_PRIORITY_MOBS
|
||||
flags = SS_KEEP_TIMING
|
||||
flags = SS_KEEP_TIMING | SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/list/currentrun = list()
|
||||
@@ -10,9 +10,12 @@ SUBSYSTEM_DEF(mobs)
|
||||
/datum/controller/subsystem/mobs/stat_entry()
|
||||
..("P:[GLOB.mob_living_list.len]")
|
||||
|
||||
/datum/controller/subsystem/mobs/Initialize(start_timeofday)
|
||||
clients_by_zlevel = new /list(world.maxz,0)
|
||||
return ..()
|
||||
/datum/controller/subsystem/mobs/proc/MaxZChanged()
|
||||
if (!islist(clients_by_zlevel))
|
||||
clients_by_zlevel = new /list(world.maxz,0)
|
||||
while (clients_by_zlevel.len < world.maxz)
|
||||
clients_by_zlevel.len++
|
||||
clients_by_zlevel[clients_by_zlevel.len] = list()
|
||||
|
||||
/datum/controller/subsystem/mobs/fire(resumed = 0)
|
||||
var/seconds = wait * 0.1
|
||||
|
||||
@@ -8,6 +8,8 @@ SUBSYSTEM_DEF(shuttle)
|
||||
flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK
|
||||
runlevels = RUNLEVEL_SETUP | RUNLEVEL_GAME
|
||||
|
||||
var/obj/machinery/shuttle_manipulator/manipulator
|
||||
|
||||
var/list/mobile = list()
|
||||
var/list/stationary = list()
|
||||
var/list/transit = list()
|
||||
@@ -53,19 +55,10 @@ SUBSYSTEM_DEF(shuttle)
|
||||
var/list/shuttle_purchase_requirements_met = list() //For keeping track of ingame events that would unlock new shuttles, such as defeating a boss or discovering a secret item
|
||||
|
||||
var/lockdown = FALSE //disallow transit after nuke goes off
|
||||
|
||||
|
||||
var/auto_call = 99000 //CIT CHANGE - time before in deciseconds in which the shuttle is auto called. Default is 2½ hours plus 15 for the shuttle. So total is 3.
|
||||
|
||||
/datum/controller/subsystem/shuttle/Initialize(timeofday)
|
||||
if(!arrivals)
|
||||
WARNING("No /obj/docking_port/mobile/arrivals placed on the map!")
|
||||
if(!emergency)
|
||||
WARNING("No /obj/docking_port/mobile/emergency placed on the map!")
|
||||
if(!backup_shuttle)
|
||||
WARNING("No /obj/docking_port/mobile/emergency/backup placed on the map!")
|
||||
if(!supply)
|
||||
WARNING("No /obj/docking_port/mobile/supply placed on the map!")
|
||||
|
||||
ordernum = rand(1, 9000)
|
||||
|
||||
for(var/pack in subtypesof(/datum/supply_pack))
|
||||
@@ -76,12 +69,32 @@ SUBSYSTEM_DEF(shuttle)
|
||||
|
||||
if(!transit_turfs.len)
|
||||
setup_transit_zone()
|
||||
initial_move()
|
||||
|
||||
initial_load()
|
||||
|
||||
#ifdef HIGHLIGHT_DYNAMIC_TRANSIT
|
||||
color_space()
|
||||
#endif
|
||||
|
||||
if(!arrivals)
|
||||
WARNING("No /obj/docking_port/mobile/arrivals placed on the map!")
|
||||
if(!emergency)
|
||||
WARNING("No /obj/docking_port/mobile/emergency placed on the map!")
|
||||
if(!backup_shuttle)
|
||||
WARNING("No /obj/docking_port/mobile/emergency/backup placed on the map!")
|
||||
if(!supply)
|
||||
WARNING("No /obj/docking_port/mobile/supply placed on the map!")
|
||||
..()
|
||||
|
||||
/datum/controller/subsystem/shuttle/proc/initial_load()
|
||||
if(!istype(manipulator))
|
||||
CRASH("No shuttle manipulator found.")
|
||||
|
||||
for(var/s in stationary)
|
||||
var/obj/docking_port/stationary/S = s
|
||||
S.load_roundstart()
|
||||
CHECK_TICK
|
||||
|
||||
/datum/controller/subsystem/shuttle/proc/setup_transit_zone()
|
||||
// transit zone
|
||||
var/z = SSmapping.transit.z_value
|
||||
@@ -436,14 +449,6 @@ SUBSYSTEM_DEF(shuttle)
|
||||
if(!(M in transit_requesters))
|
||||
transit_requesters += M
|
||||
|
||||
|
||||
/datum/controller/subsystem/shuttle/proc/autoEnd() //CIT CHANGE - allows shift to end after 3 hours has passed.
|
||||
if(world.time > auto_call && EMERGENCY_IDLE_OR_RECALLED) //3 hours
|
||||
SSshuttle.emergency.request(null, 1.5)
|
||||
priority_announce("The shift has come to an end and the shuttle called.")
|
||||
log_game("Round time limit reached. Shuttle has been auto-called.")
|
||||
message_admins("Round time limit reached. Shuttle called.")
|
||||
|
||||
/datum/controller/subsystem/shuttle/proc/generate_transit_dock(obj/docking_port/mobile/M)
|
||||
// First, determine the size of the needed zone
|
||||
// Because of shuttle rotation, the "width" of the shuttle is not
|
||||
@@ -558,15 +563,7 @@ SUBSYSTEM_DEF(shuttle)
|
||||
T.flags_1 &= ~(UNUSED_TRANSIT_TURF_1)
|
||||
|
||||
M.assigned_transit = new_transit_dock
|
||||
return TRUE
|
||||
|
||||
/datum/controller/subsystem/shuttle/proc/initial_move()
|
||||
for(var/obj/docking_port/mobile/M in mobile)
|
||||
if(!M.roundstart_move)
|
||||
continue
|
||||
M.dockRoundstart()
|
||||
M.roundstart_move = FALSE
|
||||
CHECK_TICK
|
||||
return new_transit_dock
|
||||
|
||||
/datum/controller/subsystem/shuttle/Recover()
|
||||
if (istype(SSshuttle.mobile))
|
||||
|
||||
+197
-100
@@ -1,5 +1,6 @@
|
||||
#define BUCKET_LEN (world.fps*1*60) //how many ticks should we keep in the bucket. (1 minutes worth)
|
||||
#define BUCKET_POS(timer) (round((timer.timeToRun - SStimer.head_offset) / world.tick_lag) + 1)
|
||||
#define BUCKET_POS(timer) ((round((timer.timeToRun - SStimer.head_offset) / world.tick_lag) % BUCKET_LEN) + 1)
|
||||
#define TIMER_MAX (world.time + TICKS2DS(min(BUCKET_LEN-(SStimer.practical_offset-DS2TICKS(world.time - SStimer.head_offset))-1, BUCKET_LEN-1)))
|
||||
#define TIMER_ID_MAX (2**24) //max float with integer precision
|
||||
|
||||
SUBSYSTEM_DEF(timer)
|
||||
@@ -9,11 +10,11 @@ SUBSYSTEM_DEF(timer)
|
||||
|
||||
flags = SS_TICKER|SS_NO_INIT
|
||||
|
||||
var/list/datum/timedevent/processing = list()
|
||||
var/list/datum/timedevent/second_queue = list() //awe, yes, you've had first queue, but what about second queue?
|
||||
var/list/hashes = list()
|
||||
|
||||
var/head_offset = 0 //world.time of the first entry in the the bucket.
|
||||
var/practical_offset = 0 //index of the first non-empty item in the bucket.
|
||||
var/practical_offset = 1 //index of the first non-empty item in the bucket.
|
||||
var/bucket_resolution = 0 //world.tick_lag the bucket was designed for
|
||||
var/bucket_count = 0 //how many timers are in the buckets
|
||||
|
||||
@@ -27,13 +28,19 @@ SUBSYSTEM_DEF(timer)
|
||||
var/static/last_invoke_warning = 0
|
||||
var/static/bucket_auto_reset = TRUE
|
||||
|
||||
/datum/controller/subsystem/timer/PreInit()
|
||||
bucket_list.len = BUCKET_LEN
|
||||
head_offset = world.time
|
||||
bucket_resolution = world.tick_lag
|
||||
|
||||
/datum/controller/subsystem/timer/stat_entry(msg)
|
||||
..("B:[bucket_count] P:[length(processing)] H:[length(hashes)] C:[length(clienttime_timers)]")
|
||||
..("B:[bucket_count] P:[length(second_queue)] H:[length(hashes)] C:[length(clienttime_timers)] S:[length(timer_id_dict)]")
|
||||
|
||||
/datum/controller/subsystem/timer/fire(resumed = FALSE)
|
||||
var/lit = last_invoke_tick
|
||||
var/last_check = world.time - TIMER_NO_INVOKE_WARNING
|
||||
var/list/bucket_list = src.bucket_list
|
||||
|
||||
if(!bucket_count)
|
||||
last_invoke_tick = world.time
|
||||
|
||||
@@ -60,50 +67,62 @@ SUBSYSTEM_DEF(timer)
|
||||
bucket_node = bucket_node.next
|
||||
anti_loop_check--
|
||||
while(bucket_node && bucket_node != bucket_head && anti_loop_check)
|
||||
log_world("Active timers in the processing queue:")
|
||||
for(var/I in processing)
|
||||
log_world("Active timers in the second_queue queue:")
|
||||
for(var/I in second_queue)
|
||||
log_world(get_timer_debug_string(I))
|
||||
|
||||
while(length(clienttime_timers))
|
||||
var/datum/timedevent/ctime_timer = clienttime_timers[clienttime_timers.len]
|
||||
if (ctime_timer.timeToRun <= REALTIMEOFDAY)
|
||||
--clienttime_timers.len
|
||||
var/datum/callback/callBack = ctime_timer.callBack
|
||||
ctime_timer.spent = REALTIMEOFDAY
|
||||
callBack.InvokeAsync()
|
||||
qdel(ctime_timer)
|
||||
else
|
||||
break //None of the rest are ready to run
|
||||
var/next_clienttime_timer_index = 0
|
||||
var/len = length(clienttime_timers)
|
||||
|
||||
for (next_clienttime_timer_index in 1 to len)
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
next_clienttime_timer_index--
|
||||
break
|
||||
var/datum/timedevent/ctime_timer = clienttime_timers[next_clienttime_timer_index]
|
||||
if (ctime_timer.timeToRun > REALTIMEOFDAY)
|
||||
next_clienttime_timer_index--
|
||||
break
|
||||
|
||||
var/datum/callback/callBack = ctime_timer.callBack
|
||||
if (!callBack)
|
||||
clienttime_timers.Cut(next_clienttime_timer_index,next_clienttime_timer_index+1)
|
||||
CRASH("Invalid timer: [get_timer_debug_string(ctime_timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset], REALTIMEOFDAY: [REALTIMEOFDAY]")
|
||||
|
||||
ctime_timer.spent = REALTIMEOFDAY
|
||||
callBack.InvokeAsync()
|
||||
qdel(ctime_timer)
|
||||
|
||||
|
||||
if (next_clienttime_timer_index)
|
||||
clienttime_timers.Cut(1,next_clienttime_timer_index+1)
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
var/static/list/spent = list()
|
||||
var/static/datum/timedevent/timer
|
||||
var/static/datum/timedevent/head
|
||||
if (practical_offset > BUCKET_LEN)
|
||||
head_offset += TICKS2DS(BUCKET_LEN)
|
||||
practical_offset = 1
|
||||
resumed = FALSE
|
||||
|
||||
if (practical_offset > BUCKET_LEN || (!resumed && length(bucket_list) != BUCKET_LEN || world.tick_lag != bucket_resolution))
|
||||
shift_buckets()
|
||||
if ((length(bucket_list) != BUCKET_LEN) || (world.tick_lag != bucket_resolution))
|
||||
reset_buckets()
|
||||
bucket_list = src.bucket_list
|
||||
resumed = FALSE
|
||||
|
||||
|
||||
if (!resumed)
|
||||
timer = null
|
||||
head = null
|
||||
|
||||
while (practical_offset <= BUCKET_LEN && head_offset + (practical_offset*world.tick_lag) <= world.time && !MC_TICK_CHECK)
|
||||
while (practical_offset <= BUCKET_LEN && head_offset + (practical_offset*world.tick_lag) <= world.time)
|
||||
var/datum/timedevent/head = bucket_list[practical_offset]
|
||||
if (!timer || !head || timer == head)
|
||||
head = bucket_list[practical_offset]
|
||||
if (!head)
|
||||
practical_offset++
|
||||
if (MC_TICK_CHECK)
|
||||
break
|
||||
continue
|
||||
timer = head
|
||||
do
|
||||
while (timer)
|
||||
var/datum/callback/callBack = timer.callBack
|
||||
if (!callBack)
|
||||
qdel(timer)
|
||||
bucket_resolution = null //force bucket recreation
|
||||
CRASH("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
|
||||
|
||||
@@ -113,15 +132,68 @@ SUBSYSTEM_DEF(timer)
|
||||
callBack.InvokeAsync()
|
||||
last_invoke_tick = world.time
|
||||
|
||||
timer = timer.next
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
while (timer && timer != head)
|
||||
timer = null
|
||||
|
||||
timer = timer.next
|
||||
if (timer == head)
|
||||
break
|
||||
|
||||
|
||||
bucket_list[practical_offset++] = null
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
//we freed up a bucket, lets see if anything in second_queue needs to be shifted to that bucket.
|
||||
var/i = 0
|
||||
var/L = length(second_queue)
|
||||
for (i in 1 to L)
|
||||
timer = second_queue[i]
|
||||
if (timer.timeToRun >= TIMER_MAX)
|
||||
i--
|
||||
break
|
||||
|
||||
if (timer.timeToRun < head_offset)
|
||||
bucket_resolution = null //force bucket recreation
|
||||
CRASH("[i] Invalid timer state: Timer in long run queue with a time to run less then head_offset. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
|
||||
|
||||
if (timer.callBack && !timer.spent)
|
||||
timer.callBack.InvokeAsync()
|
||||
spent += timer
|
||||
bucket_count++
|
||||
else if(!QDELETED(timer))
|
||||
qdel(timer)
|
||||
continue
|
||||
|
||||
if (timer.timeToRun < head_offset + TICKS2DS(practical_offset))
|
||||
bucket_resolution = null //force bucket recreation
|
||||
CRASH("[i] Invalid timer state: Timer in long run queue that would require a backtrack to transfer to short run queue. [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
|
||||
if (timer.callBack && !timer.spent)
|
||||
timer.callBack.InvokeAsync()
|
||||
spent += timer
|
||||
bucket_count++
|
||||
else if(!QDELETED(timer))
|
||||
qdel(timer)
|
||||
continue
|
||||
|
||||
bucket_count++
|
||||
var/bucket_pos = max(1, BUCKET_POS(timer))
|
||||
|
||||
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
|
||||
if (!bucket_head)
|
||||
bucket_list[bucket_pos] = timer
|
||||
timer.next = null
|
||||
timer.prev = null
|
||||
continue
|
||||
|
||||
if (!bucket_head.prev)
|
||||
bucket_head.prev = bucket_head
|
||||
timer.next = bucket_head
|
||||
timer.prev = bucket_head.prev
|
||||
timer.next.prev = timer
|
||||
timer.prev.next = timer
|
||||
if (i)
|
||||
second_queue.Cut(1, i+1)
|
||||
|
||||
timer = null
|
||||
|
||||
bucket_count -= length(spent)
|
||||
|
||||
@@ -141,7 +213,7 @@ SUBSYSTEM_DEF(timer)
|
||||
if(!TE.callBack)
|
||||
. += ", NO CALLBACK"
|
||||
|
||||
/datum/controller/subsystem/timer/proc/shift_buckets()
|
||||
/datum/controller/subsystem/timer/proc/reset_buckets()
|
||||
var/list/bucket_list = src.bucket_list
|
||||
var/list/alltimers = list()
|
||||
//collect the timers currently in the bucket
|
||||
@@ -162,7 +234,7 @@ SUBSYSTEM_DEF(timer)
|
||||
head_offset = world.time
|
||||
bucket_resolution = world.tick_lag
|
||||
|
||||
alltimers += processing
|
||||
alltimers += second_queue
|
||||
if (!length(alltimers))
|
||||
return
|
||||
|
||||
@@ -173,22 +245,26 @@ SUBSYSTEM_DEF(timer)
|
||||
if (head.timeToRun < head_offset)
|
||||
head_offset = head.timeToRun
|
||||
|
||||
var/list/timers_to_remove = list()
|
||||
|
||||
for (var/thing in alltimers)
|
||||
var/datum/timedevent/timer = thing
|
||||
var/new_bucket_count
|
||||
var/i = 1
|
||||
for (i in 1 to length(alltimers))
|
||||
var/datum/timedevent/timer = alltimers[1]
|
||||
if (!timer)
|
||||
timers_to_remove += timer
|
||||
continue
|
||||
|
||||
var/bucket_pos = BUCKET_POS(timer)
|
||||
if (bucket_pos > BUCKET_LEN)
|
||||
if (timer.timeToRun >= TIMER_MAX)
|
||||
i--
|
||||
break
|
||||
|
||||
timers_to_remove += timer //remove it from the big list once we are done
|
||||
|
||||
if (!timer.callBack || timer.spent)
|
||||
WARNING("Invalid timer: [get_timer_debug_string(timer)] world.time: [world.time], head_offset: [head_offset], practical_offset: [practical_offset]")
|
||||
if (timer.callBack)
|
||||
qdel(timer)
|
||||
continue
|
||||
bucket_count++
|
||||
|
||||
new_bucket_count++
|
||||
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
|
||||
if (!bucket_head)
|
||||
bucket_list[bucket_pos] = timer
|
||||
@@ -202,12 +278,14 @@ SUBSYSTEM_DEF(timer)
|
||||
timer.prev = bucket_head.prev
|
||||
timer.next.prev = timer
|
||||
timer.prev.next = timer
|
||||
|
||||
processing = (alltimers - timers_to_remove)
|
||||
if (i)
|
||||
alltimers.Cut(1, i+1)
|
||||
second_queue = alltimers
|
||||
bucket_count = new_bucket_count
|
||||
|
||||
|
||||
/datum/controller/subsystem/timer/Recover()
|
||||
processing |= SStimer.processing
|
||||
second_queue |= SStimer.second_queue
|
||||
hashes |= SStimer.hashes
|
||||
timer_id_dict |= SStimer.timer_id_dict
|
||||
bucket_list |= SStimer.bucket_list
|
||||
@@ -224,9 +302,8 @@ SUBSYSTEM_DEF(timer)
|
||||
var/datum/timedevent/next
|
||||
var/datum/timedevent/prev
|
||||
|
||||
var/static/nextid = 1
|
||||
|
||||
/datum/timedevent/New(datum/callback/callBack, timeToRun, flags, hash)
|
||||
var/static/nextid = 1
|
||||
id = TIMER_ID_NULL
|
||||
src.callBack = callBack
|
||||
src.timeToRun = timeToRun
|
||||
@@ -235,56 +312,69 @@ SUBSYSTEM_DEF(timer)
|
||||
|
||||
if (flags & TIMER_UNIQUE)
|
||||
SStimer.hashes[hash] = src
|
||||
|
||||
if (flags & TIMER_STOPPABLE)
|
||||
do
|
||||
if (nextid >= TIMER_ID_MAX)
|
||||
nextid = 1
|
||||
id = nextid++
|
||||
while(SStimer.timer_id_dict["timerid" + num2text(id, 8)])
|
||||
SStimer.timer_id_dict["timerid" + num2text(id, 8)] = src
|
||||
id = num2text(nextid, 100)
|
||||
if (nextid >= SHORT_REAL_LIMIT)
|
||||
nextid += min(1, 2**round(nextid/SHORT_REAL_LIMIT))
|
||||
else
|
||||
nextid++
|
||||
SStimer.timer_id_dict[id] = src
|
||||
|
||||
name = "Timer: " + num2text(id, 8) + ", TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT")), ", ")], callBack: [REF(callBack)], callBack.object: [callBack.object][REF(callBack.object)]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])"
|
||||
name = "Timer: [id] (\ref[src]), TTR: [timeToRun], Flags: [jointext(bitfield2list(flags, list("TIMER_UNIQUE", "TIMER_OVERRIDE", "TIMER_CLIENT_TIME", "TIMER_STOPPABLE", "TIMER_NO_HASH_WAIT")), ", ")], callBack: \ref[callBack], callBack.object: [callBack.object]\ref[callBack.object]([getcallingtype()]), callBack.delegate:[callBack.delegate]([callBack.arguments ? callBack.arguments.Join(", ") : ""])"
|
||||
|
||||
if (spent)
|
||||
CRASH("HOLY JESUS. WHAT IS THAT? WHAT THE FUCK IS THAT?")
|
||||
if ((timeToRun < world.time || timeToRun < SStimer.head_offset) && !(flags & TIMER_CLIENT_TIME))
|
||||
CRASH("Invalid timer state: Timer created that would require a backtrack to run (addtimer would never let this happen): [SStimer.get_timer_debug_string(src)]")
|
||||
|
||||
if (callBack.object != GLOBAL_PROC)
|
||||
LAZYADD(callBack.object.active_timers, src)
|
||||
|
||||
|
||||
var/list/L
|
||||
|
||||
if (flags & TIMER_CLIENT_TIME)
|
||||
//sorted insert
|
||||
var/list/ctts = SStimer.clienttime_timers
|
||||
var/cttl = length(ctts)
|
||||
L = SStimer.clienttime_timers
|
||||
else if (timeToRun >= TIMER_MAX)
|
||||
L = SStimer.second_queue
|
||||
|
||||
|
||||
if (L)
|
||||
//binary search sorted insert
|
||||
var/cttl = length(L)
|
||||
if(cttl)
|
||||
var/datum/timedevent/Last = ctts[cttl]
|
||||
if(Last.timeToRun >= timeToRun)
|
||||
ctts += src
|
||||
else
|
||||
for(var/i in cttl to 1 step -1)
|
||||
var/datum/timedevent/E = ctts[i]
|
||||
if(E.timeToRun <= timeToRun)
|
||||
ctts.Insert(i, src)
|
||||
break
|
||||
var/left = 1
|
||||
var/right = cttl
|
||||
var/mid = (left+right) >> 1 //rounded divide by two for hedgehogs
|
||||
|
||||
var/datum/timedevent/item
|
||||
while (left < right)
|
||||
item = L[mid]
|
||||
if (item.timeToRun <= timeToRun)
|
||||
left = mid+1
|
||||
else
|
||||
right = mid
|
||||
mid = (left+right) >> 1
|
||||
|
||||
item = L[mid]
|
||||
mid = item.timeToRun > timeToRun ? mid : mid+1
|
||||
L.Insert(mid, src)
|
||||
|
||||
else
|
||||
ctts += src
|
||||
L += src
|
||||
return
|
||||
|
||||
//get the list of buckets
|
||||
var/list/bucket_list = SStimer.bucket_list
|
||||
|
||||
//calculate our place in the bucket list
|
||||
var/bucket_pos = BUCKET_POS(src)
|
||||
//we are too far aways from needing to run to be in the bucket list, shift_buckets() will handle us.
|
||||
if (bucket_pos > length(bucket_list))
|
||||
SStimer.processing += src
|
||||
return
|
||||
|
||||
//get the bucket for our tick
|
||||
var/datum/timedevent/bucket_head = bucket_list[bucket_pos]
|
||||
SStimer.bucket_count++
|
||||
//empty bucket, we will just add ourselves
|
||||
if (!bucket_head)
|
||||
bucket_list[bucket_pos] = src
|
||||
if (bucket_pos < SStimer.practical_offset)
|
||||
SStimer.practical_offset = bucket_pos
|
||||
return
|
||||
//other wise, lets do a simplified linked list add.
|
||||
if (!bucket_head.prev)
|
||||
@@ -296,10 +386,9 @@ SUBSYSTEM_DEF(timer)
|
||||
|
||||
/datum/timedevent/Destroy()
|
||||
..()
|
||||
if (flags & TIMER_UNIQUE)
|
||||
if (flags & TIMER_UNIQUE && hash)
|
||||
SStimer.hashes -= hash
|
||||
|
||||
|
||||
if (callBack && callBack.object && callBack.object != GLOBAL_PROC && callBack.object.active_timers)
|
||||
callBack.object.active_timers -= src
|
||||
UNSETEMPTY(callBack.object.active_timers)
|
||||
@@ -307,13 +396,33 @@ SUBSYSTEM_DEF(timer)
|
||||
callBack = null
|
||||
|
||||
if (flags & TIMER_STOPPABLE)
|
||||
SStimer.timer_id_dict -= "timerid" + num2text(id, 8)
|
||||
SStimer.timer_id_dict -= id
|
||||
|
||||
if (flags & TIMER_CLIENT_TIME)
|
||||
SStimer.clienttime_timers -= src
|
||||
if (!spent)
|
||||
spent = world.time
|
||||
SStimer.clienttime_timers -= src
|
||||
return QDEL_HINT_IWILLGC
|
||||
|
||||
if (!spent)
|
||||
spent = world.time
|
||||
var/bucketpos = BUCKET_POS(src)
|
||||
var/datum/timedevent/buckethead
|
||||
var/list/bucket_list = SStimer.bucket_list
|
||||
if (bucketpos > 0)
|
||||
buckethead = bucket_list[bucketpos]
|
||||
|
||||
if (buckethead == src)
|
||||
bucket_list[bucketpos] = next
|
||||
SStimer.bucket_count--
|
||||
else if (timeToRun < TIMER_MAX || next || prev)
|
||||
SStimer.bucket_count--
|
||||
else
|
||||
var/l = length(SStimer.second_queue)
|
||||
SStimer.second_queue -= src
|
||||
if (l == length(SStimer.second_queue))
|
||||
SStimer.bucket_count--
|
||||
|
||||
if (prev == next && next)
|
||||
next.prev = null
|
||||
prev.next = null
|
||||
@@ -322,19 +431,6 @@ SUBSYSTEM_DEF(timer)
|
||||
prev.next = next
|
||||
if (next)
|
||||
next.prev = prev
|
||||
|
||||
var/bucketpos = BUCKET_POS(src)
|
||||
var/datum/timedevent/buckethead
|
||||
var/list/bucket_list = SStimer.bucket_list
|
||||
|
||||
if (bucketpos > 0 && bucketpos <= length(bucket_list))
|
||||
buckethead = bucket_list[bucketpos]
|
||||
SStimer.bucket_count--
|
||||
else
|
||||
SStimer.processing -= src
|
||||
|
||||
if (buckethead == src)
|
||||
bucket_list[bucketpos] = next
|
||||
else
|
||||
if (prev && prev.next == src)
|
||||
prev.next = next
|
||||
@@ -351,7 +447,7 @@ SUBSYSTEM_DEF(timer)
|
||||
else
|
||||
. = "[callBack.object.type]"
|
||||
|
||||
/proc/addtimer(datum/callback/callback, wait, flags)
|
||||
/proc/addtimer(datum/callback/callback, wait = 0, flags = 0)
|
||||
if (!callback)
|
||||
CRASH("addtimer called without a callback")
|
||||
|
||||
@@ -381,11 +477,10 @@ SUBSYSTEM_DEF(timer)
|
||||
var/datum/timedevent/hash_timer = SStimer.hashes[hash]
|
||||
if(hash_timer)
|
||||
if (hash_timer.spent) //it's pending deletion, pretend it doesn't exist.
|
||||
hash_timer.hash = null
|
||||
SStimer.hashes -= hash
|
||||
hash_timer.hash = null //but keep it from accidentally deleting us
|
||||
else
|
||||
|
||||
if (flags & TIMER_OVERRIDE)
|
||||
hash_timer.hash = null //no need having it delete it's hash if we are going to replace it
|
||||
qdel(hash_timer)
|
||||
else
|
||||
if (hash_timer.flags & TIMER_STOPPABLE)
|
||||
@@ -410,7 +505,7 @@ SUBSYSTEM_DEF(timer)
|
||||
qdel(id)
|
||||
return TRUE
|
||||
//id is string
|
||||
var/datum/timedevent/timer = SStimer.timer_id_dict["timerid[id]"]
|
||||
var/datum/timedevent/timer = SStimer.timer_id_dict[id]
|
||||
if (timer && !timer.spent)
|
||||
qdel(timer)
|
||||
return TRUE
|
||||
@@ -419,3 +514,5 @@ SUBSYSTEM_DEF(timer)
|
||||
|
||||
#undef BUCKET_LEN
|
||||
#undef BUCKET_POS
|
||||
#undef TIMER_MAX
|
||||
#undef TIMER_ID_MAX
|
||||
|
||||
@@ -26,19 +26,12 @@ SUBSYSTEM_DEF(title)
|
||||
if((L.len == 1 && L[1] != "blank.png")|| (L.len > 1 && ((use_rare_screens && lowertext(L[1]) == "rare") || (lowertext(L[1]) == lowertext(SSmapping.config.map_name)))))
|
||||
title_screens += S
|
||||
|
||||
for(var/S in title_screens)
|
||||
var/list/L = splittext(S,".")
|
||||
if(L.len != 2)
|
||||
continue
|
||||
title_screens -= S
|
||||
break
|
||||
|
||||
if(length(title_screens))
|
||||
file_path = "[global.config.directory]/title_screens/images/[pick(title_screens)]"
|
||||
|
||||
if(!file_path)
|
||||
file_path = "icons/default_title.dmi"
|
||||
|
||||
|
||||
ASSERT(fexists(file_path))
|
||||
|
||||
icon = new(fcopy_rsc(file_path))
|
||||
|
||||
@@ -11,7 +11,7 @@ SUBSYSTEM_DEF(traumas)
|
||||
#define PHOBIA_FILE "phobia.json"
|
||||
|
||||
/datum/controller/subsystem/traumas/Initialize()
|
||||
phobia_types = list("spiders", "space", "security", "clowns", "greytide", "lizards", "skeletons")
|
||||
phobia_types = list("spiders", "space", "security", "clowns", "greytide", "lizards", "skeletons", "snakes")
|
||||
|
||||
phobia_words = list("spiders" = strings(PHOBIA_FILE, "spiders"),
|
||||
"space" = strings(PHOBIA_FILE, "space"),
|
||||
@@ -20,11 +20,13 @@ SUBSYSTEM_DEF(traumas)
|
||||
"greytide" = strings(PHOBIA_FILE, "greytide"),
|
||||
"lizards" = strings(PHOBIA_FILE, "lizards"),
|
||||
"skeletons" = strings(PHOBIA_FILE, "skeletons"),
|
||||
"snakes" = strings(PHOBIA_FILE, "snakes")
|
||||
)
|
||||
|
||||
phobia_mobs = list("spiders" = typecacheof(list(/mob/living/simple_animal/hostile/poison/giant_spider)),
|
||||
"security" = typecacheof(list(/mob/living/simple_animal/bot/secbot)),
|
||||
"lizards" = typecacheof(list(/mob/living/simple_animal/hostile/lizard))
|
||||
"lizards" = typecacheof(list(/mob/living/simple_animal/hostile/lizard)),
|
||||
"snakes" = typecacheof(list(/mob/living/simple_animal/hostile/retaliate/poison/snake))
|
||||
)
|
||||
|
||||
phobia_objs = list("spiders" = typecacheof(list(/obj/structure/spider)),
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/action/proc/UpdateButtonIcon(status_only = FALSE)
|
||||
/datum/action/proc/UpdateButtonIcon(status_only = FALSE, force = FALSE)
|
||||
if(button)
|
||||
if(!status_only)
|
||||
button.name = name
|
||||
@@ -121,7 +121,7 @@
|
||||
if(button.icon_state != background_icon_state)
|
||||
button.icon_state = background_icon_state
|
||||
|
||||
ApplyIcon(button)
|
||||
ApplyIcon(button, force)
|
||||
|
||||
if(!IsAvailable())
|
||||
button.color = rgb(128,0,0,128)
|
||||
@@ -129,8 +129,8 @@
|
||||
button.color = rgb(255,255,255,255)
|
||||
return 1
|
||||
|
||||
/datum/action/proc/ApplyIcon(obj/screen/movable/action_button/current_button)
|
||||
if(icon_icon && button_icon_state && current_button.button_icon_state != button_icon_state)
|
||||
/datum/action/proc/ApplyIcon(obj/screen/movable/action_button/current_button, force = FALSE)
|
||||
if(icon_icon && button_icon_state && ((current_button.button_icon_state != button_icon_state) || force))
|
||||
current_button.cut_overlays(TRUE)
|
||||
current_button.add_overlay(mutable_appearance(icon_icon, button_icon_state))
|
||||
current_button.button_icon_state = button_icon_state
|
||||
@@ -163,11 +163,11 @@
|
||||
I.ui_action_click(owner, src)
|
||||
return 1
|
||||
|
||||
/datum/action/item_action/ApplyIcon(obj/screen/movable/action_button/current_button)
|
||||
/datum/action/item_action/ApplyIcon(obj/screen/movable/action_button/current_button, force)
|
||||
if(button_icon && button_icon_state)
|
||||
// If set, use the custom icon that we set instead
|
||||
// of the item appearence
|
||||
..(current_button)
|
||||
..()
|
||||
else if(target && current_button.appearance_cache != target.appearance) //replace with /ref comparison if this is not valid.
|
||||
var/obj/item/I = target
|
||||
var/old_layer = I.layer
|
||||
@@ -215,7 +215,7 @@
|
||||
/datum/action/item_action/set_internals
|
||||
name = "Set Internals"
|
||||
|
||||
/datum/action/item_action/set_internals/UpdateButtonIcon(status_only = FALSE)
|
||||
/datum/action/item_action/set_internals/UpdateButtonIcon(status_only = FALSE, force)
|
||||
if(..()) //button available
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/C = owner
|
||||
@@ -253,7 +253,7 @@
|
||||
if(..())
|
||||
UpdateButtonIcon()
|
||||
|
||||
/datum/action/item_action/toggle_unfriendly_fire/UpdateButtonIcon(status_only = FALSE)
|
||||
/datum/action/item_action/toggle_unfriendly_fire/UpdateButtonIcon(status_only = FALSE, force)
|
||||
if(istype(target, /obj/item/hierophant_club))
|
||||
var/obj/item/hierophant_club/H = target
|
||||
if(H.friendly_fire_check)
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#define ARMORID "armor-[melee]-[bullet]-[laser]-[energy]-[bomb]-[bio]-[rad]-[fire]-[acid]-[magic]"
|
||||
|
||||
/proc/getArmor(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0)
|
||||
. = locate(ARMORID)
|
||||
if (!.)
|
||||
. = new /datum/armor(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic)
|
||||
|
||||
/datum/armor
|
||||
datum_flags = DF_USE_TAG
|
||||
var/melee
|
||||
var/bullet
|
||||
var/laser
|
||||
var/energy
|
||||
var/bomb
|
||||
var/bio
|
||||
var/rad
|
||||
var/fire
|
||||
var/acid
|
||||
var/magic
|
||||
|
||||
/datum/armor/New(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0)
|
||||
src.melee = melee
|
||||
src.bullet = bullet
|
||||
src.laser = laser
|
||||
src.energy = energy
|
||||
src.bomb = bomb
|
||||
src.bio = bio
|
||||
src.rad = rad
|
||||
src.fire = fire
|
||||
src.acid = acid
|
||||
src.magic = magic
|
||||
tag = ARMORID
|
||||
|
||||
/datum/armor/proc/modifyRating(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0, magic = 0)
|
||||
return getArmor(src.melee+melee, src.bullet+bullet, src.laser+laser, src.energy+energy, src.bomb+bomb, src.bio+bio, src.rad+rad, src.fire+fire, src.acid+acid, src.magic+magic)
|
||||
|
||||
/datum/armor/proc/modifyAllRatings(modifier = 0)
|
||||
return getArmor(melee+modifier, bullet+modifier, laser+modifier, energy+modifier, bomb+modifier, bio+modifier, rad+modifier, fire+modifier, acid+modifier, magic+modifier)
|
||||
|
||||
/datum/armor/proc/setRating(melee, bullet, laser, energy, bomb, bio, rad, fire, acid, magic)
|
||||
return getArmor((isnull(melee) ? src.melee : melee),\
|
||||
(isnull(bullet) ? src.bullet : bullet),\
|
||||
(isnull(laser) ? src.laser : laser),\
|
||||
(isnull(energy) ? src.energy : energy),\
|
||||
(isnull(bomb) ? src.bomb : bomb),\
|
||||
(isnull(bio) ? src.bio : bio),\
|
||||
(isnull(rad) ? src.rad : rad),\
|
||||
(isnull(fire) ? src.fire : fire),\
|
||||
(isnull(acid) ? src.acid : acid),\
|
||||
(isnull(magic) ? src.magic : magic))
|
||||
|
||||
/datum/armor/proc/getRating(rating)
|
||||
return vars[rating]
|
||||
|
||||
/datum/armor/proc/getList()
|
||||
return list("melee" = melee, "bullet" = bullet, "laser" = laser, "energy" = energy, "bomb" = bomb, "bio" = bio, "rad" = rad, "fire" = fire, "acid" = acid, "magic" = magic)
|
||||
|
||||
/datum/armor/proc/attachArmor(datum/armor/AA)
|
||||
return getArmor(melee+AA.melee, bullet+AA.bullet, laser+AA.laser, energy+AA.energy, bomb+AA.bomb, bio+AA.bio, rad+AA.rad, fire+AA.fire, acid+AA.acid, magic+AA.magic)
|
||||
|
||||
/datum/armor/proc/detachArmor(datum/armor/AA)
|
||||
return getArmor(melee-AA.melee, bullet-AA.bullet, laser-AA.laser, energy-AA.energy, bomb-AA.bomb, bio-AA.bio, rad-AA.rad, fire-AA.fire, acid-AA.acid, magic-AA.magic)
|
||||
|
||||
/datum/armor/vv_edit_var(var_name, var_value)
|
||||
if (var_name == NAMEOF(src, tag))
|
||||
return FALSE
|
||||
. = ..()
|
||||
tag = ARMORID // update tag in case armor values were edited
|
||||
|
||||
#undef ARMORID
|
||||
@@ -42,7 +42,7 @@
|
||||
lose_text = "<span class='notice'>You feel smart again.</span>"
|
||||
|
||||
/datum/brain_trauma/mild/dumbness/on_gain()
|
||||
owner.add_disability(DISABILITY_DUMB, TRAUMA_DISABILITY)
|
||||
owner.add_trait(TRAIT_DUMB, TRAUMA_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/mild/dumbness/on_life()
|
||||
@@ -54,7 +54,7 @@
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/mild/dumbness/on_lose()
|
||||
owner.remove_disability(DISABILITY_DUMB, TRAUMA_DISABILITY)
|
||||
owner.remove_trait(TRAIT_DUMB, TRAUMA_TRAIT)
|
||||
owner.derpspeech = 0
|
||||
..()
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
return
|
||||
|
||||
/datum/brain_trauma/mild/phobia/on_hear(message, speaker, message_language, raw_message, radio_freq)
|
||||
if(owner.has_disability(DISABILITY_DEAF) || world.time < next_scare) //words can't trigger you if you can't hear them *taps head*
|
||||
if(owner.has_trait(TRAIT_DEAF) || world.time < next_scare) //words can't trigger you if you can't hear them *taps head*
|
||||
return message
|
||||
for(var/word in trigger_words)
|
||||
if(findtext(message, word))
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
lose_text = "<span class='notice'>You suddenly remember how to speak.</span>"
|
||||
|
||||
/datum/brain_trauma/severe/mute/on_gain()
|
||||
owner.add_disability(DISABILITY_MUTE, TRAUMA_DISABILITY)
|
||||
owner.add_trait(TRAIT_MUTE, TRAUMA_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/mute/on_lose()
|
||||
owner.remove_disability(DISABILITY_MUTE, TRAUMA_DISABILITY)
|
||||
owner.remove_trait(TRAIT_MUTE, TRAUMA_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/aphasia
|
||||
@@ -50,11 +50,11 @@
|
||||
lose_text = "<span class='notice'>Your vision returns.</span>"
|
||||
|
||||
/datum/brain_trauma/severe/blindness/on_gain()
|
||||
owner.become_blind(TRAUMA_DISABILITY)
|
||||
owner.become_blind(TRAUMA_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/blindness/on_lose()
|
||||
owner.cure_blind(TRAUMA_DISABILITY)
|
||||
owner.cure_blind(TRAUMA_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/paralysis
|
||||
@@ -120,7 +120,7 @@
|
||||
stress -= 4
|
||||
|
||||
/datum/brain_trauma/severe/monophobia/proc/check_alone()
|
||||
if(owner.has_disability(DISABILITY_BLIND))
|
||||
if(owner.has_trait(TRAIT_BLIND))
|
||||
return TRUE
|
||||
for(var/mob/M in oview(owner, 7))
|
||||
if(!isliving(M)) //ghosts ain't people
|
||||
@@ -182,11 +182,11 @@
|
||||
lose_text = "<span class='notice'>You feel in control of your hands again.</span>"
|
||||
|
||||
/datum/brain_trauma/severe/discoordination/on_gain()
|
||||
owner.add_disability(DISABILITY_MONKEYLIKE, TRAUMA_DISABILITY)
|
||||
owner.add_trait(TRAIT_MONKEYLIKE, TRAUMA_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/discoordination/on_lose()
|
||||
owner.remove_disability(DISABILITY_MONKEYLIKE, TRAUMA_DISABILITY)
|
||||
owner.remove_trait(TRAIT_MONKEYLIKE, TRAUMA_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/pacifism
|
||||
@@ -197,9 +197,9 @@
|
||||
lose_text = "<span class='notice'>You no longer feel compelled to not harm.</span>"
|
||||
|
||||
/datum/brain_trauma/severe/pacifism/on_gain()
|
||||
owner.add_disability(DISABILITY_PACIFISM, TRAUMA_DISABILITY)
|
||||
owner.add_trait(TRAIT_PACIFISM, TRAUMA_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/pacifism/on_lose()
|
||||
owner.remove_disability(DISABILITY_PACIFISM, TRAUMA_DISABILITY)
|
||||
owner.remove_trait(TRAIT_PACIFISM, TRAUMA_TRAIT)
|
||||
..()
|
||||
@@ -192,7 +192,7 @@
|
||||
return //no random switching
|
||||
|
||||
/datum/brain_trauma/severe/split_personality/brainwashing/on_hear(message, speaker, message_language, raw_message, radio_freq)
|
||||
if(owner.has_disability(DISABILITY_DEAF) || owner == speaker)
|
||||
if(owner.has_trait(TRAIT_DEAF) || owner == speaker)
|
||||
return message
|
||||
if(findtext(message, codeword))
|
||||
message = replacetext(message, codeword, "<span class='warning'>[codeword]</span>")
|
||||
|
||||
+133
-44
@@ -120,13 +120,7 @@
|
||||
else
|
||||
WARNING("Browser [title] tried to close with a null ID")
|
||||
|
||||
/datum/browser/alert
|
||||
var/selectedbutton = 0
|
||||
var/opentime = 0
|
||||
var/timeout
|
||||
var/stealfocus
|
||||
|
||||
/datum/browser/alert/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1,Timeout=6000)
|
||||
/datum/browser/modal/alert/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1,Timeout=6000)
|
||||
if (!User)
|
||||
return
|
||||
|
||||
@@ -142,44 +136,10 @@
|
||||
|
||||
output += {"</div>"}
|
||||
|
||||
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, 350, 150, src)
|
||||
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, 350, 150, src, StealFocus, Timeout)
|
||||
set_content(output)
|
||||
stealfocus = StealFocus
|
||||
if (!StealFocus)
|
||||
window_options += "focus=false;"
|
||||
timeout = Timeout
|
||||
|
||||
/datum/browser/alert/open()
|
||||
set waitfor = 0
|
||||
opentime = world.time
|
||||
|
||||
if (stealfocus)
|
||||
. = ..(use_onclose = 1)
|
||||
else
|
||||
var/focusedwindow = winget(user, null, "focus")
|
||||
. = ..(use_onclose = 1)
|
||||
|
||||
//waits for the window to show up client side before attempting to un-focus it
|
||||
//winexists sleeps until it gets a reply from the client, so we don't need to bother sleeping
|
||||
for (var/i in 1 to 10)
|
||||
if (user && winexists(user, window_id))
|
||||
if (focusedwindow)
|
||||
winset(user, focusedwindow, "focus=true")
|
||||
else
|
||||
winset(user, "mapwindow", "focus=true")
|
||||
break
|
||||
if (timeout)
|
||||
addtimer(CALLBACK(src, .proc/close), timeout)
|
||||
|
||||
/datum/browser/alert/close()
|
||||
.=..()
|
||||
opentime = 0
|
||||
|
||||
/datum/browser/alert/proc/wait()
|
||||
while (opentime && selectedbutton <= 0 && (!timeout || opentime+timeout > world.time))
|
||||
stoplag(1)
|
||||
|
||||
/datum/browser/alert/Topic(href,href_list)
|
||||
/datum/browser/modal/alert/Topic(href,href_list)
|
||||
if (href_list["close"] || !user || !user.client)
|
||||
opentime = 0
|
||||
return
|
||||
@@ -210,12 +170,141 @@
|
||||
User = C.mob
|
||||
else
|
||||
return
|
||||
var/datum/browser/alert/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)
|
||||
var/datum/browser/modal/alert/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout)
|
||||
A.open()
|
||||
A.wait()
|
||||
if (A.selectedbutton)
|
||||
return A.selectedbutton
|
||||
|
||||
/datum/browser/modal
|
||||
var/opentime = 0
|
||||
var/timeout
|
||||
var/selectedbutton = 0
|
||||
var/stealfocus
|
||||
|
||||
/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, StealFocus = 1, Timeout = 6000)
|
||||
..()
|
||||
stealfocus = StealFocus
|
||||
if (!StealFocus)
|
||||
window_options += "focus=false;"
|
||||
timeout = Timeout
|
||||
|
||||
|
||||
/datum/browser/modal/close()
|
||||
.=..()
|
||||
opentime = 0
|
||||
|
||||
/datum/browser/modal/open()
|
||||
set waitfor = 0
|
||||
opentime = world.time
|
||||
|
||||
if (stealfocus)
|
||||
. = ..(use_onclose = 1)
|
||||
else
|
||||
var/focusedwindow = winget(user, null, "focus")
|
||||
. = ..(use_onclose = 1)
|
||||
|
||||
//waits for the window to show up client side before attempting to un-focus it
|
||||
//winexists sleeps until it gets a reply from the client, so we don't need to bother sleeping
|
||||
for (var/i in 1 to 10)
|
||||
if (user && winexists(user, window_id))
|
||||
if (focusedwindow)
|
||||
winset(user, focusedwindow, "focus=true")
|
||||
else
|
||||
winset(user, "mapwindow", "focus=true")
|
||||
break
|
||||
if (timeout)
|
||||
addtimer(CALLBACK(src, .proc/close), timeout)
|
||||
|
||||
/datum/browser/modal/proc/wait()
|
||||
while (opentime && selectedbutton <= 0 && (!timeout || opentime+timeout > world.time))
|
||||
stoplag(1)
|
||||
|
||||
/datum/browser/modal/listpicker
|
||||
var/valueslist = list()
|
||||
|
||||
/datum/browser/modal/listpicker/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1, Timeout = FALSE,list/values,inputtype="checkbox")
|
||||
if (!User)
|
||||
return
|
||||
|
||||
var/output = {"<form><input type="hidden" name="src" value="[REF(src)]"><ul class="sparse">"}
|
||||
|
||||
if (inputtype == "checkbox" || inputtype == "radio")
|
||||
for (var/i in values)
|
||||
output += {"<li>
|
||||
<label class="switch">
|
||||
<input type="[inputtype]" value="1" name="[i["name"]]"[i["checked"] ? " checked" : ""]>
|
||||
<div class="slider"></div>
|
||||
<span>[i["name"]]</span>
|
||||
</label>
|
||||
</li>"}
|
||||
else
|
||||
for (var/i in values)
|
||||
output += {"<li><input id="name="[i["name"]]"" style="width: 50px" type="[type]" name="[i["name"]]" value="[i["value"]]">
|
||||
<label for="[i["name"]]">[i["name"]]</label></li>"}
|
||||
output += {"</ul><div style="text-align:center">
|
||||
<button type="submit" name="button" value="1" style="font-size:large;float:[( Button2 ? "left" : "right" )]">[Button1]</button>"}
|
||||
|
||||
if (Button2)
|
||||
output += {"<button type="submit" name="button" value="2" style="font-size:large;[( Button3 ? "" : "float:right" )]">[Button2]</button>"}
|
||||
|
||||
if (Button3)
|
||||
output += {"<button type="submit" name="button" value="3" style="font-size:large;float:right">[Button3]</button>"}
|
||||
|
||||
output += {"</form></div>"}
|
||||
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, 350, 350, src, StealFocus, Timeout)
|
||||
set_content(output)
|
||||
|
||||
/datum/browser/modal/listpicker/Topic(href,href_list)
|
||||
if (href_list["close"] || !user || !user.client)
|
||||
opentime = 0
|
||||
return
|
||||
if (href_list["button"])
|
||||
var/button = text2num(href_list["button"])
|
||||
if (button <= 3 && button >= 1)
|
||||
selectedbutton = button
|
||||
for (var/item in href_list)
|
||||
switch(item)
|
||||
if ("close", "button", "src")
|
||||
continue
|
||||
else
|
||||
valueslist[item] = href_list[item]
|
||||
opentime = 0
|
||||
close()
|
||||
|
||||
/proc/presentpicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/values, inputtype = "checkbox")
|
||||
if (!istype(User))
|
||||
if (istype(User, /client/))
|
||||
var/client/C = User
|
||||
User = C.mob
|
||||
else
|
||||
return
|
||||
var/datum/browser/modal/listpicker/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus,Timeout, values, inputtype)
|
||||
A.open()
|
||||
A.wait()
|
||||
if (A.selectedbutton)
|
||||
return list("button" = A.selectedbutton, "values" = A.valueslist)
|
||||
|
||||
/proc/input_bitfield(var/mob/User, title, bitfield, current_value)
|
||||
if (!User || !(bitfield in GLOB.bitfields))
|
||||
return
|
||||
var/list/pickerlist = list()
|
||||
for (var/i in GLOB.bitfields[bitfield])
|
||||
if (current_value & GLOB.bitfields[bitfield][i])
|
||||
pickerlist += list(list("checked" = 1, "value" = GLOB.bitfields[bitfield][i], "name" = i))
|
||||
else
|
||||
pickerlist += list(list("checked" = 0, "value" = GLOB.bitfields[bitfield][i], "name" = i))
|
||||
var/list/result = presentpicker(User, "", title, Button1="Save", Button2 = "Cancel", Timeout=FALSE, values = pickerlist)
|
||||
|
||||
if (islist(result))
|
||||
if (result["button"] == 2) // If the user pressed the cancel button
|
||||
return
|
||||
. = 0
|
||||
for (var/flag in result["values"])
|
||||
. |= GLOB.bitfields[bitfield][flag]
|
||||
else
|
||||
return
|
||||
|
||||
// This will allow you to show an icon in the browse window
|
||||
// This is added to mob so that it can be used without a reference to the browser object
|
||||
// There is probably a better place for this...
|
||||
|
||||
+62
-22
@@ -433,6 +433,12 @@
|
||||
else
|
||||
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a>"
|
||||
|
||||
else if (name in GLOB.bitfields)
|
||||
var/list/flags = list()
|
||||
for (var/i in GLOB.bitfields[name])
|
||||
if (value & GLOB.bitfields[name][i])
|
||||
flags += i
|
||||
item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(jointext(flags, ", "))]"
|
||||
else
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>[VV_HTML_ENCODE(value)]</span>"
|
||||
|
||||
@@ -453,7 +459,7 @@
|
||||
src.debug_variables(DAT)
|
||||
|
||||
else if(href_list["mob_player_panel"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/M = locate(href_list["mob_player_panel"]) in GLOB.mob_list
|
||||
@@ -477,7 +483,7 @@
|
||||
href_list["datumrefresh"] = href_list["godmode"]
|
||||
|
||||
else if(href_list["mark_object"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/datum/D = locate(href_list["mark_object"])
|
||||
@@ -489,7 +495,7 @@
|
||||
href_list["datumrefresh"] = href_list["mark_object"]
|
||||
|
||||
else if(href_list["proc_call"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/T = locate(href_list["proc_call"])
|
||||
@@ -513,7 +519,7 @@
|
||||
usr.client.object_say(locate(href_list["osay"]))
|
||||
|
||||
else if(href_list["regenerateicons"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/M = locate(href_list["regenerateicons"]) in GLOB.mob_list
|
||||
@@ -550,7 +556,7 @@
|
||||
//~CARN: for renaming mobs (updates their name, real_name, mind.name, their ID/PDA and datacore records).
|
||||
|
||||
if(href_list["rename"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/M = locate(href_list["rename"]) in GLOB.mob_list
|
||||
@@ -567,7 +573,7 @@
|
||||
href_list["datumrefresh"] = href_list["rename"]
|
||||
|
||||
else if(href_list["varnameedit"] && href_list["datumedit"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/D = locate(href_list["datumedit"])
|
||||
@@ -578,7 +584,7 @@
|
||||
modify_variables(D, href_list["varnameedit"], 1)
|
||||
|
||||
else if(href_list["varnamechange"] && href_list["datumchange"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/D = locate(href_list["datumchange"])
|
||||
@@ -589,7 +595,7 @@
|
||||
modify_variables(D, href_list["varnamechange"], 0)
|
||||
|
||||
else if(href_list["varnamemass"] && href_list["datummass"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/datum/D = locate(href_list["datummass"])
|
||||
@@ -698,7 +704,7 @@
|
||||
message_admins("[key_name_admin(src)] modified list's contents: SHUFFLE")
|
||||
|
||||
else if(href_list["give_spell"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/M = locate(href_list["give_spell"]) in GLOB.mob_list
|
||||
@@ -710,7 +716,7 @@
|
||||
href_list["datumrefresh"] = href_list["give_spell"]
|
||||
|
||||
else if(href_list["remove_spell"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/M = locate(href_list["remove_spell"]) in GLOB.mob_list
|
||||
@@ -722,7 +728,7 @@
|
||||
href_list["datumrefresh"] = href_list["remove_spell"]
|
||||
|
||||
else if(href_list["give_disease"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/M = locate(href_list["give_disease"]) in GLOB.mob_list
|
||||
@@ -757,7 +763,7 @@
|
||||
href_list["datumrefresh"] = href_list["build_mode"]
|
||||
|
||||
else if(href_list["drop_everything"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/M = locate(href_list["drop_everything"]) in GLOB.mob_list
|
||||
@@ -769,7 +775,7 @@
|
||||
usr.client.cmd_admin_drop_everything(M)
|
||||
|
||||
else if(href_list["direct_control"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/M = locate(href_list["direct_control"]) in GLOB.mob_list
|
||||
@@ -781,7 +787,7 @@
|
||||
usr.client.cmd_assume_direct_control(M)
|
||||
|
||||
else if(href_list["offer_control"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/M = locate(href_list["offer_control"]) in GLOB.mob_list
|
||||
@@ -790,6 +796,41 @@
|
||||
return
|
||||
offer_control(M)
|
||||
|
||||
else if (href_list["modarmor"])
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/obj/O = locate(href_list["modarmor"])
|
||||
if(!istype(O))
|
||||
to_chat(usr, "This can only be used on instances of type /obj")
|
||||
return
|
||||
|
||||
var/list/pickerlist = list()
|
||||
var/list/armorlist = O.armor.getList()
|
||||
|
||||
for (var/i in armorlist)
|
||||
pickerlist += list(list("value" = armorlist[i], "name" = i))
|
||||
|
||||
var/list/result = presentpicker(usr, "Modify armor", "Modify armor: [O]", Button1="Save", Button2 = "Cancel", Timeout=FALSE, Type = "text", values = pickerlist)
|
||||
|
||||
if (islist(result))
|
||||
if (result["button"] == 2) // If the user pressed the cancel button
|
||||
return
|
||||
// text2num conveniently returns a null on invalid values
|
||||
O.armor = O.armor.setRating(melee = text2num(result["values"]["melee"]),\
|
||||
bullet = text2num(result["values"]["bullet"]),\
|
||||
laser = text2num(result["values"]["laser"]),\
|
||||
energy = text2num(result["values"]["energy"]),\
|
||||
bomb = text2num(result["values"]["bomb"]),\
|
||||
bio = text2num(result["values"]["bio"]),\
|
||||
rad = text2num(result["values"]["rad"]),\
|
||||
fire = text2num(result["values"]["fire"]),\
|
||||
acid = text2num(result["values"]["acid"]))
|
||||
log_admin("[key_name(usr)] modified the armor on [O] ([O.type]) to melee: [O.armor.melee], bullet: [O.armor.bullet], laser: [O.armor.laser], energy: [O.armor.energy], bomb: [O.armor.bomb], bio: [O.armor.bio], rad: [O.armor.rad], fire: [O.armor.fire], acid: [O.armor.acid]")
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] modified the armor on [O] ([O.type]) to melee: [O.armor.melee], bullet: [O.armor.bullet], laser: [O.armor.laser], energy: [O.armor.energy], bomb: [O.armor.bomb], bio: [O.armor.bio], rad: [O.armor.rad], fire: [O.armor.fire], acid: [O.armor.acid]</span>")
|
||||
else
|
||||
return
|
||||
|
||||
else if(href_list["delall"])
|
||||
if(!check_rights(R_DEBUG|R_SERVER))
|
||||
return
|
||||
@@ -837,7 +878,7 @@
|
||||
message_admins("<span class='notice'>[key_name(usr)] deleted all objects of type or subtype of [O_type] ([i] objects deleted) </span>")
|
||||
|
||||
else if(href_list["addreagent"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/atom/A = locate(href_list["addreagent"])
|
||||
@@ -927,7 +968,7 @@
|
||||
href_list["datumrefresh"] = href_list["modtransform"]
|
||||
|
||||
else if(href_list["rotatedatum"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/atom/A = locate(href_list["rotatedatum"])
|
||||
@@ -943,7 +984,7 @@
|
||||
href_list["datumrefresh"] = href_list["rotatedatum"]
|
||||
|
||||
else if(href_list["editorgans"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/C = locate(href_list["editorgans"]) in GLOB.mob_list
|
||||
@@ -955,7 +996,7 @@
|
||||
href_list["datumrefresh"] = href_list["editorgans"]
|
||||
|
||||
else if(href_list["givetrauma"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/C = locate(href_list["givetrauma"]) in GLOB.mob_list
|
||||
@@ -978,7 +1019,7 @@
|
||||
href_list["datumrefresh"] = href_list["givetrauma"]
|
||||
|
||||
else if(href_list["curetraumas"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/C = locate(href_list["curetraumas"]) in GLOB.mob_list
|
||||
@@ -991,7 +1032,7 @@
|
||||
href_list["datumrefresh"] = href_list["curetraumas"]
|
||||
|
||||
else if(href_list["hallucinate"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/C = locate(href_list["hallucinate"]) in GLOB.mob_list
|
||||
@@ -1204,7 +1245,7 @@
|
||||
admin_ticket_log(H, msg)
|
||||
|
||||
else if(href_list["adjustDamage"] && href_list["mobToDamage"])
|
||||
if(!check_rights(0))
|
||||
if(!check_rights(NONE))
|
||||
return
|
||||
|
||||
var/mob/living/L = locate(href_list["mobToDamage"]) in GLOB.mob_list
|
||||
@@ -1244,4 +1285,3 @@
|
||||
message_admins(msg)
|
||||
admin_ticket_log(L, msg)
|
||||
href_list["datumrefresh"] = href_list["mobToDamage"]
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ DNA Saboteur
|
||||
Fatal Level.
|
||||
|
||||
Bonus
|
||||
Cleans the DNA of a person and then randomly gives them a disability.
|
||||
Cleans the DNA of a person and then randomly gives them a trait.
|
||||
|
||||
//////////////////////////////////////
|
||||
*/
|
||||
|
||||
@@ -233,7 +233,7 @@
|
||||
|
||||
/datum/symptom/heal/coma/CanHeal(datum/disease/advance/A)
|
||||
var/mob/living/M = A.affected_mob
|
||||
if(M.status_flags & FAKEDEATH)
|
||||
if(M.has_trait(TRAIT_FAKEDEATH))
|
||||
return power
|
||||
else if(M.IsUnconscious() || M.stat == UNCONSCIOUS)
|
||||
return power * 0.9
|
||||
@@ -249,7 +249,7 @@
|
||||
/datum/symptom/heal/coma/proc/coma(mob/living/M)
|
||||
if(deathgasp)
|
||||
M.emote("deathgasp")
|
||||
M.status_flags |= FAKEDEATH
|
||||
M.fakedeath("regenerative_coma")
|
||||
M.update_stat()
|
||||
M.update_canmove()
|
||||
addtimer(CALLBACK(src, .proc/uncoma, M), 300)
|
||||
@@ -258,7 +258,7 @@
|
||||
if(!active_coma)
|
||||
return
|
||||
active_coma = FALSE
|
||||
M.status_flags &= ~FAKEDEATH
|
||||
M.cure_fakedeath("regenerative_coma")
|
||||
M.update_stat()
|
||||
M.update_canmove()
|
||||
|
||||
|
||||
@@ -86,14 +86,14 @@
|
||||
if(4, 5)
|
||||
M.restoreEars()
|
||||
|
||||
if(M.has_disability(DISABILITY_BLIND, EYE_DAMAGE))
|
||||
if(M.has_trait(TRAIT_BLIND, EYE_DAMAGE))
|
||||
if(prob(20))
|
||||
to_chat(M, "<span class='notice'>Your vision slowly returns...</span>")
|
||||
M.cure_blind(EYE_DAMAGE)
|
||||
M.cure_nearsighted(EYE_DAMAGE)
|
||||
M.blur_eyes(35)
|
||||
|
||||
else if(M.has_disability(DISABILITY_NEARSIGHT, EYE_DAMAGE))
|
||||
else if(M.has_trait(TRAIT_NEARSIGHT, EYE_DAMAGE))
|
||||
to_chat(M, "<span class='notice'>You can finally focus your eyes on distant objects.</span>")
|
||||
M.cure_nearsighted(EYE_DAMAGE)
|
||||
M.blur_eyes(10)
|
||||
|
||||
@@ -61,7 +61,7 @@ Bonus
|
||||
M.become_nearsighted(EYE_DAMAGE)
|
||||
if(prob(eyes.eye_damage - 10 + 1))
|
||||
if(!remove_eyes)
|
||||
if(!M.has_disability(DISABILITY_BLIND))
|
||||
if(!M.has_trait(TRAIT_BLIND))
|
||||
to_chat(M, "<span class='userdanger'>You go blind!</span>")
|
||||
M.become_blind(EYE_DAMAGE)
|
||||
else
|
||||
|
||||
@@ -204,12 +204,13 @@
|
||||
..()
|
||||
switch(stage)
|
||||
if(1)
|
||||
if(ishuman(affected_mob) && affected_mob.dna && affected_mob.dna.species.id == "slime")
|
||||
stage = 5
|
||||
if(ishuman(affected_mob) && affected_mob.dna)
|
||||
if(affected_mob.dna.species.id == "slime" || affected_mob.dna.species.id == "stargazer" || affected_mob.dna.species.id == "lum")
|
||||
stage = 5
|
||||
if(3)
|
||||
if(ishuman(affected_mob))
|
||||
var/mob/living/carbon/human/human = affected_mob
|
||||
if(human.dna.species.id != "slime")
|
||||
if(human.dna.species.id != "slime" && affected_mob.dna.species.id != "stargazer" && affected_mob.dna.species.id != "lum")
|
||||
human.set_species(/datum/species/jelly/slime)
|
||||
|
||||
/datum/disease/transformation/corgi
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#define EMBEDID "embed-[embed_chance]-[embedded_fall_chance]-[embedded_pain_chance]-[embedded_pain_multiplier]-[embedded_fall_pain_multiplier]-[embedded_impact_pain_multiplier]-[embedded_unsafe_removal_pain_multiplier]-[embedded_unsafe_removal_time]"
|
||||
|
||||
/proc/getEmbeddingBehavior(embed_chance = EMBED_CHANCE,
|
||||
embedded_fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||
embedded_pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||
embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER,
|
||||
embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER,
|
||||
embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME)
|
||||
. = locate(EMBEDID)
|
||||
if (!.)
|
||||
. = new /datum/embedding_behavior(embed_chance, embedded_fall_chance, embedded_pain_chance, embedded_pain_multiplier, embedded_fall_pain_multiplier, embedded_impact_pain_multiplier, embedded_unsafe_removal_pain_multiplier, embedded_unsafe_removal_time)
|
||||
|
||||
/datum/embedding_behavior
|
||||
var/embed_chance
|
||||
var/embedded_fall_chance
|
||||
var/embedded_pain_chance
|
||||
var/embedded_pain_multiplier //The coefficient of multiplication for the damage this item does while embedded (this*w_class)
|
||||
var/embedded_fall_pain_multiplier //The coefficient of multiplication for the damage this item does when falling out of a limb (this*w_class)
|
||||
var/embedded_impact_pain_multiplier //The coefficient of multiplication for the damage this item does when first embedded (this*w_class)
|
||||
var/embedded_unsafe_removal_pain_multiplier //The coefficient of multiplication for the damage removing this without surgery causes (this*w_class)
|
||||
var/embedded_unsafe_removal_time //A time in ticks, multiplied by the w_class.
|
||||
|
||||
/datum/embedding_behavior/New(embed_chance = EMBED_CHANCE,
|
||||
embedded_fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||
embedded_pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||
embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER,
|
||||
embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER,
|
||||
embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME)
|
||||
src.embed_chance = embed_chance
|
||||
src.embedded_fall_chance = embedded_fall_chance
|
||||
src.embedded_pain_chance = embedded_pain_chance
|
||||
src.embedded_pain_multiplier = embedded_pain_multiplier
|
||||
src.embedded_fall_pain_multiplier = embedded_fall_pain_multiplier
|
||||
src.embedded_impact_pain_multiplier = embedded_impact_pain_multiplier
|
||||
src.embedded_unsafe_removal_pain_multiplier = embedded_unsafe_removal_pain_multiplier
|
||||
src.embedded_unsafe_removal_time = embedded_unsafe_removal_time
|
||||
tag = EMBEDID
|
||||
|
||||
/datum/embedding_behavior/proc/setRating(embed_chance, embedded_fall_chance, embedded_pain_chance, embedded_pain_multiplier, embedded_fall_pain_multiplier, embedded_impact_pain_multiplier, embedded_unsafe_removal_pain_multiplier, embedded_unsafe_removal_time)
|
||||
return getEmbeddingBehavior((isnull(embed_chance) ? src.embed_chance : embed_chance),\
|
||||
(isnull(embedded_fall_chance) ? src.embedded_fall_chance : embedded_fall_chance),\
|
||||
(isnull(embedded_pain_chance) ? src.embedded_pain_chance : embedded_pain_chance),\
|
||||
(isnull(embedded_pain_multiplier) ? src.embedded_pain_multiplier : embedded_pain_multiplier),\
|
||||
(isnull(embedded_fall_pain_multiplier) ? src.embedded_fall_pain_multiplier : embedded_fall_pain_multiplier),\
|
||||
(isnull(embedded_impact_pain_multiplier) ? src.embedded_impact_pain_multiplier : embedded_impact_pain_multiplier),\
|
||||
(isnull(embedded_unsafe_removal_pain_multiplier) ? src.embedded_unsafe_removal_pain_multiplier : embedded_unsafe_removal_pain_multiplier),\
|
||||
(isnull(embedded_unsafe_removal_time) ? src.embedded_unsafe_removal_time : embedded_unsafe_removal_time))
|
||||
|
||||
#undef EMBEDID
|
||||
@@ -101,7 +101,7 @@
|
||||
if(is_type_in_typecache(user, mob_type_blacklist_typecache))
|
||||
return FALSE
|
||||
if(status_check && !is_type_in_typecache(user, mob_type_ignore_stat_typecache))
|
||||
if(user.stat > stat_allowed || (user.status_flags & FAKEDEATH))
|
||||
if(user.stat > stat_allowed)
|
||||
to_chat(user, "<span class='notice'>You cannot [key] while unconscious.</span>")
|
||||
return FALSE
|
||||
if(restraint_check && (user.restrained() || user.buckled))
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
logs = splittext(logs[logs.len - 1], " ")
|
||||
date = unix2date(text2num(logs[5]))
|
||||
commit = logs[2]
|
||||
log_world("[date]")
|
||||
log_world("[commit]: [date]")
|
||||
logs = world.file2list(".git/logs/refs/remotes/origin/master")
|
||||
if(logs)
|
||||
if(logs.len)
|
||||
originmastercommit = splittext(logs[logs.len - 1], " ")[2]
|
||||
|
||||
if(testmerge.len)
|
||||
@@ -24,8 +24,9 @@
|
||||
var/tmcommit = testmerge[line]["commit"]
|
||||
log_world("Test merge active of PR #[line] commit [tmcommit]")
|
||||
SSblackbox.record_feedback("nested tally", "testmerged_prs", 1, list("[line]", "[tmcommit]"))
|
||||
log_world("Based off origin/master commit [originmastercommit]")
|
||||
else
|
||||
if(originmastercommit)
|
||||
log_world("Based off origin/master commit [originmastercommit]")
|
||||
else if(originmastercommit)
|
||||
log_world(originmastercommit)
|
||||
|
||||
/datum/getrev/proc/GetTestMergeInfo(header = TRUE)
|
||||
@@ -55,7 +56,8 @@
|
||||
var/pc = GLOB.revdata.originmastercommit
|
||||
to_chat(src, "[prefix]<a href=\"[CONFIG_GET(string/githuburl)]/commit/[pc]\">[copytext(pc, 1, min(length(pc), 7))]</a>")
|
||||
else
|
||||
to_chat(src, "Revision unknown")
|
||||
to_chat(src, "Master revision unknown")
|
||||
to_chat(src, "Revision: [GLOB.revdata.commit]")
|
||||
if(SERVER_TOOLS_PRESENT)
|
||||
to_chat(src, "Server tools version: [SERVER_TOOLS_VERSION]")
|
||||
to_chat(src, "Server tools API version: [SERVER_TOOLS_API_VERSION]")
|
||||
|
||||
@@ -206,6 +206,8 @@
|
||||
name = "holorecord disk"
|
||||
desc = "Stores recorder holocalls."
|
||||
icon_state = "holodisk"
|
||||
obj_flags = UNIQUE_RENAME
|
||||
materials = list(MAT_METAL = 100, MAT_GLASS = 100)
|
||||
var/datum/holorecord/record
|
||||
//Preset variables
|
||||
var/preset_image_type
|
||||
@@ -220,6 +222,22 @@
|
||||
QDEL_NULL(record)
|
||||
return ..()
|
||||
|
||||
/obj/item/disk/holodisk/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/disk/holodisk))
|
||||
var/obj/item/disk/holodisk/holodiskOriginal = W
|
||||
if (holodiskOriginal.record)
|
||||
if (!record)
|
||||
record = new
|
||||
record.caller_name = holodiskOriginal.record.caller_name
|
||||
record.caller_image = holodiskOriginal.record.caller_image
|
||||
record.entries = holodiskOriginal.record.entries.Copy()
|
||||
record.language = holodiskOriginal.record.language
|
||||
to_chat(user, "You copy the record from [holodiskOriginal] to [src] by connecting the ports!")
|
||||
name = holodiskOriginal.name
|
||||
else
|
||||
to_chat(user, "[holodiskOriginal] has no record on it!")
|
||||
..()
|
||||
|
||||
/obj/item/disk/holodisk/proc/build_record()
|
||||
record = new
|
||||
var/list/lines = splittext(preset_record_text,"\n")
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
|
||||
var/minetype = "lavaland"
|
||||
|
||||
var/shuttles = list(
|
||||
"cargo" = "cargo_box",
|
||||
"ferry" = "ferry_fancy",
|
||||
"whiteship" = "whiteship_box",
|
||||
"emergency" = "emergency_box")
|
||||
|
||||
//Order matters here.
|
||||
var/list/transition_config = list(CENTCOM = SELFLOOPING,
|
||||
MAIN_STATION = CROSSLINKED,
|
||||
@@ -69,6 +75,12 @@
|
||||
map_path = json["map_path"]
|
||||
map_file = json["map_file"]
|
||||
|
||||
if(islist(json["shuttles"]))
|
||||
var/list/L = json["shuttles"]
|
||||
for(var/key in L)
|
||||
var/value = L[key]
|
||||
shuttles[key] = value
|
||||
|
||||
minetype = json["minetype"] || minetype
|
||||
allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE
|
||||
|
||||
@@ -81,12 +93,16 @@
|
||||
|
||||
defaulted = FALSE
|
||||
|
||||
#define CHECK_EXISTS(X) if(!istext(json[X])) { log_world(X + "missing from json!"); return; }
|
||||
#define CHECK_EXISTS(X) if(!istext(json[X])) { log_world("[##X] missing from json!"); return; }
|
||||
/datum/map_config/proc/ValidateJSON(list/json)
|
||||
CHECK_EXISTS("map_name")
|
||||
CHECK_EXISTS("map_path")
|
||||
CHECK_EXISTS("map_file")
|
||||
|
||||
var/shuttles = json["shuttles"]
|
||||
if(shuttles && !islist(shuttles))
|
||||
log_world("json\[shuttles\] is not a list!")
|
||||
|
||||
var/path = GetFullMapPath(json["map_path"], json["map_file"])
|
||||
if(!fexists(path))
|
||||
log_world("Map file ([path]) does not exist!")
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
|
||||
/obj/item/twohanded/bostaff/attack(mob/target, mob/living/user)
|
||||
add_fingerprint(user)
|
||||
if((user.has_disability(DISABILITY_CLUMSY)) && prob(50))
|
||||
if((user.has_trait(TRAIT_CLUMSY)) && prob(50))
|
||||
to_chat(user, "<span class ='warning'>You club yourself over the head with [src].</span>")
|
||||
user.Knockdown(60)
|
||||
if(ishuman(user))
|
||||
|
||||
@@ -85,12 +85,12 @@
|
||||
/datum/mutation/human/clumsy/on_acquiring(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
return
|
||||
owner.add_disability(DISABILITY_CLUMSY, GENETIC_MUTATION)
|
||||
owner.add_trait(TRAIT_CLUMSY, GENETIC_MUTATION)
|
||||
|
||||
/datum/mutation/human/clumsy/on_losing(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
return
|
||||
owner.remove_disability(DISABILITY_CLUMSY, GENETIC_MUTATION)
|
||||
owner.remove_trait(TRAIT_CLUMSY, GENETIC_MUTATION)
|
||||
|
||||
|
||||
//Tourettes causes you to randomly stand in place and shout.
|
||||
@@ -124,12 +124,12 @@
|
||||
/datum/mutation/human/deaf/on_acquiring(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
return
|
||||
owner.add_disability(DISABILITY_DEAF, GENETIC_MUTATION)
|
||||
owner.add_trait(TRAIT_DEAF, GENETIC_MUTATION)
|
||||
|
||||
/datum/mutation/human/deaf/on_losing(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
return
|
||||
owner.remove_disability(DISABILITY_DEAF, GENETIC_MUTATION)
|
||||
owner.remove_trait(TRAIT_DEAF, GENETIC_MUTATION)
|
||||
|
||||
|
||||
//Monified turns you into a monkey.
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
get_chance = 15
|
||||
lowest_value = 256 * 12
|
||||
text_gain_indication = "<span class='notice'>Your muscles hurt!</span>"
|
||||
species_allowed = list("human") //no skeleton/lizard hulk
|
||||
species_allowed = list("fly") //no skeleton/lizard hulk
|
||||
health_req = 25
|
||||
|
||||
/datum/mutation/human/hulk/on_acquiring(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
return
|
||||
var/status = CANSTUN | CANKNOCKDOWN | CANUNCONSCIOUS | CANPUSH
|
||||
owner.status_flags &= ~status
|
||||
owner.add_trait(TRAIT_STUNIMMUNE, TRAIT_HULK)
|
||||
owner.add_trait(TRAIT_PUSHIMMUNE, TRAIT_HULK)
|
||||
owner.update_body_parts()
|
||||
|
||||
/datum/mutation/human/hulk/on_attack_hand(mob/living/carbon/human/owner, atom/target, proximity)
|
||||
@@ -27,7 +27,8 @@
|
||||
/datum/mutation/human/hulk/on_losing(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
return
|
||||
owner.status_flags |= CANSTUN | CANKNOCKDOWN | CANUNCONSCIOUS | CANPUSH
|
||||
owner.remove_trait(TRAIT_STUNIMMUNE, TRAIT_HULK)
|
||||
owner.remove_trait(TRAIT_PUSHIMMUNE, TRAIT_HULK)
|
||||
owner.update_body_parts()
|
||||
|
||||
/datum/mutation/human/hulk/say_mod(message)
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
/datum/mutation/human/mute/on_acquiring(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
return
|
||||
owner.add_disability(DISABILITY_MUTE, GENETIC_MUTATION)
|
||||
owner.add_trait(TRAIT_MUTE, GENETIC_MUTATION)
|
||||
|
||||
/datum/mutation/human/mute/on_losing(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
return
|
||||
owner.remove_disability(DISABILITY_MUTE, GENETIC_MUTATION)
|
||||
owner.remove_trait(TRAIT_MUTE, GENETIC_MUTATION)
|
||||
|
||||
|
||||
/datum/mutation/human/smile
|
||||
|
||||
+80
-2
@@ -40,6 +40,28 @@
|
||||
/datum/map_template/shuttle/whiteship
|
||||
port_id = "whiteship"
|
||||
|
||||
/datum/map_template/shuttle/labour
|
||||
port_id = "labour"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/mining
|
||||
port_id = "mining"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/cargo
|
||||
port_id = "cargo"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/arrival
|
||||
port_id = "arrival"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/infiltrator
|
||||
port_id = "infiltrator"
|
||||
can_be_bought = FALSE
|
||||
|
||||
|
||||
|
||||
// Shuttles start here:
|
||||
|
||||
/datum/map_template/shuttle/emergency/airless
|
||||
@@ -100,7 +122,7 @@
|
||||
description = "The glorious results of centuries of plasma research done by Nanotrasen employees. This is the reason why you are here. Get on and dance like you're on fire, burn baby burn!"
|
||||
admin_notes = "Flaming hot."
|
||||
credit_cost = 10000
|
||||
|
||||
|
||||
/datum/map_template/shuttle/emergency/arena
|
||||
suffix = "arena"
|
||||
name = "The Arena"
|
||||
@@ -218,6 +240,12 @@
|
||||
admin_notes = "If the crew can solve the puzzle, they will wake the wabbajack statue. It will likely not end well. There's a reason it's boarded up. Maybe they should have just left it alone."
|
||||
credit_cost = 15000
|
||||
|
||||
/datum/map_template/shuttle/emergency/omega
|
||||
suffix = "omega"
|
||||
name = "Omegastation Emergency Shuttle"
|
||||
description = "On the smaller size with a modern design, this shuttle is for the crew who like the cosier things, while still being able to stretch their legs."
|
||||
credit_cost = 1000
|
||||
|
||||
/datum/map_template/shuttle/ferry/base
|
||||
suffix = "base"
|
||||
name = "transport ferry"
|
||||
@@ -240,13 +268,18 @@
|
||||
Fulfilling needs you didn't even know you had. We've got EVERYTHING, and something else!"
|
||||
admin_notes = "Currently larger than ferry docking port on Box, will not hit anything, but must be force docked. Trader and ERT bodyguards are not included."
|
||||
|
||||
/datum/map_template/shuttle/ferry/fancy
|
||||
suffix = "fancy"
|
||||
name = "fancy transport ferry"
|
||||
description = "At some point, someone upgraded the ferry to have fancier flooring... and less seats."
|
||||
|
||||
/datum/map_template/shuttle/whiteship/box
|
||||
suffix = "box"
|
||||
name = "NT Medical Ship"
|
||||
|
||||
/datum/map_template/shuttle/whiteship/meta
|
||||
suffix = "meta"
|
||||
name = "NT Recovery White-ship"
|
||||
name = "NT Recovery Whiteship"
|
||||
|
||||
/datum/map_template/shuttle/whiteship/pubby
|
||||
suffix = "pubby"
|
||||
@@ -256,6 +289,11 @@
|
||||
suffix = "cere"
|
||||
name = "NT Construction Vessel"
|
||||
|
||||
/datum/map_template/shuttle/whiteship/delta
|
||||
suffix = "delta"
|
||||
name = "Unnamed NT Vessel"
|
||||
admin_notes = "The Delta whiteship doesn't have a name, apparently."
|
||||
|
||||
/datum/map_template/shuttle/cargo/box
|
||||
suffix = "box"
|
||||
name = "supply shuttle (Box)"
|
||||
@@ -277,3 +315,43 @@
|
||||
description = "The CentCom Raven Battlecruiser is currently docked at the CentCom ship bay awaiting a mission, this Battlecruiser has been reassigned as an emergency escape shuttle for currently unknown reasons. The CentCom Raven Battlecruiser should comfortably fit a medium to large crew size crew and is complete with all required facitlities including a top of the range CentCom Medical Bay."
|
||||
admin_notes = "The long way home"
|
||||
credit_cost = 12500
|
||||
|
||||
/datum/map_template/shuttle/arrival/box
|
||||
suffix = "box"
|
||||
name = "arrival shuttle (Box)"
|
||||
|
||||
/datum/map_template/shuttle/cargo/box
|
||||
suffix = "box"
|
||||
name = "cargo ferry (Box)"
|
||||
|
||||
/datum/map_template/shuttle/mining/box
|
||||
suffix = "box"
|
||||
name = "mining shuttle (Box)"
|
||||
|
||||
/datum/map_template/shuttle/labour/box
|
||||
suffix = "box"
|
||||
name = "labour shuttle (Box)"
|
||||
|
||||
/datum/map_template/shuttle/infiltrator/basic
|
||||
suffix = "basic"
|
||||
name = "basic syndicate infiltrator"
|
||||
|
||||
/datum/map_template/shuttle/cargo/delta
|
||||
suffix = "delta"
|
||||
name = "cargo ferry (Delta)"
|
||||
|
||||
/datum/map_template/shuttle/mining/delta
|
||||
suffix = "delta"
|
||||
name = "mining shuttle (Delta)"
|
||||
|
||||
/datum/map_template/shuttle/labour/delta
|
||||
suffix = "delta"
|
||||
name = "labour shuttle (Delta)"
|
||||
|
||||
/datum/map_template/shuttle/arrival/delta
|
||||
suffix = "delta"
|
||||
name = "arrival shuttle (Delta)"
|
||||
|
||||
/datum/map_template/shuttle/arrival/pubby
|
||||
suffix = "pubby"
|
||||
name = "arrival shuttle (Pubby)"
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
var/list/status = list()
|
||||
status += "The door bolts [A.locked ? "have fallen!" : "look up."]"
|
||||
status += "The test light is [A.hasPower() ? "on" : "off"]."
|
||||
status += "The AI connection light is [A.aiControlDisabled || A.emagged ? "off" : "on"]."
|
||||
status += "The AI connection light is [A.aiControlDisabled || (A.obj_flags & EMAGGED) ? "off" : "on"]."
|
||||
status += "The check wiring light is [A.safe ? "off" : "on"]."
|
||||
status += "The timer is powered [A.autoclose ? "on" : "off"]."
|
||||
status += "The speed light is [A.normalspeed ? "on" : "off"]."
|
||||
@@ -44,7 +44,7 @@
|
||||
if(WIRE_BACKUP1, WIRE_BACKUP2) // Pulse to loose backup power.
|
||||
A.loseBackupPower()
|
||||
if(WIRE_OPEN) // Pulse to open door (only works not emagged and ID wire is cut or no access is required).
|
||||
if(A.emagged)
|
||||
if(A.obj_flags & EMAGGED)
|
||||
return
|
||||
if(!A.requiresID() || A.check_access(null))
|
||||
if(A.density)
|
||||
|
||||
@@ -140,3 +140,28 @@
|
||||
/area/shuttle/syndicate_scout
|
||||
name = "Syndicate Scout"
|
||||
blob_allowed = FALSE
|
||||
|
||||
/area/shuttle/caravan
|
||||
blob_allowed = FALSE
|
||||
requires_power = TRUE
|
||||
|
||||
/area/shuttle/caravan/syndicate1
|
||||
name = "Syndicate Fighter"
|
||||
|
||||
/area/shuttle/caravan/syndicate2
|
||||
name = "Syndicate Fighter"
|
||||
|
||||
/area/shuttle/caravan/syndicate3
|
||||
name = "Syndicate Drop Ship"
|
||||
|
||||
/area/shuttle/caravan/pirate
|
||||
name = "Pirate Cutter"
|
||||
|
||||
/area/shuttle/caravan/freighter1
|
||||
name = "Small Freighter"
|
||||
|
||||
/area/shuttle/caravan/freighter2
|
||||
name = "Tiny Freighter"
|
||||
|
||||
/area/shuttle/caravan/freighter3
|
||||
name = "Tiny Freighter"
|
||||
+26
-6
@@ -531,21 +531,41 @@
|
||||
/atom/proc/return_temperature()
|
||||
return
|
||||
|
||||
// Default tool behaviors proc
|
||||
// Tool behavior procedure. Redirects to tool-specific procs by default.
|
||||
// You can override it to catch all tool interactions, for use in complex deconstruction procs.
|
||||
// Just don't forget to return ..() in the end.
|
||||
/atom/proc/tool_act(mob/living/user, obj/item/tool, tool_type)
|
||||
switch(tool_type)
|
||||
if(TOOL_CROWBAR)
|
||||
return crowbar_act(user, tool)
|
||||
if(TOOL_MULTITOOL)
|
||||
return multitool_act(user, tool)
|
||||
if(TOOL_SCREWDRIVER)
|
||||
return screwdriver_act(user, tool)
|
||||
if(TOOL_WRENCH)
|
||||
return wrench_act(user, tool)
|
||||
if(TOOL_WIRECUTTER)
|
||||
return wirecutter_act(user, tool)
|
||||
if(TOOL_WELDER)
|
||||
return welder_act(user, tool)
|
||||
|
||||
/atom/proc/crowbar_act(mob/user, obj/item/tool)
|
||||
// Tool-specific behavior procs. To be overridden in subtypes.
|
||||
/atom/proc/crowbar_act(mob/living/user, obj/item/tool)
|
||||
return
|
||||
|
||||
/atom/proc/multitool_act(mob/user, obj/item/tool)
|
||||
/atom/proc/multitool_act(mob/living/user, obj/item/tool)
|
||||
return
|
||||
|
||||
/atom/proc/screwdriver_act(mob/user, obj/item/tool)
|
||||
/atom/proc/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
return
|
||||
|
||||
/atom/proc/wrench_act(mob/user, obj/item/tool)
|
||||
/atom/proc/wrench_act(mob/living/user, obj/item/tool)
|
||||
return
|
||||
|
||||
/atom/proc/wirecutter_act(mob/user, obj/item/tool)
|
||||
/atom/proc/wirecutter_act(mob/living/user, obj/item/tool)
|
||||
return
|
||||
|
||||
/atom/proc/welder_act(mob/living/user, obj/item/tool)
|
||||
return
|
||||
|
||||
/atom/proc/GenerateTag()
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
//helper for getting the appropriate health status
|
||||
/proc/RoundHealth(mob/living/M)
|
||||
if(M.stat == DEAD || (M.status_flags & FAKEDEATH))
|
||||
if(M.stat == DEAD || (M.has_trait(TRAIT_FAKEDEATH)))
|
||||
return "health-100" //what's our health? it doesn't matter, we're dead, or faking
|
||||
var/maxi_health = M.maxHealth
|
||||
if(iscarbon(M) && M.health < 0)
|
||||
@@ -167,7 +167,7 @@
|
||||
var/image/holder = hud_list[STATUS_HUD]
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(stat == DEAD || (status_flags & FAKEDEATH))
|
||||
if(stat == DEAD || (has_trait(TRAIT_FAKEDEATH)))
|
||||
holder.icon_state = "huddead"
|
||||
else
|
||||
holder.icon_state = "hudhealthy"
|
||||
@@ -177,9 +177,9 @@
|
||||
var/icon/I = icon(icon, icon_state, dir)
|
||||
var/virus_threat = check_virus()
|
||||
holder.pixel_y = I.Height() - world.icon_size
|
||||
if(status_flags & XENO_HOST)
|
||||
if(has_trait(TRAIT_XENO_HOST))
|
||||
holder.icon_state = "hudxeno"
|
||||
else if(stat == DEAD || (status_flags & FAKEDEATH))
|
||||
else if(stat == DEAD || (has_trait(TRAIT_FAKEDEATH)))
|
||||
holder.icon_state = "huddead"
|
||||
else
|
||||
switch(virus_threat)
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
//Few global vars to track the blob
|
||||
GLOBAL_LIST_EMPTY(blobs) //complete list of all blobs made.
|
||||
GLOBAL_LIST_EMPTY(blob_cores)
|
||||
GLOBAL_LIST_EMPTY(overminds)
|
||||
GLOBAL_LIST_EMPTY(blob_nodes)
|
||||
GLOBAL_LIST_EMPTY(blobs_legit) //used for win-score calculations, contains only blobs counted for win condition
|
||||
|
||||
#define BLOB_NO_PLACE_TIME 1800 //time, in deciseconds, blobs are prevented from bursting in the gamemode
|
||||
|
||||
/datum/game_mode/blob
|
||||
name = "blob"
|
||||
config_tag = "blob"
|
||||
antag_flag = ROLE_BLOB
|
||||
false_report_weight = 5
|
||||
|
||||
required_players = 25
|
||||
required_enemies = 1
|
||||
recommended_enemies = 1
|
||||
|
||||
round_ends_with_antag_death = 1
|
||||
|
||||
announce_span = "green"
|
||||
announce_text = "Dangerous gelatinous organisms are spreading throughout the station!\n\
|
||||
<span class='green'>Blobs</span>: Consume the station and spread as far as you can.\n\
|
||||
<span class='notice'>Crew</span>: Fight back the blobs and minimize station damage."
|
||||
|
||||
var/message_sent = FALSE
|
||||
|
||||
var/cores_to_spawn = 1
|
||||
var/players_per_core = 25
|
||||
var/blob_point_rate = 3
|
||||
var/blob_base_starting_points = 80
|
||||
|
||||
var/blobwincount = 250
|
||||
|
||||
var/messagedelay_low = 2400 //in deciseconds
|
||||
var/messagedelay_high = 3600 //blob report will be sent after a random value between these (minimum 4 minutes, maximum 6 minutes)
|
||||
|
||||
var/list/blob_overminds = list()
|
||||
|
||||
/datum/game_mode/blob/pre_setup()
|
||||
cores_to_spawn = max(round(num_players()/players_per_core, 1), 1)
|
||||
|
||||
var/win_multiplier = 1 + (0.1 * cores_to_spawn)
|
||||
blobwincount = initial(blobwincount) * cores_to_spawn * win_multiplier
|
||||
|
||||
for(var/j = 0, j < cores_to_spawn, j++)
|
||||
if (!antag_candidates.len)
|
||||
break
|
||||
var/datum/mind/blob = pick(antag_candidates)
|
||||
blob_overminds += blob
|
||||
blob.assigned_role = "Blob"
|
||||
blob.special_role = "Blob"
|
||||
log_game("[blob.key] (ckey) has been selected as a Blob")
|
||||
antag_candidates -= blob
|
||||
|
||||
if(!blob_overminds.len)
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/datum/game_mode/blob/proc/get_blob_candidates()
|
||||
var/list/candidates = list()
|
||||
for(var/mob/living/carbon/human/player in GLOB.player_list)
|
||||
if(!player.stat && player.mind && !player.mind.special_role && !jobban_isbanned(player, "Syndicate") && (ROLE_BLOB in player.client.prefs.be_special))
|
||||
if(age_check(player.client))
|
||||
candidates += player
|
||||
return candidates
|
||||
|
||||
/datum/game_mode/blob/proc/show_message(message)
|
||||
for(var/datum/mind/blob in blob_overminds)
|
||||
to_chat(blob.current, message)
|
||||
|
||||
/datum/game_mode/blob/post_setup()
|
||||
set waitfor = FALSE
|
||||
|
||||
for(var/datum/mind/blob in blob_overminds)
|
||||
var/mob/camera/blob/B = blob.current.become_overmind(TRUE, round(blob_base_starting_points/blob_overminds.len))
|
||||
B.mind.name = B.name
|
||||
var/turf/T = pick(GLOB.blobstart)
|
||||
B.forceMove(T)
|
||||
B.base_point_rate = blob_point_rate
|
||||
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
|
||||
// Disable the blob event for this round.
|
||||
var/datum/round_event_control/blob/B = locate() in SSevents.control
|
||||
if(B)
|
||||
B.max_occurrences = 0 // disable the event
|
||||
|
||||
. = ..()
|
||||
|
||||
var/message_delay = rand(messagedelay_low, messagedelay_high) //between 4 and 6 minutes with 2400 low and 3600 high.
|
||||
|
||||
sleep(message_delay)
|
||||
|
||||
send_intercept(1)
|
||||
message_sent = TRUE
|
||||
addtimer(CALLBACK(src, .proc/SendSecondIntercept), 24000)
|
||||
|
||||
/datum/game_mode/blob/proc/SendSecondIntercept()
|
||||
if(!replacementmode)
|
||||
send_intercept(2) //if the blob has been alive this long, it's time to bomb it
|
||||
|
||||
/datum/game_mode/blob/generate_report()
|
||||
return "A CMP scientist by the name of [pick("Griff", "Pasteur", "Chamberland", "Buist", "Rivers", "Stanley")] boasted about his corporation's \"finest creation\" - a macrobiological \
|
||||
virus capable of self-reproduction and hellbent on consuming whatever it touches. He went on to query Cybersun for permission to utilize the virus in biochemical warfare, to which \
|
||||
CMP subsequently gained. Be vigilant for any large organisms rapidly spreading across the station, as they are classified as a level 5 biohazard and critically dangerous. Note that \
|
||||
this organism seems to be weak to extreme heat; concentrated fire (such as welding tools and lasers) will be effective against it."
|
||||
@@ -1,393 +0,0 @@
|
||||
//For the clockwork proselytizer, this proc exists to make it easy to customize what the proselytizer does when hitting something.
|
||||
|
||||
//if a valid target, returns an associated list in this format;
|
||||
//list("operation_time" = 15, "new_obj_type" = /obj/structure/window/reinforced/clockwork, "power_cost" = 5, "spawn_dir" = dir, "dir_in_new" = TRUE)
|
||||
//otherwise, return literally any non-list thing but preferably FALSE
|
||||
//returning TRUE won't produce the "cannot be proselytized" message and will still prevent proselytizing
|
||||
|
||||
/atom/proc/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Turf conversion
|
||||
/turf/closed/wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //four sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 4), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/iron/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal, five rods
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2) - (POWER_ROD * 5), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/mineral/cult/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //no metal
|
||||
return list("operation_time" = 80, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/shuttle/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_TOTAL - (POWER_METAL * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/closed/wall/r_wall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/closed/wall/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 50, "new_obj_type" = /turf/open/floor/clockwork, "power_cost" = -POWER_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/open/floor/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(floor_tile == /obj/item/stack/tile/plasteel)
|
||||
new floor_tile(src)
|
||||
make_plating()
|
||||
playsound(src, 'sound/items/Crowbar.ogg', 10, 1) //clink
|
||||
return list("operation_time" = 30, "new_obj_type" = /turf/open/floor/clockwork, "power_cost" = POWER_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
/turf/open/floor/plating/asteroid/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/plating/ashplanet/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/plating/lava/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/turf/open/floor/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(locate(/obj/structure/table) in src)
|
||||
return FALSE
|
||||
if(locate(/obj/structure/falsewall) in contents)
|
||||
to_chat(user, "<span class='warning'>There is a false wall in the way, preventing you from proselytizing [src] into a clockwork wall.</span>")
|
||||
return
|
||||
if(is_blocked_turf(src, TRUE))
|
||||
to_chat(user, "<span class='warning'>Something is in the way, preventing you from proselytizing [src] into a clockwork wall.</span>")
|
||||
return TRUE
|
||||
var/operation_time = 100
|
||||
if(proselytizer.speed_multiplier > 0)
|
||||
operation_time /= proselytizer.speed_multiplier
|
||||
return list("operation_time" = operation_time, "new_obj_type" = /turf/closed/wall/clockwork, "power_cost" = POWER_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
|
||||
|
||||
//False wall conversion
|
||||
/obj/structure/falsewall/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/cost = POWER_WALL_MINUS_FLOOR
|
||||
if(ispath(mineral, /obj/item/stack/sheet/metal))
|
||||
cost -= (POWER_METAL * (2 + mineral_amount)) //four sheets of metal, plus an assumption that the girder is also two
|
||||
else
|
||||
cost -= (POWER_METAL * 2) //anything that doesn't use metal just has the girder
|
||||
return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "power_cost" = cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/falsewall/iron/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer) //two sheets of metal, two rods; special assumption
|
||||
return list("operation_time" = 50, "new_obj_type" = /obj/structure/falsewall/brass, "power_cost" = POWER_WALL_MINUS_FLOOR - (POWER_METAL * 2) - (POWER_ROD * 2), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/falsewall/reinforced/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/falsewall/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Metal conversion
|
||||
/obj/item/stack/tile/plasteel/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
var/amount_temp = get_amount()
|
||||
if(proselytizer.metal_to_power)
|
||||
var/no_delete = FALSE
|
||||
if(amount_temp < 2)
|
||||
to_chat(user, "<span class='warning'>You need at least <b>2</b> floor tiles to convert into power.</span>")
|
||||
return TRUE
|
||||
if(IsOdd(amount_temp))
|
||||
amount_temp--
|
||||
no_delete = TRUE
|
||||
use(amount_temp)
|
||||
amount_temp *= 12.5 //each tile is 12.5 power so this is 2 tiles to 25 power
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -amount_temp, "spawn_dir" = SOUTH, "no_target_deletion" = no_delete)
|
||||
if(amount_temp >= 20)
|
||||
var/sheets_to_make = round(amount_temp * 0.05) //and 20 to 1 brass
|
||||
var/used = sheets_to_make * 20
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need at least <b>20</b> floor tiles to convert into brass.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/rods/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
if(proselytizer.metal_to_power)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_ROD), "spawn_dir" = SOUTH)
|
||||
if(get_amount() >= 10)
|
||||
var/sheets_to_make = round(get_amount() * 0.1)
|
||||
var/used = sheets_to_make * 10
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need at least <b>10</b> rods to convert into brass.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/sheet/metal/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
if(proselytizer.metal_to_power)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_METAL), "spawn_dir" = SOUTH)
|
||||
if(get_amount() >= 5)
|
||||
var/sheets_to_make = round(get_amount() * 0.2)
|
||||
var/used = sheets_to_make * 5
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need at least <b>5</b> sheets of metal to convert into brass.</span>")
|
||||
return TRUE
|
||||
|
||||
/obj/item/stack/sheet/plasteel/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
if(proselytizer.metal_to_power)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_PLASTEEL), "spawn_dir" = SOUTH)
|
||||
if(get_amount() >= 2)
|
||||
var/sheets_to_make = round(get_amount() * 0.5)
|
||||
var/used = sheets_to_make * 2
|
||||
user.visible_message("<span class='warning'>[user]'s [proselytizer.name] rips into [src], converting it to brass!</span>", \
|
||||
"<span class='brass'>You convert [get_amount() - used > 0 ? "part of ":""][src] into brass...</span>")
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
new /obj/item/stack/tile/brass(get_turf(src), sheets_to_make)
|
||||
use(used)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need at least <b>2</b> sheets of plasteel to convert into brass.</span>")
|
||||
return TRUE
|
||||
|
||||
//Brass directly to power
|
||||
/obj/item/stack/tile/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
if(source)
|
||||
return FALSE
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(amount*POWER_FLOOR), "spawn_dir" = SOUTH)
|
||||
|
||||
//Airlock conversion
|
||||
/obj/machinery/door/airlock/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/doortype = /obj/machinery/door/airlock/clockwork
|
||||
if(glass)
|
||||
doortype = /obj/machinery/door/airlock/clockwork/brass
|
||||
return list("operation_time" = 60, "new_obj_type" = doortype, "power_cost" = POWER_WALL_TOTAL, "spawn_dir" = dir)
|
||||
|
||||
/obj/machinery/door/airlock/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Table conversion
|
||||
/obj/structure/table/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/prosel_cost = POWER_STANDARD
|
||||
if(framestack == /obj/item/stack/rods)
|
||||
prosel_cost -= POWER_ROD*framestackamount
|
||||
else if(framestack == /obj/item/stack/tile/brass)
|
||||
prosel_cost -= POWER_FLOOR*framestackamount
|
||||
if(buildstack == /obj/item/stack/sheet/metal)
|
||||
prosel_cost -= POWER_METAL*buildstackamount
|
||||
else if(buildstack == /obj/item/stack/sheet/plasteel)
|
||||
prosel_cost -= POWER_PLASTEEL*buildstackamount
|
||||
return list("operation_time" = 20, "new_obj_type" = /obj/structure/table/reinforced/brass, "power_cost" = prosel_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/table/reinforced/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/table_frame/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/prosel_cost = POWER_FLOOR
|
||||
if(framestack == /obj/item/stack/rods)
|
||||
prosel_cost -= POWER_ROD*framestackamount
|
||||
else if(framestack == /obj/item/stack/tile/brass)
|
||||
prosel_cost -= POWER_FLOOR*framestackamount
|
||||
return list("operation_time" = 10, "new_obj_type" = /obj/structure/table_frame/brass, "power_cost" = prosel_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/structure/table_frame/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Window conversion
|
||||
/obj/structure/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/windowtype = /obj/structure/window/reinforced/clockwork
|
||||
var/new_dir = TRUE
|
||||
var/prosel_time = 15
|
||||
var/prosel_cost = POWER_FLOOR
|
||||
if(fulltile)
|
||||
windowtype = /obj/structure/window/reinforced/clockwork/fulltile
|
||||
new_dir = FALSE
|
||||
prosel_time = 30
|
||||
prosel_cost = POWER_STANDARD
|
||||
if(reinf)
|
||||
prosel_cost -= POWER_ROD
|
||||
if(reinf)
|
||||
prosel_cost -= POWER_ROD
|
||||
for(var/obj/structure/grille/G in get_turf(src))
|
||||
INVOKE_ASYNC(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytize, G, user)
|
||||
return list("operation_time" = prosel_time, "new_obj_type" = windowtype, "power_cost" = prosel_cost, "spawn_dir" = dir, "dir_in_new" = new_dir)
|
||||
|
||||
/obj/structure/window/reinforced/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Windoor conversion
|
||||
/obj/machinery/door/window/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 30, "new_obj_type" = /obj/machinery/door/window/clockwork, "power_cost" = POWER_STANDARD, "spawn_dir" = dir, "dir_in_new" = TRUE)
|
||||
|
||||
/obj/machinery/door/window/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Grille conversion
|
||||
/obj/structure/grille/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/grilletype = /obj/structure/grille/ratvar
|
||||
var/prosel_time = 15
|
||||
if(broken)
|
||||
grilletype = /obj/structure/grille/ratvar/broken
|
||||
prosel_time = 5
|
||||
return list("operation_time" = prosel_time, "new_obj_type" = grilletype, "power_cost" = 0, "spawn_dir" = dir)
|
||||
|
||||
/obj/structure/grille/ratvar/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Lattice conversion
|
||||
/obj/structure/lattice/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/structure/lattice/clockwork, "power_cost" = 0, "spawn_dir" = SOUTH, "no_target_deletion" = TRUE)
|
||||
|
||||
/obj/structure/lattice/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
ratvar_act() //just in case we're the wrong type for some reason??
|
||||
return FALSE
|
||||
|
||||
/obj/structure/lattice/catwalk/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/structure/lattice/catwalk/clockwork, "power_cost" = 0, "spawn_dir" = SOUTH, "no_target_deletion" = TRUE)
|
||||
|
||||
/obj/structure/lattice/catwalk/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return FALSE
|
||||
|
||||
//Girder conversion
|
||||
/obj/structure/girder/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/prosel_cost = POWER_GEAR - (POWER_METAL * 2)
|
||||
if(state == GIRDER_REINF_STRUTS || state == GIRDER_REINF)
|
||||
prosel_cost -= POWER_PLASTEEL
|
||||
return list("operation_time" = 20, "new_obj_type" = /obj/structure/destructible/clockwork/wall_gear, "power_cost" = prosel_cost, "spawn_dir" = SOUTH)
|
||||
|
||||
//Hitting a clockwork structure will try to repair it.
|
||||
/obj/structure/destructible/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
var/list/repair_values = list()
|
||||
if(!proselytizer.proselytizer_repair_checks(repair_values, src, user))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts covering [src] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairing [src]...</span>")
|
||||
proselytizer.repairing = src
|
||||
while(proselytizer && user && src)
|
||||
if(!do_after(user, repair_values["healing_for_cycle"] * proselytizer.speed_multiplier, target = src, \
|
||||
extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytizer_repair_checks, repair_values, src, user, TRUE)))
|
||||
break
|
||||
obj_integrity = Clamp(obj_integrity + repair_values["healing_for_cycle"], 0, max_integrity)
|
||||
proselytizer.modify_stored_power(-repair_values["power_required"])
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
if(proselytizer)
|
||||
proselytizer.repairing = null
|
||||
if(user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops covering [src] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairing [src]. It is now at <b>[obj_integrity]/[max_integrity]</b> integrity.</span>")
|
||||
|
||||
//Hitting a sigil of transmission will try to charge from it.
|
||||
/obj/effect/clockwork/sigil/transmission/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
var/list/charge_values = list()
|
||||
if(!proselytizer.sigil_charge_checks(charge_values, src, user))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts draining glowing orange energy from [src]...</span>", \
|
||||
"<span class='alloy'>You start recharging your [proselytizer.name]...</span>")
|
||||
proselytizer.recharging = src
|
||||
while(proselytizer && user && src)
|
||||
if(!do_after(user, 10, target = src, extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/sigil_charge_checks, charge_values, src, user, TRUE)))
|
||||
break
|
||||
modify_charge(charge_values["power_gain"])
|
||||
proselytizer.modify_stored_power(charge_values["power_gain"])
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', charge_values["power_gain"] * 0.1, 1)
|
||||
|
||||
if(proselytizer)
|
||||
proselytizer.recharging = null
|
||||
if(user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops draining glowing orange energy from [src].</span>", \
|
||||
"<span class='alloy'>You finish recharging your [proselytizer.name]. It now contains <b>[proselytizer.get_power()]W/[proselytizer.get_max_power()]W</b> power.</span>")
|
||||
|
||||
//Proselytizer mob heal proc, to avoid as much copypaste as possible.
|
||||
/mob/living/proc/proselytizer_heal(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
var/list/repair_values = list()
|
||||
if(!proselytizer.proselytizer_repair_checks(repair_values, src, user))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairin[src == user ? "g yourself" : "g [src]"]...</span>")
|
||||
proselytizer.repairing = src
|
||||
while(proselytizer && user && src)
|
||||
if(!do_after(user, repair_values["healing_for_cycle"] * proselytizer.speed_multiplier, target = src, \
|
||||
extra_checks = CALLBACK(proselytizer, /obj/item/clockwork/clockwork_proselytizer.proc/proselytizer_repair_checks, repair_values, src, user, TRUE)))
|
||||
break
|
||||
proselytizer_heal_tick(repair_values["healing_for_cycle"])
|
||||
proselytizer.modify_stored_power(-repair_values["power_required"])
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
|
||||
if(proselytizer)
|
||||
proselytizer.repairing = null
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/proselytizer_heal_tick(amount)
|
||||
var/static/list/damage_heal_order = list(BRUTE, BURN, TOX, OXY)
|
||||
heal_ordered_damage(amount, damage_heal_order)
|
||||
|
||||
/mob/living/simple_animal/proselytizer_heal_tick(amount)
|
||||
adjustHealth(-amount)
|
||||
|
||||
//Hitting a ratvar'd silicon will also try to repair it.
|
||||
/mob/living/silicon/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
if(health == maxHealth) //if we're at maximum health, prosel the turf under us
|
||||
return FALSE
|
||||
else if(proselytizer_heal(user, proselytizer) && user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself. You are":"g [src]. [p_they(TRUE)] [p_are()]"] now at <b>[abs(HEALTH_THRESHOLD_DEAD - health)]/[abs(HEALTH_THRESHOLD_DEAD - maxHealth)]</b> health.</span>")
|
||||
|
||||
//Same with clockwork mobs.
|
||||
/mob/living/simple_animal/hostile/clockwork/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
if(health == maxHealth) //if we're at maximum health, prosel the turf under us
|
||||
return FALSE
|
||||
else if(proselytizer_heal(user, proselytizer) && user)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself. You are":"g [src]. [p_they(TRUE)] [p_are()]"] now at <b>[health]/[maxHealth]</b> health.</span>")
|
||||
|
||||
//Cogscarabs get special interaction because they're drones and have innate self-heals/revives.
|
||||
/mob/living/simple_animal/drone/cogscarab/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
. = TRUE
|
||||
if(stat == DEAD)
|
||||
try_reactivate(user) //if we're at maximum health, prosel the turf under us
|
||||
return
|
||||
if(health == maxHealth)
|
||||
return FALSE
|
||||
else if(!(flags_1 & GODMODE))
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] starts coverin[src == user ? "g [user.p_them()]" : "g [src]"] in glowing orange energy...</span>", \
|
||||
"<span class='alloy'>You start repairin[src == user ? "g yourself" : "g [src]"]...</span>")
|
||||
proselytizer.repairing = src
|
||||
if(do_after(user, (maxHealth - health)*2, target=src))
|
||||
adjustHealth(-maxHealth)
|
||||
user.visible_message("<span class='notice'>[user]'s [proselytizer.name] stops coverin[src == user ? "g [user.p_them()]" : "g [src]"] with glowing orange energy.</span>", \
|
||||
"<span class='alloy'>You finish repairin[src == user ? "g yourself" : "g [src]"].</span>")
|
||||
if(proselytizer)
|
||||
proselytizer.repairing = null
|
||||
|
||||
//Convert shards and gear bits directly to power
|
||||
/obj/item/clockwork/alloy_shards/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -POWER_STANDARD, "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/gear_bit/large/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.08), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/large/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.06), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/medium/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.04), "spawn_dir" = SOUTH)
|
||||
|
||||
/obj/item/clockwork/alloy_shards/small/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
|
||||
return list("operation_time" = 0, "new_obj_type" = /obj/effect/temp_visual/ratvar/beam/itemconsume, "power_cost" = -(CLOCKCULT_POWER_UNIT*0.02), "spawn_dir" = SOUTH)
|
||||
@@ -1,93 +0,0 @@
|
||||
//Anima fragment: Low health and high melee damage, but slows down when struck. Created by inserting a soul vessel into an empty fragment.
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment
|
||||
name = "anima fragment"
|
||||
desc = "An ominous humanoid shell with a spinning cogwheel as its head, lifted by a jet of blazing red flame."
|
||||
icon_state = "anime_fragment"
|
||||
health = 90
|
||||
maxHealth = 90
|
||||
speed = -1
|
||||
melee_damage_lower = 18
|
||||
melee_damage_upper = 18
|
||||
attacktext = "crushes"
|
||||
attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg'
|
||||
loot = list(/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment)
|
||||
weather_immunities = list("lava")
|
||||
movement_type = FLYING
|
||||
light_range = 2
|
||||
light_power = 0.8
|
||||
playstyle_string = "<span class='heavy_brass'>You are an anima fragment</span><b>, a clockwork creation of Ratvar. As a fragment, you have decent health that very gradually regenerates, do \
|
||||
decent damage, and move at extreme speed in addition to being immune to extreme temperatures and pressures. Taking damage, and slamming into non-Servants, will temporarily slow you down, however.\n\
|
||||
Your goal is to serve the Justiciar and his servants in any way you can. You yourself are one of these servants, and will be able to utilize anything they can, assuming it doesn't require \
|
||||
opposable thumbs.</b>"
|
||||
var/movement_delay_time //how long the fragment is slowed after being hit
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Initialize()
|
||||
. = ..()
|
||||
if(prob(1))
|
||||
name = "anime fragment"
|
||||
desc = "I-it's not like I want to show you the light of the Justiciar or anything, B-BAKA!"
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Life()
|
||||
..()
|
||||
if(GLOB.ratvar_awakens)
|
||||
adjustHealth(-5)
|
||||
else if(movement_delay_time > world.time)
|
||||
adjustHealth(-0.2)
|
||||
else
|
||||
adjustHealth(-1)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Stat()
|
||||
..()
|
||||
if(statpanel("Status") && movement_delay_time > world.time && !GLOB.ratvar_awakens)
|
||||
stat(null, "Movement delay(seconds): [max(round((movement_delay_time - world.time)*0.1, 0.1), 0)]")
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/death(gibbed)
|
||||
visible_message("<span class='warning'>[src]'s flame jets cut out as it falls to the floor with a tremendous crash.</span>", \
|
||||
"<span class='userdanger'>Your gears seize up. Your flame jets flicker out. Your soul vessel belches smoke as you helplessly crash down.</span>")
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Process_Spacemove(movement_dir = 0)
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/Collide(atom/movable/AM)
|
||||
. = ..()
|
||||
if(movement_delay_time <= world.time && next_move <= world.time && isliving(AM) && !is_servant_of_ratvar(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.stat) //we don't want to attack them if they're unconscious or dead because that feels REALLY BAD for the player
|
||||
return
|
||||
var/previousattacktext = attacktext
|
||||
attacktext = "slams into"
|
||||
UnarmedAttack(L)
|
||||
attacktext = previousattacktext
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
if(!GLOB.ratvar_awakens)
|
||||
adjustHealth(4)
|
||||
adjust_movement_delay(10) //with the above damage, total of 20 movement delay plus speed = 0 due to damage
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/emp_act(severity)
|
||||
adjust_movement_delay(50/severity)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/movement_delay()
|
||||
. = ..()
|
||||
if(movement_delay_time > world.time && !GLOB.ratvar_awakens)
|
||||
. += min((movement_delay_time - world.time) * 0.1, 10) //the more delay we have, the slower we go
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/adjustHealth(amount)
|
||||
. = ..()
|
||||
if(amount > 0)
|
||||
adjust_movement_delay(amount*2.5)
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/proc/adjust_movement_delay(amount)
|
||||
if(GLOB.ratvar_awakens) //if ratvar is up we ignore movement delay
|
||||
movement_delay_time = 0
|
||||
else if(movement_delay_time > world.time)
|
||||
movement_delay_time = movement_delay_time + amount
|
||||
else
|
||||
movement_delay_time = world.time + amount
|
||||
|
||||
/mob/living/simple_animal/hostile/clockwork/fragment/updatehealth()
|
||||
..()
|
||||
if(health == maxHealth)
|
||||
speed = initial(speed)
|
||||
else
|
||||
speed = 0 //slow down if damaged at all
|
||||
@@ -1,211 +0,0 @@
|
||||
//////////////
|
||||
// REVENANT //
|
||||
//////////////
|
||||
|
||||
//Invoke Inath-neq, the Resonant Cogwheel: Grants invulnerability and stun immunity to everyone nearby for 15 seconds.
|
||||
/datum/clockwork_scripture/invoke_inathneq
|
||||
descname = "Area Invulnerability"
|
||||
name = "Invoke Inath-neq, the Resonant Cogwheel"
|
||||
desc = "Taps the limitless power of Inath-neq, one of Ratvar's four generals. The benevolence of Inath-Neq will grant complete invulnerability to all Servants in range for fifteen seconds."
|
||||
invocations = list("I call upon you, Vanguard!!", "Let the Resonant Cogs turn once more!!", "Grant me and my allies the strength to vanquish our foes!!")
|
||||
channel_time = 100
|
||||
consumed_components = list(VANGUARD_COGWHEEL = 10, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 3)
|
||||
usage_tip = "Servants affected by this scripture are only weak to things that outright destroy bodies, such as bombs or the singularity."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 2
|
||||
|
||||
/datum/clockwork_scripture/invoke_inathneq/check_special_requirements()
|
||||
if(!slab.no_cost && GLOB.clockwork_generals_invoked["inath-neq"] > world.time)
|
||||
to_chat(invoker, "<span class='inathneq'>\"[text2ratvar("I cannot lend you my aid yet, champion. Please be careful.")]\"</span>\n\
|
||||
<span class='warning'>Inath-neq has already been invoked recently! You must wait several minutes before calling upon the Resonant Cogwheel.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_inathneq/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/inathneq(get_turf(invoker))
|
||||
hierophant_message("<span class='inathneq_large'>[text2ratvar("Vanguard: \"I lend you my aid, champions! Let glory guide your blows!")]\"</span>", FALSE, invoker)
|
||||
GLOB.clockwork_generals_invoked["inath-neq"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
if(invoker.real_name == "Lucio")
|
||||
clockwork_say(invoker, text2ratvar("Aww, let's break it DOWN!!"))
|
||||
for(var/mob/living/L in range(7, invoker))
|
||||
if(!is_servant_of_ratvar(L) || L.stat == DEAD)
|
||||
continue
|
||||
L.apply_status_effect(STATUS_EFFECT_INATHNEQS_ENDOWMENT)
|
||||
return TRUE
|
||||
|
||||
|
||||
//Invoke Sevtug, the Formless Pariah: Causes massive global hallucinations, braindamage, confusion, and dizziness to all humans on the same zlevel.
|
||||
/datum/clockwork_scripture/invoke_sevtug
|
||||
descname = "Global Hallucination"
|
||||
name = "Invoke Sevtug, the Formless Pariah"
|
||||
desc = "Taps the limitless power of Sevtug, one of Ratvar's four generals. The mental manipulation ability of the Pariah allows its wielder to cause mass hallucinations and confusion \
|
||||
for all non-servant humans on the same z-level as them. The power of this scripture falls off somewhat with distance, and certain things may reduce its effects."
|
||||
invocations = list("I call upon you, Fright!!", "Let your power shatter the sanity of the weak-minded!!", "Let your tendrils hold sway over all!!")
|
||||
channel_time = 150
|
||||
consumed_components = list(BELLIGERENT_EYE = 6, VANGUARD_COGWHEEL = 6, GEIS_CAPACITOR = 10, HIEROPHANT_ANSIBLE = 6)
|
||||
usage_tip = "Causes brain damage, hallucinations, confusion, and dizziness in massive amounts."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
sort_priority = 3
|
||||
primary_component = GEIS_CAPACITOR
|
||||
invokers_required = 3
|
||||
multiple_invokers_used = TRUE
|
||||
var/static/list/mindbreaksayings = list("\"Oh, great. I get to shatter some minds.\"", "\"More minds to crush.\"", \
|
||||
"\"Really, this is almost boring.\"", "\"None of these minds have anything interesting in them.\"", "\"Maybe I can instill a little bit of terror in this one.\"", \
|
||||
"\"What a waste of my power.\"", "\"I'm sure I could just control these minds instead, but they never ask.\"")
|
||||
|
||||
/datum/clockwork_scripture/invoke_sevtug/check_special_requirements()
|
||||
if(!slab.no_cost && GLOB.clockwork_generals_invoked["sevtug"] > world.time)
|
||||
to_chat(invoker, "<span class='sevtug'>\"[text2ratvar("Is it really so hard - even for a simpleton like you - to grasp the concept of waiting?")]\"</span>\n\
|
||||
<span class='warning'>Sevtug has already been invoked recently! You must wait several minutes before calling upon the Formless Pariah.</span>")
|
||||
return FALSE
|
||||
if(!slab.no_cost && GLOB.ratvar_awakens)
|
||||
to_chat(invoker, "<span class='sevtug'>\"[text2ratvar("Do you really think anything I can do right now will compare to Engine's power?")]\"</span>\n\
|
||||
<span class='warning'>Sevtug will not grant his power while Ratvar's dwarfs his own!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_sevtug/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/sevtug(get_turf(invoker))
|
||||
hierophant_message("<span class='sevtug_large'>[text2ratvar("Fright: \"I heed your call, idiots. Get going and use this chance while it lasts!")]\"</span>", FALSE, invoker)
|
||||
GLOB.clockwork_generals_invoked["sevtug"] = world.time + GLOBAL_CLOCKWORK_GENERAL_COOLDOWN
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
var/hum = get_sfx('sound/effects/screech.ogg') //like playsound, same sound for everyone affected
|
||||
var/turf/T = get_turf(invoker)
|
||||
for(var/mob/living/carbon/human/H in GLOB.living_mob_list)
|
||||
if(H.z == invoker.z && !is_servant_of_ratvar(H))
|
||||
var/distance = 0
|
||||
distance += get_dist(T, get_turf(H))
|
||||
var/visualsdistance = max(150 - distance, 5)
|
||||
var/minordistance = max(200 - distance*2, 5)
|
||||
var/majordistance = max(150 - distance*3, 5)
|
||||
if(H.null_rod_check())
|
||||
to_chat(H, "<span class='sevtug'>[text2ratvar("Oh, a void weapon. How annoying, I may as well not bother.")]</span>\n\
|
||||
<span class='warning'>Your holy weapon glows a faint orange, defending your mind!</span>")
|
||||
continue
|
||||
else if(H.isloyal())
|
||||
visualsdistance = round(visualsdistance * 0.5) //half effect for shielded targets
|
||||
minordistance = round(minordistance * 0.5)
|
||||
majordistance = round(majordistance * 0.5)
|
||||
to_chat(H, "<span class='sevtug'>[text2ratvar("Oh, look, a mindshield. Cute, I suppose I'll humor it.")]</span>")
|
||||
else if(prob(visualsdistance))
|
||||
to_chat(H, "<span class='sevtug'>[text2ratvar(pick(mindbreaksayings))]</span>")
|
||||
H.playsound_local(T, hum, visualsdistance, 1)
|
||||
flash_color(H, flash_color="#AF0AAF", flash_time=visualsdistance*10)
|
||||
H.dizziness = minordistance + H.dizziness
|
||||
H.hallucination = minordistance + H.hallucination
|
||||
H.confused = majordistance + H.confused
|
||||
H.setBrainLoss(majordistance + H.getBrainLoss())
|
||||
return TRUE
|
||||
|
||||
|
||||
//Invoke Nezbere, the Brass Eidolon: Invokes Nezbere, bolstering the strength of many clockwork items for one minute.
|
||||
/datum/clockwork_scripture/invoke_nezbere
|
||||
descname = "Global Structure Buff"
|
||||
name = "Invoke Nezbere, the Brass Eidolon"
|
||||
desc = "Taps the limitless power of Nezbere, one of Ratvar's four generals. The restless toil of the Eidolon will empower a wide variety of clockwork apparatus for a full minute - notably, \
|
||||
replica fabricators will charge very rapidly."
|
||||
invocations = list("I call upon you, Armorer!!", "Let your machinations reign on this miserable station!!", "Let your power flow through the tools of your master!!")
|
||||
channel_time = 150
|
||||
consumed_components = list(BELLIGERENT_EYE = 6, VANGUARD_COGWHEEL = 6, GEIS_CAPACITOR = 6, REPLICANT_ALLOY = 10)
|
||||
usage_tip = "Ocular wardens will become empowered, tinkerer's daemons will produce twice as quickly, \
|
||||
and interdiction lenses, mania motors, tinkerer's daemons, and clockwork obelisks will all require no power."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
primary_component = REPLICANT_ALLOY
|
||||
sort_priority = 4
|
||||
invokers_required = 3
|
||||
multiple_invokers_used = TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_nezbere/check_special_requirements()
|
||||
if(!slab.no_cost && GLOB.clockwork_generals_invoked["nezbere"] > world.time)
|
||||
to_chat(invoker, "<span class='nezbere'>\"[text2ratvar("Not just yet, friend. Patience is a virtue.")]\"</span>\n\
|
||||
<span class='warning'>Nezbere has already been invoked recently! You must wait several minutes before calling upon the Brass Eidolon.</span>")
|
||||
return FALSE
|
||||
if(!slab.no_cost && GLOB.ratvar_awakens)
|
||||
to_chat(invoker, "<span class='nezbere'>\"[text2ratvar("Our master is here already. You do not require my help, friend.")]\"</span>\n\
|
||||
<span class='warning'>There is no need for Nezbere's assistance while Ratvar is risen!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_nezbere/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/nezbere(get_turf(invoker))
|
||||
hierophant_message("<span class='nezbere_large'>[text2ratvar("Armorer: \"I heed your call, champions. May your artifacts bring ruin upon the heathens that oppose our master!")]\"</span>", FALSE, invoker)
|
||||
GLOB.clockwork_generals_invoked["nezbere"] = world.time + GLOBAL_CLOCKWORK_GENERAL_COOLDOWN
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
GLOB.nezbere_invoked++
|
||||
for(var/obj/O in GLOB.all_clockwork_objects)
|
||||
O.ratvar_act()
|
||||
addtimer(CALLBACK(GLOBAL_PROC, /proc/reset_nezbere_invocation), 600)
|
||||
return TRUE
|
||||
|
||||
/proc/reset_nezbere_invocation()
|
||||
GLOB.nezbere_invoked--
|
||||
for(var/obj/O in GLOB.all_clockwork_objects)
|
||||
O.ratvar_act()
|
||||
|
||||
|
||||
//Invoke Nzcrentr, the Eternal Thunderbolt: Imbues an immense amount of energy into the invoker. After several seconds, everyone near the invoker will be hit with a devastating lightning blast.
|
||||
/datum/clockwork_scripture/invoke_nzcrentr
|
||||
descname = "Area Lightning Blast"
|
||||
name = "Invoke Nzcrentr, the Eternal Thunderbolt"
|
||||
desc = "Taps the limitless power of Nzcrentr, one of Ratvar's four generals. Nzcrentr will grant you a tiny fraction of its boundless power. After several seconds, all non-Servants near you \
|
||||
will be struck by devastating lightning bolts."
|
||||
invocations = list("I call upon you, Amperage!!", "Let your energy flow through me!!", "Let your boundless power shatter stars!!")
|
||||
channel_time = 100
|
||||
consumed_components = list(BELLIGERENT_EYE = 3, GEIS_CAPACITOR = 3, REPLICANT_ALLOY = 3, HIEROPHANT_ANSIBLE = 10)
|
||||
usage_tip = "Struck targets will also be knocked down for about sixteen seconds."
|
||||
tier = SCRIPTURE_REVENANT
|
||||
primary_component = HIEROPHANT_ANSIBLE
|
||||
sort_priority = 5
|
||||
|
||||
/datum/clockwork_scripture/invoke_nzcrentr/check_special_requirements()
|
||||
if(!slab.no_cost && GLOB.clockwork_generals_invoked["nzcrentr"] > world.time)
|
||||
to_chat(invoker, "<span class='nzcrentr'>\"[text2ratvar("The boss says you have to wait. Hey, do you think he would mind if I killed you? ...He would? Ok.")]\"</span>\n\
|
||||
<span class='warning'>Nzcrentr has already been invoked recently! You must wait several minutes before calling upon the Eternal Thunderbolt.</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/invoke_nzcrentr/scripture_effects()
|
||||
new/obj/effect/clockwork/general_marker/nzcrentr(get_turf(invoker))
|
||||
GLOB.clockwork_generals_invoked["nzcrentr"] = world.time + CLOCKWORK_GENERAL_COOLDOWN
|
||||
hierophant_message("<span class='nzcrentr_large'>[text2ratvar("Amperage: \"[invoker.real_name] has called forth my power. Hope [invoker.p_they()] [invoker.p_do()] not shatter under it!")]\"</span>", FALSE, invoker)
|
||||
invoker.visible_message("<span class='warning'>[invoker] begins to radiate a blinding light!</span>", \
|
||||
"<span class='nzcrentr'>\"[text2ratvar("The boss says it's okay to do this. Don't blame me if you die from it.")]\"</span>\n\
|
||||
<span class='userdanger'>You feel limitless power surging through you!</span>")
|
||||
playsound(invoker, 'sound/magic/clockwork/invoke_general.ogg', 50, 0)
|
||||
sleep(2)
|
||||
playsound(invoker, 'sound/magic/lightning_chargeup.ogg', 100, 0)
|
||||
var/oldcolor = invoker.color
|
||||
animate(invoker, color = list(rgb(255, 255, 255), rgb(255, 255, 255), rgb(255, 255, 255), rgb(0,0,0)), time = 88) //Gradual advancement to extreme brightness
|
||||
sleep(88)
|
||||
if(invoker)
|
||||
invoker.visible_message("<span class='warning'>Massive bolts of energy emerge from across [invoker]'s body!</span>", \
|
||||
"<span class='nzcrentr'>\"[text2ratvar("I told you you wouldn't be able to handle it.")]\"</span>\n\
|
||||
<span class='userdanger'>TOO... MUCH! CAN'T... TAKE IT!</span>")
|
||||
playsound(invoker, 'sound/magic/lightningbolt.ogg', 100, 0)
|
||||
if(invoker.stat == CONSCIOUS)
|
||||
animate(invoker, color = oldcolor, time = 10)
|
||||
addtimer(CALLBACK(invoker, /atom/proc/update_atom_colour), 10)
|
||||
for(var/mob/living/L in view(7, invoker))
|
||||
if(is_servant_of_ratvar(L) || L.null_rod_check())
|
||||
continue
|
||||
invoker.Beam(L, icon_state = "nzcrentrs_power", time = 10)
|
||||
var/randdamage = rand(40, 60)
|
||||
if(iscarbon(L))
|
||||
L.electrocute_act(randdamage, "Nzcrentr's power", 1, randdamage)
|
||||
else
|
||||
L.adjustFireLoss(randdamage)
|
||||
L.visible_message(
|
||||
"<span class='danger'>[L] was shocked by Nzcrentr's power!</span>", \
|
||||
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>", \
|
||||
"<span class='italics'>You hear a heavy electrical crack.</span>" \
|
||||
)
|
||||
L.Weaken(8)
|
||||
playsound(L, 'sound/magic/LightningShock.ogg', 50, 1)
|
||||
else
|
||||
playsound(invoker, 'sound/magic/Disintegrate.ogg', 50, 1)
|
||||
invoker.gib()
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
@@ -1,143 +0,0 @@
|
||||
//Interdiction Lens: A powerful artifact that constantly disrupts electronics and drains power but, if it fails to find something to disrupt, turns off.
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens
|
||||
name = "interdiction lens"
|
||||
desc = "An ominous, double-pronged brass totem. There's a strange gemstone clasped between the pincers."
|
||||
clockwork_desc = "A powerful totem that constantly drains nearby electronics and funnels the power drained into nearby Sigils of Transmission or the area's APC."
|
||||
icon_state = "interdiction_lens"
|
||||
construction_value = 20
|
||||
active_icon = "interdiction_lens_active"
|
||||
inactive_icon = "interdiction_lens"
|
||||
unanchored_icon = "interdiction_lens_unwrenched"
|
||||
break_message = "<span class='warning'>The lens flares a blinding violet before the totem beneath it shatters!</span>"
|
||||
break_sound = 'sound/effects/glassbr3.ogg'
|
||||
debris = list(/obj/item/clockwork/alloy_shards/small = 2, \
|
||||
/obj/item/clockwork/alloy_shards/large = 2, \
|
||||
/obj/item/clockwork/component/belligerent_eye/lens_gem = 1)
|
||||
var/recharging = 0 //world.time when the lens was last used
|
||||
var/recharge_time = 1200 //if it drains no power and affects no objects, it turns off for two minutes
|
||||
var/disabled = FALSE //if it's actually usable
|
||||
var/interdiction_range = 14 //how large an area it drains and disables in
|
||||
var/static/list/rage_messages = list("...", "Disgusting.", "Die.", "Foul.", "Worthless.", "Mortal.", "Unfit.", "Weak.", "Fragile.", "Useless.", "Leave my sight!")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/Initialize()
|
||||
. = ..()
|
||||
update_current_glow()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='[recharging > world.time ? "neovgre_small":"brass"]'>Its gemstone [recharging > world.time ? "has been breached by writhing tendrils of blackness that cover the totem" \
|
||||
: "vibrates in place and thrums with power"].</span>")
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
to_chat(user, "<span class='neovgre_small'>If it fails to drain any electronics or has nothing to return power to, it will disable itself for <b>[round(recharge_time/600, 1)]</b> minutes.</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/update_anchored(mob/user, do_damage)
|
||||
..()
|
||||
update_current_glow()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/toggle(fast_process, mob/living/user)
|
||||
. = ..()
|
||||
update_current_glow()
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/proc/update_current_glow()
|
||||
if(active)
|
||||
if(disabled)
|
||||
set_light(2, 1.6, "#151200")
|
||||
else
|
||||
set_light(2, 1.6, "#EE54EE")
|
||||
else
|
||||
if(anchored)
|
||||
set_light(1.4, 0.8, "#F42B9D")
|
||||
else
|
||||
set_light(0)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/attack_hand(mob/living/user)
|
||||
if(user.canUseTopic(src, !issilicon(user), NO_DEXTERY))
|
||||
if(disabled)
|
||||
to_chat(user, "<span class='warning'>As you place your hand on the gemstone, cold tendrils of black matter crawl up your arm. You quickly pull back.</span>")
|
||||
return 0
|
||||
toggle(0, user)
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/forced_disable(bad_effects)
|
||||
if(disabled || !anchored)
|
||||
return FALSE
|
||||
if(!active)
|
||||
toggle(0)
|
||||
visible_message("<span class='warning'>The gemstone suddenly turns horribly dark, writhing tendrils covering it!</span>")
|
||||
recharging = world.time + recharge_time
|
||||
flick("interdiction_lens_discharged", src)
|
||||
icon_state = "interdiction_lens_inactive"
|
||||
disabled = TRUE
|
||||
update_current_glow()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/destructible/clockwork/powered/interdiction_lens/process()
|
||||
. = ..()
|
||||
if(recharging > world.time)
|
||||
return
|
||||
if(disabled)
|
||||
visible_message("<span class='warning'>The writhing tendrils return to the gemstone, which begins to glow with power!</span>")
|
||||
flick("interdiction_lens_recharged", src)
|
||||
disabled = FALSE
|
||||
toggle(0)
|
||||
else
|
||||
if(!check_apc_and_sigils())
|
||||
forced_disable()
|
||||
return
|
||||
var/successfulprocess = FALSE
|
||||
var/power_drained = 0
|
||||
var/list/atoms_to_test = list()
|
||||
for(var/A in spiral_range_turfs(interdiction_range, src))
|
||||
var/turf/T = A
|
||||
for(var/M in T)
|
||||
atoms_to_test |= M
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
var/unconverted_ai = FALSE
|
||||
var/efficiency = get_efficiency_mod()
|
||||
var/rage_modifier = get_efficiency_mod(TRUE)
|
||||
|
||||
for(var/i in GLOB.ai_list)
|
||||
var/mob/living/silicon/ai/AI = i
|
||||
if(AI && AI.stat != DEAD && !is_servant_of_ratvar(AI))
|
||||
unconverted_ai = TRUE
|
||||
|
||||
for(var/M in atoms_to_test)
|
||||
var/atom/movable/A = M
|
||||
if(!A || QDELETED(A) || A == target_apc)
|
||||
continue
|
||||
power_drained += Floor(A.power_drain(TRUE) * efficiency, MIN_CLOCKCULT_POWER)
|
||||
|
||||
if(prob(1 * rage_modifier))
|
||||
to_chat(A, "<span class='neovgre'>\"[text2ratvar(pick(rage_messages))]\"</span>")
|
||||
|
||||
if(prob(100 * (efficiency * efficiency)))
|
||||
if(istype(A, /obj/machinery/camera) && unconverted_ai)
|
||||
var/obj/machinery/camera/C = A
|
||||
if(C.isEmpProof() || !C.status)
|
||||
continue
|
||||
successfulprocess = TRUE
|
||||
if(C.emped)
|
||||
continue
|
||||
C.emp_act(EMP_HEAVY)
|
||||
else if(istype(A, /obj/item/device/radio))
|
||||
var/obj/item/device/radio/O = A
|
||||
successfulprocess = TRUE
|
||||
if(O.emped || !O.on)
|
||||
continue
|
||||
O.emp_act(EMP_HEAVY)
|
||||
else if((isliving(A) && !is_servant_of_ratvar(A)) || istype(A, /obj/structure/closet) || istype(A, /obj/item/storage)) //other things may have radios in them but we don't care
|
||||
for(var/obj/item/device/radio/O in A.GetAllContents())
|
||||
successfulprocess = TRUE
|
||||
if(O.emped || !O.on)
|
||||
continue
|
||||
O.emp_act(EMP_HEAVY)
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
if(power_drained && power_drained >= MIN_CLOCKCULT_POWER && return_power(power_drained))
|
||||
successfulprocess = TRUE
|
||||
playsound(src, 'sound/items/pshoom.ogg', 50 * efficiency, 1, interdiction_range-7, 1)
|
||||
|
||||
if(!successfulprocess)
|
||||
forced_disable()
|
||||
@@ -1,116 +0,0 @@
|
||||
//Tinkerer's cache: Stores components for later use.
|
||||
/obj/structure/destructible/clockwork/cache
|
||||
name = "tinkerer's cache"
|
||||
desc = "A large brass spire with a flaming hole in its center."
|
||||
clockwork_desc = "A brass container capable of storing a large amount of components.\n\
|
||||
Shares components with all other caches and will gradually generate components if near a Clockwork Wall."
|
||||
icon_state = "tinkerers_cache"
|
||||
unanchored_icon = "tinkerers_cache_unwrenched"
|
||||
construction_value = 10
|
||||
break_message = "<span class='warning'>The cache's fire winks out before it falls in on itself!</span>"
|
||||
max_integrity = 80
|
||||
light_color = "#C2852F"
|
||||
var/wall_generation_cooldown
|
||||
var/turf/closed/wall/clockwork/linkedwall //if we've got a linked wall and are producing
|
||||
var/static/linked_caches = 0 //how many caches are linked to walls; affects how fast components are produced
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
GLOB.clockwork_caches++
|
||||
update_slab_info()
|
||||
set_light(2, 0.7)
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/Destroy()
|
||||
GLOB.clockwork_caches--
|
||||
update_slab_info()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(linkedwall)
|
||||
linked_caches--
|
||||
linkedwall.linkedcache = null
|
||||
linkedwall = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/process()
|
||||
if(!anchored)
|
||||
if(linkedwall)
|
||||
linked_caches--
|
||||
linkedwall.linkedcache = null
|
||||
linkedwall = null
|
||||
return
|
||||
for(var/turf/closed/wall/clockwork/C in range(4, src))
|
||||
if(!C.linkedcache && !linkedwall)
|
||||
linked_caches++
|
||||
C.linkedcache = src
|
||||
linkedwall = C
|
||||
wall_generation_cooldown = world.time + get_production_time()
|
||||
visible_message("<span class='warning'>[src] starts to whirr in the presence of [C]...</span>")
|
||||
break
|
||||
if(linkedwall && wall_generation_cooldown <= world.time)
|
||||
wall_generation_cooldown = world.time + get_production_time()
|
||||
var/component_id = generate_cache_component(null, src)
|
||||
playsound(linkedwall, 'sound/magic/clockwork/fellowship_armory.ogg', rand(15, 20), 1, -3, 1, 1)
|
||||
visible_message("<span class='[get_component_span(component_id)]'>Something</span><span class='warning'> cl[pick("ank", "ink", "unk", "ang")]s around inside of [src]...</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/attackby(obj/item/I, mob/living/user, params)
|
||||
if(!is_servant_of_ratvar(user))
|
||||
return ..()
|
||||
if(istype(I, /obj/item/clockwork/component))
|
||||
var/obj/item/clockwork/component/C = I
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='warning'>[src] needs to be secured to place [C] into it!</span>")
|
||||
else
|
||||
GLOB.clockwork_component_cache[C.component_id]++
|
||||
update_slab_info()
|
||||
to_chat(user, "<span class='notice'>You add [C] to [src].</span>")
|
||||
user.drop_item()
|
||||
qdel(C)
|
||||
return 1
|
||||
else if(istype(I, /obj/item/clockwork/slab))
|
||||
var/obj/item/clockwork/slab/S = I
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='warning'>[src] needs to be secured to offload your slab's components into it!</span>")
|
||||
else
|
||||
for(var/i in S.stored_components)
|
||||
GLOB.clockwork_component_cache[i] += S.stored_components[i]
|
||||
S.stored_components[i] = 0
|
||||
update_slab_info()
|
||||
user.visible_message("<span class='notice'>[user] empties [S] into [src].</span>", "<span class='notice'>You offload your slab's components into [src].</span>")
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/update_anchored(mob/user, do_damage)
|
||||
..()
|
||||
if(anchored)
|
||||
set_light(2, 0.7)
|
||||
else
|
||||
set_light(0)
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/attack_hand(mob/living/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user))
|
||||
if(linkedwall)
|
||||
if(wall_generation_cooldown > world.time)
|
||||
var/temp_time = (wall_generation_cooldown - world.time) * 0.1
|
||||
to_chat(user, "<span class='alloy'>[src] will produce a component in <b>[temp_time]</b> second[temp_time == 1 ? "":"s"].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='brass'>[src] is about to produce a component!</span>")
|
||||
else if(anchored)
|
||||
to_chat(user, "<span class='alloy'>[src] is unlinked! Construct a Clockwork Wall nearby to generate components!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='alloy'>[src] needs to be secured to generate components!</span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/examine(mob/user)
|
||||
..()
|
||||
if(is_servant_of_ratvar(user) || isobserver(user))
|
||||
if(linkedwall)
|
||||
to_chat(user, "<span class='brass'>It is linked to a Clockwork Wall and will generate a component every <b>[DisplayTimeText(get_production_time())]</b>!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='alloy'>It is unlinked! Construct a Clockwork Wall nearby to generate components!</span>")
|
||||
to_chat(user, "<b>Stored components:</b>")
|
||||
for(var/i in GLOB.clockwork_component_cache)
|
||||
to_chat(user, "[get_component_icon(i)] <span class='[get_component_span(i)]_small'><i>[get_component_name(i)][i != REPLICANT_ALLOY ? "s":""]:</i> <b>[GLOB.clockwork_component_cache[i]]</b></span>")
|
||||
|
||||
/obj/structure/destructible/clockwork/cache/proc/get_production_time()
|
||||
return (CACHE_PRODUCTION_TIME + (ACTIVE_CACHE_SLOWDOWN * linked_caches)) * get_efficiency_mod(TRUE)
|
||||
@@ -1,230 +0,0 @@
|
||||
#define DOM_BLOCKED_SPAM_CAP 6
|
||||
#define DOM_REQUIRED_TURFS 30
|
||||
#define DOM_HULK_HITS_REQUIRED 10
|
||||
|
||||
/obj/machinery/dominator
|
||||
name = "dominator"
|
||||
desc = "A visibly sinister device. Looks like you can break it if you hit it enough."
|
||||
icon = 'icons/obj/machines/dominator.dmi'
|
||||
icon_state = "dominator"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
layer = HIGH_OBJ_LAYER
|
||||
max_integrity = 300
|
||||
integrity_failure = 100
|
||||
armor = list(melee = 20, bullet = 50, laser = 50, energy = 50, bomb = 10, bio = 100, rad = 100, fire = 10, acid = 70)
|
||||
var/datum/gang/gang
|
||||
var/operating = FALSE //false=standby or broken, true=takeover
|
||||
var/warned = FALSE //if this device has set off the warning at <3 minutes yet
|
||||
var/spam_prevention = DOM_BLOCKED_SPAM_CAP //first message is immediate
|
||||
var/datum/effect_system/spark_spread/spark_system
|
||||
var/obj/effect/countdown/dominator/countdown
|
||||
|
||||
/obj/machinery/dominator/hulk_damage()
|
||||
return (max_integrity - integrity_failure) / DOM_HULK_HITS_REQUIRED
|
||||
|
||||
/proc/dominator_excessive_walls(atom/A)
|
||||
var/open = FALSE
|
||||
for(var/turf/T in view(3, A))
|
||||
if(!isclosedturf(T))
|
||||
open++
|
||||
if(open < DOM_REQUIRED_TURFS)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/dominator/tesla_act()
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/dominator/Initialize()
|
||||
. = ..()
|
||||
set_light(2)
|
||||
GLOB.poi_list |= src
|
||||
spark_system = new
|
||||
spark_system.set_up(5, TRUE, src)
|
||||
countdown = new(src)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/dominator/examine(mob/user)
|
||||
..()
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
|
||||
var/time
|
||||
if(gang && gang.is_dominating)
|
||||
time = gang.domination_time_remaining()
|
||||
if(time > 0)
|
||||
to_chat(user, "<span class='notice'>Hostile Takeover in progress. Estimated [time] seconds remain.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Hostile Takeover of [station_name()] successful. Have a great day.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>System on standby.</span>")
|
||||
to_chat(user, "<span class='danger'>System Integrity: [round((obj_integrity/max_integrity)*100,1)]%</span>")
|
||||
|
||||
/obj/machinery/dominator/process()
|
||||
..()
|
||||
if(gang && gang.is_dominating)
|
||||
var/time_remaining = gang.domination_time_remaining()
|
||||
if(time_remaining > 0)
|
||||
if(dominator_excessive_walls(src))
|
||||
gang.domination_timer += 20
|
||||
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
|
||||
if(spam_prevention < DOM_BLOCKED_SPAM_CAP)
|
||||
spam_prevention++
|
||||
else
|
||||
gang.message_gangtools("Warning: There are too many walls around your gang's dominator, its signal is being blocked!")
|
||||
say("Error: Takeover signal is currently blocked! There are too many walls within 3 standard units of this device.")
|
||||
spam_prevention = 0
|
||||
return
|
||||
. = TRUE
|
||||
playsound(loc, 'sound/items/timer.ogg', 10, 0)
|
||||
if(!warned && (time_remaining < 180))
|
||||
warned = TRUE
|
||||
var/area/domloc = get_area(loc)
|
||||
gang.message_gangtools("Less than 3 minutes remains in hostile takeover. Defend your dominator at [domloc.map_name]!")
|
||||
for(var/datum/gang/G in SSticker.mode.gangs)
|
||||
if(G != gang)
|
||||
G.message_gangtools("WARNING: [gang.name] Gang takeover imminent. Their dominator at [domloc.map_name] must be destroyed!",1,1)
|
||||
|
||||
if(!.)
|
||||
STOP_PROCESSING(SSmachines, src)
|
||||
|
||||
/obj/machinery/dominator/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(damage_amount)
|
||||
playsound(src, 'sound/effects/bang.ogg', 50, 1)
|
||||
else
|
||||
playsound(loc, 'sound/weapons/tap.ogg', 50, 1)
|
||||
if(BURN)
|
||||
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
|
||||
|
||||
/obj/machinery/dominator/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1)
|
||||
. = ..()
|
||||
if(.)
|
||||
if(obj_integrity/max_integrity > 0.66)
|
||||
if(prob(damage_amount*2))
|
||||
spark_system.start()
|
||||
else if(!(stat & BROKEN))
|
||||
spark_system.start()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/dominator/update_icon()
|
||||
cut_overlays()
|
||||
if(!(stat & BROKEN))
|
||||
icon_state = "dominator-active"
|
||||
if(operating)
|
||||
var/mutable_appearance/dominator_overlay = mutable_appearance('icons/obj/machines/dominator.dmi', "dominator-overlay")
|
||||
if(gang)
|
||||
dominator_overlay.color = gang.color_hex
|
||||
add_overlay(dominator_overlay)
|
||||
else
|
||||
icon_state = "dominator"
|
||||
if(obj_integrity/max_integrity < 0.66)
|
||||
add_overlay("damage")
|
||||
else
|
||||
icon_state = "dominator-broken"
|
||||
|
||||
/obj/machinery/dominator/obj_break(damage_flag)
|
||||
if(!(stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1))
|
||||
set_broken()
|
||||
|
||||
/obj/machinery/dominator/deconstruct(disassembled = TRUE)
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
if(!(stat & BROKEN))
|
||||
set_broken()
|
||||
new /obj/item/stack/sheet/plasteel(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user)
|
||||
add_fingerprint(user)
|
||||
..()
|
||||
|
||||
/obj/machinery/dominator/proc/set_broken()
|
||||
if(gang)
|
||||
gang.is_dominating = FALSE
|
||||
|
||||
var/takeover_in_progress = 0
|
||||
for(var/datum/gang/G in SSticker.mode.gangs)
|
||||
if(G.is_dominating)
|
||||
takeover_in_progress = 1
|
||||
break
|
||||
if(!takeover_in_progress)
|
||||
var/was_stranded = SSshuttle.emergency.mode == SHUTTLE_STRANDED
|
||||
SSshuttle.clearHostileEnvironment(src)
|
||||
if(!was_stranded)
|
||||
priority_announce("All hostile activity within station systems has ceased.","Network Alert")
|
||||
|
||||
if(get_security_level() == "delta")
|
||||
set_security_level("red")
|
||||
|
||||
gang.message_gangtools("Hostile takeover cancelled: Dominator is no longer operational.[gang.dom_attempts ? " You have [gang.dom_attempts] attempt remaining." : " The station network will have likely blocked any more attempts by us."]",1,1)
|
||||
|
||||
set_light(0)
|
||||
operating = FALSE
|
||||
stat |= BROKEN
|
||||
update_icon()
|
||||
STOP_PROCESSING(SSmachines, src)
|
||||
|
||||
/obj/machinery/dominator/Destroy()
|
||||
if(!(stat & BROKEN))
|
||||
set_broken()
|
||||
GLOB.poi_list.Remove(src)
|
||||
gang = null
|
||||
QDEL_NULL(spark_system)
|
||||
QDEL_NULL(countdown)
|
||||
STOP_PROCESSING(SSmachines, src)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/dominator/emp_act(severity)
|
||||
take_damage(100, BURN, "energy", 0)
|
||||
..()
|
||||
|
||||
/obj/machinery/dominator/attack_hand(mob/user)
|
||||
if(operating || (stat & BROKEN))
|
||||
examine(user)
|
||||
return
|
||||
|
||||
var/datum/gang/tempgang
|
||||
|
||||
if(user.mind in SSticker.mode.get_all_gangsters())
|
||||
tempgang = user.mind.gang_datum
|
||||
else
|
||||
examine(user)
|
||||
return
|
||||
|
||||
if(tempgang.is_dominating)
|
||||
to_chat(user, "<span class='warning'>Error: Hostile Takeover is already in progress.</span>")
|
||||
return
|
||||
|
||||
if(!tempgang.dom_attempts)
|
||||
to_chat(user, "<span class='warning'>Error: Unable to breach station network. Firewall has logged our signature and is blocking all further attempts.</span>")
|
||||
return
|
||||
|
||||
var/time = round(determine_domination_time(tempgang)/60,0.1)
|
||||
if(alert(user,"With [round((tempgang.territory.len/GLOB.start_state.num_territories)*100, 1)]% station control, a takeover will require [time] minutes.\nYour gang will be unable to gain influence while it is active.\nThe entire station will likely be alerted to it once it starts.\nYou have [tempgang.dom_attempts] attempt(s) remaining. Are you ready?","Confirm","Ready","Later") == "Ready")
|
||||
if((tempgang.is_dominating) || !tempgang.dom_attempts || !in_range(src, user) || !isturf(loc))
|
||||
return 0
|
||||
|
||||
var/area/A = get_area(loc)
|
||||
var/locname = A.map_name
|
||||
|
||||
gang = tempgang
|
||||
gang.dom_attempts --
|
||||
priority_announce("Network breach detected in [locname]. The [gang.name] Gang is attempting to seize control of the station!","Network Alert")
|
||||
gang.domination()
|
||||
SSshuttle.registerHostileEnvironment(src)
|
||||
name = "[gang.name] Gang [name]"
|
||||
operating = TRUE
|
||||
update_icon()
|
||||
|
||||
countdown.color = gang.color_hex
|
||||
countdown.start()
|
||||
|
||||
set_light(3)
|
||||
START_PROCESSING(SSmachines, src)
|
||||
|
||||
gang.message_gangtools("Hostile takeover in progress: Estimated [time] minutes until victory.[gang.dom_attempts ? "" : " This is your final attempt."]")
|
||||
for(var/datum/gang/G in SSticker.mode.gangs)
|
||||
if(G != gang)
|
||||
G.message_gangtools("Enemy takeover attempt detected in [locname]: Estimated [time] minutes until our defeat.",1,1)
|
||||
@@ -1,359 +0,0 @@
|
||||
//gang.dm
|
||||
//Gang War Game Mode
|
||||
|
||||
GLOBAL_LIST_INIT(gang_name_pool, list("Clandestine", "Prima", "Zero-G", "Max", "Blasto", "Waffle", "North", "Omni", "Newton", "Cyber", "Donk", "Gene", "Gib", "Tunnel", "Diablo", "Psyke", "Osiron", "Sirius", "Sleeping Carp"))
|
||||
GLOBAL_LIST_INIT(gang_colors_pool, list("red","orange","yellow","green","blue","purple", "white"))
|
||||
GLOBAL_LIST_INIT(gang_outfit_pool, list(/obj/item/clothing/suit/jacket/leather, /obj/item/clothing/suit/jacket/leather/overcoat, /obj/item/clothing/suit/jacket/puffer, /obj/item/clothing/suit/jacket/miljacket, /obj/item/clothing/suit/jacket/puffer, /obj/item/clothing/suit/pirate, /obj/item/clothing/suit/poncho, /obj/item/clothing/suit/apron/overalls, /obj/item/clothing/suit/jacket/letterman))
|
||||
|
||||
/datum/game_mode
|
||||
var/list/datum/gang/gangs = list()
|
||||
var/datum/gang_points/gang_points
|
||||
|
||||
/proc/is_gangster(var/mob/living/M)
|
||||
return istype(M) && M.mind && M.mind.gang_datum
|
||||
|
||||
/proc/is_in_gang(var/mob/living/M, var/gang_type)
|
||||
if(!is_gangster(M) || !gang_type)
|
||||
return 0
|
||||
var/datum/gang/G = M.mind.gang_datum
|
||||
if(G.name == gang_type)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/game_mode/gang
|
||||
name = "gang war"
|
||||
config_tag = "gang"
|
||||
antag_flag = ROLE_GANG
|
||||
restricted_jobs = list("Security Officer", "Warden", "Detective", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer")
|
||||
required_players = 20
|
||||
required_enemies = 2
|
||||
recommended_enemies = 2
|
||||
enemy_minimum_age = 14
|
||||
|
||||
announce_span = "danger"
|
||||
announce_text = "A violent turf war has erupted on the station!\n\
|
||||
<span class='danger'>Gangsters</span>: Take over the station with a dominator.\n\
|
||||
<span class='notice'>Crew</span>: Prevent the gangs from expanding and initiating takeover."
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//Gets the round setup, cancelling if there's not enough players at the start//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/datum/game_mode/gang/pre_setup()
|
||||
if(config.protect_roles_from_antagonist)
|
||||
restricted_jobs += protected_jobs
|
||||
|
||||
if(config.protect_assistant_from_antagonist)
|
||||
restricted_jobs += "Assistant"
|
||||
|
||||
//Spawn more bosses depending on server population
|
||||
var/gangs_to_create = 2
|
||||
if(prob(num_players() * 2))
|
||||
gangs_to_create ++
|
||||
|
||||
for(var/i=1 to gangs_to_create)
|
||||
if(!antag_candidates.len)
|
||||
break
|
||||
|
||||
//Create the gang
|
||||
var/datum/gang/G = new()
|
||||
gangs += G
|
||||
|
||||
//Now assign a boss for the gang
|
||||
for(var/n in 1 to 3)
|
||||
var/datum/mind/boss = pick(antag_candidates)
|
||||
antag_candidates -= boss
|
||||
G.bosses[boss] = GANGSTER_BOSS_STARTING_INFLUENCE
|
||||
boss.gang_datum = G
|
||||
var/title
|
||||
if(n == 1)
|
||||
title = "Boss"
|
||||
else
|
||||
title = "Lieutenant"
|
||||
boss.special_role = "[G.name] Gang [title]"
|
||||
boss.restricted_roles = restricted_jobs
|
||||
log_game("[boss.key] has been selected as the [title] for the [G.name] Gang")
|
||||
|
||||
if(gangs.len < 2) //Need at least two gangs
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
/datum/game_mode/gang/post_setup()
|
||||
set waitfor = FALSE
|
||||
..()
|
||||
sleep(rand(10,100))
|
||||
for(var/datum/gang/G in gangs)
|
||||
for(var/datum/mind/boss_mind in G.bosses)
|
||||
G.bosses[boss_mind] = GANGSTER_BOSS_STARTING_INFLUENCE //Force influence to be put on it.
|
||||
G.add_gang_hud(boss_mind)
|
||||
forge_gang_objectives(boss_mind)
|
||||
greet_gang(boss_mind)
|
||||
equip_gang(boss_mind.current,G)
|
||||
modePlayer += boss_mind
|
||||
|
||||
|
||||
/datum/game_mode/proc/forge_gang_objectives(datum/mind/boss_mind)
|
||||
var/datum/objective/rival_obj = new
|
||||
rival_obj.owner = boss_mind
|
||||
rival_obj.explanation_text = "Be the first gang to successfully takeover the station with a Dominator."
|
||||
boss_mind.objectives += rival_obj
|
||||
|
||||
/datum/game_mode/proc/greet_gang(datum/mind/boss_mind, you_are=1)
|
||||
if (you_are)
|
||||
to_chat(boss_mind.current, "<FONT size=3 color=red><B>You are the Boss of the [boss_mind.gang_datum.name] Gang!</B></FONT>")
|
||||
boss_mind.announce_objectives()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//This equips the bosses with their gear, and makes the clown not clumsy//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/datum/game_mode/proc/equip_gang(mob/living/carbon/human/mob, gang)
|
||||
if(!istype(mob))
|
||||
return
|
||||
|
||||
if (mob.mind)
|
||||
if (mob.mind.assigned_role == "Clown")
|
||||
to_chat(mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
mob.dna.remove_mutation(CLOWNMUT)
|
||||
|
||||
var/obj/item/device/gangtool/gangtool = new(mob)
|
||||
var/obj/item/pen/gang/T = new(mob)
|
||||
var/obj/item/toy/crayon/spraycan/gang/SC = new(mob,gang)
|
||||
var/obj/item/clothing/glasses/hud/security/chameleon/C = new(mob,gang)
|
||||
|
||||
var/list/slots = list (
|
||||
"backpack" = slot_in_backpack,
|
||||
"left pocket" = slot_l_store,
|
||||
"right pocket" = slot_r_store
|
||||
)
|
||||
|
||||
. = 0
|
||||
|
||||
var/where = mob.equip_in_one_of_slots(gangtool, slots)
|
||||
if (!where)
|
||||
to_chat(mob, "Your Syndicate benefactors were unfortunately unable to get you a Gangtool.")
|
||||
. += 1
|
||||
else
|
||||
gangtool.register_device(mob)
|
||||
to_chat(mob, "The <b>Gangtool</b> in your [where] will allow you to purchase weapons and equipment, send messages to your gang, and recall the emergency shuttle from anywhere on the station.")
|
||||
to_chat(mob, "As the gang boss, you can also promote your gang members to <b>lieutenant</b>. Unlike regular gangsters, Lieutenants cannot be deconverted and are able to use recruitment pens and gangtools.")
|
||||
|
||||
var/where2 = mob.equip_in_one_of_slots(T, slots)
|
||||
if (!where2)
|
||||
to_chat(mob, "Your Syndicate benefactors were unfortunately unable to get you a recruitment pen to start.")
|
||||
. += 1
|
||||
else
|
||||
to_chat(mob, "The <b>recruitment pen</b> in your [where2] will help you get your gang started. Stab unsuspecting crew members with it to recruit them.")
|
||||
|
||||
var/where3 = mob.equip_in_one_of_slots(SC, slots)
|
||||
if (!where3)
|
||||
to_chat(mob, "Your Syndicate benefactors were unfortunately unable to get you a territory spraycan to start.")
|
||||
. += 1
|
||||
else
|
||||
to_chat(mob, "The <b>territory spraycan</b> in your [where3] can be used to claim areas of the station for your gang. The more territory your gang controls, the more influence you get. All gangsters can use these, so distribute them to grow your influence faster.")
|
||||
|
||||
var/where4 = mob.equip_in_one_of_slots(C, slots)
|
||||
if (!where4)
|
||||
to_chat(mob, "Your Syndicate benefactors were unfortunately unable to get you a chameleon security HUD.")
|
||||
. += 1
|
||||
else
|
||||
to_chat(mob, "The <b>chameleon security HUD</b> in your [where4] will help you keep track of who is mindshield-implanted, and unable to be recruited.")
|
||||
return .
|
||||
|
||||
|
||||
///////////////////////////////////////////
|
||||
//Deals with converting players to a gang//
|
||||
///////////////////////////////////////////
|
||||
/datum/game_mode/proc/add_gangster(datum/mind/gangster_mind, datum/gang/G, check = 1)
|
||||
if(!G || (gangster_mind in get_all_gangsters()) || (gangster_mind.enslaved_to && !is_gangster(gangster_mind.enslaved_to)))
|
||||
if(is_in_gang(gangster_mind.current, G.name) && !(gangster_mind in get_gang_bosses()))
|
||||
return 3
|
||||
return 0
|
||||
if(check && gangster_mind.current.isloyal()) //Check to see if the potential gangster is implanted
|
||||
return 1
|
||||
G.gangsters[gangster_mind] = GANGSTER_SOLDIER_STARTING_INFLUENCE
|
||||
gangster_mind.gang_datum = G
|
||||
if(check)
|
||||
if(iscarbon(gangster_mind.current))
|
||||
var/mob/living/carbon/carbon_mob = gangster_mind.current
|
||||
carbon_mob.silent = max(carbon_mob.silent, 5)
|
||||
carbon_mob.flash_act(1, 1)
|
||||
gangster_mind.current.Stun(100)
|
||||
if(G.is_deconvertible)
|
||||
to_chat(gangster_mind.current, "<FONT size=3 color=red><B>You are now a member of the [G.name] Gang!</B></FONT>")
|
||||
to_chat(gangster_mind.current, "<font color='red'>Help your bosses take over the station by claiming territory with <b>special spraycans</b> only they can provide. Simply spray on any unclaimed area of the station.</font>")
|
||||
to_chat(gangster_mind.current, "<font color='red'>Their ultimate objective is to take over the station with a Dominator machine.</font>")
|
||||
to_chat(gangster_mind.current, "<font color='red'>You can identify your bosses by their <b>large, bright [G.color] \[G\] icon</b>.</font>")
|
||||
gangster_mind.store_memory("You are a member of the [G.name] Gang!")
|
||||
gangster_mind.current.log_message("<font color='red'>Has been converted to the [G.name] Gang!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
gangster_mind.special_role = "[G.name] Gangster"
|
||||
|
||||
G.add_gang_hud(gangster_mind)
|
||||
if(jobban_isbanned(gangster_mind.current, ROLE_GANG))
|
||||
INVOKE_ASYNC(src, /datum/game_mode.proc/replace_jobbaned_player, gangster_mind.current, ROLE_GANG, ROLE_GANG)
|
||||
return 2
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//Deals with players reverting to neutral (Not a gangster anymore)//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
/datum/game_mode/proc/remove_gangster(datum/mind/gangster_mind, beingborged, silent, remove_bosses=0)
|
||||
var/datum/gang/gang = gangster_mind.gang_datum
|
||||
for(var/obj/O in gangster_mind.current.contents)
|
||||
if(istype(O, /obj/item/device/gangtool/soldier))
|
||||
qdel(O)
|
||||
|
||||
if(!gang)
|
||||
return 0
|
||||
|
||||
var/removed
|
||||
|
||||
for(var/datum/gang/G in gangs)
|
||||
if(!G.is_deconvertible && !remove_bosses)
|
||||
return 0
|
||||
if(gangster_mind in G.gangsters)
|
||||
G.reclaim_points(G.gangsters[gangster_mind])
|
||||
G.gangsters -= gangster_mind
|
||||
removed = 1
|
||||
if(remove_bosses && (gangster_mind in G.bosses))
|
||||
G.reclaim_points(G.bosses[gangster_mind])
|
||||
G.bosses -= gangster_mind
|
||||
removed = 1
|
||||
if(G.tags_by_mind[gangster_mind] && islist(G.tags_by_mind[gangster_mind]))
|
||||
var/list/tags_cache = G.tags_by_mind[gangster_mind]
|
||||
for(var/v in tags_cache)
|
||||
var/obj/effect/decal/cleanable/crayon/gang/c = v
|
||||
c.set_mind_owner(null)
|
||||
G.tags_by_mind -= gangster_mind
|
||||
|
||||
if(!removed)
|
||||
return 0
|
||||
|
||||
|
||||
gangster_mind.special_role = null
|
||||
gangster_mind.gang_datum = null
|
||||
|
||||
if(silent < 2)
|
||||
gangster_mind.current.log_message("<font color='red'>Has reformed and defected from the [gang.name] Gang!</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
|
||||
if(beingborged)
|
||||
if(!silent)
|
||||
gangster_mind.current.visible_message("The frame beeps contentedly from the MMI before initalizing it.")
|
||||
to_chat(gangster_mind.current, "<FONT size=3 color=red><B>The frame's firmware detects and deletes your criminal behavior! You are no longer a gangster!</B></FONT>")
|
||||
message_admins("[ADMIN_LOOKUPFLW(gangster_mind.current)] has been borged while being a member of the [gang.name] Gang. They are no longer a gangster.")
|
||||
else
|
||||
if(!silent)
|
||||
gangster_mind.current.Unconscious(100)
|
||||
gangster_mind.current.visible_message("<FONT size=3><B>[gangster_mind.current] looks like they've given up the life of crime!<B></font>")
|
||||
to_chat(gangster_mind.current, "<FONT size=3 color=red><B>You have been reformed! You are no longer a gangster!</B><BR>You try as hard as you can, but you can't seem to recall any of the identities of your former gangsters...</FONT>")
|
||||
gangster_mind.memory = ""
|
||||
|
||||
gang.remove_gang_hud(gangster_mind)
|
||||
return 1
|
||||
|
||||
////////////////
|
||||
//Helper Procs//
|
||||
////////////////
|
||||
|
||||
/datum/game_mode/proc/get_all_gangsters()
|
||||
var/list/all_gangsters = list()
|
||||
all_gangsters += get_gangsters()
|
||||
all_gangsters += get_gang_bosses()
|
||||
return all_gangsters
|
||||
|
||||
/datum/game_mode/proc/get_gangsters()
|
||||
var/list/gangsters = list()
|
||||
for(var/datum/gang/G in gangs)
|
||||
gangsters += G.gangsters
|
||||
return gangsters
|
||||
|
||||
/datum/game_mode/proc/get_gang_bosses()
|
||||
var/list/gang_bosses = list()
|
||||
for(var/datum/gang/G in gangs)
|
||||
gang_bosses += G.bosses
|
||||
return gang_bosses
|
||||
|
||||
/datum/game_mode/proc/shuttle_check()
|
||||
if(SSshuttle.emergencyNoRecall)
|
||||
return
|
||||
var/alive = 0
|
||||
for(var/mob/living/L in GLOB.player_list)
|
||||
if(L.stat != DEAD)
|
||||
alive++
|
||||
|
||||
if((alive < (GLOB.joined_player_list.len * 0.4)) && ((SSshuttle.emergency.timeLeft(1) > (SSshuttle.emergencyCallTime * 0.4))))
|
||||
|
||||
SSshuttle.emergencyNoRecall = TRUE
|
||||
SSshuttle.emergency.request(null, set_coefficient = 0.4)
|
||||
priority_announce("Catastrophic casualties detected: crisis shuttle protocols activated - jamming recall signals across all frequencies.")
|
||||
|
||||
/proc/determine_domination_time(var/datum/gang/G)
|
||||
return max(180,480 - (round((G.territory.len/GLOB.start_state.num_territories)*100, 1) * 9))
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//Announces the end of the game with all relavent information stated//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
/datum/game_mode/proc/auto_declare_completion_gang(datum/gang/winner)
|
||||
if(!gangs.len)
|
||||
return
|
||||
if(!winner)
|
||||
to_chat(world, "<span class='redtext'>The station was [station_was_nuked ? "destroyed!" : "evacuated before a gang could claim it! The station wins!"]</span><br>")
|
||||
SSticker.mode_result = "loss - gangs failed takeover"
|
||||
|
||||
SSticker.news_report = GANG_LOSS
|
||||
else
|
||||
to_chat(world, "<span class='redtext'>The [winner.name] Gang successfully performed a hostile takeover of the station!</span><br>")
|
||||
SSticker.mode_result = "win - gang domination complete"
|
||||
|
||||
SSticker.news_report = GANG_TAKEOVER
|
||||
|
||||
for(var/datum/gang/G in gangs)
|
||||
var/text = "<b>The [G.name] Gang was [winner==G ? "<span class='greenannounce'>victorious</span>" : "<span class='boldannounce'>defeated</span>"] with [round((G.territory.len/GLOB.start_state.num_territories)*100, 1)]% control of the station!</b>"
|
||||
text += "<br>The [G.name] Gang Bosses were:"
|
||||
for(var/datum/mind/boss in G.bosses)
|
||||
text += printplayer(boss, 1)
|
||||
text += "<br>The [G.name] Gangsters were:"
|
||||
for(var/datum/mind/gangster in G.gangsters)
|
||||
text += printplayer(gangster, 1)
|
||||
text += "<br>"
|
||||
to_chat(world, text)
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
//Handles influence, territories, and the victory checks//
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
/datum/gang_points
|
||||
var/next_point_interval = 1800
|
||||
var/next_point_time
|
||||
|
||||
/datum/gang_points/New()
|
||||
next_point_time = world.time + next_point_interval
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/gang_points/process(seconds)
|
||||
var/list/winners = list() //stores the winners if there are any
|
||||
|
||||
for(var/datum/gang/G in SSticker.mode.gangs)
|
||||
if(world.time > next_point_time)
|
||||
G.income()
|
||||
|
||||
if(G.is_dominating)
|
||||
if(G.domination_time_remaining() < 0)
|
||||
winners += G
|
||||
|
||||
if(world.time > next_point_time)
|
||||
next_point_time = world.time + next_point_interval
|
||||
|
||||
if(winners.len)
|
||||
if(winners.len > 1) //Edge Case: If more than one dominator complete at the same time
|
||||
for(var/datum/gang/G in winners)
|
||||
G.domination(0.5)
|
||||
priority_announce("Multiple station takeover attempts have made simultaneously. Conflicting takeover attempts appears to have restarted.","Network Alert")
|
||||
else
|
||||
var/datum/gang/G = winners[1]
|
||||
G.is_dominating = FALSE
|
||||
SSticker.mode.explosion_in_progress = 1
|
||||
SSticker.station_explosion_cinematic(1,"gang war", null)
|
||||
SSticker.mode.explosion_in_progress = 0
|
||||
SSticker.force_ending = TRUE
|
||||
|
||||
@@ -1,333 +0,0 @@
|
||||
//gang_datum.dm
|
||||
//Datum-based gangs
|
||||
|
||||
/datum/gang
|
||||
var/name = "ERROR"
|
||||
var/color = "white"
|
||||
var/color_hex = "#FFFFFF"
|
||||
var/list/datum/mind/gangsters = list() //gang B Members
|
||||
var/list/datum/mind/bosses = list() //gang A Bosses
|
||||
var/list/obj/item/device/gangtool/gangtools = list()
|
||||
var/list/tags_by_mind = list() //Assoc list in format of tags_by_mind[mind_of_gangster] = list(tag1, tag2, tag3) where tags are the actual object decals.
|
||||
var/style
|
||||
var/fighting_style = "normal"
|
||||
var/list/territory = list()
|
||||
var/list/territory_new = list()
|
||||
var/list/territory_lost = list()
|
||||
var/recalls = 1
|
||||
var/dom_attempts = 2
|
||||
var/inner_outfit
|
||||
var/outer_outfit
|
||||
var/datum/atom_hud/antag/gang/ganghud
|
||||
var/is_deconvertible = TRUE //Can you deconvert normal gangsters from the gang
|
||||
|
||||
var/domination_timer
|
||||
var/is_dominating
|
||||
|
||||
var/boss_item_list
|
||||
var/boss_category_list
|
||||
var/static/list/boss_items = list(
|
||||
/datum/gang_item/function/gang_ping,
|
||||
/datum/gang_item/function/recall,
|
||||
|
||||
/datum/gang_item/clothing/under,
|
||||
/datum/gang_item/clothing/suit,
|
||||
/datum/gang_item/clothing/hat,
|
||||
/datum/gang_item/clothing/neck,
|
||||
/datum/gang_item/clothing/shoes,
|
||||
/datum/gang_item/clothing/mask,
|
||||
/datum/gang_item/clothing/hands,
|
||||
/datum/gang_item/clothing/belt,
|
||||
|
||||
/datum/gang_item/weapon/shuriken,
|
||||
/datum/gang_item/weapon/switchblade,
|
||||
/datum/gang_item/weapon/improvised,
|
||||
/datum/gang_item/weapon/ammo/improvised_ammo,
|
||||
/datum/gang_item/weapon/surplus,
|
||||
/datum/gang_item/weapon/ammo/surplus_ammo,
|
||||
/datum/gang_item/weapon/pistol,
|
||||
/datum/gang_item/weapon/ammo/pistol_ammo,
|
||||
/datum/gang_item/weapon/sniper,
|
||||
/datum/gang_item/weapon/ammo/sniper_ammo,
|
||||
/datum/gang_item/weapon/machinegun,
|
||||
/datum/gang_item/weapon/uzi,
|
||||
/datum/gang_item/weapon/ammo/uzi_ammo,
|
||||
/datum/gang_item/equipment/sharpener,
|
||||
/datum/gang_item/equipment/spraycan,
|
||||
/datum/gang_item/equipment/emp,
|
||||
/datum/gang_item/equipment/c4,
|
||||
/datum/gang_item/equipment/frag,
|
||||
/datum/gang_item/equipment/stimpack,
|
||||
/datum/gang_item/equipment/implant_breaker,
|
||||
/datum/gang_item/equipment/wetwork_boots,
|
||||
/datum/gang_item/equipment/pen,
|
||||
/datum/gang_item/equipment/dominator
|
||||
)
|
||||
|
||||
var/reg_item_list
|
||||
var/reg_category_list
|
||||
var/static/list/soldier_items = list(
|
||||
/datum/gang_item/clothing/under,
|
||||
/datum/gang_item/clothing/suit,
|
||||
/datum/gang_item/clothing/hat,
|
||||
/datum/gang_item/clothing/neck,
|
||||
/datum/gang_item/clothing/shoes,
|
||||
/datum/gang_item/clothing/mask,
|
||||
/datum/gang_item/clothing/hands,
|
||||
/datum/gang_item/clothing/belt,
|
||||
|
||||
/datum/gang_item/weapon/shuriken,
|
||||
/datum/gang_item/weapon/switchblade,
|
||||
/datum/gang_item/weapon/improvised,
|
||||
/datum/gang_item/weapon/ammo/improvised_ammo,
|
||||
/datum/gang_item/weapon/surplus,
|
||||
/datum/gang_item/weapon/ammo/surplus_ammo,
|
||||
/datum/gang_item/weapon/pistol,
|
||||
/datum/gang_item/weapon/ammo/pistol_ammo,
|
||||
/datum/gang_item/weapon/sniper,
|
||||
/datum/gang_item/weapon/ammo/sniper_ammo,
|
||||
/datum/gang_item/weapon/machinegun,
|
||||
/datum/gang_item/weapon/uzi,
|
||||
/datum/gang_item/weapon/ammo/uzi_ammo,
|
||||
/datum/gang_item/equipment/sharpener,
|
||||
/datum/gang_item/equipment/spraycan,
|
||||
/datum/gang_item/equipment/emp,
|
||||
/datum/gang_item/equipment/c4,
|
||||
/datum/gang_item/equipment/frag,
|
||||
/datum/gang_item/equipment/stimpack,
|
||||
/datum/gang_item/equipment/implant_breaker,
|
||||
/datum/gang_item/equipment/wetwork_boots,
|
||||
)
|
||||
|
||||
/datum/gang/New(loc,gangname)
|
||||
if(!GLOB.gang_colors_pool.len)
|
||||
message_admins("WARNING: Maximum number of gangs have been exceeded!")
|
||||
throw EXCEPTION("Maximum number of gangs has been exceeded")
|
||||
return
|
||||
else
|
||||
color = pick(GLOB.gang_colors_pool)
|
||||
GLOB.gang_colors_pool -= color
|
||||
switch(color)
|
||||
if("red")
|
||||
color_hex = "#DA0000"
|
||||
inner_outfit = pick(/obj/item/clothing/under/color/red, /obj/item/clothing/under/lawyer/red)
|
||||
if("orange")
|
||||
color_hex = "#FF9300"
|
||||
inner_outfit = pick(/obj/item/clothing/under/color/orange, /obj/item/clothing/under/geisha)
|
||||
if("yellow")
|
||||
color_hex = "#FFF200"
|
||||
inner_outfit = pick(/obj/item/clothing/under/color/yellow, /obj/item/clothing/under/burial, /obj/item/clothing/under/suit_jacket/tan)
|
||||
if("green")
|
||||
color_hex = "#A8E61D"
|
||||
inner_outfit = pick(/obj/item/clothing/under/color/green, /obj/item/clothing/under/syndicate/camo, /obj/item/clothing/under/suit_jacket/green)
|
||||
if("blue")
|
||||
color_hex = "#00B7EF"
|
||||
inner_outfit = pick(/obj/item/clothing/under/color/blue, /obj/item/clothing/under/suit_jacket/navy)
|
||||
if("purple")
|
||||
color_hex = "#DA00FF"
|
||||
inner_outfit = pick(/obj/item/clothing/under/color/lightpurple, /obj/item/clothing/under/lawyer/purpsuit)
|
||||
if("white")
|
||||
color_hex = "#FFFFFF"
|
||||
inner_outfit = pick(/obj/item/clothing/under/color/white, /obj/item/clothing/under/suit_jacket/white)
|
||||
|
||||
name = (gangname ? gangname : pick(GLOB.gang_name_pool))
|
||||
GLOB.gang_name_pool -= name
|
||||
outer_outfit = pick(GLOB.gang_outfit_pool)
|
||||
ganghud = new()
|
||||
ganghud.color = color_hex
|
||||
log_game("The [name] Gang has been created. Their gang color is [color].")
|
||||
build_item_list()
|
||||
|
||||
/datum/gang/proc/build_item_list()
|
||||
boss_item_list = list()
|
||||
boss_category_list = list()
|
||||
for(var/B in boss_items)
|
||||
var/datum/gang_item/G = new B()
|
||||
boss_item_list[G.id] = G
|
||||
var/list/Cat = boss_category_list[G.category]
|
||||
if(Cat)
|
||||
Cat += G
|
||||
else
|
||||
boss_category_list[G.category] = list(G)
|
||||
|
||||
reg_item_list = list()
|
||||
reg_category_list = list()
|
||||
for(var/S in soldier_items)
|
||||
var/datum/gang_item/G = new S()
|
||||
reg_item_list[G.id] = G
|
||||
var/list/Cat = reg_category_list[G.category]
|
||||
if(Cat)
|
||||
Cat += G
|
||||
else
|
||||
reg_category_list[G.category] = list(G)
|
||||
|
||||
/datum/gang/proc/add_gang_hud(datum/mind/recruit_mind)
|
||||
ganghud.join_hud(recruit_mind.current)
|
||||
SSticker.mode.set_antag_hud(recruit_mind.current, ((recruit_mind in bosses) ? "gang_boss" : "gangster"))
|
||||
|
||||
/datum/gang/proc/remove_gang_hud(datum/mind/defector_mind)
|
||||
ganghud.leave_hud(defector_mind.current)
|
||||
SSticker.mode.set_antag_hud(defector_mind.current, null)
|
||||
|
||||
/datum/gang/proc/domination(modifier=1)
|
||||
set_domination_time(determine_domination_time(src) * modifier)
|
||||
is_dominating = TRUE
|
||||
set_security_level("delta")
|
||||
|
||||
/datum/gang/proc/set_domination_time(d)
|
||||
domination_timer = world.time + (10 * d)
|
||||
|
||||
/datum/gang/proc/domination_time_remaining()
|
||||
var/diff = domination_timer - world.time
|
||||
return diff / 10
|
||||
|
||||
//////////////////////////////////////////// MESSAGING
|
||||
|
||||
|
||||
/datum/gang/proc/message_gangtools(message,beep=1,warning)
|
||||
if(!gangtools.len || !message)
|
||||
return
|
||||
for(var/obj/item/device/gangtool/tool in gangtools)
|
||||
var/mob/living/mob = get(tool.loc, /mob/living)
|
||||
if(mob && mob.mind && mob.stat == CONSCIOUS)
|
||||
if(mob.mind.gang_datum == src)
|
||||
to_chat(mob, "<span class='[warning ? "warning" : "notice"]'>[icon2html(tool, mob)] [message]</span>")
|
||||
return
|
||||
|
||||
|
||||
//////////////////////////////////////////// INCOME
|
||||
|
||||
|
||||
/datum/gang/proc/income()
|
||||
if(!bosses.len)
|
||||
return
|
||||
var/added_names = ""
|
||||
var/lost_names = ""
|
||||
|
||||
SSticker.mode.shuttle_check() // See if its time to start wrapping things up
|
||||
|
||||
//Re-add territories that were reclaimed, so if they got tagged over, they can still earn income if they tag it back before the next status report
|
||||
var/list/reclaimed_territories = territory_new & territory_lost
|
||||
territory |= reclaimed_territories
|
||||
territory_new -= reclaimed_territories
|
||||
territory_lost -= reclaimed_territories
|
||||
|
||||
//Process lost territories
|
||||
for(var/area in territory_lost)
|
||||
if(lost_names != "")
|
||||
lost_names += ", "
|
||||
lost_names += "[territory_lost[area]]"
|
||||
territory -= area
|
||||
|
||||
//Calculate and report influence growth
|
||||
|
||||
//Process new territories
|
||||
for(var/area in territory_new)
|
||||
if(added_names != "")
|
||||
added_names += ", "
|
||||
added_names += "[territory_new[area]]"
|
||||
territory += area
|
||||
|
||||
//Report territory changes
|
||||
var/message = "<b>[src] Gang Status Report:</b>.<BR>*---------*<BR>"
|
||||
message += "<b>[territory_new.len] new territories:</b><br><i>[added_names]</i><br>"
|
||||
message += "<b>[territory_lost.len] territories lost:</b><br><i>[lost_names]</i><br>"
|
||||
//Clear the lists
|
||||
territory_new = list()
|
||||
territory_lost = list()
|
||||
var/control = round((territory.len/GLOB.start_state.num_territories)*100, 1)
|
||||
var/sbonus = sqrt(LAZYLEN(territory)) // Bonus given to soldier's for the gang's total territory
|
||||
message += "Your gang now has <b>[control]% control</b> of the station.<BR>*---------*<BR>"
|
||||
if(is_dominating)
|
||||
var/seconds_remaining = domination_time_remaining()
|
||||
var/new_time = max(180, seconds_remaining - (territory.len * 2))
|
||||
if(new_time < seconds_remaining)
|
||||
message += "Takeover shortened by [seconds_remaining - new_time] seconds for defending [territory.len] territories.<BR>"
|
||||
set_domination_time(new_time)
|
||||
message += "<b>[seconds_remaining] seconds remain</b> in hostile takeover.<BR>"
|
||||
else
|
||||
pay_territory_income_to_bosses()
|
||||
pay_territory_income_to_soldiers(sbonus)
|
||||
pay_all_clothing_bonuses()
|
||||
announce_all_influence()
|
||||
|
||||
/datum/gang/proc/pay_all_clothing_bonuses()
|
||||
for(var/datum/mind/mind in gangsters|bosses)
|
||||
pay_clothing_bonus(mind)
|
||||
|
||||
/datum/gang/proc/pay_clothing_bonus(var/datum/mind/gangsta)
|
||||
var/mob/living/carbon/human/gangbanger = gangsta.current
|
||||
. = 0
|
||||
if(!istype(gangbanger) || gangbanger.stat == DEAD) //Dead gangsters aren't influential at all!
|
||||
return 0
|
||||
var/static/inner = inner_outfit
|
||||
var/static/outer = outer_outfit
|
||||
for(var/obj/item/C in gangbanger.contents)
|
||||
if(C.type == inner_outfit)
|
||||
. += 2
|
||||
continue
|
||||
else if(C.type == outer_outfit)
|
||||
. += 2
|
||||
continue
|
||||
. += C.gang_contraband_value()
|
||||
adjust_influence(gangsta, .)
|
||||
if(.)
|
||||
announce_to_mind(gangsta, "<span class='notice'>Your influential choice of clothing has increased your influence by [.] points!</span>")
|
||||
else
|
||||
announce_to_mind(gangsta, "<span class='warning'>Unfortunately, you have not gained any additional influence from your drab, old, boring clothing. Learn to dress like a gangsta, bro!</span>") //Kek
|
||||
|
||||
/datum/gang/proc/pay_soldier_territory_income(datum/mind/soldier, sbonus = 0)
|
||||
. = 0
|
||||
. = max(0,round(3 - gangsters[soldier]/10)) + (sbonus) + (get_soldier_territories(soldier)/2)
|
||||
adjust_influence(soldier, .)
|
||||
|
||||
/datum/gang/proc/get_soldier_territories(datum/mind/soldier)
|
||||
if(!islist(tags_by_mind[soldier])) //They have no tagged territories!
|
||||
return 0
|
||||
var/list/tags = tags_by_mind[soldier]
|
||||
return tags.len
|
||||
|
||||
/datum/gang/proc/pay_territory_income_to_soldiers(sbonus = 0)
|
||||
for(var/datum/mind/soldier in gangsters)
|
||||
var/returned = pay_soldier_territory_income(soldier)
|
||||
if(!returned)
|
||||
announce_to_mind(soldier, "<span class='warning'>You have not gained any influence from territories you personally tagged. Get to work, soldier!</span>")
|
||||
else
|
||||
announce_to_mind(soldier, "<span class='notice'>You have gained [returned] influence from [get_soldier_territories(soldier)] territories you have personally tagged.</span>")
|
||||
|
||||
/datum/gang/proc/announce_all_influence()
|
||||
for(var/datum/mind/MG in bosses|gangsters)
|
||||
announce_total_influence(MG)
|
||||
|
||||
/datum/gang/proc/pay_territory_income_to_bosses()
|
||||
. = 0
|
||||
for(var/datum/mind/boss_mind in bosses)
|
||||
var/inc = max(0,round(5 - bosses[boss_mind]/10)) + LAZYLEN(territory)
|
||||
. += inc
|
||||
adjust_influence(boss_mind, inc)
|
||||
announce_to_mind(boss_mind, "<span class='boldnotice'>Your influence has increased by [inc] from your gang holding [LAZYLEN(territory)] territories!</span>")
|
||||
|
||||
/datum/gang/proc/get_influence(datum/mind/gangster_mind)
|
||||
if(gangster_mind in gangsters)
|
||||
return gangsters[gangster_mind]
|
||||
if(gangster_mind in bosses)
|
||||
return bosses[gangster_mind]
|
||||
|
||||
/datum/gang/proc/adjust_influence(datum/mind/gangster_mind, amount)
|
||||
if(gangster_mind in gangsters)
|
||||
gangsters[gangster_mind] += amount
|
||||
if(gangster_mind in bosses)
|
||||
bosses[gangster_mind] += amount
|
||||
|
||||
/datum/gang/proc/announce_to_mind(datum/mind/gangster_mind, message)
|
||||
if(gangster_mind.current && gangster_mind.current.stat != DEAD)
|
||||
to_chat(gangster_mind.current, message)
|
||||
|
||||
/datum/gang/proc/announce_total_influence(datum/mind/gangster_mind)
|
||||
announce_to_mind(gangster_mind, "<span class='boldnotice'>[name] Gang: You now have a total of [get_influence(gangster_mind)] influence!</span>")
|
||||
|
||||
/datum/gang/proc/reclaim_points(amount)
|
||||
for(var/datum/mind/bawss in bosses)
|
||||
adjust_influence(bawss, amount/bosses.len)
|
||||
announce_to_mind(bawss, "<span class='notice'>[name] Gang: [amount/bosses.len] influence given from internal automatic restructuring.</span>")
|
||||
|
||||
@@ -1,453 +0,0 @@
|
||||
/datum/gang_item
|
||||
var/name
|
||||
var/item_path
|
||||
var/cost
|
||||
var/spawn_msg
|
||||
var/category
|
||||
var/id
|
||||
|
||||
|
||||
/datum/gang_item/proc/purchase(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool, check_canbuy = TRUE)
|
||||
if(check_canbuy && !can_buy(user, gang, gangtool))
|
||||
return FALSE
|
||||
var/real_cost = get_cost(user, gang, gangtool)
|
||||
gang.adjust_influence(user.mind, -real_cost)
|
||||
spawn_item(user, gang, gangtool)
|
||||
return TRUE
|
||||
|
||||
/datum/gang_item/proc/spawn_item(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(item_path)
|
||||
var/obj/item/O = new item_path(user.loc)
|
||||
user.put_in_hands(O)
|
||||
if(spawn_msg)
|
||||
to_chat(user, spawn_msg)
|
||||
|
||||
/datum/gang_item/proc/can_buy(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
return gang && (gang.get_influence(user.mind) >= get_cost(user, gang, gangtool)) && can_see(user, gang, gangtool)
|
||||
|
||||
/datum/gang_item/proc/can_see(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
return TRUE
|
||||
|
||||
/datum/gang_item/proc/get_cost(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
return cost
|
||||
|
||||
/datum/gang_item/proc/get_cost_display(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
return "([get_cost(user, gang, gangtool)] Influence)"
|
||||
|
||||
/datum/gang_item/proc/get_name_display(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
return name
|
||||
|
||||
/datum/gang_item/proc/isboss(mob/living/carbon/user, datum/gang/gang)
|
||||
return user && gang && (user.mind == gang.bosses[1])
|
||||
|
||||
/datum/gang_item/proc/get_extra_info(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
return
|
||||
|
||||
///////////////////
|
||||
//FUNCTIONS
|
||||
///////////////////
|
||||
|
||||
/datum/gang_item/function
|
||||
category = "Gangtool Functions:"
|
||||
cost = 0
|
||||
|
||||
/datum/gang_item/function/get_cost_display(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
return ""
|
||||
|
||||
|
||||
/datum/gang_item/function/gang_ping
|
||||
name = "Send Message to Gang"
|
||||
id = "gang_ping"
|
||||
|
||||
/datum/gang_item/function/gang_ping/spawn_item(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(gangtool)
|
||||
gangtool.ping_gang(user)
|
||||
|
||||
|
||||
/datum/gang_item/function/recall
|
||||
name = "Recall Emergency Shuttle"
|
||||
id = "recall"
|
||||
|
||||
/datum/gang_item/function/recall/can_see(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
return isboss(user, gang)
|
||||
|
||||
/datum/gang_item/function/recall/spawn_item(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(gangtool)
|
||||
gangtool.recall(user)
|
||||
|
||||
|
||||
///////////////////
|
||||
//CLOTHING
|
||||
///////////////////
|
||||
|
||||
/datum/gang_item/clothing
|
||||
category = "Purchase Influence-Enhancing Clothes:"
|
||||
|
||||
/datum/gang_item/clothing/under
|
||||
name = "Gang Uniform"
|
||||
id = "under"
|
||||
cost = 1
|
||||
|
||||
/datum/gang_item/clothing/under/spawn_item(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(gang.inner_outfit)
|
||||
var/obj/item/O = new gang.inner_outfit(user.loc)
|
||||
user.put_in_hands(O)
|
||||
to_chat(user, "<span class='notice'> This is your gang's official uniform, wearing it will increase your influence")
|
||||
|
||||
/datum/gang_item/clothing/suit
|
||||
name = "Gang Armored Outerwear"
|
||||
id = "suit"
|
||||
cost = 1
|
||||
|
||||
/datum/gang_item/clothing/suit/spawn_item(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(gang.outer_outfit)
|
||||
var/obj/item/O = new gang.outer_outfit(user.loc)
|
||||
O.armor = list(melee = 20, bullet = 35, laser = 10, energy = 10, bomb = 30, bio = 0, rad = 0, fire = 30, acid = 30)
|
||||
O.desc += " Tailored for the [gang.name] Gang to offer the wearer moderate protection against ballistics and physical trauma."
|
||||
user.put_in_hands(O)
|
||||
to_chat(user, "<span class='notice'> This is your gang's official outerwear, wearing it will increase your influence")
|
||||
|
||||
|
||||
/datum/gang_item/clothing/hat
|
||||
name = "Pimp Hat"
|
||||
id = "hat"
|
||||
cost = 16
|
||||
item_path = /obj/item/clothing/head/collectable/petehat/gang
|
||||
|
||||
/obj/item/clothing/head/collectable/petehat/gang
|
||||
name = "pimpin' hat"
|
||||
desc = "The undisputed king of style."
|
||||
|
||||
/obj/item/clothing/head/collectable/petehat/gang/gang_contraband_value()
|
||||
return 4
|
||||
|
||||
/datum/gang_item/clothing/mask
|
||||
name = "Golden Death Mask"
|
||||
id = "mask"
|
||||
cost = 18
|
||||
item_path = /obj/item/clothing/mask/gskull
|
||||
|
||||
/obj/item/clothing/mask/gskull
|
||||
name = "golden death mask"
|
||||
icon_state = "gskull"
|
||||
desc = "Strike terror, and envy, into the hearts of your enemies."
|
||||
|
||||
/obj/item/clothing/mask/gskull/gang_contraband_value()
|
||||
return 5
|
||||
|
||||
/datum/gang_item/clothing/shoes
|
||||
name = "Bling Boots"
|
||||
id = "boots"
|
||||
cost = 22
|
||||
item_path = /obj/item/clothing/shoes/gang
|
||||
|
||||
/obj/item/clothing/shoes/gang
|
||||
name = "blinged-out boots"
|
||||
desc = "Stand aside peasants."
|
||||
icon_state = "bling"
|
||||
|
||||
/obj/item/clothing/shoes/gang/gang_contraband_value()
|
||||
return 6
|
||||
|
||||
/datum/gang_item/clothing/neck
|
||||
name = "Gold Necklace"
|
||||
id = "necklace"
|
||||
cost = 9
|
||||
item_path = /obj/item/clothing/neck/necklace/dope
|
||||
|
||||
/datum/gang_item/clothing/hands
|
||||
name = "Decorative Brass Knuckles"
|
||||
id = "hand"
|
||||
cost = 11
|
||||
item_path = /obj/item/clothing/gloves/gang
|
||||
|
||||
/obj/item/clothing/gloves/gang
|
||||
name = "braggadocio's brass knuckles"
|
||||
desc = "Purely decorative, don't find out the hard way."
|
||||
icon_state = "knuckles"
|
||||
w_class = 3
|
||||
|
||||
/obj/item/clothing/gloves/gang/gang_contraband_value()
|
||||
return 3
|
||||
|
||||
/datum/gang_item/clothing/belt
|
||||
name = "Badass Belt"
|
||||
id = "belt"
|
||||
cost = 13
|
||||
item_path = /obj/item/storage/belt/military/gang
|
||||
|
||||
/obj/item/storage/belt/military/gang
|
||||
name = "badass belt"
|
||||
icon_state = "gangbelt"
|
||||
item_state = "gang"
|
||||
desc = "The belt buckle simply reads 'BAMF'."
|
||||
storage_slots = 1
|
||||
|
||||
/obj/item/storage/belt/military/gang/gang_contraband_value()
|
||||
return 4
|
||||
|
||||
///////////////////
|
||||
//WEAPONS
|
||||
///////////////////
|
||||
|
||||
/datum/gang_item/weapon
|
||||
category = "Purchase Weapons:"
|
||||
|
||||
/datum/gang_item/weapon/ammo
|
||||
|
||||
/datum/gang_item/weapon/ammo/get_cost_display(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
return " ↳" + ..() //this is pretty hacky but it looks nice on the popup
|
||||
|
||||
/datum/gang_item/weapon/shuriken
|
||||
name = "Shuriken"
|
||||
id = "shuriken"
|
||||
cost = 3
|
||||
item_path = /obj/item/throwing_star
|
||||
|
||||
/datum/gang_item/weapon/switchblade
|
||||
name = "Switchblade"
|
||||
id = "switchblade"
|
||||
cost = 5
|
||||
item_path = /obj/item/switchblade
|
||||
|
||||
/datum/gang_item/weapon/surplus
|
||||
name = "Surplus Rifle"
|
||||
id = "surplus"
|
||||
cost = 8
|
||||
item_path = /obj/item/gun/ballistic/automatic/surplus
|
||||
|
||||
/datum/gang_item/weapon/ammo/surplus_ammo
|
||||
name = "Surplus Rifle Ammo"
|
||||
id = "surplus_ammo"
|
||||
cost = 5
|
||||
item_path = /obj/item/ammo_box/magazine/m10mm/rifle
|
||||
|
||||
/datum/gang_item/weapon/improvised
|
||||
name = "Sawn-Off Improvised Shotgun"
|
||||
id = "sawn"
|
||||
cost = 6
|
||||
item_path = /obj/item/gun/ballistic/revolver/doublebarrel/improvised/sawn
|
||||
|
||||
/datum/gang_item/weapon/ammo/improvised_ammo
|
||||
name = "Box of Buckshot"
|
||||
id = "buckshot"
|
||||
cost = 5
|
||||
item_path = /obj/item/storage/box/lethalshot
|
||||
|
||||
/datum/gang_item/weapon/pistol
|
||||
name = "10mm Pistol"
|
||||
id = "pistol"
|
||||
cost = 30
|
||||
item_path = /obj/item/gun/ballistic/automatic/pistol
|
||||
|
||||
/datum/gang_item/weapon/ammo/pistol_ammo
|
||||
name = "10mm Ammo"
|
||||
id = "pistol_ammo"
|
||||
cost = 10
|
||||
item_path = /obj/item/ammo_box/magazine/m10mm
|
||||
|
||||
/datum/gang_item/weapon/sniper
|
||||
name = "Black Market .50cal Sniper Rifle"
|
||||
id = "sniper"
|
||||
cost = 40
|
||||
item_path = /obj/item/gun/ballistic/automatic/sniper_rifle/gang
|
||||
|
||||
/datum/gang_item/weapon/ammo/sniper_ammo
|
||||
name = "Smuggled .50cal Sniper Rounds"
|
||||
id = "sniper_ammo"
|
||||
cost = 15
|
||||
item_path = /obj/item/ammo_box/magazine/sniper_rounds/gang
|
||||
|
||||
|
||||
/datum/gang_item/weapon/ammo/sleeper_ammo
|
||||
name = "Illicit Tranquilizer Cartridges"
|
||||
id = "sniper_ammo"
|
||||
cost = 15
|
||||
item_path = /obj/item/ammo_box/magazine/sniper_rounds/gang/sleeper
|
||||
|
||||
|
||||
/datum/gang_item/weapon/machinegun
|
||||
name = "Mounted Machine Gun"
|
||||
id = "MG"
|
||||
cost = 50
|
||||
item_path = /obj/machinery/manned_turret
|
||||
spawn_msg = "<span class='notice'>The mounted machine gun features enhanced responsiveness. Hold down on the trigger while firing to control where you're shooting.</span>"
|
||||
|
||||
/datum/gang_item/weapon/uzi
|
||||
name = "Uzi SMG"
|
||||
id = "uzi"
|
||||
cost = 60
|
||||
item_path = /obj/item/gun/ballistic/automatic/mini_uzi
|
||||
|
||||
|
||||
/datum/gang_item/weapon/ammo/uzi_ammo
|
||||
name = "Uzi Ammo"
|
||||
id = "uzi_ammo"
|
||||
cost = 40
|
||||
item_path = /obj/item/ammo_box/magazine/uzim9mm
|
||||
|
||||
///////////////////
|
||||
//EQUIPMENT
|
||||
///////////////////
|
||||
|
||||
/datum/gang_item/equipment
|
||||
category = "Purchase Equipment:"
|
||||
|
||||
|
||||
/datum/gang_item/equipment/spraycan
|
||||
name = "Territory Spraycan"
|
||||
id = "spraycan"
|
||||
cost = 5
|
||||
item_path = /obj/item/toy/crayon/spraycan/gang
|
||||
|
||||
/datum/gang_item/equipment/sharpener
|
||||
name = "Sharpener"
|
||||
id = "whetstone"
|
||||
cost = 3
|
||||
item_path = /obj/item/sharpener
|
||||
|
||||
|
||||
/datum/gang_item/equipment/emp
|
||||
name = "EMP Grenade"
|
||||
id = "EMP"
|
||||
cost = 5
|
||||
item_path = /obj/item/grenade/empgrenade
|
||||
|
||||
/datum/gang_item/equipment/c4
|
||||
name = "C4 Explosive"
|
||||
id = "c4"
|
||||
cost = 7
|
||||
item_path = /obj/item/grenade/plastic/c4
|
||||
|
||||
/datum/gang_item/equipment/frag
|
||||
name = "Fragmentation Grenade"
|
||||
id = "frag nade"
|
||||
cost = 18
|
||||
item_path = /obj/item/grenade/syndieminibomb/concussion/frag
|
||||
|
||||
/datum/gang_item/equipment/stimpack
|
||||
name = "Black Market Stimulants"
|
||||
id = "stimpack"
|
||||
cost = 12
|
||||
item_path = /obj/item/reagent_containers/syringe/stimulants
|
||||
|
||||
/datum/gang_item/equipment/implant_breaker
|
||||
name = "Implant Breaker"
|
||||
id = "implant_breaker"
|
||||
cost = 10
|
||||
item_path = /obj/item/implanter/gang
|
||||
spawn_msg = "<span class='notice'>The <b>implant breaker</b> is a single-use device that destroys all implants within the target before trying to recruit them to your gang. Also works on enemy gangsters.</span>"
|
||||
|
||||
/datum/gang_item/equipment/implant_breaker/spawn_item(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(item_path)
|
||||
var/obj/item/O = new item_path(user.loc, gang) //we need to override this whole proc for this one argument
|
||||
user.put_in_hands(O)
|
||||
if(spawn_msg)
|
||||
to_chat(user, spawn_msg)
|
||||
|
||||
/datum/gang_item/equipment/wetwork_boots
|
||||
name = "Wetwork boots"
|
||||
id = "wetwork"
|
||||
cost = 20
|
||||
item_path = /obj/item/clothing/shoes/combat/gang
|
||||
|
||||
/obj/item/clothing/shoes/combat/gang
|
||||
name = "Wetwork boots"
|
||||
desc = "A gang's best hitmen are prepared for anything."
|
||||
permeability_coefficient = 0.01
|
||||
flags_1 = NOSLIP_1
|
||||
|
||||
/datum/gang_item/equipment/pen
|
||||
name = "Recruitment Pen"
|
||||
id = "pen"
|
||||
cost = 50
|
||||
item_path = /obj/item/pen/gang
|
||||
spawn_msg = "<span class='notice'>More <b>recruitment pens</b> will allow you to recruit gangsters faster. Only gang leaders can recruit with pens.</span>"
|
||||
|
||||
/datum/gang_item/equipment/pen/purchase(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(..())
|
||||
gangtool.free_pen = FALSE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/gang_item/equipment/pen/get_cost(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(gangtool && gangtool.free_pen)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/datum/gang_item/equipment/pen/get_cost_display(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(gangtool && gangtool.free_pen)
|
||||
return "(GET ONE FREE)"
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/gang_item/equipment/gangtool
|
||||
id = "gangtool"
|
||||
cost = 10
|
||||
|
||||
/datum/gang_item/equipment/gangtool/spawn_item(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
var/item_type
|
||||
if(gang && isboss(user, gang))
|
||||
item_type = /obj/item/device/gangtool/spare/lt
|
||||
if(gang.bosses.len < 3)
|
||||
to_chat(user, "<span class='notice'><b>Gangtools</b> allow you to promote a gangster to be your Lieutenant, enabling them to recruit and purchase items like you. Simply have them register the gangtool. You may promote up to [3-gang.bosses.len] more Lieutenants</span>")
|
||||
else
|
||||
item_type = /obj/item/device/gangtool/spare
|
||||
var/obj/item/device/gangtool/spare/tool = new item_type(user.loc)
|
||||
user.put_in_hands(tool)
|
||||
|
||||
/datum/gang_item/equipment/gangtool/get_name_display(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(gang && isboss(user, gang) && (gang.bosses.len < 3))
|
||||
return "Promote a Gangster"
|
||||
return "Spare Gangtool"
|
||||
|
||||
|
||||
/datum/gang_item/equipment/dominator
|
||||
name = "Station Dominator"
|
||||
id = "dominator"
|
||||
cost = 30
|
||||
item_path = /obj/machinery/dominator
|
||||
spawn_msg = "<span class='notice'>The <b>dominator</b> will secure your gang's dominance over the station. Turn it on when you are ready to defend it.</span>"
|
||||
|
||||
/datum/gang_item/equipment/dominator/can_buy(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(!gang || !gang.dom_attempts)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/gang_item/equipment/dominator/get_name_display(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(!gang || !gang.dom_attempts)
|
||||
return ..()
|
||||
return "<b>[..()]</b>"
|
||||
|
||||
/datum/gang_item/equipment/dominator/get_cost_display(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(!gang || !gang.dom_attempts)
|
||||
return "(Out of stock)"
|
||||
return ..()
|
||||
|
||||
/datum/gang_item/equipment/dominator/get_extra_info(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
if(gang)
|
||||
return "(Estimated Takeover Time: [round(determine_domination_time(gang)/60,0.1)] minutes)"
|
||||
|
||||
/datum/gang_item/equipment/dominator/purchase(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
var/area/usrarea = get_area(user.loc)
|
||||
var/usrturf = get_turf(user.loc)
|
||||
if(initial(usrarea.name) == "Space" || isspaceturf(usrturf) || usr.z != ZLEVEL_STATION || !usrarea.valid_territory)
|
||||
to_chat(user, "<span class='warning'>You can only use this on the station!</span>")
|
||||
return FALSE
|
||||
|
||||
for(var/obj/obj in usrturf)
|
||||
if(obj.density)
|
||||
to_chat(user, "<span class='warning'>There's not enough room here!</span>")
|
||||
return FALSE
|
||||
|
||||
if(dominator_excessive_walls(user))
|
||||
to_chat(user, "<span class='warning'>The <b>dominator</b> will not function here! The <b>dominator</b> requires a sizable open space within three standard units so that walls do not interfere with the signal.</span>")
|
||||
return FALSE
|
||||
|
||||
if(!(usrarea.type in gang.territory|gang.territory_new))
|
||||
to_chat(user, "<span class='warning'>The <b>dominator</b> can be spawned only on territory controlled by your gang!</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/gang_item/equipment/dominator/spawn_item(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
new item_path(user.loc)
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Gang Boss Pens
|
||||
*/
|
||||
/obj/item/pen/gang
|
||||
var/cooldown
|
||||
var/last_used = 0
|
||||
var/charges = 1
|
||||
|
||||
/obj/item/pen/gang/New()
|
||||
..()
|
||||
last_used = world.time
|
||||
|
||||
/obj/item/pen/gang/attack(mob/living/M, mob/user, stealth = TRUE)
|
||||
if(!istype(M))
|
||||
return
|
||||
if(ishuman(M) && ishuman(user) && M.stat != DEAD)
|
||||
if(user.mind && (user.mind in SSticker.mode.get_gang_bosses()))
|
||||
if(..(M,user,1))
|
||||
if(cooldown)
|
||||
to_chat(user, "<span class='warning'>[src] needs more time to recharge before it can be used.</span>")
|
||||
return
|
||||
if(M.client)
|
||||
M.mind_initialize() //give them a mind datum if they don't have one.
|
||||
var/datum/gang/G = user.mind.gang_datum
|
||||
var/recruitable = SSticker.mode.add_gangster(M.mind,G)
|
||||
switch(recruitable)
|
||||
if(3)
|
||||
for(var/obj/O in M.contents)
|
||||
if(istype(O, /obj/item/device/gangtool/soldier))
|
||||
to_chat(user, "<span class='warning'>This gangster already has an uplink!</span>")
|
||||
return
|
||||
new /obj/item/device/gangtool/soldier(M)
|
||||
to_chat(user, "<span class='warning'>You inject [M] with a new gangtool!</span>")
|
||||
cooldown(G)
|
||||
if(2)
|
||||
new /obj/item/device/gangtool/soldier(M)
|
||||
M.Unconscious(100)
|
||||
cooldown(G)
|
||||
if(1)
|
||||
to_chat(user, "<span class='warning'>This mind is resistant to recruitment!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>This mind has already been recruited into a gang!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/pen/gang/proc/cooldown(datum/gang/gang)
|
||||
set waitfor = FALSE
|
||||
var/cooldown_time = 600+(600*gang.bosses.len) // 1recruiter=2mins, 2recruiters=3mins, 3recruiters=4mins
|
||||
|
||||
cooldown = 1
|
||||
icon_state = "pen_blink"
|
||||
|
||||
var/time_passed = world.time - last_used
|
||||
var/time
|
||||
for(time=time_passed, time>=cooldown_time, time-=cooldown_time) //get 1 charge every cooldown interval
|
||||
charges++
|
||||
|
||||
charges = max(0,charges-1)
|
||||
|
||||
last_used = world.time - time
|
||||
|
||||
if(charges)
|
||||
cooldown_time = 50
|
||||
sleep(cooldown_time)
|
||||
cooldown = 0
|
||||
icon_state = "pen"
|
||||
var/mob/M = get(src, /mob)
|
||||
to_chat(M, "<span class='notice'>[icon2html(src, M)] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly. It is ready to be used again.</span>")
|
||||
@@ -1,332 +0,0 @@
|
||||
//gangtool device
|
||||
/obj/item/device/gangtool
|
||||
name = "suspicious device"
|
||||
desc = "A strange device of sorts. Hard to really make out what it actually does if you don't know how to operate it."
|
||||
icon_state = "gangtool-white"
|
||||
item_state = "radio"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
throwforce = 0
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
flags_1 = CONDUCT_1
|
||||
var/datum/gang/gang //Which gang uses this?
|
||||
var/recalling = 0
|
||||
var/outfits = 2
|
||||
var/free_pen = 0
|
||||
var/promotable = 0
|
||||
var/list/tags = list()
|
||||
|
||||
/obj/item/device/gangtool/Initialize() //Initialize supply point income if it hasn't already been started
|
||||
..()
|
||||
if(!SSticker.mode.gang_points)
|
||||
SSticker.mode.gang_points = new /datum/gang_points(SSticker.mode)
|
||||
|
||||
/obj/item/device/gangtool/attack_self(mob/user)
|
||||
if (!can_use(user))
|
||||
return
|
||||
|
||||
var/dat
|
||||
if(!gang)
|
||||
dat += "This device is not registered.<br><br>"
|
||||
if(user.mind in SSticker.mode.get_gang_bosses())
|
||||
if(promotable && user.mind.gang_datum.bosses.len < 3)
|
||||
dat += "Give this device to another member of your organization to use to promote them to Lieutenant.<br><br>"
|
||||
dat += "If this is meant as a spare device for yourself:<br>"
|
||||
dat += "<a href='?src=\ref[src];register=1'>Register Device as Spare</a><br>"
|
||||
else if (promotable)
|
||||
if(user.mind.gang_datum.bosses.len < 3)
|
||||
dat += "You have been selected for a promotion!<br>"
|
||||
dat += "<a href='?src=\ref[src];register=1'>Accept Promotion</a><br>"
|
||||
else
|
||||
dat += "No promotions available: All positions filled.<br>"
|
||||
else
|
||||
dat += "This device is not authorized to promote.<br>"
|
||||
else
|
||||
if(gang.is_dominating)
|
||||
dat += "<center><font color='red'>Takeover In Progress:<br><B>[gang.domination_time_remaining()] seconds remain</B></font></center>"
|
||||
|
||||
var/isboss = (user.mind == gang.bosses[1])
|
||||
dat += "Registration: <B>[gang.name] Gang [isboss ? "Boss" : "Lieutenant"]</B><br>"
|
||||
dat += "Organization Size: <B>[gang.gangsters.len + gang.bosses.len]</B> | Station Control: <B>[round((gang.territory.len/GLOB.start_state.num_territories)*100, 1)]%</B><br>"
|
||||
dat += "Your Influence: <B>[gang.get_influence(user.mind)]</B><br>"
|
||||
dat += "Time until Influence grows: <B>[time2text(SSticker.mode.gang_points.next_point_time - world.time, "mm:ss")]</B><br>"
|
||||
dat += "<hr>"
|
||||
|
||||
|
||||
for(var/cat in gang.boss_category_list)
|
||||
dat += "<b>[cat]</b><br>"
|
||||
for(var/V in gang.boss_category_list[cat])
|
||||
var/datum/gang_item/G = V
|
||||
if(!G.can_see(user, gang, src))
|
||||
continue
|
||||
|
||||
var/cost = G.get_cost_display(user, gang, src)
|
||||
if(cost)
|
||||
dat += cost + " "
|
||||
|
||||
var/toAdd = G.get_name_display(user, gang, src)
|
||||
if(G.can_buy(user, gang, src))
|
||||
toAdd = "<a href='?src=\ref[src];purchase=[G.id]'>[toAdd]</a>"
|
||||
dat += toAdd
|
||||
var/extra = G.get_extra_info(user, gang, src)
|
||||
if(extra)
|
||||
dat += "<br><i>[extra]</i>"
|
||||
dat += "<br>"
|
||||
dat += "<br>"
|
||||
|
||||
dat += "<a href='?src=\ref[src];choice=refresh'>Refresh</a><br>"
|
||||
|
||||
var/datum/browser/popup = new(user, "gangtool", "Welcome to GangTool v3.5", 340, 625)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
|
||||
|
||||
/obj/item/device/gangtool/Topic(href, href_list)
|
||||
if(!can_use(usr))
|
||||
return
|
||||
|
||||
add_fingerprint(usr)
|
||||
|
||||
if(href_list["register"])
|
||||
register_device(usr)
|
||||
|
||||
else if(!gang) //Gangtool must be registered before you can use the functions below
|
||||
return
|
||||
|
||||
if(href_list["purchase"])
|
||||
var/datum/gang_item/G = gang.boss_item_list[href_list["purchase"]]
|
||||
if(G && G.can_buy(usr, gang, src))
|
||||
G.purchase(usr, gang, src, FALSE)
|
||||
|
||||
attack_self(usr)
|
||||
|
||||
|
||||
/obj/item/device/gangtool/proc/ping_gang(mob/user)
|
||||
if(!user)
|
||||
return
|
||||
var/message = stripped_input(user,"Discreetly send a gang-wide message.","Send Message") as null|text
|
||||
if(!message || !can_use(user))
|
||||
return
|
||||
if(user.z > 2)
|
||||
to_chat(user, "<span class='info'>[icon2html(src, user)]Error: Station out of range.</span>")
|
||||
return
|
||||
var/list/members = list()
|
||||
members += gang.gangsters
|
||||
members += gang.bosses
|
||||
if(members.len)
|
||||
var/gang_rank = gang.bosses.Find(user.mind)
|
||||
switch(gang_rank)
|
||||
if(1)
|
||||
gang_rank = "Gang Boss"
|
||||
if(2)
|
||||
gang_rank = "1st Lieutenant"
|
||||
if(3)
|
||||
gang_rank = "2nd Lieutenant"
|
||||
if(4)
|
||||
gang_rank = "3rd Lieutenant"
|
||||
else
|
||||
gang_rank = "[gang_rank - 1]th Lieutenant"
|
||||
var/ping = "<span class='danger'><B><i>[gang.name] [gang_rank]</i>: [message]</B></span>"
|
||||
for(var/datum/mind/ganger in members)
|
||||
if(ganger.current && (ganger.current.z <= 2) && (ganger.current.stat == CONSCIOUS))
|
||||
to_chat(ganger.current, ping)
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
var/link = FOLLOW_LINK(M, user)
|
||||
to_chat(M, "[link] [ping]")
|
||||
log_talk(user,"GANG: [key_name(user)] Messaged [gang.name] Gang: [message].",LOGSAY)
|
||||
|
||||
|
||||
/obj/item/device/gangtool/proc/register_device(mob/user)
|
||||
if(gang) //It's already been registered!
|
||||
return
|
||||
if((promotable && (user.mind in SSticker.mode.get_gangsters())) || (user.mind in SSticker.mode.get_gang_bosses()))
|
||||
gang = user.mind.gang_datum
|
||||
gang.gangtools += src
|
||||
icon_state = "gangtool-[gang.color]"
|
||||
if(!(user.mind in gang.bosses))
|
||||
var/cached_influence = gang.gangsters[user.mind]
|
||||
SSticker.mode.remove_gangster(user.mind, 0, 2)
|
||||
gang.bosses[user.mind] = cached_influence
|
||||
user.mind.gang_datum = gang
|
||||
user.mind.special_role = "[gang.name] Gang Lieutenant"
|
||||
gang.add_gang_hud(user.mind)
|
||||
log_game("[key_name(user)] has been promoted to Lieutenant in the [gang.name] Gang")
|
||||
free_pen = 1
|
||||
gang.message_gangtools("[user] has been promoted to Lieutenant.")
|
||||
to_chat(user, "<FONT size=3 color=red><B>You have been promoted to Lieutenant!</B></FONT>")
|
||||
SSticker.mode.forge_gang_objectives(user.mind)
|
||||
SSticker.mode.greet_gang(user.mind,0)
|
||||
to_chat(user, "The <b>Gangtool</b> you registered will allow you to purchase weapons and equipment, and send messages to your gang.")
|
||||
to_chat(user, "Unlike regular gangsters, you may use <b>recruitment pens</b> to add recruits to your gang. Use them on unsuspecting crew members to recruit them. Don't forget to get your one free pen from the gangtool.")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>ACCESS DENIED: Unauthorized user.</span>")
|
||||
|
||||
/obj/item/device/gangtool/proc/recall(mob/user)
|
||||
if(!can_use(user))
|
||||
return 0
|
||||
|
||||
if(SSshuttle.emergencyNoRecall)
|
||||
return 0
|
||||
|
||||
if(recalling)
|
||||
to_chat(usr, "<span class='warning'>Error: Recall already in progress.</span>")
|
||||
return 0
|
||||
|
||||
if(!gang.recalls)
|
||||
to_chat(usr, "<span class='warning'>Error: Unable to access communication arrays. Firewall has logged our signature and is blocking all further attempts.</span>")
|
||||
|
||||
gang.message_gangtools("[usr] is attempting to recall the emergency shuttle.")
|
||||
recalling = 1
|
||||
to_chat(loc, "<span class='info'>[icon2html(src, loc)]Generating shuttle recall order with codes retrieved from last call signal...</span>")
|
||||
|
||||
sleep(rand(100,300))
|
||||
|
||||
if(SSshuttle.emergency.mode != SHUTTLE_CALL) //Shuttle can only be recalled when it's moving to the station
|
||||
to_chat(user, "<span class='warning'>[icon2html(src, user)]Emergency shuttle cannot be recalled at this time.</span>")
|
||||
recalling = 0
|
||||
return 0
|
||||
to_chat(loc, "<span class='info'>[icon2html(src, loc)]Shuttle recall order generated. Accessing station long-range communication arrays...</span>")
|
||||
|
||||
sleep(rand(100,300))
|
||||
|
||||
if(!gang.dom_attempts)
|
||||
to_chat(user, "<span class='warning'>[icon2html(src, user)]Error: Unable to access communication arrays. Firewall has logged our signature and is blocking all further attempts.</span>")
|
||||
recalling = 0
|
||||
return 0
|
||||
|
||||
var/turf/userturf = get_turf(user)
|
||||
if(userturf.z != ZLEVEL_STATION) //Shuttle can only be recalled while on station
|
||||
to_chat(user, "<span class='warning'>[icon2html(src, user)]Error: Device out of range of station communication arrays.</span>")
|
||||
recalling = 0
|
||||
return 0
|
||||
var/datum/station_state/end_state = new /datum/station_state()
|
||||
end_state.count()
|
||||
if((100 * GLOB.start_state.score(end_state)) < 80) //Shuttle cannot be recalled if the station is too damaged
|
||||
to_chat(user, "<span class='warning'>[icon2html(src, user)]Error: Station communication systems compromised. Unable to establish connection.</span>")
|
||||
recalling = 0
|
||||
return 0
|
||||
to_chat(loc, "<span class='info'>[icon2html(src, loc)]Comm arrays accessed. Broadcasting recall signal...</span>")
|
||||
|
||||
sleep(rand(100,300))
|
||||
|
||||
recalling = 0
|
||||
log_game("[key_name(user)] has tried to recall the shuttle with a gangtool.")
|
||||
message_admins("[key_name_admin(user)] has tried to recall the shuttle with a gangtool.", 1)
|
||||
userturf = get_turf(user)
|
||||
if(userturf.z == ZLEVEL_STATION) //Check one more time that they are on station.
|
||||
if(SSshuttle.cancelEvac(user))
|
||||
gang.recalls -= 1
|
||||
return 1
|
||||
|
||||
to_chat(loc, "<span class='info'>[icon2html(src, loc)]No response recieved. Emergency shuttle cannot be recalled at this time.</span>")
|
||||
return 0
|
||||
|
||||
/obj/item/device/gangtool/proc/can_use(mob/living/carbon/human/user)
|
||||
if(!istype(user))
|
||||
return 0
|
||||
if(user.incapacitated())
|
||||
return 0
|
||||
if(!(src in user.contents))
|
||||
return 0
|
||||
if(!user.mind)
|
||||
return 0
|
||||
if(gang && (user.mind in gang.bosses)) //If it's already registered, only let the gang's bosses use this
|
||||
return 1
|
||||
else if(user.mind in SSticker.mode.get_all_gangsters()) // For soldiers and potential LT's
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/device/gangtool/spare
|
||||
outfits = 1
|
||||
|
||||
/obj/item/device/gangtool/spare/lt
|
||||
promotable = 1
|
||||
|
||||
///////////// Internal tool used by gang regulars ///////////
|
||||
|
||||
/obj/item/device/gangtool/soldier/New(mob/user)
|
||||
. = ..()
|
||||
gang = user.mind.gang_datum
|
||||
gang.gangtools += src
|
||||
var/datum/action/innate/gang/tool/GT = new
|
||||
GT.Grant(user, src, gang)
|
||||
|
||||
/obj/item/device/gangtool/soldier/attack_self(mob/user)
|
||||
if (!can_use(user))
|
||||
return
|
||||
var/dat
|
||||
if(gang.is_dominating)
|
||||
dat += "<center><font color='red'>Takeover In Progress:<br><B>[gang.domination_time_remaining()] seconds remain</B></font></center>"
|
||||
dat += "Registration: <B>[gang.name] - Foot Soldier</B><br>"
|
||||
dat += "Organization Size: <B>[gang.gangsters.len + gang.bosses.len]</B> | Station Control: <B>[round((gang.territory.len/GLOB.start_state.num_territories)*100, 1)]%</B><br>"
|
||||
dat += "Your Influence: <B>[gang.get_influence(user.mind)]</B><br>"
|
||||
if(LAZYLEN(tags))
|
||||
dat += "Your tags generate bonus influence for you.<br> You have tagged the following territories:"
|
||||
for(var/obj/effect/decal/cleanable/crayon/gang/T in tags)
|
||||
dat += " [T.territory] -"
|
||||
else
|
||||
dat += "You have not personally tagged any territory for your gang. Use a spray can to mark your territory and receive bonus influence."
|
||||
dat += "<br>Time until Influence grows: <B>[time2text(SSticker.mode.gang_points.next_point_time - world.time, "mm:ss")]</B><br>"
|
||||
dat += "<hr>"
|
||||
for(var/cat in gang.reg_category_list)
|
||||
dat += "<b>[cat]</b><br>"
|
||||
for(var/V in gang.reg_category_list[cat])
|
||||
var/datum/gang_item/G = V
|
||||
if(!G.can_see(user, gang, src))
|
||||
continue
|
||||
|
||||
var/cost = G.get_cost_display(user, gang, src)
|
||||
if(cost)
|
||||
dat += cost + " "
|
||||
|
||||
var/toAdd = G.get_name_display(user, gang, src)
|
||||
if(G.can_buy(user, gang, src))
|
||||
toAdd = "<a href='?src=\ref[src];purchase=[G.id]'>[toAdd]</a>"
|
||||
dat += toAdd
|
||||
var/extra = G.get_extra_info(user, gang, src)
|
||||
if(extra)
|
||||
dat += "<br><i>[extra]</i>"
|
||||
dat += "<br>"
|
||||
dat += "<br>"
|
||||
|
||||
dat += "<a href='?src=\ref[src];choice=refresh'>Refresh</a><br>"
|
||||
|
||||
var/datum/browser/popup = new(user, "gangtool", "Welcome to GangTool v3.5", 340, 625)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/item/device/gangtool/soldier/Topic(href, href_list)
|
||||
if(!can_use(usr))
|
||||
return
|
||||
if(href_list["purchase"])
|
||||
var/datum/gang_item/G = gang.reg_item_list[href_list["purchase"]]
|
||||
if(G && G.can_buy(usr, gang, src))
|
||||
G.purchase(usr, gang, src, FALSE)
|
||||
|
||||
attack_self(usr)
|
||||
|
||||
/datum/action/innate/gang
|
||||
background_icon_state = "bg_spell"
|
||||
|
||||
/datum/action/innate/gang/IsAvailable()
|
||||
if(!owner.mind || !owner.mind in SSticker.mode.get_all_gangsters())
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/datum/action/innate/gang/tool
|
||||
name = "Personal Gang Tool"
|
||||
desc = "An implanted gang tool that lets you purchase gear"
|
||||
background_icon_state = "bg_mime"
|
||||
button_icon_state = "bolt_action"
|
||||
var/obj/item/device/gangtool/soldier/GT
|
||||
|
||||
/datum/action/innate/gang/tool/Grant(mob/user, obj/reg, datum/gang/G)
|
||||
. = ..()
|
||||
GT = reg
|
||||
button.color = G.color
|
||||
|
||||
/datum/action/innate/gang/tool/Activate()
|
||||
GT.attack_self(owner)
|
||||
@@ -1,52 +0,0 @@
|
||||
//Intercept reports are sent to the station every round to warn the crew of possible threats. They consist of five possibilites, one of which is always correct.
|
||||
|
||||
/datum/intercept_text
|
||||
var/text
|
||||
|
||||
/datum/intercept_text/proc/build(mode_type)
|
||||
text = "<hr>"
|
||||
switch(mode_type)
|
||||
if("blob")
|
||||
text += "A CMP scientist by the name of [pick("Griff", "Pasteur", "Chamberland", "Buist", "Rivers", "Stanley")] boasted about his corporation's \"finest creation\" - a macrobiological \
|
||||
virus capable of self-reproduction and hellbent on consuming whatever it touches. He went on to query Cybersun for permission to utilize the virus in biochemical warfare, to which \
|
||||
CMP subsequently gained. Be vigilant for any large organisms rapidly spreading across the station, as they are classified as a level 5 biohazard and critically dangerous. Note that \
|
||||
this organism seems to be weak to extreme heat; concentrated fire (such as welding tools and lasers) will be effective against it."
|
||||
if("changeling")
|
||||
text += "The Gorlex Marauders have announced the successful raid and destruction of Central Command containment ship #S-[rand(1111, 9999)]. This ship housed only a single prisoner - \
|
||||
codenamed \"Thing\", and it was highly adaptive and extremely dangerous. We have reason to believe that the Thing has allied with the Syndicate, and you should note that likelihood \
|
||||
of the Thing being sent to a station in this sector is highly likely. It may be in the guise of any crew member. Trust nobody - suspect everybody. Do not announce this to the crew, \
|
||||
as paranoia may spread and inhibit workplace efficiency."
|
||||
if("clock_cult")
|
||||
text += "We have lost contact with multiple stations in your sector. They have gone dark and do not respond to all transmissions, although they appear intact and the crew's life \
|
||||
signs remain uninterrupted. Those that have managed to send a transmission or have had some of their crew escape tell tales of a machine cult creating sapient automatons and seeking \
|
||||
to brainwash the crew to summon their god, Ratvar. If evidence of this cult is dicovered aboard your station, extreme caution and extreme vigilance must be taken going forward, and \
|
||||
all resources should be devoted to stopping this cult. Note that holy water seems to weaken and eventually return the minds of cultists that ingest it, and mindshield implants will \
|
||||
prevent conversion altogether."
|
||||
if("cult")
|
||||
text += "Some stations in your sector have reported evidence of blood sacrifice and strange magic. Ties to the Wizards' Federation have been proven not to exist, and many employees \
|
||||
have disappeared; even Central Command employees light-years away have felt strange presences and at times hysterical compulsions. Interrogations point towards this being the work of \
|
||||
the cult of Nar-Sie. If evidence of this cult is discovered aboard your station, extreme caution and extreme vigilance must be taken going forward, and all resources should be \
|
||||
devoted to stopping this cult. Note that holy water seems to weaken and eventually return the minds of cultists that ingest it, and mindshield implants will prevent conversion \
|
||||
altogether."
|
||||
if("extended")
|
||||
text += "The transmission mostly failed to mention your sector. It is possible that there is nothing in the Syndicate that could threaten your station during this shift."
|
||||
if("malf")
|
||||
text += "A large ionospheric anomaly recently passed through your sector. Although physically undetectable, ionospherics tend to have an extreme effect on telecommunications equipment \
|
||||
as well as artificial intelligence units. Closely observe the behavior of artificial intelligence, and treat any machine malfunctions as purposeful. If necessary, termination of the \
|
||||
artificial intelligence is advised; assuming that it activates the station's self-destruct, your pinpointer has been configured to constantly track it, wherever it may be."
|
||||
if("nuclear")
|
||||
text += "One of Central Command's trading routes was recently disrupted by a raid carried out by the Gorlex Marauders. They seemed to only be after one ship - a highly-sensitive \
|
||||
transport containing a nuclear fission explosive, although it is useless without the proper code and authorization disk. While the code was likely found in minutes, the only disk that \
|
||||
can activate this explosive is on your station. Ensure that it is protected at all times, and remain alert for possible intruders."
|
||||
if("revolution")
|
||||
text += "Employee unrest has spiked in recent weeks, with several attempted mutinies on heads of staff. Some crew have been observed using flashbulb devices to blind their colleagues, \
|
||||
who then follow their orders without question and work towards dethroning departmental leaders. Watch for behavior such as this with caution. If the crew attempts a mutiny, you and \
|
||||
your heads of staff are fully authorized to execute them using lethal weaponry - they will be later cloned and interrogated at Central Command."
|
||||
if("traitor")
|
||||
text += "Although more specific threats are commonplace, you should always remain vigilant for Syndicate agents aboard your station. Syndicate communications have implied that many \
|
||||
Nanotrasen employees are Syndicate agents with hidden memories that may be activated at a moment's notice, so it's possible that these agents might not even know their positions."
|
||||
if("wizard")
|
||||
text += "A dangerous Wizards' Federation individual by the name of [pick(GLOB.wizard_first)] [pick(GLOB.wizard_second)] has recently escaped confinement from an unlisted prison facility. This \
|
||||
man is a dangerous mutant with the ability to alter himself and the world around him by what he and his leaders believe to be magic. If this man attempts an attack on your station, \
|
||||
his execution is highly encouraged, as is the preservation of his body for later study."
|
||||
return text
|
||||
@@ -1,37 +0,0 @@
|
||||
/datum/game_mode
|
||||
var/list/datum/mind/abductors = list()
|
||||
|
||||
// LANDMARKS
|
||||
/obj/effect/landmark/abductor
|
||||
var/team_number = 1
|
||||
|
||||
/obj/effect/landmark/abductor/agent
|
||||
icon_state = "abductor_agent"
|
||||
/obj/effect/landmark/abductor/scientist
|
||||
icon_state = "abductor"
|
||||
|
||||
// OBJECTIVES
|
||||
/datum/objective/experiment
|
||||
target_amount = 6
|
||||
|
||||
/datum/objective/experiment/New()
|
||||
explanation_text = "Experiment on [target_amount] humans."
|
||||
|
||||
/datum/objective/experiment/check_completion()
|
||||
for(var/obj/machinery/abductor/experiment/E in GLOB.machines)
|
||||
if(!istype(team, /datum/team/abductor_team))
|
||||
return FALSE
|
||||
var/datum/team/abductor_team/T = team
|
||||
if(E.team_number == T.team_number)
|
||||
return E.points >= target_amount
|
||||
return FALSE
|
||||
|
||||
/datum/game_mode/proc/update_abductor_icons_added(datum/mind/alien_mind)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_ABDUCTOR]
|
||||
hud.join_hud(alien_mind.current)
|
||||
set_antag_hud(alien_mind.current, ((alien_mind in abductors) ? "abductor" : "abductee"))
|
||||
|
||||
/datum/game_mode/proc/update_abductor_icons_removed(datum/mind/alien_mind)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_ABDUCTOR]
|
||||
hud.leave_hud(alien_mind.current)
|
||||
set_antag_hud(alien_mind.current, null)
|
||||
@@ -1,765 +0,0 @@
|
||||
#define STATE_JUDGE 0
|
||||
#define STATE_WRATH 1
|
||||
#define STATE_FLEE 2
|
||||
|
||||
/mob/living/simple_animal/hostile/hades
|
||||
name = "hades"
|
||||
real_name = "hades"
|
||||
desc = "A strange being, clad in dark robes. Their very presence radiates an uneasy power."
|
||||
speak_emote = list("preaches","announces","spits","conveys")
|
||||
emote_hear = list("hums.","prays.")
|
||||
response_help = "kneels before"
|
||||
response_disarm = "flails at"
|
||||
response_harm = "punches"
|
||||
icon = 'icons/mob/EvilPope.dmi'
|
||||
icon_state = "EvilPope"
|
||||
icon_living = "EvilPope"
|
||||
icon_dead = "popedeath"
|
||||
speed = 1
|
||||
a_intent = "harm"
|
||||
status_flags = CANPUSH
|
||||
attack_sound = 'sound/magic/MAGIC_MISSILE.ogg'
|
||||
death_sound = 'sound/magic/Teleport_diss.ogg'
|
||||
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
|
||||
faction = list("hades")
|
||||
attacktext = "strikes with an unholy rage at"
|
||||
maxHealth = 1000
|
||||
health = 1000
|
||||
healable = 0
|
||||
environment_smash = 3
|
||||
melee_damage_lower = 15
|
||||
melee_damage_upper = 20
|
||||
see_in_dark = 8
|
||||
see_invisible = SEE_INVISIBLE_MINIMUM
|
||||
loot = list(/obj/effect/decal/cleanable/blood)
|
||||
del_on_death = 0
|
||||
deathmessage = "begins to sizzle and pop, their flesh peeling away like paper."
|
||||
|
||||
var/isDoingDeath = FALSE
|
||||
var/isFleeing = FALSE
|
||||
var/fleeTimes = 0
|
||||
var/currentState = STATE_JUDGE
|
||||
var/rageLevel = 0
|
||||
|
||||
var/maxWrathTimer = 150
|
||||
var/lastWrathTimer = 0
|
||||
|
||||
var/timeBetweenGrabs = 60
|
||||
var/lastGrabTime = 0
|
||||
|
||||
var/list/validSins = list("Greed","Gluttony","Pride","Lust","Envy","Sloth","Wrath")
|
||||
var/lastsinPerson = 0
|
||||
var/sinPersonTime = 300
|
||||
var/lastFlee = 0
|
||||
var/fleeTimer = 30
|
||||
var/fakesinPersonChance = 60
|
||||
var/list/sinPersonsayings = list("You revel in only your own greed.",\
|
||||
"There is nothing but your absolution.",\
|
||||
"Your choices have led you to this.",\
|
||||
"There is only one way out.",\
|
||||
"The only way to be free is to be free of yourself.",\
|
||||
"Wallow in sin, and give yourself unto darkness.",\
|
||||
"Only the truly sinful may stand.",\
|
||||
"Find yourself and you will find Absolution.",\
|
||||
"Forego the pain of this process, and submit.",\
|
||||
"We can be one in suffering.",\
|
||||
"You stand on the precipice of ascension, give in.",\
|
||||
"You cannot fathom what lies beyond",\
|
||||
"Repent your sins.",\
|
||||
"This is the eve of your last days.",\
|
||||
"Darkness comes.")
|
||||
|
||||
var/list/creepyasssounds = list('sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/behind_you2.ogg', \
|
||||
'sound/hallucinations/growl3.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg',\
|
||||
'sound/hallucinations/i_see_you1.ogg', 'sound/hallucinations/i_see_you2.ogg',\
|
||||
'sound/hallucinations/look_up1.ogg', 'sound/hallucinations/look_up2.ogg', 'sound/hallucinations/over_here1.ogg',\
|
||||
'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg',\
|
||||
'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/turn_around2.ogg')
|
||||
|
||||
var/obj/effect/proc_holder/spell/targeted/lightning/sinLightning
|
||||
|
||||
var/list/currentAcolytes = list()
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/New()
|
||||
..()
|
||||
|
||||
sinLightning = new/obj/effect/proc_holder/spell/targeted/lightning(src)
|
||||
|
||||
sinLightning.charge_max = 1
|
||||
sinLightning.clothes_req = 0
|
||||
sinLightning.range = 32
|
||||
sinLightning.cooldown_min = 1
|
||||
|
||||
lastsinPerson = world.time
|
||||
var/list/possible_titles = list("Pope","Bishop","Lord","Cardinal","Deacon","Pontiff")
|
||||
var/chosen = "Hades, [pick(possible_titles)] of Sin"
|
||||
name = chosen
|
||||
real_name = chosen
|
||||
|
||||
world << "<span class='warning'><font size=4>[name] has entered your reality. Kneel before them.</font></span>"
|
||||
world << 'sound/effects/pope_entry.ogg'
|
||||
|
||||
Appear(get_turf(src))
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/handle_environment(datum/gas_mixture/environment)
|
||||
//space popes are from space, they need not your fickle "oxygen"
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/handle_temperature_damage()
|
||||
//space popes are from space, they don't uh.. something fire burny death
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/death(gibbed)
|
||||
if(!isDoingDeath)
|
||||
notransform = TRUE
|
||||
anchored = TRUE
|
||||
src.visible_message("<span class='warning'><font size=4>[src] begins to twist and distort, before snapping backwards with a sickening crunch.</font></span>")
|
||||
spawn(20)
|
||||
src.visible_message("<span class='warning'><font size=4>[src] is being sucked back to their own realm, destabilizing the fabric of time and space itself!</font></span>")
|
||||
playsound(get_turf(src), 'sound/effects/hyperspace_begin.ogg', 100, 1)
|
||||
isDoingDeath = TRUE
|
||||
AIStatus = AI_OFF
|
||||
SpinAnimation()
|
||||
for(var/i in 1 to 5)
|
||||
for(var/turf/T in spiral_range_turfs(i,src))
|
||||
addtimer(src, "sinShed", i*10, FALSE, T)
|
||||
spawn(60) // required to be spawn so we can call death's ..() to complete death.
|
||||
SpinAnimation(0,0)
|
||||
explosion(get_turf(src), 0, 2, 4, 6, flame_range = 6)
|
||||
..()
|
||||
var/area/A = locate(/area/hades) in world
|
||||
if(A)
|
||||
var/turf/T = get_turf(locate(/obj/effect/landmark/event_spawn) in A)
|
||||
if(T)
|
||||
src.visible_message("<span class='warning'><font size=4>[src]'s Staff is flung free as their body explodes.</font></span>")
|
||||
var/obj/structure/ladder/unbreakable/hades/churchLadder = new/obj/structure/ladder/unbreakable/hades(T)
|
||||
var/obj/structure/ladder/unbreakable/hades/bodyLadder = new/obj/structure/ladder/unbreakable/hades(get_turf(src))
|
||||
var/obj/item/hades_staff/HS = new/obj/item/hades_staff(get_turf(src))
|
||||
HS.throw_at_fast(pick(orange(src,7)),10,1)
|
||||
churchLadder.up = bodyLadder
|
||||
bodyLadder.down = churchLadder
|
||||
qdel(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
Defend(user,I)
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/grabbedby(mob/living/carbon/user, supress_message = 0)
|
||||
..()
|
||||
Defend(user,user)
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
|
||||
..()
|
||||
lastsinPerson -= (sinPersonTime/4)
|
||||
if(istype(AM,/obj/item))
|
||||
var/obj/item/throwCast = AM
|
||||
Defend(throwCast.thrownby,AM)
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/bullet_act(obj/item/projectile/P, def_zone)
|
||||
//don't call ..() because we're going to deflect it
|
||||
lastsinPerson -= (sinPersonTime/4)
|
||||
Defend(P.firer,P)
|
||||
return -1
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/attack_hand(mob/living/carbon/human/M)
|
||||
..()
|
||||
lastsinPerson -= (sinPersonTime/4)
|
||||
Defend(M,M)
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/proc/Defend(var/mob/attacker,var/source)
|
||||
if(!isDoingDeath)
|
||||
rageLevel += 5
|
||||
src.visible_message("<span class='warning'>[src] rounds on the [attacker], gazing at them with a [pick("cold","frosty","freezing","dark")] [pick("glare","gaze","glower","stare")].</span>")
|
||||
|
||||
if(istype(source,/obj/item/projectile))
|
||||
src.visible_message("<span class='warning'>[src] [pick("calmly","silently","nonchalantly")] waves their hand, deflecting the [source].</span>")
|
||||
var/obj/item/projectile/P = source
|
||||
if(P.starting)
|
||||
var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
|
||||
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
|
||||
var/turf/curloc = get_turf(src)
|
||||
|
||||
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
|
||||
P.Angle = null
|
||||
else
|
||||
if(prob(20))
|
||||
var/chosenDefend = rand(1,3)
|
||||
switch(chosenDefend)
|
||||
if(1)
|
||||
attacker.visible_message("<span class='warning'>[attacker] is lifted from the ground, shadowy powers tossing them aside.</span>")
|
||||
attacker.throw_at_fast(pick(orange(src,7)),10,1)
|
||||
if(2)
|
||||
attacker.visible_message("<span class='warning'>[attacker] crackles with electricity, a bolt leaping from [src] to them.</span>")
|
||||
sinLightning.Bolt(src,attacker,30,5,src)
|
||||
if(3)
|
||||
src.visible_message("<span class='warning'>[src] points his staff at [attacker], a swarm of eyeballs lurching fourth!</span>")
|
||||
for(var/i in 1 to 4)
|
||||
var/mob/living/simple_animal/hostile/carp/eyeball/E = new/mob/living/simple_animal/hostile/carp/eyeball(pick(orange(attacker,1)))
|
||||
E.faction = faction
|
||||
addtimer(E, "gib", 150, FALSE)
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/proc/sinShed(var/turf/T)
|
||||
var/obj/effect/overlay/temp/cult/sparks/S = PoolOrNew(/obj/effect/overlay/temp/cult/sparks, T)
|
||||
S.anchored = FALSE
|
||||
S.throw_at_fast(src,10,1)
|
||||
PoolOrNew(/obj/effect/overlay/temp/hadesBlood, T)
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/proc/Transfer(var/mob/living/taken, var/turf/transferTarget)
|
||||
if(transferTarget)
|
||||
playsound(get_turf(taken), 'sound/magic/Ethereal_Enter.ogg', 50, 1, -1)
|
||||
PoolOrNew(/obj/effect/overlay/temp/hadesFlick, get_turf(taken))
|
||||
taken.forceMove(transferTarget)
|
||||
Appear(get_turf(taken))
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/proc/Appear(var/turf/where)
|
||||
var/obj/effect/timestop/hades/TS = new /obj/effect/timestop/hades(where)
|
||||
TS.immune = list(src)
|
||||
|
||||
/mob/living/simple_animal/hostile/hades/Life()
|
||||
if(..() && !isDoingDeath) // appropriately check if we're alive now we leave a corpse
|
||||
if(health > maxHealth/4 && !isFleeing)
|
||||
if(rageLevel > 50)
|
||||
lastWrathTimer = world.time
|
||||
currentState = STATE_WRATH
|
||||
else
|
||||
currentState = STATE_JUDGE
|
||||
else
|
||||
if(world.time > lastFlee + fleeTimer)
|
||||
lastFlee = world.time
|
||||
isFleeing = TRUE
|
||||
currentState = STATE_FLEE
|
||||
|
||||
var/area/healthCheck = get_area(src)
|
||||
|
||||
if(istype(healthCheck,/area/chapel/main))
|
||||
if(currentState == STATE_FLEE)
|
||||
lastWrathTimer = world.time
|
||||
currentState = STATE_WRATH
|
||||
if(health < maxHealth/2)
|
||||
health += 10 // slowly regain hp in the chapel, up to a maximum of half our max
|
||||
|
||||
var/spokenThisTurn = FALSE
|
||||
for(var/mob/living/A in currentAcolytes)
|
||||
if(!A)
|
||||
currentAcolytes -= A
|
||||
continue
|
||||
if(A.health <= 0)
|
||||
rageLevel += 5
|
||||
if(!spokenThisTurn)
|
||||
spokenThisTurn = TRUE
|
||||
var/list/lossSayings = list("They were weak.","For every death, two more rise.",\
|
||||
"What is but one servant lost?","Darkness engulf you!","To the Pit with them.",\
|
||||
"Fools! All of you!","You can't stop me. You. Will. Be. JUDGED.")
|
||||
src.say(pick(lossSayings))
|
||||
currentAcolytes -= A
|
||||
A.gib()
|
||||
|
||||
if(currentState == STATE_WRATH) // we have been enraged.
|
||||
if(world.time > lastWrathTimer + maxWrathTimer)
|
||||
rageLevel = 0 // wind down if we're wrathful too long.
|
||||
rageLevel -= 1 // rage phase starts at 50, meaning roughly 20s of rage.
|
||||
if(currentAcolytes.len == 0)
|
||||
src.say("Rise, Servants. AID YOUR MASTER.")
|
||||
playsound(get_turf(src), 'sound/magic/CastSummon.ogg', 100, 1)
|
||||
for(var/i in 1 to 5)
|
||||
var/mob/living/simple_animal/hostile/hadesacolyte/HA = new/mob/living/simple_animal/hostile/hadesacolyte(get_turf(pick(orange(2,src))))
|
||||
HA.master = src
|
||||
currentAcolytes += HA
|
||||
if(target)
|
||||
if(world.time > lastGrabTime + timeBetweenGrabs)
|
||||
if(get_dist(src,target) > 4) // you can't run from us. upped to 4 to give more leeway.
|
||||
lastGrabTime = world.time
|
||||
var/list/fleeSayings = list("There is no escape from your sins, [target]","Fleeing will only make your punishment worse [target]!",\
|
||||
"There is nowhere you can hide, [target]!","You can't run, [target]!","Get back here, [target]!","You coward, [target]!",\
|
||||
"I will find you, [target]!","Return to me, [target]!")
|
||||
src.say(pick(fleeSayings))
|
||||
var/mob/living/toGrab = target
|
||||
toGrab.Beam(src,"blood",'icons/effects/beam.dmi',10)
|
||||
toGrab.Weaken(6)
|
||||
playsound(get_turf(src), 'sound/magic/CastSummon.ogg', 100, 1)
|
||||
toGrab.throw_at_fast(src,10,1)
|
||||
if(rageLevel >= 100)
|
||||
rageLevel = 50
|
||||
var/list/overboardSayings = list("Ashes! It will all be ashes!","I will bring about the apocolypse!",\
|
||||
"There will be nothing but your withered husks!","Face your doom, cretins!","There. Will. Be. ORDER!",\
|
||||
"I am your Lord, lay down your arms and submit.","Your souls will be cremated!",\
|
||||
"Only in death will you obey!","This is no person's fault but your own!")
|
||||
src.say(pick(overboardSayings))
|
||||
var/turf/StartLoc = get_turf(src)
|
||||
var/list/nearby = orange(6,src)
|
||||
var/slashCount = 0
|
||||
var/aoeType = rand(1,2) // just for future proofing
|
||||
for(var/mob/living/A in nearby)
|
||||
slashCount++
|
||||
A.Beam(src,"blood",'icons/effects/beam.dmi',10)
|
||||
spawn(slashCount + 3)
|
||||
if(aoeType == 1)
|
||||
// no more cheaping it out with non-player mobs like turrets or carps
|
||||
loc = get_turf(A)
|
||||
sinShed(StartLoc)
|
||||
A.attack_animal(src)
|
||||
PoolOrNew(/obj/effect/overlay/temp/hadesBlood,get_turf(A))
|
||||
playsound(get_turf(A), 'sound/magic/SummonItems_generic.ogg', 100, 1)
|
||||
if(aoeType == 2)
|
||||
sinShed(StartLoc)
|
||||
PoolOrNew(/obj/effect/overlay/temp/hadesBite,get_turf(A))
|
||||
A.Weaken(6)
|
||||
var/obj/effect/timestop/hades/large/TS = new /obj/effect/timestop/hades/large(StartLoc)
|
||||
TS.immune = list(src)
|
||||
spawn((slashCount+1)+3)
|
||||
loc = StartLoc
|
||||
|
||||
if(currentState == STATE_FLEE) // we've been wounded, let us flee and lick our wounds
|
||||
var/area/A = locate(/area/chapel/main) in world
|
||||
if(A)
|
||||
var/turf/T = get_turf(locate(/obj/effect/landmark/event_spawn) in A)
|
||||
if(!T)
|
||||
T = get_turf(src) // no event spawn in chapel, fall back to doing it on the spot.
|
||||
if(T)
|
||||
fleeTimes++
|
||||
Transfer(src,T)
|
||||
AIStatus = AI_OFF
|
||||
notransform = TRUE
|
||||
anchored = TRUE
|
||||
for(var/i in 1 to 5)
|
||||
spawn(i*10)
|
||||
for(var/turf/S in oview(i,src) - oview((i)-1,src))
|
||||
sinShed(S)
|
||||
health += maxHealth/(10*fleeTimes) // every flee we gain less HP
|
||||
spawn(50)
|
||||
isFleeing = FALSE
|
||||
notransform = FALSE
|
||||
anchored = FALSE
|
||||
AIStatus = AI_ON
|
||||
currentState = STATE_JUDGE
|
||||
lastsinPerson = 0 // immediately teleport away to judge
|
||||
|
||||
if(currentState == STATE_JUDGE) // our default state, judge a few people and tell them they're rude or something
|
||||
if(world.time > lastsinPerson + sinPersonTime)
|
||||
if(prob(fakesinPersonChance))
|
||||
lastsinPerson = world.time
|
||||
visible_message("<span class='warning'><font size=3>[pick(sinPersonsayings)]</font></span>")
|
||||
playsound(get_turf(src), pick(creepyasssounds), 100, 1)
|
||||
else
|
||||
lastsinPerson = world.time
|
||||
var/mob/living/carbon/human/sinPerson = pick(living_mob_list)
|
||||
var/depth = living_mob_list.len + 1 // just in case
|
||||
if(sinPerson) // no more finding nullcakes
|
||||
if(!sinPerson.ckey)
|
||||
while(!sinPerson.ckey && depth > 0)
|
||||
--depth
|
||||
var/checkPerson = pick(living_mob_list)
|
||||
if(checkPerson)
|
||||
sinPerson = checkPerson
|
||||
if(!sinPerson.ckey)
|
||||
// double check ensure that if the above loop fails to get a ckey target
|
||||
// we don't go and use the last mob checked, causing odd situations
|
||||
return
|
||||
if(sinPerson)
|
||||
if(prob(65)) // moderately high chance for us to go to them, else they come here.
|
||||
Transfer(src,get_turf(pick(oview(1,sinPerson))))
|
||||
else
|
||||
Transfer(sinPerson,get_turf(pick(oview(1,src))))
|
||||
var/sinPersonchoice = pick(validSins)
|
||||
switch(sinPersonchoice)
|
||||
if("Greed")
|
||||
src.say("Your sin, [sinPerson], is Greed.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Greed(sinPerson, TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Greed(sinPerson, FALSE)
|
||||
if("Gluttony")
|
||||
src.say("Your sin, [sinPerson], is Gluttony.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Gluttony(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Gluttony(sinPerson,FALSE)
|
||||
if("Pride")
|
||||
src.say("Your sin, [sinPerson], is Pride.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Pride(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Pride(sinPerson,FALSE)
|
||||
if("Lust")
|
||||
src.say("Your sin, [sinPerson], is Lust.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Lust(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Lust(sinPerson,TRUE)
|
||||
if("Envy")
|
||||
src.say("Your sin, [sinPerson], is Envy.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Envy(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Envy(sinPerson,FALSE)
|
||||
if("Sloth")
|
||||
src.say("Your sin, [sinPerson], is Sloth.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Sloth(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Sloth(sinPerson,FALSE)
|
||||
if("Wrath")
|
||||
src.say("Your sin, [sinPerson], is Wrath.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Wrath(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Wrath(sinPerson,FALSE)
|
||||
|
||||
|
||||
///Sin related things
|
||||
|
||||
//global Sin procs, shared between staff and pope
|
||||
|
||||
/proc/sin_Greed(var/mob/living/carbon/human/sinPerson, var/isIndulged)
|
||||
if(isIndulged)
|
||||
sinPerson << "<span class='warning'>You feel like you deserve more, in fact, you want everything.</span>"
|
||||
var/list/greed = list(/obj/item/stack/sheet/mineral/gold,/obj/item/stack/sheet/mineral/silver,/obj/item/stack/sheet/mineral/diamond)
|
||||
for(var/i in 1 to 10)
|
||||
var/greed_type = pick(greed)
|
||||
new greed_type(get_turf(sinPerson))
|
||||
else
|
||||
sinPerson << "<span class='warning'>Your body begins to shift and bend, changing to reflect your inner greed.</span>"
|
||||
var/mob/living/M = sinPerson.change_mob_type(/mob/living/simple_animal/cockroach,get_turf(sinPerson),"Greedroach",1)
|
||||
M.AddSpell(new/obj/effect/proc_holder/spell/targeted/mind_transfer)
|
||||
|
||||
/proc/sin_Gluttony(var/mob/living/carbon/human/sinPerson, var/isIndulged)
|
||||
if(isIndulged)
|
||||
sinPerson << "<span class='warning'>Your stomach growls, you feel hungry.</span>"
|
||||
var/list/allTypes = list()
|
||||
for(var/A in typesof(/obj/item/reagent_containers/food/snacks))
|
||||
var/obj/item/reagent_containers/food/snacks/O = A
|
||||
if(initial(O.cooked_type))
|
||||
allTypes += A
|
||||
for(var/i in 1 to 10)
|
||||
var/greed_type = pick(allTypes)
|
||||
new greed_type(get_turf(sinPerson))
|
||||
else
|
||||
sinPerson << "<span class='warning'>Your body begins to bloat and stretch, bile rising in your throat.</span>"
|
||||
sinPerson.reagents.add_reagent("nutriment",1000)
|
||||
|
||||
/proc/sin_Pride(var/mob/living/carbon/human/sinPerson, var/isIndulged)
|
||||
if(isIndulged)
|
||||
sinPerson << "<span class='warning'>You feel strong enough to take on the world.</span>"
|
||||
var/obj/item/twohanded/sin_pride/good = new/obj/item/twohanded/sin_pride(get_turf(sinPerson))
|
||||
good.name = "Indulged [good.name]"
|
||||
good.pride_direction = FALSE
|
||||
else
|
||||
sinPerson << "<span class='warning'>You feel small and weak, like the entire world is against you.</span>"
|
||||
var/obj/item/twohanded/sin_pride/bad = new/obj/item/twohanded/sin_pride(get_turf(sinPerson))
|
||||
bad.name = "Punished [bad.name]"
|
||||
bad.pride_direction = TRUE
|
||||
|
||||
/proc/sin_Lust(var/mob/living/carbon/human/sinPerson, var/isIndulged)
|
||||
if(isIndulged)
|
||||
sinPerson << "<span class='warning'>You feel confident, like everything and everyone is drawn to you.</span>"
|
||||
var/obj/item/lovestone/good = new/obj/item/lovestone(get_turf(sinPerson))
|
||||
good.name = "Indulged [good.name]"
|
||||
good.lust_direction = FALSE
|
||||
else
|
||||
sinPerson << "<span class='warning'>You feel lonely... the wish for the warmth of another spark through your mind.</span>"
|
||||
var/obj/item/lovestone/bad = new/obj/item/lovestone(get_turf(sinPerson))
|
||||
bad.name = "Punished [bad.name]"
|
||||
bad.lust_direction = TRUE
|
||||
|
||||
/proc/sin_Envy(var/mob/living/carbon/human/sinPerson, var/isIndulged)
|
||||
if(isIndulged)
|
||||
for(var/mob/living/carbon/human/H in player_list) // name lottery
|
||||
if(H == sinPerson)
|
||||
continue
|
||||
if(prob(25))
|
||||
sinPerson.name = H.name
|
||||
sinPerson.real_name = H.real_name
|
||||
var/datum/dna/lottery = H.dna
|
||||
lottery.transfer_identity(sinPerson, transfer_SE=1)
|
||||
sinPerson.updateappearance(mutcolor_update=1)
|
||||
sinPerson.domutcheck()
|
||||
sinPerson << "<span class='warning'>You feel envious of [sinPerson.name], and your body shifts to reflect that!</span>"
|
||||
else
|
||||
var/sinPersonspecies = pick(species_list)
|
||||
var/newtype = species_list[sinPersonspecies]
|
||||
sinPerson << "<span class='warning'>You wish for more from yourself.. your body shifts to suit your wish.</span>"
|
||||
sinPerson.set_species(newtype)
|
||||
|
||||
/proc/sin_Sloth(var/mob/living/carbon/human/sinPerson, var/isIndulged)
|
||||
if(isIndulged)
|
||||
sinPerson << "<span class='warning'>You feel tired...</span>"
|
||||
sinPerson.drowsyness += 100
|
||||
else
|
||||
sinPerson << "<span class='warning'>A chill comes over your body, the feeling of frostbite nipping at your fingers.</span>"
|
||||
sinPerson.reagents.add_reagent("frostoil", 50)
|
||||
|
||||
/proc/sin_Wrath(var/mob/living/carbon/human/sinPerson, var/isIndulged)
|
||||
if(isIndulged)
|
||||
sinPerson << "<span class='warning'>You feel wrathful, like you want to destroy everyone and everything.</span>"
|
||||
sinPerson.change_mob_type(/mob/living/simple_animal/slaughter,get_turf(sinPerson),"Wrath Demon",1)
|
||||
else
|
||||
sinPerson << "<span class='warning'>Your chest feels tight, and the world begins to spin around you.</span>"
|
||||
sinPerson.reagents.add_reagent("lexorin", 29)
|
||||
sinPerson.reagents.add_reagent("mindbreaker", 29)
|
||||
|
||||
/obj/effect/overlay/temp/hadesFlick
|
||||
name = "transdimensional waste"
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "liquify"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/overlay/temp/hadesBite
|
||||
name = "biting tendril"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "tendril_bite"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/overlay/temp/hadesBlood
|
||||
name = "blood plume"
|
||||
icon = 'icons/effects/128x128.dmi'
|
||||
icon_state = "spray_plume"
|
||||
duration = 30
|
||||
|
||||
/obj/effect/timestop/hades // custom timeslip to make him immune
|
||||
name = "Frozen Time"
|
||||
desc = "Time has slowed to a halt."
|
||||
|
||||
/obj/effect/timestop/hades/New()
|
||||
spawn(5)
|
||||
..()
|
||||
|
||||
/obj/effect/timestop/hades/large
|
||||
freezerange = 6
|
||||
icon_state = "huge_rune"
|
||||
icon = 'icons/effects/224x224.dmi'
|
||||
|
||||
|
||||
/obj/item/twohanded/sin_pride
|
||||
icon_state = "mjollnir0"
|
||||
name = "Pride-struck Hammer"
|
||||
desc = "It resonates an aura of Pride."
|
||||
force = 5
|
||||
throwforce = 15
|
||||
w_class = 4
|
||||
slot_flags = SLOT_BACK
|
||||
force_unwielded = 5
|
||||
force_wielded = 20
|
||||
attack_verb = list("attacked", "smashed", "crushed", "splattered", "cracked")
|
||||
hitsound = 'sound/weapons/blade1.ogg'
|
||||
var/pride_direction = FALSE
|
||||
|
||||
/obj/item/twohanded/sin_pride/update_icon()
|
||||
icon_state = "mjollnir[wielded]"
|
||||
return
|
||||
|
||||
/obj/item/twohanded/sin_pride/afterattack(atom/A as mob|obj|turf|area, mob/user, proximity)
|
||||
if(!proximity) return
|
||||
if(wielded)
|
||||
if(istype(A,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/H = A
|
||||
var/mob/living/carbon/U = user
|
||||
if(H)
|
||||
if(pride_direction == FALSE)
|
||||
U.reagents.trans_to(H, user.reagents.total_volume, 1, 1, 0)
|
||||
U << "Your pride reflects on [H]."
|
||||
if(H.health > 0)
|
||||
U.health += force
|
||||
U.updatehealth()
|
||||
H.health -= force
|
||||
H.updatehealth()
|
||||
H << "You feel insecure, taking on [user]'s burden."
|
||||
else if(pride_direction == TRUE)
|
||||
H.reagents.trans_to(user, H.reagents.total_volume, 1, 1, 0)
|
||||
H << "Your pride reflects on [user]."
|
||||
if(U.health > 0)
|
||||
U.health -= force
|
||||
U.updatehealth()
|
||||
H.health += force
|
||||
H.updatehealth()
|
||||
U << "You feel insecure, taking on [H]'s burden."
|
||||
|
||||
/obj/item/lovestone
|
||||
name = "Stone of Lust"
|
||||
desc = "It lays within your hand, radiating pulses of uncomfortable warmth."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "lovestone"
|
||||
item_state = "lovestone"
|
||||
w_class = 1
|
||||
var/lust_direction = FALSE
|
||||
var/lastUsage = 0
|
||||
var/usageTimer = 300
|
||||
|
||||
/obj/item/lovestone/attack_self(mob/user)
|
||||
if(world.time > lastUsage + usageTimer)
|
||||
lastUsage = world.time
|
||||
user.visible_message("<span class='warning'>[user] grips the [src] tightly, causing it to vibrate and pulse brightly.</span>")
|
||||
spawn(25)
|
||||
if(lust_direction == FALSE)
|
||||
var/list/throwAt = list()
|
||||
for(var/atom/movable/AM in oview(7,user))
|
||||
if(!AM.anchored && AM != user)
|
||||
throwAt.Add(AM)
|
||||
for(var/counter = 1, counter < throwAt.len, ++counter)
|
||||
var/atom/movable/cast = throwAt[counter]
|
||||
cast.throw_at_fast(user,10,1)
|
||||
else if(lust_direction == 1)
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/mob/living/carbon/human/foundLover = locate(/mob/living/carbon/human) in orange(3,H)
|
||||
if(!foundLover)
|
||||
H << "As you hold the stone, loneliness grips you, your heart feeling heavy and you struggle to breath."
|
||||
for(var/i in 1 to 10)
|
||||
addtimer(H.reagents, "add_reagent", i*10, FALSE, "initropidril", i)
|
||||
else
|
||||
H << "You take comfort in the presence of [foundLover]"
|
||||
H.reagents.add_reagent("omnizine",25)
|
||||
H.Beam(foundLover,"r_beam",'icons/effects/beam.dmi',10)
|
||||
foundLover << "You take comfort in the presence of [H]"
|
||||
foundLover.reagents.add_reagent("omnizine",25)
|
||||
else
|
||||
user << "The stone lays inert. It is still recharging."
|
||||
|
||||
/mob/living/simple_animal/hostile/hadesacolyte
|
||||
name = "Acolyte of Hades"
|
||||
desc = "Darkness seethes from their every pore."
|
||||
icon_state = "hades_acolyte"
|
||||
icon_living = "hades_acolyte"
|
||||
icon_dead = "hades_acolyte_dead"
|
||||
speak_chance = 0
|
||||
turns_per_move = 5
|
||||
response_help = "trembles in fear of"
|
||||
response_disarm = "slaps wildly at"
|
||||
response_harm = "hits"
|
||||
speed = 1
|
||||
maxHealth = 45
|
||||
health = 45
|
||||
|
||||
harm_intent_damage = 5
|
||||
melee_damage_lower = 5
|
||||
melee_damage_upper = 15
|
||||
attacktext = "strikes at"
|
||||
attack_sound = 'sound/weapons/bladeslice.ogg'
|
||||
|
||||
butcher_results = list(/obj/item/clothing/mask/gas/cyborg/hades = 1,/obj/item/clothing/suit/hooded/chaplain_hoodie/hades = 1,/obj/item/hades_staff/fake = 1)
|
||||
|
||||
unsuitable_atmos_damage = 0
|
||||
del_on_death = 0
|
||||
faction = list("hades")
|
||||
|
||||
var/mob/living/simple_animal/hostile/hades/master
|
||||
|
||||
/mob/living/simple_animal/hostile/hadesacolyte/Life()
|
||||
if(..())
|
||||
if(master)
|
||||
if(get_dist(src,master) > 5)
|
||||
PoolOrNew(/obj/effect/overlay/temp/hadesFlick,get_turf(src))
|
||||
src.visible_message("<span class='warning'>[src] twists and distorts, before vanishing in a snap.</span>")
|
||||
src.forceMove(get_turf(pick(orange(2,master))))
|
||||
|
||||
//acolyte of hades outfit
|
||||
/obj/item/clothing/mask/gas/cyborg/hades
|
||||
name = "Skull Mask"
|
||||
desc = "It's a skull mask, made of a thin, cool metal."
|
||||
|
||||
/obj/item/clothing/suit/hooded/chaplain_hoodie/hades
|
||||
name = "Dark robes"
|
||||
desc = "A dark, soft robe."
|
||||
hooded = 1
|
||||
hoodtype = /obj/item/clothing/head/chaplain_hood/hades
|
||||
|
||||
/obj/item/clothing/head/chaplain_hood/hades
|
||||
name = "Dark hood"
|
||||
desc = "A dark, soft hood."
|
||||
body_parts_covered = HEAD
|
||||
flags_inv = HIDEHAIR|HIDEEARS
|
||||
//end hades outfit
|
||||
|
||||
/obj/item/hades_summoner
|
||||
name = "Dark Seed"
|
||||
desc = "The stone lays inert, but even when holding it you hear maddened whispers."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "dark_seed_inert"
|
||||
item_state = "dark_seed_inert"
|
||||
w_class = 1
|
||||
var/isActivated = FALSE
|
||||
var/whoActivated
|
||||
var/countDownToSummon = 10
|
||||
var/absorbedHP = 0
|
||||
|
||||
/obj/item/hades_summoner/attack_self(mob/user)
|
||||
if(!isActivated)
|
||||
var/choice = input(user,"Rub the stone?",name) in list("Yes","No")
|
||||
if(choice == "Yes")
|
||||
if(prob(15))
|
||||
user << "<span class='warning'><font size=3>You rub the stone.. and a voice springs fourth!</font></span>"
|
||||
user << "<span class='warning'><font size=3>You hear a voice in your head.. 'Bring me the flesh of a living being.. and we shall bargain.'</font></span>"
|
||||
whoActivated = user
|
||||
isActivated = TRUE
|
||||
desc = "The stone hums with a soft glow, whispering to you."
|
||||
icon_state = "dark_seed"
|
||||
else
|
||||
user << "<span class='warning'><font size=3>The stone shivers, but nothing happens. Perhaps try again later?</font></span>"
|
||||
else
|
||||
if(user != whoActivated)
|
||||
user << "<span class='warning'><font size=3>The stone lays inert.</font></span>"
|
||||
else
|
||||
if(countDownToSummon > 0)
|
||||
user << "<span class='warning'><font size=3>You hear a voice in your head.. 'I still require [countDownToSummon] vessels worth of flesh. Bring them to me'</font></span>"
|
||||
else
|
||||
user << "<span class='warning'><font size=3>I thank you, acolyte.</font></span>"
|
||||
var/mob/living/simple_animal/hostile/hadesacolyte/HA = user.change_mob_type(/mob/living/simple_animal/hostile/hadesacolyte,get_turf(user),"[user.name]",1)
|
||||
var/mob/living/simple_animal/hostile/hades/H = new/mob/living/simple_animal/hostile/hades(get_turf(user))
|
||||
H.maxHealth = absorbedHP
|
||||
H.health = H.maxHealth
|
||||
if(H.maxHealth < initial(H.maxHealth))
|
||||
HA << "<span class='warning'><font size=3>You.. you fool! How dare you summon me with such dirty flesh!</font></span>"
|
||||
HA.faction -= "hades"
|
||||
if(H.maxHealth > initial(H.maxHealth))
|
||||
HA << "<span class='warning'><font size=3>Such.. power! You have exceeded yourself, acolyte. Drink of my might!</font></span>"
|
||||
HA.maxHealth = 250
|
||||
HA.health = 250
|
||||
qdel(src)
|
||||
|
||||
/obj/item/hades_summoner/afterattack(atom/A as mob|obj|turf|area, mob/user, proximity)
|
||||
if(!proximity)
|
||||
return
|
||||
if(istype(A,/mob/living))
|
||||
var/mob/living/M = A
|
||||
if(countDownToSummon > 0)
|
||||
if(M.health > 0 && M.maxHealth > 200)
|
||||
// no absorbing super strong creatures unless they're dead
|
||||
user << "<span class='warning'><font size=3>Such power.. Slay this [M] so that I may partake of its being.</font></span>"
|
||||
return
|
||||
if(!M.stat)
|
||||
user << "<span class='warning'><font size=3>[M] is still too tightly bound to the mortal world! You must either kill or knock them unconscious to sacrifice them.</font></span>"
|
||||
return
|
||||
user << "<span class='warning'><font size=3>I accept your offering.</font></span>"
|
||||
absorbedHP += M.maxHealth
|
||||
if(!M.ckey)
|
||||
M.gib()
|
||||
else
|
||||
M << "<span class='warning'><font size=3>You feel the flesh being stripped from your bones. You're overwhelmed with maddening pain, before reforming into another being!</font></span>"
|
||||
M.change_mob_type(/mob/living/simple_animal/hostile/hadesacolyte,get_turf(user),"[user.name]",1)
|
||||
countDownToSummon--
|
||||
if(countDownToSummon <= 0)
|
||||
user << "<span class='warning'><font size=3>I am ready to ascend, my acolyte.</font></span>"
|
||||
|
||||
|
||||
#undef STATE_JUDGE
|
||||
#undef STATE_WRATH
|
||||
#undef STATE_FLEE
|
||||
@@ -1,177 +0,0 @@
|
||||
/area/hades
|
||||
name = "Chapel of Sin"
|
||||
icon_state = "yellow"
|
||||
requires_power = 0
|
||||
has_gravity = 1
|
||||
|
||||
/turf/open/floor/plasteel/hades
|
||||
name = "Sin-touched Floor"
|
||||
icon_state = "cult"
|
||||
|
||||
/obj/structure/chair/hades
|
||||
name = "Cross of Hades"
|
||||
desc = "An inverted cross, with straps on it to support the weight of a living being."
|
||||
icon_state = "chair_hades"
|
||||
var/list/watchedSpikes = list()
|
||||
|
||||
/obj/structure/chair/hades/New()
|
||||
..()
|
||||
flags_1 |= NODECONSTRUCT_1
|
||||
for(var/obj/structure/kitchenspike/KS in range(12))
|
||||
watchedSpikes += KS
|
||||
|
||||
/obj/structure/chair/hades/proc/considerReady()
|
||||
//buckled_mobs seems to work inconsistently, so we're doing some custom searching here.
|
||||
if(!buckled_mobs)
|
||||
return FALSE
|
||||
if(!buckled_mobs.len)
|
||||
return FALSE
|
||||
for(var/obj/structure/kitchenspike/KS in watchedSpikes)
|
||||
var/mob/living/M = locate(/mob/living) in get_turf(KS)
|
||||
if(!M)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/structure/chair/hades/proc/completeRitual()
|
||||
for(var/obj/structure/kitchenspike/KS in watchedSpikes)
|
||||
var/mob/living/M = locate(/mob/living) in get_turf(KS)
|
||||
M.gib()
|
||||
playsound(get_turf(src), 'sound/effects/pope_entry.ogg', 100, 1)
|
||||
sleep(100)
|
||||
playsound(get_turf(src), 'sound/effects/hyperspace_end.ogg', 100, 1)
|
||||
new/obj/item/hades_staff/imbued(get_turf(src))
|
||||
src.visible_message("<span class='warning'>[src] shatters into a thousand shards, a staff falling from it.</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/chair/hades/attackby(obj/item/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/hades_staff))
|
||||
var/obj/item/hades_staff/HS = W
|
||||
if(!HS.isKey)
|
||||
return
|
||||
src.visible_message("<span class='warning'>[user] inserts the [W] into the [src], giving it a quick turn.</span>")
|
||||
if(considerReady())
|
||||
qdel(W)
|
||||
src.visible_message("<span class='warning'>[src] shudders, the sound of moving gears arising...</span>")
|
||||
for(var/mob/living/M in buckled_mobs)
|
||||
M.gib()
|
||||
for(var/i in 1 to 4)
|
||||
addtimer(GLOBAL_PROC, "playsound", i*10, FALSE, get_turf(src), 'sound/effects/clang.ogg', 100, 1)
|
||||
spawn(50)
|
||||
src.visible_message("<span class='warning'>[src] begins to lower into the ground...</span>")
|
||||
icon_state = "chair_hades_slide"
|
||||
addtimer(src, "completeRitual", 50, FALSE)
|
||||
else
|
||||
src.visible_message("<span class='warning'>[src] clunks, the sound of grinding gears arising. Nothing happens.</span>")
|
||||
|
||||
/obj/structure/ladder/unbreakable/hades
|
||||
name = "Dimensional Rift"
|
||||
desc = "Where does it lead?"
|
||||
icon = 'icons/mob/EvilPope.dmi'
|
||||
icon_state = "popedeath"
|
||||
anchored = TRUE
|
||||
|
||||
/obj/structure/ladder/unbreakable/hades/update_icon()
|
||||
return
|
||||
|
||||
/obj/item/paper/hades_instructions
|
||||
name = "paper- 'Hastily Scrawled Letter'"
|
||||
info = "The Master has instructed us to collect corpses for the ritual, and told us to deposity them in the Ritual Room, behind a bookcase in the library. The Master has locked the device to only work with his key, so no more accidents happen."
|
||||
|
||||
/obj/item/hades_staff
|
||||
name = "Staff of Hades"
|
||||
desc = "A large, dark staff, with a set of key-like prongs on the end."
|
||||
icon_state = "staffofchange"
|
||||
icon = 'icons/obj/guns/magic.dmi'
|
||||
item_state = "staffofchange"
|
||||
slot_flags = SLOT_BELT | SLOT_BACK
|
||||
force = 25
|
||||
throwforce = 5
|
||||
w_class = 3
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("slapped", "shattered", "blasphemed", "smashed", "whacked", "crushed", "hammered")
|
||||
block_chance = 25
|
||||
var/isKey = 1
|
||||
|
||||
/obj/item/hades_staff/fake
|
||||
name = "Inert Staff of Hades"
|
||||
desc = "A large, dark staff."
|
||||
isKey = 0
|
||||
|
||||
/obj/item/hades_staff/imbued
|
||||
name = "Imbued Staff of Hades"
|
||||
desc = " Bestowed with the power of wayward souls, this Staff allows the wielder to judge a target."
|
||||
force = 75
|
||||
throwforce = 35
|
||||
block_chance = 75
|
||||
var/lastJudge = 0
|
||||
var/judgeCooldown = 150
|
||||
|
||||
/obj/item/hades_staff/imbued/attack(mob/living/carbon/human/M, mob/living/carbon/human/user)
|
||||
if(!istype(M))
|
||||
return ..()
|
||||
|
||||
if(world.time > lastJudge + judgeCooldown)
|
||||
var/mob/living/sinPerson = M
|
||||
lastJudge = world.time
|
||||
var/sinPersonchoice = pick("Greed","Gluttony","Pride","Lust","Envy","Sloth","Wrath")
|
||||
switch(sinPersonchoice)
|
||||
if("Greed")
|
||||
src.say("Your sin, [sinPerson], is Greed.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Greed(sinPerson, TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Greed(sinPerson, FALSE)
|
||||
if("Gluttony")
|
||||
src.say("Your sin, [sinPerson], is Gluttony.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Gluttony(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Gluttony(sinPerson,FALSE)
|
||||
if("Pride")
|
||||
src.say("Your sin, [sinPerson], is Pride.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Pride(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Pride(sinPerson,FALSE)
|
||||
if("Lust")
|
||||
src.say("Your sin, [sinPerson], is Lust.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Lust(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Lust(sinPerson,TRUE)
|
||||
if("Envy")
|
||||
src.say("Your sin, [sinPerson], is Envy.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Envy(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Envy(sinPerson,FALSE)
|
||||
if("Sloth")
|
||||
src.say("Your sin, [sinPerson], is Sloth.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Sloth(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Sloth(sinPerson,FALSE)
|
||||
if("Wrath")
|
||||
src.say("Your sin, [sinPerson], is Wrath.")
|
||||
if(prob(50))
|
||||
src.say("I will indulge your sin, [sinPerson].")
|
||||
sin_Wrath(sinPerson,TRUE)
|
||||
else
|
||||
src.say("Your sin will be punished, [sinPerson]!")
|
||||
sin_Wrath(sinPerson,FALSE)
|
||||
else
|
||||
..()
|
||||
user << "The [src] is still recharging."
|
||||
@@ -1,12 +0,0 @@
|
||||
This folder contains all "mini-antagonists" - antagonists that can still spice up the round but aren't enough to be a roundtype in their own right.
|
||||
Currently, that list consists of:
|
||||
-Abductors
|
||||
-Borers
|
||||
-Swarmers
|
||||
-Prophets of sin
|
||||
-The Jungle Fever virus (infected monkey bites human, human becomes another infected monkey)
|
||||
-Morphs
|
||||
-Sintouched crewmembers
|
||||
-Slaughter demons
|
||||
-Umbras (formerly revenants)
|
||||
Please update this if you add another mini-antagonist.
|
||||
@@ -52,7 +52,7 @@
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/proc/are_operatives_dead()
|
||||
for(var/datum/mind/operative_mind in get_antagonists(/datum/antagonist/nukeop))
|
||||
for(var/datum/mind/operative_mind in get_antag_minds(/datum/antagonist/nukeop))
|
||||
if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -687,7 +687,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
if("Chief Medical Officer")
|
||||
department_string = "medical"
|
||||
|
||||
var/list/lings = get_antagonists(/datum/antagonist/changeling,TRUE)
|
||||
var/list/lings = get_antag_minds(/datum/antagonist/changeling,TRUE)
|
||||
var/ling_count = lings.len
|
||||
|
||||
for(var/datum/mind/M in SSticker.minds)
|
||||
@@ -715,7 +715,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
//Needed heads is between min_lings and the maximum possible amount of command roles
|
||||
//So at the time of writing, rand(3,6), it's also capped by the amount of lings there are
|
||||
//Because you can't fill 6 head roles with 3 lings
|
||||
var/list/lings = get_antagonists(/datum/antagonist/changeling,TRUE)
|
||||
var/list/lings = get_antag_minds(/datum/antagonist/changeling,TRUE)
|
||||
var/needed_heads = rand(min_lings,GLOB.command_positions.len)
|
||||
needed_heads = min(lings.len,needed_heads)
|
||||
|
||||
@@ -792,7 +792,7 @@ GLOBAL_LIST_EMPTY(possible_items_special)
|
||||
//Check each staff member has been replaced, by cross referencing changeling minds, changeling current dna, the staff minds and their original DNA names
|
||||
var/success = 0
|
||||
changelings:
|
||||
for(var/datum/mind/changeling in get_antagonists(/datum/antagonist/changeling,TRUE))
|
||||
for(var/datum/mind/changeling in get_antag_minds(/datum/antagonist/changeling,TRUE))
|
||||
if(success >= department_minds.len) //We did it, stop here!
|
||||
return TRUE
|
||||
if(ishuman(changeling.current))
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
//A barebones antagonist team.
|
||||
/datum/objective_team
|
||||
var/list/datum/mind/members = list()
|
||||
var/name = "team"
|
||||
var/member_name = "member"
|
||||
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
|
||||
|
||||
/datum/objective_team/New(starting_members)
|
||||
. = ..()
|
||||
if(starting_members)
|
||||
if(islist(starting_members))
|
||||
for(var/datum/mind/M in starting_members)
|
||||
add_member(M)
|
||||
else
|
||||
add_member(starting_members)
|
||||
|
||||
/datum/objective_team/proc/is_solo()
|
||||
return members.len == 1
|
||||
|
||||
/datum/objective_team/proc/add_member(datum/mind/new_member)
|
||||
members |= new_member
|
||||
|
||||
/datum/objective_team/proc/remove_member(datum/mind/member)
|
||||
members -= member
|
||||
|
||||
//Display members/victory/failure/objectives for the team
|
||||
/datum/objective_team/proc/roundend_report()
|
||||
var/list/report = list()
|
||||
|
||||
report += "<b>[name]:</b>"
|
||||
report += "The [member_name]s were:"
|
||||
report += printplayerlist(members)
|
||||
|
||||
return report.Join("<br>")
|
||||
@@ -1,164 +0,0 @@
|
||||
/datum/game_mode/wizard/raginmages
|
||||
name = "ragin' mages"
|
||||
config_tag = "raginmages"
|
||||
required_players = 20
|
||||
use_huds = 1
|
||||
announce_span = "userdanger"
|
||||
announce_text = "There are many, many wizards attacking the station!\n\
|
||||
<span class='danger'>Wizards</span>: Accomplish your objectives and cause utter catastrophe!\n\
|
||||
<span class='notice'>Crew</span>: Try not to die..."
|
||||
var/max_mages = 0
|
||||
var/making_mage = 0
|
||||
var/mages_made = 1
|
||||
var/time_checked = 0
|
||||
var/bullshit_mode = 0 // requested by hornygranny
|
||||
var/time_check = 1500
|
||||
var/spawn_delay_min = 500
|
||||
var/spawn_delay_max = 700
|
||||
|
||||
/datum/game_mode/wizard/raginmages/post_setup()
|
||||
..()
|
||||
var/playercount = 0
|
||||
if(!max_mages && !bullshit_mode)
|
||||
for(var/mob/living/player in GLOB.mob_list)
|
||||
if(player.client && player.stat != 2)
|
||||
playercount += 1
|
||||
max_mages = round(playercount / 8)
|
||||
if(max_mages > 20)
|
||||
max_mages = 20
|
||||
if(max_mages < 1)
|
||||
max_mages = 1
|
||||
if(bullshit_mode)
|
||||
max_mages = INFINITY
|
||||
/datum/game_mode/wizard/raginmages/greet_wizard(datum/mind/wizard, you_are=1)
|
||||
if (you_are)
|
||||
to_chat(wizard.current, "<B>You are the Space Wizard!</B>")
|
||||
wizard.current.playsound_local('sound/ambience/antag/RagesMages.ogg',100,0)
|
||||
to_chat(wizard.current, "<B>The Space Wizards Federation has given you the following tasks:</B>")
|
||||
|
||||
var/obj_count = 1
|
||||
to_chat(wizard.current, "<b>Objective Alpha</b>: Make sure the station pays for its actions against our diplomats")
|
||||
for(var/datum/objective/objective in wizard.objectives)
|
||||
to_chat(wizard.current, "<B>Objective #[obj_count]</B>: [objective.explanation_text]")
|
||||
obj_count++
|
||||
return
|
||||
|
||||
/datum/game_mode/wizard/raginmages/check_finished()
|
||||
var/wizards_alive = 0
|
||||
for(var/datum/mind/wizard in wizards)
|
||||
if(!istype(wizard.current,/mob/living/carbon))
|
||||
continue
|
||||
if(istype(wizard.current,/mob/living/brain))
|
||||
continue
|
||||
if(wizard.current.stat==DEAD)
|
||||
continue
|
||||
if(wizard.current.stat==UNCONSCIOUS)
|
||||
if(wizard.current.health < 0)
|
||||
to_chat(wizard.current, "<font size='4'>The Space Wizard Federation is upset with your performance and have terminated your employment.</font>")
|
||||
wizard.current.death()
|
||||
continue
|
||||
wizards_alive++
|
||||
if(!time_checked)
|
||||
time_checked = world.time
|
||||
if(bullshit_mode)
|
||||
if(world.time > time_checked + time_check)
|
||||
max_mages = INFINITY
|
||||
time_checked = world.time
|
||||
make_more_mages()
|
||||
return ..()
|
||||
if (wizards_alive)
|
||||
if(world.time > time_checked + time_check && (mages_made < max_mages))
|
||||
time_checked = world.time
|
||||
make_more_mages()
|
||||
|
||||
else
|
||||
if(mages_made >= max_mages)
|
||||
finished = 1
|
||||
return ..()
|
||||
else
|
||||
make_more_mages()
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/wizard/raginmages/proc/make_more_mages()
|
||||
|
||||
if(making_mage)
|
||||
return 0
|
||||
if(mages_made >= max_mages)
|
||||
return 0
|
||||
making_mage = 1
|
||||
mages_made++
|
||||
var/list/mob/dead/observer/candidates = list()
|
||||
var/mob/dead/observer/theghost = null
|
||||
spawn(rand(spawn_delay_min, spawn_delay_max))
|
||||
message_admins("SWF is still pissed, sending another wizard - [max_mages - mages_made] left.")
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
if(G.client && !G.client.holder && !G.client.is_afk() && (ROLE_WIZARD in G.client.prefs.be_special))
|
||||
if(!jobban_isbanned(G, ROLE_WIZARD) && !jobban_isbanned(G, "Syndicate"))
|
||||
if(age_check(G.client))
|
||||
candidates += G
|
||||
if(!candidates.len)
|
||||
message_admins("No applicable ghosts for the next ragin' mage, asking ghosts instead.")
|
||||
var/time_passed = world.time
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
if(!jobban_isbanned(G, "wizard") && !jobban_isbanned(G, "Syndicate"))
|
||||
if(age_check(G.client))
|
||||
spawn(0)
|
||||
switch(alert(G, "Do you wish to be considered for the position of Space Wizard Foundation 'diplomat'?","Please answer in 30 seconds!","Yes","No"))
|
||||
if("Yes")
|
||||
if((world.time-time_passed)>300)//If more than 30 game seconds passed.
|
||||
continue
|
||||
candidates += G
|
||||
if("No")
|
||||
continue
|
||||
|
||||
sleep(300)
|
||||
if(!candidates.len)
|
||||
message_admins("This is awkward, sleeping until another mage check...")
|
||||
making_mage = 0
|
||||
mages_made--
|
||||
return
|
||||
else
|
||||
shuffle_inplace(candidates)
|
||||
for(var/mob/i in candidates)
|
||||
if(!i || !i.client) continue //Dont bother removing them from the list since we only grab one wizard
|
||||
|
||||
theghost = i
|
||||
break
|
||||
|
||||
if(theghost)
|
||||
var/mob/living/carbon/human/new_character= makeBody(theghost)
|
||||
new_character.mind.make_Wizard()
|
||||
making_mage = 0
|
||||
return 1
|
||||
|
||||
/datum/game_mode/wizard/raginmages/declare_completion()
|
||||
if(finished)
|
||||
SSticker.mode_result = "loss - wizard killed"
|
||||
to_chat(world, "<FONT size=3><B>The crew has managed to hold off the wizard attack! The Space Wizards Federation has been taught a lesson they will not soon forget!</B></FONT>")
|
||||
..(1)
|
||||
|
||||
/datum/game_mode/wizard/raginmages/proc/makeBody(mob/dead/observer/G_found) // Uses stripped down and bastardized code from respawn character
|
||||
if(!G_found || !G_found.key)
|
||||
return
|
||||
|
||||
//First we spawn a dude.
|
||||
var/mob/living/carbon/human/new_character = new//The mob being spawned.
|
||||
SSjob.SendToLateJoin(new_character)
|
||||
|
||||
G_found.client.prefs.copy_to(new_character)
|
||||
new_character.dna.update_dna_identity()
|
||||
new_character.key = G_found.key
|
||||
|
||||
return new_character
|
||||
|
||||
/datum/game_mode/wizard/raginmages/bullshit
|
||||
name = "very ragin' bullshit mages"
|
||||
config_tag = "veryraginbullshitmages"
|
||||
required_players = 20
|
||||
use_huds = 1
|
||||
bullshit_mode = 1
|
||||
time_check = 250
|
||||
spawn_delay_min = 50
|
||||
spawn_delay_max = 150
|
||||
announce_text = "<span class='userdanger'>CRAAAWLING IIIN MY SKIIIN\n\
|
||||
THESE WOOOUNDS THEY WIIIL NOT HEEEAL</span>"
|
||||
@@ -93,7 +93,6 @@ Class Procs:
|
||||
max_integrity = 200
|
||||
|
||||
var/stat = 0
|
||||
var/emagged = FALSE
|
||||
var/use_power = IDLE_POWER_USE
|
||||
//0 = dont run the auto
|
||||
//1 = run auto, use idle
|
||||
@@ -505,4 +504,4 @@ Class Procs:
|
||||
#endif
|
||||
. = . % 9
|
||||
AM.pixel_x = -8 + ((.%3)*8)
|
||||
AM.pixel_y = -8 + (round( . / 3)*8)
|
||||
AM.pixel_y = -8 + (round( . / 3)*8)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user