Merge branch 'master' into spike-loot-differentces
This commit is contained in:
@@ -346,7 +346,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
//print the key
|
||||
if(islist(key))
|
||||
recursive_list_print(output, key, datum_handler, atom_handler)
|
||||
else if(is_proper_datum(key) && (datum_handler || (isatom(key) && atom_handler)))
|
||||
else if(is_object_datatype(key) && (datum_handler || (isatom(key) && atom_handler)))
|
||||
if(isatom(key) && atom_handler)
|
||||
output += atom_handler.Invoke(key)
|
||||
else
|
||||
@@ -360,7 +360,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
var/value = input[key]
|
||||
if(islist(value))
|
||||
recursive_list_print(output, value, datum_handler, atom_handler)
|
||||
else if(is_proper_datum(value) && (datum_handler || (isatom(value) && atom_handler)))
|
||||
else if(is_object_datatype(value) && (datum_handler || (isatom(value) && atom_handler)))
|
||||
if(isatom(value) && atom_handler)
|
||||
output += atom_handler.Invoke(value)
|
||||
else
|
||||
@@ -498,7 +498,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
if(length(select_text))
|
||||
var/text = islist(select_text)? select_text.Join() : select_text
|
||||
var/static/result_offset = 0
|
||||
showmob << browse(text, "window=SDQL-result-[result_offset++]")
|
||||
showmob << browse(text, "window=SDQL-result-[result_offset++];size=800x1200")
|
||||
show_next_to_key = null
|
||||
if(qdel_on_finish)
|
||||
qdel(src)
|
||||
@@ -646,7 +646,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
switch(query_tree[1])
|
||||
if("call")
|
||||
for(var/i in found)
|
||||
if(!is_proper_datum(i))
|
||||
if(!is_object_datatype(i))
|
||||
continue
|
||||
world.SDQL_var(i, query_tree["call"][1], null, i, superuser, src)
|
||||
obj_count_finished++
|
||||
@@ -664,7 +664,10 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
var/list/text_list = list()
|
||||
var/print_nulls = !(options & SDQL2_OPTION_SELECT_OUTPUT_SKIP_NULLS)
|
||||
obj_count_finished = select_refs
|
||||
var/n = 0
|
||||
for(var/i in found)
|
||||
if(++n == 20000)
|
||||
text_list += "<br><font color='red'><b>TRUNCATED - 20000 OBJECT LIMIT HIT</b></font>"
|
||||
SDQL_print(i, text_list, print_nulls)
|
||||
select_refs[REF(i)] = TRUE
|
||||
SDQL2_TICK_CHECK
|
||||
@@ -675,7 +678,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
if("set" in query_tree)
|
||||
var/list/set_list = query_tree["set"]
|
||||
for(var/d in found)
|
||||
if(!is_proper_datum(d))
|
||||
if(!is_object_datatype(d))
|
||||
continue
|
||||
SDQL_internal_vv(d, set_list)
|
||||
obj_count_finished++
|
||||
@@ -685,47 +688,72 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
obj_count_finished = length(obj_count_finished)
|
||||
state = SDQL2_STATE_SWITCHING
|
||||
|
||||
/datum/SDQL2_query/proc/SDQL_print(object, list/text_list, print_nulls = TRUE)
|
||||
if(is_proper_datum(object))
|
||||
text_list += "<A HREF='?_src_=vars;[HrefToken(TRUE)];Vars=[REF(object)]'>[REF(object)]</A> : [object]"
|
||||
if(istype(object, /atom))
|
||||
var/atom/A = object
|
||||
var/turf/T = A.loc
|
||||
var/area/a
|
||||
if(istype(T))
|
||||
text_list += " <font color='gray'>at</font> [T] [ADMIN_COORDJMP(T)]"
|
||||
a = T.loc
|
||||
else
|
||||
var/turf/final = get_turf(T) //Recursive, hopefully?
|
||||
if(istype(final))
|
||||
text_list += " <font color='gray'>at</font> [final] [ADMIN_COORDJMP(final)]"
|
||||
a = final.loc
|
||||
/**
|
||||
* Recursively prints out an object to text list for SDQL2 output to admins, with VV links and all.
|
||||
* Recursion limit: 50
|
||||
* Limit imposed by callers should be around 10000 objects
|
||||
* Seriously, if you hit those limits, you're doing something wrong.
|
||||
*/
|
||||
/datum/SDQL2_query/proc/SDQL_print(datum/object, list/text_list, print_nulls = TRUE, recursion = 1, linebreak = TRUE)
|
||||
if(recursion > 50)
|
||||
text_list += "<br><font color='red'><b>RECURSION LIMIT REACHED.</font></b><br>"
|
||||
return
|
||||
if(is_object_datatype(object))
|
||||
if(!islist(object))
|
||||
text_list += "<A HREF='?_src_=vars;[HrefToken(TRUE)];Vars=[REF(object)]'>[object.type] [REF(object)]</A>: [object]"
|
||||
if(istype(object, /atom))
|
||||
if(istype(object, /turf))
|
||||
var/turf/T = object
|
||||
text_list += " [ADMIN_COORDJMP(T)] <font color='gray'>at</font> [T.loc]"
|
||||
else
|
||||
text_list += " <font color='gray'>at</font> nonexistant location"
|
||||
if(a)
|
||||
text_list += " <font color='gray'>in</font> area [a]"
|
||||
if(T.loc != a)
|
||||
text_list += " <font color='gray'>inside</font> [T]"
|
||||
text_list += "<br>"
|
||||
else if(islist(object))
|
||||
var/list/L = object
|
||||
var/first = TRUE
|
||||
text_list += "\["
|
||||
for (var/x in L)
|
||||
if (!first)
|
||||
text_list += ", "
|
||||
first = FALSE
|
||||
SDQL_print(x, text_list)
|
||||
if (!isnull(x) && !isnum(x) && L[x] != null)
|
||||
text_list += " -> "
|
||||
SDQL_print(L[L[x]], text_list)
|
||||
text_list += "]<br>"
|
||||
var/atom/A = object
|
||||
var/atom/container = A.loc
|
||||
if(isturf(container))
|
||||
text_list += " <font color='gray'>in</font> [container] [ADMIN_COORDJMP(container)] <font color='gray'>at</font> [container.loc]"
|
||||
else if(container)
|
||||
var/turf/T = get_turf(container)
|
||||
var/cref = REF(container)
|
||||
text_list += " <font color='gray'>in</font> <A HREF='?_src_=vars;[HrefToken(TRUE)];Vars=[cref]'>[container]([cref])</A>"
|
||||
if(T)
|
||||
text_list += " <font color='gray'>on</font> [T] [ADMIN_COORDJMP(T)] <font color='gray'>at</font>[T.loc]"
|
||||
else
|
||||
text_list += " <font color='gray'>in</font> nullspace"
|
||||
else // lists are snowflake and get special treatment.
|
||||
text_list += "<A HREF='?_src_=vars;[HrefToken(TRUE)];Vars=[REF(object)]'>/list [REF(object)]</A> \[<br>"
|
||||
var/list/L = object
|
||||
if(length(L))
|
||||
for(var/key in object)
|
||||
if(islist(key))
|
||||
text_list += "<span style='margin-left: [min(10, recursion) * 2]em;'>"
|
||||
SDQL_print(key, text_list, TRUE, recursion + 1, FALSE)
|
||||
text_list += "</span>"
|
||||
else
|
||||
SDQL_print(key, text_list, TRUE, recursion, FALSE)
|
||||
if(IS_VALID_ASSOC_KEY(key) && !isnull(L[key]))
|
||||
var/value = L[key]
|
||||
text_list += " --> "
|
||||
if(islist(value))
|
||||
text_list += "<span style='margin-left: [min(10, recursion) * 2]em;'>"
|
||||
SDQL_print(value, text_list, TRUE, recursion + 1, FALSE)
|
||||
text_list += "</span>"
|
||||
else
|
||||
SDQL_print(value, text_list, TRUE, recursion, FALSE)
|
||||
text_list += "<br>"
|
||||
text_list += "\]"
|
||||
if(linebreak)
|
||||
text_list += "<br>"
|
||||
else
|
||||
if(isnull(object))
|
||||
if(print_nulls)
|
||||
text_list += "NULL<br>"
|
||||
text_list += "NULL"
|
||||
else if(istext(object))
|
||||
text_list += "\"[object]\""
|
||||
else if(isnum(object) || ispath(object))
|
||||
text_list += "[object]"
|
||||
else
|
||||
text_list += "[object]<br>"
|
||||
text_list += "UNKNOWN: [object]"
|
||||
if(linebreak)
|
||||
text_list += "<br>"
|
||||
|
||||
/datum/SDQL2_query/CanProcCall()
|
||||
if(!allow_admin_interact)
|
||||
@@ -957,7 +985,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
var/static/list/exclude = list("usr", "src", "marked", "global")
|
||||
var/long = start < expression.len
|
||||
var/datum/D
|
||||
if(is_proper_datum(object))
|
||||
if(is_object_datatype(object))
|
||||
D = object
|
||||
|
||||
if (object == world && (!long || expression[start + 1] == ".") && !(expression[start] in exclude)) //3 == length("SS") + 1
|
||||
@@ -1161,9 +1189,6 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
|
||||
query_list += word
|
||||
return query_list
|
||||
|
||||
/proc/is_proper_datum(thing)
|
||||
return istype(thing, /datum) || istype(thing, /client)
|
||||
|
||||
/obj/effect/statclick/SDQL2_delete/Click()
|
||||
var/datum/SDQL2_query/Q = target
|
||||
Q.delete_click()
|
||||
|
||||
@@ -16,11 +16,19 @@
|
||||
header = "<li>"
|
||||
|
||||
var/item
|
||||
var/name_part = VV_HTML_ENCODE(name)
|
||||
if(level > 0 || islist(D)) //handling keys in assoc lists
|
||||
if(istype(name,/datum))
|
||||
name_part = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(name)]'>[VV_HTML_ENCODE(name)] [REF(name)]</a>"
|
||||
else if(islist(name))
|
||||
var/list/L = name
|
||||
name_part = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(name)]'> /list ([length(L)]) [REF(name)]</a>"
|
||||
|
||||
if (isnull(value))
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>null</span>"
|
||||
item = "[name_part] = <span class='value'>null</span>"
|
||||
|
||||
else if (istext(value))
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>\"[VV_HTML_ENCODE(value)]\"</span>"
|
||||
item = "[name_part] = <span class='value'>\"[VV_HTML_ENCODE(value)]\"</span>"
|
||||
|
||||
else if (isicon(value))
|
||||
#ifdef VARSICON
|
||||
@@ -28,33 +36,31 @@
|
||||
var/rnd = rand(1,10000)
|
||||
var/rname = "tmp[REF(I)][rnd].png"
|
||||
usr << browse_rsc(I, rname)
|
||||
item = "[VV_HTML_ENCODE(name)] = (<span class='value'>[value]</span>) <img class=icon src=\"[rname]\">"
|
||||
item = "[name_part] = (<span class='value'>[value]</span>) <img class=icon src=\"[rname]\">"
|
||||
#else
|
||||
item = "[VV_HTML_ENCODE(name)] = /icon (<span class='value'>[value]</span>)"
|
||||
item = "[name_part] = /icon (<span class='value'>[value]</span>)"
|
||||
#endif
|
||||
|
||||
else if (isfile(value))
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>'[value]'</span>"
|
||||
item = "[name_part] = <span class='value'>'[value]'</span>"
|
||||
|
||||
else if(istype(value, /matrix)) // Needs to be before datum
|
||||
else if(istype(value,/matrix)) // Needs to be before datum
|
||||
var/matrix/M = value
|
||||
item = {"[VV_HTML_ENCODE(name)] = <span class='value'>
|
||||
<table class='matrixbrak'><tbody><tr>
|
||||
<td class='lbrak'> </td>
|
||||
<td><table class='matrix'><tbody>
|
||||
<tr><td>[M.a]</td><td>[M.d]</td><td>0</td></tr>
|
||||
<tr><td>[M.b]</td><td>[M.e]</td><td>0</td></tr>
|
||||
<tr><td>[M.c]</td><td>[M.f]</td><td>1</td></tr>
|
||||
</tbody></table></td>
|
||||
<td class='rbrak'> </td>
|
||||
</tr></tbody></table></span>"} //TODO link to modify_transform wrapper for all matrices
|
||||
|
||||
item = {"[name_part] = <span class='value'>
|
||||
<table class='matrixbrak'><tbody><tr><td class='lbrak'> </td><td>
|
||||
<table class='matrix'>
|
||||
<tbody>
|
||||
<tr><td>[M.a]</td><td>[M.d]</td><td>0</td></tr>
|
||||
<tr><td>[M.b]</td><td>[M.e]</td><td>0</td></tr>
|
||||
<tr><td>[M.c]</td><td>[M.f]</td><td>1</td></tr>
|
||||
</tbody>
|
||||
</table></td><td class='rbrak'> </td></tr></tbody></table></span>"} //TODO link to modify_transform wrapper for all matrices
|
||||
else if (istype(value, /datum))
|
||||
var/datum/DV = value
|
||||
if ("[DV]" != "[DV.type]") //if the thing as a name var, lets use it.
|
||||
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] [REF(value)]</a> = [DV] [DV.type]"
|
||||
item = "[name_part] = <a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[DV] [DV.type] [REF(value)]</a>"
|
||||
else
|
||||
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] [REF(value)]</a> = [DV.type]"
|
||||
item = "[name_part] = <a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[DV.type] [REF(value)]</a>"
|
||||
|
||||
else if (islist(value))
|
||||
var/list/L = value
|
||||
@@ -72,19 +78,19 @@
|
||||
|
||||
items += debug_variable(key, val, level + 1, sanitize = sanitize)
|
||||
|
||||
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a><ul>[items.Join()]</ul>"
|
||||
item = "[name_part] = <a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>/list ([L.len])</a><ul>[items.Join()]</ul>"
|
||||
else
|
||||
item = "<a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>[VV_HTML_ENCODE(name)] = /list ([L.len])</a>"
|
||||
item = "[name_part] = <a href='?_src_=vars;[HrefToken()];Vars=[REF(value)]'>/list ([L.len])</a>"
|
||||
|
||||
else if (name in GLOB.bitfields)
|
||||
var/list/flags = list()
|
||||
for (var/i in GLOB.bitfields[name])
|
||||
if (value & GLOB.bitfields[name][i])
|
||||
flags += i
|
||||
item = "[VV_HTML_ENCODE(name)] = [VV_HTML_ENCODE(jointext(flags, ", "))]"
|
||||
item = "[name_part] = [VV_HTML_ENCODE(jointext(flags, ", "))]"
|
||||
else
|
||||
item = "[VV_HTML_ENCODE(name)] = <span class='value'>[VV_HTML_ENCODE(value)]</span>"
|
||||
item = "[name_part] = <span class='value'>[VV_HTML_ENCODE(value)]</span>"
|
||||
|
||||
return "[header][item]</li>"
|
||||
|
||||
#undef VV_HTML_ENCODE
|
||||
#undef VV_HTML_ENCODE
|
||||
@@ -45,13 +45,15 @@
|
||||
desc = "A solid wall of slightly twitching tendrils with a reflective glow."
|
||||
damaged_desc = "A wall of twitching tendrils with a reflective glow."
|
||||
icon_state = "blob_glow"
|
||||
flags_1 = CHECK_RICOCHET_1
|
||||
point_return = 8
|
||||
max_integrity = 100
|
||||
brute_resist = 1
|
||||
explosion_block = 2
|
||||
|
||||
/obj/structure/blob/shield/reflective/handle_ricochet(obj/item/projectile/P)
|
||||
/obj/structure/blob/shield/reflective/check_projectile_ricochet(obj/item/projectile/P)
|
||||
return PROJECTILE_RICOCHET_FORCE
|
||||
|
||||
/obj/structure/blob/shield/reflective/handle_projectile_ricochet(obj/item/projectile/P)
|
||||
var/turf/p_turf = get_turf(P)
|
||||
var/face_direction = get_dir(src, p_turf)
|
||||
var/face_angle = dir2angle(face_direction)
|
||||
@@ -61,4 +63,4 @@
|
||||
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
|
||||
P.setAngle(new_angle_s)
|
||||
visible_message("<span class='warning'>[P] reflects off [src]!</span>")
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -167,4 +167,4 @@
|
||||
///obj/item/pipe = 2)
|
||||
time = 80
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
B.organ_flags |= ORGAN_VITAL
|
||||
B.decoy_override = FALSE
|
||||
remove_changeling_powers()
|
||||
owner.special_role = null
|
||||
. = ..()
|
||||
|
||||
/datum/antagonist/changeling/proc/remove_clownmut()
|
||||
|
||||
@@ -432,15 +432,18 @@
|
||||
/obj/item/shield/changeling
|
||||
name = "shield-like mass"
|
||||
desc = "A mass of tough, boney tissue. You can still see the fingers as a twisted pattern in the shield."
|
||||
item_flags = ABSTRACT | DROPDEL
|
||||
item_flags = ABSTRACT | DROPDEL | ITEM_CAN_BLOCK
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "ling_shield"
|
||||
lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
|
||||
block_chance = 50
|
||||
block_parry_data = /datum/block_parry_data/shield/changeling
|
||||
|
||||
var/remaining_uses //Set by the changeling ability.
|
||||
|
||||
/datum/block_parry_data/shield/changeling
|
||||
block_slowdown = 0
|
||||
|
||||
/obj/item/shield/changeling/Initialize(mapload)
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
|
||||
@@ -451,7 +454,7 @@
|
||||
block_return[BLOCK_RETURN_BLOCK_CAPACITY] = (block_return[BLOCK_RETURN_BLOCK_CAPACITY] || 0) + remaining_uses
|
||||
return ..()
|
||||
|
||||
/obj/item/shield/changeling/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
/obj/item/shield/changeling/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
. = ..()
|
||||
if(--remaining_uses < 1)
|
||||
if(ishuman(loc))
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
//horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
|
||||
/atom/movable/proc/power_drain(clockcult_user)
|
||||
/atom/movable/proc/power_drain(clockcult_user, drain_weapons = FALSE) //This proc as of now is only in use for void volt
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(cell)
|
||||
return cell.power_drain(clockcult_user)
|
||||
return 0
|
||||
return 0 //Returns 0 instead of FALSE to symbolise it returning the power amount in other cases, not TRUE aka 1
|
||||
|
||||
/obj/item/melee/baton/power_drain(clockcult_user) //balance memes
|
||||
return 0
|
||||
/obj/item/melee/baton/power_drain(clockcult_user, drain_weapons = FALSE) //balance memes
|
||||
if(!drain_weapons)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/power_drain(clockcult_user) //balance memes
|
||||
return 0
|
||||
/obj/item/gun/power_drain(clockcult_user, drain_weapons = FALSE) //balance memes
|
||||
if(!drain_weapons)
|
||||
return 0
|
||||
var/obj/item/stock_parts/cell/cell = get_cell()
|
||||
if(!cell)
|
||||
return 0
|
||||
if(cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4) //Done snowflakey because guns have far smaller cells than batons / other equipment
|
||||
cell.use(.)
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user)
|
||||
/obj/machinery/power/apc/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if(cell && cell.charge)
|
||||
playsound(src, "sparks", 50, 1)
|
||||
flick("apc-spark", src)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*3)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.) //Better than a power sink!
|
||||
if(!cell.charge && !shorted)
|
||||
shorted = 1
|
||||
@@ -23,9 +33,9 @@
|
||||
update()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user)
|
||||
/obj/machinery/power/smes/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*3)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*4)
|
||||
charge -= . * 50
|
||||
if(!charge && !panel_open)
|
||||
panel_open = TRUE
|
||||
@@ -34,19 +44,19 @@
|
||||
visible_message("<span class='warning'>[src]'s panel flies open with a flurry of sparks!</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user)
|
||||
/obj/item/stock_parts/cell/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if(charge)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER*3)
|
||||
charge = use(.)
|
||||
. = min(charge, MIN_CLOCKCULT_POWER * 4) //Done like this because normal cells are usually quite a bit bigger than the ones used in guns / APCs
|
||||
use(min(charge, . * 10)) //Usually cell-powered equipment that is not a gun has at least ten times the capacity of a gun / 5 times the amount of an APC. This adjusts the drain to account for that.
|
||||
update_icon()
|
||||
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user)
|
||||
/mob/living/silicon/robot/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.)
|
||||
spark_system.start()
|
||||
|
||||
/obj/mecha/power_drain(clockcult_user)
|
||||
/obj/mecha/power_drain(clockcult_user, drain_weapons = FALSE)
|
||||
if((!clockcult_user || (occupant && !is_servant_of_ratvar(occupant))) && cell && cell.charge)
|
||||
. = min(cell.charge, MIN_CLOCKCULT_POWER*4)
|
||||
cell.use(.)
|
||||
|
||||
@@ -135,6 +135,29 @@
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Volt Void scripture, fires a ray of energy at a target location
|
||||
/obj/effect/proc_holder/slab/volt
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
/obj/effect/proc_holder/slab/volt/InterceptClickOn(mob/living/caller, params, atom/target)
|
||||
if(target == slab || ..()) //we can't cancel
|
||||
return TRUE
|
||||
|
||||
var/turf/T = ranged_ability_user.loc
|
||||
if(!isturf(T))
|
||||
return TRUE
|
||||
|
||||
if(target in view(7, get_turf(ranged_ability_user)))
|
||||
successful = TRUE
|
||||
ranged_ability_user.visible_message("<span class='warning'>[ranged_ability_user] fires a ray of energy at [target]!</span>", "<span class='nzcrentr'>You fire a volt ray at [target].</span>")
|
||||
playsound(ranged_ability_user, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
T = get_turf(target)
|
||||
new/obj/effect/temp_visual/ratvar/volt_hit(T, ranged_ability_user)
|
||||
log_combat(ranged_ability_user, T, "fired a volt ray")
|
||||
remove_ranged_ability()
|
||||
|
||||
return TRUE
|
||||
|
||||
//For the Kindle scripture; stuns and mutes a target non-servant.
|
||||
/obj/effect/proc_holder/slab/kindle
|
||||
ranged_mousepointer = 'icons/effects/volt_target.dmi'
|
||||
|
||||
@@ -203,6 +203,10 @@ Applications: 8 servants, 3 caches, and 100 CV
|
||||
if(!do_after(invoker, chant_interval, target = invoker, extra_checks = CALLBACK(src, .proc/can_recite)))
|
||||
break
|
||||
clockwork_say(invoker, text2ratvar(pick(chant_invocations)), whispered)
|
||||
if(multiple_invokers_used)
|
||||
for(var/mob/living/L in range(1, get_turf(invoker)))
|
||||
if(can_recite_scripture(L) && L != invoker)
|
||||
clockwork_say(L, text2ratvar(pick(chant_invocations)), whispered)
|
||||
if(!chant_effects(i))
|
||||
break
|
||||
if(invoker && slab)
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
space_allowed = TRUE
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 5
|
||||
sort_priority = 6
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Creates a Ratvarian shield, which can absorb energy from attacks for use in powerful bashes."
|
||||
|
||||
@@ -131,7 +131,7 @@
|
||||
usage_tip = "Throwing the spear at a mob will do massive damage and knock them down, but break the spear. You will need to wait for 30 seconds before resummoning it."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 6
|
||||
sort_priority = 7
|
||||
important = TRUE
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you."
|
||||
@@ -231,7 +231,7 @@
|
||||
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 7
|
||||
sort_priority = 9
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to create a one-way Spatial Gateway to a living Servant or Clockwork Obelisk."
|
||||
|
||||
@@ -263,3 +263,227 @@
|
||||
duration = max(duration, 100)
|
||||
return slab.procure_gateway(invoker, duration, portal_uses)
|
||||
|
||||
|
||||
//Mending Mantra: Channeled for up to ten times over twenty seconds to repair structures and heal allies
|
||||
/datum/clockwork_scripture/channeled/mending_mantra
|
||||
descname = "Channeled, Area Healing and Repair"
|
||||
name = "Mending Mantra"
|
||||
desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed. Channeled every two seconds for a maximum of twenty seconds."
|
||||
chant_invocations = list("Mend our dents!", "Heal our scratches!", "Repair our gears!")
|
||||
chant_amount = 10
|
||||
chant_interval = 20
|
||||
power_cost = 400
|
||||
usage_tip = "This is a very effective way to rapidly reinforce a base after an attack."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = VANGUARD_COGWHEEL
|
||||
sort_priority = 8
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Repairs nearby structures and constructs. Servants wearing clockwork armor will also be healed.<br><b>Maximum 10 chants.</b>"
|
||||
var/heal_attempts = 4
|
||||
var/heal_amount = 2.5
|
||||
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
|
||||
var/static/list/heal_finish_messages = list("There, all mended!", "Try not to get too damaged.", "No more dents and scratches for you!", "Champions never die.", "All patched up.", \
|
||||
"Ah, child, it's okay now.", "Pain is temporary.", "What you do for the Justiciar is eternal.", "Bear this for me.", "Be strong, child.", "Please, be careful!", \
|
||||
"If you die, you will be remembered.")
|
||||
var/static/list/heal_target_typecache = typecacheof(list(
|
||||
/obj/structure/destructible/clockwork,
|
||||
/obj/machinery/door/airlock/clockwork,
|
||||
/obj/machinery/door/window/clockwork,
|
||||
/obj/structure/window/reinforced/clockwork,
|
||||
/obj/structure/table/reinforced/brass))
|
||||
var/static/list/ratvarian_armor_typecache = typecacheof(list(
|
||||
/obj/item/clothing/suit/armor/clockwork,
|
||||
/obj/item/clothing/head/helmet/clockwork,
|
||||
/obj/item/clothing/gloves/clockwork,
|
||||
/obj/item/clothing/shoes/clockwork))
|
||||
|
||||
/datum/clockwork_scripture/channeled/mending_mantra/chant_effects(chant_number)
|
||||
var/turf/T
|
||||
for(var/atom/movable/M in range(7, invoker))
|
||||
if(isliving(M))
|
||||
if(isclockmob(M) || istype(M, /mob/living/simple_animal/drone/cogscarab))
|
||||
var/mob/living/simple_animal/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD)
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(S.health < S.maxHealth)
|
||||
S.adjustHealth(-heal_amount)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_attempts && S.health >= S.maxHealth) //we finished healing on the last tick, give them the message
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(issilicon(M))
|
||||
var/mob/living/silicon/S = M
|
||||
if(S.health == S.maxHealth || S.stat == DEAD || !is_servant_of_ratvar(S))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(S.health < S.maxHealth)
|
||||
S.heal_ordered_damage(heal_amount, damage_heal_order)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_attempts && S.health >= S.maxHealth)
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(S, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.health == H.maxHealth || H.stat == DEAD || !is_servant_of_ratvar(H))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
var/heal_ticks = 0 //one heal tick for each piece of ratvarian armor worn
|
||||
var/obj/item/I = H.get_item_by_slot(SLOT_WEAR_SUIT)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_HEAD)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_GLOVES)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
I = H.get_item_by_slot(SLOT_SHOES)
|
||||
if(is_type_in_typecache(I, ratvarian_armor_typecache))
|
||||
heal_ticks++
|
||||
if(heal_ticks)
|
||||
for(var/i in 1 to heal_ticks)
|
||||
if(H.health < H.maxHealth)
|
||||
H.heal_ordered_damage(heal_amount, damage_heal_order)
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
if(i == heal_ticks && H.health >= H.maxHealth)
|
||||
to_chat(H, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else
|
||||
to_chat(H, "<span class='inathneq'>\"[text2ratvar(pick(heal_finish_messages))]\"</span>")
|
||||
break
|
||||
else if(is_type_in_typecache(M, heal_target_typecache))
|
||||
var/obj/structure/destructible/clockwork/C = M
|
||||
if(C.obj_integrity == C.max_integrity || (istype(C) && !C.can_be_repaired))
|
||||
continue
|
||||
T = get_turf(M)
|
||||
for(var/i in 1 to heal_attempts)
|
||||
if(C.obj_integrity < C.max_integrity)
|
||||
C.obj_integrity = min(C.obj_integrity + 5, C.max_integrity)
|
||||
C.update_icon()
|
||||
new /obj/effect/temp_visual/heal(T, "#1E8CE1")
|
||||
else
|
||||
break
|
||||
new /obj/effect/temp_visual/ratvar/mending_mantra(get_turf(invoker))
|
||||
return TRUE
|
||||
|
||||
//Volt Blaster: Channeled for up to five times over ten seconds to fire up to five rays of energy at target locations.
|
||||
/datum/clockwork_scripture/channeled/volt_blaster
|
||||
descname = "Channeled, Targeted Energy Blasts"
|
||||
name = "Volt Blaster"
|
||||
desc = "Allows you to fire five energy rays at target locations. Channeled every fourth of a second for a maximum of ten seconds."
|
||||
channel_time = 30
|
||||
invocations = list("Amperage...", "...grant me your power!")
|
||||
chant_invocations = list("Use charge to kill!", "Slay with power!", "Hunt with energy!")
|
||||
chant_amount = 5
|
||||
chant_interval = 4
|
||||
power_cost = 500
|
||||
usage_tip = "Though it requires you to stand still, this scripture can do massive damage."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = BELLIGERENT_EYE
|
||||
sort_priority = 5
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Allows you to fire energy rays at target locations.<br><b>Maximum 5 chants.</b>"
|
||||
var/static/list/nzcrentr_insults = list("You're not very good at aiming.", "You hunt badly.", "What a waste of energy.", "Almost funny to watch.",
|
||||
"Boss says </span><span class='heavy_brass'>\"Click something, you idiot!\"</span><span class='nzcrentr'>.", "Stop wasting power if you can't aim.")
|
||||
|
||||
/datum/clockwork_scripture/channeled/volt_blaster/chant_effects(chant_number)
|
||||
slab.busy = null
|
||||
var/datum/clockwork_scripture/ranged_ability/volt_ray/ray = new
|
||||
ray.slab = slab
|
||||
ray.invoker = invoker
|
||||
var/turf/T = get_turf(invoker)
|
||||
if(!ray.run_scripture() && slab && invoker)
|
||||
if(can_recite() && T == get_turf(invoker))
|
||||
to_chat(invoker, "<span class='nzcrentr'>\"[text2ratvar(pick(nzcrentr_insults))]\"</span>")
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/ebeam/volt_ray
|
||||
name = "volt_ray"
|
||||
layer = LYING_MOB_LAYER
|
||||
|
||||
/datum/clockwork_scripture/ranged_ability/volt_ray
|
||||
name = "Volt Ray"
|
||||
slab_overlay = "volt"
|
||||
allow_mobility = FALSE
|
||||
ranged_type = /obj/effect/proc_holder/slab/volt
|
||||
ranged_message = "<span class='nzcrentr_small'><i>You charge the clockwork slab with shocking might.</i>\n\
|
||||
<b>Left-click a target to fire, quickly!</b></span>"
|
||||
timeout_time = 20
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt
|
||||
descname = "Channeled, Power Drain"
|
||||
name = "Void Volt"
|
||||
desc = "A channeled spell that quickly drains any powercells in a radius of eight tiles, but burns the invoker. \
|
||||
Can be channeled with more cultists to increase range and split the caused damage evenly over all invokers. \
|
||||
Also charges clockwork power by a small percentage of the drained power amount, which can help offset this scriptures powercost."
|
||||
invocations = list("Channel their energy through my body... ", "... so it may fuel Engine!")
|
||||
chant_invocations = list("Make their lights fall dark!", "They shall be powerless!", "Rob them of their power!")
|
||||
chant_amount = 20
|
||||
chant_interval = 10 //100KW drain per pulse for guns / APCs / 1MW for other cells = 10 chants / 100ds / 10s to drain a charged weapon or a baton with a nonupgraded cell
|
||||
channel_time = 50
|
||||
power_cost = 300
|
||||
multiple_invokers_used = TRUE
|
||||
multiple_invokers_optional = TRUE
|
||||
usage_tip = "It may be useful to end channelling early if the burning becomes too much to handle.."
|
||||
tier = SCRIPTURE_SCRIPT
|
||||
primary_component = GEIS_CAPACITOR
|
||||
sort_priority = 10
|
||||
quickbind = TRUE
|
||||
quickbind_desc = "Quickly drains power in an area around the invoker, causing burns proportional to the amount of energy drained.<br><b>Maximum of 20 chants.</b>"
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/scripture_effects()
|
||||
invoker.visible_message("<span class='warning'>[invoker] glows in a brilliant golden light!</span>")
|
||||
invoker.add_atom_colour("#FFD700", ADMIN_COLOUR_PRIORITY)
|
||||
invoker.light_power = 2
|
||||
invoker.light_range = 4
|
||||
invoker.light_color = LIGHT_COLOR_FIRE
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/chant_effects(chant_number)
|
||||
var/power_drained = 0
|
||||
var/power_mod = 0.005 //Amount of power drained (generally) is multiplied with this, and subsequently dealt in damage to the invoker, then 15 times that is added to the clockwork cult's power reserves.
|
||||
var/drain_range = 8
|
||||
var/additional_chanters = 0
|
||||
var/list/chanters = list()
|
||||
chanters += invoker
|
||||
for(var/mob/living/L in range(1, invoker))
|
||||
if(!L.stat && is_servant_of_ratvar(L))
|
||||
additional_chanters++
|
||||
chanters += L
|
||||
drain_range = min(drain_range + 2 * additional_chanters, drain_range * 2) //s u c c
|
||||
for(var/t in spiral_range_turfs(drain_range, invoker))
|
||||
var/turf/T = t
|
||||
for(var/M in T)
|
||||
var/atom/movable/A = M
|
||||
power_drained += A.power_drain(TRUE, TRUE) //Yes, this absolutely does drain weaponry. 10 pulses to drain guns / batons, though of course they can just be recharged.
|
||||
new /obj/effect/temp_visual/ratvar/sigil/transgression(invoker.loc, 1 + (power_drained * power_mod))
|
||||
var/datum/effect_system/spark_spread/S = new
|
||||
S.set_up(round(1 + (power_drained * power_mod), 1), 0, get_turf(invoker))
|
||||
S.start()
|
||||
adjust_clockwork_power(power_drained * power_mod * 15)
|
||||
for(var/mob/living/L in chanters)
|
||||
L.adjustFireLoss(round(clamp(power_drained * power_mod / (1 + additional_chanters), 0, 20), 0.1)) //No you won't just immediately melt if you do this in a very power-rich area
|
||||
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/channeled/void_volt/chant_end_effects()
|
||||
invoker.visible_message("<span class='warning'>[invoker] stops glowing...</span>")
|
||||
invoker.remove_atom_colour(ADMIN_COLOUR_PRIORITY)
|
||||
invoker.light_power = 0
|
||||
invoker.light_range = 0
|
||||
invoker.update_light()
|
||||
return ..()
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
/obj/structure/destructible/clockwork/attacked_by(obj/item/I, mob/living/user)
|
||||
/obj/structure/destructible/clockwork/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
if(is_servant_of_ratvar(user) && immune_to_servant_attacks)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "disintegrate"
|
||||
item_state = null
|
||||
item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL | NO_ATTACK_CHAIN_SOFT_STAMCRIT
|
||||
item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL
|
||||
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
throwforce = 0
|
||||
|
||||
@@ -273,6 +273,7 @@
|
||||
knockdown = 20
|
||||
|
||||
/obj/item/restraints/legcuffs/bola/cult/pickup(mob/living/user)
|
||||
. = ..()
|
||||
if(!iscultist(user))
|
||||
to_chat(user, "<span class='warning'>The bola seems to take on a life of its own!</span>")
|
||||
ensnare(user)
|
||||
|
||||
@@ -116,24 +116,11 @@
|
||||
/mob/living/carbon/true_devil/get_ear_protection()
|
||||
return 2
|
||||
|
||||
|
||||
/mob/living/carbon/true_devil/attacked_by(obj/item/I, mob/living/user, def_zone)
|
||||
var/weakness = check_weakness(I, user)
|
||||
apply_damage(I.force * weakness, I.damtype, def_zone)
|
||||
var/message_verb = ""
|
||||
if(I.attack_verb && I.attack_verb.len)
|
||||
message_verb = "[pick(I.attack_verb)]"
|
||||
else if(I.force)
|
||||
message_verb = "attacked"
|
||||
|
||||
var/attack_message = "[src] has been [message_verb] with [I]."
|
||||
if(user)
|
||||
user.do_attack_animation(src)
|
||||
if(user in viewers(src, null))
|
||||
attack_message = "[user] has [message_verb] [src] with [I]!"
|
||||
if(message_verb)
|
||||
visible_message("<span class='danger'>[attack_message]</span>",
|
||||
"<span class='userdanger'>[attack_message]</span>", null, COMBAT_MESSAGE_RANGE)
|
||||
/mob/living/carbon/true_devil/attacked_by(obj/item/I, mob/living/user, def_zone, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
var/totitemdamage = pre_attacked_by(I, user)
|
||||
totitemdamage *= check_weakness(I, user)
|
||||
apply_damage(totitemdamage, I.damtype, def_zone)
|
||||
send_item_attack_message(I, user, null, totitemdamage)
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/true_devil/singularity_act()
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
weight = 3
|
||||
chaos = 5
|
||||
threat = 3
|
||||
min_players = 25
|
||||
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit)
|
||||
|
||||
/datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
weight = 2
|
||||
chaos = 5
|
||||
threat = 5
|
||||
min_players = 20
|
||||
uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit)
|
||||
|
||||
/datum/traitor_class/human/martyr/forge_objectives(datum/antagonist/traitor/T)
|
||||
|
||||
@@ -7,6 +7,8 @@ GLOBAL_LIST_EMPTY(traitor_classes)
|
||||
var/chaos = 0
|
||||
var/threat = 0
|
||||
var/TC = 20
|
||||
/// Minimum players for this to randomly roll via get_random_traitor_class().
|
||||
var/min_players = 0
|
||||
var/list/uplink_filters
|
||||
|
||||
/datum/traitor_class/New()
|
||||
@@ -41,4 +43,4 @@ GLOBAL_LIST_EMPTY(traitor_classes)
|
||||
|
||||
/datum/traitor_class/proc/clean_up_traitor(datum/antagonist/traitor/T)
|
||||
// Any effects that need to be cleaned up if traitor class is being swapped.
|
||||
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
for(var/C in GLOB.traitor_classes)
|
||||
if(!(C in blacklist))
|
||||
var/datum/traitor_class/class = GLOB.traitor_classes[C]
|
||||
if(class.min_players > length(GLOB.joined_player_list))
|
||||
continue
|
||||
var/weight = LOGISTIC_FUNCTION(1.5*class.weight,chaos_weight,class.chaos,0)
|
||||
weights[C] = weight * 1000
|
||||
var/choice = pickweight(weights, 0)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
/obj/item/electronics/airalarm
|
||||
name = "air alarm electronics"
|
||||
icon_state = "airalarm_electronics"
|
||||
custom_price = 50
|
||||
custom_price = PRICE_CHEAP
|
||||
|
||||
/obj/item/wallframe/airalarm
|
||||
name = "air alarm frame"
|
||||
|
||||
@@ -162,6 +162,9 @@
|
||||
to_chat(user, "<span class='danger'>Access denied.</span>")
|
||||
return UI_CLOSE
|
||||
|
||||
/obj/machinery/atmospherics/components/attack_ghost(mob/dead/observer/O)
|
||||
. = ..()
|
||||
atmosanalyzer_scan(airs, O, src, FALSE)
|
||||
|
||||
// Tool acts
|
||||
|
||||
|
||||
@@ -111,3 +111,10 @@
|
||||
pipe_color = paint_color
|
||||
update_node_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/atmospherics/pipe/attack_ghost(mob/dead/observer/O)
|
||||
. = ..()
|
||||
if(parent)
|
||||
atmosanalyzer_scan(parent.air, O, src, FALSE)
|
||||
else
|
||||
to_chat(O, "<span class='warning'>[src] doesn't have a pipenet, which is probably a bug.</span>")
|
||||
|
||||
@@ -147,10 +147,14 @@
|
||||
/obj/machinery/portable_atmospherics/analyzer_act(mob/living/user, obj/item/I)
|
||||
atmosanalyzer_scan(air_contents, user, src)
|
||||
|
||||
/obj/machinery/portable_atmospherics/attacked_by(obj/item/I, mob/user)
|
||||
/obj/machinery/portable_atmospherics/attacked_by(obj/item/I, mob/user, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
if(I.force < 10 && !(stat & BROKEN))
|
||||
take_damage(0)
|
||||
else
|
||||
investigate_log("was smacked with \a [I] by [key_name(user)].", INVESTIGATE_ATMOS)
|
||||
add_fingerprint(user)
|
||||
..()
|
||||
|
||||
/obj/machinery/portable_atmospherics/attack_ghost(mob/dead/observer/O)
|
||||
. = ..()
|
||||
atmosanalyzer_scan(air_contents, O, src, FALSE)
|
||||
|
||||
@@ -171,10 +171,10 @@
|
||||
var/worth = 10
|
||||
var/gases = C.air_contents.gases
|
||||
|
||||
worth += gases[/datum/gas/bz]*4
|
||||
worth += gases[/datum/gas/bz]*3
|
||||
worth += gases[/datum/gas/stimulum]*25
|
||||
worth += gases[/datum/gas/hypernoblium]*1000
|
||||
worth += gases[/datum/gas/miasma]*4
|
||||
worth += gases[/datum/gas/miasma]*2
|
||||
worth += gases[/datum/gas/tritium]*7
|
||||
worth += gases[/datum/gas/pluoxium]*6
|
||||
worth += gases[/datum/gas/nitryl]*30
|
||||
|
||||
@@ -71,7 +71,8 @@
|
||||
/obj/item/clothing/mask/gas/syndicate,
|
||||
/obj/item/clothing/neck/necklace/dope,
|
||||
/obj/item/vending_refill/donksoft,
|
||||
/obj/item/circuitboard/computer/arcade/amputation)
|
||||
/obj/item/circuitboard/computer/arcade/amputation,
|
||||
/obj/item/storage/bag/ammo)
|
||||
crate_name = "crate"
|
||||
|
||||
/datum/supply_pack/costumes_toys/foamforce
|
||||
|
||||
@@ -133,3 +133,6 @@
|
||||
var/parallax_movedir = 0
|
||||
var/parallax_layers_max = 3
|
||||
var/parallax_animate_timer
|
||||
|
||||
//world.time of when the crew manifest can be accessed
|
||||
var/crew_manifest_delay
|
||||
|
||||
@@ -50,6 +50,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
/// Custom Keybindings
|
||||
var/list/key_bindings = list()
|
||||
/// List with a key string associated to a list of keybindings. Unlike key_bindings, this one operates on raw key, allowing for binding a key that triggers regardless of if a modifier is depressed as long as the raw key is sent.
|
||||
var/list/modless_key_bindings = list()
|
||||
|
||||
|
||||
var/tgui_fancy = TRUE
|
||||
@@ -154,6 +156,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
"ipc_screen" = "Sunburst",
|
||||
"ipc_antenna" = "None",
|
||||
"flavor_text" = "",
|
||||
"silicon_flavor_text" = "",
|
||||
"ooc_notes" = "",
|
||||
"meat_type" = "Mammalian",
|
||||
"body_model" = MALE,
|
||||
@@ -367,6 +370,15 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "[features["flavor_text"]]"
|
||||
else
|
||||
dat += "[TextPreview(features["flavor_text"])]...<BR>"
|
||||
dat += "<h2>Silicon Flavor Text</h2>"
|
||||
dat += "<a href='?_src_=prefs;preference=silicon_flavor_text;task=input'><b>Set Silicon Examine Text</b></a><br>"
|
||||
if(length(features["silicon_flavor_text"]) <= 40)
|
||||
if(!length(features["silicon_flavor_text"]))
|
||||
dat += "\[...\]"
|
||||
else
|
||||
dat += "[features["silicon_flavor_text"]]"
|
||||
else
|
||||
dat += "[TextPreview(features["silicon_flavor_text"])]...<BR>"
|
||||
dat += "<h2>OOC notes</h2>"
|
||||
dat += "<a href='?_src_=prefs;preference=ooc_notes;task=input'><b>Set OOC notes</b></a><br>"
|
||||
var/ooc_notes_len = length(features["ooc_notes"])
|
||||
@@ -1088,11 +1100,16 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
Input mode is the closest thing to the old input system.<br>\
|
||||
<b>IMPORTANT:</b> While in input mode's non hotkey setting (tab toggled), Ctrl + KEY will send KEY to the keybind system as the key itself, not as Ctrl + KEY. This means Ctrl + T/W/A/S/D/all your familiar stuff still works, but you \
|
||||
won't be able to access any regular Ctrl binds.<br>"
|
||||
dat += "<br><b>Modifier-Independent binding</b> - This is a singular bind that works regardless of if Ctrl/Shift/Alt are held down. For example, if combat mode is bound to C in modifier-independent binds, it'll trigger regardless of if you are \
|
||||
holding down shift for sprint. <b>Each keybind can only have one independent binding, and each key can only have one keybind independently bound to it.</b>"
|
||||
// Create an inverted list of keybindings -> key
|
||||
var/list/user_binds = list()
|
||||
var/list/user_modless_binds = list()
|
||||
for (var/key in key_bindings)
|
||||
for(var/kb_name in key_bindings[key])
|
||||
user_binds[kb_name] += list(key)
|
||||
for (var/key in modless_key_bindings)
|
||||
user_modless_binds[modless_key_bindings[key]] = key
|
||||
|
||||
var/list/kb_categories = list()
|
||||
// Group keybinds by category
|
||||
@@ -1100,21 +1117,29 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/datum/keybinding/kb = GLOB.keybindings_by_name[name]
|
||||
kb_categories[kb.category] += list(kb)
|
||||
|
||||
dat += "<style>label { display: inline-block; width: 200px; }</style><body>"
|
||||
dat += {"
|
||||
<style>
|
||||
span.bindname { display: inline-block; position: absolute; width: 20% ; left: 5px; padding: 5px; } \
|
||||
span.bindings { display: inline-block; position: relative; width: auto; left: 20%; width: auto; right: 20%; padding: 5px; } \
|
||||
span.independent { display: inline-block; position: absolute; width: 20%; right: 5px; padding: 5px; } \
|
||||
</style><body>
|
||||
"}
|
||||
|
||||
for (var/category in kb_categories)
|
||||
dat += "<h3>[category]</h3>"
|
||||
for (var/i in kb_categories[category])
|
||||
var/datum/keybinding/kb = i
|
||||
var/current_independent_binding = user_modless_binds[kb.name] || "Unbound"
|
||||
if(!length(user_binds[kb.name]))
|
||||
dat += "<label>[kb.full_name]</label> <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=["Unbound"]'>Unbound</a>"
|
||||
dat += "<span class='bindname'>[kb.full_name]</span><span class='bindings'><a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=["Unbound"]'>Unbound</a>"
|
||||
var/list/default_keys = hotkeys ? kb.hotkey_keys : kb.classic_keys
|
||||
if(LAZYLEN(default_keys))
|
||||
dat += "| Default: [default_keys.Join(", ")]"
|
||||
dat += "</span><span class='independent'>Independent Binding: <a href='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[current_independent_binding];independent=1'>[current_independent_binding]</a></span>"
|
||||
dat += "<br>"
|
||||
else
|
||||
var/bound_key = user_binds[kb.name][1]
|
||||
dat += "<label>[kb.full_name]</label> <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
|
||||
dat += "<span class='bindname'l>[kb.full_name]</span><span class='bindings'><a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
|
||||
for(var/bound_key_index in 2 to length(user_binds[kb.name]))
|
||||
bound_key = user_binds[kb.name][bound_key_index]
|
||||
dat += " | <a href ='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[bound_key]'>[bound_key]</a>"
|
||||
@@ -1123,6 +1148,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/list/default_keys = hotkeys ? kb.classic_keys : kb.hotkey_keys
|
||||
if(LAZYLEN(default_keys))
|
||||
dat += "| Default: [default_keys.Join(", ")]"
|
||||
dat += "</span><span class='independent'>Independent Binding: <a href='?_src_=prefs;preference=keybindings_capture;keybinding=[kb.name];old_key=[current_independent_binding];independent=1'>[current_independent_binding]</a></span>"
|
||||
dat += "<br>"
|
||||
|
||||
dat += "<br><br>"
|
||||
@@ -1148,7 +1174,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
#undef APPEARANCE_CATEGORY_COLUMN
|
||||
#undef MAX_MUTANT_ROWS
|
||||
|
||||
/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, var/old_key)
|
||||
/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, old_key, independent = FALSE)
|
||||
var/HTML = {"
|
||||
<div id='focus' style="outline: 0;" tabindex=0>Keybinding: [kb.full_name]<br>[kb.description]<br><br><b>Press any key to change<br>Press ESC to clear</b></div>
|
||||
<script>
|
||||
@@ -1160,7 +1186,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var shift = e.shiftKey ? 1 : 0;
|
||||
var numpad = (95 < e.keyCode && e.keyCode < 112) ? 1 : 0;
|
||||
var escPressed = e.keyCode == 27 ? 1 : 0;
|
||||
var url = 'byond://?_src_=prefs;preference=keybindings_set;keybinding=[kb.name];old_key=[old_key];clear_key='+escPressed+';key='+e.key+';alt='+alt+';ctrl='+ctrl+';shift='+shift+';numpad='+numpad+';key_code='+e.keyCode;
|
||||
var url = 'byond://?_src_=prefs;preference=keybindings_set;keybinding=[kb.name];old_key=[old_key];[independent?"independent=1":""];clear_key='+escPressed+';key='+e.key+';alt='+alt+';ctrl='+ctrl+';shift='+shift+';numpad='+numpad+';key_code='+e.keyCode;
|
||||
window.location=url;
|
||||
deedDone = true;
|
||||
}
|
||||
@@ -1612,14 +1638,19 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN)
|
||||
|
||||
if("flavor_text")
|
||||
var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", features["flavor_text"], MAX_FLAVOR_LEN, TRUE)
|
||||
var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", html_decode(features["flavor_text"]), MAX_FLAVOR_LEN, TRUE)
|
||||
if(!isnull(msg))
|
||||
features["flavor_text"] = html_decode(msg)
|
||||
features["flavor_text"] = msg
|
||||
|
||||
if("silicon_flavor_text")
|
||||
var/msg = stripped_multiline_input(usr, "Set the silicon flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Silicon Flavor Text", html_decode(features["silicon_flavor_text"]), MAX_FLAVOR_LEN, TRUE)
|
||||
if(!isnull(msg))
|
||||
features["silicon_flavor_text"] = msg
|
||||
|
||||
if("ooc_notes")
|
||||
var/msg = stripped_multiline_input(usr, "Set always-visible OOC notes related to content preferences. THIS IS NOT FOR CHARACTER DESCRIPTIONS!", "OOC notes", features["ooc_notes"], MAX_FLAVOR_LEN, TRUE)
|
||||
var/msg = stripped_multiline_input(usr, "Set always-visible OOC notes related to content preferences. THIS IS NOT FOR CHARACTER DESCRIPTIONS!", "OOC notes", html_decode(features["ooc_notes"]), MAX_FLAVOR_LEN, TRUE)
|
||||
if(!isnull(msg))
|
||||
features["ooc_notes"] = html_decode(msg)
|
||||
features["ooc_notes"] = msg
|
||||
|
||||
if("hair")
|
||||
var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null
|
||||
@@ -2357,8 +2388,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
|
||||
if("keybindings_capture")
|
||||
var/datum/keybinding/kb = GLOB.keybindings_by_name[href_list["keybinding"]]
|
||||
var/old_key = href_list["old_key"]
|
||||
CaptureKeybinding(user, kb, old_key)
|
||||
CaptureKeybinding(user, kb, href_list["old_key"], text2num(href_list["independent"]))
|
||||
return
|
||||
|
||||
if("keybindings_set")
|
||||
@@ -2368,13 +2398,18 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
ShowChoices(user)
|
||||
return
|
||||
|
||||
var/independent = href_list["independent"]
|
||||
|
||||
var/clear_key = text2num(href_list["clear_key"])
|
||||
var/old_key = href_list["old_key"]
|
||||
if(clear_key)
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
if(independent)
|
||||
modless_key_bindings -= old_key
|
||||
else
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
user << browse(null, "window=capturekeypress")
|
||||
save_preferences()
|
||||
ShowChoices(user)
|
||||
@@ -2400,15 +2435,18 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
full_key = "[AltMod][CtrlMod][new_key]"
|
||||
else
|
||||
full_key = "[AltMod][CtrlMod][ShiftMod][numpad][new_key]"
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
key_bindings[full_key] += list(kb_name)
|
||||
key_bindings[full_key] = sortList(key_bindings[full_key])
|
||||
|
||||
user << browse(null, "window=capturekeypress")
|
||||
if(independent)
|
||||
modless_key_bindings -= old_key
|
||||
modless_key_bindings[full_key] = kb_name
|
||||
else
|
||||
if(key_bindings[old_key])
|
||||
key_bindings[old_key] -= kb_name
|
||||
if(!length(key_bindings[old_key]))
|
||||
key_bindings -= old_key
|
||||
key_bindings[full_key] += list(kb_name)
|
||||
key_bindings[full_key] = sortList(key_bindings[full_key])
|
||||
user.client.update_movement_keys()
|
||||
user << browse(null, "window=capturekeypress")
|
||||
save_preferences()
|
||||
|
||||
if("keybindings_reset")
|
||||
@@ -2418,6 +2456,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
return
|
||||
hotkeys = (choice == "Hotkey")
|
||||
key_bindings = (hotkeys) ? deepCopyList(GLOB.hotkey_keybinding_list_by_key) : deepCopyList(GLOB.classic_keybinding_list_by_key)
|
||||
modless_key_bindings = list()
|
||||
user.client.update_movement_keys()
|
||||
|
||||
if("chat_on_map")
|
||||
@@ -2572,8 +2611,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
current_tab = text2num(href_list["tab"])
|
||||
if(href_list["preference"] == "gear")
|
||||
if(href_list["clear_loadout"])
|
||||
LAZYCLEARLIST(chosen_gear)
|
||||
gear_points = initial(gear_points)
|
||||
chosen_gear = list()
|
||||
gear_points = CONFIG_GET(number/initial_gear_points)
|
||||
save_preferences()
|
||||
if(href_list["select_category"])
|
||||
for(var/i in GLOB.loadout_items)
|
||||
@@ -2585,7 +2624,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
return
|
||||
var/toggle = text2num(href_list["toggle_gear"])
|
||||
if(!toggle && (G.type in chosen_gear))//toggling off and the item effectively is in chosen gear)
|
||||
LAZYREMOVE(chosen_gear, G.type)
|
||||
chosen_gear -= G.type
|
||||
gear_points += initial(G.cost)
|
||||
else if(toggle && (!(is_type_in_ref_list(G, chosen_gear))))
|
||||
if(!is_loadout_slot_available(G.category))
|
||||
@@ -2595,7 +2634,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
to_chat(user, "<span class='danger'>This is an item intended for donator use only. You are not authorized to use this item.</span>")
|
||||
return
|
||||
if(gear_points >= initial(G.cost))
|
||||
LAZYADD(chosen_gear, G.type)
|
||||
chosen_gear += G.type
|
||||
gear_points -= initial(G.cost)
|
||||
|
||||
ShowChoices(user)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// You do not need to raise this if you are adding new values that have sane defaults.
|
||||
// Only raise this value when changing the meaning/format/name/layout of an existing value
|
||||
// where you would want the updater procs below to run
|
||||
#define SAVEFILE_VERSION_MAX 32
|
||||
#define SAVEFILE_VERSION_MAX 33
|
||||
|
||||
/*
|
||||
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
|
||||
@@ -194,6 +194,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
if(current_version < 31)
|
||||
S["wing_color"] >> features["wings_color"]
|
||||
S["horn_color"] >> features["horns_color"]
|
||||
|
||||
if(current_version < 33)
|
||||
features["flavor_text"] = html_encode(features["flavor_text"])
|
||||
features["silicon_flavor_text"] = html_encode(features["silicon_flavor_text"])
|
||||
features["ooc_notes"] = html_encode(features["ooc_notes"])
|
||||
|
||||
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
|
||||
if(!ckey)
|
||||
@@ -262,6 +267,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
// Custom hotkeys
|
||||
S["key_bindings"] >> key_bindings
|
||||
S["modless_key_bindings"] >> modless_key_bindings
|
||||
|
||||
//citadel code
|
||||
S["arousable"] >> arousable
|
||||
@@ -315,7 +321,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
cit_toggles = sanitize_integer(cit_toggles, 0, 16777215, initial(cit_toggles))
|
||||
auto_ooc = sanitize_integer(auto_ooc, 0, 1, initial(auto_ooc))
|
||||
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
|
||||
key_bindings = sanitize_islist(key_bindings, list())
|
||||
key_bindings = sanitize_islist(key_bindings, list())
|
||||
modless_key_bindings = sanitize_islist(modless_key_bindings, list())
|
||||
|
||||
verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped
|
||||
|
||||
@@ -333,6 +340,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
if(!length(binds))
|
||||
key_bindings -= key
|
||||
// End
|
||||
// I hate copypaste but let's do it again but for modless ones
|
||||
for(var/key in modless_key_bindings)
|
||||
var/bindname = modless_key_bindings[key]
|
||||
if(!GLOB.keybindings_by_name[bindname])
|
||||
modless_key_bindings -= key
|
||||
|
||||
/datum/preferences/proc/save_preferences()
|
||||
if(!path)
|
||||
@@ -387,6 +399,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
WRITE_FILE(S["pda_color"], pda_color)
|
||||
WRITE_FILE(S["pda_skin"], pda_skin)
|
||||
WRITE_FILE(S["key_bindings"], key_bindings)
|
||||
WRITE_FILE(S["modless_key_bindings"], modless_key_bindings)
|
||||
|
||||
//citadel code
|
||||
WRITE_FILE(S["screenshake"], screenshake)
|
||||
@@ -553,7 +566,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
else //We have no old flavortext, default to new
|
||||
S["feature_flavor_text"] >> features["flavor_text"]
|
||||
|
||||
|
||||
S["silicon_feature_flavor_text"] >> features["silicon_flavor_text"]
|
||||
|
||||
S["feature_ooc_notes"] >> features["ooc_notes"]
|
||||
S["silicon_flavor_text"] >> features["silicon_flavor_text"]
|
||||
|
||||
S["vore_flags"] >> vore_flags
|
||||
S["vore_taste"] >> vore_taste
|
||||
@@ -678,6 +695,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
|
||||
|
||||
features["flavor_text"] = copytext(features["flavor_text"], 1, MAX_FLAVOR_LEN)
|
||||
features["silicon_flavor_text"] = copytext(features["silicon_flavor_text"], 1, MAX_FLAVOR_LEN)
|
||||
features["ooc_notes"] = copytext(features["ooc_notes"], 1, MAX_FLAVOR_LEN)
|
||||
|
||||
joblessrole = sanitize_integer(joblessrole, 1, 3, initial(joblessrole))
|
||||
|
||||
@@ -13,21 +13,38 @@ GLOBAL_VAR_INIT(normal_aooc_colour, "#ce254f")
|
||||
if(!mob)
|
||||
return
|
||||
|
||||
if(!(prefs.toggles & CHAT_OOC))
|
||||
to_chat(src, "<span class='danger'> You have OOC muted.</span>")
|
||||
return
|
||||
if(jobban_isbanned(mob, "OOC"))
|
||||
to_chat(src, "<span class='danger'>You have been banned from OOC.</span>")
|
||||
return
|
||||
|
||||
if(!holder)
|
||||
if(mob.stat == DEAD)
|
||||
to_chat(usr, "<span class='danger'>You cannot use AOOC while dead.</span>")
|
||||
return
|
||||
if(!is_special_character(mob))
|
||||
to_chat(usr, "<span class='danger'>You aren't an antagonist!</span>")
|
||||
if(prefs.muted & MUTE_OOC)
|
||||
to_chat(src, "<span class='danger'>You cannot use AOOC (muted).</span>")
|
||||
return
|
||||
if(jobban_isbanned(src.mob, "OOC"))
|
||||
to_chat(src, "<span class='danger'>You are banned from OOC.</span>")
|
||||
return
|
||||
if(!GLOB.aooc_allowed)
|
||||
to_chat(src, "<span class='danger'>AOOC is currently muted.</span>")
|
||||
return
|
||||
if(prefs.muted & MUTE_OOC)
|
||||
to_chat(src, "<span class='danger'>You cannot use AOOC (muted).</span>")
|
||||
return
|
||||
if(!is_special_character(mob))
|
||||
to_chat(usr, "<span class='danger'>You aren't an antagonist!</span>")
|
||||
if(handle_spam_prevention(msg,MUTE_OOC))
|
||||
return
|
||||
if(findtext(msg, "byond://"))
|
||||
to_chat(src, "<B>Advertising other servers is not allowed.</B>")
|
||||
log_admin("[key_name(src)] has attempted to advertise in LOOC: [msg]")
|
||||
return
|
||||
if(mob.stat)
|
||||
to_chat(usr, "<span class='danger'>You cannot use AOOC while unconscious or dead.</span>")
|
||||
return
|
||||
if(isdead(mob))
|
||||
to_chat(src, "<span class='danger'>You cannot use AOOC while ghosting.</span>")
|
||||
return
|
||||
if(HAS_TRAIT(mob, TRAIT_AOOC_MUTE))
|
||||
to_chat(src, "<span class='danger'>You cannot use AOOC right now.</span>")
|
||||
return
|
||||
|
||||
if(QDELETED(src))
|
||||
return
|
||||
|
||||
|
||||
@@ -38,11 +38,15 @@ GLOBAL_VAR_INIT(normal_looc_colour, "#6699CC")
|
||||
log_admin("[key_name(src)] has attempted to advertise in LOOC: [msg]")
|
||||
return
|
||||
if(mob.stat)
|
||||
to_chat(src, "<span class='danger'>You cannot salt in LOOC while unconscious or dead.</span>")
|
||||
to_chat(src, "<span class='danger'>You cannot use LOOC while unconscious or dead.</span>")
|
||||
return
|
||||
if(istype(mob, /mob/dead))
|
||||
if(isdead(mob))
|
||||
to_chat(src, "<span class='danger'>You cannot use LOOC while ghosting.</span>")
|
||||
return
|
||||
if(HAS_TRAIT(mob, TRAIT_LOOC_MUTE))
|
||||
to_chat(src, "<span class='danger'>You cannot use LOOC right now.</span>")
|
||||
return
|
||||
|
||||
|
||||
msg = emoji_parse(msg)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
throwforce = 0
|
||||
slot_flags = ITEM_SLOT_EARS
|
||||
resistance_flags = NONE
|
||||
custom_price = 250
|
||||
custom_price = PRICE_BELOW_NORMAL
|
||||
|
||||
/obj/item/clothing/ears/earmuffs
|
||||
name = "earmuffs"
|
||||
@@ -31,7 +31,7 @@
|
||||
slot_flags = ITEM_SLOT_EARS | ITEM_SLOT_HEAD | ITEM_SLOT_NECK //Fluff item, put it whereever you want!
|
||||
actions_types = list(/datum/action/item_action/toggle_headphones)
|
||||
var/headphones_on = FALSE
|
||||
custom_price = 125
|
||||
custom_price = PRICE_ALMOST_CHEAP
|
||||
|
||||
/obj/item/clothing/ears/headphones/Initialize()
|
||||
. = ..()
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
permeability_coefficient = 0.05
|
||||
resistance_flags = NONE
|
||||
var/can_be_cut = 1
|
||||
custom_price = 1200
|
||||
custom_premium_price = 1200
|
||||
custom_price = PRICE_EXPENSIVE
|
||||
custom_premium_price = PRICE_ALMOST_ONE_GRAND
|
||||
|
||||
/obj/item/toy/sprayoncan
|
||||
name = "spray-on insulation applicator"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
cold_protection = HANDS
|
||||
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
|
||||
strip_mod = 0.9
|
||||
custom_price = 75
|
||||
custom_price = PRICE_ALMOST_CHEAP
|
||||
|
||||
/obj/item/clothing/gloves/fingerless/pugilist
|
||||
name = "armwraps"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
cold_protection = HANDS
|
||||
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
|
||||
resistance_flags = NONE
|
||||
//custom_premium_price = 350
|
||||
//custom_premium_price = PRICE_EXPENSIVE
|
||||
/// For storing our tackler datum so we can remove it after
|
||||
var/datum/component/tackler
|
||||
/// See: [/datum/component/tackler/var/stamina_cost]
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
name = "white beanie"
|
||||
desc = "A stylish beanie. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their heads."
|
||||
icon_state = "beanie" //Default white
|
||||
custom_price = 60
|
||||
|
||||
/obj/item/clothing/head/beanie/black
|
||||
name = "black beanie"
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
/obj/item/clothing/head/hunter
|
||||
name = "hunter"
|
||||
desc = "A basic hat for hunting things."
|
||||
icon = 'modular_citadel/icons/obj/clothing/cit_hats.dmi'
|
||||
icon_state = "hunter"
|
||||
item_state = "hunter_worn"
|
||||
@@ -58,7 +58,7 @@
|
||||
desc = "A reliable, blue tinted helmet reminding you that you <i>still</i> owe that engineer a beer."
|
||||
icon_state = "blueshift"
|
||||
item_state = "blueshift"
|
||||
custom_premium_price = 750
|
||||
custom_premium_price = PRICE_ABOVE_EXPENSIVE
|
||||
|
||||
/obj/item/clothing/head/helmet/riot
|
||||
name = "riot helmet"
|
||||
|
||||
@@ -375,12 +375,6 @@
|
||||
icon_state = "telegram"
|
||||
dog_fashion = /datum/dog_fashion/head/telegram
|
||||
|
||||
/obj/item/clothing/head/colour
|
||||
name = "Singer cap"
|
||||
desc = "A light white hat that has bands of color. Just makes you want to sing and dance!"
|
||||
icon_state = "colour"
|
||||
dog_fashion = /datum/dog_fashion/head/colour
|
||||
|
||||
/obj/item/clothing/head/christmashat
|
||||
name = "red santa hat"
|
||||
desc = "A red Christmas Hat! How festive!"
|
||||
@@ -434,3 +428,4 @@
|
||||
desc = "A symbol of discipline, honor, and lots and lots of removal of some type of skewered food."
|
||||
icon_state = "russobluecamohat"
|
||||
item_state = "russobluecamohat"
|
||||
dynamic_hair_suffix = ""
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
desc = "A jack o' lantern! Believed to ward off evil spirits."
|
||||
icon_state = "hardhat0_pumpkin"
|
||||
item_state = "hardhat0_pumpkin"
|
||||
hat_type = "pumpkin"
|
||||
flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
brightness_on = 2 //luminosity when on
|
||||
@@ -150,6 +151,7 @@
|
||||
desc = "Some fake antlers and a very fake red nose."
|
||||
icon_state = "hardhat0_reindeer"
|
||||
item_state = "hardhat0_reindeer"
|
||||
hat_type = "reindeer"
|
||||
flags_inv = 0
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
brightness_on = 1 //luminosity when on
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
name = "baseball cap"
|
||||
desc = "It's a robust baseball hat, this one belongs to syndicate major league team."
|
||||
icon_state = "baseballsoft"
|
||||
soft_type = "baseballsoft"
|
||||
soft_type = "baseball"
|
||||
item_state = "baseballsoft"
|
||||
flags_inv = HIDEEYES|HIDEFACE
|
||||
armor = list("melee" = 35, "bullet" = 35, "laser" = 25, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 90)
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
icon_state = "bluetie"
|
||||
item_state = "" //no inhands
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
custom_price = 60
|
||||
|
||||
/obj/item/clothing/neck/tie/blue
|
||||
name = "blue tie"
|
||||
@@ -88,7 +87,6 @@
|
||||
/obj/item/clothing/neck/scarf //Default white color, same functionality as beanies.
|
||||
name = "white scarf"
|
||||
icon_state = "scarf"
|
||||
custom_price = 60
|
||||
desc = "A stylish scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks."
|
||||
dog_fashion = /datum/dog_fashion/head
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/obj/item/clothing/shoes/sneakers
|
||||
dying_key = DYE_REGISTRY_SNEAKERS
|
||||
custom_price = 50
|
||||
|
||||
/obj/item/clothing/shoes/sneakers/black
|
||||
name = "black shoes"
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
equip_delay_other = 50
|
||||
resistance_flags = NONE
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 40, "acid" = 75)
|
||||
custom_price = 600
|
||||
custom_price = PRICE_ABOVE_EXPENSIVE
|
||||
|
||||
/obj/item/clothing/shoes/galoshes/dry
|
||||
name = "absorbent galoshes"
|
||||
@@ -384,7 +384,6 @@
|
||||
/obj/item/clothing/shoes/cowboyboots
|
||||
name = "cowboy boots"
|
||||
desc = "A standard pair of brown cowboy boots."
|
||||
custom_price = 60 //remember to replace these lame cosmetics with tg's YEEEEHAW counterparts.
|
||||
icon_state = "cowboyboots"
|
||||
|
||||
/obj/item/clothing/shoes/cowboyboots/black
|
||||
|
||||
@@ -469,7 +469,7 @@ Contains:
|
||||
desc = "Voices echo from the hardsuit, driving the user insane. This one is pretty battle-worn, but still fearsome."
|
||||
armor = list("melee" = 55, "bullet" = 40, "laser" = 40, "energy" = 40, "bomb" = 40, "bio" = 80, "rad" = 80, "fire" = 60, "acid" = 60)
|
||||
slowdown = 0.8
|
||||
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor/old
|
||||
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/beserker/old
|
||||
charges = 6
|
||||
|
||||
/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/beserker/old
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
desc = "A large, yet comfortable piece of armor, protecting you from some threats."
|
||||
icon_state = "blueshift"
|
||||
item_state = "blueshift"
|
||||
custom_premium_price = 750
|
||||
custom_premium_price = PRICE_ABOVE_EXPENSIVE
|
||||
|
||||
/obj/item/clothing/suit/armor/hos
|
||||
name = "armored greatcoat"
|
||||
|
||||
@@ -87,7 +87,6 @@
|
||||
icon_state = "overalls"
|
||||
item_state = "lb_suit"
|
||||
can_adjust = FALSE
|
||||
custom_price = 60
|
||||
|
||||
/obj/item/clothing/under/misc/assistantformal
|
||||
name = "assistant's formal uniform"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
body_parts_covered = GROIN|LEGS
|
||||
fitted = NO_FEMALE_UNIFORM
|
||||
can_adjust = FALSE
|
||||
custom_price = 60
|
||||
mutantrace_variation = STYLE_DIGITIGRADE //how do they show up on taurs otherwise?
|
||||
|
||||
/obj/item/clothing/under/pants/classicjeans
|
||||
@@ -15,7 +14,7 @@
|
||||
name = "Must Hang jeans"
|
||||
desc = "Made in the finest space jeans factory this side of Alpha Centauri."
|
||||
icon_state = "jeansmustang"
|
||||
custom_price = 180
|
||||
custom_price = PRICE_ABOVE_NORMAL
|
||||
|
||||
/obj/item/clothing/under/pants/blackjeans
|
||||
name = "black jeans"
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
body_parts_covered = CHEST|GROIN|ARMS
|
||||
fitted = FEMALE_UNIFORM_TOP
|
||||
can_adjust = FALSE
|
||||
custom_price = 60
|
||||
|
||||
/obj/item/clothing/under/dress/skirt/red
|
||||
name = "red skirt"
|
||||
@@ -27,7 +26,6 @@
|
||||
body_parts_covered = CHEST|GROIN|ARMS
|
||||
fitted = FEMALE_UNIFORM_TOP
|
||||
can_adjust = FALSE
|
||||
custom_price = 60
|
||||
|
||||
/obj/item/clothing/under/dress/skirt/purple
|
||||
name = "purple skirt"
|
||||
@@ -37,7 +35,6 @@
|
||||
body_parts_covered = CHEST|GROIN|ARMS
|
||||
fitted = FEMALE_UNIFORM_TOP
|
||||
can_adjust = FALSE
|
||||
custom_price = 60
|
||||
|
||||
/obj/item/clothing/under/dress/sundress
|
||||
name = "sundress"
|
||||
@@ -151,7 +148,6 @@
|
||||
fitted = FEMALE_UNIFORM_TOP
|
||||
can_adjust = TRUE
|
||||
alt_covers_chest = TRUE
|
||||
custom_price = 60
|
||||
|
||||
/obj/item/clothing/under/dress/skirt/plaid/blue
|
||||
name = "blue plaid skirt"
|
||||
|
||||
@@ -97,6 +97,48 @@
|
||||
icon_state = "trek_ds9_medsci"
|
||||
item_state = "b_suit"
|
||||
|
||||
//Orvilike (Orville-inspired clothing with TOS-like color code)
|
||||
/obj/item/clothing/under/trek/command/orv
|
||||
desc = "An uniform worn by command officers since 2420s."
|
||||
icon_state = "orv_com"
|
||||
|
||||
/obj/item/clothing/under/trek/engsec/orv
|
||||
desc = "An uniform worn by operations officers since 2420s."
|
||||
icon_state = "orv_ops"
|
||||
|
||||
/obj/item/clothing/under/trek/medsci/orv
|
||||
desc = "An uniform worn by medsci officers since 2420s."
|
||||
icon_state = "orv_medsci"
|
||||
|
||||
//Orvilike Extra (Ditto, but expands it for Civilian department with SS13 colors and gives specified command uniform)
|
||||
//honestly no idea why i added specified comm. uniforms but w/e
|
||||
/obj/item/clothing/under/trek/command/orv/captain
|
||||
name = "captain uniform"
|
||||
desc = "An uniform worn by captains since 2550s."
|
||||
icon_state = "orv_com_capt"
|
||||
|
||||
/obj/item/clothing/under/trek/command/orv/engsec
|
||||
name = "operations command uniform"
|
||||
desc = "An uniform worn by operations command officers since 2550s."
|
||||
icon_state = "orv_com_ops"
|
||||
|
||||
/obj/item/clothing/under/trek/command/orv/medsci
|
||||
name = "medsci command uniform"
|
||||
desc = "An uniform worn by medsci command officers since 2550s."
|
||||
icon_state = "orv_com_medsci"
|
||||
|
||||
/obj/item/clothing/under/trek/orv
|
||||
name = "adjutant uniform"
|
||||
desc = "An uniform worn by adjutants <i>(assistants)</i> since 2550s."
|
||||
icon_state = "orv_ass"
|
||||
item_state = "gy_suit"
|
||||
|
||||
/obj/item/clothing/under/trek/orv/service
|
||||
name = "service uniform"
|
||||
desc = "An uniform worn by service officers since 2550s."
|
||||
icon_state = "orv_srv"
|
||||
item_state = "g_suit"
|
||||
|
||||
//The Motion Picture
|
||||
/obj/item/clothing/under/trek/fedutil
|
||||
name = "federation utility uniform"
|
||||
|
||||
@@ -330,8 +330,8 @@
|
||||
if(!override)
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/spacevine/attacked_by(obj/item/I, mob/living/user)
|
||||
var/damage_dealt = I.force
|
||||
/obj/structure/spacevine/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
var/damage_dealt = I.force * damage_multiplier
|
||||
if(I.get_sharpness())
|
||||
damage_dealt *= 4
|
||||
if(I.damtype == BURN)
|
||||
@@ -383,6 +383,7 @@
|
||||
/datum/spacevine_controller/New(turf/location, list/muts, potency, production, datum/round_event/event = null)
|
||||
vines = list()
|
||||
growth_queue = list()
|
||||
spawn_spacevine_piece(location, null, muts)
|
||||
START_PROCESSING(SSobj, src)
|
||||
vine_mutations_list = list()
|
||||
init_subtypes(/datum/spacevine_mutation/, vine_mutations_list)
|
||||
|
||||
@@ -268,12 +268,15 @@
|
||||
/obj/item/reagent_containers/food/drinks/ice
|
||||
name = "ice cup"
|
||||
desc = "Careful, cold ice, do not chew."
|
||||
custom_price = 15
|
||||
custom_price = PRICE_CHEAP_AS_FREE
|
||||
icon_state = "coffee"
|
||||
list_reagents = list(/datum/reagent/consumable/ice = 30)
|
||||
spillable = TRUE
|
||||
isGlass = FALSE
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/ice/sustanance
|
||||
custom_price = PRICE_FREE
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/mug/ // parent type is literally just so empty mug sprites are a thing
|
||||
name = "mug"
|
||||
desc = "A drink served in a classy mug."
|
||||
@@ -303,7 +306,7 @@
|
||||
list_reagents = list(/datum/reagent/consumable/hot_coco = 30, /datum/reagent/consumable/sugar = 5)
|
||||
foodtype = SUGAR
|
||||
resistance_flags = FREEZE_PROOF
|
||||
custom_price = 120
|
||||
custom_price = PRICE_ALMOST_CHEAP
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/dry_ramen
|
||||
name = "cup ramen"
|
||||
@@ -312,7 +315,7 @@
|
||||
list_reagents = list(/datum/reagent/consumable/dry_ramen = 30)
|
||||
foodtype = GRAIN
|
||||
isGlass = FALSE
|
||||
custom_price = 95
|
||||
custom_price = PRICE_PRETTY_CHEAP
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/beer
|
||||
name = "space beer"
|
||||
@@ -320,7 +323,7 @@
|
||||
icon_state = "beer"
|
||||
list_reagents = list(/datum/reagent/consumable/ethanol/beer = 30)
|
||||
foodtype = GRAIN | ALCOHOL
|
||||
custom_price = 60
|
||||
custom_price = PRICE_PRETTY_CHEAP
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/beer/light
|
||||
name = "Carp Lite"
|
||||
@@ -421,7 +424,7 @@
|
||||
custom_materials = list(/datum/material/iron=250)
|
||||
volume = 60
|
||||
isGlass = FALSE
|
||||
custom_price = 200
|
||||
custom_price = PRICE_ABOVE_NORMAL
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/flask/gold
|
||||
name = "captain's flask"
|
||||
@@ -452,7 +455,7 @@
|
||||
reagent_flags = NONE
|
||||
spillable = FALSE
|
||||
isGlass = FALSE
|
||||
custom_price = 45
|
||||
custom_price = PRICE_CHEAP_AS_FREE
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/soda_cans/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] is trying to eat \the [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
|
||||
@@ -346,7 +346,7 @@
|
||||
/obj/item/reagent_containers/food/drinks/bottle/applejack
|
||||
name = "Buckin' Bronco's Applejack"
|
||||
desc = "Kicks like a horse, tastes like an apple!"
|
||||
custom_price = 100
|
||||
custom_price = PRICE_CHEAP
|
||||
icon_state = "applejack_bottle"
|
||||
list_reagents = list(/datum/reagent/consumable/ethanol/applejack = 100)
|
||||
foodtype = FRUIT
|
||||
@@ -357,7 +357,6 @@
|
||||
/obj/item/reagent_containers/food/drinks/bottle/champagne
|
||||
name = "Eau d' Dandy Brut Champagne"
|
||||
desc = "Finely sourced from only the most pretentious French vineyards."
|
||||
custom_premium_price = 250
|
||||
icon_state = "champagne_bottle"
|
||||
list_reagents = list(/datum/reagent/consumable/ethanol/champagne = 100)
|
||||
|
||||
@@ -376,7 +375,7 @@
|
||||
/obj/item/reagent_containers/food/drinks/bottle/trappist
|
||||
name = "Mont de Requin Trappistes Bleu"
|
||||
desc = "Brewed in space-Belgium. Fancy!"
|
||||
custom_premium_price = 170
|
||||
custom_premium_price = PRICE_ABOVE_NORMAL
|
||||
icon_state = "trappistbottle"
|
||||
volume = 50
|
||||
list_reagents = list(/datum/reagent/consumable/ethanol/trappist = 50)
|
||||
@@ -389,7 +388,7 @@
|
||||
/obj/item/reagent_containers/food/drinks/bottle/orangejuice
|
||||
name = "orange juice"
|
||||
desc = "Full of vitamins and deliciousness!"
|
||||
custom_price = 100
|
||||
custom_price = PRICE_CHEAP
|
||||
icon_state = "orangejuice"
|
||||
item_state = "carton"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
@@ -411,7 +410,7 @@
|
||||
/obj/item/reagent_containers/food/drinks/bottle/cream
|
||||
name = "milk cream"
|
||||
desc = "It's cream. Made from milk. What else did you think you'd find in there?"
|
||||
custom_price = 100
|
||||
custom_price = PRICE_CHEAP
|
||||
icon_state = "cream"
|
||||
item_state = "carton"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
@@ -423,7 +422,7 @@
|
||||
/obj/item/reagent_containers/food/drinks/bottle/tomatojuice
|
||||
name = "tomato juice"
|
||||
desc = "Well, at least it LOOKS like tomato juice. You can't tell with all that redness."
|
||||
custom_price = 100
|
||||
custom_price = PRICE_CHEAP
|
||||
icon_state = "tomatojuice"
|
||||
item_state = "carton"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
@@ -435,7 +434,7 @@
|
||||
/obj/item/reagent_containers/food/drinks/bottle/limejuice
|
||||
name = "lime juice"
|
||||
desc = "Sweet-sour goodness."
|
||||
custom_price = 100
|
||||
custom_price = PRICE_CHEAP
|
||||
icon_state = "limejuice"
|
||||
item_state = "carton"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
@@ -469,7 +468,7 @@
|
||||
/obj/item/reagent_containers/food/drinks/bottle/menthol
|
||||
name = "menthol"
|
||||
desc = "Tastes naturally minty, and imparts a very mild numbing sensation."
|
||||
custom_price = 100
|
||||
custom_price = PRICE_CHEAP
|
||||
icon_state = "mentholbox"
|
||||
item_state = "carton"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
@@ -480,7 +479,7 @@
|
||||
/obj/item/reagent_containers/food/drinks/bottle/grenadine
|
||||
name = "Jester Grenadine"
|
||||
desc = "Contains 0% real cherries!"
|
||||
custom_price = 100
|
||||
custom_price = PRICE_CHEAP
|
||||
icon_state = "grenadine"
|
||||
isGlass = TRUE
|
||||
list_reagents = list(/datum/reagent/consumable/grenadine = 100)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
spillable = TRUE
|
||||
resistance_flags = ACID_PROOF
|
||||
obj_flags = UNIQUE_RENAME
|
||||
custom_price = 25
|
||||
custom_price = PRICE_REALLY_CHEAP
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/drinkingglass/on_reagent_change(changetype)
|
||||
cut_overlays()
|
||||
@@ -47,7 +47,7 @@
|
||||
possible_transfer_amounts = list()
|
||||
volume = 15
|
||||
custom_materials = list(/datum/material/glass=100)
|
||||
custom_price = 20
|
||||
custom_price = PRICE_CHEAP_AS_FREE
|
||||
|
||||
/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/on_reagent_change(changetype)
|
||||
cut_overlays()
|
||||
|
||||
@@ -54,6 +54,15 @@
|
||||
tastes = list("fish" = 1, "chips" = 1)
|
||||
foodtype = MEAT | VEGETABLES | FRIED
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/fishfry
|
||||
name = "fish fry"
|
||||
desc = "All that and no bag of chips..."
|
||||
icon_state = "fish_fry"
|
||||
list_reagents = list (/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 3)
|
||||
filling_color = "#ee7676"
|
||||
tastes = list("fish" = 1, "pan seared vegtables" = 1)
|
||||
foodtype = MEAT | VEGETABLES | FRIED
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/sushi_basic
|
||||
name = "funa hosomaki"
|
||||
desc = "A small cylindrical kudzu skin, filled with rice and fish."
|
||||
|
||||
@@ -12,6 +12,17 @@
|
||||
tastes = list("cheese" = 1)
|
||||
foodtype = DAIRY
|
||||
|
||||
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/royalcheese
|
||||
name = "royal cheese"
|
||||
desc = "Ascend the throne. Consume the wheel. Feel the POWER."
|
||||
icon_state = "royalcheese"
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 15, /datum/reagent/consumable/nutriment/vitamin = 5, /datum/reagent/gold = 20, /datum/reagent/toxin/mutagen = 5)
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
tastes = list("cheese" = 4, "royalty" = 1)
|
||||
foodtype = DAIRY
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/cheesewedge
|
||||
name = "cheese wedge"
|
||||
desc = "A wedge of delicious Cheddar. The cheese wheel it was cut from can't have gone far."
|
||||
|
||||
@@ -144,6 +144,15 @@
|
||||
is_decorated = TRUE
|
||||
filling_color = "#879630"
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/donut/laugh
|
||||
name = "sweet pea donut"
|
||||
desc = "Goes great with a glass of Bastion Burbon!"
|
||||
icon_state = "donut_laugh"
|
||||
bonus_reagents = list(/datum/reagent/consumable/laughter = 3)
|
||||
tastes = list("donut" = 3, "fizzy tutti frutti" = 1,)
|
||||
is_decorated = TRUE
|
||||
filling_color = "#803280"
|
||||
|
||||
//////////////////////JELLY DONUTS/////////////////////////
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/donut/jelly
|
||||
@@ -234,6 +243,15 @@
|
||||
is_decorated = TRUE
|
||||
filling_color = "#879630"
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/donut/jelly/laugh
|
||||
name = "sweet pea jelly donut"
|
||||
desc = "Goes great with a glass of Bastion Burbon!"
|
||||
icon_state = "jelly_laugh"
|
||||
bonus_reagents = list(/datum/reagent/consumable/laughter = 3)
|
||||
tastes = list("jelly" = 3, "donut" = 1, "fizzy tutti frutti" = 1)
|
||||
is_decorated = TRUE
|
||||
filling_color = "#803280"
|
||||
|
||||
//////////////////////////SLIME DONUTS/////////////////////////
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/donut/jelly/slimejelly
|
||||
@@ -315,6 +333,15 @@
|
||||
is_decorated = TRUE
|
||||
filling_color = "#879630"
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/donut/jelly/slimejelly/laugh
|
||||
name = "sweet pea jelly donut"
|
||||
desc = "Goes great with a glass of Bastion Burbon!"
|
||||
icon_state = "jelly_laugh"
|
||||
bonus_reagents = list(/datum/reagent/consumable/laughter = 3)
|
||||
tastes = list("jelly" = 3, "donut" = 1, "fizzy tutti frutti" = 1)
|
||||
is_decorated = TRUE
|
||||
filling_color = "#803280"
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/donut/glaze
|
||||
name = "glazed donut"
|
||||
desc = "A sugar glazed donut."
|
||||
|
||||
@@ -124,4 +124,22 @@
|
||||
trash = /obj/item/kitchen/knife
|
||||
bonus_reagents = list(/datum/reagent/medicine/earthsblood = 1, /datum/reagent/iron = 4)
|
||||
tastes = list("iron" = 1, "conspiracy" = 1)
|
||||
foodtype = VEGETABLES
|
||||
foodtype = VEGETABLES
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/salad/edensalad
|
||||
name = "\improper Salad of Eden"
|
||||
desc = "A salad brimming with untapped potential."
|
||||
icon_state = "eden_salad"
|
||||
trash = /obj/item/reagent_containers/glass/bowl
|
||||
list_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/nutriment/vitamin = 5, /datum/reagent/medicine/earthsblood = 3, /datum/reagent/medicine/omnizine = 5, /datum/reagent/drug/happiness = 2)
|
||||
tastes = list("hope" = 1)
|
||||
foodtype = VEGETABLES
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/salad/gumbo
|
||||
name = "black eyed gumbo"
|
||||
desc = "A spicy and savory meat and rice dish."
|
||||
icon_state = "gumbo"
|
||||
trash = /obj/item/reagent_containers/glass/bowl
|
||||
list_reagents = list(/datum/reagent/consumable/capsaicin = 2, /datum/reagent/consumable/nutriment/vitamin = 3, /datum/reagent/consumable/nutriment = 5)
|
||||
tastes = list("building heat" = 2, "savory meat and vegtables" = 1)
|
||||
foodtype = GRAIN | MEAT | VEGETABLES
|
||||
|
||||
@@ -262,3 +262,13 @@
|
||||
tastes = list("bungo" = 2, "hot curry" = 4, "tropical sweetness" = 1)
|
||||
filling_color = "#E6A625"
|
||||
foodtype = VEGETABLES | FRUIT | DAIRY
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/soup/peasoup
|
||||
name = "pea soup"
|
||||
desc = "A humble split pea soup."
|
||||
icon_state = "peasoup"
|
||||
bonus_reagents = list (/datum/reagent/consumable/nutriment/vitamin = 6, /datum/reagent/medicine/oculine = 2)
|
||||
list_reagents = list (/datum/reagent/consumable/nutriment = 8)
|
||||
tastes = list("creamy peas"= 2, "parsnip" = 1)
|
||||
filling_color = "#9dc530"
|
||||
foodtype = VEGETABLES
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
filling_color = "#FFD700"
|
||||
tastes = list("salt" = 1, "crisps" = 1)
|
||||
foodtype = JUNKFOOD | FRIED
|
||||
custom_price = 90
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/no_raisin
|
||||
name = "4no raisins"
|
||||
@@ -69,7 +68,7 @@
|
||||
junkiness = 25
|
||||
filling_color = "#FFD700"
|
||||
foodtype = JUNKFOOD | GRAIN | SUGAR
|
||||
custom_price = 30
|
||||
custom_price = PRICE_CHEAP_AS_FREE
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/cheesiehonkers
|
||||
name = "cheesie honkers"
|
||||
@@ -81,7 +80,6 @@
|
||||
filling_color = "#FFD700"
|
||||
tastes = list("cheese" = 5, "crisps" = 2)
|
||||
foodtype = JUNKFOOD | DAIRY | SUGAR
|
||||
custom_price = 45
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/syndicake
|
||||
name = "syndi-cakes"
|
||||
@@ -92,3 +90,4 @@
|
||||
filling_color = "#F5F5DC"
|
||||
tastes = list("sweetness" = 3, "cake" = 1)
|
||||
foodtype = GRAIN | FRUIT | VEGETABLES
|
||||
custom_price = PRICE_CHEAP
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#define STORAGE_CAPACITY 30
|
||||
#define LIQUID_CAPACIY 200
|
||||
#define LIQUID_CAPACITY 200
|
||||
#define MIXER_CAPACITY 100
|
||||
|
||||
/obj/machinery/food_cart
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
/obj/machinery/food_cart/Initialize()
|
||||
. = ..()
|
||||
create_reagents(LIQUID_CAPACIY, OPENCONTAINER | NO_REACT)
|
||||
create_reagents(LIQUID_CAPACITY, OPENCONTAINER | NO_REACT)
|
||||
mixer = new /obj/item/reagent_containers(src, MIXER_CAPACITY)
|
||||
mixer.name = "Mixer"
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
return food_stored >= STORAGE_CAPACITY
|
||||
|
||||
/obj/machinery/food_cart/attackby(obj/item/O, mob/user, params)
|
||||
if(O.tool_behaviour == TOOL_WRENCH)
|
||||
default_unfasten_wrench(user, O, 0)
|
||||
return TRUE
|
||||
if(istype(O, /obj/item/reagent_containers/food/drinks/drinkingglass))
|
||||
var/obj/item/reagent_containers/food/drinks/drinkingglass/DG = O
|
||||
if(!DG.reagents.total_volume) //glass is empty
|
||||
@@ -106,7 +109,7 @@
|
||||
return
|
||||
|
||||
if(href_list["disposeI"])
|
||||
reagents.del_reagent(href_list["disposeI"])
|
||||
reagents.del_reagent(text2path(href_list["disposeI"]))
|
||||
|
||||
if(href_list["dispense"])
|
||||
if(stored_food[href_list["dispense"]]-- <= 0)
|
||||
@@ -116,9 +119,13 @@
|
||||
if(sanitize(O.name) == href_list["dispense"])
|
||||
O.forceMove(drop_location())
|
||||
break
|
||||
log_combat(usr, src, "dispensed [O] from", null, "with [stored_food[href_list["dispense"]]] remaining")
|
||||
|
||||
if(href_list["portion"])
|
||||
portion = clamp(input("How much drink do you want to dispense per glass?") as num, 0, 50)
|
||||
portion = clamp(input("How much drink do you want to dispense per glass?") as num|null, 0, 50)
|
||||
|
||||
if (isnull(portion))
|
||||
return
|
||||
|
||||
if(href_list["pour"] || href_list["m_pour"])
|
||||
if(glasses-- <= 0)
|
||||
@@ -127,16 +134,16 @@
|
||||
else
|
||||
var/obj/item/reagent_containers/food/drinks/drinkingglass/DG = new(loc)
|
||||
if(href_list["pour"])
|
||||
reagents.trans_id_to(DG, href_list["pour"], portion)
|
||||
reagents.trans_id_to(DG, text2path(href_list["pour"]), portion)
|
||||
if(href_list["m_pour"])
|
||||
mixer.reagents.trans_id_to(DG, href_list["m_pour"], portion)
|
||||
mixer.reagents.trans_id_to(DG, text2path(href_list["m_pour"]), portion)
|
||||
|
||||
if(href_list["mix"])
|
||||
if(reagents.trans_id_to(mixer, href_list["mix"], portion) == 0)
|
||||
if(reagents.trans_id_to(mixer, text2path(href_list["mix"]), portion) == 0)
|
||||
to_chat(usr, "<span class='warning'>[mixer] is full!</span>")
|
||||
|
||||
if(href_list["transfer"])
|
||||
if(mixer.reagents.trans_id_to(src, href_list["transfer"], portion) == 0)
|
||||
if(mixer.reagents.trans_id_to(src, text2path(href_list["transfer"]), portion) == 0)
|
||||
to_chat(usr, "<span class='warning'>[src] is full!</span>")
|
||||
|
||||
updateDialog()
|
||||
@@ -152,5 +159,5 @@
|
||||
qdel(src)
|
||||
|
||||
#undef STORAGE_CAPACITY
|
||||
#undef LIQUID_CAPACIY
|
||||
#undef LIQUID_CAPACITY
|
||||
#undef MIXER_CAPACITY
|
||||
|
||||
@@ -121,6 +121,15 @@ datum/crafting_recipe/food/donut/meat
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/donut/matcha
|
||||
|
||||
|
||||
/datum/crafting_recipe/food/donut/laugh
|
||||
name = "Sweet Pea Donut"
|
||||
reqs = list(
|
||||
/datum/reagent/consumable/laughsyrup = 3,
|
||||
/obj/item/reagent_containers/food/snacks/donut/plain = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/donut/laugh
|
||||
|
||||
////////////////////////////////////////////////////JELLY DONUTS///////////////////////////////////////////////////////
|
||||
|
||||
/datum/crafting_recipe/food/donut/jelly/apple
|
||||
@@ -187,6 +196,14 @@ datum/crafting_recipe/food/donut/meat
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/donut/jelly/trumpet
|
||||
|
||||
/datum/crafting_recipe/food/donut/jelly/laugh
|
||||
name = "Sweet Pea Jelly Donut"
|
||||
reqs = list(
|
||||
/datum/reagent/consumable/laughsyrup = 3,
|
||||
/obj/item/reagent_containers/food/snacks/donut/jelly/plain = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/donut/jelly/laugh
|
||||
|
||||
////////////////////////////////////////////////////SLIME DONUTS///////////////////////////////////////////////////////
|
||||
|
||||
/datum/crafting_recipe/food/donut/slimejelly/apple
|
||||
@@ -253,3 +270,11 @@ datum/crafting_recipe/food/donut/meat
|
||||
/obj/item/reagent_containers/food/snacks/donut/jelly/slimejelly/plain = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/donut/jelly/slimejelly/matcha
|
||||
|
||||
/datum/crafting_recipe/food/donut/slimejelly/laugh
|
||||
name = "Sweet Pea Jelly Donut"
|
||||
reqs = list(
|
||||
/datum/reagent/consumable/laughsyrup = 3,
|
||||
/obj/item/reagent_containers/food/snacks/donut/jelly/slimejelly/plain = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/donut/jelly/slimejelly/laugh
|
||||
|
||||
@@ -171,3 +171,14 @@
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/salad/ricepork
|
||||
subcategory = CAT_MEAT
|
||||
|
||||
/datum/crafting_recipe/food/gumbo
|
||||
name = "Black eyed gumbo"
|
||||
reqs = list(
|
||||
/obj/item/reagent_containers/food/snacks/salad/boiledrice = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/peas = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/chili = 1,
|
||||
/obj/item/reagent_containers/food/snacks/meat/cutlet = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/salad/gumbo
|
||||
subcategory = CAT_MEAT
|
||||
|
||||
@@ -194,3 +194,14 @@
|
||||
)
|
||||
result = /mob/living/simple_animal/hostile/bear/butter
|
||||
subcategory = CAT_MISCFOOD
|
||||
|
||||
/datum/crafting_recipe/food/royalcheese
|
||||
name = "Royal Cheese"
|
||||
reqs = list(
|
||||
/obj/item/reagent_containers/food/snacks/store/cheesewheel = 1,
|
||||
/obj/item/clothing/head/crown = 1,
|
||||
/datum/reagent/medicine/strange_reagent = 5,
|
||||
/datum/reagent/toxin/mutagen = 5
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/royalcheese
|
||||
subcategory = CAT_MISCFOOD
|
||||
@@ -93,4 +93,17 @@
|
||||
/obj/item/reagent_containers/food/snacks/grown/cabbage = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/salad/caesar
|
||||
subcategory = CAT_SALAD
|
||||
subcategory = CAT_SALAD
|
||||
|
||||
|
||||
/datum/crafting_recipe/food/edensalad
|
||||
name = "Salad of Eden"
|
||||
reqs = list(
|
||||
/obj/item/reagent_containers/glass/bowl =1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/ambrosia/vulgaris = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/ambrosia/deus = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/ambrosia/gaia = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/peace = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/salad/edensalad
|
||||
subcategory = CAT_SALAD
|
||||
|
||||
@@ -135,4 +135,14 @@
|
||||
/obj/item/reagent_containers/food/snacks/carpmeat = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/fishandchips
|
||||
subcategory = CAT_SEAFOOD
|
||||
subcategory = CAT_SEAFOOD
|
||||
|
||||
/datum/crafting_recipe/food/fishfry
|
||||
name = "Fish fry"
|
||||
reqs = list(
|
||||
/obj/item/reagent_containers/food/snacks/grown/corn = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/peas =1,
|
||||
/obj/item/reagent_containers/food/snacks/carpmeat = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/fishfry
|
||||
subcategory = CAT_SEAFOOD
|
||||
|
||||
@@ -255,4 +255,16 @@
|
||||
/obj/item/reagent_containers/glass/bowl = 1
|
||||
)
|
||||
result= /obj/item/reagent_containers/food/snacks/soup/wish
|
||||
subcategory = CAT_SOUP
|
||||
subcategory = CAT_SOUP
|
||||
|
||||
|
||||
/datum/crafting_recipe/food/peasoup
|
||||
name = "Pea soup"
|
||||
reqs = list(
|
||||
/datum/reagent/water = 10,
|
||||
/obj/item/reagent_containers/food/snacks/grown/peas = 2,
|
||||
/obj/item/reagent_containers/food/snacks/grown/parsnip = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/carrot = 1
|
||||
)
|
||||
result = /obj/item/reagent_containers/food/snacks/soup/peasoup
|
||||
subcategory = CAT_SOUP
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
/obj/item/t_scanner = 5,
|
||||
/obj/item/airlock_painter = 1,
|
||||
/obj/item/stack/cable_coil = 6,
|
||||
/obj/item/stack/medical/bruise_pack = 1,
|
||||
/obj/item/stack/medical/suture = 1,
|
||||
/obj/item/stack/rods = 3,
|
||||
/obj/item/stack/sheet/cardboard = 2,
|
||||
/obj/item/stack/sheet/metal = 1,
|
||||
|
||||
@@ -189,6 +189,14 @@
|
||||
begin_day = 22
|
||||
begin_month = APRIL
|
||||
|
||||
/datum/holiday/lesbianvisibility
|
||||
name = "Lesbian Visibility Day"
|
||||
begin_day = 26
|
||||
begin_month = APRIL
|
||||
|
||||
/datum/holiday/lesbianvisibility/greet()
|
||||
return "Today is Lesbian Visibility Day!"
|
||||
|
||||
/datum/holiday/labor
|
||||
name = "Labor Day"
|
||||
begin_day = 1
|
||||
@@ -292,6 +300,14 @@
|
||||
/datum/holiday/programmers/getStationPrefix()
|
||||
return pick("span>","DEBUG: ","null","/list","EVENT PREFIX NOT FOUND") //Portability
|
||||
|
||||
/datum/holiday/bivisibility
|
||||
name = "Bisexual Visibility Day"
|
||||
begin_day = 23
|
||||
begin_month = SEPTEMBER
|
||||
|
||||
/datum/holiday/bivisibility/greet()
|
||||
return "Today is Bisexual Visibility Day!"
|
||||
|
||||
/datum/holiday/questions
|
||||
name = "Stupid-Questions Day"
|
||||
begin_day = 28
|
||||
@@ -314,12 +330,25 @@
|
||||
begin_month = OCTOBER
|
||||
drone_hat = /obj/item/clothing/head/papersack/smiley
|
||||
|
||||
/datum/holiday/comingoutday
|
||||
name = "Coming Out Day"
|
||||
begin_day = 11
|
||||
begin_month = OCTOBER
|
||||
|
||||
/datum/holiday/boss
|
||||
name = "Boss' Day"
|
||||
begin_day = 16
|
||||
begin_month = OCTOBER
|
||||
drone_hat = /obj/item/clothing/head/that
|
||||
|
||||
/datum/holiday/intersexawareness
|
||||
name = "Intersex Awareness Day"
|
||||
begin_day = 26
|
||||
begin_month = OCTOBER
|
||||
|
||||
/datum/holiday/intersexawareness/greet()
|
||||
return "Today is Intersex Awareness Day! It has been [text2num(time2text(world.timeofday, "YYYY")) - 1996] years since the first public protest speaking out against the human rights issues faced by intersex people."
|
||||
|
||||
/datum/holiday/halloween
|
||||
name = HALLOWEEN
|
||||
begin_day = 28
|
||||
@@ -359,6 +388,23 @@
|
||||
begin_month = NOVEMBER
|
||||
drone_hat = /obj/item/reagent_containers/food/snacks/grown/moonflower
|
||||
|
||||
/datum/holiday/transawareness
|
||||
name = "Transgender Awareness Week"
|
||||
begin_day = 13
|
||||
begin_month = NOVEMBER
|
||||
end_day = 19
|
||||
|
||||
/datum/holiday/transawareness/greet()
|
||||
return "This week is Transgender Awareness Week!"
|
||||
|
||||
/datum/holiday/transremembrance
|
||||
name = "Transgender Day of Remembrance"
|
||||
begin_day = 20
|
||||
begin_month = NOVEMBER
|
||||
|
||||
/datum/holiday/transremembrance/greet()
|
||||
return "Today is the Transgender Day of Remembrance."
|
||||
|
||||
/datum/holiday/hello
|
||||
name = "Saying-'Hello' Day"
|
||||
begin_day = 21
|
||||
@@ -397,6 +443,26 @@
|
||||
begin_month = OCTOBER
|
||||
begin_weekday = MONDAY
|
||||
|
||||
/datum/holiday/aceawareness
|
||||
name = "Asexual Awareness Week"
|
||||
begin_month = OCTOBER
|
||||
|
||||
/datum/holiday/aceawareness/greet()
|
||||
return "This week is Asexual Awareness Week!"
|
||||
|
||||
/datum/holiday/aceawareness/shouldCelebrate(dd, mm, yy, ww, ddd) //Ace awareness week falls on the last full week of October.
|
||||
if(mm != begin_month)
|
||||
return FALSE //it's not even the right month
|
||||
var/daypointer = world.timeofday - ((WEEKDAY2NUM(ddd) - 1) * 24 HOURS)
|
||||
if(text2num(time2text(daypointer, "MM")) != mm)
|
||||
return FALSE //it's the beginning of the month and it isn't even a full week
|
||||
daypointer += (24 HOURS * 6)
|
||||
if(text2num(time2text(daypointer, "MM")) != mm)
|
||||
return FALSE //this is the end of the month, and it is not a full week.
|
||||
daypointer += (24 HOURS * 7)
|
||||
if(text2num(time2text(daypointer, "MM")) != mm)
|
||||
return TRUE //the end of next week falls on a different month, meaning that the current week is the last full week
|
||||
|
||||
/datum/holiday/mother
|
||||
name = "Mother's Day"
|
||||
begin_week = 2
|
||||
@@ -412,11 +478,39 @@
|
||||
begin_month = JUNE
|
||||
begin_weekday = SUNDAY
|
||||
|
||||
/datum/holiday/pride
|
||||
name = PRIDE_MONTH
|
||||
begin_day = 1
|
||||
begin_month = JUNE
|
||||
end_day = 30
|
||||
|
||||
/datum/holiday/pride/getStationPrefix()
|
||||
return pick("Pride", "Gay", "Bi", "Trans", "Lesbian", "Ace", "Aro", "Agender", pick("Enby", "Enbie"), "Pan", "Intersex", "Demi", "Poly", "Closeted", "Genderfluid")
|
||||
|
||||
/datum/holiday/stonewall
|
||||
name = "Stonewall Riots Anniversary"
|
||||
begin_day = 28
|
||||
begin_month = JUNE
|
||||
|
||||
/datum/holiday/stonewall/greet() //Not gonna lie, I was fairly tempted to make this use the IC year instead of the IRL year, but I was worried that it would have caused too much confusion.
|
||||
return "Today marks the [text2num(time2text(world.timeofday, "YYYY")) - 1969]\th anniversary of the riots at the Stonewall Inn!"
|
||||
|
||||
/datum/holiday/moth
|
||||
name = "Moth Week"
|
||||
begin_month = JULY
|
||||
|
||||
/datum/holiday/moth/shouldCelebrate(dd, mm, yy, ww, ddd) //National Moth Week falls on the last full week of July
|
||||
return mm == JULY && (ww == 4 || (ww == 5 && ddd == SUNDAY))
|
||||
if(mm != begin_month)
|
||||
return FALSE //it's not even the right month
|
||||
var/daypointer = world.timeofday - ((WEEKDAY2NUM(ddd) - 1) * 24 HOURS)
|
||||
if(text2num(time2text(daypointer, "MM")) != mm)
|
||||
return FALSE //it's the beginning of the month and it isn't even a full week
|
||||
daypointer += (24 HOURS * 6)
|
||||
if(text2num(time2text(daypointer, "MM")) != mm)
|
||||
return FALSE //this is the end of the month, and it is not a full week.
|
||||
daypointer += (24 HOURS * 7)
|
||||
if(text2num(time2text(daypointer, "MM")) != mm)
|
||||
return TRUE //the end of next week falls on a different month, meaning that the current week is the last full week
|
||||
|
||||
/datum/holiday/moth/getStationPrefix()
|
||||
return pick("Mothball","Lepidopteran","Lightbulb","Moth","Giant Atlas","Twin-spotted Sphynx","Madagascan Sunset","Luna","Death's Head","Emperor Gum","Polyphenus","Oleander Hawk","Io","Rosy Maple","Cecropia","Noctuidae","Giant Leopard","Dysphania Militaris","Garden Tiger")
|
||||
|
||||
@@ -40,9 +40,6 @@
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
/obj/item/holo/esword/attack(target as mob, mob/user as mob)
|
||||
..()
|
||||
|
||||
/obj/item/holo/esword/Initialize()
|
||||
. = ..()
|
||||
saber_color = pick("red","blue","green","purple")
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
/obj/item/instrument/dropped(mob/user)
|
||||
. = ..()
|
||||
if((loc != user) && (user.machine == src))
|
||||
user.set_machine(null)
|
||||
user.unset_machine()
|
||||
|
||||
/obj/item/instrument/interact(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
/obj/structure/musician/ui_interact(mob/user)
|
||||
. = ..()
|
||||
user.set_machine(src)
|
||||
song.ui_interact(user)
|
||||
|
||||
/obj/structure/musician/wrench_act(mob/living/user, obj/item/I)
|
||||
|
||||
@@ -223,8 +223,6 @@
|
||||
|
||||
/// Updates the window for our user. Override in subtypes.
|
||||
/datum/song/proc/updateDialog(mob/user = usr)
|
||||
if(user.machine != src)
|
||||
return
|
||||
ui_interact(user)
|
||||
|
||||
/datum/song/process(wait)
|
||||
|
||||
@@ -35,12 +35,9 @@ Assistant
|
||||
..()
|
||||
var/suited = !preference_source || preference_source.prefs.jumpsuit_style == PREF_SUIT
|
||||
if (CONFIG_GET(flag/grey_assistants))
|
||||
if(suited)
|
||||
uniform = /obj/item/clothing/under/color/grey
|
||||
else
|
||||
uniform = /obj/item/clothing/under/color/jumpskirt/grey
|
||||
uniform = suited ? /obj/item/clothing/under/color/grey : /obj/item/clothing/under/color/jumpskirt/grey
|
||||
else
|
||||
if(suited)
|
||||
uniform = /obj/item/clothing/under/color/random
|
||||
if(SSevents.holidays && SSevents.holidays[PRIDE_MONTH])
|
||||
uniform = suited ? /obj/item/clothing/under/color/rainbow : /obj/item/clothing/under/color/jumpskirt/rainbow
|
||||
else
|
||||
uniform = /obj/item/clothing/under/color/jumpskirt/random
|
||||
uniform = suited ? /obj/item/clothing/under/color/random : /obj/item/clothing/under/color/jumpskirt/random
|
||||
|
||||
@@ -59,6 +59,11 @@
|
||||
else
|
||||
full_key = "[AltMod][CtrlMod][ShiftMod][_key]"
|
||||
var/keycount = 0
|
||||
if(prefs.modless_key_bindings[_key])
|
||||
var/datum/keybinding/kb = GLOB.keybindings_by_name[prefs.modless_key_bindings[_key]]
|
||||
if(kb.can_use(src))
|
||||
kb.down(src)
|
||||
keycount++
|
||||
for(var/kb_name in prefs.key_bindings[full_key])
|
||||
keycount++
|
||||
var/datum/keybinding/kb = GLOB.keybindings_by_name[kb_name]
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define CATEGORY_MISC "MISC"
|
||||
#define CATEGORY_MOVEMENT "MOVEMENT"
|
||||
#define CATEGORY_TARGETING "TARGETING"
|
||||
#define CATEGORY_COMBAT "COMBAT"
|
||||
|
||||
#define WEIGHT_HIGHEST 0
|
||||
#define WEIGHT_ADMIN 10
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/datum/keybinding/living/toggle_combat_mode
|
||||
hotkey_keys = list("C")
|
||||
name = "toggle_combat_mode"
|
||||
full_name = "Toggle combat mode"
|
||||
category = CATEGORY_COMBAT
|
||||
description = "Toggles whether or not you're in combat mode."
|
||||
|
||||
/datum/keybinding/living/toggle_combat_mode/down(client/user)
|
||||
SEND_SIGNAL(user.mob, COMSIG_TOGGLE_COMBAT_MODE)
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/living/active_block
|
||||
hotkey_keys = list("Northwest", "F") // HOME
|
||||
name = "active_block"
|
||||
full_name = "Block (Hold)"
|
||||
category = CATEGORY_COMBAT
|
||||
description = "Hold down to actively block with your currently in-hand object."
|
||||
|
||||
/datum/keybinding/living/active_block/down(client/user)
|
||||
var/mob/living/L = user.mob
|
||||
L.keybind_start_active_blocking()
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/living/active_block/up(client/user)
|
||||
var/mob/living/L = user.mob
|
||||
L.keybind_stop_active_blocking()
|
||||
|
||||
/datum/keybinding/living/active_parry
|
||||
hotkey_keys = list("Insert", "G")
|
||||
name = "active_parry"
|
||||
full_name = "Parry"
|
||||
category = CATEGORY_COMBAT
|
||||
description = "Press to initiate a parry sequence with your currently in-hand object."
|
||||
|
||||
/datum/keybinding/living/active_parry/down(client/user)
|
||||
var/mob/living/L = user.mob
|
||||
L.keybind_parry()
|
||||
return TRUE
|
||||
@@ -16,16 +16,6 @@
|
||||
L.resist()
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/living/toggle_combat_mode
|
||||
hotkey_keys = list("C")
|
||||
name = "toggle_combat_mode"
|
||||
full_name = "Toggle combat mode"
|
||||
description = "Toggles whether or not you're in combat mode."
|
||||
|
||||
/datum/keybinding/living/toggle_combat_mode/down(client/user)
|
||||
SEND_SIGNAL(user.mob, COMSIG_TOGGLE_COMBAT_MODE)
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/living/toggle_resting
|
||||
hotkey_keys = list("V")
|
||||
name = "toggle_resting"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/mob/cycle_intent_right
|
||||
hotkey_keys = list("Northwest", "F") // HOME
|
||||
hotkey_keys = list("Unbound")
|
||||
name = "cycle_intent_right"
|
||||
full_name = "Cycle Action Intent Right"
|
||||
description = ""
|
||||
@@ -28,7 +28,7 @@
|
||||
return TRUE
|
||||
|
||||
/datum/keybinding/mob/cycle_intent_left
|
||||
hotkey_keys = list("Insert", "G")
|
||||
hotkey_keys = list("Unbound")
|
||||
name = "cycle_intent_left"
|
||||
full_name = "Cycle Action Intent Left"
|
||||
description = ""
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
plane = EMISSIVE_BLOCKER_PLANE
|
||||
layer = EMISSIVE_BLOCKER_LAYER
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
rad_flags = RAD_NO_CONTAMINATE | RAD_PROTECT_CONTENTS
|
||||
//Why?
|
||||
//render_targets copy the transform of the target as well, but vis_contents also applies the transform
|
||||
//to what's in it. Applying RESET_TRANSFORM here makes vis_contents not apply the transform.
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
var/turf/pixel_turf // The turf the top_atom appears to over.
|
||||
var/light_power // Intensity of the emitter light.
|
||||
var/light_range // The range of the emitted light.
|
||||
var/light_color // The colour of the light, string, decomposed by parse_light_color()
|
||||
var/light_color // The colour of the light, string, decomposed by PARSE_LIGHT_COLOR()
|
||||
|
||||
// Variables for keeping track of the colour.
|
||||
var/lum_r
|
||||
@@ -48,12 +48,10 @@
|
||||
light_range = source_atom.light_range
|
||||
light_color = source_atom.light_color
|
||||
|
||||
parse_light_color()
|
||||
PARSE_LIGHT_COLOR(src)
|
||||
|
||||
update()
|
||||
|
||||
return ..()
|
||||
|
||||
/datum/light_source/Destroy(force)
|
||||
remove_lum()
|
||||
if (source_atom)
|
||||
@@ -99,17 +97,6 @@
|
||||
/datum/light_source/proc/vis_update()
|
||||
EFFECT_UPDATE(LIGHTING_VIS_UPDATE)
|
||||
|
||||
// Decompile the hexadecimal colour into lumcounts of each perspective.
|
||||
/datum/light_source/proc/parse_light_color()
|
||||
if (light_color)
|
||||
lum_r = GetRedPart (light_color) / 255
|
||||
lum_g = GetGreenPart (light_color) / 255
|
||||
lum_b = GetBluePart (light_color) / 255
|
||||
else
|
||||
lum_r = 1
|
||||
lum_g = 1
|
||||
lum_b = 1
|
||||
|
||||
// Macro that applies light to a new corner.
|
||||
// It is a macro in the interest of speed, yet not having to copy paste it.
|
||||
// If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line.
|
||||
@@ -224,7 +211,7 @@
|
||||
|
||||
if (source_atom.light_color != light_color)
|
||||
light_color = source_atom.light_color
|
||||
parse_light_color()
|
||||
PARSE_LIGHT_COLOR(src)
|
||||
update = TRUE
|
||||
|
||||
else if (applied_lum_r != lum_r || applied_lum_g != lum_g || applied_lum_b != lum_b)
|
||||
@@ -241,17 +228,16 @@
|
||||
var/list/turf/turfs = list()
|
||||
var/thing
|
||||
var/turf/T
|
||||
|
||||
if (source_turf)
|
||||
var/oldlum = source_turf.luminosity
|
||||
source_turf.luminosity = CEILING(light_range, 1)
|
||||
for(T in view(CEILING(light_range, 1), source_turf))
|
||||
turfs += T
|
||||
if(!IS_DYNAMIC_LIGHTING(T) && !T.light_sources)
|
||||
if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources) || T.has_opaque_atom )
|
||||
continue
|
||||
if(!T.lighting_corners_initialised)
|
||||
T.generate_missing_corners()
|
||||
if(T.has_opaque_atom)
|
||||
continue
|
||||
corners[T.lc_topright] = 0
|
||||
corners[T.lc_bottomright] = 0
|
||||
corners[T.lc_bottomleft] = 0
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
new /obj/item/gun/magic/wand/book/spark(src)
|
||||
|
||||
/obj/structure/closet/crate/necropolis/tendril/misc/PopulateContents()
|
||||
var/loot = rand(1,10)
|
||||
var/loot = rand(1,11)
|
||||
switch(loot)
|
||||
if(1)
|
||||
new /obj/item/shared_storage/red(src)
|
||||
@@ -102,7 +102,11 @@
|
||||
if(10)
|
||||
new /obj/item/bedsheet/cosmos(src)
|
||||
new /obj/item/melee/skateboard/hoverboard(src)
|
||||
|
||||
if(11)
|
||||
if(prob(50))
|
||||
new /obj/item/malf_upgrade
|
||||
else
|
||||
new /obj/item/disk/tech_disk/illegal
|
||||
|
||||
//KA modkit design discs
|
||||
/obj/item/disk/design_disk/modkit_disc
|
||||
|
||||
@@ -176,9 +176,6 @@
|
||||
SSticker.queue_delay = 4
|
||||
qdel(src)
|
||||
|
||||
if(!ready && href_list["preference"])
|
||||
if(client)
|
||||
client.prefs.process_link(src, href_list)
|
||||
else if(!href_list["late_join"])
|
||||
new_player_panel()
|
||||
|
||||
@@ -582,6 +579,12 @@
|
||||
qdel(src)
|
||||
|
||||
/mob/dead/new_player/proc/ViewManifest()
|
||||
if(!client)
|
||||
return
|
||||
if(world.time < client.crew_manifest_delay)
|
||||
return
|
||||
client.crew_manifest_delay = world.time + (1 SECONDS)
|
||||
|
||||
var/dat = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'></head><body>"
|
||||
dat += "<h4>Crew Manifest</h4>"
|
||||
dat += GLOB.data_core.get_manifest(OOC = 1)
|
||||
|
||||
@@ -189,6 +189,26 @@
|
||||
name = "Coffee House"
|
||||
icon_state = "hair_coffeehouse"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrows1
|
||||
name = "Cornrows"
|
||||
icon_state = "hair_cornrows"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrows2
|
||||
name = "Cornrows 2"
|
||||
icon_state = "hair_cornrows2"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrowbun
|
||||
name = "Cornrow Bun"
|
||||
icon_state = "hair_cornrowbun"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrowbraid
|
||||
name = "Cornrow Braid"
|
||||
icon_state = "hair_cornrowbraid"
|
||||
|
||||
/datum/sprite_accessory/hair/cornrowdualtail
|
||||
name = "Cornrow Tail"
|
||||
icon_state = "hair_cornrowtail"
|
||||
|
||||
/datum/sprite_accessory/hair/country
|
||||
name = "Country"
|
||||
icon_state = "hair_country"
|
||||
|
||||
@@ -717,6 +717,12 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
set name = "View Crew Manifest"
|
||||
set category = "Ghost"
|
||||
|
||||
if(!client)
|
||||
return
|
||||
if(world.time < client.crew_manifest_delay)
|
||||
return
|
||||
client.crew_manifest_delay = world.time + (1 SECONDS)
|
||||
|
||||
var/dat
|
||||
dat += "<h4>Crew Manifest</h4>"
|
||||
dat += GLOB.data_core.get_manifest()
|
||||
|
||||
@@ -333,6 +333,7 @@
|
||||
I.moveToNullspace()
|
||||
else
|
||||
I.forceMove(newloc)
|
||||
on_item_dropped(I)
|
||||
if(I.dropped(src) == ITEM_RELOCATED_BY_DROPPED)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -77,20 +77,18 @@
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/alien/humanoid/get_standard_pixel_y_offset(lying = 0)
|
||||
. = ..()
|
||||
if(leaping)
|
||||
return -32
|
||||
else if(custom_pixel_y_offset)
|
||||
return custom_pixel_y_offset
|
||||
else
|
||||
return initial(pixel_y)
|
||||
. -= 32
|
||||
if(custom_pixel_y_offset)
|
||||
. += custom_pixel_y_offset
|
||||
|
||||
/mob/living/carbon/alien/humanoid/get_standard_pixel_x_offset(lying = 0)
|
||||
. = ..()
|
||||
if(leaping)
|
||||
return -32
|
||||
else if(custom_pixel_x_offset)
|
||||
return custom_pixel_x_offset
|
||||
else
|
||||
return initial(pixel_x)
|
||||
. -= 32
|
||||
if(custom_pixel_x_offset)
|
||||
. += custom_pixel_x_offset
|
||||
|
||||
/mob/living/carbon/alien/humanoid/get_permeability_protection(list/target_zones)
|
||||
return 0.8
|
||||
|
||||
@@ -432,10 +432,9 @@
|
||||
return
|
||||
|
||||
/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
|
||||
. = ..()
|
||||
if(lying)
|
||||
return -6
|
||||
else
|
||||
return initial(pixel_y)
|
||||
. -= 6
|
||||
|
||||
/mob/living/carbon/proc/accident(obj/item/I)
|
||||
if(!I || (I.item_flags & ABSTRACT) || HAS_TRAIT(I, TRAIT_NODROP))
|
||||
|
||||
@@ -76,11 +76,13 @@
|
||||
visible_message("<span class='danger'>[I] embeds itself in [src]'s [L.name]!</span>","<span class='userdanger'>[I] embeds itself in your [L.name]!</span>")
|
||||
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
|
||||
|
||||
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
|
||||
var/totitemdamage = pre_attacked_by(I, user)
|
||||
/mob/living/carbon/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
var/totitemdamage = pre_attacked_by(I, user) * damage_multiplier
|
||||
var/impacting_zone = (user == src)? check_zone(user.zone_selected) : ran_zone(user.zone_selected)
|
||||
if((user != src) && (mob_run_block(I, totitemdamage, "the [I]", ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone, null) & BLOCK_SUCCESS))
|
||||
var/list/block_return = list()
|
||||
if((user != src) && (mob_run_block(I, totitemdamage, "the [I]", ((attackchain_flags & ATTACKCHAIN_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, impacting_zone, block_return) & BLOCK_SUCCESS))
|
||||
return FALSE
|
||||
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
|
||||
var/obj/item/bodypart/affecting = get_bodypart(impacting_zone)
|
||||
if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest)
|
||||
affecting = bodyparts[1]
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
if(istype(J) && (movement_dir || J.stabilizers) && J.allow_thrust(0.01, src))
|
||||
return 1
|
||||
|
||||
/mob/living/carbon/Move(NewLoc, direct)
|
||||
/mob/living/carbon/Moved()
|
||||
. = ..()
|
||||
if(. && (movement_type & FLOATING)) //floating is easy
|
||||
if(HAS_TRAIT(src, TRAIT_NOHUNGER))
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/mob/living/carbon/human/get_blocking_items()
|
||||
. = ..()
|
||||
if(wear_suit)
|
||||
. |= wear_suit
|
||||
if(!.[wear_suit])
|
||||
.[wear_suit] = wear_suit.block_priority
|
||||
if(w_uniform)
|
||||
. |= w_uniform
|
||||
if(!.[w_uniform])
|
||||
.[w_uniform] = w_uniform.block_priority
|
||||
if(wear_neck)
|
||||
. |= wear_neck
|
||||
if(!.[wear_neck])
|
||||
.[wear_neck] = wear_neck.block_priority
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
..()
|
||||
|
||||
|
||||
/mob/living/carbon/human/attacked_by(obj/item/I, mob/living/user)
|
||||
/mob/living/carbon/human/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
if(!I || !user)
|
||||
return 0
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
SSblackbox.record_feedback("tally", "zone_targeted", 1, target_area)
|
||||
|
||||
// the attacked_by code varies among species
|
||||
return dna.species.spec_attacked_by(I, user, affecting, a_intent, src)
|
||||
return dna.species.spec_attacked_by(I, user, affecting, a_intent, src, attackchain_flags, damage_multiplier)
|
||||
|
||||
/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
@@ -214,7 +214,7 @@
|
||||
/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
var/damage = .
|
||||
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
if(!dam_zone) //Dismemberment successful
|
||||
return TRUE
|
||||
|
||||
@@ -1700,12 +1700,14 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
if("disarm")
|
||||
disarm(M, H, attacker_style)
|
||||
|
||||
/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
|
||||
var/totitemdamage = H.pre_attacked_by(I, user)
|
||||
/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H, attackchain_flags = NONE, damage_multiplier = 1)
|
||||
var/totitemdamage = H.pre_attacked_by(I, user) * damage_multiplier
|
||||
// Allows you to put in item-specific reactions based on species
|
||||
if(user != H)
|
||||
if(H.mob_run_block(I, totitemdamage, "the [I.name]", ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone, null) & BLOCK_SUCCESS)
|
||||
var/list/block_return = list()
|
||||
if(H.mob_run_block(I, totitemdamage, "the [I.name]", ((attackchain_flags & ATTACKCHAIN_PARRY_COUNTERATTACK)? ATTACK_TYPE_PARRY_COUNTERATTACK : NONE) | ATTACK_TYPE_MELEE, I.armour_penetration, user, affecting.body_zone, block_return) & BLOCK_SUCCESS)
|
||||
return 0
|
||||
totitemdamage = block_calculate_resultant_damage(totitemdamage, block_return)
|
||||
if(H.check_martial_melee_block())
|
||||
H.visible_message("<span class='warning'>[H] blocks [I]!</span>")
|
||||
return 0
|
||||
@@ -1720,6 +1722,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/armor_block = H.run_armor_check(affecting, "melee", "<span class='notice'>Your armor has protected your [hit_area].</span>", "<span class='notice'>Your armor has softened a hit to your [hit_area].</span>",I.armour_penetration)
|
||||
armor_block = min(90,armor_block) //cap damage reduction at 90%
|
||||
var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
|
||||
|
||||
var/weakness = H.check_weakness(I, user)
|
||||
apply_damage(totitemdamage * weakness, I.damtype, def_zone, armor_block, H) //CIT CHANGE - replaces I.force with totitemdamage
|
||||
|
||||
|
||||
@@ -280,25 +280,15 @@
|
||||
. = ..()
|
||||
C.faction |= "plants"
|
||||
C.faction |= "vines"
|
||||
C.AddElement(/datum/element/photosynthesis)
|
||||
|
||||
/datum/species/golem/wood/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.faction -= "plants"
|
||||
C.faction -= "vines"
|
||||
C.RemoveElement(/datum/element/photosynthesis)
|
||||
|
||||
/datum/species/golem/wood/spec_life(mob/living/carbon/human/H)
|
||||
if(H.stat == DEAD)
|
||||
return
|
||||
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
|
||||
if(isturf(H.loc)) //else, there's considered to be no light
|
||||
var/turf/T = H.loc
|
||||
light_amount = min(1,T.get_lumcount()) - 0.5
|
||||
H.adjust_nutrition(light_amount * 4, NUTRITION_LEVEL_FULL)
|
||||
if(light_amount > 0.2) //if there's enough light, heal
|
||||
H.heal_overall_damage(1,1)
|
||||
H.adjustToxLoss(-1)
|
||||
H.adjustOxyLoss(-1)
|
||||
|
||||
if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
|
||||
H.take_overall_damage(2,0)
|
||||
|
||||
|
||||
@@ -459,8 +459,18 @@
|
||||
|
||||
/datum/action/innate/slime_change/proc/change_form()
|
||||
var/mob/living/carbon/human/H = owner
|
||||
var/select_alteration = input(owner, "Select what part of your form to alter", "Form Alteration", "cancel") in list("Hair Style", "Genitals", "Tail", "Snout", "Markings", "Ears", "Taur body", "Penis", "Vagina", "Penis Length", "Breast Size", "Breast Shape", "Cancel")
|
||||
if(select_alteration == "Hair Style")
|
||||
var/select_alteration = input(owner, "Select what part of your form to alter", "Form Alteration", "cancel") in list("Body Color","Hair Style", "Genitals", "Tail", "Snout", "Markings", "Ears", "Taur body", "Penis", "Vagina", "Penis Length", "Breast Size", "Breast Shape", "Cancel")
|
||||
|
||||
if(select_alteration == "Body Color")
|
||||
var/new_color = input(owner, "Choose your skin color:", "Race change","#"+H.dna.features["mcolor"]) as color|null
|
||||
if(new_color)
|
||||
var/temp_hsv = RGBtoHSV(new_color)
|
||||
if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright
|
||||
H.dna.features["mcolor"] = sanitize_hexcolor(new_color)
|
||||
H.update_body()
|
||||
else
|
||||
to_chat(H, "<span class='notice'>Invalid color. Your color is not bright enough.</span>")
|
||||
else if(select_alteration == "Hair Style")
|
||||
if(H.gender == MALE)
|
||||
var/new_style = input(owner, "Select a facial hair style", "Hair Alterations") as null|anything in GLOB.facial_hair_styles_list
|
||||
if(new_style)
|
||||
|
||||
@@ -14,34 +14,24 @@
|
||||
liked_food = VEGETABLES | FRUIT | GRAIN
|
||||
species_language_holder = /datum/language_holder/sylvan
|
||||
var/light_nutrition_gain_factor = 4
|
||||
var/light_toxheal = 1
|
||||
var/light_oxyheal = 1
|
||||
var/light_burnheal = 1
|
||||
var/light_bruteheal = 1
|
||||
var/light_toxheal = -1
|
||||
var/light_oxyheal = -1
|
||||
var/light_burnheal = -1
|
||||
var/light_bruteheal = -1
|
||||
|
||||
/datum/species/pod/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
C.faction |= "plants"
|
||||
C.faction |= "vines"
|
||||
C.AddElement(/datum/element/photosynthesis, light_bruteheal, light_burnheal, light_toxheal, light_oxyheal, light_nutrition_gain_factor)
|
||||
|
||||
/datum/species/pod/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.faction -= "plants"
|
||||
C.faction -= "vines"
|
||||
C.RemoveElement(/datum/element/photosynthesis, light_bruteheal, light_burnheal, light_toxheal, light_oxyheal, light_nutrition_gain_factor)
|
||||
|
||||
/datum/species/pod/spec_life(mob/living/carbon/human/H)
|
||||
if(H.stat == DEAD)
|
||||
return
|
||||
var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
|
||||
if(isturf(H.loc)) //else, there's considered to be no light
|
||||
var/turf/T = H.loc
|
||||
light_amount = min(1,T.get_lumcount()) - 0.5
|
||||
H.adjust_nutrition(light_amount * light_nutrition_gain_factor, NUTRITION_LEVEL_FULL)
|
||||
if(light_amount > 0.2) //if there's enough light, heal
|
||||
H.heal_overall_damage(light_bruteheal, light_burnheal)
|
||||
H.adjustToxLoss(-light_toxheal)
|
||||
H.adjustOxyLoss(-light_oxyheal)
|
||||
|
||||
if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
|
||||
H.take_overall_damage(2,0)
|
||||
|
||||
@@ -77,9 +67,9 @@
|
||||
mutant_bodyparts = list("mcolor" = "FFF","mcolor2" = "FFF","mcolor3" = "FFF", "mam_snouts" = "Husky", "mam_tail" = "Husky", "mam_ears" = "Husky", "mam_body_markings" = "Husky", "taur" = "None", "legs" = "Normal Legs")
|
||||
limbs_id = "pod"
|
||||
light_nutrition_gain_factor = 3
|
||||
light_bruteheal = 0.2
|
||||
light_burnheal = 0.2
|
||||
light_toxheal = 0.7
|
||||
light_bruteheal = -0.2
|
||||
light_burnheal = -0.2
|
||||
light_toxheal = -0.7
|
||||
|
||||
/datum/species/pod/pseudo_weak/spec_death(gibbed, mob/living/carbon/human/H)
|
||||
if(H)
|
||||
|
||||
@@ -15,16 +15,13 @@
|
||||
dangerous_existence = 1
|
||||
mutanteyes = /obj/item/organ/eyes/night_vision
|
||||
|
||||
/datum/species/shadow/on_species_gain(mob/living/carbon/C, datum/species/old_species)
|
||||
. = ..()
|
||||
C.AddElement(/datum/element/photosynthesis, 1, 1, 0, 0, 0, 0, SHADOW_SPECIES_LIGHT_THRESHOLD, SHADOW_SPECIES_LIGHT_THRESHOLD)
|
||||
|
||||
/datum/species/shadow/spec_life(mob/living/carbon/human/H)
|
||||
var/turf/T = H.loc
|
||||
if(istype(T))
|
||||
var/light_amount = T.get_lumcount()
|
||||
|
||||
if(light_amount > SHADOW_SPECIES_LIGHT_THRESHOLD) //if there's enough light, start dying
|
||||
H.take_overall_damage(1,1)
|
||||
else if (light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD) //heal in the dark
|
||||
H.heal_overall_damage(1,1)
|
||||
/datum/species/shadow/on_species_loss(mob/living/carbon/C)
|
||||
. = ..()
|
||||
C.RemoveElement(/datum/element/photosynthesis, 1, 1, 0, 0, 0, 0, SHADOW_SPECIES_LIGHT_THRESHOLD, SHADOW_SPECIES_LIGHT_THRESHOLD)
|
||||
|
||||
/datum/species/shadow/check_roundstart_eligible()
|
||||
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
/mob/living/carbon/monkey/attack_animal(mob/living/simple_animal/M)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
|
||||
var/damage = .
|
||||
var/dam_zone = dismembering_strike(M, pick(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
|
||||
if(!dam_zone) //Dismemberment successful
|
||||
return TRUE
|
||||
|
||||
@@ -78,8 +78,6 @@
|
||||
apply_damage(brain, BRAIN, def_zone, blocked)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
/mob/living/proc/apply_effect(effect = 0,effecttype = EFFECT_STUN, blocked = FALSE, knockdown_stamoverride, knockdown_stammax)
|
||||
var/hit_percent = (100-blocked)/100
|
||||
if(!effect || (hit_percent <= 0))
|
||||
@@ -108,7 +106,7 @@
|
||||
return 1
|
||||
|
||||
|
||||
/mob/living/proc/apply_effects(stun = 0, knockdown = 0, unconscious = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = FALSE, stamina = 0, jitter = 0, kd_stamoverride, kd_stammax)
|
||||
/mob/living/proc/apply_effects(stun = 0, knockdown = 0, unconscious = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = 0, stamina = 0, jitter = 0, kd_stamoverride, kd_stammax)
|
||||
if(blocked >= 100)
|
||||
return BULLET_ACT_BLOCK
|
||||
if(stun)
|
||||
|
||||
@@ -64,6 +64,8 @@
|
||||
|
||||
handle_gravity()
|
||||
|
||||
handle_block_parry(seconds)
|
||||
|
||||
if(machine)
|
||||
machine.check_eye(src)
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
med_hud_set_status()
|
||||
|
||||
/mob/living/Destroy()
|
||||
end_parry_sequence()
|
||||
stop_active_blocking()
|
||||
if(LAZYLEN(status_effects))
|
||||
for(var/s in status_effects)
|
||||
var/datum/status_effect/S = s
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
// Active directional block system. Shared code is in [living_blocking_parrying.dm]
|
||||
/mob/living/proc/stop_active_blocking(was_forced = FALSE)
|
||||
if(!(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING)))
|
||||
return FALSE
|
||||
var/obj/item/I = active_block_item
|
||||
combat_flags &= ~(COMBAT_FLAG_ACTIVE_BLOCKING | COMBAT_FLAG_ACTIVE_BLOCK_STARTING)
|
||||
active_block_effect_end()
|
||||
active_block_item = null
|
||||
REMOVE_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT)
|
||||
REMOVE_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT)
|
||||
remove_movespeed_modifier(/datum/movespeed_modifier/active_block)
|
||||
var/datum/block_parry_data/data = I.get_block_parry_data()
|
||||
if(timeToNextMove() < data.block_end_click_cd_add)
|
||||
changeNext_move(data.block_end_click_cd_add)
|
||||
return TRUE
|
||||
|
||||
/mob/living/proc/start_active_blocking(obj/item/I)
|
||||
if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING))
|
||||
return FALSE
|
||||
if(!(I in held_items))
|
||||
return FALSE
|
||||
var/datum/block_parry_data/data = I.get_block_parry_data()
|
||||
if(!istype(data)) //Typecheck because if an admin/coder screws up varediting or something we do not want someone being broken forever, the CRASH logs feedback so we know what happened.
|
||||
CRASH("start_active_blocking called with an item with no valid data: [I] --> [I.block_parry_data]!")
|
||||
combat_flags |= COMBAT_FLAG_ACTIVE_BLOCKING
|
||||
active_block_item = I
|
||||
if(data.block_lock_attacking)
|
||||
ADD_TRAIT(src, TRAIT_MOBILITY_NOUSE, ACTIVE_BLOCK_TRAIT) //probably should be something else at some point
|
||||
if(data.block_lock_sprinting)
|
||||
ADD_TRAIT(src, TRAIT_SPRINT_LOCKED, ACTIVE_BLOCK_TRAIT)
|
||||
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/active_block, multiplicative_slowdown = data.block_slowdown)
|
||||
active_block_effect_start()
|
||||
return TRUE
|
||||
|
||||
/// Visual effect setup for starting a directional block
|
||||
/mob/living/proc/active_block_effect_start()
|
||||
visible_message("<span class='warning'>[src] raises their [active_block_item], dropping into a defensive stance!</span>")
|
||||
animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_OUT)
|
||||
|
||||
/// Visual effect cleanup for starting a directional block
|
||||
/mob/living/proc/active_block_effect_end()
|
||||
visible_message("<span class='warning'>[src] lowers their [active_block_item].</span>")
|
||||
animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_IN)
|
||||
|
||||
/mob/living/proc/continue_starting_active_block()
|
||||
if(SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_INACTIVE))
|
||||
return DO_AFTER_STOP
|
||||
return (combat_flags & COMBAT_FLAG_ACTIVE_BLOCK_STARTING)? DO_AFTER_CONTINUE : DO_AFTER_STOP
|
||||
|
||||
/mob/living/get_standard_pixel_x_offset()
|
||||
. = ..()
|
||||
if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING))
|
||||
if(dir & EAST)
|
||||
. += 8
|
||||
if(dir & WEST)
|
||||
. -= 8
|
||||
|
||||
/mob/living/get_standard_pixel_y_offset()
|
||||
. = ..()
|
||||
if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING))
|
||||
if(dir & NORTH)
|
||||
. += 8
|
||||
if(dir & SOUTH)
|
||||
. -= 8
|
||||
|
||||
/**
|
||||
* Proc called by keybindings to toggle active blocking.
|
||||
*/
|
||||
/mob/living/proc/keybind_toggle_active_blocking()
|
||||
if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING))
|
||||
return keybind_stop_active_blocking()
|
||||
else
|
||||
return keybind_start_active_blocking()
|
||||
|
||||
/**
|
||||
* Proc called by keybindings to start active blocking.
|
||||
*/
|
||||
/mob/living/proc/keybind_start_active_blocking()
|
||||
if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING))
|
||||
return FALSE
|
||||
if(!(combat_flags & COMBAT_FLAG_BLOCK_CAPABLE))
|
||||
to_chat(src, "<span class='warning'>You're not something that can actively block.</span>")
|
||||
return FALSE
|
||||
// QOL: Instead of trying to just block with held item, grab first available item.
|
||||
var/obj/item/I = find_active_block_item()
|
||||
if(!I)
|
||||
to_chat(src, "<span class='warning'>You can't block with your bare hands!</span>")
|
||||
return
|
||||
if(!I.can_active_block())
|
||||
to_chat(src, "<span class='warning'>[I] is either not capable of being used to actively block, or is not currently in a state that can! (Try wielding it if it's twohanded, for example.)</span>")
|
||||
return
|
||||
// QOL: Attempt to toggle on combat mode if it isn't already
|
||||
SEND_SIGNAL(src, COMSIG_ENABLE_COMBAT_MODE)
|
||||
if(!SEND_SIGNAL(src, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE))
|
||||
to_chat(src, "<span class='warning'>You must be in combat mode to actively block!</span>")
|
||||
return FALSE
|
||||
var/datum/block_parry_data/data = I.get_block_parry_data()
|
||||
var/delay = data.block_start_delay
|
||||
combat_flags |= COMBAT_FLAG_ACTIVE_BLOCK_STARTING
|
||||
animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = delay, FALSE, SINE_EASING | EASE_IN)
|
||||
if(!do_after_advanced(src, delay, src, DO_AFTER_REQUIRES_USER_ON_TURF|DO_AFTER_NO_COEFFICIENT, CALLBACK(src, .proc/continue_starting_active_block), MOBILITY_USE, null, null, I))
|
||||
to_chat(src, "<span class='warning'>You fail to raise [I].</span>")
|
||||
combat_flags &= ~(COMBAT_FLAG_ACTIVE_BLOCK_STARTING)
|
||||
animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_IN, ANIMATION_END_NOW)
|
||||
return
|
||||
combat_flags &= ~(COMBAT_FLAG_ACTIVE_BLOCK_STARTING)
|
||||
start_active_blocking(I)
|
||||
|
||||
/**
|
||||
* Gets the first item we can that can block, but if that fails, default to active held item.COMSIG_ENABLE_COMBAT_MODE
|
||||
*/
|
||||
/mob/living/proc/find_active_block_item()
|
||||
var/obj/item/held = get_active_held_item()
|
||||
if(!held?.can_active_block())
|
||||
for(var/obj/item/I in held_items - held)
|
||||
if(I.can_active_block())
|
||||
return I
|
||||
return held
|
||||
|
||||
/**
|
||||
* Proc called by keybindings to stop active blocking.
|
||||
*/
|
||||
/mob/living/proc/keybind_stop_active_blocking()
|
||||
combat_flags &= ~(COMBAT_FLAG_ACTIVE_BLOCK_STARTING)
|
||||
if(combat_flags & COMBAT_FLAG_ACTIVE_BLOCKING)
|
||||
stop_active_blocking(FALSE)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Returns if we can actively block.
|
||||
*/
|
||||
/obj/item/proc/can_active_block()
|
||||
return block_parry_data && (item_flags & ITEM_CAN_BLOCK)
|
||||
|
||||
/**
|
||||
* Calculates FINAL ATTACK DAMAGE after mitigation
|
||||
*/
|
||||
/obj/item/proc/active_block_calculate_final_damage(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
var/datum/block_parry_data/data = get_block_parry_data()
|
||||
var/absorption = data.attack_type_list_scan(data.block_damage_absorption_override, attack_type)
|
||||
var/efficiency = data.attack_type_list_scan(data.block_damage_multiplier_override, attack_type)
|
||||
var/limit = data.attack_type_list_scan(data.block_damage_limit_override, attack_type)
|
||||
// must use isnulls to handle 0's.
|
||||
if(isnull(absorption))
|
||||
absorption = data.block_damage_absorption
|
||||
if(isnull(efficiency))
|
||||
efficiency = data.block_damage_multiplier
|
||||
if(isnull(limit))
|
||||
limit = data.block_damage_limit
|
||||
// now we calculate damage to reduce.
|
||||
var/final_damage = 0
|
||||
// apply limit
|
||||
if(damage > limit) //clamp and apply overrun
|
||||
final_damage += (damage - limit)
|
||||
damage = limit
|
||||
// apply absorption
|
||||
damage -= min(absorption, damage) //this way if damage is less than absorption it 0's properly.
|
||||
// apply multiplier to remaining
|
||||
final_damage += (damage * efficiency)
|
||||
return final_damage
|
||||
|
||||
/// Amount of stamina from damage blocked. Note that the damage argument is damage_blocked.
|
||||
/obj/item/proc/active_block_stamina_cost(mob/living/owner, atom/object, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
var/datum/block_parry_data/data = get_block_parry_data()
|
||||
var/efficiency = data.attack_type_list_scan(data.block_stamina_efficiency_override, attack_type)
|
||||
if(isnull(efficiency))
|
||||
efficiency = data.block_stamina_efficiency
|
||||
var/multiplier = 1
|
||||
if(!CHECK_MOBILITY(owner, MOBILITY_STAND))
|
||||
multiplier = data.attack_type_list_scan(data.block_resting_stamina_penalty_multiplier_override, attack_type)
|
||||
if(isnull(multiplier))
|
||||
multiplier = data.block_resting_stamina_penalty_multiplier
|
||||
return (damage_blocked / efficiency) * multiplier
|
||||
|
||||
/// Apply the stamina damage to our user, notice how damage argument is stamina_amount.
|
||||
/obj/item/proc/active_block_do_stamina_damage(mob/living/owner, atom/object, stamina_amount, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
var/datum/block_parry_data/data = get_block_parry_data()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/C = owner
|
||||
var/held_index = C.get_held_index_of_item(src)
|
||||
var/obj/item/bodypart/BP = C.hand_bodyparts[held_index]
|
||||
if(!BP?.body_zone)
|
||||
return C.adjustStaminaLossBuffered(stamina_amount) //nah
|
||||
var/zone = BP.body_zone
|
||||
var/stamina_to_zone = data.block_stamina_limb_ratio * stamina_amount
|
||||
var/stamina_to_chest = stamina_amount - stamina_to_zone
|
||||
var/stamina_buffered = stamina_to_chest * data.block_stamina_buffer_ratio
|
||||
stamina_to_chest -= stamina_buffered
|
||||
C.apply_damage(stamina_to_zone, STAMINA, zone)
|
||||
C.apply_damage(stamina_to_chest, STAMINA, BODY_ZONE_CHEST)
|
||||
C.adjustStaminaLossBuffered(stamina_buffered)
|
||||
else
|
||||
owner.adjustStaminaLossBuffered(stamina_amount)
|
||||
|
||||
/obj/item/proc/on_active_block(mob/living/owner, atom/object, damage, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction)
|
||||
return
|
||||
|
||||
/obj/item/proc/active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction)
|
||||
if(!can_active_block())
|
||||
return BLOCK_NONE
|
||||
var/datum/block_parry_data/data = get_block_parry_data()
|
||||
if(attack_type && !(attack_type & data.can_block_attack_types))
|
||||
return BLOCK_NONE
|
||||
var/incoming_direction
|
||||
if(isnull(override_direction))
|
||||
if(istype(object, /obj/item/projectile))
|
||||
var/obj/item/projectile/P = object
|
||||
incoming_direction = angle2dir(P.Angle)
|
||||
else
|
||||
incoming_direction = get_dir(get_turf(attacker) || get_turf(object), src)
|
||||
if(!CHECK_MOBILITY(owner, MOBILITY_STAND) && !(data.block_resting_attack_types_anydir & attack_type) && (!(data.block_resting_attack_types_directional & attack_type) || !can_block_direction(owner.dir, incoming_direction)))
|
||||
return BLOCK_NONE
|
||||
else if(!can_block_direction(owner.dir, incoming_direction))
|
||||
return BLOCK_NONE
|
||||
block_return[BLOCK_RETURN_ACTIVE_BLOCK] = TRUE
|
||||
var/final_damage = active_block_calculate_final_damage(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
|
||||
var/damage_blocked = damage - final_damage
|
||||
var/stamina_cost = active_block_stamina_cost(owner, object, damage_blocked, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
|
||||
active_block_do_stamina_damage(owner, object, stamina_cost, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
|
||||
block_return[BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATED] = damage - final_damage
|
||||
block_return[BLOCK_RETURN_SET_DAMAGE_TO] = final_damage
|
||||
. = BLOCK_SHOULD_CHANGE_DAMAGE
|
||||
if((final_damage <= 0) || (damage <= 0))
|
||||
. |= BLOCK_SUCCESS //full block
|
||||
owner.visible_message("<span class='warning'>[owner] blocks \the [attack_text] with [src]!</span>")
|
||||
else
|
||||
owner.visible_message("<span class='warning'>[owner] dampens \the [attack_text] with [src]!</span>")
|
||||
block_return[BLOCK_RETURN_PROJECTILE_BLOCK_PERCENTAGE] = data.block_projectile_mitigation
|
||||
if(length(data.block_sounds))
|
||||
playsound(loc, pickweight(data.block_sounds), 75, TRUE)
|
||||
on_active_block(owner, object, damage, damage_blocked, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return, override_direction)
|
||||
|
||||
/obj/item/proc/check_active_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
if(!can_active_block())
|
||||
return
|
||||
var/incoming_direction = get_dir(get_turf(attacker) || get_turf(object), src)
|
||||
if(!can_block_direction(owner.dir, incoming_direction))
|
||||
return
|
||||
block_return[BLOCK_RETURN_ACTIVE_BLOCK] = TRUE
|
||||
block_return[BLOCK_RETURN_ACTIVE_BLOCK_DAMAGE_MITIGATED] = damage - active_block_calculate_final_damage(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
|
||||
|
||||
/**
|
||||
* Gets the block direction bitflags of what we can block.
|
||||
*/
|
||||
/obj/item/proc/blockable_directions()
|
||||
var/datum/block_parry_data/data = get_block_parry_data()
|
||||
return data.can_block_directions
|
||||
|
||||
/**
|
||||
* Checks if we can block from a specific direction from our direction.
|
||||
*
|
||||
* @params
|
||||
* * our_dir - our direction.
|
||||
* * their_dir - their direction. Must be a single direction, or NONE for an attack from the same tile. This is incoming direction.
|
||||
*/
|
||||
/obj/item/proc/can_block_direction(our_dir, their_dir)
|
||||
their_dir = turn(their_dir, 180)
|
||||
if(our_dir != NORTH)
|
||||
var/turn_angle = dir2angle(our_dir)
|
||||
// dir2angle(), ss13 proc is clockwise so dir2angle(EAST) == 90
|
||||
// turn(), byond proc is counterclockwise so turn(NORTH, 90) == WEST
|
||||
their_dir = turn(their_dir, turn_angle)
|
||||
return (DIR2BLOCKDIR(their_dir) & blockable_directions())
|
||||
|
||||
/**
|
||||
* can_block_direction but for "compound" directions to check all of them and return the number of directions that were blocked.
|
||||
*
|
||||
* @params
|
||||
* * our_dir - our direction.
|
||||
* * their_dirs - list of their directions as we cannot use bitfields here.
|
||||
*/
|
||||
/obj/item/proc/can_block_directions_multiple(our_dir, list/their_dirs)
|
||||
. = FALSE
|
||||
for(var/i in their_dirs)
|
||||
. |= can_block_direction(our_dir, i)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user