mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
[READY]Ports /tg/station pixel projectiles, processing subsystems, timer subsystems, and some misc stuff to make it all work
This commit is contained in:
@@ -36,3 +36,4 @@
|
|||||||
#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, null)
|
#define GLOBAL_LIST(X) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, null)
|
||||||
|
|
||||||
#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, null)
|
#define GLOBAL_DATUM(X, Typepath) GLOBAL_RAW(Typepath/##X); GLOBAL_MANAGED(X, null)
|
||||||
|
|
||||||
|
|||||||
@@ -52,3 +52,5 @@
|
|||||||
__BIN_MID = __BIN_ITEM.##COMPARE > IN.##COMPARE ? __BIN_MID : __BIN_MID + 1;\
|
__BIN_MID = __BIN_ITEM.##COMPARE > IN.##COMPARE ? __BIN_MID : __BIN_MID + 1;\
|
||||||
LIST.Insert(__BIN_MID, IN);\
|
LIST.Insert(__BIN_MID, IN);\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define islist(L) istype(L, /list)
|
||||||
|
|||||||
@@ -4,16 +4,42 @@
|
|||||||
#define NONE 0
|
#define NONE 0
|
||||||
|
|
||||||
//for convenience
|
//for convenience
|
||||||
#define ENABLE_BITFIELD(variable, flag) (variable |= (flag))
|
#define ENABLE_BITFIELD(variable, flag) (variable |= (flag))
|
||||||
#define DISABLE_BITFIELD(variable, flag) (variable &= ~(flag))
|
#define DISABLE_BITFIELD(variable, flag) (variable &= ~(flag))
|
||||||
#define CHECK_BITFIELD(variable, flag) (variable & flag)
|
#define CHECK_BITFIELD(variable, flag) (variable & (flag))
|
||||||
|
|
||||||
//check if all bitflags specified are present
|
//check if all bitflags specified are present
|
||||||
#define CHECK_MULTIPLE_BITFIELDS(flagvar, flags) ((flagvar & (flags)) == flags)
|
#define CHECK_MULTIPLE_BITFIELDS(flagvar, flags) ((flagvar & (flags)) == flags)
|
||||||
|
|
||||||
GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768))
|
GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768))
|
||||||
|
|
||||||
// datum_flags
|
// datum_flags
|
||||||
#define DF_VAR_EDITED (1<<0)
|
#define DF_VAR_EDITED (1<<0)
|
||||||
#define DF_ISPROCESSING (1<<1)
|
#define DF_ISPROCESSING (1<<1)
|
||||||
|
|
||||||
|
// /atom/movable movement_type
|
||||||
|
#define UNSTOPPABLE (1<<0) //Can not be stopped from moving from Cross(), CanPass(), or Uncross() failing. Still bumps everything it passes through, though.
|
||||||
|
|
||||||
|
// Flags bitmasks. - Used in /atom/var/flags
|
||||||
|
#define NOBLUDGEON (1<<0) // When an item has this it produces no "X has been hit by Y with Z" message with the default handler.
|
||||||
|
#define CONDUCT (1<<1) // Conducts electricity. (metal etc.)
|
||||||
|
#define ON_BORDER (1<<2) // Item has priority to check when entering or leaving.
|
||||||
|
#define NOBLOODY (1<<3) // Used for items if they don't want to get a blood overlay.
|
||||||
|
#define OPENCONTAINER (1<<4) // Is an open container for chemistry purposes.
|
||||||
|
#define PHORONGUARD (1<<5) // Does not get contaminated by phoron.
|
||||||
|
#define NOREACT (1<<6) // Reagents don't react inside this container.
|
||||||
|
#define PROXMOVE (1<<7)// Does this object require proximity checking in Enter()?
|
||||||
|
#define OVERLAY_QUEUED (1<<8)// Atom queued to SSoverlay for COMPILE_OVERLAYS
|
||||||
|
|
||||||
|
//Flags for items (equipment) - Used in /obj/item/var/item_flags
|
||||||
|
#define THICKMATERIAL (1<<0) // Prevents syringes, parapens and hyposprays if equipped to slot_suit or slot_head.
|
||||||
|
#define AIRTIGHT (1<<1) // Functions with internals.
|
||||||
|
#define NOSLIP (1<<2) // Prevents from slipping on wet floors, in space, etc.
|
||||||
|
#define BLOCK_GAS_SMOKE_EFFECT (1<<3) // Blocks the effect that chemical clouds would have on a mob -- glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL)
|
||||||
|
#define FLEXIBLEMATERIAL (1<<4) // At the moment, masks with this flag will not prevent eating even if they are covering your face.
|
||||||
|
|
||||||
|
// Flags for pass_flags. - Used in /atom/var/pass_flags
|
||||||
|
#define PASSTABLE (1<<0)
|
||||||
|
#define PASSGLASS (1<<1)
|
||||||
|
#define PASSGRILLE (1<<2)
|
||||||
|
#define PASSBLOB (1<<3)
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
#define ACCESSORY_SLOT_TORSO (ACCESSORY_SLOT_UTILITY|ACCESSORY_SLOT_WEAPON)
|
#define ACCESSORY_SLOT_TORSO (ACCESSORY_SLOT_UTILITY|ACCESSORY_SLOT_WEAPON)
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
// Flags bitmasks. - Used in /atom/var/flags
|
// Flags bitmasks. - Used in /atom/var/flags
|
||||||
#define NOBLUDGEON 0x1 // When an item has this it produces no "X has been hit by Y with Z" message with the default handler.
|
#define NOBLUDGEON 0x1 // When an item has this it produces no "X has been hit by Y with Z" message with the default handler.
|
||||||
#define CONDUCT 0x2 // Conducts electricity. (metal etc.)
|
#define CONDUCT 0x2 // Conducts electricity. (metal etc.)
|
||||||
@@ -64,6 +65,8 @@
|
|||||||
#define PASSGRILLE 0x4
|
#define PASSGRILLE 0x4
|
||||||
#define PASSBLOB 0x8
|
#define PASSBLOB 0x8
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
// Bitmasks for the /obj/item/var/flags_inv variable. These determine when a piece of clothing hides another, i.e. a helmet hiding glasses.
|
// Bitmasks for the /obj/item/var/flags_inv variable. These determine when a piece of clothing hides another, i.e. a helmet hiding glasses.
|
||||||
// WARNING: The following flags apply only to the external suit!
|
// WARNING: The following flags apply only to the external suit!
|
||||||
#define HIDEGLOVES 0x1
|
#define HIDEGLOVES 0x1
|
||||||
|
|||||||
@@ -21,4 +21,4 @@
|
|||||||
#define QUANTIZE(variable) (round(variable,0.0001))
|
#define QUANTIZE(variable) (round(variable,0.0001))
|
||||||
|
|
||||||
#define TICKS_IN_DAY (TICKS_IN_SECOND * 60 * 60 * 24)
|
#define TICKS_IN_DAY (TICKS_IN_SECOND * 60 * 60 * 24)
|
||||||
#define TICKS_IN_SECOND (world.fps)
|
#define TICKS_IN_SECOND (world.fps)
|
||||||
|
|||||||
@@ -290,6 +290,11 @@ var/global/list/##LIST_NAME = list();\
|
|||||||
#define IS_WIRECUTTER "wirecutter"
|
#define IS_WIRECUTTER "wirecutter"
|
||||||
#define IS_WRENCH "wrench"
|
#define IS_WRENCH "wrench"
|
||||||
|
|
||||||
|
|
||||||
|
// Diagonal movement
|
||||||
|
#define FIRST_DIAG_STEP 1
|
||||||
|
#define SECOND_DIAG_STEP 2
|
||||||
|
|
||||||
// RCD modes. Used on the RCD, and gets passed to an object's rcd_act() when an RCD is used on it, to determine what happens.
|
// RCD modes. Used on the RCD, and gets passed to an object's rcd_act() when an RCD is used on it, to determine what happens.
|
||||||
#define RCD_FLOORWALL "Floor / Wall" // Builds plating on space/ground/open tiles. Builds a wall when on floors. Finishes walls when used on girders.
|
#define RCD_FLOORWALL "Floor / Wall" // Builds plating on space/ground/open tiles. Builds a wall when on floors. Finishes walls when used on girders.
|
||||||
#define RCD_AIRLOCK "Airlock" // Builds an airlock on the tile if one isn't already there.
|
#define RCD_AIRLOCK "Airlock" // Builds an airlock on the tile if one isn't already there.
|
||||||
@@ -300,7 +305,6 @@ var/global/list/##LIST_NAME = list();\
|
|||||||
#define RCD_VALUE_DELAY "delay"
|
#define RCD_VALUE_DELAY "delay"
|
||||||
#define RCD_VALUE_COST "cost"
|
#define RCD_VALUE_COST "cost"
|
||||||
|
|
||||||
|
|
||||||
#define RCD_SHEETS_PER_MATTER_UNIT 4 // Each physical material sheet is worth four matter units.
|
#define RCD_SHEETS_PER_MATTER_UNIT 4 // Each physical material sheet is worth four matter units.
|
||||||
#define RCD_MAX_CAPACITY 30 * RCD_SHEETS_PER_MATTER_UNIT
|
#define RCD_MAX_CAPACITY 30 * RCD_SHEETS_PER_MATTER_UNIT
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G
|
|||||||
#define FIRE_PRIORITY_DEFAULT 50
|
#define FIRE_PRIORITY_DEFAULT 50
|
||||||
#define FIRE_PRIORITY_PLANETS 75
|
#define FIRE_PRIORITY_PLANETS 75
|
||||||
#define FIRE_PRIORITY_MACHINES 100
|
#define FIRE_PRIORITY_MACHINES 100
|
||||||
|
#define FIRE_PRIORITY_PROJECTILES 150
|
||||||
#define FIRE_PRIORITY_OVERLAYS 500
|
#define FIRE_PRIORITY_OVERLAYS 500
|
||||||
|
|
||||||
// Macro defining the actual code applying our overlays lists to the BYOND overlays list. (I guess a macro for speed)
|
// Macro defining the actual code applying our overlays lists to the BYOND overlays list. (I guess a macro for speed)
|
||||||
|
|||||||
1516
code/_helpers/_lists.dm
Normal file
1516
code/_helpers/_lists.dm
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,758 +0,0 @@
|
|||||||
/*
|
|
||||||
* Holds procs to help with list operations
|
|
||||||
* Contains groups:
|
|
||||||
* Misc
|
|
||||||
* Sorting
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Misc
|
|
||||||
*/
|
|
||||||
|
|
||||||
//Returns a list in plain english as a string
|
|
||||||
/proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" )
|
|
||||||
switch(input.len)
|
|
||||||
if(0) return nothing_text
|
|
||||||
if(1) return "[input[1]]"
|
|
||||||
if(2) return "[input[1]][and_text][input[2]]"
|
|
||||||
else return "[jointext(input, comma_text, 1, -1)][final_comma_text][and_text][input[input.len]]"
|
|
||||||
|
|
||||||
//Returns list element or null. Should prevent "index out of bounds" error.
|
|
||||||
proc/listgetindex(var/list/list,index)
|
|
||||||
if(istype(list) && list.len)
|
|
||||||
if(isnum(index))
|
|
||||||
if(InRange(index,1,list.len))
|
|
||||||
return list[index]
|
|
||||||
else if(index in list)
|
|
||||||
return list[index]
|
|
||||||
return
|
|
||||||
|
|
||||||
//Return either pick(list) or null if list is not of type /list or is empty
|
|
||||||
proc/safepick(list/list)
|
|
||||||
if(!islist(list) || !list.len)
|
|
||||||
return
|
|
||||||
return pick(list)
|
|
||||||
|
|
||||||
//Checks if the list is empty
|
|
||||||
proc/isemptylist(list/list)
|
|
||||||
if(!list.len)
|
|
||||||
return 1
|
|
||||||
return 0
|
|
||||||
|
|
||||||
//Checks for specific types in a list
|
|
||||||
/proc/is_type_in_list(var/atom/A, var/list/L)
|
|
||||||
for(var/type in L)
|
|
||||||
if(istype(A, type))
|
|
||||||
return 1
|
|
||||||
return 0
|
|
||||||
|
|
||||||
//Checks for specific paths in a list
|
|
||||||
/proc/is_path_in_list(var/atom/A, var/list/L)
|
|
||||||
for(var/path in L)
|
|
||||||
if(ispath(A, path))
|
|
||||||
return 1
|
|
||||||
return 0
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
// "typecache" utilities - Making and searching them
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//Checks for specific types in specifically structured (Assoc "type" = TRUE) lists ('typecaches')
|
|
||||||
/proc/is_type_in_typecache(atom/A, list/L)
|
|
||||||
if(!LAZYLEN(L) || !A)
|
|
||||||
return FALSE
|
|
||||||
return L[A.type]
|
|
||||||
|
|
||||||
//returns a new list with only atoms that are in typecache L
|
|
||||||
/proc/typecache_filter_list(list/atoms, list/typecache)
|
|
||||||
. = list()
|
|
||||||
for(var/thing in atoms)
|
|
||||||
var/atom/A = thing
|
|
||||||
if(typecache[A.type])
|
|
||||||
. += A
|
|
||||||
|
|
||||||
/proc/typecache_filter_list_reverse(list/atoms, list/typecache)
|
|
||||||
. = list()
|
|
||||||
for(var/thing in atoms)
|
|
||||||
var/atom/A = thing
|
|
||||||
if(!typecache[A.type])
|
|
||||||
. += A
|
|
||||||
|
|
||||||
/proc/typecache_filter_multi_list_exclusion(list/atoms, list/typecache_include, list/typecache_exclude)
|
|
||||||
. = list()
|
|
||||||
for(var/thing in atoms)
|
|
||||||
var/atom/A = thing
|
|
||||||
if(typecache_include[A.type] && !typecache_exclude[A.type])
|
|
||||||
. += A
|
|
||||||
|
|
||||||
//Like typesof() or subtypesof(), but returns a typecache instead of a list
|
|
||||||
/proc/typecacheof(path, ignore_root_path, only_root_path = FALSE)
|
|
||||||
if(ispath(path))
|
|
||||||
var/list/types = list()
|
|
||||||
if(only_root_path)
|
|
||||||
types = list(path)
|
|
||||||
else
|
|
||||||
types = ignore_root_path ? subtypesof(path) : typesof(path)
|
|
||||||
var/list/L = list()
|
|
||||||
for(var/T in types)
|
|
||||||
L[T] = TRUE
|
|
||||||
return L
|
|
||||||
else if(islist(path))
|
|
||||||
var/list/pathlist = path
|
|
||||||
var/list/L = list()
|
|
||||||
if(ignore_root_path)
|
|
||||||
for(var/P in pathlist)
|
|
||||||
for(var/T in subtypesof(P))
|
|
||||||
L[T] = TRUE
|
|
||||||
else
|
|
||||||
for(var/P in pathlist)
|
|
||||||
if(only_root_path)
|
|
||||||
L[P] = TRUE
|
|
||||||
else
|
|
||||||
for(var/T in typesof(P))
|
|
||||||
L[T] = TRUE
|
|
||||||
return L
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected
|
|
||||||
proc/clearlist(list/list)
|
|
||||||
if(istype(list))
|
|
||||||
list.len = 0
|
|
||||||
return
|
|
||||||
|
|
||||||
//Removes any null entries from the list
|
|
||||||
proc/listclearnulls(list/list)
|
|
||||||
if(istype(list))
|
|
||||||
while(null in list)
|
|
||||||
list -= null
|
|
||||||
return
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns list containing all the entries from first list that are not present in second.
|
|
||||||
* If skiprep = 1, repeated elements are treated as one.
|
|
||||||
* If either of arguments is not a list, returns null
|
|
||||||
*/
|
|
||||||
/proc/difflist(var/list/first, var/list/second, var/skiprep=0)
|
|
||||||
if(!islist(first) || !islist(second))
|
|
||||||
return
|
|
||||||
var/list/result = new
|
|
||||||
if(skiprep)
|
|
||||||
for(var/e in first)
|
|
||||||
if(!(e in result) && !(e in second))
|
|
||||||
result += e
|
|
||||||
else
|
|
||||||
result = first - second
|
|
||||||
return result
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns list containing entries that are in either list but not both.
|
|
||||||
* If skipref = 1, repeated elements are treated as one.
|
|
||||||
* If either of arguments is not a list, returns null
|
|
||||||
*/
|
|
||||||
/proc/uniquemergelist(var/list/first, var/list/second, var/skiprep=0)
|
|
||||||
if(!islist(first) || !islist(second))
|
|
||||||
return
|
|
||||||
var/list/result = new
|
|
||||||
if(skiprep)
|
|
||||||
result = difflist(first, second, skiprep)+difflist(second, first, skiprep)
|
|
||||||
else
|
|
||||||
result = first ^ second
|
|
||||||
return result
|
|
||||||
|
|
||||||
//Pretends to pick an element based on its weight but really just seems to pick a random element.
|
|
||||||
/proc/pickweight(list/L)
|
|
||||||
var/total = 0
|
|
||||||
var/item
|
|
||||||
for (item in L)
|
|
||||||
if (!L[item])
|
|
||||||
L[item] = 1
|
|
||||||
total += L[item]
|
|
||||||
|
|
||||||
total = rand(1, total)
|
|
||||||
for (item in L)
|
|
||||||
total -=L [item]
|
|
||||||
if (total <= 0)
|
|
||||||
return item
|
|
||||||
|
|
||||||
return null
|
|
||||||
|
|
||||||
//Pick a random element from the list and remove it from the list.
|
|
||||||
/proc/pick_n_take(list/listfrom)
|
|
||||||
if (listfrom.len > 0)
|
|
||||||
var/picked = pick(listfrom)
|
|
||||||
listfrom -= picked
|
|
||||||
return picked
|
|
||||||
return null
|
|
||||||
|
|
||||||
//Returns the top(last) element from the list and removes it from the list (typical stack function)
|
|
||||||
/proc/pop(list/listfrom)
|
|
||||||
if (listfrom.len > 0)
|
|
||||||
var/picked = listfrom[listfrom.len]
|
|
||||||
listfrom.len--
|
|
||||||
return picked
|
|
||||||
return null
|
|
||||||
|
|
||||||
//Returns the next element in parameter list after first appearance of parameter element. If it is the last element of the list or not present in list, returns first element.
|
|
||||||
/proc/next_in_list(element, list/L)
|
|
||||||
for(var/i=1, i<L.len, i++)
|
|
||||||
if(L[i] == element)
|
|
||||||
return L[i+1]
|
|
||||||
return L[1]
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sorting
|
|
||||||
*/
|
|
||||||
|
|
||||||
//Reverses the order of items in the list
|
|
||||||
/proc/reverselist(list/L)
|
|
||||||
var/list/output = list()
|
|
||||||
if(L)
|
|
||||||
for(var/i = L.len; i >= 1; i--)
|
|
||||||
output += L[i]
|
|
||||||
return output
|
|
||||||
|
|
||||||
//Randomize: Return the list in a random order
|
|
||||||
/proc/shuffle(var/list/L)
|
|
||||||
if(!L)
|
|
||||||
return
|
|
||||||
|
|
||||||
L = L.Copy()
|
|
||||||
|
|
||||||
for(var/i=1; i<L.len; i++)
|
|
||||||
L.Swap(i, rand(i,L.len))
|
|
||||||
return L
|
|
||||||
|
|
||||||
//same, but returns nothing and acts on list in place
|
|
||||||
/proc/shuffle_inplace(list/L)
|
|
||||||
if(!L)
|
|
||||||
return
|
|
||||||
|
|
||||||
for(var/i=1, i<L.len, ++i)
|
|
||||||
L.Swap(i,rand(i,L.len))
|
|
||||||
|
|
||||||
//Return a list with no duplicate entries
|
|
||||||
/proc/uniquelist(var/list/L)
|
|
||||||
. = list()
|
|
||||||
for(var/i in L)
|
|
||||||
. |= i
|
|
||||||
|
|
||||||
//same, but returns nothing and acts on list in place (also handles associated values properly)
|
|
||||||
/proc/uniqueList_inplace(list/L)
|
|
||||||
var/temp = L.Copy()
|
|
||||||
L.len = 0
|
|
||||||
for(var/key in temp)
|
|
||||||
if (isnum(key))
|
|
||||||
L |= key
|
|
||||||
else
|
|
||||||
L[key] = temp[key]
|
|
||||||
|
|
||||||
|
|
||||||
//Mergesort: divides up the list into halves to begin the sort
|
|
||||||
/proc/sortKey(var/list/client/L, var/order = 1)
|
|
||||||
if(isnull(L) || L.len < 2)
|
|
||||||
return L
|
|
||||||
var/middle = L.len / 2 + 1
|
|
||||||
return mergeKey(sortKey(L.Copy(0,middle)), sortKey(L.Copy(middle)), order)
|
|
||||||
|
|
||||||
//Mergsort: does the actual sorting and returns the results back to sortAtom
|
|
||||||
/proc/mergeKey(var/list/client/L, var/list/client/R, var/order = 1)
|
|
||||||
var/Li=1
|
|
||||||
var/Ri=1
|
|
||||||
var/list/result = new()
|
|
||||||
while(Li <= L.len && Ri <= R.len)
|
|
||||||
var/client/rL = L[Li]
|
|
||||||
var/client/rR = R[Ri]
|
|
||||||
if(sorttext(rL.ckey, rR.ckey) == order)
|
|
||||||
result += L[Li++]
|
|
||||||
else
|
|
||||||
result += R[Ri++]
|
|
||||||
|
|
||||||
if(Li <= L.len)
|
|
||||||
return (result + L.Copy(Li, 0))
|
|
||||||
return (result + R.Copy(Ri, 0))
|
|
||||||
|
|
||||||
//Mergesort: divides up the list into halves to begin the sort
|
|
||||||
/proc/sortAtom(var/list/atom/L, var/order = 1)
|
|
||||||
if(isnull(L) || L.len < 2)
|
|
||||||
return L
|
|
||||||
var/middle = L.len / 2 + 1
|
|
||||||
return mergeAtoms(sortAtom(L.Copy(0,middle)), sortAtom(L.Copy(middle)), order)
|
|
||||||
|
|
||||||
//Mergsort: does the actual sorting and returns the results back to sortAtom
|
|
||||||
/proc/mergeAtoms(var/list/atom/L, var/list/atom/R, var/order = 1)
|
|
||||||
var/Li=1
|
|
||||||
var/Ri=1
|
|
||||||
var/list/result = new()
|
|
||||||
while(Li <= L.len && Ri <= R.len)
|
|
||||||
var/atom/rL = L[Li]
|
|
||||||
var/atom/rR = R[Ri]
|
|
||||||
if(sorttext(rL.name, rR.name) == order)
|
|
||||||
result += L[Li++]
|
|
||||||
else
|
|
||||||
result += R[Ri++]
|
|
||||||
|
|
||||||
if(Li <= L.len)
|
|
||||||
return (result + L.Copy(Li, 0))
|
|
||||||
return (result + R.Copy(Ri, 0))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Mergesort: Specifically for record datums in a list.
|
|
||||||
/proc/sortRecord(var/list/datum/data/record/L, var/field = "name", var/order = 1)
|
|
||||||
if(isnull(L))
|
|
||||||
return list()
|
|
||||||
if(L.len < 2)
|
|
||||||
return L
|
|
||||||
var/middle = L.len / 2 + 1
|
|
||||||
return mergeRecordLists(sortRecord(L.Copy(0, middle), field, order), sortRecord(L.Copy(middle), field, order), field, order)
|
|
||||||
|
|
||||||
//Mergsort: does the actual sorting and returns the results back to sortRecord
|
|
||||||
/proc/mergeRecordLists(var/list/datum/data/record/L, var/list/datum/data/record/R, var/field = "name", var/order = 1)
|
|
||||||
var/Li=1
|
|
||||||
var/Ri=1
|
|
||||||
var/list/result = new()
|
|
||||||
if(!isnull(L) && !isnull(R))
|
|
||||||
while(Li <= L.len && Ri <= R.len)
|
|
||||||
var/datum/data/record/rL = L[Li]
|
|
||||||
if(isnull(rL))
|
|
||||||
L -= rL
|
|
||||||
continue
|
|
||||||
var/datum/data/record/rR = R[Ri]
|
|
||||||
if(isnull(rR))
|
|
||||||
R -= rR
|
|
||||||
continue
|
|
||||||
if(sorttext(rL.fields[field], rR.fields[field]) == order)
|
|
||||||
result += L[Li++]
|
|
||||||
else
|
|
||||||
result += R[Ri++]
|
|
||||||
|
|
||||||
if(Li <= L.len)
|
|
||||||
return (result + L.Copy(Li, 0))
|
|
||||||
return (result + R.Copy(Ri, 0))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Mergesort: any value in a list
|
|
||||||
/proc/sortList(var/list/L)
|
|
||||||
if(L.len < 2)
|
|
||||||
return L
|
|
||||||
var/middle = L.len / 2 + 1 // Copy is first,second-1
|
|
||||||
return mergeLists(sortList(L.Copy(0,middle)), sortList(L.Copy(middle))) //second parameter null = to end of list
|
|
||||||
|
|
||||||
//Mergsorge: uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead
|
|
||||||
/proc/sortNames(var/list/L)
|
|
||||||
var/list/Q = new()
|
|
||||||
for(var/atom/x in L)
|
|
||||||
Q[x.name] = x
|
|
||||||
return sortList(Q)
|
|
||||||
|
|
||||||
/proc/mergeLists(var/list/L, var/list/R)
|
|
||||||
var/Li=1
|
|
||||||
var/Ri=1
|
|
||||||
var/list/result = new()
|
|
||||||
while(Li <= L.len && Ri <= R.len)
|
|
||||||
if(sorttext(L[Li], R[Ri]) < 1)
|
|
||||||
result += R[Ri++]
|
|
||||||
else
|
|
||||||
result += L[Li++]
|
|
||||||
|
|
||||||
if(Li <= L.len)
|
|
||||||
return (result + L.Copy(Li, 0))
|
|
||||||
return (result + R.Copy(Ri, 0))
|
|
||||||
|
|
||||||
|
|
||||||
// List of lists, sorts by element[key] - for things like crew monitoring computer sorting records by name.
|
|
||||||
/proc/sortByKey(var/list/L, var/key)
|
|
||||||
if(L.len < 2)
|
|
||||||
return L
|
|
||||||
var/middle = L.len / 2 + 1
|
|
||||||
return mergeKeyedLists(sortByKey(L.Copy(0, middle), key), sortByKey(L.Copy(middle), key), key)
|
|
||||||
|
|
||||||
/proc/mergeKeyedLists(var/list/L, var/list/R, var/key)
|
|
||||||
var/Li=1
|
|
||||||
var/Ri=1
|
|
||||||
var/list/result = new()
|
|
||||||
while(Li <= L.len && Ri <= R.len)
|
|
||||||
if(sorttext(L[Li][key], R[Ri][key]) < 1)
|
|
||||||
// Works around list += list2 merging lists; it's not pretty but it works
|
|
||||||
result += "temp item"
|
|
||||||
result[result.len] = R[Ri++]
|
|
||||||
else
|
|
||||||
result += "temp item"
|
|
||||||
result[result.len] = L[Li++]
|
|
||||||
|
|
||||||
if(Li <= L.len)
|
|
||||||
return (result + L.Copy(Li, 0))
|
|
||||||
return (result + R.Copy(Ri, 0))
|
|
||||||
|
|
||||||
|
|
||||||
//Mergesort: any value in a list, preserves key=value structure
|
|
||||||
/proc/sortAssoc(var/list/L)
|
|
||||||
if(L.len < 2)
|
|
||||||
return L
|
|
||||||
var/middle = L.len / 2 + 1 // Copy is first,second-1
|
|
||||||
return mergeAssoc(sortAssoc(L.Copy(0,middle)), sortAssoc(L.Copy(middle))) //second parameter null = to end of list
|
|
||||||
|
|
||||||
/proc/mergeAssoc(var/list/L, var/list/R)
|
|
||||||
var/Li=1
|
|
||||||
var/Ri=1
|
|
||||||
var/list/result = new()
|
|
||||||
while(Li <= L.len && Ri <= R.len)
|
|
||||||
if(sorttext(L[Li], R[Ri]) < 1)
|
|
||||||
result += R&R[Ri++]
|
|
||||||
else
|
|
||||||
result += L&L[Li++]
|
|
||||||
|
|
||||||
if(Li <= L.len)
|
|
||||||
return (result + L.Copy(Li, 0))
|
|
||||||
return (result + R.Copy(Ri, 0))
|
|
||||||
|
|
||||||
// Macros to test for bits in a bitfield. Note, that this is for use with indexes, not bit-masks!
|
|
||||||
#define BITTEST(bitfield,index) ((bitfield) & (1 << (index)))
|
|
||||||
#define BITSET(bitfield,index) (bitfield) |= (1 << (index))
|
|
||||||
#define BITRESET(bitfield,index) (bitfield) &= ~(1 << (index))
|
|
||||||
#define BITFLIP(bitfield,index) (bitfield) ^= (1 << (index))
|
|
||||||
|
|
||||||
//Converts a bitfield to a list of numbers (or words if a wordlist is provided)
|
|
||||||
/proc/bitfield2list(bitfield = 0, list/wordlist)
|
|
||||||
var/list/r = list()
|
|
||||||
if(istype(wordlist,/list))
|
|
||||||
var/max = min(wordlist.len,16)
|
|
||||||
var/bit = 1
|
|
||||||
for(var/i=1, i<=max, i++)
|
|
||||||
if(bitfield & bit)
|
|
||||||
r += wordlist[i]
|
|
||||||
bit = bit << 1
|
|
||||||
else
|
|
||||||
for(var/bit=1, bit<=65535, bit = bit << 1)
|
|
||||||
if(bitfield & bit)
|
|
||||||
r += bit
|
|
||||||
|
|
||||||
return r
|
|
||||||
|
|
||||||
// Returns the key based on the index
|
|
||||||
/proc/get_key_by_index(var/list/L, var/index)
|
|
||||||
var/i = 1
|
|
||||||
for(var/key in L)
|
|
||||||
if(index == i)
|
|
||||||
return key
|
|
||||||
i++
|
|
||||||
return null
|
|
||||||
|
|
||||||
// Returns the key based on the index
|
|
||||||
/proc/get_key_by_value(var/list/L, var/value)
|
|
||||||
for(var/key in L)
|
|
||||||
if(L[key] == value)
|
|
||||||
return key
|
|
||||||
|
|
||||||
/proc/count_by_type(var/list/L, type)
|
|
||||||
var/i = 0
|
|
||||||
for(var/T in L)
|
|
||||||
if(istype(T, type))
|
|
||||||
i++
|
|
||||||
return i
|
|
||||||
|
|
||||||
//Don't use this on lists larger than half a dozen or so
|
|
||||||
/proc/insertion_sort_numeric_list_ascending(var/list/L)
|
|
||||||
//world.log << "ascending len input: [L.len]"
|
|
||||||
var/list/out = list(pop(L))
|
|
||||||
for(var/entry in L)
|
|
||||||
if(isnum(entry))
|
|
||||||
var/success = 0
|
|
||||||
for(var/i=1, i<=out.len, i++)
|
|
||||||
if(entry <= out[i])
|
|
||||||
success = 1
|
|
||||||
out.Insert(i, entry)
|
|
||||||
break
|
|
||||||
if(!success)
|
|
||||||
out.Add(entry)
|
|
||||||
|
|
||||||
//world.log << " output: [out.len]"
|
|
||||||
return out
|
|
||||||
|
|
||||||
/proc/insertion_sort_numeric_list_descending(var/list/L)
|
|
||||||
//world.log << "descending len input: [L.len]"
|
|
||||||
var/list/out = insertion_sort_numeric_list_ascending(L)
|
|
||||||
//world.log << " output: [out.len]"
|
|
||||||
return reverselist(out)
|
|
||||||
|
|
||||||
/proc/dd_sortedObjectList(var/list/L, var/cache=list())
|
|
||||||
if(L.len < 2)
|
|
||||||
return L
|
|
||||||
var/middle = L.len / 2 + 1 // Copy is first,second-1
|
|
||||||
return dd_mergeObjectList(dd_sortedObjectList(L.Copy(0,middle), cache), dd_sortedObjectList(L.Copy(middle), cache), cache) //second parameter null = to end of list
|
|
||||||
|
|
||||||
/proc/dd_mergeObjectList(var/list/L, var/list/R, var/list/cache)
|
|
||||||
var/Li=1
|
|
||||||
var/Ri=1
|
|
||||||
var/list/result = new()
|
|
||||||
while(Li <= L.len && Ri <= R.len)
|
|
||||||
var/LLi = L[Li]
|
|
||||||
var/RRi = R[Ri]
|
|
||||||
var/LLiV = cache[LLi]
|
|
||||||
var/RRiV = cache[RRi]
|
|
||||||
if(!LLiV)
|
|
||||||
LLiV = LLi:dd_SortValue()
|
|
||||||
cache[LLi] = LLiV
|
|
||||||
if(!RRiV)
|
|
||||||
RRiV = RRi:dd_SortValue()
|
|
||||||
cache[RRi] = RRiV
|
|
||||||
if(LLiV < RRiV)
|
|
||||||
result += L[Li++]
|
|
||||||
else
|
|
||||||
result += R[Ri++]
|
|
||||||
|
|
||||||
if(Li <= L.len)
|
|
||||||
return (result + L.Copy(Li, 0))
|
|
||||||
return (result + R.Copy(Ri, 0))
|
|
||||||
|
|
||||||
// Insert an object into a sorted list, preserving sortedness
|
|
||||||
/proc/dd_insertObjectList(var/list/L, var/O)
|
|
||||||
var/min = 1
|
|
||||||
var/max = L.len
|
|
||||||
var/Oval = O:dd_SortValue()
|
|
||||||
|
|
||||||
while(1)
|
|
||||||
var/mid = min+round((max-min)/2)
|
|
||||||
|
|
||||||
if(mid == max)
|
|
||||||
L.Insert(mid, O)
|
|
||||||
return
|
|
||||||
|
|
||||||
var/Lmid = L[mid]
|
|
||||||
var/midval = Lmid:dd_SortValue()
|
|
||||||
if(Oval == midval)
|
|
||||||
L.Insert(mid, O)
|
|
||||||
return
|
|
||||||
else if(Oval < midval)
|
|
||||||
max = mid
|
|
||||||
else
|
|
||||||
min = mid+1
|
|
||||||
|
|
||||||
/*
|
|
||||||
proc/dd_sortedObjectList(list/incoming)
|
|
||||||
/*
|
|
||||||
Use binary search to order by dd_SortValue().
|
|
||||||
This works by going to the half-point of the list, seeing if the node in
|
|
||||||
question is higher or lower cost, then going halfway up or down the list
|
|
||||||
and checking again. This is a very fast way to sort an item into a list.
|
|
||||||
*/
|
|
||||||
var/list/sorted_list = new()
|
|
||||||
var/low_index
|
|
||||||
var/high_index
|
|
||||||
var/insert_index
|
|
||||||
var/midway_calc
|
|
||||||
var/current_index
|
|
||||||
var/current_item
|
|
||||||
var/current_item_value
|
|
||||||
var/current_sort_object_value
|
|
||||||
var/list/list_bottom
|
|
||||||
|
|
||||||
var/current_sort_object
|
|
||||||
for (current_sort_object in incoming)
|
|
||||||
low_index = 1
|
|
||||||
high_index = sorted_list.len
|
|
||||||
while (low_index <= high_index)
|
|
||||||
// Figure out the midpoint, rounding up for fractions. (BYOND rounds down, so add 1 if necessary.)
|
|
||||||
midway_calc = (low_index + high_index) / 2
|
|
||||||
current_index = round(midway_calc)
|
|
||||||
if (midway_calc > current_index)
|
|
||||||
current_index++
|
|
||||||
current_item = sorted_list[current_index]
|
|
||||||
|
|
||||||
current_item_value = current_item:dd_SortValue()
|
|
||||||
current_sort_object_value = current_sort_object:dd_SortValue()
|
|
||||||
if (current_sort_object_value < current_item_value)
|
|
||||||
high_index = current_index - 1
|
|
||||||
else if (current_sort_object_value > current_item_value)
|
|
||||||
low_index = current_index + 1
|
|
||||||
else
|
|
||||||
// current_sort_object == current_item
|
|
||||||
low_index = current_index
|
|
||||||
break
|
|
||||||
|
|
||||||
// Insert before low_index.
|
|
||||||
insert_index = low_index
|
|
||||||
|
|
||||||
// Special case adding to end of list.
|
|
||||||
if (insert_index > sorted_list.len)
|
|
||||||
sorted_list += current_sort_object
|
|
||||||
continue
|
|
||||||
|
|
||||||
// Because BYOND lists don't support insert, have to do it by:
|
|
||||||
// 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list.
|
|
||||||
list_bottom = sorted_list.Copy(insert_index)
|
|
||||||
sorted_list.Cut(insert_index)
|
|
||||||
sorted_list += current_sort_object
|
|
||||||
sorted_list += list_bottom
|
|
||||||
return sorted_list
|
|
||||||
*/
|
|
||||||
|
|
||||||
proc/dd_sortedtextlist(list/incoming, case_sensitive = 0)
|
|
||||||
// Returns a new list with the text values sorted.
|
|
||||||
// Use binary search to order by sortValue.
|
|
||||||
// This works by going to the half-point of the list, seeing if the node in question is higher or lower cost,
|
|
||||||
// then going halfway up or down the list and checking again.
|
|
||||||
// This is a very fast way to sort an item into a list.
|
|
||||||
var/list/sorted_text = new()
|
|
||||||
var/low_index
|
|
||||||
var/high_index
|
|
||||||
var/insert_index
|
|
||||||
var/midway_calc
|
|
||||||
var/current_index
|
|
||||||
var/current_item
|
|
||||||
var/list/list_bottom
|
|
||||||
var/sort_result
|
|
||||||
|
|
||||||
var/current_sort_text
|
|
||||||
for (current_sort_text in incoming)
|
|
||||||
low_index = 1
|
|
||||||
high_index = sorted_text.len
|
|
||||||
while (low_index <= high_index)
|
|
||||||
// Figure out the midpoint, rounding up for fractions. (BYOND rounds down, so add 1 if necessary.)
|
|
||||||
midway_calc = (low_index + high_index) / 2
|
|
||||||
current_index = round(midway_calc)
|
|
||||||
if (midway_calc > current_index)
|
|
||||||
current_index++
|
|
||||||
current_item = sorted_text[current_index]
|
|
||||||
|
|
||||||
if (case_sensitive)
|
|
||||||
sort_result = sorttextEx(current_sort_text, current_item)
|
|
||||||
else
|
|
||||||
sort_result = sorttext(current_sort_text, current_item)
|
|
||||||
|
|
||||||
switch(sort_result)
|
|
||||||
if (1)
|
|
||||||
high_index = current_index - 1 // current_sort_text < current_item
|
|
||||||
if (-1)
|
|
||||||
low_index = current_index + 1 // current_sort_text > current_item
|
|
||||||
if (0)
|
|
||||||
low_index = current_index // current_sort_text == current_item
|
|
||||||
break
|
|
||||||
|
|
||||||
// Insert before low_index.
|
|
||||||
insert_index = low_index
|
|
||||||
|
|
||||||
// Special case adding to end of list.
|
|
||||||
if (insert_index > sorted_text.len)
|
|
||||||
sorted_text += current_sort_text
|
|
||||||
continue
|
|
||||||
|
|
||||||
// Because BYOND lists don't support insert, have to do it by:
|
|
||||||
// 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list.
|
|
||||||
list_bottom = sorted_text.Copy(insert_index)
|
|
||||||
sorted_text.Cut(insert_index)
|
|
||||||
sorted_text += current_sort_text
|
|
||||||
sorted_text += list_bottom
|
|
||||||
return sorted_text
|
|
||||||
|
|
||||||
|
|
||||||
proc/dd_sortedTextList(list/incoming)
|
|
||||||
var/case_sensitive = 1
|
|
||||||
return dd_sortedtextlist(incoming, case_sensitive)
|
|
||||||
|
|
||||||
|
|
||||||
/datum/proc/dd_SortValue()
|
|
||||||
return "[src]"
|
|
||||||
|
|
||||||
/obj/machinery/dd_SortValue()
|
|
||||||
return "[sanitize_old(name)]"
|
|
||||||
|
|
||||||
/obj/machinery/camera/dd_SortValue()
|
|
||||||
return "[c_tag]"
|
|
||||||
|
|
||||||
/datum/alarm/dd_SortValue()
|
|
||||||
return "[sanitize_old(last_name)]"
|
|
||||||
|
|
||||||
/proc/subtypesof(prototype)
|
|
||||||
return (typesof(prototype) - prototype)
|
|
||||||
|
|
||||||
//creates every subtype of prototype (excluding prototype) and adds it to list L.
|
|
||||||
//if no list/L is provided, one is created.
|
|
||||||
/proc/init_subtypes(prototype, list/L)
|
|
||||||
if(!istype(L)) L = list()
|
|
||||||
for(var/path in subtypesof(prototype))
|
|
||||||
L += new path()
|
|
||||||
return L
|
|
||||||
|
|
||||||
//creates every subtype of prototype (excluding prototype) and adds it to list L as a type/instance pair.
|
|
||||||
//if no list/L is provided, one is created.
|
|
||||||
/proc/init_subtypes_assoc(prototype, list/L)
|
|
||||||
if(!istype(L)) L = list()
|
|
||||||
for(var/path in subtypesof(prototype))
|
|
||||||
L[path] = new path()
|
|
||||||
return L
|
|
||||||
|
|
||||||
//Move a single element from position fromIndex within a list, to position toIndex
|
|
||||||
//All elements in the range [1,toIndex) before the move will be before the pivot afterwards
|
|
||||||
//All elements in the range [toIndex, L.len+1) before the move will be after the pivot afterwards
|
|
||||||
//In other words, it's as if the range [fromIndex,toIndex) have been rotated using a <<< operation common to other languages.
|
|
||||||
//fromIndex and toIndex must be in the range [1,L.len+1]
|
|
||||||
//This will preserve associations ~Carnie
|
|
||||||
/proc/moveElement(list/L, fromIndex, toIndex)
|
|
||||||
if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move
|
|
||||||
return
|
|
||||||
if(fromIndex > toIndex)
|
|
||||||
++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one
|
|
||||||
|
|
||||||
L.Insert(toIndex, null)
|
|
||||||
L.Swap(fromIndex, toIndex)
|
|
||||||
L.Cut(fromIndex, fromIndex+1)
|
|
||||||
|
|
||||||
//Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex)
|
|
||||||
//Same as moveElement but for ranges of elements
|
|
||||||
//This will preserve associations ~Carnie
|
|
||||||
/proc/moveRange(list/L, fromIndex, toIndex, len=1)
|
|
||||||
var/distance = abs(toIndex - fromIndex)
|
|
||||||
if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements
|
|
||||||
if(fromIndex <= toIndex)
|
|
||||||
return //no need to move
|
|
||||||
fromIndex += len //we want to shift left instead of right
|
|
||||||
|
|
||||||
for(var/i=0, i<distance, ++i)
|
|
||||||
L.Insert(fromIndex, null)
|
|
||||||
L.Swap(fromIndex, toIndex)
|
|
||||||
L.Cut(toIndex, toIndex+1)
|
|
||||||
else
|
|
||||||
if(fromIndex > toIndex)
|
|
||||||
fromIndex += len
|
|
||||||
|
|
||||||
for(var/i=0, i<len, ++i)
|
|
||||||
L.Insert(toIndex, null)
|
|
||||||
L.Swap(fromIndex, toIndex)
|
|
||||||
L.Cut(fromIndex, fromIndex+1)
|
|
||||||
|
|
||||||
//replaces reverseList ~Carnie
|
|
||||||
/proc/reverseRange(list/L, start=1, end=0)
|
|
||||||
if(L.len)
|
|
||||||
start = start % L.len
|
|
||||||
end = end % (L.len+1)
|
|
||||||
if(start <= 0)
|
|
||||||
start += L.len
|
|
||||||
if(end <= 0)
|
|
||||||
end += L.len + 1
|
|
||||||
|
|
||||||
--end
|
|
||||||
while(start < end)
|
|
||||||
L.Swap(start++,end--)
|
|
||||||
|
|
||||||
return L
|
|
||||||
|
|
||||||
//Copies a list, and all lists inside it recusively
|
|
||||||
//Does not copy any other reference type
|
|
||||||
/proc/deepCopyList(list/l)
|
|
||||||
if(!islist(l))
|
|
||||||
return l
|
|
||||||
. = l.Copy()
|
|
||||||
for(var/i = 1 to l.len)
|
|
||||||
if(islist(.[i]))
|
|
||||||
.[i] = .(.[i])
|
|
||||||
|
|
||||||
//Return a list with no duplicate entries
|
|
||||||
/proc/uniqueList(list/L)
|
|
||||||
. = list()
|
|
||||||
for(var/i in L)
|
|
||||||
. |= i
|
|
||||||
@@ -285,16 +285,3 @@ Proc for attack log creation, because really why not
|
|||||||
else
|
else
|
||||||
. = getCompoundIcon(desired)
|
. = getCompoundIcon(desired)
|
||||||
cached_character_icons[cachekey] = .
|
cached_character_icons[cachekey] = .
|
||||||
|
|
||||||
/proc/getviewsize(view)
|
|
||||||
var/viewX
|
|
||||||
var/viewY
|
|
||||||
if(isnum(view))
|
|
||||||
var/totalviewrange = 1 + 2 * view
|
|
||||||
viewX = totalviewrange
|
|
||||||
viewY = totalviewrange
|
|
||||||
else
|
|
||||||
var/list/viewrangelist = splittext(view,"x")
|
|
||||||
viewX = text2num(viewrangelist[1])
|
|
||||||
viewY = text2num(viewrangelist[2])
|
|
||||||
return list(viewX, viewY)
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
/proc/cmp_subsystem_priority(datum/controller/subsystem/a, datum/controller/subsystem/b)
|
/proc/cmp_subsystem_priority(datum/controller/subsystem/a, datum/controller/subsystem/b)
|
||||||
return a.priority - b.priority
|
return a.priority - b.priority
|
||||||
|
|
||||||
|
/proc/cmp_timer(datum/timedevent/a, datum/timedevent/b)
|
||||||
|
return a.timeToRun - b.timeToRun
|
||||||
|
|
||||||
// Sorts qdel statistics recorsd by time and count
|
// Sorts qdel statistics recorsd by time and count
|
||||||
/proc/cmp_qdel_item_time(datum/qdel_item/A, datum/qdel_item/B)
|
/proc/cmp_qdel_item_time(datum/qdel_item/A, datum/qdel_item/B)
|
||||||
. = B.hard_delete_time - A.hard_delete_time
|
. = B.hard_delete_time - A.hard_delete_time
|
||||||
|
|||||||
@@ -1403,6 +1403,20 @@ var/mob/dview/dview_mob = new
|
|||||||
#undef NOT_FLAG
|
#undef NOT_FLAG
|
||||||
#undef HAS_FLAG
|
#undef HAS_FLAG
|
||||||
|
|
||||||
|
//datum may be null, but it does need to be a typed var
|
||||||
|
#define NAMEOF(datum, X) (#X || ##datum.##X)
|
||||||
|
|
||||||
|
#define VARSET_LIST_CALLBACK(target, var_name, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##target, ##var_name, ##var_value)
|
||||||
|
//dupe code because dm can't handle 3 level deep macros
|
||||||
|
#define VARSET_CALLBACK(datum, var, var_value) CALLBACK(GLOBAL_PROC, /proc/___callbackvarset, ##datum, NAMEOF(##datum, ##var), ##var_value)
|
||||||
|
|
||||||
|
/proc/___callbackvarset(list_or_datum, var_name, var_value)
|
||||||
|
if(length(list_or_datum))
|
||||||
|
list_or_datum[var_name] = var_value
|
||||||
|
return
|
||||||
|
var/datum/D = list_or_datum
|
||||||
|
D.vars[var_name] = var_value
|
||||||
|
|
||||||
// Returns direction-string, rounded to multiples of 22.5, from the first parameter to the second
|
// Returns direction-string, rounded to multiples of 22.5, from the first parameter to the second
|
||||||
// N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW
|
// N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW
|
||||||
/proc/get_adir(var/turf/A, var/turf/B)
|
/proc/get_adir(var/turf/A, var/turf/B)
|
||||||
|
|||||||
12
code/_helpers/view.dm
Normal file
12
code/_helpers/view.dm
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/proc/getviewsize(view)
|
||||||
|
var/viewX
|
||||||
|
var/viewY
|
||||||
|
if(isnum(view))
|
||||||
|
var/totalviewrange = 1 + 2 * view
|
||||||
|
viewX = totalviewrange
|
||||||
|
viewY = totalviewrange
|
||||||
|
else
|
||||||
|
var/list/viewrangelist = splittext(view,"x")
|
||||||
|
viewX = text2num(viewrangelist[1])
|
||||||
|
viewY = text2num(viewrangelist[2])
|
||||||
|
return list(viewX, viewY)
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
if(!locate(/turf) in list(A, A.loc)) // Prevents inventory from being drilled
|
if(!locate(/turf) in list(A, A.loc)) // Prevents inventory from being drilled
|
||||||
return
|
return
|
||||||
var/obj/mecha/M = loc
|
var/obj/mecha/M = loc
|
||||||
return M.click_action(A, src)
|
return M.click_action(A, src, params)
|
||||||
|
|
||||||
if(restrained())
|
if(restrained())
|
||||||
setClickCooldown(10)
|
setClickCooldown(10)
|
||||||
@@ -282,10 +282,10 @@
|
|||||||
Laser Eyes: as the name implies, handles this since nothing else does currently
|
Laser Eyes: as the name implies, handles this since nothing else does currently
|
||||||
face_atom: turns the mob towards what you clicked on
|
face_atom: turns the mob towards what you clicked on
|
||||||
*/
|
*/
|
||||||
/mob/proc/LaserEyes(atom/A)
|
/mob/proc/LaserEyes(atom/A, params)
|
||||||
return
|
return
|
||||||
|
|
||||||
/mob/living/LaserEyes(atom/A)
|
/mob/living/LaserEyes(atom/A, params)
|
||||||
setClickCooldown(4)
|
setClickCooldown(4)
|
||||||
var/turf/T = get_turf(src)
|
var/turf/T = get_turf(src)
|
||||||
|
|
||||||
@@ -293,8 +293,11 @@
|
|||||||
LE.icon = 'icons/effects/genetics.dmi'
|
LE.icon = 'icons/effects/genetics.dmi'
|
||||||
LE.icon_state = "eyelasers"
|
LE.icon_state = "eyelasers"
|
||||||
playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
|
playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
|
||||||
LE.launch(A)
|
LE.firer = src
|
||||||
/mob/living/carbon/human/LaserEyes()
|
LE.preparePixelProjectile(A, src, params)
|
||||||
|
LE.fire()
|
||||||
|
|
||||||
|
/mob/living/carbon/human/LaserEyes(atom/A, params)
|
||||||
if(nutrition>0)
|
if(nutrition>0)
|
||||||
..()
|
..()
|
||||||
nutrition = max(nutrition - rand(1,5),0)
|
nutrition = max(nutrition - rand(1,5),0)
|
||||||
|
|||||||
@@ -82,7 +82,7 @@
|
|||||||
/datum/action/proc/Deactivate()
|
/datum/action/proc/Deactivate()
|
||||||
return
|
return
|
||||||
|
|
||||||
/datum/action/proc/Process()
|
/datum/action/process()
|
||||||
return
|
return
|
||||||
|
|
||||||
/datum/action/proc/CheckRemoval(mob/living/user) // 1 if action is no longer valid for this mob and should be removed
|
/datum/action/proc/CheckRemoval(mob/living/user) // 1 if action is no longer valid for this mob and should be removed
|
||||||
|
|||||||
16
code/controllers/subsystems/processing/projectiles.dm
Normal file
16
code/controllers/subsystems/processing/projectiles.dm
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
PROCESSING_SUBSYSTEM_DEF(projectiles)
|
||||||
|
name = "Projectiles"
|
||||||
|
wait = 1
|
||||||
|
stat_tag = "PP"
|
||||||
|
priority = FIRE_PRIORITY_PROJECTILES
|
||||||
|
flags = SS_NO_INIT|SS_TICKER
|
||||||
|
var/global_max_tick_moves = 10
|
||||||
|
var/global_pixel_speed = 2
|
||||||
|
var/global_iterations_per_move = 16
|
||||||
|
|
||||||
|
/datum/controller/subsystem/processing/projectiles/proc/set_pixel_speed(new_speed)
|
||||||
|
global_pixel_speed = new_speed
|
||||||
|
for(var/i in processing)
|
||||||
|
var/obj/item/projectile/P = i
|
||||||
|
if(istype(P)) //there's non projectiles on this too.
|
||||||
|
P.set_pixel_speed(new_speed)
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
qdel(timer)
|
qdel(timer)
|
||||||
|
|
||||||
weakref = null // Clear this reference to ensure it's kept for as brief duration as possible.
|
weakref = null // Clear this reference to ensure it's kept for as brief duration as possible.
|
||||||
|
|
||||||
tag = null
|
tag = null
|
||||||
SSnanoui.close_uis(src)
|
SSnanoui.close_uis(src)
|
||||||
return QDEL_HINT_QUEUE
|
return QDEL_HINT_QUEUE
|
||||||
|
|||||||
227
code/datums/position_point_vector.dm
Normal file
227
code/datums/position_point_vector.dm
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
//Designed for things that need precision trajectories like projectiles.
|
||||||
|
//Don't use this for anything that you don't absolutely have to use this with (like projectiles!) because it isn't worth using a datum unless you need accuracy down to decimal places in pixels.
|
||||||
|
|
||||||
|
//You might see places where it does - 16 - 1. This is intentionally 17 instead of 16, because of how byond's tiles work and how not doing it will result in rounding errors like things getting put on the wrong turf.
|
||||||
|
|
||||||
|
#define RETURN_PRECISE_POSITION(A) new /datum/position(A)
|
||||||
|
#define RETURN_PRECISE_POINT(A) new /datum/point(A)
|
||||||
|
|
||||||
|
#define RETURN_POINT_VECTOR(ATOM, ANGLE, SPEED) {new /datum/point/vector(ATOM, null, null, null, null, ANGLE, SPEED)}
|
||||||
|
#define RETURN_POINT_VECTOR_INCREMENT(ATOM, ANGLE, SPEED, AMT) {new /datum/point/vector(ATOM, null, null, null, null, ANGLE, SPEED, AMT)}
|
||||||
|
|
||||||
|
/datum/position //For positions with map x/y/z and pixel x/y so you don't have to return lists. Could use addition/subtraction in the future I guess.
|
||||||
|
var/x = 0
|
||||||
|
var/y = 0
|
||||||
|
var/z = 0
|
||||||
|
var/pixel_x = 0
|
||||||
|
var/pixel_y = 0
|
||||||
|
|
||||||
|
/datum/position/proc/valid()
|
||||||
|
return x && y && z && !isnull(pixel_x) && !isnull(pixel_y)
|
||||||
|
|
||||||
|
/datum/position/New(_x = 0, _y = 0, _z = 0, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/point.
|
||||||
|
if(istype(_x, /datum/point))
|
||||||
|
var/datum/point/P = _x
|
||||||
|
var/turf/T = P.return_turf()
|
||||||
|
_x = T.x
|
||||||
|
_y = T.y
|
||||||
|
_z = T.z
|
||||||
|
_pixel_x = P.return_px()
|
||||||
|
_pixel_y = P.return_py()
|
||||||
|
else if(istype(_x, /atom))
|
||||||
|
var/atom/A = _x
|
||||||
|
_x = A.x
|
||||||
|
_y = A.y
|
||||||
|
_z = A.z
|
||||||
|
_pixel_x = A.pixel_x
|
||||||
|
_pixel_y = A.pixel_y
|
||||||
|
x = _x
|
||||||
|
y = _y
|
||||||
|
z = _z
|
||||||
|
pixel_x = _pixel_x
|
||||||
|
pixel_y = _pixel_y
|
||||||
|
|
||||||
|
/datum/position/proc/return_turf()
|
||||||
|
return locate(x, y, z)
|
||||||
|
|
||||||
|
/datum/position/proc/return_px()
|
||||||
|
return pixel_x
|
||||||
|
|
||||||
|
/datum/position/proc/return_py()
|
||||||
|
return pixel_y
|
||||||
|
|
||||||
|
/datum/position/proc/return_point()
|
||||||
|
return new /datum/point(src)
|
||||||
|
|
||||||
|
/proc/point_midpoint_points(datum/point/a, datum/point/b) //Obviously will not support multiZ calculations! Same for the two below.
|
||||||
|
var/datum/point/P = new
|
||||||
|
P.x = a.x + (b.x - a.x) / 2
|
||||||
|
P.y = a.y + (b.y - a.y) / 2
|
||||||
|
P.z = a.z
|
||||||
|
return P
|
||||||
|
|
||||||
|
/proc/pixel_length_between_points(datum/point/a, datum/point/b)
|
||||||
|
return sqrt(((b.x - a.x) ** 2) + ((b.y - a.y) ** 2))
|
||||||
|
|
||||||
|
/proc/angle_between_points(datum/point/a, datum/point/b)
|
||||||
|
return ATAN2((b.y - a.y), (b.x - a.x))
|
||||||
|
|
||||||
|
/datum/point //A precise point on the map in absolute pixel locations based on world.icon_size. Pixels are FROM THE EDGE OF THE MAP!
|
||||||
|
var/x = 0
|
||||||
|
var/y = 0
|
||||||
|
var/z = 0
|
||||||
|
|
||||||
|
/datum/point/proc/valid()
|
||||||
|
return x && y && z
|
||||||
|
|
||||||
|
/datum/point/proc/copy_to(datum/point/p = new)
|
||||||
|
p.x = x
|
||||||
|
p.y = y
|
||||||
|
p.z = z
|
||||||
|
return p
|
||||||
|
|
||||||
|
/datum/point/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0) //first argument can also be a /datum/position or /atom.
|
||||||
|
if(istype(_x, /datum/position))
|
||||||
|
var/datum/position/P = _x
|
||||||
|
_x = P.x
|
||||||
|
_y = P.y
|
||||||
|
_z = P.z
|
||||||
|
_pixel_x = P.pixel_x
|
||||||
|
_pixel_y = P.pixel_y
|
||||||
|
else if(istype(_x, /atom))
|
||||||
|
var/atom/A = _x
|
||||||
|
_x = A.x
|
||||||
|
_y = A.y
|
||||||
|
_z = A.z
|
||||||
|
_pixel_x = A.pixel_x
|
||||||
|
_pixel_y = A.pixel_y
|
||||||
|
initialize_location(_x, _y, _z, _pixel_x, _pixel_y)
|
||||||
|
|
||||||
|
/datum/point/proc/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
|
||||||
|
if(!isnull(tile_x))
|
||||||
|
x = ((tile_x - 1) * world.icon_size) + world.icon_size / 2 + p_x + 1
|
||||||
|
if(!isnull(tile_y))
|
||||||
|
y = ((tile_y - 1) * world.icon_size) + world.icon_size / 2 + p_y + 1
|
||||||
|
if(!isnull(tile_z))
|
||||||
|
z = tile_z
|
||||||
|
|
||||||
|
/datum/point/proc/debug_out()
|
||||||
|
var/turf/T = return_turf()
|
||||||
|
return "\ref[src] aX [x] aY [y] aZ [z] pX [return_px()] pY [return_py()] mX [T.x] mY [T.y] mZ [T.z]"
|
||||||
|
|
||||||
|
/datum/point/proc/move_atom_to_src(atom/movable/AM)
|
||||||
|
AM.forceMove(return_turf())
|
||||||
|
AM.pixel_x = return_px()
|
||||||
|
AM.pixel_y = return_py()
|
||||||
|
|
||||||
|
/datum/point/proc/return_turf()
|
||||||
|
return locate(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
|
||||||
|
|
||||||
|
/datum/point/proc/return_coordinates() //[turf_x, turf_y, z]
|
||||||
|
return list(CEILING(x / world.icon_size, 1), CEILING(y / world.icon_size, 1), z)
|
||||||
|
|
||||||
|
/datum/point/proc/return_position()
|
||||||
|
return new /datum/position(src)
|
||||||
|
|
||||||
|
/datum/point/proc/return_px()
|
||||||
|
return MODULUS(x, world.icon_size) - 16 - 1
|
||||||
|
|
||||||
|
/datum/point/proc/return_py()
|
||||||
|
return MODULUS(y, world.icon_size) - 16 - 1
|
||||||
|
|
||||||
|
|
||||||
|
/datum/point/vector
|
||||||
|
var/speed = 32 //pixels per iteration
|
||||||
|
var/iteration = 0
|
||||||
|
var/angle = 0
|
||||||
|
var/mpx = 0 //calculated x/y movement amounts to prevent having to do trig every step.
|
||||||
|
var/mpy = 0
|
||||||
|
var/starting_x = 0 //just like before, pixels from EDGE of map! This is set in initialize_location().
|
||||||
|
var/starting_y = 0
|
||||||
|
var/starting_z = 0
|
||||||
|
|
||||||
|
/datum/point/vector/New(_x, _y, _z, _pixel_x = 0, _pixel_y = 0, _angle, _speed, initial_increment = 0)
|
||||||
|
..()
|
||||||
|
initialize_trajectory(_speed, _angle)
|
||||||
|
if(initial_increment)
|
||||||
|
increment(initial_increment)
|
||||||
|
|
||||||
|
/datum/point/vector/initialize_location(tile_x, tile_y, tile_z, p_x = 0, p_y = 0)
|
||||||
|
. = ..()
|
||||||
|
starting_x = x
|
||||||
|
starting_y = y
|
||||||
|
starting_z = z
|
||||||
|
|
||||||
|
/datum/point/vector/copy_to(datum/point/vector/v = new)
|
||||||
|
..(v)
|
||||||
|
v.speed = speed
|
||||||
|
v.iteration = iteration
|
||||||
|
v.angle = angle
|
||||||
|
v.mpx = mpx
|
||||||
|
v.mpy = mpy
|
||||||
|
v.starting_x = starting_x
|
||||||
|
v.starting_y = starting_y
|
||||||
|
v.starting_z = starting_z
|
||||||
|
return v
|
||||||
|
|
||||||
|
/datum/point/vector/proc/initialize_trajectory(pixel_speed, new_angle)
|
||||||
|
if(!isnull(pixel_speed))
|
||||||
|
speed = pixel_speed
|
||||||
|
set_angle(new_angle)
|
||||||
|
|
||||||
|
/datum/point/vector/proc/set_angle(new_angle) //calculations use "byond angle" where north is 0 instead of 90, and south is 180 instead of 270.
|
||||||
|
if(isnull(angle))
|
||||||
|
return
|
||||||
|
angle = new_angle
|
||||||
|
update_offsets()
|
||||||
|
|
||||||
|
/datum/point/vector/proc/update_offsets()
|
||||||
|
mpx = sin(angle) * speed
|
||||||
|
mpy = cos(angle) * speed
|
||||||
|
|
||||||
|
/datum/point/vector/proc/set_speed(new_speed)
|
||||||
|
if(isnull(new_speed) || speed == new_speed)
|
||||||
|
return
|
||||||
|
speed = new_speed
|
||||||
|
update_offsets()
|
||||||
|
|
||||||
|
/datum/point/vector/proc/increment(multiplier = 1)
|
||||||
|
iteration++
|
||||||
|
x += mpx * multiplier
|
||||||
|
y += mpy * multiplier
|
||||||
|
|
||||||
|
/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
|
||||||
|
var/datum/point/vector/v = copy_to()
|
||||||
|
if(force_simulate)
|
||||||
|
for(var/i in 1 to amount)
|
||||||
|
v.increment(multiplier)
|
||||||
|
else
|
||||||
|
v.increment(multiplier * amount)
|
||||||
|
return v
|
||||||
|
|
||||||
|
/datum/point/vector/proc/on_z_change()
|
||||||
|
return
|
||||||
|
|
||||||
|
/datum/point/vector/processed //pixel_speed is per decisecond.
|
||||||
|
var/last_process = 0
|
||||||
|
var/last_move = 0
|
||||||
|
var/paused = FALSE
|
||||||
|
|
||||||
|
/datum/point/vector/processed/Destroy()
|
||||||
|
STOP_PROCESSING(SSprojectiles, src)
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/datum/point/vector/processed/proc/start()
|
||||||
|
last_process = world.time
|
||||||
|
last_move = world.time
|
||||||
|
START_PROCESSING(SSprojectiles, src)
|
||||||
|
|
||||||
|
/datum/point/vector/processed/process()
|
||||||
|
if(paused)
|
||||||
|
last_move += world.time - last_process
|
||||||
|
last_process = world.time
|
||||||
|
return
|
||||||
|
var/needed_time = world.time - last_move
|
||||||
|
last_process = world.time
|
||||||
|
last_move = world.time
|
||||||
|
increment(needed_time / SSprojectiles.wait)
|
||||||
@@ -8,13 +8,14 @@
|
|||||||
var/list/blood_DNA
|
var/list/blood_DNA
|
||||||
var/was_bloodied
|
var/was_bloodied
|
||||||
var/blood_color
|
var/blood_color
|
||||||
var/last_bumped = 0
|
|
||||||
var/pass_flags = 0
|
var/pass_flags = 0
|
||||||
var/throwpass = 0
|
var/throwpass = 0
|
||||||
var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom.
|
var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom.
|
||||||
var/simulated = 1 //filter for actions - used by lighting overlays
|
var/simulated = 1 //filter for actions - used by lighting overlays
|
||||||
var/fluorescent // Shows up under a UV light.
|
var/fluorescent // Shows up under a UV light.
|
||||||
|
|
||||||
|
var/last_bumped = 0
|
||||||
|
|
||||||
///Chemistry.
|
///Chemistry.
|
||||||
var/datum/reagents/reagents = null
|
var/datum/reagents/reagents = null
|
||||||
|
|
||||||
@@ -98,7 +99,7 @@
|
|||||||
return -1
|
return -1
|
||||||
|
|
||||||
/atom/proc/Bumped(AM as mob|obj)
|
/atom/proc/Bumped(AM as mob|obj)
|
||||||
return
|
set waitfor = FALSE
|
||||||
|
|
||||||
// Convenience proc to see if a container is open for chemistry handling
|
// Convenience proc to see if a container is open for chemistry handling
|
||||||
// returns true if open
|
// returns true if open
|
||||||
@@ -496,7 +497,7 @@
|
|||||||
if(!istype(drop_destination) || drop_destination == destination)
|
if(!istype(drop_destination) || drop_destination == destination)
|
||||||
return forceMove(destination)
|
return forceMove(destination)
|
||||||
destination = drop_destination
|
destination = drop_destination
|
||||||
return forceMove(null)
|
return moveToNullspace()
|
||||||
|
|
||||||
/atom/proc/onDropInto(var/atom/movable/AM)
|
/atom/proc/onDropInto(var/atom/movable/AM)
|
||||||
return // If onDropInto returns null, then dropInto will forceMove AM into us.
|
return // If onDropInto returns null, then dropInto will forceMove AM into us.
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
var/last_move = null
|
var/last_move = null
|
||||||
var/anchored = 0
|
var/anchored = 0
|
||||||
// var/elevation = 2 - not used anywhere
|
// var/elevation = 2 - not used anywhere
|
||||||
|
var/moving_diagonally
|
||||||
var/move_speed = 10
|
var/move_speed = 10
|
||||||
var/l_move_time = 1
|
var/l_move_time = 1
|
||||||
var/m_flag = 1
|
var/m_flag = 1
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
var/old_y = 0
|
var/old_y = 0
|
||||||
var/datum/riding/riding_datum //VOREStation Add - Moved from /obj/vehicle
|
var/datum/riding/riding_datum //VOREStation Add - Moved from /obj/vehicle
|
||||||
var/does_spin = TRUE // Does the atom spin when thrown (of course it does :P)
|
var/does_spin = TRUE // Does the atom spin when thrown (of course it does :P)
|
||||||
|
var/movement_type = NONE
|
||||||
|
|
||||||
/atom/movable/Destroy()
|
/atom/movable/Destroy()
|
||||||
. = ..()
|
. = ..()
|
||||||
@@ -33,7 +35,7 @@
|
|||||||
if(opacity && isturf(loc))
|
if(opacity && isturf(loc))
|
||||||
un_opaque = loc
|
un_opaque = loc
|
||||||
|
|
||||||
loc = null
|
moveToNullspace()
|
||||||
if(un_opaque)
|
if(un_opaque)
|
||||||
un_opaque.recalc_atom_opacity()
|
un_opaque.recalc_atom_opacity()
|
||||||
if (pulledby)
|
if (pulledby)
|
||||||
@@ -42,56 +44,234 @@
|
|||||||
pulledby = null
|
pulledby = null
|
||||||
QDEL_NULL(riding_datum) //VOREStation Add
|
QDEL_NULL(riding_datum) //VOREStation Add
|
||||||
|
|
||||||
/atom/movable/vv_edit_var(var_name, var_value)
|
////////////////////////////////////////
|
||||||
if(GLOB.VVpixelmovement[var_name]) //Pixel movement is not yet implemented, changing this will break everything irreversibly.
|
// Here's where we rewrite how byond handles movement except slightly different
|
||||||
return FALSE
|
// To be removed on step_ conversion
|
||||||
return ..()
|
// All this work to prevent a second bump
|
||||||
|
/atom/movable/Move(atom/newloc, direct=0)
|
||||||
/atom/movable/Bump(var/atom/A, yes)
|
. = FALSE
|
||||||
if(src.throwing)
|
if(!newloc || newloc == loc)
|
||||||
src.throw_impact(A)
|
|
||||||
src.throwing = 0
|
|
||||||
|
|
||||||
spawn(0)
|
|
||||||
if ((A && yes))
|
|
||||||
A.last_bumped = world.time
|
|
||||||
A.Bumped(src)
|
|
||||||
return
|
return
|
||||||
..()
|
|
||||||
|
if(!direct)
|
||||||
|
direct = get_dir(src, newloc)
|
||||||
|
set_dir(direct)
|
||||||
|
|
||||||
|
if(!loc.Exit(src, newloc))
|
||||||
|
return
|
||||||
|
|
||||||
|
if(!newloc.Enter(src, src.loc))
|
||||||
|
return
|
||||||
|
// Past this is the point of no return
|
||||||
|
var/atom/oldloc = loc
|
||||||
|
var/area/oldarea = get_area(oldloc)
|
||||||
|
var/area/newarea = get_area(newloc)
|
||||||
|
loc = newloc
|
||||||
|
. = TRUE
|
||||||
|
oldloc.Exited(src, newloc)
|
||||||
|
if(oldarea != newarea)
|
||||||
|
oldarea.Exited(src, newloc)
|
||||||
|
|
||||||
|
for(var/i in oldloc)
|
||||||
|
if(i == src) // Multi tile objects
|
||||||
|
continue
|
||||||
|
var/atom/movable/thing = i
|
||||||
|
thing.Uncrossed(src)
|
||||||
|
|
||||||
|
newloc.Entered(src, oldloc)
|
||||||
|
if(oldarea != newarea)
|
||||||
|
newarea.Entered(src, oldloc)
|
||||||
|
|
||||||
|
for(var/i in loc)
|
||||||
|
if(i == src) // Multi tile objects
|
||||||
|
continue
|
||||||
|
var/atom/movable/thing = i
|
||||||
|
thing.Crossed(src)
|
||||||
|
//
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
/atom/movable/Move(atom/newloc, direct)
|
||||||
|
if(!loc || !newloc)
|
||||||
|
return FALSE
|
||||||
|
var/atom/oldloc = loc
|
||||||
|
|
||||||
|
if(loc != newloc)
|
||||||
|
if (!(direct & (direct - 1))) //Cardinal move
|
||||||
|
. = ..()
|
||||||
|
else //Diagonal move, split it into cardinal moves
|
||||||
|
moving_diagonally = FIRST_DIAG_STEP
|
||||||
|
var/first_step_dir
|
||||||
|
// The `&& moving_diagonally` checks are so that a forceMove taking
|
||||||
|
// place due to a Crossed, Bumped, etc. call will interrupt
|
||||||
|
// the second half of the diagonal movement, or the second attempt
|
||||||
|
// at a first half if step() fails because we hit something.
|
||||||
|
if (direct & NORTH)
|
||||||
|
if (direct & EAST)
|
||||||
|
if (step(src, NORTH) && moving_diagonally)
|
||||||
|
first_step_dir = NORTH
|
||||||
|
moving_diagonally = SECOND_DIAG_STEP
|
||||||
|
. = step(src, EAST)
|
||||||
|
else if (moving_diagonally && step(src, EAST))
|
||||||
|
first_step_dir = EAST
|
||||||
|
moving_diagonally = SECOND_DIAG_STEP
|
||||||
|
. = step(src, NORTH)
|
||||||
|
else if (direct & WEST)
|
||||||
|
if (step(src, NORTH) && moving_diagonally)
|
||||||
|
first_step_dir = NORTH
|
||||||
|
moving_diagonally = SECOND_DIAG_STEP
|
||||||
|
. = step(src, WEST)
|
||||||
|
else if (moving_diagonally && step(src, WEST))
|
||||||
|
first_step_dir = WEST
|
||||||
|
moving_diagonally = SECOND_DIAG_STEP
|
||||||
|
. = step(src, NORTH)
|
||||||
|
else if (direct & SOUTH)
|
||||||
|
if (direct & EAST)
|
||||||
|
if (step(src, SOUTH) && moving_diagonally)
|
||||||
|
first_step_dir = SOUTH
|
||||||
|
moving_diagonally = SECOND_DIAG_STEP
|
||||||
|
. = step(src, EAST)
|
||||||
|
else if (moving_diagonally && step(src, EAST))
|
||||||
|
first_step_dir = EAST
|
||||||
|
moving_diagonally = SECOND_DIAG_STEP
|
||||||
|
. = step(src, SOUTH)
|
||||||
|
else if (direct & WEST)
|
||||||
|
if (step(src, SOUTH) && moving_diagonally)
|
||||||
|
first_step_dir = SOUTH
|
||||||
|
moving_diagonally = SECOND_DIAG_STEP
|
||||||
|
. = step(src, WEST)
|
||||||
|
else if (moving_diagonally && step(src, WEST))
|
||||||
|
first_step_dir = WEST
|
||||||
|
moving_diagonally = SECOND_DIAG_STEP
|
||||||
|
. = step(src, SOUTH)
|
||||||
|
if(moving_diagonally == SECOND_DIAG_STEP)
|
||||||
|
if(!.)
|
||||||
|
set_dir(first_step_dir)
|
||||||
|
//else if (!inertia_moving)
|
||||||
|
// inertia_next_move = world.time + inertia_move_delay
|
||||||
|
// newtonian_move(direct)
|
||||||
|
moving_diagonally = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
if(!loc || (loc == oldloc && oldloc != newloc))
|
||||||
|
last_move = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
if(.)
|
||||||
|
Moved(oldloc, direct)
|
||||||
|
|
||||||
|
//Polaris stuff
|
||||||
|
move_speed = world.time - l_move_time
|
||||||
|
l_move_time = world.time
|
||||||
|
m_flag = 1
|
||||||
|
//End
|
||||||
|
|
||||||
|
last_move = direct
|
||||||
|
set_dir(direct)
|
||||||
|
if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc,direct)) //movement failed due to buckled mob(s)
|
||||||
|
return FALSE
|
||||||
|
|
||||||
|
//Called after a successful Move(). By this point, we've already moved
|
||||||
|
/atom/movable/proc/Moved(atom/OldLoc, Dir, Forced = FALSE)
|
||||||
|
//if (!inertia_moving)
|
||||||
|
// inertia_next_move = world.time + inertia_move_delay
|
||||||
|
// newtonian_move(Dir)
|
||||||
|
//if (length(client_mobs_in_contents))
|
||||||
|
// update_parallax_contents()
|
||||||
|
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
// Make sure you know what you're doing if you call this, this is intended to only be called by byond directly.
|
||||||
|
// You probably want CanPass()
|
||||||
|
/atom/movable/Cross(atom/movable/AM)
|
||||||
|
. = TRUE
|
||||||
|
return CanPass(AM, loc)
|
||||||
|
|
||||||
|
//oldloc = old location on atom, inserted when forceMove is called and ONLY when forceMove is called!
|
||||||
|
/atom/movable/Crossed(atom/movable/AM, oldloc)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
/atom/movable/Uncross(atom/movable/AM, atom/newloc)
|
||||||
|
. = ..()
|
||||||
|
if(isturf(newloc) && !CheckExit(AM, newloc))
|
||||||
|
return FALSE
|
||||||
|
|
||||||
|
/atom/movable/Bump(atom/A)
|
||||||
|
if(!A)
|
||||||
|
CRASH("Bump was called with no argument.")
|
||||||
|
. = ..()
|
||||||
|
if(throwing)
|
||||||
|
throw_impact(A)
|
||||||
|
throwing = 0
|
||||||
|
if(QDELETED(A))
|
||||||
|
return
|
||||||
|
A.Bumped(src)
|
||||||
|
A.last_bumped = world.time
|
||||||
|
|
||||||
/atom/movable/proc/forceMove(atom/destination)
|
/atom/movable/proc/forceMove(atom/destination)
|
||||||
if(loc == destination)
|
. = FALSE
|
||||||
return 0
|
|
||||||
var/is_origin_turf = isturf(loc)
|
|
||||||
var/is_destination_turf = isturf(destination)
|
|
||||||
// It is a new area if:
|
|
||||||
// Both the origin and destination are turfs with different areas.
|
|
||||||
// When either origin or destination is a turf and the other is not.
|
|
||||||
var/is_new_area = (is_origin_turf ^ is_destination_turf) || (is_origin_turf && is_destination_turf && loc.loc != destination.loc)
|
|
||||||
|
|
||||||
var/atom/origin = loc
|
|
||||||
loc = destination
|
|
||||||
|
|
||||||
if(origin)
|
|
||||||
origin.Exited(src, destination)
|
|
||||||
if(is_origin_turf)
|
|
||||||
for(var/atom/movable/AM in origin)
|
|
||||||
AM.Uncrossed(src)
|
|
||||||
if(is_new_area && is_origin_turf)
|
|
||||||
origin.loc.Exited(src, destination)
|
|
||||||
|
|
||||||
if(destination)
|
if(destination)
|
||||||
destination.Entered(src, origin)
|
. = doMove(destination)
|
||||||
if(is_destination_turf) // If we're entering a turf, cross all movable atoms
|
else
|
||||||
for(var/atom/movable/AM in loc)
|
CRASH("No valid destination passed into forceMove")
|
||||||
if(AM != src)
|
|
||||||
AM.Crossed(src)
|
|
||||||
if(is_new_area && is_destination_turf)
|
|
||||||
destination.loc.Entered(src, origin)
|
|
||||||
|
|
||||||
Moved(origin)
|
/atom/movable/proc/moveToNullspace()
|
||||||
return 1
|
return doMove(null)
|
||||||
|
|
||||||
|
/atom/movable/proc/doMove(atom/destination)
|
||||||
|
. = FALSE
|
||||||
|
if(destination)
|
||||||
|
if(pulledby)
|
||||||
|
pulledby.stop_pulling()
|
||||||
|
var/atom/oldloc = loc
|
||||||
|
var/same_loc = oldloc == destination
|
||||||
|
var/area/old_area = get_area(oldloc)
|
||||||
|
var/area/destarea = get_area(destination)
|
||||||
|
|
||||||
|
loc = destination
|
||||||
|
moving_diagonally = 0
|
||||||
|
|
||||||
|
if(!same_loc)
|
||||||
|
if(oldloc)
|
||||||
|
oldloc.Exited(src, destination)
|
||||||
|
if(old_area && old_area != destarea)
|
||||||
|
old_area.Exited(src, destination)
|
||||||
|
for(var/atom/movable/AM in oldloc)
|
||||||
|
AM.Uncrossed(src)
|
||||||
|
var/turf/oldturf = get_turf(oldloc)
|
||||||
|
var/turf/destturf = get_turf(destination)
|
||||||
|
var/old_z = (oldturf ? oldturf.z : null)
|
||||||
|
var/dest_z = (destturf ? destturf.z : null)
|
||||||
|
if (old_z != dest_z)
|
||||||
|
onTransitZ(old_z, dest_z)
|
||||||
|
destination.Entered(src, oldloc)
|
||||||
|
if(destarea && old_area != destarea)
|
||||||
|
destarea.Entered(src, oldloc)
|
||||||
|
|
||||||
|
for(var/atom/movable/AM in destination)
|
||||||
|
if(AM == src)
|
||||||
|
continue
|
||||||
|
AM.Crossed(src, oldloc)
|
||||||
|
|
||||||
|
Moved(oldloc, NONE, TRUE)
|
||||||
|
. = TRUE
|
||||||
|
|
||||||
|
//If no destination, move the atom into nullspace (don't do this unless you know what you're doing)
|
||||||
|
else
|
||||||
|
. = TRUE
|
||||||
|
if (loc)
|
||||||
|
var/atom/oldloc = loc
|
||||||
|
var/area/old_area = get_area(oldloc)
|
||||||
|
oldloc.Exited(src, null)
|
||||||
|
if(old_area)
|
||||||
|
old_area.Exited(src, null)
|
||||||
|
loc = null
|
||||||
|
|
||||||
|
/atom/movable/proc/onTransitZ(old_z,new_z)
|
||||||
|
GLOB.z_moved_event.raise_event(src, old_z, new_z)
|
||||||
|
for(var/item in src) // Notify contents of Z-transition. This can be overridden IF we know the items contents do not care.
|
||||||
|
var/atom/movable/AM = item
|
||||||
|
AM.onTransitZ(old_z,new_z)
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
//called when src is thrown into hit_atom
|
//called when src is thrown into hit_atom
|
||||||
/atom/movable/proc/throw_impact(atom/hit_atom, var/speed)
|
/atom/movable/proc/throw_impact(atom/hit_atom, var/speed)
|
||||||
@@ -295,15 +475,12 @@
|
|||||||
|
|
||||||
/atom/movable/proc/adjust_rotation(new_rotation)
|
/atom/movable/proc/adjust_rotation(new_rotation)
|
||||||
icon_rotation = new_rotation
|
icon_rotation = new_rotation
|
||||||
|
<<<<<<< HEAD
|
||||||
|
update_transform()
|
||||||
|
=======
|
||||||
update_transform()
|
update_transform()
|
||||||
|
|
||||||
// Called when touching a lava tile.
|
// Called when touching a lava tile.
|
||||||
/atom/movable/proc/lava_act()
|
/atom/movable/proc/lava_act()
|
||||||
fire_act(null, 10000, 1000)
|
fire_act(null, 10000, 1000)
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
// Called when something changes z-levels.
|
|
||||||
/atom/movable/proc/on_z_change(old_z, new_z)
|
|
||||||
GLOB.z_moved_event.raise_event(src, old_z, new_z)
|
|
||||||
for(var/item in src) // Notify contents of Z-transition. This can be overriden IF we know the items contents do not care.
|
|
||||||
var/atom/movable/AM = item
|
|
||||||
AM.on_z_change(old_z, new_z)
|
|
||||||
|
|||||||
@@ -532,7 +532,8 @@ proc/findNullRod(var/atom/target)
|
|||||||
/obj/item/weapon/spell/construct/projectile/on_ranged_cast(atom/hit_atom, mob/living/user)
|
/obj/item/weapon/spell/construct/projectile/on_ranged_cast(atom/hit_atom, mob/living/user)
|
||||||
if(set_up(hit_atom, user))
|
if(set_up(hit_atom, user))
|
||||||
var/obj/item/projectile/new_projectile = make_projectile(spell_projectile, user)
|
var/obj/item/projectile/new_projectile = make_projectile(spell_projectile, user)
|
||||||
new_projectile.launch(hit_atom)
|
new_projectile.old_style_target(hit_atom)
|
||||||
|
new_projectile.fire()
|
||||||
log_and_message_admins("has casted [src] at \the [hit_atom].")
|
log_and_message_admins("has casted [src] at \the [hit_atom].")
|
||||||
if(fire_sound)
|
if(fire_sound)
|
||||||
playsound(get_turf(src), fire_sound, 75, 1)
|
playsound(get_turf(src), fire_sound, 75, 1)
|
||||||
@@ -597,9 +598,9 @@ proc/findNullRod(var/atom/target)
|
|||||||
light_power = -2
|
light_power = -2
|
||||||
light_color = "#FFFFFF"
|
light_color = "#FFFFFF"
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/inversion/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/inversion
|
||||||
tracer_type = /obj/effect/projectile/inversion/tracer
|
tracer_type = /obj/effect/projectile/tracer/inversion
|
||||||
impact_type = /obj/effect/projectile/inversion/impact
|
impact_type = /obj/effect/projectile/impact/inversion
|
||||||
|
|
||||||
//Harvester Pain Orb
|
//Harvester Pain Orb
|
||||||
|
|
||||||
|
|||||||
@@ -75,9 +75,10 @@
|
|||||||
H.update_action_buttons()
|
H.update_action_buttons()
|
||||||
..()
|
..()
|
||||||
|
|
||||||
/obj/item/clothing/suit/armor/tesla/proc/shoot_lightning(var/mob/target, var/power)
|
/obj/item/clothing/suit/armor/tesla/proc/shoot_lightning(mob/target, power)
|
||||||
var/obj/item/projectile/beam/lightning/lightning = new(src)
|
var/obj/item/projectile/beam/lightning/lightning = new(get_turf(src))
|
||||||
lightning.power = power
|
lightning.power = power
|
||||||
lightning.launch(target)
|
lightning.old_style_target(target)
|
||||||
|
lightning.fire()
|
||||||
visible_message("<span class='danger'>\The [src] strikes \the [target] with lightning!</span>")
|
visible_message("<span class='danger'>\The [src] strikes \the [target] with lightning!</span>")
|
||||||
playsound(get_turf(src), 'sound/weapons/gauss_shoot.ogg', 75, 1)
|
playsound(get_turf(src), 'sound/weapons/gauss_shoot.ogg', 75, 1)
|
||||||
@@ -165,14 +165,15 @@
|
|||||||
while(i)
|
while(i)
|
||||||
var/obj/item/projectile/beam/lightning/energy_siphon/lightning = new(get_turf(source))
|
var/obj/item/projectile/beam/lightning/energy_siphon/lightning = new(get_turf(source))
|
||||||
lightning.firer = user
|
lightning.firer = user
|
||||||
lightning.launch(user)
|
lightning.old_style_target(user)
|
||||||
|
lightning.fire()
|
||||||
i--
|
i--
|
||||||
sleep(3)
|
sleep(3)
|
||||||
|
|
||||||
/obj/item/projectile/beam/lightning/energy_siphon
|
/obj/item/projectile/beam/lightning/energy_siphon
|
||||||
name = "energy stream"
|
name = "energy stream"
|
||||||
icon_state = "lightning"
|
icon_state = "lightning"
|
||||||
kill_count = 6 // Backup plan in-case the effect somehow misses the Technomancer.
|
range = 6 // Backup plan in-case the effect somehow misses the Technomancer.
|
||||||
power = 5 // This fires really fast, so this may add up if someone keeps standing in the beam.
|
power = 5 // This fires really fast, so this may add up if someone keeps standing in the beam.
|
||||||
penetrating = 5
|
penetrating = 5
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,6 @@
|
|||||||
/obj/item/projectile/beam/blue
|
/obj/item/projectile/beam/blue
|
||||||
damage = 30
|
damage = 30
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/laser_blue/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/laser_blue
|
||||||
tracer_type = /obj/effect/projectile/laser_blue/tracer
|
tracer_type = /obj/effect/projectile/tracer/laser_blue
|
||||||
impact_type = /obj/effect/projectile/laser_blue/impact
|
impact_type = /obj/effect/projectile/impact/laser_blue
|
||||||
|
|||||||
@@ -26,9 +26,9 @@
|
|||||||
nodamage = 1
|
nodamage = 1
|
||||||
damage_type = HALLOSS
|
damage_type = HALLOSS
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/lightning/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/lightning
|
||||||
tracer_type = /obj/effect/projectile/lightning/tracer
|
tracer_type = /obj/effect/projectile/tracer/lightning
|
||||||
impact_type = /obj/effect/projectile/lightning/impact
|
impact_type = /obj/effect/projectile/impact/lightning
|
||||||
|
|
||||||
var/bounces = 3 //How many times it 'chains'. Note that the first hit is not counted as it counts /bounces/.
|
var/bounces = 3 //How many times it 'chains'. Note that the first hit is not counted as it counts /bounces/.
|
||||||
var/list/hit_mobs = list() //Mobs which were already hit.
|
var/list/hit_mobs = list() //Mobs which were already hit.
|
||||||
|
|||||||
@@ -26,9 +26,9 @@
|
|||||||
nodamage = 1
|
nodamage = 1
|
||||||
damage_type = HALLOSS
|
damage_type = HALLOSS
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/lightning/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/lightning
|
||||||
tracer_type = /obj/effect/projectile/lightning/tracer
|
tracer_type = /obj/effect/projectile/tracer/lightning
|
||||||
impact_type = /obj/effect/projectile/lightning/impact
|
impact_type = /obj/effect/projectile/impact/lightning
|
||||||
|
|
||||||
var/power = 60 //How hard it will hit for with electrocute_act().
|
var/power = 60 //How hard it will hit for with electrocute_act().
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
/obj/item/weapon/spell/projectile/on_ranged_cast(atom/hit_atom, mob/living/user)
|
/obj/item/weapon/spell/projectile/on_ranged_cast(atom/hit_atom, mob/living/user)
|
||||||
if(set_up(hit_atom, user))
|
if(set_up(hit_atom, user))
|
||||||
var/obj/item/projectile/new_projectile = make_projectile(spell_projectile, user)
|
var/obj/item/projectile/new_projectile = make_projectile(spell_projectile, user)
|
||||||
new_projectile.launch(hit_atom)
|
new_projectile.old_style_target(hit_atom)
|
||||||
|
new_projectile.fire()
|
||||||
log_and_message_admins("has casted [src] at \the [hit_atom].")
|
log_and_message_admins("has casted [src] at \the [hit_atom].")
|
||||||
if(fire_sound)
|
if(fire_sound)
|
||||||
playsound(get_turf(src), fire_sound, 75, 1)
|
playsound(get_turf(src), fire_sound, 75, 1)
|
||||||
|
|||||||
@@ -98,6 +98,7 @@
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/machinery/door/Bumped(atom/AM)
|
/obj/machinery/door/Bumped(atom/AM)
|
||||||
|
. = ..()
|
||||||
if(p_open || operating)
|
if(p_open || operating)
|
||||||
return
|
return
|
||||||
if(ismob(AM))
|
if(ismob(AM))
|
||||||
@@ -133,9 +134,6 @@
|
|||||||
open()
|
open()
|
||||||
else
|
else
|
||||||
do_animate("deny")
|
do_animate("deny")
|
||||||
return
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
/obj/machinery/door/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
/obj/machinery/door/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||||
if(air_group) return !block_air_zones
|
if(air_group) return !block_air_zones
|
||||||
|
|||||||
@@ -68,33 +68,26 @@
|
|||||||
if(istype(bot))
|
if(istype(bot))
|
||||||
if(density && src.check_access(bot.botcard))
|
if(density && src.check_access(bot.botcard))
|
||||||
open()
|
open()
|
||||||
sleep(50)
|
addtimer(CALLBACK(src, .proc/close), 50)
|
||||||
close()
|
|
||||||
else if(istype(AM, /obj/mecha))
|
else if(istype(AM, /obj/mecha))
|
||||||
var/obj/mecha/mecha = AM
|
var/obj/mecha/mecha = AM
|
||||||
if(density)
|
if(density)
|
||||||
if(mecha.occupant && src.allowed(mecha.occupant))
|
if(mecha.occupant && src.allowed(mecha.occupant))
|
||||||
open()
|
open()
|
||||||
sleep(50)
|
addtimer(CALLBACK(src, .proc/close), 50)
|
||||||
close()
|
|
||||||
return
|
return
|
||||||
if (!( ticker ))
|
if (!( ticker ))
|
||||||
return
|
return
|
||||||
if (src.operating)
|
if (src.operating)
|
||||||
return
|
return
|
||||||
if (src.density && src.allowed(AM))
|
if (density && allowed(AM))
|
||||||
open()
|
open()
|
||||||
if(src.check_access(null))
|
addtimer(CALLBACK(src, .proc/close), check_access(null)? 50 : 20)
|
||||||
sleep(50)
|
|
||||||
else //secure doors close faster
|
|
||||||
sleep(20)
|
|
||||||
close()
|
|
||||||
return
|
|
||||||
|
|
||||||
/obj/machinery/door/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
/obj/machinery/door/window/CanPass(atom/movable/mover, turf/target, height, air_group)
|
||||||
if(istype(mover) && mover.checkpass(PASSGLASS))
|
if(istype(mover) && mover.checkpass(PASSGLASS))
|
||||||
return 1
|
return 1
|
||||||
if(get_dir(loc, target) == dir) //Make sure looking at appropriate border
|
if(get_dir(mover, loc) == turn(dir, 180)) //Make sure looking at appropriate border
|
||||||
if(air_group) return 0
|
if(air_group) return 0
|
||||||
return !density
|
return !density
|
||||||
else
|
else
|
||||||
@@ -109,7 +102,7 @@
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/machinery/door/window/open()
|
/obj/machinery/door/window/open()
|
||||||
if (operating == 1) //doors can still open when emag-disabled
|
if (operating == 1 || !density) //doors can still open when emag-disabled
|
||||||
return 0
|
return 0
|
||||||
if (!ticker)
|
if (!ticker)
|
||||||
return 0
|
return 0
|
||||||
@@ -129,20 +122,20 @@
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/machinery/door/window/close()
|
/obj/machinery/door/window/close()
|
||||||
if (operating)
|
if(operating || density)
|
||||||
return 0
|
return FALSE
|
||||||
src.operating = 1
|
operating = TRUE
|
||||||
flick(text("[]closing", src.base_state), src)
|
flick(text("[]closing", src.base_state), src)
|
||||||
playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1)
|
playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1)
|
||||||
|
|
||||||
density = 1
|
density = TRUE
|
||||||
update_icon()
|
update_icon()
|
||||||
explosion_resistance = initial(explosion_resistance)
|
explosion_resistance = initial(explosion_resistance)
|
||||||
update_nearby_tiles()
|
update_nearby_tiles()
|
||||||
|
|
||||||
sleep(10)
|
sleep(10)
|
||||||
operating = 0
|
operating = FALSE
|
||||||
return 1
|
return TRUE
|
||||||
|
|
||||||
/obj/machinery/door/window/take_damage(var/damage)
|
/obj/machinery/door/window/take_damage(var/damage)
|
||||||
src.health = max(0, src.health - damage)
|
src.health = max(0, src.health - damage)
|
||||||
|
|||||||
@@ -17,9 +17,12 @@
|
|||||||
/datum/computer/file/embedded_program/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
|
/datum/computer/file/embedded_program/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
|
||||||
return
|
return
|
||||||
|
|
||||||
/datum/computer/file/embedded_program/process()
|
<<<<<<< HEAD
|
||||||
|
/datum/computer/file/embedded_program/proc/process()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
/datum/computer/file/embedded_program/proc/post_signal(datum/signal/signal, comm_line)
|
/datum/computer/file/embedded_program/proc/post_signal(datum/signal/signal, comm_line)
|
||||||
if(master)
|
if(master)
|
||||||
master.post_signal(signal, comm_line)
|
master.post_signal(signal, comm_line)
|
||||||
|
|||||||
@@ -722,7 +722,10 @@ var/list/turret_icons
|
|||||||
def_zone = pick(BP_TORSO, BP_GROIN)
|
def_zone = pick(BP_TORSO, BP_GROIN)
|
||||||
|
|
||||||
//Shooting Code:
|
//Shooting Code:
|
||||||
A.launch(target, def_zone)
|
A.firer = src
|
||||||
|
A.old_style_target(target)
|
||||||
|
A.def_zone = def_zone
|
||||||
|
A.fire()
|
||||||
|
|
||||||
// Reset the time needed to go back down, since we just tried to shoot at someone.
|
// Reset the time needed to go back down, since we just tried to shoot at someone.
|
||||||
timeout = 10
|
timeout = 10
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
return 0
|
return 0
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
/obj/item/mecha_parts/mecha_equipment/weapon/action(atom/target)
|
/obj/item/mecha_parts/mecha_equipment/weapon/action(atom/target, params)
|
||||||
if(!action_checks(target))
|
if(!action_checks(target))
|
||||||
return
|
return
|
||||||
var/turf/curloc = chassis.loc
|
var/turf/curloc = chassis.loc
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
playsound(chassis, fire_sound, fire_volume, 1)
|
playsound(chassis, fire_sound, fire_volume, 1)
|
||||||
projectiles--
|
projectiles--
|
||||||
var/P = new projectile(curloc)
|
var/P = new projectile(curloc)
|
||||||
Fire(P, target)
|
Fire(P, target, params)
|
||||||
if(i == 1)
|
if(i == 1)
|
||||||
set_ready_state(0)
|
set_ready_state(0)
|
||||||
if(fire_cooldown)
|
if(fire_cooldown)
|
||||||
@@ -60,11 +60,12 @@
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
/obj/item/mecha_parts/mecha_equipment/weapon/proc/Fire(atom/A, atom/target)
|
/obj/item/mecha_parts/mecha_equipment/weapon/proc/Fire(atom/A, atom/target, params)
|
||||||
var/obj/item/projectile/P = A
|
var/obj/item/projectile/P = A
|
||||||
P.dispersion = deviation
|
P.dispersion = deviation
|
||||||
process_accuracy(P, chassis.occupant, target)
|
process_accuracy(P, chassis.occupant, target)
|
||||||
P.launch(target)
|
P.preparePixelProjectile(target, chassis.occupant, params)
|
||||||
|
P.fire()
|
||||||
|
|
||||||
/obj/item/mecha_parts/mecha_equipment/weapon/proc/process_accuracy(obj/projectile, mob/living/user, atom/target)
|
/obj/item/mecha_parts/mecha_equipment/weapon/proc/process_accuracy(obj/projectile, mob/living/user, atom/target)
|
||||||
var/obj/item/projectile/P = projectile
|
var/obj/item/projectile/P = projectile
|
||||||
|
|||||||
@@ -317,7 +317,7 @@
|
|||||||
// return ..()
|
// return ..()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/obj/mecha/proc/click_action(atom/target,mob/user)
|
/obj/mecha/proc/click_action(atom/target,mob/user, params)
|
||||||
if(!src.occupant || src.occupant != user ) return
|
if(!src.occupant || src.occupant != user ) return
|
||||||
if(user.stat) return
|
if(user.stat) return
|
||||||
if(state)
|
if(state)
|
||||||
@@ -339,7 +339,7 @@
|
|||||||
if(selected && selected.is_ranged())
|
if(selected && selected.is_ranged())
|
||||||
selected.action(target)
|
selected.action(target)
|
||||||
else if(selected && selected.is_melee())
|
else if(selected && selected.is_melee())
|
||||||
selected.action(target)
|
selected.action(target, params)
|
||||||
else
|
else
|
||||||
src.melee_action(target)
|
src.melee_action(target)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -195,6 +195,7 @@
|
|||||||
else
|
else
|
||||||
L.set_dir(dir)
|
L.set_dir(dir)
|
||||||
return TRUE
|
return TRUE
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
/atom/movable/Move(atom/newloc, direct = 0)
|
/atom/movable/Move(atom/newloc, direct = 0)
|
||||||
. = ..()
|
. = ..()
|
||||||
@@ -205,3 +206,5 @@
|
|||||||
riding_datum.handle_vehicle_layer()
|
riding_datum.handle_vehicle_layer()
|
||||||
riding_datum.handle_vehicle_offsets()
|
riding_datum.handle_vehicle_offsets()
|
||||||
//VOREStation Add End
|
//VOREStation Add End
|
||||||
|
=======
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
/obj/effect/projectile/impact
|
||||||
|
name = "beam impact"
|
||||||
|
icon = 'icons/obj/projectiles_impact.dmi'
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/laser_pulse
|
||||||
|
icon_state = "impact_u_laser"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#0066FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/laser_heavy
|
||||||
|
icon_state = "impact_beam_heavy"
|
||||||
|
light_range = 3
|
||||||
|
light_power = 1
|
||||||
|
light_color = "#FF0D00"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/xray
|
||||||
|
icon_state = "impact_xray"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00CC33"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/laser_omni
|
||||||
|
icon_state = "impact_omni"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00C6FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/laser
|
||||||
|
icon_state = "impact_laser"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#FF0D00"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/laser_blue
|
||||||
|
icon_state = "impact_blue"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#0066FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/emitter
|
||||||
|
icon_state = "impact_emitter"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00CC33"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/stun
|
||||||
|
icon_state = "impact_stun"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#FFFFFF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/lightning
|
||||||
|
icon_state = "impact_lightning"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00C6FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/darkmatterstun
|
||||||
|
icon_state = "impact_darkt"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#8837A3"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/inversion
|
||||||
|
icon_state = "impact_invert"
|
||||||
|
light_range = 2
|
||||||
|
light_power = -2
|
||||||
|
light_color = "#FFFFFF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/impact/darkmatter
|
||||||
|
icon_state = "impact_darkb"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#8837A3"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tungsten/impact
|
||||||
|
icon_state = "impact_mhd_laser"
|
||||||
|
light_range = 4
|
||||||
|
light_power = 3
|
||||||
|
light_color = "#3300ff"
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/obj/effect/projectile/muzzle
|
||||||
|
name = "muzzle flash"
|
||||||
|
icon = 'icons/obj/projectiles_muzzle.dmi'
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/emitter
|
||||||
|
icon_state = "muzzle_emitter"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00CC33"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/laser_pulse
|
||||||
|
icon_state = "muzzle_u_laser"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#0066FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/pulse
|
||||||
|
icon_state = "muzzle_pulse"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#0066FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/stun
|
||||||
|
icon_state = "muzzle_stun"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#FFFFFF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/bullet
|
||||||
|
icon_state = "muzzle_bullet"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#FFFFFF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/laser_heavy
|
||||||
|
icon_state = "muzzle_beam_heavy"
|
||||||
|
light_range = 3
|
||||||
|
light_power = 1
|
||||||
|
light_color = "#FF0D00"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/lightning
|
||||||
|
icon_state = "muzzle_lightning"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00C6FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/darkmatterstun
|
||||||
|
icon_state = "muzzle_darkt"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#8837A3"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/laser_blue
|
||||||
|
icon_state = "muzzle_blue"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#0066FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/darkmatter
|
||||||
|
icon_state = "muzzle_darkb"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#8837A3"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/inversion
|
||||||
|
icon_state = "muzzle_invert"
|
||||||
|
light_range = 2
|
||||||
|
light_power = -2
|
||||||
|
light_color = "#FFFFFF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/xray
|
||||||
|
icon_state = "muzzle_xray"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00CC33"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/laser_omni
|
||||||
|
icon_state = "muzzle_omni"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00C6FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/muzzle/laser
|
||||||
|
icon_state = "muzzle_laser"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#FF0D00"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tungsten/muzzle
|
||||||
|
icon_state = "muzzle_mhd_laser"
|
||||||
|
light_range = 4
|
||||||
|
light_power = 3
|
||||||
|
light_color = "#3300ff"
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/obj/effect/projectile
|
||||||
|
name = "pew"
|
||||||
|
icon = 'icons/obj/projectiles.dmi'
|
||||||
|
icon_state = "nothing"
|
||||||
|
layer = ABOVE_MOB_LAYER
|
||||||
|
anchored = TRUE
|
||||||
|
mouse_opacity = 0
|
||||||
|
appearance_flags = 0
|
||||||
|
|
||||||
|
/obj/effect/projectile/singularity_pull()
|
||||||
|
return
|
||||||
|
|
||||||
|
/obj/effect/projectile/singularity_act()
|
||||||
|
return
|
||||||
|
|
||||||
|
/obj/effect/projectile/proc/scale_to(nx,ny,override=TRUE)
|
||||||
|
var/matrix/M
|
||||||
|
if(!override)
|
||||||
|
M = transform
|
||||||
|
else
|
||||||
|
M = new
|
||||||
|
M.Scale(nx,ny)
|
||||||
|
transform = M
|
||||||
|
|
||||||
|
/obj/effect/projectile/proc/turn_to(angle,override=TRUE)
|
||||||
|
var/matrix/M
|
||||||
|
if(!override)
|
||||||
|
M = transform
|
||||||
|
else
|
||||||
|
M = new
|
||||||
|
M.Turn(angle)
|
||||||
|
transform = M
|
||||||
|
|
||||||
|
/obj/effect/projectile/New(angle_override, p_x, p_y, color_override, scaling = 1)
|
||||||
|
if(angle_override && p_x && p_y && color_override && scaling)
|
||||||
|
apply_vars(angle_override, p_x, p_y, color_override, scaling)
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/obj/effect/projectile/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, new_loc, increment = 0)
|
||||||
|
var/mutable_appearance/look = new(src)
|
||||||
|
look.pixel_x = p_x
|
||||||
|
look.pixel_y = p_y
|
||||||
|
if(color_override)
|
||||||
|
look.color = color_override
|
||||||
|
appearance = look
|
||||||
|
scale_to(1,scaling, FALSE)
|
||||||
|
turn_to(angle_override, FALSE)
|
||||||
|
if(!isnull(new_loc)) //If you want to null it just delete it...
|
||||||
|
forceMove(new_loc)
|
||||||
|
for(var/i in 1 to increment)
|
||||||
|
pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
|
||||||
|
pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
|
||||||
|
|
||||||
|
/obj/effect/projectile_lighting
|
||||||
|
var/owner
|
||||||
|
|
||||||
|
/obj/effect/projectile_lighting/New(loc, color, range, intensity, owner_key)
|
||||||
|
. = ..()
|
||||||
|
set_light(range, intensity, color)
|
||||||
|
owner = owner_key
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/proc/generate_tracer_between_points(datum/point/starting, datum/point/ending, beam_type, color, qdel_in = 5, light_range = 2, light_color_override, light_intensity = 1, instance_key) //Do not pass z-crossing points as that will not be properly (and likely will never be properly until it's absolutely needed) supported!
|
||||||
|
if(!istype(starting) || !istype(ending) || !ispath(beam_type))
|
||||||
|
return
|
||||||
|
var/datum/point/midpoint = point_midpoint_points(starting, ending)
|
||||||
|
var/obj/effect/projectile/tracer/PB = new beam_type
|
||||||
|
if(isnull(light_color_override))
|
||||||
|
light_color_override = color
|
||||||
|
PB.apply_vars(angle_between_points(starting, ending), midpoint.return_px(), midpoint.return_py(), color, pixel_length_between_points(starting, ending) / world.icon_size, midpoint.return_turf(), 0)
|
||||||
|
. = PB
|
||||||
|
if(isnull(light_intensity) && !isnull(PB.light_power))
|
||||||
|
light_intensity = PB.light_power
|
||||||
|
if(isnull(light_range) && !isnull(PB.light_range))
|
||||||
|
light_range = PB.light_range
|
||||||
|
if(isnull(light_color_override) && !isnull(PB.light_color))
|
||||||
|
light_color_override = PB.light_color
|
||||||
|
if(light_range > 0 && light_intensity > 0)
|
||||||
|
var/list/turf/line = getline(starting.return_turf(), ending.return_turf())
|
||||||
|
tracing_line:
|
||||||
|
for(var/i in line)
|
||||||
|
var/turf/T = i
|
||||||
|
for(var/obj/effect/projectile_lighting/PL in T)
|
||||||
|
if(PL.owner == instance_key)
|
||||||
|
continue tracing_line
|
||||||
|
QDEL_IN(new /obj/effect/projectile_lighting(T, light_color_override, light_range, light_intensity, instance_key), qdel_in > 0? qdel_in : 5)
|
||||||
|
line = null
|
||||||
|
if(qdel_in)
|
||||||
|
QDEL_IN(PB, qdel_in)
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer
|
||||||
|
name = "beam"
|
||||||
|
icon = 'icons/obj/projectiles_tracer.dmi'
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/stun
|
||||||
|
icon_state = "stun"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#FFFFFF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/lightning
|
||||||
|
icon_state = "lightning"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00C6FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/laser_pulse
|
||||||
|
icon_state = "u_laser"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#0066FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/emitter
|
||||||
|
icon_state = "emitter"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00CC33"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/darkmatterstun
|
||||||
|
icon_state = "darkt"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#8837A3"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/laser_omni
|
||||||
|
icon_state = "beam_omni"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00C6FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/xray
|
||||||
|
icon_state = "xray"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#00CC33"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/laser_heavy
|
||||||
|
icon_state = "beam_heavy"
|
||||||
|
light_range = 3
|
||||||
|
light_power = 1
|
||||||
|
light_color = "#FF0D00"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/darkmatter
|
||||||
|
icon_state = "darkb"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#8837A3"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/inversion
|
||||||
|
icon_state = "invert"
|
||||||
|
light_range = 2
|
||||||
|
light_power = -2
|
||||||
|
light_color = "#FFFFFF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/laser
|
||||||
|
icon_state = "beam"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#FF0D00"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tracer/laser_blue
|
||||||
|
icon_state = "beam_blue"
|
||||||
|
light_range = 2
|
||||||
|
light_power = 0.5
|
||||||
|
light_color = "#0066FF"
|
||||||
|
|
||||||
|
/obj/effect/projectile/tungsten/tracer
|
||||||
|
icon_state = "mhd_laser"
|
||||||
|
light_range = 4
|
||||||
|
light_power = 3
|
||||||
|
light_color = "#3300ff"
|
||||||
@@ -7,14 +7,17 @@
|
|||||||
mouse_opacity = 0
|
mouse_opacity = 0
|
||||||
var/duration = 10 //in deciseconds
|
var/duration = 10 //in deciseconds
|
||||||
var/randomdir = TRUE
|
var/randomdir = TRUE
|
||||||
|
var/timerid
|
||||||
|
|
||||||
/obj/effect/temp_visual/Initialize()
|
/obj/effect/temp_visual/initialize()
|
||||||
. = ..()
|
. = ..()
|
||||||
if(randomdir)
|
if(randomdir)
|
||||||
set_dir(pick(cardinal))
|
dir = pick(list(NORTH, SOUTH, EAST, WEST))
|
||||||
|
timerid = QDEL_IN(src, duration)
|
||||||
|
|
||||||
spawn(duration)
|
/obj/effect/temp_visual/Destroy()
|
||||||
qdel(src)
|
. = ..()
|
||||||
|
deltimer(timerid)
|
||||||
|
|
||||||
/obj/effect/temp_visual/singularity_act()
|
/obj/effect/temp_visual/singularity_act()
|
||||||
return
|
return
|
||||||
@@ -25,12 +28,12 @@
|
|||||||
/obj/effect/temp_visual/ex_act()
|
/obj/effect/temp_visual/ex_act()
|
||||||
return
|
return
|
||||||
|
|
||||||
/*
|
|
||||||
/obj/effect/temp_visual/dir_setting
|
/obj/effect/temp_visual/dir_setting
|
||||||
randomdir = FALSE
|
randomdir = FALSE
|
||||||
|
|
||||||
/obj/effect/temp_visual/dir_setting/Initialize(mapload, set_dir)
|
/obj/effect/temp_visual/dir_setting/Initialize(loc, set_dir)
|
||||||
if(set_dir)
|
if(set_dir)
|
||||||
setDir(set_dir)
|
dir = set_dir
|
||||||
. = ..()
|
. = ..()
|
||||||
*/ //More tg stuff that might be useful later
|
|
||||||
|
|
||||||
@@ -50,9 +50,10 @@
|
|||||||
var/fragment_type = pickweight(fragtypes)
|
var/fragment_type = pickweight(fragtypes)
|
||||||
var/obj/item/projectile/bullet/pellet/fragment/P = new fragment_type(T)
|
var/obj/item/projectile/bullet/pellet/fragment/P = new fragment_type(T)
|
||||||
P.pellets = fragments_per_projectile
|
P.pellets = fragments_per_projectile
|
||||||
P.shot_from = src.name
|
P.shot_from = name
|
||||||
|
|
||||||
P.launch(O)
|
P.old_style_target(O)
|
||||||
|
P.fire()
|
||||||
|
|
||||||
//Make sure to hit any mobs in the source turf
|
//Make sure to hit any mobs in the source turf
|
||||||
for(var/mob/living/M in T)
|
for(var/mob/living/M in T)
|
||||||
|
|||||||
@@ -61,7 +61,8 @@
|
|||||||
var/obj/item/projectile/P = new shot_type(T)
|
var/obj/item/projectile/P = new shot_type(T)
|
||||||
P.shot_from = src.name
|
P.shot_from = src.name
|
||||||
|
|
||||||
P.launch(O)
|
P.old_style_target(O)
|
||||||
|
P.fire()
|
||||||
|
|
||||||
//Make sure to hit any mobs in the source turf
|
//Make sure to hit any mobs in the source turf
|
||||||
for(var/mob/living/M in T)
|
for(var/mob/living/M in T)
|
||||||
|
|||||||
@@ -69,9 +69,10 @@
|
|||||||
else
|
else
|
||||||
to_chat(user, "It is full.")
|
to_chat(user, "It is full.")
|
||||||
|
|
||||||
/obj/structure/closet/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
/obj/structure/closet/CanPass(atom/movable/mover, turf/target, height, air_group)
|
||||||
if(air_group || (height==0 || wall_mounted)) return 1
|
if(wall_mounted)
|
||||||
return (!density)
|
return TRUE
|
||||||
|
return ..()
|
||||||
|
|
||||||
/obj/structure/closet/proc/can_open()
|
/obj/structure/closet/proc/can_open()
|
||||||
if(src.sealed)
|
if(src.sealed)
|
||||||
|
|||||||
@@ -131,14 +131,20 @@
|
|||||||
|
|
||||||
/obj/structure/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
/obj/structure/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||||
if(istype(mover) && mover.checkpass(PASSGLASS))
|
if(istype(mover) && mover.checkpass(PASSGLASS))
|
||||||
|
<<<<<<< HEAD
|
||||||
return 1
|
return 1
|
||||||
if(is_fulltile())
|
if(is_fulltile())
|
||||||
return 0 //full tile window, you can't move into it!
|
return 0 //full tile window, you can't move into it!
|
||||||
if(get_dir(loc, target) & dir)
|
if(get_dir(loc, target) & dir)
|
||||||
|
=======
|
||||||
|
return TRUE
|
||||||
|
if(is_fulltile())
|
||||||
|
return FALSE //full tile window, you can't move into it!
|
||||||
|
if((get_dir(loc, target) & dir) || (get_dir(mover, target) == turn(dir, 180)))
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
return !density
|
return !density
|
||||||
else
|
else
|
||||||
return 1
|
return TRUE
|
||||||
|
|
||||||
|
|
||||||
/obj/structure/window/CheckExit(atom/movable/O as mob|obj, target as turf)
|
/obj/structure/window/CheckExit(atom/movable/O as mob|obj, target as turf)
|
||||||
if(istype(O) && O.checkpass(PASSGLASS))
|
if(istype(O) && O.checkpass(PASSGLASS))
|
||||||
@@ -147,7 +153,6 @@
|
|||||||
return 0
|
return 0
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
/obj/structure/window/hitby(AM as mob|obj)
|
/obj/structure/window/hitby(AM as mob|obj)
|
||||||
..()
|
..()
|
||||||
visible_message("<span class='danger'>[src] was hit by [AM].</span>")
|
visible_message("<span class='danger'>[src] was hit by [AM].</span>")
|
||||||
|
|||||||
@@ -142,50 +142,6 @@ turf/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
|||||||
sleep(2)
|
sleep(2)
|
||||||
O.update_transform()
|
O.update_transform()
|
||||||
|
|
||||||
/turf/Enter(atom/movable/mover as mob|obj, atom/forget as mob|obj|turf|area)
|
|
||||||
if(movement_disabled && usr.ckey != movement_disabled_exception)
|
|
||||||
usr << "<span class='warning'>Movement is admin-disabled.</span>" //This is to identify lag problems
|
|
||||||
return
|
|
||||||
|
|
||||||
..()
|
|
||||||
|
|
||||||
if (!mover || !isturf(mover.loc))
|
|
||||||
return 1
|
|
||||||
|
|
||||||
//First, check objects to block exit that are not on the border
|
|
||||||
for(var/obj/obstacle in mover.loc)
|
|
||||||
if(!(obstacle.flags & ON_BORDER) && (mover != obstacle) && (forget != obstacle))
|
|
||||||
if(!obstacle.CheckExit(mover, src))
|
|
||||||
mover.Bump(obstacle, 1)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
//Now, check objects to block exit that are on the border
|
|
||||||
for(var/obj/border_obstacle in mover.loc)
|
|
||||||
if((border_obstacle.flags & ON_BORDER) && (mover != border_obstacle) && (forget != border_obstacle))
|
|
||||||
if(!border_obstacle.CheckExit(mover, src))
|
|
||||||
mover.Bump(border_obstacle, 1)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
//Next, check objects to block entry that are on the border
|
|
||||||
for(var/obj/border_obstacle in src)
|
|
||||||
if(border_obstacle.flags & ON_BORDER)
|
|
||||||
if(!border_obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != border_obstacle))
|
|
||||||
mover.Bump(border_obstacle, 1)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
//Then, check the turf itself
|
|
||||||
if (!src.CanPass(mover, src))
|
|
||||||
mover.Bump(src, 1)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
//Finally, check objects/mobs to block entry that are not on the border
|
|
||||||
for(var/atom/movable/obstacle in src)
|
|
||||||
if(!(obstacle.flags & ON_BORDER))
|
|
||||||
if(!obstacle.CanPass(mover, mover.loc, 1, 0) && (forget != obstacle))
|
|
||||||
mover.Bump(obstacle, 1)
|
|
||||||
return 0
|
|
||||||
return 1 //Nothing found to block so return success!
|
|
||||||
|
|
||||||
var/const/enterloopsanity = 100
|
var/const/enterloopsanity = 100
|
||||||
/turf/Entered(atom/atom as mob|obj)
|
/turf/Entered(atom/atom as mob|obj)
|
||||||
|
|
||||||
@@ -218,14 +174,74 @@ var/const/enterloopsanity = 100
|
|||||||
var/objects = 0
|
var/objects = 0
|
||||||
if(A && (A.flags & PROXMOVE))
|
if(A && (A.flags & PROXMOVE))
|
||||||
for(var/atom/movable/thing in range(1))
|
for(var/atom/movable/thing in range(1))
|
||||||
if(objects > enterloopsanity) break
|
if(objects++ > enterloopsanity) break
|
||||||
objects++
|
|
||||||
spawn(0)
|
spawn(0)
|
||||||
if(A) //Runtime prevention
|
if(A) //Runtime prevention
|
||||||
A.HasProximity(thing, 1)
|
A.HasProximity(thing, 1)
|
||||||
if ((thing && A) && (thing.flags & PROXMOVE))
|
if ((thing && A) && (thing.flags & PROXMOVE))
|
||||||
thing.HasProximity(A, 1)
|
thing.HasProximity(A, 1)
|
||||||
return
|
|
||||||
|
/turf/CanPass(atom/movable/mover, turf/target)
|
||||||
|
if(!target)
|
||||||
|
return FALSE
|
||||||
|
|
||||||
|
if(istype(mover)) // turf/Enter(...) will perform more advanced checks
|
||||||
|
return !density
|
||||||
|
|
||||||
|
crash_with("Non movable passed to turf CanPass : [mover]")
|
||||||
|
return FALSE
|
||||||
|
|
||||||
|
//There's a lot of QDELETED() calls here if someone can figure out how to optimize this but not runtime when something gets deleted by a Bump/CanPass/Cross call, lemme know or go ahead and fix this mess - kevinz000
|
||||||
|
/turf/Enter(atom/movable/mover, atom/oldloc)
|
||||||
|
if(movement_disabled && usr.ckey != movement_disabled_exception)
|
||||||
|
usr << "<span class='warning'>Movement is admin-disabled.</span>" //This is to identify lag problems
|
||||||
|
return
|
||||||
|
// Do not call ..()
|
||||||
|
// Byond's default turf/Enter() doesn't have the behaviour we want with Bump()
|
||||||
|
// By default byond will call Bump() on the first dense object in contents
|
||||||
|
// Here's hoping it doesn't stay like this for years before we finish conversion to step_
|
||||||
|
var/atom/firstbump
|
||||||
|
var/CanPassSelf = CanPass(mover, src)
|
||||||
|
if(CanPassSelf || CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
|
||||||
|
for(var/i in contents)
|
||||||
|
if(QDELETED(mover))
|
||||||
|
return FALSE //We were deleted, do not attempt to proceed with movement.
|
||||||
|
if(i == mover || i == mover.loc) // Multi tile objects and moving out of other objects
|
||||||
|
continue
|
||||||
|
var/atom/movable/thing = i
|
||||||
|
if(!thing.Cross(mover))
|
||||||
|
if(QDELETED(mover)) //Mover deleted from Cross/CanPass, do not proceed.
|
||||||
|
return FALSE
|
||||||
|
if(CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
|
||||||
|
mover.Bump(thing)
|
||||||
|
continue
|
||||||
|
else
|
||||||
|
if(!firstbump || ((thing.layer > firstbump.layer || thing.flags & ON_BORDER) && !(firstbump.flags & ON_BORDER)))
|
||||||
|
firstbump = thing
|
||||||
|
if(QDELETED(mover)) //Mover deleted from Cross/CanPass/Bump, do not proceed.
|
||||||
|
return FALSE
|
||||||
|
if(!CanPassSelf) //Even if mover is unstoppable they need to bump us.
|
||||||
|
firstbump = src
|
||||||
|
if(firstbump)
|
||||||
|
mover.Bump(firstbump)
|
||||||
|
return !QDELETED(mover) && CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE)
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
/turf/Exit(atom/movable/mover, atom/newloc)
|
||||||
|
. = ..()
|
||||||
|
if(!. || QDELETED(mover))
|
||||||
|
return FALSE
|
||||||
|
for(var/i in contents)
|
||||||
|
if(i == mover)
|
||||||
|
continue
|
||||||
|
var/atom/movable/thing = i
|
||||||
|
if(!thing.Uncross(mover, newloc))
|
||||||
|
if(thing.flags & ON_BORDER)
|
||||||
|
mover.Bump(thing)
|
||||||
|
if(!CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
|
||||||
|
return FALSE
|
||||||
|
if(QDELETED(mover))
|
||||||
|
return FALSE //We were deleted.
|
||||||
|
|
||||||
/turf/proc/adjacent_fire_act(turf/simulated/floor/source, temperature, volume)
|
/turf/proc/adjacent_fire_act(turf/simulated/floor/source, temperature, volume)
|
||||||
return
|
return
|
||||||
|
|||||||
639
code/game/world.dm
Normal file
639
code/game/world.dm
Normal file
@@ -0,0 +1,639 @@
|
|||||||
|
|
||||||
|
#define RECOMMENDED_VERSION 501
|
||||||
|
/world/New()
|
||||||
|
world.log << "Map Loading Complete"
|
||||||
|
//logs
|
||||||
|
log_path += time2text(world.realtime, "YYYY/MM-Month/DD-Day/round-hh-mm-ss")
|
||||||
|
diary = file("[log_path].log")
|
||||||
|
href_logfile = file("[log_path]-hrefs.htm")
|
||||||
|
error_log = file("[log_path]-error.log")
|
||||||
|
debug_log = file("[log_path]-debug.log")
|
||||||
|
debug_log << "[log_end]\n[log_end]\nStarting up. [time_stamp()][log_end]\n---------------------[log_end]"
|
||||||
|
changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently
|
||||||
|
|
||||||
|
if(byond_version < RECOMMENDED_VERSION)
|
||||||
|
world.log << "Your server's byond version does not meet the recommended requirements for this server. Please update BYOND"
|
||||||
|
|
||||||
|
config.post_load()
|
||||||
|
|
||||||
|
if(config && config.server_name != null && config.server_suffix && world.port > 0)
|
||||||
|
// dumb and hardcoded but I don't care~
|
||||||
|
config.server_name += " #[(world.port % 1000) / 100]"
|
||||||
|
|
||||||
|
if(config && config.log_runtime)
|
||||||
|
log = file("data/logs/runtime/[time2text(world.realtime,"YYYY-MM-DD-(hh-mm-ss)")]-runtime.log")
|
||||||
|
|
||||||
|
GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
|
||||||
|
|
||||||
|
callHook("startup")
|
||||||
|
//Emergency Fix
|
||||||
|
load_mods()
|
||||||
|
//end-emergency fix
|
||||||
|
|
||||||
|
src.update_status()
|
||||||
|
|
||||||
|
. = ..()
|
||||||
|
|
||||||
|
#if UNIT_TEST
|
||||||
|
log_unit_test("Unit Tests Enabled. This will destroy the world when testing is complete.")
|
||||||
|
log_unit_test("If you did not intend to enable this please check code/__defines/unit_testing.dm")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Set up roundstart seed list.
|
||||||
|
plant_controller = new()
|
||||||
|
|
||||||
|
// This is kinda important. Set up details of what the hell things are made of.
|
||||||
|
populate_material_list()
|
||||||
|
|
||||||
|
// Create frame types.
|
||||||
|
populate_frame_types()
|
||||||
|
|
||||||
|
// Create floor types.
|
||||||
|
populate_flooring_types()
|
||||||
|
|
||||||
|
// Create robolimbs for chargen.
|
||||||
|
populate_robolimb_list()
|
||||||
|
|
||||||
|
processScheduler = new
|
||||||
|
master_controller = new /datum/controller/game_controller()
|
||||||
|
|
||||||
|
processScheduler.deferSetupFor(/datum/controller/process/ticker)
|
||||||
|
processScheduler.setup()
|
||||||
|
Master.Initialize(10, FALSE)
|
||||||
|
|
||||||
|
spawn(1)
|
||||||
|
master_controller.setup()
|
||||||
|
#if UNIT_TEST
|
||||||
|
initialize_unit_tests()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
spawn(3000) //so we aren't adding to the round-start lag
|
||||||
|
if(config.ToRban)
|
||||||
|
ToRban_autoupdate()
|
||||||
|
|
||||||
|
#undef RECOMMENDED_VERSION
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
var/world_topic_spam_protect_ip = "0.0.0.0"
|
||||||
|
var/world_topic_spam_protect_time = world.timeofday
|
||||||
|
|
||||||
|
/world/Topic(T, addr, master, key)
|
||||||
|
debug_log << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key][log_end]"
|
||||||
|
|
||||||
|
if (T == "ping")
|
||||||
|
var/x = 1
|
||||||
|
for (var/client/C)
|
||||||
|
x++
|
||||||
|
return x
|
||||||
|
|
||||||
|
else if(T == "players")
|
||||||
|
var/n = 0
|
||||||
|
for(var/mob/M in player_list)
|
||||||
|
if(M.client)
|
||||||
|
n++
|
||||||
|
return n
|
||||||
|
|
||||||
|
else if (copytext(T,1,7) == "status")
|
||||||
|
var/input[] = params2list(T)
|
||||||
|
var/list/s = list()
|
||||||
|
s["version"] = game_version
|
||||||
|
s["mode"] = master_mode
|
||||||
|
s["respawn"] = config.abandon_allowed
|
||||||
|
s["enter"] = config.enter_allowed
|
||||||
|
s["vote"] = config.allow_vote_mode
|
||||||
|
s["ai"] = config.allow_ai
|
||||||
|
s["host"] = host ? host : null
|
||||||
|
|
||||||
|
// This is dumb, but spacestation13.com's banners break if player count isn't the 8th field of the reply, so... this has to go here.
|
||||||
|
s["players"] = 0
|
||||||
|
s["stationtime"] = stationtime2text()
|
||||||
|
s["roundduration"] = roundduration2text()
|
||||||
|
|
||||||
|
if(input["status"] == "2")
|
||||||
|
var/list/players = list()
|
||||||
|
var/list/admins = list()
|
||||||
|
|
||||||
|
for(var/client/C in GLOB.clients)
|
||||||
|
if(C.holder)
|
||||||
|
if(C.holder.fakekey)
|
||||||
|
continue
|
||||||
|
admins[C.key] = C.holder.rank
|
||||||
|
players += C.key
|
||||||
|
|
||||||
|
s["players"] = players.len
|
||||||
|
s["playerlist"] = list2params(players)
|
||||||
|
var/list/adm = get_admin_counts()
|
||||||
|
var/list/presentmins = adm["present"]
|
||||||
|
var/list/afkmins = adm["afk"]
|
||||||
|
s["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho
|
||||||
|
s["adminlist"] = list2params(admins)
|
||||||
|
else
|
||||||
|
var/n = 0
|
||||||
|
var/admins = 0
|
||||||
|
|
||||||
|
for(var/client/C in GLOB.clients)
|
||||||
|
if(C.holder)
|
||||||
|
if(C.holder.fakekey)
|
||||||
|
continue //so stealthmins aren't revealed by the hub
|
||||||
|
admins++
|
||||||
|
s["player[n]"] = C.key
|
||||||
|
n++
|
||||||
|
|
||||||
|
s["players"] = n
|
||||||
|
s["admins"] = admins
|
||||||
|
|
||||||
|
return list2params(s)
|
||||||
|
|
||||||
|
else if(T == "manifest")
|
||||||
|
var/list/positions = list()
|
||||||
|
var/list/set_names = list(
|
||||||
|
"heads" = command_positions,
|
||||||
|
"sec" = security_positions,
|
||||||
|
"eng" = engineering_positions,
|
||||||
|
"med" = medical_positions,
|
||||||
|
"sci" = science_positions,
|
||||||
|
"car" = cargo_positions,
|
||||||
|
"civ" = civilian_positions,
|
||||||
|
"bot" = nonhuman_positions
|
||||||
|
)
|
||||||
|
|
||||||
|
for(var/datum/data/record/t in data_core.general)
|
||||||
|
var/name = t.fields["name"]
|
||||||
|
var/rank = t.fields["rank"]
|
||||||
|
var/real_rank = make_list_rank(t.fields["real_rank"])
|
||||||
|
|
||||||
|
var/department = 0
|
||||||
|
for(var/k in set_names)
|
||||||
|
if(real_rank in set_names[k])
|
||||||
|
if(!positions[k])
|
||||||
|
positions[k] = list()
|
||||||
|
positions[k][name] = rank
|
||||||
|
department = 1
|
||||||
|
if(!department)
|
||||||
|
if(!positions["misc"])
|
||||||
|
positions["misc"] = list()
|
||||||
|
positions["misc"][name] = rank
|
||||||
|
|
||||||
|
// Synthetics don't have actual records, so we will pull them from here.
|
||||||
|
for(var/mob/living/silicon/ai/ai in mob_list)
|
||||||
|
if(!positions["bot"])
|
||||||
|
positions["bot"] = list()
|
||||||
|
positions["bot"][ai.name] = "Artificial Intelligence"
|
||||||
|
for(var/mob/living/silicon/robot/robot in mob_list)
|
||||||
|
// No combat/syndicate cyborgs, no drones.
|
||||||
|
if(robot.module && robot.module.hide_on_manifest)
|
||||||
|
continue
|
||||||
|
if(!positions["bot"])
|
||||||
|
positions["bot"] = list()
|
||||||
|
positions["bot"][robot.name] = "[robot.modtype] [robot.braintype]"
|
||||||
|
|
||||||
|
for(var/k in positions)
|
||||||
|
positions[k] = list2params(positions[k]) // converts positions["heads"] = list("Bob"="Captain", "Bill"="CMO") into positions["heads"] = "Bob=Captain&Bill=CMO"
|
||||||
|
|
||||||
|
return list2params(positions)
|
||||||
|
|
||||||
|
else if(T == "revision")
|
||||||
|
if(revdata.revision)
|
||||||
|
return list2params(list(branch = revdata.branch, date = revdata.date, revision = revdata.revision))
|
||||||
|
else
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
else if(copytext(T,1,5) == "info")
|
||||||
|
var/input[] = params2list(T)
|
||||||
|
if(input["key"] != config.comms_password)
|
||||||
|
if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50)
|
||||||
|
|
||||||
|
spawn(50)
|
||||||
|
world_topic_spam_protect_time = world.time
|
||||||
|
return "Bad Key (Throttled)"
|
||||||
|
|
||||||
|
world_topic_spam_protect_time = world.time
|
||||||
|
world_topic_spam_protect_ip = addr
|
||||||
|
|
||||||
|
return "Bad Key"
|
||||||
|
|
||||||
|
var/list/search = params2list(input["info"])
|
||||||
|
var/list/ckeysearch = list()
|
||||||
|
for(var/text in search)
|
||||||
|
ckeysearch += ckey(text)
|
||||||
|
|
||||||
|
var/list/match = list()
|
||||||
|
|
||||||
|
for(var/mob/M in mob_list)
|
||||||
|
var/strings = list(M.name, M.ckey)
|
||||||
|
if(M.mind)
|
||||||
|
strings += M.mind.assigned_role
|
||||||
|
strings += M.mind.special_role
|
||||||
|
for(var/text in strings)
|
||||||
|
if(ckey(text) in ckeysearch)
|
||||||
|
match[M] += 10 // an exact match is far better than a partial one
|
||||||
|
else
|
||||||
|
for(var/searchstr in search)
|
||||||
|
if(findtext(text, searchstr))
|
||||||
|
match[M] += 1
|
||||||
|
|
||||||
|
var/maxstrength = 0
|
||||||
|
for(var/mob/M in match)
|
||||||
|
maxstrength = max(match[M], maxstrength)
|
||||||
|
for(var/mob/M in match)
|
||||||
|
if(match[M] < maxstrength)
|
||||||
|
match -= M
|
||||||
|
|
||||||
|
if(!match.len)
|
||||||
|
return "No matches"
|
||||||
|
else if(match.len == 1)
|
||||||
|
var/mob/M = match[1]
|
||||||
|
var/info = list()
|
||||||
|
info["key"] = M.key
|
||||||
|
info["name"] = M.name == M.real_name ? M.name : "[M.name] ([M.real_name])"
|
||||||
|
info["role"] = M.mind ? (M.mind.assigned_role ? M.mind.assigned_role : "No role") : "No mind"
|
||||||
|
var/turf/MT = get_turf(M)
|
||||||
|
info["loc"] = M.loc ? "[M.loc]" : "null"
|
||||||
|
info["turf"] = MT ? "[MT] @ [MT.x], [MT.y], [MT.z]" : "null"
|
||||||
|
info["area"] = MT ? "[MT.loc]" : "null"
|
||||||
|
info["antag"] = M.mind ? (M.mind.special_role ? M.mind.special_role : "Not antag") : "No mind"
|
||||||
|
info["hasbeenrev"] = M.mind ? M.mind.has_been_rev : "No mind"
|
||||||
|
info["stat"] = M.stat
|
||||||
|
info["type"] = M.type
|
||||||
|
if(isliving(M))
|
||||||
|
var/mob/living/L = M
|
||||||
|
info["damage"] = list2params(list(
|
||||||
|
oxy = L.getOxyLoss(),
|
||||||
|
tox = L.getToxLoss(),
|
||||||
|
fire = L.getFireLoss(),
|
||||||
|
brute = L.getBruteLoss(),
|
||||||
|
clone = L.getCloneLoss(),
|
||||||
|
brain = L.getBrainLoss()
|
||||||
|
))
|
||||||
|
else
|
||||||
|
info["damage"] = "non-living"
|
||||||
|
info["gender"] = M.gender
|
||||||
|
return list2params(info)
|
||||||
|
else
|
||||||
|
var/list/ret = list()
|
||||||
|
for(var/mob/M in match)
|
||||||
|
ret[M.key] = M.name
|
||||||
|
return list2params(ret)
|
||||||
|
|
||||||
|
else if(copytext(T,1,9) == "adminmsg")
|
||||||
|
/*
|
||||||
|
We got an adminmsg from IRC bot lets split the input then validate the input.
|
||||||
|
expected output:
|
||||||
|
1. adminmsg = ckey of person the message is to
|
||||||
|
2. msg = contents of message, parems2list requires
|
||||||
|
3. validatationkey = the key the bot has, it should match the gameservers commspassword in it's configuration.
|
||||||
|
4. sender = the ircnick that send the message.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
var/input[] = params2list(T)
|
||||||
|
if(input["key"] != config.comms_password)
|
||||||
|
if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50)
|
||||||
|
|
||||||
|
spawn(50)
|
||||||
|
world_topic_spam_protect_time = world.time
|
||||||
|
return "Bad Key (Throttled)"
|
||||||
|
|
||||||
|
world_topic_spam_protect_time = world.time
|
||||||
|
world_topic_spam_protect_ip = addr
|
||||||
|
|
||||||
|
return "Bad Key"
|
||||||
|
|
||||||
|
var/client/C
|
||||||
|
var/req_ckey = ckey(input["adminmsg"])
|
||||||
|
|
||||||
|
for(var/client/K in GLOB.clients)
|
||||||
|
if(K.ckey == req_ckey)
|
||||||
|
C = K
|
||||||
|
break
|
||||||
|
if(!C)
|
||||||
|
return "No client with that name on server"
|
||||||
|
|
||||||
|
var/rank = input["rank"]
|
||||||
|
if(!rank)
|
||||||
|
rank = "Admin"
|
||||||
|
|
||||||
|
var/message = "<font color='red'>IRC-[rank] PM from <b><a href='?irc_msg=[input["sender"]]'>IRC-[input["sender"]]</a></b>: [input["msg"]]</font>"
|
||||||
|
var/amessage = "<font color='blue'>IRC-[rank] PM from <a href='?irc_msg=[input["sender"]]'>IRC-[input["sender"]]</a> to <b>[key_name(C)]</b> : [input["msg"]]</font>"
|
||||||
|
|
||||||
|
C.received_irc_pm = world.time
|
||||||
|
C.irc_admin = input["sender"]
|
||||||
|
|
||||||
|
C << 'sound/effects/adminhelp.ogg'
|
||||||
|
C << message
|
||||||
|
|
||||||
|
|
||||||
|
for(var/client/A in admins)
|
||||||
|
if(A != C)
|
||||||
|
A << amessage
|
||||||
|
|
||||||
|
return "Message Successful"
|
||||||
|
|
||||||
|
else if(copytext(T,1,6) == "notes")
|
||||||
|
/*
|
||||||
|
We got a request for notes from the IRC Bot
|
||||||
|
expected output:
|
||||||
|
1. notes = ckey of person the notes lookup is for
|
||||||
|
2. validationkey = the key the bot has, it should match the gameservers commspassword in it's configuration.
|
||||||
|
*/
|
||||||
|
var/input[] = params2list(T)
|
||||||
|
if(input["key"] != config.comms_password)
|
||||||
|
if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50)
|
||||||
|
|
||||||
|
spawn(50)
|
||||||
|
world_topic_spam_protect_time = world.time
|
||||||
|
return "Bad Key (Throttled)"
|
||||||
|
|
||||||
|
world_topic_spam_protect_time = world.time
|
||||||
|
world_topic_spam_protect_ip = addr
|
||||||
|
return "Bad Key"
|
||||||
|
|
||||||
|
return show_player_info_irc(ckey(input["notes"]))
|
||||||
|
|
||||||
|
else if(copytext(T,1,4) == "age")
|
||||||
|
var/input[] = params2list(T)
|
||||||
|
if(input["key"] != config.comms_password)
|
||||||
|
if(world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50)
|
||||||
|
spawn(50)
|
||||||
|
world_topic_spam_protect_time = world.time
|
||||||
|
return "Bad Key (Throttled)"
|
||||||
|
|
||||||
|
world_topic_spam_protect_time = world.time
|
||||||
|
world_topic_spam_protect_ip = addr
|
||||||
|
return "Bad Key"
|
||||||
|
|
||||||
|
var/age = get_player_age(input["age"])
|
||||||
|
if(isnum(age))
|
||||||
|
if(age >= 0)
|
||||||
|
return "[age]"
|
||||||
|
else
|
||||||
|
return "Ckey not found"
|
||||||
|
else
|
||||||
|
return "Database connection failed or not set up"
|
||||||
|
|
||||||
|
|
||||||
|
/world/Reboot(reason = 0, fast_track = FALSE)
|
||||||
|
/*spawn(0)
|
||||||
|
world << sound(pick('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg')) // random end sounds!! - LastyBatsy
|
||||||
|
*/
|
||||||
|
if (reason || fast_track) //special reboot, do none of the normal stuff
|
||||||
|
if (usr)
|
||||||
|
log_admin("[key_name(usr)] Has requested an immediate world restart via client side debugging tools")
|
||||||
|
message_admins("[key_name_admin(usr)] Has requested an immediate world restart via client side debugging tools")
|
||||||
|
world << "<span class='boldannounce'>[key_name_admin(usr)] has requested an immediate world restart via client side debugging tools</span>"
|
||||||
|
|
||||||
|
else
|
||||||
|
world << "<span class='boldannounce'>Rebooting world immediately due to host request</span>"
|
||||||
|
else
|
||||||
|
processScheduler.stop()
|
||||||
|
Master.Shutdown() //run SS shutdowns
|
||||||
|
for(var/client/C in GLOB.clients)
|
||||||
|
if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
|
||||||
|
C << link("byond://[config.server]")
|
||||||
|
|
||||||
|
log_world("World rebooted at [time_stamp()]")
|
||||||
|
..()
|
||||||
|
|
||||||
|
/hook/startup/proc/loadMode()
|
||||||
|
world.load_mode()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
/world/proc/load_mode()
|
||||||
|
if(!fexists("data/mode.txt"))
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
var/list/Lines = file2list("data/mode.txt")
|
||||||
|
if(Lines.len)
|
||||||
|
if(Lines[1])
|
||||||
|
master_mode = Lines[1]
|
||||||
|
log_misc("Saved mode is '[master_mode]'")
|
||||||
|
|
||||||
|
/world/proc/save_mode(var/the_mode)
|
||||||
|
var/F = file("data/mode.txt")
|
||||||
|
fdel(F)
|
||||||
|
F << the_mode
|
||||||
|
|
||||||
|
|
||||||
|
/hook/startup/proc/loadMOTD()
|
||||||
|
world.load_motd()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
/world/proc/load_motd()
|
||||||
|
join_motd = file2text("config/motd.txt")
|
||||||
|
|
||||||
|
|
||||||
|
/proc/load_configuration()
|
||||||
|
config = new /datum/configuration()
|
||||||
|
config.load("config/config.txt")
|
||||||
|
config.load("config/game_options.txt","game_options")
|
||||||
|
config.loadsql("config/dbconfig.txt")
|
||||||
|
config.loadforumsql("config/forumdbconfig.txt")
|
||||||
|
|
||||||
|
/hook/startup/proc/loadMods()
|
||||||
|
world.load_mods()
|
||||||
|
world.load_mentors() // no need to write another hook.
|
||||||
|
return 1
|
||||||
|
|
||||||
|
/world/proc/load_mods()
|
||||||
|
if(config.admin_legacy_system)
|
||||||
|
var/text = file2text("config/moderators.txt")
|
||||||
|
if (!text)
|
||||||
|
error("Failed to load config/mods.txt")
|
||||||
|
else
|
||||||
|
var/list/lines = splittext(text, "\n")
|
||||||
|
for(var/line in lines)
|
||||||
|
if (!line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (copytext(line, 1, 2) == ";")
|
||||||
|
continue
|
||||||
|
|
||||||
|
var/title = "Moderator"
|
||||||
|
var/rights = admin_ranks[title]
|
||||||
|
|
||||||
|
var/ckey = copytext(line, 1, length(line)+1)
|
||||||
|
var/datum/admins/D = new /datum/admins(title, rights, ckey)
|
||||||
|
D.associate(GLOB.directory[ckey])
|
||||||
|
|
||||||
|
/world/proc/load_mentors()
|
||||||
|
if(config.admin_legacy_system)
|
||||||
|
var/text = file2text("config/mentors.txt")
|
||||||
|
if (!text)
|
||||||
|
error("Failed to load config/mentors.txt")
|
||||||
|
else
|
||||||
|
var/list/lines = splittext(text, "\n")
|
||||||
|
for(var/line in lines)
|
||||||
|
if (!line)
|
||||||
|
continue
|
||||||
|
if (copytext(line, 1, 2) == ";")
|
||||||
|
continue
|
||||||
|
|
||||||
|
var/title = "Mentor"
|
||||||
|
var/rights = admin_ranks[title]
|
||||||
|
|
||||||
|
var/ckey = copytext(line, 1, length(line)+1)
|
||||||
|
var/datum/admins/D = new /datum/admins(title, rights, ckey)
|
||||||
|
D.associate(GLOB.directory[ckey])
|
||||||
|
|
||||||
|
/world/proc/update_status()
|
||||||
|
var/s = ""
|
||||||
|
|
||||||
|
if (config && config.server_name)
|
||||||
|
s += "<b>[config.server_name]</b> — "
|
||||||
|
|
||||||
|
s += "<b>[station_name()]</b>";
|
||||||
|
s += " ("
|
||||||
|
s += "<a href=\"http://\">" //Change this to wherever you want the hub to link to.
|
||||||
|
// s += "[game_version]"
|
||||||
|
s += "Default" //Replace this with something else. Or ever better, delete it and uncomment the game version.
|
||||||
|
s += "</a>"
|
||||||
|
s += ")"
|
||||||
|
|
||||||
|
var/list/features = list()
|
||||||
|
|
||||||
|
if(ticker)
|
||||||
|
if(master_mode)
|
||||||
|
features += master_mode
|
||||||
|
else
|
||||||
|
features += "<b>STARTING</b>"
|
||||||
|
|
||||||
|
if (!config.enter_allowed)
|
||||||
|
features += "closed"
|
||||||
|
|
||||||
|
features += config.abandon_allowed ? "respawn" : "no respawn"
|
||||||
|
|
||||||
|
if (config && config.allow_vote_mode)
|
||||||
|
features += "vote"
|
||||||
|
|
||||||
|
if (config && config.allow_ai)
|
||||||
|
features += "AI allowed"
|
||||||
|
|
||||||
|
var/n = 0
|
||||||
|
for (var/mob/M in player_list)
|
||||||
|
if (M.client)
|
||||||
|
n++
|
||||||
|
|
||||||
|
if (n > 1)
|
||||||
|
features += "~[n] players"
|
||||||
|
else if (n > 0)
|
||||||
|
features += "~[n] player"
|
||||||
|
|
||||||
|
|
||||||
|
if (config && config.hostedby)
|
||||||
|
features += "hosted by <b>[config.hostedby]</b>"
|
||||||
|
|
||||||
|
if (features)
|
||||||
|
s += ": [jointext(features, ", ")]"
|
||||||
|
|
||||||
|
/* does this help? I do not know */
|
||||||
|
if (src.status != s)
|
||||||
|
src.status = s
|
||||||
|
|
||||||
|
#define FAILED_DB_CONNECTION_CUTOFF 5
|
||||||
|
var/failed_db_connections = 0
|
||||||
|
var/failed_old_db_connections = 0
|
||||||
|
|
||||||
|
/hook/startup/proc/connectDB()
|
||||||
|
if(!config.sql_enabled)
|
||||||
|
world.log << "SQL connection disabled in config."
|
||||||
|
else if(!setup_database_connection())
|
||||||
|
world.log << "Your server failed to establish a connection with the feedback database."
|
||||||
|
else
|
||||||
|
world.log << "Feedback database connection established."
|
||||||
|
return 1
|
||||||
|
|
||||||
|
proc/setup_database_connection()
|
||||||
|
|
||||||
|
if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore.
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if(!dbcon)
|
||||||
|
dbcon = new()
|
||||||
|
|
||||||
|
var/user = sqlfdbklogin
|
||||||
|
var/pass = sqlfdbkpass
|
||||||
|
var/db = sqlfdbkdb
|
||||||
|
var/address = sqladdress
|
||||||
|
var/port = sqlport
|
||||||
|
|
||||||
|
dbcon.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]")
|
||||||
|
. = dbcon.IsConnected()
|
||||||
|
if ( . )
|
||||||
|
failed_db_connections = 0 //If this connection succeeded, reset the failed connections counter.
|
||||||
|
else
|
||||||
|
failed_db_connections++ //If it failed, increase the failed connections counter.
|
||||||
|
world.log << dbcon.ErrorMsg()
|
||||||
|
|
||||||
|
return .
|
||||||
|
|
||||||
|
//This proc ensures that the connection to the feedback database (global variable dbcon) is established
|
||||||
|
proc/establish_db_connection()
|
||||||
|
if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if(!dbcon || !dbcon.IsConnected())
|
||||||
|
return setup_database_connection()
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
/hook/startup/proc/connectOldDB()
|
||||||
|
if(!config.sql_enabled)
|
||||||
|
world.log << "SQL connection disabled in config."
|
||||||
|
else if(!setup_old_database_connection())
|
||||||
|
world.log << "Your server failed to establish a connection with the SQL database."
|
||||||
|
else
|
||||||
|
world.log << "SQL database connection established."
|
||||||
|
return 1
|
||||||
|
|
||||||
|
//These two procs are for the old database, while it's being phased out. See the tgstation.sql file in the SQL folder for more information.
|
||||||
|
proc/setup_old_database_connection()
|
||||||
|
|
||||||
|
if(failed_old_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore.
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if(!dbcon_old)
|
||||||
|
dbcon_old = new()
|
||||||
|
|
||||||
|
var/user = sqllogin
|
||||||
|
var/pass = sqlpass
|
||||||
|
var/db = sqldb
|
||||||
|
var/address = sqladdress
|
||||||
|
var/port = sqlport
|
||||||
|
|
||||||
|
dbcon_old.Connect("dbi:mysql:[db]:[address]:[port]","[user]","[pass]")
|
||||||
|
. = dbcon_old.IsConnected()
|
||||||
|
if ( . )
|
||||||
|
failed_old_db_connections = 0 //If this connection succeeded, reset the failed connections counter.
|
||||||
|
else
|
||||||
|
failed_old_db_connections++ //If it failed, increase the failed connections counter.
|
||||||
|
world.log << dbcon.ErrorMsg()
|
||||||
|
|
||||||
|
return .
|
||||||
|
|
||||||
|
//This proc ensures that the connection to the feedback database (global variable dbcon) is established
|
||||||
|
proc/establish_old_db_connection()
|
||||||
|
if(failed_old_db_connections > FAILED_DB_CONNECTION_CUTOFF)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if(!dbcon_old || !dbcon_old.IsConnected())
|
||||||
|
return setup_old_database_connection()
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
|
||||||
|
// Things to do when a new z-level was just made.
|
||||||
|
/world/proc/max_z_changed()
|
||||||
|
if(!islist(GLOB.players_by_zlevel))
|
||||||
|
GLOB.players_by_zlevel = new /list(world.maxz, 0)
|
||||||
|
while(GLOB.players_by_zlevel.len < world.maxz)
|
||||||
|
GLOB.players_by_zlevel.len++
|
||||||
|
GLOB.players_by_zlevel[GLOB.players_by_zlevel.len] = list()
|
||||||
|
|
||||||
|
// Call this to make a new blank z-level, don't modify maxz directly.
|
||||||
|
/world/proc/increment_max_z()
|
||||||
|
maxz++
|
||||||
|
max_z_changed()
|
||||||
|
|
||||||
|
#undef FAILED_DB_CONNECTION_CUTOFF
|
||||||
27
code/global_init.dm
Normal file
27
code/global_init.dm
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
The initialization of the game happens roughly like this:
|
||||||
|
|
||||||
|
1. All global variables are initialized (including the global_init instance).
|
||||||
|
2. The map is initialized, and map objects are created.
|
||||||
|
3. world/New() runs, creating the process scheduler (and the old master controller) and spawning their setup.
|
||||||
|
4. processScheduler/setup() runs, creating all the processes. game_controller/setup() runs, calling initialize() on all movable atoms in the world.
|
||||||
|
5. The gameticker is created.
|
||||||
|
|
||||||
|
*/
|
||||||
|
var/global/datum/global_init/init = new ()
|
||||||
|
|
||||||
|
/*
|
||||||
|
Pre-map initialization stuff should go here.
|
||||||
|
*/
|
||||||
|
/datum/global_init/New()
|
||||||
|
|
||||||
|
makeDatumRefLists()
|
||||||
|
load_configuration()
|
||||||
|
|
||||||
|
initialize_integrated_circuits_list()
|
||||||
|
|
||||||
|
qdel(src) //we're done
|
||||||
|
|
||||||
|
/datum/global_init/Destroy()
|
||||||
|
global.init = null
|
||||||
|
return 2 // QDEL_HINT_IWILLGC
|
||||||
@@ -432,7 +432,7 @@
|
|||||||
P.pass_flags = initial(copy_projectile.pass_flags)
|
P.pass_flags = initial(copy_projectile.pass_flags)
|
||||||
P.fire_sound = initial(copy_projectile.fire_sound)
|
P.fire_sound = initial(copy_projectile.fire_sound)
|
||||||
P.hitscan = initial(copy_projectile.hitscan)
|
P.hitscan = initial(copy_projectile.hitscan)
|
||||||
P.step_delay = initial(copy_projectile.step_delay)
|
P.speed = initial(copy_projectile.speed)
|
||||||
P.muzzle_type = initial(copy_projectile.muzzle_type)
|
P.muzzle_type = initial(copy_projectile.muzzle_type)
|
||||||
P.tracer_type = initial(copy_projectile.tracer_type)
|
P.tracer_type = initial(copy_projectile.tracer_type)
|
||||||
P.impact_type = initial(copy_projectile.impact_type)
|
P.impact_type = initial(copy_projectile.impact_type)
|
||||||
|
|||||||
@@ -68,8 +68,9 @@
|
|||||||
playsound(loc, emagged ? 'sound/weapons/Laser.ogg' : 'sound/weapons/Taser.ogg', 50, 1)
|
playsound(loc, emagged ? 'sound/weapons/Laser.ogg' : 'sound/weapons/Taser.ogg', 50, 1)
|
||||||
var/obj/item/projectile/P = new projectile(loc)
|
var/obj/item/projectile/P = new projectile(loc)
|
||||||
|
|
||||||
P.launch(A)
|
P.firer = src
|
||||||
return
|
P.old_style_target(A)
|
||||||
|
P.fire()
|
||||||
|
|
||||||
// Assembly
|
// Assembly
|
||||||
|
|
||||||
|
|||||||
@@ -348,12 +348,12 @@
|
|||||||
if(alert(src,"You sure you want to sleep for a while?","Sleep","Yes","No") == "Yes")
|
if(alert(src,"You sure you want to sleep for a while?","Sleep","Yes","No") == "Yes")
|
||||||
usr.sleeping = 20 //Short nap
|
usr.sleeping = 20 //Short nap
|
||||||
|
|
||||||
/mob/living/carbon/Bump(var/atom/movable/AM, yes)
|
/mob/living/carbon/Bump(atom/A)
|
||||||
if(now_pushing || !yes)
|
if(now_pushing)
|
||||||
return
|
return
|
||||||
..()
|
..()
|
||||||
if(istype(AM, /mob/living/carbon) && prob(10))
|
if(istype(A, /mob/living/carbon) && prob(10))
|
||||||
src.spread_disease_to(AM, "Contact")
|
spread_disease_to(A, "Contact")
|
||||||
|
|
||||||
/mob/living/carbon/cannot_use_vents()
|
/mob/living/carbon/cannot_use_vents()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -142,7 +142,8 @@
|
|||||||
visible_message("<span class='warning'>[src] spits [spit_name] at \the [A]!</span>", "<span class='alium'>You spit [spit_name] at \the [A].</span>")
|
visible_message("<span class='warning'>[src] spits [spit_name] at \the [A]!</span>", "<span class='alium'>You spit [spit_name] at \the [A].</span>")
|
||||||
var/obj/item/projectile/P = new spit_projectile(get_turf(src))
|
var/obj/item/projectile/P = new spit_projectile(get_turf(src))
|
||||||
P.firer = src
|
P.firer = src
|
||||||
P.launch(A)
|
P.old_style_target(A)
|
||||||
|
P.fire()
|
||||||
playsound(loc, 'sound/weapons/pierce.ogg', 25, 0)
|
playsound(loc, 'sound/weapons/pierce.ogg', 25, 0)
|
||||||
else
|
else
|
||||||
..()
|
..()
|
||||||
|
|||||||
@@ -80,49 +80,23 @@ default behaviour is:
|
|||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
/mob/living/Bump(atom/movable/AM, yes)
|
/mob/living/Bump(atom/movable/AM)
|
||||||
spawn(0)
|
if(now_pushing || !loc)
|
||||||
if ((!( yes ) || now_pushing) || !loc)
|
return
|
||||||
return
|
now_pushing = 1
|
||||||
now_pushing = 1
|
if (istype(AM, /mob/living))
|
||||||
if (istype(AM, /mob/living))
|
var/mob/living/tmob = AM
|
||||||
var/mob/living/tmob = AM
|
|
||||||
|
|
||||||
//Even if we don't push/swap places, we "touched" them, so spread fire
|
//Even if we don't push/swap places, we "touched" them, so spread fire
|
||||||
spread_fire(tmob)
|
spread_fire(tmob)
|
||||||
|
|
||||||
for(var/mob/living/M in range(tmob, 1))
|
for(var/mob/living/M in range(tmob, 1))
|
||||||
if(tmob.pinned.len || ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) )
|
if(tmob.pinned.len || ((M.pulling == tmob && ( tmob.restrained() && !( M.restrained() ) && M.stat == 0)) || locate(/obj/item/weapon/grab, tmob.grabbed_by.len)) )
|
||||||
if ( !(world.time % 5) )
|
if ( !(world.time % 5) )
|
||||||
to_chat(src, "<span class='warning'>[tmob] is restrained, you cannot push past</span>")
|
to_chat(src, "<span class='warning'>[tmob] is restrained, you cannot push past</span>")
|
||||||
now_pushing = 0
|
|
||||||
return
|
|
||||||
if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) )
|
|
||||||
if ( !(world.time % 5) )
|
|
||||||
to_chat(src, "<span class='warning'>[tmob] is restraining [M], you cannot push past</span>")
|
|
||||||
now_pushing = 0
|
|
||||||
return
|
|
||||||
|
|
||||||
//BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
|
|
||||||
var/dense = 0
|
|
||||||
if(loc.density)
|
|
||||||
dense = 1
|
|
||||||
for(var/atom/movable/A in loc)
|
|
||||||
if(A == src)
|
|
||||||
continue
|
|
||||||
if(A.density)
|
|
||||||
if(A.flags&ON_BORDER)
|
|
||||||
dense = !A.CanPass(src, src.loc)
|
|
||||||
else
|
|
||||||
dense = 1
|
|
||||||
if(dense) break
|
|
||||||
|
|
||||||
//Leaping mobs just land on the tile, no pushing, no anything.
|
|
||||||
if(status_flags & LEAPING)
|
|
||||||
loc = tmob.loc
|
|
||||||
status_flags &= ~LEAPING
|
|
||||||
now_pushing = 0
|
now_pushing = 0
|
||||||
return
|
return
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !tmob.buckled && !buckled && !dense && can_move_mob(tmob, 1, 0)) // mutual brohugs all around!
|
if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !tmob.buckled && !buckled && !dense && can_move_mob(tmob, 1, 0)) // mutual brohugs all around!
|
||||||
var/turf/oldloc = loc
|
var/turf/oldloc = loc
|
||||||
@@ -145,15 +119,58 @@ default behaviour is:
|
|||||||
// VOREStation Edit - End
|
// VOREStation Edit - End
|
||||||
|
|
||||||
tmob.forceMove(oldloc)
|
tmob.forceMove(oldloc)
|
||||||
|
=======
|
||||||
|
if( tmob.pulling == M && ( M.restrained() && !( tmob.restrained() ) && tmob.stat == 0) )
|
||||||
|
if ( !(world.time % 5) )
|
||||||
|
to_chat(src, "<span class='warning'>[tmob] is restraining [M], you cannot push past</span>")
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
now_pushing = 0
|
now_pushing = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
if(!can_move_mob(tmob, 0, 0))
|
//BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
|
||||||
|
var/dense = 0
|
||||||
|
if(loc.density)
|
||||||
|
dense = 1
|
||||||
|
for(var/atom/movable/A in loc)
|
||||||
|
if(A == src)
|
||||||
|
continue
|
||||||
|
if(A.density)
|
||||||
|
if(A.flags&ON_BORDER)
|
||||||
|
dense = !A.CanPass(src, src.loc)
|
||||||
|
else
|
||||||
|
dense = 1
|
||||||
|
if(dense) break
|
||||||
|
|
||||||
|
//Leaping mobs just land on the tile, no pushing, no anything.
|
||||||
|
if(status_flags & LEAPING)
|
||||||
|
loc = tmob.loc
|
||||||
|
status_flags &= ~LEAPING
|
||||||
|
now_pushing = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !tmob.buckled && !buckled && !dense && can_move_mob(tmob, 1, 0)) // mutual brohugs all around!
|
||||||
|
var/turf/oldloc = loc
|
||||||
|
forceMove(tmob.loc)
|
||||||
|
tmob.forceMove(oldloc)
|
||||||
|
now_pushing = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
if(!can_move_mob(tmob, 0, 0))
|
||||||
|
now_pushing = 0
|
||||||
|
return
|
||||||
|
if(a_intent == I_HELP || src.restrained())
|
||||||
|
now_pushing = 0
|
||||||
|
return
|
||||||
|
if(istype(tmob, /mob/living/carbon/human) && (FAT in tmob.mutations))
|
||||||
|
if(prob(40) && !(FAT in src.mutations))
|
||||||
|
to_chat(src, "<span class='danger'>You fail to push [tmob]'s fat ass out of the way.</span>")
|
||||||
now_pushing = 0
|
now_pushing = 0
|
||||||
return
|
return
|
||||||
if(a_intent == I_HELP || src.restrained())
|
if(tmob.r_hand && istype(tmob.r_hand, /obj/item/weapon/shield/riot))
|
||||||
|
if(prob(99))
|
||||||
now_pushing = 0
|
now_pushing = 0
|
||||||
return
|
return
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
// VOREStation Edit - Begin
|
// VOREStation Edit - Begin
|
||||||
// Plow that nerd.
|
// Plow that nerd.
|
||||||
@@ -182,11 +199,19 @@ default behaviour is:
|
|||||||
now_pushing = 0
|
now_pushing = 0
|
||||||
return
|
return
|
||||||
if(!(tmob.status_flags & CANPUSH))
|
if(!(tmob.status_flags & CANPUSH))
|
||||||
|
=======
|
||||||
|
if(tmob.l_hand && istype(tmob.l_hand, /obj/item/weapon/shield/riot))
|
||||||
|
if(prob(99))
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
now_pushing = 0
|
now_pushing = 0
|
||||||
return
|
return
|
||||||
|
if(!(tmob.status_flags & CANPUSH))
|
||||||
|
now_pushing = 0
|
||||||
|
return
|
||||||
|
|
||||||
tmob.LAssailant = src
|
tmob.LAssailant = src
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
now_pushing = 0
|
now_pushing = 0
|
||||||
spawn(0)
|
spawn(0)
|
||||||
..()
|
..()
|
||||||
@@ -203,27 +228,36 @@ default behaviour is:
|
|||||||
src << ("<span class='warning'>You just [pick("ran", "slammed")] into \the [AM]!</span>")
|
src << ("<span class='warning'>You just [pick("ran", "slammed")] into \the [AM]!</span>")
|
||||||
to_chat(src, "<span class='warning'>You just [pick("ran", "slammed")] into \the [AM]!</span>")
|
to_chat(src, "<span class='warning'>You just [pick("ran", "slammed")] into \the [AM]!</span>")
|
||||||
*/ // VOREStation Removal End
|
*/ // VOREStation Removal End
|
||||||
|
=======
|
||||||
|
now_pushing = 0
|
||||||
|
. = ..()
|
||||||
|
if (!istype(AM, /atom/movable) || AM.anchored)
|
||||||
|
if(confused && prob(50) && m_intent=="run")
|
||||||
|
Weaken(2)
|
||||||
|
playsound(loc, "punch", 25, 1, -1)
|
||||||
|
visible_message("<span class='warning'>[src] [pick("ran", "slammed")] into \the [AM]!</span>")
|
||||||
|
src.apply_damage(5, BRUTE)
|
||||||
|
to_chat(src, "<span class='warning'>You just [pick("ran", "slammed")] into \the [AM]!</span>")
|
||||||
|
return
|
||||||
|
if (!now_pushing)
|
||||||
|
if(isobj(AM))
|
||||||
|
var/obj/I = AM
|
||||||
|
if(!can_pull_size || can_pull_size < I.w_class)
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
return
|
return
|
||||||
if (!now_pushing)
|
now_pushing = 1
|
||||||
if(isobj(AM))
|
|
||||||
var/obj/I = AM
|
|
||||||
if(!can_pull_size || can_pull_size < I.w_class)
|
|
||||||
return
|
|
||||||
now_pushing = 1
|
|
||||||
|
|
||||||
var/t = get_dir(src, AM)
|
var/t = get_dir(src, AM)
|
||||||
if (istype(AM, /obj/structure/window))
|
if (istype(AM, /obj/structure/window))
|
||||||
for(var/obj/structure/window/win in get_step(AM,t))
|
for(var/obj/structure/window/win in get_step(AM,t))
|
||||||
now_pushing = 0
|
|
||||||
return
|
|
||||||
step(AM, t)
|
|
||||||
if(ishuman(AM) && AM:grabbed_by)
|
|
||||||
for(var/obj/item/weapon/grab/G in AM:grabbed_by)
|
|
||||||
step(G:assailant, get_dir(G:assailant, AM))
|
|
||||||
G.adjust_position()
|
|
||||||
now_pushing = 0
|
now_pushing = 0
|
||||||
return
|
return
|
||||||
return
|
step(AM, t)
|
||||||
|
if(ishuman(AM) && AM:grabbed_by)
|
||||||
|
for(var/obj/item/weapon/grab/G in AM:grabbed_by)
|
||||||
|
step(G:assailant, get_dir(G:assailant, AM))
|
||||||
|
G.adjust_position()
|
||||||
|
now_pushing = 0
|
||||||
|
|
||||||
/mob/living/CanPass(atom/movable/mover, turf/target)
|
/mob/living/CanPass(atom/movable/mover, turf/target)
|
||||||
if(istype(mover, /obj/structure/blob) && faction == "blob") //Blobs should ignore things on their faction.
|
if(istype(mover, /obj/structure/blob) && faction == "blob") //Blobs should ignore things on their faction.
|
||||||
|
|||||||
@@ -1383,17 +1383,15 @@
|
|||||||
if(target == start)
|
if(target == start)
|
||||||
return
|
return
|
||||||
|
|
||||||
var/obj/item/projectile/A = new projectiletype(user:loc)
|
var/obj/item/projectile/A = new projectiletype(user.loc)
|
||||||
playsound(user, projectilesound, 100, 1)
|
playsound(user, projectilesound, 100, 1)
|
||||||
if(!A) return
|
if(!A) return
|
||||||
|
|
||||||
// if (!istype(target, /turf))
|
// if (!istype(target, /turf))
|
||||||
// qdel(A)
|
// qdel(A)
|
||||||
// return
|
// return
|
||||||
|
A.old_style_target(target)
|
||||||
A.firer = src
|
A.fire()
|
||||||
A.launch(target)
|
|
||||||
return
|
|
||||||
|
|
||||||
//We can't see the target
|
//We can't see the target
|
||||||
/mob/living/simple_mob/proc/LoseTarget()
|
/mob/living/simple_mob/proc/LoseTarget()
|
||||||
|
|||||||
@@ -128,7 +128,8 @@
|
|||||||
playsound(src, P.fire_sound ? P.fire_sound : projectilesound, 80, 1)
|
playsound(src, P.fire_sound ? P.fire_sound : projectilesound, 80, 1)
|
||||||
|
|
||||||
P.firer = src // So we can't shoot ourselves.
|
P.firer = src // So we can't shoot ourselves.
|
||||||
P.launch(A)
|
P.old_style_target(A, src)
|
||||||
|
P.fire()
|
||||||
if(needs_reload)
|
if(needs_reload)
|
||||||
reload_count++
|
reload_count++
|
||||||
|
|
||||||
|
|||||||
@@ -33,5 +33,6 @@
|
|||||||
playsound(src, 'sound/weapons/thudswoosh.ogg', 100, 1)
|
playsound(src, 'sound/weapons/thudswoosh.ogg', 100, 1)
|
||||||
if(!B)
|
if(!B)
|
||||||
return
|
return
|
||||||
B.launch(A)
|
B.old_style_target(A, src)
|
||||||
|
B.fire()
|
||||||
set_AI_busy(FALSE)
|
set_AI_busy(FALSE)
|
||||||
@@ -1,261 +1,263 @@
|
|||||||
// Stronger than a regular Dark Gygax, this one has three special attacks, based on intents.
|
// Stronger than a regular Dark Gygax, this one has three special attacks, based on intents.
|
||||||
// First special attack launches three arcing rockets at the current target.
|
// First special attack launches three arcing rockets at the current target.
|
||||||
// Second special attack fires a projectile that creates a short-lived microsingularity that pulls in everything nearby. Magboots can protect from this.
|
// Second special attack fires a projectile that creates a short-lived microsingularity that pulls in everything nearby. Magboots can protect from this.
|
||||||
// Third special attack creates a dangerous electric field that causes escalating electric damage, before emitting a tesla shock and blinding anyone looking at the mecha.
|
// Third special attack creates a dangerous electric field that causes escalating electric damage, before emitting a tesla shock and blinding anyone looking at the mecha.
|
||||||
// The AI will choose one every ten seconds.
|
// The AI will choose one every ten seconds.
|
||||||
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced
|
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced
|
||||||
name = "advanced dark gygax"
|
name = "advanced dark gygax"
|
||||||
desc = "An experimental exosuit that utilizes advanced materials to allow for greater protection while still being lightweight and fast. \
|
desc = "An experimental exosuit that utilizes advanced materials to allow for greater protection while still being lightweight and fast. \
|
||||||
It also is armed with an array of next-generation weaponry."
|
It also is armed with an array of next-generation weaponry."
|
||||||
icon_state = "darkgygax_adv"
|
icon_state = "darkgygax_adv"
|
||||||
wreckage = /obj/structure/loot_pile/mecha/gygax/dark/adv
|
wreckage = /obj/structure/loot_pile/mecha/gygax/dark/adv
|
||||||
icon_scale = 1.5
|
icon_scale = 1.5
|
||||||
movement_shake_radius = 14
|
movement_shake_radius = 14
|
||||||
|
|
||||||
maxHealth = 450
|
maxHealth = 450
|
||||||
deflect_chance = 25
|
deflect_chance = 25
|
||||||
has_repair_droid = TRUE
|
has_repair_droid = TRUE
|
||||||
armor = list(
|
armor = list(
|
||||||
"melee" = 50,
|
"melee" = 50,
|
||||||
"bullet" = 50,
|
"bullet" = 50,
|
||||||
"laser" = 50,
|
"laser" = 50,
|
||||||
"energy" = 30,
|
"energy" = 30,
|
||||||
"bomb" = 30,
|
"bomb" = 30,
|
||||||
"bio" = 100,
|
"bio" = 100,
|
||||||
"rad" = 100
|
"rad" = 100
|
||||||
)
|
)
|
||||||
|
|
||||||
special_attack_min_range = 1
|
special_attack_min_range = 1
|
||||||
special_attack_max_range = 7
|
special_attack_max_range = 7
|
||||||
special_attack_cooldown = 10 SECONDS
|
special_attack_cooldown = 10 SECONDS
|
||||||
projectiletype = /obj/item/projectile/force_missile
|
projectiletype = /obj/item/projectile/force_missile
|
||||||
projectilesound = 'sound/weapons/wave.ogg'
|
projectilesound = 'sound/weapons/wave.ogg'
|
||||||
var/obj/effect/overlay/energy_ball/energy_ball = null
|
var/obj/effect/overlay/energy_ball/energy_ball = null
|
||||||
|
|
||||||
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/Destroy()
|
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/Destroy()
|
||||||
if(energy_ball)
|
if(energy_ball)
|
||||||
energy_ball.stop_orbit()
|
energy_ball.stop_orbit()
|
||||||
qdel(energy_ball)
|
qdel(energy_ball)
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/do_special_attack(atom/A)
|
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/do_special_attack(atom/A)
|
||||||
. = TRUE // So we don't fire a laser as well.
|
. = TRUE // So we don't fire a laser as well.
|
||||||
switch(a_intent)
|
switch(a_intent)
|
||||||
if(I_DISARM) // Side gun
|
if(I_DISARM) // Side gun
|
||||||
electric_defense(A)
|
electric_defense(A)
|
||||||
if(I_HURT) // Rockets
|
if(I_HURT) // Rockets
|
||||||
launch_rockets(A)
|
launch_rockets(A)
|
||||||
if(I_GRAB) // Micro-singulo
|
if(I_GRAB) // Micro-singulo
|
||||||
launch_microsingularity(A)
|
launch_microsingularity(A)
|
||||||
|
|
||||||
#define ELECTRIC_ZAP_POWER 20000
|
#define ELECTRIC_ZAP_POWER 20000
|
||||||
|
|
||||||
// Charges a tesla shot, while emitting a dangerous electric field. The exosuit is immune to electric damage while this is ongoing.
|
// Charges a tesla shot, while emitting a dangerous electric field. The exosuit is immune to electric damage while this is ongoing.
|
||||||
// It also briefly blinds anyone looking directly at the mech without flash protection.
|
// It also briefly blinds anyone looking directly at the mech without flash protection.
|
||||||
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/proc/electric_defense(atom/target)
|
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/proc/electric_defense(atom/target)
|
||||||
set waitfor = FALSE
|
set waitfor = FALSE
|
||||||
|
|
||||||
// Temporary immunity to shock to avoid killing themselves with their own attack.
|
// Temporary immunity to shock to avoid killing themselves with their own attack.
|
||||||
var/old_shock_resist = shock_resist
|
var/old_shock_resist = shock_resist
|
||||||
shock_resist = 1
|
shock_resist = 1
|
||||||
|
|
||||||
// Make the energy ball. This is purely visual since the tesla ball is hyper-deadly.
|
// Make the energy ball. This is purely visual since the tesla ball is hyper-deadly.
|
||||||
energy_ball = new(loc)
|
energy_ball = new(loc)
|
||||||
energy_ball.adjust_scale(0.5)
|
energy_ball.adjust_scale(0.5)
|
||||||
energy_ball.orbit(src, 32, TRUE, 1 SECOND)
|
energy_ball.orbit(src, 32, TRUE, 1 SECOND)
|
||||||
|
|
||||||
visible_message(span("warning", "\The [src] creates \an [energy_ball] around itself!"))
|
visible_message(span("warning", "\The [src] creates \an [energy_ball] around itself!"))
|
||||||
|
|
||||||
playsound(src.loc, 'sound/effects/lightning_chargeup.ogg', 100, 1, extrarange = 30)
|
playsound(src.loc, 'sound/effects/lightning_chargeup.ogg', 100, 1, extrarange = 30)
|
||||||
|
|
||||||
// Shock nearby things that aren't ourselves.
|
// Shock nearby things that aren't ourselves.
|
||||||
for(var/i = 1 to 10)
|
for(var/i = 1 to 10)
|
||||||
energy_ball.adjust_scale(0.5 + (i/10))
|
energy_ball.adjust_scale(0.5 + (i/10))
|
||||||
energy_ball.set_light(i/2, i/2, "#0000FF")
|
energy_ball.set_light(i/2, i/2, "#0000FF")
|
||||||
for(var/thing in range(3, src))
|
for(var/thing in range(3, src))
|
||||||
// This is stupid because mechs are stupid and not mobs.
|
// This is stupid because mechs are stupid and not mobs.
|
||||||
if(isliving(thing))
|
if(isliving(thing))
|
||||||
var/mob/living/L = thing
|
var/mob/living/L = thing
|
||||||
|
|
||||||
if(L == src)
|
if(L == src)
|
||||||
continue
|
continue
|
||||||
if(L.stat)
|
if(L.stat)
|
||||||
continue // Otherwise it can get pretty laggy if there's loads of corpses around.
|
continue // Otherwise it can get pretty laggy if there's loads of corpses around.
|
||||||
L.inflict_shock_damage(i * 2)
|
L.inflict_shock_damage(i * 2)
|
||||||
if(L && L.has_AI()) // Some mobs delete themselves when dying.
|
if(L && L.has_AI()) // Some mobs delete themselves when dying.
|
||||||
L.ai_holder.react_to_attack(src)
|
L.ai_holder.react_to_attack(src)
|
||||||
|
|
||||||
else if(istype(thing, /obj/mecha))
|
else if(istype(thing, /obj/mecha))
|
||||||
var/obj/mecha/M = thing
|
var/obj/mecha/M = thing
|
||||||
M.take_damage(i * 2, "energy") // Mechs don't have a concept for siemens so energy armor check is the best alternative.
|
M.take_damage(i * 2, "energy") // Mechs don't have a concept for siemens so energy armor check is the best alternative.
|
||||||
|
|
||||||
sleep(1 SECOND)
|
sleep(1 SECOND)
|
||||||
|
|
||||||
// Shoot a tesla bolt, and flashes people who are looking at the mecha without sufficent eye protection.
|
// Shoot a tesla bolt, and flashes people who are looking at the mecha without sufficent eye protection.
|
||||||
visible_message(span("warning", "\The [energy_ball] explodes in a flash of light, sending a shock everywhere!"))
|
visible_message(span("warning", "\The [energy_ball] explodes in a flash of light, sending a shock everywhere!"))
|
||||||
playsound(src.loc, 'sound/effects/lightningbolt.ogg', 100, 1, extrarange = 30)
|
playsound(src.loc, 'sound/effects/lightningbolt.ogg', 100, 1, extrarange = 30)
|
||||||
tesla_zap(src.loc, 5, ELECTRIC_ZAP_POWER, FALSE)
|
tesla_zap(src.loc, 5, ELECTRIC_ZAP_POWER, FALSE)
|
||||||
for(var/mob/living/L in viewers(src))
|
for(var/mob/living/L in viewers(src))
|
||||||
if(L == src)
|
if(L == src)
|
||||||
continue
|
continue
|
||||||
var/dir_towards_us = get_dir(L, src)
|
var/dir_towards_us = get_dir(L, src)
|
||||||
if(L.dir && L.dir & dir_towards_us)
|
if(L.dir && L.dir & dir_towards_us)
|
||||||
to_chat(L, span("danger", "The flash of light blinds you briefly."))
|
to_chat(L, span("danger", "The flash of light blinds you briefly."))
|
||||||
L.flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = TRUE)
|
L.flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = TRUE)
|
||||||
|
|
||||||
// Get rid of our energy ball.
|
// Get rid of our energy ball.
|
||||||
energy_ball.stop_orbit()
|
energy_ball.stop_orbit()
|
||||||
qdel(energy_ball)
|
qdel(energy_ball)
|
||||||
|
|
||||||
sleep(1 SECOND)
|
sleep(1 SECOND)
|
||||||
// Resist resistance to old value.
|
// Resist resistance to old value.
|
||||||
shock_resist = old_shock_resist // Not using initial() in case the value gets modified by an admin or something.
|
shock_resist = old_shock_resist // Not using initial() in case the value gets modified by an admin or something.
|
||||||
|
|
||||||
#undef ELECTRIC_ZAP_POWER
|
#undef ELECTRIC_ZAP_POWER
|
||||||
|
|
||||||
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/proc/launch_rockets(atom/target)
|
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/proc/launch_rockets(atom/target)
|
||||||
set waitfor = FALSE
|
set waitfor = FALSE
|
||||||
|
|
||||||
// Telegraph our next move.
|
// Telegraph our next move.
|
||||||
Beam(target, icon_state = "sat_beam", time = 3.5 SECONDS, maxdistance = INFINITY)
|
Beam(target, icon_state = "sat_beam", time = 3.5 SECONDS, maxdistance = INFINITY)
|
||||||
visible_message(span("warning", "\The [src] deploys a missile rack!"))
|
visible_message(span("warning", "\The [src] deploys a missile rack!"))
|
||||||
playsound(src, 'sound/effects/turret/move1.wav', 50, 1)
|
playsound(src, 'sound/effects/turret/move1.wav', 50, 1)
|
||||||
sleep(0.5 SECONDS)
|
sleep(0.5 SECONDS)
|
||||||
|
|
||||||
for(var/i = 1 to 3)
|
for(var/i = 1 to 3)
|
||||||
if(target) // Might get deleted in the meantime.
|
if(target) // Might get deleted in the meantime.
|
||||||
var/turf/T = get_turf(target)
|
var/turf/T = get_turf(target)
|
||||||
if(T)
|
if(T)
|
||||||
visible_message(span("warning", "\The [src] fires a rocket into the air!"))
|
visible_message(span("warning", "\The [src] fires a rocket into the air!"))
|
||||||
playsound(src, 'sound/weapons/rpg.ogg', 70, 1)
|
playsound(src, 'sound/weapons/rpg.ogg', 70, 1)
|
||||||
face_atom(T)
|
face_atom(T)
|
||||||
var/obj/item/projectile/arc/explosive_rocket/rocket = new(loc)
|
var/obj/item/projectile/arc/explosive_rocket/rocket = new(loc)
|
||||||
rocket.launch(T)
|
rocket.old_style_target(T, src)
|
||||||
sleep(1 SECOND)
|
rocket.fire()
|
||||||
|
sleep(1 SECOND)
|
||||||
visible_message(span("warning", "\The [src] retracts the missile rack."))
|
|
||||||
playsound(src, 'sound/effects/turret/move2.wav', 50, 1)
|
visible_message(span("warning", "\The [src] retracts the missile rack."))
|
||||||
|
playsound(src, 'sound/effects/turret/move2.wav', 50, 1)
|
||||||
// Arcing rocket projectile that produces a weak explosion when it lands.
|
|
||||||
// Shouldn't punch holes in the floor, but will still hurt.
|
// Arcing rocket projectile that produces a weak explosion when it lands.
|
||||||
/obj/item/projectile/arc/explosive_rocket
|
// Shouldn't punch holes in the floor, but will still hurt.
|
||||||
name = "rocket"
|
/obj/item/projectile/arc/explosive_rocket
|
||||||
icon_state = "mortar"
|
name = "rocket"
|
||||||
|
icon_state = "mortar"
|
||||||
/obj/item/projectile/arc/explosive_rocket/on_impact(turf/T)
|
|
||||||
new /obj/effect/explosion(T) // Weak explosions don't produce this on their own, apparently.
|
/obj/item/projectile/arc/explosive_rocket/on_impact(turf/T)
|
||||||
explosion(T, 0, 0, 2, adminlog = FALSE)
|
new /obj/effect/explosion(T) // Weak explosions don't produce this on their own, apparently.
|
||||||
|
explosion(T, 0, 0, 2, adminlog = FALSE)
|
||||||
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/proc/launch_microsingularity(atom/target)
|
|
||||||
var/turf/T = get_turf(target)
|
/mob/living/simple_mob/mechanical/mecha/combat/gygax/dark/advanced/proc/launch_microsingularity(atom/target)
|
||||||
visible_message(span("warning", "\The [src] fires an energetic sphere into the air!"))
|
var/turf/T = get_turf(target)
|
||||||
playsound(src, 'sound/weapons/Laser.ogg', 50, 1)
|
visible_message(span("warning", "\The [src] fires an energetic sphere into the air!"))
|
||||||
face_atom(T)
|
playsound(src, 'sound/weapons/Laser.ogg', 50, 1)
|
||||||
var/obj/item/projectile/arc/microsingulo/sphere = new(loc)
|
face_atom(T)
|
||||||
sphere.launch(T)
|
var/obj/item/projectile/arc/microsingulo/sphere = new(loc)
|
||||||
|
sphere.old_style_target(T, src)
|
||||||
/obj/item/projectile/arc/microsingulo
|
sphere.fire()
|
||||||
name = "micro singularity"
|
|
||||||
icon_state = "bluespace"
|
/obj/item/projectile/arc/microsingulo
|
||||||
|
name = "micro singularity"
|
||||||
/obj/item/projectile/arc/microsingulo/on_impact(turf/T)
|
icon_state = "bluespace"
|
||||||
new /obj/effect/temporary_effect/pulse/microsingulo(T)
|
|
||||||
|
/obj/item/projectile/arc/microsingulo/on_impact(turf/T)
|
||||||
|
new /obj/effect/temporary_effect/pulse/microsingulo(T)
|
||||||
/obj/effect/temporary_effect/pulse/microsingulo
|
|
||||||
name = "micro singularity"
|
|
||||||
desc = "It's sucking everything in!"
|
/obj/effect/temporary_effect/pulse/microsingulo
|
||||||
icon = 'icons/obj/objects.dmi'
|
name = "micro singularity"
|
||||||
icon_state = "bhole3"
|
desc = "It's sucking everything in!"
|
||||||
light_range = 4
|
icon = 'icons/obj/objects.dmi'
|
||||||
light_power = 5
|
icon_state = "bhole3"
|
||||||
light_color = "#2ECCFA"
|
light_range = 4
|
||||||
pulses_remaining = 10
|
light_power = 5
|
||||||
pulse_delay = 0.5 SECONDS
|
light_color = "#2ECCFA"
|
||||||
var/pull_radius = 3
|
pulses_remaining = 10
|
||||||
var/pull_strength = STAGE_THREE
|
pulse_delay = 0.5 SECONDS
|
||||||
|
var/pull_radius = 3
|
||||||
/obj/effect/temporary_effect/pulse/microsingulo/on_pulse()
|
var/pull_strength = STAGE_THREE
|
||||||
for(var/atom/A in range(pull_radius, src))
|
|
||||||
A.singularity_pull(src, pull_strength)
|
/obj/effect/temporary_effect/pulse/microsingulo/on_pulse()
|
||||||
|
for(var/atom/A in range(pull_radius, src))
|
||||||
|
A.singularity_pull(src, pull_strength)
|
||||||
// The Advanced Dark Gygax's AI.
|
|
||||||
// The mob has three special attacks, based on the current intent.
|
|
||||||
// This AI choose the appropiate intent for the situation, and tries to ensure it doesn't kill itself by firing missiles at its feet.
|
// The Advanced Dark Gygax's AI.
|
||||||
/datum/ai_holder/simple_mob/intentional/adv_dark_gygax
|
// The mob has three special attacks, based on the current intent.
|
||||||
conserve_ammo = TRUE // Might help avoid 'I shoot the wall forever' cheese.
|
// This AI choose the appropiate intent for the situation, and tries to ensure it doesn't kill itself by firing missiles at its feet.
|
||||||
var/closest_desired_distance = 1 // Otherwise run up to them to be able to potentially shock or punch them.
|
/datum/ai_holder/simple_mob/intentional/adv_dark_gygax
|
||||||
|
conserve_ammo = TRUE // Might help avoid 'I shoot the wall forever' cheese.
|
||||||
var/electric_defense_radius = 3 // How big to assume electric defense's area is.
|
var/closest_desired_distance = 1 // Otherwise run up to them to be able to potentially shock or punch them.
|
||||||
var/microsingulo_radius = 3 // Same but for microsingulo pull.
|
|
||||||
var/rocket_explosive_radius = 2 // Explosion radius for the rockets.
|
var/electric_defense_radius = 3 // How big to assume electric defense's area is.
|
||||||
|
var/microsingulo_radius = 3 // Same but for microsingulo pull.
|
||||||
var/electric_defense_threshold = 2 // How many non-targeted people are needed in close proximity before electric defense is viable.
|
var/rocket_explosive_radius = 2 // Explosion radius for the rockets.
|
||||||
var/microsingulo_threshold = 2 // Similar to above, but uses an area around the target.
|
|
||||||
|
var/electric_defense_threshold = 2 // How many non-targeted people are needed in close proximity before electric defense is viable.
|
||||||
// Used to control the mob's positioning based on which special attack it has done.
|
var/microsingulo_threshold = 2 // Similar to above, but uses an area around the target.
|
||||||
// Note that the intent will not change again until the next special attack is about to happen.
|
|
||||||
/datum/ai_holder/simple_mob/intentional/adv_dark_gygax/on_engagement(atom/A)
|
// Used to control the mob's positioning based on which special attack it has done.
|
||||||
// Make the AI backpeddle if using an AoE special attack.
|
// Note that the intent will not change again until the next special attack is about to happen.
|
||||||
var/list/risky_intents = list(I_GRAB, I_HURT) // Mini-singulo and missiles.
|
/datum/ai_holder/simple_mob/intentional/adv_dark_gygax/on_engagement(atom/A)
|
||||||
if(holder.a_intent in risky_intents)
|
// Make the AI backpeddle if using an AoE special attack.
|
||||||
var/closest_distance = 1
|
var/list/risky_intents = list(I_GRAB, I_HURT) // Mini-singulo and missiles.
|
||||||
switch(holder.a_intent) // Plus one just in case.
|
if(holder.a_intent in risky_intents)
|
||||||
if(I_HURT)
|
var/closest_distance = 1
|
||||||
closest_distance = rocket_explosive_radius + 1
|
switch(holder.a_intent) // Plus one just in case.
|
||||||
if(I_GRAB)
|
if(I_HURT)
|
||||||
closest_distance = microsingulo_radius + 1
|
closest_distance = rocket_explosive_radius + 1
|
||||||
|
if(I_GRAB)
|
||||||
if(get_dist(holder, A) <= closest_distance)
|
closest_distance = microsingulo_radius + 1
|
||||||
holder.IMove(get_step_away(holder, A, closest_distance))
|
|
||||||
|
if(get_dist(holder, A) <= closest_distance)
|
||||||
// Otherwise get up close and personal.
|
holder.IMove(get_step_away(holder, A, closest_distance))
|
||||||
else if(get_dist(holder, A) > closest_desired_distance)
|
|
||||||
holder.IMove(get_step_towards(holder, A))
|
// Otherwise get up close and personal.
|
||||||
|
else if(get_dist(holder, A) > closest_desired_distance)
|
||||||
// Changes the mob's intent, which controls which special attack is used.
|
holder.IMove(get_step_towards(holder, A))
|
||||||
// I_DISARM causes Electric Defense, I_GRAB causes Micro-Singularity, and I_HURT causes Missile Barrage.
|
|
||||||
/datum/ai_holder/simple_mob/intentional/adv_dark_gygax/pre_special_attack(atom/A)
|
// Changes the mob's intent, which controls which special attack is used.
|
||||||
if(isliving(A))
|
// I_DISARM causes Electric Defense, I_GRAB causes Micro-Singularity, and I_HURT causes Missile Barrage.
|
||||||
var/mob/living/target = A
|
/datum/ai_holder/simple_mob/intentional/adv_dark_gygax/pre_special_attack(atom/A)
|
||||||
|
if(isliving(A))
|
||||||
// If we're surrounded, Electric Defense will quickly fix that.
|
var/mob/living/target = A
|
||||||
var/tally = 0
|
|
||||||
var/list/potential_targets = list_targets() // Returns list of mobs and certain objects like mechs and turrets.
|
// If we're surrounded, Electric Defense will quickly fix that.
|
||||||
for(var/atom/movable/AM in potential_targets)
|
var/tally = 0
|
||||||
if(get_dist(holder, AM) > electric_defense_radius)
|
var/list/potential_targets = list_targets() // Returns list of mobs and certain objects like mechs and turrets.
|
||||||
continue
|
for(var/atom/movable/AM in potential_targets)
|
||||||
if(!can_attack(AM))
|
if(get_dist(holder, AM) > electric_defense_radius)
|
||||||
continue
|
continue
|
||||||
tally++
|
if(!can_attack(AM))
|
||||||
|
continue
|
||||||
// Should we shock them?
|
tally++
|
||||||
if(tally >= electric_defense_threshold || get_dist(target, holder) <= electric_defense_radius)
|
|
||||||
holder.a_intent = I_DISARM
|
// Should we shock them?
|
||||||
return
|
if(tally >= electric_defense_threshold || get_dist(target, holder) <= electric_defense_radius)
|
||||||
|
holder.a_intent = I_DISARM
|
||||||
// Otherwise they're a fair distance away and we're not getting mobbed up close.
|
return
|
||||||
// See if we should use missiles or microsingulo.
|
|
||||||
tally = 0 // Let's recycle the var.
|
// Otherwise they're a fair distance away and we're not getting mobbed up close.
|
||||||
for(var/atom/movable/AM in potential_targets)
|
// See if we should use missiles or microsingulo.
|
||||||
if(get_dist(target, AM) > microsingulo_radius) // Deliberately tests distance between target and nearby targets and not the holder.
|
tally = 0 // Let's recycle the var.
|
||||||
continue
|
for(var/atom/movable/AM in potential_targets)
|
||||||
if(!can_attack(AM))
|
if(get_dist(target, AM) > microsingulo_radius) // Deliberately tests distance between target and nearby targets and not the holder.
|
||||||
continue
|
continue
|
||||||
if(AM.anchored) // Microsingulo doesn't do anything to anchored things.
|
if(!can_attack(AM))
|
||||||
tally--
|
continue
|
||||||
else
|
if(AM.anchored) // Microsingulo doesn't do anything to anchored things.
|
||||||
tally++
|
tally--
|
||||||
|
else
|
||||||
// Lots of people means minisingulo would be more useful.
|
tally++
|
||||||
if(tally >= microsingulo_threshold)
|
|
||||||
holder.a_intent = I_GRAB
|
// Lots of people means minisingulo would be more useful.
|
||||||
else // Otherwise use rockets.
|
if(tally >= microsingulo_threshold)
|
||||||
holder.a_intent = I_HURT
|
holder.a_intent = I_GRAB
|
||||||
|
else // Otherwise use rockets.
|
||||||
else
|
holder.a_intent = I_HURT
|
||||||
if(get_dist(holder, A) >= rocket_explosive_radius + 1)
|
|
||||||
holder.a_intent = I_HURT // Fire rockets if it's an obj/turf.
|
else
|
||||||
else
|
if(get_dist(holder, A) >= rocket_explosive_radius + 1)
|
||||||
holder.a_intent = I_DISARM // Electricity might not work but it's safe up close.
|
holder.a_intent = I_HURT // Fire rockets if it's an obj/turf.
|
||||||
|
else
|
||||||
|
holder.a_intent = I_DISARM // Electricity might not work but it's safe up close.
|
||||||
|
|||||||
@@ -1,94 +1,94 @@
|
|||||||
// These slimes lack certain xenobio features but get more combat-oriented goodies. Generally these are more oriented towards Explorers than Xenobiologists.
|
// These slimes lack certain xenobio features but get more combat-oriented goodies. Generally these are more oriented towards Explorers than Xenobiologists.
|
||||||
|
|
||||||
/mob/living/simple_mob/slime/feral
|
/mob/living/simple_mob/slime/feral
|
||||||
name = "feral slime"
|
name = "feral slime"
|
||||||
desc = "The result of slimes escaping containment from some xenobiology lab. \
|
desc = "The result of slimes escaping containment from some xenobiology lab. \
|
||||||
Having the means to successfully escape their lab, as well as having to survive on a harsh, cold world has made these \
|
Having the means to successfully escape their lab, as well as having to survive on a harsh, cold world has made these \
|
||||||
creatures rival the ferocity of other apex predators in this region of Sif. It is considered to be a very invasive species."
|
creatures rival the ferocity of other apex predators in this region of Sif. It is considered to be a very invasive species."
|
||||||
description_info = "Note that processing this large slime will give six cores."
|
description_info = "Note that processing this large slime will give six cores."
|
||||||
|
|
||||||
cores = 6 // Xenobio will love getting their hands on these.
|
cores = 6 // Xenobio will love getting their hands on these.
|
||||||
|
|
||||||
icon_state = "slime adult"
|
icon_state = "slime adult"
|
||||||
icon_living = "slime adult"
|
icon_living = "slime adult"
|
||||||
icon_dead = "slime adult dead"
|
icon_dead = "slime adult dead"
|
||||||
glow_range = 5
|
glow_range = 5
|
||||||
glow_intensity = 4
|
glow_intensity = 4
|
||||||
icon_scale = 2 // Twice as big as the xenobio variant.
|
icon_scale = 2 // Twice as big as the xenobio variant.
|
||||||
pixel_y = -10 // Since the base sprite isn't centered properly, the pixel auto-adjustment needs some help.
|
pixel_y = -10 // Since the base sprite isn't centered properly, the pixel auto-adjustment needs some help.
|
||||||
default_pixel_y = -10 // To prevent resetting above var.
|
default_pixel_y = -10 // To prevent resetting above var.
|
||||||
|
|
||||||
maxHealth = 300
|
maxHealth = 300
|
||||||
movement_cooldown = 10
|
movement_cooldown = 10
|
||||||
melee_attack_delay = 0.5 SECONDS
|
melee_attack_delay = 0.5 SECONDS
|
||||||
|
|
||||||
ai_holder_type = /datum/ai_holder/simple_mob/ranged/pointblank
|
ai_holder_type = /datum/ai_holder/simple_mob/ranged/pointblank
|
||||||
|
|
||||||
|
|
||||||
// Slimebatoning/xenotasing it just makes it mad at you (which can be good if you're heavily armored and your friends aren't).
|
// Slimebatoning/xenotasing it just makes it mad at you (which can be good if you're heavily armored and your friends aren't).
|
||||||
/mob/living/simple_mob/slime/feral/slimebatoned(mob/living/user, amount)
|
/mob/living/simple_mob/slime/feral/slimebatoned(mob/living/user, amount)
|
||||||
taunt(user, TRUE)
|
taunt(user, TRUE)
|
||||||
|
|
||||||
|
|
||||||
// ***********
|
// ***********
|
||||||
// *Dark Blue*
|
// *Dark Blue*
|
||||||
// ***********
|
// ***********
|
||||||
|
|
||||||
// Dark Blue feral slimes can fire a strong icicle projectile every few seconds. The icicle hits hard and has some armor penetration.
|
// Dark Blue feral slimes can fire a strong icicle projectile every few seconds. The icicle hits hard and has some armor penetration.
|
||||||
// They also have a similar aura as their xenobio counterparts, which inflicts cold damage. It also chills non-resistant mobs.
|
// They also have a similar aura as their xenobio counterparts, which inflicts cold damage. It also chills non-resistant mobs.
|
||||||
|
|
||||||
/mob/living/simple_mob/slime/feral/dark_blue
|
/mob/living/simple_mob/slime/feral/dark_blue
|
||||||
name = "dark blue feral slime"
|
name = "dark blue feral slime"
|
||||||
color = "#2398FF"
|
color = "#2398FF"
|
||||||
glow_toggle = TRUE
|
glow_toggle = TRUE
|
||||||
slime_color = "dark blue"
|
slime_color = "dark blue"
|
||||||
coretype = /obj/item/slime_extract/dark_blue
|
coretype = /obj/item/slime_extract/dark_blue
|
||||||
cold_resist = 1 // Complete immunity.
|
cold_resist = 1 // Complete immunity.
|
||||||
minbodytemp = 0
|
minbodytemp = 0
|
||||||
cold_damage_per_tick = 0
|
cold_damage_per_tick = 0
|
||||||
|
|
||||||
projectiletype = /obj/item/projectile/icicle
|
projectiletype = /obj/item/projectile/icicle
|
||||||
base_attack_cooldown = 2 SECONDS
|
base_attack_cooldown = 2 SECONDS
|
||||||
ranged_attack_delay = 1 SECOND
|
ranged_attack_delay = 1 SECOND
|
||||||
|
|
||||||
player_msg = "You can fire an icicle projectile every two seconds. It hits hard, and armor has a hard time resisting it.<br>\
|
player_msg = "You can fire an icicle projectile every two seconds. It hits hard, and armor has a hard time resisting it.<br>\
|
||||||
You are also immune to the cold, and you cause enemies around you to suffer periodic harm from the cold, if unprotected.<br>\
|
You are also immune to the cold, and you cause enemies around you to suffer periodic harm from the cold, if unprotected.<br>\
|
||||||
Unprotected enemies are also Chilled, making them slower and less evasive, and disabling effects last longer."
|
Unprotected enemies are also Chilled, making them slower and less evasive, and disabling effects last longer."
|
||||||
|
|
||||||
/obj/item/projectile/icicle
|
/obj/item/projectile/icicle
|
||||||
name = "icicle"
|
name = "icicle"
|
||||||
icon_state = "ice_2"
|
icon_state = "ice_2"
|
||||||
damage = 40
|
damage = 40
|
||||||
damage_type = BRUTE
|
damage_type = BRUTE
|
||||||
check_armour = "melee"
|
check_armour = "melee"
|
||||||
armor_penetration = 30
|
armor_penetration = 30
|
||||||
step_delay = 2 // Make it a bit easier to dodge since its not a bullet.
|
speed = 2
|
||||||
icon_scale = 2 // It hits like a truck.
|
icon_scale = 2 // It hits like a truck.
|
||||||
sharp = TRUE
|
sharp = TRUE
|
||||||
|
|
||||||
/obj/item/projectile/icicle/on_impact(atom/A)
|
/obj/item/projectile/icicle/on_impact(atom/A)
|
||||||
playsound(get_turf(A), "shatter", 70, 1)
|
playsound(get_turf(A), "shatter", 70, 1)
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
/obj/item/projectile/icicle/get_structure_damage()
|
/obj/item/projectile/icicle/get_structure_damage()
|
||||||
return damage / 2 // They're really deadly against mobs, but less effective against solid things.
|
return damage / 2 // They're really deadly against mobs, but less effective against solid things.
|
||||||
|
|
||||||
/mob/living/simple_mob/slime/feral/dark_blue/handle_special()
|
/mob/living/simple_mob/slime/feral/dark_blue/handle_special()
|
||||||
if(stat != DEAD)
|
if(stat != DEAD)
|
||||||
cold_aura()
|
cold_aura()
|
||||||
..()
|
..()
|
||||||
|
|
||||||
/mob/living/simple_mob/slime/feral/dark_blue/proc/cold_aura()
|
/mob/living/simple_mob/slime/feral/dark_blue/proc/cold_aura()
|
||||||
for(var/mob/living/L in view(3, src))
|
for(var/mob/living/L in view(3, src))
|
||||||
if(L == src)
|
if(L == src)
|
||||||
continue
|
continue
|
||||||
chill(L)
|
chill(L)
|
||||||
|
|
||||||
/mob/living/simple_mob/slime/feral/dark_blue/proc/chill(mob/living/L)
|
/mob/living/simple_mob/slime/feral/dark_blue/proc/chill(mob/living/L)
|
||||||
L.inflict_cold_damage(10)
|
L.inflict_cold_damage(10)
|
||||||
if(L.get_cold_protection() < 1)
|
if(L.get_cold_protection() < 1)
|
||||||
L.add_modifier(/datum/modifier/chilled, 5 SECONDS, src)
|
L.add_modifier(/datum/modifier/chilled, 5 SECONDS, src)
|
||||||
|
|
||||||
if(L.has_AI()) // Other AIs should react to hostile auras.
|
if(L.has_AI()) // Other AIs should react to hostile auras.
|
||||||
L.ai_holder.react_to_attack(src)
|
L.ai_holder.react_to_attack(src)
|
||||||
|
|
||||||
|
|||||||
@@ -672,10 +672,12 @@
|
|||||||
. = (is_client_active(10 MINUTES))
|
. = (is_client_active(10 MINUTES))
|
||||||
|
|
||||||
if(.)
|
if(.)
|
||||||
if(statpanel("Status") && ticker && ticker.current_state != GAME_STATE_PREGAME)
|
if(statpanel("Status"))
|
||||||
stat("Station Time", stationtime2text())
|
stat(null, "Time Dilation: [round(SStime_track.time_dilation_current,1)]% AVG:([round(SStime_track.time_dilation_avg_fast,1)]%, [round(SStime_track.time_dilation_avg,1)]%, [round(SStime_track.time_dilation_avg_slow,1)]%)")
|
||||||
stat("Station Date", stationdate2text())
|
if(ticker && ticker.current_state != GAME_STATE_PREGAME)
|
||||||
stat("Round Duration", roundduration2text())
|
stat("Station Time", stationtime2text())
|
||||||
|
stat("Station Date", stationdate2text())
|
||||||
|
stat("Round Duration", roundduration2text())
|
||||||
|
|
||||||
if(client.holder)
|
if(client.holder)
|
||||||
if(statpanel("Status"))
|
if(statpanel("Status"))
|
||||||
@@ -1192,6 +1194,8 @@ mob/proc/yank_out_object()
|
|||||||
closeToolTip(usr) //No reason not to, really
|
closeToolTip(usr) //No reason not to, really
|
||||||
|
|
||||||
..()
|
..()
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
|
||||||
// Manages a global list of mobs with clients attached, indexed by z-level.
|
// Manages a global list of mobs with clients attached, indexed by z-level.
|
||||||
/mob/proc/update_client_z(new_z) // +1 to register, null to unregister.
|
/mob/proc/update_client_z(new_z) // +1 to register, null to unregister.
|
||||||
@@ -1205,6 +1209,7 @@ mob/proc/yank_out_object()
|
|||||||
else
|
else
|
||||||
registered_z = null
|
registered_z = null
|
||||||
|
|
||||||
/mob/on_z_change(old_z, new_z)
|
/mob/onTransitZ(old_z, new_z)
|
||||||
..()
|
..()
|
||||||
update_client_z(new_z)
|
update_client_z(new_z)
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
return (!mover.density || !density || lying)
|
return (!mover.density || !density || lying)
|
||||||
else
|
else
|
||||||
return (!mover.density || !density || lying)
|
return (!mover.density || !density || lying)
|
||||||
return
|
|
||||||
|
|
||||||
/mob/proc/setMoveCooldown(var/timeout)
|
/mob/proc/setMoveCooldown(var/timeout)
|
||||||
move_delay = max(world.time + timeout, move_delay)
|
move_delay = max(world.time + timeout, move_delay)
|
||||||
@@ -18,22 +17,6 @@
|
|||||||
return FALSE // Need to wait more.
|
return FALSE // Need to wait more.
|
||||||
return TRUE
|
return TRUE
|
||||||
|
|
||||||
/client/North()
|
|
||||||
..()
|
|
||||||
|
|
||||||
|
|
||||||
/client/South()
|
|
||||||
..()
|
|
||||||
|
|
||||||
|
|
||||||
/client/West()
|
|
||||||
..()
|
|
||||||
|
|
||||||
|
|
||||||
/client/East()
|
|
||||||
..()
|
|
||||||
|
|
||||||
|
|
||||||
/client/proc/client_dir(input, direction=-1)
|
/client/proc/client_dir(input, direction=-1)
|
||||||
return turn(input, direction*dir2angle(dir))
|
return turn(input, direction*dir2angle(dir))
|
||||||
|
|
||||||
@@ -126,6 +109,7 @@
|
|||||||
*/
|
*/
|
||||||
return
|
return
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
//This proc should never be overridden elsewhere at /atom/movable to keep directions sane.
|
//This proc should never be overridden elsewhere at /atom/movable to keep directions sane.
|
||||||
/atom/movable/Move(newloc, direct)
|
/atom/movable/Move(newloc, direct)
|
||||||
if (direct & (direct - 1))
|
if (direct & (direct - 1))
|
||||||
@@ -182,6 +166,8 @@
|
|||||||
/atom/movable/proc/Moved(atom/oldloc)
|
/atom/movable/proc/Moved(atom/oldloc)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
/client/proc/Move_object(direct)
|
/client/proc/Move_object(direct)
|
||||||
if(mob && mob.control_object)
|
if(mob && mob.control_object)
|
||||||
if(mob.control_object.density)
|
if(mob.control_object.density)
|
||||||
|
|||||||
@@ -121,7 +121,7 @@
|
|||||||
var/mob/living/carbon/human/dummy/mannequin = new()
|
var/mob/living/carbon/human/dummy/mannequin = new()
|
||||||
client.prefs.dress_preview_mob(mannequin)
|
client.prefs.dress_preview_mob(mannequin)
|
||||||
var/mob/observer/dead/observer = new(mannequin)
|
var/mob/observer/dead/observer = new(mannequin)
|
||||||
observer.forceMove(null) //Let's not stay in our doomed mannequin
|
observer.moveToNullspace() //Let's not stay in our doomed mannequin
|
||||||
qdel(mannequin)
|
qdel(mannequin)
|
||||||
|
|
||||||
spawning = 1
|
spawning = 1
|
||||||
|
|||||||
@@ -75,7 +75,6 @@
|
|||||||
return
|
return
|
||||||
|
|
||||||
/obj/machinery/power/supermatter/shard/singularity_act()
|
/obj/machinery/power/supermatter/shard/singularity_act()
|
||||||
src.forceMove(null)
|
|
||||||
qdel(src)
|
qdel(src)
|
||||||
return 5000
|
return 5000
|
||||||
|
|
||||||
@@ -90,7 +89,6 @@
|
|||||||
SetUniversalState(/datum/universal_state/supermatter_cascade)
|
SetUniversalState(/datum/universal_state/supermatter_cascade)
|
||||||
log_admin("New super singularity made by eating a SM crystal [prints]. Last touched by [src.fingerprintslast].")
|
log_admin("New super singularity made by eating a SM crystal [prints]. Last touched by [src.fingerprintslast].")
|
||||||
message_admins("New super singularity made by eating a SM crystal [prints]. Last touched by [src.fingerprintslast].")
|
message_admins("New super singularity made by eating a SM crystal [prints]. Last touched by [src.fingerprintslast].")
|
||||||
src.forceMove(null)
|
|
||||||
qdel(src)
|
qdel(src)
|
||||||
return 50000
|
return 50000
|
||||||
|
|
||||||
|
|||||||
@@ -142,7 +142,8 @@
|
|||||||
|
|
||||||
var/obj/item/projectile/beam/emitter/A = get_emitter_beam()
|
var/obj/item/projectile/beam/emitter/A = get_emitter_beam()
|
||||||
A.damage = round(power_per_shot/EMITTER_DAMAGE_POWER_TRANSFER)
|
A.damage = round(power_per_shot/EMITTER_DAMAGE_POWER_TRANSFER)
|
||||||
A.launch( get_step(src.loc, src.dir) )
|
A.firer = src
|
||||||
|
A.fire(dir2angle(dir))
|
||||||
|
|
||||||
/obj/machinery/power/emitter/attackby(obj/item/W, mob/user)
|
/obj/machinery/power/emitter/attackby(obj/item/W, mob/user)
|
||||||
|
|
||||||
|
|||||||
@@ -470,7 +470,8 @@
|
|||||||
P.shot_from = src.name
|
P.shot_from = src.name
|
||||||
P.silenced = silenced
|
P.silenced = silenced
|
||||||
|
|
||||||
P.launch(target)
|
P.old_style_target(target)
|
||||||
|
P.fire()
|
||||||
|
|
||||||
last_shot = world.time
|
last_shot = world.time
|
||||||
|
|
||||||
@@ -645,24 +646,17 @@
|
|||||||
/obj/item/weapon/gun/proc/process_projectile(obj/projectile, mob/user, atom/target, var/target_zone, var/params=null)
|
/obj/item/weapon/gun/proc/process_projectile(obj/projectile, mob/user, atom/target, var/target_zone, var/params=null)
|
||||||
var/obj/item/projectile/P = projectile
|
var/obj/item/projectile/P = projectile
|
||||||
if(!istype(P))
|
if(!istype(P))
|
||||||
return 0 //default behaviour only applies to true projectiles
|
return FALSE //default behaviour only applies to true projectiles
|
||||||
|
|
||||||
if(params)
|
|
||||||
P.set_clickpoint(params)
|
|
||||||
|
|
||||||
//shooting while in shock
|
//shooting while in shock
|
||||||
var/x_offset = 0
|
var/forcespread
|
||||||
var/y_offset = 0
|
|
||||||
if(istype(user, /mob/living/carbon))
|
if(istype(user, /mob/living/carbon))
|
||||||
var/mob/living/carbon/mob = user
|
var/mob/living/carbon/mob = user
|
||||||
if(mob.shock_stage > 120)
|
if(mob.shock_stage > 120)
|
||||||
y_offset = rand(-2,2)
|
forcespread = rand(50, 50)
|
||||||
x_offset = rand(-2,2)
|
|
||||||
else if(mob.shock_stage > 70)
|
else if(mob.shock_stage > 70)
|
||||||
y_offset = rand(-1,1)
|
forcespread = rand(-25, 25)
|
||||||
x_offset = rand(-1,1)
|
var/launched = !P.launch_from_gun(target, target_zone, user, params, null, forcespread, src)
|
||||||
|
|
||||||
var/launched = !P.launch_from_gun(target, user, src, target_zone, x_offset, y_offset)
|
|
||||||
|
|
||||||
if(launched)
|
if(launched)
|
||||||
play_fire_sound(user, P)
|
play_fire_sound(user, P)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
icon_state = "dart"
|
icon_state = "dart"
|
||||||
damage = 5
|
damage = 5
|
||||||
var/reagent_amount = 15
|
var/reagent_amount = 15
|
||||||
kill_count = 15 //shorter range
|
range = 15 //shorter range
|
||||||
|
|
||||||
muzzle_type = null
|
muzzle_type = null
|
||||||
|
|
||||||
|
|||||||
@@ -79,9 +79,9 @@
|
|||||||
damage_type = HALLOSS
|
damage_type = HALLOSS
|
||||||
light_color = "#8837A3"
|
light_color = "#8837A3"
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/darkmatterstun/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/darkmatterstun
|
||||||
tracer_type = /obj/effect/projectile/darkmatterstun/tracer
|
tracer_type = /obj/effect/projectile/tracer/darkmatterstun
|
||||||
impact_type = /obj/effect/projectile/darkmatterstun/impact
|
impact_type = /obj/effect/projectile/impact/darkmatterstun
|
||||||
|
|
||||||
/obj/item/projectile/beam/darkmatter
|
/obj/item/projectile/beam/darkmatter
|
||||||
name = "dark matter bolt"
|
name = "dark matter bolt"
|
||||||
@@ -95,9 +95,9 @@
|
|||||||
|
|
||||||
embed_chance = 0
|
embed_chance = 0
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/darkmatter/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/darkmatter
|
||||||
tracer_type = /obj/effect/projectile/darkmatter/tracer
|
tracer_type = /obj/effect/projectile/tracer/darkmatter
|
||||||
impact_type = /obj/effect/projectile/darkmatter/impact
|
impact_type = /obj/effect/projectile/impact/darkmatter
|
||||||
|
|
||||||
/obj/item/projectile/energy/darkmatter
|
/obj/item/projectile/energy/darkmatter
|
||||||
name = "dark matter pellet"
|
name = "dark matter pellet"
|
||||||
|
|||||||
@@ -1,37 +1,84 @@
|
|||||||
/*
|
#define MOVES_HITSCAN -1 //Not actually hitscan but close as we get without actual hitscan.
|
||||||
#define BRUTE "brute"
|
#define MUZZLE_EFFECT_PIXEL_INCREMENT 17 //How many pixels to move the muzzle flash up so your character doesn't look like they're shitting out lasers.
|
||||||
#define BURN "burn"
|
|
||||||
#define TOX "tox"
|
|
||||||
#define OXY "oxy"
|
|
||||||
#define CLONE "clone"
|
|
||||||
|
|
||||||
#define ADD "add"
|
|
||||||
#define SET "set"
|
|
||||||
*/
|
|
||||||
|
|
||||||
/obj/item/projectile
|
/obj/item/projectile
|
||||||
name = "projectile"
|
name = "projectile"
|
||||||
icon = 'icons/obj/projectiles.dmi'
|
icon = 'icons/obj/projectiles.dmi'
|
||||||
icon_state = "bullet"
|
icon_state = "bullet"
|
||||||
density = 1
|
density = FALSE
|
||||||
unacidable = 1
|
anchored = TRUE
|
||||||
anchored = 1 //There's a reason this is here, Mport. God fucking damn it -Agouri. Find&Fix by Pete. The reason this is here is to stop the curving of emitter shots.
|
unacidable = TRUE
|
||||||
pass_flags = PASSTABLE
|
pass_flags = PASSTABLE
|
||||||
mouse_opacity = 0
|
mouse_opacity = 0
|
||||||
var/bumped = 0 //Prevents it from hitting more than one guy at once
|
|
||||||
|
////TG PROJECTILE SYTSEM
|
||||||
|
//Projectile stuff
|
||||||
|
var/range = 50
|
||||||
|
var/originalRange
|
||||||
|
|
||||||
|
//Fired processing vars
|
||||||
|
var/fired = FALSE //Have we been fired yet
|
||||||
|
var/paused = FALSE //for suspending the projectile midair
|
||||||
|
var/last_projectile_move = 0
|
||||||
|
var/last_process = 0
|
||||||
|
var/time_offset = 0
|
||||||
|
var/datum/point/vector/trajectory
|
||||||
|
var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location!
|
||||||
|
|
||||||
|
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
|
||||||
|
var/Angle = 0
|
||||||
|
var/original_angle = 0 //Angle at firing
|
||||||
|
var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle
|
||||||
|
var/spread = 0 //amount (in degrees) of projectile spread
|
||||||
|
animate_movement = 0 //Use SLIDE_STEPS in conjunction with legacy
|
||||||
|
var/ricochets = 0
|
||||||
|
var/ricochets_max = 2
|
||||||
|
var/ricochet_chance = 30
|
||||||
|
|
||||||
|
//Hitscan
|
||||||
|
var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored.
|
||||||
|
var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end. Used for hitscan effect generation.
|
||||||
|
var/datum/point/beam_index
|
||||||
|
var/turf/hitscan_last //last turf touched during hitscanning.
|
||||||
|
var/tracer_type
|
||||||
|
var/muzzle_type
|
||||||
|
var/impact_type
|
||||||
|
|
||||||
|
//Fancy hitscan lighting effects!
|
||||||
|
var/hitscan_light_intensity = 1.5
|
||||||
|
var/hitscan_light_range = 0.75
|
||||||
|
var/hitscan_light_color_override
|
||||||
|
var/muzzle_flash_intensity = 3
|
||||||
|
var/muzzle_flash_range = 1.5
|
||||||
|
var/muzzle_flash_color_override
|
||||||
|
var/impact_light_intensity = 3
|
||||||
|
var/impact_light_range = 2
|
||||||
|
var/impact_light_color_override
|
||||||
|
|
||||||
|
//Homing
|
||||||
|
var/homing = FALSE
|
||||||
|
var/atom/homing_target
|
||||||
|
var/homing_turn_speed = 10 //Angle per tick.
|
||||||
|
var/homing_inaccuracy_min = 0 //in pixels for these. offsets are set once when setting target.
|
||||||
|
var/homing_inaccuracy_max = 0
|
||||||
|
var/homing_offset_x = 0
|
||||||
|
var/homing_offset_y = 0
|
||||||
|
|
||||||
|
//Targetting
|
||||||
|
var/yo = null
|
||||||
|
var/xo = null
|
||||||
|
var/atom/original = null // the original target clicked
|
||||||
|
var/turf/starting = null // the projectile's starting turf
|
||||||
|
var/list/permutated = list() // we've passed through these atoms, don't try to hit them again
|
||||||
|
var/p_x = 16
|
||||||
|
var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center
|
||||||
|
|
||||||
|
//Misc/Polaris variables
|
||||||
|
|
||||||
var/def_zone = "" //Aiming at
|
var/def_zone = "" //Aiming at
|
||||||
var/mob/firer = null//Who shot it
|
var/mob/firer = null//Who shot it
|
||||||
var/silenced = 0 //Attack message
|
var/silenced = 0 //Attack message
|
||||||
var/yo = null
|
|
||||||
var/xo = null
|
|
||||||
var/current = null
|
|
||||||
var/shot_from = "" // name of the object which shot us
|
var/shot_from = "" // name of the object which shot us
|
||||||
var/atom/original = null // the target clicked (not necessarily where the projectile is headed). Should probably be renamed to 'target' or something.
|
|
||||||
var/turf/starting = null // the projectile's starting turf
|
|
||||||
var/list/permutated = list() // we've passed through these atoms, don't try to hit them again
|
|
||||||
|
|
||||||
var/p_x = 16
|
|
||||||
var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center
|
|
||||||
|
|
||||||
var/accuracy = 0
|
var/accuracy = 0
|
||||||
var/dispersion = 0.0
|
var/dispersion = 0.0
|
||||||
@@ -45,7 +92,6 @@
|
|||||||
var/check_armour = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb //Cael - bio and rad are also valid
|
var/check_armour = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb //Cael - bio and rad are also valid
|
||||||
var/projectile_type = /obj/item/projectile
|
var/projectile_type = /obj/item/projectile
|
||||||
var/penetrating = 0 //If greater than zero, the projectile will pass through dense objects as specified by on_penetrate()
|
var/penetrating = 0 //If greater than zero, the projectile will pass through dense objects as specified by on_penetrate()
|
||||||
var/kill_count = 50 //This will de-increment every process(). When 0, it will delete the projectile.
|
|
||||||
//Effects
|
//Effects
|
||||||
var/incendiary = 0 //1 for ignite on hit, 2 for trail of fire. 3 maybe later for burst of fire around the impact point. - Mech
|
var/incendiary = 0 //1 for ignite on hit, 2 for trail of fire. 3 maybe later for burst of fire around the impact point. - Mech
|
||||||
var/flammability = 0 //Amount of fire stacks to add for the above.
|
var/flammability = 0 //Amount of fire stacks to add for the above.
|
||||||
@@ -64,23 +110,127 @@
|
|||||||
|
|
||||||
embed_chance = 0 //Base chance for a projectile to embed
|
embed_chance = 0 //Base chance for a projectile to embed
|
||||||
|
|
||||||
var/hitscan = 0 // whether the projectile should be hitscan
|
|
||||||
var/step_delay = 1 // the delay between iterations if not a hitscan projectile
|
|
||||||
|
|
||||||
// effect types to be used
|
|
||||||
var/muzzle_type
|
|
||||||
var/tracer_type
|
|
||||||
var/impact_type
|
|
||||||
|
|
||||||
var/fire_sound = 'sound/weapons/Gunshot_old.ogg' // Can be overriden in gun.dm's fire_sound var. It can also be null but I don't know why you'd ever want to do that. -Ace
|
var/fire_sound = 'sound/weapons/Gunshot_old.ogg' // Can be overriden in gun.dm's fire_sound var. It can also be null but I don't know why you'd ever want to do that. -Ace
|
||||||
|
|
||||||
var/vacuum_traversal = 1 //Determines if the projectile can exist in vacuum, if false, the projectile will be deleted if it enters vacuum.
|
var/vacuum_traversal = TRUE //Determines if the projectile can exist in vacuum, if false, the projectile will be deleted if it enters vacuum.
|
||||||
|
|
||||||
var/datum/plot_vector/trajectory // used to plot the path of the projectile
|
/obj/item/projectile/proc/Range()
|
||||||
var/datum/vector_loc/location // current location of the projectile in pixel space
|
range--
|
||||||
var/matrix/effect_transform // matrix to rotate and scale projectile effects - putting it here so it doesn't
|
if(range <= 0 && loc)
|
||||||
// have to be recreated multiple times
|
on_range()
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/on_range() //if we want there to be effects when they reach the end of their range
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/return_predicted_turf_after_moves(moves, forced_angle) //I say predicted because there's no telling that the projectile won't change direction/location in flight.
|
||||||
|
if(!trajectory && isnull(forced_angle) && isnull(Angle))
|
||||||
|
return FALSE
|
||||||
|
var/datum/point/vector/current = trajectory
|
||||||
|
if(!current)
|
||||||
|
var/turf/T = get_turf(src)
|
||||||
|
current = new(T.x, T.y, T.z, pixel_x, pixel_y, isnull(forced_angle)? Angle : forced_angle, SSprojectiles.global_pixel_speed)
|
||||||
|
var/datum/point/vector/v = current.return_vector_after_increments(moves * SSprojectiles.global_iterations_per_move)
|
||||||
|
return v.return_turf()
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/return_pathing_turfs_in_moves(moves, forced_angle)
|
||||||
|
var/turf/current = get_turf(src)
|
||||||
|
var/turf/ending = return_predicted_turf_after_moves(moves, forced_angle)
|
||||||
|
return getline(current, ending)
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/set_pixel_speed(new_speed)
|
||||||
|
if(trajectory)
|
||||||
|
trajectory.set_speed(new_speed)
|
||||||
|
return TRUE
|
||||||
|
return FALSE
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/record_hitscan_start(datum/point/pcache)
|
||||||
|
if(pcache)
|
||||||
|
beam_segments = list()
|
||||||
|
beam_index = pcache
|
||||||
|
beam_segments[beam_index] = null //record start.
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/process_hitscan()
|
||||||
|
var/safety = range * 3
|
||||||
|
record_hitscan_start(RETURN_POINT_VECTOR_INCREMENT(src, Angle, MUZZLE_EFFECT_PIXEL_INCREMENT, 1))
|
||||||
|
while(loc && !QDELETED(src))
|
||||||
|
if(paused)
|
||||||
|
stoplag(1)
|
||||||
|
continue
|
||||||
|
if(safety-- <= 0)
|
||||||
|
if(loc)
|
||||||
|
Bump(loc)
|
||||||
|
if(!QDELETED(src))
|
||||||
|
qdel(src)
|
||||||
|
return //Kill!
|
||||||
|
pixel_move(1, TRUE)
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/pixel_move(trajectory_multiplier, hitscanning = FALSE)
|
||||||
|
if(!loc || !trajectory)
|
||||||
|
return
|
||||||
|
last_projectile_move = world.time
|
||||||
|
if(homing)
|
||||||
|
process_homing()
|
||||||
|
var/forcemoved = FALSE
|
||||||
|
for(var/i in 1 to SSprojectiles.global_iterations_per_move)
|
||||||
|
if(QDELETED(src))
|
||||||
|
return
|
||||||
|
trajectory.increment(trajectory_multiplier)
|
||||||
|
var/turf/T = trajectory.return_turf()
|
||||||
|
if(!istype(T))
|
||||||
|
qdel(src)
|
||||||
|
return
|
||||||
|
if(T.z != loc.z)
|
||||||
|
var/old = loc
|
||||||
|
before_z_change(loc, T)
|
||||||
|
trajectory_ignore_forcemove = TRUE
|
||||||
|
forceMove(T)
|
||||||
|
trajectory_ignore_forcemove = FALSE
|
||||||
|
after_z_change(old, loc)
|
||||||
|
if(!hitscanning)
|
||||||
|
pixel_x = trajectory.return_px()
|
||||||
|
pixel_y = trajectory.return_py()
|
||||||
|
forcemoved = TRUE
|
||||||
|
hitscan_last = loc
|
||||||
|
else if(T != loc)
|
||||||
|
before_move()
|
||||||
|
step_towards(src, T)
|
||||||
|
hitscan_last = loc
|
||||||
|
after_move()
|
||||||
|
if(can_hit_target(original, permutated))
|
||||||
|
Bump(original)
|
||||||
|
if(!hitscanning && !forcemoved)
|
||||||
|
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier * SSprojectiles.global_iterations_per_move
|
||||||
|
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier * SSprojectiles.global_iterations_per_move
|
||||||
|
animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
|
||||||
|
Range()
|
||||||
|
|
||||||
|
/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it.
|
||||||
|
..()
|
||||||
|
if(isliving(AM) && (AM.density || AM == original))
|
||||||
|
Bump(AM)
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/process_homing() //may need speeding up in the future performance wise.
|
||||||
|
if(!homing_target)
|
||||||
|
return FALSE
|
||||||
|
var/datum/point/PT = RETURN_PRECISE_POINT(homing_target)
|
||||||
|
PT.x += CLAMP(homing_offset_x, 1, world.maxx)
|
||||||
|
PT.y += CLAMP(homing_offset_y, 1, world.maxy)
|
||||||
|
var/angle = closer_angle_difference(Angle, angle_between_points(RETURN_PRECISE_POINT(src), PT))
|
||||||
|
setAngle(Angle + CLAMP(angle, -homing_turn_speed, homing_turn_speed))
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/set_homing_target(atom/A)
|
||||||
|
if(!A || (!isturf(A) && !isturf(A.loc)))
|
||||||
|
return FALSE
|
||||||
|
homing = TRUE
|
||||||
|
homing_target = A
|
||||||
|
homing_offset_x = rand(homing_inaccuracy_min, homing_inaccuracy_max)
|
||||||
|
homing_offset_y = rand(homing_inaccuracy_min, homing_inaccuracy_max)
|
||||||
|
if(prob(50))
|
||||||
|
homing_offset_x = -homing_offset_x
|
||||||
|
if(prob(50))
|
||||||
|
homing_offset_y = -homing_offset_y
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
//TODO: make it so this is called more reliably, instead of sometimes by bullet_act() and sometimes not
|
//TODO: make it so this is called more reliably, instead of sometimes by bullet_act() and sometimes not
|
||||||
/obj/item/projectile/proc/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
|
/obj/item/projectile/proc/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
|
||||||
if(blocked >= 100) return 0//Full block
|
if(blocked >= 100) return 0//Full block
|
||||||
@@ -91,151 +241,247 @@
|
|||||||
if(modifier_type_to_apply)
|
if(modifier_type_to_apply)
|
||||||
L.add_modifier(modifier_type_to_apply, modifier_duration)
|
L.add_modifier(modifier_type_to_apply, modifier_duration)
|
||||||
return 1
|
return 1
|
||||||
|
=======
|
||||||
|
/obj/item/projectile/process()
|
||||||
|
last_process = world.time
|
||||||
|
if(!loc || !fired || !trajectory)
|
||||||
|
fired = FALSE
|
||||||
|
return PROCESS_KILL
|
||||||
|
if(paused || !isturf(loc))
|
||||||
|
last_projectile_move += world.time - last_process //Compensates for pausing, so it doesn't become a hitscan projectile when unpaused from charged up ticks.
|
||||||
|
return
|
||||||
|
var/elapsed_time_deciseconds = (world.time - last_projectile_move) + time_offset
|
||||||
|
time_offset = 0
|
||||||
|
var/required_moves = speed > 0? FLOOR(elapsed_time_deciseconds / speed, 1) : MOVES_HITSCAN //Would be better if a 0 speed made hitscan but everyone hates those so I can't make it a universal system :<
|
||||||
|
if(required_moves == MOVES_HITSCAN)
|
||||||
|
required_moves = SSprojectiles.global_max_tick_moves
|
||||||
|
else
|
||||||
|
if(required_moves > SSprojectiles.global_max_tick_moves)
|
||||||
|
var/overrun = required_moves - SSprojectiles.global_max_tick_moves
|
||||||
|
required_moves = SSprojectiles.global_max_tick_moves
|
||||||
|
time_offset += overrun * speed
|
||||||
|
time_offset += MODULUS(elapsed_time_deciseconds, speed)
|
||||||
|
|
||||||
//called when the projectile stops flying because it collided with something
|
for(var/i in 1 to required_moves)
|
||||||
/obj/item/projectile/proc/on_impact(var/atom/A)
|
pixel_move(1, FALSE)
|
||||||
impact_effect(effect_transform) // generate impact effect
|
|
||||||
if(damage && damage_type == BURN)
|
/obj/item/projectile/proc/setAngle(new_angle) //wrapper for overrides.
|
||||||
var/turf/T = get_turf(A)
|
Angle = new_angle
|
||||||
if(T)
|
if(!nondirectional_sprite)
|
||||||
T.hotspot_expose(700, 5)
|
var/matrix/M = new
|
||||||
|
M.Turn(Angle)
|
||||||
|
transform = M
|
||||||
|
if(trajectory)
|
||||||
|
trajectory.set_angle(new_angle)
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
/obj/item/projectile/forceMove(atom/target)
|
||||||
|
if(!isloc(target) || !isloc(loc) || !z)
|
||||||
|
return ..()
|
||||||
|
var/zc = target.z != z
|
||||||
|
var/old = loc
|
||||||
|
if(zc)
|
||||||
|
before_z_change(old, target)
|
||||||
|
. = ..()
|
||||||
|
if(trajectory && !trajectory_ignore_forcemove && isturf(target))
|
||||||
|
if(hitscan)
|
||||||
|
finalize_hitscan_and_generate_tracers(FALSE)
|
||||||
|
trajectory.initialize_location(target.x, target.y, target.z, 0, 0)
|
||||||
|
if(hitscan)
|
||||||
|
record_hitscan_start(RETURN_PRECISE_POINT(src))
|
||||||
|
if(zc)
|
||||||
|
after_z_change(old, target)
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/fire(angle, atom/direct_target)
|
||||||
|
//If no angle needs to resolve it from xo/yo!
|
||||||
|
if(direct_target)
|
||||||
|
direct_target.bullet_act(src, def_zone)
|
||||||
|
qdel(src)
|
||||||
|
return
|
||||||
|
if(isnum(angle))
|
||||||
|
setAngle(angle)
|
||||||
|
var/turf/starting = get_turf(src)
|
||||||
|
if(isnull(Angle)) //Try to resolve through offsets if there's no angle set.
|
||||||
|
if(isnull(xo) || isnull(yo))
|
||||||
|
crash_with("WARNING: Projectile [type] deleted due to being unable to resolve a target after angle was null!")
|
||||||
|
qdel(src)
|
||||||
|
return
|
||||||
|
var/turf/target = locate(CLAMP(starting + xo, 1, world.maxx), CLAMP(starting + yo, 1, world.maxy), starting.z)
|
||||||
|
setAngle(Get_Angle(src, target))
|
||||||
|
if(dispersion)
|
||||||
|
setAngle(Angle + rand(-dispersion, dispersion))
|
||||||
|
original_angle = Angle
|
||||||
|
trajectory_ignore_forcemove = TRUE
|
||||||
|
forceMove(starting)
|
||||||
|
trajectory_ignore_forcemove = FALSE
|
||||||
|
trajectory = new(starting.x, starting.y, starting.z, pixel_x, pixel_y, Angle, SSprojectiles.global_pixel_speed)
|
||||||
|
last_projectile_move = world.time
|
||||||
|
permutated = list()
|
||||||
|
originalRange = range
|
||||||
|
fired = TRUE
|
||||||
|
if(hitscan)
|
||||||
|
process_hitscan()
|
||||||
|
START_PROCESSING(SSprojectiles, src)
|
||||||
|
pixel_move(1, FALSE) //move it now!
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/after_z_change(atom/olcloc, atom/newloc)
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/before_z_change(atom/oldloc, atom/newloc)
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/before_move()
|
||||||
return
|
return
|
||||||
|
|
||||||
//Checks if the projectile is eligible for embedding. Not that it necessarily will.
|
/obj/item/projectile/proc/after_move()
|
||||||
/obj/item/projectile/proc/can_embed()
|
return
|
||||||
//embed must be enabled and damage type must be brute
|
|
||||||
if(embed_chance == 0 || damage_type != BRUTE)
|
|
||||||
return 0
|
|
||||||
return 1
|
|
||||||
|
|
||||||
/obj/item/projectile/proc/get_structure_damage()
|
/obj/item/projectile/proc/store_hitscan_collision(datum/point/pcache)
|
||||||
if(damage_type == BRUTE || damage_type == BURN)
|
beam_segments[beam_index] = pcache
|
||||||
return damage
|
beam_index = pcache
|
||||||
return 0
|
beam_segments[beam_index] = null
|
||||||
|
|
||||||
//return 1 if the projectile should be allowed to pass through after all, 0 if not.
|
//Spread is FORCED!
|
||||||
/obj/item/projectile/proc/check_penetrate(var/atom/A)
|
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
|
||||||
return 1
|
var/turf/curloc = get_turf(source)
|
||||||
|
var/turf/targloc = get_turf(target)
|
||||||
|
trajectory_ignore_forcemove = TRUE
|
||||||
|
forceMove(get_turf(source))
|
||||||
|
trajectory_ignore_forcemove = FALSE
|
||||||
|
starting = get_turf(source)
|
||||||
|
original = target
|
||||||
|
if(targloc || !params)
|
||||||
|
yo = targloc.y - curloc.y
|
||||||
|
xo = targloc.x - curloc.x
|
||||||
|
setAngle(Get_Angle(src, targloc) + spread)
|
||||||
|
|
||||||
/obj/item/projectile/proc/check_fire(atom/target as mob, var/mob/living/user as mob) //Checks if you can hit them or not.
|
if(isliving(source) && params)
|
||||||
check_trajectory(target, user, pass_flags, flags)
|
var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, params)
|
||||||
|
p_x = calculated[2]
|
||||||
|
p_y = calculated[3]
|
||||||
|
|
||||||
//sets the click point of the projectile using mouse input params
|
setAngle(calculated[1] + spread)
|
||||||
/obj/item/projectile/proc/set_clickpoint(var/params)
|
else if(targloc)
|
||||||
|
yo = targloc.y - curloc.y
|
||||||
|
xo = targloc.x - curloc.x
|
||||||
|
setAngle(Get_Angle(src, targloc) + spread)
|
||||||
|
else
|
||||||
|
crash_with("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, params)
|
||||||
var/list/mouse_control = params2list(params)
|
var/list/mouse_control = params2list(params)
|
||||||
|
var/p_x = 0
|
||||||
|
var/p_y = 0
|
||||||
|
var/angle = 0
|
||||||
if(mouse_control["icon-x"])
|
if(mouse_control["icon-x"])
|
||||||
p_x = text2num(mouse_control["icon-x"])
|
p_x = text2num(mouse_control["icon-x"])
|
||||||
if(mouse_control["icon-y"])
|
if(mouse_control["icon-y"])
|
||||||
p_y = text2num(mouse_control["icon-y"])
|
p_y = text2num(mouse_control["icon-y"])
|
||||||
|
if(mouse_control["screen-loc"])
|
||||||
|
//Split screen-loc up into X+Pixel_X and Y+Pixel_Y
|
||||||
|
var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",")
|
||||||
|
|
||||||
//randomize clickpoint a bit based on dispersion
|
//Split X+Pixel_X up into list(X, Pixel_X)
|
||||||
if(dispersion)
|
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
|
||||||
var/radius = round((dispersion*0.443)*world.icon_size*0.8) //0.443 = sqrt(pi)/4 = 2a, where a is the side length of a square that shares the same area as a circle with diameter = dispersion
|
|
||||||
p_x = between(0, p_x + rand(-radius, radius), world.icon_size)
|
|
||||||
p_y = between(0, p_y + rand(-radius, radius), world.icon_size)
|
|
||||||
|
|
||||||
//called to launch a projectile
|
//Split Y+Pixel_Y up into list(Y, Pixel_Y)
|
||||||
/obj/item/projectile/proc/launch(atom/target, var/target_zone, var/x_offset=0, var/y_offset=0, var/angle_offset=0)
|
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
|
||||||
var/turf/curloc = get_turf(src)
|
var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32
|
||||||
var/turf/targloc = get_turf(target)
|
var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32
|
||||||
if (!istype(targloc) || !istype(curloc))
|
|
||||||
return 1
|
|
||||||
|
|
||||||
if(combustion)
|
//Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
|
||||||
curloc.hotspot_expose(700, 5)
|
var/list/screenview = user.client? getviewsize(user.client.view) : world.view
|
||||||
|
var/screenviewX = screenview[1] * world.icon_size
|
||||||
|
var/screenviewY = screenview[2] * world.icon_size
|
||||||
|
|
||||||
if(targloc == curloc) //Shooting something in the same turf
|
var/ox = round(screenviewX/2) - user.client.pixel_x //"origin" x
|
||||||
target.bullet_act(src, target_zone)
|
var/oy = round(screenviewY/2) - user.client.pixel_y //"origin" y
|
||||||
on_impact(target)
|
angle = ATAN2(y - oy, x - ox)
|
||||||
qdel(src)
|
return list(angle, p_x, p_y)
|
||||||
return 0
|
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/redirect(x, y, starting, source)
|
||||||
|
old_style_target(locate(x, y, z), starting? get_turf(starting) : get_turf(source))
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/old_style_target(atom/target, atom/source)
|
||||||
|
if(!source)
|
||||||
|
source = get_turf(src)
|
||||||
|
starting = source
|
||||||
original = target
|
original = target
|
||||||
def_zone = target_zone
|
setAngle(Get_Angle(source, target))
|
||||||
|
|
||||||
spawn()
|
/obj/item/projectile/Destroy()
|
||||||
setup_trajectory(curloc, targloc, x_offset, y_offset, angle_offset) //plot the initial trajectory
|
if(hitscan)
|
||||||
process()
|
finalize_hitscan_and_generate_tracers()
|
||||||
|
STOP_PROCESSING(SSprojectiles, src)
|
||||||
|
cleanup_beam_segments()
|
||||||
|
qdel(trajectory)
|
||||||
|
return ..()
|
||||||
|
|
||||||
return 0
|
/obj/item/projectile/proc/cleanup_beam_segments()
|
||||||
|
QDEL_LIST_ASSOC(beam_segments)
|
||||||
|
beam_segments = list()
|
||||||
|
qdel(beam_index)
|
||||||
|
|
||||||
//called to launch a projectile from a gun
|
/obj/item/projectile/proc/vol_by_damage()
|
||||||
/obj/item/projectile/proc/launch_from_gun(atom/target, mob/user, obj/item/weapon/gun/launcher, var/target_zone, var/x_offset=0, var/y_offset=0)
|
if(damage)
|
||||||
if(user == target) //Shooting yourself
|
return CLAMP((damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100
|
||||||
user.bullet_act(src, target_zone)
|
|
||||||
on_impact(user)
|
|
||||||
qdel(src)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
loc = get_turf(user) //move the projectile out into the world
|
|
||||||
|
|
||||||
firer = user
|
|
||||||
shot_from = launcher.name
|
|
||||||
silenced = launcher.silenced
|
|
||||||
|
|
||||||
return launch(target, target_zone, x_offset, y_offset)
|
|
||||||
|
|
||||||
//Used to change the direction of the projectile in flight.
|
|
||||||
/obj/item/projectile/proc/redirect(var/new_x, var/new_y, var/atom/starting_loc, var/mob/new_firer=null)
|
|
||||||
var/turf/new_target = locate(new_x, new_y, src.z)
|
|
||||||
|
|
||||||
original = new_target
|
|
||||||
if(new_firer)
|
|
||||||
firer = src
|
|
||||||
|
|
||||||
setup_trajectory(starting_loc, new_target)
|
|
||||||
|
|
||||||
//Called when the projectile intercepts a mob. Returns 1 if the projectile hit the mob, 0 if it missed and should keep flying.
|
|
||||||
/obj/item/projectile/proc/attack_mob(var/mob/living/target_mob, var/distance, var/miss_modifier=0)
|
|
||||||
if(!istype(target_mob))
|
|
||||||
return
|
|
||||||
|
|
||||||
//roll to-hit
|
|
||||||
miss_modifier = max(15*(distance-2) - accuracy + miss_modifier + target_mob.get_evasion(), 0)
|
|
||||||
var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1 || original != target_mob)) //if the projectile hits a target we weren't originally aiming at then retain the chance to miss
|
|
||||||
|
|
||||||
var/result = PROJECTILE_FORCE_MISS
|
|
||||||
if(hit_zone)
|
|
||||||
def_zone = hit_zone //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part
|
|
||||||
result = target_mob.bullet_act(src, def_zone)
|
|
||||||
|
|
||||||
if(result == PROJECTILE_FORCE_MISS)
|
|
||||||
if(!silenced)
|
|
||||||
visible_message("<span class='notice'>\The [src] misses [target_mob] narrowly!</span>")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
//hit messages
|
|
||||||
if(silenced)
|
|
||||||
to_chat(target_mob, "<span class='danger'>You've been hit in the [parse_zone(def_zone)] by \the [src]!</span>")
|
|
||||||
else
|
else
|
||||||
visible_message("<span class='danger'>\The [target_mob] is hit by \the [src] in the [parse_zone(def_zone)]!</span>")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter
|
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume.
|
||||||
|
|
||||||
//admin logs
|
/obj/item/projectile/proc/finalize_hitscan_and_generate_tracers(impacting = TRUE)
|
||||||
if(!no_attack_log)
|
if(trajectory && beam_index)
|
||||||
if(istype(firer, /mob) && istype(target_mob))
|
var/datum/point/pcache = trajectory.copy_to()
|
||||||
add_attack_logs(firer,target_mob,"Shot with \a [src.type] projectile")
|
beam_segments[beam_index] = pcache
|
||||||
|
generate_hitscan_tracers(null, null, impacting)
|
||||||
|
|
||||||
//sometimes bullet_act() will want the projectile to continue flying
|
/obj/item/projectile/proc/generate_hitscan_tracers(cleanup = TRUE, duration = 3, impacting = TRUE)
|
||||||
if (result == PROJECTILE_CONTINUE)
|
if(!length(beam_segments))
|
||||||
return 0
|
return
|
||||||
|
if(tracer_type)
|
||||||
|
var/tempref = "\ref[src]"
|
||||||
|
for(var/datum/point/p in beam_segments)
|
||||||
|
generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity, tempref)
|
||||||
|
if(muzzle_type && duration > 0)
|
||||||
|
var/datum/point/p = beam_segments[1]
|
||||||
|
var/atom/movable/thing = new muzzle_type
|
||||||
|
p.move_atom_to_src(thing)
|
||||||
|
var/matrix/M = new
|
||||||
|
M.Turn(original_angle)
|
||||||
|
thing.transform = M
|
||||||
|
thing.color = color
|
||||||
|
thing.set_light(muzzle_flash_range, muzzle_flash_intensity, muzzle_flash_color_override? muzzle_flash_color_override : color)
|
||||||
|
QDEL_IN(thing, duration)
|
||||||
|
if(impacting && impact_type && duration > 0)
|
||||||
|
var/datum/point/p = beam_segments[beam_segments[beam_segments.len]]
|
||||||
|
var/atom/movable/thing = new impact_type
|
||||||
|
p.move_atom_to_src(thing)
|
||||||
|
var/matrix/M = new
|
||||||
|
M.Turn(Angle)
|
||||||
|
thing.transform = M
|
||||||
|
thing.color = color
|
||||||
|
thing.set_light(impact_light_range, impact_light_intensity, impact_light_color_override? impact_light_color_override : color)
|
||||||
|
QDEL_IN(thing, duration)
|
||||||
|
if(cleanup)
|
||||||
|
cleanup_beam_segments()
|
||||||
|
|
||||||
return 1
|
//Returns true if the target atom is on our current turf and above the right layer
|
||||||
|
/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
|
||||||
|
return (target && ((target.layer >= TABLE_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
|
||||||
|
|
||||||
/obj/item/projectile/Bump(atom/A as mob|obj|turf|area, forced=0)
|
/obj/item/projectile/Bump(atom/A)
|
||||||
if(A == src)
|
if(A in permutated)
|
||||||
return 0 //no
|
return FALSE
|
||||||
|
if(firer && !reflected)
|
||||||
|
if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech
|
||||||
|
trajectory_ignore_forcemove = TRUE
|
||||||
|
forceMove(get_turf(A))
|
||||||
|
trajectory_ignore_forcemove = FALSE
|
||||||
|
return FALSE
|
||||||
|
|
||||||
if(A == firer)
|
var/distance = get_dist(starting, get_turf(src))
|
||||||
loc = A.loc
|
var/turf/target_turf = get_turf(A)
|
||||||
return 0 //cannot shoot yourself
|
var/passthrough = FALSE
|
||||||
|
|
||||||
if((bumped && !forced) || (A in permutated))
|
|
||||||
return 0
|
|
||||||
|
|
||||||
var/passthrough = 0 //if the projectile should continue flying
|
|
||||||
var/distance = get_dist(starting,loc)
|
|
||||||
|
|
||||||
bumped = 1
|
|
||||||
if(ismob(A))
|
if(ismob(A))
|
||||||
var/mob/M = A
|
var/mob/M = A
|
||||||
if(istype(A, /mob/living))
|
if(istype(A, /mob/living))
|
||||||
@@ -246,13 +492,13 @@
|
|||||||
var/shield_chance = min(80, (30 * (M.mob_size / 10))) //Small mobs have a harder time keeping a dead body as a shield than a human-sized one. Unathi would have an easier job, if they are made to be SIZE_LARGE in the future. -Mech
|
var/shield_chance = min(80, (30 * (M.mob_size / 10))) //Small mobs have a harder time keeping a dead body as a shield than a human-sized one. Unathi would have an easier job, if they are made to be SIZE_LARGE in the future. -Mech
|
||||||
if(prob(shield_chance))
|
if(prob(shield_chance))
|
||||||
visible_message("<span class='danger'>\The [M] uses [G.affecting] as a shield!</span>")
|
visible_message("<span class='danger'>\The [M] uses [G.affecting] as a shield!</span>")
|
||||||
if(Bump(G.affecting, forced=1))
|
if(Bump(G.affecting))
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
visible_message("<span class='danger'>\The [M] tries to use [G.affecting] as a shield, but fails!</span>")
|
visible_message("<span class='danger'>\The [M] tries to use [G.affecting] as a shield, but fails!</span>")
|
||||||
else
|
else
|
||||||
visible_message("<span class='danger'>\The [M] uses [G.affecting] as a shield!</span>")
|
visible_message("<span class='danger'>\The [M] uses [G.affecting] as a shield!</span>")
|
||||||
if(Bump(G.affecting, forced=1))
|
if(Bump(G.affecting))
|
||||||
return //If Bump() returns 0 (keep going) then we continue on to attack M.
|
return //If Bump() returns 0 (keep going) then we continue on to attack M.
|
||||||
|
|
||||||
passthrough = !attack_mob(M, distance)
|
passthrough = !attack_mob(M, distance)
|
||||||
@@ -269,119 +515,83 @@
|
|||||||
//penetrating projectiles can pass through things that otherwise would not let them
|
//penetrating projectiles can pass through things that otherwise would not let them
|
||||||
if(!passthrough && penetrating > 0)
|
if(!passthrough && penetrating > 0)
|
||||||
if(check_penetrate(A))
|
if(check_penetrate(A))
|
||||||
passthrough = 1
|
passthrough = TRUE
|
||||||
penetrating--
|
penetrating--
|
||||||
|
|
||||||
//the bullet passes through a dense object!
|
|
||||||
if(passthrough)
|
if(passthrough)
|
||||||
//move ourselves onto A so we can continue on our way.
|
trajectory_ignore_forcemove = TRUE
|
||||||
if(A)
|
forceMove(target_turf)
|
||||||
if(istype(A, /turf))
|
permutated.Add(A)
|
||||||
loc = A
|
trajectory_ignore_forcemove = FALSE
|
||||||
else
|
return FALSE
|
||||||
loc = A.loc
|
|
||||||
permutated.Add(A)
|
|
||||||
bumped = 0 //reset bumped variable!
|
|
||||||
return 0
|
|
||||||
|
|
||||||
//stop flying
|
|
||||||
on_impact(A)
|
|
||||||
|
|
||||||
density = 0
|
|
||||||
invisibility = 101
|
|
||||||
|
|
||||||
|
if(A)
|
||||||
|
on_impact(A)
|
||||||
qdel(src)
|
qdel(src)
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
//TODO: make it so this is called more reliably, instead of sometimes by bullet_act() and sometimes not
|
||||||
|
/obj/item/projectile/proc/on_hit(atom/target, blocked = 0, def_zone)
|
||||||
|
if(blocked >= 100) return 0//Full block
|
||||||
|
if(!isliving(target)) return 0
|
||||||
|
// if(isanimal(target)) return 0
|
||||||
|
var/mob/living/L = target
|
||||||
|
L.apply_effects(stun, weaken, paralyze, irradiate, stutter, eyeblur, drowsy, agony, blocked, incendiary, flammability) // add in AGONY!
|
||||||
|
if(modifier_type_to_apply)
|
||||||
|
L.add_modifier(modifier_type_to_apply, modifier_duration)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/item/projectile/ex_act()
|
//called when the projectile stops flying because it Bump'd with something
|
||||||
return //explosions probably shouldn't delete projectiles
|
/obj/item/projectile/proc/on_impact(atom/A)
|
||||||
|
if(damage && damage_type == BURN)
|
||||||
|
var/turf/T = get_turf(A)
|
||||||
|
if(T)
|
||||||
|
T.hotspot_expose(700, 5)
|
||||||
|
|
||||||
/obj/item/projectile/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
//Checks if the projectile is eligible for embedding. Not that it necessarily will.
|
||||||
|
/obj/item/projectile/proc/can_embed()
|
||||||
|
//embed must be enabled and damage type must be brute
|
||||||
|
if(embed_chance == 0 || damage_type != BRUTE)
|
||||||
|
return 0
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/item/projectile/process()
|
/obj/item/projectile/proc/get_structure_damage()
|
||||||
var/first_step = 1
|
if(damage_type == BRUTE || damage_type == BURN)
|
||||||
|
return damage
|
||||||
|
return 0
|
||||||
|
|
||||||
spawn while(src && src.loc)
|
//return 1 if the projectile should be allowed to pass through after all, 0 if not.
|
||||||
if(kill_count-- < 1)
|
/obj/item/projectile/proc/check_penetrate(atom/A)
|
||||||
on_impact(src.loc) //for any final impact behaviours
|
return 1
|
||||||
qdel(src)
|
|
||||||
return
|
|
||||||
if((!( current ) || loc == current))
|
|
||||||
current = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z)
|
|
||||||
if((x == 1 || x == world.maxx || y == 1 || y == world.maxy))
|
|
||||||
qdel(src)
|
|
||||||
return
|
|
||||||
|
|
||||||
trajectory.increment() // increment the current location
|
/obj/item/projectile/proc/check_fire(atom/target as mob, mob/living/user as mob) //Checks if you can hit them or not.
|
||||||
location = trajectory.return_location(location) // update the locally stored location data
|
check_trajectory(target, user, pass_flags, flags)
|
||||||
update_light() //energy projectiles will look glowy and fun
|
|
||||||
|
|
||||||
if(!location)
|
/obj/item/projectile/CanPass()
|
||||||
qdel(src) // if it's left the world... kill it
|
return TRUE
|
||||||
return
|
|
||||||
|
|
||||||
if (is_below_sound_pressure(get_turf(src)) && !vacuum_traversal) //Deletes projectiles that aren't supposed to bein vacuum if they leave pressurised areas
|
//Called when the projectile intercepts a mob. Returns 1 if the projectile hit the mob, 0 if it missed and should keep flying.
|
||||||
qdel(src)
|
/obj/item/projectile/proc/attack_mob(mob/living/target_mob, distance, miss_modifier = 0)
|
||||||
return
|
if(!istype(target_mob))
|
||||||
|
return
|
||||||
|
|
||||||
before_move()
|
//roll to-hit
|
||||||
Move(location.return_turf())
|
miss_modifier = max(15*(distance-2) - accuracy + miss_modifier + target_mob.get_evasion(), 0)
|
||||||
after_move()
|
var/hit_zone = get_zone_with_miss_chance(def_zone, target_mob, miss_modifier, ranged_attack=(distance > 1 || original != target_mob)) //if the projectile hits a target we weren't originally aiming at then retain the chance to miss
|
||||||
|
|
||||||
if(!bumped && !isturf(original))
|
var/result = PROJECTILE_FORCE_MISS
|
||||||
if(loc == get_turf(original))
|
if(hit_zone)
|
||||||
if(!(original in permutated))
|
def_zone = hit_zone //set def_zone, so if the projectile ends up hitting someone else later (to be implemented), it is more likely to hit the same part
|
||||||
if(Bump(original))
|
result = target_mob.bullet_act(src, def_zone)
|
||||||
return
|
|
||||||
|
|
||||||
if(first_step)
|
if(result == PROJECTILE_FORCE_MISS)
|
||||||
muzzle_effect(effect_transform)
|
if(!silenced)
|
||||||
first_step = 0
|
visible_message("<span class='notice'>\The [src] misses [target_mob] narrowly!</span>")
|
||||||
else if(!bumped)
|
return FALSE
|
||||||
tracer_effect(effect_transform)
|
|
||||||
|
|
||||||
if(incendiary >= 2) //This should cover the bases of 'Why is there fuel here?' in a much cleaner way than previous.
|
//hit messages
|
||||||
if(src && src.loc) //Safety.
|
|
||||||
if(!src.loc.density)
|
|
||||||
var/trail_volume = (flammability * 0.20)
|
|
||||||
new /obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(src.loc, trail_volume, src.dir)
|
|
||||||
|
|
||||||
if(!hitscan)
|
|
||||||
sleep(step_delay) //add delay between movement iterations if it's not a hitscan weapon
|
|
||||||
|
|
||||||
/obj/item/projectile/proc/before_move()
|
|
||||||
return
|
|
||||||
|
|
||||||
/obj/item/projectile/proc/after_move()
|
|
||||||
return
|
|
||||||
|
|
||||||
/obj/item/projectile/proc/setup_trajectory(turf/startloc, turf/targloc, var/x_offset = 0, var/y_offset = 0)
|
|
||||||
// setup projectile state
|
|
||||||
starting = startloc
|
|
||||||
current = startloc
|
|
||||||
yo = targloc.y - startloc.y + y_offset
|
|
||||||
xo = targloc.x - startloc.x + x_offset
|
|
||||||
|
|
||||||
// trajectory dispersion
|
|
||||||
var/offset = 0
|
|
||||||
if(dispersion)
|
|
||||||
var/radius = round(dispersion*9, 1)
|
|
||||||
offset = rand(-radius, radius)
|
|
||||||
|
|
||||||
// plot the initial trajectory
|
|
||||||
trajectory = new()
|
|
||||||
trajectory.setup(starting, original, pixel_x, pixel_y, angle_offset=offset)
|
|
||||||
|
|
||||||
// generate this now since all visual effects the projectile makes can use it
|
|
||||||
effect_transform = new()
|
|
||||||
effect_transform.Scale(trajectory.return_hypotenuse(), 1)
|
|
||||||
effect_transform.Turn(-trajectory.return_angle()) //no idea why this has to be inverted, but it works
|
|
||||||
|
|
||||||
transform = turn(transform, -(trajectory.return_angle() + 90)) //no idea why 90 needs to be added, but it works
|
|
||||||
|
|
||||||
/obj/item/projectile/proc/muzzle_effect(var/matrix/T)
|
|
||||||
if(silenced)
|
if(silenced)
|
||||||
|
<<<<<<< HEAD
|
||||||
return
|
return
|
||||||
|
|
||||||
if(ispath(muzzle_type))
|
if(ispath(muzzle_type))
|
||||||
@@ -455,13 +665,22 @@
|
|||||||
var/turf/targloc = get_turf(target)
|
var/turf/targloc = get_turf(target)
|
||||||
if(!curloc || !targloc)
|
if(!curloc || !targloc)
|
||||||
return 0
|
return 0
|
||||||
|
=======
|
||||||
|
to_chat(target_mob, "<span class='danger'>You've been hit in the [parse_zone(def_zone)] by \the [src]!</span>")
|
||||||
|
else
|
||||||
|
visible_message("<span class='danger'>\The [target_mob] is hit by \the [src] in the [parse_zone(def_zone)]!</span>")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
|
|
||||||
original = target
|
//admin logs
|
||||||
|
if(!no_attack_log)
|
||||||
|
if(istype(firer, /mob) && istype(target_mob))
|
||||||
|
add_attack_logs(firer,target_mob,"Shot with \a [src.type] projectile")
|
||||||
|
|
||||||
//plot the initial trajectory
|
//sometimes bullet_act() will want the projectile to continue flying
|
||||||
setup_trajectory(curloc, targloc)
|
if (result == PROJECTILE_CONTINUE)
|
||||||
return process(targloc)
|
return FALSE
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
/obj/item/projectile/test/process(var/turf/targloc)
|
/obj/item/projectile/test/process(var/turf/targloc)
|
||||||
while(src) //Loop on through!
|
while(src) //Loop on through!
|
||||||
if(result)
|
if(result)
|
||||||
@@ -469,12 +688,20 @@
|
|||||||
// return (result - 1)
|
// return (result - 1)
|
||||||
if((!( targloc ) || loc == targloc))
|
if((!( targloc ) || loc == targloc))
|
||||||
targloc = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) //Finding the target turf at map edge
|
targloc = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) //Finding the target turf at map edge
|
||||||
|
=======
|
||||||
|
return TRUE
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
|
|
||||||
trajectory.increment() // increment the current location
|
|
||||||
location = trajectory.return_location(location) // update the locally stored location data
|
|
||||||
|
|
||||||
Move(location.return_turf())
|
/obj/item/projectile/proc/launch_projectile(atom/target, target_zone, mob/user, params, angle_override, forced_spread = 0)
|
||||||
|
original = target
|
||||||
|
def_zone = check_zone(target_zone)
|
||||||
|
firer = user
|
||||||
|
var/direct_target
|
||||||
|
if(get_turf(target) == get_turf(src))
|
||||||
|
direct_target = target
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
var/mob/living/M = locate() in get_turf(src)
|
var/mob/living/M = locate() in get_turf(src)
|
||||||
if(istype(M)) //If there is someting living...
|
if(istype(M)) //If there is someting living...
|
||||||
result_ref = M
|
result_ref = M
|
||||||
@@ -489,14 +716,15 @@
|
|||||||
/proc/check_trajectory(atom/target as mob|obj, atom/firer as mob|obj, var/pass_flags=PASSTABLE|PASSGLASS|PASSGRILLE, flags=null)
|
/proc/check_trajectory(atom/target as mob|obj, atom/firer as mob|obj, var/pass_flags=PASSTABLE|PASSGLASS|PASSGRILLE, flags=null)
|
||||||
if(!istype(target) || !istype(firer))
|
if(!istype(target) || !istype(firer))
|
||||||
return 0
|
return 0
|
||||||
|
=======
|
||||||
|
preparePixelProjectile(target, user? user : get_turf(src), params, forced_spread)
|
||||||
|
return fire(angle_override, direct_target)
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
|
|
||||||
var/obj/item/projectile/test/trace = new /obj/item/projectile/test(get_turf(firer)) //Making the test....
|
//called to launch a projectile from a gun
|
||||||
|
/obj/item/projectile/proc/launch_from_gun(atom/target, target_zone, mob/user, params, angle_override, forced_spread, obj/item/weapon/gun/launcher)
|
||||||
|
|
||||||
//Set the flags and pass flags to that of the real projectile...
|
shot_from = launcher.name
|
||||||
if(!isnull(flags))
|
silenced = launcher.silenced
|
||||||
trace.flags = flags
|
|
||||||
trace.pass_flags = pass_flags
|
|
||||||
|
|
||||||
var/output = trace.launch(target) //Test it!
|
return launch_projectile(target, target_zone, user, params, angle_override, forced_spread)
|
||||||
qdel(trace) //No need for it anymore
|
|
||||||
return output //Send it back to the gun!
|
|
||||||
|
|||||||
@@ -9,12 +9,16 @@
|
|||||||
/obj/item/projectile/arc
|
/obj/item/projectile/arc
|
||||||
name = "arcing shot"
|
name = "arcing shot"
|
||||||
icon_state = "fireball" // WIP
|
icon_state = "fireball" // WIP
|
||||||
step_delay = 2 // Travel a bit slower, to really sell the arc visuals.
|
speed = 2 // Travel a bit slower, to really sell the arc visuals.
|
||||||
|
movement_type = UNSTOPPABLE
|
||||||
plane = ABOVE_PLANE // Since projectiles are 'in the air', they might visually overlap mobs while in flight, so the projectile needs to be above their plane.
|
plane = ABOVE_PLANE // Since projectiles are 'in the air', they might visually overlap mobs while in flight, so the projectile needs to be above their plane.
|
||||||
var/target_distance = null // How many tiles the impact site is.
|
var/target_distance = null // How many tiles the impact site is.
|
||||||
var/fired_dir = null // Which direction was the projectile fired towards. Needed to invert the projectile turning based on if facing left or right.
|
var/fired_dir = null // Which direction was the projectile fired towards. Needed to invert the projectile turning based on if facing left or right.
|
||||||
var/obj/effect/projectile_shadow/shadow = null // Visual indicator for the projectile's 'true' position. Needed due to being bound to two dimensions in reality.
|
var/obj/effect/projectile_shadow/shadow = null // Visual indicator for the projectile's 'true' position. Needed due to being bound to two dimensions in reality.
|
||||||
|
|
||||||
|
/obj/item/projectile/arc/Bump()
|
||||||
|
return
|
||||||
|
|
||||||
/obj/item/projectile/arc/Initialize()
|
/obj/item/projectile/arc/Initialize()
|
||||||
shadow = new(get_turf(src))
|
shadow = new(get_turf(src))
|
||||||
return ..()
|
return ..()
|
||||||
@@ -23,33 +27,32 @@
|
|||||||
QDEL_NULL(shadow)
|
QDEL_NULL(shadow)
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
/obj/item/projectile/arc/Bump(atom/A, forced=0)
|
|
||||||
return 0
|
|
||||||
// if(get_turf(src) != original)
|
|
||||||
// return 0
|
|
||||||
// else
|
|
||||||
// return ..()
|
|
||||||
|
|
||||||
// This is a test projectile in the sense that its testing the code to make sure it works,
|
// This is a test projectile in the sense that its testing the code to make sure it works,
|
||||||
// as opposed to a 'can I hit this thing' projectile.
|
// as opposed to a 'can I hit this thing' projectile.
|
||||||
/obj/item/projectile/arc/test/on_impact(turf/T)
|
/obj/item/projectile/arc/test/on_impact(turf/T)
|
||||||
new /obj/effect/explosion(T)
|
new /obj/effect/explosion(T)
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
/obj/item/projectile/arc/launch(atom/target, target_zone, x_offset=0, y_offset=0, angle_offset=0)
|
/obj/item/projectile/arc/old_style_target(target, source)
|
||||||
var/expected_distance = get_dist(target, loc)
|
var/source_loc = get_turf(source) || get_turf(src)
|
||||||
kill_count = expected_distance // So the projectile "hits the ground."
|
var/expected_distance = get_dist(target, source_loc)
|
||||||
|
range = expected_distance // So the projectile "hits the ground."
|
||||||
target_distance = expected_distance
|
target_distance = expected_distance
|
||||||
fired_dir = get_dir(loc, target)
|
fired_dir = get_dir(source_loc, target)
|
||||||
..() // Does the regular launching stuff.
|
..()
|
||||||
if(fired_dir & EAST)
|
if(fired_dir & EAST)
|
||||||
transform = turn(transform, -45)
|
transform = turn(transform, -45)
|
||||||
else if(fired_dir & WEST)
|
else if(fired_dir & WEST)
|
||||||
transform = turn(transform, 45)
|
transform = turn(transform, 45)
|
||||||
|
|
||||||
|
/obj/item/projectile/arc/on_range()
|
||||||
|
on_impact(loc)
|
||||||
|
return ..()
|
||||||
|
|
||||||
// Visuals.
|
// Visuals.
|
||||||
/obj/item/projectile/arc/after_move()
|
/obj/item/projectile/arc/after_move()
|
||||||
|
if(QDELETED(src))
|
||||||
|
return
|
||||||
// Handle projectile turning in flight.
|
// Handle projectile turning in flight.
|
||||||
// This won't turn if fired north/south, as it looks weird.
|
// This won't turn if fired north/south, as it looks weird.
|
||||||
var/turn_per_step = 90 / target_distance
|
var/turn_per_step = 90 / target_distance
|
||||||
@@ -73,7 +76,7 @@
|
|||||||
var/projectile_position = arc_progress / target_distance
|
var/projectile_position = arc_progress / target_distance
|
||||||
var/sine_position = projectile_position * 180
|
var/sine_position = projectile_position * 180
|
||||||
var/pixel_z_position = arc_max_height * sin(sine_position)
|
var/pixel_z_position = arc_max_height * sin(sine_position)
|
||||||
animate(src, pixel_z = pixel_z_position, time = step_delay)
|
animate(src, pixel_z = pixel_z_position, time = speed)
|
||||||
|
|
||||||
// Update our shadow.
|
// Update our shadow.
|
||||||
shadow.forceMove(loc)
|
shadow.forceMove(loc)
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
light_power = 0.5
|
light_power = 0.5
|
||||||
light_color = "#FF0D00"
|
light_color = "#FF0D00"
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/laser/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/laser
|
||||||
tracer_type = /obj/effect/projectile/laser/tracer
|
tracer_type = /obj/effect/projectile/tracer/laser
|
||||||
impact_type = /obj/effect/projectile/laser/impact
|
impact_type = /obj/effect/projectile/impact/laser
|
||||||
|
|
||||||
/obj/item/projectile/beam/practice
|
/obj/item/projectile/beam/practice
|
||||||
name = "laser"
|
name = "laser"
|
||||||
@@ -54,9 +54,9 @@
|
|||||||
light_power = 1
|
light_power = 1
|
||||||
light_color = "#FF0D00"
|
light_color = "#FF0D00"
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/laser_heavy/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/laser_heavy
|
||||||
tracer_type = /obj/effect/projectile/laser_heavy/tracer
|
tracer_type = /obj/effect/projectile/tracer/laser_heavy
|
||||||
impact_type = /obj/effect/projectile/laser_heavy/impact
|
impact_type = /obj/effect/projectile/impact/laser_heavy
|
||||||
|
|
||||||
/obj/item/projectile/beam/heavylaser/fakeemitter
|
/obj/item/projectile/beam/heavylaser/fakeemitter
|
||||||
name = "emitter beam"
|
name = "emitter beam"
|
||||||
@@ -64,9 +64,9 @@
|
|||||||
fire_sound = 'sound/weapons/emitter.ogg'
|
fire_sound = 'sound/weapons/emitter.ogg'
|
||||||
light_color = "#00CC33"
|
light_color = "#00CC33"
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/emitter/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/emitter
|
||||||
tracer_type = /obj/effect/projectile/emitter/tracer
|
tracer_type = /obj/effect/projectile/tracer/emitter
|
||||||
impact_type = /obj/effect/projectile/emitter/impact
|
impact_type = /obj/effect/projectile/impact/emitter
|
||||||
|
|
||||||
/obj/item/projectile/beam/heavylaser/cannon
|
/obj/item/projectile/beam/heavylaser/cannon
|
||||||
damage = 80
|
damage = 80
|
||||||
@@ -81,9 +81,9 @@
|
|||||||
armor_penetration = 50
|
armor_penetration = 50
|
||||||
light_color = "#00CC33"
|
light_color = "#00CC33"
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/xray/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/xray
|
||||||
tracer_type = /obj/effect/projectile/xray/tracer
|
tracer_type = /obj/effect/projectile/tracer/xray
|
||||||
impact_type = /obj/effect/projectile/xray/impact
|
impact_type = /obj/effect/projectile/impact/xray
|
||||||
|
|
||||||
/obj/item/projectile/beam/cyan
|
/obj/item/projectile/beam/cyan
|
||||||
name = "cyan beam"
|
name = "cyan beam"
|
||||||
@@ -91,9 +91,9 @@
|
|||||||
damage = 40
|
damage = 40
|
||||||
light_color = "#00C6FF"
|
light_color = "#00C6FF"
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/laser_omni/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/laser_omni
|
||||||
tracer_type = /obj/effect/projectile/laser_omni/tracer
|
tracer_type = /obj/effect/projectile/tracer/laser_omni
|
||||||
impact_type = /obj/effect/projectile/laser_omni/impact
|
impact_type = /obj/effect/projectile/impact/laser_omni
|
||||||
|
|
||||||
/obj/item/projectile/beam/pulse
|
/obj/item/projectile/beam/pulse
|
||||||
name = "pulse"
|
name = "pulse"
|
||||||
@@ -103,9 +103,9 @@
|
|||||||
armor_penetration = 100
|
armor_penetration = 100
|
||||||
light_color = "#0066FF"
|
light_color = "#0066FF"
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/laser_pulse/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/laser_pulse
|
||||||
tracer_type = /obj/effect/projectile/laser_pulse/tracer
|
tracer_type = /obj/effect/projectile/tracer/laser_pulse
|
||||||
impact_type = /obj/effect/projectile/laser_pulse/impact
|
impact_type = /obj/effect/projectile/impact/laser_pulse
|
||||||
|
|
||||||
/obj/item/projectile/beam/pulse/on_hit(var/atom/target, var/blocked = 0)
|
/obj/item/projectile/beam/pulse/on_hit(var/atom/target, var/blocked = 0)
|
||||||
if(isturf(target))
|
if(isturf(target))
|
||||||
@@ -119,9 +119,9 @@
|
|||||||
damage = 0 // The actual damage is computed in /code/modules/power/singularity/emitter.dm
|
damage = 0 // The actual damage is computed in /code/modules/power/singularity/emitter.dm
|
||||||
light_color = "#00CC33"
|
light_color = "#00CC33"
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/emitter/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/emitter
|
||||||
tracer_type = /obj/effect/projectile/emitter/tracer
|
tracer_type = /obj/effect/projectile/tracer/emitter
|
||||||
impact_type = /obj/effect/projectile/emitter/impact
|
impact_type = /obj/effect/projectile/impact/emitter
|
||||||
|
|
||||||
/obj/item/projectile/beam/lastertag/blue
|
/obj/item/projectile/beam/lastertag/blue
|
||||||
name = "lasertag beam"
|
name = "lasertag beam"
|
||||||
@@ -134,9 +134,9 @@
|
|||||||
|
|
||||||
combustion = FALSE
|
combustion = FALSE
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/laser_blue/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/laser_blue
|
||||||
tracer_type = /obj/effect/projectile/laser_blue/tracer
|
tracer_type = /obj/effect/projectile/tracer/laser_blue
|
||||||
impact_type = /obj/effect/projectile/laser_blue/impact
|
impact_type = /obj/effect/projectile/impact/laser_blue
|
||||||
|
|
||||||
/obj/item/projectile/beam/lastertag/blue/on_hit(var/atom/target, var/blocked = 0)
|
/obj/item/projectile/beam/lastertag/blue/on_hit(var/atom/target, var/blocked = 0)
|
||||||
if(istype(target, /mob/living/carbon/human))
|
if(istype(target, /mob/living/carbon/human))
|
||||||
@@ -173,9 +173,9 @@
|
|||||||
|
|
||||||
combustion = FALSE
|
combustion = FALSE
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/laser_omni/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/laser_omni
|
||||||
tracer_type = /obj/effect/projectile/laser_omni/tracer
|
tracer_type = /obj/effect/projectile/tracer/laser_omni
|
||||||
impact_type = /obj/effect/projectile/laser_omni/impact
|
impact_type = /obj/effect/projectile/impact/laser_omni
|
||||||
|
|
||||||
/obj/item/projectile/beam/lastertag/omni/on_hit(var/atom/target, var/blocked = 0)
|
/obj/item/projectile/beam/lastertag/omni/on_hit(var/atom/target, var/blocked = 0)
|
||||||
if(istype(target, /mob/living/carbon/human))
|
if(istype(target, /mob/living/carbon/human))
|
||||||
@@ -192,9 +192,9 @@
|
|||||||
armor_penetration = 10
|
armor_penetration = 10
|
||||||
light_color = "#00CC33"
|
light_color = "#00CC33"
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/xray/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/xray
|
||||||
tracer_type = /obj/effect/projectile/xray/tracer
|
tracer_type = /obj/effect/projectile/tracer/xray
|
||||||
impact_type = /obj/effect/projectile/xray/impact
|
impact_type = /obj/effect/projectile/impact/xray
|
||||||
|
|
||||||
/obj/item/projectile/beam/stun
|
/obj/item/projectile/beam/stun
|
||||||
name = "stun beam"
|
name = "stun beam"
|
||||||
@@ -208,9 +208,9 @@
|
|||||||
|
|
||||||
combustion = FALSE
|
combustion = FALSE
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/stun/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/stun
|
||||||
tracer_type = /obj/effect/projectile/stun/tracer
|
tracer_type = /obj/effect/projectile/tracer/stun
|
||||||
impact_type = /obj/effect/projectile/stun/impact
|
impact_type = /obj/effect/projectile/impact/stun
|
||||||
|
|
||||||
/obj/item/projectile/beam/stun/weak
|
/obj/item/projectile/beam/stun/weak
|
||||||
name = "weak stun beam"
|
name = "weak stun beam"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
sharp = 1
|
sharp = 1
|
||||||
var/mob_passthrough_check = 0
|
var/mob_passthrough_check = 0
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/bullet/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/bullet
|
||||||
|
|
||||||
/obj/item/projectile/bullet/on_hit(var/atom/target, var/blocked = 0)
|
/obj/item/projectile/bullet/on_hit(var/atom/target, var/blocked = 0)
|
||||||
if (..(target, blocked))
|
if (..(target, blocked))
|
||||||
@@ -257,12 +257,12 @@
|
|||||||
incendiary = 2
|
incendiary = 2
|
||||||
flammability = 4
|
flammability = 4
|
||||||
agony = 30
|
agony = 30
|
||||||
kill_count = 4
|
range = 4
|
||||||
vacuum_traversal = 0
|
vacuum_traversal = 0
|
||||||
|
|
||||||
/obj/item/projectile/bullet/incendiary/flamethrower/large
|
/obj/item/projectile/bullet/incendiary/flamethrower/large
|
||||||
damage = 15
|
damage = 15
|
||||||
kill_count = 6
|
range = 6
|
||||||
|
|
||||||
/* Practice rounds and blanks */
|
/* Practice rounds and blanks */
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
icon_state = "bullet"
|
icon_state = "bullet"
|
||||||
fire_sound = 'sound/weapons/gunshot_pathetic.ogg'
|
fire_sound = 'sound/weapons/gunshot_pathetic.ogg'
|
||||||
damage = 5
|
damage = 5
|
||||||
kill_count = 15 //if the shell hasn't hit anything after travelling this far it just explodes.
|
range = 15 //if the shell hasn't hit anything after travelling this far it just explodes.
|
||||||
var/flash_range = 0
|
var/flash_range = 0
|
||||||
var/brightness = 7
|
var/brightness = 7
|
||||||
var/light_colour = "#ffffff"
|
var/light_colour = "#ffffff"
|
||||||
@@ -165,7 +165,7 @@
|
|||||||
icon_state = "plasma_stun"
|
icon_state = "plasma_stun"
|
||||||
fire_sound = 'sound/weapons/blaster.ogg'
|
fire_sound = 'sound/weapons/blaster.ogg'
|
||||||
armor_penetration = 10
|
armor_penetration = 10
|
||||||
kill_count = 4
|
range = 4
|
||||||
damage = 5
|
damage = 5
|
||||||
agony = 55
|
agony = 55
|
||||||
damage_type = BURN
|
damage_type = BURN
|
||||||
@@ -212,25 +212,25 @@
|
|||||||
light_color = "#0000FF"
|
light_color = "#0000FF"
|
||||||
|
|
||||||
embed_chance = 0
|
embed_chance = 0
|
||||||
muzzle_type = /obj/effect/projectile/pulse/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/pulse
|
||||||
|
|
||||||
/obj/item/projectile/energy/phase
|
/obj/item/projectile/energy/phase
|
||||||
name = "phase wave"
|
name = "phase wave"
|
||||||
icon_state = "phase"
|
icon_state = "phase"
|
||||||
kill_count = 6
|
range = 6
|
||||||
damage = 5
|
damage = 5
|
||||||
SA_bonus_damage = 45 // 50 total on animals
|
SA_bonus_damage = 45 // 50 total on animals
|
||||||
SA_vulnerability = SA_ANIMAL
|
SA_vulnerability = SA_ANIMAL
|
||||||
|
|
||||||
/obj/item/projectile/energy/phase/light
|
/obj/item/projectile/energy/phase/light
|
||||||
kill_count = 4
|
range = 4
|
||||||
SA_bonus_damage = 35 // 40 total on animals
|
SA_bonus_damage = 35 // 40 total on animals
|
||||||
|
|
||||||
/obj/item/projectile/energy/phase/heavy
|
/obj/item/projectile/energy/phase/heavy
|
||||||
kill_count = 8
|
range = 8
|
||||||
SA_bonus_damage = 55 // 60 total on animals
|
SA_bonus_damage = 55 // 60 total on animals
|
||||||
|
|
||||||
/obj/item/projectile/energy/phase/heavy/cannon
|
/obj/item/projectile/energy/phase/heavy/cannon
|
||||||
kill_count = 10
|
range = 10
|
||||||
damage = 15
|
damage = 15
|
||||||
SA_bonus_damage = 60 // 75 total on animals
|
SA_bonus_damage = 60 // 75 total on animals
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
var/beam_state = "b_beam"
|
var/beam_state = "b_beam"
|
||||||
|
|
||||||
damage = 5
|
damage = 5
|
||||||
step_delay = 2
|
speed = 2
|
||||||
damage_type = BURN
|
damage_type = BURN
|
||||||
check_armour = "energy"
|
check_armour = "energy"
|
||||||
armor_penetration = 15
|
armor_penetration = 15
|
||||||
@@ -27,9 +27,9 @@
|
|||||||
var/list/help_messages = list("slaps", "pokes", "nudges", "bumps", "pinches")
|
var/list/help_messages = list("slaps", "pokes", "nudges", "bumps", "pinches")
|
||||||
var/done_mob_unique = FALSE // Has the projectile already done something to a mob?
|
var/done_mob_unique = FALSE // Has the projectile already done something to a mob?
|
||||||
|
|
||||||
/obj/item/projectile/energy/hook/launch(atom/target, target_zone, x_offset=0, y_offset=0, angle_offset=0)
|
/obj/item/projectile/energy/hook/launch_projectile(atom/target, target_zone, mob/user, params, angle_override, forced_spread = 0)
|
||||||
var/expected_distance = get_dist(target, loc)
|
var/expected_distance = get_dist(target, loc)
|
||||||
kill_count = expected_distance // So the hook hits the ground if no mob is hit.
|
range = expected_distance // So the hook hits the ground if no mob is hit.
|
||||||
target_distance = expected_distance
|
target_distance = expected_distance
|
||||||
if(firer) // Needed to ensure later checks in impact and on hit function.
|
if(firer) // Needed to ensure later checks in impact and on hit function.
|
||||||
launcher_intent = firer.a_intent
|
launcher_intent = firer.a_intent
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
penetrating = 2
|
penetrating = 2
|
||||||
embed_chance = 0
|
embed_chance = 0
|
||||||
armor_penetration = 40
|
armor_penetration = 40
|
||||||
kill_count = 20
|
range = 20
|
||||||
|
|
||||||
var/searing = 0 //Does this fuelrod ignore shields?
|
var/searing = 0 //Does this fuelrod ignore shields?
|
||||||
var/detonate_travel = 0 //Will this fuelrod explode when it reaches maximum distance?
|
var/detonate_travel = 0 //Will this fuelrod explode when it reaches maximum distance?
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
|
|
||||||
if(energetic_impact)
|
if(energetic_impact)
|
||||||
var/eye_coverage = 0
|
var/eye_coverage = 0
|
||||||
for(var/mob/living/carbon/M in viewers(world.view, location))
|
for(var/mob/living/carbon/M in viewers(world.view, get_turf(src)))
|
||||||
eye_coverage = 0
|
eye_coverage = 0
|
||||||
if(iscarbon(M))
|
if(iscarbon(M))
|
||||||
eye_coverage = M.eyecheck()
|
eye_coverage = M.eyecheck()
|
||||||
@@ -103,7 +103,7 @@
|
|||||||
armor_penetration = 100
|
armor_penetration = 100
|
||||||
penetrating = 100 //Theoretically, this shouldn't stop flying for a while, unless someone lines it up with a wall or fires it into a mountain.
|
penetrating = 100 //Theoretically, this shouldn't stop flying for a while, unless someone lines it up with a wall or fires it into a mountain.
|
||||||
irradiate = 120
|
irradiate = 120
|
||||||
kill_count = 75
|
range = 75
|
||||||
searing = 1
|
searing = 1
|
||||||
detonate_travel = 1
|
detonate_travel = 1
|
||||||
detonate_mob = 1
|
detonate_mob = 1
|
||||||
@@ -116,6 +116,9 @@
|
|||||||
return ..(target, blocked, def_zone)
|
return ..(target, blocked, def_zone)
|
||||||
|
|
||||||
/obj/item/projectile/bullet/magnetic/fuelrod/supermatter/check_penetrate()
|
/obj/item/projectile/bullet/magnetic/fuelrod/supermatter/check_penetrate()
|
||||||
|
<<<<<<< HEAD
|
||||||
|
return 1
|
||||||
|
=======
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/item/projectile/bullet/magnetic/bore
|
/obj/item/projectile/bullet/magnetic/bore
|
||||||
@@ -127,7 +130,7 @@
|
|||||||
penetrating = 0
|
penetrating = 0
|
||||||
check_armour = "melee"
|
check_armour = "melee"
|
||||||
irradiate = 20
|
irradiate = 20
|
||||||
kill_count = 6
|
range = 6
|
||||||
|
|
||||||
/obj/item/projectile/bullet/magnetic/bore/Bump(atom/A, forced=0)
|
/obj/item/projectile/bullet/magnetic/bore/Bump(atom/A, forced=0)
|
||||||
if(istype(A, /turf/simulated/mineral))
|
if(istype(A, /turf/simulated/mineral))
|
||||||
@@ -142,3 +145,4 @@
|
|||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
..()
|
..()
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
|
|||||||
@@ -9,10 +9,6 @@
|
|||||||
var/base_spread = 90 //lower means the pellets spread more across body parts. If zero then this is considered a shrapnel explosion instead of a shrapnel cone
|
var/base_spread = 90 //lower means the pellets spread more across body parts. If zero then this is considered a shrapnel explosion instead of a shrapnel cone
|
||||||
var/spread_step = 10 //higher means the pellets spread more across body parts with distance
|
var/spread_step = 10 //higher means the pellets spread more across body parts with distance
|
||||||
|
|
||||||
/obj/item/projectile/bullet/pellet/Bumped()
|
|
||||||
. = ..()
|
|
||||||
bumped = 0 //can hit all mobs in a tile. pellets is decremented inside attack_mob so this should be fine.
|
|
||||||
|
|
||||||
/obj/item/projectile/bullet/pellet/proc/get_pellets(var/distance)
|
/obj/item/projectile/bullet/pellet/proc/get_pellets(var/distance)
|
||||||
var/pellet_loss = round((distance - 1)/range_step) //pellets lost due to distance
|
var/pellet_loss = round((distance - 1)/range_step) //pellets lost due to distance
|
||||||
return max(pellets - pellet_loss, 1)
|
return max(pellets - pellet_loss, 1)
|
||||||
|
|||||||
@@ -219,7 +219,7 @@
|
|||||||
embed_chance = 0 // nope
|
embed_chance = 0 // nope
|
||||||
nodamage = 1
|
nodamage = 1
|
||||||
damage_type = HALLOSS
|
damage_type = HALLOSS
|
||||||
muzzle_type = /obj/effect/projectile/bullet/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/bullet
|
||||||
|
|
||||||
/obj/item/projectile/bola
|
/obj/item/projectile/bola
|
||||||
name = "bola"
|
name = "bola"
|
||||||
|
|||||||
38
code/modules/projectiles/projectile/trace.dm
Normal file
38
code/modules/projectiles/projectile/trace.dm
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
//Helper proc to check if you can hit them or not.
|
||||||
|
/proc/check_trajectory(atom/target as mob|obj, atom/firer as mob|obj, var/pass_flags=PASSTABLE|PASSGLASS|PASSGRILLE, flags=null)
|
||||||
|
if(!istype(target) || !istype(firer))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
var/obj/item/projectile/test/trace = new /obj/item/projectile/test(get_turf(firer)) //Making the test....
|
||||||
|
|
||||||
|
//Set the flags and pass flags to that of the real projectile...
|
||||||
|
if(!isnull(flags))
|
||||||
|
trace.flags = flags
|
||||||
|
trace.pass_flags = pass_flags
|
||||||
|
|
||||||
|
return trace.launch_projectile(target) //Test it!
|
||||||
|
|
||||||
|
/obj/item/projectile/proc/_check_fire(atom/target as mob, var/mob/living/user as mob) //Checks if you can hit them or not.
|
||||||
|
check_trajectory(target, user, pass_flags, flags)
|
||||||
|
|
||||||
|
//"Tracing" projectile
|
||||||
|
/obj/item/projectile/test //Used to see if you can hit them.
|
||||||
|
invisibility = 101 //Nope! Can't see me!
|
||||||
|
hitscan = TRUE
|
||||||
|
nodamage = TRUE
|
||||||
|
damage = 0
|
||||||
|
var/list/hit = list()
|
||||||
|
|
||||||
|
/obj/item/projectile/test/process_hitscan()
|
||||||
|
. = ..()
|
||||||
|
if(!QDELING(src))
|
||||||
|
qdel(src)
|
||||||
|
return hit
|
||||||
|
|
||||||
|
/obj/item/projectile/test/Bump(atom/A)
|
||||||
|
if(A != src)
|
||||||
|
hit |= A
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
/obj/item/projectile/test/attack_mob()
|
||||||
|
return
|
||||||
@@ -467,7 +467,7 @@
|
|||||||
H.vent_gas(loc)
|
H.vent_gas(loc)
|
||||||
qdel(H)
|
qdel(H)
|
||||||
|
|
||||||
/obj/machinery/disposal/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
/obj/machinery/disposal/CanPass(atom/movable/mover, turf/target, height, air_group)
|
||||||
if(istype(mover, /obj/item/projectile))
|
if(istype(mover, /obj/item/projectile))
|
||||||
return 1
|
return 1
|
||||||
if (istype(mover,/obj/item) && mover.throwing)
|
if (istype(mover,/obj/item) && mover.throwing)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
var/spell/targeted/projectile/carried
|
var/spell/targeted/projectile/carried
|
||||||
|
|
||||||
penetrating = 0
|
penetrating = 0
|
||||||
kill_count = 10 //set by the duration of the spell
|
range = 10 //set by the duration of the spell
|
||||||
|
|
||||||
var/proj_trail = 0 //if it leaves a trail
|
var/proj_trail = 0 //if it leaves a trail
|
||||||
var/proj_trail_lifespan = 0 //deciseconds
|
var/proj_trail_lifespan = 0 //deciseconds
|
||||||
|
|||||||
@@ -29,12 +29,13 @@ If the spell_projectile is seeking, it will update its target every process and
|
|||||||
|
|
||||||
projectile.shot_from = user //fired from the user
|
projectile.shot_from = user //fired from the user
|
||||||
projectile.hitscan = !proj_step_delay
|
projectile.hitscan = !proj_step_delay
|
||||||
projectile.step_delay = proj_step_delay
|
projectile.speed = proj_step_delay
|
||||||
if(istype(projectile, /obj/item/projectile/spell_projectile))
|
if(istype(projectile, /obj/item/projectile/spell_projectile))
|
||||||
var/obj/item/projectile/spell_projectile/SP = projectile
|
var/obj/item/projectile/spell_projectile/SP = projectile
|
||||||
SP.carried = src //casting is magical
|
SP.carried = src //casting is magical
|
||||||
projectile.launch(target, target_zone="chest")
|
projectile.def_zone = check_zone("chest")
|
||||||
return
|
projectile.old_style_target(target)
|
||||||
|
projectile.fire()
|
||||||
|
|
||||||
/spell/targeted/projectile/proc/choose_prox_targets(mob/user = usr, var/atom/movable/spell_holder)
|
/spell/targeted/projectile/proc/choose_prox_targets(mob/user = usr, var/atom/movable/spell_holder)
|
||||||
var/list/targets = list()
|
var/list/targets = list()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
/obj/structure/table/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
/obj/structure/table/CanPass(atom/movable/mover, turf/target, height, air_group)
|
||||||
if(air_group || (height==0)) return 1
|
if(air_group || (height==0)) return 1
|
||||||
if(istype(mover,/obj/item/projectile))
|
if(istype(mover,/obj/item/projectile))
|
||||||
return (check_cover(mover,target))
|
return (check_cover(mover,target))
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
var/uy = y
|
var/uy = y
|
||||||
var/uz = z
|
var/uz = z
|
||||||
var/udir = dir
|
var/udir = dir
|
||||||
forceMove(null)
|
moveToNullspace()
|
||||||
|
|
||||||
// These modifiers are used in relation to the origin
|
// These modifiers are used in relation to the origin
|
||||||
// to place the system control panels and doors.
|
// to place the system control panels and doors.
|
||||||
|
|||||||
@@ -90,9 +90,9 @@
|
|||||||
// Probably for the best so that it doesn't harm the slime.
|
// Probably for the best so that it doesn't harm the slime.
|
||||||
taser_effect = FALSE
|
taser_effect = FALSE
|
||||||
|
|
||||||
muzzle_type = /obj/effect/projectile/laser_omni/muzzle
|
muzzle_type = /obj/effect/projectile/muzzle/laser_omni
|
||||||
tracer_type = /obj/effect/projectile/laser_omni/tracer
|
tracer_type = /obj/effect/projectile/tracer/laser_omni
|
||||||
impact_type = /obj/effect/projectile/laser_omni/impact
|
impact_type = /obj/effect/projectile/impact/laser_omni
|
||||||
|
|
||||||
/obj/item/projectile/beam/stun/xeno/weak //Weaker variant for non-research equipment, turrets, or rapid fire types.
|
/obj/item/projectile/beam/stun/xeno/weak //Weaker variant for non-research equipment, turrets, or rapid fire types.
|
||||||
agony = 3
|
agony = 3
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The initialization of the game happens roughly like this:
|
The initialization of the game happens roughly like this:
|
||||||
@@ -27,12 +28,16 @@ var/global/datum/global_init/init = new ()
|
|||||||
global.init = null
|
global.init = null
|
||||||
return 2 // QDEL_HINT_IWILLGC
|
return 2 // QDEL_HINT_IWILLGC
|
||||||
|
|
||||||
|
=======
|
||||||
|
//Global init and the rest of world's code have been moved to code/global_init.dm and code/game/world.dm respectively.
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
/world
|
/world
|
||||||
mob = /mob/new_player
|
mob = /mob/new_player
|
||||||
turf = /turf/space
|
turf = /turf/space
|
||||||
area = /area/space
|
area = /area/space
|
||||||
view = "15x15"
|
view = "15x15"
|
||||||
cache_lifespan = 7
|
cache_lifespan = 7
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -679,3 +684,5 @@ proc/establish_old_db_connection()
|
|||||||
max_z_changed()
|
max_z_changed()
|
||||||
|
|
||||||
#undef FAILED_DB_CONNECTION_CUTOFF
|
#undef FAILED_DB_CONNECTION_CUTOFF
|
||||||
|
=======
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles
|
||||||
|
|||||||
BIN
icons/obj/projectiles_impact.dmi
Normal file
BIN
icons/obj/projectiles_impact.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
icons/obj/projectiles_muzzle.dmi
Normal file
BIN
icons/obj/projectiles_muzzle.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
icons/obj/projectiles_tracer.dmi
Normal file
BIN
icons/obj/projectiles_tracer.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
@@ -16,7 +16,11 @@
|
|||||||
#include "code\_map_tests.dm"
|
#include "code\_map_tests.dm"
|
||||||
#include "code\_unit_tests.dm"
|
#include "code\_unit_tests.dm"
|
||||||
#include "code\global.dm"
|
#include "code\global.dm"
|
||||||
|
<<<<<<< HEAD:vorestation.dme
|
||||||
#include "code\global_vr.dm"
|
#include "code\global_vr.dm"
|
||||||
|
=======
|
||||||
|
#include "code\global_init.dm"
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles:polaris.dme
|
||||||
#include "code\hub.dm"
|
#include "code\hub.dm"
|
||||||
#include "code\names.dm"
|
#include "code\names.dm"
|
||||||
#include "code\stylesheet.dm"
|
#include "code\stylesheet.dm"
|
||||||
@@ -89,6 +93,7 @@
|
|||||||
#include "code\_global_vars\sensitive.dm"
|
#include "code\_global_vars\sensitive.dm"
|
||||||
#include "code\_global_vars\lists\mapping.dm"
|
#include "code\_global_vars\lists\mapping.dm"
|
||||||
#include "code\_helpers\_global_objects.dm"
|
#include "code\_helpers\_global_objects.dm"
|
||||||
|
#include "code\_helpers\_lists.dm"
|
||||||
#include "code\_helpers\atmospherics.dm"
|
#include "code\_helpers\atmospherics.dm"
|
||||||
#include "code\_helpers\events.dm"
|
#include "code\_helpers\events.dm"
|
||||||
#include "code\_helpers\files.dm"
|
#include "code\_helpers\files.dm"
|
||||||
@@ -96,8 +101,11 @@
|
|||||||
#include "code\_helpers\global_lists.dm"
|
#include "code\_helpers\global_lists.dm"
|
||||||
#include "code\_helpers\global_lists_vr.dm"
|
#include "code\_helpers\global_lists_vr.dm"
|
||||||
#include "code\_helpers\icons.dm"
|
#include "code\_helpers\icons.dm"
|
||||||
|
<<<<<<< HEAD:vorestation.dme
|
||||||
#include "code\_helpers\icons_vr.dm"
|
#include "code\_helpers\icons_vr.dm"
|
||||||
#include "code\_helpers\lists.dm"
|
#include "code\_helpers\lists.dm"
|
||||||
|
=======
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles:polaris.dme
|
||||||
#include "code\_helpers\logging.dm"
|
#include "code\_helpers\logging.dm"
|
||||||
#include "code\_helpers\logging_vr.dm"
|
#include "code\_helpers\logging_vr.dm"
|
||||||
#include "code\_helpers\matrices.dm"
|
#include "code\_helpers\matrices.dm"
|
||||||
@@ -112,8 +120,12 @@
|
|||||||
#include "code\_helpers\type2type.dm"
|
#include "code\_helpers\type2type.dm"
|
||||||
#include "code\_helpers\type2type_vr.dm"
|
#include "code\_helpers\type2type_vr.dm"
|
||||||
#include "code\_helpers\unsorted.dm"
|
#include "code\_helpers\unsorted.dm"
|
||||||
|
<<<<<<< HEAD:vorestation.dme
|
||||||
#include "code\_helpers\unsorted_vr.dm"
|
#include "code\_helpers\unsorted_vr.dm"
|
||||||
#include "code\_helpers\vector.dm"
|
#include "code\_helpers\vector.dm"
|
||||||
|
=======
|
||||||
|
#include "code\_helpers\view.dm"
|
||||||
|
>>>>>>> 9ff8103... Merge pull request #5636 from kevinz000/pixel_projectiles:polaris.dme
|
||||||
#include "code\_helpers\sorts\__main.dm"
|
#include "code\_helpers\sorts\__main.dm"
|
||||||
#include "code\_helpers\sorts\comparators.dm"
|
#include "code\_helpers\sorts\comparators.dm"
|
||||||
#include "code\_helpers\sorts\TimSort.dm"
|
#include "code\_helpers\sorts\TimSort.dm"
|
||||||
@@ -241,6 +253,7 @@
|
|||||||
#include "code\controllers\subsystems\processing\fastprocess.dm"
|
#include "code\controllers\subsystems\processing\fastprocess.dm"
|
||||||
#include "code\controllers\subsystems\processing\obj.dm"
|
#include "code\controllers\subsystems\processing\obj.dm"
|
||||||
#include "code\controllers\subsystems\processing\processing.dm"
|
#include "code\controllers\subsystems\processing\processing.dm"
|
||||||
|
#include "code\controllers\subsystems\processing\projectiles.dm"
|
||||||
#include "code\controllers\subsystems\processing\turfs.dm"
|
#include "code\controllers\subsystems\processing\turfs.dm"
|
||||||
#include "code\datums\ai_law_sets.dm"
|
#include "code\datums\ai_law_sets.dm"
|
||||||
#include "code\datums\ai_laws.dm"
|
#include "code\datums\ai_laws.dm"
|
||||||
@@ -261,6 +274,7 @@
|
|||||||
#include "code\datums\mutable_appearance.dm"
|
#include "code\datums\mutable_appearance.dm"
|
||||||
#include "code\datums\orbit.dm"
|
#include "code\datums\orbit.dm"
|
||||||
#include "code\datums\organs.dm"
|
#include "code\datums\organs.dm"
|
||||||
|
#include "code\datums\position_point_vector.dm"
|
||||||
#include "code\datums\progressbar.dm"
|
#include "code\datums\progressbar.dm"
|
||||||
#include "code\datums\recipe.dm"
|
#include "code\datums\recipe.dm"
|
||||||
#include "code\datums\riding.dm"
|
#include "code\datums\riding.dm"
|
||||||
@@ -430,6 +444,7 @@
|
|||||||
#include "code\game\skincmd.dm"
|
#include "code\game\skincmd.dm"
|
||||||
#include "code\game\sound.dm"
|
#include "code\game\sound.dm"
|
||||||
#include "code\game\trader_visit.dm"
|
#include "code\game\trader_visit.dm"
|
||||||
|
#include "code\game\world.dm"
|
||||||
#include "code\game\antagonist\_antagonist_setup.dm"
|
#include "code\game\antagonist\_antagonist_setup.dm"
|
||||||
#include "code\game\antagonist\antagonist.dm"
|
#include "code\game\antagonist\antagonist.dm"
|
||||||
#include "code\game\antagonist\antagonist_add.dm"
|
#include "code\game\antagonist\antagonist_add.dm"
|
||||||
@@ -943,7 +958,11 @@
|
|||||||
#include "code\game\objects\effects\spawners\bombspawner.dm"
|
#include "code\game\objects\effects\spawners\bombspawner.dm"
|
||||||
#include "code\game\objects\effects\spawners\gibspawner.dm"
|
#include "code\game\objects\effects\spawners\gibspawner.dm"
|
||||||
#include "code\game\objects\effects\temporary_visuals\miscellaneous.dm"
|
#include "code\game\objects\effects\temporary_visuals\miscellaneous.dm"
|
||||||
#include "code\game\objects\effects\temporary_visuals\temproary_visual.dm"
|
#include "code\game\objects\effects\temporary_visuals\temporary_visual.dm"
|
||||||
|
#include "code\game\objects\effects\temporary_visuals\projectiles\impact.dm"
|
||||||
|
#include "code\game\objects\effects\temporary_visuals\projectiles\muzzle.dm"
|
||||||
|
#include "code\game\objects\effects\temporary_visuals\projectiles\projectile_effects.dm"
|
||||||
|
#include "code\game\objects\effects\temporary_visuals\projectiles\tracer.dm"
|
||||||
#include "code\game\objects\items\antag_spawners.dm"
|
#include "code\game\objects\items\antag_spawners.dm"
|
||||||
#include "code\game\objects\items\apc_frame.dm"
|
#include "code\game\objects\items\apc_frame.dm"
|
||||||
#include "code\game\objects\items\blueprints.dm"
|
#include "code\game\objects\items\blueprints.dm"
|
||||||
@@ -2595,7 +2614,6 @@
|
|||||||
#include "code\modules\power\tesla\tesla_act.dm"
|
#include "code\modules\power\tesla\tesla_act.dm"
|
||||||
#include "code\modules\projectiles\ammunition.dm"
|
#include "code\modules\projectiles\ammunition.dm"
|
||||||
#include "code\modules\projectiles\dnalocking.dm"
|
#include "code\modules\projectiles\dnalocking.dm"
|
||||||
#include "code\modules\projectiles\effects.dm"
|
|
||||||
#include "code\modules\projectiles\gun.dm"
|
#include "code\modules\projectiles\gun.dm"
|
||||||
#include "code\modules\projectiles\projectile.dm"
|
#include "code\modules\projectiles\projectile.dm"
|
||||||
#include "code\modules\projectiles\ammunition\magazines.dm"
|
#include "code\modules\projectiles\ammunition\magazines.dm"
|
||||||
@@ -2657,6 +2675,7 @@
|
|||||||
#include "code\modules\projectiles\projectile\magnetic.dm"
|
#include "code\modules\projectiles\projectile\magnetic.dm"
|
||||||
#include "code\modules\projectiles\projectile\pellets.dm"
|
#include "code\modules\projectiles\projectile\pellets.dm"
|
||||||
#include "code\modules\projectiles\projectile\special.dm"
|
#include "code\modules\projectiles\projectile\special.dm"
|
||||||
|
#include "code\modules\projectiles\projectile\trace.dm"
|
||||||
#include "code\modules\projectiles\targeting\targeting_client.dm"
|
#include "code\modules\projectiles\targeting\targeting_client.dm"
|
||||||
#include "code\modules\projectiles\targeting\targeting_gun.dm"
|
#include "code\modules\projectiles\targeting\targeting_gun.dm"
|
||||||
#include "code\modules\projectiles\targeting\targeting_mob.dm"
|
#include "code\modules\projectiles\targeting\targeting_mob.dm"
|
||||||
|
|||||||
Reference in New Issue
Block a user