Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into upstream-merge-27503
@@ -1142,6 +1142,10 @@
|
||||
/obj/effect/turf_decal/bot{
|
||||
dir = 2
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 1;
|
||||
layer = 2.9
|
||||
},
|
||||
/turf/open/floor/plasteel{
|
||||
dir = 2
|
||||
},
|
||||
@@ -1338,6 +1342,13 @@
|
||||
/obj/effect/turf_decal/bot{
|
||||
dir = 2
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 1;
|
||||
layer = 2.9
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 4
|
||||
},
|
||||
/turf/open/floor/plasteel{
|
||||
dir = 2
|
||||
},
|
||||
@@ -1356,6 +1367,13 @@
|
||||
/obj/effect/turf_decal/bot{
|
||||
dir = 2
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 1;
|
||||
layer = 2.9
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 8
|
||||
},
|
||||
/turf/open/floor/plasteel{
|
||||
dir = 2
|
||||
},
|
||||
@@ -53772,6 +53790,10 @@
|
||||
/obj/effect/turf_decal/bot{
|
||||
dir = 2
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 1;
|
||||
layer = 2.9
|
||||
},
|
||||
/turf/open/floor/plasteel{
|
||||
dir = 2
|
||||
},
|
||||
@@ -112232,11 +112254,11 @@ btp
|
||||
cbv
|
||||
ccq
|
||||
bns
|
||||
cjD
|
||||
cjD
|
||||
cjD
|
||||
cjD
|
||||
cnj
|
||||
aof
|
||||
aof
|
||||
aof
|
||||
aof
|
||||
amw
|
||||
aaa
|
||||
aaa
|
||||
aaa
|
||||
@@ -112489,13 +112511,13 @@ ckS
|
||||
bky
|
||||
ccq
|
||||
cds
|
||||
cjD
|
||||
aof
|
||||
ckt
|
||||
cly
|
||||
cmw
|
||||
cnj
|
||||
cnj
|
||||
cnj
|
||||
amw
|
||||
amw
|
||||
amw
|
||||
aaa
|
||||
aaa
|
||||
aaf
|
||||
@@ -113003,13 +113025,13 @@ cbg
|
||||
bTr
|
||||
cct
|
||||
cdu
|
||||
cjG
|
||||
aqx
|
||||
cku
|
||||
clz
|
||||
cmx
|
||||
cnj
|
||||
cnj
|
||||
cnj
|
||||
amw
|
||||
amw
|
||||
amw
|
||||
aaa
|
||||
aaa
|
||||
aaf
|
||||
@@ -113260,11 +113282,11 @@ bky
|
||||
bky
|
||||
bky
|
||||
bky
|
||||
cjD
|
||||
cjD
|
||||
cjD
|
||||
cjD
|
||||
cnj
|
||||
aof
|
||||
aof
|
||||
aof
|
||||
aof
|
||||
amw
|
||||
aaa
|
||||
aaa
|
||||
aaa
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#define MC_TICK_CHECK ( ( world.tick_usage > GLOB.CURRENT_TICKLIMIT || src.state != SS_RUNNING ) ? pause() : 0 )
|
||||
#define MC_TICK_CHECK ( ( world.tick_usage > Master.current_ticklimit || src.state != SS_RUNNING ) ? pause() : 0 )
|
||||
|
||||
#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = GLOB.CURRENT_TICKLIMIT; var/split_tick_phases = ##phase_count
|
||||
#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = Master.current_ticklimit; var/split_tick_phases = ##phase_count
|
||||
#define MC_SPLIT_TICK \
|
||||
if(split_tick_phases > 1){\
|
||||
GLOB.CURRENT_TICKLIMIT = ((original_tick_limit - world.tick_usage) / split_tick_phases) + world.tick_usage;\
|
||||
Master.current_ticklimit = ((original_tick_limit - world.tick_usage) / split_tick_phases) + world.tick_usage;\
|
||||
--split_tick_phases;\
|
||||
} else {\
|
||||
GLOB.CURRENT_TICKLIMIT = original_tick_limit;\
|
||||
Master.current_ticklimit = original_tick_limit;\
|
||||
}
|
||||
|
||||
// Used to smooth out costs to try and avoid oscillation.
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
#define TICK_LIMIT_MC 70
|
||||
#define TICK_LIMIT_MC_INIT_DEFAULT 98
|
||||
|
||||
#define TICK_CHECK ( world.tick_usage > GLOB.CURRENT_TICKLIMIT )
|
||||
#define TICK_CHECK ( world.tick_usage > Master.current_ticklimit )
|
||||
#define CHECK_TICK if TICK_CHECK stoplag()
|
||||
|
||||
@@ -626,14 +626,13 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sortInstance, new())
|
||||
var/val2 = fetchElement(L,cursor2)
|
||||
|
||||
while(1)
|
||||
if(call(cmp)(val1,val2) < 0)
|
||||
if(call(cmp)(val1,val2) <= 0)
|
||||
if(++cursor1 >= end1)
|
||||
break
|
||||
val1 = fetchElement(L,cursor1)
|
||||
else
|
||||
moveElement(L,cursor2,cursor1)
|
||||
|
||||
++cursor2
|
||||
if(++cursor2 >= end2)
|
||||
break
|
||||
++end1
|
||||
@@ -653,4 +652,4 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sortInstance, new())
|
||||
#undef MIN_GALLOP
|
||||
#undef MIN_MERGE
|
||||
|
||||
#undef fetchElement
|
||||
#undef fetchElement
|
||||
|
||||
@@ -1215,7 +1215,7 @@ proc/pick_closest_path(value, list/matches = get_fancy_list_of_atom_types())
|
||||
. += round(i*DELTA_CALC)
|
||||
sleep(i*world.tick_lag*DELTA_CALC)
|
||||
i *= 2
|
||||
while (world.tick_usage > min(TICK_LIMIT_TO_RUN, GLOB.CURRENT_TICKLIMIT))
|
||||
while (world.tick_usage > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit))
|
||||
|
||||
#undef DELTA_CALC
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
selected_target[1] = null
|
||||
|
||||
/client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
|
||||
if(selected_target[1] && over_object.IsAutoclickable())
|
||||
if(selected_target[1] && over_object && over_object.IsAutoclickable())
|
||||
selected_target[1] = over_object
|
||||
selected_target[2] = params
|
||||
|
||||
|
||||
@@ -1,467 +1,469 @@
|
||||
/*
|
||||
Click code cleanup
|
||||
~Sayu
|
||||
*/
|
||||
|
||||
// 1 decisecond click delay (above and beyond mob/next_move)
|
||||
//This is mainly modified by click code, to modify click delays elsewhere, use next_move and changeNext_move()
|
||||
/mob/var/next_click = 0
|
||||
|
||||
// THESE DO NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
|
||||
/mob/var/next_move_adjust = 0 //Amount to adjust action/click delays by, + or -
|
||||
/mob/var/next_move_modifier = 1 //Value to multiply action/click delays by
|
||||
|
||||
|
||||
//Delays the mob's next click/action by num deciseconds
|
||||
// eg: 10-3 = 7 deciseconds of delay
|
||||
// eg: 10*0.5 = 5 deciseconds of delay
|
||||
// DOES NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
|
||||
|
||||
/mob/proc/changeNext_move(num)
|
||||
next_move = world.time + ((num+next_move_adjust)*next_move_modifier)
|
||||
|
||||
|
||||
/*
|
||||
Before anything else, defer these calls to a per-mobtype handler. This allows us to
|
||||
remove istype() spaghetti code, but requires the addition of other handler procs to simplify it.
|
||||
|
||||
Alternately, you could hardcode every mob's variation in a flat ClickOn() proc; however,
|
||||
that's a lot of code duplication and is hard to maintain.
|
||||
|
||||
Note that this proc can be overridden, and is in the case of screen objects.
|
||||
*/
|
||||
/atom/Click(location,control,params)
|
||||
if(initialized)
|
||||
usr.ClickOn(src, params)
|
||||
|
||||
/atom/DblClick(location,control,params)
|
||||
if(initialized)
|
||||
usr.DblClickOn(src,params)
|
||||
|
||||
/atom/MouseWheel(delta_x,delta_y,location,control,params)
|
||||
if(initialized)
|
||||
usr.MouseWheelOn(src, delta_x, delta_y, params)
|
||||
|
||||
/*
|
||||
Standard mob ClickOn()
|
||||
Handles exceptions: Buildmode, middle click, modified clicks, mech actions
|
||||
|
||||
After that, mostly just check your state, check whether you're holding an item,
|
||||
check whether you're adjacent to the target, then pass off the click to whoever
|
||||
is recieving it.
|
||||
The most common are:
|
||||
* mob/UnarmedAttack(atom,adjacent) - used here only when adjacent, with no item in hand; in the case of humans, checks gloves
|
||||
* atom/attackby(item,user) - used only when adjacent
|
||||
* item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent
|
||||
* mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed
|
||||
*/
|
||||
/mob/proc/ClickOn( atom/A, params )
|
||||
if(world.time <= next_click)
|
||||
return
|
||||
next_click = world.time + 1
|
||||
|
||||
if(client && client.click_intercept)
|
||||
if(call(client.click_intercept, "InterceptClickOn")(src, params, A))
|
||||
return
|
||||
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["shift"] && modifiers["middle"])
|
||||
ShiftMiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"] && modifiers["ctrl"])
|
||||
CtrlShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["middle"])
|
||||
MiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"])
|
||||
ShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["alt"]) // alt and alt-gr (rightalt)
|
||||
AltClickOn(A)
|
||||
return
|
||||
if(modifiers["ctrl"])
|
||||
CtrlClickOn(A)
|
||||
return
|
||||
|
||||
if(incapacitated(ignore_restraints = 1))
|
||||
return
|
||||
|
||||
face_atom(A)
|
||||
|
||||
if(next_move > world.time) // in the year 2000...
|
||||
return
|
||||
|
||||
if(A.IsObscured())
|
||||
return
|
||||
|
||||
if(istype(loc,/obj/mecha))
|
||||
var/obj/mecha/M = loc
|
||||
return M.click_action(A,src,params)
|
||||
|
||||
if(restrained())
|
||||
changeNext_move(CLICK_CD_HANDCUFFED) //Doing shit in cuffs shall be vey slow
|
||||
RestrainedClickOn(A)
|
||||
return
|
||||
|
||||
if(in_throw_mode)
|
||||
throw_item(A)
|
||||
return
|
||||
|
||||
var/obj/item/W = get_active_held_item()
|
||||
|
||||
if(W == A)
|
||||
W.attack_self(src)
|
||||
update_inv_hands()
|
||||
return
|
||||
|
||||
//These are always reachable.
|
||||
//User itself, current loc, and user inventory
|
||||
if(DirectAccess(A))
|
||||
if(W)
|
||||
melee_item_attack_chain(src,W,A,params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A)
|
||||
return
|
||||
|
||||
//Can't reach anything else in lockers or other weirdness
|
||||
if(!loc.AllowClick())
|
||||
return
|
||||
|
||||
//Standard reach turf to turf or reaching inside storage
|
||||
if(CanReach(A,W))
|
||||
if(W)
|
||||
melee_item_attack_chain(src,W,A,params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A,1)
|
||||
else
|
||||
if(W)
|
||||
W.afterattack(A,src,0,params)
|
||||
else
|
||||
RangedAttack(A,params)
|
||||
|
||||
//Is the atom obscured by a PREVENT_CLICK_UNDER object above it
|
||||
/atom/proc/IsObscured()
|
||||
if(!isturf(loc)) //This only makes sense for things directly on turfs for now
|
||||
return FALSE
|
||||
var/turf/T = get_turf_pixel(src)
|
||||
if(!T)
|
||||
return FALSE
|
||||
for(var/atom/movable/AM in T)
|
||||
if(AM.flags & PREVENT_CLICK_UNDER && AM.density && AM.layer > layer)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/turf/IsObscured()
|
||||
for(var/atom/movable/AM in src)
|
||||
if(AM.flags & PREVENT_CLICK_UNDER && AM.density)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/atom/movable/proc/CanReach(atom/target,obj/item/tool,view_only = FALSE)
|
||||
if(isturf(target) || isturf(target.loc) || DirectAccess(target)) //Directly accessible atoms
|
||||
if(Adjacent(target) || (tool && CheckToolReach(src, target, tool.reach))) //Adjacent or reaching attacks
|
||||
return TRUE
|
||||
else
|
||||
//Things inside storage insde another storage
|
||||
//Eg Contents of a box in a backpack
|
||||
var/atom/outer_storage = get_atom_on_turf(target)
|
||||
if(outer_storage == target) //whatever that is we don't want infinite loop.
|
||||
return FALSE
|
||||
if(outer_storage && CanReach(outer_storage,tool) && outer_storage.CanReachStorage(target,src,view_only ? STORAGE_VIEW_DEPTH : INVENTORY_DEPTH))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//Can [target] in this container be reached by [user], can't be more than [depth] levels deep
|
||||
/atom/proc/CanReachStorage(atom/target,user,depth)
|
||||
return FALSE
|
||||
|
||||
/obj/item/weapon/storage/CanReachStorage(atom/target,user,depth)
|
||||
while(target && depth > 0)
|
||||
target = target.loc
|
||||
depth--
|
||||
if(target == src)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/atom/movable/proc/DirectAccess(atom/target)
|
||||
if(target == src)
|
||||
return TRUE
|
||||
if(target == loc)
|
||||
return TRUE
|
||||
|
||||
/mob/DirectAccess(atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
if(target in contents) //This could probably use moving down and restricting to inventory only
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/DirectAccess(atom/target)
|
||||
if(..()) //Lightweight checks first
|
||||
return TRUE
|
||||
if(target in GetAllContents())
|
||||
return TRUE
|
||||
|
||||
/atom/proc/AllowClick()
|
||||
return FALSE
|
||||
|
||||
/turf/AllowClick()
|
||||
return TRUE
|
||||
|
||||
/proc/CheckToolReach(atom/movable/here, atom/movable/there, reach)
|
||||
if(!here || !there)
|
||||
return
|
||||
switch(reach)
|
||||
if(0)
|
||||
return FALSE
|
||||
if(1)
|
||||
return FALSE //here.Adjacent(there)
|
||||
if(2 to INFINITY)
|
||||
var/obj/dummy = new(get_turf(here))
|
||||
dummy.pass_flags |= PASSTABLE
|
||||
dummy.invisibility = INVISIBILITY_ABSTRACT
|
||||
for(var/i in 1 to reach) //Limit it to that many tries
|
||||
var/turf/T = get_step(dummy, get_dir(dummy, there))
|
||||
if(dummy.CanReach(there))
|
||||
qdel(dummy)
|
||||
return TRUE
|
||||
if(!dummy.Move(T)) //we're blocked!
|
||||
qdel(dummy)
|
||||
return
|
||||
qdel(dummy)
|
||||
|
||||
// Default behavior: ignore double clicks (the second click that makes the doubleclick call already calls for a normal click)
|
||||
/mob/proc/DblClickOn(atom/A, params)
|
||||
return
|
||||
|
||||
|
||||
/*
|
||||
Translates into attack_hand, etc.
|
||||
|
||||
Note: proximity_flag here is used to distinguish between normal usage (flag=1),
|
||||
and usage when clicking on things telekinetically (flag=0). This proc will
|
||||
not be called at ranged except with telekinesis.
|
||||
|
||||
proximity_flag is not currently passed to attack_hand, and is instead used
|
||||
in human click code to allow glove touches only at melee range.
|
||||
*/
|
||||
/mob/proc/UnarmedAttack(atom/A, proximity_flag)
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
return
|
||||
|
||||
/*
|
||||
Ranged unarmed attack:
|
||||
|
||||
This currently is just a default for all mobs, involving
|
||||
laser eyes and telekinesis. You could easily add exceptions
|
||||
for things like ranged glove touches, spitting alien acid/neurotoxin,
|
||||
animals lunging, etc.
|
||||
*/
|
||||
/mob/proc/RangedAttack(atom/A, params)
|
||||
/*
|
||||
Restrained ClickOn
|
||||
|
||||
Used when you are handcuffed and click things.
|
||||
Not currently used by anything but could easily be.
|
||||
*/
|
||||
/mob/proc/RestrainedClickOn(atom/A)
|
||||
return
|
||||
|
||||
/*
|
||||
Middle click
|
||||
Only used for swapping hands
|
||||
*/
|
||||
/mob/proc/MiddleClickOn(atom/A)
|
||||
return
|
||||
|
||||
/mob/living/carbon/MiddleClickOn(atom/A)
|
||||
if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src))
|
||||
next_click = world.time + 5
|
||||
mind.changeling.chosen_sting.try_to_sting(src, A)
|
||||
else
|
||||
swap_hand()
|
||||
|
||||
/mob/living/simple_animal/drone/MiddleClickOn(atom/A)
|
||||
swap_hand()
|
||||
|
||||
// In case of use break glass
|
||||
/*
|
||||
/atom/proc/MiddleClick(mob/M as mob)
|
||||
return
|
||||
*/
|
||||
|
||||
/*
|
||||
Shift click
|
||||
For most mobs, examine.
|
||||
This is overridden in ai.dm
|
||||
*/
|
||||
/mob/proc/ShiftClickOn(atom/A)
|
||||
A.ShiftClick(src)
|
||||
return
|
||||
/atom/proc/ShiftClick(mob/user)
|
||||
if(user.client && user.client.eye == user || user.client.eye == user.loc)
|
||||
user.examinate(src)
|
||||
return
|
||||
|
||||
/*
|
||||
Ctrl click
|
||||
For most objects, pull
|
||||
*/
|
||||
|
||||
/mob/proc/CtrlClickOn(atom/A)
|
||||
A.CtrlClick(src)
|
||||
return
|
||||
|
||||
/atom/proc/CtrlClick(mob/user)
|
||||
var/mob/living/ML = user
|
||||
if(istype(ML))
|
||||
ML.pulled(src)
|
||||
|
||||
/mob/living/carbon/human/CtrlClick(mob/user)
|
||||
if(ishuman(user) && Adjacent(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.dna.species.grab(H, src, H.martial_art)
|
||||
H.next_click = world.time + CLICK_CD_MELEE
|
||||
else
|
||||
..()
|
||||
/*
|
||||
Alt click
|
||||
Unused except for AI
|
||||
*/
|
||||
/mob/proc/AltClickOn(atom/A)
|
||||
A.AltClick(src)
|
||||
return
|
||||
|
||||
/mob/living/carbon/AltClickOn(atom/A)
|
||||
if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src))
|
||||
next_click = world.time + 5
|
||||
mind.changeling.chosen_sting.try_to_sting(src, A)
|
||||
else
|
||||
..()
|
||||
|
||||
/atom/proc/AltClick(mob/user)
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && user.TurfAdjacent(T))
|
||||
if(user.listed_turf == T)
|
||||
user.listed_turf = null
|
||||
else
|
||||
user.listed_turf = T
|
||||
user.client.statpanel = T.name
|
||||
return
|
||||
|
||||
/mob/proc/TurfAdjacent(turf/T)
|
||||
return T.Adjacent(src)
|
||||
|
||||
/*
|
||||
Control+Shift click
|
||||
Unused except for AI
|
||||
*/
|
||||
/mob/proc/CtrlShiftClickOn(atom/A)
|
||||
A.CtrlShiftClick(src)
|
||||
return
|
||||
|
||||
/mob/proc/ShiftMiddleClickOn(atom/A)
|
||||
src.pointed(A)
|
||||
return
|
||||
|
||||
/atom/proc/CtrlShiftClick(mob/user)
|
||||
return
|
||||
|
||||
/*
|
||||
Misc helpers
|
||||
|
||||
Laser Eyes: as the name implies, handles this since nothing else does currently
|
||||
face_atom: turns the mob towards what you clicked on
|
||||
*/
|
||||
/mob/proc/LaserEyes(atom/A)
|
||||
return
|
||||
|
||||
/mob/living/LaserEyes(atom/A)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
var/turf/T = get_turf(src)
|
||||
var/turf/U = get_turf(A)
|
||||
|
||||
var/obj/item/projectile/beam/LE = new /obj/item/projectile/beam( loc )
|
||||
LE.icon = 'icons/effects/genetics.dmi'
|
||||
LE.icon_state = "eyelasers"
|
||||
playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
|
||||
|
||||
LE.firer = src
|
||||
LE.def_zone = get_organ_target()
|
||||
LE.original = A
|
||||
LE.current = T
|
||||
LE.yo = U.y - T.y
|
||||
LE.xo = U.x - T.x
|
||||
LE.fire()
|
||||
|
||||
// Simple helper to face what you clicked on, in case it should be needed in more than one place
|
||||
/mob/proc/face_atom(atom/A)
|
||||
if( buckled || stat != CONSCIOUS || !A || !x || !y || !A.x || !A.y )
|
||||
return
|
||||
var/dx = A.x - x
|
||||
var/dy = A.y - y
|
||||
if(!dx && !dy) // Wall items are graphically shifted but on the floor
|
||||
if(A.pixel_y > 16)
|
||||
setDir(NORTH)
|
||||
else if(A.pixel_y < -16)
|
||||
setDir(SOUTH)
|
||||
else if(A.pixel_x > 16)
|
||||
setDir(EAST)
|
||||
else if(A.pixel_x < -16)
|
||||
setDir(WEST)
|
||||
return
|
||||
|
||||
if(abs(dx) < abs(dy))
|
||||
if(dy > 0)
|
||||
setDir(NORTH)
|
||||
else
|
||||
setDir(SOUTH)
|
||||
else
|
||||
if(dx > 0)
|
||||
setDir(EAST)
|
||||
else
|
||||
setDir(WEST)
|
||||
|
||||
/obj/screen/click_catcher
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "click_catcher"
|
||||
plane = CLICKCATCHER_PLANE
|
||||
mouse_opacity = 2
|
||||
screen_loc = "CENTER"
|
||||
|
||||
/obj/screen/click_catcher/New()
|
||||
..()
|
||||
transform = matrix(200, 0, 0, 0, 200, 0)
|
||||
|
||||
/obj/screen/click_catcher/Click(location, control, params)
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["middle"] && istype(usr, /mob/living/carbon))
|
||||
var/mob/living/carbon/C = usr
|
||||
C.swap_hand()
|
||||
else
|
||||
var/turf/T = params2turf(modifiers["screen-loc"], get_turf(usr))
|
||||
if(T)
|
||||
T.Click(location, control, params)
|
||||
. = 1
|
||||
|
||||
|
||||
/* MouseWheelOn */
|
||||
|
||||
/mob/proc/MouseWheelOn(atom/A, delta_x, delta_y, params)
|
||||
return
|
||||
|
||||
/mob/dead/observer/MouseWheelOn(atom/A, delta_x, delta_y, params)
|
||||
var/list/modifier = params2list(params)
|
||||
if(modifier["shift"])
|
||||
var/view = 0
|
||||
if(delta_y > 0)
|
||||
view = -1
|
||||
else
|
||||
view = 1
|
||||
add_view_range(view)
|
||||
/*
|
||||
Click code cleanup
|
||||
~Sayu
|
||||
*/
|
||||
|
||||
// 1 decisecond click delay (above and beyond mob/next_move)
|
||||
//This is mainly modified by click code, to modify click delays elsewhere, use next_move and changeNext_move()
|
||||
/mob/var/next_click = 0
|
||||
|
||||
// THESE DO NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
|
||||
/mob/var/next_move_adjust = 0 //Amount to adjust action/click delays by, + or -
|
||||
/mob/var/next_move_modifier = 1 //Value to multiply action/click delays by
|
||||
|
||||
|
||||
//Delays the mob's next click/action by num deciseconds
|
||||
// eg: 10-3 = 7 deciseconds of delay
|
||||
// eg: 10*0.5 = 5 deciseconds of delay
|
||||
// DOES NOT EFFECT THE BASE 1 DECISECOND DELAY OF NEXT_CLICK
|
||||
|
||||
/mob/proc/changeNext_move(num)
|
||||
next_move = world.time + ((num+next_move_adjust)*next_move_modifier)
|
||||
|
||||
|
||||
/*
|
||||
Before anything else, defer these calls to a per-mobtype handler. This allows us to
|
||||
remove istype() spaghetti code, but requires the addition of other handler procs to simplify it.
|
||||
|
||||
Alternately, you could hardcode every mob's variation in a flat ClickOn() proc; however,
|
||||
that's a lot of code duplication and is hard to maintain.
|
||||
|
||||
Note that this proc can be overridden, and is in the case of screen objects.
|
||||
*/
|
||||
/atom/Click(location,control,params)
|
||||
if(initialized)
|
||||
usr.ClickOn(src, params)
|
||||
|
||||
/atom/DblClick(location,control,params)
|
||||
if(initialized)
|
||||
usr.DblClickOn(src,params)
|
||||
|
||||
/atom/MouseWheel(delta_x,delta_y,location,control,params)
|
||||
if(initialized)
|
||||
usr.MouseWheelOn(src, delta_x, delta_y, params)
|
||||
|
||||
/*
|
||||
Standard mob ClickOn()
|
||||
Handles exceptions: Buildmode, middle click, modified clicks, mech actions
|
||||
|
||||
After that, mostly just check your state, check whether you're holding an item,
|
||||
check whether you're adjacent to the target, then pass off the click to whoever
|
||||
is recieving it.
|
||||
The most common are:
|
||||
* mob/UnarmedAttack(atom,adjacent) - used here only when adjacent, with no item in hand; in the case of humans, checks gloves
|
||||
* atom/attackby(item,user) - used only when adjacent
|
||||
* item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent
|
||||
* mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed
|
||||
*/
|
||||
/mob/proc/ClickOn( atom/A, params )
|
||||
if(world.time <= next_click)
|
||||
return
|
||||
next_click = world.time + 1
|
||||
|
||||
if(client && client.click_intercept)
|
||||
if(call(client.click_intercept, "InterceptClickOn")(src, params, A))
|
||||
return
|
||||
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["shift"] && modifiers["middle"])
|
||||
ShiftMiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"] && modifiers["ctrl"])
|
||||
CtrlShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["middle"])
|
||||
MiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"])
|
||||
ShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["alt"]) // alt and alt-gr (rightalt)
|
||||
AltClickOn(A)
|
||||
return
|
||||
if(modifiers["ctrl"])
|
||||
CtrlClickOn(A)
|
||||
return
|
||||
|
||||
if(incapacitated(ignore_restraints = 1))
|
||||
return
|
||||
|
||||
face_atom(A)
|
||||
|
||||
if(next_move > world.time) // in the year 2000...
|
||||
return
|
||||
|
||||
if(A.IsObscured())
|
||||
return
|
||||
|
||||
if(istype(loc,/obj/mecha))
|
||||
var/obj/mecha/M = loc
|
||||
return M.click_action(A,src,params)
|
||||
|
||||
if(restrained())
|
||||
changeNext_move(CLICK_CD_HANDCUFFED) //Doing shit in cuffs shall be vey slow
|
||||
RestrainedClickOn(A)
|
||||
return
|
||||
|
||||
if(in_throw_mode)
|
||||
throw_item(A)
|
||||
return
|
||||
|
||||
var/obj/item/W = get_active_held_item()
|
||||
|
||||
if(W == A)
|
||||
W.attack_self(src)
|
||||
update_inv_hands()
|
||||
return
|
||||
|
||||
//These are always reachable.
|
||||
//User itself, current loc, and user inventory
|
||||
if(DirectAccess(A))
|
||||
if(W)
|
||||
melee_item_attack_chain(src,W,A,params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A)
|
||||
return
|
||||
|
||||
//Can't reach anything else in lockers or other weirdness
|
||||
if(!loc.AllowClick())
|
||||
return
|
||||
|
||||
//Standard reach turf to turf or reaching inside storage
|
||||
if(CanReach(A,W))
|
||||
if(W)
|
||||
melee_item_attack_chain(src,W,A,params)
|
||||
else
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
UnarmedAttack(A,1)
|
||||
else
|
||||
if(W)
|
||||
W.afterattack(A,src,0,params)
|
||||
else
|
||||
RangedAttack(A,params)
|
||||
|
||||
//Is the atom obscured by a PREVENT_CLICK_UNDER object above it
|
||||
/atom/proc/IsObscured()
|
||||
if(!isturf(loc)) //This only makes sense for things directly on turfs for now
|
||||
return FALSE
|
||||
var/turf/T = get_turf_pixel(src)
|
||||
if(!T)
|
||||
return FALSE
|
||||
for(var/atom/movable/AM in T)
|
||||
if(AM.flags & PREVENT_CLICK_UNDER && AM.density && AM.layer > layer)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/turf/IsObscured()
|
||||
for(var/atom/movable/AM in src)
|
||||
if(AM.flags & PREVENT_CLICK_UNDER && AM.density)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/atom/movable/proc/CanReach(atom/target,obj/item/tool,view_only = FALSE)
|
||||
if(isturf(target) || isturf(target.loc) || DirectAccess(target)) //Directly accessible atoms
|
||||
if(Adjacent(target) || (tool && CheckToolReach(src, target, tool.reach))) //Adjacent or reaching attacks
|
||||
return TRUE
|
||||
else
|
||||
//Things inside storage insde another storage
|
||||
//Eg Contents of a box in a backpack
|
||||
var/atom/outer_storage = get_atom_on_turf(target)
|
||||
if(outer_storage == target) //whatever that is we don't want infinite loop.
|
||||
return FALSE
|
||||
if(outer_storage && CanReach(outer_storage,tool) && outer_storage.CanReachStorage(target,src,view_only ? STORAGE_VIEW_DEPTH : INVENTORY_DEPTH))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//Can [target] in this container be reached by [user], can't be more than [depth] levels deep
|
||||
/atom/proc/CanReachStorage(atom/target,user,depth)
|
||||
return FALSE
|
||||
|
||||
/obj/item/weapon/storage/CanReachStorage(atom/target,user,depth)
|
||||
while(target && depth > 0)
|
||||
target = target.loc
|
||||
depth--
|
||||
if(target == src)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/atom/movable/proc/DirectAccess(atom/target)
|
||||
if(target == src)
|
||||
return TRUE
|
||||
if(target == loc)
|
||||
return TRUE
|
||||
|
||||
/mob/DirectAccess(atom/target)
|
||||
if(..())
|
||||
return TRUE
|
||||
if(target in contents) //This could probably use moving down and restricting to inventory only
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/DirectAccess(atom/target)
|
||||
if(..()) //Lightweight checks first
|
||||
return TRUE
|
||||
if(target in GetAllContents())
|
||||
return TRUE
|
||||
|
||||
/atom/proc/AllowClick()
|
||||
return FALSE
|
||||
|
||||
/turf/AllowClick()
|
||||
return TRUE
|
||||
|
||||
/proc/CheckToolReach(atom/movable/here, atom/movable/there, reach)
|
||||
if(!here || !there)
|
||||
return
|
||||
switch(reach)
|
||||
if(0)
|
||||
return FALSE
|
||||
if(1)
|
||||
return FALSE //here.Adjacent(there)
|
||||
if(2 to INFINITY)
|
||||
var/obj/dummy = new(get_turf(here))
|
||||
dummy.pass_flags |= PASSTABLE
|
||||
dummy.invisibility = INVISIBILITY_ABSTRACT
|
||||
for(var/i in 1 to reach) //Limit it to that many tries
|
||||
var/turf/T = get_step(dummy, get_dir(dummy, there))
|
||||
if(dummy.CanReach(there))
|
||||
qdel(dummy)
|
||||
return TRUE
|
||||
if(!dummy.Move(T)) //we're blocked!
|
||||
qdel(dummy)
|
||||
return
|
||||
qdel(dummy)
|
||||
|
||||
// Default behavior: ignore double clicks (the second click that makes the doubleclick call already calls for a normal click)
|
||||
/mob/proc/DblClickOn(atom/A, params)
|
||||
return
|
||||
|
||||
|
||||
/*
|
||||
Translates into attack_hand, etc.
|
||||
|
||||
Note: proximity_flag here is used to distinguish between normal usage (flag=1),
|
||||
and usage when clicking on things telekinetically (flag=0). This proc will
|
||||
not be called at ranged except with telekinesis.
|
||||
|
||||
proximity_flag is not currently passed to attack_hand, and is instead used
|
||||
in human click code to allow glove touches only at melee range.
|
||||
*/
|
||||
/mob/proc/UnarmedAttack(atom/A, proximity_flag)
|
||||
if(ismob(A))
|
||||
changeNext_move(CLICK_CD_MELEE)
|
||||
return
|
||||
|
||||
/*
|
||||
Ranged unarmed attack:
|
||||
|
||||
This currently is just a default for all mobs, involving
|
||||
laser eyes and telekinesis. You could easily add exceptions
|
||||
for things like ranged glove touches, spitting alien acid/neurotoxin,
|
||||
animals lunging, etc.
|
||||
*/
|
||||
/mob/proc/RangedAttack(atom/A, params)
|
||||
/*
|
||||
Restrained ClickOn
|
||||
|
||||
Used when you are handcuffed and click things.
|
||||
Not currently used by anything but could easily be.
|
||||
*/
|
||||
/mob/proc/RestrainedClickOn(atom/A)
|
||||
return
|
||||
|
||||
/*
|
||||
Middle click
|
||||
Only used for swapping hands
|
||||
*/
|
||||
/mob/proc/MiddleClickOn(atom/A)
|
||||
return
|
||||
|
||||
/mob/living/carbon/MiddleClickOn(atom/A)
|
||||
if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src))
|
||||
next_click = world.time + 5
|
||||
mind.changeling.chosen_sting.try_to_sting(src, A)
|
||||
else
|
||||
swap_hand()
|
||||
|
||||
/mob/living/simple_animal/drone/MiddleClickOn(atom/A)
|
||||
swap_hand()
|
||||
|
||||
// In case of use break glass
|
||||
/*
|
||||
/atom/proc/MiddleClick(mob/M as mob)
|
||||
return
|
||||
*/
|
||||
|
||||
/*
|
||||
Shift click
|
||||
For most mobs, examine.
|
||||
This is overridden in ai.dm
|
||||
*/
|
||||
/mob/proc/ShiftClickOn(atom/A)
|
||||
A.ShiftClick(src)
|
||||
return
|
||||
/atom/proc/ShiftClick(mob/user)
|
||||
if(user.client && user.client.eye == user || user.client.eye == user.loc)
|
||||
user.examinate(src)
|
||||
return
|
||||
|
||||
/*
|
||||
Ctrl click
|
||||
For most objects, pull
|
||||
*/
|
||||
|
||||
/mob/proc/CtrlClickOn(atom/A)
|
||||
A.CtrlClick(src)
|
||||
return
|
||||
|
||||
/atom/proc/CtrlClick(mob/user)
|
||||
var/mob/living/ML = user
|
||||
if(istype(ML))
|
||||
ML.pulled(src)
|
||||
|
||||
/mob/living/carbon/human/CtrlClick(mob/user)
|
||||
if(ishuman(user) && Adjacent(user))
|
||||
if(world.time < user.next_move)
|
||||
return FALSE
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.dna.species.grab(H, src, H.mind.martial_art)
|
||||
H.changeNext_move(CLICK_CD_MELEE)
|
||||
else
|
||||
..()
|
||||
/*
|
||||
Alt click
|
||||
Unused except for AI
|
||||
*/
|
||||
/mob/proc/AltClickOn(atom/A)
|
||||
A.AltClick(src)
|
||||
return
|
||||
|
||||
/mob/living/carbon/AltClickOn(atom/A)
|
||||
if(!src.stat && src.mind && src.mind.changeling && src.mind.changeling.chosen_sting && (istype(A, /mob/living/carbon)) && (A != src))
|
||||
next_click = world.time + 5
|
||||
mind.changeling.chosen_sting.try_to_sting(src, A)
|
||||
else
|
||||
..()
|
||||
|
||||
/atom/proc/AltClick(mob/user)
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && user.TurfAdjacent(T))
|
||||
if(user.listed_turf == T)
|
||||
user.listed_turf = null
|
||||
else
|
||||
user.listed_turf = T
|
||||
user.client.statpanel = T.name
|
||||
return
|
||||
|
||||
/mob/proc/TurfAdjacent(turf/T)
|
||||
return T.Adjacent(src)
|
||||
|
||||
/*
|
||||
Control+Shift click
|
||||
Unused except for AI
|
||||
*/
|
||||
/mob/proc/CtrlShiftClickOn(atom/A)
|
||||
A.CtrlShiftClick(src)
|
||||
return
|
||||
|
||||
/mob/proc/ShiftMiddleClickOn(atom/A)
|
||||
src.pointed(A)
|
||||
return
|
||||
|
||||
/atom/proc/CtrlShiftClick(mob/user)
|
||||
return
|
||||
|
||||
/*
|
||||
Misc helpers
|
||||
|
||||
Laser Eyes: as the name implies, handles this since nothing else does currently
|
||||
face_atom: turns the mob towards what you clicked on
|
||||
*/
|
||||
/mob/proc/LaserEyes(atom/A)
|
||||
return
|
||||
|
||||
/mob/living/LaserEyes(atom/A)
|
||||
changeNext_move(CLICK_CD_RANGE)
|
||||
var/turf/T = get_turf(src)
|
||||
var/turf/U = get_turf(A)
|
||||
|
||||
var/obj/item/projectile/beam/LE = new /obj/item/projectile/beam( loc )
|
||||
LE.icon = 'icons/effects/genetics.dmi'
|
||||
LE.icon_state = "eyelasers"
|
||||
playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
|
||||
|
||||
LE.firer = src
|
||||
LE.def_zone = get_organ_target()
|
||||
LE.original = A
|
||||
LE.current = T
|
||||
LE.yo = U.y - T.y
|
||||
LE.xo = U.x - T.x
|
||||
LE.fire()
|
||||
|
||||
// Simple helper to face what you clicked on, in case it should be needed in more than one place
|
||||
/mob/proc/face_atom(atom/A)
|
||||
if( buckled || stat != CONSCIOUS || !A || !x || !y || !A.x || !A.y )
|
||||
return
|
||||
var/dx = A.x - x
|
||||
var/dy = A.y - y
|
||||
if(!dx && !dy) // Wall items are graphically shifted but on the floor
|
||||
if(A.pixel_y > 16)
|
||||
setDir(NORTH)
|
||||
else if(A.pixel_y < -16)
|
||||
setDir(SOUTH)
|
||||
else if(A.pixel_x > 16)
|
||||
setDir(EAST)
|
||||
else if(A.pixel_x < -16)
|
||||
setDir(WEST)
|
||||
return
|
||||
|
||||
if(abs(dx) < abs(dy))
|
||||
if(dy > 0)
|
||||
setDir(NORTH)
|
||||
else
|
||||
setDir(SOUTH)
|
||||
else
|
||||
if(dx > 0)
|
||||
setDir(EAST)
|
||||
else
|
||||
setDir(WEST)
|
||||
|
||||
/obj/screen/click_catcher
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "click_catcher"
|
||||
plane = CLICKCATCHER_PLANE
|
||||
mouse_opacity = 2
|
||||
screen_loc = "CENTER"
|
||||
|
||||
/obj/screen/click_catcher/New()
|
||||
..()
|
||||
transform = matrix(200, 0, 0, 0, 200, 0)
|
||||
|
||||
/obj/screen/click_catcher/Click(location, control, params)
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["middle"] && istype(usr, /mob/living/carbon))
|
||||
var/mob/living/carbon/C = usr
|
||||
C.swap_hand()
|
||||
else
|
||||
var/turf/T = params2turf(modifiers["screen-loc"], get_turf(usr))
|
||||
if(T)
|
||||
T.Click(location, control, params)
|
||||
. = 1
|
||||
|
||||
|
||||
/* MouseWheelOn */
|
||||
|
||||
/mob/proc/MouseWheelOn(atom/A, delta_x, delta_y, params)
|
||||
return
|
||||
|
||||
/mob/dead/observer/MouseWheelOn(atom/A, delta_x, delta_y, params)
|
||||
var/list/modifier = params2list(params)
|
||||
if(modifier["shift"])
|
||||
var/view = 0
|
||||
if(delta_y > 0)
|
||||
view = -1
|
||||
else
|
||||
view = 1
|
||||
add_view_range(view)
|
||||
|
||||
@@ -14,15 +14,6 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
//Master -> SSPreInit -> GLOB -> world -> config -> SSInit -> Failsafe
|
||||
//GOT IT MEMORIZED?
|
||||
|
||||
GLOBAL_VAR_INIT(MC_restart_clear, 0)
|
||||
GLOBAL_VAR_INIT(MC_restart_timeout, 0)
|
||||
GLOBAL_VAR_INIT(MC_restart_count, 0)
|
||||
|
||||
|
||||
//current tick limit, assigned by the queue controller before running a subsystem.
|
||||
//used by check_tick as well so that the procs subsystems call can obey that SS's tick limits
|
||||
GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
|
||||
/datum/controller/master
|
||||
name = "Master"
|
||||
|
||||
@@ -59,6 +50,14 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
|
||||
var/current_runlevel //for scheduling different subsystems for different stages of the round
|
||||
|
||||
var/static/restart_clear = 0
|
||||
var/static/restart_timeout = 0
|
||||
var/static/restart_count = 0
|
||||
|
||||
//current tick limit, assigned before running a subsystem.
|
||||
//used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits
|
||||
var/static/current_ticklimit = TICK_LIMIT_RUNNING
|
||||
|
||||
/datum/controller/master/New()
|
||||
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
|
||||
subsystems = list()
|
||||
@@ -90,14 +89,14 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
// -1 if we encountered a runtime trying to recreate it
|
||||
/proc/Recreate_MC()
|
||||
. = -1 //so if we runtime, things know we failed
|
||||
if (world.time < GLOB.MC_restart_timeout)
|
||||
if (world.time < Master.restart_timeout)
|
||||
return 0
|
||||
if (world.time < GLOB.MC_restart_clear)
|
||||
GLOB.MC_restart_count *= 0.5
|
||||
if (world.time < Master.restart_clear)
|
||||
Master.restart_count *= 0.5
|
||||
|
||||
var/delay = 50 * ++GLOB.MC_restart_count
|
||||
GLOB.MC_restart_timeout = world.time + delay
|
||||
GLOB.MC_restart_clear = world.time + (delay * 2)
|
||||
var/delay = 50 * ++Master.restart_count
|
||||
Master.restart_timeout = world.time + delay
|
||||
Master.restart_clear = world.time + (delay * 2)
|
||||
Master.processing = 0 //stop ticking this one
|
||||
try
|
||||
new/datum/controller/master()
|
||||
@@ -165,13 +164,13 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
|
||||
var/start_timeofday = REALTIMEOFDAY
|
||||
// Initialize subsystems.
|
||||
GLOB.CURRENT_TICKLIMIT = config.tick_limit_mc_init
|
||||
current_ticklimit = config.tick_limit_mc_init
|
||||
for (var/datum/controller/subsystem/SS in subsystems)
|
||||
if (SS.flags & SS_NO_INIT)
|
||||
continue
|
||||
SS.Initialize(REALTIMEOFDAY)
|
||||
CHECK_TICK
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
current_ticklimit = TICK_LIMIT_RUNNING
|
||||
var/time = (REALTIMEOFDAY - start_timeofday) / 10
|
||||
|
||||
var/msg = "Initializations complete within [time] second[time == 1 ? "" : "s"]!"
|
||||
@@ -206,6 +205,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
set waitfor = 0
|
||||
if(delay)
|
||||
sleep(delay)
|
||||
testing("Master starting processing")
|
||||
var/rtn = Loop()
|
||||
if (rtn > 0 || processing < 0)
|
||||
return //this was suppose to happen.
|
||||
@@ -276,7 +276,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
while (1)
|
||||
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
|
||||
if (processing <= 0)
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
current_ticklimit = TICK_LIMIT_RUNNING
|
||||
sleep(10)
|
||||
continue
|
||||
|
||||
@@ -284,7 +284,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
// because sleeps are processed in the order received, so longer sleeps are more likely to run first
|
||||
if (world.tick_usage > TICK_LIMIT_MC)
|
||||
sleep_delta += 2
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING * 0.5
|
||||
current_ticklimit = TICK_LIMIT_RUNNING * 0.5
|
||||
sleep(world.tick_lag * (processing + sleep_delta))
|
||||
continue
|
||||
|
||||
@@ -322,7 +322,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
if (!error_level)
|
||||
iteration++
|
||||
error_level++
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
current_ticklimit = TICK_LIMIT_RUNNING
|
||||
sleep(10)
|
||||
continue
|
||||
|
||||
@@ -334,7 +334,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
if (!error_level)
|
||||
iteration++
|
||||
error_level++
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
||||
current_ticklimit = TICK_LIMIT_RUNNING
|
||||
sleep(10)
|
||||
continue
|
||||
error_level--
|
||||
@@ -345,7 +345,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
iteration++
|
||||
last_run = world.time
|
||||
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
|
||||
GLOB.CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc.
|
||||
current_ticklimit = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc.
|
||||
sleep(world.tick_lag * (processing + sleep_delta))
|
||||
|
||||
|
||||
@@ -436,7 +436,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
|
||||
|
||||
tick_precentage = max(tick_precentage*0.5, tick_precentage-queue_node.tick_overrun)
|
||||
|
||||
GLOB.CURRENT_TICKLIMIT = round(world.tick_usage + tick_precentage)
|
||||
current_ticklimit = round(world.tick_usage + tick_precentage)
|
||||
|
||||
if (!(queue_node_flags & SS_TICKER))
|
||||
ran_non_ticker = TRUE
|
||||
|
||||
@@ -150,7 +150,7 @@ SUBSYSTEM_DEF(atoms)
|
||||
/datum/controller/subsystem/atoms/Shutdown()
|
||||
var/initlog = InitLog()
|
||||
if(initlog)
|
||||
text2file("[GLOB.log_directory]/initialize.log", initlog)
|
||||
text2file(initlog, "[GLOB.log_directory]/initialize.log")
|
||||
|
||||
#undef BAD_INIT_QDEL_BEFORE
|
||||
#undef BAD_INIT_DIDNT_INIT
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
SUBSYSTEM_DEF(blackbox)
|
||||
name = "Blackbox"
|
||||
wait = 6000
|
||||
flags = SS_NO_TICK_CHECK
|
||||
flags = SS_NO_TICK_CHECK | SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/list/msg_common = list()
|
||||
var/list/msg_science = list()
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
SUBSYSTEM_DEF(fields)
|
||||
name = "Fields"
|
||||
wait = 2
|
||||
priority = 40
|
||||
flags = SS_KEEP_TIMING
|
||||
var/list/datum/proximity_monitor/advanced/running = list()
|
||||
var/list/datum/proximity_monitor/advanced/currentrun = list()
|
||||
|
||||
/datum/controller/subsystem/fields/fire(resumed = 0)
|
||||
if(!resumed)
|
||||
src.currentrun = running.Copy()
|
||||
var/list/currentrun = src.currentrun
|
||||
while(currentrun.len)
|
||||
var/datum/proximity_monitor/advanced/F = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if(!F.requires_processing)
|
||||
continue
|
||||
F.process()
|
||||
if(MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/fields/proc/register_new_field(datum/proximity_monitor/advanced/F)
|
||||
running += F
|
||||
|
||||
/datum/controller/subsystem/fields/proc/unregister_field(datum/proximity_monitor/advanced/F)
|
||||
running -= F
|
||||
@@ -61,7 +61,7 @@ SUBSYSTEM_DEF(garbage)
|
||||
for(var/path in sleptDestroy)
|
||||
dellog += "Path : [path] \n"
|
||||
dellog += "Sleeps : [sleptDestroy[path]] \n"
|
||||
text2file("[GLOB.log_directory]/qdel.log", dellog.Join())
|
||||
text2file(dellog.Join(), "[GLOB.log_directory]/qdel.log")
|
||||
|
||||
/datum/controller/subsystem/garbage/fire()
|
||||
HandleToBeQueued()
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
PROCESSING_SUBSYSTEM_DEF(fields)
|
||||
name = "Fields"
|
||||
wait = 2
|
||||
priority = 40
|
||||
flags = SS_KEEP_TIMING | SS_NO_INIT
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
@@ -79,681 +79,17 @@
|
||||
/datum/martial_art/proc/teach(mob/living/carbon/human/H,make_temporary=0)
|
||||
if(make_temporary)
|
||||
temporary = 1
|
||||
if(temporary && H.martial_art)
|
||||
if(!H.martial_art.allow_temp_override)
|
||||
if(temporary && H.mind.martial_art)
|
||||
if(!H.mind.martial_art.allow_temp_override)
|
||||
return
|
||||
base = H.martial_art
|
||||
base = H.mind.martial_art
|
||||
if(help_verb)
|
||||
H.verbs += help_verb
|
||||
H.martial_art = src
|
||||
H.mind.martial_art = src
|
||||
|
||||
/datum/martial_art/proc/remove(mob/living/carbon/human/H)
|
||||
if(H.martial_art != src)
|
||||
if(H.mind.martial_art != src)
|
||||
return
|
||||
H.martial_art = base
|
||||
H.mind.martial_art = base
|
||||
if(help_verb)
|
||||
H.verbs -= help_verb
|
||||
|
||||
/datum/martial_art/boxing
|
||||
name = "Boxing"
|
||||
|
||||
/datum/martial_art/boxing/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
to_chat(A, "<span class='warning'>Can't disarm while boxing!</span>")
|
||||
return 1
|
||||
|
||||
/datum/martial_art/boxing/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
to_chat(A, "<span class='warning'>Can't grab while boxing!</span>")
|
||||
return 1
|
||||
|
||||
/datum/martial_art/boxing/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
|
||||
var/atk_verb = pick("left hook","right hook","straight punch")
|
||||
|
||||
var/damage = rand(5, 8) + A.dna.species.punchdamagelow
|
||||
if(!damage)
|
||||
playsound(D.loc, A.dna.species.miss_sound, 25, 1, -1)
|
||||
D.visible_message("<span class='warning'>[A] has attempted to [atk_verb] [D]!</span>", \
|
||||
"<span class='userdanger'>[A] has attempted to [atk_verb] [D]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
add_logs(A, D, "attempted to hit", atk_verb)
|
||||
return 0
|
||||
|
||||
|
||||
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
|
||||
var/armor_block = D.run_armor_check(affecting, "melee")
|
||||
|
||||
playsound(D.loc, A.dna.species.attack_sound, 25, 1, -1)
|
||||
|
||||
D.visible_message("<span class='danger'>[A] has [atk_verb]ed [D]!</span>", \
|
||||
"<span class='userdanger'>[A] has [atk_verb]ed [D]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
|
||||
D.apply_damage(damage, STAMINA, affecting, armor_block)
|
||||
add_logs(A, D, "punched (boxing) ")
|
||||
if(D.getStaminaLoss() > 50)
|
||||
var/knockout_prob = D.getStaminaLoss() + rand(-15,15)
|
||||
if((D.stat != DEAD) && prob(knockout_prob))
|
||||
D.visible_message("<span class='danger'>[A] has knocked [D] out with a haymaker!</span>", \
|
||||
"<span class='userdanger'>[A] has knocked [D] out with a haymaker!</span>")
|
||||
D.apply_effect(10,WEAKEN,armor_block)
|
||||
D.SetSleeping(5)
|
||||
D.forcesay(GLOB.hit_appends)
|
||||
add_logs(A, D, "knocked out (boxing) ")
|
||||
else if(D.lying)
|
||||
D.forcesay(GLOB.hit_appends)
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/wrestling_help()
|
||||
set name = "Recall Teachings"
|
||||
set desc = "Remember how to wrestle."
|
||||
set category = "Wrestling"
|
||||
|
||||
to_chat(usr, "<b><i>You flex your muscles and have a revelation...</i></b>")
|
||||
to_chat(usr, "<span class='notice'>Clinch</span>: Grab. Passively gives you a chance to immediately aggressively grab someone. Not always successful.")
|
||||
to_chat(usr, "<span class='notice'>Suplex</span>: Disarm someone you are grabbing. Suplexes your target to the floor. Greatly injures them and leaves both you and your target on the floor.")
|
||||
to_chat(usr, "<span class='notice'>Advanced grab</span>: Grab. Passively causes stamina damage when grabbing someone.")
|
||||
|
||||
#define TORNADO_COMBO "HHD"
|
||||
#define THROWBACK_COMBO "DHD"
|
||||
#define PLASMA_COMBO "HDDDH"
|
||||
|
||||
/datum/martial_art/plasma_fist
|
||||
name = "Plasma Fist"
|
||||
help_verb = /mob/living/carbon/human/proc/plasma_fist_help
|
||||
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(findtext(streak,TORNADO_COMBO))
|
||||
streak = ""
|
||||
Tornado(A,D)
|
||||
return 1
|
||||
if(findtext(streak,THROWBACK_COMBO))
|
||||
streak = ""
|
||||
Throwback(A,D)
|
||||
return 1
|
||||
if(findtext(streak,PLASMA_COMBO))
|
||||
streak = ""
|
||||
Plasma(A,D)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/TornadoAnimate(mob/living/carbon/human/A)
|
||||
set waitfor = FALSE
|
||||
for(var/i in list(NORTH,SOUTH,EAST,WEST,EAST,SOUTH,NORTH,SOUTH,EAST,WEST,EAST,SOUTH))
|
||||
if(!A)
|
||||
break
|
||||
A.setDir(i)
|
||||
playsound(A.loc, 'sound/weapons/punch1.ogg', 15, 1, -1)
|
||||
sleep(1)
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Tornado(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
A.say("TORNADO SWEEP!")
|
||||
TornadoAnimate(A)
|
||||
var/obj/effect/proc_holder/spell/aoe_turf/repulse/R = new(null)
|
||||
var/list/turfs = list()
|
||||
for(var/turf/T in range(1,A))
|
||||
turfs.Add(T)
|
||||
R.cast(turfs)
|
||||
add_logs(A, D, "tornado sweeped(Plasma Fist)")
|
||||
return
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Throwback(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
D.visible_message("<span class='danger'>[A] has hit [D] with Plasma Punch!</span>", \
|
||||
"<span class='userdanger'>[A] has hit [D] with Plasma Punch!</span>")
|
||||
playsound(D.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
var/atom/throw_target = get_edge_target_turf(D, get_dir(D, get_step_away(D, A)))
|
||||
D.throw_at(throw_target, 200, 4,A)
|
||||
A.say("HYAH!")
|
||||
add_logs(A, D, "threw back (Plasma Fist)")
|
||||
return
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Plasma(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
playsound(D.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
A.say("PLASMA FIST!")
|
||||
D.visible_message("<span class='danger'>[A] has hit [D] with THE PLASMA FIST TECHNIQUE!</span>", \
|
||||
"<span class='userdanger'>[A] has hit [D] with THE PLASMA FIST TECHNIQUE!</span>")
|
||||
D.gib()
|
||||
add_logs(A, D, "gibbed (Plasma Fist)")
|
||||
return
|
||||
|
||||
/datum/martial_art/plasma_fist/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("H",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
basic_hit(A,D)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/plasma_fist/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("D",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
basic_hit(A,D)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/plasma_fist/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("G",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
basic_hit(A,D)
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/plasma_fist_help()
|
||||
set name = "Recall Teachings"
|
||||
set desc = "Remember the martial techniques of the Plasma Fist."
|
||||
set category = "Plasma Fist"
|
||||
|
||||
to_chat(usr, "<b><i>You clench your fists and have a flashback of knowledge...</i></b>")
|
||||
to_chat(usr, "<span class='notice'>Tornado Sweep</span>: Harm Harm Disarm. Repulses target and everyone back.")
|
||||
to_chat(usr, "<span class='notice'>Throwback</span>: Disarm Harm Disarm. Throws the target and an item at them.")
|
||||
to_chat(usr, "<span class='notice'>The Plasma Fist</span>: Harm Disarm Disarm Disarm Harm. Knocks the brain out of the opponent and gibs their body.")
|
||||
|
||||
//Used by the gang of the same name. Uses combos. Basic attacks bypass armor and never miss
|
||||
#define WRIST_WRENCH_COMBO "DD"
|
||||
#define BACK_KICK_COMBO "HG"
|
||||
#define STOMACH_KNEE_COMBO "GH"
|
||||
#define HEAD_KICK_COMBO "DHH"
|
||||
#define ELBOW_DROP_COMBO "HDHDH"
|
||||
/datum/martial_art/the_sleeping_carp
|
||||
name = "The Sleeping Carp"
|
||||
deflection_chance = 100
|
||||
no_guns = TRUE
|
||||
allow_temp_override = FALSE
|
||||
help_verb = /mob/living/carbon/human/proc/sleeping_carp_help
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(findtext(streak,WRIST_WRENCH_COMBO))
|
||||
streak = ""
|
||||
wristWrench(A,D)
|
||||
return 1
|
||||
if(findtext(streak,BACK_KICK_COMBO))
|
||||
streak = ""
|
||||
backKick(A,D)
|
||||
return 1
|
||||
if(findtext(streak,STOMACH_KNEE_COMBO))
|
||||
streak = ""
|
||||
kneeStomach(A,D)
|
||||
return 1
|
||||
if(findtext(streak,HEAD_KICK_COMBO))
|
||||
streak = ""
|
||||
headKick(A,D)
|
||||
return 1
|
||||
if(findtext(streak,ELBOW_DROP_COMBO))
|
||||
streak = ""
|
||||
elbowDrop(A,D)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/wristWrench(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat && !D.stunned && !D.weakened)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
D.visible_message("<span class='warning'>[A] grabs [D]'s wrist and wrenches it sideways!</span>", \
|
||||
"<span class='userdanger'>[A] grabs your wrist and violently wrenches it to the side!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
D.emote("scream")
|
||||
D.drop_item()
|
||||
D.apply_damage(5, BRUTE, pick("l_arm", "r_arm"))
|
||||
D.Stun(3)
|
||||
return 1
|
||||
add_logs(A, D, "wrist wrenched (Sleeping Carp)")
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/backKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(A.dir == D.dir && !D.stat && !D.weakened)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] in the back!</span>", \
|
||||
"<span class='userdanger'>[A] kicks you in the back, making you stumble and fall!</span>")
|
||||
step_to(D,get_step(D,D.dir),1)
|
||||
D.Weaken(4)
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
return 1
|
||||
add_logs(A, D, "back-kicked (Sleeping Carp)")
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/kneeStomach(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat && !D.weakened)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
D.visible_message("<span class='warning'>[A] knees [D] in the stomach!</span>", \
|
||||
"<span class='userdanger'>[A] winds you with a knee in the stomach!</span>")
|
||||
D.audible_message("<b>[D]</b> gags!")
|
||||
D.losebreath += 3
|
||||
D.Stun(2)
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
return 1
|
||||
add_logs(A, D, "stomach kneed (Sleeping Carp)")
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/headKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat && !D.weakened)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] in the head!</span>", \
|
||||
"<span class='userdanger'>[A] kicks you in the jaw!</span>")
|
||||
D.apply_damage(20, BRUTE, "head")
|
||||
D.drop_item()
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
D.Stun(4)
|
||||
return 1
|
||||
add_logs(A, D, "head kicked (Sleeping Carp)")
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/elbowDrop(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(D.weakened || D.resting || D.stat)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
D.visible_message("<span class='warning'>[A] elbow drops [D]!</span>", \
|
||||
"<span class='userdanger'>[A] piledrives you with their elbow!</span>")
|
||||
if(D.stat)
|
||||
D.death() //FINISH HIM!
|
||||
D.apply_damage(50, BRUTE, "chest")
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 75, 1, -1)
|
||||
return 1
|
||||
add_logs(A, D, "elbow dropped (Sleeping Carp)")
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("G",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
if(A.grab_state >= GRAB_AGGRESSIVE)
|
||||
D.grabbedby(A, 1)
|
||||
else
|
||||
A.start_pulling(D, 1)
|
||||
if(A.pulling)
|
||||
D.drop_all_held_items()
|
||||
D.stop_pulling()
|
||||
if(A.a_intent == INTENT_GRAB)
|
||||
add_logs(A, D, "grabbed", addition="aggressively")
|
||||
A.grab_state = GRAB_AGGRESSIVE //Instant aggressive grab
|
||||
else
|
||||
add_logs(A, D, "grabbed", addition="passively")
|
||||
A.grab_state = GRAB_PASSIVE
|
||||
return 1
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("H",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
var/atk_verb = pick("punches", "kicks", "chops", "hits", "slams")
|
||||
D.visible_message("<span class='danger'>[A] [atk_verb] [D]!</span>", \
|
||||
"<span class='userdanger'>[A] [atk_verb] you!</span>")
|
||||
D.apply_damage(rand(10,15), BRUTE)
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 25, 1, -1)
|
||||
if(prob(D.getBruteLoss()) && !D.lying)
|
||||
D.visible_message("<span class='warning'>[D] stumbles and falls!</span>", "<span class='userdanger'>The blow sends you to the ground!</span>")
|
||||
D.Weaken(4)
|
||||
add_logs(A, D, "[atk_verb] (Sleeping Carp)")
|
||||
return 1
|
||||
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("D",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/proc/sleeping_carp_help()
|
||||
set name = "Recall Teachings"
|
||||
set desc = "Remember the martial techniques of the Sleeping Carp clan."
|
||||
set category = "Sleeping Carp"
|
||||
|
||||
to_chat(usr, "<b><i>You retreat inward and recall the teachings of the Sleeping Carp...</i></b>")
|
||||
|
||||
to_chat(usr, "<span class='notice'>Wrist Wrench</span>: Disarm Disarm. Forces opponent to drop item in hand.")
|
||||
to_chat(usr, "<span class='notice'>Back Kick</span>: Harm Grab. Opponent must be facing away. Knocks down.")
|
||||
to_chat(usr, "<span class='notice'>Stomach Knee</span>: Grab Harm. Knocks the wind out of opponent and stuns.")
|
||||
to_chat(usr, "<span class='notice'>Head Kick</span>: Disarm Harm Harm. Decent damage, forces opponent to drop item in hand.")
|
||||
to_chat(usr, "<span class='notice'>Elbow Drop</span>: Harm Disarm Harm Disarm Harm. Opponent must be on the ground. Deals huge damage, instantly kills anyone in critical condition.")
|
||||
|
||||
//CQC
|
||||
#define SLAM_COMBO "GH"
|
||||
#define KICK_COMBO "HH"
|
||||
#define RESTRAIN_COMBO "GG"
|
||||
#define PRESSURE_COMBO "DG"
|
||||
#define CONSECUTIVE_COMBO "DDH"
|
||||
/datum/martial_art/cqc
|
||||
name = "CQC"
|
||||
help_verb = /mob/living/carbon/human/proc/CQC_help
|
||||
block_chance = 75
|
||||
|
||||
/datum/martial_art/cqc/proc/drop_restraining()
|
||||
restraining = 0
|
||||
|
||||
/datum/martial_art/cqc/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(findtext(streak,SLAM_COMBO))
|
||||
streak = ""
|
||||
Slam(A,D)
|
||||
return 1
|
||||
if(findtext(streak,KICK_COMBO))
|
||||
streak = ""
|
||||
Kick(A,D)
|
||||
return 1
|
||||
if(findtext(streak,RESTRAIN_COMBO))
|
||||
streak = ""
|
||||
Restrain(A,D)
|
||||
return 1
|
||||
if(findtext(streak,PRESSURE_COMBO))
|
||||
streak = ""
|
||||
Pressure(A,D)
|
||||
return 1
|
||||
if(findtext(streak,CONSECUTIVE_COMBO))
|
||||
streak = ""
|
||||
Consecutive(A,D)
|
||||
return 0
|
||||
|
||||
/datum/martial_art/cqc/proc/Slam(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat || !D.weakened)
|
||||
D.visible_message("<span class='warning'>[A] slams [D] into the ground!</span>", \
|
||||
"<span class='userdanger'>[A] slams you into the ground!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/slam.ogg', 50, 1, -1)
|
||||
D.apply_damage(10, BRUTE)
|
||||
D.Weaken(6)
|
||||
add_logs(A, D, "cqc slammed")
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/proc/Kick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat || !D.weakened)
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] back!</span>", \
|
||||
"<span class='userdanger'>[A] kicks you back!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
|
||||
var/atom/throw_target = get_edge_target_turf(D, A.dir)
|
||||
D.throw_at(throw_target, 1, 14, A)
|
||||
D.apply_damage(10, BRUTE)
|
||||
add_logs(A, D, "cqc kicked")
|
||||
if(D.weakened && !D.stat)
|
||||
D.visible_message("<span class='warning'>[A] kicks [D]'s head, knocking them out!</span>", \
|
||||
"<span class='userdanger'>[A] kicks your head, knocking you out!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1)
|
||||
D.SetSleeping(15)
|
||||
D.adjustBrainLoss(25)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/proc/Pressure(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
D.visible_message("<span class='warning'>[A] forces their arm on [D]'s neck!</span>")
|
||||
D.adjustStaminaLoss(60)
|
||||
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/proc/Restrain(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(restraining)
|
||||
return
|
||||
if(!D.stat)
|
||||
D.visible_message("<span class='warning'>[A] locks [D] into a restraining position!</span>", \
|
||||
"<span class='userdanger'>[A] locks you into a restraining position!</span>")
|
||||
D.adjustStaminaLoss(20)
|
||||
D.Stun(5)
|
||||
restraining = 1
|
||||
addtimer(CALLBACK(src, .proc/drop_restraining), 50, TIMER_UNIQUE)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/proc/Consecutive(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat)
|
||||
D.visible_message("<span class='warning'>[A] strikes [D]'s abdomen, neck and back consecutively</span>", \
|
||||
"<span class='userdanger'>[A] strikes your abdomen, neck and back consecutively!</span>")
|
||||
playsound(get_turf(D), 'sound/weapons/cqchit2.ogg', 50, 1, -1)
|
||||
var/obj/item/I = D.get_active_held_item()
|
||||
if(I && D.drop_item())
|
||||
A.put_in_hands(I)
|
||||
D.adjustStaminaLoss(50)
|
||||
D.apply_damage(25, BRUTE)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("G",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
if(A.grab_state >= GRAB_AGGRESSIVE)
|
||||
D.grabbedby(A, 1)
|
||||
else
|
||||
A.start_pulling(D, 1)
|
||||
if(A.pulling)
|
||||
D.stop_pulling()
|
||||
add_logs(A, D, "grabbed", addition="aggressively")
|
||||
A.grab_state = GRAB_AGGRESSIVE //Instant aggressive grab
|
||||
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("H",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
add_logs(A, D, "CQC'd")
|
||||
A.do_attack_animation(D)
|
||||
var/picked_hit_type = pick("CQC'd", "Big Bossed")
|
||||
var/bonus_damage = 13
|
||||
if(D.weakened || D.resting || D.lying)
|
||||
bonus_damage += 5
|
||||
picked_hit_type = "stomps on"
|
||||
D.apply_damage(bonus_damage, BRUTE)
|
||||
if(picked_hit_type == "kicks" || picked_hit_type == "stomps on")
|
||||
playsound(get_turf(D), 'sound/weapons/cqchit2.ogg', 50, 1, -1)
|
||||
else
|
||||
playsound(get_turf(D), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
|
||||
D.visible_message("<span class='danger'>[A] [picked_hit_type] [D]!</span>", \
|
||||
"<span class='userdanger'>[A] [picked_hit_type] you!</span>")
|
||||
add_logs(A, D, "[picked_hit_type] with CQC")
|
||||
if(A.resting && !D.stat && !D.weakened)
|
||||
D.visible_message("<span class='warning'>[A] leg sweeps [D]!", \
|
||||
"<span class='userdanger'>[A] leg sweeps you!</span>")
|
||||
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1)
|
||||
D.apply_damage(10, BRUTE)
|
||||
D.Weaken(3)
|
||||
add_logs(A, D, "cqc sweeped")
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("D",D)
|
||||
var/obj/item/I = null
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
if(prob(65))
|
||||
if(!D.stat || !D.weakened || !restraining)
|
||||
I = D.get_active_held_item()
|
||||
D.visible_message("<span class='warning'>[A] strikes [D]'s jaw with their hand!</span>", \
|
||||
"<span class='userdanger'>[A] strikes your jaw, disorienting you!</span>")
|
||||
playsound(get_turf(D), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
|
||||
if(I && D.drop_item())
|
||||
A.put_in_hands(I)
|
||||
D.Jitter(2)
|
||||
D.apply_damage(5, BRUTE)
|
||||
else
|
||||
D.visible_message("<span class='danger'>[A] attempted to disarm [D]!</span>", \
|
||||
"<span class='userdanger'>[A] attempted to disarm [D]!</span>")
|
||||
playsound(D, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
|
||||
add_logs(A, D, "disarmed with CQC", "[I ? " grabbing \the [I]" : ""]")
|
||||
if(restraining && A.pulling == D)
|
||||
D.visible_message("<span class='danger'>[A] puts [D] into a chokehold!</span>", \
|
||||
"<span class='userdanger'>[A] puts you into a chokehold!</span>")
|
||||
D.SetSleeping(20)
|
||||
restraining = 0
|
||||
if(A.grab_state < GRAB_NECK)
|
||||
A.grab_state = GRAB_NECK
|
||||
else
|
||||
restraining = 0
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/CQC_help()
|
||||
set name = "Remember The Basics"
|
||||
set desc = "You try to remember some of the basics of CQC."
|
||||
set category = "CQC"
|
||||
|
||||
to_chat(usr, "<b><i>You try to remember some of the basics of CQC.</i></b>")
|
||||
|
||||
to_chat(usr, "<span class='notice'>Slam</span>: Grab Harm. Slam opponent into the ground, weakens and knocks down.")
|
||||
to_chat(usr, "<span class='notice'>CQC Kick</span>: Harm Disarm Harm. Knocks opponent away. Knocks out stunned or weakened opponents.")
|
||||
to_chat(usr, "<span class='notice'>Restrain</span>: Grab Grab. Locks opponents into a restraining position, disarm to knock them out with a choke hold.")
|
||||
to_chat(usr, "<span class='notice'>Pressure</span>: Disarm Grab. Decent stamina damage.")
|
||||
to_chat(usr, "<span class='notice'>Consecutive CQC</span>: Disarm Disarm Harm. Mainly offensive move, huge damage and decent stamina damage.")
|
||||
|
||||
to_chat(usr, "<b><i>In addition, by having your throw mode on when being attacked, you enter an active defense mode where you have a chance to block and sometimes even counter attacks done to you.</i></b>")
|
||||
|
||||
//ITEMS
|
||||
|
||||
/obj/item/clothing/gloves/boxing
|
||||
var/datum/martial_art/boxing/style = new
|
||||
|
||||
/obj/item/clothing/gloves/boxing/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == slot_gloves)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,1)
|
||||
return
|
||||
|
||||
/obj/item/clothing/gloves/boxing/dropped(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.get_item_by_slot(slot_gloves) == src)
|
||||
style.remove(H)
|
||||
return
|
||||
|
||||
/obj/item/weapon/storage/belt/champion/wrestling
|
||||
name = "Wrestling Belt"
|
||||
var/datum/martial_art/wrestling/style = new
|
||||
|
||||
/obj/item/weapon/storage/belt/champion/wrestling/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == slot_belt)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,1)
|
||||
return
|
||||
|
||||
/obj/item/weapon/storage/belt/champion/wrestling/dropped(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.get_item_by_slot(slot_belt) == src)
|
||||
style.remove(H)
|
||||
return
|
||||
|
||||
/obj/item/weapon/plasma_fist_scroll
|
||||
name = "frayed scroll"
|
||||
desc = "An aged and frayed scrap of paper written in shifting runes. There are hand-drawn illustrations of pugilism."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state ="scroll2"
|
||||
var/used = 0
|
||||
|
||||
/obj/item/weapon/plasma_fist_scroll/attack_self(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(!used)
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/datum/martial_art/plasma_fist/F = new/datum/martial_art/plasma_fist(null)
|
||||
F.teach(H)
|
||||
to_chat(H, "<span class='boldannounce'>You have learned the ancient martial art of Plasma Fist.</span>")
|
||||
used = 1
|
||||
desc = "It's completely blank."
|
||||
name = "empty scroll"
|
||||
icon_state = "blankscroll"
|
||||
|
||||
/obj/item/weapon/cqc_manual
|
||||
name = "old manual"
|
||||
desc = "A small, black manual. There are drawn instructions of tactical hand-to-hand combat."
|
||||
icon = 'icons/obj/library.dmi'
|
||||
icon_state ="cqcmanual"
|
||||
|
||||
/obj/item/weapon/cqc_manual/attack_self(mob/living/carbon/human/user)
|
||||
if(!istype(user) || !user)
|
||||
return
|
||||
to_chat(user, "<span class='boldannounce'>You remember the basics of CQC.</span>")
|
||||
var/datum/martial_art/cqc/D = new(null)
|
||||
D.teach(user)
|
||||
user.drop_item()
|
||||
visible_message("<span class='warning'>[src] beeps ominously, and a moment later it bursts up in flames.</span>")
|
||||
new /obj/effect/decal/cleanable/ash(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/sleeping_carp_scroll
|
||||
name = "mysterious scroll"
|
||||
desc = "A scroll filled with strange markings. It seems to be drawings of some sort of martial art."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "scroll2"
|
||||
|
||||
/obj/item/weapon/sleeping_carp_scroll/attack_self(mob/living/carbon/human/user)
|
||||
if(!istype(user) || !user)
|
||||
return
|
||||
var/message = "<span class='sciradio'>You have learned the ancient martial art of the Sleeping Carp! Your hand-to-hand combat has become much more effective, and you are now able to deflect any projectiles \
|
||||
directed toward you. However, you are also unable to use any ranged weaponry. You can learn more about your newfound art by using the Recall Teachings verb in the Sleeping Carp tab.</span>"
|
||||
to_chat(user, message)
|
||||
var/datum/martial_art/the_sleeping_carp/theSleepingCarp = new(null)
|
||||
theSleepingCarp.teach(user)
|
||||
user.drop_item()
|
||||
visible_message("<span class='warning'>[src] lights up in fire and quickly burns to ash.</span>")
|
||||
new /obj/effect/decal/cleanable/ash(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/twohanded/bostaff
|
||||
name = "bo staff"
|
||||
desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts. Can be wielded to both kill and incapacitate."
|
||||
force = 10
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = SLOT_BACK
|
||||
force_unwielded = 10
|
||||
force_wielded = 24
|
||||
throwforce = 20
|
||||
throw_speed = 2
|
||||
attack_verb = list("smashed", "slammed", "whacked", "thwacked")
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "bostaff0"
|
||||
block_chance = 50
|
||||
|
||||
/obj/item/weapon/twohanded/bostaff/update_icon()
|
||||
icon_state = "bostaff[wielded]"
|
||||
return
|
||||
|
||||
/obj/item/weapon/twohanded/bostaff/attack(mob/target, mob/living/user)
|
||||
add_fingerprint(user)
|
||||
if((CLUMSY in user.disabilities) && prob(50))
|
||||
to_chat(user, "<span class ='warning'>You club yourself over the head with [src].</span>")
|
||||
user.Weaken(3)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.apply_damage(2*force, BRUTE, "head")
|
||||
else
|
||||
user.take_bodypart_damage(2*force)
|
||||
return
|
||||
if(iscyborg(target))
|
||||
return ..()
|
||||
if(!isliving(target))
|
||||
return ..()
|
||||
var/mob/living/carbon/C = target
|
||||
if(C.stat)
|
||||
to_chat(user, "<span class='warning'>It would be dishonorable to attack a foe while they cannot retaliate.</span>")
|
||||
return
|
||||
if(user.a_intent == INTENT_DISARM)
|
||||
if(!wielded)
|
||||
return ..()
|
||||
if(!ishuman(target))
|
||||
return ..()
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/list/fluffmessages = list("[user] clubs [H] with [src]!", \
|
||||
"[user] smacks [H] with the butt of [src]!", \
|
||||
"[user] broadsides [H] with [src]!", \
|
||||
"[user] smashes [H]'s head with [src]!", \
|
||||
"[user] beats [H] with front of [src]!", \
|
||||
"[user] twirls and slams [H] with [src]!")
|
||||
H.visible_message("<span class='warning'>[pick(fluffmessages)]</span>", \
|
||||
"<span class='userdanger'>[pick(fluffmessages)]</span>")
|
||||
playsound(get_turf(user), 'sound/effects/woodhit.ogg', 75, 1, -1)
|
||||
H.adjustStaminaLoss(rand(13,20))
|
||||
if(prob(10))
|
||||
H.visible_message("<span class='warning'>[H] collapses!</span>", \
|
||||
"<span class='userdanger'>Your legs give out!</span>")
|
||||
H.Weaken(4)
|
||||
if(H.staminaloss && !H.sleeping)
|
||||
var/total_health = (H.health - H.staminaloss)
|
||||
if(total_health <= HEALTH_THRESHOLD_CRIT && !H.stat)
|
||||
H.visible_message("<span class='warning'>[user] delivers a heavy hit to [H]'s head, knocking them out cold!</span>", \
|
||||
"<span class='userdanger'>[user] knocks you unconscious!</span>")
|
||||
H.SetSleeping(30)
|
||||
H.adjustBrainLoss(25)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
|
||||
if(wielded)
|
||||
return ..()
|
||||
return 0
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/datum/martial_art/boxing
|
||||
name = "Boxing"
|
||||
|
||||
/datum/martial_art/boxing/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
to_chat(A, "<span class='warning'>Can't disarm while boxing!</span>")
|
||||
return 1
|
||||
|
||||
/datum/martial_art/boxing/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
to_chat(A, "<span class='warning'>Can't grab while boxing!</span>")
|
||||
return 1
|
||||
|
||||
/datum/martial_art/boxing/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
|
||||
var/atk_verb = pick("left hook","right hook","straight punch")
|
||||
|
||||
var/damage = rand(5, 8) + A.dna.species.punchdamagelow
|
||||
if(!damage)
|
||||
playsound(D.loc, A.dna.species.miss_sound, 25, 1, -1)
|
||||
D.visible_message("<span class='warning'>[A] has attempted to [atk_verb] [D]!</span>", \
|
||||
"<span class='userdanger'>[A] has attempted to [atk_verb] [D]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
add_logs(A, D, "attempted to hit", atk_verb)
|
||||
return 0
|
||||
|
||||
|
||||
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
|
||||
var/armor_block = D.run_armor_check(affecting, "melee")
|
||||
|
||||
playsound(D.loc, A.dna.species.attack_sound, 25, 1, -1)
|
||||
|
||||
D.visible_message("<span class='danger'>[A] has [atk_verb]ed [D]!</span>", \
|
||||
"<span class='userdanger'>[A] has [atk_verb]ed [D]!</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
|
||||
D.apply_damage(damage, STAMINA, affecting, armor_block)
|
||||
add_logs(A, D, "punched (boxing) ")
|
||||
if(D.getStaminaLoss() > 50)
|
||||
var/knockout_prob = D.getStaminaLoss() + rand(-15,15)
|
||||
if((D.stat != DEAD) && prob(knockout_prob))
|
||||
D.visible_message("<span class='danger'>[A] has knocked [D] out with a haymaker!</span>", \
|
||||
"<span class='userdanger'>[A] has knocked [D] out with a haymaker!</span>")
|
||||
D.apply_effect(10,WEAKEN,armor_block)
|
||||
D.SetSleeping(5)
|
||||
D.forcesay(GLOB.hit_appends)
|
||||
add_logs(A, D, "knocked out (boxing) ")
|
||||
else if(D.lying)
|
||||
D.forcesay(GLOB.hit_appends)
|
||||
return 1
|
||||
|
||||
/obj/item/clothing/gloves/boxing
|
||||
var/datum/martial_art/boxing/style = new
|
||||
|
||||
/obj/item/clothing/gloves/boxing/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == slot_gloves)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,1)
|
||||
return
|
||||
|
||||
/obj/item/clothing/gloves/boxing/dropped(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.get_item_by_slot(slot_gloves) == src)
|
||||
style.remove(H)
|
||||
return
|
||||
@@ -0,0 +1,199 @@
|
||||
#define SLAM_COMBO "GH"
|
||||
#define KICK_COMBO "HH"
|
||||
#define RESTRAIN_COMBO "GG"
|
||||
#define PRESSURE_COMBO "DG"
|
||||
#define CONSECUTIVE_COMBO "DDH"
|
||||
|
||||
/datum/martial_art/cqc
|
||||
name = "CQC"
|
||||
help_verb = /mob/living/carbon/human/proc/CQC_help
|
||||
block_chance = 75
|
||||
|
||||
/datum/martial_art/cqc/proc/drop_restraining()
|
||||
restraining = 0
|
||||
|
||||
/datum/martial_art/cqc/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(findtext(streak,SLAM_COMBO))
|
||||
streak = ""
|
||||
Slam(A,D)
|
||||
return 1
|
||||
if(findtext(streak,KICK_COMBO))
|
||||
streak = ""
|
||||
Kick(A,D)
|
||||
return 1
|
||||
if(findtext(streak,RESTRAIN_COMBO))
|
||||
streak = ""
|
||||
Restrain(A,D)
|
||||
return 1
|
||||
if(findtext(streak,PRESSURE_COMBO))
|
||||
streak = ""
|
||||
Pressure(A,D)
|
||||
return 1
|
||||
if(findtext(streak,CONSECUTIVE_COMBO))
|
||||
streak = ""
|
||||
Consecutive(A,D)
|
||||
return 0
|
||||
|
||||
/datum/martial_art/cqc/proc/Slam(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat || !D.weakened)
|
||||
D.visible_message("<span class='warning'>[A] slams [D] into the ground!</span>", \
|
||||
"<span class='userdanger'>[A] slams you into the ground!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/slam.ogg', 50, 1, -1)
|
||||
D.apply_damage(10, BRUTE)
|
||||
D.Weaken(6)
|
||||
add_logs(A, D, "cqc slammed")
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/proc/Kick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat || !D.weakened)
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] back!</span>", \
|
||||
"<span class='userdanger'>[A] kicks you back!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
|
||||
var/atom/throw_target = get_edge_target_turf(D, A.dir)
|
||||
D.throw_at(throw_target, 1, 14, A)
|
||||
D.apply_damage(10, BRUTE)
|
||||
add_logs(A, D, "cqc kicked")
|
||||
if(D.weakened && !D.stat)
|
||||
D.visible_message("<span class='warning'>[A] kicks [D]'s head, knocking them out!</span>", \
|
||||
"<span class='userdanger'>[A] kicks your head, knocking you out!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/genhit1.ogg', 50, 1, -1)
|
||||
D.SetSleeping(15)
|
||||
D.adjustBrainLoss(25)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/proc/Pressure(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
D.visible_message("<span class='warning'>[A] forces their arm on [D]'s neck!</span>")
|
||||
D.adjustStaminaLoss(60)
|
||||
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/proc/Restrain(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(restraining)
|
||||
return
|
||||
if(!D.stat)
|
||||
D.visible_message("<span class='warning'>[A] locks [D] into a restraining position!</span>", \
|
||||
"<span class='userdanger'>[A] locks you into a restraining position!</span>")
|
||||
D.adjustStaminaLoss(20)
|
||||
D.Stun(5)
|
||||
restraining = 1
|
||||
addtimer(CALLBACK(src, .proc/drop_restraining), 50, TIMER_UNIQUE)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/proc/Consecutive(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat)
|
||||
D.visible_message("<span class='warning'>[A] strikes [D]'s abdomen, neck and back consecutively</span>", \
|
||||
"<span class='userdanger'>[A] strikes your abdomen, neck and back consecutively!</span>")
|
||||
playsound(get_turf(D), 'sound/weapons/cqchit2.ogg', 50, 1, -1)
|
||||
var/obj/item/I = D.get_active_held_item()
|
||||
if(I && D.drop_item())
|
||||
A.put_in_hands(I)
|
||||
D.adjustStaminaLoss(50)
|
||||
D.apply_damage(25, BRUTE)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("G",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
if(A.grab_state >= GRAB_AGGRESSIVE)
|
||||
D.grabbedby(A, 1)
|
||||
else
|
||||
A.start_pulling(D, 1)
|
||||
if(A.pulling)
|
||||
D.stop_pulling()
|
||||
add_logs(A, D, "grabbed", addition="aggressively")
|
||||
A.grab_state = GRAB_AGGRESSIVE //Instant aggressive grab
|
||||
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("H",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
add_logs(A, D, "CQC'd")
|
||||
A.do_attack_animation(D)
|
||||
var/picked_hit_type = pick("CQC'd", "Big Bossed")
|
||||
var/bonus_damage = 13
|
||||
if(D.weakened || D.resting || D.lying)
|
||||
bonus_damage += 5
|
||||
picked_hit_type = "stomps on"
|
||||
D.apply_damage(bonus_damage, BRUTE)
|
||||
if(picked_hit_type == "kicks" || picked_hit_type == "stomps on")
|
||||
playsound(get_turf(D), 'sound/weapons/cqchit2.ogg', 50, 1, -1)
|
||||
else
|
||||
playsound(get_turf(D), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
|
||||
D.visible_message("<span class='danger'>[A] [picked_hit_type] [D]!</span>", \
|
||||
"<span class='userdanger'>[A] [picked_hit_type] you!</span>")
|
||||
add_logs(A, D, "[picked_hit_type] with CQC")
|
||||
if(A.resting && !D.stat && !D.weakened)
|
||||
D.visible_message("<span class='warning'>[A] leg sweeps [D]!", \
|
||||
"<span class='userdanger'>[A] leg sweeps you!</span>")
|
||||
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1)
|
||||
D.apply_damage(10, BRUTE)
|
||||
D.Weaken(3)
|
||||
add_logs(A, D, "cqc sweeped")
|
||||
return 1
|
||||
|
||||
/datum/martial_art/cqc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("D",D)
|
||||
var/obj/item/I = null
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
if(prob(65))
|
||||
if(!D.stat || !D.weakened || !restraining)
|
||||
I = D.get_active_held_item()
|
||||
D.visible_message("<span class='warning'>[A] strikes [D]'s jaw with their hand!</span>", \
|
||||
"<span class='userdanger'>[A] strikes your jaw, disorienting you!</span>")
|
||||
playsound(get_turf(D), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
|
||||
if(I && D.drop_item())
|
||||
A.put_in_hands(I)
|
||||
D.Jitter(2)
|
||||
D.apply_damage(5, BRUTE)
|
||||
else
|
||||
D.visible_message("<span class='danger'>[A] attempted to disarm [D]!</span>", \
|
||||
"<span class='userdanger'>[A] attempted to disarm [D]!</span>")
|
||||
playsound(D, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
|
||||
add_logs(A, D, "disarmed with CQC", "[I ? " grabbing \the [I]" : ""]")
|
||||
if(restraining && A.pulling == D)
|
||||
D.visible_message("<span class='danger'>[A] puts [D] into a chokehold!</span>", \
|
||||
"<span class='userdanger'>[A] puts you into a chokehold!</span>")
|
||||
D.SetSleeping(20)
|
||||
restraining = 0
|
||||
if(A.grab_state < GRAB_NECK)
|
||||
A.grab_state = GRAB_NECK
|
||||
else
|
||||
restraining = 0
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/CQC_help()
|
||||
set name = "Remember The Basics"
|
||||
set desc = "You try to remember some of the basics of CQC."
|
||||
set category = "CQC"
|
||||
|
||||
to_chat(usr, "<b><i>You try to remember some of the basics of CQC.</i></b>")
|
||||
|
||||
to_chat(usr, "<span class='notice'>Slam</span>: Grab Harm. Slam opponent into the ground, weakens and knocks down.")
|
||||
to_chat(usr, "<span class='notice'>CQC Kick</span>: Harm Disarm Harm. Knocks opponent away. Knocks out stunned or weakened opponents.")
|
||||
to_chat(usr, "<span class='notice'>Restrain</span>: Grab Grab. Locks opponents into a restraining position, disarm to knock them out with a choke hold.")
|
||||
to_chat(usr, "<span class='notice'>Pressure</span>: Disarm Grab. Decent stamina damage.")
|
||||
to_chat(usr, "<span class='notice'>Consecutive CQC</span>: Disarm Disarm Harm. Mainly offensive move, huge damage and decent stamina damage.")
|
||||
|
||||
to_chat(usr, "<b><i>In addition, by having your throw mode on when being attacked, you enter an active defense mode where you have a chance to block and sometimes even counter attacks done to you.</i></b>")
|
||||
|
||||
/obj/item/weapon/cqc_manual
|
||||
name = "old manual"
|
||||
desc = "A small, black manual. There are drawn instructions of tactical hand-to-hand combat."
|
||||
icon = 'icons/obj/library.dmi'
|
||||
icon_state ="cqcmanual"
|
||||
|
||||
/obj/item/weapon/cqc_manual/attack_self(mob/living/carbon/human/user)
|
||||
if(!istype(user) || !user)
|
||||
return
|
||||
to_chat(user, "<span class='boldannounce'>You remember the basics of CQC.</span>")
|
||||
var/datum/martial_art/cqc/D = new(null)
|
||||
D.teach(user)
|
||||
user.drop_item()
|
||||
visible_message("<span class='warning'>[src] beeps ominously, and a moment later it bursts up in flames.</span>")
|
||||
new /obj/effect/decal/cleanable/ash(get_turf(src))
|
||||
qdel(src)
|
||||
@@ -13,12 +13,12 @@
|
||||
to_chat(owner, "<span class='warning'>You can't use Krav Maga while you're incapacitated.</span>")
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if (H.martial_art.streak == "neck_chop")
|
||||
if (H.mind.martial_art.streak == "neck_chop")
|
||||
owner.visible_message("<span class='danger'>[owner] assumes a neutral stance.</span>", "<b><i>Your next attack is cleared.</i></b>")
|
||||
H.martial_art.streak = ""
|
||||
H.mind.martial_art.streak = ""
|
||||
else
|
||||
owner.visible_message("<span class='danger'>[owner] assumes the Neck Chop stance!</span>", "<b><i>Your next attack will be a Neck Chop.</i></b>")
|
||||
H.martial_art.streak = "neck_chop"
|
||||
H.mind.martial_art.streak = "neck_chop"
|
||||
|
||||
/datum/action/leg_sweep
|
||||
name = "Leg Sweep - Trips the victim, knocking them down for a brief moment."
|
||||
@@ -29,12 +29,12 @@
|
||||
to_chat(owner, "<span class='warning'>You can't use Krav Maga while you're incapacitated.</span>")
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if (H.martial_art.streak == "leg_sweep")
|
||||
if (H.mind.martial_art.streak == "leg_sweep")
|
||||
owner.visible_message("<span class='danger'>[owner] assumes a neutral stance.</span>", "<b><i>Your next attack is cleared.</i></b>")
|
||||
H.martial_art.streak = ""
|
||||
H.mind.martial_art.streak = ""
|
||||
else
|
||||
owner.visible_message("<span class='danger'>[owner] assumes the Leg Sweep stance!</span>", "<b><i>Your next attack will be a Leg Sweep.</i></b>")
|
||||
H.martial_art.streak = "leg_sweep"
|
||||
H.mind.martial_art.streak = "leg_sweep"
|
||||
|
||||
/datum/action/lung_punch//referred to internally as 'quick choke'
|
||||
name = "Lung Punch - Delivers a strong punch just above the victim's abdomen, constraining the lungs. The victim will be unable to breathe for a short time."
|
||||
@@ -45,12 +45,12 @@
|
||||
to_chat(owner, "<span class='warning'>You can't use Krav Maga while you're incapacitated.</span>")
|
||||
return
|
||||
var/mob/living/carbon/human/H = owner
|
||||
if (H.martial_art.streak == "quick_choke")
|
||||
if (H.mind.martial_art.streak == "quick_choke")
|
||||
owner.visible_message("<span class='danger'>[owner] assumes a neutral stance.</span>", "<b><i>Your next attack is cleared.</i></b>")
|
||||
H.martial_art.streak = ""
|
||||
H.mind.martial_art.streak = ""
|
||||
else
|
||||
owner.visible_message("<span class='danger'>[owner] assumes the Lung Punch stance!</span>", "<b><i>Your next attack will be a Lung Punch.</i></b>")
|
||||
H.martial_art.streak = "quick_choke"//internal name for lung punch
|
||||
H.mind.martial_art.streak = "quick_choke"//internal name for lung punch
|
||||
|
||||
/datum/martial_art/krav_maga/teach(var/mob/living/carbon/human/H,var/make_temporary=0)
|
||||
..()
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#define TORNADO_COMBO "HHD"
|
||||
#define THROWBACK_COMBO "DHD"
|
||||
#define PLASMA_COMBO "HDDDH"
|
||||
|
||||
/datum/martial_art/plasma_fist
|
||||
name = "Plasma Fist"
|
||||
help_verb = /mob/living/carbon/human/proc/plasma_fist_help
|
||||
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(findtext(streak,TORNADO_COMBO))
|
||||
streak = ""
|
||||
Tornado(A,D)
|
||||
return 1
|
||||
if(findtext(streak,THROWBACK_COMBO))
|
||||
streak = ""
|
||||
Throwback(A,D)
|
||||
return 1
|
||||
if(findtext(streak,PLASMA_COMBO))
|
||||
streak = ""
|
||||
Plasma(A,D)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/TornadoAnimate(mob/living/carbon/human/A)
|
||||
set waitfor = FALSE
|
||||
for(var/i in list(NORTH,SOUTH,EAST,WEST,EAST,SOUTH,NORTH,SOUTH,EAST,WEST,EAST,SOUTH))
|
||||
if(!A)
|
||||
break
|
||||
A.setDir(i)
|
||||
playsound(A.loc, 'sound/weapons/punch1.ogg', 15, 1, -1)
|
||||
sleep(1)
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Tornado(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
A.say("TORNADO SWEEP!")
|
||||
TornadoAnimate(A)
|
||||
var/obj/effect/proc_holder/spell/aoe_turf/repulse/R = new(null)
|
||||
var/list/turfs = list()
|
||||
for(var/turf/T in range(1,A))
|
||||
turfs.Add(T)
|
||||
R.cast(turfs)
|
||||
add_logs(A, D, "tornado sweeped(Plasma Fist)")
|
||||
return
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Throwback(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
D.visible_message("<span class='danger'>[A] has hit [D] with Plasma Punch!</span>", \
|
||||
"<span class='userdanger'>[A] has hit [D] with Plasma Punch!</span>")
|
||||
playsound(D.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
var/atom/throw_target = get_edge_target_turf(D, get_dir(D, get_step_away(D, A)))
|
||||
D.throw_at(throw_target, 200, 4,A)
|
||||
A.say("HYAH!")
|
||||
add_logs(A, D, "threw back (Plasma Fist)")
|
||||
return
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Plasma(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
playsound(D.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
A.say("PLASMA FIST!")
|
||||
D.visible_message("<span class='danger'>[A] has hit [D] with THE PLASMA FIST TECHNIQUE!</span>", \
|
||||
"<span class='userdanger'>[A] has hit [D] with THE PLASMA FIST TECHNIQUE!</span>")
|
||||
D.gib()
|
||||
add_logs(A, D, "gibbed (Plasma Fist)")
|
||||
return
|
||||
|
||||
/datum/martial_art/plasma_fist/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("H",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
basic_hit(A,D)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/plasma_fist/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("D",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
basic_hit(A,D)
|
||||
return 1
|
||||
|
||||
/datum/martial_art/plasma_fist/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("G",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
basic_hit(A,D)
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/human/proc/plasma_fist_help()
|
||||
set name = "Recall Teachings"
|
||||
set desc = "Remember the martial techniques of the Plasma Fist."
|
||||
set category = "Plasma Fist"
|
||||
|
||||
to_chat(usr, "<b><i>You clench your fists and have a flashback of knowledge...</i></b>")
|
||||
to_chat(usr, "<span class='notice'>Tornado Sweep</span>: Harm Harm Disarm. Repulses target and everyone back.")
|
||||
to_chat(usr, "<span class='notice'>Throwback</span>: Disarm Harm Disarm. Throws the target and an item at them.")
|
||||
to_chat(usr, "<span class='notice'>The Plasma Fist</span>: Harm Disarm Disarm Disarm Harm. Knocks the brain out of the opponent and gibs their body.")
|
||||
|
||||
/obj/item/weapon/plasma_fist_scroll
|
||||
name = "frayed scroll"
|
||||
desc = "An aged and frayed scrap of paper written in shifting runes. There are hand-drawn illustrations of pugilism."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state ="scroll2"
|
||||
var/used = 0
|
||||
|
||||
/obj/item/weapon/plasma_fist_scroll/attack_self(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(!used)
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/datum/martial_art/plasma_fist/F = new/datum/martial_art/plasma_fist(null)
|
||||
F.teach(H)
|
||||
to_chat(H, "<span class='boldannounce'>You have learned the ancient martial art of Plasma Fist.</span>")
|
||||
used = 1
|
||||
desc = "It's completely blank."
|
||||
name = "empty scroll"
|
||||
icon_state = "blankscroll"
|
||||
@@ -0,0 +1,247 @@
|
||||
#define WRIST_WRENCH_COMBO "DD"
|
||||
#define BACK_KICK_COMBO "HG"
|
||||
#define STOMACH_KNEE_COMBO "GH"
|
||||
#define HEAD_KICK_COMBO "DHH"
|
||||
#define ELBOW_DROP_COMBO "HDHDH"
|
||||
|
||||
/datum/martial_art/the_sleeping_carp
|
||||
name = "The Sleeping Carp"
|
||||
deflection_chance = 100
|
||||
no_guns = TRUE
|
||||
allow_temp_override = FALSE
|
||||
help_verb = /mob/living/carbon/human/proc/sleeping_carp_help
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(findtext(streak,WRIST_WRENCH_COMBO))
|
||||
streak = ""
|
||||
wristWrench(A,D)
|
||||
return 1
|
||||
if(findtext(streak,BACK_KICK_COMBO))
|
||||
streak = ""
|
||||
backKick(A,D)
|
||||
return 1
|
||||
if(findtext(streak,STOMACH_KNEE_COMBO))
|
||||
streak = ""
|
||||
kneeStomach(A,D)
|
||||
return 1
|
||||
if(findtext(streak,HEAD_KICK_COMBO))
|
||||
streak = ""
|
||||
headKick(A,D)
|
||||
return 1
|
||||
if(findtext(streak,ELBOW_DROP_COMBO))
|
||||
streak = ""
|
||||
elbowDrop(A,D)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/wristWrench(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat && !D.stunned && !D.weakened)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
D.visible_message("<span class='warning'>[A] grabs [D]'s wrist and wrenches it sideways!</span>", \
|
||||
"<span class='userdanger'>[A] grabs your wrist and violently wrenches it to the side!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
D.emote("scream")
|
||||
D.drop_item()
|
||||
D.apply_damage(5, BRUTE, pick("l_arm", "r_arm"))
|
||||
D.Stun(3)
|
||||
return 1
|
||||
add_logs(A, D, "wrist wrenched (Sleeping Carp)")
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/backKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(A.dir == D.dir && !D.stat && !D.weakened)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] in the back!</span>", \
|
||||
"<span class='userdanger'>[A] kicks you in the back, making you stumble and fall!</span>")
|
||||
step_to(D,get_step(D,D.dir),1)
|
||||
D.Weaken(4)
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
return 1
|
||||
add_logs(A, D, "back-kicked (Sleeping Carp)")
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/kneeStomach(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat && !D.weakened)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
D.visible_message("<span class='warning'>[A] knees [D] in the stomach!</span>", \
|
||||
"<span class='userdanger'>[A] winds you with a knee in the stomach!</span>")
|
||||
D.audible_message("<b>[D]</b> gags!")
|
||||
D.losebreath += 3
|
||||
D.Stun(2)
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
return 1
|
||||
add_logs(A, D, "stomach kneed (Sleeping Carp)")
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/headKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D.stat && !D.weakened)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] in the head!</span>", \
|
||||
"<span class='userdanger'>[A] kicks you in the jaw!</span>")
|
||||
D.apply_damage(20, BRUTE, "head")
|
||||
D.drop_item()
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
D.Stun(4)
|
||||
return 1
|
||||
add_logs(A, D, "head kicked (Sleeping Carp)")
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/elbowDrop(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(D.weakened || D.resting || D.stat)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
D.visible_message("<span class='warning'>[A] elbow drops [D]!</span>", \
|
||||
"<span class='userdanger'>[A] piledrives you with their elbow!</span>")
|
||||
if(D.stat)
|
||||
D.death() //FINISH HIM!
|
||||
D.apply_damage(50, BRUTE, "chest")
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 75, 1, -1)
|
||||
return 1
|
||||
add_logs(A, D, "elbow dropped (Sleeping Carp)")
|
||||
return basic_hit(A,D)
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("G",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
if(A.grab_state >= GRAB_AGGRESSIVE)
|
||||
D.grabbedby(A, 1)
|
||||
else
|
||||
A.start_pulling(D, 1)
|
||||
if(A.pulling)
|
||||
D.drop_all_held_items()
|
||||
D.stop_pulling()
|
||||
if(A.a_intent == INTENT_GRAB)
|
||||
add_logs(A, D, "grabbed", addition="aggressively")
|
||||
A.grab_state = GRAB_AGGRESSIVE //Instant aggressive grab
|
||||
else
|
||||
add_logs(A, D, "grabbed", addition="passively")
|
||||
A.grab_state = GRAB_PASSIVE
|
||||
return 1
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("H",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
var/atk_verb = pick("punches", "kicks", "chops", "hits", "slams")
|
||||
D.visible_message("<span class='danger'>[A] [atk_verb] [D]!</span>", \
|
||||
"<span class='userdanger'>[A] [atk_verb] you!</span>")
|
||||
D.apply_damage(rand(10,15), BRUTE)
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 25, 1, -1)
|
||||
if(prob(D.getBruteLoss()) && !D.lying)
|
||||
D.visible_message("<span class='warning'>[D] stumbles and falls!</span>", "<span class='userdanger'>The blow sends you to the ground!</span>")
|
||||
D.Weaken(4)
|
||||
add_logs(A, D, "[atk_verb] (Sleeping Carp)")
|
||||
return 1
|
||||
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("D",D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/proc/sleeping_carp_help()
|
||||
set name = "Recall Teachings"
|
||||
set desc = "Remember the martial techniques of the Sleeping Carp clan."
|
||||
set category = "Sleeping Carp"
|
||||
|
||||
to_chat(usr, "<b><i>You retreat inward and recall the teachings of the Sleeping Carp...</i></b>")
|
||||
|
||||
to_chat(usr, "<span class='notice'>Wrist Wrench</span>: Disarm Disarm. Forces opponent to drop item in hand.")
|
||||
to_chat(usr, "<span class='notice'>Back Kick</span>: Harm Grab. Opponent must be facing away. Knocks down.")
|
||||
to_chat(usr, "<span class='notice'>Stomach Knee</span>: Grab Harm. Knocks the wind out of opponent and stuns.")
|
||||
to_chat(usr, "<span class='notice'>Head Kick</span>: Disarm Harm Harm. Decent damage, forces opponent to drop item in hand.")
|
||||
to_chat(usr, "<span class='notice'>Elbow Drop</span>: Harm Disarm Harm Disarm Harm. Opponent must be on the ground. Deals huge damage, instantly kills anyone in critical condition.")
|
||||
|
||||
/obj/item/weapon/sleeping_carp_scroll
|
||||
name = "mysterious scroll"
|
||||
desc = "A scroll filled with strange markings. It seems to be drawings of some sort of martial art."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "scroll2"
|
||||
|
||||
/obj/item/weapon/sleeping_carp_scroll/attack_self(mob/living/carbon/human/user)
|
||||
if(!istype(user) || !user)
|
||||
return
|
||||
var/message = "<span class='sciradio'>You have learned the ancient martial art of the Sleeping Carp! Your hand-to-hand combat has become much more effective, and you are now able to deflect any projectiles \
|
||||
directed toward you. However, you are also unable to use any ranged weaponry. You can learn more about your newfound art by using the Recall Teachings verb in the Sleeping Carp tab.</span>"
|
||||
to_chat(user, message)
|
||||
var/datum/martial_art/the_sleeping_carp/theSleepingCarp = new(null)
|
||||
theSleepingCarp.teach(user)
|
||||
user.drop_item()
|
||||
visible_message("<span class='warning'>[src] lights up in fire and quickly burns to ash.</span>")
|
||||
new /obj/effect/decal/cleanable/ash(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/twohanded/bostaff
|
||||
name = "bo staff"
|
||||
desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts. Can be wielded to both kill and incapacitate."
|
||||
force = 10
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = SLOT_BACK
|
||||
force_unwielded = 10
|
||||
force_wielded = 24
|
||||
throwforce = 20
|
||||
throw_speed = 2
|
||||
attack_verb = list("smashed", "slammed", "whacked", "thwacked")
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "bostaff0"
|
||||
block_chance = 50
|
||||
|
||||
/obj/item/weapon/twohanded/bostaff/update_icon()
|
||||
icon_state = "bostaff[wielded]"
|
||||
return
|
||||
|
||||
/obj/item/weapon/twohanded/bostaff/attack(mob/target, mob/living/user)
|
||||
add_fingerprint(user)
|
||||
if((CLUMSY in user.disabilities) && prob(50))
|
||||
to_chat(user, "<span class ='warning'>You club yourself over the head with [src].</span>")
|
||||
user.Weaken(3)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.apply_damage(2*force, BRUTE, "head")
|
||||
else
|
||||
user.take_bodypart_damage(2*force)
|
||||
return
|
||||
if(iscyborg(target))
|
||||
return ..()
|
||||
if(!isliving(target))
|
||||
return ..()
|
||||
var/mob/living/carbon/C = target
|
||||
if(C.stat)
|
||||
to_chat(user, "<span class='warning'>It would be dishonorable to attack a foe while they cannot retaliate.</span>")
|
||||
return
|
||||
if(user.a_intent == INTENT_DISARM)
|
||||
if(!wielded)
|
||||
return ..()
|
||||
if(!ishuman(target))
|
||||
return ..()
|
||||
var/mob/living/carbon/human/H = target
|
||||
var/list/fluffmessages = list("[user] clubs [H] with [src]!", \
|
||||
"[user] smacks [H] with the butt of [src]!", \
|
||||
"[user] broadsides [H] with [src]!", \
|
||||
"[user] smashes [H]'s head with [src]!", \
|
||||
"[user] beats [H] with front of [src]!", \
|
||||
"[user] twirls and slams [H] with [src]!")
|
||||
H.visible_message("<span class='warning'>[pick(fluffmessages)]</span>", \
|
||||
"<span class='userdanger'>[pick(fluffmessages)]</span>")
|
||||
playsound(get_turf(user), 'sound/effects/woodhit.ogg', 75, 1, -1)
|
||||
H.adjustStaminaLoss(rand(13,20))
|
||||
if(prob(10))
|
||||
H.visible_message("<span class='warning'>[H] collapses!</span>", \
|
||||
"<span class='userdanger'>Your legs give out!</span>")
|
||||
H.Weaken(4)
|
||||
if(H.staminaloss && !H.sleeping)
|
||||
var/total_health = (H.health - H.staminaloss)
|
||||
if(total_health <= HEALTH_THRESHOLD_CRIT && !H.stat)
|
||||
H.visible_message("<span class='warning'>[user] delivers a heavy hit to [H]'s head, knocking them out cold!</span>", \
|
||||
"<span class='userdanger'>[user] knocks you unconscious!</span>")
|
||||
H.SetSleeping(30)
|
||||
H.adjustBrainLoss(25)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance)
|
||||
if(wielded)
|
||||
return ..()
|
||||
return 0
|
||||
@@ -1,3 +1,13 @@
|
||||
/mob/living/carbon/human/proc/wrestling_help()
|
||||
set name = "Recall Teachings"
|
||||
set desc = "Remember how to wrestle."
|
||||
set category = "Wrestling"
|
||||
|
||||
to_chat(usr, "<b><i>You flex your muscles and have a revelation...</i></b>")
|
||||
to_chat(usr, "<span class='notice'>Clinch</span>: Grab. Passively gives you a chance to immediately aggressively grab someone. Not always successful.")
|
||||
to_chat(usr, "<span class='notice'>Suplex</span>: Disarm someone you are grabbing. Suplexes your target to the floor. Greatly injures them and leaves both you and your target on the floor.")
|
||||
to_chat(usr, "<span class='notice'>Advanced grab</span>: Grab. Passively causes stamina damage when grabbing someone.")
|
||||
|
||||
/datum/martial_art/wrestling
|
||||
name = "Wrestling"
|
||||
var/datum/action/slam/slam = new/datum/action/slam()
|
||||
@@ -40,7 +50,7 @@
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to BODY SLAM!</span>", "<b><i>Your next attack will be a BODY SLAM.</i></b>")
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.martial_art.streak = "slam"
|
||||
H.mind.martial_art.streak = "slam"
|
||||
|
||||
/datum/action/throw_wrassle
|
||||
name = "Throw (Cinch) - Spin a cinched opponent around and throw them."
|
||||
@@ -52,7 +62,7 @@
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to THROW!</span>", "<b><i>Your next attack will be a THROW.</i></b>")
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.martial_art.streak = "throw"
|
||||
H.mind.martial_art.streak = "throw"
|
||||
|
||||
/datum/action/kick
|
||||
name = "Kick - A powerful kick, sends people flying away from you. Also useful for escaping from bad situations."
|
||||
@@ -64,7 +74,7 @@
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to KICK!</span>", "<b><i>Your next attack will be a KICK.</i></b>")
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.martial_art.streak = "kick"
|
||||
H.mind.martial_art.streak = "kick"
|
||||
|
||||
/datum/action/strike
|
||||
name = "Strike - Hit a neaby opponent with a quick attack."
|
||||
@@ -76,7 +86,7 @@
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to STRIKE!</span>", "<b><i>Your next attack will be a STRIKE.</i></b>")
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.martial_art.streak = "strike"
|
||||
H.mind.martial_art.streak = "strike"
|
||||
|
||||
/datum/action/drop
|
||||
name = "Drop - Smash down onto an opponent."
|
||||
@@ -88,7 +98,7 @@
|
||||
return
|
||||
owner.visible_message("<span class='danger'>[owner] prepares to LEG DROP!</span>", "<b><i>Your next attack will be a LEG DROP.</i></b>")
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.martial_art.streak = "drop"
|
||||
H.mind.martial_art.streak = "drop"
|
||||
|
||||
/datum/martial_art/wrestling/teach(var/mob/living/carbon/human/H,var/make_temporary=0)
|
||||
..()
|
||||
@@ -430,3 +440,23 @@
|
||||
D.Stun(rand(3,5))
|
||||
add_logs(A, D, "cinched")
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/storage/belt/champion/wrestling
|
||||
name = "Wrestling Belt"
|
||||
var/datum/martial_art/wrestling/style = new
|
||||
|
||||
/obj/item/weapon/storage/belt/champion/wrestling/equipped(mob/user, slot)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == slot_belt)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,1)
|
||||
return
|
||||
|
||||
/obj/item/weapon/storage/belt/champion/wrestling/dropped(mob/user)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.get_item_by_slot(slot_belt) == src)
|
||||
style.remove(H)
|
||||
return
|
||||
|
||||
@@ -50,7 +50,8 @@
|
||||
var/datum/faction/faction //associated faction
|
||||
var/datum/changeling/changeling //changeling holder
|
||||
var/linglink
|
||||
|
||||
var/datum/martial_art/martial_art = null
|
||||
var/static/default_martial_art = new/datum/martial_art
|
||||
var/miming = 0 // Mime's vow of silence
|
||||
var/list/antag_datums
|
||||
var/antag_hud_icon_state = null //this mind's ANTAG_HUD should have this icon_state
|
||||
|
||||
@@ -375,8 +375,8 @@
|
||||
desc = "Used by veteran cultists to instantly transport items to their needful bretheren."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
brightness_on = 1
|
||||
icon_state = "torch-on"
|
||||
item_state = "torch-on"
|
||||
icon_state = "torch"
|
||||
item_state = "torch"
|
||||
color = "#ff0000"
|
||||
on_damage = 15
|
||||
slot_flags = null
|
||||
|
||||
@@ -332,3 +332,4 @@ GLOBAL_LIST_INIT(gang_outfit_pool, list(/obj/item/clothing/suit/jacket/leather,/
|
||||
SSticker.station_explosion_cinematic(1,"gang war", null)
|
||||
SSticker.mode.explosion_in_progress = 0
|
||||
SSticker.force_ending = TRUE
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
var/static/list/boss_items = list(
|
||||
/datum/gang_item/function/gang_ping,
|
||||
/datum/gang_item/function/recall,
|
||||
|
||||
/datum/gang_item/clothing/under,
|
||||
/datum/gang_item/clothing/suit,
|
||||
/datum/gang_item/clothing/hat,
|
||||
@@ -36,21 +37,29 @@
|
||||
/datum/gang_item/clothing/mask,
|
||||
/datum/gang_item/clothing/hands,
|
||||
/datum/gang_item/clothing/belt,
|
||||
|
||||
/datum/gang_item/weapon/shuriken,
|
||||
/datum/gang_item/weapon/switchblade,
|
||||
/datum/gang_item/weapon/improvised,
|
||||
/datum/gang_item/weapon/ammo/improvised_ammo,
|
||||
/datum/gang_item/weapon/surplus,
|
||||
/datum/gang_item/weapon/ammo/surplus_ammo,
|
||||
/datum/gang_item/weapon/pistol,
|
||||
/datum/gang_item/weapon/ammo/pistol_ammo,
|
||||
/datum/gang_item/weapon/sniper,
|
||||
/datum/gang_item/weapon/ammo/sniper_ammo,
|
||||
/datum/gang_item/weapon/machinegun,
|
||||
/datum/gang_item/weapon/uzi,
|
||||
/datum/gang_item/weapon/ammo/uzi_ammo,
|
||||
/datum/gang_item/equipment/sharpener,
|
||||
/datum/gang_item/equipment/spraycan,
|
||||
/datum/gang_item/equipment/c4,
|
||||
/datum/gang_item/equipment/sharpener,
|
||||
/datum/gang_item/equipment/emp,
|
||||
/datum/gang_item/equipment/c4,
|
||||
/datum/gang_item/equipment/frag,
|
||||
/datum/gang_item/equipment/implant_breaker,
|
||||
/datum/gang_item/equipment/stimpack,
|
||||
/datum/gang_item/equipment/implant_breaker,
|
||||
/datum/gang_item/equipment/wetwork_boots,
|
||||
/datum/gang_item/equipment/pen,
|
||||
/datum/gang_item/equipment/dominator
|
||||
)
|
||||
@@ -66,21 +75,29 @@
|
||||
/datum/gang_item/clothing/mask,
|
||||
/datum/gang_item/clothing/hands,
|
||||
/datum/gang_item/clothing/belt,
|
||||
/datum/gang_item/weapon/shuriken,
|
||||
|
||||
/datum/gang_item/weapon/shuriken,
|
||||
/datum/gang_item/weapon/switchblade,
|
||||
/datum/gang_item/weapon/improvised,
|
||||
/datum/gang_item/weapon/ammo/improvised_ammo,
|
||||
/datum/gang_item/weapon/surplus,
|
||||
/datum/gang_item/weapon/ammo/surplus_ammo,
|
||||
/datum/gang_item/weapon/pistol,
|
||||
/datum/gang_item/weapon/ammo/pistol_ammo,
|
||||
/datum/gang_item/weapon/sniper,
|
||||
/datum/gang_item/weapon/ammo/sniper_ammo,
|
||||
/datum/gang_item/weapon/machinegun,
|
||||
/datum/gang_item/weapon/uzi,
|
||||
/datum/gang_item/weapon/ammo/uzi_ammo,
|
||||
/datum/gang_item/equipment/sharpener,
|
||||
/datum/gang_item/equipment/spraycan,
|
||||
/datum/gang_item/equipment/c4,
|
||||
/datum/gang_item/equipment/sharpener,
|
||||
/datum/gang_item/equipment/emp,
|
||||
/datum/gang_item/equipment/c4,
|
||||
/datum/gang_item/equipment/frag,
|
||||
/datum/gang_item/equipment/implant_breaker,
|
||||
/datum/gang_item/equipment/stimpack,
|
||||
/datum/gang_item/equipment/implant_breaker,
|
||||
/datum/gang_item/equipment/wetwork_boots,
|
||||
)
|
||||
|
||||
/datum/gang/New(loc,gangname)
|
||||
@@ -165,7 +182,6 @@
|
||||
var/diff = domination_timer - world.time
|
||||
return diff / 10
|
||||
|
||||
|
||||
//////////////////////////////////////////// MESSAGING
|
||||
|
||||
|
||||
@@ -283,4 +299,4 @@
|
||||
ganghud = new()
|
||||
|
||||
/datum/gang/multiverse/income()
|
||||
return
|
||||
return
|
||||
|
||||
@@ -199,10 +199,34 @@
|
||||
cost = 5
|
||||
item_path = /obj/item/weapon/switchblade
|
||||
|
||||
/datum/gang_item/weapon/surplus
|
||||
name = "Surplus Rifle"
|
||||
id = "surplus"
|
||||
cost = 8
|
||||
item_path = /obj/item/weapon/gun/ballistic/automatic/surplus
|
||||
|
||||
/datum/gang_item/weapon/ammo/surplus_ammo
|
||||
name = "Surplus Rifle Ammo"
|
||||
id = "surplus_ammo"
|
||||
cost = 5
|
||||
item_path = /obj/item/ammo_box/magazine/m10mm/rifle
|
||||
|
||||
/datum/gang_item/weapon/improvised
|
||||
name = "Sawn-Off Improvised Shotgun"
|
||||
id = "sawn"
|
||||
cost = 6
|
||||
item_path = /obj/item/weapon/gun/ballistic/revolver/doublebarrel/improvised/sawn
|
||||
|
||||
/datum/gang_item/weapon/ammo/improvised_ammo
|
||||
name = "Box of Buckshot"
|
||||
id = "buckshot"
|
||||
cost = 5
|
||||
item_path = /obj/item/weapon/storage/box/lethalshot
|
||||
|
||||
/datum/gang_item/weapon/pistol
|
||||
name = "10mm Pistol"
|
||||
id = "pistol"
|
||||
cost = 25
|
||||
cost = 30
|
||||
item_path = /obj/item/weapon/gun/ballistic/automatic/pistol
|
||||
|
||||
/datum/gang_item/weapon/ammo/pistol_ammo
|
||||
@@ -223,12 +247,19 @@
|
||||
cost = 15
|
||||
item_path = /obj/item/ammo_box/magazine/sniper_rounds
|
||||
|
||||
/datum/gang_item/weapon/machinegun
|
||||
name = "Mounted Machine Gun"
|
||||
id = "MG"
|
||||
cost = 50
|
||||
item_path = /obj/machinery/manned_turret
|
||||
spawn_msg = "<span class='notice'>The mounted machine gun features enhanced responsiveness. Hold down on the trigger while firing to control where you're shooting.</span>"
|
||||
|
||||
/datum/gang_item/weapon/uzi
|
||||
name = "Uzi SMG"
|
||||
id = "uzi"
|
||||
cost = 60
|
||||
item_path = /obj/item/weapon/gun/ballistic/automatic/mini_uzi
|
||||
id = "uzi"
|
||||
|
||||
|
||||
/datum/gang_item/weapon/ammo/uzi_ammo
|
||||
name = "Uzi Ammo"
|
||||
@@ -236,8 +267,6 @@
|
||||
cost = 40
|
||||
item_path = /obj/item/ammo_box/magazine/uzim9mm
|
||||
|
||||
|
||||
|
||||
///////////////////
|
||||
//EQUIPMENT
|
||||
///////////////////
|
||||
@@ -274,13 +303,13 @@
|
||||
/datum/gang_item/equipment/frag
|
||||
name = "Fragmentation Grenade"
|
||||
id = "frag nade"
|
||||
cost = 10
|
||||
cost = 18
|
||||
item_path = /obj/item/weapon/grenade/syndieminibomb/concussion/frag
|
||||
|
||||
/datum/gang_item/equipment/stimpack
|
||||
name = "Black Market Stimulants"
|
||||
id = "stimpack"
|
||||
cost = 15
|
||||
cost = 12
|
||||
item_path = /obj/item/weapon/reagent_containers/syringe/stimulants
|
||||
|
||||
/datum/gang_item/equipment/implant_breaker
|
||||
@@ -297,6 +326,18 @@
|
||||
if(spawn_msg)
|
||||
to_chat(user, spawn_msg)
|
||||
|
||||
/datum/gang_item/equipment/wetwork_boots
|
||||
name = "Wetwork boots"
|
||||
id = "wetwork"
|
||||
cost = 20
|
||||
item_path = /obj/item/clothing/shoes/combat/gang
|
||||
|
||||
/obj/item/clothing/shoes/combat/gang
|
||||
name = "Wetwork boots"
|
||||
desc = "A gang's best hitmen are prepared for anything."
|
||||
permeability_coefficient = 0.01
|
||||
flags = NOSLIP
|
||||
|
||||
/datum/gang_item/equipment/pen
|
||||
name = "Recruitment Pen"
|
||||
id = "pen"
|
||||
@@ -390,4 +431,4 @@
|
||||
return ..()
|
||||
|
||||
/datum/gang_item/equipment/dominator/spawn_item(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
|
||||
new item_path(user.loc)
|
||||
new item_path(user.loc)
|
||||
|
||||
@@ -66,4 +66,4 @@
|
||||
cooldown = 0
|
||||
icon_state = "pen"
|
||||
var/mob/M = get(src, /mob)
|
||||
to_chat(M, "<span class='notice'>\icon[src] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly. It is ready to be used again.</span>")
|
||||
to_chat(M, "<span class='notice'>\icon[src] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly. It is ready to be used again.</span>")
|
||||
|
||||
@@ -240,6 +240,7 @@
|
||||
|
||||
/obj/item/device/gangtool/spare/lt
|
||||
promotable = 1
|
||||
|
||||
///////////// Internal tool used by gang regulars ///////////
|
||||
|
||||
/obj/item/device/gangtool/soldier
|
||||
|
||||
@@ -35,7 +35,12 @@
|
||||
var/morphed = 0
|
||||
var/atom/movable/form = null
|
||||
var/morph_time = 0
|
||||
|
||||
var/static/list/blacklist_typecache = typecacheof(list(
|
||||
/obj/screen,
|
||||
/obj/singularity,
|
||||
/mob/living/simple_animal/hostile/morph,
|
||||
/obj/effect))
|
||||
|
||||
var/playstyle_string = "<b><font size=3 color='red'>You are a morph,</font> an abomination of science created primarily with changeling cells. \
|
||||
You may take the form of anything nearby by shift-clicking it. This process will alert any nearby \
|
||||
observers, and can only be performed once every five seconds. While morphed, you move faster, but do \
|
||||
@@ -67,13 +72,7 @@
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/hostile/morph/proc/allowed(atom/movable/A) // make it into property/proc ? not sure if worth it
|
||||
if(istype(A,/obj/screen))
|
||||
return 0
|
||||
if(istype(A,/obj/singularity))
|
||||
return 0
|
||||
if(istype(A,/mob/living/simple_animal/hostile/morph))
|
||||
return 0
|
||||
return 1
|
||||
return !is_type_in_typecache(A, blacklist_typecache)
|
||||
|
||||
/mob/living/simple_animal/hostile/morph/proc/eat(atom/movable/A)
|
||||
if(A && A.loc != src)
|
||||
@@ -100,6 +99,7 @@
|
||||
visible_message("<span class='warning'>[src] suddenly twists and changes shape, becoming a copy of [target]!</span>", \
|
||||
"<span class='notice'>You twist your body and assume the form of [target].</span>")
|
||||
appearance = target.appearance
|
||||
copy_overlays(target)
|
||||
alpha = max(alpha, 150) //fucking chameleons
|
||||
transform = initial(transform)
|
||||
pixel_y = initial(pixel_y)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#define TURRET_STUN 0
|
||||
#define TURRET_LETHAL 1
|
||||
|
||||
#define POPUP_ANIM_TIME 5
|
||||
#define POPDOWN_ANIM_TIME 5 //Be sure to change the icon animation at the same time or it'll look bad
|
||||
|
||||
#define POPUP_ANIM_TIME 5
|
||||
#define POPDOWN_ANIM_TIME 5 //Be sure to change the icon animation at the same time or it'll look bad
|
||||
|
||||
/obj/machinery/porta_turret
|
||||
name = "turret"
|
||||
icon = 'icons/obj/turrets.dmi'
|
||||
@@ -87,9 +87,9 @@
|
||||
if(has_cover)
|
||||
cover = new /obj/machinery/porta_turret_cover(loc)
|
||||
cover.parent_turret = src
|
||||
underlays += image('icons/obj/turrets.dmi',icon_state = "basedark")
|
||||
underlays += image('icons/obj/turrets.dmi',icon_state = "basedark")
|
||||
if(!has_cover)
|
||||
INVOKE_ASYNC(src, .proc/popUp)
|
||||
INVOKE_ASYNC(src, .proc/popUp)
|
||||
|
||||
/obj/machinery/porta_turret/update_icon()
|
||||
cut_overlays()
|
||||
@@ -368,10 +368,10 @@
|
||||
var/list/targets = list()
|
||||
var/turretview = view(scan_range, base)
|
||||
for(var/A in turretview)
|
||||
var/atom/AA = A
|
||||
if(AA.invisibility>SEE_INVISIBLE_LIVING)
|
||||
continue
|
||||
|
||||
var/atom/AA = A
|
||||
if(AA.invisibility>SEE_INVISIBLE_LIVING)
|
||||
continue
|
||||
|
||||
if(check_anomalies)//if it's set to check for simple animals
|
||||
if(istype(A, /mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/SA = A
|
||||
@@ -426,7 +426,7 @@
|
||||
raising = 1
|
||||
if(cover)
|
||||
flick("popup", cover)
|
||||
sleep(POPUP_ANIM_TIME)
|
||||
sleep(POPUP_ANIM_TIME)
|
||||
raising = 0
|
||||
if(cover)
|
||||
cover.icon_state = "openTurretCover"
|
||||
@@ -442,7 +442,7 @@
|
||||
raising = 1
|
||||
if(cover)
|
||||
flick("popdown", cover)
|
||||
sleep(POPDOWN_ANIM_TIME)
|
||||
sleep(POPDOWN_ANIM_TIME)
|
||||
raising = 0
|
||||
if(cover)
|
||||
cover.icon_state = "turretCover"
|
||||
@@ -553,6 +553,7 @@
|
||||
use_power = 0
|
||||
has_cover = 0
|
||||
scan_range = 9
|
||||
req_access = list(GLOB.access_syndicate)
|
||||
stun_projectile = /obj/item/projectile/bullet
|
||||
lethal_projectile = /obj/item/projectile/bullet
|
||||
lethal_projectile_sound = 'sound/weapons/Gunshot.ogg'
|
||||
@@ -569,6 +570,8 @@
|
||||
return 10 //Syndicate turrets shoot everything not in their faction
|
||||
|
||||
/obj/machinery/porta_turret/syndicate/pod
|
||||
max_integrity = 40
|
||||
integrity_failure = 20
|
||||
obj_integrity = 40
|
||||
stun_projectile = /obj/item/projectile/bullet/weakbullet3
|
||||
lethal_projectile = /obj/item/projectile/bullet/weakbullet3
|
||||
@@ -792,7 +795,7 @@
|
||||
/obj/item/wallframe/turret_control
|
||||
name = "turret control frame"
|
||||
desc = "Used for building turret control panels"
|
||||
icon_state = "apc"
|
||||
icon_state = "apc"
|
||||
result_path = /obj/machinery/turretid
|
||||
materials = list(MAT_METAL=MINERAL_MATERIAL_AMOUNT)
|
||||
|
||||
@@ -921,3 +924,170 @@
|
||||
on = 0
|
||||
spawn(100)
|
||||
on = 1
|
||||
|
||||
/////// MANNED TURRET ////////
|
||||
|
||||
/obj/machinery/manned_turret
|
||||
name = "machine gun turret"
|
||||
desc = "While the trigger is held down, this gun will redistribute recoil to allow its user to easily shift targets."
|
||||
icon = 'icons/obj/turrets.dmi'
|
||||
icon_state = "machinegun"
|
||||
can_buckle = TRUE
|
||||
density = TRUE
|
||||
max_integrity = 100
|
||||
obj_integrity = 100
|
||||
buckle_lying = 0
|
||||
layer = ABOVE_MOB_LAYER
|
||||
var/view_range = 10
|
||||
var/cooldown = 0
|
||||
var/projectile_type = /obj/item/projectile/bullet/weakbullet3
|
||||
var/rate_of_fire = 1
|
||||
var/number_of_shots = 40
|
||||
var/cooldown_duration = 90
|
||||
var/atom/target
|
||||
var/turf/target_turf
|
||||
var/warned = FALSE
|
||||
|
||||
//BUCKLE HOOKS
|
||||
|
||||
/obj/machinery/manned_turret/unbuckle_mob(mob/living/buckled_mob,force = 0)
|
||||
playsound(src,'sound/mecha/mechmove01.ogg', 50, 1)
|
||||
for(var/obj/item/I in buckled_mob.held_items)
|
||||
if(istype(I, /obj/item/gun_control))
|
||||
qdel(I)
|
||||
if(istype(buckled_mob))
|
||||
buckled_mob.pixel_x = 0
|
||||
buckled_mob.pixel_y = 0
|
||||
if(buckled_mob.client)
|
||||
buckled_mob.client.change_view(world.view)
|
||||
anchored = FALSE
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/manned_turret/user_buckle_mob(mob/living/M, mob/living/carbon/user)
|
||||
if(user.incapacitated() || !istype(user))
|
||||
return
|
||||
M.forceMove(get_turf(src))
|
||||
..()
|
||||
for(var/V in M.held_items)
|
||||
var/obj/item/I = V
|
||||
if(istype(I))
|
||||
if(M.dropItemToGround(I))
|
||||
var/obj/item/gun_control/TC = new /obj/item/gun_control(src)
|
||||
M.put_in_hands(TC)
|
||||
else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand
|
||||
var/obj/item/gun_control/TC = new /obj/item/gun_control(src)
|
||||
M.put_in_hands(TC)
|
||||
M.pixel_y = 14
|
||||
layer = ABOVE_MOB_LAYER
|
||||
setDir(SOUTH)
|
||||
playsound(src,'sound/mecha/mechmove01.ogg', 50, 1)
|
||||
anchored = TRUE
|
||||
if(user.client)
|
||||
user.client.change_view(view_range)
|
||||
|
||||
/obj/item/gun_control
|
||||
name = "turret controls"
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "offhand"
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
flags = ABSTRACT | NODROP
|
||||
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF | NOBLUDGEON
|
||||
var/obj/machinery/manned_turret/turret
|
||||
|
||||
/obj/item/gun_control/New(obj/machinery/manned_turret/MT)
|
||||
if(MT)
|
||||
turret = MT
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/obj/item/gun_control/CanItemAutoclick()
|
||||
return 1
|
||||
|
||||
/obj/item/gun_control/afterattack(atom/targeted_atom, mob/user)
|
||||
..()
|
||||
var/obj/machinery/manned_turret/E = user.buckled
|
||||
E.setDir(get_dir(E,targeted_atom))
|
||||
user.setDir(E.dir)
|
||||
switch(E.dir)
|
||||
if(NORTH)
|
||||
E.layer = BELOW_MOB_LAYER
|
||||
user.pixel_x = 0
|
||||
user.pixel_y = -14
|
||||
if(NORTHEAST)
|
||||
E.layer = BELOW_MOB_LAYER
|
||||
user.pixel_x = -8
|
||||
user.pixel_y = -4
|
||||
if(EAST)
|
||||
E.layer = ABOVE_MOB_LAYER
|
||||
user.pixel_x = -14
|
||||
user.pixel_y = 0
|
||||
if(SOUTHEAST)
|
||||
E.layer = BELOW_MOB_LAYER
|
||||
user.pixel_x = -8
|
||||
user.pixel_y = 4
|
||||
if(SOUTH)
|
||||
E.layer = ABOVE_MOB_LAYER
|
||||
user.pixel_x = 0
|
||||
user.pixel_y = 14
|
||||
if(SOUTHWEST)
|
||||
E.layer = BELOW_MOB_LAYER
|
||||
user.pixel_x = 8
|
||||
user.pixel_y = 4
|
||||
if(WEST)
|
||||
E.layer = ABOVE_MOB_LAYER
|
||||
user.pixel_x = 14
|
||||
user.pixel_y = 0
|
||||
if(NORTHWEST)
|
||||
E.layer = BELOW_MOB_LAYER
|
||||
user.pixel_x = 8
|
||||
user.pixel_y = -4
|
||||
E.checkfire(targeted_atom, user)
|
||||
|
||||
/obj/machinery/manned_turret/proc/checkfire(atom/targeted_atom, mob/user)
|
||||
target = targeted_atom
|
||||
if(target == user || target == get_turf(src))
|
||||
return
|
||||
if(world.time < cooldown)
|
||||
if(!warned && world.time > (cooldown - cooldown_duration + rate_of_fire*number_of_shots)) // To capture the window where one is done firing
|
||||
warned = TRUE
|
||||
playsound(src, 'sound/weapons/sear.ogg', 100, 1)
|
||||
return
|
||||
else
|
||||
cooldown = world.time + cooldown_duration
|
||||
warned = FALSE
|
||||
INVOKE_ASYNC(src, /obj/machinery/manned_turret/.proc/volley)
|
||||
|
||||
/obj/machinery/manned_turret/proc/volley()
|
||||
target_turf = get_turf(target)
|
||||
for(var/i in 1 to number_of_shots)
|
||||
addtimer(CALLBACK(src, /obj/machinery/manned_turret/.proc/fire_helper), i*rate_of_fire)
|
||||
|
||||
|
||||
/obj/machinery/manned_turret/proc/fire_helper()
|
||||
if(!src)
|
||||
return
|
||||
var/turf/targets_from = get_turf(src)
|
||||
if(QDELETED(target))
|
||||
target = target_turf
|
||||
var/obj/item/projectile/P = new projectile_type(targets_from)
|
||||
P.current = targets_from
|
||||
P.starting = targets_from
|
||||
P.firer = src
|
||||
P.original = target
|
||||
playsound(src, 'sound/weapons/Gunshot_smg.ogg', 75, 1)
|
||||
P.yo = target.y - targets_from.y + rand(-1,1)
|
||||
P.xo = target.x - targets_from.x + rand(-1,1)
|
||||
P.fire()
|
||||
|
||||
/obj/machinery/manned_turret/ultimate // Admin-only proof of concept for autoclicker automatics
|
||||
name = "Infinity Gun"
|
||||
view_range = 12
|
||||
projectile_type = /obj/item/projectile/bullet/weakbullet3
|
||||
|
||||
|
||||
/obj/machinery/manned_turret/ultimate/checkfire(atom/targeted_atom, mob/user)
|
||||
target = targeted_atom
|
||||
if(target == user || target == get_turf(src))
|
||||
return
|
||||
target_turf = get_turf(target)
|
||||
fire_helper(target_turf)
|
||||
|
||||
@@ -1152,6 +1152,32 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
premium = list(/obj/item/clothing/under/suit_jacket/checkered=1,/obj/item/clothing/head/mailman=1,/obj/item/clothing/under/rank/mailman=1,/obj/item/clothing/suit/jacket/leather=1,/obj/item/clothing/suit/jacket/leather/overcoat=1,/obj/item/clothing/under/pants/mustangjeans=1,/obj/item/clothing/neck/necklace/dope=3,/obj/item/clothing/suit/jacket/letterman_nanotrasen=1)
|
||||
refill_canister = /obj/item/weapon/vending_refill/clothing
|
||||
|
||||
/obj/machinery/vending/toyliberationstation
|
||||
name = "\improper Syndicate Donksoft Toy Vendor"
|
||||
desc = "A ages 8 and up approved vendor that dispenses toys. If you were to find the right wires, you can unlock the adult mode setting!"
|
||||
icon_state = "syndi"
|
||||
req_access_txt = "1"
|
||||
product_slogans = "Get your cool toys today!;Trigger a valid hunter today!;Quality toy weapons for cheap prices!;Give them to HoPs for all access!;Give them to HoS to get perma briged!"
|
||||
product_ads = "Feel robust with your toys!;Express your inner child today!;Toy weapons don't kill people, but valid hunters do!;Who needs responsibilities when you have toy weapons?;Make your next murder FUN!"
|
||||
vend_reply = "Come back for more!"
|
||||
products = list(/obj/item/weapon/gun/ballistic/automatic/toy/unrestricted = 10,
|
||||
/obj/item/weapon/gun/ballistic/automatic/toy/pistol/unrestricted = 10,
|
||||
/obj/item/weapon/gun/ballistic/shotgun/toy/unrestricted = 10,
|
||||
/obj/item/toy/sword = 10, /obj/item/ammo_box/foambox = 20,
|
||||
/obj/item/toy/foamblade = 10,
|
||||
/obj/item/toy/syndicateballoon = 10,
|
||||
/obj/item/clothing/suit/syndicatefake = 5,
|
||||
/obj/item/clothing/head/syndicatefake = 5) //OPS IN DORMS oh wait it's just a assistant
|
||||
contraband = list(/obj/item/weapon/gun/ballistic/shotgun/toy/crossbow = 10, //Congrats, you unlocked the +18 setting!
|
||||
/obj/item/weapon/gun/ballistic/automatic/c20r/toy/unrestricted = 10,
|
||||
/obj/item/weapon/gun/ballistic/automatic/l6_saw/toy/unrestricted = 10,
|
||||
/obj/item/ammo_box/foambox/riot = 20,
|
||||
/obj/item/toy/katana = 10,
|
||||
/obj/item/weapon/twohanded/dualsaber/toy = 5,
|
||||
/obj/item/toy/cards/deck/syndicate = 10) //Gambling and it hurts, making it a +18 item
|
||||
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
|
||||
#undef STANDARD_CHARGE
|
||||
#undef CONTRABAND_CHARGE
|
||||
#undef COIN_CHARGE
|
||||
|
||||
@@ -106,36 +106,19 @@
|
||||
icon_state = "mecha_analyzer"
|
||||
selectable = 0
|
||||
equip_cooldown = 30
|
||||
var/scanning = 0
|
||||
var/scanning_time = 0
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/mining_scanner/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/mining_scanner/attach(obj/mecha/M)
|
||||
..()
|
||||
M.occupant_sight_flags |= SEE_TURFS
|
||||
if(M.occupant)
|
||||
M.occupant.update_sight()
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/mining_scanner/detach()
|
||||
chassis.occupant_sight_flags &= ~SEE_TURFS
|
||||
if(chassis.occupant)
|
||||
chassis.occupant.update_sight()
|
||||
return ..()
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/mining_scanner/process()
|
||||
if(!loc)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
qdel(src)
|
||||
if(scanning)
|
||||
return
|
||||
if(istype(loc,/obj/mecha/working))
|
||||
if(istype(loc,/obj/mecha/working) && scanning_time <= world.time)
|
||||
var/obj/mecha/working/mecha = loc
|
||||
if(!mecha.occupant)
|
||||
return
|
||||
var/list/L = list(mecha.occupant)
|
||||
scanning = 1
|
||||
mineral_scan_pulse(L,get_turf(loc))
|
||||
spawn(equip_cooldown)
|
||||
scanning = 0
|
||||
scanning_time = world.time + equip_cooldown
|
||||
mineral_scan_pulse(get_turf(src))
|
||||
|
||||
@@ -93,6 +93,4 @@
|
||||
|
||||
/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM)
|
||||
set waitfor = FALSE
|
||||
var/atom/H = monitor.host
|
||||
testing("HasProx: [H] -> [AM]")
|
||||
H.HasProximity(AM)
|
||||
monitor.host.HasProximity(AM)
|
||||
|
||||
@@ -196,13 +196,6 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( \
|
||||
user.visible_message("[user] starts cutting hair off \the [src].", "<span class='notice'>You start cutting the hair off \the [src]...</span>", "<span class='italics'>You hear the sound of a knife rubbing against flesh.</span>")
|
||||
if(do_after(user,50, target = src))
|
||||
to_chat(user, "<span class='notice'>You cut the hair from this [src.singular_name].</span>")
|
||||
//Try locating an exisitng stack on the tile and add to there if possible
|
||||
for(var/obj/item/stack/sheet/hairlesshide/HS in user.loc)
|
||||
if(HS.amount < 50)
|
||||
HS.amount++
|
||||
use(1)
|
||||
break
|
||||
//If it gets to here it means it did not find a suitable stack on the tile.
|
||||
var/obj/item/stack/sheet/hairlesshide/HS = new(user.loc)
|
||||
HS.amount = 1
|
||||
use(1)
|
||||
@@ -230,3 +223,9 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( \
|
||||
HS.amount = 1
|
||||
wetness = initial(wetness)
|
||||
src.use(1)
|
||||
|
||||
/obj/item/stack/sheet/wetleather/microwave_act(obj/machinery/microwave/MW)
|
||||
..()
|
||||
var/obj/item/stack/sheet/leather/L = new(loc)
|
||||
L.amount = amount
|
||||
qdel(src)
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
M.updateappearance(mutations_overlay_update=1)
|
||||
log_attack(log_msg)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/weapon/dnainjector/attack(mob/target, mob/user)
|
||||
if(!user.IsAdvancedToolUser())
|
||||
@@ -307,11 +308,11 @@
|
||||
|
||||
/obj/item/weapon/dnainjector/timed/inject(mob/living/carbon/M, mob/user)
|
||||
prepare()
|
||||
if(M.stat == DEAD) //prevents dead people from having their DNA changed
|
||||
to_chat(user, "<span class='notice'>You can't modify [M]'s DNA while [M.p_theyre()] dead.</span>")
|
||||
return FALSE
|
||||
|
||||
if(M.has_dna() && !(M.disabilities & NOCLONE))
|
||||
if(M.stat == DEAD) //prevents dead people from having their DNA changed
|
||||
to_chat(user, "<span class='notice'>You can't modify [M]'s DNA while [M.p_theyre()] dead.</span>")
|
||||
return
|
||||
M.radiation += rand(20/(damage_coeff ** 2),50/(damage_coeff ** 2))
|
||||
var/log_msg = "[key_name(user)] injected [key_name(M)] with the [name]"
|
||||
var/endtime = world.time+duration
|
||||
@@ -352,9 +353,9 @@
|
||||
M.updateappearance(mutations_overlay_update=1)
|
||||
M.dna.temporary_mutations[UI_CHANGED] = endtime
|
||||
log_attack(log_msg)
|
||||
return TRUE
|
||||
else
|
||||
to_chat(user, "<span class='notice'>It appears that [M] does not have compatible DNA.</span>")
|
||||
return
|
||||
return FALSE
|
||||
|
||||
/obj/item/weapon/dnainjector/timed/hulk
|
||||
name = "\improper DNA injector (Hulk)"
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
var/mob/living/carbon/human/H = imp_in
|
||||
if(!ishuman(H))
|
||||
return
|
||||
if(istype(H.martial_art, /datum/martial_art/krav_maga))
|
||||
if(!H.mind)
|
||||
return
|
||||
if(istype(H.mind.martial_art, /datum/martial_art/krav_maga))
|
||||
style.remove(H)
|
||||
else
|
||||
style.teach(H,1)
|
||||
|
||||
@@ -247,10 +247,10 @@
|
||||
)
|
||||
|
||||
/obj/item/weapon/storage/belt/military
|
||||
name = "military belt"
|
||||
desc = "A syndicate belt designed to be used by boarding parties. Its style is modeled after the hardsuits they wear."
|
||||
icon_state = "militarybelt"
|
||||
item_state = "military"
|
||||
name = "chest rig"
|
||||
desc = "A set of tactical webbing worn by Syndicate boarding parties."
|
||||
icon_state = "explorer1"
|
||||
item_state = "explorer1"
|
||||
max_w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/weapon/storage/belt/military/abductor
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
new /obj/item/device/flashlight/seclite(src)
|
||||
new /obj/item/clothing/gloves/krav_maga/sec(src)
|
||||
new /obj/item/weapon/door_remote/head_of_security(src)
|
||||
new /obj/item/weapon/gun/ballistic/shotgun/automatic/dual_tube(src)
|
||||
new /obj/item/weapon/gun/ballistic/shotgun/automatic/combat/compact(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/security
|
||||
name = "security officer's locker"
|
||||
|
||||
@@ -152,6 +152,8 @@
|
||||
var/transfer_choice = alert("Transfer your soul to [src]? (Warning, your old body will die!)",,"Yes","No")
|
||||
if(transfer_choice != "Yes")
|
||||
return
|
||||
if(QDELETED(src) || uses <= 0)
|
||||
return
|
||||
log_game("[user.ckey] golem-swapped into [src]")
|
||||
user.visible_message("<span class='notice'>A faint light leaves [user], moving to [src] and animating it!</span>","<span class='notice'>You leave your old body behind, and transfer into [src]!</span>")
|
||||
create(ckey = user.ckey, flavour = FALSE, name = user.real_name)
|
||||
|
||||
@@ -111,6 +111,9 @@
|
||||
initial_gas_mix = "o2=14;n2=23;TEMP=300"
|
||||
planetary_atmos = TRUE
|
||||
baseturf = /turf/open/chasm/straight_down/lava_land_surface
|
||||
light_range = 1.9 //slightly less range than lava
|
||||
light_power = 0.65 //less bright, too
|
||||
light_color = LIGHT_COLOR_LAVA //let's just say you're falling into lava, that makes sense right
|
||||
|
||||
/turf/open/chasm/straight_down/lava_land_surface/drop(atom/movable/AM)
|
||||
//Make sure the item is still there after our sleep
|
||||
|
||||
@@ -73,6 +73,8 @@
|
||||
for(i in 1 to mineralAmt)
|
||||
new mineralType(src)
|
||||
SSblackbox.add_details("ore_mined",mineralType)
|
||||
for(var/obj/effect/temp_visual/mining_overlay/M in src)
|
||||
qdel(M)
|
||||
ChangeTurf(turf_type, defer_change)
|
||||
addtimer(CALLBACK(src, .proc/AfterChange), 1, TIMER_UNIQUE)
|
||||
playsound(src, 'sound/effects/break_stone.ogg', 50, 1) //beautiful destruction
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
/obj/machinery/meter/Initialize(mapload)
|
||||
. = ..()
|
||||
SSair.atmos_machinery += src
|
||||
if (mapload && !target)
|
||||
if (!target)
|
||||
target = locate(/obj/machinery/atmospherics/pipe) in loc
|
||||
|
||||
/obj/machinery/meter/Destroy()
|
||||
|
||||
@@ -271,6 +271,8 @@ BLIND // can't see anything
|
||||
/obj/item/clothing/head
|
||||
name = "head"
|
||||
icon = 'icons/obj/clothing/hats.dmi'
|
||||
icon_state = "top_hat"
|
||||
item_state = "that"
|
||||
body_parts_covered = HEAD
|
||||
slot_flags = SLOT_HEAD
|
||||
var/blockTracking = 0 //For AI tracking
|
||||
|
||||
@@ -7,25 +7,34 @@
|
||||
actions_types = list(/datum/action/item_action/toggle_mode)
|
||||
origin_tech = "materials=3;magnets=3;engineering=3;plasmatech=3"
|
||||
|
||||
var/mode = 0 //0 - regular mesons mode 1 - t-ray mode
|
||||
mode = FALSE //FALSE - regular mesons mode TRUE - t-ray mode
|
||||
var/range = 1
|
||||
|
||||
/obj/item/clothing/glasses/meson/engine/attack_self(mob/user)
|
||||
/obj/item/clothing/glasses/meson/engine/toggle_mode(mob/user, voluntary)
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && T.z == ZLEVEL_MINING && mode)
|
||||
if(picked_excuse)
|
||||
to_chat(user, "<span class='warning'>Due to [picked_excuse], the [name] cannot currently be swapped to \[Meson] mode.</span>")
|
||||
return
|
||||
mode = !mode
|
||||
|
||||
if(mode)
|
||||
START_PROCESSING(SSobj, src)
|
||||
vision_flags = 0
|
||||
darkness_view = 2
|
||||
invis_view = SEE_INVISIBLE_LIVING
|
||||
lighting_alpha = null
|
||||
to_chat(user, "<span class='notice'>You toggle the goggles' scanning mode to \[T-Ray].</span>")
|
||||
if(voluntary)
|
||||
to_chat(user, "<span class='notice'>You toggle the goggles' scanning mode to \[T-Ray].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The goggles abruptly toggle to \[T-Ray] mode!</span>")
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
vision_flags = SEE_TURFS
|
||||
darkness_view = 1
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
|
||||
to_chat(loc, "<span class='notice'>You toggle the goggles' scanning mode to \[Meson].</span>")
|
||||
if(voluntary)
|
||||
to_chat(user, "<span class='notice'>You toggle the goggles' scanning mode to \[Meson].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>The goggles abruptly toggle to \[Meson] mode!</span>")
|
||||
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
@@ -37,8 +46,14 @@
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
|
||||
/obj/item/clothing/glasses/meson/engine/attack_self(mob/user)
|
||||
toggle_mode(user, TRUE)
|
||||
|
||||
/obj/item/clothing/glasses/meson/engine/process()
|
||||
if(!mode)
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && T.z == ZLEVEL_MINING)
|
||||
toggle_mode(loc)
|
||||
return
|
||||
|
||||
if(!ishuman(loc))
|
||||
@@ -47,7 +62,6 @@
|
||||
var/mob/living/carbon/human/user = loc
|
||||
if(user.glasses != src)
|
||||
return
|
||||
|
||||
scan()
|
||||
|
||||
/obj/item/clothing/glasses/meson/engine/proc/scan()
|
||||
@@ -89,13 +103,17 @@
|
||||
icon_state = "trayson-tray_off"
|
||||
origin_tech = "materials=3;magnets=2;engineering=2"
|
||||
|
||||
mode = 1
|
||||
var/on = 0
|
||||
mode = TRUE
|
||||
var/on = FALSE
|
||||
vision_flags = 0
|
||||
darkness_view = 2
|
||||
invis_view = SEE_INVISIBLE_LIVING
|
||||
range = 2
|
||||
|
||||
/obj/item/clothing/glasses/meson/engine/tray/Initialize()
|
||||
. = ..()
|
||||
picked_excuse = null
|
||||
|
||||
/obj/item/clothing/glasses/meson/engine/tray/process()
|
||||
if(!on)
|
||||
return
|
||||
@@ -108,15 +126,10 @@
|
||||
if(user.glasses == src)
|
||||
user.update_inv_glasses()
|
||||
|
||||
/obj/item/clothing/glasses/meson/engine/tray/attack_self(mob/user)
|
||||
/obj/item/clothing/glasses/meson/engine/tray/toggle_mode(mob/user, voluntary)
|
||||
on = !on
|
||||
|
||||
if(on)
|
||||
START_PROCESSING(SSobj, src)
|
||||
to_chat(user, "<span class='notice'>You turn the goggles on.</span>")
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
to_chat(user, "<span class='notice'>You turn the goggles off.</span>")
|
||||
to_chat(user, "<span class='[voluntary ? "notice":"warning"]'>[voluntary ? "You turn the goggles":"The goggles turn"] [on ? "on":"off"][voluntary ? ".":"!"]</span>")
|
||||
|
||||
update_icon()
|
||||
for(var/X in actions)
|
||||
|
||||
@@ -31,14 +31,60 @@
|
||||
|
||||
/obj/item/clothing/glasses/meson
|
||||
name = "Optical Meson Scanner"
|
||||
desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting condition."
|
||||
desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting conditions."
|
||||
icon_state = "meson"
|
||||
item_state = "meson"
|
||||
origin_tech = "magnets=1;engineering=2"
|
||||
darkness_view = 2
|
||||
vision_flags = SEE_TURFS
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
|
||||
glass_colour_type = /datum/client_colour/glass_colour/lightgreen
|
||||
var/static/list/meson_mining_failure_excuses = list("seismic activity", "excessive lava", "ambient radiation", "electromagnetic storms", "bluespace disruption", \
|
||||
"gravity", "dust", "dense rock", "ash", "badly understood science", "radiant heat")
|
||||
var/picked_excuse
|
||||
var/mode = FALSE //if FALSE, is in normal meson mode.
|
||||
|
||||
/obj/item/clothing/glasses/meson/Initialize()
|
||||
. = ..()
|
||||
picked_excuse = pick(meson_mining_failure_excuses)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/clothing/glasses/meson/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/glasses/meson/examine(mob/user)
|
||||
..()
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && T.z == ZLEVEL_MINING && mode && picked_excuse)
|
||||
to_chat(user, "<span class='warning'>Due to [picked_excuse], these Meson Scanners will not be able to display terrain layouts in this area.</span>")
|
||||
|
||||
/obj/item/clothing/glasses/meson/proc/toggle_mode(mob/user)
|
||||
if(vision_flags & SEE_TURFS)
|
||||
mode = TRUE
|
||||
vision_flags &= ~SEE_TURFS
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(picked_excuse)
|
||||
to_chat(H, "<span class='warning'>Due to [picked_excuse], your Meson Scanners will not be able to display terrain layouts in this area.</span>")
|
||||
if(H.glasses == src)
|
||||
H.update_sight()
|
||||
else if(!(vision_flags & SEE_TURFS))
|
||||
mode = FALSE
|
||||
vision_flags |= SEE_TURFS
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
to_chat(H, "<span class='notice'>Your Meson Scanners have reactivated.</span>")
|
||||
if(H.glasses == src)
|
||||
H.update_sight()
|
||||
|
||||
/obj/item/clothing/glasses/meson/process()
|
||||
var/turf/T = get_turf(src)
|
||||
if(T && T.z == ZLEVEL_MINING)
|
||||
if(!mode)
|
||||
toggle_mode(loc)
|
||||
else if(mode)
|
||||
toggle_mode(loc)
|
||||
|
||||
/obj/item/clothing/glasses/meson/night
|
||||
name = "Night Vision Optical Meson Scanner"
|
||||
@@ -47,7 +93,7 @@
|
||||
item_state = "nvgmeson"
|
||||
origin_tech = "magnets=4;engineering=5;plasmatech=4"
|
||||
darkness_view = 8
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
|
||||
glass_colour_type = /datum/client_colour/glass_colour/green
|
||||
|
||||
/obj/item/clothing/glasses/meson/gar
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
|
||||
/obj/item/clothing/suit/armor/vest
|
||||
name = "armor vest"
|
||||
desc = "A slim armored vest that protects against most types of damage."
|
||||
desc = "A slim Type I armored vest that provides decent protection against most types of damage."
|
||||
icon_state = "armoralt"
|
||||
item_state = "armoralt"
|
||||
blood_overlay_type = "armor"
|
||||
dog_fashion = /datum/dog_fashion/back
|
||||
|
||||
/obj/item/clothing/suit/armor/vest/alt
|
||||
desc = "An armored vest that protects against most types of damage."
|
||||
desc = "A Type I armored vest that provides decent protection against most types of damage."
|
||||
icon_state = "armor"
|
||||
item_state = "armor"
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
/obj/item/clothing/suit/armor/hos
|
||||
name = "armored greatcoat"
|
||||
desc = "A greatcoat enchanced with a special alloy for some protection and style for those with a commanding presence."
|
||||
desc = "A greatcoat enhanced with a special alloy for some extra protection and style for those with a commanding presence."
|
||||
icon_state = "hos"
|
||||
item_state = "greatcoat"
|
||||
body_parts_covered = CHEST|GROIN|ARMS|LEGS
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
/obj/item/clothing/suit/armor/vest/capcarapace
|
||||
name = "captain's carapace"
|
||||
desc = "An armored vest reinforced with ceramic plates and pauldrons to provide additional protection whilst still offering maximum mobility and flexibility. Issued only to the station's finest, although it does chafe your nipples."
|
||||
desc = "An fireproof armored chestpiece reinforced with ceramic plates and plasteel pauldrons to provide additional protection whilst still offering maximum mobility and flexibility. Issued only to the station's finest, although it does chafe your nipples."
|
||||
icon_state = "capcarapace"
|
||||
item_state = "armor"
|
||||
body_parts_covered = CHEST|GROIN
|
||||
@@ -93,7 +93,7 @@
|
||||
|
||||
/obj/item/clothing/suit/armor/riot
|
||||
name = "riot suit"
|
||||
desc = "A suit of armor with heavy padding to protect against melee attacks."
|
||||
desc = "A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks."
|
||||
icon_state = "riot"
|
||||
item_state = "swat_suit"
|
||||
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
|
||||
@@ -115,7 +115,7 @@
|
||||
|
||||
/obj/item/clothing/suit/armor/bulletproof
|
||||
name = "bulletproof armor"
|
||||
desc = "A bulletproof vest that excels in protecting the wearer against traditional projectile weaponry and explosives to a minor extent."
|
||||
desc = "A Type III heavy bulletproof vest that excels in protecting the wearer against traditional projectile weaponry and explosives to a minor extent."
|
||||
icon_state = "bulletproof"
|
||||
item_state = "armor"
|
||||
blood_overlay_type = "armor"
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
var/square_depth_up = 0
|
||||
var/square_depth_down = 0
|
||||
//Processing
|
||||
var/requires_processing = FALSE
|
||||
var/process_inner_turfs = FALSE //Don't do this unless it's absolutely necessary
|
||||
var/process_edge_turfs = FALSE //Don't do this either unless it's absolutely necessary, you can just track what things are inside manually or on the initial setup.
|
||||
var/setup_edge_turfs = FALSE //Setup edge turfs/all field turfs. Set either or both to ON when you need it, it's defaulting to off unless you do to save CPU.
|
||||
@@ -40,11 +39,7 @@
|
||||
var/list/turf/field_turfs_new = list()
|
||||
var/list/turf/edge_turfs_new = list()
|
||||
|
||||
/datum/proximity_monitor/advanced/New()
|
||||
SSfields.register_new_field(src)
|
||||
|
||||
/datum/proximity_monitor/advanced/Destroy()
|
||||
SSfields.unregister_field(src)
|
||||
full_cleanup()
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
//Only use square radius for this!
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener
|
||||
name = "\improper Hyperkinetic Dampener Field"
|
||||
requires_processing = TRUE
|
||||
setup_edge_turfs = TRUE
|
||||
setup_field_turfs = TRUE
|
||||
field_shape = FIELD_SHAPE_RADIUS_SQUARE
|
||||
@@ -22,10 +21,15 @@
|
||||
use_host_turf = TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/New()
|
||||
START_PROCESSING(SSfields, src)
|
||||
tracked = list()
|
||||
staging = list()
|
||||
..()
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/Destroy()
|
||||
STOP_PROCESSING(SSfields, src)
|
||||
return ..()
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/process()
|
||||
if(!istype(projector))
|
||||
qdel(src)
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
|
||||
/datum/language_holder/synthetic
|
||||
languages = list(/datum/language/common)
|
||||
shadow_languages = list(/datum/language/machine, /datum/language/draconic)
|
||||
shadow_languages = list(/datum/language/common, /datum/language/machine, /datum/language/draconic)
|
||||
|
||||
/datum/language_holder/universal/New()
|
||||
..()
|
||||
|
||||
@@ -270,7 +270,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
if(5)
|
||||
dat += "<H3>Upload a New Title</H3>"
|
||||
if(!scanner)
|
||||
findscanner(9)
|
||||
scanner = findscanner(9)
|
||||
if(!scanner)
|
||||
dat += "<FONT color=red>No scanner found within wireless network range.</FONT><BR>"
|
||||
else if(!scanner.cache)
|
||||
@@ -314,7 +314,7 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/libraryconsole/bookmanagement/proc/findscanner(viewrange)
|
||||
for(var/obj/machinery/libraryscanner/S in range(viewrange))
|
||||
for(var/obj/machinery/libraryscanner/S in range(viewrange, get_turf(src)))
|
||||
return S
|
||||
return null
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
icon_state = "resonator"
|
||||
item_state = "resonator"
|
||||
desc = "A handheld device that creates small fields of energy that resonate until they detonate, crushing rock. It can also be activated without a target to create a field at the user's location, to act as a delayed time trap. It's more effective in a vacuum."
|
||||
desc = "A handheld device that creates small fields of energy that resonate until they detonate, crushing rock. It's more effective in a vacuum."
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
force = 15
|
||||
throwforce = 10
|
||||
@@ -188,18 +188,6 @@
|
||||
fieldlimit = 6
|
||||
quick_burst_mod = 1
|
||||
|
||||
/obj/item/weapon/resonator/proc/CreateResonance(target, creator)
|
||||
var/turf/T = get_turf(target)
|
||||
var/obj/effect/resonance/R = locate(/obj/effect/resonance) in T
|
||||
if(R)
|
||||
R.resonance_damage *= quick_burst_mod
|
||||
R.burst()
|
||||
return
|
||||
if(fields.len < fieldlimit)
|
||||
playsound(src,'sound/weapons/resonator_fire.ogg',50,1)
|
||||
var/obj/effect/resonance/RE = new(T, creator, burst_time, src)
|
||||
fields += RE
|
||||
|
||||
/obj/item/weapon/resonator/attack_self(mob/user)
|
||||
if(burst_time == 50)
|
||||
burst_time = 30
|
||||
@@ -208,57 +196,76 @@
|
||||
burst_time = 50
|
||||
to_chat(user, "<span class='info'>You set the resonator's fields to detonate after 5 seconds.</span>")
|
||||
|
||||
/obj/item/weapon/resonator/afterattack(atom/target, mob/user, proximity_flag)
|
||||
if(proximity_flag)
|
||||
if(!check_allowed_items(target, 1))
|
||||
return
|
||||
/obj/item/weapon/resonator/proc/CreateResonance(target, mob/user)
|
||||
var/turf/T = get_turf(target)
|
||||
var/obj/effect/temp_visual/resonance/R = locate(/obj/effect/temp_visual/resonance) in T
|
||||
if(R)
|
||||
R.damage_multiplier = quick_burst_mod
|
||||
R.burst()
|
||||
return
|
||||
if(LAZYLEN(fields) < fieldlimit)
|
||||
new /obj/effect/temp_visual/resonance(T, user, src, burst_time)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
CreateResonance(target, user)
|
||||
|
||||
/obj/effect/resonance
|
||||
/obj/item/weapon/resonator/pre_attackby(atom/target, mob/user, params)
|
||||
if(check_allowed_items(target, 1))
|
||||
CreateResonance(target, user)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/temp_visual/resonance
|
||||
name = "resonance field"
|
||||
desc = "A resonating field that significantly damages anything inside of it when the field eventually ruptures. More damaging in low pressure environments."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "shield1"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
anchored = TRUE
|
||||
mouse_opacity = 0
|
||||
duration = 50
|
||||
var/resonance_damage = 20
|
||||
var/damage_multiplier = 1
|
||||
var/creator
|
||||
var/obj/item/weapon/resonator/res
|
||||
|
||||
/obj/effect/resonance/New(loc, set_creator, timetoburst, set_resonator)
|
||||
..()
|
||||
/obj/effect/temp_visual/resonance/Initialize(mapload, set_creator, set_resonator, set_duration)
|
||||
duration = set_duration
|
||||
. = ..()
|
||||
creator = set_creator
|
||||
res = set_resonator
|
||||
check_pressure()
|
||||
addtimer(CALLBACK(src, .proc/burst), timetoburst)
|
||||
if(res)
|
||||
res.fields += src
|
||||
playsound(src,'sound/weapons/resonator_fire.ogg',50,1)
|
||||
transform = matrix()*0.75
|
||||
animate(src, transform = matrix()*1.5, time = duration)
|
||||
deltimer(timerid)
|
||||
timerid = addtimer(CALLBACK(src, .proc/burst), duration, TIMER_STOPPABLE)
|
||||
|
||||
/obj/effect/resonance/Destroy()
|
||||
/obj/effect/temp_visual/resonance/Destroy()
|
||||
if(res)
|
||||
res.fields -= src
|
||||
res = null
|
||||
creator = null
|
||||
. = ..()
|
||||
|
||||
/obj/effect/resonance/proc/check_pressure()
|
||||
var/turf/proj_turf = get_turf(src)
|
||||
/obj/effect/temp_visual/resonance/proc/check_pressure(turf/proj_turf)
|
||||
if(!proj_turf)
|
||||
proj_turf = get_turf(src)
|
||||
if(!istype(proj_turf))
|
||||
return
|
||||
var/datum/gas_mixture/environment = proj_turf.return_air()
|
||||
var/pressure = environment.return_pressure()
|
||||
resonance_damage = initial(resonance_damage)
|
||||
if(pressure < 50)
|
||||
name = "strong [initial(name)]"
|
||||
resonance_damage = 60
|
||||
resonance_damage *= 3
|
||||
else
|
||||
name = initial(name)
|
||||
resonance_damage = initial(resonance_damage)
|
||||
resonance_damage *= damage_multiplier
|
||||
|
||||
/obj/effect/resonance/proc/burst()
|
||||
check_pressure()
|
||||
/obj/effect/temp_visual/resonance/proc/burst()
|
||||
var/turf/T = get_turf(src)
|
||||
playsound(src,'sound/weapons/resonator_blast.ogg',50,1)
|
||||
new /obj/effect/temp_visual/resonance_crush(T)
|
||||
if(ismineralturf(T))
|
||||
var/turf/closed/mineral/M = T
|
||||
M.gets_drilled(creator)
|
||||
check_pressure(T)
|
||||
playsound(T,'sound/weapons/resonator_blast.ogg',50,1)
|
||||
for(var/mob/living/L in T)
|
||||
if(creator)
|
||||
add_logs(creator, L, "used a resonator field on", "resonator")
|
||||
@@ -266,6 +273,16 @@
|
||||
L.apply_damage(resonance_damage, BRUTE)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/temp_visual/resonance_crush
|
||||
icon_state = "shield1"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
duration = 4
|
||||
|
||||
/obj/effect/temp_visual/resonance_crush/Initialize()
|
||||
. = ..()
|
||||
transform = matrix()*1.5
|
||||
animate(src, transform = matrix()*0.1, alpha = 50, time = 4)
|
||||
|
||||
/**********************Facehugger toy**********************/
|
||||
|
||||
/obj/item/clothing/mask/facehugger/toy
|
||||
@@ -345,28 +362,23 @@
|
||||
/**********************Mining Scanners**********************/
|
||||
|
||||
/obj/item/device/mining_scanner
|
||||
desc = "A scanner that checks surrounding rock for useful minerals; it can also be used to stop gibtonite detonations. Wear material scanners for optimal results."
|
||||
desc = "A scanner that checks surrounding rock for useful minerals; it can also be used to stop gibtonite detonations."
|
||||
name = "manual mining scanner"
|
||||
icon_state = "mining1"
|
||||
item_state = "analyzer"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BELT
|
||||
var/cooldown = 0
|
||||
var/cooldown = 35
|
||||
var/current_cooldown = 0
|
||||
origin_tech = "engineering=1;magnets=1"
|
||||
|
||||
/obj/item/device/mining_scanner/attack_self(mob/user)
|
||||
if(!user.client)
|
||||
return
|
||||
if(!cooldown)
|
||||
cooldown = TRUE
|
||||
addtimer(CALLBACK(src, .proc/clear_cooldown), 40)
|
||||
var/list/mobs = list()
|
||||
mobs |= user
|
||||
mineral_scan_pulse(mobs, get_turf(user))
|
||||
|
||||
/obj/item/device/mining_scanner/proc/clear_cooldown()
|
||||
cooldown = FALSE
|
||||
if(current_cooldown <= world.time)
|
||||
current_cooldown = world.time + cooldown
|
||||
mineral_scan_pulse(get_turf(user))
|
||||
|
||||
|
||||
//Debug item to identify all ore spread quickly
|
||||
@@ -379,7 +391,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/device/t_scanner/adv_mining_scanner
|
||||
desc = "A scanner that automatically checks surrounding rock for useful minerals; it can also be used to stop gibtonite detonations. Wear meson scanners for optimal results. This one has an extended range."
|
||||
desc = "A scanner that automatically checks surrounding rock for useful minerals; it can also be used to stop gibtonite detonations. This one has an extended range."
|
||||
name = "advanced automatic mining scanner"
|
||||
icon_state = "mining0"
|
||||
item_state = "analyzer"
|
||||
@@ -387,77 +399,47 @@
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BELT
|
||||
var/cooldown = 35
|
||||
var/on_cooldown = 0
|
||||
var/current_cooldown = 0
|
||||
var/range = 7
|
||||
var/meson = TRUE
|
||||
origin_tech = "engineering=3;magnets=3"
|
||||
|
||||
/obj/item/device/t_scanner/adv_mining_scanner/material
|
||||
meson = FALSE
|
||||
desc = "A scanner that automatically checks surrounding rock for useful minerals; it can also be used to stop gibtonite detonations. Wear material scanners for optimal results. This one has an extended range."
|
||||
|
||||
/obj/item/device/t_scanner/adv_mining_scanner/lesser
|
||||
name = "automatic mining scanner"
|
||||
desc = "A scanner that automatically checks surrounding rock for useful minerals; it can also be used to stop gibtonite detonations. Wear meson scanners for optimal results."
|
||||
desc = "A scanner that automatically checks surrounding rock for useful minerals; it can also be used to stop gibtonite detonations."
|
||||
range = 4
|
||||
cooldown = 50
|
||||
|
||||
/obj/item/device/t_scanner/adv_mining_scanner/lesser/material
|
||||
desc = "A scanner that automatically checks surrounding rock for useful minerals; it can also be used to stop gibtonite detonations. Wear material scanners for optimal results."
|
||||
meson = FALSE
|
||||
|
||||
/obj/item/device/t_scanner/adv_mining_scanner/scan()
|
||||
if(!on_cooldown)
|
||||
on_cooldown = 1
|
||||
spawn(cooldown)
|
||||
on_cooldown = 0
|
||||
if(current_cooldown <= world.time)
|
||||
current_cooldown = world.time + cooldown
|
||||
var/turf/t = get_turf(src)
|
||||
var/list/mobs = recursive_mob_check(t, 1,0,0)
|
||||
if(!mobs.len)
|
||||
return
|
||||
if(meson)
|
||||
mineral_scan_pulse(mobs, t, range)
|
||||
else
|
||||
mineral_scan_pulse_material(mobs, t, range)
|
||||
mineral_scan_pulse(t, range)
|
||||
|
||||
//For use with mesons
|
||||
/proc/mineral_scan_pulse(list/mobs, turf/T, range = world.view)
|
||||
/proc/mineral_scan_pulse(turf/T, range = world.view)
|
||||
var/list/minerals = list()
|
||||
for(var/turf/closed/mineral/M in range(range, T))
|
||||
if(M.scan_state)
|
||||
minerals += M
|
||||
if(minerals.len)
|
||||
for(var/mob/user in mobs)
|
||||
if(user.client)
|
||||
var/client/C = user.client
|
||||
for(var/turf/closed/mineral/M in minerals)
|
||||
var/turf/F = get_turf(M)
|
||||
var/image/I = image('icons/turf/smoothrocks.dmi', loc = F, icon_state = M.scan_state, layer = FLASH_LAYER)
|
||||
I.plane = FULLSCREEN_PLANE
|
||||
C.images += I
|
||||
spawn(30)
|
||||
if(C)
|
||||
C.images -= I
|
||||
|
||||
//For use with material scanners
|
||||
/proc/mineral_scan_pulse_material(list/mobs, turf/T, range = world.view)
|
||||
var/list/minerals = list()
|
||||
for(var/turf/closed/mineral/M in range(range, T))
|
||||
if(M.scan_state)
|
||||
minerals += M
|
||||
if(minerals.len)
|
||||
if(LAZYLEN(minerals))
|
||||
for(var/turf/closed/mineral/M in minerals)
|
||||
var/obj/effect/temp_visual/mining_overlay/oldC = locate(/obj/effect/temp_visual/mining_overlay) in M
|
||||
if(oldC)
|
||||
qdel(oldC)
|
||||
var/obj/effect/temp_visual/mining_overlay/C = new /obj/effect/temp_visual/mining_overlay(M)
|
||||
C.icon_state = M.scan_state
|
||||
|
||||
/obj/effect/temp_visual/mining_overlay
|
||||
plane = FULLSCREEN_PLANE
|
||||
layer = FLASH_LAYER
|
||||
icon = 'icons/turf/smoothrocks.dmi'
|
||||
anchored = 1
|
||||
mouse_opacity = 0
|
||||
duration = 30
|
||||
pixel_x = -4
|
||||
pixel_y = -4
|
||||
icon = 'icons/effects/ore_visuals.dmi'
|
||||
appearance_flags = 0 //to avoid having TILE_BOUND in the flags, so that the 480x480 icon states let you see it no matter where you are
|
||||
duration = 35
|
||||
pixel_x = -224
|
||||
pixel_y = -224
|
||||
|
||||
/obj/effect/temp_visual/mining_overlay/Initialize()
|
||||
. = ..()
|
||||
animate(src, alpha = 0, time = duration, easing = EASE_IN)
|
||||
|
||||
|
||||
/**********************Xeno Warning Sign**********************/
|
||||
@@ -529,7 +511,6 @@
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/destabilizer/on_hit(atom/target, blocked = 0)
|
||||
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
var/datum/status_effect/crusher_mark/CM = L.apply_status_effect(STATUS_EFFECT_CRUSHERMARK)
|
||||
@@ -539,7 +520,6 @@
|
||||
var/turf/closed/mineral/M = target_turf
|
||||
new /obj/effect/temp_visual/kinetic_blast(M)
|
||||
M.gets_drilled(firer)
|
||||
|
||||
..()
|
||||
|
||||
/obj/item/weapon/twohanded/required/mining_hammer/afterattack(atom/target, mob/user, proximity_flag)
|
||||
@@ -570,7 +550,6 @@
|
||||
else
|
||||
L.apply_damage(50, BRUTE, blocked = def_check)
|
||||
|
||||
|
||||
/obj/item/weapon/twohanded/required/mining_hammer/proc/Recharge()
|
||||
if(!charged)
|
||||
charged = TRUE
|
||||
|
||||
@@ -821,7 +821,9 @@
|
||||
timer = world.time + cooldown_time
|
||||
if(isliving(target) && chaser_timer <= world.time) //living and chasers off cooldown? fire one!
|
||||
chaser_timer = world.time + chaser_cooldown
|
||||
new /obj/effect/temp_visual/hierophant/chaser(get_turf(user), user, target, chaser_speed, friendly_fire_check)
|
||||
var/obj/effect/temp_visual/hierophant/chaser/C = new(get_turf(user), user, target, chaser_speed, friendly_fire_check)
|
||||
C.damage = 30
|
||||
C.monster_damage_boost = FALSE
|
||||
add_logs(user, target, "fired a chaser at", src)
|
||||
else
|
||||
INVOKE_ASYNC(src, .proc/cardinal_blasts, T, user) //otherwise, just do cardinal blast
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/weapon/hivelordstabilizer, 400),
|
||||
new /datum/data/mining_equipment("Fulton Beacon", /obj/item/fulton_core, 400),
|
||||
new /datum/data/mining_equipment("Shelter Capsule", /obj/item/weapon/survivalcapsule, 400),
|
||||
new /datum/data/mining_equipment("GAR scanners", /obj/item/clothing/glasses/meson/gar, 500),
|
||||
new /datum/data/mining_equipment("GAR Meson Scanners", /obj/item/clothing/glasses/meson/gar, 500),
|
||||
new /datum/data/mining_equipment("Explorer's Webbing", /obj/item/weapon/storage/belt/mining, 500),
|
||||
new /datum/data/mining_equipment("Survival Medipen", /obj/item/weapon/reagent_containers/hypospray/medipen/survival, 500),
|
||||
new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/weapon/storage/firstaid/brute, 600),
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
var/light_on = 0
|
||||
|
||||
var/datum/action/innate/minedrone/toggle_light/toggle_light_action
|
||||
var/datum/action/innate/minedrone/toggle_meson_vision/toggle_meson_vision_action
|
||||
var/datum/action/innate/minedrone/toggle_mode/toggle_mode_action
|
||||
var/datum/action/innate/minedrone/dump_ore/dump_ore_action
|
||||
|
||||
@@ -52,8 +51,6 @@
|
||||
..()
|
||||
toggle_light_action = new()
|
||||
toggle_light_action.Grant(src)
|
||||
toggle_meson_vision_action = new()
|
||||
toggle_meson_vision_action.Grant(src)
|
||||
toggle_mode_action = new()
|
||||
toggle_mode_action.Grant(src)
|
||||
dump_ore_action = new()
|
||||
@@ -189,23 +186,6 @@
|
||||
user.light_on = !user.light_on
|
||||
to_chat(user, "<span class='notice'>You toggle your light [user.light_on ? "on" : "off"].</span>")
|
||||
|
||||
/datum/action/innate/minedrone/toggle_meson_vision
|
||||
name = "Toggle Meson Vision"
|
||||
button_icon_state = "meson"
|
||||
|
||||
/datum/action/innate/minedrone/toggle_meson_vision/Activate()
|
||||
var/mob/living/simple_animal/hostile/mining_drone/user = owner
|
||||
if(user.sight & SEE_TURFS)
|
||||
user.sight &= ~SEE_TURFS
|
||||
user.lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
|
||||
else
|
||||
user.sight |= SEE_TURFS
|
||||
user.lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
|
||||
|
||||
user.sync_lighting_plane_alpha()
|
||||
|
||||
to_chat(user, "<span class='notice'>You toggle your meson vision [(user.sight & SEE_TURFS) ? "on" : "off"].</span>")
|
||||
|
||||
/datum/action/innate/minedrone/toggle_mode
|
||||
name = "Toggle Mode"
|
||||
button_icon_state = "mech_cycle_equip_off"
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
//initialise organs
|
||||
create_internal_organs()
|
||||
|
||||
martial_art = default_martial_art
|
||||
if(mind)
|
||||
mind.martial_art = mind.default_martial_art
|
||||
|
||||
handcrafting = new()
|
||||
|
||||
|
||||
@@ -40,12 +40,13 @@
|
||||
if(spec_return)
|
||||
return spec_return
|
||||
|
||||
if(martial_art && martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
|
||||
if(prob(martial_art.deflection_chance))
|
||||
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
|
||||
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
|
||||
return 0
|
||||
if(mind)
|
||||
if(mind.martial_art && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
|
||||
if(prob(mind.martial_art.deflection_chance))
|
||||
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
|
||||
visible_message("<span class='danger'>[src] deflects the projectile; [p_they()] can't be hit with ranged weapons!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
|
||||
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
|
||||
return 0
|
||||
|
||||
if(!(P.original == src && P.firer == src)) //can't block or reflect when shooting yourself
|
||||
if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam))
|
||||
@@ -103,10 +104,11 @@
|
||||
return 0
|
||||
|
||||
/mob/living/carbon/human/proc/check_block()
|
||||
if(martial_art && martial_art.block_chance \
|
||||
&& prob(martial_art.block_chance) && in_throw_mode \
|
||||
&& !stat && !weakened && !stunned)
|
||||
return TRUE
|
||||
if(mind)
|
||||
if(mind.martial_art && mind.martial_art.block_chance \
|
||||
&& prob(mind.martial_art.block_chance) && in_throw_mode \
|
||||
&& !stat && !weakened && !stunned)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
var/bleed_rate = 0 //how much are we bleeding
|
||||
var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding
|
||||
|
||||
var/datum/martial_art/martial_art = null
|
||||
var/static/default_martial_art = new/datum/martial_art
|
||||
|
||||
var/name_override //For temporary visible name changes
|
||||
|
||||
var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects
|
||||
|
||||
@@ -144,9 +144,9 @@
|
||||
if(NOGUNS in src.dna.species.species_traits)
|
||||
to_chat(src, "<span class='warning'>Your fingers don't fit in the trigger guard!</span>")
|
||||
return 0
|
||||
|
||||
if(martial_art && martial_art.no_guns) //great dishonor to famiry
|
||||
to_chat(src, "<span class='warning'>Use of ranged weaponry would bring dishonor to the clan.</span>")
|
||||
return 0
|
||||
if(mind)
|
||||
if(mind.martial_art && mind.martial_art.no_guns) //great dishonor to famiry
|
||||
to_chat(src, "<span class='warning'>Use of ranged weaponry would bring dishonor to the clan.</span>")
|
||||
return 0
|
||||
|
||||
return .
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/mob/living/carbon/human/Login()
|
||||
..()
|
||||
if(src.martial_art == default_martial_art && mind.stored_martial_art) //If the mind has a martial art stored and the body has the default one.
|
||||
src.mind.stored_martial_art.teach(src) //Running teach so that it deals with help verbs.
|
||||
else if(src.martial_art != default_martial_art && src.martial_art != mind.stored_martial_art) //If the body has a martial art which is not the default one and is not stored in the mind.
|
||||
if(src.martial_art_owner != mind)
|
||||
src.martial_art.remove(src)
|
||||
else
|
||||
src.mind.stored_martial_art = src.martial_art
|
||||
@@ -1304,7 +1304,7 @@
|
||||
/datum/species/proc/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
|
||||
return
|
||||
|
||||
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style = M.martial_art)
|
||||
/datum/species/proc/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
|
||||
if(!istype(M))
|
||||
return
|
||||
CHECK_DNA_AND_SPECIES(M)
|
||||
@@ -1312,6 +1312,8 @@
|
||||
|
||||
if(!istype(M)) //sanity check for drones.
|
||||
return
|
||||
if(M.mind)
|
||||
attacker_style = M.mind.martial_art
|
||||
if((M != H) && M.a_intent != INTENT_HELP && H.check_shields(0, M.name, attack_type = UNARMED_ATTACK))
|
||||
add_logs(M, H, "attempted to touch")
|
||||
H.visible_message("<span class='warning'>[M] attempted to touch [H]!</span>")
|
||||
|
||||
@@ -406,7 +406,7 @@
|
||||
else
|
||||
reactive_teleport(H)
|
||||
|
||||
/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style = M.martial_art)
|
||||
/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
|
||||
..()
|
||||
if(world.time > last_teleport + teleport_cooldown && M != H && M.a_intent != INTENT_HELP)
|
||||
reactive_teleport(H)
|
||||
@@ -490,7 +490,7 @@
|
||||
var/golem_name = "[uppertext(clown_name)]"
|
||||
return golem_name
|
||||
|
||||
/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style = M.martial_art)
|
||||
/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
|
||||
..()
|
||||
if(world.time > last_banana + banana_cooldown && M != H && M.a_intent != INTENT_HELP)
|
||||
new/obj/item/weapon/grown/bananapeel/specialpeel(get_turf(H))
|
||||
|
||||
@@ -526,7 +526,6 @@
|
||||
name = "Miner"
|
||||
basic_modules = list(
|
||||
/obj/item/device/assembly/flash/cyborg,
|
||||
/obj/item/borg/sight/meson,
|
||||
/obj/item/weapon/storage/bag/ore/cyborg,
|
||||
/obj/item/weapon/pickaxe/drill/cyborg,
|
||||
/obj/item/weapon/shovel,
|
||||
|
||||
@@ -123,8 +123,9 @@ Difficulty: Very Hard
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(H.martial_art && prob(H.martial_art.deflection_chance))
|
||||
. = TRUE
|
||||
if(H.mind)
|
||||
if(H.mind.martial_art && prob(H.mind.martial_art.deflection_chance))
|
||||
. = TRUE
|
||||
|
||||
/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
|
||||
dir_shots(GLOB.diagonals)
|
||||
|
||||
@@ -525,7 +525,9 @@ Difficulty: Hard
|
||||
targetturf = get_turf(target)
|
||||
|
||||
/obj/effect/temp_visual/hierophant/chaser/proc/make_blast()
|
||||
new /obj/effect/temp_visual/hierophant/blast(loc, caster, friendly_fire_check)
|
||||
var/obj/effect/temp_visual/hierophant/blast/B = new(loc, caster, friendly_fire_check)
|
||||
B.damage = damage
|
||||
B.monster_damage_boost = monster_damage_boost
|
||||
|
||||
/obj/effect/temp_visual/hierophant/telegraph
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
|
||||
@@ -295,8 +295,12 @@
|
||||
return A
|
||||
else
|
||||
var/atom/movable/AM = A
|
||||
if(AM == buckled) //Kind of unnecessary but let's just be sure
|
||||
if(AM == buckled)
|
||||
continue
|
||||
if(ismob(AM))
|
||||
var/mob/M = AM
|
||||
if(M.buckled)
|
||||
continue
|
||||
if(!AM.CanPass(src) || AM.density)
|
||||
if(AM.anchored)
|
||||
return AM
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/weapon/paper/New()
|
||||
..()
|
||||
/obj/item/weapon/paper/Initialize()
|
||||
. = ..()
|
||||
pixel_y = rand(-8, 8)
|
||||
pixel_x = rand(-9, 9)
|
||||
update_icon()
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
papers.Add(P)
|
||||
total_paper++
|
||||
update_icon()
|
||||
else if(istype(I, /obj/item/weapon/pen))
|
||||
else if(istype(I, /obj/item/weapon/pen) && !bin_pen)
|
||||
var/obj/item/weapon/pen/P = I
|
||||
if(!user.transferItemToLoc(P, src))
|
||||
return
|
||||
|
||||
@@ -13,6 +13,21 @@
|
||||
max_ammo = 8
|
||||
multiple_sprites = 2
|
||||
|
||||
/obj/item/ammo_box/magazine/m10mm/rifle
|
||||
name = "rifle magazine (10mm)"
|
||||
desc = "A well-worn magazine fitted for the surplus rifle."
|
||||
icon_state = "75-8"
|
||||
origin_tech = "combat=2"
|
||||
ammo_type = /obj/item/ammo_casing/c10mm
|
||||
caliber = "10mm"
|
||||
max_ammo = 10
|
||||
|
||||
/obj/item/ammo_box/magazine/m10mm/rifle/update_icon()
|
||||
if(ammo_count())
|
||||
icon_state = "75-8"
|
||||
else
|
||||
icon_state = "75-0"
|
||||
|
||||
/obj/item/ammo_box/magazine/m10mm/fire
|
||||
name = "pistol magazine (10mm incendiary)"
|
||||
desc = "A gun magazine. Loaded with rounds which ignite the target."
|
||||
@@ -52,16 +67,31 @@
|
||||
|
||||
/obj/item/ammo_box/magazine/wt550m9/wtap
|
||||
name = "wt550 magazine (Armour Piercing 4.6x30mm)"
|
||||
icon_state = "46x30mmtA-20"
|
||||
ammo_type = /obj/item/ammo_casing/c46x30mmap
|
||||
|
||||
/obj/item/ammo_box/magazine/wt550m9/wtap/update_icon()
|
||||
..()
|
||||
icon_state = "46x30mmtA-[round(ammo_count(),4)]"
|
||||
|
||||
/obj/item/ammo_box/magazine/wt550m9/wttx
|
||||
name = "wt550 magazine (Toxin Tipped 4.6x30mm)"
|
||||
icon_state = "46x30mmtT-20"
|
||||
ammo_type = /obj/item/ammo_casing/c46x30mmtox
|
||||
|
||||
/obj/item/ammo_box/magazine/wt550m9/wttx/update_icon()
|
||||
..()
|
||||
icon_state = "46x30mmtT-[round(ammo_count(),4)]"
|
||||
|
||||
/obj/item/ammo_box/magazine/wt550m9/wtic
|
||||
name = "wt550 magazine (Incindiary 4.6x30mm)"
|
||||
icon_state = "46x30mmtI-20"
|
||||
ammo_type = /obj/item/ammo_casing/c46x30mminc
|
||||
|
||||
/obj/item/ammo_box/magazine/wt550m9/wtic/update_icon()
|
||||
..()
|
||||
icon_state = "46x30mmtI-[round(ammo_count(),4)]"
|
||||
|
||||
/obj/item/ammo_box/magazine/uzim9mm
|
||||
name = "uzi magazine (9mm)"
|
||||
icon_state = "uzi9mm-32"
|
||||
|
||||
@@ -109,6 +109,11 @@
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
|
||||
max_ammo = 6
|
||||
|
||||
/obj/item/ammo_box/magazine/internal/shot/com/compact
|
||||
name = "compact combat shotgun internal magazine"
|
||||
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
|
||||
max_ammo = 4
|
||||
|
||||
/obj/item/ammo_box/magazine/internal/shot/dual
|
||||
name = "double-barrel shotgun internal magazine"
|
||||
max_ammo = 2
|
||||
|
||||
@@ -375,8 +375,29 @@
|
||||
pin = /obj/item/device/firing_pin/implant/pindicate
|
||||
origin_tech = "combat=7;syndicate=6"
|
||||
|
||||
// Old Semi-Auto Rifle //
|
||||
|
||||
/obj/item/weapon/gun/ballistic/automatic/surplus
|
||||
name = "Surplus Rifle"
|
||||
desc = "One of countless obsolete ballistic rifles that still sees use as a cheap deterrent. Uses 10mm ammo and its bulky frame prevents one-hand firing."
|
||||
origin_tech = "combat=3;materials=2"
|
||||
icon_state = "surplus"
|
||||
item_state = "moistnugget"
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
mag_type = /obj/item/ammo_box/magazine/m10mm/rifle
|
||||
fire_delay = 30
|
||||
burst_size = 1
|
||||
can_unsuppress = 1
|
||||
can_suppress = 1
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
slot_flags = SLOT_BACK
|
||||
actions_types = list()
|
||||
|
||||
/obj/item/weapon/gun/ballistic/automatic/surplus/update_icon()
|
||||
if(magazine)
|
||||
icon_state = "surplus"
|
||||
else
|
||||
icon_state = "surplus-e"
|
||||
|
||||
// Laser rifle (rechargeable magazine) //
|
||||
|
||||
|
||||
@@ -344,6 +344,15 @@
|
||||
slung = 0
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/gun/ballistic/revolver/doublebarrel/improvised/sawn
|
||||
name = "sawn-off improvised shotgun"
|
||||
desc = "A single-shot shotgun, better not miss"
|
||||
icon_state = "ishotgun"
|
||||
item_state = "gun"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
sawn_state = SAWN_OFF
|
||||
slot_flags = SLOT_BELT
|
||||
|
||||
/obj/item/weapon/gun/ballistic/revolver/reverse //Fires directly at its user... unless the user is a clown, of course.
|
||||
clumsy_check = 0
|
||||
|
||||
|
||||
@@ -192,6 +192,14 @@
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/com
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
|
||||
/obj/item/weapon/gun/ballistic/shotgun/automatic/combat/compact
|
||||
name = "compact combat shotgun"
|
||||
desc = "A compact version of the semi automatic combat shotgun. For close encounters."
|
||||
icon_state = "cshotgunc"
|
||||
origin_tech = "combat=4;materials=2"
|
||||
mag_type = /obj/item/ammo_box/magazine/internal/shot/com/compact
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
|
||||
//Dual Feed Shotgun
|
||||
|
||||
/obj/item/weapon/gun/ballistic/shotgun/automatic/dual_tube
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
diff a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm (rejected hunks)
|
||||
@@ -203,7 +203,7 @@
|
||||
range = 4
|
||||
dismemberment = 20
|
||||
impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser
|
||||
- var/mine_range = 4 //mines this many additional tiles
|
||||
+ var/mine_range = 3 //mines this many additional tiles
|
||||
|
||||
/obj/item/projectile/plasma/Initialize()
|
||||
. = ..()
|
||||
@@ -453,14 +453,14 @@
|
||||
|
||||
/datum/reagents/proc/check_ignoreslow(mob/M)
|
||||
if(istype(M, /mob))
|
||||
if(M.reagents.has_reagent("morphine")||M.reagents.has_reagent("ephedrine"))
|
||||
if(M.reagents.has_reagent("morphine"))
|
||||
return 1
|
||||
else
|
||||
M.status_flags &= ~IGNORESLOWDOWN
|
||||
|
||||
/datum/reagents/proc/check_gofast(mob/M)
|
||||
if(istype(M, /mob))
|
||||
if(M.reagents.has_reagent("unholywater")||M.reagents.has_reagent("nuka_cola")||M.reagents.has_reagent("stimulants"))
|
||||
if(M.reagents.has_reagent("unholywater")||M.reagents.has_reagent("nuka_cola")||M.reagents.has_reagent("stimulants")||M.reagents.has_reagent("ephedrine"))
|
||||
return 1
|
||||
else
|
||||
M.status_flags &= ~GOTTAGOFAST
|
||||
|
||||
@@ -1,285 +1,183 @@
|
||||
/obj/machinery/computer/pandemic
|
||||
name = "PanD.E.M.I.C 2200"
|
||||
desc = "Used to work with viruses."
|
||||
density = 1
|
||||
anchored = 1
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "mixer0"
|
||||
circuit = /obj/item/weapon/circuitboard/computer/pandemic
|
||||
use_power = 1
|
||||
use_power = TRUE
|
||||
idle_power_usage = 20
|
||||
resistance_flags = ACID_PROOF
|
||||
var/temp_html = ""
|
||||
var/wait = null
|
||||
var/obj/item/weapon/reagent_containers/beaker = null
|
||||
var/wait
|
||||
var/obj/item/weapon/reagent_containers/beaker
|
||||
|
||||
/obj/machinery/computer/pandemic/Initialize()
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/GetVirusByIndex(index)
|
||||
if(beaker && beaker.reagents)
|
||||
if(beaker.reagents.reagent_list.len)
|
||||
var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list
|
||||
if(BL)
|
||||
if(BL.data && BL.data["viruses"])
|
||||
var/list/viruses = BL.data["viruses"]
|
||||
return viruses[index]
|
||||
return null
|
||||
/obj/machinery/computer/pandemic/Destroy()
|
||||
QDEL_NULL(beaker)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/GetResistancesByIndex(index)
|
||||
if(beaker && beaker.reagents)
|
||||
if(beaker.reagents.reagent_list.len)
|
||||
var/datum/reagent/blood/BL = locate() in beaker.reagents.reagent_list
|
||||
if(BL)
|
||||
if(BL.data && BL.data["resistances"])
|
||||
var/list/resistances = BL.data["resistances"]
|
||||
return resistances[index]
|
||||
return null
|
||||
/obj/machinery/computer/pandemic/proc/get_by_index(thing, index)
|
||||
if(!beaker || !beaker.reagents)
|
||||
return
|
||||
var/datum/reagent/blood/B = locate() in beaker.reagents.reagent_list
|
||||
if(B && B.data[thing])
|
||||
return B.data[thing][index]
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/GetVirusTypeByIndex(index)
|
||||
var/datum/disease/D = GetVirusByIndex(index)
|
||||
/obj/machinery/computer/pandemic/proc/get_virus_id_by_index(index)
|
||||
var/datum/disease/D = get_by_index("viruses", index)
|
||||
if(D)
|
||||
return D.GetDiseaseID()
|
||||
return null
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/replicator_cooldown(waittime)
|
||||
wait = 1
|
||||
/obj/machinery/computer/pandemic/proc/get_viruses_data(datum/reagent/blood/B)
|
||||
. = list()
|
||||
if(!islist(B.data["viruses"]))
|
||||
return
|
||||
var/list/V = B.data["viruses"]
|
||||
var/index = 1
|
||||
for(var/virus in V)
|
||||
var/datum/disease/D = virus
|
||||
if(!istype(D) || D.visibility_flags & HIDDEN_PANDEMIC)
|
||||
continue
|
||||
|
||||
var/list/this = list()
|
||||
this["name"] = D.name
|
||||
if(istype(D, /datum/disease/advance))
|
||||
var/datum/disease/advance/A = SSdisease.archive_diseases[D.GetDiseaseID()]
|
||||
if(A.name == "Unknown")
|
||||
this["can_rename"] = TRUE
|
||||
this["name"] = A.name
|
||||
this["is_adv"] = TRUE
|
||||
this["resistance"] = A.totalResistance()
|
||||
this["stealth"] = A.totalStealth()
|
||||
this["stage_speed"] = A.totalStageSpeed()
|
||||
this["transmission"] = A.totalTransmittable()
|
||||
this["symptoms"] = list()
|
||||
for(var/symptom in A.symptoms)
|
||||
var/datum/symptom/S = symptom
|
||||
var/list/this_symptom = list()
|
||||
this_symptom["name"] = S.name
|
||||
this["symptoms"] += list(this_symptom)
|
||||
this["index"] = index++
|
||||
this["agent"] = D.agent
|
||||
this["description"] = D.desc || "none"
|
||||
this["spread"] = D.spread_text || "none"
|
||||
this["cure"] = D.cure_text || "none"
|
||||
|
||||
. += list(this)
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/get_resistance_data(datum/reagent/blood/B)
|
||||
. = list()
|
||||
if(!islist(B.data["resistances"]))
|
||||
return
|
||||
var/list/resistances = B.data["resistances"]
|
||||
for(var/id in resistances)
|
||||
var/list/this = list()
|
||||
var/datum/disease/D = SSdisease.archive_diseases[id]
|
||||
if(D)
|
||||
this["id"] = id
|
||||
this["name"] = D.name
|
||||
. += list(this)
|
||||
|
||||
/obj/machinery/computer/pandemic/proc/reset_replicator_cooldown()
|
||||
wait = FALSE
|
||||
update_icon()
|
||||
spawn(waittime)
|
||||
wait = null
|
||||
update_icon()
|
||||
playsound(src.loc, 'sound/machines/ping.ogg', 30, 1)
|
||||
playsound(loc, 'sound/machines/ping.ogg', 30, 1)
|
||||
|
||||
/obj/machinery/computer/pandemic/update_icon()
|
||||
if(stat & BROKEN)
|
||||
icon_state = (beaker ? "mixer1_b" : "mixer0_b")
|
||||
return
|
||||
|
||||
icon_state = "mixer[(beaker)?"1":"0"][(powered()) ? "" : "_nopower"]"
|
||||
|
||||
icon_state = "mixer[(beaker) ? "1" : "0"][powered() ? "" : "_nopower"]"
|
||||
if(wait)
|
||||
cut_overlays()
|
||||
else
|
||||
add_overlay("waitlight")
|
||||
|
||||
/obj/machinery/computer/pandemic/Topic(href, href_list)
|
||||
/obj/machinery/computer/pandemic/proc/eject_beaker()
|
||||
beaker.forceMove(get_turf(src))
|
||||
beaker = null
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/computer/pandemic/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open = FALSE, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "pandemic", name, 575, 500, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/pandemic/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["is_ready"] = !wait
|
||||
if(beaker)
|
||||
data["has_beaker"] = TRUE
|
||||
if(!beaker.reagents.total_volume || !beaker.reagents.reagent_list)
|
||||
data["beaker_empty"] = TRUE
|
||||
var/datum/reagent/blood/B = locate() in beaker.reagents.reagent_list
|
||||
if(B)
|
||||
data["has_blood"] = TRUE
|
||||
data["blood"] = list()
|
||||
data["blood"]["dna"] = B.data["blood_DNA"] || "none"
|
||||
data["blood"]["type"] = B.data["blood_type"] || "none"
|
||||
data["viruses"] = get_viruses_data(B)
|
||||
data["resistances"] = get_resistance_data(B)
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/pandemic/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
|
||||
usr.set_machine(src)
|
||||
if(!beaker) return
|
||||
|
||||
if (href_list["create_vaccine"])
|
||||
if(!src.wait)
|
||||
var/obj/item/weapon/reagent_containers/glass/bottle/B = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc)
|
||||
if(B)
|
||||
B.pixel_x = rand(-3, 3)
|
||||
B.pixel_y = rand(-3, 3)
|
||||
var/path = GetResistancesByIndex(text2num(href_list["create_vaccine"]))
|
||||
var/vaccine_type = path
|
||||
var/vaccine_name = "Unknown"
|
||||
|
||||
if(!ispath(vaccine_type))
|
||||
if(SSdisease.archive_diseases[path])
|
||||
var/datum/disease/D = SSdisease.archive_diseases[path]
|
||||
if(D)
|
||||
vaccine_name = D.name
|
||||
vaccine_type = path
|
||||
else if(vaccine_type)
|
||||
var/datum/disease/D = new vaccine_type(0, null)
|
||||
if(D)
|
||||
vaccine_name = D.name
|
||||
|
||||
if(vaccine_type)
|
||||
|
||||
B.name = "[vaccine_name] vaccine bottle"
|
||||
B.reagents.add_reagent("vaccine", 15, list(vaccine_type))
|
||||
replicator_cooldown(200)
|
||||
else
|
||||
temp_html = "The replicator is not ready yet."
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if (href_list["create_virus_culture"])
|
||||
if(!wait)
|
||||
var/type = GetVirusTypeByIndex(text2num(href_list["create_virus_culture"]))//the path is received as string - converting
|
||||
var/datum/disease/D = null
|
||||
if(!ispath(type))
|
||||
D = GetVirusByIndex(text2num(href_list["create_virus_culture"]))
|
||||
var/datum/disease/advance/A = SSdisease.archive_diseases[D.GetDiseaseID()]
|
||||
if(A)
|
||||
D = new A.type(0, A)
|
||||
else if(type)
|
||||
if(type in SSdisease.diseases) // Make sure this is a disease
|
||||
D = new type(0, null)
|
||||
if(!D)
|
||||
return
|
||||
var/name = stripped_input(usr,"Name:","Name the culture",D.name,MAX_NAME_LEN)
|
||||
if(name == null || wait)
|
||||
return
|
||||
var/obj/item/weapon/reagent_containers/glass/bottle/B = new/obj/item/weapon/reagent_containers/glass/bottle(src.loc)
|
||||
B.icon_state = "bottle3"
|
||||
B.pixel_x = rand(-3, 3)
|
||||
B.pixel_y = rand(-3, 3)
|
||||
replicator_cooldown(50)
|
||||
var/list/data = list("viruses"=list(D))
|
||||
B.name = "[name] culture bottle"
|
||||
B.desc = "A small bottle. Contains [D.agent] culture in synthblood medium."
|
||||
B.reagents.add_reagent("blood",20,data)
|
||||
updateUsrDialog()
|
||||
else
|
||||
temp_html = "The replicator is not ready yet."
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if (href_list["empty_beaker"])
|
||||
beaker.reagents.clear_reagents()
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if (href_list["eject"])
|
||||
beaker.forceMove(get_turf(loc))
|
||||
beaker = null
|
||||
icon_state = "mixer0"
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if (href_list["emptyeject_beaker"])
|
||||
beaker.reagents.clear_reagents()
|
||||
beaker.forceMove(get_turf(loc))
|
||||
beaker = null
|
||||
icon_state = "mixer0"
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if(href_list["clear"])
|
||||
temp_html = ""
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if(href_list["name_disease"])
|
||||
var/new_name = stripped_input(usr, "Name the Disease", "New Name", "", MAX_NAME_LEN)
|
||||
if(!new_name)
|
||||
return
|
||||
if(..())
|
||||
return
|
||||
var/id = GetVirusTypeByIndex(text2num(href_list["name_disease"]))
|
||||
if(SSdisease.archive_diseases[id])
|
||||
switch(action)
|
||||
if("eject_beaker")
|
||||
eject_beaker()
|
||||
. = TRUE
|
||||
if("empty_beaker")
|
||||
beaker.reagents.clear_reagents()
|
||||
. = TRUE
|
||||
if("empty_eject_beaker")
|
||||
beaker.reagents.clear_reagents()
|
||||
eject_beaker()
|
||||
. = TRUE
|
||||
if("rename_disease")
|
||||
var/id = get_virus_id_by_index(text2num(params["index"]))
|
||||
var/datum/disease/advance/A = SSdisease.archive_diseases[id]
|
||||
A.AssignName(new_name)
|
||||
for(var/datum/disease/advance/AD in SSdisease.processing)
|
||||
AD.Refresh()
|
||||
updateUsrDialog()
|
||||
|
||||
|
||||
else
|
||||
usr << browse(null, "window=pandemic")
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
add_fingerprint(usr)
|
||||
return
|
||||
|
||||
/obj/machinery/computer/pandemic/attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat = ""
|
||||
if(temp_html)
|
||||
dat = "[src.temp_html]<BR><BR><A href='?src=\ref[src];clear=1'>Main Menu</A>"
|
||||
else if(!beaker)
|
||||
dat += "Please insert beaker.<BR>"
|
||||
dat += "<A href='?src=\ref[user];mach_close=pandemic'>Close</A>"
|
||||
else
|
||||
var/datum/reagents/R = beaker.reagents
|
||||
var/datum/reagent/blood/Blood = null
|
||||
for(var/datum/reagent/blood/B in R.reagent_list)
|
||||
if(B)
|
||||
Blood = B
|
||||
break
|
||||
if(!R.total_volume||!R.reagent_list.len)
|
||||
dat += "The beaker is empty<BR>"
|
||||
else if(!Blood)
|
||||
dat += "No blood sample found in beaker."
|
||||
else if(!Blood.data)
|
||||
dat += "No blood data found in beaker."
|
||||
else
|
||||
dat += "<h3>Blood sample data:</h3>"
|
||||
dat += "<b>Blood DNA:</b> [(Blood.data["blood_DNA"]||"none")]<BR>"
|
||||
dat += "<b>Blood Type:</b> [(Blood.data["blood_type"]||"none")]<BR>"
|
||||
|
||||
|
||||
if(Blood.data["viruses"])
|
||||
var/list/vir = Blood.data["viruses"]
|
||||
if(vir.len)
|
||||
var/i = 0
|
||||
for(var/datum/disease/D in Blood.data["viruses"])
|
||||
i++
|
||||
if(!(D.visibility_flags & HIDDEN_PANDEMIC))
|
||||
|
||||
if(istype(D, /datum/disease/advance))
|
||||
|
||||
var/datum/disease/advance/A = D
|
||||
D = SSdisease.archive_diseases[A.GetDiseaseID()]
|
||||
if(D && D.name == "Unknown")
|
||||
dat += "<b><a href='?src=\ref[src];name_disease=[i]'>Name Disease</a></b><BR>"
|
||||
|
||||
if(!D)
|
||||
CRASH("We weren't able to get the advance disease from the archive.")
|
||||
|
||||
dat += "<b>Disease Agent:</b> [D?"[D.agent] - <A href='?src=\ref[src];create_virus_culture=[i]'>Create virus culture bottle</A>":"none"]<BR>"
|
||||
dat += "<b>Common name:</b> [(D.name||"none")]<BR>"
|
||||
dat += "<b>Description: </b> [(D.desc||"none")]<BR>"
|
||||
dat += "<b>Spread:</b> [(D.spread_text||"none")]<BR>"
|
||||
dat += "<b>Possible cure:</b> [(D.cure_text||"none")]<BR><BR>"
|
||||
if(istype(D, /datum/disease/advance))
|
||||
var/datum/disease/advance/A = D
|
||||
dat += "<b>Stealth:</b> [(A.totalStealth())]<BR>"
|
||||
dat += "<b>Resistance:</b> [(A.totalResistance())]<BR>"
|
||||
dat += "<b>Stage Speed:</b> [(A.totalStageSpeed())]<BR>"
|
||||
dat += "<b>Transmission:</b> [(A.totalTransmittable())]<BR><BR>"
|
||||
dat += "<b>Symptoms:</b> "
|
||||
var/english_symptoms = list()
|
||||
for(var/datum/symptom/S in A.symptoms)
|
||||
english_symptoms += S.name
|
||||
dat += english_list(english_symptoms)
|
||||
|
||||
else
|
||||
dat += "No detectable virus in the sample."
|
||||
else
|
||||
dat += "No detectable virus in the sample."
|
||||
|
||||
dat += "<BR><b>Contains antibodies to:</b> "
|
||||
if(Blood.data["resistances"])
|
||||
var/list/res = Blood.data["resistances"]
|
||||
if(res.len)
|
||||
dat += "<ul>"
|
||||
var/i = 0
|
||||
for(var/type in Blood.data["resistances"])
|
||||
i++
|
||||
var/disease_name = "Unknown"
|
||||
|
||||
if(!ispath(type))
|
||||
var/datum/disease/advance/A = SSdisease.archive_diseases[type]
|
||||
if(A)
|
||||
disease_name = A.name
|
||||
else
|
||||
var/datum/disease/D = new type(0, null)
|
||||
disease_name = D.name
|
||||
|
||||
dat += "<li>[disease_name] - <A href='?src=\ref[src];create_vaccine=[i]'>Create vaccine bottle</A></li>"
|
||||
dat += "</ul><BR>"
|
||||
else
|
||||
dat += "nothing<BR>"
|
||||
else
|
||||
dat += "nothing<BR>"
|
||||
dat += "<BR><A href='?src=\ref[src];eject=1'>Eject beaker</A>[((R.total_volume&&R.reagent_list.len) ? "-- <A href='?src=\ref[src];empty_beaker=1'>Empty beaker</A>":"")]"
|
||||
dat += "[((R.total_volume&&R.reagent_list.len) ? "-- <A href='?src=\ref[src];emptyeject_beaker=1'>Empty and Eject beaker</A>":"")]<BR>"
|
||||
dat += "<A href='?src=\ref[user];mach_close=pandemic'>Close</A>"
|
||||
|
||||
user << browse("<TITLE>[src.name]</TITLE><BR>[dat]", "window=pandemic;size=575x400")
|
||||
onclose(user, "pandemic")
|
||||
return
|
||||
|
||||
if(A)
|
||||
var/new_name = stripped_input(usr, "Name the disease", "New name", "", MAX_NAME_LEN)
|
||||
if(!new_name || ..())
|
||||
return
|
||||
A.AssignName(new_name)
|
||||
for(var/datum/disease/advance/AD in SSdisease.processing)
|
||||
AD.Refresh()
|
||||
. = TRUE
|
||||
if("create_culture_bottle")
|
||||
var/id = get_virus_id_by_index(text2num(params["index"]))
|
||||
var/datum/disease/advance/A = new(FALSE, SSdisease.archive_diseases[id])
|
||||
var/list/data = list("viruses" = list(A))
|
||||
var/obj/item/weapon/reagent_containers/glass/bottle/B = new(get_turf(src))
|
||||
B.name = "[A.name] culture bottle"
|
||||
B.desc = "A small bottle. Contains [A.agent] culture in synthblood medium."
|
||||
B.reagents.add_reagent("blood", 20, data)
|
||||
wait = TRUE
|
||||
update_icon()
|
||||
addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 50)
|
||||
. = TRUE
|
||||
if("create_vaccine_bottle")
|
||||
var/index = params["index"]
|
||||
var/datum/disease/D = SSdisease.archive_diseases[index]
|
||||
var/obj/item/weapon/reagent_containers/glass/bottle/B = new(get_turf(src))
|
||||
B.name = "[D.name] vaccine bottle"
|
||||
B.reagents.add_reagent("vaccine", 15, list(index))
|
||||
wait = TRUE
|
||||
update_icon()
|
||||
addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 200)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/computer/pandemic/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/reagent_containers) && (I.container_type & OPENCONTAINER))
|
||||
. = 1 //no afterattack
|
||||
. = TRUE //no afterattack
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if(beaker)
|
||||
@@ -288,15 +186,15 @@
|
||||
if(!user.drop_item())
|
||||
return
|
||||
|
||||
beaker = I
|
||||
beaker.loc = src
|
||||
beaker = I
|
||||
beaker.forceMove(src)
|
||||
to_chat(user, "<span class='notice'>You add the beaker to the machine.</span>")
|
||||
updateUsrDialog()
|
||||
icon_state = "mixer1"
|
||||
update_icon()
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/pandemic/on_deconstruction()
|
||||
if(beaker)
|
||||
beaker.loc = get_turf(src)
|
||||
..()
|
||||
beaker.forceMove(get_turf(src))
|
||||
beaker = null
|
||||
. = ..()
|
||||
@@ -160,6 +160,12 @@
|
||||
var/obj/item/toy/carpplushie/dehy_carp/dehy = O
|
||||
dehy.Swell() // Makes a carp
|
||||
|
||||
else if(istype(O, /obj/item/stack/sheet/hairlesshide))
|
||||
var/obj/item/stack/sheet/hairlesshide/HH = O
|
||||
var/obj/item/stack/sheet/wetleather/WL = new(get_turf(HH))
|
||||
WL.amount = HH.amount
|
||||
qdel(HH)
|
||||
|
||||
/*
|
||||
* Water reaction to a mob
|
||||
*/
|
||||
@@ -367,11 +373,15 @@
|
||||
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/N = M
|
||||
if(N.dna.species.id == "human") // If they're human, turn em to the "orange" race, and give em spiky black hair
|
||||
N.hair_style = "Spiky"
|
||||
N.facial_hair_style = "Shaved"
|
||||
N.facial_hair_color = "000"
|
||||
N.hair_color = "000"
|
||||
if(!(HAIR in N.dna.species.species_traits)) //No hair? No problem!
|
||||
N.dna.species.species_traits += HAIR
|
||||
if(N.dna.species.use_skintones)
|
||||
N.skin_tone = "orange"
|
||||
N.hair_style = "Spiky"
|
||||
N.hair_color = "000"
|
||||
if(MUTCOLORS in N.dna.species.species_traits) //Aliens with custom colors simply get turned orange
|
||||
else if(MUTCOLORS in N.dna.species.species_traits) //Aliens with custom colors simply get turned orange
|
||||
N.dna.features["mcolor"] = "f80"
|
||||
N.regenerate_icons()
|
||||
if(prob(7))
|
||||
@@ -380,7 +390,7 @@
|
||||
else
|
||||
M.visible_message("<b>[M]</b> flexes [M.p_their()] arms.")
|
||||
if(prob(10))
|
||||
M.say(pick("Check these sweet biceps bro!", "Deal with it.", "CHUG! CHUG! CHUG! CHUG!", "Winning!", "NERDS!", "My name is John and I hate every single one of you."))
|
||||
M.say(pick("Shit was SO cash.", "You are everything bad in the world.", "What sports do you play, other than 'jack off to naked drawn Japanese people?'", "Don’t be a stranger. Just hit me with your best shot.", "My name is John and I hate every single one of you."))
|
||||
..()
|
||||
return
|
||||
|
||||
@@ -1126,7 +1136,7 @@
|
||||
/datum/reagent/nitrous_oxide/reaction_mob(mob/M, method=TOUCH, reac_volume)
|
||||
if(method == VAPOR)
|
||||
M.drowsyness += max(round(reac_volume, 1), 2)
|
||||
|
||||
|
||||
/datum/reagent/nitrous_oxide/on_mob_life(mob/living/M)
|
||||
M.drowsyness += 2
|
||||
if(ishuman(M))
|
||||
|
||||
@@ -104,11 +104,12 @@
|
||||
if(!operating)
|
||||
return
|
||||
use_power(100)
|
||||
|
||||
affecting = loc.contents - src // moved items will be all in loc
|
||||
sleep(1)
|
||||
addtimer(CALLBACK(src, .proc/convey, affecting), 1)
|
||||
|
||||
/obj/machinery/conveyor/proc/convey(list/affecting)
|
||||
for(var/atom/movable/A in affecting)
|
||||
if(A.loc == loc)
|
||||
if((A.loc == loc) && A.has_gravity())
|
||||
A.ConveyorMove(movedir)
|
||||
|
||||
// attack with item, place item on conveyor
|
||||
|
||||
@@ -83,14 +83,18 @@
|
||||
|
||||
//sometimes we want to ignore that we don't have the required amount of legs.
|
||||
/mob/proc/get_leg_ignore()
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/mob/living/carbon/alien/larva/get_leg_ignore()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/get_leg_ignore()
|
||||
if(movement_type & FLYING)
|
||||
return 1
|
||||
return TRUE
|
||||
var/obj/item/weapon/tank/jetpack/J = get_jetpack()
|
||||
if(J && J.on && !has_gravity())
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/mob/living/proc/get_missing_limbs()
|
||||
return list()
|
||||
|
||||
@@ -914,8 +914,8 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
|
||||
cost = 3
|
||||
|
||||
/datum/uplink_item/device_tools/military_belt
|
||||
name = "Military Belt"
|
||||
desc = "A robust seven-slot red belt that is capable of holding all manner of tatical equipment."
|
||||
name = "Chest Rig"
|
||||
desc = "A robust seven-slot set of webbing that is capable of holding all manner of tatical equipment."
|
||||
item = /obj/item/weapon/storage/belt/military
|
||||
cost = 1
|
||||
exclude_modes = list(/datum/game_mode/nuclear)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Lzimann"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Pandemic is now tgui!"
|
||||
@@ -0,0 +1,5 @@
|
||||
author: "Joan"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "Resonator fields now visually show how long they have until they burst."
|
||||
- bugfix: "Hitting a legion skull with a resonator will now produce a field."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Steelpoint"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "The Warden's Cycler Shotgun has been replaced with a Compact Combat Shotgun. A unique weapon, it can fit in armour slots but at the sacrifice of a smaller ammo capacity of four shells."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "CitadelStationBot"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "Spessmen seems to have stopped suffering from the mental condition that makes them believe they can't move fast if they have only one leg, even if they're in space and using a jetpack!"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "That Really Good Soda Flavor"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "Martial arts are no longer lost when mind-swapping, cloning, moving your brain, et cetera."
|
||||
@@ -0,0 +1,7 @@
|
||||
author: "coiax"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Galactic Common has been added to silicon's internal language
|
||||
database, meaning even if a cyborg is created from someone who
|
||||
previously did not know Galactic Common, they will be able to speak it
|
||||
as a silicon."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "ma44"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Reports of syndicate base on lavaland has been outfitted with a state of the art donksoft toy weapon dispenser."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Joan"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "Chasms will glow dimly, like lava."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Steelpoint"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Auto Rifle alt ammo mags (AP, Incendiary, Uranium Tipped) now have a coloured stripe to denote them."
|
||||
@@ -0,0 +1,6 @@
|
||||
author: "Joan"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscdel: "Nanotrasen has taken a lower bid for their meson suppliers, and meson scanners will no longer display terrain layouts while on the planet."
|
||||
- tweak: "However, they have discovered that, with some tweaks, mineral scanners will no longer actually require you to be wearing mesons."
|
||||
- tweak: "The cheaper mesons will not completely remove reliance on light."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "That Really Good Soda Flavor"
|
||||
delete-after: True
|
||||
changes:
|
||||
- bugfix: "Fixed a bug where paper bins could swallow up pens into the void."
|
||||
@@ -0,0 +1,10 @@
|
||||
author: "Robustin"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Gang influence is now decentralized, each gangster has their own influence that they can increase by spraying (and protecting) their tags and new influence-enhancing bling."
|
||||
- rscadd: "Gang uniforms are now created based on your gang's color and can be purchased by any gang member. They will increase the wearer's influence and provide protection, but will make it fairly obvious which gang you belong to."
|
||||
- rscadd: "Gangs have access to a new surplus rifle; it is a semi-automatic rifle that is very bulky and has a very low rate of fire. Gang members can buy this gun for just 8 influence."
|
||||
- rscadd: "Gangs have access to the new machine gun turret; it unleashes a volley of bullets with an extended view range. It does not run out of ammo, but a significant delay between volleys and its stationary nature leaves the gunner vulnerable to flanking and return fire. Holding down the trigger will allow you to aim the gun while firing. It will cost gangs 50 influence."
|
||||
- rscadd: "The sawn-off improvised shotgun is now available to gangs for 6 influence. With buckshot shells being easy to produce or purchase, this gun gives the most \"bang for your buck\" but its single-shell capacity will leave you vulnerable during a pitched gunfight."
|
||||
- rscadd: "The Wetwork boots give gangs access to a lightly armored noslip variant."
|
||||
- tweak: "The armored gang outfits are now slightly more resistant to ballistic and bomb damage"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Tacolizard"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "Station based armour is slightly more descriptive of what it does."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "That Really Good Soda Flavor"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "Changed spray tan overdoses to be more realistic."
|
||||
@@ -0,0 +1,5 @@
|
||||
author: "QualityVan"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Hairless hides now become wet when exposed to water"
|
||||
- rscadd: "You can microwave wet leather to dry it"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Steelpoint"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Boxstation armoury weapon racks now have glass panes to help prevent the weapons easily flying out of a breached hull."
|
||||
|
After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 50 KiB |