yes
This commit is contained in:
+51
-62
@@ -6,13 +6,15 @@
|
||||
/datum/action
|
||||
var/name = "Generic Action"
|
||||
var/desc = null
|
||||
var/obj/target = null
|
||||
var/atom/target = null
|
||||
var/check_flags = 0
|
||||
var/required_mobility_flags = MOBILITY_USE
|
||||
var/processing = FALSE
|
||||
var/obj/screen/movable/action_button/button = null
|
||||
var/buttontooltipstyle = ""
|
||||
var/transparent_when_unavailable = TRUE
|
||||
var/use_target_appearance = FALSE
|
||||
var/list/target_appearance_matrix //if set, will be used to transform the target button appearance as an arglist.
|
||||
|
||||
var/button_icon = 'icons/mob/actions/backgrounds.dmi' //This is the file for the BACKGROUND icon
|
||||
var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND //And this is the state for the background icon
|
||||
@@ -88,14 +90,14 @@
|
||||
/datum/action/proc/Trigger()
|
||||
if(!IsAvailable())
|
||||
return FALSE
|
||||
if(SEND_SIGNAL(src, COMSIG_ACTION_TRIGGER, src) & COMPONENT_ACTION_BLOCK_TRIGGER)
|
||||
if(SEND_SIGNAL(src, COMSIG_ACTION_TRIGGER, target) & COMPONENT_ACTION_BLOCK_TRIGGER)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/proc/Process()
|
||||
return
|
||||
|
||||
/datum/action/proc/IsAvailable()
|
||||
/datum/action/proc/IsAvailable(silent = FALSE)
|
||||
if(!owner)
|
||||
return FALSE
|
||||
var/mob/living/L = owner
|
||||
@@ -116,29 +118,42 @@
|
||||
return TRUE
|
||||
|
||||
/datum/action/proc/UpdateButtonIcon(status_only = FALSE, force = FALSE)
|
||||
if(button)
|
||||
if(!status_only)
|
||||
button.name = name
|
||||
button.desc = desc
|
||||
if(owner && owner.hud_used && background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND)
|
||||
var/list/settings = owner.hud_used.get_action_buttons_icons()
|
||||
if(button.icon != settings["bg_icon"])
|
||||
button.icon = settings["bg_icon"]
|
||||
if(button.icon_state != settings["bg_state"])
|
||||
button.icon_state = settings["bg_state"]
|
||||
else
|
||||
if(button.icon != button_icon)
|
||||
button.icon = button_icon
|
||||
if(button.icon_state != background_icon_state)
|
||||
button.icon_state = background_icon_state
|
||||
if(!button)
|
||||
return
|
||||
if(!status_only)
|
||||
button.name = name
|
||||
button.desc = desc
|
||||
if(owner && owner.hud_used && background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND)
|
||||
var/list/settings = owner.hud_used.get_action_buttons_icons()
|
||||
if(button.icon != settings["bg_icon"])
|
||||
button.icon = settings["bg_icon"]
|
||||
if(button.icon_state != settings["bg_state"])
|
||||
button.icon_state = settings["bg_state"]
|
||||
else
|
||||
if(button.icon != button_icon)
|
||||
button.icon = button_icon
|
||||
if(button.icon_state != background_icon_state)
|
||||
button.icon_state = background_icon_state
|
||||
|
||||
if(!use_target_appearance)
|
||||
ApplyIcon(button, force)
|
||||
|
||||
if(!IsAvailable())
|
||||
button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0)
|
||||
else
|
||||
button.color = rgb(255,255,255,255)
|
||||
return 1
|
||||
else if(target && button.appearance_cache != target.appearance) //replace with /ref comparison if this is not valid.
|
||||
var/mutable_appearance/M = new(target)
|
||||
M.layer = FLOAT_LAYER
|
||||
M.plane = FLOAT_PLANE
|
||||
if(target_appearance_matrix)
|
||||
var/list/L = target_appearance_matrix
|
||||
M.transform = matrix(L[1], L[2], L[3], L[4], L[5], L[6])
|
||||
button.cut_overlays()
|
||||
button.add_overlay(M)
|
||||
button.appearance_cache = target.appearance
|
||||
|
||||
if(!IsAvailable(TRUE))
|
||||
button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0)
|
||||
else
|
||||
button.color = rgb(255,255,255,255)
|
||||
return 1
|
||||
|
||||
/datum/action/proc/ApplyIcon(obj/screen/movable/action_button/current_button, force = FALSE)
|
||||
if(icon_icon && button_icon_state && ((current_button.button_icon_state != button_icon_state) || force))
|
||||
@@ -165,6 +180,7 @@
|
||||
/datum/action/item_action
|
||||
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_LYING|AB_CHECK_CONSCIOUS
|
||||
button_icon_state = null
|
||||
use_target_appearance = TRUE
|
||||
// If you want to override the normal icon being the item
|
||||
// then change this to an icon state
|
||||
|
||||
@@ -188,23 +204,6 @@
|
||||
I.ui_action_click(owner, src)
|
||||
return 1
|
||||
|
||||
/datum/action/item_action/ApplyIcon(obj/screen/movable/action_button/current_button, force)
|
||||
if(button_icon && button_icon_state)
|
||||
// If set, use the custom icon that we set instead
|
||||
// of the item appearence
|
||||
..()
|
||||
else if(target && current_button.appearance_cache != target.appearance) //replace with /ref comparison if this is not valid.
|
||||
var/obj/item/I = target
|
||||
var/old_layer = I.layer
|
||||
var/old_plane = I.plane
|
||||
I.layer = FLOAT_LAYER //AAAH
|
||||
I.plane = FLOAT_PLANE //^ what that guy said
|
||||
current_button.cut_overlays()
|
||||
current_button.add_overlay(I)
|
||||
I.layer = old_layer
|
||||
I.plane = old_plane
|
||||
current_button.appearance_cache = I.appearance
|
||||
|
||||
/datum/action/item_action/toggle_light
|
||||
name = "Toggle Light"
|
||||
|
||||
@@ -302,23 +301,13 @@
|
||||
name = "Toggle Friendly Fire \[ON\]"
|
||||
..()
|
||||
|
||||
/datum/action/item_action/synthswitch
|
||||
name = "Change Synthesizer Instrument"
|
||||
desc = "Change the type of instrument your synthesizer is playing as."
|
||||
|
||||
/datum/action/item_action/synthswitch/Trigger()
|
||||
if(istype(target, /obj/item/instrument/piano_synth))
|
||||
var/obj/item/instrument/piano_synth/synth = target
|
||||
return synth.selectInstrument()
|
||||
return ..()
|
||||
|
||||
/datum/action/item_action/vortex_recall
|
||||
name = "Vortex Recall"
|
||||
desc = "Recall yourself, and anyone nearby, to an attuned hierophant beacon at any time.<br>If the beacon is still attached, will detach it."
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "vortex_recall"
|
||||
|
||||
/datum/action/item_action/vortex_recall/IsAvailable()
|
||||
/datum/action/item_action/vortex_recall/IsAvailable(silent = FALSE)
|
||||
if(istype(target, /obj/item/hierophant_club))
|
||||
var/obj/item/hierophant_club/H = target
|
||||
if(H.teleporting)
|
||||
@@ -330,7 +319,7 @@
|
||||
background_icon_state = "bg_clock"
|
||||
buttontooltipstyle = "clockcult"
|
||||
|
||||
/datum/action/item_action/clock/IsAvailable()
|
||||
/datum/action/item_action/clock/IsAvailable(silent = FALSE)
|
||||
if(!is_servant_of_ratvar(owner))
|
||||
return 0
|
||||
return ..()
|
||||
@@ -339,7 +328,7 @@
|
||||
name = "Create Judicial Marker"
|
||||
desc = "Allows you to create a stunning Judicial Marker at any location in view. Click again to disable."
|
||||
|
||||
/datum/action/item_action/clock/toggle_visor/IsAvailable()
|
||||
/datum/action/item_action/clock/toggle_visor/IsAvailable(silent = FALSE)
|
||||
if(!is_servant_of_ratvar(owner))
|
||||
return 0
|
||||
if(istype(target, /obj/item/clothing/glasses/judicial_visor))
|
||||
@@ -418,7 +407,7 @@
|
||||
/datum/action/item_action/jetpack_stabilization
|
||||
name = "Toggle Jetpack Stabilization"
|
||||
|
||||
/datum/action/item_action/jetpack_stabilization/IsAvailable()
|
||||
/datum/action/item_action/jetpack_stabilization/IsAvailable(silent = FALSE)
|
||||
var/obj/item/tank/jetpack/J = target
|
||||
if(!istype(J) || !J.on)
|
||||
return 0
|
||||
@@ -475,7 +464,7 @@
|
||||
/datum/action/item_action/organ_action
|
||||
check_flags = AB_CHECK_CONSCIOUS
|
||||
|
||||
/datum/action/item_action/organ_action/IsAvailable()
|
||||
/datum/action/item_action/organ_action/IsAvailable(silent = FALSE)
|
||||
var/obj/item/organ/I = target
|
||||
if(!I.owner)
|
||||
return 0
|
||||
@@ -644,32 +633,32 @@
|
||||
return FALSE
|
||||
if(target)
|
||||
var/obj/effect/proc_holder/S = target
|
||||
S.Click()
|
||||
S.Trigger(usr)
|
||||
return TRUE
|
||||
|
||||
/datum/action/spell_action/IsAvailable()
|
||||
/datum/action/spell_action/IsAvailable(silent = FALSE)
|
||||
if(!target)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/spell_action/spell
|
||||
|
||||
/datum/action/spell_action/spell/IsAvailable()
|
||||
/datum/action/spell_action/spell/IsAvailable(silent = FALSE)
|
||||
if(!target)
|
||||
return FALSE
|
||||
var/obj/effect/proc_holder/spell/S = target
|
||||
if(owner)
|
||||
return S.can_cast(owner)
|
||||
return S.can_cast(owner, FALSE, silent)
|
||||
return FALSE
|
||||
|
||||
/datum/action/spell_action/alien
|
||||
|
||||
/datum/action/spell_action/alien/IsAvailable()
|
||||
/datum/action/spell_action/alien/IsAvailable(silent = FALSE)
|
||||
if(!target)
|
||||
return FALSE
|
||||
var/obj/effect/proc_holder/alien/ab = target
|
||||
if(owner)
|
||||
return ab.cost_check(ab.check_turf,owner,1)
|
||||
return ab.cost_check(ab.check_turf,owner,silent)
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -711,7 +700,7 @@
|
||||
button.maptext_width = 24
|
||||
button.maptext_height = 12
|
||||
|
||||
/datum/action/cooldown/IsAvailable()
|
||||
/datum/action/cooldown/IsAvailable(silent = FALSE)
|
||||
return next_use_time <= world.time
|
||||
|
||||
/datum/action/cooldown/proc/StartCooldown()
|
||||
|
||||
+17
-11
@@ -9,8 +9,8 @@
|
||||
var/max_distance = 0
|
||||
var/sleep_time = 3
|
||||
var/finished = 0
|
||||
var/target_oldloc = null
|
||||
var/origin_oldloc = null
|
||||
var/turf/target_oldloc
|
||||
var/turf/origin_oldloc
|
||||
var/static_beam = 0
|
||||
var/beam_type = /obj/effect/ebeam //must be subtype
|
||||
var/timing_id = null
|
||||
@@ -23,13 +23,13 @@
|
||||
target_oldloc = get_turf(target)
|
||||
sleep_time = beam_sleep_time
|
||||
if(origin_oldloc == origin && target_oldloc == target)
|
||||
static_beam = 1
|
||||
static_beam = TRUE
|
||||
max_distance = maxdistance
|
||||
base_icon = new(beam_icon,beam_icon_state)
|
||||
icon = beam_icon
|
||||
icon_state = beam_icon_state
|
||||
beam_type = btype
|
||||
if(time < INFINITY)
|
||||
if(time < INFINITY)
|
||||
addtimer(CALLBACK(src,.proc/End), time)
|
||||
|
||||
/datum/beam/proc/Start()
|
||||
@@ -42,10 +42,14 @@
|
||||
return
|
||||
recalculating = TRUE
|
||||
timing_id = null
|
||||
if(origin && target && get_dist(origin,target)<max_distance && origin.z == target.z)
|
||||
var/origin_turf = get_turf(origin)
|
||||
var/target_turf = get_turf(target)
|
||||
if(!static_beam && (origin_turf != origin_oldloc || target_turf != target_oldloc))
|
||||
var/turf/origin_turf
|
||||
if(origin)
|
||||
origin_turf = get_turf(origin)
|
||||
var/turf/target_turf
|
||||
if(target)
|
||||
target_turf = get_turf(target)
|
||||
if(origin_turf && target_turf && (get_dist(origin_turf, target_turf) < max_distance) && (origin_turf.z == target_turf.z))
|
||||
if(!static_beam && ((origin_turf != origin_oldloc) || (target_turf != target_oldloc)))
|
||||
origin_oldloc = origin_turf //so we don't keep checking against their initial positions, leading to endless Reset()+Draw() calls
|
||||
target_oldloc = target_turf
|
||||
Reset()
|
||||
@@ -90,13 +94,15 @@
|
||||
return ..()
|
||||
|
||||
/datum/beam/proc/Draw()
|
||||
var/Angle = round(Get_Angle(origin,target))
|
||||
if(!origin_oldloc || !target_oldloc)
|
||||
return
|
||||
var/Angle = round(Get_Angle(origin_oldloc,target_oldloc))
|
||||
var/matrix/rot_matrix = matrix()
|
||||
rot_matrix.Turn(Angle)
|
||||
|
||||
//Translation vector for origin and target
|
||||
var/DX = (32*target.x+target.pixel_x)-(32*origin.x+origin.pixel_x)
|
||||
var/DY = (32*target.y+target.pixel_y)-(32*origin.y+origin.pixel_y)
|
||||
var/DX = (32*target_oldloc.x+target_oldloc.pixel_x)-(32*origin_oldloc.x+origin_oldloc.pixel_x)
|
||||
var/DY = (32*target_oldloc.y+target_oldloc.pixel_y)-(32*origin_oldloc.y+origin_oldloc.pixel_y)
|
||||
var/N = 0
|
||||
var/length = round(sqrt((DX)**2+(DY)**2)) //hypotenuse of the triangle formed by target and origin's displacement
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
..()
|
||||
make_backseats()
|
||||
get_ghost()
|
||||
RegisterSignal(M, COMSIG_MOB_DEATH, .proc/revert_to_normal)
|
||||
|
||||
/datum/brain_trauma/severe/split_personality/proc/make_backseats()
|
||||
stranger_backseat = new(owner, src)
|
||||
@@ -37,23 +38,23 @@
|
||||
qdel(src)
|
||||
|
||||
/datum/brain_trauma/severe/split_personality/on_life()
|
||||
if(owner.stat == DEAD)
|
||||
if(current_controller != OWNER)
|
||||
switch_personalities()
|
||||
qdel(src)
|
||||
else if(prob(3))
|
||||
if(prob(3))
|
||||
switch_personalities()
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/split_personality/on_lose()
|
||||
if(current_controller != OWNER) //it would be funny to cure a guy only to be left with the other personality, but it seems too cruel
|
||||
switch_personalities()
|
||||
switch_personalities(TRUE)
|
||||
QDEL_NULL(stranger_backseat)
|
||||
QDEL_NULL(owner_backseat)
|
||||
UnregisterSignal(owner, COMSIG_MOB_DEATH)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/severe/split_personality/proc/switch_personalities()
|
||||
if(QDELETED(owner) || owner.stat == DEAD || QDELETED(stranger_backseat) || QDELETED(owner_backseat))
|
||||
/datum/brain_trauma/severe/split_personality/proc/revert_to_normal()
|
||||
qdel(src)
|
||||
|
||||
/datum/brain_trauma/severe/split_personality/proc/switch_personalities(forced = FALSE)
|
||||
if(QDELETED(owner) || (owner.stat == DEAD && !forced) || QDELETED(stranger_backseat) || QDELETED(owner_backseat))
|
||||
return
|
||||
|
||||
var/mob/living/split_personality/current_backseat
|
||||
@@ -126,10 +127,6 @@
|
||||
if(QDELETED(body))
|
||||
qdel(src) //in case trauma deletion doesn't already do it
|
||||
|
||||
if((body.stat == DEAD && trauma.owner_backseat == src))
|
||||
trauma.switch_personalities()
|
||||
qdel(trauma)
|
||||
|
||||
//if one of the two ghosts, the other one stays permanently
|
||||
if(!body.client && trauma.initialized)
|
||||
trauma.switch_personalities()
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
//title_image = ntitle_image
|
||||
|
||||
/datum/browser/proc/add_stylesheet(name, file)
|
||||
if (istype(name, /datum/asset/spritesheet))
|
||||
if(istype(name, /datum/asset/spritesheet))
|
||||
var/datum/asset/spritesheet/sheet = name
|
||||
stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]"
|
||||
else
|
||||
@@ -72,9 +72,9 @@
|
||||
|
||||
return {"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<head>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||
[head_content]
|
||||
</head>
|
||||
<body scroll=auto>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
var/obj/screen/craft/C = new()
|
||||
C.icon = H.ui_style
|
||||
H.static_inventory += C
|
||||
if(!CL.prefs.widescreenpref)
|
||||
C.screen_loc = ui_boxcraft
|
||||
CL.screen += C
|
||||
RegisterSignal(C, COMSIG_CLICK, .proc/component_ui_interact)
|
||||
|
||||
|
||||
+212
-57
@@ -14,26 +14,32 @@
|
||||
name = "Glass working tools"
|
||||
desc = "A lovely belt of most the tools you will need to shape, mold, and refine glass into more advanced shapes."
|
||||
icon_state = "glass_tools"
|
||||
tool_behaviour = TOOL_GLASS_CUT
|
||||
tool_behaviour = TOOL_GLASS_CUT //Cutting takes 20 ticks
|
||||
|
||||
/obj/item/glasswork/blowing_rod
|
||||
name = "Glass working blow rod"
|
||||
desc = "A hollow metal stick made for glass blowing."
|
||||
icon_state = "blowing_rods_unused"
|
||||
tool_behaviour = TOOL_BLOW
|
||||
tool_behaviour = TOOL_BLOW //Rods take 5 ticks
|
||||
|
||||
/obj/item/glasswork/glass_base
|
||||
/obj/item/glasswork/glass_base //Welding takes 30 ticks
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A sheet of glass set aside for glass working"
|
||||
icon_state = "glass_base"
|
||||
var/next_step = null
|
||||
var/rod = /obj/item/glasswork/blowing_rod
|
||||
|
||||
/obj/item/lens
|
||||
name = "Optical lens"
|
||||
desc = "Good for selling or crafting, by itself its useless"
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "glass_optics"
|
||||
/obj/item/tea_plate
|
||||
name = "Tea Plate"
|
||||
desc = "A polished plate for a tea cup. How fancy!"
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "tea_plate"
|
||||
|
||||
/obj/item/tea_cup
|
||||
name = "Tea Cup"
|
||||
desc = "A glass cup made for fake tea!"
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "tea_plate"
|
||||
|
||||
//////////////////////Chem Disk/////////////////////
|
||||
//Two Steps //
|
||||
@@ -49,8 +55,9 @@
|
||||
/obj/item/glasswork/glass_base/dish/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_GLASS_CUT)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,20, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/dish_part1
|
||||
name = "Half chem dish sheet"
|
||||
@@ -61,8 +68,9 @@
|
||||
/obj/item/glasswork/glass_base/dish_part1/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_GLASS_CUT)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,20, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
//////////////////////Lens//////////////////////////
|
||||
//Six Steps //
|
||||
@@ -78,8 +86,9 @@
|
||||
/obj/item/glasswork/glass_base/glass_lens/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_GLASS_CUT)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,20, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part1
|
||||
name = "Glass fodder sheet"
|
||||
@@ -90,8 +99,9 @@
|
||||
/obj/item/glasswork/glass_base/glass_lens_part1/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_WELDER)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,30, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part2
|
||||
name = "Glass fodder sheet"
|
||||
@@ -102,8 +112,9 @@
|
||||
/obj/item/glasswork/glass_base/glass_lens_part2/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_WELDER)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,30, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part3
|
||||
name = "Glass fodder sheet"
|
||||
@@ -114,9 +125,10 @@
|
||||
/obj/item/glasswork/glass_base/glass_lens_part3/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_BLOW)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(I)
|
||||
if(do_after(user,5, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part4
|
||||
name = "Glass fodder sheet"
|
||||
@@ -127,29 +139,31 @@
|
||||
/obj/item/glasswork/glass_base/glass_lens_part4/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_GLASS_CUT)
|
||||
new next_step(user.loc, 1)
|
||||
new rod(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,20, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
new rod(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part5
|
||||
name = "Unpolished glass lens"
|
||||
desc = "A small unpolished glass lens. Could be polished with some cloth."
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
desc = "A small unpolished glass lens. Could be polished with some silk."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "glass_optics"
|
||||
next_step = /obj/item/glasswork/glass_base/glass_lens_part6
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part5/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/stack/sheet/cloth))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
if(istype(I, /obj/item/stack/sheet/silk))
|
||||
if(do_after(user,10, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part6
|
||||
name = "Unrefined glass lens"
|
||||
desc = "A small polished glass lens. Just needs to be refined with some sandstone."
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "glass_optics"
|
||||
next_step = /obj/item/lens
|
||||
next_step = /obj/item/glasswork/glass_base/lens
|
||||
|
||||
/obj/item/glasswork/glass_base/glass_lens_part6/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
@@ -171,8 +185,9 @@
|
||||
/obj/item/glasswork/glass_base/spouty/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_GLASS_CUT)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,20, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/spouty_part2
|
||||
name = "Glass fodder sheet"
|
||||
@@ -183,8 +198,9 @@
|
||||
/obj/item/glasswork/glass_base/spouty_part2/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_WELDER)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,30, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/spouty_part3
|
||||
name = "Glass fodder sheet"
|
||||
@@ -195,9 +211,10 @@
|
||||
/obj/item/glasswork/glass_base/spouty_part3/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_BLOW)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(I)
|
||||
if(do_after(user,5, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/spouty_part4
|
||||
name = "Glass fodder sheet"
|
||||
@@ -208,9 +225,10 @@
|
||||
/obj/item/glasswork/glass_base/spouty_part4/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_GLASS_CUT)
|
||||
new next_step(user.loc, 1)
|
||||
new rod(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,20, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
new rod(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
//////////////////////Small Bulb Flask//////////////
|
||||
//Two Steps //
|
||||
@@ -226,8 +244,9 @@
|
||||
/obj/item/glasswork/glass_base/flask_small/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_WELDER)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,30, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_small_part1
|
||||
name = "Metled glass"
|
||||
@@ -238,9 +257,10 @@
|
||||
/obj/item/glasswork/glass_base/flask_small_part1/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_BLOW)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(I)
|
||||
if(do_after(user,5, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_small_part2
|
||||
name = "Metled glass"
|
||||
@@ -251,9 +271,10 @@
|
||||
/obj/item/glasswork/glass_base/flask_small_part2/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_GLASS_CUT)
|
||||
new next_step(user.loc, 1)
|
||||
new rod(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,20, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
new rod(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
//////////////////////Large Bulb Flask//////////////
|
||||
//Two Steps //
|
||||
@@ -269,8 +290,9 @@
|
||||
/obj/item/glasswork/glass_base/flask_large/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_WELDER)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,30, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_large_part1
|
||||
name = "Metled glass"
|
||||
@@ -281,9 +303,10 @@
|
||||
/obj/item/glasswork/glass_base/flask_large_part1/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_BLOW)
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(I)
|
||||
if(do_after(user,5, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/flask_large_part2
|
||||
name = "Metled glass"
|
||||
@@ -294,6 +317,138 @@
|
||||
/obj/item/glasswork/glass_base/flask_large_part2/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_GLASS_CUT)
|
||||
new next_step(user.loc, 1)
|
||||
new rod(user.loc, 1)
|
||||
qdel(src)
|
||||
if(do_after(user,20, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
new rod(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
//////////////////////Tea Plates////////////////////
|
||||
//Three Steps //
|
||||
//Sells for 1200 cr, takes 5 glass shets //
|
||||
//Usefull for selling and chemical things //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A set of glass sheets set aside for glass working, this one is ideal for a tea plate, how fancy! Needs to be heated with some tools."
|
||||
next_step = /obj/item/glasswork/glass_base/tea_plate1
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_WELDER)
|
||||
if(do_after(user,30, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate1
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass, this one is ideal for a tea plate. Needs to be blown with some tools."
|
||||
icon_state = "glass_base_molding"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_plate2
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate1/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_BLOW)
|
||||
if(do_after(user,5, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate2
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass on the end of a blowing rod. Needs to be cut off with some tools."
|
||||
icon_state = "blowing_rods_inuse"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_plate3
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate2/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_GLASS_CUT)
|
||||
if(do_after(user,20, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
new rod(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate3
|
||||
name = "Disk of glass"
|
||||
desc = "A disk of glass that can be cant be used for much. Needs to be polished with some silk."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/tea_plate
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_plate3/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/stack/sheet/silk))
|
||||
if(do_after(user,10, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
//////////////////////Tea Cup///////////////////////
|
||||
//Four Steps //
|
||||
//Sells for 1800 cr, takes 6 glass shets //
|
||||
//Usefull for selling and chemical things //
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup
|
||||
name = "Glass fodder sheet"
|
||||
desc = "A set of glass sheets set aside for glass working, this one is ideal for a tea cup, how fancy! Needs to be heated with some tools."
|
||||
next_step = /obj/item/glasswork/glass_base/tea_cup1
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_WELDER)
|
||||
if(do_after(user,30, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup1
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass, this one is ideal for a tea cup. Needs to be blown with some tools."
|
||||
icon_state = "glass_base_molding"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_cup2
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup1/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_BLOW)
|
||||
if(do_after(user,5, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(I)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cupe2
|
||||
name = "Metled glass"
|
||||
desc = "A blob of metled glass on the end of a blowing rod. Needs to be cut off with some tools."
|
||||
icon_state = "blowing_rods_inuse"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_cup3
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup2/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_GLASS_CUT)
|
||||
if(do_after(user,20, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
new rod(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup3
|
||||
name = "Disk of glass"
|
||||
desc = "A bowl of glass that can be cant be used for much. Needs to be polished with some silk."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/glasswork/glass_base/tea_cup4
|
||||
|
||||
/obj/item/glasswork/glass_base/cup3/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/stack/sheet/silk))
|
||||
if(do_after(user,10, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/tea_cup4
|
||||
name = "Disk of glass"
|
||||
desc = "A bowl of polished glass that can be cant be used for much. Needs some more glass to make a handle."
|
||||
icon_state = "glass_base_half"
|
||||
next_step = /obj/item/tea_cup
|
||||
|
||||
/obj/item/glasswork/glass_base/cup4/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/stack/sheet/glass))
|
||||
if(do_after(user,10, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
@@ -0,0 +1,98 @@
|
||||
//This file is for crafting using a lens!
|
||||
|
||||
/obj/item/glasswork/glass_base/lens
|
||||
name = "Optical lens"
|
||||
desc = "Good for selling or crafting, by itself its useless"
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "glass_optics"
|
||||
|
||||
//Laser pointers - 2600
|
||||
/obj/item/glasswork/glass_base/laserpointer_shell
|
||||
name = "Laser pointer assembly"
|
||||
desc = "Good for selling or crafting, by itself its useless. Needs a power capactor."
|
||||
icon_state = "laser_case"
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
next_step = /obj/item/glasswork/glass_base/laserpointer_shell_1
|
||||
|
||||
/obj/item/glasswork/glass_base/laserpointer_shell/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/stock_parts/capacitor))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/laserpointer_shell_1
|
||||
name = "Laser pointer assembly"
|
||||
desc = "Good for selling or crafting, by itself its useless. Needs a glass lens."
|
||||
icon_state = "laser_wire"
|
||||
icon_state = "laser_case"
|
||||
next_step = /obj/item/glasswork/glass_base/laserpointer_shell_2
|
||||
|
||||
/obj/item/glasswork/glass_base/laserpointer_shell_1/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/glasswork/glass_base/lens))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/laserpointer_shell_2
|
||||
name = "Laser pointer assembly"
|
||||
desc = "Good for selling or crafting, by itself its useless. Needs to be screwed together."
|
||||
icon_state = "laser_wire"
|
||||
icon_state = "laser_case"
|
||||
next_step = /obj/item/laser_pointer/blue/handmade
|
||||
|
||||
/obj/item/glasswork/glass_base/laserpointer_shell_2/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
if(do_after(user,260, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
//NERD SHIT - 5000
|
||||
|
||||
/obj/item/glasswork/glass_base/glasses_frame
|
||||
name = "Glasses Frame"
|
||||
desc = "Good for crafting a pare of glasses, by itself its useless. Just add a pare of lens."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "frames"
|
||||
next_step = /obj/item/glasswork/glass_base/glasses_frame_1
|
||||
|
||||
/obj/item/glasswork/glass_base/glasses_frame/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/glasswork/glass_base/lens))
|
||||
if(do_after(user,60, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glasses_frame_1
|
||||
name = "Glasses Frame"
|
||||
desc = "Good for crafting a pare of glasses, by itself its useless. Just add a the other lens."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "frames_1"
|
||||
next_step = /obj/item/glasswork/glass_base/glasses_frame_2
|
||||
|
||||
/obj/item/glasswork/glass_base/glasses_frame_1/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/glasswork/glass_base/lens))
|
||||
if(do_after(user,60, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glass_base/glasses_frame_2
|
||||
name = "Glasses Frame"
|
||||
desc = "Good for crafting a pare of glasses, by itself its useless. Just adjust the pices into the frame with a screwdriver."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "frames_2"
|
||||
next_step = /obj/item/glasswork/glasses
|
||||
|
||||
/obj/item/glasswork/glass_base/glasses_frame_2/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(I.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
if(do_after(user,180, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glasses
|
||||
name = "Hand Made Glasses"
|
||||
desc = "Hande made glasses that have not been polished at all making them useless. Selling them could still be worth a bit of credits."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "frames_2"
|
||||
@@ -33,6 +33,13 @@
|
||||
/obj/item/organ/ears/cat = 1)
|
||||
category = CAT_CLOTHING
|
||||
|
||||
/datum/crafting_recipe/papermask
|
||||
name = "Paper Mask"
|
||||
result = /obj/item/clothing/mask/paper
|
||||
time = 10
|
||||
reqs = list(/obj/item/paper = 20)
|
||||
category = CAT_CLOTHING
|
||||
|
||||
////////
|
||||
//Huds//
|
||||
////////
|
||||
@@ -287,3 +294,12 @@
|
||||
/obj/item/bedsheet/cosmos = 1)
|
||||
time = 60
|
||||
category = CAT_CLOTHING
|
||||
|
||||
|
||||
/datum/crafting_recipe/garlic_necklace
|
||||
name = "Garlic Necklace"
|
||||
result = /obj/item/clothing/neck/garlic_necklace
|
||||
reqs = list(/obj/item/reagent_containers/food/snacks/grown/garlic = 15,
|
||||
/obj/item/stack/cable_coil = 10)
|
||||
time = 100 //Takes awhile to put all the garlics on the coil and knot it.
|
||||
category = CAT_CLOTHING
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//This component applies a customizable drop_shadow filter to its wearer when they toggle combat mode on or off. This can stack.
|
||||
|
||||
/datum/component/wearertargeting/phantomthief
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
||||
signals = list(COMSIG_LIVING_COMBAT_ENABLED)
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
signals = list(COMSIG_LIVING_COMBAT_ENABLED, COMSIG_LIVING_COMBAT_DISABLED)
|
||||
proctype = .proc/handlefilterstuff
|
||||
var/filter_x
|
||||
var/filter_y
|
||||
@@ -19,8 +19,8 @@
|
||||
filter_color = _color
|
||||
valid_slots = _valid_slots
|
||||
|
||||
/datum/component/wearertargeting/phantomthief/proc/handlefilterstuff(datum/source, mob/user, combatmodestate)
|
||||
if(!combatmodestate)
|
||||
/datum/component/wearertargeting/phantomthief/proc/handlefilterstuff(mob/living/user, was_forced = FALSE)
|
||||
if(!(user.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
|
||||
user.remove_filter("phantomthief")
|
||||
else
|
||||
user.add_filter("phantomthief", 4, list(type = "drop_shadow", x = filter_x, y = filter_y, size = filter_size, color = filter_color))
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK_OBJ, .proc/rad_attack)
|
||||
else
|
||||
CRASH("Something that wasn't an atom was given /datum/component/radioactive")
|
||||
return
|
||||
|
||||
if(strength > RAD_MINIMUM_CONTAMINATION)
|
||||
SSradiation.warn(src)
|
||||
@@ -84,4 +83,4 @@
|
||||
#undef RAD_AMOUNT_LOW
|
||||
#undef RAD_AMOUNT_MEDIUM
|
||||
#undef RAD_AMOUNT_HIGH
|
||||
#undef RAD_AMOUNT_EXTREME
|
||||
#undef RAD_AMOUNT_EXTREME
|
||||
|
||||
@@ -191,20 +191,28 @@
|
||||
|
||||
///////Yes, I said humans. No, this won't end well...//////////
|
||||
/datum/component/riding/human
|
||||
var/fireman_carrying = FALSE
|
||||
|
||||
/datum/component/riding/human/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(parent, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
|
||||
|
||||
/datum/component/riding/human/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
|
||||
var/mob/living/carbon/human/H = parent
|
||||
H.remove_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING)
|
||||
. = ..()
|
||||
var/mob/living/carbon/human/H = parent
|
||||
if(!length(H.buckled_mobs))
|
||||
H.remove_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING)
|
||||
if(!fireman_carrying)
|
||||
M.Daze(25)
|
||||
REMOVE_TRAIT(M, TRAIT_MOBILITY_NOUSE, src)
|
||||
|
||||
/datum/component/riding/human/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
|
||||
. = ..()
|
||||
var/mob/living/carbon/human/H = parent
|
||||
H.add_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING, multiplicative_slowdown = HUMAN_CARRY_SLOWDOWN)
|
||||
if(length(H.buckled_mobs))
|
||||
H.add_movespeed_modifier(MOVESPEED_ID_HUMAN_CARRYING, multiplicative_slowdown = fireman_carrying? FIREMAN_CARRY_SLOWDOWN : PIGGYBACK_CARRY_SLOWDOWN)
|
||||
if(fireman_carrying)
|
||||
ADD_TRAIT(M, TRAIT_MOBILITY_NOUSE, src)
|
||||
|
||||
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target)
|
||||
var/mob/living/carbon/human/H = parent
|
||||
@@ -236,11 +244,11 @@
|
||||
else
|
||||
return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4))
|
||||
|
||||
|
||||
/datum/component/riding/human/force_dismount(mob/living/user)
|
||||
var/atom/movable/AM = parent
|
||||
AM.unbuckle_mob(user)
|
||||
user.DefaultCombatKnockdown(60)
|
||||
user.Daze(50)
|
||||
user.visible_message("<span class='warning'>[AM] pushes [user] off of [AM.p_them()]!</span>")
|
||||
|
||||
/datum/component/riding/cyborg
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
_contents_limbo = null
|
||||
if(_user_limbo)
|
||||
for(var/i in _user_limbo)
|
||||
show_to(i)
|
||||
ui_show(i)
|
||||
_user_limbo = null
|
||||
|
||||
/datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
return
|
||||
. = COMPONENT_NO_ATTACK_HAND
|
||||
if(!check_locked(source, user, TRUE))
|
||||
show_to(user)
|
||||
ui_show(user)
|
||||
A.do_jiggle()
|
||||
if(rustle_sound)
|
||||
playsound(A, "rustle", 50, 1, -5)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
allow_quick_gather = TRUE
|
||||
allow_quick_empty = TRUE
|
||||
click_gather = TRUE
|
||||
storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = 100
|
||||
max_items = 100
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//Stack-only storage.
|
||||
/datum/component/storage/concrete/stack
|
||||
display_numerical_stacking = TRUE
|
||||
storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT
|
||||
var/max_combined_stack_amount = 300
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = WEIGHT_CLASS_NORMAL * 14
|
||||
|
||||
@@ -22,9 +22,16 @@
|
||||
|
||||
var/locked = FALSE //when locked nothing can see inside or use it.
|
||||
|
||||
var/max_w_class = WEIGHT_CLASS_SMALL //max size of objects that will fit.
|
||||
var/max_combined_w_class = 14 //max combined sizes of objects that will fit.
|
||||
var/max_items = 7 //max number of objects that will fit.
|
||||
/// Storage flags, including what kinds of limiters we use for how many items we can hold
|
||||
var/storage_flags = STORAGE_FLAGS_LEGACY_DEFAULT
|
||||
/// Max w_class we can hold. Applies to [STORAGE_LIMIT_COMBINED_W_CLASS] and [STORAGE_LIMIT_VOLUME]
|
||||
var/max_w_class = WEIGHT_CLASS_SMALL
|
||||
/// Max combined w_class. Applies to [STORAGE_LIMIT_COMBINED_W_CLASS]
|
||||
var/max_combined_w_class = WEIGHT_CLASS_SMALL * 7
|
||||
/// Max items we can hold. Applies to [STORAGE_LIMIT_MAX_ITEMS]
|
||||
var/max_items = 7
|
||||
/// Max volume we can hold. Applies to [STORAGE_LIMIT_VOLUME]. Auto scaled on New() if unset.
|
||||
var/max_volume
|
||||
|
||||
var/emp_shielded = FALSE
|
||||
|
||||
@@ -40,8 +47,17 @@
|
||||
|
||||
var/display_numerical_stacking = FALSE //stack things of the same type and show as a single object with a number.
|
||||
|
||||
var/obj/screen/storage/boxes //storage display object
|
||||
var/obj/screen/close/closer //close button object
|
||||
/// "legacy"/default view mode's storage "boxes"
|
||||
var/obj/screen/storage/boxes/ui_boxes
|
||||
/// New volumetric storage display mode's left side
|
||||
var/obj/screen/storage/left/ui_left
|
||||
/// New volumetric storage display mode's center 'blocks'
|
||||
var/obj/screen/storage/continuous/ui_continuous
|
||||
/// The close button, used in all modes. Frames right side in volumetric mode.
|
||||
var/obj/screen/storage/close/ui_close
|
||||
/// Associative list of list(item = screen object) for volumetric storage item screen blocks
|
||||
var/list/ui_item_blocks
|
||||
|
||||
var/current_maxscreensize
|
||||
|
||||
var/allow_big_nesting = FALSE //allow storage objects of the same or greater size.
|
||||
@@ -69,9 +85,6 @@
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
if(master)
|
||||
change_master(master)
|
||||
boxes = new(null, src)
|
||||
closer = new(null, src)
|
||||
orient2hud()
|
||||
|
||||
RegisterSignal(parent, COMSIG_CONTAINS_STORAGE, .proc/on_check)
|
||||
RegisterSignal(parent, COMSIG_IS_STORAGE_LOCKED, .proc/check_locked)
|
||||
@@ -112,8 +125,15 @@
|
||||
|
||||
/datum/component/storage/Destroy()
|
||||
close_all()
|
||||
QDEL_NULL(boxes)
|
||||
QDEL_NULL(closer)
|
||||
QDEL_NULL(ui_boxes)
|
||||
QDEL_NULL(ui_close)
|
||||
QDEL_NULL(ui_continuous)
|
||||
QDEL_NULL(ui_left)
|
||||
// DO NOT USE QDEL_LIST_ASSOC.
|
||||
if(ui_item_blocks)
|
||||
for(var/i in ui_item_blocks)
|
||||
qdel(ui_item_blocks[i]) //qdel the screen object not the item
|
||||
ui_item_blocks.Cut()
|
||||
LAZYCLEARLIST(is_using)
|
||||
return ..()
|
||||
|
||||
@@ -287,7 +307,7 @@
|
||||
if(!_target)
|
||||
_target = get_turf(parent)
|
||||
if(usr)
|
||||
hide_from(usr)
|
||||
ui_hide(usr)
|
||||
var/list/contents = contents()
|
||||
var/atom/real_location = real_location()
|
||||
for(var/obj/item/I in contents)
|
||||
@@ -301,106 +321,8 @@
|
||||
if(check_locked())
|
||||
close_all()
|
||||
|
||||
/datum/component/storage/proc/_process_numerical_display()
|
||||
. = list()
|
||||
for(var/obj/item/I in accessible_items())
|
||||
if(QDELETED(I))
|
||||
continue
|
||||
if(!.[I.type])
|
||||
.[I.type] = new /datum/numbered_display(I, 1)
|
||||
else
|
||||
var/datum/numbered_display/ND = .[I.type]
|
||||
ND.number++
|
||||
. = sortTim(., /proc/cmp_numbered_displays_name_asc, associative = TRUE)
|
||||
|
||||
//This proc determines the size of the inventory to be displayed. Please touch it only if you know what you're doing.
|
||||
/datum/component/storage/proc/orient2hud(mob/user, maxcolumns)
|
||||
var/list/accessible_contents = accessible_items()
|
||||
var/adjusted_contents = length(accessible_contents)
|
||||
|
||||
//Numbered contents display
|
||||
var/list/datum/numbered_display/numbered_contents
|
||||
if(display_numerical_stacking)
|
||||
numbered_contents = _process_numerical_display()
|
||||
adjusted_contents = numbered_contents.len
|
||||
|
||||
var/columns = CLAMP(max_items, 1, maxcolumns ? maxcolumns : screen_max_columns)
|
||||
var/rows = CLAMP(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows)
|
||||
standard_orient_objs(rows, columns, numbered_contents)
|
||||
|
||||
//This proc draws out the inventory and places the items on it. It uses the standard position.
|
||||
/datum/component/storage/proc/standard_orient_objs(rows, cols, list/obj/item/numerical_display_contents)
|
||||
boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+cols-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]"
|
||||
var/cx = screen_start_x
|
||||
var/cy = screen_start_y
|
||||
if(islist(numerical_display_contents))
|
||||
for(var/type in numerical_display_contents)
|
||||
var/datum/numbered_display/ND = numerical_display_contents[type]
|
||||
ND.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
ND.sample_object.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
|
||||
ND.sample_object.maptext = "<font color='white'>[(ND.number > 1)? "[ND.number]" : ""]</font>"
|
||||
ND.sample_object.layer = ABOVE_HUD_LAYER
|
||||
ND.sample_object.plane = ABOVE_HUD_PLANE
|
||||
cx++
|
||||
if(cx - screen_start_x >= cols)
|
||||
cx = screen_start_x
|
||||
cy++
|
||||
if(cy - screen_start_y >= rows)
|
||||
break
|
||||
else
|
||||
for(var/obj/O in accessible_items())
|
||||
if(QDELETED(O))
|
||||
continue
|
||||
O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip"
|
||||
O.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
|
||||
O.maptext = ""
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
cx++
|
||||
if(cx - screen_start_x >= cols)
|
||||
cx = screen_start_x
|
||||
cy++
|
||||
if(cy - screen_start_y >= rows)
|
||||
break
|
||||
closer.screen_loc = "[screen_start_x + cols]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]"
|
||||
|
||||
/datum/component/storage/proc/show_to(mob/M, set_screen_size = TRUE)
|
||||
if(!M.client)
|
||||
return FALSE
|
||||
var/list/cview = getviewsize(M.client.view)
|
||||
var/maxallowedscreensize = cview[1]-8
|
||||
if(set_screen_size)
|
||||
current_maxscreensize = maxallowedscreensize
|
||||
else if(current_maxscreensize)
|
||||
maxallowedscreensize = current_maxscreensize
|
||||
if(M.active_storage != src && (M.stat == CONSCIOUS))
|
||||
for(var/obj/item/I in accessible_items())
|
||||
if(I.on_found(M))
|
||||
return FALSE
|
||||
if(M.active_storage)
|
||||
M.active_storage.hide_from(M)
|
||||
orient2hud(M, (isliving(M) ? maxallowedscreensize : 7))
|
||||
M.client.screen |= boxes
|
||||
M.client.screen |= closer
|
||||
M.client.screen |= accessible_items()
|
||||
M.active_storage = src
|
||||
LAZYOR(is_using, M)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/hide_from(mob/M)
|
||||
if(!M.client)
|
||||
return TRUE
|
||||
var/atom/real_location = real_location()
|
||||
M.client.screen -= boxes
|
||||
M.client.screen -= closer
|
||||
M.client.screen -= real_location.contents
|
||||
if(M.active_storage == src)
|
||||
M.active_storage = null
|
||||
LAZYREMOVE(is_using, M)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/close(mob/M)
|
||||
hide_from(M)
|
||||
ui_hide(M)
|
||||
|
||||
/datum/component/storage/proc/close_all()
|
||||
. = FALSE
|
||||
@@ -419,25 +341,6 @@
|
||||
var/datum/component/storage/concrete/master = master()
|
||||
master.emp_act(source, severity)
|
||||
|
||||
//This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right.
|
||||
//The numbers are calculated from the bottom-left The bottom-left slot being 1,1.
|
||||
/datum/component/storage/proc/orient_objs(tx, ty, mx, my)
|
||||
var/atom/real_location = real_location()
|
||||
var/cx = tx
|
||||
var/cy = ty
|
||||
boxes.screen_loc = "[tx]:,[ty] to [mx],[my]"
|
||||
for(var/obj/O in real_location)
|
||||
if(QDELETED(O))
|
||||
continue
|
||||
O.screen_loc = "[cx],[cy]"
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
cx++
|
||||
if(cx > mx)
|
||||
cx = tx
|
||||
cy--
|
||||
closer.screen_loc = "[mx+1],[my]"
|
||||
|
||||
//Resets something that is being removed from storage.
|
||||
/datum/component/storage/proc/_removal_reset(atom/movable/thing)
|
||||
if(!istype(thing))
|
||||
@@ -449,6 +352,9 @@
|
||||
|
||||
/datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/thing)
|
||||
_removal_reset(thing)
|
||||
if(LAZYACCESS(ui_item_blocks, thing))
|
||||
qdel(ui_item_blocks[thing])
|
||||
ui_item_blocks -= thing
|
||||
refresh_mob_views()
|
||||
|
||||
//Call this proc to handle the removal of an item from the storage item. The item will be moved to the new_location target, if that is null it's being deleted
|
||||
@@ -463,7 +369,7 @@
|
||||
/datum/component/storage/proc/refresh_mob_views()
|
||||
var/list/seeing = can_see_contents()
|
||||
for(var/i in seeing)
|
||||
show_to(i)
|
||||
ui_show(i)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/can_see_contents()
|
||||
@@ -560,7 +466,7 @@
|
||||
A.add_fingerprint(M)
|
||||
if(!force && (check_locked(null, M) || !M.CanReach(parent, view_only = TRUE)))
|
||||
return FALSE
|
||||
show_to(M, !ghost)
|
||||
ui_show(M, !ghost)
|
||||
|
||||
/datum/component/storage/proc/mousedrop_receive(datum/source, atom/movable/O, mob/M)
|
||||
if(isitem(O))
|
||||
@@ -588,10 +494,6 @@
|
||||
if(M && !stop_messages)
|
||||
host.add_fingerprint(M)
|
||||
return FALSE
|
||||
if(real_location.contents.len >= max_items)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[host] is full, make some space!</span>")
|
||||
return FALSE //Storage item is full
|
||||
if(!length(can_hold_extra) || !is_type_in_typecache(I, can_hold_extra))
|
||||
if(length(can_hold))
|
||||
if(!is_type_in_typecache(I, can_hold))
|
||||
@@ -602,17 +504,34 @@
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[host] cannot hold [I]!</span>")
|
||||
return FALSE
|
||||
if(I.w_class > max_w_class)
|
||||
if(storage_flags & STORAGE_LIMIT_MAX_W_CLASS)
|
||||
if(I.w_class > max_w_class)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[I] is too long for [host]!</span>")
|
||||
return FALSE
|
||||
// STORAGE LIMITS
|
||||
if(storage_flags & STORAGE_LIMIT_MAX_ITEMS)
|
||||
if(real_location.contents.len >= max_items)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[I] is too big for [host]!</span>")
|
||||
to_chat(M, "<span class='warning'>[host] has too many things in it, make some space!</span>")
|
||||
return FALSE //Storage item is full
|
||||
if(storage_flags & STORAGE_LIMIT_COMBINED_W_CLASS)
|
||||
var/sum_w_class = I.w_class
|
||||
for(var/obj/item/_I in real_location)
|
||||
sum_w_class += _I.w_class //Adds up the combined w_classes which will be in the storage item if the item is added to it.
|
||||
if(sum_w_class > max_combined_w_class)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[I] won't fit in [host], make some space!</span>")
|
||||
return FALSE
|
||||
var/sum_w_class = I.w_class
|
||||
for(var/obj/item/_I in real_location)
|
||||
sum_w_class += _I.w_class //Adds up the combined w_classes which will be in the storage item if the item is added to it.
|
||||
if(sum_w_class > max_combined_w_class)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[I] won't fit in [host], make some space!</span>")
|
||||
return FALSE
|
||||
if(storage_flags & STORAGE_LIMIT_VOLUME)
|
||||
var/sum_volume = I.get_w_volume()
|
||||
for(var/obj/item/_I in real_location)
|
||||
sum_volume += _I.get_w_volume()
|
||||
if(sum_volume > get_max_volume())
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[I] is too spacious to fit in [host], make some space!</span>")
|
||||
return FALSE
|
||||
/////////////////
|
||||
if(isitem(host))
|
||||
var/obj/item/IP = host
|
||||
var/datum/component/storage/STR_I = I.GetComponent(/datum/component/storage)
|
||||
@@ -744,7 +663,7 @@
|
||||
if(A.loc == user)
|
||||
. = COMPONENT_NO_ATTACK_HAND
|
||||
if(!check_locked(source, user, TRUE))
|
||||
show_to(user)
|
||||
ui_show(user)
|
||||
A.do_jiggle()
|
||||
|
||||
/datum/component/storage/proc/signal_on_pickup(datum/source, mob/user)
|
||||
@@ -763,7 +682,7 @@
|
||||
return do_quick_empty(loctarget)
|
||||
|
||||
/datum/component/storage/proc/signal_hide_attempt(datum/source, mob/target)
|
||||
return hide_from(target)
|
||||
return ui_hide(target)
|
||||
|
||||
/datum/component/storage/proc/on_alt_click(datum/source, mob/user)
|
||||
if(!isliving(user) || !user.CanReach(parent))
|
||||
@@ -792,7 +711,7 @@
|
||||
user.visible_message("<span class='warning'>[user] draws [I] from [parent]!</span>", "<span class='notice'>You draw [I] from [parent].</span>")
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/action_trigger(datum/signal_source, datum/action/source)
|
||||
/datum/component/storage/proc/action_trigger(datum/action/source, obj/target)
|
||||
gather_mode_switch(source.owner)
|
||||
return COMPONENT_ACTION_BLOCK_TRIGGER
|
||||
|
||||
@@ -805,3 +724,9 @@
|
||||
to_chat(user, "[parent] now picks up all items in a tile at once.")
|
||||
if(COLLECT_ONE)
|
||||
to_chat(user, "[parent] now picks up one item at a time.")
|
||||
|
||||
/**
|
||||
* Gets our max volume
|
||||
*/
|
||||
/datum/component/storage/proc/get_max_volume()
|
||||
return max_volume || AUTO_SCALE_STORAGE_VOLUME(max_w_class, max_combined_w_class)
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* Generates a list of numbered_display datums for the numerical display system.
|
||||
*/
|
||||
/datum/component/storage/proc/_process_numerical_display()
|
||||
. = list()
|
||||
for(var/obj/item/I in accessible_items())
|
||||
if(QDELETED(I))
|
||||
continue
|
||||
if(!.[I.type])
|
||||
.[I.type] = new /datum/numbered_display(I, 1)
|
||||
else
|
||||
var/datum/numbered_display/ND = .[I.type]
|
||||
ND.number++
|
||||
. = sortTim(., /proc/cmp_numbered_displays_name_asc, associative = TRUE)
|
||||
|
||||
/**
|
||||
* Orients all objects in legacy mode, and returns the objects to show to the user.
|
||||
*/
|
||||
/datum/component/storage/proc/orient2hud_legacy(mob/user, maxcolumns)
|
||||
. = list()
|
||||
var/list/accessible_contents = accessible_items()
|
||||
var/adjusted_contents = length(accessible_contents)
|
||||
|
||||
//Numbered contents display
|
||||
var/list/datum/numbered_display/numbered_contents
|
||||
if(display_numerical_stacking)
|
||||
numbered_contents = _process_numerical_display()
|
||||
adjusted_contents = numbered_contents.len
|
||||
|
||||
var/columns = CLAMP(max_items, 1, maxcolumns ? maxcolumns : screen_max_columns)
|
||||
var/rows = CLAMP(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows)
|
||||
|
||||
// First, boxes.
|
||||
ui_boxes = get_ui_boxes()
|
||||
ui_boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+columns-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]"
|
||||
. += ui_boxes
|
||||
// Then, closer.
|
||||
ui_close = get_ui_close()
|
||||
ui_close.screen_loc = "[screen_start_x + columns]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]"
|
||||
. += ui_close
|
||||
// Then orient the actual items.
|
||||
var/cx = screen_start_x
|
||||
var/cy = screen_start_y
|
||||
if(islist(numbered_contents))
|
||||
for(var/type in numbered_contents)
|
||||
var/datum/numbered_display/ND = numbered_contents[type]
|
||||
ND.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
ND.sample_object.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
|
||||
ND.sample_object.maptext = "<font color='white'>[(ND.number > 1)? "[ND.number]" : ""]</font>"
|
||||
ND.sample_object.layer = ABOVE_HUD_LAYER
|
||||
ND.sample_object.plane = ABOVE_HUD_PLANE
|
||||
. += ND.sample_object
|
||||
cx++
|
||||
if(cx - screen_start_x >= columns)
|
||||
cx = screen_start_x
|
||||
cy++
|
||||
if(cy - screen_start_y >= rows)
|
||||
break
|
||||
else
|
||||
for(var/obj/O in accessible_items())
|
||||
if(QDELETED(O))
|
||||
continue
|
||||
O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip"
|
||||
O.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
|
||||
O.maptext = ""
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
. += O
|
||||
cx++
|
||||
if(cx - screen_start_x >= columns)
|
||||
cx = screen_start_x
|
||||
cy++
|
||||
if(cy - screen_start_y >= rows)
|
||||
break
|
||||
|
||||
/**
|
||||
* Orients all objects in .. volumetric mode. Does not support numerical display!
|
||||
*/
|
||||
/datum/component/storage/proc/orient2hud_volumetric(mob/user, maxcolumns)
|
||||
. = list()
|
||||
|
||||
// Generate ui_item_blocks for missing ones and render+orient.
|
||||
var/list/atom/contents = accessible_items()
|
||||
// our volume
|
||||
var/our_volume = get_max_volume()
|
||||
var/horizontal_pixels = (maxcolumns * world.icon_size) - (VOLUMETRIC_STORAGE_EDGE_PADDING * 2)
|
||||
var/max_horizontal_pixels = horizontal_pixels * screen_max_rows
|
||||
// sigh loopmania time
|
||||
var/used = 0
|
||||
// define outside for performance
|
||||
var/volume
|
||||
var/list/volume_by_item = list()
|
||||
var/list/percentage_by_item = list()
|
||||
for(var/obj/item/I in contents)
|
||||
volume = I.get_w_volume()
|
||||
used += volume
|
||||
volume_by_item[I] = volume
|
||||
percentage_by_item[I] = volume / get_max_volume()
|
||||
var/padding_pixels = ((length(percentage_by_item) - 1) * VOLUMETRIC_STORAGE_ITEM_PADDING) + VOLUMETRIC_STORAGE_EDGE_PADDING * 2
|
||||
var/min_pixels = (MINIMUM_PIXELS_PER_ITEM * length(percentage_by_item)) + padding_pixels
|
||||
// do the check for fallback for when someone has too much gamer gear
|
||||
if((min_pixels) > (max_horizontal_pixels + 4)) // 4 pixel grace zone
|
||||
to_chat(user, "<span class='warning'>[parent] was showed to you in legacy mode due to your items overrunning the three row limit! Consider not carrying too much or bugging a maintainer to raise this limit!</span>")
|
||||
return orient2hud_legacy(user, maxcolumns)
|
||||
// after this point we are sure we can somehow fit all items into our max number of rows.
|
||||
|
||||
// determine rows
|
||||
var/rows = CLAMP(CEILING(min_pixels / horizontal_pixels, 1), 1, screen_max_rows)
|
||||
|
||||
var/overrun = FALSE
|
||||
if(used > our_volume)
|
||||
// congratulations we are now in overrun mode. everything will be crammed to minimum storage pixels.
|
||||
to_chat(user, "<span class='warning'>[parent] rendered in overrun mode due to more items inside than the maximum volume supports.</span>")
|
||||
overrun = TRUE
|
||||
|
||||
// how much we are using
|
||||
var/using_horizontal_pixels = horizontal_pixels * rows
|
||||
|
||||
// item padding
|
||||
using_horizontal_pixels -= padding_pixels
|
||||
|
||||
// define outside for marginal performance boost
|
||||
var/obj/item/I
|
||||
// start at this pixel from screen_start_x.
|
||||
var/current_pixel = VOLUMETRIC_STORAGE_EDGE_PADDING
|
||||
var/row = 1
|
||||
|
||||
LAZYINITLIST(ui_item_blocks)
|
||||
|
||||
for(var/i in percentage_by_item)
|
||||
I = i
|
||||
var/percent = percentage_by_item[I]
|
||||
if(!ui_item_blocks[I])
|
||||
ui_item_blocks[I] = new /obj/screen/storage/volumetric_box/center(null, src, I)
|
||||
var/obj/screen/storage/volumetric_box/center/B = ui_item_blocks[I]
|
||||
var/pixels_to_use = overrun? MINIMUM_PIXELS_PER_ITEM : max(using_horizontal_pixels * percent, MINIMUM_PIXELS_PER_ITEM)
|
||||
var/addrow = FALSE
|
||||
if(CEILING(pixels_to_use, 1) >= FLOOR(horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING, 1))
|
||||
pixels_to_use = horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING
|
||||
addrow = TRUE
|
||||
|
||||
// now that we have pixels_to_use, place our thing and add it to the returned list.
|
||||
|
||||
B.screen_loc = I.screen_loc = "[screen_start_x]:[round(current_pixel + (pixels_to_use * 0.5) + VOLUMETRIC_STORAGE_ITEM_PADDING, 1)],[screen_start_y+row-1]:[screen_pixel_y]"
|
||||
// add the used pixels to pixel after we place the object
|
||||
current_pixel += pixels_to_use + VOLUMETRIC_STORAGE_ITEM_PADDING
|
||||
|
||||
// set various things
|
||||
B.set_pixel_size(pixels_to_use)
|
||||
B.layer = VOLUMETRIC_STORAGE_BOX_LAYER
|
||||
B.plane = VOLUMETRIC_STORAGE_BOX_PLANE
|
||||
B.name = I.name
|
||||
|
||||
I.mouse_opacity = MOUSE_OPACITY_ICON
|
||||
I.maptext = ""
|
||||
I.layer = VOLUMETRIC_STORAGE_ITEM_LAYER
|
||||
I.plane = VOLUMETRIC_STORAGE_ITEM_PLANE
|
||||
|
||||
// finally add our things.
|
||||
. += B.on_screen_objects()
|
||||
. += I
|
||||
|
||||
// go up a row if needed
|
||||
if(addrow)
|
||||
row++
|
||||
current_pixel = VOLUMETRIC_STORAGE_EDGE_PADDING
|
||||
|
||||
// Then, continuous section.
|
||||
ui_continuous = get_ui_continuous()
|
||||
ui_continuous.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+maxcolumns-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]"
|
||||
. += ui_continuous
|
||||
// Then, left.
|
||||
ui_left = get_ui_left()
|
||||
ui_left.screen_loc = "[screen_start_x]:[screen_pixel_x - 2],[screen_start_y]:[screen_pixel_y] to [screen_start_x]:[screen_pixel_x - 2],[screen_start_y+rows-1]:[screen_pixel_y]"
|
||||
. += ui_left
|
||||
// Then, closer, which is also our right element.
|
||||
ui_close = get_ui_close()
|
||||
ui_close.screen_loc = "[screen_start_x + maxcolumns]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x + maxcolumns]:[screen_pixel_x],[screen_start_y + row - 1]:[screen_pixel_y]"
|
||||
. += ui_close
|
||||
|
||||
/**
|
||||
* Shows our UI to a mob.
|
||||
*/
|
||||
/datum/component/storage/proc/ui_show(mob/M, set_screen_size = TRUE)
|
||||
if(!M.client)
|
||||
return FALSE
|
||||
var/list/cview = getviewsize(M.client.view)
|
||||
// in tiles
|
||||
var/maxallowedscreensize = cview[1]-8
|
||||
if(set_screen_size)
|
||||
current_maxscreensize = maxallowedscreensize
|
||||
else if(current_maxscreensize)
|
||||
maxallowedscreensize = current_maxscreensize
|
||||
// we got screen size, register signal
|
||||
RegisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT, .proc/on_logout, override = TRUE)
|
||||
if(M.active_storage != src)
|
||||
if(M.active_storage)
|
||||
M.active_storage.ui_hide(M)
|
||||
M.active_storage = src
|
||||
LAZYOR(is_using, M)
|
||||
if(volumetric_ui())
|
||||
//new volumetric ui bay-style
|
||||
M.client.screen |= orient2hud_volumetric(M, maxallowedscreensize)
|
||||
else
|
||||
//old ui
|
||||
M.client.screen |= orient2hud_legacy(M, maxallowedscreensize)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* VV hooked to ensure no lingering screen objects.
|
||||
*/
|
||||
/datum/component/storage/vv_edit_var(var_name, var_value)
|
||||
var/list/old
|
||||
if(var_name == NAMEOF(src, storage_flags))
|
||||
old = is_using.Copy()
|
||||
for(var/i in is_using)
|
||||
ui_hide(i)
|
||||
. = ..()
|
||||
if(old)
|
||||
for(var/i in old)
|
||||
ui_show(i)
|
||||
|
||||
/**
|
||||
* Proc triggered by signal to ensure logging out clients don't linger.
|
||||
*/
|
||||
/datum/component/storage/proc/on_logout(datum/source, client/C)
|
||||
ui_hide(source)
|
||||
|
||||
/**
|
||||
* Hides our UI from a mob
|
||||
*/
|
||||
/datum/component/storage/proc/ui_hide(mob/M)
|
||||
if(!M.client)
|
||||
return TRUE
|
||||
UnregisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT)
|
||||
M.client.screen -= list(ui_boxes, ui_close, ui_left, ui_continuous) + get_ui_item_objects_hide()
|
||||
if(M.active_storage == src)
|
||||
M.active_storage = null
|
||||
LAZYREMOVE(is_using, M)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Returns TRUE if we are using volumetric UI instead of box UI
|
||||
*/
|
||||
/datum/component/storage/proc/volumetric_ui()
|
||||
var/atom/real_location = real_location()
|
||||
return (storage_flags & STORAGE_LIMIT_VOLUME) && (length(real_location.contents) <= MAXIMUM_VOLUMETRIC_ITEMS) && !display_numerical_stacking
|
||||
|
||||
/**
|
||||
* Gets the ui item objects to ui_hide.
|
||||
*/
|
||||
/datum/component/storage/proc/get_ui_item_objects_hide()
|
||||
if(!volumetric_ui())
|
||||
var/atom/real_location = real_location()
|
||||
return real_location.contents
|
||||
else
|
||||
. = list()
|
||||
for(var/i in ui_item_blocks)
|
||||
// get both the box and the item
|
||||
. += ui_item_blocks[i]
|
||||
. += i
|
||||
|
||||
/**
|
||||
* Gets our ui_boxes, making it if it doesn't exist.
|
||||
*/
|
||||
/datum/component/storage/proc/get_ui_boxes()
|
||||
if(!ui_boxes)
|
||||
ui_boxes = new(null, src)
|
||||
return ui_boxes
|
||||
|
||||
/**
|
||||
* Gets our ui_left, making it if it doesn't exist.
|
||||
*/
|
||||
/datum/component/storage/proc/get_ui_left()
|
||||
if(!ui_left)
|
||||
ui_left = new(null, src)
|
||||
return ui_left
|
||||
|
||||
/**
|
||||
* Gets our ui_close, making it if it doesn't exist.
|
||||
*/
|
||||
/datum/component/storage/proc/get_ui_close()
|
||||
if(!ui_close)
|
||||
ui_close = new(null, src)
|
||||
return ui_close
|
||||
|
||||
/**
|
||||
* Gets our ui_continuous, making it if it doesn't exist.
|
||||
*/
|
||||
/datum/component/storage/proc/get_ui_continuous()
|
||||
if(!ui_continuous)
|
||||
ui_continuous = new(null, src)
|
||||
return ui_continuous
|
||||
@@ -27,6 +27,8 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
var/datum/ui_state/checkstate
|
||||
var/compact_mode = FALSE
|
||||
var/debug = FALSE
|
||||
var/saved_player_population = 0
|
||||
var/list/filters = list()
|
||||
|
||||
/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate, datum/traitor_class/traitor_class)
|
||||
if(!isitem(parent))
|
||||
@@ -47,7 +49,6 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
RegisterSignal(parent, COMSIG_PEN_ROTATED, .proc/pen_rotation)
|
||||
|
||||
GLOB.uplinks += src
|
||||
var/list/filters = list()
|
||||
if(istype(traitor_class))
|
||||
filters = traitor_class.uplink_filters
|
||||
starting_tc = traitor_class.TC
|
||||
@@ -68,6 +69,7 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
if(!lockable)
|
||||
active = TRUE
|
||||
locked = FALSE
|
||||
saved_player_population = GLOB.joined_player_list.len
|
||||
|
||||
/datum/component/uplink/InheritComponent(datum/component/uplink/U)
|
||||
lockable |= U.lockable
|
||||
@@ -117,7 +119,18 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
return
|
||||
active = TRUE
|
||||
if(user)
|
||||
//update the saved population
|
||||
var/previous_player_population = saved_player_population
|
||||
saved_player_population = GLOB.joined_player_list.len
|
||||
//if population has changed, update uplink items
|
||||
if(saved_player_population != previous_player_population)
|
||||
//make sure discounts are not rerolled
|
||||
var/old_discounts = uplink_items["Discounted Gear"]
|
||||
uplink_items = get_uplink_items(gamemode, FALSE, allow_restricted, filters)
|
||||
if(old_discounts)
|
||||
uplink_items["Discounted Gear"] = old_discounts
|
||||
ui_interact(user)
|
||||
|
||||
// an unlocked uplink blocks also opening the PDA or headset menu
|
||||
return COMPONENT_NO_INTERACT
|
||||
|
||||
@@ -190,7 +203,9 @@ GLOBAL_LIST_EMPTY(uplinks)
|
||||
|
||||
if(item in buyable_items)
|
||||
var/datum/uplink_item/I = buyable_items[item]
|
||||
MakePurchase(usr, I)
|
||||
//check to make sure people cannot buy items when the player pop is below the requirement
|
||||
if(GLOB.joined_player_list.len >= I.player_minimum)
|
||||
MakePurchase(usr, I)
|
||||
. = TRUE
|
||||
if("lock")
|
||||
active = FALSE
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
/**
|
||||
*The following procs simply acts as hooks for quit(), since components do not use callbacks anymore
|
||||
*/
|
||||
/datum/component/virtual_reality/proc/action_trigger(datum/signal_source, datum/action/source)
|
||||
/datum/component/virtual_reality/proc/action_trigger(datum/action/source, obj/target)
|
||||
quit()
|
||||
return COMPONENT_ACTION_BLOCK_TRIGGER
|
||||
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
UnregisterSignal(equipper, signals)
|
||||
|
||||
/datum/component/wearertargeting/proc/on_drop(datum/source, mob/user)
|
||||
UnregisterSignal(user, signals)
|
||||
UnregisterSignal(user, signals)
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
var/datum/component/wet_floor/WF = newcomp //Lets make an assumption
|
||||
if(WF.gc()) //See if it's even valid, still. Also does LAZYLEN and stuff for us.
|
||||
CRASH("Wet floor component tried to inherit another, but the other was able to garbage collect while being inherited! What a waste of time!")
|
||||
return
|
||||
for(var/i in WF.time_left_list)
|
||||
add_wet(text2num(i), WF.time_left_list[i])
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
dashing_item = dasher
|
||||
holder = user
|
||||
|
||||
/datum/action/innate/dash/IsAvailable()
|
||||
/datum/action/innate/dash/IsAvailable(silent = FALSE)
|
||||
if(current_charges > 0)
|
||||
return TRUE
|
||||
else
|
||||
|
||||
@@ -109,6 +109,8 @@
|
||||
UnregisterSignal(target, signal_procs[target])
|
||||
//END: ECS SHIT
|
||||
|
||||
SSsounds.free_datum_channels(src)
|
||||
|
||||
return QDEL_HINT_QUEUE
|
||||
|
||||
#ifdef DATUMVAR_DEBUGGING_MODE
|
||||
@@ -173,11 +175,9 @@
|
||||
if(!islist(jsonlist))
|
||||
if(!istext(jsonlist))
|
||||
CRASH("Invalid JSON")
|
||||
return
|
||||
jsonlist = json_decode(jsonlist)
|
||||
if(!islist(jsonlist))
|
||||
CRASH("Invalid JSON")
|
||||
return
|
||||
if(!jsonlist["DATUM_TYPE"])
|
||||
return
|
||||
if(!ispath(jsonlist["DATUM_TYPE"]))
|
||||
|
||||
+23
-1378
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
viable_mobtypes = list(/mob/living/carbon/human)
|
||||
disease_flags = CAN_CARRY|CAN_RESIST|CURABLE
|
||||
permeability_mod = 0.75
|
||||
desc = "Some speculate that this virus is the cause of the Space Wizard Federation's existence. Subjects affected show the signs of mental retardation, yelling obscure sentences or total gibberish. On late stages subjects sometime express the feelings of inner power, and, cite, 'the ability to control the forces of cosmos themselves!' A gulp of strong, manly spirits usually reverts them to normal, humanlike, condition."
|
||||
desc = "Some speculate that this virus is the cause of the Space Wizard Federation's existence. Subjects affected show the signs of mental hysteria, yelling obscure sentences or total gibberish. On late stages subjects sometime express the feelings of inner power, and, cite, 'the ability to control the forces of cosmos themselves!' A gulp of strong, manly spirits usually reverts them to normal, humanlike, condition."
|
||||
severity = DISEASE_SEVERITY_HARMFUL
|
||||
required_organs = list(/obj/item/bodypart/head)
|
||||
|
||||
|
||||
+21
-4
@@ -41,6 +41,7 @@
|
||||
/datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = 0)
|
||||
if(!istype(destination))
|
||||
return
|
||||
var/old_size = destination.dna.features["body_size"]
|
||||
destination.dna.unique_enzymes = unique_enzymes
|
||||
destination.dna.uni_identity = uni_identity
|
||||
destination.dna.blood_type = blood_type
|
||||
@@ -56,6 +57,8 @@
|
||||
if(transfer_SE)
|
||||
destination.dna.mutation_index = mutation_index
|
||||
|
||||
destination.dna.update_body_size(old_size)
|
||||
|
||||
SEND_SIGNAL(destination, COMSIG_CARBON_IDENTITY_TRANSFERRED_TO, src, transfer_SE)
|
||||
|
||||
/datum/dna/proc/copy_dna(datum/dna/new_dna)
|
||||
@@ -368,7 +371,9 @@
|
||||
/mob/living/carbon/human/proc/hardset_dna(ui, list/mutation_index, newreal_name, newblood_type, datum/species/mrace, newfeatures)
|
||||
|
||||
if(newfeatures)
|
||||
var/old_size = dna.features["body_size"]
|
||||
dna.features = newfeatures
|
||||
dna.update_body_size(old_size)
|
||||
|
||||
if(mrace)
|
||||
var/datum/species/newrace = new mrace.type
|
||||
@@ -412,13 +417,13 @@
|
||||
|
||||
switch(deconstruct_block(getblock(dna.uni_identity, DNA_GENDER_BLOCK), 4))
|
||||
if(G_MALE)
|
||||
set_gender(MALE, TRUE)
|
||||
set_gender(MALE, TRUE, forced = TRUE)
|
||||
if(G_FEMALE)
|
||||
set_gender(FEMALE, TRUE)
|
||||
set_gender(FEMALE, TRUE, forced = TRUE)
|
||||
if(G_PLURAL)
|
||||
set_gender(PLURAL, TRUE)
|
||||
set_gender(PLURAL, TRUE, forced = TRUE)
|
||||
else
|
||||
set_gender(NEUTER, TRUE)
|
||||
set_gender(NEUTER, TRUE, forced = TRUE)
|
||||
|
||||
/mob/living/carbon/human/updateappearance(icon_update=1, mutcolor_update=0, mutations_overlay_update=0)
|
||||
..()
|
||||
@@ -644,3 +649,15 @@
|
||||
gib()
|
||||
else
|
||||
set_species(/datum/species/dullahan)
|
||||
|
||||
/datum/dna/proc/update_body_size(old_size)
|
||||
if(!holder || features["body_size"] == old_size)
|
||||
return
|
||||
holder.resize = features["body_size"] / old_size
|
||||
holder.update_transform()
|
||||
var/danger = CONFIG_GET(number/threshold_body_size_slowdown)
|
||||
if(features["body_size"] < danger)
|
||||
var/slowdown = 1 + round(danger/features["body_size"], 0.1) * CONFIG_GET(number/body_size_slowdown_multiplier)
|
||||
holder.add_movespeed_modifier(MOVESPEED_ID_SMALL_STRIDE, TRUE, 100, NONE, TRUE, slowdown, ALL, FLOATING|CRAWLING)
|
||||
else if(old_size < danger)
|
||||
holder.remove_movespeed_modifier(MOVESPEED_ID_SMALL_STRIDE)
|
||||
|
||||
@@ -72,7 +72,7 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
var/atom/target = locate(href_list["show_flavor"])
|
||||
var/text = texts_by_atom[target]
|
||||
if(text)
|
||||
usr << browse("<HTML><HEAD><TITLE>[target.name]</TITLE></HEAD><BODY><TT>[replacetext(texts_by_atom[target], "\n", "<BR>")]</TT></BODY></HTML>", "window=[target.name];size=500x200")
|
||||
usr << browse("<HTML><HEAD><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><TITLE>[target.name]</TITLE></HEAD><BODY><TT>[replacetext(texts_by_atom[target], "\n", "<BR>")]</TT></BODY></HTML>", "window=[target.name];size=500x200")
|
||||
onclose(usr, "[target.name]")
|
||||
return TRUE
|
||||
|
||||
@@ -114,6 +114,9 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
|
||||
//subtypes with additional hooks for DNA and preferences.
|
||||
/datum/element/flavor_text/carbon
|
||||
//list of antagonists etcetera that should have nothing to do with people's snowflakes.
|
||||
var/static/list/i_dont_even_know_who_you_are = typecacheof(list(/datum/antagonist/abductor, /datum/antagonist/ert,
|
||||
/datum/antagonist/nukeop, /datum/antagonist/wizard))
|
||||
|
||||
/datum/element/flavor_text/carbon/Attach(datum/target, text = "", _name = "Flavor Text", _addendum, _max_len = MAX_FLAVOR_LEN, _always_show = FALSE, _edit = TRUE)
|
||||
if(!iscarbon(target))
|
||||
@@ -122,6 +125,7 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
if(. == ELEMENT_INCOMPATIBLE)
|
||||
return
|
||||
RegisterSignal(target, COMSIG_CARBON_IDENTITY_TRANSFERRED_TO, .proc/update_dna_flavor_text)
|
||||
RegisterSignal(target, COMSIG_MOB_ANTAG_ON_GAIN, .proc/on_antag_gain)
|
||||
if(ishuman(target))
|
||||
RegisterSignal(target, COMSIG_HUMAN_PREFS_COPIED_TO, .proc/update_prefs_flavor_text)
|
||||
RegisterSignal(target, COMSIG_HUMAN_HARDSET_DNA, .proc/update_dna_flavor_text)
|
||||
@@ -129,7 +133,7 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
|
||||
/datum/element/flavor_text/carbon/Detach(mob/living/carbon/C)
|
||||
. = ..()
|
||||
UnregisterSignal(C, list(COMSIG_CARBON_IDENTITY_TRANSFERRED_TO, COMSIG_HUMAN_PREFS_COPIED_TO, COMSIG_HUMAN_HARDSET_DNA, COMSIG_HUMAN_ON_RANDOMIZE))
|
||||
UnregisterSignal(C, list(COMSIG_CARBON_IDENTITY_TRANSFERRED_TO, COMSIG_MOB_ANTAG_ON_GAIN, COMSIG_HUMAN_PREFS_COPIED_TO, COMSIG_HUMAN_HARDSET_DNA, COMSIG_HUMAN_ON_RANDOMIZE))
|
||||
|
||||
/datum/element/flavor_text/carbon/proc/update_dna_flavor_text(mob/living/carbon/C)
|
||||
texts_by_atom[C] = C.dna.features["flavor_text"]
|
||||
@@ -144,3 +148,9 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
|
||||
/datum/element/flavor_text/carbon/proc/unset_flavor(mob/living/carbon/user)
|
||||
texts_by_atom[user] = ""
|
||||
|
||||
/datum/element/flavor_text/carbon/proc/on_antag_gain(mob/living/carbon/user, datum/antagonist/antag)
|
||||
if(is_type_in_typecache(antag, i_dont_even_know_who_you_are))
|
||||
texts_by_atom[user] = ""
|
||||
if(user.dna)
|
||||
user.dna.features["flavor_text"] = ""
|
||||
@@ -1,58 +1,54 @@
|
||||
/datum/element/ghost_role_eligibility
|
||||
element_flags = ELEMENT_DETACH
|
||||
var/list/timeouts = list()
|
||||
var/list/mob/eligible_mobs = list()
|
||||
GLOBAL_LIST_EMPTY(ghost_eligible_mobs)
|
||||
|
||||
/datum/element/ghost_role_eligibility/Attach(datum/target,penalize = FALSE)
|
||||
GLOBAL_LIST_EMPTY(client_ghost_timeouts)
|
||||
|
||||
/datum/element/ghost_role_eligibility
|
||||
element_flags = ELEMENT_DETACH | ELEMENT_BESPOKE
|
||||
id_arg_index = 2
|
||||
var/penalizing = FALSE
|
||||
var/free_ghost = FALSE
|
||||
|
||||
/datum/element/ghost_role_eligibility/Attach(datum/target,free_ghosting = FALSE, penalize_on_ghost = FALSE)
|
||||
. = ..()
|
||||
if(!ismob(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
penalizing = penalize_on_ghost
|
||||
free_ghost = free_ghosting
|
||||
var/mob/M = target
|
||||
if(!(M in eligible_mobs))
|
||||
eligible_mobs += M
|
||||
if(penalize) //penalizing them from making a ghost role / midround antag comeback right away.
|
||||
var/penalty = CONFIG_GET(number/suicide_reenter_round_timer) MINUTES
|
||||
var/roundstart_quit_limit = CONFIG_GET(number/roundstart_suicide_time_limit) MINUTES
|
||||
if(world.time < roundstart_quit_limit) //add up the time difference to their antag rolling penalty if they quit before half a (ingame) hour even passed.
|
||||
penalty += roundstart_quit_limit - world.time
|
||||
if(penalty)
|
||||
penalty += world.realtime
|
||||
if(SSautotransfer.can_fire && SSautotransfer.maxvotes)
|
||||
var/maximumRoundEnd = SSautotransfer.starttime + SSautotransfer.voteinterval * SSautotransfer.maxvotes
|
||||
if(penalty - SSshuttle.realtimeofstart > maximumRoundEnd + SSshuttle.emergencyCallTime + SSshuttle.emergencyDockTime + SSshuttle.emergencyEscapeTime)
|
||||
penalty = CANT_REENTER_ROUND
|
||||
if(!(M.ckey in timeouts))
|
||||
timeouts += M.ckey
|
||||
timeouts[M.ckey] = 0
|
||||
else if(timeouts[M.ckey] == CANT_REENTER_ROUND)
|
||||
return
|
||||
timeouts[M.ckey] = max(timeouts[M.ckey],penalty)
|
||||
if(!(M in GLOB.ghost_eligible_mobs))
|
||||
GLOB.ghost_eligible_mobs += M
|
||||
RegisterSignal(M, COMSIG_MOB_GHOSTIZE, .proc/get_ghost_flags)
|
||||
|
||||
/datum/element/ghost_role_eligibility/Detach(mob/M)
|
||||
. = ..()
|
||||
if(M in eligible_mobs)
|
||||
eligible_mobs -= M
|
||||
if(M in GLOB.ghost_eligible_mobs)
|
||||
GLOB.ghost_eligible_mobs -= M
|
||||
UnregisterSignal(M, COMSIG_MOB_GHOSTIZE)
|
||||
|
||||
/datum/element/ghost_role_eligibility/proc/get_all_ghost_role_eligible(silent = FALSE)
|
||||
/proc/get_all_ghost_role_eligible(silent = FALSE)
|
||||
var/list/candidates = list()
|
||||
for(var/m in eligible_mobs)
|
||||
for(var/m in GLOB.ghost_eligible_mobs)
|
||||
var/mob/M = m
|
||||
if(M.can_reenter_round(TRUE))
|
||||
candidates += M
|
||||
return candidates
|
||||
|
||||
/mob/proc/can_reenter_round(silent = FALSE)
|
||||
var/datum/element/ghost_role_eligibility/eli = SSdcs.GetElement(list(/datum/element/ghost_role_eligibility))
|
||||
return eli.can_reenter_round(src,silent)
|
||||
|
||||
/datum/element/ghost_role_eligibility/proc/can_reenter_round(var/mob/M,silent = FALSE)
|
||||
if(!(M in eligible_mobs))
|
||||
if(!(src in GLOB.ghost_eligible_mobs))
|
||||
return FALSE
|
||||
if(!(M.ckey in timeouts))
|
||||
if(!(ckey in GLOB.client_ghost_timeouts))
|
||||
return TRUE
|
||||
var/timeout = timeouts[M.ckey]
|
||||
var/timeout = GLOB.client_ghost_timeouts[ckey]
|
||||
if(timeout != CANT_REENTER_ROUND && timeout <= world.realtime)
|
||||
return TRUE
|
||||
if(!silent && M.client)
|
||||
to_chat(M, "<span class='warning'>You are unable to reenter the round[timeout != CANT_REENTER_ROUND ? " yet. Your ghost role blacklist will expire in [DisplayTimeText(timeout - world.realtime)]" : ""].</span>")
|
||||
if(!silent && client)
|
||||
to_chat(src, "<span class='warning'>You are unable to reenter the round[timeout != CANT_REENTER_ROUND ? " yet. Your ghost role blacklist will expire in [DisplayTimeText(timeout - world.realtime)]" : ""].</span>")
|
||||
return FALSE
|
||||
|
||||
/datum/element/ghost_role_eligibility/proc/get_ghost_flags()
|
||||
. = 0
|
||||
if(!penalizing)
|
||||
. |= COMPONENT_DO_NOT_PENALIZE_GHOSTING
|
||||
if(free_ghost)
|
||||
. |= COMPONENT_FREE_GHOSTING
|
||||
return .
|
||||
|
||||
@@ -71,11 +71,12 @@
|
||||
name = "bugged mob"
|
||||
desc = "Yell at coderbrush."
|
||||
icon = null
|
||||
alternate_worn_icon = 'icons/mob/animals_held.dmi'
|
||||
mob_overlay_icon = 'icons/mob/animals_held.dmi'
|
||||
righthand_file = 'icons/mob/animals_held_rh.dmi'
|
||||
lefthand_file = 'icons/mob/animals_held_lh.dmi'
|
||||
icon_state = ""
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
dynamic_hair_suffix = ""
|
||||
var/mob/living/held_mob
|
||||
|
||||
/obj/item/clothing/head/mob_holder/Initialize(mapload, mob/living/target, worn_state, alt_worn, right_hand, left_hand, slots = NONE)
|
||||
@@ -85,7 +86,7 @@
|
||||
assimilate(target)
|
||||
|
||||
if(alt_worn)
|
||||
alternate_worn_icon = alt_worn
|
||||
mob_overlay_icon = alt_worn
|
||||
if(worn_state)
|
||||
item_state = worn_state
|
||||
icon_state = worn_state
|
||||
@@ -162,6 +163,11 @@
|
||||
L.visible_message("<span class='warning'>[held_mob] escapes from [L]!</span>", "<span class='warning'>[held_mob] escapes your grip!</span>")
|
||||
release()
|
||||
|
||||
/obj/item/clothing/head/mob_holder/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
|
||||
if(!ishuman(M)) //monkeys holding monkeys holding monkeys...
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/head/mob_holder/assume_air(datum/gas_mixture/env)
|
||||
var/atom/location = loc
|
||||
if(!loc)
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
#define POLYCHROMIC_ALTCLICK (1<<0)
|
||||
#define POLYCHROMIC_ACTION (1<<1)
|
||||
#define POLYCHROMIC_NO_HELD (1<<2)
|
||||
#define POLYCHROMIC_NO_WORN (1<<3)
|
||||
|
||||
/datum/element/polychromic
|
||||
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
|
||||
id_arg_index = 3
|
||||
var/overlays_states //A list or a number of states. In the latter case, the atom icon_state/item_state will be used followed by a number.
|
||||
var/list/colors_by_atom = list() //list of color strings or mutable appearances, depending on the above variable.
|
||||
var/icon_file
|
||||
var/worn_file //used in place of items' held or mob overlay icons if present.
|
||||
var/list/overlays_names //wrap numbers into text strings please.
|
||||
var/list/actions_by_atom = list()
|
||||
var/poly_flags
|
||||
var/static/list/suits_with_helmet_typecache = typecacheof(list(/obj/item/clothing/suit/hooded, /obj/item/clothing/suit/space/hardsuit))
|
||||
var/list/helmet_by_suit = list() //because poly winter coats exist.
|
||||
var/list/suit_by_helmet = list() //Idem.
|
||||
|
||||
/datum/element/polychromic/Attach(datum/target, list/colors, states, _flags = POLYCHROMIC_ACTION|POLYCHROMIC_NO_HELD, _icon, _worn, list/names = list("Primary", "Secondary", "Tertiary", "Quaternary", "Quinary", "Senary"))
|
||||
. = ..()
|
||||
var/make_appearances = islist(states)
|
||||
var/states_len = make_appearances ? length(states) : states
|
||||
var/names_len = length(names)
|
||||
if(!states_len || !names_len || colors_by_atom[target] || !isatom(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
var/atom/A = target
|
||||
|
||||
overlays_states = states
|
||||
icon_file = _icon
|
||||
worn_file = _worn
|
||||
poly_flags = _flags
|
||||
|
||||
var/mut_icon = icon_file || A.icon
|
||||
var/list/L = list()
|
||||
for(var/I in 1 to states_len)
|
||||
var/col = LAZYACCESS(colors, I) || "#FFFFFF"
|
||||
L += make_appearances ? mutable_appearance(mut_icon, overlays_states[I], color = col) : col
|
||||
colors_by_atom[A] = L
|
||||
|
||||
RegisterSignal(A, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlays)
|
||||
|
||||
if(_flags & POLYCHROMIC_ALTCLICK)
|
||||
RegisterSignal(A, COMSIG_PARENT_EXAMINE, .proc/on_examine)
|
||||
RegisterSignal(A, COMSIG_CLICK_ALT, .proc/set_color)
|
||||
|
||||
if(!overlays_names && names) //generate
|
||||
overlays_names = names
|
||||
var/diff = states_len - names_len
|
||||
if(diff > 0)
|
||||
for(var/i in 1 to diff)
|
||||
overlays_names += "[names_len + i]°"
|
||||
else if(diff < 0)
|
||||
overlays_names.len += diff
|
||||
|
||||
if(isitem(A))
|
||||
if(_flags & POLYCHROMIC_ACTION)
|
||||
RegisterSignal(A, COMSIG_ITEM_EQUIPPED, .proc/grant_user_action)
|
||||
RegisterSignal(A, COMSIG_ITEM_DROPPED, .proc/remove_user_action)
|
||||
if(!(_flags & POLYCHROMIC_NO_WORN) || !(_flags & POLYCHROMIC_NO_HELD))
|
||||
A.AddElement(/datum/element/update_icon_updates_onmob)
|
||||
RegisterSignal(A, COMSIG_ITEM_WORN_OVERLAYS, .proc/apply_worn_overlays)
|
||||
if(suits_with_helmet_typecache[A.type])
|
||||
RegisterSignal(A, COMSIG_SUIT_MADE_HELMET, .proc/register_helmet)
|
||||
else if(_flags & POLYCHROMIC_ACTION && ismob(A)) //in the event mob update icon procs are ever standarized.
|
||||
var/datum/action/polychromic/P = new(A)
|
||||
RegisterSignal(P, COMSIG_ACTION_TRIGGER, .proc/activate_action)
|
||||
actions_by_atom[A] = P
|
||||
P.Grant(A)
|
||||
|
||||
A.update_icon() //apply the overlays.
|
||||
|
||||
/datum/element/polychromic/Detach(atom/A)
|
||||
. = ..()
|
||||
colors_by_atom -= A
|
||||
var/datum/action/polychromic/P = actions_by_atom[A]
|
||||
if(P)
|
||||
actions_by_atom -= A
|
||||
qdel(P)
|
||||
UnregisterSignal(A, list(COMSIG_PARENT_EXAMINE, COMSIG_CLICK_ALT, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_ITEM_WORN_OVERLAYS, COMSIG_SUIT_MADE_HELMET))
|
||||
if(isitem(A))
|
||||
var/obj/item/clothing/head/H = helmet_by_suit[A]
|
||||
if(H)
|
||||
UnregisterSignal(H, list(COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ITEM_WORN_OVERLAYS, COMSIG_PARENT_QDELETING))
|
||||
helmet_by_suit -= A
|
||||
suit_by_helmet -= H
|
||||
colors_by_atom -= H
|
||||
if(!QDELETED(H))
|
||||
H.update_icon() //removing the overlays
|
||||
if(!(poly_flags & POLYCHROMIC_NO_WORN) || !(poly_flags & POLYCHROMIC_NO_HELD))
|
||||
A.RemoveElement(/datum/element/update_icon_updates_onmob)
|
||||
if(!QDELETED(A) && ismob(A.loc))
|
||||
var/mob/M = A.loc
|
||||
if(!(poly_flags & POLYCHROMIC_NO_HELD) && M.is_holding(A))
|
||||
M.update_inv_hands()
|
||||
else if(!(poly_flags & POLYCHROMIC_NO_WORN))
|
||||
M.regenerate_icons()
|
||||
if(!QDELETED(A))
|
||||
A.update_icon() //removing the overlays
|
||||
|
||||
/datum/element/polychromic/proc/apply_overlays(atom/source, list/overlays)
|
||||
var/list/L = colors_by_atom[source]
|
||||
var/f_icon = icon_file || source.icon
|
||||
if(isnum(overlays_states))
|
||||
for(var/i in 1 to overlays_states)
|
||||
overlays += mutable_appearance(f_icon, "[source.icon_state]-[i]", color = L[i])
|
||||
else
|
||||
overlays += colors_by_atom[source]
|
||||
|
||||
/datum/element/polychromic/proc/apply_worn_overlays(obj/item/source, isinhands, icon, used_state, style_flags, list/overlays)
|
||||
if(poly_flags & (isinhands ? POLYCHROMIC_NO_HELD : POLYCHROMIC_NO_WORN))
|
||||
return
|
||||
var/f_icon = worn_file || icon
|
||||
var/list/L = colors_by_atom[source]
|
||||
|
||||
if(isnum(overlays_states))
|
||||
for(var/i in 1 to overlays_states)
|
||||
overlays += mutable_appearance(f_icon, "[used_state]-[i]", color = L[i])
|
||||
else
|
||||
for(var/i in 1 to length(overlays_states))
|
||||
var/mutable_appearance/M = L[i]
|
||||
overlays += mutable_appearance(f_icon, overlays_states[i], color = M.color)
|
||||
|
||||
/datum/element/polychromic/proc/set_color(atom/source, mob/user)
|
||||
var/choice = input(user,"Polychromic options", "Recolor [source]") as null|anything in overlays_names
|
||||
if(!choice || QDELETED(source) || !user.canUseTopic(source, BE_CLOSE, NO_DEXTERY))
|
||||
return
|
||||
var/index = overlays_names.Find(choice)
|
||||
var/list/L = colors_by_atom[source]
|
||||
if(!L) // Ummmmmh.
|
||||
return
|
||||
var/mutable_appearance/M = L[index]
|
||||
var/old_color = istype(M) ? M.color : M
|
||||
var/ncolor = input(user, "Polychromic options", "Choose [choice] Color", old_color) as color|null
|
||||
if(!ncolor || QDELETED(source) || !colors_by_atom[source] || !user.canUseTopic(source, BE_CLOSE, NO_DEXTERY))
|
||||
return
|
||||
ncolor = sanitize_hexcolor(ncolor, 6, TRUE, old_color)
|
||||
if(istype(M))
|
||||
M.color = ncolor
|
||||
else
|
||||
L[index] = ncolor
|
||||
|
||||
source.update_icon()
|
||||
return TRUE
|
||||
|
||||
/datum/element/polychromic/proc/grant_user_action(atom/source, mob/user, slot)
|
||||
if(slot == SLOT_IN_BACKPACK || slot == SLOT_LEGCUFFED || slot == SLOT_HANDCUFFED || slot == SLOT_GENERC_DEXTROUS_STORAGE)
|
||||
return
|
||||
var/datum/action/polychromic/P = actions_by_atom[source]
|
||||
if(!P)
|
||||
P = new (source)
|
||||
P.name = "Modify [source]'\s Colors"
|
||||
actions_by_atom[source] = P
|
||||
P.check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
|
||||
RegisterSignal(P, COMSIG_ACTION_TRIGGER, .proc/activate_action)
|
||||
P.Grant(user)
|
||||
|
||||
/datum/element/polychromic/proc/remove_user_action(atom/source, mob/user)
|
||||
var/datum/action/polychromic/P = actions_by_atom[source]
|
||||
P?.Remove(user)
|
||||
|
||||
/datum/element/polychromic/proc/activate_action(datum/action/source, atom/target)
|
||||
set_color(target, source.owner)
|
||||
|
||||
/datum/element/polychromic/proc/on_examine(atom/source, mob/user, list/examine_list)
|
||||
examine_list += "<span class='notice'>Alt-click to recolor it.</span>"
|
||||
|
||||
/datum/element/polychromic/proc/register_helmet(atom/source, obj/item/clothing/head/H)
|
||||
suit_by_helmet[H] = source
|
||||
helmet_by_suit[source] = H
|
||||
colors_by_atom[H] = colors_by_atom[source]
|
||||
RegisterSignal(H, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlays)
|
||||
RegisterSignal(H, COMSIG_ITEM_WORN_OVERLAYS, .proc/apply_worn_overlays)
|
||||
RegisterSignal(H, COMSIG_PARENT_QDELETING, .proc/unregister_helmet)
|
||||
|
||||
/datum/element/polychromic/proc/unregister_helmet(atom/source)
|
||||
var/obj/item/clothing/suit/S = suit_by_helmet[source]
|
||||
suit_by_helmet -= source
|
||||
helmet_by_suit -= S
|
||||
colors_by_atom -= source
|
||||
|
||||
/datum/action/polychromic
|
||||
name = "Modify Polychromic Colors"
|
||||
background_icon_state = "bg_polychromic"
|
||||
use_target_appearance = TRUE
|
||||
button_icon_state = null
|
||||
target_appearance_matrix = list(0.8,0,0,0,0.8,0)
|
||||
@@ -0,0 +1,54 @@
|
||||
/datum/element/spellcasting //allows to cast certain spells or skip requirements.
|
||||
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
|
||||
id_arg_index = 2
|
||||
var/cast_flags
|
||||
var/cast_slots
|
||||
var/list/users_by_item = list()
|
||||
var/list/stacked_spellcasting_by_user = list()
|
||||
|
||||
/datum/element/spellcasting/Attach(datum/target, _flags, _slots)
|
||||
. = ..()
|
||||
if(isitem(target))
|
||||
RegisterSignal(target, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
|
||||
RegisterSignal(target, COMSIG_ITEM_DROPPED, .proc/on_drop)
|
||||
else if(ismob(target))
|
||||
RegisterSignal(target, COMSIG_MOB_SPELL_CAN_CAST, .proc/on_cast)
|
||||
stacked_spellcasting_by_user[target]++
|
||||
else
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
cast_flags = _flags
|
||||
cast_slots = _slots
|
||||
|
||||
/datum/element/spellcasting/Detach(datum/target)
|
||||
. = ..()
|
||||
UnregisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_MOB_SPELL_CAN_CAST))
|
||||
if(users_by_item[target])
|
||||
var/mob/user = users_by_item[target]
|
||||
stacked_spellcasting_by_user[user]--
|
||||
if(!stacked_spellcasting_by_user[user])
|
||||
stacked_spellcasting_by_user -= user
|
||||
UnregisterSignal(user, COMSIG_MOB_SPELL_CAN_CAST)
|
||||
else if(ismob(target))
|
||||
stacked_spellcasting_by_user[target]--
|
||||
if(!stacked_spellcasting_by_user[target])
|
||||
stacked_spellcasting_by_user -= target
|
||||
|
||||
/datum/element/spellcasting/proc/on_equip(datum/source, mob/equipper, slot)
|
||||
if(!(cast_slots & slotdefine2slotbit(slot)))
|
||||
return
|
||||
users_by_item[source] = equipper
|
||||
if(!stacked_spellcasting_by_user[equipper])
|
||||
RegisterSignal(equipper, COMSIG_MOB_SPELL_CAN_CAST, .proc/on_cast)
|
||||
stacked_spellcasting_by_user[equipper]++
|
||||
|
||||
/datum/element/spellcasting/proc/on_drop(datum/source, mob/user)
|
||||
if(!users_by_item[source])
|
||||
return
|
||||
users_by_item -= source
|
||||
stacked_spellcasting_by_user[user]--
|
||||
if(!stacked_spellcasting_by_user[user])
|
||||
stacked_spellcasting_by_user -= user
|
||||
UnregisterSignal(user, COMSIG_MOB_SPELL_CAN_CAST)
|
||||
|
||||
/datum/element/spellcasting/proc/on_cast(mob/caster, obj/effect/proc_holder/spell)
|
||||
return cast_flags
|
||||
@@ -15,4 +15,4 @@
|
||||
|
||||
/datum/element/sword_point/proc/point(datum/source, atom/target, mob/user, proximity_flag, params)
|
||||
if(!proximity_flag && ismob(target))
|
||||
user.visible_message("<span class='notice'>[user] points the tip of [source] at [target].</span>", "<span class='notice'>You point the tip of [src] at [target].</span>")
|
||||
user.visible_message("<span class='notice'>[user] points the tip of [source] at [target].</span>", "<span class='notice'>You point the tip of [source] at [target].</span>")
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
. = ..()
|
||||
if(!istype(target, /obj/item))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
RegisterSignal(target, COMSIG_ATOM_UPDATED_ICON, .proc/update_onmob)
|
||||
RegisterSignal(target, COMSIG_ATOM_UPDATED_ICON, .proc/update_onmob, override = TRUE)
|
||||
|
||||
/datum/element/update_icon_updates_onmob/proc/update_onmob(obj/item/target)
|
||||
if(ismob(target.loc))
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
// Can most things breathe?
|
||||
if(trace_gases)
|
||||
continue
|
||||
if(A_gases[/datum/gas/oxygen] >= 16)
|
||||
if(A_gases[/datum/gas/oxygen] <= 16)
|
||||
continue
|
||||
if(A_gases[/datum/gas/plasma])
|
||||
continue
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
var/list/atoms_cache = output_atoms
|
||||
var/sound/S = sound(soundfile)
|
||||
if(direct)
|
||||
S.channel = open_sound_channel()
|
||||
S.channel = SSsounds.random_available_channel()
|
||||
S.volume = volume
|
||||
for(var/i in 1 to atoms_cache.len)
|
||||
var/atom/thing = atoms_cache[i]
|
||||
|
||||
@@ -35,6 +35,17 @@
|
||||
current_target = new_target
|
||||
streak = ""
|
||||
|
||||
/datum/martial_art/proc/damage_roll(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
//Here we roll for our damage to be added into the damage var in the various attack procs. This is changed depending on whether we are in combat mode, lying down, or if our target is in combat mode.
|
||||
var/damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh)
|
||||
if(!(D.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
|
||||
damage *= 1.5
|
||||
if(!CHECK_MOBILITY(A, MOBILITY_STAND))
|
||||
damage *= 0.5
|
||||
if(!(A.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE))
|
||||
damage *= 0.25
|
||||
return damage
|
||||
|
||||
/datum/martial_art/proc/teach(mob/living/carbon/human/H, make_temporary = FALSE)
|
||||
if(!istype(H) || !H.mind)
|
||||
return FALSE
|
||||
@@ -50,6 +61,7 @@
|
||||
if(help_verb)
|
||||
H.verbs += help_verb
|
||||
H.mind.martial_art = src
|
||||
ADD_TRAIT(H, TRAIT_PUGILIST, MARTIAL_ARTIST_TRAIT)
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/proc/store(datum/martial_art/M,mob/living/carbon/human/H)
|
||||
@@ -68,7 +80,8 @@
|
||||
else
|
||||
var/datum/martial_art/X = H.mind.default_martial_art
|
||||
X.teach(H)
|
||||
|
||||
REMOVE_TRAIT(H, TRAIT_PUGILIST, MARTIAL_ARTIST_TRAIT)
|
||||
|
||||
/datum/martial_art/proc/on_remove(mob/living/carbon/human/H)
|
||||
if(help_verb)
|
||||
H.verbs -= help_verb
|
||||
|
||||
@@ -16,16 +16,13 @@
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
|
||||
var/atk_verb = pick("left hook","right hook","straight punch")
|
||||
|
||||
var/damage = rand(10, 13)
|
||||
var/extra_damage = rand(A.dna.species.punchdamagelow, A.dna.species.punchdamagehigh)
|
||||
var/extra_damage = damage_roll(A,D)
|
||||
if(extra_damage == A.dna.species.punchdamagelow)
|
||||
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)
|
||||
log_combat(A, D, "attempted to hit", atk_verb)
|
||||
return TRUE
|
||||
damage += extra_damage
|
||||
|
||||
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
|
||||
var/armor_block = D.run_armor_check(affecting, "melee")
|
||||
@@ -35,9 +32,9 @@
|
||||
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)
|
||||
D.apply_damage(rand(10,13) + extra_damage, STAMINA, affecting, armor_block)
|
||||
log_combat(A, D, "punched (boxing) ")
|
||||
if(D.getStaminaLoss() > 100)
|
||||
if(D.getStaminaLoss() > 100 && istype(D.mind?.martial_art, /datum/martial_art/boxing))
|
||||
var/knockout_prob = (D.getStaminaLoss() + rand(-15,15))*0.75
|
||||
if((D.stat != DEAD) && prob(knockout_prob))
|
||||
D.visible_message("<span class='danger'>[A] has knocked [D] out with a haymaker!</span>", \
|
||||
|
||||
+25
-17
@@ -42,11 +42,12 @@
|
||||
/datum/martial_art/cqc/proc/Slam(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!can_use(A))
|
||||
return FALSE
|
||||
var/damage = (damage_roll(A,D) + 5)
|
||||
if(CHECK_MOBILITY(D, MOBILITY_STAND))
|
||||
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.apply_damage(damage, BRUTE)
|
||||
D.DefaultCombatKnockdown(120)
|
||||
log_combat(A, D, "slammed (CQC)")
|
||||
return TRUE
|
||||
@@ -54,29 +55,33 @@
|
||||
/datum/martial_art/cqc/proc/Kick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!can_use(A))
|
||||
return FALSE
|
||||
if(CHECK_MOBILITY(D, MOBILITY_STAND))
|
||||
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)
|
||||
log_combat(A, D, "kicked (CQC)")
|
||||
var/damage = damage_roll(A,D)
|
||||
if(!CHECK_MOBILITY(D, MOBILITY_STAND) && CHECK_MOBILITY(D, MOBILITY_USE))
|
||||
log_combat(A, D, "knocked out (Head kick)(CQC)")
|
||||
D.visible_message("<span class='warning'>[A] kicks [D]'s head, knocking [D.p_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(300)
|
||||
D.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15, 150)
|
||||
D.apply_damage(damage + 5, BRUTE)
|
||||
var/atom/throw_target = get_edge_target_turf(D, A.dir)
|
||||
D.throw_at(throw_target, 1, 14, A)
|
||||
D.adjustOrganLoss(ORGAN_SLOT_BRAIN, damage + 10, 150)
|
||||
else
|
||||
D.visible_message("<span class='warning'>[A] kicks [D]!</span>", \
|
||||
"<span class='userdanger'>[A] kicks you!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
|
||||
D.Dizzy(damage)
|
||||
D.apply_damage(damage + 15, BRUTE)
|
||||
log_combat(A, D, "kicked (CQC)")
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/cqc/proc/Pressure(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!can_use(A))
|
||||
return FALSE
|
||||
var/damage = (damage_roll(A,D) + 55)
|
||||
log_combat(A, D, "pressured (CQC)")
|
||||
D.visible_message("<span class='warning'>[A] punches [D]'s neck!</span>")
|
||||
D.adjustStaminaLoss(60)
|
||||
D.apply_damage(damage, STAMINA)
|
||||
playsound(get_turf(A), 'sound/weapons/cqchit1.ogg', 50, 1, -1)
|
||||
return TRUE
|
||||
|
||||
@@ -85,11 +90,12 @@
|
||||
return
|
||||
if(!can_use(A))
|
||||
return FALSE
|
||||
var/damage = (damage_roll(A,D) + 15)
|
||||
if(!D.stat)
|
||||
log_combat(A, D, "restrained (CQC)")
|
||||
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.apply_damage(damage, STAMINA)
|
||||
D.Stun(100)
|
||||
restraining = TRUE
|
||||
addtimer(VARSET_CALLBACK(src, restraining, FALSE), 50, TIMER_UNIQUE)
|
||||
@@ -98,6 +104,7 @@
|
||||
/datum/martial_art/cqc/proc/Consecutive(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!can_use(A))
|
||||
return FALSE
|
||||
var/damage = damage_roll(A,D)
|
||||
if(!D.stat)
|
||||
log_combat(A, D, "consecutive CQC'd (CQC)")
|
||||
D.visible_message("<span class='warning'>[A] strikes [D]'s abdomen, neck and back consecutively</span>", \
|
||||
@@ -106,8 +113,8 @@
|
||||
var/obj/item/I = D.get_active_held_item()
|
||||
if(I && D.temporarilyRemoveItemFromInventory(I))
|
||||
A.put_in_hands(I)
|
||||
D.adjustStaminaLoss(50)
|
||||
D.apply_damage(25, BRUTE)
|
||||
D.apply_damage(damage + 45, STAMINA)
|
||||
D.apply_damage(damage + 20, BRUTE)
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/cqc/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
@@ -135,7 +142,7 @@
|
||||
log_combat(A, D, "attacked (CQC)")
|
||||
A.do_attack_animation(D)
|
||||
var/picked_hit_type = pick("CQC'd", "Big Bossed")
|
||||
var/bonus_damage = 13
|
||||
var/bonus_damage = (damage_roll(A,D) + 7)
|
||||
if(!CHECK_MOBILITY(D, MOBILITY_STAND))
|
||||
bonus_damage += 5
|
||||
picked_hit_type = "stomps on"
|
||||
@@ -151,7 +158,7 @@
|
||||
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.apply_damage(bonus_damage, BRUTE)
|
||||
D.DefaultCombatKnockdown(60)
|
||||
log_combat(A, D, "sweeped (CQC)")
|
||||
return TRUE
|
||||
@@ -161,6 +168,7 @@
|
||||
return FALSE
|
||||
add_to_streak("D",D)
|
||||
var/obj/item/I = null
|
||||
var/damage = (damage_roll(A,D)*0.5)
|
||||
if(check_streak(A,D))
|
||||
return TRUE
|
||||
if(prob(65))
|
||||
@@ -172,7 +180,7 @@
|
||||
if(I && D.temporarilyRemoveItemFromInventory(I))
|
||||
A.put_in_hands(I)
|
||||
D.Jitter(2)
|
||||
D.apply_damage(5, BRUTE)
|
||||
D.apply_damage(damage, BRUTE)
|
||||
else
|
||||
D.visible_message("<span class='danger'>[A] attempted to disarm [D]!</span>", \
|
||||
"<span class='userdanger'>[A] attempted to disarm [D]!</span>")
|
||||
|
||||
@@ -84,64 +84,71 @@
|
||||
if("neck_chop")
|
||||
streak = ""
|
||||
neck_chop(A,D)
|
||||
return 1
|
||||
return TRUE
|
||||
if("leg_sweep")
|
||||
streak = ""
|
||||
leg_sweep(A,D)
|
||||
return 1
|
||||
return TRUE
|
||||
if("quick_choke")//is actually lung punch
|
||||
streak = ""
|
||||
quick_choke(A,D)
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/martial_art/krav_maga/proc/leg_sweep(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/obj/item/bodypart/affecting = D.get_bodypart(BODY_ZONE_CHEST)
|
||||
var/armor_block = D.run_armor_check(affecting, "melee")
|
||||
var/damage = damage_roll(A,D)
|
||||
if(!CHECK_MOBILITY(D, MOBILITY_STAND))
|
||||
return 0
|
||||
return FALSE
|
||||
D.visible_message("<span class='warning'>[A] leg sweeps [D]!</span>", \
|
||||
"<span class='userdanger'>[A] leg sweeps you!</span>")
|
||||
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, 1, -1)
|
||||
D.apply_damage(5, BRUTE)
|
||||
D.DefaultCombatKnockdown(40, override_hardstun = 0.01, override_stamdmg = 25)
|
||||
D.apply_damage(damage + 25, STAMINA, affecting, armor_block)
|
||||
D.DefaultCombatKnockdown(80, override_hardstun = 1, override_stamdmg = 0)
|
||||
log_combat(A, D, "leg sweeped")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/krav_maga/proc/quick_choke(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)//is actually lung punch
|
||||
var/damage = damage_roll(A,D)
|
||||
D.visible_message("<span class='warning'>[A] pounds [D] on the chest!</span>", \
|
||||
"<span class='userdanger'>[A] slams your chest! You can't breathe!</span>")
|
||||
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
|
||||
if(D.losebreath <= 10)
|
||||
D.losebreath = CLAMP(D.losebreath + 5, 0, 10)
|
||||
D.adjustOxyLoss(10)
|
||||
D.adjustOxyLoss(damage + 5)
|
||||
log_combat(A, D, "quickchoked")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/krav_maga/proc/neck_chop(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
|
||||
var/damage = (damage_roll(A,D)*0.5)
|
||||
D.visible_message("<span class='warning'>[A] karate chops [D]'s neck!</span>", \
|
||||
"<span class='userdanger'>[A] karate chops your neck, rendering you unable to speak!</span>")
|
||||
playsound(get_turf(A), 'sound/effects/hit_punch.ogg', 50, 1, -1)
|
||||
D.apply_damage(5, BRUTE)
|
||||
D.apply_damage(damage, BRUTE)
|
||||
if(D.silent <= 10)
|
||||
D.silent = CLAMP(D.silent + 10, 0, 10)
|
||||
log_combat(A, D, "neck chopped")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/krav_maga/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
return TRUE
|
||||
log_combat(A, D, "grabbed (Krav Maga)")
|
||||
..()
|
||||
|
||||
/datum/martial_art/krav_maga/harm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
|
||||
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
|
||||
var/armor_block = D.run_armor_check(affecting, "melee")
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
return TRUE
|
||||
log_combat(A, D, "punched")
|
||||
var/picked_hit_type = pick("punches", "kicks")
|
||||
var/bonus_damage = 10
|
||||
if(CHECK_MOBILITY(D, MOBILITY_STAND))
|
||||
bonus_damage += 5
|
||||
var/bonus_damage = damage_roll(A,D)
|
||||
if(!CHECK_MOBILITY(D, MOBILITY_STAND))
|
||||
bonus_damage += 10
|
||||
picked_hit_type = "stomps on"
|
||||
D.apply_damage(bonus_damage, BRUTE)
|
||||
D.apply_damage(bonus_damage, BRUTE, affecting, armor_block)
|
||||
if(picked_hit_type == "kicks" || picked_hit_type == "stomps on")
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
playsound(get_turf(D), 'sound/effects/hit_kick.ogg', 50, 1, -1)
|
||||
@@ -151,24 +158,34 @@
|
||||
D.visible_message("<span class='danger'>[A] [picked_hit_type] [D]!</span>", \
|
||||
"<span class='userdanger'>[A] [picked_hit_type] you!</span>")
|
||||
log_combat(A, D, "[picked_hit_type] with [name]")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/krav_maga/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
|
||||
var/obj/item/I = null
|
||||
if(prob(60))
|
||||
I = D.get_active_held_item()
|
||||
if(I)
|
||||
if(D.temporarilyRemoveItemFromInventory(I))
|
||||
A.put_in_hands(I)
|
||||
D.visible_message("<span class='danger'>[A] has disarmed [D]!</span>", \
|
||||
"<span class='userdanger'>[A] has disarmed [D]!</span>")
|
||||
playsound(D, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
/datum/martial_art/krav_maga/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(check_streak(A,D))
|
||||
return TRUE
|
||||
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
|
||||
var/armor_block = D.run_armor_check(affecting, "melee")
|
||||
var/damage = (damage_roll(A,D)*2)
|
||||
if(D.mobility_flags & MOBILITY_STAND)
|
||||
D.visible_message("<span class='danger'>[A] reprimands [D]!</span>", \
|
||||
"<span class='userdanger'>You're slapped by [A]!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, A)
|
||||
to_chat(A, "<span class='danger'>You jab [D]!</span>")
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
playsound(D, 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
|
||||
D.apply_damage(damage + 5, STAMINA, affecting, armor_block)
|
||||
log_combat(A, D, "punched nonlethally")
|
||||
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)
|
||||
log_combat(A, D, "disarmed (Krav Maga)", "[I ? " removing \the [I]" : ""]")
|
||||
return 1
|
||||
D.visible_message("<span class='danger'>[A] reprimands [D]!</span>", \
|
||||
"<span class='userdanger'>You're manhandled by [A]!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, A)
|
||||
to_chat(A, "<span class='danger'>You stomp [D]!</span>")
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
playsound(D, 'sound/effects/hit_punch.ogg', 50, TRUE, -1)
|
||||
D.apply_damage(damage + 10, STAMINA, affecting, armor_block)
|
||||
log_combat(A, D, "stomped nonlethally")
|
||||
if(prob(D.getStaminaLoss()))
|
||||
D.visible_message("<span class='warning'>[D] sputters and recoils in pain!</span>", "<span class='userdanger'>You recoil in pain as you are jabbed in a nerve!</span>")
|
||||
D.drop_all_held_items()
|
||||
return TRUE
|
||||
|
||||
//Krav Maga Gloves
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
/datum/martial_art/mushpunch/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/atk_verb
|
||||
var/damage = (damage_roll(A,D)*3)
|
||||
to_chat(A, "<span class='spider'>You begin to wind up an attack...</span>")
|
||||
if(!do_after(A, 25, target = D))
|
||||
to_chat(A, "<span class='spider'><b>Your attack was interrupted!</b></span>")
|
||||
@@ -12,7 +13,7 @@
|
||||
atk_verb = pick("punches", "smashes", "ruptures", "cracks")
|
||||
D.visible_message("<span class='danger'>[A] [atk_verb] [D] with inhuman strength, sending [D.p_them()] flying backwards!</span>", \
|
||||
"<span class='userdanger'>[A] [atk_verb] you with inhuman strength, sending you flying backwards!</span>")
|
||||
D.apply_damage(rand(15,30), BRUTE)
|
||||
D.apply_damage(damage, BRUTE) //KAPOW
|
||||
playsound(D, 'sound/effects/meteorimpact.ogg', 25, 1, -1)
|
||||
var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
|
||||
D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time.
|
||||
|
||||
@@ -44,11 +44,13 @@
|
||||
return
|
||||
|
||||
/datum/martial_art/plasma_fist/proc/Throwback(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/damage = (damage_roll(A,D)*3)
|
||||
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)
|
||||
D.apply_damage(damage, BRUTE)
|
||||
A.say("HYAH!", forced="plasma fist")
|
||||
log_combat(A, D, "threw back (Plasma Fist)")
|
||||
return
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
/datum/martial_art/psychotic_brawling/proc/psycho_attack(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/atk_verb
|
||||
var/damage = damage_roll(A,D)
|
||||
switch(rand(1,8))
|
||||
if(1)
|
||||
D.help_shake_act(A)
|
||||
@@ -44,10 +45,10 @@
|
||||
D.visible_message("<span class='danger'>[A] [atk_verb] [D]!</span>", \
|
||||
"<span class='userdanger'>[A] [atk_verb] you!</span>")
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 40, 1, -1)
|
||||
D.apply_damage(rand(5,10), BRUTE, BODY_ZONE_HEAD)
|
||||
A.apply_damage(rand(5,10), BRUTE, BODY_ZONE_HEAD)
|
||||
D.apply_damage(damage*1.5, BRUTE, BODY_ZONE_HEAD)
|
||||
A.apply_damage(damage, BRUTE, BODY_ZONE_HEAD)
|
||||
if(!istype(D.head,/obj/item/clothing/head/helmet/) && !istype(D.head,/obj/item/clothing/head/hardhat))
|
||||
D.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5)
|
||||
D.adjustOrganLoss(ORGAN_SLOT_BRAIN, damage)
|
||||
A.Stun(rand(10,45))
|
||||
D.DefaultCombatKnockdown(rand(5,30))//CIT CHANGE - makes stuns from martial arts always use Knockdown instead of Stun for the sake of consistency
|
||||
if(5,6)
|
||||
@@ -55,7 +56,7 @@
|
||||
atk_verb = pick("punches", "kicks", "hits", "slams into")
|
||||
D.visible_message("<span class='danger'>[A] [atk_verb] [D] with inhuman strength, sending [D.p_them()] flying backwards!</span>", \
|
||||
"<span class='userdanger'>[A] [atk_verb] you with inhuman strength, sending you flying backwards!</span>")
|
||||
D.apply_damage(rand(15,30), BRUTE)
|
||||
D.apply_damage(damage*2, BRUTE)
|
||||
playsound(get_turf(D), 'sound/effects/meteorimpact.ogg', 25, 1, -1)
|
||||
var/throwtarget = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
|
||||
D.throw_at(throwtarget, 4, 2, A)//So stuff gets tossed around at the same time.
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/the_rising_bass/proc/sideKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/damage = (damage_roll(A,D)*0.5)
|
||||
if(CHECK_MOBILITY(D, MOBILITY_STAND))
|
||||
var/dir = A.dir & (NORTH | SOUTH) ? pick(EAST, WEST) : pick(NORTH, SOUTH)
|
||||
var/oppdir = dir == NORTH ? SOUTH : dir == SOUTH ? NORTH : dir == EAST ? WEST : EAST
|
||||
@@ -87,7 +88,7 @@
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] in the side, sliding them over!</span>", \
|
||||
"<span class='userdanger'>[A] kicks you in the side, forcing you to step away!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
D.apply_damage(5, BRUTE, BODY_ZONE_CHEST)
|
||||
D.apply_damage(damage, BRUTE, BODY_ZONE_CHEST)
|
||||
D.DefaultCombatKnockdown(60)
|
||||
var/L = !checkfordensity(H,D) ? (!checkfordensity(K,D) ? D.loc : K) : H
|
||||
D.forceMove(L)
|
||||
@@ -96,6 +97,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/martial_art/the_rising_bass/proc/shoulderFlip(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/damage = (damage_roll(A,D) + 25)
|
||||
if(CHECK_MOBILITY(D, MOBILITY_STAND))
|
||||
var/turf/H = get_step(A, get_dir(D,A))
|
||||
var/L = checkfordensity(H,D) ? H : A.loc
|
||||
@@ -104,8 +106,8 @@
|
||||
"<span class='userdanger'>[A] flips you over their shoulder, slamming you into the ground!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
D.emote("scream")
|
||||
D.apply_damage(10, BRUTE, BODY_ZONE_CHEST)
|
||||
D.apply_damage(30, BRUTE, BODY_ZONE_HEAD)
|
||||
D.apply_damage(damage, BRUTE, BODY_ZONE_CHEST)
|
||||
D.apply_damage(damage, BRUTE, BODY_ZONE_HEAD)
|
||||
D.Sleeping(60)
|
||||
D.DefaultCombatKnockdown(300)
|
||||
D.forceMove(L)
|
||||
@@ -114,6 +116,7 @@
|
||||
return FALSE
|
||||
|
||||
/datum/martial_art/the_rising_bass/proc/repulsePunch(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/damage = damage_roll(A,D)
|
||||
if(CHECK_MOBILITY(D, MOBILITY_STAND) && repulsecool < world.time)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_PUNCH)
|
||||
D.visible_message("<span class='warning'>[A] smashes [D] in the chest, throwing them away!</span>", \
|
||||
@@ -121,7 +124,7 @@
|
||||
playsound(get_turf(A), 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
var/atom/F = get_edge_target_turf(D, get_dir(A, get_step_away(D, A)))
|
||||
D.throw_at(F, 10, 1)
|
||||
D.apply_damage(10, BRUTE, BODY_ZONE_CHEST)
|
||||
D.apply_damage(damage, BRUTE, BODY_ZONE_CHEST)
|
||||
D.DefaultCombatKnockdown(90)
|
||||
log_combat(A, D, "repulse punched (Rising Bass)")
|
||||
repulsecool = world.time + 3 SECONDS
|
||||
@@ -129,12 +132,13 @@
|
||||
return FALSE
|
||||
|
||||
/datum/martial_art/the_rising_bass/proc/footSmash(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/damage = (damage_roll(A,D)*0.5)
|
||||
if(CHECK_MOBILITY(D, MOBILITY_STAND))
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
D.visible_message("<span class='warning'>[A] smashes their foot down on [D]'s foot!</span>", \
|
||||
"<span class='userdanger'>[A] smashes your foot!</span>")
|
||||
playsound(get_turf(A), 'sound/weapons/punch1.ogg', 50, 1, -1)
|
||||
D.apply_damage(5, BRUTE, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
D.apply_damage(damage, BRUTE, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
D.dropItemToGround(D.get_active_held_item())
|
||||
log_combat(A, D, "foot smashed (Rising Bass)")
|
||||
return TRUE
|
||||
@@ -181,7 +185,7 @@
|
||||
. = ..()
|
||||
if(A.incapacitated(FALSE, TRUE)) //NO STUN
|
||||
return BULLET_ACT_HIT
|
||||
if(!(A.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE
|
||||
if(!CHECK_ALL_MOBILITY(A, MOBILITY_USE|MOBILITY_STAND)) //NO UNABLE TO USE, NO DODGING ON THE FLOOR
|
||||
return BULLET_ACT_HIT
|
||||
if(A.dna && A.dna.check_mutation(HULK)) //NO HULK
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
@@ -31,45 +31,48 @@
|
||||
var/atk_verb = pick("precisely kick", "brutally chop", "cleanly hit", "viciously slam")
|
||||
///this is the critical hit damage added to the attack if it rolls, it starts at 0 because it'll be changed when rolled
|
||||
var/crit_damage = 0
|
||||
var/damage = damage_roll(A,D)
|
||||
D.visible_message("<span class='danger'>[A] [atk_verb]s [D]!</span>", \
|
||||
"<span class='userdanger'>[A] [atk_verb]s you!</span>", null, null, A)
|
||||
to_chat(A, "<span class='danger'>You [atk_verb] [D]!</span>")
|
||||
if(prob(10))
|
||||
crit_damage += 20
|
||||
crit_damage += (damage*2 + 15)
|
||||
playsound(get_turf(D), 'sound/weapons/bite.ogg', 50, TRUE, -1)
|
||||
D.visible_message("<span class='warning'>[D] sputters blood as the blow strikes them with inhuman force!</span>", "<span class='userdanger'>You are struck with incredible precision by [A]!</span>")
|
||||
D.visible_message("<span class='warning'>[D] staggers as the blow strikes them with inhuman force!</span>", "<span class='userdanger'>You are struck with incredible precision by [A]!</span>")
|
||||
log_combat(A, D, "critcal strong punched (Sleeping Carp)")//log it here because a critical can swing for 40 force and it's important for the sake of how hard they hit
|
||||
else
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 25, TRUE, -1)
|
||||
log_combat(A, D, "strong punched (Sleeping Carp)")//so as to not double up on logging
|
||||
D.apply_damage(20 + crit_damage, BRUTE, affecting)
|
||||
D.apply_damage((damage + 15) + crit_damage, BRUTE, affecting)
|
||||
return
|
||||
|
||||
///Crashing Wave Kick: Harm Disarm combo, throws people seven tiles backwards
|
||||
/datum/martial_art/the_sleeping_carp/proc/launchKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/damage = (damage_roll(A,D) + 15)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] square in the chest, sending them flying!</span>", \
|
||||
"<span class='userdanger'>You are kicked square in the chest by [A], sending you flying!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, A)
|
||||
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
var/atom/throw_target = get_edge_target_turf(D, A.dir)
|
||||
D.throw_at(throw_target, 7, 14, A)
|
||||
D.apply_damage(15, BRUTE, BODY_ZONE_CHEST)
|
||||
D.apply_damage(damage, BRUTE, BODY_ZONE_CHEST)
|
||||
log_combat(A, D, "launchkicked (Sleeping Carp)")
|
||||
return
|
||||
|
||||
///Keelhaul: Harm Grab combo, knocks people down, deals stamina damage while they're on the floor
|
||||
/datum/martial_art/the_sleeping_carp/proc/dropKick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
var/damage = damage_roll(A,D)
|
||||
A.do_attack_animation(D, ATTACK_EFFECT_KICK)
|
||||
playsound(get_turf(A), 'sound/effects/hit_kick.ogg', 50, TRUE, -1)
|
||||
if((D.mobility_flags & MOBILITY_STAND))
|
||||
D.apply_damage(10, BRUTE, BODY_ZONE_HEAD)
|
||||
D.DefaultCombatKnockdown(50)
|
||||
D.adjustStaminaLoss(40) //A cit specific change form the tg port to really punish anyone who tries to stand up
|
||||
D.apply_damage(damage, BRUTE, BODY_ZONE_HEAD)
|
||||
D.DefaultCombatKnockdown(50, override_hardstun = 0.01, override_stamdmg = 0)
|
||||
D.apply_damage(damage + 35, STAMINA, BODY_ZONE_HEAD) //A cit specific change form the tg port to really punish anyone who tries to stand up
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] in the head, sending them face first into the floor!</span>", \
|
||||
"<span class='userdanger'>You are kicked in the head by [A], sending you crashing to the floor!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, A)
|
||||
if(!(D.mobility_flags & MOBILITY_STAND))
|
||||
D.apply_damage(5, BRUTE, BODY_ZONE_HEAD)
|
||||
D.adjustStaminaLoss(40)
|
||||
else
|
||||
D.apply_damage(damage*0.5, BRUTE, BODY_ZONE_HEAD)
|
||||
D.apply_damage(damage + 35, STAMINA, BODY_ZONE_HEAD)
|
||||
D.drop_all_held_items()
|
||||
D.visible_message("<span class='warning'>[A] kicks [D] in the head!</span>", \
|
||||
"<span class='userdanger'>You are kicked in the head by [A]!</span>", "<span class='hear'>You hear a sickening sound of flesh hitting flesh!</span>", COMBAT_MESSAGE_RANGE, A)
|
||||
@@ -85,6 +88,7 @@
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
add_to_streak("H",D)
|
||||
var/damage = (damage_roll(A,D) + 5)
|
||||
if(check_streak(A,D))
|
||||
return TRUE
|
||||
var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected))
|
||||
@@ -93,7 +97,7 @@
|
||||
D.visible_message("<span class='danger'>[A] [atk_verb]s [D]!</span>", \
|
||||
"<span class='userdanger'>[A] [atk_verb]s you!</span>", null, null, A)
|
||||
to_chat(A, "<span class='danger'>You [atk_verb] [D]!</span>")
|
||||
D.apply_damage(rand(10,15), BRUTE, affecting)
|
||||
D.apply_damage(damage, BRUTE, affecting)
|
||||
playsound(get_turf(D), 'sound/weapons/punch1.ogg', 25, TRUE, -1)
|
||||
log_combat(A, D, "punched (Sleeping Carp)")
|
||||
return TRUE
|
||||
@@ -110,7 +114,7 @@
|
||||
. = ..()
|
||||
if(A.incapacitated(FALSE, TRUE)) //NO STUN
|
||||
return BULLET_ACT_HIT
|
||||
if(!(A.mobility_flags & MOBILITY_USE)) //NO UNABLE TO USE
|
||||
if(!CHECK_ALL_MOBILITY(A, MOBILITY_USE|MOBILITY_STAND)) //NO UNABLE TO USE, NO DEFLECTION ON THE FLOOR
|
||||
return BULLET_ACT_HIT
|
||||
if(A.dna && A.dna.check_mutation(HULK)) //NO HULK
|
||||
return BULLET_ACT_HIT
|
||||
@@ -121,6 +125,7 @@
|
||||
playsound(get_turf(A), pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE)
|
||||
P.firer = A
|
||||
P.setAngle(rand(0, 360))//SHING
|
||||
A.adjustStaminaLossBuffered (3) //Citadel change to stop infinite bullet sponging as you run away, but it is buffered!
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
@@ -133,7 +138,6 @@
|
||||
ADD_TRAIT(H, TRAIT_NODISMEMBER, SLEEPING_CARP_TRAIT)
|
||||
H.physiology.brute_mod *= 0.4 //brute is really not gonna cut it
|
||||
H.physiology.burn_mod *= 0.7 //burn is distinctly more useful against them than brute but they're still resistant
|
||||
H.physiology.stamina_mod *= 0.5 //stun batons prove to be one of the few ways to fight them. They have stun resistance already, so I think doubling down too hard on this resistance is a bit much.
|
||||
H.physiology.stun_mod *= 0.3 //for those rare stuns
|
||||
H.physiology.pressure_mod *= 0.3 //go hang out with carp
|
||||
H.physiology.cold_mod *= 0.3 //cold mods are different to burn mods, they do stack however
|
||||
@@ -148,7 +152,6 @@
|
||||
REMOVE_TRAIT(H, TRAIT_NODISMEMBER, SLEEPING_CARP_TRAIT)
|
||||
H.physiology.brute_mod = initial(H.physiology.brute_mod)
|
||||
H.physiology.burn_mod = initial(H.physiology.burn_mod)
|
||||
H.physiology.stamina_mod = initial(H.physiology.stamina_mod)
|
||||
H.physiology.stun_mod = initial(H.physiology.stun_mod)
|
||||
H.physiology.pressure_mod = initial(H.physiology.pressure_mod) //no more carpies
|
||||
H.physiology.cold_mod = initial(H.physiology.cold_mod)
|
||||
@@ -237,7 +240,7 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/bostaff/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
if(wielded)
|
||||
return ..()
|
||||
return FALSE
|
||||
/obj/item/twohanded/bostaff/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
if(!wielded)
|
||||
return BLOCK_NONE
|
||||
return ..()
|
||||
|
||||
@@ -18,28 +18,30 @@
|
||||
var/datum/action/drop/drop = new/datum/action/drop()
|
||||
|
||||
/datum/martial_art/wrestling/proc/check_streak(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
|
||||
if(!can_use(A, D))
|
||||
return FALSE
|
||||
switch(streak)
|
||||
if("drop")
|
||||
streak = ""
|
||||
drop(A,D)
|
||||
return 1
|
||||
return TRUE
|
||||
if("strike")
|
||||
streak = ""
|
||||
strike(A,D)
|
||||
return 1
|
||||
return TRUE
|
||||
if("kick")
|
||||
streak = ""
|
||||
kick(A,D)
|
||||
return 1
|
||||
return TRUE
|
||||
if("throw")
|
||||
streak = ""
|
||||
throw_wrassle(A,D)
|
||||
return 1
|
||||
return TRUE
|
||||
if("slam")
|
||||
streak = ""
|
||||
slam(A,D)
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/action/slam
|
||||
name = "Slam (Cinch) - Slam a grappled opponent into the floor."
|
||||
@@ -136,7 +138,7 @@
|
||||
|
||||
/datum/martial_art/wrestling/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
return TRUE
|
||||
log_combat(A, D, "punched with wrestling")
|
||||
..()
|
||||
|
||||
@@ -171,11 +173,11 @@
|
||||
|
||||
if (get_dist(A, D) > 1)
|
||||
to_chat(A, "[D] is too far away!")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if (!isturf(A.loc) || !isturf(D.loc))
|
||||
to_chat(A, "You can't throw [D] from here!")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
A.setDir(turn(A.dir, 90))
|
||||
var/turf/T = get_step(A, A.dir)
|
||||
@@ -184,7 +186,7 @@
|
||||
D.forceMove(T)
|
||||
D.setDir(get_dir(D, A))
|
||||
else
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
sleep(delay)
|
||||
|
||||
@@ -193,11 +195,11 @@
|
||||
|
||||
if (get_dist(A, D) > 1)
|
||||
to_chat(A, "[D] is too far away!")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if (!isturf(A.loc) || !isturf(D.loc))
|
||||
to_chat(A, "You can't throw [D] from here!")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
D.forceMove(A.loc) // Maybe this will help with the wallthrowing bug.
|
||||
|
||||
@@ -209,7 +211,7 @@
|
||||
D.emote("scream")
|
||||
D.throw_at(T, 10, 4, A, TRUE, TRUE, callback = CALLBACK(D, /mob/living/carbon/human.proc/DefaultCombatKnockdown, 20))
|
||||
log_combat(A, D, "has thrown with wrestling")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/datum/martial_art/wrestling/proc/FlipAnimation(mob/living/carbon/human/D)
|
||||
set waitfor = FALSE
|
||||
@@ -225,6 +227,7 @@
|
||||
if(!A.pulling || A.pulling != D)
|
||||
to_chat(A, "You need to have [D] in a cinch!")
|
||||
return
|
||||
var/damage = damage_roll(A,D)
|
||||
D.forceMove(A.loc)
|
||||
A.setDir(get_dir(A, D))
|
||||
D.setDir(get_dir(D, A))
|
||||
@@ -256,7 +259,7 @@
|
||||
A.pixel_y = 0
|
||||
D.pixel_x = 0
|
||||
D.pixel_y = 0
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if (!isturf(A.loc) || !isturf(D.loc))
|
||||
to_chat(A, "You can't slam [D] here!")
|
||||
@@ -264,7 +267,7 @@
|
||||
A.pixel_y = 0
|
||||
D.pixel_x = 0
|
||||
D.pixel_y = 0
|
||||
return 0
|
||||
return FALSE
|
||||
else
|
||||
if (A)
|
||||
A.pixel_x = 0
|
||||
@@ -272,7 +275,7 @@
|
||||
if (D)
|
||||
D.pixel_x = 0
|
||||
D.pixel_y = 0
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
sleep(1)
|
||||
|
||||
@@ -284,11 +287,11 @@
|
||||
|
||||
if (get_dist(A, D) > 1)
|
||||
to_chat(A, "[D] is too far away!")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if (!isturf(A.loc) || !isturf(D.loc))
|
||||
to_chat(A, "You can't slam [D] here!")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
D.forceMove(A.loc)
|
||||
|
||||
@@ -307,11 +310,11 @@
|
||||
|
||||
switch(rand(1,3))
|
||||
if (2)
|
||||
D.adjustBruteLoss(rand(20,30))
|
||||
D.apply_damage(damage + 25, BRUTE)
|
||||
if (3)
|
||||
D.ex_act(EXPLODE_LIGHT)
|
||||
else
|
||||
D.adjustBruteLoss(rand(10,20))
|
||||
D.apply_damage(damage + 15, BRUTE)
|
||||
else
|
||||
D.ex_act(EXPLODE_LIGHT)
|
||||
|
||||
@@ -325,7 +328,7 @@
|
||||
|
||||
|
||||
log_combat(A, D, "body-slammed")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/datum/martial_art/wrestling/proc/CheckStrikeTurf(mob/living/carbon/human/A, turf/T)
|
||||
if (A && (T && isturf(T) && get_dist(A, T) <= 1))
|
||||
@@ -335,6 +338,7 @@
|
||||
if(!D)
|
||||
return
|
||||
var/turf/T = get_turf(A)
|
||||
var/damage = damage_roll(A,D)
|
||||
if (T && isturf(T) && D && isturf(D.loc))
|
||||
for (var/i = 0, i < 4, i++)
|
||||
A.setDir(turn(A.dir, 90))
|
||||
@@ -343,7 +347,7 @@
|
||||
addtimer(CALLBACK(src, .proc/CheckStrikeTurf, A, T), 4)
|
||||
|
||||
A.visible_message("<span class = 'danger'><b>[A] headbutts [D]!</b></span>")
|
||||
D.adjustBruteLoss(rand(10,20))
|
||||
D.apply_damage(damage + 15, BRUTE)
|
||||
playsound(A.loc, "swing_hit", 50, 1)
|
||||
D.Unconscious(20)
|
||||
log_combat(A, D, "headbutted")
|
||||
@@ -351,13 +355,14 @@
|
||||
/datum/martial_art/wrestling/proc/kick(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
if(!D)
|
||||
return
|
||||
var/damage = damage_roll(A,D)
|
||||
A.emote("scream")
|
||||
A.emote("flip")
|
||||
A.setDir(turn(A.dir, 90))
|
||||
|
||||
A.visible_message("<span class = 'danger'><B>[A] roundhouse-kicks [D]!</B></span>")
|
||||
playsound(A.loc, "swing_hit", 50, 1)
|
||||
D.adjustBruteLoss(rand(10,20))
|
||||
D.apply_damage(damage + 15, STAMINA)
|
||||
|
||||
var/turf/T = get_edge_target_turf(A, get_dir(A, get_step_away(D, A)))
|
||||
if (T && isturf(T))
|
||||
@@ -371,7 +376,8 @@
|
||||
var/obj/surface = null
|
||||
var/turf/ST = null
|
||||
var/falling = 0
|
||||
|
||||
var/damage = damage_roll(A,D)
|
||||
|
||||
for (var/obj/O in oview(1, A))
|
||||
if (O.density == 1)
|
||||
if (O == A)
|
||||
@@ -399,15 +405,15 @@
|
||||
A.pixel_y = 0
|
||||
if (falling == 1)
|
||||
A.visible_message("<span class = 'danger'><B>...and dives head-first into the ground, ouch!</b></span>")
|
||||
A.adjustBruteLoss(rand(10,20))
|
||||
A.apply_damage(damage + 15, BRUTE)
|
||||
A.DefaultCombatKnockdown(60)
|
||||
to_chat(A, "[D] is too far away!")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if (!isturf(A.loc) || !isturf(D.loc))
|
||||
A.pixel_y = 0
|
||||
to_chat(A, "You can't drop onto [D] from here!")
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
if(A)
|
||||
animate(A, transform = matrix(90, MATRIX_ROTATE), time = 1, loop = 0)
|
||||
@@ -425,9 +431,9 @@
|
||||
if (prob(33) || D.stat)
|
||||
D.ex_act(EXPLODE_LIGHT)
|
||||
else
|
||||
D.adjustBruteLoss(rand(20,30))
|
||||
D.apply_damage(damage + 25, BRUTE)
|
||||
else
|
||||
D.adjustBruteLoss(rand(20,30))
|
||||
D.apply_damage(damage + 25, BRUTE)
|
||||
|
||||
D.DefaultCombatKnockdown(40)
|
||||
|
||||
@@ -440,14 +446,18 @@
|
||||
return
|
||||
|
||||
/datum/martial_art/wrestling/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
damage_roll(A,D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
return TRUE
|
||||
log_combat(A, D, "wrestling-disarmed")
|
||||
..()
|
||||
|
||||
/datum/martial_art/wrestling/grab_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
damage_roll(A,D)
|
||||
if(check_streak(A,D))
|
||||
return 1
|
||||
return TRUE
|
||||
if(!can_use(A,D))
|
||||
return ..()
|
||||
if(A.pulling == D || A == D) // don't stun grab yoursel
|
||||
return FALSE
|
||||
A.start_pulling(D)
|
||||
@@ -455,7 +465,7 @@
|
||||
"<span class='userdanger'>[A] gets [D] in a cinch!</span>")
|
||||
D.Stun(rand(60,100))
|
||||
log_combat(A, D, "cinched")
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling
|
||||
name = "Wrestling Belt"
|
||||
@@ -476,3 +486,19 @@
|
||||
if(H.get_item_by_slot(SLOT_BELT) == src)
|
||||
style.remove(H)
|
||||
return
|
||||
|
||||
//Subtype of wrestling, reserved for the wrestling belts found in the holodeck
|
||||
/datum/martial_art/wrestling/holodeck
|
||||
name = "Holodeck Wrestling"
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/holodeck
|
||||
name = "Holodeck Wrestling Belt"
|
||||
style = new /datum/martial_art/wrestling/holodeck
|
||||
|
||||
//Make sure that moves can only be used on people wearing the holodeck belt
|
||||
/datum/martial_art/wrestling/holodeck/can_use(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D)
|
||||
if(!(istype(D.mind?.martial_art, /datum/martial_art/wrestling/holodeck)))
|
||||
return FALSE
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
integrity_modifier = 0.1
|
||||
sheet_type = /obj/item/stack/sheet/glass
|
||||
value_per_unit = 0.0025
|
||||
armor_modifiers = list("melee" = 0.2, "bullet" = 0.2, "laser" = 0, "energy" = 1, "bomb" = 0, "bio" = 0.2, "rad" = 0.2, "fire" = 1, "acid" = 0.2) // yeah ok retard
|
||||
armor_modifiers = list("melee" = 0.2, "bullet" = 0.2, "laser" = 0, "energy" = 1, "bomb" = 0, "bio" = 0.2, "rad" = 0.2, "fire" = 1, "acid" = 0.2) // yeah ok
|
||||
|
||||
/*
|
||||
Color matrices are like regular colors but unlike with normal colors, you can go over 255 on a channel.
|
||||
|
||||
@@ -470,7 +470,6 @@
|
||||
/datum/objective/steal,
|
||||
/datum/objective/download,
|
||||
/datum/objective/nuclear,
|
||||
/datum/objective/capture,
|
||||
/datum/objective/absorb,
|
||||
/datum/objective/custom
|
||||
)
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
//MUT_EXTRA - A mutation that is in the mutations tab, and can be given and taken away through though the DNA console. Has a 0 before it's name in the mutation section of the dna console
|
||||
//MUT_OTHER Cannot be interacted with by players through normal means. I.E. wizards mutate
|
||||
|
||||
var/list/conflicts //any mutations that might conflict. put mutation typepath defines in here. make sure to enter it both ways (so that A conflicts with B, and B with A)
|
||||
var/can_chromosome = CHROMOSOME_NONE //can we take chromosomes? 0: CHROMOSOME_NEVER never, 1:CHROMOSOME_NONE yeah, 2: CHROMOSOME_USED no, already have one
|
||||
var/chromosome_name //purely cosmetic
|
||||
var/modified = FALSE //ugly but we really don't want chromosomes and on_acquiring to overlap and apply double the powers
|
||||
@@ -60,6 +61,14 @@
|
||||
return TRUE
|
||||
if(limb_req && !H.get_bodypart(limb_req))
|
||||
return TRUE
|
||||
for(var/M in H.dna.mutations)//check for conflicting powers
|
||||
var/datum/mutation/human/mewtayshun = M
|
||||
if(LAZYLEN(mewtayshun.conflicts))
|
||||
for(var/cons in mewtayshun.conflicts)
|
||||
var/datum/mutation/human/conflicter = cons
|
||||
if(conflicter == type)
|
||||
to_chat(H, "<span class='warning'>You feel your genes resisting something.</span>")
|
||||
return TRUE
|
||||
owner = H
|
||||
dna = H.dna
|
||||
dna.mutations += src
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
desc = "You can breathe fire at a target."
|
||||
school = "evocation"
|
||||
charge_max = 600
|
||||
clothes_req = FALSE
|
||||
clothes_req = NONE
|
||||
range = 20
|
||||
base_icon_state = "fireball"
|
||||
action_icon_state = "fireball0"
|
||||
@@ -121,7 +121,7 @@
|
||||
name = "Convoke Void" //magic the gathering joke here
|
||||
desc = "A rare genome that attracts odd forces not usually observed. May sometimes pull you in randomly."
|
||||
school = "evocation"
|
||||
clothes_req = FALSE
|
||||
clothes_req = NONE
|
||||
charge_max = 600
|
||||
invocation = "DOOOOOOOOOOOOOOOOOOOOM!!!"
|
||||
invocation_type = "shout"
|
||||
@@ -155,7 +155,7 @@
|
||||
dropmessage = "You let the electricity from your hand dissipate."
|
||||
hand_path = /obj/item/melee/touch_attack/shock
|
||||
charge_max = 400
|
||||
clothes_req = FALSE
|
||||
clothes_req = NONE
|
||||
action_icon_state = "zap"
|
||||
|
||||
/obj/item/melee/touch_attack/shock
|
||||
@@ -211,7 +211,7 @@
|
||||
name = "Remember the Scent"
|
||||
desc = "Get a scent off of the item you're currently holding to track it. With an empty hand, you'll track the scent you've remembered."
|
||||
charge_max = 100
|
||||
clothes_req = FALSE
|
||||
clothes_req = NONE
|
||||
range = -1
|
||||
include_user = TRUE
|
||||
action_icon_state = "nose"
|
||||
@@ -289,8 +289,7 @@
|
||||
/obj/effect/proc_holder/spell/self/self_amputation
|
||||
name = "Drop a limb"
|
||||
desc = "Concentrate to make a random limb pop right off your body."
|
||||
clothes_req = FALSE
|
||||
human_req = FALSE
|
||||
clothes_req = NONE
|
||||
charge_max = 100
|
||||
action_icon_state = "autotomy"
|
||||
|
||||
@@ -327,8 +326,7 @@
|
||||
/obj/effect/proc_holder/spell/self/lay_genetic_web
|
||||
name = "Lay Web"
|
||||
desc = "Drops a web. Only you will be able to traverse your web easily, making it pretty good for keeping you safe."
|
||||
clothes_req = FALSE
|
||||
human_req = FALSE
|
||||
clothes_req = NONE
|
||||
charge_max = 4 SECONDS //the same time to lay a web
|
||||
action_icon = 'icons/mob/actions/actions_genetic.dmi'
|
||||
action_icon_state = "lay_web"
|
||||
@@ -369,8 +367,7 @@
|
||||
/obj/effect/proc_holder/spell/self/tongue_spike
|
||||
name = "Launch spike"
|
||||
desc = "Shoot your tongue out in the direction you're facing, embedding it and dealing damage until they remove it."
|
||||
clothes_req = FALSE
|
||||
human_req = TRUE
|
||||
clothes_req = NONE
|
||||
charge_max = 100
|
||||
action_icon = 'icons/mob/actions/actions_genetic.dmi'
|
||||
action_icon_state = "spike"
|
||||
|
||||
@@ -75,20 +75,21 @@
|
||||
quality = POSITIVE
|
||||
difficulty = 16
|
||||
instability = 5
|
||||
conflicts = list(GIGANTISM)
|
||||
locked = TRUE // Default intert species for now, so locked from regular pool.
|
||||
|
||||
/datum/mutation/human/dwarfism/on_acquiring(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
return
|
||||
owner.transform = owner.transform.Scale(1, 0.8)
|
||||
owner.pass_flags |= PASSTABLE
|
||||
passtable_on(owner, GENETIC_MUTATION)
|
||||
owner.visible_message("<span class='danger'>[owner] suddenly shrinks!</span>", "<span class='notice'>Everything around you seems to grow..</span>")
|
||||
|
||||
/datum/mutation/human/dwarfism/on_losing(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
return
|
||||
owner.transform = owner.transform.Scale(1, 1.25)
|
||||
owner.pass_flags &= ~PASSTABLE
|
||||
passtable_off(owner, GENETIC_MUTATION)
|
||||
owner.visible_message("<span class='danger'>[owner] suddenly grows!</span>", "<span class='notice'>Everything around you seems to shrink..</span>")
|
||||
|
||||
|
||||
@@ -333,6 +334,7 @@
|
||||
desc = "The cells within the subject spread out to cover more area, making the subject appear larger."
|
||||
quality = MINOR_NEGATIVE
|
||||
difficulty = 12
|
||||
conflicts = list(DWARFISM)
|
||||
|
||||
/datum/mutation/human/gigantism/on_acquiring(mob/living/carbon/human/owner)
|
||||
if(..())
|
||||
|
||||
@@ -26,3 +26,7 @@
|
||||
/datum/generecipe/tonguechem
|
||||
required = "/datum/mutation/human/tongue_spike; /datum/mutation/human/stimmed"
|
||||
result = TONGUESPIKECHEM
|
||||
|
||||
/datum/generecipe/hulk
|
||||
required = "/datum/mutation/human/strong; /datum/mutation/human/radioactive"
|
||||
result = HULK
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
message = " [message] "
|
||||
//Time for a friendly game of SS13
|
||||
message = replacetext(message," stupid "," smart ")
|
||||
message = replacetext(message," retard "," genius ")
|
||||
message = replacetext(message," idiot "," genius ")
|
||||
message = replacetext(message," unrobust "," robust ")
|
||||
message = replacetext(message," dumb "," smart ")
|
||||
message = replacetext(message," awful "," great ")
|
||||
@@ -263,7 +263,7 @@
|
||||
message = replacetext(message," thank you "," thank you, thank you very much ")
|
||||
message = replacetext(message," what are you "," whatcha ")
|
||||
message = replacetext(message," yes ",pick(" sure", "yea "))
|
||||
message = replacetext(message," faggot "," square ")
|
||||
message = replacetext(message," dumbass "," square ")
|
||||
message = replacetext(message," muh valids "," getting my kicks ")
|
||||
speech_args[SPEECH_MESSAGE] = trim(message)
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
continue
|
||||
contam_atoms += thing
|
||||
var/did_contam = 0
|
||||
if(length(can_contam))
|
||||
if(can_contam)
|
||||
var/rad_strength = ((strength-RAD_MINIMUM_CONTAMINATION) * RAD_CONTAMINATION_STR_COEFFICIENT)/contam_atoms.len
|
||||
for(var/k in 1 to contam_atoms.len)
|
||||
var/atom/thing = contam_atoms[k]
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
name = "Asteroid 1"
|
||||
description = "I-spy with my little eye, something beginning with R."
|
||||
|
||||
|
||||
/datum/map_template/ruin/space/asteroid2
|
||||
id = "asteroid2"
|
||||
suffix = "asteroid2.dmm"
|
||||
@@ -187,6 +186,7 @@
|
||||
name = "Abandoned Teleporter"
|
||||
description = "In space construction the teleporter is often the first system brought online. \
|
||||
This lonely half built teleporter is a sign of a proposed structure that for one reason or another just never got built."
|
||||
always_place = TRUE
|
||||
|
||||
/datum/map_template/ruin/space/crashedclownship
|
||||
id = "crashedclownship"
|
||||
@@ -268,6 +268,7 @@
|
||||
suffix = "whiteshipdock.dmm"
|
||||
name = "Whiteship Dock"
|
||||
description = "An abandoned but functional vessel parked in deep space, ripe for the taking."
|
||||
always_place = TRUE
|
||||
|
||||
/datum/map_template/ruin/space/cat_experiments
|
||||
id = "meow"
|
||||
@@ -287,6 +288,7 @@
|
||||
suffix = "hilbertshoteltestingsite.dmm"
|
||||
name = "Hilbert Research Facility"
|
||||
description = "A research facility of great bluespace discoveries. Long since abandoned, willingly or not..."
|
||||
|
||||
/datum/map_template/ruin/space/augmentation
|
||||
id = "augmentationfacility"
|
||||
suffix = "augmentationfacility.dmm"
|
||||
@@ -376,13 +378,13 @@
|
||||
id = "roid8"
|
||||
suffix = "roid8.dmm"
|
||||
name = "Dead wizard Roid"
|
||||
description = "Mineral asteroid. Ft. Dead wizard and toilet paradox bag."
|
||||
description = "Mineral asteroid. Ft. Dead wizard and toilet wand."
|
||||
|
||||
/datum/map_template/ruin/spacenearstation/roid9
|
||||
id = "roid9"
|
||||
suffix = "roid9.dmm"
|
||||
name = "Monitoring Roid"
|
||||
description = "Mineral asteroid. Ft. Station monitoring, syndie toolbox and erp."
|
||||
description = "Mineral asteroid. Ft. Station monitoring, toolbox and erp."
|
||||
|
||||
/datum/map_template/ruin/spacenearstation/roid10
|
||||
id = "roid10"
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
/datum/status_effect/staggered
|
||||
id = "staggered"
|
||||
blocks_sprint = TRUE
|
||||
alert_type = null
|
||||
|
||||
/datum/status_effect/staggered/on_creation(mob/living/new_owner, set_duration)
|
||||
if(isnum(set_duration))
|
||||
@@ -112,20 +113,25 @@
|
||||
duration = set_duration
|
||||
. = ..()
|
||||
|
||||
/datum/status_effect/no_combat_mode/mesmerize
|
||||
/datum/status_effect/mesmerize
|
||||
id = "Mesmerize"
|
||||
alert_type = /obj/screen/alert/status_effect/mesmerized
|
||||
|
||||
/datum/status_effect/no_combat_mode/mesmerize/on_creation(mob/living/new_owner, set_duration)
|
||||
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
|
||||
. = ..()
|
||||
ADD_TRAIT(owner, TRAIT_MUTE, "mesmerize")
|
||||
owner.add_movespeed_modifier("[STATUS_EFFECT_MESMERIZE]_[id]", TRUE, priority = 64, override = TRUE, multiplicative_slowdown = 5, blacklisted_movetypes = FALSE? NONE : CRAWLING)
|
||||
|
||||
/datum/status_effect/no_combat_mode/mesmerize/on_remove()
|
||||
/datum/status_effect/mesmerize/on_remove()
|
||||
. = ..()
|
||||
REMOVE_TRAIT(owner, TRAIT_MUTE, "mesmerize")
|
||||
owner.remove_movespeed_modifier("[STATUS_EFFECT_MESMERIZE]_[id]")
|
||||
|
||||
/datum/status_effect/mesmerize/on_creation(mob/living/new_owner, set_duration)
|
||||
if(isnum(set_duration))
|
||||
duration = set_duration
|
||||
. = ..()
|
||||
|
||||
/obj/screen/alert/status_effect/mesmerized
|
||||
name = "Mesmerized"
|
||||
desc = "You cant tear your sight from who is in front of you... their gaze is simply too enthralling.."
|
||||
|
||||
@@ -88,14 +88,6 @@
|
||||
if(quirk_holder)
|
||||
quirk_holder.remove_client_colour(/datum/client_colour/monochrome)
|
||||
|
||||
/datum/quirk/libido
|
||||
name = "Nymphomania"
|
||||
desc = "You're always feeling a bit in heat. Also, you get aroused faster than usual."
|
||||
value = 0
|
||||
mob_trait = TRAIT_PERMABONER
|
||||
gain_text = "<span class='notice'>You are feeling extra wild.</span>"
|
||||
lose_text = "<span class='notice'>You don't feel that burning sensation anymore.</span>"
|
||||
|
||||
/datum/quirk/maso
|
||||
name = "Masochism"
|
||||
desc = "You are aroused by pain."
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
..()
|
||||
if(!istype(holder, holder_type))
|
||||
CRASH("Wire holder is not of the expected type!")
|
||||
return
|
||||
|
||||
src.holder = holder
|
||||
if(randomize)
|
||||
|
||||
Reference in New Issue
Block a user